Files
2025-05-13 03:10:33 +03:00

386 lines
11 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http.Headers;
using System.Runtime.InteropServices;
using UnityEngine;
public class LevelLoader : MonoBehaviour
{
public string LevelName = "COLD1";
private string _resoucresDir = @"C:\Users\l-pro\OneDrive\Рабочий стол\HogsOfWar\Processed";
private string PmgPath { get { return Path.Combine(_resoucresDir, LevelName + ".PMG"); } }
private string PtgPath { get { return Path.Combine(_resoucresDir, LevelName + ".PTG"); } }
private string PogPath { get { return Path.Combine(_resoucresDir, LevelName + ".POG"); } }
public static uint TimPixelToRgba32(ushort timPixel) {
uint r = (uint)(timPixel & 0x1f);
uint g = (uint)(((timPixel) >> 5) & 0x1f);
uint b = (uint)(((timPixel) >> 10) & 0x1f);
r <<= 3;
g <<= 3;
b <<= 3;
bool black = (timPixel & 0x7fff) == 0;
bool stpOn = (timPixel & 0x8000) != 0;
uint alpha = ((black && stpOn) || (!black && !stpOn)) ? (byte)0xff : (byte)0x00;
return r | (g << 8) | (b << 16) | (alpha << 24);
}
public Material Mat;
private static ImageRGBA32 TimToImage(TimFile tim) {
uint[] data = new uint[tim.ImageHeight * tim.ImageWidth];
var format = tim.header.Format;
if (format == TimFile.Format.Bpp4Bit) {
for (int i = 0; i < tim.image.data.Length; i++) {
var ip = tim.image.data[i];
var i0 = (ip >> 0) & 0x0f;
var i1 = (ip >> 4) & 0x0f;
var i2 = (ip >> 8) & 0x0f;
var i3 = (ip >> 12) & 0x0f;
data[i * 4 + 0] = TimPixelToRgba32(tim.lut.data[i0]);
data[i * 4 + 1] = TimPixelToRgba32(tim.lut.data[i1]);
data[i * 4 + 2] = TimPixelToRgba32(tim.lut.data[i2]);
data[i * 4 + 3] = TimPixelToRgba32(tim.lut.data[i3]);
}
}
ImageRGBA32 img = new ImageRGBA32((uint)tim.ImageWidth, (uint)tim.ImageHeight, data);
return img;
}
public InspectorButton Rebuild_;
class ImageRGBA32 {
public uint Width;
public uint Height;
public uint[] Data;
public ImageRGBA32(uint width, uint height) {
Width = width;
Height = height;
Data = new uint[Width * Height];
}
public ImageRGBA32(uint width, uint height, uint[] data) {
Width = width;
Height = height;
Data = data;
}
public void Fill(uint color) {
for(int i = 0; i < Data.Length; ++i) {
Data[i] = color;
}
}
public void Blit(ImageRGBA32 image, uint x, uint y) {
for(uint iy = 0; iy < image.Height; ++iy) {
uint ry = iy + y;
if(ry >= Height) {
break;
}
for (uint ix = 0; ix < image.Width; ++ix) {
uint rx = ix + x;
if (rx >= Width) {
break;
}
var color = image.Data[iy * image.Width + ix];
Data[ry * Width + rx] = color;
}
}
}
public Texture2D ToTexture2D() {
Texture2D tex = new Texture2D((int)Width, (int)Height, TextureFormat.RGBA32, false);
var handle = GCHandle.Alloc(Data, GCHandleType.Pinned);
tex.LoadRawTextureData(handle.AddrOfPinnedObject(), Data.Length * 4);
handle.Free();
tex.Apply();
return tex;
}
public ImageRGBA32 FlipX() {
ImageRGBA32 result = new ImageRGBA32(Width, Height);
for (int y = 0; y < Height; ++y) {
for (int x = 0; x < Width; ++x) {
var vy = y;
var vx = Width - x - 1;
result.Data[vy * result.Width + vx] = Data[y * Width + x];
}
}
return result;
}
public ImageRGBA32 Rotate90() {
ImageRGBA32 result = new ImageRGBA32(Height, Width);
for(int y = 0; y < Height; ++y) {
for (int x = 0; x < Width; ++x) {
var vy = x;
var vx = Height - y - 1;
result.Data[vy * result.Width + vx] = Data[y * Width + x];
}
}
return result;
}
}
public Texture2D Atlas;
public bool ApplyTransform = false;
public void BuildMapTexture(PmgFile pmg, PtgFile ptg) {
var textures = ptg.Textures.Select(v => TimToImage(v)).ToArray();
var sideBlocks = (int)Math.Sqrt(pmg.Blocks.Length);
Debug.Log("Side blocks: " + sideBlocks);
uint atlasSize = (uint)(sideBlocks * 4 * ptg.Textures[0].ImageWidth);
uint textureBlockSize = textures[0].Width;
ImageRGBA32 atlas = new ImageRGBA32(atlasSize, atlasSize);
atlas.Fill(0xffffffff);
Debug.Log("Atlas size: " + atlasSize);
for (int y = 0; y < sideBlocks; ++y) {
for (int x = 0; x < sideBlocks; ++x) {
int blockId = y * sideBlocks + x;
var block = pmg.Blocks[blockId];
for (int tileY = 0; tileY < 4; ++tileY) {
for (int tileX = 0; tileX < 4; ++tileX) {
int tileId = tileY * 4 + tileX;
var tile = block.tiles[tileId];
var texId = tile.TextureIndex;
/* if(tile.RotationFlip != PmgFile.PmgBlock.Tile.Transform.None) {
Debug.Log("Transform = " + tile.RotationFlip.ToString());
}*/
var tex = textures[texId];
if (ApplyTransform) {
if ((tile.RotationFlip & PmgFile.PmgBlock.Tile.Transform.FlipX) == PmgFile.PmgBlock.Tile.Transform.FlipX) {
tex = tex.FlipX();
}
if ((tile.RotationFlip & PmgFile.PmgBlock.Tile.Transform.Rotate90) == PmgFile.PmgBlock.Tile.Transform.Rotate90) {
tex = tex.Rotate90();
}
if ((tile.RotationFlip & PmgFile.PmgBlock.Tile.Transform.Rotate180) == PmgFile.PmgBlock.Tile.Transform.Rotate180) {
tex = tex.Rotate90();
tex = tex.Rotate90();
}
}
var ty = y * 4 + tileY;
var tx = x * 4 + tileX;
atlas.Blit(tex, (uint)(tx * textureBlockSize), (uint)(ty * textureBlockSize));
}
}
}
}
Atlas = atlas.ToTexture2D();
Atlas.filterMode = FilterMode.Point;
if (Mat != null) {
Mat.mainTexture = Atlas;
}
}
public PogFile.ObjectRecord[] Objects;
private float unitScale = 1.0f / 512.0f;
private void PlaceObjects() {
var pogBytes = File.ReadAllBytes(PogPath);
Objects = PogFile.Parse(pogBytes).Objects;
var parent = transform.GetChild(0);
var oldChildsCount = parent.childCount;
List<Transform> children = new List<Transform>();
for(int i = 0; i < oldChildsCount; ++i) {
children.Add(parent.GetChild(i));
}
foreach(var child in children) {
UnityEngine.Object.DestroyImmediate(child.gameObject);
}
foreach (var obj in Objects) {
var transform = new Vector3(-obj.XOffset, obj.YOffset, -obj.ZOffset) * unitScale;
GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
cube.transform.parent = parent;
cube.transform.position = transform;
cube.transform.localScale = Vector3.one;
cube.transform.localRotation = Quaternion.identity;
cube.name = obj.Name;
}
}
public void Rebuild() {
PlaceObjects();
var pmgBytes = File.ReadAllBytes(PmgPath);
var ptgBytes = File.ReadAllBytes(PtgPath);
var pmg = PmgFile.Parse(pmgBytes);
var ptg = PtgFile.Parse(ptgBytes);
var pmgBlocks = pmg.Blocks;
List<Vector3> result = new List<Vector3>();
List<int> indices = new List<int>();
Debug.Log("pmgBlocks count: " + pmgBlocks.Length);
TriangleMeshConstructor mc = new TriangleMeshConstructor();
var uvs = mc.UvChannel(0);
int blockSideCount = (int)Math.Sqrt(pmgBlocks.Length);
int blockx = 0;
int blocky = 0;
List<Color> colors = new List<Color>();
short zoffset = -32001;
var cornerX = -8 * 4 * 512;
var cornerY = 8 * 4 * 512;
var cornerDX = cornerX - pmgBlocks[0].xOffset;
var cornerDY = cornerY - pmgBlocks[0].zOffset;
foreach (var block in pmgBlocks) {
float x = block.xOffset + cornerDX;
float z = block.zOffset+ cornerDY;
if(zoffset != block.zOffset) {
zoffset = block.zOffset;
Debug.Log("zoffset: " + zoffset);
}
var vertices = block.vertices;
int indexOffset = result.Count;
for (int i = 0; i < vertices.Length; ++i) {
var v = vertices[i];
int vx = (i % 5) * 512;
int vy = (i / 5) * 512;
int vXId = blockx * 4 + (i % 5);
int vYId = blocky * 4 + (i / 5);
uvs.Add(new Vector2(vXId / (float)(blockSideCount * 4), vYId / (float)(blockSideCount * 4)));
result.Add(new Vector3(-(x + vx), v.height, (-z + vy)) * unitScale);
float l = v.lighting / 255.0f;
colors.Add(new Color(l, l, l, 1.0f));
}
for (int yVertex = 0; yVertex < 4; yVertex++) {
for (int xVertex = 0; xVertex < 4; xVertex++) {
int i0 = (yVertex + 0) * 5 + (xVertex + 0);
int i2 = (yVertex + 1) * 5 + (xVertex + 0);
int i1 = (yVertex + 0) * 5 + (xVertex + 1);
int i3 = (yVertex + 0) * 5 + (xVertex + 1);
int i5 = (yVertex + 1) * 5 + (xVertex + 0);
int i4 = (yVertex + 1) * 5 + (xVertex + 1);
indices.Add(i0 + indexOffset);
indices.Add(i1 + indexOffset);
indices.Add(i2 + indexOffset);
indices.Add(i3 + indexOffset);
indices.Add(i4 + indexOffset);
indices.Add(i5 + indexOffset);
}
}
blockx++;
if(blockx == blockSideCount) {
blockx = 0;
blocky++;
}
}
mc.Vertices = result;
mc.Indices = indices.ToArray();
mc.Colors = colors;
// mc.AssingColors(Color.white);
mc.BreakVertices();
mc.RecalculateFlatNormals();
var pm = GetComponent<ProceduralMesh>();
pm.Rebuild(mc);
BuildMapTexture(pmg, ptg);
GetComponent<MeshRenderer>().sharedMaterial.mainTexture = Atlas;
}
}