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", _IRR_MATERIAL_MAX_TEXTURES_);
\r
57 DriverAttributes->addInt("MaxSupportedTextures", _IRR_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 = 0;
\r
558 E_TEXTURE_TYPE type = ETT_2D;
\r
560 core::array<IImage*> imageArray = createImagesFromFile(file, &type);
\r
562 if (checkImage(imageArray))
\r
567 texture = createDeviceDependentTexture(hashName.size() ? hashName : file->getFileName(), imageArray[0]);
\r
570 if (imageArray.size() >= 6 && imageArray[0] && imageArray[1] && imageArray[2] && imageArray[3] && imageArray[4] && imageArray[5])
\r
572 texture = createDeviceDependentTextureCubemap(hashName.size() ? hashName : file->getFileName(), imageArray);
\r
576 _IRR_DEBUG_BREAK_IF(true);
\r
581 os::Printer::log("Loaded texture", file->getFileName(), ELL_DEBUG);
\r
584 for (u32 i = 0; i < imageArray.size(); ++i)
\r
587 imageArray[i]->drop();
\r
594 //! adds a surface, not loaded or created by the Irrlicht Engine
\r
595 void CNullDriver::addTexture(video::ITexture* texture)
\r
600 s.Surface = texture;
\r
603 Textures.push_back(s);
\r
605 // the new texture is now at the end of the texture list. when searching for
\r
606 // the next new texture, the texture array will be sorted and the index of this texture
\r
607 // will be changed. to let the order be more consistent to the user, sort
\r
608 // the textures now already although this isn't necessary:
\r
615 //! looks if the image is already loaded
\r
616 video::ITexture* CNullDriver::findTexture(const io::path& filename)
\r
619 SDummyTexture dummy(filename, ETT_2D);
\r
620 s.Surface = &dummy;
\r
622 s32 index = Textures.binary_search(s);
\r
624 return Textures[index].Surface;
\r
629 ITexture* CNullDriver::createDeviceDependentTexture(const io::path& name, IImage* image)
\r
631 SDummyTexture* dummy = new SDummyTexture(name, ETT_2D);
\r
632 dummy->setSize(image->getDimension());
\r
636 ITexture* CNullDriver::createDeviceDependentTextureCubemap(const io::path& name, const core::array<IImage*>& image)
\r
638 return new SDummyTexture(name, ETT_CUBEMAP);
\r
641 bool CNullDriver::setRenderTargetEx(IRenderTarget* target, u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil)
\r
646 bool CNullDriver::setRenderTarget(ITexture* texture, u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil)
\r
650 // create render target if require.
\r
651 if (!SharedRenderTarget)
\r
652 SharedRenderTarget = addRenderTarget();
\r
654 ITexture* depthTexture = 0;
\r
656 // try to find available depth texture with require size.
\r
657 for (u32 i = 0; i < SharedDepthTextures.size(); ++i)
\r
659 if (SharedDepthTextures[i]->getSize() == texture->getSize())
\r
661 depthTexture = SharedDepthTextures[i];
\r
667 // create depth texture if require.
\r
670 depthTexture = addRenderTargetTexture(texture->getSize(), "IRR_DEPTH_STENCIL", video::ECF_D24S8);
\r
671 SharedDepthTextures.push_back(depthTexture);
\r
674 SharedRenderTarget->setTexture(texture, depthTexture);
\r
676 return setRenderTargetEx(SharedRenderTarget, clearFlag, clearColor, clearDepth, clearStencil);
\r
680 return setRenderTargetEx(0, clearFlag, clearColor, clearDepth, clearStencil);
\r
684 //! sets a viewport
\r
685 void CNullDriver::setViewPort(const core::rect<s32>& area)
\r
690 //! gets the area of the current viewport
\r
691 const core::rect<s32>& CNullDriver::getViewPort() const
\r
697 //! draws a vertex primitive list
\r
698 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
700 if ((iType==EIT_16BIT) && (vertexCount>65536))
\r
701 os::Printer::log("Too many vertices for 16bit index type, render artifacts may occur.");
\r
702 PrimitivesDrawn += primitiveCount;
\r
706 //! draws a vertex primitive list in 2d
\r
707 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
709 if ((iType==EIT_16BIT) && (vertexCount>65536))
\r
710 os::Printer::log("Too many vertices for 16bit index type, render artifacts may occur.");
\r
711 PrimitivesDrawn += primitiveCount;
\r
715 //! Draws a 3d line.
\r
716 void CNullDriver::draw3DLine(const core::vector3df& start,
\r
717 const core::vector3df& end, SColor color)
\r
722 //! Draws a 3d triangle.
\r
723 void CNullDriver::draw3DTriangle(const core::triangle3df& triangle, SColor color)
\r
725 S3DVertex vertices[3];
\r
726 vertices[0].Pos=triangle.pointA;
\r
727 vertices[0].Color=color;
\r
728 vertices[0].Normal=triangle.getNormal().normalize();
\r
729 vertices[0].TCoords.set(0.f,0.f);
\r
730 vertices[1].Pos=triangle.pointB;
\r
731 vertices[1].Color=color;
\r
732 vertices[1].Normal=vertices[0].Normal;
\r
733 vertices[1].TCoords.set(0.5f,1.f);
\r
734 vertices[2].Pos=triangle.pointC;
\r
735 vertices[2].Color=color;
\r
736 vertices[2].Normal=vertices[0].Normal;
\r
737 vertices[2].TCoords.set(1.f,0.f);
\r
738 const u16 indexList[] = {0,1,2};
\r
739 drawVertexPrimitiveList(vertices, 3, indexList, 1, EVT_STANDARD, scene::EPT_TRIANGLES, EIT_16BIT);
\r
743 //! Draws a 3d axis aligned box.
\r
744 void CNullDriver::draw3DBox(const core::aabbox3d<f32>& box, SColor color)
\r
746 core::vector3df edges[8];
\r
747 box.getEdges(edges);
\r
749 // TODO: optimize into one big drawIndexPrimitive call.
\r
751 draw3DLine(edges[5], edges[1], color);
\r
752 draw3DLine(edges[1], edges[3], color);
\r
753 draw3DLine(edges[3], edges[7], color);
\r
754 draw3DLine(edges[7], edges[5], color);
\r
755 draw3DLine(edges[0], edges[2], color);
\r
756 draw3DLine(edges[2], edges[6], color);
\r
757 draw3DLine(edges[6], edges[4], color);
\r
758 draw3DLine(edges[4], edges[0], color);
\r
759 draw3DLine(edges[1], edges[0], color);
\r
760 draw3DLine(edges[3], edges[2], color);
\r
761 draw3DLine(edges[7], edges[6], color);
\r
762 draw3DLine(edges[5], edges[4], color);
\r
767 //! draws an 2d image
\r
768 void CNullDriver::draw2DImage(const video::ITexture* texture, const core::position2d<s32>& destPos, bool useAlphaChannelOfTexture)
\r
773 draw2DImage(texture,destPos, core::rect<s32>(core::position2d<s32>(0,0),
\r
774 core::dimension2di(texture->getOriginalSize())),
\r
776 SColor(255,255,255,255),
\r
777 useAlphaChannelOfTexture
\r
783 //! draws a set of 2d images, using a color and the alpha channel of the
\r
784 //! texture if desired. The images are drawn beginning at pos and concatenated
\r
785 //! in one line. All drawings are clipped against clipRect (if != 0).
\r
786 //! The subtextures are defined by the array of sourceRects and are chosen
\r
787 //! by the indices given.
\r
788 void CNullDriver::draw2DImageBatch(const video::ITexture* texture,
\r
789 const core::position2d<s32>& pos,
\r
790 const core::array<core::rect<s32> >& sourceRects,
\r
791 const core::array<s32>& indices,
\r
793 const core::rect<s32>* clipRect, SColor color,
\r
794 bool useAlphaChannelOfTexture)
\r
796 core::position2d<s32> target(pos);
\r
798 for (u32 i=0; i<indices.size(); ++i)
\r
800 draw2DImage(texture, target, sourceRects[indices[i]],
\r
801 clipRect, color, useAlphaChannelOfTexture);
\r
802 target.X += sourceRects[indices[i]].getWidth();
\r
803 target.X += kerningWidth;
\r
807 //! draws a set of 2d images, using a color and the alpha channel of the
\r
808 //! texture if desired.
\r
809 void CNullDriver::draw2DImageBatch(const video::ITexture* texture,
\r
810 const core::array<core::position2d<s32> >& positions,
\r
811 const core::array<core::rect<s32> >& sourceRects,
\r
812 const core::rect<s32>* clipRect,
\r
814 bool useAlphaChannelOfTexture)
\r
816 const irr::u32 drawCount = core::min_<u32>(positions.size(), sourceRects.size());
\r
818 for (u32 i=0; i<drawCount; ++i)
\r
820 draw2DImage(texture, positions[i], sourceRects[i],
\r
821 clipRect, color, useAlphaChannelOfTexture);
\r
826 //! Draws a part of the texture into the rectangle.
\r
827 void CNullDriver::draw2DImage(const video::ITexture* texture, const core::rect<s32>& destRect,
\r
828 const core::rect<s32>& sourceRect, const core::rect<s32>* clipRect,
\r
829 const video::SColor* const colors, bool useAlphaChannelOfTexture)
\r
831 if (destRect.isValid())
\r
832 draw2DImage(texture, core::position2d<s32>(destRect.UpperLeftCorner),
\r
833 sourceRect, clipRect, colors?colors[0]:video::SColor(0xffffffff),
\r
834 useAlphaChannelOfTexture);
\r
838 //! 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
839 void CNullDriver::draw2DImage(const video::ITexture* texture, const core::position2d<s32>& destPos,
\r
840 const core::rect<s32>& sourceRect,
\r
841 const core::rect<s32>* clipRect, SColor color,
\r
842 bool useAlphaChannelOfTexture)
\r
847 //! Draws the outline of a 2d rectangle
\r
848 void CNullDriver::draw2DRectangleOutline(const core::recti& pos, SColor color)
\r
850 draw2DLine(pos.UpperLeftCorner, core::position2di(pos.LowerRightCorner.X, pos.UpperLeftCorner.Y), color);
\r
851 draw2DLine(core::position2di(pos.LowerRightCorner.X, pos.UpperLeftCorner.Y), pos.LowerRightCorner, color);
\r
852 draw2DLine(pos.LowerRightCorner, core::position2di(pos.UpperLeftCorner.X, pos.LowerRightCorner.Y), color);
\r
853 draw2DLine(core::position2di(pos.UpperLeftCorner.X, pos.LowerRightCorner.Y), pos.UpperLeftCorner, color);
\r
857 //! Draw a 2d rectangle
\r
858 void CNullDriver::draw2DRectangle(SColor color, const core::rect<s32>& pos, const core::rect<s32>* clip)
\r
860 draw2DRectangle(pos, color, color, color, color, clip);
\r
865 //! Draws a 2d rectangle with a gradient.
\r
866 void CNullDriver::draw2DRectangle(const core::rect<s32>& pos,
\r
867 SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown,
\r
868 const core::rect<s32>* clip)
\r
874 //! Draws a 2d line.
\r
875 void CNullDriver::draw2DLine(const core::position2d<s32>& start,
\r
876 const core::position2d<s32>& end, SColor color)
\r
881 void CNullDriver::drawPixel(u32 x, u32 y, const SColor & color)
\r
886 //! Draws a non filled concyclic regular 2d polygon.
\r
887 void CNullDriver::draw2DPolygon(core::position2d<s32> center,
\r
888 f32 radius, video::SColor color, s32 count)
\r
893 core::position2d<s32> first;
\r
894 core::position2d<s32> a,b;
\r
896 for (s32 j=0; j<count; ++j)
\r
900 f32 p = j / (f32)count * (core::PI*2);
\r
901 a = center + core::position2d<s32>((s32)(sin(p)*radius), (s32)(cos(p)*radius));
\r
906 draw2DLine(a, b, color);
\r
909 draw2DLine(a, first, color);
\r
913 //! returns color format
\r
914 ECOLOR_FORMAT CNullDriver::getColorFormat() const
\r
920 //! returns screen size
\r
921 const core::dimension2d<u32>& CNullDriver::getScreenSize() const
\r
927 //! get current render target
\r
928 IRenderTarget* CNullDriver::getCurrentRenderTarget() const
\r
930 return CurrentRenderTarget;
\r
934 const core::dimension2d<u32>& CNullDriver::getCurrentRenderTargetSize() const
\r
936 if (CurrentRenderTargetSize.Width == 0)
\r
939 return CurrentRenderTargetSize;
\r
943 // returns current frames per second value
\r
944 s32 CNullDriver::getFPS() const
\r
946 return FPSCounter.getFPS();
\r
951 //! returns amount of primitives (mostly triangles) were drawn in the last frame.
\r
952 //! very useful method for statistics.
\r
953 u32 CNullDriver::getPrimitiveCountDrawn( u32 param ) const
\r
955 return (0 == param) ? FPSCounter.getPrimitive() : (1 == param) ? FPSCounter.getPrimitiveAverage() : FPSCounter.getPrimitiveTotal();
\r
960 //! Sets the dynamic ambient light color. The default color is
\r
961 //! (0,0,0,0) which means it is dark.
\r
962 //! \param color: New color of the ambient light.
\r
963 void CNullDriver::setAmbientLight(const SColorf& color)
\r
965 AmbientLight = color;
\r
968 const SColorf& CNullDriver::getAmbientLight() const
\r
970 return AmbientLight;
\r
973 //! \return Returns the name of the video driver. Example: In case of the DIRECT3D8
\r
974 //! driver, it would return "Direct3D8".
\r
976 const wchar_t* CNullDriver::getName() const
\r
978 return L"Irrlicht NullDevice";
\r
983 //! Draws a shadow volume into the stencil buffer. To draw a stencil shadow, do
\r
984 //! this: First, draw all geometry. Then use this method, to draw the shadow
\r
985 //! volume. Then, use IVideoDriver::drawStencilShadow() to visualize the shadow.
\r
986 void CNullDriver::drawStencilShadowVolume(const core::array<core::vector3df>& triangles, bool zfail, u32 debugDataVisible)
\r
991 //! Fills the stencil shadow with color. After the shadow volume has been drawn
\r
992 //! into the stencil buffer using IVideoDriver::drawStencilShadowVolume(), use this
\r
993 //! to draw the color of the shadow.
\r
994 void CNullDriver::drawStencilShadow(bool clearStencilBuffer,
\r
995 video::SColor leftUpEdge, video::SColor rightUpEdge,
\r
996 video::SColor leftDownEdge, video::SColor rightDownEdge)
\r
1001 //! Creates a boolean alpha channel of the texture based of an color key.
\r
1002 void CNullDriver::makeColorKeyTexture(video::ITexture* texture,
\r
1003 video::SColor color,
\r
1004 bool zeroTexels) const
\r
1009 if (texture->getColorFormat() != ECF_A1R5G5B5 &&
\r
1010 texture->getColorFormat() != ECF_A8R8G8B8 )
\r
1012 os::Printer::log("Error: Unsupported texture color format for making color key channel.", ELL_ERROR);
\r
1016 if (texture->getColorFormat() == ECF_A1R5G5B5)
\r
1018 u16 *p = (u16*)texture->lock();
\r
1022 os::Printer::log("Could not lock texture for making color key channel.", ELL_ERROR);
\r
1026 const core::dimension2d<u32> dim = texture->getSize();
\r
1027 const u32 pitch = texture->getPitch() / 2;
\r
1029 // color with alpha disabled (i.e. fully transparent)
\r
1030 const u16 refZeroAlpha = (0x7fff & color.toA1R5G5B5());
\r
1032 const u32 pixels = pitch * dim.Height;
\r
1034 for (u32 pixel = 0; pixel < pixels; ++ pixel)
\r
1036 // If the color matches the reference color, ignoring alphas,
\r
1037 // set the alpha to zero.
\r
1038 if(((*p) & 0x7fff) == refZeroAlpha)
\r
1043 (*p) = refZeroAlpha;
\r
1049 texture->unlock();
\r
1053 u32 *p = (u32*)texture->lock();
\r
1057 os::Printer::log("Could not lock texture for making color key channel.", ELL_ERROR);
\r
1061 core::dimension2d<u32> dim = texture->getSize();
\r
1062 u32 pitch = texture->getPitch() / 4;
\r
1064 // color with alpha disabled (fully transparent)
\r
1065 const u32 refZeroAlpha = 0x00ffffff & color.color;
\r
1067 const u32 pixels = pitch * dim.Height;
\r
1068 for (u32 pixel = 0; pixel < pixels; ++ pixel)
\r
1070 // If the color matches the reference color, ignoring alphas,
\r
1071 // set the alpha to zero.
\r
1072 if(((*p) & 0x00ffffff) == refZeroAlpha)
\r
1077 (*p) = refZeroAlpha;
\r
1083 texture->unlock();
\r
1085 texture->regenerateMipMapLevels();
\r
1090 //! Creates an boolean alpha channel of the texture based of an color key position.
\r
1091 void CNullDriver::makeColorKeyTexture(video::ITexture* texture,
\r
1092 core::position2d<s32> colorKeyPixelPos,
\r
1093 bool zeroTexels) const
\r
1098 if (texture->getColorFormat() != ECF_A1R5G5B5 &&
\r
1099 texture->getColorFormat() != ECF_A8R8G8B8 )
\r
1101 os::Printer::log("Error: Unsupported texture color format for making color key channel.", ELL_ERROR);
\r
1107 if (texture->getColorFormat() == ECF_A1R5G5B5)
\r
1109 u16 *p = (u16*)texture->lock(ETLM_READ_ONLY);
\r
1113 os::Printer::log("Could not lock texture for making color key channel.", ELL_ERROR);
\r
1117 u32 pitch = texture->getPitch() / 2;
\r
1119 const u16 key16Bit = 0x7fff & p[colorKeyPixelPos.Y*pitch + colorKeyPixelPos.X];
\r
1121 colorKey = video::A1R5G5B5toA8R8G8B8(key16Bit);
\r
1125 u32 *p = (u32*)texture->lock(ETLM_READ_ONLY);
\r
1129 os::Printer::log("Could not lock texture for making color key channel.", ELL_ERROR);
\r
1133 u32 pitch = texture->getPitch() / 4;
\r
1134 colorKey = 0x00ffffff & p[colorKeyPixelPos.Y*pitch + colorKeyPixelPos.X];
\r
1137 texture->unlock();
\r
1138 makeColorKeyTexture(texture, colorKey, zeroTexels);
\r
1142 //! Returns the maximum amount of primitives (mostly vertices) which
\r
1143 //! the device is able to render with one drawIndexedTriangleList
\r
1145 u32 CNullDriver::getMaximalPrimitiveCount() const
\r
1147 return 0xFFFFFFFF;
\r
1151 //! checks triangle count and print warning if wrong
\r
1152 bool CNullDriver::checkPrimitiveCount(u32 prmCount) const
\r
1154 const u32 m = getMaximalPrimitiveCount();
\r
1159 snprintf_irr(tmp, sizeof(tmp), "Could not draw triangles, too many primitives(%u), maximum is %u.", prmCount, m);
\r
1160 os::Printer::log(tmp, ELL_ERROR);
\r
1167 bool CNullDriver::checkImage(const core::array<IImage*>& image) const
\r
1169 bool status = true;
\r
1171 if (image.size() > 0)
\r
1173 ECOLOR_FORMAT lastFormat = image[0]->getColorFormat();
\r
1174 core::dimension2d<u32> lastSize = image[0]->getDimension();
\r
1176 for (u32 i = 0; i < image.size() && status; ++i)
\r
1178 ECOLOR_FORMAT format = image[i]->getColorFormat();
\r
1179 core::dimension2d<u32> size = image[i]->getDimension();
\r
1188 if (!queryFeature(EVDF_TEXTURE_COMPRESSED_DXT))
\r
1190 os::Printer::log("DXT texture compression not available.", ELL_ERROR);
\r
1193 else if (size.getOptimalSize(true, false) != size)
\r
1195 os::Printer::log("Invalid size of image for DXT texture, size of image must be power of two.", ELL_ERROR);
\r
1199 case ECF_PVRTC_RGB2:
\r
1200 case ECF_PVRTC_ARGB2:
\r
1201 case ECF_PVRTC_RGB4:
\r
1202 case ECF_PVRTC_ARGB4:
\r
1203 if (!queryFeature(EVDF_TEXTURE_COMPRESSED_PVRTC))
\r
1205 os::Printer::log("PVRTC texture compression not available.", ELL_ERROR);
\r
1208 else if (size.getOptimalSize(true, false) != size)
\r
1210 os::Printer::log("Invalid size of image for PVRTC compressed texture, size of image must be power of two and squared.", ELL_ERROR);
\r
1214 case ECF_PVRTC2_ARGB2:
\r
1215 case ECF_PVRTC2_ARGB4:
\r
1216 if (!queryFeature(EVDF_TEXTURE_COMPRESSED_PVRTC2))
\r
1218 os::Printer::log("PVRTC2 texture compression not available.", ELL_ERROR);
\r
1223 if (!queryFeature(EVDF_TEXTURE_COMPRESSED_ETC1))
\r
1225 os::Printer::log("ETC1 texture compression not available.", ELL_ERROR);
\r
1229 case ECF_ETC2_RGB:
\r
1230 case ECF_ETC2_ARGB:
\r
1231 if (!queryFeature(EVDF_TEXTURE_COMPRESSED_ETC2))
\r
1233 os::Printer::log("ETC2 texture compression not available.", ELL_ERROR);
\r
1241 if (format != lastFormat || size != lastSize)
\r
1253 //! Enables or disables a texture creation flag.
\r
1254 void CNullDriver::setTextureCreationFlag(E_TEXTURE_CREATION_FLAG flag, bool enabled)
\r
1256 if (enabled && ((flag == ETCF_ALWAYS_16_BIT) || (flag == ETCF_ALWAYS_32_BIT)
\r
1257 || (flag == ETCF_OPTIMIZED_FOR_QUALITY) || (flag == ETCF_OPTIMIZED_FOR_SPEED)))
\r
1259 // disable other formats
\r
1260 setTextureCreationFlag(ETCF_ALWAYS_16_BIT, false);
\r
1261 setTextureCreationFlag(ETCF_ALWAYS_32_BIT, false);
\r
1262 setTextureCreationFlag(ETCF_OPTIMIZED_FOR_QUALITY, false);
\r
1263 setTextureCreationFlag(ETCF_OPTIMIZED_FOR_SPEED, false);
\r
1267 TextureCreationFlags = (TextureCreationFlags & (~flag)) |
\r
1268 ((((u32)!enabled)-1) & flag);
\r
1272 //! Returns if a texture creation flag is enabled or disabled.
\r
1273 bool CNullDriver::getTextureCreationFlag(E_TEXTURE_CREATION_FLAG flag) const
\r
1275 return (TextureCreationFlags & flag)!=0;
\r
1278 core::array<IImage*> CNullDriver::createImagesFromFile(const io::path& filename, E_TEXTURE_TYPE* type)
\r
1280 // TO-DO -> use 'move' feature from C++11 standard.
\r
1282 core::array<IImage*> imageArray;
\r
1284 if (filename.size() > 0)
\r
1286 io::IReadFile* file = FileSystem->createAndOpenFile(filename);
\r
1290 imageArray = createImagesFromFile(file, type);
\r
1294 os::Printer::log("Could not open file of image", filename, ELL_WARNING);
\r
1297 return imageArray;
\r
1300 core::array<IImage*> CNullDriver::createImagesFromFile(io::IReadFile* file, E_TEXTURE_TYPE* type)
\r
1302 // TO-DO -> use 'move' feature from C++11 standard.
\r
1304 core::array<IImage*> imageArray;
\r
1310 // try to load file based on file extension
\r
1311 for (i = SurfaceLoader.size() - 1; i >= 0; --i)
\r
1313 if (SurfaceLoader[i]->isALoadableFileExtension(file->getFileName()))
\r
1315 // reset file position which might have changed due to previous loadImage calls
\r
1317 imageArray = SurfaceLoader[i]->loadImages(file, type);
\r
1319 if (imageArray.size() == 0)
\r
1322 IImage* image = SurfaceLoader[i]->loadImage(file);
\r
1325 imageArray.push_back(image);
\r
1328 if (imageArray.size() > 0)
\r
1329 return imageArray;
\r
1333 // try to load file based on what is in it
\r
1334 for (i = SurfaceLoader.size() - 1; i >= 0; --i)
\r
1338 if (SurfaceLoader[i]->isALoadableFileFormat(file)
\r
1339 && !SurfaceLoader[i]->isALoadableFileExtension(file->getFileName()) // extension was tried above already
\r
1343 imageArray = SurfaceLoader[i]->loadImages(file, type);
\r
1345 if (imageArray.size() == 0)
\r
1348 IImage* image = SurfaceLoader[i]->loadImage(file);
\r
1351 imageArray.push_back(image);
\r
1354 if (imageArray.size() > 0)
\r
1355 return imageArray;
\r
1360 return imageArray;
\r
1364 //! Writes the provided image to disk file
\r
1365 bool CNullDriver::writeImageToFile(IImage* image, const io::path& filename,u32 param)
\r
1367 io::IWriteFile* file = FileSystem->createAndWriteFile(filename);
\r
1371 bool result = writeImageToFile(image, file, param);
\r
1377 //! Writes the provided image to a file.
\r
1378 bool CNullDriver::writeImageToFile(IImage* image, io::IWriteFile * file, u32 param)
\r
1383 for (s32 i=SurfaceWriter.size()-1; i>=0; --i)
\r
1385 if (SurfaceWriter[i]->isAWriteableFileExtension(file->getFileName()))
\r
1387 bool written = SurfaceWriter[i]->writeImage(file, image, param);
\r
1392 return false; // failed to write
\r
1396 //! Creates a software image from a byte array.
\r
1397 IImage* CNullDriver::createImageFromData(ECOLOR_FORMAT format,
\r
1398 const core::dimension2d<u32>& size, void *data, bool ownForeignMemory,
\r
1399 bool deleteMemory)
\r
1401 return new CImage(format, size, data, ownForeignMemory, deleteMemory);
\r
1405 //! Creates an empty software image.
\r
1406 IImage* CNullDriver::createImage(ECOLOR_FORMAT format, const core::dimension2d<u32>& size)
\r
1408 return new CImage(format, size);
\r
1412 //! Creates a software image from another image.
\r
1413 IImage* CNullDriver::createImage(ECOLOR_FORMAT format, IImage *imageToCopy)
\r
1415 os::Printer::log("Deprecated method, please create an empty image instead and use copyTo().", ELL_WARNING);
\r
1417 CImage* tmp = new CImage(format, imageToCopy->getDimension());
\r
1418 imageToCopy->copyTo(tmp);
\r
1423 //! Creates a software image from part of another image.
\r
1424 IImage* CNullDriver::createImage(IImage* imageToCopy, const core::position2d<s32>& pos, const core::dimension2d<u32>& size)
\r
1426 os::Printer::log("Deprecated method, please create an empty image instead and use copyTo().", ELL_WARNING);
\r
1427 CImage* tmp = new CImage(imageToCopy->getColorFormat(), imageToCopy->getDimension());
\r
1428 imageToCopy->copyTo(tmp, core::position2di(0,0), core::recti(pos,size));
\r
1433 //! Creates a software image from part of a texture.
\r
1434 IImage* CNullDriver::createImage(ITexture* texture, const core::position2d<s32>& pos, const core::dimension2d<u32>& size)
\r
1436 if ((pos==core::position2di(0,0)) && (size == texture->getSize()))
\r
1438 void * data = texture->lock(ETLM_READ_ONLY);
\r
1441 IImage* image = new CImage(texture->getColorFormat(), size, data, false, false);
\r
1442 texture->unlock();
\r
1447 // make sure to avoid buffer overruns
\r
1448 // make the vector a separate variable for g++ 3.x
\r
1449 const core::vector2d<u32> leftUpper(core::clamp(static_cast<u32>(pos.X), 0u, texture->getSize().Width),
\r
1450 core::clamp(static_cast<u32>(pos.Y), 0u, texture->getSize().Height));
\r
1451 const core::rect<u32> clamped(leftUpper,
\r
1452 core::dimension2du(core::clamp(static_cast<u32>(size.Width), 0u, texture->getSize().Width),
\r
1453 core::clamp(static_cast<u32>(size.Height), 0u, texture->getSize().Height)));
\r
1454 if (!clamped.isValid())
\r
1456 u8* src = static_cast<u8*>(texture->lock(ETLM_READ_ONLY));
\r
1459 IImage* image = new CImage(texture->getColorFormat(), clamped.getSize());
\r
1460 u8* dst = static_cast<u8*>(image->getData());
\r
1461 src += clamped.UpperLeftCorner.Y * texture->getPitch() + image->getBytesPerPixel() * clamped.UpperLeftCorner.X;
\r
1462 for (u32 i=0; i<clamped.getHeight(); ++i)
\r
1464 video::CColorConverter::convert_viaFormat(src, texture->getColorFormat(), clamped.getWidth(), dst, image->getColorFormat());
\r
1465 src += texture->getPitch();
\r
1466 dst += image->getPitch();
\r
1468 texture->unlock();
\r
1474 //! Sets the fog mode.
\r
1475 void CNullDriver::setFog(SColor color, E_FOG_TYPE fogType, f32 start, f32 end,
\r
1476 f32 density, bool pixelFog, bool rangeFog)
\r
1479 FogType = fogType;
\r
1482 FogDensity = density;
\r
1483 PixelFog = pixelFog;
\r
1484 RangeFog = rangeFog;
\r
1487 //! Gets the fog mode.
\r
1488 void CNullDriver::getFog(SColor& color, E_FOG_TYPE& fogType, f32& start, f32& end,
\r
1489 f32& density, bool& pixelFog, bool& rangeFog)
\r
1492 fogType = FogType;
\r
1495 density = FogDensity;
\r
1496 pixelFog = PixelFog;
\r
1497 rangeFog = RangeFog;
\r
1500 //! Draws a mesh buffer
\r
1501 void CNullDriver::drawMeshBuffer(const scene::IMeshBuffer* mb)
\r
1506 //IVertexBuffer and IIndexBuffer later
\r
1507 SHWBufferLink *HWBuffer=getBufferLink(mb);
\r
1510 drawHardwareBuffer(HWBuffer);
\r
1512 drawVertexPrimitiveList(mb->getVertices(), mb->getVertexCount(), mb->getIndices(), mb->getPrimitiveCount(), mb->getVertexType(), mb->getPrimitiveType(), mb->getIndexType());
\r
1516 //! Draws the normals of a mesh buffer
\r
1517 void CNullDriver::drawMeshBufferNormals(const scene::IMeshBuffer* mb, f32 length, SColor color)
\r
1519 const u32 count = mb->getVertexCount();
\r
1520 const bool normalize = mb->getMaterial().NormalizeNormals;
\r
1522 for (u32 i=0; i < count; ++i)
\r
1524 core::vector3df normalizedNormal = mb->getNormal(i);
\r
1526 normalizedNormal.normalize();
\r
1528 const core::vector3df& pos = mb->getPosition(i);
\r
1529 draw3DLine(pos, pos + (normalizedNormal * length), color);
\r
1534 CNullDriver::SHWBufferLink *CNullDriver::getBufferLink(const scene::IMeshBuffer* mb)
\r
1536 if (!mb || !isHardwareBufferRecommend(mb))
\r
1539 //search for hardware links
\r
1540 SHWBufferLink *HWBuffer = reinterpret_cast<SHWBufferLink*>(mb->getHWBuffer());
\r
1544 return createHardwareBuffer(mb); //no hardware links, and mesh wants one, create it
\r
1548 //! Update all hardware buffers, remove unused ones
\r
1549 void CNullDriver::updateAllHardwareBuffers()
\r
1551 auto it = HWBufferList.begin();
\r
1552 while (it != HWBufferList.end()) {
\r
1553 SHWBufferLink *Link = *it;
\r
1556 if (!Link->MeshBuffer || Link->MeshBuffer->getReferenceCount() == 1)
\r
1557 deleteHardwareBuffer(Link);
\r
1562 void CNullDriver::deleteHardwareBuffer(SHWBufferLink *HWBuffer)
\r
1566 HWBufferList.erase(HWBuffer->listPosition);
\r
1571 //! Remove hardware buffer
\r
1572 void CNullDriver::removeHardwareBuffer(const scene::IMeshBuffer* mb)
\r
1576 SHWBufferLink *HWBuffer = reinterpret_cast<SHWBufferLink*>(mb->getHWBuffer());
\r
1578 deleteHardwareBuffer(HWBuffer);
\r
1582 //! Remove all hardware buffers
\r
1583 void CNullDriver::removeAllHardwareBuffers()
\r
1585 while (!HWBufferList.empty())
\r
1586 deleteHardwareBuffer(HWBufferList.front());
\r
1590 bool CNullDriver::isHardwareBufferRecommend(const scene::IMeshBuffer* mb)
\r
1592 if (!mb || (mb->getHardwareMappingHint_Index()==scene::EHM_NEVER && mb->getHardwareMappingHint_Vertex()==scene::EHM_NEVER))
\r
1595 if (mb->getVertexCount()<MinVertexCountForVBO)
\r
1602 //! Create occlusion query.
\r
1603 /** Use node for identification and mesh for occlusion test. */
\r
1604 void CNullDriver::addOcclusionQuery(scene::ISceneNode* node, const scene::IMesh* mesh)
\r
1610 if ((node->getType() != scene::ESNT_MESH) && (node->getType() != scene::ESNT_ANIMATED_MESH))
\r
1612 else if (node->getType() == scene::ESNT_MESH)
\r
1613 mesh = static_cast<scene::IMeshSceneNode*>(node)->getMesh();
\r
1615 mesh = static_cast<scene::IAnimatedMeshSceneNode*>(node)->getMesh()->getMesh(0);
\r
1620 //search for query
\r
1621 s32 index = OcclusionQueries.linear_search(SOccQuery(node));
\r
1624 if (OcclusionQueries[index].Mesh != mesh)
\r
1626 OcclusionQueries[index].Mesh->drop();
\r
1627 OcclusionQueries[index].Mesh = mesh;
\r
1633 OcclusionQueries.push_back(SOccQuery(node, mesh));
\r
1634 node->setAutomaticCulling(node->getAutomaticCulling() | scene::EAC_OCC_QUERY);
\r
1639 //! Remove occlusion query.
\r
1640 void CNullDriver::removeOcclusionQuery(scene::ISceneNode* node)
\r
1642 //search for query
\r
1643 s32 index = OcclusionQueries.linear_search(SOccQuery(node));
\r
1646 node->setAutomaticCulling(node->getAutomaticCulling() & ~scene::EAC_OCC_QUERY);
\r
1647 OcclusionQueries.erase(index);
\r
1652 //! Remove all occlusion queries.
\r
1653 void CNullDriver::removeAllOcclusionQueries()
\r
1655 for (s32 i=OcclusionQueries.size()-1; i>=0; --i)
\r
1657 removeOcclusionQuery(OcclusionQueries[i].Node);
\r
1662 //! Run occlusion query. Draws mesh stored in query.
\r
1663 /** If the mesh shall be rendered visible, use
\r
1664 flag to enable the proper material setting. */
\r
1665 void CNullDriver::runOcclusionQuery(scene::ISceneNode* node, bool visible)
\r
1669 s32 index = OcclusionQueries.linear_search(SOccQuery(node));
\r
1672 OcclusionQueries[index].Run=0;
\r
1676 mat.Lighting=false;
\r
1677 mat.AntiAliasing=0;
\r
1678 mat.ColorMask=ECP_NONE;
\r
1679 mat.GouraudShading=false;
\r
1680 mat.ZWriteEnable=EZW_OFF;
\r
1683 setTransform(video::ETS_WORLD, node->getAbsoluteTransformation());
\r
1684 const scene::IMesh* mesh = OcclusionQueries[index].Mesh;
\r
1685 for (u32 i=0; i<mesh->getMeshBufferCount(); ++i)
\r
1688 setMaterial(mesh->getMeshBuffer(i)->getMaterial());
\r
1689 drawMeshBuffer(mesh->getMeshBuffer(i));
\r
1694 //! Run all occlusion queries. Draws all meshes stored in queries.
\r
1695 /** If the meshes shall not be rendered visible, use
\r
1696 overrideMaterial to disable the color and depth buffer. */
\r
1697 void CNullDriver::runAllOcclusionQueries(bool visible)
\r
1699 for (u32 i=0; i<OcclusionQueries.size(); ++i)
\r
1700 runOcclusionQuery(OcclusionQueries[i].Node, visible);
\r
1704 //! Update occlusion query. Retrieves results from GPU.
\r
1705 /** If the query shall not block, set the flag to false.
\r
1706 Update might not occur in this case, though */
\r
1707 void CNullDriver::updateOcclusionQuery(scene::ISceneNode* node, bool block)
\r
1712 //! Update all occlusion queries. Retrieves results from GPU.
\r
1713 /** If the query shall not block, set the flag to false.
\r
1714 Update might not occur in this case, though */
\r
1715 void CNullDriver::updateAllOcclusionQueries(bool block)
\r
1717 for (u32 i=0; i<OcclusionQueries.size(); ++i)
\r
1719 if (OcclusionQueries[i].Run==u32(~0))
\r
1721 updateOcclusionQuery(OcclusionQueries[i].Node, block);
\r
1722 ++OcclusionQueries[i].Run;
\r
1723 if (OcclusionQueries[i].Run>1000)
\r
1724 removeOcclusionQuery(OcclusionQueries[i].Node);
\r
1729 //! Return query result.
\r
1730 /** Return value is the number of visible pixels/fragments.
\r
1731 The value is a safe approximation, i.e. can be larger then the
\r
1732 actual value of pixels. */
\r
1733 u32 CNullDriver::getOcclusionQueryResult(scene::ISceneNode* node) const
\r
1739 //! Create render target.
\r
1740 IRenderTarget* CNullDriver::addRenderTarget()
\r
1746 //! Remove render target.
\r
1747 void CNullDriver::removeRenderTarget(IRenderTarget* renderTarget)
\r
1749 if (!renderTarget)
\r
1752 for (u32 i = 0; i < RenderTargets.size(); ++i)
\r
1754 if (RenderTargets[i] == renderTarget)
\r
1756 RenderTargets[i]->drop();
\r
1757 RenderTargets.erase(i);
\r
1765 //! Remove all render targets.
\r
1766 void CNullDriver::removeAllRenderTargets()
\r
1768 for (u32 i = 0; i < RenderTargets.size(); ++i)
\r
1769 RenderTargets[i]->drop();
\r
1771 RenderTargets.clear();
\r
1773 SharedRenderTarget = 0;
\r
1777 //! Only used by the internal engine. Used to notify the driver that
\r
1778 //! the window was resized.
\r
1779 void CNullDriver::OnResize(const core::dimension2d<u32>& size)
\r
1781 if (ViewPort.getWidth() == (s32)ScreenSize.Width &&
\r
1782 ViewPort.getHeight() == (s32)ScreenSize.Height)
\r
1783 ViewPort = core::rect<s32>(core::position2d<s32>(0,0),
\r
1784 core::dimension2di(size));
\r
1786 ScreenSize = size;
\r
1790 // adds a material renderer and drops it afterwards. To be used for internal creation
\r
1791 s32 CNullDriver::addAndDropMaterialRenderer(IMaterialRenderer* m)
\r
1793 s32 i = addMaterialRenderer(m);
\r
1802 //! Adds a new material renderer to the video device.
\r
1803 s32 CNullDriver::addMaterialRenderer(IMaterialRenderer* renderer, const char* name)
\r
1808 SMaterialRenderer r;
\r
1809 r.Renderer = renderer;
\r
1812 if (name == 0 && (MaterialRenderers.size() < (sizeof(sBuiltInMaterialTypeNames) / sizeof(char*))-1 ))
\r
1814 // set name of built in renderer so that we don't have to implement name
\r
1815 // setting in all available renderers.
\r
1816 r.Name = sBuiltInMaterialTypeNames[MaterialRenderers.size()];
\r
1819 MaterialRenderers.push_back(r);
\r
1822 return MaterialRenderers.size()-1;
\r
1826 //! Sets the name of a material renderer.
\r
1827 void CNullDriver::setMaterialRendererName(s32 idx, const char* name)
\r
1829 if (idx < s32(sizeof(sBuiltInMaterialTypeNames) / sizeof(char*))-1 ||
\r
1830 idx >= (s32)MaterialRenderers.size())
\r
1833 MaterialRenderers[idx].Name = name;
\r
1836 void CNullDriver::swapMaterialRenderers(u32 idx1, u32 idx2, bool swapNames)
\r
1838 if ( idx1 < MaterialRenderers.size() && idx2 < MaterialRenderers.size() )
\r
1840 irr::core::swap(MaterialRenderers[idx1].Renderer, MaterialRenderers[idx2].Renderer);
\r
1842 irr::core::swap(MaterialRenderers[idx1].Name, MaterialRenderers[idx2].Name);
\r
1847 //! Returns driver and operating system specific data about the IVideoDriver.
\r
1848 const SExposedVideoData& CNullDriver::getExposedVideoData()
\r
1850 return ExposedData;
\r
1854 //! Returns type of video driver
\r
1855 E_DRIVER_TYPE CNullDriver::getDriverType() const
\r
1861 //! deletes all material renderers
\r
1862 void CNullDriver::deleteMaterialRenders()
\r
1864 // delete material renderers
\r
1865 for (u32 i=0; i<MaterialRenderers.size(); ++i)
\r
1866 if (MaterialRenderers[i].Renderer)
\r
1867 MaterialRenderers[i].Renderer->drop();
\r
1869 MaterialRenderers.clear();
\r
1873 //! Returns pointer to material renderer or null
\r
1874 IMaterialRenderer* CNullDriver::getMaterialRenderer(u32 idx) const
\r
1876 if ( idx < MaterialRenderers.size() )
\r
1877 return MaterialRenderers[idx].Renderer;
\r
1883 //! Returns amount of currently available material renderers.
\r
1884 u32 CNullDriver::getMaterialRendererCount() const
\r
1886 return MaterialRenderers.size();
\r
1890 //! Returns name of the material renderer
\r
1891 const char* CNullDriver::getMaterialRendererName(u32 idx) const
\r
1893 if ( idx < MaterialRenderers.size() )
\r
1894 return MaterialRenderers[idx].Name.c_str();
\r
1900 //! Returns pointer to the IGPUProgrammingServices interface.
\r
1901 IGPUProgrammingServices* CNullDriver::getGPUProgrammingServices()
\r
1907 //! Adds a new material renderer to the VideoDriver, based on a high level shading language.
\r
1908 s32 CNullDriver::addHighLevelShaderMaterial(
\r
1909 const c8* vertexShaderProgram,
\r
1910 const c8* vertexShaderEntryPointName,
\r
1911 E_VERTEX_SHADER_TYPE vsCompileTarget,
\r
1912 const c8* pixelShaderProgram,
\r
1913 const c8* pixelShaderEntryPointName,
\r
1914 E_PIXEL_SHADER_TYPE psCompileTarget,
\r
1915 const c8* geometryShaderProgram,
\r
1916 const c8* geometryShaderEntryPointName,
\r
1917 E_GEOMETRY_SHADER_TYPE gsCompileTarget,
\r
1918 scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,
\r
1920 IShaderConstantSetCallBack* callback,
\r
1921 E_MATERIAL_TYPE baseMaterial,
\r
1924 os::Printer::log("High level shader materials not available (yet) in this driver, sorry");
\r
1929 //! Like IGPUProgrammingServices::addShaderMaterial() (look there for a detailed description),
\r
1930 //! but tries to load the programs from files.
\r
1931 s32 CNullDriver::addHighLevelShaderMaterialFromFiles(
\r
1932 const io::path& vertexShaderProgramFileName,
\r
1933 const c8* vertexShaderEntryPointName,
\r
1934 E_VERTEX_SHADER_TYPE vsCompileTarget,
\r
1935 const io::path& pixelShaderProgramFileName,
\r
1936 const c8* pixelShaderEntryPointName,
\r
1937 E_PIXEL_SHADER_TYPE psCompileTarget,
\r
1938 const io::path& geometryShaderProgramFileName,
\r
1939 const c8* geometryShaderEntryPointName,
\r
1940 E_GEOMETRY_SHADER_TYPE gsCompileTarget,
\r
1941 scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,
\r
1943 IShaderConstantSetCallBack* callback,
\r
1944 E_MATERIAL_TYPE baseMaterial,
\r
1947 io::IReadFile* vsfile = 0;
\r
1948 io::IReadFile* psfile = 0;
\r
1949 io::IReadFile* gsfile = 0;
\r
1951 if (vertexShaderProgramFileName.size() )
\r
1953 vsfile = FileSystem->createAndOpenFile(vertexShaderProgramFileName);
\r
1956 os::Printer::log("Could not open vertex shader program file",
\r
1957 vertexShaderProgramFileName, ELL_WARNING);
\r
1961 if (pixelShaderProgramFileName.size() )
\r
1963 psfile = FileSystem->createAndOpenFile(pixelShaderProgramFileName);
\r
1966 os::Printer::log("Could not open pixel shader program file",
\r
1967 pixelShaderProgramFileName, ELL_WARNING);
\r
1971 if (geometryShaderProgramFileName.size() )
\r
1973 gsfile = FileSystem->createAndOpenFile(geometryShaderProgramFileName);
\r
1976 os::Printer::log("Could not open geometry shader program file",
\r
1977 geometryShaderProgramFileName, ELL_WARNING);
\r
1981 s32 result = addHighLevelShaderMaterialFromFiles(
\r
1982 vsfile, vertexShaderEntryPointName, vsCompileTarget,
\r
1983 psfile, pixelShaderEntryPointName, psCompileTarget,
\r
1984 gsfile, geometryShaderEntryPointName, gsCompileTarget,
\r
1985 inType, outType, verticesOut,
\r
1986 callback, baseMaterial, userData);
\r
2001 //! Like IGPUProgrammingServices::addShaderMaterial() (look there for a detailed description),
\r
2002 //! but tries to load the programs from files.
\r
2003 s32 CNullDriver::addHighLevelShaderMaterialFromFiles(
\r
2004 io::IReadFile* vertexShaderProgram,
\r
2005 const c8* vertexShaderEntryPointName,
\r
2006 E_VERTEX_SHADER_TYPE vsCompileTarget,
\r
2007 io::IReadFile* pixelShaderProgram,
\r
2008 const c8* pixelShaderEntryPointName,
\r
2009 E_PIXEL_SHADER_TYPE psCompileTarget,
\r
2010 io::IReadFile* geometryShaderProgram,
\r
2011 const c8* geometryShaderEntryPointName,
\r
2012 E_GEOMETRY_SHADER_TYPE gsCompileTarget,
\r
2013 scene::E_PRIMITIVE_TYPE inType, scene::E_PRIMITIVE_TYPE outType,
\r
2015 IShaderConstantSetCallBack* callback,
\r
2016 E_MATERIAL_TYPE baseMaterial,
\r
2023 if (vertexShaderProgram)
\r
2025 const long size = vertexShaderProgram->getSize();
\r
2028 vs = new c8[size+1];
\r
2029 vertexShaderProgram->read(vs, size);
\r
2034 if (pixelShaderProgram)
\r
2036 const long size = pixelShaderProgram->getSize();
\r
2039 // if both handles are the same we must reset the file
\r
2040 if (pixelShaderProgram==vertexShaderProgram)
\r
2041 pixelShaderProgram->seek(0);
\r
2042 ps = new c8[size+1];
\r
2043 pixelShaderProgram->read(ps, size);
\r
2048 if (geometryShaderProgram)
\r
2050 const long size = geometryShaderProgram->getSize();
\r
2053 // if both handles are the same we must reset the file
\r
2054 if ((geometryShaderProgram==vertexShaderProgram) ||
\r
2055 (geometryShaderProgram==pixelShaderProgram))
\r
2056 geometryShaderProgram->seek(0);
\r
2057 gs = new c8[size+1];
\r
2058 geometryShaderProgram->read(gs, size);
\r
2063 s32 result = this->addHighLevelShaderMaterial(
\r
2064 vs, vertexShaderEntryPointName, vsCompileTarget,
\r
2065 ps, pixelShaderEntryPointName, psCompileTarget,
\r
2066 gs, geometryShaderEntryPointName, gsCompileTarget,
\r
2067 inType, outType, verticesOut,
\r
2068 callback, baseMaterial, userData);
\r
2078 //! Adds a new material renderer to the VideoDriver, using pixel and/or
\r
2079 //! vertex shaders to render geometry.
\r
2080 s32 CNullDriver::addShaderMaterial(const c8* vertexShaderProgram,
\r
2081 const c8* pixelShaderProgram,
\r
2082 IShaderConstantSetCallBack* callback,
\r
2083 E_MATERIAL_TYPE baseMaterial,
\r
2086 os::Printer::log("Shader materials not implemented yet in this driver, sorry.");
\r
2091 //! Like IGPUProgrammingServices::addShaderMaterial(), but tries to load the
\r
2092 //! programs from files.
\r
2093 s32 CNullDriver::addShaderMaterialFromFiles(io::IReadFile* vertexShaderProgram,
\r
2094 io::IReadFile* pixelShaderProgram,
\r
2095 IShaderConstantSetCallBack* callback,
\r
2096 E_MATERIAL_TYPE baseMaterial,
\r
2102 if (vertexShaderProgram)
\r
2104 const long size = vertexShaderProgram->getSize();
\r
2107 vs = new c8[size+1];
\r
2108 vertexShaderProgram->read(vs, size);
\r
2113 if (pixelShaderProgram)
\r
2115 const long size = pixelShaderProgram->getSize();
\r
2118 ps = new c8[size+1];
\r
2119 pixelShaderProgram->read(ps, size);
\r
2124 s32 result = addShaderMaterial(vs, ps, callback, baseMaterial, userData);
\r
2133 //! Like IGPUProgrammingServices::addShaderMaterial(), but tries to load the
\r
2134 //! programs from files.
\r
2135 s32 CNullDriver::addShaderMaterialFromFiles(const io::path& vertexShaderProgramFileName,
\r
2136 const io::path& pixelShaderProgramFileName,
\r
2137 IShaderConstantSetCallBack* callback,
\r
2138 E_MATERIAL_TYPE baseMaterial,
\r
2141 io::IReadFile* vsfile = 0;
\r
2142 io::IReadFile* psfile = 0;
\r
2144 if (vertexShaderProgramFileName.size())
\r
2146 vsfile = FileSystem->createAndOpenFile(vertexShaderProgramFileName);
\r
2149 os::Printer::log("Could not open vertex shader program file",
\r
2150 vertexShaderProgramFileName, ELL_WARNING);
\r
2155 if (pixelShaderProgramFileName.size())
\r
2157 psfile = FileSystem->createAndOpenFile(pixelShaderProgramFileName);
\r
2160 os::Printer::log("Could not open pixel shader program file",
\r
2161 pixelShaderProgramFileName, ELL_WARNING);
\r
2168 s32 result = addShaderMaterialFromFiles(vsfile, psfile, callback,
\r
2169 baseMaterial, userData);
\r
2181 //! Creates a render target texture.
\r
2182 ITexture* CNullDriver::addRenderTargetTexture(const core::dimension2d<u32>& size,
\r
2183 const io::path&name, const ECOLOR_FORMAT format)
\r
2188 ITexture* CNullDriver::addRenderTargetTextureCubemap(const irr::u32 sideLen,
\r
2189 const io::path& name, const ECOLOR_FORMAT format)
\r
2194 void CNullDriver::clearBuffers(u16 flag, SColor color, f32 depth, u8 stencil)
\r
2199 //! Returns a pointer to the mesh manipulator.
\r
2200 scene::IMeshManipulator* CNullDriver::getMeshManipulator()
\r
2202 return MeshManipulator;
\r
2206 //! Returns an image created from the last rendered frame.
\r
2207 IImage* CNullDriver::createScreenShot(video::ECOLOR_FORMAT format, video::E_RENDER_TARGET target)
\r
2213 // prints renderer version
\r
2214 void CNullDriver::printVersion()
\r
2216 core::stringw namePrint = L"Using renderer: ";
\r
2217 namePrint += getName();
\r
2218 os::Printer::log(namePrint.c_str(), ELL_INFORMATION);
\r
2222 //! creates a video driver
\r
2223 IVideoDriver* createNullDriver(io::IFileSystem* io, const core::dimension2d<u32>& screenSize)
\r
2225 CNullDriver* nullDriver = new CNullDriver(io, screenSize);
\r
2227 // create empty material renderers
\r
2228 for(u32 i=0; sBuiltInMaterialTypeNames[i]; ++i)
\r
2230 IMaterialRenderer* imr = new IMaterialRenderer();
\r
2231 nullDriver->addMaterialRenderer(imr);
\r
2235 return nullDriver;
\r
2239 //! Set/unset a clipping plane.
\r
2240 //! There are at least 6 clipping planes available for the user to set at will.
\r
2241 //! \param index: The plane index. Must be between 0 and MaxUserClipPlanes.
\r
2242 //! \param plane: The plane itself.
\r
2243 //! \param enable: If true, enable the clipping plane else disable it.
\r
2244 bool CNullDriver::setClipPlane(u32 index, const core::plane3df& plane, bool enable)
\r
2250 //! Enable/disable a clipping plane.
\r
2251 void CNullDriver::enableClipPlane(u32 index, bool enable)
\r
2257 ITexture* CNullDriver::createRenderTargetTexture(const core::dimension2d<u32>& size,
\r
2260 os::Printer::log("createRenderTargetTexture is deprecated, use addRenderTargetTexture instead");
\r
2261 ITexture* tex = addRenderTargetTexture(size, name);
\r
2267 void CNullDriver::setMinHardwareBufferVertexCount(u32 count)
\r
2269 MinVertexCountForVBO = count;
\r
2273 SOverrideMaterial& CNullDriver::getOverrideMaterial()
\r
2275 return OverrideMaterial;
\r
2279 //! Get the 2d override material for altering its values
\r
2280 SMaterial& CNullDriver::getMaterial2D()
\r
2282 return OverrideMaterial2D;
\r
2286 //! Enable the 2d override material
\r
2287 void CNullDriver::enableMaterial2D(bool enable)
\r
2289 OverrideMaterial2DEnabled=enable;
\r
2293 core::dimension2du CNullDriver::getMaxTextureSize() const
\r
2295 return core::dimension2du(0x10000,0x10000); // maybe large enough
\r
2298 bool CNullDriver::needsTransparentRenderPass(const irr::video::SMaterial& material) const
\r
2300 // TODO: I suspect it would be nice if the material had an enum for further control.
\r
2301 // Especially it probably makes sense to allow disabling transparent render pass as soon as material.ZWriteEnable is on.
\r
2302 // 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
2303 // Or we could at least set return false when material.ZWriteEnable is EZW_ON? Still considering that...
\r
2304 // Be careful - this function is deeply connected to getWriteZBuffer as transparent render passes are usually about rendering with
\r
2305 // zwrite disabled and getWriteZBuffer calls this function.
\r
2307 video::IMaterialRenderer* rnd = getMaterialRenderer(material.MaterialType);
\r
2308 // TODO: I suspect IMaterialRenderer::isTransparent also often could use SMaterial as parameter
\r
2309 // We could for example then get rid of IsTransparent function in SMaterial and move that to the software material renderer.
\r
2310 if (rnd && rnd->isTransparent())
\r
2317 //! Color conversion convenience function
\r
2318 /** Convert an image (as array of pixels) from source to destination
\r
2319 array, thereby converting the color format. The pixel size is
\r
2320 determined by the color formats.
\r
2321 \param sP Pointer to source
\r
2322 \param sF Color format of source
\r
2323 \param sN Number of pixels to convert, both array must be large enough
\r
2324 \param dP Pointer to destination
\r
2325 \param dF Color format of destination
\r
2327 void CNullDriver::convertColor(const void* sP, ECOLOR_FORMAT sF, s32 sN,
\r
2328 void* dP, ECOLOR_FORMAT dF) const
\r
2330 video::CColorConverter::convert_viaFormat(sP, sF, sN, dP, dF);
\r
2334 } // end namespace
\r
2335 } // end namespace
\r