static ColorRGBExp32 TexLightToLinear(long Offset) { Offset += BSP_Header.Lumps[58].FileLen / 56 > 0 ? BSP_Header.Lumps[53].FileOfs : BSP_Header.Lumps[8].FileOfs; ColorRGBExp32 ColorRGBExp32 = new ColorRGBExp32(); BSPFileReader.ReadType(ref ColorRGBExp32, Offset); float Pow = Mathf.Pow(2, ColorRGBExp32.exponent); ColorRGBExp32.r = TexLightToLinearB(ColorRGBExp32.r, Pow); ColorRGBExp32.g = TexLightToLinearB(ColorRGBExp32.g, Pow); ColorRGBExp32.b = TexLightToLinearB(ColorRGBExp32.b, Pow); return(ColorRGBExp32); }
static void CreateLightMap(IList <Face> InpFaces, ref Texture2D Lightmap_tex, ref List <Vector2> UV2) { Texture2D[] LMs = new Texture2D[InpFaces.Count]; for (Int32 i = 0; i < InpFaces.Count; i++) { if (InpFaces[i].LightOfs == -1) { continue; } LMs[i] = new Texture2D(InpFaces[i].LightMapW, InpFaces[i].LightMapH, TextureFormat.RGB24, false, true); Color32[] TexPixels = new Color32[LMs[i].width * LMs[i].height]; for (Int32 j = 0; j < TexPixels.Length; j++) { ColorRGBExp32 ColorRGBExp32 = ConfigLoader.useHDRLighting ? TexLightToLinearHDR(InpFaces[i].LightOfs + (j * 4)) : TexLightToLinear(InpFaces[i].LightOfs + (j * 4)); TexPixels[j] = new Color32(ColorRGBExp32.r, ColorRGBExp32.g, ColorRGBExp32.b, 255); } LMs[i].SetPixels32(TexPixels); } Rect[] UVs2 = Lightmap_tex.PackTextures(LMs, 1); for (Int32 i = 0; i < InpFaces.Count; i++) { UnityEngine.Object.DestroyImmediate(LMs[i]); for (Int32 j = 0; j < InpFaces[i].UV2.Length; j++) { UV2.Add(new Vector2((InpFaces[i].UV2[j].x * UVs2[i].width) + UVs2[i].x, (InpFaces[i].UV2[j].y * UVs2[i].height) + UVs2[i].y)); } } //Add lightmap in array if (!ConfigLoader.LoadLightmapsAsTextureShader) { ConfigLoader.lightmapsData.Add(new LightmapData() { lightmapColor = Lightmap_tex }); LightmapSettings.lightmaps = ConfigLoader.lightmapsData.ToArray(); ConfigLoader.CurrentLightmap++; } //Add lightmap in array }
static ColorRGBExp32 TexLightToLinearHDR(long Offset) { Offset += BSP_Header.Lumps[58].FileLen / 56 > 0 ? BSP_Header.Lumps[53].FileOfs : BSP_Header.Lumps[8].FileOfs; ColorRGBExp32 ColorRGBExp32 = new ColorRGBExp32(); BSPFileReader.ReadType(ref ColorRGBExp32, Offset); float Pow = Mathf.Pow(2, ColorRGBExp32.exponent); //https://github.com/lewa-j/Unity-Source-Tools/blob/834869c8ad7ad8924af62e11e9e55486e18203e8/Assets/Code/Read/BSPFile.cs#L337 Color32 col = new Color(TexLightToLinearF(ColorRGBExp32.r, Pow), TexLightToLinearF(ColorRGBExp32.g, Pow), TexLightToLinearF(ColorRGBExp32.b, Pow), 1f).gamma; ColorRGBExp32.r = col.r; ColorRGBExp32.g = col.g; ColorRGBExp32.b = col.b; return(ColorRGBExp32); }
private static ColorRGBExp32 TexLightToLinear(int fileofs) { switch (BSP_Header.version) { // FITCH: If BSP version more than 20, you need load HDR lumps case 21: fileofs += BSP_Header.lumps[53].fileofs; break; default: fileofs += BSP_Header.lumps[8].fileofs; break; } ColorRGBExp32 ColorRGBExp32 = CRead.ReadType <ColorRGBExp32>(fileofs); // Convert HDR pixels to RGB ColorRGBExp32.r = (byte)Mathf.Clamp(ColorRGBExp32.r * Mathf.Pow(2, ColorRGBExp32.exponent), 0, 255); ColorRGBExp32.g = (byte)Mathf.Clamp(ColorRGBExp32.g * Mathf.Pow(2, ColorRGBExp32.exponent), 0, 255); ColorRGBExp32.b = (byte)Mathf.Clamp(ColorRGBExp32.b * Mathf.Pow(2, ColorRGBExp32.exponent), 0, 255); return(ColorRGBExp32); }
private static void CreateLightMap(List <face> inpFaces, ref Texture2D lightMap, ref List <Vector2> lightMapUV) { Texture2D[] lightMaps = new Texture2D[inpFaces.Count]; // Load lightmap for each face for (int i = 0; i < inpFaces.Count; i++) { lightMaps[i] = new Texture2D(inpFaces[i].lightMapW, inpFaces[i].lightMapH, TextureFormat.RGB24, false); Color32[] TexPixels = new Color32[inpFaces[i].lightMapW * inpFaces[i].lightMapH]; int LightMapOffset = BSP_Faces[inpFaces[i].index].lightofs; if (LightMapOffset > 0) { for (int n = 0; n < TexPixels.Length; n++) { ColorRGBExp32 ColorRGBExp32 = TexLightToLinear(LightMapOffset + (n * 4)); TexPixels[n] = new Color32(ColorRGBExp32.r, ColorRGBExp32.g, ColorRGBExp32.b, 255); } lightMaps[i].SetPixels32(TexPixels); } } // Generate lightmap atlas Rect[] uvs2 = lightMap.PackTextures(lightMaps.ToArray(), 1); lightMap.wrapMode = TextureWrapMode.Clamp; lightMap.Apply(); // Generate UV for lightmap atlas for (int i = 0; i < inpFaces.Count; i++) { for (int l = 0; l < inpFaces[i].uv2.Length; l++) { lightMapUV.Add(new Vector2((inpFaces[i].uv2[l].x * uvs2[i].width) + uvs2[i].x, (inpFaces[i].uv2[l].y * uvs2[i].height) + uvs2[i].y)); } } }
private void GenerateLightmapPixels() { var lightingLump = _bsp.Lighting.Length > 0 ? _bsp.Lighting.LumpType : _bsp.LightingHdr.LumpType; var hdr = lightingLump == _bsp.LightingHdr.LumpType; using (var sampleStream = _bsp.GetLumpStream(lightingLump)) { var lightmap = _bsp.LightmapLayout; var width = lightmap.TextureSize.X; var height = lightmap.TextureSize.Y; var colors = new Color[width * height]; var sampleBuffer = new ColorRGBExp32[256 * 256]; var faces = hdr ? _bsp.FacesHdr : _bsp.Faces; var fullbright = true; for (int i = 0, iEnd = faces.Length; i < iEnd; ++i) { var face = faces[i]; if (face.LightOffset == -1) { continue; } var rect = lightmap.GetLightmapRegion(i); var sampleCount = rect.Width * rect.Height; sampleStream.Seek(face.LightOffset, System.IO.SeekOrigin.Begin); LumpReader <ColorRGBExp32> .ReadLumpFromStream(sampleStream, sampleCount, sampleBuffer); for (var y = 0; y < rect.Height; ++y) { for (var x = 0; x < rect.Width; ++x) { var s = Math.Max(0, Math.Min(x, rect.Width - 1)); var t = Math.Max(0, Math.Min(y, rect.Height - 1)); var sampleIndex = s + t * rect.Width; var sample = sampleBuffer[sampleIndex]; if (fullbright && (sample.R != 0 || sample.G != 0 || sample.B != 0)) { fullbright = false; } colors[width * (rect.Y + y) + (rect.X + x)] = new Color( TexLightToLinear(sample.R, sample.Exponent), TexLightToLinear(sample.G, sample.Exponent), TexLightToLinear(sample.B, sample.Exponent), 1.0f).gamma; } } } if (fullbright) { for (int i = 0; i < colors.Length; i++) { colors[i] = Color.white; } } var dir = new Texture2D(512, 512, UnityEngine.TextureFormat.RGBA32, false); var dirColors = new Color[512 * 512]; for (int i = 0; i < 512 * 512; i++) { dirColors[i] = Color.white; } dir.SetPixels(dirColors); dir.Apply(); var tex = new Texture2D(width, height, UnityEngine.TextureFormat.RGBA32, false); tex.SetPixels(colors); tex.Apply(); var lightmaps = LightmapSettings.lightmaps.ToList(); lightmaps.Clear(); lightmaps.Add(new LightmapData { lightmapColor = tex, lightmapDir = dir }); LightmapSettings.lightmaps = lightmaps.ToArray(); } }
public void Get([Url] string map) { if (Skip) { Response.Close(); return; } Response.ContentType = MimeTypeMap.GetMimeType(".png"); var bsp = Program.GetMap(map); var lightingLump = bsp.LightingHdr.Length > 0 ? bsp.LightingHdr.LumpType : bsp.Lighting.LumpType; using (var sampleStream = bsp.GetLumpStream(lightingLump)) { var lightmap = bsp.LightmapLayout; var width = lightmap.TextureSize.X; var height = lightmap.TextureSize.Y; var pixels = new byte[width * height * 4]; var sampleBuffer = new ColorRGBExp32[256 * 256]; var faces = bsp.FacesHdr.Length > 0 ? bsp.FacesHdr : bsp.Faces; for (int i = 0, iEnd = faces.Length; i < iEnd; ++i) { var face = faces[i]; if (face.LightOffset == -1) { continue; } var rect = lightmap.GetLightmapRegion(i); var sampleCount = rect.Width * rect.Height; sampleStream.Seek(face.LightOffset, SeekOrigin.Begin); LumpReader <ColorRGBExp32> .ReadLumpFromStream(sampleStream, sampleCount, sampleBuffer); for (var y = 0; y < rect.Height; ++y) { for (var x = 0; x < rect.Width; ++x) { var s = Math.Max(0, Math.Min(x, rect.Width - 1)); var t = Math.Max(0, Math.Min(y, rect.Height - 1)); var index = (rect.X + x + width * (rect.Y + y)) * 4; var sampleIndex = s + t * rect.Width; var sample = sampleBuffer[sampleIndex]; pixels[index + 0] = sample.B; pixels[index + 1] = sample.G; pixels[index + 2] = sample.R; pixels[index + 3] = (byte)(sample.Exponent + 128); } } } using (var img = new MagickImage(pixels, new MagickReadSettings { Width = width, Height = height, PixelStorage = new PixelStorageSettings(StorageType.Char, "BGRA") })) { img.Write(Response.OutputStream, MagickFormat.Png); } Response.OutputStream.Close(); } }
void ParseHeader(BinaryReader BR) { //used utils/vrad/vradstaticprops.cpp:1506 -- void CVradStaticPropMgr::SerializeLighting() if (BR.BaseStream.Length < 40) { throw new Exception("Not a VHV file! (file size is less than header size)"); } //parsing main header BR.BaseStream.Seek(0, SeekOrigin.Begin); Header = new Structs.FileHeader_t { m_nVersion = BR.ReadInt32(), m_nChecksum = BR.ReadUInt32(), m_nVertexFlags = (Structs.VertexFlags)BR.ReadUInt32(), m_nVertexSize = BR.ReadUInt32(), m_nVertexes = BR.ReadUInt32(), m_nMeshes = BR.ReadInt32() }; //int[] unused = BR.ReadInt32Array(4); BR.BaseStream.Seek(16, SeekOrigin.Current); //skip unused if (Header.m_nVersion != Structs.VHV_VERSION) { throw new Exception($"Not supported version or not a VHV file! ({Header.m_nVersion}!={Structs.VHV_VERSION})"); } //parsing mesh headers Header.pMesh = new Structs.MeshHeader_t[Header.m_nMeshes]; for (int n = 0; n < Header.m_nMeshes; n++) { // construct mesh dictionary Header.pMesh[n] = new Structs.MeshHeader_t { m_nLod = BR.ReadUInt32(), m_nVertexes = BR.ReadUInt32(), m_nOffset = BR.ReadUInt32() }; BR.BaseStream.Seek(16, SeekOrigin.Current); //skip unused } //BR.BaseStream.Seek(4 * 109, SeekOrigin.Current); for (int n = 0; n < Header.m_nMeshes; n++) { // construct vertexes var pMesh = Header.pMesh[n]; BR.BaseStream.Seek(pMesh.m_nOffset, SeekOrigin.Begin); ColorRGBExp32[] m_VertexColors = new ColorRGBExp32[pMesh.m_nVertexes]; long POSITION_THERE = BR.BaseStream.Position; long BYTES_LEFT = BR.BaseStream.Length - POSITION_THERE; for (int k = 0; k < pMesh.m_nVertexes; k++) { //Vector vertexColor = m_StaticProps[i].m_MeshData[n].m_VertexColors[k]; //ColorRGBExp32 rgbColor; //VectorToColorRGBExp32(vertexColor, rgbColor); //byte[] dstColor;//[4]; //ConvertRGBExp32ToRGBA8888(rgbColor, dstColor); // b,g,r,a order //pVertexData[0] = dstColor[2]; //pVertexData[1] = dstColor[1]; //pVertexData[2] = dstColor[0]; //pVertexData[3] = dstColor[3]; //pVertexData += 4; //RGBA8888 -> RGBExp32 // Linear to Tex light [0-1 to 0-255] (mb to gamma?) //RGBExp32 -> Vector //if (Header.m_nVertexFlags.HasFlag(Structs.VertexFlags.VERTEX_COLOR)) //{ // //byte[] colordata = BR.ReadBytes(4); // byte[] colordata = BR.ReadBytes(3); // //0 1 2 3 // //4 5 6 7 // //8 9 10 11 // //float exponent = (float)System.Math.Pow(2f, colordata[3]); // //m_VertexColors[k] = new ColorRGBExp32(colordata[0], // // colordata[1], // // colordata[2], // // 255); // m_VertexColors[k] = new ColorRGBExp32(LightUtils.linearToTexLight(colordata[0], 1f), // LightUtils.linearToTexLight(colordata[1], 1f), // LightUtils.linearToTexLight(colordata[2], 1f), // 255); //} //else if (Header.m_nVertexFlags.HasFlag(Structs.VertexFlags.VERTEX_NORMAL)) { byte[] colordata = BR.ReadBytes(12); //0 1 2 3 //4 5 6 7 //8 9 10 11 float exponent = (float)Math.Pow(2f, MathUtils.Avg(colordata[3], colordata[7], colordata[11])); m_VertexColors[k] = new ColorRGBExp32(LightUtils.linearToTexLight(MathUtils.Avg(colordata[2], colordata[6], colordata[10]), exponent), LightUtils.linearToTexLight(MathUtils.Avg(colordata[1], colordata[5], colordata[9]), exponent), LightUtils.linearToTexLight(MathUtils.Avg(colordata[0], colordata[4], colordata[8]), exponent), 255); } else { throw new NotImplementedException("Not implemented vertex flag: " + Header.m_nVertexFlags); } } Header.pMesh[n].m_VertexColors = m_VertexColors; } }