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