Browse Source

remove some API

David Rose 17 years ago
parent
commit
ebee79a58e

+ 9 - 15
panda/src/tinydisplay/clip.c

@@ -23,19 +23,12 @@ void gl_transform_to_viewport(GLContext *c,GLVertex *v)
   v->zp.z= (int) ( v->pc.Z * winv * c->viewport.scale.Z 
                    + c->viewport.trans.Z );
   /* color */
-  if (c->lighting_enabled) {
-      v->zp.r=(int)(v->color.v[0] * (ZB_POINT_RED_MAX - ZB_POINT_RED_MIN) 
-                    + ZB_POINT_RED_MIN);
-      v->zp.g=(int)(v->color.v[1] * (ZB_POINT_GREEN_MAX - ZB_POINT_GREEN_MIN) 
-                    + ZB_POINT_GREEN_MIN);
-      v->zp.b=(int)(v->color.v[2] * (ZB_POINT_BLUE_MAX - ZB_POINT_BLUE_MIN) 
-                    + ZB_POINT_BLUE_MIN);
-  } else {
-      /* no need to convert to integer if no lighting : take current color */
-      v->zp.r = c->longcurrent_color[0];
-      v->zp.g = c->longcurrent_color[1];
-      v->zp.b = c->longcurrent_color[2];
-  }
+  v->zp.r=(int)(v->color.v[0] * (ZB_POINT_RED_MAX - ZB_POINT_RED_MIN) 
+                + ZB_POINT_RED_MIN);
+  v->zp.g=(int)(v->color.v[1] * (ZB_POINT_GREEN_MAX - ZB_POINT_GREEN_MIN) 
+                + ZB_POINT_GREEN_MIN);
+  v->zp.b=(int)(v->color.v[2] * (ZB_POINT_BLUE_MAX - ZB_POINT_BLUE_MIN) 
+                + ZB_POINT_BLUE_MIN);
   
   /* texture */
 
@@ -295,7 +288,7 @@ static void gl_draw_triangle_clip(GLContext *c,
   int co,c_and,co1,cc[3],edge_flag_tmp,clip_mask;
   GLVertex tmp1,tmp2,*q[3];
   float tt;
-  
+
   cc[0]=p0->clip_code;
   cc[1]=p1->clip_code;
   cc[2]=p2->clip_code;
@@ -405,7 +398,8 @@ void gl_draw_triangle_fill(GLContext *c,
     count_triangles_textured++;
 #endif
     ZB_setTexture(c->zb,c->current_texture->images[0].pixmap);
-    ZB_fillTriangleMappingPerspective(c->zb,&p0->zp,&p1->zp,&p2->zp);
+    //ZB_fillTriangleMappingPerspective(c->zb,&p0->zp,&p1->zp,&p2->zp);
+    ZB_fillTriangleMappingSmooth(c->zb,&p0->zp,&p1->zp,&p2->zp);
   } else if (c->current_shade_model == GL_SMOOTH) {
     ZB_fillTriangleSmooth(c->zb,&p0->zp,&p1->zp,&p2->zp);
   } else {

+ 20 - 2
panda/src/tinydisplay/image_util.c

@@ -28,12 +28,30 @@ void gl_convertRGB_to_8A8R8G8B(unsigned int *pixmap, unsigned char *rgb,
     n=xsize*ysize;
     for(i=0;i<n;i++) {
         pixmap[i]=(((unsigned int)p[0])<<16) | 
-            (((unsigned int)p[1])<<8) | 
-            (((unsigned int)p[2])); 
+          (((unsigned int)p[1])<<8) | 
+          ((unsigned int)p[2]) | 
+          0xff000000; 
         p+=3;
     }
 }
 
+void gl_convertRGBA_to_8A8R8G8B(unsigned int *pixmap, unsigned char *rgb,
+                               int xsize, int ysize)
+{
+    int i,n;
+    unsigned char *p;
+    
+    p=rgb;
+    n=xsize*ysize;
+    for(i=0;i<n;i++) {
+        pixmap[i]=(((unsigned int)p[0])<<16) | 
+          (((unsigned int)p[1])<<8) | 
+          ((unsigned int)p[2]) |
+          (((unsigned int)p[3])<<24);
+        p+=4;
+    }
+}
+
 /*
  * linear interpolation with xf,yf normalized to 2^16
  */

+ 27 - 15
panda/src/tinydisplay/texture.c

@@ -135,25 +135,33 @@ void glopTexImage2D(GLContext *c,GLParam *p)
   GLImage *im;
   unsigned char *pixels1;
   int do_free;
+  
+  if ((target == GL_TEXTURE_2D && level == 0 && components == 3 && 
+       border == 0 && format == GL_RGB &&
+       type == GL_UNSIGNED_BYTE)) {
+    do_free=0;
+    if (width != 256 || height != 256) {
+      pixels1 = gl_malloc(256 * 256 * 3);
+      /* no interpolation is done here to respect the original image aliasing ! */
+      gl_resizeImageNoInterpolate(pixels1,256,256,pixels,width,height);
+      do_free=1;
+      width=256;
+      height=256;
+    } else {
+      pixels1=pixels;
+    }
 
-  if (!(target == GL_TEXTURE_2D && level == 0 && components == 3 && 
-        border == 0 && format == GL_RGB &&
-        type == GL_UNSIGNED_BYTE)) {
+#if TGL_FEATURE_RENDER_BITS == 32
+  } else if ((target == GL_TEXTURE_2D && level == 0 && components == 4 && 
+       border == 0 && format == GL_RGBA &&
+       type == GL_UNSIGNED_BYTE && width == 256 && height == 256)) {
+    // RGBA format is acceptable if we have 32 render bits.
+#endif
+
+  } else {
     gl_fatal_error("glTexImage2D: combinaison of parameters not handled");
   }
   
-  do_free=0;
-  if (width != 256 || height != 256) {
-    pixels1 = gl_malloc(256 * 256 * 3);
-    /* no interpolation is done here to respect the original image aliasing ! */
-    gl_resizeImageNoInterpolate(pixels1,256,256,pixels,width,height);
-    do_free=1;
-    width=256;
-    height=256;
-  } else {
-    pixels1=pixels;
-  }
-
   im=&c->current_texture->images[level];
   im->xsize=width;
   im->ysize=height;
@@ -166,7 +174,11 @@ void glopTexImage2D(GLContext *c,GLParam *p)
 #elif TGL_FEATURE_RENDER_BITS == 32
   im->pixmap=gl_malloc(width*height*4);
   if(im->pixmap) {
+    if (components == 4) {
+      gl_convertRGBA_to_8A8R8G8B(im->pixmap,pixels1,width,height);
+    } else {
       gl_convertRGB_to_8A8R8G8B(im->pixmap,pixels1,width,height);
+    }
   }
 #elif TGL_FEATURE_RENDER_BITS == 16
   im->pixmap=gl_malloc(width*height*2);

+ 369 - 93
panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx

@@ -22,6 +22,11 @@
 #include "config_tinydisplay.h"
 #include "pStatTimer.h"
 
+extern "C" {
+#include "zgl.h"
+#include "zmath.h"
+}
+
 TypeHandle TinyGraphicsStateGuardian::_type_handle;
 
 PStatCollector TinyGraphicsStateGuardian::_vertices_immediate_pcollector("Vertices:Immediate mode");
@@ -160,6 +165,67 @@ restructure_image(Texture *tex) {
   return new_image;
 }
 
+static inline void tgl_vertex_transform(GLContext * c, GLVertex * v)
+{
+    float *m;
+    V4 *n;
+
+    if (c->lighting_enabled) {
+	/* eye coordinates needed for lighting */
+
+	m = &c->matrix_stack_ptr[0]->m[0][0];
+	v->ec.X = (v->coord.X * m[0] + v->coord.Y * m[1] +
+		   v->coord.Z * m[2] + m[3]);
+	v->ec.Y = (v->coord.X * m[4] + v->coord.Y * m[5] +
+		   v->coord.Z * m[6] + m[7]);
+	v->ec.Z = (v->coord.X * m[8] + v->coord.Y * m[9] +
+		   v->coord.Z * m[10] + m[11]);
+	v->ec.W = (v->coord.X * m[12] + v->coord.Y * m[13] +
+		   v->coord.Z * m[14] + m[15]);
+
+	/* projection coordinates */
+	m = &c->matrix_stack_ptr[1]->m[0][0];
+	v->pc.X = (v->ec.X * m[0] + v->ec.Y * m[1] +
+		   v->ec.Z * m[2] + v->ec.W * m[3]);
+	v->pc.Y = (v->ec.X * m[4] + v->ec.Y * m[5] +
+		   v->ec.Z * m[6] + v->ec.W * m[7]);
+	v->pc.Z = (v->ec.X * m[8] + v->ec.Y * m[9] +
+		   v->ec.Z * m[10] + v->ec.W * m[11]);
+	v->pc.W = (v->ec.X * m[12] + v->ec.Y * m[13] +
+		   v->ec.Z * m[14] + v->ec.W * m[15]);
+
+	m = &c->matrix_model_view_inv.m[0][0];
+	n = &c->current_normal;
+
+	v->normal.X = (n->X * m[0] + n->Y * m[1] + n->Z * m[2]);
+	v->normal.Y = (n->X * m[4] + n->Y * m[5] + n->Z * m[6]);
+	v->normal.Z = (n->X * m[8] + n->Y * m[9] + n->Z * m[10]);
+
+	if (c->normalize_enabled) {
+	    gl_V3_Norm(&v->normal);
+	}
+    } else {
+	/* no eye coordinates needed, no normal */
+	/* NOTE: W = 1 is assumed */
+	m = &c->matrix_model_projection.m[0][0];
+
+	v->pc.X = (v->coord.X * m[0] + v->coord.Y * m[1] +
+		   v->coord.Z * m[2] + m[3]);
+	v->pc.Y = (v->coord.X * m[4] + v->coord.Y * m[5] +
+		   v->coord.Z * m[6] + m[7]);
+	v->pc.Z = (v->coord.X * m[8] + v->coord.Y * m[9] +
+		   v->coord.Z * m[10] + m[11]);
+	if (c->matrix_model_projection_no_w_transform) {
+	    v->pc.W = m[15];
+	} else {
+	    v->pc.W = (v->coord.X * m[12] + v->coord.Y * m[13] +
+		       v->coord.Z * m[14] + m[15]);
+	}
+    }
+
+    v->clip_code = gl_clipcode(v->pc.X, v->pc.Y, v->pc.Z, v->pc.W);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: TinyGraphicsStateGuardian::Constructor
 //       Access: Public
@@ -170,6 +236,9 @@ TinyGraphicsStateGuardian(GraphicsPipe *pipe,
 			 TinyGraphicsStateGuardian *share_with) :
   GraphicsStateGuardian(CS_yup_right, pipe)
 {
+  _c = NULL;
+  _vertices = NULL;
+  _vertices_size = 0;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -192,6 +261,11 @@ reset() {
   free_pointers();
   GraphicsStateGuardian::reset();
 
+  _c = gl_get_context();
+
+  _c->draw_triangle_front = gl_draw_triangle_fill;
+  _c->draw_triangle_back = gl_draw_triangle_fill;
+
   _supported_geom_rendering =
     Geom::GR_point | 
     Geom::GR_indexed_other |
@@ -212,6 +286,21 @@ reset() {
   add_gsg(this);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: TinyGraphicsStateGuardian::free_pointers
+//       Access: Protected, Virtual
+//  Description: Frees some memory that was explicitly allocated
+//               within the glgsg.
+////////////////////////////////////////////////////////////////////
+void TinyGraphicsStateGuardian::
+free_pointers() {
+  if (_vertices != (GLVertex *)NULL) {
+    PANDA_FREE_ARRAY(_vertices);
+    _vertices = NULL;
+  }
+  _vertices_size = 0;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: TinyGraphicsStateGuardian::make_geom_munger
 //       Access: Public, Virtual
@@ -277,12 +366,31 @@ prepare_display_region(DisplayRegionPipelineReader *dr,
 
   int l, b, w, h;
   dr->get_region_pixels(l, b, w, h);
-  GLint x = GLint(l);
-  GLint y = GLint(b);
-  GLsizei width = GLsizei(w);
-  GLsizei height = GLsizei(h);
+  int xmin = GLint(l);
+  int ymin = GLint(b);
+  int xsize = GLsizei(w);
+  int ysize = GLsizei(h);
+  
+  int xsize_req=xmin+xsize;
+  int ysize_req=ymin+ysize;
+  
+  if (_c->gl_resize_viewport && 
+      _c->gl_resize_viewport(_c,&xsize_req,&ysize_req) != 0) {
+    gl_fatal_error("glViewport: error while resizing display");
+  }
   
-  glViewport(x, y, width, height);
+  xsize=xsize_req-xmin;
+  ysize=ysize_req-ymin;
+  if (xsize <= 0 || ysize <= 0) {
+    gl_fatal_error("glViewport: size too small");
+  }
+  
+  _c->viewport.xmin=xmin;
+  _c->viewport.ymin=ymin;
+  _c->viewport.xsize=xsize;
+  _c->viewport.ysize=ysize;
+  
+  gl_eval_viewport(_c);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -341,13 +449,7 @@ calc_projection_mat(const Lens *lens) {
 ////////////////////////////////////////////////////////////////////
 bool TinyGraphicsStateGuardian::
 prepare_lens() {
-  if (tinydisplay_cat.is_spam()) {
-    tinydisplay_cat.spam()
-      << "glLoadMatrix(GL_PROJECTION): " << _projection_mat->get_mat() << endl;
-  }
-  glMatrixMode(GL_PROJECTION);
-  glLoadMatrixf(_projection_mat->get_mat().get_data());
-
+  _transform_stale = true;
   return true;
 }
 
@@ -451,47 +553,191 @@ begin_draw_primitives(const GeomPipelineReader *geom_reader,
   }
   nassertr(_data_reader != (GeomVertexDataPipelineReader *)NULL, false);
 
-  // We must use immediate mode to render primitives.
-  _sender.clear();
+  // Set up the proper transform.
+  if (_data_reader->is_vertex_transformed()) {
+    // If the vertex data claims to be already transformed into clip
+    // coordinates, wipe out the current projection and modelview
+    // matrix (so we don't attempt to transform it again).
+    const TransformState *ident = TransformState::make_identity();
+    load_matrix(_c->matrix_stack_ptr[0], ident);
+    load_matrix(_c->matrix_stack_ptr[1], ident);
+    load_matrix(&_c->matrix_model_view_inv, ident);
+    load_matrix(&_c->matrix_model_projection, ident);
+    _c->matrix_model_projection_no_w_transform = 1;
+    _transform_stale = true;
+
+  } else if (_transform_stale) {
+    // Load the actual transform.
 
-  _sender.add_column(_data_reader, InternalName::get_normal(),
-                     NULL, NULL, glNormal3f, NULL);
-  if (!_sender.add_column(_data_reader, InternalName::get_color(),
-                          NULL, NULL, glColor3f, glColor4f)) {
-    // If we didn't have a color column, the item color is white.
-    glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+    if (_c->lighting_enabled) {
+      // With the lighting equation, we need to keep the modelview and
+      // projection matrices separate.
+
+      load_matrix(_c->matrix_stack_ptr[0], _internal_transform);
+      load_matrix(_c->matrix_stack_ptr[1], _projection_mat);
+
+      /* precompute inverse modelview */
+      M4 tmp;
+      gl_M4_Inv(&tmp, _c->matrix_stack_ptr[0]);
+      gl_M4_Transpose(&_c->matrix_model_view_inv, &tmp);
+
+    } else {
+      // If we're not using lighting, go ahead and compose the
+      // modelview and projection matrices.
+      load_matrix(&_c->matrix_model_projection, 
+                  _projection_mat->compose(_internal_transform));
+
+      /* test to accelerate computation */
+      _c->matrix_model_projection_no_w_transform = 0;
+      float *m = &_c->matrix_model_projection.m[0][0];
+      if (m[12] == 0.0 && m[13] == 0.0 && m[14] == 0.0) {
+        _c->matrix_model_projection_no_w_transform = 1;
+      }
+    }
+    _transform_stale = false;
+  }
+   
+  /* test if the texture matrix is not Identity */
+  //  _c->apply_texture_matrix = !gl_M4_IsId(_c->matrix_stack_ptr[2]);
+
+  // Figure out the subset of vertices we will be using in this
+  // operation.
+  int num_vertices = data_reader->get_num_rows();
+  _min_vertex = num_vertices;
+  _max_vertex = 0;
+  int num_prims = geom_reader->get_num_primitives();
+  int i;
+  for (i = 0; i < num_prims; ++i) {
+    CPT(GeomPrimitive) prim = geom_reader->get_primitive(i);
+    int nv = prim->get_min_vertex();
+    _min_vertex = min(_min_vertex, nv);
+    int xv = prim->get_max_vertex();
+    _max_vertex = max(_max_vertex, xv);
+  }
+  if (_min_vertex > _max_vertex) {
+    return false;
+  }
+
+  // Now copy all of those vertices into our working table,
+  // transforming into screen space them as we go.
+  int num_used_vertices = _max_vertex - _min_vertex + 1;
+  if (_vertices_size < num_used_vertices) {
+    if (_vertices_size == 0) {
+      _vertices_size = 1;
+    }
+    while (_vertices_size < num_used_vertices) {
+      _vertices_size *= 2;
+    }
+    if (_vertices != (GLVertex *)NULL) {
+      PANDA_FREE_ARRAY(_vertices);
+    }
+    _vertices = (GLVertex *)PANDA_MALLOC_ARRAY(_vertices_size * sizeof(GLVertex));
   }
 
-  // TinyGL only supports single-texturing, so only bother with the
-  // first texture stage.
+  GeomVertexReader rtexcoord, rcolor, rnormal;
+
+  // We only support single-texturing, so only bother with the first
+  // texture stage.
+  bool needs_texcoord = false;
+  const InternalName *texcoord_name = InternalName::get_texcoord();
   int max_stage_index = _effective_texture->get_num_on_ff_stages();
   if (max_stage_index > 0) {
     TextureStage *stage = _effective_texture->get_on_ff_stage(0);
-    const InternalName *name = stage->get_texcoord_name();
-    _sender.add_column(_data_reader, name,
-                       NULL, glTexCoord2f, NULL, NULL);
+    rtexcoord = GeomVertexReader(data_reader, stage->get_texcoord_name());
+    rtexcoord.set_row(_min_vertex);
+    needs_texcoord = rtexcoord.has_column();
   }
 
-  // We must add vertex last, because glVertex3f() is the key
-  // function call that actually issues the vertex.
-  _sender.add_column(_data_reader, InternalName::get_vertex(),
-                     NULL, glVertex2f, glVertex3f, glVertex4f);
+  bool needs_color = false;
+  if (_vertex_colors_enabled) {
+    rcolor = GeomVertexReader(data_reader, InternalName::get_color());
+    rcolor.set_row(_min_vertex);
+    needs_color = rcolor.has_column();
+  }
 
-  if (_transform_stale) {
-    glMatrixMode(GL_MODELVIEW);
-    glLoadMatrixf(_internal_transform->get_mat().get_data());
+  if (!needs_color) {
+    if (_has_scene_graph_color) {
+      cerr << "sg color\n";
+      const Colorf &d = _scene_graph_color;
+      _c->current_color.X = d[0];
+      _c->current_color.Y = d[1];
+      _c->current_color.Z = d[2];
+      _c->current_color.W = d[3];
+      
+    } else {
+      _c->current_color.X = 1.0f;
+      _c->current_color.Y = 1.0f;
+      _c->current_color.Z = 1.0f;
+      _c->current_color.W = 1.0f;
+    }
   }
 
-  if (_data_reader->is_vertex_transformed()) {
-    // If the vertex data claims to be already transformed into clip
-    // coordinates, wipe out the current projection and modelview
-    // matrix (so we don't attempt to transform it again).
-    glMatrixMode(GL_PROJECTION);
-    glPushMatrix();
-    glLoadIdentity();
-    glMatrixMode(GL_MODELVIEW);
-    glPushMatrix();
-    glLoadIdentity();
+  bool needs_normal = false;
+  if (_c->lighting_enabled) {
+    rnormal = GeomVertexReader(data_reader, InternalName::get_normal());
+    rnormal.set_row(_min_vertex);
+    needs_normal = rnormal.has_column();
+  }
+
+  GeomVertexReader rvertex(data_reader, InternalName::get_vertex()); 
+  rvertex.set_row(_min_vertex);
+
+  for (i = 0; i < num_used_vertices; ++i) {
+    GLVertex *v = &_vertices[i];
+    const LVecBase4f &d = rvertex.get_data4f();
+    
+    v->coord.X = d[0];
+    v->coord.Y = d[1];
+    v->coord.Z = d[2];
+    v->coord.W = d[3];
+
+    if (needs_texcoord) {
+      const LVecBase2f &d = rtexcoord.get_data2f();
+      v->tex_coord.X = d[0];
+      v->tex_coord.Y = d[1];
+    }
+
+    if (needs_color) {
+      const Colorf &d = rcolor.get_data4f();
+      _c->current_color.X = d[0];
+      _c->current_color.Y = d[1];
+      _c->current_color.Z = d[2];
+      _c->current_color.W = d[3];
+
+      if (_c->color_material_enabled) {
+	GLParam q[7];
+	q[0].op = OP_Material;
+	q[1].i = _c->current_color_material_mode;
+	q[2].i = _c->current_color_material_type;
+	q[3].f = d[0];
+	q[4].f = d[1];
+	q[5].f = d[2];
+	q[6].f = d[3];
+	glopMaterial(_c, q);
+      }
+    }
+
+    v->color = _c->current_color;
+
+    if (needs_normal) {
+      const LVecBase3f &d = rnormal.get_data3f();
+      _c->current_normal.X = d[0];
+      _c->current_normal.Y = d[1];
+      _c->current_normal.Z = d[2];
+      _c->current_normal.W = 0.0f;
+    }
+
+    tgl_vertex_transform(_c, v);
+
+    if (_c->lighting_enabled) {
+      gl_shade_vertex(_c, v);
+    }
+
+    if (v->clip_code == 0) {
+      gl_transform_to_viewport(_c, v);
+    }
+
+    v->edge_flag = 0;
   }
 
   return true;
@@ -512,7 +758,27 @@ draw_triangles(const GeomPrimitivePipelineReader *reader, bool force) {
   }
 #endif  // NDEBUG
 
-  draw_immediate_simple_primitives(reader, GL_TRIANGLES);
+  int num_vertices = reader->get_num_vertices();
+  _vertices_immediate_pcollector.add_level(num_vertices);
+
+  if (reader->is_indexed()) {
+    for (int i = 0; i < num_vertices; i += 3) {
+      GLVertex *v0 = &_vertices[reader->get_vertex(i) - _min_vertex];
+      GLVertex *v1 = &_vertices[reader->get_vertex(i + 1) - _min_vertex];
+      GLVertex *v2 = &_vertices[reader->get_vertex(i + 2) - _min_vertex];
+      gl_draw_triangle(_c, v0, v1, v2);
+    }
+
+  } else {
+    int delta = reader->get_first_vertex() - _min_vertex;
+    for (int vi = 0; vi < num_vertices; vi += 3) {
+      GLVertex *v0 = &_vertices[vi + delta];
+      GLVertex *v1 = &_vertices[vi + delta + 1];
+      GLVertex *v2 = &_vertices[vi + delta + 2];
+      gl_draw_triangle(_c, v0, v1, v2);
+    }
+  }
+
   return true;
 }
 
@@ -530,7 +796,25 @@ draw_lines(const GeomPrimitivePipelineReader *reader, bool force) {
   }
 #endif  // NDEBUG
 
-  draw_immediate_simple_primitives(reader, GL_LINES);
+  int num_vertices = reader->get_num_vertices();
+  _vertices_immediate_pcollector.add_level(num_vertices);
+
+  if (reader->is_indexed()) {
+    for (int i = 0; i < num_vertices; i += 2) {
+      GLVertex *v0 = &_vertices[reader->get_vertex(i) - _min_vertex];
+      GLVertex *v1 = &_vertices[reader->get_vertex(i + 1) - _min_vertex];
+      gl_draw_line(_c, v0, v1);
+    }
+
+  } else {
+    int delta = reader->get_first_vertex() - _min_vertex;
+    for (int vi = 0; vi < num_vertices; vi += 2) {
+      GLVertex *v0 = &_vertices[vi + delta];
+      GLVertex *v1 = &_vertices[vi + delta + 1];
+      gl_draw_line(_c, v0, v1);
+    }
+  }
+
   return true;
 }
 
@@ -548,7 +832,23 @@ draw_points(const GeomPrimitivePipelineReader *reader, bool force) {
   }
 #endif  // NDEBUG
 
-  draw_immediate_simple_primitives(reader, GL_POINTS);
+  int num_vertices = reader->get_num_vertices();
+  _vertices_immediate_pcollector.add_level(num_vertices);
+
+  if (reader->is_indexed()) {
+    for (int i = 0; i < num_vertices; ++i) {
+      GLVertex *v0 = &_vertices[reader->get_vertex(i) - _min_vertex];
+      gl_draw_point(_c, v0);
+    }
+
+  } else {
+    int delta = reader->get_first_vertex() - _min_vertex;
+    for (int vi = 0; vi < num_vertices; ++vi) {
+      GLVertex *v0 = &_vertices[vi + delta];
+      gl_draw_point(_c, v0);
+    }
+  }
+
   return true;
 }
 
@@ -561,19 +861,6 @@ draw_points(const GeomPrimitivePipelineReader *reader, bool force) {
 ////////////////////////////////////////////////////////////////////
 void TinyGraphicsStateGuardian::
 end_draw_primitives() {
-  if (_transform_stale) {
-    glMatrixMode(GL_MODELVIEW);
-    glLoadMatrixf(_internal_transform->get_mat().get_data());
-  }
-
-  if (_data_reader->is_vertex_transformed()) {
-    // Restore the matrices that we pushed above.
-    glMatrixMode(GL_PROJECTION);
-    glPopMatrix();
-    glMatrixMode(GL_MODELVIEW);
-    glPopMatrix();
-  }
-
   GraphicsStateGuardian::end_draw_primitives();
 }
 
@@ -854,9 +1141,11 @@ begin_bind_lights() {
   CPT(TransformState) render_transform =
     _cs_transform->compose(_scene_setup->get_world_transform());
 
+  /*
   glMatrixMode(GL_MODELVIEW);
   glPushMatrix();
   glLoadMatrixf(render_transform->get_mat().get_data());
+  */
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -872,9 +1161,11 @@ void TinyGraphicsStateGuardian::
 end_bind_lights() {
   static PStatCollector _draw_set_state_light_end_bind_pcollector("Draw:Set State:Light:End bind");
   PStatTimer timer(_draw_set_state_light_end_bind_pcollector);
-  
+
+  /*
   glMatrixMode(GL_MODELVIEW);
   glPopMatrix();
+  */
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -888,16 +1179,8 @@ end_bind_lights() {
 ////////////////////////////////////////////////////////////////////
 void TinyGraphicsStateGuardian::
 do_issue_transform() {
-  const TransformState *transform = _internal_transform;
-  if (tinydisplay_cat.is_spam()) {
-    tinydisplay_cat.spam()
-      << "glLoadMatrix(GL_MODELVIEW): " << transform->get_mat() << endl;
-  }
-
   _transform_state_pcollector.add_level(1);
-  glMatrixMode(GL_MODELVIEW);
-  glLoadMatrixf(transform->get_mat().get_data());
-  _transform_stale = false;
+  _transform_stale = true;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -931,15 +1214,18 @@ do_issue_render_mode() {
   switch (attrib->get_mode()) {
   case RenderModeAttrib::M_unchanged:
   case RenderModeAttrib::M_filled:
-    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+    _c->draw_triangle_front = gl_draw_triangle_fill;
+    _c->draw_triangle_back = gl_draw_triangle_fill;
     break;
 
   case RenderModeAttrib::M_wireframe:
-    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+    _c->draw_triangle_front = gl_draw_triangle_line;
+    _c->draw_triangle_back = gl_draw_triangle_line;
     break;
 
   case RenderModeAttrib::M_point:
-    glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
+    _c->draw_triangle_front = gl_draw_triangle_point;
+    _c->draw_triangle_back = gl_draw_triangle_point;
     break;
 
   default:
@@ -1281,29 +1567,19 @@ upload_texture(TinyTextureContext *gtc) {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: TinyGraphicsStateGuardian::draw_immediate_simple_primitives
-//       Access: Private
-//  Description: Uses the ImmediateModeSender to draw a series of
-//               primitives of the indicated type.
+//     Function: TinyGraphicsStateGuardian::load_matrix
+//       Access: Private, Static
+//  Description: Copies the Panda matrix stored in the indicated
+//               TransformState object into the indicated TinyGL
+//               matrix.
 ////////////////////////////////////////////////////////////////////
 void TinyGraphicsStateGuardian::
-draw_immediate_simple_primitives(const GeomPrimitivePipelineReader *reader, GLenum mode) {
-  int num_vertices = reader->get_num_vertices();
-  _vertices_immediate_pcollector.add_level(num_vertices);
-  glBegin(mode);
-
-  if (reader->is_indexed()) {
-    for (int v = 0; v < num_vertices; ++v) {
-      _sender.set_vertex(reader->get_vertex(v));
-      _sender.issue_vertex();
-    }
-
-  } else {
-    _sender.set_vertex(reader->get_first_vertex());
-    for (int v = 0; v < num_vertices; ++v) {
-      _sender.issue_vertex();
-    }
+load_matrix(M4 *matrix, const TransformState *transform) {
+  const LMatrix4f &pm = transform->get_mat();
+  for (int i = 0; i < 4; ++i) {
+    matrix->m[0][i] = pm.get_cell(i, 0);
+    matrix->m[1][i] = pm.get_cell(i, 1);
+    matrix->m[2][i] = pm.get_cell(i, 2);
+    matrix->m[3][i] = pm.get_cell(i, 3);
   }
-
-  glEnd();
 }

+ 16 - 2
panda/src/tinydisplay/tinyGraphicsStateGuardian.h

@@ -26,7 +26,14 @@
 #include "tinyImmediateModeSender.h"
 #include "tinygl.h"
 
+extern "C" {
+  #include "zmath.h"
+}
+
 class TinyTextureContext;
+struct GLContext;
+struct GLVertex;
+
 
 ////////////////////////////////////////////////////////////////////
 //       Class : TinyGraphicsStateGuardian
@@ -41,6 +48,7 @@ public:
   virtual ~TinyGraphicsStateGuardian();
 
   virtual void reset();
+  virtual void free_pointers();
 
   virtual PT(GeomMunger) make_geom_munger(const RenderState *state,
                                           Thread *current_thread);
@@ -98,12 +106,18 @@ private:
   void apply_texture(TextureContext *tc);
   bool upload_texture(TinyTextureContext *gtc);
 
-  void draw_immediate_simple_primitives(const GeomPrimitivePipelineReader *reader, GLenum mode);
+  static void load_matrix(M4 *matrix, const TransformState *transform);
 
   INLINE static GLenum get_light_id(int index);
 
 private:
-  TinyImmediateModeSender _sender;
+  GLContext *_c;
+
+  // Used during being_draw_primitives() .. end_draw_primitives().
+  int _min_vertex;
+  int _max_vertex;
+  GLVertex *_vertices;
+  int _vertices_size;
 
   static PStatCollector _vertices_immediate_pcollector;
 

+ 17 - 0
panda/src/tinydisplay/zbuffer.h

@@ -34,6 +34,9 @@
 
 #define RGB_TO_PIXEL(r,g,b) \
   ((((r) >> 1) & 0x7c00) | (((g) >> 6) & 0x03e0) | ((b) >> 11))
+#define PIXEL_R(p) (((p) & 0x7c00) << 1)
+#define PIXEL_G(p) (((p) & 0x03e0) << 6)
+#define PIXEL_B(p) (((p) & 0x001f) << 11)
 typedef unsigned short PIXEL;
 /* bytes per pixel */
 #define PSZB 2 
@@ -45,6 +48,9 @@ typedef unsigned short PIXEL;
 /* 16 bit mode */
 #define RGB_TO_PIXEL(r,g,b) \
   (((r) & 0xF800) | (((g) >> 5) & 0x07E0) | ((b) >> 11))
+#define PIXEL_R(p) (((p) & 0xf800))
+#define PIXEL_G(p) (((p) & 0x07e0) << 5)
+#define PIXEL_B(p) (((p) & 0x001f) << 11)
 typedef unsigned short PIXEL;
 #define PSZB 2 
 #define PSZSH 4 
@@ -61,6 +67,9 @@ typedef unsigned char PIXEL;
 
 #define RGB_TO_PIXEL(r,g,b) \
   ((((r) << 8) & 0xff0000) | ((g) & 0xff00) | ((b) >> 8))
+#define PIXEL_R(p) (((p) & 0xff0000) >> 8)
+#define PIXEL_G(p) ((p) & 0xff00)
+#define PIXEL_B(p) (((p) & 0x00ff) << 8)
 typedef unsigned int PIXEL;
 #define PSZB 4
 #define PSZSH 5
@@ -71,6 +80,12 @@ typedef unsigned int PIXEL;
 
 #endif
 
+#define PIXEL_MULT(p1, p2) \
+  RGB_TO_PIXEL((PIXEL_R(p1) * PIXEL_R(p2)) >> 16, \
+               (PIXEL_G(p1) * PIXEL_G(p2)) >> 16, \
+               (PIXEL_B(p1) * PIXEL_B(p2)) >> 16)
+
+
 typedef struct {
     int xsize,ysize;
     int linesize; /* line size, in bytes */
@@ -140,6 +155,8 @@ void ZB_fillTriangleMapping(ZBuffer *zb,
 
 void ZB_fillTriangleMappingPerspective(ZBuffer *zb,
                     ZBufferPoint *p0,ZBufferPoint *p1,ZBufferPoint *p2);
+void ZB_fillTriangleMappingSmooth(ZBuffer *zb,
+                    ZBufferPoint *p0,ZBufferPoint *p1,ZBufferPoint *p2);
 
 
 typedef void (*ZB_fillTriangleFunc)(ZBuffer  *,

+ 8 - 8
panda/src/tinydisplay/zfeatures.h

@@ -1,11 +1,11 @@
 #ifndef _tgl_features_h_
 #define _tgl_features_h_
-
-/* Define BYTE_ORDER correctly where missing */
-#ifndef BYTE_ORDER
+
+/* Define BYTE_ORDER correctly where missing */
+#ifndef BYTE_ORDER
 #define LITTLE_ENDIAN	1234
 #define BIG_ENDIAN	4321
-
+
 #if (defined(__i386__) || defined(__i386)) || \
      defined(__ia64__) || defined(WIN32) || \
     (defined(__alpha__) || defined(__alpha)) || \
@@ -19,8 +19,8 @@
 #define BYTE_ORDER	BIG_ENDIAN
 #endif
 
-#endif
-
+#endif
+
 
 /* It is possible to enable/disable (compile time) features in this
    header file. */
@@ -57,8 +57,8 @@
 
 
 //#define TGL_FEATURE_RENDER_BITS    15
-#define TGL_FEATURE_RENDER_BITS    16
+//#define TGL_FEATURE_RENDER_BITS    16
 //#define TGL_FEATURE_RENDER_BITS    24
-//#define TGL_FEATURE_RENDER_BITS    32
+#define TGL_FEATURE_RENDER_BITS    32
 
 #endif /* _tgl_features_h_ */

+ 3 - 0
panda/src/tinydisplay/zgl.h

@@ -310,6 +310,9 @@ void glInitTextures(GLContext *c);
 void glEndTextures(GLContext *c);
 GLTexture *alloc_texture(GLContext *c,int h);
 
+/* vertex.c */
+void gl_eval_viewport(GLContext *c);
+
 /* image_util.c */
 void gl_convertRGB_to_5R6G5B(unsigned short *pixmap,unsigned char *rgb,
                              int xsize,int ysize);

+ 91 - 181
panda/src/tinydisplay/ztriangle.c

@@ -6,37 +6,10 @@
 void ZB_fillTriangleFlat(ZBuffer *zb,
 			 ZBufferPoint *p0,ZBufferPoint *p1,ZBufferPoint *p2)
 {
-#if TGL_FEATURE_RENDER_BITS == 24
-    unsigned char colorR, colorG, colorB;
-#else
     int color;
-#endif
 
 #define INTERP_Z
 
-#if TGL_FEATURE_RENDER_BITS == 24 
-
-#define DRAW_INIT()				\
-{						\
-  colorR=p2->r>>8; \
-  colorG=p2->g>>8; \
-  colorB=p2->b>>8; \
-}
-
-#define PUT_PIXEL(_a)		\
-{						\
-    zz=z >> ZB_POINT_Z_FRAC_BITS;		\
-    if (ZCMP(zz,pz[_a])) {				\
-      pp[3 * _a]=colorR;\
-      pp[3 * _a + 1]=colorG;\
-      pp[3 * _a + 2]=colorB;\
-      pz[_a]=zz;				\
-    }\
-    z+=dzdx;					\
-}
-
-#else
-
 #define DRAW_INIT()				\
 {						\
   color=RGB_TO_PIXEL(p2->r,p2->g,p2->b);	\
@@ -51,7 +24,6 @@ void ZB_fillTriangleFlat(ZBuffer *zb,
     }						\
     z+=dzdx;					\
 }
-#endif /* TGL_FEATURE_RENDER_BITS == 24 */
 
 #include "ztriangle.h"
 }
@@ -64,91 +36,11 @@ void ZB_fillTriangleFlat(ZBuffer *zb,
 void ZB_fillTriangleSmooth(ZBuffer *zb,
 			   ZBufferPoint *p0,ZBufferPoint *p1,ZBufferPoint *p2)
 {
-#if TGL_FEATURE_RENDER_BITS == 16
-        int _drgbdx;
-#endif
-
 #define INTERP_Z
 #define INTERP_RGB
 
 #define SAR_RND_TO_ZERO(v,n) (v / (1<<n))
 
-#if TGL_FEATURE_RENDER_BITS == 24
-
-#define DRAW_INIT() 				\
-{						\
-}
-
-#define PUT_PIXEL(_a)				\
-{						\
-    zz=z >> ZB_POINT_Z_FRAC_BITS;		\
-    if (ZCMP(zz,pz[_a])) {				\
-      pp[3 * _a]=or1 >> 8;\
-      pp[3 * _a + 1]=og1 >> 8;\
-      pp[3 * _a + 2]=ob1 >> 8;\
-      pz[_a]=zz;				\
-    }\
-    z+=dzdx;					\
-    og1+=dgdx;					\
-    or1+=drdx;					\
-    ob1+=dbdx;					\
-}
-
-#elif TGL_FEATURE_RENDER_BITS == 16
-
-#define DRAW_INIT() 				\
-{						\
-  _drgbdx=(SAR_RND_TO_ZERO(drdx,6) << 22) & 0xFFC00000;		\
-  _drgbdx|=SAR_RND_TO_ZERO(dgdx,5) & 0x000007FF;		\
-  _drgbdx|=(SAR_RND_TO_ZERO(dbdx,7) << 12) & 0x001FF000; 	\
-}
-
-
-#define PUT_PIXEL(_a)				\
-{						\
-    zz=z >> ZB_POINT_Z_FRAC_BITS;		\
-    if (ZCMP(zz,pz[_a])) {				\
-      tmp=rgb & 0xF81F07E0;			\
-      pp[_a]=tmp | (tmp >> 16);			\
-      pz[_a]=zz;				\
-    }						\
-    z+=dzdx;					\
-    rgb=(rgb+drgbdx) & ( ~ 0x00200800);		\
-}
-
-#define DRAW_LINE()							   \
-{									   \
-  register unsigned short *pz;					   \
-  register PIXEL *pp;					   \
-  register unsigned int tmp,z,zz,rgb,drgbdx;				   \
-  register int n;							   \
-  n=(x2 >> 16) - x1;							   \
-  pp=pp1+x1;								   \
-  pz=pz1+x1;								   \
-  z=z1;									   \
-  rgb=(r1 << 16) & 0xFFC00000;						   \
-  rgb|=(g1 >> 5) & 0x000007FF;						   \
-  rgb|=(b1 << 5) & 0x001FF000;						   \
-  drgbdx=_drgbdx;							   \
-  while (n>=3) {							   \
-    PUT_PIXEL(0);							   \
-    PUT_PIXEL(1);							   \
-    PUT_PIXEL(2);							   \
-    PUT_PIXEL(3);							   \
-    pz+=4;								   \
-    pp+=4;								   \
-    n-=4;								   \
-  }									   \
-  while (n>=0) {							   \
-    PUT_PIXEL(0);							   \
-    pz+=1;								   \
-    pp+=1;								   \
-    n-=1;								   \
-  }									   \
-}
-
-#else
-
 #define DRAW_INIT() 				\
 {						\
 }
@@ -166,8 +58,6 @@ void ZB_fillTriangleSmooth(ZBuffer *zb,
     ob1+=dbdx;					\
 }
 
-#endif /* TGL_FEATURE_RENDER_BITS */
-
 #include "ztriangle.h"
 }
 
@@ -189,26 +79,6 @@ void ZB_fillTriangleMapping(ZBuffer *zb,
   texture=zb->current_texture;			\
 }
 
-#if TGL_FEATURE_RENDER_BITS == 24
-
-#define PUT_PIXEL(_a)				\
-{						\
-   unsigned char *ptr;\
-   zz=z >> ZB_POINT_Z_FRAC_BITS;		\
-     if (ZCMP(zz,pz[_a])) {				\
-       ptr = texture + (((t & 0x3FC00000) | s) >> 14) * 3; \
-       pp[3 * _a]= ptr[0];\
-       pp[3 * _a + 1]= ptr[1];\
-       pp[3 * _a + 2]= ptr[2];\
-       pz[_a]=zz;				\
-    }						\
-    z+=dzdx;					\
-    s+=dsdx;					\
-    t+=dtdx;					\
-}
-
-#else
-
 #define PUT_PIXEL(_a)				\
 {						\
    zz=z >> ZB_POINT_Z_FRAC_BITS;		\
@@ -221,8 +91,6 @@ void ZB_fillTriangleMapping(ZBuffer *zb,
     t+=dtdx;					\
 }
 
-#endif
-
 #include "ztriangle.h"
 }
 
@@ -231,8 +99,6 @@ void ZB_fillTriangleMapping(ZBuffer *zb,
  * We use the gradient method to make less divisions.
  * TODO: pipeline the division
  */
-#if 1
-
 void ZB_fillTriangleMappingPerspective(ZBuffer *zb,
                             ZBufferPoint *p0,ZBufferPoint *p1,ZBufferPoint *p2)
 {
@@ -254,26 +120,6 @@ void ZB_fillTriangleMappingPerspective(ZBuffer *zb,
 }
 
 
-#if TGL_FEATURE_RENDER_BITS == 24
-
-#define PUT_PIXEL(_a)				\
-{						\
-   unsigned char *ptr;\
-   zz=z >> ZB_POINT_Z_FRAC_BITS;		\
-     if (ZCMP(zz,pz[_a])) {				\
-       ptr = texture + (((t & 0x3FC00000) | (s & 0x003FC000)) >> 14) * 3;\
-       pp[3 * _a]= ptr[0];\
-       pp[3 * _a + 1]= ptr[1];\
-       pp[3 * _a + 2]= ptr[2];\
-       pz[_a]=zz;				\
-    }						\
-    z+=dzdx;					\
-    s+=dsdx;					\
-    t+=dtdx;					\
-}
-
-#else
-
 #define PUT_PIXEL(_a)				\
 {						\
    zz=z >> ZB_POINT_Z_FRAC_BITS;		\
@@ -287,8 +133,6 @@ void ZB_fillTriangleMappingPerspective(ZBuffer *zb,
     t+=dtdx;					\
 }
 
-#endif
-
 #define DRAW_LINE()				\
 {						\
   register unsigned short *pz;		\
@@ -350,45 +194,111 @@ void ZB_fillTriangleMappingPerspective(ZBuffer *zb,
 #include "ztriangle.h"
 }
 
-#endif
-
-#if 0
-
-/* slow but exact version (only there for reference, incorrect for 24
-   bits) */
+/*
+ * Smooth filled triangle, with perspective-correct mapping.
+ */
 
-void ZB_fillTriangleMappingPerspective(ZBuffer *zb,
-                            ZBufferPoint *p0,ZBufferPoint *p1,ZBufferPoint *p2)
+void ZB_fillTriangleMappingSmooth(ZBuffer *zb,
+                                  ZBufferPoint *p0,ZBufferPoint *p1,ZBufferPoint *p2)
 {
     PIXEL *texture;
+    float fdzdx,fndzdx,ndszdx,ndtzdx;
 
 #define INTERP_Z
 #define INTERP_STZ
+#define INTERP_RGB
 
-#define DRAW_INIT()				\
+#define SAR_RND_TO_ZERO(v,n) (v / (1<<n))
+
+#define DRAW_INIT() 				\
 {						\
-  texture=zb->current_texture;			\
+  texture=zb->current_texture;\
+  fdzdx=(float)dzdx;\
+  fndzdx=NB_INTERP * fdzdx;\
+  ndszdx=NB_INTERP * dszdx;\
+  ndtzdx=NB_INTERP * dtzdx;\
 }
 
 #define PUT_PIXEL(_a)				\
 {						\
-   float zinv; \
-   int s,t; \
-   zz=z >> ZB_POINT_Z_FRAC_BITS;		\
-     if (ZCMP(zz,pz[_a])) {				\
-       zinv= 1.0 / (float) z; \
-       s= (int) (sz * zinv); \
-       t= (int) (tz * zinv); \
-       pp[_a]=texture[((t & 0x3FC00000) | s) >> 14];	\
-       pz[_a]=zz;				\
-    }						\
+    zz=z >> ZB_POINT_Z_FRAC_BITS;		\
+    if (ZCMP(zz,pz[_a])) {				\
+      tmp=*(PIXEL *)((char *)texture+ \
+                     (((t & 0x3FC00000) | (s & 0x003FC000)) >> (17 - PSZSH))); \
+      pp[_a] = RGB_TO_PIXEL(or1 * PIXEL_R(tmp) >> 16, \
+                            og1 * PIXEL_G(tmp) >> 16, \
+                            ob1 * PIXEL_B(tmp) >> 16);   \
+      pz[_a]=zz;				\
+    }\
     z+=dzdx;					\
-    sz+=dszdx;					\
-    tz+=dtzdx;					\
+    og1+=dgdx;					\
+    or1+=drdx;					\
+    ob1+=dbdx;					\
+    s+=dsdx;					\
+    t+=dtdx;					\
 }
 
-#include "ztriangle.h"
+#define DRAW_LINE()				\
+{						\
+  register unsigned short *pz;		\
+  register PIXEL *pp;		\
+  register unsigned int s,t,z,zz;	\
+  register int n,dsdx,dtdx;		\
+  register unsigned int or1,og1,ob1; \
+  float sz,tz,fz,zinv; \
+  n=(x2>>16)-x1;                             \
+  fz=(float)z1;\
+  zinv=1.0 / fz;\
+  pp=(PIXEL *)((char *)pp1 + x1 * PSZB); \
+  pz=pz1+x1;					\
+  z=z1;						\
+  sz=sz1;\
+  tz=tz1;\
+  or1 = r1;\
+  og1 = g1;\
+  ob1 = b1;\
+  while (n>=(NB_INTERP-1)) {						   \
+    {\
+      float ss,tt;\
+      ss=(sz * zinv);\
+      tt=(tz * zinv);\
+      s=(int) ss;\
+      t=(int) tt;\
+      dsdx= (int)( (dszdx - ss*fdzdx)*zinv );\
+      dtdx= (int)( (dtzdx - tt*fdzdx)*zinv );\
+      fz+=fndzdx;\
+      zinv=1.0 / fz;\
+    }\
+    PUT_PIXEL(0);							   \
+    PUT_PIXEL(1);							   \
+    PUT_PIXEL(2);							   \
+    PUT_PIXEL(3);							   \
+    PUT_PIXEL(4);							   \
+    PUT_PIXEL(5);							   \
+    PUT_PIXEL(6);							   \
+    PUT_PIXEL(7);							   \
+    pz+=NB_INTERP;							   \
+    pp=(PIXEL *)((char *)pp + NB_INTERP * PSZB);\
+    n-=NB_INTERP;							   \
+    sz+=ndszdx;\
+    tz+=ndtzdx;\
+  }									   \
+    {\
+      float ss,tt;\
+      ss=(sz * zinv);\
+      tt=(tz * zinv);\
+      s=(int) ss;\
+      t=(int) tt;\
+      dsdx= (int)( (dszdx - ss*fdzdx)*zinv );\
+      dtdx= (int)( (dtzdx - tt*fdzdx)*zinv );\
+    }\
+  while (n>=0) {							   \
+    PUT_PIXEL(0);							   \
+    pz+=1;								   \
+    pp=(PIXEL *)((char *)pp + PSZB);\
+    n-=1;								   \
+  }									   \
 }
 
-
-#endif
+#include "ztriangle.h"
+}