mirror of
https://github.com/dpethes/rerogue.git
synced 2025-06-07 18:58:32 +02:00
hmt parser: proper texture entry parsing. Actual pixel data is not read yet
This commit is contained in:
parent
63b5b06674
commit
4e755f8797
@ -8,24 +8,35 @@ MC * material entry (36B)
|
|||||||
2B int 0, 1 (trooper, mat2)
|
2B int 0, 1 (trooper, mat2)
|
||||||
4B float (misc)
|
4B float (misc)
|
||||||
4B float (1.0)
|
4B float (1.0)
|
||||||
4B int always zero
|
4B int zero
|
||||||
4B int always 0x0A
|
4B int 0x0A
|
||||||
16B name
|
16B name
|
||||||
}
|
}
|
||||||
4B int texcount Tc
|
4B int texcount Tc
|
||||||
TC * texture entry
|
TC * texture entry 52B
|
||||||
{
|
{
|
||||||
4B int texture data offset
|
4B int pixel offset
|
||||||
28B
|
28B zero
|
||||||
4B int ? texname offset + 16, sometimes
|
4B int palette offset
|
||||||
4B int texname offset
|
4B int texname offset
|
||||||
2B int width
|
2B int width
|
||||||
2B int height
|
2B int height
|
||||||
8B ? texture format?
|
8B texture format {
|
||||||
|
1B 0x01
|
||||||
|
1B bits per pixel:
|
||||||
|
-0: 4bit
|
||||||
|
-1: 8bit
|
||||||
|
1B subtype:
|
||||||
|
-3 RGBA
|
||||||
|
-4 greyscale
|
||||||
|
-5 ? ov_rdir
|
||||||
|
1B 0, 0x40, 0x80
|
||||||
|
4B RGBA transparent color?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
TC * texture data
|
TC * texture data
|
||||||
{
|
{
|
||||||
16B texname = material name
|
16B texname = material name
|
||||||
48B 16xRGB palette pri r_pilot, e_core, moze byt iny pocet
|
xB RGB palette
|
||||||
N * texture pixels, grayscale 4bit
|
xB pixels/samples
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,8 @@ unit hmt_parser;
|
|||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
sysutils, Classes;
|
sysutils, Classes,
|
||||||
|
rs_image;
|
||||||
|
|
||||||
type
|
type
|
||||||
THmtMaterial = record
|
THmtMaterial = record
|
||||||
@ -17,7 +18,10 @@ type
|
|||||||
|
|
||||||
THmtTexture = record
|
THmtTexture = record
|
||||||
data_offset: integer;
|
data_offset: integer;
|
||||||
unknown: array[0..47] of byte;
|
palette_offset: integer;
|
||||||
|
name_offset: integer;
|
||||||
|
width, height: word;
|
||||||
|
name: array[0..15] of byte;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
THmtFile = record
|
THmtFile = record
|
||||||
@ -28,7 +32,7 @@ type
|
|||||||
textures: array of THmtTexture;
|
textures: array of THmtTexture;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure ParseHmtFile(const fname: string);
|
function ParseHmtFile(const fname: string): THmtFile;
|
||||||
|
|
||||||
//**************************************************************************************************
|
//**************************************************************************************************
|
||||||
implementation
|
implementation
|
||||||
@ -44,12 +48,67 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure ParseHmtFile(const fname: string);
|
|
||||||
|
procedure ReadTexture(var tex: THmtTexture; var f: TMemoryStream);
|
||||||
|
var
|
||||||
|
image: TRSImage;
|
||||||
|
buf: array[0..27] of byte;
|
||||||
|
description: TImageDescription;
|
||||||
|
bpp: byte;
|
||||||
|
color_rgba: integer;
|
||||||
|
pos: int64;
|
||||||
|
begin
|
||||||
|
tex.data_offset := f.ReadDWord;
|
||||||
|
f.ReadBuffer(buf, 28);
|
||||||
|
tex.palette_offset := f.ReadDWord;
|
||||||
|
tex.name_offset := f.ReadDWord;
|
||||||
|
tex.width := f.ReadWord;
|
||||||
|
tex.height := f.ReadWord;
|
||||||
|
|
||||||
|
f.ReadByte; //0x01
|
||||||
|
bpp := f.ReadByte;
|
||||||
|
image.type_ := f.ReadByte;
|
||||||
|
f.ReadByte;
|
||||||
|
color_rgba := f.ReadDWord;
|
||||||
|
|
||||||
|
pos := f.Position;
|
||||||
|
f.Seek(tex.name_offset, TSeekOrigin.soBeginning);
|
||||||
|
f.ReadBuffer(tex.name, 16);
|
||||||
|
f.Seek(pos, TSeekOrigin.soBeginning);
|
||||||
|
|
||||||
|
description := ImageDescription[image.type_];
|
||||||
|
image.sampleBits := description.sample_bits;
|
||||||
|
image.paletteEntries := description.palette_entries;
|
||||||
|
if image.type_ = 4 then
|
||||||
|
image.sampleBits := bpp * 4 + 4;
|
||||||
|
|
||||||
|
writeln(NameToString(tex.name));
|
||||||
|
writeln('size: ', tex.width, 'x', tex.height);
|
||||||
|
writeln('subtype: ', image.type_);
|
||||||
|
writeln('sample bits: ', image.sampleBits);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure ReadMaterial(var mat: THmtMaterial; var f: TMemoryStream);
|
||||||
|
begin
|
||||||
|
mat.type1 := f.ReadWord;
|
||||||
|
mat.type2 := f.ReadWord;
|
||||||
|
mat.unknown_float1 := f.ReadDWord;
|
||||||
|
mat.unknown_float2 := f.ReadDWord;
|
||||||
|
mat.zero := f.ReadDWord;
|
||||||
|
mat.hex_a := f.ReadDWord;
|
||||||
|
f.ReadBuffer(mat.name, 16);
|
||||||
|
|
||||||
|
writeln(NameToString(mat.name));
|
||||||
|
if (mat.zero <> 0) or (mat.hex_a <> $A) then
|
||||||
|
writeln('unusual file');
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function ParseHmtFile(const fname: string): THmtFile;
|
||||||
var
|
var
|
||||||
f: TMemoryStream;
|
f: TMemoryStream;
|
||||||
hmt: THmtFile;
|
hmt: THmtFile;
|
||||||
mat: THmtMaterial;
|
|
||||||
tex: THmtTexture;
|
|
||||||
i: Integer;
|
i: Integer;
|
||||||
begin
|
begin
|
||||||
f := TMemoryStream.Create;
|
f := TMemoryStream.Create;
|
||||||
@ -62,41 +121,29 @@ begin
|
|||||||
hmt.texture_count := f.ReadDWord;
|
hmt.texture_count := f.ReadDWord;
|
||||||
f.Seek(8, TSeekOrigin.soBeginning);
|
f.Seek(8, TSeekOrigin.soBeginning);
|
||||||
|
|
||||||
writeln('materials: ', hmt.material_count);
|
|
||||||
writeln('textures: ', hmt.texture_count);
|
|
||||||
writeln(' texture bytes: ', f.Size - sizeof(hmt.texture_count) - hmt.texture_offset);
|
|
||||||
|
|
||||||
//read materials
|
//read materials
|
||||||
|
writeln('materials: ', hmt.material_count);
|
||||||
SetLength(hmt.materials, hmt.material_count);
|
SetLength(hmt.materials, hmt.material_count);
|
||||||
for i := 0 to hmt.material_count - 1 do begin
|
for i := 0 to hmt.material_count - 1 do begin
|
||||||
mat.type1 := f.ReadWord;
|
ReadMaterial(hmt.materials[i], f);
|
||||||
mat.type2 := f.ReadWord;
|
|
||||||
mat.unknown_float1 := f.ReadDWord;
|
|
||||||
mat.unknown_float2 := f.ReadDWord;
|
|
||||||
mat.zero := f.ReadDWord;
|
|
||||||
mat.hex_a := f.ReadDWord;
|
|
||||||
f.ReadBuffer(mat.name, 16);
|
|
||||||
|
|
||||||
hmt.materials[i] := mat;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
for mat in hmt.materials do begin
|
if hmt.texture_count = 0 then begin
|
||||||
writeln(NameToString(mat.name));
|
result := hmt;
|
||||||
if (mat.zero <> 0) or (mat.hex_a <> $A) then
|
f.Free;
|
||||||
writeln('unusual file');
|
exit;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
//read textures
|
//read textures
|
||||||
if hmt.texture_count = 0 then
|
writeln('textures: ', hmt.texture_count);
|
||||||
exit;
|
f.Seek(hmt.texture_offset + 4, TSeekOrigin.soBeginning);
|
||||||
f.Seek(hmt.texture_offset + sizeof(hmt.texture_count), fsFromCurrent);
|
|
||||||
SetLength(hmt.textures, hmt.texture_count);
|
SetLength(hmt.textures, hmt.texture_count);
|
||||||
for i := 0 to hmt.texture_count - 1 do begin
|
for i := 0 to hmt.texture_count - 1 do begin
|
||||||
tex.data_offset := f.ReadDWord;
|
ReadTexture(hmt.textures[i], f);
|
||||||
f.ReadBuffer(tex.unknown, 48);
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
f.Free;
|
f.Free;
|
||||||
|
result := hmt;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
238
hmt_parser/rs_image.pas
Normal file
238
hmt_parser/rs_image.pas
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
unit rs_image;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
Classes, SysUtils;
|
||||||
|
|
||||||
|
type
|
||||||
|
TRGB = array[0..2] of byte;
|
||||||
|
PRGB = ^TRGB;
|
||||||
|
TPalette = array[0..256] of TRGB;
|
||||||
|
|
||||||
|
TRSImage = record
|
||||||
|
data_size: integer;
|
||||||
|
width, height: integer;
|
||||||
|
type_: byte;
|
||||||
|
sampleBits: byte;
|
||||||
|
paletteEntries: integer;
|
||||||
|
pixels: pbyte;
|
||||||
|
samples: pbyte;
|
||||||
|
palette: TPalette;
|
||||||
|
end;
|
||||||
|
|
||||||
|
type
|
||||||
|
TImageDescription = record
|
||||||
|
palette_entries: integer;
|
||||||
|
sample_bits: integer;
|
||||||
|
//alpha: byte;
|
||||||
|
end;
|
||||||
|
|
||||||
|
const
|
||||||
|
ImageDescription: array[0..5] of TImageDescription = (
|
||||||
|
(palette_entries: 16; sample_bits: 4),
|
||||||
|
(palette_entries: 256; sample_bits: 8),
|
||||||
|
(palette_entries: 0; sample_bits: 16),
|
||||||
|
(palette_entries: 0; sample_bits: 32),
|
||||||
|
(palette_entries: 0; sample_bits: 4),
|
||||||
|
(palette_entries: 0; sample_bits: 16)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
function LoadImageFromPack(var f: file): TRSImage;
|
||||||
|
|
||||||
|
//**************************************************************************************************
|
||||||
|
implementation
|
||||||
|
|
||||||
|
procedure Unpack4To8bit(const src: PByte; const samples: integer; const dst: PByte);
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
v: byte;
|
||||||
|
begin
|
||||||
|
for i := 0 to samples div 2 - 1 do begin
|
||||||
|
v := src[i];
|
||||||
|
dst[i * 2 ] := ((v shr 4) and %1111) shl 4;
|
||||||
|
dst[i * 2 + 1] := (v and %1111) shl 4;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure Unpack4bitTo24bitRGB(const src: PByte; const size: integer; const dst: PByte; const pal: TPalette);
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
index: integer;
|
||||||
|
dest: PRGB;
|
||||||
|
begin
|
||||||
|
dest := PRGB(dst);
|
||||||
|
for i := 0 to size div 2 - 1 do begin
|
||||||
|
index := src[i];
|
||||||
|
dest[i * 2 ] := pal[(index shr 4) and 15];
|
||||||
|
dest[i * 2 + 1] := pal[index and 15];
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure Unpack8bitTo24bitRGB(const src: PByte; const size: integer; const dst: PByte; const pal: TPalette);
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
index: integer;
|
||||||
|
dest: PRGB;
|
||||||
|
begin
|
||||||
|
dest := PRGB(dst);
|
||||||
|
for i := 0 to size - 1 do begin
|
||||||
|
index := src[i];
|
||||||
|
dest[i] := pal[index];
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure UseOddBytes(const src: PByte; const size: integer; const dst: pbyte);
|
||||||
|
var
|
||||||
|
i: integer;
|
||||||
|
begin
|
||||||
|
for i := 0 to size - 1 do begin
|
||||||
|
dst[i] := src[i * 2 + 1];
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure DecodePixels(var img: TRSImage);
|
||||||
|
var
|
||||||
|
size: integer;
|
||||||
|
begin
|
||||||
|
img.pixels := nil;
|
||||||
|
if not(img.type_ in [0, 1, 2, 3, 4, 5]) then exit;
|
||||||
|
|
||||||
|
if img.sampleBits = 32 then begin
|
||||||
|
size := img.width * img.height * 4;
|
||||||
|
img.pixels := GetMem(size);
|
||||||
|
Move(img.samples^, img.pixels^, size);
|
||||||
|
end;
|
||||||
|
|
||||||
|
if img.sampleBits = 4 then begin
|
||||||
|
//4bit grayscale
|
||||||
|
if img.paletteEntries = 0 then begin
|
||||||
|
size := img.width * img.height;
|
||||||
|
img.pixels := GetMem(size);
|
||||||
|
Unpack4To8bit(img.samples, size, img.pixels);
|
||||||
|
end;
|
||||||
|
//24bit RGB palettized
|
||||||
|
if img.paletteEntries = 16 then begin
|
||||||
|
size := img.width * img.height;
|
||||||
|
img.pixels := GetMem(size * 3);
|
||||||
|
Unpack4bitTo24bitRGB(img.samples, size, img.pixels, img.palette);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if img.sampleBits = 8 then begin
|
||||||
|
//8bit grayscale
|
||||||
|
if img.paletteEntries = 0 then begin
|
||||||
|
size := img.width * img.height;
|
||||||
|
img.pixels := GetMem(size);
|
||||||
|
move(img.samples^, img.pixels^, size);
|
||||||
|
end;
|
||||||
|
//24bit RGB palettized
|
||||||
|
if img.paletteEntries = 256 then begin
|
||||||
|
size := img.width * img.height;
|
||||||
|
img.pixels := GetMem(size * 3);
|
||||||
|
Unpack8bitTo24bitRGB(img.samples, size, img.pixels, img.palette);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if img.sampleBits = 16 then begin
|
||||||
|
size := img.width * img.height;
|
||||||
|
img.pixels := GetMem(size);
|
||||||
|
UseOddBytes(img.samples, size, img.pixels);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure LoadPalette(var f: file; var image: TRSImage);
|
||||||
|
var
|
||||||
|
entries: integer;
|
||||||
|
begin
|
||||||
|
entries := image.paletteEntries;
|
||||||
|
case entries of
|
||||||
|
16: Blockread(f, image.palette, entries * 3); //RGB
|
||||||
|
256: Blockread(f, image.palette, entries * 3); //RGB
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure LoadSamples(var f: file; var image: TRSImage);
|
||||||
|
var
|
||||||
|
sample_bits: integer;
|
||||||
|
size: integer;
|
||||||
|
begin
|
||||||
|
sample_bits := image.sampleBits;
|
||||||
|
size := image.width * image.height * sample_bits div 8;
|
||||||
|
image.samples := getmem(size);
|
||||||
|
Blockread(f, image.samples^, size);
|
||||||
|
if image.type_ = 2 then
|
||||||
|
Blockread(f, image.samples^, size div 4);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure LoadImageHeader(var f: file; var image: TRSImage);
|
||||||
|
var
|
||||||
|
h: word;
|
||||||
|
w: word;
|
||||||
|
buffer: array[0..15] of byte;
|
||||||
|
description: TImageDescription;
|
||||||
|
bpp: byte;
|
||||||
|
begin
|
||||||
|
blockread(f, w, 2);
|
||||||
|
blockread(f, h, 2);
|
||||||
|
blockread(f, buffer, 4);
|
||||||
|
blockread(f, buffer[8], 4); //zero padding
|
||||||
|
|
||||||
|
w := w + (w and 1); //make width even
|
||||||
|
image.width := w;
|
||||||
|
image.height := h;
|
||||||
|
bpp := buffer[1];
|
||||||
|
image.type_ := buffer[2]; //image type
|
||||||
|
|
||||||
|
description := ImageDescription[image.type_];
|
||||||
|
image.sampleBits := description.sample_bits;
|
||||||
|
image.paletteEntries := description.palette_entries;
|
||||||
|
if image.type_ = 4 then
|
||||||
|
image.sampleBits := bpp * 4 + 4;
|
||||||
|
|
||||||
|
writeln('data size: ', image.data_size);
|
||||||
|
writeln('size: ', image.width, 'x', image.height);
|
||||||
|
writeln('subtype: ', image.type_);
|
||||||
|
writeln('sample bits: ', image.sampleBits);
|
||||||
|
writeln('attrs: ', buffer[0], ', ', buffer[1], ', ', buffer[3]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure LoadName(var f: file; const data_size: integer);
|
||||||
|
var
|
||||||
|
i: integer;
|
||||||
|
buffer: array[0..15] of byte;
|
||||||
|
s: string;
|
||||||
|
begin
|
||||||
|
s := '';
|
||||||
|
blockread(f, buffer, data_size);
|
||||||
|
for i := 0 to data_size - 1 do
|
||||||
|
s += char(buffer[i]);
|
||||||
|
s := Trim(s);
|
||||||
|
writeln('name: ', s);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function LoadImageFromPack(var f: file): TRSImage;
|
||||||
|
var
|
||||||
|
offset, string_offset: integer;
|
||||||
|
buffer: array[0..31] of byte;
|
||||||
|
begin
|
||||||
|
LoadPalette(f, result);
|
||||||
|
LoadSamples(f, result);
|
||||||
|
DecodePixels(result);
|
||||||
|
LoadName(f, result.data_size - string_offset);
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user