void FMD3Model::RenderFrame(FTexture * skin, int frameno, int cm, Matrix3x4 *modeltoworld, int translation) { if (frameno>=numFrames) return; MD3Frame * frame = &frames[frameno]; // I can't confirm correctness of this because no model I have tested uses this information // gl.MatrixMode(GL_MODELVIEW); // gl.Translatef(frame->origin[0], frame->origin[1], frame->origin[2]); for(int i=0;i<numSurfaces;i++) { MD3Surface * surf = &surfaces[i]; if (!skin) { if (surf->numSkins==0) return; skin = surf->skins[0]; if (!skin) return; } FMaterial * tex = FMaterial::ValidateTexture(skin); tex->Bind(cm, 0, translation); RenderTriangles(surf, surf->vertices + frameno * surf->numVertices, modeltoworld); } }
void FMD3Model::RenderFrame(FTexture * skin, int frameno, int cm, int translation) { if (frameno>=numFrames) return; MD3Frame * frame = &frames[frameno]; // I can't confirm correctness of this because no model I have tested uses this information // glMatrixMode(GL_MODELVIEW); // glTranslatef(frame->origin[0], frame->origin[1], frame->origin[2]); for(int i=0;i<numSurfaces;i++) { MD3Surface * surf = &surfaces[i]; // [BB] In case no skin is specified via MODELDEF, check if the MD3 has a skin for the current surface. // Note: Each surface may have a different skin. FTexture *surfaceSkin = skin; if (!surfaceSkin) { if (surf->numSkins==0) return; surfaceSkin = surf->skins[0]; if (!surfaceSkin) return; } FMaterial * tex = FMaterial::ValidateTexture(surfaceSkin); tex->Bind(cm, 0, translation); RenderTriangles(surf, surf->vertices + frameno * surf->numVertices); } }
void FGLRenderer::FillSimplePoly(FTexture *texture, FVector2 *points, int npoints, double originx, double originy, double scalex, double scaley, angle_t rotation, FDynamicColormap *colormap, int lightlevel) { if (npoints < 3) { // This is no polygon. return; } FMaterial *gltexture = FMaterial::ValidateTexture(texture); if (gltexture == NULL) { return; } FColormap cm; cm = colormap; lightlevel = gl_CalcLightLevel(lightlevel, 0, true); PalEntry pe = gl_CalcLightColor(lightlevel, cm.LightColor, cm.blendfactor, true); glColor3ub(pe.r, pe.g, pe.b); gltexture->Bind(cm.colormap); int i; float rot = float(rotation * M_PI / float(1u << 31)); bool dorotate = rot != 0; float cosrot = cos(rot); float sinrot = sin(rot); //float yoffs = GatheringWipeScreen ? 0 : LBOffset; float uscale = float(1.f / (texture->GetScaledWidth() * scalex)); float vscale = float(1.f / (texture->GetScaledHeight() * scaley)); if (gltexture->tex->bHasCanvas) { vscale = 0 - vscale; } float ox = float(originx); float oy = float(originy); gl_RenderState.Apply(); glBegin(GL_TRIANGLE_FAN); for (i = 0; i < npoints; ++i) { float u = points[i].X - 0.5f - ox; float v = points[i].Y - 0.5f - oy; if (dorotate) { float t = u; u = t * cosrot - v * sinrot; v = v * cosrot + t * sinrot; } glTexCoord2f(u * uscale, v * vscale); glVertex3f(points[i].X, points[i].Y /* + yoffs */, 0); } glEnd(); }
void FMD3Model::RenderFrameInterpolated(FTexture * skin, int frameno, int frameno2, double inter, int cm, int translation) { if (frameno>=numFrames || frameno2>=numFrames) return; for(int i=0;i<numSurfaces;i++) { MD3Surface * surf = &surfaces[i]; // [BB] In case no skin is specified via MODELDEF, check if the MD3 has a skin for the current surface. // Note: Each surface may have a different skin. FTexture *surfaceSkin = skin; if (!surfaceSkin) { if (surf->numSkins==0) return; surfaceSkin = surf->skins[0]; if (!surfaceSkin) return; } FMaterial * tex = FMaterial::ValidateTexture(surfaceSkin); tex->Bind(cm, 0, translation); MD3Vertex* verticesInterpolated = new MD3Vertex[surfaces[i].numVertices]; MD3Vertex* vertices1 = surf->vertices + frameno * surf->numVertices; MD3Vertex* vertices2 = surf->vertices + frameno2 * surf->numVertices; // [BB] Calculate the interpolated vertices by linear interpolation. for( int k = 0; k < surf->numVertices; k++ ) { verticesInterpolated[k].x = (1-inter)*vertices1[k].x+ (inter)*vertices2[k].x; verticesInterpolated[k].y = (1-inter)*vertices1[k].y+ (inter)*vertices2[k].y; verticesInterpolated[k].z = (1-inter)*vertices1[k].z+ (inter)*vertices2[k].z; // [BB] Apparently RenderTriangles doesn't use nx, ny, nz, so don't interpolate them. } RenderTriangles(surf, verticesInterpolated); delete[] verticesInterpolated; } }
void FMD3Model::RenderFrameInterpolated(FTexture * skin, int frameno, int frameno2, double inter, int cm, Matrix3x4 *modeltoworld, int translation) { if (frameno>=numFrames || frameno2>=numFrames) return; for(int i=0;i<numSurfaces;i++) { MD3Surface * surf = &surfaces[i]; if (!skin) { if (surf->numSkins==0) return; skin = surf->skins[0]; if (!skin) return; } FMaterial * tex = FMaterial::ValidateTexture(skin); tex->Bind(cm, 0, translation); MD3Vertex* verticesInterpolated = new MD3Vertex[surfaces[i].numVertices]; MD3Vertex* vertices1 = surf->vertices + frameno * surf->numVertices; MD3Vertex* vertices2 = surf->vertices + frameno2 * surf->numVertices; // [BB] Calculate the interpolated vertices by linear interpolation. for( int k = 0; k < surf->numVertices; k++ ) { verticesInterpolated[k].x = (1-inter)*vertices1[k].x+ (inter)*vertices2[k].x; verticesInterpolated[k].y = (1-inter)*vertices1[k].y+ (inter)*vertices2[k].y; verticesInterpolated[k].z = (1-inter)*vertices1[k].z+ (inter)*vertices2[k].z; // [BB] Apparently RenderTriangles doesn't use nx, ny, nz, so don't interpolate them. } RenderTriangles(surf, verticesInterpolated, modeltoworld); delete[] verticesInterpolated; } }
//----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // // // Horizon Portal // // This simply draws the area in medium sized squares. Drawing it as a whole // polygon creates visible inaccuracies. // // Originally I tried to minimize the amount of data to be drawn but there // are 2 problems with it: // // 1. Setting this up completely negates any performance gains. // 2. It doesn't work with a 360° field of view (as when you are looking up.) // // // So the brute force mechanism is just as good. // // //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // // GLHorizonPortal::DrawContents // //----------------------------------------------------------------------------- void GLHorizonPortal::DrawContents() { PortalAll.Clock(); GLSectorPlane * sp=&origin->plane; FMaterial * gltexture; PalEntry color; float z; player_t * player=&players[consoleplayer]; gltexture=FMaterial::ValidateTexture(sp->texture, true); if (!gltexture) { ClearScreen(); PortalAll.Unclock(); return; } z=FIXED2FLOAT(sp->texheight); if (gltexture && gltexture->tex->isFullbright()) { // glowing textures are always drawn full bright without color gl_SetColor(255, 0, NULL, 1.f); gl_SetFog(255, 0, &origin->colormap, false); } else { int rel = getExtraLight(); gl_SetColor(origin->lightlevel, rel, &origin->colormap, 1.0f); gl_SetFog(origin->lightlevel, rel, &origin->colormap, false); } gltexture->Bind(origin->colormap.colormap); gl_RenderState.EnableAlphaTest(false); gl_RenderState.BlendFunc(GL_ONE,GL_ZERO); gl_RenderState.Apply(); bool pushed = gl_SetPlaneTextureRotation(sp, gltexture); float vx=FIXED2FLOAT(viewx); float vy=FIXED2FLOAT(viewy); // Draw to some far away boundary for(float x=-32768+vx; x<32768+vx; x+=4096) { for(float y=-32768+vy; y<32768+vy;y+=4096) { glBegin(GL_TRIANGLE_FAN); glTexCoord2f(x/64, -y/64); glVertex3f(x, z, y); glTexCoord2f(x/64 + 64, -y/64); glVertex3f(x + 4096, z, y); glTexCoord2f(x/64 + 64, -y/64 - 64); glVertex3f(x + 4096, z, y + 4096); glTexCoord2f(x/64, -y/64 - 64); glVertex3f(x, z, y + 4096); glEnd(); } } float vz=FIXED2FLOAT(viewz); float tz=(z-vz);///64.0f; // fill the gap between the polygon and the true horizon // Since I can't draw into infinity there can always be a // small gap glBegin(GL_TRIANGLE_STRIP); glTexCoord2f(512.f, 0); glVertex3f(-32768+vx, z, -32768+vy); glTexCoord2f(512.f, tz); glVertex3f(-32768+vx, vz, -32768+vy); glTexCoord2f(-512.f, 0); glVertex3f(-32768+vx, z, 32768+vy); glTexCoord2f(-512.f, tz); glVertex3f(-32768+vx, vz, 32768+vy); glTexCoord2f(512.f, 0); glVertex3f( 32768+vx, z, 32768+vy); glTexCoord2f(512.f, tz); glVertex3f( 32768+vx, vz, 32768+vy); glTexCoord2f(-512.f, 0); glVertex3f( 32768+vx, z, -32768+vy); glTexCoord2f(-512.f, tz); glVertex3f( 32768+vx, vz, -32768+vy); glTexCoord2f(512.f, 0); glVertex3f(-32768+vx, z, -32768+vy); glTexCoord2f(512.f, tz); glVertex3f(-32768+vx, vz, -32768+vy); glEnd(); if (pushed) { glPopMatrix(); glMatrixMode(GL_MODELVIEW); } PortalAll.Unclock(); }
//========================================================================== // // Draw the plane segment into the gap // //========================================================================== void FDrawInfo::DrawFloodedPlane(wallseg * ws, float planez, sector_t * sec, bool ceiling) { GLSectorPlane plane; int lightlevel; FColormap Colormap; FMaterial * gltexture; plane.GetFromSector(sec, ceiling); gltexture=FMaterial::ValidateTexture(plane.texture, true); if (!gltexture) return; if (gl_fixedcolormap) { Colormap.Clear(); lightlevel=255; } else { Colormap=sec->ColorMap; if (gltexture->tex->isFullbright()) { Colormap.LightColor.r = Colormap.LightColor.g = Colormap.LightColor.b = 0xff; lightlevel=255; } else lightlevel=abs(ceiling? sec->GetCeilingLight() : sec->GetFloorLight()); } int rel = getExtraLight(); gl_SetColor(lightlevel, rel, Colormap, 1.0f); gl_SetFog(lightlevel, rel, &Colormap, false); gltexture->Bind(); float fviewx = FIXED2FLOAT(viewx); float fviewy = FIXED2FLOAT(viewy); float fviewz = FIXED2FLOAT(viewz); gl_SetPlaneTextureRotation(&plane, gltexture); gl_RenderState.Apply(); float prj_fac1 = (planez-fviewz)/(ws->z1-fviewz); float prj_fac2 = (planez-fviewz)/(ws->z2-fviewz); float px1 = fviewx + prj_fac1 * (ws->x1-fviewx); float py1 = fviewy + prj_fac1 * (ws->y1-fviewy); float px2 = fviewx + prj_fac2 * (ws->x1-fviewx); float py2 = fviewy + prj_fac2 * (ws->y1-fviewy); float px3 = fviewx + prj_fac2 * (ws->x2-fviewx); float py3 = fviewy + prj_fac2 * (ws->y2-fviewy); float px4 = fviewx + prj_fac1 * (ws->x2-fviewx); float py4 = fviewy + prj_fac1 * (ws->y2-fviewy); FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer(); ptr->Set(px1, planez, py1, px1 / 64, -py1 / 64); ptr++; ptr->Set(px2, planez, py2, px2 / 64, -py2 / 64); ptr++; ptr->Set(px3, planez, py3, px3 / 64, -py3 / 64); ptr++; ptr->Set(px4, planez, py4, px4 / 64, -py4 / 64); ptr++; GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_FAN); gl_RenderState.EnableTextureMatrix(false); }
//========================================================================== // // Draw the plane segment into the gap // //========================================================================== void FDrawInfo::DrawFloodedPlane(wallseg * ws, float planez, sector_t * sec, bool ceiling) { GLSectorPlane plane; int lightlevel; FColormap Colormap; FMaterial * gltexture; plane.GetFromSector(sec, ceiling); gltexture=FMaterial::ValidateTexture(plane.texture, true); if (!gltexture) return; if (gl_fixedcolormap) { Colormap.GetFixedColormap(); lightlevel=255; } else { Colormap=sec->ColorMap; if (gltexture->tex->isFullbright()) { Colormap.LightColor.r = Colormap.LightColor.g = Colormap.LightColor.b = 0xff; lightlevel=255; } else lightlevel=abs(ceiling? sec->GetCeilingLight() : sec->GetFloorLight()); } int rel = getExtraLight(); gl_SetColor(lightlevel, rel, &Colormap, 1.0f); gl_SetFog(lightlevel, rel, &Colormap, false); gltexture->Bind(Colormap.colormap); float fviewx = FIXED2FLOAT(viewx); float fviewy = FIXED2FLOAT(viewy); float fviewz = FIXED2FLOAT(viewz); gl_RenderState.Apply(); bool pushed = gl_SetPlaneTextureRotation(&plane, gltexture); glBegin(GL_TRIANGLE_FAN); float prj_fac1 = (planez-fviewz)/(ws->z1-fviewz); float prj_fac2 = (planez-fviewz)/(ws->z2-fviewz); float px1 = fviewx + prj_fac1 * (ws->x1-fviewx); float py1 = fviewy + prj_fac1 * (ws->y1-fviewy); float px2 = fviewx + prj_fac2 * (ws->x1-fviewx); float py2 = fviewy + prj_fac2 * (ws->y1-fviewy); float px3 = fviewx + prj_fac2 * (ws->x2-fviewx); float py3 = fviewy + prj_fac2 * (ws->y2-fviewy); float px4 = fviewx + prj_fac1 * (ws->x2-fviewx); float py4 = fviewy + prj_fac1 * (ws->y2-fviewy); glTexCoord2f(px1 / 64, -py1 / 64); glVertex3f(px1, planez, py1); glTexCoord2f(px2 / 64, -py2 / 64); glVertex3f(px2, planez, py2); glTexCoord2f(px3 / 64, -py3 / 64); glVertex3f(px3, planez, py3); glTexCoord2f(px4 / 64, -py4 / 64); glVertex3f(px4, planez, py4); glEnd(); if (pushed) { glPopMatrix(); glMatrixMode(GL_MODELVIEW); } }
void FGLRenderer::DrawTexture(FTexture *img, DCanvas::DrawParms &parms) { double xscale = parms.destwidth / parms.texwidth; double yscale = parms.destheight / parms.texheight; double x = parms.x - parms.left * xscale; double y = parms.y - parms.top * yscale; double w = parms.destwidth; double h = parms.destheight; float u1, v1, u2, v2, r, g, b; float light = 1.f; FMaterial * gltex = FMaterial::ValidateTexture(img); const PatchTextureInfo * pti; if (parms.colorOverlay) { // Right now there's only black. Should be implemented properly later light = 1.f - APART(parms.colorOverlay)/255.f; } if (!img->bHasCanvas) { if (!parms.alphaChannel) { int translation = 0; if (parms.remap != NULL && !parms.remap->Inactive) { GLTranslationPalette * pal = static_cast<GLTranslationPalette*>(parms.remap->GetNative()); if (pal) translation = -pal->GetIndex(); } pti = gltex->BindPatch(CM_DEFAULT, translation); } else { // This is an alpha texture pti = gltex->BindPatch(CM_SHADE, 0); } if (!pti) return; u1 = pti->GetUL(); v1 = pti->GetVT(); u2 = pti->GetUR(); v2 = pti->GetVB(); } else { gltex->Bind(CM_DEFAULT, 0, 0); u2=1.f; v2=-1.f; u1 = v1 = 0.f; gl_RenderState.SetTextureMode(TM_OPAQUE); } if (parms.flipX) { float temp = u1; u1 = u2; u2 = temp; } if (parms.windowleft > 0 || parms.windowright < parms.texwidth) { x += parms.windowleft * xscale; w -= (parms.texwidth - parms.windowright + parms.windowleft) * xscale; u1 = float(u1 + parms.windowleft / parms.texwidth); u2 = float(u2 - (parms.texwidth - parms.windowright) / parms.texwidth); } if (parms.style.Flags & STYLEF_ColorIsFixed) { r = RPART(parms.fillcolor)/255.0f; g = GPART(parms.fillcolor)/255.0f; b = BPART(parms.fillcolor)/255.0f; } else { r = g = b = light; } // scissor test doesn't use the current viewport for the coordinates, so use real screen coordinates int btm = (SCREENHEIGHT - screen->GetHeight()) / 2; btm = SCREENHEIGHT - btm; gl.Enable(GL_SCISSOR_TEST); int space = (static_cast<OpenGLFrameBuffer*>(screen)->GetTrueHeight()-screen->GetHeight())/2; gl.Scissor(parms.lclip, btm - parms.dclip + space, parms.rclip - parms.lclip, parms.dclip - parms.uclip); gl_SetRenderStyle(parms.style, !parms.masked, false); if (img->bHasCanvas) { gl_RenderState.SetTextureMode(TM_OPAQUE); } gl.Color4f(r, g, b, FIXED2FLOAT(parms.alpha)); gl_RenderState.EnableAlphaTest(false); gl_RenderState.Apply(); gl.Begin(GL_TRIANGLE_STRIP); gl.TexCoord2f(u1, v1); glVertex2d(x, y); gl.TexCoord2f(u1, v2); glVertex2d(x, y + h); gl.TexCoord2f(u2, v1); glVertex2d(x + w, y); gl.TexCoord2f(u2, v2); glVertex2d(x + w, y + h); gl.End(); gl_RenderState.EnableAlphaTest(true); gl.Scissor(0, 0, screen->GetWidth(), screen->GetHeight()); gl.Disable(GL_SCISSOR_TEST); gl_RenderState.SetTextureMode(TM_MODULATE); gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); gl_RenderState.BlendEquation(GL_FUNC_ADD); }
static void RenderBox(FTextureID texno, FMaterial * gltex, float x_offset, int CM_Index, bool sky2) { FSkyBox * sb = static_cast<FSkyBox*>(gltex->tex); int faces; FMaterial * tex; if (!sky2) glRotatef(-180.0f+x_offset, glset.skyrotatevector.X, glset.skyrotatevector.Z, glset.skyrotatevector.Y); else glRotatef(-180.0f+x_offset, glset.skyrotatevector2.X, glset.skyrotatevector2.Z, glset.skyrotatevector2.Y); glColor3f(R, G ,B); if (sb->faces[5]) { faces=4; // north tex = FMaterial::ValidateTexture(sb->faces[0]); tex->Bind(CM_Index, GLT_CLAMPX|GLT_CLAMPY, 0); gl_RenderState.Apply(); glBegin(GL_TRIANGLE_FAN); glTexCoord2f(0, 0); glVertex3f(128.f, 128.f, -128.f); glTexCoord2f(1, 0); glVertex3f(-128.f, 128.f, -128.f); glTexCoord2f(1, 1); glVertex3f(-128.f, -128.f, -128.f); glTexCoord2f(0, 1); glVertex3f(128.f, -128.f, -128.f); glEnd(); // east tex = FMaterial::ValidateTexture(sb->faces[1]); tex->Bind(CM_Index, GLT_CLAMPX|GLT_CLAMPY, 0); gl_RenderState.Apply(); glBegin(GL_TRIANGLE_FAN); glTexCoord2f(0, 0); glVertex3f(-128.f, 128.f, -128.f); glTexCoord2f(1, 0); glVertex3f(-128.f, 128.f, 128.f); glTexCoord2f(1, 1); glVertex3f(-128.f, -128.f, 128.f); glTexCoord2f(0, 1); glVertex3f(-128.f, -128.f, -128.f); glEnd(); // south tex = FMaterial::ValidateTexture(sb->faces[2]); tex->Bind(CM_Index, GLT_CLAMPX|GLT_CLAMPY, 0); gl_RenderState.Apply(); glBegin(GL_TRIANGLE_FAN); glTexCoord2f(0, 0); glVertex3f(-128.f, 128.f, 128.f); glTexCoord2f(1, 0); glVertex3f(128.f, 128.f, 128.f); glTexCoord2f(1, 1); glVertex3f(128.f, -128.f, 128.f); glTexCoord2f(0, 1); glVertex3f(-128.f, -128.f, 128.f); glEnd(); // west tex = FMaterial::ValidateTexture(sb->faces[3]); tex->Bind(CM_Index, GLT_CLAMPX|GLT_CLAMPY, 0); gl_RenderState.Apply(); glBegin(GL_TRIANGLE_FAN); glTexCoord2f(0, 0); glVertex3f(128.f, 128.f, 128.f); glTexCoord2f(1, 0); glVertex3f(128.f, 128.f, -128.f); glTexCoord2f(1, 1); glVertex3f(128.f, -128.f, -128.f); glTexCoord2f(0, 1); glVertex3f(128.f, -128.f, 128.f); glEnd(); } else { faces=1; // all 4 sides tex = FMaterial::ValidateTexture(sb->faces[0]); tex->Bind(CM_Index, GLT_CLAMPX|GLT_CLAMPY, 0); gl_RenderState.Apply(); glBegin(GL_TRIANGLE_FAN); glTexCoord2f(0, 0); glVertex3f(128.f, 128.f, -128.f); glTexCoord2f(.25f, 0); glVertex3f(-128.f, 128.f, -128.f); glTexCoord2f(.25f, 1); glVertex3f(-128.f, -128.f, -128.f); glTexCoord2f(0, 1); glVertex3f(128.f, -128.f, -128.f); glEnd(); // east glBegin(GL_TRIANGLE_FAN); glTexCoord2f(.25f, 0); glVertex3f(-128.f, 128.f, -128.f); glTexCoord2f(.5f, 0); glVertex3f(-128.f, 128.f, 128.f); glTexCoord2f(.5f, 1); glVertex3f(-128.f, -128.f, 128.f); glTexCoord2f(.25f, 1); glVertex3f(-128.f, -128.f, -128.f); glEnd(); // south glBegin(GL_TRIANGLE_FAN); glTexCoord2f(.5f, 0); glVertex3f(-128.f, 128.f, 128.f); glTexCoord2f(.75f, 0); glVertex3f(128.f, 128.f, 128.f); glTexCoord2f(.75f, 1); glVertex3f(128.f, -128.f, 128.f); glTexCoord2f(.5f, 1); glVertex3f(-128.f, -128.f, 128.f); glEnd(); // west glBegin(GL_TRIANGLE_FAN); glTexCoord2f(.75f, 0); glVertex3f(128.f, 128.f, 128.f); glTexCoord2f(1, 0); glVertex3f(128.f, 128.f, -128.f); glTexCoord2f(1, 1); glVertex3f(128.f, -128.f, -128.f); glTexCoord2f(.75f, 1); glVertex3f(128.f, -128.f, 128.f); glEnd(); } // top tex = FMaterial::ValidateTexture(sb->faces[faces]); tex->Bind(CM_Index, GLT_CLAMPX|GLT_CLAMPY, 0); gl_RenderState.Apply(); glBegin(GL_TRIANGLE_FAN); if (!sb->fliptop) { glTexCoord2f(0, 0); glVertex3f(128.f, 128.f, -128.f); glTexCoord2f(1, 0); glVertex3f(-128.f, 128.f, -128.f); glTexCoord2f(1, 1); glVertex3f(-128.f, 128.f, 128.f); glTexCoord2f(0, 1); glVertex3f(128.f, 128.f, 128.f); } else { glTexCoord2f(0, 0); glVertex3f(128.f, 128.f, 128.f); glTexCoord2f(1, 0); glVertex3f(-128.f, 128.f, 128.f); glTexCoord2f(1, 1); glVertex3f(-128.f, 128.f, -128.f); glTexCoord2f(0, 1); glVertex3f(128.f, 128.f, -128.f); } glEnd(); // bottom tex = FMaterial::ValidateTexture(sb->faces[faces+1]); tex->Bind(CM_Index, GLT_CLAMPX|GLT_CLAMPY, 0); gl_RenderState.Apply(); glBegin(GL_TRIANGLE_FAN); glTexCoord2f(0, 0); glVertex3f(128.f, -128.f, -128.f); glTexCoord2f(1, 0); glVertex3f(-128.f, -128.f, -128.f); glTexCoord2f(1, 1); glVertex3f(-128.f, -128.f, 128.f); glTexCoord2f(0, 1); glVertex3f(128.f, -128.f, 128.f); glEnd(); }