Template
*
This commit is contained in:
@@ -0,0 +1,385 @@
|
||||
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;
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user