public SourceMap(World world) { this.world = world; Commands.Instance.AddCommand("movedebug", new CommandDelegate(MoveDebug_f)); //redCube.Color = new Color4[6]; //for (int i = 0; i < 6; i++) //{ // redCube.Color[i] = new Color4(1.0f, 0.0f, 0.0f); //} //ambientLightTexture = new Texture(Renderer.Instance.device, 256, 256, 0, Usage.Dynamic | Usage.WriteOnly, Format.A16B16G16R16F, Pool.Default); }
// Hook displacements into the bsp tree static void DispTreeLeafnum(World world) { // // get the number of displacements per leaf // List<dDispTri> tris = new List<dDispTri>(); world.dispCollTrees = new DispCollTree[world.DispIndexToFaceIndex.Length]; List<dDispVert> verts = new List<dDispVert>(); int currTri = 0, currVert = 0; for (int i = 0; i < world.DispIndexToFaceIndex.Length; i++) { int j; int faceIndex = world.DispIndexToFaceIndex[i]; int dispId = world.faces_t[faceIndex].dispinfo; ddispinfo_t info = world.ddispinfos[dispId]; int power = info.power; int nVerts = (((1 << (power)) + 1) * ((1 << (power)) + 1)); verts.Clear(); // fail code for (j = 0; j < nVerts; j++) { verts.Add(world.dispVerts[j + currVert]); } currVert += nVerts; int nTris = ((1 << (power)) * (1 << (power)) * 2); tris.Clear(); for (j = 0; j < nTris; j++) { tris.Add(world.dispTris[j + currTri]); } currTri += nTris; Displacement displace = new Displacement(); displace.Surface = new DispSurface(); DispSurface dispSurf = displace.Surface; dispSurf.m_PointStart = info.startPosition; dispSurf.m_Contents = info.contents; displace.InitDispInfo(info.power, info.minTess, info.smoothingAngle, verts, tris); dispSurf.m_Index = faceIndex; face_t face = world.faces_t[faceIndex]; if (face.numedges > 4) continue; Vector3[] surfPoints = new Vector3[4]; dispSurf.m_PointCount = face.numedges; for (j = 0; j < face.numedges; j++) { int eIndex = world.surfEdges[face.firstedge + j]; if (eIndex < 0) surfPoints[j] = world.verts[world.edges[-eIndex].v[1]].position; else surfPoints[j] = world.verts[world.edges[eIndex].v[0]].position; } dispSurf.m_Points = surfPoints; dispSurf.FindSurfPointStartIndex(); dispSurf.AdjustSurfPointData(); // // generate the collision displacement surfaces // world.dispCollTrees[i] = new DispCollTree(); DispCollTree dispTree = world.dispCollTrees[i]; // // check for null faces, should have been taken care of in vbsp!!! // if (dispSurf.m_PointCount != 4) continue; displace.Create(); // new collision dispTree.Create(displace); DispTreeLeafnum_r(world, faceIndex, i, 0); } }
static void createDispSurface(Face face, ddispinfo_t dispInfo, World map, int faceIndex) { face.HasDisplacement = true; Face actualFace = face; int ndx = faceIndex; while (actualFace.face_t.origFace > 0 && actualFace.face_t.origFace != ndx) { ndx = actualFace.face_t.origFace; actualFace = world.faces_t[actualFace.face_t.origFace].face; } actualFace.HasDisplacement = true; actualFace.DisplaceFaces = new int[] { faceIndex }; face.displace_offset = world.verts.Count; //// Get the texture vectors and offsets. These are used to calculate //// texture coordinates Vector3 texU = new Vector3(face.texinfo.textureVecs[0].X, face.texinfo.textureVecs[0].Y, face.texinfo.textureVecs[0].Z); float texUOffset = face.texinfo.textureVecs[0].W; Vector3 texV = new Vector3(face.texinfo.textureVecs[1].X, face.texinfo.textureVecs[1].Y, face.texinfo.textureVecs[1].Z); float texVOffset = face.texinfo.textureVecs[1].W; // Get the base vertices for this face Vector3[] vertices = new Vector3[face.nVerts]; for (int i = 0; i < face.nVerts; i++) { vertices[i] = world.verts[face.VertexOffset + i].position; } // Rotate the base coordinates for the surface until the first vertex // matches the start position float minDist = float.MaxValue; int minIndex = 0; for (int i = 0; i < 4; i++) { // Calculate the distance of the start position from this vertex float dist = (world.verts[face.VertexOffset + i].position - dispInfo.startPosition).Length();// * 0.0254f).Length(); // If this is the smallest distance we've seen, remember it if (dist < minDist) { minDist = dist; minIndex = i; } } // Rotate the displacement surface quad until we get the starting vertex // in the 0th position for (int i = 0; i < minIndex; i++) { Vector3 temp = vertices[0]; vertices[0] = vertices[1]; vertices[1] = vertices[2]; vertices[2] = vertices[3]; vertices[3] = temp; } // Calculate the vectors for the left and right edges of the surface // (remembering that the surface is wound clockwise) Vector3 leftEdge = vertices[1] - vertices[0]; Vector3 rightEdge = vertices[2] - vertices[3]; // Calculate the number of vertices along each edge of the surface int numEdgeVertices = (1 << dispInfo.power) + 1; // Calculate the subdivide scale, which will tell us how far apart to // put each vertex (relative to the length of the surface's edges) double subdivideScale = 1.0f / (double)(numEdgeVertices - 1); // Calculate the step size between vertices on the left and right edges Vector3 leftEdgeStep = Vector3.Multiply(leftEdge, (float)subdivideScale); Vector3 rightEdgeStep = Vector3.Multiply(rightEdge, (float)subdivideScale); // Remember the first vertex index in the vertex array uint firstVertex = (uint)world.verts.Count; float lightdeltaU = (1f) / (numEdgeVertices - 1); float lightdeltaV = (1f) / (numEdgeVertices - 1); float texUScale = 1.0f / (float)face.texinfo.texdata_t.width; float texVScale = 1.0f / (float)face.texinfo.texdata_t.height; // Temporary lists for accumulating the pars of a full VertexPositionTexturedNormalLightmap List<Vector3> verts = new List<Vector3>(); List<Vector2> texcoords = new List<Vector2>(); List<Vector2> lightcoords = new List<Vector2>(); // Generate the displaced vertices (this technique comes from the // Source SDK) for (int i = 0; i < numEdgeVertices; i++) { // Calculate the two endpoints for this section of the surface Vector3 leftEnd = Vector3.Multiply(leftEdgeStep, i); leftEnd += vertices[0]; Vector3 rightEnd = Vector3.Multiply(rightEdgeStep, i); rightEnd += vertices[3]; // Now, get the vector from left to right, and subdivide it as well Vector3 leftRightSeg = rightEnd - leftEnd; Vector3 leftRightStep = Vector3.Multiply(leftRightSeg, (float)subdivideScale); // Generate the vertices for this section for (int j = 0; j < numEdgeVertices; j++) { // Get the displacement info for this vertex uint dispVertIndex = (uint)Math.Abs(dispInfo.DispVertStart); dispVertIndex += (uint)(i * numEdgeVertices + j); dDispVert dispVertInfo = world.dispVerts[(int)dispVertIndex]; // Calculate the flat vertex Vector3 flatVertex = leftRightStep; flatVertex = Vector3.Multiply(flatVertex, j) + leftEnd; // Calculate the displaced vertex Vector3 dispVertex = dispVertInfo.vec; dispVertex = Vector3.Multiply(dispVertex, (float)(dispVertInfo.dist)) + flatVertex; verts.Add(dispVertex); // Calculate the texture coordinates for this vertex. Texture // coordinates are calculated using a planar projection, so we need // to use the non-displaced vertex position here float u = Vector3.Dot(texU, flatVertex) + texUOffset; u *= texUScale; float v = Vector3.Dot(texV, flatVertex) + texVOffset; v *= texVScale; Vector2 texCoord = new Vector2(u, v); texcoords.Add(texCoord); // Generate lightmap coordinates float lightmapU = (lightdeltaU * j * face.face_t.LightmapTextureSizeInLuxels[0]) + face.lightOffsetX + 0.5f; // pixel space float lightmapV = (lightdeltaV * i * face.face_t.LightmapTextureSizeInLuxels[1]) + face.lightOffsetY + 0.5f; // pixel space lightmapU /= LightmapSize.Width; lightmapV /= LightmapSize.Height; lightcoords.Add(new Vector2(lightmapU, lightmapV)); // Get the texture blend parameter for this vertex as well //float eh = (float)(dispVertInfo.alpha / 255.0); } } List<Vector3> normals = new List<Vector3>(); // Calculate normals at each vertex (this is adapted from the Source SDK, // including the two helper functions) for (int i = 0; i < numEdgeVertices; i++) { for (int j = 0; j < numEdgeVertices; j++) { // See which of the 4 possible edges (left, up, right, or down) are // incident on this vertex byte edgeBits = 0; for (int k = 0; k < 4; k++) { if (doesEdgeExist(j, i, (int)k, numEdgeVertices)) edgeBits |= (byte)(1 << (byte)k); } // Calculate the normal based on the adjacent edges Vector3 normal = getNormalFromEdges(j, i, edgeBits, numEdgeVertices, verts); // Add the normal to the normal array normals.Add(normal); } } Vector3[] BBox = new Vector3[2]; BBox[0] = Vector3.Zero; BBox[1] = Vector3.Zero; // Build real vertices && BBox for (int i = 0; i < verts.Count; i++) { BBox[0] = Vector3.Minimize(verts[i], BBox[0]); BBox[1] = Vector3.Maximize(verts[i], BBox[1]); VertexPositionNormalTexturedLightmap vert = new VertexPositionNormalTexturedLightmap(verts[i], normals[i], texcoords[i], lightcoords[i]); world.verts.Add(vert); } face.BBox = BBox; // Build indices List<uint> indices = new List<uint>(); // Now, triangulate the surface (this technique comes from the Source SDK) for (int i = 0; i < numEdgeVertices - 1; i++) { for (int j = 0; j < numEdgeVertices - 1; j++) { // Get the current vertex index (local to this surface) uint index = (uint)(i * numEdgeVertices + j); //if (index + numEdgeVertices + 1 + firstVertex > map.disp_vertex_array.Count - 1 || index + firstVertex < firstVertex) //{ // int test = 2; //} // See if this index is odd if ((index % 2) == 1) { // Add the vertex offset (so we reference this surface's // vertices in the array) index += firstVertex; // Create two triangles on this vertex from top-left to // bottom-right indices.Add((uint) index + 1); indices.Add((uint) index); indices.Add((uint) index + (uint)numEdgeVertices); indices.Add((uint) index + (uint)numEdgeVertices + 1); indices.Add((uint) index + 1); indices.Add((uint)index + (uint)numEdgeVertices); } else { // Add the vertex offset (so we reference this surface's // vertices in the array) index += firstVertex; // Create two triangles on this vertex from bottom-left to // top-right indices.Add((uint) index + (uint)numEdgeVertices + 1); indices.Add((uint)index); indices.Add((uint)index + (uint)numEdgeVertices); indices.Add((uint)index + 1); indices.Add((uint) index); indices.Add((uint)index + (uint)numEdgeVertices + 1); } } //face.VertexOffset = firstVertex; } face.nVerts = world.verts.Count - (int)firstVertex; face.indices = indices.ToArray(); //face.nDisplace = map.disp_primitive_set.Count - face.displace_offset; }
public static void LoadWorldMap(string filename) { FileStream stream; // Check filecache if (FileCache.Instance.Contains(filename)) { stream = File.OpenRead(FileCache.Instance.GetFile(filename).FullName); } // Check absolute path else if (File.Exists(filename)) { stream = File.OpenRead(filename); } else { Common.Instance.Error(string.Format("LoadWorldMap: {0} not found", filename)); return; } world = new World(); BinaryReader br = new BinaryReader(stream, Encoding.UTF8); // Read header.. int magic = (('P' << 24) + ('S' << 16) + ('B' << 8) + 'V'); int id = br.ReadInt32(); if (id != magic) { Common.Instance.Error(string.Format("LoadWorldMap:{0}: Wrong magic number", filename)); return; } Header sHeader = new Header(); sHeader.ident = id; sHeader.version = br.ReadInt32(); // GoldSrc map if (sHeader.version == 30) { GoldSrcParser.LoadWorldMap(sHeader, br); return; } sHeader.lumps = new Lump_t[Header.HEADER_LUMPS]; for (int i = 0; i < Header.HEADER_LUMPS; i++) { Lump_t lump; lump.fileofs = br.ReadInt32(); lump.filelen = br.ReadInt32(); lump.version = br.ReadInt32(); lump.fourCC = br.ReadChars(4); sHeader.lumps[i] = lump; } sHeader.mapRevision = br.ReadInt32(); LoadWorldLights(br, sHeader); LoadLightGrids(br, sHeader); LoadLightmaps(br, sHeader); LoadPak(br, sHeader); LoadTextures(br, sHeader); LoadPlanes(br, sHeader); LoadDisplacement(br, sHeader); LoadFaces(br, sHeader); // Req: planes & texinfos & light & displacemtn LoadLeafBrushes(br, sHeader); LoadBrushes(br, sHeader); LoadLeafFaces(br, sHeader); LoadNodesAndLeafs(br, sHeader); // Req: planes LoadGameAndProps(br, sHeader); // Req: leafs LoadModels(br, sHeader); LoadEntities(br, sHeader); LoadVisibility(br, sHeader); DispTreeLeafnum(world); SourceMap map = new SourceMap(world); map.Init(); Renderer.Instance.SourceMap = map; long now = HighResolutionTimer.Ticks; for (int i = 0; i < world.sourceProps.Count; i++) { world.sourceProps[i].UpdateMesh(); } float propLightingTime = (float)(HighResolutionTimer.Ticks - now) / HighResolutionTimer.Frequency; Common.Instance.WriteLine("Finished prop lighting: {0:0.000}s", propLightingTime); }
static void DispTreeLeafnum_r(World world, int faceid, int collId, int nodeIndex) { while (true) { // // leaf // if (nodeIndex < 0) { // // get leaf node // int leadIndex = -1 - nodeIndex; dleaf_t pLeaf = world.leafs[leadIndex]; if (pLeaf.DisplacementIndexes != null) { KeyValuePair<int, int>[] indexes = pLeaf.DisplacementIndexes; KeyValuePair<int, int>[] newid = new KeyValuePair<int, int>[indexes.Length + 1]; indexes.CopyTo(newid, 0); newid[newid.Length - 1] = new KeyValuePair<int,int>(faceid, collId); pLeaf.DisplacementIndexes = newid; } else { pLeaf.DisplacementIndexes = new KeyValuePair<int,int>[] { new KeyValuePair<int,int>(faceid, collId) }; } return; } // // choose side(s) to traverse // dnode_t pNode = world.nodes[nodeIndex]; cplane_t pPlane = pNode.plane; // get box position relative to the plane Vector3 min = world.faces[faceid].BBox[0]; Vector3 max = world.faces[faceid].BBox[1]; int sideResult = Common.Instance.BoxOnPlaneSide(ref min, ref max, pPlane); // front side if (sideResult == 1) { nodeIndex = pNode.children[0]; } // back side else if (sideResult == 2) { nodeIndex = pNode.children[1]; } // split else { DispTreeLeafnum_r(world, faceid, collId, pNode.children[0]); nodeIndex = pNode.children[1]; } } }