1 /* ResidualVM - A 3D game interpreter
2  *
3  * ResidualVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the AUTHORS
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 /*
24  * This file is based on, or a modified version of code from TinyGL (C) 1997-1998 Fabrice Bellard,
25  * which is licensed under the zlib-license (see LICENSE).
26  * It also has modifications by the ResidualVM-team, which are covered under the GPLv2 (or later).
27  */
28 
29 #include "common/endian.h"
30 #include "graphics/tinygl/zbuffer.h"
31 #include "graphics/tinygl/zgl.h"
32 
33 namespace TinyGL {
34 
35 static const int NB_INTERP = 8;
36 
37 template <bool kDepthWrite, bool kEnableAlphaTest, bool kEnableScissor, bool kEnableBlending>
putPixelFlat(FrameBuffer * buffer,int buf,unsigned int * pz,int _a,int x,int y,unsigned int & z,unsigned int & r,unsigned int & g,unsigned int & b,unsigned int & a,int & dzdx)38 FORCEINLINE static void putPixelFlat(FrameBuffer *buffer, int buf, unsigned int *pz, int _a,
39                                      int x, int y, unsigned int &z, unsigned int &r, unsigned int &g, unsigned int &b, unsigned int &a, int &dzdx) {
40 	if ((!kEnableScissor || !buffer->scissorPixel(x + _a, y)) && buffer->compareDepth(z, pz[_a])) {
41 		buffer->writePixel<kEnableAlphaTest, kEnableBlending, kDepthWrite>(buf + _a, a >> (ZB_POINT_ALPHA_BITS - 8), r >> (ZB_POINT_RED_BITS - 8), g >> (ZB_POINT_GREEN_BITS - 8), b >> (ZB_POINT_BLUE_BITS - 8), z);
42 	}
43 	z += dzdx;
44 }
45 
46 template <bool kDepthWrite, bool kEnableAlphaTest, bool kEnableScissor, bool kEnableBlending>
putPixelSmooth(FrameBuffer * buffer,int buf,unsigned int * pz,int _a,int x,int y,unsigned int & z,unsigned int & r,unsigned int & g,unsigned int & b,unsigned int & a,int & dzdx,int & drdx,int & dgdx,int & dbdx,unsigned int dadx)47 FORCEINLINE static void putPixelSmooth(FrameBuffer *buffer, int buf, unsigned int *pz, int _a,
48                                        int x, int y, unsigned int &z, unsigned int &r, unsigned int &g, unsigned int &b, unsigned int &a,
49                                        int &dzdx, int &drdx, int &dgdx, int &dbdx, unsigned int dadx) {
50 	if ((!kEnableScissor || !buffer->scissorPixel(x + _a, y)) && buffer->compareDepth(z, pz[_a])) {
51 		buffer->writePixel<kEnableAlphaTest, kEnableBlending, kDepthWrite>(buf + _a, a >> (ZB_POINT_ALPHA_BITS - 8), r >> (ZB_POINT_RED_BITS - 8), g >> (ZB_POINT_GREEN_BITS - 8), b >> (ZB_POINT_BLUE_BITS - 8), z);
52 	}
53 	z += dzdx;
54 	a += dadx;
55 	r += drdx;
56 	g += dgdx;
57 	b += dbdx;
58 }
59 
60 template <bool kDepthWrite, bool kEnableScissor>
putPixelDepth(FrameBuffer * buffer,int buf,unsigned int * pz,int _a,int x,int y,unsigned int & z,int & dzdx)61 FORCEINLINE static void putPixelDepth(FrameBuffer *buffer, int buf, unsigned int *pz, int _a, int x, int y, unsigned int &z, int &dzdx) {
62 	if ((!kEnableScissor || !buffer->scissorPixel(x + _a, y)) && buffer->compareDepth(z, pz[_a])) {
63 		if (kDepthWrite) {
64 			pz[_a] = z;
65 		}
66 	}
67 	z += dzdx;
68 }
69 
70 template <bool kDepthWrite, bool kAlphaTestEnabled, bool kEnableScissor, bool kBlendingEnabled>
putPixelShadow(FrameBuffer * buffer,int buf,unsigned int * pz,int _a,int x,int y,unsigned int & z,unsigned int & r,unsigned int & g,unsigned int & b,int & dzdx,unsigned char * pm)71 FORCEINLINE static void putPixelShadow(FrameBuffer *buffer, int buf, unsigned int *pz, int _a, int x, int y, unsigned int &z, unsigned int &r, unsigned int &g, unsigned int &b, int &dzdx, unsigned char *pm) {
72 	if ((!kEnableScissor || !buffer->scissorPixel(x + _a, y)) && buffer->compareDepth(z, pz[_a]) && pm[_a]) {
73 		buffer->writePixel<kAlphaTestEnabled, kBlendingEnabled, kDepthWrite>(buf + _a, 255, r >> (ZB_POINT_RED_BITS - 8), g >> (ZB_POINT_GREEN_BITS - 8), b >> (ZB_POINT_BLUE_BITS - 8), z);
74 	}
75 	z += dzdx;
76 }
77 
78 template <bool kDepthWrite, bool kLightsMode, bool kSmoothMode, bool kEnableAlphaTest, bool kEnableScissor, bool kEnableBlending>
putPixelTextureMappingPerspective(FrameBuffer * buffer,int buf,Graphics::PixelFormat & textureFormat,Graphics::PixelBuffer & texture,unsigned int * pz,int _a,int x,int y,unsigned int & z,unsigned int & t,unsigned int & s,unsigned int & r,unsigned int & g,unsigned int & b,unsigned int & a,int & dzdx,int & dsdx,int & dtdx,int & drdx,int & dgdx,int & dbdx,unsigned int dadx)79 FORCEINLINE static void putPixelTextureMappingPerspective(FrameBuffer *buffer, int buf,
80                         Graphics::PixelFormat &textureFormat, Graphics::PixelBuffer &texture, unsigned int *pz, int _a,
81                         int x, int y, unsigned int &z, unsigned int &t, unsigned int &s, unsigned int &r, unsigned int &g, unsigned int &b, unsigned int &a,
82                         int &dzdx, int &dsdx, int &dtdx, int &drdx, int &dgdx, int &dbdx, unsigned int dadx) {
83 	if ((!kEnableScissor || !buffer->scissorPixel(x + _a, y)) && buffer->compareDepth(z, pz[_a])) {
84 		unsigned sss = (s & buffer->_textureSizeMask) >> ZB_POINT_ST_FRAC_BITS;
85 		unsigned ttt = (t & buffer->_textureSizeMask) >> ZB_POINT_ST_FRAC_BITS;
86 		int pixel = ttt * buffer->_textureSize + sss;
87 		uint8 c_a, c_r, c_g, c_b;
88 		uint32 *textureBuffer = (uint32 *)texture.getRawBuffer(pixel);
89 		uint32 col = *textureBuffer;
90 		c_a = (col >> textureFormat.aShift) & 0xFF;
91 		c_r = (col >> textureFormat.rShift) & 0xFF;
92 		c_g = (col >> textureFormat.gShift) & 0xFF;
93 		c_b = (col >> textureFormat.bShift) & 0xFF;
94 		if (kLightsMode) {
95 			unsigned int l_a = (a >> (ZB_POINT_ALPHA_BITS - 8));
96 			unsigned int l_r = (r >> (ZB_POINT_RED_BITS - 8));
97 			unsigned int l_g = (g >> (ZB_POINT_GREEN_BITS - 8));
98 			unsigned int l_b = (b >> (ZB_POINT_BLUE_BITS - 8));
99 			c_a = (c_a * l_a) >> (ZB_POINT_ALPHA_BITS - 8);
100 			c_r = (c_r * l_r) >> (ZB_POINT_RED_BITS - 8);
101 			c_g = (c_g * l_g) >> (ZB_POINT_GREEN_BITS - 8);
102 			c_b = (c_b * l_b) >> (ZB_POINT_BLUE_BITS - 8);
103 		}
104 		buffer->writePixel<kEnableAlphaTest, kEnableBlending, kDepthWrite>(buf + _a, c_a, c_r, c_g, c_b, z);
105 	}
106 	z += dzdx;
107 	s += dsdx;
108 	t += dtdx;
109 	if (kSmoothMode) {
110 		a += dadx;
111 		r += drdx;
112 		g += dgdx;
113 		b += dbdx;
114 	}
115 }
116 
117 template <bool kInterpRGB, bool kInterpZ, bool kInterpST, bool kInterpSTZ, int kDrawLogic, bool kDepthWrite, bool kAlphaTestEnabled, bool kEnableScissor, bool kBlendingEnabled>
fillTriangle(ZBufferPoint * p0,ZBufferPoint * p1,ZBufferPoint * p2)118 void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
119 	Graphics::PixelBuffer texture;
120 	Graphics::PixelFormat textureFormat;
121 	float fdzdx = 0, fndzdx = 0, ndszdx = 0, ndtzdx = 0;
122 
123 	ZBufferPoint *tp, *pr1 = 0, *pr2 = 0, *l1 = 0, *l2 = 0;
124 	float fdx1, fdx2, fdy1, fdy2, fz0, d1, d2;
125 	unsigned int *pz1 = NULL;
126 	unsigned char *pm1 = NULL;
127 	int part, update_left = 1, update_right = 1;
128 
129 	int nb_lines, dx1, dy1, tmp, dx2, dy2, y;
130 
131 	int error = 0, derror = 0;
132 	int x1 = 0, dxdy_min = 0, dxdy_max = 0;
133 	// warning: x2 is multiplied by 2^16
134 	int x2 = 0, dx2dy2 = 0;
135 
136 	int z1 = 0, dzdx = 0, dzdy = 0, dzdl_min = 0, dzdl_max = 0;
137 
138 	int r1 = 0, drdx = 0, drdy = 0, drdl_min = 0, drdl_max = 0;
139 	int g1 = 0, dgdx = 0, dgdy = 0, dgdl_min = 0, dgdl_max = 0;
140 	int b1 = 0, dbdx = 0, dbdy = 0, dbdl_min = 0, dbdl_max = 0;
141 	int a1 = 0, dadx = 0, dady = 0, dadl_min = 0, dadl_max = 0;
142 
143 	float sz1 = 0.0, dszdx = 0, dszdy = 0, dszdl_min = 0.0, dszdl_max = 0.0;
144 	float tz1 = 0.0, dtzdx = 0, dtzdy = 0, dtzdl_min = 0.0, dtzdl_max = 0.0;
145 
146 	// we sort the vertex with increasing y
147 	if (p1->y < p0->y) {
148 		tp = p0;
149 		p0 = p1;
150 		p1 = tp;
151 	}
152 	if (p2->y < p0->y) {
153 		tp = p2;
154 		p2 = p1;
155 		p1 = p0;
156 		p0 = tp;
157 	} else if (p2->y < p1->y) {
158 		tp = p1;
159 		p1 = p2;
160 		p2 = tp;
161 	}
162 
163 	// we compute dXdx and dXdy for all interpolated values
164 
165 	fdx1 = (float)(p1->x - p0->x);
166 	fdy1 = (float)(p1->y - p0->y);
167 
168 	fdx2 = (float)(p2->x - p0->x);
169 	fdy2 = (float)(p2->y - p0->y);
170 
171 	fz0 = fdx1 * fdy2 - fdx2 * fdy1;
172 	if (fz0 == 0)
173 		return;
174 	fz0 = (float)(1.0 / fz0);
175 
176 	fdx1 *= fz0;
177 	fdy1 *= fz0;
178 	fdx2 *= fz0;
179 	fdy2 *= fz0;
180 
181 	if (kInterpZ) {
182 		d1 = (float)(p1->z - p0->z);
183 		d2 = (float)(p2->z - p0->z);
184 		dzdx = (int)(fdy2 * d1 - fdy1 * d2);
185 		dzdy = (int)(fdx1 * d2 - fdx2 * d1);
186 	}
187 
188 	if (kInterpRGB) {
189 		d1 = (float)(p1->r - p0->r);
190 		d2 = (float)(p2->r - p0->r);
191 		drdx = (int)(fdy2 * d1 - fdy1 * d2);
192 		drdy = (int)(fdx1 * d2 - fdx2 * d1);
193 
194 		d1 = (float)(p1->g - p0->g);
195 		d2 = (float)(p2->g - p0->g);
196 		dgdx = (int)(fdy2 * d1 - fdy1 * d2);
197 		dgdy = (int)(fdx1 * d2 - fdx2 * d1);
198 
199 		d1 = (float)(p1->b - p0->b);
200 		d2 = (float)(p2->b - p0->b);
201 		dbdx = (int)(fdy2 * d1 - fdy1 * d2);
202 		dbdy = (int)(fdx1 * d2 - fdx2 * d1);
203 
204 		d1 = (float)(p1->a - p0->a);
205 		d2 = (float)(p2->a - p0->a);
206 		dadx = (int)(fdy2 * d1 - fdy1 * d2);
207 		dady = (int)(fdx1 * d2 - fdx2 * d1);
208 	}
209 
210 	if (kInterpST || kInterpSTZ) {
211 		if (kInterpSTZ) {
212 			float zz;
213 			zz = (float)p0->z;
214 			p0->sz = (float)p0->s * zz;
215 			p0->tz = (float)p0->t * zz;
216 			zz = (float)p1->z;
217 			p1->sz = (float)p1->s * zz;
218 			p1->tz = (float)p1->t * zz;
219 			zz = (float)p2->z;
220 			p2->sz = (float)p2->s * zz;
221 			p2->tz = (float)p2->t * zz;
222 		} else {
223 			p0->sz = (float)p0->s;
224 			p0->tz = (float)p0->t;
225 			p1->sz = (float)p1->s;
226 			p1->tz = (float)p1->t;
227 			p2->sz = (float)p2->s;
228 			p2->tz = (float)p2->t;
229 		}
230 
231 		d1 = p1->sz - p0->sz;
232 		d2 = p2->sz - p0->sz;
233 		dszdx = (fdy2 * d1 - fdy1 * d2);
234 		dszdy = (fdx1 * d2 - fdx2 * d1);
235 
236 		d1 = p1->tz - p0->tz;
237 		d2 = p2->tz - p0->tz;
238 		dtzdx = (fdy2 * d1 - fdy1 * d2);
239 		dtzdy = (fdx1 * d2 - fdx2 * d1);
240 	}
241 
242 	// screen coordinates
243 
244 	int pp1 = xsize * p0->y;
245 	pz1 = _zbuf + p0->y * xsize;
246 
247 	switch (kDrawLogic) {
248 	case DRAW_SHADOW_MASK:
249 		pm1 = shadow_mask_buf + p0->y * xsize;
250 		break;
251 	case DRAW_SHADOW:
252 		pm1 = shadow_mask_buf + p0->y * xsize;
253 		r1 = shadow_color_r;
254 		g1 = shadow_color_g;
255 		b1 = shadow_color_b;
256 		break;
257 	case DRAW_DEPTH_ONLY:
258 		break;
259 	case DRAW_FLAT:
260 		r1 = p2->r;
261 		g1 = p2->g;
262 		b1 = p2->b;
263 		a1 = p2->a;
264 		break;
265 	case DRAW_SMOOTH:
266 		break;
267 	default:
268 		break;
269 	}
270 
271 	if ((kInterpST || kInterpSTZ) && (kDrawLogic == DRAW_FLAT || kDrawLogic == DRAW_SMOOTH)) {
272 		texture = current_texture;
273 		textureFormat = texture.getFormat();
274 		assert(textureFormat.bytesPerPixel == 4);
275 		fdzdx = (float)dzdx;
276 		fndzdx = NB_INTERP * fdzdx;
277 		ndszdx = NB_INTERP * dszdx;
278 		ndtzdx = NB_INTERP * dtzdx;
279 	}
280 
281 	if (fz0 > 0) {
282 		l1 = p0;
283 		l2 = p2;
284 		pr1 = p0;
285 		pr2 = p1;
286 	} else {
287 		l1 = p0;
288 		l2 = p1;
289 		pr1 = p0;
290 		pr2 = p2;
291 	}
292 	nb_lines = p1->y - p0->y;
293 	y = p0->y;
294 	for (part = 0; part < 2; part++) {
295 		if (part == 1) {
296 			// second part
297 			if (fz0 > 0) {
298 				update_left = 0;
299 				pr1 = p1;
300 				pr2 = p2;
301 			} else {
302 				update_right = 0;
303 				l1 = p1;
304 				l2 = p2;
305 			}
306 			nb_lines = p2->y - p1->y + 1;
307 		}
308 
309 		// compute the values for the left edge
310 
311 		if (update_left) {
312 			dy1 = l2->y - l1->y;
313 			dx1 = l2->x - l1->x;
314 			if (dy1 > 0)
315 				tmp = (dx1 << 16) / dy1;
316 			else
317 				tmp = 0;
318 			x1 = l1->x;
319 			error = 0;
320 			derror = tmp & 0x0000ffff;
321 			dxdy_min = tmp >> 16;
322 			dxdy_max = dxdy_min + 1;
323 
324 			if (kInterpZ) {
325 				z1 = l1->z;
326 				dzdl_min = (dzdy + dzdx * dxdy_min);
327 				dzdl_max = dzdl_min + dzdx;
328 			}
329 
330 			if (kInterpRGB) {
331 				r1 = l1->r;
332 				drdl_min = (drdy + drdx * dxdy_min);
333 				drdl_max = drdl_min + drdx;
334 
335 				g1 = l1->g;
336 				dgdl_min = (dgdy + dgdx * dxdy_min);
337 				dgdl_max = dgdl_min + dgdx;
338 
339 				b1 = l1->b;
340 				dbdl_min = (dbdy + dbdx * dxdy_min);
341 				dbdl_max = dbdl_min + dbdx;
342 
343 				a1 = l1->a;
344 				dadl_min = (dady + dadx * dxdy_min);
345 				dadl_max = dadl_min + dadx;
346 			}
347 
348 			if (kInterpST || kInterpSTZ) {
349 				sz1 = l1->sz;
350 				dszdl_min = (dszdy + dszdx * dxdy_min);
351 				dszdl_max = dszdl_min + dszdx;
352 
353 				tz1 = l1->tz;
354 				dtzdl_min = (dtzdy + dtzdx * dxdy_min);
355 				dtzdl_max = dtzdl_min + dtzdx;
356 			}
357 		}
358 
359 		// compute values for the right edge
360 
361 		if (update_right) {
362 			dx2 = (pr2->x - pr1->x);
363 			dy2 = (pr2->y - pr1->y);
364 			if (dy2 > 0)
365 				dx2dy2 = (dx2 << 16) / dy2;
366 			else
367 				dx2dy2 = 0;
368 			x2 = pr1->x << 16;
369 		}
370 
371 		// we draw all the scan line of the part
372 		while (nb_lines > 0) {
373 			int x = x1;
374 			{
375 				if (kDrawLogic == DRAW_DEPTH_ONLY ||
376 						(kDrawLogic == DRAW_FLAT && !(kInterpST || kInterpSTZ))) {
377 					int pp;
378 					int n;
379 					unsigned int *pz;
380 					unsigned int z, a;
381 					int buf = pp1 + x1;
382 					unsigned int r = r1;
383 					unsigned int g = g1;
384 					unsigned int b = b1;
385 					n = (x2 >> 16) - x1;
386 					pp = pp1 + x1;
387 					if (kInterpZ) {
388 						pz = pz1 + x1;
389 						z = z1;
390 					}
391 					if (kDrawLogic == DRAW_FLAT) {
392 						a = a1;
393 					}
394 					while (n >= 3) {
395 						if (kDrawLogic == DRAW_DEPTH_ONLY) {
396 							putPixelDepth<kDepthWrite, kEnableScissor>(this, buf, pz, 0, x, y, z, dzdx);
397 							putPixelDepth<kDepthWrite, kEnableScissor>(this, buf, pz, 1, x, y, z, dzdx);
398 							putPixelDepth<kDepthWrite, kEnableScissor>(this, buf, pz, 2, x, y, z, dzdx);
399 							putPixelDepth<kDepthWrite, kEnableScissor>(this, buf, pz, 3, x, y, z, dzdx);
400 							buf += 4;
401 						}
402 						if (kDrawLogic == DRAW_FLAT) {
403 							putPixelFlat<kDepthWrite, kAlphaTestEnabled, kEnableScissor, kBlendingEnabled>(this, pp, pz, 0, x, y, z, r, g, b, a, dzdx);
404 							putPixelFlat<kDepthWrite, kAlphaTestEnabled, kEnableScissor, kBlendingEnabled>(this, pp, pz, 1, x, y, z, r, g, b, a, dzdx);
405 							putPixelFlat<kDepthWrite, kAlphaTestEnabled, kEnableScissor, kBlendingEnabled>(this, pp, pz, 2, x, y, z, r, g, g, a, dzdx);
406 							putPixelFlat<kDepthWrite, kAlphaTestEnabled, kEnableScissor, kBlendingEnabled>(this, pp, pz, 3, x, y, z, r, g, b, a, dzdx);
407 						}
408 						if (kInterpZ) {
409 							pz += 4;
410 						}
411 						pp += 4;
412 						n -= 4;
413 						x += 4;
414 					}
415 					while (n >= 0) {
416 						if (kDrawLogic == DRAW_DEPTH_ONLY) {
417 							putPixelDepth<kDepthWrite, kEnableScissor>(this, buf, pz, 0, x, y, z, dzdx);
418 							buf ++;
419 						}
420 						if (kDrawLogic == DRAW_FLAT) {
421 							putPixelFlat<kDepthWrite, kAlphaTestEnabled, kEnableScissor, kBlendingEnabled>(this, pp, pz, 0, x, y, z, r, g, b, a, dzdx);
422 						}
423 						if (kInterpZ) {
424 							pz += 1;
425 						}
426 						pp += 1;
427 						n -= 1;
428 						x += 1;
429 					}
430 				} else if (kDrawLogic == DRAW_SHADOW_MASK) {
431 					unsigned char *pm;
432 					int n;
433 
434 					n = (x2 >> 16) - x1;
435 					pm = pm1 + x1;
436 					while (n >= 3) {
437 						pm[0] = 0xff;
438 						pm[1] = 0xff;
439 						pm[2] = 0xff;
440 						pm[3] = 0xff;
441 						pm += 4;
442 						n -= 4;
443 						x += 4;
444 					}
445 					while (n >= 0) {
446 						pm[0] = 0xff;
447 						pm += 1;
448 						n -= 1;
449 						x += 1;
450 					}
451 				} else if (kDrawLogic == DRAW_SHADOW) {
452 					unsigned char *pm;
453 					int n;
454 					unsigned int *pz;
455 					unsigned int z;
456 					unsigned int r = r1;
457 					unsigned int g = g1;
458 					unsigned int b = b1;
459 
460 					n = (x2 >> 16) - x1;
461 
462 					int buf = pp1 + x1;
463 
464 					pm = pm1 + x1;
465 					pz = pz1 + x1;
466 					z = z1;
467 					while (n >= 3) {
468 						putPixelShadow<kDepthWrite, kAlphaTestEnabled, kEnableScissor, kBlendingEnabled>(this, buf, pz, 0, x, y, z, r, g, b, dzdx, pm);
469 						putPixelShadow<kDepthWrite, kAlphaTestEnabled, kEnableScissor, kBlendingEnabled>(this, buf, pz, 1, x, y, z, r, g, b, dzdx, pm);
470 						putPixelShadow<kDepthWrite, kAlphaTestEnabled, kEnableScissor, kBlendingEnabled>(this, buf, pz, 2, x, y, z, r, g, b, dzdx, pm);
471 						putPixelShadow<kDepthWrite, kAlphaTestEnabled, kEnableScissor, kBlendingEnabled>(this, buf, pz, 3, x, y, z, r, g, b, dzdx, pm);
472 						pz += 4;
473 						pm += 4;
474 						buf += 4;
475 						n -= 4;
476 						x += 4;
477 					}
478 					while (n >= 0) {
479 						putPixelShadow<kDepthWrite, kAlphaTestEnabled, kEnableScissor, kBlendingEnabled>(this, buf, pz, 0, x, y, z, r, g, b, dzdx, pm);
480 						pz += 1;
481 						pm += 1;
482 						buf += 1;
483 						n -= 1;
484 						x += 1;
485 					}
486 				} else if (kDrawLogic == DRAW_SMOOTH && !(kInterpST || kInterpSTZ)) {
487 					unsigned int *pz;
488 					int buf = pp1 + x1;
489 					unsigned int z, r, g, b, a;
490 					int n;
491 					n = (x2 >> 16) - x1;
492 					pz = pz1 + x1;
493 					z = z1;
494 					r = r1;
495 					g = g1;
496 					b = b1;
497 					a = a1;
498 					while (n >= 3) {
499 						putPixelSmooth<kDepthWrite, kAlphaTestEnabled, kEnableScissor, kBlendingEnabled>(this, buf, pz, 0, x, y, z, r, g, b, a, dzdx, drdx, dgdx, dbdx, dadx);
500 						putPixelSmooth<kDepthWrite, kAlphaTestEnabled, kEnableScissor, kBlendingEnabled>(this, buf, pz, 1, x, y, z, r, g, b, a, dzdx, drdx, dgdx, dbdx, dadx);
501 						putPixelSmooth<kDepthWrite, kAlphaTestEnabled, kEnableScissor, kBlendingEnabled>(this, buf, pz, 2, x, y, z, r, g, b, a, dzdx, drdx, dgdx, dbdx, dadx);
502 						putPixelSmooth<kDepthWrite, kAlphaTestEnabled, kEnableScissor, kBlendingEnabled>(this, buf, pz, 3, x, y, z, r, g, b, a, dzdx, drdx, dgdx, dbdx, dadx);
503 						pz += 4;
504 						buf += 4;
505 						n -= 4;
506 						x += 4;
507 					}
508 					while (n >= 0) {
509 						putPixelSmooth<kDepthWrite, kAlphaTestEnabled, kEnableScissor, kBlendingEnabled>(this, buf, pz, 0, x, y, z, r, g, b, a, dzdx, drdx, dgdx, dbdx, dadx);
510 						buf += 1;
511 						pz += 1;
512 						n -= 1;
513 						x += 1;
514 					}
515 				} else if (kInterpST || kInterpSTZ) {
516 					unsigned int *pz;
517 					unsigned int s, t, z, r, g, b, a;
518 					int n;
519 					float sz, tz, fz, zinv;
520 					int dsdx, dtdx;
521 
522 					n = (x2 >> 16) - x1;
523 					fz = (float)z1;
524 					zinv = (float)(1.0 / fz);
525 
526 					int buf = pp1 + x1;
527 
528 					pz = pz1 + x1;
529 					z = z1;
530 					sz = sz1;
531 					tz = tz1;
532 					r = r1;
533 					g = g1;
534 					b = b1;
535 					a = a1;
536 					while (n >= (NB_INTERP - 1)) {
537 						{
538 							float ss, tt;
539 							ss = sz * zinv;
540 							tt = tz * zinv;
541 							s = (int)ss;
542 							t = (int)tt;
543 							dsdx = (int)((dszdx - ss * fdzdx) * zinv);
544 							dtdx = (int)((dtzdx - tt * fdzdx) * zinv);
545 							fz += fndzdx;
546 							zinv = (float)(1.0 / fz);
547 						}
548 						for (int _a = 0; _a < NB_INTERP; _a++) {
549 							putPixelTextureMappingPerspective<kDepthWrite, kInterpRGB, kDrawLogic == DRAW_SMOOTH, kAlphaTestEnabled, kEnableScissor, kBlendingEnabled>(this, buf, textureFormat, texture,
550 							                           pz, _a, x, y, z, t, s, r, g, b, a, dzdx, dsdx, dtdx, drdx, dgdx, dbdx, dadx);
551 						}
552 						pz += NB_INTERP;
553 						buf += NB_INTERP;
554 						n -= NB_INTERP;
555 						x += NB_INTERP;
556 						sz += ndszdx;
557 						tz += ndtzdx;
558 					}
559 
560 					{
561 						float ss, tt;
562 						ss = sz * zinv;
563 						tt = tz * zinv;
564 						s = (int)ss;
565 						t = (int)tt;
566 						dsdx = (int)((dszdx - ss * fdzdx) * zinv);
567 						dtdx = (int)((dtzdx - tt * fdzdx) * zinv);
568 					}
569 
570 					while (n >= 0) {
571 						putPixelTextureMappingPerspective<kDepthWrite, kInterpRGB, kDrawLogic == DRAW_SMOOTH, kAlphaTestEnabled, kEnableScissor, kBlendingEnabled>(this, buf, textureFormat, texture,
572 						                           pz, 0, x, y, z, t, s, r, g, b, a, dzdx, dsdx, dtdx, drdx, dgdx, dbdx, dadx);
573 						pz += 1;
574 						buf += 1;
575 						n -= 1;
576 						x += 1;
577 					}
578 				}
579 			}
580 
581 			// left edge
582 			error += derror;
583 			if (error > 0) {
584 				error -= 0x10000;
585 				x1 += dxdy_max;
586 				if (kInterpZ) {
587 					z1 += dzdl_max;
588 				}
589 
590 				if (kInterpRGB) {
591 					r1 += drdl_max;
592 					g1 += dgdl_max;
593 					b1 += dbdl_max;
594 					a1 += dadl_max;
595 				}
596 
597 				if (kInterpST || kInterpSTZ) {
598 					sz1 += dszdl_max;
599 					tz1 += dtzdl_max;
600 				}
601 			} else {
602 				x1 += dxdy_min;
603 				if (kInterpZ) {
604 					z1 += dzdl_min;
605 				}
606 				if (kInterpRGB) {
607 					r1 += drdl_min;
608 					g1 += dgdl_min;
609 					b1 += dbdl_min;
610 					a1 += dadl_min;
611 				}
612 				if (kInterpST || kInterpSTZ) {
613 					sz1 += dszdl_min;
614 					tz1 += dtzdl_min;
615 				}
616 			}
617 
618 			// right edge
619 			x2 += dx2dy2;
620 
621 			// screen coordinates
622 			pp1 += xsize;
623 			pz1 += xsize;
624 
625 			if (kDrawLogic == DRAW_SHADOW || kDrawLogic == DRAW_SHADOW_MASK)
626 				pm1 = pm1 + xsize;
627 			nb_lines--;
628 			y++;
629 		}
630 	}
631 }
632 
633 template <bool kInterpRGB, bool kInterpZ, bool kInterpST, bool kInterpSTZ, int kDrawMode, bool kDepthWrite, bool kEnableAlphaTest, bool kEnableScissor>
fillTriangle(ZBufferPoint * p0,ZBufferPoint * p1,ZBufferPoint * p2)634 void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
635 	if (_blendingEnabled) {
636 		fillTriangle<kInterpRGB, kInterpZ, kInterpST, kInterpSTZ, kDrawMode, kDepthWrite, kEnableAlphaTest, kEnableScissor, true>(p0, p1, p2);
637 	} else {
638 		fillTriangle<kInterpRGB, kInterpZ, kInterpST, kInterpSTZ, kDrawMode, kDepthWrite, kEnableAlphaTest, kEnableScissor, false>(p0, p1, p2);
639 	}
640 }
641 
642 template <bool kInterpRGB, bool kInterpZ, bool kInterpST, bool kInterpSTZ, int kDrawMode, bool kDepthWrite, bool kEnableAlphaTest>
fillTriangle(ZBufferPoint * p0,ZBufferPoint * p1,ZBufferPoint * p2)643 void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
644 	if (_enableScissor) {
645 		fillTriangle<kInterpRGB, kInterpZ, kInterpST, kInterpSTZ, kDrawMode, kDepthWrite, kEnableAlphaTest, true>(p0, p1, p2);
646 	} else {
647 		fillTriangle<kInterpRGB, kInterpZ, kInterpST, kInterpSTZ, kDrawMode, kDepthWrite, kEnableAlphaTest, false>(p0, p1, p2);
648 	}
649 }
650 
651 template <bool kInterpRGB, bool kInterpZ, bool kInterpST, bool kInterpSTZ, int kDrawMode, bool kDepthWrite>
fillTriangle(ZBufferPoint * p0,ZBufferPoint * p1,ZBufferPoint * p2)652 void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
653 	if (_alphaTestEnabled) {
654 		fillTriangle<kInterpRGB, kInterpZ, kInterpST, kInterpSTZ, kDrawMode, kDepthWrite, true>(p0, p1, p2);
655 	}  else {
656 		fillTriangle<kInterpRGB, kInterpZ, kInterpST, kInterpSTZ, kDrawMode, kDepthWrite, false>(p0, p1, p2);
657 	}
658 }
659 
660 template <bool kInterpRGB, bool kInterpZ, bool kInterpST, bool kInterpSTZ, int kDrawMode>
fillTriangle(ZBufferPoint * p0,ZBufferPoint * p1,ZBufferPoint * p2)661 void FrameBuffer::fillTriangle(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
662 	if (_depthWrite) {
663 		fillTriangle<kInterpRGB, kInterpZ, kInterpST, kInterpSTZ, kDrawMode, true>(p0, p1, p2);
664 	} else {
665 		fillTriangle<kInterpRGB, kInterpZ, kInterpST, kInterpSTZ, kDrawMode, false>(p0, p1, p2);
666 	}
667 }
668 
fillTriangleDepthOnly(ZBufferPoint * p0,ZBufferPoint * p1,ZBufferPoint * p2)669 void FrameBuffer::fillTriangleDepthOnly(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
670 	const bool interpZ = true;
671 	const bool interpRGB = false;
672 	const bool interpST = false;
673 	const bool interpSTZ = false;
674 	if (_depthWrite && _depthTestEnabled)
675 		fillTriangle<interpRGB, interpZ, interpST, interpSTZ, DRAW_DEPTH_ONLY, true>(p0, p1, p2);
676 	else
677 		fillTriangle<interpRGB, interpZ, interpST, interpSTZ, DRAW_DEPTH_ONLY, false>(p0, p1, p2);
678 }
679 
fillTriangleFlat(ZBufferPoint * p0,ZBufferPoint * p1,ZBufferPoint * p2)680 void FrameBuffer::fillTriangleFlat(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
681 	const bool interpZ = true;
682 	const bool interpRGB = false;
683 	const bool interpST = false;
684 	const bool interpSTZ = false;
685 	if (_depthWrite && _depthTestEnabled)
686 		fillTriangle<interpRGB, interpZ, interpST, interpSTZ, DRAW_FLAT, true>(p0, p1, p2);
687 	else
688 		fillTriangle<interpRGB, interpZ, interpST, interpSTZ, DRAW_FLAT, false>(p0, p1, p2);
689 }
690 
691 // Smooth filled triangle.
fillTriangleSmooth(ZBufferPoint * p0,ZBufferPoint * p1,ZBufferPoint * p2)692 void FrameBuffer::fillTriangleSmooth(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
693 	const bool interpZ = true;
694 	const bool interpRGB = true;
695 	const bool interpST = false;
696 	const bool interpSTZ = false;
697 	if (_depthWrite && _depthTestEnabled)
698 		fillTriangle<interpRGB, interpZ, interpST, interpSTZ, DRAW_SMOOTH, true>(p0, p1, p2);
699 	else
700 		fillTriangle<interpRGB, interpZ, interpST, interpSTZ, DRAW_SMOOTH, false>(p0, p1, p2);
701 }
702 
fillTriangleTextureMappingPerspectiveSmooth(ZBufferPoint * p0,ZBufferPoint * p1,ZBufferPoint * p2)703 void FrameBuffer::fillTriangleTextureMappingPerspectiveSmooth(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
704 	const bool interpZ = true;
705 	const bool interpRGB = true;
706 	const bool interpST = false;
707 	const bool interpSTZ = true;
708 	if (_depthWrite && _depthTestEnabled)
709 		fillTriangle<interpRGB, interpZ, interpST, interpSTZ, DRAW_SMOOTH, true>(p0, p1, p2);
710 	else
711 		fillTriangle<interpRGB, interpZ, interpST, interpSTZ, DRAW_SMOOTH, false>(p0, p1, p2);
712 }
713 
fillTriangleTextureMappingPerspectiveFlat(ZBufferPoint * p0,ZBufferPoint * p1,ZBufferPoint * p2)714 void FrameBuffer::fillTriangleTextureMappingPerspectiveFlat(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
715 	const bool interpZ = true;
716 	const bool interpRGB = true;
717 	const bool interpST = false;
718 	const bool interpSTZ = true;
719 	if (_depthWrite && _depthTestEnabled)
720 		fillTriangle<interpRGB, interpZ, interpST, interpSTZ, DRAW_FLAT, true>(p0, p1, p2);
721 	else
722 		fillTriangle<interpRGB, interpZ, interpST, interpSTZ, DRAW_FLAT, false>(p0, p1, p2);
723 }
724 
fillTriangleFlatShadowMask(ZBufferPoint * p0,ZBufferPoint * p1,ZBufferPoint * p2)725 void FrameBuffer::fillTriangleFlatShadowMask(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
726 	const bool interpZ = true;
727 	const bool interpRGB = false;
728 	const bool interpST = false;
729 	const bool interpSTZ = false;
730 	if (_depthWrite && _depthTestEnabled)
731 		fillTriangle<interpRGB, interpZ, interpST, interpSTZ, DRAW_SHADOW_MASK, true>(p0, p1, p2);
732 	else
733 		fillTriangle<interpRGB, interpZ, interpST, interpSTZ, DRAW_SHADOW_MASK, false>(p0, p1, p2);
734 }
735 
fillTriangleFlatShadow(ZBufferPoint * p0,ZBufferPoint * p1,ZBufferPoint * p2)736 void FrameBuffer::fillTriangleFlatShadow(ZBufferPoint *p0, ZBufferPoint *p1, ZBufferPoint *p2) {
737 	const bool interpZ = true;
738 	const bool interpRGB = false;
739 	const bool interpST = false;
740 	const bool interpSTZ = false;
741 	if (_depthWrite && _depthTestEnabled)
742 		fillTriangle<interpRGB, interpZ, interpST, interpSTZ, DRAW_SHADOW, true>(p0, p1, p2);
743 	else
744 		fillTriangle<interpRGB, interpZ, interpST, interpSTZ, DRAW_SHADOW, false>(p0, p1, p2);
745 }
746 
747 } // end of namespace TinyGL
748