DEADSOFTWARE

gl: draw gibs
authorDeaDDooMER <deaddoomer@deadsoftware.ru>
Thu, 9 Jun 2022 13:45:23 +0000 (16:45 +0300)
committerDeaDDooMER <deaddoomer@deadsoftware.ru>
Fri, 9 Jun 2023 08:40:43 +0000 (11:40 +0300)
src/game/g_gibs.pas
src/game/renders/opengl/r_draw.pas
src/game/renders/opengl/r_map.pas
src/game/renders/opengl/r_render.pas
src/game/renders/opengl/r_textures.pas

index d190384c55cc9051d0d3cedbd65182572b3096fc..69e5ca8b960d8d63dbdedd45094cda9ff30fc530 100644 (file)
@@ -22,6 +22,7 @@ interface
   const
     DefaultGibsCount = 32;
     DefaultGibsMax = 150;
+    DefaultGibSize: TRectWH = (X: 8; Y: 8; Width: 16; Height: 16);
 
   type
     PGib = ^TGib;
@@ -163,10 +164,7 @@ implementation
         {$IFDEF ENABLE_RENDER}
           Obj.Rect := r_Render_GetGibRect(ModelID, GibID);
         {$ELSE}
-          Obj.Rect.X := 16;
-          Obj.Rect.Y := 16;
-          Obj.Rect.Width := 16;
-          Obj.Rect.Height := 16;
+          Obj.Rect := DefaultGibSize;
         {$ENDIF}
         Obj.X := fX - Obj.Rect.X - (Obj.Rect.Width div 2);
         Obj.Y := fY - Obj.Rect.Y - (Obj.Rect.Height div 2);
index ef2a38bfc31563affc81ba53864e615469e406b1..e836b30d1190e7923f536587de66c616106fd3e0 100644 (file)
@@ -24,6 +24,7 @@ interface
 
   procedure r_Draw_Texture (img: TGLTexture; x, y, w, h: Integer; flip: Boolean; r, g, b, a: Byte; blend: Boolean);
   procedure r_Draw_TextureRepeat (img: TGLTexture; x, y, w, h: Integer; flip: Boolean; r, g, b, a: Byte; blend: Boolean);
+  procedure r_Draw_TextureRepeatRotate (img: TGLTexture; x, y, w, h: Integer; flip: Boolean; r, g, b, a: Byte; blend: Boolean; rx, ry, angle: Integer);
 
   procedure r_Draw_MultiTextureRepeat (m: TGLMultiTexture; const anim: TAnimState; x, y, w, h: Integer; flip: Boolean; r, g, b, a: Byte; blend: Boolean);
   procedure r_Draw_MultiTextureRepeatRotate (m: TGLMultiTexture; const anim: TAnimState; x, y, w, h: Integer; flip: Boolean; r, g, b, a: Byte; blend: Boolean; rx, ry, angle: Integer);
@@ -148,6 +149,23 @@ implementation
           r_Draw_Texture(img, x + i * img.width, y + j * img.height, img.width, img.height, flip, r, g, b, a, blend);
   end;
 
+  procedure r_Draw_TextureRepeatRotate (img: TGLTexture; x, y, w, h: Integer; flip: Boolean; r, g, b, a: Byte; blend: Boolean; rx, ry, angle: Integer);
+  begin
+    ASSERT(w >= 0);
+    ASSERT(h >= 0);
+    if a <> 0 then
+    begin
+      glPushMatrix;
+      glTranslatef(x + rx, y + ry, 0);
+      glRotatef(angle, 0, 0, 1);
+      glTranslatef(-(x + rx), -(y + ry), 0);
+      r_Draw_TextureRepeat(img, x, y, w, h, flip, r, g, b, a, blend);
+      glPopMatrix;
+    end
+    else
+      r_Draw_TextureRepeat(img, x, y, w, h, flip, r, g, b, a, blend);
+  end;
+
   procedure r_Draw_MultiTextureRepeat (m: TGLMultiTexture; const anim: TAnimState; x, y, w, h: Integer; flip: Boolean; r, g, b, a: Byte; blend: Boolean);
     var img: TGLTexture; cur, total, i: Integer;
   begin
@@ -170,7 +188,6 @@ implementation
   end;
 
   procedure r_Draw_MultiTextureRepeatRotate (m: TGLMultiTexture; const anim: TAnimState; x, y, w, h: Integer; flip: Boolean; r, g, b, a: Byte; blend: Boolean; rx, ry, angle: Integer);
-    var i, j: Integer;
   begin
     ASSERT(w >= 0);
     ASSERT(h >= 0);
index 8438e2d35db92e44cf931e8c34881487d55f10e0..9c25806b3dba7356d97a5d41935b733cad41595a 100644 (file)
@@ -17,6 +17,8 @@ unit r_map;
 
 interface
 
+  uses g_base; // TRectWH
+
   procedure r_Map_Initialize;
   procedure r_Map_Finalize;
 
@@ -26,7 +28,12 @@ interface
   procedure r_Map_LoadTextures;
   procedure r_Map_FreeTextures;
 
+{$IFDEF ENABLE_GFX}
   procedure r_Map_NewGFX (typ, x, y: Integer);
+{$ENDIF}
+{$IFDEF ENABLE_GIBS}
+  function r_Map_GetGibSize (m, i: Integer): TRectWH;
+{$ENDIF}
 
   procedure r_Map_Update;
 
@@ -43,11 +50,14 @@ implementation
     {$ENDIF}
     e_log,
     binheap, MAPDEF, utils,
-    g_options, g_textures, g_basic, g_base, g_phys,
+    g_options, g_textures, g_basic, g_phys,
     g_game, g_map, g_panel, g_items, g_monsters, g_playermodel, g_player, g_weapons,
     {$IFDEF ENABLE_CORPSES}
       g_corpses,
     {$ENDIF}
+    {$IFDEF ENABLE_GIBS}
+      g_gibs,
+    {$ENDIF}
     {$IFDEF ENABLE_GFX}
       g_gfx,
     {$ENDIF}
@@ -175,14 +185,12 @@ implementation
       anim: array [TDirection, 0..A_LAST] of record
         base, mask: TGLMultiTexture;
       end;
-(*
-      {$IFDEF ENABLE_GIBS}
-        gibs: array of record
-          base, mask: TGLTexture;
-          rect: TRectWH;
-        end;
-      {$ENDIF}
-*)
+{$IFDEF ENABLE_GIBS}
+      gibs: record
+        base, mask: TGLTextureArray;
+        rect: TRectArray;
+      end;
+{$ENDIF}
     end;
 
     StubShotAnim: TAnimState;
@@ -224,6 +232,8 @@ implementation
   procedure r_Map_LoadModel (i: Integer);
     var prefix: AnsiString; a: Integer; d: TDirection; m: ^TPlayerModelInfo;
   begin
+    ASSERT(i < Length(Models));
+    ASSERT(i < Length(PlayerModelsArray));
     m := @PlayerModelsArray[i];
     prefix := m.FileName + ':TEXTURES/';
     for d := TDirection.D_LEFT to TDirection.D_RIGHT do
@@ -238,18 +248,30 @@ implementation
           Models[i].anim[d, a].mask := r_Textures_LoadMultiFromFileAndInfo(prefix + m.anim[d, a].mask, 64, 64, m.anim[d, a].frames, m.anim[d, a].back, true);
       end
     end;
-(*
     {$IFDEF ENABLE_GIBS}
-      Models[i].gibs := nil;
+      Models[i].gibs.base := nil;
+      Models[i].gibs.mask := nil;
+      Models[i].gibs.rect := nil;
       if m.GibsCount > 0 then
       begin
-        SetLength(Models[i].gibs, m.GibsCount);
+        SetLength(Models[i].gibs.base, m.GibsCount);
+        SetLength(Models[i].gibs.mask, m.GibsCount);
+        SetLength(Models[i].gibs.rect, m.GibsCount);
+        for a := 0 to m.GibsCount - 1 do
+          Models[i].gibs.rect[a] := DefaultGibSize;
+        if r_Textures_LoadStreamFromFile(prefix + m.GibsResource, 32, 32, m.GibsCount, Models[i].gibs.base, Models[i].gibs.rect) then
+        begin
+          if r_Textures_LoadStreamFromFile(prefix + m.GibsMask, 32, 32, m.GibsCount, Models[i].gibs.mask, nil) then
+          begin
+            // ok
+          end;
+        end;
+        for a := 0 to m.GibsCount - 1 do
+          e_logwritefln('model %s gib %s: %sx%s:%sx%s', [i, a, Models[i].gibs.rect[a].x, Models[i].gibs.rect[a].y, Models[i].gibs.rect[a].width, Models[i].gibs.rect[a].height]);
       end;
     {$ENDIF}
-*)
   end;
 
-
   procedure r_Map_Load;
     const
       WeapName: array [0..WP_LAST] of AnsiString = ('', 'CSAW', 'HGUN', 'SG', 'SSG', 'MGUN', 'RKT', 'PLZ', 'BFG', 'SPL', 'FLM');
@@ -750,6 +772,46 @@ implementation
           r_Map_DrawPlayer(gPlayers[i]);
   end;
 
+{$IFDEF ENABLE_GIBS}
+  function r_Map_GetGibSize (m, i: Integer): TRectWH;
+  begin
+    result := Models[m].gibs.rect[i];
+  end;
+
+  procedure r_Map_DrawGibs (x, y, w, h: Integer);
+    var i, fx, fy, m, id, rx, ry, ra: Integer; p: PObj; t: TGLTexture;
+  begin
+    if gGibs <> nil then
+    begin
+      for i := 0 to High(gGibs) do
+      begin
+        if gGibs[i].alive then
+        begin
+          p := @gGibs[i].Obj;
+          if g_Obj_Collide(x, y, w, h, p) then
+          begin
+            p.Lerp(gLerpFactor, fx, fy);
+            id := gGibs[i].GibID;
+            m := gGibs[i].ModelID;
+            t := Models[m].gibs.base[id];
+            if t <> nil then
+            begin
+              rx := p.Rect.X + p.Rect.Width div 2;
+              ry := p.Rect.Y + p.Rect.Height div 2;
+              ra := gGibs[i].RAngle;
+              r_Draw_TextureRepeatRotate(t, fx, fy, t.width, t.height, false, 255, 255, 255, 255, false, rx, ry, ra);
+              t := Models[m].gibs.mask[id];
+              if t <> nil then
+                r_Draw_TextureRepeatRotate(t, fx, fy, t.width, t.height, false, gGibs[i].Color.R, gGibs[i].Color.G, gGibs[i].Color.B, 255, false, rx, ry, ra);
+              // r_Draw_TextureRepeatRotate(nil, fx + p.Rect.X, fy + p.Rect.Y, p.Rect.Width, p.Rect.Height, false, 255, 255, 255, 255, false, p.Rect.Width div 2, p.Rect.Height div 2, ra);
+            end;
+          end;
+        end;
+      end;
+    end;
+  end;
+{$ENDIF}
+
 {$IFDEF ENABLE_CORPSES}
   procedure r_Map_DrawCorpses (x, y, w, h: Integer);
     var i, fX, fY: Integer; p: TCorpse;
@@ -971,7 +1033,9 @@ implementation
     r_Map_DrawShots(xx, yy, ww, hh);
     // TODO draw shells
     r_Map_DrawPlayers(xx, yy, ww, hh);
-    // TODO draw gibs
+    {$IFDEF ENABLE_GIBS}
+      r_Map_DrawGibs(xx, yy, ww, hh);
+    {$ENDIF}
     {$IFDEF ENABLE_CORPSES}
       r_Map_DrawCorpses(xx, yy, ww, hh);
     {$ENDIF}
index e40b600fe04ada739e305fdeba2d083c66035877..c5b2c30497fe751895fbbc245c6f257fadc90a5d 100644 (file)
@@ -251,10 +251,7 @@ implementation
 {$IFDEF ENABLE_GIBS}
   function r_Render_GetGibRect (m, id: Integer): TRectWH;
   begin
-    Result.X := 16;
-    Result.Y := 16;
-    Result.Width := 16;
-    Result.Height := 16;
+    result := r_Map_GetGibSize(m, id);
   end;
 {$ENDIF}
 
index d24c2ac6708ce570384f7335d34513ae3ee49eaa..ce71ebc727d7e96b0001e0a44a512ba1b9269846 100644 (file)
@@ -23,8 +23,9 @@ interface
     {$ELSE}
       GL, GLEXT,
     {$ENDIF}
-    r_atlas,
-    utils    // SSArray
+    g_base,  // TRectHW
+    utils,
+    r_atlas
   ;
 
   type
@@ -97,12 +98,17 @@ interface
         property backAnim: Boolean read mBackanim; (* this property must be located at TAnimState? *)
     end;
 
+    TGLTextureArray = array of TGLTexture;
+
+    TRectArray = array of TRectWH;
+
   procedure r_Textures_Initialize;
   procedure r_Textures_Finalize;
 
   function r_Textures_LoadFromFile (const filename: AnsiString; log: Boolean = True): TGLTexture;
   function r_Textures_LoadMultiFromFile (const filename: AnsiString; log: Boolean = True): TGLMultiTexture;
   function r_Textures_LoadMultiFromFileAndInfo (const filename: AnsiString; w, h, count: Integer; backanim: Boolean; log: Boolean = True): TGLMultiTexture;
+  function r_Textures_LoadStreamFromFile (const filename: AnsiString; w, h, count: Integer; st: TGLTextureArray; rs: TRectArray; log: Boolean = True): Boolean;
 
 implementation
 
@@ -115,7 +121,6 @@ implementation
   var
     maxTileSize: Integer;
     atl: array of TGLAtlas;
-//    tex: array of TGLTexture;
 
   (* --------- TGLAtlasNode --------- *)
 
@@ -360,6 +365,14 @@ implementation
     end;
   end;
 
+  function r_Textures_FixImageData (var img: TImageData): Boolean;
+  begin
+    result := false;
+    if ConvertImage(img, TImageFormat.ifA8R8G8B8) then
+      if SwapChannels(img, ChannelRed, ChannelBlue) then // wtf
+        result := true;
+  end;
+
   function r_Textures_LoadFromImage (var img: TImageData): TGLTexture;
     var t: TGLTexture; n: TGLAtlasNode; c: TDynImageDataArray; cw, ch, i, j: LongInt;
   begin
@@ -396,9 +409,8 @@ implementation
       InitImage(img);
       try
         if LoadImageFromMemory(data, size, img) then
-          if ConvertImage(img, TImageFormat.ifA8R8G8B8) then
-            if SwapChannels(img, ChannelRed, ChannelBlue) then // wth
-              result := r_Textures_LoadFromImage(img)
+          if r_Textures_FixImageData(img) then
+            result := r_Textures_LoadFromImage(img)
       except
       end;
       FreeImage(img);
@@ -459,9 +471,8 @@ implementation
       InitImage(img);
       try
         if LoadImageFromMemory(data, size, img) then
-          if ConvertImage(img, TImageFormat.ifA8R8G8B8) then
-            if SwapChannels(img, ChannelRed, ChannelBlue) then // wtf
-              result := r_Textures_LoadMultiFromImageAndInfo(img, w, h, c, b)
+          if r_Textures_FixImageData(img) then
+            result := r_Textures_LoadMultiFromImageAndInfo(img, w, h, c, b)
       except
       end;
       FreeImage(img);
@@ -491,9 +502,8 @@ implementation
             InitImage(img);
             try
               if LoadImageFromMemory(data, size, img) then
-                if ConvertImage(img, TImageFormat.ifA8R8G8B8) then
-                  if SwapChannels(img, ChannelRed, ChannelBlue) then // wtf
-                    result := r_Textures_LoadMultiFromImageAndInfo(img, w, h, c, b)
+                if r_Textures_FixImageData(img) then
+                  result := r_Textures_LoadMultiFromImageAndInfo(img, w, h, c, b)
             finally
               FreeMem(data);
             end;
@@ -571,4 +581,133 @@ implementation
     end
   end;
 
+  function r_Textures_GetRect (var img: TImageData): TRectWH;
+    var i, j, w, h: Integer; done: Boolean;
+
+    function IsVoid (i, j: Integer): Boolean; inline;
+    begin
+      result := GetPixel32(img, i, j).Channels[3] = 0
+    end;
+
+  begin
+    w := img.Width;
+    h := img.Height;
+
+    (* trace x from right to left *)
+    done := false; i := 0;
+    while not done and (i < w) do
+    begin
+      j := 0;
+      while (j < h) and IsVoid(i, j) do inc(j);
+      done := (j < h) and (IsVoid(i, j) = false);
+      result.x := i;
+      inc(i);
+    end;
+
+    (* trace y from up to down *)
+    done := false; j := 0;
+    while not done and (j < h) do
+    begin
+      i := 0;
+      while (i < w) and IsVoid(i, j) do inc(i);
+      done := (i < w) and (IsVoid(i, j) = false);
+      result.y := j;
+      inc(j);
+    end;
+
+    (* trace x from right to left *)
+    done := false; i := w - 1;
+    while not done and (i >= 0) do
+    begin
+      j := 0;
+      while (j < h) and IsVoid(i, j) do inc(j);
+      done := (j < h) and (IsVoid(i, j) = false);
+      result.width := i - result.x + 1;
+      dec(i);
+    end;
+
+    (* trace y from down to up *)
+    done := false; j := h - 1;
+    while not done and (j >= 0) do
+    begin
+      i := 0;
+      while (i < w) and IsVoid(i, j) do inc(i);
+      done := (i < w) and (IsVoid(i, j) = false);
+      result.height := j - result.y + 1;
+      dec(j);
+    end;
+  end;
+
+  function r_Textures_LoadStreamFromImage (var img: TImageData; w, h, c: Integer; st: TGLTextureArray; rs: TRectArray): Boolean;
+    var i: Integer; t: TImageData;
+  begin
+    ASSERT(w >= 0);
+    ASSERT(h >= 0);
+    ASSERT(c >= 1);
+    ASSERT((st <> nil) and (Length(st) >= c));
+    ASSERT((rs = nil) or (Length(rs) >= c));
+    result := true;
+    for i := 0 to c - 1 do
+    begin
+      InitImage(t);
+      st[i] := nil;
+      if NewImage(w, h, img.Format, t) then
+      begin
+        if CopyRect(img, w * i, 0, w, h, t, 0, 0) then
+        begin
+          if rs <> nil then
+            rs[i] := r_Textures_GetRect(t);
+          st[i] := r_Textures_LoadFromImage(t);
+        end;
+      end;
+      ASSERT(st[i] <> nil);
+      FreeImage(t);
+    end;
+  end;
+
+  function r_Textures_LoadStreamFromMemory (data: Pointer; size: LongInt; w, h, c: Integer; st: TGLTextureArray; rs: TRectArray): Boolean;
+    var img: TImageData;
+  begin
+    ASSERT(w >= 0);
+    ASSERT(h >= 0);
+    ASSERT(c >= 1);
+    ASSERT((st <> nil) and (Length(st) >= c));
+    ASSERT((rs = nil) or (Length(rs) >= c));
+    result := false;
+    if (data <> nil) and (size > 0) then
+    begin
+      InitImage(img);
+      try
+        if LoadImageFromMemory(data, size, img) then
+          if r_Textures_FixImageData(img) then
+            result := r_Textures_LoadStreamFromImage(img, w, h, c, st, rs)
+      except
+      end;
+      FreeImage(img);
+    end;
+  end;
+
+  function r_Textures_LoadStreamFromFile (const filename: AnsiString; w, h, count: Integer; st: TGLTextureArray; rs: TRectArray; log: Boolean = True): Boolean;
+    var wad: TWADFile; wadName, resName: AnsiString; data: Pointer; size: Integer;
+  begin
+    ASSERT(w > 0);
+    ASSERT(h > 0);
+    ASSERT(count >= 1);
+    ASSERT((st <> nil) and (Length(st) >= count));
+    ASSERT((rs = nil) or (Length(rs) >= count));
+    result := false;
+    wadName := g_ExtractWadName(filename);
+    wad := TWADFile.Create();
+    if wad.ReadFile(wadName) then
+    begin
+      resName := g_ExtractFilePathName(filename);
+      if wad.GetResource(resName, data, size, log) then
+      begin
+        result := r_Textures_LoadStreamFromMemory(data, size, w, h, count, st, rs);
+        FreeMem(data);
+      end;
+      wad.Free
+    end
+  end;
+
 end.