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