])
 
     def call_function(self, function):
-        if (function.name in self.draw_array_function_names or 
-            function.name in self.draw_elements_function_names):
+        if function.name in self.draw_elements_function_names:
             print '    GLint __array_buffer = 0;'
             print '    glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &__array_buffer);'
             print '    if (!__array_buffer) {'
 
     pointer_function_names = set([
         "glColorPointer",
-        "glColorPointerEXT",
+        #"glColorPointerEXT",
         "glEdgeFlagPointer",
-        "glEdgeFlagPointerEXT",
+        #"glEdgeFlagPointerEXT",
         "glFogCoordPointer",
-        "glFogCoordPointerEXT",
+        #"glFogCoordPointerEXT",
         "glIndexPointer",
-        "glIndexPointerEXT",
-        "glMatrixIndexPointerARB",
+        #"glIndexPointerEXT",
+        #"glMatrixIndexPointerARB",
         "glNormalPointer",
-        "glNormalPointerEXT",
+        #"glNormalPointerEXT",
         "glSecondaryColorPointer",
-        "glSecondaryColorPointerEXT",
+        #"glSecondaryColorPointerEXT",
         "glTexCoordPointer",
-        "glTexCoordPointerEXT",
-        "glVertexAttribLPointer",
-        "glVertexAttribPointer",
-        "glVertexAttribPointerARB",
-        "glVertexAttribPointerNV",
+        #"glTexCoordPointerEXT",
+        #"glVertexAttribLPointer",
+        #"glVertexAttribPointer",
+        #"glVertexAttribPointerARB",
+        #"glVertexAttribPointerNV",
         "glVertexPointer",
-        "glVertexPointerEXT",
+        #"glVertexPointerEXT",
     ])
 
     def extract_arg(self, function, arg, arg_type, lvalue, rvalue):
-        if (function.name in self.pointer_function_names and arg.name == 'pointer' or
-            function.name in self.draw_elements_function_names and arg.name == 'indices'):
+        if function.name in self.pointer_function_names and arg.name == 'pointer':
+            print '    %s = dynamic_cast<void *>(&%s);' % (lvalue, rvalue)
+            return
+
+        if function.name in self.draw_elements_function_names and arg.name == 'indices':
             print '    if (dynamic_cast<Trace::Null *>(&%s)) {' % rvalue
             print '        %s = 0;' % (lvalue)
             print '    } else {'
 
 
 class GlTracer(Tracer):
 
+    def header(self, api):
+        Tracer.header(self, api)
+        self.state_tracker_decl(api)
+
+    def footer(self, api):
+        Tracer.footer(self, api)
+        self.state_tracker_impl(api)
+
+    array_names = {
+        "VERTEX": "glVertexPointer",
+        "NORMAL": "glNormalPointer",
+        "COLOR": "glColorPointer",
+        "INDEX": "glIndexPointer",
+        "TEX_COORD": "glTexCoordPointer",
+        "EDGE_FLAG": "glEdgeFlagPointer",
+        "FOG_COORD": "glFogCoordPointer",
+        "SECONDARY_COLOR": "glSecondaryColorPointer",
+    }
+
     pointer_function_names = {
-        "glVertexPointer": "VertexPointer",
-        "glVertexPointerEXT": "VertexPointer",
-        "glNormalPointer": "NormalPointer",
-        "glNormalPointerEXT": "NormalPointer",
-        "glColorPointer": "ColorPointer",
-        "glColorPointerEXT": "ColorPointer",
-        "glIndexPointer": "IndexPointer",
-        "glIndexPointerEXT": "IndexPointer",
-        "glTexCoordPointer": "TexCoordPointer",
-        "glTexCoordPointerEXT": "TexCoordPointer",
-        "glEdgeFlagPointer": "EdgeFlagPointer",
-        "glEdgeFlagPointerEXT": "EdgeFlagPointer",
-        "glFogCoordPointer": "FogCoordPointer",
-        "glFogCoordPointerEXT": "FogCoordPointer",
-        "glSecondaryColorPointer": "SecondaryColorPointer",
-        "glSecondaryColorPointerEXT": "SecondaryColorPointer",
-        "glInterleavedArrays": "InterleavedArrays",
+        "glVertexPointer": "VERTEX",
+        "glNormalPointer": "NORMAL",
+        "glColorPointer": "COLOR",
+        "glIndexPointer": "INDEX",
+        "glTexCoordPointer": "TEX_COORD",
+        "glEdgeFlagPointer": "EDGE_FLAG",
+        "glFogCoordPointer": "FOG_COORD",
+        "glSecondaryColorPointer": "SECONDARY_COLOR",
+        #"glInterleavedArrays": ("InterleavedArrays", None)
+        #"glVertexPointerEXT": "VERTEX",
+        #"glNormalPointerEXT": "NORMAL",
+        #"glColorPointerEXT": "COLOR",
+        #"glIndexPointerEXT": "INDEX",
+        #"glTexCoordPointerEXT": "TEX_COORD",
+        #"glEdgeFlagPointerEXT": "EDGE_FLAG",
+        #"glFogCoordPointerEXT": "FOG_COORD",
+        #"glSecondaryColorPointerEXT": "SECONDARY_COLOR",
 
         #"glVertexAttribPointer": "VertexAttribPointer",
         #"glVertexAttribPointerARB": "VertexAttribPointer",
         #"glMatrixIndexPointerARB": "MatrixIndexPointer",
     }
 
-    def header(self, api):
-        Tracer.header(self, api)
-        self.state_tracker_decl(api)
-
-    def footer(self, api):
-        Tracer.footer(self, api)
-        self.state_tracker_impl(api)
+    bind_buffer_enums = [
+        'ARRAY_BUFFER',
+        'ELEMENT_ARRAY_BUFFER',
+        'PIXEL_PACK_BUFFER',
+        'PIXEL_UNPACK_BUFFER',
+    ]
+
+    client_state_enums = [
+         'COLOR_ARRAY',
+         'EDGE_FLAG_ARRAY', 
+         'FOG_COORD_ARRAY', 
+         'INDEX_ARRAY', 
+         'NORMAL_ARRAY', 
+         'SECONDARY_COLOR_ARRAY', 
+         'TEXTURE_COORD_ARRAY', 
+         'VERTEX_ARRAY',
+    ]
 
     def state_tracker_decl(self, api):
         # A simple state tracker to track the pointer values
 
-        atoms = list(set(self.pointer_function_names.itervalues()))
-        atoms.sort()
-
         # define the NEW_XXXX dirty flags
-        for i in range(len(atoms)):
-            atom = atoms[i]
-            dirtyflag = "NEW_%s" % atom.upper()
-            print '#define %s 0x%x' % (dirtyflag, 1 << i)
+        value = 1
+        for array_name in self.array_names.iterkeys():
+            dirtyflag = "NEW_%s" % array_name.upper()
+            print '#define %s 0x%x' % (dirtyflag, value)
+            value <<= 1
         print
 
         # declare the state structure
         print 'struct {'
-        for atom in atoms:
-            function = api.get_function_by_name('gl%s' % atom)
+        for enum in self.bind_buffer_enums:
+            print '    GLuint %s;' % (enum.lower(),)
+        for enum in self.client_state_enums:
+            print '    GLboolean %s;' % (enum.lower(),)
+        for array_name, function_name in self.array_names.iteritems():
+            function = api.get_function_by_name(function_name)
             print '    struct {'
             for arg in function.args:
                 print '        %s %s;' % (arg.type, arg.name)
-            print '    } %s;' % atom
+            print '    } %s;' % array_name.lower()
         print '    unsigned dirty;'
         print '} __state;'
         print
+        print 'static void __state_update(GLsizei maxIndex);'
+        print
+    
+    def trace_function_impl_body(self, function):
+        # Track bound VBOs
+        if function.name in ('glBindBuffer', 'glBindBufferARB'):
+            print '    switch(%s) {' % function.args[0].name
+            for enum in self.bind_buffer_enums:
+                print '    case GL_%s:' % enum
+                print '        __state.%s = %s;' % (enum.lower(), function.args[1].name)
+                print '        break;'
+            print '    }'
+
+        # Track enabled arrays
+        if function.name == 'glEnableClientState':
+            print '    switch(%s) {' % function.args[0].name
+            for enum in self.client_state_enums:
+                print '    case GL_%s:' % enum
+                print '        __state.%s = GL_TRUE;' % (enum.lower(),)
+                print '        break;'
+            print '    }'
+        if function.name == 'glDisableClientState':
+            print '    switch(%s) {' % function.args[0].name
+            for enum in self.client_state_enums:
+                print '    case GL_%s:' % enum
+                print '        __state.%s = GL_FALSE;' % (enum.lower(),)
+                print '        break;'
+            print '    }'
+
+        # Track array pointers
+        if function.name in self.pointer_function_names:
+            array_name = self.pointer_function_names[function.name]
+            dirtyflag = "NEW_%s" % array_name.upper()
+            for arg in function.args:
+                assert not arg.output
+                print '    __state.%s.%s = %s;' % (array_name.lower(), arg.name, arg.name)
+            print '    __state.dirty |= %s; ' % dirtyflag
+
+            # Defer tracing
+            self.dispatch_function(function)
+            return
+
+        if function.name == 'glDrawArrays':
+            print '   __state_update(first + count - 1);'
+        
+        Tracer.trace_function_impl_body(self, function)
 
     def state_tracker_impl(self, api):
         # A simple state tracker to track the pointer values
 
-        atoms = list(set(self.pointer_function_names.itervalues()))
-        atoms.sort()
-
         # update the state
-        print 'void __state_update(GLsizei )'
+        print 'static void __state_update(GLsizei maxIndex)'
         print '{'
         print '    GLint __array_buffer = 0;'
-        print '    glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &__array_buffer);'
-        for atom in atoms:
-            function = api.get_function_by_name('gl%s' % atom)
-            dirtyflag = "NEW_%s" % atom.upper()
-            print '    if (__state.dirty & %s) {' % dirtyflag
+        print '    __glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &__array_buffer);'
+        for array_name, function_name in self.array_names.iteritems():
+            function = api.get_function_by_name(function_name)
+            dirtyflag = "NEW_%s" % array_name.upper()
+            if array_name == 'TEX_COORD':
+                enableflag = 'TEXTURE_COORD_ARRAY'.lower()
+            else:
+                enableflag = '%s_array' % array_name.lower()
+            print '    if (__state.%s && (__state.dirty & %s)) {' % (enableflag, dirtyflag)
             print '        unsigned __call = Trace::BeginEnter(__%s_sig);' % (function.name,)
             for arg in function.args:
                 assert not arg.output
+                value = '__state.%s.%s' % (array_name.lower(), arg.name)
                 print '        Trace::BeginArg(%u);' % (arg.index,)
-                dump_instance(arg.type, '__state.%s.%s' % (atom, arg.name))
-                print '        Trace::EndArg();'
+                if arg.name != 'pointer':
+                    dump_instance(arg.type, value)
+                else:
+                    print '        if (__state.array_buffer) {'
+                    print '            Trace::LiteralOpaque((const void *)%s);' % value
+                    print '            __state.dirty &= ~%s;' % dirtyflag
+                    print '        } else {'
+                    if array_name in ('INDEX', 'EDGE_FLAG', 'FOG_COORD'):
+                        size = '1'
+                    elif array_name == 'NORMAL':
+                        size = '3'
+                    else:
+                        size = '__state.%s.size' % array_name.lower()
+                    if array_name == 'EDGE_FLAG':
+                        type = 'GL_BOOL'
+                    else:
+                        type = '__state.%s.type' % array_name.lower()
+                    stride = '__state.%s.stride' % array_name.lower()
+                    print '            Trace::LiteralBlob((const void *)%s, __glArrayPointer_size(%s, %s, %s, maxIndex));' % (value, size, type, stride)
+                    print '        }'
+                    print '        Trace::EndArg();'
             print '        Trace::EndEnter();'
             print '        Trace::BeginLeave(__call);'
             print '        Trace::EndLeave();'
 
         pass
 
     def trace_function_decl(self, function):
+        # Per-function declarations
+
         if function.args:
-            print '    static const char * __%s_args[%u] = {%s};' % (function.name, len(function.args), ', '.join(['"%s"' % arg.name for arg in function.args]))
+            print 'static const char * __%s_args[%u] = {%s};' % (function.name, len(function.args), ', '.join(['"%s"' % arg.name for arg in function.args]))
         else:
-            print '    static const char ** __%s_args = NULL;' % (function.name,)
-        print '    static const Trace::FunctionSig __%s_sig = {%u, "%s", %u, __%s_args};' % (function.name, int(function.id), function.name, len(function.args), function.name)
+            print 'static const char ** __%s_args = NULL;' % (function.name,)
+        print 'static const Trace::FunctionSig __%s_sig = {%u, "%s", %u, __%s_args};' % (function.name, int(function.id), function.name, len(function.args), function.name)
         print
 
-    def trace_function_fail(self, function):
-        if function.fail is not None:
-            if function.type is stdapi.Void:
-                assert function.fail == ''
-                print '            return;' 
-            else:
-                assert function.fail != ''
-                print '            return %s;' % function.fail
-        else:
-            print '            Trace::Abort();'
-
     def get_dispatch_function(self, function):
         return '__' + function.name
 
     def trace_function_impl(self, function):
         print 'extern "C" ' + function.prototype() + ' {'
-        if function.type is stdapi.Void:
-            result = ''
-        else:
+        if function.type is not stdapi.Void:
             print '    %s __result;' % function.type
-            result = '__result = '
+        self.trace_function_impl_body(function)
+        if function.type is not stdapi.Void:
+            self.wrap_ret(function, "__result")
+            print '    return __result;'
+        print '}'
+        print
+
+    def trace_function_impl_body(self, function):
         print '    unsigned __call = Trace::BeginEnter(__%s_sig);' % (function.name,)
         for arg in function.args:
             if not arg.output:
                 self.unwrap_arg(function, arg)
                 self.dump_arg(function, arg)
         print '    Trace::EndEnter();'
-        dispatch = self.get_dispatch_function(function)
-        print '    %s%s(%s);' % (result, dispatch, ', '.join([str(arg.name) for arg in function.args]))
+        self.dispatch_function(function)
         print '    Trace::BeginLeave(__call);'
         for arg in function.args:
             if arg.output:
         if function.type is not stdapi.Void:
             self.dump_ret(function, "__result")
         print '    Trace::EndLeave();'
-        if function.type is not stdapi.Void:
-            self.wrap_ret(function, "__result")
-            print '    return __result;'
-        print '}'
-        print
+
+    def dispatch_function(self, function):
+        if function.type is stdapi.Void:
+            result = ''
+        else:
+            result = '__result = '
+        dispatch = self.get_dispatch_function(function)
+        print '    %s%s(%s);' % (result, dispatch, ', '.join([str(arg.name) for arg in function.args]))
 
     def dump_arg(self, function, arg):
         print '    Trace::BeginArg(%u);' % (arg.index,)