Parcourir la source

progress on rendering modes

David Rose il y a 17 ans
Parent
commit
d48ff75151

+ 1 - 1
panda/src/tinydisplay/Sources.pp

@@ -27,7 +27,7 @@
     opinfo.h oscontext.c oscontext.h select.c specbuf.c \
     specbuf.h texture.c tinygl.h tinyglu.h vertex.c \
     zbuffer.c zbuffer.h zdither.c zfeatures.h zgl.h zline.c \
-    zline.h zmath.c zmath.h ztriangle.c ztriangle.h
+    zline.h zmath.c zmath.h ztriangle.c ztriangle.h ztriangle_two.h
 
 #end lib_target
 

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

@@ -29,6 +29,8 @@ void gl_transform_to_viewport(GLContext *c,GLVertex *v)
                 + ZB_POINT_GREEN_MIN);
   v->zp.b=(int)(v->color.v[2] * (ZB_POINT_BLUE_MAX - ZB_POINT_BLUE_MIN) 
                 + ZB_POINT_BLUE_MIN);
+  v->zp.a=(int)(v->color.v[3] * (ZB_POINT_ALPHA_MAX - ZB_POINT_ALPHA_MIN) 
+                + ZB_POINT_ALPHA_MIN);
   
   /* texture */
 
@@ -78,6 +80,7 @@ static inline void interpolate(GLVertex *q,GLVertex *p0,GLVertex *p1,float t)
   q->color.v[0]=p0->color.v[0] + (p1->color.v[0]-p0->color.v[0])*t;
   q->color.v[1]=p0->color.v[1] + (p1->color.v[1]-p0->color.v[1])*t;
   q->color.v[2]=p0->color.v[2] + (p1->color.v[2]-p0->color.v[2])*t;
+  q->color.v[3]=p0->color.v[3] + (p1->color.v[3]-p0->color.v[3])*t;
 }
 
 /*
@@ -212,10 +215,12 @@ static inline void updateTmp(GLContext *c,
     q->color.v[0]=p0->color.v[0] + (p1->color.v[0]-p0->color.v[0])*t;
     q->color.v[1]=p0->color.v[1] + (p1->color.v[1]-p0->color.v[1])*t;
     q->color.v[2]=p0->color.v[2] + (p1->color.v[2]-p0->color.v[2])*t;
+    q->color.v[3]=p0->color.v[3] + (p1->color.v[3]-p0->color.v[3])*t;
   } else {
     q->color.v[0]=p0->color.v[0];
     q->color.v[1]=p0->color.v[1];
     q->color.v[2]=p0->color.v[2];
+    q->color.v[3]=p0->color.v[3];
   }
 
   if (c->texture_2d_enabled) {
@@ -393,18 +398,13 @@ void gl_draw_triangle_fill(GLContext *c,
   }
 #endif
     
-  if (c->texture_2d_enabled) {
 #ifdef PROFILE
+  if (c->texture_2d_enabled) {
     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_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 {
-    ZB_fillTriangleFlat(c->zb,&p0->zp,&p1->zp,&p2->zp);
   }
+#endif
+
+  (*c->zb_fill_tri)(c->zb,&p0->zp,&p1->zp,&p2->zp);
 }
 
 /* Render a clipped triangle in line mode */  

+ 12 - 11
panda/src/tinydisplay/image_util.c

@@ -92,24 +92,24 @@ void gl_resizeImage(unsigned char *dest,int xsize_dest,int ysize_dest,
       yf=(int) ((y1 - floor(y1)) * INTERP_NORM);
       
       if ((xf+yf) <= INTERP_NORM) {
-	for(j=0;j<3;j++) {
-	  pix[j]=interpolate(pix_src[(yi*xsize_src+xi)*3+j],
-			     pix_src[(yi*xsize_src+xi+1)*3+j],
-			     pix_src[((yi+1)*xsize_src+xi)*3+j],
+	for(j=0;j<4;j++) {
+	  pix[j]=interpolate(pix_src[(yi*xsize_src+xi)*4+j],
+			     pix_src[(yi*xsize_src+xi+1)*4+j],
+			     pix_src[((yi+1)*xsize_src+xi)*4+j],
 			     xf,yf);
 	}
       } else {
 	xf=INTERP_NORM - xf;
 	yf=INTERP_NORM - yf;
-	for(j=0;j<3;j++) {
-	  pix[j]=interpolate(pix_src[((yi+1)*xsize_src+xi+1)*3+j],
-			     pix_src[((yi+1)*xsize_src+xi)*3+j],
-			     pix_src[(yi*xsize_src+xi+1)*3+j],
+	for(j=0;j<4;j++) {
+	  pix[j]=interpolate(pix_src[((yi+1)*xsize_src+xi+1)*4+j],
+			     pix_src[((yi+1)*xsize_src+xi)*4+j],
+			     pix_src[(yi*xsize_src+xi+1)*4+j],
 			     xf,yf);
 	}
       }
       
-      pix+=3;
+      pix+=4;
       x1+=x1inc;
     }
     y1+=y1inc;
@@ -139,13 +139,14 @@ void gl_resizeImageNoInterpolate(unsigned char *dest,int xsize_dest,int ysize_de
     for(x=0;x<xsize_dest;x++) {
       xi=x1 >> FRAC_BITS;
       yi=y1 >> FRAC_BITS;
-      pix1=pix_src+(yi*xsize_src+xi)*3;
+      pix1=pix_src+(yi*xsize_src+xi)*4;
 
       pix[0]=pix1[0];
       pix[1]=pix1[1];
       pix[2]=pix1[2];
+      pix[3]=pix1[3];
 
-      pix+=3;
+      pix+=4;
       x1+=x1inc;
     }
     y1+=y1inc;

+ 0 - 16
panda/src/tinydisplay/texture.c

@@ -151,12 +151,10 @@ void glopTexImage2D(GLContext *c,GLParam *p)
       pixels1=pixels;
     }
 
-#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");
@@ -166,12 +164,6 @@ void glopTexImage2D(GLContext *c,GLParam *p)
   im->xsize=width;
   im->ysize=height;
   if (im->pixmap!=NULL) gl_free(im->pixmap);
-#if TGL_FEATURE_RENDER_BITS == 24 
-  im->pixmap=gl_malloc(width*height*3);
-  if(im->pixmap) {
-      memcpy(im->pixmap,pixels1,width*height*3);
-  }
-#elif TGL_FEATURE_RENDER_BITS == 32
   im->pixmap=gl_malloc(width*height*4);
   if(im->pixmap) {
     if (components == 4) {
@@ -180,14 +172,6 @@ void glopTexImage2D(GLContext *c,GLParam *p)
       gl_convertRGB_to_8A8R8G8B(im->pixmap,pixels1,width,height);
     }
   }
-#elif TGL_FEATURE_RENDER_BITS == 16
-  im->pixmap=gl_malloc(width*height*2);
-  if(im->pixmap) {
-      gl_convertRGB_to_5R6G5B(im->pixmap,pixels1,width,height);
-  }
-#else
-#error TODO
-#endif
   if (do_free) gl_free(pixels1);
 }
 

+ 520 - 189
panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx

@@ -31,139 +31,61 @@ TypeHandle TinyGraphicsStateGuardian::_type_handle;
 
 PStatCollector TinyGraphicsStateGuardian::_vertices_immediate_pcollector("Vertices:Immediate mode");
 
-////////////////////////////////////////////////////////////////////
-//     Function: uchar_bgr_to_rgb
-//  Description: Recopies the given array of pixels, converting from
-//               BGR to RGB arrangement.
-////////////////////////////////////////////////////////////////////
-static void
-uchar_bgr_to_rgb(unsigned char *dest, const unsigned char *source,
-                 int num_pixels) {
-  for (int i = 0; i < num_pixels; i++) {
-    dest[0] = source[2];
-    dest[1] = source[1];
-    dest[2] = source[0];
-    dest += 3;
-    source += 3;
-  }
-}
-
-/*
-////////////////////////////////////////////////////////////////////
-//     Function: uchar_bgra_to_rgba
-//  Description: Recopies the given array of pixels, converting from
-//               BGRA to RGBA arrangement.
-////////////////////////////////////////////////////////////////////
-static void
-uchar_bgra_to_rgba(unsigned char *dest, const unsigned char *source,
-                   int num_pixels) {
-  for (int i = 0; i < num_pixels; i++) {
-    dest[0] = source[2];
-    dest[1] = source[1];
-    dest[2] = source[0];
-    dest[3] = source[3];
-    dest += 4;
-    source += 4;
-  }
-}
-*/
-
-////////////////////////////////////////////////////////////////////
-//     Function: uchar_bgra_to_rgb
-//  Description: Recopies the given array of pixels, converting from
-//               BGRA to RGB arrangement, dropping alpha.
-////////////////////////////////////////////////////////////////////
-static void
-uchar_bgra_to_rgb(unsigned char *dest, const unsigned char *source,
-                  int num_pixels) {
-  for (int i = 0; i < num_pixels; i++) {
-    dest[0] = source[2] * source[3] / 255;
-    dest[1] = source[1] * source[3] / 255;
-    dest[2] = source[0] * source[3] / 255;
-    dest += 3;
-    source += 4;
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: uchar_lum_to_rgb
-//  Description: Recopies the given array of pixels, converting from
-//               luminance to RGB arrangement.
-////////////////////////////////////////////////////////////////////
-static void
-uchar_lum_to_rgb(unsigned char *dest, const unsigned char *source,
-                 int num_pixels) {
-  for (int i = 0; i < num_pixels; i++) {
-    dest[0] = source[0];
-    dest[1] = source[0];
-    dest[2] = source[0];
-    dest += 3;
-    source += 1;
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: uchar_la_to_rgb
-//  Description: Recopies the given array of pixels, converting from
-//               luminance-alpha to RGB arrangement.
-////////////////////////////////////////////////////////////////////
-static void
-uchar_la_to_rgb(unsigned char *dest, const unsigned char *source,
-                 int num_pixels) {
-  for (int i = 0; i < num_pixels; i++) {
-    dest[2] = dest[1] = dest[0] = source[0] * source[1] / 255;
-    dest += 3;
-    source += 2;
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: restructure_image
-//  Description: Converts the pixels of the image to the appropriate
-//               format for TinyGL (i.e. GL_RGB).
-////////////////////////////////////////////////////////////////////
-static PTA_uchar
-restructure_image(Texture *tex) {
-  int num_pixels = tex->get_x_size() * tex->get_y_size();
-  CPTA_uchar orig_image = tex->get_ram_image();
-  PTA_uchar new_image = PTA_uchar::empty_array(num_pixels * 3);
-
-  switch (tex->get_format()) {
-  case Texture::F_rgb:
-  case Texture::F_rgb5:
-  case Texture::F_rgb8:
-  case Texture::F_rgb12:
-  case Texture::F_rgb332:
-    uchar_bgr_to_rgb(new_image, orig_image, num_pixels);
-    break;
-
-  case Texture::F_rgba:
-  case Texture::F_rgbm:
-  case Texture::F_rgba4:
-  case Texture::F_rgba5:
-  case Texture::F_rgba8:
-  case Texture::F_rgba12:
-  case Texture::F_rgba16:
-  case Texture::F_rgba32:
-    uchar_bgra_to_rgb(new_image, orig_image, num_pixels);
-    break;
 
-  case Texture::F_luminance:
-  case Texture::F_alpha:
-    uchar_lum_to_rgb(new_image, orig_image, num_pixels);
-    break;
-
-  case Texture::F_luminance_alphamask:
-  case Texture::F_luminance_alpha:
-    uchar_la_to_rgb(new_image, orig_image, num_pixels);
-    break;
-
-  default:
-    break;
-  }
-
-  return new_image;
-}
+static const ZB_fillTriangleFunc fill_tri_funcs
+[2 /* alpha test: anone, abin (binary) */]
+[2 /* ztest: znone, zless */]
+[3 /* white, flat, smooth */]
+[3 /* untextured, textured, perspective textured */] = {
+  { // alpha test anone
+    {
+      { ZB_fillTriangleFlat_anone_znone,
+        ZB_fillTriangleMapping_anone_znone,
+        ZB_fillTriangleMappingPerspective_anone_znone },
+      { ZB_fillTriangleFlat_anone_znone,
+        ZB_fillTriangleMappingFlat_anone_znone,
+        ZB_fillTriangleMappingPerspectiveFlat_anone_znone },
+      { ZB_fillTriangleSmooth_anone_znone,
+        ZB_fillTriangleMappingSmooth_anone_znone,
+        ZB_fillTriangleMappingPerspectiveSmooth_anone_znone },
+    },
+    {
+      { ZB_fillTriangleFlat_anone_zless,
+        ZB_fillTriangleMapping_anone_zless,
+        ZB_fillTriangleMappingPerspective_anone_zless },
+      { ZB_fillTriangleFlat_anone_zless,
+        ZB_fillTriangleMappingFlat_anone_zless,
+        ZB_fillTriangleMappingPerspectiveFlat_anone_zless },
+      { ZB_fillTriangleSmooth_anone_zless,
+        ZB_fillTriangleMappingSmooth_anone_zless,
+        ZB_fillTriangleMappingPerspectiveSmooth_anone_zless },
+    },
+  },
+  { // alpha test abin
+    {
+      { ZB_fillTriangleFlat_abin_znone,
+        ZB_fillTriangleMapping_abin_znone,
+        ZB_fillTriangleMappingPerspective_abin_znone },
+      { ZB_fillTriangleFlat_abin_znone,
+        ZB_fillTriangleMappingFlat_abin_znone,
+        ZB_fillTriangleMappingPerspectiveFlat_abin_znone },
+      { ZB_fillTriangleSmooth_abin_znone,
+        ZB_fillTriangleMappingSmooth_abin_znone,
+        ZB_fillTriangleMappingPerspectiveSmooth_abin_znone },
+    },
+    {
+      { ZB_fillTriangleFlat_abin_zless,
+        ZB_fillTriangleMapping_abin_zless,
+        ZB_fillTriangleMappingPerspective_abin_zless },
+      { ZB_fillTriangleFlat_abin_zless,
+        ZB_fillTriangleMappingFlat_abin_zless,
+        ZB_fillTriangleMappingPerspectiveFlat_abin_zless },
+      { ZB_fillTriangleSmooth_abin_zless,
+        ZB_fillTriangleMappingSmooth_abin_zless,
+        ZB_fillTriangleMappingPerspectiveSmooth_abin_zless },
+    },
+  },
+};
 
 static inline void tgl_vertex_transform(GLContext * c, GLVertex * v)
 {
@@ -581,18 +503,17 @@ begin_draw_primitives(const GeomPipelineReader *geom_reader,
       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;
-      }
+    }
+
+    // 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;
   }
@@ -740,6 +661,47 @@ begin_draw_primitives(const GeomPipelineReader *geom_reader,
     v->edge_flag = 0;
   }
 
+  // Set up the appropriate function callback for filling triangles,
+  // according to the current state.
+
+  int alpha_test_state = 0;
+  if (_target._transparency->get_mode() != TransparencyAttrib::M_none) {
+    alpha_test_state = 1;
+  }
+
+  int depth_test_state = 1;
+  if (_target._depth_test->get_mode() == DepthTestAttrib::M_none) {
+    depth_test_state = 0;
+  }
+  
+  ShadeModelAttrib::Mode shade_model = _target._shade_model->get_mode();
+  if (!needs_normal && !needs_color) {
+    // With no per-vertex lighting, and no per-vertex colors, we might
+    // as well use the flat shading model.
+    shade_model = ShadeModelAttrib::M_flat;
+  }
+  int color_state = 2;  // smooth
+  if (shade_model == ShadeModelAttrib::M_flat) {
+    color_state = 1;  // flat
+    if (_c->current_color.X == 1.0f &&
+        _c->current_color.Y == 1.0f &&
+        _c->current_color.Z == 1.0f &&
+        _c->current_color.W == 1.0f) {
+      color_state = 0;  // white
+    }
+  }
+
+  int texture_state = 0;  // untextured
+  if (_c->texture_2d_enabled) {
+    texture_state = 2;  // perspective-correct textures
+    if (_c->matrix_model_projection_no_w_transform) {
+      texture_state = 1;  // non-perspective-correct textures
+    }
+  }
+
+  _c->zb_fill_tri = fill_tri_funcs[alpha_test_state][depth_test_state][color_state][texture_state];
+  //_c->zb_fill_tri = ZB_fillTriangleFlat_zless;
+  
   return true;
 }
 
@@ -962,12 +924,6 @@ set_state_and_transform(const RenderState *target,
     _state._render_mode = _target._render_mode;
   }
 
-  if (_target._shade_model != _state._shade_model) {
-    PStatTimer timer(_draw_set_state_shade_model_pcollector);
-    do_issue_shade_model();
-    _state._shade_model = _target._shade_model;
-  }
-
   if ((_target._transparency != _state._transparency)||
       (_target._color_write != _state._color_write)||
       (_target._color_blend != _state._color_blend)) {
@@ -1035,7 +991,7 @@ prepare_texture(Texture *tex) {
   }
 
   TinyTextureContext *gtc = new TinyTextureContext(_prepared_objects, tex);
-  glGenTextures(1, &gtc->_index);
+  gtc->_gltex = (GLTexture *)gl_zalloc(sizeof(GLTexture));
 
   apply_texture(gtc);
   return gtc;
@@ -1053,9 +1009,22 @@ void TinyGraphicsStateGuardian::
 release_texture(TextureContext *tc) {
   TinyTextureContext *gtc = DCAST(TinyTextureContext, tc);
 
-  glDeleteTextures(1, &gtc->_index);
+  if (_c->current_texture == gtc->_gltex) {
+    _c->current_texture = NULL;
+    _c->zb->current_texture = NULL;
+    _c->texture_2d_enabled = false;
+  }
+
+  for (int i = 0; i < MAX_TEXTURE_LEVELS; i++) {
+    GLImage *im = &gtc->_gltex->images[i];
+    if (im->pixmap != NULL) {
+      gl_free(im->pixmap);
+    }
+  }
+
+  gl_free(gtc->_gltex);
+  gtc->_gltex = NULL;
 
-  gtc->_index = 0;
   delete gtc;
 }
 
@@ -1183,25 +1152,6 @@ do_issue_transform() {
   _transform_stale = true;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: TinyGraphicsStateGuardian::do_issue_shade_model
-//       Access: Protected
-//  Description:
-////////////////////////////////////////////////////////////////////
-void TinyGraphicsStateGuardian::
-do_issue_shade_model() {
-  const ShadeModelAttrib *attrib = _target._shade_model;
-  switch (attrib->get_mode()) {
-  case ShadeModelAttrib::M_smooth:
-    glShadeModel(GL_SMOOTH);
-    break;
-
-  case ShadeModelAttrib::M_flat:
-    glShadeModel(GL_FLAT);
-    break;
-  }
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: TinyGraphicsStateGuardian::do_issue_render_mode
 //       Access: Protected
@@ -1339,7 +1289,7 @@ do_issue_material() {
 ////////////////////////////////////////////////////////////////////
 void TinyGraphicsStateGuardian::
 do_issue_texture() {
-  glDisable(GL_TEXTURE_2D);
+  _c->texture_2d_enabled = false;
 
   int num_stages = _effective_texture->get_num_on_ff_stages();
   if (num_stages == 0) {
@@ -1359,7 +1309,6 @@ do_issue_texture() {
   }
     
   // Then, turn on the current texture mode.
-  glEnable(GL_TEXTURE_2D);
   apply_texture(tc);
 
   /*
@@ -1508,12 +1457,13 @@ apply_texture(TextureContext *tc) {
   TinyTextureContext *gtc = DCAST(TinyTextureContext, tc);
 
   gtc->set_active(true);
-  glBindTexture(GL_TEXTURE_2D, gtc->_index);
+  _c->current_texture = gtc->_gltex;
+  _c->texture_2d_enabled = true;
 
   if (gtc->was_image_modified()) {
     // If the texture image was modified, reload the texture.
     if (!upload_texture(gtc)) {
-      glDisable(GL_TEXTURE_2D);
+      _c->texture_2d_enabled = false;
     }
     gtc->mark_loaded();
 
@@ -1522,6 +1472,8 @@ apply_texture(TextureContext *tc) {
     // reload the texture.
     gtc->mark_loaded();
   }
+
+  _c->zb->current_texture = (PIXEL *)gtc->_gltex->images[0].pixmap;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -1541,24 +1493,70 @@ upload_texture(TinyTextureContext *gtc) {
     tinydisplay_cat.debug()
       << "loading texture " << tex->get_name() << "\n";
   }
-  CPTA_uchar image = tex->get_ram_image();
-  nassertr(!image.is_null(), false)
+#ifdef DO_PSTATS
+  _data_transferred_pcollector.add_level(tex->get_ram_image_size());
+#endif
 
-  int width = tex->get_x_size();
-  int height = tex->get_y_size();
+  // Internal texture size is always 256 x 256 x 4.
+  static const int iwidth = 256;
+  static const int iheight = 256;
+  static const int ibytecount = iwidth * iheight * 4;
 
-  PTA_uchar new_image = restructure_image(tex);
-  const unsigned char *image_ptr = new_image.p();
+  GLImage *im = &gtc->_gltex->images[0];
+  im->xsize = iwidth;
+  im->ysize = iheight;
+  if (im->pixmap == NULL) {
+    im->pixmap = gl_malloc(ibytecount);
+  }
 
-#ifdef DO_PSTATS
-  _data_transferred_pcollector.add_level(new_image.size());
-#endif
-  glTexImage2D(GL_TEXTURE_2D, 0, 3,
-               width, height, 0,
-               GL_RGB, GL_UNSIGNED_BYTE, (void *)image_ptr);
+  switch (tex->get_format()) {
+  case Texture::F_rgb:
+  case Texture::F_rgb5:
+  case Texture::F_rgb8:
+  case Texture::F_rgb12:
+  case Texture::F_rgb332:
+    copy_rgb_image(im, tex);
+    break;
+
+  case Texture::F_rgba:
+  case Texture::F_rgbm:
+  case Texture::F_rgba4:
+  case Texture::F_rgba5:
+  case Texture::F_rgba8:
+  case Texture::F_rgba12:
+  case Texture::F_rgba16:
+  case Texture::F_rgba32:
+    copy_rgba_image(im, tex);
+    break;
+
+  case Texture::F_luminance:
+    copy_lum_image(im, tex);
+    break;
+
+  case Texture::F_red:
+    copy_one_channel_image(im, tex, 0);
+    break;
+
+  case Texture::F_green:
+    copy_one_channel_image(im, tex, 1);
+    break;
+
+  case Texture::F_blue:
+    copy_one_channel_image(im, tex, 2);
+    break;
+
+  case Texture::F_alpha:
+    copy_alpha_image(im, tex);
+    break;
+
+  case Texture::F_luminance_alphamask:
+  case Texture::F_luminance_alpha:
+    copy_la_image(im, tex);
+    break;
+  }
   
 #ifdef DO_PSTATS 
-  gtc->update_data_size_bytes(256 * 256 * 3);
+  gtc->update_data_size_bytes(ibytecount);
 #endif
   
   tex->texture_uploaded();
@@ -1566,6 +1564,339 @@ upload_texture(TinyTextureContext *gtc) {
   return true;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: TinyGraphicsStateGuardian::copy_lum_image
+//       Access: Private, Static
+//  Description: Copies and scales the one-channel luminance image
+//               from the texture into the indicated GLImage pixmap.
+////////////////////////////////////////////////////////////////////
+void TinyGraphicsStateGuardian::
+copy_lum_image(GLImage *im, Texture *tex) {
+  nassertv(tex->get_num_components() == 1);
+
+  int xsize_src = tex->get_x_size();
+  int ysize_src = tex->get_y_size();
+  CPTA_uchar src_image = tex->get_ram_image();
+  nassertv(!src_image.is_null());
+  const unsigned char *src = src_image.p();
+
+  // Component width, and offset to the high-order byte.
+  int cw = tex->get_component_width();
+#ifdef WORDS_BIGENDIAN
+  // Big-endian: the high-order byte is always first.
+  static const int co = 0;
+#else
+  // Little-endian: the high-order byte is last.
+  int co = cw - 1;
+#endif
+
+  int xsize_dest = im->xsize;
+  int ysize_dest = im->xsize;
+  unsigned char *dest = (unsigned char *)im->pixmap;
+  nassertv(dest != NULL);
+
+  int sx_inc = (int)((float)(xsize_src) / (float)(xsize_dest));
+  int sy_inc = (int)((float)(ysize_src) / (float)(ysize_dest));
+
+  unsigned char *dpix = dest;
+  int syn = 0;
+  for (int dy = 0; dy < ysize_dest; dy++) {
+    int sy = syn / ysize_dest;
+    int sxn = 0;
+    for (int dx = 0; dx < xsize_dest; dx++) {
+      int sx = sxn / xsize_dest;
+      const unsigned char *spix = src + (sy * xsize_src + sx) * 1 * cw;
+      
+      dpix[0] = spix[co];
+      dpix[1] = spix[co];
+      dpix[2] = spix[co];
+      dpix[3] = 0xff;
+      
+      dpix += 4;
+      sxn += xsize_src;
+    }
+    syn += ysize_src;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TinyGraphicsStateGuardian::copy_alpha_image
+//       Access: Private, Static
+//  Description: Copies and scales the one-channel alpha image
+//               from the texture into the indicated GLImage pixmap.
+////////////////////////////////////////////////////////////////////
+void TinyGraphicsStateGuardian::
+copy_alpha_image(GLImage *im, Texture *tex) {
+  nassertv(tex->get_num_components() == 1);
+
+  int xsize_src = tex->get_x_size();
+  int ysize_src = tex->get_y_size();
+  CPTA_uchar src_image = tex->get_ram_image();
+  nassertv(!src_image.is_null());
+  const unsigned char *src = src_image.p();
+
+  // Component width, and offset to the high-order byte.
+  int cw = tex->get_component_width();
+#ifdef WORDS_BIGENDIAN
+  // Big-endian: the high-order byte is always first.
+  static const int co = 0;
+#else
+  // Little-endian: the high-order byte is last.
+  int co = cw - 1;
+#endif
+
+  int xsize_dest = im->xsize;
+  int ysize_dest = im->xsize;
+  unsigned char *dest = (unsigned char *)im->pixmap;
+  nassertv(dest != NULL);
+
+  int sx_inc = (int)((float)(xsize_src) / (float)(xsize_dest));
+  int sy_inc = (int)((float)(ysize_src) / (float)(ysize_dest));
+
+  unsigned char *dpix = dest;
+  int syn = 0;
+  for (int dy = 0; dy < ysize_dest; dy++) {
+    int sy = syn / ysize_dest;
+    int sxn = 0;
+    for (int dx = 0; dx < xsize_dest; dx++) {
+      int sx = sxn / xsize_dest;
+      const unsigned char *spix = src + (sy * xsize_src + sx) * 1 * cw;
+      
+      dpix[0] = 0xff;
+      dpix[1] = 0xff;
+      dpix[2] = 0xff;
+      dpix[3] = spix[co];
+      
+      dpix += 4;
+      sxn += xsize_src;
+    }
+    syn += ysize_src;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TinyGraphicsStateGuardian::copy_one_channel_image
+//       Access: Private, Static
+//  Description: Copies and scales the one-channel image (with a
+//               single channel, e.g. red, green, or blue) from
+//               the texture into the indicated GLImage pixmap.
+////////////////////////////////////////////////////////////////////
+void TinyGraphicsStateGuardian::
+copy_one_channel_image(GLImage *im, Texture *tex, int channel) {
+  nassertv(tex->get_num_components() == 1);
+
+  int xsize_src = tex->get_x_size();
+  int ysize_src = tex->get_y_size();
+  CPTA_uchar src_image = tex->get_ram_image();
+  nassertv(!src_image.is_null());
+  const unsigned char *src = src_image.p();
+
+  // Component width, and offset to the high-order byte.
+  int cw = tex->get_component_width();
+#ifdef WORDS_BIGENDIAN
+  // Big-endian: the high-order byte is always first.
+  static const int co = 0;
+#else
+  // Little-endian: the high-order byte is last.
+  int co = cw - 1;
+#endif
+
+  int xsize_dest = im->xsize;
+  int ysize_dest = im->xsize;
+  unsigned char *dest = (unsigned char *)im->pixmap;
+  nassertv(dest != NULL);
+
+  int sx_inc = (int)((float)(xsize_src) / (float)(xsize_dest));
+  int sy_inc = (int)((float)(ysize_src) / (float)(ysize_dest));
+
+  unsigned char *dpix = dest;
+  int syn = 0;
+  for (int dy = 0; dy < ysize_dest; dy++) {
+    int sy = syn / ysize_dest;
+    int sxn = 0;
+    for (int dx = 0; dx < xsize_dest; dx++) {
+      int sx = sxn / xsize_dest;
+      const unsigned char *spix = src + (sy * xsize_src + sx) * 1 * cw;
+
+      dpix[0] = 0;
+      dpix[1] = 0;
+      dpix[2] = 0;
+      dpix[3] = 0xff;
+      dpix[channel] = spix[co];
+      
+      dpix += 4;
+      sxn += xsize_src;
+    }
+    syn += ysize_src;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TinyGraphicsStateGuardian::copy_la_image
+//       Access: Private, Static
+//  Description: Copies and scales the two-channel luminance-alpha
+//               image from the texture into the indicated GLImage
+//               pixmap.
+////////////////////////////////////////////////////////////////////
+void TinyGraphicsStateGuardian::
+copy_la_image(GLImage *im, Texture *tex) {
+  nassertv(tex->get_num_components() == 2);
+
+  int xsize_src = tex->get_x_size();
+  int ysize_src = tex->get_y_size();
+  CPTA_uchar src_image = tex->get_ram_image();
+  nassertv(!src_image.is_null());
+  const unsigned char *src = src_image.p();
+
+  // Component width, and offset to the high-order byte.
+  int cw = tex->get_component_width();
+#ifdef WORDS_BIGENDIAN
+  // Big-endian: the high-order byte is always first.
+  static const int co = 0;
+#else
+  // Little-endian: the high-order byte is last.
+  int co = cw - 1;
+#endif
+
+  int xsize_dest = im->xsize;
+  int ysize_dest = im->xsize;
+  unsigned char *dest = (unsigned char *)im->pixmap;
+  nassertv(dest != NULL);
+
+  int sx_inc = (int)((float)(xsize_src) / (float)(xsize_dest));
+  int sy_inc = (int)((float)(ysize_src) / (float)(ysize_dest));
+
+  unsigned char *dpix = dest;
+  int syn = 0;
+  for (int dy = 0; dy < ysize_dest; dy++) {
+    int sy = syn / ysize_dest;
+    int sxn = 0;
+    for (int dx = 0; dx < xsize_dest; dx++) {
+      int sx = sxn / xsize_dest;
+      const unsigned char *spix = src + (sy * xsize_src + sx) * 2 * cw;
+      
+      dpix[0] = spix[co];
+      dpix[1] = spix[co];
+      dpix[2] = spix[co];
+      dpix[3] = spix[cw + co];
+      
+      dpix += 4;
+      sxn += xsize_src;
+    }
+    syn += ysize_src;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TinyGraphicsStateGuardian::copy_rgb_image
+//       Access: Private, Static
+//  Description: Copies and scales the three-channel RGB image from
+//               the texture into the indicated GLImage pixmap.
+////////////////////////////////////////////////////////////////////
+void TinyGraphicsStateGuardian::
+copy_rgb_image(GLImage *im, Texture *tex) {
+  nassertv(tex->get_num_components() == 3);
+
+  int xsize_src = tex->get_x_size();
+  int ysize_src = tex->get_y_size();
+  CPTA_uchar src_image = tex->get_ram_image();
+  nassertv(!src_image.is_null());
+  const unsigned char *src = src_image.p();
+
+  // Component width, and offset to the high-order byte.
+  int cw = tex->get_component_width();
+#ifdef WORDS_BIGENDIAN
+  // Big-endian: the high-order byte is always first.
+  static const int co = 0;
+#else
+  // Little-endian: the high-order byte is last.
+  int co = cw - 1;
+#endif
+
+  int xsize_dest = im->xsize;
+  int ysize_dest = im->xsize;
+  unsigned char *dest = (unsigned char *)im->pixmap;
+  nassertv(dest != NULL);
+
+  int sx_inc = (int)((float)(xsize_src) / (float)(xsize_dest));
+  int sy_inc = (int)((float)(ysize_src) / (float)(ysize_dest));
+
+  unsigned char *dpix = dest;
+  int syn = 0;
+  for (int dy = 0; dy < ysize_dest; dy++) {
+    int sy = syn / ysize_dest;
+    int sxn = 0;
+    for (int dx = 0; dx < xsize_dest; dx++) {
+      int sx = sxn / xsize_dest;
+      const unsigned char *spix = src + (sy * xsize_src + sx) * 3 * cw;
+      
+      dpix[0] = spix[co];
+      dpix[1] = spix[cw + co];
+      dpix[2] = spix[cw + cw + co];
+      dpix[3] = 0xff;
+      
+      dpix += 4;
+      sxn += xsize_src;
+    }
+    syn += ysize_src;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TinyGraphicsStateGuardian::copy_rgba_image
+//       Access: Private, Static
+//  Description: Copies and scales the four-channel RGBA image from
+//               the texture into the indicated GLImage pixmap.
+////////////////////////////////////////////////////////////////////
+void TinyGraphicsStateGuardian::
+copy_rgba_image(GLImage *im, Texture *tex) {
+  nassertv(tex->get_num_components() == 4);
+
+  int xsize_src = tex->get_x_size();
+  int ysize_src = tex->get_y_size();
+  CPTA_uchar src_image = tex->get_ram_image();
+  nassertv(!src_image.is_null());
+  const unsigned char *src = src_image.p();
+
+  // Component width, and offset to the high-order byte.
+  int cw = tex->get_component_width();
+#ifdef WORDS_BIGENDIAN
+  // Big-endian: the high-order byte is always first.
+  static const int co = 0;
+#else
+  // Little-endian: the high-order byte is last.
+  int co = cw - 1;
+#endif
+
+  int xsize_dest = im->xsize;
+  int ysize_dest = im->xsize;
+  unsigned char *dest = (unsigned char *)im->pixmap;
+  nassertv(dest != NULL);
+
+  int sx_inc = (int)((float)(xsize_src) / (float)(xsize_dest));
+  int sy_inc = (int)((float)(ysize_src) / (float)(ysize_dest));
+
+  unsigned char *dpix = dest;
+  int syn = 0;
+  for (int dy = 0; dy < ysize_dest; dy++) {
+    int sy = syn / ysize_dest;
+    int sxn = 0;
+    for (int dx = 0; dx < xsize_dest; dx++) {
+      int sx = sxn / xsize_dest;
+      const unsigned char *spix = src + (sy * xsize_src + sx) * 4 * cw;
+      
+      dpix[0] = spix[co];
+      dpix[1] = spix[cw + co];
+      dpix[2] = spix[cw + cw + co];
+      dpix[3] = spix[cw + cw + cw + co];
+      
+      dpix += 4;
+      sxn += xsize_src;
+    }
+    syn += ysize_src;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: TinyGraphicsStateGuardian::load_matrix
 //       Access: Private, Static

+ 8 - 1
panda/src/tinydisplay/tinyGraphicsStateGuardian.h

@@ -33,6 +33,7 @@ extern "C" {
 class TinyTextureContext;
 struct GLContext;
 struct GLVertex;
+struct GLImage;
 
 
 ////////////////////////////////////////////////////////////////////
@@ -98,7 +99,6 @@ private:
   void do_issue_transform();
   void do_issue_render_mode();
   void do_issue_cull_face();
-  void do_issue_shade_model();
   void do_issue_material();
   void do_issue_texture();
   void do_issue_blending();
@@ -106,6 +106,13 @@ private:
   void apply_texture(TextureContext *tc);
   bool upload_texture(TinyTextureContext *gtc);
 
+  static void copy_lum_image(GLImage *im, Texture *tex);
+  static void copy_alpha_image(GLImage *im, Texture *tex);
+  static void copy_one_channel_image(GLImage *im, Texture *tex, int channel);
+  static void copy_la_image(GLImage *im, Texture *tex);
+  static void copy_rgb_image(GLImage *im, Texture *tex);
+  static void copy_rgba_image(GLImage *im, Texture *tex);
+
   static void load_matrix(M4 *matrix, const TransformState *transform);
 
   INLINE static GLenum get_light_id(int index);

+ 2 - 2
panda/src/tinydisplay/tinyGraphicsWindow.cxx

@@ -181,7 +181,7 @@ process_events() {
       system_changed_properties(properties);
       _screen = SDL_SetVideoMode(_properties.get_x_size(), _properties.get_y_size(), 32, _flags);
       ZB_resize(_frame_buffer, NULL, _properties.get_x_size(), _properties.get_y_size());
-      _pitch = _screen->pitch * TGL_FEATURE_RENDER_BITS / _screen->format->BitsPerPixel;
+      _pitch = _screen->pitch * 32 / _screen->format->BitsPerPixel;
       break;
       
     case SDL_QUIT:
@@ -325,7 +325,7 @@ create_frame_buffer() {
 
   _frame_buffer = ZB_open(_properties.get_x_size(), _properties.get_y_size(), mode, 0, 0, 0, 0);
 
-  _pitch = _screen->pitch * TGL_FEATURE_RENDER_BITS / _screen->format->BitsPerPixel;
+  _pitch = _screen->pitch * 32 / _screen->format->BitsPerPixel;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 11 - 1
panda/src/tinydisplay/tinyTextureContext.I

@@ -26,5 +26,15 @@ INLINE TinyTextureContext::
 TinyTextureContext(PreparedGraphicsObjects *pgo, Texture *tex) :
   TextureContext(pgo, tex)
 {
-  _index = 0;
+  _gltex = NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TinyTextureContext::Destructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE TinyTextureContext::
+~TinyTextureContext() {
+  nassertv(_gltex == NULL);
 }

+ 5 - 2
panda/src/tinydisplay/tinyTextureContext.h

@@ -24,6 +24,8 @@
 #include "deletedChain.h"
 #include "tinygl.h"
 
+struct GLTexture;
+
 ////////////////////////////////////////////////////////////////////
 //       Class : TinyTextureContext
 // Description :
@@ -33,8 +35,9 @@ public:
   INLINE TinyTextureContext(PreparedGraphicsObjects *pgo, Texture *tex);
   ALLOC_DELETED_CHAIN(TinyTextureContext);
 
-  // This is the GL "name" of the texture object.
-  GLuint _index;
+  INLINE ~TinyTextureContext();
+
+  GLTexture *_gltex;
 
 public:
   static TypeHandle get_class_type() {

+ 0 - 237
panda/src/tinydisplay/zbuffer.c

@@ -132,230 +132,6 @@ static void ZB_copyBuffer(ZBuffer * zb,
     }
 }
 
-#if TGL_FEATURE_RENDER_BITS == 16
-
-/* 32 bpp copy */
-
-#ifdef TGL_FEATURE_32_BITS
-
-#define RGB16_TO_RGB32(p0,p1,v)\
-{\
-    unsigned int g,b,gb;\
-    g = (v & 0x07E007E0) << 5;\
-    b = (v & 0x001F001F) << 3;\
-    gb = g | b;\
-    p0 = (gb & 0x0000FFFF) | ((v & 0x0000F800) << 8);\
-    p1 = (gb >> 16) | ((v & 0xF8000000) >> 8);\
-}
-
-static void ZB_copyFrameBufferRGB32(ZBuffer * zb,
-                                    void *buf,
-                                    int linesize)
-{
-    unsigned short *q;
-    unsigned int *p, *p1, v, w0, w1;
-    int y, n;
-
-    q = zb->pbuf;
-    p1 = (unsigned int *) buf;
-
-    for (y = 0; y < zb->ysize; y++) {
-	p = p1;
-	n = zb->xsize >> 2;
-	do {
-	    v = *(unsigned int *) q;
-#if BYTE_ORDER == BIG_ENDIAN
-	    RGB16_TO_RGB32(w1, w0, v);
-#else
-	    RGB16_TO_RGB32(w0, w1, v);
-#endif
-	    p[0] = w0;
-	    p[1] = w1;
-
-	    v = *(unsigned int *) (q + 2);
-#if BYTE_ORDER == BIG_ENDIAN
-	    RGB16_TO_RGB32(w1, w0, v);
-#else
-	    RGB16_TO_RGB32(w0, w1, v);
-#endif
-	    p[2] = w0;
-	    p[3] = w1;
-
-	    q += 4;
-	    p += 4;
-	} while (--n > 0);
-
-	p1 += linesize;
-    }
-}
-
-#endif
-
-/* 24 bit packed pixel handling */
-
-#ifdef TGL_FEATURE_24_BITS
-
-/* order: RGBR GBRG BRGB */
-
-/* XXX: packed pixel 24 bit support not tested */
-/* XXX: big endian case not optimised */
-
-#if BYTE_ORDER == BIG_ENDIAN
-
-#define RGB16_TO_RGB24(p0,p1,p2,v1,v2)\
-{\
-    unsigned int r1,g1,b1,gb1,g2,b2,gb2;\
-    v1 = (v1 << 16) | (v1 >> 16);\
-    v2 = (v2 << 16) | (v2 >> 16);\
-    r1 = (v1 & 0xF800F800);\
-    g1 = (v1 & 0x07E007E0) << 5;\
-    b1 = (v1 & 0x001F001F) << 3;\
-    gb1 = g1 | b1;\
-    p0 = ((gb1 & 0x0000FFFF) << 8) | (r1 << 16) | (r1 >> 24);\
-    g2 = (v2 & 0x07E007E0) << 5;\
-    b2 = (v2 & 0x001F001F) << 3;\
-    gb2 = g2 | b2;\
-    p1 = (gb1 & 0xFFFF0000) | (v2 & 0xF800) | ((gb2 >> 8) & 0xff);\
-    p2 = (gb2 << 24) | ((v2 & 0xF8000000) >> 8) | (gb2 >> 16);\
-}
-
-#else
-
-#define RGB16_TO_RGB24(p0,p1,p2,v1,v2)\
-{\
-    unsigned int r1,g1,b1,gb1,g2,b2,gb2;\
-    r1 = (v1 & 0xF800F800);\
-    g1 = (v1 & 0x07E007E0) << 5;\
-    b1 = (v1 & 0x001F001F) << 3;\
-    gb1 = g1 | b1;\
-    p0 = ((gb1 & 0x0000FFFF) << 8) | (r1 << 16) | (r1 >> 24);\
-    g2 = (v2 & 0x07E007E0) << 5;\
-    b2 = (v2 & 0x001F001F) << 3;\
-    gb2 = g2 | b2;\
-    p1 = (gb1 & 0xFFFF0000) | (v2 & 0xF800) | ((gb2 >> 8) & 0xff);\
-    p2 = (gb2 << 24) | ((v2 & 0xF8000000) >> 8) | (gb2 >> 16);\
-}
-
-#endif
-
-static void ZB_copyFrameBufferRGB24(ZBuffer * zb,
-                                    void *buf,
-                                    int linesize)
-{
-    unsigned short *q;
-    unsigned int *p, w0, w1, w2, v0, v1;
-    char *p1;
-    int y, n;
-
-    q = zb->pbuf;
-    p1 = buf;
-    linesize = linesize * 3;
-
-    for (y = 0; y < zb->ysize; y++) {
-        p = (unsigned int *)p1;
-        n = zb->xsize >> 2;
-        do {
-            v0 = *(unsigned int *) q;
-            v1 = *(unsigned int *) (q + 2);
-            RGB16_TO_RGB24(w0, w1, w2, v0, v1);
-            p[0] = w0;
-            p[1] = w1;
-            p[2] = w2;
-    
-            q += 4;
-            p += 3;
-        } while (--n > 0);
-        p1 += linesize;
-    }
-}
-
-#endif
-
-void ZB_copyFrameBuffer(ZBuffer * zb, void *buf,
-			int linesize)
-{
-    switch (zb->mode) {
-#ifdef TGL_FEATURE_8_BITS
-    case ZB_MODE_INDEX:
-	ZB_ditherFrameBuffer(zb, buf, linesize >> 1);
-	break;
-#endif
-#ifdef TGL_FEATURE_16_BITS
-    case ZB_MODE_5R6G5B:
-	ZB_copyBuffer(zb, buf, linesize);
-	break;
-#endif
-#ifdef TGL_FEATURE_32_BITS
-    case ZB_MODE_RGBA:
-	ZB_copyFrameBufferRGB32(zb, buf, linesize >> 1);
-	break;
-#endif
-#ifdef TGL_FEATURE_24_BITS
-    case ZB_MODE_RGB24:
-	ZB_copyFrameBufferRGB24(zb, buf, linesize >> 1);
-	break;
-#endif
-    default:
-	assert(0);
-    }
-}
-
-#endif /* TGL_FEATURE_RENDER_BITS == 16 */
-
-#if TGL_FEATURE_RENDER_BITS == 24
-
-#define RGB24_TO_RGB16(r, g, b) \
-  ((((r) >> 3) << 11) | (((g) >> 2) << 5) | ((b) >> 3))
-
-/* XXX: not optimized */
-static void ZB_copyFrameBuffer5R6G5B(ZBuffer * zb, 
-                                     void *buf, int linesize) 
-{
-    PIXEL *q;
-    unsigned short *p, *p1;
-    int y, n;
-
-    q = zb->pbuf;
-    p1 = (unsigned short *) buf;
-
-    for (y = 0; y < zb->ysize; y++) {
-	p = p1;
-	n = zb->xsize >> 2;
-	do {
-            p[0] = RGB24_TO_RGB16(q[0], q[1], q[2]);
-            p[1] = RGB24_TO_RGB16(q[3], q[4], q[5]);
-            p[2] = RGB24_TO_RGB16(q[6], q[7], q[8]);
-            p[3] = RGB24_TO_RGB16(q[9], q[10], q[11]);
-	    q = (PIXEL *)((char *)q + 4 * PSZB);
-	    p += 4;
-	} while (--n > 0);
-	p1 = (unsigned short *)((char *)p1 + linesize);
-    }
-}
-
-void ZB_copyFrameBuffer(ZBuffer * zb, void *buf,
-			int linesize)
-{
-    switch (zb->mode) {
-#ifdef TGL_FEATURE_16_BITS
-    case ZB_MODE_5R6G5B:
-	ZB_copyFrameBuffer5R6G5B(zb, buf, linesize);
-	break;
-#endif
-#ifdef TGL_FEATURE_24_BITS
-    case ZB_MODE_RGB24:
-	ZB_copyBuffer(zb, buf, linesize);
-	break;
-#endif
-    default:
-	assert(0);
-    }
-}
-
-#endif /* TGL_FEATURE_RENDER_BITS == 24 */
-
-#if TGL_FEATURE_RENDER_BITS == 32
-
 #define RGB32_TO_RGB16(v) \
   (((v >> 8) & 0xf800) | (((v) >> 5) & 0x07e0) | (((v) & 0xff) >> 3))
 
@@ -404,8 +180,6 @@ void ZB_copyFrameBuffer(ZBuffer * zb, void *buf,
     }
 }
 
-#endif /* TGL_FEATURE_RENDER_BITS == 32 */
-
 
 /*
  * adr must be aligned on an 'int'
@@ -489,9 +263,7 @@ void memset_RGB24(void *adr,int r, int v, int b,long count)
 void ZB_clear(ZBuffer * zb, int clear_z, int z,
 	      int clear_color, int r, int g, int b)
 {
-#if TGL_FEATURE_RENDER_BITS != 24
     int color;
-#endif
     int y;
     PIXEL *pp;
 
@@ -501,17 +273,8 @@ void ZB_clear(ZBuffer * zb, int clear_z, int z,
     if (clear_color) {
 	pp = zb->pbuf;
 	for (y = 0; y < zb->ysize; y++) {
-#if TGL_FEATURE_RENDER_BITS == 15 || TGL_FEATURE_RENDER_BITS == 16
-            color = RGB_TO_PIXEL(r, g, b);
-	    memset_s(pp, color, zb->xsize);
-#elif TGL_FEATURE_RENDER_BITS == 32
             color = RGB_TO_PIXEL(r, g, b);
 	    memset_l(pp, color, zb->xsize);
-#elif TGL_FEATURE_RENDER_BITS == 24 
-            memset_RGB24(pp,r>>8,g>>8,b>>8,zb->xsize);
-#else
-#error TODO
-#endif
 	    pp = (PIXEL *) ((char *) pp + zb->linesize);
 	}
     }

+ 78 - 54
panda/src/tinydisplay/zbuffer.h

@@ -16,12 +16,14 @@
 #define ZB_POINT_T_MIN ( (1<<21) )
 #define ZB_POINT_T_MAX ( (1<<30)-(1<<21) )
 
-#define ZB_POINT_RED_MIN ( (1<<10) )
-#define ZB_POINT_RED_MAX ( (1<<16)-(1<<10) )
-#define ZB_POINT_GREEN_MIN ( (1<<9) )
-#define ZB_POINT_GREEN_MAX ( (1<<16)-(1<<9) )
-#define ZB_POINT_BLUE_MIN ( (1<<10) )
-#define ZB_POINT_BLUE_MAX ( (1<<16)-(1<<10) )
+#define ZB_POINT_RED_MIN   0x0000
+#define ZB_POINT_RED_MAX   0xff00
+#define ZB_POINT_GREEN_MIN 0x0000
+#define ZB_POINT_GREEN_MAX 0xff00
+#define ZB_POINT_BLUE_MIN  0x0000
+#define ZB_POINT_BLUE_MAX  0xff00
+#define ZB_POINT_ALPHA_MIN 0x0000
+#define ZB_POINT_ALPHA_MAX 0xff00
 
 /* display modes */
 #define ZB_MODE_5R6G5B  1  /* true color 16 bits */
@@ -30,56 +32,18 @@
 #define ZB_MODE_RGB24   4  /* 24 bit rgb mode */
 #define ZB_NB_COLORS    225 /* number of colors for 8 bit display */
 
-#if TGL_FEATURE_RENDER_BITS == 15
-
-#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 
-/* bits per pixel = (1 << PSZH) */
-#define PSZSH 4 
-
-#elif TGL_FEATURE_RENDER_BITS == 16
-
-/* 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 
-
-#elif TGL_FEATURE_RENDER_BITS == 24
-
-#define RGB_TO_PIXEL(r,g,b) \
-  ((((r) << 8) & 0xff0000) | ((g) & 0xff00) | ((b) >> 8))
-typedef unsigned char PIXEL;
-#define PSZB 3
-#define PSZSH 5
-
-#elif TGL_FEATURE_RENDER_BITS == 32
-
 #define RGB_TO_PIXEL(r,g,b) \
   ((((r) << 8) & 0xff0000) | ((g) & 0xff00) | ((b) >> 8))
+#define RGBA_TO_PIXEL(r,g,b,a)                                   \
+  ((((a) << 16) & 0xff000000) | (((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)
+#define PIXEL_A(p) (((p) & 0xff000000) >> 16)
 typedef unsigned int PIXEL;
 #define PSZB 4
 #define PSZSH 5
 
-#else
-
-#error Incorrect number of bits per pixel
-
-#endif
-
 #define PIXEL_MULT(p1, p2) \
   RGB_TO_PIXEL((PIXEL_R(p1) * PIXEL_R(p2)) >> 16, \
                (PIXEL_G(p1) * PIXEL_G(p2)) >> 16, \
@@ -104,7 +68,7 @@ typedef struct {
 typedef struct {
   int x,y,z;     /* integer coordinates in the zbuffer */
   int s,t;       /* coordinates for the mapping */
-  int r,g,b;     /* color indexes */
+  int r,g,b,a;     /* color indexes */
   
   float sz,tz;   /* temporary coordinates for mapping */
 } ZBufferPoint;
@@ -142,20 +106,80 @@ void ZB_line_z(ZBuffer * zb, ZBufferPoint * p1, ZBufferPoint * p2);
 
 /* ztriangle.c */
 
-void ZB_setTexture(ZBuffer *zb, PIXEL *texture);
+void ZB_fillTriangleFlat_anone_znone(ZBuffer *zb,
+		 ZBufferPoint *p1,ZBufferPoint *p2,ZBufferPoint *p3);
+void ZB_fillTriangleSmooth_anone_znone(ZBuffer *zb,
+		   ZBufferPoint *p1,ZBufferPoint *p2,ZBufferPoint *p3);
+
+void ZB_fillTriangleMapping_anone_znone(ZBuffer *zb,
+		    ZBufferPoint *p1,ZBufferPoint *p2,ZBufferPoint *p3);
+void ZB_fillTriangleMappingFlat_anone_znone(ZBuffer *zb,
+		    ZBufferPoint *p1,ZBufferPoint *p2,ZBufferPoint *p3);
+void ZB_fillTriangleMappingSmooth_anone_znone(ZBuffer *zb,
+		    ZBufferPoint *p1,ZBufferPoint *p2,ZBufferPoint *p3);
+
+void ZB_fillTriangleMappingPerspective_anone_znone(ZBuffer *zb,
+                    ZBufferPoint *p0,ZBufferPoint *p1,ZBufferPoint *p2);
+void ZB_fillTriangleMappingPerspectiveFlat_anone_znone(ZBuffer *zb,
+                    ZBufferPoint *p0,ZBufferPoint *p1,ZBufferPoint *p2);
+void ZB_fillTriangleMappingPerspectiveSmooth_anone_znone(ZBuffer *zb,
+                    ZBufferPoint *p0,ZBufferPoint *p1,ZBufferPoint *p2);
 
-void ZB_fillTriangleFlat(ZBuffer *zb,
+void ZB_fillTriangleFlat_anone_zless(ZBuffer *zb,
 		 ZBufferPoint *p1,ZBufferPoint *p2,ZBufferPoint *p3);
+void ZB_fillTriangleSmooth_anone_zless(ZBuffer *zb,
+		   ZBufferPoint *p1,ZBufferPoint *p2,ZBufferPoint *p3);
 
-void ZB_fillTriangleSmooth(ZBuffer *zb,
+void ZB_fillTriangleMapping_anone_zless(ZBuffer *zb,
+		    ZBufferPoint *p1,ZBufferPoint *p2,ZBufferPoint *p3);
+void ZB_fillTriangleMappingFlat_anone_zless(ZBuffer *zb,
+		    ZBufferPoint *p1,ZBufferPoint *p2,ZBufferPoint *p3);
+void ZB_fillTriangleMappingSmooth_anone_zless(ZBuffer *zb,
+		    ZBufferPoint *p1,ZBufferPoint *p2,ZBufferPoint *p3);
+
+void ZB_fillTriangleMappingPerspective_anone_zless(ZBuffer *zb,
+                    ZBufferPoint *p0,ZBufferPoint *p1,ZBufferPoint *p2);
+void ZB_fillTriangleMappingPerspectiveFlat_anone_zless(ZBuffer *zb,
+                    ZBufferPoint *p0,ZBufferPoint *p1,ZBufferPoint *p2);
+void ZB_fillTriangleMappingPerspectiveSmooth_anone_zless(ZBuffer *zb,
+                    ZBufferPoint *p0,ZBufferPoint *p1,ZBufferPoint *p2);
+
+void ZB_fillTriangleFlat_abin_znone(ZBuffer *zb,
+		 ZBufferPoint *p1,ZBufferPoint *p2,ZBufferPoint *p3);
+void ZB_fillTriangleSmooth_abin_znone(ZBuffer *zb,
 		   ZBufferPoint *p1,ZBufferPoint *p2,ZBufferPoint *p3);
 
-void ZB_fillTriangleMapping(ZBuffer *zb,
+void ZB_fillTriangleMapping_abin_znone(ZBuffer *zb,
+		    ZBufferPoint *p1,ZBufferPoint *p2,ZBufferPoint *p3);
+void ZB_fillTriangleMappingFlat_abin_znone(ZBuffer *zb,
+		    ZBufferPoint *p1,ZBufferPoint *p2,ZBufferPoint *p3);
+void ZB_fillTriangleMappingSmooth_abin_znone(ZBuffer *zb,
 		    ZBufferPoint *p1,ZBufferPoint *p2,ZBufferPoint *p3);
 
-void ZB_fillTriangleMappingPerspective(ZBuffer *zb,
+void ZB_fillTriangleMappingPerspective_abin_znone(ZBuffer *zb,
+                    ZBufferPoint *p0,ZBufferPoint *p1,ZBufferPoint *p2);
+void ZB_fillTriangleMappingPerspectiveFlat_abin_znone(ZBuffer *zb,
+                    ZBufferPoint *p0,ZBufferPoint *p1,ZBufferPoint *p2);
+void ZB_fillTriangleMappingPerspectiveSmooth_abin_znone(ZBuffer *zb,
+                    ZBufferPoint *p0,ZBufferPoint *p1,ZBufferPoint *p2);
+
+void ZB_fillTriangleFlat_abin_zless(ZBuffer *zb,
+		 ZBufferPoint *p1,ZBufferPoint *p2,ZBufferPoint *p3);
+void ZB_fillTriangleSmooth_abin_zless(ZBuffer *zb,
+		   ZBufferPoint *p1,ZBufferPoint *p2,ZBufferPoint *p3);
+
+void ZB_fillTriangleMapping_abin_zless(ZBuffer *zb,
+		    ZBufferPoint *p1,ZBufferPoint *p2,ZBufferPoint *p3);
+void ZB_fillTriangleMappingFlat_abin_zless(ZBuffer *zb,
+		    ZBufferPoint *p1,ZBufferPoint *p2,ZBufferPoint *p3);
+void ZB_fillTriangleMappingSmooth_abin_zless(ZBuffer *zb,
+		    ZBufferPoint *p1,ZBufferPoint *p2,ZBufferPoint *p3);
+
+void ZB_fillTriangleMappingPerspective_abin_zless(ZBuffer *zb,
+                    ZBufferPoint *p0,ZBufferPoint *p1,ZBufferPoint *p2);
+void ZB_fillTriangleMappingPerspectiveFlat_abin_zless(ZBuffer *zb,
                     ZBufferPoint *p0,ZBufferPoint *p1,ZBufferPoint *p2);
-void ZB_fillTriangleMappingSmooth(ZBuffer *zb,
+void ZB_fillTriangleMappingPerspectiveSmooth_abin_zless(ZBuffer *zb,
                     ZBufferPoint *p0,ZBufferPoint *p1,ZBufferPoint *p2);
 
 

+ 2 - 27
panda/src/tinydisplay/zfeatures.h

@@ -29,36 +29,11 @@
 #define TGL_FEATURE_DISPLAYLISTS   1
 #define TGL_FEATURE_POLYGON_OFFSET 1
 
-/*
- * Matrix of internal and external pixel formats supported. 'Y' means
- * supported.
- * 
- *           External  8    16    24    32
- * Internal 
- *  15                 .     .     .     .
- *  16                 Y     Y     Y     Y
- *  24                 .     Y     Y     .
- *  32                 .     Y     .     Y
- * 
- *
- * 15 bpp does not work yet (although it is easy to add it - ask me if
- * you need it).
- * 
- * Internal pixel format: see TGL_FEATURE_RENDER_BITS
- * External pixel format: see TGL_FEATURE_xxx_BITS 
- */
-
-/* enable various convertion code from internal pixel format (usually
-   16 bits per pixel) to any external format */
+/* enable various conversion code from internal pixel format (32 bits
+   per pixel) to any external format */
 #define TGL_FEATURE_16_BITS        1
 //#define TGL_FEATURE_8_BITS         1
 #define TGL_FEATURE_24_BITS        1
 #define TGL_FEATURE_32_BITS        1
 
-
-//#define TGL_FEATURE_RENDER_BITS    15
-//#define TGL_FEATURE_RENDER_BITS    16
-//#define TGL_FEATURE_RENDER_BITS    24
-#define TGL_FEATURE_RENDER_BITS    32
-
 #endif /* _tgl_features_h_ */

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

@@ -211,6 +211,7 @@ typedef struct GLContext {
   int cull_face_enabled;
   int normalize_enabled;
   gl_draw_triangle_func draw_triangle_front,draw_triangle_back;
+  ZB_fillTriangleFunc zb_fill_tri;
 
   /* selection */
   int render_mode;

+ 0 - 6
panda/src/tinydisplay/zline.c

@@ -13,13 +13,7 @@ void ZB_plot(ZBuffer * zb, ZBufferPoint * p)
     pp = (PIXEL *) ((char *) zb->pbuf + zb->linesize * p->y + p->x * PSZB);
     zz = p->z >> ZB_POINT_Z_FRAC_BITS;
     if (ZCMP(zz, *pz)) {
-#if TGL_FEATURE_RENDER_BITS == 24 
-        pp[0]=p->r>>8;
-        pp[1]=p->g>>8;
-        pp[2]=p->b>>8;
-#else
 	*pp = RGB_TO_PIXEL(p->r, p->g, p->b);
-#endif
 	*pz = zz;
     }
 }

+ 1 - 14
panda/src/tinydisplay/zline.h

@@ -2,7 +2,7 @@
     int n, dx, dy, sx, pp_inc_1, pp_inc_2;
     register int a;
     register PIXEL *pp;
-#if defined(INTERP_RGB) || TGL_FEATURE_RENDER_BITS == 24
+#if defined(INTERP_RGB)
     register unsigned int r, g, b;
 #endif
 #ifdef INTERP_RGB
@@ -33,27 +33,14 @@
     r = p2->r << 8;
     g = p2->g << 8;
     b = p2->b << 8;
-#elif TGL_FEATURE_RENDER_BITS == 24
-    /* for 24 bits, we store the colors in different variables */
-    r = p2->r >> 8;
-    g = p2->g >> 8;
-    b = p2->b >> 8;
 #endif
 
 #ifdef INTERP_RGB
 #define RGB(x) x
-#if TGL_FEATURE_RENDER_BITS == 24
-#define RGBPIXEL pp[0] = r >> 16, pp[1] = g >> 16, pp[2] = b >> 16
-#else
 #define RGBPIXEL *pp = RGB_TO_PIXEL(r >> 8,g >> 8,b >> 8)
-#endif
 #else /* INTERP_RGB */
 #define RGB(x)
-#if TGL_FEATURE_RENDER_BITS == 24
-#define RGBPIXEL pp[0] = r, pp[1] = g, pp[2] = b
-#else
 #define RGBPIXEL *pp = color
-#endif
 #endif /* INTERP_RGB */
 
 #ifdef INTERP_Z

+ 20 - 301
panda/src/tinydisplay/ztriangle.c

@@ -1,304 +1,23 @@
 #include <stdlib.h>
+#include <stdio.h>
 #include "zbuffer.h"
 
-#define ZCMP(z,zpix) ((z) >= (zpix))
-
-void ZB_fillTriangleFlat(ZBuffer *zb,
-			 ZBufferPoint *p0,ZBufferPoint *p1,ZBufferPoint *p2)
-{
-    int color;
-
-#define INTERP_Z
-
-#define DRAW_INIT()				\
-{						\
-  color=RGB_TO_PIXEL(p2->r,p2->g,p2->b);	\
-}
-  
-#define PUT_PIXEL(_a)				\
-{						\
-    zz=z >> ZB_POINT_Z_FRAC_BITS;		\
-    if (ZCMP(zz,pz[_a])) {				\
-      pp[_a]=color;				\
-      pz[_a]=zz;				\
-    }						\
-    z+=dzdx;					\
-}
-
-#include "ztriangle.h"
-}
-
-/*
- * Smooth filled triangle.
- * The code below is very tricky :)
- */
-
-void ZB_fillTriangleSmooth(ZBuffer *zb,
-			   ZBufferPoint *p0,ZBufferPoint *p1,ZBufferPoint *p2)
-{
-#define INTERP_Z
-#define INTERP_RGB
-
-#define SAR_RND_TO_ZERO(v,n) (v / (1<<n))
-
-#define DRAW_INIT() 				\
-{						\
-}
-
-#define PUT_PIXEL(_a)				\
-{						\
-    zz=z >> ZB_POINT_Z_FRAC_BITS;		\
-    if (ZCMP(zz,pz[_a])) {				\
-      pp[_a] = RGB_TO_PIXEL(or1, og1, ob1);\
-      pz[_a]=zz;				\
-    }\
-    z+=dzdx;					\
-    og1+=dgdx;					\
-    or1+=drdx;					\
-    ob1+=dbdx;					\
-}
-
-#include "ztriangle.h"
-}
-
-void ZB_setTexture(ZBuffer *zb,PIXEL *texture)
-{
-    zb->current_texture=texture;
-}
-
-void ZB_fillTriangleMapping(ZBuffer *zb,
-			    ZBufferPoint *p0,ZBufferPoint *p1,ZBufferPoint *p2)
-{
-    PIXEL *texture;
-
-#define INTERP_Z
-#define INTERP_ST
-
-#define DRAW_INIT()				\
-{						\
-  texture=zb->current_texture;			\
-}
-
-#define PUT_PIXEL(_a)				\
-{						\
-   zz=z >> ZB_POINT_Z_FRAC_BITS;		\
-     if (ZCMP(zz,pz[_a])) {				\
-       pp[_a]=texture[((t & 0x3FC00000) | s) >> 14];	\
-       pz[_a]=zz;				\
-    }						\
-    z+=dzdx;					\
-    s+=dsdx;					\
-    t+=dtdx;					\
-}
-
-#include "ztriangle.h"
-}
-
-/*
- * Texture mapping with perspective correction.
- * We use the gradient method to make less divisions.
- * TODO: pipeline the division
- */
-void ZB_fillTriangleMappingPerspective(ZBuffer *zb,
-                            ZBufferPoint *p0,ZBufferPoint *p1,ZBufferPoint *p2)
-{
-    PIXEL *texture;
-    float fdzdx,fndzdx,ndszdx,ndtzdx;
-
-#define INTERP_Z
-#define INTERP_STZ
-
-#define NB_INTERP 8
-
-#define DRAW_INIT()				\
-{						\
-  texture=zb->current_texture;\
-  fdzdx=(float)dzdx;\
-  fndzdx=NB_INTERP * fdzdx;\
-  ndszdx=NB_INTERP * dszdx;\
-  ndtzdx=NB_INTERP * dtzdx;\
-}
-
-
-#define PUT_PIXEL(_a)				\
-{						\
-   zz=z >> ZB_POINT_Z_FRAC_BITS;		\
-     if (ZCMP(zz,pz[_a])) {				\
-       pp[_a]=*(PIXEL *)((char *)texture+ \
-               (((t & 0x3FC00000) | (s & 0x003FC000)) >> (17 - PSZSH)));\
-       pz[_a]=zz;				\
-    }						\
-    z+=dzdx;					\
-    s+=dsdx;					\
-    t+=dtdx;					\
-}
-
-#define DRAW_LINE()				\
-{						\
-  register unsigned short *pz;		\
-  register PIXEL *pp;		\
-  register unsigned int s,t,z,zz;	\
-  register int n,dsdx,dtdx;		\
-  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;\
-  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;								   \
-  }									   \
-}
-  
-#include "ztriangle.h"
-}
-
-/*
- * Smooth filled triangle, with perspective-correct mapping.
- */
-
-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 SAR_RND_TO_ZERO(v,n) (v / (1<<n))
-
-#define DRAW_INIT() 				\
-{						\
-  texture=zb->current_texture;\
-  fdzdx=(float)dzdx;\
-  fndzdx=NB_INTERP * fdzdx;\
-  ndszdx=NB_INTERP * dszdx;\
-  ndtzdx=NB_INTERP * dtzdx;\
-}
-
-#define PUT_PIXEL(_a)				\
-{						\
-    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;					\
-    og1+=dgdx;					\
-    or1+=drdx;					\
-    ob1+=dbdx;					\
-    s+=dsdx;					\
-    t+=dtdx;					\
-}
-
-#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;								   \
-  }									   \
-}
-
-#include "ztriangle.h"
-}
+#define ACMP(a) 1
+#define ZCMP(z,zpix) 1
+#define FNAME(name) name ## _anone_znone
+#include "ztriangle_two.h"
+
+#define ACMP(a) 1
+#define ZCMP(z,zpix) ((zpix) < (z))
+#define FNAME(name) name ## _anone_zless
+#include "ztriangle_two.h"
+
+#define ACMP(a) ((a) > 0x8000)
+#define ZCMP(z,zpix) 1
+#define FNAME(name) name ## _abin_znone
+#include "ztriangle_two.h"
+
+#define ACMP(a) ((a) > 0x8000)
+#define ZCMP(z,zpix) ((zpix) < (z))
+#define FNAME(name) name ## _abin_zless
+#include "ztriangle_two.h"

+ 13 - 1
panda/src/tinydisplay/ztriangle.h

@@ -23,6 +23,7 @@
   int r1,drdx,drdy,drdl_min,drdl_max;
   int g1,dgdx,dgdy,dgdl_min,dgdl_max;
   int b1,dbdx,dbdy,dbdl_min,dbdl_max;
+  int a1,dadx,dady,dadl_min,dadl_max;
 #endif
 #ifdef INTERP_ST
   int s1,dsdx,dsdy,dsdl_min,dsdl_max;
@@ -91,6 +92,11 @@
   dbdx = (int) (fdy2 * d1 - fdy1 * d2);
   dbdy = (int) (fdx1 * d2 - fdx2 * d1);
 
+  d1 = p1->a - p0->a;
+  d2 = p2->a - p0->a;
+  dadx = (int) (fdy2 * d1 - fdy1 * d2);
+  dady = (int) (fdx1 * d2 - fdx2 * d1);
+
 #endif
   
 #ifdef INTERP_ST
@@ -203,6 +209,10 @@
       b1=l1->b;
       dbdl_min=(dbdy + dbdx * dxdy_min);
       dbdl_max=dbdl_min + dbdx;
+      
+      a1=l1->a;
+      dadl_min=(dady + dadx * dxdy_min);
+      dadl_max=dadl_min + dadx;
 #endif
 #ifdef INTERP_ST
       s1=l1->s;
@@ -250,7 +260,7 @@
           register unsigned int z,zz;
 #endif
 #ifdef INTERP_RGB
-          register unsigned int or1,og1,ob1;
+          register unsigned int or1,og1,ob1,oa1;
 #endif
 #ifdef INTERP_ST
           register unsigned int s,t;
@@ -269,6 +279,7 @@
           or1 = r1;
           og1 = g1;
           ob1 = b1;
+          oa1 = a1;
 #endif
 #ifdef INTERP_ST
           s=s1;
@@ -314,6 +325,7 @@
 	r1+=drdl_max;
 	g1+=dgdl_max;
 	b1+=dbdl_max;
+	a1+=dadl_max;
 #endif
 #ifdef INTERP_ST
 	s1+=dsdl_max;

+ 508 - 0
panda/src/tinydisplay/ztriangle_two.h

@@ -0,0 +1,508 @@
+void FNAME(ZB_fillTriangleFlat) (ZBuffer *zb,
+                      ZBufferPoint *p0,ZBufferPoint *p1,ZBufferPoint *p2)
+{
+    int color;
+    int oa;
+
+#define INTERP_Z
+
+#define DRAW_INIT()                                     \
+    {                                                   \
+      if (!ACMP(p2->a)) {                               \
+        return;                                         \
+      }                                                 \
+      color=RGBA_TO_PIXEL(p2->r,p2->g,p2->b,p2->a);	\
+    }
+  
+#define PUT_PIXEL(_a)				\
+    {						\
+      zz=z >> ZB_POINT_Z_FRAC_BITS;		\
+      if (ZCMP(zz,pz[_a])) {                    \
+        pp[_a]=color;				\
+        pz[_a]=zz;				\
+      }						\
+      z+=dzdx;					\
+    }
+
+#include "ztriangle.h"
+}
+
+/*
+ * Smooth filled triangle.
+ * The code below is very tricky :)
+ */
+
+void FNAME(ZB_fillTriangleSmooth) (ZBuffer *zb,
+			   ZBufferPoint *p0,ZBufferPoint *p1,ZBufferPoint *p2)
+{
+#define INTERP_Z
+#define INTERP_RGB
+
+#define DRAW_INIT() 				\
+  {						\
+  }
+
+#define PUT_PIXEL(_a)                                   \
+  {                                                     \
+    zz=z >> ZB_POINT_Z_FRAC_BITS;                       \
+    if (ZCMP(zz,pz[_a])) {				\
+      if (ACMP(oa1)) {                                  \
+        pp[_a] = RGBA_TO_PIXEL(or1, og1, ob1, oa1);     \
+        pz[_a]=zz;                                      \
+      }                                                 \
+    }                                                   \
+    z+=dzdx;                                            \
+    og1+=dgdx;                                          \
+    or1+=drdx;                                          \
+    ob1+=dbdx;                                          \
+    oa1+=dadx;                                          \
+  }
+
+#include "ztriangle.h"
+}
+
+void FNAME(ZB_fillTriangleMapping) (ZBuffer *zb,
+			    ZBufferPoint *p0,ZBufferPoint *p1,ZBufferPoint *p2)
+{
+    PIXEL *texture;
+
+#define INTERP_Z
+#define INTERP_ST
+
+#define DRAW_INIT()				\
+    {						\
+      texture=zb->current_texture;              \
+    }
+
+#define PUT_PIXEL(_a)                                   \
+    {                                                   \
+      zz=z >> ZB_POINT_Z_FRAC_BITS;                     \
+      if (ZCMP(zz,pz[_a])) {				\
+        tmp=texture[((t & 0x3FC00000) | s) >> 14];      \
+        if (ACMP(PIXEL_A(tmp))) {                       \
+          pp[_a]=tmp;                                   \
+          pz[_a]=zz;                                    \
+        }                                               \
+      }                                                 \
+      z+=dzdx;                                          \
+      s+=dsdx;                                          \
+      t+=dtdx;                                          \
+    }
+
+#include "ztriangle.h"
+}
+
+void FNAME(ZB_fillTriangleMappingFlat) (ZBuffer *zb,
+			    ZBufferPoint *p0,ZBufferPoint *p1,ZBufferPoint *p2)
+{
+    PIXEL *texture;
+    int or, og, ob, oa;
+
+#define INTERP_Z
+#define INTERP_ST
+
+#define DRAW_INIT()				\
+    {						\
+      texture=zb->current_texture;              \
+      or = p2->r;                               \
+      og = p2->g;                               \
+      ob = p2->b;                               \
+      oa = p2->a;                               \
+    }
+
+#define PUT_PIXEL(_a)                                           \
+    {                                                           \
+      zz=z >> ZB_POINT_Z_FRAC_BITS;                             \
+      if (ZCMP(zz,pz[_a])) {                                    \
+        tmp=texture[((t & 0x3FC00000) | s) >> 14];              \
+        int a = oa * PIXEL_A(tmp) >> 16;                        \
+        if (ACMP(a)) {                                          \
+          pp[_a] = RGBA_TO_PIXEL(or * PIXEL_R(tmp) >> 16,       \
+                                 og * PIXEL_G(tmp) >> 16,       \
+                                 ob * PIXEL_B(tmp) >> 16,       \
+                                 a);                            \
+          pz[_a]=zz;                                            \
+        }                                                       \
+      }                                                         \
+      z+=dzdx;                                                  \
+      s+=dsdx;                                                  \
+      t+=dtdx;                                                  \
+    }
+
+#include "ztriangle.h"
+}
+
+void FNAME(ZB_fillTriangleMappingSmooth) (ZBuffer *zb,
+			    ZBufferPoint *p0,ZBufferPoint *p1,ZBufferPoint *p2)
+{
+    PIXEL *texture;
+
+#define INTERP_Z
+#define INTERP_ST
+#define INTERP_RGB
+
+#define DRAW_INIT()				\
+    {						\
+      texture=zb->current_texture;              \
+    }
+
+#define PUT_PIXEL(_a)                                           \
+    {                                                           \
+      zz=z >> ZB_POINT_Z_FRAC_BITS;                             \
+      if (ZCMP(zz,pz[_a])) {                                    \
+        tmp=texture[((t & 0x3FC00000) | s) >> 14];              \
+        int a = oa1 * PIXEL_A(tmp) >> 16;                       \
+        if (ACMP(a)) {                                          \
+          pp[_a] = RGBA_TO_PIXEL(or1 * PIXEL_R(tmp) >> 16,      \
+                                 og1 * PIXEL_G(tmp) >> 16,      \
+                                 ob1 * PIXEL_B(tmp) >> 16,      \
+                                 a);                            \
+          pz[_a]=zz;                                            \
+        }                                                       \
+      }                                                         \
+      z+=dzdx;                                                  \
+      og1+=dgdx;                                                \
+      or1+=drdx;                                                \
+      ob1+=dbdx;                                                \
+      oa1+=dadx;                                                \
+      s+=dsdx;                                                  \
+      t+=dtdx;                                                  \
+    }
+
+#include "ztriangle.h"
+}
+
+/*
+ * Texture mapping with perspective correction.
+ * We use the gradient method to make less divisions.
+ * TODO: pipeline the division
+ */
+void FNAME(ZB_fillTriangleMappingPerspective) (ZBuffer *zb,
+                            ZBufferPoint *p0,ZBufferPoint *p1,ZBufferPoint *p2)
+{
+    PIXEL *texture;
+    float fdzdx,fndzdx,ndszdx,ndtzdx;
+
+#define INTERP_Z
+#define INTERP_STZ
+
+#define NB_INTERP 8
+
+#define DRAW_INIT()				\
+    {						\
+      texture=zb->current_texture;              \
+      fdzdx=(float)dzdx;                        \
+      fndzdx=NB_INTERP * fdzdx;                 \
+      ndszdx=NB_INTERP * dszdx;                 \
+      ndtzdx=NB_INTERP * dtzdx;                 \
+    }
+
+
+#define PUT_PIXEL(_a)                                                   \
+    {                                                                   \
+      zz=z >> ZB_POINT_Z_FRAC_BITS;                                     \
+      if (ZCMP(zz,pz[_a])) {                                            \
+        tmp = *(PIXEL *)((char *)texture+                               \
+                         (((t & 0x3FC00000) | (s & 0x003FC000)) >> (17 - PSZSH))); \
+        if (ACMP(PIXEL_A(tmp))) {                                       \
+          pp[_a]=tmp;                                                   \
+          pz[_a]=zz;                                                    \
+        }                                                               \
+      }                                                                 \
+      z+=dzdx;                                                          \
+      s+=dsdx;                                                          \
+      t+=dtdx;                                                          \
+    }
+
+#define DRAW_LINE()                                     \
+    {                                                   \
+      register unsigned short *pz;                      \
+      register PIXEL *pp;                               \
+      register unsigned int s,t,z,zz;                   \
+      register int n,dsdx,dtdx;                         \
+      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;                                           \
+      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;                                           \
+      }                                                 \
+    }
+  
+#include "ztriangle.h"
+}
+
+/*
+ * Flat shaded triangle, with perspective-correct mapping.
+ */
+
+void FNAME(ZB_fillTriangleMappingPerspectiveFlat) (ZBuffer *zb,
+                                             ZBufferPoint *p0,ZBufferPoint *p1,ZBufferPoint *p2)
+{
+    PIXEL *texture;
+    float fdzdx,fndzdx,ndszdx,ndtzdx;
+    int or, og, ob, oa;
+
+#define INTERP_Z
+#define INTERP_STZ
+#define INTERP_RGB
+
+
+#define DRAW_INIT() 				\
+    {						\
+      texture=zb->current_texture;              \
+      fdzdx=(float)dzdx;                        \
+      fndzdx=NB_INTERP * fdzdx;                 \
+      ndszdx=NB_INTERP * dszdx;                 \
+      ndtzdx=NB_INTERP * dtzdx;                 \
+      or = p2->r;                               \
+      og = p2->g;                               \
+      ob = p2->b;                               \
+      oa = p2->a;                               \
+    }
+
+#define PUT_PIXEL(_a)                                                   \
+    {                                                                   \
+      zz=z >> ZB_POINT_Z_FRAC_BITS;                                     \
+      if (ZCMP(zz,pz[_a])) {                                            \
+        tmp=*(PIXEL *)((char *)texture+                                 \
+                       (((t & 0x3FC00000) | (s & 0x003FC000)) >> (17 - PSZSH))); \
+        int a = oa * PIXEL_A(tmp) >> 16;                                \
+        if (ACMP(a)) {                                                  \
+          pp[_a] = RGBA_TO_PIXEL(or * PIXEL_R(tmp) >> 16,               \
+                                 og * PIXEL_G(tmp) >> 16,               \
+                                 ob * PIXEL_B(tmp) >> 16,               \
+                                 a);                                    \
+          pz[_a]=zz;                                                    \
+        }                                                               \
+      }                                                                 \
+      z+=dzdx;                                                          \
+      s+=dsdx;                                                          \
+      t+=dtdx;                                                          \
+    }
+
+#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,oa1;            \
+      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;                                         \
+      oa1 = a1;                                         \
+      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;                                           \
+      }                                                 \
+    }
+
+#include "ztriangle.h"
+}
+
+/*
+ * Smooth filled triangle, with perspective-correct mapping.
+ */
+
+void FNAME(ZB_fillTriangleMappingPerspectiveSmooth) (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() 				\
+    {						\
+      texture=zb->current_texture;              \
+      fdzdx=(float)dzdx;                        \
+      fndzdx=NB_INTERP * fdzdx;                 \
+      ndszdx=NB_INTERP * dszdx;                 \
+      ndtzdx=NB_INTERP * dtzdx;                 \
+    }
+
+#define PUT_PIXEL(_a)                                                   \
+    {                                                                   \
+      zz=z >> ZB_POINT_Z_FRAC_BITS;                                     \
+      if (ZCMP(zz,pz[_a])) {                                            \
+        tmp=*(PIXEL *)((char *)texture+                                 \
+                       (((t & 0x3FC00000) | (s & 0x003FC000)) >> (17 - PSZSH))); \
+        int a = oa1 * PIXEL_A(tmp) >> 16;                               \
+        if (ACMP(a)) {                                                  \
+          pp[_a] = RGBA_TO_PIXEL(or1 * PIXEL_R(tmp) >> 16,              \
+                                 og1 * PIXEL_G(tmp) >> 16,              \
+                                 ob1 * PIXEL_B(tmp) >> 16,              \
+                                 a);                                    \
+          pz[_a]=zz;                                                    \
+        }                                                               \
+      }                                                                 \
+      z+=dzdx;                                                          \
+      og1+=dgdx;                                                        \
+      or1+=drdx;                                                        \
+      ob1+=dbdx;                                                        \
+      oa1+=dadx;                                                        \
+      s+=dsdx;                                                          \
+      t+=dtdx;                                                          \
+    }
+
+#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,oa1;            \
+      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;                                         \
+      oa1 = a1;                                         \
+      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;                                           \
+      }                                                 \
+    }
+
+#include "ztriangle.h"
+}
+
+#undef ACMP
+#undef ZCMP
+#undef FNAME