# functions
         print '#ifdef RETRACE'
         for function in api.functions:
-            if not self.is_public_function(function):
+            if self.is_public_function(function):
+                print '#define __%s %s' % (function.name, function.name)
+            else:
                 print '#define %s __%s' % (function.name, function.name)
         print '#endif /* RETRACE */'
         print
 
 #define __glGetFramebufferAttachmentParameteriv_size __glGetFramebufferAttachmentParameterivEXT_size
 
 static inline size_t
-__glTexImage3D_size(GLenum format, GLenum type, GLsizei width, GLsizei height, GLsizei depth, GLint border) {
-    size_t num_channels;
+__gl_format_channels(GLenum format) {
     switch (format) {
     case GL_COLOR_INDEX:
     case GL_RED:
     case GL_LUMINANCE:
     case GL_DEPTH_COMPONENT:
     case GL_STENCIL_INDEX:
-        num_channels = 1;
+        return 1;
         break;
     case GL_LUMINANCE_ALPHA:
-        num_channels = 2;
+        return 2;
         break;
     case GL_RGB:
     case GL_BGR:
-        num_channels = 3;
+        return 3;
         break;
     case GL_RGBA:
     case GL_BGRA:
-        num_channels = 4;
+        return 4;
         break;
     default:
         OS::DebugMessage("warning: %s: unexpected format GLenum 0x%04X\n", __FUNCTION__, format);
-        num_channels = 0;
+        return 0;
         break;
     }
+}
+
+static inline size_t
+__glTexImage3D_size(GLenum format, GLenum type, GLsizei width, GLsizei height, GLsizei depth, GLint border) {
+    size_t num_channels = __gl_format_channels(format);
 
     size_t bits_per_pixel;
     switch (type) {
 
         print '#include "json.hpp"'
         print '#include "glimports.hpp"'
         print '#include "glproc.hpp"'
+        print '#include "glsize.hpp"'
         print '#include "glretrace.hpp"'
         print
 
 }
 
 static inline void
-writeDrawBufferImage(JSONWriter &json)
+writeDrawBufferImage(JSONWriter &json, GLenum format)
 {
     GLint width  = glretrace::window_width;
     GLint height = glretrace::window_height;
 
+    GLint channels = __gl_format_channels(format);
+
     if (!width || !height) {
         json.writeNull();
     } else {
         // texture internal format
         json.writeStringMember("__type__", "uint8");
         json.writeBoolMember("__normalized__", true);
-        json.writeNumberMember("__channels__", 4);
-        
-        GLubyte *pixels = new GLubyte[width*height*4];
+        json.writeNumberMember("__channels__", channels);
+
+        GLubyte *pixels = new GLubyte[width*height*channels];
         
         GLint drawbuffer = glretrace::double_buffer ? GL_BACK : GL_FRONT;
         GLint readbuffer = glretrace::double_buffer ? GL_BACK : GL_FRONT;
         glGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);
         glGetIntegerv(GL_READ_BUFFER, &readbuffer);
         glReadBuffer(drawbuffer);
-        glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+        glReadPixels(0, 0, width, height, format, GL_UNSIGNED_BYTE, pixels);
         glReadBuffer(readbuffer);
 
         json.writeStringMember("__encoding__", "base64");
         json.beginMember("__data__");
-        json.writeBase64(pixels, width * height * 4 * sizeof *pixels);
+        json.writeBase64(pixels, width * height * channels * sizeof *pixels);
         json.endMember(); // __data__
 
         delete [] pixels;
     def dump_framebuffer(self):
         print '    json.beginMember("framebuffer");'
         print '    json.beginObject();'
-        print '    json.beginMember("GL_DRAW_BUFFER");'
-        # TODO: Handle FBOs
-        print '    writeDrawBufferImage(json);'
+        # TODO: Handle real FBOs
+        print
+        print '    json.beginMember("GL_RGBA");'
+        print '    writeDrawBufferImage(json, GL_RGBA);'
         print '    json.endMember();'
+        print
+        print '    GLint depth_bits = 0;'
+        print '    glGetIntegerv(GL_DEPTH_BITS, &depth_bits);'
+        print '    if (depth_bits) {'
+        print '        json.beginMember("GL_DEPTH_COMPONENT");'
+        print '        writeDrawBufferImage(json, GL_DEPTH_COMPONENT);'
+        print '        json.endMember();'
+        print '    }'
+        print
+        print '    GLint stencil_bits = 0;'
+        print '    glGetIntegerv(GL_STENCIL_BITS, &stencil_bits);'
+        print '    if (stencil_bits) {'
+        print '        json.beginMember("GL_STENCIL_INDEX");'
+        print '        writeDrawBufferImage(json, GL_STENCIL_INDEX);'
+        print '        json.endMember();'
+        print '    }'
+        print
         print '    json.endObject();'
         print '    json.endMember(); // framebuffer'
         pass
 
     m_size = size;
 }
 
+int ApiSurface::numChannels() const
+{
+    return m_numChannels;
+}
+
+void ApiSurface::setNumChannels(int numChannels)
+{
+    m_numChannels = numChannels;
+}
+
 static inline int
 rgba8_to_argb(quint8 r, quint8 g, quint8 b, quint8 a)
 {
     //XXX not sure if this will work when
     //    QSysInfo::ByteOrder == QSysInfo::BigEndian
 
-    for (int y = 0; y < height; ++y) {
-        for (int x = 0; x < width; ++x) {
-            int pixel = rgba8_to_argb(data[(y * width + x) * 4 + 0],
-                                      data[(y * width + x) * 4 + 1],
-                                      data[(y * width + x) * 4 + 2],
-                                      data[(y * width + x) * 4 + 3]);
-            pixelData[y * width + x] = pixel;
+    if (m_numChannels == 4) {
+        for (int y = 0; y < height; ++y) {
+            for (int x = 0; x < width; ++x) {
+                int pixel = rgba8_to_argb(data[(y * width + x) * 4 + 0],
+                                          data[(y * width + x) * 4 + 1],
+                                          data[(y * width + x) * 4 + 2],
+                                          data[(y * width + x) * 4 + 3]);
+                pixelData[y * width + x] = pixel;
+            }
+        }
+    } else if (m_numChannels == 1) {
+        for (int y = 0; y < height; ++y) {
+            for (int x = 0; x < width; ++x) {
+                int pixel = rgba8_to_argb(data[y * width + x],
+                                          data[y * width + x],
+                                          data[y * width + x],
+                                          255);
+                pixelData[y * width + x] = pixel;
+            }
         }
+    } else {
+        Q_ASSERT(0);
     }
 
     m_image = QImage((uchar*)pixelData,
 
     QSize size() const;
     void setSize(const QSize &size);
 
+    int numChannels() const;
+    void setNumChannels(int numChannels);
+
     void contentsFromBase64(const QByteArray &base64);
 
     QImage image() const;
 
 private:
     QSize  m_size;
+    int m_numChannels;
     QImage m_image;
     QImage m_thumb;
 };
 
                     int numChannels =
                         image[QLatin1String("__channels__")].toInt();
 
-                    Q_ASSERT(numChannels == 4);
                     Q_ASSERT(type == QLatin1String("uint8"));
                     Q_ASSERT(normalized == true);
 
 
                     ApiTexture tex;
                     tex.setSize(size);
+                    tex.setNumChannels(numChannels);
                     tex.setLevel(j);
                     tex.setUnit(i);
                     tex.setTarget(itr.key());
         bool normalized = buffer[QLatin1String("__normalized__")].toBool();
         int numChannels = buffer[QLatin1String("__channels__")].toInt();
 
-        Q_ASSERT(numChannels == 4);
         Q_ASSERT(type == QLatin1String("uint8"));
         Q_ASSERT(normalized == true);
 
 
         ApiFramebuffer fbo;
         fbo.setSize(size);
+        fbo.setNumChannels(numChannels);
         fbo.setType(itr.key());
         fbo.contentsFromBase64(dataArray);
         m_framebuffers.append(fbo);