2
0
mirror of https://github.com/dpethes/rerogue.git synced 2025-06-07 18:58:32 +02:00

terrain viewer: use textures. Works for quads only at the moment

This commit is contained in:
dpethes 2015-07-06 15:25:47 +02:00
parent 93536c4b64
commit ef525fc0ff
3 changed files with 181 additions and 204 deletions

View File

@ -20,9 +20,9 @@ type
TTile = packed record
texture_index: word;
unknown_attrib: byte;
unknown_lo: byte;
unknown_hi: byte;
unknown: array[0..24] of byte;
height_lo: byte;
height_hi: byte;
heights: array[0..24] of byte;
end;
PTile = ^TTile;
@ -52,10 +52,6 @@ type
procedure LoadTextures(const tex_fname, texidx_fname: string);
procedure LoadHeightmap(fname: string);
procedure GenerateCompositeTexture;
procedure HeightmapToTexture;
procedure GenerateVertices;
procedure WriteToObj(const objFname: string);
public
heightmap: THeightmap;
@ -66,12 +62,12 @@ type
property TileHeight: word read heightmap.height;
procedure LoadFromFiles(const hmp, tex, texmap: string);
procedure ExportToObj(const objfname: string);
constructor Create;
destructor Destroy; override;
end;
procedure pnm_save(const fname: string; const p: pbyte; const w, h: integer);
//**************************************************************************************************
implementation
@ -102,7 +98,7 @@ Begin
CloseFile (f);
end;
procedure convert_4bit_to_32bit(const indices: PByte; const w, h: Word; const image: PByte; const pal: TPalette_4bit);
procedure convert_4bit_to_24bit(const indices: PByte; const w, h: Word; const image: PByte; const pal: TPalette_4bit);
var
i: Integer;
index: integer;
@ -173,7 +169,7 @@ begin
image := getmem(TEX_WIDTH * TEX_HEIGHT * 3);
Blockread(f, buf^, tex_size);
Blockread(f, palette, palette_size);
convert_4bit_to_32bit(buf, TEX_WIDTH, TEX_HEIGHT, image, palette);
convert_4bit_to_24bit(buf, TEX_WIDTH, TEX_HEIGHT, image, palette);
heightmap.textures[i] := image;
end;
freemem(buf);
@ -231,189 +227,10 @@ begin
CloseFile(f);
end;
procedure TWorld.GenerateCompositeTexture;
var
image: pbyte;
image_size: integer;
x, y, stride: integer;
tile_idx, texture_idx, texmap_idx: integer;
texture: pbyte;
begin
image_size := heightmap.width * heightmap.height * TEX_WIDTH * TEX_HEIGHT * 3;
image := GetMem(image_size);
stride := heightmap.width * TEX_WIDTH * 3;
for y := 0 to heightmap.height - 1 do
for x := 0 to heightmap.width - 1 do begin
tile_idx := heightmap.blk[y * heightmap.width + x];
texmap_idx := heightmap.tiles[tile_idx].texture_index;
if texmap_idx > Length(heightmap.texture_index_map) - 1 then
texmap_idx := 0;
texture_idx := heightmap.texture_index_map[texmap_idx];
texture := heightmap.textures[texture_idx];
CopyTexToXY(image, texture, x * TEX_WIDTH, (heightmap.height - y - 1) * TEX_HEIGHT, stride);
end;
world_texture := image;
pnm_save(TEXTURE_FNAME, image, heightmap.width * TEX_WIDTH, heightmap.height * TEX_HEIGHT);
end;
procedure TWorld.HeightmapToTexture;
const
TILE_WIDTH = 4;
SCALE = 128;
var
x, y: integer;
tile_idx: integer;
i: integer;
image_size: integer;
image: pbyte;
begin
image_size := heightmap.width * heightmap.height * TILE_WIDTH * TILE_WIDTH;
image := GetMem(image_size);
for y := 0 to heightmap.height - 1 do begin
for x := 0 to heightmap.width - 1 do begin
tile_idx := heightmap.blk[y * heightmap.width + x];
CopyTileToXY(image, @(heightmap.tiles[tile_idx].unknown),
x * TILE_WIDTH, (heightmap.height - y - 1) * TILE_WIDTH, heightmap.width * TILE_WIDTH);
end;
end;
//scale
for i := 0 to image_size - 1 do
image[i] := byte(image[i] + SCALE);
height_texture := image;
//pgm_save('map_height.pgm', image, heightmap.width * TILE_WIDTH, heightmap.height * TILE_WIDTH);
end;
{
While vertical scaling is stored within file, horizontal seems to be always 0.5
The height values need to be centered, 128 seems to be the correct offset.
The generated y coords are flipped for (opengl) rendering
}
procedure TWorld.GenerateVertices;
const
h_scale = 0.5;
var
va_size: integer;
x, y: integer;
vert: TVertex3f;
width_half, height_half: integer;
i: integer;
v_scale: single;
begin
vertex_count := heightmap.width * 4 * heightmap.height * 4;
va_size := vertex_count * SizeOf(TVertex3f);
vertex_array := getmem(va_size);
width_half := heightmap.width * 2;
height_half := heightmap.height * 2;
v_scale := heightmap.y_scale;
for y := 0 to heightmap.height * 4 - 1 do
for x := 0 to heightmap.width * 4 - 1 do begin
vert.x := (-width_half + x) * h_scale;
vert.z := (-height_half + y) * h_scale;
vert.u := x / (heightmap.width * 4);
vert.v := y / (heightmap.height * 4);
i := y * heightmap.width * 4 + x;
vert.y := (height_texture[i] - 128) * v_scale;
vert.y := -vert.y;
vertex_array[i] := vert;
end;
end;
procedure SaveMaterialFile(const obj_fname, mtl_name, texture_fname: string);
var
f: TextFile;
begin
AssignFile(f, obj_fname + '.mtl');
Rewrite(f);
writeln(f, '# RS heightmap');
writeln(f, 'newmtl ', mtl_name); //begin new material
writeln(f, 'map_Kd ', texture_fname); //texture
writeln(f, 'Ka 1.000 1.000 1.000'); //ambient color
writeln(f, 'Kd 1.000 1.000 1.000'); //diffuse color
writeln(f, 'Ks 1.000 1.000 1.000'); //specular color
writeln(f, 'Ns 100.0'); //specular weight
writeln(f, 'illum 2'); //Color on and Ambient on, Highlight on
CloseFile(f);
end;
procedure TWorld.WriteToObj(const objFname: string);
const
MAT_NAME = 'default';
var
f: textfile;
i: integer;
v: TVertex3f;
x, y, stride: integer;
i2, i3: integer;
texfname: string;
begin
AssignFile(f, objFname);
Rewrite(f);
writeln(f, '# RS heightmap');
writeln(f, 'mtllib ', objFname + '.mtl');
//vertices
for i := 0 to vertex_count - 1 do begin
v := vertex_array[i];
writeln(f, 'v ', v.x:10:6, ' ', v.y:10:6, ' ', v.z:10:6);
end;
//uv-s
for i := 0 to vertex_count - 1 do begin
v := vertex_array[i];
writeln(f, 'vt ', v.u:10:6, ' ', v.v:10:6);
end;
//select material
writeln(f, 'usemtl ' + MAT_NAME);
//faces
{
12 2
3 34
}
stride := heightmap.width * 4;
for y := 0 to heightmap.height * 4 - 2 do
for x := 0 to heightmap.width * 4 - 2 do begin
i := y * stride + x + 1;
i2 := i + 1;
i3 := i + stride;
writeln(f, Format('f %d/%d %d/%d %d/%d', [i, i, i2, i2, i3, i3]));
i := i3 + 1;
writeln(f, Format('f %d/%d %d/%d %d/%d', [i2, i2, i, i, i3, i3]));
end;
CloseFile(f);
SaveMaterialFile(objFname, MAT_NAME, TEXTURE_FNAME);
end;
procedure TWorld.LoadFromFiles(const hmp, tex, texmap: string);
begin
LoadHeightmap(hmp);
//LoadTextures(tex, texmap);
end;
procedure TWorld.ExportToObj(const objfname: string);
begin
//GenerateCompositeTexture;
HeightmapToTexture;
GenerateVertices;
//WriteToObj(objfname);
LoadTextures(tex, texmap);
end;
constructor TWorld.Create;

View File

@ -17,10 +17,18 @@ type
fg_to_draw: integer;
end;
TTerrainBlock = packed record
texture_index: integer;
vertices: array[0..25] of TVertex3f;
end;
{ TTerrainMesh }
TTerrainMesh = class
private
terrain: TWorld;
blocks: array of array of TTerrainBlock;
textures_glidx: array of integer;
procedure TransformTiles;
public
destructor Destroy; override;
procedure Load(const hmp_filename: string);
@ -30,6 +38,56 @@ type
implementation
{
While vertical scaling is stored within file, horizontal seems to be always 0.5
The generated y coords are flipped for (opengl) rendering
}
procedure TTerrainMesh.TransformTiles;
//basex/y - offset in vertices
procedure TileToBlock(var blk: TTerrainBlock; var tile: TTile; basex, basey: integer);
const
h_scale = 0.5;
var
x, y: integer;
v: TVertex3f;
width_half, height_half: integer; //size in vertices
v_scale: single;
begin
width_half := terrain.TileWidth * 2;
height_half := terrain.TileHeight * 2;
v_scale := terrain.heightmap.y_scale;
for y := 0 to 4 do
for x := 0 to 4 do begin
v.x := (-width_half + basex + x) * h_scale;
v.z := (-height_half + basey + y) * h_scale;
v.u := -x * 1/4;
v.v := -y * 1/4;
v.y := shortint(tile.heights[y+x*5]) * v_scale; //hmm... all transforms are flipped?
v.y := -v.y;
blk.vertices[y * 5 + x] := v;
end;
blk.texture_index := tile.texture_index;
end;
var
x, y, i, tile_idx: integer;
blk: TTerrainBlock;
tile: TTile;
begin
SetLength(blocks, terrain.TileWidth, terrain.TileHeight);
for y := 0 to terrain.TileHeight - 1 do begin
for x := 0 to terrain.TileWidth - 1 do begin
tile_idx := terrain.heightmap.blk[y * terrain.TileWidth + x];
tile := terrain.heightmap.tiles[tile_idx];
TileToBlock(blk, tile, y * 4, x * 4);
blocks[y, x] := blk;
end;
end;
end;
destructor TTerrainMesh.Destroy;
begin
inherited Destroy;
@ -38,29 +96,131 @@ end;
procedure TTerrainMesh.Load(const hmp_filename: string);
begin
terrain := TWorld.Create;
terrain.LoadFromFiles(hmp_filename, '', '');
terrain.ExportToObj(''); //generate vertices
terrain.LoadFromFiles('hmp_0', 'lv_0.text', 'lv_0.tex');
//terrain.LoadFromFiles('hmp_1', 'lv_1.text', 'lv_1.tex');
TransformTiles;
end;
//generate textures / texture atlas?
//generate textures. TODO texture atlas?
procedure TTerrainMesh.InitGL;
begin
end;
procedure GenTexture(tex_idx: integer);
const
TexW = 64;
TexH = 64;
var
tex: pbyte;
y: Integer;
x: Integer;
begin
glGenTextures(1, @textures_glidx[tex_idx]);
glBindTexture(GL_TEXTURE_2D, textures_glidx[tex_idx]);
tex := terrain.heightmap.textures[tex_idx];
//pnm_save('tex'+IntToStr(tex_idx) + '.pnm', tex, TexW, TexH); //debug
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, TexW, TexH, 0, GL_RGB, GL_UNSIGNED_BYTE, tex);
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
//glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
//glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
end;
//draw vertices / tiles around actual position
procedure TTerrainMesh.DrawGL(opts: TRenderOpts);
var
i: integer;
begin
glEnable(GL_TEXTURE_2D);
SetLength(textures_glidx, terrain.heightmap.texture_count);
for i := 0 to terrain.heightmap.texture_count - 1 do
GenTexture(i);
end;
//draw vertices from each block
procedure TTerrainMesh.DrawGL(opts: TRenderOpts);
procedure RenderBlock(var blk: TTerrainBlock);
var
i, x, y, stride: integer;
v: TVertex3f;
begin
glBegin(GL_POINTS);
glColor3f(0, 1, 0);
for i := 0 to terrain.vertex_count - 1 do begin
v := terrain.vertex_array[i];
glVertex3fv(@v);
end;
stride := 5;
glBindTexture(GL_TEXTURE_2D, textures_glidx[blk.texture_index]);
{
glBegin(GL_TRIANGLES);
//glColor3f(0, 1, 0);
for y := 0 to 3 do
for x := 0 to 3 do begin
//do two triangles
i := y * stride + x;
v := blk.vertices[i + 1];
glVertex3fv(@v);
glTexCoord2f(v.u, v.v);
v := blk.vertices[i];
glVertex3fv(@v);
glTexCoord2f(v.u, v.v);
v := blk.vertices[i + stride];
glVertex3fv(@v);
glTexCoord2f(v.u, v.v);
v := blk.vertices[i + 1];
glVertex3fv(@v);
glTexCoord2f(v.u, v.v);
v := blk.vertices[i + stride];
glVertex3fv(@v);
glTexCoord2f(v.u, v.v);
v := blk.vertices[i + stride + 1];
glVertex3fv(@v);
glTexCoord2f(v.u, v.v);
end;
glEnd;
}
//quad from block corners
glBegin(GL_QUADS);
i := y * stride + x;
v := blk.vertices[4];
glVertex3fv(@v);
glTexCoord2f(v.u, v.v);
v := blk.vertices[0];
glVertex3fv(@v);
glTexCoord2f(v.u, v.v);
v := blk.vertices[20];
glVertex3fv(@v);
glTexCoord2f(v.u, v.v);
v := blk.vertices[24];
glVertex3fv(@v);
glTexCoord2f(v.u, v.v);
glEnd;
end;
var
i, x, y, stride: integer;
blk: TTerrainBlock;
v: TVertex3f;
begin
if opts.points then begin
glBegin(GL_POINTS);
glColor3f(0, 1, 0);
for i := 0 to terrain.vertex_count - 1 do begin
v := terrain.vertex_array[i];
glVertex3fv(@v);
end;
glEnd;
end else begin
if opts.wireframe then
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
else
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glEnable(GL_TEXTURE_2D);
for y := 0 to terrain.TileHeight - 1 do
for x := 0 to terrain.TileWidth - 1 do begin
blk := blocks[y, x];
RenderBlock(blk);
end;
end;
end;
end.

View File

@ -338,7 +338,7 @@ var
begin
if Paramcount < 1 then begin
writeln('specify HOB file');
writeln('specify HMP file');
exit;
end;
in_file := ParamStr(1);