1 // Copyright (C) 2002-2012 Nikolaus Gebhardt
\r
2 // This file is part of the "Irrlicht Engine".
\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h
\r
5 #include "CTRTextureGouraud.h"
\r
7 #ifdef _IRR_COMPILE_WITH_SOFTWARE_
\r
15 CTRTextureGouraud::CTRTextureGouraud(IZBuffer* zbuffer)
\r
16 : RenderTarget(0), ZBuffer(zbuffer), SurfaceWidth(0), SurfaceHeight(0),
\r
17 BackFaceCullingEnabled(true), lockedZBuffer(0),
\r
18 lockedSurface(0), lockedTexture(0), lockedTextureWidth(0),
\r
19 textureXMask(0), textureYMask(0), Texture(0)
\r
22 setDebugName("CTRTextureGouraud");
\r
32 CTRTextureGouraud::~CTRTextureGouraud()
\r
35 RenderTarget->drop();
\r
46 //! sets the Texture
\r
47 void CTRTextureGouraud::setTexture(video::IImage* texture)
\r
57 lockedTextureWidth = Texture->getDimension().Width;
\r
59 textureXMask = lockedTextureWidth-1;
\r
60 textureYMask = Texture->getDimension().Height-1;
\r
67 //! en or disables the backface culling
\r
68 void CTRTextureGouraud::setBackfaceCulling(bool enabled)
\r
70 BackFaceCullingEnabled = enabled;
\r
75 //! sets a render target
\r
76 void CTRTextureGouraud::setRenderTarget(video::IImage* surface, const core::rect<s32>& viewPort)
\r
79 RenderTarget->drop();
\r
81 RenderTarget = surface;
\r
85 SurfaceWidth = RenderTarget->getDimension().Width;
\r
86 SurfaceHeight = RenderTarget->getDimension().Height;
\r
87 RenderTarget->grab();
\r
88 ViewPortRect = viewPort;
\r
94 //! draws an indexed triangle list
\r
95 void CTRTextureGouraud::drawIndexedTriangleList(S2DVertex* vertices, s32 vertexCount, const u16* indexList, s32 triangleCount)
\r
97 const S2DVertex *v1, *v2, *v3;
\r
99 f32 tmpDiv; // temporary division factor
\r
100 f32 longest; // saves the longest span
\r
101 s32 height; // saves height of triangle
\r
102 u16* targetSurface; // target pointer where to plot pixels
\r
103 s32 spanEnd; // saves end of spans
\r
104 f32 leftdeltaxf; // amount of pixels to increase on left side of triangle
\r
105 f32 rightdeltaxf; // amount of pixels to increase on right side of triangle
\r
106 s32 leftx, rightx; // position where we are
\r
107 f32 leftxf, rightxf; // same as above, but as f32 values
\r
108 s32 span; // current span
\r
109 u16 *hSpanBegin, *hSpanEnd; // pointer used when plotting pixels
\r
110 s32 leftR, leftG, leftB, rightR, rightG, rightB; // color values
\r
111 s32 leftStepR, leftStepG, leftStepB,
\r
112 rightStepR, rightStepG, rightStepB; // color steps
\r
113 s32 spanR, spanG, spanB, spanStepR, spanStepG, spanStepB; // color interpolating values while drawing a span.
\r
114 s32 leftTx, rightTx, leftTy, rightTy; // texture interpolating values
\r
115 s32 leftTxStep, rightTxStep, leftTyStep, rightTyStep; // texture interpolating values
\r
116 s32 spanTx, spanTy, spanTxStep, spanTyStep; // values of Texturecoords when drawing a span
\r
117 core::rect<s32> TriangleRect;
\r
119 s32 leftZValue, rightZValue;
\r
120 s32 leftZStep, rightZStep;
\r
121 s32 spanZValue, spanZStep; // ZValues when drawing a span
\r
122 TZBufferType* zTarget, *spanZTarget; // target of ZBuffer;
\r
124 lockedSurface = (u16*)RenderTarget->getData();
\r
125 lockedZBuffer = ZBuffer->lock();
\r
126 lockedTexture = (u16*)Texture->getData();
\r
128 for (s32 i=0; i<triangleCount; ++i)
\r
130 v1 = &vertices[*indexList];
\r
132 v2 = &vertices[*indexList];
\r
134 v3 = &vertices[*indexList];
\r
137 // back face culling
\r
139 if (BackFaceCullingEnabled)
\r
141 s32 z = ((v3->Pos.X - v1->Pos.X) * (v3->Pos.Y - v2->Pos.Y)) -
\r
142 ((v3->Pos.Y - v1->Pos.Y) * (v3->Pos.X - v2->Pos.X));
\r
148 //near plane clipping
\r
150 if (v1->ZValue<0 && v2->ZValue<0 && v3->ZValue<0)
\r
153 // sort for width for inscreen clipping
\r
155 if (v1->Pos.X > v2->Pos.X) swapVertices(&v1, &v2);
\r
156 if (v1->Pos.X > v3->Pos.X) swapVertices(&v1, &v3);
\r
157 if (v2->Pos.X > v3->Pos.X) swapVertices(&v2, &v3);
\r
159 if ((v1->Pos.X - v3->Pos.X) == 0)
\r
162 TriangleRect.UpperLeftCorner.X = v1->Pos.X;
\r
163 TriangleRect.LowerRightCorner.X = v3->Pos.X;
\r
165 // sort for height for faster drawing.
\r
167 if (v1->Pos.Y > v2->Pos.Y) swapVertices(&v1, &v2);
\r
168 if (v1->Pos.Y > v3->Pos.Y) swapVertices(&v1, &v3);
\r
169 if (v2->Pos.Y > v3->Pos.Y) swapVertices(&v2, &v3);
\r
171 TriangleRect.UpperLeftCorner.Y = v1->Pos.Y;
\r
172 TriangleRect.LowerRightCorner.Y = v3->Pos.Y;
\r
174 if (!TriangleRect.isRectCollided(ViewPortRect))
\r
177 // calculate height of triangle
\r
178 height = v3->Pos.Y - v1->Pos.Y;
\r
182 // calculate longest span
\r
184 longest = (v2->Pos.Y - v1->Pos.Y) / (f32)height * (v3->Pos.X - v1->Pos.X) + (v1->Pos.X - v2->Pos.X);
\r
186 spanEnd = v2->Pos.Y;
\r
188 leftxf = (f32)v1->Pos.X;
\r
189 rightxf = (f32)v1->Pos.X;
\r
191 leftZValue = v1->ZValue;
\r
192 rightZValue = v1->ZValue;
\r
194 leftR = rightR = video::getRed(v1->Color)<<8;
\r
195 leftG = rightG = video::getGreen(v1->Color)<<8;
\r
196 leftB = rightB = video::getBlue(v1->Color)<<8;
\r
197 leftTx = rightTx = v1->TCoords.X;
\r
198 leftTy = rightTy = v1->TCoords.Y;
\r
200 targetSurface = lockedSurface + span * SurfaceWidth;
\r
201 zTarget = lockedZBuffer + span * SurfaceWidth;
\r
203 if (longest < 0.0f)
\r
205 tmpDiv = 1.0f / (f32)(v2->Pos.Y - v1->Pos.Y);
\r
206 rightdeltaxf = (v2->Pos.X - v1->Pos.X) * tmpDiv;
\r
207 rightZStep = (s32)((v2->ZValue - v1->ZValue) * tmpDiv);
\r
208 rightStepR = (s32)(((s32)(video::getRed(v2->Color)<<8) - rightR) * tmpDiv);
\r
209 rightStepG = (s32)(((s32)(video::getGreen(v2->Color)<<8) - rightG) * tmpDiv);
\r
210 rightStepB = (s32)(((s32)(video::getBlue(v2->Color)<<8) - rightB) * tmpDiv);
\r
211 rightTxStep = (s32)((v2->TCoords.X - rightTx) * tmpDiv);
\r
212 rightTyStep = (s32)((v2->TCoords.Y - rightTy) * tmpDiv);
\r
214 tmpDiv = 1.0f / (f32)height;
\r
215 leftdeltaxf = (v3->Pos.X - v1->Pos.X) * tmpDiv;
\r
216 leftZStep = (s32)((v3->ZValue - v1->ZValue) * tmpDiv);
\r
217 leftStepR = (s32)(((s32)(video::getRed(v3->Color)<<8) - leftR) * tmpDiv);
\r
218 leftStepG = (s32)(((s32)(video::getGreen(v3->Color)<<8) - leftG) * tmpDiv);
\r
219 leftStepB = (s32)(((s32)(video::getBlue(v3->Color)<<8) - leftB) * tmpDiv);
\r
220 leftTxStep = (s32)((v3->TCoords.X - leftTx) * tmpDiv);
\r
221 leftTyStep = (s32)((v3->TCoords.Y - leftTy) * tmpDiv);
\r
225 tmpDiv = 1.0f / (f32)height;
\r
226 rightdeltaxf = (v3->Pos.X - v1->Pos.X) * tmpDiv;
\r
227 rightZStep = (s32)((v3->ZValue - v1->ZValue) * tmpDiv);
\r
228 rightStepR = (s32)(((s32)(video::getRed(v3->Color)<<8) - rightR) * tmpDiv);
\r
229 rightStepG = (s32)(((s32)(video::getGreen(v3->Color)<<8) - rightG) * tmpDiv);
\r
230 rightStepB = (s32)(((s32)(video::getBlue(v3->Color)<<8) - rightB) * tmpDiv);
\r
231 rightTxStep = (s32)((v3->TCoords.X - rightTx) * tmpDiv);
\r
232 rightTyStep = (s32)((v3->TCoords.Y - rightTy) * tmpDiv);
\r
234 tmpDiv = 1.0f / (f32)(v2->Pos.Y - v1->Pos.Y);
\r
235 leftdeltaxf = (v2->Pos.X - v1->Pos.X) * tmpDiv;
\r
236 leftZStep = (s32)((v2->ZValue - v1->ZValue) * tmpDiv);
\r
237 leftStepR = (s32)(((s32)(video::getRed(v2->Color)<<8) - leftR) * tmpDiv);
\r
238 leftStepG = (s32)(((s32)(video::getGreen(v2->Color)<<8) - leftG) * tmpDiv);
\r
239 leftStepB = (s32)(((s32)(video::getBlue(v2->Color)<<8) - leftB) * tmpDiv);
\r
240 leftTxStep = (s32)((v2->TCoords.X - leftTx) * tmpDiv);
\r
241 leftTyStep = (s32)((v2->TCoords.Y - leftTy) * tmpDiv);
\r
245 // do it twice, once for the first half of the triangle,
\r
246 // end then for the second half.
\r
248 for (s32 triangleHalf=0; triangleHalf<2; ++triangleHalf)
\r
250 if (spanEnd > ViewPortRect.LowerRightCorner.Y)
\r
251 spanEnd = ViewPortRect.LowerRightCorner.Y;
\r
253 // if the span <0, than we can skip these spans,
\r
254 // and proceed to the next spans which are really on the screen.
\r
255 if (span < ViewPortRect.UpperLeftCorner.Y)
\r
257 // we'll use leftx as temp variable
\r
258 if (spanEnd < ViewPortRect.UpperLeftCorner.Y)
\r
260 leftx = spanEnd - span;
\r
265 leftx = ViewPortRect.UpperLeftCorner.Y - span;
\r
266 span = ViewPortRect.UpperLeftCorner.Y;
\r
269 leftxf += leftdeltaxf*leftx;
\r
270 rightxf += rightdeltaxf*leftx;
\r
271 targetSurface += SurfaceWidth*leftx;
\r
272 zTarget += SurfaceWidth*leftx;
\r
273 leftZValue += leftZStep*leftx;
\r
274 rightZValue += rightZStep*leftx;
\r
276 leftR += leftStepR*leftx;
\r
277 leftG += leftStepG*leftx;
\r
278 leftB += leftStepB*leftx;
\r
279 rightR += rightStepR*leftx;
\r
280 rightG += rightStepG*leftx;
\r
281 rightB += rightStepB*leftx;
\r
283 leftTx += leftTxStep*leftx;
\r
284 leftTy += leftTyStep*leftx;
\r
285 rightTx += rightTxStep*leftx;
\r
286 rightTy += rightTyStep*leftx;
\r
290 // the main loop. Go through every span and draw it.
\r
292 while (span < spanEnd)
\r
294 leftx = (s32)(leftxf);
\r
295 rightx = (s32)(rightxf + 0.5f);
\r
297 // perform some clipping
\r
298 // thanks to a correction by hybrid
\r
299 // calculations delayed to correctly propagate to textures etc.
\r
300 s32 tDiffLeft=0, tDiffRight=0;
\r
301 if (leftx<ViewPortRect.UpperLeftCorner.X)
\r
302 tDiffLeft=ViewPortRect.UpperLeftCorner.X-leftx;
\r
304 if (leftx>ViewPortRect.LowerRightCorner.X)
\r
305 tDiffLeft=ViewPortRect.LowerRightCorner.X-leftx;
\r
307 if (rightx<ViewPortRect.UpperLeftCorner.X)
\r
308 tDiffRight=ViewPortRect.UpperLeftCorner.X-rightx;
\r
310 if (rightx>ViewPortRect.LowerRightCorner.X)
\r
311 tDiffRight=ViewPortRect.LowerRightCorner.X-rightx;
\r
314 if (rightx + tDiffRight - leftx - tDiffLeft)
\r
316 tmpDiv = 1.0f / (f32)(rightx - leftx);
\r
317 spanZStep = (s32)((rightZValue - leftZValue) * tmpDiv);
\r
318 spanZValue = leftZValue+tDiffLeft*spanZStep;
\r
320 spanStepR = (s32)((rightR - leftR) * tmpDiv);
\r
321 spanR = leftR+tDiffLeft*spanStepR;
\r
322 spanStepG = (s32)((rightG - leftG) * tmpDiv);
\r
323 spanG = leftG+tDiffLeft*spanStepG;
\r
324 spanStepB = (s32)((rightB - leftB) * tmpDiv);
\r
325 spanB = leftB+tDiffLeft*spanStepB;
\r
327 spanTxStep = (s32)((rightTx - leftTx) * tmpDiv);
\r
328 spanTx = leftTx + tDiffLeft*spanTxStep;
\r
329 spanTyStep = (s32)((rightTy - leftTy) * tmpDiv);
\r
330 spanTy = leftTy+tDiffLeft*spanTyStep;
\r
332 hSpanBegin = targetSurface + leftx+tDiffLeft;
\r
333 spanZTarget = zTarget + leftx+tDiffLeft;
\r
334 hSpanEnd = targetSurface + rightx+tDiffRight;
\r
336 while (hSpanBegin < hSpanEnd)
\r
338 if (spanZValue > *spanZTarget)
\r
340 *spanZTarget = spanZValue;
\r
341 u16 color = lockedTexture[((spanTy>>8)&textureYMask) * lockedTextureWidth + ((spanTx>>8)&textureXMask)];
\r
342 *hSpanBegin = video::RGB16(video::getRed(color) * (spanR>>8) >>2,
\r
343 video::getGreen(color) * (spanG>>8) >>2,
\r
344 video::getBlue(color) * (spanB>>8) >>2);
\r
347 spanR += spanStepR;
\r
348 spanG += spanStepG;
\r
349 spanB += spanStepB;
\r
351 spanTx += spanTxStep;
\r
352 spanTy += spanTyStep;
\r
354 spanZValue += spanZStep;
\r
360 leftxf += leftdeltaxf;
\r
361 rightxf += rightdeltaxf;
\r
363 targetSurface += SurfaceWidth;
\r
364 zTarget += SurfaceWidth;
\r
365 leftZValue += leftZStep;
\r
366 rightZValue += rightZStep;
\r
368 leftR += leftStepR;
\r
369 leftG += leftStepG;
\r
370 leftB += leftStepB;
\r
371 rightR += rightStepR;
\r
372 rightG += rightStepG;
\r
373 rightB += rightStepB;
\r
375 leftTx += leftTxStep;
\r
376 leftTy += leftTyStep;
\r
377 rightTx += rightTxStep;
\r
378 rightTy += rightTyStep;
\r
381 if (triangleHalf>0) // break, we've gout only two halves
\r
385 // setup variables for second half of the triangle.
\r
387 if (longest < 0.0f)
\r
389 tmpDiv = 1.0f / (v3->Pos.Y - v2->Pos.Y);
\r
391 rightdeltaxf = (v3->Pos.X - v2->Pos.X) * tmpDiv;
\r
392 rightxf = (f32)v2->Pos.X;
\r
394 rightZValue = v2->ZValue;
\r
395 rightZStep = (s32)((v3->ZValue - v2->ZValue) * tmpDiv);
\r
397 rightR = video::getRed(v2->Color)<<8;
\r
398 rightG = video::getGreen(v2->Color)<<8;
\r
399 rightB = video::getBlue(v2->Color)<<8;
\r
400 rightStepR = (s32)(((s32)(video::getRed(v3->Color)<<8) - rightR) * tmpDiv);
\r
401 rightStepG = (s32)(((s32)(video::getGreen(v3->Color)<<8) - rightG) * tmpDiv);
\r
402 rightStepB = (s32)(((s32)(video::getBlue(v3->Color)<<8) - rightB) * tmpDiv);
\r
404 rightTx = v2->TCoords.X;
\r
405 rightTy = v2->TCoords.Y;
\r
406 rightTxStep = (s32)((v3->TCoords.X - rightTx) * tmpDiv);
\r
407 rightTyStep = (s32)((v3->TCoords.Y - rightTy) * tmpDiv);
\r
411 tmpDiv = 1.0f / (v3->Pos.Y - v2->Pos.Y);
\r
413 leftdeltaxf = (v3->Pos.X - v2->Pos.X) * tmpDiv;
\r
414 leftxf = (f32)v2->Pos.X;
\r
416 leftZValue = v2->ZValue;
\r
417 leftZStep = (s32)((v3->ZValue - v2->ZValue) * tmpDiv);
\r
419 leftR = video::getRed(v2->Color)<<8;
\r
420 leftG = video::getGreen(v2->Color)<<8;
\r
421 leftB = video::getBlue(v2->Color)<<8;
\r
422 leftStepR = (s32)(((s32)(video::getRed(v3->Color)<<8) - leftR) * tmpDiv);
\r
423 leftStepG = (s32)(((s32)(video::getGreen(v3->Color)<<8) - leftG) * tmpDiv);
\r
424 leftStepB = (s32)(((s32)(video::getBlue(v3->Color)<<8) - leftB) * tmpDiv);
\r
426 leftTx = v2->TCoords.X;
\r
427 leftTy = v2->TCoords.Y;
\r
428 leftTxStep = (s32)((v3->TCoords.X - leftTx) * tmpDiv);
\r
429 leftTyStep = (s32)((v3->TCoords.Y - leftTy) * tmpDiv);
\r
433 spanEnd = v3->Pos.Y;
\r
442 } // end namespace video
\r
443 } // end namespace irr
\r
445 #endif // _IRR_COMPILE_WITH_SOFTWARE_
\r
452 //! creates a flat triangle renderer
\r
453 ITriangleRenderer* createTriangleRendererTextureGouraud(IZBuffer* zbuffer)
\r
455 #ifdef _IRR_COMPILE_WITH_SOFTWARE_
\r
456 return new CTRTextureGouraud(zbuffer);
\r
459 #endif // _IRR_COMPILE_WITH_SOFTWARE_
\r
463 } // end namespace video
\r
464 } // end namespace irr
\r