(* Copyright (C) Doom 2D: Forever Developers
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License ONLY.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*)
{$INCLUDE ../shared/a_modes.inc}
unit g_textures;
interface
uses
SysUtils, Classes,
{$IFDEF USE_MEMPOOL}mempool,{$ENDIF}
e_graphics, MAPDEF, ImagingTypes, Imaging, ImagingUtility;
type
TLevelTexture = record
textureName: AnsiString;
width, height: Word;
case anim: Boolean of
false: (textureID: LongWord);
true: (framesID: LongWord; framesCount: Byte; speed: Byte);
end;
TLevelTextureArray = array of TLevelTexture;
TAnimation = class{$IFDEF USE_MEMPOOL}(TPoolObject){$ENDIF}
private
mId: LongWord;
mAlpha: Byte;
mBlending: Boolean;
mCounter: Byte; // Счетчик ожидания между кадрами
mSpeed: Byte; // Время ожидания между кадрами
mCurrentFrame: Integer; // Текущий кадр (начиная с 0)
mLoop: Boolean; // Переходить на первый кадр после последнего?
mEnabled: Boolean; // Работа разрешена?
mPlayed: Boolean; // Проиграна вся хотя бы раз?
mHeight: Word;
mWidth: Word;
mMinLength: Byte; // Ожидание после проигрывания
mRevert: Boolean; // Смена кадров обратная?
public
constructor Create (aframesID: LongWord; aloop: Boolean; aspeed: Byte);
destructor Destroy (); override;
procedure draw (x, y: Integer; mirror: TMirrorType);
procedure drawEx (x, y: Integer; mirror: TMirrorType; rpoint: TDFPoint; angle: SmallInt);
procedure reset ();
procedure update ();
procedure enable ();
procedure disable ();
procedure revert (r: Boolean);
procedure saveState (st: TStream);
procedure loadState (st: TStream);
function totalFrames (): Integer; inline;
public
property played: Boolean read mPlayed;
property enabled: Boolean read mEnabled;
property isReverse: Boolean read mRevert;
property loop: Boolean read mLoop write mLoop;
property speed: Byte read mSpeed write mSpeed;
property minLength: Byte read mMinLength write mMinLength;
property currentFrame: Integer read mCurrentFrame write mCurrentFrame;
property currentCounter: Byte read mCounter write mCounter;
property counter: Byte read mCounter;
property blending: Boolean read mBlending write mBlending;
property alpha: Byte read mAlpha write mAlpha;
property framesId: LongWord read mId;
property width: Word read mWidth;
property height: Word read mHeight;
end;
function g_Texture_CreateWAD (var ID: LongWord; const Resource: AnsiString): Boolean;
function g_Texture_CreateFile (var ID: LongWord; const FileName: AnsiString): Boolean;
function g_Texture_CreateWADEx (const textureName, Resource: AnsiString): Boolean;
function g_Texture_CreateFileEx (const textureName, FileName: AnsiString): Boolean;
function g_Texture_Get (const textureName: AnsiString; var ID: LongWord): Boolean;
function g_Texture_GetSize (const textureName: AnsiString; var w, h: Integer): Boolean; overload;
function g_Texture_GetSize (ID: LongWord; var w, h: Integer): Boolean; overload;
procedure g_Texture_Delete (const textureName: AnsiString);
procedure g_Texture_DeleteAll ();
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_CreateRevert(ID: PDWORD; Name: ShortString; Frames: string): 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 ();
procedure DumpTextureNames ();
function g_Texture_Light (): Integer;
implementation
uses
{$INCLUDE ../nogl/noGLuses.inc}
g_game, e_log, g_basic, g_console, wadreader,
g_language, utils, xstreams;
type
_TTexture = record
name: AnsiString;
id: LongWord;
width, height: Word;
used: Boolean;
end;
TFrames = record
texturesID: array of LongWord;
name: AnsiString;
frameWidth, frameHeight: Word;
used: Boolean;
end;
var
texturesArray: array of _TTexture = nil;
framesArray: array of TFrames = nil;
const
ANIM_SIGNATURE = $4D494E41; // 'ANIM'
function allocTextureSlot (): LongWord;
var
f: integer;
begin
for f := 0 to High(texturesArray) do
begin
if (not texturesArray[f].used) then
begin
result := f;
exit;
end;
end;
result := Length(texturesArray);
SetLength(texturesArray, result+64);
for f := result to High(texturesArray) do
begin
with texturesArray[f] do
begin
name := '';
id := 0;
width := 0;
height := 0;
used := false;
end;
end;
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_Texture_CreateWAD (var ID: LongWord; const Resource: AnsiString): Boolean;
var
WAD: TWADFile;
FileName: AnsiString;
TextureData: Pointer;
ResourceLength: Integer;
begin
result := false;
FileName := g_ExtractWadName(Resource);
WAD := TWADFile.Create;
WAD.ReadFile(FileName);
if WAD.GetResource(g_ExtractFilePathName(Resource), TextureData, ResourceLength) then
begin
if e_CreateTextureMem(TextureData, ResourceLength, ID) then
result := true;
FreeMem(TextureData)
end
else
begin
e_WriteLog(Format('Error loading texture %s', [Resource]), TMsgType.Warning);
//e_WriteLog(Format('WAD Reader error: %s', [WAD.GetLastErrorStr]), MSG_WARNING);
end;
WAD.Free();
end;
function g_Texture_CreateFile (var ID: LongWord; const FileName: AnsiString): Boolean;
begin
result := true;
if not e_CreateTexture(FileName, ID) then
begin
e_WriteLog(Format('Error loading texture %s', [FileName]), TMsgType.Warning);
result := false;
end;
end;
function g_Texture_CreateWADEx (const textureName, Resource: AnsiString): Boolean;
var
WAD: TWADFile;
FileName: AnsiString;
TextureData: Pointer;
find_id: LongWord;
ResourceLength: Integer;
begin
FileName := g_ExtractWadName(Resource);
find_id := allocTextureSlot();
WAD := TWADFile.Create;
WAD.ReadFile(FileName);
if WAD.GetResource(g_ExtractFilePathName(Resource), TextureData, ResourceLength) then
begin
result := e_CreateTextureMem(TextureData, ResourceLength, texturesArray[find_id].ID);
if result then
begin
e_GetTextureSize(texturesArray[find_id].ID, @texturesArray[find_id].width, @texturesArray[find_id].height);
texturesArray[find_id].used := true;
texturesArray[find_id].Name := textureName;
end;
FreeMem(TextureData)
end
else
begin
e_WriteLog(Format('Error loading texture %s', [Resource]), TMsgType.Warning);
//e_WriteLog(Format('WAD Reader error: %s', [WAD.GetLastErrorStr]), MSG_WARNING);
result := false;
end;
WAD.Free();
end;
function g_Texture_CreateFileEx (const textureName, FileName: AnsiString): Boolean;
var
find_id: LongWord;
begin
find_id := allocTextureSlot();
result := e_CreateTexture(FileName, texturesArray[find_id].ID);
if result then
begin
texturesArray[find_id].used := true;
texturesArray[find_id].Name := textureName;
e_GetTextureSize(texturesArray[find_id].ID, @texturesArray[find_id].width, @texturesArray[find_id].height);
end
else e_WriteLog(Format('Error loading texture %s', [FileName]), TMsgType.Warning);
end;
function g_Texture_Get (const textureName: AnsiString; var id: LongWord): Boolean;
var
a: Integer;
begin
result := false;
if (Length(texturesArray) = 0) or (Length(textureName) = 0) then exit;
for a := 0 to High(texturesArray) do
begin
if (StrEquCI1251(texturesArray[a].name, textureName)) then
begin
id := texturesArray[a].id;
result := true;
break;
end;
end;
//if not Result then g_ConsoleAdd('Texture '+TextureName+' not found');
end;
function g_Texture_GetSize (const textureName: AnsiString; var w, h: Integer): Boolean; overload;
var
a: Integer;
begin
result := false;
w := 0;
h := 0;
if (Length(texturesArray) = 0) or (Length(textureName) = 0) then exit;
for a := 0 to High(texturesArray) do
begin
if (StrEquCI1251(texturesArray[a].name, textureName)) then
begin
w := texturesArray[a].width;
h := texturesArray[a].height;
result := true;
break;
end;
end;
end;
function g_Texture_GetSize (ID: LongWord; var w, h: Integer): Boolean; overload;
var
a: Integer;
begin
result := false;
w := 0;
h := 0;
if (Length(texturesArray) = 0) then exit;
for a := 0 to High(texturesArray) do
begin
if (texturesArray[a].id = ID) then
begin
w := texturesArray[a].width;
h := texturesArray[a].height;
result := true;
break;
end;
end;
end;
procedure g_Texture_Delete (const textureName: AnsiString);
var
a: Integer;
begin
if (Length(texturesArray) = 0) or (Length(textureName) = 0) then exit;
for a := 0 to High(texturesArray) do
begin
if (StrEquCI1251(texturesArray[a].name, textureName)) then
begin
e_DeleteTexture(texturesArray[a].ID);
texturesArray[a].used := false;
texturesArray[a].name := '';
texturesArray[a].id := 0;
texturesArray[a].width := 0;
texturesArray[a].height := 0;
end;
end;
end;
procedure g_Texture_DeleteAll ();
var
a: Integer;
begin
for a := 0 to High(texturesArray) do
begin
if (texturesArray[a].used) then e_DeleteTexture(texturesArray[a].ID);
end;
texturesArray := nil;
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 := '';
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 := '';
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 := '';
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_CreateRevert(ID: PDWORD; Name: ShortString; Frames: string): Boolean;
var
find_id, b: DWORD;
a, c: Integer;
begin
Result := False;
if not g_Frames_Get(b, Frames) then Exit;
find_id := FindFrame();
FramesArray[find_id].Name := Name;
FramesArray[find_id].FrameWidth := FramesArray[b].FrameWidth;
FramesArray[find_id].FrameHeight := FramesArray[b].FrameHeight;
c := High(FramesArray[find_id].TexturesID);
for a := 0 to c do
FramesArray[find_id].TexturesID[a] := FramesArray[b].TexturesID[c-a];
Result := True;
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;
procedure DumpTextureNames ();
var
i: Integer;
begin
e_WriteLog('BEGIN Textures:', TMsgType.Notify);
for i := 0 to High(texturesArray) do e_WriteLog(' '+IntToStr(i)+'. '+texturesArray[i].Name, TMsgType.Notify);
e_WriteLog('END Textures.', TMsgType.Notify);
e_WriteLog('BEGIN Frames:', TMsgType.Notify);
for i := 0 to High(framesArray) do e_WriteLog(' '+IntToStr(i)+'. '+framesArray[i].Name, TMsgType.Notify);
e_WriteLog('END Frames.', TMsgType.Notify);
end;
{ TAnimation }
constructor TAnimation.Create (aframesID: LongWord; aloop: Boolean; aspeed: Byte);
begin
if (aframesID >= Length(framesArray)) then raise Exception.Create('trying to create inexisting frame: something is very wrong here');
mId := aframesID;
mMinLength := 0;
mLoop := aloop;
mSpeed := aspeed;
mEnabled := true;
mCurrentFrame := 0;
mPlayed := false;
mAlpha := 0;
mWidth := framesArray[mId].FrameWidth;
mHeight := framesArray[mId].FrameHeight;
end;
destructor TAnimation.Destroy ();
begin
inherited;
end;
procedure TAnimation.draw (x, y: Integer; mirror: TMirrorType);
begin
if (not mEnabled) then exit;
e_DrawAdv(framesArray[mId].TexturesID[mCurrentFrame], x, y, mAlpha, true, mBlending, 0, nil, mirror);
//e_DrawQuad(X, Y, X+FramesArray[ID].FrameWidth-1, Y+FramesArray[ID].FrameHeight-1, 0, 255, 0);
end;
procedure TAnimation.update ();
begin
if (not mEnabled) then exit;
mCounter += 1;
if (mCounter >= mSpeed) then
begin
// Ожидание между кадрами закончилось
// Обратный порядок кадров?
if mRevert then
begin
// Дошли до конца анимации. Возможно, ждем еще
if (mCurrentFrame = 0) then
begin
if (Length(framesArray[mId].TexturesID)*mSpeed+mCounter < mMinLength) then exit;
end;
mCurrentFrame -= 1;
mPlayed := (mCurrentFrame < 0);
// Повторять ли анимацию по кругу?
if mPlayed then
begin
if mLoop then mCurrentFrame := High(framesArray[mId].TexturesID) else mCurrentFrame += 1;
end;
mCounter := 0;
end
else
begin
// Прямой порядок кадров
// Дошли до конца анимации. Возможно, ждем еще
if (mCurrentFrame = High(framesArray[mId].TexturesID)) then
begin
if (Length(framesArray[mId].TexturesID)*mSpeed+mCounter < mMinLength) then exit;
end;
mCurrentFrame += 1;
mPlayed := (mCurrentFrame > High(framesArray[mId].TexturesID));
// Повторять ли анимацию по кругу?
if mPlayed then
begin
if mLoop then mCurrentFrame := 0 else mCurrentFrame -= 1;
end;
mCounter := 0;
end;
end;
end;
procedure TAnimation.reset ();
begin
if mRevert then mCurrentFrame := High(framesArray[mId].TexturesID) else mCurrentFrame := 0;
mCounter := 0;
mPlayed := false;
end;
procedure TAnimation.disable (); begin mEnabled := false; end;
procedure TAnimation.enable (); begin mEnabled := true; end;
procedure TAnimation.drawEx (x, y: Integer; mirror: TMirrorType; rpoint: TDFPoint; angle: SmallInt);
begin
if (not mEnabled) then exit;
e_DrawAdv(framesArray[mId].TexturesID[mCurrentFrame], x, y, mAlpha, true, mBlending, angle, @rpoint, mirror);
end;
function TAnimation.totalFrames (): Integer; inline; begin result := Length(framesArray[mId].TexturesID); end;
procedure TAnimation.revert (r: Boolean);
begin
mRevert := r;
reset();
end;
procedure TAnimation.saveState (st: TStream);
begin
if (st = nil) then exit;
utils.writeSign(st, 'ANIM');
utils.writeInt(st, Byte(0)); // version
// Счетчик ожидания между кадрами
utils.writeInt(st, Byte(mCounter));
// Текущий кадр
utils.writeInt(st, LongInt(mCurrentFrame));
// Проиграна ли анимация целиком
utils.writeBool(st, mPlayed);
// Alpha-канал всей текстуры
utils.writeInt(st, Byte(mAlpha));
// Размытие текстуры
utils.writeInt(st, Byte(mBlending));
// Время ожидания между кадрами
utils.writeInt(st, Byte(mSpeed));
// Зациклена ли анимация
utils.writeBool(st, mLoop);
// Включена ли
utils.writeBool(st, mEnabled);
// Ожидание после проигрывания
utils.writeInt(st, Byte(mMinLength));
// Обратный ли порядок кадров
utils.writeBool(st, mRevert);
end;
procedure TAnimation.loadState (st: TStream);
begin
if (st = nil) then exit;
if not utils.checkSign(st, 'ANIM') then raise XStreamError.Create('animation chunk expected');
if (utils.readByte(st) <> 0) then raise XStreamError.Create('invalid animation chunk version');
// Счетчик ожидания между кадрами
mCounter := utils.readByte(st);
// Текущий кадр
mCurrentFrame := utils.readLongInt(st);
// Проиграна ли анимация целиком
mPlayed := utils.readBool(st);
// Alpha-канал всей текстуры
mAlpha := utils.readByte(st);
// Размытие текстуры
mBlending := utils.readBool(st);
// Время ожидания между кадрами
mSpeed := utils.readByte(st);
// Зациклена ли анимация
mLoop := utils.readBool(st);
// Включена ли
mEnabled := utils.readBool(st);
// Ожидание после проигрывания
mMinLength := utils.readByte(st);
// Обратный ли порядок кадров
mRevert := utils.readBool(st);
end;
// ////////////////////////////////////////////////////////////////////////// //
var
ltexid: GLuint = 0;
function g_Texture_Light (): Integer;
const
Radius: Integer = 128;
var
tex, tpp: PByte;
x, y, a: Integer;
dist: Double;
begin
if ltexid = 0 then
begin
GetMem(tex, (Radius*2)*(Radius*2)*4);
tpp := tex;
for y := 0 to Radius*2-1 do
begin
for x := 0 to Radius*2-1 do
begin
dist := 1.0-sqrt((x-Radius)*(x-Radius)+(y-Radius)*(y-Radius))/Radius;
if (dist < 0) then
begin
tpp^ := 0; Inc(tpp);
tpp^ := 0; Inc(tpp);
tpp^ := 0; Inc(tpp);
tpp^ := 0; Inc(tpp);
end
else
begin
//tc.setPixel(x, y, Color(cast(int)(dist*255), cast(int)(dist*255), cast(int)(dist*255)));
if (dist > 0.5) then dist := 0.5;
a := round(dist*255);
if (a < 0) then a := 0 else if (a > 255) then a := 255;
tpp^ := 255; Inc(tpp);
tpp^ := 255; Inc(tpp);
tpp^ := 255; Inc(tpp);
tpp^ := Byte(a); Inc(tpp);
end;
end;
end;
glGenTextures(1, @ltexid);
//if (tid == 0) assert(0, "VGL: can't create screen texture");
glBindTexture(GL_TEXTURE_2D, ltexid);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//GLfloat[4] bclr = 0.0;
//glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, bclr.ptr);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Radius*2, Radius*2, 0, GL_RGBA{gltt}, GL_UNSIGNED_BYTE, tex);
end;
result := ltexid;
end;
end.