diff --git a/terrain_viewer/rs_world.pas b/terrain_viewer/rs_world.pas index b307f7a..92b30bd 100644 --- a/terrain_viewer/rs_world.pas +++ b/terrain_viewer/rs_world.pas @@ -5,7 +5,7 @@ unit rs_world; interface uses - Classes, SysUtils; + Classes, SysUtils, gvector, rs_dat; const TEX_WIDTH = 64; @@ -37,6 +37,15 @@ type texture_index_map: array of integer; end; + TLevelListItem = record + name: string; + hmp: PRsDatFileNode; + texture: PRsDatFileNode; + texture_index: PRsDatFileNode; + end; + TLevelList = specialize TVector; + + { TWorld } TWorld = class @@ -44,8 +53,8 @@ type world_texture: pbyte; height_texture: pbyte; - procedure LoadTextures(const tex_fname, texidx_fname: string); - procedure LoadHeightmap(fname: string); + procedure LoadTextures(tex_node, texindex_node: PRsDatFileNode); + procedure LoadHeightmap(node: PRsDatFileNode); public heightmap: THeightmap; @@ -54,7 +63,7 @@ type property TileWidth: word read heightmap.width; property TileHeight: word read heightmap.height; - procedure LoadFromFiles(const hmp, tex, texmap: string); + procedure LoadFromNodes(level: TLevelListItem); constructor Create; destructor Destroy; override; @@ -135,9 +144,9 @@ end; { TWorld } -procedure TWorld.LoadTextures(const tex_fname, texidx_fname: string); +procedure TWorld.LoadTextures(tex_node, texindex_node: PRsDatFileNode); var - f: file; + f: TMemoryStream; buf: pbyte; tex_size: integer; i: Integer; @@ -146,12 +155,13 @@ var palette_size: Integer; texture_count: integer; begin - AssignFile(f, tex_fname); - reset(f, 1); + f := TMemoryStream.Create; + f.WriteBuffer(tex_node^.Data^, tex_node^.size); + f.Seek(0, soBeginning); palette_size := 48; //16x RGB tex_size := TEX_WIDTH * TEX_HEIGHT div 2; - texture_count := filesize(f) div (tex_size + palette_size); + texture_count := f.Size div (tex_size + palette_size); //writeln('texture_count: ', texture_count); SetLength(heightmap.textures, texture_count); @@ -160,27 +170,28 @@ begin buf := getmem(tex_size); for i := 0 to texture_count - 1 do begin image := getmem(TEX_WIDTH * TEX_HEIGHT * 3); - Blockread(f, buf^, tex_size); - Blockread(f, palette, palette_size); + f.Read(buf^, tex_size); + f.Read(palette, palette_size); convert_4bit_to_24bit(buf, TEX_WIDTH, TEX_HEIGHT, image, palette); heightmap.textures[i] := image; end; freemem(buf); - CloseFile(f); + f.Free; - AssignFile(f, texidx_fname); - Reset(f, 1); + f := TMemoryStream.Create; + f.WriteBuffer(texindex_node^.Data^, texindex_node^.size); + f.Seek(0, soBeginning); - texture_count := filesize(f) div 4 - 1; + texture_count := f.Size div 4 - 1; //should match previous texture_count from texture atlas? SetLength(heightmap.texture_index_map, texture_count); - Blockread(f, heightmap.texture_index_map[0], texture_count * 4); + f.Read(heightmap.texture_index_map[0], texture_count * 4); - CloseFile(f); + f.Free; end; -procedure TWorld.LoadHeightmap(fname: string); +procedure TWorld.LoadHeightmap(node: PRsDatFileNode); var - f: file; + f: TMemoryStream; buffer: array[0..15] of byte; tile_offset: integer; blk: pword; @@ -188,44 +199,45 @@ var tile_count: word; i: integer; begin - AssignFile(f, fname); - reset(f, 1); + f := TMemoryStream.Create; + f.WriteBuffer(node^.Data^, node^.size); + f.Seek(0, soBeginning); //header - Blockread(f, buffer, 12); - Blockread(f, buffer, 4); - Blockread(f, heightmap.y_scale, 4); - Blockread(f, buffer, 4); - Blockread(f, tile_count, 2); //tile count - Blockread(f, buffer, 2); //2B? - Blockread(f, tile_offset, 4); //tile offset - Blockread(f, buffer, 4); //offset? - Blockread(f, heightmap.width, 2); - Blockread(f, heightmap.height, 2); + f.Read(buffer, 12); + f.Read(buffer, 4); + f.Read(heightmap.y_scale, 4); //float + f.Read(buffer, 4); + tile_count := f.ReadWord; + f.Read(buffer, 2); + tile_offset := f.ReadDWord; + f.Read(buffer, 4); + heightmap.width := f.ReadWord; + heightmap.height := f.ReadWord; //blocks / tile indices blk_size := heightmap.width * heightmap.height * 2; blk := getmem(blk_size); - Blockread(f, blk^, blk_size); + f.Read(blk^, blk_size); heightmap.blk := blk; //tiles //writeln('filepos: ', FilePos(f)); writeln('tile pos: ', tile_offset); - Seek(f, tile_offset); + f.Seek(tile_offset, soBeginning); heightmap.tile_count := tile_count; heightmap.tiles := getmem(tile_count * 30); for i := 0 to tile_count - 1 do - Blockread(f, heightmap.tiles[i], 30); + f.Read(heightmap.tiles[i], 30); - CloseFile(f); + f.Free; end; -procedure TWorld.LoadFromFiles(const hmp, tex, texmap: string); +procedure TWorld.LoadFromNodes(level: TLevelListItem); var i: Integer; begin - LoadHeightmap(hmp); - LoadTextures(tex, texmap); + LoadHeightmap(level.hmp); + LoadTextures(level.texture, level.texture_index); for i := 0 to heightmap.tile_count - 1 do begin heightmap.tiles[i].texture_index := heightmap.texture_index_map[heightmap.tiles[i].texture_index]; end; diff --git a/terrain_viewer/terrain_mesh.pas b/terrain_viewer/terrain_mesh.pas index 369a1cd..0dc8778 100644 --- a/terrain_viewer/terrain_mesh.pas +++ b/terrain_viewer/terrain_mesh.pas @@ -48,7 +48,7 @@ type procedure InitBlockStaticData; public destructor Destroy; override; - procedure Load(level_idx: integer); + procedure Load(level: TLevelListItem); procedure InitGL; procedure DrawGL(opts: TRenderOpts); end; @@ -78,6 +78,7 @@ const h_scale = 0.5; var x, y, idx: integer; + vx, vy, vz: single; v_scale: single; begin result.texture_index := tile.texture_index; @@ -88,11 +89,11 @@ begin for y := 0 to 4 do for x := 0 to 4 do begin idx := y * 5 + x; - result.vertices[idx].init( //x,y,z, rotated by 180 around z - (basex + x) * h_scale * -1, - tile.heights[idx] * v_scale * -1, - (basey + y) * h_scale - ); + //x,y,z, rotated by 180 around z + vx := (basex + x) * h_scale * -1; + vy := tile.heights[idx] * v_scale * -1; + vz := (basey + y) * h_scale; + result.vertices[idx].init(vx, vy, vz); end; end; @@ -186,19 +187,10 @@ begin inherited Destroy; end; -procedure TTerrainMesh.Load(level_idx: integer); -const - LevelIds = '0123456789abcdefgh'; -var - c: char; +procedure TTerrainMesh.Load(level: TLevelListItem); begin terrain := TWorld.Create; - level_idx := level_idx mod length(LevelIds); - c := LevelIds[1 + level_idx]; - terrain.LoadFromFiles( - 'data\hmp_' + c, - 'data\lv_'+c+'.text', - 'data\lv_'+c+'.tex'); + terrain.LoadFromNodes(level); TransformTiles; InitBlockStaticData; WriteLn(Format('terrain size: %dx%d, tris: %d', diff --git a/terrain_viewer/terrain_viewer.lpi b/terrain_viewer/terrain_viewer.lpi index 95af3f0..34d1396 100644 --- a/terrain_viewer/terrain_viewer.lpi +++ b/terrain_viewer/terrain_viewer.lpi @@ -1,7 +1,7 @@ - + @@ -17,9 +17,6 @@ - - - @@ -28,36 +25,43 @@ - + + + + + + + + - + - - - - + + + + @@ -68,11 +72,9 @@ + - - - diff --git a/terrain_viewer/terrain_viewer.pas b/terrain_viewer/terrain_viewer.pas index f99833a..dd84f73 100644 --- a/terrain_viewer/terrain_viewer.pas +++ b/terrain_viewer/terrain_viewer.pas @@ -22,7 +22,7 @@ program terrain_viewer; uses sysutils, math, gl, glu, glext, sdl, - terrain_mesh; + terrain_mesh, rs_dat, rs_world; const SCR_W_fscrn = 1024; @@ -37,6 +37,9 @@ const MouseTranslateMultiply = 0.025; var + g_rsdata: TRSDatFile; + g_levels: TLevelList; + surface: PSDL_Surface; done, fullscreen: boolean; @@ -298,19 +301,68 @@ begin end; {case} end; +//we only care about HOB and HMT files +procedure LoadLevelFilelist; + procedure AddFile(const map, level: PRsDatFileNode); + var + item: TLevelListItem; + fnode: PRsDatFileNode; + begin + item.name := map^.Name; //lv_0 + for fnode in map^.nodes do + if fnode^.name = 'hmp' then + item.hmp := fnode; + for fnode in level^.nodes do begin + if fnode^.name = item.name + '_TEX' then //lv_0_TEX + item.texture_index := fnode; + if fnode^.name = item.name + '_TEXT' then //lv_0_TEXT + item.texture := fnode; + end; + g_levels.PushBack(item); + end; +var + rs_files: TRsDatFileNodeList; + fnode: TRsDatFileNode; + data_dir, level_dir, map_dir: PRsDatFileNode; +begin + //go to data/level/ + rs_files := g_rsdata.GetStructure(); + for fnode in rs_files do begin + if fnode.is_directory and (fnode.Name = 'data') then begin + data_dir := @fnode; + break; + end; + end; + Assert(data_dir <> nil); + for level_dir in data_dir^.nodes do begin + if level_dir^.is_directory and (level_dir^.Name = 'level') then + break; + end; + Assert(level_dir <> nil); + + for map_dir in level_dir^.nodes do + if map_dir^.is_directory then + AddFile(map_dir, level_dir); +end; + //****************************************************************************** var sec, frames: integer; - in_file: integer; begin - if Paramcount < 1 then begin - writeln('specify HMP file index'); + if not (FileExists(RS_DATA_HDR) and FileExists(RS_DATA_DAT)) then begin + writeln('RS data files not found!'); exit; end; - in_file := StrToInt( ParamStr(1) ); + + writeln('loading data'); + g_rsdata := TRSDatFile.Create(RS_DATA_HDR, RS_DATA_DAT); + g_rsdata.Parse(); + g_levels := TLevelList.Create; + LoadLevelFilelist; + terrain := TTerrainMesh.Create; - terrain.Load(14); + terrain.Load(g_levels[0]); writeln('Init SDL...'); SDL_Init( SDL_INIT_VIDEO ); @@ -343,5 +395,7 @@ begin terrain.Free; SDL_Quit; + g_levels.Free; + g_rsdata.Free; end.