// Create a new texture handle... geRDriver_THandle *DRIVERCC THandle_Create(int32 Width, int32 Height, int32 NumMipLevels, const geRDriver_PixelFormat *PixelFormat) { geRDriver_THandle *THandle; GLubyte Log; THandle = FindTextureHandle(); if (!THandle) { SetLastDrvError(DRV_ERROR_GENERIC, "OGL_THandleCreate: No more handles left."); gllog("ERROR: OGL_THandleCreate: No more handles left.\n"); goto ExitWithError; } if(PixelFormat->Flags & RDRIVER_PF_3D) { char errMsg[64]; if(Width > maxTextureSize) { sprintf(errMsg, "OGL_THandleCreate: Width > GL_MAX_TEXTURE_SIZE (%d)", maxTextureSize); SetLastDrvError(DRV_ERROR_GENERIC, errMsg); gllog("%s\n", errMsg); goto ExitWithError; } if (Height > maxTextureSize) { sprintf(errMsg, "OGL_THandleCreate: Height > GL_MAX_TEXTURE_SIZE (%d)", maxTextureSize); SetLastDrvError(DRV_ERROR_GENERIC, errMsg); gllog("%s\n", errMsg); goto ExitWithError; } } THandle->MipLevels = NumMipLevels; THandle->Width = Width; THandle->Height = Height; THandle->PixelFormat = *PixelFormat; THandle->Flags = 0; Log = (uint8)GetLog(Width, Height); if(THandle->PixelFormat.Flags & RDRIVER_PF_2D) { THandle->PaddedWidth = SnapToPower2(THandle->Width); THandle->PaddedHeight = SnapToPower2(THandle->Height); } else if(THandle->PixelFormat.Flags & RDRIVER_PF_3D) { THandle->InvScale = 1.0f / (GLfloat)((1<<Log)); } else { // Must be a lightmap THandle->Flags |= THANDLE_UPDATE_LM; THandle->InvScale = 1.0f / (GLfloat)((1<<Log)<<4); } // Init an OpenGL texture object to hold this texture glGenTextures(1, &(THandle->TextureID)); return THandle; ExitWithError: { return NULL; } }
int32 GetLog(int32 Width, int32 Height) { int32 LWidth = SnapToPower2(max(Width, Height)); return Log2(LWidth); }
// Render a 2D decal graphic... // Notes: unfortunately traditional thru-the-API framebuffer access for OpenGL is // ridculously slow with most ICDs. // So I've implemented decals as clamped textures on polygons. // This works rather well... usually... and it is fast. However, it has drawbacks.... // 1) Extra use of texture ram to hold decals // 2) May look shoddy under some situations on cards with 256x256 texture maximums // (3DFX Voodoo springs to mind) // Reason: If they only support 256x256, large decals like the GTest bitmap font may // be sampled down to 256x256 and then restreched when drawing. I haven't tested this // against such cards, due to lack of any access to one, but my guess is the resulting // image wont look so hot. // // In the future, may want to add platform-specific framebuffer access (GDI, X11, etc) as // allowed. But...for Windows, DirectDraw isn't supported, and to the best of my knowledge, // GDI is only reliably supported when not using a double-buffer. Joy. geBoolean DRIVERCC DrawDecal(geRDriver_THandle *THandle, RECT *SRect, int32 x, int32 y) { RECT tmpRect, *srcRect; GLint width, height; GLfloat uClamp, vClamp; GLfloat uDiff = 1.0f, vDiff = 1.0f; if(!RenderingIsOK) return GE_TRUE; if(!SRect) { tmpRect.left = 0; tmpRect.right = THandle->Width; tmpRect.top = 0; tmpRect.bottom = THandle->Height; srcRect = &tmpRect; width = (THandle->Width); height = (THandle->Height); } else { srcRect = SRect; width = (srcRect->right - srcRect->left); height = (srcRect->bottom - srcRect->top); } if(x + width <= 0 || y + height <= 0 || x >= ClientWindow.Width || y >= ClientWindow.Height) { return GE_TRUE; } if(x + width >= (ClientWindow.Width - 1)) { srcRect->right -= ((x + width) - (ClientWindow.Width - 1)); } if(y + height >= (ClientWindow.Height - 1)) { srcRect->bottom -= ((y + height) - (ClientWindow.Height - 1)); } if(x < 0) { srcRect->left += -x; x = 0; } if(y < 0) { srcRect->top += -y; y = 0; } if(boundTexture != THandle->TextureID) { glBindTexture(GL_TEXTURE_2D, THandle->TextureID); boundTexture = THandle->TextureID; } if(THandle->Flags & THANDLE_UPDATE) { THandle_Update(THandle); } glDisable(GL_DEPTH_TEST); glColor4f(1.0, 1.0, 1.0, 1.0); glShadeModel(GL_FLAT); if(THandle->Data[1] == NULL) { uClamp = width / (GLfloat)THandle->PaddedWidth; vClamp = height / (GLfloat)THandle->PaddedHeight; glMatrixMode(GL_TEXTURE); glPushMatrix(); glLoadIdentity(); glTranslatef(srcRect->left / (GLfloat)THandle->PaddedWidth, srcRect->top / (GLfloat)THandle->PaddedHeight, 0.0f); glBegin(GL_QUADS); glTexCoord2f(0.0f, 0.0); glVertex2i(x, y); glTexCoord2f(uClamp, 0.0f); glVertex2i(x + width, y); glTexCoord2f(uClamp, vClamp); glVertex2i(x + width, y + height); glTexCoord2f(0.0f, vClamp); glVertex2i(x, y + height); glEnd(); glPopMatrix(); glMatrixMode(GL_MODELVIEW); } else { glPixelStorei(GL_UNPACK_ROW_LENGTH, THandle->Width); glPixelStorei(GL_UNPACK_SKIP_PIXELS, srcRect->left); glPixelStorei(GL_UNPACK_SKIP_ROWS, srcRect->top); glPixelZoom(1.0, -1.0); if(width <= maxTextureSize && height <= maxTextureSize && width == SnapToPower2(width) && height == SnapToPower2(height)) { // Last chance to avoid the dreaded glDrawPixels...Yes, this is faster // than glDrawPixels on the ICD's I've tested. Go figure. // (Could add a more complex texture upload/clamp system for // width/heights other than powers of 2, but for now, // this is enough complexity...Sorry, 3DFX) if(decalTexObj == -1) { glGenTextures(1, &decalTexObj); } glBindTexture(GL_TEXTURE_2D, decalTexObj); boundTexture = decalTexObj; glTexImage2D(GL_TEXTURE_2D, 0, 4, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, THandle->Data[1]); glBegin(GL_QUADS); glTexCoord2f(0.0f, 0.0); glVertex2i(x, y); glTexCoord2f(1.0f, 0.0f); glVertex2i(x + width, y); glTexCoord2f(1.0f, 1.0f); glVertex2i(x + width, y + height); glTexCoord2f(0.0f, 1.0f); glVertex2i(x, y + height); glEnd(); } else { glPixelZoom(1.0, -1.0); glRasterPos2i(x, y); glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_BYTE, THandle->Data[1]); } glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); } glShadeModel(GL_SMOOTH); glEnable(GL_DEPTH_TEST); return GE_TRUE; }