DEADSOFTWARE

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