~baltix/+junk/irrlicht-test

« back to all changes in this revision

Viewing changes to source/Irrlicht/CSoftwareDriver.cpp

  • Committer: Mantas Kriaučiūnas
  • Date: 2011-07-18 13:06:25 UTC
  • Revision ID: mantas@akl.lt-20110718130625-c5pvifp61e7kj1ol
Included whole irrlicht SVN libraries to work around launchpad recipe issue with quilt, see https://answers.launchpad.net/launchpad/+question/165193

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright (C) 2002-2011 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
 
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
 
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
 
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.
 
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
 
164
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
 
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
 
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>
 
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.
 
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
 
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.
 
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
 
788
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.
 
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.
 
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
 
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
 
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.
 
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".
 
872
const wchar_t* CSoftwareDriver::getName() const
 
873
{
 
874
        return L"Irrlicht Software Driver 1.0";
 
875
}
 
876
 
 
877
 
 
878
//! Returns type of video driver
 
879
E_DRIVER_TYPE CSoftwareDriver::getDriverType() const
 
880
{
 
881
        return EDT_SOFTWARE;
 
882
}
 
883
 
 
884
 
 
885
//! returns color format
 
886
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
 
896
const core::matrix4& CSoftwareDriver::getTransform(E_TRANSFORMATION_STATE state) const
 
897
{
 
898
        return TransformationMatrix[state];
 
899
}
 
900
 
 
901
 
 
902
//! Creates a render target texture.
 
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.
 
917
void CSoftwareDriver::clearZBuffer()
 
918
{
 
919
        if (ZBuffer)
 
920
                ZBuffer->clear();
 
921
}
 
922
 
 
923
 
 
924
//! Returns an image created from the last rendered frame.
 
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.
 
944
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
 
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