163 lines
5.5 KiB
C#
163 lines
5.5 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using UnityEngine;
|
|
|
|
// Filename : CBlockImageFix16.cs
|
|
// Creator : ported from C++ (AutoPFImp/AutoMoveImp/blockimage.h)
|
|
// Date : 2026/01/09
|
|
|
|
namespace AutoMove
|
|
{
|
|
/// <summary>
|
|
/// Block image (FIX16) used by AutoPF to store delta-height (DH map).
|
|
/// 自动寻路使用的块图(FIX16),用于存储高度差(DH 图)。
|
|
/// </summary>
|
|
public class CBlockImageFix16
|
|
{
|
|
// Current Version // 当前版本
|
|
private const uint BLOCKIMAGE_VER = 0x00000002;
|
|
private const int NULL_ID = -1;
|
|
|
|
private int[] m_BlockIDs;
|
|
private readonly List<short[]> m_arrBlocks = new List<short[]>(256);
|
|
|
|
private int m_iBlockSize;
|
|
private int m_iBlockSizeExp;
|
|
private int m_iWidth; // blocks in width // 块宽
|
|
private int m_iLength; // blocks in length // 块长
|
|
|
|
private float m_fPixelSize;
|
|
private int m_iImageWidth;
|
|
private int m_iImageLength;
|
|
|
|
private short m_defaultVal;
|
|
|
|
public CBlockImageFix16(short defaultVal = 0, int iExp = 4)
|
|
{
|
|
m_defaultVal = defaultVal;
|
|
SetBlockSizeExp(iExp);
|
|
}
|
|
|
|
private void SetBlockSizeExp(int iExp)
|
|
{
|
|
m_iBlockSizeExp = iExp;
|
|
m_iBlockSize = 1 << iExp;
|
|
}
|
|
|
|
public void Release()
|
|
{
|
|
m_BlockIDs = null;
|
|
m_arrBlocks.Clear();
|
|
}
|
|
|
|
public void GetImageSize(out int width, out int length)
|
|
{
|
|
width = m_iImageWidth;
|
|
length = m_iImageLength;
|
|
}
|
|
|
|
public float GetPixelSize() => m_fPixelSize;
|
|
|
|
public short GetPixel(int u, int v)
|
|
{
|
|
if (m_BlockIDs == null) return m_defaultVal;
|
|
if (u < 0 || u >= m_iImageWidth || v < 0 || v >= m_iImageLength) return m_defaultVal;
|
|
|
|
int uBlkID = u >> m_iBlockSizeExp;
|
|
int vBlkID = v >> m_iBlockSizeExp;
|
|
int blkIndex = vBlkID * m_iWidth + uBlkID;
|
|
int blkId = m_BlockIDs[blkIndex];
|
|
if (blkId == NULL_ID) return m_defaultVal;
|
|
|
|
int uBlkOffset = u & (m_iBlockSize - 1);
|
|
int vBlkOffset = v & (m_iBlockSize - 1);
|
|
return m_arrBlocks[blkId][(vBlkOffset << m_iBlockSizeExp) + uBlkOffset];
|
|
}
|
|
|
|
/// <summary>
|
|
/// Load from bytes (binary). Matches C++ CBlockImage::Load logic for FIX16.
|
|
/// 从字节加载(二进制)。匹配 C++ 的 CBlockImage::Load 逻辑(FIX16)。
|
|
/// </summary>
|
|
public bool Load(byte[] fileBytes)
|
|
{
|
|
try
|
|
{
|
|
if (fileBytes == null || fileBytes.Length < 8) return false;
|
|
|
|
using var ms = new MemoryStream(fileBytes, false);
|
|
using var br = new BinaryReader(ms);
|
|
|
|
uint dwFileVersion = br.ReadUInt32();
|
|
if (dwFileVersion > BLOCKIMAGE_VER)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
uint bufSize = br.ReadUInt32();
|
|
if (bufSize == 0 || bufSize > fileBytes.Length) return false;
|
|
byte[] buf = br.ReadBytes((int)bufSize);
|
|
if (buf.Length != bufSize) return false;
|
|
|
|
int cur = 0;
|
|
|
|
if (dwFileVersion == BLOCKIMAGE_VER)
|
|
{
|
|
// Version 2: includes T size and default T value.
|
|
// 版本2:包含 T 的大小与默认值。
|
|
uint tSize = BitConverter.ToUInt32(buf, cur); cur += 4;
|
|
if (tSize != 2)
|
|
{
|
|
// FIX16 should be 2 bytes.
|
|
// FIX16 应为 2 字节。
|
|
return false;
|
|
}
|
|
|
|
m_defaultVal = BitConverter.ToInt16(buf, cur); cur += 2;
|
|
}
|
|
|
|
m_iWidth = BitConverter.ToInt32(buf, cur); cur += 4;
|
|
m_iLength = BitConverter.ToInt32(buf, cur); cur += 4;
|
|
m_iBlockSizeExp = BitConverter.ToInt32(buf, cur); cur += 4;
|
|
m_iBlockSize = 1 << m_iBlockSizeExp;
|
|
m_iImageWidth = BitConverter.ToInt32(buf, cur); cur += 4;
|
|
m_iImageLength = BitConverter.ToInt32(buf, cur); cur += 4;
|
|
m_fPixelSize = BitConverter.ToSingle(buf, cur); cur += 4;
|
|
|
|
int blkIdCount = m_iWidth * m_iLength;
|
|
if (blkIdCount <= 0) return false;
|
|
int blkIdBytes = blkIdCount * 4;
|
|
if (cur + blkIdBytes > buf.Length) return false;
|
|
|
|
m_BlockIDs = new int[blkIdCount];
|
|
Buffer.BlockCopy(buf, cur, m_BlockIDs, 0, blkIdBytes);
|
|
cur += blkIdBytes;
|
|
|
|
int nBlocks = BitConverter.ToInt32(buf, cur); cur += 4;
|
|
if (nBlocks < 0) return false;
|
|
|
|
m_arrBlocks.Clear();
|
|
int blkSizeShorts = m_iBlockSize * m_iBlockSize;
|
|
int blkSizeBytes = blkSizeShorts * 2;
|
|
for (int i = 0; i < nBlocks; i++)
|
|
{
|
|
if (cur + blkSizeBytes > buf.Length) return false;
|
|
short[] block = new short[blkSizeShorts];
|
|
Buffer.BlockCopy(buf, cur, block, 0, blkSizeBytes);
|
|
cur += blkSizeBytes;
|
|
m_arrBlocks.Add(block);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.LogWarning($"[CBlockImageFix16] Load failed: {ex.Message}");
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|