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}
21 {$I ../../../nogl/noGLuses.inc}
22 g_base
, g_animations
, // TRectHW, TAnimInfo
28 TGLHints
= (txNoRepeat
);
29 TGLHintsSet
= set of TGLHints
;
33 TGLAtlasNode
= class (TAtlasNode
)
38 constructor Create (base
: TGLAtlas
);
39 destructor Destroy
; override;
41 function GetID (): GLuint
;
43 property base
: TGLAtlas read mBase
;
44 property id
: GLuint read GetID
;
47 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;
60 property filter
: Boolean read mFilter write mFilter
;
68 mTile
: array of TGLAtlasNode
;
73 destructor Destroy
; override;
75 function GetTile (col
, line
: Integer): TGLAtlasNode
;
77 function GetLines (): Integer; inline;
79 property width
: Integer read mWidth
;
80 property height
: Integer read mHeight
;
81 property cols
: Integer read mCols
;
82 property lines
: Integer read GetLines
;
83 property hints
: TGLHintsSet read mHints
;
84 property filter
: Boolean read mFilter write mFilter
;
87 TGLMultiTexture
= class
89 mTexture
: array of TGLTexture
;
92 destructor Destroy
; override;
94 function GetWidth (): Integer; inline;
95 function GetHeight (): Integer; inline;
96 function GetCount (): Integer; inline;
97 function GetTexture (i
: Integer): TGLTexture
; {inline;}
99 property width
: Integer read GetWidth
;
100 property height
: Integer read GetHeight
;
101 property count
: Integer read GetCount
;
104 TGLTextureArray
= array of TGLTexture
;
106 TRectArray
= array of TRectWH
;
108 TGLFont
= class sealed (TFont
)
114 destructor Destroy
; override;
115 function GetChar (c
: AnsiChar): TGLTexture
;
116 function GetWidth (c
: AnsiChar): Integer;
117 function GetMaxWidth (): Integer;
118 function GetMaxHeight (): Integer;
119 function GetSpace (): Integer;
122 TAnimTextInfo
= record
128 TConvProc
= function (x
: Integer): Integer;
130 procedure r_Textures_Initialize
;
131 procedure r_Textures_Finalize
;
133 function r_Textures_LoadFromFile (const filename
: AnsiString; hints
: TGLHintsSet
; log
: Boolean = True): TGLTexture
;
134 function r_Textures_LoadMultiFromFile (const filename
: AnsiString; hints
: TGLHintsSet
; log
: Boolean = True): TGLMultiTexture
;
135 function r_Textures_LoadMultiFromFileAndInfo (const filename
: AnsiString; w
, h
, count
: Integer; hints
: TGLHintsSet
; log
: Boolean = True): TGLMultiTexture
;
136 function r_Textures_LoadMultiTextFromFile (const filename
: AnsiString; var txt
: TAnimTextInfo
; hints
: TGLHintsSet
; log
: Boolean = True): TGLMultiTexture
;
138 function r_Textures_LoadStreamFromFile (const filename
: AnsiString; w
, h
, count
, cw
: Integer; st
: TGLTextureArray
; rs
: TRectArray
; hints
: TGLHintsSet
; log
: Boolean = True): Boolean;
140 function r_Textures_LoadFontFromFile (const filename
: AnsiString; constref f
: TFontInfo
; font2enc
: TConvProc
; log
: Boolean = true): TGLFont
;
142 procedure r_Textures_GL_Bind (id
: GLuint
);
149 e_log
, e_res
, WADReader
, Config
,
150 g_console
, // cvar declaration
151 Imaging
, ImagingTypes
, ImagingUtility
155 r_GL_MaxTexSize
: WORD;
156 r_GL_RepeatOpt
: Boolean;
157 maxTileSize
: Integer;
158 atl
, ratl
: array of TGLAtlas
;
159 currentTexture2D
: GLuint
;
161 function r_Textures_GL_GetError (msg
: AnsiString): Boolean;
162 var code
: GLenum
; s
: AnsiString;
164 code
:= glGetError();
165 if code
<> GL_NO_ERROR
then
168 GL_INVALID_ENUM
: s
:= 'GL_INVALID_ENUM';
169 GL_INVALID_VALUE
: s
:= 'GL_INVALID_VALUE';
170 GL_INVALID_OPERATION
: s
:= 'GL_INVALID_OPERATION';
171 GL_STACK_OVERFLOW
: s
:= 'GL_STACK_OVERFLOW';
172 GL_STACK_UNDERFLOW
: s
:= 'GL_STACK_UNDERFLOW';
173 GL_OUT_OF_MEMORY
: s
:= 'GL_OUT_OF_MEMORY';
175 GL_TABLE_TOO_LARGE
: s
:= 'GL_TABLE_TOO_LARGE';
180 e_LogWritefln('%s: %s', [msg
, s
])
182 e_LogWritefln('%s: error code %s', [msg
, code
]);
184 result
:= code
<> GL_NO_ERROR
;
187 procedure r_Textures_GL_ClearError
;
191 code
:= glGetError();
192 until code
= GL_NO_ERROR
;
195 procedure r_Textures_GL_Bind (id
: GLuint
);
197 if id
<> currentTexture2D
then
199 glBindTexture(GL_TEXTURE_2D
, id
);
200 currentTexture2D
:= id
;
204 function r_Textures_GL_BindAndCheck (id
: GLuint
): Boolean;
207 if id
<> currentTexture2D
then
209 r_Textures_GL_ClearError
;
210 glBindTexture(GL_TEXTURE_2D
, id
);
211 result
:= not r_Textures_GL_GetError('failed to bind texture');
212 if result
= true then
213 currentTexture2D
:= id
;
217 (* --------- TGLAtlasNode --------- *)
219 constructor TGLAtlasNode
.Create (base
: TGLAtlas
);
226 destructor TGLAtlasNode
.Destroy
;
231 function TGLAtlasNode
.GetID (): GLuint
;
233 result
:= self
.base
.id
236 function r_Textures_UpdateNode (n
: TGLAtlasNode
; data
: Pointer; x
, y
, w
, h
: Integer): Boolean;
240 ASSERT(n
.base
<> nil);
244 ASSERT(n
.l
+ x
+ w
- 1 <= n
.r
);
245 ASSERT(n
.t
+ y
+ h
- 1 <= n
.b
);
248 if r_Textures_GL_BindAndCheck(n
.id
) then
250 glTexSubImage2D(GL_TEXTURE_2D
, 0, n
.l
+ x
, n
.t
+ y
, w
, h
, GL_RGBA
, GL_UNSIGNED_BYTE
, data
);
251 result
:= not r_Textures_GL_GetError('failed to update atlas node');
252 r_Textures_GL_Bind(0);
256 (* --------- TGLAtlas --------- *)
258 constructor TGLAtlas
.Create (ww
, hh
: Integer; id
: GLuint
);
262 inherited Create(ww
, hh
);
264 self
.mFilter
:= false;
267 destructor TGLAtlas
.Destroy
;
272 function TGLAtlas
.CreateNode (): TGLAtlasNode
;
274 result
:= TGLAtlasNode
.Create(self
);
277 function TGLAtlas
.Alloc (ww
, hh
: Integer): TGLAtlasNode
;
279 result
:= TGLAtlasNode(inherited Alloc(ww
, hh
));
282 procedure r_Textures_AllocHWTexture (w
, h
: Integer; out id
: GLuint
; out ok
: Boolean);
284 id
:= 0; ok
:= false;
285 r_Textures_GL_ClearError
;
286 glGenTextures(1, @id
);
287 if not r_Textures_GL_GetError('failed to allocate texture id') then
289 if r_Textures_GL_BindAndCheck(id
) then
291 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_REPEAT
);
292 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_REPEAT
);
293 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
294 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
295 r_Textures_GL_ClearError
;
296 glTexImage2D(GL_TEXTURE_2D
, 0, GL_RGBA
, w
, h
, 0, GL_RGBA
, GL_UNSIGNED_BYTE
, nil);
297 ok
:= not r_Textures_GL_GetError('failed to allocate hardware texture');
298 r_Textures_GL_Bind(0);
302 glDeleteTextures(1, @id
);
308 function r_Textures_AllocAtlas (): TGLAtlas
;
309 var i
: Integer; id
: GLuint
; ok
: Boolean;
312 r_Textures_AllocHWTexture(maxTileSize
, maxTileSize
, id
, ok
);
316 SetLength(atl
, i
+ 1);
317 atl
[i
] := TGLAtlas
.Create(maxTileSize
, maxTileSize
, id
);
322 function r_Textures_AllocRepeatAtlas (w
, h
: Integer): TGLAtlas
;
323 var i
: Integer; id
: GLuint
; ok
: Boolean;
326 r_Textures_AllocHWTexture(w
, h
, id
, ok
);
330 SetLength(ratl
, i
+ 1);
331 ratl
[i
] := TGLAtlas
.Create(w
, h
, id
);
336 function r_Textures_AllocNode (w
, h
: Integer): TGLAtlasNode
;
337 var i
: Integer; n
: TGLAtlasNode
; a
: TGLAtlas
;
343 while (i
>= 0) and (n
= nil) do
345 n
:= atl
[i
].Alloc(w
, h
);
351 a
:= r_Textures_AllocAtlas();
358 function r_Textures_AllocRepeatNode (w
, h
: Integer): TGLAtlasNode
;
359 var i
: Integer; n
: TGLAtlasNode
; a
: TGLAtlas
;
365 while (i
>= 0) and (ratl
[i
] <> nil) do DEC(i
);
366 if i
>= 0 then a
:= ratl
[i
];
368 if a
= nil then a
:= r_Textures_AllocRepeatAtlas(w
, h
);
374 i
:= High(ratl
); while (i
>= 0) and (ratl
[i
] <> a
) do DEC(i
);
375 if i
>= 0 then ratl
[i
] := nil;
376 r_Common_FreeAndNil(a
);
382 (* --------- TGLTexture --------- *)
384 destructor TGLTexture
.Destroy
;
385 var i
: Integer; a
: TGLAtlas
;
387 if self
.mTile
<> nil then
389 if TGLHints
.txNoRepeat
in self
.hints
then (* non repeatable texture -> delete tiles only *)
391 for i
:= 0 to High(self
.mTile
) do
393 if self
.mTile
[i
] <> nil then
395 self
.mTile
[i
].Dealloc
;
400 else (* repeatable texture -> delete whole atlas *)
402 a
:= self
.mTile
[0].base
;
403 i
:= High(ratl
); while (i
>= 0) and (ratl
[i
] <> a
) do DEC(i
);
404 if i
>= 0 then ratl
[i
] := nil;
405 r_Common_FreeAndNil(a
);
407 SetLength(self
.mTile
, 0);
412 function TGLTexture
.GetLines (): Integer;
414 ASSERT(self
.mTile
<> nil);
415 result
:= Length(self
.mTile
) div self
.mCols
418 function TGLTexture
.GetTile (col
, line
: Integer): TGLAtlasNode
;
422 ASSERT(col
<= mCols
);
423 ASSERT(self
.mTile
<> nil);
424 i
:= line
* mCols
+ col
;
426 ASSERT(i
< Length(mTile
));
428 ASSERT(result
<> nil)
431 function r_Textures_Alloc (w
, h
: Integer; hints
: TGLHintsSet
): TGLTexture
;
432 var x
, y
, mw
, mh
, cols
, lines
: Integer; t
: TGLTexture
;
436 if TGLHints
.txNoRepeat
in hints
then
438 cols
:= (w
+ maxTileSize
- 1) div maxTileSize
;
439 lines
:= (h
+ maxTileSize
- 1) div maxTileSize
;
440 t
:= TGLTexture
.Create
;
444 // t.mLines := lines;
447 SetLength(t
.mTile
, cols
* lines
);
448 for y
:= 0 to lines
- 1 do
450 mh
:= Min(maxTileSize
, h
- y
* maxTileSize
);
452 for x
:= 0 to cols
- 1 do
454 mw
:= Min(maxTileSize
, w
- x
* maxTileSize
);
456 t
.mTile
[y
* cols
+ x
] := r_Textures_AllocNode(mw
, mh
);
462 t
:= TGLTexture
.Create
;
468 SetLength(t
.mTile
, 1);
469 t
.mTile
[0] := r_Textures_AllocRepeatNode(w
, h
);
474 (* --------- TGLMultiTexture --------- *)
476 destructor TGLMultiTexture
.Destroy
;
479 for i
:= 0 to self
.count
- 1 do
480 r_Common_FreeAndNil(self
.mTexture
[i
]);
481 SetLength(self
.mTexture
, 0);
485 function TGLMultiTexture
.GetWidth (): Integer;
487 result
:= self
.mTexture
[0].width
490 function TGLMultiTexture
.GetHeight (): Integer;
492 result
:= self
.mTexture
[0].height
495 function TGLMultiTexture
.GetCount (): Integer;
497 result
:= Length(self
.mTexture
)
500 function TGLMultiTexture
.GetTexture (i
: Integer): TGLTexture
;
503 ASSERT(i
< self
.count
);
504 result
:= self
.mTexture
[i
];
505 ASSERT(result
<> nil);
508 (* --------- Init / Fin --------- *)
510 function IsPOT (v
: LongWord): Boolean;
512 result
:= (v
<> 0) and ((v
and (v
- 1)) = 0)
515 function NextPOT (v
: LongWord): LongWord;
527 function r_Textures_GetMaxHardwareSize (): Integer;
530 if r_GL_MaxTexSize
<= 0 then
532 // auto, max possible reccomended by driver
533 glGetIntegerv(GL_MAX_TEXTURE_SIZE
, @size
);
534 size
:= size
div 2; (* hack: on some devices max size may produce invalid texture *)
535 if size
< 64 then size
:= 64; (* at least 64x64 are guarantied by specification *)
540 if IsPOT(r_GL_MaxTexSize
) then
541 size
:= r_GL_MaxTexSize
543 size
:= NextPOT(r_GL_MaxTexSize
);
548 procedure r_Textures_Initialize
;
550 currentTexture2D
:= 0;
551 maxTileSize
:= r_Textures_GetMaxHardwareSize();
552 e_LogWritefln('Texture Tile Size: %s', [maxTileSize
]);
555 procedure r_Textures_Finalize
;
560 for i
:= 0 to High(atl
) do
562 if atl
[i
] <> nil then
564 glDeleteTextures(1, @atl
[i
].id
);
566 r_Common_FreeAndNil(atl
[i
]);
574 for i
:= 0 to High(ratl
) do
576 if ratl
[i
] <> nil then
578 glDeleteTextures(1, @ratl
[i
].id
);
580 r_Common_FreeAndNil(ratl
[i
]);
587 function r_Textures_FixImageData (var img
: TImageData
): Boolean;
590 if ConvertImage(img
, TImageFormat
.ifA8R8G8B8
) then
591 if SwapChannels(img
, ChannelRed
, ChannelBlue
) then // wtf
595 function r_Textures_ValidRepeatTexture (w
, h
: Integer; hints
: TGLHintsSet
): Boolean;
597 result
:= r_GL_RepeatOpt
and
598 not (TGLHints
.txNoRepeat
in hints
) and
599 (w
<= maxTileSize
) and
600 (h
<= maxTileSize
) and
605 function r_Textures_LoadFromImage (var img
: TImageData
; hints
: TGLHintsSet
): TGLTexture
; // !!!
606 var t
: TGLTexture
; n
: TGLAtlasNode
; c
: TDynImageDataArray
; cw
, ch
, i
, j
: LongInt; ok
: Boolean;
608 t
:= nil; ok
:= false;
609 if r_Textures_ValidRepeatTexture(img
.width
, img
.height
, hints
) then
611 t
:= r_Textures_Alloc(img
.width
, img
.height
, hints
- [TGLHints
.txNoRepeat
]);
614 n
:= t
.GetTile(0, 0);
616 ok
:= r_Textures_UpdateNode(n
, img
.bits
, 0, 0, n
.width
, n
.height
);
619 else if SplitImage(img
, c
, maxTileSize
, maxTileSize
, cw
, ch
, False) then
621 t
:= r_Textures_Alloc(img
.width
, img
.height
, hints
+ [TGLHints
.txNoRepeat
]);
626 ASSERT(ch
= t
.lines
);
627 for j
:= 0 to ch
- 1 do
629 for i
:= 0 to cw
- 1 do
631 n
:= t
.GetTile(i
, j
);
633 ok
:= ok
and r_Textures_UpdateNode(n
, c
[j
* cw
+ i
].bits
, 0, 0, n
.width
, n
.height
)
637 FreeImagesInArray(c
);
640 r_Common_FreeAndNil(t
);
644 function r_Textures_LoadFromMemory (data
: Pointer; size
: LongInt; hints
: TGLHintsSet
): TGLTexture
;
648 if (data
<> nil) and (size
> 0) then
652 if LoadImageFromMemory(data
, size
, img
) then
653 if r_Textures_FixImageData(img
) then
654 result
:= r_Textures_LoadFromImage(img
, hints
)
661 function r_Textures_LoadFromFile (const filename
: AnsiString; hints
: TGLHintsSet
; log
: Boolean = True): TGLTexture
;
662 var wad
: TWADFile
; wadName
, resName
: AnsiString; data
: Pointer; size
: Integer;
665 wadName
:= g_ExtractWadName(filename
);
666 wad
:= TWADFile
.Create();
667 if wad
.ReadFile(wadName
) then
669 resName
:= g_ExtractFilePathName(filename
);
670 if wad
.GetResource(resName
, data
, size
, log
) then
672 result
:= r_Textures_LoadFromMemory(data
, size
, hints
);
679 function r_Textures_LoadMultiFromImageAndInfo (var img
: TImageData
; w
, h
, c
: Integer; hints
: TGLHintsSet
): TGLMultiTexture
;
680 var t
: TImageData
; a
: array of TGLTexture
; i
: Integer; m
: TGLMultiTexture
;
687 for i
:= 0 to c
- 1 do
690 if NewImage(w
, h
, img
.Format
, t
) then
691 if CopyRect(img
, w
* i
, 0, w
, h
, t
, 0, 0) then
692 a
[i
] := r_Textures_LoadFromImage(t
, hints
);
696 m
:= TGLMultiTexture
.Create();
698 ASSERT(m
.mTexture
<> nil);
702 function r_Textures_LoadMultiFromDataAndInfo (data
: Pointer; size
: LongInt; w
, h
, c
: Integer; hints
: TGLHintsSet
): TGLMultiTexture
;
709 if (data
<> nil) and (size
> 0) then
713 if LoadImageFromMemory(data
, size
, img
) then
714 if r_Textures_FixImageData(img
) then
715 result
:= r_Textures_LoadMultiFromImageAndInfo(img
, w
, h
, c
, hints
)
722 function r_Textures_LoadTextFromMemory (data
: Pointer; size
: LongInt; var text: TAnimTextInfo
): Boolean;
728 cfg
:= TConfig
.CreateMem(data
, size
);
731 text.name
:= cfg
.ReadStr('', 'resource', '');
732 text.w
:= cfg
.ReadInt('', 'framewidth', 0);
733 text.h
:= cfg
.ReadInt('', 'frameheight', 0);
734 text.anim
.loop
:= true;
735 text.anim
.delay
:= cfg
.ReadInt('', 'waitcount', 0);
736 text.anim
.frames
:= cfg
.ReadInt('', 'framecount', 0);
737 text.anim
.back
:= cfg
.ReadBool('', 'backanim', false);
738 if text.w
<= 0 then e_LogWritefln('Warning: bad animation width %s for %s', [text.w
, text.name
]);
739 if text.h
<= 0 then e_LogWritefln('Warning: bad animation height %s for %s', [text.h
, text.name
]);
740 if text.anim
.delay
<= 0 then e_LogWritefln('Warning: bad animation delay %s for %s', [text.anim
.delay
, text.name
]);
741 if text.anim
.frames
<= 0 then e_LogWritefln('Warning: bad animation frame count %s for %s', [text.anim
.frames
, text.name
]);
742 text.w
:= MAX(0, text.w
);
743 text.h
:= MAX(0, text.h
);
744 text.anim
.delay
:= MAX(1, text.anim
.delay
);
745 text.anim
.frames
:= MAX(1, text.anim
.frames
);
747 result
:= (text.name
<> '') and (text.w
> 0) and (text.h
> 0) and (text.anim
.delay
> 0) and (text.anim
.frames
> 0);
752 function r_Textures_LoadMultiFromWad (wad
: TWADFile
; var txt
: TAnimTextInfo
; hints
: TGLHintsSet
): TGLMultiTexture
;
753 var data
: Pointer; size
: LongInt; img
: TImageData
;
757 if wad
.GetResource('TEXT/ANIM', data
, size
) then
759 if r_Textures_LoadTextFromMemory(data
, size
, txt
) then
762 if wad
.GetResource('TEXTURES/' + txt
.name
, data
, size
) then
766 if LoadImageFromMemory(data
, size
, img
) then
767 if r_Textures_FixImageData(img
) then
768 result
:= r_Textures_LoadMultiFromImageAndInfo(img
, txt
.w
, txt
.h
, txt
.anim
.frames
, hints
);
780 function r_Textures_LoadMultiFromMemory (data
: Pointer; size
: LongInt; var txt
: TAnimTextInfo
; hints
: TGLHintsSet
): TGLMultiTexture
;
781 var wad
: TWADFile
; t
: TGLTexture
; m
: TGLMultiTexture
;
784 if (data
<> nil) and (size
> 0) then
786 t
:= r_Textures_LoadFromMemory(data
, size
, hints
);
789 m
:= TGLMultiTexture
.Create();
790 SetLength(m
.mTexture
, 1);
795 txt
.anim
.loop
:= true;
797 txt
.anim
.frames
:= 1;
798 txt
.anim
.back
:= false;
801 else if IsWadData(data
, size
) then
803 wad
:= TWADFile
.Create();
804 if wad
.ReadMemory(data
, size
) then
806 result
:= r_Textures_LoadMultiFromWad(wad
, txt
, hints
);
813 function r_Textures_LoadMultiTextFromFile (const filename
: AnsiString; var txt
: TAnimTextInfo
; hints
: TGLHintsSet
; log
: Boolean = True): TGLMultiTexture
;
814 var wad
: TWADFile
; wadName
, resName
: AnsiString; data
: Pointer; size
: Integer;
817 wadName
:= g_ExtractWadName(filename
);
818 wad
:= TWADFile
.Create();
819 if wad
.ReadFile(wadName
) then
821 resName
:= g_ExtractFilePathName(filename
);
822 if wad
.GetResource(resName
, data
, size
, log
) then
824 result
:= r_Textures_LoadMultiFromMemory(data
, size
, txt
, hints
);
831 function r_Textures_LoadMultiFromFile (const filename
: AnsiString; hints
: TGLHintsSet
; log
: Boolean = True): TGLMultiTexture
;
832 var txt
: TAnimTextInfo
;
834 result
:= r_Textures_LoadMultiTextFromFile(filename
, txt
, hints
, log
);
837 function r_Textures_LoadMultiFromFileAndInfo (const filename
: AnsiString; w
, h
, count
: Integer; hints
: TGLHintsSet
; log
: Boolean = True): TGLMultiTexture
;
838 var wad
: TWADFile
; wadName
, resName
: AnsiString; data
: Pointer; size
: Integer;
844 wadName
:= g_ExtractWadName(filename
);
845 wad
:= TWADFile
.Create();
846 if wad
.ReadFile(wadName
) then
848 resName
:= g_ExtractFilePathName(filename
);
849 if wad
.GetResource(resName
, data
, size
, log
) then
851 result
:= r_Textures_LoadMultiFromDataAndInfo(data
, size
, w
, h
, count
, hints
);
858 function r_Textures_GetRect (var img
: TImageData
): TRectWH
;
859 var i
, j
, w
, h
: Integer; done
: Boolean;
861 function IsVoid (i
, j
: Integer): Boolean; inline;
863 result
:= GetPixel32(img
, i
, j
).Channels
[3] = 0
870 (* trace x from right to left *)
871 done
:= false; i
:= 0;
872 while not done
and (i
< w
) do
875 while (j
< h
) and IsVoid(i
, j
) do inc(j
);
876 done
:= (j
< h
) and (IsVoid(i
, j
) = false);
881 (* trace y from up to down *)
882 done
:= false; j
:= 0;
883 while not done
and (j
< h
) do
886 while (i
< w
) and IsVoid(i
, j
) do inc(i
);
887 done
:= (i
< w
) and (IsVoid(i
, j
) = false);
892 (* trace x from right to left *)
893 done
:= false; i
:= w
- 1;
894 while not done
and (i
>= 0) do
897 while (j
< h
) and IsVoid(i
, j
) do inc(j
);
898 done
:= (j
< h
) and (IsVoid(i
, j
) = false);
899 result
.width
:= i
- result
.x
+ 1;
903 (* trace y from down to up *)
904 done
:= false; j
:= h
- 1;
905 while not done
and (j
>= 0) do
908 while (i
< w
) and IsVoid(i
, j
) do inc(i
);
909 done
:= (i
< w
) and (IsVoid(i
, j
) = false);
910 result
.height
:= j
- result
.y
+ 1;
915 function r_Textures_LoadStreamFromImage (var img
: TImageData
; w
, h
, c
, cw
: Integer; st
: TGLTextureArray
; rs
: TRectArray
; hints
: TGLHintsSet
): Boolean;
916 var i
, x
, y
: Integer; t
: TImageData
;
922 ASSERT((st
<> nil) and (Length(st
) >= c
));
923 ASSERT((rs
= nil) or (Length(rs
) >= c
));
925 for i
:= 0 to c
- 1 do
931 if NewImage(w
, h
, img
.Format
, t
) then
933 if CopyRect(img
, x
* w
, y
* h
, w
, h
, t
, 0, 0) then
936 rs
[i
] := r_Textures_GetRect(t
);
937 st
[i
] := r_Textures_LoadFromImage(t
, hints
);
940 ASSERT(st
[i
] <> nil);
945 function r_Textures_LoadStreamFromMemory (data
: Pointer; size
: LongInt; w
, h
, c
, cw
: Integer; st
: TGLTextureArray
; rs
: TRectArray
; hints
: TGLHintsSet
): Boolean;
952 ASSERT((st
<> nil) and (Length(st
) >= c
));
953 ASSERT((rs
= nil) or (Length(rs
) >= c
));
955 if (data
<> nil) and (size
> 0) then
959 if LoadImageFromMemory(data
, size
, img
) then
961 if r_Textures_FixImageData(img
) then
963 result
:= r_Textures_LoadStreamFromImage(img
, w
, h
, c
, cw
, st
, rs
, hints
)
972 function r_Textures_LoadStreamFromFile (const filename
: AnsiString; w
, h
, count
, cw
: Integer; st
: TGLTextureArray
; rs
: TRectArray
; hints
: TGLHintsSet
; log
: Boolean = True): Boolean;
973 var wad
: TWADFile
; wadName
, resName
: AnsiString; data
: Pointer; size
: Integer;
979 ASSERT((st
<> nil) and (Length(st
) >= count
));
980 ASSERT((rs
= nil) or (Length(rs
) >= count
));
982 wadName
:= g_ExtractWadName(filename
);
983 wad
:= TWADFile
.Create();
984 if wad
.ReadFile(wadName
) then
986 resName
:= g_ExtractFilePathName(filename
);
987 if wad
.GetResource(resName
, data
, size
, log
) then
989 result
:= r_Textures_LoadStreamFromMemory(data
, size
, w
, h
, count
, cw
, st
, rs
, hints
);
996 (* --------- TGLFont --------- *)
998 function r_Textures_LoadFontFromFile (const filename
: AnsiString; constref f
: TFontInfo
; font2enc
: TConvProc
; log
: Boolean = true): TGLFont
;
999 var i
, ch
: Integer; st
, stch
: TGLTextureArray
; font
: TGLFont
;
1003 if r_Textures_LoadStreamFromFile(filename
, f
.w
, f
.h
, 256, 16, st
, nil, [TGLHints
.txNoRepeat
], log
) then
1005 font
:= TGLFont
.Create();
1008 if Assigned(font2enc
) then
1010 SetLength(stch
, 256);
1011 for i
:= 0 to 255 do
1014 ASSERT((ch
>= 0) and (ch
<= 255));
1024 destructor TGLFont
.Destroy
;
1027 if self
.ch
<> nil then
1028 for i
:= 0 to High(self
.ch
) do
1033 function TGLFont
.GetChar (c
: AnsiChar): TGLTexture
;
1035 result
:= self
.ch
[ORD(c
)];
1038 function TGLFont
.GetWidth (c
: AnsiChar): Integer;
1040 result
:= self
.info
.ch
[c
].w
;
1042 result
:= self
.info
.w
;
1043 if self
.info
.kern
< 0 then
1044 result
:= result
+ self
.info
.kern
;
1047 function TGLFont
.GetMaxWidth (): Integer;
1049 result
:= self
.info
.w
;
1050 if self
.info
.kern
< 0 then
1051 result
:= result
+ self
.info
.kern
;
1054 function TGLFont
.GetMaxHeight (): Integer;
1056 result
:= self
.info
.h
;
1059 function TGLFont
.GetSpace (): Integer;
1061 result
:= self
.info
.kern
;
1065 conRegVar('r_gl_maxtexsize', @r_GL_MaxTexSize
, '', '');
1066 conRegVar('r_gl_repeat', @r_GL_RepeatOpt
, '', '');
1067 r_GL_MaxTexSize
:= 0; // default is automatic value
1068 r_GL_RepeatOpt
:= true;