]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/CTRTextureGouraud.cpp
CIrrDeviceWin32: drop all video mode code
[irrlicht.git] / source / Irrlicht / CTRTextureGouraud.cpp
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
4 \r
5 #include "CTRTextureGouraud.h"\r
6 \r
7 #ifdef _IRR_COMPILE_WITH_SOFTWARE_\r
8 \r
9 namespace irr\r
10 {\r
11 namespace video\r
12 {\r
13 \r
14 //! constructor\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
20 {\r
21         #ifdef _DEBUG\r
22         setDebugName("CTRTextureGouraud");\r
23         #endif\r
24 \r
25         if (ZBuffer)\r
26                 zbuffer->grab();\r
27 }\r
28 \r
29 \r
30 \r
31 //! destructor\r
32 CTRTextureGouraud::~CTRTextureGouraud()\r
33 {\r
34         if (RenderTarget)\r
35                 RenderTarget->drop();\r
36 \r
37         if (ZBuffer)\r
38                 ZBuffer->drop();\r
39 \r
40         if (Texture)\r
41                 Texture->drop();\r
42 }\r
43 \r
44 \r
45 \r
46 //! sets the Texture\r
47 void CTRTextureGouraud::setTexture(video::IImage* texture)\r
48 {\r
49         if (Texture)\r
50                 Texture->drop();\r
51 \r
52         Texture = texture;\r
53 \r
54         if (Texture)\r
55         {\r
56                 Texture->grab();\r
57                 lockedTextureWidth = Texture->getDimension().Width;\r
58 \r
59                 textureXMask = lockedTextureWidth-1;\r
60                 textureYMask = Texture->getDimension().Height-1;\r
61         }\r
62 }\r
63 \r
64 \r
65 \r
66 \r
67 //! en or disables the backface culling\r
68 void CTRTextureGouraud::setBackfaceCulling(bool enabled)\r
69 {\r
70         BackFaceCullingEnabled = enabled;\r
71 }\r
72 \r
73 \r
74 \r
75 //! sets a render target\r
76 void CTRTextureGouraud::setRenderTarget(video::IImage* surface, const core::rect<s32>& viewPort)\r
77 {\r
78         if (RenderTarget)\r
79                 RenderTarget->drop();\r
80 \r
81         RenderTarget = surface;\r
82 \r
83         if (RenderTarget)\r
84         {\r
85                 SurfaceWidth = RenderTarget->getDimension().Width;\r
86                 SurfaceHeight = RenderTarget->getDimension().Height;\r
87                 RenderTarget->grab();\r
88                 ViewPortRect = viewPort;\r
89         }\r
90 }\r
91 \r
92 \r
93 \r
94 //! draws an indexed triangle list\r
95 void CTRTextureGouraud::drawIndexedTriangleList(S2DVertex* vertices, s32 vertexCount, const u16* indexList, s32 triangleCount)\r
96 {\r
97         const S2DVertex *v1, *v2, *v3;\r
98 \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
118 \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
123 \r
124         lockedSurface = (u16*)RenderTarget->getData();\r
125         lockedZBuffer = ZBuffer->lock();\r
126         lockedTexture = (u16*)Texture->getData();\r
127 \r
128         for (s32 i=0; i<triangleCount; ++i)\r
129         {\r
130                 v1 = &vertices[*indexList];\r
131                 ++indexList;\r
132                 v2 = &vertices[*indexList];\r
133                 ++indexList;\r
134                 v3 = &vertices[*indexList];\r
135                 ++indexList;\r
136 \r
137                 // back face culling\r
138 \r
139                 if (BackFaceCullingEnabled)\r
140                 {\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
143 \r
144                         if (z < 0)\r
145                                 continue;\r
146                 }\r
147 \r
148                 //near plane clipping\r
149 \r
150                 if (v1->ZValue<0 && v2->ZValue<0 && v3->ZValue<0)\r
151                         continue;\r
152 \r
153                 // sort for width for inscreen clipping\r
154 \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
158 \r
159                 if ((v1->Pos.X - v3->Pos.X) == 0)\r
160                         continue;\r
161 \r
162                 TriangleRect.UpperLeftCorner.X = v1->Pos.X;\r
163                 TriangleRect.LowerRightCorner.X = v3->Pos.X;\r
164 \r
165                 // sort for height for faster drawing.\r
166 \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
170 \r
171                 TriangleRect.UpperLeftCorner.Y = v1->Pos.Y;\r
172                 TriangleRect.LowerRightCorner.Y = v3->Pos.Y;\r
173 \r
174                 if (!TriangleRect.isRectCollided(ViewPortRect))\r
175                         continue;\r
176 \r
177                 // calculate height of triangle\r
178                 height = v3->Pos.Y - v1->Pos.Y;\r
179                 if (!height)\r
180                         continue;\r
181 \r
182                 // calculate longest span\r
183 \r
184                 longest = (v2->Pos.Y - v1->Pos.Y) / (f32)height * (v3->Pos.X - v1->Pos.X) + (v1->Pos.X - v2->Pos.X);\r
185 \r
186                 spanEnd = v2->Pos.Y;\r
187                 span = v1->Pos.Y;\r
188                 leftxf = (f32)v1->Pos.X;\r
189                 rightxf = (f32)v1->Pos.X;\r
190 \r
191                 leftZValue = v1->ZValue;\r
192                 rightZValue = v1->ZValue;\r
193 \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
199 \r
200                 targetSurface = lockedSurface + span * SurfaceWidth;\r
201                 zTarget = lockedZBuffer + span * SurfaceWidth;\r
202 \r
203                 if (longest < 0.0f)\r
204                 {\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
213 \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
222                 }\r
223                 else\r
224                 {\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
233 \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
242                 }\r
243 \r
244 \r
245                 // do it twice, once for the first half of the triangle,\r
246                 // end then for the second half.\r
247 \r
248                 for (s32 triangleHalf=0; triangleHalf<2; ++triangleHalf)\r
249                 {\r
250                         if (spanEnd > ViewPortRect.LowerRightCorner.Y)\r
251                                 spanEnd = ViewPortRect.LowerRightCorner.Y;\r
252 \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
256                         {\r
257                                 // we'll use leftx as temp variable\r
258                                 if (spanEnd < ViewPortRect.UpperLeftCorner.Y)\r
259                                 {\r
260                                         leftx = spanEnd - span;\r
261                                         span = spanEnd;\r
262                                 }\r
263                                 else\r
264                                 {\r
265                                         leftx = ViewPortRect.UpperLeftCorner.Y - span;\r
266                                         span = ViewPortRect.UpperLeftCorner.Y;\r
267                                 }\r
268 \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
275 \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
282 \r
283                                 leftTx += leftTxStep*leftx;\r
284                                 leftTy += leftTyStep*leftx;\r
285                                 rightTx += rightTxStep*leftx;\r
286                                 rightTy += rightTyStep*leftx;\r
287                         }\r
288 \r
289 \r
290                         // the main loop. Go through every span and draw it.\r
291 \r
292                         while (span < spanEnd)\r
293                         {\r
294                                 leftx = (s32)(leftxf);\r
295                                 rightx = (s32)(rightxf + 0.5f);\r
296 \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
303                                 else\r
304                                 if (leftx>ViewPortRect.LowerRightCorner.X)\r
305                                         tDiffLeft=ViewPortRect.LowerRightCorner.X-leftx;\r
306 \r
307                                 if (rightx<ViewPortRect.UpperLeftCorner.X)\r
308                                         tDiffRight=ViewPortRect.UpperLeftCorner.X-rightx;\r
309                                 else\r
310                                 if (rightx>ViewPortRect.LowerRightCorner.X)\r
311                                         tDiffRight=ViewPortRect.LowerRightCorner.X-rightx;\r
312 \r
313                                 // draw the span\r
314                                 if (rightx + tDiffRight - leftx - tDiffLeft)\r
315                                 {\r
316                                         tmpDiv = 1.0f / (f32)(rightx - leftx);\r
317                                         spanZStep = (s32)((rightZValue - leftZValue) * tmpDiv);\r
318                                         spanZValue = leftZValue+tDiffLeft*spanZStep;\r
319 \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
326 \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
331 \r
332                                         hSpanBegin = targetSurface + leftx+tDiffLeft;\r
333                                         spanZTarget = zTarget + leftx+tDiffLeft;\r
334                                         hSpanEnd = targetSurface + rightx+tDiffRight;\r
335 \r
336                                         while (hSpanBegin < hSpanEnd)\r
337                                         {\r
338                                                 if (spanZValue > *spanZTarget)\r
339                                                 {\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
345                                                 }\r
346 \r
347                                                 spanR += spanStepR;\r
348                                                 spanG += spanStepG;\r
349                                                 spanB += spanStepB;\r
350 \r
351                                                 spanTx += spanTxStep;\r
352                                                 spanTy += spanTyStep;\r
353 \r
354                                                 spanZValue += spanZStep;\r
355                                                 ++hSpanBegin;\r
356                                                 ++spanZTarget;\r
357                                         }\r
358                                 }\r
359 \r
360                                 leftxf += leftdeltaxf;\r
361                                 rightxf += rightdeltaxf;\r
362                                 ++span;\r
363                                 targetSurface += SurfaceWidth;\r
364                                 zTarget += SurfaceWidth;\r
365                                 leftZValue += leftZStep;\r
366                                 rightZValue += rightZStep;\r
367 \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
374 \r
375                                 leftTx += leftTxStep;\r
376                                 leftTy += leftTyStep;\r
377                                 rightTx += rightTxStep;\r
378                                 rightTy += rightTyStep;\r
379                         }\r
380 \r
381                         if (triangleHalf>0) // break, we've gout only two halves\r
382                                 break;\r
383 \r
384 \r
385                         // setup variables for second half of the triangle.\r
386 \r
387                         if (longest < 0.0f)\r
388                         {\r
389                                 tmpDiv = 1.0f / (v3->Pos.Y - v2->Pos.Y);\r
390 \r
391                                 rightdeltaxf = (v3->Pos.X - v2->Pos.X) * tmpDiv;\r
392                                 rightxf = (f32)v2->Pos.X;\r
393 \r
394                                 rightZValue = v2->ZValue;\r
395                                 rightZStep = (s32)((v3->ZValue - v2->ZValue) * tmpDiv);\r
396 \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
403 \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
408                         }\r
409                         else\r
410                         {\r
411                                 tmpDiv = 1.0f / (v3->Pos.Y - v2->Pos.Y);\r
412 \r
413                                 leftdeltaxf = (v3->Pos.X - v2->Pos.X) * tmpDiv;\r
414                                 leftxf = (f32)v2->Pos.X;\r
415 \r
416                                 leftZValue = v2->ZValue;\r
417                                 leftZStep = (s32)((v3->ZValue - v2->ZValue) * tmpDiv);\r
418 \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
425 \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
430                         }\r
431 \r
432 \r
433                         spanEnd = v3->Pos.Y;\r
434                 }\r
435 \r
436         }\r
437 \r
438         ZBuffer->unlock();\r
439 }\r
440 \r
441 \r
442 } // end namespace video\r
443 } // end namespace irr\r
444 \r
445 #endif // _IRR_COMPILE_WITH_SOFTWARE_\r
446 \r
447 namespace irr\r
448 {\r
449 namespace video\r
450 {\r
451 \r
452 //! creates a flat triangle renderer\r
453 ITriangleRenderer* createTriangleRendererTextureGouraud(IZBuffer* zbuffer)\r
454 {\r
455         #ifdef _IRR_COMPILE_WITH_SOFTWARE_\r
456         return new CTRTextureGouraud(zbuffer);\r
457         #else\r
458         return 0;\r
459         #endif // _IRR_COMPILE_WITH_SOFTWARE_\r
460 }\r
461 \r
462 \r
463 } // end namespace video\r
464 } // end namespace irr\r
465 \r
466 \r