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 "CSoftwareDriver.h"
7
8 #ifdef _IRR_COMPILE_WITH_SOFTWARE_
9
10 #include "CSoftwareTexture.h"
11 #include "CBlit.h"
12 #include "os.h"
13 #include "S3DVertex.h"
14
15 namespace irr
16 {
17 namespace video
18 {
19
20
21 //! constructor
CSoftwareDriver(const core::dimension2d<u32> & windowSize,bool fullscreen,io::IFileSystem * io,video::IImagePresenter * presenter)22 CSoftwareDriver::CSoftwareDriver(const core::dimension2d<u32>& windowSize, bool fullscreen, io::IFileSystem* io, video::IImagePresenter* presenter)
23 : CNullDriver(io, windowSize), BackBuffer(0), Presenter(presenter), WindowId(0),
24 SceneSourceRect(0), RenderTargetTexture(0), RenderTargetSurface(0),
25 CurrentTriangleRenderer(0), ZBuffer(0), Texture(0)
26 {
27 #ifdef _DEBUG
28 setDebugName("CSoftwareDriver");
29 #endif
30
31 // create backbuffer
32
33 BackBuffer = new CImage(ECF_A1R5G5B5, windowSize);
34 if (BackBuffer)
35 {
36 BackBuffer->fill(SColor(0));
37
38 // create z buffer
39 ZBuffer = video::createZBuffer(BackBuffer->getDimension());
40 }
41
42 DriverAttributes->setAttribute("MaxTextures", 1);
43 DriverAttributes->setAttribute("MaxIndices", 1<<16);
44 DriverAttributes->setAttribute("MaxTextureSize", 1024);
45 DriverAttributes->setAttribute("Version", 1);
46
47 // create triangle renderers
48
49 TriangleRenderers[ETR_FLAT] = createTriangleRendererFlat(ZBuffer);
50 TriangleRenderers[ETR_FLAT_WIRE] = createTriangleRendererFlatWire(ZBuffer);
51 TriangleRenderers[ETR_GOURAUD] = createTriangleRendererGouraud(ZBuffer);
52 TriangleRenderers[ETR_GOURAUD_WIRE] = createTriangleRendererGouraudWire(ZBuffer);
53 TriangleRenderers[ETR_TEXTURE_FLAT] = createTriangleRendererTextureFlat(ZBuffer);
54 TriangleRenderers[ETR_TEXTURE_FLAT_WIRE] = createTriangleRendererTextureFlatWire(ZBuffer);
55 TriangleRenderers[ETR_TEXTURE_GOURAUD] = createTriangleRendererTextureGouraud(ZBuffer);
56 TriangleRenderers[ETR_TEXTURE_GOURAUD_WIRE] = createTriangleRendererTextureGouraudWire(ZBuffer);
57 TriangleRenderers[ETR_TEXTURE_GOURAUD_NOZ] = createTriangleRendererTextureGouraudNoZ();
58 TriangleRenderers[ETR_TEXTURE_GOURAUD_ADD] = createTriangleRendererTextureGouraudAdd(ZBuffer);
59
60 // select render target
61
62 setRenderTarget(BackBuffer);
63
64 // select the right renderer
65
66 selectRightTriangleRenderer();
67 }
68
69
70
71 //! destructor
~CSoftwareDriver()72 CSoftwareDriver::~CSoftwareDriver()
73 {
74 // delete Backbuffer
75 if (BackBuffer)
76 BackBuffer->drop();
77
78 // delete triangle renderers
79
80 for (s32 i=0; i<ETR_COUNT; ++i)
81 if (TriangleRenderers[i])
82 TriangleRenderers[i]->drop();
83
84 // delete zbuffer
85
86 if (ZBuffer)
87 ZBuffer->drop();
88
89 // delete current texture
90
91 if (Texture)
92 Texture->drop();
93
94 if (RenderTargetTexture)
95 RenderTargetTexture->drop();
96
97 if (RenderTargetSurface)
98 RenderTargetSurface->drop();
99 }
100
101
102
103 //! switches to a triangle renderer
switchToTriangleRenderer(ETriangleRenderer renderer)104 void CSoftwareDriver::switchToTriangleRenderer(ETriangleRenderer renderer)
105 {
106 video::IImage* s = 0;
107 if (Texture)
108 s = ((CSoftwareTexture*)Texture)->getTexture();
109
110 CurrentTriangleRenderer = TriangleRenderers[renderer];
111 CurrentTriangleRenderer->setBackfaceCulling(Material.BackfaceCulling == true);
112 CurrentTriangleRenderer->setTexture(s);
113 CurrentTriangleRenderer->setRenderTarget(RenderTargetSurface, ViewPort);
114 }
115
116
117 //! void selects the right triangle renderer based on the render states.
selectRightTriangleRenderer()118 void CSoftwareDriver::selectRightTriangleRenderer()
119 {
120
121 ETriangleRenderer renderer = ETR_FLAT;
122
123 if (Texture)
124 {
125 if (!Material.GouraudShading)
126 renderer = (!Material.Wireframe) ? ETR_TEXTURE_FLAT : ETR_TEXTURE_FLAT_WIRE;
127 else
128 {
129 if (Material.Wireframe)
130 renderer = ETR_TEXTURE_GOURAUD_WIRE;
131 else
132 {
133 if (Material.MaterialType == EMT_TRANSPARENT_ADD_COLOR ||
134 Material.MaterialType == EMT_TRANSPARENT_ALPHA_CHANNEL ||
135 Material.MaterialType == EMT_TRANSPARENT_VERTEX_ALPHA)
136 {
137 // simply draw all transparent stuff with the same renderer. at
138 // least it is transparent then.
139 renderer = ETR_TEXTURE_GOURAUD_ADD;
140 }
141 else
142 if ((Material.ZBuffer==ECFN_NEVER) && !Material.ZWriteEnable)
143 renderer = ETR_TEXTURE_GOURAUD_NOZ;
144 else
145 {
146 renderer = ETR_TEXTURE_GOURAUD;
147 }
148 }
149 }
150 }
151 else
152 {
153 if (!Material.GouraudShading)
154 renderer = (!Material.Wireframe) ? ETR_FLAT : ETR_FLAT_WIRE;
155 else
156 renderer = (!Material.Wireframe) ? ETR_GOURAUD : ETR_GOURAUD_WIRE;
157 }
158
159 switchToTriangleRenderer(renderer);
160 }
161
162
163 //! queries the features of the driver, returns true if feature is available
queryFeature(E_VIDEO_DRIVER_FEATURE feature) const164 bool CSoftwareDriver::queryFeature(E_VIDEO_DRIVER_FEATURE feature) const
165 {
166 switch (feature)
167 {
168 case EVDF_RENDER_TO_TARGET:
169 case EVDF_TEXTURE_NSQUARE:
170 return FeatureEnabled[feature];
171 default:
172 return false;
173 };
174 }
175
176
177 //! sets transformation
setTransform(E_TRANSFORMATION_STATE state,const core::matrix4 & mat)178 void CSoftwareDriver::setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat)
179 {
180 TransformationMatrix[state] = mat;
181 }
182
183
184 //! sets the current Texture
setActiveTexture(u32 stage,video::ITexture * texture)185 bool CSoftwareDriver::setActiveTexture(u32 stage, video::ITexture* texture)
186 {
187 if (texture && texture->getDriverType() != EDT_SOFTWARE)
188 {
189 os::Printer::log("Fatal Error: Tried to set a texture not owned by this driver.", ELL_ERROR);
190 return false;
191 }
192
193 if (Texture)
194 Texture->drop();
195
196 Texture = texture;
197
198 if (Texture)
199 Texture->grab();
200
201 selectRightTriangleRenderer();
202 return true;
203 }
204
205
206 //! sets a material
setMaterial(const SMaterial & material)207 void CSoftwareDriver::setMaterial(const SMaterial& material)
208 {
209 Material = material;
210 OverrideMaterial.apply(Material);
211
212 for (u32 i = 0; i < 1; ++i)
213 {
214 setActiveTexture(i, Material.getTexture(i));
215 setTransform ((E_TRANSFORMATION_STATE) ( ETS_TEXTURE_0 + i ),
216 material.getTextureMatrix(i));
217 }
218 }
219
220
221 //! clears the zbuffer
beginScene(bool backBuffer,bool zBuffer,SColor color,const SExposedVideoData & videoData,core::rect<s32> * sourceRect)222 bool CSoftwareDriver::beginScene(bool backBuffer, bool zBuffer, SColor color,
223 const SExposedVideoData& videoData, core::rect<s32>* sourceRect)
224 {
225 CNullDriver::beginScene(backBuffer, zBuffer, color, videoData, sourceRect);
226 WindowId=videoData.D3D9.HWnd;
227 SceneSourceRect = sourceRect;
228
229 if (backBuffer && BackBuffer)
230 BackBuffer->fill(color);
231
232 if (ZBuffer && zBuffer)
233 ZBuffer->clear();
234
235 return true;
236 }
237
238
239 //! presents the rendered scene on the screen, returns false if failed
endScene()240 bool CSoftwareDriver::endScene()
241 {
242 CNullDriver::endScene();
243
244 return Presenter->present(BackBuffer, WindowId, SceneSourceRect);
245 }
246
247
248 //! returns a device dependent texture from a software surface (IImage)
249 //! THIS METHOD HAS TO BE OVERRIDDEN BY DERIVED DRIVERS WITH OWN TEXTURES
createDeviceDependentTexture(IImage * surface,const io::path & name,void * mipmapData)250 ITexture* CSoftwareDriver::createDeviceDependentTexture(IImage* surface, const io::path& name, void* mipmapData)
251 {
252 return new CSoftwareTexture(surface, name, false, mipmapData);
253 }
254
255
256 //! sets a render target
setRenderTarget(video::ITexture * texture,bool clearBackBuffer,bool clearZBuffer,SColor color)257 bool CSoftwareDriver::setRenderTarget(video::ITexture* texture, bool clearBackBuffer,
258 bool clearZBuffer, SColor color)
259 {
260 if (texture && texture->getDriverType() != EDT_SOFTWARE)
261 {
262 os::Printer::log("Fatal Error: Tried to set a texture not owned by this driver.", ELL_ERROR);
263 return false;
264 }
265
266 if (RenderTargetTexture)
267 RenderTargetTexture->drop();
268
269 RenderTargetTexture = texture;
270
271 if (RenderTargetTexture)
272 {
273 RenderTargetTexture->grab();
274 setRenderTarget(((CSoftwareTexture*)RenderTargetTexture)->getTexture());
275 }
276 else
277 {
278 setRenderTarget(BackBuffer);
279 }
280
281 if (RenderTargetSurface && (clearBackBuffer || clearZBuffer))
282 {
283 if (clearZBuffer)
284 ZBuffer->clear();
285
286 if (clearBackBuffer)
287 RenderTargetSurface->fill(color);
288 }
289
290 return true;
291 }
292
293
294 //! sets a render target
setRenderTarget(video::CImage * image)295 void CSoftwareDriver::setRenderTarget(video::CImage* image)
296 {
297 if (RenderTargetSurface)
298 RenderTargetSurface->drop();
299
300 RenderTargetSurface = image;
301 RenderTargetSize.Width = 0;
302 RenderTargetSize.Height = 0;
303 Render2DTranslation.X = 0;
304 Render2DTranslation.Y = 0;
305
306 if (RenderTargetSurface)
307 {
308 RenderTargetSurface->grab();
309 RenderTargetSize = RenderTargetSurface->getDimension();
310 }
311
312 setViewPort(core::rect<s32>(0,0,RenderTargetSize.Width,RenderTargetSize.Height));
313
314 if (ZBuffer)
315 ZBuffer->setSize(RenderTargetSize);
316 }
317
318
319 //! sets a viewport
setViewPort(const core::rect<s32> & area)320 void CSoftwareDriver::setViewPort(const core::rect<s32>& area)
321 {
322 ViewPort = area;
323
324 //TODO: the clipping is not correct, because the projection is affected.
325 // to correct this, ViewPortSize and Render2DTranslation will have to be corrected.
326 core::rect<s32> rendert(0,0,RenderTargetSize.Width,RenderTargetSize.Height);
327 ViewPort.clipAgainst(rendert);
328
329 ViewPortSize = core::dimension2du(ViewPort.getSize());
330 Render2DTranslation.X = (ViewPortSize.Width / 2) + ViewPort.UpperLeftCorner.X;
331 Render2DTranslation.Y = ViewPort.UpperLeftCorner.Y + ViewPortSize.Height - (ViewPortSize.Height / 2);// + ViewPort.UpperLeftCorner.Y;
332
333 if (CurrentTriangleRenderer)
334 CurrentTriangleRenderer->setRenderTarget(RenderTargetSurface, ViewPort);
335 }
336
337
drawVertexPrimitiveList(const void * vertices,u32 vertexCount,const void * indexList,u32 primitiveCount,E_VERTEX_TYPE vType,scene::E_PRIMITIVE_TYPE pType,E_INDEX_TYPE iType)338 void CSoftwareDriver::drawVertexPrimitiveList(const void* vertices, u32 vertexCount,
339 const void* indexList, u32 primitiveCount,
340 E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType)
341
342 {
343 switch (iType)
344 {
345 case (EIT_16BIT):
346 {
347 drawVertexPrimitiveList16(vertices, vertexCount, (const u16*)indexList, primitiveCount, vType, pType);
348 break;
349 }
350 case (EIT_32BIT):
351 {
352 os::Printer::log("Software driver can not render 32bit buffers", ELL_ERROR);
353 break;
354 }
355 }
356 }
357
358
359 //! draws a vertex primitive list
drawVertexPrimitiveList16(const void * vertices,u32 vertexCount,const u16 * indexList,u32 primitiveCount,E_VERTEX_TYPE vType,scene::E_PRIMITIVE_TYPE pType)360 void CSoftwareDriver::drawVertexPrimitiveList16(const void* vertices, u32 vertexCount, const u16* indexList, u32 primitiveCount, E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType)
361 {
362 const u16* indexPointer=0;
363 core::array<u16> newBuffer;
364 switch (pType)
365 {
366 case scene::EPT_LINE_STRIP:
367 {
368 switch (vType)
369 {
370 case EVT_STANDARD:
371 {
372 for (u32 i=0; i < primitiveCount-1; ++i)
373 draw3DLine(((S3DVertex*)vertices)[indexList[i]].Pos,
374 ((S3DVertex*)vertices)[indexList[i+1]].Pos,
375 ((S3DVertex*)vertices)[indexList[i]].Color);
376 }
377 break;
378 case EVT_2TCOORDS:
379 {
380 for (u32 i=0; i < primitiveCount-1; ++i)
381 draw3DLine(((S3DVertex2TCoords*)vertices)[indexList[i]].Pos,
382 ((S3DVertex2TCoords*)vertices)[indexList[i+1]].Pos,
383 ((S3DVertex2TCoords*)vertices)[indexList[i]].Color);
384 }
385 break;
386 case EVT_TANGENTS:
387 {
388 for (u32 i=0; i < primitiveCount-1; ++i)
389 draw3DLine(((S3DVertexTangents*)vertices)[indexList[i]].Pos,
390 ((S3DVertexTangents*)vertices)[indexList[i+1]].Pos,
391 ((S3DVertexTangents*)vertices)[indexList[i]].Color);
392 }
393 break;
394 }
395 }
396 return;
397 case scene::EPT_LINE_LOOP:
398 drawVertexPrimitiveList16(vertices, vertexCount, indexList, primitiveCount-1, vType, scene::EPT_LINE_STRIP);
399 switch (vType)
400 {
401 case EVT_STANDARD:
402 draw3DLine(((S3DVertex*)vertices)[indexList[primitiveCount-1]].Pos,
403 ((S3DVertex*)vertices)[indexList[0]].Pos,
404 ((S3DVertex*)vertices)[indexList[primitiveCount-1]].Color);
405 break;
406 case EVT_2TCOORDS:
407 draw3DLine(((S3DVertex2TCoords*)vertices)[indexList[primitiveCount-1]].Pos,
408 ((S3DVertex2TCoords*)vertices)[indexList[0]].Pos,
409 ((S3DVertex2TCoords*)vertices)[indexList[primitiveCount-1]].Color);
410 break;
411 case EVT_TANGENTS:
412 draw3DLine(((S3DVertexTangents*)vertices)[indexList[primitiveCount-1]].Pos,
413 ((S3DVertexTangents*)vertices)[indexList[0]].Pos,
414 ((S3DVertexTangents*)vertices)[indexList[primitiveCount-1]].Color);
415 break;
416 }
417 return;
418 case scene::EPT_LINES:
419 {
420 switch (vType)
421 {
422 case EVT_STANDARD:
423 {
424 for (u32 i=0; i < 2*primitiveCount; i+=2)
425 draw3DLine(((S3DVertex*)vertices)[indexList[i]].Pos,
426 ((S3DVertex*)vertices)[indexList[i+1]].Pos,
427 ((S3DVertex*)vertices)[indexList[i]].Color);
428 }
429 break;
430 case EVT_2TCOORDS:
431 {
432 for (u32 i=0; i < 2*primitiveCount; i+=2)
433 draw3DLine(((S3DVertex2TCoords*)vertices)[indexList[i]].Pos,
434 ((S3DVertex2TCoords*)vertices)[indexList[i+1]].Pos,
435 ((S3DVertex2TCoords*)vertices)[indexList[i]].Color);
436 }
437 break;
438 case EVT_TANGENTS:
439 {
440 for (u32 i=0; i < 2*primitiveCount; i+=2)
441 draw3DLine(((S3DVertexTangents*)vertices)[indexList[i]].Pos,
442 ((S3DVertexTangents*)vertices)[indexList[i+1]].Pos,
443 ((S3DVertexTangents*)vertices)[indexList[i]].Color);
444 }
445 break;
446 }
447 }
448 return;
449 case scene::EPT_TRIANGLE_FAN:
450 {
451 // TODO: don't convert fan to list
452 newBuffer.reallocate(primitiveCount*3);
453 for( u32 t=0; t<primitiveCount; ++t )
454 {
455 newBuffer.push_back(indexList[0]);
456 newBuffer.push_back(indexList[t+1]);
457 newBuffer.push_back(indexList[t+2]);
458 }
459
460 indexPointer = newBuffer.pointer();
461 }
462 break;
463 case scene::EPT_TRIANGLES:
464 indexPointer=indexList;
465 break;
466 default:
467 return;
468 }
469 switch (vType)
470 {
471 case EVT_STANDARD:
472 drawClippedIndexedTriangleListT((S3DVertex*)vertices, vertexCount, indexPointer, primitiveCount);
473 break;
474 case EVT_2TCOORDS:
475 drawClippedIndexedTriangleListT((S3DVertex2TCoords*)vertices, vertexCount, indexPointer, primitiveCount);
476 break;
477 case EVT_TANGENTS:
478 drawClippedIndexedTriangleListT((S3DVertexTangents*)vertices, vertexCount, indexPointer, primitiveCount);
479 break;
480 }
481 }
482
483
484 template<class VERTEXTYPE>
drawClippedIndexedTriangleListT(const VERTEXTYPE * vertices,s32 vertexCount,const u16 * indexList,s32 triangleCount)485 void CSoftwareDriver::drawClippedIndexedTriangleListT(const VERTEXTYPE* vertices,
486 s32 vertexCount, const u16* indexList, s32 triangleCount)
487 {
488 if (!RenderTargetSurface || !ZBuffer || !triangleCount)
489 return;
490
491 if (!checkPrimitiveCount(triangleCount))
492 return;
493
494 // arrays for storing clipped vertices
495 core::array<VERTEXTYPE> clippedVertices;
496 core::array<u16> clippedIndices;
497
498 // calculate inverse world transformation
499 core::matrix4 worldinv(TransformationMatrix[ETS_WORLD]);
500 worldinv.makeInverse();
501
502 // calculate view frustum planes
503 scene::SViewFrustum frustum(TransformationMatrix[ETS_PROJECTION] * TransformationMatrix[ETS_VIEW]);
504
505 // copy and transform clipping planes ignoring far plane
506 core::plane3df planes[5]; // ordered by near, left, right, bottom, top
507 for (int p=0; p<5; ++p)
508 worldinv.transformPlane(frustum.planes[p+1], planes[p]);
509
510 core::EIntersectionRelation3D inout[3]; // is point in front or back of plane?
511
512 // temporary buffer for vertices to be clipped by all planes
513 core::array<VERTEXTYPE> tClpBuf;
514 int t;
515
516 int i;
517 for (i=0; i<triangleCount; ++i) // for all input triangles
518 {
519 // add next triangle to tempClipBuffer
520 for (t=0; t<3; ++t)
521 tClpBuf.push_back(vertices[indexList[(i*3)+t]]);
522
523 for (int p=0; p<5; ++p) // for all clip planes
524 for (int v=0; v<(int)tClpBuf.size(); v+=3) // for all vertices in temp clip buffer
525 {
526 int inside = 0;
527 int outside = 0;
528
529 // test intersection relation of the current vertices
530 for (t=0; t<3; ++t)
531 {
532 inout[t] = planes[p].classifyPointRelation(tClpBuf[v+t].Pos);
533 if (inout[t] != core::ISREL3D_FRONT)
534 ++inside;
535 else
536 if (inout[t] == core::ISREL3D_FRONT)
537 ++outside;
538 }
539
540 if (!outside)
541 {
542 // add all vertices to new buffer, this triangle needs no clipping.
543 // so simply don't change this part of the temporary triangle buffer
544 continue;
545 }
546
547 if (!inside)
548 {
549 // all vertices are outside, don't add this triangle, so erase this
550 // triangle from the tClpBuf
551 tClpBuf.erase(v,3);
552 v -= 3;
553 continue;
554 }
555
556 // this vertex has to be clipped by this clipping plane.
557
558 // The following lines represent my try to implement some real clipping.
559 // There is a bug somewhere, and after some time I've given up.
560 // So now it is commented out, resulting that triangles which would need clipping
561 // are simply taken out (in the next two lines).
562 #ifndef __SOFTWARE_CLIPPING_PROBLEM__
563 tClpBuf.erase(v,3);
564 v -= 3;
565 #endif
566
567 /*
568 // my idea is the following:
569 // current vertex to next vertex relation:
570 // out - out : add nothing
571 // out - in : add middle point
572 // in - out : add first and middle point
573 // in - in : add both
574
575
576 // now based on the number of intersections, create new vertices
577 // into tClpBuf (at the front for not letting them be clipped again)
578
579 int added = 0;
580 int prev = v+2;
581 for (int index=v; index<v+3; ++index)
582 {
583 if (inout[prev] == core::ISREL3D_BACK)
584 {
585 if (inout[index] != core::ISREL3D_BACK)
586 {
587 VERTEXTYPE& vt1 = tClpBuf[prev];
588 VERTEXTYPE& vt2 = tClpBuf[index];
589
590 f32 fact = planes[p].getKnownIntersectionWithLine(vt1.Pos, vt2.Pos);
591 VERTEXTYPE nvt;
592 nvt.Pos = vt1.Pos.getInterpolated(vt2.Pos, fact);
593 nvt.Color = vt1.Color.getInterpolated(vt2.Color, fact);
594 nvt.TCoords = vt1.TCoords.getInterpolated(vt2.TCoords, fact);
595
596 tClpBuf.push_front(nvt); ++index; ++prev; ++v;
597 ++added;
598 }
599 }
600 else
601 {
602 if (inout[index] != core::ISREL3D_BACK)
603 {
604 VERTEXTYPE vt1 = tClpBuf[index];
605 VERTEXTYPE vt2 = tClpBuf[prev];
606 tClpBuf.push_front(vt1); ++index; ++prev; ++v;
607 tClpBuf.push_front(vt2); ++index; ++prev; ++v;
608 added+= 2;
609 }
610 else
611 {
612 // same as above, but other way round.
613 VERTEXTYPE vt1 = tClpBuf[index];
614 VERTEXTYPE vt2 = tClpBuf[prev];
615
616 f32 fact = planes[p].getKnownIntersectionWithLine(vt1.Pos, vt2.Pos);
617 VERTEXTYPE nvt;
618 nvt.Pos = vt1.Pos.getInterpolated(vt2.Pos, fact);
619 nvt.Color = vt1.Color.getInterpolated(vt2.Color, fact);
620 nvt.TCoords = vt1.TCoords.getInterpolated(vt2.TCoords, fact);
621
622 tClpBuf.push_front(vt2); ++index; ++prev; ++v;
623 tClpBuf.push_front(nvt); ++index; ++prev; ++v;
624 added += 2;
625 }
626 }
627
628 prev = index;
629 }
630
631 // erase original vertices
632 tClpBuf.erase(v,3);
633 v -= 3;
634 */
635
636
637 } // end for all clip planes
638
639 // now add all remaining triangles in tempClipBuffer to clippedIndices
640 // and clippedVertices array.
641 if (clippedIndices.size() + tClpBuf.size() < 65535)
642 for (t=0; t<(int)tClpBuf.size(); ++t)
643 {
644 clippedIndices.push_back(clippedVertices.size());
645 clippedVertices.push_back(tClpBuf[t]);
646 }
647 tClpBuf.clear();
648
649 } // end for all input triangles
650
651
652 // draw newly created triangles.
653
654 // -----------------------------------------------------------
655 // here all triangles are being drawn. I put this in a separate
656 // method, but the visual studio 6 compiler has great problems
657 // with templates and didn't accept two template methods in this
658 // class.
659
660 // draw triangles
661
662 CNullDriver::drawVertexPrimitiveList(clippedVertices.pointer(), clippedVertices.size(),
663 clippedIndices.pointer(), clippedIndices.size()/3, EVT_STANDARD, scene::EPT_TRIANGLES, EIT_16BIT);
664
665 if (TransformedPoints.size() < clippedVertices.size())
666 TransformedPoints.set_used(clippedVertices.size());
667
668 if (TransformedPoints.empty())
669 return;
670
671 const VERTEXTYPE* currentVertex = clippedVertices.pointer();
672 S2DVertex* tp = &TransformedPoints[0];
673
674 core::dimension2d<u32> textureSize(0,0);
675 f32 zDiv;
676
677 if (Texture)
678 textureSize = ((CSoftwareTexture*)Texture)->getTexture()->getDimension();
679
680 f32 transformedPos[4]; // transform all points in the list
681
682 core::matrix4 matrix(TransformationMatrix[ETS_PROJECTION]);
683 matrix *= TransformationMatrix[ETS_VIEW];
684 matrix *= TransformationMatrix[ETS_WORLD];
685
686 s32 ViewTransformWidth = (ViewPortSize.Width>>1);
687 s32 ViewTransformHeight = (ViewPortSize.Height>>1);
688
689 for (i=0; i<(int)clippedVertices.size(); ++i)
690 {
691 transformedPos[0] = currentVertex->Pos.X;
692 transformedPos[1] = currentVertex->Pos.Y;
693 transformedPos[2] = currentVertex->Pos.Z;
694 transformedPos[3] = 1.0f;
695
696 matrix.multiplyWith1x4Matrix(transformedPos);
697 zDiv = transformedPos[3] == 0.0f ? 1.0f : (1.0f / transformedPos[3]);
698
699 tp->Pos.X = (s32)(ViewTransformWidth * (transformedPos[0] * zDiv) + (Render2DTranslation.X));
700 tp->Pos.Y = (Render2DTranslation.Y - (s32)(ViewTransformHeight * (transformedPos[1] * zDiv)));
701 tp->Color = currentVertex->Color.toA1R5G5B5();
702 tp->ZValue = (TZBufferType)(32767.0f * zDiv);
703
704 tp->TCoords.X = (s32)(currentVertex->TCoords.X * textureSize.Width);
705 tp->TCoords.X <<= 8;
706 tp->TCoords.Y = (s32)(currentVertex->TCoords.Y * textureSize.Height);
707 tp->TCoords.Y <<= 8;
708
709 ++currentVertex;
710 ++tp;
711 }
712
713 // draw all transformed points from the index list
714 CurrentTriangleRenderer->drawIndexedTriangleList(&TransformedPoints[0],
715 clippedVertices.size(), clippedIndices.pointer(), clippedIndices.size()/3);
716 }
717
718
719 //! Draws a 3d line.
draw3DLine(const core::vector3df & start,const core::vector3df & end,SColor color)720 void CSoftwareDriver::draw3DLine(const core::vector3df& start,
721 const core::vector3df& end, SColor color)
722 {
723 core::vector3df vect = start.crossProduct(end);
724 vect.normalize();
725 vect *= Material.Thickness*0.3f;
726
727 S3DVertex vtx[4];
728
729 vtx[0].Color = color;
730 vtx[1].Color = color;
731 vtx[2].Color = color;
732 vtx[3].Color = color;
733
734 vtx[0].Pos = start;
735 vtx[1].Pos = end;
736
737 vtx[2].Pos = start + vect;
738 vtx[3].Pos = end + vect;
739
740 u16 idx[12] = {0,1,2, 0,2,1, 0,1,3, 0,3,1};
741
742 drawIndexedTriangleList(vtx, 4, idx, 4);
743 }
744
745
746 //! clips a triangle against the viewing frustum
clipTriangle(f32 * transformedPos)747 void CSoftwareDriver::clipTriangle(f32* transformedPos)
748 {
749 }
750
751
752 //! Only used by the internal engine. Used to notify the driver that
753 //! the window was resized.
OnResize(const core::dimension2d<u32> & size)754 void CSoftwareDriver::OnResize(const core::dimension2d<u32>& size)
755 {
756 // make sure width and height are multiples of 2
757 core::dimension2d<u32> realSize(size);
758
759 if (realSize.Width % 2)
760 realSize.Width += 1;
761
762 if (realSize.Height % 2)
763 realSize.Height += 1;
764
765 if (ScreenSize != realSize)
766 {
767 if (ViewPort.getWidth() == (s32)ScreenSize.Width &&
768 ViewPort.getHeight() == (s32)ScreenSize.Height)
769 {
770 ViewPort = core::rect<s32>(core::position2d<s32>(0,0),
771 core::dimension2di(realSize));
772 }
773
774 ScreenSize = realSize;
775
776 bool resetRT = (RenderTargetSurface == BackBuffer);
777
778 if (BackBuffer)
779 BackBuffer->drop();
780 BackBuffer = new CImage(ECF_A1R5G5B5, realSize);
781
782 if (resetRT)
783 setRenderTarget(BackBuffer);
784 }
785 }
786
787 //! returns the current render target size
getCurrentRenderTargetSize() const788 const core::dimension2d<u32>& CSoftwareDriver::getCurrentRenderTargetSize() const
789 {
790 return RenderTargetSize;
791 }
792
793
794 //! draws an 2d image, using a color (if color is other then Color(255,255,255,255)) and the alpha channel of the texture if wanted.
draw2DImage(const video::ITexture * texture,const core::position2d<s32> & destPos,const core::rect<s32> & sourceRect,const core::rect<s32> * clipRect,SColor color,bool useAlphaChannelOfTexture)795 void CSoftwareDriver::draw2DImage(const video::ITexture* texture, const core::position2d<s32>& destPos,
796 const core::rect<s32>& sourceRect,
797 const core::rect<s32>* clipRect, SColor color,
798 bool useAlphaChannelOfTexture)
799 {
800 if (texture)
801 {
802 if (texture->getDriverType() != EDT_SOFTWARE)
803 {
804 os::Printer::log("Fatal Error: Tried to copy from a surface not owned by this driver.", ELL_ERROR);
805 return;
806 }
807
808 if (useAlphaChannelOfTexture)
809 ((CSoftwareTexture*)texture)->getImage()->copyToWithAlpha(
810 RenderTargetSurface, destPos, sourceRect, color, clipRect);
811 else
812 ((CSoftwareTexture*)texture)->getImage()->copyTo(
813 RenderTargetSurface, destPos, sourceRect, clipRect);
814 }
815 }
816
817
818
819 //! Draws a 2d line.
draw2DLine(const core::position2d<s32> & start,const core::position2d<s32> & end,SColor color)820 void CSoftwareDriver::draw2DLine(const core::position2d<s32>& start,
821 const core::position2d<s32>& end,
822 SColor color)
823 {
824 drawLine(RenderTargetSurface, start, end, color );
825 }
826
827
828 //! Draws a pixel
drawPixel(u32 x,u32 y,const SColor & color)829 void CSoftwareDriver::drawPixel(u32 x, u32 y, const SColor & color)
830 {
831 BackBuffer->setPixel(x, y, color, true);
832 }
833
834
835 //! draw a 2d rectangle
draw2DRectangle(SColor color,const core::rect<s32> & pos,const core::rect<s32> * clip)836 void CSoftwareDriver::draw2DRectangle(SColor color, const core::rect<s32>& pos,
837 const core::rect<s32>* clip)
838 {
839 if (clip)
840 {
841 core::rect<s32> p(pos);
842
843 p.clipAgainst(*clip);
844
845 if(!p.isValid())
846 return;
847
848 drawRectangle(RenderTargetSurface, p, color);
849 }
850 else
851 {
852 if(!pos.isValid())
853 return;
854
855 drawRectangle(RenderTargetSurface, pos, color);
856 }
857 }
858
859
860 //!Draws an 2d rectangle with a gradient.
draw2DRectangle(const core::rect<s32> & pos,SColor colorLeftUp,SColor colorRightUp,SColor colorLeftDown,SColor colorRightDown,const core::rect<s32> * clip)861 void CSoftwareDriver::draw2DRectangle(const core::rect<s32>& pos,
862 SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown,
863 const core::rect<s32>* clip)
864 {
865 // TODO: implement
866 draw2DRectangle(colorLeftUp, pos, clip);
867 }
868
869
870 //! \return Returns the name of the video driver. Example: In case of the Direct3D8
871 //! driver, it would return "Direct3D8.1".
getName() const872 const wchar_t* CSoftwareDriver::getName() const
873 {
874 return L"Irrlicht Software Driver 1.0";
875 }
876
877
878 //! Returns type of video driver
getDriverType() const879 E_DRIVER_TYPE CSoftwareDriver::getDriverType() const
880 {
881 return EDT_SOFTWARE;
882 }
883
884
885 //! returns color format
getColorFormat() const886 ECOLOR_FORMAT CSoftwareDriver::getColorFormat() const
887 {
888 if (BackBuffer)
889 return BackBuffer->getColorFormat();
890 else
891 return CNullDriver::getColorFormat();
892 }
893
894
895 //! Returns the transformation set by setTransform
getTransform(E_TRANSFORMATION_STATE state) const896 const core::matrix4& CSoftwareDriver::getTransform(E_TRANSFORMATION_STATE state) const
897 {
898 return TransformationMatrix[state];
899 }
900
901
902 //! Creates a render target texture.
addRenderTargetTexture(const core::dimension2d<u32> & size,const io::path & name,const ECOLOR_FORMAT format)903 ITexture* CSoftwareDriver::addRenderTargetTexture(const core::dimension2d<u32>& size,
904 const io::path& name,
905 const ECOLOR_FORMAT format)
906 {
907 IImage* img = createImage(video::ECF_A1R5G5B5, size);
908 ITexture* tex = new CSoftwareTexture(img, name, true);
909 img->drop();
910 addTexture(tex);
911 tex->drop();
912 return tex;
913 }
914
915
916 //! Clears the ZBuffer.
clearZBuffer()917 void CSoftwareDriver::clearZBuffer()
918 {
919 if (ZBuffer)
920 ZBuffer->clear();
921 }
922
923
924 //! Returns an image created from the last rendered frame.
createScreenShot(video::ECOLOR_FORMAT format,video::E_RENDER_TARGET target)925 IImage* CSoftwareDriver::createScreenShot(video::ECOLOR_FORMAT format, video::E_RENDER_TARGET target)
926 {
927 if (target != video::ERT_FRAME_BUFFER)
928 return 0;
929
930 if (BackBuffer)
931 {
932 IImage* tmp = createImage(BackBuffer->getColorFormat(), BackBuffer->getDimension());
933 BackBuffer->copyTo(tmp);
934 return tmp;
935 }
936 else
937 return 0;
938 }
939
940
941 //! Returns the maximum amount of primitives (mostly vertices) which
942 //! the device is able to render with one drawIndexedTriangleList
943 //! call.
getMaximalPrimitiveCount() const944 u32 CSoftwareDriver::getMaximalPrimitiveCount() const
945 {
946 return 0x00800000;
947 }
948
949 } // end namespace video
950 } // end namespace irr
951
952 #endif // _IRR_COMPILE_WITH_SOFTWARE_
953
954 namespace irr
955 {
956 namespace video
957 {
958
959
960 //! creates a video driver
createSoftwareDriver(const core::dimension2d<u32> & windowSize,bool fullscreen,io::IFileSystem * io,video::IImagePresenter * presenter)961 IVideoDriver* createSoftwareDriver(const core::dimension2d<u32>& windowSize, bool fullscreen, io::IFileSystem* io, video::IImagePresenter* presenter)
962 {
963 #ifdef _IRR_COMPILE_WITH_SOFTWARE_
964 return new CSoftwareDriver(windowSize, fullscreen, io, presenter);
965 #else
966 return 0;
967 #endif
968 }
969
970
971 } // end namespace video
972 } // end namespace irr
973
974