/// <summary> /// Compile the map into a stream of OpenGL-compatible data /// </summary> public static void CompileMap(List <Vertex> verts, List <Face> faces, List <int> meshVerts, List <lightmap_rect_t> lightmaps, List <shader_p> shaders, int tesselationLevel) { Vertex vert; BspCompiler.faces = faces; q3bsp.onMessage(new MessageParams() { type = "status", message = "Map geometry parsed, compiling shaders..." }); // Find associated shaders for all clusters // Per-face operations for (int i = 0; i < faces.Count; ++i) { Face face = faces[i]; if (face.type == 1 || face.type == 2 || face.type == 3) { // Add face to the appropriate texture face list shader_p shader = shaders[(int)face.shader]; shader.faces.Add(face); lightmap_rect_t lightmap = face.lightmap > 0 ? lightmaps[(int)face.lightmap] : null; if (lightmap == null) { lightmap = lightmaps[0]; } if (face.type == 1 || face.type == 3) { shader.geomType = face.type; // Transform lightmap coords to match position in combined texture for (int j = 0; j < face.meshVertCount; ++j) { vert = verts[(int)face.vertex + (int)meshVerts[(int)face.meshVert + j]]; vert.lmNewCoord.X = (vert.lmCoord.X * lightmap.xScale) + lightmap.x; vert.lmNewCoord.Y = (vert.lmCoord.Y * lightmap.yScale) + lightmap.y; } } else { q3bsp.onMessage(new MessageParams() { type = "status", message = "Tesselating face " + i.ToString() + " of " + faces.Count.ToString() }); // Build Bezier curve BspTess.Tesselate(face, verts, meshVerts, tesselationLevel); for (int j = 0; j < face.vertCount; ++j) { vert = verts[(int)face.vertex + j]; vert.lmNewCoord.X = (vert.lmCoord.X * lightmap.xScale) + lightmap.x; vert.lmNewCoord.Y = (vert.lmCoord.Y * lightmap.yScale) + lightmap.y; } } } } // Compile vert list INTERLEAVE float[] vertices; vertices = Interleave(verts); // Compile index list List <ushort> lst_indices = new List <ushort>(); for (int i = 0; i < shaders.Count; ++i) { shader_p shader = shaders[i]; if (shader.faces.Count > 0) { shader.indexOffset = lst_indices.Count * 2; // Offset is in bytes for (int j = 0; j < shader.faces.Count; ++j) { Face face = shader.faces[j]; face.indexOffset = lst_indices.Count * 2; for (int k = 0; k < face.meshVertCount; ++k) { lst_indices.Add((ushort)(face.vertex + meshVerts[face.meshVert + k])); } shader.elementCount += (int)face.meshVertCount; } } shader.faces = null; // Don't need to send this to the render thread. } ushort[] indices = lst_indices.ToArray(); // Send the compiled vertex/index data back to the render thread q3bsp.onMessage(new MessageParams() { type = "geometry", vertices = vertices, indices = indices, surfaces = shaders }); }
/// <summary> /// Read all lightmaps /// </summary> private static List <lightmap_rect_t> ReadLightmaps(bsp_header_lump_t lump, BinaryStreamReader src) { int lightmapSize = 128 * 128; int count = (int)lump.length / (lightmapSize * 3); var gridSize = 2; while (gridSize * gridSize < count) { gridSize *= 2; } var textureSize = gridSize * 128; int xOffset = 0; int yOffset = 0; List <lightmap_t> lightmaps = new List <lightmap_t>(); List <lightmap_rect_t> lightmapRects = new List <lightmap_rect_t>(); Vector3 rgb = Vector3.Zero; src.Seek(lump.offset); for (int i = 0; i < count; ++i) { byte[] elements = new byte[lightmapSize * 4]; for (int j = 0; j < lightmapSize * 4; j += 4) { rgb.X = src.ReadUByte(); rgb.Y = src.ReadUByte(); rgb.Z = src.ReadUByte(); rgb = BspHelpers.brightnessAdjust(rgb, 4.0f); elements[j] = (byte)rgb.X; elements[j + 1] = (byte)rgb.Y; elements[j + 2] = (byte)rgb.Z; elements[j + 3] = 255; } lightmap_t l = new lightmap_t(); l.x = xOffset; l.y = yOffset; l.width = 128; l.height = 128; l.bytes = elements; lightmaps.Add(l); lightmap_rect_t r = new lightmap_rect_t(); r.x = (float)xOffset / (float)textureSize; r.y = (float)yOffset / (float)textureSize; r.xScale = 128f / (float)textureSize; r.yScale = 128f / (float)textureSize; lightmapRects.Add(r); xOffset += 128; if (xOffset >= textureSize) { yOffset += 128; xOffset = 0; } } // Send the lightmap data back to the render thread q3bsp.onMessage(new MessageParams() { type = "lightmap", size = textureSize, lightmaps = lightmaps }); return(lightmapRects); }