TGX 1.0.1
A tiny 2D/3D graphics library optimized for 32 bits microcontrollers.
Loading...
Searching...
No Matches
Shaders.h
Go to the documentation of this file.
1
5//
6// Copyright 2020 Arvind Singh
7//
8// This library is free software; you can redistribute it and/or
9// modify it under the terms of the GNU Lesser General Public
10// License as published by the Free Software Foundation; either
11// version 2.1 of the License, or (at your option) any later version.
12//
13// This library is distributed in the hope that it will be useful,
14// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU
16// Lesser General Public License for more details.
17//
18// You should have received a copy of the GNU Lesser General Public
19// License along with this library; If not, see <http://www.gnu.org/licenses/>.
20#ifndef _TGX_SHADERS_H_
21#define _TGX_SHADERS_H_
22
23
24// only C++, no plain C
25#ifdef __cplusplus
26
27
28#include "ShaderParams.h"
29
30namespace tgx
31{
32
34 inline TGX_INLINE int shaderclip(int v, int maxv)
35 {
36 return ((v < 0) ? 0 : ((v > maxv) ? maxv : v));
37 }
38
39
40
44 template<typename color_t, typename ZBUFFER_t>
45 void shader_test(const int32_t& offset, const int32_t& lx, const int32_t& ly,
46 const int32_t& dx1, const int32_t& dy1, int32_t O1, const tgx::RasterizerVec4& fP1,
47 const int32_t& dx2, const int32_t& dy2, int32_t O2, const tgx::RasterizerVec4& fP2,
48 const int32_t& dx3, const int32_t& dy3, int32_t O3, const tgx::RasterizerVec4& fP3,
49 const tgx::RasterizerParams<color_t, color_t, ZBUFFER_t>& data)
50 {
51 color_t col = (color_t)tgx::RGB32_Red; //data.facecolor;
52 color_t* buf = data.im->data() + offset;
53 const int32_t stride = data.im->stride();
54 for (int y = 0; y < ly; y++)
55 {
56 for (int x = 0; x < lx; x++)
57 {
58 const int32_t o1 = O1 + dx1 * x + dy1 * y;
59 const int32_t o2 = O2 + dx2 * x + dy2 * y;
60 const int32_t o3 = O3 + dx3 * x + dy3 * y;
61 if ((o1 >= 0) && (o2 >= 0) && (o3 >= 0))
62 {
63 buf[x + stride * y].blend256(col, 128);
64 }
65 }
66 }
67 }
68
69
73 template<typename color_t, typename ZBUFFER_t>
74 void shader_Flat(const int32_t& offset, const int32_t& lx, const int32_t& ly,
75 const int32_t& dx1, const int32_t& dy1, int32_t O1, const RasterizerVec4& fP1,
76 const int32_t& dx2, const int32_t& dy2, int32_t O2, const RasterizerVec4& fP2,
77 const int32_t& dx3, const int32_t& dy3, int32_t O3, const RasterizerVec4& fP3,
78 const RasterizerParams<color_t, color_t, ZBUFFER_t>& data)
79 {
80 color_t col = (color_t)data.facecolor;
81 color_t* buf = data.im->data() + offset;
82 const int32_t stride = data.im->stride();
83
84 const uintptr_t end = (uintptr_t)(buf + (ly * stride));
85
86 while ((uintptr_t)(buf) < end)
87 { // iterate over scanlines
88 int32_t bx = 0; // start offset
89 if (O1 < 0)
90 {
91 // we know that dx1 > 0
92 bx = (-O1 + dx1 - 1) / dx1; // first index where it becomes positive
93 }
94 if (O2 < 0)
95 {
96 if (dx2 <= 0)
97 {
98 if (dy2 <= 0) return;
99 const int32_t by = (-O2 + dy2 - 1) / dy2;
100 O1 += (by * dy1);
101 O2 += (by * dy2);
102 O3 += (by * dy3);
103 const int32_t offs = by * stride;
104 buf += offs;
105 continue;
106 }
107 bx = max(bx, ((-O2 + dx2 - 1) / dx2));
108 }
109 if (O3 < 0)
110 {
111 if (dx3 <= 0)
112 {
113 if (dy3 <= 0) return;
114 const int32_t by = (-O3 + dy3 - 1) / dy3;
115 O1 += (by * dy1);
116 O2 += (by * dy2);
117 O3 += (by * dy3);
118 const int32_t offs = by * stride;
119 buf += offs;
120 continue;
121 }
122 bx = max(bx, ((-O3 + dx3 - 1) / dx3));
123 }
124
125 int32_t C2 = O2 + (dx2 * bx);
126 int32_t C3 = O3 + (dx3 * bx);
127 while ((bx < lx) && ((C2 | C3) >= 0))
128 {
129 buf[bx] = col;
130 //buf[bx].blend256(col, 128) // for testing.
131 C2 += dx2;
132 C3 += dx3;
133 bx++;
134 }
135
136 O1 += dy1;
137 O2 += dy2;
138 O3 += dy3;
139 buf += stride;
140 }
141 }
142
143
144
148 template<typename color_t, typename ZBUFFER_t>
149 void shader_Gouraud(const int32_t& offset, const int32_t& lx, const int32_t& ly,
150 const int32_t& dx1, const int32_t& dy1, int32_t O1, const RasterizerVec4& fP1,
151 const int32_t& dx2, const int32_t& dy2, int32_t O2, const RasterizerVec4& fP2,
152 const int32_t& dx3, const int32_t& dy3, int32_t O3, const RasterizerVec4& fP3,
153 const RasterizerParams<color_t, color_t, ZBUFFER_t>& data)
154 {
155 color_t* buf = data.im->data() + offset;
156 const int32_t stride = data.im->stride();
157
158 const color_t col1 = (color_t)fP1.color;
159 const color_t col2 = (color_t)fP2.color;
160 const color_t col3 = (color_t)fP3.color;
161
162 const uintptr_t end = (uintptr_t)(buf + (ly * stride));
163 const int32_t pa = O1 + O2 + O3;
164 const int32_t E = ((pa == 0) ? 1 : 0);
165 const int32_t aera = pa + E;
166 const int shiftC = (aera > (1 << 22)) ? 10 : 0; // prevent overflow during color interpolation
167
168 while ((uintptr_t)(buf) < end)
169 { // iterate over scanlines
170 int32_t bx = 0; // start offset
171 if (O1 < 0)
172 {
173 // we know that dx1 > 0
174 bx = (-O1 + dx1 - 1) / dx1; // first index where it becomes positive
175 }
176 if (O2 < 0)
177 {
178 if (dx2 <= 0)
179 {
180 if (dy2 <= 0) return;
181 const int32_t by = (-O2 + dy2 - 1) / dy2;
182 O1 += (by * dy1);
183 O2 += (by * dy2);
184 O3 += (by * dy3);
185 const int32_t offs = by * stride;
186 buf += offs;
187 continue;
188 }
189 bx = max(bx, ((-O2 + dx2 - 1) / dx2));
190 }
191 if (O3 < 0)
192 {
193 if (dx3 <= 0)
194 {
195 if (dy3 <= 0) return;
196 const int32_t by = (-O3 + dy3 - 1) / dy3;
197 O1 += (by * dy1);
198 O2 += (by * dy2);
199 O3 += (by * dy3);
200 const int32_t offs = by * stride;
201 buf += offs;
202 continue;
203 }
204 bx = max(bx, ((-O3 + dx3 - 1) / dx3));
205 }
206
207 int32_t C2 = O2 + (dx2 * bx);
208 int32_t C3 = O3 + (dx3 * bx);
209 while ((bx < lx) && ((C2 | C3) >= 0))
210 {
211 buf[bx] = interpolateColorsTriangle(col2, C2 >> shiftC, col3, C3 >> shiftC, col1, aera >> shiftC);
212 C2 += dx2;
213 C3 += dx3;
214 bx++;
215 }
216
217 O1 += dy1;
218 O2 += dy2;
219 O3 += dy3;
220 buf += stride;
221 }
222 }
223
224
225
229 template<typename color_t, typename ZBUFFER_t, bool TEXTURE_BILINEAR, bool TEXTURE_WRAP>
230 void shader_Flat_Texture(const int32_t& offset, const int32_t& lx, const int32_t& ly,
231 const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4& fP1,
232 const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4& fP2,
233 const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4& fP3,
234 const RasterizerParams<color_t, color_t, ZBUFFER_t>& data)
235 {
236 color_t* buf = data.im->data() + offset;
237 const int32_t stride = data.im->stride();
238
239 const uintptr_t end = (uintptr_t)(buf + (ly * stride));
240 const int32_t pa = O1 + O2 + O3;
241 const int32_t E = ((pa == 0) ? 1 : 0);
242 const int32_t aera = pa + E;
243
244
245 const float invaera = fast_inv((float)aera);
246 const float fP1a = fP1.w * invaera;
247 const float fP2a = fP2.w * invaera;
248 const float fP3a = fP3.w * invaera;
249
250 const float dw = (dx1 * fP1a) + (dx2 * fP2a) + (dx3 * fP3a);
251
252 const RGBf& cf = (RGBf)data.facecolor;
253 const int fPR = (int)(256 * cf.R);
254 const int fPG = (int)(256 * cf.G);
255 const int fPB = (int)(256 * cf.B);
256
257 // the texture coord
258 fVec2 T1 = fP1.T;
259 fVec2 T2 = fP2.T;
260 fVec2 T3 = fP3.T;
261
262 const color_t* tex = data.tex->data();
263 const int32_t texsize_x = data.tex->width();
264 const int32_t texsize_y = data.tex->height();
265 const int32_t texsize_x_mm = texsize_x - 1;
266 const int32_t texsize_y_mm = texsize_y - 1;
267 const int32_t texstride = data.tex->stride();
268
269 // divide the texture coord by z * aera
270 T1 *= fP1a;
271 T2 *= fP2a;
272 T3 *= fP3a;
273 T1.x *= texsize_x;
274 T2.x *= texsize_x;
275 T3.x *= texsize_x;
276 T1.y *= texsize_y;
277 T2.y *= texsize_y;
278 T3.y *= texsize_y;
279
280 const float dtx = ((T1.x * dx1) + (T2.x * dx2) + (T3.x * dx3));
281 const float dty = ((T1.y * dx1) + (T2.y * dx2) + (T3.y * dx3));
282
283 while ((uintptr_t)(buf) < end)
284 { // iterate over scanlines
285 int32_t bx = 0; // start offset
286 if (O1 < 0)
287 {
288 // we know that dx1 > 0
289 bx = (-O1 + dx1 - 1) / dx1; // first index where it becomes positive
290 }
291 if (O2 < 0)
292 {
293 if (dx2 <= 0)
294 {
295 if (dy2 <= 0) return;
296 const int32_t by = (-O2 + dy2 - 1) / dy2;
297 O1 += (by * dy1);
298 O2 += (by * dy2);
299 O3 += (by * dy3);
300 const int32_t offs = by * stride;
301 buf += offs;
302 continue;
303 }
304 bx = max(bx, ((-O2 + dx2 - 1) / dx2));
305 }
306 if (O3 < 0)
307 {
308 if (dx3 <= 0)
309 {
310 if (dy3 <= 0) return;
311 const int32_t by = (-O3 + dy3 - 1) / dy3;
312 O1 += (by * dy1);
313 O2 += (by * dy2);
314 O3 += (by * dy3);
315 const int32_t offs = by * stride;
316 buf += offs;
317 continue;
318 }
319 bx = max(bx, ((-O3 + dx3 - 1) / dx3));
320 }
321
322 int32_t C1 = O1 + (dx1 * bx) + E;
323 int32_t C2 = O2 + (dx2 * bx);
324 int32_t C3 = O3 + (dx3 * bx);
325 float cw = ((C1 * fP1a) + (C2 * fP2a) + (C3 * fP3a));
326
327 float tx = ((T1.x * C1) + (T2.x * C2) + (T3.x * C3));
328 float ty = ((T1.y * C1) + (T2.y * C2) + (T3.y * C3));
329
330 while ((bx < lx) && ((C2 | C3) >= 0))
331 {
332 const float icw = fast_inv(cw);
333
334 color_t col;
335 if (TEXTURE_BILINEAR)
336 {
337 const float xx = tx * icw;
338 const float yy = ty * icw;
339 const int ttx = (int)floorf(xx);
340 const int tty = (int)floorf(yy);
341 const float ax = xx - ttx;
342 const float ay = yy - tty;
343 const int minx = (TEXTURE_WRAP ? (ttx & (texsize_x_mm)) : shaderclip(ttx, texsize_x_mm));
344 const int maxx = (TEXTURE_WRAP ? ((ttx + 1) & (texsize_x_mm)) : shaderclip(ttx + 1, texsize_x_mm));
345 const int miny = (TEXTURE_WRAP ? ((tty & (texsize_y_mm))*texstride) : shaderclip(tty, texsize_y_mm) * texstride);
346 const int maxy = (TEXTURE_WRAP ? (((tty + 1) & (texsize_y_mm))*texstride) : shaderclip(tty + 1, texsize_y_mm) * texstride);
347 col = interpolateColorsBilinear(tex[minx + miny], tex[maxx + miny], tex[minx + maxy], tex[maxx + maxy], ax, ay);
348 }
349 else
350 {
351 const int ttx = (TEXTURE_WRAP ? ((int)((tx * icw))) & (texsize_x_mm) : shaderclip((int)(tx * icw), texsize_x_mm));
352 const int tty = (TEXTURE_WRAP ? ((int)((ty * icw))) & (texsize_y_mm) : shaderclip((int)(ty * icw), texsize_y_mm));
353 col = tex[ttx + (tty)*texstride];
354 }
355
356 col.mult256(fPR, fPG, fPB);
357 buf[bx] = col;
358
359 C2 += dx2;
360 C3 += dx3;
361 cw += dw;
362
363 tx += dtx;
364 ty += dty;
365
366 bx++;
367 }
368
369 O1 += dy1;
370 O2 += dy2;
371 O3 += dy3;
372 buf += stride;
373 }
374 }
375
376
377
381 template<typename color_t, typename ZBUFFER_t, bool TEXTURE_BILINEAR, bool TEXTURE_WRAP>
382 void shader_Gouraud_Texture(const int32_t& offset, const int32_t& lx, const int32_t& ly,
383 const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4& fP1,
384 const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4& fP2,
385 const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4& fP3,
386 const RasterizerParams<color_t, color_t, ZBUFFER_t>& data)
387 {
388
389 color_t* buf = data.im->data() + offset;
390 const int32_t stride = data.im->stride();
391
392 const uintptr_t end = (uintptr_t)(buf + (ly * stride));
393 const int32_t pa = O1 + O2 + O3;
394 const int32_t E = ((pa == 0) ? 1 : 0);
395 const int32_t aera = pa + E;
396
397 const float invaera = fast_inv((float)aera);
398 const float fP1a = fP1.w * invaera;
399 const float fP2a = fP2.w * invaera;
400 const float fP3a = fP3.w * invaera;
401
402 const float dw = (dx1 * fP1a) + (dx2 * fP2a) + (dx3 * fP3a);
403
404 const RGBf& cf1 = (RGBf)fP1.color;
405 const RGBf& cf2 = (RGBf)fP2.color;
406 const RGBf& cf3 = (RGBf)fP3.color;
407 const int fP1R = (int)(256 * cf1.R);
408 const int fP1G = (int)(256 * cf1.G);
409 const int fP1B = (int)(256 * cf1.B);
410 const int fP21R = (int)(256 * (cf2.R - cf1.R));
411 const int fP21G = (int)(256 * (cf2.G - cf1.G));
412 const int fP21B = (int)(256 * (cf2.B - cf1.B));
413 const int fP31R = (int)(256 * (cf3.R - cf1.R));
414 const int fP31G = (int)(256 * (cf3.G - cf1.G));
415 const int fP31B = (int)(256 * (cf3.B - cf1.B));
416
417 // the texture coord
418 fVec2 T1 = fP1.T;
419 fVec2 T2 = fP2.T;
420 fVec2 T3 = fP3.T;
421
422 const color_t* tex = data.tex->data();
423 const int32_t texsize_x = data.tex->width();
424 const int32_t texsize_y = data.tex->height();
425 const int32_t texsize_x_mm = texsize_x - 1;
426 const int32_t texsize_y_mm = texsize_y - 1;
427 const int32_t texstride = data.tex->stride();
428
429 // divide the texture coord by z * aera
430 T1 *= fP1a;
431 T2 *= fP2a;
432 T3 *= fP3a;
433 T1.x *= texsize_x;
434 T2.x *= texsize_x;
435 T3.x *= texsize_x;
436 T1.y *= texsize_y;
437 T2.y *= texsize_y;
438 T3.y *= texsize_y;
439
440
441 const float dtx = ((T1.x * dx1) + (T2.x * dx2) + (T3.x * dx3));
442 const float dty = ((T1.y * dx1) + (T2.y * dx2) + (T3.y * dx3));
443
444 while ((uintptr_t)(buf) < end)
445 { // iterate over scanlines
446 int32_t bx = 0; // start offset
447 if (O1 < 0)
448 {
449 // we know that dx1 > 0
450 bx = (-O1 + dx1 - 1) / dx1; // first index where it becomes positive
451 }
452 if (O2 < 0)
453 {
454 if (dx2 <= 0)
455 {
456 if (dy2 <= 0) return;
457 const int32_t by = (-O2 + dy2 - 1) / dy2;
458 O1 += (by * dy1);
459 O2 += (by * dy2);
460 O3 += (by * dy3);
461 const int32_t offs = by * stride;
462 buf += offs;
463 continue;
464 }
465 bx = max(bx, ((-O2 + dx2 - 1) / dx2));
466 }
467 if (O3 < 0)
468 {
469 if (dx3 <= 0)
470 {
471 if (dy3 <= 0) return;
472 const int32_t by = (-O3 + dy3 - 1) / dy3;
473 O1 += (by * dy1);
474 O2 += (by * dy2);
475 O3 += (by * dy3);
476 const int32_t offs = by * stride;
477 buf += offs;
478 continue;
479 }
480 bx = max(bx, ((-O3 + dx3 - 1) / dx3));
481 }
482
483 int32_t C1 = O1 + (dx1 * bx) + E;
484 int32_t C2 = O2 + (dx2 * bx);
485 int32_t C3 = O3 + (dx3 * bx);
486 float cw = ((C1 * fP1a) + (C2 * fP2a) + (C3 * fP3a));
487
488 float tx = ((T1.x * C1) + (T2.x * C2) + (T3.x * C3));
489 float ty = ((T1.y * C1) + (T2.y * C2) + (T3.y * C3));
490
491 while ((bx < lx) && ((C2 | C3) >= 0))
492 {
493 const float icw = fast_inv(cw);
494
495 color_t col;
496 if (TEXTURE_BILINEAR)
497 {
498 const float xx = tx * icw;
499 const float yy = ty * icw;
500 const int ttx = (int)floorf(xx);
501 const int tty = (int)floorf(yy);
502 const float ax = xx - ttx;
503 const float ay = yy - tty;
504 const int minx = (TEXTURE_WRAP ? (ttx & (texsize_x_mm)) : shaderclip(ttx, texsize_x_mm));
505 const int maxx = (TEXTURE_WRAP ? ((ttx + 1) & (texsize_x_mm)) : shaderclip(ttx + 1, texsize_x_mm));
506 const int miny = (TEXTURE_WRAP ? ((tty & (texsize_y_mm)) * texstride) : shaderclip(tty, texsize_y_mm) * texstride);
507 const int maxy = (TEXTURE_WRAP ? (((tty + 1) & (texsize_y_mm)) * texstride) : shaderclip(tty + 1, texsize_y_mm) * texstride);
508 col = interpolateColorsBilinear(tex[minx + miny], tex[maxx + miny], tex[minx + maxy], tex[maxx + maxy], ax, ay);
509 }
510 else
511 {
512 const int ttx = (TEXTURE_WRAP ? ((int)((tx * icw))) & (texsize_x_mm) : shaderclip((int)(tx * icw), texsize_x_mm));
513 const int tty = (TEXTURE_WRAP ? ((int)((ty * icw))) & (texsize_y_mm) : shaderclip((int)(ty * icw), texsize_y_mm));
514 col = tex[ttx + (tty)*texstride];
515 }
516
517 const int r = fP1R + ((C2 * fP21R + C3 * fP31R) / aera);
518 const int g = fP1G + ((C2 * fP21G + C3 * fP31G) / aera);
519 const int b = fP1B + ((C2 * fP21B + C3 * fP31B) / aera);
520
521 col.mult256(r, g, b);
522 buf[bx] = col;
523
524 C2 += dx2;
525 C3 += dx3;
526 cw += dw;
527
528 tx += dtx;
529 ty += dty;
530
531 bx++;
532 }
533
534 O1 += dy1;
535 O2 += dy2;
536 O3 += dy3;
537 buf += stride;
538 }
539 }
540
541
542
546 template<typename color_t, typename ZBUFFER_t>
547 void shader_Flat_Zbuffer(const int32_t offset, const int32_t& lx, const int32_t& ly,
548 const int32_t& dx1, const int32_t& dy1, int32_t O1, const RasterizerVec4& fP1,
549 const int32_t& dx2, const int32_t& dy2, int32_t O2, const RasterizerVec4& fP2,
550 const int32_t& dx3, const int32_t& dy3, int32_t O3, const RasterizerVec4& fP3,
551 const RasterizerParams<color_t, color_t, ZBUFFER_t>& data)
552 {
553 const color_t col = (color_t)data.facecolor;
554 color_t* buf = data.im->data() + offset;
555 ZBUFFER_t * zbuf = data.zbuf + offset;
556
557 const int32_t stride = data.im->stride();
558 const int32_t zstride = data.im->lx();
559
560 const uintptr_t end = (uintptr_t)(buf + (ly * stride));
561 const int32_t pa = O1 + O2 + O3;
562 const int32_t E = ((pa == 0) ? 1 : 0);
563 const int32_t aera = pa + E;
564
565 const float wa = data.wa;
566 const float wb = data.wb;
567 const float invaera = fast_inv((float)aera);
568 const float invaera_wa = invaera * wa;
569 const float fP1a = fP1.w * invaera_wa;
570 const float fP2a = fP2.w * invaera_wa;
571 const float fP3a = fP3.w * invaera_wa;
572 const float dw = (dx1 * fP1a) + (dx2 * fP2a) + (dx3 * fP3a);
573
574 while ((uintptr_t)(buf) < end)
575 { // iterate over scanlines
576 int32_t bx = 0; // start offset
577 if (O1 < 0)
578 {
579 // we know that dx1 > 0
580 bx = (-O1 + dx1 - 1) / dx1; // first index where it becomes positive
581 }
582 if (O2 < 0)
583 {
584 if (dx2 <= 0)
585 {
586 if (dy2 <= 0) return;
587 const int32_t by = (-O2 + dy2 - 1) / dy2;
588 O1 += (by * dy1);
589 O2 += (by * dy2);
590 O3 += (by * dy3);
591 const int32_t offs = by * stride;
592 buf += offs;
593 zbuf += offs;
594 continue;
595 }
596 bx = max(bx, ((-O2 + dx2 - 1) / dx2));
597 }
598 if (O3 < 0)
599 {
600 if (dx3 <= 0)
601 {
602 if (dy3 <= 0) return;
603 const int32_t by = (-O3 + dy3 - 1) / dy3;
604 O1 += (by * dy1);
605 O2 += (by * dy2);
606 O3 += (by * dy3);
607 const int32_t offs = by * stride;
608 buf += offs;
609 zbuf += offs;
610 continue;
611 }
612 bx = max(bx, ((-O3 + dx3 - 1) / dx3));
613 }
614
615 const int32_t C1 = O1 + (dx1 * bx) + E;
616 int32_t C2 = O2 + (dx2 * bx);
617 int32_t C3 = O3 + (dx3 * bx);
618 float cw = ((C1 * fP1a) + (C2 * fP2a) + (C3 * fP3a)) + wb;
619
620 while ((bx < lx) && ((C2 | C3) >= 0))
621 {
622 ZBUFFER_t& W = zbuf[bx];
623 const ZBUFFER_t aa = (ZBUFFER_t)(cw);
624 if (W < aa)
625 {
626 W = aa;
627 buf[bx] = col;
628 }
629 C2 += dx2;
630 C3 += dx3;
631 cw += dw;
632 bx++;
633 }
634
635 O1 += dy1;
636 O2 += dy2;
637 O3 += dy3;
638 buf += stride;
639 zbuf += zstride;
640 }
641 }
642
643
644
648 template<typename color_t, typename ZBUFFER_t>
649 void shader_Gouraud_Zbuffer(const int32_t& offset, const int32_t& lx, const int32_t& ly,
650 const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4& fP1,
651 const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4& fP2,
652 const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4& fP3,
653 const RasterizerParams<color_t, color_t, ZBUFFER_t>& data)
654 {
655 color_t* buf = data.im->data() + offset;
656 ZBUFFER_t* zbuf = data.zbuf + offset;
657
658
659 const int32_t stride = data.im->stride();
660 const int32_t zstride = data.im->lx();
661
662 const color_t col1 = (color_t)fP1.color;
663 const color_t col2 = (color_t)fP2.color;
664 const color_t col3 = (color_t)fP3.color;
665
666 const uintptr_t end = (uintptr_t)(buf + (ly * stride));
667 const int32_t pa = O1 + O2 + O3;
668 const int32_t E = ((pa == 0) ? 1 : 0);
669 const int32_t aera = pa + E;
670 const int shiftC = (aera > (1 << 22)) ? 10 : 0; // prevent overflow during color interpolation
671
672 const float wa = data.wa;
673 const float wb = data.wb;
674 const float invaera = fast_inv((float)aera);
675 const float invaera_wa = invaera * wa;
676 const float fP1a = fP1.w * invaera_wa;
677 const float fP2a = fP2.w * invaera_wa;
678 const float fP3a = fP3.w * invaera_wa;
679 const float dw = (dx1 * fP1a) + (dx2 * fP2a) + (dx3 * fP3a);
680
681 while ((uintptr_t)(buf) < end)
682 { // iterate over scanlines
683 int32_t bx = 0; // start offset
684 if (O1 < 0)
685 {
686 // we know that dx1 > 0
687 bx = (-O1 + dx1 - 1) / dx1; // first index where it becomes positive
688 }
689 if (O2 < 0)
690 {
691 if (dx2 <= 0)
692 {
693 if (dy2 <= 0) return;
694 const int32_t by = (-O2 + dy2 - 1) / dy2;
695 O1 += (by * dy1);
696 O2 += (by * dy2);
697 O3 += (by * dy3);
698 const int32_t offs = by * stride;
699 buf += offs;
700 zbuf += offs;
701 continue;
702 }
703 bx = max(bx, ((-O2 + dx2 - 1) / dx2));
704 }
705 if (O3 < 0)
706 {
707 if (dx3 <= 0)
708 {
709 if (dy3 <= 0) return;
710 const int32_t by = (-O3 + dy3 - 1) / dy3;
711 O1 += (by * dy1);
712 O2 += (by * dy2);
713 O3 += (by * dy3);
714 const int32_t offs = by * stride;
715 buf += offs;
716 zbuf += offs;
717 continue;
718 }
719 bx = max(bx, ((-O3 + dx3 - 1) / dx3));
720 }
721
722 const int32_t C1 = O1 + (dx1 * bx) + E;
723 int32_t C2 = O2 + (dx2 * bx);
724 int32_t C3 = O3 + (dx3 * bx);
725 float cw = ((C1 * fP1a) + (C2 * fP2a) + (C3 * fP3a)) + wb;
726
727 while ((bx < lx) && ((C2 | C3) >= 0))
728 {
729 ZBUFFER_t& W = zbuf[bx];
730 const ZBUFFER_t aa = (ZBUFFER_t)(cw);
731 if (W < aa)
732 {
733 W = aa;
734 buf[bx] = interpolateColorsTriangle(col2, C2 >> shiftC, col3, C3 >> shiftC, col1, aera >> shiftC);
735 }
736 C2 += dx2;
737 C3 += dx3;
738 cw += dw;
739 bx++;
740 }
741
742 O1 += dy1;
743 O2 += dy2;
744 O3 += dy3;
745 buf += stride;
746 zbuf += zstride;
747 }
748 }
749
750
754 template<typename color_t, typename ZBUFFER_t, bool TEXTURE_BILINEAR, bool TEXTURE_WRAP>
755 void shader_Flat_Texture_Zbuffer(const int32_t& offset, const int32_t& lx, const int32_t& ly,
756 const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4& fP1,
757 const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4& fP2,
758 const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4& fP3,
759 const RasterizerParams<color_t, color_t, ZBUFFER_t>& data)
760 {
761 color_t* buf = data.im->data() + offset;
762 ZBUFFER_t* zbuf = data.zbuf + offset;
763
764 const float wa = data.wa;
765 const float wb = data.wb;
766 (void)wa; // silence possible unused warnings
767 (void)wb; //
768
769
770 const int32_t stride = data.im->stride();
771 const int32_t zstride = data.im->lx();
772
773 const uintptr_t end = (uintptr_t)(buf + (ly * stride));
774 const int32_t pa = O1 + O2 + O3;
775 const int32_t E = ((pa == 0) ? 1 : 0);
776 const int32_t aera = pa + E;
777
778 const float invaera = fast_inv((float)aera);
779 const float fP1a = fP1.w * invaera;
780 const float fP2a = fP2.w * invaera;
781 const float fP3a = fP3.w * invaera;
782
783 const float dw = (dx1 * fP1a) + (dx2 * fP2a) + (dx3 * fP3a);
784
785 const RGBf& cf = (RGBf)data.facecolor;
786 const int fPR = (int)(256 * cf.R);
787 const int fPG = (int)(256 * cf.G);
788 const int fPB = (int)(256 * cf.B);
789
790 // the texture coord
791 fVec2 T1 = fP1.T;
792 fVec2 T2 = fP2.T;
793 fVec2 T3 = fP3.T;
794
795 const color_t* tex = data.tex->data();
796 const int32_t texsize_x = data.tex->width();
797 const int32_t texsize_y = data.tex->height();
798 const int32_t texsize_x_mm = texsize_x - 1;
799 const int32_t texsize_y_mm = texsize_y - 1;
800 const int32_t texstride = data.tex->stride();
801
802 // divide the texture coord by z * aera
803 T1 *= fP1a;
804 T2 *= fP2a;
805 T3 *= fP3a;
806 T1.x *= texsize_x;
807 T2.x *= texsize_x;
808 T3.x *= texsize_x;
809 T1.y *= texsize_y;
810 T2.y *= texsize_y;
811 T3.y *= texsize_y;
812
813 const float dtx = ((T1.x * dx1) + (T2.x * dx2) + (T3.x * dx3));
814 const float dty = ((T1.y * dx1) + (T2.y * dx2) + (T3.y * dx3));
815
816 while ((uintptr_t)(buf) < end)
817 { // iterate over scanlines
818 int32_t bx = 0; // start offset
819 if (O1 < 0)
820 {
821 // we know that dx1 > 0
822 bx = (-O1 + dx1 - 1) / dx1; // first index where it becomes positive
823 }
824 if (O2 < 0)
825 {
826 if (dx2 <= 0)
827 {
828 if (dy2 <= 0) return;
829 const int32_t by = (-O2 + dy2 - 1) / dy2;
830 O1 += (by * dy1);
831 O2 += (by * dy2);
832 O3 += (by * dy3);
833 const int32_t offs = by * stride;
834 buf += offs;
835 zbuf += offs;
836 continue;
837 }
838 bx = max(bx, ((-O2 + dx2 - 1) / dx2));
839 }
840 if (O3 < 0)
841 {
842 if (dx3 <= 0)
843 {
844 if (dy3 <= 0) return;
845 const int32_t by = (-O3 + dy3 - 1) / dy3;
846 O1 += (by * dy1);
847 O2 += (by * dy2);
848 O3 += (by * dy3);
849 const int32_t offs = by * stride;
850 buf += offs;
851 zbuf += offs;
852 continue;
853 }
854 bx = max(bx, ((-O3 + dx3 - 1) / dx3));
855 }
856
857 int32_t C1 = O1 + (dx1 * bx) + E;
858 int32_t C2 = O2 + (dx2 * bx);
859 int32_t C3 = O3 + (dx3 * bx);
860 float cw = ((C1 * fP1a) + (C2 * fP2a) + (C3 * fP3a));
861
862 float tx = ((T1.x * C1) + (T2.x * C2) + (T3.x * C3));
863 float ty = ((T1.y * C1) + (T2.y * C2) + (T3.y * C3));
864
865 while ((bx < lx) && ((C2 | C3) >= 0))
866 {
867 ZBUFFER_t& W = zbuf[bx];
868 const ZBUFFER_t aa = (std::is_same<ZBUFFER_t, uint16_t>::value) ? ((ZBUFFER_t)(cw * wa + wb)) : ((ZBUFFER_t)cw);
869 if (W < aa)
870 {
871 W = aa;
872 const float icw = fast_inv(cw);
873 color_t col;
874 if (TEXTURE_BILINEAR)
875 {
876 const float xx = tx * icw;
877 const float yy = ty * icw;
878 const int ttx = (int)floorf(xx);
879 const int tty = (int)floorf(yy);
880 const float ax = xx - ttx;
881 const float ay = yy - tty;
882 const int minx = (TEXTURE_WRAP ? (ttx & (texsize_x_mm)) : shaderclip(ttx, texsize_x_mm));
883 const int maxx = (TEXTURE_WRAP ? ((ttx + 1) & (texsize_x_mm)) : shaderclip(ttx + 1, texsize_x_mm));
884 const int miny = (TEXTURE_WRAP ? ((tty & (texsize_y_mm)) * texstride) : shaderclip(tty, texsize_y_mm) * texstride);
885 const int maxy = (TEXTURE_WRAP ? (((tty + 1) & (texsize_y_mm)) * texstride) : shaderclip(tty + 1, texsize_y_mm) * texstride);
886 col = interpolateColorsBilinear(tex[minx + miny], tex[maxx + miny], tex[minx + maxy], tex[maxx + maxy], ax, ay);
887 }
888 else
889 {
890 const int ttx = (TEXTURE_WRAP ? ((int)((tx * icw))) & (texsize_x_mm) : shaderclip((int)(tx * icw), texsize_x_mm));
891 const int tty = (TEXTURE_WRAP ? ((int)((ty * icw))) & (texsize_y_mm) : shaderclip((int)(ty * icw), texsize_y_mm));
892 col = tex[ttx + (tty)*texstride];
893 }
894
895 col.mult256(fPR, fPG, fPB);
896 buf[bx] = col;
897 }
898
899 C2 += dx2;
900 C3 += dx3;
901 cw += dw;
902
903 tx += dtx;
904 ty += dty;
905
906 bx++;
907 }
908
909 O1 += dy1;
910 O2 += dy2;
911 O3 += dy3;
912 buf += stride;
913 zbuf += zstride;
914 }
915 }
916
917
918
922 template<typename color_t, typename ZBUFFER_t, bool TEXTURE_BILINEAR, bool TEXTURE_WRAP>
923 void shader_Gouraud_Texture_Zbuffer(const int32_t& offset, const int32_t& lx, const int32_t& ly,
924 const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4& fP1,
925 const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4& fP2,
926 const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4& fP3,
927 const RasterizerParams<color_t, color_t, ZBUFFER_t>& data)
928 {
929 color_t* buf = data.im->data() + offset;
930 ZBUFFER_t* zbuf = data.zbuf + offset;
931
932 const float wa = data.wa;
933 const float wb = data.wb;
934 (void)wa; // silence possible unused warnings
935 (void)wb; //
936
937 const int32_t stride = data.im->stride();
938 const int32_t zstride = data.im->lx();
939
940 const uintptr_t end = (uintptr_t)(buf + (ly * stride));
941 const int32_t pa = O1 + O2 + O3;
942 const int32_t E = ((pa == 0) ? 1 : 0);
943 const int32_t aera = pa + E;
944
945 const float invaera = fast_inv((float)aera);
946 const float fP1a = fP1.w * invaera;
947 const float fP2a = fP2.w * invaera;
948 const float fP3a = fP3.w * invaera;
949
950 const float dw = (dx1 * fP1a) + (dx2 * fP2a) + (dx3 * fP3a);
951
952 const RGBf& cf1 = (RGBf)fP1.color;
953 const RGBf& cf2 = (RGBf)fP2.color;
954 const RGBf& cf3 = (RGBf)fP3.color;
955 const int fP1R = (int)(256 * cf1.R);
956 const int fP1G = (int)(256 * cf1.G);
957 const int fP1B = (int)(256 * cf1.B);
958 const int fP21R = (int)(256 * (cf2.R - cf1.R));
959 const int fP21G = (int)(256 * (cf2.G - cf1.G));
960 const int fP21B = (int)(256 * (cf2.B - cf1.B));
961 const int fP31R = (int)(256 * (cf3.R - cf1.R));
962 const int fP31G = (int)(256 * (cf3.G - cf1.G));
963 const int fP31B = (int)(256 * (cf3.B - cf1.B));
964
965 // the texture coord
966 fVec2 T1 = fP1.T;
967 fVec2 T2 = fP2.T;
968 fVec2 T3 = fP3.T;
969
970 const color_t* tex = data.tex->data();
971 const int32_t texsize_x = data.tex->width();
972 const int32_t texsize_y = data.tex->height();
973 const int32_t texsize_x_mm = texsize_x - 1;
974 const int32_t texsize_y_mm = texsize_y - 1;
975 const int32_t texstride = data.tex->stride();
976
977 // divide the texture coord by z * aera
978 T1 *= fP1a;
979 T2 *= fP2a;
980 T3 *= fP3a;
981 T1.x *= texsize_x;
982 T2.x *= texsize_x;
983 T3.x *= texsize_x;
984 T1.y *= texsize_y;
985 T2.y *= texsize_y;
986 T3.y *= texsize_y;
987
988 const float dtx = ((T1.x * dx1) + (T2.x * dx2) + (T3.x * dx3));
989 const float dty = ((T1.y * dx1) + (T2.y * dx2) + (T3.y * dx3));
990
991 while ((uintptr_t)(buf) < end)
992 { // iterate over scanlines
993 int32_t bx = 0; // start offset
994 if (O1 < 0)
995 {
996 // we know that dx1 > 0
997 bx = (-O1 + dx1 - 1) / dx1; // first index where it becomes positive
998 }
999 if (O2 < 0)
1000 {
1001 if (dx2 <= 0)
1002 {
1003 if (dy2 <= 0) return;
1004 const int32_t by = (-O2 + dy2 - 1) / dy2;
1005 O1 += (by * dy1);
1006 O2 += (by * dy2);
1007 O3 += (by * dy3);
1008 const int32_t offs = by * stride;
1009 buf += offs;
1010 zbuf += offs;
1011 continue;
1012 }
1013 bx = max(bx, ((-O2 + dx2 - 1) / dx2));
1014 }
1015 if (O3 < 0)
1016 {
1017 if (dx3 <= 0)
1018 {
1019 if (dy3 <= 0) return;
1020 const int32_t by = (-O3 + dy3 - 1) / dy3;
1021 O1 += (by * dy1);
1022 O2 += (by * dy2);
1023 O3 += (by * dy3);
1024 const int32_t offs = by * stride;
1025 buf += offs;
1026 zbuf += offs;
1027 continue;
1028 }
1029 bx = max(bx, ((-O3 + dx3 - 1) / dx3));
1030 }
1031 int32_t C1 = O1 + (dx1 * bx) + E;
1032 int32_t C2 = O2 + (dx2 * bx);
1033 int32_t C3 = O3 + (dx3 * bx);
1034 float cw = ((C1 * fP1a) + (C2 * fP2a) + (C3 * fP3a));
1035
1036 float tx = ((T1.x * C1) + (T2.x * C2) + (T3.x * C3));
1037 float ty = ((T1.y * C1) + (T2.y * C2) + (T3.y * C3));
1038
1039 while ((bx < lx) && ((C2 | C3) >= 0))
1040 {
1041 ZBUFFER_t& W = zbuf[bx];
1042 const ZBUFFER_t aa = (std::is_same<ZBUFFER_t, uint16_t>::value) ? ((ZBUFFER_t)(cw * wa + wb)) : ((ZBUFFER_t)cw);
1043 if (W < aa)
1044 {
1045 W = aa;
1046 const float icw = fast_inv(cw);
1047
1048 color_t col;
1049 if (TEXTURE_BILINEAR)
1050 {
1051 const float xx = tx * icw;
1052 const float yy = ty * icw;
1053 const int ttx = (int)floorf(xx);
1054 const int tty = (int)floorf(yy);
1055 const float ax = xx - ttx;
1056 const float ay = yy - tty;
1057 const int minx = (TEXTURE_WRAP ? (ttx & (texsize_x_mm)) : shaderclip(ttx, texsize_x_mm));
1058 const int maxx = (TEXTURE_WRAP ? ((ttx + 1) & (texsize_x_mm)) : shaderclip(ttx + 1, texsize_x_mm));
1059 const int miny = (TEXTURE_WRAP ? ((tty & (texsize_y_mm)) * texstride) : shaderclip(tty, texsize_y_mm) * texstride);
1060 const int maxy = (TEXTURE_WRAP ? (((tty + 1) & (texsize_y_mm)) * texstride) : shaderclip(tty + 1, texsize_y_mm) * texstride);
1061 col = interpolateColorsBilinear(tex[minx + miny], tex[maxx + miny], tex[minx + maxy], tex[maxx + maxy], ax, ay);
1062 }
1063 else
1064 {
1065 const int ttx = (TEXTURE_WRAP ? ((int)((tx * icw))) & (texsize_x_mm) : shaderclip((int)(tx * icw), texsize_x_mm));
1066 const int tty = (TEXTURE_WRAP ? ((int)((ty * icw))) & (texsize_y_mm) : shaderclip((int)(ty * icw), texsize_y_mm));
1067 col = tex[ttx + (tty)*texstride];
1068 }
1069
1070 const int r = fP1R + ((C2 * fP21R + C3 * fP31R) / aera);
1071 const int g = fP1G + ((C2 * fP21G + C3 * fP31G) / aera);
1072 const int b = fP1B + ((C2 * fP21B + C3 * fP31B) / aera);
1073 col.mult256(r, g, b);
1074 buf[bx] = col;
1075 }
1076
1077 C2 += dx2;
1078 C3 += dx3;
1079 cw += dw;
1080
1081 tx += dtx;
1082 ty += dty;
1083
1084 bx++;
1085 }
1086
1087 O1 += dy1;
1088 O2 += dy2;
1089 O3 += dy3;
1090 buf += stride;
1091 zbuf += zstride;
1092 }
1093 }
1094
1095
1096
1100 template<typename color_t, typename ZBUFFER_t, bool TEXTURE_BILINEAR, bool TEXTURE_WRAP>
1101 void shader_Flat_Texture_Ortho(const int32_t& offset, const int32_t& lx, const int32_t& ly,
1102 const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4& fP1,
1103 const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4& fP2,
1104 const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4& fP3,
1105 const RasterizerParams<color_t, color_t, ZBUFFER_t>& data)
1106 {
1107 color_t* buf = data.im->data() + offset;
1108 const int32_t stride = data.im->stride();
1109
1110 const uintptr_t end = (uintptr_t)(buf + (ly * stride));
1111 const int32_t pa = O1 + O2 + O3;
1112 const int32_t E = ((pa == 0) ? 1 : 0);
1113 const int32_t aera = pa + E;
1114
1115 const float invaera = fast_inv((float)aera);
1116
1117 const RGBf& cf = (RGBf)data.facecolor;
1118 const int fPR = (int)(256 * cf.R);
1119 const int fPG = (int)(256 * cf.G);
1120 const int fPB = (int)(256 * cf.B);
1121
1122 // the texture coord
1123 fVec2 T1 = fP1.T;
1124 fVec2 T2 = fP2.T;
1125 fVec2 T3 = fP3.T;
1126
1127 const color_t* tex = data.tex->data();
1128 const int32_t texsize_x = data.tex->width();
1129 const int32_t texsize_y = data.tex->height();
1130 const int32_t texsize_x_mm = texsize_x - 1;
1131 const int32_t texsize_y_mm = texsize_y - 1;
1132 const int32_t texstride = data.tex->stride();
1133
1134 // divide the texture coord by aera
1135 T1 *= invaera;
1136 T2 *= invaera;
1137 T3 *= invaera;
1138 T1.x *= texsize_x;
1139 T2.x *= texsize_x;
1140 T3.x *= texsize_x;
1141 T1.y *= texsize_y;
1142 T2.y *= texsize_y;
1143 T3.y *= texsize_y;
1144
1145 const float dtx = ((T1.x * dx1) + (T2.x * dx2) + (T3.x * dx3));
1146 const float dty = ((T1.y * dx1) + (T2.y * dx2) + (T3.y * dx3));
1147
1148 while ((uintptr_t)(buf) < end)
1149 { // iterate over scanlines
1150 int32_t bx = 0; // start offset
1151 if (O1 < 0)
1152 {
1153 // we know that dx1 > 0
1154 bx = (-O1 + dx1 - 1) / dx1; // first index where it becomes positive
1155 }
1156 if (O2 < 0)
1157 {
1158 if (dx2 <= 0)
1159 {
1160 if (dy2 <= 0) return;
1161 const int32_t by = (-O2 + dy2 - 1) / dy2;
1162 O1 += (by * dy1);
1163 O2 += (by * dy2);
1164 O3 += (by * dy3);
1165 const int32_t offs = by * stride;
1166 buf += offs;
1167 continue;
1168 }
1169 bx = max(bx, ((-O2 + dx2 - 1) / dx2));
1170 }
1171 if (O3 < 0)
1172 {
1173 if (dx3 <= 0)
1174 {
1175 if (dy3 <= 0) return;
1176 const int32_t by = (-O3 + dy3 - 1) / dy3;
1177 O1 += (by * dy1);
1178 O2 += (by * dy2);
1179 O3 += (by * dy3);
1180 const int32_t offs = by * stride;
1181 buf += offs;
1182 continue;
1183 }
1184 bx = max(bx, ((-O3 + dx3 - 1) / dx3));
1185 }
1186 int32_t C1 = O1 + (dx1 * bx) + E;
1187 int32_t C2 = O2 + (dx2 * bx);
1188 int32_t C3 = O3 + (dx3 * bx);
1189
1190 float tx = ((T1.x * C1) + (T2.x * C2) + (T3.x * C3));
1191 float ty = ((T1.y * C1) + (T2.y * C2) + (T3.y * C3));
1192
1193 while ((bx < lx) && ((C2 | C3) >= 0))
1194 {
1195
1196 color_t col;
1197 if (TEXTURE_BILINEAR)
1198 {
1199 const float xx = tx;
1200 const float yy = ty;
1201 const int ttx = (int)floorf(xx);
1202 const int tty = (int)floorf(yy);
1203 const float ax = xx - ttx;
1204 const float ay = yy - tty;
1205 const int minx = (TEXTURE_WRAP ? (ttx & (texsize_x_mm)) : shaderclip(ttx, texsize_x_mm));
1206 const int maxx = (TEXTURE_WRAP ? ((ttx + 1) & (texsize_x_mm)) : shaderclip(ttx + 1, texsize_x_mm));
1207 const int miny = (TEXTURE_WRAP ? ((tty & (texsize_y_mm)) * texstride) : shaderclip(tty, texsize_y_mm) * texstride);
1208 const int maxy = (TEXTURE_WRAP ? (((tty + 1) & (texsize_y_mm)) * texstride) : shaderclip(tty + 1, texsize_y_mm) * texstride);
1209 col = interpolateColorsBilinear(tex[minx + miny], tex[maxx + miny], tex[minx + maxy], tex[maxx + maxy], ax, ay);
1210 }
1211 else
1212 {
1213 const int ttx = (TEXTURE_WRAP ? ((int)((tx))) & (texsize_x_mm) : shaderclip((int)(tx), texsize_x_mm));
1214 const int tty = (TEXTURE_WRAP ? ((int)((ty))) & (texsize_y_mm) : shaderclip((int)(ty), texsize_y_mm));
1215 col = tex[ttx + (tty)*texstride];
1216 }
1217
1218 col.mult256(fPR, fPG, fPB);
1219 buf[bx] = col;
1220
1221 C2 += dx2;
1222 C3 += dx3;
1223
1224 tx += dtx;
1225 ty += dty;
1226
1227 bx++;
1228 }
1229
1230 O1 += dy1;
1231 O2 += dy2;
1232 O3 += dy3;
1233 buf += stride;
1234 }
1235 }
1236
1237
1238
1242 template<typename color_t, typename ZBUFFER_t, bool TEXTURE_BILINEAR, bool TEXTURE_WRAP>
1243 void shader_Gouraud_Texture_Ortho(const int32_t& offset, const int32_t& lx, const int32_t& ly,
1244 const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4& fP1,
1245 const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4& fP2,
1246 const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4& fP3,
1247 const RasterizerParams<color_t, color_t, ZBUFFER_t>& data)
1248 {
1249 color_t* buf = data.im->data() + offset;
1250 const int32_t stride = data.im->stride();
1251
1252 const uintptr_t end = (uintptr_t)(buf + (ly * stride));
1253 const int32_t pa = O1 + O2 + O3;
1254 const int32_t E = ((pa == 0) ? 1 : 0);
1255 const int32_t aera = pa + E;
1256
1257 const float invaera = fast_inv((float)aera);
1258
1259 const RGBf& cf1 = (RGBf)fP1.color;
1260 const RGBf& cf2 = (RGBf)fP2.color;
1261 const RGBf& cf3 = (RGBf)fP3.color;
1262 const int fP1R = (int)(256 * cf1.R);
1263 const int fP1G = (int)(256 * cf1.G);
1264 const int fP1B = (int)(256 * cf1.B);
1265 const int fP21R = (int)(256 * (cf2.R - cf1.R));
1266 const int fP21G = (int)(256 * (cf2.G - cf1.G));
1267 const int fP21B = (int)(256 * (cf2.B - cf1.B));
1268 const int fP31R = (int)(256 * (cf3.R - cf1.R));
1269 const int fP31G = (int)(256 * (cf3.G - cf1.G));
1270 const int fP31B = (int)(256 * (cf3.B - cf1.B));
1271
1272 // the texture coord
1273 fVec2 T1 = fP1.T;
1274 fVec2 T2 = fP2.T;
1275 fVec2 T3 = fP3.T;
1276
1277 const color_t* tex = data.tex->data();
1278 const int32_t texsize_x = data.tex->width();
1279 const int32_t texsize_y = data.tex->height();
1280 const int32_t texsize_x_mm = texsize_x - 1;
1281 const int32_t texsize_y_mm = texsize_y - 1;
1282 const int32_t texstride = data.tex->stride();
1283
1284 // divide the texture coord by aera
1285 T1 *= invaera;
1286 T2 *= invaera;
1287 T3 *= invaera;
1288 T1.x *= texsize_x;
1289 T2.x *= texsize_x;
1290 T3.x *= texsize_x;
1291 T1.y *= texsize_y;
1292 T2.y *= texsize_y;
1293 T3.y *= texsize_y;
1294
1295 const float dtx = ((T1.x * dx1) + (T2.x * dx2) + (T3.x * dx3));
1296 const float dty = ((T1.y * dx1) + (T2.y * dx2) + (T3.y * dx3));
1297
1298 while ((uintptr_t)(buf) < end)
1299 { // iterate over scanlines
1300 int32_t bx = 0; // start offset
1301 if (O1 < 0)
1302 {
1303 // we know that dx1 > 0
1304 bx = (-O1 + dx1 - 1) / dx1; // first index where it becomes positive
1305 }
1306 if (O2 < 0)
1307 {
1308 if (dx2 <= 0)
1309 {
1310 if (dy2 <= 0) return;
1311 const int32_t by = (-O2 + dy2 - 1) / dy2;
1312 O1 += (by * dy1);
1313 O2 += (by * dy2);
1314 O3 += (by * dy3);
1315 const int32_t offs = by * stride;
1316 buf += offs;
1317 continue;
1318 }
1319 bx = max(bx, ((-O2 + dx2 - 1) / dx2));
1320 }
1321 if (O3 < 0)
1322 {
1323 if (dx3 <= 0)
1324 {
1325 if (dy3 <= 0) return;
1326 const int32_t by = (-O3 + dy3 - 1) / dy3;
1327 O1 += (by * dy1);
1328 O2 += (by * dy2);
1329 O3 += (by * dy3);
1330 const int32_t offs = by * stride;
1331 buf += offs;
1332 continue;
1333 }
1334 bx = max(bx, ((-O3 + dx3 - 1) / dx3));
1335 }
1336
1337 int32_t C1 = O1 + (dx1 * bx) + E;
1338 int32_t C2 = O2 + (dx2 * bx);
1339 int32_t C3 = O3 + (dx3 * bx);
1340
1341 float tx = ((T1.x * C1) + (T2.x * C2) + (T3.x * C3));
1342 float ty = ((T1.y * C1) + (T2.y * C2) + (T3.y * C3));
1343
1344 while ((bx < lx) && ((C2 | C3) >= 0))
1345 {
1346
1347 color_t col;
1348 if (TEXTURE_BILINEAR)
1349 {
1350 const float xx = tx;
1351 const float yy = ty;
1352 const int ttx = (int)floorf(xx);
1353 const int tty = (int)floorf(yy);
1354 const float ax = xx - ttx;
1355 const float ay = yy - tty;
1356 const int minx = (TEXTURE_WRAP ? (ttx & (texsize_x_mm)) : shaderclip(ttx, texsize_x_mm));
1357 const int maxx = (TEXTURE_WRAP ? ((ttx + 1) & (texsize_x_mm)) : shaderclip(ttx + 1, texsize_x_mm));
1358 const int miny = (TEXTURE_WRAP ? ((tty & (texsize_y_mm)) * texstride) : shaderclip(tty, texsize_y_mm) * texstride);
1359 const int maxy = (TEXTURE_WRAP ? (((tty + 1) & (texsize_y_mm)) * texstride) : shaderclip(tty + 1, texsize_y_mm) * texstride);
1360 col = interpolateColorsBilinear(tex[minx + miny], tex[maxx + miny], tex[minx + maxy], tex[maxx + maxy], ax, ay);
1361 }
1362 else
1363 {
1364 const int ttx = (TEXTURE_WRAP ? ((int)((tx))) & (texsize_x_mm) : shaderclip((int)(tx), texsize_x_mm));
1365 const int tty = (TEXTURE_WRAP ? ((int)((ty))) & (texsize_y_mm) : shaderclip((int)(ty), texsize_y_mm));
1366 col = tex[ttx + (tty)*texstride];
1367 }
1368
1369 const int r = fP1R + ((C2 * fP21R + C3 * fP31R) / aera);
1370 const int g = fP1G + ((C2 * fP21G + C3 * fP31G) / aera);
1371 const int b = fP1B + ((C2 * fP21B + C3 * fP31B) / aera);
1372 col.mult256(r, g, b);
1373 buf[bx] = col;
1374
1375 C2 += dx2;
1376 C3 += dx3;
1377
1378 tx += dtx;
1379 ty += dty;
1380
1381 bx++;
1382 }
1383
1384 O1 += dy1;
1385 O2 += dy2;
1386 O3 += dy3;
1387 buf += stride;
1388 }
1389 }
1390
1391
1392
1396 template<typename color_t, typename ZBUFFER_t, bool TEXTURE_BILINEAR, bool TEXTURE_WRAP>
1397 void shader_Flat_Texture_Zbuffer_Ortho(const int32_t& offset, const int32_t& lx, const int32_t& ly,
1398 const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4& fP1,
1399 const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4& fP2,
1400 const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4& fP3,
1401 const RasterizerParams<color_t, color_t, ZBUFFER_t>& data)
1402 {
1403 color_t* buf = data.im->data() + offset;
1404 ZBUFFER_t* zbuf = data.zbuf + offset;
1405
1406 const float wa = data.wa;
1407 const float wb = data.wb;
1408 (void)wa; // silence possible unused warnings
1409 (void)wb; //
1410
1411 const int32_t stride = data.im->stride();
1412 const int32_t zstride = data.im->lx();
1413
1414 const uintptr_t end = (uintptr_t)(buf + (ly * stride));
1415 const int32_t pa = O1 + O2 + O3;
1416 const int32_t E = ((pa == 0) ? 1 : 0);
1417 const int32_t aera = pa + E;
1418
1419 const float invaera = fast_inv((float)aera);
1420 const float fP1a = fP1.w * invaera;
1421 const float fP2a = fP2.w * invaera;
1422 const float fP3a = fP3.w * invaera;
1423
1424 const float dw = (dx1 * fP1a) + (dx2 * fP2a) + (dx3 * fP3a);
1425
1426 const RGBf& cf = (RGBf)data.facecolor;
1427 const int fPR = (int)(256 * cf.R);
1428 const int fPG = (int)(256 * cf.G);
1429 const int fPB = (int)(256 * cf.B);
1430
1431 // the texture coord
1432 fVec2 T1 = fP1.T;
1433 fVec2 T2 = fP2.T;
1434 fVec2 T3 = fP3.T;
1435
1436 const color_t* tex = data.tex->data();
1437 const int32_t texsize_x = data.tex->width();
1438 const int32_t texsize_y = data.tex->height();
1439 const int32_t texsize_x_mm = texsize_x - 1;
1440 const int32_t texsize_y_mm = texsize_y - 1;
1441 const int32_t texstride = data.tex->stride();
1442
1443 // divide the texture coord by aera
1444 T1 *= invaera;
1445 T2 *= invaera;
1446 T3 *= invaera;
1447 T1.x *= texsize_x;
1448 T2.x *= texsize_x;
1449 T3.x *= texsize_x;
1450 T1.y *= texsize_y;
1451 T2.y *= texsize_y;
1452 T3.y *= texsize_y;
1453
1454 const float dtx = ((T1.x * dx1) + (T2.x * dx2) + (T3.x * dx3));
1455 const float dty = ((T1.y * dx1) + (T2.y * dx2) + (T3.y * dx3));
1456
1457 while ((uintptr_t)(buf) < end)
1458 { // iterate over scanlines
1459 int32_t bx = 0; // start offset
1460 if (O1 < 0)
1461 {
1462 // we know that dx1 > 0
1463 bx = (-O1 + dx1 - 1) / dx1; // first index where it becomes positive
1464 }
1465 if (O2 < 0)
1466 {
1467 if (dx2 <= 0)
1468 {
1469 if (dy2 <= 0) return;
1470 const int32_t by = (-O2 + dy2 - 1) / dy2;
1471 O1 += (by * dy1);
1472 O2 += (by * dy2);
1473 O3 += (by * dy3);
1474 const int32_t offs = by * stride;
1475 buf += offs;
1476 zbuf += offs;
1477 continue;
1478 }
1479 bx = max(bx, ((-O2 + dx2 - 1) / dx2));
1480 }
1481 if (O3 < 0)
1482 {
1483 if (dx3 <= 0)
1484 {
1485 if (dy3 <= 0) return;
1486 const int32_t by = (-O3 + dy3 - 1) / dy3;
1487 O1 += (by * dy1);
1488 O2 += (by * dy2);
1489 O3 += (by * dy3);
1490 const int32_t offs = by * stride;
1491 buf += offs;
1492 zbuf += offs;
1493 continue;
1494 }
1495 bx = max(bx, ((-O3 + dx3 - 1) / dx3));
1496 }
1497
1498 int32_t C1 = O1 + (dx1 * bx) + E;
1499 int32_t C2 = O2 + (dx2 * bx);
1500 int32_t C3 = O3 + (dx3 * bx);
1501 float cw = ((C1 * fP1a) + (C2 * fP2a) + (C3 * fP3a));
1502
1503 float tx = ((T1.x * C1) + (T2.x * C2) + (T3.x * C3));
1504 float ty = ((T1.y * C1) + (T2.y * C2) + (T3.y * C3));
1505
1506 while ((bx < lx) && ((C2 | C3) >= 0))
1507 {
1508 ZBUFFER_t& W = zbuf[bx];
1509 const ZBUFFER_t aa = (std::is_same<ZBUFFER_t, uint16_t>::value) ? ((ZBUFFER_t)(cw * wa + wb)) : ((ZBUFFER_t)cw);
1510 if (W < aa)
1511 {
1512 W = aa;
1513
1514 color_t col;
1515 if (TEXTURE_BILINEAR)
1516 {
1517 const float xx = tx;
1518 const float yy = ty;
1519 const int ttx = (int)floorf(xx);
1520 const int tty = (int)floorf(yy);
1521 const float ax = xx - ttx;
1522 const float ay = yy - tty;
1523 const int minx = (TEXTURE_WRAP ? (ttx & (texsize_x_mm)) : shaderclip(ttx, texsize_x_mm));
1524 const int maxx = (TEXTURE_WRAP ? ((ttx + 1) & (texsize_x_mm)) : shaderclip(ttx + 1, texsize_x_mm));
1525 const int miny = (TEXTURE_WRAP ? ((tty & (texsize_y_mm)) * texstride) : shaderclip(tty, texsize_y_mm) * texstride);
1526 const int maxy = (TEXTURE_WRAP ? (((tty + 1) & (texsize_y_mm)) * texstride) : shaderclip(tty + 1, texsize_y_mm) * texstride);
1527 col = interpolateColorsBilinear(tex[minx + miny], tex[maxx + miny], tex[minx + maxy], tex[maxx + maxy], ax, ay);
1528 }
1529 else
1530 {
1531 const int ttx = (TEXTURE_WRAP ? ((int)((tx))) & (texsize_x_mm) : shaderclip((int)(tx), texsize_x_mm));
1532 const int tty = (TEXTURE_WRAP ? ((int)((ty))) & (texsize_y_mm) : shaderclip((int)(ty), texsize_y_mm));
1533 col = tex[ttx + (tty)*texstride];
1534 }
1535
1536 col.mult256(fPR, fPG, fPB);
1537 buf[bx] = col;
1538 }
1539
1540 C2 += dx2;
1541 C3 += dx3;
1542 cw += dw;
1543
1544 tx += dtx;
1545 ty += dty;
1546
1547 bx++;
1548 }
1549
1550 O1 += dy1;
1551 O2 += dy2;
1552 O3 += dy3;
1553 buf += stride;
1554 zbuf += zstride;
1555 }
1556 }
1557
1558
1559
1563 template<typename color_t, typename ZBUFFER_t, bool TEXTURE_BILINEAR, bool TEXTURE_WRAP>
1564 void shader_Gouraud_Texture_Zbuffer_Ortho(const int32_t& offset, const int32_t& lx, const int32_t& ly,
1565 const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4& fP1,
1566 const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4& fP2,
1567 const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4& fP3,
1568 const RasterizerParams<color_t, color_t, ZBUFFER_t>& data)
1569 {
1570 color_t* buf = data.im->data() + offset;
1571 ZBUFFER_t* zbuf = data.zbuf + offset;
1572
1573 const float wa = data.wa;
1574 const float wb = data.wb;
1575 (void)wa; // silence possible unused warnings
1576 (void)wb; //
1577
1578 const int32_t stride = data.im->stride();
1579 const int32_t zstride = data.im->lx();
1580
1581 const uintptr_t end = (uintptr_t)(buf + (ly * stride));
1582 const int32_t pa = O1 + O2 + O3;
1583 const int32_t E = ((pa == 0) ? 1 : 0);
1584 const int32_t aera = pa + E;
1585
1586 const float invaera = fast_inv((float)aera);
1587 const float fP1a = fP1.w * invaera;
1588 const float fP2a = fP2.w * invaera;
1589 const float fP3a = fP3.w * invaera;
1590
1591 const float dw = (dx1 * fP1a) + (dx2 * fP2a) + (dx3 * fP3a);
1592
1593 const RGBf& cf1 = (RGBf)fP1.color;
1594 const RGBf& cf2 = (RGBf)fP2.color;
1595 const RGBf& cf3 = (RGBf)fP3.color;
1596 const int fP1R = (int)(256 * cf1.R);
1597 const int fP1G = (int)(256 * cf1.G);
1598 const int fP1B = (int)(256 * cf1.B);
1599 const int fP21R = (int)(256 * (cf2.R - cf1.R));
1600 const int fP21G = (int)(256 * (cf2.G - cf1.G));
1601 const int fP21B = (int)(256 * (cf2.B - cf1.B));
1602 const int fP31R = (int)(256 * (cf3.R - cf1.R));
1603 const int fP31G = (int)(256 * (cf3.G - cf1.G));
1604 const int fP31B = (int)(256 * (cf3.B - cf1.B));
1605
1606 // the texture coord
1607 fVec2 T1 = fP1.T;
1608 fVec2 T2 = fP2.T;
1609 fVec2 T3 = fP3.T;
1610
1611 const color_t* tex = data.tex->data();
1612 const int32_t texsize_x = data.tex->width();
1613 const int32_t texsize_y = data.tex->height();
1614 const int32_t texsize_x_mm = texsize_x - 1;
1615 const int32_t texsize_y_mm = texsize_y - 1;
1616 const int32_t texstride = data.tex->stride();
1617
1618 // divide the texture coord by aera
1619 T1 *= invaera;
1620 T2 *= invaera;
1621 T3 *= invaera;
1622 T1.x *= texsize_x;
1623 T2.x *= texsize_x;
1624 T3.x *= texsize_x;
1625 T1.y *= texsize_y;
1626 T2.y *= texsize_y;
1627 T3.y *= texsize_y;
1628
1629 const float dtx = ((T1.x * dx1) + (T2.x * dx2) + (T3.x * dx3));
1630 const float dty = ((T1.y * dx1) + (T2.y * dx2) + (T3.y * dx3));
1631
1632 while ((uintptr_t)(buf) < end)
1633 { // iterate over scanlines
1634 int32_t bx = 0; // start offset
1635 if (O1 < 0)
1636 {
1637 // we know that dx1 > 0
1638 bx = (-O1 + dx1 - 1) / dx1; // first index where it becomes positive
1639 }
1640 if (O2 < 0)
1641 {
1642 if (dx2 <= 0)
1643 {
1644 if (dy2 <= 0) return;
1645 const int32_t by = (-O2 + dy2 - 1) / dy2;
1646 O1 += (by * dy1);
1647 O2 += (by * dy2);
1648 O3 += (by * dy3);
1649 const int32_t offs = by * stride;
1650 buf += offs;
1651 zbuf += offs;
1652 continue;
1653 }
1654 bx = max(bx, ((-O2 + dx2 - 1) / dx2));
1655 }
1656 if (O3 < 0)
1657 {
1658 if (dx3 <= 0)
1659 {
1660 if (dy3 <= 0) return;
1661 const int32_t by = (-O3 + dy3 - 1) / dy3;
1662 O1 += (by * dy1);
1663 O2 += (by * dy2);
1664 O3 += (by * dy3);
1665 const int32_t offs = by * stride;
1666 buf += offs;
1667 zbuf += offs;
1668 continue;
1669 }
1670 bx = max(bx, ((-O3 + dx3 - 1) / dx3));
1671 }
1672
1673 int32_t C1 = O1 + (dx1 * bx) + E;
1674 int32_t C2 = O2 + (dx2 * bx);
1675 int32_t C3 = O3 + (dx3 * bx);
1676 float cw = ((C1 * fP1a) + (C2 * fP2a) + (C3 * fP3a));
1677
1678 float tx = ((T1.x * C1) + (T2.x * C2) + (T3.x * C3));
1679 float ty = ((T1.y * C1) + (T2.y * C2) + (T3.y * C3));
1680
1681 while ((bx < lx) && ((C2 | C3) >= 0))
1682 {
1683 ZBUFFER_t& W = zbuf[bx];
1684 const ZBUFFER_t aa = (std::is_same<ZBUFFER_t, uint16_t>::value) ? ((ZBUFFER_t)(cw * wa + wb)) : ((ZBUFFER_t)cw);
1685 if (W < aa)
1686 {
1687 W = aa;
1688
1689 color_t col;
1690 if (TEXTURE_BILINEAR)
1691 {
1692 const float xx = tx;
1693 const float yy = ty;
1694 const int ttx = (int)floorf(xx);
1695 const int tty = (int)floorf(yy);
1696 const float ax = xx - ttx;
1697 const float ay = yy - tty;
1698 const int minx = (TEXTURE_WRAP ? (ttx & (texsize_x_mm)) : shaderclip(ttx, texsize_x_mm));
1699 const int maxx = (TEXTURE_WRAP ? ((ttx + 1) & (texsize_x_mm)) : shaderclip(ttx + 1, texsize_x_mm));
1700 const int miny = (TEXTURE_WRAP ? ((tty & (texsize_y_mm)) * texstride) : shaderclip(tty, texsize_y_mm) * texstride);
1701 const int maxy = (TEXTURE_WRAP ? (((tty + 1) & (texsize_y_mm)) * texstride) : shaderclip(tty + 1, texsize_y_mm) * texstride);
1702 col = interpolateColorsBilinear(tex[minx + miny], tex[maxx + miny], tex[minx + maxy], tex[maxx + maxy], ax, ay);
1703 }
1704 else
1705 {
1706 const int ttx = (TEXTURE_WRAP ? ((int)((tx))) & (texsize_x_mm) : shaderclip((int)(tx), texsize_x_mm));
1707 const int tty = (TEXTURE_WRAP ? ((int)((ty))) & (texsize_y_mm) : shaderclip((int)(ty), texsize_y_mm));
1708 col = tex[ttx + (tty)*texstride];
1709 }
1710
1711 const int r = fP1R + ((C2 * fP21R + C3 * fP31R) / aera);
1712 const int g = fP1G + ((C2 * fP21G + C3 * fP31G) / aera);
1713 const int b = fP1B + ((C2 * fP21B + C3 * fP31B) / aera);
1714
1715 col.mult256(r, g, b);
1716 buf[bx] = col;
1717
1718 }
1719
1720 C2 += dx2;
1721 C3 += dx3;
1722 cw += dw;
1723
1724 tx += dtx;
1725 ty += dty;
1726
1727 bx++;
1728 }
1729
1730 O1 += dy1;
1731 O2 += dy2;
1732 O3 += dy3;
1733 buf += stride;
1734 zbuf += zstride;
1735 }
1736 }
1737
1738
1739
1740
1744 template<int SHADER_FLAGS_ENABLED, typename color_t, typename ZBUFFER_t> void shader_select(const int32_t& offset, const int32_t& lx, const int32_t& ly,
1745 const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4& fP1,
1746 const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4& fP2,
1747 const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4& fP3,
1748 const RasterizerParams<color_t, color_t, ZBUFFER_t> & data)
1749 {
1750 int raster_type = data.shader_type;
1751 if (TGX_SHADER_HAS_ZBUFFER(SHADER_FLAGS_ENABLED) && (TGX_SHADER_HAS_ZBUFFER(raster_type)))
1752 { // USING ZBUFFER
1753 if (TGX_SHADER_HAS_ORTHO(SHADER_FLAGS_ENABLED) && (TGX_SHADER_HAS_ORTHO(raster_type)))
1754 { // USING ORTHOGRAPHIC PROJECTION
1755 if (TGX_SHADER_HAS_TEXTURE(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE(raster_type))
1756 {
1757 if (TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_GOURAUD(raster_type))
1758 {
1759 if (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type))
1760 {
1761 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
1762 shader_Gouraud_Texture_Zbuffer_Ortho<color_t,ZBUFFER_t, true,false>(offset, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1763 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1764 shader_Gouraud_Texture_Zbuffer_Ortho<color_t, ZBUFFER_t, true, true>(offset, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1765 }
1766 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
1767 {
1768 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
1769 shader_Gouraud_Texture_Zbuffer_Ortho<color_t, ZBUFFER_t, false,false>(offset, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1770 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1771 shader_Gouraud_Texture_Zbuffer_Ortho<color_t, ZBUFFER_t, false,true>(offset, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1772 }
1773 }
1774 else if (TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED))
1775 {
1776 if (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type))
1777 {
1778 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
1779 shader_Flat_Texture_Zbuffer_Ortho<color_t, ZBUFFER_t, true,false>(offset, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1780 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1781 shader_Flat_Texture_Zbuffer_Ortho<color_t, ZBUFFER_t, true,true>(offset, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1782 }
1783 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
1784 {
1785 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
1786 shader_Flat_Texture_Zbuffer_Ortho<color_t, ZBUFFER_t, false,false>(offset, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1787 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1788 shader_Flat_Texture_Zbuffer_Ortho<color_t, ZBUFFER_t, false,true>(offset, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1789 }
1790 }
1791 }
1792 else if (TGX_SHADER_HAS_NOTEXTURE(SHADER_FLAGS_ENABLED))
1793 {
1794 if (TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_GOURAUD(raster_type))
1795 shader_Gouraud_Zbuffer<color_t, ZBUFFER_t>(offset, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data); // same as perspective projection
1796 else if (TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED))
1797 shader_Flat_Zbuffer<color_t, ZBUFFER_t>(offset, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data); // same as perspective projection
1798 }
1799 }
1800 else if (TGX_SHADER_HAS_PERSPECTIVE(SHADER_FLAGS_ENABLED))
1801 { // USING PERSPECTIVE PROJECTION
1802 if (TGX_SHADER_HAS_TEXTURE(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE(raster_type))
1803 {
1804 if (TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_GOURAUD(raster_type))
1805 {
1806 if (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type))
1807 {
1808 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
1809 shader_Gouraud_Texture_Zbuffer<color_t, ZBUFFER_t, true,false>(offset, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1810 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1811 shader_Gouraud_Texture_Zbuffer<color_t, ZBUFFER_t, true, true>(offset, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1812 }
1813 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
1814 {
1815 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
1816 shader_Gouraud_Texture_Zbuffer<color_t, ZBUFFER_t, false,false>(offset, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1817 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1818 shader_Gouraud_Texture_Zbuffer<color_t, ZBUFFER_t, false,true>(offset, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1819 }
1820 }
1821 else if (TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED))
1822 {
1823 if (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type))
1824 {
1825 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
1826 shader_Flat_Texture_Zbuffer<color_t, ZBUFFER_t, true,false>(offset, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1827 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1828 shader_Flat_Texture_Zbuffer<color_t, ZBUFFER_t, true,true>(offset, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1829 }
1830 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
1831 {
1832 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
1833 shader_Flat_Texture_Zbuffer<color_t, ZBUFFER_t, false,false>(offset, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1834 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1835 shader_Flat_Texture_Zbuffer<color_t, ZBUFFER_t, false,true>(offset, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1836 }
1837 }
1838 }
1839 else if (TGX_SHADER_HAS_NOTEXTURE(SHADER_FLAGS_ENABLED))
1840 {
1841 if (TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_GOURAUD(raster_type))
1842 shader_Gouraud_Zbuffer<color_t, ZBUFFER_t>(offset, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1843 else if (TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED))
1844 shader_Flat_Zbuffer<color_t, ZBUFFER_t>(offset, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1845 }
1846 }
1847 }
1848 else if (TGX_SHADER_HAS_NOZBUFFER(SHADER_FLAGS_ENABLED))
1849 { // NOT USING Z-BUFFER
1850 if (TGX_SHADER_HAS_ORTHO(SHADER_FLAGS_ENABLED) && (TGX_SHADER_HAS_ORTHO(raster_type)))
1851 { // USING ORTHOGRAPHIC PROJECTION
1852 if (TGX_SHADER_HAS_TEXTURE(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE(raster_type))
1853 {
1854 if (TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_GOURAUD(raster_type))
1855 {
1856 if (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type))
1857 {
1858 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
1859 shader_Gouraud_Texture_Ortho<color_t, ZBUFFER_t, true,false>(offset, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1860 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1861 shader_Gouraud_Texture_Ortho<color_t, ZBUFFER_t, true,true>(offset, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1862 }
1863 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
1864 {
1865 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
1866 shader_Gouraud_Texture_Ortho<color_t, ZBUFFER_t, false,false>(offset, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1867 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1868 shader_Gouraud_Texture_Ortho<color_t, ZBUFFER_t, false,true>(offset, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1869 }
1870 }
1871 else if (TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED))
1872 {
1873 if (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type))
1874 {
1875 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
1876 shader_Flat_Texture_Ortho<color_t, ZBUFFER_t, true,false>(offset, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1877 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1878 shader_Flat_Texture_Ortho<color_t, ZBUFFER_t, true,true>(offset, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1879 }
1880 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
1881 {
1882 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
1883 shader_Flat_Texture_Ortho<color_t, ZBUFFER_t, false,false>(offset, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1884 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1885 shader_Flat_Texture_Ortho<color_t, ZBUFFER_t, false,true>(offset, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1886 }
1887 }
1888 }
1889 else if (TGX_SHADER_HAS_NOTEXTURE(SHADER_FLAGS_ENABLED))
1890 {
1891 if (TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_GOURAUD(raster_type))
1892 shader_Gouraud<color_t, ZBUFFER_t>(offset, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data); // same as perspective projection
1893 else if (TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED))
1894 shader_Flat<color_t, ZBUFFER_t>(offset, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data); // same as perspective projection
1895 }
1896 }
1897 else if (TGX_SHADER_HAS_PERSPECTIVE(SHADER_FLAGS_ENABLED))
1898 { // USING PERSPECTIVE PROJECTION
1899 if (TGX_SHADER_HAS_TEXTURE(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE(raster_type))
1900 {
1901 if (TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_GOURAUD(raster_type))
1902 {
1903 if (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type))
1904 {
1905 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
1906 shader_Gouraud_Texture<color_t, ZBUFFER_t, true, false>(offset, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1907 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1908 shader_Gouraud_Texture<color_t, ZBUFFER_t, true, true>(offset, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1909 }
1910 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
1911 {
1912 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
1913 shader_Gouraud_Texture<color_t, ZBUFFER_t, false, false>(offset, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1914 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1915 shader_Gouraud_Texture<color_t, ZBUFFER_t, false, true>(offset, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1916 }
1917 }
1918 else if (TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED))
1919 {
1920 if (TGX_SHADER_HAS_TEXTURE_BILINEAR(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_BILINEAR(raster_type))
1921 {
1922 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
1923 shader_Flat_Texture<color_t, ZBUFFER_t, true, false>(offset, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1924 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1925 shader_Flat_Texture<color_t, ZBUFFER_t, true, true>(offset, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1926 }
1927 else if (TGX_SHADER_HAS_TEXTURE_NEAREST(SHADER_FLAGS_ENABLED))
1928 {
1929 if (TGX_SHADER_HAS_TEXTURE_CLAMP(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_TEXTURE_CLAMP(raster_type))
1930 shader_Flat_Texture<color_t, ZBUFFER_t, false, false>(offset, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1931 else if (TGX_SHADER_HAS_TEXTURE_WRAP_POW2(SHADER_FLAGS_ENABLED))
1932 shader_Flat_Texture<color_t, ZBUFFER_t, false, true>(offset, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1933 }
1934 }
1935 }
1936 else if (TGX_SHADER_HAS_NOTEXTURE(SHADER_FLAGS_ENABLED))
1937 {
1938 if (TGX_SHADER_HAS_GOURAUD(SHADER_FLAGS_ENABLED) && TGX_SHADER_HAS_GOURAUD(raster_type))
1939 shader_Gouraud<color_t, ZBUFFER_t>(offset, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1940 else if (TGX_SHADER_HAS_FLAT(SHADER_FLAGS_ENABLED))
1941 shader_Flat<color_t, ZBUFFER_t>(offset, lx, ly, dx1, dy1, O1, fP1, dx2, dy2, O2, fP2, dx3, dy3, O3, fP3, data);
1942 }
1943 }
1944 }
1945 }
1946
1947
1948
1949
1950
1954 template<bool USE_BLENDING, typename color_t_im>
1955 void shader_2D_gradient(const int32_t& offset, const int32_t& lx, const int32_t& ly,
1956 const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4& fP1,
1957 const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4& fP2,
1958 const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4& fP3,
1959 const RasterizerParams<color_t_im, color_t_im, float> & data)
1960 {
1961 color_t_im * buf = data.im->data() + offset;
1962 const int32_t stride = data.im->stride();
1963
1964 // use RGB32 (could use RGB64 be it would be slower).
1965 const RGB32 col1 = RGB64(fP1.color.R, fP1.color.G, fP1.color.B, fP1.A);
1966 const RGB32 col2 = RGB64(fP2.color.R, fP2.color.G, fP2.color.B, fP2.A);
1967 const RGB32 col3 = RGB64(fP3.color.R, fP3.color.G, fP3.color.B, fP3.A);
1968
1969 const uintptr_t end = (uintptr_t)(buf + (ly * stride));
1970 const int32_t pa = O1 + O2 + O3;
1971 const int32_t E = ((pa == 0) ? 1 : 0);
1972 const int32_t aera = pa + E;
1973 const int shiftC = (aera > (1 << 22)) ? 10 : 0; // prevent overflow during color interpolation
1974
1975 while ((uintptr_t)(buf) < end)
1976 { // iterate over scanlines
1977 int32_t bx = 0; // start offset
1978 if (O1 < 0)
1979 {
1980 // we know that dx1 > 0
1981 bx = (-O1 + dx1 - 1) / dx1; // first index where it becomes positive
1982 }
1983 if (O2 < 0)
1984 {
1985 if (dx2 <= 0)
1986 {
1987 if (dy2 <= 0) return;
1988 const int32_t by = (-O2 + dy2 - 1) / dy2;
1989 O1 += (by * dy1);
1990 O2 += (by * dy2);
1991 O3 += (by * dy3);
1992 const int32_t offs = by * stride;
1993 buf += offs;
1994 continue;
1995 }
1996 bx = max(bx, ((-O2 + dx2 - 1) / dx2));
1997 }
1998 if (O3 < 0)
1999 {
2000 if (dx3 <= 0)
2001 {
2002 if (dy3 <= 0) return;
2003 const int32_t by = (-O3 + dy3 - 1) / dy3;
2004 O1 += (by * dy1);
2005 O2 += (by * dy2);
2006 O3 += (by * dy3);
2007 const int32_t offs = by * stride;
2008 buf += offs;
2009 continue;
2010 }
2011 bx = max(bx, ((-O3 + dx3 - 1) / dx3));
2012 }
2013
2014 int32_t C2 = O2 + (dx2 * bx);
2015 int32_t C3 = O3 + (dx3 * bx);
2016 while ((bx < lx) && ((C2 | C3) >= 0))
2017 {
2018 if (USE_BLENDING)
2019 {
2020 RGB32 c(buf[bx]); // could use RGB64 instead but would be slower
2021 c.blend(interpolateColorsTriangle(col2, C2 >> shiftC, col3, C3 >> shiftC, col1, aera >> shiftC), data.opacity);
2022 buf[bx] = color_t_im(c);
2023 }
2024 else
2025 {
2026 buf[bx] = color_t_im(interpolateColorsTriangle(col2, C2 >> shiftC, col3, C3 >> shiftC, col1, aera >> shiftC));
2027 }
2028 C2 += dx2;
2029 C3 += dx3;
2030 bx++;
2031 }
2032
2033 O1 += dy1;
2034 O2 += dy2;
2035 O3 += dy3;
2036 buf += stride;
2037 }
2038 }
2039
2040
2041
2045 template<bool USE_BLENDING, bool USE_MASKING, bool USE_GRADIENT, typename color_t_im, typename color_t_tex>
2046 void shader_2D_texture(const int32_t& offset, const int32_t& lx, const int32_t& ly,
2047 const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4& fP1,
2048 const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4& fP2,
2049 const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4& fP3,
2050 const RasterizerParams<color_t_im, color_t_tex, float> & data)
2051 {
2052
2053 color_t_im * buf = data.im->data() + offset;
2054 const int32_t stride = data.im->stride();
2055
2056 const uintptr_t end = (uintptr_t)(buf + (ly * stride));
2057 const int32_t pa = O1 + O2 + O3;
2058 const int32_t E = ((pa == 0) ? 1 : 0);
2059 const int32_t aera = pa + E;
2060
2061 const float invaera = fast_inv((float)aera);
2062
2063 const color_t_tex mask_color = data.mask_color;
2064
2065 const RGBf& cf1 = (RGBf)fP1.color;
2066 const RGBf& cf2 = (RGBf)fP2.color;
2067 const RGBf& cf3 = (RGBf)fP3.color;
2068
2069 // the texture coord
2070 fVec2 T1 = fP1.T;
2071 fVec2 T2 = fP2.T;
2072 fVec2 T3 = fP3.T;
2073
2074 const color_t_tex * tex = data.tex->data();
2075 const int32_t texsize_x = data.tex->width();
2076 const int32_t texsize_y = data.tex->height();
2077 const int32_t texsize_x_mm = data.tex->width() - 1;
2078 const int32_t texsize_y_mm = data.tex->height() - 1;
2079 const int32_t texstride = data.tex->stride();
2080
2081 // divide the texture coord by aera
2082 T1 *= invaera;
2083 T2 *= invaera;
2084 T3 *= invaera;
2085 T1.x *= texsize_x;
2086 T2.x *= texsize_x;
2087 T3.x *= texsize_x;
2088 T1.y *= texsize_y;
2089 T2.y *= texsize_y;
2090 T3.y *= texsize_y;
2091
2092 const float dtx = ((T1.x * dx1) + (T2.x * dx2) + (T3.x * dx3));
2093 const float dty = ((T1.y * dx1) + (T2.y * dx2) + (T3.y * dx3));
2094
2095 while ((uintptr_t)(buf) < end)
2096 { // iterate over scanlines
2097 int32_t bx = 0; // start offset
2098 if (O1 < 0)
2099 {
2100 // we know that dx1 > 0
2101 bx = (-O1 + dx1 - 1) / dx1; // first index where it becomes positive
2102 }
2103 if (O2 < 0)
2104 {
2105 if (dx2 <= 0)
2106 {
2107 if (dy2 <= 0) return;
2108 const int32_t by = (-O2 + dy2 - 1) / dy2;
2109 O1 += (by * dy1);
2110 O2 += (by * dy2);
2111 O3 += (by * dy3);
2112 const int32_t offs = by * stride;
2113 buf += offs;
2114 continue;
2115 }
2116 bx = max(bx, ((-O2 + dx2 - 1) / dx2));
2117 }
2118 if (O3 < 0)
2119 {
2120 if (dx3 <= 0)
2121 {
2122 if (dy3 <= 0) return;
2123 const int32_t by = (-O3 + dy3 - 1) / dy3;
2124 O1 += (by * dy1);
2125 O2 += (by * dy2);
2126 O3 += (by * dy3);
2127 const int32_t offs = by * stride;
2128 buf += offs;
2129 continue;
2130 }
2131 bx = max(bx, ((-O3 + dx3 - 1) / dx3));
2132 }
2133
2134 int32_t C1 = O1 + (dx1 * bx) + E;
2135 int32_t C2 = O2 + (dx2 * bx);
2136 int32_t C3 = O3 + (dx3 * bx);
2137
2138 float tx = ((T1.x * C1) + (T2.x * C2) + (T3.x * C3)) - 0.5f;
2139 float ty = ((T1.y * C1) + (T2.y * C2) + (T3.y * C3)) - 0.5f;
2140
2141 while ((bx < lx) && ((C2 | C3) >= 0))
2142 {
2143 const float xx = tx;
2144 const float yy = ty;
2145 const int ttx = (int)floorf(xx);
2146 const int tty = (int)floorf(yy);
2147 const float ax = xx - ttx;
2148 const float ay = yy - tty;
2149
2150 const int minx = shaderclip(ttx, texsize_x_mm);
2151 const int maxx = shaderclip(ttx + 1, texsize_x_mm);
2152 const int miny = shaderclip(tty, texsize_y_mm) * texstride;
2153 const int maxy = shaderclip(tty + 1, texsize_y_mm) * texstride;
2154
2155 if (USE_MASKING)
2156 { //
2157 auto col00 = tex[minx + miny];
2158 tgx::RGB32 acol00 = (col00 == mask_color) ? tgx::RGB32((uint32_t)0) : tgx::RGB32(col00);
2159
2160 auto col10 = tex[maxx + miny];
2161 tgx::RGB32 acol10 = (col10 == mask_color) ? tgx::RGB32((uint32_t)0) : tgx::RGB32(col10);
2162
2163 auto col01 = tex[minx + maxy];
2164 tgx::RGB32 acol01 = (col01 == mask_color) ? tgx::RGB32((uint32_t)0) : tgx::RGB32(col01);
2165
2166 auto col11 = tex[maxx + maxy];
2167 tgx::RGB32 acol11 = (col11 == mask_color) ? tgx::RGB32((uint32_t)0) : tgx::RGB32(col11);
2168
2169 tgx::RGB32 col = interpolateColorsBilinear(acol00, acol10, acol01, acol11, ax, ay);
2170
2171 if (USE_GRADIENT)
2172 {
2173 const int sC2 = C2;
2174 const int sC3 = C3;
2175 const int sC1 = aera - C3 - C2;
2176 const float m = 256.0f / aera;
2177 const int r = (int)((sC1 * cf1.R + sC2 * cf2.R + sC3 * cf3.R) * m);
2178 const int g = (int)((sC1 * cf1.G + sC2 * cf2.G + sC3 * cf3.G) * m);
2179 const int b = (int)((sC1 * cf1.B + sC2 * cf2.B + sC3 * cf3.B) * m);
2180 const int a = (int)((sC1 * fP1.A + sC2 * fP2.A + sC3 * fP3.A) * m);
2181 col.mult256(r, g, b, a);
2182 }
2183 if (USE_BLENDING)
2184 {
2185 tgx::RGB32 c = tgx::RGB32(buf[bx]);
2186 c.blend(col, data.opacity);
2187 buf[bx] = color_t_im(c);
2188 }
2189 else
2190 {
2191 buf[bx] = color_t_im(col);
2192 }
2193 }
2194 else
2195 {
2196 color_t_tex col = interpolateColorsBilinear(tex[minx + miny], tex[maxx + miny], tex[minx + maxy], tex[maxx + maxy], ax, ay);
2197 if (USE_GRADIENT)
2198 {
2199 const int sC2 = C2;
2200 const int sC3 = C3;
2201 const int sC1 = aera - C3 - C2;
2202 const float m = 256.0f / aera;
2203 const int r = (int)((sC1 * cf1.R + sC2 * cf2.R + sC3 * cf3.R) * m);
2204 const int g = (int)((sC1 * cf1.G + sC2 * cf2.G + sC3 * cf3.G) * m);
2205 const int b = (int)((sC1 * cf1.B + sC2 * cf2.B + sC3 * cf3.B) * m);
2206 const int a = (int)((sC1 * fP1.A + sC2 * fP2.A + sC3 * fP3.A) * m);
2207 col.mult256(r, g, b, a);
2208 }
2209 if (USE_BLENDING)
2210 {
2211 color_t_tex c = color_t_tex(buf[bx]);
2212 c.blend(col, data.opacity);
2213 buf[bx] = color_t_im(c);
2214 }
2215 else
2216 {
2217 buf[bx] = color_t_im(col);
2218 }
2219 }
2220
2221 C2 += dx2;
2222 C3 += dx3;
2223
2224 tx += dtx;
2225 ty += dty;
2226
2227 bx++;
2228 }
2229
2230 O1 += dy1;
2231 O2 += dy2;
2232 O3 += dy3;
2233 buf += stride;
2234 }
2235 }
2236
2237
2238
2239
2243 template<typename BLEND_OP, typename color_t_im, typename color_t_tex>
2244 void shader_2D_texture_blend_op(const int32_t& offset, const int32_t& lx, const int32_t& ly,
2245 const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4& fP1,
2246 const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4& fP2,
2247 const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4& fP3,
2248 const RasterizerParams<color_t_im, color_t_tex, float, BLEND_OP> & data)
2249 {
2250
2251 color_t_im * buf = data.im->data() + offset;
2252 const int32_t stride = data.im->stride();
2253
2254 const uintptr_t end = (uintptr_t)(buf + (ly * stride));
2255 const int32_t pa = O1 + O2 + O3;
2256 const int32_t E = ((pa == 0) ? 1 : 0);
2257 const int32_t aera = pa + E;
2258
2259 const float invaera = fast_inv((float)aera);
2260
2261 // the texture coord
2262 fVec2 T1 = fP1.T;
2263 fVec2 T2 = fP2.T;
2264 fVec2 T3 = fP3.T;
2265
2266
2267 const color_t_tex * tex = data.tex->data();
2268 const int32_t texsize_x = data.tex->width();
2269 const int32_t texsize_y = data.tex->height();
2270 const int32_t texsize_x_mm = data.tex->width() - 1;
2271 const int32_t texsize_y_mm = data.tex->height() - 1;
2272 const int32_t texstride = data.tex->stride();
2273
2274 // divide the texture coord by aera
2275 T1 *= invaera;
2276 T2 *= invaera;
2277 T3 *= invaera;
2278 T1.x *= texsize_x;
2279 T2.x *= texsize_x;
2280 T3.x *= texsize_x;
2281 T1.y *= texsize_y;
2282 T2.y *= texsize_y;
2283 T3.y *= texsize_y;
2284
2285 const float dtx = ((T1.x * dx1) + (T2.x * dx2) + (T3.x * dx3));
2286 const float dty = ((T1.y * dx1) + (T2.y * dx2) + (T3.y * dx3));
2287
2288 while ((uintptr_t)(buf) < end)
2289 { // iterate over scanlines
2290 int32_t bx = 0; // start offset
2291 if (O1 < 0)
2292 {
2293 // we know that dx1 > 0
2294 bx = (-O1 + dx1 - 1) / dx1; // first index where it becomes positive
2295 }
2296 if (O2 < 0)
2297 {
2298 if (dx2 <= 0)
2299 {
2300 if (dy2 <= 0) return;
2301 const int32_t by = (-O2 + dy2 - 1) / dy2;
2302 O1 += (by * dy1);
2303 O2 += (by * dy2);
2304 O3 += (by * dy3);
2305 const int32_t offs = by * stride;
2306 buf += offs;
2307 continue;
2308 }
2309 bx = max(bx, ((-O2 + dx2 - 1) / dx2));
2310 }
2311 if (O3 < 0)
2312 {
2313 if (dx3 <= 0)
2314 {
2315 if (dy3 <= 0) return;
2316 const int32_t by = (-O3 + dy3 - 1) / dy3;
2317 O1 += (by * dy1);
2318 O2 += (by * dy2);
2319 O3 += (by * dy3);
2320 const int32_t offs = by * stride;
2321 buf += offs;
2322 continue;
2323 }
2324 bx = max(bx, ((-O3 + dx3 - 1) / dx3));
2325 }
2326
2327 int32_t C1 = O1 + (dx1 * bx) + E;
2328 int32_t C2 = O2 + (dx2 * bx);
2329 int32_t C3 = O3 + (dx3 * bx);
2330
2331 float tx = ((T1.x * C1) + (T2.x * C2) + (T3.x * C3)) - 0.5f;
2332 float ty = ((T1.y * C1) + (T2.y * C2) + (T3.y * C3)) - 0.5f;
2333
2334 while ((bx < lx) && ((C2 | C3) >= 0))
2335 {
2336 const float xx = tx;
2337 const float yy = ty;
2338 const int ttx = (int)floorf(xx);
2339 const int tty = (int)floorf(yy);
2340 const float ax = xx - ttx;
2341 const float ay = yy - tty;
2342
2343 const int minx = shaderclip(ttx, texsize_x_mm);
2344 const int maxx = shaderclip(ttx + 1, texsize_x_mm);
2345 const int miny = shaderclip(tty, texsize_y_mm) * texstride;
2346 const int maxy = shaderclip(tty + 1, texsize_y_mm) * texstride;
2347
2348 color_t_tex col = interpolateColorsBilinear(tex[minx + miny], tex[maxx + miny], tex[minx + maxy], tex[maxx + maxy], ax, ay);
2349
2350 buf[bx] = (color_t_im)((*data.p_blend_op)(col, buf[bx]));
2351
2352 C2 += dx2;
2353 C3 += dx3;
2354
2355 tx += dtx;
2356 ty += dty;
2357
2358 bx++;
2359 }
2360
2361 O1 += dy1;
2362 O2 += dy2;
2363 O3 += dy3;
2364 buf += stride;
2365 }
2366 }
2367
2368
2369}
2370
2371#endif
2372
2373#endif
2374
const RGB32 RGB32_Red
Color red in RGB32 format.
RGB565 interpolateColorsBilinear(const RGB565 &C00, const RGB565 &C10, const RGB565 &C01, const RGB565 &C11, const float ax, const float ay)
Bilinear interpolation between 4 colors.
Definition: Color.h:621
RGB565 interpolateColorsTriangle(const RGB565 &col1, int32_t C1, const RGB565 &col2, int32_t C2, const RGB565 &col3, const int32_t totC)
Interpolate between 3 colors.
Definition: Color.h:591
TGX_INLINE T max(const T &a, const T &b)
Don't know why but much faster than fmaxf() for floats.
Definition: Misc.h:184
TGX_INLINE float fast_inv(float x)
Fast (approximate) computation of 1/x.
Definition: Misc.h:219
Triangle shader parameters.
void shader_test(const int32_t &offset, const int32_t &lx, const int32_t &ly, const int32_t &dx1, const int32_t &dy1, int32_t O1, const tgx::RasterizerVec4 &fP1, const int32_t &dx2, const int32_t &dy2, int32_t O2, const tgx::RasterizerVec4 &fP2, const int32_t &dx3, const int32_t &dy3, int32_t O3, const tgx::RasterizerVec4 &fP3, const tgx::RasterizerParams< color_t, color_t, ZBUFFER_t > &data)
For test purposes...
Definition: Shaders.h:45
void shader_select(const int32_t &offset, const int32_t &lx, const int32_t &ly, const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4 &fP1, const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4 &fP2, const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4 &fP3, const RasterizerParams< color_t, color_t, ZBUFFER_t > &data)
META-Shader THAT DISPATCH TO THE CORRECT Shader ABOVE (IF ENABLED).
Definition: Shaders.h:1744
void shader_Gouraud_Texture(const int32_t &offset, const int32_t &lx, const int32_t &ly, const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4 &fP1, const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4 &fP2, const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4 &fP3, const RasterizerParams< color_t, color_t, ZBUFFER_t > &data)
TEXTURE + GOURAUD SHADING (NO ZBUFFER)
Definition: Shaders.h:382
void shader_2D_texture(const int32_t &offset, const int32_t &lx, const int32_t &ly, const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4 &fP1, const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4 &fP2, const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4 &fP3, const RasterizerParams< color_t_im, color_t_tex, float > &data)
2D shader (texture)
Definition: Shaders.h:2046
void shader_Flat(const int32_t &offset, const int32_t &lx, const int32_t &ly, const int32_t &dx1, const int32_t &dy1, int32_t O1, const RasterizerVec4 &fP1, const int32_t &dx2, const int32_t &dy2, int32_t O2, const RasterizerVec4 &fP2, const int32_t &dx3, const int32_t &dy3, int32_t O3, const RasterizerVec4 &fP3, const RasterizerParams< color_t, color_t, ZBUFFER_t > &data)
FLAT SHADING (NO ZBUFFER)
Definition: Shaders.h:74
void shader_Flat_Texture(const int32_t &offset, const int32_t &lx, const int32_t &ly, const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4 &fP1, const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4 &fP2, const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4 &fP3, const RasterizerParams< color_t, color_t, ZBUFFER_t > &data)
TEXTURE + FLAT SHADING (NO ZBUFFER)
Definition: Shaders.h:230
void shader_Gouraud(const int32_t &offset, const int32_t &lx, const int32_t &ly, const int32_t &dx1, const int32_t &dy1, int32_t O1, const RasterizerVec4 &fP1, const int32_t &dx2, const int32_t &dy2, int32_t O2, const RasterizerVec4 &fP2, const int32_t &dx3, const int32_t &dy3, int32_t O3, const RasterizerVec4 &fP3, const RasterizerParams< color_t, color_t, ZBUFFER_t > &data)
GOURAUD SHADING (NO Z BUFFER)
Definition: Shaders.h:149
void shader_Flat_Texture_Zbuffer_Ortho(const int32_t &offset, const int32_t &lx, const int32_t &ly, const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4 &fP1, const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4 &fP2, const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4 &fP3, const RasterizerParams< color_t, color_t, ZBUFFER_t > &data)
ZBUFFER + TEXTURE + FLAT SHADING + ORTHOGRAPHIC.
Definition: Shaders.h:1397
void shader_Gouraud_Texture_Ortho(const int32_t &offset, const int32_t &lx, const int32_t &ly, const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4 &fP1, const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4 &fP2, const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4 &fP3, const RasterizerParams< color_t, color_t, ZBUFFER_t > &data)
TEXTURE + GOURAUD SHADING (NO ZBUFFER) + ORTHOGRAPHIC.
Definition: Shaders.h:1243
void shader_Flat_Texture_Zbuffer(const int32_t &offset, const int32_t &lx, const int32_t &ly, const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4 &fP1, const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4 &fP2, const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4 &fP3, const RasterizerParams< color_t, color_t, ZBUFFER_t > &data)
ZBUFFER + TEXTURE + FLAT SHADING.
Definition: Shaders.h:755
void shader_Flat_Texture_Ortho(const int32_t &offset, const int32_t &lx, const int32_t &ly, const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4 &fP1, const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4 &fP2, const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4 &fP3, const RasterizerParams< color_t, color_t, ZBUFFER_t > &data)
TEXTURE + FLAT SHADING (NO ZBUFFER) + ORTHOGRAPHIC.
Definition: Shaders.h:1101
void shader_Gouraud_Texture_Zbuffer_Ortho(const int32_t &offset, const int32_t &lx, const int32_t &ly, const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4 &fP1, const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4 &fP2, const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4 &fP3, const RasterizerParams< color_t, color_t, ZBUFFER_t > &data)
ZBUFFER + TEXTURE + GOURAUD SHADING + ORTHOGRAPHIC.
Definition: Shaders.h:1564
void shader_Gouraud_Zbuffer(const int32_t &offset, const int32_t &lx, const int32_t &ly, const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4 &fP1, const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4 &fP2, const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4 &fP3, const RasterizerParams< color_t, color_t, ZBUFFER_t > &data)
ZBUFFER + GOURAUD SHADING.
Definition: Shaders.h:649
void shader_2D_gradient(const int32_t &offset, const int32_t &lx, const int32_t &ly, const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4 &fP1, const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4 &fP2, const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4 &fP3, const RasterizerParams< color_t_im, color_t_im, float > &data)
2D shader (gradient)
Definition: Shaders.h:1955
TGX_INLINE int shaderclip(int v, int maxv)
for texture clamping
Definition: Shaders.h:34
void shader_Flat_Zbuffer(const int32_t offset, const int32_t &lx, const int32_t &ly, const int32_t &dx1, const int32_t &dy1, int32_t O1, const RasterizerVec4 &fP1, const int32_t &dx2, const int32_t &dy2, int32_t O2, const RasterizerVec4 &fP2, const int32_t &dx3, const int32_t &dy3, int32_t O3, const RasterizerVec4 &fP3, const RasterizerParams< color_t, color_t, ZBUFFER_t > &data)
ZBUFFER + FLAT SHADING.
Definition: Shaders.h:547
void shader_Gouraud_Texture_Zbuffer(const int32_t &offset, const int32_t &lx, const int32_t &ly, const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4 &fP1, const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4 &fP2, const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4 &fP3, const RasterizerParams< color_t, color_t, ZBUFFER_t > &data)
ZBUFFER + TEXTURE + GOURAUD SHADING.
Definition: Shaders.h:923
void shader_2D_texture_blend_op(const int32_t &offset, const int32_t &lx, const int32_t &ly, const int32_t dx1, const int32_t dy1, int32_t O1, const RasterizerVec4 &fP1, const int32_t dx2, const int32_t dy2, int32_t O2, const RasterizerVec4 &fP2, const int32_t dx3, const int32_t dy3, int32_t O3, const RasterizerVec4 &fP3, const RasterizerParams< color_t_im, color_t_tex, float, BLEND_OP > &data)
2D shader (texture with custom blending operator)
Definition: Shaders.h:2244
Color in R8/G8/B8/A8 format.
Definition: Color.h:1176
void mult256(int mr, int mg, int mb)
Multiply each color component by a given factor m/256 with m in [0,256] except the A component.
Definition: Color.h:1590
void blend256(const RGB32 &fg_col, uint32_t alpha)
alpha-blend fg_col over this one with a given opacity in the range 0.0f (fully transparent) to 1....
Definition: Color.h:1561
void blend(const RGB32 &fg_col, float alpha)
alpha-blend fg_col over this one with a given opacity in the range 0.0f (fully transparent) to 1....
Definition: Color.h:1546
float opacity() const
Return the opacity (alpha channel value) of this color in the range [0,1] (0=fully transparent,...
Definition: Color.h:1629
float opacity() const
Dummy function for compatibility with color types having an alpha channel.
Definition: Color.h:565
Color in R16/G16/B16/A16 format.
Definition: Color.h:1791
Color in R,G,B float format.
Definition: Color.h:2407
float R
Red channel.
Definition: Color.h:2420
float B
Blue channel.
Definition: Color.h:2422
float G
Green channel.
Definition: Color.h:2421
T x
'x' coordinate (first dimension)
Definition: Vec2.h:72
T y
'y' coordinate (second dimension)
Definition: Vec2.h:73