|
void MeshShadows(unsigned char *lightmap, int lightmapSize, unsigned char shadowColor[3], float lightDir[3])
{
// variable initialization
int lightmapChunkSize = 128;
if(lightmapSize < lightmapChunkSize) lightmapChunkSize = lightmapSize;
float terrainDivisions = lightmapSize / lightmapChunkSize;
int terrainChunkSize = Terrain.size() / terrainDivisions;
unsigned char *chunk = new unsigned char[(lightmapChunkSize)*(lightmapChunkSize)*3];
// create shadow texture
GLuint shadowChunk;
glGenTextures(1, &shadowChunk);
glBindTexture(GL_TEXTURE_2D, shadowChunk);
glEnable(GL_TEXTURE_2D);
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, lightmapChunkSize, lightmapChunkSize, 0);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
int terrainCol = 0;
int terrainRow = 0;
float x0 = 0;
float y0 = 0;
float x1 = terrainChunkSize;
float y1 = terrainChunkSize;
for(terrainRow = 0; terrainRow < terrainDivisions; terrainRow++)
{
for(terrainCol = 0; terrainCol < terrainDivisions; terrainCol++)
{
// setup orthogonal view
glViewport(0, 0, terrainChunkSize * Terrain.size(), terrainChunkSize * Terrain.size());
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, terrainChunkSize, 0, terrainChunkSize, -10000, 10000);
glMatrixMode(GL_MODELVIEW);
// apply light's direction to modelview matrix
gluLookAt(lightDir[0], lightDir[1], lightDir[2], 0, 0, 0, 0, 1, 0);
// loop through all vertices in terrain and find min and max points with respect to screen space
float minX = 999999, maxX = -999999;
float minY = 999999, maxY = -999999;
double X, Y, Z;
// get pointer to terrain vertices
float *vertices = Terrain.vertices()->lock();
for(int i = y0-1; i < y1+1; i++)
{
if(i < 0) continue;
for(int j = x0-1; j < x1+1; j++)
{
if(j < 0) continue;
int index = i * Terrain.size() + j;
// get screen coordinates for current vertex
static GLint viewport[4];
static GLdouble modelview[16];
static GLdouble projection[16];
static GLfloat winX, winY, winZ;
glGetDoublev( GL_MODELVIEW_MATRIX, modelview );
glGetDoublev( GL_PROJECTION_MATRIX, projection );
glGetIntegerv( GL_VIEWPORT, viewport );
gluProject(vertices[index*3+0], vertices[index*3+1], vertices[index*3+2], modelview, projection, viewport, &X, &Y, &Z);
if(X < minX) minX = X;
if(X > maxX) maxX = X;
if(Y < minY) minY = Y;
if(Y > maxY) maxY = Y;
}
}
// clear min and max values
static float minX2, minY2, maxX2, maxY2;
minX2 = minX;
minY2 = minY;
maxX2 = maxX;
maxY2 = maxY;
// clear screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, lightmapChunkSize, lightmapChunkSize);
// orient viewport so that terrain chunk fits inside
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(minX, maxX, minY, maxY, -10000, 10000);
glMatrixMode(GL_MODELVIEW);
// apply light's direction vector to model view transformation
glLoadIdentity();
gluLookAt(lightDir[0], lightDir[1], lightDir[2], 0, 0, 0, 0, 1, 0);
// disable writing to the color buffer
glColorMask(false, false, false, false);
// render terrain
Terrain.render();
// enable writing to the color buffer
glColorMask(true, true, true, true);
// render scene meshes '''BLACK'''
RenderAllSceneMeshes();
// bind shadowChunk texture and copy frame buffer data
glBindTexture(GL_TEXTURE_2D, shadowChunk);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, lightmapChunkSize, lightmapChunkSize);
glBindTexture(GL_TEXTURE_2D, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, terrainChunkSize * Terrain.size(), terrainChunkSize * Terrain.size());
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 0, terrainChunkSize, terrainChunkSize, -10000, 10000);
glMatrixMode(GL_MODELVIEW);
// rotate view so that xz plane becomes the xy plane
glLoadIdentity();
glRotatef(90, 1, 0, 0);
// reset max and min values
minX = minY = 999999;
maxX = maxY = -999999;
glGetDoublev( GL_MODELVIEW_MATRIX, modelview );
glGetDoublev( GL_PROJECTION_MATRIX, projection );
glGetIntegerv( GL_VIEWPORT, viewport );
// project each corner onto the screen
// the corners are represented by the x0, y0, x1 and y1 values
gluProject(x0, y0, modelview, projection, viewport, &X, &Y, &Z);
if(X < minX) minX = X;
if(X > maxX) maxX = X;
if(Y < minY) minY = Y;
if(Y > maxY) maxY = Y;
gluProject(x1, y0, modelview, projection, viewport, &X, &Y, &Z);
if(X < minX) minX = X;
if(X > maxX) maxX = X;
if(Y < minY) minY = Y;
if(Y > maxY) maxY = Y;
gluProject(x1, y1, modelview, projection, viewport, &X, &Y, &Z);
if(X < minX) minX = X;
if(X > maxX) maxX = X;
if(Y < minY) minY = Y;
if(Y > maxY) maxY = Y;
gluProject(x0, y1, modelview, projection, viewport, &X, &Y, &Z);
if(X < minX) minX = X;
if(X > maxX) maxX = X;
if(Y < minY) minY = Y;
if(Y > maxY) maxY = Y;
// resize and re-orient the viewport
glViewport(0, 0, terrainChunkSize * Terrain.size(), terrainChunkSize * Terrain.size());
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(minX, minY, maxX, maxY, -10000, 10000);
glMatrixMode(GL_MODELVIEW);
// rotate view so that xz plane becomes the xy plane
glLoadIdentity();
glRotatef(90, 1, 0, 0);
// setup projective texturing
float PS[] = {1, 0, 0, 0};
float PT[] = {0, 1, 0, 0};
float PR[] = {0, 0, 1, 0};
float PQ[] = {0, 0, 0, 1};
glTexGenfv(GL_S, GL_EYE_PLANE, PS);
glTexGenfv(GL_T, GL_EYE_PLANE, PT);
glTexGenfv(GL_R, GL_EYE_PLANE, PR);
glTexGenfv(GL_Q, GL_EYE_PLANE, PQ);
glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T);
glEnable(GL_TEXTURE_GEN_R);
glEnable(GL_TEXTURE_GEN_Q);
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
// setup texture matrix
glBindTexture(GL_TEXTURE_2D, shadowChunk);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glTranslatef(0.5, 0.5, 0);
glScalef(0.5, 0.5, 1);
glOrtho(minX2, maxX2, minY2, maxY2, -10000, 10000);
gluLookAt(lightDir[0], lightDir[1], lightDir[2], 0, 0, 0, 0, 1, 0);
glMatrixMode(GL_MODELVIEW);
// render the terrain
Terrain.render();
glBindTexture(GL_TEXTURE_2D, shadowChunk);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, lightmapChunkSize, lightmapChunkSize);
// disable projective texturing
glDisable(GL_TEXTURE_GEN_S);
glDisable(GL_TEXTURE_GEN_T);
glDisable(GL_TEXTURE_GEN_R);
glDisable(GL_TEXTURE_GEN_Q);
// reset texture matrix
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
// get shadow texture data
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);
for(int a = 0; a < lightmapChunkSize; a++)
{
for(int b = 0; b < lightmapChunkSize; b++)
{
int a2 = a + lightmapChunkSize * terrainRow;
int b2 = b + lightmapChunkSize * terrainCol;
lightmap[(a2 * lightmapSize + b2) * 3 + 0] = pixels[(a * lightmapChunkSize + b) * 3 + 0];
lightmap[(a2 * lightmapSize + b2) * 3 + 1] = pixels[(a * lightmapChunkSize + b) * 3 + 1];
lightmap[(a2 * lightmapSize + b2) * 3 + 2] = pixels[(a * lightmapChunkSize + b) * 3 + 2];
}
}
}
}
// increment which section on the terrain we are looking at
x0 += terrainChunkSize;
x1 += terrainChunkSize;
}
x0 = 0;
x1 = terrainChunkSize;
y0 += terrainChunkSize;
y1 += terrainChunkSize;
}
// free memory
glDeleteTextures(1, &shadowTexture);
delete [] pixels;
} |
|