diff --git a/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx b/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx index b6dc116c50..530b2641d7 100644 --- a/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx +++ b/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx @@ -636,27 +636,72 @@ begin_draw_primitives(const GeomPipelineReader *geom_reader, GeomVertexReader rcolor, rnormal; // We now support up to 2-stage multitexturing. - GeomVertexReader rtexcoord[MAX_TEXTURE_STAGES]; - bool needs_texcoord[MAX_TEXTURE_STAGES] = { false, false }; - bool needs_texmat[MAX_TEXTURE_STAGES] = { false, false }; - LMatrix4f texmat[MAX_TEXTURE_STAGES]; - const InternalName *texcoord_name[MAX_TEXTURE_STAGES] = { - InternalName::get_texcoord(), InternalName::get_texcoord() - }; + GenTexcoordFunc *texgen_func[MAX_TEXTURE_STAGES]; + TexCoordData tcdata[MAX_TEXTURE_STAGES]; + + const TexGenAttrib *target_tex_gen = DCAST(TexGenAttrib, _target_rs->get_attrib_def(TexGenAttrib::get_class_slot())); + const TexMatrixAttrib *target_tex_matrix = DCAST(TexMatrixAttrib, _target_rs->get_attrib_def(TexMatrixAttrib::get_class_slot())); + int max_stage_index = _target_texture->get_num_on_ff_stages(); for (int si = 0; si < max_stage_index; ++si) { TextureStage *stage = _target_texture->get_on_ff_stage(si); - rtexcoord[si] = GeomVertexReader(data_reader, stage->get_texcoord_name(), - force); - rtexcoord[si].set_row(_min_vertex); - needs_texcoord[si] = rtexcoord[si].has_column(); - if (needs_texcoord[si]) { - const TexMatrixAttrib *target_tex_matrix = DCAST(TexMatrixAttrib, _target_rs->get_attrib_def(TexMatrixAttrib::get_class_slot())); - if (target_tex_matrix->has_stage(stage)) { - needs_texmat[si] = true; - texmat[si] = target_tex_matrix->get_mat(stage); + switch (target_tex_gen->get_mode(stage)) { + case TexGenAttrib::M_eye_sphere_map: + tcdata[si]._r1 = GeomVertexReader(data_reader, InternalName::get_normal(), + force); + tcdata[si]._r2 = GeomVertexReader(data_reader, InternalName::get_vertex(), + force); + texgen_func[si] = &texgen_sphere_map; + tcdata[si]._mat = _internal_transform->get_mat(); + break; + + case TexGenAttrib::M_eye_position: + tcdata[si]._r1 = GeomVertexReader(data_reader, InternalName::get_vertex(), + force); + texgen_func[si] = &texgen_texmat; + { + CPT(TransformState) eye_transform = + _cs_transform->invert_compose(_internal_transform); + tcdata[si]._mat = eye_transform->get_mat(); } + if (target_tex_matrix->has_stage(stage)) { + tcdata[si]._mat = tcdata[si]._mat * target_tex_matrix->get_mat(stage); + } + break; + + case TexGenAttrib::M_world_position: + tcdata[si]._r1 = GeomVertexReader(data_reader, InternalName::get_vertex(), + force); + texgen_func[si] = &texgen_texmat; + { + CPT(TransformState) render_transform = + _cs_transform->compose(_scene_setup->get_world_transform()); + CPT(TransformState) world_transform = + _internal_transform->invert_compose(render_transform); + tcdata[si]._mat = world_transform->get_mat(); + } + if (target_tex_matrix->has_stage(stage)) { + tcdata[si]._mat = tcdata[si]._mat * target_tex_matrix->get_mat(stage); + } + break; + + default: + // Fall through: use the standard texture coordinates. + tcdata[si]._r1 = GeomVertexReader(data_reader, stage->get_texcoord_name(), + force); + texgen_func[si] = &texgen_simple; + if (target_tex_matrix->has_stage(stage)) { + texgen_func[si] = &texgen_texmat; + tcdata[si]._mat = target_tex_matrix->get_mat(stage); + } + + break; + } + tcdata[si]._r1.set_row(_min_vertex); + tcdata[si]._r2.set_row(_min_vertex); + if (!tcdata[si]._r1.has_column()) { + texgen_func[si] = &texgen_null; } } @@ -722,18 +767,8 @@ begin_draw_primitives(const GeomPipelineReader *geom_reader, // Texture coordinates. for (int si = 0; si < max_stage_index; ++si) { - if (needs_texmat[si]) { - // Transform texcoords as a four-component vector for most generality. - LVecBase4f d = rtexcoord[si].get_data4f() * texmat[si]; - v->tex_coord[si].v[0] = d[0]; - v->tex_coord[si].v[1] = d[1]; - - } else if (needs_texcoord[si]) { - // No need to transform, so just extract as two-component. - const LVecBase2f &d = rtexcoord[si].get_data2f(); - v->tex_coord[si].v[0] = d[0]; - v->tex_coord[si].v[1] = d[1]; - } + TexCoordf d; + (*texgen_func[si])(v->tex_coord[si], tcdata[si]); } if (needs_color) { @@ -2974,3 +3009,76 @@ get_tex_filter_func(Texture::FilterType filter) { } } +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsStateGuardian::texgen_null +// Access: Private, Static +// Description: Generates invalid texture coordinates. Used when +// texture coordinate params are invalid or unsupported. +//////////////////////////////////////////////////////////////////// +void TinyGraphicsStateGuardian:: +texgen_null(V2 &result, TinyGraphicsStateGuardian::TexCoordData &) { + result.v[0] = 0.0; + result.v[1] = 0.0; +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsStateGuardian::texgen_simple +// Access: Private, Static +// Description: Extracts a simple 2-d texture coordinate pair from +// the vertex data, without applying any texture matrix. +//////////////////////////////////////////////////////////////////// +void TinyGraphicsStateGuardian:: +texgen_simple(V2 &result, TinyGraphicsStateGuardian::TexCoordData &tcdata) { + // No need to transform, so just extract as two-component. + const LVecBase2f &d = tcdata._r1.get_data2f(); + result.v[0] = d[0]; + result.v[1] = d[1]; +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsStateGuardian::texgen_simple +// Access: Private, Static +// Description: Extracts a simple 2-d texture coordinate pair from +// the vertex data, and then applies a texture matrix. +//////////////////////////////////////////////////////////////////// +void TinyGraphicsStateGuardian:: +texgen_texmat(V2 &result, TinyGraphicsStateGuardian::TexCoordData &tcdata) { + // Transform texcoords as a four-component vector for most generality. + LVecBase4f d = tcdata._r1.get_data4f() * tcdata._mat; + result.v[0] = d[0] / d[3]; + result.v[1] = d[1] / d[3]; +} + +//////////////////////////////////////////////////////////////////// +// Function: TinyGraphicsStateGuardian::texgen_sphere_map +// Access: Private, Static +// Description: Computes appropriate sphere map texture coordinates +// based on the eye normal coordinates. +//////////////////////////////////////////////////////////////////// +void TinyGraphicsStateGuardian:: +texgen_sphere_map(V2 &result, TinyGraphicsStateGuardian::TexCoordData &tcdata) { + // Get the normal and point in eye coordinates. + LVector3f n = tcdata._mat.xform_vec(tcdata._r1.get_data3f()); + LVector3f u = tcdata._mat.xform_point(tcdata._r2.get_data3f()); + + // Normalize the vectors. + n.normalize(); + u.normalize(); + + // Compute the reflection vector. + LVector3f r = u - n * dot(n, u) * 2.0f; + + // compute the denominator, m. + float m = 2.0f * csqrt(r[0] * r[0] + r[1] * r[1] + (r[2] + 1.0f) * (r[2] + 1.0f)); + + // Now we can compute the s and t coordinates. + result.v[0] = r[0] / m + 0.5f; + result.v[1] = r[1] / m + 0.5f; + + /* + cerr << "n = " << n << " u = " << u << "\n" + << " r = " << r << "\n" + << " m = " << m << ", result = " << result.v[0] << " " << result.v[1] + << "\n"; + */ +} diff --git a/panda/src/tinydisplay/tinyGraphicsStateGuardian.h b/panda/src/tinydisplay/tinyGraphicsStateGuardian.h index 480af90e40..77051f560f 100644 --- a/panda/src/tinydisplay/tinyGraphicsStateGuardian.h +++ b/panda/src/tinydisplay/tinyGraphicsStateGuardian.h @@ -23,6 +23,7 @@ #include "zmath.h" #include "zbuffer.h" #include "zgl.h" +#include "geomVertexReader.h" class TinyTextureContext; @@ -127,6 +128,19 @@ private: INLINE void clear_light_state(); + // Methods used to generate texture coordinates. + class TexCoordData { + public: + GeomVertexReader _r1; + GeomVertexReader _r2; + LMatrix4f _mat; + }; + typedef void GenTexcoordFunc(V2 &result, TexCoordData &tcdata); + + static void texgen_null(V2 &result, TexCoordData &tcdata); + static void texgen_simple(V2 &result, TexCoordData &tcdata); + static void texgen_texmat(V2 &result, TexCoordData &tcdata); + static void texgen_sphere_map(V2 &result, TexCoordData &tcdata); public: // Filled in by the Tiny*GraphicsWindow at begin_frame(). ZBuffer *_current_frame_buffer; diff --git a/panda/src/tinydisplay/zgl.h b/panda/src/tinydisplay/zgl.h index 78e8a4300d..a479f67281 100644 --- a/panda/src/tinydisplay/zgl.h +++ b/panda/src/tinydisplay/zgl.h @@ -105,7 +105,7 @@ typedef struct GLVertex { int edge_flag; V3 normal; V4 coord; - V4 tex_coord[MAX_TEXTURE_STAGES]; + V2 tex_coord[MAX_TEXTURE_STAGES]; V4 color; /* computed values */ diff --git a/panda/src/tinydisplay/zmath.h b/panda/src/tinydisplay/zmath.h index 6387085a79..2bd4cd3422 100644 --- a/panda/src/tinydisplay/zmath.h +++ b/panda/src/tinydisplay/zmath.h @@ -15,6 +15,10 @@ typedef struct { float m[3][4]; } M34; +typedef struct { + float v[2]; +} V2; + typedef struct { float v[3]; } V3;