DEADSOFTWARE

gl: draw shots
[d2df-sdl.git] / src / game / renders / opengl / r_map.pas
index 016aed3c0ac210c20ed5b23b1606aa7bdd2d5205..5a0c7afed6f09af475718918d26e5bee9494ad14 100644 (file)
@@ -26,6 +26,8 @@ interface
   procedure r_Map_LoadTextures;
   procedure r_Map_FreeTextures;
 
+  procedure r_Map_NewGFX (typ, x, y: Integer);
+
   procedure r_Map_Update;
 
   procedure r_Map_Draw (x, y, w, h, camx, camy: Integer);
@@ -41,10 +43,13 @@ implementation
     e_log,
     binheap, MAPDEF, utils,
     g_options, g_textures, g_basic, g_base, g_phys,
-    g_game, g_map, g_panel, g_items, g_monsters, g_playermodel, g_player,
+    g_game, g_map, g_panel, g_items, g_monsters, g_playermodel, g_player, g_weapons,
     {$IFDEF ENABLE_CORPSES}
       g_corpses,
     {$ENDIF}
+    {$IFDEF ENABLE_GFX}
+      g_gfx,
+    {$ENDIF}
     r_textures, r_draw
   ;
 
@@ -77,6 +82,69 @@ implementation
     VILEFIRE_DX = 32;
     VILEFIRE_DY = 128;
 
+    GFXAnim: array [0..R_GFX_LAST] of record
+      name: AnsiString;
+      w, h: Integer;
+      count: Integer;
+      back: Boolean;
+      speed: Integer;
+      rspeed: Integer;
+      alpha: Integer;
+    end = (
+      (name: '';            w: 0;   h: 0;   count: 0;  back: false; speed: 0; rspeed: 0; alpha: 0),
+      (name: 'TELEPORT';    w: 64;  h: 64;  count: 10; back: false; speed: 6; rspeed: 0; alpha: 0),
+      (name: 'FLAME';       w: 32;  h: 32;  count: 11; back: false; speed: 3; rspeed: 0; alpha: 0),
+      (name: 'EROCKET';     w: 128; h: 128; count: 6;  back: false; speed: 6; rspeed: 0; alpha: 0),
+      (name: 'EBFG';        w: 128; h: 128; count: 6;  back: false; speed: 6; rspeed: 0; alpha: 0),
+      (name: 'BFGHIT';      w: 64;  h: 64;  count: 4;  back: false; speed: 4; rspeed: 0; alpha: 0),
+      (name: 'FIRE';        w: 64;  h: 128; count: 8;  back: false; speed: 4; rspeed: 2; alpha: 0),
+      (name: 'ITEMRESPAWN'; w: 32;  h: 32;  count: 5;  back: true;  speed: 4; rspeed: 0; alpha: 0),
+      (name: 'SMOKE';       w: 32;  h: 32;  count: 10; back: false; speed: 3; rspeed: 0; alpha: 0),
+      (name: 'ESKELFIRE';   w: 64;  h: 64;  count: 3;  back: false; speed: 8; rspeed: 0; alpha: 0),
+      (name: 'EPLASMA';     w: 32;  h: 32;  count: 4;  back: true;  speed: 3; rspeed: 0; alpha: 0),
+      (name: 'EBSPFIRE';    w: 32;  h: 32;  count: 5;  back: false; speed: 3; rspeed: 0; alpha: 0),
+      (name: 'EIMPFIRE';    w: 64;  h: 64;  count: 3;  back: false; speed: 6; rspeed: 0; alpha: 0),
+      (name: 'ECACOFIRE';   w: 64;  h: 64;  count: 3;  back: false; speed: 6; rspeed: 0; alpha: 0),
+      (name: 'EBARONFIRE';  w: 64;  h: 64;  count: 3;  back: false; speed: 6; rspeed: 0; alpha: 0),
+      (name: 'TELEPORT';    w: 64;  h: 64;  count: 10; back: false; speed: 3; rspeed: 0; alpha: 0),   // fast
+      (name: 'SMOKE';       w: 32;  h: 32;  count: 10; back: false; speed: 3; rspeed: 0; alpha: 150), // transparent
+      (name: 'FLAME';       w: 32;  h: 32;  count: 11; back: false; speed: 3; rspeed: 2; alpha: 0)    // random
+    );
+
+    ShotAnim: array [0..WEAPON_LAST] of record
+      name: AnsiString;
+      w, h: Integer;
+      count: Integer;
+    end = (
+      (name: '';            w: 0;  h: 0;  count: 0),  // 0  KASTET
+      (name: '';            w: 0;  h: 0;  count: 0),  // 1  SAW
+      (name: '';            w: 0;  h: 0;  count: 0),  // 2  PISTOL
+      (name: '';            w: 0;  h: 0;  count: 0),  // 3  SHOTGUN1
+      (name: '';            w: 0;  h: 0;  count: 0),  // 4  SHOTGUN2
+      (name: '';            w: 0;  h: 0;  count: 0),  // 5  CHAINGUN
+      (name: 'BROCKET';     w: 64; h: 32; count: 1),  // 6  ROCKETLAUNCHER
+      (name: 'BPLASMA';     w: 16; h: 16; count: 2),  // 7  PLASMA
+      (name: 'BBFG';        w: 64; h: 64; count: 2),  // 8  BFG
+      (name: '';            w: 0;  h: 0;  count: 0),  // 9  SUPERPULEMET
+      (name: 'FLAME';       w: 32; h: 32; count: 11), // 10 FLAMETHROWER
+      (name: '';            w: 0;  h: 0;  count: 0),  // 11
+      (name: '';            w: 0;  h: 0;  count: 0),  // 12
+      (name: '';            w: 0;  h: 0;  count: 0),  // 13
+      (name: '';            w: 0;  h: 0;  count: 0),  // 14
+      (name: '';            w: 0;  h: 0;  count: 0),  // 15
+      (name: '';            w: 0;  h: 0;  count: 0),  // 16
+      (name: '';            w: 0;  h: 0;  count: 0),  // 17
+      (name: '';            w: 0;  h: 0;  count: 0),  // 18
+      (name: '';            w: 0;  h: 0;  count: 0),  // 19
+      (name: '';            w: 0;  h: 0;  count: 0),  // 20 ZOMPY_PISTOL
+      (name: 'BIMPFIRE';    w: 16; h: 16; count: 2),  // 21 IMP_FIRE
+      (name: 'BBSPFIRE';    w: 16; h: 16; count: 2),  // 22 BSP_FIRE
+      (name: 'BCACOFIRE';   w: 16; h: 16; count: 2),  // 23 CACO_FIRE
+      (name: 'BBARONFIRE';  w: 64; h: 16; count: 2),  // 24 BARON_FIRE
+      (name: 'BMANCUBFIRE'; w: 64; h: 32; count: 2),  // 25 MANCUB_FIRE
+      (name: 'BSKELFIRE';   w: 64; h: 64; count: 2)   // 26 SKEL_FIRE
+    );
+
   type
     TBinHeapPanelDrawCmp = class
       public
@@ -98,6 +166,8 @@ implementation
       anim: TAnimState;
     end;
     MonTextures: array [0..MONSTER_MAN] of TMonsterAnims;
+    WeapTextures: array [0..WP_LAST, 0..W_POS_LAST, 0..W_ACT_LAST] of TGLTexture;
+    ShotTextures: array [0..WEAPON_LAST] of TGLMultiTexture;
     VileFire: TGLMultiTexture;
     Models: array of record
       anim: array [TDirection, 0..A_LAST] of record
@@ -113,6 +183,19 @@ implementation
 *)
     end;
 
+    StubShotAnim: TAnimState;
+
+{$IFDEF ENABLE_GFX}
+    GFXTextures: array [0..R_GFX_LAST] of TGLMultiTexture;
+    gfxlist: array of record
+      typ: Byte;
+      alpha: Byte;
+      x, y: Integer;
+      oldX, oldY: Integer;
+      anim: TAnimState;
+    end = nil;
+{$ENDIF}
+
     plist: TBinHeapPanelDraw = nil;
 
   class function TBinHeapPanelDrawCmp.less (const a, b: TPanel): Boolean; inline;
@@ -124,12 +207,14 @@ implementation
 
   procedure r_Map_Initialize;
   begin
+    StubShotAnim := TAnimState.Create(true, 1, 1);
     plist := TBinHeapPanelDraw.Create();
   end;
 
   procedure r_Map_Finalize;
   begin
-    plist.Free
+    plist.Free;
+    StubShotAnim.Invalidate;
   end;
 
   procedure r_Map_LoadModel (i: Integer);
@@ -162,7 +247,12 @@ implementation
 
 
   procedure r_Map_Load;
-    var i, j: Integer; d: TDirection;
+    const
+      WeapName: array [0..WP_LAST] of AnsiString = ('', 'CSAW', 'HGUN', 'SG', 'SSG', 'MGUN', 'RKT', 'PLZ', 'BFG', 'SPL', 'FLM');
+      WeapPos: array [0..W_POS_LAST] of AnsiString = ('', '_UP', '_DN');
+      WeapAct: array [0..W_ACT_LAST] of AnsiString = ('', '_FIRE');
+    var
+      i, j, k: Integer; d: TDirection;
 
     procedure LoadItem (i: Integer; const name: AnsiString; w, h, delay, count: Integer; backanim: Boolean);
     begin
@@ -262,11 +352,65 @@ implementation
       for i := 0 to High(PlayerModelsArray) do
         r_Map_LoadModel(i);
     end;
+    // --------- player weapons --------- //
+    for i := 1 to WP_LAST do
+      for j := 0 to W_POS_LAST do
+        for k := 0 to W_ACT_LAST do
+          WeapTextures[i, j, k] := r_Textures_LoadFromFile(GameWAD + ':WEAPONS\' + WeapName[i] + WeapPos[j] + WeapAct[k]);
+    // --------- gfx animations --------- //
+    {$IFDEF ENABLE_GFX}
+      for i := 1 to R_GFX_LAST do
+        if GFXAnim[i].count > 0 then
+          GFXTextures[i] := r_Textures_LoadMultiFromFileAndInfo(GameWad + ':TEXTURES/' + GFXAnim[i].name, GFXAnim[i].w, GFXAnim[i].h, GFXAnim[i].count, GFXAnim[i].back);
+    {$ENDIF}
+    // --------- shots --------- //
+    for i := 0 to WEAPON_LAST do
+      if ShotAnim[i].count > 0 then
+        ShotTextures[i] := r_Textures_LoadMultiFromFileAndInfo(GameWad + ':TEXTURES/' + ShotAnim[i].name, ShotAnim[i].w, ShotAnim[i].h, ShotAnim[i].count, false);
   end;
 
   procedure r_Map_Free;
-    var i, j: Integer; d: TDirection;
+    var i, j, k, a: Integer; d: TDirection;
   begin
+    for i := 0 to WEAPON_LAST do
+    begin
+      if ShotTextures[i] <> nil then
+        ShotTextures[i].Free;
+      ShotTextures[i] := nil;
+    end;
+    {$IFDEF ENABLE_GFX}
+      gfxlist := nil;
+      for i := 0 to R_GFX_LAST do
+      begin
+        if GFXTextures[i] <> nil then
+          GFXTextures[i].Free;
+        GFXTextures[i] := nil;
+      end;
+    {$ENDIF}
+    for i := 1 to WP_LAST do
+    begin
+      for j := 0 to W_POS_LAST do
+      begin
+        for k := 0 to W_ACT_LAST do
+        begin
+          if WeapTextures[i, j, k] <> nil then
+            WeapTextures[i, j, k].Free;
+          WeapTextures[i, j, k] := nil;
+        end;
+      end;
+    end;
+    for d := TDirection.D_LEFT to TDirection.D_RIGHT do
+    begin
+      for a := A_STAND to A_LAST do
+      begin
+        if Models[i].anim[d, a].base <> nil then
+          Models[i].anim[d, a].base.Free;
+        if Models[i].anim[d, a].mask <> nil then
+          Models[i].anim[d, a].mask.Free;
+        Models[i].anim[d, a].base := nil;
+        Models[i].anim[d, a].mask := nil;
+      end;
+    end;
     for i := MONSTER_DEMON to MONSTER_MAN do
     begin
       for j := 0 to ANIM_LAST do
@@ -331,13 +475,6 @@ implementation
     RenTextures := nil;
   end;
 
-  procedure r_Map_Update;
-    var i: Integer;
-  begin
-    for i := 0 to ITEM_MAX do
-      Items[i].anim.Update;
-  end;
-
   procedure r_Map_DrawPanel (p: TPanel);
     var Texture: Integer; t: TGLMultiTexture;
   begin
@@ -499,12 +636,37 @@ implementation
   end;
 
   procedure r_Map_DrawPlayerModel (pm: TPlayerModel; x, y: Integer);
-    var a: Integer; d: TDirection; flip: Boolean; t: TGLMultiTexture;
+    var a, pos, act, xx, yy: Integer; d: TDirection; flip: Boolean; t: TGLMultiTexture; tex: TGLTexture;
   begin
-    // TODO draw flag
-    // TODO draw weapon
     a := pm.CurrentAnimation;
     d := pm.Direction;
+    // TODO draw flag
+    if PlayerModelsArray[pm.id].HaveWeapon and not (a in [A_DIE1, A_DIE2, A_PAIN]) then
+    begin
+      case a of
+        A_SEEUP, A_ATTACKUP: pos := W_POS_UP;
+        A_SEEDOWN, A_ATTACKDOWN: pos := W_POS_DOWN;
+      else pos := W_POS_NORMAL;
+      end;
+      if (a in [A_ATTACK, A_ATTACKUP, A_ATTACKDOWN]) or pm.GetFire() then
+        act := W_ACT_FIRE
+      else
+        act := W_ACT_NORMAL;
+      tex := WeapTextures[pm.CurrentWeapon, pos, act];
+      if tex <> nil then
+      begin
+        xx := PlayerModelsArray[pm.id].WeaponPoints[pm.CurrentWeapon, a, d, pm.AnimState.CurrentFrame].X;
+        yy := PlayerModelsArray[pm.id].WeaponPoints[pm.CurrentWeapon, a, d, pm.AnimState.CurrentFrame].Y;
+        r_Draw_Texture(
+          tex,
+          x + xx,
+          y + yy,
+          tex.width,
+          tex.height,
+          d = TDirection.D_LEFT
+        );
+      end;
+    end;
     if r_Map_GetPlayerModelTex(pm.id, a, d, flip) then
     begin
       t := Models[pm.id].anim[d, a].base;
@@ -564,6 +726,164 @@ implementation
   end;
 {$ENDIF}
 
+{$IFDEF ENABLE_GFX}
+  function r_Map_GetGFXID (): Integer;
+    var i: Integer;
+  begin
+    i := 0;
+    if gfxlist <> nil then
+    begin
+      while (i < Length(gfxlist)) and gfxlist[i].anim.IsValid() do
+        Inc(i);
+      if i >= Length(gfxlist) then
+        SetLength(gfxlist, Length(gfxlist) + 1)
+    end
+    else
+      SetLength(gfxlist, 1);
+    gfxlist[i].typ := R_GFX_NONE;
+    gfxlist[i].anim.Invalidate;
+    result := i
+  end;
+
+  procedure r_Map_NewGFX (typ, x, y: Integer);
+    var i: Integer;
+  begin
+    if gpart_dbg_enabled and (typ > 0) and (typ <= R_GFX_LAST) then
+    begin
+      i := r_Map_GetGFXID();
+      if i >= 0 then
+      begin
+        gfxlist[i].typ := typ;
+        gfxlist[i].x := x;
+        gfxlist[i].y := y;
+        gfxlist[i].oldX := x;
+        gfxlist[i].oldY := y;
+        gfxlist[i].anim := TAnimState.Create(false, GFXAnim[typ].speed + Random(GFXAnim[typ].rspeed), GFXAnim[typ].count);
+        gfxlist[i].anim.Reset();
+        gfxlist[i].anim.Enable();
+      end;
+    end;
+  end;
+
+  procedure r_Map_UpdateGFX;
+    var i: Integer;
+  begin
+    if gfxlist <> nil then
+    begin
+      for i := 0 to High(gfxlist) do
+      begin
+        if gfxlist[i].anim.IsValid() then
+        begin
+          gfxlist[i].oldX := gfxlist[i].x;
+          gfxlist[i].oldY := gfxlist[i].y;
+          case gfxlist[i].typ of
+            R_GFX_FLAME, R_GFX_SMOKE:
+            begin
+              if Random(3) = 0 then
+                gfxlist[i].x := gfxlist[i].x - 1 + Random(3);
+              if Random(2) = 0 then
+                gfxlist[i].y := gfxlist[i].y - Random(2);
+            end;
+          end;
+          if gfxlist[i].anim.played then
+            gfxlist[i].anim.Invalidate
+          else
+            gfxlist[i].anim.Update
+        end;
+      end;
+    end;
+  end;
+
+  procedure r_Map_DrawParticles (x, y, w, h: Integer);
+    var i, fx, fy: Integer;
+  begin
+    if gpart_dbg_enabled and (Particles <> nil) then
+    begin
+      glDisable(GL_TEXTURE_2D);
+      if (g_dbg_scale < 0.6) then
+        glPointSize(1)
+      else if (g_dbg_scale > 1.3) then
+        glPointSize(g_dbg_scale + 1)
+      else
+        glPointSize(2);
+      glDisable(GL_POINT_SMOOTH);
+      glEnable(GL_BLEND);
+      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+      glBegin(GL_POINTS);
+        for i := 0 to High(Particles) do
+        begin
+          if Particles[i].alive then
+          begin
+            fx := nlerp(Particles[i].oldX, Particles[i].x, gLerpFactor);
+            fy := nlerp(Particles[i].oldY, Particles[i].y, gLerpFactor);
+            glColor4ub(Particles[i].red, Particles[i].green, Particles[i].blue, Particles[i].alpha);
+            glVertex2f(fx, fy);
+          end;
+        end;
+      glEnd;
+
+      glDisable(GL_BLEND);
+    end;
+  end;
+
+  procedure r_Map_DrawGFX (x, y, w, h: Integer);
+    var i, fx, fy, typ: Integer; tex: TGLMultiTexture;
+  begin
+    if gfxlist <> nil then
+    begin
+      for i := 0 to High(gfxlist) do
+      begin
+        if gfxlist[i].anim.IsValid() then
+        begin
+          typ := gfxlist[i].typ;
+          tex := GFXTextures[typ];
+          if tex <> nil then
+          begin
+            fx := nlerp(gfxlist[i].oldX, gfxlist[i].x, gLerpFactor);
+            fy := nlerp(gfxlist[i].oldY, gfxlist[i].y, gLerpFactor);
+            // TODO set GFXAnim[typ].alpha
+            r_Draw_MultiTextureRepeat(tex, gfxlist[i].anim, fx, fy, tex.width, tex.height, false);
+          end;
+        end;
+      end;
+    end;
+  end;
+{$ENDIF}
+
+  procedure r_Map_DrawShots (x, y, w, h: Integer);
+    var i, a, fX, fY, pX, pY, typ: Integer; tex: TGLMultiTexture; anim: ^TAnimState;
+  begin
+    if Shots <> nil then
+    begin
+      for i := 0 to High(Shots) do
+      begin
+        typ := Shots[i].ShotType;
+        if typ <> 0 then
+        begin
+          e_logwritefln('draw shot %s typ %s', [i, typ]);
+          tex := ShotTextures[typ];
+          if tex <> nil then
+          begin
+            e_logwritefln('draw shot %s typ %s <> nil', [i, typ]);
+            a := 0;
+            case typ of
+              WEAPON_ROCKETLAUNCHER, WEAPON_BARON_FIRE, WEAPON_MANCUB_FIRE, WEAPON_SKEL_FIRE:
+                a := -GetAngle2(Shots[i].Obj.Vel.X, Shots[i].Obj.Vel.Y)
+            end;
+            Shots[i].Obj.Lerp(gLerpFactor, fX, fY);
+            pX := Shots[i].Obj.Rect.Width div 2;
+            pY := Shots[i].Obj.Rect.Height div 2;
+            // TODO fix this
+            if Shots[i].Animation.IsValid() then anim := @Shots[i].Animation else anim := @StubShotAnim;
+            // TODO: change angle and base point
+            r_Draw_MultiTextureRepeat(tex, anim^, fX, fY, tex.width, tex.height, false);
+          end;
+        end;
+      end;
+    end;
+  end;
+
   procedure r_Map_Draw (x, y, w, h, camx, camy: Integer);
     var iter: TPanelGrid.Iter; p: PPanel; cx, cy, xx, yy, ww, hh: Integer;
   begin
@@ -589,7 +909,7 @@ implementation
     r_Map_DrawPanelType(PANEL_BACK);
     r_Map_DrawPanelType(PANEL_STEP);
     r_Map_DrawItems(xx, yy, ww, hh, false);
-    // TODO draw weapons
+    r_Map_DrawShots(xx, yy, ww, hh);
     // TODO draw shells
     r_Map_DrawPlayers(xx, yy, ww, hh);
     // TODO draw gibs
@@ -600,7 +920,10 @@ implementation
     r_Map_DrawMonsters(xx, yy, ww, hh);
     r_Map_DrawItems(xx, yy, ww, hh, true);
     r_Map_DrawPanelType(PANEL_CLOSEDOOR);
-    // TODO draw gfx
+    {$IFDEF ENABLE_GFX}
+      r_Map_DrawParticles(xx, yy, ww, hh);
+      r_Map_DrawGFX(xx, yy, ww, hh);
+    {$ENDIF}
     // TODO draw flags
     r_Map_DrawPanelType(PANEL_ACID1);
     r_Map_DrawPanelType(PANEL_ACID2);
@@ -609,4 +932,12 @@ implementation
     glPopMatrix;
   end;
 
+  procedure r_Map_Update;
+    var i: Integer;
+  begin
+    for i := 0 to ITEM_MAX do
+      Items[i].anim.Update;
+    r_Map_UpdateGFX;
+  end;
+
 end.