ce71ebc727d7e96b0001e0a44a512ba1b9269846
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}
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 procedure r_Textures_Initialize
;
106 procedure r_Textures_Finalize
;
108 function r_Textures_LoadFromFile (const filename
: AnsiString; log
: Boolean = True): TGLTexture
;
109 function r_Textures_LoadMultiFromFile (const filename
: AnsiString; log
: Boolean = True): TGLMultiTexture
;
110 function r_Textures_LoadMultiFromFileAndInfo (const filename
: AnsiString; w
, h
, count
: Integer; backanim
: Boolean; log
: Boolean = True): TGLMultiTexture
;
111 function r_Textures_LoadStreamFromFile (const filename
: AnsiString; w
, h
, count
: Integer; st
: TGLTextureArray
; rs
: TRectArray
; log
: Boolean = True): Boolean;
117 e_log
, e_res
, WADReader
, Config
,
118 Imaging
, ImagingTypes
, ImagingUtility
122 maxTileSize
: Integer;
123 atl
: array of TGLAtlas
;
125 (* --------- TGLAtlasNode --------- *)
127 constructor TGLAtlasNode
.Create (base
: TGLAtlas
);
134 destructor TGLAtlasNode
.Destroy
;
139 function TGLAtlasNode
.GetID (): GLuint
;
141 result
:= self
.base
.id
144 procedure r_Textures_UpdateNode (n
: TGLAtlasNode
; data
: Pointer; x
, y
, w
, h
: Integer);
148 ASSERT(n
.base
<> nil);
152 ASSERT(n
.l
+ x
+ w
- 1 <= n
.r
);
153 ASSERT(n
.t
+ y
+ h
- 1 <= n
.b
);
155 glBindTexture(GL_TEXTURE_2D
, n
.id
);
156 glTexSubImage2D(GL_TEXTURE_2D
, 0, n
.l
+ x
, n
.t
+ y
, w
, h
, GL_RGBA
, GL_UNSIGNED_BYTE
, data
);
157 glBindTexture(GL_TEXTURE_2D
, 0);
160 (* --------- TGLAtlas --------- *)
162 constructor TGLAtlas
.Create (ww
, hh
: Integer; id
: GLuint
);
166 inherited Create(ww
, hh
);
170 destructor TGLAtlas
.Destroy
;
175 function TGLAtlas
.CreateNode (): TGLAtlasNode
;
177 result
:= TGLAtlasNode
.Create(self
);
180 function TGLAtlas
.Alloc (ww
, hh
: Integer): TGLAtlasNode
;
182 result
:= TGLAtlasNode(inherited Alloc(ww
, hh
));
185 function r_Textures_AllocHWTexture (w
, h
: Integer): GLuint
;
188 glGenTextures(1, @id
);
191 glBindTexture(GL_TEXTURE_2D
, id
);
192 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
193 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
194 glTexImage2D(GL_TEXTURE_2D
, 0, GL_RGBA
, w
, h
, 0, GL_RGBA
, GL_UNSIGNED_BYTE
, nil);
195 glBindTexture(GL_TEXTURE_2D
, 0);
200 function r_Textures_AllocAtlas (): TGLAtlas
;
201 var i
: Integer; id
: GLuint
;
204 id
:= r_Textures_AllocHWTexture(maxTileSize
, maxTileSize
);
208 SetLength(atl
, i
+ 1);
209 atl
[i
] := TGLAtlas
.Create(maxTileSize
, maxTileSize
, id
);
214 function r_Textures_AllocNode (w
, h
: Integer): TGLAtlasNode
;
215 var i
: Integer; n
: TGLAtlasNode
; a
: TGLAtlas
;
221 while (i
>= 0) and (n
= nil) do
223 n
:= atl
[i
].Alloc(w
, h
);
229 a
:= r_Textures_AllocAtlas();
236 (* --------- TGLTexture --------- *)
238 destructor TGLTexture
.Destroy
;
241 if self
.mTile
<> nil then
243 for i
:= 0 to High(self
.mTile
) do
245 if self
.mTile
[i
] <> nil then
247 self
.mTile
[i
].Dealloc
;
248 self
.mTile
[i
] := nil;
256 function TGLTexture
.GetLines (): Integer;
258 ASSERT(self
.mTile
<> nil);
259 result
:= Length(self
.mTile
) div self
.mCols
262 function TGLTexture
.GetTile (col
, line
: Integer): TGLAtlasNode
;
266 ASSERT(col
<= mCols
);
267 ASSERT(self
.mTile
<> nil);
268 i
:= line
* mCols
+ col
;
270 ASSERT(i
< Length(mTile
));
272 ASSERT(result
<> nil)
275 function r_Textures_Alloc (w
, h
: Integer): TGLTexture
;
276 var x
, y
, mw
, mh
, cols
, lines
: Integer; t
: TGLTexture
;
280 cols
:= (w
+ maxTileSize
- 1) div maxTileSize
;
281 lines
:= (h
+ maxTileSize
- 1) div maxTileSize
;
282 t
:= TGLTexture
.Create
;
286 // t.mLines := lines;
287 SetLength(t
.mTile
, cols
* lines
);
288 for y
:= 0 to lines
- 1 do
290 mh
:= Min(maxTileSize
, h
- y
* maxTileSize
);
292 for x
:= 0 to cols
- 1 do
294 mw
:= Min(maxTileSize
, w
- x
* maxTileSize
);
296 t
.mTile
[y
* cols
+ x
] := r_Textures_AllocNode(mw
, mh
);
302 (* --------- TGLMultiTexture --------- *)
304 destructor TGLMultiTexture
.Destroy
;
307 for i
:= 0 to self
.count
- 1 do
308 self
.mTexture
[i
].Free
;
309 self
.mTexture
:= nil;
313 function TGLMultiTexture
.GetWidth (): Integer;
315 result
:= self
.mTexture
[0].width
318 function TGLMultiTexture
.GetHeight (): Integer;
320 result
:= self
.mTexture
[0].height
323 function TGLMultiTexture
.GetCount (): Integer;
325 result
:= Length(self
.mTexture
)
328 function TGLMultiTexture
.GetTexture (i
: Integer): TGLTexture
;
331 ASSERT(i
< self
.count
);
332 result
:= self
.mTexture
[i
];
333 ASSERT(result
<> nil);
336 (* --------- Init / Fin --------- *)
338 function r_Textures_GetMaxHardwareSize (): Integer;
341 glGetIntegerv(GL_MAX_TEXTURE_SIZE
, @size
);
342 if size
< 64 then size
:= 64;
343 //if size > 512 then size := 512;
348 procedure r_Textures_Initialize
;
350 maxTileSize
:= r_Textures_GetMaxHardwareSize();
353 procedure r_Textures_Finalize
;
358 for i
:= 0 to High(atl
) do
360 glDeleteTextures(1, @atl
[i
].id
);
368 function r_Textures_FixImageData (var img
: TImageData
): Boolean;
371 if ConvertImage(img
, TImageFormat
.ifA8R8G8B8
) then
372 if SwapChannels(img
, ChannelRed
, ChannelBlue
) then // wtf
376 function r_Textures_LoadFromImage (var img
: TImageData
): TGLTexture
;
377 var t
: TGLTexture
; n
: TGLAtlasNode
; c
: TDynImageDataArray
; cw
, ch
, i
, j
: LongInt;
379 // e_logwritefln('r_Textures_CreateFromImage: w=%s h=%s', [img.width, img.height]);
381 if SplitImage(img
, c
, maxTileSize
, maxTileSize
, cw
, ch
, False) then
383 t
:= r_Textures_Alloc(img
.width
, img
.height
);
387 ASSERT(ch
= t
.lines
);
388 for j
:= 0 to ch
- 1 do
390 for i
:= 0 to cw
- 1 do
392 n
:= t
.GetTile(i
, j
);
394 r_Textures_UpdateNode(n
, c
[j
* cw
+ i
].bits
, 0, 0, n
.width
, n
.height
)
399 FreeImagesInArray(c
);
403 function r_Textures_LoadFromMemory (data
: Pointer; size
: LongInt): TGLTexture
;
407 if (data
<> nil) and (size
> 0) then
411 if LoadImageFromMemory(data
, size
, img
) then
412 if r_Textures_FixImageData(img
) then
413 result
:= r_Textures_LoadFromImage(img
)
420 function r_Textures_LoadFromFile (const filename
: AnsiString; log
: Boolean = True): TGLTexture
;
421 var wad
: TWADFile
; wadName
, resName
: AnsiString; data
: Pointer; size
: Integer;
424 wadName
:= g_ExtractWadName(filename
);
425 wad
:= TWADFile
.Create();
426 if wad
.ReadFile(wadName
) then
428 resName
:= g_ExtractFilePathName(filename
);
429 if wad
.GetResource(resName
, data
, size
, log
) then
431 result
:= r_Textures_LoadFromMemory(data
, size
);
438 function r_Textures_LoadMultiFromImageAndInfo (var img
: TImageData
; w
, h
, c
: Integer; b
: Boolean): TGLMultiTexture
;
439 var t
: TImageData
; a
: array of TGLTexture
; i
: Integer; m
: TGLMultiTexture
;
446 for i
:= 0 to c
- 1 do
449 if NewImage(w
, h
, img
.Format
, t
) then
450 if CopyRect(img
, w
* i
, 0, w
, h
, t
, 0, 0) then
451 a
[i
] := r_Textures_LoadFromImage(t
);
455 m
:= TGLMultiTexture
.Create();
458 ASSERT(m
.mTexture
<> nil);
462 function r_Textures_LoadMultiFromDataAndInfo (data
: Pointer; size
: LongInt; w
, h
, c
: Integer; b
: Boolean): TGLMultiTexture
;
469 if (data
<> nil) and (size
> 0) then
473 if LoadImageFromMemory(data
, size
, img
) then
474 if r_Textures_FixImageData(img
) then
475 result
:= r_Textures_LoadMultiFromImageAndInfo(img
, w
, h
, c
, b
)
482 function r_Textures_LoadMultiFromWad (wad
: TWADFile
): TGLMultiTexture
;
483 var data
: Pointer; size
: LongInt; TexRes
: AnsiString; w
, h
, c
: Integer; b
: Boolean; cfg
: TConfig
; img
: TImageData
;
487 if wad
.GetResource('TEXT/ANIM', data
, size
) then
489 cfg
:= TConfig
.CreateMem(data
, size
);
493 TexRes
:= cfg
.ReadStr('', 'resource', '');
494 w
:= cfg
.ReadInt('', 'framewidth', 0);
495 h
:= cfg
.ReadInt('', 'frameheight', 0);
496 c
:= cfg
.ReadInt('', 'framecount', 0);
497 b
:= cfg
.ReadBool('', 'backanim', false);
498 if (TexRes
<> '') and (w
> 0) and (h
> 0) and (c
> 0) then
500 if wad
.GetResource('TEXTURES/' + TexRes
, data
, size
) then
504 if LoadImageFromMemory(data
, size
, img
) then
505 if r_Textures_FixImageData(img
) then
506 result
:= r_Textures_LoadMultiFromImageAndInfo(img
, w
, h
, c
, b
)
518 function r_Textures_LoadMultiFromMemory (data
: Pointer; size
: LongInt): TGLMultiTexture
;
519 var wad
: TWADFile
; t
: TGLTexture
; m
: TGLMultiTexture
;
522 if (data
<> nil) and (size
> 0) then
524 t
:= r_Textures_LoadFromMemory(data
, size
);
527 m
:= TGLMultiTexture
.Create();
528 SetLength(m
.mTexture
, 1);
530 m
.mBackanim
:= false;
533 else if IsWadData(data
, size
) then
535 wad
:= TWADFile
.Create();
536 if wad
.ReadMemory(data
, size
) then
538 result
:= r_Textures_LoadMultiFromWad(wad
);
545 function r_Textures_LoadMultiFromFile (const filename
: AnsiString; log
: Boolean = True): TGLMultiTexture
;
546 var wad
: TWADFile
; wadName
, resName
: AnsiString; data
: Pointer; size
: Integer; t
: TGLTexture
;
549 wadName
:= g_ExtractWadName(filename
);
550 wad
:= TWADFile
.Create();
551 if wad
.ReadFile(wadName
) then
553 resName
:= g_ExtractFilePathName(filename
);
554 if wad
.GetResource(resName
, data
, size
, log
) then
556 result
:= r_Textures_LoadMultiFromMemory(data
, size
);
563 function r_Textures_LoadMultiFromFileAndInfo (const filename
: AnsiString; w
, h
, count
: Integer; backanim
: Boolean; log
: Boolean = True): TGLMultiTexture
;
564 var wad
: TWADFile
; wadName
, resName
: AnsiString; data
: Pointer; size
: Integer;
570 wadName
:= g_ExtractWadName(filename
);
571 wad
:= TWADFile
.Create();
572 if wad
.ReadFile(wadName
) then
574 resName
:= g_ExtractFilePathName(filename
);
575 if wad
.GetResource(resName
, data
, size
, log
) then
577 result
:= r_Textures_LoadMultiFromDataAndInfo(data
, size
, w
, h
, count
, backanim
);
584 function r_Textures_GetRect (var img
: TImageData
): TRectWH
;
585 var i
, j
, w
, h
: Integer; done
: Boolean;
587 function IsVoid (i
, j
: Integer): Boolean; inline;
589 result
:= GetPixel32(img
, i
, j
).Channels
[3] = 0
596 (* trace x from right to left *)
597 done
:= false; i
:= 0;
598 while not done
and (i
< w
) do
601 while (j
< h
) and IsVoid(i
, j
) do inc(j
);
602 done
:= (j
< h
) and (IsVoid(i
, j
) = false);
607 (* trace y from up to down *)
608 done
:= false; j
:= 0;
609 while not done
and (j
< h
) do
612 while (i
< w
) and IsVoid(i
, j
) do inc(i
);
613 done
:= (i
< w
) and (IsVoid(i
, j
) = false);
618 (* trace x from right to left *)
619 done
:= false; i
:= w
- 1;
620 while not done
and (i
>= 0) do
623 while (j
< h
) and IsVoid(i
, j
) do inc(j
);
624 done
:= (j
< h
) and (IsVoid(i
, j
) = false);
625 result
.width
:= i
- result
.x
+ 1;
629 (* trace y from down to up *)
630 done
:= false; j
:= h
- 1;
631 while not done
and (j
>= 0) do
634 while (i
< w
) and IsVoid(i
, j
) do inc(i
);
635 done
:= (i
< w
) and (IsVoid(i
, j
) = false);
636 result
.height
:= j
- result
.y
+ 1;
641 function r_Textures_LoadStreamFromImage (var img
: TImageData
; w
, h
, c
: Integer; st
: TGLTextureArray
; rs
: TRectArray
): Boolean;
642 var i
: Integer; t
: TImageData
;
647 ASSERT((st
<> nil) and (Length(st
) >= c
));
648 ASSERT((rs
= nil) or (Length(rs
) >= c
));
650 for i
:= 0 to c
- 1 do
654 if NewImage(w
, h
, img
.Format
, t
) then
656 if CopyRect(img
, w
* i
, 0, w
, h
, t
, 0, 0) then
659 rs
[i
] := r_Textures_GetRect(t
);
660 st
[i
] := r_Textures_LoadFromImage(t
);
663 ASSERT(st
[i
] <> nil);
668 function r_Textures_LoadStreamFromMemory (data
: Pointer; size
: LongInt; w
, h
, c
: Integer; st
: TGLTextureArray
; rs
: TRectArray
): Boolean;
674 ASSERT((st
<> nil) and (Length(st
) >= c
));
675 ASSERT((rs
= nil) or (Length(rs
) >= c
));
677 if (data
<> nil) and (size
> 0) then
681 if LoadImageFromMemory(data
, size
, img
) then
682 if r_Textures_FixImageData(img
) then
683 result
:= r_Textures_LoadStreamFromImage(img
, w
, h
, c
, st
, rs
)
690 function r_Textures_LoadStreamFromFile (const filename
: AnsiString; w
, h
, count
: Integer; st
: TGLTextureArray
; rs
: TRectArray
; log
: Boolean = True): Boolean;
691 var wad
: TWADFile
; wadName
, resName
: AnsiString; data
: Pointer; size
: Integer;
696 ASSERT((st
<> nil) and (Length(st
) >= count
));
697 ASSERT((rs
= nil) or (Length(rs
) >= count
));
699 wadName
:= g_ExtractWadName(filename
);
700 wad
:= TWADFile
.Create();
701 if wad
.ReadFile(wadName
) then
703 resName
:= g_ExtractFilePathName(filename
);
704 if wad
.GetResource(resName
, data
, size
, log
) then
706 result
:= r_Textures_LoadStreamFromMemory(data
, size
, w
, h
, count
, st
, rs
);