diff --git a/README.md b/README.md index f7f59ce..8afca32 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ Tools to extract data from Star Wars: Rogue Squadron 3D. * Image exporter - exports some images to pnm/pgm/tga files (according to their internal format). * HOB parser - parses mesh data files. * HMT parser - parses material data files and exports stored textures. +* HMT compiler - builds custom material data files. * HOB display - utilizes HOB & HMT parsers to view 3d objects used in game. Uses OpenGL and SDL for display & input handling. Compilation @@ -20,6 +21,7 @@ TODO ----------- * hmt parser: decode all image subtypes +* hmt compiler: needs some usable interface * hob parser: parse more header fields * mesh viewer: reuse hmt & hob parsers to display data * bundle repack: extract & compile bundle.00x archives diff --git a/hmt_compiler/hmt_compiler.lpi b/hmt_compiler/hmt_compiler.lpi new file mode 100644 index 0000000..52ddfe2 --- /dev/null +++ b/hmt_compiler/hmt_compiler.lpi @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + <UseAppBundle Value="False"/> + <ResourceType Value="res"/> + </General> + <i18n> + <EnableI18N LFM="False"/> + </i18n> + <VersionInfo> + <StringTable ProductVersion=""/> + </VersionInfo> + <BuildModes Count="1"> + <Item1 Name="Default" Default="True"/> + </BuildModes> + <PublishOptions> + <Version Value="2"/> + </PublishOptions> + <RunParams> + <local> + <FormatVersion Value="1"/> + </local> + </RunParams> + <Units Count="2"> + <Unit0> + <Filename Value="hmt_compiler.lpr"/> + <IsPartOfProject Value="True"/> + </Unit0> + <Unit1> + <Filename Value="..\hmt_parser\hmt_parser.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="hmt_parser"/> + </Unit1> + </Units> + </ProjectOptions> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <Target> + <Filename Value="hmt_compiler"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <OtherUnitFiles Value="..\hmt_parser"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + </CompilerOptions> + <Debugging> + <Exceptions Count="3"> + <Item1> + <Name Value="EAbort"/> + </Item1> + <Item2> + <Name Value="ECodetoolError"/> + </Item2> + <Item3> + <Name Value="EFOpenError"/> + </Item3> + </Exceptions> + </Debugging> +</CONFIG> diff --git a/hmt_compiler/hmt_compiler.lpr b/hmt_compiler/hmt_compiler.lpr new file mode 100644 index 0000000..aa85044 --- /dev/null +++ b/hmt_compiler/hmt_compiler.lpr @@ -0,0 +1,203 @@ +program hmt_compiler; + +uses + sysutils, + hmt_parser; + +var + hmt: THmtFile; + +procedure pgm_read(const fname: string; var p: pbyte; var w, h: word); +var + f: file; + c: char; + magic: array [0..1] of char; + s: string; +begin + if not FileExists(fname) then begin + writeln('pgm_read: subor neexistuje: ', fname); + halt; + end; + s := ''; + AssignFile (f, fname); + Reset (f, 1); + + //precitaj magic id + blockread (f, magic, 2); + if (magic <> 'P5') then begin + writeln (stderr, 'error: bad input type'); + halt(); + end; + blockread (f, c, 1); + + //sirka + blockread (f, c, 1); + while not(c = ' ') do begin + s := s + c; + blockread (f, c, 1); + end; + w := StrToInt(s); + //vyska + s := ''; + while not(c in [#10, #13]) do begin + s := s + c; + blockread (f, c, 1); + end; + h := StrToInt(s); + //maxval ignorujeme + repeat blockread (f, c, 1) until (c in [#10, #13]); + + //alokuj a nacitaj data + GetMem (p, w * h); + blockread (f, p^, w * h); + CloseFile (f); +end; + +procedure Pack8To4bit(const src: PByte; const samples: integer; const dst: PByte); +var + i: Integer; + a, b: byte; +begin + for i := 0 to samples div 2 - 1 do begin + a := src[i * 2]; + b := src[i * 2 + 1]; + dst[i] := a or (b shr 4); + end; +end; + +procedure HmtAddMaterial(const mat_name: string); +var + mat: THmtMaterial; + i: Integer; +begin + mat.hex_a := $a; + mat.type_ := 2; + mat.tex_index := 0; + mat.unknown_float1 := 1.0; + mat.unknown_float2 := 1.0; + for i := 0 to Length(mat_name) do begin + mat.name[i] := byte( mat_name[i+1] ); + end; + + if mat_name = 'tie_wing' then + mat.type_ := 1; + + hmt.material_count += 1; + SetLength(hmt.materials, hmt.material_count); + hmt.materials[hmt.material_count - 1] := mat; +end; + +procedure HmtAddTexture(const fname, tex_name: string); +var + w, h: word; + tex: THmtTexture; + i: Integer; + pixbuf: pbyte; +begin + pgm_read(fname, pixbuf, w, h); + tex.image.pixels := getmem(w*h); + Pack8To4bit(pixbuf, w*h, tex.image.pixels); + freemem(pixbuf); + + tex.palette_offset := 0; + tex.width := w; + tex.height := h; + for i := 0 to Length(tex_name) do begin + tex.name[i] := byte( tex_name[i+1] ); + end; + + hmt.texture_count += 1; + SetLength(hmt.textures, hmt.texture_count); + hmt.textures[hmt.texture_count - 1] := tex; +end; + +procedure WriteHmt(const fname: string); +var + f: File; + mat: THmtMaterial; + tex: THmtTexture; + i, k: Integer; + zero: integer; + texdata_offset: integer; + texformat: array[0..3] of byte; + alpha: longword; +begin + hmt.texture_offset := hmt.material_count * 36 + 8; + zero := 0; + AssignFile(f, fname); + Rewrite(f, 1); + BlockWrite(f, hmt.material_count, 4); + BlockWrite(f, hmt.texture_offset, 4); + for i := 0 to hmt.material_count - 1 do begin + mat := hmt.materials[i]; + BlockWrite(f, mat.type_, 2); + BlockWrite(f, mat.tex_index, 2); + BlockWrite(f, mat.unknown_float1, 4); + BlockWrite(f, mat.unknown_float2, 4); + BlockWrite(f, zero, 4); + BlockWrite(f, mat.hex_a, 4); + BlockWrite(f, mat.name, 16); + end; + + //textures + BlockWrite(f, hmt.texture_count, 4); + texdata_offset := FilePos(f) + hmt.texture_count * 52; + + for i := 0 to hmt.texture_count - 1 do begin + tex := hmt.textures[i]; + k := texdata_offset + 16; + BlockWrite(f, k, 4); + for k := 1 to 7 do + BlockWrite(f, zero, 4); + BlockWrite(f, zero, 4); //palette offset, 0 = no palette + BlockWrite(f, texdata_offset, 4); //texname offset + BlockWrite(f, tex.width, 2); + BlockWrite(f, tex.height, 2); + //format + texformat[0] := 1; //1? + texformat[1] := 0; //? + texformat[2] := 4; //subtype + texformat[3] := $40; //? + BlockWrite(f, texformat, 4); + alpha := $80808080; + BlockWrite(f, alpha, 4); //4B RGBA transparent color? +// texdata_offset += pixsize; + end; + + //texdata + for i := 0 to hmt.texture_count - 1 do begin + tex := hmt.textures[i]; + BlockWrite(f, tex.name, 16); + BlockWrite(f, tex.image.pixels^, tex.width * tex.height div 2); + end; + Closefile(f); +end; + +const + mats: array[0..12] of string[16] = ( + 'mat_0', + 'tie_hull_bk', + 'tie_hatch_top', + 'tie_hull_frt', + 'tie_wingdet', + 'arm_frt', + 'tie_wing', + 'mat_7', + 'tie_hull_bk_lod', + 'tie_hull_frt_lo', + 'tie_wing_lod', + 'mat_11', + 'mat_12' + ); + +var + i: integer; +begin + hmt.material_count := 0; + hmt.texture_count := 0; + for i := 0 to 12 do + HmtAddMaterial(mats[i]); + HmtAddTexture('tie_wing.pgm', 'tie_wing'); + WriteHmt('tiefighter.HMT'); +end. + diff --git a/hmt_parser/hmt_parser.pas b/hmt_parser/hmt_parser.pas index e02d347..2ad9e95 100644 --- a/hmt_parser/hmt_parser.pas +++ b/hmt_parser/hmt_parser.pas @@ -9,7 +9,8 @@ uses type THmtMaterial = record - type1, type2: shortint; + type_: shortint; + tex_index: shortint; unknown_float1, unknown_float2: single; zero: integer; hex_a: integer; @@ -118,8 +119,8 @@ end; procedure ReadMaterial(var mat: THmtMaterial; var f: TMemoryStream); begin - mat.type1 := f.ReadWord; - mat.type2 := f.ReadWord; + mat.type_ := f.ReadWord; + mat.tex_index := f.ReadWord; mat.unknown_float1 := f.ReadDWord; mat.unknown_float2 := f.ReadDWord; mat.zero := f.ReadDWord; @@ -129,6 +130,8 @@ begin writeln(NameToString(mat.name)); if (mat.zero <> 0) or (mat.hex_a <> $A) then writeln('unusual file'); + writeln(' type1: ', mat.type_); + writeln(' type2: ', mat.tex_index); end;