DEADSOFTWARE

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