Line data Source code
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 :
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 :
57 : static GFINLINE Bool evg3d_persp_divide(GF_Vec4 *pt)
58 : {
59 : //perspective divide
60 49741 : if (!pt->q) return GF_FALSE;
61 49741 : pt->q = gf_divfix(FIX_ONE, pt->q);
62 49741 : pt->x = gf_mulfix(pt->x, pt->q);
63 49741 : pt->y = gf_mulfix(pt->y, pt->q);
64 49741 : pt->z = gf_mulfix(pt->z, pt->q);
65 : return GF_TRUE;
66 : }
67 :
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 5 : pt->x = (pt->x + FIX_ONE) / 2 * surf->width;
72 : //idem but flip Y
73 5 : pt->y = (FIX_ONE - (pt->y + FIX_ONE)/2) * surf->height;
74 :
75 : //move Z from [-1, 1] to [min_depth, max_depth]
76 5 : pt->z += FIX_ONE;
77 5 : pt->z /= 2;
78 :
79 : #ifdef GPAC_FIXED_POINT
80 : *x = UPSCALE(pt->x);
81 : *y = UPSCALE(pt->y);
82 : #else
83 5 : *x = (s32) (pt->x * ONE_PIXEL);
84 5 : *y = (s32) (pt->y * ONE_PIXEL);
85 : #endif
86 : }
87 49736 : 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 49736 : pt->x = (pt->x + FIX_ONE) / 2 * surf->ext3d->vp_w + surf->ext3d->vp_x;
91 : //idem but flip Y
92 49736 : pt->y = (FIX_ONE - (pt->y + FIX_ONE)/2) * surf->ext3d->vp_h + surf->ext3d->vp_y;
93 : /*compute depth*/
94 49736 : if (!surf->ext3d->clip_zero) {
95 : //move Z from [-1, 1] to [min_depth, max_depth]
96 3636 : pt->z += FIX_ONE;
97 3636 : pt->z /= 2;
98 : }
99 49736 : 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 49736 : *x = (s32) (pt->x * ONE_PIXEL);
106 49736 : *y = (s32) (pt->y * ONE_PIXEL);
107 : #endif
108 49736 : }
109 :
110 2703 : 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 2703 : gray_record_cell(raster);
116 :
117 2703 : ex = TRUNC(x);
118 2703 : ey = TRUNC(y);
119 2703 : if ( ex < raster->min_ex ) ex = (TCoord)(raster->min_ex - 1);
120 2703 : raster->area = 0;
121 2703 : raster->cover = 0;
122 2703 : gray_set_cell( raster, ex, ey );
123 2703 : if (ey<0) ey=0;
124 2703 : raster->last_ey = SUBPIXELS( ey );
125 :
126 2703 : raster->x = x;
127 2703 : raster->y = y;
128 2703 : return 0;
129 : }
130 :
131 1 : 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 1 : EVG_Raster raster = surf->raster;
140 : EVG_Outline *outline = &surf->ftoutline;
141 :
142 1 : raster->render_span = (EVG_Raster_Span_Func) surf->gray_spans;
143 1 : raster->render_span_data = surf;
144 :
145 : /* Set up state in the raster object */
146 1 : raster->min_ex = surf->clip_xMin;
147 1 : raster->min_ey = surf->clip_yMin;
148 1 : raster->max_ex = surf->clip_xMax;
149 1 : raster->max_ey = surf->clip_yMax;
150 :
151 :
152 1 : size_y = (u32) (raster->max_ey - raster->min_ey);
153 1 : if ((u32) raster->max_lines < size_y) {
154 0 : raster->scanlines = (AAScanline*)gf_realloc(raster->scanlines, sizeof(AAScanline)*size_y);
155 0 : memset(&raster->scanlines[raster->max_lines], 0, sizeof(AAScanline)*(size_y-raster->max_lines) );
156 0 : raster->max_lines = size_y;
157 : }
158 :
159 1 : raster->ex = (int) (raster->max_ex+1);
160 1 : raster->ey = (int) (raster->max_ey+1);
161 1 : raster->cover = 0;
162 1 : raster->area = 0;
163 1 : raster->first_scanline = raster->max_ey;
164 :
165 : dir.x = dir.y = 0;
166 : dir.z = -FIX_ONE;
167 :
168 : first = 0;
169 2 : 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 1 : last = outline->contours[n];
175 1 : limit = outline->points + last;
176 1 : v_start = outline->points[first];
177 : point = outline->points + first;
178 :
179 1 : pt.x = v_start.x;
180 1 : pt.y = v_start.y;
181 1 : pt.z = 0;
182 1 : pt.q = 1;
183 1 : gf_mx_apply_vec_4x4(&surf->mx3d, &pt);
184 : if (!evg3d_persp_divide(&pt)) {
185 0 : continue;
186 : }
187 1 : evg_ndc_to_raster(surf, &pt, &_sx, &_sy);
188 1 : gray3d_move_to(raster, _sx, _sy);
189 6 : while ( point < limit ) {
190 4 : point++;
191 :
192 4 : pt.x = point->x;
193 4 : pt.y = point->y;
194 4 : pt.z = 0;
195 4 : pt.q = 1;
196 4 : gf_mx_apply_vec_4x4(&surf->mx3d, &pt);
197 : if (!evg3d_persp_divide(&pt)) {
198 : break;
199 : }
200 4 : evg_ndc_to_raster(surf, &pt, &_x, &_y);
201 4 : gray_render_line(raster, _x, _y);
202 : }
203 1 : gray_render_line(raster, _sx, _sy);
204 :
205 1 : first = last + 1;
206 : }
207 :
208 1 : gray_record_cell( raster );
209 : /* sort each scanline and render it*/
210 17 : for (li=raster->first_scanline; li<size_y; li++) {
211 16 : AAScanline *sl = &raster->scanlines[li];
212 16 : if (sl->num) {
213 16 : if (sl->num>1) gray_quick_sort(sl->cells, sl->num);
214 16 : gray_sweep_line(raster, sl, li, GF_TRUE);
215 : }
216 : }
217 1 : return GF_OK;
218 : }
219 :
220 :
221 4812826 : Bool evg3d_get_fragment(GF_EVGSurface *surf, GF_EVGFragmentParam *frag_param, Bool *is_transparent)
222 : {
223 4812826 : surf->fill_col = 0;
224 4812826 : surf->fill_col_wide = 0;
225 :
226 4812826 : 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 4812826 : if (frag_param->color.q<1.0) *is_transparent = GF_TRUE;
237 :
238 4812826 : if (surf->not_8bits) {
239 0 : 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 4812826 : u8 a = (u8) (frag_param->color.q*255);
242 4812826 : u8 r = (u8) (frag_param->color.x*255);
243 4812826 : u8 g = (u8) (frag_param->color.y*255);
244 4812826 : u8 b = (u8) (frag_param->color.z*255);
245 4812826 : surf->fill_col = GF_COL_ARGB(a, r, g, b);
246 : }
247 :
248 4812826 : if (surf->not_8bits) {
249 0 : if (surf->yuv_type) {
250 0 : if (frag_param->frag_valid==GF_EVG_FRAG_RGB) {
251 0 : surf->fill_col_wide = gf_evg_argb_to_ayuv_wide(surf, surf->fill_col_wide);
252 : }
253 : } else {
254 0 : if (frag_param->frag_valid==GF_EVG_FRAG_YUV) {
255 0 : surf->fill_col_wide = gf_evg_ayuv_to_argb_wide(surf, surf->fill_col_wide);
256 : }
257 : }
258 : } else {
259 4812826 : if (surf->yuv_type) {
260 : /*RGB frag*/
261 1204487 : if (frag_param->frag_valid==GF_EVG_FRAG_RGB) {
262 0 : surf->fill_col = gf_evg_argb_to_ayuv(surf, surf->fill_col);
263 : }
264 : } else {
265 3608339 : if (frag_param->frag_valid==GF_EVG_FRAG_YUV) {
266 0 : surf->fill_col = gf_evg_ayuv_to_argb(surf, surf->fill_col);
267 : }
268 : }
269 : }
270 : return GF_TRUE;
271 : }
272 :
273 : static float edgeFunction(const GF_Vec4 *a, const GF_Vec4 *b, const GF_Vec4 *c)
274 : {
275 2812 : return (c->x - a->x) * (b->y - a->y) - (c->y - a->y) * (b->x - a->x);
276 : }
277 :
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 14571291 : 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 :
289 239004 : 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 2605084 : for (i=0; i<sl->pnum; i++) {
294 1137512 : if (sl->pixels[i].x>x) break;
295 1063544 : if (sl->pixels[i].x<x) continue;
296 6 : sl->pixels[i].color = col;
297 6 : sl->pixels[i].cover = coverage;
298 6 : sl->pixels[i].depth = depth;
299 6 : sl->pixels[i].write_depth = write_depth;
300 6 : sl->pixels[i].idx1 = idx1;
301 6 : sl->pixels[i].idx2 = idx2;
302 6 : return;
303 : }
304 238998 : if (coverage==0xFF) return;
305 :
306 238998 : if (sl->pnum == sl->palloc) {
307 2654 : sl->palloc += AA_CELL_STEP_ALLOC;
308 2654 : sl->pixels = gf_realloc(sl->pixels, sizeof(PatchPixel) * sl->palloc);
309 : }
310 238998 : if (i==sl->pnum) {
311 165030 : pp = &sl->pixels[sl->pnum];
312 : } else {
313 73968 : memmove(&sl->pixels[i+1], &sl->pixels[i], sizeof(PatchPixel)*(sl->pnum - i));
314 73968 : pp = &sl->pixels[i];
315 : }
316 238998 : sl->pnum++;
317 238998 : pp->color = col;
318 238998 : pp->cover = coverage;
319 238998 : pp->x = x;
320 238998 : pp->depth = depth;
321 238998 : pp->write_depth = write_depth;
322 238998 : pp->idx1 = idx1;
323 238998 : pp->idx2 = idx2;
324 : }
325 :
326 : static PatchPixel *get_patch_pixel(AAScanline *sl, s32 x)
327 : {
328 : u32 i;
329 9502222 : for (i=0; i<sl->pnum; i++) {
330 11817224 : if (sl->pixels[i].x>x) break;
331 9621543 : if (sl->pixels[i].x<x) continue;
332 : return &sl->pixels[i];
333 : }
334 : return NULL;
335 : }
336 :
337 :
338 113754 : static void remove_patch_pixel(AAScanline *sl, s32 x)
339 : {
340 : u32 i;
341 521942 : for (i=0; i<sl->pnum; i++) {
342 317848 : if (sl->pixels[i].x>x) break;
343 317848 : if (sl->pixels[i].x<x) continue;
344 113754 : if (i+1<sl->pnum)
345 102983 : memmove(&sl->pixels[i], &sl->pixels[i+1], sizeof(PatchPixel)*(sl->pnum-i-1));
346 113754 : sl->pnum--;
347 : return;
348 : }
349 : }
350 :
351 121262 : 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 121262 : GF_EVGSurface *surf = fcbck->surf;
357 121262 : EVG_Surface3DExt *s3d = surf->ext3d;
358 121262 : GF_EVGFragmentParam *frag_param = &fcbck->frag_param;
359 121262 : AAScanline *sl = &surf->raster->scanlines[y];
360 121262 : 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 818954 : for (i=0; i<count; i++) {
367 697692 : u8 coverage = spans[i].coverage;
368 697692 : u32 j, len = spans[i].len;
369 697692 : s32 sx = spans[i].x;
370 5554789 : for (j=0; j<len; j++) {
371 :
372 :
373 4857097 : Bool transparent=GF_FALSE;
374 : Float depth, bc1, bc2, bc3;
375 : Bool full_cover=GF_TRUE;
376 : Bool edge_merge=GF_FALSE;
377 4857097 : s32 x = sx + j;
378 : PatchPixel *prev_partial = NULL;
379 :
380 : /*no AA, force full opacity and test pixel/line below*/
381 4857097 : if (s3d->disable_aa)
382 : coverage = 0xFF;
383 4857097 : else if (!s3d->mode2d)
384 4484342 : prev_partial = get_patch_pixel(sl, x);
385 :
386 4857097 : pix.x = (Float)x + 0.5f;
387 4857097 : pix.y = (Float)y + 0.5f;
388 :
389 4857097 : if (s3d->prim_type==GF_EVG_POINTS) {
390 0 : if (s3d->smooth_points) {
391 : Float dx, dy;
392 0 : dx = (Float)x - s3d->s_v1.x;
393 0 : dy = (Float)y - s3d->s_v1.y;
394 0 : dx *=dx;
395 0 : dy *=dy;
396 0 : if (dx+dy > s3d->pt_radius) {
397 0 : spans[i].coverage=0;
398 287178 : continue;
399 : }
400 : }
401 0 : depth = s3d->s_v1.z;
402 :
403 : bc1 = bc2 = bc3 = 0;
404 0 : if (coverage!=0xFF) {
405 : full_cover = GF_FALSE;
406 : }
407 4857097 : } else if (s3d->prim_type==GF_EVG_LINES) {
408 : GF_Vec pt;
409 :
410 0 : gf_vec_diff(pt, pix, s3d->s_v1);
411 0 : bc1 = gf_vec_len(pt);
412 0 : bc1 /= s3d->v1v2_length;
413 : bc1 = float_clamp(bc1, 0, 1);
414 0 : bc2 = FIX_ONE - bc1;
415 0 : depth = s3d->s_v1.z * bc1 + s3d->s_v2.z * bc2;
416 :
417 : bc3 = 0;
418 0 : if (coverage!=0xFF) {
419 : full_cover = GF_FALSE;
420 : }
421 : } else {
422 4857097 : bc1 = edgeFunction_pre(&s3d->s_v2, s3d->s3_m_s2_x, s3d->s3_m_s2_y, &pix);
423 4857097 : bc1 /= s3d->area;
424 4857097 : bc2 = edgeFunction_pre(&s3d->s_v3, s3d->s1_m_s3_x, s3d->s1_m_s3_y, &pix);
425 4857097 : bc2 /= s3d->area;
426 4857097 : bc3 = edgeFunction_pre(&s3d->s_v1, s3d->s2_m_s1_x, s3d->s2_m_s1_y, &pix);
427 4857097 : 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 4857097 : if (s3d->disable_aa)
434 : {
435 0 : if ((bc1<0) || (bc2<0) || (bc3<0)) {
436 0 : spans[i].coverage=0;
437 0 : 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 4857097 : 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 541778 : 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 541778 : transparent = GF_TRUE;
525 : }
526 4857097 : depth = s3d->s_v1.z * bc1 + s3d->s_v2.z * bc2 + s3d->s_v3.z * bc3;
527 : }
528 :
529 : //clip by depth
530 4857097 : if ((depth<s3d->min_depth) || (depth>s3d->max_depth)) {
531 4692 : spans[i].coverage=0;
532 4692 : continue;
533 : }
534 :
535 4852405 : depth_buf_val = depth_line ? depth_line[x] : s3d->max_depth;
536 4852405 : if (prev_partial) {
537 117663 : if ((spans[i].idx1==prev_partial->idx1)
538 115892 : || (spans[i].idx1==prev_partial->idx2)
539 1618 : || (spans[i].idx2==prev_partial->idx1)
540 1110 : || (spans[i].idx2==prev_partial->idx2)
541 : ) {
542 117657 : depth = prev_partial->depth;
543 117657 : edge_merge = GF_TRUE;
544 : } else {
545 : edge_merge = GF_FALSE;
546 6 : if (!s3d->depth_test(prev_partial->write_depth, depth_buf_val))
547 6 : depth_buf_val = prev_partial->write_depth;
548 : }
549 : }
550 :
551 :
552 : //do depth test except for edges
553 4852405 : if (! edge_merge && s3d->early_depth_test) {
554 4734748 : if (! s3d->depth_test(depth_buf_val, depth)) {
555 39579 : spans[i].coverage=0;
556 39579 : continue;
557 : }
558 : }
559 :
560 4812826 : frag_param->screen_x = pix.x;
561 4812826 : frag_param->screen_y = pix.y;
562 : //compute Z window coord
563 4812826 : frag_param->screen_z = s3d->zw_factor * depth + s3d->zw_offset;
564 4812826 : frag_param->depth = depth;
565 4812826 : frag_param->color.q = 1.0;
566 4812826 : 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 4812826 : frag_param->pbc1 = bc1*s3d->s_v1.q;
569 4812826 : frag_param->pbc2 = bc2*s3d->s_v2.q;
570 4812826 : frag_param->pbc3 = bc3*s3d->s_v3.q;
571 :
572 4812826 : frag_param->persp_denum = frag_param->pbc1 + frag_param->pbc2 + frag_param->pbc3;
573 :
574 4812826 : if (!evg3d_get_fragment(surf, frag_param, &transparent)) {
575 0 : spans[i].coverage=0;
576 0 : continue;
577 : }
578 4812826 : if (!s3d->early_depth_test) {
579 0 : if (! s3d->depth_test(depth_buf_val, frag_param->depth)) {
580 0 : spans[i].coverage=0;
581 0 : continue;
582 : }
583 : }
584 : //we overwrite a partial
585 4812826 : if (prev_partial) {
586 117663 : if (edge_merge) {
587 117657 : u32 ncov = coverage;
588 :
589 117657 : ncov += prev_partial->cover;
590 117657 : if (!s3d->depth_test(depth_buf_val, depth)) {
591 0 : remove_patch_pixel(sl, prev_partial->x);
592 0 : spans[i].coverage=0;
593 0 : continue;
594 : }
595 117657 : if (ncov>=0xFF) {
596 113754 : if (prev_partial->cover==0xFF) {
597 0 : spans[i].coverage=0;
598 0 : continue;
599 : }
600 113754 : remove_patch_pixel(sl, prev_partial->x);
601 : full_cover = GF_TRUE;
602 : coverage = 0xFF;
603 : } else {
604 3903 : prev_partial->cover = ncov;
605 3903 : prev_partial->color = surf->fill_col;
606 3903 : spans[i].coverage=0;
607 3903 : continue;
608 : }
609 : }
610 6 : else if (s3d->depth_test(prev_partial->write_depth, depth)) {
611 6 : prev_partial->write_depth = depth;
612 : }
613 : }
614 :
615 : //partial coverage, store
616 4695169 : if (!full_cover && !s3d->mode2d) {
617 239004 : push_patch_pixel(sl, x, surf->fill_col, coverage, depth, depth_buf_val, spans[i].idx1, spans[i].idx2);
618 239004 : spans[i].coverage=0;
619 239004 : continue;
620 : }
621 : //full opacity, write
622 : else {
623 4569919 : if (surf->fill_single) {
624 3464500 : if (transparent) {
625 228829 : surf->fill_single_a(y, x, coverage, surf->fill_col, surf);
626 : } else {
627 3235671 : surf->fill_single(y, x, surf->fill_col, surf);
628 : }
629 : } else {
630 1105419 : spans[i].coverage = 0xFF;
631 1105419 : s3d->pix_vals[x] = surf->fill_col;
632 : }
633 : }
634 :
635 : //write depth
636 4569919 : if (s3d->run_write_depth)
637 4561135 : depth_line[x] = frag_param->depth;
638 :
639 :
640 : } //end span.len loop
641 : } //end spans count loop
642 :
643 121262 : if (!surf->fill_single) {
644 42186 : surf->gray_spans(y, count, spans, surf);
645 : }
646 121262 : }
647 :
648 2812 : 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 2812 : if ((_x1<xmin) && (_x2<xmin) && (_x3<xmin))
656 : return GF_FALSE;
657 2812 : if ((_y1<ymin) && (_y2<ymin) && (_y3<ymin))
658 : return GF_FALSE;
659 2812 : if ((_x1>=xmax) && (_x2>=xmax) && (_x3>=xmax))
660 : return GF_FALSE;
661 2812 : if ((_y1>=ymax) && (_y2>=ymax) && (_y3>=ymax))
662 : return GF_FALSE;
663 :
664 5624 : s3d->area = edgeFunction(s_pt1, s_pt2, s_pt3);
665 :
666 2812 : s3d->s_v1 = *s_pt1;
667 2812 : s3d->s_v2 = *s_pt2;
668 2812 : s3d->s_v3 = *s_pt3;
669 2812 : frag_ckck->frag_param.idx1 = vidx1;
670 2812 : frag_ckck->frag_param.idx2 = vidx2;
671 2812 : frag_ckck->frag_param.idx3 = vidx3;
672 :
673 :
674 : //precompute a few things for this run
675 2812 : s3d->s3_m_s2_x = s3d->s_v3.x - s3d->s_v2.x;
676 2812 : s3d->s3_m_s2_y = s3d->s_v3.y - s3d->s_v2.y;
677 2812 : s3d->s1_m_s3_x = s3d->s_v1.x - s3d->s_v3.x;
678 2812 : s3d->s1_m_s3_y = s3d->s_v1.y - s3d->s_v3.y;
679 2812 : s3d->s2_m_s1_x = s3d->s_v2.x - s3d->s_v1.x;
680 2812 : s3d->s2_m_s1_y = s3d->s_v2.y - s3d->s_v1.y;
681 :
682 : GF_Vec lv;
683 : lv.z=0;
684 2812 : gf_vec_diff(lv, *s_pt2, *s_pt1);
685 2812 : s3d->v1v2_length = gf_vec_len(lv);
686 2812 : gf_vec_norm(&lv);
687 2812 : s3d->v1v2 = lv;
688 2812 : gf_vec_diff(lv, *s_pt3, *s_pt2);
689 2812 : s3d->v2v3_length = gf_vec_len(lv);
690 2812 : gf_vec_norm(&lv);
691 2812 : s3d->v2v3 = lv;
692 2812 : gf_vec_diff(lv, *s_pt3, *s_pt1);
693 2812 : s3d->v1v3_length = gf_vec_len(lv);
694 2812 : gf_vec_norm(&lv);
695 2812 : s3d->v1v3 = lv;
696 :
697 2812 : return GF_TRUE;
698 : }
699 :
700 226 : 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 226 : EVG_Raster raster = surf->raster;
707 226 : 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 226 : if (!surf->ext3d->frag_shader) return GF_BAD_PARAM;
717 :
718 226 : raster->render_span = (EVG_Raster_Span_Func) EVG3D_SpanFunc;
719 226 : raster->render_span_data = &frag_ckck;
720 :
721 : /* Set up state in the raster object */
722 226 : raster->min_ex = surf->clip_xMin;
723 226 : raster->min_ey = surf->clip_yMin;
724 226 : raster->max_ex = surf->clip_xMax;
725 226 : raster->max_ey = surf->clip_yMax;
726 :
727 226 : s3d->run_write_depth = s3d->depth_buffer ? s3d->write_depth : GF_FALSE;
728 :
729 226 : size_y = (u32) (raster->max_ey - raster->min_ey);
730 226 : if (raster->max_lines < size_y) {
731 18 : raster->scanlines = (AAScanline*)gf_realloc(raster->scanlines, sizeof(AAScanline)*size_y);
732 18 : memset(&raster->scanlines[raster->max_lines], 0, sizeof(AAScanline)*(size_y-raster->max_lines) );
733 18 : raster->max_lines = size_y;
734 : }
735 140220 : for (li=0; li<size_y; li++) {
736 140220 : raster->scanlines[li].pnum = 0;
737 : }
738 : first_patch = 0xFFFFFFFF;
739 : last_patch = 0;
740 :
741 226 : gf_mx_copy(projModeView, s3d->proj);
742 226 : gf_mx_add_matrix_4x4(&projModeView, &s3d->modelview);
743 :
744 226 : switch (prim_type) {
745 0 : case GF_EVG_LINE_STRIP:
746 : is_strip_fan = 1;
747 0 : case GF_EVG_LINES:
748 : idx_inc = 2;
749 0 : hlw = (int) (s3d->line_size*ONE_PIXEL/2);
750 : prim_type = GF_EVG_LINES;
751 0 : break;
752 : case GF_EVG_TRIANGLES:
753 : idx_inc = 3;
754 : break;
755 0 : case GF_EVG_TRIANGLE_STRIP:
756 : is_strip_fan = 1;
757 : idx_inc = 3;
758 : prim_type = GF_EVG_TRIANGLES;
759 0 : break;
760 0 : 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 0 : break;
766 0 : case GF_EVG_QUADS:
767 : idx_inc = 4;
768 : glob_quad_done = GF_FALSE;
769 0 : break;
770 0 : 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 0 : break;
776 0 : default:
777 : idx_inc = 1;
778 0 : hpw = (int) (s3d->point_size*ONE_PIXEL/2);
779 0 : s3d->pt_radius = (Float) (s3d->point_size*s3d->point_size) / 4;
780 :
781 0 : break;
782 : }
783 226 : if (!is_strip_fan && (nb_idx % idx_inc))
784 : return GF_BAD_PARAM;
785 :
786 226 : s3d->prim_type = prim_type;
787 : memset(&frag_ckck, 0, sizeof(EVGFragCallback));
788 226 : frag_ckck.surf = surf;
789 226 : frag_ckck.frag_param.ptype = prim_type;
790 : frag_ckck.frag_param.prim_index = 0;
791 :
792 226 : xmin = raster->min_ex * ONE_PIXEL;
793 226 : xmax = raster->max_ex * ONE_PIXEL;
794 226 : ymin = raster->min_ey * ONE_PIXEL;
795 226 : ymax = raster->max_ey * ONE_PIXEL;
796 :
797 : //raster coordinates of points
798 226 : 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 226 : vparam.ptype = prim_type;
806 :
807 226 : nb_comp_1 = nb_comp-1;
808 2938 : 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 2712 : if (s3d->vert_shader) {
813 1500 : vparam.prim_index = prim_index;
814 : }
815 2712 : 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 2712 : if (is_strip_fan && i) {
837 : idx_inc=1;
838 0 : if (prim_type==GF_EVG_LINES) {
839 0 : _x1 = _x2;
840 0 : _y1 = _y2;
841 0 : s_pt1 = s_pt2;
842 : vidx1 = vidx2;
843 0 : vidx2 = indices[i];
844 0 : idx2 = vidx2 * nb_comp;
845 0 : vparam.vertex_idx = vidx2;
846 0 : vparam.vertex_idx_in_prim = 1;
847 0 : GETVEC(pt2, idx2)
848 0 : evg3d_ndc_to_raster(surf, &s_pt2, &_x2, &_y2);
849 : }
850 : //triangle strip
851 0 : else if (is_strip_fan==1) {
852 : /*triangle strip*/
853 0 : if (prim_type==GF_EVG_TRIANGLES) {
854 : /*swap v2 to v1 and v3 to v2*/
855 0 : _x1 = _x2;
856 0 : _y1 = _y2;
857 0 : s_pt1 = s_pt2;
858 : vidx1 = vidx2;
859 :
860 0 : _x2 = _x3;
861 0 : _y2 = _y3;
862 0 : s_pt2 = s_pt3;
863 : vidx2 = vidx3;
864 :
865 0 : vidx3 = indices[i];
866 0 : idx3 = vidx3 * nb_comp;
867 0 : vparam.vertex_idx = vidx3;
868 0 : vparam.vertex_idx_in_prim = 2;
869 0 : GETVEC(pt3, idx3)
870 0 : 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 0 : _x1 = _prev_x2;
876 0 : _y1 = _prev_y2;
877 0 : s_pt1 = prev_s_pt2;
878 : vidx1 = prev_vidx2;
879 :
880 0 : vidx4 = indices[i];
881 0 : idx4 = vidx4 * nb_comp;
882 0 : vparam.vertex_idx = vidx4;
883 0 : vparam.vertex_idx_in_prim = 3;
884 0 : GETVEC(pt4, idx4)
885 0 : 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 0 : _x2 = _x3;
892 0 : _y2 = _y3;
893 0 : s_pt2 = s_pt3;
894 : vidx2 = vidx3;
895 :
896 0 : vidx3 = indices[i];
897 0 : idx3 = vidx3 * nb_comp;
898 0 : vparam.vertex_idx = vidx3;
899 0 : vparam.vertex_idx_in_prim = 2;
900 0 : GETVEC(pt3, idx3)
901 0 : evg3d_ndc_to_raster(surf, &s_pt3, &_x3, &_y3);
902 : }
903 : } else {
904 2712 : vidx1 = indices[i];
905 2712 : idx1 = vidx1 * nb_comp;
906 2712 : vparam.vertex_idx = vidx1;
907 2712 : vparam.vertex_idx_in_prim = 0;
908 2712 : GETVEC(pt1, idx1)
909 2712 : evg3d_ndc_to_raster(surf, &s_pt1, &_x1, &_y1);
910 2712 : if (prim_type>=GF_EVG_LINES) {
911 2712 : vidx2 = indices[i+1];
912 2712 : idx2 = vidx2 * nb_comp;
913 2712 : vparam.vertex_idx = vidx2;
914 2712 : vparam.vertex_idx_in_prim = 1;
915 2712 : GETVEC(pt2, idx2)
916 2712 : evg3d_ndc_to_raster(surf, &s_pt2, &_x2, &_y2);
917 2712 : if (prim_type>=GF_EVG_TRIANGLES) {
918 2712 : vidx3 = indices[i+2];
919 2712 : idx3 = vidx3 * nb_comp;
920 2712 : vparam.vertex_idx = vidx3;
921 2712 : vparam.vertex_idx_in_prim = 2;
922 2712 : GETVEC(pt3, idx3)
923 2712 : evg3d_ndc_to_raster(surf, &s_pt3, &_x3, &_y3);
924 2712 : if (prim_type==GF_EVG_QUADS) {
925 0 : vidx4 = indices[i+3];
926 0 : idx4 = vidx4 * nb_comp;
927 0 : vparam.vertex_idx = vidx4;
928 0 : vparam.vertex_idx_in_prim = 3;
929 0 : GETVEC(pt4, idx4)
930 0 : evg3d_ndc_to_raster(surf, &s_pt4, &_x4, &_y4);
931 : }
932 : }
933 : }
934 : }
935 : #undef GETVEC
936 :
937 2712 : restart_quad:
938 2712 : raster->first_scanline = surf->height;
939 2712 : raster->ex = (int) (raster->max_ex+1);
940 2712 : raster->ey = (int) (raster->max_ey+1);
941 2712 : raster->cover = 0;
942 2712 : raster->area = 0;
943 :
944 :
945 2712 : if (prim_type>=GF_EVG_TRIANGLES) {
946 :
947 2712 : 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 0 : continue;
949 :
950 : //check backcull
951 2712 : if (s3d->is_ccw) {
952 2712 : if (s3d->area<0) {
953 1610 : if (s3d->backface_cull)
954 1610 : continue;
955 : }
956 : } else {
957 0 : if (s3d->area>0) {
958 0 : if (s3d->backface_cull)
959 0 : continue;
960 : }
961 : }
962 : } else {
963 0 : s3d->s_v1 = s_pt1;
964 0 : frag_ckck.frag_param.idx1 = vidx1;
965 0 : if (prim_type==GF_EVG_LINES) {
966 : GF_Vec lv;
967 0 : s3d->s_v2 = s_pt2;
968 0 : gf_vec_diff(lv, s_pt2, s_pt1);
969 0 : lv.z=0;
970 0 : s3d->v1v2_length = gf_vec_len(lv);
971 0 : frag_ckck.frag_param.idx2 = vidx2;
972 : }
973 : }
974 1102 : frag_ckck.frag_param.prim_index = prim_index-1;
975 :
976 1102 : if (prim_type==GF_EVG_POINTS) {
977 0 : raster->idx1 = raster->idx2 = idx1;
978 : //draw square
979 0 : gray3d_move_to(raster, _x1-hpw, _y1-hpw);
980 0 : gray_render_line(raster, _x1+hpw, _y1-hpw);
981 0 : gray_render_line(raster, _x1+hpw, _y1+hpw);
982 0 : gray_render_line(raster, _x1-hpw, _y1+hpw);
983 : //and close
984 0 : gray_render_line(raster, _x1-hpw, _y1-hpw);
985 0 : gray_record_cell( raster );
986 1102 : } else if (prim_type==GF_EVG_LINES) {
987 0 : raster->idx1 = idx1;
988 0 : raster->idx2 = idx2;
989 0 : gray3d_move_to(raster, _x1+hlw, _y1+hlw);
990 0 : gray_render_line(raster, _x1-hlw, _y1-hlw);
991 0 : gray_render_line(raster, _x2-hlw, _y2-hlw);
992 0 : gray_render_line(raster, _x2+hlw, _y2+hlw);
993 : //and close
994 0 : gray_render_line(raster, _x1+hlw, _y1+hlw);
995 0 : gray_record_cell( raster );
996 : } else {
997 1102 : raster->idx1 = idx1;
998 1102 : raster->idx2 = idx2;
999 1102 : gray3d_move_to(raster, _x1, _y1);
1000 1102 : gray_render_line(raster, _x2, _y2);
1001 1102 : raster->idx1 = idx2;
1002 1102 : raster->idx2 = idx3;
1003 1102 : gray_render_line(raster, _x3, _y3);
1004 :
1005 : //and close
1006 1102 : raster->idx1 = idx3;
1007 1102 : raster->idx2 = idx1;
1008 1102 : gray_render_line(raster, _x1, _y1);
1009 1102 : gray_record_cell( raster );
1010 : }
1011 :
1012 : /* sort each scanline and render it*/
1013 113730 : for (li=raster->first_scanline; li<size_y; li++) {
1014 113726 : AAScanline *sl = &raster->scanlines[li];
1015 : //if nothing on this line, we are done for this primitive
1016 113726 : if (!sl->num) break;
1017 :
1018 112628 : if (sl->num>1) gray_quick_sort(sl->cells, sl->num);
1019 112628 : gray_sweep_line(raster, sl, li, GF_FALSE);
1020 :
1021 112628 : if (sl->pnum) {
1022 111669 : if (first_patch>li) first_patch = li;
1023 111669 : if (last_patch<li) last_patch = li;
1024 : }
1025 : }
1026 1102 : if (!quad_done) {
1027 0 : if (is_strip_fan) {
1028 0 : _prev_x2 = _x2;
1029 0 : _prev_y2 = _y2;
1030 0 : prev_s_pt2 = s_pt2;
1031 : prev_vidx2 = vidx2;
1032 : }
1033 : quad_done = GF_TRUE;
1034 0 : _x2 = _x3;
1035 0 : _y2 = _y3;
1036 0 : _x3 = _x4;
1037 0 : _y3 = _y4;
1038 0 : s_pt2 = s_pt3;
1039 0 : s_pt3 = s_pt4;
1040 : vidx2 = vidx3;
1041 : vidx3 = vidx4;
1042 0 : s3d->s_v1 = s3d->s_v2;
1043 0 : s3d->s_v2 = s3d->s_v3;
1044 0 : goto restart_quad;
1045 : }
1046 : }
1047 :
1048 : /*flush all partial fragments*/
1049 226 : span.len = 0;
1050 32090 : for (li=first_patch; li<=last_patch; li++) {
1051 31864 : AAScanline *sl = &raster->scanlines[li];
1052 31864 : Float *depth_line = &surf->ext3d->depth_buffer[li];
1053 157108 : for (i=0; i<sl->pnum; i++) {
1054 125244 : PatchPixel *pi = &sl->pixels[i];
1055 :
1056 125244 : if (pi->cover == 0xFF) continue;
1057 125244 : if (!surf->ext3d->depth_test(pi->write_depth, pi->depth)) continue;
1058 :
1059 125244 : if (surf->fill_single) {
1060 76878 : surf->fill_single_a(li, pi->x, pi->cover, pi->color, surf);
1061 : } else {
1062 48366 : span.coverage = pi->cover;
1063 48366 : span.x = pi->x;
1064 48366 : surf->gray_spans(li, 1, &span, surf);
1065 : }
1066 125244 : if (surf->ext3d->run_write_depth)
1067 124826 : depth_line[pi->x] = pi->depth;
1068 : }
1069 : }
1070 : return GF_OK;
1071 : }
1072 :
1073 100 : 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 100 : EVG_Raster raster = surf->raster;
1082 : EVG_Outline *outline;
1083 : GF_Matrix projModeView;
1084 100 : 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 100 : if (!surf->ext3d->frag_shader) return GF_BAD_PARAM;
1091 :
1092 100 : e = gf_evg_surface_set_path(surf, path);
1093 100 : if (e) return e;
1094 :
1095 : outline = &surf->ftoutline;
1096 :
1097 100 : raster->render_span = (EVG_Raster_Span_Func) EVG3D_SpanFunc;
1098 100 : raster->render_span_data = &frag_ckck;
1099 :
1100 : /* Set up state in the raster object */
1101 100 : raster->min_ex = surf->clip_xMin;
1102 100 : raster->min_ey = surf->clip_yMin;
1103 100 : raster->max_ex = surf->clip_xMax;
1104 100 : raster->max_ey = surf->clip_yMax;
1105 100 : s3d->run_write_depth = s3d->depth_buffer ? s3d->write_depth : GF_FALSE;
1106 :
1107 100 : size_y = (u32) (raster->max_ey - raster->min_ey);
1108 100 : if (raster->max_lines < size_y) {
1109 0 : raster->scanlines = (AAScanline*)gf_realloc(raster->scanlines, sizeof(AAScanline)*size_y);
1110 0 : memset(&raster->scanlines[raster->max_lines], 0, sizeof(AAScanline)*(size_y-raster->max_lines) );
1111 0 : raster->max_lines = size_y;
1112 : }
1113 :
1114 100 : gf_mx_copy(projModeView, s3d->proj);
1115 100 : gf_mx_add_matrix_4x4(&projModeView, &s3d->modelview);
1116 :
1117 100 : s3d->prim_type = GF_EVG_TRIANGLES;
1118 : memset(&frag_ckck, 0, sizeof(EVGFragCallback));
1119 100 : frag_ckck.surf = surf;
1120 100 : frag_ckck.frag_param.ptype = GF_EVG_TRIANGLES;
1121 : frag_ckck.frag_param.prim_index = 0;
1122 :
1123 100 : xmin = raster->min_ex * ONE_PIXEL;
1124 100 : xmax = raster->max_ex * ONE_PIXEL;
1125 100 : ymin = raster->min_ey * ONE_PIXEL;
1126 100 : 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 100 : gf_path_get_bounds(path, &rc);
1135 100 : s_pt1.x = rc.x; s_pt1.y = rc.y; s_pt1.z = z; s_pt1.q = 1;
1136 100 : s_pt2.x = rc.x + rc.width; s_pt2.y = rc.y; s_pt2.z = z; s_pt2.q = 1;
1137 100 : s_pt3.x = rc.x + rc.width; s_pt3.y = rc.y - rc.height ; s_pt3.z = z; s_pt3.q = 1;
1138 :
1139 100 : gf_mx_apply_vec_4x4(&projModeView, &s_pt1);
1140 : evg3d_persp_divide(&s_pt1);
1141 100 : evg3d_ndc_to_raster(surf, &s_pt1, &_x1, &_y1);
1142 100 : gf_mx_apply_vec_4x4(&projModeView, &s_pt2);
1143 : evg3d_persp_divide(&s_pt2);
1144 100 : evg3d_ndc_to_raster(surf, &s_pt2, &_x2, &_y2);
1145 100 : gf_mx_apply_vec_4x4(&projModeView, &s_pt3);
1146 : evg3d_persp_divide(&s_pt3);
1147 100 : evg3d_ndc_to_raster(surf, &s_pt3, &_x3, &_y3);
1148 :
1149 100 : 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 100 : s3d->mode2d = GF_TRUE;
1153 : first = 0;
1154 1700 : 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 1600 : last = outline->contours[n];
1160 1600 : limit = outline->points + last;
1161 1600 : v_start = outline->points[first];
1162 : point = outline->points + first;
1163 :
1164 1600 : pt.x = v_start.x;
1165 1600 : pt.y = v_start.y;
1166 1600 : pt.z = z;
1167 1600 : pt.q = 1;
1168 1600 : gf_mx_apply_vec_4x4(&projModeView, &pt);
1169 : if (!evg3d_persp_divide(&pt)) {
1170 0 : continue;
1171 : }
1172 1600 : evg3d_ndc_to_raster(surf, &pt, &_sx, &_sy);
1173 1600 : gray3d_move_to(raster, _sx, _sy);
1174 42900 : while ( point < limit ) {
1175 39700 : point++;
1176 :
1177 39700 : pt.x = point->x;
1178 39700 : pt.y = point->y;
1179 39700 : pt.z = z;
1180 39700 : pt.q = 1;
1181 39700 : gf_mx_apply_vec_4x4(&projModeView, &pt);
1182 : if (!evg3d_persp_divide(&pt)) {
1183 : break;
1184 : }
1185 39700 : evg3d_ndc_to_raster(surf, &pt, &_x, &_y);
1186 39700 : gray_render_line(raster, _x, _y);
1187 : }
1188 1600 : gray_render_line(raster, _sx, _sy);
1189 :
1190 1600 : first = last + 1;
1191 : }
1192 :
1193 100 : gray_record_cell( raster );
1194 : /* sort each scanline and render it*/
1195 35816 : for (li=raster->first_scanline; li<size_y; li++) {
1196 35716 : AAScanline *sl = &raster->scanlines[li];
1197 35716 : if (sl->num) {
1198 7237 : if (sl->num>1) gray_quick_sort(sl->cells, sl->num);
1199 7237 : gray_sweep_line(raster, sl, li, GF_TRUE);
1200 : }
1201 : }
1202 100 : surf->ext3d->mode2d = GF_FALSE;
1203 100 : return GF_OK;
1204 :
1205 : }
1206 19 : 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 19 : surf->ext3d->depth_buffer = NULL;
1212 :
1213 19 : if (!surf->ext3d->vp_w || !surf->ext3d->vp_h) {
1214 19 : surf->ext3d->vp_x = 0;
1215 19 : surf->ext3d->vp_y = 0;
1216 19 : surf->ext3d->vp_w = surf->width;
1217 19 : surf->ext3d->vp_h = surf->height;
1218 : }
1219 19 : surf->ext3d->pix_vals = gf_realloc(surf->ext3d->pix_vals, sizeof(u32)*surf->width);
1220 19 : return GF_OK;
1221 : }
1222 :
1223 : GF_EXPORT
1224 226 : 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 226 : if (!surf->ext3d) return GF_BAD_PARAM;
1230 :
1231 226 : depths = surf->ext3d->depth_buffer;
1232 226 : if (!depths) return GF_OK; //GF_BAD_PARAM;
1233 : //copy first line
1234 196780 : for (i=0; i<surf->width; i++) {
1235 196780 : depths[i] = depth;
1236 : }
1237 : //copy first line
1238 226 : depth_p = (u8 *) surf->ext3d->depth_buffer;
1239 226 : lsize = sizeof(Float) * surf->width;
1240 140220 : for (i=1; i<surf->height; i++) {
1241 139994 : u8 *depth_l = depth_p + i*lsize;
1242 139994 : memcpy(depth_l, depth_p, lsize);
1243 : }
1244 : return GF_OK;
1245 : }
1246 :
1247 :
1248 : GF_EXPORT
1249 226 : GF_Err gf_evg_surface_viewport(GF_EVGSurface *surf, u32 x, u32 y, u32 w, u32 h)
1250 : {
1251 226 : if (!surf->ext3d) return GF_BAD_PARAM;
1252 226 : surf->ext3d->vp_x = x;
1253 226 : surf->ext3d->vp_y = y;
1254 226 : surf->ext3d->vp_w = w;
1255 226 : surf->ext3d->vp_h = h;
1256 226 : return GF_OK;
1257 : }
1258 :
1259 9587 : static Bool depth_test_never(Float depth_buf_value, Float frag_value)
1260 : {
1261 9587 : return GF_FALSE;
1262 : }
1263 20010 : static Bool depth_test_always(Float depth_buf_value, Float frag_value)
1264 : {
1265 20010 : return GF_TRUE;
1266 : }
1267 4898457 : static Bool depth_test_less(Float depth_buf_value, Float frag_value)
1268 : {
1269 4898457 : if (frag_value<depth_buf_value) return GF_TRUE;
1270 20411 : return GF_FALSE;
1271 : }
1272 10005 : static Bool depth_test_less_equal(Float depth_buf_value, Float frag_value)
1273 : {
1274 10005 : if (frag_value<=depth_buf_value) return GF_TRUE;
1275 0 : return GF_FALSE;
1276 : }
1277 9587 : static Bool depth_test_equal(Float depth_buf_value, Float frag_value)
1278 : {
1279 9587 : if (frag_value==depth_buf_value) return GF_TRUE;
1280 9587 : return GF_FALSE;
1281 : }
1282 10005 : static Bool depth_test_greater(Float depth_buf_value, Float frag_value)
1283 : {
1284 10005 : if (frag_value>depth_buf_value) return GF_TRUE;
1285 0 : return GF_FALSE;
1286 : }
1287 10005 : static Bool depth_test_greater_equal(Float depth_buf_value, Float frag_value)
1288 : {
1289 10005 : if (frag_value>=depth_buf_value) return GF_TRUE;
1290 0 : return GF_FALSE;
1291 : }
1292 10005 : static Bool depth_test_not_equal(Float depth_buf_value, Float frag_value)
1293 : {
1294 10005 : if (frag_value==depth_buf_value) return GF_FALSE;
1295 10005 : return GF_TRUE;
1296 : }
1297 :
1298 : GF_EXPORT
1299 226 : GF_Err gf_evg_set_depth_test(GF_EVGSurface *surf, GF_EVGDepthTest mode)
1300 : {
1301 226 : if (!surf->ext3d) return GF_BAD_PARAM;
1302 226 : surf->ext3d->write_depth = GF_TRUE;
1303 226 : switch (mode) {
1304 1 : case GF_EVGDEPTH_NEVER:
1305 1 : surf->ext3d->depth_test = depth_test_never;
1306 1 : return GF_OK;
1307 1 : case GF_EVGDEPTH_ALWAYS:
1308 1 : surf->ext3d->depth_test = depth_test_always;
1309 1 : return GF_OK;
1310 1 : case GF_EVGDEPTH_EQUAL:
1311 1 : surf->ext3d->depth_test = depth_test_equal;
1312 1 : return GF_OK;
1313 1 : case GF_EVGDEPTH_NEQUAL:
1314 1 : surf->ext3d->depth_test = depth_test_not_equal;
1315 1 : return GF_OK;
1316 218 : case GF_EVGDEPTH_LESS:
1317 218 : surf->ext3d->depth_test = depth_test_less;
1318 218 : return GF_OK;
1319 1 : case GF_EVGDEPTH_LESS_EQUAL:
1320 1 : surf->ext3d->depth_test = depth_test_less_equal;
1321 1 : return GF_OK;
1322 1 : case GF_EVGDEPTH_GREATER:
1323 1 : surf->ext3d->depth_test = depth_test_greater;
1324 1 : return GF_OK;
1325 1 : case GF_EVGDEPTH_GREATER_EQUAL:
1326 1 : surf->ext3d->depth_test = depth_test_greater_equal;
1327 1 : return GF_OK;
1328 1 : case GF_EVGDEPTH_DISABLE:
1329 1 : surf->ext3d->depth_test = depth_test_always;
1330 1 : surf->ext3d->write_depth = GF_FALSE;
1331 1 : return GF_OK;
1332 : }
1333 : return GF_BAD_PARAM;
1334 :
1335 : }
1336 :
1337 164 : GF_Err evg_3d_update_depth_range(GF_EVGSurface *surf)
1338 : {
1339 164 : if (!surf || !surf->ext3d) return GF_BAD_PARAM;
1340 145 : surf->ext3d->depth_range = surf->ext3d->max_depth - surf->ext3d->min_depth;
1341 145 : if (surf->ext3d->clip_zero) {
1342 145 : surf->ext3d->zw_factor = surf->ext3d->depth_range;
1343 145 : surf->ext3d->zw_offset = surf->ext3d->min_depth;
1344 : } else {
1345 0 : surf->ext3d->zw_factor = surf->ext3d->depth_range / 2;
1346 0 : surf->ext3d->zw_offset = (surf->ext3d->min_depth+surf->ext3d->max_depth)/2;
1347 :
1348 : }
1349 : return GF_OK;
1350 : }
1351 :
1352 238255 : static void yuv_3d_fill_run(GF_EVGStencil *p, GF_EVGSurface *surf, s32 _x, s32 _y, u32 count)
1353 : {
1354 238255 : u32 *data = surf->stencil_pix_run;
1355 238255 : u32 *src = surf->ext3d->pix_vals + _x;
1356 :
1357 238255 : memcpy(data, src, sizeof(u32)*count);
1358 238255 : }
1359 :
1360 19 : EVG_Surface3DExt *evg_init_3d_surface(GF_EVGSurface *surf)
1361 : {
1362 : EVG_Surface3DExt *ext3d;
1363 19 : GF_SAFEALLOC(ext3d, EVG_Surface3DExt);
1364 19 : if (!ext3d) return NULL;
1365 38 : gf_mx_init(ext3d->proj);
1366 38 : gf_mx_init(ext3d->modelview);
1367 19 : ext3d->backface_cull = GF_TRUE;
1368 19 : ext3d->is_ccw = GF_TRUE;
1369 19 : ext3d->min_depth = 0;
1370 19 : ext3d->max_depth = FIX_ONE;
1371 19 : ext3d->depth_range = FIX_ONE;
1372 19 : ext3d->point_size = FIX_ONE;
1373 19 : ext3d->line_size = FIX_ONE;
1374 19 : ext3d->clip_zero = GF_FALSE;
1375 19 : ext3d->disable_aa = GF_FALSE;
1376 19 : ext3d->write_depth = GF_TRUE;
1377 19 : ext3d->early_depth_test = GF_TRUE;
1378 19 : ext3d->depth_test = depth_test_less;
1379 19 : ext3d->yuv_sten.fill_run = yuv_3d_fill_run;
1380 19 : evg_3d_update_depth_range(surf);
1381 19 : return ext3d;
1382 : }
1383 :
1384 :
1385 :
1386 326 : GF_Err gf_evg_surface_set_fragment_shader(GF_EVGSurface *surf, gf_evg_fragment_shader shader, void *shader_udta)
1387 : {
1388 326 : if (!surf || !surf->ext3d) return GF_BAD_PARAM;
1389 326 : surf->ext3d->frag_shader = shader;
1390 326 : surf->ext3d->frag_shader_udta = shader_udta;
1391 326 : return GF_OK;
1392 : }
1393 :
1394 326 : GF_Err gf_evg_surface_disable_early_depth(GF_EVGSurface *surf, Bool disable)
1395 : {
1396 326 : if (!surf || !surf->ext3d) return GF_BAD_PARAM;
1397 326 : surf->ext3d->early_depth_test = !disable;
1398 326 : return GF_OK;
1399 : }
1400 :
1401 225 : GF_Err gf_evg_surface_set_vertex_shader(GF_EVGSurface *surf, gf_evg_vertex_shader shader, void *shader_udta)
1402 : {
1403 225 : if (!surf || !surf->ext3d) return GF_BAD_PARAM;
1404 225 : surf->ext3d->vert_shader = shader;
1405 225 : surf->ext3d->vert_shader_udta = shader_udta;
1406 225 : return GF_OK;
1407 : }
1408 :
1409 10 : GF_Err gf_evg_surface_set_ccw(GF_EVGSurface *surf, Bool is_ccw)
1410 : {
1411 10 : if (!surf || !surf->ext3d) return GF_BAD_PARAM;
1412 10 : surf->ext3d->is_ccw = is_ccw;
1413 10 : return GF_OK;
1414 : }
1415 226 : GF_Err gf_evg_surface_set_backcull(GF_EVGSurface *surf, Bool backcull)
1416 : {
1417 226 : if (!surf || !surf->ext3d) return GF_BAD_PARAM;
1418 226 : surf->ext3d->backface_cull = backcull;
1419 226 : return GF_OK;
1420 : }
1421 226 : GF_Err gf_evg_surface_set_antialias(GF_EVGSurface *surf, Bool antialias)
1422 : {
1423 226 : if (!surf || !surf->ext3d) return GF_BAD_PARAM;
1424 226 : surf->ext3d->disable_aa = antialias ? GF_FALSE : GF_TRUE;
1425 226 : return GF_OK;
1426 : }
1427 10 : GF_Err gf_evg_surface_set_min_depth(GF_EVGSurface *surf, Float min_depth)
1428 : {
1429 10 : if (!surf || !surf->ext3d) return GF_BAD_PARAM;
1430 10 : surf->ext3d->min_depth = min_depth;
1431 10 : evg_3d_update_depth_range(surf);
1432 10 : return GF_OK;
1433 : }
1434 10 : GF_Err gf_evg_surface_set_max_depth(GF_EVGSurface *surf, Float max_depth)
1435 : {
1436 10 : if (!surf || !surf->ext3d) return GF_BAD_PARAM;
1437 10 : surf->ext3d->max_depth = max_depth;
1438 10 : evg_3d_update_depth_range(surf);
1439 10 : return GF_OK;
1440 : }
1441 :
1442 125 : GF_Err gf_evg_surface_set_clip_zero(GF_EVGSurface *surf, Bool clip_zero)
1443 : {
1444 125 : if (!surf || !surf->ext3d) return GF_BAD_PARAM;
1445 125 : surf->ext3d->clip_zero = clip_zero;
1446 125 : evg_3d_update_depth_range(surf);
1447 125 : return GF_OK;
1448 : }
1449 :
1450 10 : GF_Err gf_evg_surface_set_point_size(GF_EVGSurface *surf, Float size)
1451 : {
1452 10 : if (!surf || !surf->ext3d) return GF_BAD_PARAM;
1453 10 : surf->ext3d->point_size = size;
1454 10 : return GF_OK;
1455 : }
1456 10 : GF_Err gf_evg_surface_set_line_size(GF_EVGSurface *surf, Float size)
1457 : {
1458 10 : if (!surf || !surf->ext3d) return GF_BAD_PARAM;
1459 10 : surf->ext3d->line_size = size;
1460 10 : return GF_OK;
1461 : }
1462 10 : GF_Err gf_evg_surface_set_point_smooth(GF_EVGSurface *surf, Bool smooth)
1463 : {
1464 10 : if (!surf || !surf->ext3d) return GF_BAD_PARAM;
1465 10 : surf->ext3d->smooth_points = smooth;
1466 10 : return GF_OK;
1467 : }
1468 :
1469 10 : GF_Err gf_evg_surface_write_depth(GF_EVGSurface *surf, Bool do_write)
1470 : {
1471 10 : if (!surf || !surf->ext3d) return GF_BAD_PARAM;
1472 10 : surf->ext3d->write_depth = do_write;
1473 10 : return GF_OK;
1474 : }
1475 19 : GF_Err gf_evg_surface_set_depth_buffer(GF_EVGSurface *surf, Float *depth)
1476 : {
1477 19 : if (!surf || !surf->ext3d) return GF_BAD_PARAM;
1478 19 : surf->ext3d->depth_buffer = depth;
1479 19 : return GF_OK;
1480 : }
|