/* Copyright (C) 2006 Parallel Realities This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "bsp.h" #define TESSELATION 10 TextureSpec *getTextureSpec(char *basename) { // ignore this texture if ((strcmp(basename, "textures/common/blank") == 0) || (strcmp(basename, "noshader") == 0) || (strcmp(basename, "textures/NULL") == 0) || (strcmp(basename, "textures/common/nodraw") == 0)) { ////printf("getTextureSpec() - Returning NULL (%s)\n", basename); return NULL; } debug(("getTextureSpec() - %s\n", basename)); TextureSpec *textureSpec; Texture *texture; String filename; textureSpec = textureSpecManager->getTextureSpec(basename); if ((textureSpec != NULL) && (textureSpec->texture != 0)) { debug(("getTextureSpec() - Found spec for %s\n", basename)); return textureSpec; } else if (textureSpec == NULL) { debug(("getTextureSpec() - Building default for %s\n", basename)); textureSpec = textureSpecManager->createDefaultTextureSpec(basename); } filename.setText("%s.jpg", basename); if (pak->getFileLocation(filename.getText()) != FILE_NOT_FOUND) { debug(("getTextureSpec() - Loading Texture %s\n", filename.getText())); texture = graphics->loadTexture(filename.getText()); textureManager->addTexture(filename.getText(), texture); } else { filename.setText("%s.tga", basename); if (pak->getFileLocation(filename.getText()) != FILE_NOT_FOUND) { debug(("getTextureSpec() - Loading Texture %s\n", filename.getText())); texture = graphics->loadTexture(filename.getText()); textureManager->addTexture(filename.getText(), texture); textureSpec->blended = true; //textureSpec->blendSource = GL_SRC_ALPHA; //textureSpec->blendDest = GL_ONE_MINUS_SRC_ALPHA; } else { //graphics->showErrorAndExit("Could not load texture '%s' as JPG or TGA", filename.getText()); printf("WARNING - Couldn't load texture '%s'. Using Metal instead!\n", basename); texture = textureManager->getTexture("Metal"); texture = graphics->loadTexture("textures/mech/metal05.jpg"); textureManager->addTexture("Metal", texture); } } textureSpec->texture = texture->data; return textureSpec; } int tesselate(BSPBiQuadraticPatch *quadPatch) { int u, v, row, point; float px, py; BSPVertex temp[3]; bsp->tesselation = TESSELATION; quadPatch->verts = (BSPVertex *)malloc((bsp->tesselation + 1) * (bsp->tesselation + 1) * sizeof(BSPVertex)); if (quadPatch->verts == NULL) { graphics->showErrorAndExit("BSP - Failed to allocate %ld bytes for tesselation", (bsp->tesselation + 1) * (bsp->tesselation + 1) * sizeof(BSPVertex)); } for (v=0;v<=bsp->tesselation;v++) { px = (float)v / bsp->tesselation; quadPatch->verts[v].position.x = quadPatch->controlPoints[0].position.x * ((1.0f - px) * (1.0f - px)) + quadPatch->controlPoints[3].position.x * ((1.0f - px) * px * 2) + quadPatch->controlPoints[6].position.x * (px * px); quadPatch->verts[v].position.y = quadPatch->controlPoints[0].position.y * ((1.0f - px) * (1.0f - px)) + quadPatch->controlPoints[3].position.y * ((1.0f - px) * px * 2) + quadPatch->controlPoints[6].position.y * (px * px); quadPatch->verts[v].position.z = quadPatch->controlPoints[0].position.z * ((1.0f - px) * (1.0f - px)) + quadPatch->controlPoints[3].position.z * ((1.0f - px) * px * 2) + quadPatch->controlPoints[6].position.z * (px * px); quadPatch->verts[v].textureCoord.x = quadPatch->controlPoints[0].textureCoord.x * ((1.0f - px) * (1.0f - px)) + quadPatch->controlPoints[3].textureCoord.x * ((1.0f - px) * px * 2) + quadPatch->controlPoints[6].textureCoord.x * (px * px); quadPatch->verts[v].textureCoord.y = quadPatch->controlPoints[0].textureCoord.y * ((1.0f - px) * (1.0f - px)) + quadPatch->controlPoints[3].textureCoord.y * ((1.0f - px) * px * 2) + quadPatch->controlPoints[6].textureCoord.y * (px * px); quadPatch->verts[v].lightmapCoord.x = quadPatch->controlPoints[0].lightmapCoord.x * ((1.0f - px) * (1.0f - px)) + quadPatch->controlPoints[3].lightmapCoord.x * ((1.0f - px) * px * 2) + quadPatch->controlPoints[6].lightmapCoord.x * (px * px); quadPatch->verts[v].lightmapCoord.y = quadPatch->controlPoints[0].lightmapCoord.y * ((1.0f - px) * (1.0f - px)) + quadPatch->controlPoints[3].lightmapCoord.y * ((1.0f - px) * px * 2) + quadPatch->controlPoints[6].lightmapCoord.y * (px * px); quadPatch->verts[v].normal.x = quadPatch->controlPoints[0].normal.x * ((1.0f - px) * (1.0f - px)) + quadPatch->controlPoints[3].normal.x * ((1.0f - px) * px * 2) + quadPatch->controlPoints[6].normal.x * (px * px); quadPatch->verts[v].normal.y = quadPatch->controlPoints[0].normal.y * ((1.0f - px) * (1.0f - px)) + quadPatch->controlPoints[3].normal.y * ((1.0f - px) * px * 2) + quadPatch->controlPoints[6].normal.y * (px * px); quadPatch->verts[v].normal.z = quadPatch->controlPoints[0].normal.z * ((1.0f - px) * (1.0f - px)) + quadPatch->controlPoints[3].normal.z * ((1.0f - px) * px * 2) + quadPatch->controlPoints[6].normal.z * (px * px); } for (u=1;u<=bsp->tesselation;u++) { py = (float)u / bsp->tesselation; temp[0].position.x = quadPatch->controlPoints[0].position.x * ((1.0f - py) * (1.0f - py)) + quadPatch->controlPoints[1].position.x * ((1.0f - py) * py * 2) + quadPatch->controlPoints[2].position.x * (py * py); temp[0].position.y = quadPatch->controlPoints[0].position.y * ((1.0f - py) * (1.0f - py)) + quadPatch->controlPoints[1].position.y * ((1.0f - py) * py * 2) + quadPatch->controlPoints[2].position.y * (py * py); temp[0].position.z = quadPatch->controlPoints[0].position.z * ((1.0f - py) * (1.0f - py)) + quadPatch->controlPoints[1].position.z * ((1.0f - py) * py * 2) + quadPatch->controlPoints[2].position.z * (py * py); temp[1].position.x = quadPatch->controlPoints[3].position.x * ((1.0f - py) * (1.0f - py)) + quadPatch->controlPoints[4].position.x * ((1.0f - py) * py * 2) + quadPatch->controlPoints[5].position.x * (py * py); temp[1].position.y = quadPatch->controlPoints[3].position.y * ((1.0f - py) * (1.0f - py)) + quadPatch->controlPoints[4].position.y * ((1.0f - py) * py * 2) + quadPatch->controlPoints[5].position.y * (py * py); temp[1].position.z = quadPatch->controlPoints[3].position.z * ((1.0f - py) * (1.0f - py)) + quadPatch->controlPoints[4].position.z * ((1.0f - py) * py * 2) + quadPatch->controlPoints[5].position.z * (py * py); temp[2].position.x = quadPatch->controlPoints[6].position.x * ((1.0f - py) * (1.0f - py)) + quadPatch->controlPoints[7].position.x * ((1.0f - py) * py * 2) + quadPatch->controlPoints[8].position.x * (py * py); temp[2].position.y = quadPatch->controlPoints[6].position.y * ((1.0f - py) * (1.0f - py)) + quadPatch->controlPoints[7].position.y * ((1.0f - py) * py * 2) + quadPatch->controlPoints[8].position.y * (py * py); temp[2].position.z = quadPatch->controlPoints[6].position.z * ((1.0f - py) * (1.0f - py)) + quadPatch->controlPoints[7].position.z * ((1.0f - py) * py * 2) + quadPatch->controlPoints[8].position.z * (py * py); temp[0].textureCoord.x = quadPatch->controlPoints[0].textureCoord.x * ((1.0f - py) * (1.0f - py)) + quadPatch->controlPoints[1].textureCoord.x * ((1.0f - py) * py * 2) + quadPatch->controlPoints[2].textureCoord.x * (py * py); temp[0].textureCoord.y = quadPatch->controlPoints[0].textureCoord.y * ((1.0f - py) * (1.0f - py)) + quadPatch->controlPoints[1].textureCoord.y * ((1.0f - py) * py * 2) + quadPatch->controlPoints[2].textureCoord.y * (py * py); temp[1].textureCoord.x = quadPatch->controlPoints[3].textureCoord.x * ((1.0f - py) * (1.0f - py)) + quadPatch->controlPoints[4].textureCoord.x * ((1.0f - py) * py * 2) + quadPatch->controlPoints[5].textureCoord.x * (py * py); temp[1].textureCoord.y = quadPatch->controlPoints[3].textureCoord.y * ((1.0f - py) * (1.0f - py)) + quadPatch->controlPoints[4].textureCoord.y * ((1.0f - py) * py * 2) + quadPatch->controlPoints[5].textureCoord.y * (py * py); temp[2].textureCoord.x = quadPatch->controlPoints[6].textureCoord.x * ((1.0f - py) * (1.0f - py)) + quadPatch->controlPoints[7].textureCoord.x * ((1.0f - py) * py * 2) + quadPatch->controlPoints[8].textureCoord.x * (py * py); temp[2].textureCoord.y = quadPatch->controlPoints[6].textureCoord.y * ((1.0f - py) * (1.0f - py)) + quadPatch->controlPoints[7].textureCoord.y * ((1.0f - py) * py * 2) + quadPatch->controlPoints[8].textureCoord.y * (py * py); temp[0].lightmapCoord.x = quadPatch->controlPoints[0].lightmapCoord.x * ((1.0f - py) * (1.0f - py)) + quadPatch->controlPoints[1].lightmapCoord.x * ((1.0f - py) * py * 2) + quadPatch->controlPoints[2].lightmapCoord.x * (py * py); temp[0].lightmapCoord.y = quadPatch->controlPoints[0].lightmapCoord.y * ((1.0f - py) * (1.0f - py)) + quadPatch->controlPoints[1].lightmapCoord.y * ((1.0f - py) * py * 2) + quadPatch->controlPoints[2].lightmapCoord.y * (py * py); temp[1].lightmapCoord.x = quadPatch->controlPoints[3].lightmapCoord.x * ((1.0f - py) * (1.0f - py)) + quadPatch->controlPoints[4].lightmapCoord.x * ((1.0f - py) * py * 2) + quadPatch->controlPoints[5].lightmapCoord.x * (py * py); temp[1].lightmapCoord.y = quadPatch->controlPoints[3].lightmapCoord.y * ((1.0f - py) * (1.0f - py)) + quadPatch->controlPoints[4].lightmapCoord.y * ((1.0f - py) * py * 2) + quadPatch->controlPoints[5].lightmapCoord.y * (py * py); temp[2].lightmapCoord.x = quadPatch->controlPoints[6].lightmapCoord.x * ((1.0f - py) * (1.0f - py)) + quadPatch->controlPoints[7].lightmapCoord.x * ((1.0f - py) * py * 2) + quadPatch->controlPoints[8].lightmapCoord.x * (py * py); temp[2].lightmapCoord.y = quadPatch->controlPoints[6].lightmapCoord.y * ((1.0f - py) * (1.0f - py)) + quadPatch->controlPoints[7].lightmapCoord.y * ((1.0f - py) * py * 2) + quadPatch->controlPoints[8].lightmapCoord.y * (py * py); temp[0].normal.x = quadPatch->controlPoints[0].normal.x * ((1.0f - py) * (1.0f - py)) + quadPatch->controlPoints[1].normal.x * ((1.0f - py) * py * 2) + quadPatch->controlPoints[2].normal.x * (py * py); temp[0].normal.y = quadPatch->controlPoints[0].normal.y * ((1.0f - py) * (1.0f - py)) + quadPatch->controlPoints[1].normal.y * ((1.0f - py) * py * 2) + quadPatch->controlPoints[2].normal.y * (py * py); temp[0].normal.z = quadPatch->controlPoints[0].normal.z * ((1.0f - py) * (1.0f - py)) + quadPatch->controlPoints[1].normal.z * ((1.0f - py) * py * 2) + quadPatch->controlPoints[2].normal.z * (py * py); temp[1].normal.x = quadPatch->controlPoints[3].normal.x * ((1.0f - py) * (1.0f - py)) + quadPatch->controlPoints[4].normal.x * ((1.0f - py) * py * 2) + quadPatch->controlPoints[5].normal.x * (py * py); temp[1].normal.y = quadPatch->controlPoints[3].normal.y * ((1.0f - py) * (1.0f - py)) + quadPatch->controlPoints[4].normal.y * ((1.0f - py) * py * 2) + quadPatch->controlPoints[5].normal.y * (py * py); temp[1].normal.z = quadPatch->controlPoints[3].normal.z * ((1.0f - py) * (1.0f - py)) + quadPatch->controlPoints[4].normal.z * ((1.0f - py) * py * 2) + quadPatch->controlPoints[5].normal.z * (py * py); temp[2].normal.x = quadPatch->controlPoints[6].normal.x * ((1.0f - py) * (1.0f - py)) + quadPatch->controlPoints[7].normal.x * ((1.0f - py) * py * 2) + quadPatch->controlPoints[8].normal.x * (py * py); temp[2].normal.y = quadPatch->controlPoints[6].normal.y * ((1.0f - py) * (1.0f - py)) + quadPatch->controlPoints[7].normal.y * ((1.0f - py) * py * 2) + quadPatch->controlPoints[8].normal.y * (py * py); temp[2].normal.z = quadPatch->controlPoints[6].normal.z * ((1.0f - py) * (1.0f - py)) + quadPatch->controlPoints[7].normal.z * ((1.0f - py) * py * 2) + quadPatch->controlPoints[8].normal.z * (py * py); for(v=0;v<=bsp->tesselation;v++) { px = (float)v / bsp->tesselation; quadPatch->verts[u * (bsp->tesselation + 1) + v].position.x = temp[0].position.x * ((1.0f - px) * (1.0f - px)) + temp[1].position.x * ((1.0f - px) * px * 2) + temp[2].position.x * (px * px); quadPatch->verts[u * (bsp->tesselation + 1) + v].position.y = temp[0].position.y * ((1.0f - px) * (1.0f - px)) + temp[1].position.y * ((1.0f - px) * px * 2) + temp[2].position.y * (px * px); quadPatch->verts[u * (bsp->tesselation + 1) + v].position.z = temp[0].position.z * ((1.0f - px) * (1.0f - px)) + temp[1].position.z * ((1.0f - px) * px * 2) + temp[2].position.z * (px * px); quadPatch->verts[u * (bsp->tesselation + 1) + v].textureCoord.x = temp[0].textureCoord.x * ((1.0f - px) * (1.0f - px)) + temp[1].textureCoord.x * ((1.0f - px) * px * 2) + temp[2].textureCoord.x * (px * px); quadPatch->verts[u * (bsp->tesselation + 1) + v].textureCoord.y = temp[0].textureCoord.y * ((1.0f - px) * (1.0f - px)) + temp[1].textureCoord.y * ((1.0f - px) * px * 2) + temp[2].textureCoord.y * (px * px); quadPatch->verts[u * (bsp->tesselation + 1) + v].lightmapCoord.x = temp[0].lightmapCoord.x * ((1.0f - px) * (1.0f - px)) + temp[1].lightmapCoord.x * ((1.0f - px) * px * 2) + temp[2].lightmapCoord.x * (px * px); quadPatch->verts[u * (bsp->tesselation + 1) + v].lightmapCoord.y = temp[0].lightmapCoord.y * ((1.0f - px) * (1.0f - px)) + temp[1].lightmapCoord.y * ((1.0f - px) * px * 2) + temp[2].lightmapCoord.y * (px * px); quadPatch->verts[u * (bsp->tesselation + 1) + v].normal.x = temp[0].normal.x * ((1.0f - px) * (1.0f - px)) + temp[1].normal.x * ((1.0f - px) * px * 2) + temp[2].normal.x * (px * px); quadPatch->verts[u * (bsp->tesselation + 1) + v].normal.y = temp[0].normal.y * ((1.0f - px) * (1.0f - px)) + temp[1].normal.y * ((1.0f - px) * px * 2) + temp[2].normal.y * (px * px); quadPatch->verts[u * (bsp->tesselation + 1) + v].normal.z = temp[0].normal.z * ((1.0f - px) * (1.0f - px)) + temp[1].normal.z * ((1.0f - px) * px * 2) + temp[2].normal.z * (px * px); } } quadPatch->indices = (unsigned int *)malloc(bsp->tesselation * (bsp->tesselation + 1) * 2 * sizeof(unsigned int)); if (quadPatch->indices == NULL) { graphics->showErrorAndExit("BSP - Failed to allocate %ld bytes for indices", bsp->tesselation * (bsp->tesselation + 1) * 2 * sizeof(unsigned int)); } for (row=0;rowtesselation;row++) { for (point=0;point<=bsp->tesselation;point++) { quadPatch->indices[(row * (bsp->tesselation + 1) + point) * 2 + 1] = row * (bsp->tesselation + 1) + point; quadPatch->indices[(row * (bsp->tesselation + 1) + point) * 2] =(row + 1) * (bsp->tesselation + 1) + point; } } quadPatch->trianglesPerRow = (int *)malloc(bsp->tesselation * sizeof(int)); quadPatch->rowIndexPointers = (unsigned int **)malloc(bsp->tesselation * sizeof(unsigned int *)); if (quadPatch->trianglesPerRow == NULL) { graphics->showErrorAndExit("BSP - Failed to allocate %ld bytes for trianglesPerRow", bsp->tesselation * sizeof(int)); } if (quadPatch->rowIndexPointers == NULL) { graphics->showErrorAndExit("BSP - Failed to allocate %ld bytes for rowIndexPointers", bsp->tesselation * sizeof(unsigned int)); } for (row=0;rowtesselation;row++) { quadPatch->trianglesPerRow[row] = 2 * (bsp->tesselation + 1); quadPatch->rowIndexPointers[row] = &quadPatch->indices[row * 2 * (bsp->tesselation + 1)]; } return 0; } int loadVertices(FILE *fp, BSPLump *lumps) { int i; bsp->numOfVerts = lumps[kVertices].length / sizeof(BSPVertex); bsp->verts = (BSPVertex *)malloc(bsp->numOfVerts * sizeof(BSPVertex)); if (bsp->verts == NULL) { return 1; } fseek(fp, lumps[kVertices].offset, SEEK_SET); bsp->minCords.set(RAND_MAX, RAND_MAX, RAND_MAX); bsp->maxCords.set(-RAND_MAX, -RAND_MAX, -RAND_MAX); for (i=0;inumOfVerts;i++) { fread(&bsp->verts[i], 1, sizeof(BSPVertex), fp); #if SDL_BYTEORDER != SDL_LIL_ENDIAN bsp->verts[i].position.x = swapBytes(bsp->verts[i].position.x); bsp->verts[i].position.y = swapBytes(bsp->verts[i].position.y); bsp->verts[i].position.z = swapBytes(bsp->verts[i].position.z); bsp->verts[i].textureCoord.x = swapBytes(bsp->verts[i].textureCoord.x); bsp->verts[i].textureCoord.y = swapBytes(bsp->verts[i].textureCoord.y); bsp->verts[i].lightmapCoord.x = swapBytes(bsp->verts[i].lightmapCoord.x); bsp->verts[i].lightmapCoord.y = swapBytes(bsp->verts[i].lightmapCoord.y); bsp->verts[i].normal.x = swapBytes(bsp->verts[i].normal.x); bsp->verts[i].normal.y = swapBytes(bsp->verts[i].normal.y); bsp->verts[i].normal.z = swapBytes(bsp->verts[i].normal.z); bsp->verts[i].color[0] = SDL_SwapLE32(bsp->verts[i].color[0]); bsp->verts[i].color[1] = SDL_SwapLE32(bsp->verts[i].color[1]); bsp->verts[i].color[2] = SDL_SwapLE32(bsp->verts[i].color[2]); bsp->verts[i].color[3] = SDL_SwapLE32(bsp->verts[i].color[3]); #endif bsp->minCords.x = min(bsp->verts[i].position.x, bsp->minCords.x); bsp->minCords.y = min(bsp->verts[i].position.y, bsp->minCords.y); bsp->minCords.z = min(bsp->verts[i].position.z, bsp->minCords.z); bsp->maxCords.x = max(bsp->verts[i].position.x, bsp->maxCords.x); bsp->maxCords.y = max(bsp->verts[i].position.y, bsp->maxCords.y); bsp->maxCords.z = max(bsp->verts[i].position.z, bsp->maxCords.z); } return 0; } int loadFaces(FILE *fp, BSPLump *lumps) { int i; bsp->numOfFaces = lumps[kFaces].length / sizeof(BSPFace); bsp->faces = (BSPFace *)malloc(bsp->numOfFaces * sizeof(BSPFace)); if (bsp->faces == NULL) { return 1; } fseek(fp, lumps[kFaces].offset, SEEK_SET); fread(bsp->faces, bsp->numOfFaces, sizeof(BSPFace), fp); for (i=0;inumOfFaces;i++) { #if SDL_BYTEORDER != SDL_LIL_ENDIAN bsp->faces[i].textureID = SDL_SwapLE32(bsp->faces[i].textureID); bsp->faces[i].effect = SDL_SwapLE32(bsp->faces[i].effect); bsp->faces[i].type = SDL_SwapLE32(bsp->faces[i].type); bsp->faces[i].startVertIndex = SDL_SwapLE32(bsp->faces[i].startVertIndex); bsp->faces[i].numOfVerts = SDL_SwapLE32(bsp->faces[i].numOfVerts); bsp->faces[i].meshVertIndex = SDL_SwapLE32(bsp->faces[i].meshVertIndex); bsp->faces[i].numMeshVerts = SDL_SwapLE32(bsp->faces[i].numMeshVerts); bsp->faces[i].lightmapID = SDL_SwapLE32(bsp->faces[i].lightmapID); bsp->faces[i].lMapCorner[0] = SDL_SwapLE32(bsp->faces[i].lMapCorner[0]); bsp->faces[i].lMapCorner[1] = SDL_SwapLE32(bsp->faces[i].lMapCorner[1]); bsp->faces[i].lMapSize[0] = SDL_SwapLE32(bsp->faces[i].lMapSize[0]); bsp->faces[i].lMapSize[1] = SDL_SwapLE32(bsp->faces[i].lMapSize[1]); bsp->faces[i].lMapPos.x = swapBytes(bsp->faces[i].lMapPos.x); bsp->faces[i].lMapPos.y = swapBytes(bsp->faces[i].lMapPos.y); bsp->faces[i].lMapPos.z = swapBytes(bsp->faces[i].lMapPos.z); bsp->faces[i].lMapVecs[0].x = swapBytes(bsp->faces[i].lMapVecs[0].x); bsp->faces[i].lMapVecs[0].y = swapBytes(bsp->faces[i].lMapVecs[0].y); bsp->faces[i].lMapVecs[0].z = swapBytes(bsp->faces[i].lMapVecs[0].z); bsp->faces[i].lMapVecs[1].x = swapBytes(bsp->faces[i].lMapVecs[1].x); bsp->faces[i].lMapVecs[1].y = swapBytes(bsp->faces[i].lMapVecs[1].y); bsp->faces[i].lMapVecs[1].z = swapBytes(bsp->faces[i].lMapVecs[1].z); bsp->faces[i].vNormal.x = swapBytes(bsp->faces[i].vNormal.x); bsp->faces[i].vNormal.y = swapBytes(bsp->faces[i].vNormal.y); bsp->faces[i].vNormal.z = swapBytes(bsp->faces[i].vNormal.z); bsp->faces[i].size[0] = SDL_SwapLE32(bsp->faces[i].size[0]); bsp->faces[i].size[1] = SDL_SwapLE32(bsp->faces[i].size[1]); #endif } return 0; } int loadMeshes(FILE *fp, BSPLump *lumps) { int i; bsp->numOfMeshIndices = lumps[kMeshVerts].length / sizeof(int); bsp->meshIndices = (int *)malloc(bsp->numOfMeshIndices * sizeof(int)); if (bsp->meshIndices == NULL) { return 1; } fseek(fp, lumps[kMeshVerts].offset, SEEK_SET); fread(bsp->meshIndices, bsp->numOfMeshIndices, sizeof(int), fp); for (i=0;inumOfMeshIndices;i++) { bsp->meshIndices[i] = SDL_SwapLE32(bsp->meshIndices[i]); } return 0; } int loadTextures(FILE *fp, BSPLump *lumps) { bsp->numOfTextures = lumps[kTextures].length / sizeof(BSPTexture); bsp->textures = (BSPTexture *)malloc(bsp->numOfTextures * sizeof(BSPTexture)); if (bsp->textures == NULL) { fclose(fp); graphics->showErrorAndExit("BSP - Failed to allocate %ld bytes for textures", bsp->numOfTextures * sizeof(BSPTexture)); } bsp->textureSpec = (TextureSpec **)malloc(bsp->numOfTextures * sizeof(TextureSpec *)); if (bsp->textureSpec == NULL) { fclose(fp); graphics->showErrorAndExit("BSP - Failed to allocate %ld bytes for texture validation", bsp->numOfTextures * sizeof(TextureSpec)); } fseek(fp, lumps[kTextures].offset, SEEK_SET); fread(bsp->textures, bsp->numOfTextures, sizeof(BSPTexture), fp); memset(bsp->textureSpec, 0, sizeof(TextureSpec *) * bsp->numOfTextures); for (int i = 0 ; i < bsp->numOfTextures ; i++) { bsp->textureSpec[i] = getTextureSpec(bsp->textures[i].strName); bsp->textures[i].flags = SDL_SwapLE32(bsp->textures[i].flags); bsp->textures[i].contents = SDL_SwapLE32(bsp->textures[i].contents); if (bsp->textureSpec[i] != NULL) { //bsp->textures[i].contents = bsp->textureSpec[i]->contents; } } return 0; } int loadLightmaps(FILE *fp, BSPLump *lumps) { int i, j; float temp, gamma, r, g, b, scale, white[4]; BSPLightmap *lightmaps; bsp->numOfLightmaps = lumps[kLightmaps].length / sizeof(BSPLightmap); debug(("BSP: %d lightmaps\n", bsp->numOfLightmaps)); lightmaps = (BSPLightmap *)malloc(bsp->numOfLightmaps * sizeof(BSPLightmap)); if (lightmaps == NULL) { return 1; } fseek(fp, lumps[kLightmaps].offset, SEEK_SET); fread(lightmaps, bsp->numOfLightmaps, sizeof(BSPLightmap), fp); bsp->lightmapTextures = (unsigned int *)malloc(bsp->numOfLightmaps * sizeof(unsigned int)); if (bsp->lightmapTextures == NULL) { return 1; } glGenTextures(bsp->numOfLightmaps, bsp->lightmapTextures); white[0] = 1.0f; white[1] = 1.0f; white[2] = 1.0f; white[3] = 1.0f; gamma = 2.5f; for (i=0;inumOfLightmaps;i++) { for (j=0;j<128*128;j++) { scale = 1.0f; r = lightmaps[i].lightmapData[j * 3 + 0]; g = lightmaps[i].lightmapData[j * 3 + 1]; b = lightmaps[i].lightmapData[j * 3 + 2]; r *= gamma / 255.0f; g *= gamma / 255.0f; b *= gamma / 255.0f; if (r > 1.0f && (temp = (1.0f / r)) < scale) { scale = temp; } if (g > 1.0f && (temp = (1.0f / g)) < scale) { scale = temp; } if (b > 1.0f && (temp = (1.0f / b)) < scale) { scale = temp; } scale *= 255.0f; r *= scale; g *= scale; b *= scale; Math::limit(&r, 0, 128); Math::limit(&g, 0, 128); Math::limit(&b, 0, 128); lightmaps[i].lightmapData[j * 3 + 0] = (GLubyte)r; lightmaps[i].lightmapData[j * 3 + 1] = (GLubyte)g; lightmaps[i].lightmapData[j * 3 + 2] = (GLubyte)b; } } for (i=0;inumOfLightmaps;i++) { glBindTexture(GL_TEXTURE_2D, bsp->lightmapTextures[i]); gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA8, 128, 128, GL_RGB, GL_UNSIGNED_BYTE, lightmaps[i].lightmapData); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); } glGenTextures(1, &bsp->whiteTexture); glBindTexture(GL_TEXTURE_2D, bsp->whiteTexture); gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA8, 1, 1, GL_RGB, GL_FLOAT, white); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); free(lightmaps); return 0; } int loadNodes(FILE *fp, BSPLump *lumps) { int i; bsp->numOfNodes = lumps[kNodes].length / sizeof(BSPNode); bsp->nodes = (BSPNode *)malloc(bsp->numOfNodes * sizeof(BSPNode)); if (bsp->nodes == NULL) { return 1; } fseek(fp, lumps[kNodes].offset, SEEK_SET); fread(bsp->nodes, bsp->numOfNodes, sizeof(BSPNode), fp); for (i=0;inumOfNodes;i++) { bsp->nodes[i].plane = SDL_SwapLE32(bsp->nodes[i].plane); bsp->nodes[i].children[0] = SDL_SwapLE32(bsp->nodes[i].children[0]); bsp->nodes[i].children[1] = SDL_SwapLE32(bsp->nodes[i].children[1]); bsp->nodes[i].min.x = SDL_SwapLE32(bsp->nodes[i].min.x); bsp->nodes[i].min.y = SDL_SwapLE32(bsp->nodes[i].min.y); bsp->nodes[i].min.z = SDL_SwapLE32(bsp->nodes[i].min.z); bsp->nodes[i].max.x = SDL_SwapLE32(bsp->nodes[i].max.x); bsp->nodes[i].max.y = SDL_SwapLE32(bsp->nodes[i].max.y); bsp->nodes[i].max.z = SDL_SwapLE32(bsp->nodes[i].max.z); } return 0; } int loadLeafs(FILE *fp, BSPLump *lumps) { int i; bsp->numOfLeafs = lumps[kLeafs].length / sizeof(BSPLeaf); bsp->leafs = (BSPLeaf *)malloc(bsp->numOfLeafs * sizeof(BSPLeaf)); if (bsp->leafs == NULL) { return 1; } fseek(fp, lumps[kLeafs].offset, SEEK_SET); fread(bsp->leafs, bsp->numOfLeafs, sizeof(BSPLeaf), fp); for (i=0;inumOfLeafs;i++) { bsp->leafs[i].cluster = SDL_SwapLE32(bsp->leafs[i].cluster); bsp->leafs[i].area = SDL_SwapLE32(bsp->leafs[i].area); bsp->leafs[i].leafFace = SDL_SwapLE32(bsp->leafs[i].leafFace); bsp->leafs[i].numOfLeafFaces = SDL_SwapLE32(bsp->leafs[i].numOfLeafFaces); bsp->leafs[i].leafBrush = SDL_SwapLE32(bsp->leafs[i].leafBrush); bsp->leafs[i].numOfLeafBrushes = SDL_SwapLE32(bsp->leafs[i].numOfLeafBrushes); bsp->leafs[i].min.x = SDL_SwapLE32(bsp->leafs[i].min.x); bsp->leafs[i].min.y = SDL_SwapLE32(bsp->leafs[i].min.y); bsp->leafs[i].min.z = SDL_SwapLE32(bsp->leafs[i].min.z); bsp->leafs[i].max.x = SDL_SwapLE32(bsp->leafs[i].max.x); bsp->leafs[i].max.y = SDL_SwapLE32(bsp->leafs[i].max.y); bsp->leafs[i].max.z = SDL_SwapLE32(bsp->leafs[i].max.z); } return 0; } int loadEntities(FILE *fp, BSPLump *lumps) { bsp->numOfEntityChars = lumps[kEntities].length / sizeof(char); bsp->strEntities = (char *)malloc(bsp->numOfEntityChars * sizeof(char)); if (bsp->strEntities == NULL) { return 1; } fseek(fp, lumps[kEntities].offset, SEEK_SET); fread(bsp->strEntities, bsp->numOfEntityChars, sizeof(char), fp); return 0; } int loadLeafFaces(FILE *fp, BSPLump *lumps) { int i; bsp->numOfLeafFaces = lumps[kLeafFaces].length / sizeof(int); bsp->leafFaces = (int *)malloc(bsp->numOfLeafFaces * sizeof(int)); if (bsp->leafFaces == NULL) { return 1; } fseek(fp, lumps[kLeafFaces].offset, SEEK_SET); fread(bsp->leafFaces, bsp->numOfLeafFaces, sizeof(int), fp); for (i=0;inumOfLeafFaces;i++) { bsp->leafFaces[i] = SDL_SwapLE32(bsp->leafFaces[i]); } return 0; } int loadPlanes(FILE *fp, BSPLump *lumps) { int i; bsp->numOfPlanes = lumps[kPlanes].length / sizeof(Plane); bsp->planes = (Plane *)malloc(bsp->numOfPlanes * sizeof(Plane)); if (bsp->planes == NULL) { return 1; } fseek(fp, lumps[kPlanes].offset, SEEK_SET); fread(bsp->planes, bsp->numOfPlanes, sizeof(Plane), fp); for (i=0;inumOfPlanes;i++) { #if SDL_BYTEORDER != SDL_LIL_ENDIAN bsp->planes[i].normal.x = swapBytes(bsp->planes[i].normal.x); bsp->planes[i].normal.y = swapBytes(bsp->planes[i].normal.y); bsp->planes[i].normal.z = swapBytes(bsp->planes[i].normal.z); bsp->planes[i].d = swapBytes(bsp->planes[i].d); #endif } return 0; } int loadShaders(FILE *fp, BSPLump *lumps) { int i; bsp->numOfShaders = lumps[kShaders].length / sizeof(BSPShader); bsp->shaders = (BSPShader *)malloc(bsp->numOfShaders * sizeof(BSPShader)); if (bsp->shaders == NULL) { return 1; } fseek(fp, lumps[kShaders].offset, SEEK_SET); fread(bsp->shaders, bsp->numOfShaders, sizeof(BSPShader), fp); for (i=0;inumOfShaders;i++) { bsp->shaders[i].brushID = SDL_SwapLE32(bsp->shaders[i].brushID); bsp->shaders[i].unknown = SDL_SwapLE32(bsp->shaders[i].unknown); } return 0; } int loadVisData(FILE *fp, BSPLump *lumps) { int size; fseek(fp, lumps[kVisData].offset, SEEK_SET); if (lumps[kVisData].length > 0) { fread(&bsp->clusters.numOfClusters, 1, sizeof(int), fp); bsp->clusters.numOfClusters = SDL_SwapLE32(bsp->clusters.numOfClusters); fread(&bsp->clusters.bytesPerCluster, 1, sizeof(int), fp); bsp->clusters.bytesPerCluster = SDL_SwapLE32(bsp->clusters.bytesPerCluster); size = bsp->clusters.numOfClusters * bsp->clusters.bytesPerCluster; bsp->clusters.pBitsets = (unsigned char *)malloc(size * sizeof(unsigned char)); if (bsp->clusters.pBitsets == NULL) { return 1; } fread(bsp->clusters.pBitsets, 1, sizeof(unsigned char) * size, fp); } else { bsp->clusters.pBitsets = NULL; } return 0; } int loadBrushes(FILE *fp, BSPLump *lumps) { int i; bsp->numOfBrushes = lumps[kBrushes].length / sizeof(BSPBrush); bsp->brushes = (BSPBrush *)malloc(bsp->numOfBrushes * sizeof(BSPBrush)); if (bsp->brushes == NULL) { return 1; } fseek(fp, lumps[kBrushes].offset, SEEK_SET); fread(bsp->brushes, bsp->numOfBrushes, sizeof(BSPBrush), fp); for (i=0;inumOfBrushes;i++) { bsp->brushes[i].brushSide = SDL_SwapLE32(bsp->brushes[i].brushSide); bsp->brushes[i].numOfBrushSides = SDL_SwapLE32(bsp->brushes[i].numOfBrushSides); bsp->brushes[i].textureID = SDL_SwapLE32(bsp->brushes[i].textureID); } return 0; } int loadLeafBrushes(FILE *fp, BSPLump *lumps) { int i; bsp->numOfLeafBrushes = lumps[kLeafBrushes].length / sizeof(int); bsp->leafBrushes = (int *)malloc(bsp->numOfLeafBrushes * sizeof(int)); if (bsp->leafBrushes == NULL) { return 1; } fseek(fp, lumps[kLeafBrushes].offset, SEEK_SET); fread(bsp->leafBrushes, bsp->numOfLeafBrushes, sizeof(int), fp); for (i=0;inumOfLeafBrushes;i++) { bsp->leafBrushes[i] = SDL_SwapLE32(bsp->leafBrushes[i]); } return 0; } int loadBrushSides(FILE *fp, BSPLump *lumps) { int i; bsp->numOfBrushSides = lumps[kBrushSides].length / sizeof(BSPBrushSide); bsp->brushSides = (BSPBrushSide *)malloc(bsp->numOfBrushSides * sizeof(BSPBrushSide)); if (bsp->brushSides == NULL) { return 1; } fseek(fp, lumps[kBrushSides].offset, SEEK_SET); fread(bsp->brushSides, bsp->numOfBrushSides, sizeof(BSPBrushSide), fp); for (i=0;inumOfBrushSides;i++) { bsp->brushSides[i].plane = SDL_SwapLE32(bsp->brushSides[i].plane); bsp->brushSides[i].textureID = SDL_SwapLE32(bsp->brushSides[i].textureID); } return 0; } int loadFaceDrawing(FILE *fp, BSPLump *lumps) { bsp->facesDrawn.size = (bsp->numOfFaces / 32) + 1; bsp->facesDrawn.bits = (unsigned int *)malloc(bsp->facesDrawn.size * sizeof(unsigned int)); if (bsp->facesDrawn.bits == NULL) { return 1; } memset(bsp->facesDrawn.bits, 0, sizeof(unsigned int) * bsp->facesDrawn.size); return 0; } int loadPatches(FILE *fp, BSPLump *lumps) { int i, numPatchesWide, numPatchesHigh, x, y, row, point, patch; bsp->numOfPatches = 0; for (i=0;inumOfFaces;i++) { if (bsp->faces[i].type == 2) { bsp->numOfPatches++; } } if (bsp->numOfPatches > 0) { patch = 0; bsp->patches = (BSPPatch *)malloc(bsp->numOfPatches * sizeof(BSPPatch)); if (bsp->patches == NULL) { printf("Failed to allocate %ld bytes for patches\n", bsp->numOfPatches * sizeof(BSPPatch)); fclose(fp); exit(1); } for (i=0;inumOfFaces;i++) { if (bsp->faces[i].type != 2) { continue; } bsp->patches[patch].textureID = bsp->faces[i].textureID; bsp->patches[patch].lightmapID = bsp->faces[i].lightmapID; bsp->patches[patch].width = bsp->faces[i].size[0]; bsp->patches[patch].height = bsp->faces[i].size[1]; numPatchesWide = (bsp->patches[patch].width - 1) / 2; numPatchesHigh = (bsp->patches[patch].height - 1) / 2; bsp->patches[patch].numQuadPatches = numPatchesWide * numPatchesHigh; bsp->patches[patch].quadPatches = (BSPBiQuadraticPatch *)malloc(bsp->patches[patch].numQuadPatches * sizeof(BSPBiQuadraticPatch)); if (bsp->patches[patch].quadPatches == NULL) { return 1; } for (y=0;ypatches[patch].quadPatches[y * numPatchesWide + x].controlPoints[row * 3 + point] = bsp->verts[bsp->faces[i].startVertIndex + (y * 2 * bsp->patches[patch].width + x * 2) + row * bsp->patches[patch].width + point]; } } /* Tesselate the patch */ if (tesselate(&bsp->patches[patch].quadPatches[y * numPatchesWide + x]) == 1) { return 1; } } } patch++; } } return 0; } int loadModels(FILE *fp, BSPLump *lumps) { int i, j, k, meshIndex, vertexIndex, offset, meshCount; float centerX, centerY, centerZ; bsp->numOfModels = lumps[kModels].length / sizeof(BSPModel); bsp->models = (BSPModel *)malloc(bsp->numOfModels * sizeof(BSPModel)); if (bsp->models == NULL) { return 1; } String mdlName; MDLModel *model; fseek(fp, lumps[kModels].offset, SEEK_SET); fread(bsp->models, bsp->numOfModels, sizeof(BSPModel), fp); for (i=1;inumOfModels;i++) { #if SDL_BYTEORDER != SDL_LIL_ENDIAN bsp->models[i].mins.x = swapBytes(bsp->models[i].mins.x); bsp->models[i].mins.y = swapBytes(bsp->models[i].mins.y); bsp->models[i].mins.z = swapBytes(bsp->models[i].mins.z); bsp->models[i].maxs.x = swapBytes(bsp->models[i].maxs.x); bsp->models[i].maxs.y = swapBytes(bsp->models[i].maxs.y); bsp->models[i].maxs.z = swapBytes(bsp->models[i].maxs.z); bsp->models[i].faceIndex = SDL_SwapLE32(bsp->models[i].faceIndex); bsp->models[i].numOfFaces = SDL_SwapLE32(bsp->models[i].numOfFaces); bsp->models[i].brushIndex = SDL_SwapLE32(bsp->models[i].brushIndex); bsp->models[i].numOfBrushes = SDL_SwapLE32(bsp->models[i].numOfBrushes); #endif centerX = ((bsp->models[i].maxs.x) + (bsp->models[i].mins.x)) / 2; centerY = ((bsp->models[i].maxs.y) + (bsp->models[i].mins.y)) / 2; centerZ = ((bsp->models[i].maxs.z) + (bsp->models[i].mins.z)) / 2; model = new MDLModel(); mdlName.setText("*%d", i); modelManager->addMDLModel(mdlName.getText(), model); model->originalPosition.set(centerX, centerY, centerZ); model->mins = bsp->models[i].mins; model->maxs = bsp->models[i].maxs; model->numOfFaces = bsp->models[i].numOfFaces; model->numMeshVerts = (int *)malloc(bsp->models[i].numOfFaces * sizeof(int)); model->lightmapID = (int *)malloc(bsp->models[i].numOfFaces * sizeof(int)); model->textureID = (int *)malloc(bsp->models[i].numOfFaces * sizeof(int)); model->indices = (int **)malloc(bsp->models[i].numOfFaces * sizeof(int *)); model->position = (Vector **)malloc(bsp->models[i].numOfFaces * sizeof(Vector *)); model->lightmapCoord = (Point **)malloc(bsp->models[i].numOfFaces * sizeof(Point *)); model->textureCoord = (Point **)malloc(bsp->models[i].numOfFaces * sizeof(Point *)); for (j=0;jmodels[i].numOfFaces;j++) { meshIndex = bsp->faces[bsp->models[i].faceIndex + j].meshVertIndex; meshCount = bsp->faces[bsp->models[i].faceIndex + j].numMeshVerts; vertexIndex = bsp->faces[bsp->models[i].faceIndex + j].startVertIndex; model->numMeshVerts[j] = meshCount; model->textureID[j] = bsp->faces[bsp->models[i].faceIndex + j].textureID; model->lightmapID[j] = bsp->faces[bsp->models[i].faceIndex + j].lightmapID; model->position[j] = (Vector *)malloc(meshCount * sizeof(Vector)); model->indices[j] = (int *)malloc(meshCount * sizeof(int)); model->lightmapCoord[j] = (Point *)malloc(meshCount * sizeof(Point)); model->textureCoord[j] = (Point *)malloc(meshCount * sizeof(Point)); for (k=0;k bsp->numOfMeshIndices) { return 1; } offset = bsp->meshIndices[meshIndex + k] + vertexIndex; if (offset > bsp->numOfVerts) { return 1; } model->position[j][k] = bsp->verts[offset].position; model->textureCoord[j][k] = bsp->verts[offset].textureCoord; model->lightmapCoord[j][k] = bsp->verts[offset].lightmapCoord; model->position[j][k].x -= centerX; model->position[j][k].y -= centerY; model->position[j][k].z -= centerZ; model->indices[j][k] = k; } } } return 0; } void removeBSPModelFaces() { BSPModel *bspModel; for (int modelIndex = 1 ; modelIndex < bsp->numOfModels ; modelIndex++) { bspModel = &bsp->models[modelIndex]; for (int i = 0 ; i < bspModel->numOfFaces ; i++) { bsp->faces[bspModel->faceIndex + i].textureID = -1; } } } void drawBSP(bool drawBlended) { /* Set up texture units */ /* Unit 0 */ glPushAttrib(GL_ALL_ATTRIB_BITS); /* Unit 0 */ glActiveTextureARB(GL_TEXTURE0_ARB); glEnable(GL_TEXTURE_2D); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); /* Unit 1 */ glActiveTextureARB(GL_TEXTURE1_ARB); glEnable(GL_TEXTURE_2D); /* Set up environment to draw textures, lightmaps etc. */ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PREVIOUS_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR); glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 2.0f); /* Set back to unit 0 */ glActiveTextureARB(GL_TEXTURE0_ARB); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glClientActiveTextureARB(GL_TEXTURE1_ARB); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glClientActiveTextureARB(GL_TEXTURE0_ARB); /* Loop through the face list and draw the associated vertex */ for (int i=0;inumOfFaces;i++) { if (bsp->faces[i].textureID == -1) { continue; } if (bsp->textureSpec[bsp->faces[i].textureID] == NULL) { continue; } if (bsp->textureSpec[bsp->faces[i].textureID]->blended != drawBlended) { continue; } if (bsp->clusters.pBitsets != NULL) { if ((bsp->facesDrawn.bits[i >> 5] & (1 << (i & 31))) == 0) { continue; } } switch (bsp->faces[i].type) { case 1: glVertexPointer(3, GL_FLOAT, sizeof(BSPVertex), &bsp->verts[0].position); glClientActiveTextureARB(GL_TEXTURE0_ARB); glTexCoordPointer(2, GL_FLOAT, sizeof(BSPVertex), &bsp->verts[0].textureCoord); glClientActiveTextureARB(GL_TEXTURE1_ARB); glTexCoordPointer(2, GL_FLOAT, sizeof(BSPVertex), &bsp->verts[0].lightmapCoord); glActiveTextureARB(GL_TEXTURE0_ARB); if (game->totalRemaining != 0) { if (!bsp->textureSpec[bsp->faces[i].textureID]->blended) { glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); bsp->textureSpec[bsp->faces[i].textureID]->activate(engine->getTimeDifference(TD_ANIMATION)); glColor4f(1.0, graphics->redPulse, graphics->redPulse, 1.0); } else { bsp->textureSpec[bsp->faces[i].textureID]->activate(engine->getTimeDifference(TD_ANIMATION)); } } else { bsp->textureSpec[bsp->faces[i].textureID]->activate(engine->getTimeDifference(TD_ANIMATION)); } glActiveTextureARB(GL_TEXTURE1_ARB); if (graphics->lightMaps) { if ((bsp->faces[i].lightmapID >= 0) && (!bsp->textureSpec[bsp->faces[i].textureID]->bright)) { glBindTexture(GL_TEXTURE_2D, bsp->lightmapTextures[bsp->faces[i].lightmapID]); } else { glBindTexture(GL_TEXTURE_2D, bsp->whiteTexture); } } glActiveTextureARB(GL_TEXTURE0_ARB); glDrawElements(graphics->wireframe ? GL_LINES : GL_TRIANGLES, bsp->faces[i].numMeshVerts, GL_UNSIGNED_INT, &bsp->type1Faces[i][0]); glDisable(GL_BLEND); break; case 2: for (int j=0;jpatches[i].numQuadPatches;j++) { glVertexPointer(3, GL_FLOAT, sizeof(BSPVertex), &bsp->patches[i].quadPatches[j].verts[0].position); glClientActiveTextureARB(GL_TEXTURE0_ARB); glTexCoordPointer(2, GL_FLOAT, sizeof(BSPVertex), &bsp->patches[i].quadPatches[j].verts[0].textureCoord); glClientActiveTextureARB(GL_TEXTURE1_ARB); glTexCoordPointer(2, GL_FLOAT, sizeof(BSPVertex), &bsp->patches[i].quadPatches[j].verts[0].lightmapCoord); glActiveTextureARB(GL_TEXTURE0_ARB); bsp->textureSpec[bsp->patches[i].textureID]->activate(engine->getTimeDifference(TD_ANIMATION)); glActiveTextureARB(GL_TEXTURE1_ARB); if (graphics->lightMaps) { if ((bsp->faces[i].lightmapID >= 0) && (!bsp->textureSpec[bsp->faces[i].textureID]->bright)) { glBindTexture(GL_TEXTURE_2D, bsp->lightmapTextures[bsp->patches[i].lightmapID]); } else { glBindTexture(GL_TEXTURE_2D, bsp->whiteTexture); } } glActiveTextureARB(GL_TEXTURE0_ARB); for (int row=0;rowtesselation;row++) { glDrawElements(graphics->wireframe ? GL_LINE_STRIP : GL_TRIANGLE_STRIP, 2 * (bsp->tesselation + 1), GL_UNSIGNED_INT, &bsp->patches[i].quadPatches[j].indices[row * 2 * (bsp->tesselation + 1)]); } } break; case 3: int offset = bsp->faces[i].startVertIndex; glVertexPointer(3, GL_FLOAT, sizeof(BSPVertex), &bsp->verts[offset].position); glClientActiveTextureARB(GL_TEXTURE0_ARB); glTexCoordPointer(2, GL_FLOAT, sizeof(BSPVertex), &bsp->verts[offset].textureCoord); glClientActiveTextureARB(GL_TEXTURE1_ARB); glTexCoordPointer(2, GL_FLOAT, sizeof(BSPVertex), &bsp->verts[offset].lightmapCoord); glActiveTextureARB(GL_TEXTURE0_ARB); bsp->textureSpec[bsp->faces[i].textureID]->activate(engine->getTimeDifference(TD_ANIMATION)); glActiveTextureARB(GL_TEXTURE1_ARB); if (graphics->lightMaps) { if ((bsp->faces[i].lightmapID >= 0) && (!bsp->textureSpec[bsp->faces[i].textureID]->bright)) { glBindTexture(GL_TEXTURE_2D, bsp->lightmapTextures[bsp->faces[i].lightmapID]); } else { glBindTexture(GL_TEXTURE_2D, bsp->whiteTexture); } } glActiveTextureARB(GL_TEXTURE0_ARB); glDrawElements(graphics->wireframe ? GL_LINES : GL_TRIANGLES, bsp->faces[i].numMeshVerts, GL_UNSIGNED_INT, &bsp->meshIndices[bsp->faces[i].meshVertIndex]); break; } bsp->textureSpec[bsp->faces[i].textureID]->finish(); } glActiveTextureARB(GL_TEXTURE1_ARB); glDisable(GL_TEXTURE_2D); glActiveTextureARB(GL_TEXTURE0_ARB); glClientActiveTextureARB(GL_TEXTURE1_ARB); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glClientActiveTextureARB(GL_TEXTURE0_ARB); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glPopAttrib(); } int calculateEntityLeaf(Vector position) { int currentNode = 0; while (currentNode >= 0) { if (camera->frustum.classifyPoint(bsp->planes[bsp->nodes[currentNode].plane], position) == POINT_IN_FRONT_OF_PLANE) { currentNode = bsp->nodes[currentNode].children[0]; } else { currentNode = bsp->nodes[currentNode].children[1]; } } return ~currentNode; } void getCluster(Entity *entity, float zAdjustment) { Vector v; v = entity->position; v.z += zAdjustment; int entityLeaf = calculateEntityLeaf(v); entity->cluster = bsp->leafs[entityLeaf].cluster; } int isClusterVisible(int cluster) { int index; if (bsp->clusters.pBitsets == NULL || camera->cluster < 0) { return 1; } index = (camera->cluster * bsp->clusters.bytesPerCluster) + (cluster / 8); if (index > bsp->clusters.numOfClusters * bsp->clusters.bytesPerCluster) { printf("FATAL: Could not get BSP cluster %d. Max is %d\n", index, bsp->clusters.numOfClusters * bsp->clusters.bytesPerCluster); exit(1); } return bsp->clusters.pBitsets[index] & (1 << (cluster & 7)); } void renderBSP() { Vector position; int cameraLeaf, i, j, facesToDraw, faceIndex; memset(bsp->facesDrawn.bits, 0, sizeof(unsigned int) * bsp->facesDrawn.size); facesToDraw = 0; cameraLeaf = calculateEntityLeaf(camera->getRenderingTarget()); camera->cluster = bsp->leafs[cameraLeaf].cluster; for (i=bsp->numOfLeafs - 1;i>=0;i--) { if (isClusterVisible(bsp->leafs[i].cluster) == 0) { continue; } position.set(bsp->leafs[i].min.x, bsp->leafs[i].min.y, bsp->leafs[i].min.z); position.x += bsp->leafs[i].max.x; position.y += bsp->leafs[i].max.y; position.z += bsp->leafs[i].max.z; for (j=bsp->leafs[i].numOfLeafFaces - 1;j>=0;j--) { faceIndex = bsp->leafFaces[bsp->leafs[i].leafFace + j]; if ((bsp->facesDrawn.bits[faceIndex >> 5] & (1 << (faceIndex & 31))) == 0) { bsp->facesDrawn.bits[faceIndex >> 5] |= (1 << (faceIndex & 31)); } } } } void loadBSP(char *name) { int i, j, vertexIndex, meshIndex, meshCount, offset; FILE *fp; BSPHeader header; BSPLump lumps[kMaxLumps]; Pak *pak = Pak::getInstance(); pak->getFileLocation(name); debug(("loadBSP() - %s\n", pak->getFileName())); fp = fopen(pak->getFileName(), "rb"); if (fp == NULL) { graphics->showErrorAndExit("Failed to open BSP file %s", pak->getFileName()); } fread(&header, 1, sizeof(BSPHeader), fp); fread(&lumps, kMaxLumps, sizeof(BSPLump), fp); header.version = SDL_SwapLE32(header.version); for (i=0;itype1Faces = (int **)malloc(bsp->numOfFaces * sizeof(int *)); if (bsp->type1Faces == NULL) { //printf("Failed to allocate %d bytes for Type 1 faces\n", bsp->numOfFaces * sizeof(int)); fclose(fp); exit(1); } for (i=0;inumOfFaces;i++) { if (bsp->faces[i].type != 1) { continue; } meshIndex = bsp->faces[i].meshVertIndex; meshCount = bsp->faces[i].numMeshVerts; vertexIndex = bsp->faces[i].startVertIndex; bsp->type1Faces[i] = (int *)malloc(meshCount * sizeof(int)); if (bsp->type1Faces[i] == NULL) { //printf("Failed to allocate %d bytes for type1Faces[%d]\n", meshCount * sizeof(int), i); fclose(fp); exit(1); } for (j=0;j bsp->numOfMeshIndices) { //printf("Could not get offset %d as max is %d\n", meshIndex + j, bsp->numOfMeshIndices); fclose(fp); exit(1); } offset = bsp->meshIndices[meshIndex + j] + vertexIndex; if (offset > bsp->numOfVerts) { //printf("Could not draw vertex %d as max is %d\n", offset, bsp->numOfVerts); fclose(fp); exit(1); } bsp->type1Faces[i][j] = offset; } } fclose(fp); debug(("loadBSP() :: Done\n")); } float swapBytes(float f) { unsigned int i; Convert c1, c2; c1.f = f; for (i=0;i