shithub: tinygl

Download patch

ref: c9bcf05e0d5eb9302d185d74d2ba2c1e186c841c
author: David <gek@katherine>
date: Thu Feb 11 11:36:52 EST 2021

Initial Commit

--- /dev/null
+++ b/LICENSE
@@ -1,0 +1,24 @@
+Copyright notice:
+
+ (C) 1997-2020 Fabrice Bellard, C-Chads
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product and its documentation 
+     *is* required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+If you redistribute modified sources, I would appreciate that you
+include in the files history information documenting your changes.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Version: TinyGL 0.5-CCHADS
\ No newline at end of file
--- /dev/null
+++ b/LIMITATIONS
@@ -1,0 +1,206 @@
+
+Here are listed the functions that TinyGL understands with the known
+limitations. The non mentionned functions are *not* implemented and
+must not be used.
+
+
+************ glEnable / glDisable
+
+- The following flags are handled:
+
+GL_CULL_FACE, GL_LIGHTING, GL_COLOR_MATERIAL, GL_TEXTURE_2D, GL_NORMALIZE,
+GL_LIGHTx, GL_POLYGON_OFFSET_FILL, GL_POLYGON_OFFSET_POINT,
+GL_POLYGON_OFFSET_LINE
+
+
+- GL_DEPTH_TEST is accepted, but it is only used for lines. For all
+  other primitives, Z buffer use is assumed.  The DepthMode is
+  hardcoded as GL_LESS (OpenGL default).
+
+************ glShadeModel
+
+OK.
+
+************ glCullFace
+
+OK.
+
+************ glPolygonMode
+
+OK.
+
+************ glBegin
+
+No tests are performed to prevent some functions of being executed
+between glBegin/glEnd.
+
+************ glEnd
+
+OK.
+
+************ glVertex
+
+Some prototypes are not implemented.
+
+
+************ glColor
+
+Some prototypes are not implemented.
+
+************ glNormal
+
+Some prototypes are not implemented.
+
+************ glTexCoord
+
+- Some prototypes are not implemented.
+
+- The Matrix transformation is not applied yet.
+
+************ glEdgeFlag
+
+OK. The edge handling has to be tested, although it is not much useful
+in TinyGL.
+
+************ glMatrixMode / glLoadMatrixf / glLoadIdentity / glMultMatrixf /
+             glPushMatrix / glPopMatrix / glRotatef / glTranslatef / glScalef /
+             glFrustum
+
+- The prototypes with doubles are not implemented.
+
+************ glViewport
+
+GlViewport calls a function pointers to tell glx (or another display
+system) to resize the Z buffer and the ximage. Made optional in
+version 0.2.
+
+************ glGenLists / glIsList / glNewList / glEndList / glCallList
+
+OK.
+
+************ glClear / glClearColor / glClearDepth
+
+The whole zbuffer and the colors are cleared in any case. The clear color
+can be redefined, by *not* the initial z value.
+
+************ glRenderMode
+
+Only the modes GL_RENDER and GL_SELECT are implemented.
+
+************ glSelectBuffer / glInitNames / glPushName / glPopName / glLoadName
+
+OK.
+
+************ glGenTextures / glDeleteTextures / glBindTexture 
+
+OK. These functions should be used to get the maximum performance with
+TinyGL. 
+
+************ glTexImage2D
+
+The function accepts only RGB UNSIGNED_BYTES bitmaps. They are
+internally resized to 256x256 so you'd better use that size. No
+mipmapping is implemented although it will come if asked. No borders
+are implemented.
+
+************ glTexEnvi
+
+The only supported mode is GL_DECAL, although others are planned if
+asked.
+
+
+************ glTexParameteri
+
+The other prototypes are not implemented. Only the follwing mode are
+implemented:
+
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+************ glPixelStorei
+
+The pixels are alware byte aligned.
+
+************ glMaterialfv / glMaterialf / glColorMaterial
+
+OK.
+
+
+************ glLightfv / glLightf / glLightModeli / glLightModelfv
+
+OK. The OpenGL lightening is implemented but not optimized.
+
+
+************ glFlush
+
+Ignored.
+
+************ glHint
+
+Ignored.
+
+************ glGetIntegerv
+
+- only GL_VIEWPORT, GL_MAX_MODELVIEW_STACK_DEPTH, 
+GL_MAX_PROJECTION_STACK_DEPTH, GL_MAX_LIGHTS, GL_MAX_TEXTURE_SIZE,
+GL_MAX_TEXTURE_STACK_DEPTH
+
+************ glGetIntegerv
+
+- only GL_TEXTURE_MATRIX, GL_PROJECTION_MATRIX, GL_MODELVIEW_MATRIX,
+GL_LINE_WIDTH, GL_LINE_WIDTH_RANGE, GL_POINT_SIZE, GL_POINT_SIZE_RANGE
+
+************ glPolygonOffset
+
+- only API implemented.
+
+************ glEnableClientState, glDisableClientState,
+             
+- No support for GL_INDEX_ARRAY_POINTER or GL_EDGE_FLAG_ARRAY_POINTER
+
+************ glVertexPointer, glNormalPointer, 
+             glColorPointer, glTexureCoordPointer
+
+- OK
+
+------------------------------------------------------------------------------
+
+TinyGL GLX emulation:
+
+
+************ glXQueryExtension
+
+Returns always True
+
+************ glXChooseVisual
+
+Only 8 bit Pseudocolor or 16 bit Truecolor Visual are accepted. The
+attribute list is ignored.
+
+************ glXCreateContext
+
+The sharing is not implemented although the code could handle it.
+
+************ glXDestroyContext
+
+OK.
+
+************ glXMakeCurrent
+
+Not all the syntax is supported yet, in particular with the 'NULL' or
+'None' parameters.
+
+
+************ glXSwapBuffers
+
+OK.
+
+************ glXWaitGL / glXWaitX
+
+Ignored.
+
+
+See README.BEOS for BeOS limitations.
+
--- /dev/null
+++ b/Makefile
@@ -1,0 +1,7 @@
+
+
+all:
+#	( for f in $(DIRS); do ( cd $$f ; make all ) || exit 1 ; done )
+	cd src && $(MAKE) && cd ..
+clean:
+	cd src && $(MAKE) clean && cd ..
\ No newline at end of file
--- /dev/null
+++ b/README
@@ -1,0 +1,173 @@
+TinyGL 0.5 (c) 1997-2020 Fabrice Bellard, C-Chads (see License, it's free software)
+
+This is a maintained fork of TinyGL, by the C-Chads.
+It is a small, suckless Software-only partial GL 1.1 implementation.
+
+The original project was by Fabrice Bellard. We have forked it.
+The changelog is as such:
+NEW FUNCTIONS
+glSetEnableSpecular(int shouldenablespecular);
+  Allows you to configure specular rendering. Turn it off
+  if you want to use GL_LIGHTING but don't plan on using
+  specular lighting. it will save cycles.
+glGetTexturePixmap(int text, int level, int* xsize, int* ysize)
+  Allows the user to retrieve the raw pixel data of a texture, for their own modification.
+
+
+FIXED BUGS FROM THE ORIGINAL!
+  TinyGL 0.4 had incorrect color interpolation and issues with
+  GL_FLAT, causing the hello world triangle to look rather...
+  wrong. Additionally, per vertex color is just cool.
+
+  It's fixed.
+FULLY COMPATIBLE WITH RGBA!
+  The library is now configured properly for RGBA rendering.
+
+General Description:
+--------------------
+
+TinyGL is intended to be a very small implementation of a subset of
+OpenGL* for embedded systems or games. It is a software only
+implementation. Only the main OpenGL calls are implemented. All the
+calls I considered not important are simply *not implemented*.
+
+The main strength of TinyGL is that it is fast and simple because it
+has not to be exactly compatible with OpenGL. In particular, the
+texture mapping and the geometrical transformations are very fast.
+
+The main features of TinyGL are:
+
+- Header compatible with OpenGL (the headers are adapted from the very good
+Mesa by Brian Paul et al.)
+
+- Zlib-like licence for easy integration in commercial designs (read
+the LICENCE file).
+
+- Subset of GLX for easy testing with X Window. 
+
+- GLX like API (NGLX) to use it with NanoX in MicroWindows/NanoX.
+
+- Subset of BGLView under BeOS.
+
+- OpenGL like lightening.
+
+- Complete OpenGL selection mode handling for object picking.
+
+- 16 bit Z buffer. 16/24/32 bit RGB rendering. High speed dithering to
+paletted 8 bits if needed. High speed conversion to 24 bit packed
+pixel or 32 bit RGBA if needed.
+
+- Fast Gouraud shadding optimized for 16 bit RGB.
+
+- Fast texture mapping capabilities, with perspective correction and
+texture objects.
+
+- 32 bit float only arithmetic.
+
+- Very small: compiled code size of about 40 kB on x86. The file
+  src/zfeatures.h can be used to remove some unused features from
+  TinyGL.
+
+- C sources for GCC on 32/64 bit architectures. It has been tested
+succesfully on x86-Linux and sparc-Solaris.
+
+Examples:
+---------
+
+I took three simple examples from the Mesa package to test the main
+functions of TinyGL. You can link them to either TinyGL, Mesa or any
+other OpenGL/GLX implementation. You can also compile them with
+Microwindows.
+
+- texobj illustrates the use of texture objects. Its shows the speed
+of TinyGL in this case.
+
+- glutmech comes from the GLUT packages. It is much bigger and slower
+because it uses the lightening. I have just included some GLU
+functions and suppressed the GLUT related code to make it work. It
+shows the display list handling of TinyGL in particular. You can look
+at the source code to learn the keys to move the robot. The key 't'
+toggles between shaded rendering and wire frame.
+
+- You can download and compile the VReng project to see that TinyGL
+has been successfully used in a big project
+(http://www-inf.enst.fr/vreng).
+
+Architecture:
+-------------
+
+TinyGL is made up four main modules:
+
+- Mathematical routines (zmath).
+
+- OpenGL-like emulation (zgl).
+
+- Z buffer and rasterisation (zbuffer).
+
+- GLX interface (zglx).
+
+To use TinyGL in an embedded system, you should look at the GLX layer
+and modify it to suit your need. Adding a more user friendly
+developper layer (as in Mesa) may be useful.
+
+Notes - limitations:
+--------------------
+
+- See the file 'LIMITATIONS' to see the current functions supported by the API.
+
+- The multithreading could be easily implemented since no global state
+is maintainted. The library gets the current context with a function
+which can be modified.
+
+- The lightening is not very fast. I supposed that in most games the
+lightening is computed by the 3D engine.
+
+- Some changes are needed for 64 bit pointers for the handling of
+arrays of float with the GLParam union.
+
+- List sharing is partialy supported in the source, but not by the
+current TinyGLX implementation (is it really useful ?).
+
+- No user clipping planes are supported.
+
+- No color index mode (no longer useful !)
+
+- The mipmapping is not implemented.
+
+- The perspecture correction in the mapping code does not use W but
+1/Z. In any 'normal scene' it should work.
+
+- The resizing of the viewport in TinyGLX ensures that the width and
+the height are multiples of 4. This is not optimal because some pixels
+of the window may not be refreshed.
+
+Why ?
+-----
+
+TinyGL was developped as a student project for a Virtual Reality
+network system called VReng (see the VReng home page at
+http://www-inf.enst.fr/vreng).
+
+At that time (January 1997), my initial project was to write my own 3D
+rasterizer based on some old sources I wrote. But I realized that it
+would be better to use OpenGL to work on any platform. My problem was
+that I wanted to use texture mapping which was (and is still) quite
+slower on many software OpenGL implementation. I could have modified
+Mesa to suit my needs, but I really wanted to use my old sources for
+that project. 
+
+I finally decided to use the same syntax as OpenGL but with my own
+libraries, thinking that later it could ease the porting of VReng to
+OpenGL.
+
+Now VReng is at last compatible with OpenGL, and I managed to patch
+TinyGL so that VReng can still work with it without any modifications.
+
+Since TinyGL may be useful for some people, especially in the world of
+embedded designs, I decided to release it 'as is', otherwise, it would
+have been lost on my hard disk !
+
+------------------------------------------------------------------------------
+* OpenGL(R) is a registered trademark of Silicon Graphics, Inc.
+------------------------------------------------------------------------------
+Fabrice Bellard.
--- /dev/null
+++ b/config-old.mk
@@ -1,0 +1,82 @@
+#####################################################################
+# C compiler
+
+# linux
+CC= gcc
+CFLAGS= -g -Wall -O2
+LFLAGS=
+
+# for BeOS PPC
+#CC= mwcc
+#CFLAGS= -I. -i-
+#LFLAGS=
+
+#####################################################################
+# TinyGL configuration 
+
+#####################################################################
+# Select window API for TinyGL: 
+
+# standard X11 GLX like API 
+TINYGL_USE_GLX=y
+
+# BEOS API
+#TINYGL_USE_BEOS=y
+
+# Micro Windows NanoX API
+#TINYGL_USE_NANOX=y
+
+#####################################################################
+# X11 configuration (for the examples only)
+
+ifdef TINYGL_USE_GLX
+# Linux
+UI_LIBS= -L/usr/X11R6/lib -lX11 -lXext
+UI_INCLUDES= 
+# Solaris
+#UI_LIBS= -L/usr/X11/lib -lX11 -lXext -lsocket -lnsl
+#UI_INCLUDES= 
+
+UI_OBJS=x11.o
+endif
+
+#####################################################################
+# Micro windowX11 configuration (for the examples only)
+
+ifdef TINYGL_USE_NANOX
+UI_LIBS= -lnano-X -lmwengine -lmwdrivers -lmwfonts
+UI_INCLUDES=
+
+# X11 target for nanoX
+UI_LIBS+= -L/usr/X11R6/lib -lX11 -lXext
+
+UI_OBJS=nanox.o
+endif
+
+#####################################################################
+# OpenGL configuration (for the examples only)
+
+# use TinyGL 
+GL_LIBS= -L../lib -lTinyGL 
+GL_INCLUDES= -I../include
+GL_DEPS= ../lib/libTinyGL.a
+
+# use Mesa
+#GL_LIBS= -lMesaGL 
+#GL_INCLUDES= 
+#GL_DEPS=
+
+# use OpenGL
+#GL_LIBS= -lGL 
+#GL_INCLUDES= 
+#GL_DEPS=
+
+####################################################################
+# Compile and link control
+
+# UNIX systems
+DIRS= src examples
+
+# BeOS
+# DIRS= src BeOS
+
--- /dev/null
+++ b/src/LICENSE
@@ -1,0 +1,24 @@
+Copyright notice:
+
+ (C) 1997-2020 Fabrice Bellard, C-Chads
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product and its documentation 
+     *is* required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+If you redistribute modified sources, I would appreciate that you
+include in the files history information documenting your changes.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Version: TinyGL 0.5-CCHADS
\ No newline at end of file
--- /dev/null
+++ b/src/LIMITATIONS
@@ -1,0 +1,171 @@
+
+Here are listed the functions that TinyGL understands with the known
+limitations. The non mentionned functions are *not* implemented and
+must not be used.
+
+
+************ glEnable / glDisable
+
+- The following flags are handled:
+
+GL_CULL_FACE, GL_LIGHTING, GL_COLOR_MATERIAL, GL_TEXTURE_2D, GL_NORMALIZE,
+GL_LIGHTx, GL_POLYGON_OFFSET_FILL, GL_POLYGON_OFFSET_POINT, GL_POLYGON_STIPPLE,
+GL_POLYGON_OFFSET_LINE
+
+
+- GL_DEPTH_TEST is accepted, but it is only used for lines. For all
+  other primitives, Z buffer use is assumed.  The DepthMode is
+  hardcoded as GL_LESS (OpenGL default).
+
+************ glPolygonStipple
+OK. (Implemented by Gek! The variables for it are stored per zBuffer rather than per context.)
+
+************ glShadeModel
+
+OK.
+
+************ glCullFace
+
+OK.
+
+************ glPolygonMode
+
+OK.
+
+************ glBegin
+
+No tests are performed to prevent some functions of being executed
+between glBegin/glEnd.
+
+************ glEnd
+
+OK.
+
+************ glVertex
+
+Some prototypes are not implemented.
+
+
+************ glColor
+
+Some prototypes are not implemented.
+
+************ glNormal
+
+Some prototypes are not implemented.
+
+************ glTexCoord
+
+- Some prototypes are not implemented.
+
+- The Matrix transformation is not applied yet.
+
+************ glEdgeFlag
+
+OK. The edge handling has to be tested, although it is not much useful
+in TinyGL.
+
+************ glMatrixMode / glLoadMatrixf / glLoadIdentity / glMultMatrixf /
+             glPushMatrix / glPopMatrix / glRotatef / glTranslatef / glScalef /
+             glFrustum
+
+- The prototypes with doubles are not implemented.
+
+************ glViewport
+
+GlViewport calls a function pointers to tell glx (or another display
+system) to resize the Z buffer and the ximage. Made optional in
+version 0.2.
+
+************ glGenLists / glIsList / glNewList / glEndList / glCallList
+
+OK.
+
+************ glClear / glClearColor / glClearDepth
+
+The whole zbuffer and the colors are cleared in any case. The clear color
+can be redefined, by *not* the initial z value.
+
+************ glRenderMode
+
+Only the modes GL_RENDER and GL_SELECT are implemented.
+
+************ glSelectBuffer / glInitNames / glPushName / glPopName / glLoadName
+
+OK.
+
+************ glGenTextures / glDeleteTextures / glBindTexture 
+
+OK. These functions should be used to get the maximum performance with
+TinyGL. 
+
+************ glTexImage2D
+
+The function accepts only RGB UNSIGNED_BYTES bitmaps. They are
+internally resized to 256x256 so you'd better use that size. No
+mipmapping is implemented (TODO)
+
+************ glTexEnvi
+
+The only supported mode is GL_DECAL, although others are planned if
+asked.
+
+
+************ glTexParameteri
+
+The other prototypes are not implemented. Only the follwing mode are
+implemented:
+
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+************ glPixelStorei
+
+The pixels are always byte aligned.
+
+************ glMaterialfv / glMaterialf / glColorMaterial
+
+OK.
+
+
+************ glLightfv / glLightf / glLightModeli / glLightModelfv
+
+OK. The OpenGL lightening is implemented but not optimized.
+
+
+************ glFlush
+
+Ignored.
+
+************ glHint
+
+Ignored.
+
+************ glGetIntegerv
+
+- only GL_VIEWPORT, GL_MAX_MODELVIEW_STACK_DEPTH, 
+GL_MAX_PROJECTION_STACK_DEPTH, GL_MAX_LIGHTS, GL_MAX_TEXTURE_SIZE,
+GL_MAX_TEXTURE_STACK_DEPTH
+
+************ glGetIntegerv
+
+- only GL_TEXTURE_MATRIX, GL_PROJECTION_MATRIX, GL_MODELVIEW_MATRIX,
+GL_LINE_WIDTH, GL_LINE_WIDTH_RANGE, GL_POINT_SIZE, GL_POINT_SIZE_RANGE
+
+************ glPolygonOffset
+
+- only API implemented.
+
+************ glEnableClientState, glDisableClientState,
+             
+- No support for GL_INDEX_ARRAY_POINTER or GL_EDGE_FLAG_ARRAY_POINTER
+
+************ glVertexPointer, glNormalPointer, 
+             glColorPointer, glTexureCoordPointer
+
+- OK
+
+------------------------------------------------------------------------------
+
--- /dev/null
+++ b/src/Makefile
@@ -1,0 +1,44 @@
+include config.mk
+
+OBJS= api.o list.o vertex.o init.o matrix.o texture.o \
+      misc.o clear.o light.o clip.o select.o get.o error.o \
+      zbuffer.o zline.o zdither.o ztriangle.o \
+      zmath.o image_util.o oscontext.o msghandling.o \
+      arrays.o specbuf.o memory.o
+ifdef TINYGL_USE_GLX
+#OBJS += glx.o
+endif
+ifdef TINYGL_USE_NANOX
+OBJS += nglx.o
+endif
+
+INCLUDES = -I./include
+LIB = libTinyGL.a
+
+all: $(LIB) SDL_Examples
+
+$(LIB): $(OBJS)
+	rm -f $(LIB)
+	ar rcs $(LIB) $(OBJS)
+	
+SDL_Examples:
+	cd SDL_Examples && $(MAKE) && cd ..
+clean:
+	rm -f *~ *.o *.a
+	cd SDL_Examples && $(MAKE) clean && cd ..
+.c.o:
+	$(CC) $(CFLAGS) $(INCLUDES) -c $*.c
+
+clip.o: zgl.h zfeatures.h
+vertex.o: zgl.h zfeatures.h
+light.o: zgl.h zfeatures.h
+matrix.o: zgl.h zfeatures.h
+list.o: zgl.h opinfo.h zfeatures.h
+arrays.c: zgl.h zfeatures.h
+specbuf.o: zgl.h zfeatures.h
+glx.o: zgl.h zfeatures.h
+nglx.o: zgl.h zfeatures.h
+zline.o: zgl.h zfeatures.h zline.h
+
+ztriangle.o: ztriangle.c ztriangle.h zgl.h zfeatures.h
+	$(CC) $(CFLAGS) -Wno-uninitialized $(INCLUDES) -c $*.c
--- /dev/null
+++ b/src/SDL_Examples/Makefile
@@ -1,0 +1,10 @@
+CC= gcc
+CFLAGS = -g -Wall -O3
+GL_LIBS= -L../ 
+GL_INCLUDES= -I../include/
+ALL_T= gears
+all: $(ALL_T)
+clean:
+	rm -f $(ALL_T)
+gears:
+	gcc gears.c ../libTinyGL.a -o gears $(GL_INCLUDES) $(GL_LIBS) $(CFLAGS) -lSDL -lm
\ No newline at end of file
--- /dev/null
+++ b/src/SDL_Examples/gears.c
@@ -1,0 +1,344 @@
+/* sdlGears.c */
+/*
+ * 3-D gear wheels by Brian Paul. This program is in the public domain.
+ *
+ * ported to libSDL/TinyGL by Gerald Franz (gfz@o2online.de)
+ */
+
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "../include/GL/gl.h"
+#include <SDL/SDL.h>
+#include "../zbuffer.h"
+
+#ifndef M_PI
+#  define M_PI 3.14159265
+#endif
+
+
+/*
+ * Draw a gear wheel.  You'll probably want to call this function when
+ * building a display list since we do a lot of trig here.
+ *
+ * Input:  inner_radius - radius of hole at center
+ *         outer_radius - radius at center of teeth
+ *         width - width of gear
+ *         teeth - number of teeth
+ *         tooth_depth - depth of tooth
+ */
+static void gear( GLfloat inner_radius, GLfloat outer_radius, GLfloat width,
+                 GLint teeth, GLfloat tooth_depth )
+{
+    GLint i;
+    GLfloat r0, r1, r2;
+    GLfloat angle, da;
+    GLfloat u, v, len;
+
+    r0 = inner_radius;
+    r1 = outer_radius - tooth_depth/2.0;
+    r2 = outer_radius + tooth_depth/2.0;
+
+    da = 2.0*M_PI / teeth / 4.0;
+
+    glShadeModel( GL_FLAT );
+
+    glNormal3f( 0.0, 0.0, 1.0 );
+
+    /* draw front face */
+    glBegin( GL_QUAD_STRIP );
+    for (i=0;i<=teeth;i++) {
+        angle = i * 2.0*M_PI / teeth;
+        glVertex3f( r0*cos(angle), r0*sin(angle), width*0.5 );
+        glVertex3f( r1*cos(angle), r1*sin(angle), width*0.5 );
+        glVertex3f( r0*cos(angle), r0*sin(angle), width*0.5 );
+        glVertex3f( r1*cos(angle+3*da), r1*sin(angle+3*da), width*0.5 );
+    }
+    glEnd();
+
+    /* draw front sides of teeth */
+    glBegin( GL_QUADS );
+    da = 2.0*M_PI / teeth / 4.0;
+    for (i=0;i<teeth;i++) {
+        angle = i * 2.0*M_PI / teeth;
+
+        glVertex3f( r1*cos(angle),      r1*sin(angle),      width*0.5 );
+        glVertex3f( r2*cos(angle+da),   r2*sin(angle+da),   width*0.5 );
+        glVertex3f( r2*cos(angle+2*da), r2*sin(angle+2*da), width*0.5 );
+        glVertex3f( r1*cos(angle+3*da), r1*sin(angle+3*da), width*0.5 );
+    }
+    glEnd();
+
+    glNormal3f( 0.0, 0.0, -1.0 );
+
+    /* draw back face */
+    glBegin( GL_QUAD_STRIP );
+    for (i=0;i<=teeth;i++) {
+        angle = i * 2.0*M_PI / teeth;
+        glVertex3f( r1*cos(angle), r1*sin(angle), -width*0.5 );
+        glVertex3f( r0*cos(angle), r0*sin(angle), -width*0.5 );
+        glVertex3f( r1*cos(angle+3*da), r1*sin(angle+3*da), -width*0.5 );
+        glVertex3f( r0*cos(angle), r0*sin(angle), -width*0.5 );
+    }
+    glEnd();
+
+    /* draw back sides of teeth */
+    glBegin( GL_QUADS );
+    da = 2.0*M_PI / teeth / 4.0;
+    for (i=0;i<teeth;i++) {
+        angle = i * 2.0*M_PI / teeth;
+
+        glVertex3f( r1*cos(angle+3*da), r1*sin(angle+3*da), -width*0.5 );
+        glVertex3f( r2*cos(angle+2*da), r2*sin(angle+2*da), -width*0.5 );
+        glVertex3f( r2*cos(angle+da),   r2*sin(angle+da),   -width*0.5 );
+        glVertex3f( r1*cos(angle),      r1*sin(angle),      -width*0.5 );
+    }
+    glEnd();
+
+    /* draw outward faces of teeth */
+    glBegin( GL_QUAD_STRIP );
+    for (i=0;i<teeth;i++) {
+        angle = i * 2.0*M_PI / teeth;
+
+        glVertex3f( r1*cos(angle),      r1*sin(angle),       width*0.5 );
+        glVertex3f( r1*cos(angle),      r1*sin(angle),      -width*0.5 );
+        u = r2*cos(angle+da) - r1*cos(angle);
+        v = r2*sin(angle+da) - r1*sin(angle);
+        len = sqrt( u*u + v*v );
+        u /= len;
+        v /= len;
+        glNormal3f( v, -u, 0.0 );
+        glVertex3f( r2*cos(angle+da),   r2*sin(angle+da),    width*0.5 );
+        glVertex3f( r2*cos(angle+da),   r2*sin(angle+da),   -width*0.5 );
+        glNormal3f( cos(angle), sin(angle), 0.0 );
+        glVertex3f( r2*cos(angle+2*da), r2*sin(angle+2*da),  width*0.5 );
+        glVertex3f( r2*cos(angle+2*da), r2*sin(angle+2*da), -width*0.5 );
+        u = r1*cos(angle+3*da) - r2*cos(angle+2*da);
+        v = r1*sin(angle+3*da) - r2*sin(angle+2*da);
+        glNormal3f( v, -u, 0.0 );
+        glVertex3f( r1*cos(angle+3*da), r1*sin(angle+3*da),  width*0.5 );
+        glVertex3f( r1*cos(angle+3*da), r1*sin(angle+3*da), -width*0.5 );
+        glNormal3f( cos(angle), sin(angle), 0.0 );
+    }
+
+    glVertex3f( r1*cos(0), r1*sin(0), width*0.5 );
+    glVertex3f( r1*cos(0), r1*sin(0), -width*0.5 );
+
+    glEnd();
+
+
+    glShadeModel( GL_SMOOTH );
+
+    /* draw inside radius cylinder */
+    glBegin( GL_QUAD_STRIP );
+    for (i=0;i<=teeth;i++) {
+        angle = i * 2.0*M_PI / teeth;
+        glNormal3f( -cos(angle), -sin(angle), 0.0 );
+        glVertex3f( r0*cos(angle), r0*sin(angle), -width*0.5 );
+        glVertex3f( r0*cos(angle), r0*sin(angle), width*0.5 );
+    }
+    glEnd();
+
+}
+
+
+static GLfloat view_rotx=20.0, view_roty=30.0;
+static GLint gear1, gear2, gear3;
+static GLfloat angle = 0.0;
+
+void draw() {
+    angle += 2.0;
+    glPushMatrix();
+    glRotatef( view_rotx, 1.0, 0.0, 0.0 );
+    glRotatef( view_roty, 0.0, 1.0, 0.0 );
+    //glRotatef( view_rotz, 0.0, 0.0, 1.0 );
+
+    glPushMatrix();
+    glTranslatef( -3.0, -2.0, 0.0 );
+    glRotatef( angle, 0.0, 0.0, 1.0 );
+    glCallList(gear1);
+    glPopMatrix();
+
+    glPushMatrix();
+    glTranslatef( 3.1, -2.0, 0.0 );
+    glRotatef( -2.0*angle-9.0, 0.0, 0.0, 1.0 );
+    glCallList(gear2);
+    glPopMatrix();
+
+    glPushMatrix();
+    glTranslatef( -3.1, 4.2, 0.0 );
+    glRotatef( -2.0*angle-25.0, 0.0, 0.0, 1.0 );
+    glCallList(gear3);
+    glPopMatrix();
+
+    glPopMatrix();
+}
+
+
+void initScene() {
+    static GLfloat pos[4] = {5.0, 5.0, 10.0, 0.0 };
+    static GLfloat red[4] = {0.8, 0.1, 0.0, 1.0 };
+    static GLfloat green[4] = {0.0, 0.8, 0.2, 1.0 };
+    static GLfloat blue[4] = {0.2, 0.2, 1.0, 1.0 };
+
+    glLightfv( GL_LIGHT0, GL_POSITION, pos );
+    glEnable( GL_CULL_FACE );
+    glEnable( GL_LIGHTING );
+    glEnable( GL_LIGHT0 );
+    glEnable( GL_DEPTH_TEST );
+
+    /* make the gears */
+    gear1 = glGenLists(1);
+    glNewList(gear1, GL_COMPILE);
+    glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red );
+    gear( 1.0, 4.0, 1.0, 20, 0.7 );
+    glEndList();
+
+    gear2 = glGenLists(1);
+    glNewList(gear2, GL_COMPILE);
+    glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green );
+    gear( 0.5, 2.0, 2.0, 10, 0.7 );
+    glEndList();
+
+    gear3 = glGenLists(1);
+    glNewList(gear3, GL_COMPILE);
+    glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue );
+    gear( 1.3, 2.0, 0.5, 10, 0.7 );
+    glEndList();
+    glEnable( GL_NORMALIZE );
+}
+
+int main(int argc, char **argv) {
+    // initialize SDL video:
+    int winSizeX=320;
+    int winSizeY=480;
+    if(SDL_Init(SDL_INIT_VIDEO)<0) {
+        fprintf(stderr,"ERROR: cannot initialize SDL video.\n");
+        return 1;
+    }
+    SDL_Surface* screen = NULL;
+    if((screen=SDL_SetVideoMode( winSizeX, winSizeY, 32, SDL_SWSURFACE)) == 0 ) {
+        fprintf(stderr,"ERROR: Video mode set failed.\n");
+        return 1;
+    }
+    SDL_ShowCursor(SDL_DISABLE);
+    SDL_WM_SetCaption(argv[0],0);
+
+    // initialize TinyGL:
+    unsigned int pitch;
+    int	mode;
+    switch( screen->format->BitsPerPixel ) {
+    case  8:
+        fprintf(stderr,"ERROR: Palettes are currently not supported.\n");
+        fprintf(stderr,"\nUnsupported by maintainer!!!");
+        return 1;
+    case 16:
+        pitch = screen->pitch;
+        fprintf(stderr,"\nUnsupported by maintainer!!!");
+        mode = ZB_MODE_5R6G5B;
+        break;
+    case 24:
+        pitch = ( screen->pitch * 2 ) / 3;
+        fprintf(stderr,"\nUnsupported by maintainer!!!");
+        mode = ZB_MODE_RGB24;
+        break;
+    case 32:
+        pitch = screen->pitch / 2;
+        mode = ZB_MODE_RGBA;
+        break;
+    default:
+        return 1;
+        break;
+    }
+    ZBuffer *frameBuffer = ZB_open( winSizeX, winSizeY, mode, 0, 0, 0, 0);
+    glInit( frameBuffer );
+
+    // initialize GL:
+    glClearColor (0.0, 0.0, 0.0, 0.0);
+    glViewport (0, 0, winSizeX, winSizeY);
+    glEnable(GL_DEPTH_TEST);
+    GLfloat  h = (GLfloat) winSizeY / (GLfloat) winSizeX;
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    glFrustum( -1.0, 1.0, -h, h, 5.0, 60.0 );
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+    glTranslatef( 0.0, 0.0, -45.0 );
+
+    initScene();
+
+    // variables for timing:
+    unsigned int frames=0;
+    unsigned int tNow=SDL_GetTicks();
+    unsigned int tLastFps=tNow;
+
+    // main loop:
+    int isRunning=1;
+    while(isRunning) {
+        ++frames;
+        tNow=SDL_GetTicks();
+        // do event handling:
+        SDL_Event evt;
+        while( SDL_PollEvent( &evt ) ) switch(evt.type) {
+        case SDL_KEYDOWN:
+            switch(evt.key.keysym.sym) {
+            case SDLK_UP:
+                view_rotx += 5.0;
+                break;
+            case SDLK_DOWN:
+                view_rotx -= 5.0;
+                break;
+            case SDLK_LEFT:
+                view_roty += 5.0;
+                break;
+            case SDLK_RIGHT:
+                view_roty -= 5.0;
+                break;
+            case SDLK_ESCAPE :
+            case SDLK_q :
+                isRunning=0;
+            default:
+                break;
+            }
+            break;
+        case SDL_QUIT:
+            isRunning=0;
+            break;
+        }
+
+        // draw scene:
+        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+        draw();
+
+        // swap buffers:
+        if ( SDL_MUSTLOCK(screen) && (SDL_LockSurface(screen)<0) ) {
+            fprintf(stderr, "SDL ERROR: Can't lock screen: %s\n", SDL_GetError());
+            return 1;
+        }
+        ZB_copyFrameBuffer(frameBuffer, screen->pixels, screen->pitch);
+        if ( SDL_MUSTLOCK(screen) ) SDL_UnlockSurface(screen);
+        SDL_Flip(screen);
+
+        // check for error conditions:
+        char* sdl_error = SDL_GetError( );
+        if( sdl_error[0] != '\0' ) {
+            fprintf(stderr,"SDL ERROR: \"%s\"\n",sdl_error);
+            SDL_ClearError();
+        }
+        // update fps:
+        if(tNow>=tLastFps+5000) {
+            printf("%i frames in %f secs, %f frames per second.\n",frames,(float)(tNow-tLastFps)*0.001f,(float)frames*1000.0f/(float)(tNow-tLastFps));
+            tLastFps=tNow;
+            frames=0;
+        }
+    }
+    printf("%i frames in %f secs, %f frames per second.\n",frames,(float)(tNow-tLastFps)*0.001f,(float)frames*1000.0f/(float)(tNow-tLastFps));
+    // cleanup:
+    ZB_close(frameBuffer);
+    if(SDL_WasInit(SDL_INIT_VIDEO))
+        SDL_QuitSubSystem(SDL_INIT_VIDEO);
+    SDL_Quit();
+    return 0;
+}
--- /dev/null
+++ b/src/api.c
@@ -1,0 +1,668 @@
+#include "zgl.h"
+#include <stdio.h>
+/* glVertex */
+
+void glVertex4f(float x,float y,float z,float w)
+{
+  GLParam p[5];
+
+  p[0].op=OP_Vertex;
+  p[1].f=x;
+  p[2].f=y;
+  p[3].f=z;
+  p[4].f=w;
+
+  gl_add_op(p);
+}
+
+void glVertex2f(float x,float y) 
+{
+  glVertex4f(x,y,0,1);
+}
+
+void glVertex3f(float x,float y,float z) 
+{
+  glVertex4f(x,y,z,1);
+}
+
+void glVertex3fv(float *v) 
+{
+  glVertex4f(v[0],v[1],v[2],1);
+}
+
+/* glNormal */
+
+void glNormal3f(float x,float y,float z)
+{
+  GLParam p[4];
+
+  p[0].op=OP_Normal;
+  p[1].f=x;
+  p[2].f=y;
+  p[3].f=z;
+
+  gl_add_op(p);
+}
+
+void glNormal3fv(float *v) 
+{
+  glNormal3f(v[0],v[1],v[2]);
+}
+
+/* glColor */
+
+void glColor4f(float r,float g,float b,float a)
+{
+  GLParam p[8];
+
+  p[0].op=OP_Color;
+  p[1].f=r;
+  p[2].f=g;
+  p[3].f=b;
+  p[4].f=a;
+  /* direct convertion to integer to go faster if no shading */
+  p[5].ui = (unsigned int) (r * (ZB_POINT_RED_MAX - ZB_POINT_RED_MIN) + 
+                            ZB_POINT_RED_MIN);
+  p[6].ui = (unsigned int) (g * (ZB_POINT_GREEN_MAX - ZB_POINT_GREEN_MIN) + 
+                            ZB_POINT_GREEN_MIN);
+  p[7].ui = (unsigned int) (b * (ZB_POINT_BLUE_MAX - ZB_POINT_BLUE_MIN) + 
+                            ZB_POINT_BLUE_MIN);
+  gl_add_op(p);
+}
+
+void glColor4fv(float *v)
+{
+  GLParam p[8];
+
+  p[0].op=OP_Color;
+  p[1].f=v[0];
+  p[2].f=v[1];
+  p[3].f=v[2];
+  p[4].f=v[3];
+  /* direct convertion to integer to go faster if no shading */
+  p[5].ui = (unsigned int) (v[0] * (ZB_POINT_RED_MAX - ZB_POINT_RED_MIN) + 
+                            ZB_POINT_RED_MIN);
+  p[6].ui = (unsigned int) (v[1] * (ZB_POINT_GREEN_MAX - ZB_POINT_GREEN_MIN) + 
+                            ZB_POINT_GREEN_MIN);
+  p[7].ui = (unsigned int) (v[2] * (ZB_POINT_BLUE_MAX - ZB_POINT_BLUE_MIN) + 
+                            ZB_POINT_BLUE_MIN);
+  gl_add_op(p);
+}
+
+void glColor3f(float x,float y,float z) 
+{
+  glColor4f(x,y,z,1);
+}
+
+void glColor3fv(float *v) 
+{
+  glColor4f(v[0],v[1],v[2],1);
+}
+
+
+/* TexCoord */
+
+void glTexCoord4f(float s,float t,float r,float q)
+{
+  GLParam p[5];
+
+  p[0].op=OP_TexCoord;
+  p[1].f=s;
+  p[2].f=t;
+  p[3].f=r;
+  p[4].f=q;
+
+  gl_add_op(p);
+}
+
+void glTexCoord2f(float s,float t)
+{
+  glTexCoord4f(s,t,0,1);
+}
+
+void glTexCoord2fv(float *v)
+{
+  glTexCoord4f(v[0],v[1],0,1);
+}
+
+void glEdgeFlag(int flag)
+{
+  GLParam p[2];
+
+  p[0].op=OP_EdgeFlag;
+  p[1].i=flag;
+
+  gl_add_op(p);
+}
+
+/* misc */
+
+void glShadeModel(int mode)
+{
+  GLParam p[2];
+
+  assert(mode == GL_FLAT || mode == GL_SMOOTH);
+
+  p[0].op=OP_ShadeModel;
+  p[1].i=mode;
+
+  gl_add_op(p);
+}
+
+void glCullFace(int mode)
+{
+  GLParam p[2];
+
+  assert(mode == GL_BACK || 
+         mode == GL_FRONT || 
+         mode == GL_FRONT_AND_BACK);
+
+  p[0].op=OP_CullFace;
+  p[1].i=mode;
+
+  gl_add_op(p);
+}
+
+void glFrontFace(int mode)
+{
+  GLParam p[2];
+
+  assert(mode == GL_CCW || mode == GL_CW);
+
+  mode = (mode != GL_CCW);
+
+  p[0].op=OP_FrontFace;
+  p[1].i=mode;
+
+  gl_add_op(p);
+}
+
+void glPolygonMode(int face,int mode)
+{
+  GLParam p[3];
+
+  assert(face == GL_BACK || 
+         face == GL_FRONT || 
+         face == GL_FRONT_AND_BACK);
+  assert(mode == GL_POINT || mode == GL_LINE || mode==GL_FILL);
+
+  p[0].op=OP_PolygonMode;
+  p[1].i=face;
+  p[2].i=mode;
+
+  gl_add_op(p);
+}
+
+
+/* glEnable / glDisable */
+
+void glEnable(int cap)
+{
+  GLParam p[3];
+
+  p[0].op=OP_EnableDisable;
+  p[1].i=cap;
+  p[2].i=1;
+
+  gl_add_op(p);
+}
+
+void glDisable(int cap)
+{
+  GLParam p[3];
+
+  p[0].op=OP_EnableDisable;
+  p[1].i=cap;
+  p[2].i=0;
+
+  gl_add_op(p);
+}
+
+/* glBegin / glEnd */
+
+void glBegin(int mode)
+{
+  GLParam p[2];
+
+  p[0].op=OP_Begin;
+  p[1].i=mode;
+
+  gl_add_op(p);
+}
+
+void glEnd(void)
+{
+  GLParam p[1];
+
+  p[0].op=OP_End;
+
+  gl_add_op(p);
+}
+
+/* matrix */
+
+void glMatrixMode(int mode)
+{
+  GLParam p[2];
+
+  p[0].op=OP_MatrixMode;
+  p[1].i=mode;
+
+  gl_add_op(p);
+}
+
+void glLoadMatrixf(const float *m)
+{
+  GLParam p[17];
+  int i;
+
+  p[0].op=OP_LoadMatrix;
+  for(i=0;i<16;i++) p[i+1].f=m[i];
+
+  gl_add_op(p);
+}
+
+void glLoadIdentity(void)
+{
+  GLParam p[1];
+
+  p[0].op=OP_LoadIdentity;
+
+  gl_add_op(p);
+}
+
+void glMultMatrixf(const float *m)
+{
+  GLParam p[17];
+  int i;
+
+  p[0].op=OP_MultMatrix;
+  for(i=0;i<16;i++) p[i+1].f=m[i];
+
+  gl_add_op(p);
+}
+
+void glPushMatrix(void)
+{
+  GLParam p[1];
+
+  p[0].op=OP_PushMatrix;
+
+  gl_add_op(p);
+}
+
+void glPopMatrix(void)
+{
+  GLParam p[1];
+
+  p[0].op=OP_PopMatrix;
+
+  gl_add_op(p);
+}
+
+void glRotatef(float angle,float x,float y,float z)
+{
+  GLParam p[5];
+
+  p[0].op=OP_Rotate;
+  p[1].f=angle;
+  p[2].f=x;
+  p[3].f=y;
+  p[4].f=z;
+
+  gl_add_op(p);
+}
+
+void glTranslatef(float x,float y,float z)
+{
+  GLParam p[4];
+
+  p[0].op=OP_Translate;
+  p[1].f=x;
+  p[2].f=y;
+  p[3].f=z;
+
+  gl_add_op(p);
+}
+
+void glScalef(float x,float y,float z)
+{
+  GLParam p[4];
+
+  p[0].op=OP_Scale;
+  p[1].f=x;
+  p[2].f=y;
+  p[3].f=z;
+
+  gl_add_op(p);
+}
+
+
+void glViewport(int x,int y,int width,int height)
+{
+  GLParam p[5];
+
+  p[0].op=OP_Viewport;
+  p[1].i=x;
+  p[2].i=y;
+  p[3].i=width;
+  p[4].i=height;
+
+  gl_add_op(p);
+}
+
+void glFrustum(double left,double right,double bottom,double top,
+               double near,double farv)
+{
+  GLParam p[7];
+
+  p[0].op=OP_Frustum;
+  p[1].f=left;
+  p[2].f=right;
+  p[3].f=bottom;
+  p[4].f=top;
+  p[5].f=near;
+  p[6].f=farv;
+
+  gl_add_op(p);
+}
+
+/* lightening */
+
+void glMaterialfv(int mode,int type,float *v)
+{
+  GLParam p[7];
+  int i,n;
+
+  assert(mode == GL_FRONT  || mode == GL_BACK || mode==GL_FRONT_AND_BACK);
+
+  p[0].op=OP_Material;
+  p[1].i=mode;
+  p[2].i=type;
+  n=4;
+  if (type == GL_SHININESS) n=1;
+  for(i=0;i<4;i++) p[3+i].f=v[i];
+  for(i=n;i<4;i++) p[3+i].f=0;
+
+  gl_add_op(p);
+}
+
+void glMaterialf(int mode,int type,float v)
+{
+  GLParam p[7];
+  int i;
+
+  p[0].op=OP_Material;
+  p[1].i=mode;
+  p[2].i=type;
+  p[3].f=v;
+  for(i=0;i<3;i++) p[4+i].f=0;
+
+  gl_add_op(p);
+}
+
+void glColorMaterial(int mode,int type)
+{
+  GLParam p[3];
+
+  p[0].op=OP_ColorMaterial;
+  p[1].i=mode;
+  p[2].i=type;
+
+  gl_add_op(p);
+}
+
+void glLightfv(int light,int type,float *v)
+{
+  GLParam p[7];
+  int i;
+
+  p[0].op=OP_Light;
+  p[1].i=light;
+  p[2].i=type;
+  /* TODO: 3 composants ? */
+  for(i=0;i<4;i++) p[3+i].f=v[i];
+
+  gl_add_op(p);
+}
+
+
+void glLightf(int light,int type,float v)
+{
+  GLParam p[7];
+  int i;
+
+  p[0].op=OP_Light;
+  p[1].i=light;
+  p[2].i=type;
+  p[3].f=v;
+  for(i=0;i<3;i++) p[4+i].f=0;
+
+  gl_add_op(p);
+}
+
+void glLightModeli(int pname,int param)
+{
+  GLParam p[6];
+
+  p[0].op=OP_LightModel;
+  p[1].i=pname;
+  p[2].f=(float)param;
+//  for(i=0;i<4;i++) p[3+i].f=0;
+//  for(i=0;i<3;i++) p[3+i].f=0;
+  p[3].f=0;
+  p[4].f=0;
+  p[5].f=0;
+  gl_add_op(p);
+}
+
+void glLightModelfv(int pname,float *param)
+{
+  GLParam p[6];
+  int i;
+
+  p[0].op=OP_LightModel;
+  p[1].i=pname;
+  for(i=0;i<4;i++) p[2+i].f=param[i];
+
+  gl_add_op(p);
+}
+
+/* clear */
+
+void glClear(int mask)
+{
+  GLParam p[2];
+
+  p[0].op=OP_Clear;
+  p[1].i=mask;
+
+  gl_add_op(p);
+}
+
+void glClearColor(float r,float g,float b,float a)
+{
+  GLParam p[5];
+
+  p[0].op=OP_ClearColor;
+  p[1].f=r;
+  p[2].f=g;
+  p[3].f=b;
+  p[4].f=a;
+
+  gl_add_op(p);
+}
+
+void glClearDepth(double depth)
+{
+  GLParam p[2];
+
+  p[0].op=OP_ClearDepth;
+  p[1].f=depth;
+
+  gl_add_op(p);
+}
+
+
+/* textures */
+
+void glTexImage2D( int target, int level, int components,
+                   int width, int height, int border,
+                   int format, int type, void *pixels)
+{
+  GLParam p[10];
+
+  p[0].op=OP_TexImage2D;
+  p[1].i=target;
+  p[2].i=level;
+  p[3].i=components;
+  p[4].i=width;
+  p[5].i=height;
+  p[6].i=border;
+  p[7].i=format;
+  p[8].i=type;
+  p[9].p=pixels;
+
+  gl_add_op(p);
+}
+
+
+void glBindTexture(int target,int texture)
+{
+  GLParam p[3];
+
+  p[0].op=OP_BindTexture;
+  p[1].i=target;
+  p[2].i=texture;
+
+  gl_add_op(p);
+}
+
+void glTexEnvi(int target,int pname,int param)
+{
+  GLParam p[8];
+  
+  p[0].op=OP_TexEnv;
+  p[1].i=target;
+  p[2].i=pname;
+  p[3].i=param;
+  p[4].f=0;
+  p[5].f=0;
+  p[6].f=0;
+  p[7].f=0;
+
+  gl_add_op(p);
+}
+
+void glTexParameteri(int target,int pname,int param)
+{
+  GLParam p[8];
+  
+  p[0].op=OP_TexParameter;
+  p[1].i=target;
+  p[2].i=pname;
+  p[3].i=param;
+  p[4].f=0;
+  p[5].f=0;
+  p[6].f=0;
+  p[7].f=0;
+
+  gl_add_op(p);
+}
+
+void glPixelStorei(int pname,int param)
+{
+  GLParam p[3];
+
+  p[0].op=OP_PixelStore;
+  p[1].i=pname;
+  p[2].i=param;
+
+  gl_add_op(p);
+}
+
+/* selection */
+
+void glInitNames(void)
+{
+  GLParam p[1];
+
+  p[0].op=OP_InitNames;
+
+  gl_add_op(p);
+}
+
+void glPushName(unsigned int name)
+{
+  GLParam p[2];
+
+  p[0].op=OP_PushName;
+  p[1].i=name;
+
+  gl_add_op(p);
+}
+
+void glPopName(void)
+{
+  GLParam p[1];
+
+  p[0].op=OP_PopName;
+
+  gl_add_op(p);
+}
+
+void glLoadName(unsigned int name)
+{
+  GLParam p[2];
+
+  p[0].op=OP_LoadName;
+  p[1].i=name;
+
+  gl_add_op(p);
+}
+
+void 
+glPolygonOffset(GLfloat factor, GLfloat units)
+{
+  GLParam p[3];
+  p[0].op = OP_PolygonOffset;
+  p[1].f = factor;
+  p[2].f = units;
+}
+
+/* Special Functions */
+
+void glCallList(unsigned int list)
+{
+  GLParam p[2];
+
+  p[0].op=OP_CallList;
+  p[1].i=list;
+
+  gl_add_op(p);
+}
+
+void glFlush(void)
+{
+  /* nothing to do */
+}
+
+void glHint(int target,int mode)
+{
+  GLParam p[3];
+
+  p[0].op=OP_Hint;
+  p[1].i=target;
+  p[2].i=mode;
+
+  gl_add_op(p);
+}
+
+/* Non standard functions */
+
+void glDebug(int mode)
+{
+  GLContext *c=gl_get_context();
+  c->print_flag=mode;
+}
+
--- /dev/null
+++ b/src/arrays.c
@@ -1,0 +1,206 @@
+#include "zgl.h"
+#include <assert.h>
+#include <stdio.h>
+
+#define VERTEX_ARRAY   0x0001
+#define COLOR_ARRAY    0x0002
+#define NORMAL_ARRAY   0x0004
+#define TEXCOORD_ARRAY 0x0008
+
+void
+glopArrayElement(GLContext *c, GLParam *param)
+{
+  int i;
+  int states = c->client_states;
+  int idx = param[1].i;
+    
+  if (states & COLOR_ARRAY) {
+    GLParam p[5];
+    int size = c->color_array_size; 
+    i = idx * (size + c->color_array_stride);
+    p[1].f = c->color_array[i];
+    p[2].f = c->color_array[i+1];
+    p[3].f = c->color_array[i+2];
+    p[4].f = size > 3 ? c->color_array[i+3] : 1.0f;
+    glopColor(c, p);  
+  }
+  if (states & NORMAL_ARRAY) {
+    i = idx * (3 + c->normal_array_stride);
+    c->current_normal.X = c->normal_array[i];
+    c->current_normal.Y = c->normal_array[i+1];
+    c->current_normal.Z = c->normal_array[i+2];
+    c->current_normal.Z = 0.0f;
+  }
+  if (states & TEXCOORD_ARRAY) {
+    int size = c->texcoord_array_size;
+    i = idx * (size + c->texcoord_array_stride);
+    c->current_tex_coord.X = c->texcoord_array[i];
+    c->current_tex_coord.Y = c->texcoord_array[i+1];
+    c->current_tex_coord.Z = size > 2 ? c->texcoord_array[i+2] : 0.0f;
+    c->current_tex_coord.W = size > 3 ? c->texcoord_array[i+3] : 1.0f;
+  }
+  if (states & VERTEX_ARRAY) {
+    GLParam p[5];
+    int size = c->vertex_array_size;
+    i = idx * (size + c->vertex_array_stride);
+    p[1].f = c->vertex_array[i];
+    p[2].f = c->vertex_array[i+1];
+    p[3].f = size > 2 ? c->vertex_array[i+2] : 0.0f;
+    p[4].f = size > 3 ? c->vertex_array[i+3] : 1.0f;
+    glopVertex(c, p);
+  }
+}
+
+void
+glArrayElement(GLint i)
+{
+  GLParam p[2];
+  p[0].op = OP_ArrayElement;
+  p[1].i = i;
+  gl_add_op(p);
+}
+
+
+void
+glopEnableClientState(GLContext *c, GLParam *p)
+{
+  c->client_states |= p[1].i;
+}
+
+void 
+glEnableClientState(GLenum array)
+{
+  GLParam p[2];
+  p[0].op = OP_EnableClientState;
+  
+  switch(array) {
+  case GL_VERTEX_ARRAY:
+    p[1].i = VERTEX_ARRAY;
+    break;  
+  case GL_NORMAL_ARRAY:
+    p[1].i = NORMAL_ARRAY;
+    break;
+  case GL_COLOR_ARRAY:
+    p[1].i = COLOR_ARRAY;
+    break;
+  case GL_TEXTURE_COORD_ARRAY:
+    p[1].i = TEXCOORD_ARRAY;
+    break;
+  default:
+    assert(0);
+    break;
+  }
+  gl_add_op(p);
+}
+
+void
+glopDisableClientState(GLContext *c, GLParam *p)
+{
+  c->client_states &= p[1].i;
+}
+
+void
+glDisableClientState(GLenum array)
+{
+  GLParam p[2];
+  p[0].op = OP_DisableClientState;
+    
+  switch(array) {
+  case GL_VERTEX_ARRAY:
+    p[1].i = ~VERTEX_ARRAY;
+    break;  
+  case GL_NORMAL_ARRAY:
+    p[1].i = ~NORMAL_ARRAY;
+    break;
+  case GL_COLOR_ARRAY:
+    p[1].i = ~COLOR_ARRAY;
+    break;
+  case GL_TEXTURE_COORD_ARRAY:
+    p[1].i = ~TEXCOORD_ARRAY;
+    break;
+  default:
+    assert(0);
+    break;
+  }
+  gl_add_op(p);
+}
+
+void
+glopVertexPointer(GLContext *c, GLParam *p)
+{
+  c->vertex_array_size = p[1].i;
+  c->vertex_array_stride = p[2].i;
+  c->vertex_array = p[3].p;
+}
+
+void 
+glVertexPointer(GLint size, GLenum type, GLsizei stride, 
+                const GLvoid *pointer)
+{
+  GLParam p[4];
+  assert(type == GL_FLOAT);
+  p[0].op = OP_VertexPointer;
+  p[1].i = size;
+  p[2].i = stride;
+  p[3].p = (void*)pointer;
+  gl_add_op(p);
+}
+
+void
+glopColorPointer(GLContext *c, GLParam *p)
+{
+  c->color_array_size = p[1].i;
+  c->color_array_stride = p[2].i;
+  c->color_array = p[3].p;  
+}
+
+void 
+glColorPointer(GLint size, GLenum type, GLsizei stride, 
+               const GLvoid *pointer)
+{
+  GLParam p[4];
+  assert(type == GL_FLOAT);
+  p[0].op = OP_ColorPointer;
+  p[1].i = size;
+  p[2].i = stride;
+  p[3].p = (void*)pointer;
+  gl_add_op(p);
+}
+
+void
+glopNormalPointer(GLContext *c, GLParam *p)
+{
+  c->normal_array_stride = p[1].i;
+  c->normal_array = p[2].p;  
+}
+
+void 
+glNormalPointer(GLenum type, GLsizei stride, 
+                const GLvoid *pointer)
+{
+  GLParam p[3];
+  assert(type == GL_FLOAT);
+  p[0].op = OP_NormalPointer;
+  p[1].i = stride;
+  p[2].p = (void*)pointer;
+}
+
+void
+glopTexCoordPointer(GLContext *c, GLParam *p)
+{
+  c->texcoord_array_size = p[1].i;
+  c->texcoord_array_stride = p[2].i;
+  c->texcoord_array = p[3].p;
+}
+
+void 
+glTexCoordPointer(GLint size, GLenum type, GLsizei stride, 
+                  const GLvoid *pointer)
+{
+  GLParam p[4];
+  assert(type == GL_FLOAT);
+  p[0].op = OP_TexCoordPointer;
+  p[1].i = size;
+  p[2].i = stride;
+  p[3].p = (void*)pointer;
+}
--- /dev/null
+++ b/src/clear.c
@@ -1,0 +1,30 @@
+#include "zgl.h"
+
+
+void glopClearColor(GLContext *c,GLParam *p)
+{
+  c->clear_color.v[0]=p[1].f;
+  c->clear_color.v[1]=p[2].f;
+  c->clear_color.v[2]=p[3].f;
+  c->clear_color.v[3]=p[4].f;
+}
+void glopClearDepth(GLContext *c,GLParam *p)
+{
+  c->clear_depth=p[1].f;
+}
+
+
+void glopClear(GLContext *c,GLParam *p)
+{
+  int mask=p[1].i;
+  int z=0;
+  int r=(int)(c->clear_color.v[0]*65535);
+  int g=(int)(c->clear_color.v[1]*65535);
+  int b=(int)(c->clear_color.v[2]*65535);
+
+  /* TODO : correct value of Z */
+
+  ZB_clear(c->zb,mask & GL_DEPTH_BUFFER_BIT,z,
+	   mask & GL_COLOR_BUFFER_BIT,r,g,b);
+}
+
--- /dev/null
+++ b/src/clip.c
@@ -1,0 +1,466 @@
+#include "zgl.h"
+
+/* fill triangle profile */
+/* #define PROFILE */
+
+#define CLIP_XMIN   (1<<0)
+#define CLIP_XMAX   (1<<1)
+#define CLIP_YMIN   (1<<2)
+#define CLIP_YMAX   (1<<3)
+#define CLIP_ZMIN   (1<<4)
+#define CLIP_ZMAX   (1<<5)
+
+void gl_transform_to_viewport(GLContext *c,GLVertex *v)
+{
+  float winv;
+
+  /* coordinates */
+  winv=1.0/v->pc.W;
+  v->zp.x= (int) ( v->pc.X * winv * c->viewport.scale.X 
+                   + c->viewport.trans.X );
+  v->zp.y= (int) ( v->pc.Y * winv * c->viewport.scale.Y 
+                   + c->viewport.trans.Y );
+  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 */
+      /* OLD CODE
+      v->zp.r = c->longcurrent_color[0];
+      v->zp.g = c->longcurrent_color[1];
+      v->zp.b = c->longcurrent_color[2]; */
+      //NEW CODE
+      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 */
+
+  if (c->texture_2d_enabled) {
+    v->zp.s=(int)(v->tex_coord.X * (ZB_POINT_S_MAX - ZB_POINT_S_MIN) 
+                  + ZB_POINT_S_MIN);
+    v->zp.t=(int)(v->tex_coord.Y * (ZB_POINT_T_MAX - ZB_POINT_T_MIN) 
+                  + ZB_POINT_T_MIN);
+  }
+}
+
+
+static void gl_add_select1(GLContext *c,int z1,int z2,int z3)
+{
+  unsigned int min,max;
+  min=max=z1;
+  if (z2<min) min=z2;
+  if (z3<min) min=z3;
+  if (z2>max) max=z2;
+  if (z3>max) max=z3;
+
+  gl_add_select(c,0xffffffff-min,0xffffffff-max);
+}
+
+/* point */
+
+void gl_draw_point(GLContext *c,GLVertex *p0)
+{
+  if (p0->clip_code == 0) {
+    if (c->render_mode == GL_SELECT) {
+      gl_add_select(c,p0->zp.z,p0->zp.z);
+    } else {
+      ZB_plot(c->zb,&p0->zp);
+    }
+  }
+}
+
+/* line */
+
+static inline void interpolate(GLVertex *q,GLVertex *p0,GLVertex *p1,float t)
+{
+  q->pc.X=p0->pc.X+(p1->pc.X-p0->pc.X)*t;
+  q->pc.Y=p0->pc.Y+(p1->pc.Y-p0->pc.Y)*t;
+  q->pc.Z=p0->pc.Z+(p1->pc.Z-p0->pc.Z)*t;
+  q->pc.W=p0->pc.W+(p1->pc.W-p0->pc.W)*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;
+}
+
+/*
+ * Line Clipping 
+ */
+
+/* Line Clipping algorithm from 'Computer Graphics', Principles and
+   Practice */
+static inline int ClipLine1(float denom,float num,float *tmin,float *tmax)
+{
+  float t;
+	 
+  if (denom>0) {
+    t=num/denom;
+    if (t>*tmax) return 0;
+    if (t>*tmin) *tmin=t;
+  } else if (denom<0) {
+    t=num/denom;
+    if (t<*tmin) return 0;
+    if (t<*tmax) *tmax=t;
+  } else if (num>0) return 0;
+  return 1;
+}
+
+void gl_draw_line(GLContext *c,GLVertex *p1,GLVertex *p2)
+{
+  float dx,dy,dz,dw,x1,y1,z1,w1;
+  float tmin,tmax;
+  GLVertex q1,q2;
+  int cc1,cc2;
+  
+  cc1=p1->clip_code;
+  cc2=p2->clip_code;
+
+  if ( (cc1 | cc2) == 0) {
+    if (c->render_mode == GL_SELECT) {
+      gl_add_select1(c,p1->zp.z,p2->zp.z,p2->zp.z);
+    } else {
+        if (c->depth_test)
+            ZB_line_z(c->zb,&p1->zp,&p2->zp);
+        else
+            ZB_line(c->zb,&p1->zp,&p2->zp);
+    }
+  } else if ( (cc1&cc2) != 0 ) {
+    return;
+  } else {
+    dx=p2->pc.X-p1->pc.X;
+    dy=p2->pc.Y-p1->pc.Y;
+    dz=p2->pc.Z-p1->pc.Z;
+    dw=p2->pc.W-p1->pc.W;
+    x1=p1->pc.X;
+    y1=p1->pc.Y;
+    z1=p1->pc.Z;
+    w1=p1->pc.W;
+    
+    tmin=0;
+    tmax=1;
+    if (ClipLine1(dx+dw,-x1-w1,&tmin,&tmax) &&
+        ClipLine1(-dx+dw,x1-w1,&tmin,&tmax) &&
+        ClipLine1(dy+dw,-y1-w1,&tmin,&tmax) &&
+        ClipLine1(-dy+dw,y1-w1,&tmin,&tmax) &&
+        ClipLine1(dz+dw,-z1-w1,&tmin,&tmax) && 
+        ClipLine1(-dz+dw,z1-w1,&tmin,&tmax)) {
+
+      interpolate(&q1,p1,p2,tmin);
+      interpolate(&q2,p1,p2,tmax);
+      gl_transform_to_viewport(c,&q1);
+      gl_transform_to_viewport(c,&q2);
+
+      if (c->depth_test)
+          ZB_line_z(c->zb,&q1.zp,&q2.zp);
+      else
+          ZB_line(c->zb,&q1.zp,&q2.zp);
+    }
+  }
+}
+
+	 
+/* triangle */
+
+/*
+ * Clipping
+ */
+
+/* We clip the segment [a,b] against the 6 planes of the normal volume.
+ * We compute the point 'c' of intersection and the value of the parameter 't'
+ * of the intersection if x=a+t(b-a). 
+ */
+	 
+#define clip_func(name,sign,dir,dir1,dir2) \
+static float name(V4 *c,V4 *a,V4 *b) \
+{\
+  float t,dX,dY,dZ,dW,den;\
+  dX = (b->X - a->X);\
+  dY = (b->Y - a->Y);\
+  dZ = (b->Z - a->Z);\
+  dW = (b->W - a->W);\
+  den = -(sign d ## dir) + dW;\
+  if (den == 0) t=0;\
+  else t = ( sign a->dir - a->W) / den;\
+  c->dir1 = a->dir1 + t * d ## dir1;\
+  c->dir2 = a->dir2 + t * d ## dir2;\
+  c->W = a->W + t * dW;\
+  c->dir = sign c->W;\
+  return t;\
+}
+
+
+clip_func(clip_xmin,-,X,Y,Z)
+
+clip_func(clip_xmax,+,X,Y,Z)
+
+clip_func(clip_ymin,-,Y,X,Z)
+
+clip_func(clip_ymax,+,Y,X,Z)
+
+clip_func(clip_zmin,-,Z,X,Y)
+
+clip_func(clip_zmax,+,Z,X,Y)
+
+
+float (*clip_proc[6])(V4 *,V4 *,V4 *)=  {
+    clip_xmin,clip_xmax,
+    clip_ymin,clip_ymax,
+    clip_zmin,clip_zmax
+};
+
+static inline void updateTmp(GLContext *c,
+			     GLVertex *q,GLVertex *p0,GLVertex *p1,float t)
+{
+  if (c->current_shade_model == GL_SMOOTH) {
+    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->zp.r = p0->zp.r + (p1->zp.r - p0->zp.r)*t;
+    q->zp.g = p0->zp.g + (p1->zp.g - p0->zp.g)*t;
+    q->zp.b = p0->zp.b + (p1->zp.b - p0->zp.b)*t;
+    //q->color.v[3]=p0->color.v[3] + (p1->color.v[3] - p0->color.v[3])*t;
+    //printf("\np0 Components are %f, %f, %f", p0->color.v[0], p0->color.v[1], p0->color.v[2]);
+    //printf("\nZbuffer point r,g,b for p0 are: %d %d %d",p0->zp.r, p0->zp.g,p0->zp.b);
+	//printf("\n~\nNew Components are %f, %f, %f", q->color.v[0], q->color.v[1], q->color.v[2]);
+    //printf("\nZbuffer point r,g,b for new point are: %d %d %d",q->zp.r, q->zp.g,q->zp.b);
+ /// *
+  } 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->zp.r = p0->zp.r;
+    q->zp.g = p0->zp.g;
+    q->zp.b = p0->zp.b;
+  }
+	//	*/
+  if (c->texture_2d_enabled) {
+    q->tex_coord.X = p0->tex_coord.X + (p1->tex_coord.X-p0->tex_coord.X)*t;
+    q->tex_coord.Y = p0->tex_coord.Y + (p1->tex_coord.Y-p0->tex_coord.Y)*t;
+  }
+
+  q->clip_code=gl_clipcode(q->pc.X,q->pc.Y,q->pc.Z,q->pc.W);
+  if (q->clip_code==0)
+    gl_transform_to_viewport(c,q);
+}
+
+static void gl_draw_triangle_clip(GLContext *c,
+                                  GLVertex *p0,GLVertex *p1,GLVertex *p2,int clip_bit);
+
+void gl_draw_triangle(GLContext *c,
+                      GLVertex *p0,GLVertex *p1,GLVertex *p2)
+{
+  int co,c_and,cc[3],front;
+  float norm;
+  
+  cc[0]=p0->clip_code;
+  cc[1]=p1->clip_code;
+  cc[2]=p2->clip_code;
+  
+  co=cc[0] | cc[1] | cc[2];
+
+  /* we handle the non clipped case here to go faster */
+  if (co==0) {
+    
+      norm=(float)(p1->zp.x-p0->zp.x)*(float)(p2->zp.y-p0->zp.y)-
+        (float)(p2->zp.x-p0->zp.x)*(float)(p1->zp.y-p0->zp.y);
+      
+      if (norm == 0) return;
+
+      front = norm < 0.0;
+      front = front ^ c->current_front_face;
+  
+      /* back face culling */
+      if (c->cull_face_enabled) {
+        /* most used case first */
+        if (c->current_cull_face == GL_BACK) {
+          if (front == 0) return;
+          c->draw_triangle_front(c,p0,p1,p2);
+        } else if (c->current_cull_face == GL_FRONT) {
+          if (front != 0) return;
+          c->draw_triangle_back(c,p0,p1,p2);
+        } else {
+          return;
+        }
+      } else {
+        /* no culling */
+        if (front) {
+          c->draw_triangle_front(c,p0,p1,p2);
+        } else {
+          c->draw_triangle_back(c,p0,p1,p2);
+        }
+      }
+  } else {
+    c_and=cc[0] & cc[1] & cc[2];
+    if (c_and==0) { //Don't draw a triangle with no points
+      gl_draw_triangle_clip(c,p0,p1,p2,0);
+    }
+  }
+}
+
+static void gl_draw_triangle_clip(GLContext *c,
+                                  GLVertex *p0,GLVertex *p1,GLVertex *p2,int clip_bit)
+{
+  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;
+  
+  co=cc[0] | cc[1] | cc[2];
+  if (co == 0) {
+    gl_draw_triangle(c,p0,p1,p2);
+  } else {
+    c_and=cc[0] & cc[1] & cc[2];
+    /* the triangle is completely outside */
+    if (c_and!=0) return;
+
+    /* find the next direction to clip */
+    while (clip_bit < 6 && (co & (1 << clip_bit)) == 0)  {
+      clip_bit++;
+    }
+
+    /* this test can be true only in case of rounding errors */
+    if (clip_bit == 6) {
+#if 0
+      printf("Error:\n");
+      printf("%f %f %f %f\n",p0->pc.X,p0->pc.Y,p0->pc.Z,p0->pc.W);
+      printf("%f %f %f %f\n",p1->pc.X,p1->pc.Y,p1->pc.Z,p1->pc.W);
+      printf("%f %f %f %f\n",p2->pc.X,p2->pc.Y,p2->pc.Z,p2->pc.W);
+#endif
+      return;
+    }
+  
+    clip_mask = 1 << clip_bit;
+    co1=(cc[0] ^ cc[1] ^ cc[2]) & clip_mask;
+    
+    if (co1)  { 
+      /* one point outside */
+
+      if (cc[0] & clip_mask) { q[0]=p0; q[1]=p1; q[2]=p2; }
+      else if (cc[1] & clip_mask) { q[0]=p1; q[1]=p2; q[2]=p0; }
+      else { q[0]=p2; q[1]=p0; q[2]=p1; }
+      
+      tt=clip_proc[clip_bit](&tmp1.pc,&q[0]->pc,&q[1]->pc);
+      updateTmp(c,&tmp1,q[0],q[1],tt);
+
+      tt=clip_proc[clip_bit](&tmp2.pc,&q[0]->pc,&q[2]->pc);
+      updateTmp(c,&tmp2,q[0],q[2],tt);
+
+      tmp1.edge_flag=q[0]->edge_flag;
+      edge_flag_tmp=q[2]->edge_flag;
+      q[2]->edge_flag=0;
+      gl_draw_triangle_clip(c,&tmp1,q[1],q[2],clip_bit+1);
+
+      tmp2.edge_flag=1;
+      tmp1.edge_flag=0;
+      q[2]->edge_flag=edge_flag_tmp;
+      gl_draw_triangle_clip(c,&tmp2,&tmp1,q[2],clip_bit+1);
+    } else {
+      /* two points outside */
+
+      if ((cc[0] & clip_mask)==0) { q[0]=p0; q[1]=p1; q[2]=p2; }
+      else if ((cc[1] & clip_mask)==0) { q[0]=p1; q[1]=p2; q[2]=p0; } 
+      else { q[0]=p2; q[1]=p0; q[2]=p1; }
+      
+      tt=clip_proc[clip_bit](&tmp1.pc,&q[0]->pc,&q[1]->pc);
+      updateTmp(c,&tmp1,q[0],q[1],tt);
+
+      tt=clip_proc[clip_bit](&tmp2.pc,&q[0]->pc,&q[2]->pc);
+      updateTmp(c,&tmp2,q[0],q[2],tt);
+      
+      tmp1.edge_flag=1;
+      tmp2.edge_flag=q[2]->edge_flag;
+      gl_draw_triangle_clip(c,q[0],&tmp1,&tmp2,clip_bit+1);
+    }
+  }
+}
+
+
+void gl_draw_triangle_select(GLContext *c,
+                             GLVertex *p0,GLVertex *p1,GLVertex *p2)
+{
+  gl_add_select1(c,p0->zp.z,p1->zp.z,p2->zp.z);
+}
+
+#ifdef PROFILE
+int count_triangles,count_triangles_textured,count_pixels;
+#endif
+
+void gl_draw_triangle_fill(GLContext *c,
+                           GLVertex *p0,GLVertex *p1,GLVertex *p2)
+{
+	//puts("\n <yes, it's draw_triangle_fill>");
+#ifdef PROFILE
+  {
+    int norm;
+    assert(p0->zp.x >= 0 && p0->zp.x < c->zb->xsize);
+    assert(p0->zp.y >= 0 && p0->zp.y < c->zb->ysize);
+    assert(p1->zp.x >= 0 && p1->zp.x < c->zb->xsize);
+    assert(p1->zp.y >= 0 && p1->zp.y < c->zb->ysize);
+    assert(p2->zp.x >= 0 && p2->zp.x < c->zb->xsize);
+    assert(p2->zp.y >= 0 && p2->zp.y < c->zb->ysize);
+    
+    norm=(p1->zp.x-p0->zp.x)*(p2->zp.y-p0->zp.y)-
+      (p2->zp.x-p0->zp.x)*(p1->zp.y-p0->zp.y);
+    count_pixels+=abs(norm)/2;
+    count_triangles++;
+  }
+#endif
+    
+  if (c->texture_2d_enabled) {
+#ifdef PROFILE
+    count_triangles_textured++;
+#endif
+    ZB_setTexture(c->zb,c->current_texture->images[0].pixmap);
+    ZB_fillTriangleMappingPerspective(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);
+  }
+}
+
+/* Render a clipped triangle in line mode */  
+
+void gl_draw_triangle_line(GLContext *c,
+                           GLVertex *p0,GLVertex *p1,GLVertex *p2)
+{
+    if (c->depth_test) {
+        if (p0->edge_flag) ZB_line_z(c->zb,&p0->zp,&p1->zp);
+        if (p1->edge_flag) ZB_line_z(c->zb,&p1->zp,&p2->zp);
+        if (p2->edge_flag) ZB_line_z(c->zb,&p2->zp,&p0->zp);
+    } else {
+        if (p0->edge_flag) ZB_line(c->zb,&p0->zp,&p1->zp);
+        if (p1->edge_flag) ZB_line(c->zb,&p1->zp,&p2->zp);
+        if (p2->edge_flag) ZB_line(c->zb,&p2->zp,&p0->zp);
+    }
+}
+
+
+
+/* Render a clipped triangle in point mode */
+void gl_draw_triangle_point(GLContext *c,
+                            GLVertex *p0,GLVertex *p1,GLVertex *p2)
+{
+  if (p0->edge_flag) ZB_plot(c->zb,&p0->zp);
+  if (p1->edge_flag) ZB_plot(c->zb,&p1->zp);
+  if (p2->edge_flag) ZB_plot(c->zb,&p2->zp);
+}
+
+
+
+
--- /dev/null
+++ b/src/config.mk
@@ -1,0 +1,83 @@
+#####################################################################
+# C compiler
+
+# linux
+CC= gcc
+CFLAGS= -Wall -O3 -g -std=c99
+LFLAGS=
+
+# for BeOS PPC
+#CC= mwcc
+#CFLAGS= -I. -i-
+#LFLAGS=
+
+#####################################################################
+# TinyGL configuration 
+
+#####################################################################
+# Select window API for TinyGL: 
+
+# standard X11 GLX like API 
+TINYGL_USE_GLX=n
+
+# BEOS API
+#TINYGL_USE_BEOS=y
+
+# Micro Windows NanoX API
+#TINYGL_USE_NANOX=y
+
+#####################################################################
+# X11 configuration (for the examples only)
+
+ifdef TINYGL_USE_GLX
+# Linux
+#UI_LIBS= -L/usr/X11R6/lib -lX11 -lXext
+UI_LIBS=
+UI_INCLUDES= 
+# Solaris
+#UI_LIBS= -L/usr/X11/lib -lX11 -lXext -lsocket -lnsl
+#UI_INCLUDES= 
+
+UI_OBJS=x11.o
+endif
+
+#####################################################################
+# Micro windowX11 configuration (for the examples only)
+
+ifdef TINYGL_USE_NANOX
+UI_LIBS= -lnano-X -lmwengine -lmwdrivers -lmwfonts
+UI_INCLUDES=
+
+# X11 target for nanoX
+UI_LIBS+= -L/usr/X11R6/lib -lX11 -lXext
+
+UI_OBJS=nanox.o
+endif
+
+#####################################################################
+# OpenGL configuration (for the examples only)
+
+# use TinyGL 
+GL_LIBS= -L../ -lTinyGL 
+GL_INCLUDES= -I../include
+GL_DEPS= ../libTinyGL.a
+
+# use Mesa
+#GL_LIBS= -lMesaGL 
+#GL_INCLUDES= 
+#GL_DEPS=
+
+# use OpenGL
+#GL_LIBS= -lGL 
+#GL_INCLUDES= 
+#GL_DEPS=
+
+####################################################################
+# Compile and link control
+
+# UNIX systems
+DIRS= src examples
+
+# BeOS
+# DIRS= src BeOS
+
--- /dev/null
+++ b/src/error.c
@@ -1,0 +1,16 @@
+#include <stdarg.h>
+#include "zgl.h"
+
+void gl_fatal_error(char *format, ...)
+{
+  va_list ap;
+
+  va_start(ap,format);
+
+  fprintf(stderr,"TinyGL: fatal error: ");
+  vfprintf(stderr,format,ap);
+  fprintf(stderr,"\n");
+  exit(1);
+
+  va_end(ap);
+}
--- /dev/null
+++ b/src/get.c
@@ -1,0 +1,72 @@
+#include "zgl.h"
+
+void glGetIntegerv(int pname,int *params)
+{
+  GLContext *c=gl_get_context();
+
+  switch(pname) {
+  case GL_VIEWPORT:
+    params[0]=c->viewport.xmin;
+    params[1]=c->viewport.ymin;
+    params[2]=c->viewport.xsize;
+    params[3]=c->viewport.ysize;
+    break;
+  case GL_MAX_MODELVIEW_STACK_DEPTH:
+    *params = MAX_MODELVIEW_STACK_DEPTH;
+    break;
+  case GL_MAX_PROJECTION_STACK_DEPTH:
+    *params = MAX_PROJECTION_STACK_DEPTH;
+    break;
+  case GL_MAX_LIGHTS:
+    *params = MAX_LIGHTS;
+    break;
+  case GL_MAX_TEXTURE_SIZE:
+    *params = 256; /* not completely true, but... */
+    break;
+  case GL_MAX_TEXTURE_STACK_DEPTH:
+    *params = MAX_TEXTURE_STACK_DEPTH;
+    break;
+  default:
+    gl_fatal_error("glGet: option not implemented");
+    break;
+  }
+}
+
+void glGetFloatv(int pname, float *v)
+{
+  int i;
+  int mnr = 0; /* just a trick to return the correct matrix */
+  GLContext *c = gl_get_context();
+  switch (pname) {
+  case GL_TEXTURE_MATRIX:
+    mnr++; 
+  case GL_PROJECTION_MATRIX:
+    mnr++; 
+  case GL_MODELVIEW_MATRIX:
+    {
+      float *p = &c->matrix_stack_ptr[mnr]->m[0][0];;
+      for (i = 0; i < 4; i++) {
+        *v++ = p[0];
+        *v++ = p[4];
+        *v++ = p[8];
+        *v++ = p[12];
+        p++;
+      }
+    } 
+    break;
+  case GL_LINE_WIDTH:
+    *v = 1.0f;
+    break;
+  case GL_LINE_WIDTH_RANGE:
+    v[0] = v[1] = 1.0f;
+    break;
+  case GL_POINT_SIZE:
+    *v = 1.0f;
+    break;
+  case GL_POINT_SIZE_RANGE:
+    v[0] = v[1] = 1.0f;
+  default:
+    fprintf(stderr,"warning: unknown pname in glGetFloatv()\n");
+    break;
+  }
+}
--- /dev/null
+++ b/src/image_util.c
@@ -1,0 +1,136 @@
+#include "zgl.h"
+
+/*
+ * image conversion
+ */
+
+void gl_convertRGB_to_5R6G5B(unsigned short *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]=((p[0]&0xF8)<<8) | ((p[1]&0xFC)<<3) | ((p[2]&0xF8)>>3); 
+    p+=3;
+  }
+}
+
+void gl_convertRGB_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[2])<<16) | 
+            (((unsigned int)p[1])<<8) | 
+            (((unsigned int)p[0])); 
+        p+=3;
+    }
+}
+
+/*
+ * linear interpolation with xf,yf normalized to 2^16
+ */
+
+#define INTERP_NORM_BITS  16
+#define INTERP_NORM       (1 << INTERP_NORM_BITS)
+
+static inline int interpolate(int v00,int v01,int v10,int xf,int yf)
+{
+  return v00+(((v01-v00)*xf + (v10-v00)*yf) >> INTERP_NORM_BITS);
+}
+
+
+/* 
+ * TODO: more accurate resampling 
+ */
+
+void gl_resizeImage(unsigned char *dest,int xsize_dest,int ysize_dest,
+                    unsigned char *src,int xsize_src,int ysize_src)
+{
+  unsigned char *pix,*pix_src;
+  float x1,y1,x1inc,y1inc;
+  int xi,yi,j,xf,yf,x,y;
+
+  pix=dest;
+  pix_src=src;
+  
+  x1inc=(float) (xsize_src - 1) / (float) (xsize_dest - 1);
+  y1inc=(float) (ysize_src - 1) / (float) (ysize_dest - 1);
+
+  y1=0;
+  for(y=0;y<ysize_dest;y++) {
+    x1=0;
+    for(x=0;x<xsize_dest;x++) {
+      xi=(int) x1;
+      yi=(int) y1;
+      xf=(int) ((x1 - floor(x1)) * INTERP_NORM);
+      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],
+			     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],
+			     xf,yf);
+	}
+      }
+      
+      pix+=3;
+      x1+=x1inc;
+    }
+    y1+=y1inc;
+  }
+}
+
+#define FRAC_BITS 16
+
+/* resizing with no interlating nor nearest pixel */
+
+void gl_resizeImageNoInterpolate(unsigned char *dest,int xsize_dest,int ysize_dest,
+                                 unsigned char *src,int xsize_src,int ysize_src)
+{
+  unsigned char *pix,*pix_src,*pix1;
+  int x1,y1,x1inc,y1inc;
+  int xi,yi,x,y;
+
+  pix=dest;
+  pix_src=src;
+  
+  x1inc=(int)((float) ((xsize_src)<<FRAC_BITS) / (float) (xsize_dest));
+  y1inc=(int)((float) ((ysize_src)<<FRAC_BITS) / (float) (ysize_dest));
+
+  y1=0;
+  for(y=0;y<ysize_dest;y++) {
+    x1=0;
+    for(x=0;x<xsize_dest;x++) {
+      xi=x1 >> FRAC_BITS;
+      yi=y1 >> FRAC_BITS;
+      pix1=pix_src+(yi*xsize_src+xi)*3;
+
+      pix[0]=pix1[0];
+      pix[1]=pix1[1];
+      pix[2]=pix1[2];
+
+      pix+=3;
+      x1+=x1inc;
+    }
+    y1+=y1inc;
+  }
+}
+
--- /dev/null
+++ b/src/include/GL/gl.h
@@ -1,0 +1,843 @@
+/*
+ * The following constants come from Mesa
+ */
+#ifndef GL_H
+#define GL_H
+
+#define GL_VERSION_1_1 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum {
+	/* Boolean values */
+	GL_FALSE			= 0,
+	GL_TRUE				= 1,
+
+	/* Data types */
+	GL_BYTE				= 0x1400,
+	GL_UNSIGNED_BYTE		= 0x1401,
+	GL_SHORT			= 0x1402,
+	GL_UNSIGNED_SHORT		= 0x1403,
+	GL_INT				= 0x1404,
+	GL_UNSIGNED_INT			= 0x1405,
+	GL_FLOAT			= 0x1406,
+	GL_DOUBLE			= 0x140A,
+	GL_2_BYTES			= 0x1407,
+	GL_3_BYTES			= 0x1408,
+	GL_4_BYTES			= 0x1409,
+
+	/* Primitives */
+	GL_LINES			= 0x0001,
+	GL_POINTS			= 0x0000,
+	GL_LINE_STRIP			= 0x0003,
+	GL_LINE_LOOP			= 0x0002,
+	GL_TRIANGLES			= 0x0004,
+	GL_TRIANGLE_STRIP		= 0x0005,
+	GL_TRIANGLE_FAN			= 0x0006,
+	GL_QUADS			= 0x0007,
+	GL_QUAD_STRIP			= 0x0008,
+	GL_POLYGON			= 0x0009,
+	GL_EDGE_FLAG			= 0x0B43,
+
+	/* Vertex Arrays */
+	GL_VERTEX_ARRAY			= 0x8074,
+	GL_NORMAL_ARRAY			= 0x8075,
+	GL_COLOR_ARRAY			= 0x8076,
+	GL_INDEX_ARRAY			= 0x8077,
+	GL_TEXTURE_COORD_ARRAY		= 0x8078,
+	GL_EDGE_FLAG_ARRAY		= 0x8079,
+	GL_VERTEX_ARRAY_SIZE		= 0x807A,
+	GL_VERTEX_ARRAY_TYPE		= 0x807B,
+	GL_VERTEX_ARRAY_STRIDE		= 0x807C,
+	GL_VERTEX_ARRAY_COUNT		= 0x807D,
+	GL_NORMAL_ARRAY_TYPE		= 0x807E,
+	GL_NORMAL_ARRAY_STRIDE		= 0x807F,
+	GL_NORMAL_ARRAY_COUNT		= 0x8080,
+	GL_COLOR_ARRAY_SIZE		= 0x8081,
+	GL_COLOR_ARRAY_TYPE		= 0x8082,
+	GL_COLOR_ARRAY_STRIDE		= 0x8083,
+	GL_COLOR_ARRAY_COUNT		= 0x8084,
+	GL_INDEX_ARRAY_TYPE		= 0x8085,
+	GL_INDEX_ARRAY_STRIDE		= 0x8086,
+	GL_INDEX_ARRAY_COUNT		= 0x8087,
+	GL_TEXTURE_COORD_ARRAY_SIZE	= 0x8088,
+	GL_TEXTURE_COORD_ARRAY_TYPE	= 0x8089,
+	GL_TEXTURE_COORD_ARRAY_STRIDE	= 0x808A,
+	GL_TEXTURE_COORD_ARRAY_COUNT	= 0x808B,
+	GL_EDGE_FLAG_ARRAY_STRIDE	= 0x808C,
+	GL_EDGE_FLAG_ARRAY_COUNT	= 0x808D,
+	GL_VERTEX_ARRAY_POINTER		= 0x808E,
+	GL_NORMAL_ARRAY_POINTER		= 0x808F,
+	GL_COLOR_ARRAY_POINTER		= 0x8090,
+	GL_INDEX_ARRAY_POINTER		= 0x8091,
+	GL_TEXTURE_COORD_ARRAY_POINTER	= 0x8092,
+	GL_EDGE_FLAG_ARRAY_POINTER	= 0x8093,
+        GL_V2F				= 0x2A20,
+	GL_V3F				= 0x2A21,
+	GL_C4UB_V2F			= 0x2A22,
+	GL_C4UB_V3F			= 0x2A23,
+	GL_C3F_V3F			= 0x2A24,
+	GL_N3F_V3F			= 0x2A25,
+	GL_C4F_N3F_V3F			= 0x2A26,
+	GL_T2F_V3F			= 0x2A27,
+	GL_T4F_V4F			= 0x2A28,
+	GL_T2F_C4UB_V3F			= 0x2A29,
+	GL_T2F_C3F_V3F			= 0x2A2A,
+	GL_T2F_N3F_V3F			= 0x2A2B,
+	GL_T2F_C4F_N3F_V3F		= 0x2A2C,
+	GL_T4F_C4F_N3F_V4F		= 0x2A2D,
+
+	/* Matrix Mode */
+	GL_MATRIX_MODE			= 0x0BA0,
+	GL_MODELVIEW			= 0x1700,
+	GL_PROJECTION			= 0x1701,
+	GL_TEXTURE			= 0x1702,
+
+	/* Points */
+	GL_POINT_SMOOTH			= 0x0B10,
+	GL_POINT_SIZE			= 0x0B11,
+	GL_POINT_SIZE_GRANULARITY 	= 0x0B13,
+	GL_POINT_SIZE_RANGE		= 0x0B12,
+
+	/* Lines */
+	GL_LINE_SMOOTH			= 0x0B20,
+	GL_LINE_STIPPLE			= 0x0B24,
+	GL_LINE_STIPPLE_PATTERN		= 0x0B25,
+	GL_LINE_STIPPLE_REPEAT		= 0x0B26,
+	GL_LINE_WIDTH			= 0x0B21,
+	GL_LINE_WIDTH_GRANULARITY	= 0x0B23,
+	GL_LINE_WIDTH_RANGE		= 0x0B22,
+
+	/* Polygons */
+	GL_POINT			= 0x1B00,
+	GL_LINE				= 0x1B01,
+	GL_FILL				= 0x1B02,
+	GL_CCW				= 0x0901,
+	GL_CW				= 0x0900,
+	GL_FRONT			= 0x0404,
+	GL_BACK				= 0x0405,
+	GL_CULL_FACE			= 0x0B44,
+	GL_CULL_FACE_MODE		= 0x0B45,
+	GL_POLYGON_SMOOTH		= 0x0B41,
+	GL_POLYGON_STIPPLE		= 0x0B42,
+	GL_FRONT_FACE			= 0x0B46,
+	GL_POLYGON_MODE			= 0x0B40,
+	GL_POLYGON_OFFSET_FACTOR	= 0x3038,
+	GL_POLYGON_OFFSET_UNITS		= 0x2A00,
+	GL_POLYGON_OFFSET_POINT		= 0x2A01,
+	GL_POLYGON_OFFSET_LINE		= 0x2A02,
+	GL_POLYGON_OFFSET_FILL		= 0x8037,
+
+	/* Display Lists */
+	GL_COMPILE			= 0x1300,
+	GL_COMPILE_AND_EXECUTE		= 0x1301,
+	GL_LIST_BASE			= 0x0B32,
+	GL_LIST_INDEX			= 0x0B33,
+	GL_LIST_MODE			= 0x0B30,
+
+	/* Depth buffer */
+	GL_NEVER			= 0x0200,
+	GL_LESS				= 0x0201,
+	GL_GEQUAL			= 0x0206,
+	GL_LEQUAL			= 0x0203,
+	GL_GREATER			= 0x0204,
+	GL_NOTEQUAL			= 0x0205,
+	GL_EQUAL			= 0x0202,
+	GL_ALWAYS			= 0x0207,
+	GL_DEPTH_TEST			= 0x0B71,
+	GL_DEPTH_BITS			= 0x0D56,
+	GL_DEPTH_CLEAR_VALUE		= 0x0B73,
+	GL_DEPTH_FUNC			= 0x0B74,
+	GL_DEPTH_RANGE			= 0x0B70,
+	GL_DEPTH_WRITEMASK		= 0x0B72,
+	GL_DEPTH_COMPONENT		= 0x1902,
+
+	/* Lighting */
+	GL_LIGHTING			= 0x0B50,
+	GL_LIGHT0			= 0x4000,
+	GL_LIGHT1			= 0x4001,
+	GL_LIGHT2			= 0x4002,
+	GL_LIGHT3			= 0x4003,
+	GL_LIGHT4			= 0x4004,
+	GL_LIGHT5			= 0x4005,
+	GL_LIGHT6			= 0x4006,
+	GL_LIGHT7			= 0x4007,
+	GL_SPOT_EXPONENT		= 0x1205,
+	GL_SPOT_CUTOFF			= 0x1206,
+	GL_CONSTANT_ATTENUATION		= 0x1207,
+	GL_LINEAR_ATTENUATION		= 0x1208,
+	GL_QUADRATIC_ATTENUATION	= 0x1209,
+	GL_AMBIENT			= 0x1200,
+	GL_DIFFUSE			= 0x1201,
+	GL_SPECULAR			= 0x1202,
+	GL_SHININESS			= 0x1601,
+	GL_EMISSION			= 0x1600,
+	GL_POSITION			= 0x1203,
+	GL_SPOT_DIRECTION		= 0x1204,
+	GL_AMBIENT_AND_DIFFUSE		= 0x1602,
+	GL_COLOR_INDEXES		= 0x1603,
+	GL_LIGHT_MODEL_TWO_SIDE		= 0x0B52,
+	GL_LIGHT_MODEL_LOCAL_VIEWER	= 0x0B51,
+	GL_LIGHT_MODEL_AMBIENT		= 0x0B53,
+	GL_FRONT_AND_BACK		= 0x0408,
+	GL_SHADE_MODEL			= 0x0B54,
+	GL_FLAT				= 0x1D00,
+	GL_SMOOTH			= 0x1D01,
+	GL_COLOR_MATERIAL		= 0x0B57,
+	GL_COLOR_MATERIAL_FACE		= 0x0B55,
+	GL_COLOR_MATERIAL_PARAMETER	= 0x0B56,
+	GL_NORMALIZE			= 0x0BA1,
+
+	/* User clipping planes */
+	GL_CLIP_PLANE0			= 0x3000,
+	GL_CLIP_PLANE1			= 0x3001,
+	GL_CLIP_PLANE2			= 0x3002,
+	GL_CLIP_PLANE3			= 0x3003,
+	GL_CLIP_PLANE4			= 0x3004,
+	GL_CLIP_PLANE5			= 0x3005,
+
+	/* Accumulation buffer */
+	GL_ACCUM_RED_BITS		= 0x0D58,
+	GL_ACCUM_GREEN_BITS		= 0x0D59,
+	GL_ACCUM_BLUE_BITS		= 0x0D5A,
+	GL_ACCUM_ALPHA_BITS		= 0x0D5B,
+	GL_ACCUM_CLEAR_VALUE		= 0x0B80,
+	GL_ACCUM			= 0x0100,
+	GL_ADD				= 0x0104,
+	GL_LOAD				= 0x0101,
+	GL_MULT				= 0x0103,
+	GL_RETURN			= 0x0102,
+
+	/* Alpha testing */
+	GL_ALPHA_TEST			= 0x0BC0,
+	GL_ALPHA_TEST_REF		= 0x0BC2,
+	GL_ALPHA_TEST_FUNC		= 0x0BC1,
+
+	/* Blending */
+	GL_BLEND			= 0x0BE2,
+	GL_BLEND_SRC			= 0x0BE1,
+	GL_BLEND_DST			= 0x0BE0,
+	GL_ZERO				= 0,
+	GL_ONE				= 1,
+	GL_SRC_COLOR			= 0x0300,
+	GL_ONE_MINUS_SRC_COLOR		= 0x0301,
+	GL_DST_COLOR			= 0x0306,
+	GL_ONE_MINUS_DST_COLOR		= 0x0307,
+	GL_SRC_ALPHA			= 0x0302,
+	GL_ONE_MINUS_SRC_ALPHA		= 0x0303,
+	GL_DST_ALPHA			= 0x0304,
+	GL_ONE_MINUS_DST_ALPHA		= 0x0305,
+	GL_SRC_ALPHA_SATURATE		= 0x0308,
+	GL_CONSTANT_COLOR		= 0x8001,
+	GL_ONE_MINUS_CONSTANT_COLOR	= 0x8002,
+	GL_CONSTANT_ALPHA		= 0x8003,
+	GL_ONE_MINUS_CONSTANT_ALPHA	= 0x8004,
+
+	/* Render Mode */
+	GL_FEEDBACK			= 0x1C01,
+	GL_RENDER			= 0x1C00,
+	GL_SELECT			= 0x1C02,
+
+	/* Feedback */
+	GL_2D				= 0x0600,
+	GL_3D				= 0x0601,
+	GL_3D_COLOR			= 0x0602,
+	GL_3D_COLOR_TEXTURE		= 0x0603,
+	GL_4D_COLOR_TEXTURE		= 0x0604,
+	GL_POINT_TOKEN			= 0x0701,
+	GL_LINE_TOKEN			= 0x0702,
+	GL_LINE_RESET_TOKEN		= 0x0707,
+	GL_POLYGON_TOKEN		= 0x0703,
+	GL_BITMAP_TOKEN			= 0x0704,
+	GL_DRAW_PIXEL_TOKEN		= 0x0705,
+	GL_COPY_PIXEL_TOKEN		= 0x0706,
+	GL_PASS_THROUGH_TOKEN		= 0x0700,
+
+	/* Fog */
+	GL_FOG				= 0x0B60,
+	GL_FOG_MODE			= 0x0B65,
+	GL_FOG_DENSITY			= 0x0B62,
+	GL_FOG_COLOR			= 0x0B66,
+	GL_FOG_INDEX			= 0x0B61,
+	GL_FOG_START			= 0x0B63,
+	GL_FOG_END			= 0x0B64,
+	GL_LINEAR			= 0x2601,
+	GL_EXP				= 0x0800,
+	GL_EXP2				= 0x0801,
+
+	/* Logic Ops */
+	GL_LOGIC_OP			= 0x0BF1,
+	GL_LOGIC_OP_MODE		= 0x0BF0,
+	GL_CLEAR			= 0x1500,
+	GL_SET				= 0x150F,
+	GL_COPY				= 0x1503,
+	GL_COPY_INVERTED		= 0x150C,
+	GL_NOOP				= 0x1505,
+	GL_INVERT			= 0x150A,
+	GL_AND				= 0x1501,
+	GL_NAND				= 0x150E,
+	GL_OR				= 0x1507,
+	GL_NOR				= 0x1508,
+	GL_XOR				= 0x1506,
+	GL_EQUIV			= 0x1509,
+	GL_AND_REVERSE			= 0x1502,
+	GL_AND_INVERTED			= 0x1504,
+	GL_OR_REVERSE			= 0x150B,
+	GL_OR_INVERTED			= 0x150D,
+
+	/* Stencil */
+	GL_STENCIL_TEST			= 0x0B90,
+	GL_STENCIL_WRITEMASK		= 0x0B98,
+	GL_STENCIL_BITS			= 0x0D57,
+	GL_STENCIL_FUNC			= 0x0B92,
+	GL_STENCIL_VALUE_MASK		= 0x0B93,
+	GL_STENCIL_REF			= 0x0B97,
+	GL_STENCIL_FAIL			= 0x0B94,
+	GL_STENCIL_PASS_DEPTH_PASS	= 0x0B96,
+	GL_STENCIL_PASS_DEPTH_FAIL	= 0x0B95,
+	GL_STENCIL_CLEAR_VALUE		= 0x0B91,
+	GL_STENCIL_INDEX		= 0x1901,
+	GL_KEEP				= 0x1E00,
+	GL_REPLACE			= 0x1E01,
+	GL_INCR				= 0x1E02,
+	GL_DECR				= 0x1E03,
+
+	/* Buffers, Pixel Drawing/Reading */
+	GL_NONE				= 0,
+	GL_LEFT				= 0x0406,
+	GL_RIGHT			= 0x0407,
+	/*GL_FRONT			= 0x0404, */
+	/*GL_BACK			= 0x0405, */
+	/*GL_FRONT_AND_BACK		= 0x0408, */
+	GL_FRONT_LEFT			= 0x0400,
+	GL_FRONT_RIGHT			= 0x0401,
+	GL_BACK_LEFT			= 0x0402,
+	GL_BACK_RIGHT			= 0x0403,
+	GL_AUX0				= 0x0409,
+	GL_AUX1				= 0x040A,
+	GL_AUX2				= 0x040B,
+	GL_AUX3				= 0x040C,
+	GL_COLOR_INDEX			= 0x1900,
+	GL_RED				= 0x1903,
+	GL_GREEN			= 0x1904,
+	GL_BLUE				= 0x1905,
+	GL_ALPHA			= 0x1906,
+	GL_LUMINANCE			= 0x1909,
+	GL_LUMINANCE_ALPHA		= 0x190A,
+	GL_ALPHA_BITS			= 0x0D55,
+	GL_RED_BITS			= 0x0D52,
+	GL_GREEN_BITS			= 0x0D53,
+	GL_BLUE_BITS			= 0x0D54,
+	GL_INDEX_BITS			= 0x0D51,
+	GL_SUBPIXEL_BITS		= 0x0D50,
+	GL_AUX_BUFFERS			= 0x0C00,
+	GL_READ_BUFFER			= 0x0C02,
+	GL_DRAW_BUFFER			= 0x0C01,
+	GL_DOUBLEBUFFER			= 0x0C32,
+	GL_STEREO			= 0x0C33,
+	GL_BITMAP			= 0x1A00,
+	GL_COLOR			= 0x1800,
+	GL_DEPTH			= 0x1801,
+	GL_STENCIL			= 0x1802,
+	GL_DITHER			= 0x0BD0,
+	GL_RGB				= 0x1907,
+	GL_RGBA				= 0x1908,
+
+	/* Implementation limits */
+	GL_MAX_LIST_NESTING		= 0x0B31,
+	GL_MAX_ATTRIB_STACK_DEPTH	= 0x0D35,
+	GL_MAX_MODELVIEW_STACK_DEPTH	= 0x0D36,
+	GL_MAX_NAME_STACK_DEPTH		= 0x0D37,
+	GL_MAX_PROJECTION_STACK_DEPTH	= 0x0D38,
+	GL_MAX_TEXTURE_STACK_DEPTH	= 0x0D39,
+	GL_MAX_EVAL_ORDER		= 0x0D30,
+	GL_MAX_LIGHTS			= 0x0D31,
+	GL_MAX_CLIP_PLANES		= 0x0D32,
+	GL_MAX_TEXTURE_SIZE		= 0x0D33,
+	GL_MAX_PIXEL_MAP_TABLE		= 0x0D34,
+	GL_MAX_VIEWPORT_DIMS		= 0x0D3A,
+	GL_MAX_CLIENT_ATTRIB_STACK_DEPTH= 0x0D3B,
+
+	/* Gets */
+	GL_ATTRIB_STACK_DEPTH		= 0x0BB0,
+	GL_COLOR_CLEAR_VALUE		= 0x0C22,
+	GL_COLOR_WRITEMASK		= 0x0C23,
+	GL_CURRENT_INDEX		= 0x0B01,
+	GL_CURRENT_COLOR		= 0x0B00,
+	GL_CURRENT_NORMAL		= 0x0B02,
+	GL_CURRENT_RASTER_COLOR		= 0x0B04,
+	GL_CURRENT_RASTER_DISTANCE	= 0x0B09,
+	GL_CURRENT_RASTER_INDEX		= 0x0B05,
+	GL_CURRENT_RASTER_POSITION	= 0x0B07,
+	GL_CURRENT_RASTER_TEXTURE_COORDS = 0x0B06,
+	GL_CURRENT_RASTER_POSITION_VALID = 0x0B08,
+	GL_CURRENT_TEXTURE_COORDS	= 0x0B03,
+	GL_INDEX_CLEAR_VALUE		= 0x0C20,
+	GL_INDEX_MODE			= 0x0C30,
+	GL_INDEX_WRITEMASK		= 0x0C21,
+	GL_MODELVIEW_MATRIX		= 0x0BA6,
+	GL_MODELVIEW_STACK_DEPTH	= 0x0BA3,
+	GL_NAME_STACK_DEPTH		= 0x0D70,
+	GL_PROJECTION_MATRIX		= 0x0BA7,
+	GL_PROJECTION_STACK_DEPTH	= 0x0BA4,
+	GL_RENDER_MODE			= 0x0C40,
+	GL_RGBA_MODE			= 0x0C31,
+	GL_TEXTURE_MATRIX		= 0x0BA8,
+	GL_TEXTURE_STACK_DEPTH		= 0x0BA5,
+	GL_VIEWPORT			= 0x0BA2,
+
+
+	/* Evaluators */
+	GL_AUTO_NORMAL			= 0x0D80,
+	GL_MAP1_COLOR_4			= 0x0D90,
+	GL_MAP1_GRID_DOMAIN		= 0x0DD0,
+	GL_MAP1_GRID_SEGMENTS		= 0x0DD1,
+	GL_MAP1_INDEX			= 0x0D91,
+	GL_MAP1_NORMAL			= 0x0D92,
+	GL_MAP1_TEXTURE_COORD_1		= 0x0D93,
+	GL_MAP1_TEXTURE_COORD_2		= 0x0D94,
+	GL_MAP1_TEXTURE_COORD_3		= 0x0D95,
+	GL_MAP1_TEXTURE_COORD_4		= 0x0D96,
+	GL_MAP1_VERTEX_3		= 0x0D97,
+	GL_MAP1_VERTEX_4		= 0x0D98,
+	GL_MAP2_COLOR_4			= 0x0DB0,
+	GL_MAP2_GRID_DOMAIN		= 0x0DD2,
+	GL_MAP2_GRID_SEGMENTS		= 0x0DD3,
+	GL_MAP2_INDEX			= 0x0DB1,
+	GL_MAP2_NORMAL			= 0x0DB2,
+	GL_MAP2_TEXTURE_COORD_1		= 0x0DB3,
+	GL_MAP2_TEXTURE_COORD_2		= 0x0DB4,
+	GL_MAP2_TEXTURE_COORD_3		= 0x0DB5,
+	GL_MAP2_TEXTURE_COORD_4		= 0x0DB6,
+	GL_MAP2_VERTEX_3		= 0x0DB7,
+	GL_MAP2_VERTEX_4		= 0x0DB8,
+	GL_COEFF			= 0x0A00,
+	GL_DOMAIN			= 0x0A02,
+	GL_ORDER			= 0x0A01,
+
+	/* Hints */
+	GL_FOG_HINT			= 0x0C54,
+	GL_LINE_SMOOTH_HINT		= 0x0C52,
+	GL_PERSPECTIVE_CORRECTION_HINT	= 0x0C50,
+	GL_POINT_SMOOTH_HINT		= 0x0C51,
+	GL_POLYGON_SMOOTH_HINT		= 0x0C53,
+	GL_DONT_CARE			= 0x1100,
+	GL_FASTEST			= 0x1101,
+	GL_NICEST			= 0x1102,
+
+	/* Scissor box */
+	GL_SCISSOR_TEST			= 0x0C11,
+	GL_SCISSOR_BOX			= 0x0C10,
+
+	/* Pixel Mode / Transfer */
+	GL_MAP_COLOR			= 0x0D10,
+	GL_MAP_STENCIL			= 0x0D11,
+	GL_INDEX_SHIFT			= 0x0D12,
+	GL_INDEX_OFFSET			= 0x0D13,
+	GL_RED_SCALE			= 0x0D14,
+	GL_RED_BIAS			= 0x0D15,
+	GL_GREEN_SCALE			= 0x0D18,
+	GL_GREEN_BIAS			= 0x0D19,
+	GL_BLUE_SCALE			= 0x0D1A,
+	GL_BLUE_BIAS			= 0x0D1B,
+	GL_ALPHA_SCALE			= 0x0D1C,
+	GL_ALPHA_BIAS			= 0x0D1D,
+	GL_DEPTH_SCALE			= 0x0D1E,
+	GL_DEPTH_BIAS			= 0x0D1F,
+	GL_PIXEL_MAP_S_TO_S_SIZE	= 0x0CB1,
+	GL_PIXEL_MAP_I_TO_I_SIZE	= 0x0CB0,
+	GL_PIXEL_MAP_I_TO_R_SIZE	= 0x0CB2,
+	GL_PIXEL_MAP_I_TO_G_SIZE	= 0x0CB3,
+	GL_PIXEL_MAP_I_TO_B_SIZE	= 0x0CB4,
+	GL_PIXEL_MAP_I_TO_A_SIZE	= 0x0CB5,
+	GL_PIXEL_MAP_R_TO_R_SIZE	= 0x0CB6,
+	GL_PIXEL_MAP_G_TO_G_SIZE	= 0x0CB7,
+	GL_PIXEL_MAP_B_TO_B_SIZE	= 0x0CB8,
+	GL_PIXEL_MAP_A_TO_A_SIZE	= 0x0CB9,
+	GL_PIXEL_MAP_S_TO_S		= 0x0C71,
+	GL_PIXEL_MAP_I_TO_I		= 0x0C70,
+	GL_PIXEL_MAP_I_TO_R		= 0x0C72,
+	GL_PIXEL_MAP_I_TO_G		= 0x0C73,
+	GL_PIXEL_MAP_I_TO_B		= 0x0C74,
+	GL_PIXEL_MAP_I_TO_A		= 0x0C75,
+	GL_PIXEL_MAP_R_TO_R		= 0x0C76,
+	GL_PIXEL_MAP_G_TO_G		= 0x0C77,
+	GL_PIXEL_MAP_B_TO_B		= 0x0C78,
+	GL_PIXEL_MAP_A_TO_A		= 0x0C79,
+	GL_PACK_ALIGNMENT		= 0x0D05,
+	GL_PACK_LSB_FIRST		= 0x0D01,
+	GL_PACK_ROW_LENGTH		= 0x0D02,
+	GL_PACK_SKIP_PIXELS		= 0x0D04,
+	GL_PACK_SKIP_ROWS		= 0x0D03,
+	GL_PACK_SWAP_BYTES		= 0x0D00,
+	GL_UNPACK_ALIGNMENT		= 0x0CF5,
+	GL_UNPACK_LSB_FIRST		= 0x0CF1,
+	GL_UNPACK_ROW_LENGTH		= 0x0CF2,
+	GL_UNPACK_SKIP_PIXELS		= 0x0CF4,
+	GL_UNPACK_SKIP_ROWS		= 0x0CF3,
+	GL_UNPACK_SWAP_BYTES		= 0x0CF0,
+	GL_ZOOM_X			= 0x0D16,
+	GL_ZOOM_Y			= 0x0D17,
+
+	/* Texture mapping */
+	GL_TEXTURE_ENV			= 0x2300,
+	GL_TEXTURE_ENV_MODE		= 0x2200,
+	GL_TEXTURE_1D			= 0x0DE0,
+	GL_TEXTURE_2D			= 0x0DE1,
+	GL_TEXTURE_WRAP_S		= 0x2802,
+	GL_TEXTURE_WRAP_T		= 0x2803,
+	GL_TEXTURE_MAG_FILTER		= 0x2800,
+	GL_TEXTURE_MIN_FILTER		= 0x2801,
+	GL_TEXTURE_ENV_COLOR		= 0x2201,
+	GL_TEXTURE_GEN_S		= 0x0C60,
+	GL_TEXTURE_GEN_T		= 0x0C61,
+	GL_TEXTURE_GEN_MODE		= 0x2500,
+	GL_TEXTURE_BORDER_COLOR		= 0x1004,
+	GL_TEXTURE_WIDTH		= 0x1000,
+	GL_TEXTURE_HEIGHT		= 0x1001,
+	GL_TEXTURE_BORDER		= 0x1005,
+	GL_TEXTURE_COMPONENTS		= 0x1003,
+	GL_NEAREST_MIPMAP_NEAREST	= 0x2700,
+	GL_NEAREST_MIPMAP_LINEAR	= 0x2702,
+	GL_LINEAR_MIPMAP_NEAREST	= 0x2701,
+	GL_LINEAR_MIPMAP_LINEAR		= 0x2703,
+	GL_OBJECT_LINEAR		= 0x2401,
+	GL_OBJECT_PLANE			= 0x2501,
+	GL_EYE_LINEAR			= 0x2400,
+	GL_EYE_PLANE			= 0x2502,
+	GL_SPHERE_MAP			= 0x2402,
+	GL_DECAL			= 0x2101,
+	GL_MODULATE			= 0x2100,
+	GL_NEAREST			= 0x2600,
+	GL_REPEAT			= 0x2901,
+	GL_CLAMP			= 0x2900,
+	GL_S				= 0x2000,
+	GL_T				= 0x2001,
+	GL_R				= 0x2002,
+	GL_Q				= 0x2003,
+	GL_TEXTURE_GEN_R		= 0x0C62,
+	GL_TEXTURE_GEN_Q		= 0x0C63,
+
+	GL_PROXY_TEXTURE_1D		= 0x8063,
+	GL_PROXY_TEXTURE_2D		= 0x8064,
+	GL_TEXTURE_PRIORITY		= 0x8066,
+	GL_TEXTURE_RESIDENT		= 0x8067,
+	GL_TEXTURE_1D_BINDING		= 0x8068,
+	GL_TEXTURE_2D_BINDING		= 0x8069,
+
+	/* Internal texture formats */
+	GL_ALPHA4			= 0x803B,
+	GL_ALPHA8			= 0x803C,
+	GL_ALPHA12			= 0x803D,
+	GL_ALPHA16			= 0x803E,
+	GL_LUMINANCE4			= 0x803F,
+	GL_LUMINANCE8			= 0x8040,
+	GL_LUMINANCE12			= 0x8041,
+	GL_LUMINANCE16			= 0x8042,
+	GL_LUMINANCE4_ALPHA4		= 0x8043,
+	GL_LUMINANCE6_ALPHA2		= 0x8044,
+	GL_LUMINANCE8_ALPHA8		= 0x8045,
+	GL_LUMINANCE12_ALPHA4		= 0x8046,
+	GL_LUMINANCE12_ALPHA12		= 0x8047,
+	GL_LUMINANCE16_ALPHA16		= 0x8048,
+	GL_INTENSITY			= 0x8049,
+	GL_INTENSITY4			= 0x804A,
+	GL_INTENSITY8			= 0x804B,
+	GL_INTENSITY12			= 0x804C,
+	GL_INTENSITY16			= 0x804D,
+	GL_R3_G3_B2			= 0x2A10,
+	GL_RGB4				= 0x804F,
+	GL_RGB5				= 0x8050,
+	GL_RGB8				= 0x8051,
+	GL_RGB10			= 0x8052,
+	GL_RGB12			= 0x8053,
+	GL_RGB16			= 0x8054,
+	GL_RGBA2			= 0x8055,
+	GL_RGBA4			= 0x8056,
+	GL_RGB5_A1			= 0x8057,
+	GL_RGBA8			= 0x8058,
+	GL_RGB10_A2			= 0x8059,
+	GL_RGBA12			= 0x805A,
+	GL_RGBA16			= 0x805B,
+
+	/* Utility */
+	GL_VENDOR			= 0x1F00,
+	GL_RENDERER			= 0x1F01,
+	GL_VERSION			= 0x1F02,
+	GL_EXTENSIONS			= 0x1F03,
+
+	/* Errors */
+	GL_INVALID_VALUE		= 0x0501,
+	GL_INVALID_ENUM			= 0x0500,
+	GL_INVALID_OPERATION		= 0x0502,
+	GL_STACK_OVERFLOW		= 0x0503,
+	GL_STACK_UNDERFLOW		= 0x0504,
+	GL_OUT_OF_MEMORY		= 0x0505,
+
+	/*
+	 * 1.0 Extensions
+	 */
+        /* GL_EXT_blend_minmax and GL_EXT_blend_color */
+	GL_CONSTANT_COLOR_EXT		= 0x8001,
+	GL_ONE_MINUS_CONSTANT_COLOR_EXT	= 0x8002,
+	GL_CONSTANT_ALPHA_EXT		= 0x8003,
+	GL_ONE_MINUS_CONSTANT_ALPHA_EXT	= 0x8004,
+	GL_BLEND_EQUATION_EXT		= 0x8009,
+	GL_MIN_EXT			= 0x8007,
+	GL_MAX_EXT			= 0x8008,
+	GL_FUNC_ADD_EXT			= 0x8006,
+	GL_FUNC_SUBTRACT_EXT		= 0x800A,
+	GL_FUNC_REVERSE_SUBTRACT_EXT	= 0x800B,
+	GL_BLEND_COLOR_EXT		= 0x8005,
+
+	/* GL_EXT_polygon_offset */
+        GL_POLYGON_OFFSET_EXT           = 0x8037,
+        GL_POLYGON_OFFSET_FACTOR_EXT    = 0x8038,
+        GL_POLYGON_OFFSET_BIAS_EXT      = 0x8039,
+
+	/* GL_EXT_vertex_array */
+	GL_VERTEX_ARRAY_EXT		= 0x8074,
+	GL_NORMAL_ARRAY_EXT		= 0x8075,
+	GL_COLOR_ARRAY_EXT		= 0x8076,
+	GL_INDEX_ARRAY_EXT		= 0x8077,
+	GL_TEXTURE_COORD_ARRAY_EXT	= 0x8078,
+	GL_EDGE_FLAG_ARRAY_EXT		= 0x8079,
+	GL_VERTEX_ARRAY_SIZE_EXT	= 0x807A,
+	GL_VERTEX_ARRAY_TYPE_EXT	= 0x807B,
+	GL_VERTEX_ARRAY_STRIDE_EXT	= 0x807C,
+	GL_VERTEX_ARRAY_COUNT_EXT	= 0x807D,
+	GL_NORMAL_ARRAY_TYPE_EXT	= 0x807E,
+	GL_NORMAL_ARRAY_STRIDE_EXT	= 0x807F,
+	GL_NORMAL_ARRAY_COUNT_EXT	= 0x8080,
+	GL_COLOR_ARRAY_SIZE_EXT		= 0x8081,
+	GL_COLOR_ARRAY_TYPE_EXT		= 0x8082,
+	GL_COLOR_ARRAY_STRIDE_EXT	= 0x8083,
+	GL_COLOR_ARRAY_COUNT_EXT	= 0x8084,
+	GL_INDEX_ARRAY_TYPE_EXT		= 0x8085,
+	GL_INDEX_ARRAY_STRIDE_EXT	= 0x8086,
+	GL_INDEX_ARRAY_COUNT_EXT	= 0x8087,
+	GL_TEXTURE_COORD_ARRAY_SIZE_EXT	= 0x8088,
+	GL_TEXTURE_COORD_ARRAY_TYPE_EXT	= 0x8089,
+	GL_TEXTURE_COORD_ARRAY_STRIDE_EXT= 0x808A,
+	GL_TEXTURE_COORD_ARRAY_COUNT_EXT= 0x808B,
+	GL_EDGE_FLAG_ARRAY_STRIDE_EXT	= 0x808C,
+	GL_EDGE_FLAG_ARRAY_COUNT_EXT	= 0x808D,
+	GL_VERTEX_ARRAY_POINTER_EXT	= 0x808E,
+	GL_NORMAL_ARRAY_POINTER_EXT	= 0x808F,
+	GL_COLOR_ARRAY_POINTER_EXT	= 0x8090,
+	GL_INDEX_ARRAY_POINTER_EXT	= 0x8091,
+	GL_TEXTURE_COORD_ARRAY_POINTER_EXT= 0x8092,
+	GL_EDGE_FLAG_ARRAY_POINTER_EXT	= 0x8093
+
+};
+
+enum {
+	GL_CURRENT_BIT		= 0x00000001,
+	GL_POINT_BIT		= 0x00000002,
+	GL_LINE_BIT		= 0x00000004,
+	GL_POLYGON_BIT		= 0x00000008,
+	GL_POLYGON_STIPPLE_BIT	= 0x00000010,
+	GL_PIXEL_MODE_BIT	= 0x00000020,
+	GL_LIGHTING_BIT		= 0x00000040,
+	GL_FOG_BIT		= 0x00000080,
+	GL_DEPTH_BUFFER_BIT	= 0x00000100,
+	GL_ACCUM_BUFFER_BIT	= 0x00000200,
+	GL_STENCIL_BUFFER_BIT	= 0x00000400,
+	GL_VIEWPORT_BIT		= 0x00000800,
+	GL_TRANSFORM_BIT	= 0x00001000,
+	GL_ENABLE_BIT		= 0x00002000,
+	GL_COLOR_BUFFER_BIT	= 0x00004000,
+	GL_HINT_BIT		= 0x00008000,
+	GL_EVAL_BIT		= 0x00010000,
+	GL_LIST_BIT		= 0x00020000,
+	GL_TEXTURE_BIT		= 0x00040000,
+	GL_SCISSOR_BIT		= 0x00080000,
+	GL_ALL_ATTRIB_BITS	= 0x000fffff
+};
+
+/* some types */
+
+typedef int		GLenum;
+typedef void		GLvoid;
+typedef unsigned char	GLboolean;
+typedef signed char	GLbyte;		/* 1-byte signed */
+typedef short		GLshort;	/* 2-byte signed */
+typedef int		GLint;		/* 4-byte signed */
+typedef unsigned char	GLubyte;	/* 1-byte unsigned */
+typedef unsigned short	GLushort;	/* 2-byte unsigned */
+typedef unsigned int	GLuint;		/* 4-byte unsigned */
+typedef float		GLfloat;	/* single precision float */
+typedef double		GLdouble;	/* double precision float */
+typedef int GLsizei;
+
+/* functions */
+
+void glEnable(int code);
+void glDisable(int code);
+
+void glShadeModel(int mode);
+void glCullFace(int mode);
+void glPolygonMode(int face,int mode);
+
+void glBegin(int type);
+void glEnd(void);
+
+//NEW functions added by GEK!!!
+void glSetEnableSpecular(int s); //Toggle specular rendering (Speedup!!!)
+void* glGetTexturePixmap(int text, int level, int* xsize, int* ysize); //Get the raw data of a texture!
+
+#define PROTO_GL1(name)				\
+void gl ## name ## 1f(float);	\
+void gl ## name ## 1d(double);	\
+void gl ## name ## 1fv(float *);		\
+void gl ## name ## 1dv(double *);
+
+#define PROTO_GL2(name)				\
+void gl ## name ## 2f(float ,float);	\
+void gl ## name ## 2d(double ,double);	\
+void gl ## name ## 2fv(float *);		\
+void gl ## name ## 2dv(double *);
+
+#define PROTO_GL3(name)				\
+void gl ## name ## 3f(float ,float ,float);	\
+void gl ## name ## 3d(double ,double ,double);	\
+void gl ## name ## 3fv(float *);		\
+void gl ## name ## 3dv(double *);
+
+#define PROTO_GL4(name)				\
+void gl ## name ## 4f(float ,float ,float, float );	\
+void gl ## name ## 4d(double ,double ,double, double );	\
+void gl ## name ## 4fv(float *);		\
+void gl ## name ## 4dv(double *);
+
+PROTO_GL2(Vertex)
+PROTO_GL3(Vertex)
+PROTO_GL4(Vertex)
+
+PROTO_GL3(Color)
+PROTO_GL4(Color)
+
+PROTO_GL3(Normal)
+
+PROTO_GL1(TexCoord)
+PROTO_GL2(TexCoord)
+PROTO_GL3(TexCoord)
+PROTO_GL4(TexCoord)
+
+void glEdgeFlag(int flag);
+
+/* matrix */
+void glMatrixMode(int mode);
+void glLoadMatrixf(const float *m);
+void glLoadIdentity(void);
+void glMultMatrixf(const float *m);
+void glPushMatrix(void);
+void glPopMatrix(void);
+void glRotatef(float angle,float x,float y,float z);
+void glTranslatef(float x,float y,float z);
+void glScalef(float x,float y,float z);
+
+void glViewport(int x,int y,int width,int height);
+void glFrustum(double left,double right,double bottom,double top,
+               double near,double far);
+
+/* lists */
+unsigned int glGenLists(int range);
+int glIsList(unsigned int list);
+void glNewList(unsigned int list,int mode);
+void glEndList(void);
+void glCallList(unsigned int list);
+
+/* clear */
+void glClear(int mask);
+void glClearColor(float r,float g,float b,float a);
+void glClearDepth(double depth);
+
+/* selection */
+int glRenderMode(int mode);
+void glSelectBuffer(int size,unsigned int *buf);
+
+void glInitNames(void);
+void glPushName(unsigned int name);
+void glPopName(void);
+void glLoadName(unsigned int name);
+
+/* textures */
+void glGenTextures(int n, unsigned int *textures);
+void glDeleteTextures(int n, const unsigned int *textures);
+void glBindTexture(int target,int texture);
+void glTexImage2D( int target, int level, int components,
+		    int width, int height, int border,
+                    int format, int type, void *pixels);
+void glTexEnvi(int target,int pname,int param);
+void glTexParameteri(int target,int pname,int param);
+void glPixelStorei(int pname,int param);
+
+/* lighting */
+
+void glMaterialfv(int mode,int type,float *v);
+void glMaterialf(int mode,int type,float v);
+void glColorMaterial(int mode,int type);
+
+void glLightfv(int light,int type,float *v);
+void glLightf(int light,int type,float v);
+void glLightModeli(int pname,int param);
+void glLightModelfv(int pname,float *param);
+
+/* misc */
+
+void glFlush(void);
+void glHint(int target,int mode);
+void glGetIntegerv(int pname,int *params);
+void glGetFloatv(int pname, float *v);
+void glFrontFace(int mode);
+
+/* opengl 1.2 arrays */
+void glEnableClientState(GLenum array);
+void glDisableClientState(GLenum array);
+void glArrayElement(GLint i);
+void glVertexPointer(GLint size, GLenum type, GLsizei stride, 
+                     const GLvoid *pointer);
+void glColorPointer(GLint size, GLenum type, GLsizei stride, 
+                     const GLvoid *pointer);
+void glNormalPointer(GLenum type, GLsizei stride, 
+                      const GLvoid *pointer);
+void glTexCoordPointer(GLint size, GLenum type, GLsizei stride, 
+                       const GLvoid *pointer);
+
+/* opengl 1.2 polygon offset */
+void glPolygonOffset(GLfloat factor, GLfloat units);
+
+/* not implemented, just added to compile  */
+  /*
+inline void glPointSize(float) {}
+inline void glLineWidth(float) {}
+inline void glDeleteLists(int, int) {}
+inline void glDepthFunc(int) {}
+inline void glBlendFunc(int, int) {}
+inline void glTexEnvf(int, int, int) {}
+inline void glOrtho(float,float,float,float,float,float){}
+inline void glVertex2i(int,int) {}
+inline void glDepthMask(int) {}
+inline void glFogi(int, int) {}
+inline void glFogfv(int, const float*) {}
+inline void glFogf(int, float) {}
+inline void glRasterPos2f(float, float) {}
+inline void glPolygonStipple(void*) {}
+inline void glTexParameterf(int, int, int) {};
+  */
+void glPolygonStipple(void* a); //TODO: implement
+/* non compatible functions */
+
+void glDebug(int mode);
+
+void glInit(void *zbuffer);
+void glClose(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+++ b/src/include/GL/glx.h
@@ -1,0 +1,144 @@
+#ifndef GLX_H
+#define GLX_H
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include "GL/gl.h"
+
+
+/* the following comes from Mesa */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define GLX_VERSION_1_1		1
+
+
+/*
+ * Tokens for glXChooseVisual and glXGetConfig:
+ */
+enum _GLX_CONFIGS {
+	GLX_USE_GL		= 1,
+	GLX_BUFFER_SIZE		= 2,
+	GLX_LEVEL		= 3,
+	GLX_RGBA		= 4,
+	GLX_DOUBLEBUFFER	= 5, 
+	GLX_STEREO		= 6,
+	GLX_AUX_BUFFERS		= 7,
+	GLX_RED_SIZE		= 8,
+	GLX_GREEN_SIZE		= 9,
+	GLX_BLUE_SIZE		= 10,
+	GLX_ALPHA_SIZE		= 11,
+	GLX_DEPTH_SIZE		= 12,
+	GLX_STENCIL_SIZE	= 13,
+	GLX_ACCUM_RED_SIZE	= 14,
+	GLX_ACCUM_GREEN_SIZE	= 15,
+	GLX_ACCUM_BLUE_SIZE	= 16,
+	GLX_ACCUM_ALPHA_SIZE	= 17,
+
+	/* GLX_EXT_visual_info extension */
+	GLX_X_VISUAL_TYPE_EXT		= 0x22,
+	GLX_TRANSPARENT_TYPE_EXT	= 0x23,
+	GLX_TRANSPARENT_INDEX_VALUE_EXT	= 0x24,
+	GLX_TRANSPARENT_RED_VALUE_EXT	= 0x25,
+	GLX_TRANSPARENT_GREEN_VALUE_EXT	= 0x26,
+	GLX_TRANSPARENT_BLUE_VALUE_EXT	= 0x27,
+	GLX_TRANSPARENT_ALPHA_VALUE_EXT	= 0x28
+};
+
+
+/*
+ * Error codes returned by glXGetConfig:
+ */
+#define GLX_BAD_SCREEN		1
+#define GLX_BAD_ATTRIBUTE	2
+#define GLX_NO_EXTENSION	3
+#define GLX_BAD_VISUAL		4
+#define GLX_BAD_CONTEXT		5
+#define GLX_BAD_VALUE       	6
+#define GLX_BAD_ENUM		7
+
+
+/*
+ * GLX 1.1 and later:
+ */
+#define GLX_VENDOR		1
+#define GLX_VERSION		2
+#define GLX_EXTENSIONS 		3
+
+
+/*
+ * GLX_visual_info extension
+ */
+#define GLX_TRUE_COLOR_EXT		0x8002
+#define GLX_DIRECT_COLOR_EXT		0x8003
+#define GLX_PSEUDO_COLOR_EXT		0x8004
+#define GLX_STATIC_COLOR_EXT		0x8005
+#define GLX_GRAY_SCALE_EXT		0x8006
+#define GLX_STATIC_GRAY_EXT		0x8007
+#define GLX_NONE_EXT			0x8000
+#define GLX_TRANSPARENT_RGB_EXT		0x8008
+#define GLX_TRANSPARENT_INDEX_EXT	0x8009
+
+
+typedef void *GLXContext;
+typedef Pixmap GLXPixmap;
+typedef Drawable GLXDrawable;
+typedef XID GLXContextID;
+
+
+extern XVisualInfo* glXChooseVisual( Display *dpy, int screen,
+				     int *attribList );
+
+extern GLXContext glXCreateContext( Display *dpy, XVisualInfo *vis,
+				    GLXContext shareList, Bool direct );
+
+extern void glXDestroyContext( Display *dpy, GLXContext ctx );
+
+extern Bool glXMakeCurrent( Display *dpy, GLXDrawable drawable,
+			    GLXContext ctx);
+
+extern void glXCopyContext( Display *dpy, GLXContext src, GLXContext dst,
+			    GLuint mask );
+
+extern void glXSwapBuffers( Display *dpy, GLXDrawable drawable );
+
+extern GLXPixmap glXCreateGLXPixmap( Display *dpy, XVisualInfo *visual,
+				     Pixmap pixmap );
+
+extern void glXDestroyGLXPixmap( Display *dpy, GLXPixmap pixmap );
+
+extern Bool glXQueryExtension( Display *dpy, int *errorb, int *event );
+
+extern Bool glXQueryVersion( Display *dpy, int *maj, int *min );
+
+extern Bool glXIsDirect( Display *dpy, GLXContext ctx );
+
+extern int glXGetConfig( Display *dpy, XVisualInfo *visual,
+			 int attrib, int *value );
+
+extern GLXContext glXGetCurrentContext( void );
+
+extern GLXDrawable glXGetCurrentDrawable( void );
+
+extern void glXWaitGL( void );
+
+extern void glXWaitX( void );
+
+extern void glXUseXFont( Font font, int first, int count, int list );
+
+
+/* GLX 1.1 and later */
+extern const char *glXQueryExtensionsString( Display *dpy, int screen );
+
+extern const char *glXQueryServerString( Display *dpy, int screen, int name );
+
+extern const char *glXGetClientString( Display *dpy, int name );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+++ b/src/include/GL/nglx.h
@@ -1,0 +1,27 @@
+#ifndef NGLX_H
+#define NGLX_H
+
+#include <microwin/nano-X.h>
+#include "GL/gl.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void *NGLXContext;
+typedef GR_DRAW_ID NGLXDrawable;
+
+extern NGLXContext nglXCreateContext( NGLXContext shareList, int flags );
+
+extern void nglXDestroyContext( NGLXContext ctx );
+
+extern int nglXMakeCurrent( NGLXDrawable drawable,
+			    NGLXContext ctx);
+
+extern void nglXSwapBuffers( NGLXDrawable drawable );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+++ b/src/include/GL/oscontext.h
@@ -1,0 +1,37 @@
+#ifndef _tgl_osbuffer_h_
+#define _tgl_osbuffer_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+  void **zbs;
+  void **framebuffers;
+  int numbuffers;
+  int xsize, ysize;
+} ostgl_context;
+
+ostgl_context *
+ostgl_create_context(const int xsize,
+                     const int ysize,
+                     const int depth,
+                     void **framebuffers,
+                     const int numbuffers);
+void
+ostgl_delete_context(ostgl_context *context);
+
+void
+ostgl_make_current(ostgl_context *context, const int index);
+
+void
+ostgl_resize(ostgl_context * context,
+             const int xsize,
+             const int ysize,
+             void **framebuffers);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _tgl_osbuffer_h_ */
--- /dev/null
+++ b/src/include/GLView.h
@@ -1,0 +1,72 @@
+#ifndef _glview_h_
+#define _glview_h_
+
+#define BGL_RGB           0
+#define BGL_INDEX         1
+#define BGL_SINGLE        0
+#define BGL_DOUBLE        2
+#define BGL_DIRECT        0
+#define BGL_INDIRECT      4
+#define BGL_ACCUM         8
+#define BGL_ALPHA        16
+#define BGL_DEPTH        32
+#define BGL_OVERLAY      64
+#define BGL_UNDERLAY    128
+#define BGL_STENCIL     512
+
+#include <interface/View.h>
+#include <support/Locker.h>
+#include "GL/gl.h"
+#include "GL/oscontext.h"
+#include <game/WindowScreen.h>
+#include <game/DirectWindow.h>
+
+class BGLView : public BView {
+public:
+  BGLView(BRect rect, char *name,
+          ulong resizingMode, ulong mode,
+          ulong options);
+  virtual ~BGLView();
+
+  void LockGL();
+  void UnlockGL();
+  void SwapBuffers();
+//  BView *EmbeddedView();
+//  status_t CopyPixelsOut(BPoint source, BBitmap *dest);
+//  status_t CopyPixelsIn(BBitmap *source, BPoint dest);
+
+  virtual void ErrorCallback(GLenum errorCode);
+  virtual void Draw(BRect updateRect);
+  virtual void AttachedToWindow();
+  virtual void AllAttached();
+  virtual void DetachedFromWindow();
+  virtual void AllDetached();
+  virtual void FrameResized(float width, float height);
+//  virtual status_t Perform(perform_code d, void *arg);
+
+  //
+  // Methods below are pass-throughs to BView for the moment.
+  //
+  
+  virtual status_t Archive(BMessage *data, bool deep = true) const;
+  virtual void MessageReceived(BMessage *msg);
+  virtual void SetResizingMode(uint32 mode);
+
+  virtual void Show();
+  virtual void Hide();
+
+  virtual BHandler *ResolveSpecifier(BMessage *msg, int32 index,
+							         BMessage *specifier, int32 form,
+							         const char *property);
+  virtual status_t GetSupportedSuites(BMessage *data);
+  //void DirectConnected( direct_buffer_info *info );
+  //void EnableDirectMode( bool enabled );
+
+private:
+  ostgl_context *context;
+  BBitmap *bitmaps[2];
+  int currBitmap;
+  static BLocker locker;
+};
+
+#endif // _glview_h_
--- /dev/null
+++ b/src/init.c
@@ -1,0 +1,191 @@
+#include "zgl.h"
+
+GLContext *gl_ctx;
+
+
+void initSharedState(GLContext *c)
+{
+  GLSharedState *s=&c->shared_state;
+  s->lists=gl_zalloc(sizeof(GLList *) * MAX_DISPLAY_LISTS);
+  s->texture_hash_table=
+      gl_zalloc(sizeof(GLTexture *) * TEXTURE_HASH_TABLE_SIZE);
+
+  alloc_texture(c,0);
+}
+
+void endSharedState(GLContext *c)
+{
+  GLSharedState *s=&c->shared_state;
+  int i;
+
+  for(i=0;i<MAX_DISPLAY_LISTS;i++) {
+    /* TODO */
+  }
+  gl_free(s->lists);
+
+  gl_free(s->texture_hash_table);
+}
+
+
+void glInit(void *zbuffer1)
+{
+  ZBuffer *zbuffer=(ZBuffer *)zbuffer1;
+  GLContext *c;
+  GLViewport *v;
+  int i;
+
+  c=gl_zalloc(sizeof(GLContext));
+  gl_ctx=c;
+
+  c->zb=zbuffer;
+
+  /* allocate GLVertex array */
+  c->vertex_max = POLYGON_MAX_VERTEX;
+  c->vertex = gl_malloc(POLYGON_MAX_VERTEX*sizeof(GLVertex));
+  
+  /* viewport */
+  v=&c->viewport;
+  v->xmin=0;
+  v->ymin=0;
+  v->xsize=zbuffer->xsize;
+  v->ysize=zbuffer->ysize;
+  v->updated=1;
+
+  /* shared state */
+  initSharedState(c);
+
+  /* lists */
+
+  c->exec_flag=1;
+  c->compile_flag=0;
+  c->print_flag=0;
+
+  c->in_begin=0;
+
+  /* lights */
+  for(i=0;i<MAX_LIGHTS;i++) {
+    GLLight *l=&c->lights[i];
+    l->ambient=gl_V4_New(0,0,0,1);
+    l->diffuse=gl_V4_New(1,1,1,1);
+    l->specular=gl_V4_New(1,1,1,1);
+    l->position=gl_V4_New(0,0,1,0);
+    l->norm_position=gl_V3_New(0,0,1);
+    l->spot_direction=gl_V3_New(0,0,-1);
+    l->norm_spot_direction=gl_V3_New(0,0,-1);
+    l->spot_exponent=0;
+    l->spot_cutoff=180;
+    l->attenuation[0]=1;
+    l->attenuation[1]=0;
+    l->attenuation[2]=0;
+    l->enabled=0;
+  }
+  c->first_light=NULL;
+  c->ambient_light_model=gl_V4_New(0.2,0.2,0.2,1);
+  c->local_light_model=0;
+  c->lighting_enabled=0;
+  c->light_model_two_side = 0;
+
+  /* default materials */
+  for(i=0;i<2;i++) {
+    GLMaterial *m=&c->materials[i];
+    m->emission=gl_V4_New(0,0,0,1);
+    m->ambient=gl_V4_New(0.2,0.2,0.2,1);
+    m->diffuse=gl_V4_New(0.8,0.8,0.8,1);
+    m->specular=gl_V4_New(0,0,0,1);
+    m->shininess=0;
+  }
+  c->current_color_material_mode=GL_FRONT_AND_BACK;
+  c->current_color_material_type=GL_AMBIENT_AND_DIFFUSE;
+  c->color_material_enabled=0;
+
+  /* textures */
+  glInitTextures(c);
+
+  /* default state */
+  c->current_color.X=1.0;
+  c->current_color.Y=1.0;
+  c->current_color.Z=1.0;
+  c->current_color.W=1.0;
+  c->longcurrent_color[0] = 65535;
+  c->longcurrent_color[1] = 65535;
+  c->longcurrent_color[2] = 65535;
+
+  c->current_normal.X=1.0;
+  c->current_normal.Y=0.0;
+  c->current_normal.Z=0.0;
+  c->current_normal.W=0.0;
+
+  c->current_edge_flag=1;
+  
+  c->current_tex_coord.X=0;
+  c->current_tex_coord.Y=0;
+  c->current_tex_coord.Z=0;
+  c->current_tex_coord.W=1;
+
+  c->polygon_mode_front=GL_FILL;
+  c->polygon_mode_back=GL_FILL;
+
+  c->current_front_face=0; /* 0 = GL_CCW  1 = GL_CW */
+  c->current_cull_face=GL_BACK;
+  c->current_shade_model=GL_SMOOTH;
+  c->cull_face_enabled=0;
+  c->zb->dostipple = 0;
+  for(int i = 0; i < 128; i++)
+  	c->zb->stipplepattern[i] = 0xFF;
+  /* clear */
+  c->clear_color.v[0]=0;
+  c->clear_color.v[1]=0;
+  c->clear_color.v[2]=0;
+  c->clear_color.v[3]=0;
+  c->clear_depth=0;
+
+  /* selection */
+  c->render_mode=GL_RENDER;
+  c->select_buffer=NULL;
+  c->name_stack_size=0;
+
+  /* matrix */
+  c->matrix_mode=0;
+  
+  c->matrix_stack_depth_max[0]=MAX_MODELVIEW_STACK_DEPTH;
+  c->matrix_stack_depth_max[1]=MAX_PROJECTION_STACK_DEPTH;
+  c->matrix_stack_depth_max[2]=MAX_TEXTURE_STACK_DEPTH;
+
+  for(i=0;i<3;i++) {
+    c->matrix_stack[i]=gl_zalloc(c->matrix_stack_depth_max[i] * sizeof(M4));
+    c->matrix_stack_ptr[i]=c->matrix_stack[i];
+  }
+
+  glMatrixMode(GL_PROJECTION);
+  glLoadIdentity();
+  glMatrixMode(GL_TEXTURE);
+  glLoadIdentity();
+  glMatrixMode(GL_MODELVIEW);
+  glLoadIdentity();
+
+  c->matrix_model_projection_updated=1;
+
+  /* opengl 1.1 arrays */
+  c->client_states = 0;
+  
+  /* opengl 1.1 polygon offset */
+  c->offset_states = 0;
+  
+  /* clear the resize callback function pointer */
+  c->gl_resize_viewport = NULL;
+  
+  /* specular buffer */
+  c->specbuf_first = NULL;
+  c->specbuf_used_counter = 0;
+  c->specbuf_num_buffers = 0;
+
+  /* depth test */
+  c->depth_test = 0;
+}
+
+void glClose(void)
+{
+  GLContext *c=gl_get_context();
+  endSharedState(c);
+  gl_free(c);
+}
--- /dev/null
+++ b/src/light.c
@@ -1,0 +1,312 @@
+#include "zgl.h"
+#include "msghandling.h"
+
+void glopMaterial(GLContext *c,GLParam *p)
+{
+  int mode=p[1].i;
+  int type=p[2].i;
+  float *v=&p[3].f;
+  int i;
+  GLMaterial *m;
+
+  if (mode == GL_FRONT_AND_BACK) {
+    p[1].i=GL_FRONT;
+    glopMaterial(c,p);
+    mode=GL_BACK;
+  }
+  if (mode == GL_FRONT) m=&c->materials[0];
+  else m=&c->materials[1];
+
+  switch(type) {
+  case GL_EMISSION:
+    for(i=0;i<4;i++)
+      m->emission.v[i]=v[i];
+    break;
+  case GL_AMBIENT:
+    for(i=0;i<4;i++)
+      m->ambient.v[i]=v[i];
+    break;
+  case GL_DIFFUSE:
+    for(i=0;i<4;i++)
+      m->diffuse.v[i]=v[i];
+    break;
+  case GL_SPECULAR:
+    for(i=0;i<4;i++)
+      m->specular.v[i]=v[i];
+    break;
+  case GL_SHININESS:
+    m->shininess=v[0];
+    m->shininess_i = (v[0]/128.0f)*SPECULAR_BUFFER_RESOLUTION;
+    break;
+  case GL_AMBIENT_AND_DIFFUSE:
+    for(i=0;i<4;i++)
+      m->diffuse.v[i]=v[i];
+    for(i=0;i<4;i++)
+      m->ambient.v[i]=v[i];
+    break;
+  default:
+    assert(0);
+  }
+}
+
+void glopColorMaterial(GLContext *c,GLParam *p)
+{
+  int mode=p[1].i;
+  int type=p[2].i;
+
+  c->current_color_material_mode=mode;
+  c->current_color_material_type=type;
+}
+
+void glopLight(GLContext *c,GLParam *p)
+{
+  int light=p[1].i;
+  int type=p[2].i;
+  V4 v;
+  GLLight *l;
+  int i;
+  
+  assert(light >= GL_LIGHT0 && light < GL_LIGHT0+MAX_LIGHTS );
+
+  l=&c->lights[light-GL_LIGHT0];
+
+  for(i=0;i<4;i++) v.v[i]=p[3+i].f;
+
+  switch(type) {
+  case GL_AMBIENT:
+    l->ambient=v;
+    break;
+  case GL_DIFFUSE:
+    l->diffuse=v;
+    break;
+  case GL_SPECULAR:
+    l->specular=v;
+    break;
+  case GL_POSITION:
+    {
+      V4 pos;
+      gl_M4_MulV4(&pos,c->matrix_stack_ptr[0],&v);
+
+      l->position=pos;
+
+      if (l->position.v[3] == 0) {
+        l->norm_position.X=pos.X;
+        l->norm_position.Y=pos.Y;
+        l->norm_position.Z=pos.Z;
+        
+        gl_V3_Norm(&l->norm_position);
+      }
+    }
+    break;
+  case GL_SPOT_DIRECTION:
+    for(i=0;i<3;i++) {
+      l->spot_direction.v[i]=v.v[i];
+      l->norm_spot_direction.v[i]=v.v[i];
+    }
+    gl_V3_Norm(&l->norm_spot_direction);
+    break;
+  case GL_SPOT_EXPONENT:
+    l->spot_exponent=v.v[0];
+    break;
+  case GL_SPOT_CUTOFF:
+    {
+      float a=v.v[0];
+      assert(a == 180 || (a>=0 && a<=90));
+      l->spot_cutoff=a;
+      if (a != 180) l->cos_spot_cutoff=cos(a * M_PI / 180.0);
+    }
+    break;
+  case GL_CONSTANT_ATTENUATION:
+    l->attenuation[0]=v.v[0];
+    break;
+  case GL_LINEAR_ATTENUATION:
+    l->attenuation[1]=v.v[0];
+    break;
+  case GL_QUADRATIC_ATTENUATION:
+    l->attenuation[2]=v.v[0];
+    break;
+  default:
+    assert(0);
+  }
+}
+  
+
+void glopLightModel(GLContext *c,GLParam *p)
+{
+  int pname=p[1].i;
+  float *v=&p[2].f;
+  int i;
+
+  switch(pname) {
+  case GL_LIGHT_MODEL_AMBIENT:
+    for(i=0;i<4;i++) 
+      c->ambient_light_model.v[i]=v[i];
+    break;
+  case GL_LIGHT_MODEL_LOCAL_VIEWER:
+    c->local_light_model=(int)v[0];
+    break;
+  case GL_LIGHT_MODEL_TWO_SIDE:
+    c->light_model_two_side = (int)v[0];
+    break;
+  default:
+    tgl_warning("glopLightModel: illegal pname: 0x%x\n", pname);
+    //assert(0);
+    break;
+  }
+}
+
+
+static inline float clampf(float a,float min,float max)
+{
+  if (a<min) return min;
+  else if (a>max) return max;
+  else return a;
+}
+
+void gl_enable_disable_light(GLContext *c,int light,int v)
+{
+  GLLight *l=&c->lights[light];
+  if (v && !l->enabled) {
+    l->enabled=1;
+    l->next=c->first_light;
+    c->first_light=l;
+    l->prev=NULL;
+  } else if (!v && l->enabled) {
+    l->enabled=0;
+    if (l->prev == NULL) c->first_light=l->next;
+    else l->prev->next=l->next;
+    if (l->next != NULL) l->next->prev=l->prev;
+  }
+}
+
+//FEATURES
+int zEnableSpecular = 1; //Enable specular lighting
+void glSetEnableSpecular(int s){
+	zEnableSpecular = s;
+}
+/* non optimized lightening model */
+void gl_shade_vertex(GLContext *c,GLVertex *v)
+{
+  float R,G,B,A;
+  GLMaterial *m;
+  GLLight *l;
+  V3 n,s,d;
+  float dist,tmp,att,dot,dot_spot,dot_spec;
+  int twoside = c->light_model_two_side;
+
+  m=&c->materials[0];
+
+  n.X=v->normal.X;
+  n.Y=v->normal.Y;
+  n.Z=v->normal.Z;
+
+  R=m->emission.v[0]+m->ambient.v[0]*c->ambient_light_model.v[0];
+  G=m->emission.v[1]+m->ambient.v[1]*c->ambient_light_model.v[1];
+  B=m->emission.v[2]+m->ambient.v[2]*c->ambient_light_model.v[2];
+  A=clampf(m->diffuse.v[3],0,1);
+
+  for(l=c->first_light;l!=NULL;l=l->next) {
+    float lR,lB,lG;
+    
+    /* ambient */
+    lR=l->ambient.v[0] * m->ambient.v[0];
+    lG=l->ambient.v[1] * m->ambient.v[1];
+    lB=l->ambient.v[2] * m->ambient.v[2];
+
+    if (l->position.v[3] == 0) {
+      /* light at infinity */
+      d.X=l->position.v[0];
+      d.Y=l->position.v[1];
+      d.Z=l->position.v[2];
+      att=1;
+    } else {
+      /* distance attenuation */
+      d.X=l->position.v[0]-v->ec.v[0];
+      d.Y=l->position.v[1]-v->ec.v[1];
+      d.Z=l->position.v[2]-v->ec.v[2];
+      dist=sqrt(d.X*d.X+d.Y*d.Y+d.Z*d.Z);
+      if (dist>1E-3) {
+        tmp=1/dist;
+        d.X*=tmp;
+        d.Y*=tmp;
+        d.Z*=tmp;
+      }
+      att=1.0f/(l->attenuation[0]+dist*(l->attenuation[1]+
+				     dist*l->attenuation[2]));
+    }
+    dot=d.X*n.X+d.Y*n.Y+d.Z*n.Z;
+    if (twoside && dot < 0) dot = -dot;
+    if (dot>0) {
+      /* diffuse light */
+      lR+=dot * l->diffuse.v[0] * m->diffuse.v[0];
+      lG+=dot * l->diffuse.v[1] * m->diffuse.v[1];
+      lB+=dot * l->diffuse.v[2] * m->diffuse.v[2];
+
+      /* spot light */
+      if (l->spot_cutoff != 180) {
+        dot_spot=-(d.X*l->norm_spot_direction.v[0]+
+                   d.Y*l->norm_spot_direction.v[1]+
+                   d.Z*l->norm_spot_direction.v[2]);
+        if (twoside && dot_spot < 0) dot_spot = -dot_spot;
+        if (dot_spot < l->cos_spot_cutoff) {
+          /* no contribution */
+          continue;
+        } else {
+          /* TODO: optimize */
+          if (l->spot_exponent > 0) {
+            att=att*pow(dot_spot,l->spot_exponent);
+          }
+        }
+      }
+
+      /* specular light */
+      if (zEnableSpecular){
+	      if (c->local_light_model) {
+	        V3 vcoord;
+	        vcoord.X=v->ec.X;
+	        vcoord.Y=v->ec.Y;
+	        vcoord.Z=v->ec.Z;
+	        gl_V3_Norm(&vcoord);
+	        s.X=d.X-vcoord.X;
+	        s.Y=d.Y-vcoord.X;
+	        s.Z=d.Z-vcoord.X;
+	      } else {
+	        s.X=d.X;
+	        s.Y=d.Y;
+	        s.Z=d.Z+1.0;
+	      }
+	      dot_spec=n.X*s.X+n.Y*s.Y+n.Z*s.Z;
+	      if (twoside && dot_spec < 0) dot_spec = -dot_spec;
+	      if (dot_spec>0) {
+	        GLSpecBuf *specbuf;
+	        int idx;
+	        tmp=sqrt(s.X*s.X+s.Y*s.Y+s.Z*s.Z);
+	        if (tmp > 1E-3) {
+	          dot_spec=dot_spec / tmp;
+	        }
+	      
+	        /* TODO: optimize */
+	        /* testing specular buffer code */
+	        /* dot_spec= pow(dot_spec,m->shininess);*/
+	        specbuf = specbuf_get_buffer(c, m->shininess_i, m->shininess);
+	        idx = (int)(dot_spec*SPECULAR_BUFFER_SIZE);
+	        if (idx > SPECULAR_BUFFER_SIZE) idx = SPECULAR_BUFFER_SIZE;
+	        dot_spec = specbuf->buf[idx];
+	        lR+=dot_spec * l->specular.v[0] * m->specular.v[0];
+	        lG+=dot_spec * l->specular.v[1] * m->specular.v[1];
+	        lB+=dot_spec * l->specular.v[2] * m->specular.v[2];
+          }//EOF if dot_spec>0
+      }//EOF zEnableSpecular
+    } //EOF if dot > 0
+
+    R+=att * lR;
+    G+=att * lG;
+    B+=att * lB;
+  } //End of light loop.
+
+  v->color.v[0]=clampf(R,0,1);
+  v->color.v[1]=clampf(G,0,1);
+  v->color.v[2]=clampf(B,0,1);
+  v->color.v[3]=A;
+}
+
--- /dev/null
+++ b/src/list.c
@@ -1,0 +1,255 @@
+#include "zgl.h"
+
+static char *op_table_str[]=
+{
+#define ADD_OP(a,b,c) "gl" #a " " #c,
+
+#include "opinfo.h"
+};
+
+static void (*op_table_func[])(GLContext *,GLParam *)=
+{
+#define ADD_OP(a,b,c) glop ## a ,
+
+#include "opinfo.h"
+};
+
+static int op_table_size[]=
+{
+#define ADD_OP(a,b,c) b + 1 ,
+
+#include "opinfo.h"
+};
+
+
+GLContext *gl_get_context(void)
+{
+  return gl_ctx;
+}
+
+static GLList *find_list(GLContext *c,unsigned int list)
+{
+  return c->shared_state.lists[list];
+}
+
+static void delete_list(GLContext *c,int list)
+{
+  GLParamBuffer *pb,*pb1;
+  GLList *l;
+
+  l=find_list(c,list);
+  assert(l != NULL);
+  
+  /* free param buffer */
+  pb=l->first_op_buffer;
+  while (pb!=NULL) {
+    pb1=pb->next;
+    gl_free(pb);
+    pb=pb1;
+  }
+  
+  gl_free(l);
+  c->shared_state.lists[list]=NULL;
+}
+
+static GLList *alloc_list(GLContext *c,int list)
+{
+  GLList *l;
+  GLParamBuffer *ob;
+
+  l=gl_zalloc(sizeof(GLList));
+  ob=gl_zalloc(sizeof(GLParamBuffer));
+
+  ob->next=NULL;
+  l->first_op_buffer=ob;
+  
+  ob->ops[0].op=OP_EndList;
+
+  c->shared_state.lists[list]=l;
+  return l;
+}
+
+
+void gl_print_op(FILE *f,GLParam *p)
+{
+  int op;
+  char *s;
+
+  op=p[0].op;
+  p++;
+  s=op_table_str[op];
+  while (*s != 0) {
+    if (*s == '%') {
+      s++;
+      switch (*s++) {
+      case 'f':
+	fprintf(f,"%g",p[0].f);
+	break;
+      default:
+	fprintf(f,"%d",p[0].i);
+	break;
+      }
+      p++;
+    } else {
+      fputc(*s,f);
+      s++;
+    }
+  }
+  fprintf(f,"\n");
+}
+
+
+void gl_compile_op(GLContext *c,GLParam *p)
+{
+  int op,op_size;
+  GLParamBuffer *ob,*ob1;
+  int index,i;
+
+  op=p[0].op;
+  op_size=op_table_size[op];
+  index=c->current_op_buffer_index;
+  ob=c->current_op_buffer;
+
+  /* we should be able to add a NextBuffer opcode */
+  if ((index + op_size) > (OP_BUFFER_MAX_SIZE-2)) {
+
+    ob1=gl_zalloc(sizeof(GLParamBuffer));
+    ob1->next=NULL;
+
+    ob->next=ob1;
+    ob->ops[index].op=OP_NextBuffer;
+    ob->ops[index+1].p=(void *)ob1;
+
+    c->current_op_buffer=ob1;
+    ob=ob1;
+    index=0;
+  }
+
+  for(i=0;i<op_size;i++) {
+    ob->ops[index]=p[i];
+    index++;
+  }
+  c->current_op_buffer_index=index;
+}
+
+void gl_add_op(GLParam *p)
+{
+  GLContext *c=gl_get_context();
+  int op;
+
+  op=p[0].op;
+  if (c->exec_flag) {
+    op_table_func[op](c,p);
+  }
+  if (c->compile_flag) {
+    gl_compile_op(c,p);
+  }
+  if (c->print_flag) {
+    gl_print_op(stderr,p);
+  }
+}
+
+/* this opcode is never called directly */
+void glopEndList(GLContext *c,GLParam *p)
+{
+  assert(0);
+}
+
+/* this opcode is never called directly */
+void glopNextBuffer(GLContext *c,GLParam *p)
+{
+  assert(0);
+}
+
+
+void glopCallList(GLContext *c,GLParam *p)
+{
+  GLList *l;
+  int list,op;
+
+  list=p[1].ui;
+  l=find_list(c,list);
+  if (l == NULL) gl_fatal_error("list %d not defined",list);
+  p=l->first_op_buffer->ops;
+
+  while (1) {
+    op=p[0].op;
+    if (op == OP_EndList) break;
+    if (op == OP_NextBuffer) {
+      p=(GLParam *)p[1].p;
+    } else {
+      op_table_func[op](c,p);
+      p+=op_table_size[op];
+    }
+  }
+}
+
+
+
+void glNewList(unsigned int list,int mode)
+{
+  GLList *l;
+  GLContext *c=gl_get_context();
+
+  assert(mode == GL_COMPILE || mode == GL_COMPILE_AND_EXECUTE);
+  assert(c->compile_flag == 0);
+
+  l=find_list(c,list);
+  if (l!=NULL) delete_list(c,list);
+  l=alloc_list(c,list);
+
+  c->current_op_buffer=l->first_op_buffer;
+  c->current_op_buffer_index=0;
+  
+  c->compile_flag=1;
+  c->exec_flag=(mode == GL_COMPILE_AND_EXECUTE);
+}
+
+void glEndList(void)
+{
+  GLContext *c=gl_get_context();
+  GLParam p[1];
+
+  assert(c->compile_flag == 1);
+  
+  /* end of list */
+  p[0].op=OP_EndList;
+  gl_compile_op(c,p);
+  
+  c->compile_flag=0;
+  c->exec_flag=1;
+}
+
+int glIsList(unsigned int list)
+{
+  GLContext *c=gl_get_context();
+  GLList *l;
+  l=find_list(c,list);
+  return (l != NULL);
+}
+
+unsigned int glGenLists(int range)
+{
+  GLContext *c=gl_get_context();
+  int count,i,list;
+  GLList **lists;
+
+  lists=c->shared_state.lists;
+  count=0;
+  for(i=0;i<MAX_DISPLAY_LISTS;i++) {
+    if (lists[i]==NULL) {
+      count++;
+      if (count == range) {
+	list=i-range+1;
+	for(i=0;i<range;i++) {
+	  alloc_list(c,list+i);
+	}
+	return list;
+      }
+    } else {
+      count=0;
+    }
+  }
+  return 0;
+}
+
--- /dev/null
+++ b/src/matrix.c
@@ -1,0 +1,241 @@
+#include "zgl.h"
+
+void gl_print_matrix( const float *m)
+{
+   int i;
+
+   for (i=0;i<4;i++) {
+      fprintf(stderr,"%f %f %f %f\n", m[i], m[4+i], m[8+i], m[12+i] );
+   }
+}
+
+static inline void gl_matrix_update(GLContext *c)
+{
+  c->matrix_model_projection_updated=(c->matrix_mode<=1);
+}
+
+
+void glopMatrixMode(GLContext *c,GLParam *p)
+{
+  int mode=p[1].i;
+  switch(mode) {
+  case GL_MODELVIEW:
+    c->matrix_mode=0;
+    break;
+  case GL_PROJECTION:
+    c->matrix_mode=1;
+    break;
+  case GL_TEXTURE:
+    c->matrix_mode=2;
+    break;
+  default:
+    assert(0);
+  }
+}
+
+void glopLoadMatrix(GLContext *c,GLParam *p)
+{
+  M4 *m;
+  int i;
+  
+  GLParam *q;
+
+  m=c->matrix_stack_ptr[c->matrix_mode];
+  q=p+1;
+
+  for(i=0;i<4;i++) {
+    m->m[0][i]=q[0].f;
+    m->m[1][i]=q[1].f;
+    m->m[2][i]=q[2].f;
+    m->m[3][i]=q[3].f;
+    q+=4;
+  }
+
+  gl_matrix_update(c);
+}
+
+void glopLoadIdentity(GLContext *c,GLParam *p)
+{
+
+  gl_M4_Id(c->matrix_stack_ptr[c->matrix_mode]);
+
+  gl_matrix_update(c);
+}
+
+void glopMultMatrix(GLContext *c,GLParam *p)
+{
+  M4 m;
+  int i;
+
+  GLParam *q;
+  q=p+1;
+
+  for(i=0;i<4;i++) {
+    m.m[0][i]=q[0].f;
+    m.m[1][i]=q[1].f;
+    m.m[2][i]=q[2].f;
+    m.m[3][i]=q[3].f;
+    q+=4;
+  }
+
+  gl_M4_MulLeft(c->matrix_stack_ptr[c->matrix_mode],&m);
+
+  gl_matrix_update(c);
+}
+
+
+void glopPushMatrix(GLContext *c,GLParam *p)
+{
+  int n=c->matrix_mode;
+  M4 *m;
+
+  assert( (c->matrix_stack_ptr[n] - c->matrix_stack[n] + 1 )
+	   < c->matrix_stack_depth_max[n] );
+
+  m=++c->matrix_stack_ptr[n];
+  
+  gl_M4_Move(&m[0],&m[-1]);
+
+  gl_matrix_update(c);
+}
+
+void glopPopMatrix(GLContext *c,GLParam *p)
+{
+  int n=c->matrix_mode;
+
+  assert( c->matrix_stack_ptr[n] > c->matrix_stack[n] );
+  c->matrix_stack_ptr[n]--;
+  gl_matrix_update(c);
+}
+
+
+void glopRotate(GLContext *c,GLParam *p)
+{
+  M4 m;
+  float u[3];
+  float angle;
+  int dir_code;
+
+  angle = p[1].f * M_PI / 180.0;
+  u[0]=p[2].f;
+  u[1]=p[3].f;
+  u[2]=p[4].f;
+
+  /* simple case detection */
+  dir_code = ((u[0] != 0)<<2) | ((u[1] != 0)<<1) | (u[2] != 0);
+
+  switch(dir_code) {
+  case 0:
+    gl_M4_Id(&m);
+    break;
+  case 4:
+    if (u[0] < 0) angle=-angle;
+    gl_M4_Rotate(&m,angle,0);
+    break;
+  case 2:
+    if (u[1] < 0) angle=-angle;
+    gl_M4_Rotate(&m,angle,1);
+    break;
+  case 1:
+    if (u[2] < 0) angle=-angle;
+    gl_M4_Rotate(&m,angle,2);
+    break;
+  default:
+    {
+      float cost, sint;
+
+      /* normalize vector */
+      float len = u[0]*u[0]+u[1]*u[1]+u[2]*u[2];
+      if (len == 0.0f) return;
+      len = 1.0f / sqrt(len);
+      u[0] *= len;
+      u[1] *= len;
+      u[2] *= len;
+
+      /* store cos and sin values */
+      cost=cos(angle);
+      sint=sin(angle);
+
+      /* fill in the values */
+      m.m[3][0]=m.m[3][1]=m.m[3][2]=
+        m.m[0][3]=m.m[1][3]=m.m[2][3]=0.0f;
+      m.m[3][3]=1.0f;
+
+      /* do the math */
+      m.m[0][0]=u[0]*u[0]+cost*(1-u[0]*u[0]);
+      m.m[1][0]=u[0]*u[1]*(1-cost)-u[2]*sint;
+      m.m[2][0]=u[2]*u[0]*(1-cost)+u[1]*sint;
+      m.m[0][1]=u[0]*u[1]*(1-cost)+u[2]*sint;
+      m.m[1][1]=u[1]*u[1]+cost*(1-u[1]*u[1]);
+      m.m[2][1]=u[1]*u[2]*(1-cost)-u[0]*sint;
+      m.m[0][2]=u[2]*u[0]*(1-cost)-u[1]*sint;
+      m.m[1][2]=u[1]*u[2]*(1-cost)+u[0]*sint;
+      m.m[2][2]=u[2]*u[2]+cost*(1-u[2]*u[2]);
+    }
+  }
+
+  gl_M4_MulLeft(c->matrix_stack_ptr[c->matrix_mode],&m);
+
+  gl_matrix_update(c);
+}
+
+void glopScale(GLContext *c,GLParam *p)
+{
+  float *m;
+  float x=p[1].f,y=p[2].f,z=p[3].f;
+
+  m=&c->matrix_stack_ptr[c->matrix_mode]->m[0][0];
+
+  m[0] *= x;   m[1] *= y;   m[2]  *= z;
+  m[4] *= x;   m[5] *= y;   m[6]  *= z;
+  m[8] *= x;   m[9] *= y;   m[10] *= z;
+  m[12] *= x;   m[13] *= y;   m[14] *= z;
+  gl_matrix_update(c);
+}
+
+void glopTranslate(GLContext *c,GLParam *p)
+{
+  float *m;
+  float x=p[1].f,y=p[2].f,z=p[3].f;
+
+  m=&c->matrix_stack_ptr[c->matrix_mode]->m[0][0];
+
+  m[3] = m[0] * x + m[1] * y + m[2]  * z + m[3];
+  m[7] = m[4] * x + m[5] * y + m[6]  * z + m[7];
+  m[11] = m[8] * x + m[9] * y + m[10] * z + m[11];
+  m[15] = m[12] * x + m[13] * y + m[14] * z + m[15];
+
+  gl_matrix_update(c);
+}
+
+
+void glopFrustum(GLContext *c,GLParam *p)
+{
+  float *r;
+  M4 m;
+  float left=p[1].f;
+  float right=p[2].f;
+  float bottom=p[3].f;
+  float top=p[4].f;
+  float near=p[5].f;
+  float farp=p[6].f;
+  float x,y,A,B,C,D;
+
+  x = (2.0*near) / (right-left);
+  y = (2.0*near) / (top-bottom);
+  A = (right+left) / (right-left);
+  B = (top+bottom) / (top-bottom);
+  C = -(farp+near) / ( farp-near);
+  D = -(2.0*farp*near) / (farp-near);
+
+  r=&m.m[0][0];
+  r[0]= x; r[1]=0; r[2]=A; r[3]=0;
+  r[4]= 0; r[5]=y; r[6]=B; r[7]=0;
+  r[8]= 0; r[9]=0; r[10]=C; r[11]=D;
+  r[12]= 0; r[13]=0; r[14]=-1; r[15]=0;
+
+  gl_M4_MulLeft(c->matrix_stack_ptr[c->matrix_mode],&m);
+
+  gl_matrix_update(c);
+}
+  
--- /dev/null
+++ b/src/memory.c
@@ -1,0 +1,21 @@
+/*
+ * Memory allocator for TinyGL
+ */
+#include "zgl.h"
+
+/* modify these functions so that they suit your needs */
+
+void gl_free(void *p)
+{
+    free(p);
+}
+
+void *gl_malloc(int size)
+{
+    return malloc(size);
+}
+
+void *gl_zalloc(int size)
+{
+    return calloc(1, size);
+}
--- /dev/null
+++ b/src/misc.c
@@ -1,0 +1,163 @@
+#include "zgl.h"
+#include "msghandling.h"
+
+
+
+void glPolygonStipple(void* a){
+	unsigned char* b = a;
+	GLContext *c=gl_get_context();
+	ZBuffer *zb = c->zb;
+	for(int i = 0; i < 128; i++)
+	{
+		zb->stipplepattern[i] = b[i];
+	}
+}
+
+
+void glopViewport(GLContext *c,GLParam *p)
+{
+  int xsize,ysize,xmin,ymin,xsize_req,ysize_req;
+  
+  xmin=p[1].i;
+  ymin=p[2].i;
+  xsize=p[3].i;
+  ysize=p[4].i;
+
+  /* we may need to resize the zbuffer */
+
+  if (c->viewport.xmin != xmin ||
+      c->viewport.ymin != ymin ||
+      c->viewport.xsize != xsize ||
+      c->viewport.ysize != ysize) {
+
+    xsize_req=xmin+xsize;
+    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");
+    }
+
+    xsize=xsize_req-xmin;
+    ysize=ysize_req-ymin;
+    if (xsize <= 0 || ysize <= 0) {
+      gl_fatal_error("glViewport: size too small");
+    }
+
+    tgl_trace("glViewport: %d %d %d %d\n",
+              xmin, ymin, xsize, ysize);
+    c->viewport.xmin=xmin;
+    c->viewport.ymin=ymin;
+    c->viewport.xsize=xsize;
+    c->viewport.ysize=ysize;
+    
+    c->viewport.updated=1;
+  }
+}
+
+void glopEnableDisable(GLContext *c,GLParam *p)
+{
+  int code=p[1].i;
+  int v=p[2].i;
+
+  switch(code) {
+  case GL_CULL_FACE:
+    c->cull_face_enabled=v;
+    break;
+  case GL_LIGHTING:
+    c->lighting_enabled=v;
+    break;
+  case GL_COLOR_MATERIAL:
+    c->color_material_enabled=v;
+      break;
+  case GL_TEXTURE_2D:
+    c->texture_2d_enabled=v;
+    break;
+  case GL_NORMALIZE:
+    c->normalize_enabled=v;
+    break;
+  case GL_DEPTH_TEST:
+    c->depth_test = v;
+    break;
+  case GL_POLYGON_OFFSET_FILL:
+    if (v) c->offset_states |= TGL_OFFSET_FILL;
+    else c->offset_states &= ~TGL_OFFSET_FILL;
+    break; 
+  case GL_POLYGON_STIPPLE:
+  	c->zb->dostipple = v;
+  	break;
+  case GL_POLYGON_OFFSET_POINT:
+    if (v) c->offset_states |= TGL_OFFSET_POINT;
+    else c->offset_states &= ~TGL_OFFSET_POINT;
+    break; 
+  case GL_POLYGON_OFFSET_LINE:
+    if (v) c->offset_states |= TGL_OFFSET_LINE;
+    else c->offset_states &= ~TGL_OFFSET_LINE;
+    break; 
+  default:
+    if (code>=GL_LIGHT0 && code<GL_LIGHT0+MAX_LIGHTS) {
+      gl_enable_disable_light(c,code - GL_LIGHT0, v);
+    } else {
+      /*
+      fprintf(stderr,"glEnableDisable: 0x%X not supported.\n",code);
+      */
+    }
+    break;
+  }
+}
+
+void glopShadeModel(GLContext *c,GLParam *p)
+{
+  int code=p[1].i;
+  c->current_shade_model=code;
+}
+
+void glopCullFace(GLContext *c,GLParam *p)
+{
+  int code=p[1].i;
+  c->current_cull_face=code;
+}
+
+void glopFrontFace(GLContext *c,GLParam *p)
+{
+  int code=p[1].i;
+  c->current_front_face=code;
+}
+
+void glopPolygonMode(GLContext *c,GLParam *p)
+{
+  int face=p[1].i;
+  int mode=p[2].i;
+  
+  switch(face) {
+  case GL_BACK:
+    c->polygon_mode_back=mode;
+    break;
+  case GL_FRONT:
+    c->polygon_mode_front=mode;
+    break;
+  case GL_FRONT_AND_BACK:
+    c->polygon_mode_front=mode;
+    c->polygon_mode_back=mode;
+    break;
+  default:
+    assert(0);
+  }
+}
+
+void glopHint(GLContext *c,GLParam *p)
+{
+#if 0
+  int target=p[1].i;
+  int mode=p[2].i;
+
+  /* do nothing */
+#endif
+}
+
+void 
+glopPolygonOffset(GLContext *c, GLParam *p)
+{
+  c->offset_factor = p[1].f;
+  c->offset_units = p[2].f;
+}
--- /dev/null
+++ b/src/msghandling.c
@@ -1,0 +1,52 @@
+#include <stdarg.h>
+#include <stdio.h>
+
+#define NDEBUG
+
+#ifdef NDEBUG
+#define NO_DEBUG_OUTPUT
+#endif
+
+/* Use this function to output messages when something unexpected
+   happens (which might be an indication of an error). *Don't* use it
+   when there's internal errors in the code - these should be handled
+   by asserts. */
+void
+tgl_warning(const char *format, ...)
+{
+#ifndef NO_DEBUG_OUTPUT
+  va_list args;
+  va_start(args, format);
+  fprintf(stderr, "*WARNING* ");
+  vfprintf(stderr, format, args);
+  va_end(args);
+#endif /* !NO_DEBUG_OUTPUT */
+}
+
+/* This function should be used for debug output only. */
+void
+tgl_trace(const char *format, ...)
+{
+#ifndef NO_DEBUG_OUTPUT
+  va_list args;
+  va_start(args, format);
+  fprintf(stderr, "*DEBUG* ");
+  vfprintf(stderr, format, args);
+  va_end(args);
+#endif /* !NO_DEBUG_OUTPUT */
+}
+
+/* Use this function to output info about things in the code which
+   should be fixed (missing handling of special cases, important
+   features not implemented, known bugs/buglets, ...). */
+void
+tgl_fixme(const char *format, ...)
+{
+#ifndef NO_DEBUG_OUTPUT
+  va_list args;
+  va_start(args, format);
+  fprintf(stderr, "*FIXME* ");
+  vfprintf(stderr, format, args);
+  va_end(args);
+#endif /* !NO_DEBUG_OUTPUT */
+}
--- /dev/null
+++ b/src/msghandling.h
@@ -1,0 +1,8 @@
+#ifndef _msghandling_h_
+#define _msghandling_h_
+
+extern void tgl_warning(const char *text, ...);
+extern void tgl_trace(const char *text, ...);
+extern void tgl_fixme(const char *text, ...);
+
+#endif /* _msghandling_h_ */
--- /dev/null
+++ b/src/opinfo.h
@@ -1,0 +1,71 @@
+
+
+ADD_OP(Color,7,"%f %f %f %f %d %d %d")
+ADD_OP(TexCoord,4,"%f %f %f %f")
+ADD_OP(EdgeFlag,1,"%d")
+ADD_OP(Normal,3,"%f %f %f")
+
+ADD_OP(Begin,1,"%C")
+ADD_OP(Vertex,4,"%f %f %f %f")
+ADD_OP(End,0,"")
+
+ADD_OP(EnableDisable,2,"%C %d")
+
+ADD_OP(MatrixMode,1,"%C")
+ADD_OP(LoadMatrix,16,"")
+ADD_OP(LoadIdentity,0,"")
+ADD_OP(MultMatrix,16,"")
+ADD_OP(PushMatrix,0,"")
+ADD_OP(PopMatrix,0,"")
+ADD_OP(Rotate,4,"%f %f %f %f")
+ADD_OP(Translate,3,"%f %f %f")
+ADD_OP(Scale,3,"%f %f %f")
+
+ADD_OP(Viewport,4,"%d %d %d %d")
+ADD_OP(Frustum,6,"%f %f %f %f %f %f")
+
+ADD_OP(Material,6,"%C %C %f %f %f %f")
+ADD_OP(ColorMaterial,2,"%C %C")
+ADD_OP(Light,6,"%C %C %f %f %f %f")
+ADD_OP(LightModel,5,"%C %f %f %f %f")
+
+ADD_OP(Clear,1,"%d")
+ADD_OP(ClearColor,4,"%f %f %f %f")
+ADD_OP(ClearDepth,1,"%f")
+
+ADD_OP(InitNames,0,"")
+ADD_OP(PushName,1,"%d")
+ADD_OP(PopName,0,"")
+ADD_OP(LoadName,1,"%d")
+
+ADD_OP(TexImage2D,9,"%d %d %d %d %d %d %d %d %d")
+ADD_OP(BindTexture,2,"%C %d")
+ADD_OP(TexEnv,7,"%C %C %C %f %f %f %f")
+ADD_OP(TexParameter,7,"%C %C %C %f %f %f %f")
+ADD_OP(PixelStore,2,"%C %C")
+
+ADD_OP(ShadeModel,1,"%C")
+ADD_OP(CullFace,1,"%C")
+ADD_OP(FrontFace,1,"%C")
+ADD_OP(PolygonMode,2,"%C %C")
+
+ADD_OP(CallList,1,"%d")
+ADD_OP(Hint,2,"%C %C")
+
+/* special opcodes */
+ADD_OP(EndList,0,"")
+ADD_OP(NextBuffer,1,"%p")
+
+/* opengl 1.1 arrays */
+ADD_OP(ArrayElement, 1, "%d")
+ADD_OP(EnableClientState, 1, "%C")
+ADD_OP(DisableClientState, 1, "%C")
+ADD_OP(VertexPointer, 4, "%d %C %d %p")
+ADD_OP(ColorPointer, 4, "%d %C %d %p")
+ADD_OP(NormalPointer, 3, "%C %d %p")
+ADD_OP(TexCoordPointer, 4, "%d %C %d %p")
+
+/* opengl 1.1 polygon offset */
+ADD_OP(PolygonOffset, 2, "%f %f")
+
+#undef ADD_OP
--- /dev/null
+++ b/src/oscontext.c
@@ -1,0 +1,84 @@
+#include "include/GL/oscontext.h"
+#include "zbuffer.h"
+#include "zgl.h"
+#include "include/GL/gl.h"
+#include <stdlib.h>
+#include <assert.h>
+
+static int buffercnt = 0;
+
+ostgl_context *
+ostgl_create_context(const int xsize,
+                     const int ysize,
+                     const int depth,
+                     void **framebuffers,
+                     const int numbuffers)
+{
+  ostgl_context *context;
+  int i;
+  ZBuffer *zb;
+   
+  assert(depth == 16); /* support for other depths must include bpp 
+                          convertion */
+  assert(numbuffers >= 1);
+  
+  context = gl_malloc(sizeof(ostgl_context));
+  assert(context);
+  context->zbs = gl_malloc(sizeof(void*)*numbuffers);
+  context->framebuffers = gl_malloc(sizeof(void*)*numbuffers);
+  
+  assert(context->zbs != NULL && context->framebuffers != NULL);
+  
+  for (i = 0; i < numbuffers; i++) {
+    context->framebuffers[i] = framebuffers[i];
+    zb = ZB_open(xsize, ysize, ZB_MODE_5R6G5B, 0, NULL, NULL, framebuffers[i]);
+    if (zb == NULL) {
+      fprintf(stderr, "Error while initializing Z buffer\n");
+      exit(1);
+    }
+    context->zbs[i] = zb;
+  }
+  if (++buffercnt == 1) {
+    glInit(context->zbs[0]);
+  }
+  context->xsize = xsize;
+  context->ysize = ysize;
+  context->numbuffers = numbuffers;
+  return context;
+}
+
+void
+ostgl_delete_context(ostgl_context *context)
+{
+  int i;
+  for (i = 0; i < context->numbuffers; i++) {
+    ZB_close(context->zbs[i]);
+  }
+  gl_free(context->zbs);
+  gl_free(context->framebuffers);
+  gl_free(context);
+  
+  if (--buffercnt == 0) {
+    glClose();
+  }
+}
+
+void
+ostgl_make_current(ostgl_context *oscontext, const int idx)
+{
+  GLContext *context = gl_get_context();
+  assert(idx < oscontext->numbuffers);
+  context->zb = oscontext->zbs[idx];
+}
+
+void
+ostgl_resize(ostgl_context *context,
+             const int xsize,
+             const int ysize,
+             void **framebuffers)
+{
+  int i;
+  for (i = 0; i < context->numbuffers; i++) {
+    ZB_resize(context->zbs[i], framebuffers[i], xsize, ysize);
+  }
+}
--- /dev/null
+++ b/src/select.c
@@ -1,0 +1,114 @@
+#include "zgl.h"
+
+int glRenderMode(int mode)
+{
+  GLContext *c=gl_get_context();
+  int result=0;
+  
+  switch(c->render_mode) {
+  case GL_RENDER:
+    break;
+  case GL_SELECT:
+    if (c->select_overflow) {
+      result=-c->select_hits;
+    } else {
+      result=c->select_hits;
+    }
+    c->select_overflow=0;
+    c->select_ptr=c->select_buffer;
+    c->name_stack_size=0;
+    break;
+  default:
+    assert(0);
+  }
+  switch(mode) {
+  case GL_RENDER:
+    c->render_mode=GL_RENDER;
+    break;
+  case GL_SELECT:
+    c->render_mode=GL_SELECT;
+    assert( c->select_buffer != NULL);
+    c->select_ptr=c->select_buffer;
+    c->select_hits=0;
+    c->select_overflow=0;
+    c->select_hit=NULL;
+    break;
+  default:
+    assert(0);
+  }
+  return result;
+}
+
+void glSelectBuffer(int size,unsigned int *buf)
+{
+  GLContext *c=gl_get_context();
+
+  assert(c->render_mode != GL_SELECT);
+  
+  c->select_buffer=buf;
+  c->select_size=size;
+}
+
+
+void glopInitNames(GLContext *c,GLParam *p)
+{
+  if (c->render_mode == GL_SELECT) {
+    c->name_stack_size=0;
+    c->select_hit=NULL;
+  }
+}
+
+void glopPushName(GLContext *c,GLParam *p)
+{
+  if (c->render_mode == GL_SELECT) {
+    assert(c->name_stack_size<MAX_NAME_STACK_DEPTH);
+    c->name_stack[c->name_stack_size++]=p[1].i;
+    c->select_hit=NULL;
+  }
+}
+
+void glopPopName(GLContext *c,GLParam *p)
+{
+  if (c->render_mode == GL_SELECT) {
+    assert(c->name_stack_size>0);
+    c->name_stack_size--;
+    c->select_hit=NULL;
+  }
+}
+
+void glopLoadName(GLContext *c,GLParam *p)
+{
+  if (c->render_mode == GL_SELECT) {
+   assert(c->name_stack_size>0);
+   c->name_stack[c->name_stack_size-1]=p[1].i;
+   c->select_hit=NULL;
+  }
+}
+
+void gl_add_select(GLContext *c,unsigned int zmin,unsigned int zmax)
+{
+  unsigned int *ptr;
+  int n,i;
+
+  if (!c->select_overflow) {
+    if (c->select_hit==NULL) {
+      n=c->name_stack_size;
+      if ((c->select_ptr-c->select_buffer+3+n) > 
+	  c->select_size) {
+	c->select_overflow=1;
+      } else {
+	ptr=c->select_ptr;
+	c->select_hit=ptr;
+	*ptr++=c->name_stack_size;
+	*ptr++=zmin;
+	*ptr++=zmax;
+	for(i=0;i<n;i++) *ptr++=c->name_stack[i];
+	c->select_ptr=ptr;
+	c->select_hits++;
+      }
+    } else {
+      if (zmin<c->select_hit[1]) c->select_hit[1]=zmin;
+      if (zmax>c->select_hit[2]) c->select_hit[2]=zmax;
+    }
+  }
+}
--- /dev/null
+++ b/src/specbuf.c
@@ -1,0 +1,52 @@
+#include "zgl.h"
+#include "msghandling.h"
+#include <math.h>
+#include <stdlib.h>
+
+static void calc_buf(GLSpecBuf *buf, const float shininess)
+{
+  int i;
+  float val, inc;
+  val = 0.0f;
+  inc = 1.0f/SPECULAR_BUFFER_SIZE;
+  for (i = 0; i <= SPECULAR_BUFFER_SIZE; i++) {
+    buf->buf[i] = pow(val, shininess);
+    val += inc;
+  }
+}
+
+GLSpecBuf *
+specbuf_get_buffer(GLContext *c, const int shininess_i, 
+                   const float shininess)
+{
+  GLSpecBuf *found, *oldest;
+  found = oldest = c->specbuf_first;
+  while (found && found->shininess_i != shininess_i) {
+    if (found->last_used < oldest->last_used) {
+      oldest = found;
+    }
+    found = found->next; 
+  }
+  if (found) { /* hey, found one! */
+    found->last_used = c->specbuf_used_counter++;
+    return found;
+  }
+  if (oldest == NULL || c->specbuf_num_buffers < MAX_SPECULAR_BUFFERS) {
+    /* create new buffer */
+    GLSpecBuf *buf = gl_malloc(sizeof(GLSpecBuf));
+    if (!buf) gl_fatal_error("could not allocate specular buffer");
+    c->specbuf_num_buffers++;
+    buf->next = c->specbuf_first;
+    c->specbuf_first = buf;
+    buf->last_used = c->specbuf_used_counter++;
+    buf->shininess_i = shininess_i;
+    calc_buf(buf, shininess);
+    return buf;     
+  }
+  /* overwrite the lru buffer */
+  /*tgl_trace("overwriting spec buffer :(\n");*/
+  oldest->shininess_i = shininess_i;
+  oldest->last_used = c->specbuf_used_counter++;
+  calc_buf(oldest, shininess);
+  return oldest;
+}
--- /dev/null
+++ b/src/specbuf.h
@@ -1,0 +1,22 @@
+#ifndef _tgl_specbuf_h_
+#define _tgl_specbuf_h_
+
+/* Max # of specular light pow buffers */
+#define MAX_SPECULAR_BUFFERS 8
+/* # of entries in specular buffer */
+#define SPECULAR_BUFFER_SIZE 1024
+/* specular buffer granularity */
+#define SPECULAR_BUFFER_RESOLUTION 1024
+
+typedef struct GLSpecBuf {
+  int shininess_i;
+  int last_used;
+  float buf[SPECULAR_BUFFER_SIZE+1];
+  struct GLSpecBuf *next;
+} GLSpecBuf;
+
+GLSpecBuf *specbuf_get_buffer(GLContext *c, const int shininess_i, 
+                              const float shininess);
+void specbuf_cleanup(GLContext *c); /* free all memory used */
+
+#endif /* _tgl_specbuf_h_ */
\ No newline at end of file
--- /dev/null
+++ b/src/texture.c
@@ -1,0 +1,240 @@
+/*
+ * Texture Manager
+ */
+
+#include "zgl.h"
+
+static GLTexture *find_texture(GLContext *c,int h)
+{
+  GLTexture *t;
+
+  t=c->shared_state.texture_hash_table[h % TEXTURE_HASH_TABLE_SIZE];
+  while (t!=NULL) {
+    if (t->handle == h) return t;
+    t=t->next;
+  }
+  return NULL;
+}
+
+void* glGetTexturePixmap(int text, int level, int* xsize, int* ysize){
+	GLTexture* tex;
+	GLContext *c=gl_get_context();
+	assert(text >= 0 && level < MAX_TEXTURE_LEVELS);
+	tex = find_texture(c, text);
+	if(!tex)return NULL;
+	*xsize = tex->images[level].xsize;
+	*ysize = tex->images[level].ysize;
+	return tex->images[level].pixmap;
+}
+
+static void free_texture(GLContext *c,int h)
+{
+  GLTexture *t,**ht;
+  GLImage *im;
+  int i;
+
+  t=find_texture(c,h);
+  if (t->prev==NULL) {
+    ht=&c->shared_state.texture_hash_table
+      [t->handle % TEXTURE_HASH_TABLE_SIZE];
+    *ht=t->next;
+  } else {
+    t->prev->next=t->next;
+  }
+  if (t->next!=NULL) t->next->prev=t->prev;
+
+  for(i=0;i<MAX_TEXTURE_LEVELS;i++) {
+    im=&t->images[i];
+    if (im->pixmap != NULL) gl_free(im->pixmap);
+  }
+
+  gl_free(t);
+}
+
+GLTexture *alloc_texture(GLContext *c,int h)
+{
+  GLTexture *t,**ht;
+  
+  t=gl_zalloc(sizeof(GLTexture));
+
+  ht=&c->shared_state.texture_hash_table[h % TEXTURE_HASH_TABLE_SIZE];
+
+  t->next=*ht;
+  t->prev=NULL;
+  if (t->next != NULL) t->next->prev=t;
+  *ht=t;
+
+  t->handle=h;
+  
+  return t;
+}
+
+
+void glInitTextures(GLContext *c)
+{
+  /* textures */
+
+  c->texture_2d_enabled=0;
+  c->current_texture=find_texture(c,0);
+}
+
+void glGenTextures(int n, unsigned int *textures)
+{
+  GLContext *c=gl_get_context();
+  int max,i;
+  GLTexture *t;
+
+  max=0;
+  for(i=0;i<TEXTURE_HASH_TABLE_SIZE;i++) {
+    t=c->shared_state.texture_hash_table[i];
+    while (t!=NULL) {
+      if (t->handle>max) max=t->handle;
+      t=t->next;
+    }
+
+  }
+  for(i=0;i<n;i++) {
+    textures[i]=max+i+1;
+  }
+}
+
+
+void glDeleteTextures(int n, const unsigned int *textures)
+{
+  GLContext *c=gl_get_context();
+  int i;
+  GLTexture *t;
+
+  for(i=0;i<n;i++) {
+    t=find_texture(c,textures[i]);
+    if (t!=NULL && t!=0) {
+      if (t==c->current_texture) {
+	glBindTexture(GL_TEXTURE_2D,0);
+      }
+      free_texture(c,textures[i]);
+    }
+  }
+}
+
+
+void glopBindTexture(GLContext *c,GLParam *p)
+{
+  int target=p[1].i;
+  int texture=p[2].i;
+  GLTexture *t;
+
+  assert(target == GL_TEXTURE_2D && texture >= 0);
+
+  t=find_texture(c,texture);
+  if (t==NULL) {
+    t=alloc_texture(c,texture);
+  }
+  c->current_texture=t;
+}
+
+void glopTexImage2D(GLContext *c,GLParam *p)
+{
+  int target=p[1].i;
+  int level=p[2].i;
+  int components=p[3].i;
+  int width=p[4].i;
+  int height=p[5].i;
+  int border=p[6].i;
+  int format=p[7].i;
+  int type=p[8].i;
+  void *pixels=p[9].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)) {
+    gl_fatal_error("glTexImage2D: combination 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;
+  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) {
+      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);
+}
+
+
+/* TODO: not all tests are done */
+void glopTexEnv(GLContext *c,GLParam *p)
+{
+  int target=p[1].i;
+  int pname=p[2].i;
+  int param=p[3].i;
+
+  if (target != GL_TEXTURE_ENV) {
+  error:
+    gl_fatal_error("glTexParameter: unsupported option");
+  }
+
+  if (pname != GL_TEXTURE_ENV_MODE) goto error;
+
+  if (param != GL_DECAL) goto error;
+}
+
+/* TODO: not all tests are done */
+void glopTexParameter(GLContext *c,GLParam *p)
+{
+  int target=p[1].i;
+  int pname=p[2].i;
+  int param=p[3].i;
+  
+  if (target != GL_TEXTURE_2D) {
+  error:
+    gl_fatal_error("glTexParameter: unsupported option");
+  }
+
+  switch(pname) {
+  case GL_TEXTURE_WRAP_S:
+  case GL_TEXTURE_WRAP_T:
+    if (param != GL_REPEAT) goto error;
+    break;
+  }
+}
+
+void glopPixelStore(GLContext *c,GLParam *p)
+{
+  int pname=p[1].i;
+  int param=p[2].i;
+
+  if (pname != GL_UNPACK_ALIGNMENT ||
+      param != 1) {
+    gl_fatal_error("glPixelStore: unsupported option");
+  }
+}
--- /dev/null
+++ b/src/vertex.c
@@ -1,0 +1,364 @@
+#include "zgl.h"
+#include <string.h>
+void glopNormal(GLContext * c, GLParam * p)
+{
+    V3 v;
+
+    v.X = p[1].f;
+    v.Y = p[2].f;
+    v.Z = p[3].f;
+
+    c->current_normal.X = v.X;
+    c->current_normal.Y = v.Y;
+    c->current_normal.Z = v.Z;
+    c->current_normal.W = 0;
+}
+
+void glopTexCoord(GLContext * c, GLParam * p)
+{
+    c->current_tex_coord.X = p[1].f;
+    c->current_tex_coord.Y = p[2].f;
+    c->current_tex_coord.Z = p[3].f;
+    c->current_tex_coord.W = p[4].f;
+}
+
+void glopEdgeFlag(GLContext * c, GLParam * p)
+{
+    c->current_edge_flag = p[1].i;
+}
+
+void glopColor(GLContext * c, GLParam * p)
+{
+
+    c->current_color.X = p[1].f;
+    c->current_color.Y = p[2].f;
+    c->current_color.Z = p[3].f;
+    c->current_color.W = p[4].f;
+    c->longcurrent_color[0] = p[5].ui;
+    c->longcurrent_color[1] = p[6].ui;
+    c->longcurrent_color[2] = p[7].ui;
+
+    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 = p[1].f;
+	q[4].f = p[2].f;
+	q[5].f = p[3].f;
+	q[6].f = p[4].f;
+	glopMaterial(c, q);
+    }
+}
+
+
+void gl_eval_viewport(GLContext * c)
+{
+    GLViewport *v;
+    float zsize = (1 << (ZB_Z_BITS + ZB_POINT_Z_FRAC_BITS));
+
+    v = &c->viewport;
+
+    v->trans.X = ((v->xsize - 0.5) / 2.0) + v->xmin;
+    v->trans.Y = ((v->ysize - 0.5) / 2.0) + v->ymin;
+    v->trans.Z = ((zsize - 0.5) / 2.0) + ((1 << ZB_POINT_Z_FRAC_BITS)) / 2;
+
+    v->scale.X = (v->xsize - 0.5) / 2.0;
+    v->scale.Y = -(v->ysize - 0.5) / 2.0;
+    v->scale.Z = -((zsize - 0.5) / 2.0);
+}
+
+void glopBegin(GLContext * c, GLParam * p)
+{
+    int type;
+    M4 tmp;
+
+    assert(c->in_begin == 0);
+
+    type = p[1].i;
+    c->begin_type = type;
+    c->in_begin = 1;
+    c->vertex_n = 0;
+    c->vertex_cnt = 0;
+
+    if (c->matrix_model_projection_updated) {
+
+	if (c->lighting_enabled) {
+	    /* precompute inverse modelview */
+	    gl_M4_Inv(&tmp, c->matrix_stack_ptr[0]);
+	    gl_M4_Transpose(&c->matrix_model_view_inv, &tmp);
+	} else {
+	    float *m = &c->matrix_model_projection.m[0][0];
+	    /* precompute projection matrix */
+	    gl_M4_Mul(&c->matrix_model_projection,
+		      c->matrix_stack_ptr[1],
+		      c->matrix_stack_ptr[0]);
+	    /* test to accelerate computation */
+	    c->matrix_model_projection_no_w_transform = 0;
+	    if (m[12] == 0.0 && m[13] == 0.0 && m[14] == 0.0)
+		c->matrix_model_projection_no_w_transform = 1;
+	}
+
+	/* test if the texture matrix is not Identity */
+	c->apply_texture_matrix = !gl_M4_IsId(c->matrix_stack_ptr[2]);
+
+	c->matrix_model_projection_updated = 0;
+    }
+    /*  viewport */
+    if (c->viewport.updated) {
+	gl_eval_viewport(c);
+	c->viewport.updated = 0;
+    }
+    /* triangle drawing functions */
+    if (c->render_mode == GL_SELECT) {
+	c->draw_triangle_front = gl_draw_triangle_select;
+	c->draw_triangle_back = gl_draw_triangle_select;
+    } else {
+	switch (c->polygon_mode_front) {
+	case GL_POINT:
+	    c->draw_triangle_front = gl_draw_triangle_point;
+	    break;
+	case GL_LINE:
+	    c->draw_triangle_front = gl_draw_triangle_line;
+	    break;
+	default:
+	    c->draw_triangle_front = gl_draw_triangle_fill;
+	    break;
+	}
+
+	switch (c->polygon_mode_back) {
+	case GL_POINT:
+	    c->draw_triangle_back = gl_draw_triangle_point;
+	    break;
+	case GL_LINE:
+	    c->draw_triangle_back = gl_draw_triangle_line;
+	    break;
+	default:
+	    c->draw_triangle_back = gl_draw_triangle_fill;
+	    break;
+	}
+    }
+}
+
+/* coords, tranformation , clip code and projection */
+/* TODO : handle all cases */
+static inline void gl_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);
+}
+
+void glopVertex(GLContext * c, GLParam * p)
+{
+    GLVertex *v;
+    int n, i, cnt;
+
+    assert(c->in_begin != 0);
+
+    n = c->vertex_n;
+    cnt = c->vertex_cnt;
+    cnt++;
+    c->vertex_cnt = cnt;
+
+    /* quick fix to avoid crashes on large polygons */
+    if (n >= c->vertex_max) {
+	GLVertex *newarray;
+	c->vertex_max <<= 1;	/* just double size */
+	newarray = gl_malloc(sizeof(GLVertex) * c->vertex_max);
+	if (!newarray) {
+	    gl_fatal_error("unable to allocate GLVertex array.\n");
+	}
+	memcpy(newarray, c->vertex, n * sizeof(GLVertex));
+	gl_free(c->vertex);
+	c->vertex = newarray;
+    }
+    /* new vertex entry */
+    v = &c->vertex[n];
+    n++;
+
+    v->coord.X = p[1].f;
+    v->coord.Y = p[2].f;
+    v->coord.Z = p[3].f;
+    v->coord.W = p[4].f;
+
+    gl_vertex_transform(c, v);
+
+    /* color */
+
+    if (c->lighting_enabled) {
+	gl_shade_vertex(c, v);
+    } else {
+	v->color = c->current_color;
+    }
+
+    /* tex coords */
+
+    if (c->texture_2d_enabled) {
+	if (c->apply_texture_matrix) {
+	    gl_M4_MulV4(&v->tex_coord, c->matrix_stack_ptr[2], &c->current_tex_coord);
+	} else {
+	    v->tex_coord = c->current_tex_coord;
+	}
+    }
+    /* precompute the mapping to the viewport */
+    if (v->clip_code == 0)
+	gl_transform_to_viewport(c, v);
+
+    /* edge flag */
+
+    v->edge_flag = c->current_edge_flag;
+
+    switch (c->begin_type) {
+    case GL_POINTS:
+	gl_draw_point(c, &c->vertex[0]);
+	n = 0;
+	break;
+
+    case GL_LINES:
+	if (n == 2) {
+	    gl_draw_line(c, &c->vertex[0], &c->vertex[1]);
+	    n = 0;
+	}
+	break;
+    case GL_LINE_STRIP:
+    case GL_LINE_LOOP:
+	if (n == 1) {
+	    c->vertex[2] = c->vertex[0];
+	} else if (n == 2) {
+	    gl_draw_line(c, &c->vertex[0], &c->vertex[1]);
+	    c->vertex[0] = c->vertex[1];
+	    n = 1;
+	}
+	break;
+
+    case GL_TRIANGLES:
+	if (n == 3) {
+	    gl_draw_triangle(c, &c->vertex[0], &c->vertex[1], &c->vertex[2]);
+	    n = 0;
+	}
+	break;
+    case GL_TRIANGLE_STRIP:
+	if (cnt >= 3) {
+	    if (n == 3)
+		n = 0;
+            /* needed to respect triangle orientation */
+            switch(cnt & 1) {
+            case 0:
+      		gl_draw_triangle(c,&c->vertex[2],&c->vertex[1],&c->vertex[0]);
+      		break;
+            default:
+            case 1:
+      		gl_draw_triangle(c,&c->vertex[0],&c->vertex[1],&c->vertex[2]);
+      		break;
+            }
+	}
+	break;
+    case GL_TRIANGLE_FAN:
+	if (n == 3) {
+	    gl_draw_triangle(c, &c->vertex[0], &c->vertex[1], &c->vertex[2]);
+	    c->vertex[1] = c->vertex[2];
+	    n = 2;
+	}
+	break;
+
+    case GL_QUADS:
+	if (n == 4) {
+	    c->vertex[2].edge_flag = 0;
+	    gl_draw_triangle(c, &c->vertex[0], &c->vertex[1], &c->vertex[2]);
+	    c->vertex[2].edge_flag = 1;
+	    c->vertex[0].edge_flag = 0;
+	    gl_draw_triangle(c, &c->vertex[0], &c->vertex[2], &c->vertex[3]);
+	    n = 0;
+	}
+	break;
+
+    case GL_QUAD_STRIP:
+	if (n == 4) {
+	    gl_draw_triangle(c, &c->vertex[0], &c->vertex[1], &c->vertex[2]);
+	    gl_draw_triangle(c, &c->vertex[1], &c->vertex[3], &c->vertex[2]);
+	    for (i = 0; i < 2; i++)
+		c->vertex[i] = c->vertex[i + 2];
+	    n = 2;
+	}
+	break;
+    case GL_POLYGON:
+	break;
+    default:
+	gl_fatal_error("glBegin: type %x not handled\n", c->begin_type);
+    }
+
+    c->vertex_n = n;
+}
+
+void glopEnd(GLContext * c, GLParam * param)
+{
+    assert(c->in_begin == 1);
+
+    if (c->begin_type == GL_LINE_LOOP) {
+	if (c->vertex_cnt >= 3) {
+	    gl_draw_line(c, &c->vertex[0], &c->vertex[2]);
+	}
+    } else if (c->begin_type == GL_POLYGON) {
+	int i = c->vertex_cnt;
+	while (i >= 3) {
+	    i--;
+	    gl_draw_triangle(c, &c->vertex[i], &c->vertex[0], &c->vertex[i - 1]);
+	}
+    }
+    c->in_begin = 0;
+}
--- /dev/null
+++ b/src/zbuffer.c
@@ -1,0 +1,531 @@
+/*
+
+ * Z buffer: 16 bits Z / 16 bits color
+ * 
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include "zbuffer.h"
+
+ZBuffer *ZB_open(int xsize, int ysize, int mode,
+		 int nb_colors,
+		 unsigned char *color_indexes,
+		 int *color_table,
+		 void *frame_buffer)
+{
+    ZBuffer *zb;
+    int size;
+
+    zb = gl_malloc(sizeof(ZBuffer));
+    if (zb == NULL)
+	return NULL;
+
+    zb->xsize = xsize;
+    zb->ysize = ysize;
+    zb->mode = mode;
+    zb->linesize = (xsize * PSZB + 3) & ~3;
+
+    switch (mode) {
+#ifdef TGL_FEATURE_8_BITS
+    case ZB_MODE_INDEX:
+	ZB_initDither(zb, nb_colors, color_indexes, color_table);
+	break;
+#endif
+#ifdef TGL_FEATURE_32_BITS
+    case ZB_MODE_RGBA:
+#endif
+#ifdef TGL_FEATURE_24_BITS
+    case ZB_MODE_RGB24:
+#endif
+    case ZB_MODE_5R6G5B:
+	zb->nb_colors = 0;
+	break;
+    default:
+	goto error;
+    }
+
+    size = zb->xsize * zb->ysize * sizeof(unsigned short);
+
+    zb->zbuf = gl_malloc(size);
+    if (zb->zbuf == NULL)
+	goto error;
+
+    if (frame_buffer == NULL) {
+	zb->pbuf = gl_malloc(zb->ysize * zb->linesize);
+	if (zb->pbuf == NULL) {
+	    gl_free(zb->zbuf);
+	    goto error;
+	}
+	zb->frame_buffer_allocated = 1;
+    } else {
+	zb->frame_buffer_allocated = 0;
+	zb->pbuf = frame_buffer;
+    }
+
+    zb->current_texture = NULL;
+
+    return zb;
+  error:
+    gl_free(zb);
+    return NULL;
+}
+
+void ZB_close(ZBuffer * zb)
+{
+#ifdef TGL_FEATURE_8_BITS
+    if (zb->mode == ZB_MODE_INDEX)
+	ZB_closeDither(zb);
+#endif
+
+    if (zb->frame_buffer_allocated)
+	gl_free(zb->pbuf);
+
+    gl_free(zb->zbuf);
+    gl_free(zb);
+}
+
+void ZB_resize(ZBuffer * zb, void *frame_buffer, int xsize, int ysize)
+{
+    int size;
+
+    /* xsize must be a multiple of 4 */
+    xsize = xsize & ~3;
+
+    zb->xsize = xsize;
+    zb->ysize = ysize;
+    zb->linesize = (xsize * PSZB + 3) & ~3;
+
+    size = zb->xsize * zb->ysize * sizeof(unsigned short);
+
+    gl_free(zb->zbuf);
+    zb->zbuf = gl_malloc(size);
+
+    if (zb->frame_buffer_allocated)
+	gl_free(zb->pbuf);
+
+    if (frame_buffer == NULL) {
+	zb->pbuf = gl_malloc(zb->ysize * zb->linesize);
+	zb->frame_buffer_allocated = 1;
+    } else {
+	zb->pbuf = frame_buffer;
+	zb->frame_buffer_allocated = 0;
+    }
+}
+
+static void ZB_copyBuffer(ZBuffer * zb,
+                          void *buf,
+                          int linesize)
+{
+    unsigned char *p1;
+    PIXEL *q;
+    int y;
+    #if !TGL_FEATURE_NO_COPY_COLOR
+    int n;
+    #endif
+
+    q = zb->pbuf;
+    p1 = buf;
+    #if !TGL_FEATURE_NO_COPY_COLOR
+    n = zb->xsize * PSZB;
+    #endif
+    for (y = 0; y < zb->ysize; y++) {
+    #if TGL_FEATURE_NO_COPY_COLOR
+		for(int i = 0; i < zb->xsize; i++)
+		{
+			if((*(q+i) & TGL_COLOR_MASK) != TGL_NO_COPY_COLOR)
+				*(((PIXEL*)p1) + i) = *(q+i);
+		}
+    #else
+		memcpy(p1, q, n);
+	#endif
+	p1 += linesize; //TODO make this a predictable behavior.
+	q = (PIXEL *) ((char *) q + zb->linesize);
+    }
+}
+
+#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;
+	puts("\nBEING CALLED\n");
+    for (y = 0; y < zb->ysize; y++) {
+	p = p1;
+	n = zb->xsize >> 2;
+	do {
+	    v = *(unsigned int *) q;
+	    RGB16_TO_RGB32(w1, w0, v);
+	    p[0] = w0;
+	    p[1] = w1;
+	    v = *(unsigned int *) (q + 2);
+	    RGB16_TO_RGB32(w1, w0, v);
+	    p[2] = w0;
+	    p[3] = 0;
+
+	    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, *p1, w0, w1, w2, v0, v1;
+    int y, n;
+
+    q = zb->pbuf;
+    p1 = (unsigned int *) buf;
+    linesize = linesize * 3;
+
+    for (y = 0; y < zb->ysize; y++) {
+	p = 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);
+
+	*((char *) 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))
+
+/* 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] = RGB32_TO_RGB16(q[0]);
+            p[1] = RGB32_TO_RGB16(q[1]);
+            p[2] = RGB32_TO_RGB16(q[2]);
+            p[3] = RGB32_TO_RGB16(q[3]);
+	    q += 4;
+	    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_32_BITS
+    case ZB_MODE_RGBA:
+	ZB_copyBuffer(zb, buf, linesize);
+	break;
+#endif
+    default:
+	assert(0);
+    }
+}
+
+#endif /* TGL_FEATURE_RENDER_BITS == 32 */
+
+
+/*
+ * adr must be aligned on an 'int'
+ */
+void memset_s(void *adr, int val, int count)
+{
+    int i, n, v;
+    unsigned int *p;
+    unsigned short *q;
+
+    p = adr;
+    v = val | (val << 16);
+
+    n = count >> 3;
+    for (i = 0; i < n; i++) {
+	p[0] = v;
+	p[1] = v;
+	p[2] = v;
+	p[3] = v;
+	p += 4;
+    }
+
+    q = (unsigned short *) p;
+    n = count & 7;
+    for (i = 0; i < n; i++)
+	*q++ = val;
+}
+
+void memset_l(void *adr, int val, int count)
+{
+    int i, n, v;
+    unsigned int *p;
+
+    p = adr;
+    v = val;
+    n = count >> 2;
+    for (i = 0; i < n; i++) {
+	p[0] = v;
+	p[1] = v;
+	p[2] = v;
+	p[3] = v;
+	p += 4;
+    }
+
+    n = count & 3;
+    for (i = 0; i < n; i++)
+	*p++ = val;
+}
+
+/* count must be a multiple of 4 and >= 4 */
+void memset_RGB24(void *adr,int r, int v, int b,long count)
+{
+    long i, n;
+    register long v1,v2,v3,*pt=(long *)(adr);
+    unsigned char *p,R=(unsigned char)r,V=(unsigned char)v,B=(unsigned char)b;
+
+    p=(unsigned char *)adr;
+    *p++=R;
+    *p++=V;
+    *p++=B;
+    *p++=R;
+    *p++=V;
+    *p++=B;
+    *p++=R;
+    *p++=V;
+    *p++=B;
+    *p++=R;
+    *p++=V;
+    *p++=B;
+    v1=*pt++;
+    v2=*pt++;
+    v3=*pt++;
+    n = count >> 2;
+    for(i=1;i<n;i++) {
+        *pt++=v1;
+        *pt++=v2;
+        *pt++=v3;
+    }
+}
+
+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;
+
+    if (clear_z) {
+	memset_s(zb->zbuf, z, zb->xsize * zb->ysize);
+    }
+    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);
+         #if TGL_FEATURE_FORCE_CLEAR_NO_COPY_COLOR
+         	color = TGL_NO_COPY_COLOR;
+         #else
+         	color = RGB_TO_PIXEL(r, g, b);
+         #endif
+	    memset_s(pp, color, zb->xsize);
+#elif TGL_FEATURE_RENDER_BITS == 32
+		#if TGL_FEATURE_FORCE_CLEAR_NO_COPY_COLOR
+			color = TGL_NO_COPY_COLOR;
+		#else
+            color = RGB_TO_PIXEL(r, g, b);
+        #endif
+	    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);
+	}
+    }
+}
--- /dev/null
+++ b/src/zbuffer.h
@@ -1,0 +1,157 @@
+#ifndef _tgl_zbuffer_h_
+#define _tgl_zbuffer_h_
+
+/*
+ * Z buffer
+ */
+
+#include "zfeatures.h"
+
+#define ZB_Z_BITS 16
+
+#define ZB_POINT_Z_FRAC_BITS 14
+
+#define ZB_POINT_S_MIN ( (1<<13) )
+#define ZB_POINT_S_MAX ( (1<<22)-(1<<13) )
+#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) )
+
+/* display modes */
+#define ZB_MODE_5R6G5B  1  /* true color 16 bits */
+#define ZB_MODE_INDEX   2  /* color index 8 bits */
+#define ZB_MODE_RGBA    3  /* 32 bit rgba mode */
+#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) \
+  ((((b) >> 1) & 0x7c00) | (((g) >> 6) & 0x03e0) | ((r) >> 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))
+typedef unsigned short PIXEL;
+#define PSZB 2 
+#define PSZSH 4 
+
+#elif TGL_FEATURE_RENDER_BITS == 24
+
+#define RGB_TO_PIXEL(r,g,b) \
+  ((((b) << 8) & 0xff0000) | ((g) & 0xff00) | ((r) >> 8))
+typedef unsigned char PIXEL;
+#define PSZB 3
+#define PSZSH 5
+
+#elif TGL_FEATURE_RENDER_BITS == 32
+
+#define RGB_TO_PIXEL(r,g,b) \
+  ((((b) << 8) & 0xff0000) | ((g) & 0xff00) | ((r) >> 8))
+//  ((((r) << 8) & 0xff0000) | ((g) & 0xff00) | ((b) >> 8))
+typedef unsigned int PIXEL;
+#define PSZB 4
+#define PSZSH 5
+
+#else
+
+#error Incorrect number of bits per pixel
+
+#endif
+
+typedef struct {
+    int xsize,ysize;
+    int linesize; /* line size, in bytes */
+    int mode;
+    
+    unsigned short *zbuf;
+    PIXEL *pbuf;
+    int frame_buffer_allocated;
+    /* opengl polygon stipple*/
+    int dostipple;
+    unsigned char stipplepattern[128]; //32 bits wide, 32 bits tall. 32 * 4 bytes.
+     
+    int nb_colors;
+    unsigned char *dctable;
+    int *ctable;
+    PIXEL *current_texture;
+} ZBuffer;
+
+typedef struct {
+  int x,y,z;     /* integer coordinates in the zbuffer */
+  int s,t;       /* coordinates for the mapping */
+  int r,g,b;     /* color indexes */
+  
+  float sz,tz;   /* temporary coordinates for mapping */
+} ZBufferPoint;
+
+/* zbuffer.c */
+
+ZBuffer *ZB_open(int xsize,int ysize,int mode,
+		 int nb_colors,
+		 unsigned char *color_indexes,
+		 int *color_table,
+		 void *frame_buffer);
+
+
+void ZB_close(ZBuffer *zb);
+
+void ZB_resize(ZBuffer *zb,void *frame_buffer,int xsize,int ysize);
+void ZB_clear(ZBuffer *zb,int clear_z,int z,
+	      int clear_color,int r,int g,int b);
+/* linesize is in BYTES */
+void ZB_copyFrameBuffer(ZBuffer *zb,void *buf,int linesize);
+
+/* zdither.c */
+
+void ZB_initDither(ZBuffer *zb,int nb_colors,
+		   unsigned char *color_indexes,int *color_table);
+void ZB_closeDither(ZBuffer *zb);
+void ZB_ditherFrameBuffer(ZBuffer *zb,unsigned char *dest,
+			  int linesize);
+
+/* zline.c */
+
+void ZB_plot(ZBuffer *zb,ZBufferPoint *p);
+void ZB_line(ZBuffer *zb,ZBufferPoint *p1,ZBufferPoint *p2);
+void ZB_line_z(ZBuffer * zb, ZBufferPoint * p1, ZBufferPoint * p2);
+
+/* ztriangle.c */
+
+void ZB_setTexture(ZBuffer *zb, PIXEL *texture);
+
+void ZB_fillTriangleFlat(ZBuffer *zb,
+		 ZBufferPoint *p1,ZBufferPoint *p2,ZBufferPoint *p3);
+
+void ZB_fillTriangleSmooth(ZBuffer *zb,
+		   ZBufferPoint *p1,ZBufferPoint *p2,ZBufferPoint *p3);
+
+void ZB_fillTriangleMapping(ZBuffer *zb,
+		    ZBufferPoint *p1,ZBufferPoint *p2,ZBufferPoint *p3);
+
+void ZB_fillTriangleMappingPerspective(ZBuffer *zb,
+                    ZBufferPoint *p0,ZBufferPoint *p1,ZBufferPoint *p2);
+
+
+typedef void (*ZB_fillTriangleFunc)(ZBuffer  *,
+	    ZBufferPoint *,ZBufferPoint *,ZBufferPoint *);
+
+/* memory.c */
+void gl_free(void *p);
+void *gl_malloc(int size);
+void *gl_zalloc(int size);
+
+#endif /* _tgl_zbuffer_h_ */
--- /dev/null
+++ b/src/zdither.c
@@ -1,0 +1,159 @@
+/* 
+ * Highly optimised dithering 16 bits -> 8 bits. 
+ * The formulas were taken in Mesa (Bob Mercier mercier@hollywood.cinenet.net).
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "zbuffer.h"
+#include <assert.h>
+
+#if defined(TGL_FEATURE_8_BITS)
+
+#define _R	5
+#define _G	9
+#define _B	5
+#define _DX	4
+#define _DY	4
+#define _D	(_DX*_DY)
+#define _MIX(r,g,b)	( ((g)<<6) | ((b)<<3) | (r) )
+
+#define DITHER_TABLE_SIZE (1 << 15)
+
+#define DITHER_INDEX(r,g,b) ((b) + (g) * _B + (r) * (_B * _G))
+
+#define MAXC	256
+static int kernel8[_DY*_DX] = {
+    0 * MAXC,  8 * MAXC,  2 * MAXC, 10 * MAXC,
+   12 * MAXC,  4 * MAXC, 14 * MAXC,  6 * MAXC,
+    3 * MAXC, 11 * MAXC,  1 * MAXC,  9 * MAXC,
+   15 * MAXC,  7 * MAXC, 13 * MAXC,  5 * MAXC,
+};
+
+/* we build the color table and the lookup table */
+
+void ZB_initDither(ZBuffer *zb,int nb_colors,
+		   unsigned char *color_indexes,int *color_table)
+{
+  int c,r,g,b,i,index,r1,g1,b1;
+
+  if (nb_colors < (_R * _G * _B)) {
+    fprintf(stderr,"zdither: not enough colors\n");
+    exit(1);
+  }
+
+  for(i=0;i<nb_colors;i++) color_table[i]=0;
+
+  zb->nb_colors=nb_colors;
+  zb->ctable=gl_malloc(nb_colors * sizeof(int));
+
+  for (r = 0; r < _R; r++) {
+    for (g = 0; g < _G; g++) {
+      for (b = 0; b < _B; b++) {
+	r1=(r*255) / (_R - 1);
+	g1=(g*255) / (_G - 1);
+	b1=(b*255) / (_B - 1);
+	index=DITHER_INDEX(r,g,b);
+	c=(r1 << 16) | (g1 << 8) | b1;
+	zb->ctable[index]=c;
+	color_table[index]=c;
+      }
+    }
+  }
+
+  zb->dctable=gl_malloc( DITHER_TABLE_SIZE );
+
+  for(i=0;i<DITHER_TABLE_SIZE;i++) {
+    r=(i >> 12) & 0x7;
+    g=(i >> 8) & 0xF;
+    b=(i >> 3) & 0x7;
+    index=DITHER_INDEX(r,g,b);
+    zb->dctable[i]=color_indexes[index];
+  }
+}
+
+void ZB_closeDither(ZBuffer *zb)
+{
+    gl_free(zb->ctable);
+    gl_free(zb->dctable);
+}
+
+#if 0
+int ZDither_lookupColor(int r,int g,int b)
+{
+  unsigned char *ctable=zdither_color_table;
+  return ctable[_MIX(_DITH0(_R, r), _DITH0(_G, g),_DITH0(_B, b))];
+}
+#endif
+
+
+#define DITHER_PIXEL2(a)			\
+{ \
+  register int v,t,r,g,c;			\
+  v=*(unsigned int *)(pp+(a));                  \
+  g=(v & 0x07DF07DF) + g_d; \
+  r=(((v & 0xF800F800) >> 2) + r_d) & 0x70007000; \
+  t=r | g; \
+  c=ctable[t & 0xFFFF] | (ctable[t >> 16] << 8); \
+  *(unsigned short *)(dest+(a))=c; 	\
+}
+
+/* NOTE: all the memory access are 16 bit aligned, so if buf or
+   linesize are not multiple of 2, it cannot work efficiently (or
+   hang!) */
+
+void ZB_ditherFrameBuffer(ZBuffer *zb,unsigned char *buf,
+			  int linesize)
+{
+  int xk,yk,x,y,c1,c2;
+  unsigned char *dest1;
+  unsigned short *pp1;
+  int r_d,g_d,b_d;
+  unsigned char *ctable=zb->dctable;
+  register unsigned char *dest;
+  register unsigned short *pp;
+
+  assert( ((long)buf & 1) == 0 && (linesize & 1) == 0);
+
+  for(yk=0;yk<4;yk++) {
+    for(xk=0;xk<4;xk+=2) {
+#if BYTE_ORDER == BIG_ENDIAN
+      c1=kernel8[yk*4+xk+1];
+      c2=kernel8[yk*4+xk];
+#else
+      c1=kernel8[yk*4+xk];
+      c2=kernel8[yk*4+xk+1];
+#endif
+      r_d=((c1 << 2) & 0xF800) >> 2;
+      g_d=(c1 >> 4) & 0x07C0;
+      b_d=(c1 >> 9) & 0x001F;
+      
+      r_d|=(((c2 << 2) & 0xF800) >> 2) << 16;
+      g_d|=((c2 >> 4) & 0x07C0) << 16;
+      b_d|=((c2 >> 9) & 0x001F) << 16;
+      g_d=b_d | g_d;
+
+      dest1=buf + (yk * linesize) + xk;
+      pp1=zb->pbuf + (yk * zb->xsize) + xk;
+      
+      for(y=yk;y<zb->ysize;y+=4) {
+	dest=dest1;
+	pp=pp1;
+	for(x=xk;x<zb->xsize;x+=16) {
+
+	  DITHER_PIXEL2(0);
+	  DITHER_PIXEL2(1*4);
+	  DITHER_PIXEL2(2*4);
+	  DITHER_PIXEL2(3*4);
+
+	  pp+=16;
+	  dest+=16;
+	}
+	dest1+=linesize*4;
+	pp1+=zb->xsize*4;
+      }
+    }
+  }
+}
+
+#endif
--- /dev/null
+++ b/src/zfeatures.h
@@ -1,0 +1,54 @@
+#ifndef _tgl_features_h_
+#define _tgl_features_h_
+
+/* It is possible to enable/disable (compile time) features in this
+   header file. */
+
+#define TGL_FEATURE_ARRAYS         1
+#define TGL_FEATURE_DISPLAYLISTS   1
+#define TGL_FEATURE_POLYGON_OFFSET 1
+#define TGL_FEATURE_POLYGON_STIPPLE 1
+#define TGL_FEATURE_NO_COPY_COLOR 0
+#define TGL_FEATURE_FORCE_CLEAR_NO_COPY_COLOR 0
+#define TGL_NO_COPY_COLOR 0xff00ff
+//NOTE: fc02fc is what you'll get if you set glColor3f to 1,0,1. 
+//^ solid debug pink.
+#define TGL_COLOR_MASK 0xffffff
+//^ mask to check for copybuffer. This is configured for the default mode.
+
+/*
+ * 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 */
+//CURRENT MAINTAINER'S NOTE: Only FEATURE_32_BITS is being maintained.
+#define TGL_FEATURE_16_BITS        1
+#define TGL_FEATURE_8_BITS         1
+#define TGL_FEATURE_24_BITS        1
+#define TGL_FEATURE_32_BITS        1
+
+//MAINTAINER'S NOTE: Only TGL_FEATURE_RENDER_BITS 32 is maintained.
+//All others are experimental.
+//24 bit is broken.
+//#define TGL_FEATURE_RENDER_BITS    15
+//#define TGL_FEATURE_RENDER_BITS    16
+//#define TGL_FEATURE_RENDER_BITS    24 //BROKEN!
+#define TGL_FEATURE_RENDER_BITS    32
+
+#endif /* _tgl_features_h_ */
--- /dev/null
+++ b/src/zgl.h
@@ -1,0 +1,374 @@
+#ifndef _tgl_zgl_h_
+#define _tgl_zgl_h_
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <assert.h>
+#include "include/GL/gl.h"
+#include "zbuffer.h"
+#include "zmath.h"
+#include "zfeatures.h"
+#ifndef M_PI
+#define M_PI 3.14159265358979323
+#endif
+#define DEBUG
+/* #define NDEBUG */
+
+enum {
+
+#define ADD_OP(a,b,c) OP_ ## a ,
+
+#include "opinfo.h"
+
+};
+
+/* initially # of allocated GLVertexes (will grow when necessary) */
+#define POLYGON_MAX_VERTEX 16
+
+/* Max # of specular light pow buffers */
+#define MAX_SPECULAR_BUFFERS 8
+/* # of entries in specular buffer */
+#define SPECULAR_BUFFER_SIZE 1024
+/* specular buffer granularity */
+#define SPECULAR_BUFFER_RESOLUTION 1024
+
+
+#define MAX_MODELVIEW_STACK_DEPTH  32
+#define MAX_PROJECTION_STACK_DEPTH 8
+#define MAX_TEXTURE_STACK_DEPTH    8
+#define MAX_NAME_STACK_DEPTH       64
+#define MAX_TEXTURE_LEVELS         11
+#define MAX_LIGHTS                 16
+
+#define VERTEX_HASH_SIZE 1031
+
+#define MAX_DISPLAY_LISTS 1024
+#define OP_BUFFER_MAX_SIZE 512
+
+#define TGL_OFFSET_FILL    0x1
+#define TGL_OFFSET_LINE    0x2
+#define TGL_OFFSET_POINT   0x4
+
+typedef struct GLSpecBuf {
+  int shininess_i;
+  int last_used;
+  float buf[SPECULAR_BUFFER_SIZE+1];
+  struct GLSpecBuf *next;
+} GLSpecBuf;
+
+typedef struct GLLight {
+  V4 ambient;
+  V4 diffuse;
+  V4 specular;
+  V4 position;	
+  V3 spot_direction;
+  float spot_exponent;
+  float spot_cutoff;
+  float attenuation[3];
+  /* precomputed values */
+  float cos_spot_cutoff;
+  V3 norm_spot_direction;
+  V3 norm_position;
+  /* we use a linked list to know which are the enabled lights */
+  int enabled;
+  struct GLLight *next,*prev;
+} GLLight;
+
+typedef struct GLMaterial {
+  V4 emission;
+  V4 ambient;
+  V4 diffuse;
+  V4 specular;
+  float shininess;
+
+  /* computed values */
+  int shininess_i;
+  int do_specular;  
+} GLMaterial;
+
+
+typedef struct GLViewport {
+  int xmin,ymin,xsize,ysize;
+  V3 scale;
+  V3 trans;
+  int updated;
+} GLViewport;
+
+typedef union {
+  int op;
+  float f;
+  int i;
+  unsigned int ui;
+  void *p;
+} GLParam;
+
+typedef struct GLParamBuffer {
+  GLParam ops[OP_BUFFER_MAX_SIZE];
+  struct GLParamBuffer *next;
+} GLParamBuffer;
+
+typedef struct GLList {
+  GLParamBuffer *first_op_buffer;
+  /* TODO: extensions for an hash table or a better allocating scheme */
+} GLList;
+
+typedef struct GLVertex {
+  int edge_flag;
+  V3 normal;
+  V4 coord;
+  V4 tex_coord;
+  V4 color;
+  
+  /* computed values */
+  V4 ec;                /* eye coordinates */
+  V4 pc;                /* coordinates in the normalized volume */
+  int clip_code;        /* clip code */
+  ZBufferPoint zp;      /* integer coordinates for the rasterization */
+} GLVertex;
+
+typedef struct GLImage {
+  void *pixmap;
+  int xsize,ysize;
+} GLImage;
+
+/* textures */
+
+#define TEXTURE_HASH_TABLE_SIZE 256
+
+typedef struct GLTexture {
+  GLImage images[MAX_TEXTURE_LEVELS];
+  int handle;
+  struct GLTexture *next,*prev;
+} GLTexture;
+
+
+/* shared state */
+
+typedef struct GLSharedState {
+  GLList **lists;
+  GLTexture **texture_hash_table;
+} GLSharedState;
+
+struct GLContext;
+
+typedef void (*gl_draw_triangle_func)(struct GLContext *c,
+                                      GLVertex *p0,GLVertex *p1,GLVertex *p2);
+
+/* display context */
+
+typedef struct GLContext {
+  /* Z buffer */
+  ZBuffer *zb;
+
+  /* lights */
+  GLLight lights[MAX_LIGHTS];
+  GLLight *first_light;
+  V4 ambient_light_model;
+  int local_light_model;
+  int lighting_enabled;
+  int light_model_two_side;
+
+  /* materials */
+  GLMaterial materials[2];
+  int color_material_enabled;
+  int current_color_material_mode;
+  int current_color_material_type;
+
+  /* textures */
+  GLTexture *current_texture;
+  int texture_2d_enabled;
+
+  /* shared state */
+  GLSharedState shared_state;
+
+  /* current list */
+  GLParamBuffer *current_op_buffer;
+  int current_op_buffer_index;
+  int exec_flag,compile_flag,print_flag;
+
+  /* matrix */
+
+  int matrix_mode;
+  M4 *matrix_stack[3];
+  M4 *matrix_stack_ptr[3];
+  int matrix_stack_depth_max[3];
+
+  M4 matrix_model_view_inv;
+  M4 matrix_model_projection;
+  int matrix_model_projection_updated;
+  int matrix_model_projection_no_w_transform; 
+  int apply_texture_matrix;
+
+  /* viewport */
+  GLViewport viewport;
+
+  /* current state */
+  int polygon_mode_back;
+  int polygon_mode_front;
+
+  int current_front_face;
+  int current_shade_model;
+  int current_cull_face;
+  int cull_face_enabled;
+  int normalize_enabled;
+  gl_draw_triangle_func draw_triangle_front,draw_triangle_back;
+
+  /* selection */
+  int render_mode;
+  unsigned int *select_buffer;
+  int select_size;
+  unsigned int *select_ptr,*select_hit;
+  int select_overflow;
+  int select_hits;
+
+  /* names */
+  unsigned int name_stack[MAX_NAME_STACK_DEPTH];
+  int name_stack_size;
+
+  /* clear */
+  float clear_depth;
+  V4 clear_color;
+
+  /* current vertex state */
+  V4 current_color;
+  unsigned int longcurrent_color[3]; /* precomputed integer color */
+  V4 current_normal;
+  V4 current_tex_coord;
+  int current_edge_flag;
+
+  /* glBegin / glEnd */
+  int in_begin;
+  int begin_type;
+  int vertex_n,vertex_cnt;
+  int vertex_max;
+  GLVertex *vertex;
+
+  /* opengl 1.1 arrays  */
+  float *vertex_array;
+  int vertex_array_size;
+  int vertex_array_stride;
+  float *normal_array;
+  int normal_array_stride;
+  float *color_array;
+  int color_array_size;
+  int color_array_stride;
+  float *texcoord_array;
+  int texcoord_array_size;
+  int texcoord_array_stride;
+  int client_states;
+  
+  /* opengl 1.1 polygon offset */
+  float offset_factor;
+  float offset_units;
+  int offset_states;
+  
+  /* specular buffer. could probably be shared between contexts, 
+    but that wouldn't be 100% thread safe */
+  GLSpecBuf *specbuf_first;
+  int specbuf_used_counter;
+  int specbuf_num_buffers;
+
+  /* opaque structure for user's use */
+  void *opaque;
+  /* resize viewport function */
+  int (*gl_resize_viewport)(struct GLContext *c,int *xsize,int *ysize);
+
+  /* depth test */
+  int depth_test;
+} GLContext;
+
+extern GLContext *gl_ctx;
+
+void gl_add_op(GLParam *p);
+
+/* clip.c */
+void gl_transform_to_viewport(GLContext *c,GLVertex *v);
+void gl_draw_triangle(GLContext *c,GLVertex *p0,GLVertex *p1,GLVertex *p2);
+void gl_draw_line(GLContext *c,GLVertex *p0,GLVertex *p1);
+void gl_draw_point(GLContext *c,GLVertex *p0);
+
+void gl_draw_triangle_point(GLContext *c,
+                            GLVertex *p0,GLVertex *p1,GLVertex *p2);
+void gl_draw_triangle_line(GLContext *c,
+                           GLVertex *p0,GLVertex *p1,GLVertex *p2);
+void gl_draw_triangle_fill(GLContext *c,
+                           GLVertex *p0,GLVertex *p1,GLVertex *p2);
+void gl_draw_triangle_select(GLContext *c,
+                             GLVertex *p0,GLVertex *p1,GLVertex *p2);
+
+/* matrix.c */
+void gl_print_matrix(const float *m);
+/*
+void glopLoadIdentity(GLContext *c,GLParam *p);
+void glopTranslate(GLContext *c,GLParam *p);*/
+
+/* light.c */
+void gl_add_select(GLContext *c,unsigned int zmin,unsigned int zmax);
+void gl_enable_disable_light(GLContext *c,int light,int v);
+void gl_shade_vertex(GLContext *c,GLVertex *v);
+
+void glInitTextures(GLContext *c);
+void glEndTextures(GLContext *c);
+GLTexture *alloc_texture(GLContext *c,int h);
+
+/* image_util.c */
+void gl_convertRGB_to_5R6G5B(unsigned short *pixmap,unsigned char *rgb,
+                             int xsize,int ysize);
+void gl_convertRGB_to_8A8R8G8B(unsigned int *pixmap, unsigned char *rgb,
+                               int xsize, int ysize);
+void gl_resizeImage(unsigned char *dest,int xsize_dest,int ysize_dest,
+                    unsigned char *src,int xsize_src,int ysize_src);
+void gl_resizeImageNoInterpolate(unsigned char *dest,int xsize_dest,int ysize_dest,
+                                 unsigned char *src,int xsize_src,int ysize_src);
+
+GLContext *gl_get_context(void);
+
+void gl_fatal_error(char *format, ...);
+
+
+/* specular buffer "api" */
+GLSpecBuf *specbuf_get_buffer(GLContext *c, const int shininess_i, 
+                              const float shininess);
+
+#ifdef __BEOS__
+void dprintf(const char *, ...);
+
+#else /* !BEOS */
+
+#ifdef DEBUG
+
+#define dprintf(format, args...)  \
+  fprintf(stderr,"In '%s': " format "\n",__FUNCTION__, ##args);
+
+#else
+
+#define dprintf(format, args...)
+
+#endif
+#endif /* !BEOS */
+
+/* glopXXX functions */
+
+#define ADD_OP(a,b,c) void glop ## a (GLContext *,GLParam *);
+#include "opinfo.h"
+
+/* this clip epsilon is needed to avoid some rounding errors after
+   several clipping stages */
+
+#define CLIP_EPSILON (1E-5)
+
+static inline int gl_clipcode(float x,float y,float z,float w1)
+{
+  float w;
+
+  w=w1 * (1.0 + CLIP_EPSILON);
+  return (x<-w) |
+    ((x>w)<<1) |
+    ((y<-w)<<2) |
+    ((y>w)<<3) |
+    ((z<-w)<<4) | 
+    ((z>w)<<5) ;
+}
+
+#endif /* _tgl_zgl_h_ */
--- /dev/null
+++ b/src/zline.c
@@ -1,0 +1,84 @@
+#include <stdlib.h>
+#include "zbuffer.h"
+
+#define ZCMP(z,zpix) ((z) >= (zpix))
+
+void ZB_plot(ZBuffer * zb, ZBufferPoint * p)
+{
+    unsigned short *pz;
+    PIXEL *pp;
+    int zz;
+
+    pz = zb->zbuf + (p->y * zb->xsize + p->x);
+    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;
+    }
+}
+
+#define INTERP_Z
+static void ZB_line_flat_z(ZBuffer * zb, ZBufferPoint * p1, ZBufferPoint * p2, 
+                           int color)
+{
+#include "zline.h"
+}
+
+/* line with color interpolation */
+#define INTERP_Z
+#define INTERP_RGB
+static void ZB_line_interp_z(ZBuffer * zb, ZBufferPoint * p1, ZBufferPoint * p2)
+{
+#include "zline.h"
+}
+
+/* no Z interpolation */
+
+static void ZB_line_flat(ZBuffer * zb, ZBufferPoint * p1, ZBufferPoint * p2, 
+                             int color)
+{
+#include "zline.h"
+}
+
+#define INTERP_RGB
+static void ZB_line_interp(ZBuffer * zb, ZBufferPoint * p1, ZBufferPoint * p2)
+{
+#include "zline.h"
+}
+
+void ZB_line_z(ZBuffer * zb, ZBufferPoint * p1, ZBufferPoint * p2)
+{
+    int color1, color2;
+
+    color1 = RGB_TO_PIXEL(p1->r, p1->g, p1->b);
+    color2 = RGB_TO_PIXEL(p2->r, p2->g, p2->b);
+
+    /* choose if the line should have its color interpolated or not */
+    if (color1 == color2) {
+        ZB_line_flat_z(zb, p1, p2, color1);
+    } else {
+        ZB_line_interp_z(zb, p1, p2);
+    }
+}
+
+void ZB_line(ZBuffer * zb, ZBufferPoint * p1, ZBufferPoint * p2)
+{
+    int color1, color2;
+
+    color1 = RGB_TO_PIXEL(p1->r, p1->g, p1->b);
+    color2 = RGB_TO_PIXEL(p2->r, p2->g, p2->b);
+
+    /* choose if the line should have its color interpolated or not */
+    if (color1 == color2) {
+        ZB_line_flat(zb, p1, p2, color1);
+    } else {
+        ZB_line_interp(zb, p1, p2);
+    }
+}
--- /dev/null
+++ b/src/zline.h
@@ -1,0 +1,121 @@
+{
+    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
+    register unsigned int r, g, b;
+#endif
+#ifdef INTERP_RGB
+    register unsigned int rinc, ginc, binc;
+#endif
+#ifdef INTERP_Z
+    register unsigned short *pz;
+    int zinc;
+    register int z, zz;
+#endif
+
+    if (p1->y > p2->y || (p1->y == p2->y && p1->x > p2->x)) {
+	ZBufferPoint *tmp;
+	tmp = p1;
+	p1 = p2;
+	p2 = tmp;
+    }
+    sx = zb->xsize;
+    pp = (PIXEL *) ((char *) zb->pbuf + zb->linesize * p1->y + p1->x * PSZB);
+#ifdef INTERP_Z
+    pz = zb->zbuf + (p1->y * sx + p1->x);
+    z = p1->z;
+#endif
+
+    dx = p2->x - p1->x;
+    dy = p2->y - p1->y;
+#ifdef INTERP_RGB
+    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
+#define ZZ(x) x
+#define PUTPIXEL() 				\
+  {						\
+    zz=z >> ZB_POINT_Z_FRAC_BITS;		\
+    if (ZCMP(zz,*pz))  { 			\
+      RGBPIXEL;	\
+      *pz=zz; 					\
+    }						\
+  }
+#else /* INTERP_Z */
+#define ZZ(x)
+#define PUTPIXEL() RGBPIXEL
+#endif /* INTERP_Z */
+
+#define DRAWLINE(dx,dy,inc_1,inc_2) \
+    n=dx;\
+    ZZ(zinc=(p2->z-p1->z)/n);\
+    RGB(rinc=((p2->r-p1->r) << 8)/n;\
+        ginc=((p2->g-p1->g) << 8)/n;\
+        binc=((p2->b-p1->b) << 8)/n);\
+    a=2*dy-dx;\
+    dy=2*dy;\
+    dx=2*dx-dy;\
+    pp_inc_1 = (inc_1) * PSZB;\
+    pp_inc_2 = (inc_2) * PSZB;\
+    do {\
+        PUTPIXEL();\
+        ZZ(z+=zinc);\
+        RGB(r+=rinc;g+=ginc;b+=binc);\
+        if (a>0) { pp=(PIXEL *)((char *)pp + pp_inc_1); ZZ(pz+=(inc_1));  a-=dx; }\
+	else { pp=(PIXEL *)((char *)pp + pp_inc_2); ZZ(pz+=(inc_2)); a+=dy; }\
+    } while (--n >= 0);
+
+/* fin macro */
+
+    if (dx == 0 && dy == 0) {
+	PUTPIXEL();
+    } else if (dx > 0) {
+	if (dx >= dy) {
+	    DRAWLINE(dx, dy, sx + 1, 1);
+	} else {
+	    DRAWLINE(dy, dx, sx + 1, sx);
+	}
+    } else {
+	dx = -dx;
+	if (dx >= dy) {
+	    DRAWLINE(dx, dy, sx - 1, -1);
+	} else {
+	    DRAWLINE(dy, dx, sx - 1, sx);
+	}
+    }
+}
+
+#undef INTERP_Z
+#undef INTERP_RGB
+
+/* internal defines */
+#undef DRAWLINE
+#undef PUTPIXEL
+#undef ZZ
+#undef RGB
+#undef RGBPIXEL 
--- /dev/null
+++ b/src/zmath.c
@@ -1,0 +1,275 @@
+/* Some simple mathematical functions. Don't look for some logic in
+   the function names :-) */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "zmath.h"
+
+
+/* ******* Gestion des matrices 4x4 ****** */
+
+void gl_M4_Id(M4 *a)
+{
+	int i,j;
+	for(i=0;i<4;i++)
+	for(j=0;j<4;j++) 
+	if (i==j) a->m[i][j]=1.0; else a->m[i][j]=0.0;
+}
+
+int gl_M4_IsId(M4 *a)
+{
+	int i,j;
+	for(i=0;i<4;i++)
+    for(j=0;j<4;j++) {
+      if (i==j) { 
+        if (a->m[i][j] != 1.0) return 0;
+      } else if (a->m[i][j] != 0.0) return 0;
+    }
+  return 1;
+}
+
+void gl_M4_Mul(M4 *c,M4 *a,M4 *b)
+{
+  int i,j,k;
+  float s;
+  for(i=0;i<4;i++)
+    for(j=0;j<4;j++) {
+      s=0.0;
+      for(k=0;k<4;k++) s+=a->m[i][k]*b->m[k][j];
+      c->m[i][j]=s;
+    }
+}
+
+/* c=c*a */
+void gl_M4_MulLeft(M4 *c,M4 *b)
+{
+  int i,j,k;
+  float s;
+  M4 a;
+
+  /*memcpy(&a, c, 16*sizeof(float));
+  */
+  a=*c;
+
+  for(i=0;i<4;i++)
+    for(j=0;j<4;j++) {
+      s=0.0;
+      for(k=0;k<4;k++) s+=a.m[i][k]*b->m[k][j];
+      c->m[i][j]=s;
+    }
+}
+
+void gl_M4_Move(M4 *a,M4 *b)
+{
+	memcpy(a,b,sizeof(M4));
+}
+
+void gl_MoveV3(V3 *a,V3 *b)
+{
+	memcpy(a,b,sizeof(V3));
+}
+
+
+void gl_MulM4V3(V3 *a,M4 *b,V3 *c)
+{
+	 a->X=b->m[0][0]*c->X+b->m[0][1]*c->Y+b->m[0][2]*c->Z+b->m[0][3];
+	 a->Y=b->m[1][0]*c->X+b->m[1][1]*c->Y+b->m[1][2]*c->Z+b->m[1][3];
+	 a->Z=b->m[2][0]*c->X+b->m[2][1]*c->Y+b->m[2][2]*c->Z+b->m[2][3];
+}
+
+void gl_MulM3V3(V3 *a,M4 *b,V3 *c)
+{
+	 a->X=b->m[0][0]*c->X+b->m[0][1]*c->Y+b->m[0][2]*c->Z;
+	 a->Y=b->m[1][0]*c->X+b->m[1][1]*c->Y+b->m[1][2]*c->Z;
+	 a->Z=b->m[2][0]*c->X+b->m[2][1]*c->Y+b->m[2][2]*c->Z;
+}
+
+void gl_M4_MulV4(V4 *a,M4 *b,V4 *c)
+{
+	 a->X=b->m[0][0]*c->X+b->m[0][1]*c->Y+b->m[0][2]*c->Z+b->m[0][3]*c->W;
+	 a->Y=b->m[1][0]*c->X+b->m[1][1]*c->Y+b->m[1][2]*c->Z+b->m[1][3]*c->W;
+	 a->Z=b->m[2][0]*c->X+b->m[2][1]*c->Y+b->m[2][2]*c->Z+b->m[2][3]*c->W;
+	 a->W=b->m[3][0]*c->X+b->m[3][1]*c->Y+b->m[3][2]*c->Z+b->m[3][3]*c->W;
+}
+	
+/* transposition of a 4x4 matrix */
+void gl_M4_Transpose(M4 *a,M4 *b)
+{
+  a->m[0][0]=b->m[0][0]; 
+  a->m[0][1]=b->m[1][0]; 
+  a->m[0][2]=b->m[2][0]; 
+  a->m[0][3]=b->m[3][0]; 
+
+  a->m[1][0]=b->m[0][1]; 
+  a->m[1][1]=b->m[1][1]; 
+  a->m[1][2]=b->m[2][1]; 
+  a->m[1][3]=b->m[3][1]; 
+
+  a->m[2][0]=b->m[0][2]; 
+  a->m[2][1]=b->m[1][2]; 
+  a->m[2][2]=b->m[2][2]; 
+  a->m[2][3]=b->m[3][2]; 
+
+  a->m[3][0]=b->m[0][3]; 
+  a->m[3][1]=b->m[1][3]; 
+  a->m[3][2]=b->m[2][3]; 
+  a->m[3][3]=b->m[3][3]; 
+}
+
+/* inversion of an orthogonal matrix of type Y=M.X+P */ 
+void gl_M4_InvOrtho(M4 *a,M4 b)
+{
+	int i,j;
+	float s;
+	for(i=0;i<3;i++)
+	for(j=0;j<3;j++) a->m[i][j]=b.m[j][i];
+	a->m[3][0]=0.0; a->m[3][1]=0.0; a->m[3][2]=0.0; a->m[3][3]=1.0;
+	for(i=0;i<3;i++) {
+		s=0;
+		for(j=0;j<3;j++) s-=b.m[j][i]*b.m[j][3];
+		a->m[i][3]=s;
+	}
+}
+
+/* Inversion of a general nxn matrix.
+   Note : m is destroyed */
+
+int Matrix_Inv(float *r,float *m,int n)
+{
+	 int i,j,k,l;
+	 float max,tmp,t;
+
+	 /* identit�e dans r */
+	 for(i=0;i<n*n;i++) r[i]=0;
+	 for(i=0;i<n;i++) r[i*n+i]=1;
+	 
+	 for(j=0;j<n;j++) {
+			
+			/* recherche du nombre de plus grand module sur la colonne j */
+			max=m[j*n+j];
+			k=j;
+			for(i=j+1;i<n;i++)
+				if (fabs(m[i*n+j])>fabs(max)) {
+					 k=i;
+					 max=m[i*n+j];
+				}
+
+      /* non intersible matrix */
+      if (max==0) return 1;
+
+			
+			/* permutation des lignes j et k */
+			if (k!=j) {
+				 for(i=0;i<n;i++) {
+						tmp=m[j*n+i];
+						m[j*n+i]=m[k*n+i];
+						m[k*n+i]=tmp;
+						
+						tmp=r[j*n+i];
+						r[j*n+i]=r[k*n+i];
+						r[k*n+i]=tmp;
+				 }
+			}
+			
+			/* multiplication de la ligne j par 1/max */
+			max=1/max;
+			for(i=0;i<n;i++) {
+				 m[j*n+i]*=max;
+				 r[j*n+i]*=max;
+			}
+			
+			
+			for(l=0;l<n;l++) if (l!=j) {
+				 t=m[l*n+j];
+				 for(i=0;i<n;i++) {
+						m[l*n+i]-=m[j*n+i]*t;
+						r[l*n+i]-=r[j*n+i]*t;
+				 }
+			}
+	 }
+
+	 return 0;
+}
+
+
+/* inversion of a 4x4 matrix */
+
+void gl_M4_Inv(M4 *a,M4 *b)
+{
+  M4 tmp;
+  memcpy(&tmp, b, 16*sizeof(float));
+  /*tmp=*b;*/
+  Matrix_Inv(&a->m[0][0],&tmp.m[0][0],4);
+}
+
+void gl_M4_Rotate(M4 *a,float t,int u)
+{
+	 float s,c;
+	 int v,w;
+   if ((v=u+1)>2) v=0;
+	 if ((w=v+1)>2) w=0;
+	 s=sin(t);
+	 c=cos(t);
+	 gl_M4_Id(a);
+	 a->m[v][v]=c;	a->m[v][w]=-s;
+	 a->m[w][v]=s;	a->m[w][w]=c;
+}
+	
+
+/* inverse of a 3x3 matrix */
+void gl_M3_Inv(M3 *a,M3 *m)
+{
+	 float det;
+	 
+	 det = m->m[0][0]*m->m[1][1]*m->m[2][2]-m->m[0][0]*m->m[1][2]*m->m[2][1]-
+		 m->m[1][0]*m->m[0][1]*m->m[2][2]+m->m[1][0]*m->m[0][2]*m->m[2][1]+
+		 m->m[2][0]*m->m[0][1]*m->m[1][2]-m->m[2][0]*m->m[0][2]*m->m[1][1];
+
+	 a->m[0][0] = (m->m[1][1]*m->m[2][2]-m->m[1][2]*m->m[2][1])/det;
+	 a->m[0][1] = -(m->m[0][1]*m->m[2][2]-m->m[0][2]*m->m[2][1])/det;
+	 a->m[0][2] = -(-m->m[0][1]*m->m[1][2]+m->m[0][2]*m->m[1][1])/det;
+	 
+	 a->m[1][0] = -(m->m[1][0]*m->m[2][2]-m->m[1][2]*m->m[2][0])/det;
+	 a->m[1][1] = (m->m[0][0]*m->m[2][2]-m->m[0][2]*m->m[2][0])/det;
+	 a->m[1][2] = -(m->m[0][0]*m->m[1][2]-m->m[0][2]*m->m[1][0])/det;
+
+	 a->m[2][0] = (m->m[1][0]*m->m[2][1]-m->m[1][1]*m->m[2][0])/det;
+	 a->m[2][1] = -(m->m[0][0]*m->m[2][1]-m->m[0][1]*m->m[2][0])/det;
+	 a->m[2][2] = (m->m[0][0]*m->m[1][1]-m->m[0][1]*m->m[1][0])/det;
+}
+
+																										
+/* vector arithmetic */
+
+int gl_V3_Norm(V3 *a)
+{
+	float n;
+	n=sqrt(a->X*a->X+a->Y*a->Y+a->Z*a->Z);
+	if (n==0) return 1;
+	a->X/=n;
+	a->Y/=n;
+	a->Z/=n;
+	return 0;
+}
+
+V3 gl_V3_New(float x,float y,float z)
+{
+	 V3 a;
+	 a.X=x;
+	 a.Y=y;
+	 a.Z=z;
+	 return a;
+}
+
+V4 gl_V4_New(float x,float y,float z,float w)
+{
+  V4 a;
+  a.X=x;
+  a.Y=y;
+  a.Z=z;
+  a.W=w;
+  return a;
+}
+
+
--- /dev/null
+++ b/src/zmath.h
@@ -1,0 +1,54 @@
+#ifndef __ZMATH__
+#define __ZMATH__
+
+/* Matrix & Vertex */
+
+typedef struct {
+	float m[4][4];
+} M4;
+
+typedef struct {
+	float m[3][3];
+} M3;
+
+typedef struct {
+	 float m[3][4];
+} M34;
+
+
+#define X v[0]
+#define Y v[1]
+#define Z v[2]
+#define W v[3]
+
+typedef struct {
+	 float v[3];
+} V3;
+
+typedef struct {
+	 float v[4];
+} V4;
+	
+void gl_M4_Id(M4 *a);
+int gl_M4_IsId(M4 *a);
+void gl_M4_Move(M4 *a,M4 *b);
+void gl_MoveV3(V3 *a,V3 *b);
+void gl_MulM4V3(V3 *a,M4 *b,V3 *c);
+void gl_MulM3V3(V3 *a,M4 *b,V3 *c);
+
+void gl_M4_MulV4(V4 * a,M4 *b,V4 * c);
+void gl_M4_InvOrtho(M4 *a,M4 b);
+void gl_M4_Inv(M4 *a,M4 *b);
+void gl_M4_Mul(M4 *c,M4 *a,M4 *b);
+void gl_M4_MulLeft(M4 *c,M4 *a);
+void gl_M4_Transpose(M4 *a,M4 *b);
+void gl_M4_Rotate(M4 *c,float t,int u);
+int  gl_V3_Norm(V3 *a);
+
+V3 gl_V3_New(float x,float y,float z);
+V4 gl_V4_New(float x,float y,float z,float w);
+
+int gl_Matrix_Inv(float *r,float *m,int n);
+
+#endif
+// __ZMATH__ 
--- /dev/null
+++ b/src/ztriangle.c
@@ -1,0 +1,409 @@
+#include <stdlib.h>
+#include "zbuffer.h"
+#if TGL_FEATURE_RENDER_BITS == 32
+#define THE_X (((unsigned short)(pp-pp1)))
+#elif TGL_FEATURE_RENDER_BITS == 16
+#define THE_X (((unsigned short)(pp-pp1)))
+#elif TGL_FEATURE_RENDER_BITS == 8
+#define THE_X (((unsigned short)pp)-(unsigned short)pp1)
+#else
+#error "24 bit mode is not supported in this port. Use 16 or 32 bit modes."
+#endif
+#define XSTIP(_a) ((THE_X+_a)& 31)
+#define YSTIP (the_y & 31)
+#define STIPBIT(_a) (zb->stipplepattern[(XSTIP(_a) + (YSTIP<<5))>>3] & (1<<(XSTIP(_a) & 7)))
+#define STIPTEST(_a) !(zb->dostipple && !STIPBIT(_a))
+#if TGL_FEATURE_POLYGON_STIPPLE
+#define ZCMP(z,zpix,_a) ((z) >= (zpix) && STIPTEST(_a))
+#else
+#define ZCMP(z,zpix,_a) ((z) >= (zpix))
+#endif
+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);	\
+}
+  
+#define PUT_PIXEL(_a)				\
+{						\
+    zz=z >> ZB_POINT_Z_FRAC_BITS;		\
+    if (ZCMP(zz,pz[_a],_a)) {				\
+      pp[_a]=color;				\
+      pz[_a]=zz;				\
+    }						\
+    z+=dzdx;					\
+}
+#endif /* TGL_FEATURE_RENDER_BITS == 24 */
+
+#include "ztriangle.h"
+}
+
+/*
+ * Smooth filled triangle.
+ * The code below is very tricky :)
+ */
+
+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],_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],_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);/*the_x++;*/							   \
+    PUT_PIXEL(1);/*the_x++;*/							   \
+    PUT_PIXEL(2);/*the_x++;*/							   \
+    PUT_PIXEL(3);/*the_x++;*/							   \
+    pz+=4;								   \
+    pp+=4;								   \
+    n-=4;								   \
+  }									   \
+  while (n>=0) {							   \
+    PUT_PIXEL(0);/*the_x++;*/						   \
+    pz+=1;								   \
+    pp+=1;								   \
+    n-=1;								   \
+  }									   \
+}
+
+#else
+
+#define DRAW_INIT() 				\
+{						\
+}
+
+#define PUT_PIXEL(_a)				\
+{						\
+    zz=z >> ZB_POINT_Z_FRAC_BITS;		\
+    if (ZCMP(zz,pz[_a],_a)) {				\
+      pp[_a] = RGB_TO_PIXEL(or1, og1, ob1);\
+      pz[_a]=zz;				\
+    }\
+    z+=dzdx;					\
+    og1+=dgdx;					\
+    or1+=drdx;					\
+    ob1+=dbdx;					\
+}
+
+#endif /* TGL_FEATURE_RENDER_BITS */
+
+#include "ztriangle.h"
+} //EOF smooth fill triangle
+
+void ZB_setTexture(ZBuffer *zb,PIXEL *texture)
+{
+    zb->current_texture=texture;
+}
+//Ignore this it is never used
+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;			\
+}
+
+#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],_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;		\
+     if (ZCMP(zz,pz[_a],_a)) {				\
+       pp[_a]=texture[((t & 0x3FC00000) | s) >> 14];	\
+       pz[_a]=zz;				\
+    }						\
+    z+=dzdx;					\
+    s+=dsdx;					\
+    t+=dtdx;					\
+}
+
+#endif
+
+#include "ztriangle.h"
+}
+
+/*
+ * Texture mapping with perspective correction.
+ * 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)
+{
+    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;\
+}
+
+
+#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],_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;		\
+     if (ZCMP(zz,pz[_a],_a)) {				\
+       pp[_a]=*(PIXEL *)((char *)texture+ \
+               (((t & 0x3FC00000) | (s & 0x003FC000)) >> (17 - PSZSH)));\
+       pz[_a]=zz;				\
+    }						\
+    z+=dzdx;					\
+    s+=dsdx;					\
+    t+=dtdx;					\
+}
+
+#endif
+
+#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);/*the_x++;*/		   \
+    PUT_PIXEL(1);/*the_x++;*/		   \
+    PUT_PIXEL(2);/*the_x++;*/		   \
+    PUT_PIXEL(3);/*the_x++;*/		   \
+    PUT_PIXEL(4);/*the_x++;*/		   \
+    PUT_PIXEL(5);/*the_x++;*/		   \
+    PUT_PIXEL(6);/*the_x++;*/		   \
+    PUT_PIXEL(7);/*the_x-=7;*/		   \
+    pz+=NB_INTERP;							   \
+    pp=(PIXEL *)((char *)pp + NB_INTERP * PSZB);/*the_x+=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);/*the_x += PSZB;*/			   \
+    pz+=1;								   \
+    pp=(PIXEL *)((char *)pp + PSZB);\
+    n-=1;								   \
+  }									   \
+}
+  
+#include "ztriangle.h"
+}
+
+#endif
+
+#if 0
+
+/* slow but exact version (only there for reference, incorrect for 24
+   bits) */
+
+void ZB_fillTriangleMappingPerspective(ZBuffer *zb,
+                            ZBufferPoint *p0,ZBufferPoint *p1,ZBufferPoint *p2)
+{
+    PIXEL *texture;
+
+#define INTERP_Z
+#define INTERP_STZ
+
+#define DRAW_INIT()				\
+{						\
+  texture=zb->current_texture;			\
+}
+
+#define PUT_PIXEL(_a)				\
+{						\
+   float zinv; \
+   int s,t; \
+   zz=z >> ZB_POINT_Z_FRAC_BITS;		\
+     if (ZCMP(zz,pz[_a],_a)) {				\
+       zinv= 1.0 / (float) z; \
+       s= (int) (sz * zinv); \
+       t= (int) (tz * zinv); \
+       pp[_a]=texture[((t & 0x3FC00000) | s) >> 14];	\
+       pz[_a]=zz;				\
+    }						\
+    z+=dzdx;					\
+    sz+=dszdx;					\
+    tz+=dtzdx;					\
+}
+
+#include "ztriangle.h"
+}
+
+
+#endif
--- /dev/null
+++ b/src/ztriangle.h
@@ -1,0 +1,367 @@
+/*
+ * We draw a triangle with various interpolations
+ */
+
+{
+  ZBufferPoint *t,*pr1,*pr2,*l1,*l2;
+  float fdx1, fdx2, fdy1, fdy2, fz, d1, d2;
+  unsigned short *pz1;
+  PIXEL *pp1;
+  int part,update_left,update_right;
+
+  int nb_lines,dx1,dy1,tmp,dx2,dy2;
+  unsigned short the_y;
+
+  int error,derror;
+  int x1,dxdy_min,dxdy_max;
+/* warning: x2 is multiplied by 2^16 */
+  int x2,dx2dy2;  
+
+#ifdef INTERP_Z
+  int z1,dzdx,dzdy,dzdl_min,dzdl_max;
+#endif
+#ifdef INTERP_RGB
+  int r1,drdx,drdy,drdl_min,drdl_max;
+  int g1,dgdx,dgdy,dgdl_min,dgdl_max;
+  int b1,dbdx,dbdy,dbdl_min,dbdl_max;
+#endif
+#ifdef INTERP_ST
+  int s1,dsdx,dsdy,dsdl_min,dsdl_max;
+  int t1,dtdx,dtdy,dtdl_min,dtdl_max;
+#endif
+#ifdef INTERP_STZ
+  float sz1,dszdx,dszdy,dszdl_min,dszdl_max;
+  float tz1,dtzdx,dtzdy,dtzdl_min,dtzdl_max;
+#endif
+
+  /* we sort the vertex with increasing y */
+  if (p1->y < p0->y) {
+    t = p0;
+    p0 = p1;
+    p1 = t;
+  }
+  if (p2->y < p0->y) {
+    t = p2;
+    p2 = p1;
+    p1 = p0;
+    p0 = t;
+  } else if (p2->y < p1->y) {
+    t = p1;
+    p1 = p2;
+    p2 = t;
+  }
+
+  /* we compute dXdx and dXdy for all interpolated values */
+  
+  fdx1 = p1->x - p0->x;
+  fdy1 = p1->y - p0->y;
+
+  fdx2 = p2->x - p0->x;
+  fdy2 = p2->y - p0->y;
+
+  fz = fdx1 * fdy2 - fdx2 * fdy1;
+  if (fz == 0)
+    return;
+  fz = 1.0 / fz;
+
+  fdx1 *= fz;
+  fdy1 *= fz;
+  fdx2 *= fz;
+  fdy2 *= fz;
+
+#ifdef INTERP_Z
+  d1 = p1->z - p0->z;
+  d2 = p2->z - p0->z;
+  dzdx = (int) (fdy2 * d1 - fdy1 * d2);
+  dzdy = (int) (fdx1 * d2 - fdx2 * d1);
+#endif
+
+#ifdef INTERP_RGB
+  d1 = p1->r - p0->r;
+  d2 = p2->r - p0->r;
+  drdx = (int) (fdy2 * d1 - fdy1 * d2);
+  drdy = (int) (fdx1 * d2 - fdx2 * d1);
+
+  d1 = p1->g - p0->g;
+  d2 = p2->g - p0->g;
+  dgdx = (int) (fdy2 * d1 - fdy1 * d2);
+  dgdy = (int) (fdx1 * d2 - fdx2 * d1);
+
+  d1 = p1->b - p0->b;
+  d2 = p2->b - p0->b;
+  dbdx = (int) (fdy2 * d1 - fdy1 * d2);
+  dbdy = (int) (fdx1 * d2 - fdx2 * d1);
+
+#endif
+  
+#ifdef INTERP_ST
+  d1 = p1->s - p0->s;
+  d2 = p2->s - p0->s;
+  dsdx = (int) (fdy2 * d1 - fdy1 * d2);
+  dsdy = (int) (fdx1 * d2 - fdx2 * d1);
+  
+  d1 = p1->t - p0->t;
+  d2 = p2->t - p0->t;
+  dtdx = (int) (fdy2 * d1 - fdy1 * d2);
+  dtdy = (int) (fdx1 * d2 - fdx2 * d1);
+#endif
+
+#ifdef INTERP_STZ
+  {
+    float zz;
+    zz=(float) p0->z;
+    p0->sz= (float) p0->s * zz;
+    p0->tz= (float) p0->t * zz;
+    zz=(float) p1->z;
+    p1->sz= (float) p1->s * zz;
+    p1->tz= (float) p1->t * zz;
+    zz=(float) p2->z;
+    p2->sz= (float) p2->s * zz;
+    p2->tz= (float) p2->t * zz;
+
+    d1 = p1->sz - p0->sz;
+    d2 = p2->sz - p0->sz;
+    dszdx = (fdy2 * d1 - fdy1 * d2);
+    dszdy = (fdx1 * d2 - fdx2 * d1);
+    
+    d1 = p1->tz - p0->tz;
+    d2 = p2->tz - p0->tz;
+    dtzdx = (fdy2 * d1 - fdy1 * d2);
+    dtzdy = (fdx1 * d2 - fdx2 * d1);
+  }
+#endif
+
+  /* screen coordinates */
+
+  pp1 = (PIXEL *) ((char *) zb->pbuf + zb->linesize * p0->y); 
+  the_y = p0->y;
+  pz1 = zb->zbuf + p0->y * zb->xsize;
+
+  DRAW_INIT();
+
+  for(part=0;part<2;part++) {
+    if (part == 0) {
+      if (fz > 0) {
+	update_left=1;
+	update_right=1;
+	l1=p0;
+	l2=p2;
+	pr1=p0;
+	pr2=p1;
+      } else {
+	update_left=1;
+	update_right=1;
+	l1=p0;
+	l2=p1;
+	pr1=p0;
+	pr2=p2;
+      }
+      nb_lines = p1->y - p0->y;
+    } else {
+      /* second part */
+      if (fz > 0) {
+	update_left=0;
+	update_right=1;
+	pr1=p1;
+	pr2=p2;
+      } else {
+	update_left=1;
+	update_right=0;
+	l1=p1; 
+	l2=p2;
+      }
+      nb_lines = p2->y - p1->y + 1;
+    }
+
+    /* compute the values for the left edge */
+
+    if (update_left) {
+      dy1 = l2->y - l1->y;
+      dx1 = l2->x - l1->x;
+      if (dy1 > 0) 
+	tmp = (dx1 << 16) / dy1;
+      else
+	tmp = 0;
+      x1 = l1->x;
+      error = 0;
+      derror = tmp & 0x0000ffff;
+      dxdy_min = tmp >> 16;
+      dxdy_max = dxdy_min + 1;
+      
+#ifdef INTERP_Z
+      z1=l1->z;
+      dzdl_min=(dzdy + dzdx * dxdy_min); 
+      dzdl_max=dzdl_min + dzdx;
+#endif
+#ifdef INTERP_RGB
+      r1=l1->r;
+      drdl_min=(drdy + drdx * dxdy_min);
+      drdl_max=drdl_min + drdx;
+      
+      g1=l1->g;
+      dgdl_min=(dgdy + dgdx * dxdy_min);
+      dgdl_max=dgdl_min + dgdx;
+      
+      b1=l1->b;
+      dbdl_min=(dbdy + dbdx * dxdy_min);
+      dbdl_max=dbdl_min + dbdx;
+#endif
+#ifdef INTERP_ST
+      s1=l1->s;
+      dsdl_min=(dsdy + dsdx * dxdy_min);
+      dsdl_max=dsdl_min + dsdx;
+      
+      t1=l1->t;
+      dtdl_min=(dtdy + dtdx * dxdy_min);
+      dtdl_max=dtdl_min + dtdx;
+#endif
+#ifdef INTERP_STZ
+      sz1=l1->sz;
+      dszdl_min=(dszdy + dszdx * dxdy_min);
+      dszdl_max=dszdl_min + dszdx;
+      
+      tz1=l1->tz;
+      dtzdl_min=(dtzdy + dtzdx * dxdy_min);
+      dtzdl_max=dtzdl_min + dtzdx;
+#endif
+    }
+
+    /* compute values for the right edge */
+
+    if (update_right) {
+      dx2 = (pr2->x - pr1->x);
+      dy2 = (pr2->y - pr1->y);
+      if (dy2>0) 
+	dx2dy2 = ( dx2 << 16) / dy2;
+      else
+	dx2dy2 = 0;
+      x2 = pr1->x << 16;
+    }
+
+    /* we draw all the scan line of the part */
+
+    while (nb_lines>0) {
+      nb_lines--;
+#ifndef DRAW_LINE
+      /* generic draw line */
+      {
+          register PIXEL *pp;
+          register int n;
+#ifdef INTERP_Z
+          register unsigned short *pz;
+          register unsigned int z,zz;
+#endif
+#ifdef INTERP_RGB
+          register unsigned int or1,og1,ob1;
+#endif
+#ifdef INTERP_ST
+          register unsigned int s,t;
+#endif
+#ifdef INTERP_STZ
+          float sz,tz;
+#endif
+
+          n=(x2 >> 16) - x1;
+          /*the_x = x1; //Gek added this to make determining the X coordinate easier!*/
+          pp=(PIXEL *)((char *)pp1 + x1 * PSZB);
+#ifdef INTERP_Z
+          pz=pz1+x1;
+          z=z1;
+#endif
+#ifdef INTERP_RGB
+          or1 = r1;
+          og1 = g1;
+          ob1 = b1;
+#endif
+#ifdef INTERP_ST
+          s=s1;
+          t=t1;
+#endif
+#ifdef INTERP_STZ
+          sz=sz1;
+          tz=tz1;
+#endif
+          while (n>=3) {
+              PUT_PIXEL(0);/*the_x++;*/
+              PUT_PIXEL(1);/*the_x++;*/
+              PUT_PIXEL(2);/*the_x++;*/
+              PUT_PIXEL(3);/*the_x++;*/
+#ifdef INTERP_Z
+              pz+=4;
+#endif
+              pp=(PIXEL *)((char *)pp + 4 * PSZB);
+              n-=4;
+          }
+          while (n>=0) {
+              PUT_PIXEL(0);/*the_x++;*/
+#ifdef INTERP_Z
+              pz+=1;
+#endif
+              pp=(PIXEL *)((char *)pp + PSZB);
+              n-=1;
+          }
+      }//the_y++;
+#else
+      DRAW_LINE();//the_y++;
+#endif
+      
+      /* left edge */
+      error+=derror;
+      if (error > 0) {
+	error-=0x10000;
+	x1+=dxdy_max;
+#ifdef INTERP_Z
+	z1+=dzdl_max;
+#endif      
+#ifdef INTERP_RGB
+	r1+=drdl_max;
+	g1+=dgdl_max;
+	b1+=dbdl_max;
+#endif
+#ifdef INTERP_ST
+	s1+=dsdl_max;
+	t1+=dtdl_max;
+#endif
+#ifdef INTERP_STZ
+	sz1+=dszdl_max;
+	tz1+=dtzdl_max;
+#endif
+      } else {
+	x1+=dxdy_min;
+#ifdef INTERP_Z
+	z1+=dzdl_min;
+#endif      
+#ifdef INTERP_RGB
+	r1+=drdl_min;
+	g1+=dgdl_min;
+	b1+=dbdl_min;
+#endif
+#ifdef INTERP_ST
+	s1+=dsdl_min;
+	t1+=dtdl_min;
+#endif
+#ifdef INTERP_STZ
+	sz1+=dszdl_min;
+	tz1+=dtzdl_min;
+#endif
+      } 
+      
+      /* right edge */
+      x2+=dx2dy2;
+
+      /* screen coordinates */
+      pp1=(PIXEL *)((char *)pp1 + zb->linesize);
+      the_y++;
+      pz1+=zb->xsize;
+    }
+  }
+}
+
+#undef INTERP_Z
+#undef INTERP_RGB
+#undef INTERP_ST
+#undef INTERP_STZ
+
+#undef DRAW_INIT
+#undef DRAW_LINE  
+#undef PUT_PIXEL