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 CTRTextureFlatWire : public CTRTextureGouraud
16 {
17 public:
18 
CTRTextureFlatWire(IZBuffer * zbuffer)19 	CTRTextureFlatWire(IZBuffer* zbuffer)
20 		: CTRTextureGouraud(zbuffer)
21 	{
22 		#ifdef _DEBUG
23 		setDebugName("CTRTextureFlatWire");
24 		#endif
25 	}
26 
27 	//! draws an indexed triangle list
drawIndexedTriangleList(S2DVertex * vertices,s32 vertexCount,const u16 * indexList,s32 triangleCount)28 	virtual void drawIndexedTriangleList(S2DVertex* vertices, s32 vertexCount, const u16* indexList, s32 triangleCount)
29 	{
30 		const S2DVertex *v1, *v2, *v3;
31 
32 		f32 tmpDiv; // temporary division factor
33 		f32 longest; // saves the longest span
34 		s32 height; // saves height of triangle
35 		u16* targetSurface; // target pointer where to plot pixels
36 		s32 spanEnd; // saves end of spans
37 		f32 leftdeltaxf; // amount of pixels to increase on left side of triangle
38 		f32 rightdeltaxf; // amount of pixels to increase on right side of triangle
39 		s32 leftx, rightx; // position where we are
40 		f32 leftxf, rightxf; // same as above, but as f32 values
41 		s32 span; // current span
42 		s32 leftTx, rightTx, leftTy, rightTy; // texture interpolating values
43 		s32 leftTxStep, rightTxStep, leftTyStep, rightTyStep; // texture interpolating values
44 		core::rect<s32> TriangleRect;
45 
46 		s32 leftZValue, rightZValue;
47 		s32 leftZStep, rightZStep;
48 		TZBufferType* zTarget; // target of ZBuffer;
49 
50 		lockedSurface = (u16*)RenderTarget->lock();
51 		lockedZBuffer = ZBuffer->lock();
52 		lockedTexture = (u16*)Texture->lock();
53 
54 		for (s32 i=0; i<triangleCount; ++i)
55 		{
56 			v1 = &vertices[*indexList];
57 			++indexList;
58 			v2 = &vertices[*indexList];
59 			++indexList;
60 			v3 = &vertices[*indexList];
61 			++indexList;
62 
63 			// back face culling
64 
65 			if (BackFaceCullingEnabled)
66 			{
67 				s32 z = ((v3->Pos.X - v1->Pos.X) * (v3->Pos.Y - v2->Pos.Y)) -
68 					((v3->Pos.Y - v1->Pos.Y) * (v3->Pos.X - v2->Pos.X));
69 
70 				if (z < 0)
71 					continue;
72 			}
73 
74 			//near plane clipping
75 
76 			if (v1->ZValue<0 && v2->ZValue<0 && v3->ZValue<0)
77 				continue;
78 
79 			// sort for width for inscreen clipping
80 
81 			if (v1->Pos.X > v2->Pos.X)	swapVertices(&v1, &v2);
82 			if (v1->Pos.X > v3->Pos.X)	swapVertices(&v1, &v3);
83 			if (v2->Pos.X > v3->Pos.X)	swapVertices(&v2, &v3);
84 
85 			if ((v1->Pos.X - v3->Pos.X) == 0)
86 				continue;
87 
88 			TriangleRect.UpperLeftCorner.X = v1->Pos.X;
89 			TriangleRect.LowerRightCorner.X = v3->Pos.X;
90 
91 			// sort for height for faster drawing.
92 
93 			if (v1->Pos.Y > v2->Pos.Y)	swapVertices(&v1, &v2);
94 			if (v1->Pos.Y > v3->Pos.Y)	swapVertices(&v1, &v3);
95 			if (v2->Pos.Y > v3->Pos.Y)	swapVertices(&v2, &v3);
96 
97 			TriangleRect.UpperLeftCorner.Y = v1->Pos.Y;
98 			TriangleRect.LowerRightCorner.Y = v3->Pos.Y;
99 
100 			if (!TriangleRect.isRectCollided(ViewPortRect))
101 				continue;
102 
103 			// calculate height of triangle
104 			height = v3->Pos.Y - v1->Pos.Y;
105 			if (!height)
106 				continue;
107 
108 			// calculate longest span
109 
110 			longest = (v2->Pos.Y - v1->Pos.Y) / (f32)height * (v3->Pos.X - v1->Pos.X) + (v1->Pos.X - v2->Pos.X);
111 
112 			spanEnd = v2->Pos.Y;
113 			span = v1->Pos.Y;
114 			leftxf = (f32)v1->Pos.X;
115 			rightxf = (f32)v1->Pos.X;
116 
117 			leftZValue = v1->ZValue;
118 			rightZValue = v1->ZValue;
119 
120 			leftTx = rightTx = v1->TCoords.X;
121 			leftTy = rightTy = v1->TCoords.Y;
122 
123 			targetSurface = lockedSurface + span * SurfaceWidth;
124 			zTarget = lockedZBuffer + span * SurfaceWidth;
125 
126 			if (longest < 0.0f)
127 			{
128 				tmpDiv = 1.0f / (f32)(v2->Pos.Y - v1->Pos.Y);
129 				rightdeltaxf = (v2->Pos.X - v1->Pos.X) * tmpDiv;
130 				rightZStep = (s32)((v2->ZValue - v1->ZValue) * tmpDiv);
131 				rightTxStep = (s32)((v2->TCoords.X - rightTx) * tmpDiv);
132 				rightTyStep = (s32)((v2->TCoords.Y - rightTy) * tmpDiv);
133 
134 				tmpDiv = 1.0f / (f32)height;
135 				leftdeltaxf = (v3->Pos.X - v1->Pos.X) * tmpDiv;
136 				leftZStep = (s32)((v3->ZValue - v1->ZValue) * tmpDiv);
137 				leftTxStep = (s32)((v3->TCoords.X - leftTx) * tmpDiv);
138 				leftTyStep = (s32)((v3->TCoords.Y - leftTy) * tmpDiv);
139 			}
140 			else
141 			{
142 				tmpDiv = 1.0f / (f32)height;
143 				rightdeltaxf = (v3->Pos.X - v1->Pos.X) * tmpDiv;
144 				rightZStep = (s32)((v3->ZValue - v1->ZValue) * tmpDiv);
145 				rightTxStep = (s32)((v3->TCoords.X - rightTx) * tmpDiv);
146 				rightTyStep = (s32)((v3->TCoords.Y - rightTy) * tmpDiv);
147 
148 				tmpDiv = 1.0f / (f32)(v2->Pos.Y - v1->Pos.Y);
149 				leftdeltaxf = (v2->Pos.X - v1->Pos.X) * tmpDiv;
150 				leftZStep = (s32)((v2->ZValue - v1->ZValue) * tmpDiv);
151 				leftTxStep = (s32)((v2->TCoords.X - leftTx) * tmpDiv);
152 				leftTyStep = (s32)((v2->TCoords.Y - leftTy) * tmpDiv);
153 			}
154 
155 
156 			// do it twice, once for the first half of the triangle,
157 			// end then for the second half.
158 
159 			for (s32 triangleHalf=0; triangleHalf<2; ++triangleHalf)
160 			{
161 				if (spanEnd > ViewPortRect.LowerRightCorner.Y)
162 					spanEnd = ViewPortRect.LowerRightCorner.Y;
163 
164 				// if the span <0, than we can skip these spans,
165 				// and proceed to the next spans which are really on the screen.
166 				if (span < ViewPortRect.UpperLeftCorner.Y)
167 				{
168 					// we'll use leftx as temp variable
169 					if (spanEnd < ViewPortRect.UpperLeftCorner.Y)
170 					{
171 						leftx = spanEnd - span;
172 						span = spanEnd;
173 					}
174 					else
175 					{
176 						leftx = ViewPortRect.UpperLeftCorner.Y - span;
177 						span = ViewPortRect.UpperLeftCorner.Y;
178 					}
179 
180 					leftxf += leftdeltaxf*leftx;
181 					rightxf += rightdeltaxf*leftx;
182 					targetSurface += SurfaceWidth*leftx;
183 					zTarget += SurfaceWidth*leftx;
184 					leftZValue += leftZStep*leftx;
185 					rightZValue += rightZStep*leftx;
186 
187 					leftTx += leftTxStep*leftx;
188 					leftTy += leftTyStep*leftx;
189 					rightTx += rightTxStep*leftx;
190 					rightTy += rightTyStep*leftx;
191 				}
192 
193 
194 				// the main loop. Go through every span and draw it.
195 
196 				while (span < spanEnd)
197 				{
198 					leftx = (s32)(leftxf);
199 					rightx = (s32)(rightxf + 0.5f);
200 
201 					// perform some clipping
202 
203 					if (leftx>=ViewPortRect.UpperLeftCorner.X &&
204 						leftx<=ViewPortRect.LowerRightCorner.X)
205 					{
206 						if (leftZValue > *(zTarget + leftx))
207 						{
208 							*(zTarget + leftx) = leftZValue;
209 							*(targetSurface + leftx) = lockedTexture[((leftTy>>8)&textureYMask) * lockedTextureWidth + ((rightTx>>8)&textureXMask)];
210 						}
211 					}
212 
213 
214 					if (rightx>=ViewPortRect.UpperLeftCorner.X &&
215 						rightx<=ViewPortRect.LowerRightCorner.X)
216 					{
217 						if (rightZValue > *(zTarget + rightx))
218 						{
219 							*(zTarget + rightx) = rightZValue;
220 							*(targetSurface + rightx) = lockedTexture[((rightTy>>8)&textureYMask) * lockedTextureWidth + ((rightTx>>8)&textureXMask)];
221 						}
222 
223 					}
224 
225 
226 					leftxf += leftdeltaxf;
227 					rightxf += rightdeltaxf;
228 					++span;
229 					targetSurface += SurfaceWidth;
230 					zTarget += SurfaceWidth;
231 					leftZValue += leftZStep;
232 					rightZValue += rightZStep;
233 
234 					leftTx += leftTxStep;
235 					leftTy += leftTyStep;
236 					rightTx += rightTxStep;
237 					rightTy += rightTyStep;
238 				}
239 
240 				if (triangleHalf>0) // break, we've gout only two halves
241 					break;
242 
243 
244 				// setup variables for second half of the triangle.
245 
246 				if (longest < 0.0f)
247 				{
248 					tmpDiv = 1.0f / (v3->Pos.Y - v2->Pos.Y);
249 
250 					rightdeltaxf = (v3->Pos.X - v2->Pos.X) * tmpDiv;
251 					rightxf = (f32)v2->Pos.X;
252 
253 					rightZValue = v2->ZValue;
254 					rightZStep = (s32)((v3->ZValue - v2->ZValue) * tmpDiv);
255 
256 					rightTx = v2->TCoords.X;
257 					rightTy = v2->TCoords.Y;
258 					rightTxStep = (s32)((v3->TCoords.X - rightTx) * tmpDiv);
259 					rightTyStep = (s32)((v3->TCoords.Y - rightTy) * tmpDiv);
260 				}
261 				else
262 				{
263 					tmpDiv = 1.0f / (v3->Pos.Y - v2->Pos.Y);
264 
265 					leftdeltaxf = (v3->Pos.X - v2->Pos.X) * tmpDiv;
266 					leftxf = (f32)v2->Pos.X;
267 
268 					leftZValue = v2->ZValue;
269 					leftZStep = (s32)((v3->ZValue - v2->ZValue) * tmpDiv);
270 
271 					leftTx = v2->TCoords.X;
272 					leftTy = v2->TCoords.Y;
273 					leftTxStep = (s32)((v3->TCoords.X - leftTx) * tmpDiv);
274 					leftTyStep = (s32)((v3->TCoords.Y - leftTy) * tmpDiv);
275 				}
276 
277 
278 				spanEnd = v3->Pos.Y;
279 			}
280 
281 		}
282 
283 		RenderTarget->unlock();
284 		ZBuffer->unlock();
285 		Texture->unlock();
286 
287 	}
288 };
289 
290 } // end namespace video
291 } // end namespace irr
292 
293 #endif // _IRR_COMPILE_WITH_SOFTWARE_
294 
295 namespace irr
296 {
297 namespace video
298 {
299 
300 //! creates a flat triangle renderer
createTriangleRendererTextureFlatWire(IZBuffer * zbuffer)301 ITriangleRenderer* createTriangleRendererTextureFlatWire(IZBuffer* zbuffer)
302 {
303 	#ifdef _IRR_COMPILE_WITH_SOFTWARE_
304 	return new CTRTextureFlatWire(zbuffer);
305 	#else
306 	return 0;
307 	#endif // _IRR_COMPILE_WITH_SOFTWARE_
308 }
309 
310 } // end namespace video
311 } // end namespace irr
312 
313 
314