   BSP loading Questions
  Hey,I am trying to load a BSP. But unfortunately it looks like its not loading correctly. Some triangles just dont seem to get rendered and the rendered scene is totally wrong. This is how I am loading in a bsp.FILE *fp;fp = fopen(filename, "rb");if(!fp) return false;// first load in the headerbspHeader tmpHeader;fread(&tmpHeader, sizeof(bspHeader), 1, fp);// the nread in the lump informationbspLump tmpLumps[kMaxLumps];fread(&tmpLumps, kMaxLumps, sizeof(bspLump), fp);// Allocate memory for our member variablesthis->m_numVerts = tmpLumps[kVertices].length/sizeof(bspVertex);this->m_pVertices = new bspVertex[this->m_numVerts];this->m_numFaces = tmpLumps[kFaces].length / sizeof(bspFace);this->m_pFaces = new bspFace[this->m_numFaces];this->m_numTextures = tmpLumps[kTextures].length /sizeof(bspTexture);bspTexture *tmpTextures = new bspTexture[this->m_numTextures];// the following will get to the position of the vertices// read in the vertex information and also swap z and y value// we also need to check if texture coordinates need to be invertedfseek(fp, tmpLumps[kVertices].offset, SEEK_SET);fread(this->m_pVertices, this->m_numVerts, sizeof(bspVertex), fp);for(int i = 0; i < this->m_numVerts; i++){    float temp = this->m_pVertices.vPosition.m_fVec[1];    this->m_pVertices.vPosition.m_fVec[1] = this->m_pVertices.vPosition.m_fVec[2];    this->m_pVertices.vPosition.m_fVec[2] = temp;    m_pVertices.vTexCoord.m_fVec[1] *= -1;}// set the file pointer to the start of the faces and read in the the face informationfseek(fp, tmpLumps[kFaces].offset, SEEK_SET);fread(this->m_pFaces, this->m_numFaces, sizeof(bspFace), fp);// offset the pointer to load in texture informationfseek(fp, tmpLumps[kTextures].offset, SEEK_SET);fread(tmpTextures, this->m_numTextures, sizeof(bspTexture), fp);this->m_Image = new CImage[this->m_numTextures];// load all of the texturesfor(i = 0; i < this->m_numTextures; i++){    this->FindTextureExtension(tmpTextures.strName);    bool loaded = this->m_Image.Load(tmpTextures.strName);}delete [] tmpTextures;fclose(fp);This is how I am doing the rendering of the scene. void CBSPLoader::Render(){// render using vertex arrays - add in code for VBO support// as that will cache our vertices onto the hardware completelyglVertexPointer(3, GL_FLOAT, sizeof(bspVertex), &this->m_pVertices[0].vPosition);glTexCoordPointer(2, GL_FLOAT, sizeof(bspVertex), &this->m_pVertices[0].vTexCoord);//glNormalPointer(3, GL_FLOAT, &this->m_pVertices[0].vNormal);glEnableClientState(GL_VERTEX_ARRAY);//glEnableClientState(GL_NORMAL_ARRAY);glEnableClientState(GL_TEXTURE_COORD_ARRAY);// Go through all the facesint i = this->m_numFaces;m_FacesDrawn.ClearAll();while(i--){// Before drawing this face, make sure it's a   normal polygonif(m_pFaces.type != 1) continue;RenderFace(i);}}void CBSPLoader::RenderFace(int faceIndex){// grab the facebspFace *pFace = &this->m_pFaces[faceIndex];// texturing is always onif(!glIsEnabled(GL_TEXTURE_2D)){glEnable(GL_TEXTURE_2D);}this->m_Image[pFace->textureID].Bind();glDrawArrays(GL_TRIANGLE_FAN, pFace->vertIndex, pFace->numMeshVerts);}If I render using GL_TRIANGLE_STRIPS it seems to be a bit better but still some triangles dont seem to be drawn. But with GL_TRIANGLE_FAN most of it seems to be totally out of place. I am not sure what I am doing wrong. Is it that I am doing something wrong while loading ? Thanks.   
  The only thing I can think of is that the more standard use of fread is:fread( void *ptr, size_t element_size, size_t num_elements, FILE *stream );Where as you currently have element_size and num_elements swapped round, but to be honest I doubt that that is causing your problem.  At a pure guess, perhaps the compiler is padding your bsp structs in a way that the bsp file is not.  I'd try googling for documentation on how to instruct your compiler to pack structs.  Hope it all works out.   ;  Darnit, still not many people know about this.THE GAMETUTORIALS.COM BSP LOADING TUTORIALS ARE _WRONG_(and many others)right, in quake3 ALL triangle data CAN be renderered usingGL_TRIANGLES and the MeshVerts as indicies.the MeshVerts are indicies for the triangles for ALL type 1 faces.so if your rendering the Triangle Soup's you can just render using the same function.Cheers,this 'bug' shows up when compiled with Q3Map2 as it is far more optimized for speed and i beleive leaves out the triangle_fan generation.;  Hey,Well technically I shoud be using fread like you said but it really didn't matter. Eventually it should read in count * size. To keep the fread definition consistent I have changed it to how it should be. Secondly I have taken a screenshot - I used a simple cube in the bsp loader. Here is an image of it. It looks as though 1 triangle is missing. When you said packing could be a problem I tried #pragma pack(1) but it didn't matter at all. I am really not sure whats happening to the 1 triangles. It definitely not a texturing problem because even in wireframe mode I get strange artifacts during rotation.Quote:right, in quake3 ALL triangle data CAN be renderered usingGL_TRIANGLES and the MeshVerts as indicies.Lastly I tried GL_TRIANGLES it is even more messed up. So I would like to know how are you using GL_TRIANGLES. i presume you are saying that I do the followingglDrawArrays(GL_TRIANGLES, pFaces->vertIndex, pFaces->numFaces);Is that correct ? Thanks.   ;  I'm guessing that this is redundant, but just in case... Are you sure that you have requested a depth buffer and that you have depth testing enabled?  The other thing would be winding order.  Try calling glDisable( GL_CULL_FACE ); somewhere before rendering.[Edited by - Hamster on July 6, 2004 7:35:14 PM];  your close...in the BSPFace structure, you can see 2 integers (the 6th and 7th item in the struct)one is the starting index for "meshvert"the other is the number of "meshverts"these are the indices you have to use to render the triangles with.unfortunatly this can't be done in non-immediate mode openGLunless you have a rendering backend which uses a buffer-flush style design.glBegin( GL_TRIANGLES );for( int i=0; i< face->numMeshVerts; i++) { int offset = m_pMeshVerts[face->meshVertsStart+i] + face->vertIndex; glVertex3fv( &m_pVerts[offset].x);}glEnd();dont forget your glMultiTexCoord2f(...) calls to set the Lightmap and Texture coords.i see you havn't actually loaded the MeshVerts, so heres how you do that:int *m_pMeshVerts;// Allocate memory for our member variablesm_numMeshVerts= tmpLumps[kMeshVerts].length/sizeof(int);m_pMeshVerts = new int[m_numMeshVerts];fseek(fp, tmpLumps[kMeshVerts].offset, SEEK_SET);fread(m_pMeshVerts, m_numMeshVerts, sizeof(int), fp);thats pretty much all you need :)hope that helps..   ;  Why can't you do it in non-immediate mode OpenGL?voidBSP::RenderFace(int i){if(mpFaces.LastFrameDrawn == FPS->frames)return;mpFaces.LastFrameDrawn = FPS->frames;//FIXME: you can probably save a lot of speed right here without having to re-bind everything//all of the timegpNTGLAPI->glActiveTextureARB(GL_TEXTURE0_ARB);gpNTGLAPI->ntglEnable(GL_TEXTURE_2D);//gpNTGLAPI->ntglBindTexture(GL_TEXTURE_2D, mpGLTextures[mpFaces.textureID]);gpTextureManager->BindTexture(GL_TEXTURE_2D,mpGLTextures[mpFaces.textureID]);gpNTGLAPI->glActiveTextureARB(GL_TEXTURE1_ARB);gpNTGLAPI->ntglEnable(GL_TEXTURE_2D);gpNTGLAPI->ntglBindTexture(GL_TEXTURE_2D,  mpLightMaps[mpFaces.lightmapID]);gpNTGLAPI->ntglVertexPointer(3,GL_FLOAT,sizeof(tBSPVertex),&mpVertices[mpFaces.startVertIndex].vPosition);gpNTGLAPI->glClientActiveTextureARB(GL_TEXTURE0_ARB);gpNTGLAPI->ntglTexCoordPointer(2, GL_FLOAT,sizeof(tBSPVertex), &mpVertices[mpFaces.startVertIndex].vTextureCoord);gpNTGLAPI->glClientActiveTextureARB(GL_TEXTURE1_ARB);gpNTGLAPI->ntglTexCoordPointer(2,GL_FLOAT, sizeof(tBSPVertex), &mpVertices[mpFaces.startVertIndex].vLightmapCoord);//doesn't work when you pass GL_FLOAT instead of intgpNTGLAPI->ntglDrawElements(GL_TRIANGLES, mpFaces.numMeshVerts, GL_UNSIGNED_INT, &mpIndexArray[mpFaces.meshVertIndex]);};  if you take a look at the code i provided, more closely, the meshverts are offset by a value that each face has (this is individual)there is no way of telling OpenGL to offset the indicies bythis value in non-immediate mode, and its not possible to simplyoffset them at load-time because the same meshvert can be usedbut many different faces.and when i said this wasnt possible in non-immediate mode, i meantit as not possible "straight out of the box"what you need is to create a list of indicies perframe to renderthat way you can submit the properly offset values and flushthose with a few glDrawElements calls   ;  I'm having the same problem and I don't know how to fix it. I miss faces in my Q3BSP loader too. The code I use to load the Q3 BSP is: (that's not everything, I also load bezier patches with no problems at all)bool Q3BSP::LoadVertices(FILE * file){numTempVertices = header.directoryEntries[bspVertices].length / sizeof(BSP_LOAD_VERTEX);tempVertices = new BSP_LOAD_VERTEX[numTempVertices];if(!tempVertices)return false;fseek(file, header.directoryEntries[bspVertices].offset, SEEK_SET);fread(tempVertices, header.directoryEntries[bspVertices].length, 1, file);return true;}bool Q3BSP::LoadPolygonFaces(FILE * file){// Calculate the number of facesint numLoadFaces = header.directoryEntries[bspFaces].length / sizeof(BSP_LOAD_FACE);// Create space for the facesBSP_LOAD_FACE * loadFaces = new BSP_LOAD_FACE[numLoadFaces];if(!loadFaces)return false;fseek(file, header.directoryEntries[bspFaces].offset, SEEK_SET);fread(loadFaces, header.directoryEntries[bspFaces].length, 1, file);//Number of PVS FacesnumPVSFaces = numLoadFaces;// Start - Calculate how many polygon faces existnumPolygonFaces = 0;for(int i = 0; i < numLoadFaces; ++i){// Skip this face if it isn't a polygon faceif(loadFaces.type != bspPolygonFace)continue;// Skip this face if it has fewer than 3 verticesif(loadFaces.numVertices < 3)continue;// Everything is ok.++numPolygonFaces;}// End - Calculate how many polygon faces exist// Create space for this many polygon facespolygonFaces = new BSP_POLYGON_FACE[numPolygonFaces];if(!polygonFaces)return false;// Start - Fill in the info for the polygon facesint currentPolygonFace=0;for(i = 0; i < numLoadFaces; ++i){// Skip this face if it isn't a polygon faceif(loadFaces.type != bspPolygonFace)continue;// Skip this face if it has fewer than 3 verticesif(loadFaces.numVertices < 3){__asm int 3continue;}int numVertices = loadFaces.numVertices;// Everything is valid, start filling the info.polygonFaces[currentPolygonFace].pvsFaceNumber = i;polygonFaces[currentPolygonFace].surfaceTextureIndex = tempTextureIndices[loadFaces.texture];GEO_VERTEX * faceVertices = new GEO_VERTEX[numVertices];if(!faceVertices)return false;// Fill in the array of vertices// reverse the winding and change the coords to fit the system.for(int j=0; j<numVertices; ++j){faceVertices[numVertices-j-1].position.x = tempVertices[loadFaces.firstVertexIndex+j].position.x;faceVertices[numVertices-j-1].position.y = tempVertices[loadFaces.firstVertexIndex+j].position.z;faceVertices[numVertices-j-1].position.z = -tempVertices[loadFaces.firstVertexIndex+j].position.y;faceVertices[numVertices-j-1].texCoords.x = tempVertices[loadFaces.firstVertexIndex+j].decalCoords.x;faceVertices[numVertices-j-1].texCoords.y = -tempVertices[loadFaces.firstVertexIndex+j].decalCoords.y;}// Send the vertices to the render manager.int firstVertexIndex=RENDER_MANAGER::CurrentInstance()->AddTemporaryGeometryVertex(faceVertices[0]);for(j = 1; j < numVertices; ++j)RENDER_MANAGER::CurrentInstance()->AddTemporaryGeometryVertex(faceVertices[j]);// Fill an array of vertex positionspolygonFaces[currentPolygonFace].numVertexPositions = numVertices;polygonFaces[currentPolygonFace].vertexPositions = new VEC3[numVertices];if(!polygonFaces[currentPolygonFace].vertexPositions)return false;for(j=0; j<numVertices; ++j)polygonFaces[currentPolygonFace].vertexPositions[j] = faceVertices[j].position;// Erase the temporary vertex arrayif(faceVertices)delete [] faceVertices;faceVertices=NULL;polygonFaces[currentPolygonFace].numIndices = 3 * (numVertices - 2);// Create space for the indicespolygonFaces[currentPolygonFace].indices = new GLuint[3 * (numVertices - 2)];if(!polygonFaces[currentPolygonFace].indices)return false;// Fill in the indicesint currentIndex=0;for(j = 2; j < numVertices; ++j){polygonFaces[currentPolygonFace].indices[currentIndex++] = firstVertexIndex;polygonFaces[currentPolygonFace].indices[currentIndex++] = firstVertexIndex + j - 1;polygonFaces[currentPolygonFace].indices[currentIndex++] = firstVertexIndex + j;}// Fill in the edge indices.polygonFaces[currentPolygonFace].numEdges = numVertices;polygonFaces[currentPolygonFace].edgeIndices = new GLuint[numVertices*2];if(!polygonFaces[currentPolygonFace].edgeIndices)return false;for(j = 0; j < numVertices; ++j){unsigned int index1=firstVertexIndex+j;unsigned int index2=firstVertexIndex+j+1;if(index2 > firstVertexIndex + numVertices - 1)index2=firstVertexIndex;polygonFaces[currentPolygonFace].edgeIndices[j*2+0] = index1;polygonFaces[currentPolygonFace].edgeIndices[j*2+1] = index2;}++currentPolygonFace;}if(loadFaces)delete [] loadFaces;loadFaces = NULL;return true;}And you see I have a render manager, its just to use VAO and some other stuff but the call that renders the stuff after binding the textures and other stuff isglDrawElements(GL_TRIANGLES, geometryData.indexLists.GetSize(), GL_UNSIGNED_INT, geometryData.indexLists.entries);Got any idea how to fix this?   ;  when i get home i will post some working code, ok?   