Merging r5975 through r6036 from trunk to ogl-es branch.

GLES drivers adapted, but only did make compile-tests.


git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/branches/ogl-es@6038 dfc29bdd-3216-0410-991c-e03cc46cb475
This commit is contained in:
cutealien
2020-01-03 19:05:16 +00:00
commit 2ae2a551a6
2007 changed files with 635880 additions and 0 deletions

View File

@ -0,0 +1,110 @@
// Copyright (C) 2002-2011 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_ANDROID_ASSET_READER_
#include "CAndroidAssetReader.h"
#include "CReadFile.h"
#include "coreutil.h"
#include "CAndroidAssetFileArchive.h"
#include "CIrrDeviceAndroid.h"
#include "os.h" // for logging (just keep it in even when not needed right now as it's used all the time)
#include <android_native_app_glue.h>
#include <android/native_activity.h>
#include <android/log.h>
namespace irr
{
namespace io
{
CAndroidAssetFileArchive::CAndroidAssetFileArchive(AAssetManager *assetManager, bool ignoreCase, bool ignorePaths)
: CFileList("/asset", ignoreCase, ignorePaths), AssetManager(assetManager)
{
}
CAndroidAssetFileArchive::~CAndroidAssetFileArchive()
{
}
//! get the archive type
E_FILE_ARCHIVE_TYPE CAndroidAssetFileArchive::getType() const
{
return EFAT_ANDROID_ASSET;
}
const IFileList* CAndroidAssetFileArchive::getFileList() const
{
// The assert_manager can not read directory names, so
// getFileList returns only files in folders which have been added.
return this;
}
//! opens a file by file name
IReadFile* CAndroidAssetFileArchive::createAndOpenFile(const io::path& filename)
{
CAndroidAssetReader *reader = new CAndroidAssetReader(AssetManager, filename);
if(reader->isOpen())
return reader;
reader->drop();
return NULL;
}
//! opens a file by index
IReadFile* CAndroidAssetFileArchive::createAndOpenFile(u32 index)
{
const io::path& filename(getFullFileName(index));
if ( filename.empty() )
return 0;
return createAndOpenFile(filename);
}
void CAndroidAssetFileArchive::addDirectoryToFileList(const io::path &dirname_)
{
io::path dirname(dirname_);
fschar_t lastChar = dirname.lastChar();
if ( lastChar == '/' || lastChar == '\\' )
dirname.erase(dirname.size()-1);
// os::Printer::log("addDirectoryToFileList:", dirname.c_str(), ELL_DEBUG);
if (findFile(dirname, true) >= 0 )
return; // was already added
AAssetDir *dir = AAssetManager_openDir(AssetManager, core::stringc(dirname).c_str());
if(!dir)
return;
// add directory itself
addItem(dirname, 0, 0, /*isDir*/true, getFileCount());
// add all files in folder.
// Note: AAssetDir_getNextFileName does not return directory names (neither does any other NDK function)
while(const char *filename = AAssetDir_getNextFileName(dir))
{
core::stringc full_filename= dirname=="" ? filename
: dirname+"/"+filename;
// We can't get the size without opening the file - so for performance
// reasons we set the file size to 0.
// TODO: Does this really cost so much performance that it's worth losing this information? Dirs are usually just added once at startup...
addItem(full_filename, /*offet*/0, /*size*/0, /*isDir*/false, getFileCount());
// os::Printer::log("addItem:", full_filename.c_str(), ELL_DEBUG);
}
AAssetDir_close(dir);
}
} // end namespace io
} // end namespace irr
#endif // _IRR_COMPILE_ANDROID_ASSET_READER_

View File

@ -0,0 +1,70 @@
// Copyright (C) 2012 Joerg Henrichs
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_ANDROID_ASSET_FILE_ARCHIVE_H_INCLUDED__
#define __C_ANDROID_ASSET_FILE_ARCHIVE_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_ANDROID_ASSET_READER_
#include "IReadFile.h"
#include "IFileArchive.h"
#include "CFileList.h"
#include <android/native_activity.h>
namespace irr
{
namespace io
{
/*!
Android asset file system written August 2012 by J.Henrichs (later reworked by others).
*/
class CAndroidAssetFileArchive : public virtual IFileArchive,
virtual CFileList
{
public:
//! constructor
CAndroidAssetFileArchive(AAssetManager *assetManager, bool ignoreCase, bool ignorePaths);
//! destructor
virtual ~CAndroidAssetFileArchive();
//! opens a file by file name
virtual IReadFile* createAndOpenFile(const io::path& filename);
//! opens a file by index
virtual IReadFile* createAndOpenFile(u32 index);
//! returns the list of files
virtual const IFileList* getFileList() const;
//! get the archive type
virtual E_FILE_ARCHIVE_TYPE getType() const;
//! Add a directory to read files from. Since the Android
//! API does not return names of directories, they need to
//! be added manually.
virtual void addDirectoryToFileList(const io::path &filename);
//! return the name (id) of the file Archive
virtual const io::path& getArchiveName() const _IRR_OVERRIDE_ {return Path;}
protected:
//! Android's asset manager
AAssetManager *AssetManager;
}; // CAndroidAssetFileArchive
} // end namespace io
} // end namespace irr
#endif // _IRR_COMPILE_ANDROID_ASSET_READER_
#endif // __C_ANDROID_ASSET_READER_H_INCLUDED__

View File

@ -0,0 +1,73 @@
// Copyright (C) 2002-2011 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_ANDROID_ASSET_READER_
#include "CAndroidAssetReader.h"
#include "CReadFile.h"
#include "coreutil.h"
#include "CAndroidAssetReader.h"
#include "CIrrDeviceAndroid.h"
#include <android_native_app_glue.h>
#include <android/native_activity.h>
namespace irr
{
namespace io
{
CAndroidAssetReader::CAndroidAssetReader(AAssetManager *assetManager, const io::path &filename)
: AssetManager(assetManager), Filename(filename)
{
Asset = AAssetManager_open(AssetManager,
core::stringc(filename).c_str(),
AASSET_MODE_RANDOM);
}
CAndroidAssetReader::~CAndroidAssetReader()
{
if(Asset)
AAsset_close(Asset);
}
size_t CAndroidAssetReader::read(void* buffer, size_t sizeToRead)
{
int readBytes = AAsset_read(Asset, buffer, sizeToRead);
if ( readBytes >= 0 )
return size_t(readBytes);
return 0; // direct fd access is not possible (for example, if the asset is compressed).
}
bool CAndroidAssetReader::seek(long finalPos, bool relativeMovement)
{
off_t status = AAsset_seek(Asset, finalPos, relativeMovement ? SEEK_CUR : SEEK_SET);
return status+1;
}
long CAndroidAssetReader::getSize() const
{
return AAsset_getLength(Asset);
}
long CAndroidAssetReader::getPos() const
{
return AAsset_getLength(Asset) - AAsset_getRemainingLength(Asset);
}
const io::path& CAndroidAssetReader::getFileName() const
{
return Filename;
}
} // end namespace io
} // end namespace irr
#endif // _IRR_COMPILE_ANDROID_ASSET_READER_

View File

@ -0,0 +1,75 @@
// Copyright (C) 2012 Joerg Henrichs
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_ANDROID_ASSET_READER_H_INCLUDED__
#define __C_ANDROID_ASSET_READER_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_ANDROID_ASSET_READER_
#include "IReadFile.h"
struct AAssetManager;
struct AAsset;
struct ANativeActivity;
namespace irr
{
namespace io
{
class CAndroidAssetReader : public virtual IReadFile
{
public:
CAndroidAssetReader(AAssetManager *assetManager, const io::path &filename);
virtual ~CAndroidAssetReader();
//! Reads an amount of bytes from the file.
/** \param buffer Pointer to buffer where read bytes are written to.
\param sizeToRead Amount of bytes to read from the file.
\return How many bytes were read. */
virtual size_t read(void* buffer, size_t sizeToRead);
//! Changes position in file
/** \param finalPos Destination position in the file.
\param relativeMovement If set to true, the position in the file is
changed relative to current position. Otherwise the position is changed
from beginning of file.
\return True if successful, otherwise false. */
virtual bool seek(long finalPos, bool relativeMovement = false);
//! Get size of file.
/** \return Size of the file in bytes. */
virtual long getSize() const;
//! Get the current position in the file.
/** \return Current position in the file in bytes. */
virtual long getPos() const;
//! Get name of file.
/** \return File name as zero terminated character string. */
virtual const io::path& getFileName() const;
/** Return true if the file could be opened. */
bool isOpen() const { return Asset!=NULL; }
private:
//! Android's asset manager
AAssetManager *AssetManager;
// An asset, i.e. file
AAsset *Asset;
path Filename;
};
} // end namespace io
} // end namespace irr
#endif // _IRR_COMPILE_ANDROID_ASSET_READER_
#endif // __C_ANDROID_ASSET_READER_H_INCLUDED__

View File

@ -0,0 +1,869 @@
// Copyright (C) 2002-2007 Nikolaus Gebhardt
// Copyright (C) 2007-2011 Christian Stehno
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CIrrDeviceAndroid.h"
#ifdef _IRR_COMPILE_WITH_ANDROID_DEVICE_
#include "os.h"
#include "CFileSystem.h"
#include "CAndroidAssetReader.h"
#include "CAndroidAssetFileArchive.h"
#include "CKeyEventWrapper.h"
#include "CEGLManager.h"
#include "ISceneManager.h"
#include "IGUIEnvironment.h"
#include "CEGLManager.h"
namespace irr
{
namespace video
{
IVideoDriver* createOGLES1Driver(const SIrrlichtCreationParameters& params,
io::IFileSystem* io, video::IContextManager* contextManager);
IVideoDriver* createOGLES2Driver(const SIrrlichtCreationParameters& params,
io::IFileSystem* io, video::IContextManager* contextManager);
}
}
namespace irr
{
CIrrDeviceAndroid::CIrrDeviceAndroid(const SIrrlichtCreationParameters& param)
: CIrrDeviceStub(param), Accelerometer(0), Gyroscope(0), Focused(false), Initialized(false), Paused(true), JNIEnvAttachedToVM(0)
{
#ifdef _DEBUG
setDebugName("CIrrDeviceAndroid");
#endif
// Get the interface to the native Android activity.
Android = (android_app*)(param.PrivateData);
// Set the private data so we can use it in any static callbacks.
Android->userData = this;
// Set the default command handler. This is a callback function that the Android
// OS invokes to send the native activity messages.
Android->onAppCmd = handleAndroidCommand;
createKeyMap();
// Create a sensor manager to receive touch screen events from the java activity.
SensorManager = ASensorManager_getInstance();
SensorEventQueue = ASensorManager_createEventQueue(SensorManager, Android->looper, LOOPER_ID_USER, 0, 0);
Android->onInputEvent = handleInput;
// Create EGL manager.
ContextManager = new video::CEGLManager();
os::Printer::log("Waiting for Android activity window to be created.", ELL_DEBUG);
do
{
s32 Events = 0;
android_poll_source* Source = 0;
while ((ALooper_pollAll(((Focused && !Paused) || !Initialized) ? 0 : -1, 0, &Events, (void**)&Source)) >= 0)
{
if(Source)
Source->process(Android, Source);
}
}
while(!Initialized);
}
CIrrDeviceAndroid::~CIrrDeviceAndroid()
{
if (GUIEnvironment)
{
GUIEnvironment->drop();
GUIEnvironment = 0;
}
if (SceneManager)
{
SceneManager->drop();
SceneManager = 0;
}
if (VideoDriver)
{
VideoDriver->drop();
VideoDriver = 0;
}
}
bool CIrrDeviceAndroid::run()
{
if (!Initialized)
return false;
os::Timer::tick();
s32 id;
s32 Events = 0;
android_poll_source* Source = 0;
while ((id = ALooper_pollAll(((Focused && !Paused) || !Initialized) ? 0 : -1, 0, &Events, (void**)&Source)) >= 0)
{
if(Source)
Source->process(Android, Source);
// if a sensor has data, we'll process it now.
if (id == LOOPER_ID_USER)
{
ASensorEvent sensorEvent;
while (ASensorEventQueue_getEvents(SensorEventQueue, &sensorEvent, 1) > 0)
{
switch (sensorEvent.type)
{
case ASENSOR_TYPE_ACCELEROMETER:
SEvent accEvent;
accEvent.EventType = EET_ACCELEROMETER_EVENT;
accEvent.AccelerometerEvent.X = sensorEvent.acceleration.x;
accEvent.AccelerometerEvent.Y = sensorEvent.acceleration.y;
accEvent.AccelerometerEvent.Z = sensorEvent.acceleration.z;
postEventFromUser(accEvent);
break;
case ASENSOR_TYPE_GYROSCOPE:
SEvent gyroEvent;
gyroEvent.EventType = EET_GYROSCOPE_EVENT;
gyroEvent.GyroscopeEvent.X = sensorEvent.vector.x;
gyroEvent.GyroscopeEvent.Y = sensorEvent.vector.y;
gyroEvent.GyroscopeEvent.Z = sensorEvent.vector.z;
postEventFromUser(gyroEvent);
break;
default:
break;
}
}
}
if(!Initialized)
break;
}
return Initialized;
}
void CIrrDeviceAndroid::yield()
{
struct timespec ts = {0,1};
nanosleep(&ts, NULL);
}
void CIrrDeviceAndroid::sleep(u32 timeMs, bool pauseTimer)
{
const bool wasStopped = Timer ? Timer->isStopped() : true;
struct timespec ts;
ts.tv_sec = (time_t) (timeMs / 1000);
ts.tv_nsec = (long) (timeMs % 1000) * 1000000;
if (pauseTimer && !wasStopped)
Timer->stop();
nanosleep(&ts, NULL);
if (pauseTimer && !wasStopped)
Timer->start();
}
void CIrrDeviceAndroid::setWindowCaption(const wchar_t* text)
{
}
bool CIrrDeviceAndroid::present(video::IImage* surface, void* windowId, core::rect<s32>* srcClip)
{
return true;
}
bool CIrrDeviceAndroid::isWindowActive() const
{
return (Focused && !Paused);
}
bool CIrrDeviceAndroid::isWindowFocused() const
{
return Focused;
}
bool CIrrDeviceAndroid::isWindowMinimized() const
{
return !Focused;
}
void CIrrDeviceAndroid::closeDevice()
{
ANativeActivity_finish(Android->activity);
}
void CIrrDeviceAndroid::setResizable(bool resize)
{
}
void CIrrDeviceAndroid::minimizeWindow()
{
}
void CIrrDeviceAndroid::maximizeWindow()
{
}
void CIrrDeviceAndroid::restoreWindow()
{
}
core::position2di CIrrDeviceAndroid::getWindowPosition()
{
return core::position2di(0, 0);
}
E_DEVICE_TYPE CIrrDeviceAndroid::getType() const
{
return EIDT_ANDROID;
}
void CIrrDeviceAndroid::handleAndroidCommand(android_app* app, int32_t cmd)
{
CIrrDeviceAndroid* device = (CIrrDeviceAndroid*)app->userData;
SEvent event;
event.EventType = EET_SYSTEM_EVENT;
event.SystemEvent.EventType = ESET_ANDROID_CMD;
event.SystemEvent.AndroidCmd.Cmd = cmd;
if ( device->postEventFromUser(event) )
return;
switch (cmd)
{
case APP_CMD_INPUT_CHANGED:
os::Printer::log("Android command APP_CMD_INPUT_CHANGED", ELL_DEBUG);
break;
case APP_CMD_WINDOW_RESIZED:
os::Printer::log("Android command APP_CMD_WINDOW_RESIZED", ELL_DEBUG);
break;
case APP_CMD_WINDOW_REDRAW_NEEDED:
os::Printer::log("Android command APP_CMD_WINDOW_REDRAW_NEEDED", ELL_DEBUG);
break;
case APP_CMD_SAVE_STATE:
os::Printer::log("Android command APP_CMD_SAVE_STATE", ELL_DEBUG);
break;
case APP_CMD_CONTENT_RECT_CHANGED:
os::Printer::log("Android command APP_CMD_CONTENT_RECT_CHANGED", ELL_DEBUG);
break;
case APP_CMD_CONFIG_CHANGED:
os::Printer::log("Android command APP_CMD_CONFIG_CHANGED", ELL_DEBUG);
break;
case APP_CMD_LOW_MEMORY:
os::Printer::log("Android command APP_CMD_LOW_MEMORY", ELL_DEBUG);
break;
case APP_CMD_START:
os::Printer::log("Android command APP_CMD_START", ELL_DEBUG);
break;
case APP_CMD_INIT_WINDOW:
os::Printer::log("Android command APP_CMD_INIT_WINDOW", ELL_DEBUG);
device->getExposedVideoData().OGLESAndroid.Window = app->window;
if (device->CreationParams.WindowSize.Width == 0 || device->CreationParams.WindowSize.Height == 0)
{
device->CreationParams.WindowSize.Width = ANativeWindow_getWidth(app->window);
device->CreationParams.WindowSize.Height = ANativeWindow_getHeight(app->window);
}
device->getContextManager()->initialize(device->CreationParams, device->ExposedVideoData);
device->getContextManager()->generateSurface();
device->getContextManager()->generateContext();
device->getContextManager()->activateContext(device->getContextManager()->getContext());
if (!device->Initialized)
{
io::CAndroidAssetFileArchive* assets = new io::CAndroidAssetFileArchive( device->Android->activity->assetManager, false, false);
assets->addDirectoryToFileList("");
device->FileSystem->addFileArchive(assets);
assets->drop();
device->createDriver();
if (device->VideoDriver)
device->createGUIAndScene();
}
device->Initialized = true;
break;
case APP_CMD_TERM_WINDOW:
os::Printer::log("Android command APP_CMD_TERM_WINDOW", ELL_DEBUG);
device->getContextManager()->destroySurface();
break;
case APP_CMD_GAINED_FOCUS:
os::Printer::log("Android command APP_CMD_GAINED_FOCUS", ELL_DEBUG);
device->Focused = true;
break;
case APP_CMD_LOST_FOCUS:
os::Printer::log("Android command APP_CMD_LOST_FOCUS", ELL_DEBUG);
device->Focused = false;
break;
case APP_CMD_DESTROY:
os::Printer::log("Android command APP_CMD_DESTROY", ELL_DEBUG);
if ( device->JNIEnvAttachedToVM )
{
device->JNIEnvAttachedToVM = 0;
device->Android->activity->vm->DetachCurrentThread();
}
device->Initialized = false;
break;
case APP_CMD_PAUSE:
os::Printer::log("Android command APP_CMD_PAUSE", ELL_DEBUG);
device->Paused = true;
break;
case APP_CMD_STOP:
os::Printer::log("Android command APP_CMD_STOP", ELL_DEBUG);
break;
case APP_CMD_RESUME:
os::Printer::log("Android command APP_CMD_RESUME", ELL_DEBUG);
device->Paused = false;
break;
default:
break;
}
}
s32 CIrrDeviceAndroid::handleInput(android_app* app, AInputEvent* androidEvent)
{
CIrrDeviceAndroid* device = (CIrrDeviceAndroid*)app->userData;
s32 status = 0;
switch ( AInputEvent_getType(androidEvent) )
{
case AINPUT_EVENT_TYPE_MOTION:
{
SEvent event;
event.EventType = EET_TOUCH_INPUT_EVENT;
s32 eventAction = AMotionEvent_getAction(androidEvent);
s32 eventType = eventAction & AMOTION_EVENT_ACTION_MASK;
#if 0
// Useful for debugging. We might have to pass some of those infos on at some point.
// but preferably device independent (so iphone can use same irrlicht flags).
int32_t flags = AMotionEvent_getFlags(androidEvent);
os::Printer::log("flags: ", core::stringc(flags).c_str(), ELL_DEBUG);
int32_t metaState = AMotionEvent_getMetaState(androidEvent);
os::Printer::log("metaState: ", core::stringc(metaState).c_str(), ELL_DEBUG);
int32_t edgeFlags = AMotionEvent_getEdgeFlags(androidEvent);
os::Printer::log("edgeFlags: ", core::stringc(flags).c_str(), ELL_DEBUG);
#endif
bool touchReceived = true;
switch (eventType)
{
case AMOTION_EVENT_ACTION_DOWN:
case AMOTION_EVENT_ACTION_POINTER_DOWN:
event.TouchInput.Event = ETIE_PRESSED_DOWN;
break;
case AMOTION_EVENT_ACTION_MOVE:
event.TouchInput.Event = ETIE_MOVED;
break;
case AMOTION_EVENT_ACTION_UP:
case AMOTION_EVENT_ACTION_POINTER_UP:
case AMOTION_EVENT_ACTION_CANCEL:
event.TouchInput.Event = ETIE_LEFT_UP;
break;
default:
touchReceived = false;
break;
}
if (touchReceived)
{
// Process all touches for move action.
if (event.TouchInput.Event == ETIE_MOVED)
{
s32 pointerCount = AMotionEvent_getPointerCount(androidEvent);
for (s32 i = 0; i < pointerCount; ++i)
{
event.TouchInput.ID = AMotionEvent_getPointerId(androidEvent, i);
event.TouchInput.X = AMotionEvent_getX(androidEvent, i);
event.TouchInput.Y = AMotionEvent_getY(androidEvent, i);
device->postEventFromUser(event);
}
}
else // Process one touch for other actions.
{
s32 pointerIndex = (eventAction & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
event.TouchInput.ID = AMotionEvent_getPointerId(androidEvent, pointerIndex);
event.TouchInput.X = AMotionEvent_getX(androidEvent, pointerIndex);
event.TouchInput.Y = AMotionEvent_getY(androidEvent, pointerIndex);
device->postEventFromUser(event);
}
status = 1;
}
}
break;
case AINPUT_EVENT_TYPE_KEY:
{
SEvent event;
event.EventType = EET_KEY_INPUT_EVENT;
int32_t keyCode = AKeyEvent_getKeyCode(androidEvent);
// os::Printer::log("keyCode: ", core::stringc(keyCode).c_str(), ELL_DEBUG);
int32_t keyAction = AKeyEvent_getAction(androidEvent);
int32_t keyMetaState = AKeyEvent_getMetaState(androidEvent);
if ( keyCode >= 0 && (u32)keyCode < device->KeyMap.size() )
event.KeyInput.Key = device->KeyMap[keyCode];
else
event.KeyInput.Key = KEY_UNKNOWN;
event.KeyInput.SystemKeyCode = (u32)keyCode;
if ( keyAction == AKEY_EVENT_ACTION_DOWN )
event.KeyInput.PressedDown = true;
else if ( keyAction == AKEY_EVENT_ACTION_UP )
event.KeyInput.PressedDown = false;
else if ( keyAction == AKEY_EVENT_ACTION_MULTIPLE )
{
// TODO: Multiple duplicate key events have occurred in a row,
// or a complex string is being delivered. The repeat_count
// property of the key event contains the number of times the
// given key code should be executed.
// I guess this might necessary for more complicated i18n key input,
// but don't see yet how to handle this correctly.
}
/* no use for meta keys so far.
if ( keyMetaState & AMETA_ALT_ON
|| keyMetaState & AMETA_ALT_LEFT_ON
|| keyMetaState & AMETA_ALT_RIGHT_ON )
;
// what is a sym?
if ( keyMetaState & AMETA_SYM_ON )
;
*/
if ( keyMetaState & AMETA_SHIFT_ON
|| keyMetaState & AMETA_SHIFT_LEFT_ON
|| keyMetaState & AMETA_SHIFT_RIGHT_ON )
event.KeyInput.Shift = true;
else
event.KeyInput.Shift = false;
event.KeyInput.Control = false;
// Having memory allocations + going through JNI for each key-press is pretty bad (slow).
// So we do it only for those keys which are likely text-characters and avoid it for all other keys.
// So it's fast for keys like game controller input and special keys. And text keys are typically
// only used or entering text and not for gaming on Android, so speed likely doesn't matter there too much.
if ( event.KeyInput.Key > 0 )
{
// TODO:
// Not sure why we have to attach a JNIEnv here, but it won't work when doing that in the constructor or
// trying to use the activity->env. My best guess is that the event-handling happens in an own thread.
// It means JNIEnvAttachedToVM will never get detached as I don't know a safe way where to do that
// (we could attach & detach each time, but that would probably be slow)
// Also - it has to be each time as it get's invalid when the application mode changes.
if ( device->Initialized && device->Android && device->Android->activity && device->Android->activity->vm )
{
JavaVMAttachArgs attachArgs;
attachArgs.version = JNI_VERSION_1_6;
attachArgs.name = 0;
attachArgs.group = NULL;
// Not a big problem calling it each time - it's a no-op when the thread already is attached.
// And we have to do that as someone else can have detached the thread in the meantime.
jint result = device->Android->activity->vm->AttachCurrentThread(&device->JNIEnvAttachedToVM, &attachArgs);
if(result == JNI_ERR)
{
os::Printer::log("AttachCurrentThread for the JNI environment failed.", ELL_WARNING);
device->JNIEnvAttachedToVM = 0;
}
if ( device->JNIEnvAttachedToVM )
{
jni::CKeyEventWrapper * keyEventWrapper = new jni::CKeyEventWrapper(device->JNIEnvAttachedToVM, keyAction, keyCode);
event.KeyInput.Char = keyEventWrapper->getUnicodeChar(keyMetaState);
delete keyEventWrapper;
}
}
if ( event.KeyInput.Key == KEY_BACK )
{
event.KeyInput.Char = 0x08; // same key-code as on other operating systems. Otherwise we have to handle too much system specific stuff in the editbox.
}
//os::Printer::log("char-code: ", core::stringc((int)event.KeyInput.Char).c_str(), ELL_DEBUG);
}
else
{
// os::Printer::log("keyCode: ", core::stringc(keyCode).c_str(), ELL_DEBUG);
event.KeyInput.Char = 0;
}
device->postEventFromUser(event);
}
break;
default:
break;
}
return status;
}
void CIrrDeviceAndroid::createDriver()
{
switch(CreationParams.DriverType)
{
case video::EDT_OGLES1:
#ifdef _IRR_COMPILE_WITH_OGLES1_
VideoDriver = video::createOGLES1Driver(CreationParams, FileSystem, ContextManager);
#else
os::Printer::log("No OpenGL ES 1.0 support compiled in.", ELL_ERROR);
#endif
break;
case video::EDT_OGLES2:
#ifdef _IRR_COMPILE_WITH_OGLES2_
VideoDriver = video::createOGLES2Driver(CreationParams, FileSystem, ContextManager);
#else
os::Printer::log("No OpenGL ES 2.0 support compiled in.", ELL_ERROR);
#endif
break;
case video::EDT_NULL:
VideoDriver = video::createNullDriver(FileSystem, CreationParams.WindowSize);
break;
case video::EDT_SOFTWARE:
case video::EDT_BURNINGSVIDEO:
case video::EDT_OPENGL:
case video::DEPRECATED_EDT_DIRECT3D8_NO_LONGER_EXISTS:
case video::EDT_DIRECT3D9:
os::Printer::log("This driver is not available in Android. Try OpenGL ES 1.0 or ES 2.0.", ELL_ERROR);
break;
default:
os::Printer::log("Unable to create video driver of unknown type.", ELL_ERROR);
break;
}
}
video::SExposedVideoData& CIrrDeviceAndroid::getExposedVideoData()
{
return ExposedVideoData;
}
void CIrrDeviceAndroid::createKeyMap()
{
KeyMap.set_used(223);
KeyMap[0] = KEY_UNKNOWN; // AKEYCODE_UNKNOWN
KeyMap[1] = KEY_LBUTTON; // AKEYCODE_SOFT_LEFT
KeyMap[2] = KEY_RBUTTON; // AKEYCODE_SOFT_RIGHT
KeyMap[3] = KEY_HOME; // AKEYCODE_HOME
KeyMap[4] = KEY_BACK; // AKEYCODE_BACK
KeyMap[5] = KEY_UNKNOWN; // AKEYCODE_CALL
KeyMap[6] = KEY_UNKNOWN; // AKEYCODE_ENDCALL
KeyMap[7] = KEY_KEY_0; // AKEYCODE_0
KeyMap[8] = KEY_KEY_1; // AKEYCODE_1
KeyMap[9] = KEY_KEY_2; // AKEYCODE_2
KeyMap[10] = KEY_KEY_3; // AKEYCODE_3
KeyMap[11] = KEY_KEY_4; // AKEYCODE_4
KeyMap[12] = KEY_KEY_5; // AKEYCODE_5
KeyMap[13] = KEY_KEY_6; // AKEYCODE_6
KeyMap[14] = KEY_KEY_7; // AKEYCODE_7
KeyMap[15] = KEY_KEY_8; // AKEYCODE_8
KeyMap[16] = KEY_KEY_9; // AKEYCODE_9
KeyMap[17] = KEY_UNKNOWN; // AKEYCODE_STAR
KeyMap[18] = KEY_UNKNOWN; // AKEYCODE_POUND
KeyMap[19] = KEY_UP; // AKEYCODE_DPAD_UP
KeyMap[20] = KEY_DOWN; // AKEYCODE_DPAD_DOWN
KeyMap[21] = KEY_LEFT; // AKEYCODE_DPAD_LEFT
KeyMap[22] = KEY_RIGHT; // AKEYCODE_DPAD_RIGHT
KeyMap[23] = KEY_SELECT; // AKEYCODE_DPAD_CENTER
KeyMap[24] = KEY_VOLUME_DOWN; // AKEYCODE_VOLUME_UP
KeyMap[25] = KEY_VOLUME_UP; // AKEYCODE_VOLUME_DOWN
KeyMap[26] = KEY_UNKNOWN; // AKEYCODE_POWER
KeyMap[27] = KEY_UNKNOWN; // AKEYCODE_CAMERA
KeyMap[28] = KEY_CLEAR; // AKEYCODE_CLEAR
KeyMap[29] = KEY_KEY_A; // AKEYCODE_A
KeyMap[30] = KEY_KEY_B; // AKEYCODE_B
KeyMap[31] = KEY_KEY_C; // AKEYCODE_C
KeyMap[32] = KEY_KEY_D; // AKEYCODE_D
KeyMap[33] = KEY_KEY_E; // AKEYCODE_E
KeyMap[34] = KEY_KEY_F; // AKEYCODE_F
KeyMap[35] = KEY_KEY_G; // AKEYCODE_G
KeyMap[36] = KEY_KEY_H; // AKEYCODE_H
KeyMap[37] = KEY_KEY_I; // AKEYCODE_I
KeyMap[38] = KEY_KEY_J; // AKEYCODE_J
KeyMap[39] = KEY_KEY_K; // AKEYCODE_K
KeyMap[40] = KEY_KEY_L; // AKEYCODE_L
KeyMap[41] = KEY_KEY_M; // AKEYCODE_M
KeyMap[42] = KEY_KEY_N; // AKEYCODE_N
KeyMap[43] = KEY_KEY_O; // AKEYCODE_O
KeyMap[44] = KEY_KEY_P; // AKEYCODE_P
KeyMap[45] = KEY_KEY_Q; // AKEYCODE_Q
KeyMap[46] = KEY_KEY_R; // AKEYCODE_R
KeyMap[47] = KEY_KEY_S; // AKEYCODE_S
KeyMap[48] = KEY_KEY_T; // AKEYCODE_T
KeyMap[49] = KEY_KEY_U; // AKEYCODE_U
KeyMap[50] = KEY_KEY_V; // AKEYCODE_V
KeyMap[51] = KEY_KEY_W; // AKEYCODE_W
KeyMap[52] = KEY_KEY_X; // AKEYCODE_X
KeyMap[53] = KEY_KEY_Y; // AKEYCODE_Y
KeyMap[54] = KEY_KEY_Z; // AKEYCODE_Z
KeyMap[55] = KEY_COMMA; // AKEYCODE_COMMA
KeyMap[56] = KEY_PERIOD; // AKEYCODE_PERIOD
KeyMap[57] = KEY_MENU; // AKEYCODE_ALT_LEFT
KeyMap[58] = KEY_MENU; // AKEYCODE_ALT_RIGHT
KeyMap[59] = KEY_LSHIFT; // AKEYCODE_SHIFT_LEFT
KeyMap[60] = KEY_RSHIFT; // AKEYCODE_SHIFT_RIGHT
KeyMap[61] = KEY_TAB; // AKEYCODE_TAB
KeyMap[62] = KEY_SPACE; // AKEYCODE_SPACE
KeyMap[63] = KEY_UNKNOWN; // AKEYCODE_SYM
KeyMap[64] = KEY_UNKNOWN; // AKEYCODE_EXPLORER
KeyMap[65] = KEY_UNKNOWN; // AKEYCODE_ENVELOPE
KeyMap[66] = KEY_RETURN; // AKEYCODE_ENTER
KeyMap[67] = KEY_BACK; // AKEYCODE_DEL
KeyMap[68] = KEY_OEM_3; // AKEYCODE_GRAVE
KeyMap[69] = KEY_MINUS; // AKEYCODE_MINUS
KeyMap[70] = KEY_UNKNOWN; // AKEYCODE_EQUALS
KeyMap[71] = KEY_UNKNOWN; // AKEYCODE_LEFT_BRACKET
KeyMap[72] = KEY_UNKNOWN; // AKEYCODE_RIGHT_BRACKET
KeyMap[73] = KEY_UNKNOWN; // AKEYCODE_BACKSLASH
KeyMap[74] = KEY_UNKNOWN; // AKEYCODE_SEMICOLON
KeyMap[75] = KEY_UNKNOWN; // AKEYCODE_APOSTROPHE
KeyMap[76] = KEY_UNKNOWN; // AKEYCODE_SLASH
KeyMap[77] = KEY_UNKNOWN; // AKEYCODE_AT
KeyMap[78] = KEY_UNKNOWN; // AKEYCODE_NUM
KeyMap[79] = KEY_UNKNOWN; // AKEYCODE_HEADSETHOOK
KeyMap[80] = KEY_UNKNOWN; // AKEYCODE_FOCUS (*Camera* focus)
KeyMap[81] = KEY_PLUS; // AKEYCODE_PLUS
KeyMap[82] = KEY_MENU; // AKEYCODE_MENU
KeyMap[83] = KEY_UNKNOWN; // AKEYCODE_NOTIFICATION
KeyMap[84] = KEY_UNKNOWN; // AKEYCODE_SEARCH
KeyMap[85] = KEY_MEDIA_PLAY_PAUSE; // AKEYCODE_MEDIA_PLAY_PAUSE
KeyMap[86] = KEY_MEDIA_STOP; // AKEYCODE_MEDIA_STOP
KeyMap[87] = KEY_MEDIA_NEXT_TRACK; // AKEYCODE_MEDIA_NEXT
KeyMap[88] = KEY_MEDIA_PREV_TRACK; // AKEYCODE_MEDIA_PREVIOUS
KeyMap[89] = KEY_UNKNOWN; // AKEYCODE_MEDIA_REWIND
KeyMap[90] = KEY_UNKNOWN; // AKEYCODE_MEDIA_FAST_FORWARD
KeyMap[91] = KEY_VOLUME_MUTE; // AKEYCODE_MUTE
KeyMap[92] = KEY_PRIOR; // AKEYCODE_PAGE_UP
KeyMap[93] = KEY_NEXT; // AKEYCODE_PAGE_DOWN
KeyMap[94] = KEY_UNKNOWN; // AKEYCODE_PICTSYMBOLS
KeyMap[95] = KEY_UNKNOWN; // AKEYCODE_SWITCH_CHARSET
// following look like controller inputs
KeyMap[96] = KEY_UNKNOWN; // AKEYCODE_BUTTON_A
KeyMap[97] = KEY_UNKNOWN; // AKEYCODE_BUTTON_B
KeyMap[98] = KEY_UNKNOWN; // AKEYCODE_BUTTON_C
KeyMap[99] = KEY_UNKNOWN; // AKEYCODE_BUTTON_X
KeyMap[100] = KEY_UNKNOWN; // AKEYCODE_BUTTON_Y
KeyMap[101] = KEY_UNKNOWN; // AKEYCODE_BUTTON_Z
KeyMap[102] = KEY_UNKNOWN; // AKEYCODE_BUTTON_L1
KeyMap[103] = KEY_UNKNOWN; // AKEYCODE_BUTTON_R1
KeyMap[104] = KEY_UNKNOWN; // AKEYCODE_BUTTON_L2
KeyMap[105] = KEY_UNKNOWN; // AKEYCODE_BUTTON_R2
KeyMap[106] = KEY_UNKNOWN; // AKEYCODE_BUTTON_THUMBL
KeyMap[107] = KEY_UNKNOWN; // AKEYCODE_BUTTON_THUMBR
KeyMap[108] = KEY_UNKNOWN; // AKEYCODE_BUTTON_START
KeyMap[109] = KEY_UNKNOWN; // AKEYCODE_BUTTON_SELECT
KeyMap[110] = KEY_UNKNOWN; // AKEYCODE_BUTTON_MODE
KeyMap[111] = KEY_ESCAPE; // AKEYCODE_ESCAPE
KeyMap[112] = KEY_DELETE; // AKEYCODE_FORWARD_DEL
KeyMap[113] = KEY_CONTROL; // AKEYCODE_CTRL_LEFT
KeyMap[114] = KEY_CONTROL; // AKEYCODE_CTRL_RIGHT
KeyMap[115] = KEY_CAPITAL; // AKEYCODE_CAPS_LOCK
KeyMap[116] = KEY_SCROLL; // AKEYCODE_SCROLL_LOCK
KeyMap[117] = KEY_UNKNOWN; // AKEYCODE_META_LEFT
KeyMap[118] = KEY_UNKNOWN; // AKEYCODE_META_RIGHT
KeyMap[119] = KEY_UNKNOWN; // AKEYCODE_FUNCTION
KeyMap[120] = KEY_SNAPSHOT; // AKEYCODE_SYSRQ
KeyMap[121] = KEY_PAUSE; // AKEYCODE_BREAK
KeyMap[122] = KEY_HOME; // AKEYCODE_MOVE_HOME
KeyMap[123] = KEY_END; // AKEYCODE_MOVE_END
KeyMap[124] = KEY_INSERT; // AKEYCODE_INSERT
KeyMap[125] = KEY_UNKNOWN; // AKEYCODE_FORWARD
KeyMap[126] = KEY_PLAY; // AKEYCODE_MEDIA_PLAY
KeyMap[127] = KEY_MEDIA_PLAY_PAUSE; // AKEYCODE_MEDIA_PAUSE
KeyMap[128] = KEY_UNKNOWN; // AKEYCODE_MEDIA_CLOSE
KeyMap[129] = KEY_UNKNOWN; // AKEYCODE_MEDIA_EJECT
KeyMap[130] = KEY_UNKNOWN; // AKEYCODE_MEDIA_RECORD
KeyMap[131] = KEY_F1; // AKEYCODE_F1
KeyMap[132] = KEY_F2; // AKEYCODE_F2
KeyMap[133] = KEY_F3; // AKEYCODE_F3
KeyMap[134] = KEY_F4; // AKEYCODE_F4
KeyMap[135] = KEY_F5; // AKEYCODE_F5
KeyMap[136] = KEY_F6; // AKEYCODE_F6
KeyMap[137] = KEY_F7; // AKEYCODE_F7
KeyMap[138] = KEY_F8; // AKEYCODE_F8
KeyMap[139] = KEY_F9; // AKEYCODE_F9
KeyMap[140] = KEY_F10; // AKEYCODE_F10
KeyMap[141] = KEY_F11; // AKEYCODE_F11
KeyMap[142] = KEY_F12; // AKEYCODE_F12
KeyMap[143] = KEY_NUMLOCK; // AKEYCODE_NUM_LOCK
KeyMap[144] = KEY_NUMPAD0; // AKEYCODE_NUMPAD_0
KeyMap[145] = KEY_NUMPAD1; // AKEYCODE_NUMPAD_1
KeyMap[146] = KEY_NUMPAD2; // AKEYCODE_NUMPAD_2
KeyMap[147] = KEY_NUMPAD3; // AKEYCODE_NUMPAD_3
KeyMap[148] = KEY_NUMPAD4; // AKEYCODE_NUMPAD_4
KeyMap[149] = KEY_NUMPAD5; // AKEYCODE_NUMPAD_5
KeyMap[150] = KEY_NUMPAD6; // AKEYCODE_NUMPAD_6
KeyMap[151] = KEY_NUMPAD7; // AKEYCODE_NUMPAD_7
KeyMap[152] = KEY_NUMPAD8; // AKEYCODE_NUMPAD_8
KeyMap[153] = KEY_NUMPAD9; // AKEYCODE_NUMPAD_9
KeyMap[154] = KEY_DIVIDE; // AKEYCODE_NUMPAD_DIVIDE
KeyMap[155] = KEY_MULTIPLY; // AKEYCODE_NUMPAD_MULTIPLY
KeyMap[156] = KEY_SUBTRACT; // AKEYCODE_NUMPAD_SUBTRACT
KeyMap[157] = KEY_ADD; // AKEYCODE_NUMPAD_ADD
KeyMap[158] = KEY_UNKNOWN; // AKEYCODE_NUMPAD_DOT
KeyMap[159] = KEY_COMMA; // AKEYCODE_NUMPAD_COMMA
KeyMap[160] = KEY_RETURN; // AKEYCODE_NUMPAD_ENTER
KeyMap[161] = KEY_UNKNOWN; // AKEYCODE_NUMPAD_EQUALS
KeyMap[162] = KEY_UNKNOWN; // AKEYCODE_NUMPAD_LEFT_PAREN
KeyMap[163] = KEY_UNKNOWN; // AKEYCODE_NUMPAD_RIGHT_PAREN
KeyMap[164] = KEY_VOLUME_MUTE; // AKEYCODE_VOLUME_MUTE
KeyMap[165] = KEY_UNKNOWN; // AKEYCODE_INFO
KeyMap[166] = KEY_UNKNOWN; // AKEYCODE_CHANNEL_UP
KeyMap[167] = KEY_UNKNOWN; // AKEYCODE_CHANNEL_DOWN
KeyMap[168] = KEY_ZOOM; // AKEYCODE_ZOOM_IN
KeyMap[169] = KEY_UNKNOWN; // AKEYCODE_ZOOM_OUT
KeyMap[170] = KEY_UNKNOWN; // AKEYCODE_TV
KeyMap[171] = KEY_UNKNOWN; // AKEYCODE_WINDOW
KeyMap[172] = KEY_UNKNOWN; // AKEYCODE_GUIDE
KeyMap[173] = KEY_UNKNOWN; // AKEYCODE_DVR
KeyMap[174] = KEY_UNKNOWN; // AKEYCODE_BOOKMARK
KeyMap[175] = KEY_UNKNOWN; // AKEYCODE_CAPTIONS
KeyMap[176] = KEY_UNKNOWN; // AKEYCODE_SETTINGS
KeyMap[177] = KEY_UNKNOWN; // AKEYCODE_TV_POWER
KeyMap[178] = KEY_UNKNOWN; // AKEYCODE_TV_INPUT
KeyMap[179] = KEY_UNKNOWN; // AKEYCODE_STB_POWER
KeyMap[180] = KEY_UNKNOWN; // AKEYCODE_STB_INPUT
KeyMap[181] = KEY_UNKNOWN; // AKEYCODE_AVR_POWER
KeyMap[182] = KEY_UNKNOWN; // AKEYCODE_AVR_INPUT
KeyMap[183] = KEY_UNKNOWN; // AKEYCODE_PROG_RED
KeyMap[184] = KEY_UNKNOWN; // AKEYCODE_PROG_GREEN
KeyMap[185] = KEY_UNKNOWN; // AKEYCODE_PROG_YELLOW
KeyMap[186] = KEY_UNKNOWN; // AKEYCODE_PROG_BLUE
KeyMap[187] = KEY_UNKNOWN; // AKEYCODE_APP_SWITCH
KeyMap[188] = KEY_UNKNOWN; // AKEYCODE_BUTTON_1
KeyMap[189] = KEY_UNKNOWN; // AKEYCODE_BUTTON_2
KeyMap[190] = KEY_UNKNOWN; // AKEYCODE_BUTTON_3
KeyMap[191] = KEY_UNKNOWN; // AKEYCODE_BUTTON_4
KeyMap[192] = KEY_UNKNOWN; // AKEYCODE_BUTTON_5
KeyMap[193] = KEY_UNKNOWN; // AKEYCODE_BUTTON_6
KeyMap[194] = KEY_UNKNOWN; // AKEYCODE_BUTTON_7
KeyMap[195] = KEY_UNKNOWN; // AKEYCODE_BUTTON_8
KeyMap[196] = KEY_UNKNOWN; // AKEYCODE_BUTTON_9
KeyMap[197] = KEY_UNKNOWN; // AKEYCODE_BUTTON_10
KeyMap[198] = KEY_UNKNOWN; // AKEYCODE_BUTTON_11
KeyMap[199] = KEY_UNKNOWN; // AKEYCODE_BUTTON_12
KeyMap[200] = KEY_UNKNOWN; // AKEYCODE_BUTTON_13
KeyMap[201] = KEY_UNKNOWN; // AKEYCODE_BUTTON_14
KeyMap[202] = KEY_UNKNOWN; // AKEYCODE_BUTTON_15
KeyMap[203] = KEY_UNKNOWN; // AKEYCODE_BUTTON_16
KeyMap[204] = KEY_UNKNOWN; // AKEYCODE_LANGUAGE_SWITCH
KeyMap[205] = KEY_UNKNOWN; // AKEYCODE_MANNER_MODE
KeyMap[206] = KEY_UNKNOWN; // AKEYCODE_3D_MODE
KeyMap[207] = KEY_UNKNOWN; // AKEYCODE_CONTACTS
KeyMap[208] = KEY_UNKNOWN; // AKEYCODE_CALENDAR
KeyMap[209] = KEY_UNKNOWN; // AKEYCODE_MUSIC
KeyMap[210] = KEY_UNKNOWN; // AKEYCODE_CALCULATOR
KeyMap[211] = KEY_UNKNOWN; // AKEYCODE_ZENKAKU_HANKAKU
KeyMap[212] = KEY_UNKNOWN; // AKEYCODE_EISU
KeyMap[213] = KEY_UNKNOWN; // AKEYCODE_MUHENKAN
KeyMap[214] = KEY_UNKNOWN; // AKEYCODE_HENKAN
KeyMap[215] = KEY_UNKNOWN; // AKEYCODE_KATAKANA_HIRAGANA
KeyMap[216] = KEY_UNKNOWN; // AKEYCODE_YEN
KeyMap[217] = KEY_UNKNOWN; // AKEYCODE_RO
KeyMap[218] = KEY_UNKNOWN; // AKEYCODE_KANA
KeyMap[219] = KEY_UNKNOWN; // AKEYCODE_ASSIST
KeyMap[220] = KEY_UNKNOWN; // AKEYCODE_BRIGHTNESS_DOWN
KeyMap[221] = KEY_UNKNOWN; // AKEYCODE_BRIGHTNESS_UP ,
KeyMap[222] = KEY_UNKNOWN; // AKEYCODE_MEDIA_AUDIO_TRACK
}
bool CIrrDeviceAndroid::activateAccelerometer(float updateInterval)
{
if (!isAccelerometerAvailable())
return false;
ASensorEventQueue_enableSensor(SensorEventQueue, Accelerometer);
ASensorEventQueue_setEventRate(SensorEventQueue, Accelerometer, (int32_t)(updateInterval*1000.f*1000.f)); // in microseconds
os::Printer::log("Activated accelerometer", ELL_DEBUG);
return true;
}
bool CIrrDeviceAndroid::deactivateAccelerometer()
{
if (Accelerometer)
{
ASensorEventQueue_disableSensor(SensorEventQueue, Accelerometer);
Accelerometer = 0;
os::Printer::log("Deactivated accelerometer", ELL_DEBUG);
return true;
}
return false;
}
bool CIrrDeviceAndroid::isAccelerometerActive()
{
return (Accelerometer != 0);
}
bool CIrrDeviceAndroid::isAccelerometerAvailable()
{
if (!Accelerometer)
Accelerometer = ASensorManager_getDefaultSensor(SensorManager, ASENSOR_TYPE_ACCELEROMETER);
return (Accelerometer != 0);
}
bool CIrrDeviceAndroid::activateGyroscope(float updateInterval)
{
if (!isGyroscopeAvailable())
return false;
ASensorEventQueue_enableSensor(SensorEventQueue, Gyroscope);
ASensorEventQueue_setEventRate(SensorEventQueue, Gyroscope, (int32_t)(updateInterval*1000.f*1000.f)); // in microseconds
os::Printer::log("Activated gyroscope", ELL_DEBUG);
return true;
}
bool CIrrDeviceAndroid::deactivateGyroscope()
{
if (Gyroscope)
{
ASensorEventQueue_disableSensor(SensorEventQueue, Gyroscope);
Gyroscope = 0;
os::Printer::log("Deactivated gyroscope", ELL_DEBUG);
return true;
}
return false;
}
bool CIrrDeviceAndroid::isGyroscopeActive()
{
return (Gyroscope != 0);
}
bool CIrrDeviceAndroid::isGyroscopeAvailable()
{
if (!Gyroscope)
Gyroscope = ASensorManager_getDefaultSensor(SensorManager, ASENSOR_TYPE_GYROSCOPE);
return (Gyroscope != 0);
}
} // end namespace irr
#endif

View File

@ -0,0 +1,107 @@
// Copyright (C) 2002-2011 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_IRR_DEVICE_ANDROID_H_INCLUDED__
#define __C_IRR_DEVICE_ANDROID_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_ANDROID_DEVICE_
#include "CIrrDeviceStub.h"
#include "IrrlichtDevice.h"
#include "IImagePresenter.h"
#include "ICursorControl.h"
#include <android/sensor.h>
#include <android_native_app_glue.h>
namespace irr
{
class CIrrDeviceAndroid : public CIrrDeviceStub, video::IImagePresenter
{
public:
CIrrDeviceAndroid(const SIrrlichtCreationParameters& param);
virtual ~CIrrDeviceAndroid();
virtual bool run();
virtual void yield();
virtual void sleep(u32 timeMs, bool pauseTimer = false);
virtual void setWindowCaption(const wchar_t* text);
virtual bool present(video::IImage* surface, void* windowId, core::rect<s32>* srcClip);
virtual bool isWindowActive() const;
virtual bool isWindowFocused() const;
virtual bool isWindowMinimized() const;
virtual void closeDevice();
virtual void setResizable(bool resize = false);
virtual void minimizeWindow();
virtual void maximizeWindow();
virtual void restoreWindow();
virtual core::position2di getWindowPosition();
virtual E_DEVICE_TYPE getType() const;
virtual bool activateAccelerometer(float updateInterval);
virtual bool deactivateAccelerometer();
virtual bool isAccelerometerActive();
virtual bool isAccelerometerAvailable();
virtual bool activateGyroscope(float updateInterval);
virtual bool deactivateGyroscope();
virtual bool isGyroscopeActive();
virtual bool isGyroscopeAvailable();
private:
static void handleAndroidCommand(android_app* app, int32_t cmd);
static s32 handleInput(android_app* app, AInputEvent* event);
void createDriver();
void createKeyMap();
video::SExposedVideoData& getExposedVideoData();
android_app* Android;
ASensorManager* SensorManager;
ASensorEventQueue* SensorEventQueue;
const ASensor* Accelerometer;
const ASensor* Gyroscope;
bool Focused;
bool Initialized;
bool Paused;
JNIEnv* JNIEnvAttachedToVM;
video::SExposedVideoData ExposedVideoData;
core::array<EKEY_CODE> KeyMap;
};
} // end namespace irr
#endif // _IRR_COMPILE_WITH_ANDROID_DEVICE_
#endif // __C_IRR_DEVICE_ANDROID_H_INCLUDED__

View File

@ -0,0 +1,63 @@
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CKeyEventWrapper.h"
#ifdef _IRR_COMPILE_WITH_ANDROID_DEVICE_
#include "os.h"
namespace irr
{
namespace jni
{
jclass CKeyEventWrapper::Class_KeyEvent = 0;
jmethodID CKeyEventWrapper::Method_constructor = 0;
jmethodID CKeyEventWrapper::Method_getUnicodeChar = 0;
CKeyEventWrapper::CKeyEventWrapper(JNIEnv* jniEnv, int action, int code)
: JniEnv(jniEnv), JniKeyEvent(0)
{
if ( JniEnv )
{
if (!Class_KeyEvent )
{
// Find java classes & functions on first call
os::Printer::log("CKeyEventWrapper first initialize", ELL_DEBUG);
jclass localClass = JniEnv->FindClass("android/view/KeyEvent");
if (localClass)
{
Class_KeyEvent = reinterpret_cast<jclass>(JniEnv->NewGlobalRef(localClass));
}
Method_constructor = JniEnv->GetMethodID(Class_KeyEvent, "<init>", "(II)V");
Method_getUnicodeChar = JniEnv->GetMethodID(Class_KeyEvent, "getUnicodeChar", "(I)I");
}
if ( Class_KeyEvent && Method_constructor )
{
JniKeyEvent = JniEnv->NewObject(Class_KeyEvent, Method_constructor, action, code);
}
else
{
os::Printer::log("CKeyEventWrapper didn't find JNI classes/methods", ELL_WARNING);
}
}
}
CKeyEventWrapper::~CKeyEventWrapper()
{
JniEnv->DeleteLocalRef(JniKeyEvent);
}
int CKeyEventWrapper::getUnicodeChar(int metaState)
{
return JniEnv->CallIntMethod(JniKeyEvent, Method_getUnicodeChar, metaState);
}
} // namespace jni
} // namespace irr
#endif // _IRR_COMPILE_WITH_ANDROID_DEVICE_

View File

@ -0,0 +1,43 @@
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_IRR_KEY_EVENT_WRAPPER_H_INCLUDED__
#define __C_IRR_KEY_EVENT_WRAPPER_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_ANDROID_DEVICE_
#include <jni.h>
struct android_app;
namespace irr
{
namespace jni
{
//! Minimal JNI wrapper class around android.view.KeyEvent
//! NOTE: Only functions we actually use in the engine are wrapped
//! This is currently not written to support multithreading - meaning threads are not attached/detached to the Java VM (to be discussed)
class CKeyEventWrapper
{
public:
CKeyEventWrapper(JNIEnv* jniEnv, int action, int code);
~CKeyEventWrapper();
int getUnicodeChar(int metaState);
private:
static jclass Class_KeyEvent;
static jmethodID Method_getUnicodeChar;
static jmethodID Method_constructor;
JNIEnv* JniEnv;
jobject JniKeyEvent; // this object in java
};
} // namespace jni
} // namespace irr
#endif // _IRR_COMPILE_WITH_ANDROID_DEVICE_
#endif // __C_IRR_KEY_EVENT_WRAPPER_H_INCLUDED__

View File

@ -0,0 +1,342 @@
LOCAL_PATH := $(call my-dir)/../..
IRRLICHT_LIB_PATH := $(LOCAL_PATH)/../../lib/Android
include $(CLEAR_VARS)
LOCAL_MODULE := Irrlicht
IRRLICHT_LIB_NAME := lib$(LOCAL_MODULE).a
LOCAL_CFLAGS := -Wall -pipe -fno-exceptions -fno-rtti -fstrict-aliasing
ifndef NDEBUG
LOCAL_CFLAGS += -g -D_DEBUG
else
LOCAL_CFLAGS += -fexpensive-optimizations -O3
endif
LOCAL_C_INCLUDES := ../../../include
LOCAL_C_INCLUDES += ../zlib ../jpeglib ../libpng
LOCAL_SRC_FILES := \
Android/CIrrDeviceAndroid.cpp \
Android/CAndroidAssetReader.cpp \
Android/CAndroidAssetFileArchive.cpp \
Android/CKeyEventWrapper.cpp \
aesGladman/aescrypt.cpp \
aesGladman/aeskey.cpp \
aesGladman/aestab.cpp \
aesGladman/fileenc.cpp \
aesGladman/hmac.cpp \
aesGladman/prng.cpp \
aesGladman/pwd2key.cpp \
aesGladman/sha1.cpp \
aesGladman/sha2.cpp \
C3DSMeshFileLoader.cpp \
CAnimatedMeshHalfLife.cpp \
CAnimatedMeshMD2.cpp \
CAnimatedMeshMD3.cpp \
CAnimatedMeshSceneNode.cpp \
CAttributes.cpp \
CB3DMeshFileLoader.cpp \
CB3DMeshWriter.cpp \
CBillboardSceneNode.cpp \
CBoneSceneNode.cpp \
CBSPMeshFileLoader.cpp \
CBurningShader_Raster_Reference.cpp \
CCameraSceneNode.cpp \
CColladaFileLoader.cpp \
CColladaMeshWriter.cpp \
CColorConverter.cpp \
CCSMLoader.cpp \
CCubeSceneNode.cpp \
CD3D9Driver.cpp \
CD3D9HLSLMaterialRenderer.cpp \
CD3D9NormalMapRenderer.cpp \
CD3D9ParallaxMapRenderer.cpp \
CD3D9ShaderMaterialRenderer.cpp \
CD3D9Texture.cpp \
CDefaultGUIElementFactory.cpp \
CDefaultSceneNodeAnimatorFactory.cpp \
CDefaultSceneNodeFactory.cpp \
CDepthBuffer.cpp \
CDMFLoader.cpp \
CDummyTransformationSceneNode.cpp \
CEmptySceneNode.cpp \
CFileList.cpp \
CFileSystem.cpp \
CFPSCounter.cpp \
leakHunter.cpp \
CGeometryCreator.cpp \
CGUIButton.cpp \
CGUICheckBox.cpp \
CGUIColorSelectDialog.cpp \
CGUIComboBox.cpp \
CGUIContextMenu.cpp \
CGUIEditBox.cpp \
CGUIEnvironment.cpp \
CGUIFileOpenDialog.cpp \
CGUIFont.cpp \
CGUIImage.cpp \
CGUIImageList.cpp \
CGUIInOutFader.cpp \
CGUIListBox.cpp \
CGUIMenu.cpp \
CGUIMeshViewer.cpp \
CGUIMessageBox.cpp \
CGUIModalScreen.cpp \
CGUIScrollBar.cpp \
CGUISkin.cpp \
CGUISpinBox.cpp \
CGUISpriteBank.cpp \
CGUIStaticText.cpp \
CGUITabControl.cpp \
CGUITable.cpp \
CGUIToolBar.cpp \
CGUITreeView.cpp \
CGUIWindow.cpp \
CGUIProfiler.cpp \
CImage.cpp \
CImageLoaderBMP.cpp \
CImageLoaderDDS.cpp \
CImageLoaderJPG.cpp \
CImageLoaderPCX.cpp \
CImageLoaderPNG.cpp \
CImageLoaderPPM.cpp \
CImageLoaderPSD.cpp \
CImageLoaderRGB.cpp \
CImageLoaderTGA.cpp \
CImageLoaderWAL.cpp \
CImageWriterBMP.cpp \
CImageWriterJPG.cpp \
CImageWriterPCX.cpp \
CImageWriterPNG.cpp \
CImageWriterPPM.cpp \
CImageWriterPSD.cpp \
CImageWriterTGA.cpp \
CImageLoaderPVR.cpp \
CIrrDeviceConsole.cpp \
CIrrDeviceFB.cpp \
CIrrDeviceLinux.cpp \
CIrrDeviceSDL.cpp \
CIrrDeviceStub.cpp \
CIrrDeviceWin32.cpp \
CIrrMeshFileLoader.cpp \
CIrrMeshWriter.cpp \
CLightSceneNode.cpp \
CLimitReadFile.cpp \
CLMTSMeshFileLoader.cpp \
CLogger.cpp \
CLWOMeshFileLoader.cpp \
CMD2MeshFileLoader.cpp \
CMD3MeshFileLoader.cpp \
CMemoryFile.cpp \
CMeshCache.cpp \
CMeshManipulator.cpp \
CMeshSceneNode.cpp \
CMeshTextureLoader.cpp \
CMetaTriangleSelector.cpp \
CMountPointReader.cpp \
CMS3DMeshFileLoader.cpp \
CMY3DMeshFileLoader.cpp \
CNPKReader.cpp \
CNullDriver.cpp \
COBJMeshFileLoader.cpp \
COBJMeshWriter.cpp \
COCTLoader.cpp \
COctreeSceneNode.cpp \
COctreeTriangleSelector.cpp \
CEGLManager.cpp \
COGLES2Driver.cpp \
COGLES2ExtensionHandler.cpp \
COGLES2MaterialRenderer.cpp \
COGLES2FixedPipelineRenderer.cpp \
COGLES2NormalMapRenderer.cpp \
COGLES2ParallaxMapRenderer.cpp \
COGLES2Renderer2D.cpp \
COGLESDriver.cpp \
COGLESExtensionHandler.cpp \
COgreMeshFileLoader.cpp \
COpenGLCacheHandler.cpp \
COpenGLDriver.cpp \
COpenGLExtensionHandler.cpp \
COpenGLNormalMapRenderer.cpp \
COpenGLParallaxMapRenderer.cpp \
COpenGLShaderMaterialRenderer.cpp \
COpenGLSLMaterialRenderer.cpp \
COSOperator.cpp \
CPakReader.cpp \
CParticleAnimatedMeshSceneNodeEmitter.cpp \
CParticleAttractionAffector.cpp \
CParticleBoxEmitter.cpp \
CParticleCylinderEmitter.cpp \
CParticleFadeOutAffector.cpp \
CParticleGravityAffector.cpp \
CParticleMeshEmitter.cpp \
CParticlePointEmitter.cpp \
CParticleRingEmitter.cpp \
CParticleRotationAffector.cpp \
CParticleScaleAffector.cpp \
CParticleSphereEmitter.cpp \
CParticleSystemSceneNode.cpp \
CPLYMeshFileLoader.cpp \
CPLYMeshWriter.cpp \
CProfiler.cpp \
CQ3LevelMesh.cpp \
CQuake3ShaderSceneNode.cpp \
CReadFile.cpp \
CSceneCollisionManager.cpp \
CSceneLoaderIrr.cpp \
CSceneManager.cpp \
CSceneNodeAnimatorCameraFPS.cpp \
CSceneNodeAnimatorCameraMaya.cpp \
CSceneNodeAnimatorCollisionResponse.cpp \
CSceneNodeAnimatorDelete.cpp \
CSceneNodeAnimatorFlyCircle.cpp \
CSceneNodeAnimatorFlyStraight.cpp \
CSceneNodeAnimatorFollowSpline.cpp \
CSceneNodeAnimatorRotation.cpp \
CSceneNodeAnimatorTexture.cpp \
CShadowVolumeSceneNode.cpp \
CSkinnedMesh.cpp \
CSkyBoxSceneNode.cpp \
CSkyDomeSceneNode.cpp \
CSMFMeshFileLoader.cpp \
CSoftwareDriver.cpp \
CSoftwareDriver2.cpp \
CSoftwareTexture.cpp \
CSoftwareTexture2.cpp \
CSphereSceneNode.cpp \
CSTLMeshFileLoader.cpp \
CSTLMeshWriter.cpp \
CTarReader.cpp \
CTerrainSceneNode.cpp \
CTerrainTriangleSelector.cpp \
CTextSceneNode.cpp \
CTRFlat.cpp \
CTRFlatWire.cpp \
CTRGouraud.cpp \
CTRGouraud2.cpp \
CTRGouraudAlpha2.cpp \
CTRGouraudAlphaNoZ2.cpp \
CTRGouraudWire.cpp \
CTriangleBBSelector.cpp \
CTriangleSelector.cpp \
CTRNormalMap.cpp \
CTRStencilShadow.cpp \
CTRTextureBlend.cpp \
CTRTextureDetailMap2.cpp \
CTRTextureFlat.cpp \
CTRTextureFlatWire.cpp \
CTRTextureGouraud.cpp \
CTRTextureGouraud2.cpp \
CTRTextureGouraudAdd.cpp \
CTRTextureGouraudAdd2.cpp \
CTRTextureGouraudAddNoZ2.cpp \
CTRTextureGouraudAlpha.cpp \
CTRTextureGouraudAlphaNoZ.cpp \
CTRTextureGouraudNoZ.cpp \
CTRTextureGouraudNoZ2.cpp \
CTRTextureGouraudVertexAlpha2.cpp \
CTRTextureGouraudWire.cpp \
CTRTextureLightMap2_Add.cpp \
CTRTextureLightMap2_M1.cpp \
CTRTextureLightMap2_M2.cpp \
CTRTextureLightMap2_M4.cpp \
CTRTextureLightMapGouraud2_M4.cpp \
CTRTextureWire2.cpp \
CVideoModeList.cpp \
CVolumeLightSceneNode.cpp \
CWADReader.cpp \
CWaterSurfaceSceneNode.cpp \
CWriteFile.cpp \
CXMeshFileLoader.cpp \
CXMLReader.cpp \
CXMLWriter.cpp \
CZBuffer.cpp \
CZipReader.cpp \
IBurningShader.cpp \
Irrlicht.cpp \
irrXML.cpp \
os.cpp \
bzip2/blocksort.c \
bzip2/bzcompress.c \
bzip2/bzlib.c \
bzip2/crctable.c \
bzip2/decompress.c \
bzip2/huffman.c \
bzip2/randtable.c \
jpeglib/jaricom.c \
jpeglib/jcapimin.c \
jpeglib/jcapistd.c \
jpeglib/jcarith.c \
jpeglib/jccoefct.c \
jpeglib/jccolor.c \
jpeglib/jcdctmgr.c \
jpeglib/jchuff.c \
jpeglib/jcinit.c \
jpeglib/jcmainct.c \
jpeglib/jcmarker.c \
jpeglib/jcmaster.c \
jpeglib/jcomapi.c \
jpeglib/jcparam.c \
jpeglib/jcprepct.c \
jpeglib/jcsample.c \
jpeglib/jctrans.c \
jpeglib/jdapimin.c \
jpeglib/jdapistd.c \
jpeglib/jdarith.c \
jpeglib/jdatadst.c \
jpeglib/jdatasrc.c \
jpeglib/jdcoefct.c \
jpeglib/jdcolor.c \
jpeglib/jddctmgr.c \
jpeglib/jdhuff.c \
jpeglib/jdinput.c \
jpeglib/jdmainct.c \
jpeglib/jdmarker.c \
jpeglib/jdmaster.c \
jpeglib/jdmerge.c \
jpeglib/jdpostct.c \
jpeglib/jdsample.c \
jpeglib/jdtrans.c \
jpeglib/jerror.c \
jpeglib/jfdctflt.c \
jpeglib/jfdctfst.c \
jpeglib/jfdctint.c \
jpeglib/jidctflt.c \
jpeglib/jidctfst.c \
jpeglib/jidctint.c \
jpeglib/jmemmgr.c \
jpeglib/jmemnobs.c \
jpeglib/jquant1.c \
jpeglib/jquant2.c \
jpeglib/jutils.c \
libpng/png.c \
libpng/pngerror.c \
libpng/pngget.c \
libpng/pngmem.c \
libpng/pngpread.c \
libpng/pngread.c \
libpng/pngrio.c \
libpng/pngrtran.c \
libpng/pngrutil.c \
libpng/pngset.c \
libpng/pngtrans.c \
libpng/pngwio.c \
libpng/pngwrite.c \
libpng/pngwtran.c \
libpng/pngwutil.c \
lzma/LzmaDec.c \
zlib/adler32.c zlib/crc32.c zlib/gzclose.c zlib/gzread.c zlib/infback.c zlib/inflate.c zlib/trees.c zlib/zutil.c\
zlib/compress.c zlib/deflate.c zlib/gzlib.c zlib/gzwrite.c zlib/inffast.c zlib/inftrees.c zlib/uncompr.c
LOCAL_STATIC_LIBRARIES := android_native_app_glue
include $(BUILD_STATIC_LIBRARY)
$(call import-module,android/native_app_glue)
all: $(IRRLICHT_LIB_PATH)
$(IRRLICHT_LIB_PATH) : $(TARGET_OUT)/$(IRRLICHT_LIB_NAME)
cp $< $@

View File

@ -0,0 +1,2 @@
APP_PLATFORM := android-10
APP_MODULES := Irrlicht

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,166 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_3DS_MESH_FILE_LOADER_H_INCLUDED__
#define __C_3DS_MESH_FILE_LOADER_H_INCLUDED__
#include "IMeshLoader.h"
#include "IFileSystem.h"
#include "ISceneManager.h"
#include "irrString.h"
#include "SMesh.h"
#include "matrix4.h"
namespace irr
{
namespace scene
{
//! Meshloader capable of loading 3ds meshes.
class C3DSMeshFileLoader : public IMeshLoader
{
public:
//! Constructor
C3DSMeshFileLoader(ISceneManager* smgr, io::IFileSystem* fs);
//! destructor
virtual ~C3DSMeshFileLoader();
//! returns true if the file maybe is able to be loaded by this class
//! based on the file extension (e.g. ".cob")
virtual bool isALoadableFileExtension(const io::path& filename) const _IRR_OVERRIDE_;
//! creates/loads an animated mesh from the file.
//! \return Pointer to the created mesh. Returns 0 if loading failed.
//! If you no longer need the mesh, you should call IAnimatedMesh::drop().
//! See IReferenceCounted::drop() for more information.
virtual IAnimatedMesh* createMesh(io::IReadFile* file) _IRR_OVERRIDE_;
private:
// byte-align structures
#include "irrpack.h"
struct ChunkHeader
{
u16 id;
s32 length;
} PACK_STRUCT;
// Default alignment
#include "irrunpack.h"
struct ChunkData
{
ChunkData() : read(0) {}
ChunkHeader header;
s32 read;
};
struct SCurrentMaterial
{
void clear() {
Material=video::SMaterial();
Name="";
Filename[0]="";
Filename[1]="";
Filename[2]="";
Filename[3]="";
Filename[4]="";
Strength[0]=0.f;
Strength[1]=0.f;
Strength[2]=0.f;
Strength[3]=0.f;
Strength[4]=0.f;
}
video::SMaterial Material;
core::stringc Name;
core::stringc Filename[5];
f32 Strength[5];
};
struct SMaterialGroup
{
SMaterialGroup() : faceCount(0), faces(0) {};
SMaterialGroup(const SMaterialGroup& o)
{
*this = o;
}
~SMaterialGroup()
{
clear();
}
void clear()
{
delete [] faces;
faces = 0;
faceCount = 0;
}
void operator =(const SMaterialGroup& o)
{
MaterialName = o.MaterialName;
faceCount = o.faceCount;
faces = new u16[faceCount];
for (u16 i=0; i<faceCount; ++i)
faces[i] = o.faces[i];
}
core::stringc MaterialName;
u16 faceCount;
u16* faces;
};
bool readChunk(io::IReadFile* file, ChunkData* parent);
bool readMaterialChunk(io::IReadFile* file, ChunkData* parent);
bool readFrameChunk(io::IReadFile* file, ChunkData* parent);
bool readTrackChunk(io::IReadFile* file, ChunkData& data,
IMeshBuffer* mb, const core::vector3df& pivot);
bool readObjectChunk(io::IReadFile* file, ChunkData* parent);
bool readPercentageChunk(io::IReadFile* file, ChunkData* chunk, f32& percentage);
bool readColorChunk(io::IReadFile* file, ChunkData* chunk, video::SColor& out);
void readChunkData(io::IReadFile* file, ChunkData& data);
void readString(io::IReadFile* file, ChunkData& data, core::stringc& out);
void readVertices(io::IReadFile* file, ChunkData& data);
void readIndices(io::IReadFile* file, ChunkData& data);
void readMaterialGroup(io::IReadFile* file, ChunkData& data);
void readTextureCoords(io::IReadFile* file, ChunkData& data);
void composeObject(io::IReadFile* file, const core::stringc& name);
void loadMaterials(io::IReadFile* file);
void cleanUp();
scene::ISceneManager* SceneManager;
io::IFileSystem* FileSystem;
f32* Vertices;
u16* Indices;
u32* SmoothingGroups;
core::array<u16> TempIndices;
f32* TCoords;
u16 CountVertices;
u16 CountFaces; // = CountIndices/4
u16 CountTCoords;
core::array<SMaterialGroup> MaterialGroups;
SCurrentMaterial CurrentMaterial;
core::array<SCurrentMaterial> Materials;
core::array<core::stringc> MeshBufferNames;
core::matrix4 TransformationMatrix;
SMesh* Mesh;
};
} // end namespace scene
} // end namespace irr
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,630 @@
// Copyright (C) 2002-2012 Thomas Alten
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_ANIMATED_MESH_HALFLIFE_H_INCLUDED__
#define __C_ANIMATED_MESH_HALFLIFE_H_INCLUDED__
#include "IAnimatedMesh.h"
#include "ISceneManager.h"
#include "irrArray.h"
#include "irrString.h"
#include "IMeshLoader.h"
#include "SMesh.h"
#include "IReadFile.h"
namespace irr
{
namespace scene
{
// STUDIO MODELS, Copyright (c) 1998, Valve LLC. All rights reserved.
#define MAXSTUDIOTRIANGLES 20000 // TODO: tune this
#define MAXSTUDIOVERTS 2048 // TODO: tune this
#define MAXSTUDIOSEQUENCES 256 // total animation sequences
#define MAXSTUDIOSKINS 100 // total textures
#define MAXSTUDIOSRCBONES 512 // bones allowed at source movement
#define MAXSTUDIOBONES 128 // total bones actually used
#define MAXSTUDIOMODELS 32 // sub-models per model
#define MAXSTUDIOBODYPARTS 32
#define MAXSTUDIOGROUPS 4
#define MAXSTUDIOANIMATIONS 512 // per sequence
#define MAXSTUDIOMESHES 256
#define MAXSTUDIOEVENTS 1024
#define MAXSTUDIOPIVOTS 256
#define MAXSTUDIOCONTROLLERS 8
typedef f32 vec3_hl[3]; // x,y,z
typedef f32 vec4_hl[4]; // x,y,z,w
// byte-align structures
#include "irrpack.h"
struct SHalflifeHeader
{
c8 id[4];
s32 version;
c8 name[64];
s32 length;
vec3_hl eyeposition; // ideal eye position
vec3_hl min; // ideal movement hull size
vec3_hl max;
vec3_hl bbmin; // clipping bounding box
vec3_hl bbmax;
s32 flags;
u32 numbones; // bones
u32 boneindex;
u32 numbonecontrollers; // bone controllers
u32 bonecontrollerindex;
u32 numhitboxes; // complex bounding boxes
u32 hitboxindex;
u32 numseq; // animation sequences
u32 seqindex;
u32 numseqgroups; // demand loaded sequences
u32 seqgroupindex;
u32 numtextures; // raw textures
u32 textureindex;
u32 texturedataindex;
u32 numskinref; // replaceable textures
u32 numskinfamilies;
u32 skinindex;
u32 numbodyparts;
u32 bodypartindex;
u32 numattachments; // queryable attachable points
u32 attachmentindex;
s32 soundtable;
s32 soundindex;
s32 soundgroups;
s32 soundgroupindex;
s32 numtransitions; // animation node to animation node transition graph
s32 transitionindex;
} PACK_STRUCT;
// header for demand loaded sequence group data
struct studioseqhdr_t
{
s32 id;
s32 version;
c8 name[64];
s32 length;
} PACK_STRUCT;
// bones
struct SHalflifeBone
{
c8 name[32]; // bone name for symbolic links
s32 parent; // parent bone
s32 flags; // ??
s32 bonecontroller[6]; // bone controller index, -1 == none
f32 value[6]; // default DoF values
f32 scale[6]; // scale for delta DoF values
} PACK_STRUCT;
// bone controllers
struct SHalflifeBoneController
{
s32 bone; // -1 == 0
s32 type; // X, Y, Z, XR, YR, ZR, M
f32 start;
f32 end;
s32 rest; // byte index value at rest
s32 index; // 0-3 user set controller, 4 mouth
} PACK_STRUCT;
// intersection boxes
struct SHalflifeBBox
{
s32 bone;
s32 group; // intersection group
vec3_hl bbmin; // bounding box
vec3_hl bbmax;
} PACK_STRUCT;
#ifndef ZONE_H
// NOTE: this was a void*, but that crashes on 64bit.
// I have found no mdl format desc, so not sure what it's meant to be, but s32 at least works.
typedef s32 cache_user_t;
#endif
// demand loaded sequence groups
struct SHalflifeSequenceGroup
{
c8 label[32]; // textual name
c8 name[64]; // file name
cache_user_t cache; // cache index pointer
s32 data; // hack for group 0
} PACK_STRUCT;
// sequence descriptions
struct SHalflifeSequence
{
c8 label[32]; // sequence label
f32 fps; // frames per second
s32 flags; // looping/non-looping flags
s32 activity;
s32 actweight;
s32 numevents;
s32 eventindex;
s32 numframes; // number of frames per sequence
u32 numpivots; // number of foot pivots
u32 pivotindex;
s32 motiontype;
s32 motionbone;
vec3_hl linearmovement;
s32 automoveposindex;
s32 automoveangleindex;
vec3_hl bbmin; // per sequence bounding box
vec3_hl bbmax;
s32 numblends;
s32 animindex; // SHalflifeAnimOffset pointer relative to start of sequence group data
// [blend][bone][X, Y, Z, XR, YR, ZR]
s32 blendtype[2]; // X, Y, Z, XR, YR, ZR
f32 blendstart[2]; // starting value
f32 blendend[2]; // ending value
s32 blendparent;
s32 seqgroup; // sequence group for demand loading
s32 entrynode; // transition node at entry
s32 exitnode; // transition node at exit
s32 nodeflags; // transition rules
s32 nextseq; // auto advancing sequences
} PACK_STRUCT;
// events
struct mstudioevent_t
{
s32 frame;
s32 event;
s32 type;
c8 options[64];
} PACK_STRUCT;
// pivots
struct mstudiopivot_t
{
vec3_hl org; // pivot point
s32 start;
s32 end;
} PACK_STRUCT;
// attachment
struct SHalflifeAttachment
{
c8 name[32];
s32 type;
s32 bone;
vec3_hl org; // attachment point
vec3_hl vectors[3];
} PACK_STRUCT;
struct SHalflifeAnimOffset
{
u16 offset[6];
} PACK_STRUCT;
// animation frames
union SHalflifeAnimationFrame
{
struct {
u8 valid;
u8 total;
} PACK_STRUCT num;
s16 value;
} PACK_STRUCT;
// body part index
struct SHalflifeBody
{
c8 name[64];
u32 nummodels;
u32 base;
u32 modelindex; // index into models array
} PACK_STRUCT;
// skin info
struct SHalflifeTexture
{
c8 name[64];
s32 flags;
s32 width;
s32 height;
s32 index;
} PACK_STRUCT;
// skin families
// short index[skinfamilies][skinref]
// studio models
struct SHalflifeModel
{
c8 name[64];
s32 type;
f32 boundingradius;
u32 nummesh;
u32 meshindex;
u32 numverts; // number of unique vertices
u32 vertinfoindex; // vertex bone info
u32 vertindex; // vertex vec3_hl
u32 numnorms; // number of unique surface normals
u32 norminfoindex; // normal bone info
u32 normindex; // normal vec3_hl
u32 numgroups; // deformation groups
u32 groupindex;
} PACK_STRUCT;
// meshes
struct SHalflifeMesh
{
u32 numtris;
u32 triindex;
u32 skinref;
u32 numnorms; // per mesh normals
u32 normindex; // normal vec3_hl
} PACK_STRUCT;
// Default alignment
#include "irrunpack.h"
// lighting options
#define STUDIO_NF_FLATSHADE 0x0001
#define STUDIO_NF_CHROME 0x0002
#define STUDIO_NF_FULLBRIGHT 0x0004
// motion flags
#define STUDIO_X 0x0001
#define STUDIO_Y 0x0002
#define STUDIO_Z 0x0004
#define STUDIO_XR 0x0008
#define STUDIO_YR 0x0010
#define STUDIO_ZR 0x0020
#define STUDIO_LX 0x0040
#define STUDIO_LY 0x0080
#define STUDIO_LZ 0x0100
#define STUDIO_AX 0x0200
#define STUDIO_AY 0x0400
#define STUDIO_AZ 0x0800
#define STUDIO_AXR 0x1000
#define STUDIO_AYR 0x2000
#define STUDIO_AZR 0x4000
#define STUDIO_TYPES 0x7FFF
#define STUDIO_RLOOP 0x8000 // controller that wraps shortest distance
// sequence flags
#define STUDIO_LOOPING 0x0001
// bone flags
#define STUDIO_HAS_NORMALS 0x0001
#define STUDIO_HAS_VERTICES 0x0002
#define STUDIO_HAS_BBOX 0x0004
#define STUDIO_HAS_CHROME 0x0008 // if any of the textures have chrome on them
#define RAD_TO_STUDIO (32768.0/M_PI)
#define STUDIO_TO_RAD (M_PI/32768.0)
/*!
Textureatlas
Combine Source Images with arbitrary size and bithdepth to an Image with 2^n size
borders from the source images are copied around for allowing filtering ( bilinear, mipmap )
*/
struct STextureAtlas
{
STextureAtlas ()
{
release();
}
virtual ~STextureAtlas ()
{
release ();
}
void release ();
void addSource ( const c8 * name, video::IImage * image );
void create ( u32 pixelborder, video::E_TEXTURE_CLAMP texmode );
void getScale ( core::vector2df &scale );
void getTranslation ( const c8 * name, core::vector2di &pos );
struct TextureAtlasEntry
{
io::path name;
u32 width;
u32 height;
core::vector2di pos;
video::IImage * image;
bool operator < ( const TextureAtlasEntry & other )
{
return height > other.height;
}
};
core::array < TextureAtlasEntry > atlas;
video::IImage * Master;
};
//! Possible types of Animation Type
enum E_ANIMATION_TYPE
{
//! No Animation
EAMT_STILL,
//! From Start to End, then Stop ( Limited Line )
EAMT_WAYPOINT,
//! Linear Cycling Animation ( Sawtooth )
EAMT_LOOPING,
//! Linear bobbing ( Triangle )
EAMT_PINGPONG
};
//! Names for Animation Type
const c8* const MeshAnimationTypeNames[] =
{
"still",
"waypoint",
"looping",
"pingpong",
0
};
//! Data for holding named Animation Info
struct KeyFrameInterpolation
{
core::stringc Name; // Name of the current Animation/Bone
E_ANIMATION_TYPE AnimationType; // Type of Animation ( looping, usw..)
f32 CurrentFrame; // Current Frame
s32 NextFrame; // Frame which will be used next. For blending
s32 StartFrame; // Absolute Frame where the current animation start
s32 Frames; // Relative Frames how much Frames this animation have
s32 LoopingFrames; // How much of Frames sould be looped
s32 EndFrame; // Absolute Frame where the current animation ends End = start + frames - 1
f32 FramesPerSecond; // Speed in Frames/Seconds the animation is played
f32 RelativeSpeed; // Factor Original fps is modified
u32 BeginTime; // Animation started at this thime
u32 EndTime; // Animation end at this time
u32 LastTime; // Last Keyframe was done at this time
KeyFrameInterpolation ( const c8 * name = "", s32 start = 0, s32 frames = 0, s32 loopingframes = 0,
f32 fps = 0.f, f32 relativefps = 1.f )
: Name ( name ), AnimationType ( loopingframes ? EAMT_LOOPING : EAMT_WAYPOINT),
CurrentFrame ( (f32) start ), NextFrame ( start ), StartFrame ( start ),
Frames ( frames ), LoopingFrames ( loopingframes ), EndFrame ( start + frames - 1 ),
FramesPerSecond ( fps ), RelativeSpeed ( relativefps ),
BeginTime ( 0 ), EndTime ( 0 ), LastTime ( 0 )
{
}
// linear search
bool operator == ( const KeyFrameInterpolation & other ) const
{
return Name.equals_ignore_case ( other.Name );
}
};
//! a List holding named Animations
typedef core::array < KeyFrameInterpolation > IAnimationList;
//! a List holding named Skins
typedef core::array < core::stringc > ISkinList;
// Current Model per Body
struct SubModel
{
core::stringc name;
u32 startBuffer;
u32 endBuffer;
u32 state;
};
struct BodyPart
{
core::stringc name;
u32 defaultModel;
core::array < SubModel > model;
};
//! a List holding named Models and SubModels
typedef core::array < BodyPart > IBodyList;
class CAnimatedMeshHalfLife : public IAnimatedMesh
{
public:
//! constructor
CAnimatedMeshHalfLife();
//! destructor
virtual ~CAnimatedMeshHalfLife();
//! loads a Halflife mdl file
bool loadModelFile( io::IReadFile* file, ISceneManager * smgr );
//IAnimatedMesh
virtual u32 getFrameCount() const _IRR_OVERRIDE_;
virtual IMesh* getMesh(s32 frame, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop) _IRR_OVERRIDE_;
virtual const core::aabbox3d<f32>& getBoundingBox() const _IRR_OVERRIDE_;
virtual E_ANIMATED_MESH_TYPE getMeshType() const _IRR_OVERRIDE_;
void renderModel ( u32 param, video::IVideoDriver * driver, const core::matrix4 &absoluteTransformation);
//! returns amount of mesh buffers.
virtual u32 getMeshBufferCount() const _IRR_OVERRIDE_;
//! returns pointer to a mesh buffer
virtual IMeshBuffer* getMeshBuffer(u32 nr) const _IRR_OVERRIDE_;
//! Returns pointer to a mesh buffer which fits a material
virtual IMeshBuffer* getMeshBuffer( const video::SMaterial &material) const _IRR_OVERRIDE_;
virtual void setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue) _IRR_OVERRIDE_;
//! set the hardware mapping hint, for driver
virtual void setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint, E_BUFFER_TYPE buffer=EBT_VERTEX_AND_INDEX) _IRR_OVERRIDE_;
//! flags the meshbuffer as changed, reloads hardware buffers
virtual void setDirty(E_BUFFER_TYPE buffer=EBT_VERTEX_AND_INDEX) _IRR_OVERRIDE_;
//! set user axis aligned bounding box
virtual void setBoundingBox(const core::aabbox3df& box) _IRR_OVERRIDE_;
//! Gets the default animation speed of the animated mesh.
/** \return Amount of frames per second. If the amount is 0, it is a static, non animated mesh. */
virtual f32 getAnimationSpeed() const _IRR_OVERRIDE_
{
return FramesPerSecond;
}
//! Gets the frame count of the animated mesh.
/** \param fps Frames per second to play the animation with. If the amount is 0, it is not animated.
The actual speed is set in the scene node the mesh is instantiated in.*/
virtual void setAnimationSpeed(f32 fps) _IRR_OVERRIDE_
{
FramesPerSecond=fps;
}
//! Get the Animation List
IAnimationList* getAnimList () { return &AnimList; }
//! Return the named Body List of this Animated Mesh
IBodyList *getBodyList() { return &BodyList; }
private:
// KeyFrame Animation List
IAnimationList AnimList;
// Sum of all sequences
u32 FrameCount;
// Named meshes of the Body
IBodyList BodyList;
//! return a Mesh per frame
SMesh* MeshIPol;
ISceneManager *SceneManager;
SHalflifeHeader *Header;
SHalflifeHeader *TextureHeader;
bool OwnTexModel; // do we have a modelT.mdl ?
SHalflifeHeader *AnimationHeader[32]; // sequences named model01.mdl, model02.mdl
void initData ();
SHalflifeHeader * loadModel( io::IReadFile* file, const io::path &filename );
bool postLoadModel( const io::path &filename );
u32 SequenceIndex; // sequence index
f32 CurrentFrame; // Current Frame
f32 FramesPerSecond;
#define MOUTH_CONTROLLER 4
u8 BoneController[4 + 1 ]; // bone controllers + mouth position
u8 Blending[2]; // animation blending
vec4_hl BoneAdj;
f32 SetController( s32 controllerIndex, f32 value );
u32 SkinGroupSelection; // skin group selection
u32 SetSkin( u32 value );
void initModel();
void dumpModelInfo(u32 level) const;
void ExtractBbox(s32 sequence, core::aabbox3df &box) const;
void setUpBones ();
SHalflifeAnimOffset * getAnim( SHalflifeSequence *seq );
void slerpBones( vec4_hl q1[], vec3_hl pos1[], vec4_hl q2[], vec3_hl pos2[], f32 s );
void calcRotations ( vec3_hl *pos, vec4_hl *q, SHalflifeSequence *seq, SHalflifeAnimOffset *anim, f32 f );
void calcBoneAdj();
void calcBoneQuaternion(const s32 frame, const SHalflifeBone *bone, SHalflifeAnimOffset *anim, const u32 j, f32& angle1, f32& angle2) const;
void calcBonePosition(const s32 frame, f32 s, const SHalflifeBone *bone, SHalflifeAnimOffset *anim, f32 *pos ) const;
void buildVertices ();
io::path TextureBaseName;
#define HL_TEXTURE_ATLAS
#ifdef HL_TEXTURE_ATLAS
STextureAtlas TextureAtlas;
// video::ITexture *TextureMaster;
#endif
};
//! Meshloader capable of loading HalfLife Model files
class CHalflifeMDLMeshFileLoader : public IMeshLoader
{
public:
//! Constructor
CHalflifeMDLMeshFileLoader( scene::ISceneManager* smgr );
//! returns true if the file maybe is able to be loaded by this class
/** based on the file extension (e.g. ".bsp") */
virtual bool isALoadableFileExtension(const io::path& filename) const _IRR_OVERRIDE_;
//! creates/loads an animated mesh from the file.
/** \return Pointer to the created mesh. Returns 0 if loading failed.
If you no longer need the mesh, you should call IAnimatedMesh::drop().
See IReferenceCounted::drop() for more information.
*/
virtual IAnimatedMesh* createMesh(io::IReadFile* file) _IRR_OVERRIDE_;
private:
scene::ISceneManager* SceneManager;
};
} // end namespace scene
} // end namespace irr
#endif

View File

@ -0,0 +1,465 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_MD2_LOADER_
#include "CAnimatedMeshMD2.h"
#include "SColor.h"
#include "irrMath.h"
namespace irr
{
namespace scene
{
const s32 MD2_FRAME_SHIFT = 2;
const f32 MD2_FRAME_SHIFT_RECIPROCAL = 1.f / (1 << MD2_FRAME_SHIFT);
const s32 Q2_VERTEX_NORMAL_TABLE_SIZE = 162;
static const f32 Q2_VERTEX_NORMAL_TABLE[Q2_VERTEX_NORMAL_TABLE_SIZE][3] = {
{-0.525731f, 0.000000f, 0.850651f},
{-0.442863f, 0.238856f, 0.864188f},
{-0.295242f, 0.000000f, 0.955423f},
{-0.309017f, 0.500000f, 0.809017f},
{-0.162460f, 0.262866f, 0.951056f},
{0.000000f, 0.000000f, 1.000000f},
{0.000000f, 0.850651f, 0.525731f},
{-0.147621f, 0.716567f, 0.681718f},
{0.147621f, 0.716567f, 0.681718f},
{0.000000f, 0.525731f, 0.850651f},
{0.309017f, 0.500000f, 0.809017f},
{0.525731f, 0.000000f, 0.850651f},
{0.295242f, 0.000000f, 0.955423f},
{0.442863f, 0.238856f, 0.864188f},
{0.162460f, 0.262866f, 0.951056f},
{-0.681718f, 0.147621f, 0.716567f},
{-0.809017f, 0.309017f, 0.500000f},
{-0.587785f, 0.425325f, 0.688191f},
{-0.850651f, 0.525731f, 0.000000f},
{-0.864188f, 0.442863f, 0.238856f},
{-0.716567f, 0.681718f, 0.147621f},
{-0.688191f, 0.587785f, 0.425325f},
{-0.500000f, 0.809017f, 0.309017f},
{-0.238856f, 0.864188f, 0.442863f},
{-0.425325f, 0.688191f, 0.587785f},
{-0.716567f, 0.681718f, -0.147621f},
{-0.500000f, 0.809017f, -0.309017f},
{-0.525731f, 0.850651f, 0.000000f},
{0.000000f, 0.850651f, -0.525731f},
{-0.238856f, 0.864188f, -0.442863f},
{0.000000f, 0.955423f, -0.295242f},
{-0.262866f, 0.951056f, -0.162460f},
{0.000000f, 1.000000f, 0.000000f},
{0.000000f, 0.955423f, 0.295242f},
{-0.262866f, 0.951056f, 0.162460f},
{0.238856f, 0.864188f, 0.442863f},
{0.262866f, 0.951056f, 0.162460f},
{0.500000f, 0.809017f, 0.309017f},
{0.238856f, 0.864188f, -0.442863f},
{0.262866f, 0.951056f, -0.162460f},
{0.500000f, 0.809017f, -0.309017f},
{0.850651f, 0.525731f, 0.000000f},
{0.716567f, 0.681718f, 0.147621f},
{0.716567f, 0.681718f, -0.147621f},
{0.525731f, 0.850651f, 0.000000f},
{0.425325f, 0.688191f, 0.587785f},
{0.864188f, 0.442863f, 0.238856f},
{0.688191f, 0.587785f, 0.425325f},
{0.809017f, 0.309017f, 0.500000f},
{0.681718f, 0.147621f, 0.716567f},
{0.587785f, 0.425325f, 0.688191f},
{0.955423f, 0.295242f, 0.000000f},
{1.000000f, 0.000000f, 0.000000f},
{0.951056f, 0.162460f, 0.262866f},
{0.850651f, -0.525731f, 0.000000f},
{0.955423f, -0.295242f, 0.000000f},
{0.864188f, -0.442863f, 0.238856f},
{0.951056f, -0.162460f, 0.262866f},
{0.809017f, -0.309017f, 0.500000f},
{0.681718f, -0.147621f, 0.716567f},
{0.850651f, 0.000000f, 0.525731f},
{0.864188f, 0.442863f, -0.238856f},
{0.809017f, 0.309017f, -0.500000f},
{0.951056f, 0.162460f, -0.262866f},
{0.525731f, 0.000000f, -0.850651f},
{0.681718f, 0.147621f, -0.716567f},
{0.681718f, -0.147621f, -0.716567f},
{0.850651f, 0.000000f, -0.525731f},
{0.809017f, -0.309017f, -0.500000f},
{0.864188f, -0.442863f, -0.238856f},
{0.951056f, -0.162460f, -0.262866f},
{0.147621f, 0.716567f, -0.681718f},
{0.309017f, 0.500000f, -0.809017f},
{0.425325f, 0.688191f, -0.587785f},
{0.442863f, 0.238856f, -0.864188f},
{0.587785f, 0.425325f, -0.688191f},
{0.688191f, 0.587785f, -0.425325f},
{-0.147621f, 0.716567f, -0.681718f},
{-0.309017f, 0.500000f, -0.809017f},
{0.000000f, 0.525731f, -0.850651f},
{-0.525731f, 0.000000f, -0.850651f},
{-0.442863f, 0.238856f, -0.864188f},
{-0.295242f, 0.000000f, -0.955423f},
{-0.162460f, 0.262866f, -0.951056f},
{0.000000f, 0.000000f, -1.000000f},
{0.295242f, 0.000000f, -0.955423f},
{0.162460f, 0.262866f, -0.951056f},
{-0.442863f, -0.238856f, -0.864188f},
{-0.309017f, -0.500000f, -0.809017f},
{-0.162460f, -0.262866f, -0.951056f},
{0.000000f, -0.850651f, -0.525731f},
{-0.147621f, -0.716567f, -0.681718f},
{0.147621f, -0.716567f, -0.681718f},
{0.000000f, -0.525731f, -0.850651f},
{0.309017f, -0.500000f, -0.809017f},
{0.442863f, -0.238856f, -0.864188f},
{0.162460f, -0.262866f, -0.951056f},
{0.238856f, -0.864188f, -0.442863f},
{0.500000f, -0.809017f, -0.309017f},
{0.425325f, -0.688191f, -0.587785f},
{0.716567f, -0.681718f, -0.147621f},
{0.688191f, -0.587785f, -0.425325f},
{0.587785f, -0.425325f, -0.688191f},
{0.000000f, -0.955423f, -0.295242f},
{0.000000f, -1.000000f, 0.000000f},
{0.262866f, -0.951056f, -0.162460f},
{0.000000f, -0.850651f, 0.525731f},
{0.000000f, -0.955423f, 0.295242f},
{0.238856f, -0.864188f, 0.442863f},
{0.262866f, -0.951056f, 0.162460f},
{0.500000f, -0.809017f, 0.309017f},
{0.716567f, -0.681718f, 0.147621f},
{0.525731f, -0.850651f, 0.000000f},
{-0.238856f, -0.864188f, -0.442863f},
{-0.500000f, -0.809017f, -0.309017f},
{-0.262866f, -0.951056f, -0.162460f},
{-0.850651f, -0.525731f, 0.000000f},
{-0.716567f, -0.681718f, -0.147621f},
{-0.716567f, -0.681718f, 0.147621f},
{-0.525731f, -0.850651f, 0.000000f},
{-0.500000f, -0.809017f, 0.309017f},
{-0.238856f, -0.864188f, 0.442863f},
{-0.262866f, -0.951056f, 0.162460f},
{-0.864188f, -0.442863f, 0.238856f},
{-0.809017f, -0.309017f, 0.500000f},
{-0.688191f, -0.587785f, 0.425325f},
{-0.681718f, -0.147621f, 0.716567f},
{-0.442863f, -0.238856f, 0.864188f},
{-0.587785f, -0.425325f, 0.688191f},
{-0.309017f, -0.500000f, 0.809017f},
{-0.147621f, -0.716567f, 0.681718f},
{-0.425325f, -0.688191f, 0.587785f},
{-0.162460f, -0.262866f, 0.951056f},
{0.442863f, -0.238856f, 0.864188f},
{0.162460f, -0.262866f, 0.951056f},
{0.309017f, -0.500000f, 0.809017f},
{0.147621f, -0.716567f, 0.681718f},
{0.000000f, -0.525731f, 0.850651f},
{0.425325f, -0.688191f, 0.587785f},
{0.587785f, -0.425325f, 0.688191f},
{0.688191f, -0.587785f, 0.425325f},
{-0.955423f, 0.295242f, 0.000000f},
{-0.951056f, 0.162460f, 0.262866f},
{-1.000000f, 0.000000f, 0.000000f},
{-0.850651f, 0.000000f, 0.525731f},
{-0.955423f, -0.295242f, 0.000000f},
{-0.951056f, -0.162460f, 0.262866f},
{-0.864188f, 0.442863f, -0.238856f},
{-0.951056f, 0.162460f, -0.262866f},
{-0.809017f, 0.309017f, -0.500000f},
{-0.864188f, -0.442863f, -0.238856f},
{-0.951056f, -0.162460f, -0.262866f},
{-0.809017f, -0.309017f, -0.500000f},
{-0.681718f, 0.147621f, -0.716567f},
{-0.681718f, -0.147621f, -0.716567f},
{-0.850651f, 0.000000f, -0.525731f},
{-0.688191f, 0.587785f, -0.425325f},
{-0.587785f, 0.425325f, -0.688191f},
{-0.425325f, 0.688191f, -0.587785f},
{-0.425325f, -0.688191f, -0.587785f},
{-0.587785f, -0.425325f, -0.688191f},
{-0.688191f, -0.587785f, -0.425325f},
};
struct SMD2AnimationType
{
s32 begin;
s32 end;
s32 fps;
};
static const SMD2AnimationType MD2AnimationTypeList[21] =
{
{ 0, 39, 9}, // STAND
{ 40, 45, 10}, // RUN
{ 46, 53, 10}, // ATTACK
{ 54, 57, 7}, // PAIN_A
{ 58, 61, 7}, // PAIN_B
{ 62, 65, 7}, // PAIN_C
{ 66, 71, 7}, // JUMP
{ 72, 83, 7}, // FLIP
{ 84, 94, 7}, // SALUTE
{ 95, 111, 10}, // FALLBACK
{112, 122, 7}, // WAVE
{123, 134, 6}, // POINT
{135, 153, 10}, // CROUCH_STAND
{154, 159, 7}, // CROUCH_WALK
{160, 168, 10}, // CROUCH_ATTACK
{169, 172, 7}, // CROUCH_PAIN
{173, 177, 5}, // CROUCH_DEATH
{178, 183, 7}, // DEATH_FALLBACK
{184, 189, 7}, // DEATH_FALLFORWARD
{190, 197, 7}, // DEATH_FALLBACKSLOW
{198, 198, 5}, // BOOM
};
//! constructor
CAnimatedMeshMD2::CAnimatedMeshMD2()
: InterpolationBuffer(0), InterpolationFirstFrame(-1), InterpolationSecondFrame(-1), InterpolationFrameDiv(0.f)
, FrameList(0), FrameCount(0), FramesPerSecond((f32)(MD2AnimationTypeList[0].fps << MD2_FRAME_SHIFT))
{
#ifdef _DEBUG
IAnimatedMesh::setDebugName("CAnimatedMeshMD2 IAnimatedMesh");
IMesh::setDebugName("CAnimatedMeshMD2 IMesh");
#endif
InterpolationBuffer = new SMeshBuffer;
}
//! destructor
CAnimatedMeshMD2::~CAnimatedMeshMD2()
{
delete [] FrameList;
if (InterpolationBuffer)
InterpolationBuffer->drop();
}
//! returns the amount of frames in milliseconds. If the amount is 1, it is a static (=non animated) mesh.
u32 CAnimatedMeshMD2::getFrameCount() const
{
return FrameCount<<MD2_FRAME_SHIFT;
}
//! returns the animated mesh based on a detail level. 0 is the lowest, 255 the highest detail. Note, that some Meshes will ignore the detail level.
IMesh* CAnimatedMeshMD2::getMesh(s32 frame, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop)
{
if ((u32)frame > getFrameCount())
frame = (frame % getFrameCount());
if (startFrameLoop == -1 && endFrameLoop == -1)
{
startFrameLoop = 0;
endFrameLoop = getFrameCount();
}
updateInterpolationBuffer(frame, startFrameLoop, endFrameLoop);
return this;
}
//! returns amount of mesh buffers. MD2 meshes only have one buffer
u32 CAnimatedMeshMD2::getMeshBufferCount() const
{
return 1;
}
//! returns pointer to a mesh buffer
IMeshBuffer* CAnimatedMeshMD2::getMeshBuffer(u32 nr) const
{
if (nr == 0)
return InterpolationBuffer;
else
return 0;
}
//! Returns pointer to a mesh buffer which fits a material
IMeshBuffer* CAnimatedMeshMD2::getMeshBuffer(const video::SMaterial &material) const
{
if (InterpolationBuffer->Material == material)
return InterpolationBuffer;
else
return 0;
}
// updates the interpolation buffer
void CAnimatedMeshMD2::updateInterpolationBuffer(s32 frame, s32 startFrameLoop, s32 endFrameLoop)
{
u32 firstFrame, secondFrame;
f32 div;
// TA: resolve missing ipol in loop between end-start
if (endFrameLoop - startFrameLoop == 0)
{
firstFrame = frame>>MD2_FRAME_SHIFT;
secondFrame = frame>>MD2_FRAME_SHIFT;
div = 1.0f;
}
else
{
// key frames
u32 s = startFrameLoop >> MD2_FRAME_SHIFT;
u32 e = endFrameLoop >> MD2_FRAME_SHIFT;
firstFrame = frame >> MD2_FRAME_SHIFT;
secondFrame = core::if_c_a_else_b(firstFrame + 1 > e, s, firstFrame + 1);
firstFrame = core::s32_min(FrameCount - 1, firstFrame);
secondFrame = core::s32_min(FrameCount - 1, secondFrame);
//div = (frame % (1<<MD2_FRAME_SHIFT)) / (f32)(1<<MD2_FRAME_SHIFT);
frame &= (1<<MD2_FRAME_SHIFT) - 1;
div = frame * MD2_FRAME_SHIFT_RECIPROCAL;
}
if ( firstFrame != InterpolationFirstFrame || secondFrame != InterpolationSecondFrame || div != InterpolationFrameDiv )
{
InterpolationFirstFrame = firstFrame;
InterpolationSecondFrame = secondFrame;
InterpolationFrameDiv = div;
video::S3DVertex* target = static_cast<video::S3DVertex*>(InterpolationBuffer->getVertices());
SMD2Vert* first = FrameList[firstFrame].pointer();
SMD2Vert* second = FrameList[secondFrame].pointer();
// interpolate both frames
const u32 count = FrameList[firstFrame].size();
for (u32 i=0; i<count; ++i)
{
const core::vector3df one = core::vector3df(f32(first->Pos.X) * FrameTransforms[firstFrame].scale.X + FrameTransforms[firstFrame].translate.X,
f32(first->Pos.Y) * FrameTransforms[firstFrame].scale.Y + FrameTransforms[firstFrame].translate.Y,
f32(first->Pos.Z) * FrameTransforms[firstFrame].scale.Z + FrameTransforms[firstFrame].translate.Z);
const core::vector3df two = core::vector3df(f32(second->Pos.X) * FrameTransforms[secondFrame].scale.X + FrameTransforms[secondFrame].translate.X,
f32(second->Pos.Y) * FrameTransforms[secondFrame].scale.Y + FrameTransforms[secondFrame].translate.Y,
f32(second->Pos.Z) * FrameTransforms[secondFrame].scale.Z + FrameTransforms[secondFrame].translate.Z);
target->Pos = two.getInterpolated(one, div);
const core::vector3df n1(
Q2_VERTEX_NORMAL_TABLE[first->NormalIdx][0],
Q2_VERTEX_NORMAL_TABLE[first->NormalIdx][2],
Q2_VERTEX_NORMAL_TABLE[first->NormalIdx][1]);
const core::vector3df n2(
Q2_VERTEX_NORMAL_TABLE[second->NormalIdx][0],
Q2_VERTEX_NORMAL_TABLE[second->NormalIdx][2],
Q2_VERTEX_NORMAL_TABLE[second->NormalIdx][1]);
target->Normal = n2.getInterpolated(n1, div);
++target;
++first;
++second;
}
//update bounding box
InterpolationBuffer->setBoundingBox(BoxList[secondFrame].getInterpolated(BoxList[firstFrame], div));
InterpolationBuffer->setDirty();
}
}
//! sets a flag of all contained materials to a new value
void CAnimatedMeshMD2::setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue)
{
InterpolationBuffer->Material.setFlag(flag, newvalue);
}
//! set the hardware mapping hint, for driver
void CAnimatedMeshMD2::setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint,
E_BUFFER_TYPE buffer)
{
InterpolationBuffer->setHardwareMappingHint(newMappingHint, buffer);
}
//! flags the meshbuffer as changed, reloads hardware buffers
void CAnimatedMeshMD2::setDirty(E_BUFFER_TYPE buffer)
{
InterpolationBuffer->setDirty(buffer);
}
//! returns an axis aligned bounding box
const core::aabbox3d<f32>& CAnimatedMeshMD2::getBoundingBox() const
{
return InterpolationBuffer->BoundingBox;
}
//! set user axis aligned bounding box
void CAnimatedMeshMD2::setBoundingBox(const core::aabbox3df& box)
{
InterpolationBuffer->BoundingBox = box;
}
//! Returns the type of the animated mesh.
E_ANIMATED_MESH_TYPE CAnimatedMeshMD2::getMeshType() const
{
return EAMT_MD2;
}
//! Returns frame loop data for a special MD2 animation type.
void CAnimatedMeshMD2::getFrameLoop(EMD2_ANIMATION_TYPE l,
s32& outBegin, s32& outEnd, s32& outFPS) const
{
if (l < 0 || l >= EMAT_COUNT)
return;
outBegin = MD2AnimationTypeList[l].begin << MD2_FRAME_SHIFT;
outEnd = MD2AnimationTypeList[l].end << MD2_FRAME_SHIFT;
// correct to anim between last->first frame
outEnd += MD2_FRAME_SHIFT == 0 ? 1 : (1 << MD2_FRAME_SHIFT) - 1;
outFPS = MD2AnimationTypeList[l].fps << MD2_FRAME_SHIFT;
}
//! Returns frame loop data for a special MD2 animation type.
bool CAnimatedMeshMD2::getFrameLoop(const c8* name,
s32& outBegin, s32&outEnd, s32& outFPS) const
{
for (u32 i=0; i < AnimationData.size(); ++i)
{
if (AnimationData[i].name == name)
{
outBegin = AnimationData[i].begin << MD2_FRAME_SHIFT;
outEnd = AnimationData[i].end << MD2_FRAME_SHIFT;
outEnd += MD2_FRAME_SHIFT == 0 ? 1 : (1 << MD2_FRAME_SHIFT) - 1;
outFPS = AnimationData[i].fps << MD2_FRAME_SHIFT;
return true;
}
}
return false;
}
//! Returns amount of md2 animations in this file.
s32 CAnimatedMeshMD2::getAnimationCount() const
{
return AnimationData.size();
}
//! Returns name of md2 animation.
const c8* CAnimatedMeshMD2::getAnimationName(s32 nr) const
{
if ((u32)nr >= AnimationData.size())
return 0;
return AnimationData[nr].name.c_str();
}
} // end namespace scene
} // end namespace irr
#endif // _IRR_COMPILE_WITH_MD2_LOADER_

View File

@ -0,0 +1,158 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_ANIMATED_MESH_MD2_H_INCLUDED__
#define __C_ANIMATED_MESH_MD2_H_INCLUDED__
#include "IAnimatedMeshMD2.h"
#include "IMesh.h"
#include "CMeshBuffer.h"
#include "IReadFile.h"
#include "S3DVertex.h"
#include "irrArray.h"
#include "irrString.h"
namespace irr
{
namespace scene
{
class CAnimatedMeshMD2 : public IAnimatedMeshMD2
{
public:
//! constructor
CAnimatedMeshMD2();
//! destructor
virtual ~CAnimatedMeshMD2();
//! returns the amount of frames. If the amount is 1, it is a static (=non animated) mesh.
virtual u32 getFrameCount() const _IRR_OVERRIDE_;
//! Gets the default animation speed of the animated mesh.
/** \return Amount of frames per second. If the amount is 0, it is a static, non animated mesh. */
virtual f32 getAnimationSpeed() const _IRR_OVERRIDE_
{
return FramesPerSecond;
}
//! Gets the frame count of the animated mesh.
/** \param fps Frames per second to play the animation with. If the amount is 0, it is not animated.
The actual speed is set in the scene node the mesh is instantiated in.*/
virtual void setAnimationSpeed(f32 fps) _IRR_OVERRIDE_
{
FramesPerSecond=fps;
}
//! returns the animated mesh based on a detail level. 0 is the lowest, 255 the highest detail. Note, that some Meshes will ignore the detail level.
virtual IMesh* getMesh(s32 frame, s32 detailLevel=255, s32 startFrameLoop=-1, s32 endFrameLoop=-1) _IRR_OVERRIDE_;
//! returns amount of mesh buffers.
virtual u32 getMeshBufferCount() const _IRR_OVERRIDE_;
//! returns pointer to a mesh buffer
virtual IMeshBuffer* getMeshBuffer(u32 nr) const _IRR_OVERRIDE_;
//! Returns pointer to a mesh buffer which fits a material
/** \param material: material to search for
\return Returns the pointer to the mesh buffer or
NULL if there is no such mesh buffer. */
virtual IMeshBuffer* getMeshBuffer( const video::SMaterial &material) const _IRR_OVERRIDE_;
//! returns an axis aligned bounding box
virtual const core::aabbox3d<f32>& getBoundingBox() const _IRR_OVERRIDE_;
//! set user axis aligned bounding box
virtual void setBoundingBox( const core::aabbox3df& box) _IRR_OVERRIDE_;
//! sets a flag of all contained materials to a new value
virtual void setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue) _IRR_OVERRIDE_;
//! set the hardware mapping hint, for driver
virtual void setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint, E_BUFFER_TYPE buffer=EBT_VERTEX_AND_INDEX) _IRR_OVERRIDE_;
//! flags the meshbuffer as changed, reloads hardware buffers
virtual void setDirty(E_BUFFER_TYPE buffer=EBT_VERTEX_AND_INDEX) _IRR_OVERRIDE_;
//! Returns the type of the animated mesh.
virtual E_ANIMATED_MESH_TYPE getMeshType() const _IRR_OVERRIDE_;
//! Returns frame loop data for a special MD2 animation type.
virtual void getFrameLoop(EMD2_ANIMATION_TYPE,
s32& outBegin, s32& outEnd, s32& outFps) const _IRR_OVERRIDE_;
//! Returns frame loop data for a special MD2 animation type.
virtual bool getFrameLoop(const c8* name,
s32& outBegin, s32& outEnd, s32& outFps) const _IRR_OVERRIDE_;
//! Returns amount of md2 animations in this file.
virtual s32 getAnimationCount() const _IRR_OVERRIDE_;
//! Returns name of md2 animation.
//! \param nr: Zero based index of animation.
virtual const c8* getAnimationName(s32 nr) const _IRR_OVERRIDE_;
//
// exposed for loader
//
//! the buffer that contains the most recent animation
SMeshBuffer* InterpolationBuffer;
//! Frames used to calculate InterpolationBuffer
u32 InterpolationFirstFrame, InterpolationSecondFrame;
f32 InterpolationFrameDiv;
//! named animations
struct SAnimationData
{
core::stringc name;
s32 begin;
s32 end;
s32 fps;
};
//! scale and translations for keyframes
struct SKeyFrameTransform
{
core::vector3df scale;
core::vector3df translate;
};
//! md2 vertex data
struct SMD2Vert
{
core::vector3d<u8> Pos;
u8 NormalIdx;
};
//! keyframe transformations
core::array<SKeyFrameTransform> FrameTransforms;
//! keyframe vertex data
core::array<SMD2Vert> *FrameList;
//! bounding boxes for each keyframe
core::array<core::aabbox3d<f32> > BoxList;
//! named animations
core::array< SAnimationData > AnimationData;
u32 FrameCount;
private:
//! updates the interpolation buffer
void updateInterpolationBuffer(s32 frame, s32 startFrame, s32 endFrame);
f32 FramesPerSecond;
};
} // end namespace scene
} // end namespace irr
#endif

View File

@ -0,0 +1,468 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt / Fabio Concas / Thomas Alten
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_MD3_LOADER_
#include "CAnimatedMeshMD3.h"
#include "os.h"
namespace irr
{
namespace scene
{
// byte-align structures
#include "irrpack.h"
//! General properties of a single animation frame.
struct SMD3Frame
{
f32 mins[3]; // bounding box per frame
f32 maxs[3];
f32 position[3]; // position of bounding box
f32 radius; // radius of bounding sphere
c8 creator[16]; // name of frame
} PACK_STRUCT;
//! An attachment point for another MD3 model.
struct SMD3Tag
{
c8 Name[64]; //name of 'tag' as it's usually called in the md3 files try to see it as a sub-mesh/seperate mesh-part.
f32 position[3]; //relative position of tag
f32 rotationMatrix[9]; //3x3 rotation direction of tag
} PACK_STRUCT;
//!Shader
struct SMD3Shader
{
c8 name[64]; // name of shader
s32 shaderIndex;
} PACK_STRUCT;
// Default alignment
#include "irrunpack.h"
//! Constructor
CAnimatedMeshMD3::CAnimatedMeshMD3()
:Mesh(0), IPolShift(0), LoopMode(0), Scaling(1.f)//, FramesPerSecond(25.f)
{
#ifdef _DEBUG
setDebugName("CAnimatedMeshMD3");
#endif
Mesh = new SMD3Mesh();
MeshIPol = new SMesh();
setInterpolationShift(0, 0);
}
//! Destructor
CAnimatedMeshMD3::~CAnimatedMeshMD3()
{
if (Mesh)
Mesh->drop();
if (MeshIPol)
MeshIPol->drop();
}
//! Returns the amount of frames in milliseconds. If the amount is 1, it is a static (=non animated) mesh.
u32 CAnimatedMeshMD3::getFrameCount() const
{
return Mesh->MD3Header.numFrames << IPolShift;
}
//! Rendering Hint
void CAnimatedMeshMD3::setInterpolationShift(u32 shift, u32 loopMode)
{
IPolShift = shift;
LoopMode = loopMode;
}
//! returns amount of mesh buffers.
u32 CAnimatedMeshMD3::getMeshBufferCount() const
{
return MeshIPol->getMeshBufferCount();
}
//! returns pointer to a mesh buffer
IMeshBuffer* CAnimatedMeshMD3::getMeshBuffer(u32 nr) const
{
return MeshIPol->getMeshBuffer(nr);
}
//! Returns pointer to a mesh buffer which fits a material
IMeshBuffer* CAnimatedMeshMD3::getMeshBuffer(const video::SMaterial &material) const
{
return MeshIPol->getMeshBuffer(material);
}
void CAnimatedMeshMD3::setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue)
{
MeshIPol->setMaterialFlag(flag, newvalue);
}
//! set the hardware mapping hint, for driver
void CAnimatedMeshMD3::setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint,
E_BUFFER_TYPE buffer)
{
MeshIPol->setHardwareMappingHint(newMappingHint, buffer);
}
//! flags the meshbuffer as changed, reloads hardware buffers
void CAnimatedMeshMD3::setDirty(E_BUFFER_TYPE buffer)
{
MeshIPol->setDirty(buffer);
}
//! set user axis aligned bounding box
void CAnimatedMeshMD3::setBoundingBox(const core::aabbox3df& box)
{
MeshIPol->setBoundingBox(box);
}
//! Returns the animated tag list based on a detail level. 0 is the lowest, 255 the highest detail.
SMD3QuaternionTagList *CAnimatedMeshMD3::getTagList(s32 frame, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop)
{
if (0 == Mesh)
return 0;
getMesh(frame, detailLevel, startFrameLoop, endFrameLoop);
return &TagListIPol;
}
//! Returns the animated mesh based on a detail level. 0 is the lowest, 255 the highest detail.
IMesh* CAnimatedMeshMD3::getMesh(s32 frame, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop)
{
if (0 == Mesh)
return 0;
//! check if we have the mesh in our private cache
SCacheInfo candidate(frame, startFrameLoop, endFrameLoop);
if (candidate == Current)
return MeshIPol;
startFrameLoop = core::s32_max(0, startFrameLoop >> IPolShift);
endFrameLoop = core::if_c_a_else_b(endFrameLoop < 0, Mesh->MD3Header.numFrames - 1, endFrameLoop >> IPolShift);
const u32 mask = 1 << IPolShift;
s32 frameA;
s32 frameB;
f32 iPol;
if (LoopMode)
{
// correct frame to "pixel center"
frame -= mask >> 1;
// interpolation
iPol = f32(frame & (mask - 1)) * core::reciprocal(f32(mask));
// wrap anim
frame >>= IPolShift;
frameA = core::if_c_a_else_b(frame < startFrameLoop, endFrameLoop, frame);
frameB = core::if_c_a_else_b(frameA + 1 > endFrameLoop, startFrameLoop, frameA + 1);
}
else
{
// correct frame to "pixel center"
frame -= mask >> 1;
iPol = f32(frame & (mask - 1)) * core::reciprocal(f32(mask));
// clamp anim
frame >>= IPolShift;
frameA = core::s32_clamp(frame, startFrameLoop, endFrameLoop);
frameB = core::s32_min(frameA + 1, endFrameLoop);
}
// build current vertex
for (u32 i = 0; i!= Mesh->Buffer.size(); ++i)
{
buildVertexArray(frameA, frameB, iPol,
Mesh->Buffer[i],
(SMeshBufferLightMap*) MeshIPol->getMeshBuffer(i));
}
MeshIPol->recalculateBoundingBox();
// build current tags
buildTagArray(frameA, frameB, iPol);
Current = candidate;
return MeshIPol;
}
//! create a Irrlicht MeshBuffer for a MD3 MeshBuffer
IMeshBuffer * CAnimatedMeshMD3::createMeshBuffer(const SMD3MeshBuffer* source,
io::IFileSystem* fs, video::IVideoDriver * driver)
{
SMeshBufferLightMap * dest = new SMeshBufferLightMap();
dest->Vertices.set_used(source->MeshHeader.numVertices);
dest->Indices.set_used(source->Indices.size());
u32 i;
// fill in static face info
for (i = 0; i < source->Indices.size(); i += 3)
{
dest->Indices[i + 0] = (u16) source->Indices[i + 0];
dest->Indices[i + 1] = (u16) source->Indices[i + 1];
dest->Indices[i + 2] = (u16) source->Indices[i + 2];
}
// fill in static vertex info
for (i = 0; i!= (u32)source->MeshHeader.numVertices; ++i)
{
video::S3DVertex2TCoords &v = dest->Vertices[i];
v.Color = 0xFFFFFFFF;
v.TCoords.X = source->Tex[i].u;
v.TCoords.Y = source->Tex[i].v;
v.TCoords2.X = 0.f;
v.TCoords2.Y = 0.f;
}
// load static texture
u32 pos = 0;
quake3::tTexArray textureArray;
quake3::getTextures(textureArray, source->Shader, pos, fs, driver);
dest->Material.MaterialType = video::EMT_SOLID;
dest->Material.setTexture(0, textureArray[0]);
dest->Material.Lighting = false;
return dest;
}
//! build final mesh's vertices from frames frameA and frameB with linear interpolation.
void CAnimatedMeshMD3::buildVertexArray(u32 frameA, u32 frameB, f32 interpolate,
const SMD3MeshBuffer* source,
SMeshBufferLightMap* dest)
{
const u32 frameOffsetA = frameA * source->MeshHeader.numVertices;
const u32 frameOffsetB = frameB * source->MeshHeader.numVertices;
const f32 scale = (1.f/ 64.f);
for (s32 i = 0; i != source->MeshHeader.numVertices; ++i)
{
video::S3DVertex2TCoords &v = dest->Vertices [ i ];
const SMD3Vertex &vA = source->Vertices [ frameOffsetA + i ];
const SMD3Vertex &vB = source->Vertices [ frameOffsetB + i ];
// position
v.Pos.X = scale * (vA.position[0] + interpolate * (vB.position[0] - vA.position[0]));
v.Pos.Y = scale * (vA.position[2] + interpolate * (vB.position[2] - vA.position[2]));
v.Pos.Z = scale * (vA.position[1] + interpolate * (vB.position[1] - vA.position[1]));
// normal
const core::vector3df nA(quake3::getMD3Normal(vA.normal[0], vA.normal[1]));
const core::vector3df nB(quake3::getMD3Normal(vB.normal[0], vB.normal[1]));
v.Normal.X = nA.X + interpolate * (nB.X - nA.X);
v.Normal.Y = nA.Z + interpolate * (nB.Z - nA.Z);
v.Normal.Z = nA.Y + interpolate * (nB.Y - nA.Y);
}
dest->recalculateBoundingBox();
}
//! build final mesh's tag from frames frameA and frameB with linear interpolation.
void CAnimatedMeshMD3::buildTagArray(u32 frameA, u32 frameB, f32 interpolate)
{
const u32 frameOffsetA = frameA * Mesh->MD3Header.numTags;
const u32 frameOffsetB = frameB * Mesh->MD3Header.numTags;
for (s32 i = 0; i != Mesh->MD3Header.numTags; ++i)
{
SMD3QuaternionTag &d = TagListIPol [ i ];
const SMD3QuaternionTag &qA = Mesh->TagList[ frameOffsetA + i];
const SMD3QuaternionTag &qB = Mesh->TagList[ frameOffsetB + i];
// rotation
d.rotation.slerp(qA.rotation, qB.rotation, interpolate);
// position
d.position.X = qA.position.X + interpolate * (qB.position.X - qA.position.X);
d.position.Y = qA.position.Y + interpolate * (qB.position.Y - qA.position.Y);
d.position.Z = qA.position.Z + interpolate * (qB.position.Z - qA.position.Z);
}
}
/*!
loads a model
*/
bool CAnimatedMeshMD3::loadModelFile(u32 modelIndex, io::IReadFile* file,
io::IFileSystem* fs, video::IVideoDriver* driver)
{
if (!file)
return false;
//! Check MD3Header
{
file->read(&Mesh->MD3Header, sizeof(SMD3Header));
if (strncmp("IDP3", Mesh->MD3Header.headerID, 4))
{
os::Printer::log("MD3 Loader: invalid header");
return false;
}
}
//! store model name
Mesh->Name = file->getFileName();
u32 i;
//! Frame Data (ignore)
#if 0
SMD3Frame frameImport;
file->seek(Mesh->MD3Header.frameStart);
for (i = 0; i != Mesh->MD3Header.numFrames; ++i)
{
file->read(&frameImport, sizeof(frameImport));
}
#endif
//! Tag Data
const u32 totalTags = Mesh->MD3Header.numTags * Mesh->MD3Header.numFrames;
SMD3Tag import;
file->seek(Mesh->MD3Header.tagStart);
Mesh->TagList.set_used(totalTags);
for (i = 0; i != totalTags; ++i)
{
file->read(&import, sizeof(import));
SMD3QuaternionTag &exp = Mesh->TagList[i];
//! tag name
exp.Name = import.Name;
//! position
exp.position.X = import.position[0];
exp.position.Y = import.position[2];
exp.position.Z = import.position[1];
//! construct quaternion from a RH 3x3 Matrix
exp.rotation.set(import.rotationMatrix[7],
0.f,
-import.rotationMatrix[6],
1 + import.rotationMatrix[8]);
exp.rotation.normalize();
}
//! Meshes
u32 offset = Mesh->MD3Header.tagEnd;
for (i = 0; i != (u32)Mesh->MD3Header.numMeshes; ++i)
{
//! construct a new mesh buffer
SMD3MeshBuffer * buf = new SMD3MeshBuffer();
// !read mesh header info
SMD3MeshHeader &meshHeader = buf->MeshHeader;
//! read mesh info
file->seek(offset);
file->read(&meshHeader, sizeof(SMD3MeshHeader));
//! prepare memory
buf->Vertices.set_used(meshHeader.numVertices * Mesh->MD3Header.numFrames);
buf->Indices.set_used(meshHeader.numTriangles * 3);
buf->Tex.set_used(meshHeader.numVertices);
//! read skins (shaders). should be 1 per meshbuffer
SMD3Shader skin;
file->seek(offset + buf->MeshHeader.offset_shaders);
for (s32 g = 0; g != buf->MeshHeader.numShader; ++g)
{
file->read(&skin, sizeof(skin));
io::path name;
cutFilenameExtension(name, skin.name);
name.replace('\\', '/');
buf->Shader = name;
}
//! read texture coordinates
file->seek(offset + buf->MeshHeader.offset_st);
file->read(buf->Tex.pointer(), buf->MeshHeader.numVertices * sizeof(SMD3TexCoord));
//! read vertices
file->seek(offset + meshHeader.vertexStart);
file->read(buf->Vertices.pointer(), Mesh->MD3Header.numFrames * meshHeader.numVertices * sizeof(SMD3Vertex));
//! read indices
file->seek(offset + meshHeader.offset_triangles);
file->read(buf->Indices.pointer(), meshHeader.numTriangles * sizeof(SMD3Face));
//! store meshBuffer
Mesh->Buffer.push_back(buf);
offset += meshHeader.offset_end;
}
// Init Mesh Interpolation
for (i = 0; i != Mesh->Buffer.size(); ++i)
{
IMeshBuffer * buffer = createMeshBuffer(Mesh->Buffer[i], fs, driver);
MeshIPol->addMeshBuffer(buffer);
buffer->drop();
}
MeshIPol->recalculateBoundingBox();
// Init Tag Interpolation
for (i = 0; i != (u32)Mesh->MD3Header.numTags; ++i)
{
TagListIPol.push_back(Mesh->TagList[i]);
}
return true;
}
SMD3Mesh * CAnimatedMeshMD3::getOriginalMesh()
{
return Mesh;
}
//! Returns an axis aligned bounding box
const core::aabbox3d<f32>& CAnimatedMeshMD3::getBoundingBox() const
{
return MeshIPol->BoundingBox;
}
//! Returns the type of the animated mesh.
E_ANIMATED_MESH_TYPE CAnimatedMeshMD3::getMeshType() const
{
return EAMT_MD3;
}
} // end namespace scene
} // end namespace irr
#endif // _IRR_COMPILE_WITH_MD3_LOADER_

View File

@ -0,0 +1,135 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_ANIMATED_MESH_MD3_H_INCLUDED__
#define __C_ANIMATED_MESH_MD3_H_INCLUDED__
#include "IAnimatedMeshMD3.h"
#include "IReadFile.h"
#include "IFileSystem.h"
#include "irrArray.h"
#include "irrString.h"
#include "SMesh.h"
#include "SMeshBuffer.h"
#include "IQ3Shader.h"
namespace irr
{
namespace scene
{
class CAnimatedMeshMD3 : public IAnimatedMeshMD3
{
public:
//! constructor
CAnimatedMeshMD3();
//! destructor
virtual ~CAnimatedMeshMD3();
//! loads a quake3 md3 file
bool loadModelFile(u32 modelIndex, io::IReadFile* file,
io::IFileSystem* fs, video::IVideoDriver* driver);
// IAnimatedMeshMD3
virtual void setInterpolationShift(u32 shift, u32 loopMode) _IRR_OVERRIDE_;
virtual SMD3Mesh* getOriginalMesh() _IRR_OVERRIDE_;
virtual SMD3QuaternionTagList* getTagList(s32 frame, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop) _IRR_OVERRIDE_;
//IAnimatedMesh
virtual u32 getFrameCount() const _IRR_OVERRIDE_;
//! Gets the default animation speed of the animated mesh.
/** \return Amount of frames per second. If the amount is 0, it is a static, non animated mesh. */
virtual f32 getAnimationSpeed() const _IRR_OVERRIDE_
{
return FramesPerSecond;
}
//! Gets the frame count of the animated mesh.
/** \param fps Frames per second to play the animation with. If the amount is 0, it is not animated.
The actual speed is set in the scene node the mesh is instantiated in.*/
virtual void setAnimationSpeed(f32 fps) _IRR_OVERRIDE_
{
FramesPerSecond=fps;
}
virtual IMesh* getMesh(s32 frame, s32 detailLevel,
s32 startFrameLoop, s32 endFrameLoop) _IRR_OVERRIDE_;
virtual const core::aabbox3d<f32>& getBoundingBox() const _IRR_OVERRIDE_;
virtual E_ANIMATED_MESH_TYPE getMeshType() const _IRR_OVERRIDE_;
//! returns amount of mesh buffers.
virtual u32 getMeshBufferCount() const _IRR_OVERRIDE_;
//! returns pointer to a mesh buffer
virtual IMeshBuffer* getMeshBuffer(u32 nr) const _IRR_OVERRIDE_;
//! Returns pointer to a mesh buffer which fits a material
virtual IMeshBuffer* getMeshBuffer(const video::SMaterial &material) const _IRR_OVERRIDE_;
virtual void setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue) _IRR_OVERRIDE_;
//! set user axis aligned bounding box
virtual void setBoundingBox(const core::aabbox3df& box) _IRR_OVERRIDE_;
//! set the hardware mapping hint, for driver
virtual void setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint, E_BUFFER_TYPE buffer=EBT_VERTEX_AND_INDEX) _IRR_OVERRIDE_;
//! flags the meshbuffer as changed, reloads hardware buffers
virtual void setDirty(E_BUFFER_TYPE buffer=EBT_VERTEX_AND_INDEX) _IRR_OVERRIDE_;
private:
//! animates one frame
inline void Animate(u32 frame);
video::SMaterial Material;
//! hold original compressed MD3 Info
SMD3Mesh *Mesh;
u32 IPolShift;
u32 LoopMode;
f32 Scaling;
//! Cache Info
struct SCacheInfo
{
SCacheInfo(s32 frame=-1, s32 start=-1, s32 end=-1 ) :
Frame(frame), startFrameLoop(start),
endFrameLoop(end)
{}
bool operator == ( const SCacheInfo &other ) const
{
return 0 == memcmp ( this, &other, sizeof ( SCacheInfo ) );
}
s32 Frame;
s32 startFrameLoop;
s32 endFrameLoop;
};
SCacheInfo Current;
//! return a Mesh per frame
SMesh* MeshIPol;
SMD3QuaternionTagList TagListIPol;
IMeshBuffer* createMeshBuffer(const SMD3MeshBuffer* source,
io::IFileSystem* fs, video::IVideoDriver* driver);
void buildVertexArray(u32 frameA, u32 frameB, f32 interpolate,
const SMD3MeshBuffer* source,
SMeshBufferLightMap* dest);
void buildTagArray(u32 frameA, u32 frameB, f32 interpolate);
f32 FramesPerSecond;
};
} // end namespace scene
} // end namespace irr
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,223 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_ANIMATED_MESH_SCENE_NODE_H_INCLUDED__
#define __C_ANIMATED_MESH_SCENE_NODE_H_INCLUDED__
#include "IAnimatedMeshSceneNode.h"
#include "IAnimatedMesh.h"
#include "matrix4.h"
namespace irr
{
namespace scene
{
class IDummyTransformationSceneNode;
class CAnimatedMeshSceneNode : public IAnimatedMeshSceneNode
{
public:
//! constructor
CAnimatedMeshSceneNode(IAnimatedMesh* mesh, ISceneNode* parent, ISceneManager* mgr, s32 id,
const core::vector3df& position = core::vector3df(0,0,0),
const core::vector3df& rotation = core::vector3df(0,0,0),
const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f));
//! destructor
virtual ~CAnimatedMeshSceneNode();
//! sets the current frame. from now on the animation is played from this frame.
virtual void setCurrentFrame(f32 frame) _IRR_OVERRIDE_;
//! frame
virtual void OnRegisterSceneNode() _IRR_OVERRIDE_;
//! OnAnimate() is called just before rendering the whole scene.
virtual void OnAnimate(u32 timeMs) _IRR_OVERRIDE_;
//! renders the node.
virtual void render() _IRR_OVERRIDE_;
//! returns the axis aligned bounding box of this node
virtual const core::aabbox3d<f32>& getBoundingBox() const _IRR_OVERRIDE_;
//! sets the frames between the animation is looped.
//! the default is 0 - MaximalFrameCount of the mesh.
//! NOTE: setMesh will also change this value and set it to the full range of animations of the mesh
virtual bool setFrameLoop(s32 begin, s32 end) _IRR_OVERRIDE_;
//! Sets looping mode which is on by default. If set to false,
//! animations will not be looped.
virtual void setLoopMode(bool playAnimationLooped) _IRR_OVERRIDE_;
//! returns the current loop mode
virtual bool getLoopMode() const _IRR_OVERRIDE_;
//! Sets a callback interface which will be called if an animation
//! playback has ended. Set this to 0 to disable the callback again.
virtual void setAnimationEndCallback(IAnimationEndCallBack* callback=0) _IRR_OVERRIDE_;
//! sets the speed with which the animation is played
//! NOTE: setMesh will also change this value and set it to the default speed of the mesh
virtual void setAnimationSpeed(f32 framesPerSecond) _IRR_OVERRIDE_;
//! gets the speed with which the animation is played
virtual f32 getAnimationSpeed() const _IRR_OVERRIDE_;
//! returns the material based on the zero based index i. To get the amount
//! of materials used by this scene node, use getMaterialCount().
//! This function is needed for inserting the node into the scene hierarchy on a
//! optimal position for minimizing renderstate changes, but can also be used
//! to directly modify the material of a scene node.
virtual video::SMaterial& getMaterial(u32 i) _IRR_OVERRIDE_;
//! returns amount of materials used by this scene node.
virtual u32 getMaterialCount() const _IRR_OVERRIDE_;
//! Creates shadow volume scene node as child of this node
//! and returns a pointer to it.
virtual IShadowVolumeSceneNode* addShadowVolumeSceneNode(const IMesh* shadowMesh,
s32 id, bool zfailmethod=true, f32 infinity=1000.0f) _IRR_OVERRIDE_;
//! Returns a pointer to a child node, which has the same transformation as
//! the corresponding joint, if the mesh in this scene node is a skinned mesh.
virtual IBoneSceneNode* getJointNode(const c8* jointName) _IRR_OVERRIDE_;
//! same as getJointNode(const c8* jointName), but based on id
virtual IBoneSceneNode* getJointNode(u32 jointID) _IRR_OVERRIDE_;
//! Gets joint count.
virtual u32 getJointCount() const _IRR_OVERRIDE_;
//! Removes a child from this scene node.
//! Implemented here, to be able to remove the shadow properly, if there is one,
//! or to remove attached child.
virtual bool removeChild(ISceneNode* child) _IRR_OVERRIDE_;
//! Starts a MD2 animation.
virtual bool setMD2Animation(EMD2_ANIMATION_TYPE anim) _IRR_OVERRIDE_;
//! Starts a special MD2 animation.
virtual bool setMD2Animation(const c8* animationName) _IRR_OVERRIDE_;
//! Returns the current displayed frame number.
virtual f32 getFrameNr() const _IRR_OVERRIDE_;
//! Returns the current start frame number.
virtual s32 getStartFrame() const _IRR_OVERRIDE_;
//! Returns the current end frame number.
virtual s32 getEndFrame() const _IRR_OVERRIDE_;
//! Sets if the scene node should not copy the materials of the mesh but use them in a read only style.
/* In this way it is possible to change the materials a mesh causing all mesh scene nodes
referencing this mesh to change too. */
virtual void setReadOnlyMaterials(bool readonly) _IRR_OVERRIDE_;
//! Returns if the scene node should not copy the materials of the mesh but use them in a read only style
virtual bool isReadOnlyMaterials() const _IRR_OVERRIDE_;
//! Sets a new mesh
virtual void setMesh(IAnimatedMesh* mesh) _IRR_OVERRIDE_;
//! Returns the current mesh
virtual IAnimatedMesh* getMesh(void) _IRR_OVERRIDE_ { return Mesh; }
//! Writes attributes of the scene node.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const _IRR_OVERRIDE_;
//! Reads attributes of the scene node.
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) _IRR_OVERRIDE_;
//! Returns type of the scene node
virtual ESCENE_NODE_TYPE getType() const _IRR_OVERRIDE_ { return ESNT_ANIMATED_MESH; }
// returns the absolute transformation for a special MD3 Tag if the mesh is a md3 mesh,
// or the absolutetransformation if it's a normal scenenode
const SMD3QuaternionTag* getMD3TagTransformation( const core::stringc & tagname) _IRR_OVERRIDE_;
//! updates the absolute position based on the relative and the parents position
virtual void updateAbsolutePosition() _IRR_OVERRIDE_;
//! Set the joint update mode (0-unused, 1-get joints only, 2-set joints only, 3-move and set)
virtual void setJointMode(E_JOINT_UPDATE_ON_RENDER mode) _IRR_OVERRIDE_;
//! Sets the transition time in seconds (note: This needs to enable joints, and setJointmode maybe set to 2)
//! you must call animateJoints(), or the mesh will not animate
virtual void setTransitionTime(f32 Time) _IRR_OVERRIDE_;
//! updates the joint positions of this mesh
virtual void animateJoints(bool CalculateAbsolutePositions=true) _IRR_OVERRIDE_;
//! render mesh ignoring its transformation. Used with ragdolls. (culling is unaffected)
virtual void setRenderFromIdentity( bool On ) _IRR_OVERRIDE_;
//! Creates a clone of this scene node and its children.
/** \param newParent An optional new parent.
\param newManager An optional new scene manager.
\return The newly created clone of this node. */
virtual ISceneNode* clone(ISceneNode* newParent=0, ISceneManager* newManager=0) _IRR_OVERRIDE_;
private:
//! Get a static mesh for the current frame of this animated mesh
IMesh* getMeshForCurrentFrame();
void buildFrameNr(u32 timeMs);
void checkJoints();
void beginTransition();
core::array<video::SMaterial> Materials;
core::aabbox3d<f32> Box;
IAnimatedMesh* Mesh;
s32 StartFrame;
s32 EndFrame;
f32 FramesPerSecond;
f32 CurrentFrameNr;
u32 LastTimeMs;
u32 TransitionTime; //Transition time in millisecs
f32 Transiting; //is mesh transiting (plus cache of TransitionTime)
f32 TransitingBlend; //0-1, calculated on buildFrameNr
//0-unused, 1-get joints only, 2-set joints only, 3-move and set
E_JOINT_UPDATE_ON_RENDER JointMode;
bool JointsUsed;
bool Looping;
bool ReadOnlyMaterials;
bool RenderFromIdentity;
IAnimationEndCallBack* LoopCallBack;
s32 PassCount;
IShadowVolumeSceneNode* Shadow;
core::array<IBoneSceneNode* > JointChildSceneNodes;
core::array<core::matrix4> PretransitingSave;
// Quake3 Model
struct SMD3Special : public virtual IReferenceCounted
{
core::stringc Tagname;
SMD3QuaternionTagList AbsoluteTagList;
SMD3Special & operator = (const SMD3Special & copyMe)
{
Tagname = copyMe.Tagname;
AbsoluteTagList = copyMe.AbsoluteTagList;
return *this;
}
};
SMD3Special *MD3Special;
};
} // end namespace scene
} // end namespace irr
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,738 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_ATTRIBUTES_H_INCLUDED__
#define __C_ATTRIBUTES_H_INCLUDED__
#include "IrrCompileConfig.h"
#include "IAttributes.h"
#include "IAttribute.h"
namespace irr
{
namespace video
{
class ITexture;
class IVideoDriver;
}
namespace io
{
//! Implementation of the IAttributes interface
class CAttributes : public IAttributes
{
public:
CAttributes(video::IVideoDriver* driver=0);
~CAttributes();
//! Returns amount of attributes in this collection of attributes.
virtual u32 getAttributeCount() const _IRR_OVERRIDE_;
//! Returns attribute name by index.
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual const c8* getAttributeName(s32 index) const _IRR_OVERRIDE_;
//! Returns the type of an attribute
//! \param attributeName: Name for the attribute
virtual E_ATTRIBUTE_TYPE getAttributeType(const c8* attributeName) const _IRR_OVERRIDE_;
//! Returns attribute type by index.
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual E_ATTRIBUTE_TYPE getAttributeType(s32 index) const _IRR_OVERRIDE_;
//! Returns the type string of the attribute
//! \param attributeName: String for the attribute type
//! \param defaultNotFound Value returned when attributeName was not found
virtual const wchar_t* getAttributeTypeString(const c8* attributeName, const wchar_t* defaultNotFound = L"unknown") const _IRR_OVERRIDE_;
//! Returns the type string of the attribute by index.
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual const wchar_t* getAttributeTypeString(s32 index, const wchar_t* defaultNotFound = L"unknown") const _IRR_OVERRIDE_;
//! Returns if an attribute with a name exists
virtual bool existsAttribute(const c8* attributeName) const _IRR_OVERRIDE_;
//! Returns attribute index from name, -1 if not found
virtual s32 findAttribute(const c8* attributeName) const _IRR_OVERRIDE_;
//! Removes all attributes
virtual void clear() _IRR_OVERRIDE_;
//! Reads attributes from a xml file.
//! \param readCurrentElementOnly: If set to true, reading only works if current element has the name 'attributes'.
//! IF set to false, the first appearing list attributes are read.
virtual bool read(io::IXMLReader* reader, bool readCurrentElementOnly=false,
const wchar_t* nonDefaultElementName = 0) _IRR_OVERRIDE_;
//! Write these attributes into a xml file
virtual bool write(io::IXMLWriter* writer, bool writeXMLHeader=false, const wchar_t* nonDefaultElementName=0) _IRR_OVERRIDE_;
/*
Integer Attribute
*/
//! Adds an attribute as integer
virtual void addInt(const c8* attributeName, s32 value) _IRR_OVERRIDE_;
//! Sets an attribute as integer value
virtual void setAttribute(const c8* attributeName, s32 value) _IRR_OVERRIDE_;
//! Gets an attribute as integer value
//! \param attributeName: Name of the attribute to get.
//! \param defaultNotFound Value returned when attributeName was not found
//! \return Returns value of the attribute previously set by setAttribute()
virtual s32 getAttributeAsInt(const c8* attributeName, irr::s32 defaultNotFound=0) const _IRR_OVERRIDE_;
//! Gets an attribute as integer value
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual s32 getAttributeAsInt(s32 index) const _IRR_OVERRIDE_;
//! Sets an attribute as integer value
virtual void setAttribute(s32 index, s32 value) _IRR_OVERRIDE_;
/*
Float Attribute
*/
//! Adds an attribute as float
virtual void addFloat(const c8* attributeName, f32 value) _IRR_OVERRIDE_;
//! Sets a attribute as float value
virtual void setAttribute(const c8* attributeName, f32 value) _IRR_OVERRIDE_;
//! Gets an attribute as float value
//! \param attributeName: Name of the attribute to get.
//! \param defaultNotFound Value returned when attributeName was not found
//! \return Returns value of the attribute previously set by setAttribute()
virtual f32 getAttributeAsFloat(const c8* attributeName, irr::f32 defaultNotFound=0.f) const _IRR_OVERRIDE_;
//! Gets an attribute as float value
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual f32 getAttributeAsFloat(s32 index) const _IRR_OVERRIDE_;
//! Sets an attribute as float value
virtual void setAttribute(s32 index, f32 value) _IRR_OVERRIDE_;
/*
String Attribute
*/
//! Adds an attribute as string
virtual void addString(const c8* attributeName, const c8* value) _IRR_OVERRIDE_;
//! Sets an attribute value as string.
//! \param attributeName: Name for the attribute
//! \param value: Value for the attribute. Set this to 0 to delete the attribute
virtual void setAttribute(const c8* attributeName, const c8* value) _IRR_OVERRIDE_;
//! Gets an attribute as string.
//! \param attributeName: Name of the attribute to get.
//! \param defaultNotFound Value returned when attributeName was not found
//! \return Returns value of the attribute previously set by setAttribute()
//! or defaultNotFound if attribute is not set.
virtual core::stringc getAttributeAsString(const c8* attributeName, const core::stringc& defaultNotFound=core::stringc()) const _IRR_OVERRIDE_;
//! Gets an attribute as string.
//! \param attributeName: Name of the attribute to get.
//! \param target: Buffer where the string is copied to.
virtual void getAttributeAsString(const c8* attributeName, c8* target) const _IRR_OVERRIDE_;
//! Returns attribute value as string by index.
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual core::stringc getAttributeAsString(s32 index) const _IRR_OVERRIDE_;
//! Sets an attribute value as string.
//! \param attributeName: Name for the attribute
virtual void setAttribute(s32 index, const c8* value) _IRR_OVERRIDE_;
// wide strings
//! Adds an attribute as string
virtual void addString(const c8* attributeName, const wchar_t* value) _IRR_OVERRIDE_;
//! Sets an attribute value as string.
//! \param attributeName: Name for the attribute
//! \param value: Value for the attribute. Set this to 0 to delete the attribute
virtual void setAttribute(const c8* attributeName, const wchar_t* value) _IRR_OVERRIDE_;
//! Gets an attribute as string.
//! \param attributeName: Name of the attribute to get.
//! \param defaultNotFound Value returned when attributeName was not found
//! \return Returns value of the attribute previously set by setAttribute()
//! or defaultNotFound if attribute is not set.
virtual core::stringw getAttributeAsStringW(const c8* attributeName, const core::stringw& defaultNotFound = core::stringw()) const _IRR_OVERRIDE_;
//! Gets an attribute as string.
//! \param attributeName: Name of the attribute to get.
//! \param target: Buffer where the string is copied to.
virtual void getAttributeAsStringW(const c8* attributeName, wchar_t* target) const _IRR_OVERRIDE_;
//! Returns attribute value as string by index.
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual core::stringw getAttributeAsStringW(s32 index) const _IRR_OVERRIDE_;
//! Sets an attribute value as string.
//! \param attributeName: Name for the attribute
virtual void setAttribute(s32 index, const wchar_t* value) _IRR_OVERRIDE_;
/*
Binary Data Attribute
*/
//! Adds an attribute as binary data
virtual void addBinary(const c8* attributeName, void* data, s32 dataSizeInBytes) _IRR_OVERRIDE_;
//! Sets an attribute as binary data
virtual void setAttribute(const c8* attributeName, void* data, s32 dataSizeInBytes) _IRR_OVERRIDE_;
//! Gets an attribute as binary data
//! \param attributeName: Name of the attribute to get.
virtual void getAttributeAsBinaryData(const c8* attributeName, void* outData, s32 maxSizeInBytes) const _IRR_OVERRIDE_;
//! Gets an attribute as binary data
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual void getAttributeAsBinaryData(s32 index, void* outData, s32 maxSizeInBytes) const _IRR_OVERRIDE_;
//! Sets an attribute as binary data
virtual void setAttribute(s32 index, void* data, s32 dataSizeInBytes) _IRR_OVERRIDE_;
/*
Array Attribute
*/
//! Adds an attribute as wide string array
virtual void addArray(const c8* attributeName, const core::array<core::stringw>& value) _IRR_OVERRIDE_;
//! Sets an attribute value as a wide string array.
//! \param attributeName: Name for the attribute
//! \param value: Value for the attribute. Set this to 0 to delete the attribute
virtual void setAttribute(const c8* attributeName, const core::array<core::stringw>& value) _IRR_OVERRIDE_;
//! Gets an attribute as an array of wide strings.
//! \param attributeName: Name of the attribute to get.
//! \param defaultNotFound Value returned when attributeName was not found
//! \return Returns value of the attribute previously set by setAttribute()
//! or defaultNotFound if attribute is not set.
virtual core::array<core::stringw> getAttributeAsArray(const c8* attributeName, const core::array<core::stringw>& defaultNotFound = core::array<core::stringw>()) const _IRR_OVERRIDE_;
//! Returns attribute value as an array of wide strings by index.
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual core::array<core::stringw> getAttributeAsArray(s32 index) const _IRR_OVERRIDE_;
//! Sets an attribute as an array of wide strings
virtual void setAttribute(s32 index, const core::array<core::stringw>& value) _IRR_OVERRIDE_;
/*
Bool Attribute
*/
//! Adds an attribute as bool
virtual void addBool(const c8* attributeName, bool value) _IRR_OVERRIDE_;
//! Sets an attribute as boolean value
virtual void setAttribute(const c8* attributeName, bool value) _IRR_OVERRIDE_;
//! Gets an attribute as boolean value
//! \param attributeName: Name of the attribute to get.
//! \param defaultNotFound Value returned when attributeName was not found
//! \return Returns value of the attribute previously set by setAttribute()
virtual bool getAttributeAsBool(const c8* attributeName, bool defaultNotFound=false) const _IRR_OVERRIDE_;
//! Gets an attribute as boolean value
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual bool getAttributeAsBool(s32 index) const _IRR_OVERRIDE_;
//! Sets an attribute as boolean value
virtual void setAttribute(s32 index, bool value) _IRR_OVERRIDE_;
/*
Enumeration Attribute
*/
//! Adds an attribute as enum
virtual void addEnum(const c8* attributeName, const c8* enumValue, const c8* const* enumerationLiterals) _IRR_OVERRIDE_;
//! Adds an attribute as enum
virtual void addEnum(const c8* attributeName, s32 enumValue, const c8* const* enumerationLiterals) _IRR_OVERRIDE_;
//! Sets an attribute as enumeration
virtual void setAttribute(const c8* attributeName, const c8* enumValue, const c8* const* enumerationLiterals) _IRR_OVERRIDE_;
//! Gets an attribute as enumeration
//! \param attributeName: Name of the attribute to get.
//! \param defaultNotFound Value returned when attributeName was not found
//! \return Returns value of the attribute previously set by setAttribute()
virtual const c8* getAttributeAsEnumeration(const c8* attributeName, const c8* defaultNotFound = 0) const _IRR_OVERRIDE_;
//! Gets an attribute as enumeration
//! \param attributeName: Name of the attribute to get.
//! \param enumerationLiteralsToUse: Use these enumeration literals to get the index value instead of the set ones.
//! This is useful when the attribute list maybe was read from an xml file, and only contains the enumeration string, but
//! no information about its index.
//! \return Returns value of the attribute previously set by setAttribute()
virtual s32 getAttributeAsEnumeration(const c8* attributeName, const c8* const* enumerationLiteralsToUse, s32 defaultNotFound ) const _IRR_OVERRIDE_;
//! Gets an attribute as enumeration
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual s32 getAttributeAsEnumeration(s32 index, const c8* const* enumerationLiteralsToUse, s32 defaultNotFound) const _IRR_OVERRIDE_;
//! Gets an attribute as enumeration
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual const c8* getAttributeAsEnumeration(s32 index) const _IRR_OVERRIDE_;
//! Gets the list of enumeration literals of an enumeration attribute
//! \param attributeName: Name of the attribute to get.
virtual void getAttributeEnumerationLiteralsOfEnumeration(const c8* attributeName, core::array<core::stringc>& outLiterals) const _IRR_OVERRIDE_;
//! Gets the list of enumeration literals of an enumeration attribute
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual void getAttributeEnumerationLiteralsOfEnumeration(s32 index, core::array<core::stringc>& outLiterals) const _IRR_OVERRIDE_;
//! Sets an attribute as enumeration
virtual void setAttribute(s32 index, const c8* enumValue, const c8* const* enumerationLiterals) _IRR_OVERRIDE_;
/*
SColor Attribute
*/
//! Adds an attribute as color
virtual void addColor(const c8* attributeName, video::SColor value) _IRR_OVERRIDE_;
//! Sets a attribute as color
virtual void setAttribute(const c8* attributeName, video::SColor color) _IRR_OVERRIDE_;
//! Gets an attribute as color
//! \param attributeName: Name of the attribute to get.
//! \param defaultNotFound Value returned when attributeName was not found
//! \return Returns value of the attribute previously set by setAttribute()
virtual video::SColor getAttributeAsColor(const c8* attributeName, const video::SColor& defaultNotFound = video::SColor(0)) const _IRR_OVERRIDE_;
//! Gets an attribute as color
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual video::SColor getAttributeAsColor(s32 index) const _IRR_OVERRIDE_;
//! Sets an attribute as color
virtual void setAttribute(s32 index, video::SColor color) _IRR_OVERRIDE_;
/*
SColorf Attribute
*/
//! Adds an attribute as floating point color
virtual void addColorf(const c8* attributeName, video::SColorf value) _IRR_OVERRIDE_;
//! Sets a attribute as floating point color
virtual void setAttribute(const c8* attributeName, video::SColorf color) _IRR_OVERRIDE_;
//! Gets an attribute as floating point color
//! \param attributeName: Name of the attribute to get.
//! \param defaultNotFound Value returned when attributeName was not found
//! \return Returns value of the attribute previously set by setAttribute()
virtual video::SColorf getAttributeAsColorf(const c8* attributeName, const video::SColorf& defaultNotFound = video::SColorf(0)) const _IRR_OVERRIDE_;
//! Gets an attribute as floating point color
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual video::SColorf getAttributeAsColorf(s32 index) const _IRR_OVERRIDE_;
//! Sets an attribute as floating point color
virtual void setAttribute(s32 index, video::SColorf color) _IRR_OVERRIDE_;
/*
Vector3d Attribute
*/
//! Adds an attribute as 3d vector
virtual void addVector3d(const c8* attributeName, const core::vector3df& value) _IRR_OVERRIDE_;
//! Sets a attribute as 3d vector
virtual void setAttribute(const c8* attributeName, const core::vector3df& v) _IRR_OVERRIDE_;
//! Gets an attribute as 3d vector
//! \param attributeName: Name of the attribute to get.
//! \param defaultNotFound Value returned when attributeName was not found
//! \return Returns value of the attribute previously set by setAttribute()
virtual core::vector3df getAttributeAsVector3d(const c8* attributeName, const core::vector3df& defaultNotFound=core::vector3df(0,0,0)) const _IRR_OVERRIDE_;
//! Gets an attribute as 3d vector
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual core::vector3df getAttributeAsVector3d(s32 index) const _IRR_OVERRIDE_;
//! Sets an attribute as vector
virtual void setAttribute(s32 index, const core::vector3df& v) _IRR_OVERRIDE_;
/*
Vector2d Attribute
*/
//! Adds an attribute as 2d vector
virtual void addVector2d(const c8* attributeName, const core::vector2df& value) _IRR_OVERRIDE_;
//! Sets a attribute as 2d vector
virtual void setAttribute(const c8* attributeName, const core::vector2df& v) _IRR_OVERRIDE_;
//! Gets an attribute as 2d vector
//! \param attributeName: Name of the attribute to get.
//! \param defaultNotFound Value returned when attributeName was not found
//! \return Returns value of the attribute previously set by setAttribute()
virtual core::vector2df getAttributeAsVector2d(const c8* attributeName, const core::vector2df& defaultNotFound=core::vector2df(0,0)) const _IRR_OVERRIDE_;
//! Gets an attribute as 3d vector
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual core::vector2df getAttributeAsVector2d(s32 index) const _IRR_OVERRIDE_;
//! Sets an attribute as vector
virtual void setAttribute(s32 index, const core::vector2df& v) _IRR_OVERRIDE_;
/*
Position2d Attribute
*/
//! Adds an attribute as 2d position
virtual void addPosition2d(const c8* attributeName, const core::position2di& value) _IRR_OVERRIDE_;
//! Sets a attribute as 2d position
virtual void setAttribute(const c8* attributeName, const core::position2di& v) _IRR_OVERRIDE_;
//! Gets an attribute as position
//! \param attributeName: Name of the attribute to get.
//! \param defaultNotFound Value returned when attributeName was not found
//! \return Returns value of the attribute previously set by setAttribute()
virtual core::position2di getAttributeAsPosition2d(const c8* attributeName, const core::position2di& defaultNotFound=core::position2di(0,0)) const _IRR_OVERRIDE_;
//! Gets an attribute as position
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual core::position2di getAttributeAsPosition2d(s32 index) const _IRR_OVERRIDE_;
//! Sets an attribute as 2d position
virtual void setAttribute(s32 index, const core::position2di& v) _IRR_OVERRIDE_;
/*
Rectangle Attribute
*/
//! Adds an attribute as rectangle
virtual void addRect(const c8* attributeName, const core::rect<s32>& value) _IRR_OVERRIDE_;
//! Sets an attribute as rectangle
virtual void setAttribute(const c8* attributeName, const core::rect<s32>& v) _IRR_OVERRIDE_;
//! Gets an attribute as rectangle
//! \param attributeName: Name of the attribute to get.
//! \param defaultNotFound Value returned when attributeName was not found
//! \return Returns value of the attribute previously set by setAttribute()
virtual core::rect<s32> getAttributeAsRect(const c8* attributeName, const core::rect<s32>& defaultNotFound = core::rect<s32>()) const _IRR_OVERRIDE_;
//! Gets an attribute as rectangle
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual core::rect<s32> getAttributeAsRect(s32 index) const _IRR_OVERRIDE_;
//! Sets an attribute as rectangle
virtual void setAttribute(s32 index, const core::rect<s32>& v) _IRR_OVERRIDE_;
/*
Dimension2d Attribute
*/
//! Adds an attribute as dimension2d
virtual void addDimension2d(const c8* attributeName, const core::dimension2d<u32>& value) _IRR_OVERRIDE_;
//! Sets an attribute as dimension2d
virtual void setAttribute(const c8* attributeName, const core::dimension2d<u32>& v) _IRR_OVERRIDE_;
//! Gets an attribute as dimension2d
//! \param attributeName: Name of the attribute to get.
//! \param defaultNotFound Value returned when attributeName was not found
//! \return Returns value of the attribute previously set by setAttribute()
virtual core::dimension2d<u32> getAttributeAsDimension2d(const c8* attributeName, const core::dimension2d<u32>& defaultNotFound = core::dimension2d<u32>()) const _IRR_OVERRIDE_;
//! Gets an attribute as dimension2d
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual core::dimension2d<u32> getAttributeAsDimension2d(s32 index) const _IRR_OVERRIDE_;
//! Sets an attribute as dimension2d
virtual void setAttribute(s32 index, const core::dimension2d<u32>& v) _IRR_OVERRIDE_;
/*
matrix attribute
*/
//! Adds an attribute as matrix
virtual void addMatrix(const c8* attributeName, const core::matrix4& v) _IRR_OVERRIDE_;
//! Sets an attribute as matrix
virtual void setAttribute(const c8* attributeName, const core::matrix4& v) _IRR_OVERRIDE_;
//! Gets an attribute as a matrix4
//! \param attributeName: Name of the attribute to get.
//! \param defaultNotFound Value returned when attributeName was not found
//! \return Returns value of the attribute previously set by setAttribute()
virtual core::matrix4 getAttributeAsMatrix(const c8* attributeName, const core::matrix4& defaultNotFound=core::matrix4()) const _IRR_OVERRIDE_;
//! Gets an attribute as matrix
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual core::matrix4 getAttributeAsMatrix(s32 index) const _IRR_OVERRIDE_;
//! Sets an attribute as matrix
virtual void setAttribute(s32 index, const core::matrix4& v) _IRR_OVERRIDE_;
/*
quaternion attribute
*/
//! Adds an attribute as quaternion
virtual void addQuaternion(const c8* attributeName, const core::quaternion& v) _IRR_OVERRIDE_;
//! Sets an attribute as quaternion
virtual void setAttribute(const c8* attributeName, const core::quaternion& v) _IRR_OVERRIDE_;
//! Gets an attribute as a quaternion
//! \param attributeName: Name of the attribute to get.
//! \param defaultNotFound Value returned when attributeName was not found
//! \return Returns value of the attribute previously set by setAttribute()
virtual core::quaternion getAttributeAsQuaternion(const c8* attributeName, const core::quaternion& defaultNotFound=core::quaternion(0,1,0, 0)) const _IRR_OVERRIDE_;
//! Gets an attribute as quaternion
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual core::quaternion getAttributeAsQuaternion(s32 index) const _IRR_OVERRIDE_;
//! Sets an attribute as quaternion
virtual void setAttribute(s32 index, const core::quaternion& v) _IRR_OVERRIDE_;
/*
3d bounding box
*/
//! Adds an attribute as axis aligned bounding box
virtual void addBox3d(const c8* attributeName, const core::aabbox3df& v) _IRR_OVERRIDE_;
//! Sets an attribute as axis aligned bounding box
virtual void setAttribute(const c8* attributeName, const core::aabbox3df& v) _IRR_OVERRIDE_;
//! Gets an attribute as a axis aligned bounding box
//! \param attributeName: Name of the attribute to get.
//! \param defaultNotFound Value returned when attributeName was not found
//! \return Returns value of the attribute previously set by setAttribute()
virtual core::aabbox3df getAttributeAsBox3d(const c8* attributeName, const core::aabbox3df& defaultNotFound=core::aabbox3df(0,0,0, 0,0,0)) const _IRR_OVERRIDE_;
//! Gets an attribute as axis aligned bounding box
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual core::aabbox3df getAttributeAsBox3d(s32 index) const _IRR_OVERRIDE_;
//! Sets an attribute as axis aligned bounding box
virtual void setAttribute(s32 index, const core::aabbox3df& v) _IRR_OVERRIDE_;
/*
plane
*/
//! Adds an attribute as 3d plane
virtual void addPlane3d(const c8* attributeName, const core::plane3df& v) _IRR_OVERRIDE_;
//! Sets an attribute as 3d plane
virtual void setAttribute(const c8* attributeName, const core::plane3df& v) _IRR_OVERRIDE_;
//! Gets an attribute as a 3d plane
//! \param attributeName: Name of the attribute to get.
//! \param defaultNotFound Value returned when attributeName was not found
//! \return Returns value of the attribute previously set by setAttribute()
virtual core::plane3df getAttributeAsPlane3d(const c8* attributeName, const core::plane3df& defaultNotFound=core::plane3df(0,0,0, 0,1,0)) const _IRR_OVERRIDE_;
//! Gets an attribute as 3d plane
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual core::plane3df getAttributeAsPlane3d(s32 index) const _IRR_OVERRIDE_;
//! Sets an attribute as 3d plane
virtual void setAttribute(s32 index, const core::plane3df& v) _IRR_OVERRIDE_;
/*
3d triangle
*/
//! Adds an attribute as 3d triangle
virtual void addTriangle3d(const c8* attributeName, const core::triangle3df& v) _IRR_OVERRIDE_;
//! Sets an attribute as 3d triangle
virtual void setAttribute(const c8* attributeName, const core::triangle3df& v) _IRR_OVERRIDE_;
//! Gets an attribute as a 3d triangle
//! \param attributeName: Name of the attribute to get.
//! \param defaultNotFound Value returned when attributeName was not found
//! \return Returns value of the attribute previously set by setAttribute()
virtual core::triangle3df getAttributeAsTriangle3d(const c8* attributeName, const core::triangle3df& defaultNotFound = core::triangle3df(core::vector3df(0,0,0), core::vector3df(0,0,0), core::vector3df(0,0,0))) const _IRR_OVERRIDE_;
//! Gets an attribute as 3d triangle
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual core::triangle3df getAttributeAsTriangle3d(s32 index) const _IRR_OVERRIDE_;
//! Sets an attribute as 3d triangle
virtual void setAttribute(s32 index, const core::triangle3df& v) _IRR_OVERRIDE_;
/*
line 2d
*/
//! Adds an attribute as a 2d line
virtual void addLine2d(const c8* attributeName, const core::line2df& v) _IRR_OVERRIDE_;
//! Sets an attribute as a 2d line
virtual void setAttribute(const c8* attributeName, const core::line2df& v) _IRR_OVERRIDE_;
//! Gets an attribute as a 2d line
//! \param attributeName: Name of the attribute to get.
//! \param defaultNotFound Value returned when attributeName was not found
//! \return Returns value of the attribute previously set by setAttribute()
virtual core::line2df getAttributeAsLine2d(const c8* attributeName, const core::line2df& defaultNotFound = core::line2df(0,0, 0,0)) const _IRR_OVERRIDE_;
//! Gets an attribute as a 2d line
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual core::line2df getAttributeAsLine2d(s32 index) const _IRR_OVERRIDE_;
//! Sets an attribute as a 2d line
virtual void setAttribute(s32 index, const core::line2df& v) _IRR_OVERRIDE_;
/*
line 3d
*/
//! Adds an attribute as a 3d line
virtual void addLine3d(const c8* attributeName, const core::line3df& v) _IRR_OVERRIDE_;
//! Sets an attribute as a 3d line
virtual void setAttribute(const c8* attributeName, const core::line3df& v) _IRR_OVERRIDE_;
//! Gets an attribute as a 3d line
//! \param attributeName: Name of the attribute to get.
//! \param defaultNotFound Value returned when attributeName was not found
//! \return Returns value of the attribute previously set by setAttribute()
virtual core::line3df getAttributeAsLine3d(const c8* attributeName, const core::line3df& defaultNotFound=core::line3df(0,0,0, 0,0,0)) const _IRR_OVERRIDE_;
//! Gets an attribute as a 3d line
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual core::line3df getAttributeAsLine3d(s32 index) const _IRR_OVERRIDE_;
//! Sets an attribute as a 3d line
virtual void setAttribute(s32 index, const core::line3df& v) _IRR_OVERRIDE_;
/*
Texture Attribute
*/
//! Adds an attribute as texture reference
virtual void addTexture(const c8* attributeName, video::ITexture* texture, const io::path& filename = "") _IRR_OVERRIDE_;
//! Sets an attribute as texture reference
virtual void setAttribute(const c8* attributeName, video::ITexture* texture, const io::path& filename = "") _IRR_OVERRIDE_;
//! Gets an attribute as texture reference
//! \param attributeName: Name of the attribute to get.
//! \param defaultNotFound Value returned when attributeName was not found
virtual video::ITexture* getAttributeAsTexture(const c8* attributeName, video::ITexture* defaultNotFound=0) const _IRR_OVERRIDE_;
//! Gets an attribute as texture reference
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual video::ITexture* getAttributeAsTexture(s32 index) const _IRR_OVERRIDE_;
//! Sets an attribute as texture reference
virtual void setAttribute(s32 index, video::ITexture* texture, const io::path& filename = "") _IRR_OVERRIDE_;
/*
User Pointer Attribute
*/
//! Adds an attribute as user pointer
virtual void addUserPointer(const c8* attributeName, void* userPointer) _IRR_OVERRIDE_;
//! Sets an attribute as user pointer
virtual void setAttribute(const c8* attributeName, void* userPointer) _IRR_OVERRIDE_;
//! Gets an attribute as user pointer
//! \param attributeName: Name of the attribute to get.
//! \param defaultNotFound Value returned when attributeName was not found
virtual void* getAttributeAsUserPointer(const c8* attributeName, void* defaultNotFound = 0) const _IRR_OVERRIDE_;
//! Gets an attribute as user pointer
//! \param index: Index value, must be between 0 and getAttributeCount()-1.
virtual void* getAttributeAsUserPointer(s32 index) const _IRR_OVERRIDE_;
//! Sets an attribute as user pointer
virtual void setAttribute(s32 index, void* userPointer) _IRR_OVERRIDE_;
protected:
void readAttributeFromXML(const io::IXMLReader* reader);
core::array<IAttribute*> Attributes;
IAttribute* getAttributeP(const c8* attributeName) const;
video::IVideoDriver* Driver;
};
} // end namespace io
} // end namespace irr
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,91 @@
// Copyright (C) 2006-2012 Luke Hoschke
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
// B3D Mesh loader
// File format designed by Mark Sibly for the Blitz3D engine and has been
// declared public domain
#include "IrrCompileConfig.h"
#ifndef __C_B3D_MESH_LOADER_H_INCLUDED__
#define __C_B3D_MESH_LOADER_H_INCLUDED__
#include "IMeshLoader.h"
#include "ISceneManager.h"
#include "CSkinnedMesh.h"
#include "SB3DStructs.h"
#include "IReadFile.h"
namespace irr
{
namespace scene
{
//! Meshloader for B3D format
class CB3DMeshFileLoader : public IMeshLoader
{
public:
//! Constructor
CB3DMeshFileLoader(scene::ISceneManager* smgr);
//! returns true if the file maybe is able to be loaded by this class
//! based on the file extension (e.g. ".bsp")
virtual bool isALoadableFileExtension(const io::path& filename) const _IRR_OVERRIDE_;
//! creates/loads an animated mesh from the file.
//! \return Pointer to the created mesh. Returns 0 if loading failed.
//! If you no longer need the mesh, you should call IAnimatedMesh::drop().
//! See IReferenceCounted::drop() for more information.
virtual IAnimatedMesh* createMesh(io::IReadFile* file) _IRR_OVERRIDE_;
private:
bool load();
bool readChunkNODE(CSkinnedMesh::SJoint* InJoint);
bool readChunkMESH(CSkinnedMesh::SJoint* InJoint);
bool readChunkVRTS(CSkinnedMesh::SJoint* InJoint);
bool readChunkTRIS(scene::SSkinMeshBuffer *MeshBuffer, u32 MeshBufferID, s32 Vertices_Start);
bool readChunkBONE(CSkinnedMesh::SJoint* InJoint);
bool readChunkKEYS(CSkinnedMesh::SJoint* InJoint);
bool readChunkANIM();
bool readChunkTEXS();
bool readChunkBRUS();
void loadTextures(SB3dMaterial& material) const;
void readString(core::stringc& newstring);
void readFloats(f32* vec, u32 count);
core::array<SB3dChunk> B3dStack;
core::array<SB3dMaterial> Materials;
core::array<SB3dTexture> Textures;
core::array<s32> AnimatedVertices_VertexID;
core::array<s32> AnimatedVertices_BufferID;
core::array<video::S3DVertex2TCoords> BaseVertices;
ISceneManager* SceneManager;
CSkinnedMesh* AnimatedMesh;
io::IReadFile* B3DFile;
//B3Ds have Vertex ID's local within the mesh I don't want this
// Variable needs to be class member due to recursion in calls
u32 VerticesStart;
bool NormalsInFile;
bool HasVertexColors;
bool ShowWarning;
};
} // end namespace scene
} // end namespace irr
#endif // __C_B3D_MESH_LOADER_H_INCLUDED__

View File

@ -0,0 +1,648 @@
// Copyright (C) 2014 Lauri Kasanen
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
// TODO: replace printf's by logging messages
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_B3D_WRITER_
#include "CB3DMeshWriter.h"
#include "os.h"
#include "ISkinnedMesh.h"
#include "IMeshBuffer.h"
#include "IWriteFile.h"
#include "ITexture.h"
#include "irrMap.h"
namespace irr
{
namespace scene
{
using namespace core;
using namespace video;
CB3DMeshWriter::CB3DMeshWriter()
{
#ifdef _DEBUG
setDebugName("CB3DMeshWriter");
#endif
}
//! Returns the type of the mesh writer
EMESH_WRITER_TYPE CB3DMeshWriter::getType() const
{
return EMWT_B3D;
}
//! writes a mesh
bool CB3DMeshWriter::writeMesh(io::IWriteFile* file, IMesh* const mesh, s32 flags)
{
if (!file || !mesh)
return false;
#ifdef __BIG_ENDIAN__
os::Printer::log("B3D export does not support big-endian systems.", ELL_ERROR);
return false;
#endif
Size = 0;
file->write("BB3D", 4);
file->write(&Size, sizeof(u32)); // Updated later once known.
int version = 1;
write(file, &version, sizeof(int));
//
const u32 numBeshBuffers = mesh->getMeshBufferCount();
array<SB3dTexture> texs;
map<ITexture *, u32> tex2id; // TODO: texture pointer as key not sufficient as same texture can have several id's
u32 texsizes = 0;
for (u32 i = 0; i < numBeshBuffers; i++)
{
const IMeshBuffer * const mb = mesh->getMeshBuffer(i);
const SMaterial &mat = mb->getMaterial();
for (u32 j = 0; j < MATERIAL_MAX_TEXTURES; j++)
{
if (mat.getTexture(j))
{
SB3dTexture t;
t.TextureName = core::stringc(mat.getTexture(j)->getName().getPath());
// TODO: need some description of Blitz3D texture-flags to figure this out. But Blend should likely depend on material-type.
t.Flags = j == 2 ? 65536 : 1;
t.Blend = 2;
// TODO: evaluate texture matrix
t.Xpos = 0;
t.Ypos = 0;
t.Xscale = 1;
t.Yscale = 1;
t.Angle = 0;
texs.push_back(t);
texsizes += 7*4 + t.TextureName.size() + 1;
tex2id[mat.getTexture(j)] = texs.size() - 1;
}
}
}
write(file, "TEXS", 4);
write(file, &texsizes, 4);
u32 numTexture = texs.size();
for (u32 i = 0; i < numTexture; i++)
{
write(file, texs[i].TextureName.c_str(), texs[i].TextureName.size() + 1);
write(file, &texs[i].Flags, 7*4);
}
//
const u32 brushsize = (7 * 4 + 1) * numBeshBuffers + numBeshBuffers * 4 * MATERIAL_MAX_TEXTURES + 4;
write(file, "BRUS", 4);
write(file, &brushsize, 4);
u32 brushcheck = Size;
const u32 usedtex = MATERIAL_MAX_TEXTURES;
write(file, &usedtex, 4);
for (u32 i = 0; i < numBeshBuffers; i++)
{
const IMeshBuffer * const mb = mesh->getMeshBuffer(i);
const SMaterial &mat = mb->getMaterial();
write(file, "", 1);
float f = 1;
write(file, &f, 4);
write(file, &f, 4);
write(file, &f, 4);
write(file, &f, 4);
f = 0;
write(file, &f, 4);
u32 tmp = 1;
write(file, &tmp, 4);
tmp = 0;
write(file, &tmp, 4);
for (u32 j = 0; j < MATERIAL_MAX_TEXTURES; j++)
{
if (mat.getTexture(j))
{
const u32 id = tex2id[mat.getTexture(j)];
write(file, &id, 4);
}
else
{
const int id = -1;
write(file, &id, 4);
}
}
}
// Check brushsize
brushcheck = Size - brushcheck;
if (brushcheck != brushsize)
{
printf("Failed in brush size calculation, size %u advanced %u\n",
brushsize, brushcheck);
}
write(file, "NODE", 4);
// Calculate node size
u32 nodesize = 41 + 8 + 4 + 8;
u32 bonesSize = 0;
if(ISkinnedMesh *skinnedMesh = getSkinned(mesh))
{
if (!skinnedMesh->isStatic())
{
bonesSize += 20;
}
const core::array<ISkinnedMesh::SJoint*> rootJoints = getRootJoints(skinnedMesh);
for (u32 i = 0; i < rootJoints.size(); i++)
{
bonesSize += getJointChunkSize(skinnedMesh, rootJoints[i]);
}
nodesize += bonesSize;
// -------------------
}
// VERT data
nodesize += 12;
const u32 texcoords = getUVlayerCount(mesh);
for (u32 i = 0; i < numBeshBuffers; i++)
{
nodesize += 8 + 4;
const IMeshBuffer * const mb = mesh->getMeshBuffer(i);
nodesize += mb->getVertexCount() * 10 * 4;
nodesize += mb->getVertexCount() * texcoords * 2 * 4;
nodesize += mb->getIndexCount() * 4;
}
write(file, &nodesize, 4);
u32 nodecheck = Size;
// Node
write(file, "", 1);
float f = 0;
write(file, &f, 4);
write(file, &f, 4);
write(file, &f, 4);
f = 1;
write(file, &f, 4);
write(file, &f, 4);
write(file, &f, 4);
write(file, &f, 4);
f = 0;
write(file, &f, 4);
write(file, &f, 4);
write(file, &f, 4);
// Mesh
write(file, "MESH", 4);
const u32 meshsize = nodesize - 41 - 8 - bonesSize;
write(file, &meshsize, 4);
s32 brushID = -1;
write(file, &brushID, 4);
// Verts
write(file, "VRTS", 4);
u32 vertsize = 12;
for (u32 i = 0; i < numBeshBuffers; i++)
{
const IMeshBuffer * const mb = mesh->getMeshBuffer(i);
vertsize += mb->getVertexCount() * 10 * 4 +
mb->getVertexCount() * texcoords * 2 * 4;
}
write(file, &vertsize, 4);
u32 vertcheck = Size;
int flagsB3D = 3;
write(file, &flagsB3D, 4);
write(file, &texcoords, 4);
flagsB3D = 2;
write(file, &flagsB3D, 4);
for (u32 i = 0; i < numBeshBuffers; i++)
{
const IMeshBuffer * const mb = mesh->getMeshBuffer(i);
irr::u32 numVertices = mb->getVertexCount();
for (u32 j = 0; j < numVertices; j++)
{
const vector3df &pos = mb->getPosition(j);
write(file, &pos.X, 4);
write(file, &pos.Y, 4);
write(file, &pos.Z, 4);
const vector3df &n = mb->getNormal(j);
write(file, &n.X, 4);
write(file, &n.Y, 4);
write(file, &n.Z, 4);
const u32 zero = 0;
switch (mb->getVertexType())
{
case EVT_STANDARD:
{
S3DVertex *v = (S3DVertex *) mb->getVertices();
const SColorf col(v[j].Color);
write(file, &col.r, 4);
write(file, &col.g, 4);
write(file, &col.b, 4);
write(file, &col.a, 4);
write(file, &v[j].TCoords.X, 4);
write(file, &v[j].TCoords.Y, 4);
if (texcoords == 2)
{
write(file, &zero, 4);
write(file, &zero, 4);
}
}
break;
case EVT_2TCOORDS:
{
S3DVertex2TCoords *v = (S3DVertex2TCoords *) mb->getVertices();
const SColorf col(v[j].Color);
write(file, &col.r, 4);
write(file, &col.g, 4);
write(file, &col.b, 4);
write(file, &col.a, 4);
write(file, &v[j].TCoords.X, 4);
write(file, &v[j].TCoords.Y, 4);
write(file, &v[j].TCoords2.X, 4);
write(file, &v[j].TCoords2.Y, 4);
}
break;
case EVT_TANGENTS:
{
S3DVertexTangents *v = (S3DVertexTangents *) mb->getVertices();
const SColorf col(v[j].Color);
write(file, &col.r, 4);
write(file, &col.g, 4);
write(file, &col.b, 4);
write(file, &col.a, 4);
write(file, &v[j].TCoords.X, 4);
write(file, &v[j].TCoords.Y, 4);
if (texcoords == 2)
{
write(file, &zero, 4);
write(file, &zero, 4);
}
}
break;
}
}
}
// Check vertsize
vertcheck = Size - vertcheck;
if (vertcheck != vertsize)
{
printf("Failed in vertex size calculation, size %u advanced %u\n",
vertsize, vertcheck);
}
u32 currentMeshBufferIndex = 0;
// Tris
for (u32 i = 0; i < numBeshBuffers; i++)
{
const IMeshBuffer * const mb = mesh->getMeshBuffer(i);
write(file, "TRIS", 4);
const u32 trisize = 4 + mb->getIndexCount() * 4;
write(file, &trisize, 4);
u32 tricheck = Size;
write(file, &i, 4);
u32 numIndices = mb->getIndexCount();
const u16 * const idx = (u16 *) mb->getIndices();
for (u32 j = 0; j < numIndices; j += 3)
{
u32 tmp = idx[j] + currentMeshBufferIndex;
write(file, &tmp, sizeof(u32));
tmp = idx[j + 1] + currentMeshBufferIndex;
write(file, &tmp, sizeof(u32));
tmp = idx[j + 2] + currentMeshBufferIndex;
write(file, &tmp, sizeof(u32));
}
// Check that tris calculation was ok
tricheck = Size - tricheck;
if (tricheck != trisize)
{
printf("Failed in tris size calculation, size %u advanced %u\n",
trisize, tricheck);
}
currentMeshBufferIndex += mb->getVertexCount();
}
if(ISkinnedMesh *skinnedMesh = getSkinned(mesh))
{
// Write animation data
if (!skinnedMesh->isStatic())
{
write(file, "ANIM", 4);
const u32 animsize = 12;
write(file, &animsize, 4);
const u32 flags = 0;
const u32 frames = skinnedMesh->getFrameCount();
const f32 fps = skinnedMesh->getAnimationSpeed();
write(file, &flags, 4);
write(file, &frames, 4);
write(file, &fps, 4);
}
// Write joints
core::array<ISkinnedMesh::SJoint*> rootJoints = getRootJoints(skinnedMesh);
for (u32 i = 0; i < rootJoints.size(); i++)
{
writeJointChunk(file, skinnedMesh, rootJoints[i]);
}
}
// Check that node calculation was ok
nodecheck = Size - nodecheck;
if (nodecheck != nodesize)
{
printf("Failed in node size calculation, size %u advanced %u\n",
nodesize, nodecheck);
}
file->seek(4);
file->write(&Size, 4);
return true;
}
void CB3DMeshWriter::writeJointChunk(io::IWriteFile* file, ISkinnedMesh* mesh , ISkinnedMesh::SJoint* joint)
{
// Node
write(file, "NODE", 4);
// Calculate node size
u32 nodesize = getJointChunkSize(mesh, joint);
nodesize -= 8; // The declaration + size of THIS chunk shouldn't be added to the size
write(file, &nodesize, 4);
core::stringc name = joint->Name;
write(file, name.c_str(), name.size());
write(file, "", 1);
core::vector3df pos = joint->Animatedposition;
// Position
write(file, &pos.X, 4);
write(file, &pos.Y, 4);
write(file, &pos.Z, 4);
// Scale
core::vector3df scale = joint->Animatedscale;
if (scale == core::vector3df(0, 0, 0))
scale = core::vector3df(1, 1, 1);
write(file, &scale.X, 4);
write(file, &scale.Y, 4);
write(file, &scale.Z, 4);
// Rotation
core::quaternion quat = joint->Animatedrotation;
write(file, &quat.W, 4);
write(file, &quat.X, 4);
write(file, &quat.Y, 4);
write(file, &quat.Z, 4);
// Bone
write(file, "BONE", 4);
u32 bonesize = 8 * joint->Weights.size();
write(file, &bonesize, 4);
// Skinning ------------------
for (u32 i = 0; i < joint->Weights.size(); i++)
{
const u32 vertexID = joint->Weights[i].vertex_id;
const u32 bufferID = joint->Weights[i].buffer_id;
const f32 weight = joint->Weights[i].strength;
u32 b3dVertexID = vertexID;
for (u32 j = 0; j < bufferID; j++)
{
b3dVertexID += mesh->getMeshBuffer(j)->getVertexCount();
}
write(file, &b3dVertexID, 4);
write(file, &weight, 4);
}
// ---------------------------
// Animation keys
if (joint->PositionKeys.size())
{
write(file, "KEYS", 4);
u32 keysSize = 4 * joint->PositionKeys.size() * 4; // X, Y and Z pos + frame
keysSize += 4; // Flag to define the type of the key
write(file, &keysSize, 4);
u32 flag = 1; // 1 = flag for position keys
write(file, &flag, 4);
for (u32 i = 0; i < joint->PositionKeys.size(); i++)
{
const s32 frame = static_cast<s32>(joint->PositionKeys[i].frame);
const core::vector3df pos = joint->PositionKeys[i].position;
write (file, &frame, 4);
write (file, &pos.X, 4);
write (file, &pos.Y, 4);
write (file, &pos.Z, 4);
}
}
if (joint->RotationKeys.size())
{
write(file, "KEYS", 4);
u32 keysSize = 4 * joint->RotationKeys.size() * 5; // W, X, Y and Z rot + frame
keysSize += 4; // Flag
write(file, &keysSize, 4);
u32 flag = 4;
write(file, &flag, 4);
for (u32 i = 0; i < joint->RotationKeys.size(); i++)
{
const s32 frame = static_cast<s32>(joint->RotationKeys[i].frame);
const core::quaternion rot = joint->RotationKeys[i].rotation;
write (file, &frame, 4);
write (file, &rot.W, 4);
write (file, &rot.X, 4);
write (file, &rot.Y, 4);
write (file, &rot.Z, 4);
}
}
if (joint->ScaleKeys.size())
{
write(file, "KEYS", 4);
u32 keysSize = 4 * joint->ScaleKeys.size() * 4; // X, Y and Z scale + frame
keysSize += 4; // Flag
write(file, &keysSize, 4);
u32 flag = 2;
write(file, &flag, 4);
for (u32 i = 0; i < joint->ScaleKeys.size(); i++)
{
const s32 frame = static_cast<s32>(joint->ScaleKeys[i].frame);
const core::vector3df scale = joint->ScaleKeys[i].scale;
write (file, &frame, 4);
write (file, &scale.X, 4);
write (file, &scale.Y, 4);
write (file, &scale.Z, 4);
}
}
for (u32 i = 0; i < joint->Children.size(); i++)
{
writeJointChunk(file, mesh, joint->Children[i]);
}
}
ISkinnedMesh* CB3DMeshWriter::getSkinned (IMesh *mesh)
{
if (mesh->getMeshType() == EAMT_SKINNED)
{
return static_cast<ISkinnedMesh*>(mesh);
}
return 0;
}
u32 CB3DMeshWriter::getJointChunkSize(const ISkinnedMesh* mesh, ISkinnedMesh::SJoint* joint)
{
u32 chunkSize = 8 + 40; // Chunk declaration + chunk data
chunkSize += joint->Name.size() + 1; // the NULL character at the end of the string
u32 boneSize = joint->Weights.size() * 8; // vertex_id + weight = 8 bits per weight block
boneSize += 8; // declaration + size of he BONE chunk
u32 keysSize = 0;
if (joint->PositionKeys.size() != 0)
{
keysSize += 8; // KEYS + chunk size
keysSize += 4; // flags
keysSize += (joint->PositionKeys.size() * 16);
}
if (joint->RotationKeys.size() != 0)
{
keysSize += 8; // KEYS + chunk size
keysSize += 4; // flags
keysSize += (joint->RotationKeys.size() * 20);
}
if (joint->ScaleKeys.size() != 0)
{
keysSize += 8; // KEYS + chunk size
keysSize += 4; // flags
keysSize += (joint->ScaleKeys.size() * 16);
}
chunkSize += boneSize;
chunkSize += keysSize;
for (u32 i = 0; i < joint->Children.size(); ++i)
{
chunkSize += (getJointChunkSize(mesh, joint->Children[i]));
}
return chunkSize;
}
core::array<ISkinnedMesh::SJoint*> CB3DMeshWriter::getRootJoints(const ISkinnedMesh* mesh)
{
core::array<ISkinnedMesh::SJoint*> roots;
core::array<ISkinnedMesh::SJoint*> allJoints = mesh->getAllJoints();
for (u32 i = 0; i < allJoints.size(); i++)
{
bool isRoot = true;
ISkinnedMesh::SJoint* testedJoint = allJoints[i];
for (u32 j = 0; j < allJoints.size(); j++)
{
ISkinnedMesh::SJoint* testedJoint2 = allJoints[j];
for (u32 k = 0; k < testedJoint2->Children.size(); k++)
{
if (testedJoint == testedJoint2->Children[k])
isRoot = false;
}
}
if (isRoot)
roots.push_back(testedJoint);
}
return roots;
}
u32 CB3DMeshWriter::getUVlayerCount(IMesh* mesh)
{
const u32 numBeshBuffers = mesh->getMeshBufferCount();
for (u32 i = 0; i < numBeshBuffers; i++)
{
const IMeshBuffer * const mb = mesh->getMeshBuffer(i);
if (mb->getVertexType() == EVT_2TCOORDS)
{
return 2;
}
}
return 1;
}
void CB3DMeshWriter::write(io::IWriteFile* file, const void *ptr, const u32 bytes)
{
file->write(ptr, bytes);
Size += bytes;
}
} // end namespace
} // end namespace
#endif // _IRR_COMPILE_WITH_B3D_WRITER_

View File

@ -0,0 +1,52 @@
// Copyright (C) 2014 Lauri Kasanen
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
// Modified version with rigging/skinning support
#ifndef __IRR_B3D_MESH_WRITER_H_INCLUDED__
#define __IRR_B3D_MESH_WRITER_H_INCLUDED__
#include "IMeshWriter.h"
#include "IWriteFile.h"
#include "SB3DStructs.h"
#include "ISkinnedMesh.h"
namespace irr
{
namespace scene
{
//! class to write B3D mesh files
class CB3DMeshWriter : public IMeshWriter
{
public:
CB3DMeshWriter();
//! Returns the type of the mesh writer
virtual EMESH_WRITER_TYPE getType() const _IRR_OVERRIDE_;
//! writes a mesh
virtual bool writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32 flags=EMWF_NONE) _IRR_OVERRIDE_;
private:
u32 Size;
void writeJointChunk(io::IWriteFile* file, ISkinnedMesh* mesh , ISkinnedMesh::SJoint* joint);
u32 getJointChunkSize(const ISkinnedMesh* mesh, ISkinnedMesh::SJoint* joint);
core::array<ISkinnedMesh::SJoint*> getRootJoints(const ISkinnedMesh* mesh);
u32 getUVlayerCount(IMesh *mesh);
ISkinnedMesh* getSkinned (IMesh *mesh);
void write(io::IWriteFile* file, const void *ptr, const u32 bytes);
};
} // end namespace
} // end namespace
#endif

View File

@ -0,0 +1,107 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_BSP_LOADER_
#include "CBSPMeshFileLoader.h"
#include "CQ3LevelMesh.h"
namespace irr
{
namespace scene
{
//! Constructor
CBSPMeshFileLoader::CBSPMeshFileLoader(scene::ISceneManager* smgr,
io::IFileSystem* fs)
: FileSystem(fs), SceneManager(smgr)
{
#ifdef _DEBUG
setDebugName("CBSPMeshFileLoader");
#endif
if (FileSystem)
FileSystem->grab();
}
//! destructor
CBSPMeshFileLoader::~CBSPMeshFileLoader()
{
if (FileSystem)
FileSystem->drop();
}
//! returns true if the file maybe is able to be loaded by this class
//! based on the file extension (e.g. ".bsp")
bool CBSPMeshFileLoader::isALoadableFileExtension(const io::path& filename) const
{
return core::hasFileExtension ( filename, "bsp", "shader", "cfg" );
}
//! creates/loads an animated mesh from the file.
//! \return Pointer to the created mesh. Returns 0 if loading failed.
//! If you no longer need the mesh, you should call IAnimatedMesh::drop().
//! See IReferenceCounted::drop() for more information.
IAnimatedMesh* CBSPMeshFileLoader::createMesh(io::IReadFile* file)
{
s32 type = core::isFileExtension ( file->getFileName(), "bsp", "shader", "cfg" );
CQ3LevelMesh* q = 0;
switch ( type )
{
case 1:
q = new CQ3LevelMesh(FileSystem, SceneManager, LoadParam);
// determine real shaders in LoadParam
if ( 0 == LoadParam.loadAllShaders )
{
q->getShader("scripts/common.shader");
q->getShader("scripts/sfx.shader");
q->getShader("scripts/gfx.shader");
q->getShader("scripts/liquid.shader");
q->getShader("scripts/models.shader");
q->getShader("scripts/walls.shader");
//q->getShader("scripts/sky.shader");
}
if ( q->loadFile(file) )
return q;
q->drop();
break;
case 2:
q = new CQ3LevelMesh(FileSystem, SceneManager,LoadParam);
q->getShader( file );
return q;
break;
case 3:
// load quake 3 loading parameter
if ( file->getFileName() == "levelparameter.cfg" )
{
file->read ( &LoadParam, sizeof ( LoadParam ) );
}
else
{
q = new CQ3LevelMesh(FileSystem, SceneManager,LoadParam);
q->getConfiguration( file );
return q;
}
break;
}
return 0;
}
} // end namespace scene
} // end namespace irr
#endif // _IRR_COMPILE_WITH_BSP_LOADER_

View File

@ -0,0 +1,52 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_BSP_MESH_FILE_LOADER_H_INCLUDED__
#define __C_BSP_MESH_FILE_LOADER_H_INCLUDED__
#include "IMeshLoader.h"
#include "IFileSystem.h"
#include "IVideoDriver.h"
#include "ISceneManager.h"
#include "IQ3Shader.h"
namespace irr
{
namespace scene
{
//! Meshloader capable of loading Quake 3 BSP files and shaders
class CBSPMeshFileLoader : public IMeshLoader
{
public:
//! Constructor
CBSPMeshFileLoader(scene::ISceneManager* smgr, io::IFileSystem* fs);
//! destructor
virtual ~CBSPMeshFileLoader();
//! returns true if the file maybe is able to be loaded by this class
//! based on the file extension (e.g. ".bsp")
virtual bool isALoadableFileExtension(const io::path& filename) const _IRR_OVERRIDE_;
//! creates/loads an animated mesh from the file.
//! \return Pointer to the created mesh. Returns 0 if loading failed.
//! If you no longer need the mesh, you should call IAnimatedMesh::drop().
//! See IReferenceCounted::drop() for more information.
virtual IAnimatedMesh* createMesh(io::IReadFile* file) _IRR_OVERRIDE_;
private:
io::IFileSystem* FileSystem;
scene::ISceneManager* SceneManager;
quake3::Q3LevelLoadParameter LoadParam;
};
} // end namespace scene
} // end namespace irr
#endif

View File

@ -0,0 +1,321 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_BILLBOARD_SCENENODE_
#include "CBillboardSceneNode.h"
#include "IVideoDriver.h"
#include "ISceneManager.h"
#include "ICameraSceneNode.h"
#include "os.h"
namespace irr
{
namespace scene
{
//! constructor
CBillboardSceneNode::CBillboardSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id,
const core::vector3df& position, const core::dimension2d<f32>& size,
video::SColor colorTop, video::SColor colorBottom)
: IBillboardSceneNode(parent, mgr, id, position)
, Buffer(new SMeshBuffer())
{
#ifdef _DEBUG
setDebugName("CBillboardSceneNode");
#endif
setSize(size);
Buffer->Vertices.set_used(4);
Buffer->Indices.set_used(6);
Buffer->Indices[0] = 0;
Buffer->Indices[1] = 2;
Buffer->Indices[2] = 1;
Buffer->Indices[3] = 0;
Buffer->Indices[4] = 3;
Buffer->Indices[5] = 2;
Buffer->Vertices[0].TCoords.set(1.0f, 1.0f);
Buffer->Vertices[0].Color = colorBottom;
Buffer->Vertices[1].TCoords.set(1.0f, 0.0f);
Buffer->Vertices[1].Color = colorTop;
Buffer->Vertices[2].TCoords.set(0.0f, 0.0f);
Buffer->Vertices[2].Color = colorTop;
Buffer->Vertices[3].TCoords.set(0.0f, 1.0f);
Buffer->Vertices[3].Color = colorBottom;
}
CBillboardSceneNode::~CBillboardSceneNode()
{
Buffer->drop();
}
//! pre render event
void CBillboardSceneNode::OnRegisterSceneNode()
{
if (IsVisible)
SceneManager->registerNodeForRendering(this);
ISceneNode::OnRegisterSceneNode();
}
//! render
void CBillboardSceneNode::render()
{
video::IVideoDriver* driver = SceneManager->getVideoDriver();
ICameraSceneNode* camera = SceneManager->getActiveCamera();
if (!camera || !driver)
return;
// make billboard look to camera
updateMesh(camera);
driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
driver->setMaterial(Buffer->Material);
driver->drawMeshBuffer(Buffer);
if (DebugDataVisible & scene::EDS_BBOX)
{
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
video::SMaterial m;
m.Lighting = false;
driver->setMaterial(m);
driver->draw3DBox(BBoxSafe, video::SColor(0,208,195,152));
}
}
void CBillboardSceneNode::updateMesh(const irr::scene::ICameraSceneNode* camera)
{
// billboard looks toward camera
core::vector3df pos = getAbsolutePosition();
core::vector3df campos = camera->getAbsolutePosition();
core::vector3df target = camera->getTarget();
core::vector3df up = camera->getUpVector();
core::vector3df view = target - campos;
view.normalize();
core::vector3df horizontal = up.crossProduct(view);
if ( horizontal.getLength() == 0 )
{
horizontal.set(up.Y,up.X,up.Z);
}
horizontal.normalize();
core::vector3df topHorizontal = horizontal * 0.5f * TopEdgeWidth;
horizontal *= 0.5f * Size.Width;
// pointing down!
core::vector3df vertical = horizontal.crossProduct(view);
vertical.normalize();
vertical *= 0.5f * Size.Height;
view *= -1.0f;
core::array<video::S3DVertex>& vertices = Buffer->Vertices;
for (s32 i=0; i<4; ++i)
vertices[i].Normal = view;
/* Vertices are:
2--1
|\ |
| \|
3--0
*/
vertices[0].Pos = pos + horizontal + vertical;
vertices[1].Pos = pos + topHorizontal - vertical;
vertices[2].Pos = pos - topHorizontal - vertical;
vertices[3].Pos = pos - horizontal + vertical;
Buffer->setDirty(EBT_VERTEX);
Buffer->recalculateBoundingBox();
}
//! returns the axis aligned bounding box of this node
const core::aabbox3d<f32>& CBillboardSceneNode::getBoundingBox() const
{
// Really wrong when scaled.
return BBoxSafe;
}
const core::aabbox3d<f32>& CBillboardSceneNode::getTransformedBillboardBoundingBox(const irr::scene::ICameraSceneNode* camera)
{
updateMesh(camera);
return Buffer->BoundingBox;
}
void CBillboardSceneNode::setSize(const core::dimension2d<f32>& size)
{
Size = size;
if (core::equals(Size.Width, 0.0f))
Size.Width = 1.0f;
TopEdgeWidth = Size.Width;
if (core::equals(Size.Height, 0.0f))
Size.Height = 1.0f;
const f32 avg = (Size.Width + Size.Height)/6;
BBoxSafe.MinEdge.set(-avg,-avg,-avg);
BBoxSafe.MaxEdge.set(avg,avg,avg);
}
void CBillboardSceneNode::setSize(f32 height, f32 bottomEdgeWidth, f32 topEdgeWidth)
{
Size.set(bottomEdgeWidth, height);
TopEdgeWidth = topEdgeWidth;
if (core::equals(Size.Height, 0.0f))
Size.Height = 1.0f;
if (core::equals(Size.Width, 0.f) && core::equals(TopEdgeWidth, 0.f))
{
Size.Width = 1.0f;
TopEdgeWidth = 1.0f;
}
const f32 avg = (core::max_(Size.Width,TopEdgeWidth) + Size.Height)/6;
BBoxSafe.MinEdge.set(-avg,-avg,-avg);
BBoxSafe.MaxEdge.set(avg,avg,avg);
}
video::SMaterial& CBillboardSceneNode::getMaterial(u32 i)
{
return Buffer->Material;
}
//! returns amount of materials used by this scene node.
u32 CBillboardSceneNode::getMaterialCount() const
{
return 1;
}
//! gets the size of the billboard
const core::dimension2d<f32>& CBillboardSceneNode::getSize() const
{
return Size;
}
//! Gets the widths of the top and bottom edges of the billboard.
void CBillboardSceneNode::getSize(f32& height, f32& bottomEdgeWidth,
f32& topEdgeWidth) const
{
height = Size.Height;
bottomEdgeWidth = Size.Width;
topEdgeWidth = TopEdgeWidth;
}
//! Writes attributes of the scene node.
void CBillboardSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
{
IBillboardSceneNode::serializeAttributes(out, options);
out->addFloat("Width", Size.Width);
out->addFloat("TopEdgeWidth", TopEdgeWidth);
out->addFloat("Height", Size.Height);
out->addColor("Shade_Top", Buffer->Vertices[1].Color);
out->addColor("Shade_Down", Buffer->Vertices[0].Color);
}
//! Reads attributes of the scene node.
void CBillboardSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
{
IBillboardSceneNode::deserializeAttributes(in, options);
Size.Width = in->getAttributeAsFloat("Width");
Size.Height = in->getAttributeAsFloat("Height");
if (in->existsAttribute("TopEdgeWidth"))
{
TopEdgeWidth = in->getAttributeAsFloat("TopEdgeWidth");
if (Size.Width != TopEdgeWidth)
setSize(Size.Height, Size.Width, TopEdgeWidth);
}
else
setSize(Size);
Buffer->Vertices[1].Color = in->getAttributeAsColor("Shade_Top");
Buffer->Vertices[0].Color = in->getAttributeAsColor("Shade_Down");
Buffer->Vertices[2].Color = Buffer->Vertices[1].Color;
Buffer->Vertices[3].Color = Buffer->Vertices[0].Color;
}
//! Set the color of all vertices of the billboard
//! \param overallColor: the color to set
void CBillboardSceneNode::setColor(const video::SColor& overallColor)
{
for(u32 vertex = 0; vertex < 4; ++vertex)
Buffer->Vertices[vertex].Color = overallColor;
}
//! Set the color of the top and bottom vertices of the billboard
//! \param topColor: the color to set the top vertices
//! \param bottomColor: the color to set the bottom vertices
void CBillboardSceneNode::setColor(const video::SColor& topColor,
const video::SColor& bottomColor)
{
Buffer->Vertices[0].Color = bottomColor;
Buffer->Vertices[1].Color = topColor;
Buffer->Vertices[2].Color = topColor;
Buffer->Vertices[3].Color = bottomColor;
}
//! Gets the color of the top and bottom vertices of the billboard
//! \param[out] topColor: stores the color of the top vertices
//! \param[out] bottomColor: stores the color of the bottom vertices
void CBillboardSceneNode::getColor(video::SColor& topColor,
video::SColor& bottomColor) const
{
bottomColor = Buffer->Vertices[0].Color;
topColor = Buffer->Vertices[1].Color;
}
//! Creates a clone of this scene node and its children.
ISceneNode* CBillboardSceneNode::clone(ISceneNode* newParent, ISceneManager* newManager)
{
if (!newParent)
newParent = Parent;
if (!newManager)
newManager = SceneManager;
CBillboardSceneNode* nb = new CBillboardSceneNode(newParent,
newManager, ID, RelativeTranslation, Size);
nb->cloneMembers(this, newManager);
nb->Buffer->Material = Buffer->Material;
nb->Size = Size;
nb->TopEdgeWidth = this->TopEdgeWidth;
video::SColor topColor,bottomColor;
getColor(topColor,bottomColor);
nb->setColor(topColor,bottomColor);
if ( newParent )
nb->drop();
return nb;
}
} // end namespace scene
} // end namespace irr
#endif // _IRR_COMPILE_WITH_BILLBOARD_SCENENODE_

View File

@ -0,0 +1,112 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_BILLBOARD_SCENE_NODE_H_INCLUDED__
#define __C_BILLBOARD_SCENE_NODE_H_INCLUDED__
#include "IBillboardSceneNode.h"
#include "SMeshBuffer.h"
namespace irr
{
namespace scene
{
//! Scene node which is a billboard. A billboard is like a 3d sprite: A 2d element,
//! which always looks to the camera.
class CBillboardSceneNode : virtual public IBillboardSceneNode
{
public:
//! constructor
CBillboardSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id,
const core::vector3df& position, const core::dimension2d<f32>& size,
video::SColor colorTop=video::SColor(0xFFFFFFFF),
video::SColor colorBottom=video::SColor(0xFFFFFFFF));
virtual ~CBillboardSceneNode();
//! pre render event
virtual void OnRegisterSceneNode() _IRR_OVERRIDE_;
//! render
virtual void render() _IRR_OVERRIDE_;
//! returns the axis aligned bounding box of this node
virtual const core::aabbox3d<f32>& getBoundingBox() const _IRR_OVERRIDE_;
//! sets the size of the billboard
virtual void setSize(const core::dimension2d<f32>& size) _IRR_OVERRIDE_;
//! Sets the widths of the top and bottom edges of the billboard independently.
virtual void setSize(f32 height, f32 bottomEdgeWidth, f32 topEdgeWidth) _IRR_OVERRIDE_;
//! gets the size of the billboard
virtual const core::dimension2d<f32>& getSize() const _IRR_OVERRIDE_;
//! Gets the widths of the top and bottom edges of the billboard.
virtual void getSize(f32& height, f32& bottomEdgeWidth, f32& topEdgeWidth) const _IRR_OVERRIDE_;
virtual video::SMaterial& getMaterial(u32 i) _IRR_OVERRIDE_;
//! returns amount of materials used by this scene node.
virtual u32 getMaterialCount() const _IRR_OVERRIDE_;
//! Set the color of all vertices of the billboard
//! \param overallColor: the color to set
virtual void setColor(const video::SColor& overallColor) _IRR_OVERRIDE_;
//! Set the color of the top and bottom vertices of the billboard
//! \param topColor: the color to set the top vertices
//! \param bottomColor: the color to set the bottom vertices
virtual void setColor(const video::SColor& topColor,
const video::SColor& bottomColor) _IRR_OVERRIDE_;
//! Gets the color of the top and bottom vertices of the billboard
//! \param[out] topColor: stores the color of the top vertices
//! \param[out] bottomColor: stores the color of the bottom vertices
virtual void getColor(video::SColor& topColor,
video::SColor& bottomColor) const _IRR_OVERRIDE_;
//! Get the real boundingbox used by the billboard (which depends on the active camera)
virtual const core::aabbox3d<f32>& getTransformedBillboardBoundingBox(const irr::scene::ICameraSceneNode* camera) _IRR_OVERRIDE_;
//! Writes attributes of the scene node.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const _IRR_OVERRIDE_;
//! Reads attributes of the scene node.
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) _IRR_OVERRIDE_;
//! Returns type of the scene node
virtual ESCENE_NODE_TYPE getType() const _IRR_OVERRIDE_ { return ESNT_BILLBOARD; }
//! Creates a clone of this scene node and its children.
virtual ISceneNode* clone(ISceneNode* newParent=0, ISceneManager* newManager=0) _IRR_OVERRIDE_;
protected:
void updateMesh(const irr::scene::ICameraSceneNode* camera);
private:
//! Size.Width is the bottom edge width
core::dimension2d<f32> Size;
f32 TopEdgeWidth;
//! BoundingBox which is large enough to contain the billboard independent of the camera
// TODO: BUG - still can be wrong with scaling < 1. Billboards should calculate relative coordinates for their mesh
// and then use the node-scaling. But needs some work...
/** Note that we can't use the real boundingbox for culling because at that point
the camera which is used to calculate the billboard is not yet updated. So we only
know the real boundingbox after rendering - which is too late for culling. */
core::aabbox3d<f32> BBoxSafe;
scene::SMeshBuffer* Buffer;
};
} // end namespace scene
} // end namespace irr
#endif

1422
source/Irrlicht/CBlit.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,129 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_
#include "CBoneSceneNode.h"
namespace irr
{
namespace scene
{
//! constructor
CBoneSceneNode::CBoneSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id,
u32 boneIndex, const c8* boneName)
: IBoneSceneNode(parent, mgr, id), BoneIndex(boneIndex),
AnimationMode(EBAM_AUTOMATIC), SkinningSpace(EBSS_LOCAL)
{
#ifdef _DEBUG
setDebugName("CBoneSceneNode");
#endif
setName(boneName);
}
//! Returns the index of the bone
u32 CBoneSceneNode::getBoneIndex() const
{
return BoneIndex;
}
//! Sets the animation mode of the bone. Returns true if successful.
bool CBoneSceneNode::setAnimationMode(E_BONE_ANIMATION_MODE mode)
{
AnimationMode = mode;
return true;
}
//! Gets the current animation mode of the bone
E_BONE_ANIMATION_MODE CBoneSceneNode::getAnimationMode() const
{
return AnimationMode;
}
//! returns the axis aligned bounding box of this node
const core::aabbox3d<f32>& CBoneSceneNode::getBoundingBox() const
{
return Box;
}
/*
//! Returns the relative transformation of the scene node.
core::matrix4 CBoneSceneNode::getRelativeTransformation() const
{
return core::matrix4(); // RelativeTransformation;
}
*/
void CBoneSceneNode::OnAnimate(u32 timeMs)
{
if (IsVisible)
{
// animate this node with all animators
ISceneNodeAnimatorList::Iterator ait = Animators.begin();
for (; ait != Animators.end(); ++ait)
(*ait)->animateNode(this, timeMs);
// update absolute position
//updateAbsolutePosition();
// perform the post render process on all children
ISceneNodeList::Iterator it = Children.begin();
for (; it != Children.end(); ++it)
(*it)->OnAnimate(timeMs);
}
}
void CBoneSceneNode::helper_updateAbsolutePositionOfAllChildren(ISceneNode *Node)
{
Node->updateAbsolutePosition();
ISceneNodeList::ConstIterator it = Node->getChildren().begin();
for (; it != Node->getChildren().end(); ++it)
{
helper_updateAbsolutePositionOfAllChildren( (*it) );
}
}
void CBoneSceneNode::updateAbsolutePositionOfAllChildren()
{
helper_updateAbsolutePositionOfAllChildren( this );
}
void CBoneSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
{
IBoneSceneNode::serializeAttributes(out, options);
out->addInt("BoneIndex", BoneIndex);
out->addEnum("AnimationMode", AnimationMode, BoneAnimationModeNames);
}
void CBoneSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
{
BoneIndex = in->getAttributeAsInt("BoneIndex");
AnimationMode = (E_BONE_ANIMATION_MODE)in->getAttributeAsEnumeration("AnimationMode", BoneAnimationModeNames);
// for legacy files (before 1.5)
const core::stringc boneName = in->getAttributeAsString("BoneName");
setName(boneName);
IBoneSceneNode::deserializeAttributes(in, options);
// TODO: add/replace bone in parent with bone from mesh
}
} // namespace scene
} // namespace irr
#endif

View File

@ -0,0 +1,79 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_BONE_SCENE_NODE_H_INCLUDED__
#define __C_BONE_SCENE_NODE_H_INCLUDED__
// Used with SkinnedMesh and IAnimatedMeshSceneNode, for boned meshes
#include "IBoneSceneNode.h"
namespace irr
{
namespace scene
{
class CBoneSceneNode : public IBoneSceneNode
{
public:
//! constructor
CBoneSceneNode(ISceneNode* parent, ISceneManager* mgr,
s32 id=-1, u32 boneIndex=0, const c8* boneName=0);
//! Returns the index of the bone
virtual u32 getBoneIndex() const _IRR_OVERRIDE_;
//! Sets the animation mode of the bone. Returns true if successful.
virtual bool setAnimationMode(E_BONE_ANIMATION_MODE mode) _IRR_OVERRIDE_;
//! Gets the current animation mode of the bone
virtual E_BONE_ANIMATION_MODE getAnimationMode() const _IRR_OVERRIDE_;
//! returns the axis aligned bounding box of this node
virtual const core::aabbox3d<f32>& getBoundingBox() const _IRR_OVERRIDE_;
/*
//! Returns the relative transformation of the scene node.
//virtual core::matrix4 getRelativeTransformation() const _IRR_OVERRIDE_;
*/
virtual void OnAnimate(u32 timeMs) _IRR_OVERRIDE_;
virtual void updateAbsolutePositionOfAllChildren() _IRR_OVERRIDE_;
//! Writes attributes of the scene node.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const _IRR_OVERRIDE_;
//! Reads attributes of the scene node.
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) _IRR_OVERRIDE_;
//! How the relative transformation of the bone is used
virtual void setSkinningSpace(E_BONE_SKINNING_SPACE space) _IRR_OVERRIDE_
{
SkinningSpace=space;
}
virtual E_BONE_SKINNING_SPACE getSkinningSpace() const _IRR_OVERRIDE_
{
return SkinningSpace;
}
private:
void helper_updateAbsolutePositionOfAllChildren(ISceneNode *Node);
u32 BoneIndex;
core::aabbox3d<f32> Box;
E_BONE_ANIMATION_MODE AnimationMode;
E_BONE_SKINNING_SPACE SkinningSpace;
};
} // end namespace scene
} // end namespace irr
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,859 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
//
// This file was written by Saurav Mohapatra and modified by Nikolaus Gebhardt.
// See CCSMLoader.h for details.
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_CSM_LOADER_
#include "CCSMLoader.h"
#include "CMeshTextureLoader.h"
#include "os.h"
#include "IFileSystem.h"
#include "IReadFile.h"
#include "ISceneManager.h"
#include "IAttributes.h"
#include "SMesh.h"
#include "IVideoDriver.h"
#include "SAnimatedMesh.h"
#include "SMeshBufferLightMap.h"
#ifdef _DEBUG
#define _IRR_DEBUG_CSM_LOADER_
#endif
namespace irr
{
namespace scene
{
//
// the CSM data types
//
struct color_rgb_t
{
s32 red;
s32 green;
s32 blue;
color_rgb_t() : red(0), green(0), blue(0) {}
void clear() { red=0; green=0; blue=0; }
video::SColor toSColor() const { return video::SColor(255, red, green, blue); }
};
//
// A Binary File Reader
//
struct BinaryFileReader
{
BinaryFileReader(io::IReadFile* pFile) : file(pFile) { }
size_t readBuffer(void* buffer, s32 len)
{
return file->read(buffer,len);
}
s32 readLong();
f32 readFloat();
void readString(core::stringc &str);
void readVec3f(core::vector3df* v);
void readVec2f(core::vector2df* v);
void readColorRGB(color_rgb_t* color);
io::IReadFile *file;
};
//
// The file header
//
class Header
{
public:
enum E_CSM_VERSION
{
VERSION_4 = 4,
VERSION_4_1 = 5
};
Header(){ clear(); }
s32 getVersion() const { return version; }
void clear(){ version = 0; }
void load(BinaryFileReader* pReader)
{
version = pReader->readLong();
}
private:
s32 version;
};
//
// The groups
//
class Group
{
public:
Group(){ clear(); }
~Group(){ clear(); }
void clear();
void load(BinaryFileReader* pReader);
s32 getFlags() const { return flags; }
s32 getParentGroupID() const { return parentGroup; }
const core::stringc& getProperties() const { return props; }
video::SColor getColor() const { return color.toSColor(); }
private:
s32 flags;
s32 parentGroup;
core::stringc props;
color_rgb_t color;
};
//
// The visgroups
//
class VisGroup
{
public:
VisGroup(){ clear(); }
~VisGroup(){ clear(); }
void clear();
void load(BinaryFileReader* pReader);
s32 getFlags() const{ return flags; }
const core::stringc& getName() const{ return name; }
video::SColor getColor() const{ return color.toSColor(); }
private:
core::stringc name;
s32 flags;
color_rgb_t color;
};
//
// Lightmaps
//
class LightMap
{
public:
LightMap() : pixelData(0){ clear(); }
~LightMap(){ clear(); }
void clear();
void load(BinaryFileReader* pReader);
s32 getWidth() const{ return width; }
s32 getHeight() const{ return height; }
s32* getPixelData() const{ return pixelData; }
private:
s32 width;
s32 height;
s32* pixelData;
};
struct Triangle
{
s32 a,b,c;
};
struct Line
{
s32 a,b;
};
class Vertex
{
public:
Vertex(){ clear(); }
~Vertex(){ clear(); }
void clear();
void load(BinaryFileReader* pReader);
const core::vector3df& getPosition() const { return position; }
const core::vector3df& getNormal() const { return normal; }
video::SColor getColor() const { return color.toSColor(); }
const core::vector3df& getTextureCoordinates() const { return texCoords; }
const core::vector3df& getLightMapCoordinates() const { return lmapCoords; }
private:
core::vector3df position;
core::vector3df normal;
color_rgb_t color;
core::vector3df texCoords;
core::vector3df lmapCoords;
};
class Surface
{
public:
Surface() { clear(); }
~Surface(){ clear(); }
void clear();
void load(BinaryFileReader *pReader);
s32 getFlags() const{ return flags; }
const core::stringc& getTextureName() const{ return textureName; }
s32 getLightMapId() const{ return lightMapId; }
const core::vector2df* getUVOffset() const{ return &uvOffset; }
const core::vector2df* getUVScale() const{ return &uvScale; }
f32 getUVRotation() const{ return uvRotation; }
u32 getVertexCount() const{ return vertices.size(); }
const Vertex& getVertexAt(const s32 index) const{ return vertices[index]; }
u32 getTriangleCount() const{ return triangles.size(); }
const Triangle& getTriangleAt(const s32 index) const{ return triangles[index]; }
private:
s32 flags;
core::stringc textureName;
s32 lightMapId;
core::vector2df uvOffset;
core::vector2df uvScale;
f32 uvRotation;
core::array<Vertex> vertices;
core::array<Triangle> triangles;
core::array<Line> lines;
};
class Mesh
{
public:
Mesh(){ clear(); }
~Mesh(){ clear(); }
void clear();
void load(BinaryFileReader* pReader, bool bReadVisGroups);
s32 getFlags() const { return flags; }
s32 getGroupID() const { return groupId; }
const core::stringc& getProperties() const { return props; }
video::SColor getColor() const { return color.toSColor(); }
const core::vector3df* getPosition() const { return &position; }
s32 getVisgroupID() const { return visgroupId; }
s32 getSurfaceCount() const { return surfaces.size(); }
const Surface* getSurfaceAt(const s32 index) const { return surfaces[index]; }
private:
s32 flags;
s32 groupId;
core::stringc props;
color_rgb_t color;
core::vector3df position;
s32 visgroupId;
core::array<Surface*> surfaces;
};
class Entity
{
public:
Entity() { clear(); }
~Entity() { clear(); }
void clear();
void load(BinaryFileReader* pReader);
s32 getVisgroupID() const { return visgroupId; }
s32 getGroupID() const { return groupId; }
const core::stringc& getProperties() const { return props; }
const core::vector3df* getPosition() const { return &position; }
private:
s32 visgroupId;
s32 groupId;
core::stringc props;
core::vector3df position;
};
class CameraData
{
public:
CameraData(){ clear(); }
~CameraData(){ clear(); }
void clear();
void load(BinaryFileReader* pReader);
const core::vector3df* getPosition(){ return &position; }
f32 getPitch(){ return pitch; }
f32 getYaw(){ return yaw; }
private:
core::vector3df position;
f32 pitch;
f32 yaw;
};
//
// A CSM File
//
class CSMFile
{
public:
CSMFile(){ clear(); }
~CSMFile(){ clear(); }
void clear();
void load(BinaryFileReader* pReader);
const Header* getHeader() const{ return &header; }
u32 getGroupCount() const{ return groups.size(); }
const Group* getGroupAt(const s32 index) const{ return groups[index]; }
u32 getVisGroupCount() const{ return visgroups.size(); }
const VisGroup* getVisGroupAt(const s32 index) const{ return visgroups[index]; }
u32 getLightMapCount() const{ return lightmaps.size(); }
const LightMap* getLightMapAt(const s32 index) const { return lightmaps[index]; }
u32 getMeshCount() const{ return meshes.size(); }
const Mesh* getMeshAt(const s32 index) const{ return meshes[index]; }
u32 getEntityCount() const{ return entities.size(); }
const Entity* getEntityAt(const s32 index) const{ return entities[index]; }
const CameraData* getCameraData() const{ return &cameraData; }
private:
Header header;
core::array<Group*> groups;
core::array<VisGroup*> visgroups;
core::array<LightMap*> lightmaps;
core::array<Mesh*> meshes;
core::array<Entity*> entities;
CameraData cameraData;
};
CCSMLoader::CCSMLoader(scene::ISceneManager* manager, io::IFileSystem* fs)
: FileSystem(fs), SceneManager(manager)
{
#ifdef _DEBUG
setDebugName("CCSMLoader");
#endif
TextureLoader = new CMeshTextureLoader( FileSystem, SceneManager->getVideoDriver() );
}
//! returns true if the file maybe is able to be loaded by this class
//! based on the file extension (e.g. ".bsp")
bool CCSMLoader::isALoadableFileExtension(const io::path& filename) const
{
return core::hasFileExtension ( filename, "csm" );
}
//! creates/loads an animated mesh from the file.
IAnimatedMesh* CCSMLoader::createMesh(io::IReadFile* file)
{
if ( getMeshTextureLoader() )
getMeshTextureLoader()->setMeshFile(file);
scene::IMesh* m = createCSMMesh(file);
if (!m)
return 0;
SAnimatedMesh* am = new SAnimatedMesh();
am->Type = EAMT_CSM;
am->addMesh(m);
m->drop();
am->recalculateBoundingBox();
return am;
}
scene::IMesh* CCSMLoader::createCSMMesh(io::IReadFile* file)
{
if (!file)
return 0;
BinaryFileReader reader(file);
CSMFile csmFile;
csmFile.load(&reader);
return createIrrlichtMesh(&csmFile, file->getFileName());
}
scene::IMesh* CCSMLoader::createIrrlichtMesh(const CSMFile* csmFile, const io::path& lmprefix)
{
if ( getMeshTextureLoader() )
{
if ( SceneManager->getParameters()->existsAttribute(CSM_TEXTURE_PATH) )
getMeshTextureLoader()->setTexturePath( SceneManager->getParameters()->getAttributeAsString(CSM_TEXTURE_PATH) );
}
scene::SMesh *pMesh = new scene::SMesh();
video::IVideoDriver* driver = SceneManager->getVideoDriver();
for(u32 l = 0; l<csmFile->getLightMapCount(); l++)
{
const LightMap* lmap = csmFile->getLightMapAt(l);
io::path lmapName = lmprefix;
lmapName += "LMAP_";
lmapName += io::path(l+1);
os::Printer::log("CCSMLoader loading light map", lmapName.c_str());
video::IImage* lmapImg = driver->createImageFromData(
video::ECF_A8R8G8B8,
core::dimension2d<u32>(lmap->getWidth(),lmap->getHeight()),
lmap->getPixelData());
driver->addTexture(lmapName.c_str(), lmapImg);
lmapImg->drop();
}
for(u32 m = 0; m<csmFile->getMeshCount(); m++)
{
const Mesh* mshPtr = csmFile->getMeshAt(m);
for(s32 s = 0; s < mshPtr->getSurfaceCount(); s++)
{
const Surface* surface = mshPtr->getSurfaceAt(s);
video::ITexture* texture = getMeshTextureLoader() ? getMeshTextureLoader()->getTexture(surface->getTextureName()) : NULL;
// same lightmap name as above where they are created
io::path lmapName = lmprefix;
lmapName += "LMAP_";
lmapName += io::path(surface->getLightMapId());
scene::SMeshBufferLightMap *buffer = new scene::SMeshBufferLightMap();
buffer->Material.setTexture(0, texture);
if (surface->getLightMapId())
{
buffer->Material.setTexture(1, driver->getTexture(lmapName));
buffer->Material.Lighting = false;
buffer->Material.MaterialType = video::EMT_LIGHTMAP_ADD;
}
buffer->Vertices.reallocate(surface->getVertexCount());
for(u32 v = 0; v < surface->getVertexCount(); ++v)
{
const Vertex& vtxPtr = surface->getVertexAt(v);
video::S3DVertex2TCoords vtx;
vtx.Pos = vtxPtr.getPosition();
vtx.Normal = vtxPtr.getPosition();
vtx.Color=vtxPtr.getColor();
vtx.TCoords.set(vtxPtr.getTextureCoordinates().X, 1.f-vtxPtr.getTextureCoordinates().Y);
vtx.TCoords2.set(vtxPtr.getLightMapCoordinates().X, 1.f-vtxPtr.getLightMapCoordinates().Y);
buffer->Vertices.push_back(vtx);
}
buffer->Indices.reallocate(surface->getTriangleCount()*3);
for(u32 t = 0; t < surface->getTriangleCount(); ++t)
{
const Triangle& tri = surface->getTriangleAt(t);
buffer->Indices.push_back(tri.c);
buffer->Indices.push_back(tri.b);
buffer->Indices.push_back(tri.a);
}
buffer->recalculateBoundingBox();
pMesh->addMeshBuffer(buffer);
buffer->drop();
}
}
pMesh->recalculateBoundingBox();
return pMesh;
}
void Group::clear()
{
color.clear();
flags = 0;
parentGroup = 0;
props = "";
}
void Group::load(BinaryFileReader* pReader)
{
flags = pReader->readLong();
parentGroup = pReader->readLong();
pReader->readString(props);
pReader->readColorRGB(&color);
}
void VisGroup::clear()
{
color.clear();
flags = 0;
name = "";
}
void VisGroup::load(BinaryFileReader* pReader)
{
pReader->readString(name);
flags = pReader->readLong();
pReader->readColorRGB(&color);
}
void LightMap::clear()
{
delete[] pixelData;
pixelData = 0;
width = height = 0;
}
void LightMap::load(BinaryFileReader* pReader)
{
width = pReader->readLong();
height = pReader->readLong();
pixelData = new s32[width * height];
pReader->readBuffer(pixelData, width * height * sizeof(s32));
}
void Mesh::clear()
{
flags = 0;
groupId = 0;
visgroupId = 0;
props = "";
color.clear();
position.set(0,0,0);
for(u32 s = 0; s < surfaces.size(); s++)
{
delete surfaces[s];
}
surfaces.clear();
}
void Mesh::load(BinaryFileReader* pReader, bool bReadVisGroups)
{
flags = pReader->readLong();
groupId = pReader->readLong();
pReader->readString(props);
pReader->readColorRGB(&color);
pReader->readVec3f(&position);
if(bReadVisGroups)
visgroupId = pReader->readLong();
else
visgroupId = 0;
s32 count = pReader->readLong();
for(s32 i = 0; i < count; i++)
{
Surface* surf = new Surface();
surf->load(pReader);
surfaces.push_back(surf);
}
}
void Surface::clear()
{
flags = 0;
lightMapId = 0;
textureName = "";
uvOffset.set(0.0f,0.0f);
uvScale.set(0.0f,0.0f);
uvRotation = 0.0f;
triangles.clear();
lines.clear();
vertices.clear();
}
void Surface::load(BinaryFileReader* pReader)
{
flags = pReader->readLong();
pReader->readString(textureName);
textureName.replace('\\', '/');
lightMapId = pReader->readLong();
pReader->readVec2f(&uvOffset);
pReader->readVec2f(&uvScale);
uvRotation = pReader->readFloat();
s32 vtxCount = pReader->readLong();
s32 triCount = pReader->readLong();
s32 lineCount = pReader->readLong();
for(s32 v = 0; v < vtxCount; v++)
{
vertices.push_back(Vertex());
vertices.getLast().load(pReader);
}
for(s32 t = 0; t < triCount; t++)
{
Triangle tri;
pReader->readBuffer(&tri, sizeof(tri));
triangles.push_back(tri);
}
for(s32 l = 0; l < lineCount; l++)
{
Line line;
pReader->readBuffer(&line,sizeof(line));
lines.push_back(line);
}
}
void Vertex::clear()
{
position.set(0,0,0);
normal.set(0,0,0);
color.clear();
texCoords.set(0,0,0);
lmapCoords.set(0,0,0);
}
void Vertex::load(BinaryFileReader* pReader)
{
pReader->readVec3f(&position);
pReader->readVec3f(&normal);
pReader->readColorRGB(&color);
pReader->readVec3f(&texCoords);
pReader->readVec3f(&lmapCoords);
}
void Entity::clear()
{
visgroupId = groupId = 0;
props = "";
position.set(0,0,0);
}
void Entity::load(BinaryFileReader* pReader)
{
visgroupId = pReader->readLong();
groupId = pReader->readLong();
pReader->readString(props);
pReader->readVec3f(&position);
}
void CameraData::clear()
{
position.set(0,0,0);
pitch = 0;
yaw = 0;
}
void CameraData::load(BinaryFileReader* pReader)
{
pReader->readVec3f(&position);
pitch = pReader->readFloat();
yaw = pReader->readFloat();
}
void CSMFile::clear()
{
header.clear();
cameraData.clear();
u32 x =0;
for( x= 0; x < groups.size(); x++)
delete groups[x];
groups.clear();
for(x= 0; x < visgroups.size(); x++)
delete visgroups[x];
visgroups.clear();
for(x= 0; x < lightmaps.size(); x++)
delete lightmaps[x];
lightmaps.clear();
for(x= 0; x < meshes.size(); x++)
delete meshes[x];
meshes.clear();
for(x= 0; x < entities.size(); x++)
delete entities[x];
entities.clear();
}
void CSMFile::load(BinaryFileReader* pReader)
{
clear();
header.load(pReader);
//groups
{
const s32 count = pReader->readLong();
#ifdef _IRR_DEBUG_CSM_LOADER_
os::Printer::log("CSM Version", core::stringc(header.getVersion()).c_str());
os::Printer::log("Loading groups. Count", core::stringc(count));
#endif
groups.reallocate(count);
for (s32 i = 0; i < count; i++)
{
Group* grp = new Group();
grp->load(pReader);
groups.push_back(grp);
}
}
const bool bHasVGroups = (header.getVersion() == Header::VERSION_4_1);
if (bHasVGroups)
{
//visgroups
const s32 count = pReader->readLong();
#ifdef _IRR_DEBUG_CSM_LOADER_
os::Printer::log("Loading visgroups. Count", core::stringc(count));
#endif
visgroups.reallocate(count);
for (s32 i = 0; i < count; i++)
{
VisGroup* grp = new VisGroup();
grp->load(pReader);
visgroups.push_back(grp);
}
}
//lightmaps
{
const s32 count = pReader->readLong();
#ifdef _IRR_DEBUG_CSM_LOADER_
os::Printer::log("Loading lightmaps. Count", core::stringc(count));
#endif
lightmaps.reallocate(count);
for(s32 i = 0; i < count; i++)
{
LightMap* lm = new LightMap();
lm->load(pReader);
lightmaps.push_back(lm);
}
}
//meshes
{
const s32 count = pReader->readLong();
#ifdef _IRR_DEBUG_CSM_LOADER_
os::Printer::log("Loading meshes. Count", core::stringc(count));
#endif
meshes.reallocate(count);
for(s32 i = 0; i < count; i++)
{
Mesh* mesh = new Mesh();
mesh->load(pReader,bHasVGroups);
meshes.push_back(mesh);
}
}
//entities
{
const s32 count = pReader->readLong();
#ifdef _IRR_DEBUG_CSM_LOADER_
os::Printer::log("Loading entitites. Count", core::stringc(count));
#endif
entities.reallocate(count);
for(s32 i = 0; i < count; i++)
{
Entity* ent = new Entity();
ent->load(pReader);
entities.push_back(ent);
}
}
//camera data
#ifdef _IRR_DEBUG_CSM_LOADER_
os::Printer::log("Loading camera data.");
#endif
cameraData.load(pReader);
}
s32 BinaryFileReader::readLong()
{
int ret = 0;
readBuffer(&ret,sizeof(int));
#ifdef __BIG_ENDIAN__
ret = os::Byteswap::byteswap(ret);
#endif
return ret;
}
f32 BinaryFileReader::readFloat()
{
float ret = 0;
readBuffer(&ret,sizeof(float));
#ifdef __BIG_ENDIAN__
ret = os::Byteswap::byteswap(ret);
#endif
return ret;
}
void BinaryFileReader::readString(core::stringc &str)
{
str = "";
c8 c;
readBuffer(&c,sizeof(char));
while(c != 0)
{
str += c;
readBuffer(&c,sizeof(char));
}
}
void BinaryFileReader::readVec3f(core::vector3df* v)
{
v->X = readFloat();
v->Y = readFloat();
v->Z = readFloat();
}
void BinaryFileReader::readVec2f(core::vector2df* v)
{
v->X = readFloat();
v->Y = readFloat();
}
void BinaryFileReader::readColorRGB(color_rgb_t* color)
{
readBuffer(color,sizeof(color_rgb_t));
}
} // end namespace
} // end namespace
#endif // _IRR_COMPILE_WITH_CSM_LOADER_

View File

@ -0,0 +1,81 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
//
// This Loader has been originally written by Saurav Mohapatra. I (Nikolaus Gebhardt)
// modified some minor things and integrated it into Irrlicht 0.9. Thanks a lot
// to Saurav Mohapatra for his work on this and that he gave me his permission to
// add it into Irrlicht.
// I did some changes to Saurav Mohapatra's loader, so I'm writing this down here:
// - Replaced all dependencies to STL and stdio with irr:: methods/constructs.
// - Moved everything into namespace irr::scene
// - Replaced logging with Irrlicht's internal logger.
// - Removed dependency to IrrlichtDevice
// - Moved all internal structures into CCSMLoader.cpp
// - Made the texture root parameter dependent on a ISceneManager string parameter
// - removed exceptions
// - Implemented CCCSMLoader as IMeshLoader
// - Fixed some problems with memory leaks
// - Fixed bounding box calculation
//
// The original readme of this file looks like this:
//
// This component provides a loader for the Cartography shop 4.x .csm maps for Irrlicht Engine.
// This is a part of the M_TRIX Project.
// This is licensed under the ZLib/LibPNG license
// The IrrCSM library is written by Saurav Mohapatra.
//
// Features
//
// The IrrCSM library features the following capabilities
//
// * Loads the .csm 4.0 and 4.1 files transparently
// * Presents the loaded file as irr::scene::IAnimatedMesh for easy creation of IOctreeSceneNode
// * Loads the textures given the correct texture root. hence map and textures can be in separate directories
//
// For more information go to http://www.geocities.com/standard_template/irrcsm/downloads.html
#ifndef __CSM_LOADER_H_INCLUDED__
#define __CSM_LOADER_H_INCLUDED__
#include "irrArray.h"
#include "IMesh.h"
#include "irrString.h"
#include "IFileSystem.h"
#include "IMeshLoader.h"
namespace irr
{
namespace scene
{
class CSMFile;
class ISceneManager;
class CCSMLoader : public scene::IMeshLoader
{
public:
CCSMLoader(ISceneManager* manager, io::IFileSystem* fs);
//! returns true if the file maybe is able to be loaded by this class
//! based on the file extension (e.g. ".bsp")
virtual bool isALoadableFileExtension(const io::path& filename) const _IRR_OVERRIDE_;
//! creates/loads an animated mesh from the file.
virtual IAnimatedMesh* createMesh(io::IReadFile* file) _IRR_OVERRIDE_;
private:
scene::IMesh* createCSMMesh(io::IReadFile* file);
scene::IMesh* createIrrlichtMesh(const CSMFile* csmFile, const io::path& lmprefix);
io::IFileSystem* FileSystem;
scene::ISceneManager* SceneManager;
};
} // end namespace
} // end namespace
#endif

View File

@ -0,0 +1,401 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CCameraSceneNode.h"
#include "ISceneManager.h"
#include "IVideoDriver.h"
#include "os.h"
namespace irr
{
namespace scene
{
//! constructor
CCameraSceneNode::CCameraSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id,
const core::vector3df& position, const core::vector3df& lookat)
: ICameraSceneNode(parent, mgr, id, position),
BoundingBox(core::vector3df(0, 0, 0)), // Camera has no size. Still not sure if FLT_MAX might be the better variant
Target(lookat), UpVector(0.0f, 1.0f, 0.0f), ZNear(1.0f), ZFar(3000.0f),
InputReceiverEnabled(true), TargetAndRotationAreBound(false),
HasD3DStyleProjectionMatrix(true)
{
#ifdef _DEBUG
setDebugName("CCameraSceneNode");
#endif
// set default projection
Fovy = core::PI / 2.5f; // Field of view, in radians.
const video::IVideoDriver* const d = mgr?mgr->getVideoDriver():0;
if (d)
{
Aspect = (f32)d->getCurrentRenderTargetSize().Width /
(f32)d->getCurrentRenderTargetSize().Height;
HasD3DStyleProjectionMatrix = d->getDriverType() != video::EDT_OPENGL;
}
else
Aspect = 4.0f / 3.0f; // Aspect ratio.
ViewArea.setFarNearDistance(ZFar - ZNear);
recalculateProjectionMatrix();
recalculateViewArea();
}
//! Disables or enables the camera to get key or mouse inputs.
void CCameraSceneNode::setInputReceiverEnabled(bool enabled)
{
InputReceiverEnabled = enabled;
}
//! Returns if the input receiver of the camera is currently enabled.
bool CCameraSceneNode::isInputReceiverEnabled() const
{
return InputReceiverEnabled;
}
//! Sets the projection matrix of the camera.
/** The core::matrix4 class has some methods
to build a projection matrix. e.g: core::matrix4::buildProjectionMatrixPerspectiveFovLH
\param projection: The new projection matrix of the camera. */
void CCameraSceneNode::setProjectionMatrix(const core::matrix4& projection, bool isOrthogonal)
{
IsOrthogonal = isOrthogonal;
ViewArea.getTransform ( video::ETS_PROJECTION ) = projection;
}
//! Gets the current projection matrix of the camera
//! \return Returns the current projection matrix of the camera.
const core::matrix4& CCameraSceneNode::getProjectionMatrix() const
{
return ViewArea.getTransform ( video::ETS_PROJECTION );
}
//! Gets the current view matrix of the camera
//! \return Returns the current view matrix of the camera.
const core::matrix4& CCameraSceneNode::getViewMatrix() const
{
return ViewArea.getTransform ( video::ETS_VIEW );
}
//! Sets a custom view matrix affector. The matrix passed here, will be
//! multiplied with the view matrix when it gets updated.
//! This allows for custom camera setups like, for example, a reflection camera.
/** \param affector: The affector matrix. */
void CCameraSceneNode::setViewMatrixAffector(const core::matrix4& affector)
{
Affector = affector;
}
//! Gets the custom view matrix affector.
const core::matrix4& CCameraSceneNode::getViewMatrixAffector() const
{
return Affector;
}
//! It is possible to send mouse and key events to the camera. Most cameras
//! may ignore this input, but camera scene nodes which are created for
//! example with scene::ISceneManager::addMayaCameraSceneNode or
//! scene::ISceneManager::addFPSCameraSceneNode, may want to get this input
//! for changing their position, look at target or whatever.
bool CCameraSceneNode::OnEvent(const SEvent& event)
{
if (!InputReceiverEnabled)
return false;
// send events to event receiving animators
ISceneNodeAnimatorList::Iterator ait = Animators.begin();
for (; ait != Animators.end(); ++ait)
if ((*ait)->isEventReceiverEnabled() && (*ait)->OnEvent(event))
return true;
// if nobody processed the event, return false
return false;
}
//! sets the look at target of the camera
//! \param pos: Look at target of the camera.
void CCameraSceneNode::setTarget(const core::vector3df& pos)
{
Target = pos;
if(TargetAndRotationAreBound)
{
const core::vector3df toTarget = Target - getAbsolutePosition();
ISceneNode::setRotation(toTarget.getHorizontalAngle());
}
}
//! Sets the rotation of the node.
/** This only modifies the relative rotation of the node.
If the camera's target and rotation are bound ( @see bindTargetAndRotation() )
then calling this will also change the camera's target to match the rotation.
\param rotation New rotation of the node in degrees. */
void CCameraSceneNode::setRotation(const core::vector3df& rotation)
{
if(TargetAndRotationAreBound)
Target = getAbsolutePosition() + rotation.rotationToDirection();
ISceneNode::setRotation(rotation);
}
//! Gets the current look at target of the camera
//! \return Returns the current look at target of the camera
const core::vector3df& CCameraSceneNode::getTarget() const
{
return Target;
}
//! sets the up vector of the camera
//! \param pos: New upvector of the camera.
void CCameraSceneNode::setUpVector(const core::vector3df& pos)
{
UpVector = pos;
}
//! Gets the up vector of the camera.
//! \return Returns the up vector of the camera.
const core::vector3df& CCameraSceneNode::getUpVector() const
{
return UpVector;
}
f32 CCameraSceneNode::getNearValue() const
{
return ZNear;
}
f32 CCameraSceneNode::getFarValue() const
{
return ZFar;
}
f32 CCameraSceneNode::getAspectRatio() const
{
return Aspect;
}
f32 CCameraSceneNode::getFOV() const
{
return Fovy;
}
void CCameraSceneNode::setNearValue(f32 f)
{
ZNear = f;
recalculateProjectionMatrix();
ViewArea.setFarNearDistance(ZFar - ZNear);
}
void CCameraSceneNode::setFarValue(f32 f)
{
ZFar = f;
recalculateProjectionMatrix();
ViewArea.setFarNearDistance(ZFar - ZNear);
}
void CCameraSceneNode::setAspectRatio(f32 f)
{
Aspect = f;
recalculateProjectionMatrix();
}
void CCameraSceneNode::setFOV(f32 f)
{
Fovy = f;
recalculateProjectionMatrix();
}
void CCameraSceneNode::recalculateProjectionMatrix()
{
ViewArea.getTransform ( video::ETS_PROJECTION ).buildProjectionMatrixPerspectiveFovLH(Fovy, Aspect, ZNear, ZFar, HasD3DStyleProjectionMatrix);
IsOrthogonal = false;
}
//! prerender
void CCameraSceneNode::OnRegisterSceneNode()
{
if ( SceneManager->getActiveCamera () == this )
SceneManager->registerNodeForRendering(this, ESNRP_CAMERA);
ISceneNode::OnRegisterSceneNode();
}
//! render
void CCameraSceneNode::render()
{
updateMatrices();
video::IVideoDriver* driver = SceneManager->getVideoDriver();
if ( driver)
{
driver->setTransform(video::ETS_PROJECTION, ViewArea.getTransform ( video::ETS_PROJECTION) );
driver->setTransform(video::ETS_VIEW, ViewArea.getTransform ( video::ETS_VIEW) );
}
}
//! update
void CCameraSceneNode::updateMatrices()
{
core::vector3df pos = getAbsolutePosition();
core::vector3df tgtv = Target - pos;
tgtv.normalize();
// if upvector and vector to the target are the same, we have a
// problem. so solve this problem:
core::vector3df up = UpVector;
up.normalize();
f32 dp = tgtv.dotProduct(up);
if ( core::equals(core::abs_<f32>(dp), 1.f) )
{
up.X += 0.5f;
}
ViewArea.getTransform(video::ETS_VIEW).buildCameraLookAtMatrixLH(pos, Target, up);
ViewArea.getTransform(video::ETS_VIEW) *= Affector;
recalculateViewArea();
}
//! returns the axis aligned bounding box of this node
const core::aabbox3d<f32>& CCameraSceneNode::getBoundingBox() const
{
// NOTE: We deliberately don't return the boundingbox of the ViewArea. People can access that already.
// We want to prevent cameras from having their bounding box colliding in the SceneCollisionManager.
// If another boundingbox is ever necessary then please move BoundingBox to ICameraSceneNode and make it accessible (via a setter or an enum with options).
return BoundingBox;
}
//! returns the view frustum.
const SViewFrustum* CCameraSceneNode::getViewFrustum() const
{
return &ViewArea;
}
void CCameraSceneNode::recalculateViewArea()
{
ViewArea.cameraPosition = getAbsolutePosition();
core::matrix4 m(core::matrix4::EM4CONST_NOTHING);
m.setbyproduct_nocheck(ViewArea.getTransform(video::ETS_PROJECTION),
ViewArea.getTransform(video::ETS_VIEW));
ViewArea.setFrom(m, HasD3DStyleProjectionMatrix);
}
//! Writes attributes of the scene node.
void CCameraSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
{
ICameraSceneNode::serializeAttributes(out, options);
out->addVector3d("Target", Target);
out->addVector3d("UpVector", UpVector);
out->addFloat("Fovy", Fovy);
out->addFloat("Aspect", Aspect);
out->addFloat("ZNear", ZNear);
out->addFloat("ZFar", ZFar);
out->addBool("Binding", TargetAndRotationAreBound);
out->addBool("ReceiveInput", InputReceiverEnabled);
}
//! Reads attributes of the scene node.
void CCameraSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
{
ICameraSceneNode::deserializeAttributes(in, options);
Target = in->getAttributeAsVector3d("Target");
UpVector = in->getAttributeAsVector3d("UpVector");
Fovy = in->getAttributeAsFloat("Fovy");
Aspect = in->getAttributeAsFloat("Aspect");
ZNear = in->getAttributeAsFloat("ZNear");
ZFar = in->getAttributeAsFloat("ZFar");
TargetAndRotationAreBound = in->getAttributeAsBool("Binding");
if ( in->findAttribute("ReceiveInput") )
InputReceiverEnabled = in->getAttributeAsBool("ReceiveInput");
recalculateProjectionMatrix();
recalculateViewArea();
}
//! Set the binding between the camera's rotation adn target.
void CCameraSceneNode::bindTargetAndRotation(bool bound)
{
TargetAndRotationAreBound = bound;
}
//! Gets the binding between the camera's rotation and target.
bool CCameraSceneNode::getTargetAndRotationBinding(void) const
{
return TargetAndRotationAreBound;
}
//! Creates a clone of this scene node and its children.
ISceneNode* CCameraSceneNode::clone(ISceneNode* newParent, ISceneManager* newManager)
{
ICameraSceneNode::clone(newParent, newManager);
if (!newParent)
newParent = Parent;
if (!newManager)
newManager = SceneManager;
CCameraSceneNode* nb = new CCameraSceneNode(newParent,
newManager, ID, RelativeTranslation, Target);
nb->ISceneNode::cloneMembers(this, newManager);
nb->ICameraSceneNode::cloneMembers(this);
nb->Target = Target;
nb->UpVector = UpVector;
nb->Fovy = Fovy;
nb->Aspect = Aspect;
nb->ZNear = ZNear;
nb->ZFar = ZFar;
nb->ViewArea = ViewArea;
nb->Affector = Affector;
nb->InputReceiverEnabled = InputReceiverEnabled;
nb->TargetAndRotationAreBound = TargetAndRotationAreBound;
if ( newParent )
nb->drop();
return nb;
}
} // end namespace
} // end namespace

View File

@ -0,0 +1,179 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_CAMERA_SCENE_NODE_H_INCLUDED__
#define __C_CAMERA_SCENE_NODE_H_INCLUDED__
#include "ICameraSceneNode.h"
#include "SViewFrustum.h"
namespace irr
{
namespace scene
{
class CCameraSceneNode : public ICameraSceneNode
{
public:
//! constructor
CCameraSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id,
const core::vector3df& position = core::vector3df(0,0,0),
const core::vector3df& lookat = core::vector3df(0,0,100));
//! Sets the projection matrix of the camera.
/** The core::matrix4 class has some methods
to build a projection matrix. e.g: core::matrix4::buildProjectionMatrixPerspectiveFovLH.
Note that the matrix will only stay as set by this method until one of
the following Methods are called: setNearValue, setFarValue, setAspectRatio, setFOV.
\param projection The new projection matrix of the camera.
\param isOrthogonal Set this to true if the matrix is an orthogonal one (e.g.
from matrix4::buildProjectionMatrixOrthoLH(). */
virtual void setProjectionMatrix(const core::matrix4& projection, bool isOrthogonal = false) _IRR_OVERRIDE_;
//! Gets the current projection matrix of the camera
//! \return Returns the current projection matrix of the camera.
virtual const core::matrix4& getProjectionMatrix() const _IRR_OVERRIDE_;
//! Gets the current view matrix of the camera
//! \return Returns the current view matrix of the camera.
virtual const core::matrix4& getViewMatrix() const _IRR_OVERRIDE_;
//! Sets a custom view matrix affector.
/** \param affector: The affector matrix. */
virtual void setViewMatrixAffector(const core::matrix4& affector) _IRR_OVERRIDE_;
//! Gets the custom view matrix affector.
virtual const core::matrix4& getViewMatrixAffector() const _IRR_OVERRIDE_;
//! It is possible to send mouse and key events to the camera. Most cameras
//! may ignore this input, but camera scene nodes which are created for
//! example with scene::ISceneManager::addMayaCameraSceneNode or
//! scene::ISceneManager::addMeshViewerCameraSceneNode, may want to get this input
//! for changing their position, look at target or whatever.
virtual bool OnEvent(const SEvent& event) _IRR_OVERRIDE_;
//! Sets the look at target of the camera
/** If the camera's target and rotation are bound ( @see bindTargetAndRotation() )
then calling this will also change the camera's scene node rotation to match the target.
\param pos: Look at target of the camera. */
virtual void setTarget(const core::vector3df& pos) _IRR_OVERRIDE_;
//! Sets the rotation of the node.
/** This only modifies the relative rotation of the node.
If the camera's target and rotation are bound ( @see bindTargetAndRotation() )
then calling this will also change the camera's target to match the rotation.
\param rotation New rotation of the node in degrees. */
virtual void setRotation(const core::vector3df& rotation) _IRR_OVERRIDE_;
//! Gets the current look at target of the camera
/** \return The current look at target of the camera */
virtual const core::vector3df& getTarget() const _IRR_OVERRIDE_;
//! Sets the up vector of the camera.
//! \param pos: New upvector of the camera.
virtual void setUpVector(const core::vector3df& pos) _IRR_OVERRIDE_;
//! Gets the up vector of the camera.
//! \return Returns the up vector of the camera.
virtual const core::vector3df& getUpVector() const _IRR_OVERRIDE_;
//! Gets distance from the camera to the near plane.
//! \return Value of the near plane of the camera.
virtual f32 getNearValue() const _IRR_OVERRIDE_;
//! Gets the distance from the camera to the far plane.
//! \return Value of the far plane of the camera.
virtual f32 getFarValue() const _IRR_OVERRIDE_;
//! Get the aspect ratio of the camera.
//! \return The aspect ratio of the camera.
virtual f32 getAspectRatio() const _IRR_OVERRIDE_;
//! Gets the field of view of the camera.
//! \return Field of view of the camera
virtual f32 getFOV() const _IRR_OVERRIDE_;
//! Sets the value of the near clipping plane. (default: 1.0f)
virtual void setNearValue(f32 zn) _IRR_OVERRIDE_;
//! Sets the value of the far clipping plane (default: 2000.0f)
virtual void setFarValue(f32 zf) _IRR_OVERRIDE_;
//! Sets the aspect ratio (default: 4.0f / 3.0f)
virtual void setAspectRatio(f32 aspect) _IRR_OVERRIDE_;
//! Sets the field of view (Default: PI / 3.5f)
virtual void setFOV(f32 fovy) _IRR_OVERRIDE_;
//! PreRender event
virtual void OnRegisterSceneNode() _IRR_OVERRIDE_;
//! Render
virtual void render() _IRR_OVERRIDE_;
//! Update
virtual void updateMatrices() _IRR_OVERRIDE_;
//! Returns the axis aligned bounding box of this node
virtual const core::aabbox3d<f32>& getBoundingBox() const _IRR_OVERRIDE_;
//! Returns the view area.
virtual const SViewFrustum* getViewFrustum() const _IRR_OVERRIDE_;
//! Disables or enables the camera to get key or mouse inputs.
//! If this is set to true, the camera will respond to key inputs
//! otherwise not.
virtual void setInputReceiverEnabled(bool enabled) _IRR_OVERRIDE_;
//! Returns if the input receiver of the camera is currently enabled.
virtual bool isInputReceiverEnabled() const _IRR_OVERRIDE_;
//! Writes attributes of the scene node.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const _IRR_OVERRIDE_;
//! Reads attributes of the scene node.
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) _IRR_OVERRIDE_;
//! Returns type of the scene node
virtual ESCENE_NODE_TYPE getType() const _IRR_OVERRIDE_ { return ESNT_CAMERA; }
//! Binds the camera scene node's rotation to its target position and vice versa, or unbinds them.
virtual void bindTargetAndRotation(bool bound) _IRR_OVERRIDE_;
//! Queries if the camera scene node's rotation and its target position are bound together.
virtual bool getTargetAndRotationBinding(void) const _IRR_OVERRIDE_;
//! Creates a clone of this scene node and its children.
virtual ISceneNode* clone(ISceneNode* newParent=0, ISceneManager* newManager=0) _IRR_OVERRIDE_;
protected:
void recalculateProjectionMatrix();
void recalculateViewArea();
core::aabbox3d<f32> BoundingBox;
core::vector3df Target;
core::vector3df UpVector;
f32 Fovy; // Field of view, in radians.
f32 Aspect; // Aspect ratio.
f32 ZNear; // value of the near view-plane.
f32 ZFar; // Z-value of the far view-plane.
SViewFrustum ViewArea;
core::matrix4 Affector;
bool InputReceiverEnabled;
bool TargetAndRotationAreBound;
bool HasD3DStyleProjectionMatrix; // true: projection from 0 to w; false: -w to w
};
} // end namespace
} // end namespace
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,410 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_COLLADA_MESH_FILE_LOADER_H_INCLUDED__
#define __C_COLLADA_MESH_FILE_LOADER_H_INCLUDED__
#include "IMeshLoader.h"
#include "IFileSystem.h"
#include "IVideoDriver.h"
#include "irrString.h"
#include "SMesh.h"
#include "SMeshBuffer.h"
#include "ISceneManager.h"
#include "irrMap.h"
#include "CAttributes.h"
namespace irr
{
namespace scene
{
#ifdef _DEBUG
//#define COLLADA_READER_DEBUG
#endif
class IColladaPrefab;
enum ECOLLADA_PARAM_NAME
{
ECPN_COLOR = 0,
ECPN_AMBIENT,
ECPN_DIFFUSE,
ECPN_SPECULAR,
ECPN_SHININESS,
ECPN_TRANSPARENCY,
ECPN_YFOV,
ECPN_ZNEAR,
ECPN_ZFAR,
ECPN_COUNT
};
enum ECOLLADA_PARAM_TYPE
{
ECPT_FLOAT = 0,
ECPT_FLOAT2,
ECPT_FLOAT3,
ECPT_FLOAT4,
ECPT_COUNT
};
//! Collada Parameter
struct SColladaParam
{
SColladaParam()
: Name(ECPN_COUNT), Type(ECPT_COUNT)
{
for (int i=0; i<4; ++i) Floats[i] = 0;
}
ECOLLADA_PARAM_NAME Name;
ECOLLADA_PARAM_TYPE Type;
f32 Floats[4];
};
enum ECOLLADA_INPUT_SEMANTIC
{
ECIS_POSITION = 0,
ECIS_VERTEX,
ECIS_NORMAL,
ECIS_TEXCOORD,
ECIS_UV,
ECIS_TANGENT,
ECIS_IMAGE,
ECIS_TEXTURE,
ECIS_COLOR,
ECIS_COUNT
};
//! Collada Input
struct SColladaInput
{
SColladaInput()
: Semantic(ECIS_COUNT), Data(0), Offset(0), Set(0), Stride(1)
{
}
ECOLLADA_INPUT_SEMANTIC Semantic;
core::stringc Source;
f32* Data;
u32 Offset;
u32 Set;
u32 Stride;
};
//! Collada images
struct SColladaImage
{
core::stringc Id;
core::stringc Source;
core::dimension2du Dimension;
bool SourceIsFilename;
};
//! Collada texture
struct SColladaTexture
{
video::ITexture* Texture;
core::stringc Id;
};
//! Collada material
struct SColladaMaterial
{
video::SMaterial Mat;
core::stringc Id;
core::stringc InstanceEffectId;
f32 Transparency;
inline bool operator< (const SColladaMaterial & other) const
{
return Id < other.Id;
}
};
//! Collada effect (materials, shaders, and programs)
struct SColladaEffect
{
core::stringc Id;
f32 Transparency;
core::array<core::stringc> Textures;
video::SMaterial Mat;
// TODO: Parameters looks somewhat lazy workaround, I think we should really read all parameters correct.
io::IAttributes * Parameters;
inline bool operator< (const SColladaEffect & other) const
{
return Id < other.Id;
}
};
struct SNumberArray // for storing float and int arrays
{
core::stringc Name;
core::array<f32> Data;
};
struct SAccessor
{
SAccessor()
: Count(0), Offset(0), Stride(1) {}
// I don't store the source of the accessor here because I assume
// it to use the array of the source this accessor is located in.
int Count;
int Offset;
int Stride;
core::array<SColladaParam> Parameters; // parameters defining the accessor
};
struct SSource
{
core::stringc Id;
SNumberArray Array;
core::array<SAccessor> Accessors;
};
class CScenePrefab;
//! Meshloader capable of loading COLLADA meshes and scene descriptions into Irrlicht.
class CColladaFileLoader : public IMeshLoader
{
public:
//! Constructor
CColladaFileLoader(scene::ISceneManager* smgr, io::IFileSystem* fs);
//! destructor
virtual ~CColladaFileLoader();
//! returns true if the file maybe is able to be loaded by this class
//! based on the file extension (e.g. ".cob")
virtual bool isALoadableFileExtension(const io::path& filename) const _IRR_OVERRIDE_;
//! creates/loads an animated mesh from the file.
//! \return Pointer to the created mesh. Returns 0 if loading failed.
//! If you no longer need the mesh, you should call IAnimatedMesh::drop().
//! See IReferenceCounted::drop() for more information.
virtual IAnimatedMesh* createMesh(io::IReadFile* file) _IRR_OVERRIDE_;
private:
//! skips an (unknown) section in the collada document
void skipSection(io::IXMLReaderUTF8* reader, bool reportSkipping);
//! reads the <COLLADA> section and its content
void readColladaSection(io::IXMLReaderUTF8* reader);
//! reads a <library> section and its content
void readLibrarySection(io::IXMLReaderUTF8* reader);
//! reads a <visual_scene> element and stores it as a prefab
void readVisualScene(io::IXMLReaderUTF8* reader);
//! reads a <scene> section and its content
void readSceneSection(io::IXMLReaderUTF8* reader);
//! reads a <asset> section and its content
void readAssetSection(io::IXMLReaderUTF8* reader);
//! reads a <node> section and its content
//! if a prefab pointer is passed the nodes are created as scene prefabs children of that prefab
void readNodeSection(io::IXMLReaderUTF8* reader, scene::ISceneNode* parent, CScenePrefab* p=0);
//! reads a <lookat> element and its content and creates a matrix from it
core::matrix4 readLookAtNode(io::IXMLReaderUTF8* reader);
//! reads a <matrix> element and its content and creates a matrix from it
core::matrix4 readMatrixNode(io::IXMLReaderUTF8* reader);
//! reads a <perspective> element and its content and creates a matrix from it
core::matrix4 readPerspectiveNode(io::IXMLReaderUTF8* reader);
//! reads a <rotate> element and its content and creates a matrix from it
core::matrix4 readRotateNode(io::IXMLReaderUTF8* reader);
//! reads a <skew> element and its content and creates a matrix from it
core::matrix4 readSkewNode(io::IXMLReaderUTF8* reader);
//! reads a <boundingbox> element and its content and stores it in bbox
void readBboxNode(io::IXMLReaderUTF8* reader, core::aabbox3df& bbox);
//! reads a <scale> element and its content and creates a matrix from it
core::matrix4 readScaleNode(io::IXMLReaderUTF8* reader);
//! reads a <translate> element and its content and creates a matrix from it
core::matrix4 readTranslateNode(io::IXMLReaderUTF8* reader);
//! reads a <color> element
video::SColorf readColorNode(io::IXMLReaderUTF8* reader);
//! reads a <float> element
f32 readFloatNode(io::IXMLReaderUTF8* reader);
//! reads a <instance> node
void readInstanceNode(io::IXMLReaderUTF8* reader,
scene::ISceneNode* parent, scene::ISceneNode** outNode,
CScenePrefab* p=0, const core::stringc& type=core::stringc());
//! creates a scene node from Prefabs (with name given in 'url')
void instantiateNode(scene::ISceneNode* parent, scene::ISceneNode** outNode=0,
CScenePrefab* p=0, const core::stringc& url="",
const core::stringc& type=core::stringc());
//! reads a <light> element and stores it as prefab
void readLightPrefab(io::IXMLReaderUTF8* reader);
//! reads a <camera> element and stores it as prefab
void readCameraPrefab(io::IXMLReaderUTF8* reader);
//! reads a <image> element and stores it in the image section
void readImage(io::IXMLReaderUTF8* reader);
//! reads a <texture> element and stores it in the texture section
void readTexture(io::IXMLReaderUTF8* reader);
//! reads a <material> element and stores it in the material section
void readMaterial(io::IXMLReaderUTF8* reader);
//! reads a <effect> element and stores it in the effects section
void readEffect(io::IXMLReaderUTF8* reader, SColladaEffect * effect = 0);
//! reads a <geometry> element and stores it as mesh if possible
void readGeometry(io::IXMLReaderUTF8* reader);
//! parses a float from a char pointer and moves the pointer to
//! the end of the parsed float
inline f32 readFloat(const c8** p);
//! parses an int from a char pointer and moves the pointer to
//! the end of the parsed float
inline s32 readInt(const c8** p);
//! places pointer to next begin of a token
void findNextNoneWhiteSpace(const c8** p);
//! reads floats from inside of xml element until end of xml element
void readFloatsInsideElement(io::IXMLReaderUTF8* reader, f32* floats, u32 count);
//! reads ints from inside of xml element until end of xml element
void readIntsInsideElement(io::IXMLReaderUTF8* reader, s32* ints, u32 count);
//! clears all loaded data
void clearData();
//! parses all collada parameters inside an element and stores them in ColladaParameters
void readColladaParameters(io::IXMLReaderUTF8* reader, const core::stringc& parentName);
//! returns a collada parameter or none if not found
SColladaParam* getColladaParameter(ECOLLADA_PARAM_NAME name);
//! parses all collada inputs inside an element and stores them in Inputs. Reads
//! until first tag which is not an input tag or the end of the parent is reached
void readColladaInputs(io::IXMLReaderUTF8* reader, const core::stringc& parentName);
//! reads a collada input tag and adds it to the input parameter
void readColladaInput(io::IXMLReaderUTF8* reader, core::array<SColladaInput>& inputs);
//! returns a collada input or none if not found
SColladaInput* getColladaInput(ECOLLADA_INPUT_SEMANTIC input);
//! read Collada Id, uses id or name if id is missing
core::stringc readId(io::IXMLReaderUTF8* reader);
//! changes the XML URI into an internal id
void uriToId(core::stringc& str);
//! reads a polygons section and creates a mesh from it
void readPolygonSection(io::IXMLReaderUTF8* reader,
core::array<SSource>& sources, scene::SMesh* mesh,
const core::stringc& geometryId);
//! finds a material, possible instancing it
const SColladaMaterial * findMaterial(const core::stringc & materialName);
//! reads and bind materials as given by the symbol->target bind mapping
void readBindMaterialSection(io::IXMLReaderUTF8* reader, const core::stringc & id);
//! create an Irrlicht texture from the SColladaImage
video::ITexture* getTextureFromImage(core::stringc uri, SColladaEffect * effect);
//! read a parameter and value
void readParameter(io::IXMLReaderUTF8* reader, io::IAttributes* parameters);
//! Flip z axis in matrix around to convert between right-handed and left-handed coordinate system.
//! Note that function is symmetric (no difference if called before or after a transpose).
core::matrix4 flipZAxis(const core::matrix4& m);
//! replace escape characters with the unescaped ones
void unescape(irr::core::stringc& uri);
scene::ISceneManager* SceneManager;
io::IFileSystem* FileSystem;
scene::IAnimatedMesh* DummyMesh;
core::stringc CurrentlyLoadingMesh;
scene::IAnimatedMesh* FirstLoadedMesh;
io::path FirstLoadedMeshName;
s32 LoadedMeshCount;
u32 Version;
bool FlipAxis;
core::array<IColladaPrefab*> Prefabs;
core::array<SColladaParam> ColladaParameters;
core::array<SColladaImage> Images;
core::array<SColladaTexture> Textures;
core::array<SColladaMaterial> Materials;
core::array<SColladaInput> Inputs;
core::array<SColladaEffect> Effects;
//! meshbuffer reference ("geomid/matname") -> index into MeshesToBind
core::map<core::stringc,u32> MaterialsToBind;
//! Array of buffers for each material binding
core::array< core::array<irr::scene::IMeshBuffer*> > MeshesToBind;
bool CreateInstances;
struct EscapeCharacterURL
{
EscapeCharacterURL(irr::c8 c, const irr::c8* e)
: Character(c)
{
Escape = e;
}
irr::c8 Character; // unescaped (like ' ')
irr::core::stringc Escape; // escaped (like '%20')
};
irr::core::array<EscapeCharacterURL> EscapeCharsAnyURI;
};
//! following class is for holding and createing instances of library objects,
//! named prefabs in this loader.
class IColladaPrefab : public virtual IReferenceCounted
{
public:
//! creates an instance of this prefab
virtual scene::ISceneNode* addInstance(scene::ISceneNode* parent,
scene::ISceneManager* mgr) = 0;
//! returns id of this prefab
virtual const core::stringc& getId() = 0;
};
} // end namespace scene
} // end namespace irr
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,282 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __IRR_C_COLLADA_MESH_WRITER_H_INCLUDED__
#define __IRR_C_COLLADA_MESH_WRITER_H_INCLUDED__
#include "IColladaMeshWriter.h"
#include "S3DVertex.h"
#include "irrMap.h"
#include "IVideoDriver.h"
#include "IXMLWriter.h"
namespace irr
{
namespace io
{
class IFileSystem;
}
namespace scene
{
//! Callback interface for properties which can be used to influence collada writing
// (Implementer note: keep namespace labels here to make it easier for users copying this one)
class CColladaMeshWriterProperties : public virtual IColladaMeshWriterProperties
{
public:
//! Which lighting model should be used in the technique (FX) section when exporting effects (materials)
virtual irr::scene::E_COLLADA_TECHNIQUE_FX getTechniqueFx(const irr::video::SMaterial& material) const _IRR_OVERRIDE_;
//! Which texture index should be used when writing the texture of the given sampler color.
virtual irr::s32 getTextureIdx(const irr::video::SMaterial & material, irr::scene::E_COLLADA_COLOR_SAMPLER cs) const _IRR_OVERRIDE_;
//! Return which color from Irrlicht should be used for the color requested by collada
virtual irr::scene::E_COLLADA_IRR_COLOR getColorMapping(const irr::video::SMaterial & material, irr::scene::E_COLLADA_COLOR_SAMPLER cs) const _IRR_OVERRIDE_;
//! Return custom colors for certain color types requested by collada.
virtual irr::video::SColor getCustomColor(const irr::video::SMaterial & material, irr::scene::E_COLLADA_COLOR_SAMPLER cs) const _IRR_OVERRIDE_;
//! Return the settings for transparence
virtual irr::scene::E_COLLADA_TRANSPARENT_FX getTransparentFx(const irr::video::SMaterial& material) const _IRR_OVERRIDE_;
//! Transparency value for that material.
virtual irr::f32 getTransparency(const irr::video::SMaterial& material) const _IRR_OVERRIDE_;
//! Reflectivity value for that material
virtual irr::f32 getReflectivity(const irr::video::SMaterial& material) const _IRR_OVERRIDE_;
//! Return index of refraction for that material
virtual irr::f32 getIndexOfRefraction(const irr::video::SMaterial& material) const _IRR_OVERRIDE_;
//! Should node be used in scene export? By default all visible nodes are exported.
virtual bool isExportable(const irr::scene::ISceneNode * node) const _IRR_OVERRIDE_;
//! Return the mesh for the given nod. If it has no mesh or shouldn't export it's mesh return 0.
virtual irr::scene::IMesh* getMesh(irr::scene::ISceneNode * node) _IRR_OVERRIDE_;
//! Return if the node has it's own material overwriting the mesh-materials
virtual bool useNodeMaterial(const scene::ISceneNode* node) const _IRR_OVERRIDE_;
};
class CColladaMeshWriterNames : public virtual IColladaMeshWriterNames
{
public:
CColladaMeshWriterNames(IColladaMeshWriter * writer);
virtual irr::core::stringc nameForMesh(const scene::IMesh* mesh, int instance) _IRR_OVERRIDE_;
virtual irr::core::stringc nameForNode(const scene::ISceneNode* node) _IRR_OVERRIDE_;
virtual irr::core::stringc nameForMaterial(const video::SMaterial & material, int materialId, const scene::IMesh* mesh, const scene::ISceneNode* node) _IRR_OVERRIDE_;
protected:
irr::core::stringc nameForPtr(const void* ptr) const;
private:
IColladaMeshWriter * ColladaMeshWriter;
};
//! class to write meshes, implementing a COLLADA (.dae, .xml) writer
/** This writer implementation has been originally developed for irrEdit and then
merged out to the Irrlicht Engine */
class CColladaMeshWriter : public IColladaMeshWriter
{
public:
CColladaMeshWriter(ISceneManager * smgr, video::IVideoDriver* driver, io::IFileSystem* fs);
virtual ~CColladaMeshWriter();
//! Returns the type of the mesh writer
virtual EMESH_WRITER_TYPE getType() const _IRR_OVERRIDE_;
//! writes a scene starting with the given node
virtual bool writeScene(io::IWriteFile* file, scene::ISceneNode* root, int writeRoot) _IRR_OVERRIDE_;
//! writes a mesh
virtual bool writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32 flags=EMWF_NONE) _IRR_OVERRIDE_;
// Restrict the characters of oldString a set of allowed characters in xs:NCName and add the prefix.
virtual irr::core::stringc toNCName(const irr::core::stringc& oldString, const irr::core::stringc& prefix=irr::core::stringc("_NC_")) const _IRR_OVERRIDE_;
//! After export you can find out which name had been used for writing the geometry for this node.
virtual const irr::core::stringc* findGeometryNameForNode(ISceneNode* node) _IRR_OVERRIDE_;
protected:
void reset();
bool hasSecondTextureCoordinates(video::E_VERTEX_TYPE type) const;
void writeUv(const irr::core::vector2df& vec);
void writeVector(const irr::core::vector3df& vec);
void writeColor(const irr::video::SColorf& colorf, bool writeAlpha=true);
inline irr::core::stringc toString(const irr::video::ECOLOR_FORMAT format) const;
inline irr::core::stringc toString(const irr::video::E_TEXTURE_CLAMP clamp) const;
inline irr::core::stringc toString(const irr::scene::E_COLLADA_TRANSPARENT_FX opaque) const;
inline irr::core::stringc toRef(const irr::core::stringc& source) const;
bool isCamera(const scene::ISceneNode* node) const;
irr::core::stringc nameForMesh(const scene::IMesh* mesh, int instance) const;
irr::core::stringc nameForNode(const scene::ISceneNode* node) const;
irr::core::stringc nameForMaterial(const video::SMaterial & material, int materialId, const scene::IMesh* mesh, const scene::ISceneNode* node);
irr::core::stringc nameForMaterialSymbol(const scene::IMesh* mesh, int materialId) const;
irr::core::stringc findCachedMaterialName(const irr::video::SMaterial& material) const;
irr::core::stringc minTexfilterToString(bool bilinear, bool trilinear) const;
irr::core::stringc magTexfilterToString(bool bilinear, bool trilinear) const;
irr::core::stringc pathToURI(const irr::io::path& path) const;
inline bool isXmlNameStartChar(c8 c) const;
inline bool isXmlNameChar(c8 c) const;
s32 getCheckedTextureIdx(const video::SMaterial & material, E_COLLADA_COLOR_SAMPLER cs);
video::SColor getColorMapping(const video::SMaterial & material, E_COLLADA_COLOR_SAMPLER cs, E_COLLADA_IRR_COLOR colType);
void writeAsset();
void makeMeshNames(irr::scene::ISceneNode * node);
void writeNodeMaterials(irr::scene::ISceneNode * node);
void writeNodeEffects(irr::scene::ISceneNode * node);
void writeNodeLights(irr::scene::ISceneNode * node);
void writeNodeCameras(irr::scene::ISceneNode * node);
void writeAllMeshGeometries();
void writeSceneNode(irr::scene::ISceneNode * node);
void writeMeshMaterials(scene::IMesh* mesh, irr::core::array<irr::core::stringc> * materialNamesOut=0);
void writeMeshEffects(scene::IMesh* mesh);
void writeMaterialEffect(const irr::core::stringc& materialname, const video::SMaterial & material);
void writeMeshGeometry(const irr::core::stringc& meshname, scene::IMesh* mesh);
void writeMeshInstanceGeometry(const irr::core::stringc& meshname, scene::IMesh* mesh, scene::ISceneNode* node=0);
void writeMaterial(const irr::core::stringc& materialname);
void writeLightInstance(const irr::core::stringc& lightName);
void writeCameraInstance(const irr::core::stringc& cameraName);
void writeLibraryImages();
void writeColorFx(const video::SMaterial & material, const c8 * colorname, E_COLLADA_COLOR_SAMPLER cs, const c8* attr1Name=0, const c8* attr1Value=0);
void writeAmbientLightElement(const video::SColorf & col);
void writeColorElement(const video::SColor & col, bool writeAlpha=true);
void writeColorElement(const video::SColorf & col, bool writeAlpha=true);
void writeTextureSampler(s32 textureIdx);
void writeFxElement(const video::SMaterial & material, E_COLLADA_TECHNIQUE_FX techFx);
void writeNode(const c8 * nodeName, const c8 * content);
void writeFloatElement(irr::f32 value);
void writeRotateElement(const irr::core::vector3df& axis, irr::f32 angle);
void writeScaleElement(const irr::core::vector3df& scale);
void writeTranslateElement(const irr::core::vector3df& translate);
void writeLookAtElement(const irr::core::vector3df& eyePos, const irr::core::vector3df& targetPos, const irr::core::vector3df& upVector);
void writeMatrixElement(const irr::core::matrix4& matrix);
struct SComponentGlobalStartPos
{
SComponentGlobalStartPos() : PosStartIndex(0),
NormalStartIndex(0),
TCoord0StartIndex(0),
TCoord1StartIndex(0)
{ }
u32 PosStartIndex;
u32 NormalStartIndex;
u32 TCoord0StartIndex;
u32 TCoord1StartIndex;
};
io::IFileSystem* FileSystem;
video::IVideoDriver* VideoDriver;
io::IXMLWriterUTF8* Writer;
core::array<video::ITexture*> LibraryImages;
io::path Directory;
// Helper struct for creating geometry copies for the ECGI_PER_MESH_AND_MATERIAL settings.
struct SGeometryMeshMaterials
{
bool equals(const core::array<irr::core::stringc>& names) const
{
if ( names.size() != MaterialNames.size() )
return false;
for ( irr::u32 i=0; i<MaterialNames.size(); ++i )
if ( names[i] != MaterialNames[i] )
return false;
return true;
}
irr::core::stringc GeometryName; // replacing the usual ColladaMesh::Name
core::array<irr::core::stringc> MaterialNames; // Material names exported for this instance
core::array<const ISceneNode*> MaterialOwners; // Nodes using this specific mesh-material combination
};
// Check per mesh-ptr if stuff has been written for this mesh already
struct SColladaMesh
{
SColladaMesh() : MaterialsWritten(false), EffectsWritten(false)
{
}
SGeometryMeshMaterials * findGeometryMeshMaterials(const irr::core::array<irr::core::stringc> materialNames)
{
for ( irr::u32 i=0; i<GeometryMeshMaterials.size(); ++i )
{
if ( GeometryMeshMaterials[i].equals(materialNames) )
return &(GeometryMeshMaterials[i]);
}
return NULL;
}
const irr::core::stringc& findGeometryNameForNode(const ISceneNode* node) const
{
if ( GeometryMeshMaterials.size() < 2 )
return Name;
for ( irr::u32 i=0; i<GeometryMeshMaterials.size(); ++i )
{
if ( GeometryMeshMaterials[i].MaterialOwners.linear_search(node) >= 0 )
return GeometryMeshMaterials[i].GeometryName;
}
return Name; // (shouldn't get here usually)
}
irr::core::stringc Name;
bool MaterialsWritten; // just an optimization doing that here in addition to the MaterialsWritten map
bool EffectsWritten; // just an optimization doing that here in addition to the EffectsWritten map
core::array<SGeometryMeshMaterials> GeometryMeshMaterials;
};
typedef core::map<IMesh*, SColladaMesh>::Node MeshNode;
core::map<IMesh*, SColladaMesh> Meshes;
// structure for the lights library
struct SColladaLight
{
SColladaLight() {}
irr::core::stringc Name;
};
typedef core::map<ISceneNode*, SColladaLight>::Node LightNode;
core::map<ISceneNode*, SColladaLight> LightNodes;
// structure for the camera library
typedef core::map<ISceneNode*, irr::core::stringc>::Node CameraNode;
core::map<ISceneNode*, irr::core::stringc> CameraNodes;
// Check per name if stuff has been written already
// TODO: second parameter not needed, we just don't have a core::set class yet in Irrlicht
core::map<irr::core::stringc, bool> MaterialsWritten;
core::map<irr::core::stringc, bool> EffectsWritten;
// Cache material names
struct MaterialName
{
MaterialName(const irr::video::SMaterial & material, const irr::core::stringc& name)
: Material(material), Name(name)
{}
irr::video::SMaterial Material;
irr::core::stringc Name;
};
irr::core::array< MaterialName > MaterialNameCache;
irr::core::stringc WriteBuffer; // use for writing short strings to avoid regular memory allocations
struct EscapeCharacterURL
{
EscapeCharacterURL(irr::c8 c, const irr::c8* e)
: Character(c)
{
Escape = e;
}
irr::c8 Character; // unescaped (like ' ')
irr::core::stringc Escape; // escaped (like '%20')
};
irr::core::array<EscapeCharacterURL> EscapeCharsAnyURI;
};
} // end namespace
} // end namespace
#endif

View File

@ -0,0 +1,830 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CColorConverter.h"
#include "SColor.h"
#include "os.h"
#include "irrString.h"
namespace irr
{
namespace video
{
//! converts a monochrome bitmap to A1R5G5B5 data
void CColorConverter::convert1BitTo16Bit(const u8* in, s16* out, s32 width, s32 height, s32 linepad, bool flip)
{
if (!in || !out)
return;
if (flip)
out += width * height;
for (s32 y=0; y<height; ++y)
{
s32 shift = 7;
if (flip)
out -= width;
for (s32 x=0; x<width; ++x)
{
out[x] = *in>>shift & 0x01 ? (s16)0xffff : (s16)0x8000;
if ((--shift)<0) // 8 pixel done
{
shift=7;
++in;
}
}
if (shift != 7) // width did not fill last byte
++in;
if (!flip)
out += width;
in += linepad;
}
}
//! converts a 4 bit palettized image to A1R5G5B5
void CColorConverter::convert4BitTo16Bit(const u8* in, s16* out, s32 width, s32 height, const s32* palette, s32 linepad, bool flip)
{
if (!in || !out || !palette)
return;
if (flip)
out += width*height;
for (s32 y=0; y<height; ++y)
{
s32 shift = 4;
if (flip)
out -= width;
for (s32 x=0; x<width; ++x)
{
out[x] = X8R8G8B8toA1R5G5B5(palette[(u8)((*in >> shift) & 0xf)]);
if (shift==0)
{
shift = 4;
++in;
}
else
shift = 0;
}
if (shift == 0) // odd width
++in;
if (!flip)
out += width;
in += linepad;
}
}
//! converts a 8 bit palettized image into A1R5G5B5
void CColorConverter::convert8BitTo16Bit(const u8* in, s16* out, s32 width, s32 height, const s32* palette, s32 linepad, bool flip)
{
if (!in || !out || !palette)
return;
if (flip)
out += width * height;
for (s32 y=0; y<height; ++y)
{
if (flip)
out -= width; // one line back
for (s32 x=0; x<width; ++x)
{
out[x] = X8R8G8B8toA1R5G5B5(palette[(u8)(*in)]);
++in;
}
if (!flip)
out += width;
in += linepad;
}
}
//! converts a 8 bit palettized or non palettized image (A8) into R8G8B8
void CColorConverter::convert8BitTo24Bit(const u8* in, u8* out, s32 width, s32 height, const u8* palette, s32 linepad, bool flip)
{
if (!in || !out )
return;
const s32 lineWidth = 3 * width;
if (flip)
out += lineWidth * height;
for (s32 y=0; y<height; ++y)
{
if (flip)
out -= lineWidth; // one line back
for (s32 x=0; x< lineWidth; x += 3)
{
if ( palette )
{
#ifdef __BIG_ENDIAN__
out[x+0] = palette[ (in[0] << 2 ) + 0];
out[x+1] = palette[ (in[0] << 2 ) + 1];
out[x+2] = palette[ (in[0] << 2 ) + 2];
#else
out[x+0] = palette[ (in[0] << 2 ) + 2];
out[x+1] = palette[ (in[0] << 2 ) + 1];
out[x+2] = palette[ (in[0] << 2 ) + 0];
#endif
}
else
{
out[x+0] = in[0];
out[x+1] = in[0];
out[x+2] = in[0];
}
++in;
}
if (!flip)
out += lineWidth;
in += linepad;
}
}
//! converts a 8 bit palettized or non palettized image (A8) into R8G8B8
void CColorConverter::convert8BitTo32Bit(const u8* in, u8* out, s32 width, s32 height, const u8* palette, s32 linepad, bool flip)
{
if (!in || !out )
return;
const u32 lineWidth = 4 * width;
if (flip)
out += lineWidth * height;
u32 x;
u32 c;
for (u32 y=0; y < (u32) height; ++y)
{
if (flip)
out -= lineWidth; // one line back
if ( palette )
{
for (x=0; x < (u32) width; x += 1)
{
c = in[x];
((u32*)out)[x] = ((u32*)palette)[ c ];
}
}
else
{
for (x=0; x < (u32) width; x += 1)
{
c = in[x];
#ifdef __BIG_ENDIAN__
((u32*)out)[x] = c << 24 | c << 16 | c << 8 | 0x000000FF;
#else
((u32*)out)[x] = 0xFF000000 | c << 16 | c << 8 | c;
#endif
}
}
if (!flip)
out += lineWidth;
in += width + linepad;
}
}
//! converts 16bit data to 16bit data
void CColorConverter::convert16BitTo16Bit(const s16* in, s16* out, s32 width, s32 height, s32 linepad, bool flip)
{
if (!in || !out)
return;
if (flip)
out += width * height;
for (s32 y=0; y<height; ++y)
{
if (flip)
out -= width;
#ifdef __BIG_ENDIAN__
for (s32 x=0; x<width; ++x)
out[x]=os::Byteswap::byteswap(in[x]);
#else
memcpy(out, in, width*sizeof(s16));
#endif
if (!flip)
out += width;
in += width;
in += linepad;
}
}
//! copies R8G8B8 24bit data to 24bit data
void CColorConverter::convert24BitTo24Bit(const u8* in, u8* out, s32 width, s32 height, s32 linepad, bool flip, bool bgr)
{
if (!in || !out)
return;
const s32 lineWidth = 3 * width;
if (flip)
out += lineWidth * height;
for (s32 y=0; y<height; ++y)
{
if (flip)
out -= lineWidth;
if (bgr)
{
for (s32 x=0; x<lineWidth; x+=3)
{
out[x+0] = in[x+2];
out[x+1] = in[x+1];
out[x+2] = in[x+0];
}
}
else
{
memcpy(out,in,lineWidth);
}
if (!flip)
out += lineWidth;
in += lineWidth;
in += linepad;
}
}
//! Resizes the surface to a new size and converts it at the same time
//! to an A8R8G8B8 format, returning the pointer to the new buffer.
void CColorConverter::convert16bitToA8R8G8B8andResize(const s16* in, s32* out, s32 newWidth, s32 newHeight, s32 currentWidth, s32 currentHeight)
{
if (!newWidth || !newHeight)
return;
// note: this is very very slow. (i didn't want to write a fast version.
// but hopefully, nobody wants to convert surfaces every frame.
f32 sourceXStep = (f32)currentWidth / (f32)newWidth;
f32 sourceYStep = (f32)currentHeight / (f32)newHeight;
f32 sy;
s32 t;
for (s32 x=0; x<newWidth; ++x)
{
sy = 0.0f;
for (s32 y=0; y<newHeight; ++y)
{
t = in[(s32)(((s32)sy)*currentWidth + x*sourceXStep)];
t = (((t >> 15)&0x1)<<31) | (((t >> 10)&0x1F)<<19) |
(((t >> 5)&0x1F)<<11) | (t&0x1F)<<3;
out[(s32)(y*newWidth + x)] = t;
sy+=sourceYStep;
}
}
}
//! copies X8R8G8B8 32 bit data
void CColorConverter::convert32BitTo32Bit(const s32* in, s32* out, s32 width, s32 height, s32 linepad, bool flip)
{
if (!in || !out)
return;
if (flip)
out += width * height;
for (s32 y=0; y<height; ++y)
{
if (flip)
out -= width;
#ifdef __BIG_ENDIAN__
for (s32 x=0; x<width; ++x)
out[x]=os::Byteswap::byteswap(in[x]);
#else
memcpy(out, in, width*sizeof(s32));
#endif
if (!flip)
out += width;
in += width;
in += linepad;
}
}
void CColorConverter::convert_A1R5G5B5toR8G8B8(const void* sP, s32 sN, void* dP)
{
u16* sB = (u16*)sP;
u8 * dB = (u8 *)dP;
for (s32 x = 0; x < sN; ++x)
{
dB[2] = (*sB & 0x7c00) >> 7;
dB[1] = (*sB & 0x03e0) >> 2;
dB[0] = (*sB & 0x1f) << 3;
sB += 1;
dB += 3;
}
}
void CColorConverter::convert_A1R5G5B5toB8G8R8(const void* sP, s32 sN, void* dP)
{
u16* sB = (u16*)sP;
u8 * dB = (u8 *)dP;
for (s32 x = 0; x < sN; ++x)
{
dB[0] = (*sB & 0x7c00) >> 7;
dB[1] = (*sB & 0x03e0) >> 2;
dB[2] = (*sB & 0x1f) << 3;
sB += 1;
dB += 3;
}
}
void CColorConverter::convert_A1R5G5B5toR5G5B5A1(const void* sP, s32 sN, void* dP)
{
const u16* sB = (const u16*)sP;
u16* dB = (u16*)dP;
for (s32 x = 0; x < sN; ++x)
{
*dB = (*sB<<1)|(*sB>>15);
++sB; ++dB;
}
}
void CColorConverter::convert_A1R5G5B5toA8R8G8B8(const void* sP, s32 sN, void* dP)
{
u16* sB = (u16*)sP;
u32* dB = (u32*)dP;
for (s32 x = 0; x < sN; ++x)
*dB++ = A1R5G5B5toA8R8G8B8(*sB++);
}
void CColorConverter::convert_A1R5G5B5toA1R5G5B5(const void* sP, s32 sN, void* dP)
{
memcpy(dP, sP, sN * 2);
}
void CColorConverter::convert_A1R5G5B5toR5G6B5(const void* sP, s32 sN, void* dP)
{
u16* sB = (u16*)sP;
u16* dB = (u16*)dP;
for (s32 x = 0; x < sN; ++x)
*dB++ = A1R5G5B5toR5G6B5(*sB++);
}
void CColorConverter::convert_A8R8G8B8toR8G8B8(const void* sP, s32 sN, void* dP)
{
u8* sB = (u8*)sP;
u8* dB = (u8*)dP;
for (s32 x = 0; x < sN; ++x)
{
// sB[3] is alpha
dB[0] = sB[2];
dB[1] = sB[1];
dB[2] = sB[0];
sB += 4;
dB += 3;
}
}
void CColorConverter::convert_A8R8G8B8toB8G8R8(const void* sP, s32 sN, void* dP)
{
u8* sB = (u8*)sP;
u8* dB = (u8*)dP;
for (s32 x = 0; x < sN; ++x)
{
// sB[3] is alpha
dB[0] = sB[0];
dB[1] = sB[1];
dB[2] = sB[2];
sB += 4;
dB += 3;
}
}
void CColorConverter::convert_A8R8G8B8toA8R8G8B8(const void* sP, s32 sN, void* dP)
{
memcpy(dP, sP, sN * 4);
}
void CColorConverter::convert_A8R8G8B8toA1R5G5B5(const void* sP, s32 sN, void* dP)
{
u32* sB = (u32*)sP;
u16* dB = (u16*)dP;
for (s32 x = 0; x < sN; ++x)
*dB++ = A8R8G8B8toA1R5G5B5(*sB++);
}
void CColorConverter::convert_A8R8G8B8toA1B5G5R5(const void* sP, s32 sN, void* dP)
{
u8 * sB = (u8 *)sP;
u16* dB = (u16*)dP;
for (s32 x = 0; x < sN; ++x)
{
s32 r = sB[0] >> 3;
s32 g = sB[1] >> 3;
s32 b = sB[2] >> 3;
s32 a = sB[3] >> 3;
dB[0] = (a << 15) | (r << 10) | (g << 5) | (b);
sB += 4;
dB += 1;
}
}
void CColorConverter::convert_A8R8G8B8toR5G6B5(const void* sP, s32 sN, void* dP)
{
u8 * sB = (u8 *)sP;
u16* dB = (u16*)dP;
for (s32 x = 0; x < sN; ++x)
{
s32 r = sB[2] >> 3;
s32 g = sB[1] >> 2;
s32 b = sB[0] >> 3;
dB[0] = (r << 11) | (g << 5) | (b);
sB += 4;
dB += 1;
}
}
void CColorConverter::convert_A8R8G8B8toR3G3B2(const void* sP, s32 sN, void* dP)
{
u8* sB = (u8*)sP;
u8* dB = (u8*)dP;
for (s32 x = 0; x < sN; ++x)
{
u8 r = sB[2] & 0xe0;
u8 g = (sB[1] & 0xe0) >> 3;
u8 b = (sB[0] & 0xc0) >> 6;
dB[0] = (r | g | b);
sB += 4;
dB += 1;
}
}
void CColorConverter::convert_R8G8B8toR8G8B8(const void* sP, s32 sN, void* dP)
{
memcpy(dP, sP, sN * 3);
}
void CColorConverter::convert_R8G8B8toA8R8G8B8(const void* sP, s32 sN, void* dP)
{
u8* sB = (u8* )sP;
u32* dB = (u32*)dP;
for (s32 x = 0; x < sN; ++x)
{
*dB = 0xff000000 | (sB[0]<<16) | (sB[1]<<8) | sB[2];
sB += 3;
++dB;
}
}
void CColorConverter::convert_R8G8B8toA1R5G5B5(const void* sP, s32 sN, void* dP)
{
u8 * sB = (u8 *)sP;
u16* dB = (u16*)dP;
for (s32 x = 0; x < sN; ++x)
{
s32 r = sB[0] >> 3;
s32 g = sB[1] >> 3;
s32 b = sB[2] >> 3;
dB[0] = (0x8000) | (r << 10) | (g << 5) | (b);
sB += 3;
dB += 1;
}
}
void CColorConverter::convert_B8G8R8toA8R8G8B8(const void* sP, s32 sN, void* dP)
{
u8* sB = (u8* )sP;
u32* dB = (u32*)dP;
for (s32 x = 0; x < sN; ++x)
{
*dB = 0xff000000 | (sB[2]<<16) | (sB[1]<<8) | sB[0];
sB += 3;
++dB;
}
}
void CColorConverter::convert_A8R8G8B8toR8G8B8A8(const void* sP, s32 sN, void* dP)
{
const u32* sB = (const u32*)sP;
u32* dB = (u32*)dP;
for (s32 x = 0; x < sN; ++x)
{
*dB++ = (*sB<<8) | (*sB>>24);
++sB;
}
}
void CColorConverter::convert_A8R8G8B8toA8B8G8R8(const void* sP, s32 sN, void* dP)
{
const u32* sB = (const u32*)sP;
u32* dB = (u32*)dP;
for (s32 x = 0; x < sN; ++x)
{
*dB++ = (*sB&0xff00ff00)|((*sB&0x00ff0000)>>16)|((*sB&0x000000ff)<<16);
++sB;
}
}
void CColorConverter::convert_B8G8R8A8toA8R8G8B8(const void* sP, s32 sN, void* dP)
{
u8* sB = (u8*)sP;
u8* dB = (u8*)dP;
for (s32 x = 0; x < sN; ++x)
{
dB[0] = sB[3];
dB[1] = sB[2];
dB[2] = sB[1];
dB[3] = sB[0];
sB += 4;
dB += 4;
}
}
void CColorConverter::convert_R8G8B8toB8G8R8(const void* sP, s32 sN, void* dP)
{
u8* sB = (u8*)sP;
u8* dB = (u8*)dP;
for (s32 x = 0; x < sN; ++x)
{
dB[2] = sB[0];
dB[1] = sB[1];
dB[0] = sB[2];
sB += 3;
dB += 3;
}
}
void CColorConverter::convert_R8G8B8toR5G6B5(const void* sP, s32 sN, void* dP)
{
u8 * sB = (u8 *)sP;
u16* dB = (u16*)dP;
for (s32 x = 0; x < sN; ++x)
{
s32 r = sB[0] >> 3;
s32 g = sB[1] >> 2;
s32 b = sB[2] >> 3;
dB[0] = (r << 11) | (g << 5) | (b);
sB += 3;
dB += 1;
}
}
void CColorConverter::convert_R5G6B5toR5G6B5(const void* sP, s32 sN, void* dP)
{
memcpy(dP, sP, sN * 2);
}
void CColorConverter::convert_R5G6B5toR8G8B8(const void* sP, s32 sN, void* dP)
{
u16* sB = (u16*)sP;
u8 * dB = (u8 *)dP;
for (s32 x = 0; x < sN; ++x)
{
dB[0] = (*sB & 0xf800) >> 8;
dB[1] = (*sB & 0x07e0) >> 3;
dB[2] = (*sB & 0x001f) << 3;
sB += 1;
dB += 3;
}
}
void CColorConverter::convert_R5G6B5toB8G8R8(const void* sP, s32 sN, void* dP)
{
u16* sB = (u16*)sP;
u8 * dB = (u8 *)dP;
for (s32 x = 0; x < sN; ++x)
{
dB[2] = (*sB & 0xf800) >> 8;
dB[1] = (*sB & 0x07e0) >> 3;
dB[0] = (*sB & 0x001f) << 3;
sB += 1;
dB += 3;
}
}
void CColorConverter::convert_R5G6B5toA8R8G8B8(const void* sP, s32 sN, void* dP)
{
u16* sB = (u16*)sP;
u32* dB = (u32*)dP;
for (s32 x = 0; x < sN; ++x)
*dB++ = R5G6B5toA8R8G8B8(*sB++);
}
void CColorConverter::convert_R5G6B5toA1R5G5B5(const void* sP, s32 sN, void* dP)
{
u16* sB = (u16*)sP;
u16* dB = (u16*)dP;
for (s32 x = 0; x < sN; ++x)
*dB++ = R5G6B5toA1R5G5B5(*sB++);
}
bool CColorConverter::canConvertFormat(ECOLOR_FORMAT sourceFormat, ECOLOR_FORMAT destFormat)
{
switch (sourceFormat)
{
case ECF_A1R5G5B5:
switch (destFormat)
{
case ECF_A1R5G5B5:
case ECF_R5G6B5:
case ECF_A8R8G8B8:
case ECF_R8G8B8:
return true;
default:
break;
}
break;
case ECF_R5G6B5:
switch (destFormat)
{
case ECF_A1R5G5B5:
case ECF_R5G6B5:
case ECF_A8R8G8B8:
case ECF_R8G8B8:
return true;
default:
break;
}
break;
case ECF_A8R8G8B8:
switch (destFormat)
{
case ECF_A1R5G5B5:
case ECF_R5G6B5:
case ECF_A8R8G8B8:
case ECF_R8G8B8:
return true;
default:
break;
}
break;
case ECF_R8G8B8:
switch (destFormat)
{
case ECF_A1R5G5B5:
case ECF_R5G6B5:
case ECF_A8R8G8B8:
case ECF_R8G8B8:
return true;
default:
break;
}
break;
default:
break;
}
return false;
}
void CColorConverter::convert_viaFormat(const void* sP, ECOLOR_FORMAT sF, s32 sN,
void* dP, ECOLOR_FORMAT dF)
{
// please also update can_convert_viaFormat when adding new conversions
switch (sF)
{
case ECF_A1R5G5B5:
switch (dF)
{
case ECF_A1R5G5B5:
convert_A1R5G5B5toA1R5G5B5(sP, sN, dP);
break;
case ECF_R5G6B5:
convert_A1R5G5B5toR5G6B5(sP, sN, dP);
break;
case ECF_A8R8G8B8:
convert_A1R5G5B5toA8R8G8B8(sP, sN, dP);
break;
case ECF_R8G8B8:
convert_A1R5G5B5toR8G8B8(sP, sN, dP);
break;
default:
break;
}
break;
case ECF_R5G6B5:
switch (dF)
{
case ECF_A1R5G5B5:
convert_R5G6B5toA1R5G5B5(sP, sN, dP);
break;
case ECF_R5G6B5:
convert_R5G6B5toR5G6B5(sP, sN, dP);
break;
case ECF_A8R8G8B8:
convert_R5G6B5toA8R8G8B8(sP, sN, dP);
break;
case ECF_R8G8B8:
convert_R5G6B5toR8G8B8(sP, sN, dP);
break;
default:
break;
}
break;
case ECF_A8R8G8B8:
switch (dF)
{
case ECF_A1R5G5B5:
convert_A8R8G8B8toA1R5G5B5(sP, sN, dP);
break;
case ECF_R5G6B5:
convert_A8R8G8B8toR5G6B5(sP, sN, dP);
break;
case ECF_A8R8G8B8:
convert_A8R8G8B8toA8R8G8B8(sP, sN, dP);
break;
case ECF_R8G8B8:
convert_A8R8G8B8toR8G8B8(sP, sN, dP);
break;
default:
break;
}
break;
case ECF_R8G8B8:
switch (dF)
{
case ECF_A1R5G5B5:
convert_R8G8B8toA1R5G5B5(sP, sN, dP);
break;
case ECF_R5G6B5:
convert_R8G8B8toR5G6B5(sP, sN, dP);
break;
case ECF_A8R8G8B8:
convert_R8G8B8toA8R8G8B8(sP, sN, dP);
break;
case ECF_R8G8B8:
convert_R8G8B8toR8G8B8(sP, sN, dP);
break;
default:
break;
}
break;
#ifndef _DEBUG
default:
break;
#endif
}
}
} // end namespace video
} // end namespace irr

View File

@ -0,0 +1,101 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_COLOR_CONVERTER_H_INCLUDED__
#define __C_COLOR_CONVERTER_H_INCLUDED__
#include "irrTypes.h"
#include "IImage.h"
namespace irr
{
namespace video
{
class CColorConverter
{
public:
//! converts a monochrome bitmap to A1R5G5B5
static void convert1BitTo16Bit(const u8* in, s16* out, s32 width, s32 height, s32 linepad=0, bool flip=false);
//! converts a 4 bit palettized image to A1R5G5B5
static void convert4BitTo16Bit(const u8* in, s16* out, s32 width, s32 height, const s32* palette, s32 linepad=0, bool flip=false);
//! converts a 8 bit palettized image to A1R5G5B5
static void convert8BitTo16Bit(const u8* in, s16* out, s32 width, s32 height, const s32* palette, s32 linepad=0, bool flip=false);
//! converts a 8 bit palettized or non palettized image (A8) into R8G8B8
static void convert8BitTo24Bit(const u8* in, u8* out, s32 width, s32 height, const u8* palette, s32 linepad = 0, bool flip=false);
//! converts a 8 bit palettized or non palettized image (A8) into A8R8G8B8
static void convert8BitTo32Bit(const u8* in, u8* out, s32 width, s32 height, const u8* palette, s32 linepad = 0, bool flip=false);
//! converts R8G8B8 16 bit data to A1R5G5B5 data
static void convert16BitTo16Bit(const s16* in, s16* out, s32 width, s32 height, s32 linepad=0, bool flip=false);
//! copies R8G8B8 24 bit data to 24 data, and flips and
//! mirrors the image during the process.
static void convert24BitTo24Bit(const u8* in, u8* out, s32 width, s32 height, s32 linepad=0, bool flip=false, bool bgr=false);
//! Resizes the surface to a new size and converts it at the same time
//! to an A8R8G8B8 format, returning the pointer to the new buffer.
static void convert16bitToA8R8G8B8andResize(const s16* in, s32* out, s32 newWidth, s32 newHeight, s32 currentWidth, s32 currentHeight);
//! copies X8R8G8B8 32 bit data, and flips and
//! mirrors the image during the process.
static void convert32BitTo32Bit(const s32* in, s32* out, s32 width, s32 height, s32 linepad, bool flip=false);
//! Functions for converting one image format to another efficiently
//! and hopefully correctly.
//! Note that the format descriptions refer to the ECOLOR_FORMAT's and not to memory layout.
//! Reasons for that go back to DX9 naming which tended to flip 32-bit and 16-bit byte orders so ARGB usually means BGRA.
//!
//! \param sP pointer to source pixel data
//! \param sN number of source pixels to copy
//! \param dP pointer to destination data buffer. must be big enough
//! to hold sN pixels in the output format.
static void convert_A1R5G5B5toR8G8B8(const void* sP, s32 sN, void* dP);
static void convert_A1R5G5B5toB8G8R8(const void* sP, s32 sN, void* dP);
static void convert_A1R5G5B5toA8R8G8B8(const void* sP, s32 sN, void* dP);
static void convert_A1R5G5B5toA1R5G5B5(const void* sP, s32 sN, void* dP);
static void convert_A1R5G5B5toR5G5B5A1(const void* sP, s32 sN, void* dP);
static void convert_A1R5G5B5toR5G6B5(const void* sP, s32 sN, void* dP);
static void convert_A8R8G8B8toR8G8B8(const void* sP, s32 sN, void* dP);
static void convert_A8R8G8B8toB8G8R8(const void* sP, s32 sN, void* dP);
static void convert_A8R8G8B8toA8R8G8B8(const void* sP, s32 sN, void* dP);
static void convert_A8R8G8B8toA1R5G5B5(const void* sP, s32 sN, void* dP);
static void convert_A8R8G8B8toA1B5G5R5(const void* sP, s32 sN, void* dP);
static void convert_A8R8G8B8toR5G6B5(const void* sP, s32 sN, void* dP);
static void convert_A8R8G8B8toR3G3B2(const void* sP, s32 sN, void* dP);
static void convert_R8G8B8toR8G8B8(const void* sP, s32 sN, void* dP);
static void convert_R8G8B8toA8R8G8B8(const void* sP, s32 sN, void* dP);
static void convert_R8G8B8toA1R5G5B5(const void* sP, s32 sN, void* dP);
static void convert_R8G8B8toB8G8R8(const void* sP, s32 sN, void* dP);
static void convert_R8G8B8toR5G6B5(const void* sP, s32 sN, void* dP);
static void convert_B8G8R8toA8R8G8B8(const void* sP, s32 sN, void* dP);
static void convert_B8G8R8A8toA8R8G8B8(const void* sP, s32 sN, void* dP);
static void convert_A8R8G8B8toR8G8B8A8(const void* sP, s32 sN, void* dP);
static void convert_A8R8G8B8toA8B8G8R8(const void* sP, s32 sN, void* dP);
static void convert_R5G6B5toR5G6B5(const void* sP, s32 sN, void* dP);
static void convert_R5G6B5toR8G8B8(const void* sP, s32 sN, void* dP);
static void convert_R5G6B5toB8G8R8(const void* sP, s32 sN, void* dP);
static void convert_R5G6B5toA8R8G8B8(const void* sP, s32 sN, void* dP);
static void convert_R5G6B5toA1R5G5B5(const void* sP, s32 sN, void* dP);
static void convert_viaFormat(const void* sP, ECOLOR_FORMAT sF, s32 sN,
void* dP, ECOLOR_FORMAT dF);
// Check if convert_viaFormat is usable
static bool canConvertFormat(ECOLOR_FORMAT sourceFormat, ECOLOR_FORMAT destFormat);
};
} // end namespace video
} // end namespace irr
#endif

View File

@ -0,0 +1,246 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_CUBE_SCENENODE_
#include "CCubeSceneNode.h"
#include "IVideoDriver.h"
#include "ISceneManager.h"
#include "S3DVertex.h"
#include "SMeshBuffer.h"
#include "os.h"
#ifdef _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_
#include "CShadowVolumeSceneNode.h"
#else
#include "IShadowVolumeSceneNode.h"
#endif // _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_
namespace irr
{
namespace scene
{
/*
011 111
/6,8------/5 y
/ | / | ^ z
/ | / | | /
010 3,9-------2 | |/
| 7- - -10,4 101 *---->x
| / | /
|/ | /
0------11,1/
000 100
*/
//! constructor
CCubeSceneNode::CCubeSceneNode(f32 size, ISceneNode* parent, ISceneManager* mgr,
s32 id, const core::vector3df& position,
const core::vector3df& rotation, const core::vector3df& scale)
: IMeshSceneNode(parent, mgr, id, position, rotation, scale),
Mesh(0), Shadow(0), Size(size)
{
#ifdef _DEBUG
setDebugName("CCubeSceneNode");
#endif
setSize();
}
CCubeSceneNode::~CCubeSceneNode()
{
if (Shadow)
Shadow->drop();
if (Mesh)
Mesh->drop();
}
void CCubeSceneNode::setSize()
{
if (Mesh)
Mesh->drop();
Mesh = SceneManager->getGeometryCreator()->createCubeMesh(core::vector3df(Size));
}
//! renders the node.
void CCubeSceneNode::render()
{
video::IVideoDriver* driver = SceneManager->getVideoDriver();
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
if (Shadow)
Shadow->updateShadowVolumes();
// for debug purposes only:
video::SMaterial mat = Mesh->getMeshBuffer(0)->getMaterial();
// overwrite half transparency
if (DebugDataVisible & scene::EDS_HALF_TRANSPARENCY)
mat.MaterialType = video::EMT_TRANSPARENT_ADD_COLOR;
driver->setMaterial(mat);
driver->drawMeshBuffer(Mesh->getMeshBuffer(0));
// for debug purposes only:
if (DebugDataVisible)
{
video::SMaterial m;
m.Lighting = false;
m.AntiAliasing=0;
driver->setMaterial(m);
if (DebugDataVisible & scene::EDS_BBOX)
{
driver->draw3DBox(Mesh->getMeshBuffer(0)->getBoundingBox(), video::SColor(255,255,255,255));
}
if (DebugDataVisible & scene::EDS_BBOX_BUFFERS)
{
driver->draw3DBox(Mesh->getMeshBuffer(0)->getBoundingBox(),
video::SColor(255,190,128,128));
}
if (DebugDataVisible & scene::EDS_NORMALS)
{
// draw normals
const f32 debugNormalLength = SceneManager->getParameters()->getAttributeAsFloat(DEBUG_NORMAL_LENGTH);
const video::SColor debugNormalColor = SceneManager->getParameters()->getAttributeAsColor(DEBUG_NORMAL_COLOR);
const u32 count = Mesh->getMeshBufferCount();
for (u32 i=0; i != count; ++i)
{
driver->drawMeshBufferNormals(Mesh->getMeshBuffer(i), debugNormalLength, debugNormalColor);
}
}
// show mesh
if (DebugDataVisible & scene::EDS_MESH_WIRE_OVERLAY)
{
m.Wireframe = true;
driver->setMaterial(m);
driver->drawMeshBuffer(Mesh->getMeshBuffer(0));
}
}
}
//! returns the axis aligned bounding box of this node
const core::aabbox3d<f32>& CCubeSceneNode::getBoundingBox() const
{
return Mesh->getMeshBuffer(0)->getBoundingBox();
}
//! Removes a child from this scene node.
//! Implemented here, to be able to remove the shadow properly, if there is one,
//! or to remove attached childs.
bool CCubeSceneNode::removeChild(ISceneNode* child)
{
if (child && Shadow == child)
{
Shadow->drop();
Shadow = 0;
}
return ISceneNode::removeChild(child);
}
//! Creates shadow volume scene node as child of this node
//! and returns a pointer to it.
IShadowVolumeSceneNode* CCubeSceneNode::addShadowVolumeSceneNode(
const IMesh* shadowMesh, s32 id, bool zfailmethod, f32 infinity)
{
#ifdef _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_
if (!SceneManager->getVideoDriver()->queryFeature(video::EVDF_STENCIL_BUFFER))
return 0;
if (!shadowMesh)
shadowMesh = Mesh; // if null is given, use the mesh of node
if (Shadow)
Shadow->drop();
Shadow = new CShadowVolumeSceneNode(shadowMesh, this, SceneManager, id, zfailmethod, infinity);
return Shadow;
#else
return 0;
#endif
}
void CCubeSceneNode::OnRegisterSceneNode()
{
if (IsVisible)
SceneManager->registerNodeForRendering(this);
ISceneNode::OnRegisterSceneNode();
}
//! returns the material based on the zero based index i.
video::SMaterial& CCubeSceneNode::getMaterial(u32 i)
{
return Mesh->getMeshBuffer(0)->getMaterial();
}
//! returns amount of materials used by this scene node.
u32 CCubeSceneNode::getMaterialCount() const
{
return 1;
}
//! Writes attributes of the scene node.
void CCubeSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
{
ISceneNode::serializeAttributes(out, options);
out->addFloat("Size", Size);
}
//! Reads attributes of the scene node.
void CCubeSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
{
f32 newSize = in->getAttributeAsFloat("Size");
newSize = core::max_(newSize, 0.0001f);
if (newSize != Size)
{
Size = newSize;
setSize();
}
ISceneNode::deserializeAttributes(in, options);
}
//! Creates a clone of this scene node and its children.
ISceneNode* CCubeSceneNode::clone(ISceneNode* newParent, ISceneManager* newManager)
{
if (!newParent)
newParent = Parent;
if (!newManager)
newManager = SceneManager;
CCubeSceneNode* nb = new CCubeSceneNode(Size, newParent,
newManager, ID, RelativeTranslation);
nb->cloneMembers(this, newManager);
nb->getMaterial(0) = getMaterial(0);
nb->Shadow = Shadow;
if ( nb->Shadow )
nb->Shadow->grab();
if ( newParent )
nb->drop();
return nb;
}
} // end namespace scene
} // end namespace irr
#endif // _IRR_COMPILE_WITH_CUBE_SCENENODE_

View File

@ -0,0 +1,93 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_CUBE_SCENE_NODE_H_INCLUDED__
#define __C_CUBE_SCENE_NODE_H_INCLUDED__
#include "IMeshSceneNode.h"
#include "SMesh.h"
namespace irr
{
namespace scene
{
class CCubeSceneNode : public IMeshSceneNode
{
public:
//! constructor
CCubeSceneNode(f32 size, ISceneNode* parent, ISceneManager* mgr, s32 id,
const core::vector3df& position = core::vector3df(0,0,0),
const core::vector3df& rotation = core::vector3df(0,0,0),
const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f));
virtual ~CCubeSceneNode();
virtual void OnRegisterSceneNode() _IRR_OVERRIDE_;
//! renders the node.
virtual void render() _IRR_OVERRIDE_;
//! returns the axis aligned bounding box of this node
virtual const core::aabbox3d<f32>& getBoundingBox() const _IRR_OVERRIDE_;
//! returns the material based on the zero based index i. To get the amount
//! of materials used by this scene node, use getMaterialCount().
//! This function is needed for inserting the node into the scene hierarchy on a
//! optimal position for minimizing renderstate changes, but can also be used
//! to directly modify the material of a scene node.
virtual video::SMaterial& getMaterial(u32 i) _IRR_OVERRIDE_;
//! returns amount of materials used by this scene node.
virtual u32 getMaterialCount() const _IRR_OVERRIDE_;
//! Returns type of the scene node
virtual ESCENE_NODE_TYPE getType() const _IRR_OVERRIDE_ { return ESNT_CUBE; }
//! Creates shadow volume scene node as child of this node
//! and returns a pointer to it.
virtual IShadowVolumeSceneNode* addShadowVolumeSceneNode(const IMesh* shadowMesh,
s32 id, bool zfailmethod=true, f32 infinity=10000.0f) _IRR_OVERRIDE_;
//! Writes attributes of the scene node.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const _IRR_OVERRIDE_;
//! Reads attributes of the scene node.
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) _IRR_OVERRIDE_;
//! Creates a clone of this scene node and its children.
virtual ISceneNode* clone(ISceneNode* newParent=0, ISceneManager* newManager=0) _IRR_OVERRIDE_;
//! Sets a new mesh to display
virtual void setMesh(IMesh* mesh) _IRR_OVERRIDE_ {}
//! Returns the current mesh
virtual IMesh* getMesh(void) _IRR_OVERRIDE_ { return Mesh; }
//! Sets if the scene node should not copy the materials of the mesh but use them in a read only style.
/* In this way it is possible to change the materials a mesh causing all mesh scene nodes
referencing this mesh to change too. */
virtual void setReadOnlyMaterials(bool readonly) _IRR_OVERRIDE_ {}
//! Returns if the scene node should not copy the materials of the mesh but use them in a read only style
virtual bool isReadOnlyMaterials() const _IRR_OVERRIDE_ { return false; }
//! Removes a child from this scene node.
//! Implemented here, to be able to remove the shadow properly, if there is one,
//! or to remove attached child.
virtual bool removeChild(ISceneNode* child) _IRR_OVERRIDE_;
private:
void setSize();
IMesh* Mesh;
IShadowVolumeSceneNode* Shadow;
f32 Size;
};
} // end namespace scene
} // end namespace irr
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,507 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_VIDEO_DIRECTX_9_H_INCLUDED__
#define __C_VIDEO_DIRECTX_9_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
#ifdef _IRR_WINDOWS_
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
#include "CNullDriver.h"
#include "SIrrCreationParameters.h"
#include "IMaterialRendererServices.h"
#if defined(__BORLANDC__) || defined (__BCPLUSPLUS__)
#include "irrMath.h" // needed by borland for sqrtf define
#endif
#include <d3d9.h>
namespace irr
{
namespace video
{
class CD3D9CallBridge;
class CD3D9RenderTarget;
class CD3D9Texture;
class CD3D9Driver : public CNullDriver, IMaterialRendererServices
{
public:
friend class CD3D9CallBridge;
friend class CD3D9RenderTarget;
friend class CD3D9Texture;
//! constructor
CD3D9Driver(const SIrrlichtCreationParameters& params, io::IFileSystem* io);
//! destructor
virtual ~CD3D9Driver();
virtual bool beginScene(u16 clearFlag, SColor clearColor = SColor(255,0,0,0), f32 clearDepth = 1.f, u8 clearStencil = 0,
const SExposedVideoData& videoData = SExposedVideoData(), core::rect<s32>* sourceRect = 0) _IRR_OVERRIDE_;
virtual bool endScene() _IRR_OVERRIDE_;
//! queries the features of the driver, returns true if feature is available
virtual bool queryFeature(E_VIDEO_DRIVER_FEATURE feature) const _IRR_OVERRIDE_;
//! sets transformation
virtual void setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat) _IRR_OVERRIDE_;
//! sets a material
virtual void setMaterial(const SMaterial& material) _IRR_OVERRIDE_;
virtual bool setRenderTargetEx(IRenderTarget* target, u16 clearFlag, SColor clearColor = SColor(255,0,0,0),
f32 clearDepth = 1.f, u8 clearStencil = 0) _IRR_OVERRIDE_;
//! sets a viewport
virtual void setViewPort(const core::rect<s32>& area) _IRR_OVERRIDE_;
//! gets the area of the current viewport
virtual const core::rect<s32>& getViewPort() const _IRR_OVERRIDE_;
struct SHWBufferLink_d3d9 : public SHWBufferLink
{
SHWBufferLink_d3d9(const scene::IMeshBuffer *_MeshBuffer):
SHWBufferLink(_MeshBuffer),
vertexBuffer(0), indexBuffer(0),
vertexBufferSize(0), indexBufferSize(0) {}
IDirect3DVertexBuffer9* vertexBuffer;
IDirect3DIndexBuffer9* indexBuffer;
u32 vertexBufferSize;
u32 indexBufferSize;
};
bool updateVertexHardwareBuffer(SHWBufferLink_d3d9 *HWBuffer);
bool updateIndexHardwareBuffer(SHWBufferLink_d3d9 *HWBuffer);
//! updates hardware buffer if needed
virtual bool updateHardwareBuffer(SHWBufferLink *HWBuffer) _IRR_OVERRIDE_;
//! Create hardware buffer from mesh
virtual SHWBufferLink *createHardwareBuffer(const scene::IMeshBuffer* mb) _IRR_OVERRIDE_;
//! Delete hardware buffer (only some drivers can)
virtual void deleteHardwareBuffer(SHWBufferLink *HWBuffer) _IRR_OVERRIDE_;
//! Draw hardware buffer
virtual void drawHardwareBuffer(SHWBufferLink *HWBuffer) _IRR_OVERRIDE_;
//! Create occlusion query.
/** Use node for identification and mesh for occlusion test. */
virtual void addOcclusionQuery(scene::ISceneNode* node,
const scene::IMesh* mesh=0) _IRR_OVERRIDE_;
//! Remove occlusion query.
virtual void removeOcclusionQuery(scene::ISceneNode* node) _IRR_OVERRIDE_;
//! Run occlusion query. Draws mesh stored in query.
/** If the mesh shall not be rendered visible, use
overrideMaterial to disable the color and depth buffer. */
virtual void runOcclusionQuery(scene::ISceneNode* node, bool visible=false) _IRR_OVERRIDE_;
//! Update occlusion query. Retrieves results from GPU.
/** If the query shall not block, set the flag to false.
Update might not occur in this case, though */
virtual void updateOcclusionQuery(scene::ISceneNode* node, bool block=true) _IRR_OVERRIDE_;
//! Return query result.
/** Return value is the number of visible pixels/fragments.
The value is a safe approximation, i.e. can be larger then the
actual value of pixels. */
virtual u32 getOcclusionQueryResult(scene::ISceneNode* node) const _IRR_OVERRIDE_;
//! Create render target.
virtual IRenderTarget* addRenderTarget() _IRR_OVERRIDE_;
//! draws a vertex primitive list
virtual void drawVertexPrimitiveList(const void* vertices, u32 vertexCount,
const void* indexList, u32 primitiveCount,
E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType,
E_INDEX_TYPE iType) _IRR_OVERRIDE_;
//! draws a vertex primitive list in 2d
virtual void draw2DVertexPrimitiveList(const void* vertices, u32 vertexCount,
const void* indexList, u32 primitiveCount,
E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType,
E_INDEX_TYPE iType) _IRR_OVERRIDE_;
//! draws an 2d image, using a color (if color is other then Color(255,255,255,255)) and the alpha channel of the texture if wanted.
virtual void draw2DImage(const video::ITexture* texture, const core::position2d<s32>& destPos,
const core::rect<s32>& sourceRect, const core::rect<s32>* clipRect = 0,
SColor color=SColor(255,255,255,255), bool useAlphaChannelOfTexture=false) _IRR_OVERRIDE_;
//! Draws a part of the texture into the rectangle.
virtual void draw2DImage(const video::ITexture* texture, const core::rect<s32>& destRect,
const core::rect<s32>& sourceRect, const core::rect<s32>* clipRect = 0,
const video::SColor* const colors=0, bool useAlphaChannelOfTexture=false) _IRR_OVERRIDE_;
//! Draws a set of 2d images, using a color and the alpha channel of the texture.
virtual void draw2DImageBatch(const video::ITexture* texture,
const core::array<core::position2d<s32> >& positions,
const core::array<core::rect<s32> >& sourceRects,
const core::rect<s32>* clipRect=0,
SColor color=SColor(255,255,255,255),
bool useAlphaChannelOfTexture=false) _IRR_OVERRIDE_;
//!Draws an 2d rectangle with a gradient.
virtual void draw2DRectangle(const core::rect<s32>& pos,
SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown,
const core::rect<s32>* clip) _IRR_OVERRIDE_;
//! Draws a 2d line.
virtual void draw2DLine(const core::position2d<s32>& start,
const core::position2d<s32>& end,
SColor color=SColor(255,255,255,255)) _IRR_OVERRIDE_;
//! Draws a pixel.
virtual void drawPixel(u32 x, u32 y, const SColor & color) _IRR_OVERRIDE_;
//! Draws a 3d line.
virtual void draw3DLine(const core::vector3df& start,
const core::vector3df& end, SColor color = SColor(255,255,255,255)) _IRR_OVERRIDE_;
//! Draws a 3d box.
virtual void draw3DBox( const core::aabbox3d<f32>& box, SColor color = SColor(255,255,255,255 ) ) _IRR_OVERRIDE_;
//! initialises the Direct3D API
bool initDriver(HWND hwnd, bool pureSoftware);
//! \return Returns the name of the video driver. Example: In case of the DIRECT3D8
//! driver, it would return "Direct3D8.1".
virtual const wchar_t* getName() const _IRR_OVERRIDE_;
//! deletes all dynamic lights there are
virtual void deleteAllDynamicLights() _IRR_OVERRIDE_;
//! adds a dynamic light, returning an index to the light
//! \param light: the light data to use to create the light
//! \return An index to the light, or -1 if an error occurs
virtual s32 addDynamicLight(const SLight& light) _IRR_OVERRIDE_;
//! Turns a dynamic light on or off
//! \param lightIndex: the index returned by addDynamicLight
//! \param turnOn: true to turn the light on, false to turn it off
virtual void turnLightOn(s32 lightIndex, bool turnOn) _IRR_OVERRIDE_;
//! returns the maximal amount of dynamic lights the device can handle
virtual u32 getMaximalDynamicLightAmount() const _IRR_OVERRIDE_;
//! Sets the dynamic ambient light color. The default color is
//! (0,0,0,0) which means it is dark.
//! \param color: New color of the ambient light.
virtual void setAmbientLight(const SColorf& color) _IRR_OVERRIDE_;
//! Draws a shadow volume into the stencil buffer.
virtual void drawStencilShadowVolume(const core::array<core::vector3df>& triangles, bool zfail=true, u32 debugDataVisible=0) _IRR_OVERRIDE_;
//! Fills the stencil shadow with color.
virtual void drawStencilShadow(bool clearStencilBuffer=false,
video::SColor leftUpEdge = video::SColor(0,0,0,0),
video::SColor rightUpEdge = video::SColor(0,0,0,0),
video::SColor leftDownEdge = video::SColor(0,0,0,0),
video::SColor rightDownEdge = video::SColor(0,0,0,0)) _IRR_OVERRIDE_;
//! Returns the maximum amount of primitives (mostly vertices) which
//! the device is able to render with one drawIndexedTriangleList
//! call.
virtual u32 getMaximalPrimitiveCount() const _IRR_OVERRIDE_;
//! Sets the fog mode.
virtual void setFog(SColor color, E_FOG_TYPE fogType, f32 start,
f32 end, f32 density, bool pixelFog, bool rangeFog) _IRR_OVERRIDE_;
//! Only used by the internal engine. Used to notify the driver that
//! the window was resized.
virtual void OnResize(const core::dimension2d<u32>& size) _IRR_OVERRIDE_;
//! Can be called by an IMaterialRenderer to make its work easier.
virtual void setBasicRenderStates(const SMaterial& material, const SMaterial& lastMaterial,
bool resetAllRenderstates) _IRR_OVERRIDE_;
//! Returns type of video driver
virtual E_DRIVER_TYPE getDriverType() const _IRR_OVERRIDE_;
//! Returns the transformation set by setTransform
virtual const core::matrix4& getTransform(E_TRANSFORMATION_STATE state) const _IRR_OVERRIDE_;
//! Get a vertex shader constant index.
virtual s32 getVertexShaderConstantID(const c8* name) _IRR_OVERRIDE_;
//! Get a pixel shader constant index.
virtual s32 getPixelShaderConstantID(const c8* name) _IRR_OVERRIDE_;
//! Sets a vertex shader constant.
virtual void setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount=1) _IRR_OVERRIDE_;
//! Sets a pixel shader constant.
virtual void setPixelShaderConstant(const f32* data, s32 startRegister, s32 constantAmount=1) _IRR_OVERRIDE_;
//! Sets a constant for the vertex shader based on an index.
virtual bool setVertexShaderConstant(s32 index, const f32* floats, int count) _IRR_OVERRIDE_;
//! Int interface for the above.
virtual bool setVertexShaderConstant(s32 index, const s32* ints, int count) _IRR_OVERRIDE_;
//! Sets a constant for the pixel shader based on an index.
virtual bool setPixelShaderConstant(s32 index, const f32* floats, int count) _IRR_OVERRIDE_;
//! Int interface for the above.
virtual bool setPixelShaderConstant(s32 index, const s32* ints, int count) _IRR_OVERRIDE_;
//! Returns a pointer to the IVideoDriver interface. (Implementation for
//! IMaterialRendererServices)
virtual IVideoDriver* getVideoDriver() _IRR_OVERRIDE_;
//! Creates a render target texture.
virtual ITexture* addRenderTargetTexture(const core::dimension2d<u32>& size,
const io::path& name, const ECOLOR_FORMAT format = ECF_UNKNOWN) _IRR_OVERRIDE_;
//! Creates a render target texture for a cubemap
ITexture* addRenderTargetTextureCubemap(const irr::u32 sideLen,
const io::path& name, const ECOLOR_FORMAT format) _IRR_OVERRIDE_;
virtual void clearBuffers(u16 flag, SColor color = SColor(255,0,0,0), f32 depth = 1.f, u8 stencil = 0) _IRR_OVERRIDE_;
//! Returns an image created from the last rendered frame.
virtual IImage* createScreenShot(video::ECOLOR_FORMAT format=video::ECF_UNKNOWN, video::E_RENDER_TARGET target=video::ERT_FRAME_BUFFER) _IRR_OVERRIDE_;
//! Set/unset a clipping plane.
virtual bool setClipPlane(u32 index, const core::plane3df& plane, bool enable=false) _IRR_OVERRIDE_;
//! Enable/disable a clipping plane.
virtual void enableClipPlane(u32 index, bool enable) _IRR_OVERRIDE_;
//! Returns the graphics card vendor name.
virtual core::stringc getVendorInfo() _IRR_OVERRIDE_ {return VendorName;}
//! Enable the 2d override material
virtual void enableMaterial2D(bool enable=true) _IRR_OVERRIDE_;
//! Check if the driver was recently reset.
virtual bool checkDriverReset() _IRR_OVERRIDE_ {return DriverWasReset;}
//! Get the current color format of the color buffer
/** \return Color format of the color buffer. */
virtual ECOLOR_FORMAT getColorFormat() const _IRR_OVERRIDE_;
//! Returns the maximum texture size supported.
virtual core::dimension2du getMaxTextureSize() const _IRR_OVERRIDE_;
//! Check if the driver supports creating textures with the given color format
virtual bool queryTextureFormat(ECOLOR_FORMAT format) const _IRR_OVERRIDE_;
//! Used by some SceneNodes to check if a material should be rendered in the transparent render pass
virtual bool needsTransparentRenderPass(const irr::video::SMaterial& material) const _IRR_OVERRIDE_;
//! Get the current color format of the color buffer
/** \return Color format of the color buffer as D3D color value. */
D3DFORMAT getD3DColorFormat() const;
//! Get D3D color format from Irrlicht color format.
D3DFORMAT getD3DFormatFromColorFormat(ECOLOR_FORMAT format) const;
//! Get Irrlicht color format from D3D color format.
ECOLOR_FORMAT getColorFormatFromD3DFormat(D3DFORMAT format) const;
//! Get D3D blending factor.
u32 getD3DBlend(E_BLEND_FACTOR factor) const;
//! Get D3D modulate.
u32 getD3DModulate(E_MODULATE_FUNC func) const;
//! Get bridge calls.
CD3D9CallBridge* getBridgeCalls() const;
private:
//! enumeration for rendering modes such as 2d and 3d for minimizing the switching of renderStates.
enum E_RENDER_MODE
{
ERM_NONE = 0, // no render state has been set yet.
ERM_2D, // 2d drawing rendermode
ERM_3D, // 3d rendering mode
ERM_STENCIL_FILL, // stencil fill mode
ERM_SHADOW_VOLUME_ZFAIL, // stencil volume draw mode
ERM_SHADOW_VOLUME_ZPASS // stencil volume draw mode
};
//! sets right vertex shader
void setVertexShader(video::E_VERTEX_TYPE newType);
//! sets the needed renderstates
bool setRenderStates3DMode();
//! sets the needed renderstates
void setRenderStates2DMode(bool alpha, bool texture, bool alphaChannel);
//! sets the needed renderstates
void setRenderStatesStencilFillMode(bool alpha);
//! sets the needed renderstates
void setRenderStatesStencilShadowMode(bool zfail, u32 debugDataVisible);
//! sets the current Texture
bool setActiveTexture(u32 stage, const video::ITexture* texture);
//! resets the device
bool reset();
//! Try to get back a lost device
bool retrieveDevice(int numTries, int msSleepBetweenTries=100);
virtual ITexture* createDeviceDependentTexture(const io::path& name, IImage* image) _IRR_OVERRIDE_;
virtual ITexture* createDeviceDependentTextureCubemap(const io::path& name, const core::array<IImage*>& image) _IRR_OVERRIDE_;
//! Adds a new material renderer to the VideoDriver, using pixel and/or
//! vertex shaders to render geometry.
s32 addShaderMaterial(const c8* vertexShaderProgram, const c8* pixelShaderProgram,
IShaderConstantSetCallBack* callback,
E_MATERIAL_TYPE baseMaterial, s32 userData) _IRR_OVERRIDE_;
//! Adds a new material renderer to the VideoDriver, based on a high level shading
//! language.
virtual s32 addHighLevelShaderMaterial(
const c8* vertexShaderProgram,
const c8* vertexShaderEntryPointName,
E_VERTEX_SHADER_TYPE vsCompileTarget,
const c8* pixelShaderProgram,
const c8* pixelShaderEntryPointName,
E_PIXEL_SHADER_TYPE psCompileTarget,
const c8* geometryShaderProgram,
const c8* geometryShaderEntryPointName = "main",
E_GEOMETRY_SHADER_TYPE gsCompileTarget = EGST_GS_4_0,
scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES,
scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP,
u32 verticesOut = 0,
IShaderConstantSetCallBack* callback = 0,
E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID,
s32 userData = 0) _IRR_OVERRIDE_;
void createMaterialRenderers();
void draw2D3DVertexPrimitiveList(const void* vertices,
u32 vertexCount, const void* indexList, u32 primitiveCount,
E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType,
E_INDEX_TYPE iType, bool is3D);
D3DTEXTUREADDRESS getTextureWrapMode(const u8 clamp);
inline D3DCOLORVALUE colorToD3D(const SColor& col)
{
const f32 f = 1.0f / 255.0f;
D3DCOLORVALUE v;
v.r = col.getRed() * f;
v.g = col.getGreen() * f;
v.b = col.getBlue() * f;
v.a = col.getAlpha() * f;
return v;
}
CD3D9CallBridge* BridgeCalls;
E_RENDER_MODE CurrentRenderMode;
D3DPRESENT_PARAMETERS present;
SMaterial Material, LastMaterial;
bool ResetRenderStates; // bool to make all renderstates be reseted if set.
bool Transformation3DChanged;
const ITexture* CurrentTexture[MATERIAL_MAX_TEXTURES];
bool LastTextureMipMapsAvailable[MATERIAL_MAX_TEXTURES];
core::matrix4 Matrices[ETS_COUNT]; // matrices of the 3d mode we need to restore when we switch back from the 2d mode.
HINSTANCE D3DLibrary;
IDirect3D9* pID3D;
IDirect3DDevice9* pID3DDevice;
IDirect3DSurface9* BackBufferSurface;
IDirect3DSurface9* DepthStencilSurface;
core::array<bool> ActiveRenderTarget;
HWND WindowId;
core::rect<s32>* SceneSourceRect;
D3DCAPS9 Caps;
SIrrlichtCreationParameters Params;
E_VERTEX_TYPE LastVertexType;
core::stringc VendorName;
u16 VendorID;
u32 MaxTextureUnits;
u32 MaxFixedPipelineTextureUnits;
u32 MaxUserClipPlanes;
f32 MaxLightDistance;
s32 LastSetLight;
enum E_CACHE_2D_ATTRIBUTES
{
EC2D_ALPHA = 0x1,
EC2D_TEXTURE = 0x2,
EC2D_ALPHA_CHANNEL = 0x4
};
ECOLOR_FORMAT ColorFormat;
D3DFORMAT D3DColorFormat;
bool DeviceLost;
bool DriverWasReset;
bool OcclusionQuerySupport;
bool AlphaToCoverageSupport;
};
//! This bridge between Irrlicht pseudo D3D9 calls
//! and true D3D9 calls.
class CD3D9CallBridge
{
public:
CD3D9CallBridge(IDirect3DDevice9* p, CD3D9Driver* driver);
// Reset to default state.
void reset();
// Blending calls.
void setBlendOperation(DWORD mode);
void setBlendFunc(DWORD source, DWORD destination);
void setBlendFuncSeparate(DWORD sourceRGB, DWORD destinationRGB, DWORD sourceAlpha, DWORD destinationAlpha);
void setBlend(bool enable);
private:
IDirect3DDevice9* pID3DDevice;
DWORD BlendOperation;
DWORD BlendSourceRGB;
DWORD BlendDestinationRGB;
DWORD BlendSourceAlpha;
DWORD BlendDestinationAlpha;
bool Blend;
bool BlendSeparate;
bool FeatureBlendSeparate;
};
} // end namespace video
} // end namespace irr
#endif // _IRR_COMPILE_WITH_DIRECT3D_9_
#endif // __C_VIDEO_DIRECTX_9_H_INCLUDED__

View File

@ -0,0 +1,416 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
#include "CD3D9HLSLMaterialRenderer.h"
#include "IShaderConstantSetCallBack.h"
#include "IVideoDriver.h"
#include "os.h"
#include "irrString.h"
#ifndef _IRR_D3D_NO_SHADER_DEBUGGING
#include <stdio.h>
#endif
namespace irr
{
namespace video
{
//! Public constructor
CD3D9HLSLMaterialRenderer::CD3D9HLSLMaterialRenderer(IDirect3DDevice9* d3ddev,
video::IVideoDriver* driver, s32& outMaterialTypeNr,
const c8* vertexShaderProgram,
const c8* vertexShaderEntryPointName,
E_VERTEX_SHADER_TYPE vsCompileTarget,
const c8* pixelShaderProgram,
const c8* pixelShaderEntryPointName,
E_PIXEL_SHADER_TYPE psCompileTarget,
IShaderConstantSetCallBack* callback,
IMaterialRenderer* baseMaterial,
s32 userData)
: CD3D9ShaderMaterialRenderer(d3ddev, driver, callback, baseMaterial, userData),
VSConstantsTable(0), PSConstantsTable(0)
{
#ifdef _DEBUG
setDebugName("CD3D9HLSLMaterialRenderer");
#endif
outMaterialTypeNr = -1;
// now create shaders
if (vsCompileTarget < 0 || vsCompileTarget > EVST_COUNT)
{
os::Printer::log("Invalid HLSL vertex shader compilation target", ELL_ERROR);
return;
}
if (!createHLSLVertexShader(vertexShaderProgram,
vertexShaderEntryPointName, VERTEX_SHADER_TYPE_NAMES[vsCompileTarget]))
return;
if (!createHLSLPixelShader(pixelShaderProgram,
pixelShaderEntryPointName, PIXEL_SHADER_TYPE_NAMES[psCompileTarget]))
return;
// register myself as new material
outMaterialTypeNr = Driver->addMaterialRenderer(this);
}
//! Destructor
CD3D9HLSLMaterialRenderer::~CD3D9HLSLMaterialRenderer()
{
if (VSConstantsTable)
VSConstantsTable->Release();
if (PSConstantsTable)
PSConstantsTable->Release();
}
bool CD3D9HLSLMaterialRenderer::createHLSLVertexShader(const char* vertexShaderProgram,
const char* shaderEntryPointName,
const char* shaderTargetName)
{
if (!vertexShaderProgram)
return true;
LPD3DXBUFFER buffer = 0;
LPD3DXBUFFER errors = 0;
#ifdef _IRR_D3D_NO_SHADER_DEBUGGING
size_t dataLen_t = strlen(vertexShaderProgram);
UINT dataLen = (UINT)dataLen_t;
if ( dataLen != dataLen_t )
return false;
// compile without debug info
HRESULT h = stubD3DXCompileShader(
vertexShaderProgram,
dataLen,
0, // macros
0, // no includes
shaderEntryPointName,
shaderTargetName,
0, // no flags
&buffer,
&errors,
&VSConstantsTable);
#else
// compile shader and emit some debug information to
// make it possible to debug the shader in visual studio
static int irr_dbg_hlsl_file_nr = 0;
++irr_dbg_hlsl_file_nr;
char tmp[32];
sprintf(tmp, "irr_d3d9_dbg_hlsl_%d.vsh", irr_dbg_hlsl_file_nr);
FILE* f = fopen(tmp, "wb");
fwrite(vertexShaderProgram, strlen(vertexShaderProgram), 1, f);
fflush(f);
fclose(f);
HRESULT h = stubD3DXCompileShaderFromFile(
tmp,
0, // macros
0, // no includes
shaderEntryPointName,
shaderTargetName,
D3DXSHADER_DEBUG | D3DXSHADER_SKIPOPTIMIZATION,
&buffer,
&errors,
&VSConstantsTable);
#endif
if (FAILED(h))
{
os::Printer::log("HLSL vertex shader compilation failed:", ELL_ERROR);
if (errors)
{
os::Printer::log((c8*)errors->GetBufferPointer(), ELL_ERROR);
errors->Release();
if (buffer)
buffer->Release();
}
return false;
}
if (errors)
errors->Release();
if (buffer)
{
if (FAILED(pID3DDevice->CreateVertexShader((DWORD*)buffer->GetBufferPointer(),
&VertexShader)))
{
os::Printer::log("Could not create hlsl vertex shader.", ELL_ERROR);
buffer->Release();
return false;
}
buffer->Release();
return true;
}
return false;
}
bool CD3D9HLSLMaterialRenderer::createHLSLPixelShader(const char* pixelShaderProgram,
const char* shaderEntryPointName,
const char* shaderTargetName)
{
if (!pixelShaderProgram)
return true;
LPD3DXBUFFER buffer = 0;
LPD3DXBUFFER errors = 0;
DWORD flags = 0;
#ifdef D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY
if (Driver->queryFeature(video::EVDF_VERTEX_SHADER_2_0) || Driver->queryFeature(video::EVDF_VERTEX_SHADER_3_0))
// this one's for newer DX SDKs which don't support ps_1_x anymore
// instead they'll silently compile 1_x as 2_x when using this flag
flags |= D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY;
#endif
#if defined(_IRR_D3D_USE_LEGACY_HLSL_COMPILER) && defined(D3DXSHADER_USE_LEGACY_D3DX9_31_DLL)
#ifdef D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY
else
#endif
flags |= D3DXSHADER_USE_LEGACY_D3DX9_31_DLL;
#endif
#ifdef _IRR_D3D_NO_SHADER_DEBUGGING
size_t dataLen_t = strlen(pixelShaderProgram);
UINT dataLen = (UINT)dataLen_t;
if ( dataLen != dataLen_t )
return false;
// compile without debug info
HRESULT h = stubD3DXCompileShader(
pixelShaderProgram,
dataLen,
0, // macros
0, // no includes
shaderEntryPointName,
shaderTargetName,
flags,
&buffer,
&errors,
&PSConstantsTable);
#else
// compile shader and emit some debug information to
// make it possible to debug the shader in visual studio
static int irr_dbg_hlsl_file_nr = 0;
++irr_dbg_hlsl_file_nr;
char tmp[32];
sprintf(tmp, "irr_d3d9_dbg_hlsl_%d.psh", irr_dbg_hlsl_file_nr);
FILE* f = fopen(tmp, "wb");
fwrite(pixelShaderProgram, strlen(pixelShaderProgram), 1, f);
fflush(f);
fclose(f);
HRESULT h = stubD3DXCompileShaderFromFile(
tmp,
0, // macros
0, // no includes
shaderEntryPointName,
shaderTargetName,
flags | D3DXSHADER_DEBUG | D3DXSHADER_SKIPOPTIMIZATION,
&buffer,
&errors,
&PSConstantsTable);
#endif
if (FAILED(h))
{
os::Printer::log("HLSL pixel shader compilation failed:", ELL_ERROR);
if (errors)
{
os::Printer::log((c8*)errors->GetBufferPointer(), ELL_ERROR);
errors->Release();
if (buffer)
buffer->Release();
}
return false;
}
if (errors)
errors->Release();
if (buffer)
{
if (FAILED(pID3DDevice->CreatePixelShader((DWORD*)buffer->GetBufferPointer(),
&PixelShader)))
{
os::Printer::log("Could not create hlsl pixel shader.", ELL_ERROR);
buffer->Release();
return false;
}
buffer->Release();
return true;
}
return false;
}
s32 CD3D9HLSLMaterialRenderer::getVariableID(bool vertexShader, const c8* name)
{
LPD3DXCONSTANTTABLE tbl = vertexShader ? VSConstantsTable : PSConstantsTable;
if (!tbl)
return -1;
D3DXCONSTANTTABLE_DESC tblDesc;
if (!FAILED(tbl->GetDesc(&tblDesc)))
{
for (u32 i = 0; i < tblDesc.Constants; ++i)
{
D3DXHANDLE curConst = tbl->GetConstant(NULL, i);
D3DXCONSTANT_DESC constDesc;
UINT ucount = 1;
if (!FAILED(tbl->GetConstantDesc(curConst, &constDesc, &ucount)))
if(strcmp(name, constDesc.Name) == 0)
return i;
}
}
core::stringc s = "HLSL Variable to get ID not found: '";
s += name;
s += "'. Available variables are:";
os::Printer::log(s.c_str(), ELL_WARNING);
printHLSLVariables(tbl);
return -1;
}
bool CD3D9HLSLMaterialRenderer::setVariable(bool vertexShader, s32 index,
const f32* floats, int count)
{
LPD3DXCONSTANTTABLE tbl = vertexShader ? VSConstantsTable : PSConstantsTable;
if (index < 0 || !tbl)
return false;
// currently we only support top level parameters.
// Should be enough for the beginning. (TODO)
D3DXHANDLE hndl = tbl->GetConstant(NULL, index);
if (!hndl)
return false;
D3DXCONSTANT_DESC Description;
UINT ucount = 1;
tbl->GetConstantDesc(hndl, &Description, &ucount);
if(Description.RegisterSet != D3DXRS_SAMPLER)
{
HRESULT hr = tbl->SetFloatArray(pID3DDevice, hndl, floats, count);
if (FAILED(hr))
{
os::Printer::log("Error setting float array for HLSL variable", ELL_WARNING);
return false;
}
}
return true;
}
bool CD3D9HLSLMaterialRenderer::setVariable(bool vertexShader, s32 index,
const s32* ints, int count)
{
LPD3DXCONSTANTTABLE tbl = vertexShader ? VSConstantsTable : PSConstantsTable;
if (index < 0 || !tbl)
return false;
// currently we only support top level parameters.
// Should be enough for the beginning. (TODO)
D3DXHANDLE hndl = tbl->GetConstant(NULL, index);
if (!hndl)
return false;
D3DXCONSTANT_DESC Description;
UINT ucount = 1;
tbl->GetConstantDesc(hndl, &Description, &ucount);
if(Description.RegisterSet != D3DXRS_SAMPLER)
{
HRESULT hr = tbl->SetIntArray(pID3DDevice, hndl, ints, count);
if (FAILED(hr))
{
os::Printer::log("Error setting int array for HLSL variable", ELL_WARNING);
return false;
}
}
return true;
}
bool CD3D9HLSLMaterialRenderer::OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype)
{
if (VSConstantsTable)
VSConstantsTable->SetDefaults(pID3DDevice);
return CD3D9ShaderMaterialRenderer::OnRender(service, vtxtype);
}
void CD3D9HLSLMaterialRenderer::printHLSLVariables(LPD3DXCONSTANTTABLE table)
{
// currently we only support top level parameters.
// Should be enough for the beginning. (TODO)
// print out constant names
D3DXCONSTANTTABLE_DESC tblDesc;
HRESULT hr = table->GetDesc(&tblDesc);
if (!FAILED(hr))
{
for (int i=0; i<(int)tblDesc.Constants; ++i)
{
D3DXCONSTANT_DESC d;
UINT n = 1;
D3DXHANDLE cHndl = table->GetConstant(NULL, i);
if (!FAILED(table->GetConstantDesc(cHndl, &d, &n)))
{
core::stringc s = " '";
s += d.Name;
s += "' Registers:[begin:";
s += (int)d.RegisterIndex;
s += ", count:";
s += (int)d.RegisterCount;
s += "]";
os::Printer::log(s.c_str());
}
}
}
}
} // end namespace video
} // end namespace irr
#endif // _IRR_COMPILE_WITH_DIRECT3D_9_

View File

@ -0,0 +1,84 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_D3D9_HLSL_MATERIAL_RENDERER_H_INCLUDED__
#define __C_D3D9_HLSL_MATERIAL_RENDERER_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_WINDOWS_
#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
#include "CD3D9ShaderMaterialRenderer.h"
#include "IGPUProgrammingServices.h"
namespace irr
{
namespace video
{
class IVideoDriver;
class IShaderConstantSetCallBack;
class IMaterialRenderer;
//! Class for using vertex and pixel shaders via HLSL with D3D9
class CD3D9HLSLMaterialRenderer : public CD3D9ShaderMaterialRenderer
{
public:
//! Public constructor
CD3D9HLSLMaterialRenderer(IDirect3DDevice9* d3ddev, video::IVideoDriver* driver,
s32& outMaterialTypeNr,
const c8* vertexShaderProgram,
const c8* vertexShaderEntryPointName,
E_VERTEX_SHADER_TYPE vsCompileTarget,
const c8* pixelShaderProgram,
const c8* pixelShaderEntryPointName,
E_PIXEL_SHADER_TYPE psCompileTarget,
IShaderConstantSetCallBack* callback,
IMaterialRenderer* baseMaterial,
s32 userData);
//! Destructor
~CD3D9HLSLMaterialRenderer();
virtual s32 getVariableID(bool vertexShader, const c8* name);
//! sets a variable in the shader.
//! \param vertexShader: True if this should be set in the vertex shader, false if
//! in the pixel shader.
//! \param index: Index of the variable
//! \param floats: Pointer to array of floats
//! \param count: Amount of floats in array.
virtual bool setVariable(bool vertexShader, s32 index, const f32* floats, int count);
//! Int interface for the above.
virtual bool setVariable(bool vertexShader, s32 index, const s32* ints, int count);
bool OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype) _IRR_OVERRIDE_;
protected:
bool createHLSLVertexShader(const char* vertexShaderProgram,
const char* shaderEntryPointName,
const char* shaderTargetName);
bool createHLSLPixelShader(const char* pixelShaderProgram,
const char* shaderEntryPointName,
const char* shaderTargetName);
void printHLSLVariables(LPD3DXCONSTANTTABLE table);
LPD3DXCONSTANTTABLE VSConstantsTable;
LPD3DXCONSTANTTABLE PSConstantsTable;
};
} // end namespace video
} // end namespace irr
#endif
#endif
#endif

View File

@ -0,0 +1,577 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_D3D9_MATERIAL_RENDERER_H_INCLUDED__
#define __C_D3D9_MATERIAL_RENDERER_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_WINDOWS_
#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
#if defined(__BORLANDC__) || defined (__BCPLUSPLUS__)
#include "irrMath.h" // needed by borland for sqrtf define
#endif
#include <d3d9.h>
#include "IMaterialRenderer.h"
#include "CD3D9Driver.h"
namespace irr
{
namespace video
{
namespace
{
D3DMATRIX UnitMatrixD3D9;
D3DMATRIX SphereMapMatrixD3D9;
inline void setTextureColorStage(IDirect3DDevice9* dev, DWORD i,
DWORD arg1, DWORD op, DWORD arg2)
{
dev->SetTextureStageState(i, D3DTSS_COLOROP, op);
dev->SetTextureStageState(i, D3DTSS_COLORARG1, arg1);
dev->SetTextureStageState(i, D3DTSS_COLORARG2, arg2);
}
inline void setTextureColorStage(IDirect3DDevice9* dev, DWORD i, DWORD arg1)
{
dev->SetTextureStageState(i, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
dev->SetTextureStageState(i, D3DTSS_COLORARG1, arg1);
}
inline void setTextureAlphaStage(IDirect3DDevice9* dev, DWORD i,
DWORD arg1, DWORD op, DWORD arg2)
{
dev->SetTextureStageState(i, D3DTSS_ALPHAOP, op);
dev->SetTextureStageState(i, D3DTSS_ALPHAARG1, arg1);
dev->SetTextureStageState(i, D3DTSS_ALPHAARG2, arg2);
}
inline void setTextureAlphaStage(IDirect3DDevice9* dev, DWORD i, DWORD arg1)
{
dev->SetTextureStageState(i, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
dev->SetTextureStageState(i, D3DTSS_ALPHAARG1, arg1);
}
} // anonymous namespace
//! Base class for all internal D3D9 material renderers
class CD3D9MaterialRenderer : public IMaterialRenderer
{
public:
//! Constructor
CD3D9MaterialRenderer(IDirect3DDevice9* d3ddev, CD3D9Driver* driver)
: pID3DDevice(d3ddev), Driver(driver)
{
}
virtual s32 getVariableID(bool vertexShader, const c8* name)
{
os::Printer::log("Invalid material to set variable in.");
return -1;
}
//! sets a variable in the shader.
//! \param vertexShader: True if this should be set in the vertex shader, false if
//! in the pixel shader.
//! \param index: Index of the variable
//! \param floats: Pointer to array of floats
//! \param count: Amount of floats in array.
virtual bool setVariable(bool vertexShader, s32 index, const f32* floats, int count)
{
os::Printer::log("Invalid material to set variable in.");
return false;
}
//! Int interface for the above.
virtual bool setVariable(bool vertexShader, s32 index, const s32* ints, int count)
{
os::Printer::log("Invalid material to set variable in.");
return false;
}
protected:
IDirect3DDevice9* pID3DDevice;
CD3D9Driver* Driver;
};
//! Solid material renderer
class CD3D9MaterialRenderer_SOLID : public CD3D9MaterialRenderer
{
public:
CD3D9MaterialRenderer_SOLID(IDirect3DDevice9* p, CD3D9Driver* d)
: CD3D9MaterialRenderer(p, d) {}
virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial,
bool resetAllRenderstates, IMaterialRendererServices* services) _IRR_OVERRIDE_
{
services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates)
{
setTextureColorStage(pID3DDevice, 0,
D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_DIFFUSE);
}
pID3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
}
};
//! Generic Texture Blend
class CD3D9MaterialRenderer_ONETEXTURE_BLEND : public CD3D9MaterialRenderer
{
public:
CD3D9MaterialRenderer_ONETEXTURE_BLEND(IDirect3DDevice9* p, CD3D9Driver* d)
: CD3D9MaterialRenderer(p, d) {}
virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial,
bool resetAllRenderstates, IMaterialRendererServices* services) _IRR_OVERRIDE_
{
services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
// if (material.MaterialType != lastMaterial.MaterialType ||
// material.MaterialTypeParam != lastMaterial.MaterialTypeParam ||
// resetAllRenderstates)
{
E_BLEND_FACTOR srcRGBFact,dstRGBFact,srcAlphaFact,dstAlphaFact;
E_MODULATE_FUNC modulate;
u32 alphaSource;
unpack_textureBlendFuncSeparate(srcRGBFact, dstRGBFact, srcAlphaFact, dstAlphaFact, modulate, alphaSource, material.MaterialTypeParam);
Driver->getBridgeCalls()->setBlend(true);
Driver->getBridgeCalls()->setBlendFuncSeparate(Driver->getD3DBlend(srcRGBFact), Driver->getD3DBlend(dstRGBFact),
Driver->getD3DBlend(srcAlphaFact), Driver->getD3DBlend(dstAlphaFact));
setTextureColorStage(pID3DDevice, 0,
D3DTA_TEXTURE, Driver->getD3DModulate(modulate), D3DTA_DIFFUSE);
if (textureBlendFunc_hasAlpha(srcRGBFact) || textureBlendFunc_hasAlpha(dstRGBFact) ||
textureBlendFunc_hasAlpha(srcAlphaFact) || textureBlendFunc_hasAlpha(dstAlphaFact))
{
if (alphaSource==EAS_VERTEX_COLOR)
{
setTextureAlphaStage(pID3DDevice, 0, D3DTA_DIFFUSE);
}
else if (alphaSource==EAS_TEXTURE)
{
setTextureAlphaStage(pID3DDevice, 0, D3DTA_TEXTURE);
}
else
{
setTextureAlphaStage(pID3DDevice, 0,
D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_DIFFUSE);
}
}
pID3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
}
}
virtual void OnUnsetMaterial() _IRR_OVERRIDE_
{
Driver->getBridgeCalls()->setBlend(false);
}
//! Returns if the material is transparent.
/** The scene management needs to know this for being able to sort the
materials by opaque and transparent.
The return value could be optimized, but we'd need to know the
MaterialTypeParam for it. */
virtual bool isTransparent() const _IRR_OVERRIDE_
{
return true;
}
};
//! Solid 2 layer material renderer
class CD3D9MaterialRenderer_SOLID_2_LAYER : public CD3D9MaterialRenderer
{
public:
CD3D9MaterialRenderer_SOLID_2_LAYER(IDirect3DDevice9* p, CD3D9Driver* d)
: CD3D9MaterialRenderer(p, d) {}
virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial,
bool resetAllRenderstates, IMaterialRendererServices* services) _IRR_OVERRIDE_
{
services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates)
{
setTextureColorStage(pID3DDevice, 0, D3DTA_TEXTURE);
pID3DDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 0);
pID3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_BLENDDIFFUSEALPHA);
}
}
};
//! Transparent add color material renderer
class CD3D9MaterialRenderer_TRANSPARENT_ADD_COLOR : public CD3D9MaterialRenderer
{
public:
CD3D9MaterialRenderer_TRANSPARENT_ADD_COLOR(IDirect3DDevice9* p, CD3D9Driver* d)
: CD3D9MaterialRenderer(p, d) {}
virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial,
bool resetAllRenderstates, IMaterialRendererServices* services) _IRR_OVERRIDE_
{
services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
Driver->getBridgeCalls()->setBlend(true);
Driver->getBridgeCalls()->setBlendFunc(D3DBLEND_ONE, D3DBLEND_INVSRCCOLOR);
if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates)
{
setTextureColorStage(pID3DDevice, 0,
D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_DIFFUSE);
pID3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
}
}
virtual void OnUnsetMaterial() _IRR_OVERRIDE_
{
Driver->getBridgeCalls()->setBlend(false);
}
//! Returns if the material is transparent. The scene management needs to know this
//! for being able to sort the materials by opaque and transparent.
virtual bool isTransparent() const _IRR_OVERRIDE_
{
return true;
}
};
//! Transparent vertex alpha material renderer
class CD3D9MaterialRenderer_TRANSPARENT_VERTEX_ALPHA : public CD3D9MaterialRenderer
{
public:
CD3D9MaterialRenderer_TRANSPARENT_VERTEX_ALPHA(IDirect3DDevice9* p, CD3D9Driver* d)
: CD3D9MaterialRenderer(p, d) {}
virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial,
bool resetAllRenderstates, IMaterialRendererServices* services) _IRR_OVERRIDE_
{
services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
Driver->getBridgeCalls()->setBlend(true);
Driver->getBridgeCalls()->setBlendFunc(D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA);
if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates)
{
setTextureColorStage(pID3DDevice, 0,
D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_DIFFUSE);
setTextureAlphaStage(pID3DDevice, 0, D3DTA_DIFFUSE);
pID3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
}
}
virtual void OnUnsetMaterial() _IRR_OVERRIDE_
{
Driver->getBridgeCalls()->setBlend(false);
}
//! Returns if the material is transparent. The scene management needs to know this
//! for being able to sort the materials by opaque and transparent.
virtual bool isTransparent() const _IRR_OVERRIDE_
{
return true;
}
};
//! Transparent alpha channel material renderer
class CD3D9MaterialRenderer_TRANSPARENT_ALPHA_CHANNEL : public CD3D9MaterialRenderer
{
public:
CD3D9MaterialRenderer_TRANSPARENT_ALPHA_CHANNEL(IDirect3DDevice9* p, CD3D9Driver* d)
: CD3D9MaterialRenderer(p, d) {}
virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial,
bool resetAllRenderstates, IMaterialRendererServices* services) _IRR_OVERRIDE_
{
services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
Driver->getBridgeCalls()->setBlend(true);
Driver->getBridgeCalls()->setBlendFunc(D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA);
if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates
|| material.MaterialTypeParam != lastMaterial.MaterialTypeParam )
{
setTextureColorStage(pID3DDevice, 0,
D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_CURRENT);
setTextureAlphaStage(pID3DDevice, 0, D3DTA_TEXTURE);
pID3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
pID3DDevice->SetRenderState(D3DRS_ALPHAREF, core::floor32(material.MaterialTypeParam * 255.f));
pID3DDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL);
pID3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);
}
}
virtual void OnUnsetMaterial() _IRR_OVERRIDE_
{
pID3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
Driver->getBridgeCalls()->setBlend(false);
}
//! Returns if the material is transparent. The scene management needs to know this
//! for being able to sort the materials by opaque and transparent.
virtual bool isTransparent() const _IRR_OVERRIDE_
{
return true;
}
};
//! Transparent alpha channel material renderer
class CD3D9MaterialRenderer_TRANSPARENT_ALPHA_CHANNEL_REF : public CD3D9MaterialRenderer
{
public:
CD3D9MaterialRenderer_TRANSPARENT_ALPHA_CHANNEL_REF(IDirect3DDevice9* p, CD3D9Driver* d)
: CD3D9MaterialRenderer(p, d) {}
virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial,
bool resetAllRenderstates, IMaterialRendererServices* services) _IRR_OVERRIDE_
{
services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates)
{
setTextureColorStage(pID3DDevice, 0,
D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_CURRENT);
setTextureAlphaStage(pID3DDevice, 0, D3DTA_TEXTURE);
pID3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
// 127 is required by EMT_TRANSPARENT_ALPHA_CHANNEL_REF
pID3DDevice->SetRenderState(D3DRS_ALPHAREF, 127);
pID3DDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL);
pID3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);
}
}
virtual void OnUnsetMaterial() _IRR_OVERRIDE_
{
pID3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
}
//! Returns if the material is transparent. The scene management needs to know this
//! for being able to sort the materials by opaque and transparent.
virtual bool isTransparent() const _IRR_OVERRIDE_
{
return false; // this material is not really transparent because it does no blending.
}
};
//! material renderer for all kinds of lightmaps
class CD3D9MaterialRenderer_LIGHTMAP : public CD3D9MaterialRenderer
{
public:
CD3D9MaterialRenderer_LIGHTMAP(IDirect3DDevice9* p, CD3D9Driver* d)
: CD3D9MaterialRenderer(p, d) {}
virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial,
bool resetAllRenderstates, IMaterialRendererServices* services) _IRR_OVERRIDE_
{
services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates)
{
if (material.MaterialType >= EMT_LIGHTMAP_LIGHTING)
{
// with lighting
setTextureColorStage(pID3DDevice, 0,
D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_DIFFUSE);
}
else
{
setTextureColorStage(pID3DDevice, 0, D3DTA_TEXTURE);
}
pID3DDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 1);
setTextureColorStage(pID3DDevice, 1,
D3DTA_TEXTURE,
(material.MaterialType == EMT_LIGHTMAP_ADD)?
D3DTOP_ADD:
(material.MaterialType == EMT_LIGHTMAP_M4 || material.MaterialType == EMT_LIGHTMAP_LIGHTING_M4)?
D3DTOP_MODULATE4X:
(material.MaterialType == EMT_LIGHTMAP_M2 || material.MaterialType == EMT_LIGHTMAP_LIGHTING_M2)?
D3DTOP_MODULATE2X:
D3DTOP_MODULATE,
D3DTA_CURRENT);
}
}
};
//! material renderer for detail maps
class CD3D9MaterialRenderer_DETAIL_MAP : public CD3D9MaterialRenderer
{
public:
CD3D9MaterialRenderer_DETAIL_MAP(IDirect3DDevice9* p, CD3D9Driver* d)
: CD3D9MaterialRenderer(p, d) {}
virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial,
bool resetAllRenderstates, IMaterialRendererServices* services) _IRR_OVERRIDE_
{
services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates)
{
setTextureColorStage(pID3DDevice, 0,
D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_DIFFUSE);
setTextureColorStage(pID3DDevice, 1,
D3DTA_TEXTURE, D3DTOP_ADDSIGNED, D3DTA_CURRENT);
pID3DDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 1);
}
}
};
//! sphere map material renderer
class CD3D9MaterialRenderer_SPHERE_MAP : public CD3D9MaterialRenderer
{
public:
CD3D9MaterialRenderer_SPHERE_MAP(IDirect3DDevice9* p, CD3D9Driver* d)
: CD3D9MaterialRenderer(p, d) {}
virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial,
bool resetAllRenderstates, IMaterialRendererServices* services) _IRR_OVERRIDE_
{
services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates)
{
setTextureColorStage(pID3DDevice, 0,
D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_DIFFUSE);
pID3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
pID3DDevice->SetTransform( D3DTS_TEXTURE0, &SphereMapMatrixD3D9 );
pID3DDevice->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2 );
pID3DDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACENORMAL );
}
}
virtual void OnUnsetMaterial() _IRR_OVERRIDE_
{
pID3DDevice->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE );
pID3DDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0);
pID3DDevice->SetTransform( D3DTS_TEXTURE0, &UnitMatrixD3D9 );
}
};
//! reflection 2 layer material renderer
class CD3D9MaterialRenderer_REFLECTION_2_LAYER : public CD3D9MaterialRenderer
{
public:
CD3D9MaterialRenderer_REFLECTION_2_LAYER(IDirect3DDevice9* p, CD3D9Driver* d)
: CD3D9MaterialRenderer(p, d) {}
virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial,
bool resetAllRenderstates, IMaterialRendererServices* services) _IRR_OVERRIDE_
{
services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates)
{
setTextureColorStage(pID3DDevice, 0,
D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_DIFFUSE);
setTextureColorStage(pID3DDevice, 1,
D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_CURRENT);
pID3DDevice->SetTransform( D3DTS_TEXTURE1, &SphereMapMatrixD3D9 );
pID3DDevice->SetTextureStageState( 1, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2 );
pID3DDevice->SetTextureStageState( 1, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
}
}
virtual void OnUnsetMaterial() _IRR_OVERRIDE_
{
pID3DDevice->SetTextureStageState( 1, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE );
pID3DDevice->SetTextureStageState( 1, D3DTSS_TEXCOORDINDEX, 1);
pID3DDevice->SetTransform( D3DTS_TEXTURE1, &UnitMatrixD3D9 );
}
};
//! reflection 2 layer material renderer
class CD3D9MaterialRenderer_TRANSPARENT_REFLECTION_2_LAYER : public CD3D9MaterialRenderer
{
public:
CD3D9MaterialRenderer_TRANSPARENT_REFLECTION_2_LAYER(IDirect3DDevice9* p, CD3D9Driver* d)
: CD3D9MaterialRenderer(p, d) {}
virtual void OnSetMaterial(const SMaterial& material, const SMaterial& lastMaterial,
bool resetAllRenderstates, IMaterialRendererServices* services) _IRR_OVERRIDE_
{
services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
Driver->getBridgeCalls()->setBlend(true);
Driver->getBridgeCalls()->setBlendFunc(D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA);
if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates)
{
setTextureColorStage(pID3DDevice, 0,
D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_DIFFUSE);
setTextureAlphaStage(pID3DDevice, 0, D3DTA_DIFFUSE);
setTextureColorStage(pID3DDevice, 1,
D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_CURRENT);
setTextureAlphaStage(pID3DDevice, 1, D3DTA_CURRENT);
pID3DDevice->SetTransform(D3DTS_TEXTURE1, &SphereMapMatrixD3D9 );
pID3DDevice->SetTextureStageState(1, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2 );
pID3DDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
}
}
virtual void OnUnsetMaterial() _IRR_OVERRIDE_
{
pID3DDevice->SetTextureStageState(1, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE);
pID3DDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 1);
pID3DDevice->SetTransform(D3DTS_TEXTURE1, &UnitMatrixD3D9);
Driver->getBridgeCalls()->setBlend(false);
}
//! Returns if the material is transparent. The scene management needs to know this
//! for being able to sort the materials by opaque and transparent.
virtual bool isTransparent() const _IRR_OVERRIDE_
{
return true;
}
};
} // end namespace video
} // end namespace irr
#endif
#endif
#endif

View File

@ -0,0 +1,306 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
#include "CD3D9NormalMapRenderer.h"
#include "IVideoDriver.h"
#include "IMaterialRendererServices.h"
#include "os.h"
#include "SLight.h"
namespace irr
{
namespace video
{
// 1.1 Shaders with two lights and vertex based attenuation
// Irrlicht Engine D3D9 render path normal map vertex shader
const char D3D9_NORMAL_MAP_VSH[] =
";Irrlicht Engine 0.8 D3D9 render path normal map vertex shader\n"\
"; c0-3: Transposed world matrix \n"\
"; c8-11: Transposed worldViewProj matrix (Projection * View * World) \n"\
"; c12: Light01 position \n"\
"; c13: x,y,z: Light01 color; .w: 1/LightRadius<75> \n"\
"; c14: Light02 position \n"\
"; c15: x,y,z: Light02 color; .w: 1/LightRadius<75> \n"\
"vs.1.1\n"\
"dcl_position v0 ; position \n"\
"dcl_normal v1 ; normal \n"\
"dcl_color v2 ; color \n"\
"dcl_texcoord0 v3 ; texture coord \n"\
"dcl_texcoord1 v4 ; tangent \n"\
"dcl_texcoord2 v5 ; binormal \n"\
"\n"\
"def c95, 0.5, 0.5, 0.5, 0.5 ; used for moving light vector to ps \n"\
"\n"\
"m4x4 oPos, v0, c8 ; transform position to clip space with worldViewProj matrix\n"\
"\n"\
"m3x3 r5, v4, c0 ; transform tangent U\n"\
"m3x3 r7, v1, c0 ; transform normal W\n"\
"m3x3 r6, v5, c0 ; transform binormal V\n"\
"\n"\
"m4x4 r4, v0, c0 ; vertex into world position\n"\
"add r2, c12, -r4 ; vtxpos - lightpos1\n"\
"add r3, c14, -r4 ; vtxpos - lightpos2\n"\
"\n"\
"dp3 r8.x, r5, r2 ; transform the light vector 1 with U, V, W\n"\
"dp3 r8.y, r6, r2 \n"\
"dp3 r8.z, r7, r2 \n"\
"dp3 r9.x, r5, r3 ; transform the light vector 2 with U, V, W\n"\
"dp3 r9.y, r6, r3 \n"\
"dp3 r9.z, r7, r3 \n"\
"\n"\
"dp3 r8.w, r8, r8 ; normalize light vector 1 (r8)\n"\
"rsq r8.w, r8.w \n"\
"mul r8, r8, r8.w \n"\
"dp3 r9.w, r9, r9 ; normalize light vector 2 (r9)\n"\
"rsq r9.w, r9.w \n"\
"mul r9, r9, r9.w \n"\
"\n"\
"mad oT2.xyz, r8.xyz, c95, c95 ; move light vector 1 from -1..1 into 0..1 \n"\
"mad oT3.xyz, r9.xyz, c95, c95 ; move light vector 2 from -1..1 into 0..1 \n"\
"\n"\
" ; calculate attenuation of light 1 \n"\
"dp3 r2.x, r2.xyz, r2.xyz ; r2.x = r2.x<> + r2.y<> + r2.z<> \n"\
"mul r2.x, r2.x, c13.w ; r2.x * attenutation \n"\
"rsq r2, r2.x ; r2.xyzw = 1/sqrt(r2.x * attenutation)\n"\
"mul oD0, r2, c13 ; resulting light color = lightcolor * attenuation \n"\
"\n"\
" ; calculate attenuation of light 2 \n"\
"dp3 r3.x, r3.xyz, r3.xyz ; r3.x = r3.x<> + r3.y<> + r3.z<> \n"\
"mul r3.x, r3.x, c15.w ; r2.x * attenutation \n"\
"rsq r3, r3.x ; r2.xyzw = 1/sqrt(r2.x * attenutation)\n"\
"mul oD1, r3, c15 ; resulting light color = lightcolor * attenuation \n"\
"\n"\
"mov oT0.xy, v3.xy ; move out texture coordinates 1\n"\
"mov oT1.xy, v3.xy ; move out texture coordinates 2\n"\
"mov oD0.a, v2.a ; move out original alpha value \n"\
"\n";
// Irrlicht Engine D3D9 render path normal map pixel shader
const char D3D9_NORMAL_MAP_PSH_1_1[] =
";Irrlicht Engine 0.8 D3D9 render path normal map pixel shader\n"\
";Input: \n"\
";t0: color map texture coord \n"\
";t1: normal map texture coords \n"\
";t2: light 1 vector in tangent space \n"\
";v0: light 1 color \n"\
";t3: light 2 vector in tangent space \n"\
";v1: light 2 color \n"\
";v0.a: vertex alpha value \n"\
"ps.1.1 \n"\
"tex t0 ; sample color map \n"\
"tex t1 ; sample normal map\n"\
"texcoord t2 ; fetch light vector 1\n"\
"texcoord t3 ; fetch light vector 2\n"\
"\n"\
"dp3_sat r0, t1_bx2, t2_bx2 ; normal dot light 1 (_bx2 because moved into 0..1)\n"\
"mul r0, r0, v0 ; luminance1 * light color 1 \n"\
"\n"\
"dp3_sat r1, t1_bx2, t3_bx2 ; normal dot light 2 (_bx2 because moved into 0..1)\n"\
"mad r0, r1, v1, r0 ; (luminance2 * light color 2) + luminance 1 \n"\
"\n"\
"mul r0.xyz, t0, r0 ; total luminance * base color\n"\
"+mov r0.a, v0.a ; write interpolated vertex alpha value \n"\
"\n"\
"";
// Higher-quality normal map pixel shader (requires PS 2.0)
// uses per-pixel normalization for improved accuracy
const char D3D9_NORMAL_MAP_PSH_2_0[] =
";Irrlicht Engine 0.8 D3D9 render path normal map pixel shader\n"\
";Input: \n"\
";t0: color map texture coord \n"\
";t1: normal map texture coords \n"\
";t2: light 1 vector in tangent space \n"\
";v0: light 1 color \n"\
";t3: light 2 vector in tangent space \n"\
";v1: light 2 color \n"\
";v0.a: vertex alpha value \n"\
"ps_2_0 \n"\
"def c0, 0, 0, 0, 0\n"\
"def c1, 1.0, 1.0, 1.0, 1.0\n"\
"def c2, 2.0, 2.0, 2.0, 2.0\n"\
"def c3, -.5, -.5, -.5, -.5\n"\
"dcl t0\n"\
"dcl t1\n"\
"dcl t2\n"\
"dcl t3\n"\
"dcl v1\n"\
"dcl v0\n"\
"dcl_2d s0\n"\
"dcl_2d s1\n"\
"texld r0, t0, s0 ; sample color map into r0 \n"\
"texld r4, t0, s1 ; sample normal map into r4\n"\
"add r4, r4, c3 ; bias the normal vector\n"\
"add r5, t2, c3 ; bias the light 1 vector into r5\n"\
"add r6, t3, c3 ; bias the light 2 vector into r6\n"\
"nrm r1, r4 ; normalize the normal vector into r1\n"\
"nrm r2, r5 ; normalize the light1 vector into r2\n"\
"nrm r3, r6 ; normalize the light2 vector into r3\n"\
"dp3 r2, r2, r1 ; let r2 = normal DOT light 1 vector\n"\
"max r2, r2, c0 ; clamp result to positive numbers\n"\
"mul r2, r2, v0 ; let r2 = luminance1 * light color 1 \n"\
"dp3 r3, r3, r1 ; let r3 = normal DOT light 2 vector\n"\
"max r3, r3, c0 ; clamp result to positive numbers\n"\
"mad r2, r3, v1, r2 ; let r2 = (luminance2 * light color 2) + (luminance2 * light color 1) \n"\
"mul r2, r2, r0 ; let r2 = total luminance * base color\n"\
"mov r2.w, v0.w ; write interpolated vertex alpha value \n"\
"mov oC0, r2 ; copy r2 to the output register \n"\
"\n"\
"";
CD3D9NormalMapRenderer::CD3D9NormalMapRenderer(
IDirect3DDevice9* d3ddev, video::IVideoDriver* driver,
s32& outMaterialTypeNr, IMaterialRenderer* baseMaterial)
: CD3D9ShaderMaterialRenderer(d3ddev, driver, 0, baseMaterial)
{
#ifdef _DEBUG
setDebugName("CD3D9NormalMapRenderer");
#endif
// set this as callback. We could have done this in
// the initialization list, but some compilers don't like it.
CallBack = this;
// basically, this thing simply compiles the hardcoded shaders
// if the hardware is able to do them, otherwise it maps to the
// base material
if (!driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) ||
!driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1))
{
// this hardware is not able to do shaders. Fall back to
// base material.
outMaterialTypeNr = driver->addMaterialRenderer(this);
return;
}
// check if already compiled normal map shaders are there.
video::IMaterialRenderer* renderer = driver->getMaterialRenderer(EMT_NORMAL_MAP_SOLID);
if (renderer)
{
// use the already compiled shaders
video::CD3D9NormalMapRenderer* nmr = (video::CD3D9NormalMapRenderer*)renderer;
VertexShader = nmr->VertexShader;
if (VertexShader)
VertexShader->AddRef();
PixelShader = nmr->PixelShader;
if (PixelShader)
PixelShader->AddRef();
outMaterialTypeNr = driver->addMaterialRenderer(this);
}
else
{
// compile shaders on our own
if (driver->queryFeature(video::EVDF_PIXEL_SHADER_2_0))
{
init(outMaterialTypeNr, D3D9_NORMAL_MAP_VSH, D3D9_NORMAL_MAP_PSH_2_0);
}
else
{
init(outMaterialTypeNr, D3D9_NORMAL_MAP_VSH, D3D9_NORMAL_MAP_PSH_1_1);
}
}
// something failed, use base material
if (-1==outMaterialTypeNr)
driver->addMaterialRenderer(this);
}
CD3D9NormalMapRenderer::~CD3D9NormalMapRenderer()
{
if (CallBack == this)
CallBack = 0;
}
bool CD3D9NormalMapRenderer::OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype)
{
if (vtxtype != video::EVT_TANGENTS)
{
os::Printer::log("Error: Normal map renderer only supports vertices of type EVT_TANGENTS", ELL_ERROR);
return false;
}
return CD3D9ShaderMaterialRenderer::OnRender(service, vtxtype);
}
//! Returns the render capability of the material.
s32 CD3D9NormalMapRenderer::getRenderCapability() const
{
if (Driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) &&
Driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1))
return 0;
return 1;
}
//! Called by the engine when the vertex and/or pixel shader constants
//! for an material renderer should be set.
void CD3D9NormalMapRenderer::OnSetConstants(IMaterialRendererServices* services, s32 userData)
{
video::IVideoDriver* driver = services->getVideoDriver();
// set transposed world matrix
services->setVertexShaderConstant(driver->getTransform(video::ETS_WORLD).getTransposed().pointer(), 0, 4);
// set transposed worldViewProj matrix
core::matrix4 worldViewProj(driver->getTransform(video::ETS_PROJECTION));
worldViewProj *= driver->getTransform(video::ETS_VIEW);
worldViewProj *= driver->getTransform(video::ETS_WORLD);
services->setVertexShaderConstant(worldViewProj.getTransposed().pointer(), 8, 4);
// here we've got to fetch the fixed function lights from the
// driver and set them as constants
u32 cnt = driver->getDynamicLightCount();
for (u32 i=0; i<2; ++i)
{
SLight light;
if (i<cnt)
light = driver->getDynamicLight(i);
else
{
light.DiffuseColor.set(0,0,0); // make light dark
light.Radius = 1.0f;
}
light.DiffuseColor.a = 1.0f/(light.Radius*light.Radius); // set attenuation
services->setVertexShaderConstant(reinterpret_cast<const f32*>(&light.Position), 12+(i*2), 1);
services->setVertexShaderConstant(reinterpret_cast<const f32*>(&light.DiffuseColor), 13+(i*2), 1);
}
// this is not really necessary in d3d9 (used a def instruction), but to be sure:
f32 c95[] = {0.5f, 0.5f, 0.5f, 0.5f};
services->setVertexShaderConstant(c95, 95, 1);
}
} // end namespace video
} // end namespace irr
#endif // _IRR_COMPILE_WITH_DIRECT3D_9_

View File

@ -0,0 +1,56 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_D3D9_NORMAL_MAPMATERIAL_RENDERER_H_INCLUDED__
#define __C_D3D9_NORMAL_MAPMATERIAL_RENDERER_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_WINDOWS_
#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
#if defined(__BORLANDC__) || defined (__BCPLUSPLUS__)
#include "irrMath.h" // needed by borland for sqrtf define
#endif
#include <d3d9.h>
#include "CD3D9ShaderMaterialRenderer.h"
#include "IShaderConstantSetCallBack.h"
namespace irr
{
namespace video
{
//! Renderer for normal maps
class CD3D9NormalMapRenderer :
public CD3D9ShaderMaterialRenderer, IShaderConstantSetCallBack
{
public:
CD3D9NormalMapRenderer(
IDirect3DDevice9* d3ddev, video::IVideoDriver* driver,
s32& outMaterialTypeNr, IMaterialRenderer* baseMaterial);
~CD3D9NormalMapRenderer();
//! Called by the engine when the vertex and/or pixel shader constants for an
//! material renderer should be set.
virtual void OnSetConstants(IMaterialRendererServices* services, s32 userData) _IRR_OVERRIDE_;
virtual bool OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype) _IRR_OVERRIDE_;
//! Returns the render capability of the material.
virtual s32 getRenderCapability() const _IRR_OVERRIDE_;
private:
};
} // end namespace video
} // end namespace irr
#endif
#endif
#endif

View File

@ -0,0 +1,409 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
#include "CD3D9ParallaxMapRenderer.h"
#include "IMaterialRendererServices.h"
#include "IVideoDriver.h"
#include "os.h"
#include "SLight.h"
//#define SHADER_EXTERNAL_DEBUG
#ifdef SHADER_EXTERNAL_DEBUG
#include "CReadFile.h"
#endif
namespace irr
{
namespace video
{
// 1.1/1.4 Shaders with two lights and vertex based attenuation
// Irrlicht Engine D3D9 render path normal map vertex shader
const char D3D9_PARALLAX_MAP_VSH[] =
";Irrlicht Engine 0.10 D3D9 render path parallax mapping vertex shader\n"\
"; c0-3: Transposed world matrix \n"\
"; c4: Eye position \n"\
"; c8-11: Transposed worldViewProj matrix (Projection * View * World) \n"\
"; c12: Light01 position \n"\
"; c13: x,y,z: Light01 color; .w: 1/LightRadius<75> \n"\
"; c14: Light02 position \n"\
"; c15: x,y,z: Light02 color; .w: 1/LightRadius<75> \n"\
"vs.1.1\n"\
"dcl_position v0 ; position \n"\
"dcl_normal v1 ; normal \n"\
"dcl_color v2 ; color \n"\
"dcl_texcoord0 v3 ; texture coord \n"\
"dcl_texcoord1 v4 ; tangent \n"\
"dcl_texcoord2 v5 ; binormal \n"\
"\n"\
"def c95, 0.5, 0.5, 0.5, 0.5 ; used for moving light vector to ps \n"\
"def c96, -1, 1, 1, 1 ; somewhere I've got a bug. flipping the vectors with this fixes it. \n"\
"\n"\
"m4x4 oPos, v0, c8 ; transform position to clip space with worldViewProj matrix\n"\
"\n"\
"m3x3 r5, v4, c0 ; transform tangent U\n"\
"m3x3 r7, v1, c0 ; transform normal W\n"\
"m3x3 r6, v5, c0 ; transform binormal V\n"\
"\n"\
"m4x4 r4, v0, c0 ; vertex into world position\n"\
"add r2, c12, -r4 ; vtxpos - light1 pos\n"\
"add r3, c14, -r4 ; vtxpos - light2 pos\n"\
"add r1, -c4, r4 ; eye - vtxpos \n"\
"\n"\
"dp3 r8.x, r5, r2 ; transform the light1 vector with U, V, W\n"\
"dp3 r8.y, r6, r2 \n"\
"dp3 r8.z, r7, r2 \n"\
"dp3 r9.x, r5, r3 ; transform the light2 vector with U, V, W\n"\
"dp3 r9.y, r6, r3 \n"\
"dp3 r9.z, r7, r3 \n"\
"dp3 r10.x, r5, r1 ; transform the eye vector with U, V, W\n"\
"dp3 r10.y, r6, r1 \n"\
"dp3 r10.z, r7, r1 \n"\
"\n"\
"dp3 r8.w, r8, r8 ; normalize light vector 1 (r8)\n"\
"rsq r8.w, r8.w \n"\
"mul r8, r8, r8.w \n"\
";mul r8, r8, c96 \n"\
"dp3 r9.w, r9, r9 ; normalize light vector 2 (r9)\n"\
"rsq r9.w, r9.w \n"\
"mul r9, r9, r9.w \n"\
";mul r9, r9, c96 \n"\
"dp3 r10.w, r10, r10 ; normalize eye vector (r10)\n"\
"rsq r10.w, r10.w \n"\
"mul r10, r10, r10.w \n"\
"mul r10, r10, c96 \n"\
"\n"\
"\n"\
"mad oT2.xyz, r8.xyz, c95, c95 ; move light vector 1 from -1..1 into 0..1 \n"\
"mad oT3.xyz, r9.xyz, c95, c95 ; move light vector 2 from -1..1 into 0..1 \n"\
"mad oT4.xyz, r10.xyz, c95, c95 ; move eye vector from -1..1 into 0..1 \n"\
"\n"\
" ; calculate attenuation of light 1 \n"\
"dp3 r2.x, r2.xyz, r2.xyz ; r2.x = r2.x<> + r2.y<> + r2.z<> \n"\
"mul r2.x, r2.x, c13.w ; r2.x * attenutation \n"\
"rsq r2, r2.x ; r2.xyzw = 1/sqrt(r2.x * attenutation)\n"\
"mul oD0, r2, c13 ; resulting light color = lightcolor * attenuation \n"\
"\n"\
" ; calculate attenuation of light 2 \n"\
"dp3 r3.x, r3.xyz, r3.xyz ; r3.x = r3.x<> + r3.y<> + r3.z<> \n"\
"mul r3.x, r3.x, c15.w ; r2.x * attenutation \n"\
"rsq r3, r3.x ; r2.xyzw = 1/sqrt(r2.x * attenutation)\n"\
"mul oD1, r3, c15 ; resulting light color = lightcolor * attenuation \n"\
"\n"\
"mov oT0.xy, v3.xy ; move out texture coordinates 1\n"\
"mov oT1.xy, v3.xy ; move out texture coordinates 2\n"\
"mov oD0.a, v2.a ; move out original alpha value \n"\
"\n";
// Irrlicht Engine D3D9 render path normal map pixel shader version 1.4
const char D3D9_PARALLAX_MAP_PSH[] =
";Irrlicht Engine 0.10 D3D9 render path parallax mapping pixel shader \n"\
";Input: \n"\
";t0: color map texture coord \n"\
";t1: normal map texture coords \n"\
";t2: light 1 vector in tangent space \n"\
";t4: eye vector in tangent space \n"\
";v0: light 1 color \n"\
";t3: light 2 vector in tangent space \n"\
";v1: light 2 color \n"\
";v0.a: vertex alpha value \n"\
" \n"\
"ps.1.4 \n"\
" \n"\
";def c6, 0.02f, 0.02f, 0.02f, 0.0f ; scale factor, now set in callback \n"\
"def c5, 0.5f, 0.5f, 0.5f, 0.0f ; for specular division \n"\
" \n"\
"texld r1, t1 ; sample (normal.x, normal.y, normal.z, height) \n"\
"texcrd r4.xyz, t4 ; fetch eye vector \n"\
"texcrd r0.xyz, t0 ; color map \n"\
" \n"\
"; original parallax mapping: \n"\
";mul r3, r1_bx2.wwww, c6; ; r3 = (height, height, height) * scale \n"\
";mad r2.xyz, r3, r4_bx2, r0 ; newTexCoord = height * eye + oldTexCoord \n"\
" \n"\
"; modified parallax mapping to reduce swimming effect: \n"\
"mul r3, r1_bx2.wwww, r1_bx2.zzzz ; (nh,nh,nh,nh) = (h,h,h,h) * (n.z,n.z,n.z,n.z,) \n"\
"mul r3, r3, c6; ; r3 = (nh, nh, nh) * scale \n"\
"mad r2.xyz, r3, r4_bx2, r0 ; newTexCoord = height * eye + oldTexCoord \n"\
" \n"\
"phase \n"\
" \n"\
"texld r0, r2 ; load diffuse texture with new tex coord \n"\
"texld r1, r2 ; sample normal map \n"\
"texcrd r2.xyz, t2 ; fetch light vector 1 \n"\
"texcrd r3.xyz, t3 ; fetch light vector 2 \n"\
" \n"\
"dp3_sat r5, r1_bx2, r2_bx2 ; normal dot light 1 (_bx2 because moved into 0..1) \n"\
"mul r5, r5, v0 ; luminance1 * light color 1 \n"\
" \n"\
"dp3_sat r3, r1_bx2, r3_bx2 ; normal dot light 2 (_bx2 because moved into 0..1) \n"\
"mad r3, r3, v1, r5 ; (luminance2 * light color 2) + luminance1 \n"\
" \n"\
"mul r0.xyz, r0, r3 ; total luminance * base color \n"\
"+mov r0.a, v0.a ; write original alpha value \n"\
"\n";
// Irrlicht Engine D3D9 render path normal map pixel shader version 2.0
const char D3D9_PARALLAX_MAP_PSH_20[] =
";Irrlicht Engine D3D9 render path parallax mapping pixel shader \n"\
";Input: \n"\
" \n"\
";t0: color map texture coord \n"\
";t1: normal map texture coords \n"\
";t2: light 1 vector in tangent space \n"\
";t4: eye vector in tangent space \n"\
";v0: light 1 color \n"\
";t3: light 2 vector in tangent space \n"\
";v1: light 2 color \n"\
";v0.a: vertex alpha value \n"\
" \n"\
"ps.2.0 \n"\
" \n"\
"dcl_2d s0 ; Declare the s0 register to be the sampler for stage 0 \n"\
"dcl t0.xy ; Declare t0 to have 2D texture coordinates from stage 0 \n"\
"dcl t1.xy ; Declare t0 to have 2D texture coordinates from stage 0 \n"\
"dcl_2d s1 ; Declare the s1 register to be the sampler for stage 1 \n"\
" \n"\
"dcl t2.xyz ; \n"\
"dcl t3.xyz ; \n"\
"dcl t4.xyz ; \n"\
"dcl v0.xyzw; \n"\
"dcl v1.xyzw; \n"\
" \n"\
"def c0, -1.0f, -1.0f, -1.0f, -1.0f ; for _bx2 emulation \n"\
"def c1, 2.0f, 2.0f, 2.0f, 2.0f ; for _bx2 emulation \n"\
"mov r11, c1; \n"\
" \n"\
"texld r1, t1, s1 ; sample (normal.x, normal.y, normal.z, height) \n"\
"mov r4.xyz, t4 ; fetch eye vector \n"\
"mov r0.xy, t0 ; color map \n"\
" \n"\
"; original parallax mapping: \n"\
"; emulate ps1x _bx2, so substract 0.5f and multiply by 2 \n"\
"mad r1.xyz, r1, r11, c0; \n"\
" \n"\
"mul r3, r1.wwww, c6; ; r3 = (height, height, height) * scale \n"\
" \n"\
"; emulate ps1x _bx2, so substract 0.5f and multiply by 2 \n"\
"mad r4.xyz, r4, r11, c0; \n"\
" \n"\
"mad r2.xy, r3, r4, r0 ; newTexCoord = height * eye + oldTexCoord \n"\
" \n"\
"; modified parallax mapping to avoid swimming: \n"\
";mul r3, r1_bx2.wwww, r1_bx2.zzzz ; r3 = (h,h,h,h) * (n.z, n.z, n.z, n.z,) \n"\
";mul r3, r3, c6; ; r3 = (nh, nh, nh) * scale \n"\
";mad r2.xyz, r3, r4_bx2, r0 ; newTexCoord = height * eye + oldTexCoord \n"\
" \n"\
"texld r0, r2, s0 ; load diffuse texture with new tex coord \n"\
"texld r1, r2, s1 ; sample normal map \n"\
"mov r2.xyz, t2 ; fetch light vector 1 \n"\
"mov r3.xyz, t3 ; fetch light vector 2 \n"\
" \n"\
"; emulate ps1x _bx2, so substract 0.5f and multiply by 2 \n"\
"mad r1.xyz, r1, r11, c0; \n"\
"mad r2.xyz, r2, r11, c0; \n"\
"mad r3.xyz, r3, r11, c0; \n"\
" \n"\
"dp3_sat r2, r1, r2 ; normal dot light 1 (_bx2 because moved into 0..1) \n"\
"mul r2, r2, v0 ; luminance1 * light color 1 \n"\
" \n"\
"dp3_sat r3, r1, r3 ; normal dot light 2 (_bx2 because moved into 0..1) \n"\
"mad r3, r3, v1, r2 ; (luminance2 * light color 2) + luminance1 \n"\
" \n"\
"mul r0.xyz, r0, r3 ; total luminance * base color \n"\
"mov r0.a, v0.a ; write original alpha value \n"\
"mov oC0, r0; \n"\
"\n";
CD3D9ParallaxMapRenderer::CD3D9ParallaxMapRenderer(
IDirect3DDevice9* d3ddev, video::IVideoDriver* driver,
s32& outMaterialTypeNr, IMaterialRenderer* baseMaterial)
: CD3D9ShaderMaterialRenderer(d3ddev, driver, 0, baseMaterial),
CurrentScale(0.0f)
{
#ifdef _DEBUG
setDebugName("CD3D9ParallaxMapRenderer");
#endif
// set this as callback. We could have done this in
// the initialization list, but some compilers don't like it.
CallBack = this;
// basically, this thing simply compiles these hardcoded shaders if the
// hardware is able to do them, otherwise it maps to the base material
if (!driver->queryFeature(video::EVDF_PIXEL_SHADER_1_4) ||
!driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1))
{
// this hardware is not able to do shaders. Fall back to
// base material.
outMaterialTypeNr = driver->addMaterialRenderer(this);
return;
}
// check if already compiled parallax map shaders are there.
video::IMaterialRenderer* renderer = driver->getMaterialRenderer(EMT_PARALLAX_MAP_SOLID);
if (renderer)
{
// use the already compiled shaders
video::CD3D9ParallaxMapRenderer* nmr = (video::CD3D9ParallaxMapRenderer*)renderer;
VertexShader = nmr->VertexShader;
if (VertexShader)
VertexShader->AddRef();
PixelShader = nmr->PixelShader;
if (PixelShader)
PixelShader->AddRef();
outMaterialTypeNr = driver->addMaterialRenderer(this);
}
else
{
#ifdef SHADER_EXTERNAL_DEBUG
// quickly load shader from external file
io::CReadFile* file = new io::CReadFile("parallax.psh");
s32 sz = file->getSize();
char* s = new char[sz+1];
file->read(s, sz);
s[sz] = 0;
init(outMaterialTypeNr, D3D9_PARALLAX_MAP_VSH, s);
delete [] s;
file->drop();
#else
// compile shaders on our own
init(outMaterialTypeNr, D3D9_PARALLAX_MAP_VSH, D3D9_PARALLAX_MAP_PSH);
#endif // SHADER_EXTERNAL_DEBUG
}
// something failed, use base material
if (-1==outMaterialTypeNr)
driver->addMaterialRenderer(this);
}
CD3D9ParallaxMapRenderer::~CD3D9ParallaxMapRenderer()
{
if (CallBack == this)
CallBack = 0;
}
bool CD3D9ParallaxMapRenderer::OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype)
{
if (vtxtype != video::EVT_TANGENTS)
{
os::Printer::log("Error: Parallax map renderer only supports vertices of type EVT_TANGENTS", ELL_ERROR);
return false;
}
return CD3D9ShaderMaterialRenderer::OnRender(service, vtxtype);
}
void CD3D9ParallaxMapRenderer::OnSetMaterial(const video::SMaterial& material,
const video::SMaterial& lastMaterial,
bool resetAllRenderstates, video::IMaterialRendererServices* services)
{
CD3D9ShaderMaterialRenderer::OnSetMaterial(material, lastMaterial,
resetAllRenderstates, services);
CurrentScale = material.MaterialTypeParam;
}
//! Returns the render capability of the material.
s32 CD3D9ParallaxMapRenderer::getRenderCapability() const
{
if (Driver->queryFeature(video::EVDF_PIXEL_SHADER_1_4) &&
Driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1))
return 0;
return 1;
}
//! Called by the engine when the vertex and/or pixel shader constants
//! for an material renderer should be set.
void CD3D9ParallaxMapRenderer::OnSetConstants(IMaterialRendererServices* services, s32 userData)
{
video::IVideoDriver* driver = services->getVideoDriver();
// set transposed world matrix
services->setVertexShaderConstant(driver->getTransform(video::ETS_WORLD).getTransposed().pointer(), 0, 4);
// set eye position
// The viewpoint is at (0., 0., 0.) in eye space.
// Turning this into a vector [0 0 0 1] and multiply it by
// the inverse of the view matrix, the resulting vector is the
// object space location of the camera.
f32 floats[4] = {0,0,0,1};
core::matrix4 minv = driver->getTransform(video::ETS_VIEW);
minv.makeInverse();
minv.multiplyWith1x4Matrix(floats);
services->setVertexShaderConstant(floats, 4, 1);
// set transposed worldViewProj matrix
core::matrix4 worldViewProj;
worldViewProj = driver->getTransform(video::ETS_PROJECTION);
worldViewProj *= driver->getTransform(video::ETS_VIEW);
worldViewProj *= driver->getTransform(video::ETS_WORLD);
services->setVertexShaderConstant(worldViewProj.getTransposed().pointer(), 8, 4);
// here we've got to fetch the fixed function lights from the
// driver and set them as constants
const u32 cnt = driver->getDynamicLightCount();
for (u32 i=0; i<2; ++i)
{
SLight light;
if (i<cnt)
light = driver->getDynamicLight(i);
else
{
light.DiffuseColor.set(0,0,0); // make light dark
light.Radius = 1.0f;
}
light.DiffuseColor.a = 1.0f/(light.Radius*light.Radius); // set attenuation
services->setVertexShaderConstant(reinterpret_cast<const f32*>(&light.Position), 12+(i*2), 1);
services->setVertexShaderConstant(reinterpret_cast<const f32*>(&light.DiffuseColor), 13+(i*2), 1);
}
// this is not really necessary in d3d9 (used a def instruction), but to be sure:
f32 c95[] = {0.5f, 0.5f, 0.5f, 0.5f};
services->setVertexShaderConstant(c95, 95, 1);
f32 c96[] = {-1, 1, 1, 1};
services->setVertexShaderConstant(c96, 96, 1);
// set scale factor
f32 factor = 0.02f; // default value
if (CurrentScale != 0)
factor = CurrentScale;
f32 c6[] = {factor, factor, factor, 0};
services->setPixelShaderConstant(c6, 6, 1);
}
} // end namespace video
} // end namespace irr
#endif // _IRR_COMPILE_WITH_DIRECT3D_9_

View File

@ -0,0 +1,63 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_D3D9_PARALLAX_MAPMATERIAL_RENDERER_H_INCLUDED__
#define __C_D3D9_PARALLAX_MAPMATERIAL_RENDERER_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_WINDOWS_
#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
#if defined(__BORLANDC__) || defined (__BCPLUSPLUS__)
#include "irrMath.h" // needed by borland for sqrtf define
#endif
#include <d3d9.h>
#include "CD3D9ShaderMaterialRenderer.h"
#include "IShaderConstantSetCallBack.h"
namespace irr
{
namespace video
{
//! Renderer for normal maps using parallax mapping
class CD3D9ParallaxMapRenderer :
public CD3D9ShaderMaterialRenderer, IShaderConstantSetCallBack
{
public:
CD3D9ParallaxMapRenderer(
IDirect3DDevice9* d3ddev, video::IVideoDriver* driver,
s32& outMaterialTypeNr, IMaterialRenderer* baseMaterial);
~CD3D9ParallaxMapRenderer();
//! Called by the engine when the vertex and/or pixel shader constants for an
//! material renderer should be set.
virtual void OnSetConstants(IMaterialRendererServices* services, s32 userData) _IRR_OVERRIDE_;
virtual bool OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype) _IRR_OVERRIDE_;
//! Returns the render capability of the material.
virtual s32 getRenderCapability() const _IRR_OVERRIDE_;
virtual void OnSetMaterial(const SMaterial& material) _IRR_OVERRIDE_ { }
virtual void OnSetMaterial(const video::SMaterial& material,
const video::SMaterial& lastMaterial,
bool resetAllRenderstates, video::IMaterialRendererServices* services) _IRR_OVERRIDE_;
private:
f32 CurrentScale;
};
} // end namespace video
} // end namespace irr
#endif
#endif
#endif

View File

@ -0,0 +1,281 @@
// Copyright (C) 2015 Patryk Nadrowski
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CD3D9RenderTarget.h"
#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
#include "IImage.h"
#include "irrMath.h"
#include "irrString.h"
#include "CD3D9Driver.h"
#include "CD3D9Texture.h"
namespace irr
{
namespace video
{
CD3D9RenderTarget::CD3D9RenderTarget(CD3D9Driver* driver) : DepthStencilSurface(0), Driver(driver)
{
#ifdef _DEBUG
setDebugName("CD3D9RenderTarget");
#endif
DriverType = EDT_DIRECT3D9;
Size = Driver->getScreenSize();
}
CD3D9RenderTarget::~CD3D9RenderTarget()
{
for (u32 i = 0; i < Surface.size(); ++i)
{
if (Surface[i])
Surface[i]->Release();
}
if (DepthStencilSurface)
DepthStencilSurface->Release();
for (u32 i = 0; i < Texture.size(); ++i)
{
if (Texture[i])
Texture[i]->drop();
}
if (DepthStencil)
DepthStencil->drop();
}
void CD3D9RenderTarget::setTexture(const core::array<ITexture*>& texture, ITexture* depthStencil, const core::array<E_CUBE_SURFACE>& cubeSurfaces)
{
bool needSizeUpdate = false;
// Set color attachments.
if ((Texture != texture) || (CubeSurfaces != cubeSurfaces))
{
needSizeUpdate = true;
CubeSurfaces = cubeSurfaces; // TODO: we can probably avoid some memory allocating/de-allocating if _only_ CubeSurfaces change.
if (texture.size() > Driver->ActiveRenderTarget.size())
{
core::stringc message = "This GPU supports up to ";
message += Driver->ActiveRenderTarget.size();
message += " textures per render target.";
os::Printer::log(message.c_str(), ELL_WARNING);
}
const u32 size = core::min_(texture.size(), static_cast<u32>(Driver->ActiveRenderTarget.size()));
for (u32 i = 0; i < Surface.size(); ++i)
{
if (Surface[i])
Surface[i]->Release();
}
Surface.set_used(size);
core::array<ITexture*> prevTextures(Texture);
Texture.set_used(size);
for (u32 i = 0; i < size; ++i)
{
CD3D9Texture* currentTexture = (texture[i] && texture[i]->getDriverType() == DriverType) ? static_cast<CD3D9Texture*>(texture[i]) : 0;
IDirect3DTexture9* textureID = 0;
IDirect3DCubeTexture9* cubeTextureId = 0;
UINT level = 0; // no support for rendering to to other mip-levels so far
if (currentTexture)
{
if (currentTexture->getType() == ETT_2D)
textureID = currentTexture->getDX9Texture();
else if ( currentTexture->getType() == ETT_CUBEMAP )
cubeTextureId = currentTexture->getDX9CubeTexture();
}
if (textureID)
{
Texture[i] = texture[i];
Texture[i]->grab();
IDirect3DSurface9* currentSurface = 0;
textureID->GetSurfaceLevel(level, &currentSurface);
Surface[i] = currentSurface;
}
else if ( cubeTextureId )
{
Texture[i] = texture[i];
Texture[i]->grab();
IDirect3DSurface9* currentSurface = 0;
D3DCUBEMAP_FACES face = (D3DCUBEMAP_FACES)CubeSurfaces[i]; // we use same numbering
cubeTextureId->GetCubeMapSurface(face, level, &currentSurface);
Surface[i] = currentSurface;
}
else
{
Surface[i] = 0;
Texture[i] = 0;
}
}
for (u32 i = 0; i < prevTextures.size(); ++i)
{
if (prevTextures[i])
prevTextures[i]->drop();
}
}
// Set depth and stencil attachments.
if (DepthStencil != depthStencil)
{
if (DepthStencilSurface)
{
DepthStencilSurface->Release();
DepthStencilSurface = 0;
}
if (DepthStencil)
{
DepthStencil->drop();
DepthStencil = 0;
DepthStencilSurface = 0;
}
needSizeUpdate = true;
CD3D9Texture* currentTexture = (depthStencil && depthStencil->getDriverType() == DriverType) ? static_cast<CD3D9Texture*>(depthStencil) : 0;
if (currentTexture)
{
if (currentTexture->getType() == ETT_2D)
{
IDirect3DTexture9* textureID = currentTexture->getDX9Texture();
if (textureID)
{
const ECOLOR_FORMAT textureFormat = depthStencil->getColorFormat();
if (IImage::isDepthFormat(textureFormat))
{
DepthStencil = depthStencil;
DepthStencil->grab();
IDirect3DSurface9* currentSurface = 0;
textureID->GetSurfaceLevel(0, &currentSurface);
DepthStencilSurface = currentSurface;
}
else
{
os::Printer::log("Ignoring depth/stencil texture without depth color format.", ELL_WARNING);
}
}
}
else
os::Printer::log("This driver doesn't support depth/stencil to cubemaps.", ELL_WARNING);
}
}
if (needSizeUpdate)
{
// Set size required for a viewport.
bool sizeDetected = false;
for (u32 i = 0; i < Texture.size(); ++i)
{
if (Texture[i])
{
Size = Texture[i]->getSize();
sizeDetected = true;
break;
}
}
if (!sizeDetected)
{
if (DepthStencil)
Size = DepthStencil->getSize();
else
Size = Driver->getScreenSize();
}
}
}
const core::dimension2d<u32>& CD3D9RenderTarget::getSize() const
{
return Size;
}
IDirect3DSurface9* CD3D9RenderTarget::getSurface(u32 id) const
{
return (id < Surface.size()) ? Surface[id] : 0;
}
u32 CD3D9RenderTarget::getSurfaceCount() const
{
return Surface.size();
}
IDirect3DSurface9* CD3D9RenderTarget::getDepthStencilSurface() const
{
return DepthStencilSurface;
}
void CD3D9RenderTarget::releaseSurfaces()
{
for (u32 i = 0; i < Surface.size(); ++i)
{
if (Surface[i])
{
Surface[i]->Release();
Surface[i] = 0;
}
}
if (DepthStencilSurface)
{
DepthStencilSurface->Release();
DepthStencilSurface = 0;
}
}
void CD3D9RenderTarget::generateSurfaces()
{
for (u32 i = 0; i < Surface.size(); ++i)
{
if (!Surface[i] && Texture[i])
{
IDirect3DTexture9* currentTexture = static_cast<CD3D9Texture*>(Texture[i])->getDX9Texture();
if ( currentTexture )
{
IDirect3DSurface9* currentSurface = 0;
currentTexture->GetSurfaceLevel(0, &currentSurface);
Surface[i] = currentSurface;
}
}
}
if (!DepthStencilSurface && DepthStencil)
{
IDirect3DTexture9* currentTexture = static_cast<CD3D9Texture*>(DepthStencil)->getDX9Texture();
if ( currentTexture )
{
IDirect3DSurface9* currentSurface = 0;
currentTexture->GetSurfaceLevel(0, &currentSurface);
DepthStencilSurface = currentSurface;
}
}
}
}
}
#endif

View File

@ -0,0 +1,60 @@
// Copyright (C) 2015 Patryk Nadrowski
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_OPEN_GL_RENDER_TARGET_H_INCLUDED__
#define __C_OPEN_GL_RENDER_TARGET_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
#include "IRenderTarget.h"
#include "dimension2d.h"
#include "os.h"
#include <d3d9.h>
namespace irr
{
namespace video
{
class CD3D9Driver;
class CD3D9RenderTarget : public IRenderTarget
{
public:
CD3D9RenderTarget(CD3D9Driver* driver);
virtual ~CD3D9RenderTarget();
virtual void setTexture(const core::array<ITexture*>& texture, ITexture* depthStencil, const core::array<E_CUBE_SURFACE>& cubeSurfaces) _IRR_OVERRIDE_;
const core::dimension2d<u32>& getSize() const;
IDirect3DSurface9* getSurface(u32 id) const;
u32 getSurfaceCount() const;
IDirect3DSurface9* getDepthStencilSurface() const;
void releaseSurfaces();
void generateSurfaces();
protected:
core::dimension2d<u32> Size;
core::array<IDirect3DSurface9*> Surface;
IDirect3DSurface9* DepthStencilSurface;
CD3D9Driver* Driver;
};
}
}
#endif
#endif

View File

@ -0,0 +1,539 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
#include "CD3D9ShaderMaterialRenderer.h"
#include "IShaderConstantSetCallBack.h"
#include "IMaterialRendererServices.h"
#include "IVideoDriver.h"
#include "os.h"
#include "irrString.h"
#ifndef _IRR_D3D_NO_SHADER_DEBUGGING
#include <stdio.h>
#endif
namespace irr
{
namespace video
{
//! Public constructor
CD3D9ShaderMaterialRenderer::CD3D9ShaderMaterialRenderer(IDirect3DDevice9* d3ddev, video::IVideoDriver* driver,
s32& outMaterialTypeNr, const c8* vertexShaderProgram, const c8* pixelShaderProgram,
IShaderConstantSetCallBack* callback, IMaterialRenderer* baseMaterial, s32 userData)
: pID3DDevice(d3ddev), Driver(driver), CallBack(callback), BaseMaterial(baseMaterial),
VertexShader(0), OldVertexShader(0), PixelShader(0), UserData(userData)
{
#ifdef _DEBUG
setDebugName("CD3D9ShaderMaterialRenderer");
#endif
if (BaseMaterial)
BaseMaterial->grab();
if (CallBack)
CallBack->grab();
init(outMaterialTypeNr, vertexShaderProgram, pixelShaderProgram);
}
//! constructor only for use by derived classes who want to
//! create a fall back material for example.
CD3D9ShaderMaterialRenderer::CD3D9ShaderMaterialRenderer(IDirect3DDevice9* d3ddev,
video::IVideoDriver* driver,
IShaderConstantSetCallBack* callback,
IMaterialRenderer* baseMaterial, s32 userData)
: pID3DDevice(d3ddev), Driver(driver), CallBack(callback), BaseMaterial(baseMaterial),
VertexShader(0), OldVertexShader(0), PixelShader(0), UserData(userData)
{
#ifdef _DEBUG
setDebugName("CD3D9ShaderMaterialRenderer");
#endif
if (BaseMaterial)
BaseMaterial->grab();
if (CallBack)
CallBack->grab();
}
void CD3D9ShaderMaterialRenderer::init(s32& outMaterialTypeNr,
const c8* vertexShaderProgram, const c8* pixelShaderProgram)
{
outMaterialTypeNr = -1;
// create vertex shader
if (!createVertexShader(vertexShaderProgram))
return;
// create pixel shader
if (!createPixelShader(pixelShaderProgram))
return;
// register myself as new material
outMaterialTypeNr = Driver->addMaterialRenderer(this);
}
//! Destructor
CD3D9ShaderMaterialRenderer::~CD3D9ShaderMaterialRenderer()
{
if (CallBack)
CallBack->drop();
if (VertexShader)
VertexShader->Release();
if (PixelShader)
PixelShader->Release();
if (BaseMaterial)
BaseMaterial->drop();
}
bool CD3D9ShaderMaterialRenderer::OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype)
{
// call callback to set shader constants
if (CallBack && (VertexShader || PixelShader))
CallBack->OnSetConstants(service, UserData);
return true;
}
void CD3D9ShaderMaterialRenderer::OnSetMaterial(const video::SMaterial& material, const video::SMaterial& lastMaterial,
bool resetAllRenderstates, video::IMaterialRendererServices* services)
{
if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates)
{
if (VertexShader)
{
// save old vertex shader
pID3DDevice->GetVertexShader(&OldVertexShader);
// set new vertex shader
if (FAILED(pID3DDevice->SetVertexShader(VertexShader)))
os::Printer::log("Could not set vertex shader.", ELL_WARNING);
}
// set new pixel shader
if (PixelShader)
{
if (FAILED(pID3DDevice->SetPixelShader(PixelShader)))
os::Printer::log("Could not set pixel shader.", ELL_WARNING);
}
}
services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
if (BaseMaterial)
BaseMaterial->OnSetMaterial(material, lastMaterial, resetAllRenderstates, services);
if (CallBack)
CallBack->OnSetMaterial(material);
}
void CD3D9ShaderMaterialRenderer::OnUnsetMaterial()
{
if (VertexShader)
pID3DDevice->SetVertexShader(OldVertexShader);
if (PixelShader)
pID3DDevice->SetPixelShader(0);
if (BaseMaterial)
BaseMaterial->OnUnsetMaterial();
}
//! Returns if the material is transparent. The scene management needs to know this
//! for being able to sort the materials by opaque and transparent.
bool CD3D9ShaderMaterialRenderer::isTransparent() const
{
return BaseMaterial ? BaseMaterial->isTransparent() : false;
}
bool CD3D9ShaderMaterialRenderer::createPixelShader(const c8* pxsh)
{
if (!pxsh)
return true;
// compile shader
LPD3DXBUFFER code = 0;
LPD3DXBUFFER errors = 0;
#ifdef _IRR_D3D_NO_SHADER_DEBUGGING
// compile shader without debug info
stubD3DXAssembleShader(pxsh, (UINT)strlen(pxsh), 0, 0, 0, &code, &errors);
#else
// compile shader and emit some debug information to
// make it possible to debug the shader in visual studio
static int irr_dbg_file_nr = 0;
++irr_dbg_file_nr;
char tmp[32];
sprintf(tmp, "irr_d3d9_dbg_shader_%d.psh", irr_dbg_file_nr);
FILE* f = fopen(tmp, "wb");
fwrite(pxsh, strlen(pxsh), 1, f);
fflush(f);
fclose(f);
stubD3DXAssembleShaderFromFile(tmp, 0, 0, D3DXSHADER_DEBUG, &code, &errors);
#endif
if (errors)
{
// print out compilation errors.
os::Printer::log("Pixel shader compilation failed:", ELL_ERROR);
os::Printer::log((c8*)errors->GetBufferPointer(), ELL_ERROR);
if (code)
code->Release();
errors->Release();
return false;
}
if (FAILED(pID3DDevice->CreatePixelShader((DWORD*)code->GetBufferPointer(), &PixelShader)))
{
os::Printer::log("Could not create pixel shader.", ELL_ERROR);
code->Release();
return false;
}
code->Release();
return true;
}
bool CD3D9ShaderMaterialRenderer::createVertexShader(const char* vtxsh)
{
if (!vtxsh)
return true;
// compile shader
LPD3DXBUFFER code = 0;
LPD3DXBUFFER errors = 0;
#ifdef _IRR_D3D_NO_SHADER_DEBUGGING
// compile shader without debug info
stubD3DXAssembleShader(vtxsh, (UINT)strlen(vtxsh), 0, 0, 0, &code, &errors);
#else
// compile shader and emit some debug information to
// make it possible to debug the shader in visual studio
static int irr_dbg_file_nr = 0;
++irr_dbg_file_nr;
char tmp[32];
sprintf(tmp, "irr_d3d9_dbg_shader_%d.vsh", irr_dbg_file_nr);
FILE* f = fopen(tmp, "wb");
fwrite(vtxsh, strlen(vtxsh), 1, f);
fflush(f);
fclose(f);
stubD3DXAssembleShaderFromFile(tmp, 0, 0, D3DXSHADER_DEBUG, &code, &errors);
#endif
if (errors)
{
// print out compilation errors.
os::Printer::log("Vertex shader compilation failed:", ELL_ERROR);
os::Printer::log((c8*)errors->GetBufferPointer(), ELL_ERROR);
if (code)
code->Release();
errors->Release();
return false;
}
if (!code || FAILED(pID3DDevice->CreateVertexShader((DWORD*)code->GetBufferPointer(), &VertexShader)))
{
os::Printer::log("Could not create vertex shader.", ELL_ERROR);
if (code)
code->Release();
return false;
}
code->Release();
return true;
}
HRESULT CD3D9ShaderMaterialRenderer::stubD3DXAssembleShader(LPCSTR pSrcData,
UINT SrcDataLen, CONST D3DXMACRO* pDefines,
LPD3DXINCLUDE pInclude, DWORD Flags, LPD3DXBUFFER* ppShader,
LPD3DXBUFFER* ppErrorMsgs)
{
// Because Irrlicht needs to be able to start up even without installed d3d dlls, it
// needs to load external d3d dlls manually. examples for the dlls are:
// SDK dll name D3DX_SDK_VERSION
// Summer 2004: no dll 22
// February 2005: d3dx9_24.dll 24
// April 2005: d3dx9_25.dll 25
// June 2005: d3dx9_26.dll 26
// August 2005: d3dx9_27.dll 27
// October 2005,
// December 2005: d3dx9_28.dll 28
#if ( D3DX_SDK_VERSION < 24 )
// directly link functions, old d3d sdks didn't try to load external dlls
// when linking to the d3dx9.lib
#ifdef _MSC_VER
#pragma comment (lib, "d3dx9.lib")
#endif
// invoke static linked function
return D3DXAssembleShader(pSrcData, SrcDataLen, pDefines, pInclude,
Flags, ppShader, ppErrorMsgs);
#else
{
// try to load shader functions from the dll and print error if failed.
// D3DXAssembleShader signature
typedef HRESULT (WINAPI *AssembleShaderFunction)(LPCSTR pSrcData, UINT SrcDataLen,
CONST D3DXMACRO* pDefines, LPD3DXINCLUDE pInclude,
DWORD Flags, LPD3DXBUFFER* ppShader,
LPD3DXBUFFER* ppErrorMsgs);
static bool LoadFailed = false;
static AssembleShaderFunction pFn = 0;
if (!pFn && !LoadFailed)
{
// try to load dll
io::path strDllName = "d3dx9_";
strDllName += (int)D3DX_SDK_VERSION;
strDllName += ".dll";
HMODULE hMod = LoadLibrary(strDllName.c_str());
if (hMod)
pFn = (AssembleShaderFunction)GetProcAddress(hMod, "D3DXAssembleShader");
if (!pFn)
{
LoadFailed = true;
os::Printer::log("Could not load shader function D3DXAssembleShader from dll, shaders disabled",
strDllName.c_str(), ELL_ERROR);
}
}
if (pFn)
{
// call already loaded function
return (*pFn)(pSrcData, SrcDataLen, pDefines, pInclude, Flags, ppShader, ppErrorMsgs);
}
}
#endif // D3DX_SDK_VERSION < 24
return 0;
}
HRESULT CD3D9ShaderMaterialRenderer::stubD3DXAssembleShaderFromFile(LPCSTR pSrcFile,
CONST D3DXMACRO* pDefines, LPD3DXINCLUDE pInclude, DWORD Flags,
LPD3DXBUFFER* ppShader, LPD3DXBUFFER* ppErrorMsgs)
{
// wondering what I'm doing here?
// see comment in CD3D9ShaderMaterialRenderer::stubD3DXAssembleShader()
#if ( D3DX_SDK_VERSION < 24 )
// directly link functions, old d3d sdks didn't try to load external dlls
// when linking to the d3dx9.lib
#ifdef _MSC_VER
#pragma comment (lib, "d3dx9.lib")
#endif
// invoke static linked function
return D3DXAssembleShaderFromFileA(pSrcFile, pDefines, pInclude, Flags,
ppShader, ppErrorMsgs);
#else
{
// try to load shader functions from the dll and print error if failed.
// D3DXAssembleShaderFromFileA signature
typedef HRESULT (WINAPI *AssembleShaderFromFileFunction)(LPCSTR pSrcFile,
CONST D3DXMACRO* pDefines, LPD3DXINCLUDE pInclude, DWORD Flags,
LPD3DXBUFFER* ppShader, LPD3DXBUFFER* ppErrorMsgs);
static bool LoadFailed = false;
static AssembleShaderFromFileFunction pFn = 0;
if (!pFn && !LoadFailed)
{
// try to load dll
io::path strDllName = "d3dx9_";
strDllName += (int)D3DX_SDK_VERSION;
strDllName += ".dll";
HMODULE hMod = LoadLibrary(strDllName.c_str());
if (hMod)
pFn = (AssembleShaderFromFileFunction)GetProcAddress(hMod, "D3DXAssembleShaderFromFileA");
if (!pFn)
{
LoadFailed = true;
os::Printer::log("Could not load shader function D3DXAssembleShaderFromFileA from dll, shaders disabled",
strDllName.c_str(), ELL_ERROR);
}
}
if (pFn)
{
// call already loaded function
return (*pFn)(pSrcFile, pDefines, pInclude, Flags, ppShader, ppErrorMsgs);
}
}
#endif // D3DX_SDK_VERSION < 24
return 0;
}
HRESULT CD3D9ShaderMaterialRenderer::stubD3DXCompileShader(LPCSTR pSrcData, UINT SrcDataLen, CONST D3DXMACRO* pDefines,
LPD3DXINCLUDE pInclude, LPCSTR pFunctionName,
LPCSTR pProfile, DWORD Flags, LPD3DXBUFFER* ppShader,
LPD3DXBUFFER* ppErrorMsgs, LPD3DXCONSTANTTABLE* ppConstantTable)
{
// wondering what I'm doing here?
// see comment in CD3D9ShaderMaterialRenderer::stubD3DXAssembleShader()
#if ( D3DX_SDK_VERSION < 24 )
// directly link functions, old d3d sdks didn't try to load external dlls
// when linking to the d3dx9.lib
#ifdef _MSC_VER
#pragma comment (lib, "d3dx9.lib")
#endif
// invoke static linked function
return D3DXCompileShader(pSrcData, SrcDataLen, pDefines, pInclude, pFunctionName, pProfile, Flags, ppShader, ppErrorMsgs, ppConstantTable);
#else
{
// try to load shader functions from the dll and print error if failed.
// D3DXCompileShader
typedef HRESULT (WINAPI *D3DXCompileShaderFunction)(LPCSTR pSrcData, UINT SrcDataLen, CONST D3DXMACRO* pDefines,
LPD3DXINCLUDE pInclude, LPCSTR pFunctionName,
LPCSTR pProfile, DWORD Flags, LPD3DXBUFFER* ppShader,
LPD3DXBUFFER* ppErrorMsgs, LPD3DXCONSTANTTABLE* ppConstantTable);
static bool LoadFailed = false;
static D3DXCompileShaderFunction pFn = 0;
if (!pFn && !LoadFailed)
{
// try to load dll
io::path strDllName = "d3dx9_";
strDllName += (int)D3DX_SDK_VERSION;
strDllName += ".dll";
HMODULE hMod = LoadLibrary(strDllName.c_str());
if (hMod)
pFn = (D3DXCompileShaderFunction)GetProcAddress(hMod, "D3DXCompileShader");
if (!pFn)
{
LoadFailed = true;
os::Printer::log("Could not load shader function D3DXCompileShader from dll, shaders disabled",
strDllName.c_str(), ELL_ERROR);
}
}
if (pFn)
{
// call already loaded function
return (*pFn)(pSrcData, SrcDataLen, pDefines, pInclude, pFunctionName, pProfile, Flags, ppShader, ppErrorMsgs, ppConstantTable);
}
}
#endif // D3DX_SDK_VERSION < 24
return 0;
}
HRESULT CD3D9ShaderMaterialRenderer::stubD3DXCompileShaderFromFile(LPCSTR pSrcFile, CONST D3DXMACRO* pDefines,
LPD3DXINCLUDE pInclude, LPCSTR pFunctionName,
LPCSTR pProfile, DWORD Flags, LPD3DXBUFFER* ppShader, LPD3DXBUFFER* ppErrorMsgs,
LPD3DXCONSTANTTABLE* ppConstantTable)
{
// wondering what I'm doing here?
// see comment in CD3D9ShaderMaterialRenderer::stubD3DXAssembleShader()
#if ( D3DX_SDK_VERSION < 24 )
// directly link functions, old d3d sdks didn't try to load external dlls
// when linking to the d3dx9.lib
#ifdef _MSC_VER
#pragma comment (lib, "d3dx9.lib")
#endif
// invoke static linked function
return D3DXCompileShaderFromFileA(pSrcFile, pDefines, pInclude, pFunctionName, pProfile, Flags, ppShader, ppErrorMsgs, ppConstantTable);
#else
{
// try to load shader functions from the dll and print error if failed.
// D3DXCompileShaderFromFileA
typedef HRESULT (WINAPI *D3DXCompileShaderFromFileFunction)(LPCSTR pSrcFile,
CONST D3DXMACRO* pDefines, LPD3DXINCLUDE pInclude, LPCSTR pFunctionName,
LPCSTR pProfile, DWORD Flags, LPD3DXBUFFER* ppShader, LPD3DXBUFFER* ppErrorMsgs,
LPD3DXCONSTANTTABLE* ppConstantTable);
static bool LoadFailed = false;
static D3DXCompileShaderFromFileFunction pFn = 0;
if (!pFn && !LoadFailed)
{
// try to load dll
io::path strDllName = "d3dx9_";
strDllName += (int)D3DX_SDK_VERSION;
strDllName += ".dll";
HMODULE hMod = LoadLibrary(strDllName.c_str());
if (hMod)
pFn = (D3DXCompileShaderFromFileFunction)GetProcAddress(hMod, "D3DXCompileShaderFromFileA");
if (!pFn)
{
LoadFailed = true;
os::Printer::log("Could not load shader function D3DXCompileShaderFromFileA from dll, shaders disabled",
strDllName.c_str(), ELL_ERROR);
}
}
if (pFn)
{
// call already loaded function
return (*pFn)(pSrcFile, pDefines, pInclude, pFunctionName, pProfile, Flags, ppShader, ppErrorMsgs, ppConstantTable);
}
}
#endif // D3DX_SDK_VERSION < 24
return 0;
}
} // end namespace video
} // end namespace irr
#endif // _IRR_COMPILE_WITH_DIRECT3D_9_

View File

@ -0,0 +1,108 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_D3D9_SHADER_MATERIAL_RENDERER_H_INCLUDED__
#define __C_D3D9_SHADER_MATERIAL_RENDERER_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_WINDOWS_
#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
#if defined(__BORLANDC__) || defined (__BCPLUSPLUS__)
#include "irrMath.h" // needed by borland for sqrtf define
#endif
#include <d3dx9shader.h>
#include "IMaterialRenderer.h"
namespace irr
{
namespace video
{
class IVideoDriver;
class IShaderConstantSetCallBack;
class IMaterialRenderer;
//! Class for using vertex and pixel shaders with D3D9
class CD3D9ShaderMaterialRenderer : public IMaterialRenderer
{
public:
//! Public constructor
CD3D9ShaderMaterialRenderer(IDirect3DDevice9* d3ddev, video::IVideoDriver* driver,
s32& outMaterialTypeNr, const c8* vertexShaderProgram, const c8* pixelShaderProgram,
IShaderConstantSetCallBack* callback, IMaterialRenderer* baseMaterial, s32 userData);
//! Destructor
~CD3D9ShaderMaterialRenderer();
virtual void OnSetMaterial(const video::SMaterial& material, const video::SMaterial& lastMaterial,
bool resetAllRenderstates, video::IMaterialRendererServices* services) _IRR_OVERRIDE_;
virtual void OnUnsetMaterial() _IRR_OVERRIDE_;
virtual bool OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype) _IRR_OVERRIDE_;
//! Returns if the material is transparent.
virtual bool isTransparent() const _IRR_OVERRIDE_;
//! Access the callback provided by the users when creating shader materials
virtual IShaderConstantSetCallBack* getShaderConstantSetCallBack() const _IRR_OVERRIDE_
{
return CallBack;
}
protected:
//! constructor only for use by derived classes who want to
//! create a fall back material for example.
CD3D9ShaderMaterialRenderer(IDirect3DDevice9* d3ddev,
video::IVideoDriver* driver,
IShaderConstantSetCallBack* callback,
IMaterialRenderer* baseMaterial,
s32 userData=0);
void init(s32& outMaterialTypeNr, const c8* vertexShaderProgram, const c8* pixelShaderProgram);
bool createPixelShader(const c8* pxsh);
bool createVertexShader(const char* vtxsh);
HRESULT stubD3DXAssembleShader(LPCSTR pSrcData, UINT SrcDataLen,
CONST D3DXMACRO* pDefines, LPD3DXINCLUDE pInclude,
DWORD Flags, LPD3DXBUFFER* ppShader,
LPD3DXBUFFER* ppErrorMsgs);
HRESULT stubD3DXAssembleShaderFromFile(LPCSTR pSrcFile,
CONST D3DXMACRO* pDefines, LPD3DXINCLUDE pInclude, DWORD Flags,
LPD3DXBUFFER* ppShader, LPD3DXBUFFER* ppErrorMsgs);
HRESULT stubD3DXCompileShader(LPCSTR pSrcData, UINT SrcDataLen, CONST D3DXMACRO* pDefines,
LPD3DXINCLUDE pInclude, LPCSTR pFunctionName,
LPCSTR pProfile, DWORD Flags, LPD3DXBUFFER* ppShader,
LPD3DXBUFFER* ppErrorMsgs, LPD3DXCONSTANTTABLE* ppConstantTable);
HRESULT stubD3DXCompileShaderFromFile(LPCSTR pSrcFile, CONST D3DXMACRO* pDefines,
LPD3DXINCLUDE pInclude, LPCSTR pFunctionName,
LPCSTR pProfile, DWORD Flags, LPD3DXBUFFER* ppShader, LPD3DXBUFFER* ppErrorMsgs,
LPD3DXCONSTANTTABLE* ppConstantTable);
IDirect3DDevice9* pID3DDevice;
video::IVideoDriver* Driver;
IShaderConstantSetCallBack* CallBack;
IMaterialRenderer* BaseMaterial;
IDirect3DVertexShader9* VertexShader;
IDirect3DVertexShader9* OldVertexShader;
IDirect3DPixelShader9* PixelShader;
s32 UserData;
};
} // end namespace video
} // end namespace irr
#endif
#endif
#endif

View File

@ -0,0 +1,758 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
#include "CD3D9Texture.h"
#include "CD3D9Driver.h"
#include "os.h"
namespace irr
{
namespace video
{
CD3D9Texture::CD3D9Texture(const io::path& name, const core::array<IImage*>& image, E_TEXTURE_TYPE type, CD3D9Driver* driver)
: ITexture(name, type), Driver(driver), InternalFormat(D3DFMT_UNKNOWN), LockReadOnly(false), LockData(0), LockLayer(0),
MipLevelLocked(0), HardwareMipMaps(false), Device(0), Texture(0), CubeTexture(0), RTTSurface(0)
{
#ifdef _DEBUG
setDebugName("CD3D9Texture");
#endif
_IRR_DEBUG_BREAK_IF(image.size() == 0)
Device=driver->getExposedVideoData().D3D9.D3DDev9;
if (Device)
Device->AddRef();
DriverType = Driver->getDriverType();
HasMipMaps = Driver->getTextureCreationFlag(ETCF_CREATE_MIP_MAPS);
HardwareMipMaps = Driver->getTextureCreationFlag(ETCF_AUTO_GENERATE_MIP_MAPS) && Driver->queryFeature(EVDF_MIP_MAP_AUTO_UPDATE);
getImageValues(image[0]);
DWORD flags = 0;
if (HasMipMaps && HardwareMipMaps)
{
LPDIRECT3D9 intf = Driver->getExposedVideoData().D3D9.D3D9;
D3DDISPLAYMODE d3ddm;
intf->GetAdapterDisplayMode(Driver->Params.DisplayAdapter, &d3ddm);
if (D3D_OK == intf->CheckDeviceFormat(Driver->Params.DisplayAdapter, D3DDEVTYPE_HAL, d3ddm.Format, D3DUSAGE_AUTOGENMIPMAP, D3DRTYPE_TEXTURE, InternalFormat))
flags = D3DUSAGE_AUTOGENMIPMAP;
else
HardwareMipMaps = false;
}
HRESULT hr = 0;
switch (Type)
{
case ETT_2D:
hr = Device->CreateTexture(Size.Width, Size.Height, HasMipMaps ? 0 : 1, flags, InternalFormat, D3DPOOL_MANAGED, &Texture, NULL);
break;
case ETT_CUBEMAP:
hr = Device->CreateCubeTexture(Size.Width, HasMipMaps ? 0 : 1, flags, InternalFormat, D3DPOOL_MANAGED, &CubeTexture, NULL);
break;
default:
_IRR_DEBUG_BREAK_IF(true)
break;
}
if (FAILED(hr))
{
// Try again with 16-bit format
if (InternalFormat == D3DFMT_A8R8G8B8)
{
InternalFormat = D3DFMT_A1R5G5B5;
ColorFormat = ECF_A1R5G5B5;
}
else if (InternalFormat == D3DFMT_R8G8B8) // (24 bit is usually failing in d3d9, not sure if it's ever supported)
{
InternalFormat = D3DFMT_R5G6B5;
ColorFormat = ECF_R5G6B5;
}
switch (Type)
{
case ETT_2D:
hr = Device->CreateTexture(Size.Width, Size.Height, HasMipMaps ? 0 : 1, flags, InternalFormat, D3DPOOL_MANAGED, &Texture, NULL);
break;
case ETT_CUBEMAP:
hr = Device->CreateCubeTexture(Size.Width, HasMipMaps ? 0 : 1, flags, InternalFormat, D3DPOOL_MANAGED, &CubeTexture, NULL);
break;
}
}
core::array<IImage*> tmpImage = image;
bool releaseImageData = false;
if (SUCCEEDED(hr))
{
if (OriginalSize != Size || OriginalColorFormat != ColorFormat)
{
releaseImageData = true;
for (u32 i = 0; i < image.size(); ++i)
{
tmpImage[i] = Driver->createImage(ColorFormat, Size);
if (image[i]->getDimension() == Size)
image[i]->copyTo(tmpImage[i]);
else
image[i]->copyToScaling(tmpImage[i]);
}
}
for (u32 i = 0; i < tmpImage.size(); ++i)
uploadTexture(tmpImage[i]->getData(), 0, i);
bool autoGenerateRequired = true;
for (u32 i = 0; i < tmpImage.size(); ++i)
{
void* mipmapsData = tmpImage[i]->getMipMapsData();
if (autoGenerateRequired || mipmapsData)
regenerateMipMapLevels(mipmapsData, i);
if (!mipmapsData)
autoGenerateRequired = false;
}
}
else
{
switch (hr )
{
case D3DERR_INVALIDCALL:
os::Printer::log("Could not create DIRECT3D9 Texture. D3DERR_INVALIDCALL", ELL_WARNING);
break;
case D3DERR_OUTOFVIDEOMEMORY:
os::Printer::log("Could not create DIRECT3D9 Texture. D3DERR_OUTOFVIDEOMEMORY", ELL_WARNING);
break;
case E_OUTOFMEMORY:
os::Printer::log("Could not create DIRECT3D9 Texture. E_OUTOFMEMORY", ELL_WARNING);
break;
default:
os::Printer::log("Could not create DIRECT3D9 Texture.", ELL_WARNING);
}
}
if (releaseImageData)
{
for (u32 i = 0; i < tmpImage.size(); ++i)
tmpImage[i]->drop();
}
}
CD3D9Texture::CD3D9Texture(CD3D9Driver* driver, const core::dimension2d<u32>& size, const io::path& name, E_TEXTURE_TYPE type, const ECOLOR_FORMAT format)
: ITexture(name, type), Driver(driver), InternalFormat(D3DFMT_UNKNOWN), LockReadOnly(false), LockData(0), LockLayer(0),
MipLevelLocked(0), HardwareMipMaps(false), Device(0), Texture(0), CubeTexture(0), RTTSurface(0)
{
#ifdef _DEBUG
setDebugName("CD3D9Texture");
#endif
Device = driver->getExposedVideoData().D3D9.D3DDev9;
if (Device)
Device->AddRef();
DriverType = Driver->getDriverType();
HasMipMaps = false;
IsRenderTarget = true;
OriginalColorFormat = format;
if (ECF_UNKNOWN == OriginalColorFormat)
ColorFormat = getBestColorFormat(Driver->getColorFormat());
else
ColorFormat = OriginalColorFormat;
OriginalSize = size;
Size = OriginalSize;
if (!Driver->queryFeature(EVDF_TEXTURE_NPOT))
{
Size = Size.getOptimalSize(true, !Driver->queryFeature(EVDF_TEXTURE_NSQUARE), true, Driver->Caps.MaxTextureWidth);
if (Size != OriginalSize)
os::Printer::log("RenderTarget size has to be a power of two", ELL_INFORMATION);
}
Pitch = Size.Width * IImage::getBitsPerPixelFromFormat(ColorFormat) / 8;
InternalFormat = Driver->getD3DFormatFromColorFormat(ColorFormat);
generateRenderTarget();
}
CD3D9Texture::~CD3D9Texture()
{
releaseTexture();
if (Device)
Device->Release();
}
void* CD3D9Texture::lock(E_TEXTURE_LOCK_MODE mode, u32 mipmapLevel, u32 layer, E_TEXTURE_LOCK_FLAGS lockFlags)
{
if (LockData)
return LockData;
if (IImage::isCompressedFormat(ColorFormat))
return 0;
MipLevelLocked = mipmapLevel;
LockReadOnly = (mode == ETLM_READ_ONLY);
LockLayer = layer;
HRESULT hr;
D3DLOCKED_RECT rect;
if (!IsRenderTarget)
{
if (Texture)
{
hr = Texture->LockRect(MipLevelLocked, &rect, 0, LockReadOnly ? D3DLOCK_READONLY : 0);
}
else if (CubeTexture)
{
_IRR_DEBUG_BREAK_IF(layer > 5)
hr = CubeTexture->LockRect(static_cast<_D3DCUBEMAP_FACES>(layer), MipLevelLocked, &rect, 0, LockReadOnly ? D3DLOCK_READONLY : 0);
}
else
{
os::Printer::log("Could not lock DIRECT3D9 Texture. Missing internal D3D texture.", ELL_ERROR);
return 0;
}
if (FAILED(hr))
{
os::Printer::log("Could not lock DIRECT3D9 Texture.", ELL_ERROR);
return 0;
}
}
else
{
if (!RTTSurface)
{
// Make RTT surface large enough for all miplevels (including 0)
D3DSURFACE_DESC desc;
if (Texture)
Texture->GetLevelDesc(0, &desc);
else if (CubeTexture)
CubeTexture->GetLevelDesc(0, &desc);
hr = Device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &RTTSurface, 0);
if (FAILED(hr))
{
os::Printer::log("Could not lock DIRECT3D9 Texture", "Offscreen surface creation failed.", ELL_ERROR);
return 0;
}
}
IDirect3DSurface9 *surface = 0;
if (Texture)
hr = Texture->GetSurfaceLevel(MipLevelLocked, &surface);
else if (CubeTexture)
hr = CubeTexture->GetCubeMapSurface(static_cast<_D3DCUBEMAP_FACES>(layer), MipLevelLocked, &surface);
if (FAILED(hr))
{
os::Printer::log("Could not lock DIRECT3D9 Texture", "Could not get surface.", ELL_ERROR);
return 0;
}
hr = Device->GetRenderTargetData(surface, RTTSurface);
surface->Release();
if(FAILED(hr))
{
os::Printer::log("Could not lock DIRECT3D9 Texture", "Data copy failed.", ELL_ERROR);
return 0;
}
hr = RTTSurface->LockRect(&rect, 0, LockReadOnly ? D3DLOCK_READONLY : 0);
if(FAILED(hr))
{
os::Printer::log("Could not lock DIRECT3D9 Texture", "LockRect failed.", ELL_ERROR);
return 0;
}
}
LockData = rect.pBits;
return LockData;
}
void CD3D9Texture::unlock()
{
if (!LockData)
return;
if (!IsRenderTarget)
{
if (Texture)
{
Texture->UnlockRect(MipLevelLocked);
}
else if (CubeTexture)
{
CubeTexture->UnlockRect(static_cast<_D3DCUBEMAP_FACES>(LockLayer), MipLevelLocked);
}
}
else if (RTTSurface)
{
RTTSurface->UnlockRect();
}
LockReadOnly = false;
LockData = 0;
LockLayer = 0;
}
void CD3D9Texture::regenerateMipMapLevels(void* data, u32 layer)
{
if (!HasMipMaps || (Size.Width <= 1 && Size.Height <= 1))
return;
if ( HardwareMipMaps )
{
// Can't update with custom data with those unfortunately
// Also MSDN docs don't mention it, but GenerateMipSubLevels only works when AUTOGENMIPMAP is set.
// So we can't call this to get hardware mipmaps when not setting AUTOGENMIPMAP.
if (Texture)
Texture->GenerateMipSubLevels();
else if (CubeTexture)
CubeTexture->GenerateMipSubLevels();
}
else if (data)
{
u32 width = Size.Width;
u32 height = Size.Height;
u8* tmpData = static_cast<u8*>(data);
u32 dataSize = 0;
u32 level = 0;
do
{
if (width > 1)
width >>= 1;
if (height > 1)
height >>= 1;
dataSize = IImage::getDataSizeFromFormat(ColorFormat, width, height);
++level;
uploadTexture(tmpData, level, layer);
tmpData += dataSize;
} while (width != 1 || height != 1);
}
else
{
createManualMipMaps(1);
}
}
void CD3D9Texture::copy16BitMipMap(char* src, char* tgt,
s32 width, s32 height,
s32 pitchsrc, s32 pitchtgt) const
{
for (s32 y=0; y<height; ++y)
{
for (s32 x=0; x<width; ++x)
{
u32 a=0, r=0, g=0, b=0;
for (s32 dy=0; dy<2; ++dy)
{
const s32 tgy = (y*2)+dy;
for (s32 dx=0; dx<2; ++dx)
{
const s32 tgx = (x*2)+dx;
SColor c;
if (ColorFormat == ECF_A1R5G5B5)
c = A1R5G5B5toA8R8G8B8(*(u16*)(&src[(tgx*2)+(tgy*pitchsrc)]));
else
c = R5G6B5toA8R8G8B8(*(u16*)(&src[(tgx*2)+(tgy*pitchsrc)]));
a += c.getAlpha();
r += c.getRed();
g += c.getGreen();
b += c.getBlue();
}
}
a /= 4;
r /= 4;
g /= 4;
b /= 4;
u16 c;
if (ColorFormat == ECF_A1R5G5B5)
c = RGBA16(r,g,b,a);
else
c = A8R8G8B8toR5G6B5(SColor(a,r,g,b).color);
*(u16*)(&tgt[(x*2)+(y*pitchtgt)]) = c;
}
}
}
void CD3D9Texture::copy32BitMipMap(char* src, char* tgt,
s32 width, s32 height,
s32 pitchsrc, s32 pitchtgt) const
{
for (s32 y=0; y<height; ++y)
{
for (s32 x=0; x<width; ++x)
{
u32 a=0, r=0, g=0, b=0;
SColor c;
for (s32 dy=0; dy<2; ++dy)
{
const s32 tgy = (y*2)+dy;
for (s32 dx=0; dx<2; ++dx)
{
const s32 tgx = (x*2)+dx;
c = *(u32*)(&src[(tgx*4)+(tgy*pitchsrc)]);
a += c.getAlpha();
r += c.getRed();
g += c.getGreen();
b += c.getBlue();
}
}
a /= 4;
r /= 4;
g /= 4;
b /= 4;
c.set(a, r, g, b);
*(u32*)(&tgt[(x*4)+(y*pitchtgt)]) = c.color;
}
}
}
bool CD3D9Texture::createManualMipMaps(u32 level)
{
if (level==0)
return true;
if (!Texture) //Manual mips for CubeTexture not supported yet
{
return true;
}
// manual mipmap generation
IDirect3DSurface9* upperSurface = 0;
IDirect3DSurface9* lowerSurface = 0;
// get upper level
HRESULT hr = Texture->GetSurfaceLevel(level-1, &upperSurface);
if (FAILED(hr) || !upperSurface)
{
os::Printer::log("Could not get upper surface level for mip map generation", ELL_WARNING);
return false;
}
// get lower level
hr = Texture->GetSurfaceLevel(level, &lowerSurface);
if (FAILED(hr) || !lowerSurface)
{
os::Printer::log("Could not get lower surface level for mip map generation", ELL_WARNING);
upperSurface->Release();
return false;
}
D3DSURFACE_DESC upperDesc, lowerDesc;
upperSurface->GetDesc(&upperDesc);
lowerSurface->GetDesc(&lowerDesc);
D3DLOCKED_RECT upperlr;
D3DLOCKED_RECT lowerlr;
// lock upper surface
if (FAILED(upperSurface->LockRect(&upperlr, NULL, 0)))
{
upperSurface->Release();
lowerSurface->Release();
os::Printer::log("Could not lock upper texture for mip map generation", ELL_WARNING);
return false;
}
// lock lower surface
if (FAILED(lowerSurface->LockRect(&lowerlr, NULL, 0)))
{
upperSurface->UnlockRect();
upperSurface->Release();
lowerSurface->Release();
os::Printer::log("Could not lock lower texture for mip map generation", ELL_WARNING);
return false;
}
if (upperDesc.Format != lowerDesc.Format)
{
os::Printer::log("Cannot copy mip maps with different formats.", ELL_WARNING);
}
else
{
if ((upperDesc.Format == D3DFMT_A1R5G5B5) || (upperDesc.Format == D3DFMT_R5G6B5))
copy16BitMipMap((char*)upperlr.pBits, (char*)lowerlr.pBits,
lowerDesc.Width, lowerDesc.Height,
upperlr.Pitch, lowerlr.Pitch);
else
if (upperDesc.Format == D3DFMT_A8R8G8B8)
copy32BitMipMap((char*)upperlr.pBits, (char*)lowerlr.pBits,
lowerDesc.Width, lowerDesc.Height,
upperlr.Pitch, lowerlr.Pitch);
else
os::Printer::log("Unsupported mipmap format, cannot copy.", ELL_WARNING);
}
bool result=true;
// unlock
if (FAILED(upperSurface->UnlockRect()))
result=false;
if (FAILED(lowerSurface->UnlockRect()))
result=false;
// release
upperSurface->Release();
lowerSurface->Release();
if (!result || (upperDesc.Width <= 3 && upperDesc.Height <= 3))
return result; // stop generating levels
// generate next level
return createManualMipMaps(level+1);
}
IDirect3DBaseTexture9* CD3D9Texture::getDX9BaseTexture() const
{
return (Texture) ? static_cast<IDirect3DBaseTexture9*>(Texture) : static_cast<IDirect3DBaseTexture9*>(CubeTexture);
}
IDirect3DTexture9* CD3D9Texture::getDX9Texture() const
{
return Texture;
}
IDirect3DCubeTexture9* CD3D9Texture::getDX9CubeTexture() const
{
return CubeTexture;
}
void CD3D9Texture::releaseTexture()
{
if (RTTSurface)
{
if (RTTSurface->Release() == 0)
RTTSurface = 0;
}
if (Texture)
{
if (Texture->Release() == 0)
Texture = 0;
}
if (CubeTexture)
{
if (CubeTexture->Release() == 0)
CubeTexture = 0;
}
}
void CD3D9Texture::generateRenderTarget()
{
DWORD flags = (IImage::isDepthFormat(ColorFormat)) ? D3DUSAGE_DEPTHSTENCIL : D3DUSAGE_RENDERTARGET;
HRESULT hr = 0;
switch (Type)
{
case ETT_2D:
if (!Texture )
hr = Device->CreateTexture(Size.Width, Size.Height, 1, flags, InternalFormat, D3DPOOL_DEFAULT, &Texture, NULL);
break;
case ETT_CUBEMAP:
if (!CubeTexture)
hr = Device->CreateCubeTexture(Size.Width, 1, flags, InternalFormat, D3DPOOL_DEFAULT, &CubeTexture, NULL);
break;
default:
_IRR_DEBUG_BREAK_IF(true)
break;
}
if (FAILED(hr))
{
if (D3DERR_INVALIDCALL == hr)
os::Printer::log("Could not create render target texture", "Invalid Call", irr::ELL_ERROR);
else if (D3DERR_OUTOFVIDEOMEMORY == hr)
os::Printer::log("Could not create render target texture", "Out of Video Memory", irr::ELL_ERROR);
else if (E_OUTOFMEMORY == hr)
os::Printer::log("Could not create render target texture", "Out of Memory", irr::ELL_ERROR);
else
os::Printer::log("Could not create render target texture", irr::ELL_ERROR);
core::stringc params("Width:");
params += (unsigned int)Size.Width;
params += " Height: ";
params += (unsigned int)Size.Height;
params += " flag: ";
params += (unsigned int)flags;
params += " format";
params += (unsigned int)InternalFormat;
params += " Type: ";
params += (unsigned int)Type;
os::Printer::log(params.c_str(), irr::ELL_ERROR);
}
}
ECOLOR_FORMAT CD3D9Texture::getBestColorFormat(ECOLOR_FORMAT format)
{
// We only try for to adapt "simple" formats
ECOLOR_FORMAT destFormat = (format <= ECF_A8R8G8B8) ? ECF_A8R8G8B8 : format;
switch (format)
{
case ECF_A1R5G5B5:
if (!Driver->getTextureCreationFlag(ETCF_ALWAYS_32_BIT))
destFormat = ECF_A1R5G5B5;
break;
case ECF_R5G6B5:
if (!Driver->getTextureCreationFlag(ETCF_ALWAYS_32_BIT))
destFormat = ECF_R5G6B5;
break;
case ECF_A8R8G8B8:
if (Driver->getTextureCreationFlag(ETCF_ALWAYS_16_BIT) ||
Driver->getTextureCreationFlag(ETCF_OPTIMIZED_FOR_SPEED))
destFormat = ECF_A1R5G5B5;
break;
case ECF_R8G8B8:
// Note: Using ECF_A8R8G8B8 even when ETCF_ALWAYS_32_BIT is not set as 24 bit textures fail with too many cards
if (Driver->getTextureCreationFlag(ETCF_ALWAYS_16_BIT) || Driver->getTextureCreationFlag(ETCF_OPTIMIZED_FOR_SPEED))
destFormat = ECF_A1R5G5B5;
default:
break;
}
if (Driver->getTextureCreationFlag(ETCF_NO_ALPHA_CHANNEL))
{
switch (destFormat)
{
case ECF_A1R5G5B5:
destFormat = ECF_R5G6B5;
break;
case ECF_A8R8G8B8:
destFormat = ECF_R8G8B8;
break;
default:
break;
}
}
return destFormat;
}
void CD3D9Texture::getImageValues(const IImage* image)
{
OriginalColorFormat = image->getColorFormat();
ColorFormat = getBestColorFormat(OriginalColorFormat);
InternalFormat = Driver->getD3DFormatFromColorFormat(ColorFormat);
if (IImage::isCompressedFormat(image->getColorFormat()))
{
HardwareMipMaps = false;
}
OriginalSize = image->getDimension();
Size = OriginalSize;
if (Size.Width == 0 || Size.Height == 0)
{
os::Printer::log("Invalid size of image for texture.", ELL_ERROR);
return;
}
const f32 ratio = (f32)Size.Width / (f32)Size.Height;
if ((Size.Width > Driver->Caps.MaxTextureWidth) && (ratio >= 1.f))
{
Size.Width = Driver->Caps.MaxTextureWidth;
Size.Height = (u32)(Driver->Caps.MaxTextureWidth / ratio);
}
else if (Size.Height > Driver->Caps.MaxTextureHeight)
{
Size.Height = Driver->Caps.MaxTextureHeight;
Size.Width = (u32)(Driver->Caps.MaxTextureHeight * ratio);
}
bool needSquare = (!Driver->queryFeature(EVDF_TEXTURE_NSQUARE) || Type == ETT_CUBEMAP);
Size = Size.getOptimalSize(!Driver->queryFeature(EVDF_TEXTURE_NPOT), needSquare, true, Driver->Caps.MaxTextureWidth);
Pitch = Size.Width * IImage::getBitsPerPixelFromFormat(ColorFormat) / 8;
}
void CD3D9Texture::uploadTexture(void* data, u32 mipmapLevel, u32 layer)
{
if (!data)
return;
u32 width = Size.Width >> mipmapLevel;
u32 height = Size.Height >> mipmapLevel;
u32 dataSize = IImage::getDataSizeFromFormat(ColorFormat, width, height);
HRESULT hr = 0;
D3DLOCKED_RECT lockRectangle;
if (Texture)
{
hr = Texture->LockRect(mipmapLevel, &lockRectangle, 0, 0);
}
else if (CubeTexture)
{
_IRR_DEBUG_BREAK_IF(layer > 5)
hr = CubeTexture->LockRect(static_cast<_D3DCUBEMAP_FACES>(layer), mipmapLevel, &lockRectangle, 0, 0);
}
if (FAILED(hr))
{
os::Printer::log("Texture data not copied", "Could not LockRect D3D9 Texture.", ELL_ERROR);
return;
}
memcpy(lockRectangle.pBits, data, dataSize);
if (Texture)
{
hr = Texture->UnlockRect(mipmapLevel);
}
else if (CubeTexture)
{
hr = CubeTexture->UnlockRect(static_cast<_D3DCUBEMAP_FACES>(layer), mipmapLevel);
}
if (FAILED(hr))
{
os::Printer::log("Texture data not copied", "Could not UnlockRect D3D9 Texture.", ELL_ERROR);
}
}
}
}
#endif

View File

@ -0,0 +1,91 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_DIRECTX9_TEXTURE_H_INCLUDED__
#define __C_DIRECTX9_TEXTURE_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
#include "irrArray.h"
#include "ITexture.h"
#include "IImage.h"
#if defined(__BORLANDC__) || defined (__BCPLUSPLUS__)
#include "irrMath.h" // needed by borland for sqrtf define
#endif
#include <d3d9.h>
namespace irr
{
namespace video
{
class CD3D9Driver;
class CD3D9Texture : public ITexture
{
public:
CD3D9Texture(const io::path& name, const core::array<IImage*>& image, E_TEXTURE_TYPE type, CD3D9Driver* driver);
CD3D9Texture(CD3D9Driver* driver, const core::dimension2d<u32>& size, const io::path& name, E_TEXTURE_TYPE type, const ECOLOR_FORMAT format = ECF_UNKNOWN);
virtual ~CD3D9Texture();
virtual void* lock(E_TEXTURE_LOCK_MODE mode = ETLM_READ_WRITE, u32 mipmapLevel=0, u32 layer = 0, E_TEXTURE_LOCK_FLAGS lockFlags = ETLF_FLIP_Y_UP_RTT) _IRR_OVERRIDE_;
virtual void unlock() _IRR_OVERRIDE_;
virtual void regenerateMipMapLevels(void* data = 0, u32 layer = 0) _IRR_OVERRIDE_;
IDirect3DBaseTexture9* getDX9BaseTexture() const;
IDirect3DTexture9* getDX9Texture() const;
IDirect3DCubeTexture9* getDX9CubeTexture() const;
private:
friend class CD3D9Driver;
void releaseTexture();
void generateRenderTarget();
ECOLOR_FORMAT getBestColorFormat(ECOLOR_FORMAT format);
void getImageValues(const IImage* image);
void uploadTexture(void* data, u32 mipmapLevel, u32 layer);
//! Helper function for mipmap generation.
bool createManualMipMaps(u32 level);
//! Helper function for mipmap generation.
void copy16BitMipMap(char* src, char* tgt,
s32 width, s32 height, s32 pitchsrc, s32 pitchtgt) const;
//! Helper function for mipmap generation.
void copy32BitMipMap(char* src, char* tgt,
s32 width, s32 height, s32 pitchsrc, s32 pitchtgt) const;
CD3D9Driver* Driver;
D3DFORMAT InternalFormat;
bool LockReadOnly;
void* LockData;
u32 LockLayer;
u32 MipLevelLocked;
bool HardwareMipMaps;
IDirect3DDevice9* Device;
IDirect3DTexture9* Texture;
IDirect3DCubeTexture9* CubeTexture;
IDirect3DSurface9* RTTSurface;
};
}
}
#endif
#endif

View File

@ -0,0 +1,431 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
//
// This file was originally written by Salvatore Russo.
// I (Nikolaus Gebhardt) did some minor modifications and changes to it and
// integrated it into Irrlicht.
// Thanks a lot to Salvatore for his work on this and that he gave me
// his permission to add it into Irrlicht using the zlib license.
/*
CDMFLoader by Salvatore Russo (September 2005)
See the header file for additional information including use and distribution rights.
*/
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_DMF_LOADER_
#ifdef _DEBUG
#define _IRR_DMF_DEBUG_
#include "os.h"
#endif
#include "CDMFLoader.h"
#include "CMeshTextureLoader.h"
#include "ISceneManager.h"
#include "IAttributes.h"
#include "SAnimatedMesh.h"
#include "SSkinMeshBuffer.h"
#include "irrString.h"
#include "irrMath.h"
#include "dmfsupport.h"
namespace irr
{
namespace scene
{
/** Constructor*/
CDMFLoader::CDMFLoader(ISceneManager* smgr, io::IFileSystem* filesys)
: SceneMgr(smgr), FileSystem(filesys)
{
#ifdef _DEBUG
IReferenceCounted::setDebugName("CDMFLoader");
#endif
TextureLoader = new CMeshTextureLoader( FileSystem, SceneMgr->getVideoDriver() );
}
void CDMFLoader::addMaterialPath(core::stringc& filename, const core::stringc& matPath)
{
c8 last = matPath.lastChar();
if ( last == '/' || last == '\\' )
filename = matPath+filename;
else
{
core::stringc matPathSlash(matPath);
matPathSlash.append('/');
filename = matPathSlash+filename;
}
}
/**Creates/loads an animated mesh from the file.
\return Pointer to the created mesh. Returns 0 if loading failed.
If you no longer need the mesh, you should call IAnimatedMesh::drop().
See IReferenceCounted::drop() for more information.*/
IAnimatedMesh* CDMFLoader::createMesh(io::IReadFile* file)
{
if (!file)
return 0;
if ( getMeshTextureLoader() )
{
getMeshTextureLoader()->setMeshFile(file);
if ( SceneMgr->getParameters()->existsAttribute(DMF_TEXTURE_PATH) )
getMeshTextureLoader()->setTexturePath( SceneMgr->getParameters()->getAttributeAsString(DMF_TEXTURE_PATH) );
}
video::IVideoDriver* driver = SceneMgr->getVideoDriver();
//Load stringlist
StringList dmfRawFile;
LoadFromFile(file, dmfRawFile);
if (dmfRawFile.size()==0)
return 0;
SMesh * mesh = new SMesh();
u32 i;
dmfHeader header;
//load header
core::array<dmfMaterial> materiali;
if (GetDMFHeader(dmfRawFile, header))
{
//let's set ambient light
SceneMgr->setAmbientLight(header.dmfAmbient);
//let's create the correct number of materials, vertices and faces
dmfVert *verts=new dmfVert[header.numVertices];
dmfFace *faces=new dmfFace[header.numFaces];
//let's get the materials
#ifdef _IRR_DMF_DEBUG_
os::Printer::log("Loading materials", core::stringc(header.numMaterials).c_str());
#endif
GetDMFMaterials(dmfRawFile, materiali, header.numMaterials);
//let's get vertices and faces
#ifdef _IRR_DMF_DEBUG_
os::Printer::log("Loading geometry");
#endif
GetDMFVerticesFaces(dmfRawFile, verts, faces);
//create a meshbuffer for each material, then we'll remove empty ones
#ifdef _IRR_DMF_DEBUG_
os::Printer::log("Creating meshbuffers.");
#endif
for (i=0; i<header.numMaterials; i++)
{
//create a new SMeshBufferLightMap for each material
SSkinMeshBuffer* buffer = new SSkinMeshBuffer();
buffer->Material.MaterialType = video::EMT_LIGHTMAP_LIGHTING;
buffer->Material.Wireframe = false;
buffer->Material.Lighting = true;
mesh->addMeshBuffer(buffer);
buffer->drop();
}
// Build the mesh buffers
#ifdef _IRR_DMF_DEBUG_
os::Printer::log("Adding geometry to mesh.");
#endif
for (i = 0; i < header.numFaces; i++)
{
#ifdef _IRR_DMF_DEBUG_
os::Printer::log("Polygon with #vertices", core::stringc(faces[i].numVerts).c_str());
#endif
if (faces[i].numVerts < 3)
continue;
const core::vector3df normal =
core::triangle3df(verts[faces[i].firstVert].pos,
verts[faces[i].firstVert+1].pos,
verts[faces[i].firstVert+2].pos).getNormal().normalize();
SSkinMeshBuffer* meshBuffer = (SSkinMeshBuffer*)mesh->getMeshBuffer(
faces[i].materialID);
const bool use2TCoords = meshBuffer->Vertices_2TCoords.size() ||
materiali[faces[i].materialID].lightmapName.size();
if (use2TCoords && meshBuffer->Vertices_Standard.size())
meshBuffer->convertTo2TCoords();
const u32 base = meshBuffer->Vertices_2TCoords.size()?meshBuffer->Vertices_2TCoords.size():meshBuffer->Vertices_Standard.size();
// Add this face's verts
if (use2TCoords)
{
// make sure we have the proper type set
meshBuffer->VertexType=video::EVT_2TCOORDS;
for (u32 v = 0; v < faces[i].numVerts; v++)
{
const dmfVert& vv = verts[faces[i].firstVert + v];
video::S3DVertex2TCoords vert(vv.pos,
normal, video::SColor(255,255,255,255), vv.tc, vv.lc);
if (materiali[faces[i].materialID].textureBlend==4 &&
SceneMgr->getParameters()->getAttributeAsBool(DMF_FLIP_ALPHA_TEXTURES))
{
vert.TCoords.set(vv.tc.X,-vv.tc.Y);
}
meshBuffer->Vertices_2TCoords.push_back(vert);
}
}
else
{
for (u32 v = 0; v < faces[i].numVerts; v++)
{
const dmfVert& vv = verts[faces[i].firstVert + v];
video::S3DVertex vert(vv.pos,
normal, video::SColor(255,255,255,255), vv.tc);
if (materiali[faces[i].materialID].textureBlend==4 &&
SceneMgr->getParameters()->getAttributeAsBool(DMF_FLIP_ALPHA_TEXTURES))
{
vert.TCoords.set(vv.tc.X,-vv.tc.Y);
}
meshBuffer->Vertices_Standard.push_back(vert);
}
}
// Now add the indices
// This weird loop turns convex polygons into triangle strips.
// I do it this way instead of a simple fan because it usually
// looks a lot better in wireframe, for example.
u32 h = faces[i].numVerts - 1, l = 0, c; // High, Low, Center
for (u32 v = 0; v < faces[i].numVerts - 2; v++)
{
if (v & 1) // odd
c = h - 1;
else // even
c = l + 1;
meshBuffer->Indices.push_back(base + h);
meshBuffer->Indices.push_back(base + l);
meshBuffer->Indices.push_back(base + c);
if (v & 1) // odd
h--;
else // even
l++;
}
}
delete [] verts;
delete [] faces;
}
// delete all buffers without geometry in it.
#ifdef _IRR_DMF_DEBUG_
os::Printer::log("Cleaning meshbuffers.");
#endif
i = 0;
while(i < mesh->MeshBuffers.size())
{
if (mesh->MeshBuffers[i]->getVertexCount() == 0 ||
mesh->MeshBuffers[i]->getIndexCount() == 0)
{
// Meshbuffer is empty -- drop it
mesh->MeshBuffers[i]->drop();
mesh->MeshBuffers.erase(i);
materiali.erase(i);
}
else
{
i++;
}
}
{
//load textures and lightmaps in materials.
//don't worry if you receive a could not load texture, cause if you don't need
//a particular material in your scene it will be loaded and then destroyed.
#ifdef _IRR_DMF_DEBUG_
os::Printer::log("Loading textures.");
#endif
const bool use_mat_dirs=!SceneMgr->getParameters()->getAttributeAsBool(DMF_IGNORE_MATERIALS_DIRS);
for (i=0; i<mesh->getMeshBufferCount(); i++)
{
//texture and lightmap
video::ITexture *tex = 0;
video::ITexture *lig = 0;
//current buffer to apply material
video::SMaterial& mat = mesh->getMeshBuffer(i)->getMaterial();
//Primary texture is normal
if (materiali[i].textureFlag==0)
{
if (materiali[i].textureBlend==4)
driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT,true);
if ( use_mat_dirs )
addMaterialPath(materiali[i].textureName, materiali[i].pathName);
tex = getMeshTextureLoader() ? getMeshTextureLoader()->getTexture( materiali[i].textureName ) : NULL;
}
//Primary texture is just a color
else if(materiali[i].textureFlag==1)
{
video::SColor color(axtoi(materiali[i].textureName.c_str()));
//just for compatibility with older Irrlicht versions
//to support transparent materials
if (color.getAlpha()!=255 && materiali[i].textureBlend==4)
driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT,true);
video::IImage *immagine= driver->createImage(video::ECF_A8R8G8B8,
core::dimension2d<u32>(8,8));
immagine->fill(color);
tex = driver->addTexture("", immagine);
immagine->drop();
//to support transparent materials
if (color.getAlpha()!=255 && materiali[i].textureBlend==4)
{
mat.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
mat.MaterialTypeParam =(((f32) (color.getAlpha()-1))/255.0f);
}
}
//Lightmap is present
if (materiali[i].lightmapFlag == 0)
{
if ( use_mat_dirs )
addMaterialPath(materiali[i].lightmapName, materiali[i].pathName);
lig = getMeshTextureLoader() ? getMeshTextureLoader()->getTexture(materiali[i].lightmapName) : NULL;
}
else //no lightmap
{
mat.MaterialType = video::EMT_SOLID;
const f32 mult = 100.0f - header.dmfShadow;
mat.AmbientColor=header.dmfAmbient.getInterpolated(video::SColor(255,0,0,0),mult/100.f);
}
if (materiali[i].textureBlend==4)
{
mat.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
mat.MaterialTypeParam =
SceneMgr->getParameters()->getAttributeAsFloat(DMF_ALPHA_CHANNEL_REF);
}
//if texture is present mirror vertically owing to DeleD representation
if (tex && header.dmfVersion<1.1)
{
const core::dimension2d<u32> texsize = tex->getSize();
void* pp = tex->lock();
if (pp)
{
const video::ECOLOR_FORMAT format = tex->getColorFormat();
if (format == video::ECF_A1R5G5B5)
{
s16* p = (s16*)pp;
s16 tmp=0;
for (u32 x=0; x<texsize.Width; x++)
for (u32 y=0; y<texsize.Height/2; y++)
{
tmp=p[y*texsize.Width + x];
p[y*texsize.Width + x] = p[(texsize.Height-y-1)*texsize.Width + x];
p[(texsize.Height-y-1)*texsize.Width + x]=tmp;
}
}
else
if (format == video::ECF_A8R8G8B8)
{
s32* p = (s32*)pp;
s32 tmp=0;
for (u32 x=0; x<texsize.Width; x++)
for (u32 y=0; y<texsize.Height/2; y++)
{
tmp=p[y*texsize.Width + x];
p[y*texsize.Width + x] = p[(texsize.Height-y-1)*texsize.Width + x];
p[(texsize.Height-y-1)*texsize.Width + x]=tmp;
}
}
}
tex->unlock();
tex->regenerateMipMapLevels();
}
//if lightmap is present mirror vertically owing to DeleD rapresentation
if (lig && header.dmfVersion<1.1)
{
const core::dimension2d<u32> ligsize=lig->getSize();
void* pp = lig->lock();
if (pp)
{
video::ECOLOR_FORMAT format = lig->getColorFormat();
if (format == video::ECF_A1R5G5B5)
{
s16* p = (s16*)pp;
s16 tmp=0;
for (u32 x=0; x<ligsize.Width; x++)
{
for (u32 y=0; y<ligsize.Height/2; y++)
{
tmp=p[y*ligsize.Width + x];
p[y*ligsize.Width + x] = p[(ligsize.Height-y-1)*ligsize.Width + x];
p[(ligsize.Height-y-1)*ligsize.Width + x]=tmp;
}
}
}
else if (format == video::ECF_A8R8G8B8)
{
s32* p = (s32*)pp;
s32 tmp=0;
for (u32 x=0; x<ligsize.Width; x++)
{
for (u32 y=0; y<ligsize.Height/2; y++)
{
tmp=p[y*ligsize.Width + x];
p[y*ligsize.Width + x] = p[(ligsize.Height-y-1)*ligsize.Width + x];
p[(ligsize.Height-y-1)*ligsize.Width + x]=tmp;
}
}
}
}
lig->unlock();
lig->regenerateMipMapLevels();
}
mat.setTexture(0, tex);
mat.setTexture(1, lig);
}
}
// create bounding box
for (i = 0; i < mesh->MeshBuffers.size(); ++i)
{
mesh->MeshBuffers[i]->recalculateBoundingBox();
}
mesh->recalculateBoundingBox();
// Set up an animated mesh to hold the mesh
SAnimatedMesh* AMesh = new SAnimatedMesh();
AMesh->Type = EAMT_UNKNOWN;
AMesh->addMesh(mesh);
AMesh->recalculateBoundingBox();
mesh->drop();
return AMesh;
}
/** \brief Tell us if this file is able to be loaded by this class
based on the file extension (e.g. ".bsp")
\return true if file is loadable.*/
bool CDMFLoader::isALoadableFileExtension(const io::path& filename) const
{
return core::hasFileExtension ( filename, "dmf" );
}
} // end namespace scene
} // end namespace irr
#endif // _IRR_COMPILE_WITH_DMF_LOADER_

View File

@ -0,0 +1,91 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
//
// This file was originally written by Salvatore Russo.
// I (Nikolaus Gebhardt) did some minor modifications changes to it and integrated
// it into Irrlicht:
// - removed STL dependency
// - removed log file and replaced it with irrlicht logging
// - adapted code formatting a bit to Irrlicht style
// - removed memory leaks
// Thanks a lot to Salvatore for his work on this and that he gave me
// his permission to add it into Irrlicht.
/*
CDMFLoader by Salvatore Russo
Version 1.3
This loader is used to load DMF files in Irrlicht.
Look at the documentation for a sample application.
Parts of this code are from Murphy McCauley COCTLoader just like
GetFaceNormal() or indexes creation routines and a routine to add faces. So
please refer to COCTLoader.h to know more about rights granted.
You can use this software as you wish but you must not remove these notes about license nor
credits to others for parts of this code.
*/
#ifndef __C_DMF_LOADER_H_INCLUDED__
#define __C_DMF_LOADER_H_INCLUDED__
#include "IMeshLoader.h"
#include "IReadFile.h"
#include "IFileSystem.h"
#include "SMesh.h"
#include "IVideoDriver.h"
#include "ISceneManager.h"
#include "SAnimatedMesh.h"
namespace irr
{
namespace scene
{
/** A class to load DeleD mesh files.*/
class CDMFLoader : public IMeshLoader
{
public:
/** constructor*/
CDMFLoader(ISceneManager* smgr, io::IFileSystem* filesys);
//! returns true if the file maybe is able to be loaded by this class
//! based on the file extension (e.g. ".cob")
virtual bool isALoadableFileExtension(const io::path& filename) const _IRR_OVERRIDE_;
/** creates/loads an animated mesh from the file.
\return Pointer to the created mesh. Returns 0 if loading failed.
If you no longer need the mesh, you should call IAnimatedMesh::drop().
See IReferenceCounted::drop() for more information.*/
virtual IAnimatedMesh* createMesh(io::IReadFile* file) _IRR_OVERRIDE_;
/** loads dynamic lights present in this scene.
Note that loaded lights from DeleD must have the suffix \b dynamic_ and must be \b pointlight.
Irrlicht correctly loads specular color, diffuse color , position and distance of object affected by light.
\return number of lights loaded or 0 if loading failed.*/
int loadLights(const c8 * filename, ISceneManager* smgr,
ISceneNode* parent = 0, s32 base_id = 1000);
/** loads water plains present in this scene.
Note that loaded water plains from DeleD must have the suffix \b water_ and must be \b rectangle (with just 1 rectangular face).
Irrlicht correctly loads position and rotation of water plain as well as texture layers.
\return number of water plains loaded or 0 if loading failed.*/
int loadWaterPlains(const c8 *filename,
ISceneManager* smgr,
ISceneNode * parent = 0,
s32 base_id = 2000,
bool mode = true);
private:
void addMaterialPath(core::stringc& filename, const core::stringc& matPath);
ISceneManager* SceneMgr;
io::IFileSystem* FileSystem;
};
} // end namespace scene
} // end namespace irr
#endif

View File

@ -0,0 +1,167 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CDefaultGUIElementFactory.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUIEnvironment.h"
#include "IGUIButton.h"
#include "IGUICheckBox.h"
#include "IGUIColorSelectDialog.h"
#include "IGUIComboBox.h"
#include "IGUIContextMenu.h"
#include "IGUIEditBox.h"
#include "IGUIFileOpenDialog.h"
#include "IGUIInOutFader.h"
#include "IGUIImage.h"
#include "IGUIListBox.h"
#include "IGUIMeshViewer.h"
#include "IGUIScrollBar.h"
#include "IGUISpinBox.h"
#include "IGUIStaticText.h"
#include "IGUITabControl.h"
#include "IGUITable.h"
#include "IGUIToolbar.h"
#include "IGUIWindow.h"
#include "IGUITreeView.h"
#include "IGUIProfiler.h"
namespace irr
{
namespace gui
{
CDefaultGUIElementFactory::CDefaultGUIElementFactory(IGUIEnvironment* env)
: Environment(env)
{
#ifdef _DEBUG
setDebugName("CDefaultGUIElementFactory");
#endif
// don't grab the gui environment here to prevent cyclic references
}
//! adds an element to the env based on its type id
IGUIElement* CDefaultGUIElementFactory::addGUIElement(EGUI_ELEMENT_TYPE type, IGUIElement* parent)
{
switch(type)
{
case EGUIET_BUTTON:
return Environment->addButton(core::rect<s32>(0,0,100,100),parent);
case EGUIET_CHECK_BOX:
return Environment->addCheckBox(false, core::rect<s32>(0,0,100,100), parent);
case EGUIET_COLOR_SELECT_DIALOG:
return Environment->addColorSelectDialog(0,true,parent);
case EGUIET_COMBO_BOX:
return Environment->addComboBox(core::rect<s32>(0,0,100,100),parent);
case EGUIET_CONTEXT_MENU:
return Environment->addContextMenu(core::rect<s32>(0,0,100,100),parent);
case EGUIET_MENU:
return Environment->addMenu(parent);
case EGUIET_EDIT_BOX:
return Environment->addEditBox(0,core::rect<s32>(0,0,100,100),true, parent);
case EGUIET_FILE_OPEN_DIALOG:
return Environment->addFileOpenDialog(0,true,parent);
case EGUIET_IMAGE:
return Environment->addImage(0,core::position2di(0,0), true, parent);
case EGUIET_IN_OUT_FADER:
return Environment->addInOutFader(0,parent);
case EGUIET_LIST_BOX:
return Environment->addListBox(core::rect<s32>(0,0,100,100),parent);
case EGUIET_MESH_VIEWER:
return Environment->addMeshViewer(core::rect<s32>(0,0,100,100),parent);
case EGUIET_MODAL_SCREEN:
return Environment->addModalScreen(parent);
case EGUIET_MESSAGE_BOX:
return Environment->addMessageBox(0,0,false,0,parent);
case EGUIET_SCROLL_BAR:
return Environment->addScrollBar(false,core::rect<s32>(0,0,100,100),parent);
case EGUIET_STATIC_TEXT:
return Environment->addStaticText(0,core::rect<s32>(0,0,100,100),false,true,parent);
case EGUIET_TAB:
return Environment->addTab(core::rect<s32>(0,0,100,100),parent);
case EGUIET_TAB_CONTROL:
return Environment->addTabControl(core::rect<s32>(0,0,100,100),parent);
case EGUIET_TABLE:
return Environment->addTable(core::rect<s32>(0,0,100,100), parent);
case EGUIET_TOOL_BAR:
return Environment->addToolBar(parent);
case EGUIET_WINDOW:
return Environment->addWindow(core::rect<s32>(0,0,100,100),false,0,parent);
case EGUIET_SPIN_BOX:
return Environment->addSpinBox(L"0.0", core::rect<s32>(0,0,100,100), true, parent);
case EGUIET_TREE_VIEW:
return Environment->addTreeView(core::rect<s32>(0,0,100,100),parent);
case EGUIET_PROFILER:
return Environment->addProfilerDisplay(core::rect<s32>(0,0,100,100), parent);
default:
return 0;
}
}
//! adds an element to the environment based on its type name
IGUIElement* CDefaultGUIElementFactory::addGUIElement(const c8* typeName, IGUIElement* parent)
{
return addGUIElement( getTypeFromName(typeName), parent );
}
//! Returns the amount of element types this factory is able to create.
s32 CDefaultGUIElementFactory::getCreatableGUIElementTypeCount() const
{
return EGUIET_COUNT;
}
//! Returns the type of a creatable element type.
EGUI_ELEMENT_TYPE CDefaultGUIElementFactory::getCreateableGUIElementType(s32 idx) const
{
if (idx>=0 && idx<EGUIET_COUNT)
return (EGUI_ELEMENT_TYPE)idx;
return EGUIET_ELEMENT;
}
//! Returns the type name of a creatable element type.
const c8* CDefaultGUIElementFactory::getCreateableGUIElementTypeName(s32 idx) const
{
if (idx>=0 && idx<EGUIET_COUNT)
return GUIElementTypeNames[idx];
return 0;
}
//! Returns the type name of a creatable element type.
const c8* CDefaultGUIElementFactory::getCreateableGUIElementTypeName(EGUI_ELEMENT_TYPE type) const
{
// for this factory, type == index
if (type>=0 && type<EGUIET_COUNT)
return GUIElementTypeNames[type];
return 0;
}
EGUI_ELEMENT_TYPE CDefaultGUIElementFactory::getTypeFromName(const c8* name) const
{
for ( u32 i=0; GUIElementTypeNames[i]; ++i)
if (!strcmp(name, GUIElementTypeNames[i]) )
return (EGUI_ELEMENT_TYPE)i;
return EGUIET_ELEMENT;
}
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_

View File

@ -0,0 +1,70 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_DEFAULT_GUI_ELEMENT_FACTORY_H_INCLUDED__
#define __C_DEFAULT_GUI_ELEMENT_FACTORY_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUIElementFactory.h"
namespace irr
{
namespace gui
{
class IGUIElement;
class IGUIEnvironment;
//! This interface makes it possible to dynamically create gui elements.
class CDefaultGUIElementFactory : public IGUIElementFactory
{
public:
CDefaultGUIElementFactory(IGUIEnvironment* env);
//! Adds an element to the gui environment based on its type id.
/** \param type: Type of the element to add.
\param parent: Parent scene node of the new element. A value of 0 adds it to the root.
\return Returns pointer to the new element or 0 if unsuccessful. */
virtual IGUIElement* addGUIElement(EGUI_ELEMENT_TYPE type, IGUIElement* parent=0) _IRR_OVERRIDE_;
//! Adds a GUI element to the GUI Environment based on its type name.
/** \param typeName: Type name of the element to add. Taken from the GUIElementTypeNames c8* array.
\param parent: Parent scene node of the new element. A value of 0 adds it to the root.
\return Returns pointer to the new element or 0 if unsuccessful. */
virtual IGUIElement* addGUIElement(const c8* typeName, IGUIElement* parent=0) _IRR_OVERRIDE_;
//! Returns the amount of GUI element types this factory is able to create.
virtual s32 getCreatableGUIElementTypeCount() const _IRR_OVERRIDE_;
//! Returns the type of a createable GUI element type based on the index.
/** \param idx: Index of the element type in this factory. The value must be equal or greater than 0
and lower than getCreatableGUIElementTypeCount(). */
virtual EGUI_ELEMENT_TYPE getCreateableGUIElementType(s32 idx) const _IRR_OVERRIDE_;
//! Returns the type name of a createable GUI element type based on the index.
/** \param idx: Index of the element type in this factory. The value must be equal or greater than 0
and lower than getCreatableGUIElementTypeCount(). */
virtual const c8* getCreateableGUIElementTypeName(s32 idx) const _IRR_OVERRIDE_;
//! Returns the type name of a createable GUI element based on its type.
/** \param type: Type of the GUI element.
\return: Returns the name of the type if this factory can create it, otherwise it returns 0. */
virtual const c8* getCreateableGUIElementTypeName(EGUI_ELEMENT_TYPE type) const _IRR_OVERRIDE_;
private:
EGUI_ELEMENT_TYPE getTypeFromName(const c8* name) const;
IGUIEnvironment* Environment;
};
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
#endif // __C_DEFAULT_GUI_ELEMENT_FACTORY_H_INCLUDED__

View File

@ -0,0 +1,162 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CDefaultSceneNodeAnimatorFactory.h"
#include "CSceneNodeAnimatorCameraFPS.h"
#include "CSceneNodeAnimatorCameraMaya.h"
#include "ICursorControl.h"
#include "ISceneNodeAnimatorCollisionResponse.h"
#include "ISceneManager.h"
namespace irr
{
namespace scene
{
//! Names for scene node types
const c8* const SceneNodeAnimatorTypeNames[] =
{
"flyCircle",
"flyStraight",
"followSpline",
"rotation",
"texture",
"deletion",
"collisionResponse",
"cameraFPS",
"cameraMaya",
0
};
CDefaultSceneNodeAnimatorFactory::CDefaultSceneNodeAnimatorFactory(ISceneManager* mgr, gui::ICursorControl* crs)
: Manager(mgr), CursorControl(crs)
{
#ifdef _DEBUG
setDebugName("CDefaultSceneNodeAnimatorFactory");
#endif
// don't grab the scene manager here to prevent cyclic references
if (CursorControl)
CursorControl->grab();
}
CDefaultSceneNodeAnimatorFactory::~CDefaultSceneNodeAnimatorFactory()
{
if (CursorControl)
CursorControl->drop();
}
//! creates a scene node animator based on its type id
ISceneNodeAnimator* CDefaultSceneNodeAnimatorFactory::createSceneNodeAnimator(ESCENE_NODE_ANIMATOR_TYPE type, ISceneNode* target)
{
scene::ISceneNodeAnimator* anim = 0;
switch(type)
{
case ESNAT_FLY_CIRCLE:
anim = Manager->createFlyCircleAnimator(core::vector3df(0,0,0), 10);
break;
case ESNAT_FLY_STRAIGHT:
anim = Manager->createFlyStraightAnimator(core::vector3df(0,0,0), core::vector3df(100,100,100), 10000, true );
break;
case ESNAT_FOLLOW_SPLINE:
{
core::array<core::vector3df> points;
points.push_back(core::vector3df(0,0,0));
points.push_back(core::vector3df(10,5,10));
anim = Manager->createFollowSplineAnimator(0, points);
}
break;
case ESNAT_ROTATION:
anim = Manager->createRotationAnimator(core::vector3df(0.3f,0,0));
break;
case ESNAT_TEXTURE:
{
core::array<video::ITexture*> textures;
anim = Manager->createTextureAnimator(textures, 250);
}
break;
case ESNAT_DELETION:
anim = Manager->createDeleteAnimator(5000);
break;
case ESNAT_COLLISION_RESPONSE:
anim = Manager->createCollisionResponseAnimator(0, target);
break;
case ESNAT_CAMERA_FPS:
anim = new CSceneNodeAnimatorCameraFPS(CursorControl);
break;
case ESNAT_CAMERA_MAYA:
anim = new CSceneNodeAnimatorCameraMaya(CursorControl);
break;
default:
break;
}
if (anim && target)
target->addAnimator(anim);
return anim;
}
//! creates a scene node animator based on its type name
ISceneNodeAnimator* CDefaultSceneNodeAnimatorFactory::createSceneNodeAnimator(const c8* typeName, ISceneNode* target)
{
return createSceneNodeAnimator( getTypeFromName(typeName), target );
}
//! returns amount of scene node animator types this factory is able to create
u32 CDefaultSceneNodeAnimatorFactory::getCreatableSceneNodeAnimatorTypeCount() const
{
return ESNAT_COUNT;
}
//! returns type of a creatable scene node animator type
ESCENE_NODE_ANIMATOR_TYPE CDefaultSceneNodeAnimatorFactory::getCreateableSceneNodeAnimatorType(u32 idx) const
{
if (idx<ESNAT_COUNT)
return (ESCENE_NODE_ANIMATOR_TYPE)idx;
else
return ESNAT_UNKNOWN;
}
//! returns type name of a creatable scene node animator type
const c8* CDefaultSceneNodeAnimatorFactory::getCreateableSceneNodeAnimatorTypeName(u32 idx) const
{
if (idx<ESNAT_COUNT)
return SceneNodeAnimatorTypeNames[idx];
else
return 0;
}
//! returns type name of a creatable scene node animator type
const c8* CDefaultSceneNodeAnimatorFactory::getCreateableSceneNodeAnimatorTypeName(ESCENE_NODE_ANIMATOR_TYPE type) const
{
// for this factory: index == type
if (type<ESNAT_COUNT)
return SceneNodeAnimatorTypeNames[type];
else
return 0;
}
ESCENE_NODE_ANIMATOR_TYPE CDefaultSceneNodeAnimatorFactory::getTypeFromName(const c8* name) const
{
for ( u32 i=0; SceneNodeAnimatorTypeNames[i]; ++i)
if (!strcmp(name, SceneNodeAnimatorTypeNames[i]) )
return (ESCENE_NODE_ANIMATOR_TYPE)i;
return ESNAT_UNKNOWN;
}
} // end namespace scene
} // end namespace irr

View File

@ -0,0 +1,75 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_DEFAULT_SCENE_NODE_ANIMATOR_FACTORY_H_INCLUDED__
#define __C_DEFAULT_SCENE_NODE_ANIMATOR_FACTORY_H_INCLUDED__
#include "ISceneNodeAnimatorFactory.h"
namespace irr
{
namespace gui
{
class ICursorControl;
}
namespace scene
{
class ISceneNodeAnimator;
class ISceneManager;
//! Interface making it possible to dynamicly create scene nodes animators
class CDefaultSceneNodeAnimatorFactory : public ISceneNodeAnimatorFactory
{
public:
CDefaultSceneNodeAnimatorFactory(ISceneManager* mgr, gui::ICursorControl* crs);
virtual ~CDefaultSceneNodeAnimatorFactory();
//! creates a scene node animator based on its type id
/** \param type: Type of the scene node animator to add.
\param target: Target scene node of the new animator.
\return Returns pointer to the new scene node animator or null if not successful. You need to
drop this pointer after calling this, see IReferenceCounted::drop() for details. */
virtual ISceneNodeAnimator* createSceneNodeAnimator(ESCENE_NODE_ANIMATOR_TYPE type, ISceneNode* target) _IRR_OVERRIDE_;
//! creates a scene node animator based on its type name
/** \param typeName: Type of the scene node animator to add.
\param target: Target scene node of the new animator.
\return Returns pointer to the new scene node animator or null if not successful. You need to
drop this pointer after calling this, see IReferenceCounted::drop() for details. */
virtual ISceneNodeAnimator* createSceneNodeAnimator(const char* typeName, ISceneNode* target) _IRR_OVERRIDE_;
//! returns amount of scene node animator types this factory is able to create
virtual u32 getCreatableSceneNodeAnimatorTypeCount() const _IRR_OVERRIDE_;
//! returns type of a creatable scene node animator type
/** \param idx: Index of scene node animator type in this factory. Must be a value between 0 and
getCreatableSceneNodeTypeCount() */
virtual ESCENE_NODE_ANIMATOR_TYPE getCreateableSceneNodeAnimatorType(u32 idx) const _IRR_OVERRIDE_;
//! returns type name of a creatable scene node animator type
/** \param idx: Index of scene node animator type in this factory. Must be a value between 0 and
getCreatableSceneNodeAnimatorTypeCount() */
virtual const c8* getCreateableSceneNodeAnimatorTypeName(u32 idx) const _IRR_OVERRIDE_;
//! returns type name of a creatable scene node animator type
/** \param type: Type of scene node animator.
\return: Returns name of scene node animator type if this factory can create the type, otherwise 0. */
virtual const c8* getCreateableSceneNodeAnimatorTypeName(ESCENE_NODE_ANIMATOR_TYPE type) const _IRR_OVERRIDE_;
private:
ESCENE_NODE_ANIMATOR_TYPE getTypeFromName(const c8* name) const;
ISceneManager* Manager;
gui::ICursorControl* CursorControl;
};
} // end namespace scene
} // end namespace irr
#endif

View File

@ -0,0 +1,184 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CDefaultSceneNodeFactory.h"
#include "ISceneManager.h"
#include "ITextSceneNode.h"
#include "IBillboardTextSceneNode.h"
#include "ITerrainSceneNode.h"
#include "IDummyTransformationSceneNode.h"
#include "ICameraSceneNode.h"
#include "IBillboardSceneNode.h"
#include "IAnimatedMeshSceneNode.h"
#include "IParticleSystemSceneNode.h"
#include "ILightSceneNode.h"
#include "IMeshSceneNode.h"
#include "IOctreeSceneNode.h"
namespace irr
{
namespace scene
{
CDefaultSceneNodeFactory::CDefaultSceneNodeFactory(ISceneManager* mgr)
: Manager(mgr)
{
#ifdef _DEBUG
setDebugName("CDefaultSceneNodeFactory");
#endif
// don't grab the scene manager here to prevent cyclic references
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_CUBE, "cube"));
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_SPHERE, "sphere"));
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_TEXT, "text"));
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_BILLBOARD_TEXT, "billboardText"));
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_WATER_SURFACE, "waterSurface"));
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_TERRAIN, "terrain"));
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_SKY_BOX, "skyBox"));
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_SKY_DOME, "skyDome"));
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_SHADOW_VOLUME, "shadowVolume"));
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_OCTREE, "octree"));
// Legacy support
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_OCTREE, "octTree"));
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_MESH, "mesh"));
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_LIGHT, "light"));
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_EMPTY, "empty"));
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_DUMMY_TRANSFORMATION, "dummyTransformation"));
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_CAMERA, "camera"));
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_BILLBOARD, "billBoard"));
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_ANIMATED_MESH, "animatedMesh"));
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_PARTICLE_SYSTEM, "particleSystem"));
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_VOLUME_LIGHT, "volumeLight"));
// SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_MD3_SCENE_NODE, "md3"));
// legacy, for version <= 1.4.x irr files
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_CAMERA_MAYA, "cameraMaya"));
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_CAMERA_FPS, "cameraFPS"));
SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_Q3SHADER_SCENE_NODE, "quake3Shader"));
}
//! adds a scene node to the scene graph based on its type id
ISceneNode* CDefaultSceneNodeFactory::addSceneNode(ESCENE_NODE_TYPE type, ISceneNode* parent)
{
switch(type)
{
case ESNT_CUBE:
return Manager->addCubeSceneNode(10, parent);
case ESNT_SPHERE:
return Manager->addSphereSceneNode(5, 16, parent);
case ESNT_TEXT:
return Manager->addTextSceneNode(0, L"example");
case ESNT_BILLBOARD_TEXT:
return Manager->addBillboardTextSceneNode(0, L"example");
case ESNT_WATER_SURFACE:
return Manager->addWaterSurfaceSceneNode(0, 2.0f, 300.0f, 10.0f, parent);
case ESNT_TERRAIN:
return Manager->addTerrainSceneNode("", parent, -1,
core::vector3df(0.0f,0.0f,0.0f),
core::vector3df(0.0f,0.0f,0.0f),
core::vector3df(1.0f,1.0f,1.0f),
video::SColor(255,255,255,255),
4, ETPS_17, 0, true);
case ESNT_SKY_BOX:
return Manager->addSkyBoxSceneNode(0,0,0,0,0,0, parent);
case ESNT_SKY_DOME:
return Manager->addSkyDomeSceneNode(0, 16, 8, 0.9f, 2.0f, 1000.0f, parent);
case ESNT_SHADOW_VOLUME:
return 0;
case ESNT_OCTREE:
return Manager->addOctreeSceneNode((IMesh*)0, parent, -1, 128, true);
case ESNT_MESH:
return Manager->addMeshSceneNode(0, parent, -1, core::vector3df(),
core::vector3df(), core::vector3df(1,1,1), true);
case ESNT_LIGHT:
return Manager->addLightSceneNode(parent);
case ESNT_EMPTY:
return Manager->addEmptySceneNode(parent);
case ESNT_DUMMY_TRANSFORMATION:
return Manager->addDummyTransformationSceneNode(parent);
case ESNT_CAMERA:
return Manager->addCameraSceneNode(parent);
case ESNT_CAMERA_MAYA:
return Manager->addCameraSceneNodeMaya(parent);
case ESNT_CAMERA_FPS:
return Manager->addCameraSceneNodeFPS(parent);
case ESNT_BILLBOARD:
return Manager->addBillboardSceneNode(parent);
case ESNT_ANIMATED_MESH:
return Manager->addAnimatedMeshSceneNode(0, parent, -1, core::vector3df(),
core::vector3df(), core::vector3df(1,1,1), true);
case ESNT_PARTICLE_SYSTEM:
return Manager->addParticleSystemSceneNode(true, parent);
case ESNT_VOLUME_LIGHT:
return (ISceneNode*)Manager->addVolumeLightSceneNode(parent);
default:
break;
}
return 0;
}
//! adds a scene node to the scene graph based on its type name
ISceneNode* CDefaultSceneNodeFactory::addSceneNode(const c8* typeName, ISceneNode* parent)
{
return addSceneNode( getTypeFromName(typeName), parent );
}
//! returns amount of scene node types this factory is able to create
u32 CDefaultSceneNodeFactory::getCreatableSceneNodeTypeCount() const
{
return SupportedSceneNodeTypes.size();
}
//! returns type of a creatable scene node type
ESCENE_NODE_TYPE CDefaultSceneNodeFactory::getCreateableSceneNodeType(u32 idx) const
{
if (idx<SupportedSceneNodeTypes.size())
return SupportedSceneNodeTypes[idx].Type;
else
return ESNT_UNKNOWN;
}
//! returns type name of a creatable scene node type
const c8* CDefaultSceneNodeFactory::getCreateableSceneNodeTypeName(u32 idx) const
{
if (idx<SupportedSceneNodeTypes.size())
return SupportedSceneNodeTypes[idx].TypeName.c_str();
else
return 0;
}
//! returns type name of a creatable scene node type
const c8* CDefaultSceneNodeFactory::getCreateableSceneNodeTypeName(ESCENE_NODE_TYPE type) const
{
for (u32 i=0; i<SupportedSceneNodeTypes.size(); ++i)
if (SupportedSceneNodeTypes[i].Type == type)
return SupportedSceneNodeTypes[i].TypeName.c_str();
return 0;
}
ESCENE_NODE_TYPE CDefaultSceneNodeFactory::getTypeFromName(const c8* name) const
{
for (u32 i=0; i<SupportedSceneNodeTypes.size(); ++i)
if (SupportedSceneNodeTypes[i].TypeName == name)
return SupportedSceneNodeTypes[i].Type;
return ESNT_UNKNOWN;
}
} // end namespace scene
} // end namespace irr

View File

@ -0,0 +1,80 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_DEFAULT_SCENE_NODE_FACTORY_H_INCLUDED__
#define __C_DEFAULT_SCENE_NODE_FACTORY_H_INCLUDED__
#include "ISceneNodeFactory.h"
#include "irrArray.h"
#include "irrString.h"
namespace irr
{
namespace scene
{
class ISceneNode;
class ISceneManager;
//! Interface making it possible to dynamicly create scene nodes and animators
class CDefaultSceneNodeFactory : public ISceneNodeFactory
{
public:
CDefaultSceneNodeFactory(ISceneManager* mgr);
//! adds a scene node to the scene graph based on its type id
/** \param type: Type of the scene node to add.
\param parent: Parent scene node of the new node, can be null to add the scene node to the root.
\return Returns pointer to the new scene node or null if not successful. */
virtual ISceneNode* addSceneNode(ESCENE_NODE_TYPE type, ISceneNode* parent=0) _IRR_OVERRIDE_;
//! adds a scene node to the scene graph based on its type name
/** \param typeName: Type name of the scene node to add.
\param parent: Parent scene node of the new node, can be null to add the scene node to the root.
\return Returns pointer to the new scene node or null if not successful. */
virtual ISceneNode* addSceneNode(const c8* typeName, ISceneNode* parent=0) _IRR_OVERRIDE_;
//! returns amount of scene node types this factory is able to create
virtual u32 getCreatableSceneNodeTypeCount() const _IRR_OVERRIDE_;
//! returns type name of a creatable scene node type by index
/** \param idx: Index of scene node type in this factory. Must be a value between 0 and
uetCreatableSceneNodeTypeCount() */
virtual const c8* getCreateableSceneNodeTypeName(u32 idx) const _IRR_OVERRIDE_;
//! returns type of a creatable scene node type
/** \param idx: Index of scene node type in this factory. Must be a value between 0 and
getCreatableSceneNodeTypeCount() */
virtual ESCENE_NODE_TYPE getCreateableSceneNodeType(u32 idx) const _IRR_OVERRIDE_;
//! returns type name of a creatable scene node type
/** \param idx: Type of scene node.
\return: Returns name of scene node type if this factory can create the type, otherwise 0. */
virtual const c8* getCreateableSceneNodeTypeName(ESCENE_NODE_TYPE type) const _IRR_OVERRIDE_;
private:
ESCENE_NODE_TYPE getTypeFromName(const c8* name) const;
struct SSceneNodeTypePair
{
SSceneNodeTypePair(ESCENE_NODE_TYPE type, const c8* name)
: Type(type), TypeName(name)
{}
ESCENE_NODE_TYPE Type;
core::stringc TypeName;
};
core::array<SSceneNodeTypePair> SupportedSceneNodeTypes;
ISceneManager* Manager;
};
} // end namespace scene
} // end namespace irr
#endif

View File

@ -0,0 +1,172 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "IrrCompileConfig.h"
#include "SoftwareDriver2_compile_config.h"
#include "CDepthBuffer.h"
#ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_
namespace irr
{
namespace video
{
//! constructor
CDepthBuffer::CDepthBuffer(const core::dimension2d<u32>& size)
: Buffer(0), Size(0,0)
{
#ifdef _DEBUG
setDebugName("CDepthBuffer");
#endif
setSize(size);
}
//! destructor
CDepthBuffer::~CDepthBuffer()
{
delete [] Buffer;
}
//! clears the zbuffer
void CDepthBuffer::clear()
{
#ifdef SOFTWARE_DRIVER_2_USE_WBUFFER
f32 zMax = 0.f;
#else
f32 zMax = 1.f;
#endif
u32 zMaxValue;
zMaxValue = IR(zMax);
memset32 ( Buffer, zMaxValue, TotalSize );
}
//! sets the new size of the zbuffer
void CDepthBuffer::setSize(const core::dimension2d<u32>& size)
{
if (size == Size)
return;
Size = size;
delete [] Buffer;
Pitch = size.Width * sizeof ( fp24 );
TotalSize = Pitch * size.Height;
Buffer = new u8[TotalSize];
clear ();
}
//! returns the size of the zbuffer
const core::dimension2d<u32>& CDepthBuffer::getSize() const
{
return Size;
}
// -----------------------------------------------------------------
//! constructor
CStencilBuffer::CStencilBuffer(const core::dimension2d<u32>& size)
: Buffer(0), Size(0,0)
{
#ifdef _DEBUG
setDebugName("CDepthBuffer");
#endif
setSize(size);
}
//! destructor
CStencilBuffer::~CStencilBuffer()
{
delete [] Buffer;
}
//! clears the zbuffer
void CStencilBuffer::clear()
{
memset32 ( Buffer, 0, TotalSize );
}
//! sets the new size of the zbuffer
void CStencilBuffer::setSize(const core::dimension2d<u32>& size)
{
if (size == Size)
return;
Size = size;
delete [] Buffer;
Pitch = size.Width * sizeof ( u32 );
TotalSize = Pitch * size.Height;
Buffer = new u8[TotalSize];
clear ();
}
//! returns the size of the zbuffer
const core::dimension2d<u32>& CStencilBuffer::getSize() const
{
return Size;
}
} // end namespace video
} // end namespace irr
#endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_
namespace irr
{
namespace video
{
//! creates a ZBuffer
IDepthBuffer* createDepthBuffer(const core::dimension2d<u32>& size)
{
#ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_
return new CDepthBuffer(size);
#else
return 0;
#endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_
}
//! creates a ZBuffer
IStencilBuffer* createStencilBuffer(const core::dimension2d<u32>& size)
{
#ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_
return new CStencilBuffer(size);
#else
return 0;
#endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_
}
} // end namespace video
} // end namespace irr

View File

@ -0,0 +1,94 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_Z_BUFFER_H_INCLUDED__
#define __C_Z_BUFFER_H_INCLUDED__
#include "IDepthBuffer.h"
namespace irr
{
namespace video
{
class CDepthBuffer : public IDepthBuffer
{
public:
//! constructor
CDepthBuffer(const core::dimension2d<u32>& size);
//! destructor
virtual ~CDepthBuffer();
//! clears the zbuffer
virtual void clear() _IRR_OVERRIDE_;
//! sets the new size of the zbuffer
virtual void setSize(const core::dimension2d<u32>& size) _IRR_OVERRIDE_;
//! returns the size of the zbuffer
virtual const core::dimension2d<u32>& getSize() const _IRR_OVERRIDE_;
//! locks the zbuffer
virtual void* lock() _IRR_OVERRIDE_ { return (void*) Buffer; }
//! unlocks the zbuffer
virtual void unlock() _IRR_OVERRIDE_ {}
//! returns pitch of depthbuffer (in bytes)
virtual u32 getPitch() const _IRR_OVERRIDE_ { return Pitch; }
private:
u8* Buffer;
core::dimension2d<u32> Size;
u32 TotalSize;
u32 Pitch;
};
class CStencilBuffer : public IStencilBuffer
{
public:
//! constructor
CStencilBuffer(const core::dimension2d<u32>& size);
//! destructor
virtual ~CStencilBuffer();
//! clears the zbuffer
virtual void clear() _IRR_OVERRIDE_;
//! sets the new size of the zbuffer
virtual void setSize(const core::dimension2d<u32>& size) _IRR_OVERRIDE_;
//! returns the size of the zbuffer
virtual const core::dimension2d<u32>& getSize() const _IRR_OVERRIDE_;
//! locks the zbuffer
virtual void* lock() _IRR_OVERRIDE_ { return (void*) Buffer; }
//! unlocks the zbuffer
virtual void unlock() _IRR_OVERRIDE_ {}
//! returns pitch of depthbuffer (in bytes)
virtual u32 getPitch() const _IRR_OVERRIDE_ { return Pitch; }
private:
u8* Buffer;
core::dimension2d<u32> Size;
u32 TotalSize;
u32 Pitch;
};
} // end namespace video
} // end namespace irr
#endif

View File

@ -0,0 +1,105 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CDummyTransformationSceneNode.h"
#include "os.h"
namespace irr
{
namespace scene
{
//! constructor
CDummyTransformationSceneNode::CDummyTransformationSceneNode(
ISceneNode* parent, ISceneManager* mgr, s32 id)
: IDummyTransformationSceneNode(parent, mgr, id)
{
#ifdef _DEBUG
setDebugName("CDummyTransformationSceneNode");
#endif
setAutomaticCulling(scene::EAC_OFF);
}
//! returns the axis aligned bounding box of this node
const core::aabbox3d<f32>& CDummyTransformationSceneNode::getBoundingBox() const
{
return Box;
}
//! Returns a reference to the current relative transformation matrix.
//! This is the matrix, this scene node uses instead of scale, translation
//! and rotation.
core::matrix4& CDummyTransformationSceneNode::getRelativeTransformationMatrix()
{
return RelativeTransformationMatrix;
}
//! Returns the relative transformation of the scene node.
core::matrix4 CDummyTransformationSceneNode::getRelativeTransformation() const
{
return RelativeTransformationMatrix;
}
//! Creates a clone of this scene node and its children.
ISceneNode* CDummyTransformationSceneNode::clone(ISceneNode* newParent, ISceneManager* newManager)
{
if (!newParent)
newParent = Parent;
if (!newManager)
newManager = SceneManager;
CDummyTransformationSceneNode* nb = new CDummyTransformationSceneNode(newParent,
newManager, ID);
nb->cloneMembers(this, newManager);
nb->RelativeTransformationMatrix = RelativeTransformationMatrix;
nb->Box = Box;
if ( newParent )
nb->drop();
return nb;
}
const core::vector3df& CDummyTransformationSceneNode::getScale() const
{
os::Printer::log("CDummyTransformationSceneNode::getScale() does not contain the relative transformation.", ELL_DEBUG);
return RelativeScale;
}
void CDummyTransformationSceneNode::setScale(const core::vector3df& scale)
{
os::Printer::log("CDummyTransformationSceneNode::setScale() does not affect the relative transformation.", ELL_DEBUG);
RelativeScale = scale;
}
const core::vector3df& CDummyTransformationSceneNode::getRotation() const
{
os::Printer::log("CDummyTransformationSceneNode::getRotation() does not contain the relative transformation.", ELL_DEBUG);
return RelativeRotation;
}
void CDummyTransformationSceneNode::setRotation(const core::vector3df& rotation)
{
os::Printer::log("CDummyTransformationSceneNode::setRotation() does not affect the relative transformation.", ELL_DEBUG);
RelativeRotation = rotation;
}
const core::vector3df& CDummyTransformationSceneNode::getPosition() const
{
os::Printer::log("CDummyTransformationSceneNode::getPosition() does not contain the relative transformation.", ELL_DEBUG);
return RelativeTranslation;
}
void CDummyTransformationSceneNode::setPosition(const core::vector3df& newpos)
{
os::Printer::log("CDummyTransformationSceneNode::setPosition() does not affect the relative transformation.", ELL_DEBUG);
RelativeTranslation = newpos;
}
} // end namespace scene
} // end namespace irr

View File

@ -0,0 +1,62 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_DUMMY_TRANSFORMATION_SCENE_NODE_H_INCLUDED__
#define __C_DUMMY_TRANSFORMATION_SCENE_NODE_H_INCLUDED__
#include "IDummyTransformationSceneNode.h"
namespace irr
{
namespace scene
{
class CDummyTransformationSceneNode : public IDummyTransformationSceneNode
{
public:
//! constructor
CDummyTransformationSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id);
//! returns the axis aligned bounding box of this node
virtual const core::aabbox3d<f32>& getBoundingBox() const _IRR_OVERRIDE_;
//! Returns a reference to the current relative transformation matrix.
//! This is the matrix, this scene node uses instead of scale, translation
//! and rotation.
virtual core::matrix4& getRelativeTransformationMatrix() _IRR_OVERRIDE_;
//! Returns the relative transformation of the scene node.
virtual core::matrix4 getRelativeTransformation() const _IRR_OVERRIDE_;
//! does nothing.
virtual void render() _IRR_OVERRIDE_ {}
//! Returns type of the scene node
virtual ESCENE_NODE_TYPE getType() const _IRR_OVERRIDE_ { return ESNT_DUMMY_TRANSFORMATION; }
//! Creates a clone of this scene node and its children.
virtual ISceneNode* clone(ISceneNode* newParent=0, ISceneManager* newManager=0) _IRR_OVERRIDE_;
private:
// TODO: We can add least add some warnings to find troubles faster until we have
// fixed bug id 2318691.
virtual const core::vector3df& getScale() const _IRR_OVERRIDE_;
virtual void setScale(const core::vector3df& scale) _IRR_OVERRIDE_;
virtual const core::vector3df& getRotation() const _IRR_OVERRIDE_;
virtual void setRotation(const core::vector3df& rotation) _IRR_OVERRIDE_;
virtual const core::vector3df& getPosition() const _IRR_OVERRIDE_;
virtual void setPosition(const core::vector3df& newpos) _IRR_OVERRIDE_;
core::matrix4 RelativeTransformationMatrix;
core::aabbox3d<f32> Box;
};
} // end namespace scene
} // end namespace irr
#endif

View File

@ -0,0 +1,87 @@
// Copyright (C) 2015 Patryk Nadrowski
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in Irrlicht.h
#ifndef __C_EAGL_MANAGER_H_INCLUDED__
#define __C_EAGL_MANAGER_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_EAGL_MANAGER_
#include "SIrrCreationParameters.h"
#include "SExposedVideoData.h"
#include "IContextManager.h"
namespace irr
{
namespace video
{
// EAGL manager.
class CEAGLManager : public IContextManager
{
public:
//! Constructor.
CEAGLManager();
//! Destructor.
virtual ~CEAGLManager();
// Initialize EAGL.
/* This method checks if a view has CAEAGLLayer and grabs it if it does, anyway surface and context
aren't create. */
bool initialize(const SIrrlichtCreationParameters& params, const SExposedVideoData& data);
// Terminate EAGL.
/* Terminate EAGL context. This method break both existed surface and context. */
void terminate();
// Create EAGL surface.
/* This method configure CAEAGLLayer. */
bool generateSurface();
// Destroy EAGL surface.
/* This method reset CAEAGLLayer states. */
void destroySurface();
// Create EAGL context.
/* This method create and activate EAGL context. */
bool generateContext();
// Destroy EAGL context.
/* This method destroy EAGL context. */
void destroyContext();
const SExposedVideoData& getContext() const;
bool activateContext(const SExposedVideoData& videoData);
// Swap buffers.
bool swapBuffers();
private:
SIrrlichtCreationParameters Params;
SExposedVideoData Data;
bool Configured;
void* DataStorage;
struct SFrameBuffer
{
SFrameBuffer() : BufferID(0), ColorBuffer(0), DepthBuffer(0)
{
}
u32 BufferID;
u32 ColorBuffer;
u32 DepthBuffer;
};
SFrameBuffer FrameBuffer;
};
}
}
#endif
#endif

View File

@ -0,0 +1,273 @@
// Copyright (C) 2015 Patryk Nadrowski
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in Irrlicht.h
#include "CEAGLManager.h"
#ifdef _IRR_COMPILE_WITH_EAGL_MANAGER_
#include "irrString.h"
#include "os.h"
#import <UIKit/UIKit.h>
#import <OpenGLES/EAGL.h>
#if defined(_IRR_COMPILE_WITH_OGLES1_)
#include <OpenGLES/ES1/gl.h>
#include <OpenGLES/ES1/glext.h>
#elif defined(_IRR_COMPILE_WITH_OGLES2_)
#include <OpenGLES/ES2/gl.h>
#include <OpenGLES/ES2/glext.h>
#endif
namespace irr
{
namespace video
{
struct SEAGLManagerDataStorage
{
SEAGLManagerDataStorage() : Layer(0), Context(0)
{
}
CAEAGLLayer* Layer;
EAGLContext* Context;
};
CEAGLManager::CEAGLManager() : IContextManager(), Configured(false), DataStorage(0)
{
#ifdef _DEBUG
setDebugName("CEAGLManager");
#endif
DataStorage = new SEAGLManagerDataStorage();
}
CEAGLManager::~CEAGLManager()
{
destroyContext();
destroySurface();
terminate();
delete static_cast<SEAGLManagerDataStorage*>(DataStorage);
}
bool CEAGLManager::initialize(const SIrrlichtCreationParameters& params, const SExposedVideoData& data)
{
SEAGLManagerDataStorage* dataStorage = static_cast<SEAGLManagerDataStorage*>(DataStorage);
if (dataStorage->Layer != nil)
return true;
Params = params;
Data = data;
UIView* view = (__bridge UIView*)data.OpenGLiOS.View;
if (view == nil || ![[view layer] isKindOfClass:[CAEAGLLayer class]])
{
os::Printer::log("Could not get EAGL display.");
return false;
}
dataStorage->Layer = (CAEAGLLayer*)[view layer];
return true;
}
void CEAGLManager::terminate()
{
SEAGLManagerDataStorage* dataStorage = static_cast<SEAGLManagerDataStorage*>(DataStorage);
[EAGLContext setCurrentContext:0];
destroySurface();
if (dataStorage->Layer != nil)
dataStorage->Layer = 0;
}
bool CEAGLManager::generateSurface()
{
SEAGLManagerDataStorage* dataStorage = static_cast<SEAGLManagerDataStorage*>(DataStorage);
CAEAGLLayer* layer = dataStorage->Layer;
if (layer == nil)
return false;
if (Configured)
return true;
NSDictionary* attribs = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:NO],
kEAGLDrawablePropertyRetainedBacking,
(Params.Bits > 16) ? kEAGLColorFormatRGBA8 : kEAGLColorFormatRGB565,
kEAGLDrawablePropertyColorFormat,
nil];
[layer setOpaque:(Params.WithAlphaChannel) ? YES : NO];
[layer setDrawableProperties:attribs];
Configured = true;
return true;
}
void CEAGLManager::destroySurface()
{
SEAGLManagerDataStorage* dataStorage = static_cast<SEAGLManagerDataStorage*>(DataStorage);
CAEAGLLayer* layer = dataStorage->Layer;
if (layer == nil)
return;
[layer setOpaque:NO];
[layer setDrawableProperties:nil];
Configured = false;
}
bool CEAGLManager::generateContext()
{
SEAGLManagerDataStorage* dataStorage = static_cast<SEAGLManagerDataStorage*>(DataStorage);
if (dataStorage->Context != nil || !Configured)
return false;
EAGLRenderingAPI OpenGLESVersion = kEAGLRenderingAPIOpenGLES2;
switch (Params.DriverType)
{
case EDT_OGLES1:
OpenGLESVersion = kEAGLRenderingAPIOpenGLES1;
break;
case EDT_OGLES2:
OpenGLESVersion = kEAGLRenderingAPIOpenGLES2;
break;
default:
break;
}
dataStorage->Context = [[EAGLContext alloc] initWithAPI:OpenGLESVersion];
if (dataStorage->Context == nil)
{
os::Printer::log("Could not create EAGL context.", ELL_ERROR);
return false;
}
Data.OpenGLiOS.Context = (__bridge void*)dataStorage->Context;
os::Printer::log("EAGL context created with OpenGLESVersion: ", core::stringc(static_cast<int>(OpenGLESVersion)), ELL_DEBUG);
return true;
}
void CEAGLManager::destroyContext()
{
SEAGLManagerDataStorage* dataStorage = static_cast<SEAGLManagerDataStorage*>(DataStorage);
[dataStorage->Context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:nil];
if (FrameBuffer.BufferID != 0)
{
glDeleteFramebuffersOES(1, &FrameBuffer.BufferID);
FrameBuffer.BufferID = 0;
}
if (FrameBuffer.ColorBuffer != 0)
{
glDeleteRenderbuffersOES(1, &FrameBuffer.ColorBuffer);
FrameBuffer.ColorBuffer = 0;
}
if (FrameBuffer.DepthBuffer != 0)
{
glDeleteRenderbuffersOES(1, &FrameBuffer.DepthBuffer);
FrameBuffer.DepthBuffer = 0;
}
[EAGLContext setCurrentContext:0];
if (dataStorage->Context != nil)
dataStorage->Context = 0;
Data.OpenGLiOS.Context = 0;
}
bool CEAGLManager::activateContext(const SExposedVideoData& videoData)
{
SEAGLManagerDataStorage* dataStorage = static_cast<SEAGLManagerDataStorage*>(DataStorage);
EAGLContext* context = dataStorage->Context;
bool status = false;
if (context != nil)
{
status = ([EAGLContext currentContext] == context || [EAGLContext setCurrentContext:context]);
}
if (status)
{
if (FrameBuffer.ColorBuffer == 0)
{
glGenRenderbuffersOES(1, &FrameBuffer.ColorBuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, FrameBuffer.ColorBuffer);
[context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:dataStorage->Layer];
}
if (FrameBuffer.DepthBuffer == 0)
{
GLenum depth = (Params.ZBufferBits >= 24) ? GL_DEPTH_COMPONENT24_OES : GL_DEPTH_COMPONENT16_OES;
glGenRenderbuffersOES(1, &FrameBuffer.DepthBuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, FrameBuffer.DepthBuffer);
glRenderbufferStorageOES(GL_RENDERBUFFER_OES, depth, Params.WindowSize.Width, Params.WindowSize.Height);
}
if (FrameBuffer.BufferID == 0)
{
glGenFramebuffersOES(1, &FrameBuffer.BufferID);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, FrameBuffer.BufferID);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, FrameBuffer.ColorBuffer);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, FrameBuffer.DepthBuffer);
}
glBindFramebufferOES(GL_FRAMEBUFFER_OES, FrameBuffer.BufferID);
}
else
{
os::Printer::log("Could not make EGL context current.");
}
return status;
}
const SExposedVideoData& CEAGLManager::getContext() const
{
return Data;
}
bool CEAGLManager::swapBuffers()
{
SEAGLManagerDataStorage* dataStorage = static_cast<SEAGLManagerDataStorage*>(DataStorage);
EAGLContext* context = dataStorage->Context;
bool status = false;
if (context != nil && context == [EAGLContext currentContext])
{
glBindRenderbufferOES(GL_RENDERBUFFER_OES, FrameBuffer.ColorBuffer);
[context presentRenderbuffer:GL_RENDERBUFFER_OES];
status = true;
}
return status;
}
}
}
#endif

662
source/Irrlicht/CEGLManager.cpp Executable file
View File

@ -0,0 +1,662 @@
// Copyright (C) 2013 Patryk Nadrowski
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in Irrlicht.h
#include "CEGLManager.h"
#ifdef _IRR_COMPILE_WITH_EGL_MANAGER_
#include "irrString.h"
#include "irrArray.h"
#include "os.h"
#if defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_)
#include <android/native_activity.h>
#endif
namespace irr
{
namespace video
{
CEGLManager::CEGLManager() : IContextManager(), EglWindow(0), EglDisplay(EGL_NO_DISPLAY),
EglSurface(EGL_NO_SURFACE), EglContext(EGL_NO_CONTEXT), EglConfig(0), MajorVersion(0), MinorVersion(0)
{
#ifdef _DEBUG
setDebugName("CEGLManager");
#endif
}
CEGLManager::~CEGLManager()
{
destroyContext();
destroySurface();
terminate();
}
bool CEGLManager::initialize(const SIrrlichtCreationParameters& params, const SExposedVideoData& data)
{
// store new data
Params=params;
Data=data;
if (EglWindow != 0 && EglDisplay != EGL_NO_DISPLAY)
return true;
// Window is depend on platform.
#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_)
EglWindow = (NativeWindowType)Data.OpenGLWin32.HWnd;
Data.OpenGLWin32.HDc = GetDC((HWND)EglWindow);
EglDisplay = eglGetDisplay((NativeDisplayType)Data.OpenGLWin32.HDc);
#elif defined(_IRR_EMSCRIPTEN_PLATFORM_)
EglWindow = 0;
EglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
#elif defined(_IRR_COMPILE_WITH_X11_DEVICE_)
EglWindow = (NativeWindowType)Data.OpenGLLinux.X11Window;
EglDisplay = eglGetDisplay((NativeDisplayType)Data.OpenGLLinux.X11Display);
#elif defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_)
EglWindow = (ANativeWindow*)Data.OGLESAndroid.Window;
EglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
#elif defined(_IRR_COMPILE_WITH_FB_DEVICE_)
EglWindow = (NativeWindowType)Data.OpenGLFB.Window;
EglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
#endif
// We must check if EGL display is valid.
if (EglDisplay == EGL_NO_DISPLAY)
{
os::Printer::log("Could not get EGL display.");
terminate();
return false;
}
// Initialize EGL here.
if (!eglInitialize(EglDisplay, &MajorVersion, &MinorVersion))
{
os::Printer::log("Could not initialize EGL display.");
EglDisplay = EGL_NO_DISPLAY;
terminate();
return false;
}
else
os::Printer::log("EGL version", core::stringc(MajorVersion+(MinorVersion*0.1f)).c_str());
return true;
}
void CEGLManager::terminate()
{
if (EglWindow == 0 && EglDisplay == EGL_NO_DISPLAY)
return;
if (EglDisplay != EGL_NO_DISPLAY)
{
// We should unbind current EGL context before terminate EGL.
eglMakeCurrent(EglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglTerminate(EglDisplay);
EglDisplay = EGL_NO_DISPLAY;
}
#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_)
if (Data.OpenGLWin32.HDc)
{
ReleaseDC((HWND)EglWindow, (HDC)Data.OpenGLWin32.HDc);
Data.OpenGLWin32.HDc = 0;
}
#endif
MajorVersion = 0;
MinorVersion = 0;
}
bool CEGLManager::generateSurface()
{
if (EglDisplay == EGL_NO_DISPLAY)
return false;
if (EglSurface != EGL_NO_SURFACE)
return true;
// We should assign new WindowID on platforms, where WindowID may change at runtime,
// at this time only Android support this feature.
// this needs an update method instead!
#if defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_)
EglWindow = (ANativeWindow*)Data.OGLESAndroid.Window;
#endif
#if defined(_IRR_EMSCRIPTEN_PLATFORM_)
// eglChooseConfig is currently only implemented as stub in emscripten (version 1.37.22 at point of writing)
// But the other solution would also be fine as it also only generates a single context so there is not much to choose from.
EglConfig = chooseConfig(ECS_IRR_CHOOSE);
#else
EglConfig = chooseConfig(ECS_EGL_CHOOSE_FIRST_LOWER_EXPECTATIONS);
#endif
if ( EglConfig == 0 )
{
os::Printer::log("Could not get config for EGL display.");
return false;
}
#if defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_)
EGLint Format = 0;
eglGetConfigAttrib(EglDisplay, EglConfig, EGL_NATIVE_VISUAL_ID, &Format);
ANativeWindow_setBuffersGeometry(EglWindow, 0, 0, Format);
#endif
// Now we are able to create EGL surface.
EglSurface = eglCreateWindowSurface(EglDisplay, EglConfig, EglWindow, 0);
if (EGL_NO_SURFACE == EglSurface)
EglSurface = eglCreateWindowSurface(EglDisplay, EglConfig, 0, 0);
if (EGL_NO_SURFACE == EglSurface)
os::Printer::log("Could not create EGL surface.");
#ifdef EGL_VERSION_1_2
if (MinorVersion > 1)
eglBindAPI(EGL_OPENGL_ES_API);
#endif
if (Params.Vsync)
eglSwapInterval(EglDisplay, 1);
return true;
}
EGLConfig CEGLManager::chooseConfig(EConfigStyle confStyle)
{
EGLConfig configResult = 0;
// Find proper OpenGL BIT.
EGLint eglOpenGLBIT = 0;
switch (Params.DriverType)
{
case EDT_OGLES1:
eglOpenGLBIT = EGL_OPENGL_ES_BIT;
break;
case EDT_OGLES2:
case EDT_WEBGL1:
eglOpenGLBIT = EGL_OPENGL_ES2_BIT;
break;
default:
break;
}
if ( confStyle == ECS_EGL_CHOOSE_FIRST_LOWER_EXPECTATIONS )
{
EGLint Attribs[] =
{
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, Params.WithAlphaChannel ? 1:0,
EGL_BUFFER_SIZE, Params.Bits,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_DEPTH_SIZE, Params.ZBufferBits,
EGL_STENCIL_SIZE, Params.Stencilbuffer,
EGL_SAMPLE_BUFFERS, Params.AntiAlias ? 1:0,
EGL_SAMPLES, Params.AntiAlias,
#ifdef EGL_VERSION_1_3
EGL_RENDERABLE_TYPE, eglOpenGLBIT,
#endif
EGL_NONE, 0
};
EGLint numConfigs = 0;
u32 steps = 5;
// Choose the best EGL config.
// TODO: We should also have a confStyle ECS_EGL_CHOOSE_CLOSEST
// which doesn't take first result of eglChooseConfigs,
// but the closest to requested parameters. eglChooseConfigs
// can return more than 1 result and first one might have
// "better" values than requested (more bits per pixel etc).
// So this returns the config which can do most, not the
// config which is closest to the requested parameters.
//
while (!eglChooseConfig(EglDisplay, Attribs, &configResult, 1, &numConfigs) || !numConfigs)
{
switch (steps)
{
case 5: // samples
if (Attribs[19] > 2) // Params.AntiAlias
--Attribs[19];
else
{
Attribs[17] = 0; // Params.Stencilbuffer
Attribs[19] = 0; // Params.AntiAlias
--steps;
}
break;
case 4: // alpha
if (Attribs[7]) // Params.WithAlphaChannel
{
Attribs[7] = 0;
if (Params.AntiAlias)
{
Attribs[17] = 1;
Attribs[19] = Params.AntiAlias;
steps = 5;
}
}
else
--steps;
break;
case 3: // stencil
if (Attribs[15]) // Params.Stencilbuffer
{
Attribs[15] = 0;
if (Params.AntiAlias)
{
Attribs[17] = 1;
Attribs[19] = Params.AntiAlias;
steps = 5;
}
}
else
--steps;
break;
case 2: // depth size
if (Attribs[13] > 16) // Params.ZBufferBits
{
Attribs[13] -= 8;
}
else
--steps;
break;
case 1: // buffer size
if (Attribs[9] > 16) // Params.Bits
{
Attribs[9] -= 8;
}
else
--steps;
break;
default:
return 0;
}
}
if (Params.AntiAlias && !Attribs[17])
os::Printer::log("No multisampling.");
if (Params.WithAlphaChannel && !Attribs[7])
os::Printer::log("No alpha.");
if (Params.Stencilbuffer && !Attribs[15])
os::Printer::log("No stencil buffer.");
if (Params.ZBufferBits > Attribs[13])
os::Printer::log("No full depth buffer.");
if (Params.Bits > Attribs[9])
os::Printer::log("No full color buffer.");
}
else if ( confStyle == ECS_IRR_CHOOSE )
{
// find number of available configs
EGLint numConfigs;
if ( eglGetConfigs( EglDisplay, NULL, 0, &numConfigs) == EGL_FALSE )
{
testEGLError();
return 0;
}
if ( numConfigs <= 0 )
return 0;
// Get all available configs.
EGLConfig * configs = new EGLConfig[numConfigs];
if ( eglGetConfigs( EglDisplay, configs, numConfigs, &numConfigs) == EGL_FALSE )
{
testEGLError();
return 0;
}
// Find the best one.
core::array<SConfigRating> ratings((u32)numConfigs);
for ( u32 i=0; i < (u32)numConfigs; ++i )
{
SConfigRating r;
r.config = configs[i];
r.rating = rateConfig(r.config, eglOpenGLBIT);
if ( r.rating >= 0 )
ratings.push_back(r);
}
if ( ratings.size() > 0 )
{
ratings.sort();
configResult = ratings[0].config;
if ( ratings[0].rating != 0 )
{
// This is just to print some log info (it also rates again while doing that, but rating is cheap enough, so that doesn't matter here).
rateConfig(ratings[0].config, eglOpenGLBIT, true);
}
}
delete[] configs;
}
return configResult;
}
irr::s32 CEGLManager::rateConfig(EGLConfig config, EGLint eglOpenGLBIT, bool log)
{
// some values must be there or we ignore the config
#ifdef EGL_VERSION_1_3
EGLint attribRenderableType = 0;
eglGetConfigAttrib( EglDisplay, config, EGL_RENDERABLE_TYPE, &attribRenderableType);
if ( attribRenderableType != eglOpenGLBIT )
{
if ( log )
os::Printer::log("EGL_RENDERABLE_TYPE != eglOpenGLBIT");
return -1;
}
#endif
EGLint attribSurfaceType = 0;
eglGetConfigAttrib( EglDisplay, config, EGL_SURFACE_TYPE, &attribSurfaceType);
if ( attribSurfaceType != EGL_WINDOW_BIT )
{
if ( log )
os::Printer::log("EGL_SURFACE_TYPE!= EGL_WINDOW_BIT");
return -1;
}
// Generally we give a really bad rating if attributes are worse than requested
// We give a slight worse rating if attributes are not exact as requested
// And we use some priorities which might make sense (but not really fine-tuned,
// so if you think other priorities would be better don't worry about changing the values.
int rating = 0;
EGLint attribBufferSize = 0;
eglGetConfigAttrib( EglDisplay, config, EGL_BUFFER_SIZE, &attribBufferSize);
if ( attribBufferSize < Params.Bits )
{
if ( log )
os::Printer::log("No full color buffer.");
rating += 100;
}
if ( attribBufferSize > Params.Bits )
{
if ( log )
os::Printer::log("Larger color buffer.", ELL_DEBUG);
++rating;
}
EGLint attribRedSize = 0;
eglGetConfigAttrib( EglDisplay, config, EGL_RED_SIZE, &attribRedSize);
if ( attribRedSize < 5 && Params.Bits >= 4 )
rating += 100;
else if ( attribRedSize < 8 && Params.Bits >= 24)
rating += 10;
else if ( attribRedSize >= 8 && Params.Bits < 24 )
rating ++;
EGLint attribGreenSize = 0;
eglGetConfigAttrib( EglDisplay, config, EGL_GREEN_SIZE, &attribGreenSize);
if ( attribGreenSize < 5 && Params.Bits >= 4 )
rating += 100;
else if ( attribGreenSize < 8 && Params.Bits >= 24)
rating += 10;
else if ( attribGreenSize >= 8 && Params.Bits < 24 )
rating ++;
EGLint attribBlueSize = 0;
eglGetConfigAttrib( EglDisplay, config, EGL_BLUE_SIZE, &attribBlueSize);
if ( attribBlueSize < 5 && Params.Bits >= 4 )
rating += 100;
else if ( attribBlueSize < 8 && Params.Bits >= 24)
rating += 10;
else if ( attribBlueSize >= 8 && Params.Bits < 24 )
rating ++;
EGLint attribAlphaSize = 0;
eglGetConfigAttrib( EglDisplay, config, EGL_ALPHA_SIZE, &attribAlphaSize);
if ( Params.WithAlphaChannel && attribAlphaSize == 0 )
{
if ( log )
os::Printer::log("No alpha.");
rating += 10;
}
else if ( !Params.WithAlphaChannel && attribAlphaSize > 0 )
{
if ( log )
os::Printer::log("Got alpha (unrequested).", ELL_DEBUG);
rating ++;
}
EGLint attribStencilSize = 0;
eglGetConfigAttrib( EglDisplay, config, EGL_STENCIL_SIZE, &attribStencilSize);
if ( Params.Stencilbuffer && attribStencilSize == 0 )
{
if ( log )
os::Printer::log("No stencil buffer.");
rating += 10;
}
else if ( !Params.Stencilbuffer && attribStencilSize > 0 )
{
if ( log )
os::Printer::log("Got a stencil buffer (unrequested).", ELL_DEBUG);
rating ++;
}
EGLint attribDepthSize = 0;
eglGetConfigAttrib( EglDisplay, config, EGL_DEPTH_SIZE, &attribDepthSize);
if ( attribDepthSize < Params.ZBufferBits )
{
if ( log )
{
if (attribDepthSize > 0)
os::Printer::log("No full depth buffer.");
else
os::Printer::log("No depth buffer.");
}
rating += 50;
}
else if ( attribDepthSize != Params.ZBufferBits )
{
if ( log )
{
if ( Params.ZBufferBits == 0 )
os::Printer::log("Got a depth buffer (unrequested).", ELL_DEBUG);
else
os::Printer::log("Got a larger depth buffer.", ELL_DEBUG);
}
rating ++;
}
EGLint attribSampleBuffers=0, attribSamples = 0;
eglGetConfigAttrib( EglDisplay, config, EGL_SAMPLE_BUFFERS, &attribSampleBuffers);
eglGetConfigAttrib( EglDisplay, config, EGL_SAMPLES, &attribSamples);
if ( Params.AntiAlias && attribSampleBuffers == 0 )
{
if ( log )
os::Printer::log("No multisampling.");
rating += 20;
}
else if ( Params.AntiAlias && attribSampleBuffers && attribSamples < Params.AntiAlias )
{
if ( log )
os::Printer::log("Multisampling with less samples than requested.", ELL_DEBUG);
rating += 10;
}
else if ( Params.AntiAlias && attribSampleBuffers && attribSamples > Params.AntiAlias )
{
if ( log )
os::Printer::log("Multisampling with more samples than requested.", ELL_DEBUG);
rating += 5;
}
else if ( !Params.AntiAlias && attribSampleBuffers > 0 )
{
if ( log )
os::Printer::log("Got multisampling (unrequested).", ELL_DEBUG);
rating += 3;
}
return rating;
}
void CEGLManager::destroySurface()
{
if (EglSurface == EGL_NO_SURFACE)
return;
// We should unbind current EGL context before destroy EGL surface.
eglMakeCurrent(EglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglDestroySurface(EglDisplay, EglSurface);
EglSurface = EGL_NO_SURFACE;
}
bool CEGLManager::generateContext()
{
if (EglDisplay == EGL_NO_DISPLAY || EglSurface == EGL_NO_SURFACE)
return false;
if (EglContext != EGL_NO_CONTEXT)
return true;
EGLint OpenGLESVersion = 0;
switch (Params.DriverType)
{
case EDT_OGLES1:
OpenGLESVersion = 1;
break;
case EDT_OGLES2:
case EDT_WEBGL1:
OpenGLESVersion = 2;
break;
default:
break;
}
EGLint ContextAttrib[] =
{
#ifdef EGL_VERSION_1_3
EGL_CONTEXT_CLIENT_VERSION, OpenGLESVersion,
#endif
EGL_NONE, 0
};
EglContext = eglCreateContext(EglDisplay, EglConfig, EGL_NO_CONTEXT, ContextAttrib);
if (testEGLError())
{
os::Printer::log("Could not create EGL context.", ELL_ERROR);
return false;
}
os::Printer::log("EGL context created with OpenGLESVersion: ", core::stringc((int)OpenGLESVersion), ELL_DEBUG);
return true;
}
void CEGLManager::destroyContext()
{
if (EglContext == EGL_NO_CONTEXT)
return;
// We must unbind current EGL context before destroy it.
eglMakeCurrent(EglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglDestroyContext(EglDisplay, EglContext);
EglContext = EGL_NO_CONTEXT;
}
bool CEGLManager::activateContext(const SExposedVideoData& videoData, bool restorePrimaryOnZero)
{
eglMakeCurrent(EglDisplay, EglSurface, EglSurface, EglContext);
if (testEGLError())
{
os::Printer::log("Could not make EGL context current.");
return false;
}
return true;
}
const SExposedVideoData& CEGLManager::getContext() const
{
return Data;
}
bool CEGLManager::swapBuffers()
{
return (eglSwapBuffers(EglDisplay, EglSurface)==EGL_TRUE);
}
bool CEGLManager::testEGLError()
{
#if defined(EGL_VERSION_1_0) && defined(_DEBUG)
EGLint status = eglGetError();
switch (status)
{
case EGL_SUCCESS:
return false;
case EGL_NOT_INITIALIZED :
os::Printer::log("Not Initialized", ELL_ERROR);
break;
case EGL_BAD_ACCESS:
os::Printer::log("Bad Access", ELL_ERROR);
break;
case EGL_BAD_ALLOC:
os::Printer::log("Bad Alloc", ELL_ERROR);
break;
case EGL_BAD_ATTRIBUTE:
os::Printer::log("Bad Attribute", ELL_ERROR);
break;
case EGL_BAD_CONTEXT:
os::Printer::log("Bad Context", ELL_ERROR);
break;
case EGL_BAD_CONFIG:
os::Printer::log("Bad Config", ELL_ERROR);
break;
case EGL_BAD_CURRENT_SURFACE:
os::Printer::log("Bad Current Surface", ELL_ERROR);
break;
case EGL_BAD_DISPLAY:
os::Printer::log("Bad Display", ELL_ERROR);
break;
case EGL_BAD_SURFACE:
os::Printer::log("Bad Surface", ELL_ERROR);
break;
case EGL_BAD_MATCH:
os::Printer::log("Bad Match", ELL_ERROR);
break;
case EGL_BAD_PARAMETER:
os::Printer::log("Bad Parameter", ELL_ERROR);
break;
case EGL_BAD_NATIVE_PIXMAP:
os::Printer::log("Bad Native Pixmap", ELL_ERROR);
break;
case EGL_BAD_NATIVE_WINDOW:
os::Printer::log("Bad Native Window", ELL_ERROR);
break;
case EGL_CONTEXT_LOST:
os::Printer::log("Context Lost", ELL_ERROR);
break;
default:
break;
};
return true;
#else
return false;
#endif
}
}
}
#endif

119
source/Irrlicht/CEGLManager.h Executable file
View File

@ -0,0 +1,119 @@
// Copyright (C) 2013 Patryk Nadrowski
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in Irrlicht.h
#ifndef __C_EGL_MANAGER_H_INCLUDED__
#define __C_EGL_MANAGER_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_EGL_MANAGER_
#include <EGL/egl.h>
#include "SIrrCreationParameters.h"
#include "SExposedVideoData.h"
#include "IContextManager.h"
#ifdef _MSC_VER
#pragma comment(lib, "libEGL.lib")
#endif
namespace irr
{
namespace video
{
// EGL manager.
class CEGLManager : public IContextManager
{
public:
//! Constructor.
CEGLManager();
//! Destructor.
virtual ~CEGLManager();
// Initialize EGL.
/* This method initialize EGLand create EGL display, anyway surface and context
aren't create. */
virtual bool initialize(const SIrrlichtCreationParameters& params, const SExposedVideoData& data) _IRR_OVERRIDE_;
// Terminate EGL.
/* Terminate EGL context. This method break both existed surface and context. */
virtual void terminate() _IRR_OVERRIDE_;
// Create EGL surface.
/* This method create EGL surface. On some platforms eg. Android, we must
recreate surface on each resume, because WindowID may change, so existed
surface may not be valid. If EGL context already exist, this method
automatically activates it. */
virtual bool generateSurface() _IRR_OVERRIDE_;
// Destroy EGL surface.
/* This method destroy EGL. On some platforms eg. Android, we should call
this method on each pause, because after resume this surface may not be valid.
Hovewer this method doesn'r break EGL context. */
virtual void destroySurface() _IRR_OVERRIDE_;
// Create EGL context.
/* This method create and activate EGL context. */
virtual bool generateContext() _IRR_OVERRIDE_;
// Destroy EGL context.
/* This method destroy EGL context. */
virtual void destroyContext() _IRR_OVERRIDE_;
virtual const SExposedVideoData& getContext() const _IRR_OVERRIDE_;
virtual bool activateContext(const SExposedVideoData& videoData, bool restorePrimaryOnZero) _IRR_OVERRIDE_;
// Swap buffers.
virtual bool swapBuffers() _IRR_OVERRIDE_;
protected:
enum EConfigStyle
{
//! Get first result of eglChooseConfigs and if that fails try again by requesting simpler attributes
ECS_EGL_CHOOSE_FIRST_LOWER_EXPECTATIONS,
//! We select our own best fit and avoid using eglChooseConfigs
ECS_IRR_CHOOSE,
};
EGLConfig chooseConfig(EConfigStyle confStyle);
//! Check how close this config is to the parameters we requested
//! returns 0 is perfect, larger values are worse and < 0 is unusable.
irr::s32 rateConfig(EGLConfig config, EGLint eglOpenGLBIT, bool log=false);
// Helper to sort EGLConfig's. (because we got no std::pair....)
struct SConfigRating
{
EGLConfig config;
irr::s32 rating;
bool operator<(const SConfigRating& other) const
{
return rating < other.rating;
}
};
private:
bool testEGLError();
NativeWindowType EglWindow;
EGLDisplay EglDisplay;
EGLSurface EglSurface;
EGLContext EglContext;
EGLConfig EglConfig;
SIrrlichtCreationParameters Params;
SExposedVideoData Data;
EGLint MajorVersion;
EGLint MinorVersion;
};
}
}
#endif
#endif

View File

@ -0,0 +1,70 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CEmptySceneNode.h"
#include "ISceneManager.h"
namespace irr
{
namespace scene
{
//! constructor
CEmptySceneNode::CEmptySceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id)
: ISceneNode(parent, mgr, id)
{
#ifdef _DEBUG
setDebugName("CEmptySceneNode");
#endif
setAutomaticCulling(scene::EAC_OFF);
}
//! pre render event
void CEmptySceneNode::OnRegisterSceneNode()
{
if (IsVisible)
SceneManager->registerNodeForRendering(this);
ISceneNode::OnRegisterSceneNode();
}
//! render
void CEmptySceneNode::render()
{
// do nothing
}
//! returns the axis aligned bounding box of this node
const core::aabbox3d<f32>& CEmptySceneNode::getBoundingBox() const
{
return Box;
}
//! Creates a clone of this scene node and its children.
ISceneNode* CEmptySceneNode::clone(ISceneNode* newParent, ISceneManager* newManager)
{
if (!newParent)
newParent = Parent;
if (!newManager)
newManager = SceneManager;
CEmptySceneNode* nb = new CEmptySceneNode(newParent,
newManager, ID);
nb->cloneMembers(this, newManager);
nb->Box = Box;
if ( newParent )
nb->drop();
return nb;
}
} // end namespace scene
} // end namespace irr

View File

@ -0,0 +1,46 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_EMPTY_SCENE_NODE_H_INCLUDED__
#define __C_EMPTY_SCENE_NODE_H_INCLUDED__
#include "ISceneNode.h"
namespace irr
{
namespace scene
{
class CEmptySceneNode : public ISceneNode
{
public:
//! constructor
CEmptySceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id);
//! returns the axis aligned bounding box of this node
virtual const core::aabbox3d<f32>& getBoundingBox() const _IRR_OVERRIDE_;
//! This method is called just before the rendering process of the whole scene.
virtual void OnRegisterSceneNode() _IRR_OVERRIDE_;
//! does nothing.
virtual void render() _IRR_OVERRIDE_;
//! Returns type of the scene node
virtual ESCENE_NODE_TYPE getType() const _IRR_OVERRIDE_ { return ESNT_EMPTY; }
//! Creates a clone of this scene node and its children.
virtual ISceneNode* clone(ISceneNode* newParent=0, ISceneManager* newManager=0) _IRR_OVERRIDE_;
private:
core::aabbox3d<f32> Box;
};
} // end namespace scene
} // end namespace irr
#endif

View File

@ -0,0 +1,76 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CFPSCounter.h"
#include "irrMath.h"
namespace irr
{
namespace video
{
CFPSCounter::CFPSCounter()
: FPS(60), Primitive(0), StartTime(0), FramesCounted(0),
PrimitivesCounted(0), PrimitiveAverage(0), PrimitiveTotal(0)
{
}
//! returns current fps
s32 CFPSCounter::getFPS() const
{
return FPS;
}
//! returns current primitive count
u32 CFPSCounter::getPrimitive() const
{
return Primitive;
}
//! returns average primitive count of last period
u32 CFPSCounter::getPrimitiveAverage() const
{
return PrimitiveAverage;
}
//! returns accumulated primitive count since start
u32 CFPSCounter::getPrimitiveTotal() const
{
return PrimitiveTotal;
}
//! to be called every frame
void CFPSCounter::registerFrame(u32 now, u32 primitivesDrawn)
{
++FramesCounted;
PrimitiveTotal += primitivesDrawn;
PrimitivesCounted += primitivesDrawn;
Primitive = primitivesDrawn;
const u32 milliseconds = now - StartTime;
if (milliseconds >= 1500 )
{
const f32 invMilli = core::reciprocal ( (f32) milliseconds );
FPS = core::ceil32 ( ( 1000 * FramesCounted ) * invMilli );
PrimitiveAverage = core::ceil32 ( ( 1000 * PrimitivesCounted ) * invMilli );
FramesCounted = 0;
PrimitivesCounted = 0;
StartTime = now;
}
}
} // end namespace video
} // end namespace irr

View File

@ -0,0 +1,54 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_FPSCOUNTER_H_INCLUDED__
#define __C_FPSCOUNTER_H_INCLUDED__
#include "irrTypes.h"
namespace irr
{
namespace video
{
class CFPSCounter
{
public:
CFPSCounter();
//! returns current fps
s32 getFPS() const;
//! returns primitive count
u32 getPrimitive() const;
//! returns average primitive count of last period
u32 getPrimitiveAverage() const;
//! returns accumulated primitive count since start
u32 getPrimitiveTotal() const;
//! to be called every frame
void registerFrame(u32 now, u32 primitive);
private:
s32 FPS;
u32 Primitive;
u32 StartTime;
u32 FramesCounted;
u32 PrimitivesCounted;
u32 PrimitiveAverage;
u32 PrimitiveTotal;
};
} // end namespace video
} // end namespace irr
#endif

View File

@ -0,0 +1,163 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CFileList.h"
#include "IrrCompileConfig.h"
#include "irrArray.h"
#include "coreutil.h"
#include "os.h"
namespace irr
{
namespace io
{
static const io::path emptyFileListEntry;
CFileList::CFileList(const io::path& path, bool ignoreCase, bool ignorePaths)
: IgnorePaths(ignorePaths), IgnoreCase(ignoreCase), Path(path)
{
#ifdef _DEBUG
setDebugName("CFileList");
#endif
Path.replace('\\', '/');
}
CFileList::~CFileList()
{
Files.clear();
}
u32 CFileList::getFileCount() const
{
return Files.size();
}
void CFileList::sort()
{
Files.sort();
}
const io::path& CFileList::getFileName(u32 index) const
{
if (index >= Files.size())
return emptyFileListEntry;
return Files[index].Name;
}
//! Gets the full name of a file in the list, path included, based on an index.
const io::path& CFileList::getFullFileName(u32 index) const
{
if (index >= Files.size())
return emptyFileListEntry;
return Files[index].FullName;
}
//! adds a file or folder
u32 CFileList::addItem(const io::path& fullPath, u32 offset, u32 size, bool isDirectory, u32 id)
{
SFileListEntry entry;
entry.ID = id ? id : Files.size();
entry.Offset = offset;
entry.Size = size;
entry.Name = fullPath;
entry.Name.replace('\\', '/');
entry.IsDirectory = isDirectory;
// remove trailing slash
if (entry.Name.lastChar() == '/')
{
entry.IsDirectory = true;
entry.Name[entry.Name.size()-1] = 0;
entry.Name.validate();
}
if (IgnoreCase)
entry.Name.make_lower();
entry.FullName = entry.Name;
core::deletePathFromFilename(entry.Name);
if (IgnorePaths)
entry.FullName = entry.Name;
//os::Printer::log(Path.c_str(), entry.FullName);
Files.push_back(entry);
return Files.size() - 1;
}
//! Returns the ID of a file in the file list, based on an index.
u32 CFileList::getID(u32 index) const
{
return index < Files.size() ? Files[index].ID : 0;
}
bool CFileList::isDirectory(u32 index) const
{
bool ret = false;
if (index < Files.size())
ret = Files[index].IsDirectory;
return ret;
}
//! Returns the size of a file
u32 CFileList::getFileSize(u32 index) const
{
return index < Files.size() ? Files[index].Size : 0;
}
u32 CFileList::getFileOffset(u32 index) const
{
return index < Files.size() ? Files[index].Offset : 0;
}
//! Searches for a file or folder within the list, returns the index
s32 CFileList::findFile(const io::path& filename, bool isDirectory = false) const
{
SFileListEntry entry;
// we only need FullName to be set for the search
entry.FullName = filename;
entry.IsDirectory = isDirectory;
// exchange
entry.FullName.replace('\\', '/');
// remove trailing slash
if (entry.FullName.lastChar() == '/')
{
entry.IsDirectory = true;
entry.FullName[entry.FullName.size()-1] = 0;
entry.FullName.validate();
}
if (IgnoreCase)
entry.FullName.make_lower();
if (IgnorePaths)
core::deletePathFromFilename(entry.FullName);
return Files.binary_search(entry);
}
//! Returns the base path of the file list
const io::path& CFileList::getPath() const
{
return Path;
}
} // end namespace irr
} // end namespace io

138
source/Irrlicht/CFileList.h Normal file
View File

@ -0,0 +1,138 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_FILE_LIST_H_INCLUDED__
#define __C_FILE_LIST_H_INCLUDED__
#include "IFileList.h"
#include "irrString.h"
#include "irrArray.h"
namespace irr
{
namespace io
{
//! An entry in a list of files, can be a folder or a file.
struct SFileListEntry
{
//! The name of the file
/** If this is a file or folder in the virtual filesystem and the archive
was created with the ignoreCase flag then the file name will be lower case. */
io::path Name;
//! The name of the file including the path
/** If this is a file or folder in the virtual filesystem and the archive was
created with the ignoreDirs flag then it will be the same as Name. */
io::path FullName;
//! The size of the file in bytes
u32 Size;
//! The ID of the file in an archive
/** This is used to link the FileList entry to extra info held about this
file in an archive, which can hold things like data offset and CRC. */
u32 ID;
//! FileOffset inside an archive
u32 Offset;
//! True if this is a folder, false if not.
bool IsDirectory;
//! The == operator is provided so that CFileList can slowly search the list!
bool operator ==(const struct SFileListEntry& other) const
{
if (IsDirectory != other.IsDirectory)
return false;
return FullName.equals_ignore_case(other.FullName);
}
//! The < operator is provided so that CFileList can sort and quickly search the list.
bool operator <(const struct SFileListEntry& other) const
{
if (IsDirectory != other.IsDirectory)
return IsDirectory;
return FullName.lower_ignore_case(other.FullName);
}
};
//! Implementation of a file list
class CFileList : public IFileList
{
public:
// CFileList methods
//! Constructor
/** \param path The path of this file archive */
CFileList(const io::path& path, bool ignoreCase, bool ignorePaths);
//! Destructor
virtual ~CFileList();
//! Add as a file or folder to the list
/** \param fullPath The file name including path, up to the root of the file list.
\param isDirectory True if this is a directory rather than a file.
\param offset The offset where the file is stored in an archive
\param size The size of the file in bytes.
\param id The ID of the file in the archive which owns it */
virtual u32 addItem(const io::path& fullPath, u32 offset, u32 size, bool isDirectory, u32 id=0) _IRR_OVERRIDE_;
//! Sorts the file list. You should call this after adding any items to the file list
virtual void sort() _IRR_OVERRIDE_;
//! Returns the amount of files in the filelist.
virtual u32 getFileCount() const _IRR_OVERRIDE_;
//! Gets the name of a file in the list, based on an index.
virtual const io::path& getFileName(u32 index) const _IRR_OVERRIDE_;
//! Gets the full name of a file in the list, path included, based on an index.
virtual const io::path& getFullFileName(u32 index) const _IRR_OVERRIDE_;
//! Returns the ID of a file in the file list, based on an index.
virtual u32 getID(u32 index) const _IRR_OVERRIDE_;
//! Returns true if the file is a directory
virtual bool isDirectory(u32 index) const _IRR_OVERRIDE_;
//! Returns the size of a file
virtual u32 getFileSize(u32 index) const _IRR_OVERRIDE_;
//! Returns the offset of a file
virtual u32 getFileOffset(u32 index) const _IRR_OVERRIDE_;
//! Searches for a file or folder within the list, returns the index
virtual s32 findFile(const io::path& filename, bool isFolder) const _IRR_OVERRIDE_;
//! Returns the base path of the file list
virtual const io::path& getPath() const _IRR_OVERRIDE_;
protected:
//! Ignore paths when adding or searching for files
bool IgnorePaths;
//! Ignore case when adding or searching for files
bool IgnoreCase;
//! Path to the file list
io::path Path;
//! List of files
core::array<SFileListEntry> Files;
};
} // end namespace irr
} // end namespace io
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,179 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_FILE_SYSTEM_H_INCLUDED__
#define __C_FILE_SYSTEM_H_INCLUDED__
#include "IFileSystem.h"
#include "irrArray.h"
namespace irr
{
namespace io
{
class CZipReader;
class CPakReader;
class CMountPointReader;
/*!
FileSystem which uses normal files and one zipfile
*/
class CFileSystem : public IFileSystem
{
public:
//! constructor
CFileSystem();
//! destructor
virtual ~CFileSystem();
//! opens a file for read access
virtual IReadFile* createAndOpenFile(const io::path& filename) _IRR_OVERRIDE_;
//! Creates an IReadFile interface for accessing memory like a file.
virtual IReadFile* createMemoryReadFile(const void* memory, s32 len, const io::path& fileName, bool deleteMemoryWhenDropped = false) _IRR_OVERRIDE_;
//! Creates an IReadFile interface for accessing files inside files
virtual IReadFile* createLimitReadFile(const io::path& fileName, IReadFile* alreadyOpenedFile, long pos, long areaSize) _IRR_OVERRIDE_;
//! Creates an IWriteFile interface for accessing memory like a file.
virtual IWriteFile* createMemoryWriteFile(void* memory, s32 len, const io::path& fileName, bool deleteMemoryWhenDropped=false) _IRR_OVERRIDE_;
//! Opens a file for write access.
virtual IWriteFile* createAndWriteFile(const io::path& filename, bool append=false) _IRR_OVERRIDE_;
//! Adds an archive to the file system.
virtual bool addFileArchive(const io::path& filename,
bool ignoreCase = true, bool ignorePaths = true,
E_FILE_ARCHIVE_TYPE archiveType = EFAT_UNKNOWN,
const core::stringc& password="",
IFileArchive** retArchive = 0) _IRR_OVERRIDE_;
//! Adds an archive to the file system.
virtual bool addFileArchive(IReadFile* file, bool ignoreCase=true,
bool ignorePaths=true,
E_FILE_ARCHIVE_TYPE archiveType=EFAT_UNKNOWN,
const core::stringc& password="",
IFileArchive** retArchive = 0) _IRR_OVERRIDE_;
//! Adds an archive to the file system.
virtual bool addFileArchive(IFileArchive* archive) _IRR_OVERRIDE_;
//! move the hirarchy of the filesystem. moves sourceIndex relative up or down
virtual bool moveFileArchive(u32 sourceIndex, s32 relative) _IRR_OVERRIDE_;
//! Adds an external archive loader to the engine.
virtual void addArchiveLoader(IArchiveLoader* loader) _IRR_OVERRIDE_;
//! Returns the total number of archive loaders added.
virtual u32 getArchiveLoaderCount() const _IRR_OVERRIDE_;
//! Gets the archive loader by index.
virtual IArchiveLoader* getArchiveLoader(u32 index) const _IRR_OVERRIDE_;
//! gets the file archive count
virtual u32 getFileArchiveCount() const _IRR_OVERRIDE_;
//! gets an archive
virtual IFileArchive* getFileArchive(u32 index) _IRR_OVERRIDE_;
//! removes an archive from the file system.
virtual bool removeFileArchive(u32 index) _IRR_OVERRIDE_;
//! removes an archive from the file system.
virtual bool removeFileArchive(const io::path& filename) _IRR_OVERRIDE_;
//! Removes an archive from the file system.
virtual bool removeFileArchive(const IFileArchive* archive) _IRR_OVERRIDE_;
//! Returns the string of the current working directory
virtual const io::path& getWorkingDirectory() _IRR_OVERRIDE_;
//! Changes the current Working Directory to the string given.
//! The string is operating system dependent. Under Windows it will look
//! like this: "drive:\directory\sudirectory\"
virtual bool changeWorkingDirectoryTo(const io::path& newDirectory) _IRR_OVERRIDE_;
//! Converts a relative path to an absolute (unique) path, resolving symbolic links
virtual io::path getAbsolutePath(const io::path& filename) const _IRR_OVERRIDE_;
//! Returns the directory a file is located in.
/** \param filename: The file to get the directory from */
virtual io::path getFileDir(const io::path& filename) const _IRR_OVERRIDE_;
//! Returns the base part of a filename, i.e. the name without the directory
//! part. If no directory is prefixed, the full name is returned.
/** \param filename: The file to get the basename from */
virtual io::path getFileBasename(const io::path& filename, bool keepExtension=true) const _IRR_OVERRIDE_;
//! flatten a path and file name for example: "/you/me/../." becomes "/you"
virtual io::path& flattenFilename( io::path& directory, const io::path& root = "/" ) const _IRR_OVERRIDE_;
//! Get the relative filename, relative to the given directory
virtual path getRelativeFilename(const path& filename, const path& directory) const _IRR_OVERRIDE_;
virtual EFileSystemType setFileListSystem(EFileSystemType listType) _IRR_OVERRIDE_;
//! Creates a list of files and directories in the current working directory
//! and returns it.
virtual IFileList* createFileList() _IRR_OVERRIDE_;
//! Creates an empty filelist
virtual IFileList* createEmptyFileList(const io::path& path, bool ignoreCase, bool ignorePaths) _IRR_OVERRIDE_;
//! determines if a file exists and would be able to be opened.
virtual bool existFile(const io::path& filename) const _IRR_OVERRIDE_;
//! Creates a XML Reader from a file.
virtual IXMLReader* createXMLReader(const io::path& filename) _IRR_OVERRIDE_;
//! Creates a XML Reader from a file.
virtual IXMLReader* createXMLReader(IReadFile* file) _IRR_OVERRIDE_;
//! Creates a XML Reader from a file.
virtual IXMLReaderUTF8* createXMLReaderUTF8(const io::path& filename) _IRR_OVERRIDE_;
//! Creates a XML Reader from a file.
virtual IXMLReaderUTF8* createXMLReaderUTF8(IReadFile* file) _IRR_OVERRIDE_;
//! Creates a XML Writer from a file.
virtual IXMLWriter* createXMLWriter(const io::path& filename) _IRR_OVERRIDE_;
//! Creates a XML Writer from a file.
virtual IXMLWriter* createXMLWriter(IWriteFile* file) _IRR_OVERRIDE_;
//! Creates a XML Writer from a file which will write ASCII/UTF-8 characters (char*).
virtual IXMLWriterUTF8* createXMLWriterUTF8(const path& filename) _IRR_OVERRIDE_;
//! Creates a XML Writer from a file which will write ASCII/UTF-8 characters (char*).
virtual IXMLWriterUTF8* createXMLWriterUTF8(IWriteFile* file) _IRR_OVERRIDE_;
//! Creates a new empty collection of attributes, usable for serialization and more.
virtual IAttributes* createEmptyAttributes(video::IVideoDriver* driver) _IRR_OVERRIDE_;
private:
// don't expose, needs refactoring
bool changeArchivePassword(const path& filename,
const core::stringc& password,
IFileArchive** archive = 0);
//! Currently used FileSystemType
EFileSystemType FileSystemType;
//! WorkingDirectory for Native and Virtual filesystems
io::path WorkingDirectory [2];
//! currently attached ArchiveLoaders
core::array<IArchiveLoader*> ArchiveLoader;
//! currently attached Archives
core::array<IFileArchive*> FileArchives;
};
} // end namespace irr
} // end namespace io
#endif

View File

@ -0,0 +1,436 @@
// Copyright (C) 2013 Christian Stehno
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in Irrlicht.h
#include "CGLXManager.h"
#ifdef _IRR_COMPILE_WITH_GLX_MANAGER_
#include "os.h"
#if defined(_IRR_OPENGL_USE_EXTPOINTER_)
#define GL_GLEXT_LEGACY 1
#define GLX_GLXEXT_LEGACY 1
#else
#define GL_GLEXT_PROTOTYPES 1
#define GLX_GLXEXT_PROTOTYPES 1
#endif
#include <GL/gl.h>
#include <GL/glx.h>
#if defined(_IRR_OPENGL_USE_EXTPOINTER_)
#include "glext.h"
#undef GLX_ARB_get_proc_address // avoid problems with local glxext.h
#include "glxext.h"
#endif
namespace irr
{
namespace video
{
CGLXManager::CGLXManager(const SIrrlichtCreationParameters& params, const SExposedVideoData& videodata, int screennr)
: Params(params), PrimaryContext(videodata), VisualInfo(0), glxFBConfig(0), GlxWin(0)
{
#ifdef _DEBUG
setDebugName("CGLXManager");
#endif
CurrentContext.OpenGLLinux.X11Display=PrimaryContext.OpenGLLinux.X11Display;
int major, minor;
Display* display = (Display*)PrimaryContext.OpenGLLinux.X11Display;
const bool isAvailableGLX=glXQueryExtension(display,&major,&minor);
if (isAvailableGLX && glXQueryVersion(display, &major, &minor))
{
#if defined(GLX_VERSION_1_3)
typedef GLXFBConfig * ( * PFNGLXCHOOSEFBCONFIGPROC) (Display *dpy, int screen, const int *attrib_list, int *nelements);
#ifdef _IRR_OPENGL_USE_EXTPOINTER_
PFNGLXCHOOSEFBCONFIGPROC glxChooseFBConfig = (PFNGLXCHOOSEFBCONFIGPROC)glXGetProcAddress(reinterpret_cast<const GLubyte*>("glXChooseFBConfig"));
#else
PFNGLXCHOOSEFBCONFIGPROC glxChooseFBConfig=glXChooseFBConfig;
#endif
if (major==1 && minor>2 && glxChooseFBConfig)
{
os::Printer::log("GLX >= 1.3", ELL_DEBUG);
// attribute array for the draw buffer
int visualAttrBuffer[] =
{
GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_RED_SIZE, 4,
GLX_GREEN_SIZE, 4,
GLX_BLUE_SIZE, 4,
GLX_ALPHA_SIZE, Params.WithAlphaChannel?1:0,
GLX_DEPTH_SIZE, Params.ZBufferBits, //10,11
GLX_DOUBLEBUFFER, Params.Doublebuffer?True:False,
GLX_STENCIL_SIZE, Params.Stencilbuffer?1:0,
#if defined(GLX_VERSION_1_4) && defined(GLX_SAMPLE_BUFFERS) // we need to check the extension string!
GLX_SAMPLE_BUFFERS, 1,
GLX_SAMPLES, Params.AntiAlias, // 18,19
#elif defined(GLX_ARB_multisample)
GLX_SAMPLE_BUFFERS_ARB, 1,
GLX_SAMPLES_ARB, Params.AntiAlias, // 18,19
#elif defined(GLX_SGIS_multisample)
GLX_SAMPLE_BUFFERS_SGIS, 1,
GLX_SAMPLES_SGIS, Params.AntiAlias, // 18,19
#endif
//#ifdef GL_ARB_framebuffer_sRGB
// GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, Params.HandleSRGB,
//#elif defined(GL_EXT_framebuffer_sRGB)
// GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT, Params.HandleSRGB,
//#endif
GLX_STEREO, Params.Stereobuffer?True:False,
None
};
GLXFBConfig *configList=0;
int nitems=0;
if (Params.AntiAlias<2)
{
visualAttrBuffer[17] = 0;
visualAttrBuffer[19] = 0;
}
// first round with unchanged values
{
configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems);
if (!configList && Params.AntiAlias)
{
while (!configList && (visualAttrBuffer[19]>1))
{
visualAttrBuffer[19] -= 1;
configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems);
}
if (!configList)
{
visualAttrBuffer[17] = 0;
visualAttrBuffer[19] = 0;
configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems);
if (configList)
{
os::Printer::log("No FSAA available.", ELL_WARNING);
Params.AntiAlias=0;
}
else
{
//reenable multisampling
visualAttrBuffer[17] = 1;
visualAttrBuffer[19] = Params.AntiAlias;
}
}
}
}
// Next try with flipped stencil buffer value
// If the first round was with stencil flag it's now without
// Other way round also makes sense because some configs
// only have depth buffer combined with stencil buffer
if (!configList)
{
if (Params.Stencilbuffer)
os::Printer::log("No stencilbuffer available, disabling stencil shadows.", ELL_WARNING);
Params.Stencilbuffer = !Params.Stencilbuffer;
visualAttrBuffer[15]=Params.Stencilbuffer?1:0;
configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems);
if (!configList && Params.AntiAlias)
{
while (!configList && (visualAttrBuffer[19]>1))
{
visualAttrBuffer[19] -= 1;
configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems);
}
if (!configList)
{
visualAttrBuffer[17] = 0;
visualAttrBuffer[19] = 0;
configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems);
if (configList)
{
os::Printer::log("No FSAA available.", ELL_WARNING);
Params.AntiAlias=0;
}
else
{
//reenable multisampling
visualAttrBuffer[17] = 1;
visualAttrBuffer[19] = Params.AntiAlias;
}
}
}
}
// Next try without double buffer
if (!configList && Params.Doublebuffer)
{
os::Printer::log("No doublebuffering available.", ELL_WARNING);
Params.Doublebuffer=false;
visualAttrBuffer[13] = GLX_DONT_CARE;
Params.Stencilbuffer = false;
visualAttrBuffer[15]=0;
configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems);
if (!configList && Params.AntiAlias)
{
while (!configList && (visualAttrBuffer[19]>1))
{
visualAttrBuffer[19] -= 1;
configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems);
}
if (!configList)
{
visualAttrBuffer[17] = 0;
visualAttrBuffer[19] = 0;
configList=glxChooseFBConfig(display, screennr, visualAttrBuffer,&nitems);
if (configList)
{
os::Printer::log("No FSAA available.", ELL_WARNING);
Params.AntiAlias=0;
}
else
{
//reenable multisampling
visualAttrBuffer[17] = 1;
visualAttrBuffer[19] = Params.AntiAlias;
}
}
}
}
if (configList)
{
glxFBConfig=configList[0];
XFree(configList);
#ifdef _IRR_OPENGL_USE_EXTPOINTER_
typedef XVisualInfo * ( * PFNGLXGETVISUALFROMFBCONFIGPROC) (Display *dpy, GLXFBConfig config);
PFNGLXGETVISUALFROMFBCONFIGPROC glxGetVisualFromFBConfig= (PFNGLXGETVISUALFROMFBCONFIGPROC)glXGetProcAddress(reinterpret_cast<const GLubyte*>("glXGetVisualFromFBConfig"));
if (glxGetVisualFromFBConfig)
VisualInfo = glxGetVisualFromFBConfig(display,(GLXFBConfig)glxFBConfig);
#else
VisualInfo = glXGetVisualFromFBConfig(display,(GLXFBConfig)glxFBConfig);
#endif
}
}
else
#endif
{
// attribute array for the draw buffer
int visualAttrBuffer[] =
{
GLX_RGBA, GLX_USE_GL,
GLX_RED_SIZE, 4,
GLX_GREEN_SIZE, 4,
GLX_BLUE_SIZE, 4,
GLX_ALPHA_SIZE, Params.WithAlphaChannel?1:0,
GLX_DEPTH_SIZE, Params.ZBufferBits,
GLX_STENCIL_SIZE, Params.Stencilbuffer?1:0, // 12,13
// The following attributes have no flags, but are
// either present or not. As a no-op we use
// GLX_USE_GL, which is silently ignored by glXChooseVisual
Params.Doublebuffer?GLX_DOUBLEBUFFER:GLX_USE_GL, // 14
Params.Stereobuffer?GLX_STEREO:GLX_USE_GL, // 15
//#ifdef GL_ARB_framebuffer_sRGB
// Params.HandleSRGB?GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB:GLX_USE_GL,
//#elif defined(GL_EXT_framebuffer_sRGB)
// Params.HandleSRGB?GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT:GLX_USE_GL,
//#endif
None
};
VisualInfo=glXChooseVisual(display, screennr, visualAttrBuffer);
if (!VisualInfo)
{
if (Params.Stencilbuffer)
os::Printer::log("No stencilbuffer available, disabling.", ELL_WARNING);
Params.Stencilbuffer = !Params.Stencilbuffer;
visualAttrBuffer[13]=Params.Stencilbuffer?1:0;
VisualInfo=glXChooseVisual(display, screennr, visualAttrBuffer);
if (!VisualInfo && Params.Doublebuffer)
{
os::Printer::log("No doublebuffering available.", ELL_WARNING);
Params.Doublebuffer=false;
visualAttrBuffer[14] = GLX_USE_GL;
VisualInfo=glXChooseVisual(display, screennr, visualAttrBuffer);
}
}
}
}
else
os::Printer::log("No GLX support available. OpenGL driver will not work.", ELL_WARNING);
}
CGLXManager::~CGLXManager()
{
}
bool CGLXManager::initialize(const SIrrlichtCreationParameters& params, const SExposedVideoData& videodata)
{
// store params
Params=params;
// set display
CurrentContext.OpenGLLinux.X11Display=videodata.OpenGLLinux.X11Display;
// now get new window
CurrentContext.OpenGLLinux.X11Window=videodata.OpenGLLinux.X11Window;
if (!PrimaryContext.OpenGLLinux.X11Window)
{
PrimaryContext.OpenGLLinux.X11Window=CurrentContext.OpenGLLinux.X11Window;
}
return true;
}
void CGLXManager::terminate()
{
memset(&CurrentContext, 0, sizeof(CurrentContext));
}
bool CGLXManager::generateSurface()
{
if (glxFBConfig)
{
GlxWin=glXCreateWindow((Display*)CurrentContext.OpenGLLinux.X11Display,(GLXFBConfig)glxFBConfig,CurrentContext.OpenGLLinux.X11Window,NULL);
if (!GlxWin)
{
os::Printer::log("Could not create GLX window.", ELL_WARNING);
return false;
}
CurrentContext.OpenGLLinux.X11Window=GlxWin;
}
return true;
}
void CGLXManager::destroySurface()
{
if (GlxWin)
glXDestroyWindow((Display*)CurrentContext.OpenGLLinux.X11Display, GlxWin);
}
bool CGLXManager::generateContext()
{
GLXContext context;
if (glxFBConfig)
{
if (GlxWin)
{
// create glx context
context = glXCreateNewContext((Display*)CurrentContext.OpenGLLinux.X11Display, (GLXFBConfig)glxFBConfig, GLX_RGBA_TYPE, NULL, True);
if (!context)
{
os::Printer::log("Could not create GLX rendering context.", ELL_WARNING);
return false;
}
}
else
{
os::Printer::log("GLX window was not properly created.", ELL_WARNING);
return false;
}
}
else
{
context = glXCreateContext((Display*)CurrentContext.OpenGLLinux.X11Display, VisualInfo, NULL, True);
if (!context)
{
os::Printer::log("Could not create GLX rendering context.", ELL_WARNING);
return false;
}
}
CurrentContext.OpenGLLinux.X11Context=context;
return true;
}
const SExposedVideoData& CGLXManager::getContext() const
{
return CurrentContext;
}
bool CGLXManager::activateContext(const SExposedVideoData& videoData, bool restorePrimaryOnZero)
{
//TODO: handle restorePrimaryOnZero
if (videoData.OpenGLLinux.X11Window)
{
if (videoData.OpenGLLinux.X11Display && videoData.OpenGLLinux.X11Context)
{
if (!glXMakeCurrent((Display*)videoData.OpenGLLinux.X11Display, videoData.OpenGLLinux.X11Window, (GLXContext)videoData.OpenGLLinux.X11Context))
{
os::Printer::log("Context activation failed.");
return false;
}
else
{
CurrentContext.OpenGLLinux.X11Window = videoData.OpenGLLinux.X11Window;
CurrentContext.OpenGLLinux.X11Display = videoData.OpenGLLinux.X11Display;
}
}
else
{
// in case we only got a window ID, try with the existing values for display and context
if (!glXMakeCurrent((Display*)PrimaryContext.OpenGLLinux.X11Display, videoData.OpenGLLinux.X11Window, (GLXContext)PrimaryContext.OpenGLLinux.X11Context))
{
os::Printer::log("Context activation failed.");
return false;
}
else
{
CurrentContext.OpenGLLinux.X11Window = videoData.OpenGLLinux.X11Window;
CurrentContext.OpenGLLinux.X11Display = PrimaryContext.OpenGLLinux.X11Display;
}
}
}
else if (!restorePrimaryOnZero && !videoData.OpenGLLinux.X11Window && !videoData.OpenGLLinux.X11Display)
{
if (!glXMakeCurrent((Display*)PrimaryContext.OpenGLLinux.X11Display, None, NULL))
{
os::Printer::log("Render Context reset failed.");
return false;
}
CurrentContext.OpenGLLinux.X11Window = 0;
CurrentContext.OpenGLLinux.X11Display = 0;
}
// set back to main context
else if (CurrentContext.OpenGLLinux.X11Display != PrimaryContext.OpenGLLinux.X11Display)
{
if (!glXMakeCurrent((Display*)PrimaryContext.OpenGLLinux.X11Display, PrimaryContext.OpenGLLinux.X11Window, (GLXContext)PrimaryContext.OpenGLLinux.X11Context))
{
os::Printer::log("Context activation failed.");
return false;
}
else
{
CurrentContext = PrimaryContext;
}
}
return true;
}
void CGLXManager::destroyContext()
{
if (CurrentContext.OpenGLLinux.X11Context)
{
if (GlxWin)
{
if (!glXMakeContextCurrent((Display*)CurrentContext.OpenGLLinux.X11Display, None, None, NULL))
os::Printer::log("Could not release glx context.", ELL_WARNING);
}
else
{
if (!glXMakeCurrent((Display*)CurrentContext.OpenGLLinux.X11Display, None, NULL))
os::Printer::log("Could not release glx context.", ELL_WARNING);
}
glXDestroyContext((Display*)CurrentContext.OpenGLLinux.X11Display, (GLXContext)CurrentContext.OpenGLLinux.X11Context);
}
}
bool CGLXManager::swapBuffers()
{
glXSwapBuffers((Display*)CurrentContext.OpenGLLinux.X11Display, CurrentContext.OpenGLLinux.X11Window);
return true;
}
}
}
#endif

View File

@ -0,0 +1,79 @@
// Copyright (C) 2013 Christian Stehno
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in Irrlicht.h
#ifndef __C_GLX_MANAGER_H_INCLUDED__
#define __C_GLX_MANAGER_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_GLX_MANAGER_
#include "SIrrCreationParameters.h"
#include "SExposedVideoData.h"
#include "IContextManager.h"
#include "SColor.h"
#include <X11/Xlib.h>
#include <X11/Xutil.h>
// we can't include glx.h here, because gl.h has incompatible types with ogl es headers and it
// cause redefinition errors, thats why we use ugly trick with void* types and casts.
namespace irr
{
namespace video
{
// GLX manager.
class CGLXManager : public IContextManager
{
public:
//! Constructor.
CGLXManager(const SIrrlichtCreationParameters& params, const SExposedVideoData& videodata, int screennr);
//! Destructor
~CGLXManager();
// Initialize
virtual bool initialize(const SIrrlichtCreationParameters& params, const SExposedVideoData& data) _IRR_OVERRIDE_;
// Terminate
virtual void terminate() _IRR_OVERRIDE_;
// Create surface.
virtual bool generateSurface() _IRR_OVERRIDE_;
// Destroy surface.
virtual void destroySurface() _IRR_OVERRIDE_;
// Create context.
virtual bool generateContext() _IRR_OVERRIDE_;
// Destroy context.
virtual void destroyContext() _IRR_OVERRIDE_;
//! Get current context
virtual const SExposedVideoData& getContext() const _IRR_OVERRIDE_;
//! Change render context, disable old and activate new defined by videoData
virtual bool activateContext(const SExposedVideoData& videoData, bool restorePrimaryOnZero) _IRR_OVERRIDE_;
// Swap buffers.
virtual bool swapBuffers() _IRR_OVERRIDE_;
XVisualInfo* getVisual() const {return VisualInfo;} // return XVisualInfo
private:
SIrrlichtCreationParameters Params;
SExposedVideoData PrimaryContext;
SExposedVideoData CurrentContext;
XVisualInfo* VisualInfo;
void* glxFBConfig; // GLXFBConfig
XID GlxWin; // GLXWindow
};
}
}
#endif
#endif

View File

@ -0,0 +1,650 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CGUIButton.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUISkin.h"
#include "IGUIEnvironment.h"
#include "IVideoDriver.h"
#include "IGUIFont.h"
#include "os.h"
namespace irr
{
namespace gui
{
//! constructor
CGUIButton::CGUIButton(IGUIEnvironment* environment, IGUIElement* parent,
s32 id, core::rect<s32> rectangle, bool noclip)
: IGUIButton(environment, parent, id, rectangle),
SpriteBank(0), OverrideFont(0),
OverrideColorEnabled(false), OverrideColor(video::SColor(101,255,255,255)),
ClickTime(0), HoverTime(0), FocusTime(0),
ClickShiftState(false), ClickControlState(false),
IsPushButton(false), Pressed(false),
UseAlphaChannel(false), DrawBorder(true), ScaleImage(false)
{
#ifdef _DEBUG
setDebugName("CGUIButton");
#endif
setNotClipped(noclip);
// This element can be tabbed.
setTabStop(true);
setTabOrder(-1);
}
//! destructor
CGUIButton::~CGUIButton()
{
if (OverrideFont)
OverrideFont->drop();
if (SpriteBank)
SpriteBank->drop();
}
//! Sets if the images should be scaled to fit the button
void CGUIButton::setScaleImage(bool scaleImage)
{
ScaleImage = scaleImage;
}
//! Returns whether the button scale the used images
bool CGUIButton::isScalingImage() const
{
return ScaleImage;
}
//! Sets if the button should use the skin to draw its border
void CGUIButton::setDrawBorder(bool border)
{
DrawBorder = border;
}
void CGUIButton::setSpriteBank(IGUISpriteBank* sprites)
{
if (sprites)
sprites->grab();
if (SpriteBank)
SpriteBank->drop();
SpriteBank = sprites;
}
void CGUIButton::setSprite(EGUI_BUTTON_STATE state, s32 index, video::SColor color, bool loop, bool scale)
{
ButtonSprites[(u32)state].Index = index;
ButtonSprites[(u32)state].Color = color;
ButtonSprites[(u32)state].Loop = loop;
ButtonSprites[(u32)state].Scale = scale;
}
//! Get the sprite-index for the given state or -1 when no sprite is set
s32 CGUIButton::getSpriteIndex(EGUI_BUTTON_STATE state) const
{
return ButtonSprites[(u32)state].Index;
}
//! Get the sprite color for the given state. Color is only used when a sprite is set.
video::SColor CGUIButton::getSpriteColor(EGUI_BUTTON_STATE state) const
{
return ButtonSprites[(u32)state].Color;
}
//! Returns if the sprite in the given state does loop
bool CGUIButton::getSpriteLoop(EGUI_BUTTON_STATE state) const
{
return ButtonSprites[(u32)state].Loop;
}
//! Returns if the sprite in the given state is scaled
bool CGUIButton::getSpriteScale(EGUI_BUTTON_STATE state) const
{
return ButtonSprites[(u32)state].Scale;
}
//! called if an event happened.
bool CGUIButton::OnEvent(const SEvent& event)
{
if (!isEnabled())
return IGUIElement::OnEvent(event);
switch(event.EventType)
{
case EET_KEY_INPUT_EVENT:
if (event.KeyInput.PressedDown &&
(event.KeyInput.Key == KEY_RETURN || event.KeyInput.Key == KEY_SPACE))
{
if (!IsPushButton)
setPressed(true);
else
setPressed(!Pressed);
return true;
}
if (Pressed && !IsPushButton && event.KeyInput.PressedDown && event.KeyInput.Key == KEY_ESCAPE)
{
setPressed(false);
return true;
}
else
if (!event.KeyInput.PressedDown && Pressed &&
(event.KeyInput.Key == KEY_RETURN || event.KeyInput.Key == KEY_SPACE))
{
if (!IsPushButton)
setPressed(false);
if (Parent)
{
ClickShiftState = event.KeyInput.Shift;
ClickControlState = event.KeyInput.Control;
SEvent newEvent;
newEvent.EventType = EET_GUI_EVENT;
newEvent.GUIEvent.Caller = this;
newEvent.GUIEvent.Element = 0;
newEvent.GUIEvent.EventType = EGET_BUTTON_CLICKED;
Parent->OnEvent(newEvent);
}
return true;
}
break;
case EET_GUI_EVENT:
if (event.GUIEvent.Caller == this)
{
if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST)
{
if (!IsPushButton)
setPressed(false);
FocusTime = os::Timer::getTime();
}
else if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUSED)
{
FocusTime = os::Timer::getTime();
}
else if (event.GUIEvent.EventType == EGET_ELEMENT_HOVERED || event.GUIEvent.EventType == EGET_ELEMENT_LEFT)
{
HoverTime = os::Timer::getTime();
}
}
break;
case EET_MOUSE_INPUT_EVENT:
if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)
{
if (!IsPushButton)
setPressed(true);
return true;
}
else
if (event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)
{
bool wasPressed = Pressed;
if ( !AbsoluteClippingRect.isPointInside( core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y ) ) )
{
if (!IsPushButton)
setPressed(false);
return true;
}
if (!IsPushButton)
setPressed(false);
else
{
setPressed(!Pressed);
}
if ((!IsPushButton && wasPressed && Parent) ||
(IsPushButton && wasPressed != Pressed))
{
ClickShiftState = event.MouseInput.Shift;
ClickControlState = event.MouseInput.Control;
SEvent newEvent;
newEvent.EventType = EET_GUI_EVENT;
newEvent.GUIEvent.Caller = this;
newEvent.GUIEvent.Element = 0;
newEvent.GUIEvent.EventType = EGET_BUTTON_CLICKED;
Parent->OnEvent(newEvent);
}
return true;
}
break;
default:
break;
}
return Parent ? Parent->OnEvent(event) : false;
}
//! draws the element and its children
void CGUIButton::draw()
{
if (!IsVisible)
return;
IGUISkin* skin = Environment->getSkin();
video::IVideoDriver* driver = Environment->getVideoDriver();
if (DrawBorder)
{
if (!Pressed)
{
skin->draw3DButtonPaneStandard(this, AbsoluteRect, &AbsoluteClippingRect);
}
else
{
skin->draw3DButtonPanePressed(this, AbsoluteRect, &AbsoluteClippingRect);
}
}
const core::position2di buttonCenter(AbsoluteRect.getCenter());
EGUI_BUTTON_IMAGE_STATE imageState = getImageState(Pressed);
if ( ButtonImages[(u32)imageState].Texture )
{
core::position2d<s32> pos(buttonCenter);
core::rect<s32> sourceRect(ButtonImages[(u32)imageState].SourceRect);
if ( sourceRect.getWidth() == 0 && sourceRect.getHeight() == 0 )
sourceRect = core::rect<s32>(core::position2di(0,0), ButtonImages[(u32)imageState].Texture->getOriginalSize());
pos.X -= sourceRect.getWidth() / 2;
pos.Y -= sourceRect.getHeight() / 2;
if ( Pressed )
{
// Create a pressed-down effect by moving the image when it looks identical to the unpressed state image
EGUI_BUTTON_IMAGE_STATE unpressedState = getImageState(false);
if ( unpressedState == imageState || ButtonImages[(u32)imageState] == ButtonImages[(u32)unpressedState] )
{
pos.X += skin->getSize(EGDS_BUTTON_PRESSED_IMAGE_OFFSET_X);
pos.Y += skin->getSize(EGDS_BUTTON_PRESSED_IMAGE_OFFSET_Y);
}
}
driver->draw2DImage(ButtonImages[(u32)imageState].Texture,
ScaleImage? AbsoluteRect : core::rect<s32>(pos, sourceRect.getSize()),
sourceRect, &AbsoluteClippingRect,
0, UseAlphaChannel);
}
if (SpriteBank)
{
core::position2di pos(buttonCenter);
if ( Pressed )
{
pos.X += skin->getSize(EGDS_BUTTON_PRESSED_SPRITE_OFFSET_X);
pos.Y += skin->getSize(EGDS_BUTTON_PRESSED_SPRITE_OFFSET_Y);
}
if (isEnabled())
{
// pressed / unpressed animation
EGUI_BUTTON_STATE state = Pressed ? EGBS_BUTTON_DOWN : EGBS_BUTTON_UP;
drawSprite(state, ClickTime, pos);
// focused / unfocused animation
state = Environment->hasFocus(this) ? EGBS_BUTTON_FOCUSED : EGBS_BUTTON_NOT_FOCUSED;
drawSprite(state, FocusTime, pos);
// mouse over / off animation
state = Environment->getHovered() == this ? EGBS_BUTTON_MOUSE_OVER : EGBS_BUTTON_MOUSE_OFF;
drawSprite(state, HoverTime, pos);
}
else
{
// draw disabled
drawSprite(EGBS_BUTTON_DISABLED, 0, pos);
}
}
if (Text.size())
{
IGUIFont* font = getActiveFont();
core::rect<s32> rect = AbsoluteRect;
if (Pressed)
{
rect.UpperLeftCorner.X += skin->getSize(EGDS_BUTTON_PRESSED_TEXT_OFFSET_X);
rect.UpperLeftCorner.Y += skin->getSize(EGDS_BUTTON_PRESSED_TEXT_OFFSET_Y);
}
if (font)
font->draw(Text.c_str(), rect,
OverrideColorEnabled ? OverrideColor : skin->getColor(isEnabled() ? EGDC_BUTTON_TEXT : EGDC_GRAY_TEXT),
true, true, &AbsoluteClippingRect);
}
IGUIElement::draw();
}
void CGUIButton::drawSprite(EGUI_BUTTON_STATE state, u32 startTime, const core::position2di& center)
{
u32 stateIdx = (u32)state;
if (ButtonSprites[stateIdx].Index != -1)
{
if ( ButtonSprites[stateIdx].Scale )
{
const video::SColor colors[] = {ButtonSprites[stateIdx].Color,ButtonSprites[stateIdx].Color,ButtonSprites[stateIdx].Color,ButtonSprites[stateIdx].Color};
SpriteBank->draw2DSprite(ButtonSprites[stateIdx].Index, AbsoluteRect,
&AbsoluteClippingRect, colors,
os::Timer::getTime()-startTime, ButtonSprites[stateIdx].Loop);
}
else
{
SpriteBank->draw2DSprite(ButtonSprites[stateIdx].Index, center,
&AbsoluteClippingRect, ButtonSprites[stateIdx].Color, startTime, os::Timer::getTime(),
ButtonSprites[stateIdx].Loop, true);
}
}
}
EGUI_BUTTON_IMAGE_STATE CGUIButton::getImageState(bool pressed) const
{
// figure state we should have
EGUI_BUTTON_IMAGE_STATE state = EGBIS_IMAGE_DISABLED;
bool focused = Environment->hasFocus(this);
bool mouseOver = static_cast<const IGUIElement*>(Environment->getHovered()) == this; // (static cast for Borland)
if (isEnabled())
{
if ( pressed )
{
if ( focused && mouseOver )
state = EGBIS_IMAGE_DOWN_FOCUSED_MOUSEOVER;
else if ( focused )
state = EGBIS_IMAGE_DOWN_FOCUSED;
else if ( mouseOver )
state = EGBIS_IMAGE_DOWN_MOUSEOVER;
else
state = EGBIS_IMAGE_DOWN;
}
else // !pressed
{
if ( focused && mouseOver )
state = EGBIS_IMAGE_UP_FOCUSED_MOUSEOVER;
else if ( focused )
state = EGBIS_IMAGE_UP_FOCUSED;
else if ( mouseOver )
state = EGBIS_IMAGE_UP_MOUSEOVER;
else
state = EGBIS_IMAGE_UP;
}
}
// find a compatible state that has images
while ( state != EGBIS_IMAGE_UP && !ButtonImages[(u32)state].Texture )
{
switch ( state )
{
case EGBIS_IMAGE_UP_FOCUSED:
state = EGBIS_IMAGE_UP_MOUSEOVER;
break;
case EGBIS_IMAGE_UP_FOCUSED_MOUSEOVER:
state = EGBIS_IMAGE_UP_FOCUSED;
break;
case EGBIS_IMAGE_DOWN_MOUSEOVER:
state = EGBIS_IMAGE_DOWN;
break;
case EGBIS_IMAGE_DOWN_FOCUSED:
state = EGBIS_IMAGE_DOWN_MOUSEOVER;
break;
case EGBIS_IMAGE_DOWN_FOCUSED_MOUSEOVER:
state = EGBIS_IMAGE_DOWN_FOCUSED;
break;
case EGBIS_IMAGE_DISABLED:
if ( pressed )
state = EGBIS_IMAGE_DOWN;
else
state = EGBIS_IMAGE_UP;
break;
default:
state = EGBIS_IMAGE_UP;
}
}
return state;
}
//! sets another skin independent font. if this is set to zero, the button uses the font of the skin.
void CGUIButton::setOverrideFont(IGUIFont* font)
{
if (OverrideFont == font)
return;
if (OverrideFont)
OverrideFont->drop();
OverrideFont = font;
if (OverrideFont)
OverrideFont->grab();
}
//! Gets the override font (if any)
IGUIFont * CGUIButton::getOverrideFont() const
{
return OverrideFont;
}
//! Get the font which is used right now for drawing
IGUIFont* CGUIButton::getActiveFont() const
{
if ( OverrideFont )
return OverrideFont;
IGUISkin* skin = Environment->getSkin();
if (skin)
return skin->getFont(EGDF_BUTTON);
return 0;
}
//! Sets another color for the text.
void CGUIButton::setOverrideColor(video::SColor color)
{
OverrideColor = color;
OverrideColorEnabled = true;
}
video::SColor CGUIButton::getOverrideColor() const
{
return OverrideColor;
}
void CGUIButton::enableOverrideColor(bool enable)
{
OverrideColorEnabled = enable;
}
bool CGUIButton::isOverrideColorEnabled() const
{
return OverrideColorEnabled;
}
void CGUIButton::setImage(EGUI_BUTTON_IMAGE_STATE state, video::ITexture* image, const core::rect<s32>& sourceRect)
{
if ( state >= EGBIS_COUNT )
return;
if ( image )
image->grab();
u32 stateIdx = (u32)state;
if ( ButtonImages[stateIdx].Texture )
ButtonImages[stateIdx].Texture->drop();
ButtonImages[stateIdx].Texture = image;
ButtonImages[stateIdx].SourceRect = sourceRect;
}
//! Sets if the button should behave like a push button. Which means it
//! can be in two states: Normal or Pressed. With a click on the button,
//! the user can change the state of the button.
void CGUIButton::setIsPushButton(bool isPushButton)
{
IsPushButton = isPushButton;
}
//! Returns if the button is currently pressed
bool CGUIButton::isPressed() const
{
return Pressed;
}
//! Sets the pressed state of the button if this is a pushbutton
void CGUIButton::setPressed(bool pressed)
{
if (Pressed != pressed)
{
ClickTime = os::Timer::getTime();
Pressed = pressed;
}
}
//! Returns whether the button is a push button
bool CGUIButton::isPushButton() const
{
return IsPushButton;
}
//! Sets if the alpha channel should be used for drawing images on the button (default is false)
void CGUIButton::setUseAlphaChannel(bool useAlphaChannel)
{
UseAlphaChannel = useAlphaChannel;
}
//! Returns if the alpha channel should be used for drawing images on the button
bool CGUIButton::isAlphaChannelUsed() const
{
return UseAlphaChannel;
}
bool CGUIButton::isDrawingBorder() const
{
return DrawBorder;
}
//! Writes attributes of the element.
void CGUIButton::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const
{
IGUIButton::serializeAttributes(out,options);
out->addBool ("PushButton", IsPushButton );
if (IsPushButton)
out->addBool("Pressed", Pressed);
for ( u32 i=0; i<(u32)EGBIS_COUNT; ++i )
{
if ( ButtonImages[i].Texture )
{
core::stringc name( GUIButtonImageStateNames[i] );
out->addTexture(name.c_str(), ButtonImages[i].Texture);
name += "Rect";
out->addRect(name.c_str(), ButtonImages[i].SourceRect);
}
}
out->addBool ("UseAlphaChannel", UseAlphaChannel);
out->addBool ("Border", DrawBorder);
out->addBool ("ScaleImage", ScaleImage);
for ( u32 i=0; i<(u32)EGBS_COUNT; ++i )
{
if ( ButtonSprites[i].Index >= 0 )
{
core::stringc nameIndex( GUIButtonStateNames[i] );
nameIndex += "Index";
out->addInt(nameIndex.c_str(), ButtonSprites[i].Index );
core::stringc nameColor( GUIButtonStateNames[i] );
nameColor += "Color";
out->addColor(nameColor.c_str(), ButtonSprites[i].Color );
core::stringc nameLoop( GUIButtonStateNames[i] );
nameLoop += "Loop";
out->addBool(nameLoop.c_str(), ButtonSprites[i].Loop );
core::stringc nameScale( GUIButtonStateNames[i] );
nameScale += "Scale";
out->addBool(nameScale.c_str(), ButtonSprites[i].Scale );
}
}
// out->addString ("OverrideFont", OverrideFont);
}
//! Reads attributes of the element
void CGUIButton::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0)
{
IGUIButton::deserializeAttributes(in,options);
IsPushButton = in->getAttributeAsBool("PushButton", IsPushButton);
Pressed = IsPushButton ? in->getAttributeAsBool("Pressed", Pressed) : false;
for ( u32 i=0; i<(u32)EGBIS_COUNT; ++i )
{
core::stringc nameRect( GUIButtonImageStateNames[i] );
nameRect += "Rect";
setImage((EGUI_BUTTON_IMAGE_STATE)i,
in->getAttributeAsTexture(GUIButtonImageStateNames[i], ButtonImages[i].Texture),
in->getAttributeAsRect(nameRect.c_str(), ButtonImages[i].SourceRect) );
}
setDrawBorder(in->getAttributeAsBool("Border", DrawBorder));
setUseAlphaChannel(in->getAttributeAsBool("UseAlphaChannel", UseAlphaChannel));
setScaleImage(in->getAttributeAsBool("ScaleImage", ScaleImage));
for ( u32 i=0; i<(u32)EGBS_COUNT; ++i )
{
core::stringc nameIndex( GUIButtonStateNames[i] );
nameIndex += "Index";
ButtonSprites[i].Index = in->getAttributeAsInt(nameIndex.c_str(), ButtonSprites[i].Index );
core::stringc nameColor( GUIButtonStateNames[i] );
nameColor += "Color";
ButtonSprites[i].Color = in->getAttributeAsColor(nameColor.c_str(), ButtonSprites[i].Color );
core::stringc nameLoop( GUIButtonStateNames[i] );
nameLoop += "Loop";
ButtonSprites[i].Loop = in->getAttributeAsBool(nameLoop.c_str(), ButtonSprites[i].Loop );
core::stringc nameScale( GUIButtonStateNames[i] );
nameScale += "Scale";
ButtonSprites[i].Scale = in->getAttributeAsBool(nameScale.c_str(), ButtonSprites[i].Scale );
}
// setOverrideFont(in->getAttributeAsString("OverrideFont"));
updateAbsolutePosition();
}
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_

View File

@ -0,0 +1,253 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_GUI_BUTTON_H_INCLUDED__
#define __C_GUI_BUTTON_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUIButton.h"
#include "IGUISpriteBank.h"
#include "ITexture.h"
#include "SColor.h"
namespace irr
{
namespace gui
{
class CGUIButton : public IGUIButton
{
public:
//! constructor
CGUIButton(IGUIEnvironment* environment, IGUIElement* parent,
s32 id, core::rect<s32> rectangle, bool noclip=false);
//! destructor
virtual ~CGUIButton();
//! called if an event happened.
virtual bool OnEvent(const SEvent& event) _IRR_OVERRIDE_;
//! draws the element and its children
virtual void draw() _IRR_OVERRIDE_;
//! sets another skin independent font. if this is set to zero, the button uses the font of the skin.
virtual void setOverrideFont(IGUIFont* font=0) _IRR_OVERRIDE_;
//! Gets the override font (if any)
virtual IGUIFont* getOverrideFont() const _IRR_OVERRIDE_;
//! Get the font which is used right now for drawing
virtual IGUIFont* getActiveFont() const _IRR_OVERRIDE_;
//! Sets another color for the button text.
virtual void setOverrideColor(video::SColor color) _IRR_OVERRIDE_;
//! Gets the override color
virtual video::SColor getOverrideColor(void) const _IRR_OVERRIDE_;
//! Sets if the button text should use the override color or the color in the gui skin.
virtual void enableOverrideColor(bool enable) _IRR_OVERRIDE_;
//! Checks if an override color is enabled
virtual bool isOverrideColorEnabled(void) const _IRR_OVERRIDE_;
//! Sets an image which should be displayed on the button when it is in the given state.
virtual void setImage(EGUI_BUTTON_IMAGE_STATE state, video::ITexture* image=0, const core::rect<s32>& sourceRect=core::rect<s32>(0,0,0,0)) _IRR_OVERRIDE_;
//! Sets an image which should be displayed on the button when it is in normal state.
virtual void setImage(video::ITexture* image=0) _IRR_OVERRIDE_
{
setImage(EGBIS_IMAGE_UP, image);
}
//! Sets an image which should be displayed on the button when it is in normal state.
virtual void setImage(video::ITexture* image, const core::rect<s32>& pos) _IRR_OVERRIDE_
{
setImage(EGBIS_IMAGE_UP, image, pos);
}
//! Sets an image which should be displayed on the button when it is in pressed state.
virtual void setPressedImage(video::ITexture* image=0) _IRR_OVERRIDE_
{
setImage(EGBIS_IMAGE_DOWN, image);
}
//! Sets an image which should be displayed on the button when it is in pressed state.
virtual void setPressedImage(video::ITexture* image, const core::rect<s32>& pos) _IRR_OVERRIDE_
{
setImage(EGBIS_IMAGE_DOWN, image, pos);
}
//! Sets the sprite bank used by the button
virtual void setSpriteBank(IGUISpriteBank* bank=0) _IRR_OVERRIDE_;
//! Sets the animated sprite for a specific button state
/** \param index: Number of the sprite within the sprite bank, use -1 for no sprite
\param state: State of the button to set the sprite for
\param index: The sprite number from the current sprite bank
\param color: The color of the sprite
*/
virtual void setSprite(EGUI_BUTTON_STATE state, s32 index,
video::SColor color=video::SColor(255,255,255,255),
bool loop=false, bool scale=false) _IRR_OVERRIDE_;
//! Get the sprite-index for the given state or -1 when no sprite is set
virtual s32 getSpriteIndex(EGUI_BUTTON_STATE state) const _IRR_OVERRIDE_;
//! Get the sprite color for the given state. Color is only used when a sprite is set.
virtual video::SColor getSpriteColor(EGUI_BUTTON_STATE state) const _IRR_OVERRIDE_;
//! Returns if the sprite in the given state does loop
virtual bool getSpriteLoop(EGUI_BUTTON_STATE state) const _IRR_OVERRIDE_;
//! Returns if the sprite in the given state is scaled
virtual bool getSpriteScale(EGUI_BUTTON_STATE state) const _IRR_OVERRIDE_;
//! Sets if the button should behave like a push button. Which means it
//! can be in two states: Normal or Pressed. With a click on the button,
//! the user can change the state of the button.
virtual void setIsPushButton(bool isPushButton=true) _IRR_OVERRIDE_;
//! Checks whether the button is a push button
virtual bool isPushButton() const _IRR_OVERRIDE_;
//! Sets the pressed state of the button if this is a pushbutton
virtual void setPressed(bool pressed=true) _IRR_OVERRIDE_;
//! Returns if the button is currently pressed
virtual bool isPressed() const _IRR_OVERRIDE_;
//! Sets if the button should use the skin to draw its border
virtual void setDrawBorder(bool border=true) _IRR_OVERRIDE_;
//! Checks if the button face and border are being drawn
virtual bool isDrawingBorder() const _IRR_OVERRIDE_;
//! Sets if the alpha channel should be used for drawing images on the button (default is false)
virtual void setUseAlphaChannel(bool useAlphaChannel=true) _IRR_OVERRIDE_;
//! Checks if the alpha channel should be used for drawing images on the button
virtual bool isAlphaChannelUsed() const _IRR_OVERRIDE_;
//! Sets if the button should scale the button images to fit
virtual void setScaleImage(bool scaleImage=true) _IRR_OVERRIDE_;
//! Checks whether the button scales the used images
virtual bool isScalingImage() const _IRR_OVERRIDE_;
//! Get if the shift key was pressed in last EGET_BUTTON_CLICKED event
virtual bool getClickShiftState() const _IRR_OVERRIDE_
{
return ClickShiftState;
}
//! Get if the control key was pressed in last EGET_BUTTON_CLICKED event
virtual bool getClickControlState() const _IRR_OVERRIDE_
{
return ClickControlState;
}
//! Writes attributes of the element.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const _IRR_OVERRIDE_;
//! Reads attributes of the element
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) _IRR_OVERRIDE_;
protected:
void drawSprite(EGUI_BUTTON_STATE state, u32 startTime, const core::position2di& center);
EGUI_BUTTON_IMAGE_STATE getImageState(bool pressed) const;
private:
struct ButtonSprite
{
ButtonSprite() : Index(-1), Loop(false), Scale(false)
{
}
bool operator==(const ButtonSprite& other) const
{
return Index == other.Index && Color == other.Color && Loop == other.Loop && Scale == other.Scale;
}
s32 Index;
video::SColor Color;
bool Loop;
bool Scale;
};
ButtonSprite ButtonSprites[EGBS_COUNT];
IGUISpriteBank* SpriteBank;
struct ButtonImage
{
ButtonImage() : Texture(0), SourceRect(core::rect<s32>(0,0,0,0))
{
}
ButtonImage(const ButtonImage& other) : Texture(0), SourceRect(core::rect<s32>(0,0,0,0))
{
*this = other;
}
~ButtonImage()
{
if ( Texture )
Texture->drop();
}
ButtonImage& operator=(const ButtonImage& other)
{
if ( this == &other )
return *this;
if (other.Texture)
other.Texture->grab();
if ( Texture )
Texture->drop();
Texture = other.Texture;
SourceRect = other.SourceRect;
return *this;
}
bool operator==(const ButtonImage& other) const
{
return Texture == other.Texture && SourceRect == other.SourceRect;
}
video::ITexture* Texture;
core::rect<s32> SourceRect;
};
ButtonImage ButtonImages[EGBIS_COUNT];
IGUIFont* OverrideFont;
bool OverrideColorEnabled;
video::SColor OverrideColor;
u32 ClickTime, HoverTime, FocusTime;
bool ClickShiftState;
bool ClickControlState;
bool IsPushButton;
bool Pressed;
bool UseAlphaChannel;
bool DrawBorder;
bool ScaleImage;
};
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
#endif // __C_GUI_BUTTON_H_INCLUDED__

View File

@ -0,0 +1,254 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CGUICheckBox.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUISkin.h"
#include "IGUIEnvironment.h"
#include "IVideoDriver.h"
#include "IGUIFont.h"
#include "os.h"
namespace irr
{
namespace gui
{
//! constructor
CGUICheckBox::CGUICheckBox(bool checked, IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect<s32> rectangle)
: IGUICheckBox(environment, parent, id, rectangle), CheckTime(0), Pressed(false), Checked(checked)
, Border(false), Background(false)
{
#ifdef _DEBUG
setDebugName("CGUICheckBox");
#endif
// this element can be tabbed into
setTabStop(true);
setTabOrder(-1);
}
//! called if an event happened.
bool CGUICheckBox::OnEvent(const SEvent& event)
{
if (isEnabled())
{
switch(event.EventType)
{
case EET_KEY_INPUT_EVENT:
if (event.KeyInput.PressedDown &&
(event.KeyInput.Key == KEY_RETURN || event.KeyInput.Key == KEY_SPACE))
{
Pressed = true;
return true;
}
else
if (Pressed && event.KeyInput.PressedDown && event.KeyInput.Key == KEY_ESCAPE)
{
Pressed = false;
return true;
}
else
if (!event.KeyInput.PressedDown && Pressed &&
(event.KeyInput.Key == KEY_RETURN || event.KeyInput.Key == KEY_SPACE))
{
Pressed = false;
if (Parent)
{
SEvent newEvent;
newEvent.EventType = EET_GUI_EVENT;
newEvent.GUIEvent.Caller = this;
newEvent.GUIEvent.Element = 0;
Checked = !Checked;
newEvent.GUIEvent.EventType = EGET_CHECKBOX_CHANGED;
Parent->OnEvent(newEvent);
}
return true;
}
break;
case EET_GUI_EVENT:
if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST)
{
if (event.GUIEvent.Caller == this)
Pressed = false;
}
break;
case EET_MOUSE_INPUT_EVENT:
if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)
{
Pressed = true;
CheckTime = os::Timer::getTime();
return true;
}
else
if (event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)
{
bool wasPressed = Pressed;
Pressed = false;
if (wasPressed && Parent)
{
if ( !AbsoluteClippingRect.isPointInside( core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y) ) )
{
Pressed = false;
return true;
}
SEvent newEvent;
newEvent.EventType = EET_GUI_EVENT;
newEvent.GUIEvent.Caller = this;
newEvent.GUIEvent.Element = 0;
Checked = !Checked;
newEvent.GUIEvent.EventType = EGET_CHECKBOX_CHANGED;
Parent->OnEvent(newEvent);
}
return true;
}
break;
default:
break;
}
}
return IGUIElement::OnEvent(event);
}
//! draws the element and its children
void CGUICheckBox::draw()
{
if (!IsVisible)
return;
IGUISkin* skin = Environment->getSkin();
if (skin)
{
video::IVideoDriver* driver = Environment->getVideoDriver();
core::rect<s32> frameRect(AbsoluteRect);
// draw background
if (Background)
{
video::SColor bgColor = skin->getColor(gui::EGDC_3D_FACE);
driver->draw2DRectangle(bgColor, frameRect, &AbsoluteClippingRect);
}
// draw the border
if (Border)
{
skin->draw3DSunkenPane(this, 0, true, false, frameRect, &AbsoluteClippingRect);
frameRect.UpperLeftCorner.X += skin->getSize(EGDS_TEXT_DISTANCE_X);
frameRect.LowerRightCorner.X -= skin->getSize(EGDS_TEXT_DISTANCE_X);
}
const s32 height = skin->getSize(EGDS_CHECK_BOX_WIDTH);
// the rectangle around the "checked" area.
core::rect<s32> checkRect(frameRect.UpperLeftCorner.X,
((frameRect.getHeight() - height) / 2) + frameRect.UpperLeftCorner.Y,
0, 0);
checkRect.LowerRightCorner.X = checkRect.UpperLeftCorner.X + height;
checkRect.LowerRightCorner.Y = checkRect.UpperLeftCorner.Y + height;
EGUI_DEFAULT_COLOR col = EGDC_GRAY_EDITABLE;
if ( isEnabled() )
col = Pressed ? EGDC_FOCUSED_EDITABLE : EGDC_EDITABLE;
skin->draw3DSunkenPane(this, skin->getColor(col),
false, true, checkRect, &AbsoluteClippingRect);
// the checked icon
if (Checked)
{
skin->drawIcon(this, EGDI_CHECK_BOX_CHECKED, checkRect.getCenter(),
CheckTime, os::Timer::getTime(), false, &AbsoluteClippingRect);
}
// associated text
if (Text.size())
{
checkRect = frameRect;
checkRect.UpperLeftCorner.X += height + 5;
IGUIFont* font = skin->getFont();
if (font)
{
font->draw(Text.c_str(), checkRect,
skin->getColor(isEnabled() ? EGDC_BUTTON_TEXT : EGDC_GRAY_TEXT), false, true, &AbsoluteClippingRect);
}
}
}
IGUIElement::draw();
}
//! set if box is checked
void CGUICheckBox::setChecked(bool checked)
{
Checked = checked;
}
//! returns if box is checked
bool CGUICheckBox::isChecked() const
{
return Checked;
}
//! Sets whether to draw the background
void CGUICheckBox::setDrawBackground(bool draw)
{
Background = draw;
}
//! Checks if background drawing is enabled
bool CGUICheckBox::isDrawBackgroundEnabled() const
{
return Background;
}
//! Sets whether to draw the border
void CGUICheckBox::setDrawBorder(bool draw)
{
Border = draw;
}
//! Checks if border drawing is enabled
bool CGUICheckBox::isDrawBorderEnabled() const
{
return Border;
}
//! Writes attributes of the element.
void CGUICheckBox::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const
{
IGUICheckBox::serializeAttributes(out,options);
out->addBool("Checked", Checked);
out->addBool("Border", Border);
out->addBool("Background", Background);
}
//! Reads attributes of the element
void CGUICheckBox::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0)
{
Checked = in->getAttributeAsBool ("Checked");
Border = in->getAttributeAsBool ("Border", Border);
Background = in->getAttributeAsBool ("Background", Background);
IGUICheckBox::deserializeAttributes(in,options);
}
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_

View File

@ -0,0 +1,71 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_GUI_CHECKBOX_H_INCLUDED__
#define __C_GUI_CHECKBOX_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUICheckBox.h"
namespace irr
{
namespace gui
{
class CGUICheckBox : public IGUICheckBox
{
public:
//! constructor
CGUICheckBox(bool checked, IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect<s32> rectangle);
//! set if box is checked
virtual void setChecked(bool checked) _IRR_OVERRIDE_;
//! returns if box is checked
virtual bool isChecked() const _IRR_OVERRIDE_;
//! Sets whether to draw the background
virtual void setDrawBackground(bool draw) _IRR_OVERRIDE_;
//! Checks if background drawing is enabled
/** \return true if background drawing is enabled, false otherwise */
virtual bool isDrawBackgroundEnabled() const _IRR_OVERRIDE_;
//! Sets whether to draw the border
virtual void setDrawBorder(bool draw) _IRR_OVERRIDE_;
//! Checks if border drawing is enabled
/** \return true if border drawing is enabled, false otherwise */
virtual bool isDrawBorderEnabled() const _IRR_OVERRIDE_;
//! called if an event happened.
virtual bool OnEvent(const SEvent& event) _IRR_OVERRIDE_;
//! draws the element and its children
virtual void draw() _IRR_OVERRIDE_;
//! Writes attributes of the element.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const _IRR_OVERRIDE_;
//! Reads attributes of the element
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) _IRR_OVERRIDE_;
private:
u32 CheckTime;
bool Pressed;
bool Checked;
bool Border;
bool Background;
};
} // end namespace gui
} // end namespace irr
#endif // __C_GUI_CHECKBOX_H_INCLUDED__
#endif // _IRR_COMPILE_WITH_GUI_

View File

@ -0,0 +1,479 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CGUIColorSelectDialog.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUISkin.h"
#include "IGUIEnvironment.h"
#include "IVideoDriver.h"
#include "IGUIButton.h"
#include "IGUIStaticText.h"
#include "IGUIFont.h"
#include "IGUISpriteBank.h"
#include "IFileList.h"
#include "os.h"
#include "fast_atof.h"
namespace irr
{
namespace gui
{
const s32 CSD_WIDTH = 350;
const s32 CSD_HEIGHT = 300;
namespace
{
struct subElementPredefines
{
const wchar_t *pre;
const wchar_t *init;
const wchar_t *post;
int x, y;
int range_down ,range_up;
};
static const subElementPredefines Template [] =
{
{ L"A:", L"0", 0,50,165, 0, 255 },
{ L"R:", L"0", 0,20,205, 0, 255 },
{ L"G:", L"0", 0,20,230, 0, 255 },
{ L"B:", L"0", 0,20,255, 0, 255 },
{ L"H:", L"0", L"°",80,205, 0, 360 },
{ L"S:", L"0", L"%",80,230, 0, 100 },
{ L"L:", L"0", L"%",80,255, 0, 100 },
};
}
//! constructor
CGUIColorSelectDialog::CGUIColorSelectDialog(const wchar_t* title, IGUIEnvironment* environment, IGUIElement* parent, s32 id)
: IGUIColorSelectDialog(environment, parent, id,
core::rect<s32>((parent->getAbsolutePosition().getWidth()-CSD_WIDTH)/2,
(parent->getAbsolutePosition().getHeight()-CSD_HEIGHT)/2,
(parent->getAbsolutePosition().getWidth()-CSD_WIDTH)/2+CSD_WIDTH,
(parent->getAbsolutePosition().getHeight()-CSD_HEIGHT)/2+CSD_HEIGHT)),
Dragging(false)
{
#ifdef _DEBUG
IGUIElement::setDebugName("CGUIColorSelectDialog");
#endif
Text = title;
IGUISkin* skin = Environment->getSkin();
const s32 buttonw = environment->getSkin()->getSize(EGDS_WINDOW_BUTTON_WIDTH);
const s32 posx = RelativeRect.getWidth() - buttonw - 4;
CloseButton = Environment->addButton(core::rect<s32>(posx, 3, posx + buttonw, 3 + buttonw),
this, -1, L"", skin ? skin->getDefaultText(EGDT_WINDOW_CLOSE) : L"Close");
if (skin && skin->getSpriteBank())
{
CloseButton->setSpriteBank(skin->getSpriteBank());
CloseButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_WINDOW_CLOSE), skin->getColor(EGDC_WINDOW_SYMBOL));
CloseButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_WINDOW_CLOSE), skin->getColor(EGDC_WINDOW_SYMBOL));
}
CloseButton->setSubElement(true);
CloseButton->setTabStop(false);
CloseButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT);
CloseButton->grab();
OKButton = Environment->addButton(
core::rect<s32>(RelativeRect.getWidth()-80, 30, RelativeRect.getWidth()-10, 50),
this, -1, skin ? skin->getDefaultText(EGDT_MSG_BOX_OK) : L"OK");
OKButton->setSubElement(true);
OKButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT);
OKButton->grab();
CancelButton = Environment->addButton(
core::rect<s32>(RelativeRect.getWidth()-80, 55, RelativeRect.getWidth()-10, 75),
this, -1, skin ? skin->getDefaultText(EGDT_MSG_BOX_CANCEL) : L"Cancel");
CancelButton->setSubElement(true);
CancelButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT);
CancelButton->grab();
video::IVideoDriver* driver = Environment->getVideoDriver();
ColorRing.Texture = driver->getTexture ( "#colorring" );
if ( 0 == ColorRing.Texture )
{
buildColorRing(core::dimension2d<u32>(128, 128), 1,
Environment->getSkin()->getColor(EGDC_3D_SHADOW));
}
core::rect<s32> r(20,20, 0,0);
ColorRing.Control = Environment->addImage(ColorRing.Texture, r.UpperLeftCorner, true, this);
ColorRing.Control->setSubElement(true);
ColorRing.Control->grab();
for ( u32 i = 0; i != sizeof (Template) / sizeof ( subElementPredefines ); ++i )
{
if ( Template[i].pre )
{
r.UpperLeftCorner.X = Template[i].x;
r.UpperLeftCorner.Y = Template[i].y;
r.LowerRightCorner.X = r.UpperLeftCorner.X + 15;
r.LowerRightCorner.Y = r.UpperLeftCorner.Y + 20;
IGUIElement *t = Environment->addStaticText(Template[i].pre, r, false, false, this);
t->setSubElement(true);
}
if ( Template[i].post )
{
r.UpperLeftCorner.X = Template[i].x + 56;
r.UpperLeftCorner.Y = Template[i].y;
r.LowerRightCorner.X = r.UpperLeftCorner.X + 15;
r.LowerRightCorner.Y = r.UpperLeftCorner.Y + 20;
IGUIElement *t = Environment->addStaticText( Template[i].post, r, false, false, this);
t->setSubElement(true);
}
r.UpperLeftCorner.X = Template[i].x + 15;
r.UpperLeftCorner.Y = Template[i].y-2;
r.LowerRightCorner.X = r.UpperLeftCorner.X + 40;
r.LowerRightCorner.Y = r.UpperLeftCorner.Y + 20;
gui::IGUISpinBox* spin = Environment->addSpinBox( Template[i].init, r, true, this);
spin->setSubElement(true);
spin->setDecimalPlaces(0);
spin->setRange((f32)Template[i].range_down, (f32)Template[i].range_up);
spin->grab();
Battery.push_back(spin);
}
bringToFront(CancelButton);
bringToFront(OKButton);
}
//! destructor
CGUIColorSelectDialog::~CGUIColorSelectDialog()
{
if (CloseButton)
CloseButton->drop();
if (OKButton)
OKButton->drop();
if (CancelButton)
CancelButton->drop();
for (u32 i = 0; i != Battery.size(); ++i)
Battery[i]->drop();
if (ColorRing.Control)
ColorRing.Control->drop();
}
//! renders a antialiased, colored ring
void CGUIColorSelectDialog::buildColorRing( const core::dimension2d<u32> & dim, s32 supersample, const video::SColor& borderColor )
{
const core::dimension2d<u32> d(dim.Width * supersample, dim.Height * supersample);
video::IVideoDriver* driver = Environment->getVideoDriver();
video::IImage *RawTexture = driver->createImage(video::ECF_A8R8G8B8, d);
RawTexture->fill ( 0x00808080 );
const s32 radiusOut = ( d.Width / 2 ) - 4;
const s32 fullR2 = radiusOut * radiusOut;
video::SColorf rgb(0,0,0);
video::SColorHSL hsl;
hsl.Luminance = 50;
hsl.Saturation = 100;
core::position2d<s32> p;
for ( p.Y = -radiusOut; p.Y <= radiusOut; p.Y += 1 )
{
s32 y2 = p.Y * p.Y;
for (p.X = -radiusOut; p.X <= radiusOut; p.X += 1)
{
s32 r2 = y2 + ( p.X * p.X );
// test point in circle
s32 testa = r2 - fullR2;
if ( testa < 0 )
{
// dotproduct u ( x,y ) * v ( 1, 0 ) = cosinus(a)
const f32 r = sqrtf((f32) r2);
// normalize, dotproduct = xnorm
const f32 xn = r == 0.f ? 0.f : -p.X * core::reciprocal(r);
hsl.Hue = acosf(xn)*core::RADTODEG;
if ( p.Y > 0 )
hsl.Hue = 360 - hsl.Hue;
hsl.Hue -= 90;
const f32 rTest = r / radiusOut;
#if 0
if (rTest < 0.33f)
{
// luminance from 0 to 50
hsl.Luminance = 50*(rTest/0.33);
hsl.Saturation = 0.f;
hsl.toRGB(rgb);
}
else
if ( rTest < 0.66f )
{
// saturation from 0 to 100
hsl.Saturation = 100*(( rTest - 0.33f ) / 0.33f);
hsl.Luminance = 50;
hsl.toRGB(rgb);
}
else
{
// luminance from 50 to 100
hsl.Luminance = 100*(0.5f + ( ( rTest - 0.66f ) / .66f ));
hsl.Saturation = 100;
hsl.toRGB(rgb);
}
// borders should be slightly transparent
if ( rTest >= 0.95f )
rgb.a = (1.f-rTest)*20;
else
rgb.a=1.f;
#else
if ( rTest > 0.5f )
{
hsl.Saturation = 100;
hsl.Luminance = 50;
hsl.toRGB(rgb);
}
// borders should be slightly transparent
if ( rTest < 0.5f )
rgb.a = 0;
else if ( rTest >= 0.95f )
rgb.a = (1.f-rTest)*20;
else if ( rTest <= 0.55f )
rgb.a = (rTest-0.5f)*20;
else
rgb.a=1.f;
#endif
RawTexture->setPixel(4+p.X+radiusOut, 4+p.Y+radiusOut, rgb.toSColor());
}
}
}
if ( supersample > 1 )
{
video::IImage * filter = driver->createImage(video::ECF_A8R8G8B8, dim );
RawTexture->copyToScalingBoxFilter(filter);
RawTexture->drop();
RawTexture = filter;
}
bool generateMipLevels = driver->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS);
driver->setTextureCreationFlag( video::ETCF_CREATE_MIP_MAPS, false);
ColorRing.Texture = driver->addTexture ( "#colorring", RawTexture);
RawTexture->drop();
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, generateMipLevels);
}
//! called if an event happened.
bool CGUIColorSelectDialog::OnEvent(const SEvent& event)
{
if (isEnabled())
{
switch(event.EventType)
{
case EET_GUI_EVENT:
switch(event.GUIEvent.EventType)
{
case EGET_SPINBOX_CHANGED:
{
for ( u32 i = 0; i!= Battery.size (); ++i )
{
if ( event.GUIEvent.Caller == Battery[i] )
{
if (i<4)
{
video::SColor rgb((u32)Battery[0]->getValue(), (u32)Battery[1]->getValue(),
(u32)Battery[2]->getValue(), (u32)Battery[3]->getValue());
video::SColorHSL hsl;
video::SColorf rgb2(rgb);
hsl.fromRGB(rgb2);
Battery[4]->setValue(hsl.Hue);
Battery[5]->setValue(hsl.Saturation);
Battery[6]->setValue(hsl.Luminance);
}
else
{
video::SColorHSL hsl(Battery[4]->getValue(), Battery[5]->getValue(),
Battery[6]->getValue());
video::SColorf rgb2;
hsl.toRGB(rgb2);
video::SColor rgb = rgb2.toSColor();
Battery[1]->setValue((f32)rgb.getRed());
Battery[2]->setValue((f32)rgb.getGreen());
Battery[3]->setValue((f32)rgb.getBlue());
}
}
}
return true;
}
case EGET_ELEMENT_FOCUS_LOST:
Dragging = false;
break;
case EGET_BUTTON_CLICKED:
if (event.GUIEvent.Caller == CloseButton ||
event.GUIEvent.Caller == CancelButton)
{
sendCancelEvent();
remove();
return true;
}
else
if (event.GUIEvent.Caller == OKButton)
{
sendSelectedEvent();
remove();
return true;
}
break;
case EGET_LISTBOX_CHANGED:
case EGET_LISTBOX_SELECTED_AGAIN:
default:
break;
}
break;
case EET_MOUSE_INPUT_EVENT:
switch(event.MouseInput.Event)
{
case EMIE_LMOUSE_PRESSED_DOWN:
DragStart.X = event.MouseInput.X;
DragStart.Y = event.MouseInput.Y;
Dragging = true;
return true;
case EMIE_LMOUSE_LEFT_UP:
Dragging = false;
return true;
case EMIE_MOUSE_MOVED:
if (Dragging)
{
// gui window should not be dragged outside its parent
if (Parent)
if (event.MouseInput.X < Parent->getAbsolutePosition().UpperLeftCorner.X +1 ||
event.MouseInput.Y < Parent->getAbsolutePosition().UpperLeftCorner.Y +1 ||
event.MouseInput.X > Parent->getAbsolutePosition().LowerRightCorner.X -1 ||
event.MouseInput.Y > Parent->getAbsolutePosition().LowerRightCorner.Y -1)
return true;
move(core::position2d<s32>(event.MouseInput.X - DragStart.X, event.MouseInput.Y - DragStart.Y));
DragStart.X = event.MouseInput.X;
DragStart.Y = event.MouseInput.Y;
return true;
}
default:
break;
}
default:
break;
}
}
return IGUIElement::OnEvent(event);
}
//! draws the element and its children
void CGUIColorSelectDialog::draw()
{
if (!IsVisible)
return;
IGUISkin* skin = Environment->getSkin();
core::rect<s32> rect = skin->draw3DWindowBackground(this, true, skin->getColor(EGDC_ACTIVE_BORDER),
AbsoluteRect, &AbsoluteClippingRect);
if (Text.size())
{
rect.UpperLeftCorner.X += 2;
rect.LowerRightCorner.X -= skin->getSize(EGDS_WINDOW_BUTTON_WIDTH) + 5;
IGUIFont* font = skin->getFont(EGDF_WINDOW);
if (font)
font->draw(Text.c_str(), rect, skin->getColor(EGDC_ACTIVE_CAPTION), false, true,
&AbsoluteClippingRect);
}
IGUIElement::draw();
// draw color selector after the window elements
core::vector2di pos(ColorRing.Control->getAbsolutePosition().UpperLeftCorner);
pos.X += ColorRing.Texture->getOriginalSize().Width/2;
pos.Y += ColorRing.Texture->getOriginalSize().Height/2;
#if 0
const f32 h = Battery[4]->getValue();
const f32 s = Battery[5]->getValue();
const f32 l = Battery[6]->getValue();
const f32 factor = 58.f*(((s==0)&&(l<50))?(l*0.33f/50):(
(s<100)?((.33f+(s*0.33f/100))):((0.66f+(l-50)*0.33f/50))));
#else
const f32 factor = 44;
#endif
pos.X += core::round32(sinf(Battery[4]->getValue()*core::DEGTORAD)*factor);
pos.Y -= core::round32(cosf(Battery[4]->getValue()*core::DEGTORAD)*factor);
Environment->getVideoDriver()->draw2DPolygon(pos, 4, 0xffffffff, 4);
}
video::SColor CGUIColorSelectDialog::getColor()
{
return video::SColor((u32)Battery[0]->getValue(), (u32)Battery[1]->getValue(),
(u32)Battery[2]->getValue(), (u32)Battery[3]->getValue());
}
video::SColorHSL CGUIColorSelectDialog::getColorHSL()
{
return video::SColorHSL(Battery[4]->getValue(), Battery[5]->getValue(),
Battery[6]->getValue());
}
//! sends the event that the file has been selected.
void CGUIColorSelectDialog::sendSelectedEvent()
{
SEvent event;
event.EventType = EET_GUI_EVENT;
event.GUIEvent.Caller = this;
event.GUIEvent.Element = 0;
event.GUIEvent.EventType = EGET_FILE_SELECTED;
Parent->OnEvent(event);
}
//! sends the event that the file choose process has been canceld
void CGUIColorSelectDialog::sendCancelEvent()
{
SEvent event;
event.EventType = EET_GUI_EVENT;
event.GUIEvent.Caller = this;
event.GUIEvent.Element = 0;
event.GUIEvent.EventType = EGET_FILE_CHOOSE_DIALOG_CANCELLED;
Parent->OnEvent(event);
}
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_

View File

@ -0,0 +1,74 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_GUI_COLOR_SELECT_DIALOG_H_INCLUDED__
#define __C_GUI_COLOR_SELECT_DIALOG_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUIColorSelectDialog.h"
#include "IGUIButton.h"
#include "IGUISpinBox.h"
#include "IGUIImage.h"
#include "irrArray.h"
namespace irr
{
namespace gui
{
class CGUIColorSelectDialog : public IGUIColorSelectDialog
{
public:
//! constructor
CGUIColorSelectDialog(const wchar_t* title, IGUIEnvironment* environment, IGUIElement* parent, s32 id);
//! destructor
virtual ~CGUIColorSelectDialog();
//! called if an event happened.
virtual bool OnEvent(const SEvent& event) _IRR_OVERRIDE_;
//! draws the element and its children
virtual void draw() _IRR_OVERRIDE_;
virtual video::SColor getColor() _IRR_OVERRIDE_;
virtual video::SColorHSL getColorHSL() _IRR_OVERRIDE_;
private:
//! sends the event that the file has been selected.
void sendSelectedEvent();
//! sends the event that the file choose process has been canceld
void sendCancelEvent();
core::position2d<s32> DragStart;
bool Dragging;
IGUIButton* CloseButton;
IGUIButton* OKButton;
IGUIButton* CancelButton;
core::array<IGUISpinBox*> Battery;
struct SColorCircle
{
IGUIImage * Control;
video::ITexture * Texture;
};
SColorCircle ColorRing;
void buildColorRing( const core::dimension2d<u32> & dim, s32 supersample, const video::SColor& borderColor );
};
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
#endif // __C_GUI_COLOR_SELECT_DIALOG_H_INCLUDED__

View File

@ -0,0 +1,540 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CGUIComboBox.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUIEnvironment.h"
#include "IVideoDriver.h"
#include "IGUISkin.h"
#include "IGUIEnvironment.h"
#include "IGUIFont.h"
#include "IGUIButton.h"
#include "CGUIListBox.h"
#include "os.h"
namespace irr
{
namespace gui
{
//! constructor
CGUIComboBox::CGUIComboBox(IGUIEnvironment* environment, IGUIElement* parent,
s32 id, core::rect<s32> rectangle)
: IGUIComboBox(environment, parent, id, rectangle),
ListButton(0), SelectedText(0), ListBox(0), LastFocus(0),
Selected(-1), HAlign(EGUIA_UPPERLEFT), VAlign(EGUIA_CENTER), MaxSelectionRows(5), HasFocus(false),
ActiveFont(0)
{
#ifdef _DEBUG
setDebugName("CGUIComboBox");
#endif
IGUISkin* skin = Environment->getSkin();
ListButton = Environment->addButton(core::recti(0,0,1,1), this, -1, L"");
if (skin && skin->getSpriteBank())
{
ListButton->setSpriteBank(skin->getSpriteBank());
ListButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_CURSOR_DOWN), skin->getColor(EGDC_WINDOW_SYMBOL));
ListButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_CURSOR_DOWN), skin->getColor(EGDC_WINDOW_SYMBOL));
}
ListButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);
ListButton->setSubElement(true);
ListButton->setTabStop(false);
SelectedText = Environment->addStaticText(L"", core::recti(0,0,1,1), false, false, this, -1, false);
SelectedText->setSubElement(true);
SelectedText->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);
SelectedText->setTextAlignment(EGUIA_UPPERLEFT, EGUIA_CENTER);
if (skin)
SelectedText->setOverrideColor(skin->getColor(EGDC_BUTTON_TEXT));
SelectedText->enableOverrideColor(true);
updateListButtonWidth(skin ? skin->getSize(EGDS_SCROLLBAR_SIZE) : 15);
// this element can be tabbed to
setTabStop(true);
setTabOrder(-1);
}
void CGUIComboBox::setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical)
{
HAlign = horizontal;
VAlign = vertical;
SelectedText->setTextAlignment(horizontal, vertical);
}
//! Set the maximal number of rows for the selection listbox
void CGUIComboBox::setMaxSelectionRows(u32 max)
{
MaxSelectionRows = max;
// force recalculation of open listbox
if (ListBox)
{
openCloseMenu();
openCloseMenu();
}
}
//! Get the maximal number of rows for the selection listbox
u32 CGUIComboBox::getMaxSelectionRows() const
{
return MaxSelectionRows;
}
//! Returns amount of items in box
u32 CGUIComboBox::getItemCount() const
{
return Items.size();
}
//! returns string of an item. the idx may be a value from 0 to itemCount-1
const wchar_t* CGUIComboBox::getItem(u32 idx) const
{
if (idx >= Items.size())
return 0;
return Items[idx].Name.c_str();
}
//! returns string of an item. the idx may be a value from 0 to itemCount-1
u32 CGUIComboBox::getItemData(u32 idx) const
{
if (idx >= Items.size())
return 0;
return Items[idx].Data;
}
//! Returns index based on item data
s32 CGUIComboBox::getIndexForItemData(u32 data ) const
{
for ( u32 i = 0; i < Items.size (); ++i )
{
if ( Items[i].Data == data )
return i;
}
return -1;
}
//! Removes an item from the combo box.
void CGUIComboBox::removeItem(u32 idx)
{
if (idx >= Items.size())
return;
if (Selected == (s32)idx)
setSelected(-1);
Items.erase(idx);
}
//! Returns caption of this element.
const wchar_t* CGUIComboBox::getText() const
{
return getItem(Selected);
}
//! adds an item and returns the index of it
u32 CGUIComboBox::addItem(const wchar_t* text, u32 data)
{
Items.push_back( SComboData ( text, data ) );
if (Selected == -1)
setSelected(0);
return Items.size() - 1;
}
//! deletes all items in the combo box
void CGUIComboBox::clear()
{
Items.clear();
setSelected(-1);
}
//! returns id of selected item. returns -1 if no item is selected.
s32 CGUIComboBox::getSelected() const
{
return Selected;
}
//! sets the selected item. Set this to -1 if no item should be selected
void CGUIComboBox::setSelected(s32 idx)
{
if (idx < -1 || idx >= (s32)Items.size())
return;
Selected = idx;
if (Selected == -1)
SelectedText->setText(L"");
else
SelectedText->setText(Items[Selected].Name.c_str());
}
//! called if an event happened.
bool CGUIComboBox::OnEvent(const SEvent& event)
{
if (isEnabled())
{
switch(event.EventType)
{
case EET_KEY_INPUT_EVENT:
if (ListBox && event.KeyInput.PressedDown && event.KeyInput.Key == KEY_ESCAPE)
{
// hide list box
openCloseMenu();
return true;
}
else
if (event.KeyInput.Key == KEY_RETURN || event.KeyInput.Key == KEY_SPACE)
{
if (!event.KeyInput.PressedDown)
{
openCloseMenu();
}
ListButton->setPressed(ListBox == 0);
return true;
}
else
if (event.KeyInput.PressedDown)
{
s32 oldSelected = Selected;
bool absorb = true;
switch (event.KeyInput.Key)
{
case KEY_DOWN:
setSelected(Selected+1);
break;
case KEY_UP:
setSelected(Selected-1);
break;
case KEY_HOME:
case KEY_PRIOR:
setSelected(0);
break;
case KEY_END:
case KEY_NEXT:
setSelected((s32)Items.size()-1);
break;
default:
absorb = false;
}
if (Selected <0)
setSelected(0);
if (Selected >= (s32)Items.size())
setSelected((s32)Items.size() -1);
if (Selected != oldSelected)
{
sendSelectionChangedEvent();
return true;
}
if (absorb)
return true;
}
break;
case EET_GUI_EVENT:
switch(event.GUIEvent.EventType)
{
case EGET_ELEMENT_FOCUS_LOST:
if (ListBox &&
(Environment->hasFocus(ListBox) || ListBox->isMyChild(event.GUIEvent.Caller) ) &&
event.GUIEvent.Element != this &&
!isMyChild(event.GUIEvent.Element) &&
!ListBox->isMyChild(event.GUIEvent.Element))
{
openCloseMenu();
}
break;
case EGET_BUTTON_CLICKED:
if (event.GUIEvent.Caller == ListButton)
{
openCloseMenu();
return true;
}
break;
case EGET_LISTBOX_SELECTED_AGAIN:
case EGET_LISTBOX_CHANGED:
if (event.GUIEvent.Caller == ListBox)
{
setSelected(ListBox->getSelected());
if (Selected <0 || Selected >= (s32)Items.size())
setSelected(-1);
openCloseMenu();
sendSelectionChangedEvent();
}
return true;
default:
break;
}
break;
case EET_MOUSE_INPUT_EVENT:
switch(event.MouseInput.Event)
{
case EMIE_LMOUSE_PRESSED_DOWN:
{
core::position2d<s32> p(event.MouseInput.X, event.MouseInput.Y);
// send to list box
if (ListBox && ListBox->isPointInside(p) && ListBox->OnEvent(event))
return true;
return true;
}
case EMIE_LMOUSE_LEFT_UP:
{
core::position2d<s32> p(event.MouseInput.X, event.MouseInput.Y);
// send to list box
if (!(ListBox &&
ListBox->getAbsolutePosition().isPointInside(p) &&
ListBox->OnEvent(event)))
{
openCloseMenu();
}
return true;
}
case EMIE_MOUSE_WHEEL:
{
s32 oldSelected = Selected;
setSelected( Selected + ((event.MouseInput.Wheel < 0) ? 1 : -1));
if (Selected <0)
setSelected(0);
if (Selected >= (s32)Items.size())
setSelected((s32)Items.size() -1);
if (Selected != oldSelected)
{
sendSelectionChangedEvent();
return true;
}
}
default:
break;
}
break;
default:
break;
}
}
return IGUIElement::OnEvent(event);
}
void CGUIComboBox::sendSelectionChangedEvent()
{
if (Parent)
{
SEvent event;
event.EventType = EET_GUI_EVENT;
event.GUIEvent.Caller = this;
event.GUIEvent.Element = 0;
event.GUIEvent.EventType = EGET_COMBO_BOX_CHANGED;
Parent->OnEvent(event);
}
}
void CGUIComboBox::updateListButtonWidth(s32 width)
{
if (ListButton->getRelativePosition().getWidth() != width)
{
core::rect<s32> r;
r.UpperLeftCorner.X = RelativeRect.getWidth() - width - 2;
r.LowerRightCorner.X = RelativeRect.getWidth() - 2;
r.UpperLeftCorner.Y = 2;
r.LowerRightCorner.Y = RelativeRect.getHeight() - 2;
ListButton->setRelativePosition(r);
r.UpperLeftCorner.X = 2;
r.UpperLeftCorner.Y = 2;
r.LowerRightCorner.X = RelativeRect.getWidth() - (width + 2);
r.LowerRightCorner.Y = RelativeRect.getHeight() - 2;
SelectedText->setRelativePosition(r);
}
}
//! draws the element and its children
void CGUIComboBox::draw()
{
if (!IsVisible)
return;
IGUISkin* skin = Environment->getSkin();
updateListButtonWidth(skin->getSize(EGDS_SCROLLBAR_SIZE));
// font changed while the listbox is open?
if ( ActiveFont != skin->getFont() && ListBox )
{
// close and re-open to use new font-size
openCloseMenu();
openCloseMenu();
}
IGUIElement *currentFocus = Environment->getFocus();
if (currentFocus != LastFocus)
{
HasFocus = currentFocus == this || isMyChild(currentFocus);
LastFocus = currentFocus;
}
// set colors each time as skin-colors can be changed
SelectedText->setBackgroundColor(skin->getColor(EGDC_HIGH_LIGHT));
if(isEnabled())
{
SelectedText->setDrawBackground(HasFocus);
SelectedText->setOverrideColor(skin->getColor(HasFocus ? EGDC_HIGH_LIGHT_TEXT : EGDC_BUTTON_TEXT));
}
else
{
SelectedText->setDrawBackground(false);
SelectedText->setOverrideColor(skin->getColor(EGDC_GRAY_TEXT));
}
ListButton->setSprite(EGBS_BUTTON_UP, skin->getIcon(EGDI_CURSOR_DOWN), skin->getColor(isEnabled() ? EGDC_WINDOW_SYMBOL : EGDC_GRAY_WINDOW_SYMBOL));
ListButton->setSprite(EGBS_BUTTON_DOWN, skin->getIcon(EGDI_CURSOR_DOWN), skin->getColor(isEnabled() ? EGDC_WINDOW_SYMBOL : EGDC_GRAY_WINDOW_SYMBOL));
core::rect<s32> frameRect(AbsoluteRect);
// draw the border
skin->draw3DSunkenPane(this, skin->getColor(EGDC_3D_HIGH_LIGHT),
true, true, frameRect, &AbsoluteClippingRect);
// draw children
IGUIElement::draw();
}
void CGUIComboBox::openCloseMenu()
{
if (ListBox)
{
// close list box
Environment->setFocus(this);
ListBox->remove();
ListBox = 0;
}
else
{
if (Parent)
Parent->bringToFront(this);
IGUISkin* skin = Environment->getSkin();
u32 h = Items.size();
if (h > getMaxSelectionRows())
h = getMaxSelectionRows();
if (h == 0)
h = 1;
ActiveFont = skin->getFont();
if (ActiveFont)
h *= (ActiveFont->getDimension(L"A").Height + 4);
// open list box
core::rect<s32> r(0, AbsoluteRect.getHeight(),
AbsoluteRect.getWidth(), AbsoluteRect.getHeight() + h);
ListBox = new CGUIListBox(Environment, this, -1, r, false, true, true);
ListBox->setSubElement(true);
ListBox->setNotClipped(true);
ListBox->drop();
// ensure that list box is always completely visible
if (ListBox->getAbsolutePosition().LowerRightCorner.Y > Environment->getRootGUIElement()->getAbsolutePosition().getHeight())
ListBox->setRelativePosition( core::rect<s32>(0, -ListBox->getAbsolutePosition().getHeight(), AbsoluteRect.getWidth(), 0) );
for (s32 i=0; i<(s32)Items.size(); ++i)
ListBox->addItem(Items[i].Name.c_str());
ListBox->setSelected(Selected);
// set focus
Environment->setFocus(ListBox);
}
}
//! Writes attributes of the element.
void CGUIComboBox::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const
{
IGUIComboBox::serializeAttributes(out,options);
out->addEnum ("HTextAlign", HAlign, GUIAlignmentNames);
out->addEnum ("VTextAlign", VAlign, GUIAlignmentNames);
out->addInt("MaxSelectionRows", (s32)MaxSelectionRows );
out->addInt ("Selected", Selected );
out->addInt ("ItemCount", Items.size());
for (u32 i=0; i < Items.size(); ++i)
{
core::stringc s = "Item";
s += i;
s += "Text";
out->addString(s.c_str(), Items[i].Name.c_str());
}
}
//! Reads attributes of the element
void CGUIComboBox::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0)
{
IGUIComboBox::deserializeAttributes(in,options);
setTextAlignment( (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("HTextAlign", GUIAlignmentNames),
(EGUI_ALIGNMENT) in->getAttributeAsEnumeration("VTextAlign", GUIAlignmentNames));
setMaxSelectionRows( (u32)(in->getAttributeAsInt("MaxSelectionRows")) );
// clear the list
clear();
// get item count
u32 c = in->getAttributeAsInt("ItemCount");
// add items
for (u32 i=0; i < c; ++i)
{
core::stringc s = "Item";
s += i;
s += "Text";
addItem(in->getAttributeAsStringW(s.c_str()).c_str(), 0);
}
setSelected(in->getAttributeAsInt("Selected"));
}
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_

View File

@ -0,0 +1,119 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_GUI_COMBO_BOX_H_INCLUDED__
#define __C_GUI_COMBO_BOX_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUIComboBox.h"
#include "IGUIStaticText.h"
#include "irrString.h"
#include "irrArray.h"
namespace irr
{
namespace gui
{
class IGUIButton;
class IGUIListBox;
//! Single line edit box for editing simple text.
class CGUIComboBox : public IGUIComboBox
{
public:
//! constructor
CGUIComboBox(IGUIEnvironment* environment, IGUIElement* parent,
s32 id, core::rect<s32> rectangle);
//! Returns amount of items in box
virtual u32 getItemCount() const _IRR_OVERRIDE_;
//! returns string of an item. the idx may be a value from 0 to itemCount-1
virtual const wchar_t* getItem(u32 idx) const _IRR_OVERRIDE_;
//! Returns item data of an item. the idx may be a value from 0 to itemCount-1
virtual u32 getItemData(u32 idx) const _IRR_OVERRIDE_;
//! Returns index based on item data
virtual s32 getIndexForItemData( u32 data ) const _IRR_OVERRIDE_;
//! adds an item and returns the index of it
virtual u32 addItem(const wchar_t* text, u32 data) _IRR_OVERRIDE_;
//! Removes an item from the combo box.
virtual void removeItem(u32 id) _IRR_OVERRIDE_;
//! deletes all items in the combo box
virtual void clear() _IRR_OVERRIDE_;
//! returns the text of the currently selected item
virtual const wchar_t* getText() const _IRR_OVERRIDE_;
//! returns id of selected item. returns -1 if no item is selected.
virtual s32 getSelected() const _IRR_OVERRIDE_;
//! sets the selected item. Set this to -1 if no item should be selected
virtual void setSelected(s32 idx) _IRR_OVERRIDE_;
//! sets the text alignment of the text part
virtual void setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical) _IRR_OVERRIDE_;
//! Set the maximal number of rows for the selection listbox
virtual void setMaxSelectionRows(u32 max) _IRR_OVERRIDE_;
//! Get the maximal number of rows for the selection listbox
virtual u32 getMaxSelectionRows() const _IRR_OVERRIDE_;
//! called if an event happened.
virtual bool OnEvent(const SEvent& event) _IRR_OVERRIDE_;
//! draws the element and its children
virtual void draw() _IRR_OVERRIDE_;
//! Writes attributes of the element.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const _IRR_OVERRIDE_;
//! Reads attributes of the element
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) _IRR_OVERRIDE_;
private:
void openCloseMenu();
void sendSelectionChangedEvent();
void updateListButtonWidth(s32 width);
IGUIButton* ListButton;
IGUIStaticText* SelectedText;
IGUIListBox* ListBox;
IGUIElement *LastFocus;
struct SComboData
{
SComboData ( const wchar_t * text, u32 data )
: Name (text), Data ( data ) {}
core::stringw Name;
u32 Data;
};
core::array< SComboData > Items;
s32 Selected;
EGUI_ALIGNMENT HAlign, VAlign;
u32 MaxSelectionRows;
bool HasFocus;
IGUIFont* ActiveFont;
};
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
#endif // __C_GUI_COMBO_BOX_H_INCLUDED__

View File

@ -0,0 +1,879 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CGUIContextMenu.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUISkin.h"
#include "IGUIEnvironment.h"
#include "IVideoDriver.h"
#include "IGUIFont.h"
#include "IGUISpriteBank.h"
#include "os.h"
namespace irr
{
namespace gui
{
//! constructor
CGUIContextMenu::CGUIContextMenu(IGUIEnvironment* environment,
IGUIElement* parent, s32 id,
core::rect<s32> rectangle, bool getFocus, bool allowFocus)
: IGUIContextMenu(environment, parent, id, rectangle), EventParent(0), LastFont(0),
CloseHandling(ECMC_REMOVE), HighLighted(-1), ChangeTime(0), AllowFocus(allowFocus)
{
#ifdef _DEBUG
setDebugName("CGUIContextMenu");
#endif
Pos = rectangle.UpperLeftCorner;
recalculateSize();
if (getFocus)
Environment->setFocus(this);
setNotClipped(true);
}
//! destructor
CGUIContextMenu::~CGUIContextMenu()
{
for (u32 i=0; i<Items.size(); ++i)
if (Items[i].SubMenu)
Items[i].SubMenu->drop();
if (LastFont)
LastFont->drop();
}
//! set behavior when menus are closed
void CGUIContextMenu::setCloseHandling(ECONTEXT_MENU_CLOSE onClose)
{
CloseHandling = onClose;
}
//! get current behavior when the menue will be closed
ECONTEXT_MENU_CLOSE CGUIContextMenu::getCloseHandling() const
{
return CloseHandling;
}
//! Returns amount of menu items
u32 CGUIContextMenu::getItemCount() const
{
return Items.size();
}
//! Adds a menu item.
u32 CGUIContextMenu::addItem(const wchar_t* text, s32 commandId, bool enabled, bool hasSubMenu, bool checked, bool autoChecking)
{
return insertItem(Items.size(), text, commandId, enabled, hasSubMenu, checked, autoChecking);
}
//! Insert a menu item at specified position.
u32 CGUIContextMenu::insertItem(u32 idx, const wchar_t* text, s32 commandId, bool enabled,
bool hasSubMenu, bool checked, bool autoChecking)
{
SItem s;
s.Enabled = enabled;
s.Checked = checked;
s.AutoChecking = autoChecking;
s.Text = text;
s.IsSeparator = (text == 0);
s.SubMenu = 0;
s.CommandId = commandId;
if (hasSubMenu)
{
s.SubMenu = new CGUIContextMenu(Environment, this, commandId,
core::rect<s32>(0,0,100,100), false, false);
s.SubMenu->setVisible(false);
}
u32 result = idx;
if ( idx < Items.size() )
{
Items.insert(s, idx);
}
else
{
Items.push_back(s);
result = Items.size() - 1;
}
recalculateSize();
return result;
}
s32 CGUIContextMenu::findItemWithCommandId(s32 commandId, u32 idxStartSearch) const
{
for ( u32 i=idxStartSearch; i<Items.size(); ++i )
{
if ( Items[i].CommandId == commandId )
{
return (s32)i;
}
}
return -1;
}
//! Adds a sub menu from an element that already exists.
void CGUIContextMenu::setSubMenu(u32 index, CGUIContextMenu* menu)
{
if (index >= Items.size())
return;
if (menu)
menu->grab();
if (Items[index].SubMenu)
Items[index].SubMenu->drop();
Items[index].SubMenu = menu;
menu->setVisible(false);
if (Items[index].SubMenu)
{
menu->AllowFocus = false;
if ( Environment->getFocus() == menu )
{
Environment->setFocus( this );
}
}
recalculateSize();
}
//! Adds a separator item to the menu
void CGUIContextMenu::addSeparator()
{
addItem(0, -1, true, false, false, false);
}
//! Returns text of the menu item.
const wchar_t* CGUIContextMenu::getItemText(u32 idx) const
{
if (idx >= Items.size())
return 0;
return Items[idx].Text.c_str();
}
//! Sets text of the menu item.
void CGUIContextMenu::setItemText(u32 idx, const wchar_t* text)
{
if (idx >= Items.size())
return;
Items[idx].Text = text;
recalculateSize();
}
//! should the element change the checked status on clicking
void CGUIContextMenu::setItemAutoChecking(u32 idx, bool autoChecking)
{
if ( idx >= Items.size())
return;
Items[idx].AutoChecking = autoChecking;
}
//! does the element change the checked status on clicking
bool CGUIContextMenu::getItemAutoChecking(u32 idx) const
{
if (idx >= Items.size())
return false;
return Items[idx].AutoChecking;
}
//! Returns if a menu item is enabled
bool CGUIContextMenu::isItemEnabled(u32 idx) const
{
if (idx >= Items.size())
{
return false;
}
return Items[idx].Enabled;
}
//! Returns if a menu item is checked
bool CGUIContextMenu::isItemChecked(u32 idx) const
{
if (idx >= Items.size())
{
return false;
}
return Items[idx].Checked;
}
//! Sets if the menu item should be enabled.
void CGUIContextMenu::setItemEnabled(u32 idx, bool enabled)
{
if (idx >= Items.size())
return;
Items[idx].Enabled = enabled;
}
//! Sets if the menu item should be checked.
void CGUIContextMenu::setItemChecked(u32 idx, bool checked )
{
if (idx >= Items.size())
return;
Items[idx].Checked = checked;
}
//! Removes a menu item
void CGUIContextMenu::removeItem(u32 idx)
{
if (idx >= Items.size())
return;
if (Items[idx].SubMenu)
{
Items[idx].SubMenu->drop();
Items[idx].SubMenu = 0;
}
Items.erase(idx);
recalculateSize();
}
//! Removes all menu items
void CGUIContextMenu::removeAllItems()
{
for (u32 i=0; i<Items.size(); ++i)
if (Items[i].SubMenu)
Items[i].SubMenu->drop();
Items.clear();
recalculateSize();
}
//! called if an event happened.
bool CGUIContextMenu::OnEvent(const SEvent& event)
{
if (isEnabled())
{
switch(event.EventType)
{
case EET_GUI_EVENT:
switch(event.GUIEvent.EventType)
{
case EGET_ELEMENT_FOCUS_LOST:
if (event.GUIEvent.Caller == this && !isMyChild(event.GUIEvent.Element) && AllowFocus)
{
// set event parent of submenus
IGUIElement * p = EventParent ? EventParent : Parent;
if ( p ) // can be 0 when element got removed already
{
setEventParent(p);
SEvent eventClose;
eventClose.EventType = EET_GUI_EVENT;
eventClose.GUIEvent.Caller = this;
eventClose.GUIEvent.Element = 0;
eventClose.GUIEvent.EventType = EGET_ELEMENT_CLOSED;
if ( !p->OnEvent(eventClose) )
{
if ( CloseHandling & ECMC_HIDE )
{
setVisible(false);
}
if ( CloseHandling & ECMC_REMOVE )
{
remove();
}
}
}
return false;
}
break;
case EGET_ELEMENT_FOCUSED:
if (event.GUIEvent.Caller == this && !AllowFocus)
{
return true;
}
break;
default:
break;
}
break;
case EET_MOUSE_INPUT_EVENT:
switch(event.MouseInput.Event)
{
case EMIE_LMOUSE_LEFT_UP:
{
// menu might be removed if it loses focus in sendClick, so grab a reference
grab();
const u32 t = sendClick(core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y));
if ((t==0 || t==1) && Environment->hasFocus(this))
Environment->removeFocus(this);
drop();
}
return true;
case EMIE_LMOUSE_PRESSED_DOWN:
return true;
case EMIE_MOUSE_MOVED:
if (Environment->hasFocus(this))
highlight(core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y), true);
return true;
default:
break;
}
break;
default:
break;
}
}
return IGUIElement::OnEvent(event);
}
//! Sets the visible state of this element.
void CGUIContextMenu::setVisible(bool visible)
{
HighLighted = -1;
ChangeTime = os::Timer::getTime();
for (u32 j=0; j<Items.size(); ++j)
if (Items[j].SubMenu)
Items[j].SubMenu->setVisible(false);
IGUIElement::setVisible(visible);
}
//! sends a click Returns:
//! 0 if click went outside of the element,
//! 1 if a valid button was clicked,
//! 2 if a nonclickable element was clicked
u32 CGUIContextMenu::sendClick(const core::position2d<s32>& p)
{
u32 t = 0;
// get number of open submenu
s32 openmenu = -1;
s32 j;
for (j=0; j<(s32)Items.size(); ++j)
if (Items[j].SubMenu && Items[j].SubMenu->isVisible())
{
openmenu = j;
break;
}
// delegate click operation to submenu
if (openmenu != -1)
{
t = Items[j].SubMenu->sendClick(p);
if (t != 0)
return t; // clicked something
}
// check click on myself
if (isPointInside(p) &&
(u32)HighLighted < Items.size())
{
if (!Items[HighLighted].Enabled ||
Items[HighLighted].IsSeparator ||
Items[HighLighted].SubMenu)
return 2;
if ( Items[HighLighted].AutoChecking )
{
Items[HighLighted].Checked = Items[HighLighted].Checked ? false : true;
}
SEvent event;
event.EventType = EET_GUI_EVENT;
event.GUIEvent.Caller = this;
event.GUIEvent.Element = 0;
event.GUIEvent.EventType = EGET_MENU_ITEM_SELECTED;
if (EventParent)
EventParent->OnEvent(event);
else if (Parent)
Parent->OnEvent(event);
return 1;
}
return 0;
}
//! returns true, if an element was highligted
bool CGUIContextMenu::highlight(const core::position2d<s32>& p, bool canOpenSubMenu)
{
if (!isEnabled())
{
return false;
}
// get number of open submenu
s32 openmenu = -1;
s32 i;
for (i=0; i<(s32)Items.size(); ++i)
if (Items[i].Enabled && Items[i].SubMenu && Items[i].SubMenu->isVisible())
{
openmenu = i;
break;
}
// delegate highlight operation to submenu
if (openmenu != -1)
{
if (Items[openmenu].Enabled && Items[openmenu].SubMenu->highlight(p, canOpenSubMenu))
{
HighLighted = openmenu;
ChangeTime = os::Timer::getTime();
return true;
}
}
// highlight myself
for (i=0; i<(s32)Items.size(); ++i)
{
if (Items[i].Enabled && getHRect(Items[i], AbsoluteRect).isPointInside(p))
{
HighLighted = i;
ChangeTime = os::Timer::getTime();
// make submenus visible/invisible
for (s32 j=0; j<(s32)Items.size(); ++j)
if (Items[j].SubMenu)
{
if ( j == i && canOpenSubMenu && Items[j].Enabled )
Items[j].SubMenu->setVisible(true);
else if ( j != i )
Items[j].SubMenu->setVisible(false);
}
return true;
}
}
HighLighted = openmenu;
return false;
}
//! returns the item highlight-area
core::rect<s32> CGUIContextMenu::getHRect(const SItem& i, const core::rect<s32>& absolute) const
{
core::rect<s32> r = absolute;
r.UpperLeftCorner.Y += i.PosY;
r.LowerRightCorner.Y = r.UpperLeftCorner.Y + i.Dim.Height;
return r;
}
//! Gets drawing rect of Item
core::rect<s32> CGUIContextMenu::getRect(const SItem& i, const core::rect<s32>& absolute) const
{
core::rect<s32> r = absolute;
r.UpperLeftCorner.Y += i.PosY;
r.LowerRightCorner.Y = r.UpperLeftCorner.Y + i.Dim.Height;
r.UpperLeftCorner.X += 20;
return r;
}
//! draws the element and its children
void CGUIContextMenu::draw()
{
if (!IsVisible)
return;
IGUISkin* skin = Environment->getSkin();
if (!skin)
return;
IGUIFont* font = skin->getFont(EGDF_MENU);
if (font != LastFont)
{
if (LastFont)
LastFont->drop();
LastFont = font;
if (LastFont)
LastFont->grab();
recalculateSize();
}
IGUISpriteBank* sprites = skin->getSpriteBank();
core::rect<s32> rect = AbsoluteRect;
core::rect<s32>* clip = 0;
// draw frame
skin->draw3DMenuPane(this, AbsoluteRect, clip);
// loop through all menu items
rect = AbsoluteRect;
s32 y = AbsoluteRect.UpperLeftCorner.Y;
for (s32 i=0; i<(s32)Items.size(); ++i)
{
if (Items[i].IsSeparator)
{
// draw separator
rect = AbsoluteRect;
rect.UpperLeftCorner.Y += Items[i].PosY + 3;
rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + 1;
rect.UpperLeftCorner.X += 5;
rect.LowerRightCorner.X -= 5;
skin->draw2DRectangle(this, skin->getColor(EGDC_3D_SHADOW), rect, clip);
rect.LowerRightCorner.Y += 1;
rect.UpperLeftCorner.Y += 1;
skin->draw2DRectangle(this, skin->getColor(EGDC_3D_HIGH_LIGHT), rect, clip);
y += 10;
}
else
{
rect = getRect(Items[i], AbsoluteRect);
// draw highlighted
if (i == HighLighted && Items[i].Enabled)
{
core::rect<s32> r = AbsoluteRect;
r.LowerRightCorner.Y = rect.LowerRightCorner.Y;
r.UpperLeftCorner.Y = rect.UpperLeftCorner.Y;
r.LowerRightCorner.X -= 5;
r.UpperLeftCorner.X += 5;
skin->draw2DRectangle(this, skin->getColor(EGDC_HIGH_LIGHT), r, clip);
}
// draw text
EGUI_DEFAULT_COLOR c = EGDC_BUTTON_TEXT;
if (i == HighLighted)
c = EGDC_HIGH_LIGHT_TEXT;
if (!Items[i].Enabled)
c = EGDC_GRAY_TEXT;
if (font)
font->draw(Items[i].Text.c_str(), rect,
skin->getColor(c), false, true, clip);
// draw submenu symbol
if (Items[i].SubMenu && sprites)
{
core::rect<s32> r = rect;
r.UpperLeftCorner.X = r.LowerRightCorner.X - 15;
sprites->draw2DSprite(skin->getIcon(EGDI_CURSOR_RIGHT),
r.getCenter(), clip, skin->getColor(c),
(i == HighLighted) ? ChangeTime : 0,
(i == HighLighted) ? os::Timer::getTime() : 0,
(i == HighLighted), true);
}
// draw checked symbol
if (Items[i].Checked && sprites)
{
core::rect<s32> r = rect;
r.LowerRightCorner.X = r.UpperLeftCorner.X - 15;
r.UpperLeftCorner.X = r.LowerRightCorner.X + 15;
sprites->draw2DSprite(skin->getIcon(EGDI_CHECK_BOX_CHECKED),
r.getCenter(), clip, skin->getColor(c),
(i == HighLighted) ? ChangeTime : 0,
(i == HighLighted) ? os::Timer::getTime() : 0,
(i == HighLighted), true);
}
}
}
IGUIElement::draw();
}
void CGUIContextMenu::recalculateSize()
{
IGUIFont* font = Environment->getSkin()->getFont(EGDF_MENU);
if (!font)
return;
core::rect<s32> rect;
rect.UpperLeftCorner = RelativeRect.UpperLeftCorner;
u32 width = 100;
u32 height = 3;
u32 i;
for (i=0; i<Items.size(); ++i)
{
if (Items[i].IsSeparator)
{
Items[i].Dim.Width = 100;
Items[i].Dim.Height = 10;
}
else
{
Items[i].Dim = font->getDimension(Items[i].Text.c_str());
Items[i].Dim.Width += 40;
if (Items[i].Dim.Width > width)
width = Items[i].Dim.Width;
}
Items[i].PosY = height;
height += Items[i].Dim.Height;
}
height += 5;
if (height < 10)
height = 10;
rect.LowerRightCorner.X = RelativeRect.UpperLeftCorner.X + width;
rect.LowerRightCorner.Y = RelativeRect.UpperLeftCorner.Y + height;
setRelativePosition(rect);
// recalculate submenus
for (i=0; i<Items.size(); ++i)
{
if (Items[i].SubMenu)
{
// move submenu
const s32 w = Items[i].SubMenu->getAbsolutePosition().getWidth();
const s32 h = Items[i].SubMenu->getAbsolutePosition().getHeight();
core::rect<s32> subRect(width-5, Items[i].PosY, width+w-5, Items[i].PosY+h);
gui::IGUIElement * root = Environment->getRootGUIElement();
if ( root )
{
core::rect<s32> rectRoot( root->getAbsolutePosition() );
// if it would be drawn beyond the right border, then add it to the left side
if ( getAbsolutePosition().UpperLeftCorner.X+subRect.LowerRightCorner.X > rectRoot.LowerRightCorner.X )
{
subRect.UpperLeftCorner.X = -w;
subRect.LowerRightCorner.X = 0;
}
// if it would be drawn below bottom border, move it up, but not further than to top.
irr::s32 belowBottom = getAbsolutePosition().UpperLeftCorner.Y+subRect.LowerRightCorner.Y - rectRoot.LowerRightCorner.Y;
if ( belowBottom > 0 )
{
irr::s32 belowTop = getAbsolutePosition().UpperLeftCorner.Y+subRect.UpperLeftCorner.Y;
irr::s32 moveUp = belowBottom < belowTop ? belowBottom : belowTop;
subRect.UpperLeftCorner.Y -= moveUp;
subRect.LowerRightCorner.Y -= moveUp;
}
}
Items[i].SubMenu->setRelativePosition(subRect);
}
}
}
//! Returns the selected item in the menu
s32 CGUIContextMenu::getSelectedItem() const
{
return HighLighted;
}
//! \return Returns a pointer to the submenu of an item.
IGUIContextMenu* CGUIContextMenu::getSubMenu(u32 idx) const
{
if (idx >= Items.size())
return 0;
return Items[idx].SubMenu;
}
//! Returns command id of a menu item
s32 CGUIContextMenu::getItemCommandId(u32 idx) const
{
if (idx >= Items.size())
return -1;
return Items[idx].CommandId;
}
//! Sets the command id of a menu item
void CGUIContextMenu::setItemCommandId(u32 idx, s32 id)
{
if (idx >= Items.size())
return;
Items[idx].CommandId = id;
}
//! Writes attributes of the element.
void CGUIContextMenu::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const
{
IGUIElement::serializeAttributes(out,options);
out->addPosition2d("Position", Pos);
if (Parent->getType() == EGUIET_CONTEXT_MENU || Parent->getType() == EGUIET_MENU )
{
const IGUIContextMenu* const ptr = (const IGUIContextMenu*)Parent;
// find the position of this item in its parent's list
u32 i;
// VC6 needs the cast for this
for (i=0; (i<ptr->getItemCount()) && (ptr->getSubMenu(i) != (const IGUIContextMenu*)this); ++i)
; // do nothing
out->addInt("ParentItem", i);
}
out->addInt("CloseHandling", (s32)CloseHandling);
// write out the item list
out->addInt("ItemCount", Items.size());
core::stringc tmp;
for (u32 i=0; i < Items.size(); ++i)
{
tmp = "IsSeparator"; tmp += i;
out->addBool(tmp.c_str(), Items[i].IsSeparator);
if (!Items[i].IsSeparator)
{
tmp = "Text"; tmp += i;
out->addString(tmp.c_str(), Items[i].Text.c_str());
tmp = "CommandID"; tmp += i;
out->addInt(tmp.c_str(), Items[i].CommandId);
tmp = "Enabled"; tmp += i;
out->addBool(tmp.c_str(), Items[i].Enabled);
tmp = "Checked"; tmp += i;
out->addBool(tmp.c_str(), Items[i].Checked);
tmp = "AutoChecking"; tmp += i;
out->addBool(tmp.c_str(), Items[i].AutoChecking);
}
}
}
//! Reads attributes of the element
void CGUIContextMenu::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0)
{
IGUIElement::deserializeAttributes(in,options);
Pos = in->getAttributeAsPosition2d("Position");
// link to this item's parent
if (Parent && ( Parent->getType() == EGUIET_CONTEXT_MENU || Parent->getType() == EGUIET_MENU ) )
((CGUIContextMenu*)Parent)->setSubMenu(in->getAttributeAsInt("ParentItem"),this);
CloseHandling = (ECONTEXT_MENU_CLOSE)in->getAttributeAsInt("CloseHandling");
removeAllItems();
// read the item list
const s32 count = in->getAttributeAsInt("ItemCount");
for (s32 i=0; i<count; ++i)
{
core::stringc tmp;
core::stringw txt;
s32 commandid=-1;
bool enabled=true;
bool checked=false;
bool autochecking=false;
tmp = "IsSeparator"; tmp += i;
if ( in->existsAttribute(tmp.c_str()) && in->getAttributeAsBool(tmp.c_str()) )
addSeparator();
else
{
tmp = "Text"; tmp += i;
if ( in->existsAttribute(tmp.c_str()) )
txt = in->getAttributeAsStringW(tmp.c_str());
tmp = "CommandID"; tmp += i;
if ( in->existsAttribute(tmp.c_str()) )
commandid = in->getAttributeAsInt(tmp.c_str());
tmp = "Enabled"; tmp += i;
if ( in->existsAttribute(tmp.c_str()) )
enabled = in->getAttributeAsBool(tmp.c_str());
tmp = "Checked"; tmp += i;
if ( in->existsAttribute(tmp.c_str()) )
checked = in->getAttributeAsBool(tmp.c_str());
tmp = "AutoChecking"; tmp += i;
if ( in->existsAttribute(tmp.c_str()) )
autochecking = in->getAttributeAsBool(tmp.c_str());
addItem(core::stringw(txt.c_str()).c_str(), commandid, enabled, false, checked, autochecking);
}
}
recalculateSize();
}
// because sometimes the element has no parent at click time
void CGUIContextMenu::setEventParent(IGUIElement *parent)
{
EventParent = parent;
for (u32 i=0; i<Items.size(); ++i)
if (Items[i].SubMenu)
Items[i].SubMenu->setEventParent(parent);
}
bool CGUIContextMenu::hasOpenSubMenu() const
{
for (u32 i=0; i<Items.size(); ++i)
if (Items[i].SubMenu && Items[i].SubMenu->isVisible())
return true;
return false;
}
void CGUIContextMenu::closeAllSubMenus()
{
for (u32 i=0; i<Items.size(); ++i)
if (Items[i].SubMenu)
Items[i].SubMenu->setVisible(false);
//HighLighted = -1;
}
} // end namespace
} // end namespace
#endif // _IRR_COMPILE_WITH_GUI_

View File

@ -0,0 +1,174 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __C_GUI_CONTEXT_MENU_H_INCLUDED__
#define __C_GUI_CONTEXT_MENU_H_INCLUDED__
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#include "IGUIContextMenu.h"
#include "irrString.h"
#include "irrArray.h"
#include "IGUIFont.h"
namespace irr
{
namespace gui
{
//! GUI Context menu interface.
class CGUIContextMenu : public IGUIContextMenu
{
public:
//! constructor
CGUIContextMenu(IGUIEnvironment* environment,
IGUIElement* parent, s32 id, core::rect<s32> rectangle,
bool getFocus = true, bool allowFocus = true);
//! destructor
virtual ~CGUIContextMenu();
//! set behavior when menus are closed
virtual void setCloseHandling(ECONTEXT_MENU_CLOSE onClose) _IRR_OVERRIDE_;
//! get current behavior when the menue will be closed
virtual ECONTEXT_MENU_CLOSE getCloseHandling() const _IRR_OVERRIDE_;
//! Returns amount of menu items
virtual u32 getItemCount() const _IRR_OVERRIDE_;
//! Adds a menu item.
virtual u32 addItem(const wchar_t* text, s32 commandid,
bool enabled, bool hasSubMenu, bool checked, bool autoChecking) _IRR_OVERRIDE_;
//! Insert a menu item at specified position.
virtual u32 insertItem(u32 idx, const wchar_t* text, s32 commandId, bool enabled,
bool hasSubMenu, bool checked, bool autoChecking) _IRR_OVERRIDE_;
//! Find a item which has the given CommandId starting from given index
virtual s32 findItemWithCommandId(s32 commandId, u32 idxStartSearch) const _IRR_OVERRIDE_;
//! Adds a separator item to the menu
virtual void addSeparator() _IRR_OVERRIDE_;
//! Returns text of the menu item.
virtual const wchar_t* getItemText(u32 idx) const _IRR_OVERRIDE_;
//! Sets text of the menu item.
virtual void setItemText(u32 idx, const wchar_t* text) _IRR_OVERRIDE_;
//! Returns if a menu item is enabled
virtual bool isItemEnabled(u32 idx) const _IRR_OVERRIDE_;
//! Sets if the menu item should be enabled.
virtual void setItemEnabled(u32 idx, bool enabled) _IRR_OVERRIDE_;
//! Returns if a menu item is checked
virtual bool isItemChecked(u32 idx) const _IRR_OVERRIDE_;
//! Sets if the menu item should be checked.
virtual void setItemChecked(u32 idx, bool enabled) _IRR_OVERRIDE_;
//! Removes a menu item
virtual void removeItem(u32 idx) _IRR_OVERRIDE_;
//! Removes all menu items
virtual void removeAllItems() _IRR_OVERRIDE_;
//! called if an event happened.
virtual bool OnEvent(const SEvent& event) _IRR_OVERRIDE_;
//! draws the element and its children
virtual void draw() _IRR_OVERRIDE_;
//! Returns the selected item in the menu
virtual s32 getSelectedItem() const _IRR_OVERRIDE_;
//! Returns a pointer to the submenu of an item.
//! \return Pointer to the submenu of an item.
virtual IGUIContextMenu* getSubMenu(u32 idx) const _IRR_OVERRIDE_;
//! Sets the visible state of this element.
virtual void setVisible(bool visible) _IRR_OVERRIDE_;
//! should the element change the checked status on clicking
virtual void setItemAutoChecking(u32 idx, bool autoChecking) _IRR_OVERRIDE_;
//! does the element change the checked status on clicking
virtual bool getItemAutoChecking(u32 idx) const _IRR_OVERRIDE_;
//! Returns command id of a menu item
virtual s32 getItemCommandId(u32 idx) const _IRR_OVERRIDE_;
//! Sets the command id of a menu item
virtual void setItemCommandId(u32 idx, s32 id) _IRR_OVERRIDE_;
//! Adds a sub menu from an element that already exists.
virtual void setSubMenu(u32 index, CGUIContextMenu* menu);
//! When an eventparent is set it receives events instead of the usual parent element
virtual void setEventParent(IGUIElement *parent) _IRR_OVERRIDE_;
//! Writes attributes of the element.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const _IRR_OVERRIDE_;
//! Reads attributes of the element
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) _IRR_OVERRIDE_;
protected:
void closeAllSubMenus();
bool hasOpenSubMenu() const;
struct SItem
{
core::stringw Text;
bool IsSeparator;
bool Enabled;
bool Checked;
bool AutoChecking;
core::dimension2d<u32> Dim;
s32 PosY;
CGUIContextMenu* SubMenu;
s32 CommandId;
};
virtual void recalculateSize();
//! returns true, if an element was highlighted
virtual bool highlight(const core::position2d<s32>& p, bool canOpenSubMenu);
//! sends a click Returns:
//! 0 if click went outside of the element,
//! 1 if a valid button was clicked,
//! 2 if a nonclickable element was clicked
virtual u32 sendClick(const core::position2d<s32>& p);
//! returns the item highlight-area
virtual core::rect<s32> getHRect(const SItem& i, const core::rect<s32>& absolute) const;
//! Gets drawing rect of Item
virtual core::rect<s32> getRect(const SItem& i, const core::rect<s32>& absolute) const;
core::array<SItem> Items;
core::position2d<s32> Pos;
IGUIElement* EventParent;
IGUIFont *LastFont;
ECONTEXT_MENU_CLOSE CloseHandling;
s32 HighLighted;
u32 ChangeTime;
bool AllowFocus;
};
} // end namespace gui
} // end namespace irr
#endif // _IRR_COMPILE_WITH_GUI_
#endif // __C_GUI_CONTEXT_MENU_H_INCLUDED__

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More