David Rose 17 years ago
parent
commit
a9825fe78f

+ 135 - 27
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()));
+    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)) {
-        needs_texmat[si] = true;
-        texmat[si] = target_tex_matrix->get_mat(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";
+  */
+}

+ 14 - 0
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;

+ 1 - 1
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 */

+ 4 - 0
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;