irrlicht/source/Irrlicht/CSoftwareDriver.cpp
cutealien 2928a632a4 Material.ZWriteEnable is now of type E_ZWRITE instead of bool and ZWriteFineControl get removed (or merged into ZWriteEnable).
This breaks compiling. To have old values replace false with EZW_OFF and true with EWZ_AUTO.

There's a bit history to this change. ZWriteFineControl got introduced after 1.8 so it was never in a released version.
Basically it was needed after some changes had been made to allow shaders to have zwrite enabled independent
of the material-type (which worked badly for shaders). This had caused other problems as it was then enabled too often instead. 
So to quickly fix those bugs and avoid breaking compatibility I had introduced a new enum ZWriteFineControl in SMaterial.
This worked and didn't break compiling - but I noticed by now that introducing a second flag for this made maintainance for an already 
very hard to understand problem (figuring out the implementation of transparency and zwriting) even more complicated. 
So to keep maintance somewhat sane I decided to break compiling now and merge those two flags. 
The behavior should not be affected by this commit - except for users which set this flag already in their code and have to switch to the enum now.

Serialization is switched on loading old files (so SMaterial has enum already and writes that out).


git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@6026 dfc29bdd-3216-0410-991c-e03cc46cb475
2020-01-02 15:34:52 +00:00

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