Add IFileSystem::createMemoryWriteFile() to allow writing to memory.
Replace CMemoryReadFile with CMemoryFile that also implement IWriteFile.
Add an IVideoDriver::writeImageToFile() overload that takes an IWriteFile.
This allows writing (e.g.) screenshots to memory, rather than directly to file.

New unit test added to test the new functionality.  Tested on Windows with VS2005 and C::B. I'll do Linux ASAP.

git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@2081 dfc29bdd-3216-0410-991c-e03cc46cb475
master
Rogerborg 2009-01-16 14:19:38 +00:00
parent 90eec5ade9
commit a603abe03a
23 changed files with 285 additions and 48 deletions

View File

@ -1,5 +1,11 @@
Changes in version 1.6
- Added IFileSystem::createMemoryWriteFile() to allow creation of an IWriteFile interface that uses an application supplied memory buffer.
- Added an IVideoDriver::writeImageToFile() overload that can take an IWriteFile interface.
- (Internal) Replaced CMemoryReadFile with CMemoryFile, that also implements an IWriteFile interface.
- Added an optional light manager to the scene manager to allow the user application to turn lights on and off during scene rendering. This can be used to produce "zoned" lighting. See example 20.ManagedLights.
- Added a method to flip the Y movement of the FPS camera.

View File

@ -52,6 +52,21 @@ public:
*/
virtual IReadFile* createMemoryReadFile(void* memory, s32 len, const c8* fileName, bool deleteMemoryWhenDropped=false) = 0;
//! Creates an IWriteFile interface for accessing memory like a file.
/** This allows you to use a pointer to memory where an IWriteFile is requested.
You are responsible for allocating enough memory.
\param memory: A pointer to the start of the file in memory (allocated by you)
\param len: The length of the memory in bytes
\param fileName: The name given to this file
\param deleteMemoryWhenDropped: True if the memory should be deleted
along with the IWriteFile when it is dropped.
\return Returns a pointer to the created file interface.
The returned pointer should be dropped when no longer needed.
See IReferenceCounted::drop() for more information.
*/
virtual IWriteFile* createMemoryWriteFile(void* memory, s32 len, const c8* fileName, bool deleteMemoryWhenDropped=false) = 0;
//! Opens a file for write access.
/** \param filename: Name of file to open.
\param append: If the file already exist, all write operations are

View File

@ -25,6 +25,7 @@ namespace io
{
class IAttributes;
class IReadFile;
class IWriteFile;
} // end namespace io
namespace scene
{
@ -834,6 +835,19 @@ namespace video
\return True on successful write. */
virtual bool writeImageToFile(IImage* image, const c8* filename, u32 param = 0) = 0;
//! Writes the provided image to a file.
/** Requires that there is a suitable image writer registered
for writing the image.
\param image Image to write.
\param file An already open io::IWriteFile object
\param extension A file extension that will identify the desired image
writer, e.g. ".jpg"
\param param Control parameter for the backend (e.g. compression
level).
\return True on successful write. */
virtual bool writeImageToFile(IImage* image, io::IWriteFile* file,
const c8* extension, u32 param = 0) = 0;
//! Creates a software image from a byte array.
/** No hardware texture will be created for this image. This
method is useful for example if you want to read a heightmap

View File

@ -14,7 +14,7 @@
#include "os.h"
#include "IrrCompileConfig.h"
#include "CAttributes.h"
#include "CMemoryReadFile.h"
#include "CMemoryFile.h"
#if defined (_IRR_WINDOWS_API_)
#if !defined ( _WIN32_WCE )
@ -97,7 +97,17 @@ IReadFile* CFileSystem::createMemoryReadFile(void* memory, s32 len,
if (!memory)
return 0;
else
return new CMemoryReadFile(memory, len, fileName, deleteMemoryWhenDropped);
return new CMemoryFile(memory, len, fileName, deleteMemoryWhenDropped);
}
//! Creates an IReadFile interface for treating memory like a file.
IWriteFile* CFileSystem::createMemoryWriteFile(void* memory, s32 len,
const c8* fileName, bool deleteMemoryWhenDropped)
{
if (!memory)
return 0;
else
return new CMemoryFile(memory, len, fileName, deleteMemoryWhenDropped);
}

View File

@ -37,6 +37,9 @@ public:
//! Creates an IReadFile interface for accessing memory like a file.
virtual IReadFile* createMemoryReadFile(void* memory, s32 len, const c8* fileName, bool deleteMemoryWhenDropped = false);
//! Creates an IWriteFile interface for accessing memory like a file.
virtual IWriteFile* createMemoryWriteFile(void* memory, s32 len, const c8* fileName, bool deleteMemoryWhenDropped=false);
//! Opens a file for write access.
virtual IWriteFile* createAndWriteFile(const c8* filename, bool append=false);

View File

@ -1,8 +1,8 @@
// Copyright (C) 2002-2009 Nikolaus Gebhardt
// Copyright (C) 2002-2008 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CMemoryReadFile.h"
#include "CMemoryFile.h"
#include "irrString.h"
namespace irr
@ -11,16 +11,16 @@ namespace io
{
CMemoryReadFile::CMemoryReadFile(void* memory, long len, const c8* fileName, bool d)
CMemoryFile::CMemoryFile(void* memory, long len, const c8* fileName, bool d)
: Buffer(memory), Len(len), Pos(0), Filename(fileName), deleteMemoryWhenDropped(d)
{
#ifdef _DEBUG
setDebugName("CMemoryReadFile");
setDebugName("CMemoryFile");
#endif
}
CMemoryReadFile::~CMemoryReadFile()
CMemoryFile::~CMemoryFile()
{
if (deleteMemoryWhenDropped)
delete [] (c8*)Buffer;
@ -28,7 +28,7 @@ CMemoryReadFile::~CMemoryReadFile()
//! returns how much was read
s32 CMemoryReadFile::read(void* buffer, u32 sizeToRead)
s32 CMemoryFile::read(void* buffer, u32 sizeToRead)
{
s32 amount = static_cast<s32>(sizeToRead);
if (Pos + amount > Len)
@ -45,11 +45,30 @@ s32 CMemoryReadFile::read(void* buffer, u32 sizeToRead)
return amount;
}
//! returns how much was written
s32 CMemoryFile::write(const void* buffer, u32 sizeToWrite)
{
s32 amount = static_cast<s32>(sizeToWrite);
if (Pos + amount > Len)
amount -= Pos + amount - Len;
if (amount <= 0)
return 0;
c8* p = (c8*)Buffer;
memcpy(p + Pos, buffer, amount);
Pos += amount;
return amount;
}
//! changes position in file, returns true if successful
//! if relativeMovement==true, the pos is changed relative to current pos,
//! otherwise from begin of file
bool CMemoryReadFile::seek(long finalPos, bool relativeMovement)
bool CMemoryFile::seek(long finalPos, bool relativeMovement)
{
if (relativeMovement)
{
@ -71,21 +90,21 @@ bool CMemoryReadFile::seek(long finalPos, bool relativeMovement)
//! returns size of file
long CMemoryReadFile::getSize() const
long CMemoryFile::getSize() const
{
return Len;
}
//! returns where in the file we are.
long CMemoryReadFile::getPos() const
long CMemoryFile::getPos() const
{
return Pos;
}
//! returns name of file
const c8* CMemoryReadFile::getFileName() const
const c8* CMemoryFile::getFileName() const
{
return Filename.c_str();
}
@ -93,7 +112,7 @@ const c8* CMemoryReadFile::getFileName() const
IReadFile* createMemoryReadFile(void* memory, long size, const c8* fileName, bool deleteMemoryWhenDropped)
{
CMemoryReadFile* file = new CMemoryReadFile(memory, size, fileName, deleteMemoryWhenDropped);
CMemoryFile* file = new CMemoryFile(memory, size, fileName, deleteMemoryWhenDropped);
return file;
}

View File

@ -1,4 +1,4 @@
// Copyright (C) 2002-2009 Nikolaus Gebhardt
// Copyright (C) 2002-2008 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
@ -6,6 +6,7 @@
#define __C_MEMORY_READ_FILE_H_INCLUDED__
#include "IReadFile.h"
#include "IWriteFile.h"
#include "irrString.h"
namespace irr
@ -15,21 +16,24 @@ namespace io
{
/*!
Class for reading from memory.
Class for reading and writing from memory.
*/
class CMemoryReadFile : public IReadFile
class CMemoryFile : public IReadFile, public IWriteFile
{
public:
//! Constructor
CMemoryReadFile(void* memory, long len, const c8* fileName, bool deleteMemoryWhenDropped);
CMemoryFile(void* memory, long len, const c8* fileName, bool deleteMemoryWhenDropped);
//! Destructor
virtual ~CMemoryReadFile();
virtual ~CMemoryFile();
//! returns how much was read
virtual s32 read(void* buffer, u32 sizeToRead);
//! returns how much was written
virtual s32 write(const void* buffer, u32 sizeToWrite);
//! changes position in file, returns true if successful
virtual bool seek(long finalPos, bool relativeMovement = false);

View File

@ -1244,18 +1244,29 @@ IImage* CNullDriver::createImageFromFile(io::IReadFile* file)
//! Writes the provided image to disk file
bool CNullDriver::writeImageToFile(IImage* image, const char* filename,u32 param)
{
io::IWriteFile* file = FileSystem->createAndWriteFile(filename);
if(!file)
return false;
bool result = writeImageToFile(image, file, filename, param);
file->drop();
return result;
}
//! Writes the provided image to a file.
bool CNullDriver::writeImageToFile(IImage* image, io::IWriteFile * file, const c8* extension, u32 param)
{
if(!file)
return false;
for (u32 i=0; i<SurfaceWriter.size(); ++i)
{
if (SurfaceWriter[i]->isAWriteableFileExtension(filename))
if (SurfaceWriter[i]->isAWriteableFileExtension(extension))
{
io::IWriteFile* file = FileSystem->createAndWriteFile(filename);
if (file)
{
bool written = SurfaceWriter[i]->writeImage(file, image, param);
file->drop();
if (written)
return true;
}
bool written = SurfaceWriter[i]->writeImage(file, image, param);
if (written)
return true;
}
}
return false; // failed to write

View File

@ -488,6 +488,9 @@ namespace video
//! Writes the provided image to disk file
virtual bool writeImageToFile(IImage* image, const char* filename, u32 param = 0);
//! Writes the provided image to a file.
virtual bool writeImageToFile(IImage* image, io::IWriteFile * file, const c8* extension, u32 param = 0);
//! Sets the name of a material renderer.
virtual void setMaterialRendererName(s32 idx, const char* name);

View File

@ -537,8 +537,8 @@
<Unit filename="CMY3DHelper.h" />
<Unit filename="CMY3DMeshFileLoader.cpp" />
<Unit filename="CMY3DMeshFileLoader.h" />
<Unit filename="CMemoryReadFile.cpp" />
<Unit filename="CMemoryReadFile.h" />
<Unit filename="CMemoryFile.cpp" />
<Unit filename="CMemoryFile.h" />
<Unit filename="CMeshCache.cpp" />
<Unit filename="CMeshCache.h" />
<Unit filename="CMeshManipulator.cpp" />

View File

@ -2840,7 +2840,7 @@ OverrideBuildCmd=0
BuildCmd=
[Unit282]
FileName=CMemoryReadFile.cpp
FileName=CMemoryFile.cpp
Folder=io_impl
Compile=1
CompileCpp=1
@ -2850,7 +2850,7 @@ OverrideBuildCmd=0
BuildCmd=
[Unit283]
FileName=CMemoryReadFile.h
FileName=CMemoryFile.h
Folder=io_impl
Compile=1
CompileCpp=1

View File

@ -1995,10 +1995,10 @@
RelativePath=".\CLimitReadFile.h">
</File>
<File
RelativePath=".\CMemoryReadFile.cpp">
RelativePath=".\CMemoryFile.cpp">
</File>
<File
RelativePath=".\CMemoryReadFile.h">
RelativePath=".\CMemoryFile.h">
</File>
<File
RelativePath=".\CPakReader.cpp">

View File

@ -2191,11 +2191,11 @@
>
</File>
<File
RelativePath="CDummyTransformationSceneNode.cpp"
RelativePath=".\CDummyTransformationSceneNode.cpp"
>
</File>
<File
RelativePath="CDummyTransformationSceneNode.h"
RelativePath=".\CDummyTransformationSceneNode.h"
>
</File>
<File
@ -2596,11 +2596,11 @@
>
</File>
<File
RelativePath="CMemoryReadFile.cpp"
RelativePath=".\CMemoryFile.cpp"
>
</File>
<File
RelativePath="CMemoryReadFile.h"
RelativePath=".\CMemoryFile.h"
>
</File>
<File

View File

@ -2675,11 +2675,11 @@
>
</File>
<File
RelativePath="CMemoryReadFile.cpp"
RelativePath="CMemoryFile.cpp"
>
</File>
<File
RelativePath="CMemoryReadFile.h"
RelativePath="CMemoryFile.h"
>
</File>
<File

View File

@ -7,7 +7,7 @@
// Other builds must link against it in the project files.
#if defined(_MSC_VER)
#pragma comment(lib, "Irrlicht.lib")
#define _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS 1
#endif // _MSC_VER
#include "testUtils.h"
@ -86,6 +86,7 @@ int main(int argumentCount, char * arguments[])
TEST(matrixOps);
TEST(sceneNodeAnimator);
TEST(vectorPositionDimension2d);
TEST(writeImageToFile);
const unsigned int numberOfTests = tests.size();

View File

@ -1,7 +1,10 @@
// Copyright (C) 2008-2009 Colin MacDonald
// No rights reserved: this software is in the public domain.
#define _CRT_SECURE_NO_WARNINGS
#if defined(_MSC_VER)
#define _CRT_SECURE_NO_WARNINGS 1
#endif // _MSC_VER
#include "testUtils.h"
#include <memory.h>
#include <stdio.h>
@ -41,9 +44,12 @@ bool binaryCompareFiles(const char * fileName1, const char * fileName2)
(void)fseek(file1, 0, SEEK_END);
(void)fseek(file2, 0, SEEK_END);
if(ftell(file1) != ftell(file2))
const size_t file1Size = ftell(file1);
const size_t file2Size = ftell(file2);
if(file1Size != file2Size)
{
logTestString("binaryCompareFiles: Files are different sizes\n");
logTestString("binaryCompareFiles: Files are different sizes: %d vs %d\n",
file1Size, file2Size);
(void)fclose(file1);
(void)fclose(file2);
return false;

View File

@ -2,12 +2,16 @@
#ifndef _TEST_UTILS_H_
#define _TEST_UTILS_H_ 1
#include "irrlicht.h"
#if defined(_WIN32) || defined(_WIN64) || defined(WIN32) || defined(WIN64) || defined(_WIN32_WCE)
#define TESTING_ON_WINDOWS
#define DIR_SEP_STRING "\\"
#else
#define DIR_SEP_STRING "/"
#endif
#include "irrlicht.h"
//! Compare two files
/** \param fileName1 The first file for comparison.
\param fileName1 The second file for comparison.

View File

@ -1,2 +1,2 @@
Test suite pass at GMT Mon Jan 12 10:46:46 2009
Test suite pass at GMT Fri Jan 16 14:15:51 2009

View File

@ -46,8 +46,8 @@
<Unit filename="drawRectOutline.cpp" />
<Unit filename="exports.cpp" />
<Unit filename="fast_atof.cpp" />
<Unit filename="irrCoreEquals.cpp" />
<Unit filename="guiDisabledMenu.cpp" />
<Unit filename="irrCoreEquals.cpp" />
<Unit filename="line2dIntersectWith.cpp" />
<Unit filename="main.cpp" />
<Unit filename="makeColorKeyTexture.cpp" />
@ -65,6 +65,7 @@
<Unit filename="textureRenderStates.cpp" />
<Unit filename="transparentAlphaChannelRef.cpp" />
<Unit filename="vectorPositionDimension2d.cpp" />
<Unit filename="writeImageToFile.cpp" />
<Extensions>
<code_completion />
<debugger />

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<CodeBlocks_workspace_file>
<Workspace title="tests">
<Project filename="..\source\Irrlicht\Irrlicht-gcc.cbp" />
<Project filename="tests.cbp" active="1" />
<Project filename="..\source\Irrlicht\Irrlicht-gcc.cbp" />
</Workspace>
</CodeBlocks_workspace_file>

View File

@ -281,6 +281,10 @@
RelativePath=".\vectorPositionDimension2d.cpp"
>
</File>
<File
RelativePath=".\writeImageToFile.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"

View File

@ -279,6 +279,10 @@
RelativePath=".\vectorPositionDimension2d.cpp"
>
</File>
<File
RelativePath=".\writeImageToFile.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"

132
tests/writeImageToFile.cpp Normal file
View File

@ -0,0 +1,132 @@
// Copyright (C) 2009 Colin MacDonald
// No rights reserved: this software is in the public domain.
#if defined(_MSC_VER)
#define _CRT_SECURE_NO_WARNINGS 1
#endif // _MSC_VER
#include "irrlicht.h"
#include "testUtils.h"
#include <assert.h>
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
//! Tests IVideoDriver::writeImageToFile() using IWriteFile
bool writeImageToFile(void)
{
IrrlichtDevice *device = createDevice( EDT_BURNINGSVIDEO, dimension2d<s32>(160, 120), 32);
if (!device)
return true; // Treat a failure to create a driver as benign; this saves a lot of #ifdefs
IVideoDriver* driver = device->getVideoDriver();
ISceneManager * smgr = device->getSceneManager();
// Draw a cube background so that we can check that the pixels' alpha is working.
ISceneNode * cube = smgr->addCubeSceneNode(50.f, 0, -1, vector3df(0, 0, 60));
cube->setMaterialTexture(0, driver->getTexture("../media/wall.bmp"));
cube->setMaterialFlag(video::EMF_LIGHTING, false);
(void)smgr->addCameraSceneNode();
driver->beginScene(true, true, SColor(255,100,101,140));
smgr->drawAll();
// Test for benign handling of offscreen pixel values as well as onscreen ones.
for(s32 x = -10; x < 170; ++x)
{
s32 y = 120 * x / 160;
driver->drawPixel((u32)x, (u32)y, SColor(255, 255 * x / 640, 255 * (640 - x) / 640, 0));
y = 120 - y;
driver->drawPixel((u32)x, (u32)y, SColor(255 * x / 640, 0, 255, 255));
}
driver->endScene();
bool result = false;
IWriteFile * writtenFile = 0;
IWriteFile * memoryFile = 0;
const char * writtenFilename = 0;
const u32 BUFFER_SIZE = 160 * 120 * 4;
c8 * buffer = 0;
const char * referenceFilename = 0;
irr::video::IImage * screenshot = driver->createScreenShot();
if(!screenshot)
{
logTestString("Failed to take screenshot\n");
assert(false);
goto cleanup;
}
const video::ECOLOR_FORMAT format = screenshot->getColorFormat();
if(format != video::ECF_R8G8B8)
{
irr::video::IImage * fixedScreenshot = driver->createImage(video::ECF_R8G8B8, screenshot);
screenshot->drop();
if(!fixedScreenshot)
{
logTestString("Failed to convert screenshot to ECF_A8R8G8B8\n");
assert(false);
goto cleanup;
}
screenshot = fixedScreenshot;
}
buffer = new c8[BUFFER_SIZE];
memoryFile = device->getFileSystem()->createMemoryWriteFile(buffer, BUFFER_SIZE, "foo", false);
if(!driver->writeImageToFile(screenshot, memoryFile, ".png"))
{
logTestString("Failed to write png to memory file\n");
assert(false);
goto cleanup;
}
writtenFilename = "results" DIR_SEP_STRING "burnings video 0.39b-drawPixel.png";
writtenFile = device->getFileSystem()->createAndWriteFile(writtenFilename);
if(!writtenFile)
{
logTestString("Can't open %s for writing.\n", writtenFilename);
assert(false);
goto cleanup;
}
if(memoryFile->getPos() != writtenFile->write(buffer, memoryFile->getPos()))
{
logTestString("Error while writing to %s.\n", writtenFilename);
assert(false);
goto cleanup;
}
writtenFile->drop();
writtenFile = 0;
referenceFilename = "media" DIR_SEP_STRING "burnings video 0.39b-drawPixel.png";
if(!binaryCompareFiles(writtenFilename, referenceFilename))
{
logTestString("File written from memory is not the same as the reference file.\n");
assert(false);
goto cleanup;
}
result = true;
cleanup:
if(writtenFile)
writtenFile->drop();
if(memoryFile)
memoryFile->drop();
delete [] buffer;
device->drop();
return result;
}