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 core::array<IImage*> imageArray(1);
\r
348 imageArray.push_back(image);
\r
350 if (checkImage(imageArray))
\r
352 t = createDeviceDependentTexture(name, image);
\r
366 ITexture* CNullDriver::addTexture(const io::path& name, IImage* image)
\r
368 if (0 == name.size())
\r
370 os::Printer::log("Could not create ITexture, texture needs to have a non-empty name.", ELL_WARNING);
\r
379 core::array<IImage*> imageArray(1);
\r
380 imageArray.push_back(image);
\r
382 if (checkImage(imageArray))
\r
384 t = createDeviceDependentTexture(name, image);
\r
396 ITexture* CNullDriver::addTextureCubemap(const io::path& name, IImage* imagePosX, IImage* imageNegX, IImage* imagePosY,
\r
397 IImage* imageNegY, IImage* imagePosZ, IImage* imageNegZ)
\r
399 if (0 == name.size() || !imagePosX || !imageNegX || !imagePosY || !imageNegY || !imagePosZ || !imageNegZ)
\r
404 core::array<IImage*> imageArray(6);
\r
405 imageArray.push_back(imagePosX);
\r
406 imageArray.push_back(imageNegX);
\r
407 imageArray.push_back(imagePosY);
\r
408 imageArray.push_back(imageNegY);
\r
409 imageArray.push_back(imagePosZ);
\r
410 imageArray.push_back(imageNegZ);
\r
412 if (checkImage(imageArray))
\r
414 t = createDeviceDependentTextureCubemap(name, imageArray);
\r
426 ITexture* CNullDriver::addTextureCubemap(const irr::u32 sideLen, const io::path& name, ECOLOR_FORMAT format)
\r
428 if ( 0 == sideLen )
\r
431 if (0 == name.size())
\r
433 os::Printer::log("Could not create ITexture, texture needs to have a non-empty name.", ELL_WARNING);
\r
437 core::array<IImage*> imageArray(6);
\r
438 for ( int i=0; i < 6; ++i )
\r
439 imageArray.push_back(new CImage(format, core::dimension2du(sideLen, sideLen)));
\r
442 if (checkImage(imageArray))
\r
444 t = createDeviceDependentTextureCubemap(name, imageArray);
\r
453 for ( int i=0; i < 6; ++i )
\r
454 imageArray[i]->drop();
\r
459 //! loads a Texture
\r
460 ITexture* CNullDriver::getTexture(const io::path& filename)
\r
462 // Identify textures by their absolute filenames if possible.
\r
463 const io::path absolutePath = FileSystem->getAbsolutePath(filename);
\r
465 ITexture* texture = findTexture(absolutePath);
\r
468 texture->updateSource(ETS_FROM_CACHE);
\r
472 // Then try the raw filename, which might be in an Archive
\r
473 texture = findTexture(filename);
\r
476 texture->updateSource(ETS_FROM_CACHE);
\r
480 // Now try to open the file using the complete path.
\r
481 io::IReadFile* file = FileSystem->createAndOpenFile(absolutePath);
\r
485 // Try to open it using the raw filename.
\r
486 file = FileSystem->createAndOpenFile(filename);
\r
491 // Re-check name for actual archive names
\r
492 texture = findTexture(file->getFileName());
\r
495 texture->updateSource(ETS_FROM_CACHE);
\r
500 texture = loadTextureFromFile(file);
\r
505 texture->updateSource(ETS_FROM_FILE);
\r
506 addTexture(texture);
\r
507 texture->drop(); // drop it because we created it, one grab too much
\r
510 os::Printer::log("Could not load texture", filename, ELL_ERROR);
\r
515 os::Printer::log("Could not open file of texture", filename, ELL_WARNING);
\r
521 //! loads a Texture
\r
522 ITexture* CNullDriver::getTexture(io::IReadFile* file)
\r
524 ITexture* texture = 0;
\r
528 texture = findTexture(file->getFileName());
\r
532 texture->updateSource(ETS_FROM_CACHE);
\r
536 texture = loadTextureFromFile(file);
\r
540 texture->updateSource(ETS_FROM_FILE);
\r
541 addTexture(texture);
\r
542 texture->drop(); // drop it because we created it, one grab too much
\r
546 os::Printer::log("Could not load texture", file->getFileName(), ELL_WARNING);
\r
553 //! opens the file and loads it into the surface
\r
554 video::ITexture* CNullDriver::loadTextureFromFile(io::IReadFile* file, const io::path& hashName )
\r
556 ITexture *texture = nullptr;
\r
558 IImage *image = createImageFromFile(file);
\r
562 core::array<IImage*> imageArray;
\r
563 imageArray.push_back(image);
\r
564 if (checkImage(imageArray)) {
\r
565 texture = createDeviceDependentTexture(hashName.size() ? hashName : file->getFileName(), image);
\r
567 os::Printer::log("Loaded texture", file->getFileName(), ELL_DEBUG);
\r
576 //! adds a surface, not loaded or created by the Irrlicht Engine
\r
577 void CNullDriver::addTexture(video::ITexture* texture)
\r
582 s.Surface = texture;
\r
585 Textures.push_back(s);
\r
587 // the new texture is now at the end of the texture list. when searching for
\r
588 // the next new texture, the texture array will be sorted and the index of this texture
\r
589 // will be changed. to let the order be more consistent to the user, sort
\r
590 // the textures now already although this isn't necessary:
\r
597 //! looks if the image is already loaded
\r
598 video::ITexture* CNullDriver::findTexture(const io::path& filename)
\r
601 SDummyTexture dummy(filename, ETT_2D);
\r
602 s.Surface = &dummy;
\r
604 s32 index = Textures.binary_search(s);
\r
606 return Textures[index].Surface;
\r
611 ITexture* CNullDriver::createDeviceDependentTexture(const io::path& name, IImage* image)
\r
613 SDummyTexture* dummy = new SDummyTexture(name, ETT_2D);
\r
614 dummy->setSize(image->getDimension());
\r
618 ITexture* CNullDriver::createDeviceDependentTextureCubemap(const io::path& name, const core::array<IImage*>& image)
\r
620 return new SDummyTexture(name, ETT_CUBEMAP);
\r
623 bool CNullDriver::setRenderTargetEx(IRenderTarget* target, u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil)
\r
628 bool CNullDriver::setRenderTarget(ITexture* texture, u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil)
\r
632 // create render target if require.
\r
633 if (!SharedRenderTarget)
\r
634 SharedRenderTarget = addRenderTarget();
\r
636 ITexture* depthTexture = 0;
\r
638 // try to find available depth texture with require size.
\r
639 for (u32 i = 0; i < SharedDepthTextures.size(); ++i)
\r
641 if (SharedDepthTextures[i]->getSize() == texture->getSize())
\r
643 depthTexture = SharedDepthTextures[i];
\r
649 // create depth texture if require.
\r
652 depthTexture = addRenderTargetTexture(texture->getSize(), "IRR_DEPTH_STENCIL", video::ECF_D24S8);
\r
653 SharedDepthTextures.push_back(depthTexture);
\r
656 SharedRenderTarget->setTexture(texture, depthTexture);
\r
658 return setRenderTargetEx(SharedRenderTarget, clearFlag, clearColor, clearDepth, clearStencil);
\r
662 return setRenderTargetEx(0, clearFlag, clearColor, clearDepth, clearStencil);
\r
666 //! sets a viewport
\r
667 void CNullDriver::setViewPort(const core::rect<s32>& area)
\r
672 //! gets the area of the current viewport
\r
673 const core::rect<s32>& CNullDriver::getViewPort() const
\r
679 //! draws a vertex primitive list
\r
680 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
682 if ((iType==EIT_16BIT) && (vertexCount>65536))
\r
683 os::Printer::log("Too many vertices for 16bit index type, render artifacts may occur.");
\r
684 PrimitivesDrawn += primitiveCount;
\r
688 //! draws a vertex primitive list in 2d
\r
689 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
691 if ((iType==EIT_16BIT) && (vertexCount>65536))
\r
692 os::Printer::log("Too many vertices for 16bit index type, render artifacts may occur.");
\r
693 PrimitivesDrawn += primitiveCount;
\r
697 //! Draws a 3d line.
\r
698 void CNullDriver::draw3DLine(const core::vector3df& start,
\r
699 const core::vector3df& end, SColor color)
\r
704 //! Draws a 3d axis aligned box.
\r
705 void CNullDriver::draw3DBox(const core::aabbox3d<f32>& box, SColor color)
\r
707 core::vector3df edges[8];
\r
708 box.getEdges(edges);
\r
710 // TODO: optimize into one big drawIndexPrimitive call.
\r
712 draw3DLine(edges[5], edges[1], color);
\r
713 draw3DLine(edges[1], edges[3], color);
\r
714 draw3DLine(edges[3], edges[7], color);
\r
715 draw3DLine(edges[7], edges[5], color);
\r
716 draw3DLine(edges[0], edges[2], color);
\r
717 draw3DLine(edges[2], edges[6], color);
\r
718 draw3DLine(edges[6], edges[4], color);
\r
719 draw3DLine(edges[4], edges[0], color);
\r
720 draw3DLine(edges[1], edges[0], color);
\r
721 draw3DLine(edges[3], edges[2], color);
\r
722 draw3DLine(edges[7], edges[6], color);
\r
723 draw3DLine(edges[5], edges[4], color);
\r
728 //! draws an 2d image
\r
729 void CNullDriver::draw2DImage(const video::ITexture* texture, const core::position2d<s32>& destPos, bool useAlphaChannelOfTexture)
\r
734 draw2DImage(texture,destPos, core::rect<s32>(core::position2d<s32>(0,0),
\r
735 core::dimension2di(texture->getOriginalSize())),
\r
737 SColor(255,255,255,255),
\r
738 useAlphaChannelOfTexture
\r
743 //! draws a set of 2d images, using a color and the alpha channel of the
\r
744 //! texture if desired.
\r
745 void CNullDriver::draw2DImageBatch(const video::ITexture* texture,
\r
746 const core::array<core::position2d<s32> >& positions,
\r
747 const core::array<core::rect<s32> >& sourceRects,
\r
748 const core::rect<s32>* clipRect,
\r
750 bool useAlphaChannelOfTexture)
\r
752 const irr::u32 drawCount = core::min_<u32>(positions.size(), sourceRects.size());
\r
754 for (u32 i=0; i<drawCount; ++i)
\r
756 draw2DImage(texture, positions[i], sourceRects[i],
\r
757 clipRect, color, useAlphaChannelOfTexture);
\r
762 //! Draws a part of the texture into the rectangle.
\r
763 void CNullDriver::draw2DImage(const video::ITexture* texture, const core::rect<s32>& destRect,
\r
764 const core::rect<s32>& sourceRect, const core::rect<s32>* clipRect,
\r
765 const video::SColor* const colors, bool useAlphaChannelOfTexture)
\r
767 if (destRect.isValid())
\r
768 draw2DImage(texture, core::position2d<s32>(destRect.UpperLeftCorner),
\r
769 sourceRect, clipRect, colors?colors[0]:video::SColor(0xffffffff),
\r
770 useAlphaChannelOfTexture);
\r
774 //! 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
775 void CNullDriver::draw2DImage(const video::ITexture* texture, const core::position2d<s32>& destPos,
\r
776 const core::rect<s32>& sourceRect,
\r
777 const core::rect<s32>* clipRect, SColor color,
\r
778 bool useAlphaChannelOfTexture)
\r
783 //! Draw a 2d rectangle
\r
784 void CNullDriver::draw2DRectangle(SColor color, const core::rect<s32>& pos, const core::rect<s32>* clip)
\r
786 draw2DRectangle(pos, color, color, color, color, clip);
\r
791 //! Draws a 2d rectangle with a gradient.
\r
792 void CNullDriver::draw2DRectangle(const core::rect<s32>& pos,
\r
793 SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown,
\r
794 const core::rect<s32>* clip)
\r
800 //! Draws a 2d line.
\r
801 void CNullDriver::draw2DLine(const core::position2d<s32>& start,
\r
802 const core::position2d<s32>& end, SColor color)
\r
807 //! returns color format
\r
808 ECOLOR_FORMAT CNullDriver::getColorFormat() const
\r
814 //! returns screen size
\r
815 const core::dimension2d<u32>& CNullDriver::getScreenSize() const
\r
821 //! get current render target
\r
822 IRenderTarget* CNullDriver::getCurrentRenderTarget() const
\r
824 return CurrentRenderTarget;
\r
828 const core::dimension2d<u32>& CNullDriver::getCurrentRenderTargetSize() const
\r
830 if (CurrentRenderTargetSize.Width == 0)
\r
833 return CurrentRenderTargetSize;
\r
837 // returns current frames per second value
\r
838 s32 CNullDriver::getFPS() const
\r
840 return FPSCounter.getFPS();
\r
845 //! returns amount of primitives (mostly triangles) were drawn in the last frame.
\r
846 //! very useful method for statistics.
\r
847 u32 CNullDriver::getPrimitiveCountDrawn( u32 param ) const
\r
849 return (0 == param) ? FPSCounter.getPrimitive() : (1 == param) ? FPSCounter.getPrimitiveAverage() : FPSCounter.getPrimitiveTotal();
\r
854 //! Sets the dynamic ambient light color. The default color is
\r
855 //! (0,0,0,0) which means it is dark.
\r
856 //! \param color: New color of the ambient light.
\r
857 void CNullDriver::setAmbientLight(const SColorf& color)
\r
859 AmbientLight = color;
\r
862 const SColorf& CNullDriver::getAmbientLight() const
\r
864 return AmbientLight;
\r
867 //! \return Returns the name of the video driver. Example: In case of the DIRECT3D8
\r
868 //! driver, it would return "Direct3D8".
\r
870 const wchar_t* CNullDriver::getName() const
\r
872 return L"Irrlicht NullDevice";
\r
876 //! Creates a boolean alpha channel of the texture based of an color key.
\r
877 void CNullDriver::makeColorKeyTexture(video::ITexture* texture,
\r
878 video::SColor color,
\r
879 bool zeroTexels) const
\r
884 if (texture->getColorFormat() != ECF_A1R5G5B5 &&
\r
885 texture->getColorFormat() != ECF_A8R8G8B8 )
\r
887 os::Printer::log("Error: Unsupported texture color format for making color key channel.", ELL_ERROR);
\r
891 if (texture->getColorFormat() == ECF_A1R5G5B5)
\r
893 u16 *p = (u16*)texture->lock();
\r
897 os::Printer::log("Could not lock texture for making color key channel.", ELL_ERROR);
\r
901 const core::dimension2d<u32> dim = texture->getSize();
\r
902 const u32 pitch = texture->getPitch() / 2;
\r
904 // color with alpha disabled (i.e. fully transparent)
\r
905 const u16 refZeroAlpha = (0x7fff & color.toA1R5G5B5());
\r
907 const u32 pixels = pitch * dim.Height;
\r
909 for (u32 pixel = 0; pixel < pixels; ++ pixel)
\r
911 // If the color matches the reference color, ignoring alphas,
\r
912 // set the alpha to zero.
\r
913 if(((*p) & 0x7fff) == refZeroAlpha)
\r
918 (*p) = refZeroAlpha;
\r
928 u32 *p = (u32*)texture->lock();
\r
932 os::Printer::log("Could not lock texture for making color key channel.", ELL_ERROR);
\r
936 core::dimension2d<u32> dim = texture->getSize();
\r
937 u32 pitch = texture->getPitch() / 4;
\r
939 // color with alpha disabled (fully transparent)
\r
940 const u32 refZeroAlpha = 0x00ffffff & color.color;
\r
942 const u32 pixels = pitch * dim.Height;
\r
943 for (u32 pixel = 0; pixel < pixels; ++ pixel)
\r
945 // If the color matches the reference color, ignoring alphas,
\r
946 // set the alpha to zero.
\r
947 if(((*p) & 0x00ffffff) == refZeroAlpha)
\r
952 (*p) = refZeroAlpha;
\r
960 texture->regenerateMipMapLevels();
\r
965 //! Creates an boolean alpha channel of the texture based of an color key position.
\r
966 void CNullDriver::makeColorKeyTexture(video::ITexture* texture,
\r
967 core::position2d<s32> colorKeyPixelPos,
\r
968 bool zeroTexels) const
\r
973 if (texture->getColorFormat() != ECF_A1R5G5B5 &&
\r
974 texture->getColorFormat() != ECF_A8R8G8B8 )
\r
976 os::Printer::log("Error: Unsupported texture color format for making color key channel.", ELL_ERROR);
\r
982 if (texture->getColorFormat() == ECF_A1R5G5B5)
\r
984 u16 *p = (u16*)texture->lock(ETLM_READ_ONLY);
\r
988 os::Printer::log("Could not lock texture for making color key channel.", ELL_ERROR);
\r
992 u32 pitch = texture->getPitch() / 2;
\r
994 const u16 key16Bit = 0x7fff & p[colorKeyPixelPos.Y*pitch + colorKeyPixelPos.X];
\r
996 colorKey = video::A1R5G5B5toA8R8G8B8(key16Bit);
\r
1000 u32 *p = (u32*)texture->lock(ETLM_READ_ONLY);
\r
1004 os::Printer::log("Could not lock texture for making color key channel.", ELL_ERROR);
\r
1008 u32 pitch = texture->getPitch() / 4;
\r
1009 colorKey = 0x00ffffff & p[colorKeyPixelPos.Y*pitch + colorKeyPixelPos.X];
\r
1012 texture->unlock();
\r
1013 makeColorKeyTexture(texture, colorKey, zeroTexels);
\r
1017 //! Returns the maximum amount of primitives (mostly vertices) which
\r
1018 //! the device is able to render with one drawIndexedTriangleList
\r
1020 u32 CNullDriver::getMaximalPrimitiveCount() const
\r
1022 return 0xFFFFFFFF;
\r
1026 //! checks triangle count and print warning if wrong
\r
1027 bool CNullDriver::checkPrimitiveCount(u32 prmCount) const
\r
1029 const u32 m = getMaximalPrimitiveCount();
\r
1034 snprintf_irr(tmp, sizeof(tmp), "Could not draw triangles, too many primitives(%u), maximum is %u.", prmCount, m);
\r
1035 os::Printer::log(tmp, ELL_ERROR);
\r
1042 bool CNullDriver::checkImage(const core::array<IImage*>& image) const
\r
1044 bool status = true;
\r
1046 if (image.size() > 0)
\r
1048 ECOLOR_FORMAT lastFormat = image[0]->getColorFormat();
\r
1049 core::dimension2d<u32> lastSize = image[0]->getDimension();
\r
1051 for (u32 i = 0; i < image.size() && status; ++i)
\r
1053 ECOLOR_FORMAT format = image[i]->getColorFormat();
\r
1054 core::dimension2d<u32> size = image[i]->getDimension();
\r
1063 if (!queryFeature(EVDF_TEXTURE_COMPRESSED_DXT))
\r
1065 os::Printer::log("DXT texture compression not available.", ELL_ERROR);
\r
1068 else if (size.getOptimalSize(true, false) != size)
\r
1070 os::Printer::log("Invalid size of image for DXT texture, size of image must be power of two.", ELL_ERROR);
\r
1074 case ECF_PVRTC_RGB2:
\r
1075 case ECF_PVRTC_ARGB2:
\r
1076 case ECF_PVRTC_RGB4:
\r
1077 case ECF_PVRTC_ARGB4:
\r
1078 if (!queryFeature(EVDF_TEXTURE_COMPRESSED_PVRTC))
\r
1080 os::Printer::log("PVRTC texture compression not available.", ELL_ERROR);
\r
1083 else if (size.getOptimalSize(true, false) != size)
\r
1085 os::Printer::log("Invalid size of image for PVRTC compressed texture, size of image must be power of two and squared.", ELL_ERROR);
\r
1089 case ECF_PVRTC2_ARGB2:
\r
1090 case ECF_PVRTC2_ARGB4:
\r
1091 if (!queryFeature(EVDF_TEXTURE_COMPRESSED_PVRTC2))
\r
1093 os::Printer::log("PVRTC2 texture compression not available.", ELL_ERROR);
\r
1098 if (!queryFeature(EVDF_TEXTURE_COMPRESSED_ETC1))
\r
1100 os::Printer::log("ETC1 texture compression not available.", ELL_ERROR);
\r
1104 case ECF_ETC2_RGB:
\r
1105 case ECF_ETC2_ARGB:
\r
1106 if (!queryFeature(EVDF_TEXTURE_COMPRESSED_ETC2))
\r
1108 os::Printer::log("ETC2 texture compression not available.", ELL_ERROR);
\r
1116 if (format != lastFormat || size != lastSize)
\r
1128 //! Enables or disables a texture creation flag.
\r
1129 void CNullDriver::setTextureCreationFlag(E_TEXTURE_CREATION_FLAG flag, bool enabled)
\r
1131 if (enabled && ((flag == ETCF_ALWAYS_16_BIT) || (flag == ETCF_ALWAYS_32_BIT)
\r
1132 || (flag == ETCF_OPTIMIZED_FOR_QUALITY) || (flag == ETCF_OPTIMIZED_FOR_SPEED)))
\r
1134 // disable other formats
\r
1135 setTextureCreationFlag(ETCF_ALWAYS_16_BIT, false);
\r
1136 setTextureCreationFlag(ETCF_ALWAYS_32_BIT, false);
\r
1137 setTextureCreationFlag(ETCF_OPTIMIZED_FOR_QUALITY, false);
\r
1138 setTextureCreationFlag(ETCF_OPTIMIZED_FOR_SPEED, false);
\r
1142 TextureCreationFlags = (TextureCreationFlags & (~flag)) |
\r
1143 ((((u32)!enabled)-1) & flag);
\r
1147 //! Returns if a texture creation flag is enabled or disabled.
\r
1148 bool CNullDriver::getTextureCreationFlag(E_TEXTURE_CREATION_FLAG flag) const
\r
1150 return (TextureCreationFlags & flag)!=0;
\r
1153 IImage *CNullDriver::createImageFromFile(const io::path& filename)
\r
1155 if (!filename.size())
\r
1158 io::IReadFile* file = FileSystem->createAndOpenFile(filename);
\r
1160 os::Printer::log("Could not open file of image", filename, ELL_WARNING);
\r
1164 IImage *image = createImageFromFile(file);
\r
1169 IImage *CNullDriver::createImageFromFile(io::IReadFile* file)
\r
1174 // try to load file based on file extension
\r
1175 for (int i = SurfaceLoader.size() - 1; i >= 0; --i) {
\r
1176 if (!SurfaceLoader[i]->isALoadableFileExtension(file->getFileName()))
\r
1179 file->seek(0); // reset file position which might have changed due to previous loadImage calls
\r
1180 if (IImage *image = SurfaceLoader[i]->loadImage(file))
\r
1184 // try to load file based on what is in it
\r
1185 for (int i = SurfaceLoader.size() - 1; i >= 0; --i) {
\r
1186 if (SurfaceLoader[i]->isALoadableFileExtension(file->getFileName()))
\r
1187 continue; // extension was tried above already
\r
1188 file->seek(0); // dito
\r
1189 if (!SurfaceLoader[i]->isALoadableFileFormat(file))
\r
1193 if (IImage *image = SurfaceLoader[i]->loadImage(file))
\r
1201 //! Writes the provided image to disk file
\r
1202 bool CNullDriver::writeImageToFile(IImage* image, const io::path& filename,u32 param)
\r
1204 io::IWriteFile* file = FileSystem->createAndWriteFile(filename);
\r
1208 bool result = writeImageToFile(image, file, param);
\r
1214 //! Writes the provided image to a file.
\r
1215 bool CNullDriver::writeImageToFile(IImage* image, io::IWriteFile * file, u32 param)
\r
1220 for (s32 i=SurfaceWriter.size()-1; i>=0; --i)
\r
1222 if (SurfaceWriter[i]->isAWriteableFileExtension(file->getFileName()))
\r
1224 bool written = SurfaceWriter[i]->writeImage(file, image, param);
\r
1229 return false; // failed to write
\r
1233 //! Creates a software image from a byte array.
\r
1234 IImage* CNullDriver::createImageFromData(ECOLOR_FORMAT format,
\r
1235 const core::dimension2d<u32>& size, void *data, bool ownForeignMemory,
\r
1236 bool deleteMemory)
\r
1238 return new CImage(format, size, data, ownForeignMemory, deleteMemory);
\r
1242 //! Creates an empty software image.
\r
1243 IImage* CNullDriver::createImage(ECOLOR_FORMAT format, const core::dimension2d<u32>& size)
\r
1245 return new CImage(format, size);
\r
1249 //! Creates a software image from another image.
\r
1250 IImage* CNullDriver::createImage(ECOLOR_FORMAT format, IImage *imageToCopy)
\r
1252 os::Printer::log("Deprecated method, please create an empty image instead and use copyTo().", ELL_WARNING);
\r
1254 CImage* tmp = new CImage(format, imageToCopy->getDimension());
\r
1255 imageToCopy->copyTo(tmp);
\r
1260 //! Creates a software image from part of another image.
\r
1261 IImage* CNullDriver::createImage(IImage* imageToCopy, const core::position2d<s32>& pos, const core::dimension2d<u32>& size)
\r
1263 os::Printer::log("Deprecated method, please create an empty image instead and use copyTo().", ELL_WARNING);
\r
1264 CImage* tmp = new CImage(imageToCopy->getColorFormat(), imageToCopy->getDimension());
\r
1265 imageToCopy->copyTo(tmp, core::position2di(0,0), core::recti(pos,size));
\r
1270 //! Creates a software image from part of a texture.
\r
1271 IImage* CNullDriver::createImage(ITexture* texture, const core::position2d<s32>& pos, const core::dimension2d<u32>& size)
\r
1273 if ((pos==core::position2di(0,0)) && (size == texture->getSize()))
\r
1275 void * data = texture->lock(ETLM_READ_ONLY);
\r
1278 IImage* image = new CImage(texture->getColorFormat(), size, data, false, false);
\r
1279 texture->unlock();
\r
1284 // make sure to avoid buffer overruns
\r
1285 // make the vector a separate variable for g++ 3.x
\r
1286 const core::vector2d<u32> leftUpper(core::clamp(static_cast<u32>(pos.X), 0u, texture->getSize().Width),
\r
1287 core::clamp(static_cast<u32>(pos.Y), 0u, texture->getSize().Height));
\r
1288 const core::rect<u32> clamped(leftUpper,
\r
1289 core::dimension2du(core::clamp(static_cast<u32>(size.Width), 0u, texture->getSize().Width),
\r
1290 core::clamp(static_cast<u32>(size.Height), 0u, texture->getSize().Height)));
\r
1291 if (!clamped.isValid())
\r
1293 u8* src = static_cast<u8*>(texture->lock(ETLM_READ_ONLY));
\r
1296 IImage* image = new CImage(texture->getColorFormat(), clamped.getSize());
\r
1297 u8* dst = static_cast<u8*>(image->getData());
\r
1298 src += clamped.UpperLeftCorner.Y * texture->getPitch() + image->getBytesPerPixel() * clamped.UpperLeftCorner.X;
\r
1299 for (u32 i=0; i<clamped.getHeight(); ++i)
\r
1301 video::CColorConverter::convert_viaFormat(src, texture->getColorFormat(), clamped.getWidth(), dst, image->getColorFormat());
\r
1302 src += texture->getPitch();
\r
1303 dst += image->getPitch();
\r
1305 texture->unlock();
\r
1311 //! Sets the fog mode.
\r
1312 void CNullDriver::setFog(SColor color, E_FOG_TYPE fogType, f32 start, f32 end,
\r
1313 f32 density, bool pixelFog, bool rangeFog)
\r
1316 FogType = fogType;
\r
1319 FogDensity = density;
\r
1320 PixelFog = pixelFog;
\r
1321 RangeFog = rangeFog;
\r
1324 //! Gets the fog mode.
\r
1325 void CNullDriver::getFog(SColor& color, E_FOG_TYPE& fogType, f32& start, f32& end,
\r
1326 f32& density, bool& pixelFog, bool& rangeFog)
\r
1329 fogType = FogType;
\r
1332 density = FogDensity;
\r
1333 pixelFog = PixelFog;
\r
1334 rangeFog = RangeFog;
\r
1337 //! Draws a mesh buffer
\r
1338 void CNullDriver::drawMeshBuffer(const scene::IMeshBuffer* mb)
\r
1343 //IVertexBuffer and IIndexBuffer later
\r
1344 SHWBufferLink *HWBuffer=getBufferLink(mb);
\r
1347 drawHardwareBuffer(HWBuffer);
\r
1349 drawVertexPrimitiveList(mb->getVertices(), mb->getVertexCount(), mb->getIndices(), mb->getPrimitiveCount(), mb->getVertexType(), mb->getPrimitiveType(), mb->getIndexType());
\r
1353 //! Draws the normals of a mesh buffer
\r
1354 void CNullDriver::drawMeshBufferNormals(const scene::IMeshBuffer* mb, f32 length, SColor color)
\r
1356 const u32 count = mb->getVertexCount();
\r
1357 const bool normalize = mb->getMaterial().NormalizeNormals;
\r
1359 for (u32 i=0; i < count; ++i)
\r
1361 core::vector3df normalizedNormal = mb->getNormal(i);
\r
1363 normalizedNormal.normalize();
\r
1365 const core::vector3df& pos = mb->getPosition(i);
\r
1366 draw3DLine(pos, pos + (normalizedNormal * length), color);
\r
1371 CNullDriver::SHWBufferLink *CNullDriver::getBufferLink(const scene::IMeshBuffer* mb)
\r
1373 if (!mb || !isHardwareBufferRecommend(mb))
\r
1376 //search for hardware links
\r
1377 SHWBufferLink *HWBuffer = reinterpret_cast<SHWBufferLink*>(mb->getHWBuffer());
\r
1381 return createHardwareBuffer(mb); //no hardware links, and mesh wants one, create it
\r
1385 //! Update all hardware buffers, remove unused ones
\r
1386 void CNullDriver::updateAllHardwareBuffers()
\r
1388 auto it = HWBufferList.begin();
\r
1389 while (it != HWBufferList.end()) {
\r
1390 SHWBufferLink *Link = *it;
\r
1393 if (!Link->MeshBuffer || Link->MeshBuffer->getReferenceCount() == 1)
\r
1394 deleteHardwareBuffer(Link);
\r
1399 void CNullDriver::deleteHardwareBuffer(SHWBufferLink *HWBuffer)
\r
1403 HWBufferList.erase(HWBuffer->listPosition);
\r
1408 //! Remove hardware buffer
\r
1409 void CNullDriver::removeHardwareBuffer(const scene::IMeshBuffer* mb)
\r
1413 SHWBufferLink *HWBuffer = reinterpret_cast<SHWBufferLink*>(mb->getHWBuffer());
\r
1415 deleteHardwareBuffer(HWBuffer);
\r
1419 //! Remove all hardware buffers
\r
1420 void CNullDriver::removeAllHardwareBuffers()
\r
1422 while (!HWBufferList.empty())
\r
1423 deleteHardwareBuffer(HWBufferList.front());
\r
1427 bool CNullDriver::isHardwareBufferRecommend(const scene::IMeshBuffer* mb)
\r
1429 if (!mb || (mb->getHardwareMappingHint_Index()==scene::EHM_NEVER && mb->getHardwareMappingHint_Vertex()==scene::EHM_NEVER))
\r
1432 if (mb->getVertexCount()<MinVertexCountForVBO)
\r
1439 //! Create occlusion query.
\r
1440 /** Use node for identification and mesh for occlusion test. */
\r
1441 void CNullDriver::addOcclusionQuery(scene::ISceneNode* node, const scene::IMesh* mesh)
\r
1447 if ((node->getType() != scene::ESNT_MESH) && (node->getType() != scene::ESNT_ANIMATED_MESH))
\r
1449 else if (node->getType() == scene::ESNT_MESH)
\r
1450 mesh = static_cast<scene::IMeshSceneNode*>(node)->getMesh();
\r
1452 mesh = static_cast<scene::IAnimatedMeshSceneNode*>(node)->getMesh()->getMesh(0);
\r
1457 //search for query
\r
1458 s32 index = OcclusionQueries.linear_search(SOccQuery(node));
\r
1461 if (OcclusionQueries[index].Mesh != mesh)
\r
1463 OcclusionQueries[index].Mesh->drop();
\r
1464 OcclusionQueries[index].Mesh = mesh;
\r
1470 OcclusionQueries.push_back(SOccQuery(node, mesh));
\r
1471 node->setAutomaticCulling(node->getAutomaticCulling() | scene::EAC_OCC_QUERY);
\r
1476 //! Remove occlusion query.
\r
1477 void CNullDriver::removeOcclusionQuery(scene::ISceneNode* node)
\r
1479 //search for query
\r
1480 s32 index = OcclusionQueries.linear_search(SOccQuery(node));
\r
1483 node->setAutomaticCulling(node->getAutomaticCulling() & ~scene::EAC_OCC_QUERY);
\r
1484 OcclusionQueries.erase(index);
\r
1489 //! Remove all occlusion queries.
\r
1490 void CNullDriver::removeAllOcclusionQueries()
\r
1492 for (s32 i=OcclusionQueries.size()-1; i>=0; --i)
\r
1494 removeOcclusionQuery(OcclusionQueries[i].Node);
\r
1499 //! Run occlusion query. Draws mesh stored in query.
\r
1500 /** If the mesh shall be rendered visible, use
\r
1501 flag to enable the proper material setting. */
\r
1502 void CNullDriver::runOcclusionQuery(scene::ISceneNode* node, bool visible)
\r
1506 s32 index = OcclusionQueries.linear_search(SOccQuery(node));
\r
1509 OcclusionQueries[index].Run=0;
\r
1513 mat.Lighting=false;
\r
1514 mat.AntiAliasing=0;
\r
1515 mat.ColorMask=ECP_NONE;
\r
1516 mat.GouraudShading=false;
\r
1517 mat.ZWriteEnable=EZW_OFF;
\r
1520 setTransform(video::ETS_WORLD, node->getAbsoluteTransformation());
\r
1521 const scene::IMesh* mesh = OcclusionQueries[index].Mesh;
\r
1522 for (u32 i=0; i<mesh->getMeshBufferCount(); ++i)
\r
1525 setMaterial(mesh->getMeshBuffer(i)->getMaterial());
\r
1526 drawMeshBuffer(mesh->getMeshBuffer(i));
\r
1531 //! Run all occlusion queries. Draws all meshes stored in queries.
\r
1532 /** If the meshes shall not be rendered visible, use
\r
1533 overrideMaterial to disable the color and depth buffer. */
\r
1534 void CNullDriver::runAllOcclusionQueries(bool visible)
\r
1536 for (u32 i=0; i<OcclusionQueries.size(); ++i)
\r
1537 runOcclusionQuery(OcclusionQueries[i].Node, visible);
\r
1541 //! Update occlusion query. Retrieves results from GPU.
\r
1542 /** If the query shall not block, set the flag to false.
\r
1543 Update might not occur in this case, though */
\r
1544 void CNullDriver::updateOcclusionQuery(scene::ISceneNode* node, bool block)
\r
1549 //! Update all occlusion queries. Retrieves results from GPU.
\r
1550 /** If the query shall not block, set the flag to false.
\r
1551 Update might not occur in this case, though */
\r
1552 void CNullDriver::updateAllOcclusionQueries(bool block)
\r
1554 for (u32 i=0; i<OcclusionQueries.size(); ++i)
\r
1556 if (OcclusionQueries[i].Run==u32(~0))
\r
1558 updateOcclusionQuery(OcclusionQueries[i].Node, block);
\r
1559 ++OcclusionQueries[i].Run;
\r
1560 if (OcclusionQueries[i].Run>1000)
\r
1561 removeOcclusionQuery(OcclusionQueries[i].Node);
\r
1566 //! Return query result.
\r
1567 /** Return value is the number of visible pixels/fragments.
\r
1568 The value is a safe approximation, i.e. can be larger then the
\r
1569 actual value of pixels. */
\r
1570 u32 CNullDriver::getOcclusionQueryResult(scene::ISceneNode* node) const
\r
1576 //! Create render target.
\r
1577 IRenderTarget* CNullDriver::addRenderTarget()
\r
1583 //! Remove render target.
\r
1584 void CNullDriver::removeRenderTarget(IRenderTarget* renderTarget)
\r
1586 if (!renderTarget)
\r
1589 for (u32 i = 0; i < RenderTargets.size(); ++i)
\r
1591 if (RenderTargets[i] == renderTarget)
\r
1593 RenderTargets[i]->drop();
\r
1594 RenderTargets.erase(i);
\r
1602 //! Remove all render targets.
\r
1603 void CNullDriver::removeAllRenderTargets()
\r
1605 for (u32 i = 0; i < RenderTargets.size(); ++i)
\r
1606 RenderTargets[i]->drop();
\r
1608 RenderTargets.clear();
\r
1610 SharedRenderTarget = 0;
\r
1614 //! Only used by the internal engine. Used to notify the driver that
\r
1615 //! the window was resized.
\r
1616 void CNullDriver::OnResize(const core::dimension2d<u32>& size)
\r
1618 if (ViewPort.getWidth() == (s32)ScreenSize.Width &&
\r
1619 ViewPort.getHeight() == (s32)ScreenSize.Height)
\r
1620 ViewPort = core::rect<s32>(core::position2d<s32>(0,0),
\r
1621 core::dimension2di(size));
\r
1623 ScreenSize = size;
\r
1627 // adds a material renderer and drops it afterwards. To be used for internal creation
\r
1628 s32 CNullDriver::addAndDropMaterialRenderer(IMaterialRenderer* m)
\r
1630 s32 i = addMaterialRenderer(m);
\r
1639 //! Adds a new material renderer to the video device.
\r
1640 s32 CNullDriver::addMaterialRenderer(IMaterialRenderer* renderer, const char* name)
\r
1645 SMaterialRenderer r;
\r
1646 r.Renderer = renderer;
\r
1649 if (name == 0 && (MaterialRenderers.size() < (sizeof(sBuiltInMaterialTypeNames) / sizeof(char*))-1 ))
\r
1651 // set name of built in renderer so that we don't have to implement name
\r
1652 // setting in all available renderers.
\r
1653 r.Name = sBuiltInMaterialTypeNames[MaterialRenderers.size()];
\r
1656 MaterialRenderers.push_back(r);
\r
1659 return MaterialRenderers.size()-1;
\r
1663 //! Sets the name of a material renderer.
\r
1664 void CNullDriver::setMaterialRendererName(u32 idx, const char* name)
\r
1666 if (idx < (sizeof(sBuiltInMaterialTypeNames) / sizeof(char*))-1 ||
\r
1667 idx >= MaterialRenderers.size())
\r
1670 MaterialRenderers[idx].Name = name;
\r
1673 void CNullDriver::swapMaterialRenderers(u32 idx1, u32 idx2, bool swapNames)
\r
1675 if ( idx1 < MaterialRenderers.size() && idx2 < MaterialRenderers.size() )
\r
1677 irr::core::swap(MaterialRenderers[idx1].Renderer, MaterialRenderers[idx2].Renderer);
\r
1679 irr::core::swap(MaterialRenderers[idx1].Name, MaterialRenderers[idx2].Name);
\r
1684 //! Returns driver and operating system specific data about the IVideoDriver.
\r
1685 const SExposedVideoData& CNullDriver::getExposedVideoData()
\r
1687 return ExposedData;
\r
1691 //! Returns type of video driver
\r
1692 E_DRIVER_TYPE CNullDriver::getDriverType() const
\r
1698 //! deletes all material renderers
\r
1699 void CNullDriver::deleteMaterialRenders()
\r
1701 // delete material renderers
\r
1702 for (u32 i=0; i<MaterialRenderers.size(); ++i)
\r
1703 if (MaterialRenderers[i].Renderer)
\r
1704 MaterialRenderers[i].Renderer->drop();
\r
1706 MaterialRenderers.clear();
\r
1710 //! Returns pointer to material renderer or null
\r
1711 IMaterialRenderer* CNullDriver::getMaterialRenderer(u32 idx) const
\r
1713 if ( idx < MaterialRenderers.size() )
\r
1714 return MaterialRenderers[idx].Renderer;
\r
1720 //! Returns amount of currently available material renderers.
\r
1721 u32 CNullDriver::getMaterialRendererCount() const
\r
1723 return MaterialRenderers.size();
\r
1727 //! Returns name of the material renderer
\r
1728 const char* CNullDriver::getMaterialRendererName(u32 idx) const
\r
1730 if ( idx < MaterialRenderers.size() )
\r
1731 return MaterialRenderers[idx].Name.c_str();
\r
1737 //! Returns pointer to the IGPUProgrammingServices interface.
\r
1738 IGPUProgrammingServices* CNullDriver::getGPUProgrammingServices()
\r
1744 //! Adds a new material renderer to the VideoDriver, based on a high level shading language.
\r
1745 s32 CNullDriver::addHighLevelShaderMaterial(
\r
1746 const c8* vertexShaderProgram,
\r
1747 const c8* vertexShaderEntryPointName,
\r
1748 E_VERTEX_SHADER_TYPE vsCompileTarget,
\r
1749 const c8* pixelShaderProgram,
\r
1750 const c8* pixelShaderEntryPointName,
\r
1751 E_PIXEL_SHADER_TYPE psCompileTarget,
\r
1752 const c8* geometryShaderProgram,
\r
1753 const c8* geometryShaderEntryPointName,
\r
1754 E_GEOMETRY_SHADER_TYPE gsCompileTarget,
\r
1755 scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,
\r
1757 IShaderConstantSetCallBack* callback,
\r
1758 E_MATERIAL_TYPE baseMaterial,
\r
1761 os::Printer::log("High level shader materials not available (yet) in this driver, sorry");
\r
1766 //! Like IGPUProgrammingServices::addShaderMaterial() (look there for a detailed description),
\r
1767 //! but tries to load the programs from files.
\r
1768 s32 CNullDriver::addHighLevelShaderMaterialFromFiles(
\r
1769 const io::path& vertexShaderProgramFileName,
\r
1770 const c8* vertexShaderEntryPointName,
\r
1771 E_VERTEX_SHADER_TYPE vsCompileTarget,
\r
1772 const io::path& pixelShaderProgramFileName,
\r
1773 const c8* pixelShaderEntryPointName,
\r
1774 E_PIXEL_SHADER_TYPE psCompileTarget,
\r
1775 const io::path& geometryShaderProgramFileName,
\r
1776 const c8* geometryShaderEntryPointName,
\r
1777 E_GEOMETRY_SHADER_TYPE gsCompileTarget,
\r
1778 scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,
\r
1780 IShaderConstantSetCallBack* callback,
\r
1781 E_MATERIAL_TYPE baseMaterial,
\r
1784 io::IReadFile* vsfile = 0;
\r
1785 io::IReadFile* psfile = 0;
\r
1786 io::IReadFile* gsfile = 0;
\r
1788 if (vertexShaderProgramFileName.size() )
\r
1790 vsfile = FileSystem->createAndOpenFile(vertexShaderProgramFileName);
\r
1793 os::Printer::log("Could not open vertex shader program file",
\r
1794 vertexShaderProgramFileName, ELL_WARNING);
\r
1798 if (pixelShaderProgramFileName.size() )
\r
1800 psfile = FileSystem->createAndOpenFile(pixelShaderProgramFileName);
\r
1803 os::Printer::log("Could not open pixel shader program file",
\r
1804 pixelShaderProgramFileName, ELL_WARNING);
\r
1808 if (geometryShaderProgramFileName.size() )
\r
1810 gsfile = FileSystem->createAndOpenFile(geometryShaderProgramFileName);
\r
1813 os::Printer::log("Could not open geometry shader program file",
\r
1814 geometryShaderProgramFileName, ELL_WARNING);
\r
1818 s32 result = addHighLevelShaderMaterialFromFiles(
\r
1819 vsfile, vertexShaderEntryPointName, vsCompileTarget,
\r
1820 psfile, pixelShaderEntryPointName, psCompileTarget,
\r
1821 gsfile, geometryShaderEntryPointName, gsCompileTarget,
\r
1822 inType, outType, verticesOut,
\r
1823 callback, baseMaterial, userData);
\r
1838 //! Like IGPUProgrammingServices::addShaderMaterial() (look there for a detailed description),
\r
1839 //! but tries to load the programs from files.
\r
1840 s32 CNullDriver::addHighLevelShaderMaterialFromFiles(
\r
1841 io::IReadFile* vertexShaderProgram,
\r
1842 const c8* vertexShaderEntryPointName,
\r
1843 E_VERTEX_SHADER_TYPE vsCompileTarget,
\r
1844 io::IReadFile* pixelShaderProgram,
\r
1845 const c8* pixelShaderEntryPointName,
\r
1846 E_PIXEL_SHADER_TYPE psCompileTarget,
\r
1847 io::IReadFile* geometryShaderProgram,
\r
1848 const c8* geometryShaderEntryPointName,
\r
1849 E_GEOMETRY_SHADER_TYPE gsCompileTarget,
\r
1850 scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,
\r
1852 IShaderConstantSetCallBack* callback,
\r
1853 E_MATERIAL_TYPE baseMaterial,
\r
1860 if (vertexShaderProgram)
\r
1862 const long size = vertexShaderProgram->getSize();
\r
1865 vs = new c8[size+1];
\r
1866 vertexShaderProgram->read(vs, size);
\r
1871 if (pixelShaderProgram)
\r
1873 const long size = pixelShaderProgram->getSize();
\r
1876 // if both handles are the same we must reset the file
\r
1877 if (pixelShaderProgram==vertexShaderProgram)
\r
1878 pixelShaderProgram->seek(0);
\r
1879 ps = new c8[size+1];
\r
1880 pixelShaderProgram->read(ps, size);
\r
1885 if (geometryShaderProgram)
\r
1887 const long size = geometryShaderProgram->getSize();
\r
1890 // if both handles are the same we must reset the file
\r
1891 if ((geometryShaderProgram==vertexShaderProgram) ||
\r
1892 (geometryShaderProgram==pixelShaderProgram))
\r
1893 geometryShaderProgram->seek(0);
\r
1894 gs = new c8[size+1];
\r
1895 geometryShaderProgram->read(gs, size);
\r
1900 s32 result = this->addHighLevelShaderMaterial(
\r
1901 vs, vertexShaderEntryPointName, vsCompileTarget,
\r
1902 ps, pixelShaderEntryPointName, psCompileTarget,
\r
1903 gs, geometryShaderEntryPointName, gsCompileTarget,
\r
1904 inType, outType, verticesOut,
\r
1905 callback, baseMaterial, userData);
\r
1915 //! Adds a new material renderer to the VideoDriver, using pixel and/or
\r
1916 //! vertex shaders to render geometry.
\r
1917 s32 CNullDriver::addShaderMaterial(const c8* vertexShaderProgram,
\r
1918 const c8* pixelShaderProgram,
\r
1919 IShaderConstantSetCallBack* callback,
\r
1920 E_MATERIAL_TYPE baseMaterial,
\r
1923 os::Printer::log("Shader materials not implemented yet in this driver, sorry.");
\r
1928 //! Like IGPUProgrammingServices::addShaderMaterial(), but tries to load the
\r
1929 //! programs from files.
\r
1930 s32 CNullDriver::addShaderMaterialFromFiles(io::IReadFile* vertexShaderProgram,
\r
1931 io::IReadFile* pixelShaderProgram,
\r
1932 IShaderConstantSetCallBack* callback,
\r
1933 E_MATERIAL_TYPE baseMaterial,
\r
1939 if (vertexShaderProgram)
\r
1941 const long size = vertexShaderProgram->getSize();
\r
1944 vs = new c8[size+1];
\r
1945 vertexShaderProgram->read(vs, size);
\r
1950 if (pixelShaderProgram)
\r
1952 const long size = pixelShaderProgram->getSize();
\r
1955 ps = new c8[size+1];
\r
1956 pixelShaderProgram->read(ps, size);
\r
1961 s32 result = addShaderMaterial(vs, ps, callback, baseMaterial, userData);
\r
1970 //! Like IGPUProgrammingServices::addShaderMaterial(), but tries to load the
\r
1971 //! programs from files.
\r
1972 s32 CNullDriver::addShaderMaterialFromFiles(const io::path& vertexShaderProgramFileName,
\r
1973 const io::path& pixelShaderProgramFileName,
\r
1974 IShaderConstantSetCallBack* callback,
\r
1975 E_MATERIAL_TYPE baseMaterial,
\r
1978 io::IReadFile* vsfile = 0;
\r
1979 io::IReadFile* psfile = 0;
\r
1981 if (vertexShaderProgramFileName.size())
\r
1983 vsfile = FileSystem->createAndOpenFile(vertexShaderProgramFileName);
\r
1986 os::Printer::log("Could not open vertex shader program file",
\r
1987 vertexShaderProgramFileName, ELL_WARNING);
\r
1992 if (pixelShaderProgramFileName.size())
\r
1994 psfile = FileSystem->createAndOpenFile(pixelShaderProgramFileName);
\r
1997 os::Printer::log("Could not open pixel shader program file",
\r
1998 pixelShaderProgramFileName, ELL_WARNING);
\r
2005 s32 result = addShaderMaterialFromFiles(vsfile, psfile, callback,
\r
2006 baseMaterial, userData);
\r
2018 //! Creates a render target texture.
\r
2019 ITexture* CNullDriver::addRenderTargetTexture(const core::dimension2d<u32>& size,
\r
2020 const io::path&name, const ECOLOR_FORMAT format)
\r
2025 ITexture* CNullDriver::addRenderTargetTextureCubemap(const irr::u32 sideLen,
\r
2026 const io::path& name, const ECOLOR_FORMAT format)
\r
2031 void CNullDriver::clearBuffers(u16 flag, SColor color, f32 depth, u8 stencil)
\r
2036 //! Returns a pointer to the mesh manipulator.
\r
2037 scene::IMeshManipulator* CNullDriver::getMeshManipulator()
\r
2039 return MeshManipulator;
\r
2043 //! Returns an image created from the last rendered frame.
\r
2044 IImage* CNullDriver::createScreenShot(video::ECOLOR_FORMAT format, video::E_RENDER_TARGET target)
\r
2050 // prints renderer version
\r
2051 void CNullDriver::printVersion()
\r
2053 core::stringw namePrint = L"Using renderer: ";
\r
2054 namePrint += getName();
\r
2055 os::Printer::log(namePrint.c_str(), ELL_INFORMATION);
\r
2059 //! creates a video driver
\r
2060 IVideoDriver* createNullDriver(io::IFileSystem* io, const core::dimension2d<u32>& screenSize)
\r
2062 CNullDriver* nullDriver = new CNullDriver(io, screenSize);
\r
2064 // create empty material renderers
\r
2065 for(u32 i=0; sBuiltInMaterialTypeNames[i]; ++i)
\r
2067 IMaterialRenderer* imr = new IMaterialRenderer();
\r
2068 nullDriver->addMaterialRenderer(imr);
\r
2072 return nullDriver;
\r
2076 //! Set/unset a clipping plane.
\r
2077 //! There are at least 6 clipping planes available for the user to set at will.
\r
2078 //! \param index: The plane index. Must be between 0 and MaxUserClipPlanes.
\r
2079 //! \param plane: The plane itself.
\r
2080 //! \param enable: If true, enable the clipping plane else disable it.
\r
2081 bool CNullDriver::setClipPlane(u32 index, const core::plane3df& plane, bool enable)
\r
2087 //! Enable/disable a clipping plane.
\r
2088 void CNullDriver::enableClipPlane(u32 index, bool enable)
\r
2094 ITexture* CNullDriver::createRenderTargetTexture(const core::dimension2d<u32>& size,
\r
2097 os::Printer::log("createRenderTargetTexture is deprecated, use addRenderTargetTexture instead");
\r
2098 ITexture* tex = addRenderTargetTexture(size, name);
\r
2104 void CNullDriver::setMinHardwareBufferVertexCount(u32 count)
\r
2106 MinVertexCountForVBO = count;
\r
2110 SOverrideMaterial& CNullDriver::getOverrideMaterial()
\r
2112 return OverrideMaterial;
\r
2116 //! Get the 2d override material for altering its values
\r
2117 SMaterial& CNullDriver::getMaterial2D()
\r
2119 return OverrideMaterial2D;
\r
2123 //! Enable the 2d override material
\r
2124 void CNullDriver::enableMaterial2D(bool enable)
\r
2126 OverrideMaterial2DEnabled=enable;
\r
2130 core::dimension2du CNullDriver::getMaxTextureSize() const
\r
2132 return core::dimension2du(0x10000,0x10000); // maybe large enough
\r
2135 bool CNullDriver::needsTransparentRenderPass(const irr::video::SMaterial& material) const
\r
2137 // TODO: I suspect it would be nice if the material had an enum for further control.
\r
2138 // Especially it probably makes sense to allow disabling transparent render pass as soon as material.ZWriteEnable is on.
\r
2139 // 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
2140 // Or we could at least set return false when material.ZWriteEnable is EZW_ON? Still considering that...
\r
2141 // Be careful - this function is deeply connected to getWriteZBuffer as transparent render passes are usually about rendering with
\r
2142 // zwrite disabled and getWriteZBuffer calls this function.
\r
2144 video::IMaterialRenderer* rnd = getMaterialRenderer(material.MaterialType);
\r
2145 // TODO: I suspect IMaterialRenderer::isTransparent also often could use SMaterial as parameter
\r
2146 // We could for example then get rid of IsTransparent function in SMaterial and move that to the software material renderer.
\r
2147 if (rnd && rnd->isTransparent())
\r
2154 //! Color conversion convenience function
\r
2155 /** Convert an image (as array of pixels) from source to destination
\r
2156 array, thereby converting the color format. The pixel size is
\r
2157 determined by the color formats.
\r
2158 \param sP Pointer to source
\r
2159 \param sF Color format of source
\r
2160 \param sN Number of pixels to convert, both array must be large enough
\r
2161 \param dP Pointer to destination
\r
2162 \param dF Color format of destination
\r
2164 void CNullDriver::convertColor(const void* sP, ECOLOR_FORMAT sF, s32 sN,
\r
2165 void* dP, ECOLOR_FORMAT dF) const
\r
2167 video::CColorConverter::convert_viaFormat(sP, sF, sN, dP, dF);
\r
2171 } // end namespace
\r
2172 } // end namespace
\r