public void Run() { using (globalLoadMarker.Auto()) { Stopwatch s = Stopwatch.StartNew(); lightMapPropertyId = Shader.PropertyToID(lightMapProperty); // Create a new BSPmap, which is an object that // represents the map and all its data as a whole using (fileLoadMarker.Auto()) { if (mapIsInsidePK3) { map = new BSPMap(mapName, true); } else { string path = Path.Combine(Application.streamingAssetsPath, mapName); map = new BSPMap(path, false); } s.Stop(); Debug.Log($"Read map file in {s.ElapsedMilliseconds}ms"); } s.Restart(); using (facesLoadMarker.Auto()) { // Each face is its own gameobject var groups = map.faceLump.faces.GroupBy(x => new { x.type, x.texture, x.lm_index }); foreach (var group in groups) { Face[] faces = group.ToArray(); if (faces.Length == 0) { continue; } Material mat = useRippedTextures ? FetchMaterial(map.textureLump.Textures[faces[0].texture].Name, faces[0].lm_index) : fallbackMaterial; switch (group.Key.type) { case 2: { GenerateBezObject(mat, faces); break; } case 1: case 3: { GeneratePolygonObject(mat, faces); break; } default: Debug.Log( $"Skipped face because it was not a polygon, mesh, or bez patch ({group.Key.type})."); break; } } GC.Collect(); s.Stop(); Debug.Log($"Loaded map in {s.ElapsedMilliseconds}ms"); } vertsCache = new List <Vector3>(); uvCache = new List <Vector2>(); uv2Cache = new List <Vector2>(); normalsCache = new List <Vector3>(); indiciesCache = new List <int>(); BezierMesh.ClearCaches(); } }
// This forms a mesh from a bez patch of your choice // from the face of your choice. // It's ready to render with tex coords and all. Mesh GenerateBezMesh(Face face, int patchNumber) { //Calculate how many patches there are using size[] //There are n_patchesX by n_patchesY patches in the grid, each of those //starts at a vert (i,j) in the overall grid //We don't actually need to know how many are on the Y length //but the forumla is here for historical/academic purposes int n_patchesX = ((face.size [0]) - 1) / 2; //int n_patchesY = ((face.size[1]) - 1) / 2; //Calculate what [n,m] patch we want by using an index //called patchNumber Think of patchNumber as if you //numbered the patches left to right, top to bottom on //the grid in a piece of paper. int pxStep = 0; int pyStep = 0; for (int i = 0; i < patchNumber; i++) { pxStep++; if (pxStep == n_patchesX) { pxStep = 0; pyStep++; } } //Create an array the size of the grid, which is given by //size[] on the face object. Vertex[,] vertGrid = new Vertex[face.size [0], face.size [1]]; //Read the verts for this face into the grid, making sure //that the final shape of the grid matches the size[] of //the face. int gridXstep = 0; int gridYstep = 0; int vertStep = face.vertex; for (int i = 0; i < face.n_vertexes; i++) { vertGrid [gridXstep, gridYstep] = map.vertexLump.Verts [vertStep]; vertStep++; gridXstep++; if (gridXstep == face.size [0]) { gridXstep = 0; gridYstep++; } } //We now need to pluck out exactly nine vertexes to pass to our //teselate function, so lets calculate the starting vertex of the //3x3 grid of nine vertexes that will make up our patch. //we already know how many patches are in the grid, which we have //as n and m. There are n by m patches. Since this method will //create one gameobject at a time, we only need to be able to grab //one. The starting vertex will be called vi,vj think of vi,vj as x,y //coords into the grid. int vi = 2 * pxStep; int vj = 2 * pyStep; //Now that we have those, we need to get the vert at [vi,vj] and then //the two verts at [vi+1,vj] and [vi+2,vj], and then [vi,vj+1], etc. //the ending vert will at [vi+2,vj+2] List<Vector3> bverts = new List<Vector3>(); //read texture/lightmap coords while we're at it //they will be tessellated as well. List<Vector2> uvs = new List<Vector2>(); List<Vector2> uv2s = new List<Vector2>(); //Top row bverts.Add(vertGrid [vi, vj].position); bverts.Add(vertGrid [vi + 1, vj].position); bverts.Add(vertGrid [vi + 2, vj].position); uvs.Add(vertGrid [vi, vj].texcoord); uvs.Add(vertGrid [vi + 1, vj].texcoord); uvs.Add(vertGrid [vi + 2, vj].texcoord); uv2s.Add(vertGrid [vi, vj].lmcoord); uv2s.Add(vertGrid [vi + 1, vj].lmcoord); uv2s.Add(vertGrid [vi + 2, vj].lmcoord); //Middle row bverts.Add(vertGrid [vi, vj + 1].position); bverts.Add(vertGrid [vi + 1, vj + 1].position); bverts.Add(vertGrid [vi + 2, vj + 1].position); uvs.Add(vertGrid [vi, vj + 1].texcoord); uvs.Add(vertGrid [vi + 1, vj + 1].texcoord); uvs.Add(vertGrid [vi + 2, vj + 1].texcoord); uv2s.Add(vertGrid [vi, vj + 1].lmcoord); uv2s.Add(vertGrid [vi + 1, vj + 1].lmcoord); uv2s.Add(vertGrid [vi + 2, vj + 1].lmcoord); //Bottom row bverts.Add(vertGrid [vi, vj + 2].position); bverts.Add(vertGrid [vi + 1, vj + 2].position); bverts.Add(vertGrid [vi + 2, vj + 2].position); uvs.Add(vertGrid [vi, vj + 2].texcoord); uvs.Add(vertGrid [vi + 1, vj + 2].texcoord); uvs.Add(vertGrid [vi + 2, vj + 2].texcoord); uv2s.Add(vertGrid [vi, vj + 2].lmcoord); uv2s.Add(vertGrid [vi + 1, vj + 2].lmcoord); uv2s.Add(vertGrid [vi + 2, vj + 2].lmcoord); //Now that we have our control grid, it's business as usual Mesh bezMesh = new Mesh(); bezMesh.name = "BSPfacemesh (bez)"; BezierMesh bezPatch = new BezierMesh(tessellations, bverts, uvs, uv2s); return bezPatch.Mesh; }
// This forms a mesh from a bez patch of your choice // from the face of your choice. // It's ready to render with tex coords and all. private Mesh GenerateBezMesh(Face face, int patchNumber) { using (generateBezMeshMarker.Auto()) { //Calculate how many patches there are using size[] //There are n_patchesX by n_patchesY patches in the grid, each of those //starts at a vert (i,j) in the overall grid //We don't actually need to know how many are on the Y length //but the forumla is here for historical/academic purposes int n_patchesX = (face.size[0] - 1) / 2; //int n_patchesY = ((face.size[1]) - 1) / 2; //Calculate what [n,m] patch we want by using an index //called patchNumber Think of patchNumber as if you //numbered the patches left to right, top to bottom on //the grid in a piece of paper. int pxStep = 0; int pyStep = 0; for (int i = 0; i < patchNumber; i++) { pxStep++; if (pxStep == n_patchesX) { pxStep = 0; pyStep++; } } //Create an array the size of the grid, which is given by //size[] on the face object. Vertex[,] vertGrid = new Vertex[face.size[0], face.size[1]]; //Read the verts for this face into the grid, making sure //that the final shape of the grid matches the size[] of //the face. int gridXstep = 0; int gridYstep = 0; int vertStep = face.vertex; for (int i = 0; i < face.n_vertexes; i++) { vertGrid[gridXstep, gridYstep] = map.vertexLump.verts[vertStep]; vertStep++; gridXstep++; if (gridXstep == face.size[0]) { gridXstep = 0; gridYstep++; } } //We now need to pluck out exactly nine vertexes to pass to our //teselate function, so lets calculate the starting vertex of the //3x3 grid of nine vertexes that will make up our patch. //we already know how many patches are in the grid, which we have //as n and m. There are n by m patches. Since this method will //create one gameobject at a time, we only need to be able to grab //one. The starting vertex will be called vi,vj think of vi,vj as x,y //coords into the grid. int vi = 2 * pxStep; int vj = 2 * pyStep; //Now that we have those, we need to get the vert at [vi,vj] and then //the two verts at [vi+1,vj] and [vi+2,vj], and then [vi,vj+1], etc. //the ending vert will at [vi+2,vj+2] int capacity = 3 * 3; List <Vector3> bverts = new List <Vector3>(capacity); //read texture/lightmap coords while we're at it //they will be tessellated as well. List <Vector2> uv = new List <Vector2>(capacity); List <Vector2> uv2 = new List <Vector2>(capacity); //Top row bverts.Add(vertGrid[vi, vj].position); bverts.Add(vertGrid[vi + 1, vj].position); bverts.Add(vertGrid[vi + 2, vj].position); uv.Add(vertGrid[vi, vj].texcoord); uv.Add(vertGrid[vi + 1, vj].texcoord); uv.Add(vertGrid[vi + 2, vj].texcoord); uv2.Add(vertGrid[vi, vj].lmcoord); uv2.Add(vertGrid[vi + 1, vj].lmcoord); uv2.Add(vertGrid[vi + 2, vj].lmcoord); //Middle row bverts.Add(vertGrid[vi, vj + 1].position); bverts.Add(vertGrid[vi + 1, vj + 1].position); bverts.Add(vertGrid[vi + 2, vj + 1].position); uv.Add(vertGrid[vi, vj + 1].texcoord); uv.Add(vertGrid[vi + 1, vj + 1].texcoord); uv.Add(vertGrid[vi + 2, vj + 1].texcoord); uv2.Add(vertGrid[vi, vj + 1].lmcoord); uv2.Add(vertGrid[vi + 1, vj + 1].lmcoord); uv2.Add(vertGrid[vi + 2, vj + 1].lmcoord); //Bottom row bverts.Add(vertGrid[vi, vj + 2].position); bverts.Add(vertGrid[vi + 1, vj + 2].position); bverts.Add(vertGrid[vi + 2, vj + 2].position); uv.Add(vertGrid[vi, vj + 2].texcoord); uv.Add(vertGrid[vi + 1, vj + 2].texcoord); uv.Add(vertGrid[vi + 2, vj + 2].texcoord); uv2.Add(vertGrid[vi, vj + 2].lmcoord); uv2.Add(vertGrid[vi + 1, vj + 2].lmcoord); uv2.Add(vertGrid[vi + 2, vj + 2].lmcoord); //Now that we have our control grid, it's business as usual Mesh bezMesh = new Mesh(); bezMesh.name = "BSPfacemesh (bez)"; BezierMesh bezPatch = new BezierMesh(tessellations, bverts, uv, uv2); return(bezPatch.Mesh); } }