GLES drivers adapted, but only did make compile-tests. git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/branches/ogl-es@6038 dfc29bdd-3216-0410-991c-e03cc46cb475
		
			
				
	
	
		
			977 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			977 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Copyright (C) 2002-2012 Nikolaus Gebhardt
 | |
| // This file is part of the "Irrlicht Engine".
 | |
| // For conditions of distribution and use, see copyright notice in irrlicht.h
 | |
| 
 | |
| #include "IrrCompileConfig.h"
 | |
| #include "CSoftwareDriver.h"
 | |
| 
 | |
| #ifdef _IRR_COMPILE_WITH_SOFTWARE_
 | |
| 
 | |
| #include "CSoftwareTexture.h"
 | |
| #include "CBlit.h"
 | |
| #include "os.h"
 | |
| #include "S3DVertex.h"
 | |
| 
 | |
| namespace irr
 | |
| {
 | |
| namespace video
 | |
| {
 | |
| 
 | |
| 
 | |
| //! constructor
 | |
| CSoftwareDriver::CSoftwareDriver(const core::dimension2d<u32>& windowSize, bool fullscreen, io::IFileSystem* io, video::IImagePresenter* presenter)
 | |
| : CNullDriver(io, windowSize), BackBuffer(0), Presenter(presenter), WindowId(0),
 | |
| 	SceneSourceRect(0), RenderTargetTexture(0), RenderTargetSurface(0),
 | |
| 	CurrentTriangleRenderer(0), ZBuffer(0), Texture(0)
 | |
| {
 | |
| 	#ifdef _DEBUG
 | |
| 	setDebugName("CSoftwareDriver");
 | |
| 	#endif
 | |
| 
 | |
| 	// create backbuffer
 | |
| 
 | |
| 	BackBuffer = new CImage(ECF_A1R5G5B5, windowSize);
 | |
| 	if (BackBuffer)
 | |
| 	{
 | |
| 		BackBuffer->fill(SColor(0));
 | |
| 
 | |
| 		// create z buffer
 | |
| 		ZBuffer = video::createZBuffer(BackBuffer->getDimension());
 | |
| 	}
 | |
| 
 | |
| 	DriverAttributes->setAttribute("MaxTextures", 1);
 | |
| 	DriverAttributes->setAttribute("MaxIndices", 1<<16);
 | |
| 	DriverAttributes->setAttribute("MaxTextureSize", 1024);
 | |
| 	DriverAttributes->setAttribute("Version", 1);
 | |
| 
 | |
| 	// create triangle renderers
 | |
| 
 | |
| 	TriangleRenderers[ETR_FLAT] = createTriangleRendererFlat(ZBuffer);
 | |
| 	TriangleRenderers[ETR_FLAT_WIRE] = createTriangleRendererFlatWire(ZBuffer);
 | |
| 	TriangleRenderers[ETR_GOURAUD] = createTriangleRendererGouraud(ZBuffer);
 | |
| 	TriangleRenderers[ETR_GOURAUD_WIRE] = createTriangleRendererGouraudWire(ZBuffer);
 | |
| 	TriangleRenderers[ETR_TEXTURE_FLAT] = createTriangleRendererTextureFlat(ZBuffer);
 | |
| 	TriangleRenderers[ETR_TEXTURE_FLAT_WIRE] = createTriangleRendererTextureFlatWire(ZBuffer);
 | |
| 	TriangleRenderers[ETR_TEXTURE_GOURAUD] = createTriangleRendererTextureGouraud(ZBuffer);
 | |
| 	TriangleRenderers[ETR_TEXTURE_GOURAUD_WIRE] = createTriangleRendererTextureGouraudWire(ZBuffer);
 | |
| 	TriangleRenderers[ETR_TEXTURE_GOURAUD_NOZ] = createTriangleRendererTextureGouraudNoZ();
 | |
| 	TriangleRenderers[ETR_TEXTURE_GOURAUD_ADD] = createTriangleRendererTextureGouraudAdd(ZBuffer);
 | |
| 
 | |
| 	// select render target
 | |
| 
 | |
| 	setRenderTargetImage(BackBuffer);
 | |
| 
 | |
| 	// select the right renderer
 | |
| 
 | |
| 	selectRightTriangleRenderer();
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| //! destructor
 | |
| CSoftwareDriver::~CSoftwareDriver()
 | |
| {
 | |
| 	// delete Backbuffer
 | |
| 	if (BackBuffer)
 | |
| 		BackBuffer->drop();
 | |
| 
 | |
| 	// delete triangle renderers
 | |
| 
 | |
| 	for (s32 i=0; i<ETR_COUNT; ++i)
 | |
| 		if (TriangleRenderers[i])
 | |
| 			TriangleRenderers[i]->drop();
 | |
| 
 | |
| 	// delete zbuffer
 | |
| 
 | |
| 	if (ZBuffer)
 | |
| 		ZBuffer->drop();
 | |
| 
 | |
| 	// delete current texture
 | |
| 
 | |
| 	if (Texture)
 | |
| 		Texture->drop();
 | |
| 
 | |
| 	if (RenderTargetTexture)
 | |
| 		RenderTargetTexture->drop();
 | |
| 
 | |
| 	if (RenderTargetSurface)
 | |
| 		RenderTargetSurface->drop();
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| //! switches to a triangle renderer
 | |
| void CSoftwareDriver::switchToTriangleRenderer(ETriangleRenderer renderer)
 | |
| {
 | |
| 	video::IImage* s = 0;
 | |
| 	if (Texture)
 | |
| 		s = ((CSoftwareTexture*)Texture)->getTexture();
 | |
| 
 | |
| 	CurrentTriangleRenderer = TriangleRenderers[renderer];
 | |
| 	CurrentTriangleRenderer->setBackfaceCulling(Material.BackfaceCulling == true);
 | |
| 	CurrentTriangleRenderer->setTexture(s);
 | |
| 	CurrentTriangleRenderer->setRenderTarget(RenderTargetSurface, ViewPort);
 | |
| }
 | |
| 
 | |
| 
 | |
| //! void selects the right triangle renderer based on the render states.
 | |
| void CSoftwareDriver::selectRightTriangleRenderer()
 | |
| {
 | |
| 
 | |
| 	ETriangleRenderer renderer = ETR_FLAT;
 | |
| 
 | |
| 	if (Texture)
 | |
| 	{
 | |
| 		if (!Material.GouraudShading)
 | |
| 			renderer = (!Material.Wireframe) ? ETR_TEXTURE_FLAT : ETR_TEXTURE_FLAT_WIRE;
 | |
| 		else
 | |
| 		{
 | |
| 			if (Material.Wireframe)
 | |
| 				renderer = ETR_TEXTURE_GOURAUD_WIRE;
 | |
| 			else
 | |
| 			{
 | |
| 				if (Material.MaterialType == EMT_TRANSPARENT_ADD_COLOR ||
 | |
| 						Material.MaterialType == EMT_TRANSPARENT_ALPHA_CHANNEL ||
 | |
| 						Material.MaterialType == EMT_TRANSPARENT_VERTEX_ALPHA)
 | |
| 				{
 | |
| 					// simply draw all transparent stuff with the same renderer. at
 | |
| 					// least it is transparent then.
 | |
| 					renderer = ETR_TEXTURE_GOURAUD_ADD;
 | |
| 				}
 | |
| 				else
 | |
| 				if ((Material.ZBuffer==ECFN_DISABLED) && Material.ZWriteEnable == video::EZW_OFF)
 | |
| 					renderer = ETR_TEXTURE_GOURAUD_NOZ;
 | |
| 				else
 | |
| 				{
 | |
| 					renderer = ETR_TEXTURE_GOURAUD;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		if (!Material.GouraudShading)
 | |
| 			renderer = (!Material.Wireframe) ? ETR_FLAT : ETR_FLAT_WIRE;
 | |
| 		else
 | |
| 			renderer = (!Material.Wireframe) ? ETR_GOURAUD : ETR_GOURAUD_WIRE;
 | |
| 	}
 | |
| 
 | |
| 	switchToTriangleRenderer(renderer);
 | |
| }
 | |
| 
 | |
| 
 | |
| //! queries the features of the driver, returns true if feature is available
 | |
| bool CSoftwareDriver::queryFeature(E_VIDEO_DRIVER_FEATURE feature) const
 | |
| {
 | |
| 	switch (feature)
 | |
| 	{
 | |
| 	case EVDF_RENDER_TO_TARGET:
 | |
| 	case EVDF_TEXTURE_NSQUARE:
 | |
| 		return FeatureEnabled[feature];
 | |
| 	default:
 | |
| 		return false;
 | |
| 	};
 | |
| }
 | |
| 
 | |
| 
 | |
| //! Create render target.
 | |
| IRenderTarget* CSoftwareDriver::addRenderTarget()
 | |
| {
 | |
| 	CSoftwareRenderTarget* renderTarget = new CSoftwareRenderTarget(this);
 | |
| 	RenderTargets.push_back(renderTarget);
 | |
| 
 | |
| 	return renderTarget;
 | |
| }
 | |
| 
 | |
| 
 | |
| //! sets transformation
 | |
| void CSoftwareDriver::setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat)
 | |
| {
 | |
| 	TransformationMatrix[state] = mat;
 | |
| }
 | |
| 
 | |
| 
 | |
| //! sets the current Texture
 | |
| bool CSoftwareDriver::setActiveTexture(u32 stage, video::ITexture* texture)
 | |
| {
 | |
| 	if (texture && texture->getDriverType() != EDT_SOFTWARE)
 | |
| 	{
 | |
| 		os::Printer::log("Fatal Error: Tried to set a texture not owned by this driver.", ELL_ERROR);
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	if (Texture)
 | |
| 		Texture->drop();
 | |
| 
 | |
| 	Texture = texture;
 | |
| 
 | |
| 	if (Texture)
 | |
| 		Texture->grab();
 | |
| 
 | |
| 	selectRightTriangleRenderer();
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| 
 | |
| //! sets a material
 | |
| void CSoftwareDriver::setMaterial(const SMaterial& material)
 | |
| {
 | |
| 	Material = material;
 | |
| 	OverrideMaterial.apply(Material);
 | |
| 
 | |
| 	for (u32 i = 0; i < 1; ++i)
 | |
| 	{
 | |
| 		setActiveTexture(i, Material.getTexture(i));
 | |
| 		setTransform ((E_TRANSFORMATION_STATE) ( ETS_TEXTURE_0 + i ),
 | |
| 				material.getTextureMatrix(i));
 | |
| 	}
 | |
| }
 | |
| 
 | |
| bool CSoftwareDriver::beginScene(u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil, const SExposedVideoData& videoData, core::rect<s32>* sourceRect)
 | |
| {
 | |
| 	CNullDriver::beginScene(clearFlag, clearColor, clearDepth, clearStencil, videoData, sourceRect);
 | |
| 	WindowId=videoData.D3D9.HWnd;
 | |
| 	SceneSourceRect = sourceRect;
 | |
| 
 | |
| 	clearBuffers(clearFlag, clearColor, clearDepth, clearStencil);
 | |
| 
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| bool CSoftwareDriver::endScene()
 | |
| {
 | |
| 	CNullDriver::endScene();
 | |
| 
 | |
| 	return Presenter->present(BackBuffer, WindowId, SceneSourceRect);
 | |
| }
 | |
| 
 | |
| ITexture* CSoftwareDriver::createDeviceDependentTexture(const io::path& name, IImage* image)
 | |
| {
 | |
| 	CSoftwareTexture* texture = new CSoftwareTexture(image, name, false);
 | |
| 
 | |
| 	return texture;
 | |
| }
 | |
| 
 | |
| ITexture* CSoftwareDriver::createDeviceDependentTextureCubemap(const io::path& name, const core::array<IImage*>& image)
 | |
| {
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| bool CSoftwareDriver::setRenderTargetEx(IRenderTarget* target, u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil)
 | |
| {
 | |
| 	if (target && target->getDriverType() != EDT_SOFTWARE)
 | |
| 	{
 | |
| 		os::Printer::log("Fatal Error: Tried to set a render target not owned by this driver.", ELL_ERROR);
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	if (RenderTargetTexture)
 | |
| 		RenderTargetTexture->drop();
 | |
| 
 | |
| 	CSoftwareRenderTarget* renderTarget = static_cast<CSoftwareRenderTarget*>(target);
 | |
| 	RenderTargetTexture = (renderTarget) ? renderTarget->getTexture() : 0;
 | |
| 
 | |
| 	if (RenderTargetTexture)
 | |
| 	{
 | |
| 		RenderTargetTexture->grab();
 | |
| 		setRenderTargetImage(((CSoftwareTexture*)RenderTargetTexture)->getTexture());
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		setRenderTargetImage(BackBuffer);
 | |
| 	}
 | |
| 
 | |
| 	clearBuffers(clearFlag, clearColor, clearDepth, clearStencil);
 | |
| 
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| 
 | |
| //! sets a render target
 | |
| void CSoftwareDriver::setRenderTargetImage(video::CImage* image)
 | |
| {
 | |
| 	if (RenderTargetSurface)
 | |
| 		RenderTargetSurface->drop();
 | |
| 
 | |
| 	RenderTargetSurface = image;
 | |
| 	RenderTargetSize.Width = 0;
 | |
| 	RenderTargetSize.Height = 0;
 | |
| 	Render2DTranslation.X = 0;
 | |
| 	Render2DTranslation.Y = 0;
 | |
| 
 | |
| 	if (RenderTargetSurface)
 | |
| 	{
 | |
| 		RenderTargetSurface->grab();
 | |
| 		RenderTargetSize = RenderTargetSurface->getDimension();
 | |
| 	}
 | |
| 
 | |
| 	setViewPort(core::rect<s32>(0,0,RenderTargetSize.Width,RenderTargetSize.Height));
 | |
| 
 | |
| 	if (ZBuffer)
 | |
| 		ZBuffer->setSize(RenderTargetSize);
 | |
| }
 | |
| 
 | |
| 
 | |
| //! sets a viewport
 | |
| void CSoftwareDriver::setViewPort(const core::rect<s32>& area)
 | |
| {
 | |
| 	ViewPort = area;
 | |
| 
 | |
| 	//TODO: the clipping is not correct, because the projection is affected.
 | |
| 	// to correct this, ViewPortSize and Render2DTranslation will have to be corrected.
 | |
| 	core::rect<s32> rendert(0,0,RenderTargetSize.Width,RenderTargetSize.Height);
 | |
| 	ViewPort.clipAgainst(rendert);
 | |
| 
 | |
| 	ViewPortSize = core::dimension2du(ViewPort.getSize());
 | |
| 	Render2DTranslation.X = (ViewPortSize.Width / 2) + ViewPort.UpperLeftCorner.X;
 | |
| 	Render2DTranslation.Y = ViewPort.UpperLeftCorner.Y + ViewPortSize.Height - (ViewPortSize.Height / 2);// + ViewPort.UpperLeftCorner.Y;
 | |
| 
 | |
| 	if (CurrentTriangleRenderer)
 | |
| 		CurrentTriangleRenderer->setRenderTarget(RenderTargetSurface, ViewPort);
 | |
| }
 | |
| 
 | |
| 
 | |
| void CSoftwareDriver::drawVertexPrimitiveList(const void* vertices, u32 vertexCount,
 | |
| 				const void* indexList, u32 primitiveCount,
 | |
| 				E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType)
 | |
| 
 | |
| {
 | |
| 	switch (iType)
 | |
| 	{
 | |
| 		case (EIT_16BIT):
 | |
| 		{
 | |
| 			drawVertexPrimitiveList16(vertices, vertexCount, (const u16*)indexList, primitiveCount, vType, pType);
 | |
| 			break;
 | |
| 		}
 | |
| 		case (EIT_32BIT):
 | |
| 		{
 | |
| 			os::Printer::log("Software driver can not render 32bit buffers", ELL_ERROR);
 | |
| 			break;
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| //! draws a vertex primitive list
 | |
| void CSoftwareDriver::drawVertexPrimitiveList16(const void* vertices, u32 vertexCount, const u16* indexList, u32 primitiveCount, E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType)
 | |
| {
 | |
| 	const u16* indexPointer=0;
 | |
| 	core::array<u16> newBuffer;
 | |
| 	switch (pType)
 | |
| 	{
 | |
| 		case scene::EPT_LINE_STRIP:
 | |
| 			{
 | |
| 				switch (vType)
 | |
| 				{
 | |
| 					case EVT_STANDARD:
 | |
| 						{
 | |
| 							for (u32 i=0; i < primitiveCount-1; ++i)
 | |
| 								draw3DLine(((S3DVertex*)vertices)[indexList[i]].Pos,
 | |
| 									((S3DVertex*)vertices)[indexList[i+1]].Pos,
 | |
| 									((S3DVertex*)vertices)[indexList[i]].Color);
 | |
| 						}
 | |
| 						break;
 | |
| 					case EVT_2TCOORDS:
 | |
| 						{
 | |
| 							for (u32 i=0; i < primitiveCount-1; ++i)
 | |
| 								draw3DLine(((S3DVertex2TCoords*)vertices)[indexList[i]].Pos,
 | |
| 									((S3DVertex2TCoords*)vertices)[indexList[i+1]].Pos,
 | |
| 									((S3DVertex2TCoords*)vertices)[indexList[i]].Color);
 | |
| 						}
 | |
| 						break;
 | |
| 					case EVT_TANGENTS:
 | |
| 						{
 | |
| 							for (u32 i=0; i < primitiveCount-1; ++i)
 | |
| 								draw3DLine(((S3DVertexTangents*)vertices)[indexList[i]].Pos,
 | |
| 									((S3DVertexTangents*)vertices)[indexList[i+1]].Pos,
 | |
| 									((S3DVertexTangents*)vertices)[indexList[i]].Color);
 | |
| 						}
 | |
| 						break;
 | |
| 				}
 | |
| 			}
 | |
| 			return;
 | |
| 		case scene::EPT_LINE_LOOP:
 | |
| 			drawVertexPrimitiveList16(vertices, vertexCount, indexList, primitiveCount-1, vType, scene::EPT_LINE_STRIP);
 | |
| 			switch (vType)
 | |
| 			{
 | |
| 				case EVT_STANDARD:
 | |
| 					draw3DLine(((S3DVertex*)vertices)[indexList[primitiveCount-1]].Pos,
 | |
| 						((S3DVertex*)vertices)[indexList[0]].Pos,
 | |
| 						((S3DVertex*)vertices)[indexList[primitiveCount-1]].Color);
 | |
| 					break;
 | |
| 				case EVT_2TCOORDS:
 | |
| 					draw3DLine(((S3DVertex2TCoords*)vertices)[indexList[primitiveCount-1]].Pos,
 | |
| 						((S3DVertex2TCoords*)vertices)[indexList[0]].Pos,
 | |
| 						((S3DVertex2TCoords*)vertices)[indexList[primitiveCount-1]].Color);
 | |
| 					break;
 | |
| 				case EVT_TANGENTS:
 | |
| 					draw3DLine(((S3DVertexTangents*)vertices)[indexList[primitiveCount-1]].Pos,
 | |
| 						((S3DVertexTangents*)vertices)[indexList[0]].Pos,
 | |
| 						((S3DVertexTangents*)vertices)[indexList[primitiveCount-1]].Color);
 | |
| 					break;
 | |
| 			}
 | |
| 			return;
 | |
| 		case scene::EPT_LINES:
 | |
| 			{
 | |
| 				switch (vType)
 | |
| 				{
 | |
| 					case EVT_STANDARD:
 | |
| 						{
 | |
| 							for (u32 i=0; i < 2*primitiveCount; i+=2)
 | |
| 								draw3DLine(((S3DVertex*)vertices)[indexList[i]].Pos,
 | |
| 									((S3DVertex*)vertices)[indexList[i+1]].Pos,
 | |
| 									((S3DVertex*)vertices)[indexList[i]].Color);
 | |
| 						}
 | |
| 						break;
 | |
| 					case EVT_2TCOORDS:
 | |
| 						{
 | |
| 							for (u32 i=0; i < 2*primitiveCount; i+=2)
 | |
| 								draw3DLine(((S3DVertex2TCoords*)vertices)[indexList[i]].Pos,
 | |
| 									((S3DVertex2TCoords*)vertices)[indexList[i+1]].Pos,
 | |
| 									((S3DVertex2TCoords*)vertices)[indexList[i]].Color);
 | |
| 						}
 | |
| 						break;
 | |
| 					case EVT_TANGENTS:
 | |
| 						{
 | |
| 							for (u32 i=0; i < 2*primitiveCount; i+=2)
 | |
| 								draw3DLine(((S3DVertexTangents*)vertices)[indexList[i]].Pos,
 | |
| 									((S3DVertexTangents*)vertices)[indexList[i+1]].Pos,
 | |
| 									((S3DVertexTangents*)vertices)[indexList[i]].Color);
 | |
| 						}
 | |
| 						break;
 | |
| 				}
 | |
| 			}
 | |
| 			return;
 | |
| 		case scene::EPT_TRIANGLE_FAN:
 | |
| 			{
 | |
| 				// TODO: don't convert fan to list
 | |
| 				newBuffer.reallocate(primitiveCount*3);
 | |
| 				for( u32 t=0; t<primitiveCount; ++t )
 | |
| 				{
 | |
| 					newBuffer.push_back(indexList[0]);
 | |
| 					newBuffer.push_back(indexList[t+1]);
 | |
| 					newBuffer.push_back(indexList[t+2]);
 | |
| 				}
 | |
| 
 | |
| 				indexPointer = newBuffer.pointer();
 | |
| 			}
 | |
| 			break;
 | |
| 		case scene::EPT_TRIANGLES:
 | |
| 			indexPointer=indexList;
 | |
| 			break;
 | |
| 		default:
 | |
| 			return;
 | |
| 	}
 | |
| 	switch (vType)
 | |
| 	{
 | |
| 		case EVT_STANDARD:
 | |
| 			drawClippedIndexedTriangleListT((S3DVertex*)vertices, vertexCount, indexPointer, primitiveCount);
 | |
| 			break;
 | |
| 		case EVT_2TCOORDS:
 | |
| 			drawClippedIndexedTriangleListT((S3DVertex2TCoords*)vertices, vertexCount, indexPointer, primitiveCount);
 | |
| 			break;
 | |
| 		case EVT_TANGENTS:
 | |
| 			drawClippedIndexedTriangleListT((S3DVertexTangents*)vertices, vertexCount, indexPointer, primitiveCount);
 | |
| 			break;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| template<class VERTEXTYPE>
 | |
| void CSoftwareDriver::drawClippedIndexedTriangleListT(const VERTEXTYPE* vertices,
 | |
| 	s32 vertexCount, const u16* indexList, s32 triangleCount)
 | |
| {
 | |
| 	if (!RenderTargetSurface || !ZBuffer || !triangleCount)
 | |
| 		return;
 | |
| 
 | |
| 	if (!checkPrimitiveCount(triangleCount))
 | |
| 		return;
 | |
| 
 | |
| 	// arrays for storing clipped vertices
 | |
| 	core::array<VERTEXTYPE> clippedVertices;
 | |
| 	core::array<u16> clippedIndices;
 | |
| 
 | |
| 	// calculate inverse world transformation
 | |
| 	core::matrix4 worldinv(TransformationMatrix[ETS_WORLD]);
 | |
| 	worldinv.makeInverse();
 | |
| 
 | |
| 	// calculate view frustum planes
 | |
| 	scene::SViewFrustum frustum(TransformationMatrix[ETS_PROJECTION] * TransformationMatrix[ETS_VIEW], true);
 | |
| 
 | |
| 	// copy and transform clipping planes ignoring far plane
 | |
| 	core::plane3df planes[5]; // ordered by near, left, right, bottom, top
 | |
| 	for (int p=0; p<5; ++p)
 | |
| 		worldinv.transformPlane(frustum.planes[p+1], planes[p]);
 | |
| 
 | |
| 	core::EIntersectionRelation3D inout[3]; // is point in front or back of plane?
 | |
| 
 | |
| 	// temporary buffer for vertices to be clipped by all planes
 | |
| 	core::array<VERTEXTYPE> tClpBuf;
 | |
| 	int t;
 | |
| 
 | |
| 	int i;
 | |
| 	for (i=0; i<triangleCount; ++i) // for all input triangles
 | |
| 	{
 | |
| 		// add next triangle to tempClipBuffer
 | |
| 		for (t=0; t<3; ++t)
 | |
| 			tClpBuf.push_back(vertices[indexList[(i*3)+t]]);
 | |
| 
 | |
| 		for (int p=0; p<5; ++p) // for all clip planes
 | |
| 		for (int v=0; v<(int)tClpBuf.size(); v+=3) // for all vertices in temp clip buffer
 | |
| 		{
 | |
| 			int inside = 0;
 | |
| 			int outside = 0;
 | |
| 
 | |
| 			// test intersection relation of the current vertices
 | |
| 			for (t=0; t<3; ++t)
 | |
| 			{
 | |
| 				inout[t] = planes[p].classifyPointRelation(tClpBuf[v+t].Pos);
 | |
| 				if (inout[t] != core::ISREL3D_FRONT)
 | |
| 					++inside;
 | |
| 				else
 | |
| 				if (inout[t] == core::ISREL3D_FRONT)
 | |
| 					++outside;
 | |
| 			}
 | |
| 
 | |
| 			if (!outside)
 | |
| 			{
 | |
| 				// add all vertices to new buffer, this triangle needs no clipping.
 | |
| 				// so simply don't change this part of the temporary triangle buffer
 | |
| 				continue;
 | |
| 			}
 | |
| 
 | |
| 			if (!inside)
 | |
| 			{
 | |
| 				// all vertices are outside, don't add this triangle, so erase this
 | |
| 				// triangle from the tClpBuf
 | |
| 				tClpBuf.erase(v,3);
 | |
| 				v -= 3;
 | |
| 				continue;
 | |
| 			}
 | |
| 
 | |
| 			// this vertex has to be clipped by this clipping plane.
 | |
| 
 | |
| 			// The following lines represent my try to implement some real clipping.
 | |
| 			// There is a bug somewhere, and after some time I've given up.
 | |
| 			// So now it is commented out, resulting that triangles which would need clipping
 | |
| 			// are simply taken out (in the next two lines).
 | |
| #ifndef __SOFTWARE_CLIPPING_PROBLEM__
 | |
| 			tClpBuf.erase(v,3);
 | |
| 			v -= 3;
 | |
| #endif
 | |
| 
 | |
| 			/*
 | |
| 			// my idea is the following:
 | |
| 			// current vertex to next vertex relation:
 | |
| 			// out - out : add nothing
 | |
| 			// out -  in : add middle point
 | |
| 			// in -  out : add first and middle point
 | |
| 			// in -   in : add both
 | |
| 
 | |
| 
 | |
| 			// now based on the number of intersections, create new vertices
 | |
| 			// into tClpBuf (at the front for not letting them be clipped again)
 | |
| 
 | |
| 			int added = 0;
 | |
| 			int prev = v+2;
 | |
| 			for (int index=v; index<v+3; ++index)
 | |
| 			{
 | |
| 				if (inout[prev] == core::ISREL3D_BACK)
 | |
| 				{
 | |
| 					if (inout[index] != core::ISREL3D_BACK)
 | |
| 					{
 | |
| 						VERTEXTYPE& vt1 = tClpBuf[prev];
 | |
| 						VERTEXTYPE& vt2 = tClpBuf[index];
 | |
| 
 | |
| 						f32 fact = planes[p].getKnownIntersectionWithLine(vt1.Pos, vt2.Pos);
 | |
| 						VERTEXTYPE nvt;
 | |
| 						nvt.Pos = vt1.Pos.getInterpolated(vt2.Pos, fact);
 | |
| 						nvt.Color = vt1.Color.getInterpolated(vt2.Color, fact);
 | |
| 						nvt.TCoords = vt1.TCoords.getInterpolated(vt2.TCoords, fact);
 | |
| 
 | |
| 						tClpBuf.push_front(nvt); ++index; ++prev; ++v;
 | |
| 						++added;
 | |
| 					}
 | |
| 				}
 | |
| 				else
 | |
| 				{
 | |
| 					if (inout[index] != core::ISREL3D_BACK)
 | |
| 					{
 | |
| 						VERTEXTYPE vt1 = tClpBuf[index];
 | |
| 						VERTEXTYPE vt2 = tClpBuf[prev];
 | |
| 						tClpBuf.push_front(vt1); ++index; ++prev; ++v;
 | |
| 						tClpBuf.push_front(vt2); ++index; ++prev; ++v;
 | |
| 						added+= 2;
 | |
| 					}
 | |
| 					else
 | |
| 					{
 | |
| 						// same as above, but other way round.
 | |
| 						VERTEXTYPE vt1 = tClpBuf[index];
 | |
| 						VERTEXTYPE vt2 = tClpBuf[prev];
 | |
| 
 | |
| 						f32 fact = planes[p].getKnownIntersectionWithLine(vt1.Pos, vt2.Pos);
 | |
| 						VERTEXTYPE nvt;
 | |
| 						nvt.Pos = vt1.Pos.getInterpolated(vt2.Pos, fact);
 | |
| 						nvt.Color = vt1.Color.getInterpolated(vt2.Color, fact);
 | |
| 						nvt.TCoords = vt1.TCoords.getInterpolated(vt2.TCoords, fact);
 | |
| 
 | |
| 						tClpBuf.push_front(vt2); ++index; ++prev; ++v;
 | |
| 						tClpBuf.push_front(nvt); ++index; ++prev; ++v;
 | |
| 						added += 2;
 | |
| 					}
 | |
| 				}
 | |
| 
 | |
| 				prev = index;
 | |
| 			}
 | |
| 
 | |
| 			// erase original vertices
 | |
| 			tClpBuf.erase(v,3);
 | |
| 			v -= 3;
 | |
| 			*/
 | |
| 
 | |
| 
 | |
| 		} // end for all clip planes
 | |
| 
 | |
| 		// now add all remaining triangles in tempClipBuffer to clippedIndices
 | |
| 		// and clippedVertices array.
 | |
| 		if (clippedIndices.size() + tClpBuf.size() < 65535)
 | |
| 		for (t=0; t<(int)tClpBuf.size(); ++t)
 | |
| 		{
 | |
| 			clippedIndices.push_back(clippedVertices.size());
 | |
| 			clippedVertices.push_back(tClpBuf[t]);
 | |
| 		}
 | |
| 		tClpBuf.clear();
 | |
| 
 | |
| 	} // end for all input triangles
 | |
| 
 | |
| 
 | |
| 	// draw newly created triangles.
 | |
| 
 | |
| 	// -----------------------------------------------------------
 | |
| 	// here all triangles are being drawn. I put this in a separate
 | |
| 	// method, but the visual studio 6 compiler has great problems
 | |
| 	// with templates and didn't accept two template methods in this
 | |
| 	// class.
 | |
| 
 | |
| 	// draw triangles
 | |
| 
 | |
| 	CNullDriver::drawVertexPrimitiveList(clippedVertices.pointer(), clippedVertices.size(),
 | |
| 		clippedIndices.pointer(), clippedIndices.size()/3, EVT_STANDARD, scene::EPT_TRIANGLES, EIT_16BIT);
 | |
| 
 | |
| 	if (TransformedPoints.size() < clippedVertices.size())
 | |
| 		TransformedPoints.set_used(clippedVertices.size());
 | |
| 
 | |
| 	if (TransformedPoints.empty())
 | |
| 		return;
 | |
| 
 | |
| 	const VERTEXTYPE* currentVertex = clippedVertices.pointer();
 | |
| 	S2DVertex* tp = &TransformedPoints[0];
 | |
| 
 | |
| 	core::dimension2d<u32> textureSize(0,0);
 | |
| 	f32 zDiv;
 | |
| 
 | |
| 	if (Texture)
 | |
| 		textureSize = ((CSoftwareTexture*)Texture)->getTexture()->getDimension();
 | |
| 
 | |
| 	f32 transformedPos[4]; // transform all points in the list
 | |
| 
 | |
| 	core::matrix4 matrix(TransformationMatrix[ETS_PROJECTION]);
 | |
| 	matrix *= TransformationMatrix[ETS_VIEW];
 | |
| 	matrix *= TransformationMatrix[ETS_WORLD];
 | |
| 
 | |
| 	s32 ViewTransformWidth = (ViewPortSize.Width>>1);
 | |
| 	s32 ViewTransformHeight = (ViewPortSize.Height>>1);
 | |
| 
 | |
| 	for (i=0; i<(int)clippedVertices.size(); ++i)
 | |
| 	{
 | |
| 		transformedPos[0] = currentVertex->Pos.X;
 | |
| 		transformedPos[1] = currentVertex->Pos.Y;
 | |
| 		transformedPos[2] = currentVertex->Pos.Z;
 | |
| 		transformedPos[3] = 1.0f;
 | |
| 
 | |
| 		matrix.multiplyWith1x4Matrix(transformedPos);
 | |
| 		zDiv = transformedPos[3] == 0.0f ? 1.0f : (1.0f / transformedPos[3]);
 | |
| 
 | |
| 		tp->Pos.X = (s32)(ViewTransformWidth * (transformedPos[0] * zDiv) + (Render2DTranslation.X));
 | |
| 		tp->Pos.Y = (Render2DTranslation.Y - (s32)(ViewTransformHeight * (transformedPos[1] * zDiv)));
 | |
| 		tp->Color = currentVertex->Color.toA1R5G5B5();
 | |
| 		tp->ZValue = (TZBufferType)(32767.0f * zDiv);
 | |
| 
 | |
| 		tp->TCoords.X = (s32)(currentVertex->TCoords.X * textureSize.Width);
 | |
| 		tp->TCoords.X <<= 8;
 | |
| 		tp->TCoords.Y = (s32)(currentVertex->TCoords.Y * textureSize.Height);
 | |
| 		tp->TCoords.Y <<= 8;
 | |
| 
 | |
| 		++currentVertex;
 | |
| 		++tp;
 | |
| 	}
 | |
| 
 | |
| 	// draw all transformed points from the index list
 | |
| 	CurrentTriangleRenderer->drawIndexedTriangleList(&TransformedPoints[0],
 | |
| 		clippedVertices.size(), clippedIndices.pointer(), clippedIndices.size()/3);
 | |
| }
 | |
| 
 | |
| 
 | |
| //! Draws a 3d line.
 | |
| void CSoftwareDriver::draw3DLine(const core::vector3df& start,
 | |
| 				const core::vector3df& end, SColor color)
 | |
| {
 | |
| 	core::vector3df vect = start.crossProduct(end);
 | |
| 	vect.normalize();
 | |
| 	vect *= Material.Thickness*0.3f;
 | |
| 
 | |
| 	S3DVertex vtx[4];
 | |
| 
 | |
| 	vtx[0].Color = color;
 | |
| 	vtx[1].Color = color;
 | |
| 	vtx[2].Color = color;
 | |
| 	vtx[3].Color = color;
 | |
| 
 | |
| 	vtx[0].Pos = start;
 | |
| 	vtx[1].Pos = end;
 | |
| 
 | |
| 	vtx[2].Pos = start + vect;
 | |
| 	vtx[3].Pos = end + vect;
 | |
| 
 | |
| 	u16 idx[12] = {0,1,2, 0,2,1, 0,1,3, 0,3,1};
 | |
| 
 | |
| 	drawIndexedTriangleList(vtx, 4, idx, 4);
 | |
| }
 | |
| 
 | |
| 
 | |
| //! clips a triangle against the viewing frustum
 | |
| void CSoftwareDriver::clipTriangle(f32* transformedPos)
 | |
| {
 | |
| }
 | |
| 
 | |
| 
 | |
| //! Only used by the internal engine. Used to notify the driver that
 | |
| //! the window was resized.
 | |
| void CSoftwareDriver::OnResize(const core::dimension2d<u32>& size)
 | |
| {
 | |
| 	// make sure width and height are multiples of 2
 | |
| 	core::dimension2d<u32> realSize(size);
 | |
| 
 | |
| 	if (realSize.Width % 2)
 | |
| 		realSize.Width += 1;
 | |
| 
 | |
| 	if (realSize.Height % 2)
 | |
| 		realSize.Height += 1;
 | |
| 
 | |
| 	if (ScreenSize != realSize)
 | |
| 	{
 | |
| 		if (ViewPort.getWidth() == (s32)ScreenSize.Width &&
 | |
| 			ViewPort.getHeight() == (s32)ScreenSize.Height)
 | |
| 		{
 | |
| 			ViewPort = core::rect<s32>(core::position2d<s32>(0,0),
 | |
| 										core::dimension2di(realSize));
 | |
| 		}
 | |
| 
 | |
| 		ScreenSize = realSize;
 | |
| 
 | |
| 		bool resetRT = (RenderTargetSurface == BackBuffer);
 | |
| 
 | |
| 		if (BackBuffer)
 | |
| 			BackBuffer->drop();
 | |
| 		BackBuffer = new CImage(ECF_A1R5G5B5, realSize);
 | |
| 
 | |
| 		if (resetRT)
 | |
| 			setRenderTargetImage(BackBuffer);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| //! returns the current render target size
 | |
| const core::dimension2d<u32>& CSoftwareDriver::getCurrentRenderTargetSize() const
 | |
| {
 | |
| 	return RenderTargetSize;
 | |
| }
 | |
| 
 | |
| 
 | |
| //! 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.
 | |
| void CSoftwareDriver::draw2DImage(const video::ITexture* texture, const core::position2d<s32>& destPos,
 | |
| 					const core::rect<s32>& sourceRect,
 | |
| 					const core::rect<s32>* clipRect, SColor color,
 | |
| 					bool useAlphaChannelOfTexture)
 | |
| {
 | |
| 	if (texture)
 | |
| 	{
 | |
| 		if (texture->getDriverType() != EDT_SOFTWARE)
 | |
| 		{
 | |
| 			os::Printer::log("Fatal Error: Tried to copy from a surface not owned by this driver.", ELL_ERROR);
 | |
| 			return;
 | |
| 		}
 | |
| 
 | |
| 		if (useAlphaChannelOfTexture)
 | |
| 			((CSoftwareTexture*)texture)->getImage()->copyToWithAlpha(
 | |
| 				RenderTargetSurface, destPos, sourceRect, color, clipRect);
 | |
| 		else
 | |
| 			((CSoftwareTexture*)texture)->getImage()->copyTo(
 | |
| 				RenderTargetSurface, destPos, sourceRect, clipRect);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| //! Draws a 2d line.
 | |
| void CSoftwareDriver::draw2DLine(const core::position2d<s32>& start,
 | |
| 				const core::position2d<s32>& end,
 | |
| 				SColor color)
 | |
| {
 | |
| 	drawLine(RenderTargetSurface, start, end, color );
 | |
| }
 | |
| 
 | |
| 
 | |
| //! Draws a pixel
 | |
| void CSoftwareDriver::drawPixel(u32 x, u32 y, const SColor & color)
 | |
| {
 | |
| 	BackBuffer->setPixel(x, y, color, true);
 | |
| }
 | |
| 
 | |
| 
 | |
| //! draw a 2d rectangle
 | |
| void CSoftwareDriver::draw2DRectangle(SColor color, const core::rect<s32>& pos,
 | |
| 					const core::rect<s32>* clip)
 | |
| {
 | |
| 	if (clip)
 | |
| 	{
 | |
| 		core::rect<s32> p(pos);
 | |
| 
 | |
| 		p.clipAgainst(*clip);
 | |
| 
 | |
| 		if(!p.isValid())
 | |
| 			return;
 | |
| 
 | |
| 		drawRectangle(RenderTargetSurface, p, color);
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		if(!pos.isValid())
 | |
| 			return;
 | |
| 
 | |
| 		drawRectangle(RenderTargetSurface, pos, color);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| //!Draws an 2d rectangle with a gradient.
 | |
| void CSoftwareDriver::draw2DRectangle(const core::rect<s32>& pos,
 | |
| 	SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown,
 | |
| 	const core::rect<s32>* clip)
 | |
| {
 | |
| 	// TODO: implement
 | |
| 	draw2DRectangle(colorLeftUp, pos, clip);
 | |
| }
 | |
| 
 | |
| 
 | |
| //! \return Returns the name of the video driver. Example: In case of the Direct3D8
 | |
| //! driver, it would return "Direct3D8.1".
 | |
| const wchar_t* CSoftwareDriver::getName() const
 | |
| {
 | |
| 	return L"Irrlicht Software Driver 1.0";
 | |
| }
 | |
| 
 | |
| 
 | |
| //! Returns type of video driver
 | |
| E_DRIVER_TYPE CSoftwareDriver::getDriverType() const
 | |
| {
 | |
| 	return EDT_SOFTWARE;
 | |
| }
 | |
| 
 | |
| 
 | |
| //! returns color format
 | |
| ECOLOR_FORMAT CSoftwareDriver::getColorFormat() const
 | |
| {
 | |
| 	if (BackBuffer)
 | |
| 		return BackBuffer->getColorFormat();
 | |
| 	else
 | |
| 		return CNullDriver::getColorFormat();
 | |
| }
 | |
| 
 | |
| 
 | |
| //! Returns the transformation set by setTransform
 | |
| const core::matrix4& CSoftwareDriver::getTransform(E_TRANSFORMATION_STATE state) const
 | |
| {
 | |
| 	return TransformationMatrix[state];
 | |
| }
 | |
| 
 | |
| 
 | |
| //! Creates a render target texture.
 | |
| ITexture* CSoftwareDriver::addRenderTargetTexture(const core::dimension2d<u32>& size,
 | |
| 												  const io::path& name,
 | |
| 												  const ECOLOR_FORMAT format)
 | |
| {
 | |
| 	IImage* img = createImage(video::ECF_A1R5G5B5, size);
 | |
| 	ITexture* tex = new CSoftwareTexture(img, name, true);
 | |
| 	img->drop();
 | |
| 	addTexture(tex);
 | |
| 	tex->drop();
 | |
| 	return tex;
 | |
| }
 | |
| 
 | |
| void CSoftwareDriver::clearBuffers(u16 flag, SColor color, f32 depth, u8 stencil)
 | |
| {
 | |
| 	if ((flag & ECBF_COLOR) && RenderTargetSurface)
 | |
| 		RenderTargetSurface->fill(color);
 | |
| 
 | |
| 	if ((flag & ECBF_DEPTH) && ZBuffer)
 | |
| 		ZBuffer->clear();
 | |
| }
 | |
| 
 | |
| 
 | |
| //! Returns an image created from the last rendered frame.
 | |
| IImage* CSoftwareDriver::createScreenShot(video::ECOLOR_FORMAT format, video::E_RENDER_TARGET target)
 | |
| {
 | |
| 	if (target != video::ERT_FRAME_BUFFER)
 | |
| 		return 0;
 | |
| 
 | |
| 	if (BackBuffer)
 | |
| 	{
 | |
| 		IImage* tmp = createImage(BackBuffer->getColorFormat(), BackBuffer->getDimension());
 | |
| 		BackBuffer->copyTo(tmp);
 | |
| 		return tmp;
 | |
| 	}
 | |
| 	else
 | |
| 		return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| //! Returns the maximum amount of primitives (mostly vertices) which
 | |
| //! the device is able to render with one drawIndexedTriangleList
 | |
| //! call.
 | |
| u32 CSoftwareDriver::getMaximalPrimitiveCount() const
 | |
| {
 | |
| 	return 0x00800000;
 | |
| }
 | |
| 
 | |
| bool CSoftwareDriver::queryTextureFormat(ECOLOR_FORMAT format) const
 | |
| {
 | |
| 	return format == ECF_A1R5G5B5;
 | |
| }
 | |
| 
 | |
| 
 | |
| } // end namespace video
 | |
| } // end namespace irr
 | |
| 
 | |
| #endif // _IRR_COMPILE_WITH_SOFTWARE_
 | |
| 
 | |
| namespace irr
 | |
| {
 | |
| namespace video
 | |
| {
 | |
| 
 | |
| 
 | |
| //! creates a video driver
 | |
| IVideoDriver* createSoftwareDriver(const core::dimension2d<u32>& windowSize, bool fullscreen, io::IFileSystem* io, video::IImagePresenter* presenter)
 | |
| {
 | |
| 	#ifdef _IRR_COMPILE_WITH_SOFTWARE_
 | |
| 	return new CSoftwareDriver(windowSize, fullscreen, io, presenter);
 | |
| 	#else
 | |
| 	return 0;
 | |
| 	#endif
 | |
| }
 | |
| 
 | |
| 
 | |
| } // end namespace video
 | |
| } // end namespace irr
 | |
| 
 |