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}
20 uses g_panel
, MAPDEF
; // TPanel, TDFColor
22 procedure r_Map_Initialize
;
23 procedure r_Map_Finalize
;
28 procedure r_Map_LoadTextures
;
29 procedure r_Map_FreeTextures
;
31 procedure r_Map_Update
;
33 procedure r_Map_DrawBack (dx
, dy
: Integer);
34 procedure r_Map_DrawPanels (PanelType
: Word; hasAmbient
: Boolean; constref ambColor
: TDFColor
); // unaccelerated
35 procedure r_Map_CollectDrawPanels (x0
, y0
, wdt
, hgt
: Integer);
36 procedure r_Map_DrawPanelShadowVolumes (lightX
: Integer; lightY
: Integer; radius
: Integer);
37 procedure r_Map_DrawFlags
;
39 procedure r_Panel_Draw (constref p
: TPanel
; hasAmbient
: Boolean; constref ambColor
: TDFColor
);
40 procedure r_Panel_DrawShadowVolume (constref p
: TPanel
; lightX
, lightY
: Integer; radius
: Integer);
45 {$INCLUDE ../nogl/noGLuses.inc}
46 SysUtils
, Classes
, Math
, e_log
, wadreader
, CONFIG
, utils
,
47 r_graphics
, r_animations
, r_textures
, g_textures
,
48 g_base
, g_basic
, g_game
, g_options
,
53 RenTextures
: array of record
58 FlagFrames
: array [FLAG_RED
..FLAG_BLUE
] of DWORD
;
59 FlagAnim
: TAnimationState
;
61 procedure r_Map_Initialize
;
63 FlagAnim
:= TAnimationState
.Create(True, 8, 5);
66 procedure r_Map_Finalize
;
74 g_Frames_CreateWAD(@FlagFrames
[FLAG_RED
], 'FRAMES_FLAG_RED', GameWAD
+ ':TEXTURES\FLAGRED', 64, 64, 5, False);
75 g_Frames_CreateWAD(@FlagFrames
[FLAG_BLUE
], 'FRAMES_FLAG_BLUE', GameWAD
+ ':TEXTURES\FLAGBLUE', 64, 64, 5, False);
80 g_Frames_DeleteByName('FRAMES_FLAG_RED');
81 g_Frames_DeleteByName('FRAMES_FLAG_BLUE');
84 procedure r_Map_LoadTextures
;
89 WadName
, ResName
: String;
91 ResData
, ReszData
: Pointer;
92 ResLen
, ReszLen
: Integer;
94 TextureResource
: String;
95 Width
, Height
: Integer;
99 if Textures
<> nil then
101 n
:= Length(Textures
);
102 SetLength(RenTextures
, n
);
103 for i
:= 0 to n
- 1 do
105 // e_LogWritefln('r_Map_LoadTextures: -> [%s] :: [%s]', [Textures[i].FullName, Textures[i].TextureName]);
106 RenTextures
[i
].ID
:= LongWord(TEXTURE_NONE
);
107 RenTextures
[i
].Width
:= 0;
108 RenTextures
[i
].Height
:= 0;
109 RenTextures
[i
].Anim
:= False;
110 case Textures
[i
].TextureName
of
111 TEXTURE_NAME_WATER
: RenTextures
[i
].ID
:= LongWord(TEXTURE_SPECIAL_WATER
);
112 TEXTURE_NAME_ACID1
: RenTextures
[i
].ID
:= LongWord(TEXTURE_SPECIAL_ACID1
);
113 TEXTURE_NAME_ACID2
: RenTextures
[i
].ID
:= LongWord(TEXTURE_SPECIAL_ACID2
);
115 WadName
:= g_ExtractWadName(Textures
[i
].FullName
);
116 ResName
:= g_ExtractFilePathName(Textures
[i
].FullName
);
117 WAD
:= TWADFile
.Create();
118 if WAD
.ReadFile(WadName
) then
120 if WAD
.GetResource(ResName
, ResData
, ResLen
, log
) then
122 if IsWadData(ResData
, ResLen
) then
124 WADz
:= TWADFile
.Create();
125 if WADz
.ReadMemory(ResData
, ResLen
) then
127 if WADz
.GetResource('TEXT/ANIM', ReszData
, ReszLen
) then
129 cfg
:= TConfig
.CreateMem(ReszData
, ReszLen
);
133 TextureResource
:= cfg
.ReadStr('', 'resource', '');
134 Width
:= cfg
.ReadInt('', 'framewidth', 0);
135 Height
:= cfg
.ReadInt('', 'frameheight', 0);
136 FramesCount
:= cfg
.ReadInt('', 'framecount', 0);
137 // Speed := cfg.ReadInt('', 'waitcount', 0);
138 BackAnim
:= cfg
.ReadBool('', 'backanimation', False);
139 RenTextures
[i
].Width
:= Width
;
140 RenTextures
[i
].Height
:= Height
;
141 if TextureResource
<> '' then
143 if WADz
.GetResource('TEXTURES/' + TextureResource
, ReszData
, ReszLen
) then
145 if g_Frames_CreateMemory(@RenTextures
[i
].ID
, '', ReszData
, ReszLen
, Width
, Height
, FramesCount
, BackAnim
) then
146 RenTextures
[i
].Anim
:= True
148 e_LogWritefln('r_Map_LoadTextures: failed to create frames object (%s)', [Textures
[i
].FullName
]);
152 e_LogWritefln('r_Map_LoadTextures: failed to open animation resources (%s)', [Textures
[i
].FullName
])
155 e_LogWritefln('r_Map_LoadTextures: failed to animation has no texture resource string (%s)', [Textures
[i
].FullName
]);
159 e_LogWritefln('r_Map_LoadTextures: failed to parse animation description (%s)', [Textures
[i
].FullName
])
162 e_LogWritefln('r_Map_LoadTextures: failed to open animation description (%s)', [Textures
[i
].FullName
])
165 e_LogWritefln('r_Map_LoadTextures: failed to open animation (%s)', [Textures
[i
].FullName
]);
170 if e_CreateTextureMem(ResData
, ResLen
, RenTextures
[i
].ID
) then
171 e_GetTextureSize(RenTextures
[i
].ID
, @RenTextures
[i
].Width
, @RenTextures
[i
].Height
)
173 e_LogWritefln('r_Map_LoadTextures: failed to create texture (%s)', [Textures
[i
].FullName
])
178 e_LogWritefln('r_Map_LoadTextures: failed to open (%s)', [Textures
[i
].FullName
])
181 e_LogWritefln('r_Map_LoadTextures: failed to open %s', [WadName
]);
188 procedure r_Map_FreeTextures
;
193 procedure dplClear ();
195 if (gDrawPanelList
= nil) then gDrawPanelList
:= TBinHeapPanelDraw
.Create() else gDrawPanelList
.clear();
199 procedure r_Map_DrawPanels (PanelType
: Word; hasAmbient
: Boolean; constref ambColor
: TDFColor
);
201 procedure DrawPanels (constref panels
: TPanelArray
; drawDoors
: Boolean=False);
205 if (panels
<> nil) then
207 // alas, no visible set
208 for idx
:= 0 to High(panels
) do
210 if not (drawDoors
xor panels
[idx
].Door
) then
211 r_Panel_Draw(panels
[idx
], hasAmbient
, ambColor
);
218 PANEL_WALL
: DrawPanels(gWalls
);
219 PANEL_CLOSEDOOR
: DrawPanels(gWalls
, True);
220 PANEL_BACK
: DrawPanels(gRenderBackgrounds
);
221 PANEL_FORE
: DrawPanels(gRenderForegrounds
);
222 PANEL_WATER
: DrawPanels(gWater
);
223 PANEL_ACID1
: DrawPanels(gAcid1
);
224 PANEL_ACID2
: DrawPanels(gAcid2
);
225 PANEL_STEP
: DrawPanels(gSteps
);
230 procedure r_Map_CollectDrawPanels (x0
, y0
, wdt
, hgt
: Integer);
236 it
:= mapGrid
.forEachInAABB(x0
, y0
, wdt
, hgt
, GridDrawableMask
);
237 for mwit
in it
do if (((mwit
^.tag
and GridTagDoor
) <> 0) = mwit
^.Door
) then gDrawPanelList
.insert(mwit
^);
239 // list will be rendered in `g_game.DrawPlayer()`
242 procedure r_Map_DrawPanelShadowVolumes (lightX
: Integer; lightY
: Integer; radius
: Integer);
247 it
:= mapGrid
.forEachInAABB(lightX
-radius
, lightY
-radius
, radius
*2, radius
*2, (GridTagWall
or GridTagDoor
));
248 for mwit
in it
do r_Panel_DrawShadowVolume(mwit
^, lightX
, lightY
, radius
);
252 procedure r_Map_DrawBack(dx
, dy
: Integer);
254 if gDrawBackGround
and (BackID
<> DWORD(-1)) then
255 e_DrawSize(BackID
, dx
, dy
, 0, False, False, gBackSize
.X
, gBackSize
.Y
)
257 e_Clear(GL_COLOR_BUFFER_BIT
, 0, 0, 0);
260 procedure r_Map_DrawFlags
;
261 var i
, dx
: Integer; Mirror
: TMirrorType
; f
: PFlag
;
263 if gGameSettings
.GameMode
= GM_CTF
then
265 for i
:= FLAG_RED
to FLAG_BLUE
do
268 if not (f
.State
in [FLAG_STATE_NONE
, FLAG_STATE_CAPTURED
]) then
270 if f
.Direction
= TDirection
.D_LEFT
then
271 Mirror
:= TMirrorType
.Horizontal
273 Mirror
:= TMirrorType
.None
;
274 dx
:= IfThen(f
.Direction
= TDirection
.D_LEFT
, -1, +1);
275 r_AnimationState_Draw(FlagFrames
[i
], FlagAnim
, f
.Obj
.X
+ dx
, f
.Obj
.Y
+ 1, Mirror
);
276 if g_debug_Frames
then
277 e_DrawQuad(f
.Obj
.X
+ f
.Obj
.Rect
.X
, f
.Obj
.Y
+ f
.Obj
.Rect
.Y
, f
.Obj
.X
+ f
.Obj
.Rect
.X
+ f
.Obj
.Rect
.Width
- 1, f
.Obj
.Y
+ f
.Obj
.Rect
.Y
+ f
.Obj
.Rect
.Height
- 1, 0, 255, 0)
283 procedure r_Panel_Draw (constref p
: TPanel
; hasAmbient
: Boolean; constref ambColor
: TDFColor
);
284 var xx
, yy
: Integer; NoTextureID
, TextureID
, FramesID
: DWORD
; NW
, NH
: Word; Texture
: Cardinal; IsAnim
: Boolean; w
, h
: Integer;
286 if {p.Enabled and} (p
.FCurTexture
>= 0) and (p
.Width
> 0) and (p
.Height
> 0) and (p
.Alpha
< 255) {and g_Collide(X, Y, Width, Height, sX, sY, sWidth, sHeight)} then
288 Texture
:= p
.TextureIDs
[p
.FCurTexture
].Texture
;
289 IsAnim
:= RenTextures
[Texture
].Anim
;
292 if p
.TextureIDs
[p
.FCurTexture
].AnTex
<> nil then
294 FramesID
:= RenTextures
[Texture
].ID
;
295 w
:= RenTextures
[Texture
].Width
;
296 h
:= RenTextures
[Texture
].Height
;
297 for xx
:= 0 to p
.Width
div w
- 1 do
298 for yy
:= 0 to p
.Height
div h
- 1 do
299 r_AnimationState_Draw(FramesID
, p
.TextureIDs
[p
.FCurTexture
].AnTex
, p
.X
+ xx
* w
, p
.Y
+ yy
* h
, TMirrorType
.None
);
304 TextureID
:= RenTextures
[Texture
].ID
;
305 w
:= RenTextures
[Texture
].Width
;
306 h
:= RenTextures
[Texture
].Height
;
308 LongWord(TEXTURE_SPECIAL_WATER
): e_DrawFillQuad(p
.X
, p
.Y
, p
.X
+ p
.Width
- 1, p
.Y
+ p
.Height
- 1, 0, 0, 255, 0, TBlending
.Filter
);
309 LongWord(TEXTURE_SPECIAL_ACID1
): e_DrawFillQuad(p
.X
, p
.Y
, p
.X
+ p
.Width
- 1, p
.Y
+ p
.Height
- 1, 0, 230, 0, 0, TBlending
.Filter
);
310 LongWord(TEXTURE_SPECIAL_ACID2
): e_DrawFillQuad(p
.X
, p
.Y
, p
.X
+ p
.Width
- 1, p
.Y
+ p
.Height
- 1, 230, 0, 0, 0, TBlending
.Filter
);
311 LongWord(TEXTURE_NONE
):
312 if g_Texture_Get('NOTEXTURE', NoTextureID
) then
314 e_GetTextureSize(NoTextureID
, @NW
, @NH
);
315 e_DrawFill(NoTextureID
, p
.X
, p
.Y
, p
.Width
div NW
, p
.Height
div NH
, 0, False, False);
319 xx
:= p
.X
+ (p
.Width
div 2);
320 yy
:= p
.Y
+ (p
.Height
div 2);
321 e_DrawFillQuad(p
.X
, p
.Y
, xx
, yy
, 255, 0, 255, 0);
322 e_DrawFillQuad(xx
, p
.Y
, p
.X
+ p
.Width
- 1, yy
, 255, 255, 0, 0);
323 e_DrawFillQuad(p
.X
, yy
, xx
, p
.Y
+ p
.Height
- 1, 255, 255, 0, 0);
324 e_DrawFillQuad(xx
, yy
, p
.X
+ p
.Width
- 1, p
.Y
+ p
.Height
- 1, 255, 0, 255, 0);
327 if not p
.movingActive
then
328 e_DrawFill(TextureID
, p
.X
, p
.Y
, p
.Width
div w
, p
.Height
div h
, p
.Alpha
, True, p
.Blending
, hasAmbient
)
330 e_DrawFillX(TextureID
, p
.X
, p
.Y
, p
.Width
, p
.Height
, p
.Alpha
, True, p
.Blending
, g_dbg_scale
, hasAmbient
);
332 e_AmbientQuad(p
.X
, p
.Y
, p
.Width
, p
.Height
, ambColor
.r
, ambColor
.g
, ambColor
.b
, ambColor
.a
);
338 procedure r_Panel_DrawShadowVolume (constref p
: TPanel
; lightX
, lightY
: Integer; radius
: Integer);
339 var Texture
: Cardinal;
341 procedure extrude (x
: Integer; y
: Integer);
343 glVertex2i(x
+ (x
- lightX
) * 500, y
+ (y
- lightY
) * 500);
344 //e_WriteLog(Format(' : (%d,%d)', [x + (x - lightX) * 300, y + (y - lightY) * 300]), MSG_WARNING);
347 procedure drawLine (x0
: Integer; y0
: Integer; x1
: Integer; y1
: Integer);
349 // does this side facing the light?
350 if ((x1
- x0
) * (lightY
- y0
) - (lightX
- x0
) * (y1
- y0
) >= 0) then exit
;
351 //e_WriteLog(Format('lightpan: (%d,%d)-(%d,%d)', [x0, y0, x1, y1]), MSG_WARNING);
352 // this edge is facing the light, extrude and draw it
360 if radius
< 4 then exit
;
361 if p
.Enabled
and (p
.FCurTexture
>= 0) and (p
.Width
> 0) and (p
.Height
> 0) and (p
.Alpha
< 255) {and g_Collide(X, Y, Width, Height, sX, sY, sWidth, sHeight)} then
363 Texture
:= p
.TextureIDs
[p
.FCurTexture
].Texture
;
364 if not RenTextures
[Texture
].Anim
then
366 case RenTextures
[Texture
].ID
of
367 LongWord(TEXTURE_SPECIAL_WATER
): exit
;
368 LongWord(TEXTURE_SPECIAL_ACID1
): exit
;
369 LongWord(TEXTURE_SPECIAL_ACID2
): exit
;
370 LongWord(TEXTURE_NONE
): exit
;
373 if (p
.X
+ p
.Width
< lightX
- radius
) then exit
;
374 if (p
.Y
+ p
.Height
< lightY
- radius
) then exit
;
375 if (p
.X
> lightX
+ radius
) then exit
;
376 if (p
.Y
> lightY
+ radius
) then exit
;
377 //e_DrawFill(TextureIDs[FCurTexture].Tex, X, Y, Width div TextureWidth, Height div TextureHeight, Alpha, True, Blending);
379 drawLine(p
.x
, p
.y
, p
.x
+ p
.width
, p
.y
); // top
380 drawLine(p
.x
+ p
.width
, p
.y
, p
.x
+ p
.width
, p
.y
+ p
.height
); // right
381 drawLine(p
.x
+ p
.width
, p
.y
+ p
.height
, p
.x
, p
.y
+ p
.height
); // bottom
382 drawLine(p
.x
, p
.y
+ p
.height
, p
.x
, p
.y
); // left
387 procedure r_Map_Update
;