DEADSOFTWARE

gl: optimize repeatable textures
[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 implementation
46 uses
47 {$IFDEF USE_GLES1}
48 GLES11,
49 {$ELSE}
50 GL, GLEXT,
51 {$ENDIF}
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;
66 procedure r_Draw_Setup (w, h: Integer);
67 begin
68 ASSERT(w >= 0);
69 ASSERT(h >= 0);
70 ScreenWidth := w;
71 ScreenHeight := h;
72 glScissor(0, 0, w, h);
73 glViewport(0, 0, w, h);
74 glMatrixMode(GL_PROJECTION);
75 glLoadIdentity;
76 glOrtho(0, w, h, 0, 0, 1);
77 glMatrixMode(GL_MODELVIEW);
78 glLoadIdentity;
79 glEnable(GL_SCISSOR_TEST);
80 r_Draw_SetRect(0, 0, w - 1, h - 1);
81 end;
83 procedure DrawQuad (x, y, w, h: Integer);
84 begin
85 glBegin(GL_QUADS);
86 glVertex2i(x + w, y);
87 glVertex2i(x, y);
88 glVertex2i(x, y + h);
89 glVertex2i(x + w, y + h);
90 glEnd();
91 end;
93 procedure DrawTile (tile: TGLAtlasNode; x, y, w, h: Integer; flip: Boolean; rr, gg, bb, aa: Byte; blend: Boolean);
94 var nw, nh, ax, bx, ay, by: GLfloat; l, t, r, b: Integer;
95 begin
96 if tile = nil then
97 begin
98 glColor4ub(rr, gg, bb, aa);
99 if blend then glBlendFunc(GL_SRC_ALPHA, GL_ONE) else glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
100 glDisable(GL_TEXTURE_2D);
101 glEnable(GL_BLEND);
102 DrawQuad(x, y, w, h);
103 end
104 else
105 begin
106 nw := tile.base.w;
107 nh := tile.base.h;
108 ax := IfThen(flip, tile.l, tile.r + 1) / nw;
109 bx := IfThen(flip, tile.r + 1, tile.l) / nh;
110 ay := (tile.t) / nw;
111 by := (tile.b + 1) / nh;
112 l := x; t := y; r := x + w; b := y + h;
113 glBindTexture(GL_TEXTURE_2D, tile.id);
114 glColor4ub(rr, gg, bb, aa);
115 if blend then glBlendFunc(GL_SRC_ALPHA, GL_ONE) else glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
116 glEnable(GL_TEXTURE_2D);
117 glEnable(GL_BLEND);
118 glBegin(GL_QUADS);
119 glTexCoord2f(ax, ay); glVertex2i(r, t);
120 glTexCoord2f(bx, ay); glVertex2i(l, t);
121 glTexCoord2f(bx, by); glVertex2i(l, b);
122 glTexCoord2f(ax, by); glVertex2i(r, b);
123 glEnd();
124 glDisable(GL_TEXTURE_2D);
125 glBindTexture(GL_TEXTURE_2D, 0);
126 end
127 end;
129 procedure DrawHWTexture (gltex: GLint; nw, nh, x, y, w, h: Integer; flip: Boolean; rr, gg, bb, aa: Byte; blend: Boolean);
130 var ax, bx, ay, by: GLfloat; l, t, r, b: Integer;
131 begin
132 ax := IfThen(flip, 0, w) / nw;
133 bx := IfThen(flip, w, 0) / nh;
134 ay := 0 / nw;
135 by := h / nh;
136 l := x; t := y; r := x + w; b := y + h;
137 glBindTexture(GL_TEXTURE_2D, gltex);
138 glColor4ub(rr, gg, bb, aa);
139 if blend then glBlendFunc(GL_SRC_ALPHA, GL_ONE) else glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
140 glEnable(GL_TEXTURE_2D);
141 glEnable(GL_BLEND);
142 glBegin(GL_QUADS);
143 glTexCoord2f(ax, ay); glVertex2i(r, t);
144 glTexCoord2f(bx, ay); glVertex2i(l, t);
145 glTexCoord2f(bx, by); glVertex2i(l, b);
146 glTexCoord2f(ax, by); glVertex2i(r, b);
147 glEnd();
148 glDisable(GL_TEXTURE_2D);
149 glBindTexture(GL_TEXTURE_2D, 0);
150 end;
152 procedure r_Draw_Texture (img: TGLTexture; x, y, w, h: Integer; flip: Boolean; r, g, b, a: Byte; blend: Boolean);
153 var i, j, first, last, step: Integer; n: TGLAtlasNode;
154 begin
155 ASSERT(w >= 0);
156 ASSERT(h >= 0);
157 if img = nil then
158 DrawTile(nil, x, y, w, h, flip, NTR, NTB, NTG, NTA, blend)
159 else
160 begin
161 if flip then first := img.cols - 1 else first := 0;
162 if flip then last := -1 else last := img.cols;
163 if flip then step := -1 else step := +1;
164 glPushMatrix;
165 glTranslatef(x, y, 0);
166 glScalef(w / img.width, h / img.height, 1);
167 for j := 0 to img.lines - 1 do
168 begin
169 i := first;
170 repeat
171 n := img.GetTile(i, j);
172 ASSERT(n <> nil);
173 DrawTile(n, 0, 0, n.width, n.height, flip, r, g, b, a, blend);
174 glTranslatef(n.width, 0, 0);
175 i := i + step;
176 until i = last;
177 glTranslatef(-img.width, n.height, 0);
178 end;
179 glPopMatrix;
180 end
181 end;
183 function r_Draw_IsHWRepeatable (img: TGLTexture): Boolean;
184 var n: TGLAtlasNode; a: TGLAtlas;
185 begin
186 ASSERT(img <> nil);
187 result := false;
188 if (img.cols = 1) and (img.lines = 1) then
189 begin
190 n := img.GetTile(0, 0);
191 if (n.width = img.width) and (n.height = img.height) then
192 begin
193 a := n.base;
194 result := (a.GetWidth() = img.width) and (a.GetHeight() = img.height)
195 end;
196 end;
197 end;
199 procedure r_Draw_TextureRepeat (img: TGLTexture; x, y, w, h: Integer; flip: Boolean; r, g, b, a: Byte; blend: Boolean);
200 var i, j: Integer;
201 begin
202 ASSERT(w >= 0);
203 ASSERT(h >= 0);
204 if img = nil then
205 r_Draw_Texture(nil, x, y, w, h, flip, NTR, NTG, NTB, NTB, blend)
206 else if r_Draw_IsHWRepeatable(img) then
207 DrawHWTexture(img.GetTile(0, 0).base.id, img.width, img.height, x, y, w, h, flip, r, g, b, a, blend)
208 else
209 for j := 0 to (h - 1) div img.height do
210 for i := 0 to (w - 1) div img.width do
211 r_Draw_Texture(img, x + i * img.width, y + j * img.height, img.width, img.height, flip, r, g, b, a, blend);
212 end;
214 procedure r_Draw_TextureRepeatRotate (img: TGLTexture; x, y, w, h: Integer; flip: Boolean; r, g, b, a: Byte; blend: Boolean; rx, ry, angle: Integer);
215 begin
216 ASSERT(w >= 0);
217 ASSERT(h >= 0);
218 if a <> 0 then
219 begin
220 glPushMatrix;
221 glTranslatef(x + rx, y + ry, 0);
222 glRotatef(angle, 0, 0, 1);
223 glTranslatef(-(x + rx), -(y + ry), 0);
224 r_Draw_TextureRepeat(img, x, y, w, h, flip, r, g, b, a, blend);
225 glPopMatrix;
226 end
227 else
228 r_Draw_TextureRepeat(img, x, y, w, h, flip, r, g, b, a, blend);
229 end;
231 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);
232 var img: TGLTexture; frame: LongInt;
233 begin
234 ASSERT(anim.IsValid());
235 if m = nil then
236 r_Draw_TextureRepeat(nil, x, y, w, h, flip, NTR, NTG, NTB, NTB, blend)
237 else
238 begin
239 g_Anim_GetFrameFromState(anim, backanim, frame);
240 ASSERT(frame >= 0);
241 ASSERT(frame < m.count);
242 img := m.GetTexture(frame);
243 r_Draw_TextureRepeat(img, x, y, w, h, flip, r, g, b, a, blend);
244 end
245 end;
247 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);
248 begin
249 ASSERT(w >= 0);
250 ASSERT(h >= 0);
251 if a <> 0 then
252 begin
253 glPushMatrix;
254 glTranslatef(x + rx, y + ry, 0);
255 glRotatef(angle, 0, 0, 1);
256 glTranslatef(-(x + rx), -(y + ry), 0);
257 r_Draw_MultiTextureRepeat(m, anim, backanim, x, y, w, h, flip, r, g, b, a, blend);
258 glPopMatrix;
259 end
260 else
261 r_Draw_MultiTextureRepeat(m, anim, backanim, x, y, w, h, flip, r, g, b, a, blend);
262 end;
264 procedure r_Draw_Filter (l, t, r, b: Integer; rr, gg, bb, aa: Byte);
265 begin
266 ASSERT(r >= l);
267 ASSERT(b >= t);
268 glEnable(GL_BLEND);
269 glBlendFunc(GL_ZERO, GL_SRC_COLOR);
270 glDisable(GL_TEXTURE_2D);
271 glColor4ub(rr, gg, bb, aa);
272 glBegin(GL_QUADS);
273 glVertex2i(l, t);
274 glVertex2i(r, t);
275 glVertex2i(r, b);
276 glVertex2i(l, b);
277 glEnd;
278 end;
280 procedure r_Draw_Rect (l, t, r, b: Integer; rr, gg, bb, aa: Byte);
281 begin
282 ASSERT(r >= l);
283 ASSERT(b >= t);
284 glEnable(GL_BLEND);
285 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
286 glDisable(GL_TEXTURE_2D);
287 glColor4ub(rr, gg, bb, aa);
288 glBegin(GL_LINE_LOOP);
290 glVertex2i(l, t);
291 glVertex2i(r, t);
292 glVertex2i(r, b);
293 glVertex2i(l, b);
295 glVertex2f(l + 0.5, t + 0.5);
296 glVertex2f(r - 0.5, t + 0.5);
297 glVertex2f(r - 0.5, b - 0.5);
298 glVertex2f(l + 0.5, b - 0.5);
299 glEnd;
300 end;
302 procedure r_Draw_FillRect (l, t, r, b: Integer; rr, gg, bb, aa: Byte);
303 begin
304 ASSERT(r >= l);
305 ASSERT(b >= t);
306 glEnable(GL_BLEND);
307 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
308 glDisable(GL_TEXTURE_2D);
309 glColor4ub(rr, gg, bb, aa);
310 glBegin(GL_QUADS);
312 glVertex2i(l, t);
313 glVertex2i(r, t);
314 glVertex2i(r, b);
315 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);
323 glVertex2f(l + 0, t + 0);
324 glVertex2f(r + 0.75, t + 0);
325 glVertex2f(r + 0.75, b + 0.75);
326 glVertex2f(l + 0, b + 0.75);
327 glEnd;
328 end;
330 procedure r_Draw_InvertRect (l, t, r, b: Integer; rr, gg, bb, aa: Byte);
331 begin
332 ASSERT(r >= l);
333 ASSERT(b >= t);
334 glEnable(GL_BLEND);
335 glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO);
336 glDisable(GL_TEXTURE_2D);
337 glColor4ub(rr, gg, bb, aa);
338 glBegin(GL_QUADS);
339 glVertex2i(l, t);
340 glVertex2i(r, t);
341 glVertex2i(r, b);
342 glVertex2i(l, b);
343 glEnd;
344 end;
346 procedure r_Draw_Text (const text: AnsiString; x, y: Integer; r, g, b, a: Byte; f: TGLFont);
347 var i, xoff, spc: Integer; t: TGLTexture; ch: AnsiChar;
348 begin
349 xoff := x; spc := MAX(0, f.GetSpace());
350 for i := 1 to Length(text) do
351 begin
352 ch := text[i];
353 t := f.GetChar(ch);
354 if t <> nil then
355 r_Draw_Texture(t, xoff, y, t.width, t.height, false, r, g, b, a, false);
356 Inc(xoff, f.GetWidth(ch) + spc);
357 end;
358 end;
360 procedure r_Draw_GetTextSize (const text: AnsiString; f: TGLFont; out w, h: Integer);
361 var i, spc, len: Integer;
362 begin
363 w := 0;
364 h := f.GetMaxHeight();
365 len := Length(text);
366 if len > 0 then
367 begin
368 spc := MAX(0, f.GetSpace());
369 for i := 1 to len - 1 do
370 Inc(w, f.GetWidth(text[i]) + spc);
371 Inc(w, f.GetWidth(text[len]));
372 end;
373 end;
375 procedure r_Draw_SetRect (l, t, r, b: Integer);
376 var w, h: Integer;
377 begin
378 ASSERT(l <= r);
379 ASSERT(t <= b);
380 w := r - l + 1;
381 h := b - t + 1;
382 glScissor(l, ScreenHeight - h - t, w, h);
383 sl := l; st := t; sr := r; sb := b;
384 end;
386 procedure r_Draw_GetRect (out l, t, r, b: Integer);
387 begin
388 l := sl; t := st; r := sr; b := sb;
389 end;
391 end.