unit vfm;

interface

uses
  OpenGL, constants, variables, meshes, records, textures,
  global, files_names;

type
  TText = class
    str : string;
    p : RPoint;
    sx, sy, sz : single;
    color : RColor;
  public
    procedure Redraw;
  end;

  TObject = class
    id : integer;
    color : RColor;
    object_a : single;
    x, y, z : single;

    map_x, map_y : integer;

    sx, sy, sz : single;
    rx, ry, rz : single;
    current_mesh : integer;
    mesh : TMesh;
    current_frame_f : single;
    animation_step : boolean;
    animation_speed : single;
    renderable : boolean;
  public
    constructor CreateStandart(mx, my : single; mesh : integer);
    procedure Link(target : TObject);
    procedure SetFrame(var mesh : TMesh);
    procedure LinkAnimation(target : TObject);
    procedure Animate(count : single);
    procedure Redraw;
  end;

  TWorld = class
    Camera : RCamera;
    left_border, right_border, near_border, far_border : single;
  public
    constructor Create;
    procedure LoadNewTexture(i : integer; file_name : string);
    procedure LoadNewMesh(i : integer; file_name : string; texture_num : integer);
  end;

var
  world : TWorld;
  all_meshes : array[1..max_meshes] of TMesh;
  total_meshes : integer = 0;

implementation

{---------------- LOADING PROCEDURES ----------------}
procedure TWorld.LoadNewTexture(i : integer; file_name : string);
begin
if (i < 1) or (i > max_textures) then exit;
total_textures := total_textures + 1;
all_textures[i] := TTexture.create(textures_folder + file_name);
end;

procedure TWorld.LoadNewMesh(i : integer; file_name : string; texture_num : integer);
begin
if (i < 1) or (i > max_meshes) then exit;
total_meshes := total_meshes + 1;
all_meshes[i] := TMesh.create;
all_meshes[i].Load(meshes_folder + file_name);

all_meshes[i].texture := texture_num;
all_meshes[i].texturize := true;
if texture_num <= 0 then all_meshes[i].texturize := false;
end;

{---------------- HELPERS PROCEDURES ----------------}

procedure TextOut(s : string; x, y, z, sx, sy, sz : single; cr, cg, cb, ca : single);
begin
glColor4f(cr, cg, cb, ca);
glPushMatrix;
glTranslatef(x, y, z);
glScalef(sx, sy, sz);
glListBase(text_start_list);
glCallLists(length(s), GL_UNSIGNED_BYTE, pchar(s));
glPopMatrix;
end;

{---------------- VFM CLASS PROCEDURES ----------------}

constructor TWorld.Create;
var
i1, i2 : integer;
begin
inherited Create;
LoadNewTexture(texture_bricks_id,      texture_bricks);
LoadNewTexture(texture_wood_id,        texture_wood);
LoadNewTexture(texture_stones_id,      texture_stones);
LoadNewTexture(texture_bricks2_id,     texture_bricks2);
LoadNewTexture(texture_stem_id,        texture_stem);
LoadNewTexture(texture_leaves_id,      texture_leaves);
LoadNewTexture(texture_enemy1_id,      texture_enemy1);
LoadNewTexture(texture_enemy2_id,      texture_enemy2);
LoadNewTexture(texture_blood_id,       texture_blood);

LoadNewMesh(mesh_base1_id,             mesh_base1,             texture_bricks2_id);
LoadNewMesh(mesh_base2_id,             mesh_base2,             texture_wood_id);
LoadNewMesh(mesh_base3_id,             mesh_base3,             texture_stones_id);
LoadNewMesh(mesh_base4_id,             mesh_base4,             texture_bricks_id);
LoadNewMesh(mesh_tower_small_base_id,  mesh_tower_small_base,  texture_stones_id);
LoadNewMesh(mesh_tower_small_head_id,  mesh_tower_small_head,  texture_wood_id);
LoadNewMesh(mesh_tower_middle_base_id, mesh_tower_middle_base, texture_bricks_id);
LoadNewMesh(mesh_tower_middle_head_id, mesh_tower_middle_head, texture_wood_id);
LoadNewMesh(mesh_tower_big_base_id,    mesh_tower_big_base,    texture_bricks2_id);
LoadNewMesh(mesh_tower_big_head_id,    mesh_tower_big_head,    texture_wood_id);
LoadNewMesh(mesh_tree_stem_id,         mesh_tree_stem,         texture_stem_id);
LoadNewMesh(mesh_tree_leaves_id,       mesh_tree_leaves,       texture_leaves_id);
LoadNewMesh(mesh_buildplace_id,        mesh_buildplace,        texture_stones_id);
LoadNewMesh(mesh_enemy_body1_id,       mesh_enemy_body1,       texture_enemy1_id);
LoadNewMesh(mesh_enemy_body2_id,       mesh_enemy_body2,       texture_enemy2_id);
LoadNewMesh(mesh_enemy_wings1_id,      mesh_enemy_wings1,      texture_enemy1_id);
LoadNewMesh(mesh_enemy_wings2_id,      mesh_enemy_wings2,      texture_enemy2_id);
LoadNewMesh(mesh_enemy_death_id,       mesh_enemy_death,       texture_blood_id);
LoadNewMesh(mesh_building_process_id,  mesh_building_process,  texture_wood_id);

with camera do
  begin
    up.x := 0;
    up.y := 0;
    up.z := 100000;

    destination := 900;
    height := 500;

    enemy_destination := 80;
    enemy_height := 80;
  end;
end;

procedure TText.Redraw;
begin
TextOut(str, p.x, p.y, p.z, sx, sy, sz, color.r, color.g, color.b, color.a);
end;

constructor TObject.CreateStandart(mx, my : single; mesh : integer);
var
ix, iy : integer;
begin
inherited Create;

ix := trunc(mx);
iy := trunc(my);

map_x := ix; map_y := iy;
renderable := true;
sx := global_scale_x; sy := global_scale_y; sz := global_scale_z;
x := mx * landscape.sx;
y := my * landscape.sy;
z := landscape.map[map_x, map_y].z;
current_mesh := mesh;
with color do begin r := 1; g := 1; b := 1; a := 1; end;
object_a := 0.4;
end;

procedure TObject.Link(target : TObject);
begin
x := target.x; y := target.y; z := target.z;
rx := target.rx; ry := target.ry; rz := target.rz;
sx := target.sx; sy := target.sy; sz := target.sz;
map_x := target.map_x; map_y := target.map_y;
end;

procedure TObject.SetFrame(var mesh : TMesh);
begin
with mesh do
  begin
    current_frame := round(current_frame_f);
    if current_frame <= 1 then animation_step := true;
    if current_frame >= total_frames - 1 then animation_step := false;
  end;
end;

procedure TObject.LinkAnimation(target : TObject);
begin
current_frame_f := target.current_frame_f;
animation_step := target.animation_step;
if current_mesh = 0 then SetFrame(all_meshes[current_mesh])
else SetFrame(all_meshes[current_mesh]);
end;

procedure TObject.Animate(count : single);
begin
if animation_step then
  current_frame_f := current_frame_f + count * animation_speed
else current_frame_f:= current_frame_f - count * animation_speed;

if current_mesh = 0 then SetFrame(all_meshes[current_mesh])
else SetFrame(all_meshes[current_mesh]);
end;

procedure TObject.Redraw;
var
i1, i2 : integer;
begin
renderable := landscape.map[map_x, map_y].renderable;

if not renderable then exit;  

color.a := object_a + landscape.map[map_x, map_y].color.a -
                      landscape.map[map_x, map_y].fog_a;

glPushMatrix;
glTranslatef(x, y, z);
glRotatef(rx, 1, 0, 0);
glRotatef(ry, 0, 1, 0);
glRotatef(rz, 0, 0, 1);
glScalef(sx, sy, sz);

with color do glColor4f(r, g, b, a);
if select_objects then glLoadName(id);
if current_mesh = 0 then mesh.ReBuild
else all_meshes[current_mesh].ReBuild;

glPopMatrix;    
end;

end.
