mirror of
https://github.com/minetest/irrlicht.git
synced 2024-09-07 05:10:19 +02:00
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
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
|
|
|