1 /*
2 *			GPAC - Multimedia Framework C SDK
3 *
4 *			Authors: Jean Le Feuvre
5 *			Copyright (c) Telecom ParisTech 2019
6 *					All rights reserved
7 *
8 *  This file is part of GPAC / software 3D rasterizer module
9 *
10 *  GPAC is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU Lesser General Public License as published by
12 *  the Free Software Foundation; either version 2, or (at your option)
13 *  any later version.
14 *
15 *  GPAC is distributed in the hope that it will be useful,
16 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 *  GNU Lesser General Public License for more details.
19 *
20 *  You should have received a copy of the GNU Lesser General Public
21 *  License along with this library; see the file COPYING.  If not, write to
22 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 *
25 */
26 
27 #include "rast_soft.h"
28 
29 
30 
31 #if defined(WIN32) && !defined(__GNUC__)
32 # include <intrin.h>
33 # define GPAC_HAS_SSE2
34 #else
35 # ifdef __SSE2__
36 #  include <emmintrin.h>
37 #  define GPAC_HAS_SSE2
38 # endif
39 #endif
40 
41 #ifdef GPAC_HAS_SSE2
42 
float_clamp(Float val,Float minval,Float maxval)43 static Float float_clamp(Float val, Float minval, Float maxval)
44 {
45     _mm_store_ss( &val, _mm_min_ss( _mm_max_ss(_mm_set_ss(val),_mm_set_ss(minval)), _mm_set_ss(maxval) ) );
46     return val;
47 }
48 #else
49 
50 #define float_clamp(_val, _minval, _maxval)\
51 	(_val<_minval) ? _minval : (_val>_maxval) ? _maxval : _val;
52 
53 #endif
54 
55 
56 
evg3d_persp_divide(GF_Vec4 * pt)57 static GFINLINE Bool evg3d_persp_divide(GF_Vec4 *pt)
58 {
59 	//perspective divide
60 	if (!pt->q) return GF_FALSE;
61 	pt->q = gf_divfix(FIX_ONE, pt->q);
62 	pt->x = gf_mulfix(pt->x, pt->q);
63 	pt->y = gf_mulfix(pt->y, pt->q);
64 	pt->z = gf_mulfix(pt->z, pt->q);
65 	return GF_TRUE;
66 }
67 
evg_ndc_to_raster(GF_EVGSurface * surf,GF_Vec4 * pt,TPos * x,TPos * y)68 static GFINLINE void evg_ndc_to_raster(GF_EVGSurface *surf, GF_Vec4 *pt, TPos *x, TPos *y)
69 {
70 	//from [-1, 1] to [0,2] to [0,1] to [0,vp_width] to [vp left, vp right]
71 	pt->x = (pt->x + FIX_ONE) / 2 * surf->width;
72 	//idem but flip Y
73 	pt->y = (FIX_ONE - (pt->y + FIX_ONE)/2) * surf->height;
74 
75 	//move Z from [-1, 1] to [min_depth, max_depth]
76 	pt->z += FIX_ONE;
77 	pt->z /= 2;
78 
79 #ifdef GPAC_FIXED_POINT
80 	*x = UPSCALE(pt->x);
81 	*y = UPSCALE(pt->y);
82 #else
83 	*x = (s32) (pt->x * ONE_PIXEL);
84 	*y = (s32) (pt->y * ONE_PIXEL);
85 #endif
86 }
evg3d_ndc_to_raster(GF_EVGSurface * surf,GF_Vec4 * pt,TPos * x,TPos * y)87 static GFINLINE void evg3d_ndc_to_raster(GF_EVGSurface *surf, GF_Vec4 *pt, TPos *x, TPos *y)
88 {
89 	//from [-1, 1] to [0,2] to [0,1] to [0,vp_width] to [vp left, vp right]
90 	pt->x = (pt->x + FIX_ONE) / 2 * surf->ext3d->vp_w + surf->ext3d->vp_x;
91 	//idem but flip Y
92 	pt->y = (FIX_ONE - (pt->y + FIX_ONE)/2) * surf->ext3d->vp_h + surf->ext3d->vp_y;
93 	/*compute depth*/
94 	if (!surf->ext3d->clip_zero) {
95 		//move Z from [-1, 1] to [min_depth, max_depth]
96 		pt->z += FIX_ONE;
97 		pt->z /= 2;
98 	}
99 	pt->z = surf->ext3d->min_depth + pt->z * surf->ext3d->depth_range;
100 
101 #ifdef GPAC_FIXED_POINT
102 	*x = UPSCALE(pt->x);
103 	*y = UPSCALE(pt->y);
104 #else
105 	*x = (s32) (pt->x * ONE_PIXEL);
106 	*y = (s32) (pt->y * ONE_PIXEL);
107 #endif
108 }
109 
gray3d_move_to(EVG_Raster raster,TPos x,TPos y)110 static GFINLINE int gray3d_move_to(EVG_Raster raster, TPos x, TPos y)
111 {
112 	TCoord  ex, ey;
113 
114 	/* record current cell, if any */
115 	gray_record_cell(raster);
116 
117 	ex = TRUNC(x);
118 	ey = TRUNC(y);
119 	if ( ex < raster->min_ex ) ex = (TCoord)(raster->min_ex - 1);
120 	raster->area    = 0;
121 	raster->cover   = 0;
122 	gray_set_cell( raster, ex, ey );
123 	if (ey<0) ey=0;
124 	raster->last_ey = SUBPIXELS( ey );
125 
126 	raster->x = x;
127 	raster->y = y;
128 	return 0;
129 }
130 
evg_raster_render_path_3d(GF_EVGSurface * surf)131 GF_Err evg_raster_render_path_3d(GF_EVGSurface *surf)
132 {
133 	EVG_Vector   v_start;
134 	int   n;         /* index of contour in outline     */
135 	int   first;     /* index of first point in contour */
136 	TPos _x, _y, _sx, _sy;
137 	GF_Vec dir;
138 	u32 li, size_y;
139 	EVG_Raster raster = surf->raster;
140 	EVG_Outline *outline = &surf->ftoutline;
141 
142 	raster->render_span  = (EVG_Raster_Span_Func) surf->gray_spans;
143 	raster->render_span_data = surf;
144 
145 	/* Set up state in the raster object */
146 	raster->min_ex = surf->clip_xMin;
147 	raster->min_ey = surf->clip_yMin;
148 	raster->max_ex = surf->clip_xMax;
149 	raster->max_ey = surf->clip_yMax;
150 
151 
152 	size_y = (u32) (raster->max_ey - raster->min_ey);
153 	if ((u32) raster->max_lines < size_y) {
154 		raster->scanlines = (AAScanline*)gf_realloc(raster->scanlines, sizeof(AAScanline)*size_y);
155 		memset(&raster->scanlines[raster->max_lines], 0, sizeof(AAScanline)*(size_y-raster->max_lines) );
156 		raster->max_lines = size_y;
157 	}
158 
159 	raster->ex = (int) (raster->max_ex+1);
160 	raster->ey = (int) (raster->max_ey+1);
161 	raster->cover = 0;
162 	raster->area = 0;
163 	raster->first_scanline = raster->max_ey;
164 
165 	dir.x = dir.y = 0;
166 	dir.z = -FIX_ONE;
167 
168 	first = 0;
169 	for ( n = 0; n < outline->n_contours; n++ ) {
170 		GF_Vec4 pt;
171 		EVG_Vector *point;
172 		EVG_Vector *limit;
173 		int  last;  /* index of last point in contour */
174 		last  = outline->contours[n];
175 		limit = outline->points + last;
176 		v_start = outline->points[first];
177 		point = outline->points + first;
178 
179 		pt.x = v_start.x;
180 		pt.y = v_start.y;
181 		pt.z = 0;
182 		pt.q = 1;
183 		gf_mx_apply_vec_4x4(&surf->mx3d, &pt);
184 		if (!evg3d_persp_divide(&pt)) {
185 			continue;
186 		}
187 		evg_ndc_to_raster(surf, &pt, &_sx, &_sy);
188 		gray3d_move_to(raster, _sx, _sy);
189 		while ( point < limit ) {
190 			point++;
191 
192 			pt.x = point->x;
193 			pt.y = point->y;
194 			pt.z = 0;
195 			pt.q = 1;
196 			gf_mx_apply_vec_4x4(&surf->mx3d, &pt);
197 			if (!evg3d_persp_divide(&pt)) {
198 				break;
199 			}
200 			evg_ndc_to_raster(surf, &pt, &_x, &_y);
201 			gray_render_line(raster, _x, _y);
202 		}
203 		gray_render_line(raster, _sx, _sy);
204 
205 		first = last + 1;
206 	}
207 
208 	gray_record_cell( raster );
209 	/* sort each scanline and render it*/
210 	for (li=raster->first_scanline; li<size_y; li++) {
211 		AAScanline *sl = &raster->scanlines[li];
212 		if (sl->num) {
213 			if (sl->num>1) gray_quick_sort(sl->cells, sl->num);
214 			gray_sweep_line(raster, sl, li, GF_TRUE);
215 		}
216 	}
217 	return GF_OK;
218 }
219 
220 
evg3d_get_fragment(GF_EVGSurface * surf,GF_EVGFragmentParam * frag_param,Bool * is_transparent)221 Bool evg3d_get_fragment(GF_EVGSurface *surf, GF_EVGFragmentParam *frag_param, Bool *is_transparent)
222 {
223 	surf->fill_col = 0;
224 	surf->fill_col_wide = 0;
225 
226 	if (!surf->ext3d->frag_shader(surf->ext3d->frag_shader_udta, frag_param))
227 		return GF_FALSE;
228 
229 #if 0
230 	frag_param->color.x = float_clamp(frag_param->color.x, 0.0, 1.0);
231 	frag_param->color.y = float_clamp(frag_param->color.y, 0.0, 1.0);
232 	frag_param->color.z = float_clamp(frag_param->color.z, 0.0, 1.0);
233 	frag_param->color.q = float_clamp(frag_param->color.q, 0.0, 1.0);
234 #endif
235 
236 	if (frag_param->color.q<1.0) *is_transparent = GF_TRUE;
237 
238 	if (surf->not_8bits) {
239 		surf->fill_col_wide = evg_make_col_wide((u16) frag_param->color.q*0xFFFF, (u16) frag_param->color.x*0xFFFF, (u16) frag_param->color.y*0xFFFF, (u16) frag_param->color.z*0xFFFF);
240 	} else {
241 		u8 a = (u8) (frag_param->color.q*255);
242 		u8 r = (u8) (frag_param->color.x*255);
243 		u8 g = (u8) (frag_param->color.y*255);
244 		u8 b = (u8) (frag_param->color.z*255);
245 		surf->fill_col = GF_COL_ARGB(a, r, g, b);
246 	}
247 
248 	if (surf->not_8bits) {
249 		if (surf->yuv_type) {
250 			if (frag_param->frag_valid==GF_EVG_FRAG_RGB) {
251 				surf->fill_col_wide = gf_evg_argb_to_ayuv_wide(surf, surf->fill_col_wide);
252 			}
253 		} else {
254 			if (frag_param->frag_valid==GF_EVG_FRAG_YUV) {
255 				surf->fill_col_wide = gf_evg_ayuv_to_argb_wide(surf, surf->fill_col_wide);
256 			}
257 		}
258 	} else {
259 		if (surf->yuv_type) {
260 			/*RGB frag*/
261 			if (frag_param->frag_valid==GF_EVG_FRAG_RGB) {
262 				surf->fill_col = gf_evg_argb_to_ayuv(surf, surf->fill_col);
263 			}
264 		} else {
265 			if (frag_param->frag_valid==GF_EVG_FRAG_YUV) {
266 				surf->fill_col = gf_evg_ayuv_to_argb(surf, surf->fill_col);
267 			}
268 		}
269 	}
270 	return GF_TRUE;
271 }
272 
edgeFunction(const GF_Vec4 * a,const GF_Vec4 * b,const GF_Vec4 * c)273 static float edgeFunction(const GF_Vec4 *a, const GF_Vec4 *b, const GF_Vec4 *c)
274 {
275 	return (c->x - a->x) * (b->y - a->y) - (c->y - a->y) * (b->x - a->x);
276 }
277 
edgeFunction_pre(const GF_Vec4 * a,const Float b_minus_a_x,const Float b_minus_a_y,const GF_Vec4 * c)278 static float edgeFunction_pre(const GF_Vec4 *a, const Float b_minus_a_x, const Float b_minus_a_y, const GF_Vec4 *c)
279 {
280 	return (c->x - a->x) * (b_minus_a_y) - (c->y - a->y) * (b_minus_a_x);
281 }
282 
283 typedef struct
284 {
285 	GF_EVGSurface *surf;
286 	GF_EVGFragmentParam frag_param;
287 } EVGFragCallback;
288 
push_patch_pixel(AAScanline * sl,s32 x,u32 col,u8 coverage,Float depth,Float write_depth,u32 idx1,u32 idx2)289 static void push_patch_pixel(AAScanline *sl, s32 x, u32 col, u8 coverage, Float depth, Float write_depth, u32 idx1, u32 idx2)
290 {
291 	u32 i;
292 	PatchPixel *pp;
293 	for (i=0; i<sl->pnum; i++) {
294 		if (sl->pixels[i].x>x) break;
295 		if (sl->pixels[i].x<x) continue;
296 		sl->pixels[i].color = col;
297 		sl->pixels[i].cover = coverage;
298 		sl->pixels[i].depth = depth;
299 		sl->pixels[i].write_depth = write_depth;
300 		sl->pixels[i].idx1 = idx1;
301 		sl->pixels[i].idx2 = idx2;
302 		return;
303 	}
304 	if (coverage==0xFF) return;
305 
306 	if (sl->pnum == sl->palloc) {
307 		sl->palloc += AA_CELL_STEP_ALLOC;
308 		sl->pixels = gf_realloc(sl->pixels, sizeof(PatchPixel) * sl->palloc);
309 	}
310 	if (i==sl->pnum) {
311 		pp = &sl->pixels[sl->pnum];
312 	} else {
313 		memmove(&sl->pixels[i+1], &sl->pixels[i], sizeof(PatchPixel)*(sl->pnum - i));
314 		pp = &sl->pixels[i];
315 	}
316 	sl->pnum++;
317 	pp->color = col;
318 	pp->cover = coverage;
319 	pp->x = x;
320 	pp->depth = depth;
321 	pp->write_depth = write_depth;
322 	pp->idx1 = idx1;
323 	pp->idx2 = idx2;
324 }
325 
get_patch_pixel(AAScanline * sl,s32 x)326 static PatchPixel *get_patch_pixel(AAScanline *sl, s32 x)
327 {
328 	u32 i;
329 	for (i=0; i<sl->pnum; i++) {
330 		if (sl->pixels[i].x>x) break;
331 		if (sl->pixels[i].x<x) continue;
332 		return &sl->pixels[i];
333 	}
334 	return NULL;
335 }
336 
337 
remove_patch_pixel(AAScanline * sl,s32 x)338 static void remove_patch_pixel(AAScanline *sl, s32 x)
339 {
340 	u32 i;
341 	for (i=0; i<sl->pnum; i++) {
342 		if (sl->pixels[i].x>x) break;
343 		if (sl->pixels[i].x<x) continue;
344 		if (i+1<sl->pnum)
345 			memmove(&sl->pixels[i], &sl->pixels[i+1], sizeof(PatchPixel)*(sl->pnum-i-1));
346 		sl->pnum--;
347 		return;
348 	}
349 }
350 
EVG3D_SpanFunc(int y,int count,EVG_Span * spans,void * user)351 void EVG3D_SpanFunc(int y, int count, EVG_Span *spans, void *user)
352 {
353 	int i;
354 	GF_Vec4 pix;
355 	EVGFragCallback *fcbck = user;
356 	GF_EVGSurface *surf = fcbck->surf;
357 	EVG_Surface3DExt *s3d = surf->ext3d;
358 	GF_EVGFragmentParam *frag_param = &fcbck->frag_param;
359 	AAScanline *sl = &surf->raster->scanlines[y];
360 	Float *depth_line = s3d->depth_buffer ? &s3d->depth_buffer[y*surf->width] : NULL;
361 	Float depth_buf_val;
362 
363 	pix.z=0;
364 	pix.q=1;
365 
366 	for (i=0; i<count; i++) {
367 		u8 coverage = spans[i].coverage;
368 		u32 j, len = spans[i].len;
369 		s32 sx = spans[i].x;
370 		for (j=0; j<len; j++) {
371 
372 
373 	Bool transparent=GF_FALSE;
374 	Float depth, bc1, bc2, bc3;
375 	Bool full_cover=GF_TRUE;
376 	Bool edge_merge=GF_FALSE;
377 	s32 x = sx + j;
378 	PatchPixel *prev_partial = NULL;
379 
380 	/*no AA, force full opacity and test pixel/line below*/
381 	if (s3d->disable_aa)
382 		coverage = 0xFF;
383 	else if (!s3d->mode2d)
384 		prev_partial = get_patch_pixel(sl, x);
385 
386 	pix.x = (Float)x + 0.5f;
387 	pix.y = (Float)y + 0.5f;
388 
389 	if (s3d->prim_type==GF_EVG_POINTS) {
390 		if (s3d->smooth_points) {
391 			Float dx, dy;
392 			dx = (Float)x - s3d->s_v1.x;
393 			dy = (Float)y - s3d->s_v1.y;
394 			dx *=dx;
395 			dy *=dy;
396 			if (dx+dy > s3d->pt_radius) {
397 				spans[i].coverage=0;
398 				continue;
399 			}
400 		}
401 		depth = s3d->s_v1.z;
402 
403 		bc1 = bc2 = bc3 = 0;
404 		if (coverage!=0xFF) {
405 			full_cover = GF_FALSE;
406 		}
407 	} else if (s3d->prim_type==GF_EVG_LINES) {
408 		GF_Vec pt;
409 
410 		gf_vec_diff(pt, pix, s3d->s_v1);
411 		bc1 = gf_vec_len(pt);
412 		bc1 /= s3d->v1v2_length;
413 		bc1 = float_clamp(bc1, 0, 1);
414 		bc2 = FIX_ONE - bc1;
415 		depth = s3d->s_v1.z * bc1 + s3d->s_v2.z * bc2;
416 
417 		bc3 = 0;
418 		if (coverage!=0xFF) {
419 			full_cover = GF_FALSE;
420 		}
421 	} else {
422 		bc1 = edgeFunction_pre(&s3d->s_v2, s3d->s3_m_s2_x, s3d->s3_m_s2_y, &pix);
423 		bc1 /= s3d->area;
424 		bc2 = edgeFunction_pre(&s3d->s_v3, s3d->s1_m_s3_x, s3d->s1_m_s3_y, &pix);
425 		bc2 /= s3d->area;
426 		bc3 = edgeFunction_pre(&s3d->s_v1, s3d->s2_m_s1_x, s3d->s2_m_s1_y, &pix);
427 		bc3 /= s3d->area;
428 		//bc3 = 1.0 - bc1 - bc2;
429 
430 		/* in antialiased mode, we don't need to test for bc1>=0 && bc2>=0 && bc3>=0 (ie, is the pixel in the triangle),
431 		because we already know the point is in the triangle since we are called back
432 		in non-AA mode, coverage is forced to full pixel, and we check if we are or not in the triangle*/
433 		if (s3d->disable_aa)
434 		{
435 			if ((bc1<0) || (bc2<0) || (bc3<0)) {
436 				spans[i].coverage=0;
437 				continue;
438 			}
439 		}
440 		/*if coverage is not full, we are on a line - recompute the weights assuming the pixel is exactly on the line*/
441 		else if (coverage!=0xFF) {
442 
443 		//results are not precise enough to give better results, we always clamp for now
444 #if 0
445 			if (!s3d->backface_cull) {
446 
447 #if 0
448 				//method 1, find a subpixel in a 5x5 grid belonging to the triangle
449 				GF_Vec4 subp;
450 				u32 k, l;
451 				subp.q = 1;
452 				subp.z = 0;
453 				Bool subp_found=GF_FALSE;
454 				for (k=0; k<=4; k++) {
455 					for (l=0; l<=4; l++) {
456 						subp.x = (Float) x + 0.25*k;
457 						subp.y = (Float) x + 0.25*l;
458 						bc1 = edgeFunction_pre(&s3d->s_v2, s3d->s3_m_s2_x, s3d->s3_m_s2_y, &subp);
459 						bc1 /= s3d->area;
460 						bc2 = edgeFunction_pre(&s3d->s_v3, s3d->s1_m_s3_x, s3d->s1_m_s3_y, &subp);
461 						bc2 /= s3d->area;
462 						bc3 = 1.0 - bc1 - bc2;
463 						if ((bc1<0) || (bc2<0) || (bc3<0)) continue;
464 						subp_found = GF_TRUE;
465 						break;
466 					}
467 				}
468 //				assert(subp_found);
469 
470 #else
471 				//method 2, reproject point on triangle edges
472 				GF_Vec pt;
473 				u32 on_line = 0;
474 
475 				if ((bc1<0) || (bc2<0) || (bc3<0)) {
476 					if ((bc1<0) && (bc2<0)) { bc3 = 1.0; bc1 = bc2 = 0; }
477 					else if ((bc1<0) && (bc3<0)) { bc2 = 1.0; bc1 = bc3 = 0; }
478 					else if ((bc2<0) && (bc3<0)) { bc1 = 1.0; bc2 = bc3 = 0; }
479 					else if ((bc1<=bc2) && (bc1<=bc3)) on_line = 3;
480 					else if ((bc2<=bc1) && (bc2<=bc3)) on_line = 2;
481 					else if ((bc3<=bc1) && (bc3<=bc2)) on_line = 1;
482 				}
483 				//project pixel center on line v2v3
484 				if (on_line==3) {
485 					bc1 = 0;
486 					gf_vec_diff(pt, pix, s3d->s_v2);
487 					pt.z=0;
488 					bc2 = gf_vec_dot(pt, s3d->v2v3);
489 					bc2 /= s3d->v2v3_length;
490 					bc3 = float_clamp(bc2, 0, 1);
491 					bc2 = FIX_ONE - bc3;
492 				}
493 				//project pixel center on line v1v3
494 				else if (on_line==2) {
495 					bc2 = 0;
496 					gf_vec_diff(pt, pix, s3d->s_v1);
497 					pt.z=0;
498 					bc1 = gf_vec_dot(pt, s3d->v1v3);
499 					bc1 /= s3d->v1v3_length;
500 					bc3 = float_clamp(bc1, 0, 1);
501 					bc1 = FIX_ONE - bc3;
502 				}
503 				//project pixel center on line v1v2
504 				else if (on_line==1) {
505 					bc3 = 0;
506 					gf_vec_diff(pt, pix, s3d->s_v1);
507 					pt.z=0;
508 					bc1 = gf_vec_dot(pt, s3d->v1v2);
509 					bc1 /= s3d->v1v2_length;
510 					bc2 = float_clamp(bc1, 0, 1);
511 					bc1 = FIX_ONE - bc2;
512 				}
513 #endif
514 
515 			} else
516 #endif
517 			if (!s3d->mode2d) {
518 				bc1 = float_clamp(bc1, 0, 1);
519 				bc2 = float_clamp(bc2, 0, 1);
520 				bc3 = float_clamp(bc3, 0, 1);
521 			}
522 
523 			full_cover = GF_FALSE;
524 			transparent = GF_TRUE;
525 		}
526 		depth = s3d->s_v1.z * bc1 + s3d->s_v2.z * bc2 + s3d->s_v3.z * bc3;
527 	}
528 
529 	//clip by depth
530 	if ((depth<s3d->min_depth) || (depth>s3d->max_depth)) {
531 		spans[i].coverage=0;
532 		continue;
533 	}
534 
535 	depth_buf_val = depth_line ? depth_line[x] : s3d->max_depth;
536 	if (prev_partial) {
537 		if ((spans[i].idx1==prev_partial->idx1)
538 			|| (spans[i].idx1==prev_partial->idx2)
539 			|| (spans[i].idx2==prev_partial->idx1)
540 			|| (spans[i].idx2==prev_partial->idx2)
541 		) {
542 			depth = prev_partial->depth;
543 			edge_merge = GF_TRUE;
544 		} else {
545 			edge_merge = GF_FALSE;
546 			if (!s3d->depth_test(prev_partial->write_depth, depth_buf_val))
547 				depth_buf_val = prev_partial->write_depth;
548 		}
549 	}
550 
551 
552 	//do depth test except for edges
553 	if (! edge_merge && s3d->early_depth_test) {
554 		if (! s3d->depth_test(depth_buf_val, depth)) {
555 			spans[i].coverage=0;
556 			continue;
557 		}
558 	}
559 
560 	frag_param->screen_x = pix.x;
561 	frag_param->screen_y = pix.y;
562 	//compute Z window coord
563 	frag_param->screen_z = s3d->zw_factor * depth + s3d->zw_offset;
564 	frag_param->depth = depth;
565 	frag_param->color.q = 1.0;
566 	frag_param->frag_valid = 0;
567 	/*perspective corrected barycentric, eg bc1/q1, bc2/q2, bc3/q3 - we already have store 1/q in the perspective divide step*/
568 	frag_param->pbc1 = bc1*s3d->s_v1.q;
569 	frag_param->pbc2 = bc2*s3d->s_v2.q;
570 	frag_param->pbc3 = bc3*s3d->s_v3.q;
571 
572 	frag_param->persp_denum = frag_param->pbc1 + frag_param->pbc2 + frag_param->pbc3;
573 
574 	if (!evg3d_get_fragment(surf, frag_param, &transparent)) {
575 		spans[i].coverage=0;
576 		continue;
577 	}
578 	if (!s3d->early_depth_test) {
579 		if (! s3d->depth_test(depth_buf_val, frag_param->depth)) {
580 			spans[i].coverage=0;
581 			continue;
582 		}
583 	}
584 	//we overwrite a partial
585 	if (prev_partial) {
586 		if (edge_merge) {
587 			u32 ncov = coverage;
588 
589 			ncov += prev_partial->cover;
590 			if (!s3d->depth_test(depth_buf_val, depth)) {
591 				remove_patch_pixel(sl, prev_partial->x);
592 				spans[i].coverage=0;
593 				continue;
594 			}
595 			if (ncov>=0xFF) {
596 				if (prev_partial->cover==0xFF) {
597 					spans[i].coverage=0;
598 					continue;
599 				}
600 				remove_patch_pixel(sl, prev_partial->x);
601 				full_cover = GF_TRUE;
602 				coverage = 0xFF;
603 			} else {
604 				prev_partial->cover = ncov;
605 				prev_partial->color = surf->fill_col;
606 				spans[i].coverage=0;
607 				continue;
608 			}
609 		}
610 		else if (s3d->depth_test(prev_partial->write_depth, depth)) {
611 			prev_partial->write_depth = depth;
612 		}
613 	}
614 
615 	//partial coverage, store
616 	if (!full_cover && !s3d->mode2d) {
617 		push_patch_pixel(sl, x, surf->fill_col, coverage, depth, depth_buf_val, spans[i].idx1, spans[i].idx2);
618 		spans[i].coverage=0;
619 		continue;
620 	}
621 	//full opacity, write
622 	else {
623 		if (surf->fill_single) {
624 			if (transparent) {
625 				surf->fill_single_a(y, x, coverage, surf->fill_col, surf);
626 			} else {
627 				surf->fill_single(y, x, surf->fill_col, surf);
628 			}
629 		} else {
630 			spans[i].coverage = 0xFF;
631 			s3d->pix_vals[x] = surf->fill_col;
632 		}
633 	}
634 
635 	//write depth
636 	if (s3d->run_write_depth)
637 		depth_line[x] = frag_param->depth;
638 
639 
640 		}	//end span.len loop
641 	} //end spans count loop
642 
643 	if (!surf->fill_single) {
644 		surf->gray_spans(y, count, spans, surf);
645 	}
646 }
647 
precompute_tri(EVG_Surface3DExt * s3d,EVGFragCallback * frag_ckck,TPos xmin,TPos xmax,TPos ymin,TPos ymax,TPos _x1,TPos _y1,TPos _x2,TPos _y2,TPos _x3,TPos _y3,GF_Vec4 * s_pt1,GF_Vec4 * s_pt2,GF_Vec4 * s_pt3,u32 vidx1,u32 vidx2,u32 vidx3)648 static GFINLINE Bool precompute_tri(EVG_Surface3DExt *s3d, EVGFragCallback *frag_ckck, TPos xmin, TPos xmax, TPos ymin, TPos ymax,
649 									TPos _x1, TPos _y1, TPos _x2, TPos _y2, TPos _x3, TPos _y3,
650 									GF_Vec4 *s_pt1, GF_Vec4 *s_pt2, GF_Vec4 *s_pt3,
651 									u32 vidx1, u32 vidx2, u32 vidx3
652 )
653 {
654 	/*completely outside viewport*/
655 	if ((_x1<xmin) && (_x2<xmin) && (_x3<xmin))
656 		return GF_FALSE;
657 	if ((_y1<ymin) && (_y2<ymin) && (_y3<ymin))
658 		return GF_FALSE;
659 	if ((_x1>=xmax) && (_x2>=xmax) && (_x3>=xmax))
660 		return GF_FALSE;
661 	if ((_y1>=ymax) && (_y2>=ymax) && (_y3>=ymax))
662 		return GF_FALSE;
663 
664 	s3d->area = edgeFunction(s_pt1, s_pt2, s_pt3);
665 
666 	s3d->s_v1 = *s_pt1;
667 	s3d->s_v2 = *s_pt2;
668 	s3d->s_v3 = *s_pt3;
669 	frag_ckck->frag_param.idx1 = vidx1;
670 	frag_ckck->frag_param.idx2 = vidx2;
671 	frag_ckck->frag_param.idx3 = vidx3;
672 
673 
674 	//precompute a few things for this run
675 	s3d->s3_m_s2_x = s3d->s_v3.x - s3d->s_v2.x;
676 	s3d->s3_m_s2_y = s3d->s_v3.y - s3d->s_v2.y;
677 	s3d->s1_m_s3_x = s3d->s_v1.x - s3d->s_v3.x;
678 	s3d->s1_m_s3_y = s3d->s_v1.y - s3d->s_v3.y;
679 	s3d->s2_m_s1_x = s3d->s_v2.x - s3d->s_v1.x;
680 	s3d->s2_m_s1_y = s3d->s_v2.y - s3d->s_v1.y;
681 
682 	GF_Vec lv;
683 	lv.z=0;
684 	gf_vec_diff(lv, *s_pt2, *s_pt1);
685 	s3d->v1v2_length = gf_vec_len(lv);
686 	gf_vec_norm(&lv);
687 	s3d->v1v2 = lv;
688 	gf_vec_diff(lv, *s_pt3, *s_pt2);
689 	s3d->v2v3_length = gf_vec_len(lv);
690 	gf_vec_norm(&lv);
691 	s3d->v2v3 = lv;
692 	gf_vec_diff(lv, *s_pt3, *s_pt1);
693 	s3d->v1v3_length = gf_vec_len(lv);
694 	gf_vec_norm(&lv);
695 	s3d->v1v3 = lv;
696 
697 	return GF_TRUE;
698 }
699 
evg_raster_render3d(GF_EVGSurface * surf,u32 * indices,u32 nb_idx,Float * vertices,u32 nb_vertices,u32 nb_comp,GF_EVGPrimitiveType prim_type)700 GF_Err evg_raster_render3d(GF_EVGSurface *surf, u32 *indices, u32 nb_idx, Float *vertices, u32 nb_vertices, u32 nb_comp, GF_EVGPrimitiveType prim_type)
701 {
702 	u32 i, li, size_y, nb_comp_1, idx_inc;
703 	GF_Matrix projModeView;
704 	EVG_Span span;
705 	u32 is_strip_fan=0;
706 	EVG_Raster raster = surf->raster;
707 	EVG_Surface3DExt *s3d = surf->ext3d;
708 	EVGFragCallback frag_ckck;
709 	u32 first_patch, last_patch;
710 	TPos xmin, xmax, ymin, ymax;
711 	Bool glob_quad_done = GF_TRUE;
712 	u32 prim_index=0;
713 	GF_EVGVertexParam vparam;
714 	int hpw=0;
715 	int hlw=0;
716 	if (!surf->ext3d->frag_shader) return GF_BAD_PARAM;
717 
718 	raster->render_span  = (EVG_Raster_Span_Func) EVG3D_SpanFunc;
719 	raster->render_span_data = &frag_ckck;
720 
721 	/* Set up state in the raster object */
722 	raster->min_ex = surf->clip_xMin;
723 	raster->min_ey = surf->clip_yMin;
724 	raster->max_ex = surf->clip_xMax;
725 	raster->max_ey = surf->clip_yMax;
726 
727 	s3d->run_write_depth = s3d->depth_buffer ? s3d->write_depth : GF_FALSE;
728 
729 	size_y = (u32) (raster->max_ey - raster->min_ey);
730 	if (raster->max_lines < size_y) {
731 		raster->scanlines = (AAScanline*)gf_realloc(raster->scanlines, sizeof(AAScanline)*size_y);
732 		memset(&raster->scanlines[raster->max_lines], 0, sizeof(AAScanline)*(size_y-raster->max_lines) );
733 		raster->max_lines = size_y;
734 	}
735 	for (li=0; li<size_y; li++) {
736 		raster->scanlines[li].pnum = 0;
737 	}
738 	first_patch = 0xFFFFFFFF;
739 	last_patch = 0;
740 
741 	gf_mx_copy(projModeView, s3d->proj);
742 	gf_mx_add_matrix_4x4(&projModeView, &s3d->modelview);
743 
744 	switch (prim_type) {
745 	case GF_EVG_LINE_STRIP:
746 		is_strip_fan = 1;
747 	case GF_EVG_LINES:
748 		idx_inc = 2;
749 		hlw = (int) (s3d->line_size*ONE_PIXEL/2);
750 		prim_type = GF_EVG_LINES;
751 		break;
752 	case GF_EVG_TRIANGLES:
753 		idx_inc = 3;
754 		break;
755 	case GF_EVG_TRIANGLE_STRIP:
756 		is_strip_fan = 1;
757 		idx_inc = 3;
758 		prim_type = GF_EVG_TRIANGLES;
759 		break;
760 	case GF_EVG_POLYGON:
761 	case GF_EVG_TRIANGLE_FAN:
762 		is_strip_fan = 2;
763 		idx_inc = 3;
764 		prim_type = GF_EVG_TRIANGLES;
765 		break;
766 	case GF_EVG_QUADS:
767 		idx_inc = 4;
768 		glob_quad_done = GF_FALSE;
769 		break;
770 	case GF_EVG_QUAD_STRIP:
771 		idx_inc = 4;
772 		glob_quad_done = GF_FALSE;
773 		is_strip_fan = 1;
774 		prim_type = GF_EVG_QUADS;
775 		break;
776 	default:
777 		idx_inc = 1;
778 		hpw = (int) (s3d->point_size*ONE_PIXEL/2);
779 		s3d->pt_radius = (Float) (s3d->point_size*s3d->point_size) / 4;
780 
781 		break;
782 	}
783 	if (!is_strip_fan && (nb_idx % idx_inc))
784 		return GF_BAD_PARAM;
785 
786 	s3d->prim_type = prim_type;
787 	memset(&frag_ckck, 0, sizeof(EVGFragCallback));
788 	frag_ckck.surf = surf;
789 	frag_ckck.frag_param.ptype = prim_type;
790 	frag_ckck.frag_param.prim_index = 0;
791 
792 	xmin = raster->min_ex * ONE_PIXEL;
793 	xmax = raster->max_ex * ONE_PIXEL;
794 	ymin = raster->min_ey * ONE_PIXEL;
795 	ymax = raster->max_ey * ONE_PIXEL;
796 
797 	//raster coordinates of points
798 	TPos _x1=0, _y1=0, _x2=0, _y2=0, _x3=0, _y3=0, _x4=0, _y4=0, _prev_x2=0, _prev_y2=0;
799 	/*vertices in raster/window space: x and y are in pixel space, z is [min_depth, max_depth]*/
800 	GF_Vec4 s_pt1, s_pt2, s_pt3, s_pt4, prev_s_pt2;
801 	u32 idx1=0, idx2=0, idx3=0, idx4=0;
802 	u32 vidx1=0, vidx2=0, vidx3=0, vidx4=0, prev_vidx2=0;
803 
804 	memset(&vparam, 0, sizeof(GF_EVGVertexParam));
805 	vparam.ptype = prim_type;
806 
807 	nb_comp_1 = nb_comp-1;
808 	for (i=0; i<nb_idx; i += idx_inc) {
809 		Bool quad_done = glob_quad_done;
810 		GF_Vec4 *vx = &vparam.in_vertex;
811 
812 		if (s3d->vert_shader) {
813 			vparam.prim_index = prim_index;
814 		}
815 		prim_index++;
816 
817 #define GETVEC(_name, _idx)\
818 		vx->x = vertices[_idx];\
819 		vx->y = vertices[_idx+1];\
820 		if (_idx+nb_comp_1>=nb_vertices) return GF_BAD_PARAM;\
821 		vx->z = (nb_comp>2) ? vertices[_idx+2] : 0.0f;\
822 		vx->q = 1.0;\
823 		if (s3d->vert_shader) {\
824 			s3d->vert_shader(s3d->vert_shader_udta, &vparam); \
825 			s_##_name = vparam.out_vertex;\
826 		} else {\
827 			s_##_name.x = vx->x;\
828 			s_##_name.y = vx->y;\
829 			s_##_name.z = vx->z;\
830 			s_##_name.q = 1;\
831 			gf_mx_apply_vec_4x4(&projModeView, &s_##_name);\
832 		}\
833 		if (!evg3d_persp_divide(&s_##_name)) continue;\
834 
835 		/*get vertice, apply transform and perspective divide and translate to raster*/
836 		if (is_strip_fan && i) {
837 			idx_inc=1;
838 			if (prim_type==GF_EVG_LINES) {
839 				_x1 = _x2;
840 				_y1 = _y2;
841 				s_pt1 = s_pt2;
842 				vidx1 = vidx2;
843 				vidx2 = indices[i];
844 				idx2 = vidx2 * nb_comp;
845 				vparam.vertex_idx = vidx2;
846 				vparam.vertex_idx_in_prim = 1;
847 				GETVEC(pt2, idx2)
848 				evg3d_ndc_to_raster(surf, &s_pt2, &_x2, &_y2);
849 			}
850 			//triangle strip
851 			else if (is_strip_fan==1) {
852 				/*triangle strip*/
853 				if (prim_type==GF_EVG_TRIANGLES) {
854 					/*swap v2 to v1 and v3 to v2*/
855 					_x1 = _x2;
856 					_y1 = _y2;
857 					s_pt1 = s_pt2;
858 					vidx1 = vidx2;
859 
860 					_x2 = _x3;
861 					_y2 = _y3;
862 					s_pt2 = s_pt3;
863 					vidx2 = vidx3;
864 
865 					vidx3 = indices[i];
866 					idx3 = vidx3 * nb_comp;
867 					vparam.vertex_idx = vidx3;
868 					vparam.vertex_idx_in_prim = 2;
869 					GETVEC(pt3, idx3)
870 					evg3d_ndc_to_raster(surf, &s_pt3, &_x3, &_y3);
871 				}
872 				//quad strip - since we draw [v1, v2, v3, v4] as 2 triangles [v1, v2, v3] and [v1, v3, v4]
873 				// we only need to restore prev v2 as v1
874 				else {
875 					_x1 = _prev_x2;
876 					_y1 = _prev_y2;
877 					s_pt1 = prev_s_pt2;
878 					vidx1 = prev_vidx2;
879 
880 					vidx4 = indices[i];
881 					idx4 = vidx4 * nb_comp;
882 					vparam.vertex_idx = vidx4;
883 					vparam.vertex_idx_in_prim = 3;
884 					GETVEC(pt4, idx4)
885 					evg3d_ndc_to_raster(surf, &s_pt4, &_x4, &_y4);
886 				}
887 			}
888 			//triangle fan
889 			else {
890 				//keep center and move 3rd vertex as second
891 				_x2 = _x3;
892 				_y2 = _y3;
893 				s_pt2 = s_pt3;
894 				vidx2 = vidx3;
895 
896 				vidx3 = indices[i];
897 				idx3 = vidx3 * nb_comp;
898 				vparam.vertex_idx = vidx3;
899 				vparam.vertex_idx_in_prim = 2;
900 				GETVEC(pt3, idx3)
901 				evg3d_ndc_to_raster(surf, &s_pt3, &_x3, &_y3);
902 			}
903 		} else {
904 			vidx1 = indices[i];
905 			idx1 = vidx1 * nb_comp;
906 			vparam.vertex_idx = vidx1;
907 			vparam.vertex_idx_in_prim = 0;
908 			GETVEC(pt1, idx1)
909 			evg3d_ndc_to_raster(surf, &s_pt1, &_x1, &_y1);
910 			if (prim_type>=GF_EVG_LINES) {
911 				vidx2 = indices[i+1];
912 				idx2 = vidx2 * nb_comp;
913 				vparam.vertex_idx = vidx2;
914 				vparam.vertex_idx_in_prim = 1;
915 				GETVEC(pt2, idx2)
916 				evg3d_ndc_to_raster(surf, &s_pt2, &_x2, &_y2);
917 				if (prim_type>=GF_EVG_TRIANGLES) {
918 					vidx3 = indices[i+2];
919 					idx3 = vidx3 * nb_comp;
920 					vparam.vertex_idx = vidx3;
921 					vparam.vertex_idx_in_prim = 2;
922 					GETVEC(pt3, idx3)
923 					evg3d_ndc_to_raster(surf, &s_pt3, &_x3, &_y3);
924 					if (prim_type==GF_EVG_QUADS) {
925 						vidx4 = indices[i+3];
926 						idx4 = vidx4 * nb_comp;
927 						vparam.vertex_idx = vidx4;
928 						vparam.vertex_idx_in_prim = 3;
929 						GETVEC(pt4, idx4)
930 						evg3d_ndc_to_raster(surf, &s_pt4, &_x4, &_y4);
931 					}
932 				}
933 			}
934 		}
935 #undef GETVEC
936 
937 restart_quad:
938 		raster->first_scanline = surf->height;
939 		raster->ex = (int) (raster->max_ex+1);
940 		raster->ey = (int) (raster->max_ey+1);
941 		raster->cover = 0;
942 		raster->area = 0;
943 
944 
945 		if (prim_type>=GF_EVG_TRIANGLES) {
946 
947 			if (!precompute_tri(s3d, &frag_ckck, xmin, xmax, ymin, ymax, _x1, _y1, _x2, _y2, _x3, _y3, &s_pt1, &s_pt2, &s_pt3, vidx1, vidx2, vidx3))
948 				continue;
949 
950 			//check backcull
951 			if (s3d->is_ccw) {
952 				if (s3d->area<0) {
953 					if (s3d->backface_cull)
954 						continue;
955 				}
956 			} else {
957 				if (s3d->area>0) {
958 					if (s3d->backface_cull)
959 						continue;
960 				}
961 			}
962 		} else {
963 			s3d->s_v1 = s_pt1;
964 			frag_ckck.frag_param.idx1 = vidx1;
965 			if (prim_type==GF_EVG_LINES) {
966 				GF_Vec lv;
967 				s3d->s_v2 = s_pt2;
968 				gf_vec_diff(lv, s_pt2, s_pt1);
969 				lv.z=0;
970 				s3d->v1v2_length = gf_vec_len(lv);
971 				frag_ckck.frag_param.idx2 = vidx2;
972 			}
973 		}
974 		frag_ckck.frag_param.prim_index = prim_index-1;
975 
976 		if (prim_type==GF_EVG_POINTS) {
977 			raster->idx1 = raster->idx2 = idx1;
978 			//draw square
979 			gray3d_move_to(raster, _x1-hpw, _y1-hpw);
980 			gray_render_line(raster, _x1+hpw, _y1-hpw);
981 			gray_render_line(raster, _x1+hpw, _y1+hpw);
982 			gray_render_line(raster, _x1-hpw, _y1+hpw);
983 			//and close
984 			gray_render_line(raster, _x1-hpw, _y1-hpw);
985 			gray_record_cell( raster );
986 		} else if (prim_type==GF_EVG_LINES) {
987 			raster->idx1 = idx1;
988 			raster->idx2 = idx2;
989 			gray3d_move_to(raster, _x1+hlw, _y1+hlw);
990 			gray_render_line(raster, _x1-hlw, _y1-hlw);
991 			gray_render_line(raster, _x2-hlw, _y2-hlw);
992 			gray_render_line(raster, _x2+hlw, _y2+hlw);
993 			//and close
994 			gray_render_line(raster, _x1+hlw, _y1+hlw);
995 			gray_record_cell( raster );
996 		} else {
997 			raster->idx1 = idx1;
998 			raster->idx2 = idx2;
999 			gray3d_move_to(raster, _x1, _y1);
1000 			gray_render_line(raster, _x2, _y2);
1001 			raster->idx1 = idx2;
1002 			raster->idx2 = idx3;
1003 			gray_render_line(raster, _x3, _y3);
1004 
1005 			//and close
1006 			raster->idx1 = idx3;
1007 			raster->idx2 = idx1;
1008 			gray_render_line(raster, _x1, _y1);
1009 			gray_record_cell( raster );
1010 		}
1011 
1012 		/* sort each scanline and render it*/
1013 		for (li=raster->first_scanline; li<size_y; li++) {
1014 			AAScanline *sl = &raster->scanlines[li];
1015 			//if nothing on this line, we are done for this primitive
1016 			if (!sl->num) break;
1017 
1018 			if (sl->num>1) gray_quick_sort(sl->cells, sl->num);
1019 			gray_sweep_line(raster, sl, li, GF_FALSE);
1020 
1021 			if (sl->pnum) {
1022 				if (first_patch>li) first_patch = li;
1023 				if (last_patch<li) last_patch = li;
1024 			}
1025 		}
1026 		if (!quad_done) {
1027 			if (is_strip_fan) {
1028 				_prev_x2 = _x2;
1029 				_prev_y2 = _y2;
1030 				prev_s_pt2 = s_pt2;
1031 				prev_vidx2 = vidx2;
1032 			}
1033 			quad_done = GF_TRUE;
1034 			_x2 = _x3;
1035 			_y2 = _y3;
1036 			_x3 = _x4;
1037 			_y3 = _y4;
1038 			s_pt2 = s_pt3;
1039 			s_pt3 = s_pt4;
1040 			vidx2 = vidx3;
1041 			vidx3 = vidx4;
1042 			s3d->s_v1 = s3d->s_v2;
1043 			s3d->s_v2 = s3d->s_v3;
1044 			goto restart_quad;
1045 		}
1046 	}
1047 
1048 	/*flush all partial fragments*/
1049 	span.len = 0;
1050 	for (li=first_patch; li<=last_patch; li++) {
1051 		AAScanline *sl = &raster->scanlines[li];
1052 		Float *depth_line = &surf->ext3d->depth_buffer[li];
1053 		for (i=0; i<sl->pnum; i++) {
1054 			PatchPixel *pi = &sl->pixels[i];
1055 
1056 			if (pi->cover == 0xFF) continue;
1057 			if (!surf->ext3d->depth_test(pi->write_depth, pi->depth)) continue;
1058 
1059 			if (surf->fill_single) {
1060 				surf->fill_single_a(li, pi->x, pi->cover, pi->color, surf);
1061 			} else {
1062 				span.coverage = pi->cover;
1063 				span.x = pi->x;
1064 				surf->gray_spans(li, 1, &span, surf);
1065 			}
1066 			if (surf->ext3d->run_write_depth)
1067 				depth_line[pi->x] = pi->depth;
1068 		}
1069 	}
1070 	return GF_OK;
1071 }
1072 
evg_raster_render3d_path(GF_EVGSurface * surf,GF_Path * path,Float z)1073 GF_Err evg_raster_render3d_path(GF_EVGSurface *surf, GF_Path *path, Float z)
1074 {
1075 
1076 	EVG_Vector   v_start;
1077 	int   n;         /* index of contour in outline     */
1078 	int   first;     /* index of first point in contour */
1079 	TPos _x, _y, _sx, _sy;
1080 	u32 li, size_y;
1081 	EVG_Raster raster = surf->raster;
1082 	EVG_Outline *outline;
1083 	GF_Matrix projModeView;
1084 	EVG_Surface3DExt *s3d = surf->ext3d;
1085 	EVGFragCallback frag_ckck;
1086 	u32 xmin, xmax, ymin, ymax;
1087 	GF_Err e;
1088 	GF_Rect rc;
1089 
1090 	if (!surf->ext3d->frag_shader) return GF_BAD_PARAM;
1091 
1092 	e = gf_evg_surface_set_path(surf, path);
1093 	if (e) return e;
1094 
1095 	outline = &surf->ftoutline;
1096 
1097 	raster->render_span  = (EVG_Raster_Span_Func) EVG3D_SpanFunc;
1098 	raster->render_span_data = &frag_ckck;
1099 
1100 	/* Set up state in the raster object */
1101 	raster->min_ex = surf->clip_xMin;
1102 	raster->min_ey = surf->clip_yMin;
1103 	raster->max_ex = surf->clip_xMax;
1104 	raster->max_ey = surf->clip_yMax;
1105 	s3d->run_write_depth = s3d->depth_buffer ? s3d->write_depth : GF_FALSE;
1106 
1107 	size_y = (u32) (raster->max_ey - raster->min_ey);
1108 	if (raster->max_lines < size_y) {
1109 		raster->scanlines = (AAScanline*)gf_realloc(raster->scanlines, sizeof(AAScanline)*size_y);
1110 		memset(&raster->scanlines[raster->max_lines], 0, sizeof(AAScanline)*(size_y-raster->max_lines) );
1111 		raster->max_lines = size_y;
1112 	}
1113 
1114 	gf_mx_copy(projModeView, s3d->proj);
1115 	gf_mx_add_matrix_4x4(&projModeView, &s3d->modelview);
1116 
1117 	s3d->prim_type = GF_EVG_TRIANGLES;
1118 	memset(&frag_ckck, 0, sizeof(EVGFragCallback));
1119 	frag_ckck.surf = surf;
1120 	frag_ckck.frag_param.ptype = GF_EVG_TRIANGLES;
1121 	frag_ckck.frag_param.prim_index = 0;
1122 
1123 	xmin = raster->min_ex * ONE_PIXEL;
1124 	xmax = raster->max_ex * ONE_PIXEL;
1125 	ymin = raster->min_ey * ONE_PIXEL;
1126 	ymax = raster->max_ey * ONE_PIXEL;
1127 
1128 	//raster coordinates of points
1129 	TPos _x1, _y1, _x2, _y2, _x3, _y3;
1130 	/*vertices in raster/window space: x and y are in pixel space, z is [min_depth, max_depth]*/
1131 	GF_Vec4 s_pt1, s_pt2, s_pt3;
1132 
1133 	/*get bounds, and compute interpolation from (top-left, top-right, bottom-right) vertices*/
1134 	gf_path_get_bounds(path, &rc);
1135 	s_pt1.x = rc.x; s_pt1.y = rc.y; s_pt1.z = z; s_pt1.q = 1;
1136 	s_pt2.x = rc.x + rc.width; s_pt2.y = rc.y; s_pt2.z = z; s_pt2.q = 1;
1137 	s_pt3.x = rc.x + rc.width; s_pt3.y = rc.y - rc.height ; s_pt3.z = z; s_pt3.q = 1;
1138 
1139 	gf_mx_apply_vec_4x4(&projModeView, &s_pt1);
1140 	evg3d_persp_divide(&s_pt1);
1141 	evg3d_ndc_to_raster(surf, &s_pt1, &_x1, &_y1);
1142 	gf_mx_apply_vec_4x4(&projModeView, &s_pt2);
1143 	evg3d_persp_divide(&s_pt2);
1144 	evg3d_ndc_to_raster(surf, &s_pt2, &_x2, &_y2);
1145 	gf_mx_apply_vec_4x4(&projModeView, &s_pt3);
1146 	evg3d_persp_divide(&s_pt3);
1147 	evg3d_ndc_to_raster(surf, &s_pt3, &_x3, &_y3);
1148 
1149 	if (!precompute_tri(s3d, &frag_ckck, xmin, xmax, ymin, ymax, _x1, _y1, _x2, _y2, _x3, _y3, &s_pt1, &s_pt2, &s_pt3, 0, 1, 2))
1150 		return GF_OK;
1151 
1152 	s3d->mode2d = GF_TRUE;
1153 	first = 0;
1154 	for ( n = 0; n < outline->n_contours; n++ ) {
1155 		GF_Vec4 pt;
1156 		EVG_Vector *point;
1157 		EVG_Vector *limit;
1158 		int  last;  /* index of last point in contour */
1159 		last  = outline->contours[n];
1160 		limit = outline->points + last;
1161 		v_start = outline->points[first];
1162 		point = outline->points + first;
1163 
1164 		pt.x = v_start.x;
1165 		pt.y = v_start.y;
1166 		pt.z = z;
1167 		pt.q = 1;
1168 		gf_mx_apply_vec_4x4(&projModeView, &pt);
1169 		if (!evg3d_persp_divide(&pt)) {
1170 			continue;
1171 		}
1172 		evg3d_ndc_to_raster(surf, &pt, &_sx, &_sy);
1173 		gray3d_move_to(raster, _sx, _sy);
1174 		while ( point < limit ) {
1175 			point++;
1176 
1177 			pt.x = point->x;
1178 			pt.y = point->y;
1179 			pt.z = z;
1180 			pt.q = 1;
1181 			gf_mx_apply_vec_4x4(&projModeView, &pt);
1182 			if (!evg3d_persp_divide(&pt)) {
1183 				break;
1184 			}
1185 			evg3d_ndc_to_raster(surf, &pt, &_x, &_y);
1186 			gray_render_line(raster, _x, _y);
1187 		}
1188 		gray_render_line(raster, _sx, _sy);
1189 
1190 		first = last + 1;
1191 	}
1192 
1193 	gray_record_cell( raster );
1194 	/* sort each scanline and render it*/
1195 	for (li=raster->first_scanline; li<size_y; li++) {
1196 		AAScanline *sl = &raster->scanlines[li];
1197 		if (sl->num) {
1198 			if (sl->num>1) gray_quick_sort(sl->cells, sl->num);
1199 			gray_sweep_line(raster, sl, li, GF_TRUE);
1200 		}
1201 	}
1202 	surf->ext3d->mode2d = GF_FALSE;
1203 	return GF_OK;
1204 
1205 }
evg_3d_resize(GF_EVGSurface * surf)1206 GF_Err evg_3d_resize(GF_EVGSurface *surf)
1207 {
1208 /*	surf->ext3d->depth_buffer = gf_realloc(surf->ext3d->depth_buffer, sizeof(Float)*surf->width*surf->height);
1209 	if (!surf->ext3d->depth_buffer) return GF_OUT_OF_MEM;
1210 */
1211 	surf->ext3d->depth_buffer = NULL;
1212 
1213 	if (!surf->ext3d->vp_w || !surf->ext3d->vp_h) {
1214 		surf->ext3d->vp_x = 0;
1215 		surf->ext3d->vp_y = 0;
1216 		surf->ext3d->vp_w = surf->width;
1217 		surf->ext3d->vp_h = surf->height;
1218 	}
1219 	surf->ext3d->pix_vals = gf_realloc(surf->ext3d->pix_vals, sizeof(u32)*surf->width);
1220 	return GF_OK;
1221 }
1222 
1223 GF_EXPORT
gf_evg_surface_clear_depth(GF_EVGSurface * surf,Float depth)1224 GF_Err gf_evg_surface_clear_depth(GF_EVGSurface *surf, Float depth)
1225 {
1226 	u32 i, lsize;
1227 	Float *depths;
1228 	u8 *depth_p;
1229 	if (!surf->ext3d) return GF_BAD_PARAM;
1230 
1231 	depths = surf->ext3d->depth_buffer;
1232 	if (!depths) return GF_OK; //GF_BAD_PARAM;
1233 	//copy first line
1234 	for (i=0; i<surf->width; i++) {
1235 		depths[i] = depth;
1236 	}
1237 	//copy first line
1238 	depth_p = (u8 *) surf->ext3d->depth_buffer;
1239 	lsize = sizeof(Float) * surf->width;
1240 	for (i=1; i<surf->height; i++) {
1241 		u8 *depth_l = depth_p + i*lsize;
1242 		memcpy(depth_l, depth_p, lsize);
1243 	}
1244 	return GF_OK;
1245 }
1246 
1247 
1248 GF_EXPORT
gf_evg_surface_viewport(GF_EVGSurface * surf,u32 x,u32 y,u32 w,u32 h)1249 GF_Err gf_evg_surface_viewport(GF_EVGSurface *surf, u32 x, u32 y, u32 w, u32 h)
1250 {
1251 	if (!surf->ext3d) return GF_BAD_PARAM;
1252 	surf->ext3d->vp_x = x;
1253 	surf->ext3d->vp_y = y;
1254 	surf->ext3d->vp_w = w;
1255 	surf->ext3d->vp_h = h;
1256 	return GF_OK;
1257 }
1258 
depth_test_never(Float depth_buf_value,Float frag_value)1259 static Bool depth_test_never(Float depth_buf_value, Float frag_value)
1260 {
1261 	return GF_FALSE;
1262 }
depth_test_always(Float depth_buf_value,Float frag_value)1263 static Bool depth_test_always(Float depth_buf_value, Float frag_value)
1264 {
1265 	return GF_TRUE;
1266 }
depth_test_less(Float depth_buf_value,Float frag_value)1267 static Bool depth_test_less(Float depth_buf_value, Float frag_value)
1268 {
1269 	if (frag_value<depth_buf_value) return GF_TRUE;
1270 	return GF_FALSE;
1271 }
depth_test_less_equal(Float depth_buf_value,Float frag_value)1272 static Bool depth_test_less_equal(Float depth_buf_value, Float frag_value)
1273 {
1274 	if (frag_value<=depth_buf_value) return GF_TRUE;
1275 	return GF_FALSE;
1276 }
depth_test_equal(Float depth_buf_value,Float frag_value)1277 static Bool depth_test_equal(Float depth_buf_value, Float frag_value)
1278 {
1279 	if (frag_value==depth_buf_value) return GF_TRUE;
1280 	return GF_FALSE;
1281 }
depth_test_greater(Float depth_buf_value,Float frag_value)1282 static Bool depth_test_greater(Float depth_buf_value, Float frag_value)
1283 {
1284 	if (frag_value>depth_buf_value) return GF_TRUE;
1285 	return GF_FALSE;
1286 }
depth_test_greater_equal(Float depth_buf_value,Float frag_value)1287 static Bool depth_test_greater_equal(Float depth_buf_value, Float frag_value)
1288 {
1289 	if (frag_value>=depth_buf_value) return GF_TRUE;
1290 	return GF_FALSE;
1291 }
depth_test_not_equal(Float depth_buf_value,Float frag_value)1292 static Bool depth_test_not_equal(Float depth_buf_value, Float frag_value)
1293 {
1294 	if (frag_value==depth_buf_value) return GF_FALSE;
1295 	return GF_TRUE;
1296 }
1297 
1298 GF_EXPORT
gf_evg_set_depth_test(GF_EVGSurface * surf,GF_EVGDepthTest mode)1299 GF_Err gf_evg_set_depth_test(GF_EVGSurface *surf, GF_EVGDepthTest mode)
1300 {
1301 	if (!surf->ext3d) return GF_BAD_PARAM;
1302 	surf->ext3d->write_depth = GF_TRUE;
1303 	switch (mode) {
1304 	case GF_EVGDEPTH_NEVER:
1305 		surf->ext3d->depth_test = depth_test_never;
1306 		return GF_OK;
1307 	case GF_EVGDEPTH_ALWAYS:
1308 		surf->ext3d->depth_test = depth_test_always;
1309 		return GF_OK;
1310 	case GF_EVGDEPTH_EQUAL:
1311 		surf->ext3d->depth_test = depth_test_equal;
1312 		return GF_OK;
1313 	case GF_EVGDEPTH_NEQUAL:
1314 		surf->ext3d->depth_test = depth_test_not_equal;
1315 		return GF_OK;
1316 	case GF_EVGDEPTH_LESS:
1317 		surf->ext3d->depth_test = depth_test_less;
1318 		return GF_OK;
1319 	case GF_EVGDEPTH_LESS_EQUAL:
1320 		surf->ext3d->depth_test = depth_test_less_equal;
1321 		return GF_OK;
1322 	case GF_EVGDEPTH_GREATER:
1323 		surf->ext3d->depth_test = depth_test_greater;
1324 		return GF_OK;
1325 	case GF_EVGDEPTH_GREATER_EQUAL:
1326 		surf->ext3d->depth_test = depth_test_greater_equal;
1327 		return GF_OK;
1328 	case GF_EVGDEPTH_DISABLE:
1329 		surf->ext3d->depth_test = depth_test_always;
1330 		surf->ext3d->write_depth = GF_FALSE;
1331 		return GF_OK;
1332 	}
1333 	return GF_BAD_PARAM;
1334 
1335 }
1336 
evg_3d_update_depth_range(GF_EVGSurface * surf)1337 GF_Err evg_3d_update_depth_range(GF_EVGSurface *surf)
1338 {
1339 	if (!surf || !surf->ext3d) return GF_BAD_PARAM;
1340 	surf->ext3d->depth_range = surf->ext3d->max_depth - surf->ext3d->min_depth;
1341 	if (surf->ext3d->clip_zero) {
1342 		surf->ext3d->zw_factor = surf->ext3d->depth_range;
1343 		surf->ext3d->zw_offset = surf->ext3d->min_depth;
1344 	} else {
1345 		surf->ext3d->zw_factor = surf->ext3d->depth_range / 2;
1346 		surf->ext3d->zw_offset = (surf->ext3d->min_depth+surf->ext3d->max_depth)/2;
1347 
1348 	}
1349 	return GF_OK;
1350 }
1351 
yuv_3d_fill_run(GF_EVGStencil * p,GF_EVGSurface * surf,s32 _x,s32 _y,u32 count)1352 static void yuv_3d_fill_run(GF_EVGStencil *p, GF_EVGSurface *surf, s32 _x, s32 _y, u32 count)
1353 {
1354 	u32 *data = surf->stencil_pix_run;
1355 	u32 *src = surf->ext3d->pix_vals + _x;
1356 
1357 	memcpy(data, src, sizeof(u32)*count);
1358 }
1359 
evg_init_3d_surface(GF_EVGSurface * surf)1360 EVG_Surface3DExt *evg_init_3d_surface(GF_EVGSurface *surf)
1361 {
1362 	EVG_Surface3DExt *ext3d;
1363 	GF_SAFEALLOC(ext3d, EVG_Surface3DExt);
1364 	if (!ext3d) return NULL;
1365 	gf_mx_init(ext3d->proj);
1366 	gf_mx_init(ext3d->modelview);
1367 	ext3d->backface_cull = GF_TRUE;
1368 	ext3d->is_ccw = GF_TRUE;
1369 	ext3d->min_depth = 0;
1370 	ext3d->max_depth = FIX_ONE;
1371 	ext3d->depth_range = FIX_ONE;
1372 	ext3d->point_size = FIX_ONE;
1373 	ext3d->line_size = FIX_ONE;
1374 	ext3d->clip_zero = GF_FALSE;
1375 	ext3d->disable_aa = GF_FALSE;
1376 	ext3d->write_depth = GF_TRUE;
1377 	ext3d->early_depth_test = GF_TRUE;
1378 	ext3d->depth_test = depth_test_less;
1379 	ext3d->yuv_sten.fill_run = yuv_3d_fill_run;
1380 	evg_3d_update_depth_range(surf);
1381 	return ext3d;
1382 }
1383 
1384 
1385 
gf_evg_surface_set_fragment_shader(GF_EVGSurface * surf,gf_evg_fragment_shader shader,void * shader_udta)1386 GF_Err gf_evg_surface_set_fragment_shader(GF_EVGSurface *surf, gf_evg_fragment_shader shader, void *shader_udta)
1387 {
1388 	if (!surf || !surf->ext3d) return GF_BAD_PARAM;
1389 	surf->ext3d->frag_shader = shader;
1390 	surf->ext3d->frag_shader_udta = shader_udta;
1391 	return GF_OK;
1392 }
1393 
gf_evg_surface_disable_early_depth(GF_EVGSurface * surf,Bool disable)1394 GF_Err gf_evg_surface_disable_early_depth(GF_EVGSurface *surf, Bool disable)
1395 {
1396 	if (!surf || !surf->ext3d) return GF_BAD_PARAM;
1397 	surf->ext3d->early_depth_test = !disable;
1398 	return GF_OK;
1399 }
1400 
gf_evg_surface_set_vertex_shader(GF_EVGSurface * surf,gf_evg_vertex_shader shader,void * shader_udta)1401 GF_Err gf_evg_surface_set_vertex_shader(GF_EVGSurface *surf, gf_evg_vertex_shader shader, void *shader_udta)
1402 {
1403 	if (!surf || !surf->ext3d) return GF_BAD_PARAM;
1404 	surf->ext3d->vert_shader = shader;
1405 	surf->ext3d->vert_shader_udta = shader_udta;
1406 	return GF_OK;
1407 }
1408 
gf_evg_surface_set_ccw(GF_EVGSurface * surf,Bool is_ccw)1409 GF_Err gf_evg_surface_set_ccw(GF_EVGSurface *surf, Bool is_ccw)
1410 {
1411 	if (!surf || !surf->ext3d) return GF_BAD_PARAM;
1412 	surf->ext3d->is_ccw = is_ccw;
1413 	return GF_OK;
1414 }
gf_evg_surface_set_backcull(GF_EVGSurface * surf,Bool backcull)1415 GF_Err gf_evg_surface_set_backcull(GF_EVGSurface *surf, Bool backcull)
1416 {
1417 	if (!surf || !surf->ext3d) return GF_BAD_PARAM;
1418 	surf->ext3d->backface_cull = backcull;
1419 	return GF_OK;
1420 }
gf_evg_surface_set_antialias(GF_EVGSurface * surf,Bool antialias)1421 GF_Err gf_evg_surface_set_antialias(GF_EVGSurface *surf, Bool antialias)
1422 {
1423 	if (!surf || !surf->ext3d) return GF_BAD_PARAM;
1424 	surf->ext3d->disable_aa = antialias ? GF_FALSE : GF_TRUE;
1425 	return GF_OK;
1426 }
gf_evg_surface_set_min_depth(GF_EVGSurface * surf,Float min_depth)1427 GF_Err gf_evg_surface_set_min_depth(GF_EVGSurface *surf, Float min_depth)
1428 {
1429 	if (!surf || !surf->ext3d) return GF_BAD_PARAM;
1430 	surf->ext3d->min_depth = min_depth;
1431 	evg_3d_update_depth_range(surf);
1432 	return GF_OK;
1433 }
gf_evg_surface_set_max_depth(GF_EVGSurface * surf,Float max_depth)1434 GF_Err gf_evg_surface_set_max_depth(GF_EVGSurface *surf, Float max_depth)
1435 {
1436 	if (!surf || !surf->ext3d) return GF_BAD_PARAM;
1437 	surf->ext3d->max_depth = max_depth;
1438 	evg_3d_update_depth_range(surf);
1439 	return GF_OK;
1440 }
1441 
gf_evg_surface_set_clip_zero(GF_EVGSurface * surf,Bool clip_zero)1442 GF_Err gf_evg_surface_set_clip_zero(GF_EVGSurface *surf, Bool clip_zero)
1443 {
1444 	if (!surf || !surf->ext3d) return GF_BAD_PARAM;
1445 	surf->ext3d->clip_zero = clip_zero;
1446 	evg_3d_update_depth_range(surf);
1447 	return GF_OK;
1448 }
1449 
gf_evg_surface_set_point_size(GF_EVGSurface * surf,Float size)1450 GF_Err gf_evg_surface_set_point_size(GF_EVGSurface *surf, Float size)
1451 {
1452 	if (!surf || !surf->ext3d) return GF_BAD_PARAM;
1453 	surf->ext3d->point_size = size;
1454 	return GF_OK;
1455 }
gf_evg_surface_set_line_size(GF_EVGSurface * surf,Float size)1456 GF_Err gf_evg_surface_set_line_size(GF_EVGSurface *surf, Float size)
1457 {
1458 	if (!surf || !surf->ext3d) return GF_BAD_PARAM;
1459 	surf->ext3d->line_size = size;
1460 	return GF_OK;
1461 }
gf_evg_surface_set_point_smooth(GF_EVGSurface * surf,Bool smooth)1462 GF_Err gf_evg_surface_set_point_smooth(GF_EVGSurface *surf, Bool smooth)
1463 {
1464 	if (!surf || !surf->ext3d) return GF_BAD_PARAM;
1465 	surf->ext3d->smooth_points = smooth;
1466 	return GF_OK;
1467 }
1468 
gf_evg_surface_write_depth(GF_EVGSurface * surf,Bool do_write)1469 GF_Err gf_evg_surface_write_depth(GF_EVGSurface *surf, Bool do_write)
1470 {
1471 	if (!surf || !surf->ext3d) return GF_BAD_PARAM;
1472 	surf->ext3d->write_depth = do_write;
1473 	return GF_OK;
1474 }
gf_evg_surface_set_depth_buffer(GF_EVGSurface * surf,Float * depth)1475 GF_Err gf_evg_surface_set_depth_buffer(GF_EVGSurface *surf, Float *depth)
1476 {
1477 	if (!surf || !surf->ext3d) return GF_BAD_PARAM;
1478 	surf->ext3d->depth_buffer = depth;
1479 	return GF_OK;
1480 }
1481