DEADSOFTWARE

render: move textures loaders to render
[d2df-sdl.git] / src / game / opengl / r_animations.pas
index 71d752a79da7606ed47a7c035dd134917c42d3a8..1b634051753716d481178091eaf2134a6bbe88bb 100644 (file)
@@ -17,14 +17,44 @@ unit r_animations;
 
 interface
 
-  uses g_base, g_textures, MAPDEF; // TMirrorType, TAnimation, TDFPoint
+  uses g_base, g_textures, MAPDEF, Imaging; // TMirrorType, TAnimation, TDFPoint, TDynImageDataArray
 
   procedure r_Animation_Draw (t: TAnimation; x, y: Integer; mirror: TMirrorType);
   procedure r_Animation_DrawEx (t: TAnimation; x, y: Integer; mirror: TMirrorType; rpoint: TDFPoint; angle: SmallInt);
 
+  function g_CreateFramesImg (ia: TDynImageDataArray; ID: PDWORD; const Name: AnsiString; BackAnimation: Boolean = false): Boolean;
+
+  function g_Frames_CreateWAD (ID: PDWORD; const Name, Resource: AnsiString; mWidth, mHeight, mCount: Word; BackAnimation: Boolean=false): Boolean;
+  function g_Frames_CreateFile (ID: PDWORD; const Name, FileName: AnsiString; mWidth, mHeight, mCount: Word; BackAnimation: Boolean = false): Boolean;
+  function g_Frames_CreateMemory (ID: PDWORD; const Name: AnsiString; pData: Pointer; dataSize: LongInt; mWidth, mHeight, mCount: Word; BackAnimation: Boolean=false): Boolean;
+  function g_Frames_Dup (const NewName, OldName: AnsiString): Boolean;
+  function g_Frames_Get (out ID: LongWord; const FramesName: AnsiString): Boolean;
+  function g_Frames_GetTexture (out ID: LongWord; const FramesName: AnsiString; Frame: Word): Boolean;
+  function g_Frames_Exists (const FramesName: AnsiString): Boolean;
+  procedure g_Frames_DeleteByName (const FramesName: AnsiString);
+  procedure g_Frames_DeleteByID (ID: LongWord);
+  procedure g_Frames_DeleteAll;
+
+  type
+    TFrames = record
+      texturesID: array of LongWord;
+      name: AnsiString;
+      frameWidth, frameHeight: Word;
+      used: Boolean;
+    end;
+
+  var
+    framesArray: array of TFrames = nil;
+
 implementation
 
-  uses r_graphics;
+  uses
+    SysUtils, Classes, Math,
+    WadReader, utils,
+    e_log,
+    r_graphics,
+    g_language, g_game
+  ;
 
   procedure r_Animation_Draw (t: TAnimation; x, y: Integer; mirror: TMirrorType);
   begin
@@ -38,4 +68,328 @@ implementation
       e_DrawAdv(framesArray[t.id].TexturesID[t.currentFrame], x, y, t.alpha, true, t.blending, angle, @rpoint, mirror)
   end;
 
+function allocFrameSlot (): LongWord;
+var
+  f: integer;
+begin
+  for f := 0 to High(framesArray) do
+  begin
+    if (not framesArray[f].used) then
+    begin
+      result := f;
+      exit;
+    end;
+  end;
+
+  result := Length(framesArray);
+  SetLength(framesArray, result+64);
+  for f := result to High(framesArray) do
+  begin
+    with framesArray[f] do
+    begin
+      texturesID := nil;
+      name := '';
+      frameWidth := 0;
+      frameHeight := 0;
+      used := false;
+    end;
+  end;
+end;
+
+function g_Frames_CreateFile (ID: PDWORD; const Name, FileName: AnsiString;
+                              mWidth, mHeight, mCount: Word; BackAnimation: Boolean = false): Boolean;
+var
+  a: Integer;
+  find_id: LongWord;
+begin
+  result := false;
+
+  find_id := allocFrameSlot();
+
+  if (mCount <= 2) then BackAnimation := false;
+
+  if BackAnimation then SetLength(framesArray[find_id].TexturesID, mCount+mCount-2)
+  else SetLength(framesArray[find_id].TexturesID, mCount);
+
+  for a := 0 to mCount-1 do
+  begin
+    if not e_CreateTextureEx(FileName, framesArray[find_id].TexturesID[a], a*mWidth, 0, mWidth, mHeight) then exit;
+  end;
+
+  if BackAnimation then
+  begin
+    for a := 1 to mCount-2 do framesArray[find_id].TexturesID[mCount+mCount-2-a] := framesArray[find_id].TexturesID[a];
+  end;
+
+  framesArray[find_id].used := true;
+  framesArray[find_id].FrameWidth := mWidth;
+  framesArray[find_id].FrameHeight := mHeight;
+  if (Name <> '') then framesArray[find_id].Name := Name else framesArray[find_id].Name := '<noname>';
+
+  if (ID <> nil) then ID^ := find_id;
+
+  result := true;
+end;
+
+function CreateFramesMem (pData: Pointer; dataSize: LongInt; ID: PDWORD; Name: AnsiString;
+                          mWidth, mHeight, mCount: Word; BackAnimation: Boolean = false): Boolean;
+var
+  find_id: LongWord;
+  a: Integer;
+begin
+  result := false;
+
+  find_id := allocFrameSlot();
+
+  if (mCount <= 2) then BackAnimation := false;
+
+  if BackAnimation then SetLength(framesArray[find_id].TexturesID, mCount+mCount-2)
+  else SetLength(framesArray[find_id].TexturesID, mCount);
+
+  for a := 0 to mCount-1 do
+    if not e_CreateTextureMemEx(pData, dataSize, framesArray[find_id].TexturesID[a], a*mWidth, 0, mWidth, mHeight) then
+    begin
+      //!!!FreeMem(pData);
+      exit;
+    end;
+
+  if BackAnimation then
+  begin
+    for a := 1 to mCount-2 do framesArray[find_id].TexturesID[mCount+mCount-2-a] := framesArray[find_id].TexturesID[a];
+  end;
+
+  framesArray[find_id].used := true;
+  framesArray[find_id].FrameWidth := mWidth;
+  framesArray[find_id].FrameHeight := mHeight;
+  if (Name <> '') then framesArray[find_id].Name := Name else framesArray[find_id].Name := '<noname>';
+
+  if (ID <> nil) then ID^ := find_id;
+
+  result := true;
+end;
+
+function g_CreateFramesImg (ia: TDynImageDataArray; ID: PDWORD; const Name: AnsiString; BackAnimation: Boolean = false): Boolean;
+var
+  find_id: LongWord;
+  a, mCount: Integer;
+begin
+  result := false;
+  find_id := allocFrameSlot();
+
+  mCount := Length(ia);
+
+  //e_WriteLog(Format('+++ creating %d frames [%s]', [FCount, Name]), MSG_NOTIFY);
+
+  if (mCount < 1) then exit;
+  if (mCount <= 2) then BackAnimation := false;
+
+  if BackAnimation then SetLength(framesArray[find_id].TexturesID, mCount+mCount-2)
+  else SetLength(framesArray[find_id].TexturesID, mCount);
+
+  //e_WriteLog(Format('+++ creating %d frames, %dx%d', [FCount, ia[0].width, ia[0].height]), MSG_NOTIFY);
+
+  for a := 0 to mCount-1 do
+  begin
+    if not e_CreateTextureImg(ia[a], framesArray[find_id].TexturesID[a]) then exit;
+    //e_WriteLog(Format('+++   frame %d, %dx%d', [a, ia[a].width, ia[a].height]), MSG_NOTIFY);
+  end;
+
+  if BackAnimation then
+  begin
+    for a := 1 to mCount-2 do framesArray[find_id].TexturesID[mCount+mCount-2-a] := framesArray[find_id].TexturesID[a];
+  end;
+
+  framesArray[find_id].used := true;
+  framesArray[find_id].FrameWidth := ia[0].width;
+  framesArray[find_id].FrameHeight := ia[0].height;
+  if (Name <> '') then framesArray[find_id].Name := Name else framesArray[find_id].Name := '<noname>';
+
+  if (ID <> nil) then ID^ := find_id;
+
+  result := true;
+end;
+
+function g_Frames_CreateWAD (ID: PDWORD; const Name, Resource: AnsiString;
+                             mWidth, mHeight, mCount: Word; BackAnimation: Boolean=false): Boolean;
+var
+  WAD: TWADFile;
+  FileName: AnsiString;
+  TextureData: Pointer;
+  ResourceLength: Integer;
+begin
+  result := false;
+
+  // models without "advanced" animations asks for "nothing" like this; don't spam log
+  if (Length(Resource) > 0) and ((Resource[Length(Resource)] = '/') or (Resource[Length(Resource)] = '\')) then exit;
+
+  FileName := g_ExtractWadName(Resource);
+
+  WAD := TWADFile.Create();
+  WAD.ReadFile(FileName);
+
+  if not WAD.GetResource(g_ExtractFilePathName(Resource), TextureData, ResourceLength) then
+  begin
+    WAD.Free();
+    e_WriteLog(Format('Error loading texture %s', [Resource]), TMsgType.Warning);
+    //e_WriteLog(Format('WAD Reader error: %s', [WAD.GetLastErrorStr]), MSG_WARNING);
+    exit;
+  end;
+
+  if not CreateFramesMem(TextureData, ResourceLength, ID, Name, mWidth, mHeight, mCount, BackAnimation) then
+  begin
+    FreeMem(TextureData);
+    WAD.Free();
+    exit;
+  end;
+
+  FreeMem(TextureData);
+  WAD.Free();
+
+  result := true;
+end;
+
+function g_Frames_CreateMemory (ID: PDWORD; const Name: AnsiString; pData: Pointer; dataSize: LongInt;
+                                mWidth, mHeight, mCount: Word; BackAnimation: Boolean = false): Boolean;
+begin
+  result := CreateFramesMem(pData, dataSize, ID, Name, mWidth, mHeight, mCount, BackAnimation);
+end;
+
+function g_Frames_Dup (const NewName, OldName: AnsiString): Boolean;
+var
+  find_id, b: LongWord;
+  a, c: Integer;
+begin
+  result := false;
+
+  if not g_Frames_Get(b, OldName) then exit;
+
+  find_id := allocFrameSlot();
+
+  framesArray[find_id].used := true;
+  framesArray[find_id].Name := NewName;
+  framesArray[find_id].FrameWidth := framesArray[b].FrameWidth;
+  framesArray[find_id].FrameHeight := framesArray[b].FrameHeight;
+
+  c := High(framesArray[b].TexturesID);
+  SetLength(framesArray[find_id].TexturesID, c+1);
+
+  for a := 0 to c do framesArray[find_id].TexturesID[a] := framesArray[b].TexturesID[a];
+
+  result := true;
+end;
+
+
+procedure g_Frames_DeleteByName (const FramesName: AnsiString);
+var
+  a, b: Integer;
+begin
+  if (Length(framesArray) = 0) then exit;
+  for a := 0 to High(framesArray) do
+  begin
+    if (StrEquCI1251(framesArray[a].Name, FramesName)) then
+    begin
+      if framesArray[a].TexturesID <> nil then
+      begin
+        for b := 0 to High(framesArray[a].TexturesID) do e_DeleteTexture(framesArray[a].TexturesID[b]);
+      end;
+      framesArray[a].used := false;
+      framesArray[a].TexturesID := nil;
+      framesArray[a].Name := '';
+      framesArray[a].FrameWidth := 0;
+      framesArray[a].FrameHeight := 0;
+    end;
+  end;
+end;
+
+procedure g_Frames_DeleteByID (ID: LongWord);
+var
+  b: Integer;
+begin
+  if (Length(framesArray) = 0) then exit;
+  if (framesArray[ID].TexturesID <> nil) then
+  begin
+    for b := 0 to High(framesArray[ID].TexturesID) do e_DeleteTexture(framesArray[ID].TexturesID[b]);
+  end;
+  framesArray[ID].used := false;
+  framesArray[ID].TexturesID := nil;
+  framesArray[ID].Name := '';
+  framesArray[ID].FrameWidth := 0;
+  framesArray[ID].FrameHeight := 0;
+end;
+
+procedure g_Frames_DeleteAll ();
+var
+  a, b: Integer;
+begin
+  for a := 0 to High(framesArray) do
+  begin
+    if (framesArray[a].used) then
+    begin
+      for b := 0 to High(framesArray[a].TexturesID) do e_DeleteTexture(framesArray[a].TexturesID[b]);
+    end;
+    framesArray[a].used := false;
+    framesArray[a].TexturesID := nil;
+    framesArray[a].Name := '';
+    framesArray[a].FrameWidth := 0;
+    framesArray[a].FrameHeight := 0;
+  end;
+  framesArray := nil;
+end;
+
+
+function g_Frames_Get (out ID: LongWord; const FramesName: AnsiString): Boolean;
+var
+  a: Integer;
+begin
+  result := false;
+  if (Length(framesArray) = 0) then exit;
+  for a := 0 to High(framesArray) do
+  begin
+    if (StrEquCI1251(framesArray[a].Name, FramesName)) then
+    begin
+      ID := a;
+      result := true;
+      break;
+    end;
+  end;
+  if not result then g_FatalError(Format(_lc[I_GAME_ERROR_FRAMES], [FramesName]));
+end;
+
+function g_Frames_GetTexture (out ID: LongWord; const FramesName: AnsiString; Frame: Word): Boolean;
+var
+  a: Integer;
+begin
+  result := false;
+  if (Length(framesArray) = 0) then exit;
+  for a := 0 to High(framesArray) do
+  begin
+    if (StrEquCI1251(framesArray[a].Name, FramesName)) then
+    begin
+      if (Frame < Length(framesArray[a].TexturesID)) then
+      begin
+        ID := framesArray[a].TexturesID[Frame];
+        result := true;
+        break;
+      end;
+    end;
+  end;
+  if not result then g_FatalError(Format(_lc[I_GAME_ERROR_FRAMES], [FramesName]));
+end;
+
+function g_Frames_Exists (const FramesName: AnsiString): Boolean;
+var
+  a: Integer;
+begin
+  result := false;
+  if (Length(framesArray) = 0) then exit;
+  for a := 0 to High(framesArray) do
+  begin
+    if (StrEquCI1251(framesArray[a].Name, FramesName)) then
+    begin
+      result := true;
+      exit;
+    end;
+  end;
+end;
+
 end.