Main Page | Alphabetical List | Compound List | File List | Compound Members | File Members

Render.c

Go to the documentation of this file.
00001 /****************************************************************************************/
00002 /*  Render.c                                                                            */
00003 /*                                                                                      */
00004 /*  Author: George McBay (gfm@my-deja.com)                                              */
00005 /*  Description: Polygon rasterization functions for OpenGL driver                      */
00006 /*                                                                                      */
00007 /*  The contents of this file are subject to the Genesis3D Public License               */
00008 /*  Version 1.01 (the "License"); you may not use this file except in                   */
00009 /*  compliance with the License. You may obtain a copy of the License at                */
00010 /*  http://www.genesis3d.com                                                            */
00011 /*                                                                                      */
00012 /*  Software distributed under the License is distributed on an "AS IS"                 */
00013 /*  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See                */
00014 /*  the License for the specific language governing rights and limitations              */
00015 /*  under the License.                                                                  */
00016 /*                                                                                      */
00017 /*                                                                                      */
00018 /****************************************************************************************/
00019 
00020 #include <windows.h>
00021 #include <gl/gl.h>
00022 
00023 #include "Render.h"
00024 #include "OglDrv.h"
00025 #include "OglMisc.h"
00026 #include "THandle.h"
00027 #include "Win32.h"
00028 
00029 
00030 DRV_RENDER_MODE         RenderMode = RENDER_NONE;
00031 uint32                          Render_HardwareFlags = 0;
00032 
00033 GLint                           boundTexture = -1;  // Currently bound OpenGL texture object
00034 GLint                           boundTexture2 = -1; // Currently bound OpenGL tex object on second TMU
00035 
00036 GLint                           decalTexObj = -1;
00037 
00038 // Render a world polygon without multitexture support.  This will do two-polygon draws,
00039 // one with the regular texture, then another with the lightmap texture.  Clearly we hope
00040 // we don't have to use this function (if multitexture is supported in hardware and OpenGL
00041 // ICD, we won't have to), but its here just in case.
00042 void Render_WorldPolyRegular(DRV_TLVertex *Pnts, int32 NumPoints, geRDriver_THandle *THandle,
00043                                                          DRV_LInfo *LInfo, GLfloat shiftU, GLfloat shiftV, 
00044                                                          GLfloat scaleU, GLfloat scaleV,
00045                                                          GLubyte alpha)
00046 {
00047         DRV_TLVertex *pPnt;
00048         GLfloat zRecip;
00049         GLfloat tu, tv;
00050         GLint   i;
00051 
00052 #ifdef USE_LIGHTMAPS
00053         if(LInfo != NULL)
00054         {
00055                 glDepthMask(GL_FALSE);
00056         }
00057 #endif
00058 
00059         pPnt = Pnts;
00060 
00061         glBegin(GL_TRIANGLE_FAN);       
00062 
00063         for(i = 0; i < NumPoints; i++)
00064         {       
00065                 zRecip = 1.0f / pPnt->z;   
00066 
00067                 tu = (pPnt->u * scaleU + shiftU);
00068                 tv = (pPnt->v * scaleV + shiftV);
00069 
00070                 glColor4ub((GLubyte)pPnt->r, (GLubyte)pPnt->g, (GLubyte)pPnt->b, alpha);
00071 
00072                 glTexCoord4f(tu * THandle->InvScale * zRecip, 
00073                         tv * THandle->InvScale * zRecip, 0.0f, zRecip);
00074         
00075                 glVertex3f(pPnt->x, pPnt->y, -1.0f + zRecip);
00076                 
00077                 pPnt++;
00078         }
00079 
00080         glEnd(); 
00081 
00082 #ifdef USE_LIGHTMAPS
00083         if(LInfo != NULL)
00084         {
00085                 glDepthMask(GL_TRUE);
00086                 
00087                 glBlendFunc(GL_DST_COLOR,GL_ZERO);
00088 
00089                 pPnt = Pnts;
00090 
00091                 if(boundTexture != LInfo->THandle->TextureID)
00092                 {
00093                         glBindTexture(GL_TEXTURE_2D, LInfo->THandle->TextureID);
00094                         boundTexture = LInfo->THandle->TextureID;
00095                 }
00096 
00097                 if(LInfo->THandle->Flags & THANDLE_UPDATE)
00098                 {
00099                         THandle_Update(LInfo->THandle);
00100                 }
00101 
00102                 shiftU = (GLfloat)LInfo->MinU - 8.0f;
00103                 shiftV = (GLfloat)LInfo->MinV - 8.0f;
00104 
00105                 glColor4ub(255, 255, 255, 255);
00106 
00107             glBegin(GL_TRIANGLE_FAN);   
00108                 
00109                 for(i = 0; i < NumPoints; i++)
00110                 {       
00111                         zRecip = 1.0f / pPnt->z;   
00112 
00113                         tu = pPnt->u - shiftU;
00114                         tv = pPnt->v - shiftV;
00115 
00116                         glTexCoord4f(tu * LInfo->THandle->InvScale * zRecip, 
00117                                 tv * LInfo->THandle->InvScale * zRecip, 0.0f, zRecip);
00118 
00119                         glVertex3f(pPnt->x, pPnt->y, -1.0f + zRecip);
00120                         
00121                         pPnt++;
00122                 }
00123                 
00124                 glEnd(); 
00125 
00126                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00127         }
00128 #endif
00129 }
00130 
00131 
00132 // Render a world polygon using multiple TMUs to map the regular texture and lightmap in one pass 
00133 void Render_WorldPolyMultitexture(DRV_TLVertex *Pnts, int32 NumPoints, geRDriver_THandle *THandle,
00134                                                                   DRV_LInfo *LInfo, GLfloat shiftU, GLfloat shiftV, 
00135                                                                   GLfloat scaleU, GLfloat scaleV,
00136                                                                   GLubyte alpha)
00137 {
00138         DRV_TLVertex *pPnt;
00139         GLfloat zRecip;
00140         GLfloat tu, tv, lu, lv;
00141         GLfloat shiftU2, shiftV2;
00142         GLint   i;
00143         
00144 
00145         if(LInfo != NULL)
00146         {
00147                 glActiveTextureARB(GL_TEXTURE1_ARB);
00148                 glEnable(GL_TEXTURE_2D);
00149 
00150                 if(boundTexture2 != LInfo->THandle->TextureID)
00151                 {
00152                         glBindTexture(GL_TEXTURE_2D, LInfo->THandle->TextureID);
00153                         boundTexture2 = LInfo->THandle->TextureID;
00154                 }
00155 
00156                 if(LInfo->THandle->Flags & THANDLE_UPDATE)
00157                 {
00158                         THandle_Update(LInfo->THandle);
00159                 }
00160 
00161                 shiftU2 = (GLfloat)LInfo->MinU - 8.0f;
00162                 shiftV2 = (GLfloat)LInfo->MinV - 8.0f;
00163         }
00164 
00165         pPnt = Pnts;
00166 
00167         glBegin(GL_TRIANGLE_FAN);       
00168 
00169         for(i = 0; i < NumPoints; i++)
00170         {       
00171                 zRecip = 1.0f / pPnt->z;   
00172 
00173                 tu = (pPnt->u * scaleU + shiftU);
00174                 tv = (pPnt->v * scaleV + shiftV);
00175 
00176                 glColor4ub((GLubyte)pPnt->r, (GLubyte)pPnt->g, (GLubyte)pPnt->b, alpha);
00177 
00178                 glMultiTexCoord4fARB(GL_TEXTURE0_ARB, tu * THandle->InvScale * zRecip, 
00179                         tv * THandle->InvScale * zRecip, 0.0f, zRecip);
00180 
00181                 if(LInfo)
00182                 {
00183                         lu = pPnt->u - shiftU2;
00184                         lv = pPnt->v - shiftV2;
00185 
00186                         glMultiTexCoord4fARB(GL_TEXTURE1_ARB, lu * LInfo->THandle->InvScale * zRecip, 
00187                                 lv * LInfo->THandle->InvScale * zRecip, 0.0f, zRecip);
00188                 }
00189 
00190                 glVertex3f(pPnt->x, pPnt->y, -1.0f + zRecip);
00191                 
00192                 pPnt++;
00193         }
00194 
00195         glEnd(); 
00196 
00197         if(LInfo != NULL)
00198         {
00199                 glDisable(GL_TEXTURE_2D);
00200                 glActiveTextureARB(GL_TEXTURE0_ARB);
00201         }
00202 } 
00203 
00204 // Entry point to render a world polygon, does some setup and then passed off control
00205 // to a specific WorldPoly function (see above) depending upon whether multitexture is on or
00206 // off
00207 geBoolean DRIVERCC Render_WorldPoly(DRV_TLVertex *Pnts, int32 NumPoints, geRDriver_THandle *THandle, 
00208                                                                         DRV_TexInfo *TexInfo, DRV_LInfo *LInfo, uint32 Flags)
00209 {
00210         GLfloat shiftU, shiftV, scaleU, scaleV;
00211         DRV_TLVertex *pPnt = Pnts;
00212         GLubyte alpha;
00213         BOOL    Dynamic = 0;
00214 
00215 
00216         if(Flags & DRV_RENDER_ALPHA)
00217         {
00218                 alpha = (GLubyte)Pnts->a;
00219         }
00220         else
00221         {
00222                 alpha = 255;
00223         }
00224 
00225 
00226         shiftU = TexInfo->ShiftU;
00227         shiftV = TexInfo->ShiftV;
00228         scaleU = 1.0f / TexInfo->DrawScaleU;
00229         scaleV = 1.0f / TexInfo->DrawScaleV;
00230 
00231         if(boundTexture != THandle->TextureID)
00232         {
00233                 glBindTexture(GL_TEXTURE_2D, THandle->TextureID);
00234                 boundTexture = THandle->TextureID;
00235         }
00236 
00237         if(THandle->Flags & THANDLE_UPDATE)
00238         {
00239                 THandle_Update(THandle);
00240         }
00241 
00242         if(LInfo != NULL)
00243         {
00244                 OGLDRV.SetupLightmap(LInfo, &Dynamic);
00245 
00246                 if(Dynamic || LInfo->THandle->Flags & THANDLE_UPDATE_LM)
00247                 {
00248                         THandle_DownloadLightmap(LInfo);
00249 
00250                         if(Dynamic)
00251                         {
00252                                 LInfo->THandle->Flags |= THANDLE_UPDATE_LM;
00253                         }
00254                         else
00255                         {
00256                                 LInfo->THandle->Flags &= ~THANDLE_UPDATE_LM;
00257                         } 
00258                 }
00259         }
00260 
00261 
00262         if(multitexture) 
00263         {
00264                 // Hooray!!
00265                 Render_WorldPolyMultitexture(Pnts, NumPoints, THandle, LInfo, shiftU, shiftV,
00266                         scaleU, scaleV, alpha);
00267         }
00268         else
00269         {
00270                 // Hiss! Boo!
00271                 Render_WorldPolyRegular(Pnts, NumPoints, THandle, LInfo, shiftU, shiftV,
00272                         scaleU, scaleV, alpha);
00273         }
00274 
00275         OGLDRV.NumRenderedPolys++; 
00276 
00277         return GE_TRUE;
00278 }
00279 
00280 
00281 // Render a generic plain ol' polygon using Gouraud smooth shading and no texture map.
00282 geBoolean DRIVERCC Render_GouraudPoly(DRV_TLVertex *Pnts, int32 NumPoints, uint32 Flags)
00283 {
00284         GLint i;
00285         GLfloat zRecip;
00286         DRV_TLVertex *pPnt = Pnts;
00287         GLubyte alpha;
00288 
00289         if(Flags & DRV_RENDER_ALPHA)
00290         {
00291                 alpha = (GLubyte)Pnts->a;
00292         }
00293         else
00294         {
00295                 alpha = 255;
00296         }
00297 
00298         glDisable(GL_TEXTURE_2D);
00299 
00300         glBegin(GL_TRIANGLE_FAN);
00301 
00302         for(i = 0; i < NumPoints; i++)
00303         {
00304                 zRecip = 1.0f / pPnt->z;   
00305                 
00306                 glColor4ub((GLubyte)pPnt->r, (GLubyte)pPnt->g, (GLubyte)pPnt->b, alpha);
00307 
00308                 glVertex3f(pPnt->x, pPnt->y, -1.0f + zRecip);
00309 
00310                 pPnt++;
00311         }
00312 
00313         glEnd(); 
00314 
00315         glEnable(GL_TEXTURE_2D); 
00316 
00317         OGLDRV.NumRenderedPolys++; 
00318 
00319         return GE_TRUE;
00320 }
00321 
00322 
00323 // Render a non-world polygon (such as on an actor).  
00324 geBoolean DRIVERCC Render_MiscTexturePoly(DRV_TLVertex *Pnts, int32 NumPoints, 
00325                                                                                   geRDriver_THandle *THandle, uint32 Flags)
00326 {
00327         GLint i;
00328         GLfloat zRecip;
00329         DRV_TLVertex *pPnt = Pnts;
00330         GLubyte alpha;
00331 
00332 
00333         if(Flags & DRV_RENDER_ALPHA)
00334         {
00335                 alpha = (GLubyte)Pnts->a;
00336         }
00337         else
00338         {
00339                 alpha = 255;
00340         }
00341 
00342         if(boundTexture != THandle->TextureID)
00343         {
00344                 glBindTexture(GL_TEXTURE_2D, THandle->TextureID);
00345                 boundTexture = THandle->TextureID;
00346         }
00347 
00348         if(THandle->Flags & THANDLE_UPDATE)
00349         {
00350                 THandle_Update(THandle);
00351         }
00352 
00353         if(Flags & DRV_RENDER_NO_ZMASK)
00354         {
00355                 glDisable(GL_DEPTH_TEST);
00356         }
00357 
00358         glBegin(GL_TRIANGLE_FAN);
00359 
00360         for(i = 0; i < NumPoints; i++)
00361         {
00362                 zRecip = 1.0f / pPnt->z;                    
00363 
00364                 glColor4ub((GLubyte)pPnt->r, (GLubyte)pPnt->g, (GLubyte)pPnt->b, alpha);
00365 
00366                 glTexCoord4f(pPnt->u * zRecip, pPnt->v * zRecip, 0.0f, zRecip);
00367 
00368                 glVertex3f(pPnt->x, pPnt->y, -1.0f + zRecip);
00369 
00370                 pPnt++;
00371         }
00372 
00373         glEnd();  
00374 
00375         if(Flags & DRV_RENDER_NO_ZMASK)
00376         {
00377                 glEnable(GL_DEPTH_TEST);
00378         }
00379 
00380         return GE_TRUE;
00381 }
00382 
00383 
00384 // Render a 2D decal graphic...
00385 // Notes: unfortunately traditional thru-the-API framebuffer access for OpenGL is 
00386 //        ridculously slow with most ICDs.
00387 //        So I've implemented decals as clamped textures on polygons.
00388 //        This works rather well... usually... and it is fast.  However, it has drawbacks....
00389 //        1) Extra use of texture ram to hold decals
00390 //        2) May look shoddy under some situations on cards with 256x256 texture maximums 
00391 //           (3DFX Voodoo springs to mind) 
00392 //           Reason: If they only support 256x256, large decals like the GTest bitmap font may 
00393 //           be sampled down to 256x256 and then restreched when drawing.  I haven't tested this 
00394 //           against such cards, due to lack of any access to one, but my guess is the resulting 
00395 //           image wont look so hot.
00396 //
00397 // In the future, may want to add platform-specific framebuffer access (GDI, X11, etc) as 
00398 // allowed.  But...for Windows, DirectDraw isn't supported, and to the best of my knowledge, 
00399 // GDI is only reliably supported when not using a double-buffer.  Joy.
00400 geBoolean DRIVERCC DrawDecal(geRDriver_THandle *THandle, RECT *SRect, int32 x, int32 y)
00401 {
00402         RECT tmpRect, *srcRect;
00403         GLint width, height;
00404         GLfloat uClamp, vClamp;
00405         GLfloat uDiff = 1.0f, vDiff = 1.0f;
00406         
00407         if(!SRect)
00408         {
00409                 tmpRect.left = 0;
00410                 tmpRect.right = THandle->Width;
00411                 tmpRect.top = 0;
00412                 tmpRect.bottom = THandle->Height;
00413 
00414                 srcRect = &tmpRect;
00415                 width = (THandle->Width);
00416                 height = (THandle->Height);
00417         }
00418         else
00419         {
00420                 srcRect = SRect;
00421                 width = (srcRect->right - srcRect->left);
00422                 height = (srcRect->bottom - srcRect->top);
00423         }
00424         
00425         if(x + width <= 0 || y + height <= 0 || x >= ClientWindow.Width || y >= ClientWindow.Height)
00426         {
00427                 return GE_TRUE;
00428         }
00429         
00430         if(x + width >= (ClientWindow.Width - 1))
00431         {
00432                 srcRect->right -= ((x + width) - (ClientWindow.Width - 1));
00433         }
00434 
00435         if(y + height >= (ClientWindow.Height - 1))
00436         {
00437                 srcRect->bottom -= ((y + height) - (ClientWindow.Height - 1));
00438         }
00439 
00440         if(x < 0)
00441         {
00442                 srcRect->left += -x;
00443                 x = 0;
00444         }
00445         
00446         if(y < 0)
00447         {
00448                 srcRect->top += -y;
00449                 y = 0;
00450         }
00451 
00452         if(boundTexture != THandle->TextureID)
00453         {
00454                 glBindTexture(GL_TEXTURE_2D, THandle->TextureID);
00455                 boundTexture = THandle->TextureID;
00456         }
00457 
00458         if(THandle->Flags & THANDLE_UPDATE)
00459         {
00460                 THandle_Update(THandle);
00461         }
00462         
00463         glDisable(GL_DEPTH_TEST);
00464         
00465         glColor4f(1.0, 1.0, 1.0, 1.0);
00466         
00467         glShadeModel(GL_FLAT);
00468         
00469         if(THandle->Data[1] == NULL)
00470         {
00471                 uClamp = width / (GLfloat)THandle->PaddedWidth;
00472                 vClamp = height / (GLfloat)THandle->PaddedHeight;
00473                 
00474                 glMatrixMode(GL_TEXTURE); 
00475                 glPushMatrix();
00476                 glLoadIdentity();
00477                 glTranslatef(srcRect->left / (GLfloat)THandle->PaddedWidth, 
00478                         srcRect->top / (GLfloat)THandle->PaddedHeight, 0.0f);
00479                 
00480                 glBegin(GL_QUADS);
00481                 
00482                 glTexCoord2f(0.0f, 0.0);
00483                 glVertex2i(x, y);
00484                 
00485                 glTexCoord2f(uClamp, 0.0f);
00486                 glVertex2i(x + width, y);
00487                 
00488                 glTexCoord2f(uClamp, vClamp);
00489                 glVertex2i(x + width, y + height);
00490                 
00491                 glTexCoord2f(0.0f, vClamp);
00492                 glVertex2i(x, y + height);
00493                 
00494                 glEnd();  
00495                 
00496                 glPopMatrix();
00497                 glMatrixMode(GL_MODELVIEW);
00498         }
00499         else
00500         {
00501         
00502                 glPixelStorei(GL_UNPACK_ROW_LENGTH, THandle->Width);
00503                 glPixelStorei(GL_UNPACK_SKIP_PIXELS, srcRect->left);
00504                 glPixelStorei(GL_UNPACK_SKIP_ROWS, srcRect->top);
00505 
00506                 glPixelZoom(1.0, -1.0);
00507 
00508                 if(width <= maxTextureSize && height <= maxTextureSize &&
00509                         width == SnapToPower2(width) && height == SnapToPower2(height))
00510                 {
00511                         // Last chance to avoid the dreaded glDrawPixels...Yes, this is faster
00512                         // than glDrawPixels on the ICD's I've tested.  Go figure.
00513                         // (Could add a more complex texture upload/clamp system for
00514                         //  width/heights other than powers of 2, but for now,
00515                         //  this is enough complexity...Sorry, 3DFX)
00516 
00517                         if(decalTexObj == -1)
00518                         {
00519                                 glGenTextures(1, &decalTexObj);
00520                         }
00521 
00522                         glBindTexture(GL_TEXTURE_2D, decalTexObj);
00523                         boundTexture = decalTexObj;
00524 
00525                         glTexImage2D(GL_TEXTURE_2D, 0, 4, width, height, 
00526                                         0, GL_RGBA, GL_UNSIGNED_BYTE, THandle->Data[1]); 
00527 
00528                         glBegin(GL_QUADS);
00529                         
00530                         glTexCoord2f(0.0f, 0.0);
00531                         glVertex2i(x, y);
00532                         
00533                         glTexCoord2f(1.0f, 0.0f);
00534                         glVertex2i(x + width, y);
00535                         
00536                         glTexCoord2f(1.0f, 1.0f);
00537                         glVertex2i(x + width, y + height);
00538                         
00539                         glTexCoord2f(0.0f, 1.0f);
00540                         glVertex2i(x, y + height);
00541                         
00542                         glEnd();
00543                 }
00544                 else
00545                 {
00546                         glPixelZoom(1.0, -1.0);
00547 
00548                         glRasterPos2i(x, y);
00549                         glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_BYTE, THandle->Data[1]);
00550                 }
00551 
00552                 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
00553                 glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
00554                 glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
00555         } 
00556         
00557         glShadeModel(GL_SMOOTH);
00558         
00559         glEnable(GL_DEPTH_TEST); 
00560         
00561         return GE_TRUE; 
00562 }
00563 
00564 
00565 geBoolean DRIVERCC BeginScene(geBoolean Clear, geBoolean ClearZ, RECT *WorldRect)
00566 {
00567 
00568         if(Clear)
00569         {
00570                 glClear(GL_COLOR_BUFFER_BIT);
00571         }
00572         
00573         if(ClearZ)
00574         {
00575                 glClear(GL_DEPTH_BUFFER_BIT);
00576         }
00577 
00578         OGLDRV.NumRenderedPolys = 0;
00579 
00580         return GE_TRUE;
00581 }
00582 
00583 
00584 geBoolean DRIVERCC EndScene(void)
00585 {       
00586         FlipGLBuffers();
00587         
00588         return GE_TRUE;
00589 }
00590 
00591 
00592 geBoolean DRIVERCC BeginWorld(void)
00593 {
00594         RenderMode = RENDER_WORLD;
00595 
00596         OGLDRV.NumWorldPixels = 0;
00597         OGLDRV.NumWorldSpans = 0;
00598 
00599         return TRUE;
00600 }
00601 
00602 
00603 geBoolean DRIVERCC EndWorld(void)
00604 {
00605         RenderMode = RENDER_NONE;
00606 
00607 
00608         return TRUE;
00609 }
00610 
00611 
00612 geBoolean DRIVERCC BeginMeshes(void)
00613 {
00614         RenderMode = RENDER_MESHES;
00615 
00616         return TRUE;
00617 }
00618 
00619 
00620 geBoolean DRIVERCC EndMeshes(void)
00621 {
00622         RenderMode = RENDER_NONE;
00623 
00624         return TRUE;
00625 }
00626 
00627 
00628 geBoolean DRIVERCC BeginModels(void)
00629 {
00630         RenderMode = RENDER_MODELS;
00631 
00632         return TRUE;
00633 }
00634 
00635 
00636 geBoolean DRIVERCC EndModels(void)
00637 {
00638         RenderMode = RENDER_NONE;
00639 
00640         return TRUE;
00641 }

Generated on Tue Sep 30 12:36:17 2003 for GTestAndEngine by doxygen 1.3.2