private bool LoadFaceLump(Q3BSPDirEntry dir, BinaryReader fileReader) { int faceCount = dir.Length / Q3BSPConstants.sizeFace; faces = new Q3BSPFace[faceCount]; facesToDraw = new bool[faceCount]; for (int i = 0; i < faceCount; i++) { faces[i] = Q3BSPFace.FromStream(fileReader); } bspLogger.WriteLine("No of faces: " + faceCount); return(true); }
int IComparer.Compare(object x, object y) { Q3BSPFace face1 = (Q3BSPFace)x; Q3BSPFace face2 = (Q3BSPFace)y; if (face1.TextureIndex != face2.TextureIndex) { return(face1.TextureIndex - face2.TextureIndex); } else { return(face1.LightMapIndex - face2.LightMapIndex); } }
public void InitializeStatic(GraphicsDevice graphics) { List <short> indexList = new List <short>(); List <short[]> indexBufferList = new List <short[]>(); List <Vector2> textureAndLightMapList = new List <Vector2>(); int lastTextureIndex = 0; int lastLightMapIndex = 0; Q3BSPFace[] tempFaces = new Q3BSPFace[faces.Length]; faces.CopyTo(tempFaces, 0); System.Array.Sort(tempFaces, new Q3BSPFaceComparer()); foreach (Q3BSPFace face in tempFaces) { // The current index buffer is done and needs to be refreshed. if ((face.TextureIndex != lastTextureIndex || face.LightMapIndex != lastLightMapIndex) && ((indexList.Count != 0 || indexList.Count > int.MaxValue))) { indexBufferList.Add(indexList.ToArray()); textureAndLightMapList.Add(new Vector2(lastTextureIndex, lastLightMapIndex)); indexList.Clear(); } if (face.FaceType == Q3BSPFaceType.Patch) { Q3BSPVertex[] patchVertices = patches[face.PatchIndex].GetVertices(); short[] patchIndices = patches[face.PatchIndex].GetIndices(); Q3BSPVertex[] newVertexArray = new Q3BSPVertex[vertices.Length + patchVertices.Length]; vertices.CopyTo(newVertexArray, 0); patchVertices.CopyTo(newVertexArray, vertices.Length); foreach (short index in patchIndices) { indexList.Add((short)(vertices.Length + index)); } vertices = newVertexArray; } for (int i = 0; i < face.MeshVertexCount; ++i) { indexList.Add((short)(face.StartVertex + meshVertices[face.StartMeshVertex + i])); } lastTextureIndex = face.TextureIndex; lastLightMapIndex = face.LightMapIndex; } // Add the last index buffer indexBufferList.Add(indexList.ToArray()); textureAndLightMapList.Add(new Vector2(lastTextureIndex, lastLightMapIndex)); indexList.Clear(); // Set the vertex and index buffers vertexBuffer = new VertexBuffer(graphics, typeof(Q3BSPVertex), vertices.Length, BufferUsage.WriteOnly); vertexBuffer.SetData <Q3BSPVertex>(vertices); indexBuffers = new IndexBuffer[indexBufferList.Count]; indexBufferLengths = new int[indexBufferList.Count]; for (int i = 0; i < indexBuffers.Length; i++) { indexBuffers[i] = new IndexBuffer(graphics, typeof(short), indexBufferList[i].Length, BufferUsage.WriteOnly); indexBuffers[i].SetData <short>(indexBufferList[i]); indexBufferLengths[i] = indexBufferList[i].Length; } // Set the texture and lightmap array textureAndLightMapIndices = textureAndLightMapList.ToArray(); }
/// <param name="shaderPath">Path to the directory that contains all compiled .shaders. Is relative to the Content.BasePath directory. Do not include a leading '/'.</param> public bool InitializeLevel(GraphicsDevice graphics, ContentManager content, string shaderPath, string quakePath) { bool bSuccess = true; lightMapManager = new Q3BSPLightMapManager(); bSuccess = lightMapManager.GenerateLightMaps(lightMapData, graphics); if (bSuccess) { shaderManager = new Q3BSPShaderManager(); shaderManager.ShaderPath = shaderPath; shaderManager.QuakePath = quakePath; bSuccess = shaderManager.LoadTextures(textureData, graphics, content); } if (bSuccess && shaderManager.SkyMaterial != null) { skybox = new Q3BSPSkybox(skyboxSize, skyboxTessellation, graphics, shaderManager); } if (bSuccess) { shaderManager.LightMapManager = lightMapManager; } levelInitialized = bSuccess; if (renderType == Q3BSPRenderType.StaticBuffer) { InitializeStatic(graphics); } else if (renderType == Q3BSPRenderType.BSPCulling) { Q3BSPFace[] tempFaces = new Q3BSPFace[faces.Length]; faces.CopyTo(tempFaces, 0); System.Array.Sort(tempFaces, new Q3BSPFaceComparer()); int indexCount = 0; int lastTextureIndex = 0; int lastLightMapIndex = 0; this.maximumNumberOfIndicesToDraw = 0; foreach (Q3BSPFace face in tempFaces) { // The current index buffer is done and needs to be refreshed. if ((face.TextureIndex != lastTextureIndex || face.LightMapIndex != lastLightMapIndex)) { if (face.TextureIndex == 4) { indexCount += 0; } if (indexCount > maximumNumberOfIndicesToDraw) { maximumNumberOfIndicesToDraw = indexCount; } indexCount = 0; } lastTextureIndex = face.TextureIndex; lastLightMapIndex = face.LightMapIndex; indexCount += face.MeshVertexCount; } if (indexCount > maximumNumberOfIndicesToDraw) { maximumNumberOfIndicesToDraw = indexCount; } } bspLogger.WriteLine("Level initialized: " + levelInitialized.ToString()); return(levelInitialized); }
public void RenderLevelBSP(Vector3 cameraPosition, Matrix viewMatrix, Matrix projMatrix, GameTime gameTime, GraphicsDevice graphics) { int cameraLeaf = GetCameraLeaf(cameraPosition); int cameraCluster = leafs[cameraLeaf].Cluster; CurrentCluster = cameraCluster; CurrentLeaf = cameraLeaf; if (0 > cameraCluster) { cameraCluster = lastGoodCluster; } lastGoodCluster = cameraCluster; ResetFacesToDraw(); BoundingFrustum frustum = new BoundingFrustum(viewMatrix * projMatrix); ArrayList visibleFaces = new ArrayList(); foreach (Q3BSPLeaf leaf in leafs) { if (!visData.FastIsClusterVisible(cameraCluster, leaf.Cluster)) { continue; } //// Culls visible leafs. Unsure as to why. //if (!frustum.Intersects(leaf.Bounds)) //{ // continue; //} for (int i = 0; i < leaf.LeafFaceCount; i++) { int faceIndex = leafFaces[leaf.StartLeafFace + i]; Q3BSPFace face = faces[faceIndex]; if (face.FaceType != Q3BSPFaceType.Billboard && !facesToDraw[faceIndex]) { facesToDraw[faceIndex] = true; visibleFaces.Add(face); } } } if (0 >= visibleFaces.Count) { return; } Q3BSPFaceComparer fc = new Q3BSPFaceComparer(); visibleFaces.Sort(fc); graphics.VertexDeclaration = vertexDeclaration; Matrix matrixWorldViewProjection = viewMatrix * projMatrix; Effect effect; int[] indexArray = new int[maximumNumberOfIndicesToDraw]; int lastTextureIndex = 0; int lastLightMapIndex = 0; int accumulatedIndexCount = 0; graphics.RenderState.DepthBufferEnable = true; foreach (Q3BSPFace face in visibleFaces) { if (face.FaceType == Q3BSPFaceType.Patch) { effect = shaderManager.GetEffect(face.TextureIndex, face.LightMapIndex, viewMatrix, matrixWorldViewProjection, gameTime); effect.Begin(); foreach (EffectPass pass in effect.CurrentTechnique.Passes) { pass.Begin(); patches[face.PatchIndex].Draw(graphics); pass.End(); } effect.End(); continue; } if ((face.TextureIndex != lastTextureIndex || face.LightMapIndex != lastLightMapIndex) && accumulatedIndexCount > 0) { if (shaderManager.IsMaterialDrawable(lastTextureIndex)) { effect = shaderManager.GetEffect(lastTextureIndex, lastLightMapIndex, viewMatrix, matrixWorldViewProjection, gameTime); effect.Begin(); foreach (EffectPass pass in effect.CurrentTechnique.Passes) { pass.Begin(); graphics.DrawUserIndexedPrimitives <Q3BSPVertex>(PrimitiveType.TriangleList, vertices, 0, vertices.Length, indexArray, 0, accumulatedIndexCount / 3); pass.End(); } effect.End(); } //indexArray = new int[maximumNumberOfIndicesToDraw]; accumulatedIndexCount = 0; } lastTextureIndex = face.TextureIndex; lastLightMapIndex = face.LightMapIndex; for (int i = 0; i < face.MeshVertexCount; ++i) { indexArray[accumulatedIndexCount] = (face.StartVertex + meshVertices[face.StartMeshVertex + i]); accumulatedIndexCount++; } } // Draw the final batch of faces if (indexArray.Length != 0 && shaderManager.IsMaterialDrawable(lastTextureIndex)) { effect = shaderManager.GetEffect(lastTextureIndex, lastLightMapIndex, viewMatrix, matrixWorldViewProjection, gameTime); effect.Begin(); foreach (EffectPass pass in effect.CurrentTechnique.Passes) { pass.Begin(); graphics.DrawUserIndexedPrimitives <Q3BSPVertex>(PrimitiveType.TriangleList, vertices, 0, vertices.Length, indexArray, 0, accumulatedIndexCount / 3); pass.End(); } effect.End(); } }
public void RenderLevelBSP(Vector3 cameraPosition, Matrix worldMatrix, Matrix viewMatrix, Matrix projMatrix, GameTime gameTime, GraphicsDevice graphics) { int cameraLeaf = GetCameraLeaf(Vector3.Transform(cameraPosition, Matrix.Invert(worldMatrix))); /* transform to world coords */ //int cameraLeaf = GetCameraLeaf(Vector3.Transform(cameraPosition, worldMatrix)); //int cameraLeaf = GetCameraLeaf(cameraPosition); /* transform to world coords */ int cameraCluster = leafs[cameraLeaf].Cluster; CurrentCluster = cameraCluster; CurrentLeaf = cameraLeaf; if (0 > cameraCluster) { cameraCluster = lastGoodCluster; } lastGoodCluster = cameraCluster; ResetFacesToDraw(); BoundingFrustum frustum = new BoundingFrustum(Matrix.Multiply(viewMatrix, projMatrix)); ArrayList visibleFaces = new ArrayList(); VisibleLeafs = 0; Intersect = false; foreach (Q3BSPLeaf leaf in leafs) { if (!visData.FastIsClusterVisible(cameraCluster, leaf.Cluster)) { continue; } //// Culls visible leafs. Unsure as to why. /* * if (!frustum.Intersects(leaf.Bounds)) * { * continue; * } */ /* oriented bounding boxes fix the upper problem */ // create oriented bounding box in world space obb = new OrientedBoundingBox(leaf.Bounds, worldMatrix); if (!frustum.Intersects(obb.AABBWorld)) { continue; } else { Intersect = true; } VisibleLeafs++; for (int i = 0; i < leaf.LeafFaceCount; i++) { int faceIndex = leafFaces[leaf.StartLeafFace + i]; Q3BSPFace face = faces[faceIndex]; if (face.FaceType != Q3BSPFaceType.Billboard && !facesToDraw[faceIndex]) { facesToDraw[faceIndex] = true; visibleFaces.Add(face); } } } if (0 >= visibleFaces.Count) { return; } Q3BSPFaceComparer fc = new Q3BSPFaceComparer(); visibleFaces.Sort(fc); Matrix matrixWorldViewProjection = worldMatrix * viewMatrix * projMatrix; Effect effect; short[] indexArray = new short[maximumNumberOfIndicesToDraw]; int lastTextureIndex = 0; int lastLightMapIndex = 0; int accumulatedIndexCount = 0; graphics.DepthStencilState = DepthStencilState.Default; foreach (Q3BSPFace face in visibleFaces) { if (face.FaceType == Q3BSPFaceType.Patch) { effect = shaderManager.GetEffect(face.TextureIndex, face.LightMapIndex, viewMatrix, matrixWorldViewProjection, gameTime); foreach (EffectPass pass in effect.CurrentTechnique.Passes) { pass.Apply(); patches[face.PatchIndex].Draw(graphics); } continue; } if ((face.TextureIndex != lastTextureIndex || face.LightMapIndex != lastLightMapIndex) && accumulatedIndexCount > 0) { if (shaderManager.IsMaterialDrawable(lastTextureIndex)) { effect = shaderManager.GetEffect(lastTextureIndex, lastLightMapIndex, viewMatrix, matrixWorldViewProjection, gameTime); foreach (EffectPass pass in effect.CurrentTechnique.Passes) { pass.Apply(); graphics.DrawUserIndexedPrimitives <Q3BSPVertex>(PrimitiveType.TriangleList, vertices, 0, vertices.Length, indexArray, 0, accumulatedIndexCount / 3); } } //indexArray = new int[maximumNumberOfIndicesToDraw]; accumulatedIndexCount = 0; } lastTextureIndex = face.TextureIndex; lastLightMapIndex = face.LightMapIndex; for (int i = 0; i < face.MeshVertexCount; ++i) { indexArray[accumulatedIndexCount] = (short)(face.StartVertex + meshVertices[face.StartMeshVertex + i]); accumulatedIndexCount++; } } // Draw the final batch of faces if (indexArray.Length != 0 && shaderManager.IsMaterialDrawable(lastTextureIndex)) { effect = shaderManager.GetEffect(lastTextureIndex, lastLightMapIndex, viewMatrix, matrixWorldViewProjection, gameTime); foreach (EffectPass pass in effect.CurrentTechnique.Passes) { pass.Apply(); graphics.DrawUserIndexedPrimitives <Q3BSPVertex>(PrimitiveType.TriangleList, vertices, 0, vertices.Length, indexArray, 0, accumulatedIndexCount / 3); } } }