mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-30 00:32:57 -04:00
gobj: Cube map sampling support in TexturePeeker
Closes #1098 Co-authored-by: Mitchell Stokes <mogurijin@gmail.com>
This commit is contained in:
parent
1fb8480585
commit
8372b8150a
@ -56,3 +56,11 @@ INLINE bool TexturePeeker::
|
|||||||
has_pixel(int x, int y) const {
|
has_pixel(int x, int y) const {
|
||||||
return x >= 0 && y >= 0 && x < _x_size && y < _y_size;
|
return x >= 0 && y >= 0 && x < _x_size && y < _y_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether a given coordinate is inside of the texture dimensions.
|
||||||
|
*/
|
||||||
|
INLINE bool TexturePeeker::
|
||||||
|
has_pixel(int x, int y, int z) const {
|
||||||
|
return x >= 0 && y >= 0 && z >= 0 && x < _x_size && y < _y_size && z < _z_size;
|
||||||
|
}
|
||||||
|
@ -74,56 +74,42 @@ static double get_signed_int_i(const unsigned char *&p) {
|
|||||||
*/
|
*/
|
||||||
TexturePeeker::
|
TexturePeeker::
|
||||||
TexturePeeker(Texture *tex, Texture::CData *cdata) {
|
TexturePeeker(Texture *tex, Texture::CData *cdata) {
|
||||||
if (cdata->_texture_type == Texture::TT_cube_map) {
|
// Simple ram images are possible if it is a 2-d texture.
|
||||||
// Cube map texture. We'll need to map from (u, v, w) to (u, v) within
|
if (tex->do_has_ram_image(cdata) && cdata->_ram_image_compression == Texture::CM_off) {
|
||||||
// the appropriate page, where w indicates the page.
|
// Get the regular RAM image if it is available.
|
||||||
|
_image = tex->do_get_ram_image(cdata);
|
||||||
|
_x_size = cdata->_x_size;
|
||||||
|
_y_size = cdata->_y_size;
|
||||||
|
_z_size = cdata->_z_size;
|
||||||
|
_pixel_width = cdata->_component_width * cdata->_num_components;
|
||||||
|
_format = cdata->_format;
|
||||||
|
_component_type = cdata->_component_type;
|
||||||
|
}
|
||||||
|
else if (!cdata->_simple_ram_image._image.empty()) {
|
||||||
|
// Get the simple RAM image if *that* is available.
|
||||||
|
_image = cdata->_simple_ram_image._image;
|
||||||
|
_x_size = cdata->_simple_x_size;
|
||||||
|
_y_size = cdata->_simple_y_size;
|
||||||
|
_z_size = 1;
|
||||||
|
|
||||||
// TODO: handle cube maps.
|
_pixel_width = 4;
|
||||||
return;
|
_format = Texture::F_rgba;
|
||||||
|
_component_type = Texture::T_unsigned_byte;
|
||||||
} else {
|
}
|
||||||
// Regular 1-d, 2-d, or 3-d texture. The coordinates map directly.
|
else {
|
||||||
// Simple ram images are possible if it is a 2-d texture.
|
// Failing that, reload and get the uncompressed RAM image.
|
||||||
if (tex->do_has_ram_image(cdata) && cdata->_ram_image_compression == Texture::CM_off) {
|
_image = tex->do_get_uncompressed_ram_image(cdata);
|
||||||
// Get the regular RAM image if it is available.
|
_x_size = cdata->_x_size;
|
||||||
_image = tex->do_get_ram_image(cdata);
|
_y_size = cdata->_y_size;
|
||||||
_x_size = cdata->_x_size;
|
_z_size = cdata->_z_size;
|
||||||
_y_size = cdata->_y_size;
|
_pixel_width = cdata->_component_width * cdata->_num_components;
|
||||||
_z_size = cdata->_z_size;
|
_format = cdata->_format;
|
||||||
_component_width = cdata->_component_width;
|
_component_type = cdata->_component_type;
|
||||||
_num_components = cdata->_num_components;
|
|
||||||
_format = cdata->_format;
|
|
||||||
_component_type = cdata->_component_type;
|
|
||||||
|
|
||||||
} else if (!cdata->_simple_ram_image._image.empty()) {
|
|
||||||
// Get the simple RAM image if *that* is available.
|
|
||||||
_image = cdata->_simple_ram_image._image;
|
|
||||||
_x_size = cdata->_simple_x_size;
|
|
||||||
_y_size = cdata->_simple_y_size;
|
|
||||||
_z_size = 1;
|
|
||||||
|
|
||||||
_component_width = 1;
|
|
||||||
_num_components = 4;
|
|
||||||
_format = Texture::F_rgba;
|
|
||||||
_component_type = Texture::T_unsigned_byte;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// Failing that, reload and get the uncompressed RAM image.
|
|
||||||
_image = tex->do_get_uncompressed_ram_image(cdata);
|
|
||||||
_x_size = cdata->_x_size;
|
|
||||||
_y_size = cdata->_y_size;
|
|
||||||
_z_size = cdata->_z_size;
|
|
||||||
_component_width = cdata->_component_width;
|
|
||||||
_num_components = cdata->_num_components;
|
|
||||||
_format = cdata->_format;
|
|
||||||
_component_type = cdata->_component_type;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_image.is_null()) {
|
if (_image.is_null()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_pixel_width = _component_width * _num_components;
|
|
||||||
|
|
||||||
if (Texture::is_integer(_format)) {
|
if (Texture::is_integer(_format)) {
|
||||||
switch (_component_type) {
|
switch (_component_type) {
|
||||||
@ -291,8 +277,10 @@ TexturePeeker(Texture *tex, Texture::CData *cdata) {
|
|||||||
_image.clear();
|
_image.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
_is_cube = (cdata->_texture_type == Texture::TT_cube_map ||
|
||||||
|
cdata->_texture_type == Texture::TT_cube_map_array);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fills "color" with the RGBA color of the texel at point (u, v).
|
* Fills "color" with the RGBA color of the texel at point (u, v).
|
||||||
@ -304,22 +292,95 @@ TexturePeeker(Texture *tex, Texture::CData *cdata) {
|
|||||||
*/
|
*/
|
||||||
void TexturePeeker::
|
void TexturePeeker::
|
||||||
lookup(LColor &color, PN_stdfloat u, PN_stdfloat v) const {
|
lookup(LColor &color, PN_stdfloat u, PN_stdfloat v) const {
|
||||||
int x = int((u - cfloor(u)) * (PN_stdfloat)_x_size) % _x_size;
|
if (!_is_cube) {
|
||||||
int y = int((v - cfloor(v)) * (PN_stdfloat)_y_size) % _y_size;
|
int x = int((u - cfloor(u)) * (PN_stdfloat)_x_size) % _x_size;
|
||||||
fetch_pixel(color, x, y);
|
int y = int((v - cfloor(v)) * (PN_stdfloat)_y_size) % _y_size;
|
||||||
|
fetch_pixel(color, x, y);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lookup(color, u, v, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Works like TexturePeeker::lookup(), but instead uv-coordinates integer
|
* Fills "color" with the RGBA color of the texel at point (u, v, w).
|
||||||
* coordinates are used.
|
*
|
||||||
|
* The texel color is determined via nearest-point sampling (no filtering of
|
||||||
|
* adjacent pixels), regardless of the filter type associated with the
|
||||||
|
* texture. u, v, and w will wrap around regardless of the texture's wrap
|
||||||
|
* mode.
|
||||||
*/
|
*/
|
||||||
void TexturePeeker::
|
void TexturePeeker::
|
||||||
fetch_pixel(LColor& color, int x, int y) const {
|
lookup(LColor &color, PN_stdfloat u, PN_stdfloat v, PN_stdfloat w) const {
|
||||||
|
if (!_is_cube) {
|
||||||
|
int x = int((u - cfloor(u)) * (PN_stdfloat)_x_size) % _x_size;
|
||||||
|
int y = int((v - cfloor(v)) * (PN_stdfloat)_y_size) % _y_size;
|
||||||
|
int z = int((w - cfloor(w)) * (PN_stdfloat)_z_size) % _z_size;
|
||||||
|
|
||||||
|
nassertv(x >= 0 && x < _x_size && y >= 0 && y < _y_size &&
|
||||||
|
z >= 0 && z < _z_size);
|
||||||
|
const unsigned char *p = _image.p() + (z * _x_size * _y_size + y * _x_size + x) * _pixel_width;
|
||||||
|
|
||||||
|
(*_get_texel)(color, p, _get_component);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PN_stdfloat absu = fabs(u),
|
||||||
|
absv = fabs(v),
|
||||||
|
absw = fabs(w);
|
||||||
|
PN_stdfloat magnitude;
|
||||||
|
PN_stdfloat u2d, v2d;
|
||||||
|
int z;
|
||||||
|
|
||||||
|
// The following was pulled from:
|
||||||
|
// https://www.gamedev.net/forums/topic/687535-implementing-a-cube-map-lookup-function/
|
||||||
|
if (absw >= absu && absw >= absv) {
|
||||||
|
z = 4 + (w < 0.0);
|
||||||
|
magnitude = 0.5 / absw;
|
||||||
|
u2d = w < 0.0 ? -u : u;
|
||||||
|
v2d = -v;
|
||||||
|
}
|
||||||
|
else if (absv >= absu) {
|
||||||
|
z = 2 + (v < 0.0);
|
||||||
|
magnitude = 0.5 / absv;
|
||||||
|
u2d = u;
|
||||||
|
v2d = v < 0.0 ? -w : w;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
z = 0 + (u < 0.0);
|
||||||
|
magnitude = 0.5 / absu;
|
||||||
|
u2d = u < 0.0 ? w : -w;
|
||||||
|
v2d = -v;
|
||||||
|
}
|
||||||
|
u2d = u2d * magnitude + 0.5;
|
||||||
|
v2d = v2d * magnitude + 0.5;
|
||||||
|
|
||||||
|
int x = int((u2d - cfloor(u2d)) * (PN_stdfloat)_x_size) % _x_size;
|
||||||
|
int y = int((v2d - cfloor(v2d)) * (PN_stdfloat)_y_size) % _y_size;
|
||||||
|
fetch_pixel(color, x, y, z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Works like TexturePeeker::lookup(), but instead uv-coordinates integer
|
||||||
|
* coordinates are used.
|
||||||
|
*/
|
||||||
|
void TexturePeeker::
|
||||||
|
fetch_pixel(LColor &color, int x, int y) const {
|
||||||
nassertv(x >= 0 && x < _x_size && y >= 0 && y < _y_size);
|
nassertv(x >= 0 && x < _x_size && y >= 0 && y < _y_size);
|
||||||
const unsigned char *p = _image.p() + (y * _x_size + x) * _pixel_width;
|
const unsigned char *p = _image.p() + (y * _x_size + x) * _pixel_width;
|
||||||
(*_get_texel)(color, p, _get_component);
|
(*_get_texel)(color, p, _get_component);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Works like TexturePeeker::lookup(), but instead uv-coordinates integer
|
||||||
|
* coordinates are used.
|
||||||
|
*/
|
||||||
|
void TexturePeeker::
|
||||||
|
fetch_pixel(LColor &color, int x, int y, int z) const {
|
||||||
|
nassertv(x >= 0 && x < _x_size && y >= 0 && y < _y_size && z >= 0 && z < _z_size);
|
||||||
|
const unsigned char *p = _image.p() + ((z * _y_size + y) * _x_size + x) * _pixel_width;
|
||||||
|
(*_get_texel)(color, p, _get_component);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs a bilinear lookup to retrieve the color value stored at the uv
|
* Performs a bilinear lookup to retrieve the color value stored at the uv
|
||||||
@ -370,27 +431,6 @@ lookup_bilinear(LColor &color, PN_stdfloat u, PN_stdfloat v) const {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Fills "color" with the RGBA color of the texel at point (u, v, w).
|
|
||||||
*
|
|
||||||
* The texel color is determined via nearest-point sampling (no filtering of
|
|
||||||
* adjacent pixels), regardless of the filter type associated with the
|
|
||||||
* texture. u, v, and w will wrap around regardless of the texture's wrap
|
|
||||||
* mode.
|
|
||||||
*/
|
|
||||||
void TexturePeeker::
|
|
||||||
lookup(LColor &color, PN_stdfloat u, PN_stdfloat v, PN_stdfloat w) const {
|
|
||||||
int x = int((u - cfloor(u)) * (PN_stdfloat)_x_size) % _x_size;
|
|
||||||
int y = int((v - cfloor(v)) * (PN_stdfloat)_y_size) % _y_size;
|
|
||||||
int z = int((w - cfloor(w)) * (PN_stdfloat)_z_size) % _z_size;
|
|
||||||
|
|
||||||
nassertv(x >= 0 && x < _x_size && y >= 0 && y < _y_size &&
|
|
||||||
z >= 0 && z < _z_size);
|
|
||||||
const unsigned char *p = _image.p() + (z * _x_size * _y_size + y * _x_size + x) * _pixel_width;
|
|
||||||
|
|
||||||
(*_get_texel)(color, p, _get_component);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fills "color" with the average RGBA color of the texels within the
|
* Fills "color" with the average RGBA color of the texels within the
|
||||||
* rectangle defined by the specified coordinate range.
|
* rectangle defined by the specified coordinate range.
|
||||||
|
@ -37,9 +37,11 @@ PUBLISHED:
|
|||||||
INLINE int get_z_size() const;
|
INLINE int get_z_size() const;
|
||||||
|
|
||||||
INLINE bool has_pixel(int x, int y) const;
|
INLINE bool has_pixel(int x, int y) const;
|
||||||
|
INLINE bool has_pixel(int x, int y, int z) const;
|
||||||
void lookup(LColor &color, PN_stdfloat u, PN_stdfloat v) const;
|
void lookup(LColor &color, PN_stdfloat u, PN_stdfloat v) const;
|
||||||
void lookup(LColor &color, PN_stdfloat u, PN_stdfloat v, PN_stdfloat w) const;
|
void lookup(LColor &color, PN_stdfloat u, PN_stdfloat v, PN_stdfloat w) const;
|
||||||
void fetch_pixel(LColor &color, int x, int y) const;
|
void fetch_pixel(LColor &color, int x, int y) const;
|
||||||
|
void fetch_pixel(LColor &color, int x, int y, int z) const;
|
||||||
bool lookup_bilinear(LColor &color, PN_stdfloat u, PN_stdfloat v) const;
|
bool lookup_bilinear(LColor &color, PN_stdfloat u, PN_stdfloat v) const;
|
||||||
void filter_rect(LColor &color,
|
void filter_rect(LColor &color,
|
||||||
PN_stdfloat min_u, PN_stdfloat min_v,
|
PN_stdfloat min_u, PN_stdfloat min_v,
|
||||||
@ -86,8 +88,8 @@ private:
|
|||||||
int _x_size;
|
int _x_size;
|
||||||
int _y_size;
|
int _y_size;
|
||||||
int _z_size;
|
int _z_size;
|
||||||
int _component_width;
|
int _is_cube;
|
||||||
int _num_components;
|
int _unused1;
|
||||||
int _pixel_width;
|
int _pixel_width;
|
||||||
Texture::Format _format;
|
Texture::Format _format;
|
||||||
Texture::ComponentType _component_type;
|
Texture::ComponentType _component_type;
|
||||||
|
@ -158,3 +158,51 @@ def test_texture_peek_int_i():
|
|||||||
col = LColor()
|
col = LColor()
|
||||||
peeker.fetch_pixel(col, 0, 0)
|
peeker.fetch_pixel(col, 0, 0)
|
||||||
assert col == (minval, -1, 0, maxval)
|
assert col == (minval, -1, 0, maxval)
|
||||||
|
|
||||||
|
|
||||||
|
def test_texture_peek_cube():
|
||||||
|
maxval = 255
|
||||||
|
data_list = []
|
||||||
|
for z in range(6):
|
||||||
|
for y in range(3):
|
||||||
|
for x in range(3):
|
||||||
|
data_list += [z, y, x, maxval]
|
||||||
|
data = array('B', data_list)
|
||||||
|
tex = Texture("")
|
||||||
|
tex.setup_cube_map(3, Texture.T_unsigned_byte, Texture.F_rgba8i)
|
||||||
|
tex.set_ram_image(data)
|
||||||
|
peeker = tex.peek()
|
||||||
|
assert peeker.has_pixel(0, 0)
|
||||||
|
assert peeker.has_pixel(0, 0, 0)
|
||||||
|
|
||||||
|
# If no z is specified, face 0 is used by default
|
||||||
|
col = LColor()
|
||||||
|
peeker.fetch_pixel(col, 1, 2)
|
||||||
|
assert col == (1, 2, 0, maxval)
|
||||||
|
|
||||||
|
# Now try each face
|
||||||
|
for faceidx in range(6):
|
||||||
|
col = LColor()
|
||||||
|
peeker.fetch_pixel(col, 0, 0, faceidx)
|
||||||
|
assert col == (0, 0, faceidx, maxval)
|
||||||
|
|
||||||
|
# Try some vector lookups.
|
||||||
|
def lookup(*vec):
|
||||||
|
col = LColor()
|
||||||
|
peeker.lookup(col, *vec)
|
||||||
|
return col
|
||||||
|
assert lookup(1, 0, 0) == (1, 1, 0, maxval)
|
||||||
|
assert lookup(-1, 0, 0) == (1, 1, 1, maxval)
|
||||||
|
assert lookup(0, 1, 0) == (1, 1, 2, maxval)
|
||||||
|
assert lookup(0, -1, 0) == (1, 1, 3, maxval)
|
||||||
|
assert lookup(0, 0, 1) == (1, 1, 4, maxval)
|
||||||
|
assert lookup(0, 0, -1) == (1, 1, 5, maxval)
|
||||||
|
|
||||||
|
# Magnitude shouldn't matter
|
||||||
|
assert lookup(0, 2, 0) == (1, 1, 2, maxval)
|
||||||
|
assert lookup(0, 0, -0.5) == (1, 1, 5, maxval)
|
||||||
|
|
||||||
|
# Sample in corner (slight bias to disambiguate which face is selected)
|
||||||
|
assert lookup(1.00001, 1, 1) == (0, 0, 0, maxval)
|
||||||
|
assert lookup(1.00001, 1, 0) == (1, 0, 0, maxval)
|
||||||
|
assert lookup(1, 1.00001, 0) == (2, 1, 2, maxval)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user