Fix opengl state clobbering, optimize terrain rendering a little.

master
safety0ff 2010-10-16 17:36:02 -04:00
parent 1401fbd13d
commit 7e872312b8
5 changed files with 132 additions and 122 deletions

View File

@ -84,7 +84,7 @@ typedef struct RENDER_STATE
typedef enum
{
TEXPAGE_NONE = -1,
TEXPAGE_FONT = -2
TEXPAGE_EXTERN = -2
} TEXPAGE_TYPE;
typedef enum

View File

@ -33,10 +33,6 @@
//*************************************************************************
#define iV_TEXNAME(i) ((char *) (&_TEX_PAGE[(i)].name))
//*************************************************************************
typedef struct
{
char name[iV_TEXNAME_MAX];
@ -50,6 +46,18 @@ extern iTexPage _TEX_PAGE[iV_TEX_MAX];
//*************************************************************************
static inline char * iV_TexName(SDWORD pageNum)
{
return _TEX_PAGE[pageNum].name;
}
static inline GLuint iV_NativeTexID(SDWORD pageNum)
{
return _TEX_PAGE[pageNum].id;
}
//*************************************************************************
extern int iV_GetTexture(const char *filename);
extern void iV_unloadImage(iV_Image *image);
extern unsigned int iV_getPixelFormat(const iV_Image *image);

View File

@ -410,12 +410,12 @@ void pie_SetTexturePage(SDWORD num)
case TEXPAGE_NONE:
glDisable(GL_TEXTURE_2D);
break;
case TEXPAGE_FONT:
case TEXPAGE_EXTERN:
// GLC will set the texture, we just need to enable texturing
glEnable(GL_TEXTURE_2D);
break;
default:
if (rendStates.texPage == TEXPAGE_NONE || rendStates.texPage == TEXPAGE_FONT)
if (rendStates.texPage == TEXPAGE_NONE)
{
glEnable(GL_TEXTURE_2D);
}

View File

@ -598,7 +598,7 @@ int iV_DrawFormattedText(const char* String, UDWORD x, UDWORD y, UDWORD Width, U
void iV_DrawTextRotated(const char* string, float XPos, float YPos, float rotation)
{
pie_SetTexturePage(TEXPAGE_FONT);
pie_SetTexturePage(TEXPAGE_EXTERN);
glMatrixMode(GL_TEXTURE);
glPushMatrix();

View File

@ -92,7 +92,8 @@ static GLuint lightmap_tex_num;
/// When are we going to update the lightmap next?
static unsigned int lightmapNextUpdate;
/// How big is the lightmap?
static int lightmapSize;
static int lightmapWidth;
static int lightmapHeight;
/// Lightmap image
static GLubyte *lightmapPixmap;
/// Ticks per lightmap refresh
@ -706,7 +707,6 @@ bool initTerrain(void)
GLuint *textureIndex;
PIELIGHT *texture;
int decalSize;
int size;
int maxSectorSizeIndices, maxSectorSizeVertices;
bool decreasedSize = false;
@ -1001,23 +1001,16 @@ bool initTerrain(void)
lightmap_tex_num = 0;
lightmapNextUpdate = 0;
lightmapWidth = 1;
lightmapHeight = 1;
// determine the smallest power-of-two size we can use for the lightmap
size = mapWidth;
if (mapHeight > size)
{
size = mapHeight;
}
lightmapSize = 1;
while (size)
{
size >>= 1;
lightmapSize <<=1;
}
while (mapWidth > (lightmapWidth <<= 1));
while (mapHeight > (lightmapHeight <<= 1));
debug(LOG_TERRAIN, "the size of the map is %ix%i", mapWidth, mapHeight);
debug(LOG_TERRAIN, "lightmap texture size is %ix%i", lightmapSize, lightmapSize);
debug(LOG_TERRAIN, "lightmap texture size is %ix%i", lightmapWidth, lightmapHeight);
// Prepare the lightmap pixmap and texture
lightmapPixmap = (GLubyte *)calloc(1, lightmapSize * lightmapSize * 3 * sizeof(GLubyte));
lightmapPixmap = (GLubyte *)calloc(lightmapWidth * lightmapHeight, 3 * sizeof(GLubyte));
if (lightmapPixmap == NULL)
{
debug(LOG_FATAL, "Out of memory!");
@ -1029,12 +1022,12 @@ bool initTerrain(void)
glBindTexture(GL_TEXTURE_2D, lightmap_tex_num);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, 3, lightmapSize, lightmapSize, 0, GL_RGB, GL_UNSIGNED_BYTE, lightmapPixmap);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, lightmapWidth, lightmapHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, lightmapPixmap);
terrainInitalised = true;
@ -1064,6 +1057,7 @@ void shutdownTerrain(void)
}
}
free(sectors);
sectors = NULL;
glDeleteTextures(1, &lightmap_tex_num);
free(lightmapPixmap);
@ -1081,15 +1075,12 @@ void drawTerrain(void)
{
int i, j, x, y;
int texPage;
PIELIGHT colour;
int layer;
int offset, size;
float xPos, yPos, distance;
GLfloat paramsX[4] = {0, 0, -1.0/world_coord(mapHeight)*((float)mapHeight/lightmapSize), 0};
GLfloat paramsY[4] = {1.0/world_coord(mapWidth)*((float)mapWidth/lightmapSize), 0, 0, 0};
const GLfloat paramsX[4] = {1.0/world_coord(mapWidth)*((float)mapWidth/lightmapWidth), 0, 0, 0};
const GLfloat paramsY[4] = {0, 0, -1.0/world_coord(mapHeight)*((float)mapHeight/lightmapHeight), 0};
glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TEXTURE_BIT | GL_DEPTH_BUFFER_BIT);
///////////////////////////////////
// set up the lightmap texture
@ -1103,27 +1094,28 @@ void drawTerrain(void)
{
lightmapNextUpdate = gameTime + LIGHTMAP_REFRESH;
for (i = 0; i < lightmapSize; i++)
for (j = 0; j < mapHeight; ++j)
{
for (j = 0; j < lightmapSize; j++)
for (i = 0; i < mapWidth; ++i)
{
float darken, distToEdge;
float distA, distB, distC, distD;
float playerX = (float)player.p.x/TILE_UNITS+visibleTiles.x/2;
float playerY = (float)player.p.z/TILE_UNITS+visibleTiles.y/2;
getColour(&colour, i, j, false);
lightmapPixmap[(i * lightmapSize + j) * 3 + 0] = colour.byte.r;
lightmapPixmap[(i * lightmapSize + j) * 3 + 1] = colour.byte.g;
lightmapPixmap[(i * lightmapSize + j) * 3 + 2] = colour.byte.b;
if (!rendStates.fogEnabled)
const PIELIGHT colour = getTileColour(i, j);
lightmapPixmap[(i + j * lightmapWidth) * 3 + 0] = colour.byte.r;
lightmapPixmap[(i + j * lightmapWidth) * 3 + 1] = colour.byte.g;
lightmapPixmap[(i + j * lightmapWidth) * 3 + 2] = colour.byte.b;
if (!pie_GetFogStatus())
{
// fade to black at the edges of the visible terrain area
distA = visibleTiles.x/2-(i-playerX);
distB = (i-playerX)+visibleTiles.x/2;
distC = visibleTiles.y/2-(j-playerY);
distD = (j-playerY)+visibleTiles.y/2;
const float playerX = (float)player.p.x/TILE_UNITS+visibleTiles.x/2;
const float playerY = (float)player.p.z/TILE_UNITS+visibleTiles.y/2;
const float distA = visibleTiles.x/2-(i-playerX);
const float distB = (i-playerX)+visibleTiles.x/2;
const float distC = visibleTiles.y/2-(j-playerY);
const float distD = (j-playerY)+visibleTiles.y/2;
float darken, distToEdge;
// calculate the distance to the closest edge of the visible map
// determine the smallest distance
distToEdge = distA;
@ -1132,43 +1124,26 @@ void drawTerrain(void)
if (distD < distToEdge) distToEdge = distD;
darken = (distToEdge)/2.0f;
if (darken < 0)
if (darken <= 0)
{
darken = 0;
lightmapPixmap[(i + j * lightmapWidth) * 3 + 0] = 0;
lightmapPixmap[(i + j * lightmapWidth) * 3 + 1] = 0;
lightmapPixmap[(i + j * lightmapWidth) * 3 + 2] = 0;
}
if (darken < 1)
else if (darken < 1)
{
lightmapPixmap[(i * lightmapSize + j) * 3 + 0] *= darken;
lightmapPixmap[(i * lightmapSize + j) * 3 + 1] *= darken;
lightmapPixmap[(i * lightmapSize + j) * 3 + 2] *= darken;
lightmapPixmap[(i + j * lightmapWidth) * 3 + 0] *= darken;
lightmapPixmap[(i + j * lightmapWidth) * 3 + 1] *= darken;
lightmapPixmap[(i + j * lightmapWidth) * 3 + 2] *= darken;
}
}
}
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, lightmapSize, lightmapSize, GL_RGB, GL_UNSIGNED_BYTE, lightmapPixmap);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, lightmapWidth, lightmapHeight, GL_RGB, GL_UNSIGNED_BYTE, lightmapPixmap);
}
// enable texture coord generation
glEnable(GL_TEXTURE_GEN_S); glError();
glEnable(GL_TEXTURE_GEN_T); glError();
glEnable(GL_BLEND);
// set the parameters for the texture coord generation
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
glTexGenfv(GL_S, GL_OBJECT_PLANE, paramsX);
glTexGenfv(GL_T, GL_OBJECT_PLANE, paramsY);
// shift the lightmap half a tile as lights are supposed to be placed at the center of a tile
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glTranslatef(1.0/lightmapSize/2, 1.0/lightmapSize/2, 0);
glMatrixMode(GL_MODELVIEW);
glActiveTexture(GL_TEXTURE0);
///////////////////////////////////
// terrain culling
for (x = 0; x < xSectors; x++)
@ -1195,14 +1170,31 @@ void drawTerrain(void)
}
}
// enable texture coord generation
glEnable(GL_TEXTURE_GEN_S); glError();
glEnable(GL_TEXTURE_GEN_T); glError();
// set the parameters for the texture coord generation
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
glTexGenfv(GL_S, GL_OBJECT_PLANE, paramsX);
glTexGenfv(GL_T, GL_OBJECT_PLANE, paramsY);
// shift the lightmap half a tile as lights are supposed to be placed at the center of a tile
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glTranslatef(1.0/lightmapWidth/2, 1.0/lightmapHeight/2, 0);
glMatrixMode(GL_MODELVIEW);
glActiveTexture(GL_TEXTURE0);
//////////////////////////////////////
// canvas to draw on
glDisable(GL_TEXTURE_2D);
pie_SetTexturePage(TEXPAGE_NONE);
pie_SetRendMode(REND_OPAQUE);
// we only draw in the depth buffer of using fog of war, as the clear color is black then
if (rendStates.fogEnabled)
if (pie_GetFogStatus())
{
// FIXME: with fog enabled we draw this also to the color buffer. A fogbox might be faster.
glDisable(GL_FOG);
@ -1212,13 +1204,14 @@ void drawTerrain(void)
{
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
}
// draw slightly higher distance than it actually is so it will not
// by accident obscure the actual terrain
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(0.1f, 1.0f);
// bind the vertex buffer
glEnableClientState( GL_VERTEX_ARRAY );
glEnableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, geometryIndexVBO); glError();
glBindBuffer(GL_ARRAY_BUFFER, geometryVBO); glError();
@ -1243,10 +1236,10 @@ void drawTerrain(void)
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
if (rendStates.fogEnabled)
if (pie_GetFogStatus())
{
glEnable(GL_FOG);
glColor4ub(0xFF, 0xFF, 0xFF, 0xFF);
glEnable(GL_FOG); // resync fog state
glColor4ub(0xFF, 0xFF, 0xFF, 0xFF);
}
else
{
@ -1258,10 +1251,9 @@ void drawTerrain(void)
///////////////////////////////////
// terrain
// we are going to use this one
glEnable(GL_TEXTURE_2D);
glEnableClientState( GL_COLOR_ARRAY );
glEnableClientState(GL_COLOR_ARRAY);
// set up for texture coord generation
glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T);
@ -1273,10 +1265,10 @@ void drawTerrain(void)
// only draw colors
glDepthMask(GL_FALSE);
glEnableClientState( GL_VERTEX_ARRAY );
glEnableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, textureIndexVBO); glError();
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
// load the vertex (geometry) buffer
glBindBuffer(GL_ARRAY_BUFFER, geometryVBO);
@ -1289,21 +1281,22 @@ void drawTerrain(void)
// draw each layer separately
for (layer = 0; layer < numGroundTypes; layer++)
{
GLfloat paramsX[4] = {0, 0, -1.0/world_coord(psGroundTypes[layer].textureSize), 0};
GLfloat paramsY[4] = {1.0/world_coord(psGroundTypes[layer].textureSize), 0, 0, 0};
const GLfloat paramsX[4] = {0, 0, -1.0/world_coord(psGroundTypes[layer].textureSize), 0};
const GLfloat paramsY[4] = {1.0/world_coord(psGroundTypes[layer].textureSize), 0, 0, 0};
// load the texture
texPage = iV_GetTexture(psGroundTypes[layer].textureName);
pie_SetTexturePage(texPage);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// set the texture generation parameters
glTexGenfv(GL_S, GL_OBJECT_PLANE, paramsX);
glTexGenfv(GL_T, GL_OBJECT_PLANE, paramsY);
// load the color buffer
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(PIELIGHT), BUFFER_OFFSET(sizeof(PIELIGHT)*xSectors*ySectors*(sectorSize+1)*(sectorSize+1)*2*layer));
for (x = 0; x < xSectors; x++)
{
for (y = 0; y < ySectors; y++)
@ -1324,16 +1317,20 @@ void drawTerrain(void)
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
// we don't need this one anymore
glDisableClientState( GL_COLOR_ARRAY );
glDisableClientState(GL_COLOR_ARRAY);
// no more texture generation
glDisable(GL_TEXTURE_GEN_S); glError();
glDisable(GL_TEXTURE_GEN_T); glError();
#ifdef MESA_BUG
// prevent the terrain from getting corrupted by the decal drawing code
// (something with VBO + changing the texture)
// this happens on radeon + mesa
// FIXME: remove this after the driver is fixed
glFlush();
#endif
//////////////////////////////////
// decals
@ -1342,8 +1339,8 @@ void drawTerrain(void)
// use the alpha to blend
pie_SetRendMode(REND_ALPHA);
// and the texture coordinates buffer
glEnableClientState( GL_TEXTURE_COORD_ARRAY ); glError();
glEnableClientState( GL_VERTEX_ARRAY ); glError();
glEnableClientState(GL_TEXTURE_COORD_ARRAY); glError();
glEnableClientState(GL_VERTEX_ARRAY); glError();
glBindBuffer(GL_ARRAY_BUFFER, decalVBO); glError();
glVertexPointer(3, GL_FLOAT, sizeof(DecalVertex), BUFFER_OFFSET(0)); glError();
glTexCoordPointer(2, GL_FLOAT, sizeof(DecalVertex), BUFFER_OFFSET(12)); glError();
@ -1378,7 +1375,9 @@ void drawTerrain(void)
////////////////////////////////
// disable the lightmap texture
glActiveTexture(GL_TEXTURE1);
pie_SetTexturePage(TEXPAGE_NONE);
glDisable(GL_TEXTURE_2D);
glDisable(GL_TEXTURE_GEN_S);
glDisable(GL_TEXTURE_GEN_T);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glActiveTexture(GL_TEXTURE0);
@ -1386,13 +1385,10 @@ void drawTerrain(void)
glMatrixMode(GL_MODELVIEW);
// leave everything in a sane state so it won't mess up somewhere else
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
glDisableClientState( GL_VERTEX_ARRAY );
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glDepthMask(GL_TRUE);
pie_SetRendMode(REND_OPAQUE);
glPopAttrib();
}
/**
@ -1400,26 +1396,28 @@ void drawTerrain(void)
*/
void drawWater(void)
{
float white[4] = {1.0f, 1.0f, 1.0f, 1.0f};
int x,y;
int x, y;
const GLfloat paramsX[4] = {0, 0, -1.0/world_coord(4), 0};
const GLfloat paramsY[4] = {1.0/world_coord(4), 0, 0, 0};
const GLfloat paramsX2[4] = {0, 0, -1.0/world_coord(5), 0};
const GLfloat paramsY2[4] = {1.0/world_coord(5), 0, 0, 0};
glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TEXTURE_BIT | GL_DEPTH_BUFFER_BIT | GL_FOG_BIT);
const GLfloat white[4] = {1.0f, 1.0f, 1.0f, 1.0f};
const GLfloat fogColour[4] = {pie_GetFogColour().byte.r/255.f,
pie_GetFogColour().byte.g/255.f,
pie_GetFogColour().byte.b/255.f,
pie_GetFogColour().byte.a/255.f};
glEnable(GL_TEXTURE_GEN_S); glError();
glEnable(GL_TEXTURE_GEN_T); glError();
glColor4ub(0xFF, 0xFF, 0xFF, 0xFF);
glDepthMask(GL_FALSE);
if (rendStates.fogEnabled)
if (pie_GetFogStatus())
{
glFogfv(GL_FOG_COLOR, white);
}
// first texture unit
pie_SetTexturePage(iV_GetTexture("page-80")); glError();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
@ -1434,10 +1432,11 @@ void drawWater(void)
// multiplicative blending
pie_SetRendMode(REND_MULTIPLICATIVE);
// second texture unit
glActiveTexture(GL_TEXTURE1);
pie_SetTexturePage(iV_GetTexture("page-81")); glError();
glBindTexture(GL_TEXTURE_2D, iV_NativeTexID(iV_GetTexture("page-81")));
glError();
glEnable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glEnable(GL_TEXTURE_GEN_S); glError();
@ -1452,7 +1451,7 @@ void drawWater(void)
glTranslatef(-waterOffset, 0, 0);
// bind the vertex buffer
glEnableClientState( GL_VERTEX_ARRAY );
glEnableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, waterIndexVBO); glError();
glBindBuffer(GL_ARRAY_BUFFER, waterVBO); glError();
@ -1477,7 +1476,7 @@ void drawWater(void)
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDisableClientState( GL_VERTEX_ARRAY );
glDisableClientState(GL_VERTEX_ARRAY);
// move the water
if(!gamePaused())
@ -1492,14 +1491,17 @@ void drawWater(void)
glDisable(GL_TEXTURE_GEN_T);
glActiveTexture(GL_TEXTURE0);
if (pie_GetFogStatus())
{
glFogfv(GL_FOG_COLOR, fogColour); // resync fog state
}
// clean up
glDisable(GL_TEXTURE_GEN_S);
glDisable(GL_TEXTURE_GEN_T);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glDepthMask(GL_TRUE);
glLoadIdentity();
glDisable(GL_TEXTURE_GEN_S);
glDisable(GL_TEXTURE_GEN_T);
glMatrixMode(GL_MODELVIEW);
glDisable(GL_TEXTURE_GEN_S);
glDisable(GL_TEXTURE_GEN_T);
glPopAttrib();
}