aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/others/irrlicht-1.8.1/source/Irrlicht/CNullDriver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/others/irrlicht-1.8.1/source/Irrlicht/CNullDriver.cpp')
-rw-r--r--src/others/irrlicht-1.8.1/source/Irrlicht/CNullDriver.cpp2448
1 files changed, 2448 insertions, 0 deletions
diff --git a/src/others/irrlicht-1.8.1/source/Irrlicht/CNullDriver.cpp b/src/others/irrlicht-1.8.1/source/Irrlicht/CNullDriver.cpp
new file mode 100644
index 0000000..3d02abe
--- /dev/null
+++ b/src/others/irrlicht-1.8.1/source/Irrlicht/CNullDriver.cpp
@@ -0,0 +1,2448 @@
1// Copyright (C) 2002-2012 Nikolaus Gebhardt
2// This file is part of the "Irrlicht Engine".
3// For conditions of distribution and use, see copyright notice in irrlicht.h
4
5#include "CNullDriver.h"
6#include "os.h"
7#include "CImage.h"
8#include "CAttributes.h"
9#include "IReadFile.h"
10#include "IWriteFile.h"
11#include "IImageLoader.h"
12#include "IImageWriter.h"
13#include "IMaterialRenderer.h"
14#include "IAnimatedMeshSceneNode.h"
15#include "CMeshManipulator.h"
16#include "CColorConverter.h"
17#include "IAttributeExchangingObject.h"
18
19
20namespace irr
21{
22namespace video
23{
24
25//! creates a loader which is able to load windows bitmaps
26IImageLoader* createImageLoaderBMP();
27
28//! creates a loader which is able to load jpeg images
29IImageLoader* createImageLoaderJPG();
30
31//! creates a loader which is able to load targa images
32IImageLoader* createImageLoaderTGA();
33
34//! creates a loader which is able to load psd images
35IImageLoader* createImageLoaderPSD();
36
37//! creates a loader which is able to load dds images
38IImageLoader* createImageLoaderDDS();
39
40//! creates a loader which is able to load pcx images
41IImageLoader* createImageLoaderPCX();
42
43//! creates a loader which is able to load png images
44IImageLoader* createImageLoaderPNG();
45
46//! creates a loader which is able to load WAL images
47IImageLoader* createImageLoaderWAL();
48
49//! creates a loader which is able to load halflife images
50IImageLoader* createImageLoaderHalfLife();
51
52//! creates a loader which is able to load lmp images
53IImageLoader* createImageLoaderLMP();
54
55//! creates a loader which is able to load ppm/pgm/pbm images
56IImageLoader* createImageLoaderPPM();
57
58//! creates a loader which is able to load rgb images
59IImageLoader* createImageLoaderRGB();
60
61
62//! creates a writer which is able to save bmp images
63IImageWriter* createImageWriterBMP();
64
65//! creates a writer which is able to save jpg images
66IImageWriter* createImageWriterJPG();
67
68//! creates a writer which is able to save tga images
69IImageWriter* createImageWriterTGA();
70
71//! creates a writer which is able to save psd images
72IImageWriter* createImageWriterPSD();
73
74//! creates a writer which is able to save pcx images
75IImageWriter* createImageWriterPCX();
76
77//! creates a writer which is able to save png images
78IImageWriter* createImageWriterPNG();
79
80//! creates a writer which is able to save ppm images
81IImageWriter* createImageWriterPPM();
82
83//! constructor
84CNullDriver::CNullDriver(io::IFileSystem* io, const core::dimension2d<u32>& screenSize)
85: FileSystem(io), MeshManipulator(0), ViewPort(0,0,0,0), ScreenSize(screenSize),
86 PrimitivesDrawn(0), MinVertexCountForVBO(500), TextureCreationFlags(0),
87 OverrideMaterial2DEnabled(false), AllowZWriteOnTransparent(false)
88{
89 #ifdef _DEBUG
90 setDebugName("CNullDriver");
91 #endif
92
93 DriverAttributes = new io::CAttributes();
94 DriverAttributes->addInt("MaxTextures", _IRR_MATERIAL_MAX_TEXTURES_);
95 DriverAttributes->addInt("MaxSupportedTextures", _IRR_MATERIAL_MAX_TEXTURES_);
96 DriverAttributes->addInt("MaxLights", getMaximalDynamicLightAmount());
97 DriverAttributes->addInt("MaxAnisotropy", 1);
98// DriverAttributes->addInt("MaxUserClipPlanes", 0);
99// DriverAttributes->addInt("MaxAuxBuffers", 0);
100 DriverAttributes->addInt("MaxMultipleRenderTargets", 1);
101 DriverAttributes->addInt("MaxIndices", -1);
102 DriverAttributes->addInt("MaxTextureSize", -1);
103// DriverAttributes->addInt("MaxGeometryVerticesOut", 0);
104// DriverAttributes->addFloat("MaxTextureLODBias", 0.f);
105 DriverAttributes->addInt("Version", 1);
106// DriverAttributes->addInt("ShaderLanguageVersion", 0);
107// DriverAttributes->addInt("AntiAlias", 0);
108
109 setFog();
110
111 setTextureCreationFlag(ETCF_ALWAYS_32_BIT, true);
112 setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, true);
113
114 ViewPort = core::rect<s32>(core::position2d<s32>(0,0), core::dimension2di(screenSize));
115
116 // create manipulator
117 MeshManipulator = new scene::CMeshManipulator();
118
119 if (FileSystem)
120 FileSystem->grab();
121
122 // create surface loader
123
124#ifdef _IRR_COMPILE_WITH_HALFLIFE_LOADER_
125 SurfaceLoader.push_back(video::createImageLoaderHalfLife());
126#endif
127#ifdef _IRR_COMPILE_WITH_WAL_LOADER_
128 SurfaceLoader.push_back(video::createImageLoaderWAL());
129#endif
130#ifdef _IRR_COMPILE_WITH_LMP_LOADER_
131 SurfaceLoader.push_back(video::createImageLoaderLMP());
132#endif
133#ifdef _IRR_COMPILE_WITH_PPM_LOADER_
134 SurfaceLoader.push_back(video::createImageLoaderPPM());
135#endif
136#ifdef _IRR_COMPILE_WITH_RGB_LOADER_
137 SurfaceLoader.push_back(video::createImageLoaderRGB());
138#endif
139#ifdef _IRR_COMPILE_WITH_PSD_LOADER_
140 SurfaceLoader.push_back(video::createImageLoaderPSD());
141#endif
142#ifdef _IRR_COMPILE_WITH_DDS_LOADER_
143 SurfaceLoader.push_back(video::createImageLoaderDDS());
144#endif
145#ifdef _IRR_COMPILE_WITH_PCX_LOADER_
146 SurfaceLoader.push_back(video::createImageLoaderPCX());
147#endif
148#ifdef _IRR_COMPILE_WITH_TGA_LOADER_
149 SurfaceLoader.push_back(video::createImageLoaderTGA());
150#endif
151#ifdef _IRR_COMPILE_WITH_PNG_LOADER_
152 SurfaceLoader.push_back(video::createImageLoaderPNG());
153#endif
154#ifdef _IRR_COMPILE_WITH_JPG_LOADER_
155 SurfaceLoader.push_back(video::createImageLoaderJPG());
156#endif
157#ifdef _IRR_COMPILE_WITH_BMP_LOADER_
158 SurfaceLoader.push_back(video::createImageLoaderBMP());
159#endif
160
161
162#ifdef _IRR_COMPILE_WITH_PPM_WRITER_
163 SurfaceWriter.push_back(video::createImageWriterPPM());
164#endif
165#ifdef _IRR_COMPILE_WITH_PCX_WRITER_
166 SurfaceWriter.push_back(video::createImageWriterPCX());
167#endif
168#ifdef _IRR_COMPILE_WITH_PSD_WRITER_
169 SurfaceWriter.push_back(video::createImageWriterPSD());
170#endif
171#ifdef _IRR_COMPILE_WITH_TGA_WRITER_
172 SurfaceWriter.push_back(video::createImageWriterTGA());
173#endif
174#ifdef _IRR_COMPILE_WITH_JPG_WRITER_
175 SurfaceWriter.push_back(video::createImageWriterJPG());
176#endif
177#ifdef _IRR_COMPILE_WITH_PNG_WRITER_
178 SurfaceWriter.push_back(video::createImageWriterPNG());
179#endif
180#ifdef _IRR_COMPILE_WITH_BMP_WRITER_
181 SurfaceWriter.push_back(video::createImageWriterBMP());
182#endif
183
184
185 // set ExposedData to 0
186 memset(&ExposedData, 0, sizeof(ExposedData));
187 for (u32 i=0; i<video::EVDF_COUNT; ++i)
188 FeatureEnabled[i]=true;
189
190 InitMaterial2D.AntiAliasing=video::EAAM_OFF;
191 InitMaterial2D.Lighting=false;
192 InitMaterial2D.ZWriteEnable=false;
193 InitMaterial2D.ZBuffer=video::ECFN_NEVER;
194 InitMaterial2D.UseMipMaps=false;
195 for (u32 i=0; i<video::MATERIAL_MAX_TEXTURES; ++i)
196 {
197 InitMaterial2D.TextureLayer[i].BilinearFilter=false;
198 InitMaterial2D.TextureLayer[i].TextureWrapU=video::ETC_REPEAT;
199 InitMaterial2D.TextureLayer[i].TextureWrapV=video::ETC_REPEAT;
200 }
201 OverrideMaterial2D=InitMaterial2D;
202}
203
204
205//! destructor
206CNullDriver::~CNullDriver()
207{
208 if (DriverAttributes)
209 DriverAttributes->drop();
210
211 if (FileSystem)
212 FileSystem->drop();
213
214 if (MeshManipulator)
215 MeshManipulator->drop();
216 deleteAllTextures();
217
218 u32 i;
219 for (i=0; i<SurfaceLoader.size(); ++i)
220 SurfaceLoader[i]->drop();
221
222 for (i=0; i<SurfaceWriter.size(); ++i)
223 SurfaceWriter[i]->drop();
224
225 // delete material renderers
226 deleteMaterialRenders();
227
228 // delete hardware mesh buffers
229 removeAllHardwareBuffers();
230}
231
232
233//! Adds an external surface loader to the engine.
234void CNullDriver::addExternalImageLoader(IImageLoader* loader)
235{
236 if (!loader)
237 return;
238
239 loader->grab();
240 SurfaceLoader.push_back(loader);
241}
242
243
244//! Adds an external surface writer to the engine.
245void CNullDriver::addExternalImageWriter(IImageWriter* writer)
246{
247 if (!writer)
248 return;
249
250 writer->grab();
251 SurfaceWriter.push_back(writer);
252}
253
254
255//! Retrieve the number of image loaders
256u32 CNullDriver::getImageLoaderCount() const
257{
258 return SurfaceLoader.size();
259}
260
261
262//! Retrieve the given image loader
263IImageLoader* CNullDriver::getImageLoader(u32 n)
264{
265 if (n < SurfaceLoader.size())
266 return SurfaceLoader[n];
267 return 0;
268}
269
270
271//! Retrieve the number of image writers
272u32 CNullDriver::getImageWriterCount() const
273{
274 return SurfaceWriter.size();
275}
276
277
278//! Retrieve the given image writer
279IImageWriter* CNullDriver::getImageWriter(u32 n)
280{
281 if (n < SurfaceWriter.size())
282 return SurfaceWriter[n];
283 return 0;
284}
285
286
287//! deletes all textures
288void CNullDriver::deleteAllTextures()
289{
290 // we need to remove previously set textures which might otherwise be kept in the
291 // last set material member. Could be optimized to reduce state changes.
292 setMaterial(SMaterial());
293
294 for (u32 i=0; i<Textures.size(); ++i)
295 Textures[i].Surface->drop();
296
297 Textures.clear();
298}
299
300
301
302//! applications must call this method before performing any rendering. returns false if failed.
303bool CNullDriver::beginScene(bool backBuffer, bool zBuffer, SColor color,
304 const SExposedVideoData& videoData, core::rect<s32>* sourceRect)
305{
306 core::clearFPUException();
307 PrimitivesDrawn = 0;
308 return true;
309}
310
311
312//! applications must call this method after performing any rendering. returns false if failed.
313bool CNullDriver::endScene()
314{
315 FPSCounter.registerFrame(os::Timer::getRealTime(), PrimitivesDrawn);
316 updateAllHardwareBuffers();
317 updateAllOcclusionQueries();
318 return true;
319}
320
321
322//! Disable a feature of the driver.
323void CNullDriver::disableFeature(E_VIDEO_DRIVER_FEATURE feature, bool flag)
324{
325 FeatureEnabled[feature]=!flag;
326}
327
328
329//! queries the features of the driver, returns true if feature is available
330bool CNullDriver::queryFeature(E_VIDEO_DRIVER_FEATURE feature) const
331{
332 return false;
333}
334
335
336//! Get attributes of the actual video driver
337const io::IAttributes& CNullDriver::getDriverAttributes() const
338{
339 return *DriverAttributes;
340}
341
342
343//! sets transformation
344void CNullDriver::setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat)
345{
346}
347
348
349//! Returns the transformation set by setTransform
350const core::matrix4& CNullDriver::getTransform(E_TRANSFORMATION_STATE state) const
351{
352 return TransformationMatrix;
353}
354
355
356//! sets a material
357void CNullDriver::setMaterial(const SMaterial& material)
358{
359}
360
361
362//! Removes a texture from the texture cache and deletes it, freeing lot of
363//! memory.
364void CNullDriver::removeTexture(ITexture* texture)
365{
366 if (!texture)
367 return;
368
369 for (u32 i=0; i<Textures.size(); ++i)
370 {
371 if (Textures[i].Surface == texture)
372 {
373 texture->drop();
374 Textures.erase(i);
375 }
376 }
377}
378
379
380//! Removes all texture from the texture cache and deletes them, freeing lot of
381//! memory.
382void CNullDriver::removeAllTextures()
383{
384 setMaterial ( SMaterial() );
385 deleteAllTextures();
386}
387
388
389//! Returns a texture by index
390ITexture* CNullDriver::getTextureByIndex(u32 i)
391{
392 if ( i < Textures.size() )
393 return Textures[i].Surface;
394
395 return 0;
396}
397
398
399//! Returns amount of textures currently loaded
400u32 CNullDriver::getTextureCount() const
401{
402 return Textures.size();
403}
404
405
406//! Renames a texture
407void CNullDriver::renameTexture(ITexture* texture, const io::path& newName)
408{
409 // we can do a const_cast here safely, the name of the ITexture interface
410 // is just readonly to prevent the user changing the texture name without invoking
411 // this method, because the textures will need resorting afterwards
412
413 io::SNamedPath& name = const_cast<io::SNamedPath&>(texture->getName());
414 name.setPath(newName);
415
416 Textures.sort();
417}
418
419
420//! loads a Texture
421ITexture* CNullDriver::getTexture(const io::path& filename)
422{
423 // Identify textures by their absolute filenames if possible.
424 const io::path absolutePath = FileSystem->getAbsolutePath(filename);
425
426 ITexture* texture = findTexture(absolutePath);
427 if (texture)
428 return texture;
429
430 // Then try the raw filename, which might be in an Archive
431 texture = findTexture(filename);
432 if (texture)
433 return texture;
434
435 // Now try to open the file using the complete path.
436 io::IReadFile* file = FileSystem->createAndOpenFile(absolutePath);
437
438 if (!file)
439 {
440 // Try to open it using the raw filename.
441 file = FileSystem->createAndOpenFile(filename);
442 }
443
444 if (file)
445 {
446 // Re-check name for actual archive names
447 texture = findTexture(file->getFileName());
448 if (texture)
449 {
450 file->drop();
451 return texture;
452 }
453
454 texture = loadTextureFromFile(file);
455 file->drop();
456
457 if (texture)
458 {
459 addTexture(texture);
460 texture->drop(); // drop it because we created it, one grab too much
461 }
462 else
463 os::Printer::log("Could not load texture", filename, ELL_ERROR);
464 return texture;
465 }
466 else
467 {
468 os::Printer::log("Could not open file of texture", filename, ELL_WARNING);
469 return 0;
470 }
471}
472
473
474//! loads a Texture
475ITexture* CNullDriver::getTexture(io::IReadFile* file)
476{
477 ITexture* texture = 0;
478
479 if (file)
480 {
481 texture = findTexture(file->getFileName());
482
483 if (texture)
484 return texture;
485
486 texture = loadTextureFromFile(file);
487
488 if (texture)
489 {
490 addTexture(texture);
491 texture->drop(); // drop it because we created it, one grab too much
492 }
493
494 if (!texture)
495 os::Printer::log("Could not load texture", file->getFileName(), ELL_WARNING);
496 }
497
498 return texture;
499}
500
501
502//! opens the file and loads it into the surface
503video::ITexture* CNullDriver::loadTextureFromFile(io::IReadFile* file, const io::path& hashName )
504{
505 ITexture* texture = 0;
506 IImage* image = createImageFromFile(file);
507
508 if (image)
509 {
510 // create texture from surface
511 texture = createDeviceDependentTexture(image, hashName.size() ? hashName : file->getFileName() );
512 os::Printer::log("Loaded texture", file->getFileName());
513 image->drop();
514 }
515
516 return texture;
517}
518
519
520//! adds a surface, not loaded or created by the Irrlicht Engine
521void CNullDriver::addTexture(video::ITexture* texture)
522{
523 if (texture)
524 {
525 SSurface s;
526 s.Surface = texture;
527 texture->grab();
528
529 Textures.push_back(s);
530
531 // the new texture is now at the end of the texture list. when searching for
532 // the next new texture, the texture array will be sorted and the index of this texture
533 // will be changed. to let the order be more consistent to the user, sort
534 // the textures now already although this isn't necessary:
535
536 Textures.sort();
537 }
538}
539
540
541//! looks if the image is already loaded
542video::ITexture* CNullDriver::findTexture(const io::path& filename)
543{
544 SSurface s;
545 SDummyTexture dummy(filename);
546 s.Surface = &dummy;
547
548 s32 index = Textures.binary_search(s);
549 if (index != -1)
550 return Textures[index].Surface;
551
552 return 0;
553}
554
555
556//! Creates a texture from a loaded IImage.
557ITexture* CNullDriver::addTexture(const io::path& name, IImage* image, void* mipmapData)
558{
559 if ( 0 == name.size() || !image)
560 return 0;
561
562 ITexture* t = createDeviceDependentTexture(image, name, mipmapData);
563 if (t)
564 {
565 addTexture(t);
566 t->drop();
567 }
568 return t;
569}
570
571
572//! creates a Texture
573ITexture* CNullDriver::addTexture(const core::dimension2d<u32>& size,
574 const io::path& name, ECOLOR_FORMAT format)
575{
576 if(IImage::isRenderTargetOnlyFormat(format))
577 {
578 os::Printer::log("Could not create ITexture, format only supported for render target textures.", ELL_WARNING);
579 return 0;
580 }
581
582 if ( 0 == name.size () )
583 return 0;
584
585 IImage* image = new CImage(format, size);
586 ITexture* t = createDeviceDependentTexture(image, name);
587 image->drop();
588 addTexture(t);
589
590 if (t)
591 t->drop();
592
593 return t;
594}
595
596
597
598//! returns a device dependent texture from a software surface (IImage)
599//! THIS METHOD HAS TO BE OVERRIDDEN BY DERIVED DRIVERS WITH OWN TEXTURES
600ITexture* CNullDriver::createDeviceDependentTexture(IImage* surface, const io::path& name, void* mipmapData)
601{
602 return new SDummyTexture(name);
603}
604
605
606//! set or reset special render targets
607bool CNullDriver::setRenderTarget(video::E_RENDER_TARGET target, bool clearTarget,
608 bool clearZBuffer, SColor color)
609{
610 if (ERT_FRAME_BUFFER==target)
611 return setRenderTarget(0,clearTarget, clearZBuffer, color);
612 else
613 return false;
614}
615
616
617//! sets a render target
618bool CNullDriver::setRenderTarget(video::ITexture* texture, bool clearBackBuffer,
619 bool clearZBuffer, SColor color)
620{
621 return false;
622}
623
624
625//! Sets multiple render targets
626bool CNullDriver::setRenderTarget(const core::array<video::IRenderTarget>& texture,
627 bool clearBackBuffer, bool clearZBuffer, SColor color)
628{
629 return false;
630}
631
632
633//! sets a viewport
634void CNullDriver::setViewPort(const core::rect<s32>& area)
635{
636}
637
638
639//! gets the area of the current viewport
640const core::rect<s32>& CNullDriver::getViewPort() const
641{
642 return ViewPort;
643}
644
645
646//! draws a vertex primitive list
647void CNullDriver::drawVertexPrimitiveList(const void* vertices, u32 vertexCount, const void* indexList, u32 primitiveCount, E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType)
648{
649 if ((iType==EIT_16BIT) && (vertexCount>65536))
650 os::Printer::log("Too many vertices for 16bit index type, render artifacts may occur.");
651 PrimitivesDrawn += primitiveCount;
652}
653
654
655//! draws a vertex primitive list in 2d
656void CNullDriver::draw2DVertexPrimitiveList(const void* vertices, u32 vertexCount, const void* indexList, u32 primitiveCount, E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType)
657{
658 if ((iType==EIT_16BIT) && (vertexCount>65536))
659 os::Printer::log("Too many vertices for 16bit index type, render artifacts may occur.");
660 PrimitivesDrawn += primitiveCount;
661}
662
663
664//! Draws a 3d line.
665void CNullDriver::draw3DLine(const core::vector3df& start,
666 const core::vector3df& end, SColor color)
667{
668}
669
670
671//! Draws a 3d triangle.
672void CNullDriver::draw3DTriangle(const core::triangle3df& triangle, SColor color)
673{
674 S3DVertex vertices[3];
675 vertices[0].Pos=triangle.pointA;
676 vertices[0].Color=color;
677 vertices[0].Normal=triangle.getNormal().normalize();
678 vertices[0].TCoords.set(0.f,0.f);
679 vertices[1].Pos=triangle.pointB;
680 vertices[1].Color=color;
681 vertices[1].Normal=vertices[0].Normal;
682 vertices[1].TCoords.set(0.5f,1.f);
683 vertices[2].Pos=triangle.pointC;
684 vertices[2].Color=color;
685 vertices[2].Normal=vertices[0].Normal;
686 vertices[2].TCoords.set(1.f,0.f);
687 const u16 indexList[] = {0,1,2};
688 drawVertexPrimitiveList(vertices, 3, indexList, 1, EVT_STANDARD, scene::EPT_TRIANGLES, EIT_16BIT);
689}
690
691
692//! Draws a 3d axis aligned box.
693void CNullDriver::draw3DBox(const core::aabbox3d<f32>& box, SColor color)
694{
695 core::vector3df edges[8];
696 box.getEdges(edges);
697
698 // TODO: optimize into one big drawIndexPrimitive call.
699
700 draw3DLine(edges[5], edges[1], color);
701 draw3DLine(edges[1], edges[3], color);
702 draw3DLine(edges[3], edges[7], color);
703 draw3DLine(edges[7], edges[5], color);
704 draw3DLine(edges[0], edges[2], color);
705 draw3DLine(edges[2], edges[6], color);
706 draw3DLine(edges[6], edges[4], color);
707 draw3DLine(edges[4], edges[0], color);
708 draw3DLine(edges[1], edges[0], color);
709 draw3DLine(edges[3], edges[2], color);
710 draw3DLine(edges[7], edges[6], color);
711 draw3DLine(edges[5], edges[4], color);
712}
713
714
715
716//! draws an 2d image
717void CNullDriver::draw2DImage(const video::ITexture* texture, const core::position2d<s32>& destPos)
718{
719 if (!texture)
720 return;
721
722 draw2DImage(texture,destPos, core::rect<s32>(core::position2d<s32>(0,0),
723 core::dimension2di(texture->getOriginalSize())));
724}
725
726
727
728//! draws a set of 2d images, using a color and the alpha channel of the
729//! texture if desired. The images are drawn beginning at pos and concatenated
730//! in one line. All drawings are clipped against clipRect (if != 0).
731//! The subtextures are defined by the array of sourceRects and are chosen
732//! by the indices given.
733void CNullDriver::draw2DImageBatch(const video::ITexture* texture,
734 const core::position2d<s32>& pos,
735 const core::array<core::rect<s32> >& sourceRects,
736 const core::array<s32>& indices,
737 s32 kerningWidth,
738 const core::rect<s32>* clipRect, SColor color,
739 bool useAlphaChannelOfTexture)
740{
741 core::position2d<s32> target(pos);
742
743 for (u32 i=0; i<indices.size(); ++i)
744 {
745 draw2DImage(texture, target, sourceRects[indices[i]],
746 clipRect, color, useAlphaChannelOfTexture);
747 target.X += sourceRects[indices[i]].getWidth();
748 target.X += kerningWidth;
749 }
750}
751
752//! draws a set of 2d images, using a color and the alpha channel of the
753//! texture if desired.
754void CNullDriver::draw2DImageBatch(const video::ITexture* texture,
755 const core::array<core::position2d<s32> >& positions,
756 const core::array<core::rect<s32> >& sourceRects,
757 const core::rect<s32>* clipRect,
758 SColor color,
759 bool useAlphaChannelOfTexture)
760{
761 const irr::u32 drawCount = core::min_<u32>(positions.size(), sourceRects.size());
762
763 for (u32 i=0; i<drawCount; ++i)
764 {
765 draw2DImage(texture, positions[i], sourceRects[i],
766 clipRect, color, useAlphaChannelOfTexture);
767 }
768}
769
770
771//! Draws a part of the texture into the rectangle.
772void CNullDriver::draw2DImage(const video::ITexture* texture, const core::rect<s32>& destRect,
773 const core::rect<s32>& sourceRect, const core::rect<s32>* clipRect,
774 const video::SColor* const colors, bool useAlphaChannelOfTexture)
775{
776 if (destRect.isValid())
777 draw2DImage(texture, core::position2d<s32>(destRect.UpperLeftCorner),
778 sourceRect, clipRect, colors?colors[0]:video::SColor(0xffffffff),
779 useAlphaChannelOfTexture);
780}
781
782
783//! Draws a 2d image, using a color (if color is other then Color(255,255,255,255)) and the alpha channel of the texture if wanted.
784void CNullDriver::draw2DImage(const video::ITexture* texture, const core::position2d<s32>& destPos,
785 const core::rect<s32>& sourceRect,
786 const core::rect<s32>* clipRect, SColor color,
787 bool useAlphaChannelOfTexture)
788{
789}
790
791
792//! Draws the outline of a 2d rectangle
793void CNullDriver::draw2DRectangleOutline(const core::recti& pos, SColor color)
794{
795 draw2DLine(pos.UpperLeftCorner, core::position2di(pos.LowerRightCorner.X, pos.UpperLeftCorner.Y), color);
796 draw2DLine(core::position2di(pos.LowerRightCorner.X, pos.UpperLeftCorner.Y), pos.LowerRightCorner, color);
797 draw2DLine(pos.LowerRightCorner, core::position2di(pos.UpperLeftCorner.X, pos.LowerRightCorner.Y), color);
798 draw2DLine(core::position2di(pos.UpperLeftCorner.X, pos.LowerRightCorner.Y), pos.UpperLeftCorner, color);
799}
800
801
802//! Draw a 2d rectangle
803void CNullDriver::draw2DRectangle(SColor color, const core::rect<s32>& pos, const core::rect<s32>* clip)
804{
805 draw2DRectangle(pos, color, color, color, color, clip);
806}
807
808
809
810//! Draws a 2d rectangle with a gradient.
811void CNullDriver::draw2DRectangle(const core::rect<s32>& pos,
812 SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown,
813 const core::rect<s32>* clip)
814{
815}
816
817
818
819//! Draws a 2d line.
820void CNullDriver::draw2DLine(const core::position2d<s32>& start,
821 const core::position2d<s32>& end, SColor color)
822{
823}
824
825//! Draws a pixel
826void CNullDriver::drawPixel(u32 x, u32 y, const SColor & color)
827{
828}
829
830
831//! Draws a non filled concyclic regular 2d polyon.
832void CNullDriver::draw2DPolygon(core::position2d<s32> center,
833 f32 radius, video::SColor color, s32 count)
834{
835 if (count < 2)
836 return;
837
838 core::position2d<s32> first;
839 core::position2d<s32> a,b;
840
841 for (s32 j=0; j<count; ++j)
842 {
843 b = a;
844
845 f32 p = j / (f32)count * (core::PI*2);
846 a = center + core::position2d<s32>((s32)(sin(p)*radius), (s32)(cos(p)*radius));
847
848 if (j==0)
849 first = a;
850 else
851 draw2DLine(a, b, color);
852 }
853
854 draw2DLine(a, first, color);
855}
856
857
858//! returns color format
859ECOLOR_FORMAT CNullDriver::getColorFormat() const
860{
861 return ECF_R5G6B5;
862}
863
864
865//! returns screen size
866const core::dimension2d<u32>& CNullDriver::getScreenSize() const
867{
868 return ScreenSize;
869}
870
871
872//! returns the current render target size,
873//! or the screen size if render targets are not implemented
874const core::dimension2d<u32>& CNullDriver::getCurrentRenderTargetSize() const
875{
876 return ScreenSize;
877}
878
879
880// returns current frames per second value
881s32 CNullDriver::getFPS() const
882{
883 return FPSCounter.getFPS();
884}
885
886
887
888//! returns amount of primitives (mostly triangles) were drawn in the last frame.
889//! very useful method for statistics.
890u32 CNullDriver::getPrimitiveCountDrawn( u32 param ) const
891{
892 return (0 == param) ? FPSCounter.getPrimitive() : (1 == param) ? FPSCounter.getPrimitiveAverage() : FPSCounter.getPrimitiveTotal();
893}
894
895
896
897//! Sets the dynamic ambient light color. The default color is
898//! (0,0,0,0) which means it is dark.
899//! \param color: New color of the ambient light.
900void CNullDriver::setAmbientLight(const SColorf& color)
901{
902}
903
904
905
906//! \return Returns the name of the video driver. Example: In case of the DIRECT3D8
907//! driver, it would return "Direct3D8".
908
909const wchar_t* CNullDriver::getName() const
910{
911 return L"Irrlicht NullDevice";
912}
913
914
915
916//! Draws a shadow volume into the stencil buffer. To draw a stencil shadow, do
917//! this: Frist, draw all geometry. Then use this method, to draw the shadow
918//! volume. Then, use IVideoDriver::drawStencilShadow() to visualize the shadow.
919void CNullDriver::drawStencilShadowVolume(const core::array<core::vector3df>& triangles, bool zfail, u32 debugDataVisible)
920{
921}
922
923
924//! Fills the stencil shadow with color. After the shadow volume has been drawn
925//! into the stencil buffer using IVideoDriver::drawStencilShadowVolume(), use this
926//! to draw the color of the shadow.
927void CNullDriver::drawStencilShadow(bool clearStencilBuffer,
928 video::SColor leftUpEdge, video::SColor rightUpEdge,
929 video::SColor leftDownEdge, video::SColor rightDownEdge)
930{
931}
932
933
934//! deletes all dynamic lights there are
935void CNullDriver::deleteAllDynamicLights()
936{
937 Lights.set_used(0);
938}
939
940
941//! adds a dynamic light
942s32 CNullDriver::addDynamicLight(const SLight& light)
943{
944 Lights.push_back(light);
945 return Lights.size() - 1;
946}
947
948//! Turns a dynamic light on or off
949//! \param lightIndex: the index returned by addDynamicLight
950//! \param turnOn: true to turn the light on, false to turn it off
951void CNullDriver::turnLightOn(s32 lightIndex, bool turnOn)
952{
953 // Do nothing
954}
955
956
957//! returns the maximal amount of dynamic lights the device can handle
958u32 CNullDriver::getMaximalDynamicLightAmount() const
959{
960 return 0;
961}
962
963
964//! Returns current amount of dynamic lights set
965//! \return Current amount of dynamic lights set
966u32 CNullDriver::getDynamicLightCount() const
967{
968 return Lights.size();
969}
970
971
972//! Returns light data which was previously set by IVideoDriver::addDynamicLight().
973//! \param idx: Zero based index of the light. Must be greater than 0 and smaller
974//! than IVideoDriver()::getDynamicLightCount.
975//! \return Light data.
976const SLight& CNullDriver::getDynamicLight(u32 idx) const
977{
978 if ( idx < Lights.size() )
979 return Lights[idx];
980 else
981 return *((SLight*)0);
982}
983
984
985//! Creates a boolean alpha channel of the texture based of an color key.
986void CNullDriver::makeColorKeyTexture(video::ITexture* texture,
987 video::SColor color,
988 bool zeroTexels) const
989{
990 if (!texture)
991 return;
992
993 if (texture->getColorFormat() != ECF_A1R5G5B5 &&
994 texture->getColorFormat() != ECF_A8R8G8B8 )
995 {
996 os::Printer::log("Error: Unsupported texture color format for making color key channel.", ELL_ERROR);
997 return;
998 }
999
1000 if (texture->getColorFormat() == ECF_A1R5G5B5)
1001 {
1002 u16 *p = (u16*)texture->lock();
1003
1004 if (!p)
1005 {
1006 os::Printer::log("Could not lock texture for making color key channel.", ELL_ERROR);
1007 return;
1008 }
1009
1010 const core::dimension2d<u32> dim = texture->getSize();
1011 const u32 pitch = texture->getPitch() / 2;
1012
1013 // color with alpha disabled (i.e. fully transparent)
1014 const u16 refZeroAlpha = (0x7fff & color.toA1R5G5B5());
1015
1016 const u32 pixels = pitch * dim.Height;
1017
1018 for (u32 pixel = 0; pixel < pixels; ++ pixel)
1019 {
1020 // If the color matches the reference color, ignoring alphas,
1021 // set the alpha to zero.
1022 if(((*p) & 0x7fff) == refZeroAlpha)
1023 {
1024 if(zeroTexels)
1025 (*p) = 0;
1026 else
1027 (*p) = refZeroAlpha;
1028 }
1029
1030 ++p;
1031 }
1032
1033 texture->unlock();
1034 }
1035 else
1036 {
1037 u32 *p = (u32*)texture->lock();
1038
1039 if (!p)
1040 {
1041 os::Printer::log("Could not lock texture for making color key channel.", ELL_ERROR);
1042 return;
1043 }
1044
1045 core::dimension2d<u32> dim = texture->getSize();
1046 u32 pitch = texture->getPitch() / 4;
1047
1048 // color with alpha disabled (fully transparent)
1049 const u32 refZeroAlpha = 0x00ffffff & color.color;
1050
1051 const u32 pixels = pitch * dim.Height;
1052 for (u32 pixel = 0; pixel < pixels; ++ pixel)
1053 {
1054 // If the color matches the reference color, ignoring alphas,
1055 // set the alpha to zero.
1056 if(((*p) & 0x00ffffff) == refZeroAlpha)
1057 {
1058 if(zeroTexels)
1059 (*p) = 0;
1060 else
1061 (*p) = refZeroAlpha;
1062 }
1063
1064 ++p;
1065 }
1066
1067 texture->unlock();
1068 }
1069 texture->regenerateMipMapLevels();
1070}
1071
1072
1073
1074//! Creates an boolean alpha channel of the texture based of an color key position.
1075void CNullDriver::makeColorKeyTexture(video::ITexture* texture,
1076 core::position2d<s32> colorKeyPixelPos,
1077 bool zeroTexels) const
1078{
1079 if (!texture)
1080 return;
1081
1082 if (texture->getColorFormat() != ECF_A1R5G5B5 &&
1083 texture->getColorFormat() != ECF_A8R8G8B8 )
1084 {
1085 os::Printer::log("Error: Unsupported texture color format for making color key channel.", ELL_ERROR);
1086 return;
1087 }
1088
1089 SColor colorKey;
1090
1091 if (texture->getColorFormat() == ECF_A1R5G5B5)
1092 {
1093 u16 *p = (u16*)texture->lock(ETLM_READ_ONLY);
1094
1095 if (!p)
1096 {
1097 os::Printer::log("Could not lock texture for making color key channel.", ELL_ERROR);
1098 return;
1099 }
1100
1101 u32 pitch = texture->getPitch() / 2;
1102
1103 const u16 key16Bit = 0x7fff & p[colorKeyPixelPos.Y*pitch + colorKeyPixelPos.X];
1104
1105 colorKey = video::A1R5G5B5toA8R8G8B8(key16Bit);
1106 }
1107 else
1108 {
1109 u32 *p = (u32*)texture->lock(ETLM_READ_ONLY);
1110
1111 if (!p)
1112 {
1113 os::Printer::log("Could not lock texture for making color key channel.", ELL_ERROR);
1114 return;
1115 }
1116
1117 u32 pitch = texture->getPitch() / 4;
1118 colorKey = 0x00ffffff & p[colorKeyPixelPos.Y*pitch + colorKeyPixelPos.X];
1119 }
1120
1121 texture->unlock();
1122 makeColorKeyTexture(texture, colorKey, zeroTexels);
1123}
1124
1125
1126
1127//! Creates a normal map from a height map texture.
1128//! \param amplitude: Constant value by which the height information is multiplied.
1129void CNullDriver::makeNormalMapTexture(video::ITexture* texture, f32 amplitude) const
1130{
1131 if (!texture)
1132 return;
1133
1134 if (texture->getColorFormat() != ECF_A1R5G5B5 &&
1135 texture->getColorFormat() != ECF_A8R8G8B8 )
1136 {
1137 os::Printer::log("Error: Unsupported texture color format for making normal map.", ELL_ERROR);
1138 return;
1139 }
1140
1141 core::dimension2d<u32> dim = texture->getSize();
1142 amplitude = amplitude / 255.0f;
1143 f32 vh = dim.Height / (f32)dim.Width;
1144 f32 hh = dim.Width / (f32)dim.Height;
1145
1146 if (texture->getColorFormat() == ECF_A8R8G8B8)
1147 {
1148 // ECF_A8R8G8B8 version
1149
1150 s32 *p = (s32*)texture->lock();
1151
1152 if (!p)
1153 {
1154 os::Printer::log("Could not lock texture for making normal map.", ELL_ERROR);
1155 return;
1156 }
1157
1158 // copy texture
1159
1160 u32 pitch = texture->getPitch() / 4;
1161
1162 s32* in = new s32[dim.Height * pitch];
1163 memcpy(in, p, dim.Height * pitch * 4);
1164
1165 for (s32 x=0; x < s32(pitch); ++x)
1166 for (s32 y=0; y < s32(dim.Height); ++y)
1167 {
1168 // TODO: this could be optimized really a lot
1169
1170 core::vector3df h1((x-1)*hh, nml32(x-1, y, pitch, dim.Height, in)*amplitude, y*vh);
1171 core::vector3df h2((x+1)*hh, nml32(x+1, y, pitch, dim.Height, in)*amplitude, y*vh);
1172 //core::vector3df v1(x*hh, nml32(x, y-1, pitch, dim.Height, in)*amplitude, (y-1)*vh);
1173 //core::vector3df v2(x*hh, nml32(x, y+1, pitch, dim.Height, in)*amplitude, (y+1)*vh);
1174 core::vector3df v1(x*hh, nml32(x, y+1, pitch, dim.Height, in)*amplitude, (y-1)*vh);
1175 core::vector3df v2(x*hh, nml32(x, y-1, pitch, dim.Height, in)*amplitude, (y+1)*vh);
1176
1177 core::vector3df v = v1-v2;
1178 core::vector3df h = h1-h2;
1179
1180 core::vector3df n = v.crossProduct(h);
1181 n.normalize();
1182 n *= 0.5f;
1183 n += core::vector3df(0.5f,0.5f,0.5f); // now between 0 and 1
1184 n *= 255.0f;
1185
1186 s32 height = (s32)nml32(x, y, pitch, dim.Height, in);
1187 p[y*pitch + x] = video::SColor(
1188 height, // store height in alpha
1189 (s32)n.X, (s32)n.Z, (s32)n.Y).color;
1190 }
1191
1192 delete [] in;
1193 texture->unlock();
1194 }
1195 else
1196 {
1197 // ECF_A1R5G5B5 version
1198
1199 s16 *p = (s16*)texture->lock();
1200
1201 if (!p)
1202 {
1203 os::Printer::log("Could not lock texture for making normal map.", ELL_ERROR);
1204 return;
1205 }
1206
1207 u32 pitch = texture->getPitch() / 2;
1208
1209 // copy texture
1210
1211 s16* in = new s16[dim.Height * pitch];
1212 memcpy(in, p, dim.Height * pitch * 2);
1213
1214 for (s32 x=0; x < s32(pitch); ++x)
1215 for (s32 y=0; y < s32(dim.Height); ++y)
1216 {
1217 // TODO: this could be optimized really a lot
1218
1219 core::vector3df h1((x-1)*hh, nml16(x-1, y, pitch, dim.Height, in)*amplitude, y*vh);
1220 core::vector3df h2((x+1)*hh, nml16(x+1, y, pitch, dim.Height, in)*amplitude, y*vh);
1221 core::vector3df v1(x*hh, nml16(x, y-1, pitch, dim.Height, in)*amplitude, (y-1)*vh);
1222 core::vector3df v2(x*hh, nml16(x, y+1, pitch, dim.Height, in)*amplitude, (y+1)*vh);
1223
1224 core::vector3df v = v1-v2;
1225 core::vector3df h = h1-h2;
1226
1227 core::vector3df n = v.crossProduct(h);
1228 n.normalize();
1229 n *= 0.5f;
1230 n += core::vector3df(0.5f,0.5f,0.5f); // now between 0 and 1
1231 n *= 255.0f;
1232
1233 p[y*pitch + x] = video::RGBA16((u32)n.X, (u32)n.Z, (u32)n.Y);
1234 }
1235
1236 delete [] in;
1237 texture->unlock();
1238 }
1239
1240 texture->regenerateMipMapLevels();
1241}
1242
1243
1244//! Returns the maximum amount of primitives (mostly vertices) which
1245//! the device is able to render with one drawIndexedTriangleList
1246//! call.
1247u32 CNullDriver::getMaximalPrimitiveCount() const
1248{
1249 return 0xFFFFFFFF;
1250}
1251
1252
1253//! checks triangle count and print warning if wrong
1254bool CNullDriver::checkPrimitiveCount(u32 prmCount) const
1255{
1256 const u32 m = getMaximalPrimitiveCount();
1257
1258 if (prmCount > m)
1259 {
1260 char tmp[1024];
1261 sprintf(tmp,"Could not draw triangles, too many primitives(%u), maxium is %u.", prmCount, m);
1262 os::Printer::log(tmp, ELL_ERROR);
1263 return false;
1264 }
1265
1266 return true;
1267}
1268
1269//! Enables or disables a texture creation flag.
1270void CNullDriver::setTextureCreationFlag(E_TEXTURE_CREATION_FLAG flag, bool enabled)
1271{
1272 if (enabled && ((flag == ETCF_ALWAYS_16_BIT) || (flag == ETCF_ALWAYS_32_BIT)
1273 || (flag == ETCF_OPTIMIZED_FOR_QUALITY) || (flag == ETCF_OPTIMIZED_FOR_SPEED)))
1274 {
1275 // disable other formats
1276 setTextureCreationFlag(ETCF_ALWAYS_16_BIT, false);
1277 setTextureCreationFlag(ETCF_ALWAYS_32_BIT, false);
1278 setTextureCreationFlag(ETCF_OPTIMIZED_FOR_QUALITY, false);
1279 setTextureCreationFlag(ETCF_OPTIMIZED_FOR_SPEED, false);
1280 }
1281
1282 // set flag
1283 TextureCreationFlags = (TextureCreationFlags & (~flag)) |
1284 ((((u32)!enabled)-1) & flag);
1285}
1286
1287
1288//! Returns if a texture creation flag is enabled or disabled.
1289bool CNullDriver::getTextureCreationFlag(E_TEXTURE_CREATION_FLAG flag) const
1290{
1291 return (TextureCreationFlags & flag)!=0;
1292}
1293
1294
1295//! Creates a software image from a file.
1296IImage* CNullDriver::createImageFromFile(const io::path& filename)
1297{
1298 if (!filename.size())
1299 return 0;
1300
1301 IImage* image = 0;
1302 io::IReadFile* file = FileSystem->createAndOpenFile(filename);
1303
1304 if (file)
1305 {
1306 image = createImageFromFile(file);
1307 file->drop();
1308 }
1309 else
1310 os::Printer::log("Could not open file of image", filename, ELL_WARNING);
1311
1312 return image;
1313}
1314
1315
1316//! Creates a software image from a file.
1317IImage* CNullDriver::createImageFromFile(io::IReadFile* file)
1318{
1319 if (!file)
1320 return 0;
1321
1322 IImage* image = 0;
1323
1324 s32 i;
1325
1326 // try to load file based on file extension
1327 for (i=SurfaceLoader.size()-1; i>=0; --i)
1328 {
1329 if (SurfaceLoader[i]->isALoadableFileExtension(file->getFileName()))
1330 {
1331 // reset file position which might have changed due to previous loadImage calls
1332 file->seek(0);
1333 image = SurfaceLoader[i]->loadImage(file);
1334 if (image)
1335 return image;
1336 }
1337 }
1338
1339 // try to load file based on what is in it
1340 for (i=SurfaceLoader.size()-1; i>=0; --i)
1341 {
1342 // dito
1343 file->seek(0);
1344 if (SurfaceLoader[i]->isALoadableFileFormat(file))
1345 {
1346 file->seek(0);
1347 image = SurfaceLoader[i]->loadImage(file);
1348 if (image)
1349 return image;
1350 }
1351 }
1352
1353 return 0; // failed to load
1354}
1355
1356
1357//! Writes the provided image to disk file
1358bool CNullDriver::writeImageToFile(IImage* image, const io::path& filename,u32 param)
1359{
1360 io::IWriteFile* file = FileSystem->createAndWriteFile(filename);
1361 if(!file)
1362 return false;
1363
1364 bool result = writeImageToFile(image, file, param);
1365 file->drop();
1366
1367 return result;
1368}
1369
1370//! Writes the provided image to a file.
1371bool CNullDriver::writeImageToFile(IImage* image, io::IWriteFile * file, u32 param)
1372{
1373 if(!file)
1374 return false;
1375
1376 for (s32 i=SurfaceWriter.size()-1; i>=0; --i)
1377 {
1378 if (SurfaceWriter[i]->isAWriteableFileExtension(file->getFileName()))
1379 {
1380 bool written = SurfaceWriter[i]->writeImage(file, image, param);
1381 if (written)
1382 return true;
1383 }
1384 }
1385 return false; // failed to write
1386}
1387
1388
1389//! Creates a software image from a byte array.
1390IImage* CNullDriver::createImageFromData(ECOLOR_FORMAT format,
1391 const core::dimension2d<u32>& size,
1392 void *data, bool ownForeignMemory,
1393 bool deleteMemory)
1394{
1395 if(IImage::isRenderTargetOnlyFormat(format))
1396 {
1397 os::Printer::log("Could not create IImage, format only supported for render target textures.", ELL_WARNING);
1398 return 0;
1399 }
1400
1401 return new CImage(format, size, data, ownForeignMemory, deleteMemory);
1402}
1403
1404
1405//! Creates an empty software image.
1406IImage* CNullDriver::createImage(ECOLOR_FORMAT format, const core::dimension2d<u32>& size)
1407{
1408 if(IImage::isRenderTargetOnlyFormat(format))
1409 {
1410 os::Printer::log("Could not create IImage, format only supported for render target textures.", ELL_WARNING);
1411 return 0;
1412 }
1413
1414 return new CImage(format, size);
1415}
1416
1417
1418//! Creates a software image from another image.
1419IImage* CNullDriver::createImage(ECOLOR_FORMAT format, IImage *imageToCopy)
1420{
1421 os::Printer::log("Deprecated method, please create an empty image instead and use copyTo().", ELL_WARNING);
1422 if(IImage::isRenderTargetOnlyFormat(format))
1423 {
1424 os::Printer::log("Could not create IImage, format only supported for render target textures.", ELL_WARNING);
1425 return 0;
1426 }
1427
1428 CImage* tmp = new CImage(format, imageToCopy->getDimension());
1429 imageToCopy->copyTo(tmp);
1430 return tmp;
1431}
1432
1433
1434//! Creates a software image from part of another image.
1435IImage* CNullDriver::createImage(IImage* imageToCopy, const core::position2d<s32>& pos, const core::dimension2d<u32>& size)
1436{
1437 os::Printer::log("Deprecated method, please create an empty image instead and use copyTo().", ELL_WARNING);
1438 CImage* tmp = new CImage(imageToCopy->getColorFormat(), imageToCopy->getDimension());
1439 imageToCopy->copyTo(tmp, core::position2di(0,0), core::recti(pos,size));
1440 return tmp;
1441}
1442
1443
1444//! Creates a software image from part of a texture.
1445IImage* CNullDriver::createImage(ITexture* texture, const core::position2d<s32>& pos, const core::dimension2d<u32>& size)
1446{
1447 if ((pos==core::position2di(0,0)) && (size == texture->getSize()))
1448 {
1449 IImage* image = new CImage(texture->getColorFormat(), size, texture->lock(ETLM_READ_ONLY), false);
1450 texture->unlock();
1451 return image;
1452 }
1453 else
1454 {
1455 // make sure to avoid buffer overruns
1456 // make the vector a separate variable for g++ 3.x
1457 const core::vector2d<u32> leftUpper(core::clamp(static_cast<u32>(pos.X), 0u, texture->getSize().Width),
1458 core::clamp(static_cast<u32>(pos.Y), 0u, texture->getSize().Height));
1459 const core::rect<u32> clamped(leftUpper,
1460 core::dimension2du(core::clamp(static_cast<u32>(size.Width), 0u, texture->getSize().Width),
1461 core::clamp(static_cast<u32>(size.Height), 0u, texture->getSize().Height)));
1462 if (!clamped.isValid())
1463 return 0;
1464 u8* src = static_cast<u8*>(texture->lock(ETLM_READ_ONLY));
1465 if (!src)
1466 return 0;
1467 IImage* image = new CImage(texture->getColorFormat(), clamped.getSize());
1468 u8* dst = static_cast<u8*>(image->lock());
1469 src += clamped.UpperLeftCorner.Y * texture->getPitch() + image->getBytesPerPixel() * clamped.UpperLeftCorner.X;
1470 for (u32 i=0; i<clamped.getHeight(); ++i)
1471 {
1472 video::CColorConverter::convert_viaFormat(src, texture->getColorFormat(), clamped.getWidth(), dst, image->getColorFormat());
1473 src += texture->getPitch();
1474 dst += image->getPitch();
1475 }
1476 image->unlock();
1477 texture->unlock();
1478 return image;
1479 }
1480}
1481
1482
1483//! Sets the fog mode.
1484void CNullDriver::setFog(SColor color, E_FOG_TYPE fogType, f32 start, f32 end,
1485 f32 density, bool pixelFog, bool rangeFog)
1486{
1487 FogColor = color;
1488 FogType = fogType;
1489 FogStart = start;
1490 FogEnd = end;
1491 FogDensity = density;
1492 PixelFog = pixelFog;
1493 RangeFog = rangeFog;
1494}
1495
1496//! Gets the fog mode.
1497void CNullDriver::getFog(SColor& color, E_FOG_TYPE& fogType, f32& start, f32& end,
1498 f32& density, bool& pixelFog, bool& rangeFog)
1499{
1500 color = FogColor;
1501 fogType = FogType;
1502 start = FogStart;
1503 end = FogEnd;
1504 density = FogDensity;
1505 pixelFog = PixelFog;
1506 rangeFog = RangeFog;
1507}
1508
1509//! Draws a mesh buffer
1510void CNullDriver::drawMeshBuffer(const scene::IMeshBuffer* mb)
1511{
1512 if (!mb)
1513 return;
1514
1515 //IVertexBuffer and IIndexBuffer later
1516 SHWBufferLink *HWBuffer=getBufferLink(mb);
1517
1518 if (HWBuffer)
1519 drawHardwareBuffer(HWBuffer);
1520 else
1521 drawVertexPrimitiveList(mb->getVertices(), mb->getVertexCount(), mb->getIndices(), mb->getIndexCount()/3, mb->getVertexType(), scene::EPT_TRIANGLES, mb->getIndexType());
1522}
1523
1524
1525//! Draws the normals of a mesh buffer
1526void CNullDriver::drawMeshBufferNormals(const scene::IMeshBuffer* mb, f32 length, SColor color)
1527{
1528 const u32 count = mb->getVertexCount();
1529 const bool normalize = mb->getMaterial().NormalizeNormals;
1530
1531 for (u32 i=0; i < count; ++i)
1532 {
1533 core::vector3df normalizedNormal = mb->getNormal(i);
1534 if (normalize)
1535 normalizedNormal.normalize();
1536
1537 const core::vector3df& pos = mb->getPosition(i);
1538 draw3DLine(pos, pos + (normalizedNormal * length), color);
1539 }
1540}
1541
1542
1543CNullDriver::SHWBufferLink *CNullDriver::getBufferLink(const scene::IMeshBuffer* mb)
1544{
1545 if (!mb || !isHardwareBufferRecommend(mb))
1546 return 0;
1547
1548 //search for hardware links
1549 core::map< const scene::IMeshBuffer*,SHWBufferLink* >::Node* node = HWBufferMap.find(mb);
1550 if (node)
1551 return node->getValue();
1552
1553 return createHardwareBuffer(mb); //no hardware links, and mesh wants one, create it
1554}
1555
1556
1557//! Update all hardware buffers, remove unused ones
1558void CNullDriver::updateAllHardwareBuffers()
1559{
1560 core::map<const scene::IMeshBuffer*,SHWBufferLink*>::ParentFirstIterator Iterator=HWBufferMap.getParentFirstIterator();
1561
1562 for (;!Iterator.atEnd();Iterator++)
1563 {
1564 SHWBufferLink *Link=Iterator.getNode()->getValue();
1565
1566 Link->LastUsed++;
1567 if (Link->LastUsed>20000)
1568 {
1569 deleteHardwareBuffer(Link);
1570
1571 // todo: needs better fix
1572 Iterator = HWBufferMap.getParentFirstIterator();
1573 }
1574 }
1575}
1576
1577
1578void CNullDriver::deleteHardwareBuffer(SHWBufferLink *HWBuffer)
1579{
1580 if (!HWBuffer)
1581 return;
1582 HWBufferMap.remove(HWBuffer->MeshBuffer);
1583 delete HWBuffer;
1584}
1585
1586
1587//! Remove hardware buffer
1588void CNullDriver::removeHardwareBuffer(const scene::IMeshBuffer* mb)
1589{
1590 core::map<const scene::IMeshBuffer*,SHWBufferLink*>::Node* node = HWBufferMap.find(mb);
1591 if (node)
1592 deleteHardwareBuffer(node->getValue());
1593}
1594
1595
1596//! Remove all hardware buffers
1597void CNullDriver::removeAllHardwareBuffers()
1598{
1599 while (HWBufferMap.size())
1600 deleteHardwareBuffer(HWBufferMap.getRoot()->getValue());
1601}
1602
1603
1604bool CNullDriver::isHardwareBufferRecommend(const scene::IMeshBuffer* mb)
1605{
1606 if (!mb || (mb->getHardwareMappingHint_Index()==scene::EHM_NEVER && mb->getHardwareMappingHint_Vertex()==scene::EHM_NEVER))
1607 return false;
1608
1609 if (mb->getVertexCount()<MinVertexCountForVBO)
1610 return false;
1611
1612 return true;
1613}
1614
1615
1616//! Create occlusion query.
1617/** Use node for identification and mesh for occlusion test. */
1618void CNullDriver::addOcclusionQuery(scene::ISceneNode* node, const scene::IMesh* mesh)
1619{
1620 if (!node)
1621 return;
1622 if (!mesh)
1623 {
1624 if ((node->getType() != scene::ESNT_MESH) && (node->getType() != scene::ESNT_ANIMATED_MESH))
1625 return;
1626 else if (node->getType() == scene::ESNT_MESH)
1627 mesh = static_cast<scene::IMeshSceneNode*>(node)->getMesh();
1628 else
1629 mesh = static_cast<scene::IAnimatedMeshSceneNode*>(node)->getMesh()->getMesh(0);
1630 if (!mesh)
1631 return;
1632 }
1633
1634 //search for query
1635 s32 index = OcclusionQueries.linear_search(SOccQuery(node));
1636 if (index != -1)
1637 {
1638 if (OcclusionQueries[index].Mesh != mesh)
1639 {
1640 OcclusionQueries[index].Mesh->drop();
1641 OcclusionQueries[index].Mesh = mesh;
1642 mesh->grab();
1643 }
1644 }
1645 else
1646 {
1647 OcclusionQueries.push_back(SOccQuery(node, mesh));
1648 node->setAutomaticCulling(node->getAutomaticCulling() | scene::EAC_OCC_QUERY);
1649 }
1650}
1651
1652
1653//! Remove occlusion query.
1654void CNullDriver::removeOcclusionQuery(scene::ISceneNode* node)
1655{
1656 //search for query
1657 s32 index = OcclusionQueries.linear_search(SOccQuery(node));
1658 if (index != -1)
1659 {
1660 node->setAutomaticCulling(node->getAutomaticCulling() & ~scene::EAC_OCC_QUERY);
1661 OcclusionQueries.erase(index);
1662 }
1663}
1664
1665
1666//! Remove all occlusion queries.
1667void CNullDriver::removeAllOcclusionQueries()
1668{
1669 for (s32 i=OcclusionQueries.size()-1; i>=0; --i)
1670 {
1671 removeOcclusionQuery(OcclusionQueries[i].Node);
1672 }
1673}
1674
1675
1676//! Run occlusion query. Draws mesh stored in query.
1677/** If the mesh shall be rendered visible, use
1678flag to enable the proper material setting. */
1679void CNullDriver::runOcclusionQuery(scene::ISceneNode* node, bool visible)
1680{
1681 if(!node)
1682 return;
1683 s32 index = OcclusionQueries.linear_search(SOccQuery(node));
1684 if (index==-1)
1685 return;
1686 OcclusionQueries[index].Run=0;
1687 if (!visible)
1688 {
1689 SMaterial mat;
1690 mat.Lighting=false;
1691 mat.AntiAliasing=0;
1692 mat.ColorMask=ECP_NONE;
1693 mat.GouraudShading=false;
1694 mat.ZWriteEnable=false;
1695 setMaterial(mat);
1696 }
1697 setTransform(video::ETS_WORLD, node->getAbsoluteTransformation());
1698 const scene::IMesh* mesh = OcclusionQueries[index].Mesh;
1699 for (u32 i=0; i<mesh->getMeshBufferCount(); ++i)
1700 {
1701 if (visible)
1702 setMaterial(mesh->getMeshBuffer(i)->getMaterial());
1703 drawMeshBuffer(mesh->getMeshBuffer(i));
1704 }
1705}
1706
1707
1708//! Run all occlusion queries. Draws all meshes stored in queries.
1709/** If the meshes shall not be rendered visible, use
1710overrideMaterial to disable the color and depth buffer. */
1711void CNullDriver::runAllOcclusionQueries(bool visible)
1712{
1713 for (u32 i=0; i<OcclusionQueries.size(); ++i)
1714 runOcclusionQuery(OcclusionQueries[i].Node, visible);
1715}
1716
1717
1718//! Update occlusion query. Retrieves results from GPU.
1719/** If the query shall not block, set the flag to false.
1720Update might not occur in this case, though */
1721void CNullDriver::updateOcclusionQuery(scene::ISceneNode* node, bool block)
1722{
1723}
1724
1725
1726//! Update all occlusion queries. Retrieves results from GPU.
1727/** If the query shall not block, set the flag to false.
1728Update might not occur in this case, though */
1729void CNullDriver::updateAllOcclusionQueries(bool block)
1730{
1731 for (u32 i=0; i<OcclusionQueries.size(); ++i)
1732 {
1733 if (OcclusionQueries[i].Run==u32(~0))
1734 continue;
1735 updateOcclusionQuery(OcclusionQueries[i].Node, block);
1736 ++OcclusionQueries[i].Run;
1737 if (OcclusionQueries[i].Run>1000)
1738 removeOcclusionQuery(OcclusionQueries[i].Node);
1739 }
1740}
1741
1742
1743//! Return query result.
1744/** Return value is the number of visible pixels/fragments.
1745The value is a safe approximation, i.e. can be larger then the
1746actual value of pixels. */
1747u32 CNullDriver::getOcclusionQueryResult(scene::ISceneNode* node) const
1748{
1749 return ~0;
1750}
1751
1752
1753//! Only used by the internal engine. Used to notify the driver that
1754//! the window was resized.
1755void CNullDriver::OnResize(const core::dimension2d<u32>& size)
1756{
1757 if (ViewPort.getWidth() == (s32)ScreenSize.Width &&
1758 ViewPort.getHeight() == (s32)ScreenSize.Height)
1759 ViewPort = core::rect<s32>(core::position2d<s32>(0,0),
1760 core::dimension2di(size));
1761
1762 ScreenSize = size;
1763}
1764
1765
1766// adds a material renderer and drops it afterwards. To be used for internal creation
1767s32 CNullDriver::addAndDropMaterialRenderer(IMaterialRenderer* m)
1768{
1769 s32 i = addMaterialRenderer(m);
1770
1771 if (m)
1772 m->drop();
1773
1774 return i;
1775}
1776
1777
1778//! Adds a new material renderer to the video device.
1779s32 CNullDriver::addMaterialRenderer(IMaterialRenderer* renderer, const char* name)
1780{
1781 if (!renderer)
1782 return -1;
1783
1784 SMaterialRenderer r;
1785 r.Renderer = renderer;
1786 r.Name = name;
1787
1788 if (name == 0 && (MaterialRenderers.size() < (sizeof(sBuiltInMaterialTypeNames) / sizeof(char*))-1 ))
1789 {
1790 // set name of built in renderer so that we don't have to implement name
1791 // setting in all available renderers.
1792 r.Name = sBuiltInMaterialTypeNames[MaterialRenderers.size()];
1793 }
1794
1795 MaterialRenderers.push_back(r);
1796 renderer->grab();
1797
1798 return MaterialRenderers.size()-1;
1799}
1800
1801
1802//! Sets the name of a material renderer.
1803void CNullDriver::setMaterialRendererName(s32 idx, const char* name)
1804{
1805 if (idx < s32(sizeof(sBuiltInMaterialTypeNames) / sizeof(char*))-1 ||
1806 idx >= (s32)MaterialRenderers.size())
1807 return;
1808
1809 MaterialRenderers[idx].Name = name;
1810}
1811
1812
1813//! Creates material attributes list from a material, usable for serialization and more.
1814io::IAttributes* CNullDriver::createAttributesFromMaterial(const video::SMaterial& material,
1815 io::SAttributeReadWriteOptions* options)
1816{
1817 io::CAttributes* attr = new io::CAttributes(this);
1818
1819 attr->addEnum("Type", material.MaterialType, sBuiltInMaterialTypeNames);
1820
1821 attr->addColor("Ambient", material.AmbientColor);
1822 attr->addColor("Diffuse", material.DiffuseColor);
1823 attr->addColor("Emissive", material.EmissiveColor);
1824 attr->addColor("Specular", material.SpecularColor);
1825
1826 attr->addFloat("Shininess", material.Shininess);
1827 attr->addFloat("Param1", material.MaterialTypeParam);
1828 attr->addFloat("Param2", material.MaterialTypeParam2);
1829
1830 core::stringc prefix="Texture";
1831 u32 i;
1832 for (i=0; i<MATERIAL_MAX_TEXTURES; ++i)
1833 {
1834 if (options && (options->Flags&io::EARWF_USE_RELATIVE_PATHS) && options->Filename && material.getTexture(i))
1835 {
1836 io::path path = FileSystem->getRelativeFilename(
1837 FileSystem->getAbsolutePath(material.getTexture(i)->getName()), options->Filename);
1838 attr->addTexture((prefix+core::stringc(i+1)).c_str(), material.getTexture(i), path);
1839 }
1840 else
1841 attr->addTexture((prefix+core::stringc(i+1)).c_str(), material.getTexture(i));
1842 }
1843
1844 attr->addBool("Wireframe", material.Wireframe);
1845 attr->addBool("GouraudShading", material.GouraudShading);
1846 attr->addBool("Lighting", material.Lighting);
1847 attr->addBool("ZWriteEnable", material.ZWriteEnable);
1848 attr->addInt("ZBuffer", material.ZBuffer);
1849 attr->addBool("BackfaceCulling", material.BackfaceCulling);
1850 attr->addBool("FrontfaceCulling", material.FrontfaceCulling);
1851 attr->addBool("FogEnable", material.FogEnable);
1852 attr->addBool("NormalizeNormals", material.NormalizeNormals);
1853 attr->addBool("UseMipMaps", material.UseMipMaps);
1854 attr->addInt("AntiAliasing", material.AntiAliasing);
1855 attr->addInt("ColorMask", material.ColorMask);
1856 attr->addInt("ColorMaterial", material.ColorMaterial);
1857 attr->addInt("PolygonOffsetFactor", material.PolygonOffsetFactor);
1858 attr->addEnum("PolygonOffsetDirection", material.PolygonOffsetDirection, video::PolygonOffsetDirectionNames);
1859
1860 prefix = "BilinearFilter";
1861 for (i=0; i<MATERIAL_MAX_TEXTURES; ++i)
1862 attr->addBool((prefix+core::stringc(i+1)).c_str(), material.TextureLayer[i].BilinearFilter);
1863 prefix = "TrilinearFilter";
1864 for (i=0; i<MATERIAL_MAX_TEXTURES; ++i)
1865 attr->addBool((prefix+core::stringc(i+1)).c_str(), material.TextureLayer[i].TrilinearFilter);
1866 prefix = "AnisotropicFilter";
1867 for (i=0; i<MATERIAL_MAX_TEXTURES; ++i)
1868 attr->addInt((prefix+core::stringc(i+1)).c_str(), material.TextureLayer[i].AnisotropicFilter);
1869 prefix="TextureWrapU";
1870 for (i=0; i<MATERIAL_MAX_TEXTURES; ++i)
1871 attr->addEnum((prefix+core::stringc(i+1)).c_str(), material.TextureLayer[i].TextureWrapU, aTextureClampNames);
1872 prefix="TextureWrapV";
1873 for (i=0; i<MATERIAL_MAX_TEXTURES; ++i)
1874 attr->addEnum((prefix+core::stringc(i+1)).c_str(), material.TextureLayer[i].TextureWrapV, aTextureClampNames);
1875 prefix="LODBias";
1876 for (i=0; i<MATERIAL_MAX_TEXTURES; ++i)
1877 attr->addInt((prefix+core::stringc(i+1)).c_str(), material.TextureLayer[i].LODBias);
1878
1879 return attr;
1880}
1881
1882
1883//! Fills an SMaterial structure from attributes.
1884void CNullDriver::fillMaterialStructureFromAttributes(video::SMaterial& outMaterial, io::IAttributes* attr)
1885{
1886 outMaterial.MaterialType = video::EMT_SOLID;
1887
1888 core::stringc name = attr->getAttributeAsString("Type");
1889
1890 u32 i;
1891
1892 for ( i=0; i < MaterialRenderers.size(); ++i)
1893 if ( name == MaterialRenderers[i].Name )
1894 {
1895 outMaterial.MaterialType = (video::E_MATERIAL_TYPE)i;
1896 break;
1897 }
1898
1899 outMaterial.AmbientColor = attr->getAttributeAsColor("Ambient");
1900 outMaterial.DiffuseColor = attr->getAttributeAsColor("Diffuse");
1901 outMaterial.EmissiveColor = attr->getAttributeAsColor("Emissive");
1902 outMaterial.SpecularColor = attr->getAttributeAsColor("Specular");
1903
1904 outMaterial.Shininess = attr->getAttributeAsFloat("Shininess");
1905 outMaterial.MaterialTypeParam = attr->getAttributeAsFloat("Param1");
1906 outMaterial.MaterialTypeParam2 = attr->getAttributeAsFloat("Param2");
1907
1908 core::stringc prefix="Texture";
1909 for (i=0; i<MATERIAL_MAX_TEXTURES; ++i)
1910 outMaterial.setTexture(i, attr->getAttributeAsTexture((prefix+core::stringc(i+1)).c_str()));
1911
1912 outMaterial.Wireframe = attr->getAttributeAsBool("Wireframe");
1913 outMaterial.GouraudShading = attr->getAttributeAsBool("GouraudShading");
1914 outMaterial.Lighting = attr->getAttributeAsBool("Lighting");
1915 outMaterial.ZWriteEnable = attr->getAttributeAsBool("ZWriteEnable");
1916 outMaterial.ZBuffer = (u8)attr->getAttributeAsInt("ZBuffer");
1917 outMaterial.BackfaceCulling = attr->getAttributeAsBool("BackfaceCulling");
1918 outMaterial.FrontfaceCulling = attr->getAttributeAsBool("FrontfaceCulling");
1919 outMaterial.FogEnable = attr->getAttributeAsBool("FogEnable");
1920 outMaterial.NormalizeNormals = attr->getAttributeAsBool("NormalizeNormals");
1921 if (attr->existsAttribute("UseMipMaps")) // legacy
1922 outMaterial.UseMipMaps = attr->getAttributeAsBool("UseMipMaps");
1923 else
1924 outMaterial.UseMipMaps = true;
1925
1926 // default 0 is ok
1927 outMaterial.AntiAliasing = attr->getAttributeAsInt("AntiAliasing");
1928 if (attr->existsAttribute("ColorMask"))
1929 outMaterial.ColorMask = attr->getAttributeAsInt("ColorMask");
1930 if (attr->existsAttribute("ColorMaterial"))
1931 outMaterial.ColorMaterial = attr->getAttributeAsInt("ColorMaterial");
1932 if (attr->existsAttribute("PolygonOffsetFactor"))
1933 outMaterial.PolygonOffsetFactor = attr->getAttributeAsInt("PolygonOffsetFactor");
1934 if (attr->existsAttribute("PolygonOffsetDirection"))
1935 outMaterial.PolygonOffsetDirection = (video::E_POLYGON_OFFSET)attr->getAttributeAsEnumeration("PolygonOffsetDirection", video::PolygonOffsetDirectionNames);
1936 prefix = "BilinearFilter";
1937 if (attr->existsAttribute(prefix.c_str())) // legacy
1938 outMaterial.setFlag(EMF_BILINEAR_FILTER, attr->getAttributeAsBool(prefix.c_str()));
1939 else
1940 for (i=0; i<MATERIAL_MAX_TEXTURES; ++i)
1941 outMaterial.TextureLayer[i].BilinearFilter = attr->getAttributeAsBool((prefix+core::stringc(i+1)).c_str());
1942
1943 prefix = "TrilinearFilter";
1944 if (attr->existsAttribute(prefix.c_str())) // legacy
1945 outMaterial.setFlag(EMF_TRILINEAR_FILTER, attr->getAttributeAsBool(prefix.c_str()));
1946 else
1947 for (i=0; i<MATERIAL_MAX_TEXTURES; ++i)
1948 outMaterial.TextureLayer[i].TrilinearFilter = attr->getAttributeAsBool((prefix+core::stringc(i+1)).c_str());
1949
1950 prefix = "AnisotropicFilter";
1951 if (attr->existsAttribute(prefix.c_str())) // legacy
1952 outMaterial.setFlag(EMF_ANISOTROPIC_FILTER, attr->getAttributeAsBool(prefix.c_str()));
1953 else
1954 for (i=0; i<MATERIAL_MAX_TEXTURES; ++i)
1955 outMaterial.TextureLayer[i].AnisotropicFilter = attr->getAttributeAsInt((prefix+core::stringc(i+1)).c_str());
1956
1957 prefix = "TextureWrap";
1958 if (attr->existsAttribute(prefix.c_str())) // legacy
1959 {
1960 for (i=0; i<MATERIAL_MAX_TEXTURES; ++i)
1961 {
1962 outMaterial.TextureLayer[i].TextureWrapU = (E_TEXTURE_CLAMP)attr->getAttributeAsEnumeration((prefix+core::stringc(i+1)).c_str(), aTextureClampNames);
1963 outMaterial.TextureLayer[i].TextureWrapV = outMaterial.TextureLayer[i].TextureWrapU;
1964 }
1965 }
1966 else
1967 {
1968 for (i=0; i<MATERIAL_MAX_TEXTURES; ++i)
1969 {
1970 outMaterial.TextureLayer[i].TextureWrapU = (E_TEXTURE_CLAMP)attr->getAttributeAsEnumeration((prefix+"U"+core::stringc(i+1)).c_str(), aTextureClampNames);
1971 outMaterial.TextureLayer[i].TextureWrapV = (E_TEXTURE_CLAMP)attr->getAttributeAsEnumeration((prefix+"V"+core::stringc(i+1)).c_str(), aTextureClampNames);
1972 }
1973 }
1974
1975 // default 0 is ok
1976 prefix="LODBias";
1977 for (i=0; i<MATERIAL_MAX_TEXTURES; ++i)
1978 outMaterial.TextureLayer[i].LODBias = attr->getAttributeAsInt((prefix+core::stringc(i+1)).c_str());
1979}
1980
1981
1982//! Returns driver and operating system specific data about the IVideoDriver.
1983const SExposedVideoData& CNullDriver::getExposedVideoData()
1984{
1985 return ExposedData;
1986}
1987
1988
1989//! Returns type of video driver
1990E_DRIVER_TYPE CNullDriver::getDriverType() const
1991{
1992 return EDT_NULL;
1993}
1994
1995
1996//! deletes all material renderers
1997void CNullDriver::deleteMaterialRenders()
1998{
1999 // delete material renderers
2000 for (u32 i=0; i<MaterialRenderers.size(); ++i)
2001 if (MaterialRenderers[i].Renderer)
2002 MaterialRenderers[i].Renderer->drop();
2003
2004 MaterialRenderers.clear();
2005}
2006
2007
2008//! Returns pointer to material renderer or null
2009IMaterialRenderer* CNullDriver::getMaterialRenderer(u32 idx)
2010{
2011 if ( idx < MaterialRenderers.size() )
2012 return MaterialRenderers[idx].Renderer;
2013 else
2014 return 0;
2015}
2016
2017
2018//! Returns amount of currently available material renderers.
2019u32 CNullDriver::getMaterialRendererCount() const
2020{
2021 return MaterialRenderers.size();
2022}
2023
2024
2025//! Returns name of the material renderer
2026const char* CNullDriver::getMaterialRendererName(u32 idx) const
2027{
2028 if ( idx < MaterialRenderers.size() )
2029 return MaterialRenderers[idx].Name.c_str();
2030
2031 return 0;
2032}
2033
2034
2035//! Returns pointer to the IGPUProgrammingServices interface.
2036IGPUProgrammingServices* CNullDriver::getGPUProgrammingServices()
2037{
2038 return this;
2039}
2040
2041
2042//! Adds a new material renderer to the VideoDriver, based on a high level shading language.
2043s32 CNullDriver::addHighLevelShaderMaterial(
2044 const c8* vertexShaderProgram,
2045 const c8* vertexShaderEntryPointName,
2046 E_VERTEX_SHADER_TYPE vsCompileTarget,
2047 const c8* pixelShaderProgram,
2048 const c8* pixelShaderEntryPointName,
2049 E_PIXEL_SHADER_TYPE psCompileTarget,
2050 const c8* geometryShaderProgram,
2051 const c8* geometryShaderEntryPointName,
2052 E_GEOMETRY_SHADER_TYPE gsCompileTarget,
2053 scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,
2054 u32 verticesOut,
2055 IShaderConstantSetCallBack* callback,
2056 E_MATERIAL_TYPE baseMaterial,
2057 s32 userData, E_GPU_SHADING_LANGUAGE shadingLang)
2058{
2059 os::Printer::log("High level shader materials not available (yet) in this driver, sorry");
2060 return -1;
2061}
2062
2063
2064//! Like IGPUProgrammingServices::addShaderMaterial() (look there for a detailed description),
2065//! but tries to load the programs from files.
2066s32 CNullDriver::addHighLevelShaderMaterialFromFiles(
2067 const io::path& vertexShaderProgramFileName,
2068 const c8* vertexShaderEntryPointName,
2069 E_VERTEX_SHADER_TYPE vsCompileTarget,
2070 const io::path& pixelShaderProgramFileName,
2071 const c8* pixelShaderEntryPointName,
2072 E_PIXEL_SHADER_TYPE psCompileTarget,
2073 const io::path& geometryShaderProgramFileName,
2074 const c8* geometryShaderEntryPointName,
2075 E_GEOMETRY_SHADER_TYPE gsCompileTarget,
2076 scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,
2077 u32 verticesOut,
2078 IShaderConstantSetCallBack* callback,
2079 E_MATERIAL_TYPE baseMaterial,
2080 s32 userData, E_GPU_SHADING_LANGUAGE shadingLang)
2081{
2082 io::IReadFile* vsfile = 0;
2083 io::IReadFile* psfile = 0;
2084 io::IReadFile* gsfile = 0;
2085
2086 if (vertexShaderProgramFileName.size() )
2087 {
2088 vsfile = FileSystem->createAndOpenFile(vertexShaderProgramFileName);
2089 if (!vsfile)
2090 {
2091 os::Printer::log("Could not open vertex shader program file",
2092 vertexShaderProgramFileName, ELL_WARNING);
2093 }
2094 }
2095
2096 if (pixelShaderProgramFileName.size() )
2097 {
2098 psfile = FileSystem->createAndOpenFile(pixelShaderProgramFileName);
2099 if (!psfile)
2100 {
2101 os::Printer::log("Could not open pixel shader program file",
2102 pixelShaderProgramFileName, ELL_WARNING);
2103 }
2104 }
2105
2106 if (geometryShaderProgramFileName.size() )
2107 {
2108 gsfile = FileSystem->createAndOpenFile(geometryShaderProgramFileName);
2109 if (!gsfile)
2110 {
2111 os::Printer::log("Could not open geometry shader program file",
2112 geometryShaderProgramFileName, ELL_WARNING);
2113 }
2114 }
2115
2116 s32 result = addHighLevelShaderMaterialFromFiles(
2117 vsfile, vertexShaderEntryPointName, vsCompileTarget,
2118 psfile, pixelShaderEntryPointName, psCompileTarget,
2119 gsfile, geometryShaderEntryPointName, gsCompileTarget,
2120 inType, outType, verticesOut,
2121 callback, baseMaterial, userData, shadingLang);
2122
2123 if (psfile)
2124 psfile->drop();
2125
2126 if (vsfile)
2127 vsfile->drop();
2128
2129 if (gsfile)
2130 gsfile->drop();
2131
2132 return result;
2133}
2134
2135
2136//! Like IGPUProgrammingServices::addShaderMaterial() (look there for a detailed description),
2137//! but tries to load the programs from files.
2138s32 CNullDriver::addHighLevelShaderMaterialFromFiles(
2139 io::IReadFile* vertexShaderProgram,
2140 const c8* vertexShaderEntryPointName,
2141 E_VERTEX_SHADER_TYPE vsCompileTarget,
2142 io::IReadFile* pixelShaderProgram,
2143 const c8* pixelShaderEntryPointName,
2144 E_PIXEL_SHADER_TYPE psCompileTarget,
2145 io::IReadFile* geometryShaderProgram,
2146 const c8* geometryShaderEntryPointName,
2147 E_GEOMETRY_SHADER_TYPE gsCompileTarget,
2148 scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,
2149 u32 verticesOut,
2150 IShaderConstantSetCallBack* callback,
2151 E_MATERIAL_TYPE baseMaterial,
2152 s32 userData, E_GPU_SHADING_LANGUAGE shadingLang)
2153{
2154 c8* vs = 0;
2155 c8* ps = 0;
2156 c8* gs = 0;
2157
2158 if (vertexShaderProgram)
2159 {
2160 const long size = vertexShaderProgram->getSize();
2161 if (size)
2162 {
2163 vs = new c8[size+1];
2164 vertexShaderProgram->read(vs, size);
2165 vs[size] = 0;
2166 }
2167 }
2168
2169 if (pixelShaderProgram)
2170 {
2171 const long size = pixelShaderProgram->getSize();
2172 if (size)
2173 {
2174 // if both handles are the same we must reset the file
2175 if (pixelShaderProgram==vertexShaderProgram)
2176 pixelShaderProgram->seek(0);
2177 ps = new c8[size+1];
2178 pixelShaderProgram->read(ps, size);
2179 ps[size] = 0;
2180 }
2181 }
2182
2183 if (geometryShaderProgram)
2184 {
2185 const long size = geometryShaderProgram->getSize();
2186 if (size)
2187 {
2188 // if both handles are the same we must reset the file
2189 if ((geometryShaderProgram==vertexShaderProgram) ||
2190 (geometryShaderProgram==pixelShaderProgram))
2191 geometryShaderProgram->seek(0);
2192 gs = new c8[size+1];
2193 geometryShaderProgram->read(gs, size);
2194 gs[size] = 0;
2195 }
2196 }
2197
2198 s32 result = this->addHighLevelShaderMaterial(
2199 vs, vertexShaderEntryPointName, vsCompileTarget,
2200 ps, pixelShaderEntryPointName, psCompileTarget,
2201 gs, geometryShaderEntryPointName, gsCompileTarget,
2202 inType, outType, verticesOut,
2203 callback, baseMaterial, userData, shadingLang);
2204
2205 delete [] vs;
2206 delete [] ps;
2207 delete [] gs;
2208
2209 return result;
2210}
2211
2212
2213//! Adds a new material renderer to the VideoDriver, using pixel and/or
2214//! vertex shaders to render geometry.
2215s32 CNullDriver::addShaderMaterial(const c8* vertexShaderProgram,
2216 const c8* pixelShaderProgram,
2217 IShaderConstantSetCallBack* callback,
2218 E_MATERIAL_TYPE baseMaterial,
2219 s32 userData)
2220{
2221 os::Printer::log("Shader materials not implemented yet in this driver, sorry.");
2222 return -1;
2223}
2224
2225
2226//! Like IGPUProgrammingServices::addShaderMaterial(), but tries to load the
2227//! programs from files.
2228s32 CNullDriver::addShaderMaterialFromFiles(io::IReadFile* vertexShaderProgram,
2229 io::IReadFile* pixelShaderProgram,
2230 IShaderConstantSetCallBack* callback,
2231 E_MATERIAL_TYPE baseMaterial,
2232 s32 userData)
2233{
2234 c8* vs = 0;
2235 c8* ps = 0;
2236
2237 if (vertexShaderProgram)
2238 {
2239 const long size = vertexShaderProgram->getSize();
2240 if (size)
2241 {
2242 vs = new c8[size+1];
2243 vertexShaderProgram->read(vs, size);
2244 vs[size] = 0;
2245 }
2246 }
2247
2248 if (pixelShaderProgram)
2249 {
2250 const long size = pixelShaderProgram->getSize();
2251 if (size)
2252 {
2253 ps = new c8[size+1];
2254 pixelShaderProgram->read(ps, size);
2255 ps[size] = 0;
2256 }
2257 }
2258
2259 s32 result = addShaderMaterial(vs, ps, callback, baseMaterial, userData);
2260
2261 delete [] vs;
2262 delete [] ps;
2263
2264 return result;
2265}
2266
2267
2268//! Like IGPUProgrammingServices::addShaderMaterial(), but tries to load the
2269//! programs from files.
2270s32 CNullDriver::addShaderMaterialFromFiles(const io::path& vertexShaderProgramFileName,
2271 const io::path& pixelShaderProgramFileName,
2272 IShaderConstantSetCallBack* callback,
2273 E_MATERIAL_TYPE baseMaterial,
2274 s32 userData)
2275{
2276 io::IReadFile* vsfile = 0;
2277 io::IReadFile* psfile = 0;
2278
2279 if (vertexShaderProgramFileName.size())
2280 {
2281 vsfile = FileSystem->createAndOpenFile(vertexShaderProgramFileName);
2282 if (!vsfile)
2283 {
2284 os::Printer::log("Could not open vertex shader program file",
2285 vertexShaderProgramFileName, ELL_WARNING);
2286 return -1;
2287 }
2288 }
2289
2290 if (pixelShaderProgramFileName.size())
2291 {
2292 psfile = FileSystem->createAndOpenFile(pixelShaderProgramFileName);
2293 if (!psfile)
2294 {
2295 os::Printer::log("Could not open pixel shader program file",
2296 pixelShaderProgramFileName, ELL_WARNING);
2297 if (vsfile)
2298 vsfile->drop();
2299 return -1;
2300 }
2301 }
2302
2303 s32 result = addShaderMaterialFromFiles(vsfile, psfile, callback,
2304 baseMaterial, userData);
2305
2306 if (psfile)
2307 psfile->drop();
2308
2309 if (vsfile)
2310 vsfile->drop();
2311
2312 return result;
2313}
2314
2315
2316//! Creates a render target texture.
2317ITexture* CNullDriver::addRenderTargetTexture(const core::dimension2d<u32>& size,
2318 const io::path&name, const ECOLOR_FORMAT format)
2319{
2320 return 0;
2321}
2322
2323
2324//! Clears the ZBuffer.
2325void CNullDriver::clearZBuffer()
2326{
2327}
2328
2329
2330//! Returns a pointer to the mesh manipulator.
2331scene::IMeshManipulator* CNullDriver::getMeshManipulator()
2332{
2333 return MeshManipulator;
2334}
2335
2336
2337//! Returns an image created from the last rendered frame.
2338IImage* CNullDriver::createScreenShot(video::ECOLOR_FORMAT format, video::E_RENDER_TARGET target)
2339{
2340 return 0;
2341}
2342
2343
2344// prints renderer version
2345void CNullDriver::printVersion()
2346{
2347 core::stringw namePrint = L"Using renderer: ";
2348 namePrint += getName();
2349 os::Printer::log(namePrint.c_str(), ELL_INFORMATION);
2350}
2351
2352
2353//! creates a video driver
2354IVideoDriver* createNullDriver(io::IFileSystem* io, const core::dimension2d<u32>& screenSize)
2355{
2356 CNullDriver* nullDriver = new CNullDriver(io, screenSize);
2357
2358 // create empty material renderers
2359 for(u32 i=0; sBuiltInMaterialTypeNames[i]; ++i)
2360 {
2361 IMaterialRenderer* imr = new IMaterialRenderer();
2362 nullDriver->addMaterialRenderer(imr);
2363 imr->drop();
2364 }
2365
2366 return nullDriver;
2367}
2368
2369
2370//! Set/unset a clipping plane.
2371//! There are at least 6 clipping planes available for the user to set at will.
2372//! \param index: The plane index. Must be between 0 and MaxUserClipPlanes.
2373//! \param plane: The plane itself.
2374//! \param enable: If true, enable the clipping plane else disable it.
2375bool CNullDriver::setClipPlane(u32 index, const core::plane3df& plane, bool enable)
2376{
2377 return false;
2378}
2379
2380
2381//! Enable/disable a clipping plane.
2382void CNullDriver::enableClipPlane(u32 index, bool enable)
2383{
2384 // not necessary
2385}
2386
2387
2388ITexture* CNullDriver::createRenderTargetTexture(const core::dimension2d<u32>& size,
2389 const c8* name)
2390{
2391 os::Printer::log("createRenderTargetTexture is deprecated, use addRenderTargetTexture instead");
2392 ITexture* tex = addRenderTargetTexture(size, name);
2393 tex->grab();
2394 return tex;
2395}
2396
2397
2398void CNullDriver::setMinHardwareBufferVertexCount(u32 count)
2399{
2400 MinVertexCountForVBO = count;
2401}
2402
2403
2404SOverrideMaterial& CNullDriver::getOverrideMaterial()
2405{
2406 return OverrideMaterial;
2407}
2408
2409
2410//! Get the 2d override material for altering its values
2411SMaterial& CNullDriver::getMaterial2D()
2412{
2413 return OverrideMaterial2D;
2414}
2415
2416
2417//! Enable the 2d override material
2418void CNullDriver::enableMaterial2D(bool enable)
2419{
2420 OverrideMaterial2DEnabled=enable;
2421}
2422
2423
2424core::dimension2du CNullDriver::getMaxTextureSize() const
2425{
2426 return core::dimension2du(0x10000,0x10000); // maybe large enough
2427}
2428
2429
2430//! Color conversion convenience function
2431/** Convert an image (as array of pixels) from source to destination
2432array, thereby converting the color format. The pixel size is
2433determined by the color formats.
2434\param sP Pointer to source
2435\param sF Color format of source
2436\param sN Number of pixels to convert, both array must be large enough
2437\param dP Pointer to destination
2438\param dF Color format of destination
2439*/
2440void CNullDriver::convertColor(const void* sP, ECOLOR_FORMAT sF, s32 sN,
2441 void* dP, ECOLOR_FORMAT dF) const
2442{
2443 video::CColorConverter::convert_viaFormat(sP, sF, sN, dP, dF);
2444}
2445
2446
2447} // end namespace
2448} // end namespace