1 // Copyright (C) 2002-2012 Nikolaus Gebhardt
\r
2 // This file is part of the "Irrlicht Engine".
\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h
\r
5 #include "CNullDriver.h"
\r
8 #include "CAttributes.h"
\r
9 #include "IReadFile.h"
\r
10 #include "IWriteFile.h"
\r
11 #include "IImageLoader.h"
\r
12 #include "IImageWriter.h"
\r
13 #include "IMaterialRenderer.h"
\r
14 #include "IAnimatedMeshSceneNode.h"
\r
15 #include "CMeshManipulator.h"
\r
16 #include "CColorConverter.h"
\r
17 #include "IReferenceCounted.h"
\r
18 #include "IRenderTarget.h"
\r
26 //! creates a loader which is able to load windows bitmaps
\r
27 IImageLoader* createImageLoaderBMP();
\r
29 //! creates a loader which is able to load jpeg images
\r
30 IImageLoader* createImageLoaderJPG();
\r
32 //! creates a loader which is able to load targa images
\r
33 IImageLoader* createImageLoaderTGA();
\r
35 //! creates a loader which is able to load png images
\r
36 IImageLoader* createImageLoaderPNG();
\r
38 //! creates a writer which is able to save jpg images
\r
39 IImageWriter* createImageWriterJPG();
\r
41 //! creates a writer which is able to save png images
\r
42 IImageWriter* createImageWriterPNG();
\r
46 CNullDriver::CNullDriver(io::IFileSystem* io, const core::dimension2d<u32>& screenSize)
\r
47 : SharedRenderTarget(0), CurrentRenderTarget(0), CurrentRenderTargetSize(0, 0), FileSystem(io), MeshManipulator(0),
\r
48 ViewPort(0, 0, 0, 0), ScreenSize(screenSize), PrimitivesDrawn(0), MinVertexCountForVBO(500),
\r
49 TextureCreationFlags(0), OverrideMaterial2DEnabled(false), AllowZWriteOnTransparent(false)
\r
52 setDebugName("CNullDriver");
\r
55 DriverAttributes = new io::CAttributes();
\r
56 DriverAttributes->addInt("MaxTextures", MATERIAL_MAX_TEXTURES);
\r
57 DriverAttributes->addInt("MaxSupportedTextures", MATERIAL_MAX_TEXTURES);
\r
58 DriverAttributes->addInt("MaxAnisotropy", 1);
\r
59 // DriverAttributes->addInt("MaxUserClipPlanes", 0);
\r
60 // DriverAttributes->addInt("MaxAuxBuffers", 0);
\r
61 DriverAttributes->addInt("MaxMultipleRenderTargets", 1);
\r
62 DriverAttributes->addInt("MaxIndices", -1);
\r
63 DriverAttributes->addInt("MaxTextureSize", -1);
\r
64 // DriverAttributes->addInt("MaxGeometryVerticesOut", 0);
\r
65 // DriverAttributes->addFloat("MaxTextureLODBias", 0.f);
\r
66 DriverAttributes->addInt("Version", 1);
\r
67 // DriverAttributes->addInt("ShaderLanguageVersion", 0);
\r
68 // DriverAttributes->addInt("AntiAlias", 0);
\r
72 setTextureCreationFlag(ETCF_ALWAYS_32_BIT, true);
\r
73 setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, true);
\r
74 setTextureCreationFlag(ETCF_AUTO_GENERATE_MIP_MAPS, true);
\r
75 setTextureCreationFlag(ETCF_ALLOW_MEMORY_COPY, true);
\r
77 ViewPort = core::rect<s32>(core::position2d<s32>(0,0), core::dimension2di(screenSize));
\r
79 // create manipulator
\r
80 MeshManipulator = new scene::CMeshManipulator();
\r
85 // create surface loaders and writers
\r
86 SurfaceLoader.push_back(video::createImageLoaderTGA());
\r
87 SurfaceLoader.push_back(video::createImageLoaderPNG());
\r
88 SurfaceLoader.push_back(video::createImageLoaderJPG());
\r
89 SurfaceLoader.push_back(video::createImageLoaderBMP());
\r
91 SurfaceWriter.push_back(video::createImageWriterJPG());
\r
92 SurfaceWriter.push_back(video::createImageWriterPNG());
\r
95 // set ExposedData to 0
\r
96 memset((void*)&ExposedData, 0, sizeof(ExposedData));
\r
97 for (u32 i=0; i<video::EVDF_COUNT; ++i)
\r
98 FeatureEnabled[i]=true;
\r
100 InitMaterial2D.AntiAliasing=video::EAAM_OFF;
\r
101 InitMaterial2D.Lighting=false;
\r
102 InitMaterial2D.ZWriteEnable=video::EZW_OFF;
\r
103 InitMaterial2D.ZBuffer=video::ECFN_DISABLED;
\r
104 InitMaterial2D.UseMipMaps=false;
\r
105 for (u32 i=0; i<video::MATERIAL_MAX_TEXTURES; ++i)
\r
107 InitMaterial2D.TextureLayer[i].BilinearFilter=false;
\r
108 InitMaterial2D.TextureLayer[i].TextureWrapU=video::ETC_REPEAT;
\r
109 InitMaterial2D.TextureLayer[i].TextureWrapV=video::ETC_REPEAT;
\r
110 InitMaterial2D.TextureLayer[i].TextureWrapW = video::ETC_REPEAT;
\r
112 OverrideMaterial2D=InitMaterial2D;
\r
117 CNullDriver::~CNullDriver()
\r
119 if (DriverAttributes)
\r
120 DriverAttributes->drop();
\r
123 FileSystem->drop();
\r
125 if (MeshManipulator)
\r
126 MeshManipulator->drop();
\r
128 removeAllRenderTargets();
\r
130 deleteAllTextures();
\r
133 for (i=0; i<SurfaceLoader.size(); ++i)
\r
134 SurfaceLoader[i]->drop();
\r
136 for (i=0; i<SurfaceWriter.size(); ++i)
\r
137 SurfaceWriter[i]->drop();
\r
139 // delete material renderers
\r
140 deleteMaterialRenders();
\r
142 // delete hardware mesh buffers
\r
143 removeAllHardwareBuffers();
\r
147 //! Adds an external surface loader to the engine.
\r
148 void CNullDriver::addExternalImageLoader(IImageLoader* loader)
\r
154 SurfaceLoader.push_back(loader);
\r
158 //! Adds an external surface writer to the engine.
\r
159 void CNullDriver::addExternalImageWriter(IImageWriter* writer)
\r
165 SurfaceWriter.push_back(writer);
\r
169 //! Retrieve the number of image loaders
\r
170 u32 CNullDriver::getImageLoaderCount() const
\r
172 return SurfaceLoader.size();
\r
176 //! Retrieve the given image loader
\r
177 IImageLoader* CNullDriver::getImageLoader(u32 n)
\r
179 if (n < SurfaceLoader.size())
\r
180 return SurfaceLoader[n];
\r
185 //! Retrieve the number of image writers
\r
186 u32 CNullDriver::getImageWriterCount() const
\r
188 return SurfaceWriter.size();
\r
192 //! Retrieve the given image writer
\r
193 IImageWriter* CNullDriver::getImageWriter(u32 n)
\r
195 if (n < SurfaceWriter.size())
\r
196 return SurfaceWriter[n];
\r
201 //! deletes all textures
\r
202 void CNullDriver::deleteAllTextures()
\r
204 // we need to remove previously set textures which might otherwise be kept in the
\r
205 // last set material member. Could be optimized to reduce state changes.
\r
206 setMaterial(SMaterial());
\r
208 // reset render targets.
\r
210 for (u32 i=0; i<RenderTargets.size(); ++i)
\r
211 RenderTargets[i]->setTexture(0, 0);
\r
213 // remove textures.
\r
215 for (u32 i=0; i<Textures.size(); ++i)
\r
216 Textures[i].Surface->drop();
\r
220 SharedDepthTextures.clear();
\r
223 bool CNullDriver::beginScene(u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil, const SExposedVideoData& videoData, core::rect<s32>* sourceRect)
\r
225 PrimitivesDrawn = 0;
\r
229 bool CNullDriver::endScene()
\r
231 FPSCounter.registerFrame(os::Timer::getRealTime(), PrimitivesDrawn);
\r
232 updateAllHardwareBuffers();
\r
233 updateAllOcclusionQueries();
\r
238 //! Disable a feature of the driver.
\r
239 void CNullDriver::disableFeature(E_VIDEO_DRIVER_FEATURE feature, bool flag)
\r
241 FeatureEnabled[feature]=!flag;
\r
245 //! queries the features of the driver, returns true if feature is available
\r
246 bool CNullDriver::queryFeature(E_VIDEO_DRIVER_FEATURE feature) const
\r
252 //! Get attributes of the actual video driver
\r
253 const io::IAttributes& CNullDriver::getDriverAttributes() const
\r
255 return *DriverAttributes;
\r
259 //! sets transformation
\r
260 void CNullDriver::setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat)
\r
265 //! Returns the transformation set by setTransform
\r
266 const core::matrix4& CNullDriver::getTransform(E_TRANSFORMATION_STATE state) const
\r
268 return TransformationMatrix;
\r
272 //! sets a material
\r
273 void CNullDriver::setMaterial(const SMaterial& material)
\r
278 //! Removes a texture from the texture cache and deletes it, freeing lot of
\r
280 void CNullDriver::removeTexture(ITexture* texture)
\r
285 for (u32 i=0; i<Textures.size(); ++i)
\r
287 if (Textures[i].Surface == texture)
\r
297 //! Removes all texture from the texture cache and deletes them, freeing lot of
\r
299 void CNullDriver::removeAllTextures()
\r
301 setMaterial ( SMaterial() );
\r
302 deleteAllTextures();
\r
306 //! Returns a texture by index
\r
307 ITexture* CNullDriver::getTextureByIndex(u32 i)
\r
309 if ( i < Textures.size() )
\r
310 return Textures[i].Surface;
\r
316 //! Returns amount of textures currently loaded
\r
317 u32 CNullDriver::getTextureCount() const
\r
319 return Textures.size();
\r
323 //! Renames a texture
\r
324 void CNullDriver::renameTexture(ITexture* texture, const io::path& newName)
\r
326 // we can do a const_cast here safely, the name of the ITexture interface
\r
327 // is just readonly to prevent the user changing the texture name without invoking
\r
328 // this method, because the textures will need resorting afterwards
\r
330 io::SNamedPath& name = const_cast<io::SNamedPath&>(texture->getName());
\r
331 name.setPath(newName);
\r
336 ITexture* CNullDriver::addTexture(const core::dimension2d<u32>& size, const io::path& name, ECOLOR_FORMAT format)
\r
338 if (0 == name.size())
\r
340 os::Printer::log("Could not create ITexture, texture needs to have a non-empty name.", ELL_WARNING);
\r
344 IImage* image = new CImage(format, size);
\r
347 if (checkImage(image))
\r
349 t = createDeviceDependentTexture(name, image);
\r
363 ITexture* CNullDriver::addTexture(const io::path& name, IImage* image)
\r
365 if (0 == name.size())
\r
367 os::Printer::log("Could not create ITexture, texture needs to have a non-empty name.", ELL_WARNING);
\r
376 if (checkImage(image))
\r
378 t = createDeviceDependentTexture(name, image);
\r
390 ITexture* CNullDriver::addTextureCubemap(const io::path& name, IImage* imagePosX, IImage* imageNegX, IImage* imagePosY,
\r
391 IImage* imageNegY, IImage* imagePosZ, IImage* imageNegZ)
\r
393 if (0 == name.size() || !imagePosX || !imageNegX || !imagePosY || !imageNegY || !imagePosZ || !imageNegZ)
\r
398 core::array<IImage*> imageArray(6);
\r
399 imageArray.push_back(imagePosX);
\r
400 imageArray.push_back(imageNegX);
\r
401 imageArray.push_back(imagePosY);
\r
402 imageArray.push_back(imageNegY);
\r
403 imageArray.push_back(imagePosZ);
\r
404 imageArray.push_back(imageNegZ);
\r
406 if (checkImage(imageArray))
\r
408 t = createDeviceDependentTextureCubemap(name, imageArray);
\r
420 ITexture* CNullDriver::addTextureCubemap(const irr::u32 sideLen, const io::path& name, ECOLOR_FORMAT format)
\r
422 if ( 0 == sideLen )
\r
425 if (0 == name.size())
\r
427 os::Printer::log("Could not create ITexture, texture needs to have a non-empty name.", ELL_WARNING);
\r
431 core::array<IImage*> imageArray(6);
\r
432 for ( int i=0; i < 6; ++i )
\r
433 imageArray.push_back(new CImage(format, core::dimension2du(sideLen, sideLen)));
\r
436 if (checkImage(imageArray))
\r
438 t = createDeviceDependentTextureCubemap(name, imageArray);
\r
447 for ( int i=0; i < 6; ++i )
\r
448 imageArray[i]->drop();
\r
453 //! loads a Texture
\r
454 ITexture* CNullDriver::getTexture(const io::path& filename)
\r
456 // Identify textures by their absolute filenames if possible.
\r
457 const io::path absolutePath = FileSystem->getAbsolutePath(filename);
\r
459 ITexture* texture = findTexture(absolutePath);
\r
462 texture->updateSource(ETS_FROM_CACHE);
\r
466 // Then try the raw filename, which might be in an Archive
\r
467 texture = findTexture(filename);
\r
470 texture->updateSource(ETS_FROM_CACHE);
\r
474 // Now try to open the file using the complete path.
\r
475 io::IReadFile* file = FileSystem->createAndOpenFile(absolutePath);
\r
479 // Try to open it using the raw filename.
\r
480 file = FileSystem->createAndOpenFile(filename);
\r
485 // Re-check name for actual archive names
\r
486 texture = findTexture(file->getFileName());
\r
489 texture->updateSource(ETS_FROM_CACHE);
\r
494 texture = loadTextureFromFile(file);
\r
499 texture->updateSource(ETS_FROM_FILE);
\r
500 addTexture(texture);
\r
501 texture->drop(); // drop it because we created it, one grab too much
\r
504 os::Printer::log("Could not load texture", filename, ELL_ERROR);
\r
509 os::Printer::log("Could not open file of texture", filename, ELL_WARNING);
\r
515 //! loads a Texture
\r
516 ITexture* CNullDriver::getTexture(io::IReadFile* file)
\r
518 ITexture* texture = 0;
\r
522 texture = findTexture(file->getFileName());
\r
526 texture->updateSource(ETS_FROM_CACHE);
\r
530 texture = loadTextureFromFile(file);
\r
534 texture->updateSource(ETS_FROM_FILE);
\r
535 addTexture(texture);
\r
536 texture->drop(); // drop it because we created it, one grab too much
\r
540 os::Printer::log("Could not load texture", file->getFileName(), ELL_WARNING);
\r
547 //! opens the file and loads it into the surface
\r
548 video::ITexture* CNullDriver::loadTextureFromFile(io::IReadFile* file, const io::path& hashName )
\r
550 ITexture *texture = nullptr;
\r
552 IImage *image = createImageFromFile(file);
\r
556 if (checkImage(image)) {
\r
557 texture = createDeviceDependentTexture(hashName.size() ? hashName : file->getFileName(), image);
\r
559 os::Printer::log("Loaded texture", file->getFileName(), ELL_DEBUG);
\r
568 //! adds a surface, not loaded or created by the Irrlicht Engine
\r
569 void CNullDriver::addTexture(video::ITexture* texture)
\r
574 s.Surface = texture;
\r
577 Textures.push_back(s);
\r
579 // the new texture is now at the end of the texture list. when searching for
\r
580 // the next new texture, the texture array will be sorted and the index of this texture
\r
581 // will be changed. to let the order be more consistent to the user, sort
\r
582 // the textures now already although this isn't necessary:
\r
589 //! looks if the image is already loaded
\r
590 video::ITexture* CNullDriver::findTexture(const io::path& filename)
\r
593 SDummyTexture dummy(filename, ETT_2D);
\r
594 s.Surface = &dummy;
\r
596 s32 index = Textures.binary_search(s);
\r
598 return Textures[index].Surface;
\r
603 ITexture* CNullDriver::createDeviceDependentTexture(const io::path& name, IImage* image)
\r
605 SDummyTexture* dummy = new SDummyTexture(name, ETT_2D);
\r
606 dummy->setSize(image->getDimension());
\r
610 ITexture* CNullDriver::createDeviceDependentTextureCubemap(const io::path& name, const core::array<IImage*>& image)
\r
612 return new SDummyTexture(name, ETT_CUBEMAP);
\r
615 bool CNullDriver::setRenderTargetEx(IRenderTarget* target, u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil)
\r
620 bool CNullDriver::setRenderTarget(ITexture* texture, u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil)
\r
624 // create render target if require.
\r
625 if (!SharedRenderTarget)
\r
626 SharedRenderTarget = addRenderTarget();
\r
628 ITexture* depthTexture = 0;
\r
630 // try to find available depth texture with require size.
\r
631 for (u32 i = 0; i < SharedDepthTextures.size(); ++i)
\r
633 if (SharedDepthTextures[i]->getSize() == texture->getSize())
\r
635 depthTexture = SharedDepthTextures[i];
\r
641 // create depth texture if require.
\r
644 depthTexture = addRenderTargetTexture(texture->getSize(), "IRR_DEPTH_STENCIL", video::ECF_D24S8);
\r
645 SharedDepthTextures.push_back(depthTexture);
\r
648 SharedRenderTarget->setTexture(texture, depthTexture);
\r
650 return setRenderTargetEx(SharedRenderTarget, clearFlag, clearColor, clearDepth, clearStencil);
\r
654 return setRenderTargetEx(0, clearFlag, clearColor, clearDepth, clearStencil);
\r
658 //! sets a viewport
\r
659 void CNullDriver::setViewPort(const core::rect<s32>& area)
\r
664 //! gets the area of the current viewport
\r
665 const core::rect<s32>& CNullDriver::getViewPort() const
\r
671 //! draws a vertex primitive list
\r
672 void 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)
\r
674 if ((iType==EIT_16BIT) && (vertexCount>65536))
\r
675 os::Printer::log("Too many vertices for 16bit index type, render artifacts may occur.");
\r
676 PrimitivesDrawn += primitiveCount;
\r
680 //! draws a vertex primitive list in 2d
\r
681 void 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)
\r
683 if ((iType==EIT_16BIT) && (vertexCount>65536))
\r
684 os::Printer::log("Too many vertices for 16bit index type, render artifacts may occur.");
\r
685 PrimitivesDrawn += primitiveCount;
\r
689 //! Draws a 3d line.
\r
690 void CNullDriver::draw3DLine(const core::vector3df& start,
\r
691 const core::vector3df& end, SColor color)
\r
696 //! Draws a 3d axis aligned box.
\r
697 void CNullDriver::draw3DBox(const core::aabbox3d<f32>& box, SColor color)
\r
699 core::vector3df edges[8];
\r
700 box.getEdges(edges);
\r
702 // TODO: optimize into one big drawIndexPrimitive call.
\r
704 draw3DLine(edges[5], edges[1], color);
\r
705 draw3DLine(edges[1], edges[3], color);
\r
706 draw3DLine(edges[3], edges[7], color);
\r
707 draw3DLine(edges[7], edges[5], color);
\r
708 draw3DLine(edges[0], edges[2], color);
\r
709 draw3DLine(edges[2], edges[6], color);
\r
710 draw3DLine(edges[6], edges[4], color);
\r
711 draw3DLine(edges[4], edges[0], color);
\r
712 draw3DLine(edges[1], edges[0], color);
\r
713 draw3DLine(edges[3], edges[2], color);
\r
714 draw3DLine(edges[7], edges[6], color);
\r
715 draw3DLine(edges[5], edges[4], color);
\r
720 //! draws an 2d image
\r
721 void CNullDriver::draw2DImage(const video::ITexture* texture, const core::position2d<s32>& destPos, bool useAlphaChannelOfTexture)
\r
726 draw2DImage(texture,destPos, core::rect<s32>(core::position2d<s32>(0,0),
\r
727 core::dimension2di(texture->getOriginalSize())),
\r
729 SColor(255,255,255,255),
\r
730 useAlphaChannelOfTexture
\r
735 //! draws a set of 2d images, using a color and the alpha channel of the
\r
736 //! texture if desired.
\r
737 void CNullDriver::draw2DImageBatch(const video::ITexture* texture,
\r
738 const core::array<core::position2d<s32> >& positions,
\r
739 const core::array<core::rect<s32> >& sourceRects,
\r
740 const core::rect<s32>* clipRect,
\r
742 bool useAlphaChannelOfTexture)
\r
744 const irr::u32 drawCount = core::min_<u32>(positions.size(), sourceRects.size());
\r
746 for (u32 i=0; i<drawCount; ++i)
\r
748 draw2DImage(texture, positions[i], sourceRects[i],
\r
749 clipRect, color, useAlphaChannelOfTexture);
\r
754 //! Draws a part of the texture into the rectangle.
\r
755 void CNullDriver::draw2DImage(const video::ITexture* texture, const core::rect<s32>& destRect,
\r
756 const core::rect<s32>& sourceRect, const core::rect<s32>* clipRect,
\r
757 const video::SColor* const colors, bool useAlphaChannelOfTexture)
\r
759 if (destRect.isValid())
\r
760 draw2DImage(texture, core::position2d<s32>(destRect.UpperLeftCorner),
\r
761 sourceRect, clipRect, colors?colors[0]:video::SColor(0xffffffff),
\r
762 useAlphaChannelOfTexture);
\r
766 //! 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.
\r
767 void CNullDriver::draw2DImage(const video::ITexture* texture, const core::position2d<s32>& destPos,
\r
768 const core::rect<s32>& sourceRect,
\r
769 const core::rect<s32>* clipRect, SColor color,
\r
770 bool useAlphaChannelOfTexture)
\r
775 //! Draw a 2d rectangle
\r
776 void CNullDriver::draw2DRectangle(SColor color, const core::rect<s32>& pos, const core::rect<s32>* clip)
\r
778 draw2DRectangle(pos, color, color, color, color, clip);
\r
783 //! Draws a 2d rectangle with a gradient.
\r
784 void CNullDriver::draw2DRectangle(const core::rect<s32>& pos,
\r
785 SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown,
\r
786 const core::rect<s32>* clip)
\r
792 //! Draws a 2d line.
\r
793 void CNullDriver::draw2DLine(const core::position2d<s32>& start,
\r
794 const core::position2d<s32>& end, SColor color)
\r
799 //! returns color format
\r
800 ECOLOR_FORMAT CNullDriver::getColorFormat() const
\r
806 //! returns screen size
\r
807 const core::dimension2d<u32>& CNullDriver::getScreenSize() const
\r
813 //! get current render target
\r
814 IRenderTarget* CNullDriver::getCurrentRenderTarget() const
\r
816 return CurrentRenderTarget;
\r
820 const core::dimension2d<u32>& CNullDriver::getCurrentRenderTargetSize() const
\r
822 if (CurrentRenderTargetSize.Width == 0)
\r
825 return CurrentRenderTargetSize;
\r
829 // returns current frames per second value
\r
830 s32 CNullDriver::getFPS() const
\r
832 return FPSCounter.getFPS();
\r
837 //! returns amount of primitives (mostly triangles) were drawn in the last frame.
\r
838 //! very useful method for statistics.
\r
839 u32 CNullDriver::getPrimitiveCountDrawn( u32 param ) const
\r
841 return (0 == param) ? FPSCounter.getPrimitive() : (1 == param) ? FPSCounter.getPrimitiveAverage() : FPSCounter.getPrimitiveTotal();
\r
846 //! Sets the dynamic ambient light color. The default color is
\r
847 //! (0,0,0,0) which means it is dark.
\r
848 //! \param color: New color of the ambient light.
\r
849 void CNullDriver::setAmbientLight(const SColorf& color)
\r
851 AmbientLight = color;
\r
854 const SColorf& CNullDriver::getAmbientLight() const
\r
856 return AmbientLight;
\r
859 //! \return Returns the name of the video driver. Example: In case of the DIRECT3D8
\r
860 //! driver, it would return "Direct3D8".
\r
862 const wchar_t* CNullDriver::getName() const
\r
864 return L"Irrlicht NullDevice";
\r
868 //! Creates a boolean alpha channel of the texture based of an color key.
\r
869 void CNullDriver::makeColorKeyTexture(video::ITexture* texture,
\r
870 video::SColor color,
\r
871 bool zeroTexels) const
\r
876 if (texture->getColorFormat() != ECF_A1R5G5B5 &&
\r
877 texture->getColorFormat() != ECF_A8R8G8B8 )
\r
879 os::Printer::log("Error: Unsupported texture color format for making color key channel.", ELL_ERROR);
\r
883 if (texture->getColorFormat() == ECF_A1R5G5B5)
\r
885 u16 *p = (u16*)texture->lock();
\r
889 os::Printer::log("Could not lock texture for making color key channel.", ELL_ERROR);
\r
893 const core::dimension2d<u32> dim = texture->getSize();
\r
894 const u32 pitch = texture->getPitch() / 2;
\r
896 // color with alpha disabled (i.e. fully transparent)
\r
897 const u16 refZeroAlpha = (0x7fff & color.toA1R5G5B5());
\r
899 const u32 pixels = pitch * dim.Height;
\r
901 for (u32 pixel = 0; pixel < pixels; ++ pixel)
\r
903 // If the color matches the reference color, ignoring alphas,
\r
904 // set the alpha to zero.
\r
905 if(((*p) & 0x7fff) == refZeroAlpha)
\r
910 (*p) = refZeroAlpha;
\r
920 u32 *p = (u32*)texture->lock();
\r
924 os::Printer::log("Could not lock texture for making color key channel.", ELL_ERROR);
\r
928 core::dimension2d<u32> dim = texture->getSize();
\r
929 u32 pitch = texture->getPitch() / 4;
\r
931 // color with alpha disabled (fully transparent)
\r
932 const u32 refZeroAlpha = 0x00ffffff & color.color;
\r
934 const u32 pixels = pitch * dim.Height;
\r
935 for (u32 pixel = 0; pixel < pixels; ++ pixel)
\r
937 // If the color matches the reference color, ignoring alphas,
\r
938 // set the alpha to zero.
\r
939 if(((*p) & 0x00ffffff) == refZeroAlpha)
\r
944 (*p) = refZeroAlpha;
\r
952 texture->regenerateMipMapLevels();
\r
957 //! Creates an boolean alpha channel of the texture based of an color key position.
\r
958 void CNullDriver::makeColorKeyTexture(video::ITexture* texture,
\r
959 core::position2d<s32> colorKeyPixelPos,
\r
960 bool zeroTexels) const
\r
965 if (texture->getColorFormat() != ECF_A1R5G5B5 &&
\r
966 texture->getColorFormat() != ECF_A8R8G8B8 )
\r
968 os::Printer::log("Error: Unsupported texture color format for making color key channel.", ELL_ERROR);
\r
974 if (texture->getColorFormat() == ECF_A1R5G5B5)
\r
976 u16 *p = (u16*)texture->lock(ETLM_READ_ONLY);
\r
980 os::Printer::log("Could not lock texture for making color key channel.", ELL_ERROR);
\r
984 u32 pitch = texture->getPitch() / 2;
\r
986 const u16 key16Bit = 0x7fff & p[colorKeyPixelPos.Y*pitch + colorKeyPixelPos.X];
\r
988 colorKey = video::A1R5G5B5toA8R8G8B8(key16Bit);
\r
992 u32 *p = (u32*)texture->lock(ETLM_READ_ONLY);
\r
996 os::Printer::log("Could not lock texture for making color key channel.", ELL_ERROR);
\r
1000 u32 pitch = texture->getPitch() / 4;
\r
1001 colorKey = 0x00ffffff & p[colorKeyPixelPos.Y*pitch + colorKeyPixelPos.X];
\r
1004 texture->unlock();
\r
1005 makeColorKeyTexture(texture, colorKey, zeroTexels);
\r
1009 //! Returns the maximum amount of primitives (mostly vertices) which
\r
1010 //! the device is able to render with one drawIndexedTriangleList
\r
1012 u32 CNullDriver::getMaximalPrimitiveCount() const
\r
1014 return 0xFFFFFFFF;
\r
1018 //! checks triangle count and print warning if wrong
\r
1019 bool CNullDriver::checkPrimitiveCount(u32 prmCount) const
\r
1021 const u32 m = getMaximalPrimitiveCount();
\r
1026 snprintf_irr(tmp, sizeof(tmp), "Could not draw triangles, too many primitives(%u), maximum is %u.", prmCount, m);
\r
1027 os::Printer::log(tmp, ELL_ERROR);
\r
1034 bool CNullDriver::checkImage(IImage *image) const
\r
1036 ECOLOR_FORMAT format = image->getColorFormat();
\r
1037 core::dimension2d<u32> size = image->getDimension();
\r
1046 if (!queryFeature(EVDF_TEXTURE_COMPRESSED_DXT))
\r
1048 os::Printer::log("DXT texture compression not available.", ELL_ERROR);
\r
1051 else if (size.getOptimalSize(true, false) != size)
\r
1053 os::Printer::log("Invalid size of image for DXT texture, size of image must be power of two.", ELL_ERROR);
\r
1057 case ECF_PVRTC_RGB2:
\r
1058 case ECF_PVRTC_ARGB2:
\r
1059 case ECF_PVRTC_RGB4:
\r
1060 case ECF_PVRTC_ARGB4:
\r
1061 if (!queryFeature(EVDF_TEXTURE_COMPRESSED_PVRTC))
\r
1063 os::Printer::log("PVRTC texture compression not available.", ELL_ERROR);
\r
1066 else if (size.getOptimalSize(true, false) != size)
\r
1068 os::Printer::log("Invalid size of image for PVRTC compressed texture, size of image must be power of two and squared.", ELL_ERROR);
\r
1072 case ECF_PVRTC2_ARGB2:
\r
1073 case ECF_PVRTC2_ARGB4:
\r
1074 if (!queryFeature(EVDF_TEXTURE_COMPRESSED_PVRTC2))
\r
1076 os::Printer::log("PVRTC2 texture compression not available.", ELL_ERROR);
\r
1081 if (!queryFeature(EVDF_TEXTURE_COMPRESSED_ETC1))
\r
1083 os::Printer::log("ETC1 texture compression not available.", ELL_ERROR);
\r
1087 case ECF_ETC2_RGB:
\r
1088 case ECF_ETC2_ARGB:
\r
1089 if (!queryFeature(EVDF_TEXTURE_COMPRESSED_ETC2))
\r
1091 os::Printer::log("ETC2 texture compression not available.", ELL_ERROR);
\r
1101 bool CNullDriver::checkImage(const core::array<IImage*>& image) const
\r
1103 if (!image.size())
\r
1106 ECOLOR_FORMAT lastFormat = image[0]->getColorFormat();
\r
1107 core::dimension2d<u32> lastSize = image[0]->getDimension();
\r
1109 for (u32 i = 0; i < image.size(); ++i) {
\r
1110 ECOLOR_FORMAT format = image[i]->getColorFormat();
\r
1111 core::dimension2d<u32> size = image[i]->getDimension();
\r
1113 if (!checkImage(image[i]))
\r
1116 if (format != lastFormat || size != lastSize)
\r
1122 //! Enables or disables a texture creation flag.
\r
1123 void CNullDriver::setTextureCreationFlag(E_TEXTURE_CREATION_FLAG flag, bool enabled)
\r
1125 if (enabled && ((flag == ETCF_ALWAYS_16_BIT) || (flag == ETCF_ALWAYS_32_BIT)
\r
1126 || (flag == ETCF_OPTIMIZED_FOR_QUALITY) || (flag == ETCF_OPTIMIZED_FOR_SPEED)))
\r
1128 // disable other formats
\r
1129 setTextureCreationFlag(ETCF_ALWAYS_16_BIT, false);
\r
1130 setTextureCreationFlag(ETCF_ALWAYS_32_BIT, false);
\r
1131 setTextureCreationFlag(ETCF_OPTIMIZED_FOR_QUALITY, false);
\r
1132 setTextureCreationFlag(ETCF_OPTIMIZED_FOR_SPEED, false);
\r
1136 TextureCreationFlags = (TextureCreationFlags & (~flag)) |
\r
1137 ((((u32)!enabled)-1) & flag);
\r
1141 //! Returns if a texture creation flag is enabled or disabled.
\r
1142 bool CNullDriver::getTextureCreationFlag(E_TEXTURE_CREATION_FLAG flag) const
\r
1144 return (TextureCreationFlags & flag)!=0;
\r
1147 IImage *CNullDriver::createImageFromFile(const io::path& filename)
\r
1149 if (!filename.size())
\r
1152 io::IReadFile* file = FileSystem->createAndOpenFile(filename);
\r
1154 os::Printer::log("Could not open file of image", filename, ELL_WARNING);
\r
1158 IImage *image = createImageFromFile(file);
\r
1163 IImage *CNullDriver::createImageFromFile(io::IReadFile* file)
\r
1168 // try to load file based on file extension
\r
1169 for (int i = SurfaceLoader.size() - 1; i >= 0; --i) {
\r
1170 if (!SurfaceLoader[i]->isALoadableFileExtension(file->getFileName()))
\r
1173 file->seek(0); // reset file position which might have changed due to previous loadImage calls
\r
1174 if (IImage *image = SurfaceLoader[i]->loadImage(file))
\r
1178 // try to load file based on what is in it
\r
1179 for (int i = SurfaceLoader.size() - 1; i >= 0; --i) {
\r
1180 if (SurfaceLoader[i]->isALoadableFileExtension(file->getFileName()))
\r
1181 continue; // extension was tried above already
\r
1182 file->seek(0); // dito
\r
1183 if (!SurfaceLoader[i]->isALoadableFileFormat(file))
\r
1187 if (IImage *image = SurfaceLoader[i]->loadImage(file))
\r
1195 //! Writes the provided image to disk file
\r
1196 bool CNullDriver::writeImageToFile(IImage* image, const io::path& filename,u32 param)
\r
1198 io::IWriteFile* file = FileSystem->createAndWriteFile(filename);
\r
1202 bool result = writeImageToFile(image, file, param);
\r
1208 //! Writes the provided image to a file.
\r
1209 bool CNullDriver::writeImageToFile(IImage* image, io::IWriteFile * file, u32 param)
\r
1214 for (s32 i=SurfaceWriter.size()-1; i>=0; --i)
\r
1216 if (SurfaceWriter[i]->isAWriteableFileExtension(file->getFileName()))
\r
1218 bool written = SurfaceWriter[i]->writeImage(file, image, param);
\r
1223 return false; // failed to write
\r
1227 //! Creates a software image from a byte array.
\r
1228 IImage* CNullDriver::createImageFromData(ECOLOR_FORMAT format,
\r
1229 const core::dimension2d<u32>& size, void *data, bool ownForeignMemory,
\r
1230 bool deleteMemory)
\r
1232 return new CImage(format, size, data, ownForeignMemory, deleteMemory);
\r
1236 //! Creates an empty software image.
\r
1237 IImage* CNullDriver::createImage(ECOLOR_FORMAT format, const core::dimension2d<u32>& size)
\r
1239 return new CImage(format, size);
\r
1243 //! Creates a software image from another image.
\r
1244 IImage* CNullDriver::createImage(ECOLOR_FORMAT format, IImage *imageToCopy)
\r
1246 os::Printer::log("Deprecated method, please create an empty image instead and use copyTo().", ELL_WARNING);
\r
1248 CImage* tmp = new CImage(format, imageToCopy->getDimension());
\r
1249 imageToCopy->copyTo(tmp);
\r
1254 //! Creates a software image from part of another image.
\r
1255 IImage* CNullDriver::createImage(IImage* imageToCopy, const core::position2d<s32>& pos, const core::dimension2d<u32>& size)
\r
1257 os::Printer::log("Deprecated method, please create an empty image instead and use copyTo().", ELL_WARNING);
\r
1258 CImage* tmp = new CImage(imageToCopy->getColorFormat(), imageToCopy->getDimension());
\r
1259 imageToCopy->copyTo(tmp, core::position2di(0,0), core::recti(pos,size));
\r
1264 //! Creates a software image from part of a texture.
\r
1265 IImage* CNullDriver::createImage(ITexture* texture, const core::position2d<s32>& pos, const core::dimension2d<u32>& size)
\r
1267 if ((pos==core::position2di(0,0)) && (size == texture->getSize()))
\r
1269 void * data = texture->lock(ETLM_READ_ONLY);
\r
1272 IImage* image = new CImage(texture->getColorFormat(), size, data, false, false);
\r
1273 texture->unlock();
\r
1278 // make sure to avoid buffer overruns
\r
1279 // make the vector a separate variable for g++ 3.x
\r
1280 const core::vector2d<u32> leftUpper(core::clamp(static_cast<u32>(pos.X), 0u, texture->getSize().Width),
\r
1281 core::clamp(static_cast<u32>(pos.Y), 0u, texture->getSize().Height));
\r
1282 const core::rect<u32> clamped(leftUpper,
\r
1283 core::dimension2du(core::clamp(static_cast<u32>(size.Width), 0u, texture->getSize().Width),
\r
1284 core::clamp(static_cast<u32>(size.Height), 0u, texture->getSize().Height)));
\r
1285 if (!clamped.isValid())
\r
1287 u8* src = static_cast<u8*>(texture->lock(ETLM_READ_ONLY));
\r
1290 IImage* image = new CImage(texture->getColorFormat(), clamped.getSize());
\r
1291 u8* dst = static_cast<u8*>(image->getData());
\r
1292 src += clamped.UpperLeftCorner.Y * texture->getPitch() + image->getBytesPerPixel() * clamped.UpperLeftCorner.X;
\r
1293 for (u32 i=0; i<clamped.getHeight(); ++i)
\r
1295 video::CColorConverter::convert_viaFormat(src, texture->getColorFormat(), clamped.getWidth(), dst, image->getColorFormat());
\r
1296 src += texture->getPitch();
\r
1297 dst += image->getPitch();
\r
1299 texture->unlock();
\r
1305 //! Sets the fog mode.
\r
1306 void CNullDriver::setFog(SColor color, E_FOG_TYPE fogType, f32 start, f32 end,
\r
1307 f32 density, bool pixelFog, bool rangeFog)
\r
1310 FogType = fogType;
\r
1313 FogDensity = density;
\r
1314 PixelFog = pixelFog;
\r
1315 RangeFog = rangeFog;
\r
1318 //! Gets the fog mode.
\r
1319 void CNullDriver::getFog(SColor& color, E_FOG_TYPE& fogType, f32& start, f32& end,
\r
1320 f32& density, bool& pixelFog, bool& rangeFog)
\r
1323 fogType = FogType;
\r
1326 density = FogDensity;
\r
1327 pixelFog = PixelFog;
\r
1328 rangeFog = RangeFog;
\r
1331 //! Draws a mesh buffer
\r
1332 void CNullDriver::drawMeshBuffer(const scene::IMeshBuffer* mb)
\r
1337 //IVertexBuffer and IIndexBuffer later
\r
1338 SHWBufferLink *HWBuffer=getBufferLink(mb);
\r
1341 drawHardwareBuffer(HWBuffer);
\r
1343 drawVertexPrimitiveList(mb->getVertices(), mb->getVertexCount(), mb->getIndices(), mb->getPrimitiveCount(), mb->getVertexType(), mb->getPrimitiveType(), mb->getIndexType());
\r
1347 //! Draws the normals of a mesh buffer
\r
1348 void CNullDriver::drawMeshBufferNormals(const scene::IMeshBuffer* mb, f32 length, SColor color)
\r
1350 const u32 count = mb->getVertexCount();
\r
1351 const bool normalize = mb->getMaterial().NormalizeNormals;
\r
1353 for (u32 i=0; i < count; ++i)
\r
1355 core::vector3df normalizedNormal = mb->getNormal(i);
\r
1357 normalizedNormal.normalize();
\r
1359 const core::vector3df& pos = mb->getPosition(i);
\r
1360 draw3DLine(pos, pos + (normalizedNormal * length), color);
\r
1365 CNullDriver::SHWBufferLink *CNullDriver::getBufferLink(const scene::IMeshBuffer* mb)
\r
1367 if (!mb || !isHardwareBufferRecommend(mb))
\r
1370 //search for hardware links
\r
1371 SHWBufferLink *HWBuffer = reinterpret_cast<SHWBufferLink*>(mb->getHWBuffer());
\r
1375 return createHardwareBuffer(mb); //no hardware links, and mesh wants one, create it
\r
1379 //! Update all hardware buffers, remove unused ones
\r
1380 void CNullDriver::updateAllHardwareBuffers()
\r
1382 auto it = HWBufferList.begin();
\r
1383 while (it != HWBufferList.end()) {
\r
1384 SHWBufferLink *Link = *it;
\r
1387 if (!Link->MeshBuffer || Link->MeshBuffer->getReferenceCount() == 1)
\r
1388 deleteHardwareBuffer(Link);
\r
1393 void CNullDriver::deleteHardwareBuffer(SHWBufferLink *HWBuffer)
\r
1397 HWBufferList.erase(HWBuffer->listPosition);
\r
1402 //! Remove hardware buffer
\r
1403 void CNullDriver::removeHardwareBuffer(const scene::IMeshBuffer* mb)
\r
1407 SHWBufferLink *HWBuffer = reinterpret_cast<SHWBufferLink*>(mb->getHWBuffer());
\r
1409 deleteHardwareBuffer(HWBuffer);
\r
1413 //! Remove all hardware buffers
\r
1414 void CNullDriver::removeAllHardwareBuffers()
\r
1416 while (!HWBufferList.empty())
\r
1417 deleteHardwareBuffer(HWBufferList.front());
\r
1421 bool CNullDriver::isHardwareBufferRecommend(const scene::IMeshBuffer* mb)
\r
1423 if (!mb || (mb->getHardwareMappingHint_Index()==scene::EHM_NEVER && mb->getHardwareMappingHint_Vertex()==scene::EHM_NEVER))
\r
1426 if (mb->getVertexCount()<MinVertexCountForVBO)
\r
1433 //! Create occlusion query.
\r
1434 /** Use node for identification and mesh for occlusion test. */
\r
1435 void CNullDriver::addOcclusionQuery(scene::ISceneNode* node, const scene::IMesh* mesh)
\r
1441 if ((node->getType() != scene::ESNT_MESH) && (node->getType() != scene::ESNT_ANIMATED_MESH))
\r
1443 else if (node->getType() == scene::ESNT_MESH)
\r
1444 mesh = static_cast<scene::IMeshSceneNode*>(node)->getMesh();
\r
1446 mesh = static_cast<scene::IAnimatedMeshSceneNode*>(node)->getMesh()->getMesh(0);
\r
1451 //search for query
\r
1452 s32 index = OcclusionQueries.linear_search(SOccQuery(node));
\r
1455 if (OcclusionQueries[index].Mesh != mesh)
\r
1457 OcclusionQueries[index].Mesh->drop();
\r
1458 OcclusionQueries[index].Mesh = mesh;
\r
1464 OcclusionQueries.push_back(SOccQuery(node, mesh));
\r
1465 node->setAutomaticCulling(node->getAutomaticCulling() | scene::EAC_OCC_QUERY);
\r
1470 //! Remove occlusion query.
\r
1471 void CNullDriver::removeOcclusionQuery(scene::ISceneNode* node)
\r
1473 //search for query
\r
1474 s32 index = OcclusionQueries.linear_search(SOccQuery(node));
\r
1477 node->setAutomaticCulling(node->getAutomaticCulling() & ~scene::EAC_OCC_QUERY);
\r
1478 OcclusionQueries.erase(index);
\r
1483 //! Remove all occlusion queries.
\r
1484 void CNullDriver::removeAllOcclusionQueries()
\r
1486 for (s32 i=OcclusionQueries.size()-1; i>=0; --i)
\r
1488 removeOcclusionQuery(OcclusionQueries[i].Node);
\r
1493 //! Run occlusion query. Draws mesh stored in query.
\r
1494 /** If the mesh shall be rendered visible, use
\r
1495 flag to enable the proper material setting. */
\r
1496 void CNullDriver::runOcclusionQuery(scene::ISceneNode* node, bool visible)
\r
1500 s32 index = OcclusionQueries.linear_search(SOccQuery(node));
\r
1503 OcclusionQueries[index].Run=0;
\r
1507 mat.Lighting=false;
\r
1508 mat.AntiAliasing=0;
\r
1509 mat.ColorMask=ECP_NONE;
\r
1510 mat.GouraudShading=false;
\r
1511 mat.ZWriteEnable=EZW_OFF;
\r
1514 setTransform(video::ETS_WORLD, node->getAbsoluteTransformation());
\r
1515 const scene::IMesh* mesh = OcclusionQueries[index].Mesh;
\r
1516 for (u32 i=0; i<mesh->getMeshBufferCount(); ++i)
\r
1519 setMaterial(mesh->getMeshBuffer(i)->getMaterial());
\r
1520 drawMeshBuffer(mesh->getMeshBuffer(i));
\r
1525 //! Run all occlusion queries. Draws all meshes stored in queries.
\r
1526 /** If the meshes shall not be rendered visible, use
\r
1527 overrideMaterial to disable the color and depth buffer. */
\r
1528 void CNullDriver::runAllOcclusionQueries(bool visible)
\r
1530 for (u32 i=0; i<OcclusionQueries.size(); ++i)
\r
1531 runOcclusionQuery(OcclusionQueries[i].Node, visible);
\r
1535 //! Update occlusion query. Retrieves results from GPU.
\r
1536 /** If the query shall not block, set the flag to false.
\r
1537 Update might not occur in this case, though */
\r
1538 void CNullDriver::updateOcclusionQuery(scene::ISceneNode* node, bool block)
\r
1543 //! Update all occlusion queries. Retrieves results from GPU.
\r
1544 /** If the query shall not block, set the flag to false.
\r
1545 Update might not occur in this case, though */
\r
1546 void CNullDriver::updateAllOcclusionQueries(bool block)
\r
1548 for (u32 i=0; i<OcclusionQueries.size(); ++i)
\r
1550 if (OcclusionQueries[i].Run==u32(~0))
\r
1552 updateOcclusionQuery(OcclusionQueries[i].Node, block);
\r
1553 ++OcclusionQueries[i].Run;
\r
1554 if (OcclusionQueries[i].Run>1000)
\r
1555 removeOcclusionQuery(OcclusionQueries[i].Node);
\r
1560 //! Return query result.
\r
1561 /** Return value is the number of visible pixels/fragments.
\r
1562 The value is a safe approximation, i.e. can be larger then the
\r
1563 actual value of pixels. */
\r
1564 u32 CNullDriver::getOcclusionQueryResult(scene::ISceneNode* node) const
\r
1570 //! Create render target.
\r
1571 IRenderTarget* CNullDriver::addRenderTarget()
\r
1577 //! Remove render target.
\r
1578 void CNullDriver::removeRenderTarget(IRenderTarget* renderTarget)
\r
1580 if (!renderTarget)
\r
1583 for (u32 i = 0; i < RenderTargets.size(); ++i)
\r
1585 if (RenderTargets[i] == renderTarget)
\r
1587 RenderTargets[i]->drop();
\r
1588 RenderTargets.erase(i);
\r
1596 //! Remove all render targets.
\r
1597 void CNullDriver::removeAllRenderTargets()
\r
1599 for (u32 i = 0; i < RenderTargets.size(); ++i)
\r
1600 RenderTargets[i]->drop();
\r
1602 RenderTargets.clear();
\r
1604 SharedRenderTarget = 0;
\r
1608 //! Only used by the internal engine. Used to notify the driver that
\r
1609 //! the window was resized.
\r
1610 void CNullDriver::OnResize(const core::dimension2d<u32>& size)
\r
1612 if (ViewPort.getWidth() == (s32)ScreenSize.Width &&
\r
1613 ViewPort.getHeight() == (s32)ScreenSize.Height)
\r
1614 ViewPort = core::rect<s32>(core::position2d<s32>(0,0),
\r
1615 core::dimension2di(size));
\r
1617 ScreenSize = size;
\r
1621 // adds a material renderer and drops it afterwards. To be used for internal creation
\r
1622 s32 CNullDriver::addAndDropMaterialRenderer(IMaterialRenderer* m)
\r
1624 s32 i = addMaterialRenderer(m);
\r
1633 //! Adds a new material renderer to the video device.
\r
1634 s32 CNullDriver::addMaterialRenderer(IMaterialRenderer* renderer, const char* name)
\r
1639 SMaterialRenderer r;
\r
1640 r.Renderer = renderer;
\r
1643 if (name == 0 && (MaterialRenderers.size() < (sizeof(sBuiltInMaterialTypeNames) / sizeof(char*))-1 ))
\r
1645 // set name of built in renderer so that we don't have to implement name
\r
1646 // setting in all available renderers.
\r
1647 r.Name = sBuiltInMaterialTypeNames[MaterialRenderers.size()];
\r
1650 MaterialRenderers.push_back(r);
\r
1653 return MaterialRenderers.size()-1;
\r
1657 //! Sets the name of a material renderer.
\r
1658 void CNullDriver::setMaterialRendererName(u32 idx, const char* name)
\r
1660 if (idx < (sizeof(sBuiltInMaterialTypeNames) / sizeof(char*))-1 ||
\r
1661 idx >= MaterialRenderers.size())
\r
1664 MaterialRenderers[idx].Name = name;
\r
1667 void CNullDriver::swapMaterialRenderers(u32 idx1, u32 idx2, bool swapNames)
\r
1669 if ( idx1 < MaterialRenderers.size() && idx2 < MaterialRenderers.size() )
\r
1671 irr::core::swap(MaterialRenderers[idx1].Renderer, MaterialRenderers[idx2].Renderer);
\r
1673 irr::core::swap(MaterialRenderers[idx1].Name, MaterialRenderers[idx2].Name);
\r
1678 //! Returns driver and operating system specific data about the IVideoDriver.
\r
1679 const SExposedVideoData& CNullDriver::getExposedVideoData()
\r
1681 return ExposedData;
\r
1685 //! Returns type of video driver
\r
1686 E_DRIVER_TYPE CNullDriver::getDriverType() const
\r
1692 //! deletes all material renderers
\r
1693 void CNullDriver::deleteMaterialRenders()
\r
1695 // delete material renderers
\r
1696 for (u32 i=0; i<MaterialRenderers.size(); ++i)
\r
1697 if (MaterialRenderers[i].Renderer)
\r
1698 MaterialRenderers[i].Renderer->drop();
\r
1700 MaterialRenderers.clear();
\r
1704 //! Returns pointer to material renderer or null
\r
1705 IMaterialRenderer* CNullDriver::getMaterialRenderer(u32 idx) const
\r
1707 if ( idx < MaterialRenderers.size() )
\r
1708 return MaterialRenderers[idx].Renderer;
\r
1714 //! Returns amount of currently available material renderers.
\r
1715 u32 CNullDriver::getMaterialRendererCount() const
\r
1717 return MaterialRenderers.size();
\r
1721 //! Returns name of the material renderer
\r
1722 const char* CNullDriver::getMaterialRendererName(u32 idx) const
\r
1724 if ( idx < MaterialRenderers.size() )
\r
1725 return MaterialRenderers[idx].Name.c_str();
\r
1731 //! Returns pointer to the IGPUProgrammingServices interface.
\r
1732 IGPUProgrammingServices* CNullDriver::getGPUProgrammingServices()
\r
1738 //! Adds a new material renderer to the VideoDriver, based on a high level shading language.
\r
1739 s32 CNullDriver::addHighLevelShaderMaterial(
\r
1740 const c8* vertexShaderProgram,
\r
1741 const c8* vertexShaderEntryPointName,
\r
1742 E_VERTEX_SHADER_TYPE vsCompileTarget,
\r
1743 const c8* pixelShaderProgram,
\r
1744 const c8* pixelShaderEntryPointName,
\r
1745 E_PIXEL_SHADER_TYPE psCompileTarget,
\r
1746 const c8* geometryShaderProgram,
\r
1747 const c8* geometryShaderEntryPointName,
\r
1748 E_GEOMETRY_SHADER_TYPE gsCompileTarget,
\r
1749 scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,
\r
1751 IShaderConstantSetCallBack* callback,
\r
1752 E_MATERIAL_TYPE baseMaterial,
\r
1755 os::Printer::log("High level shader materials not available (yet) in this driver, sorry");
\r
1760 //! Like IGPUProgrammingServices::addShaderMaterial() (look there for a detailed description),
\r
1761 //! but tries to load the programs from files.
\r
1762 s32 CNullDriver::addHighLevelShaderMaterialFromFiles(
\r
1763 const io::path& vertexShaderProgramFileName,
\r
1764 const c8* vertexShaderEntryPointName,
\r
1765 E_VERTEX_SHADER_TYPE vsCompileTarget,
\r
1766 const io::path& pixelShaderProgramFileName,
\r
1767 const c8* pixelShaderEntryPointName,
\r
1768 E_PIXEL_SHADER_TYPE psCompileTarget,
\r
1769 const io::path& geometryShaderProgramFileName,
\r
1770 const c8* geometryShaderEntryPointName,
\r
1771 E_GEOMETRY_SHADER_TYPE gsCompileTarget,
\r
1772 scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,
\r
1774 IShaderConstantSetCallBack* callback,
\r
1775 E_MATERIAL_TYPE baseMaterial,
\r
1778 io::IReadFile* vsfile = 0;
\r
1779 io::IReadFile* psfile = 0;
\r
1780 io::IReadFile* gsfile = 0;
\r
1782 if (vertexShaderProgramFileName.size() )
\r
1784 vsfile = FileSystem->createAndOpenFile(vertexShaderProgramFileName);
\r
1787 os::Printer::log("Could not open vertex shader program file",
\r
1788 vertexShaderProgramFileName, ELL_WARNING);
\r
1792 if (pixelShaderProgramFileName.size() )
\r
1794 psfile = FileSystem->createAndOpenFile(pixelShaderProgramFileName);
\r
1797 os::Printer::log("Could not open pixel shader program file",
\r
1798 pixelShaderProgramFileName, ELL_WARNING);
\r
1802 if (geometryShaderProgramFileName.size() )
\r
1804 gsfile = FileSystem->createAndOpenFile(geometryShaderProgramFileName);
\r
1807 os::Printer::log("Could not open geometry shader program file",
\r
1808 geometryShaderProgramFileName, ELL_WARNING);
\r
1812 s32 result = addHighLevelShaderMaterialFromFiles(
\r
1813 vsfile, vertexShaderEntryPointName, vsCompileTarget,
\r
1814 psfile, pixelShaderEntryPointName, psCompileTarget,
\r
1815 gsfile, geometryShaderEntryPointName, gsCompileTarget,
\r
1816 inType, outType, verticesOut,
\r
1817 callback, baseMaterial, userData);
\r
1832 //! Like IGPUProgrammingServices::addShaderMaterial() (look there for a detailed description),
\r
1833 //! but tries to load the programs from files.
\r
1834 s32 CNullDriver::addHighLevelShaderMaterialFromFiles(
\r
1835 io::IReadFile* vertexShaderProgram,
\r
1836 const c8* vertexShaderEntryPointName,
\r
1837 E_VERTEX_SHADER_TYPE vsCompileTarget,
\r
1838 io::IReadFile* pixelShaderProgram,
\r
1839 const c8* pixelShaderEntryPointName,
\r
1840 E_PIXEL_SHADER_TYPE psCompileTarget,
\r
1841 io::IReadFile* geometryShaderProgram,
\r
1842 const c8* geometryShaderEntryPointName,
\r
1843 E_GEOMETRY_SHADER_TYPE gsCompileTarget,
\r
1844 scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,
\r
1846 IShaderConstantSetCallBack* callback,
\r
1847 E_MATERIAL_TYPE baseMaterial,
\r
1854 if (vertexShaderProgram)
\r
1856 const long size = vertexShaderProgram->getSize();
\r
1859 vs = new c8[size+1];
\r
1860 vertexShaderProgram->read(vs, size);
\r
1865 if (pixelShaderProgram)
\r
1867 const long size = pixelShaderProgram->getSize();
\r
1870 // if both handles are the same we must reset the file
\r
1871 if (pixelShaderProgram==vertexShaderProgram)
\r
1872 pixelShaderProgram->seek(0);
\r
1873 ps = new c8[size+1];
\r
1874 pixelShaderProgram->read(ps, size);
\r
1879 if (geometryShaderProgram)
\r
1881 const long size = geometryShaderProgram->getSize();
\r
1884 // if both handles are the same we must reset the file
\r
1885 if ((geometryShaderProgram==vertexShaderProgram) ||
\r
1886 (geometryShaderProgram==pixelShaderProgram))
\r
1887 geometryShaderProgram->seek(0);
\r
1888 gs = new c8[size+1];
\r
1889 geometryShaderProgram->read(gs, size);
\r
1894 s32 result = this->addHighLevelShaderMaterial(
\r
1895 vs, vertexShaderEntryPointName, vsCompileTarget,
\r
1896 ps, pixelShaderEntryPointName, psCompileTarget,
\r
1897 gs, geometryShaderEntryPointName, gsCompileTarget,
\r
1898 inType, outType, verticesOut,
\r
1899 callback, baseMaterial, userData);
\r
1909 //! Adds a new material renderer to the VideoDriver, using pixel and/or
\r
1910 //! vertex shaders to render geometry.
\r
1911 s32 CNullDriver::addShaderMaterial(const c8* vertexShaderProgram,
\r
1912 const c8* pixelShaderProgram,
\r
1913 IShaderConstantSetCallBack* callback,
\r
1914 E_MATERIAL_TYPE baseMaterial,
\r
1917 os::Printer::log("Shader materials not implemented yet in this driver, sorry.");
\r
1922 //! Like IGPUProgrammingServices::addShaderMaterial(), but tries to load the
\r
1923 //! programs from files.
\r
1924 s32 CNullDriver::addShaderMaterialFromFiles(io::IReadFile* vertexShaderProgram,
\r
1925 io::IReadFile* pixelShaderProgram,
\r
1926 IShaderConstantSetCallBack* callback,
\r
1927 E_MATERIAL_TYPE baseMaterial,
\r
1933 if (vertexShaderProgram)
\r
1935 const long size = vertexShaderProgram->getSize();
\r
1938 vs = new c8[size+1];
\r
1939 vertexShaderProgram->read(vs, size);
\r
1944 if (pixelShaderProgram)
\r
1946 const long size = pixelShaderProgram->getSize();
\r
1949 ps = new c8[size+1];
\r
1950 pixelShaderProgram->read(ps, size);
\r
1955 s32 result = addShaderMaterial(vs, ps, callback, baseMaterial, userData);
\r
1964 //! Like IGPUProgrammingServices::addShaderMaterial(), but tries to load the
\r
1965 //! programs from files.
\r
1966 s32 CNullDriver::addShaderMaterialFromFiles(const io::path& vertexShaderProgramFileName,
\r
1967 const io::path& pixelShaderProgramFileName,
\r
1968 IShaderConstantSetCallBack* callback,
\r
1969 E_MATERIAL_TYPE baseMaterial,
\r
1972 io::IReadFile* vsfile = 0;
\r
1973 io::IReadFile* psfile = 0;
\r
1975 if (vertexShaderProgramFileName.size())
\r
1977 vsfile = FileSystem->createAndOpenFile(vertexShaderProgramFileName);
\r
1980 os::Printer::log("Could not open vertex shader program file",
\r
1981 vertexShaderProgramFileName, ELL_WARNING);
\r
1986 if (pixelShaderProgramFileName.size())
\r
1988 psfile = FileSystem->createAndOpenFile(pixelShaderProgramFileName);
\r
1991 os::Printer::log("Could not open pixel shader program file",
\r
1992 pixelShaderProgramFileName, ELL_WARNING);
\r
1999 s32 result = addShaderMaterialFromFiles(vsfile, psfile, callback,
\r
2000 baseMaterial, userData);
\r
2012 //! Creates a render target texture.
\r
2013 ITexture* CNullDriver::addRenderTargetTexture(const core::dimension2d<u32>& size,
\r
2014 const io::path&name, const ECOLOR_FORMAT format)
\r
2019 ITexture* CNullDriver::addRenderTargetTextureCubemap(const irr::u32 sideLen,
\r
2020 const io::path& name, const ECOLOR_FORMAT format)
\r
2025 void CNullDriver::clearBuffers(u16 flag, SColor color, f32 depth, u8 stencil)
\r
2030 //! Returns a pointer to the mesh manipulator.
\r
2031 scene::IMeshManipulator* CNullDriver::getMeshManipulator()
\r
2033 return MeshManipulator;
\r
2037 //! Returns an image created from the last rendered frame.
\r
2038 IImage* CNullDriver::createScreenShot(video::ECOLOR_FORMAT format, video::E_RENDER_TARGET target)
\r
2044 // prints renderer version
\r
2045 void CNullDriver::printVersion()
\r
2047 core::stringw namePrint = L"Using renderer: ";
\r
2048 namePrint += getName();
\r
2049 os::Printer::log(namePrint.c_str(), ELL_INFORMATION);
\r
2053 //! creates a video driver
\r
2054 IVideoDriver* createNullDriver(io::IFileSystem* io, const core::dimension2d<u32>& screenSize)
\r
2056 CNullDriver* nullDriver = new CNullDriver(io, screenSize);
\r
2058 // create empty material renderers
\r
2059 for(u32 i=0; sBuiltInMaterialTypeNames[i]; ++i)
\r
2061 IMaterialRenderer* imr = new IMaterialRenderer();
\r
2062 nullDriver->addMaterialRenderer(imr);
\r
2066 return nullDriver;
\r
2070 //! Set/unset a clipping plane.
\r
2071 //! There are at least 6 clipping planes available for the user to set at will.
\r
2072 //! \param index: The plane index. Must be between 0 and MaxUserClipPlanes.
\r
2073 //! \param plane: The plane itself.
\r
2074 //! \param enable: If true, enable the clipping plane else disable it.
\r
2075 bool CNullDriver::setClipPlane(u32 index, const core::plane3df& plane, bool enable)
\r
2081 //! Enable/disable a clipping plane.
\r
2082 void CNullDriver::enableClipPlane(u32 index, bool enable)
\r
2088 ITexture* CNullDriver::createRenderTargetTexture(const core::dimension2d<u32>& size,
\r
2091 os::Printer::log("createRenderTargetTexture is deprecated, use addRenderTargetTexture instead");
\r
2092 ITexture* tex = addRenderTargetTexture(size, name);
\r
2098 void CNullDriver::setMinHardwareBufferVertexCount(u32 count)
\r
2100 MinVertexCountForVBO = count;
\r
2104 SOverrideMaterial& CNullDriver::getOverrideMaterial()
\r
2106 return OverrideMaterial;
\r
2110 //! Get the 2d override material for altering its values
\r
2111 SMaterial& CNullDriver::getMaterial2D()
\r
2113 return OverrideMaterial2D;
\r
2117 //! Enable the 2d override material
\r
2118 void CNullDriver::enableMaterial2D(bool enable)
\r
2120 OverrideMaterial2DEnabled=enable;
\r
2124 core::dimension2du CNullDriver::getMaxTextureSize() const
\r
2126 return core::dimension2du(0x10000,0x10000); // maybe large enough
\r
2129 bool CNullDriver::needsTransparentRenderPass(const irr::video::SMaterial& material) const
\r
2131 // TODO: I suspect it would be nice if the material had an enum for further control.
\r
2132 // Especially it probably makes sense to allow disabling transparent render pass as soon as material.ZWriteEnable is on.
\r
2133 // But then we might want an enum for the renderpass in material instead of just a transparency flag in material - and that's more work.
\r
2134 // Or we could at least set return false when material.ZWriteEnable is EZW_ON? Still considering that...
\r
2135 // Be careful - this function is deeply connected to getWriteZBuffer as transparent render passes are usually about rendering with
\r
2136 // zwrite disabled and getWriteZBuffer calls this function.
\r
2138 video::IMaterialRenderer* rnd = getMaterialRenderer(material.MaterialType);
\r
2139 // TODO: I suspect IMaterialRenderer::isTransparent also often could use SMaterial as parameter
\r
2140 // We could for example then get rid of IsTransparent function in SMaterial and move that to the software material renderer.
\r
2141 if (rnd && rnd->isTransparent())
\r
2148 //! Color conversion convenience function
\r
2149 /** Convert an image (as array of pixels) from source to destination
\r
2150 array, thereby converting the color format. The pixel size is
\r
2151 determined by the color formats.
\r
2152 \param sP Pointer to source
\r
2153 \param sF Color format of source
\r
2154 \param sN Number of pixels to convert, both array must be large enough
\r
2155 \param dP Pointer to destination
\r
2156 \param dF Color format of destination
\r
2158 void CNullDriver::convertColor(const void* sP, ECOLOR_FORMAT sF, s32 sN,
\r
2159 void* dP, ECOLOR_FORMAT dF) const
\r
2161 video::CColorConverter::convert_viaFormat(sP, sF, sN, dP, dF);
\r
2165 } // end namespace
\r
2166 } // end namespace
\r