mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-29 00:06:44 -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 {
|
||||
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(Texture *tex, Texture::CData *cdata) {
|
||||
if (cdata->_texture_type == Texture::TT_cube_map) {
|
||||
// Cube map texture. We'll need to map from (u, v, w) to (u, v) within
|
||||
// the appropriate page, where w indicates the page.
|
||||
// Simple ram images are possible if it is a 2-d texture.
|
||||
if (tex->do_has_ram_image(cdata) && cdata->_ram_image_compression == Texture::CM_off) {
|
||||
// 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.
|
||||
return;
|
||||
|
||||
} else {
|
||||
// Regular 1-d, 2-d, or 3-d texture. The coordinates map directly.
|
||||
// Simple ram images are possible if it is a 2-d texture.
|
||||
if (tex->do_has_ram_image(cdata) && cdata->_ram_image_compression == Texture::CM_off) {
|
||||
// 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;
|
||||
_component_width = cdata->_component_width;
|
||||
_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;
|
||||
}
|
||||
_pixel_width = 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;
|
||||
_pixel_width = cdata->_component_width * cdata->_num_components;
|
||||
_format = cdata->_format;
|
||||
_component_type = cdata->_component_type;
|
||||
}
|
||||
|
||||
if (_image.is_null()) {
|
||||
return;
|
||||
}
|
||||
_pixel_width = _component_width * _num_components;
|
||||
|
||||
if (Texture::is_integer(_format)) {
|
||||
switch (_component_type) {
|
||||
@ -291,8 +277,10 @@ TexturePeeker(Texture *tex, Texture::CData *cdata) {
|
||||
_image.clear();
|
||||
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).
|
||||
@ -304,22 +292,95 @@ TexturePeeker(Texture *tex, Texture::CData *cdata) {
|
||||
*/
|
||||
void TexturePeeker::
|
||||
lookup(LColor &color, PN_stdfloat u, PN_stdfloat v) 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;
|
||||
fetch_pixel(color, x, y);
|
||||
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;
|
||||
fetch_pixel(color, x, y);
|
||||
}
|
||||
else {
|
||||
lookup(color, u, v, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Works like TexturePeeker::lookup(), but instead uv-coordinates integer
|
||||
* coordinates are used.
|
||||
* 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::
|
||||
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);
|
||||
const unsigned char *p = _image.p() + (y * _x_size + x) * _pixel_width;
|
||||
(*_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
|
||||
@ -370,27 +431,6 @@ lookup_bilinear(LColor &color, PN_stdfloat u, PN_stdfloat v) const {
|
||||
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
|
||||
* rectangle defined by the specified coordinate range.
|
||||
|
@ -37,9 +37,11 @@ PUBLISHED:
|
||||
INLINE int get_z_size() 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, PN_stdfloat w) 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;
|
||||
void filter_rect(LColor &color,
|
||||
PN_stdfloat min_u, PN_stdfloat min_v,
|
||||
@ -86,8 +88,8 @@ private:
|
||||
int _x_size;
|
||||
int _y_size;
|
||||
int _z_size;
|
||||
int _component_width;
|
||||
int _num_components;
|
||||
int _is_cube;
|
||||
int _unused1;
|
||||
int _pixel_width;
|
||||
Texture::Format _format;
|
||||
Texture::ComponentType _component_type;
|
||||
|
@ -158,3 +158,51 @@ def test_texture_peek_int_i():
|
||||
col = LColor()
|
||||
peeker.fetch_pixel(col, 0, 0)
|
||||
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