1 // Copyright (C) 2002-2012 Nikolaus Gebhardt
2 // This file is part of the "Irrlicht Engine".
3 // For conditions of distribution and use, see copyright notice in irrlicht.h
4 
5 #include "IrrCompileConfig.h"
6 #include "CTRTextureGouraud.h"
7 
8 #ifdef _IRR_COMPILE_WITH_SOFTWARE_
9 
10 namespace irr
11 {
12 namespace video
13 {
14 
15 class CTRTextureGouraudAdd : public CTRTextureGouraud
16 {
17 public:
18 
19 	//! constructor
20 	CTRTextureGouraudAdd(IZBuffer* zbuffer);
21 
22 	//! draws an indexed triangle list
23 	virtual void drawIndexedTriangleList(S2DVertex* vertices, s32 vertexCount, const u16* indexList, s32 triangleCount);
24 
25 protected:
26 
27 };
28 
29 //! constructor
CTRTextureGouraudAdd(IZBuffer * zbuffer)30 CTRTextureGouraudAdd::CTRTextureGouraudAdd(IZBuffer* zbuffer)
31 : CTRTextureGouraud(zbuffer)
32 {
33 	#ifdef _DEBUG
34 	setDebugName("CTRTextureGouraudAdd");
35 	#endif
36 }
37 
38 
39 //! draws an indexed triangle list
drawIndexedTriangleList(S2DVertex * vertices,s32 vertexCount,const u16 * indexList,s32 triangleCount)40 void CTRTextureGouraudAdd::drawIndexedTriangleList(S2DVertex* vertices, s32 vertexCount, const u16* indexList, s32 triangleCount)
41 {
42 	const S2DVertex *v1, *v2, *v3;
43 
44 	u16 color;
45 	f32 tmpDiv; // temporary division factor
46 	f32 longest; // saves the longest span
47 	s32 height; // saves height of triangle
48 	u16* targetSurface; // target pointer where to plot pixels
49 	s32 spanEnd; // saves end of spans
50 	f32 leftdeltaxf; // amount of pixels to increase on left side of triangle
51 	f32 rightdeltaxf; // amount of pixels to increase on right side of triangle
52 	s32 leftx, rightx; // position where we are
53 	f32 leftxf, rightxf; // same as above, but as f32 values
54 	s32 span; // current span
55 	u16 *hSpanBegin, *hSpanEnd; // pointer used when plotting pixels
56 	s32 leftR, leftG, leftB, rightR, rightG, rightB; // color values
57 	s32 leftStepR, leftStepG, leftStepB,
58 		rightStepR, rightStepG, rightStepB; // color steps
59 	s32 spanR, spanG, spanB, spanStepR, spanStepG, spanStepB; // color interpolating values while drawing a span.
60 	s32 leftTx, rightTx, leftTy, rightTy; // texture interpolating values
61 	s32 leftTxStep, rightTxStep, leftTyStep, rightTyStep; // texture interpolating values
62 	s32 spanTx, spanTy, spanTxStep, spanTyStep; // values of Texturecoords when drawing a span
63 	core::rect<s32> TriangleRect;
64 
65 	s32 leftZValue, rightZValue;
66 	s32 leftZStep, rightZStep;
67 	s32 spanZValue, spanZStep; // ZValues when drawing a span
68 	TZBufferType* zTarget, *spanZTarget; // target of ZBuffer;
69 
70 	lockedSurface = (u16*)RenderTarget->lock();
71 	lockedZBuffer = ZBuffer->lock();
72 	lockedTexture = (u16*)Texture->lock();
73 
74 	for (s32 i=0; i<triangleCount; ++i)
75 	{
76 		v1 = &vertices[*indexList];
77 		++indexList;
78 		v2 = &vertices[*indexList];
79 		++indexList;
80 		v3 = &vertices[*indexList];
81 		++indexList;
82 
83 		// back face culling
84 
85 		if (BackFaceCullingEnabled)
86 		{
87 			s32 z = ((v3->Pos.X - v1->Pos.X) * (v3->Pos.Y - v2->Pos.Y)) -
88 				((v3->Pos.Y - v1->Pos.Y) * (v3->Pos.X - v2->Pos.X));
89 
90 			if (z < 0)
91 				continue;
92 		}
93 
94 		//near plane clipping
95 
96 		if (v1->ZValue<0 && v2->ZValue<0 && v3->ZValue<0)
97 			continue;
98 
99 		// sort for width for inscreen clipping
100 
101 		if (v1->Pos.X > v2->Pos.X)	swapVertices(&v1, &v2);
102 		if (v1->Pos.X > v3->Pos.X)	swapVertices(&v1, &v3);
103 		if (v2->Pos.X > v3->Pos.X)	swapVertices(&v2, &v3);
104 
105 		if ((v1->Pos.X - v3->Pos.X) == 0)
106 			continue;
107 
108 		TriangleRect.UpperLeftCorner.X = v1->Pos.X;
109 		TriangleRect.LowerRightCorner.X = v3->Pos.X;
110 
111 		// sort for height for faster drawing.
112 
113 		if (v1->Pos.Y > v2->Pos.Y)	swapVertices(&v1, &v2);
114 		if (v1->Pos.Y > v3->Pos.Y)	swapVertices(&v1, &v3);
115 		if (v2->Pos.Y > v3->Pos.Y)	swapVertices(&v2, &v3);
116 
117 		TriangleRect.UpperLeftCorner.Y = v1->Pos.Y;
118 		TriangleRect.LowerRightCorner.Y = v3->Pos.Y;
119 
120 		if (!TriangleRect.isRectCollided(ViewPortRect))
121 			continue;
122 
123 		// calculate height of triangle
124 		height = v3->Pos.Y - v1->Pos.Y;
125 		if (!height)
126 			continue;
127 
128 		// calculate longest span
129 
130 		longest = (v2->Pos.Y - v1->Pos.Y) / (f32)height * (v3->Pos.X - v1->Pos.X) + (v1->Pos.X - v2->Pos.X);
131 
132 		spanEnd = v2->Pos.Y;
133 		span = v1->Pos.Y;
134 		leftxf = (f32)v1->Pos.X;
135 		rightxf = (f32)v1->Pos.X;
136 
137 		leftZValue = v1->ZValue;
138 		rightZValue = v1->ZValue;
139 
140 		leftR = rightR = video::getRed(v1->Color)<<8;
141 		leftG = rightG = video::getGreen(v1->Color)<<8;
142 		leftB = rightB = video::getBlue(v1->Color)<<8;
143 		leftTx = rightTx = v1->TCoords.X;
144 		leftTy = rightTy = v1->TCoords.Y;
145 
146 		targetSurface = lockedSurface + span * SurfaceWidth;
147 		zTarget = lockedZBuffer + span * SurfaceWidth;
148 
149 		if (longest < 0.0f)
150 		{
151 			tmpDiv = 1.0f / (f32)(v2->Pos.Y - v1->Pos.Y);
152 			rightdeltaxf = (v2->Pos.X - v1->Pos.X) * tmpDiv;
153 			rightZStep = (s32)((v2->ZValue - v1->ZValue) * tmpDiv);
154 			rightStepR = (s32)(((s32)(video::getRed(v2->Color)<<8) - rightR) * tmpDiv);
155 			rightStepG = (s32)(((s32)(video::getGreen(v2->Color)<<8) - rightG) * tmpDiv);
156 			rightStepB = (s32)(((s32)(video::getBlue(v2->Color)<<8) - rightB) * tmpDiv);
157 			rightTxStep = (s32)((v2->TCoords.X - rightTx) * tmpDiv);
158 			rightTyStep = (s32)((v2->TCoords.Y - rightTy) * tmpDiv);
159 
160 			tmpDiv = 1.0f / (f32)height;
161 			leftdeltaxf = (v3->Pos.X - v1->Pos.X) * tmpDiv;
162 			leftZStep = (s32)((v3->ZValue - v1->ZValue) * tmpDiv);
163 			leftStepR = (s32)(((s32)(video::getRed(v3->Color)<<8) - leftR) * tmpDiv);
164 			leftStepG = (s32)(((s32)(video::getGreen(v3->Color)<<8) - leftG) * tmpDiv);
165 			leftStepB = (s32)(((s32)(video::getBlue(v3->Color)<<8) - leftB) * tmpDiv);
166 			leftTxStep = (s32)((v3->TCoords.X - leftTx) * tmpDiv);
167 			leftTyStep = (s32)((v3->TCoords.Y - leftTy) * tmpDiv);
168 		}
169 		else
170 		{
171 			tmpDiv = 1.0f / (f32)height;
172 			rightdeltaxf = (v3->Pos.X - v1->Pos.X) * tmpDiv;
173 			rightZStep = (s32)((v3->ZValue - v1->ZValue) * tmpDiv);
174 			rightStepR = (s32)(((s32)(video::getRed(v3->Color)<<8) - rightR) * tmpDiv);
175 			rightStepG = (s32)(((s32)(video::getGreen(v3->Color)<<8) - rightG) * tmpDiv);
176 			rightStepB = (s32)(((s32)(video::getBlue(v3->Color)<<8) - rightB) * tmpDiv);
177 			rightTxStep = (s32)((v3->TCoords.X - rightTx) * tmpDiv);
178 			rightTyStep = (s32)((v3->TCoords.Y - rightTy) * tmpDiv);
179 
180 			tmpDiv = 1.0f / (f32)(v2->Pos.Y - v1->Pos.Y);
181 			leftdeltaxf = (v2->Pos.X - v1->Pos.X) * tmpDiv;
182 			leftZStep = (s32)((v2->ZValue - v1->ZValue) * tmpDiv);
183 			leftStepR = (s32)(((s32)(video::getRed(v2->Color)<<8) - leftR) * tmpDiv);
184 			leftStepG = (s32)(((s32)(video::getGreen(v2->Color)<<8) - leftG) * tmpDiv);
185 			leftStepB = (s32)(((s32)(video::getBlue(v2->Color)<<8) - leftB) * tmpDiv);
186 			leftTxStep = (s32)((v2->TCoords.X - leftTx) * tmpDiv);
187 			leftTyStep = (s32)((v2->TCoords.Y - leftTy) * tmpDiv);
188 		}
189 
190 
191 		// do it twice, once for the first half of the triangle,
192 		// end then for the second half.
193 
194 		for (s32 triangleHalf=0; triangleHalf<2; ++triangleHalf)
195 		{
196 			if (spanEnd > ViewPortRect.LowerRightCorner.Y)
197 				spanEnd = ViewPortRect.LowerRightCorner.Y;
198 
199 			// if the span <0, than we can skip these spans,
200 			// and proceed to the next spans which are really on the screen.
201 			if (span < ViewPortRect.UpperLeftCorner.Y)
202 			{
203 				// we'll use leftx as temp variable
204 				if (spanEnd < ViewPortRect.UpperLeftCorner.Y)
205 				{
206 					leftx = spanEnd - span;
207 					span = spanEnd;
208 				}
209 				else
210 				{
211 					leftx = ViewPortRect.UpperLeftCorner.Y - span;
212 					span = ViewPortRect.UpperLeftCorner.Y;
213 				}
214 
215 				leftxf += leftdeltaxf*leftx;
216 				rightxf += rightdeltaxf*leftx;
217 				targetSurface += SurfaceWidth*leftx;
218 				zTarget += SurfaceWidth*leftx;
219 				leftZValue += leftZStep*leftx;
220 				rightZValue += rightZStep*leftx;
221 
222 				leftR += leftStepR*leftx;
223 				leftG += leftStepG*leftx;
224 				leftB += leftStepB*leftx;
225 				rightR += rightStepR*leftx;
226 				rightG += rightStepG*leftx;
227 				rightB += rightStepB*leftx;
228 
229 				leftTx += leftTxStep*leftx;
230 				leftTy += leftTyStep*leftx;
231 				rightTx += rightTxStep*leftx;
232 				rightTy += rightTyStep*leftx;
233 			}
234 
235 
236 			// the main loop. Go through every span and draw it.
237 
238 			while (span < spanEnd)
239 			{
240 				leftx = (s32)(leftxf);
241 				rightx = (s32)(rightxf + 0.5f);
242 
243 				// perform some clipping
244 				// thanks to a correction by hybrid
245 				// calculations delayed to correctly propagate to textures etc.
246 				s32 tDiffLeft=0, tDiffRight=0;
247 				if (leftx<ViewPortRect.UpperLeftCorner.X)
248 					tDiffLeft=ViewPortRect.UpperLeftCorner.X-leftx;
249 				else
250 				if (leftx>ViewPortRect.LowerRightCorner.X)
251 					tDiffLeft=ViewPortRect.LowerRightCorner.X-leftx;
252 
253 				if (rightx<ViewPortRect.UpperLeftCorner.X)
254 					tDiffRight=ViewPortRect.UpperLeftCorner.X-rightx;
255 				else
256 				if (rightx>ViewPortRect.LowerRightCorner.X)
257 					tDiffRight=ViewPortRect.LowerRightCorner.X-rightx;
258 
259 				// draw the span
260 				if (rightx + tDiffRight - leftx - tDiffLeft)
261 				{
262 					tmpDiv = 1.0f / (f32)(rightx - leftx);
263 					spanZStep = (s32)((rightZValue - leftZValue) * tmpDiv);
264 					spanZValue = leftZValue+tDiffLeft*spanZStep;
265 
266 					spanStepR = (s32)((rightR - leftR) * tmpDiv);
267 					spanR = leftR+tDiffLeft*spanStepR;
268 					spanStepG = (s32)((rightG - leftG) * tmpDiv);
269 					spanG = leftG+tDiffLeft*spanStepG;
270 					spanStepB = (s32)((rightB - leftB) * tmpDiv);
271 					spanB = leftB+tDiffLeft*spanStepB;
272 
273 					spanTxStep = (s32)((rightTx - leftTx) * tmpDiv);
274 					spanTx = leftTx + tDiffLeft*spanTxStep;
275 					spanTyStep = (s32)((rightTy - leftTy) * tmpDiv);
276 					spanTy = leftTy+tDiffLeft*spanTyStep;
277 
278 					hSpanBegin = targetSurface + leftx+tDiffLeft;
279 					spanZTarget = zTarget + leftx+tDiffLeft;
280 					hSpanEnd = targetSurface + rightx+tDiffRight;
281 
282 					while (hSpanBegin < hSpanEnd)
283 					{
284 						if (spanZValue > *spanZTarget)
285 						{
286 							//*spanZTarget = spanZValue;
287 							color = lockedTexture[((spanTy>>8)&textureYMask) * lockedTextureWidth + ((spanTx>>8)&textureXMask)];
288 
289 							s32 basis = *hSpanBegin;
290 							s32 r = (video::getRed(basis)<<3) + (video::getRed(color)<<3);
291 							if (r > 255) r = 255;
292 							s32 g = (video::getGreen(basis)<<3) + (video::getGreen(color)<<3);
293 							if (g > 255) g = 255;
294 							s32 b = (video::getBlue(basis)<<3) + (video::getBlue(color)<<3);
295 							if (b > 255) b = 255;
296 
297 							*hSpanBegin = video::RGB16(r, g, b);
298 						}
299 
300 						spanR += spanStepR;
301 						spanG += spanStepG;
302 						spanB += spanStepB;
303 
304 						spanTx += spanTxStep;
305 						spanTy += spanTyStep;
306 
307 						spanZValue += spanZStep;
308 						++hSpanBegin;
309 						++spanZTarget;
310 					}
311 				}
312 
313 				leftxf += leftdeltaxf;
314 				rightxf += rightdeltaxf;
315 				++span;
316 				targetSurface += SurfaceWidth;
317 				zTarget += SurfaceWidth;
318 				leftZValue += leftZStep;
319 				rightZValue += rightZStep;
320 
321 				leftR += leftStepR;
322 				leftG += leftStepG;
323 				leftB += leftStepB;
324 				rightR += rightStepR;
325 				rightG += rightStepG;
326 				rightB += rightStepB;
327 
328 				leftTx += leftTxStep;
329 				leftTy += leftTyStep;
330 				rightTx += rightTxStep;
331 				rightTy += rightTyStep;
332 			}
333 
334 			if (triangleHalf>0) // break, we've gout only two halves
335 				break;
336 
337 
338 			// setup variables for second half of the triangle.
339 
340 			if (longest < 0.0f)
341 			{
342 				tmpDiv = 1.0f / (v3->Pos.Y - v2->Pos.Y);
343 
344 				rightdeltaxf = (v3->Pos.X - v2->Pos.X) * tmpDiv;
345 				rightxf = (f32)v2->Pos.X;
346 
347 				rightZValue = v2->ZValue;
348 				rightZStep = (s32)((v3->ZValue - v2->ZValue) * tmpDiv);
349 
350 				rightR = video::getRed(v2->Color)<<8;
351 				rightG = video::getGreen(v2->Color)<<8;
352 				rightB = video::getBlue(v2->Color)<<8;
353 				rightStepR = (s32)(((s32)(video::getRed(v3->Color)<<8) - rightR) * tmpDiv);
354 				rightStepG = (s32)(((s32)(video::getGreen(v3->Color)<<8) - rightG) * tmpDiv);
355 				rightStepB = (s32)(((s32)(video::getBlue(v3->Color)<<8) - rightB) * tmpDiv);
356 
357 				rightTx = v2->TCoords.X;
358 				rightTy = v2->TCoords.Y;
359 				rightTxStep = (s32)((v3->TCoords.X - rightTx) * tmpDiv);
360 				rightTyStep = (s32)((v3->TCoords.Y - rightTy) * tmpDiv);
361 			}
362 			else
363 			{
364 				tmpDiv = 1.0f / (v3->Pos.Y - v2->Pos.Y);
365 
366 				leftdeltaxf = (v3->Pos.X - v2->Pos.X) * tmpDiv;
367 				leftxf = (f32)v2->Pos.X;
368 
369 				leftZValue = v2->ZValue;
370 				leftZStep = (s32)((v3->ZValue - v2->ZValue) * tmpDiv);
371 
372 				leftR = video::getRed(v2->Color)<<8;
373 				leftG = video::getGreen(v2->Color)<<8;
374 				leftB = video::getBlue(v2->Color)<<8;
375 				leftStepR = (s32)(((s32)(video::getRed(v3->Color)<<8) - leftR) * tmpDiv);
376 				leftStepG = (s32)(((s32)(video::getGreen(v3->Color)<<8) - leftG) * tmpDiv);
377 				leftStepB = (s32)(((s32)(video::getBlue(v3->Color)<<8) - leftB) * tmpDiv);
378 
379 				leftTx = v2->TCoords.X;
380 				leftTy = v2->TCoords.Y;
381 				leftTxStep = (s32)((v3->TCoords.X - leftTx) * tmpDiv);
382 				leftTyStep = (s32)((v3->TCoords.Y - leftTy) * tmpDiv);
383 			}
384 
385 
386 			spanEnd = v3->Pos.Y;
387 		}
388 
389 	}
390 
391 	RenderTarget->unlock();
392 	ZBuffer->unlock();
393 	Texture->unlock();
394 }
395 
396 } // end namespace video
397 } // end namespace irr
398 
399 #endif // _IRR_COMPILE_WITH_SOFTWARE_
400 
401 namespace irr
402 {
403 namespace video
404 {
405 
createTriangleRendererTextureGouraudAdd(IZBuffer * zbuffer)406 ITriangleRenderer* createTriangleRendererTextureGouraudAdd(IZBuffer* zbuffer)
407 {
408 	#ifdef _IRR_COMPILE_WITH_SOFTWARE_
409 	return new CTRTextureGouraudAdd(zbuffer);
410 	#else
411 	return 0;
412 	#endif // _IRR_COMPILE_WITH_SOFTWARE_
413 }
414 
415 } // end namespace video
416 } // end namespace irr
417 
418 
419 
420