void GPUProgram::getProgramError(int& pos, const unsigned char*& msg) const { switch (extension) { case NVIDIA: pos = glGetInteger(GL_PROGRAM_ERROR_POSITION_NV); msg = glGetString(GL_PROGRAM_ERROR_STRING_NV); break; case ARB: pos = glGetInteger(GL_PROGRAM_ERROR_POSITION_ARB); msg = glGetString(GL_PROGRAM_ERROR_STRING_ARB); break; } }
void trace_VertexAttribPointerData(GLTraceContext *context, GLuint minIndex, GLuint maxIndex, nsecs_t time) { GLuint maxAttribs = glGetInteger(context, GL_MAX_VERTEX_ATTRIBS); for (GLuint index = 0; index < maxAttribs; index++) { if (!glGetVertexAttrib(context, index, GL_VERTEX_ATTRIB_ARRAY_ENABLED)) { // vertex array disabled continue; } if (glGetVertexAttrib(context, index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING)) { // vbo continue; } GLint size = glGetVertexAttrib(context, index, GL_VERTEX_ATTRIB_ARRAY_SIZE); GLenum type = glGetVertexAttrib(context, index, GL_VERTEX_ATTRIB_ARRAY_TYPE); GLboolean norm = glGetVertexAttrib(context, index, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED); GLsizei stride = glGetVertexAttrib(context, index, GL_VERTEX_ATTRIB_ARRAY_STRIDE); GLvoid* ptr; context->hooks->gl.glGetVertexAttribPointerv(index, GL_VERTEX_ATTRIB_ARRAY_POINTER, &ptr); trace_glVertexAttribPointerData(context, index, size, type, norm, stride, ptr, minIndex, maxIndex, time); } }
static std::string getMatrixState() { std::string result; result += getOneMatrixState(GL_MODELVIEW_MATRIX, GL_MODELVIEW); result += getOneMatrixState(GL_PROJECTION_MATRIX, GL_PROJECTION); // Get the matrix mode result += std::string("glMatrixMode(") + GLenumToString(glGetInteger(GL_MATRIX_MODE)) + ");\n\n"; return result; }
void Framebuffer::set(AttachmentPoint ap, const TextureRef& texture) { if (texture.isNull()) { // We're in the wrong overload set(ap, (void*)NULL); return; } // Get current framebuffer GLint origFB = glGetInteger(GL_FRAMEBUFFER_BINDING_EXT); // If we aren't already bound, bind us now if (origFB != (GLint)openGLID()) { // Bind this framebuffer glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, openGLID()); debugAssertGLOk(); } // Check for completeness if (numAttachments == 0) { // This is the first attachment. // Set texture height/width m_width = texture->texelWidth(); m_height = texture->texelHeight(); } else { // Verify same dimensions debugAssertM((texture->texelWidth() != width()) || (texture->texelHeight() != height()), "All attachments bound to a Framebuffer must " "have identical dimensions!"); } if (! attachmentTable.containsKey(ap)) { attachmentTable.set(ap, Attachment(texture)); } // Bind texture to framebuffer glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, ap, texture->openGLTextureTarget(), texture->openGLID(), 0); debugAssertGLOk(); // If we were already bound, don't bother restoring if (origFB != (GLint)openGLID()) { // Bind original framebuffer glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, origFB); } debugAssertGLOk(); }
void fixup_glBufferSubData(GLTraceContext *context, GLMessage *glmsg, void *pointersToFixup[]) { /* void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data) */ GLenum target = glmsg->args(0).intvalue(0); GLintptr offset = glmsg->args(1).intvalue(0); GLsizeiptr size = glmsg->args(2).intvalue(0); GLvoid *datap = (GLvoid *) pointersToFixup[0]; if (target == GL_ELEMENT_ARRAY_BUFFER) { GLint bufferId = glGetInteger(context, GL_ELEMENT_ARRAY_BUFFER_BINDING); context->updateBufferSubData(bufferId, offset, datap, size); } // add buffer data to the protobuf message addGlBufferData(glmsg, 3, datap, size); }
//=========================================== void ImageContent::render_derived(RenderDevice* RD) { bool is_right = false; if (is_stereo) { GLint val = glGetInteger(GL_DRAW_BUFFER); is_right = (val == GL_BACK_RIGHT) || (val == GL_FRONT_RIGHT); } if (is_right) { RD->setTexture(0, right); } else { RD->setTexture(0, left); } RD->setBlendFunc(RenderDevice::BLEND_SRC_ALPHA, RenderDevice::BLEND_ONE_MINUS_SRC_ALPHA, RenderDevice::BLENDEQ_ADD); //RD->setDepthTest(RenderDevice::DEPTH_ALWAYS_PASS); /* RD->setCullFace(RenderDevice::CULL_NONE); RD->setDepthTest(RenderDevice::DEPTH_ALWAYS_PASS); RD->setBlendFunc(RenderDevice::BLEND_SRC_ALPHA, RenderDevice::BLEND_ONE_MINUS_SRC_ALPHA, RenderDevice::BLENDEQ_ADD); //RD->setBlendFunc(RenderDevice::RenderDevice::BLEND_ONE, RenderDevice::BLEND_ONE_MINUS_SRC_ALPHA); */ RD->beginPrimitive(RenderDevice::QUADS); RD->setTexCoord(0, coords[0]); RD->setNormal(Vector3::unitZ()); RD->sendVertex(verts[0]); RD->setTexCoord(0, coords[1]); RD->setNormal(Vector3::unitZ()); RD->sendVertex(verts[1]); RD->setTexCoord(0, coords[2]); RD->setNormal(Vector3::unitZ()); RD->sendVertex(verts[2]); RD->setTexCoord(0, coords[3]); RD->setNormal(Vector3::unitZ()); RD->sendVertex(verts[3]); RD->endPrimitive(); RD->setTexture(0, NULL); }
void Framebuffer::set(AttachmentPoint ap, const void* n) { debugAssert(n == NULL); // Get current framebuffer GLint origFB = glGetInteger(GL_FRAMEBUFFER_BINDING_EXT); debugAssertGLOk(); // If we aren't already bound, bind us now if (origFB != (GLint)openGLID()) { // Bind this framebuffer glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, openGLID()); debugAssertGLOk(); } if (attachmentTable.containsKey(ap)) { // Detach if (attachmentTable[ap].type == Attachment::TEXTURE) { glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, ap, GL_TEXTURE_2D, 0, 0); debugAssertGLOk(); if (attachmentTable[ap].hadAutoMipMap) { attachmentTable[ap].texture->setAutoMipMap(true); } } else { glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, ap, GL_RENDERBUFFER_EXT, 0); debugAssertGLOk(); } --numAttachments; } else { // Wipe our record for that slot attachmentTable.remove(ap); } // If we were already bound, don't bother restoring if (origFB != (GLint)openGLID()) { // Bind original framebuffer glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, origFB); debugAssertGLOk(); } }
void fixup_glBufferData(GLTraceContext *context, GLMessage *glmsg, void *pointersToFixup[]) { /* void glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) */ GLsizeiptr size = glmsg->args(1).intvalue(0); GLvoid *datap = (GLvoid *) pointersToFixup[0]; // Save element array buffers for future use to fixup glVertexAttribPointers // when a glDrawElements() call is performed. GLenum target = glmsg->args(0).intvalue(0); if (target == GL_ELEMENT_ARRAY_BUFFER) { GLint bufferId = glGetInteger(context, GL_ELEMENT_ARRAY_BUFFER_BINDING); context->bindBuffer(bufferId, datap, size); } // add buffer data to the protobuf message if (datap != NULL) { addGlBufferData(glmsg, 2, datap, size); } }
static std::string getClippingState() { std::string result; int numPlanes = glGetInteger(GL_MAX_CLIP_PLANES); int C; for(C = 0; C < numPlanes; C++) { result += format("// Clip plane %d\n", C); result += format("%s(GL_CLIP_PLANE0 + %d);\n", glIsEnabled(GL_CLIP_PLANE0 + C) ? "glEnable" : "glDisable", C); double x[4]; glGetClipPlane(GL_CLIP_PLANE0 + C, x); result += format("{double coefficients[]={%4.4e, %4.4e, %4.4e, %4.4e};\n glClipPlane(GL_CLIP_PLANE0 + %d, coefficients);}\n", x[0], x[1], x[2], x[3], C); } return result; }
void trace_VertexAttribPointerDataForGlDrawElements(GLTraceContext *context, GLMessage *glmsg, GLvoid *indices) { if (context->getVersion() == egl_connection_t::GLESv1_INDEX) { // only supported for GLES2 and above return; } /* void glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) */ GLsizei count = glmsg->args(1).intvalue(0); GLenum type = glmsg->args(2).intvalue(0); GLuint index; GLuint minIndex, maxIndex; // The index buffer is either passed in as an argument to the glDrawElements() call, // or it is stored in the current GL_ELEMENT_ARRAY_BUFFER. GLvoid *indexBuffer; if (isUsingElementArrayBuffers(context)) { GLsizeiptr eaBufferSize; GLuint bufferId = glGetInteger(context, GL_ELEMENT_ARRAY_BUFFER_BINDING); context->getBuffer(bufferId, &indexBuffer, &eaBufferSize); } else { indexBuffer = indices; } // Rather than sending vertex attribute data that corresponds to the indices // being drawn, we send the vertex attribute data for the entire range of // indices being drawn, including the ones not drawn. The min & max indices // provide the range of indices being drawn. findMinAndMaxIndices(indexBuffer, count, type, &minIndex, &maxIndex); // Vertex attrib pointer data patchup calls should appear as if // they occurred right before the draw call. nsecs_t time = glmsg->start_time() - 1; trace_VertexAttribPointerData(context, minIndex, maxIndex + 1, time); }
bool isUsingElementArrayBuffers(GLTraceContext *context) { return glGetInteger(context, GL_ELEMENT_ARRAY_BUFFER_BINDING) != 0; }
bool isUsingPixelBuffers(GLTraceContext *context) { if (context->getVersionMajor() < 3) { return false; // PBOs not supported prior to GLES 3.0 } return glGetInteger(context, GL_PIXEL_UNPACK_BUFFER_BINDING) != 0; }
std::string getOpenGLState(bool showDisabled) { { debugAssertGLOk(); glGetInteger(GL_BLEND); debugAssertM(glGetError() != GL_INVALID_OPERATION, "Can't call getOpenGLState between glBegin() and glEnd()"); } // The implementation has to be careful not to disrupt any OpenGL state and // to produce output code that sets values that interact (e.g. lighting and modelview matrix) in an order // so they produce the same results as currently in memory. std::string result; result += "///////////////////////////////////////////////////////////////////\n"; result += "// Matrices //\n\n"; result += getMatrixState(); result += "///////////////////////////////////////////////////////////////////\n"; result += "// Lighting //\n\n"; result += getLightingState(showDisabled); result += "///////////////////////////////////////////////////////////////////\n"; result += "// Clipping //\n\n"; result += getClippingState(); result += "///////////////////////////////////////////////////////////////////\n"; result += "// Textures //\n\n"; result += getTextureState(showDisabled); result += "///////////////////////////////////////////////////////////////////\n"; result += "// Other //\n\n"; GLdouble d[4]; GLboolean b[4]; // Viewport glGetDoublev(GL_VIEWPORT, d); result += format("glViewport(%g, %g, %g, %g);\n\n", d[0], d[1], d[2], d[3]); //color result += enableEntry(GL_COLOR_ARRAY); result += enableEntry(GL_COLOR_LOGIC_OP); result += enableEntry(GL_COLOR_MATERIAL); glGetDoublev(GL_COLOR_CLEAR_VALUE, d); result += format("glClearColor(%g, %g, %g, %g);\n", d[0], d[1], d[2], d[3]); glGetDoublev(GL_CURRENT_COLOR, d); result += format("glColor4d(%g, %g, %g, %g);\n", d[0], d[1], d[2], d[3]); glGetBooleanv(GL_COLOR_WRITEMASK, b); result += format("glColorMask(%d, %d, %d, %d);\n", b[0], b[1], b[2], b[3]); result += format("\n"); //blend result += enableEntry(GL_BLEND); if (showDisabled || glGetBoolean(GL_BLEND)) { result += format("glBlendFunc(%s, %s);\n", GLenumToString(glGetInteger(GL_BLEND_DST)), GLenumToString(glGetInteger(GL_BLEND_SRC))); result += format("\n"); } //alpha result += enableEntry(GL_ALPHA_TEST); if (showDisabled || glGetBoolean(GL_ALPHA_TEST)) { result += format("glAlphaFunc(%s, %g);\n", GLenumToString(glGetInteger(GL_ALPHA_TEST_FUNC)), glGetDouble(GL_ALPHA_TEST_REF)); result += format("\n"); } //depth stuff result += "///////////////////////////////////////////////////////////////////\n"; result += "// Depth Buffer //\n\n"; result += enableEntry(GL_DEPTH_TEST); if (showDisabled || glGetBoolean(GL_DEPTH_TEST)) { result += format("glDepthFunc(%s);\n", GLenumToString(glGetInteger(GL_DEPTH_FUNC))); } result += format("glClearDepth(%g);\n", glGetDouble(GL_DEPTH_CLEAR_VALUE)); result += format("glDepthMask(%d);\n", glGetBoolean(GL_DEPTH_WRITEMASK)); { Vector2 range = glGetVector2(GL_DEPTH_RANGE); result += format("glDepthRange(%g, %g);\n", range.x, range.y); } result += format("\n"); //stencil stuff result += "///////////////////////////////////////////////////////////////////////\n"; result += "// Stencil\n\n"; result += enableEntry(GL_STENCIL_TEST); result += format("glClearStencil(0x%x);\n", glGetInteger(GL_STENCIL_CLEAR_VALUE)); if (GLCaps::supports_GL_EXT_stencil_two_side()) { result += "glActiveStencilFaceEXT(GL_BACK);\n"; glActiveStencilFaceEXT(GL_BACK); } if (showDisabled || glGetBoolean(GL_STENCIL_TEST)) result += format( "glStencilFunc(%s, %d, %d);\n", GLenumToString(glGetInteger(GL_STENCIL_FUNC)), glGetInteger(GL_STENCIL_REF), glGetInteger(GL_STENCIL_VALUE_MASK)); result += format( "glStencilOp(%s, %s, %s);\n", GLenumToString(glGetInteger(GL_STENCIL_FAIL)), GLenumToString(glGetInteger(GL_STENCIL_PASS_DEPTH_FAIL)), GLenumToString(glGetInteger(GL_STENCIL_PASS_DEPTH_PASS))); result += format("glStencilMask(0x%x);\n", glGetInteger(GL_STENCIL_WRITEMASK)); if (GLCaps::supports_GL_EXT_stencil_two_side()) { result += "\nglActiveStencilFaceEXT(GL_FRONT);\n"; glActiveStencilFaceEXT(GL_FRONT); if (showDisabled || glGetBoolean(GL_STENCIL_TEST)) result += format( "glStencilFunc(%s, %d, %d);\n", GLenumToString(glGetInteger(GL_STENCIL_FUNC)), glGetInteger(GL_STENCIL_REF), glGetInteger(GL_STENCIL_VALUE_MASK)); result += format( "glStencilOp(%s, %s, %s);\n", GLenumToString(glGetInteger(GL_STENCIL_FAIL)), GLenumToString(glGetInteger(GL_STENCIL_PASS_DEPTH_FAIL)), GLenumToString(glGetInteger(GL_STENCIL_PASS_DEPTH_PASS))); result += format("glStencilMask(0x%x);\n", glGetInteger(GL_STENCIL_WRITEMASK)); } result += ("\n"); //misc result += enableEntry(GL_NORMAL_ARRAY); result += enableEntry(GL_NORMALIZE); glGetDoublev(GL_CURRENT_NORMAL, d); result += format("glNormal3d(%g, %g, %g);\n", d[0], d[1], d[2]); result += ("\n"); result += format("glPixelZoom(%g, %g);\n", glGetDouble(GL_ZOOM_X), glGetDouble(GL_ZOOM_Y)); result += format("glReadBuffer(%s);\n", GLenumToString(glGetInteger(GL_READ_BUFFER))); result += enableEntry(GL_POLYGON_SMOOTH); result += enableEntry(GL_POLYGON_STIPPLE); result += enableEntry(GL_LINE_SMOOTH); result += enableEntry(GL_LINE_STIPPLE); result += enableEntry(GL_POINT_SMOOTH); result += enableEntry(GL_AUTO_NORMAL); result += enableEntry(GL_CULL_FACE); result += enableEntry(GL_POLYGON_OFFSET_FILL); result += enableEntry(GL_POLYGON_OFFSET_LINE); result += enableEntry(GL_POLYGON_OFFSET_POINT); result += ("\n"); result += enableEntry(GL_DITHER); result += enableEntry(GL_FOG); result += enableEntry(GL_VERTEX_ARRAY); result += enableEntry(GL_INDEX_ARRAY); result += enableEntry(GL_INDEX_LOGIC_OP); result += format("\n"); result += enableEntry(GL_MAP1_COLOR_4); result += enableEntry(GL_MAP1_INDEX); result += enableEntry(GL_MAP1_NORMAL); result += enableEntry(GL_MAP1_TEXTURE_COORD_1); result += enableEntry(GL_MAP1_TEXTURE_COORD_2); result += enableEntry(GL_MAP1_TEXTURE_COORD_3); result += enableEntry(GL_MAP1_TEXTURE_COORD_4); result += enableEntry(GL_MAP1_VERTEX_3); result += enableEntry(GL_MAP1_VERTEX_4); result += enableEntry(GL_MAP2_COLOR_4); result += enableEntry(GL_MAP2_INDEX); result += enableEntry(GL_MAP2_NORMAL); result += enableEntry(GL_MAP2_TEXTURE_COORD_1); result += enableEntry(GL_MAP2_TEXTURE_COORD_2); result += enableEntry(GL_MAP2_TEXTURE_COORD_3); result += enableEntry(GL_MAP2_TEXTURE_COORD_4); result += enableEntry(GL_MAP2_VERTEX_3); result += enableEntry(GL_MAP2_VERTEX_4); result += format("\n"); result += enableEntry(GL_SCISSOR_TEST); return result; }
static std::string getTextureState(bool showDisabled) { std::string result; GLenum pname[] = {GL_TEXTURE_WRAP_S, GL_TEXTURE_WRAP_T, GL_TEXTURE_WRAP_R}; GLenum tname[] = {GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D}; GLenum tname2[] = {GL_TEXTURE_BINDING_1D, GL_TEXTURE_BINDING_2D, GL_TEXTURE_BINDING_3D}; // Let's check the multitexture availability if (!GLCaps::supports_GL_ARB_multitexture()) { result += format("//NO MULTITEXTURE\n"); // See if the texture unit is enabled bool enabled = false; for (int tt = 0; tt < 3; ++tt) enabled = enabled || (glGetBoolean(tname[tt]) ? true : false); if (!enabled && !showDisabled) { for (int tt = 0; tt < 3; ++tt) result += format("glDisable(%s); ", GLenumToString(tname[tt])); result += "\n"; } else { for (int tt = 0; tt < 3; ++tt) { bool on = glGetBoolean(tname[tt]) ? true : false; result += format("%s(%s);\n", on ? "glEnable" : "glDisable", GLenumToString(tname[tt])); if (showDisabled || on) { result += format("glBindTexture(%s, %d);\n", GLenumToString(tname[tt]), glGetInteger(tname2[tt])); for (int p = 0; p < 3; ++p) { result += format("glTexParameteri(%s, %s, %s);\n", GLenumToString(tname[tt]), GLenumToString(pname[p]), GLenumToString(glGetTexParameteri(tname[tt], pname[p]))); } result += "\n"; } } // TODO: texture environment GLdouble v[4]; glGetDoublev(GL_CURRENT_TEXTURE_COORDS, v); result += format("glTexCoord4dARB(%g, %g, %g, %g);\n", v[0], v[1], v[2], v[3]); result += getOneMatrixState(GL_TEXTURE_MATRIX, GL_TEXTURE); result += "\n"; } return result; } //============= //multitexture //============= int numUnits = glGetInteger(GL_MAX_TEXTURE_UNITS_ARB); int active = glGetInteger(GL_ACTIVE_TEXTURE_ARB); // Iterate over all of the texture units for (int t = 0; t < numUnits; ++t) { result += format("// Texture Unit %d\n", t); result += format("glActiveTextureARB(GL_TEXTURE0_ARB + %d);\n", t); glActiveTextureARB(GL_TEXTURE0_ARB + t); // See if this unit is on bool enabled = false; for (int tt = 0; tt < 3; ++tt) { enabled = enabled || (glGetBoolean(tname[tt]) ? true : false); } if (! enabled && ! showDisabled) { for (int tt = 0; tt < 3; ++tt) { result += format("glDisable(%s); ", GLenumToString(tname[tt])); } result += "\n"; } else { for (int tt = 0; tt < 3; ++tt) { bool on = glGetBoolean(tname[tt]) ? true : false; result += format("%s(%s);\n", on ? "glEnable" : "glDisable", GLenumToString(tname[tt])); if (showDisabled || on) { result += format("glBindTexture(%s, %d);\n", GLenumToString(tname[tt]), glGetInteger(tname2[tt])); for (int p = 0; p < 3; ++p) { result += format("glTexParameteri(%s, %s, %s);\n", GLenumToString(tname[tt]), GLenumToString(pname[p]), GLenumToString(glGetTexParameteri(tname[tt], pname[p]))); } result += "\n"; } } // TODO: texture environment GLdouble v[4]; glGetDoublev(GL_CURRENT_TEXTURE_COORDS, v); result += format("glMultiTexCoord4dARB(GL_TEXTURE0_ARB + %d, %g, %g, %g, %g);\n", t, v[0], v[1], v[2], v[3]); result += getOneMatrixState(GL_TEXTURE_MATRIX, GL_TEXTURE); result += "\n"; } } // Restore the active texture unit glActiveTextureARB(active); result += format("glActiveTextureARB(GL_TEXTURE0_ARB + %d);\n\n", active - GL_TEXTURE0_ARB); return result; }
static std::string getLightingState(bool showDisabled) { std::string result; int L; if (glIsEnabled(GL_LIGHTING)) { result += "glEnable(GL_LIGHTING);\n"; } else { result += "glDisable(GL_LIGHTING);\n"; if (! showDisabled) { return result; } } result += "\n"; result += format("glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, %d);\n\n", glGetInteger(GL_LIGHT_MODEL_TWO_SIDE)); for (L = 0; L < 8; L++) { result += format("// Light %d\n", L); if (glIsEnabled(GL_LIGHT0 + L)) { result += format("glEnable(GL_LIGHT0 + %d);\n", L); } else { result += format("glDisable(GL_LIGHT0 + %d);\n", L); } if (showDisabled || glIsEnabled(GL_LIGHT0 + L)) { float x[4]; glGetLightfv(GL_LIGHT0 + L, GL_POSITION, x); result += format("{float pos[]={%4.4ff, %4.4ff, %4.4ff, %4.4ff};\nglLightfv(GL_LIGHT0 + %d, GL_POSITION, pos);}\n", x[0], x[1], x[2], x[3], L); glGetLightfv(GL_LIGHT0 + L, GL_AMBIENT, x); result += format("{float col[]={%4.4ff, %4.4ff, %4.4ff, %4.4ff};\nglLightfv(GL_LIGHT0 + %d, GL_AMBIENT, col);}\n", x[0], x[1], x[2], x[3], L); glGetLightfv(GL_LIGHT0 + L, GL_DIFFUSE, x); result += format("{float col[]={%4.4ff, %4.4ff, %4.4ff, %4.4ff};\nglLightfv(GL_LIGHT0 + %d, GL_DIFFUSE, col);}\n", x[0], x[1], x[2], x[3], L); glGetLightfv(GL_LIGHT0 + L, GL_SPECULAR, x); result += format("{float col[]={%4.4ff, %4.4ff, %4.4ff, %4.4ff};\nglLightfv(GL_LIGHT0 + %d, GL_SPECULAR, col);}\n", x[0], x[1], x[2], x[3], L); glGetLightfv(GL_LIGHT0 + L, GL_CONSTANT_ATTENUATION, x); result += format("glLightf (GL_LIGHT0 + %d, GL_CONSTANT_ATTENUATION, %ff);\n", L, x[0]); glGetLightfv(GL_LIGHT0 + L, GL_LINEAR_ATTENUATION, x); result += format("glLightf (GL_LIGHT0 + %d, GL_LINEAR_ATTENUATION, %ff);\n", L, x[0]); glGetLightfv(GL_LIGHT0 + L, GL_QUADRATIC_ATTENUATION, x); result += format("glLightf (GL_LIGHT0 + %d, GL_QUADRATIC_ATTENUATION, %ff);\n", L, x[0]); } result += "\n"; } // Ambient result += "// Ambient\n"; float x[4]; glGetFloatv(GL_LIGHT_MODEL_AMBIENT, x); result += format("{float col[] = {%ff, %ff, %ff, %ff};\n glLightModelfv(GL_LIGHT_MODEL_AMBIENT, col);}\n", x[0], x[1], x[2], x[3]); result += "\n"; return result; }