062f76bdcebe373f1ecc231c88ba127b7724d476
1 (* Copyright (C) Doom 2D: Forever Developers
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.
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.
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/>.
15 {$INCLUDE ../../../shared/a_modes.inc}
26 g_base
, g_animations
, // TRectHW, TAnimInfo
34 TGLAtlasNode
= class (TAtlasNode
)
39 constructor Create (base
: TGLAtlas
);
40 destructor Destroy
; override;
42 function GetID (): GLuint
;
44 property base
: TGLAtlas read mBase
;
45 property id
: GLuint read GetID
;
48 TGLAtlas
= class (TAtlas
)
53 constructor Create (ww
, hh
: Integer; id
: GLuint
);
54 destructor Destroy
; override;
56 function CreateNode (): TGLAtlasNode
; override;
57 function Alloc (ww
, hh
: Integer): TGLAtlasNode
; overload
;
59 property id
: GLuint read mID write mID default
0;
67 mTile
: array of TGLAtlasNode
;
70 destructor Destroy
; override;
72 function GetTile (col
, line
: Integer): TGLAtlasNode
;
74 function GetLines (): Integer; inline;
76 property width
: Integer read mWidth
;
77 property height
: Integer read mHeight
;
78 property cols
: Integer read mCols
;
79 property lines
: Integer read GetLines
;
82 TGLMultiTexture
= class
84 mTexture
: array of TGLTexture
;
88 destructor Destroy
; override;
90 function GetWidth (): Integer; inline;
91 function GetHeight (): Integer; inline;
92 function GetCount (): Integer; inline;
93 function GetTexture (i
: Integer): TGLTexture
; {inline;}
95 property width
: Integer read GetWidth
;
96 property height
: Integer read GetHeight
;
97 property count
: Integer read GetCount
;
98 property backAnim
: Boolean read mBackanim
; (* this property must be located at TAnimState? *)
101 TGLTextureArray
= array of TGLTexture
;
103 TRectArray
= array of TRectWH
;
105 TGLFont
= class sealed (TFont
)
111 destructor Destroy
; override;
112 function GetChar (c
: AnsiChar): TGLTexture
;
113 function GetWidth (c
: AnsiChar): Integer;
114 function GetMaxWidth (): Integer;
115 function GetMaxHeight (): Integer;
116 function GetSpace (): Integer;
119 TAnimTextInfo
= record
125 procedure r_Textures_Initialize
;
126 procedure r_Textures_Finalize
;
128 function r_Textures_LoadFromFile (const filename
: AnsiString; log
: Boolean = True): TGLTexture
;
129 function r_Textures_LoadMultiFromFile (const filename
: AnsiString; log
: Boolean = True): TGLMultiTexture
;
130 function r_Textures_LoadMultiFromFileAndInfo (const filename
: AnsiString; w
, h
, count
: Integer; backanim
: Boolean; log
: Boolean = True): TGLMultiTexture
;
131 function r_Textures_LoadMultiTextFromFile (const filename
: AnsiString; var txt
: TAnimTextInfo
; log
: Boolean = True): TGLMultiTexture
;
133 function r_Textures_LoadStreamFromFile (const filename
: AnsiString; w
, h
, count
, cw
: Integer; st
: TGLTextureArray
; rs
: TRectArray
; log
: Boolean = True): Boolean;
135 function r_Textures_LoadFontFromFile (const filename
: AnsiString; constref f
: TFontInfo
; skipch
: Integer; log
: Boolean = true): TGLFont
;
141 e_log
, e_res
, WADReader
, Config
,
142 Imaging
, ImagingTypes
, ImagingUtility
146 maxTileSize
: Integer;
147 atl
: array of TGLAtlas
;
149 (* --------- TGLAtlasNode --------- *)
151 constructor TGLAtlasNode
.Create (base
: TGLAtlas
);
158 destructor TGLAtlasNode
.Destroy
;
163 function TGLAtlasNode
.GetID (): GLuint
;
165 result
:= self
.base
.id
168 procedure r_Textures_UpdateNode (n
: TGLAtlasNode
; data
: Pointer; x
, y
, w
, h
: Integer);
172 ASSERT(n
.base
<> nil);
176 ASSERT(n
.l
+ x
+ w
- 1 <= n
.r
);
177 ASSERT(n
.t
+ y
+ h
- 1 <= n
.b
);
179 glBindTexture(GL_TEXTURE_2D
, n
.id
);
180 glTexSubImage2D(GL_TEXTURE_2D
, 0, n
.l
+ x
, n
.t
+ y
, w
, h
, GL_RGBA
, GL_UNSIGNED_BYTE
, data
);
181 glBindTexture(GL_TEXTURE_2D
, 0);
184 (* --------- TGLAtlas --------- *)
186 constructor TGLAtlas
.Create (ww
, hh
: Integer; id
: GLuint
);
190 inherited Create(ww
, hh
);
194 destructor TGLAtlas
.Destroy
;
199 function TGLAtlas
.CreateNode (): TGLAtlasNode
;
201 result
:= TGLAtlasNode
.Create(self
);
204 function TGLAtlas
.Alloc (ww
, hh
: Integer): TGLAtlasNode
;
206 result
:= TGLAtlasNode(inherited Alloc(ww
, hh
));
209 function r_Textures_AllocHWTexture (w
, h
: Integer): GLuint
;
212 glGenTextures(1, @id
);
215 glBindTexture(GL_TEXTURE_2D
, id
);
216 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
217 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
218 glTexImage2D(GL_TEXTURE_2D
, 0, GL_RGBA
, w
, h
, 0, GL_RGBA
, GL_UNSIGNED_BYTE
, nil);
219 glBindTexture(GL_TEXTURE_2D
, 0);
224 function r_Textures_AllocAtlas (): TGLAtlas
;
225 var i
: Integer; id
: GLuint
;
228 id
:= r_Textures_AllocHWTexture(maxTileSize
, maxTileSize
);
232 SetLength(atl
, i
+ 1);
233 atl
[i
] := TGLAtlas
.Create(maxTileSize
, maxTileSize
, id
);
238 function r_Textures_AllocNode (w
, h
: Integer): TGLAtlasNode
;
239 var i
: Integer; n
: TGLAtlasNode
; a
: TGLAtlas
;
245 while (i
>= 0) and (n
= nil) do
247 n
:= atl
[i
].Alloc(w
, h
);
253 a
:= r_Textures_AllocAtlas();
260 (* --------- TGLTexture --------- *)
262 destructor TGLTexture
.Destroy
;
265 if self
.mTile
<> nil then
267 for i
:= 0 to High(self
.mTile
) do
269 if self
.mTile
[i
] <> nil then
271 self
.mTile
[i
].Dealloc
;
272 self
.mTile
[i
] := nil;
280 function TGLTexture
.GetLines (): Integer;
282 ASSERT(self
.mTile
<> nil);
283 result
:= Length(self
.mTile
) div self
.mCols
286 function TGLTexture
.GetTile (col
, line
: Integer): TGLAtlasNode
;
290 ASSERT(col
<= mCols
);
291 ASSERT(self
.mTile
<> nil);
292 i
:= line
* mCols
+ col
;
294 ASSERT(i
< Length(mTile
));
296 ASSERT(result
<> nil)
299 function r_Textures_Alloc (w
, h
: Integer): TGLTexture
;
300 var x
, y
, mw
, mh
, cols
, lines
: Integer; t
: TGLTexture
;
304 cols
:= (w
+ maxTileSize
- 1) div maxTileSize
;
305 lines
:= (h
+ maxTileSize
- 1) div maxTileSize
;
306 t
:= TGLTexture
.Create
;
310 // t.mLines := lines;
311 SetLength(t
.mTile
, cols
* lines
);
312 for y
:= 0 to lines
- 1 do
314 mh
:= Min(maxTileSize
, h
- y
* maxTileSize
);
316 for x
:= 0 to cols
- 1 do
318 mw
:= Min(maxTileSize
, w
- x
* maxTileSize
);
320 t
.mTile
[y
* cols
+ x
] := r_Textures_AllocNode(mw
, mh
);
326 (* --------- TGLMultiTexture --------- *)
328 destructor TGLMultiTexture
.Destroy
;
331 for i
:= 0 to self
.count
- 1 do
332 self
.mTexture
[i
].Free
;
333 self
.mTexture
:= nil;
337 function TGLMultiTexture
.GetWidth (): Integer;
339 result
:= self
.mTexture
[0].width
342 function TGLMultiTexture
.GetHeight (): Integer;
344 result
:= self
.mTexture
[0].height
347 function TGLMultiTexture
.GetCount (): Integer;
349 result
:= Length(self
.mTexture
)
352 function TGLMultiTexture
.GetTexture (i
: Integer): TGLTexture
;
355 ASSERT(i
< self
.count
);
356 result
:= self
.mTexture
[i
];
357 ASSERT(result
<> nil);
360 (* --------- Init / Fin --------- *)
362 function r_Textures_GetMaxHardwareSize (): Integer;
365 glGetIntegerv(GL_MAX_TEXTURE_SIZE
, @size
);
366 if size
< 64 then size
:= 64;
367 //if size > 512 then size := 512;
372 procedure r_Textures_Initialize
;
374 maxTileSize
:= r_Textures_GetMaxHardwareSize();
377 procedure r_Textures_Finalize
;
382 for i
:= 0 to High(atl
) do
384 glDeleteTextures(1, @atl
[i
].id
);
392 function r_Textures_FixImageData (var img
: TImageData
): Boolean;
395 if ConvertImage(img
, TImageFormat
.ifA8R8G8B8
) then
396 if SwapChannels(img
, ChannelRed
, ChannelBlue
) then // wtf
400 function r_Textures_LoadFromImage (var img
: TImageData
): TGLTexture
;
401 var t
: TGLTexture
; n
: TGLAtlasNode
; c
: TDynImageDataArray
; cw
, ch
, i
, j
: LongInt;
404 if SplitImage(img
, c
, maxTileSize
, maxTileSize
, cw
, ch
, False) then
406 t
:= r_Textures_Alloc(img
.width
, img
.height
);
410 ASSERT(ch
= t
.lines
);
411 for j
:= 0 to ch
- 1 do
413 for i
:= 0 to cw
- 1 do
415 n
:= t
.GetTile(i
, j
);
417 r_Textures_UpdateNode(n
, c
[j
* cw
+ i
].bits
, 0, 0, n
.width
, n
.height
)
422 FreeImagesInArray(c
);
426 function r_Textures_LoadFromMemory (data
: Pointer; size
: LongInt): TGLTexture
;
430 if (data
<> nil) and (size
> 0) then
434 if LoadImageFromMemory(data
, size
, img
) then
435 if r_Textures_FixImageData(img
) then
436 result
:= r_Textures_LoadFromImage(img
)
443 function r_Textures_LoadFromFile (const filename
: AnsiString; log
: Boolean = True): TGLTexture
;
444 var wad
: TWADFile
; wadName
, resName
: AnsiString; data
: Pointer; size
: Integer;
447 wadName
:= g_ExtractWadName(filename
);
448 wad
:= TWADFile
.Create();
449 if wad
.ReadFile(wadName
) then
451 resName
:= g_ExtractFilePathName(filename
);
452 if wad
.GetResource(resName
, data
, size
, log
) then
454 result
:= r_Textures_LoadFromMemory(data
, size
);
461 function r_Textures_LoadMultiFromImageAndInfo (var img
: TImageData
; w
, h
, c
: Integer; b
: Boolean): TGLMultiTexture
;
462 var t
: TImageData
; a
: array of TGLTexture
; i
: Integer; m
: TGLMultiTexture
;
469 for i
:= 0 to c
- 1 do
472 if NewImage(w
, h
, img
.Format
, t
) then
473 if CopyRect(img
, w
* i
, 0, w
, h
, t
, 0, 0) then
474 a
[i
] := r_Textures_LoadFromImage(t
);
478 m
:= TGLMultiTexture
.Create();
481 ASSERT(m
.mTexture
<> nil);
485 function r_Textures_LoadMultiFromDataAndInfo (data
: Pointer; size
: LongInt; w
, h
, c
: Integer; b
: Boolean): TGLMultiTexture
;
492 if (data
<> nil) and (size
> 0) then
496 if LoadImageFromMemory(data
, size
, img
) then
497 if r_Textures_FixImageData(img
) then
498 result
:= r_Textures_LoadMultiFromImageAndInfo(img
, w
, h
, c
, b
)
505 function r_Textures_LoadTextFromMemory (data
: Pointer; size
: LongInt; var txt
: TAnimTextInfo
): Boolean;
511 cfg
:= TConfig
.CreateMem(data
, size
);
514 txt
.name
:= cfg
.ReadStr('', 'resource', '');
515 txt
.w
:= MAX(0, cfg
.ReadInt('', 'framewidth', 0));
516 txt
.h
:= MAX(0, cfg
.ReadInt('', 'frameheight', 0));
517 txt
.anim
.loop
:= true;
518 txt
.anim
.delay
:= MAX(0, cfg
.ReadInt('', 'waitcount', 0));
519 txt
.anim
.frames
:= MAX(0, cfg
.ReadInt('', 'framecount', 0));
520 txt
.anim
.back
:= cfg
.ReadBool('', 'backanim', false);
522 result
:= (txt
.name
<> '') and (txt
.w
> 0) and (txt
.h
> 0) and (txt
.anim
.delay
> 0) and (txt
.anim
.frames
> 0);
527 function r_Textures_LoadMultiFromWad (wad
: TWADFile
; var txt
: TAnimTextInfo
): TGLMultiTexture
;
528 var data
: Pointer; size
: LongInt; img
: TImageData
;
532 if wad
.GetResource('TEXT/ANIM', data
, size
) then
534 if r_Textures_LoadTextFromMemory(data
, size
, txt
) then
537 if wad
.GetResource('TEXTURES/' + txt
.name
, data
, size
) then
541 if LoadImageFromMemory(data
, size
, img
) then
542 if r_Textures_FixImageData(img
) then
543 result
:= r_Textures_LoadMultiFromImageAndInfo(img
, txt
.w
, txt
.h
, txt
.anim
.frames
, txt
.anim
.back
);
555 function r_Textures_LoadMultiFromMemory (data
: Pointer; size
: LongInt; var txt
: TAnimTextInfo
): TGLMultiTexture
;
556 var wad
: TWADFile
; t
: TGLTexture
; m
: TGLMultiTexture
;
559 if (data
<> nil) and (size
> 0) then
561 t
:= r_Textures_LoadFromMemory(data
, size
);
564 m
:= TGLMultiTexture
.Create();
565 SetLength(m
.mTexture
, 1);
567 m
.mBackanim
:= false;
571 txt
.anim
.loop
:= true;
573 txt
.anim
.frames
:= 1;
574 txt
.anim
.back
:= false;
577 else if IsWadData(data
, size
) then
579 wad
:= TWADFile
.Create();
580 if wad
.ReadMemory(data
, size
) then
582 result
:= r_Textures_LoadMultiFromWad(wad
, txt
);
589 function r_Textures_LoadMultiTextFromFile (const filename
: AnsiString; var txt
: TAnimTextInfo
; log
: Boolean = True): TGLMultiTexture
;
590 var wad
: TWADFile
; wadName
, resName
: AnsiString; data
: Pointer; size
: Integer;
593 wadName
:= g_ExtractWadName(filename
);
594 wad
:= TWADFile
.Create();
595 if wad
.ReadFile(wadName
) then
597 resName
:= g_ExtractFilePathName(filename
);
598 if wad
.GetResource(resName
, data
, size
, log
) then
600 result
:= r_Textures_LoadMultiFromMemory(data
, size
, txt
);
607 function r_Textures_LoadMultiFromFile (const filename
: AnsiString; log
: Boolean = True): TGLMultiTexture
;
608 var txt
: TAnimTextInfo
;
610 result
:= r_Textures_LoadMultiTextFromFile(filename
, txt
, log
);
613 function r_Textures_LoadMultiFromFileAndInfo (const filename
: AnsiString; w
, h
, count
: Integer; backanim
: Boolean; log
: Boolean = True): TGLMultiTexture
;
614 var wad
: TWADFile
; wadName
, resName
: AnsiString; data
: Pointer; size
: Integer;
620 wadName
:= g_ExtractWadName(filename
);
621 wad
:= TWADFile
.Create();
622 if wad
.ReadFile(wadName
) then
624 resName
:= g_ExtractFilePathName(filename
);
625 if wad
.GetResource(resName
, data
, size
, log
) then
627 result
:= r_Textures_LoadMultiFromDataAndInfo(data
, size
, w
, h
, count
, backanim
);
634 function r_Textures_GetRect (var img
: TImageData
): TRectWH
;
635 var i
, j
, w
, h
: Integer; done
: Boolean;
637 function IsVoid (i
, j
: Integer): Boolean; inline;
639 result
:= GetPixel32(img
, i
, j
).Channels
[3] = 0
646 (* trace x from right to left *)
647 done
:= false; i
:= 0;
648 while not done
and (i
< w
) do
651 while (j
< h
) and IsVoid(i
, j
) do inc(j
);
652 done
:= (j
< h
) and (IsVoid(i
, j
) = false);
657 (* trace y from up to down *)
658 done
:= false; j
:= 0;
659 while not done
and (j
< h
) do
662 while (i
< w
) and IsVoid(i
, j
) do inc(i
);
663 done
:= (i
< w
) and (IsVoid(i
, j
) = false);
668 (* trace x from right to left *)
669 done
:= false; i
:= w
- 1;
670 while not done
and (i
>= 0) do
673 while (j
< h
) and IsVoid(i
, j
) do inc(j
);
674 done
:= (j
< h
) and (IsVoid(i
, j
) = false);
675 result
.width
:= i
- result
.x
+ 1;
679 (* trace y from down to up *)
680 done
:= false; j
:= h
- 1;
681 while not done
and (j
>= 0) do
684 while (i
< w
) and IsVoid(i
, j
) do inc(i
);
685 done
:= (i
< w
) and (IsVoid(i
, j
) = false);
686 result
.height
:= j
- result
.y
+ 1;
691 function r_Textures_LoadStreamFromImage (var img
: TImageData
; w
, h
, c
, cw
: Integer; st
: TGLTextureArray
; rs
: TRectArray
): Boolean;
692 var i
, x
, y
: Integer; t
: TImageData
;
698 ASSERT((st
<> nil) and (Length(st
) >= c
));
699 ASSERT((rs
= nil) or (Length(rs
) >= c
));
701 for i
:= 0 to c
- 1 do
707 if NewImage(w
, h
, img
.Format
, t
) then
709 if CopyRect(img
, x
* w
, y
* h
, w
, h
, t
, 0, 0) then
712 rs
[i
] := r_Textures_GetRect(t
);
713 st
[i
] := r_Textures_LoadFromImage(t
);
716 ASSERT(st
[i
] <> nil);
721 function r_Textures_LoadStreamFromMemory (data
: Pointer; size
: LongInt; w
, h
, c
, cw
: Integer; st
: TGLTextureArray
; rs
: TRectArray
): Boolean;
728 ASSERT((st
<> nil) and (Length(st
) >= c
));
729 ASSERT((rs
= nil) or (Length(rs
) >= c
));
731 if (data
<> nil) and (size
> 0) then
735 if LoadImageFromMemory(data
, size
, img
) then
737 if r_Textures_FixImageData(img
) then
739 result
:= r_Textures_LoadStreamFromImage(img
, w
, h
, c
, cw
, st
, rs
)
748 function r_Textures_LoadStreamFromFile (const filename
: AnsiString; w
, h
, count
, cw
: Integer; st
: TGLTextureArray
; rs
: TRectArray
; log
: Boolean = True): Boolean;
749 var wad
: TWADFile
; wadName
, resName
: AnsiString; data
: Pointer; size
: Integer;
755 ASSERT((st
<> nil) and (Length(st
) >= count
));
756 ASSERT((rs
= nil) or (Length(rs
) >= count
));
758 wadName
:= g_ExtractWadName(filename
);
759 wad
:= TWADFile
.Create();
760 if wad
.ReadFile(wadName
) then
762 resName
:= g_ExtractFilePathName(filename
);
763 if wad
.GetResource(resName
, data
, size
, log
) then
765 result
:= r_Textures_LoadStreamFromMemory(data
, size
, w
, h
, count
, cw
, st
, rs
);
772 (* --------- TGLFont --------- *)
774 function r_Textures_LoadFontFromFile (const filename
: AnsiString; constref f
: TFontInfo
; skipch
: Integer; log
: Boolean = true): TGLFont
;
775 var i
: Integer; st
: TGLTextureArray
; font
: TGLFont
; t
: TGLTexture
;
780 if r_Textures_LoadStreamFromFile(filename
, f
.w
, f
.h
, 256, 16, st
, nil, log
) then
787 st
[i
] := st
[(i
+ skipch
) mod 256];
788 st
[(i
+ skipch
) mod 256] := t
;
791 font
:= TGLFont
.Create();
798 destructor TGLFont
.Destroy
;
801 if self
.ch
<> nil then
802 for i
:= 0 to High(self
.ch
) do
807 function TGLFont
.GetChar (c
: AnsiChar): TGLTexture
;
809 result
:= self
.ch
[ORD(c
)];
812 function TGLFont
.GetWidth (c
: AnsiChar): Integer;
814 result
:= self
.info
.ch
[c
].w
;
816 result
:= self
.info
.w
;
817 if self
.info
.kern
< 0 then
818 result
:= result
+ self
.info
.kern
;
821 function TGLFont
.GetMaxWidth (): Integer;
823 result
:= self
.info
.w
;
824 if self
.info
.kern
< 0 then
825 result
:= result
+ self
.info
.kern
;
828 function TGLFont
.GetMaxHeight (): Integer;
830 result
:= self
.info
.h
;
833 function TGLFont
.GetSpace (): Integer;
835 result
:= self
.info
.kern
;