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("MaxLights", getMaximalDynamicLightAmount());
\r
59 DriverAttributes->addInt("MaxAnisotropy", 1);
\r
60 // DriverAttributes->addInt("MaxUserClipPlanes", 0);
\r
61 // DriverAttributes->addInt("MaxAuxBuffers", 0);
\r
62 DriverAttributes->addInt("MaxMultipleRenderTargets", 1);
\r
63 DriverAttributes->addInt("MaxIndices", -1);
\r
64 DriverAttributes->addInt("MaxTextureSize", -1);
\r
65 // DriverAttributes->addInt("MaxGeometryVerticesOut", 0);
\r
66 // DriverAttributes->addFloat("MaxTextureLODBias", 0.f);
\r
67 DriverAttributes->addInt("Version", 1);
\r
68 // DriverAttributes->addInt("ShaderLanguageVersion", 0);
\r
69 // DriverAttributes->addInt("AntiAlias", 0);
\r
73 setTextureCreationFlag(ETCF_ALWAYS_32_BIT, true);
\r
74 setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, true);
\r
75 setTextureCreationFlag(ETCF_AUTO_GENERATE_MIP_MAPS, true);
\r
76 setTextureCreationFlag(ETCF_ALLOW_MEMORY_COPY, true);
\r
78 ViewPort = core::rect<s32>(core::position2d<s32>(0,0), core::dimension2di(screenSize));
\r
80 // create manipulator
\r
81 MeshManipulator = new scene::CMeshManipulator();
\r
86 // create surface loaders and writers
\r
87 SurfaceLoader.push_back(video::createImageLoaderTGA());
\r
88 SurfaceLoader.push_back(video::createImageLoaderPNG());
\r
89 SurfaceLoader.push_back(video::createImageLoaderJPG());
\r
90 SurfaceLoader.push_back(video::createImageLoaderBMP());
\r
92 SurfaceWriter.push_back(video::createImageWriterJPG());
\r
93 SurfaceWriter.push_back(video::createImageWriterPNG());
\r
96 // set ExposedData to 0
\r
97 memset((void*)&ExposedData, 0, sizeof(ExposedData));
\r
98 for (u32 i=0; i<video::EVDF_COUNT; ++i)
\r
99 FeatureEnabled[i]=true;
\r
101 InitMaterial2D.AntiAliasing=video::EAAM_OFF;
\r
102 InitMaterial2D.Lighting=false;
\r
103 InitMaterial2D.ZWriteEnable=video::EZW_OFF;
\r
104 InitMaterial2D.ZBuffer=video::ECFN_DISABLED;
\r
105 InitMaterial2D.UseMipMaps=false;
\r
106 for (u32 i=0; i<video::MATERIAL_MAX_TEXTURES; ++i)
\r
108 InitMaterial2D.TextureLayer[i].BilinearFilter=false;
\r
109 InitMaterial2D.TextureLayer[i].TextureWrapU=video::ETC_REPEAT;
\r
110 InitMaterial2D.TextureLayer[i].TextureWrapV=video::ETC_REPEAT;
\r
111 InitMaterial2D.TextureLayer[i].TextureWrapW = video::ETC_REPEAT;
\r
113 OverrideMaterial2D=InitMaterial2D;
\r
118 CNullDriver::~CNullDriver()
\r
120 if (DriverAttributes)
\r
121 DriverAttributes->drop();
\r
124 FileSystem->drop();
\r
126 if (MeshManipulator)
\r
127 MeshManipulator->drop();
\r
129 removeAllRenderTargets();
\r
131 deleteAllTextures();
\r
134 for (i=0; i<SurfaceLoader.size(); ++i)
\r
135 SurfaceLoader[i]->drop();
\r
137 for (i=0; i<SurfaceWriter.size(); ++i)
\r
138 SurfaceWriter[i]->drop();
\r
140 // delete material renderers
\r
141 deleteMaterialRenders();
\r
143 // delete hardware mesh buffers
\r
144 removeAllHardwareBuffers();
\r
148 //! Adds an external surface loader to the engine.
\r
149 void CNullDriver::addExternalImageLoader(IImageLoader* loader)
\r
155 SurfaceLoader.push_back(loader);
\r
159 //! Adds an external surface writer to the engine.
\r
160 void CNullDriver::addExternalImageWriter(IImageWriter* writer)
\r
166 SurfaceWriter.push_back(writer);
\r
170 //! Retrieve the number of image loaders
\r
171 u32 CNullDriver::getImageLoaderCount() const
\r
173 return SurfaceLoader.size();
\r
177 //! Retrieve the given image loader
\r
178 IImageLoader* CNullDriver::getImageLoader(u32 n)
\r
180 if (n < SurfaceLoader.size())
\r
181 return SurfaceLoader[n];
\r
186 //! Retrieve the number of image writers
\r
187 u32 CNullDriver::getImageWriterCount() const
\r
189 return SurfaceWriter.size();
\r
193 //! Retrieve the given image writer
\r
194 IImageWriter* CNullDriver::getImageWriter(u32 n)
\r
196 if (n < SurfaceWriter.size())
\r
197 return SurfaceWriter[n];
\r
202 //! deletes all textures
\r
203 void CNullDriver::deleteAllTextures()
\r
205 // we need to remove previously set textures which might otherwise be kept in the
\r
206 // last set material member. Could be optimized to reduce state changes.
\r
207 setMaterial(SMaterial());
\r
209 // reset render targets.
\r
211 for (u32 i=0; i<RenderTargets.size(); ++i)
\r
212 RenderTargets[i]->setTexture(0, 0);
\r
214 // remove textures.
\r
216 for (u32 i=0; i<Textures.size(); ++i)
\r
217 Textures[i].Surface->drop();
\r
221 SharedDepthTextures.clear();
\r
224 bool CNullDriver::beginScene(u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil, const SExposedVideoData& videoData, core::rect<s32>* sourceRect)
\r
226 PrimitivesDrawn = 0;
\r
230 bool CNullDriver::endScene()
\r
232 FPSCounter.registerFrame(os::Timer::getRealTime(), PrimitivesDrawn);
\r
233 updateAllHardwareBuffers();
\r
234 updateAllOcclusionQueries();
\r
239 //! Disable a feature of the driver.
\r
240 void CNullDriver::disableFeature(E_VIDEO_DRIVER_FEATURE feature, bool flag)
\r
242 FeatureEnabled[feature]=!flag;
\r
246 //! queries the features of the driver, returns true if feature is available
\r
247 bool CNullDriver::queryFeature(E_VIDEO_DRIVER_FEATURE feature) const
\r
253 //! Get attributes of the actual video driver
\r
254 const io::IAttributes& CNullDriver::getDriverAttributes() const
\r
256 return *DriverAttributes;
\r
260 //! sets transformation
\r
261 void CNullDriver::setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat)
\r
266 //! Returns the transformation set by setTransform
\r
267 const core::matrix4& CNullDriver::getTransform(E_TRANSFORMATION_STATE state) const
\r
269 return TransformationMatrix;
\r
273 //! sets a material
\r
274 void CNullDriver::setMaterial(const SMaterial& material)
\r
279 //! Removes a texture from the texture cache and deletes it, freeing lot of
\r
281 void CNullDriver::removeTexture(ITexture* texture)
\r
286 for (u32 i=0; i<Textures.size(); ++i)
\r
288 if (Textures[i].Surface == texture)
\r
298 //! Removes all texture from the texture cache and deletes them, freeing lot of
\r
300 void CNullDriver::removeAllTextures()
\r
302 setMaterial ( SMaterial() );
\r
303 deleteAllTextures();
\r
307 //! Returns a texture by index
\r
308 ITexture* CNullDriver::getTextureByIndex(u32 i)
\r
310 if ( i < Textures.size() )
\r
311 return Textures[i].Surface;
\r
317 //! Returns amount of textures currently loaded
\r
318 u32 CNullDriver::getTextureCount() const
\r
320 return Textures.size();
\r
324 //! Renames a texture
\r
325 void CNullDriver::renameTexture(ITexture* texture, const io::path& newName)
\r
327 // we can do a const_cast here safely, the name of the ITexture interface
\r
328 // is just readonly to prevent the user changing the texture name without invoking
\r
329 // this method, because the textures will need resorting afterwards
\r
331 io::SNamedPath& name = const_cast<io::SNamedPath&>(texture->getName());
\r
332 name.setPath(newName);
\r
337 ITexture* CNullDriver::addTexture(const core::dimension2d<u32>& size, const io::path& name, ECOLOR_FORMAT format)
\r
339 if (0 == name.size())
\r
341 os::Printer::log("Could not create ITexture, texture needs to have a non-empty name.", ELL_WARNING);
\r
345 IImage* image = new CImage(format, size);
\r
348 if (checkImage(image))
\r
350 t = createDeviceDependentTexture(name, image);
\r
364 ITexture* CNullDriver::addTexture(const io::path& name, IImage* image)
\r
366 if (0 == name.size())
\r
368 os::Printer::log("Could not create ITexture, texture needs to have a non-empty name.", ELL_WARNING);
\r
377 if (checkImage(image))
\r
379 t = createDeviceDependentTexture(name, image);
\r
391 ITexture* CNullDriver::addTextureCubemap(const io::path& name, IImage* imagePosX, IImage* imageNegX, IImage* imagePosY,
\r
392 IImage* imageNegY, IImage* imagePosZ, IImage* imageNegZ)
\r
394 if (0 == name.size() || !imagePosX || !imageNegX || !imagePosY || !imageNegY || !imagePosZ || !imageNegZ)
\r
399 core::array<IImage*> imageArray(6);
\r
400 imageArray.push_back(imagePosX);
\r
401 imageArray.push_back(imageNegX);
\r
402 imageArray.push_back(imagePosY);
\r
403 imageArray.push_back(imageNegY);
\r
404 imageArray.push_back(imagePosZ);
\r
405 imageArray.push_back(imageNegZ);
\r
407 if (checkImage(imageArray))
\r
409 t = createDeviceDependentTextureCubemap(name, imageArray);
\r
421 ITexture* CNullDriver::addTextureCubemap(const irr::u32 sideLen, const io::path& name, ECOLOR_FORMAT format)
\r
423 if ( 0 == sideLen )
\r
426 if (0 == name.size())
\r
428 os::Printer::log("Could not create ITexture, texture needs to have a non-empty name.", ELL_WARNING);
\r
432 core::array<IImage*> imageArray(6);
\r
433 for ( int i=0; i < 6; ++i )
\r
434 imageArray.push_back(new CImage(format, core::dimension2du(sideLen, sideLen)));
\r
437 if (checkImage(imageArray))
\r
439 t = createDeviceDependentTextureCubemap(name, imageArray);
\r
448 for ( int i=0; i < 6; ++i )
\r
449 imageArray[i]->drop();
\r
454 //! loads a Texture
\r
455 ITexture* CNullDriver::getTexture(const io::path& filename)
\r
457 // Identify textures by their absolute filenames if possible.
\r
458 const io::path absolutePath = FileSystem->getAbsolutePath(filename);
\r
460 ITexture* texture = findTexture(absolutePath);
\r
463 texture->updateSource(ETS_FROM_CACHE);
\r
467 // Then try the raw filename, which might be in an Archive
\r
468 texture = findTexture(filename);
\r
471 texture->updateSource(ETS_FROM_CACHE);
\r
475 // Now try to open the file using the complete path.
\r
476 io::IReadFile* file = FileSystem->createAndOpenFile(absolutePath);
\r
480 // Try to open it using the raw filename.
\r
481 file = FileSystem->createAndOpenFile(filename);
\r
486 // Re-check name for actual archive names
\r
487 texture = findTexture(file->getFileName());
\r
490 texture->updateSource(ETS_FROM_CACHE);
\r
495 texture = loadTextureFromFile(file);
\r
500 texture->updateSource(ETS_FROM_FILE);
\r
501 addTexture(texture);
\r
502 texture->drop(); // drop it because we created it, one grab too much
\r
505 os::Printer::log("Could not load texture", filename, ELL_ERROR);
\r
510 os::Printer::log("Could not open file of texture", filename, ELL_WARNING);
\r
516 //! loads a Texture
\r
517 ITexture* CNullDriver::getTexture(io::IReadFile* file)
\r
519 ITexture* texture = 0;
\r
523 texture = findTexture(file->getFileName());
\r
527 texture->updateSource(ETS_FROM_CACHE);
\r
531 texture = loadTextureFromFile(file);
\r
535 texture->updateSource(ETS_FROM_FILE);
\r
536 addTexture(texture);
\r
537 texture->drop(); // drop it because we created it, one grab too much
\r
541 os::Printer::log("Could not load texture", file->getFileName(), ELL_WARNING);
\r
548 //! opens the file and loads it into the surface
\r
549 video::ITexture* CNullDriver::loadTextureFromFile(io::IReadFile* file, const io::path& hashName )
\r
551 ITexture *texture = nullptr;
\r
553 IImage *image = createImageFromFile(file);
\r
557 if (checkImage(image)) {
\r
558 texture = createDeviceDependentTexture(hashName.size() ? hashName : file->getFileName(), image);
\r
560 os::Printer::log("Loaded texture", file->getFileName(), ELL_DEBUG);
\r
569 //! adds a surface, not loaded or created by the Irrlicht Engine
\r
570 void CNullDriver::addTexture(video::ITexture* texture)
\r
575 s.Surface = texture;
\r
578 Textures.push_back(s);
\r
580 // the new texture is now at the end of the texture list. when searching for
\r
581 // the next new texture, the texture array will be sorted and the index of this texture
\r
582 // will be changed. to let the order be more consistent to the user, sort
\r
583 // the textures now already although this isn't necessary:
\r
590 //! looks if the image is already loaded
\r
591 video::ITexture* CNullDriver::findTexture(const io::path& filename)
\r
594 SDummyTexture dummy(filename, ETT_2D);
\r
595 s.Surface = &dummy;
\r
597 s32 index = Textures.binary_search(s);
\r
599 return Textures[index].Surface;
\r
604 ITexture* CNullDriver::createDeviceDependentTexture(const io::path& name, IImage* image)
\r
606 SDummyTexture* dummy = new SDummyTexture(name, ETT_2D);
\r
607 dummy->setSize(image->getDimension());
\r
611 ITexture* CNullDriver::createDeviceDependentTextureCubemap(const io::path& name, const core::array<IImage*>& image)
\r
613 return new SDummyTexture(name, ETT_CUBEMAP);
\r
616 bool CNullDriver::setRenderTargetEx(IRenderTarget* target, u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil)
\r
621 bool CNullDriver::setRenderTarget(ITexture* texture, u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil)
\r
625 // create render target if require.
\r
626 if (!SharedRenderTarget)
\r
627 SharedRenderTarget = addRenderTarget();
\r
629 ITexture* depthTexture = 0;
\r
631 // try to find available depth texture with require size.
\r
632 for (u32 i = 0; i < SharedDepthTextures.size(); ++i)
\r
634 if (SharedDepthTextures[i]->getSize() == texture->getSize())
\r
636 depthTexture = SharedDepthTextures[i];
\r
642 // create depth texture if require.
\r
645 depthTexture = addRenderTargetTexture(texture->getSize(), "IRR_DEPTH_STENCIL", video::ECF_D24S8);
\r
646 SharedDepthTextures.push_back(depthTexture);
\r
649 SharedRenderTarget->setTexture(texture, depthTexture);
\r
651 return setRenderTargetEx(SharedRenderTarget, clearFlag, clearColor, clearDepth, clearStencil);
\r
655 return setRenderTargetEx(0, clearFlag, clearColor, clearDepth, clearStencil);
\r
659 //! sets a viewport
\r
660 void CNullDriver::setViewPort(const core::rect<s32>& area)
\r
665 //! gets the area of the current viewport
\r
666 const core::rect<s32>& CNullDriver::getViewPort() const
\r
672 //! draws a vertex primitive list
\r
673 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
675 if ((iType==EIT_16BIT) && (vertexCount>65536))
\r
676 os::Printer::log("Too many vertices for 16bit index type, render artifacts may occur.");
\r
677 PrimitivesDrawn += primitiveCount;
\r
681 //! draws a vertex primitive list in 2d
\r
682 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
684 if ((iType==EIT_16BIT) && (vertexCount>65536))
\r
685 os::Printer::log("Too many vertices for 16bit index type, render artifacts may occur.");
\r
686 PrimitivesDrawn += primitiveCount;
\r
690 //! Draws a 3d line.
\r
691 void CNullDriver::draw3DLine(const core::vector3df& start,
\r
692 const core::vector3df& end, SColor color)
\r
697 //! Draws a 3d axis aligned box.
\r
698 void CNullDriver::draw3DBox(const core::aabbox3d<f32>& box, SColor color)
\r
700 core::vector3df edges[8];
\r
701 box.getEdges(edges);
\r
703 // TODO: optimize into one big drawIndexPrimitive call.
\r
705 draw3DLine(edges[5], edges[1], color);
\r
706 draw3DLine(edges[1], edges[3], color);
\r
707 draw3DLine(edges[3], edges[7], color);
\r
708 draw3DLine(edges[7], edges[5], color);
\r
709 draw3DLine(edges[0], edges[2], color);
\r
710 draw3DLine(edges[2], edges[6], color);
\r
711 draw3DLine(edges[6], edges[4], color);
\r
712 draw3DLine(edges[4], edges[0], color);
\r
713 draw3DLine(edges[1], edges[0], color);
\r
714 draw3DLine(edges[3], edges[2], color);
\r
715 draw3DLine(edges[7], edges[6], color);
\r
716 draw3DLine(edges[5], edges[4], color);
\r
721 //! draws an 2d image
\r
722 void CNullDriver::draw2DImage(const video::ITexture* texture, const core::position2d<s32>& destPos, bool useAlphaChannelOfTexture)
\r
727 draw2DImage(texture,destPos, core::rect<s32>(core::position2d<s32>(0,0),
\r
728 core::dimension2di(texture->getOriginalSize())),
\r
730 SColor(255,255,255,255),
\r
731 useAlphaChannelOfTexture
\r
736 //! draws a set of 2d images, using a color and the alpha channel of the
\r
737 //! texture if desired.
\r
738 void CNullDriver::draw2DImageBatch(const video::ITexture* texture,
\r
739 const core::array<core::position2d<s32> >& positions,
\r
740 const core::array<core::rect<s32> >& sourceRects,
\r
741 const core::rect<s32>* clipRect,
\r
743 bool useAlphaChannelOfTexture)
\r
745 const irr::u32 drawCount = core::min_<u32>(positions.size(), sourceRects.size());
\r
747 for (u32 i=0; i<drawCount; ++i)
\r
749 draw2DImage(texture, positions[i], sourceRects[i],
\r
750 clipRect, color, useAlphaChannelOfTexture);
\r
755 //! Draws a part of the texture into the rectangle.
\r
756 void CNullDriver::draw2DImage(const video::ITexture* texture, const core::rect<s32>& destRect,
\r
757 const core::rect<s32>& sourceRect, const core::rect<s32>* clipRect,
\r
758 const video::SColor* const colors, bool useAlphaChannelOfTexture)
\r
760 if (destRect.isValid())
\r
761 draw2DImage(texture, core::position2d<s32>(destRect.UpperLeftCorner),
\r
762 sourceRect, clipRect, colors?colors[0]:video::SColor(0xffffffff),
\r
763 useAlphaChannelOfTexture);
\r
767 //! 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
768 void CNullDriver::draw2DImage(const video::ITexture* texture, const core::position2d<s32>& destPos,
\r
769 const core::rect<s32>& sourceRect,
\r
770 const core::rect<s32>* clipRect, SColor color,
\r
771 bool useAlphaChannelOfTexture)
\r
776 //! Draw a 2d rectangle
\r
777 void CNullDriver::draw2DRectangle(SColor color, const core::rect<s32>& pos, const core::rect<s32>* clip)
\r
779 draw2DRectangle(pos, color, color, color, color, clip);
\r
784 //! Draws a 2d rectangle with a gradient.
\r
785 void CNullDriver::draw2DRectangle(const core::rect<s32>& pos,
\r
786 SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown,
\r
787 const core::rect<s32>* clip)
\r
793 //! Draws a 2d line.
\r
794 void CNullDriver::draw2DLine(const core::position2d<s32>& start,
\r
795 const core::position2d<s32>& end, SColor color)
\r
800 //! returns color format
\r
801 ECOLOR_FORMAT CNullDriver::getColorFormat() const
\r
807 //! returns screen size
\r
808 const core::dimension2d<u32>& CNullDriver::getScreenSize() const
\r
814 //! get current render target
\r
815 IRenderTarget* CNullDriver::getCurrentRenderTarget() const
\r
817 return CurrentRenderTarget;
\r
821 const core::dimension2d<u32>& CNullDriver::getCurrentRenderTargetSize() const
\r
823 if (CurrentRenderTargetSize.Width == 0)
\r
826 return CurrentRenderTargetSize;
\r
830 // returns current frames per second value
\r
831 s32 CNullDriver::getFPS() const
\r
833 return FPSCounter.getFPS();
\r
838 //! returns amount of primitives (mostly triangles) were drawn in the last frame.
\r
839 //! very useful method for statistics.
\r
840 u32 CNullDriver::getPrimitiveCountDrawn( u32 param ) const
\r
842 return (0 == param) ? FPSCounter.getPrimitive() : (1 == param) ? FPSCounter.getPrimitiveAverage() : FPSCounter.getPrimitiveTotal();
\r
847 //! Sets the dynamic ambient light color. The default color is
\r
848 //! (0,0,0,0) which means it is dark.
\r
849 //! \param color: New color of the ambient light.
\r
850 void CNullDriver::setAmbientLight(const SColorf& color)
\r
852 AmbientLight = color;
\r
855 const SColorf& CNullDriver::getAmbientLight() const
\r
857 return AmbientLight;
\r
860 //! \return Returns the name of the video driver. Example: In case of the DIRECT3D8
\r
861 //! driver, it would return "Direct3D8".
\r
863 const wchar_t* CNullDriver::getName() const
\r
865 return L"Irrlicht NullDevice";
\r
870 //! Draws a shadow volume into the stencil buffer. To draw a stencil shadow, do
\r
871 //! this: First, draw all geometry. Then use this method, to draw the shadow
\r
872 //! volume. Then, use IVideoDriver::drawStencilShadow() to visualize the shadow.
\r
873 void CNullDriver::drawStencilShadowVolume(const core::array<core::vector3df>& triangles, bool zfail, u32 debugDataVisible)
\r
878 //! Fills the stencil shadow with color. After the shadow volume has been drawn
\r
879 //! into the stencil buffer using IVideoDriver::drawStencilShadowVolume(), use this
\r
880 //! to draw the color of the shadow.
\r
881 void CNullDriver::drawStencilShadow(bool clearStencilBuffer,
\r
882 video::SColor leftUpEdge, video::SColor rightUpEdge,
\r
883 video::SColor leftDownEdge, video::SColor rightDownEdge)
\r
888 //! deletes all dynamic lights there are
\r
889 void CNullDriver::deleteAllDynamicLights()
\r
891 Lights.set_used(0);
\r
895 //! adds a dynamic light
\r
896 s32 CNullDriver::addDynamicLight(const SLight& light)
\r
898 Lights.push_back(light);
\r
899 return Lights.size() - 1;
\r
902 //! Turns a dynamic light on or off
\r
903 //! \param lightIndex: the index returned by addDynamicLight
\r
904 //! \param turnOn: true to turn the light on, false to turn it off
\r
905 void CNullDriver::turnLightOn(s32 lightIndex, bool turnOn)
\r
911 //! returns the maximal amount of dynamic lights the device can handle
\r
912 u32 CNullDriver::getMaximalDynamicLightAmount() const
\r
918 //! Returns current amount of dynamic lights set
\r
919 //! \return Current amount of dynamic lights set
\r
920 u32 CNullDriver::getDynamicLightCount() const
\r
922 return Lights.size();
\r
926 //! Returns light data which was previously set by IVideoDriver::addDynamicLight().
\r
927 //! \param idx: Zero based index of the light. Must be greater than 0 and smaller
\r
928 //! than IVideoDriver()::getDynamicLightCount.
\r
929 //! \return Light data.
\r
930 const SLight& CNullDriver::getDynamicLight(u32 idx) const
\r
932 if ( idx < Lights.size() )
\r
933 return Lights[idx];
\r
936 _IRR_DEBUG_BREAK_IF(true)
\r
937 static const SLight dummy;
\r
943 //! Creates a boolean alpha channel of the texture based of an color key.
\r
944 void CNullDriver::makeColorKeyTexture(video::ITexture* texture,
\r
945 video::SColor color,
\r
946 bool zeroTexels) const
\r
951 if (texture->getColorFormat() != ECF_A1R5G5B5 &&
\r
952 texture->getColorFormat() != ECF_A8R8G8B8 )
\r
954 os::Printer::log("Error: Unsupported texture color format for making color key channel.", ELL_ERROR);
\r
958 if (texture->getColorFormat() == ECF_A1R5G5B5)
\r
960 u16 *p = (u16*)texture->lock();
\r
964 os::Printer::log("Could not lock texture for making color key channel.", ELL_ERROR);
\r
968 const core::dimension2d<u32> dim = texture->getSize();
\r
969 const u32 pitch = texture->getPitch() / 2;
\r
971 // color with alpha disabled (i.e. fully transparent)
\r
972 const u16 refZeroAlpha = (0x7fff & color.toA1R5G5B5());
\r
974 const u32 pixels = pitch * dim.Height;
\r
976 for (u32 pixel = 0; pixel < pixels; ++ pixel)
\r
978 // If the color matches the reference color, ignoring alphas,
\r
979 // set the alpha to zero.
\r
980 if(((*p) & 0x7fff) == refZeroAlpha)
\r
985 (*p) = refZeroAlpha;
\r
995 u32 *p = (u32*)texture->lock();
\r
999 os::Printer::log("Could not lock texture for making color key channel.", ELL_ERROR);
\r
1003 core::dimension2d<u32> dim = texture->getSize();
\r
1004 u32 pitch = texture->getPitch() / 4;
\r
1006 // color with alpha disabled (fully transparent)
\r
1007 const u32 refZeroAlpha = 0x00ffffff & color.color;
\r
1009 const u32 pixels = pitch * dim.Height;
\r
1010 for (u32 pixel = 0; pixel < pixels; ++ pixel)
\r
1012 // If the color matches the reference color, ignoring alphas,
\r
1013 // set the alpha to zero.
\r
1014 if(((*p) & 0x00ffffff) == refZeroAlpha)
\r
1019 (*p) = refZeroAlpha;
\r
1025 texture->unlock();
\r
1027 texture->regenerateMipMapLevels();
\r
1032 //! Creates an boolean alpha channel of the texture based of an color key position.
\r
1033 void CNullDriver::makeColorKeyTexture(video::ITexture* texture,
\r
1034 core::position2d<s32> colorKeyPixelPos,
\r
1035 bool zeroTexels) const
\r
1040 if (texture->getColorFormat() != ECF_A1R5G5B5 &&
\r
1041 texture->getColorFormat() != ECF_A8R8G8B8 )
\r
1043 os::Printer::log("Error: Unsupported texture color format for making color key channel.", ELL_ERROR);
\r
1049 if (texture->getColorFormat() == ECF_A1R5G5B5)
\r
1051 u16 *p = (u16*)texture->lock(ETLM_READ_ONLY);
\r
1055 os::Printer::log("Could not lock texture for making color key channel.", ELL_ERROR);
\r
1059 u32 pitch = texture->getPitch() / 2;
\r
1061 const u16 key16Bit = 0x7fff & p[colorKeyPixelPos.Y*pitch + colorKeyPixelPos.X];
\r
1063 colorKey = video::A1R5G5B5toA8R8G8B8(key16Bit);
\r
1067 u32 *p = (u32*)texture->lock(ETLM_READ_ONLY);
\r
1071 os::Printer::log("Could not lock texture for making color key channel.", ELL_ERROR);
\r
1075 u32 pitch = texture->getPitch() / 4;
\r
1076 colorKey = 0x00ffffff & p[colorKeyPixelPos.Y*pitch + colorKeyPixelPos.X];
\r
1079 texture->unlock();
\r
1080 makeColorKeyTexture(texture, colorKey, zeroTexels);
\r
1084 //! Returns the maximum amount of primitives (mostly vertices) which
\r
1085 //! the device is able to render with one drawIndexedTriangleList
\r
1087 u32 CNullDriver::getMaximalPrimitiveCount() const
\r
1089 return 0xFFFFFFFF;
\r
1093 //! checks triangle count and print warning if wrong
\r
1094 bool CNullDriver::checkPrimitiveCount(u32 prmCount) const
\r
1096 const u32 m = getMaximalPrimitiveCount();
\r
1101 snprintf_irr(tmp, sizeof(tmp), "Could not draw triangles, too many primitives(%u), maximum is %u.", prmCount, m);
\r
1102 os::Printer::log(tmp, ELL_ERROR);
\r
1109 bool CNullDriver::checkImage(IImage *image) const
\r
1111 ECOLOR_FORMAT format = image->getColorFormat();
\r
1112 core::dimension2d<u32> size = image->getDimension();
\r
1121 if (!queryFeature(EVDF_TEXTURE_COMPRESSED_DXT))
\r
1123 os::Printer::log("DXT texture compression not available.", ELL_ERROR);
\r
1126 else if (size.getOptimalSize(true, false) != size)
\r
1128 os::Printer::log("Invalid size of image for DXT texture, size of image must be power of two.", ELL_ERROR);
\r
1132 case ECF_PVRTC_RGB2:
\r
1133 case ECF_PVRTC_ARGB2:
\r
1134 case ECF_PVRTC_RGB4:
\r
1135 case ECF_PVRTC_ARGB4:
\r
1136 if (!queryFeature(EVDF_TEXTURE_COMPRESSED_PVRTC))
\r
1138 os::Printer::log("PVRTC texture compression not available.", ELL_ERROR);
\r
1141 else if (size.getOptimalSize(true, false) != size)
\r
1143 os::Printer::log("Invalid size of image for PVRTC compressed texture, size of image must be power of two and squared.", ELL_ERROR);
\r
1147 case ECF_PVRTC2_ARGB2:
\r
1148 case ECF_PVRTC2_ARGB4:
\r
1149 if (!queryFeature(EVDF_TEXTURE_COMPRESSED_PVRTC2))
\r
1151 os::Printer::log("PVRTC2 texture compression not available.", ELL_ERROR);
\r
1156 if (!queryFeature(EVDF_TEXTURE_COMPRESSED_ETC1))
\r
1158 os::Printer::log("ETC1 texture compression not available.", ELL_ERROR);
\r
1162 case ECF_ETC2_RGB:
\r
1163 case ECF_ETC2_ARGB:
\r
1164 if (!queryFeature(EVDF_TEXTURE_COMPRESSED_ETC2))
\r
1166 os::Printer::log("ETC2 texture compression not available.", ELL_ERROR);
\r
1176 bool CNullDriver::checkImage(const core::array<IImage*>& image) const
\r
1178 if (!image.size())
\r
1181 ECOLOR_FORMAT lastFormat = image[0]->getColorFormat();
\r
1182 core::dimension2d<u32> lastSize = image[0]->getDimension();
\r
1184 for (u32 i = 0; i < image.size(); ++i) {
\r
1185 ECOLOR_FORMAT format = image[i]->getColorFormat();
\r
1186 core::dimension2d<u32> size = image[i]->getDimension();
\r
1188 if (!checkImage(image[i]))
\r
1191 if (format != lastFormat || size != lastSize)
\r
1197 //! Enables or disables a texture creation flag.
\r
1198 void CNullDriver::setTextureCreationFlag(E_TEXTURE_CREATION_FLAG flag, bool enabled)
\r
1200 if (enabled && ((flag == ETCF_ALWAYS_16_BIT) || (flag == ETCF_ALWAYS_32_BIT)
\r
1201 || (flag == ETCF_OPTIMIZED_FOR_QUALITY) || (flag == ETCF_OPTIMIZED_FOR_SPEED)))
\r
1203 // disable other formats
\r
1204 setTextureCreationFlag(ETCF_ALWAYS_16_BIT, false);
\r
1205 setTextureCreationFlag(ETCF_ALWAYS_32_BIT, false);
\r
1206 setTextureCreationFlag(ETCF_OPTIMIZED_FOR_QUALITY, false);
\r
1207 setTextureCreationFlag(ETCF_OPTIMIZED_FOR_SPEED, false);
\r
1211 TextureCreationFlags = (TextureCreationFlags & (~flag)) |
\r
1212 ((((u32)!enabled)-1) & flag);
\r
1216 //! Returns if a texture creation flag is enabled or disabled.
\r
1217 bool CNullDriver::getTextureCreationFlag(E_TEXTURE_CREATION_FLAG flag) const
\r
1219 return (TextureCreationFlags & flag)!=0;
\r
1222 IImage *CNullDriver::createImageFromFile(const io::path& filename)
\r
1224 if (!filename.size())
\r
1227 io::IReadFile* file = FileSystem->createAndOpenFile(filename);
\r
1229 os::Printer::log("Could not open file of image", filename, ELL_WARNING);
\r
1233 IImage *image = createImageFromFile(file);
\r
1238 IImage *CNullDriver::createImageFromFile(io::IReadFile* file)
\r
1243 // try to load file based on file extension
\r
1244 for (int i = SurfaceLoader.size() - 1; i >= 0; --i) {
\r
1245 if (!SurfaceLoader[i]->isALoadableFileExtension(file->getFileName()))
\r
1248 file->seek(0); // reset file position which might have changed due to previous loadImage calls
\r
1249 if (IImage *image = SurfaceLoader[i]->loadImage(file))
\r
1253 // try to load file based on what is in it
\r
1254 for (int i = SurfaceLoader.size() - 1; i >= 0; --i) {
\r
1255 if (SurfaceLoader[i]->isALoadableFileExtension(file->getFileName()))
\r
1256 continue; // extension was tried above already
\r
1257 file->seek(0); // dito
\r
1258 if (!SurfaceLoader[i]->isALoadableFileFormat(file))
\r
1262 if (IImage *image = SurfaceLoader[i]->loadImage(file))
\r
1270 //! Writes the provided image to disk file
\r
1271 bool CNullDriver::writeImageToFile(IImage* image, const io::path& filename,u32 param)
\r
1273 io::IWriteFile* file = FileSystem->createAndWriteFile(filename);
\r
1277 bool result = writeImageToFile(image, file, param);
\r
1283 //! Writes the provided image to a file.
\r
1284 bool CNullDriver::writeImageToFile(IImage* image, io::IWriteFile * file, u32 param)
\r
1289 for (s32 i=SurfaceWriter.size()-1; i>=0; --i)
\r
1291 if (SurfaceWriter[i]->isAWriteableFileExtension(file->getFileName()))
\r
1293 bool written = SurfaceWriter[i]->writeImage(file, image, param);
\r
1298 return false; // failed to write
\r
1302 //! Creates a software image from a byte array.
\r
1303 IImage* CNullDriver::createImageFromData(ECOLOR_FORMAT format,
\r
1304 const core::dimension2d<u32>& size, void *data, bool ownForeignMemory,
\r
1305 bool deleteMemory)
\r
1307 return new CImage(format, size, data, ownForeignMemory, deleteMemory);
\r
1311 //! Creates an empty software image.
\r
1312 IImage* CNullDriver::createImage(ECOLOR_FORMAT format, const core::dimension2d<u32>& size)
\r
1314 return new CImage(format, size);
\r
1318 //! Creates a software image from another image.
\r
1319 IImage* CNullDriver::createImage(ECOLOR_FORMAT format, IImage *imageToCopy)
\r
1321 os::Printer::log("Deprecated method, please create an empty image instead and use copyTo().", ELL_WARNING);
\r
1323 CImage* tmp = new CImage(format, imageToCopy->getDimension());
\r
1324 imageToCopy->copyTo(tmp);
\r
1329 //! Creates a software image from part of another image.
\r
1330 IImage* CNullDriver::createImage(IImage* imageToCopy, const core::position2d<s32>& pos, const core::dimension2d<u32>& size)
\r
1332 os::Printer::log("Deprecated method, please create an empty image instead and use copyTo().", ELL_WARNING);
\r
1333 CImage* tmp = new CImage(imageToCopy->getColorFormat(), imageToCopy->getDimension());
\r
1334 imageToCopy->copyTo(tmp, core::position2di(0,0), core::recti(pos,size));
\r
1339 //! Creates a software image from part of a texture.
\r
1340 IImage* CNullDriver::createImage(ITexture* texture, const core::position2d<s32>& pos, const core::dimension2d<u32>& size)
\r
1342 if ((pos==core::position2di(0,0)) && (size == texture->getSize()))
\r
1344 void * data = texture->lock(ETLM_READ_ONLY);
\r
1347 IImage* image = new CImage(texture->getColorFormat(), size, data, false, false);
\r
1348 texture->unlock();
\r
1353 // make sure to avoid buffer overruns
\r
1354 // make the vector a separate variable for g++ 3.x
\r
1355 const core::vector2d<u32> leftUpper(core::clamp(static_cast<u32>(pos.X), 0u, texture->getSize().Width),
\r
1356 core::clamp(static_cast<u32>(pos.Y), 0u, texture->getSize().Height));
\r
1357 const core::rect<u32> clamped(leftUpper,
\r
1358 core::dimension2du(core::clamp(static_cast<u32>(size.Width), 0u, texture->getSize().Width),
\r
1359 core::clamp(static_cast<u32>(size.Height), 0u, texture->getSize().Height)));
\r
1360 if (!clamped.isValid())
\r
1362 u8* src = static_cast<u8*>(texture->lock(ETLM_READ_ONLY));
\r
1365 IImage* image = new CImage(texture->getColorFormat(), clamped.getSize());
\r
1366 u8* dst = static_cast<u8*>(image->getData());
\r
1367 src += clamped.UpperLeftCorner.Y * texture->getPitch() + image->getBytesPerPixel() * clamped.UpperLeftCorner.X;
\r
1368 for (u32 i=0; i<clamped.getHeight(); ++i)
\r
1370 video::CColorConverter::convert_viaFormat(src, texture->getColorFormat(), clamped.getWidth(), dst, image->getColorFormat());
\r
1371 src += texture->getPitch();
\r
1372 dst += image->getPitch();
\r
1374 texture->unlock();
\r
1380 //! Sets the fog mode.
\r
1381 void CNullDriver::setFog(SColor color, E_FOG_TYPE fogType, f32 start, f32 end,
\r
1382 f32 density, bool pixelFog, bool rangeFog)
\r
1385 FogType = fogType;
\r
1388 FogDensity = density;
\r
1389 PixelFog = pixelFog;
\r
1390 RangeFog = rangeFog;
\r
1393 //! Gets the fog mode.
\r
1394 void CNullDriver::getFog(SColor& color, E_FOG_TYPE& fogType, f32& start, f32& end,
\r
1395 f32& density, bool& pixelFog, bool& rangeFog)
\r
1398 fogType = FogType;
\r
1401 density = FogDensity;
\r
1402 pixelFog = PixelFog;
\r
1403 rangeFog = RangeFog;
\r
1406 //! Draws a mesh buffer
\r
1407 void CNullDriver::drawMeshBuffer(const scene::IMeshBuffer* mb)
\r
1412 //IVertexBuffer and IIndexBuffer later
\r
1413 SHWBufferLink *HWBuffer=getBufferLink(mb);
\r
1416 drawHardwareBuffer(HWBuffer);
\r
1418 drawVertexPrimitiveList(mb->getVertices(), mb->getVertexCount(), mb->getIndices(), mb->getPrimitiveCount(), mb->getVertexType(), mb->getPrimitiveType(), mb->getIndexType());
\r
1422 //! Draws the normals of a mesh buffer
\r
1423 void CNullDriver::drawMeshBufferNormals(const scene::IMeshBuffer* mb, f32 length, SColor color)
\r
1425 const u32 count = mb->getVertexCount();
\r
1426 const bool normalize = mb->getMaterial().NormalizeNormals;
\r
1428 for (u32 i=0; i < count; ++i)
\r
1430 core::vector3df normalizedNormal = mb->getNormal(i);
\r
1432 normalizedNormal.normalize();
\r
1434 const core::vector3df& pos = mb->getPosition(i);
\r
1435 draw3DLine(pos, pos + (normalizedNormal * length), color);
\r
1440 CNullDriver::SHWBufferLink *CNullDriver::getBufferLink(const scene::IMeshBuffer* mb)
\r
1442 if (!mb || !isHardwareBufferRecommend(mb))
\r
1445 //search for hardware links
\r
1446 SHWBufferLink *HWBuffer = reinterpret_cast<SHWBufferLink*>(mb->getHWBuffer());
\r
1450 return createHardwareBuffer(mb); //no hardware links, and mesh wants one, create it
\r
1454 //! Update all hardware buffers, remove unused ones
\r
1455 void CNullDriver::updateAllHardwareBuffers()
\r
1457 auto it = HWBufferList.begin();
\r
1458 while (it != HWBufferList.end()) {
\r
1459 SHWBufferLink *Link = *it;
\r
1462 if (!Link->MeshBuffer || Link->MeshBuffer->getReferenceCount() == 1)
\r
1463 deleteHardwareBuffer(Link);
\r
1468 void CNullDriver::deleteHardwareBuffer(SHWBufferLink *HWBuffer)
\r
1472 HWBufferList.erase(HWBuffer->listPosition);
\r
1477 //! Remove hardware buffer
\r
1478 void CNullDriver::removeHardwareBuffer(const scene::IMeshBuffer* mb)
\r
1482 SHWBufferLink *HWBuffer = reinterpret_cast<SHWBufferLink*>(mb->getHWBuffer());
\r
1484 deleteHardwareBuffer(HWBuffer);
\r
1488 //! Remove all hardware buffers
\r
1489 void CNullDriver::removeAllHardwareBuffers()
\r
1491 while (!HWBufferList.empty())
\r
1492 deleteHardwareBuffer(HWBufferList.front());
\r
1496 bool CNullDriver::isHardwareBufferRecommend(const scene::IMeshBuffer* mb)
\r
1498 if (!mb || (mb->getHardwareMappingHint_Index()==scene::EHM_NEVER && mb->getHardwareMappingHint_Vertex()==scene::EHM_NEVER))
\r
1501 if (mb->getVertexCount()<MinVertexCountForVBO)
\r
1508 //! Create occlusion query.
\r
1509 /** Use node for identification and mesh for occlusion test. */
\r
1510 void CNullDriver::addOcclusionQuery(scene::ISceneNode* node, const scene::IMesh* mesh)
\r
1516 if ((node->getType() != scene::ESNT_MESH) && (node->getType() != scene::ESNT_ANIMATED_MESH))
\r
1518 else if (node->getType() == scene::ESNT_MESH)
\r
1519 mesh = static_cast<scene::IMeshSceneNode*>(node)->getMesh();
\r
1521 mesh = static_cast<scene::IAnimatedMeshSceneNode*>(node)->getMesh()->getMesh(0);
\r
1526 //search for query
\r
1527 s32 index = OcclusionQueries.linear_search(SOccQuery(node));
\r
1530 if (OcclusionQueries[index].Mesh != mesh)
\r
1532 OcclusionQueries[index].Mesh->drop();
\r
1533 OcclusionQueries[index].Mesh = mesh;
\r
1539 OcclusionQueries.push_back(SOccQuery(node, mesh));
\r
1540 node->setAutomaticCulling(node->getAutomaticCulling() | scene::EAC_OCC_QUERY);
\r
1545 //! Remove occlusion query.
\r
1546 void CNullDriver::removeOcclusionQuery(scene::ISceneNode* node)
\r
1548 //search for query
\r
1549 s32 index = OcclusionQueries.linear_search(SOccQuery(node));
\r
1552 node->setAutomaticCulling(node->getAutomaticCulling() & ~scene::EAC_OCC_QUERY);
\r
1553 OcclusionQueries.erase(index);
\r
1558 //! Remove all occlusion queries.
\r
1559 void CNullDriver::removeAllOcclusionQueries()
\r
1561 for (s32 i=OcclusionQueries.size()-1; i>=0; --i)
\r
1563 removeOcclusionQuery(OcclusionQueries[i].Node);
\r
1568 //! Run occlusion query. Draws mesh stored in query.
\r
1569 /** If the mesh shall be rendered visible, use
\r
1570 flag to enable the proper material setting. */
\r
1571 void CNullDriver::runOcclusionQuery(scene::ISceneNode* node, bool visible)
\r
1575 s32 index = OcclusionQueries.linear_search(SOccQuery(node));
\r
1578 OcclusionQueries[index].Run=0;
\r
1582 mat.Lighting=false;
\r
1583 mat.AntiAliasing=0;
\r
1584 mat.ColorMask=ECP_NONE;
\r
1585 mat.GouraudShading=false;
\r
1586 mat.ZWriteEnable=EZW_OFF;
\r
1589 setTransform(video::ETS_WORLD, node->getAbsoluteTransformation());
\r
1590 const scene::IMesh* mesh = OcclusionQueries[index].Mesh;
\r
1591 for (u32 i=0; i<mesh->getMeshBufferCount(); ++i)
\r
1594 setMaterial(mesh->getMeshBuffer(i)->getMaterial());
\r
1595 drawMeshBuffer(mesh->getMeshBuffer(i));
\r
1600 //! Run all occlusion queries. Draws all meshes stored in queries.
\r
1601 /** If the meshes shall not be rendered visible, use
\r
1602 overrideMaterial to disable the color and depth buffer. */
\r
1603 void CNullDriver::runAllOcclusionQueries(bool visible)
\r
1605 for (u32 i=0; i<OcclusionQueries.size(); ++i)
\r
1606 runOcclusionQuery(OcclusionQueries[i].Node, visible);
\r
1610 //! Update occlusion query. Retrieves results from GPU.
\r
1611 /** If the query shall not block, set the flag to false.
\r
1612 Update might not occur in this case, though */
\r
1613 void CNullDriver::updateOcclusionQuery(scene::ISceneNode* node, bool block)
\r
1618 //! Update all occlusion queries. Retrieves results from GPU.
\r
1619 /** If the query shall not block, set the flag to false.
\r
1620 Update might not occur in this case, though */
\r
1621 void CNullDriver::updateAllOcclusionQueries(bool block)
\r
1623 for (u32 i=0; i<OcclusionQueries.size(); ++i)
\r
1625 if (OcclusionQueries[i].Run==u32(~0))
\r
1627 updateOcclusionQuery(OcclusionQueries[i].Node, block);
\r
1628 ++OcclusionQueries[i].Run;
\r
1629 if (OcclusionQueries[i].Run>1000)
\r
1630 removeOcclusionQuery(OcclusionQueries[i].Node);
\r
1635 //! Return query result.
\r
1636 /** Return value is the number of visible pixels/fragments.
\r
1637 The value is a safe approximation, i.e. can be larger then the
\r
1638 actual value of pixels. */
\r
1639 u32 CNullDriver::getOcclusionQueryResult(scene::ISceneNode* node) const
\r
1645 //! Create render target.
\r
1646 IRenderTarget* CNullDriver::addRenderTarget()
\r
1652 //! Remove render target.
\r
1653 void CNullDriver::removeRenderTarget(IRenderTarget* renderTarget)
\r
1655 if (!renderTarget)
\r
1658 for (u32 i = 0; i < RenderTargets.size(); ++i)
\r
1660 if (RenderTargets[i] == renderTarget)
\r
1662 RenderTargets[i]->drop();
\r
1663 RenderTargets.erase(i);
\r
1671 //! Remove all render targets.
\r
1672 void CNullDriver::removeAllRenderTargets()
\r
1674 for (u32 i = 0; i < RenderTargets.size(); ++i)
\r
1675 RenderTargets[i]->drop();
\r
1677 RenderTargets.clear();
\r
1679 SharedRenderTarget = 0;
\r
1683 //! Only used by the internal engine. Used to notify the driver that
\r
1684 //! the window was resized.
\r
1685 void CNullDriver::OnResize(const core::dimension2d<u32>& size)
\r
1687 if (ViewPort.getWidth() == (s32)ScreenSize.Width &&
\r
1688 ViewPort.getHeight() == (s32)ScreenSize.Height)
\r
1689 ViewPort = core::rect<s32>(core::position2d<s32>(0,0),
\r
1690 core::dimension2di(size));
\r
1692 ScreenSize = size;
\r
1696 // adds a material renderer and drops it afterwards. To be used for internal creation
\r
1697 s32 CNullDriver::addAndDropMaterialRenderer(IMaterialRenderer* m)
\r
1699 s32 i = addMaterialRenderer(m);
\r
1708 //! Adds a new material renderer to the video device.
\r
1709 s32 CNullDriver::addMaterialRenderer(IMaterialRenderer* renderer, const char* name)
\r
1714 SMaterialRenderer r;
\r
1715 r.Renderer = renderer;
\r
1718 if (name == 0 && (MaterialRenderers.size() < (sizeof(sBuiltInMaterialTypeNames) / sizeof(char*))-1 ))
\r
1720 // set name of built in renderer so that we don't have to implement name
\r
1721 // setting in all available renderers.
\r
1722 r.Name = sBuiltInMaterialTypeNames[MaterialRenderers.size()];
\r
1725 MaterialRenderers.push_back(r);
\r
1728 return MaterialRenderers.size()-1;
\r
1732 //! Sets the name of a material renderer.
\r
1733 void CNullDriver::setMaterialRendererName(u32 idx, const char* name)
\r
1735 if (idx < (sizeof(sBuiltInMaterialTypeNames) / sizeof(char*))-1 ||
\r
1736 idx >= MaterialRenderers.size())
\r
1739 MaterialRenderers[idx].Name = name;
\r
1742 void CNullDriver::swapMaterialRenderers(u32 idx1, u32 idx2, bool swapNames)
\r
1744 if ( idx1 < MaterialRenderers.size() && idx2 < MaterialRenderers.size() )
\r
1746 irr::core::swap(MaterialRenderers[idx1].Renderer, MaterialRenderers[idx2].Renderer);
\r
1748 irr::core::swap(MaterialRenderers[idx1].Name, MaterialRenderers[idx2].Name);
\r
1753 //! Returns driver and operating system specific data about the IVideoDriver.
\r
1754 const SExposedVideoData& CNullDriver::getExposedVideoData()
\r
1756 return ExposedData;
\r
1760 //! Returns type of video driver
\r
1761 E_DRIVER_TYPE CNullDriver::getDriverType() const
\r
1767 //! deletes all material renderers
\r
1768 void CNullDriver::deleteMaterialRenders()
\r
1770 // delete material renderers
\r
1771 for (u32 i=0; i<MaterialRenderers.size(); ++i)
\r
1772 if (MaterialRenderers[i].Renderer)
\r
1773 MaterialRenderers[i].Renderer->drop();
\r
1775 MaterialRenderers.clear();
\r
1779 //! Returns pointer to material renderer or null
\r
1780 IMaterialRenderer* CNullDriver::getMaterialRenderer(u32 idx) const
\r
1782 if ( idx < MaterialRenderers.size() )
\r
1783 return MaterialRenderers[idx].Renderer;
\r
1789 //! Returns amount of currently available material renderers.
\r
1790 u32 CNullDriver::getMaterialRendererCount() const
\r
1792 return MaterialRenderers.size();
\r
1796 //! Returns name of the material renderer
\r
1797 const char* CNullDriver::getMaterialRendererName(u32 idx) const
\r
1799 if ( idx < MaterialRenderers.size() )
\r
1800 return MaterialRenderers[idx].Name.c_str();
\r
1806 //! Returns pointer to the IGPUProgrammingServices interface.
\r
1807 IGPUProgrammingServices* CNullDriver::getGPUProgrammingServices()
\r
1813 //! Adds a new material renderer to the VideoDriver, based on a high level shading language.
\r
1814 s32 CNullDriver::addHighLevelShaderMaterial(
\r
1815 const c8* vertexShaderProgram,
\r
1816 const c8* vertexShaderEntryPointName,
\r
1817 E_VERTEX_SHADER_TYPE vsCompileTarget,
\r
1818 const c8* pixelShaderProgram,
\r
1819 const c8* pixelShaderEntryPointName,
\r
1820 E_PIXEL_SHADER_TYPE psCompileTarget,
\r
1821 const c8* geometryShaderProgram,
\r
1822 const c8* geometryShaderEntryPointName,
\r
1823 E_GEOMETRY_SHADER_TYPE gsCompileTarget,
\r
1824 scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,
\r
1826 IShaderConstantSetCallBack* callback,
\r
1827 E_MATERIAL_TYPE baseMaterial,
\r
1830 os::Printer::log("High level shader materials not available (yet) in this driver, sorry");
\r
1835 //! Like IGPUProgrammingServices::addShaderMaterial() (look there for a detailed description),
\r
1836 //! but tries to load the programs from files.
\r
1837 s32 CNullDriver::addHighLevelShaderMaterialFromFiles(
\r
1838 const io::path& vertexShaderProgramFileName,
\r
1839 const c8* vertexShaderEntryPointName,
\r
1840 E_VERTEX_SHADER_TYPE vsCompileTarget,
\r
1841 const io::path& pixelShaderProgramFileName,
\r
1842 const c8* pixelShaderEntryPointName,
\r
1843 E_PIXEL_SHADER_TYPE psCompileTarget,
\r
1844 const io::path& geometryShaderProgramFileName,
\r
1845 const c8* geometryShaderEntryPointName,
\r
1846 E_GEOMETRY_SHADER_TYPE gsCompileTarget,
\r
1847 scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,
\r
1849 IShaderConstantSetCallBack* callback,
\r
1850 E_MATERIAL_TYPE baseMaterial,
\r
1853 io::IReadFile* vsfile = 0;
\r
1854 io::IReadFile* psfile = 0;
\r
1855 io::IReadFile* gsfile = 0;
\r
1857 if (vertexShaderProgramFileName.size() )
\r
1859 vsfile = FileSystem->createAndOpenFile(vertexShaderProgramFileName);
\r
1862 os::Printer::log("Could not open vertex shader program file",
\r
1863 vertexShaderProgramFileName, ELL_WARNING);
\r
1867 if (pixelShaderProgramFileName.size() )
\r
1869 psfile = FileSystem->createAndOpenFile(pixelShaderProgramFileName);
\r
1872 os::Printer::log("Could not open pixel shader program file",
\r
1873 pixelShaderProgramFileName, ELL_WARNING);
\r
1877 if (geometryShaderProgramFileName.size() )
\r
1879 gsfile = FileSystem->createAndOpenFile(geometryShaderProgramFileName);
\r
1882 os::Printer::log("Could not open geometry shader program file",
\r
1883 geometryShaderProgramFileName, ELL_WARNING);
\r
1887 s32 result = addHighLevelShaderMaterialFromFiles(
\r
1888 vsfile, vertexShaderEntryPointName, vsCompileTarget,
\r
1889 psfile, pixelShaderEntryPointName, psCompileTarget,
\r
1890 gsfile, geometryShaderEntryPointName, gsCompileTarget,
\r
1891 inType, outType, verticesOut,
\r
1892 callback, baseMaterial, userData);
\r
1907 //! Like IGPUProgrammingServices::addShaderMaterial() (look there for a detailed description),
\r
1908 //! but tries to load the programs from files.
\r
1909 s32 CNullDriver::addHighLevelShaderMaterialFromFiles(
\r
1910 io::IReadFile* vertexShaderProgram,
\r
1911 const c8* vertexShaderEntryPointName,
\r
1912 E_VERTEX_SHADER_TYPE vsCompileTarget,
\r
1913 io::IReadFile* pixelShaderProgram,
\r
1914 const c8* pixelShaderEntryPointName,
\r
1915 E_PIXEL_SHADER_TYPE psCompileTarget,
\r
1916 io::IReadFile* geometryShaderProgram,
\r
1917 const c8* geometryShaderEntryPointName,
\r
1918 E_GEOMETRY_SHADER_TYPE gsCompileTarget,
\r
1919 scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,
\r
1921 IShaderConstantSetCallBack* callback,
\r
1922 E_MATERIAL_TYPE baseMaterial,
\r
1929 if (vertexShaderProgram)
\r
1931 const long size = vertexShaderProgram->getSize();
\r
1934 vs = new c8[size+1];
\r
1935 vertexShaderProgram->read(vs, size);
\r
1940 if (pixelShaderProgram)
\r
1942 const long size = pixelShaderProgram->getSize();
\r
1945 // if both handles are the same we must reset the file
\r
1946 if (pixelShaderProgram==vertexShaderProgram)
\r
1947 pixelShaderProgram->seek(0);
\r
1948 ps = new c8[size+1];
\r
1949 pixelShaderProgram->read(ps, size);
\r
1954 if (geometryShaderProgram)
\r
1956 const long size = geometryShaderProgram->getSize();
\r
1959 // if both handles are the same we must reset the file
\r
1960 if ((geometryShaderProgram==vertexShaderProgram) ||
\r
1961 (geometryShaderProgram==pixelShaderProgram))
\r
1962 geometryShaderProgram->seek(0);
\r
1963 gs = new c8[size+1];
\r
1964 geometryShaderProgram->read(gs, size);
\r
1969 s32 result = this->addHighLevelShaderMaterial(
\r
1970 vs, vertexShaderEntryPointName, vsCompileTarget,
\r
1971 ps, pixelShaderEntryPointName, psCompileTarget,
\r
1972 gs, geometryShaderEntryPointName, gsCompileTarget,
\r
1973 inType, outType, verticesOut,
\r
1974 callback, baseMaterial, userData);
\r
1984 //! Adds a new material renderer to the VideoDriver, using pixel and/or
\r
1985 //! vertex shaders to render geometry.
\r
1986 s32 CNullDriver::addShaderMaterial(const c8* vertexShaderProgram,
\r
1987 const c8* pixelShaderProgram,
\r
1988 IShaderConstantSetCallBack* callback,
\r
1989 E_MATERIAL_TYPE baseMaterial,
\r
1992 os::Printer::log("Shader materials not implemented yet in this driver, sorry.");
\r
1997 //! Like IGPUProgrammingServices::addShaderMaterial(), but tries to load the
\r
1998 //! programs from files.
\r
1999 s32 CNullDriver::addShaderMaterialFromFiles(io::IReadFile* vertexShaderProgram,
\r
2000 io::IReadFile* pixelShaderProgram,
\r
2001 IShaderConstantSetCallBack* callback,
\r
2002 E_MATERIAL_TYPE baseMaterial,
\r
2008 if (vertexShaderProgram)
\r
2010 const long size = vertexShaderProgram->getSize();
\r
2013 vs = new c8[size+1];
\r
2014 vertexShaderProgram->read(vs, size);
\r
2019 if (pixelShaderProgram)
\r
2021 const long size = pixelShaderProgram->getSize();
\r
2024 ps = new c8[size+1];
\r
2025 pixelShaderProgram->read(ps, size);
\r
2030 s32 result = addShaderMaterial(vs, ps, callback, baseMaterial, userData);
\r
2039 //! Like IGPUProgrammingServices::addShaderMaterial(), but tries to load the
\r
2040 //! programs from files.
\r
2041 s32 CNullDriver::addShaderMaterialFromFiles(const io::path& vertexShaderProgramFileName,
\r
2042 const io::path& pixelShaderProgramFileName,
\r
2043 IShaderConstantSetCallBack* callback,
\r
2044 E_MATERIAL_TYPE baseMaterial,
\r
2047 io::IReadFile* vsfile = 0;
\r
2048 io::IReadFile* psfile = 0;
\r
2050 if (vertexShaderProgramFileName.size())
\r
2052 vsfile = FileSystem->createAndOpenFile(vertexShaderProgramFileName);
\r
2055 os::Printer::log("Could not open vertex shader program file",
\r
2056 vertexShaderProgramFileName, ELL_WARNING);
\r
2061 if (pixelShaderProgramFileName.size())
\r
2063 psfile = FileSystem->createAndOpenFile(pixelShaderProgramFileName);
\r
2066 os::Printer::log("Could not open pixel shader program file",
\r
2067 pixelShaderProgramFileName, ELL_WARNING);
\r
2074 s32 result = addShaderMaterialFromFiles(vsfile, psfile, callback,
\r
2075 baseMaterial, userData);
\r
2087 //! Creates a render target texture.
\r
2088 ITexture* CNullDriver::addRenderTargetTexture(const core::dimension2d<u32>& size,
\r
2089 const io::path&name, const ECOLOR_FORMAT format)
\r
2094 ITexture* CNullDriver::addRenderTargetTextureCubemap(const irr::u32 sideLen,
\r
2095 const io::path& name, const ECOLOR_FORMAT format)
\r
2100 void CNullDriver::clearBuffers(u16 flag, SColor color, f32 depth, u8 stencil)
\r
2105 //! Returns a pointer to the mesh manipulator.
\r
2106 scene::IMeshManipulator* CNullDriver::getMeshManipulator()
\r
2108 return MeshManipulator;
\r
2112 //! Returns an image created from the last rendered frame.
\r
2113 IImage* CNullDriver::createScreenShot(video::ECOLOR_FORMAT format, video::E_RENDER_TARGET target)
\r
2119 // prints renderer version
\r
2120 void CNullDriver::printVersion()
\r
2122 core::stringw namePrint = L"Using renderer: ";
\r
2123 namePrint += getName();
\r
2124 os::Printer::log(namePrint.c_str(), ELL_INFORMATION);
\r
2128 //! creates a video driver
\r
2129 IVideoDriver* createNullDriver(io::IFileSystem* io, const core::dimension2d<u32>& screenSize)
\r
2131 CNullDriver* nullDriver = new CNullDriver(io, screenSize);
\r
2133 // create empty material renderers
\r
2134 for(u32 i=0; sBuiltInMaterialTypeNames[i]; ++i)
\r
2136 IMaterialRenderer* imr = new IMaterialRenderer();
\r
2137 nullDriver->addMaterialRenderer(imr);
\r
2141 return nullDriver;
\r
2145 //! Set/unset a clipping plane.
\r
2146 //! There are at least 6 clipping planes available for the user to set at will.
\r
2147 //! \param index: The plane index. Must be between 0 and MaxUserClipPlanes.
\r
2148 //! \param plane: The plane itself.
\r
2149 //! \param enable: If true, enable the clipping plane else disable it.
\r
2150 bool CNullDriver::setClipPlane(u32 index, const core::plane3df& plane, bool enable)
\r
2156 //! Enable/disable a clipping plane.
\r
2157 void CNullDriver::enableClipPlane(u32 index, bool enable)
\r
2163 ITexture* CNullDriver::createRenderTargetTexture(const core::dimension2d<u32>& size,
\r
2166 os::Printer::log("createRenderTargetTexture is deprecated, use addRenderTargetTexture instead");
\r
2167 ITexture* tex = addRenderTargetTexture(size, name);
\r
2173 void CNullDriver::setMinHardwareBufferVertexCount(u32 count)
\r
2175 MinVertexCountForVBO = count;
\r
2179 SOverrideMaterial& CNullDriver::getOverrideMaterial()
\r
2181 return OverrideMaterial;
\r
2185 //! Get the 2d override material for altering its values
\r
2186 SMaterial& CNullDriver::getMaterial2D()
\r
2188 return OverrideMaterial2D;
\r
2192 //! Enable the 2d override material
\r
2193 void CNullDriver::enableMaterial2D(bool enable)
\r
2195 OverrideMaterial2DEnabled=enable;
\r
2199 core::dimension2du CNullDriver::getMaxTextureSize() const
\r
2201 return core::dimension2du(0x10000,0x10000); // maybe large enough
\r
2204 bool CNullDriver::needsTransparentRenderPass(const irr::video::SMaterial& material) const
\r
2206 // TODO: I suspect it would be nice if the material had an enum for further control.
\r
2207 // Especially it probably makes sense to allow disabling transparent render pass as soon as material.ZWriteEnable is on.
\r
2208 // 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
2209 // Or we could at least set return false when material.ZWriteEnable is EZW_ON? Still considering that...
\r
2210 // Be careful - this function is deeply connected to getWriteZBuffer as transparent render passes are usually about rendering with
\r
2211 // zwrite disabled and getWriteZBuffer calls this function.
\r
2213 video::IMaterialRenderer* rnd = getMaterialRenderer(material.MaterialType);
\r
2214 // TODO: I suspect IMaterialRenderer::isTransparent also often could use SMaterial as parameter
\r
2215 // We could for example then get rid of IsTransparent function in SMaterial and move that to the software material renderer.
\r
2216 if (rnd && rnd->isTransparent())
\r
2223 //! Color conversion convenience function
\r
2224 /** Convert an image (as array of pixels) from source to destination
\r
2225 array, thereby converting the color format. The pixel size is
\r
2226 determined by the color formats.
\r
2227 \param sP Pointer to source
\r
2228 \param sF Color format of source
\r
2229 \param sN Number of pixels to convert, both array must be large enough
\r
2230 \param dP Pointer to destination
\r
2231 \param dF Color format of destination
\r
2233 void CNullDriver::convertColor(const void* sP, ECOLOR_FORMAT sF, s32 sN,
\r
2234 void* dP, ECOLOR_FORMAT dF) const
\r
2236 video::CColorConverter::convert_viaFormat(sP, sF, sN, dP, dF);
\r
2240 } // end namespace
\r
2241 } // end namespace
\r