📄 trap.cpp
字号:
ny = gglMulx(ny, norm, 21); v[2][0] = v1[0]; v[2][1] = v1[1]; v[3][0] = v0[0]; v[3][1] = v0[1]; v[0][0] += nx; v[0][1] += ny; v[1][0] += nx; v[1][1] += ny; v[2][0] -= nx; v[2][1] -= ny; v[3][0] -= nx; v[3][1] -= ny; aapolyx(con, v[0], 4); }// ----------------------------------------------------------------------------#if 0#pragma mark -#pragma mark Rect#endifvoid recti_validate(void *con, GGLint l, GGLint t, GGLint r, GGLint b){ GGL_CONTEXT(c, con); ggl_pick(c); c->procs.recti = recti; c->procs.recti(con, l, t, r, b);}void recti(void* con, GGLint l, GGLint t, GGLint r, GGLint b){ GGL_CONTEXT(c, con); // scissor... if (l < GGLint(c->state.scissor.left)) l = GGLint(c->state.scissor.left); if (t < GGLint(c->state.scissor.top)) t = GGLint(c->state.scissor.top); if (r > GGLint(c->state.scissor.right)) r = GGLint(c->state.scissor.right); if (b > GGLint(c->state.scissor.bottom)) b = GGLint(c->state.scissor.bottom); int xc = r - l; int yc = b - t; if (xc>0 && yc>0) { c->iterators.xl = l; c->iterators.xr = r; c->init_y(c, t); c->rect(c, yc); }}// ----------------------------------------------------------------------------#if 0#pragma mark -#pragma mark Triangle / Debugging#endifstatic void scanline_set(context_t* c){ int32_t x = c->iterators.xl; size_t ct = c->iterators.xr - x; int32_t y = c->iterators.y; surface_t* cb = &(c->state.buffers.color); const GGLFormat* fp = &(c->formats[cb->format]); uint8_t* dst = reinterpret_cast<uint8_t*>(cb->data) + (x + (cb->stride * y)) * fp->size; const size_t size = ct * fp->size; memset(dst, 0xFF, size);}static void trianglex_debug(void* con, const GGLcoord* v0, const GGLcoord* v1, const GGLcoord* v2){ GGL_CONTEXT(c, con); if (c->state.needs.p & GGL_NEED_MASK(P_AA)) { aa_trianglex(con,v0,v1,v2); } else { trianglex_big(con,v0,v1,v2); } void (*save_scanline)(context_t*) = c->scanline; c->scanline = scanline_set; linex(con, v0, v1, TRI_ONE); linex(con, v1, v2, TRI_ONE); linex(con, v2, v0, TRI_ONE); c->scanline = save_scanline;}static void trianglex_xor(void* con, const GGLcoord* v0, const GGLcoord* v1, const GGLcoord* v2){ trianglex_big(con,v0,v1,v2); trianglex_small(con,v0,v1,v2);}// ----------------------------------------------------------------------------#if 0#pragma mark -#pragma mark Triangle#endifvoid trianglex_validate(void *con, const GGLcoord* v0, const GGLcoord* v1, const GGLcoord* v2){ GGL_CONTEXT(c, con); ggl_pick(c); if (c->state.needs.p & GGL_NEED_MASK(P_AA)) { c->procs.trianglex = DEBUG_TRANGLES ? trianglex_debug : aa_trianglex; } else { c->procs.trianglex = DEBUG_TRANGLES ? trianglex_debug : trianglex_big; } c->procs.trianglex(con, v0, v1, v2);}// ----------------------------------------------------------------------------void trianglex_small(void* con, const GGLcoord* v0, const GGLcoord* v1, const GGLcoord* v2){ GGL_CONTEXT(c, con); // vertices are in 28.4 fixed point, which allows // us to use 32 bits multiplies below. int32_t x0 = v0[0]; int32_t y0 = v0[1]; int32_t x1 = v1[0]; int32_t y1 = v1[1]; int32_t x2 = v2[0]; int32_t y2 = v2[1]; int32_t dx01 = x0 - x1; int32_t dy20 = y2 - y0; int32_t dy01 = y0 - y1; int32_t dx20 = x2 - x0; // The code below works only with CCW triangles // so if we get a CW triangle, we need to swap two of its vertices if (dx01*dy20 < dy01*dx20) { swap(x0, x1); swap(y0, y1); dx01 = x0 - x1; dy01 = y0 - y1; dx20 = x2 - x0; dy20 = y2 - y0; } int32_t dx12 = x1 - x2; int32_t dy12 = y1 - y2; // bounding box & scissor const int32_t bminx = TRI_FLOOR(min(x0, x1, x2)) >> TRI_FRACTION_BITS; const int32_t bminy = TRI_FLOOR(min(y0, y1, y2)) >> TRI_FRACTION_BITS; const int32_t bmaxx = TRI_CEIL( max(x0, x1, x2)) >> TRI_FRACTION_BITS; const int32_t bmaxy = TRI_CEIL( max(y0, y1, y2)) >> TRI_FRACTION_BITS; const int32_t minx = max(bminx, c->state.scissor.left); const int32_t miny = max(bminy, c->state.scissor.top); const int32_t maxx = min(bmaxx, c->state.scissor.right); const int32_t maxy = min(bmaxy, c->state.scissor.bottom); if ((minx >= maxx) || (miny >= maxy)) return; // too small or clipped out... // step equations to the bounding box and snap to pixel center const int32_t my = (miny << TRI_FRACTION_BITS) + TRI_HALF; const int32_t mx = (minx << TRI_FRACTION_BITS) + TRI_HALF; int32_t ey0 = dy01 * (x0 - mx) - dx01 * (y0 - my); int32_t ey1 = dy12 * (x1 - mx) - dx12 * (y1 - my); int32_t ey2 = dy20 * (x2 - mx) - dx20 * (y2 - my); // right-exclusive fill rule, to avoid rare cases // of over drawing if (dy01<0 || (dy01 == 0 && dx01>0)) ey0++; if (dy12<0 || (dy12 == 0 && dx12>0)) ey1++; if (dy20<0 || (dy20 == 0 && dx20>0)) ey2++; c->init_y(c, miny); for (int32_t y = miny; y < maxy; y++) { register int32_t ex0 = ey0; register int32_t ex1 = ey1; register int32_t ex2 = ey2; register int32_t xl, xr; for (xl=minx ; xl<maxx ; xl++) { if (ex0>0 && ex1>0 && ex2>0) break; // all strictly positive ex0 -= dy01 << TRI_FRACTION_BITS; ex1 -= dy12 << TRI_FRACTION_BITS; ex2 -= dy20 << TRI_FRACTION_BITS; } xr = xl; for ( ; xr<maxx ; xr++) { if (!(ex0>0 && ex1>0 && ex2>0)) break; // not all strictly positive ex0 -= dy01 << TRI_FRACTION_BITS; ex1 -= dy12 << TRI_FRACTION_BITS; ex2 -= dy20 << TRI_FRACTION_BITS; } if (xl < xr) { c->iterators.xl = xl; c->iterators.xr = xr; c->scanline(c); } c->step_y(c); ey0 += dx01 << TRI_FRACTION_BITS; ey1 += dx12 << TRI_FRACTION_BITS; ey2 += dx20 << TRI_FRACTION_BITS; }}// ----------------------------------------------------------------------------#if 0#pragma mark -#endif// the following routine fills a triangle via edge stepping, which// unfortunately requires divisions in the setup phase to get right,// it should probably only be used for relatively large trianges// x = y*DX/DY (ou DX and DY are constants, DY > 0, et y >= 0)// // for an equation of the type:// x' = y*K/2^p (with K and p constants "carefully chosen")// // We can now do a DDA without precision loss. We define 'e' by:// x' - x = y*(DX/DY - K/2^p) = y*e// // If we choose K = round(DX*2^p/DY) then,// abs(e) <= 1/2^(p+1) by construction// // therefore abs(x'-x) = y*abs(e) <= y/2^(p+1) <= DY/2^(p+1) <= DMAX/2^(p+1)// // which means that if DMAX <= 2^p, therefore abs(x-x') <= 1/2, including// at the last line. In fact, it's even a strict inequality except in one// extrem case (DY == DMAX et e = +/- 1/2)// // Applying that to our coordinates, we need 2^p >= 4096*16 = 65536// so p = 16 is enough, we're so lucky!const int TRI_ITERATORS_BITS = 16;struct Edge{ int32_t x; // edge position in 16.16 coordinates int32_t x_incr; // on each step, increment x by that amount int32_t y_top; // starting scanline, 16.4 format int32_t y_bot;};static voidedge_dump( Edge* edge ){ LOGI( " top=%d (%.3f) bot=%d (%.3f) x=%d (%.3f) ix=%d (%.3f)", edge->y_top, edge->y_top/float(TRI_ONE), edge->y_bot, edge->y_bot/float(TRI_ONE), edge->x, edge->x/float(FIXED_ONE), edge->x_incr, edge->x_incr/float(FIXED_ONE) );}static voidtriangle_dump_edges( Edge* edges, int count ){ LOGI( "%d edge%s:\n", count, count == 1 ? "" : "s" ); for ( ; count > 0; count--, edges++ ) edge_dump( edges );}// the following function sets up an edge, it assumes// that ymin and ymax are in already in the 'reduced'// formatstatic __attribute__((noinline))void edge_setup( Edge* edges, int* pcount, const GGLcoord* p1, const GGLcoord* p2, int32_t ymin, int32_t ymax ){ const GGLfixed* top = p1; const GGLfixed* bot = p2; Edge* edge = edges + *pcount; if (top[1] > bot[1]) { swap(top, bot); } int y1 = top[1] | 1; int y2 = bot[1] | 1; int dy = y2 - y1; if ( dy == 0 || y1 > ymax || y2 < ymin ) return; if ( y1 > ymin ) ymin = TRI_SNAP_NEXT_HALF(y1); if ( y2 < ymax ) ymax = TRI_SNAP_PREV_HALF(y2); if ( ymin > ymax ) // when the edge doesn't cross any scanline return; const int x1 = top[0]; const int dx = bot[0] - x1; const int shift = TRI_ITERATORS_BITS - TRI_FRACTION_BITS; // setup edge fields // We add 0.5 to edge->x here because it simplifies the rounding // in triangle_sweep_edges() -- this doesn't change the ordering of 'x' edge->x = (x1 << shift) + (1LU << (TRI_ITERATORS_BITS-1)); edge->x_incr = 0; edge->y_top = ymin; edge->y_bot = ymax; if (ggl_likely(ymin <= ymax && dx)) { edge->x_incr = gglDivQ16(dx, dy); } if (ggl_likely(y1 < ymin)) { int32_t xadjust = (edge->x_incr * (ymin-y1)) >> TRI_FRACTION_BITS; edge->x += xadjust; } ++*pcount;}static voidtriangle_sweep_edges( Edge* left, Edge* right, int ytop, int ybot, context_t* c ){ int count = ((ybot - ytop)>>TRI_FRACTION_BITS) + 1; if (count<=0) return; // sort the edges horizontally if ((left->x > right->x) || ((left->x == right->x) && (left->x_incr > right->x_incr))) { swap(left, right); } int left_x = left->x; int right_x = right->x; const int left_xi = left->x_incr; const int right_xi = right->x_incr; left->x += left_xi * count; right->x += right_xi * count; const int xmin = c->state.scissor.left; const int xmax = c->state.scissor.right; do { // horizontal scissoring const int32_t xl = max(left_x >> TRI_ITERATORS_BITS, xmin); const int32_t xr = min(right_x >> TRI_ITERATORS_BITS, xmax); left_x += left_xi; right_x += right_xi; // invoke the scanline rasterizer if (ggl_likely(xl < xr)) { c->iterators.xl = xl; c->iterators.xr = xr; c->scanline(c); } c->step_y(c); } while (--count);}void trianglex_big(void* con, const GGLcoord* v0, const GGLcoord* v1, const GGLcoord* v2){ GGL_CONTEXT(c, con); Edge edges[3]; int num_edges = 0; int32_t ymin = TRI_FROM_INT(c->state.scissor.top) + TRI_HALF; int32_t ymax = TRI_FROM_INT(c->state.scissor.bottom) - TRI_HALF; edge_setup( edges, &num_edges, v0, v1, ymin, ymax ); edge_setup( edges, &num_edges, v0, v2, ymin, ymax ); edge_setup( edges, &num_edges, v1, v2, ymin, ymax ); if (ggl_unlikely(num_edges<2)) // for really tiny triangles that don't return; // cross any scanline centers Edge* left = &edges[0]; Edge* right = &edges[1]; Edge* other = &edges[2]; int32_t y_top = min(left->y_top, right->y_top); int32_t y_bot = max(left->y_bot, right->y_bot); if (ggl_likely(num_edges==3)) { y_top = min(y_top, edges[2].y_top);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -