DEADSOFTWARE

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