DEADSOFTWARE

87893c2a9cc22089e60ac02798d1bbbdf2e097a2
[d2df-sdl.git] / src / game / g_textures.pas
1 (* Copyright (C) Doom 2D: Forever Developers
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, version 3 of the License ONLY.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 *)
15 {$INCLUDE ../shared/a_modes.inc}
16 unit g_textures;
18 interface
20 uses
21 SysUtils, Classes,
22 {$IFDEF USE_MEMPOOL}mempool,{$ENDIF}
23 e_graphics, MAPDEF, ImagingTypes, Imaging, ImagingUtility;
25 type
26 TLevelTexture = record
27 textureName: AnsiString;
28 width, height: Word;
29 case anim: Boolean of
30 false: (textureID: LongWord);
31 true: (framesID: LongWord; framesCount: Byte; speed: Byte);
32 end;
34 TLevelTextureArray = array of TLevelTexture;
36 TAnimation = class{$IFDEF USE_MEMPOOL}(TPoolObject){$ENDIF}
37 private
38 mId: LongWord;
39 mAlpha: Byte;
40 mBlending: Boolean;
41 mCounter: Byte; // Ñ÷åò÷èê îæèäàíèÿ ìåæäó êàäðàìè
42 mSpeed: Byte; // Âðåìÿ îæèäàíèÿ ìåæäó êàäðàìè
43 mCurrentFrame: Integer; // Òåêóùèé êàäð (íà÷èíàÿ ñ 0)
44 mLoop: Boolean; // Ïåðåõîäèòü íà ïåðâûé êàäð ïîñëå ïîñëåäíåãî?
45 mEnabled: Boolean; // Ðàáîòà ðàçðåøåíà?
46 mPlayed: Boolean; // Ïðîèãðàíà âñÿ õîòÿ áû ðàç?
47 mHeight: Word;
48 mWidth: Word;
49 mMinLength: Byte; // Îæèäàíèå ïîñëå ïðîèãðûâàíèÿ
50 mRevert: Boolean; // Ñìåíà êàäðîâ îáðàòíàÿ?
52 public
53 constructor Create (aframesID: LongWord; aloop: Boolean; aspeed: Byte);
54 destructor Destroy (); override;
56 procedure draw (x, y: Integer; mirror: TMirrorType);
57 procedure drawEx (x, y: Integer; mirror: TMirrorType; rpoint: TDFPoint; angle: SmallInt);
59 procedure reset ();
60 procedure update ();
61 procedure enable ();
62 procedure disable ();
63 procedure revert (r: Boolean);
65 procedure saveState (st: TStream);
66 procedure loadState (st: TStream);
68 function totalFrames (): Integer; inline;
70 public
71 property played: Boolean read mPlayed;
72 property enabled: Boolean read mEnabled;
73 property isReverse: Boolean read mRevert;
74 property loop: Boolean read mLoop write mLoop;
75 property speed: Byte read mSpeed write mSpeed;
76 property minLength: Byte read mMinLength write mMinLength;
77 property currentFrame: Integer read mCurrentFrame write mCurrentFrame;
78 property currentCounter: Byte read mCounter write mCounter;
79 property counter: Byte read mCounter;
80 property blending: Boolean read mBlending write mBlending;
81 property alpha: Byte read mAlpha write mAlpha;
82 property framesId: LongWord read mId;
83 property width: Word read mWidth;
84 property height: Word read mHeight;
85 end;
88 function g_Texture_CreateWAD (var ID: LongWord; const Resource: AnsiString): Boolean;
89 function g_Texture_CreateFile (var ID: LongWord; const FileName: AnsiString): Boolean;
90 function g_Texture_CreateWADEx (const textureName, Resource: AnsiString): Boolean;
91 function g_Texture_CreateFileEx (const textureName, FileName: AnsiString): Boolean;
92 function g_Texture_Get (const textureName: AnsiString; var ID: LongWord): Boolean;
93 function g_Texture_GetSize (const textureName: AnsiString; var w, h: Integer): Boolean; overload;
94 function g_Texture_GetSize (ID: LongWord; var w, h: Integer): Boolean; overload;
95 procedure g_Texture_Delete (const textureName: AnsiString);
96 procedure g_Texture_DeleteAll ();
98 function g_CreateFramesImg (ia: TDynImageDataArray; ID: PDWORD; const Name: AnsiString; BackAnimation: Boolean=false): Boolean;
100 function g_Frames_CreateWAD (ID: PDWORD; const Name, Resource: AnsiString; mWidth, mHeight, mCount: Word; BackAnimation: Boolean=false): Boolean;
101 function g_Frames_CreateFile (ID: PDWORD; const Name, FileName: AnsiString; mWidth, mHeight, mCount: Word; BackAnimation: Boolean=false): Boolean;
102 function g_Frames_CreateMemory (ID: PDWORD; const Name: AnsiString; pData: Pointer; dataSize: LongInt;
103 mWidth, mHeight, mCount: Word; BackAnimation: Boolean=false): Boolean;
104 function g_Frames_Dup (const NewName, OldName: AnsiString): Boolean;
105 //function g_Frames_CreateRevert(ID: PDWORD; Name: ShortString; Frames: string): Boolean;
106 function g_Frames_Get (out ID: LongWord; const FramesName: AnsiString): Boolean;
107 function g_Frames_GetTexture (out ID: LongWord; const FramesName: AnsiString; Frame: Word): Boolean;
108 function g_Frames_Exists (const FramesName: AnsiString): Boolean;
109 procedure g_Frames_DeleteByName (const FramesName: AnsiString);
110 procedure g_Frames_DeleteByID (ID: LongWord);
111 procedure g_Frames_DeleteAll ();
113 procedure DumpTextureNames ();
115 function g_Texture_Light (): Integer;
118 implementation
120 uses
121 {$INCLUDE ../nogl/noGLuses.inc}
122 g_game, e_log, g_basic, g_console, wadreader,
123 g_language, utils, xstreams;
125 type
126 _TTexture = record
127 name: AnsiString;
128 id: LongWord;
129 width, height: Word;
130 used: Boolean;
131 end;
133 TFrames = record
134 texturesID: array of LongWord;
135 name: AnsiString;
136 frameWidth, frameHeight: Word;
137 used: Boolean;
138 end;
140 var
141 texturesArray: array of _TTexture = nil;
142 framesArray: array of TFrames = nil;
145 const
146 ANIM_SIGNATURE = $4D494E41; // 'ANIM'
149 function allocTextureSlot (): LongWord;
150 var
151 f: integer;
152 begin
153 for f := 0 to High(texturesArray) do
154 begin
155 if (not texturesArray[f].used) then
156 begin
157 result := f;
158 exit;
159 end;
160 end;
162 result := Length(texturesArray);
163 SetLength(texturesArray, result+64);
164 for f := result to High(texturesArray) do
165 begin
166 with texturesArray[f] do
167 begin
168 name := '';
169 id := 0;
170 width := 0;
171 height := 0;
172 used := false;
173 end;
174 end;
175 end;
178 function allocFrameSlot (): LongWord;
179 var
180 f: integer;
181 begin
182 for f := 0 to High(framesArray) do
183 begin
184 if (not framesArray[f].used) then
185 begin
186 result := f;
187 exit;
188 end;
189 end;
191 result := Length(framesArray);
192 SetLength(framesArray, result+64);
193 for f := result to High(framesArray) do
194 begin
195 with framesArray[f] do
196 begin
197 texturesID := nil;
198 name := '';
199 frameWidth := 0;
200 frameHeight := 0;
201 used := false;
202 end;
203 end;
204 end;
207 // ////////////////////////////////////////////////////////////////////////// //
208 function g_Texture_CreateWAD (var ID: LongWord; const Resource: AnsiString): Boolean;
209 var
210 WAD: TWADFile;
211 FileName: AnsiString;
212 TextureData: Pointer;
213 ResourceLength: Integer;
214 begin
215 result := false;
216 FileName := g_ExtractWadName(Resource);
218 WAD := TWADFile.Create;
219 WAD.ReadFile(FileName);
221 if WAD.GetResource(g_ExtractFilePathName(Resource), TextureData, ResourceLength) then
222 begin
223 if e_CreateTextureMem(TextureData, ResourceLength, ID) then
224 result := true;
225 FreeMem(TextureData)
226 end
227 else
228 begin
229 e_WriteLog(Format('Error loading texture %s', [Resource]), TMsgType.Warning);
230 //e_WriteLog(Format('WAD Reader error: %s', [WAD.GetLastErrorStr]), MSG_WARNING);
231 end;
232 WAD.Free();
233 end;
236 function g_Texture_CreateFile (var ID: LongWord; const FileName: AnsiString): Boolean;
237 begin
238 result := true;
239 if not e_CreateTexture(FileName, ID) then
240 begin
241 e_WriteLog(Format('Error loading texture %s', [FileName]), TMsgType.Warning);
242 result := false;
243 end;
244 end;
247 function g_Texture_CreateWADEx (const textureName, Resource: AnsiString): Boolean;
248 var
249 WAD: TWADFile;
250 FileName: AnsiString;
251 TextureData: Pointer;
252 find_id: LongWord;
253 ResourceLength: Integer;
254 begin
255 FileName := g_ExtractWadName(Resource);
257 find_id := allocTextureSlot();
259 WAD := TWADFile.Create;
260 WAD.ReadFile(FileName);
262 if WAD.GetResource(g_ExtractFilePathName(Resource), TextureData, ResourceLength) then
263 begin
264 result := e_CreateTextureMem(TextureData, ResourceLength, texturesArray[find_id].ID);
265 if result then
266 begin
267 e_GetTextureSize(texturesArray[find_id].ID, @texturesArray[find_id].width, @texturesArray[find_id].height);
268 texturesArray[find_id].used := true;
269 texturesArray[find_id].Name := textureName;
270 end;
271 FreeMem(TextureData)
272 end
273 else
274 begin
275 e_WriteLog(Format('Error loading texture %s', [Resource]), TMsgType.Warning);
276 //e_WriteLog(Format('WAD Reader error: %s', [WAD.GetLastErrorStr]), MSG_WARNING);
277 result := false;
278 end;
279 WAD.Free();
280 end;
283 function g_Texture_CreateFileEx (const textureName, FileName: AnsiString): Boolean;
284 var
285 find_id: LongWord;
286 begin
287 find_id := allocTextureSlot();
288 result := e_CreateTexture(FileName, texturesArray[find_id].ID);
289 if result then
290 begin
291 texturesArray[find_id].used := true;
292 texturesArray[find_id].Name := textureName;
293 e_GetTextureSize(texturesArray[find_id].ID, @texturesArray[find_id].width, @texturesArray[find_id].height);
294 end
295 else e_WriteLog(Format('Error loading texture %s', [FileName]), TMsgType.Warning);
296 end;
299 function g_Texture_Get (const textureName: AnsiString; var id: LongWord): Boolean;
300 var
301 a: Integer;
302 begin
303 result := false;
304 if (Length(texturesArray) = 0) or (Length(textureName) = 0) then exit;
305 for a := 0 to High(texturesArray) do
306 begin
307 if (StrEquCI1251(texturesArray[a].name, textureName)) then
308 begin
309 id := texturesArray[a].id;
310 result := true;
311 break;
312 end;
313 end;
314 //if not Result then g_ConsoleAdd('Texture '+TextureName+' not found');
315 end;
318 function g_Texture_GetSize (const textureName: AnsiString; var w, h: Integer): Boolean; overload;
319 var
320 a: Integer;
321 begin
322 result := false;
323 w := 0;
324 h := 0;
325 if (Length(texturesArray) = 0) or (Length(textureName) = 0) then exit;
326 for a := 0 to High(texturesArray) do
327 begin
328 if (StrEquCI1251(texturesArray[a].name, textureName)) then
329 begin
330 w := texturesArray[a].width;
331 h := texturesArray[a].height;
332 result := true;
333 break;
334 end;
335 end;
336 end;
339 function g_Texture_GetSize (ID: LongWord; var w, h: Integer): Boolean; overload;
340 var
341 a: Integer;
342 begin
343 result := false;
344 w := 0;
345 h := 0;
346 if (Length(texturesArray) = 0) then exit;
347 for a := 0 to High(texturesArray) do
348 begin
349 if (texturesArray[a].id = ID) then
350 begin
351 w := texturesArray[a].width;
352 h := texturesArray[a].height;
353 result := true;
354 break;
355 end;
356 end;
357 end;
360 procedure g_Texture_Delete (const textureName: AnsiString);
361 var
362 a: Integer;
363 begin
364 if (Length(texturesArray) = 0) or (Length(textureName) = 0) then exit;
365 for a := 0 to High(texturesArray) do
366 begin
367 if (StrEquCI1251(texturesArray[a].name, textureName)) then
368 begin
369 e_DeleteTexture(texturesArray[a].ID);
370 texturesArray[a].used := false;
371 texturesArray[a].name := '';
372 texturesArray[a].id := 0;
373 texturesArray[a].width := 0;
374 texturesArray[a].height := 0;
375 end;
376 end;
377 end;
380 procedure g_Texture_DeleteAll ();
381 var
382 a: Integer;
383 begin
384 for a := 0 to High(texturesArray) do
385 begin
386 if (texturesArray[a].used) then e_DeleteTexture(texturesArray[a].ID);
387 end;
388 texturesArray := nil;
389 end;
392 function g_Frames_CreateFile (ID: PDWORD; const Name, FileName: AnsiString;
393 mWidth, mHeight, mCount: Word; BackAnimation: Boolean = false): Boolean;
394 var
395 a: Integer;
396 find_id: LongWord;
397 begin
398 result := false;
400 find_id := allocFrameSlot();
402 if (mCount <= 2) then BackAnimation := false;
404 if BackAnimation then SetLength(framesArray[find_id].TexturesID, mCount+mCount-2)
405 else SetLength(framesArray[find_id].TexturesID, mCount);
407 for a := 0 to mCount-1 do
408 begin
409 if not e_CreateTextureEx(FileName, framesArray[find_id].TexturesID[a], a*mWidth, 0, mWidth, mHeight) then exit;
410 end;
412 if BackAnimation then
413 begin
414 for a := 1 to mCount-2 do framesArray[find_id].TexturesID[mCount+mCount-2-a] := framesArray[find_id].TexturesID[a];
415 end;
417 framesArray[find_id].used := true;
418 framesArray[find_id].FrameWidth := mWidth;
419 framesArray[find_id].FrameHeight := mHeight;
420 if (Name <> '') then framesArray[find_id].Name := Name else framesArray[find_id].Name := '<noname>';
422 if (ID <> nil) then ID^ := find_id;
424 result := true;
425 end;
428 function CreateFramesMem (pData: Pointer; dataSize: LongInt; ID: PDWORD; Name: AnsiString;
429 mWidth, mHeight, mCount: Word; BackAnimation: Boolean = false): Boolean;
430 var
431 find_id: LongWord;
432 a: Integer;
433 begin
434 result := false;
436 find_id := allocFrameSlot();
438 if (mCount <= 2) then BackAnimation := false;
440 if BackAnimation then SetLength(framesArray[find_id].TexturesID, mCount+mCount-2)
441 else SetLength(framesArray[find_id].TexturesID, mCount);
443 for a := 0 to mCount-1 do
444 if not e_CreateTextureMemEx(pData, dataSize, framesArray[find_id].TexturesID[a], a*mWidth, 0, mWidth, mHeight) then
445 begin
446 //!!!FreeMem(pData);
447 exit;
448 end;
450 if BackAnimation then
451 begin
452 for a := 1 to mCount-2 do framesArray[find_id].TexturesID[mCount+mCount-2-a] := framesArray[find_id].TexturesID[a];
453 end;
455 framesArray[find_id].used := true;
456 framesArray[find_id].FrameWidth := mWidth;
457 framesArray[find_id].FrameHeight := mHeight;
458 if (Name <> '') then framesArray[find_id].Name := Name else framesArray[find_id].Name := '<noname>';
460 if (ID <> nil) then ID^ := find_id;
462 result := true;
463 end;
466 function g_CreateFramesImg (ia: TDynImageDataArray; ID: PDWORD; const Name: AnsiString; BackAnimation: Boolean = false): Boolean;
467 var
468 find_id: LongWord;
469 a, mCount: Integer;
470 begin
471 result := false;
472 find_id := allocFrameSlot();
474 mCount := Length(ia);
476 //e_WriteLog(Format('+++ creating %d frames [%s]', [FCount, Name]), MSG_NOTIFY);
478 if (mCount < 1) then exit;
479 if (mCount <= 2) then BackAnimation := false;
481 if BackAnimation then SetLength(framesArray[find_id].TexturesID, mCount+mCount-2)
482 else SetLength(framesArray[find_id].TexturesID, mCount);
484 //e_WriteLog(Format('+++ creating %d frames, %dx%d', [FCount, ia[0].width, ia[0].height]), MSG_NOTIFY);
486 for a := 0 to mCount-1 do
487 begin
488 if not e_CreateTextureImg(ia[a], framesArray[find_id].TexturesID[a]) then exit;
489 //e_WriteLog(Format('+++ frame %d, %dx%d', [a, ia[a].width, ia[a].height]), MSG_NOTIFY);
490 end;
492 if BackAnimation then
493 begin
494 for a := 1 to mCount-2 do framesArray[find_id].TexturesID[mCount+mCount-2-a] := framesArray[find_id].TexturesID[a];
495 end;
497 framesArray[find_id].used := true;
498 framesArray[find_id].FrameWidth := ia[0].width;
499 framesArray[find_id].FrameHeight := ia[0].height;
500 if (Name <> '') then framesArray[find_id].Name := Name else framesArray[find_id].Name := '<noname>';
502 if (ID <> nil) then ID^ := find_id;
504 result := true;
505 end;
508 function g_Frames_CreateWAD (ID: PDWORD; const Name, Resource: AnsiString;
509 mWidth, mHeight, mCount: Word; BackAnimation: Boolean=false): Boolean;
510 var
511 WAD: TWADFile;
512 FileName: AnsiString;
513 TextureData: Pointer;
514 ResourceLength: Integer;
515 begin
516 result := false;
518 // models without "advanced" animations asks for "nothing" like this; don't spam log
519 if (Length(Resource) > 0) and ((Resource[Length(Resource)] = '/') or (Resource[Length(Resource)] = '\')) then exit;
521 FileName := g_ExtractWadName(Resource);
523 WAD := TWADFile.Create();
524 WAD.ReadFile(FileName);
526 if not WAD.GetResource(g_ExtractFilePathName(Resource), TextureData, ResourceLength) then
527 begin
528 WAD.Free();
529 e_WriteLog(Format('Error loading texture %s', [Resource]), TMsgType.Warning);
530 //e_WriteLog(Format('WAD Reader error: %s', [WAD.GetLastErrorStr]), MSG_WARNING);
531 exit;
532 end;
534 if not CreateFramesMem(TextureData, ResourceLength, ID, Name, mWidth, mHeight, mCount, BackAnimation) then
535 begin
536 FreeMem(TextureData);
537 WAD.Free();
538 exit;
539 end;
541 FreeMem(TextureData);
542 WAD.Free();
544 result := true;
545 end;
548 function g_Frames_CreateMemory (ID: PDWORD; const Name: AnsiString; pData: Pointer; dataSize: LongInt;
549 mWidth, mHeight, mCount: Word; BackAnimation: Boolean = false): Boolean;
550 begin
551 result := CreateFramesMem(pData, dataSize, ID, Name, mWidth, mHeight, mCount, BackAnimation);
552 end;
555 {function g_Frames_CreateRevert(ID: PDWORD; Name: ShortString; Frames: string): Boolean;
556 var
557 find_id, b: DWORD;
558 a, c: Integer;
559 begin
560 Result := False;
562 if not g_Frames_Get(b, Frames) then Exit;
564 find_id := FindFrame();
566 FramesArray[find_id].Name := Name;
567 FramesArray[find_id].FrameWidth := FramesArray[b].FrameWidth;
568 FramesArray[find_id].FrameHeight := FramesArray[b].FrameHeight;
570 c := High(FramesArray[find_id].TexturesID);
572 for a := 0 to c do
573 FramesArray[find_id].TexturesID[a] := FramesArray[b].TexturesID[c-a];
575 Result := True;
576 end;}
579 function g_Frames_Dup (const NewName, OldName: AnsiString): Boolean;
580 var
581 find_id, b: LongWord;
582 a, c: Integer;
583 begin
584 result := false;
586 if not g_Frames_Get(b, OldName) then exit;
588 find_id := allocFrameSlot();
590 framesArray[find_id].used := true;
591 framesArray[find_id].Name := NewName;
592 framesArray[find_id].FrameWidth := framesArray[b].FrameWidth;
593 framesArray[find_id].FrameHeight := framesArray[b].FrameHeight;
595 c := High(framesArray[b].TexturesID);
596 SetLength(framesArray[find_id].TexturesID, c+1);
598 for a := 0 to c do framesArray[find_id].TexturesID[a] := framesArray[b].TexturesID[a];
600 result := true;
601 end;
604 procedure g_Frames_DeleteByName (const FramesName: AnsiString);
605 var
606 a, b: Integer;
607 begin
608 if (Length(framesArray) = 0) then exit;
609 for a := 0 to High(framesArray) do
610 begin
611 if (StrEquCI1251(framesArray[a].Name, FramesName)) then
612 begin
613 if framesArray[a].TexturesID <> nil then
614 begin
615 for b := 0 to High(framesArray[a].TexturesID) do e_DeleteTexture(framesArray[a].TexturesID[b]);
616 end;
617 framesArray[a].used := false;
618 framesArray[a].TexturesID := nil;
619 framesArray[a].Name := '';
620 framesArray[a].FrameWidth := 0;
621 framesArray[a].FrameHeight := 0;
622 end;
623 end;
624 end;
627 procedure g_Frames_DeleteByID (ID: LongWord);
628 var
629 b: Integer;
630 begin
631 if (Length(framesArray) = 0) then exit;
632 if (framesArray[ID].TexturesID <> nil) then
633 begin
634 for b := 0 to High(framesArray[ID].TexturesID) do e_DeleteTexture(framesArray[ID].TexturesID[b]);
635 end;
636 framesArray[ID].used := false;
637 framesArray[ID].TexturesID := nil;
638 framesArray[ID].Name := '';
639 framesArray[ID].FrameWidth := 0;
640 framesArray[ID].FrameHeight := 0;
641 end;
644 procedure g_Frames_DeleteAll ();
645 var
646 a, b: Integer;
647 begin
648 for a := 0 to High(framesArray) do
649 begin
650 if (framesArray[a].used) then
651 begin
652 for b := 0 to High(framesArray[a].TexturesID) do e_DeleteTexture(framesArray[a].TexturesID[b]);
653 end;
654 framesArray[a].used := false;
655 framesArray[a].TexturesID := nil;
656 framesArray[a].Name := '';
657 framesArray[a].FrameWidth := 0;
658 framesArray[a].FrameHeight := 0;
659 end;
660 framesArray := nil;
661 end;
664 function g_Frames_Get (out ID: LongWord; const FramesName: AnsiString): Boolean;
665 var
666 a: Integer;
667 begin
668 result := false;
669 if (Length(framesArray) = 0) then exit;
670 for a := 0 to High(framesArray) do
671 begin
672 if (StrEquCI1251(framesArray[a].Name, FramesName)) then
673 begin
674 ID := a;
675 result := true;
676 break;
677 end;
678 end;
679 if not result then g_FatalError(Format(_lc[I_GAME_ERROR_FRAMES], [FramesName]));
680 end;
683 function g_Frames_GetTexture (out ID: LongWord; const FramesName: AnsiString; Frame: Word): Boolean;
684 var
685 a: Integer;
686 begin
687 result := false;
688 if (Length(framesArray) = 0) then exit;
689 for a := 0 to High(framesArray) do
690 begin
691 if (StrEquCI1251(framesArray[a].Name, FramesName)) then
692 begin
693 if (Frame < Length(framesArray[a].TexturesID)) then
694 begin
695 ID := framesArray[a].TexturesID[Frame];
696 result := true;
697 break;
698 end;
699 end;
700 end;
701 if not result then g_FatalError(Format(_lc[I_GAME_ERROR_FRAMES], [FramesName]));
702 end;
705 function g_Frames_Exists (const FramesName: AnsiString): Boolean;
706 var
707 a: Integer;
708 begin
709 result := false;
710 if (Length(framesArray) = 0) then exit;
711 for a := 0 to High(framesArray) do
712 begin
713 if (StrEquCI1251(framesArray[a].Name, FramesName)) then
714 begin
715 result := true;
716 exit;
717 end;
718 end;
719 end;
722 procedure DumpTextureNames ();
723 var
724 i: Integer;
725 begin
726 e_WriteLog('BEGIN Textures:', TMsgType.Notify);
727 for i := 0 to High(texturesArray) do e_WriteLog(' '+IntToStr(i)+'. '+texturesArray[i].Name, TMsgType.Notify);
728 e_WriteLog('END Textures.', TMsgType.Notify);
730 e_WriteLog('BEGIN Frames:', TMsgType.Notify);
731 for i := 0 to High(framesArray) do e_WriteLog(' '+IntToStr(i)+'. '+framesArray[i].Name, TMsgType.Notify);
732 e_WriteLog('END Frames.', TMsgType.Notify);
733 end;
736 { TAnimation }
738 constructor TAnimation.Create (aframesID: LongWord; aloop: Boolean; aspeed: Byte);
739 begin
740 if (aframesID >= Length(framesArray)) then raise Exception.Create('trying to create inexisting frame: something is very wrong here');
741 mId := aframesID;
742 mMinLength := 0;
743 mLoop := aloop;
744 mSpeed := aspeed;
745 mEnabled := true;
746 mCurrentFrame := 0;
747 mPlayed := false;
748 mAlpha := 0;
749 mWidth := framesArray[mId].FrameWidth;
750 mHeight := framesArray[mId].FrameHeight;
751 end;
754 destructor TAnimation.Destroy ();
755 begin
756 inherited;
757 end;
760 procedure TAnimation.draw (x, y: Integer; mirror: TMirrorType);
761 begin
762 if (not mEnabled) then exit;
763 e_DrawAdv(framesArray[mId].TexturesID[mCurrentFrame], x, y, mAlpha, true, mBlending, 0, nil, mirror);
764 //e_DrawQuad(X, Y, X+FramesArray[ID].FrameWidth-1, Y+FramesArray[ID].FrameHeight-1, 0, 255, 0);
765 end;
768 procedure TAnimation.update ();
769 begin
770 if (not mEnabled) then exit;
772 mCounter += 1;
774 if (mCounter >= mSpeed) then
775 begin
776 // Îæèäàíèå ìåæäó êàäðàìè çàêîí÷èëîñü
777 // Îáðàòíûé ïîðÿäîê êàäðîâ?
778 if mRevert then
779 begin
780 // Äîøëè äî êîíöà àíèìàöèè. Âîçìîæíî, æäåì åùå
781 if (mCurrentFrame = 0) then
782 begin
783 if (Length(framesArray[mId].TexturesID)*mSpeed+mCounter < mMinLength) then exit;
784 end;
786 mCurrentFrame -= 1;
787 mPlayed := (mCurrentFrame < 0);
789 // Ïîâòîðÿòü ëè àíèìàöèþ ïî êðóãó?
790 if mPlayed then
791 begin
792 if mLoop then mCurrentFrame := High(framesArray[mId].TexturesID) else mCurrentFrame += 1;
793 end;
795 mCounter := 0;
796 end
797 else
798 begin
799 // Ïðÿìîé ïîðÿäîê êàäðîâ
800 // Äîøëè äî êîíöà àíèìàöèè. Âîçìîæíî, æäåì åùå
801 if (mCurrentFrame = High(framesArray[mId].TexturesID)) then
802 begin
803 if (Length(framesArray[mId].TexturesID)*mSpeed+mCounter < mMinLength) then exit;
804 end;
806 mCurrentFrame += 1;
807 mPlayed := (mCurrentFrame > High(framesArray[mId].TexturesID));
809 // Ïîâòîðÿòü ëè àíèìàöèþ ïî êðóãó?
810 if mPlayed then
811 begin
812 if mLoop then mCurrentFrame := 0 else mCurrentFrame -= 1;
813 end;
815 mCounter := 0;
816 end;
817 end;
818 end;
821 procedure TAnimation.reset ();
822 begin
823 if mRevert then mCurrentFrame := High(framesArray[mId].TexturesID) else mCurrentFrame := 0;
824 mCounter := 0;
825 mPlayed := false;
826 end;
829 procedure TAnimation.disable (); begin mEnabled := false; end;
830 procedure TAnimation.enable (); begin mEnabled := true; end;
833 procedure TAnimation.drawEx (x, y: Integer; mirror: TMirrorType; rpoint: TDFPoint; angle: SmallInt);
834 begin
835 if (not mEnabled) then exit;
836 e_DrawAdv(framesArray[mId].TexturesID[mCurrentFrame], x, y, mAlpha, true, mBlending, angle, @rpoint, mirror);
837 end;
840 function TAnimation.totalFrames (): Integer; inline; begin result := Length(framesArray[mId].TexturesID); end;
843 procedure TAnimation.revert (r: Boolean);
844 begin
845 mRevert := r;
846 reset();
847 end;
850 procedure TAnimation.saveState (st: TStream);
851 begin
852 if (st = nil) then exit;
854 utils.writeSign(st, 'ANIM');
855 utils.writeInt(st, Byte(0)); // version
856 // Ñ÷åò÷èê îæèäàíèÿ ìåæäó êàäðàìè
857 utils.writeInt(st, Byte(mCounter));
858 // Òåêóùèé êàäð
859 utils.writeInt(st, LongInt(mCurrentFrame));
860 // Ïðîèãðàíà ëè àíèìàöèÿ öåëèêîì
861 utils.writeBool(st, mPlayed);
862 // Alpha-êàíàë âñåé òåêñòóðû
863 utils.writeInt(st, Byte(mAlpha));
864 // Ðàçìûòèå òåêñòóðû
865 utils.writeInt(st, Byte(mBlending));
866 // Âðåìÿ îæèäàíèÿ ìåæäó êàäðàìè
867 utils.writeInt(st, Byte(mSpeed));
868 // Çàöèêëåíà ëè àíèìàöèÿ
869 utils.writeBool(st, mLoop);
870 // Âêëþ÷åíà ëè
871 utils.writeBool(st, mEnabled);
872 // Îæèäàíèå ïîñëå ïðîèãðûâàíèÿ
873 utils.writeInt(st, Byte(mMinLength));
874 // Îáðàòíûé ëè ïîðÿäîê êàäðîâ
875 utils.writeBool(st, mRevert);
876 end;
879 procedure TAnimation.loadState (st: TStream);
880 begin
881 if (st = nil) then exit;
883 if not utils.checkSign(st, 'ANIM') then raise XStreamError.Create('animation chunk expected');
884 if (utils.readByte(st) <> 0) then raise XStreamError.Create('invalid animation chunk version');
885 // Ñ÷åò÷èê îæèäàíèÿ ìåæäó êàäðàìè
886 mCounter := utils.readByte(st);
887 // Òåêóùèé êàäð
888 mCurrentFrame := utils.readLongInt(st);
889 // Ïðîèãðàíà ëè àíèìàöèÿ öåëèêîì
890 mPlayed := utils.readBool(st);
891 // Alpha-êàíàë âñåé òåêñòóðû
892 mAlpha := utils.readByte(st);
893 // Ðàçìûòèå òåêñòóðû
894 mBlending := utils.readBool(st);
895 // Âðåìÿ îæèäàíèÿ ìåæäó êàäðàìè
896 mSpeed := utils.readByte(st);
897 // Çàöèêëåíà ëè àíèìàöèÿ
898 mLoop := utils.readBool(st);
899 // Âêëþ÷åíà ëè
900 mEnabled := utils.readBool(st);
901 // Îæèäàíèå ïîñëå ïðîèãðûâàíèÿ
902 mMinLength := utils.readByte(st);
903 // Îáðàòíûé ëè ïîðÿäîê êàäðîâ
904 mRevert := utils.readBool(st);
905 end;
908 // ////////////////////////////////////////////////////////////////////////// //
909 var
910 ltexid: GLuint = 0;
912 function g_Texture_Light (): Integer;
913 const
914 Radius: Integer = 128;
915 var
916 tex, tpp: PByte;
917 x, y, a: Integer;
918 dist: Double;
919 begin
920 if ltexid = 0 then
921 begin
922 GetMem(tex, (Radius*2)*(Radius*2)*4);
923 tpp := tex;
924 for y := 0 to Radius*2-1 do
925 begin
926 for x := 0 to Radius*2-1 do
927 begin
928 dist := 1.0-sqrt((x-Radius)*(x-Radius)+(y-Radius)*(y-Radius))/Radius;
929 if (dist < 0) then
930 begin
931 tpp^ := 0; Inc(tpp);
932 tpp^ := 0; Inc(tpp);
933 tpp^ := 0; Inc(tpp);
934 tpp^ := 0; Inc(tpp);
935 end
936 else
937 begin
938 //tc.setPixel(x, y, Color(cast(int)(dist*255), cast(int)(dist*255), cast(int)(dist*255)));
939 if (dist > 0.5) then dist := 0.5;
940 a := round(dist*255);
941 if (a < 0) then a := 0 else if (a > 255) then a := 255;
942 tpp^ := 255; Inc(tpp);
943 tpp^ := 255; Inc(tpp);
944 tpp^ := 255; Inc(tpp);
945 tpp^ := Byte(a); Inc(tpp);
946 end;
947 end;
948 end;
950 glGenTextures(1, @ltexid);
951 //if (tid == 0) assert(0, "VGL: can't create screen texture");
953 glBindTexture(GL_TEXTURE_2D, ltexid);
954 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
955 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
956 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
957 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
959 //GLfloat[4] bclr = 0.0;
960 //glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, bclr.ptr);
962 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Radius*2, Radius*2, 0, GL_RGBA{gltt}, GL_UNSIGNED_BYTE, tex);
963 end;
965 result := ltexid;
966 end;
969 end.