DEADSOFTWARE

gl: draw pink-white chessboard as invalid texture placeholder
[d2df-sdl.git] / src / game / renders / opengl / r_draw.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 r_draw;
18 interface
20 uses
21 g_animations,
22 r_textures
23 ;
25 procedure r_Draw_Texture (img: TGLTexture; x, y, w, h: Integer; flip: Boolean; r, g, b, a: Byte; blend: Boolean);
26 procedure r_Draw_TextureRepeat (img: TGLTexture; x, y, w, h: Integer; flip: Boolean; r, g, b, a: Byte; blend: Boolean);
27 procedure r_Draw_TextureRepeatRotate (img: TGLTexture; x, y, w, h: Integer; flip: Boolean; r, g, b, a: Byte; blend: Boolean; rx, ry, angle: Integer);
29 procedure r_Draw_MultiTextureRepeat (m: TGLMultiTexture; const anim: TAnimState; backanim: Boolean; x, y, w, h: Integer; flip: Boolean; r, g, b, a: Byte; blend: Boolean);
30 procedure r_Draw_MultiTextureRepeatRotate (m: TGLMultiTexture; const anim: TAnimState; backanim: Boolean; x, y, w, h: Integer; flip: Boolean; r, g, b, a: Byte; blend: Boolean; rx, ry, angle: Integer);
32 procedure r_Draw_Filter (l, t, r, b: Integer; rr, gg, bb, aa: Byte);
33 procedure r_Draw_Rect (l, t, r, b: Integer; rr, gg, bb, aa: Byte);
34 procedure r_Draw_FillRect (l, t, r, b: Integer; rr, gg, bb, aa: Byte);
35 procedure r_Draw_InvertRect (l, t, r, b: Integer; rr, gg, bb, aa: Byte);
37 procedure r_Draw_Text (const text: AnsiString; x, y: Integer; r, g, b, a: Byte; f: TGLFont);
38 procedure r_Draw_GetTextSize (const text: AnsiString; f: TGLFont; out w, h: Integer);
40 procedure r_Draw_Setup (sw, sh, gw, gh: Integer);
41 procedure r_Draw_SetRect (l, t, r, b: Integer);
42 procedure r_Draw_GetRect (out l, t, r, b: Integer);
44 procedure r_Draw_EnableTexture2D (enable: Boolean);
45 procedure r_Draw_SetColor (r, g, b, a: Byte);
47 implementation
49 uses
50 {$I ../../../nogl/noGLuses.inc}
51 SysUtils, Classes, Math,
52 e_log, utils
53 ;
55 const
56 NTR = $FF;
57 NTG = $00;
58 NTB = $00;
59 NTA = $FF;
61 var
62 sl, st, sr, sb: Integer;
63 ScreenWidth, ScreenHeight: Integer;
64 GameWidth, GameHeight: Integer;
66 enableTexture2D: Boolean;
67 curR, curG, curB, curA: Byte;
69 procedure r_Draw_EnableTexture2D (enable: Boolean);
70 begin
71 if enable <> enableTexture2D then
72 begin
73 if enable then glEnable(GL_TEXTURE_2D) else glDisable(GL_TEXTURE_2D);
74 enableTexture2D := enable;
75 end;
76 end;
78 procedure r_Draw_SetColor (r, g, b, a: Byte);
79 begin
80 if (r <> curR) or (g <> curG) or (b <> curB) or (curA <> a) then
81 begin
82 glColor4ub(r, g, b, a);
83 curR := r;
84 curG := g;
85 curB := b;
86 curA := a;
87 end;
88 end;
90 procedure r_Draw_Setup (sw, sh, gw, gh: Integer);
91 begin
92 ASSERT((sw >= 0) and (sh >= 0)); // screen/window size
93 ASSERT((gw >= 0) and (gh >= 0)); // virtual screen size
94 ScreenWidth := sw;
95 ScreenHeight := sh;
96 GameWidth := gw;
97 GameHeight := gh;
98 glScissor(0, 0, sw, sh);
99 glViewport(0, 0, sw, sh);
100 glMatrixMode(GL_PROJECTION);
101 glLoadIdentity;
102 glOrtho(0, gw, gh, 0, 0, 1);
103 glMatrixMode(GL_MODELVIEW);
104 glLoadIdentity;
105 glEnable(GL_SCISSOR_TEST);
106 r_Draw_SetRect(0, 0, gw - 1, gh - 1);
107 end;
109 procedure DrawQuad (x, y, w, h: Integer);
110 begin
111 glBegin(GL_QUADS);
112 glVertex2i(x + w, y);
113 glVertex2i(x, y);
114 glVertex2i(x, y + h);
115 glVertex2i(x + w, y + h);
116 glEnd();
117 end;
119 procedure DrawTextureError (x, y, w, h: Integer);
120 var w2, h2: Integer;
121 begin
122 w2 := w div 2; h2 := h div 2;
123 r_Draw_FillRect(x, y, x + w2, y + h2, 255, 0, 255, 255);
124 r_Draw_FillRect(x + w2, y, x + w, y + h2, 255, 255, 255, 255);
125 r_Draw_FillRect(x + w2, y + h2, x + w, y + h, 255, 0, 255, 255);
126 r_Draw_FillRect(x, y + h2, x + w2, y + h, 255, 255, 255, 255);
127 if (w > 2) and (h > 2) then
128 r_Draw_Rect(x, y, x + w, y + h, 0, 255, 0, 255);
129 end;
131 procedure DrawTile (tile: TGLAtlasNode; x, y, w, h: Integer; flip: Boolean; rr, gg, bb, aa: Byte; blend: Boolean);
132 var nw, nh, ax, bx, ay, by: GLfloat; l, t, r, b: Integer;
133 begin
134 if tile = nil then
135 begin
136 DrawTextureError(x, y, w, h);
137 end
138 else
139 begin
140 nw := tile.base.w;
141 nh := tile.base.h;
142 ax := IfThen(flip, tile.l, tile.r + 1) / nw;
143 bx := IfThen(flip, tile.r + 1, tile.l) / nh;
144 ay := (tile.t) / nw;
145 by := (tile.b + 1) / nh;
146 l := x; t := y; r := x + w; b := y + h;
147 r_Textures_GL_Bind(tile.id);
148 r_Draw_SetColor(rr, gg, bb, aa);
149 r_Draw_EnableTexture2D(true);
150 if blend then glBlendFunc(GL_SRC_ALPHA, GL_ONE) else glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
151 glEnable(GL_BLEND);
152 glBegin(GL_QUADS);
153 glTexCoord2f(ax, ay); glVertex2i(r, t);
154 glTexCoord2f(bx, ay); glVertex2i(l, t);
155 glTexCoord2f(bx, by); glVertex2i(l, b);
156 glTexCoord2f(ax, by); glVertex2i(r, b);
157 glEnd();
158 end
159 end;
161 procedure DrawHWTexture (gltex: GLint; nw, nh, x, y, w, h: Integer; flip: Boolean; rr, gg, bb, aa: Byte; blend: Boolean);
162 var ax, bx, ay, by: GLfloat; l, t, r, b: Integer;
163 begin
164 ax := IfThen(flip, 0, w) / nw;
165 bx := IfThen(flip, w, 0) / nh;
166 ay := 0 / nw;
167 by := h / nh;
168 l := x; t := y; r := x + w; b := y + h;
169 r_Textures_GL_Bind(gltex);
170 r_Draw_SetColor(rr, gg, bb, aa);
171 r_Draw_EnableTexture2D(true);
172 if blend then glBlendFunc(GL_SRC_ALPHA, GL_ONE) else glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
173 glEnable(GL_BLEND);
174 glBegin(GL_QUADS);
175 glTexCoord2f(ax, ay); glVertex2i(r, t);
176 glTexCoord2f(bx, ay); glVertex2i(l, t);
177 glTexCoord2f(bx, by); glVertex2i(l, b);
178 glTexCoord2f(ax, by); glVertex2i(r, b);
179 glEnd();
180 end;
182 procedure r_Draw_Texture (img: TGLTexture; x, y, w, h: Integer; flip: Boolean; r, g, b, a: Byte; blend: Boolean);
183 var i, j, first, last, step: Integer; n: TGLAtlasNode;
184 begin
185 ASSERT(w >= 0);
186 ASSERT(h >= 0);
187 if img = nil then
188 DrawTextureError(x, y, w, h)
189 else
190 begin
191 if flip then first := img.cols - 1 else first := 0;
192 if flip then last := -1 else last := img.cols;
193 if flip then step := -1 else step := +1;
194 glPushMatrix;
195 glTranslatef(x, y, 0);
196 glScalef(w / img.width, h / img.height, 1);
197 for j := 0 to img.lines - 1 do
198 begin
199 i := first;
200 repeat
201 n := img.GetTile(i, j);
202 ASSERT(n <> nil);
203 DrawTile(n, 0, 0, n.width, n.height, flip, r, g, b, a, blend);
204 glTranslatef(n.width, 0, 0);
205 i := i + step;
206 until i = last;
207 glTranslatef(-img.width, n.height, 0);
208 end;
209 glPopMatrix;
210 end
211 end;
213 function r_Draw_IsHWRepeatable (img: TGLTexture): Boolean;
214 var n: TGLAtlasNode; a: TGLAtlas;
215 begin
216 ASSERT(img <> nil);
217 result := false;
218 if (img.cols = 1) and (img.lines = 1) then
219 begin
220 n := img.GetTile(0, 0);
221 if (n.width = img.width) and (n.height = img.height) then
222 begin
223 a := n.base;
224 result := (a.GetWidth() = img.width) and (a.GetHeight() = img.height)
225 end;
226 end;
227 end;
229 procedure r_Draw_TextureRepeat (img: TGLTexture; x, y, w, h: Integer; flip: Boolean; r, g, b, a: Byte; blend: Boolean);
230 var i, j: Integer;
231 begin
232 ASSERT(w >= 0);
233 ASSERT(h >= 0);
234 if img = nil then
235 DrawTextureError(x, y, w, h)
236 else if r_Draw_IsHWRepeatable(img) then
237 DrawHWTexture(img.GetTile(0, 0).base.id, img.width, img.height, x, y, w, h, flip, r, g, b, a, blend)
238 else
239 for j := 0 to (h - 1) div img.height do
240 for i := 0 to (w - 1) div img.width do
241 r_Draw_Texture(img, x + i * img.width, y + j * img.height, img.width, img.height, flip, r, g, b, a, blend);
242 end;
244 procedure r_Draw_TextureRepeatRotate (img: TGLTexture; x, y, w, h: Integer; flip: Boolean; r, g, b, a: Byte; blend: Boolean; rx, ry, angle: Integer);
245 begin
246 ASSERT(w >= 0);
247 ASSERT(h >= 0);
248 if a <> 0 then
249 begin
250 glPushMatrix;
251 glTranslatef(x + rx, y + ry, 0);
252 glRotatef(angle, 0, 0, 1);
253 glTranslatef(-(x + rx), -(y + ry), 0);
254 r_Draw_TextureRepeat(img, x, y, w, h, flip, r, g, b, a, blend);
255 glPopMatrix;
256 end
257 else
258 r_Draw_TextureRepeat(img, x, y, w, h, flip, r, g, b, a, blend);
259 end;
261 procedure r_Draw_MultiTextureRepeat (m: TGLMultiTexture; const anim: TAnimState; backanim: Boolean; x, y, w, h: Integer; flip: Boolean; r, g, b, a: Byte; blend: Boolean);
262 var img: TGLTexture; frame: LongInt;
263 begin
264 ASSERT(anim.IsValid());
265 if m = nil then
266 DrawTextureError(x, y, w, h)
267 else
268 begin
269 g_Anim_GetFrameFromState(anim, backanim, frame);
270 ASSERT(frame >= 0);
271 ASSERT(frame < m.count);
272 img := m.GetTexture(frame);
273 r_Draw_TextureRepeat(img, x, y, w, h, flip, r, g, b, a, blend);
274 end
275 end;
277 procedure r_Draw_MultiTextureRepeatRotate (m: TGLMultiTexture; const anim: TAnimState; backanim: Boolean; x, y, w, h: Integer; flip: Boolean; r, g, b, a: Byte; blend: Boolean; rx, ry, angle: Integer);
278 begin
279 ASSERT(w >= 0);
280 ASSERT(h >= 0);
281 if a <> 0 then
282 begin
283 glPushMatrix;
284 glTranslatef(x + rx, y + ry, 0);
285 glRotatef(angle, 0, 0, 1);
286 glTranslatef(-(x + rx), -(y + ry), 0);
287 r_Draw_MultiTextureRepeat(m, anim, backanim, x, y, w, h, flip, r, g, b, a, blend);
288 glPopMatrix;
289 end
290 else
291 r_Draw_MultiTextureRepeat(m, anim, backanim, x, y, w, h, flip, r, g, b, a, blend);
292 end;
294 procedure r_Draw_Rect (l, t, r, b: Integer; rr, gg, bb, aa: Byte);
295 begin
296 ASSERT(l <= r);
297 ASSERT(t <= b);
298 if (l < r) and (t < b) then
299 begin
300 glEnable(GL_BLEND);
301 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
302 r_Draw_EnableTexture2D(false);
303 r_Draw_SetColor(rr, gg, bb, aa);
304 glBegin(GL_QUADS);
305 (* top *)
306 glVertex2i(l, t);
307 glVertex2i(r, t);
308 glVertex2i(r, t+1);
309 glVertex2i(l, t+1);
310 (* bottom *)
311 glVertex2i(l, b-1);
312 glVertex2i(r, b-1);
313 glVertex2i(r, b);
314 glVertex2i(l, b);
315 (* left *)
316 glVertex2i(l, t+1);
317 glVertex2i(l+1, t+1);
318 glVertex2i(l+1, b-1);
319 glVertex2i(l, b-1);
320 (* right *)
321 glVertex2i(r-1, t+1);
322 glVertex2i(r, t+1);
323 glVertex2i(r, b-1);
324 glVertex2i(r-1, b-1);
325 glEnd;
326 end;
327 end;
329 procedure r_Draw_FillRect (l, t, r, b: Integer; rr, gg, bb, aa: Byte);
330 begin
331 ASSERT(l <= r);
332 ASSERT(t <= b);
333 if (l < r) and (t < b) then
334 begin
335 glEnable(GL_BLEND);
336 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
337 r_Draw_EnableTexture2D(false);
338 r_Draw_SetColor(rr, gg, bb, aa);
339 glBegin(GL_QUADS);
340 glVertex2i(l, t);
341 glVertex2i(r, t);
342 glVertex2i(r, b);
343 glVertex2i(l, b);
344 glEnd;
345 end;
346 end;
348 procedure r_Draw_Filter (l, t, r, b: Integer; rr, gg, bb, aa: Byte);
349 begin
350 ASSERT(l <= r);
351 ASSERT(t <= b);
352 if (l < r) and (t < b) then
353 begin
354 glEnable(GL_BLEND);
355 glBlendFunc(GL_ZERO, GL_SRC_COLOR);
356 r_Draw_EnableTexture2D(false);
357 r_Draw_SetColor(rr, gg, bb, aa);
358 glBegin(GL_QUADS);
359 glVertex2i(l, t);
360 glVertex2i(r, t);
361 glVertex2i(r, b);
362 glVertex2i(l, b);
363 glEnd;
364 end;
365 end;
367 procedure r_Draw_InvertRect (l, t, r, b: Integer; rr, gg, bb, aa: Byte);
368 begin
369 ASSERT(l <= r);
370 ASSERT(t <= b);
371 if (l < r) and (t < b) then
372 begin
373 glEnable(GL_BLEND);
374 glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO);
375 r_Draw_EnableTexture2D(false);
376 r_Draw_SetColor(rr, gg, bb, aa);
377 glBegin(GL_QUADS);
378 glVertex2i(l, t);
379 glVertex2i(r, t);
380 glVertex2i(r, b);
381 glVertex2i(l, b);
382 glEnd;
383 end;
384 end;
386 procedure r_Draw_Text (const text: AnsiString; x, y: Integer; r, g, b, a: Byte; f: TGLFont);
387 var i, xoff, spc: Integer; t: TGLTexture; ch: AnsiChar;
388 begin
389 xoff := x; spc := MAX(0, f.GetSpace());
390 for i := 1 to Length(text) do
391 begin
392 ch := text[i];
393 t := f.GetChar(ch);
394 if t <> nil then
395 r_Draw_Texture(t, xoff, y, t.width, t.height, false, r, g, b, a, false);
396 Inc(xoff, f.GetWidth(ch) + spc);
397 end;
398 end;
400 procedure r_Draw_GetTextSize (const text: AnsiString; f: TGLFont; out w, h: Integer);
401 var i, spc, len: Integer;
402 begin
403 w := 0;
404 h := f.GetMaxHeight();
405 len := Length(text);
406 if len > 0 then
407 begin
408 spc := MAX(0, f.GetSpace());
409 for i := 1 to len - 1 do
410 Inc(w, f.GetWidth(text[i]) + spc);
411 Inc(w, f.GetWidth(text[len]));
412 end;
413 end;
415 procedure r_Draw_SetRect (l, t, r, b: Integer);
416 var x, y, w, h: Integer;
417 begin
418 ASSERT(l <= r);
419 ASSERT(t <= b);
420 x := l * ScreenWidth div GameWidth;
421 y := t * ScreenHeight div GameHeight;
422 w := (r - l + 1) * ScreenWidth div GameWidth;
423 h := (b - t + 1) * ScreenHeight div GameHeight;
424 glScissor(x, ScreenHeight - h - y, w, h);
425 sl := l; st := t; sr := r; sb := b;
426 end;
428 procedure r_Draw_GetRect (out l, t, r, b: Integer);
429 begin
430 l := sl; t := st; r := sr; b := sb;
431 end;
433 end.