00001
00002
00003
00004
00005
00006
00007
00008 #ifndef __SP_MATH_RASTERIZER_H__
00009 #define __SP_MATH_RASTERIZER_H__
00010
00011
00012 #include "Base/spStandard.hpp"
00013 #include "Base/spMath.hpp"
00014
00015 #include <boost/function.hpp>
00016
00017
00018 namespace sp
00019 {
00020 namespace math
00021 {
00022
00023
00025 typedef boost::function<void (s32 x, s32 y, void* UserData)> RenderPixelCallback;
00026
00027
00034 class SP_EXPORT RasterizerVertex
00035 {
00036
00037 public:
00038
00039 RasterizerVertex()
00040 {
00041 }
00042 virtual ~RasterizerVertex()
00043 {
00044 }
00045
00046
00047
00048 virtual RasterizerVertex& operator = (const RasterizerVertex &Other) = 0;
00049
00050 virtual RasterizerVertex& operator += (const RasterizerVertex &Other) = 0;
00051 virtual RasterizerVertex& operator -= (const RasterizerVertex &Other) = 0;
00052
00053 virtual RasterizerVertex& operator *= (f32 Factor) = 0;
00054 virtual RasterizerVertex& operator /= (f32 Factor) = 0;
00055
00056
00057
00059 virtual s32 getScreenCoordX() const = 0;
00061 virtual s32 getScreenCoordY() const = 0;
00062
00063 };
00064
00065
00067 namespace Rasterizer
00068 {
00069
00071 template <class VtxT> void computeRasterScanline(
00072 const VtxT* (&v)[3], s32 y, s32 yStart, s32 yMiddle, VtxT &a, VtxT &b)
00073 {
00074
00075 f32 dy = static_cast<f32>(y - yStart);
00076
00077
00078 f32 Factor = dy / (v[2]->getScreenCoordY() - v[0]->getScreenCoordY());
00079
00080
00081 math::Lerp(a, *v[0], *v[2], Factor);
00082
00083 if (y < yMiddle)
00084 {
00085
00086 Factor = dy / (v[1]->getScreenCoordY() - v[0]->getScreenCoordY());
00087
00088
00089 math::Lerp(b, *v[0], *v[1], Factor);
00090 }
00091 else
00092 {
00093
00094 dy = static_cast<f32>(y - yMiddle);
00095
00096
00097 Factor = dy / (v[2]->getScreenCoordY() - v[1]->getScreenCoordY());
00098
00099
00100 math::Lerp(b, *v[1], *v[2], Factor);
00101 }
00102 }
00103
00116 template <class VtxT> void rasterizeTriangle(
00117 const boost::function<void (s32 x, s32 y, const VtxT &Vertex, void* UserData)> &RenderPixelCallback,
00118 const VtxT &VertexA, const VtxT &VertexB, const VtxT &VertexC, void* UserData = 0)
00119 {
00120
00121 const VtxT* v[3] = { &VertexA, &VertexB, &VertexC };
00122
00123
00124 if (v[0]->getScreenCoordY() > v[1]->getScreenCoordY())
00125 Swap(v[0], v[1]);
00126 if (v[0]->getScreenCoordY() > v[2]->getScreenCoordY())
00127 Swap(v[0], v[2]);
00128 if (v[1]->getScreenCoordY() > v[2]->getScreenCoordY())
00129 Swap(v[1], v[2]);
00130
00131
00132 s32 v0x = v[0]->getScreenCoordX();
00133 s32 v1x = v[1]->getScreenCoordX();
00134 s32 v2x = v[2]->getScreenCoordX();
00135
00136
00137 s32 yStart = v[0]->getScreenCoordY();
00138 s32 yMiddle = v[1]->getScreenCoordY();
00139 s32 yEnd = v[2]->getScreenCoordY();
00140
00141
00142 s32 yMiddleStart = yMiddle - yStart;
00143 s32 yEndMiddle = yEnd - yMiddle;
00144 s32 yEndStart = yEnd - yStart;
00145
00146
00147 s32 x, y, xStart, xEnd;
00148 VtxT lside, rside, step, cur;
00149
00150
00151 for (y = yStart; y < yEnd; ++y)
00152 {
00153
00154 if (y < yMiddle)
00155 xStart = v0x + ( v1x - v0x ) * ( y - yStart ) / yMiddleStart;
00156 else if (y > yMiddle)
00157 xStart = v1x + ( v2x - v1x ) * ( y - yMiddle ) / yEndMiddle;
00158 else
00159 xStart = v1x;
00160
00161 xEnd = v0x + ( v2x - v0x ) * ( y - yStart ) / yEndStart;
00162
00163
00164 if (xStart > xEnd)
00165 {
00166 math::Swap(xStart, xEnd);
00167 computeRasterScanline(v, y, yStart, yMiddle, lside, rside);
00168 }
00169 else
00170 computeRasterScanline(v, y, yStart, yMiddle, rside, lside);
00171
00172
00173 f32 dx = static_cast<f32>(xEnd - xStart);
00174
00175 step = rside;
00176 step -= lside;
00177 step /= dx;
00178
00179 cur = lside;
00180
00181
00182 for (x = xStart; x < xEnd; ++x)
00183 {
00184 RenderPixelCallback(x, y, cur, UserData);
00185
00186
00187 cur += step;
00188 }
00189 }
00190 }
00191
00203 template <class VtxT> void rasterizeLine(
00204 const boost::function<void (s32 x, s32 y, const VtxT &Vertex, void* UserData)> &RenderPixelCallback,
00205 const VtxT &VertexA, const VtxT &VertexB, void* UserData = 0)
00206 {
00207
00208 s32 x1 = VertexA.getScreenCoordX();
00209 s32 y1 = VertexA.getScreenCoordY();
00210
00211 s32 x2 = VertexB.getScreenCoordX();
00212 s32 y2 = VertexB.getScreenCoordY();
00213
00214
00215 s32 dx = x2 - x1;
00216 s32 dy = y2 - y1;
00217
00218 s32 incx = (dx > 0) ? 1 : (dx < 0) ? -1 : 0;
00219 s32 incy = (dy > 0) ? 1 : (dy < 0) ? -1 : 0;
00220
00221 if (dx < 0) dx = -dx;
00222 if (dy < 0) dy = -dy;
00223
00224 s32 pdx, pdy, ddx, ddy, es, el;
00225
00226 if (dx > dy)
00227 {
00228 pdx = incx;
00229 pdy = 0;
00230 ddx = incx;
00231 ddy = incy;
00232 es = dy;
00233 el = dx;
00234 }
00235 else
00236 {
00237 pdx = 0;
00238 pdy = incy;
00239 ddx = incx;
00240 ddy = incy;
00241 es = dx;
00242 el = dy;
00243 }
00244
00245 if (el == 0)
00246 return;
00247
00248 s32 x = x1;
00249 s32 y = y1;
00250 s32 err = el/2;
00251
00252
00253 VtxT step, cur;
00254
00255 step = VertexB;
00256 step -= VertexA;
00257 step /= static_cast<f32>(el);
00258
00259 cur = VertexA;
00260
00261
00262 for (s32 t = 0; t < el; ++t)
00263 {
00264
00265 RenderPixelCallback(x, y, cur, UserData);
00266
00267 cur += step;
00268
00269
00270 err -= es;
00271 if (err < 0)
00272 {
00273 err += el;
00274 x += ddx;
00275 y += ddy;
00276 }
00277 else
00278 {
00279 x += pdx;
00280 y += pdy;
00281 }
00282 }
00283 }
00284
00296 SP_EXPORT void rasterizeTriangle(
00297 const RenderPixelCallback &RenderCallback,
00298 dim::point2di PointA, dim::point2di PointB, dim::point2di PointC,
00299 void* UserData = 0
00300 );
00301
00310 SP_EXPORT void rasterizeCircle(
00311 const RenderPixelCallback &RenderCallback, const dim::point2di &Position, s32 Radius, void* UserData = 0
00312 );
00313
00322 SP_EXPORT void rasterizeEllipse(
00323 const RenderPixelCallback &RenderCallback, const dim::point2di &Position, const dim::size2di &Radius, void* UserData = 0
00324 );
00325
00326 }
00327
00328
00329 }
00330
00331 }
00332
00333
00334 #endif
00335
00336
00337
00338