From 48069a7bcc43bf7e8e92b5dfdefab9d2a2c826d7 Mon Sep 17 00:00:00 2001 From: Lucas Baudin Date: Wed, 24 Feb 2016 20:34:46 +0100 Subject: [PATCH] More backport from the ogl-es irrlicht branch --- lib/irrlicht/include/EDeviceTypes.h | 12 +- lib/irrlicht/include/IEventReceiver.h | 172 +- lib/irrlicht/include/IFileArchive.h | 3 + lib/irrlicht/include/SIrrCreationParameters.h | 1 + .../source/Irrlicht/C3DSMeshFileLoader.cpp | 1396 ++++++++++ .../source/Irrlicht/C3DSMeshFileLoader.h | 166 ++ .../Irrlicht/CAndroidAssetFileArchive.cpp | 101 + .../Irrlicht/CAndroidAssetFileArchive.h | 70 + .../source/Irrlicht/CAndroidAssetReader.cpp | 72 + .../source/Irrlicht/CAndroidAssetReader.h | 74 + .../source/Irrlicht/CIrrDeviceAndroid.cpp | 448 +++ .../source/Irrlicht/CIrrDeviceAndroid.h | 157 ++ lib/irrlicht/source/Irrlicht/COGLESDriver.cpp | 7 + .../source/Irrlicht/CSceneManager.cpp | 15 + .../source/Irrlicht/CXMeshFileLoader.cpp | 2419 +++++++++++++++++ .../source/Irrlicht/CXMeshFileLoader.h | 198 ++ lib/irrlicht/source/Irrlicht/Irrlicht.cpp | 28 +- lib/irrlicht/source/Irrlicht/os.cpp | 7 + 18 files changed, 5293 insertions(+), 53 deletions(-) create mode 100644 lib/irrlicht/source/Irrlicht/C3DSMeshFileLoader.cpp create mode 100644 lib/irrlicht/source/Irrlicht/C3DSMeshFileLoader.h create mode 100644 lib/irrlicht/source/Irrlicht/CAndroidAssetFileArchive.cpp create mode 100644 lib/irrlicht/source/Irrlicht/CAndroidAssetFileArchive.h create mode 100644 lib/irrlicht/source/Irrlicht/CAndroidAssetReader.cpp create mode 100644 lib/irrlicht/source/Irrlicht/CAndroidAssetReader.h create mode 100644 lib/irrlicht/source/Irrlicht/CIrrDeviceAndroid.cpp create mode 100644 lib/irrlicht/source/Irrlicht/CIrrDeviceAndroid.h create mode 100644 lib/irrlicht/source/Irrlicht/CXMeshFileLoader.cpp create mode 100644 lib/irrlicht/source/Irrlicht/CXMeshFileLoader.h diff --git a/lib/irrlicht/include/EDeviceTypes.h b/lib/irrlicht/include/EDeviceTypes.h index 44b009431..e15a0bfd2 100644 --- a/lib/irrlicht/include/EDeviceTypes.h +++ b/lib/irrlicht/include/EDeviceTypes.h @@ -28,6 +28,10 @@ namespace irr //! A device native to Mac OSX /** This device uses Apple's Cocoa API and works in Mac OSX 10.2 and above. */ EIDT_OSX, + + //! A device native to the IPhone/IPod touch + /** This device should be used with the OpenGL-ES driver. */ + EIDT_IPHONE, //! A device which uses Simple DirectMedia Layer /** The SDL device works under all platforms supported by SDL but first must be compiled @@ -51,7 +55,13 @@ namespace irr to your operating system. If this is unavailable then the X11, SDL and then console device will be tried. This ensures that Irrlicht will run even if your platform is unsupported, although it may not be able to render anything. */ - EIDT_BEST + EIDT_BEST, + + //! A device for Android platforms + /** Best used with embedded devices and mobile systems. + Does not need X11 or other graphical subsystems. + May support hw-acceleration via OpenGL-ES */ + EIDT_ANDROID, }; } // end namespace irr diff --git a/lib/irrlicht/include/IEventReceiver.h b/lib/irrlicht/include/IEventReceiver.h index c19248a83..4ec9b7da7 100644 --- a/lib/irrlicht/include/IEventReceiver.h +++ b/lib/irrlicht/include/IEventReceiver.h @@ -33,6 +33,18 @@ namespace irr /** Like mouse events, keyboard events are created by the device and passed to IrrlichtDevice::postEventFromUser. They take the same path as mouse events. */ EET_KEY_INPUT_EVENT, + + //! A multi touch event. + EET_MULTI_TOUCH_EVENT, + + //! A accelerometer event. + EET_ACCELEROMETER_EVENT, + + //! A gyroscope event. + EET_GYROSCOPE_EVENT, + + //! A device motion event. + EET_DEVICE_MOTION_EVENT, //! A joystick (joypad, gamepad) input event. /** Joystick events are created by polling all connected joysticks once per @@ -49,14 +61,6 @@ namespace irr user receiver then no text will be sent to the console. */ EET_LOG_TEXT_EVENT, -#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_) - //! A input method event - /** Input method events are created by the input method message and passed to IrrlichtDevice::postEventFromUser. - Windows: Implemented. - Linux / Other: Not yet implemented. */ - EET_IMPUT_METHOD_EVENT, -#endif - //! A user event with user data. /** This is not used by Irrlicht and can be used to send user specific data though the system. The Irrlicht 'window handle' @@ -149,20 +153,25 @@ namespace irr EMBSM_FORCE_32_BIT = 0x7fffffff }; - -#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_) - //! Enumeration for all input method events - enum EINPUT_METHOD_EVENT + + //! Enumeration for all touch input events + enum EMULTI_TOUCH_INPUT_EVENT { - //! a character from input method. - EIME_CHAR_INPUT = 0, - - //! change position of composition window - EIME_CHANGE_POS, - - EIME_FORCE_32_BIT = 0x7fffffff + //! Max multi touch count + NUMBER_OF_MULTI_TOUCHES = 10, + + //! Touch was pressed down. + EMTIE_PRESSED_DOWN = 0, + + //! Touch was left up. + EMTIE_LEFT_UP, + + //! The touch changed its position. + EMTIE_MOVED, + + //! No real event. Just for convenience to get number of events + EMTIE_COUNT }; -#endif namespace gui { @@ -352,6 +361,97 @@ struct SEvent //! True if ctrl was also pressed bool Control:1; }; + + //! Any kind of multi touch event. + struct SMultiTouchInput + { + //! A helper function to check if a button is pressed. + u32 touchedCount() const + { + u32 count = 0; + + for (u16 i = 0; i < NUMBER_OF_MULTI_TOUCHES; ++i) + { + if (Touched[i]) + count++; + } + + return count; + } + + //! Reset variables. + void clear() + { + for (u16 i = 0; i < NUMBER_OF_MULTI_TOUCHES; ++i) + { + Touched[i] = 0; + X[i] = 0; + Y[i] = 0; + PrevX[i] = 0; + PrevY[i] = 0; + } + } + + // Status of simple touch. + u8 Touched[NUMBER_OF_MULTI_TOUCHES]; + + // X position of simple touch. + s32 X[NUMBER_OF_MULTI_TOUCHES]; + + // Y position of simple touch. + s32 Y[NUMBER_OF_MULTI_TOUCHES]; + + // Previous X position of simple touch. + s32 PrevX[NUMBER_OF_MULTI_TOUCHES]; + + // Previous Y position of simple touch. + s32 PrevY[NUMBER_OF_MULTI_TOUCHES]; + + //! Type of multi touch event + EMULTI_TOUCH_INPUT_EVENT Event; + }; + + //! Any kind of accelerometer event. + struct SAccelerometerEvent + { + + // X acceleration. + f64 X; + + // Y acceleration. + f64 Y; + + // Z acceleration. + f64 Z; + }; + + //! Any kind of gyroscope event. + struct SGyroscopeEvent + { + + // X rotation. + f64 X; + + // Y rotation. + f64 Y; + + // Z rotation. + f64 Z; + }; + + //! Any kind of device motion event. + struct SDeviceMotionEvent + { + + // X angle - roll. + f64 X; + + // Y angle - pitch. + f64 Y; + + // Z angle - yaw. + f64 Z; + }; //! A joystick event. /** Unlike other events, joystick events represent the result of polling @@ -373,7 +473,7 @@ struct SEvent AXIS_R, // e.g. rudder, or analog 2 stick 2 top to bottom AXIS_U, AXIS_V, - NUMBER_OF_AXES = 32 + NUMBER_OF_AXES }; /** A bitmap of button states. You can use IsButtonPressed() to @@ -412,7 +512,6 @@ struct SEvent } }; - //! Any kind of log event. struct SLogEvent { @@ -433,32 +532,19 @@ struct SEvent s32 UserData2; }; -#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_) - struct SInputMethodEvent - { - //! Parent window handle for IMM functions (Windows only) - void* Handle; - - //! Character from Input Method - wchar_t Char; - - //! Type of input method event - EINPUT_METHOD_EVENT Event; - }; -#endif - EEVENT_TYPE EventType; union { struct SGUIEvent GUIEvent; struct SMouseInput MouseInput; struct SKeyInput KeyInput; + struct SMultiTouchInput MultiTouchInput; + struct SAccelerometerEvent AccelerometerEvent; + struct SGyroscopeEvent GyroscopeEvent; + struct SDeviceMotionEvent DeviceMotionEvent; struct SJoystickEvent JoystickEvent; struct SLogEvent LogEvent; struct SUserEvent UserEvent; -#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_) - struct SInputMethodEvent InputMethodEvent; -#endif }; }; @@ -520,14 +606,6 @@ struct SJoystickInfo //! The presence or absence of a hat cannot be determined. POV_HAT_UNKNOWN } PovHat; - - //! Set if the name of the joystick is useful: - /** On windows the generic name is useless, since it's always the same - * indepentent of what joystick is connected ("Microsoft PC-joystick driver"). - * We will try to get a better name from the registry, but if this should - * fail this flag is set and used by STK. */ - bool HasGenericName; - }; // struct SJoystickInfo diff --git a/lib/irrlicht/include/IFileArchive.h b/lib/irrlicht/include/IFileArchive.h index a2e02a837..c382defe2 100644 --- a/lib/irrlicht/include/IFileArchive.h +++ b/lib/irrlicht/include/IFileArchive.h @@ -45,6 +45,9 @@ enum E_FILE_ARCHIVE_TYPE //! A wad Archive, Quake2, Halflife EFAT_WAD = MAKE_IRR_ID('W','A','D', 0), + //! An Android asset file archive + EFAT_ANDROID_ASSET = MAKE_IRR_ID('A','S','S','E'), + //! The type of this archive is unknown EFAT_UNKNOWN = MAKE_IRR_ID('u','n','k','n') }; diff --git a/lib/irrlicht/include/SIrrCreationParameters.h b/lib/irrlicht/include/SIrrCreationParameters.h index 50c5dcdfc..bd64b39c8 100644 --- a/lib/irrlicht/include/SIrrCreationParameters.h +++ b/lib/irrlicht/include/SIrrCreationParameters.h @@ -81,6 +81,7 @@ namespace irr DisplayAdapter = other.DisplayAdapter; UsePerformanceTimer = other.UsePerformanceTimer; ForceLegacyDevice = other.ForceLegacyDevice; + PrivateData = other.PrivateData; return *this; } diff --git a/lib/irrlicht/source/Irrlicht/C3DSMeshFileLoader.cpp b/lib/irrlicht/source/Irrlicht/C3DSMeshFileLoader.cpp new file mode 100644 index 000000000..65d3117be --- /dev/null +++ b/lib/irrlicht/source/Irrlicht/C3DSMeshFileLoader.cpp @@ -0,0 +1,1396 @@ +// 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_3DS_LOADER_ + +#include "C3DSMeshFileLoader.h" +#include "os.h" +#include "SMeshBuffer.h" +#include "SAnimatedMesh.h" +#include "IReadFile.h" +#include "IVideoDriver.h" +#include "IMeshManipulator.h" + +#ifdef _DEBUG +#define _IRR_DEBUG_3DS_LOADER_ +#endif + +namespace irr +{ +namespace scene +{ + + +namespace +{ +enum e3DSChunk +{ + // Primary chunk + C3DS_MAIN3DS = 0x4D4D, + + // Main Chunks + C3DS_EDIT3DS = 0x3D3D, + C3DS_KEYF3DS = 0xB000, + C3DS_VERSION = 0x0002, + C3DS_MESHVERSION = 0x3D3E, + + // sub chunks of C3DS_EDIT3DS + C3DS_EDIT_MATERIAL = 0xAFFF, + C3DS_EDIT_OBJECT = 0x4000, + + // sub chunks of C3DS_EDIT_MATERIAL + C3DS_MATNAME = 0xA000, + C3DS_MATAMBIENT = 0xA010, + C3DS_MATDIFFUSE = 0xA020, + C3DS_MATSPECULAR = 0xA030, + C3DS_MATSHININESS = 0xA040, + C3DS_MATSHIN2PCT = 0xA041, + C3DS_TRANSPARENCY = 0xA050, + C3DS_TRANSPARENCY_FALLOFF = 0xA052, + C3DS_REFL_BLUR = 0xA053, + C3DS_TWO_SIDE = 0xA081, + C3DS_WIRE = 0xA085, + C3DS_SHADING = 0xA100, + C3DS_MATTEXMAP = 0xA200, + C3DS_MATSPECMAP = 0xA204, + C3DS_MATOPACMAP = 0xA210, + C3DS_MATREFLMAP = 0xA220, + C3DS_MATBUMPMAP = 0xA230, + C3DS_MATMAPFILE = 0xA300, + C3DS_MAT_TEXTILING = 0xA351, + C3DS_MAT_USCALE = 0xA354, + C3DS_MAT_VSCALE = 0xA356, + C3DS_MAT_UOFFSET = 0xA358, + C3DS_MAT_VOFFSET = 0xA35A, + + // subs of C3DS_EDIT_OBJECT + C3DS_OBJTRIMESH = 0x4100, + + // subs of C3DS_OBJTRIMESH + C3DS_TRIVERT = 0x4110, + C3DS_POINTFLAGARRAY= 0x4111, + C3DS_TRIFACE = 0x4120, + C3DS_TRIFACEMAT = 0x4130, + C3DS_TRIUV = 0x4140, + C3DS_TRISMOOTH = 0x4150, + C3DS_TRIMATRIX = 0x4160, + C3DS_MESHCOLOR = 0x4165, + C3DS_DIRECT_LIGHT = 0x4600, + C3DS_DL_INNER_RANGE= 0x4659, + C3DS_DL_OUTER_RANGE= 0x465A, + C3DS_DL_MULTIPLIER = 0x465B, + C3DS_CAMERA = 0x4700, + C3DS_CAM_SEE_CONE = 0x4710, + C3DS_CAM_RANGES = 0x4720, + + // subs of C3DS_KEYF3DS + C3DS_KF_HDR = 0xB00A, + C3DS_AMBIENT_TAG = 0xB001, + C3DS_OBJECT_TAG = 0xB002, + C3DS_CAMERA_TAG = 0xB003, + C3DS_TARGET_TAG = 0xB004, + C3DS_LIGHTNODE_TAG = 0xB005, + C3DS_KF_SEG = 0xB008, + C3DS_KF_CURTIME = 0xB009, + C3DS_KF_NODE_HDR = 0xB010, + C3DS_PIVOTPOINT = 0xB013, + C3DS_BOUNDBOX = 0xB014, + C3DS_MORPH_SMOOTH = 0xB015, + C3DS_POS_TRACK_TAG = 0xB020, + C3DS_ROT_TRACK_TAG = 0xB021, + C3DS_SCL_TRACK_TAG = 0xB022, + C3DS_NODE_ID = 0xB030, + + // Viewport definitions + C3DS_VIEWPORT_LAYOUT = 0x7001, + C3DS_VIEWPORT_DATA = 0x7011, + C3DS_VIEWPORT_DATA_3 = 0x7012, + C3DS_VIEWPORT_SIZE = 0x7020, + + // different color chunk types + C3DS_COL_RGB = 0x0010, + C3DS_COL_TRU = 0x0011, + C3DS_COL_LIN_24 = 0x0012, + C3DS_COL_LIN_F = 0x0013, + + // percentage chunk types + C3DS_PERCENTAGE_I = 0x0030, + C3DS_PERCENTAGE_F = 0x0031, + + C3DS_CHUNK_MAX = 0xFFFF +}; +} + + +//! Constructor +C3DSMeshFileLoader::C3DSMeshFileLoader(ISceneManager* smgr, io::IFileSystem* fs) +: SceneManager(smgr), FileSystem(fs), Vertices(0), Indices(0), SmoothingGroups(0), TCoords(0), + CountVertices(0), CountFaces(0), CountTCoords(0), Mesh(0) +{ + + #ifdef _DEBUG + setDebugName("C3DSMeshFileLoader"); + #endif + + if (FileSystem) + FileSystem->grab(); +} + + +//! destructor +C3DSMeshFileLoader::~C3DSMeshFileLoader() +{ + cleanUp(); + + if (FileSystem) + FileSystem->drop(); + + if (Mesh) + Mesh->drop(); +} + + +//! returns true if the file maybe is able to be loaded by this class +//! based on the file extension (e.g. ".bsp") +bool C3DSMeshFileLoader::isALoadableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension ( filename, "3ds" ); +} + + +//! 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* C3DSMeshFileLoader::createMesh(io::IReadFile* file) +{ + ChunkData data; + + readChunkData(file, data); + + if (data.header.id != C3DS_MAIN3DS ) + return 0; + + CurrentMaterial.clear(); + Materials.clear(); + MeshBufferNames.clear(); + cleanUp(); + + if (Mesh) + Mesh->drop(); + + Mesh = new SMesh(); + + if (readChunk(file, &data)) + { + // success + + for (u32 i=0; igetMeshBufferCount(); ++i) + { + SMeshBuffer* mb = ((SMeshBuffer*)Mesh->getMeshBuffer(i)); + // drop empty buffers + if (mb->getIndexCount() == 0 || mb->getVertexCount() == 0) + { + Mesh->MeshBuffers.erase(i--); + mb->drop(); + } + else + { + if (mb->Material.MaterialType == video::EMT_PARALLAX_MAP_SOLID) + { + SMesh tmp; + tmp.addMeshBuffer(mb); + mb->drop(); + IMesh* tangentMesh = SceneManager->getMeshManipulator()->createMeshWithTangents(&tmp); + Mesh->MeshBuffers[i]=tangentMesh->getMeshBuffer(0); + // we need to grab because we replace the buffer manually. + Mesh->MeshBuffers[i]->grab(); + // clean up intermediate mesh struct + tangentMesh->drop(); + } + Mesh->MeshBuffers[i]->recalculateBoundingBox(); + } + } + + Mesh->recalculateBoundingBox(); + + SAnimatedMesh* am = new SAnimatedMesh(); + am->Type = EAMT_3DS; + am->addMesh(Mesh); + am->recalculateBoundingBox(); + Mesh->drop(); + Mesh = 0; + return am; + } + + Mesh->drop(); + Mesh = 0; + + return 0; +} + + +bool C3DSMeshFileLoader::readPercentageChunk(io::IReadFile* file, + ChunkData* chunk, f32& percentage) +{ +#ifdef _IRR_DEBUG_3DS_LOADER_ + os::Printer::log("Load percentage chunk.", ELL_DEBUG); +#endif + + ChunkData data; + readChunkData(file, data); + + short intpercentage; + float fpercentage; + + switch(data.header.id) + { + case C3DS_PERCENTAGE_I: + { + // read short + file->read(&intpercentage, 2); +#ifdef __BIG_ENDIAN__ + intpercentage = os::Byteswap::byteswap(intpercentage); +#endif + percentage=intpercentage/100.0f; + data.read += 2; + } + break; + case C3DS_PERCENTAGE_F: + { + // read float + file->read(&fpercentage, sizeof(float)); + data.read += sizeof(float); +#ifdef __BIG_ENDIAN__ + percentage = os::Byteswap::byteswap(fpercentage); +#else + percentage = (f32)fpercentage; +#endif + } + break; + default: + { + // unknown percentage chunk + os::Printer::log("Unknown percentage chunk in 3Ds file.", ELL_WARNING); + file->seek(data.header.length - data.read, true); + data.read += data.header.length - data.read; + } + } + + chunk->read += data.read; + + return true; +} + +bool C3DSMeshFileLoader::readColorChunk(io::IReadFile* file, ChunkData* chunk, + video::SColor& out) +{ +#ifdef _IRR_DEBUG_3DS_LOADER_ + os::Printer::log("Load color chunk.", ELL_DEBUG); +#endif + ChunkData data; + readChunkData(file, data); + + u8 c[3]; + f32 cf[3]; + + switch(data.header.id) + { + case C3DS_COL_TRU: + case C3DS_COL_LIN_24: + { + // read 8 bit data + file->read(c, sizeof(c)); + out.set(255, c[0], c[1], c[2]); + data.read += sizeof(c); + } + break; + case C3DS_COL_RGB: + case C3DS_COL_LIN_F: + { + // read float data + file->read(cf, sizeof(cf)); +#ifdef __BIG_ENDIAN__ + cf[0] = os::Byteswap::byteswap(cf[0]); + cf[1] = os::Byteswap::byteswap(cf[1]); + cf[2] = os::Byteswap::byteswap(cf[2]); +#endif + out.set(255, (s32)(cf[0]*255.0f), (s32)(cf[1]*255.0f), (s32)(cf[2]*255.0f)); + data.read += sizeof(cf); + } + break; + default: + { + // unknown color chunk size + os::Printer::log("Unknown size of color chunk in 3Ds file.", ELL_WARNING); + file->seek(data.header.length - data.read, true); + data.read += data.header.length - data.read; + } + } + + chunk->read += data.read; + + return true; +} + + +bool C3DSMeshFileLoader::readMaterialChunk(io::IReadFile* file, ChunkData* parent) +{ +#ifdef _IRR_DEBUG_3DS_LOADER_ + os::Printer::log("Load material chunk.", ELL_DEBUG); +#endif + u16 matSection=0; + + while(parent->read < parent->header.length) + { + ChunkData data; + readChunkData(file, data); + + switch(data.header.id) + { + case C3DS_MATNAME: + { + c8* c = new c8[data.header.length - data.read]; + file->read(c, data.header.length - data.read); + + if (strlen(c)) + CurrentMaterial.Name = c; + + data.read += data.header.length - data.read; + delete [] c; + } + break; + case C3DS_MATAMBIENT: + readColorChunk(file, &data, CurrentMaterial.Material.AmbientColor); + break; + case C3DS_MATDIFFUSE: + readColorChunk(file, &data, CurrentMaterial.Material.DiffuseColor); + break; + case C3DS_MATSPECULAR: + readColorChunk(file, &data, CurrentMaterial.Material.SpecularColor); + break; + case C3DS_MATSHININESS: + readPercentageChunk(file, &data, CurrentMaterial.Material.Shininess); + CurrentMaterial.Material.Shininess = (1.f-CurrentMaterial.Material.Shininess)*128.f; + break; + case C3DS_TRANSPARENCY: + { + f32 percentage; + readPercentageChunk(file, &data, percentage); + if (percentage>0.0f) + { + CurrentMaterial.Material.MaterialTypeParam=percentage; + CurrentMaterial.Material.MaterialType=video::EMT_TRANSPARENT_VERTEX_ALPHA; + } + else + { + CurrentMaterial.Material.MaterialType=video::EMT_SOLID; + } + } + break; + case C3DS_WIRE: + CurrentMaterial.Material.Wireframe=true; + break; + case C3DS_TWO_SIDE: + CurrentMaterial.Material.BackfaceCulling=false; + break; + case C3DS_SHADING: + { + s16 flags; + file->read(&flags, 2); +#ifdef __BIG_ENDIAN__ + flags = os::Byteswap::byteswap(flags); +#endif + switch (flags) + { + case 0: + CurrentMaterial.Material.Wireframe=true; + break; + case 1: + CurrentMaterial.Material.Wireframe=false; + CurrentMaterial.Material.GouraudShading=false; + break; + case 2: + CurrentMaterial.Material.Wireframe=false; + CurrentMaterial.Material.GouraudShading=true; + break; + default: + // phong and metal missing + break; + } + data.read += data.header.length - data.read; + } + break; + case C3DS_MATTEXMAP: + case C3DS_MATSPECMAP: + case C3DS_MATOPACMAP: + case C3DS_MATREFLMAP: + case C3DS_MATBUMPMAP: + { + matSection=data.header.id; + // Should contain a percentage chunk, but does + // not always have it + s16 testval; + const long pos = file->getPos(); + file->read(&testval, 2); +#ifdef __BIG_ENDIAN__ + testval = os::Byteswap::byteswap(testval); +#endif + file->seek(pos, false); + if ((testval == C3DS_PERCENTAGE_I) || + (testval == C3DS_PERCENTAGE_F)) + switch (matSection) + { + case C3DS_MATTEXMAP: + readPercentageChunk(file, &data, CurrentMaterial.Strength[0]); + break; + case C3DS_MATSPECMAP: + readPercentageChunk(file, &data, CurrentMaterial.Strength[1]); + break; + case C3DS_MATOPACMAP: + readPercentageChunk(file, &data, CurrentMaterial.Strength[2]); + break; + case C3DS_MATBUMPMAP: + readPercentageChunk(file, &data, CurrentMaterial.Strength[4]); + break; + } + } + break; + case C3DS_MATMAPFILE: + { + // read texture file name + c8* c = new c8[data.header.length - data.read]; + file->read(c, data.header.length - data.read); + switch (matSection) + { + case C3DS_MATTEXMAP: + CurrentMaterial.Filename[0] = c; + break; + case C3DS_MATSPECMAP: + CurrentMaterial.Filename[1] = c; + break; + case C3DS_MATOPACMAP: + CurrentMaterial.Filename[2] = c; + break; + case C3DS_MATREFLMAP: + CurrentMaterial.Filename[3] = c; + break; + case C3DS_MATBUMPMAP: + CurrentMaterial.Filename[4] = c; + break; + } + data.read += data.header.length - data.read; + delete [] c; + } + break; + case C3DS_MAT_TEXTILING: + { + s16 flags; + file->read(&flags, 2); +#ifdef __BIG_ENDIAN__ + flags = os::Byteswap::byteswap(flags); +#endif + data.read += 2; + } + break; + case C3DS_MAT_USCALE: + case C3DS_MAT_VSCALE: + case C3DS_MAT_UOFFSET: + case C3DS_MAT_VOFFSET: + { + f32 value; + file->read(&value, 4); +#ifdef __BIG_ENDIAN__ + value = os::Byteswap::byteswap(value); +#endif + u32 i=0; + if (matSection != C3DS_MATTEXMAP) + i=1; + u32 j=0,k=0; + if (data.header.id == C3DS_MAT_VSCALE) + { + j=1; + k=1; + } + else if (data.header.id == C3DS_MAT_UOFFSET) + { + j=2; + k=0; + } + else if (data.header.id == C3DS_MAT_VOFFSET) + { + j=2; + k=1; + } + CurrentMaterial.Material.getTextureMatrix(i)(j,k)=value; + + data.read += 4; + } + break; + default: + // ignore chunk + file->seek(data.header.length - data.read, true); + data.read += data.header.length - data.read; + } + + parent->read += data.read; + } + + Materials.push_back(CurrentMaterial); + CurrentMaterial.clear(); + + return true; +} + + + +bool C3DSMeshFileLoader::readTrackChunk(io::IReadFile* file, ChunkData& data, + IMeshBuffer* mb, const core::vector3df& pivot) +{ +#ifdef _IRR_DEBUG_3DS_LOADER_ + os::Printer::log("Load track chunk.", ELL_DEBUG); +#endif + u16 flags; + u32 flags2; + // Track flags + file->read(&flags, 2); +#ifdef __BIG_ENDIAN__ + flags = os::Byteswap::byteswap(flags); +#endif + file->read(&flags2, 4); +#ifdef __BIG_ENDIAN__ + flags2 = os::Byteswap::byteswap(flags2); +#endif + file->read(&flags2, 4); +#ifdef __BIG_ENDIAN__ + flags2 = os::Byteswap::byteswap(flags2); +#endif + // Num keys + file->read(&flags2, 4); +#ifdef __BIG_ENDIAN__ + flags2 = os::Byteswap::byteswap(flags2); +#endif + file->read(&flags2, 4); +#ifdef __BIG_ENDIAN__ + flags2 = os::Byteswap::byteswap(flags2); +#endif + // TCB flags + file->read(&flags, 2); +#ifdef __BIG_ENDIAN__ + flags = os::Byteswap::byteswap(flags); +#endif + data.read += 20; + + f32 angle=0.0f; + if (data.header.id== C3DS_ROT_TRACK_TAG) + { + // Angle + file->read(&angle, sizeof(f32)); +#ifdef __BIG_ENDIAN__ + angle = os::Byteswap::byteswap(angle); +#endif + data.read += sizeof(f32); + } + core::vector3df vec; + file->read(&vec.X, sizeof(f32)); + file->read(&vec.Y, sizeof(f32)); + file->read(&vec.Z, sizeof(f32)); +#ifdef __BIG_ENDIAN__ + vec.X = os::Byteswap::byteswap(vec.X); + vec.Y = os::Byteswap::byteswap(vec.Y); + vec.Z = os::Byteswap::byteswap(vec.Z); +#endif + data.read += 12; + vec-=pivot; + + // apply transformation to mesh buffer + if (false)//mb) + { + video::S3DVertex *vertices=(video::S3DVertex*)mb->getVertices(); + if (data.header.id==C3DS_POS_TRACK_TAG) + { + for (u32 i=0; igetVertexCount(); ++i) + vertices[i].Pos+=vec; + } + else if (data.header.id==C3DS_ROT_TRACK_TAG) + { + //TODO + } + else if (data.header.id==C3DS_SCL_TRACK_TAG) + { + //TODO + } + } + // skip further frames + file->seek(data.header.length - data.read, true); + data.read += data.header.length - data.read; + return true; +} + + +bool C3DSMeshFileLoader::readFrameChunk(io::IReadFile* file, ChunkData* parent) +{ +#ifdef _IRR_DEBUG_3DS_LOADER_ + os::Printer::log("Load frame chunk.", ELL_DEBUG); +#endif + ChunkData data; + + //KF_HDR is always at the beginning + readChunkData(file, data); + if (data.header.id != C3DS_KF_HDR) + return false; + else + { +#ifdef _IRR_DEBUG_3DS_LOADER_ + os::Printer::log("Load keyframe header.", ELL_DEBUG); +#endif + u16 version; + file->read(&version, 2); +#ifdef __BIG_ENDIAN__ + version = os::Byteswap::byteswap(version); +#endif + core::stringc name; + readString(file, data, name); + u32 flags; + file->read(&flags, 4); +#ifdef __BIG_ENDIAN__ + flags = os::Byteswap::byteswap(flags); +#endif + + data.read += 4; + parent->read += data.read; + } + data.read=0; + + IMeshBuffer* mb=0; + core::vector3df pivot,bboxCenter; + while(parent->read < parent->header.length) + { + readChunkData(file, data); + + switch(data.header.id) + { + case C3DS_OBJECT_TAG: + { +#ifdef _IRR_DEBUG_3DS_LOADER_ + os::Printer::log("Load object tag.", ELL_DEBUG); +#endif + mb=0; + pivot.set(0.0f, 0.0f, 0.0f); + } + break; + case C3DS_KF_SEG: + { +#ifdef _IRR_DEBUG_3DS_LOADER_ + os::Printer::log("Load keyframe segment.", ELL_DEBUG); +#endif + u32 flags; + file->read(&flags, 4); +#ifdef __BIG_ENDIAN__ + flags = os::Byteswap::byteswap(flags); +#endif + file->read(&flags, 4); +#ifdef __BIG_ENDIAN__ + flags = os::Byteswap::byteswap(flags); +#endif + data.read += 8; + } + break; + case C3DS_KF_NODE_HDR: + { +#ifdef _IRR_DEBUG_3DS_LOADER_ + os::Printer::log("Load keyframe node header.", ELL_DEBUG); +#endif + s16 flags; + c8* c = new c8[data.header.length - data.read-6]; + file->read(c, data.header.length - data.read-6); + + // search mesh buffer to apply these transformations to + for (u32 i=0; igetMeshBuffer(i); + break; + } + } + + file->read(&flags, 2); +#ifdef __BIG_ENDIAN__ + flags = os::Byteswap::byteswap(flags); +#endif + file->read(&flags, 2); +#ifdef __BIG_ENDIAN__ + flags = os::Byteswap::byteswap(flags); +#endif + file->read(&flags, 2); +#ifdef __BIG_ENDIAN__ + flags = os::Byteswap::byteswap(flags); +#endif + data.read += data.header.length - data.read; + delete [] c; + } + break; + case C3DS_KF_CURTIME: + { +#ifdef _IRR_DEBUG_3DS_LOADER_ + os::Printer::log("Load keyframe current time.", ELL_DEBUG); +#endif + u32 flags; + file->read(&flags, 4); +#ifdef __BIG_ENDIAN__ + flags = os::Byteswap::byteswap(flags); +#endif + data.read += 4; + } + break; + case C3DS_NODE_ID: + { +#ifdef _IRR_DEBUG_3DS_LOADER_ + os::Printer::log("Load node ID.", ELL_DEBUG); +#endif + u16 flags; + file->read(&flags, 2); +#ifdef __BIG_ENDIAN__ + flags = os::Byteswap::byteswap(flags); +#endif + data.read += 2; + } + break; + case C3DS_PIVOTPOINT: + { +#ifdef _IRR_DEBUG_3DS_LOADER_ + os::Printer::log("Load pivot point.", ELL_DEBUG); +#endif + file->read(&pivot.X, sizeof(f32)); + file->read(&pivot.Y, sizeof(f32)); + file->read(&pivot.Z, sizeof(f32)); +#ifdef __BIG_ENDIAN__ + pivot.X = os::Byteswap::byteswap(pivot.X); + pivot.Y = os::Byteswap::byteswap(pivot.Y); + pivot.Z = os::Byteswap::byteswap(pivot.Z); +#endif + data.read += 12; + } + break; + case C3DS_BOUNDBOX: + { +#ifdef _IRR_DEBUG_3DS_LOADER_ + os::Printer::log("Load bounding box.", ELL_DEBUG); +#endif + core::aabbox3df bbox; + // abuse bboxCenter as temporary variable + file->read(&bboxCenter.X, sizeof(f32)); + file->read(&bboxCenter.Y, sizeof(f32)); + file->read(&bboxCenter.Z, sizeof(f32)); +#ifdef __BIG_ENDIAN__ + bboxCenter.X = os::Byteswap::byteswap(bboxCenter.X); + bboxCenter.Y = os::Byteswap::byteswap(bboxCenter.Y); + bboxCenter.Z = os::Byteswap::byteswap(bboxCenter.Z); +#endif + bbox.reset(bboxCenter); + file->read(&bboxCenter.X, sizeof(f32)); + file->read(&bboxCenter.Y, sizeof(f32)); + file->read(&bboxCenter.Z, sizeof(f32)); +#ifdef __BIG_ENDIAN__ + bboxCenter.X = os::Byteswap::byteswap(bboxCenter.X); + bboxCenter.Y = os::Byteswap::byteswap(bboxCenter.Y); + bboxCenter.Z = os::Byteswap::byteswap(bboxCenter.Z); +#endif + bbox.addInternalPoint(bboxCenter); + bboxCenter=bbox.getCenter(); + data.read += 24; + } + break; + case C3DS_MORPH_SMOOTH: + { +#ifdef _IRR_DEBUG_3DS_LOADER_ + os::Printer::log("Load morph smooth.", ELL_DEBUG); +#endif + f32 flag; + file->read(&flag, 4); +#ifdef __BIG_ENDIAN__ + flag = os::Byteswap::byteswap(flag); +#endif + data.read += 4; + } + break; + case C3DS_POS_TRACK_TAG: + case C3DS_ROT_TRACK_TAG: + case C3DS_SCL_TRACK_TAG: + readTrackChunk(file, data, mb, bboxCenter-pivot); + break; + default: + // ignore chunk + file->seek(data.header.length - data.read, true); + data.read += data.header.length - data.read; + } + + parent->read += data.read; + data.read=0; + } + + return true; +} + + +bool C3DSMeshFileLoader::readChunk(io::IReadFile* file, ChunkData* parent) +{ + while(parent->read < parent->header.length) + { + ChunkData data; + readChunkData(file, data); + + switch(data.header.id) + { + case C3DS_VERSION: + { + u16 version; + file->read(&version, sizeof(u16)); +#ifdef __BIG_ENDIAN__ + version = os::Byteswap::byteswap(version); +#endif + file->seek(data.header.length - data.read - 2, true); + data.read += data.header.length - data.read; + if (version != 0x03) + os::Printer::log("3ds file version is other than 3.", ELL_ERROR); + } + break; + case C3DS_EDIT_MATERIAL: + readMaterialChunk(file, &data); + break; + case C3DS_KEYF3DS: + readFrameChunk(file, &data); + break; + case C3DS_EDIT3DS: + break; + case C3DS_MESHVERSION: + case 0x01: + { + u32 version; + file->read(&version, sizeof(u32)); +#ifdef __BIG_ENDIAN__ + version = os::Byteswap::byteswap(version); +#endif + data.read += sizeof(u32); + } + break; + case C3DS_EDIT_OBJECT: + { + core::stringc name; + readString(file, data, name); + readObjectChunk(file, &data); + composeObject(file, name); + } + break; + + default: + // ignore chunk + file->seek(data.header.length - data.read, true); + data.read += data.header.length - data.read; + } + + parent->read += data.read; + } + + return true; +} + + +bool C3DSMeshFileLoader::readObjectChunk(io::IReadFile* file, ChunkData* parent) +{ +#ifdef _IRR_DEBUG_3DS_LOADER_ + os::Printer::log("Load object chunk.", ELL_DEBUG); +#endif + while(parent->read < parent->header.length) + { + ChunkData data; + readChunkData(file, data); + + switch(data.header.id) + { + case C3DS_OBJTRIMESH: + readObjectChunk(file, &data); + break; + + case C3DS_TRIVERT: + readVertices(file, data); + break; + + case C3DS_POINTFLAGARRAY: + { + u16 numVertex, flags; + file->read(&numVertex, sizeof(u16)); +#ifdef __BIG_ENDIAN__ + numVertex= os::Byteswap::byteswap(numVertex); +#endif + for (u16 i=0; iread(&flags, sizeof(u16)); +#ifdef __BIG_ENDIAN__ + flags = os::Byteswap::byteswap(flags); +#endif + } + data.read += (numVertex+1)*sizeof(u16); + } + break; + + case C3DS_TRIFACE: + readIndices(file, data); + readObjectChunk(file, &data); // read smooth and material groups + break; + + case C3DS_TRIFACEMAT: + readMaterialGroup(file, data); + break; + + case C3DS_TRIUV: // getting texture coordinates + readTextureCoords(file, data); + break; + + case C3DS_TRIMATRIX: + { + f32 mat[4][3]; + file->read(&mat, 12*sizeof(f32)); + TransformationMatrix.makeIdentity(); + for (int i=0; i<4; ++i) + { + for (int j=0; j<3; ++j) + { +#ifdef __BIG_ENDIAN__ + TransformationMatrix(i,j)=os::Byteswap::byteswap(mat[i][j]); +#else + TransformationMatrix(i,j)=mat[i][j]; +#endif + } + } + data.read += 12*sizeof(f32); + } + break; + case C3DS_MESHCOLOR: + { + u8 flag; + file->read(&flag, sizeof(u8)); + ++data.read; + } + break; + case C3DS_TRISMOOTH: // TODO + { + SmoothingGroups = new u32[CountFaces]; + file->read(SmoothingGroups, CountFaces*sizeof(u32)); +#ifdef __BIG_ENDIAN__ + for (u16 i=0; iseek(data.header.length - data.read, true); + data.read += data.header.length - data.read; + } + + parent->read += data.read; + } + + return true; +} + + +void C3DSMeshFileLoader::composeObject(io::IReadFile* file, const core::stringc& name) +{ +#ifdef _IRR_DEBUG_3DS_LOADER_ + os::Printer::log("Compose object.", ELL_DEBUG); +#endif + if (Mesh->getMeshBufferCount() != Materials.size()) + loadMaterials(file); + + if (MaterialGroups.empty()) + { + // no material group, so add all + SMaterialGroup group; + group.faceCount = CountFaces; + group.faces = new u16[group.faceCount]; + for (u16 i=0; iaddMeshBuffer(mb); + mb->getMaterial() = Materials[0].Material; + mb->drop(); + // add an empty mesh buffer name + MeshBufferNames.push_back(""); + } + } + + for (u32 i=0; igetVideoDriver()->getMaximalPrimitiveCount(), (u32)((1<<16)-1))-3; // currently hardcoded s16 max value for index pointers + + // find mesh buffer for this group + for (mbPos=0; mbPosgetMeshBuffer(mbPos); + mat=&Materials[mbPos].Material; + MeshBufferNames[mbPos]=name; + break; + } + } + + if (mb != 0) + { + // add geometry to the buffer. + + video::S3DVertex vtx; + core::vector3df vec; + vtx.Color=mat->DiffuseColor; + if (mat->MaterialType==video::EMT_TRANSPARENT_VERTEX_ALPHA) + { + vtx.Color.setAlpha((int)(255.0f*mat->MaterialTypeParam)); + } + vtx.Normal.set(0,0,0); + + for (s32 f=0; fVertices.size(); + if (vtxCount>maxPrimitives) + { + IMeshBuffer* tmp = mb; + mb = new SMeshBuffer(); + Mesh->addMeshBuffer(mb); + mb->drop(); + Mesh->MeshBuffers[mbPos] = Mesh->MeshBuffers.getLast(); + Mesh->MeshBuffers[Mesh->MeshBuffers.size()-1] = tmp; + mb->getMaterial() = tmp->getMaterial(); + vtxCount=0; + } + + for (s32 v=0; v<3; ++v) + { + s32 idx = Indices[MaterialGroups[i].faces[f]*4 +v]; + + if (CountVertices > idx) + { + vtx.Pos.X = Vertices[idx*3 + 0]; + vtx.Pos.Z = Vertices[idx*3 + 1]; + vtx.Pos.Y = Vertices[idx*3 + 2]; +// TransformationMatrix.transformVect(vtx.Pos); + } + + if (CountTCoords > idx) + { + vtx.TCoords.X = TCoords[idx*2 + 0]; + vtx.TCoords.Y = 1.0f -TCoords[idx*2 + 1]; + } + + mb->Vertices.push_back(vtx); + } + + // compute normal + core::plane3d pl(mb->Vertices[vtxCount].Pos, mb->Vertices[vtxCount+2].Pos, + mb->Vertices[vtxCount+1].Pos); + + mb->Vertices[vtxCount].Normal = pl.Normal; + mb->Vertices[vtxCount+1].Normal = pl.Normal; + mb->Vertices[vtxCount+2].Normal = pl.Normal; + + // add indices + + mb->Indices.push_back(vtxCount); + mb->Indices.push_back(vtxCount+2); + mb->Indices.push_back(vtxCount+1); + } + } + else + os::Printer::log("Found no matching material for Group in 3ds file.", ELL_WARNING); + } + + cleanUp(); +} + + +void C3DSMeshFileLoader::loadMaterials(io::IReadFile* file) +{ + // create a mesh buffer for every material + core::stringc modelFilename = file->getFileName(); + + if (Materials.empty()) + os::Printer::log("No materials found in 3ds file.", ELL_INFORMATION); + + MeshBufferNames.reallocate(Materials.size()); + for (u32 i=0; iaddMeshBuffer(m); + + m->getMaterial() = Materials[i].Material; + if (Materials[i].Filename[0].size()) + { + video::ITexture* texture = 0; + if (FileSystem->existFile(Materials[i].Filename[0])) + texture = SceneManager->getVideoDriver()->getTexture(Materials[i].Filename[0]); + if (!texture) + { + const core::stringc fname = FileSystem->getFileDir(modelFilename) + "/" + FileSystem->getFileBasename(Materials[i].Filename[0]); + if (FileSystem->existFile(fname)) + texture = SceneManager->getVideoDriver()->getTexture(fname); + } + if (!texture) + os::Printer::log("Could not load a texture for entry in 3ds file", + Materials[i].Filename[0].c_str(), ELL_WARNING); + else + m->getMaterial().setTexture(0, texture); + } + + if (Materials[i].Filename[2].size()) + { + video::ITexture* texture = 0; + if (FileSystem->existFile(Materials[i].Filename[2])) + texture = SceneManager->getVideoDriver()->getTexture(Materials[i].Filename[2]); + if (!texture) + { + const core::stringc fname = FileSystem->getFileDir(modelFilename) + "/" + FileSystem->getFileBasename(Materials[i].Filename[2]); + if (FileSystem->existFile(fname)) + texture = SceneManager->getVideoDriver()->getTexture(fname); + } + if (!texture) + { + os::Printer::log("Could not load a texture for entry in 3ds file", + Materials[i].Filename[2].c_str(), ELL_WARNING); + } + else + { + m->getMaterial().setTexture(0, texture); + m->getMaterial().MaterialType = video::EMT_TRANSPARENT_ADD_COLOR; + } + } + + if (Materials[i].Filename[3].size()) + { + video::ITexture* texture = 0; + if (FileSystem->existFile(Materials[i].Filename[3])) + texture = SceneManager->getVideoDriver()->getTexture(Materials[i].Filename[3]); + if (!texture) + { + const core::stringc fname = FileSystem->getFileDir(modelFilename) + "/" + FileSystem->getFileBasename(Materials[i].Filename[3]); + if (FileSystem->existFile(fname)) + texture = SceneManager->getVideoDriver()->getTexture(fname); + } + + if (!texture) + { + os::Printer::log("Could not load a texture for entry in 3ds file", + Materials[i].Filename[3].c_str(), ELL_WARNING); + } + else + { + m->getMaterial().setTexture(1, m->getMaterial().getTexture(0)); + m->getMaterial().setTexture(0, texture); + m->getMaterial().MaterialType = video::EMT_REFLECTION_2_LAYER; + } + } + + if (Materials[i].Filename[4].size()) + { + video::ITexture* texture = 0; + if (FileSystem->existFile(Materials[i].Filename[4])) + texture = SceneManager->getVideoDriver()->getTexture(Materials[i].Filename[4]); + if (!texture) + { + const core::stringc fname = FileSystem->getFileDir(modelFilename) + "/" + FileSystem->getFileBasename(Materials[i].Filename[4]); + if (FileSystem->existFile(fname)) + texture = SceneManager->getVideoDriver()->getTexture(fname); + } + if (!texture) + os::Printer::log("Could not load a texture for entry in 3ds file", + Materials[i].Filename[4].c_str(), ELL_WARNING); + else + { + m->getMaterial().setTexture(1, texture); + SceneManager->getVideoDriver()->makeNormalMapTexture(texture, Materials[i].Strength[4]*10.f); + m->getMaterial().MaterialType=video::EMT_PARALLAX_MAP_SOLID; + m->getMaterial().MaterialTypeParam=.035f; + } + } + + m->drop(); + } +} + + +void C3DSMeshFileLoader::cleanUp() +{ + delete [] Vertices; + CountVertices = 0; + Vertices = 0; + delete [] Indices; + Indices = 0; + CountFaces = 0; + delete [] SmoothingGroups; + SmoothingGroups = 0; + delete [] TCoords; + TCoords = 0; + CountTCoords = 0; + + MaterialGroups.clear(); +} + + +void C3DSMeshFileLoader::readTextureCoords(io::IReadFile* file, ChunkData& data) +{ +#ifdef _IRR_DEBUG_3DS_LOADER_ + os::Printer::log("Load texture coords.", ELL_DEBUG); +#endif + file->read(&CountTCoords, sizeof(CountTCoords)); +#ifdef __BIG_ENDIAN__ + CountTCoords = os::Byteswap::byteswap(CountTCoords); +#endif + data.read += sizeof(CountTCoords); + + s32 tcoordsBufferByteSize = CountTCoords * sizeof(f32) * 2; + + if (data.header.length - data.read != tcoordsBufferByteSize) + { + os::Printer::log("Invalid size of tcoords found in 3ds file.", ELL_WARNING); + return; + } + + TCoords = new f32[CountTCoords * 3]; + file->read(TCoords, tcoordsBufferByteSize); +#ifdef __BIG_ENDIAN__ + for (int i=0;iread(&group.faceCount, sizeof(group.faceCount)); +#ifdef __BIG_ENDIAN__ + group.faceCount = os::Byteswap::byteswap(group.faceCount); +#endif + data.read += sizeof(group.faceCount); + + // read faces + group.faces = new u16[group.faceCount]; + file->read(group.faces, sizeof(u16) * group.faceCount); +#ifdef __BIG_ENDIAN__ + for (u32 i=0;iread(&CountFaces, sizeof(CountFaces)); +#ifdef __BIG_ENDIAN__ + CountFaces = os::Byteswap::byteswap(CountFaces); +#endif + data.read += sizeof(CountFaces); + + s32 indexBufferByteSize = CountFaces * sizeof(u16) * 4; + + // Indices are u16s. + // After every 3 Indices in the array, there follows an edge flag. + Indices = new u16[CountFaces * 4]; + file->read(Indices, indexBufferByteSize); +#ifdef __BIG_ENDIAN__ + for (int i=0;iread(&CountVertices, sizeof(CountVertices)); +#ifdef __BIG_ENDIAN__ + CountVertices = os::Byteswap::byteswap(CountVertices); +#endif + data.read += sizeof(CountVertices); + + const s32 vertexBufferByteSize = CountVertices * sizeof(f32) * 3; + + if (data.header.length - data.read != vertexBufferByteSize) + { + os::Printer::log("Invalid size of vertices found in 3ds file", core::stringc(CountVertices), ELL_ERROR); + return; + } + + Vertices = new f32[CountVertices * 3]; + file->read(Vertices, vertexBufferByteSize); +#ifdef __BIG_ENDIAN__ + for (int i=0;iread(&data.header, sizeof(ChunkHeader)); +#ifdef __BIG_ENDIAN__ + data.header.id = os::Byteswap::byteswap(data.header.id); + data.header.length = os::Byteswap::byteswap(data.header.length); +#endif + data.read += sizeof(ChunkHeader); +} + + +void C3DSMeshFileLoader::readString(io::IReadFile* file, ChunkData& data, core::stringc& out) +{ + c8 c = 1; + out = ""; + + while (c) + { + file->read(&c, sizeof(c8)); + if (c) + out.append(c); + } + data.read+=out.size()+1; +} + + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_3DS_LOADER_ + diff --git a/lib/irrlicht/source/Irrlicht/C3DSMeshFileLoader.h b/lib/irrlicht/source/Irrlicht/C3DSMeshFileLoader.h new file mode 100644 index 000000000..221925127 --- /dev/null +++ b/lib/irrlicht/source/Irrlicht/C3DSMeshFileLoader.h @@ -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; + + //! 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); + +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 TempIndices; + f32* TCoords; + u16 CountVertices; + u16 CountFaces; // = CountIndices/4 + u16 CountTCoords; + core::array MaterialGroups; + + SCurrentMaterial CurrentMaterial; + core::array Materials; + core::array MeshBufferNames; + core::matrix4 TransformationMatrix; + + SMesh* Mesh; +}; + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/lib/irrlicht/source/Irrlicht/CAndroidAssetFileArchive.cpp b/lib/irrlicht/source/Irrlicht/CAndroidAssetFileArchive.cpp new file mode 100644 index 000000000..100496236 --- /dev/null +++ b/lib/irrlicht/source/Irrlicht/CAndroidAssetFileArchive.cpp @@ -0,0 +1,101 @@ +// 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 +#include +#include + +namespace irr +{ +namespace io +{ + +CAndroidAssetFileArchive *createAndroidAssetFileArchive(bool ignoreCase, bool ignorePaths) +{ + if(!CIrrDeviceAndroid::getAndroidApp()) + return NULL; + return new CAndroidAssetFileArchive(ignoreCase, ignorePaths); +} + + +CAndroidAssetFileArchive::CAndroidAssetFileArchive(bool ignoreCase, bool ignorePaths) + : CFileList("/asset", ignoreCase, ignorePaths) +{ + AssetManager = CIrrDeviceAndroid::getAndroidApp()->activity->assetManager; + addDirectory(""); +} + + +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 + // for now getFileList does not work as expected. + return this; // Keep the compiler happy +} + + +//! opens a file by file name +IReadFile* CAndroidAssetFileArchive::createAndOpenFile(const io::path& filename) +{ + CAndroidAssetReader *reader = new CAndroidAssetReader(filename); + + if(reader->isOpen()) + return reader; + + reader->drop(); + return NULL; +} + +//! opens a file by index +IReadFile* CAndroidAssetFileArchive::createAndOpenFile(u32 index) +{ + // Since we can't list files, not much sense in giving them an index +} + +void CAndroidAssetFileArchive::addDirectory(const io::path &dirname) +{ + + AAssetDir *dir = AAssetManager_openDir(AssetManager, core::stringc(dirname).c_str()); + if(!dir) + return; + + addItem(dirname, 0, 0, /*isDir*/true, getFileCount()); + 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. + addItem(full_filename, /*offet*/0, /*size*/0, /*isDir*/false, + getFileCount()); + } +} + +} // end namespace io +} // end namespace irr + +#endif // _IRR_COMPILE_ANDROID_ASSET_READER_ diff --git a/lib/irrlicht/source/Irrlicht/CAndroidAssetFileArchive.h b/lib/irrlicht/source/Irrlicht/CAndroidAssetFileArchive.h new file mode 100644 index 000000000..8ba35240a --- /dev/null +++ b/lib/irrlicht/source/Irrlicht/CAndroidAssetFileArchive.h @@ -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 + +namespace irr +{ +namespace io +{ + +/*! + Android asset file system written August 2012 by J.Henrichs +*/ + class CAndroidAssetFileArchive : public virtual IFileArchive, + virtual CFileList + { + public: + + //! constructor + CAndroidAssetFileArchive(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 addDirectory(const io::path &filename); + protected: + //! Android's asset manager - keep a copy here + AAssetManager *AssetManager; + + }; // CAndroidAssetFileArchive + + + CAndroidAssetFileArchive *createAndroidAssetFileArchive(bool ignoreCase=false, + bool ignorePaths=false); + +} // end namespace io +} // end namespace irr + +#endif // _IRR_COMPILE_ANDROID_ASSET_READER_ +#endif // __C_ANDROID_ASSET_READER_H_INCLUDED__ + diff --git a/lib/irrlicht/source/Irrlicht/CAndroidAssetReader.cpp b/lib/irrlicht/source/Irrlicht/CAndroidAssetReader.cpp new file mode 100644 index 000000000..cc9954d03 --- /dev/null +++ b/lib/irrlicht/source/Irrlicht/CAndroidAssetReader.cpp @@ -0,0 +1,72 @@ +// 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 +#include +#include + +namespace irr +{ +namespace io +{ + +CAndroidAssetReader::CAndroidAssetReader(const io::path &filename) +{ + AssetManager = CIrrDeviceAndroid::getAndroidApp()->activity->assetManager; + Asset = AAssetManager_open(AssetManager, + core::stringc(filename).c_str(), + AASSET_MODE_RANDOM); + Filename = filename; + +} + +CAndroidAssetReader::~CAndroidAssetReader() +{ + if(Asset) + AAsset_close(Asset); +} + +s32 CAndroidAssetReader::read(void* buffer, u32 sizeToRead) +{ + return AAsset_read(Asset, buffer, sizeToRead); +} + +bool CAndroidAssetReader::seek(long finalPos, bool relativeMovement) +{ + long off = AAsset_seek(Asset, finalPos, relativeMovement ? SEEK_CUR + : SEEK_SET); + return off = relativeMovement-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_ diff --git a/lib/irrlicht/source/Irrlicht/CAndroidAssetReader.h b/lib/irrlicht/source/Irrlicht/CAndroidAssetReader.h new file mode 100644 index 000000000..5dbd9beaf --- /dev/null +++ b/lib/irrlicht/source/Irrlicht/CAndroidAssetReader.h @@ -0,0 +1,74 @@ +// 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; + +namespace irr +{ +namespace io +{ + + class CAndroidAssetReader : public virtual IReadFile + { + public: + CAndroidAssetReader(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 s32 read(void* buffer, u32 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; } + protected: + //! Android's asset manager - keep a copy here + 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__ + diff --git a/lib/irrlicht/source/Irrlicht/CIrrDeviceAndroid.cpp b/lib/irrlicht/source/Irrlicht/CIrrDeviceAndroid.cpp new file mode 100644 index 000000000..ad770a4bd --- /dev/null +++ b/lib/irrlicht/source/Irrlicht/CIrrDeviceAndroid.cpp @@ -0,0 +1,448 @@ +// 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 +#include "os.h" +#include "CFileSystem.h" +#include "CAndroidAssetFileArchive.h" + +namespace irr +{ + namespace video + { + IVideoDriver* createOGLES1Driver(const SIrrlichtCreationParameters& params, + video::SExposedVideoData& data, io::IFileSystem* io); + + IVideoDriver* createOGLES2Driver(const SIrrlichtCreationParameters& params, + video::SExposedVideoData& data, io::IFileSystem* io); + } +} + +namespace irr +{ + +android_app* CIrrDeviceAndroid::Android = NULL; +#include + +//! constructor +CIrrDeviceAndroid::CIrrDeviceAndroid(const SIrrlichtCreationParameters& param) + : CIrrDeviceStub(param), + Animating(false), + IsReady(false), + IsClosing(false), + DeviceWidth(param.WindowSize.Width), + DeviceHeight(param.WindowSize.Height), + MouseX(0), + MouseY(0) +{ + int ident; + int events; + struct android_poll_source* source; + + #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; + + // Create a sensor manager to recieve touch screen events from the + // java acivity. + SensorManager = ASensorManager_getInstance(); + SensorEventQueue = ASensorManager_createEventQueue( + SensorManager, Android->looper, + LOOPER_ID_USER, NULL, NULL); + Android->onInputEvent = handleInput; + + // Need to find a better way of doing this... but poll until the + // Android activity has been created and a window is open. The device + // cannot be created until the main window has been created by the + // Android OS. + os::Printer::log("Waiting for Android activity window to be created.", ELL_DEBUG); + + do + { + while( (ident = ALooper_pollAll( 0, NULL, &events,(void**)&source)) >= 0 ) + { + // Process this event. + if( source != NULL ) + { + source->process( Android, source ); + } + } + } + while( IsReady == false ); + + assert( Android->window ); + + // Create cursor control + CursorControl = new CCursorControl(this); + + // Create the driver. + createDriver(); + + if (VideoDriver) + createGUIAndScene(); + + io::CAndroidAssetFileArchive *assets = io::createAndroidAssetFileArchive(false, false); + assets->addDirectory("media"); + FileSystem->addFileArchive(assets); + // TODO + // + // if engine->app->savedState is not NULL then use postEventFromUser() + // with a custom android event so the user can use their own event + // receiver in order to load the apps previous state. + // The message should have a pointer to be filled and a size variable + // of how much data has been saved. Android free's this data later so + // there's no need to free it manually. + + Animating = true; +} + + +CIrrDeviceAndroid::~CIrrDeviceAndroid(void) +{ +} + +void CIrrDeviceAndroid::createDriver( void ) +{ + video::SExposedVideoData data; + + // Create the driver. + switch(CreationParams.DriverType) + { + case video::EDT_OGLES1: + #ifdef _IRR_COMPILE_WITH_OGLES1_ + VideoDriver = video::createOGLES1Driver(CreationParams, data, FileSystem); + #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, data, FileSystem); + #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; + + default: + os::Printer::log("Unable to create video driver of unknown type.", ELL_ERROR); + break; + } +} + +bool CIrrDeviceAndroid::run( void ) +{ + bool close = false; + + // Read all pending events. + int ident; + int events; + struct android_poll_source* source; + + // Check if Android is trying to shut us down. + if( IsClosing == true ) + return( false ); + + // If not animating, we will block forever waiting for events. + // If animating, we loop until all events are read, then continue + // to draw the next frame of animation. + while( ( ident = ALooper_pollAll( ( Animating || IsClosing ) ? 0 : -1, + NULL, &events, + (void**)&source)) >= 0 ) + { + // Process this event. + if( source != NULL ) + { + source->process( Android, source ); + } +#if 0 + // If a sensor has data, process it now. + if (ident == LOOPER_ID_USER) { + if (engine.accelerometerSensor != NULL) { + ASensorEvent event; + while (ASensorEventQueue_getEvents(engine.sensorEventQueue, + &event, 1) > 0) { + DEBUG_INFO1("accelerometer: x=%f y=%f z=%f", + event.acceleration.x, event.acceleration.y, + event.acceleration.z); + } + } + } +#endif + // Check if we are exiting. + if( Android->destroyRequested != 0 ) + { + close = true; + } + } + + os::Timer::tick(); + return( !close ); +} + +void CIrrDeviceAndroid::yield( void ) +{ +} + +void CIrrDeviceAndroid::sleep( u32 timeMs, bool pauseTimer ) +{ +} + +void CIrrDeviceAndroid::setWindowCaption(const wchar_t* text) +{ +} + +bool CIrrDeviceAndroid::present(video::IImage* surface, void* windowId, core::rect* srcClip) +{ + return( true ); +} + +bool CIrrDeviceAndroid::isWindowActive( void ) const +{ + return( true ); +} + +bool CIrrDeviceAndroid::isWindowFocused( void ) const +{ + return( false ); +} + +bool CIrrDeviceAndroid::isWindowMinimized( void ) const +{ + return( false ); +} + +void CIrrDeviceAndroid::closeDevice( void ) +{ +} + +void CIrrDeviceAndroid::setResizable( bool resize ) +{ +} + +void CIrrDeviceAndroid::minimizeWindow( void ) +{ +} + +void CIrrDeviceAndroid::maximizeWindow( void ) +{ +} + +void CIrrDeviceAndroid::restoreWindow( void ) +{ +} + +E_DEVICE_TYPE CIrrDeviceAndroid::getType( void ) const +{ + return( EIDT_ANDROID ); +} + +/////////////////////////////// +/////////////////////////////// + +void CIrrDeviceAndroid::handleAndroidCommand( struct android_app* app, s32 cmd ) +{ + CIrrDeviceAndroid *deviceAndroid = (CIrrDeviceAndroid *)app->userData; + switch (cmd) + { + case APP_CMD_SAVE_STATE: + os::Printer::log("Android command APP_CMD_SAVE_STATE", ELL_DEBUG); + + // TODO + // + // use postEventFromUser() with a custom android event so the user can + // use their own event receiver in order to save the apps state. + // The message should have a pointer to be filled and a size variable + // of ho emuch data has been saved. +#if 0 + // The system has asked us to save our current state. Do so. + engine->app->savedState = malloc(sizeof(struct saved_state)); + *((struct saved_state*)engine->app->savedState) = engine->state; + engine->app->savedStateSize = sizeof(struct saved_state); +#endif + break; + case APP_CMD_INIT_WINDOW: + os::Printer::log("Android command APP_CMD_INIT_WINDOW", ELL_DEBUG); + deviceAndroid->IsReady = true; + break; + case APP_CMD_TERM_WINDOW: + os::Printer::log("Android command APP_CMD_TERM_WINDOW", ELL_DEBUG); + break; + case APP_CMD_GAINED_FOCUS: + os::Printer::log("Android command APP_CMD_GAINED_FOCUS", ELL_DEBUG); +#if 0 + // When our app gains focus, we start monitoring the accelerometer. + if (engine->accelerometerSensor != NULL) { + ASensorEventQueue_enableSensor(engine->sensorEventQueue, + engine->accelerometerSensor); + // We'd like to get 60 events per second (in us). + ASensorEventQueue_setEventRate(engine->sensorEventQueue, + engine->accelerometerSensor, (1000L/60)*1000); + } +#endif + deviceAndroid->Animating = true; + break; + case APP_CMD_LOST_FOCUS: + os::Printer::log("Android command APP_CMD_LOST_FOCUS", ELL_DEBUG); + // When our app loses focus, we stop monitoring the accelerometer. + // This is to avoid consuming battery while not being used. +#if 0 + if (engine->accelerometerSensor != NULL) { + ASensorEventQueue_disableSensor(engine->sensorEventQueue, + engine->accelerometerSensor); + } +#endif + // Also stop animating. + deviceAndroid->Animating = false; + + break; + case APP_CMD_DESTROY: + // The application is being destroyed. We must close the native + // acitivity code and clean up otherwise the acitivity will stay + // active. + os::Printer::log("Android command APP_CMD_DESTROY", ELL_DEBUG); + deviceAndroid->IsClosing = true; + break; + + case APP_CMD_PAUSE: + os::Printer::log("Android command APP_CMD_PAUSE", ELL_DEBUG); + 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); + break; + + default: + os::Printer::log("Unhandled android command", + core::stringc(cmd).c_str(), ELL_WARNING ); + + } +} + +s32 CIrrDeviceAndroid::handleInput( struct android_app* app, AInputEvent* androidEvent ) +{ + CIrrDeviceAndroid *deviceAndroid = (CIrrDeviceAndroid *)app->userData; + int32_t eventAction; + int pointerCount = 0; + SEvent irrEvent; + int i = 0; + + if( AInputEvent_getType( androidEvent ) == AINPUT_EVENT_TYPE_MOTION ) + { + // Get the number of pointers. + pointerCount = AMotionEvent_getPointerCount( androidEvent ); + + // Get the actual input event type. + eventAction = AMotionEvent_getAction( androidEvent ); + + switch( eventAction ) + { + case AMOTION_EVENT_ACTION_DOWN: + if( pointerCount == 1 ) + { + irrEvent.EventType = EET_MOUSE_INPUT_EVENT; + irrEvent.MouseInput.Event = EMIE_LMOUSE_PRESSED_DOWN; + } + break; + + case AMOTION_EVENT_ACTION_MOVE: + if( pointerCount == 1 ) + { + irrEvent.EventType = EET_MOUSE_INPUT_EVENT; + irrEvent.MouseInput.Event = EMIE_MOUSE_MOVED; + } + else + { + irrEvent.EventType = EET_MULTI_TOUCH_EVENT; + irrEvent.MultiTouchInput.Event = EMTIE_MOVED; + } + + deviceAndroid->postEventFromUser(irrEvent); + break; + + case AMOTION_EVENT_ACTION_UP: + if( pointerCount == 1 ) + { + irrEvent.EventType = EET_MOUSE_INPUT_EVENT; + irrEvent.MouseInput.Event = EMIE_LMOUSE_LEFT_UP; + } + break; + default: + os::Printer::log("Unhandled motion event", + core::stringc(eventAction).c_str(), + ELL_WARNING ); + } + + if( pointerCount == 1 ) + { + // Fill in the details for a one touch event. + deviceAndroid->MouseX = irrEvent.MouseInput.X = AMotionEvent_getX(androidEvent, 0); + deviceAndroid->MouseY = irrEvent.MouseInput.Y = AMotionEvent_getY(androidEvent, 0); + irrEvent.MouseInput.ButtonStates = 0; + } + else if( pointerCount > 1 ) + { + // Fill in the details for a multi touch event. + for( i=0 ; ipostEventFromUser(irrEvent); + + return( 1 ); + } + return( 0 ); +} + +} // end namespace irr + +#endif + + diff --git a/lib/irrlicht/source/Irrlicht/CIrrDeviceAndroid.h b/lib/irrlicht/source/Irrlicht/CIrrDeviceAndroid.h new file mode 100644 index 000000000..a24f971b2 --- /dev/null +++ b/lib/irrlicht/source/Irrlicht/CIrrDeviceAndroid.h @@ -0,0 +1,157 @@ +// 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 +#include +#include "CIrrDeviceStub.h" +#include "IrrlichtDevice.h" +#include "IImagePresenter.h" +#include "ICursorControl.h" + +namespace irr +{ + + class CIrrDeviceAndroid : public CIrrDeviceStub, video::IImagePresenter + { + public: + + //! constructor + CIrrDeviceAndroid(const SIrrlichtCreationParameters& param); + + //! destructor + virtual ~CIrrDeviceAndroid(); + + virtual bool run( void ); + virtual void yield( void ); + 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* srcClip) ; + virtual bool isWindowActive( void ) const; + virtual bool isWindowFocused( void ) const; + virtual bool isWindowMinimized( void ) const; + virtual void closeDevice( void ); + virtual void setResizable( bool resize=false ); + virtual void minimizeWindow( void ); + virtual void maximizeWindow( void ); + virtual void restoreWindow( void ); + virtual E_DEVICE_TYPE getType( void ) const; + + //! Implementation of the linux cursor control + class CCursorControl : public gui::ICursorControl + { + public: + + CCursorControl(CIrrDeviceAndroid* dev) + : Device(dev), IsVisible(true) + { + } + + //! Changes the visible state of the mouse cursor. + virtual void setVisible(bool visible) + { + IsVisible = visible; + //if ( visible ) + // SDL_ShowCursor( SDL_ENABLE ); + //else + // SDL_ShowCursor( SDL_DISABLE ); + } + + //! Returns if the cursor is currently visible. + virtual bool isVisible() const + { + return IsVisible; + } + + //! Sets the new position of the cursor. + virtual void setPosition(const core::position2d &pos) + { + setPosition(pos.X, pos.Y); + } + + //! Sets the new position of the cursor. + virtual void setPosition(f32 x, f32 y) + { + setPosition((s32)(x*Device->DeviceWidth), (s32)(y*Device->DeviceHeight)); + } + + //! Sets the new position of the cursor. + virtual void setPosition(const core::position2d &pos) + { + setPosition(pos.X, pos.Y); + } + + //! Sets the new position of the cursor. + virtual void setPosition(s32 x, s32 y) + { + //SDL_WarpMouse( x, y ); + } + + //! Returns the current position of the mouse cursor. + virtual const core::position2d& getPosition() + { + updateCursorPos(); + return CursorPos; + } + + //! Returns the current position of the mouse cursor. + virtual core::position2d getRelativePosition() + { + updateCursorPos(); + return core::position2d(CursorPos.X / (f32)Device->DeviceWidth, + CursorPos.Y / (f32)Device->DeviceHeight); + } + + virtual void setReferenceRect(core::rect* rect=0) + { + } + + private: + + void updateCursorPos() + { + CursorPos.X = Device->MouseX; + CursorPos.Y = Device->MouseY; + + if (CursorPos.X < 0) + CursorPos.X = 0; + if (CursorPos.X > (s32)Device->DeviceWidth) + CursorPos.X = Device->DeviceWidth; + if (CursorPos.Y < 0) + CursorPos.Y = 0; + if (CursorPos.Y > (s32)Device->DeviceHeight) + CursorPos.Y = Device->DeviceHeight; + } + + CIrrDeviceAndroid* Device; + core::position2d CursorPos; + bool IsVisible; + }; + + static android_app *getAndroidApp() { return Android; } + private: + + static android_app *Android; + ASensorManager *SensorManager; + ASensorEventQueue *SensorEventQueue; + bool Animating; + bool IsReady; + bool IsClosing; + u32 DeviceWidth, DeviceHeight; + u32 MouseX, MouseY; + void createDriver( void ); + static void handleAndroidCommand( struct android_app* app, s32 cmd ); + static s32 handleInput( struct android_app* app, AInputEvent* event ); + }; + +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_ANDROID_DEVICE_ +#endif // __C_IRR_DEVICE_ANDROID_H_INCLUDED__ diff --git a/lib/irrlicht/source/Irrlicht/COGLESDriver.cpp b/lib/irrlicht/source/Irrlicht/COGLESDriver.cpp index f1b4904c0..f17ff606f 100644 --- a/lib/irrlicht/source/Irrlicht/COGLESDriver.cpp +++ b/lib/irrlicht/source/Irrlicht/COGLESDriver.cpp @@ -17,6 +17,8 @@ #include #endif +#include + namespace irr { namespace video @@ -41,6 +43,8 @@ COGLES1Driver::COGLES1Driver(const SIrrlichtCreationParameters& params, ,ViewDepthRenderbuffer(0) #endif { +__android_log_print(ANDROID_LOG_VERBOSE, "native-activity", "frame %d", __LINE__); +__android_log_print(ANDROID_LOG_VERBOSE, "native-activity", "frame %s %d", __FILE__, __LINE__); #ifdef _DEBUG setDebugName("COGLESDriver"); #endif @@ -55,8 +59,11 @@ COGLES1Driver::COGLES1Driver(const SIrrlichtCreationParameters& params, #elif defined(_IRR_COMPILE_WITH_IPHONE_DEVICE_) Device = device; #elif defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_) +__android_log_print(ANDROID_LOG_VERBOSE, "native-activity", "frame %s %d", __FILE__, __LINE__); +__android_log_print(ANDROID_LOG_VERBOSE, "native-activity", "frame %d %d", __LINE__, ((struct android_app *)(params.PrivateData))); EglWindow = ((struct android_app *)(params.PrivateData))->window; EglDisplay = EGL_NO_DISPLAY; +__android_log_print(ANDROID_LOG_VERBOSE, "native-activity", "frame %s %d", __FILE__, __LINE__); #endif #ifdef EGL_VERSION_1_0 if(EglDisplay == EGL_NO_DISPLAY) diff --git a/lib/irrlicht/source/Irrlicht/CSceneManager.cpp b/lib/irrlicht/source/Irrlicht/CSceneManager.cpp index eabb96ea8..48439f941 100644 --- a/lib/irrlicht/source/Irrlicht/CSceneManager.cpp +++ b/lib/irrlicht/source/Irrlicht/CSceneManager.cpp @@ -70,6 +70,14 @@ //! Enable debug features #define SCENEMANAGER_DEBUG +#ifdef _IRR_COMPILE_WITH_3DS_LOADER_ +#include "C3DSMeshFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_X_LOADER_ +#include "CXMeshFileLoader.h" +#endif + namespace irr { namespace scene @@ -126,6 +134,13 @@ CSceneManager::CSceneManager(video::IVideoDriver* driver, io::IFileSystem* fs, #ifdef _IRR_COMPILE_WITH_B3D_LOADER_ MeshLoaderList.push_back(new CB3DMeshFileLoader(this)); #endif + + #ifdef _IRR_COMPILE_WITH_3DS_LOADER_ + MeshLoaderList.push_back(new C3DSMeshFileLoader(this, FileSystem)); + #endif + #ifdef _IRR_COMPILE_WITH_X_LOADER_ + MeshLoaderList.push_back(new CXMeshFileLoader(this, FileSystem)); + #endif // factories diff --git a/lib/irrlicht/source/Irrlicht/CXMeshFileLoader.cpp b/lib/irrlicht/source/Irrlicht/CXMeshFileLoader.cpp new file mode 100644 index 000000000..595e91100 --- /dev/null +++ b/lib/irrlicht/source/Irrlicht/CXMeshFileLoader.cpp @@ -0,0 +1,2419 @@ +// 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_X_LOADER_ + +#include "CXMeshFileLoader.h" +#include "os.h" + +#include "fast_atof.h" +#include "coreutil.h" +#include "ISceneManager.h" +#include "IVideoDriver.h" +#include "IFileSystem.h" +#include "IReadFile.h" + +#ifdef _DEBUG +#define _XREADER_DEBUG +#endif +//#define BETTER_MESHBUFFER_SPLITTING_FOR_X + +namespace irr +{ +namespace scene +{ + +//! Constructor +CXMeshFileLoader::CXMeshFileLoader(scene::ISceneManager* smgr, io::IFileSystem* fs) +: SceneManager(smgr), FileSystem(fs), AllJoints(0), AnimatedMesh(0), + Buffer(0), P(0), End(0), BinaryNumCount(0), Line(0), + CurFrame(0), MajorVersion(0), MinorVersion(0), BinaryFormat(false), FloatSize(0) +{ + #ifdef _DEBUG + setDebugName("CXMeshFileLoader"); + #endif +} + + +//! returns true if the file maybe is able to be loaded by this class +//! based on the file extension (e.g. ".bsp") +bool CXMeshFileLoader::isALoadableFileExtension(const io::path& filename) const +{ + return core::hasFileExtension ( filename, "x" ); +} + + +//! 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* CXMeshFileLoader::createMesh(io::IReadFile* f) +{ + if (!f) + return 0; + +#ifdef _XREADER_DEBUG + u32 time = os::Timer::getRealTime(); +#endif + + AnimatedMesh = new CSkinnedMesh(); + + if (load(f)) + { + AnimatedMesh->finalize(); + } + else + { + AnimatedMesh->drop(); + AnimatedMesh = 0; + } +#ifdef _XREADER_DEBUG + time = os::Timer::getRealTime() - time; + core::stringc tmpString = "Time to load "; + tmpString += BinaryFormat ? "binary" : "ascii"; + tmpString += " X file: "; + tmpString += time; + tmpString += "ms"; + os::Printer::log(tmpString.c_str()); +#endif + //Clear up + + MajorVersion=0; + MinorVersion=0; + BinaryFormat=0; + BinaryNumCount=0; + FloatSize=0; + P=0; + End=0; + CurFrame=0; + TemplateMaterials.clear(); + + delete [] Buffer; + Buffer = 0; + + for (u32 i=0; iMaterials.size()) + { + mesh->Materials.push_back(video::SMaterial()); + mesh->Materials[0].DiffuseColor.set(0xff777777); + mesh->Materials[0].Shininess=0.f; + mesh->Materials[0].SpecularColor.set(0xff777777); + mesh->Materials[0].EmissiveColor.set(0xff000000); + } + + u32 i; + + mesh->Buffers.reallocate(mesh->Materials.size()); +#ifndef BETTER_MESHBUFFER_SPLITTING_FOR_X + const u32 bufferOffset = AnimatedMesh->getMeshBufferCount(); +#endif + for (i=0; iMaterials.size(); ++i) + { + mesh->Buffers.push_back( AnimatedMesh->addMeshBuffer() ); + mesh->Buffers.getLast()->Material = mesh->Materials[i]; + + if (!mesh->HasSkinning) + { + //Set up rigid animation + if (mesh->AttachedJointID!=-1) + { + AnimatedMesh->getAllJoints()[mesh->AttachedJointID]->AttachedMeshes.push_back( AnimatedMesh->getMeshBuffers().size()-1 ); + } + } + } + + if (!mesh->FaceMaterialIndices.size()) + { + mesh->FaceMaterialIndices.set_used(mesh->Indices.size() / 3); + for (i=0; iFaceMaterialIndices.size(); ++i) + mesh->FaceMaterialIndices[i]=0; + } + + if (!mesh->HasVertexColors) + { + for (u32 j=0;jFaceMaterialIndices.size();++j) + { + for (u32 id=j*3+0;id<=j*3+2;++id) + { + mesh->Vertices[ mesh->Indices[id] ].Color = mesh->Buffers[mesh->FaceMaterialIndices[j]]->Material.DiffuseColor; + } + } + } + + #ifdef BETTER_MESHBUFFER_SPLITTING_FOR_X + { + //the same vertex can be used in many different meshbuffers, but it's slow to work out + + core::array< core::array< u32 > > verticesLinkIndex; + verticesLinkIndex.reallocate(mesh->Vertices.size()); + core::array< core::array< u16 > > verticesLinkBuffer; + verticesLinkBuffer.reallocate(mesh->Vertices.size()); + + for (i=0;iVertices.size();++i) + { + verticesLinkIndex.push_back( core::array< u32 >() ); + verticesLinkBuffer.push_back( core::array< u16 >() ); + } + + for (i=0;iFaceMaterialIndices.size();++i) + { + for (u32 id=i*3+0;id<=i*3+2;++id) + { + core::array< u16 > &Array=verticesLinkBuffer[ mesh->Indices[id] ]; + bool found=false; + + for (u32 j=0; j < Array.size(); ++j) + { + if (Array[j]==mesh->FaceMaterialIndices[i]) + { + found=true; + break; + } + } + + if (!found) + Array.push_back( mesh->FaceMaterialIndices[i] ); + } + } + + for (i=0;iVertices.size();++i) + { + core::array< u16 > &Array = verticesLinkBuffer[i]; + verticesLinkIndex[i].reallocate(Array.size()); + for (u32 j=0; j < Array.size(); ++j) + { + scene::SSkinMeshBuffer *buffer = mesh->Buffers[ Array[j] ]; + verticesLinkIndex[i].push_back( buffer->Vertices_Standard.size() ); + buffer->Vertices_Standard.push_back( mesh->Vertices[i] ); + } + } + + for (i=0;iFaceMaterialIndices.size();++i) + { + scene::SSkinMeshBuffer *buffer=mesh->Buffers[ mesh->FaceMaterialIndices[i] ]; + + for (u32 id=i*3+0;id<=i*3+2;++id) + { + core::array< u16 > &Array=verticesLinkBuffer[ mesh->Indices[id] ]; + + for (u32 j=0;j< Array.size() ;++j) + { + if ( Array[j]== mesh->FaceMaterialIndices[i] ) + buffer->Indices.push_back( verticesLinkIndex[ mesh->Indices[id] ][j] ); + } + } + } + + for (u32 j=0;jWeightJoint.size();++j) + { + ISkinnedMesh::SJoint* joint = AnimatedMesh->getAllJoints()[mesh->WeightJoint[j]]; + ISkinnedMesh::SWeight& weight = joint->Weights[mesh->WeightNum[j]]; + + u32 id = weight.vertex_id; + + if (id>=verticesLinkIndex.size()) + { + os::Printer::log("X loader: Weight id out of range", ELL_WARNING); + id=0; + weight.strength=0.f; + } + + if (verticesLinkBuffer[id].size()==1) + { + weight.vertex_id=verticesLinkIndex[id][0]; + weight.buffer_id=verticesLinkBuffer[id][0]; + } + else if (verticesLinkBuffer[id].size() != 0) + { + for (u32 k=1; k < verticesLinkBuffer[id].size(); ++k) + { + ISkinnedMesh::SWeight* WeightClone = AnimatedMesh->addWeight(joint); + WeightClone->strength = weight.strength; + WeightClone->vertex_id = verticesLinkIndex[id][k]; + WeightClone->buffer_id = verticesLinkBuffer[id][k]; + } + } + } + } + #else + { + core::array< u32 > verticesLinkIndex; + core::array< s16 > verticesLinkBuffer; + verticesLinkBuffer.set_used(mesh->Vertices.size()); + + // init with 0 + for (i=0;iVertices.size();++i) + { + // watch out for vertices which are not part of the mesh + // they will keep the -1 and can lead to out-of-bounds access + verticesLinkBuffer[i]=-1; + } + + bool warned = false; + // store meshbuffer number per vertex + for (i=0;iFaceMaterialIndices.size();++i) + { + for (u32 id=i*3+0;id<=i*3+2;++id) + { + if ((verticesLinkBuffer[mesh->Indices[id]] != -1) && (verticesLinkBuffer[mesh->Indices[id]] != (s16)mesh->FaceMaterialIndices[i])) + { + if (!warned) + { + os::Printer::log("X loader", "Duplicated vertex, animation might be corrupted.", ELL_WARNING); + warned=true; + } + const u32 tmp = mesh->Vertices.size(); + mesh->Vertices.push_back(mesh->Vertices[ mesh->Indices[id] ]); + mesh->Indices[id] = tmp; + verticesLinkBuffer.set_used(mesh->Vertices.size()); + } + verticesLinkBuffer[ mesh->Indices[id] ] = mesh->FaceMaterialIndices[i]; + } + } + + if (mesh->FaceMaterialIndices.size() != 0) + { + // store vertices in buffers and remember relation in verticesLinkIndex + u32* vCountArray = new u32[mesh->Buffers.size()]; + memset(vCountArray, 0, mesh->Buffers.size()*sizeof(u32)); + // count vertices in each buffer and reallocate + for (i=0; iVertices.size(); ++i) + { + if (verticesLinkBuffer[i] != -1) + ++vCountArray[verticesLinkBuffer[i]]; + } + if (mesh->TCoords2.size()) + { + for (i=0; i!=mesh->Buffers.size(); ++i) + { + mesh->Buffers[i]->Vertices_2TCoords.reallocate(vCountArray[i]); + mesh->Buffers[i]->VertexType=video::EVT_2TCOORDS; + } + } + else + { + for (i=0; i!=mesh->Buffers.size(); ++i) + mesh->Buffers[i]->Vertices_Standard.reallocate(vCountArray[i]); + } + + verticesLinkIndex.set_used(mesh->Vertices.size()); + // actually store vertices + for (i=0; iVertices.size(); ++i) + { + // if a vertex is missing for some reason, just skip it + if (verticesLinkBuffer[i]==-1) + continue; + scene::SSkinMeshBuffer *buffer = mesh->Buffers[ verticesLinkBuffer[i] ]; + + if (mesh->TCoords2.size()) + { + verticesLinkIndex[i] = buffer->Vertices_2TCoords.size(); + buffer->Vertices_2TCoords.push_back( mesh->Vertices[i] ); + // We have a problem with correct tcoord2 handling here + // crash fixed for now by checking the values + buffer->Vertices_2TCoords.getLast().TCoords2=(iTCoords2.size())?mesh->TCoords2[i]:mesh->Vertices[i].TCoords; + } + else + { + verticesLinkIndex[i] = buffer->Vertices_Standard.size(); + buffer->Vertices_Standard.push_back( mesh->Vertices[i] ); + } + } + + // count indices per buffer and reallocate + memset(vCountArray, 0, mesh->Buffers.size()*sizeof(u32)); + for (i=0; iFaceMaterialIndices.size(); ++i) + ++vCountArray[ mesh->FaceMaterialIndices[i] ]; + for (i=0; i!=mesh->Buffers.size(); ++i) + mesh->Buffers[i]->Indices.reallocate(vCountArray[i]); + delete [] vCountArray; + // create indices per buffer + for (i=0; iFaceMaterialIndices.size(); ++i) + { + scene::SSkinMeshBuffer *buffer = mesh->Buffers[ mesh->FaceMaterialIndices[i] ]; + for (u32 id=i*3+0; id!=i*3+3; ++id) + { + buffer->Indices.push_back( verticesLinkIndex[ mesh->Indices[id] ] ); + } + } + } + + for (u32 j=0; jWeightJoint.size(); ++j) + { + ISkinnedMesh::SWeight& weight = (AnimatedMesh->getAllJoints()[mesh->WeightJoint[j]]->Weights[mesh->WeightNum[j]]); + + u32 id = weight.vertex_id; + + if (id>=verticesLinkIndex.size()) + { + os::Printer::log("X loader: Weight id out of range", ELL_WARNING); + id=0; + weight.strength=0.f; + } + + weight.vertex_id=verticesLinkIndex[id]; + weight.buffer_id=verticesLinkBuffer[id] + bufferOffset; + } + } + #endif + + } + + return true; +} + + +//! Reads file into memory +bool CXMeshFileLoader::readFileIntoMemory(io::IReadFile* file) +{ + const long size = file->getSize(); + if (size < 12) + { + os::Printer::log("X File is too small.", ELL_WARNING); + return false; + } + + Buffer = new c8[size]; + + //! read all into memory + if (file->read(Buffer, size) != size) + { + os::Printer::log("Could not read from x file.", ELL_WARNING); + return false; + } + + Line = 1; + End = Buffer + size; + + //! check header "xof " + if (strncmp(Buffer, "xof ", 4)!=0) + { + os::Printer::log("Not an x file, wrong header.", ELL_WARNING); + return false; + } + + //! read minor and major version, e.g. 0302 or 0303 + c8 tmp[3]; + tmp[0] = Buffer[4]; + tmp[1] = Buffer[5]; + tmp[2] = 0x0; + MajorVersion = core::strtoul10(tmp); + + tmp[0] = Buffer[6]; + tmp[1] = Buffer[7]; + MinorVersion = core::strtoul10(tmp); + + //! read format + if (strncmp(&Buffer[8], "txt ", 4) ==0) + BinaryFormat = false; + else if (strncmp(&Buffer[8], "bin ", 4) ==0) + BinaryFormat = true; + else + { + os::Printer::log("Only uncompressed x files currently supported.", ELL_WARNING); + return false; + } + BinaryNumCount=0; + + //! read float size + if (strncmp(&Buffer[12], "0032", 4) ==0) + FloatSize = 4; + else if (strncmp(&Buffer[12], "0064", 4) ==0) + FloatSize = 8; + else + { + os::Printer::log("Float size not supported.", ELL_WARNING); + return false; + } + + P = &Buffer[16]; + + readUntilEndOfLine(); + FilePath = FileSystem->getFileDir(file->getFileName()) + "/"; + + return true; +} + + +//! Parses the file +bool CXMeshFileLoader::parseFile() +{ + while(parseDataObject()) + { + // loop + } + + return true; +} + + +//! Parses the next Data object in the file +bool CXMeshFileLoader::parseDataObject() +{ + core::stringc objectName = getNextToken(); + + if (objectName.size() == 0) + return false; + + // parse specific object +#ifdef _XREADER_DEBUG + os::Printer::log("debug DataObject:", objectName.c_str(), ELL_DEBUG); +#endif + + if (objectName == "template") + return parseDataObjectTemplate(); + else + if (objectName == "Frame") + { + return parseDataObjectFrame( 0 ); + } + else + if (objectName == "Mesh") + { + // some meshes have no frames at all + //CurFrame = AnimatedMesh->addJoint(0); + + SXMesh *mesh=new SXMesh; + + //mesh->Buffer=AnimatedMesh->addMeshBuffer(); + Meshes.push_back(mesh); + + return parseDataObjectMesh(*mesh); + } + else + if (objectName == "AnimationSet") + { + return parseDataObjectAnimationSet(); + } + else + if (objectName == "Material") + { + // template materials now available thanks to joeWright + TemplateMaterials.push_back(SXTemplateMaterial()); + TemplateMaterials.getLast().Name = getNextToken(); + return parseDataObjectMaterial(TemplateMaterials.getLast().Material); + } + else + if (objectName == "}") + { + os::Printer::log("} found in dataObject", ELL_WARNING); + return true; + } + + os::Printer::log("Unknown data object in animation of .x file", objectName.c_str(), ELL_WARNING); + + return parseUnknownDataObject(); +} + + +bool CXMeshFileLoader::parseDataObjectTemplate() +{ +#ifdef _XREADER_DEBUG + os::Printer::log("CXFileReader: Reading template", ELL_DEBUG); +#endif + + // parse a template data object. Currently not stored. + core::stringc name; + + if (!readHeadOfDataObject(&name)) + { + os::Printer::log("Left delimiter in template data object missing.", + name.c_str(), ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + // read GUID + getNextToken(); + + // read and ignore data members + while(true) + { + core::stringc s = getNextToken(); + + if (s == "}") + break; + + if (s.size() == 0) + return false; + } + + return true; +} + + +bool CXMeshFileLoader::parseDataObjectFrame(CSkinnedMesh::SJoint *Parent) +{ +#ifdef _XREADER_DEBUG + os::Printer::log("CXFileReader: Reading frame", ELL_DEBUG); +#endif + + // A coordinate frame, or "frame of reference." The Frame template + // is open and can contain any object. The Direct3D extensions (D3DX) + // mesh-loading functions recognize Mesh, FrameTransformMatrix, and + // Frame template instances as child objects when loading a Frame + // instance. + + u32 JointID=0; + + core::stringc name; + + if (!readHeadOfDataObject(&name)) + { + os::Printer::log("No opening brace in Frame found in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + CSkinnedMesh::SJoint *joint=0; + + if (name.size()) + { + for (u32 n=0; n < AnimatedMesh->getAllJoints().size(); ++n) + { + if (AnimatedMesh->getAllJoints()[n]->Name==name) + { + joint=AnimatedMesh->getAllJoints()[n]; + JointID=n; + break; + } + } + } + + if (!joint) + { +#ifdef _XREADER_DEBUG + os::Printer::log("creating joint ", name.c_str(), ELL_DEBUG); +#endif + joint=AnimatedMesh->addJoint(Parent); + joint->Name=name; + JointID=AnimatedMesh->getAllJoints().size()-1; + } + else + { +#ifdef _XREADER_DEBUG + os::Printer::log("using joint ", name.c_str(), ELL_DEBUG); +#endif + if (Parent) + Parent->Children.push_back(joint); + } + + // Now inside a frame. + // read tokens until closing brace is reached. + + while(true) + { + core::stringc objectName = getNextToken(); + +#ifdef _XREADER_DEBUG + os::Printer::log("debug DataObject in frame:", objectName.c_str(), ELL_DEBUG); +#endif + + if (objectName.size() == 0) + { + os::Printer::log("Unexpected ending found in Frame in x file.", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + else + if (objectName == "}") + { + break; // frame finished + } + else + if (objectName == "Frame") + { + + if (!parseDataObjectFrame(joint)) + return false; + } + else + if (objectName == "FrameTransformMatrix") + { + if (!parseDataObjectTransformationMatrix(joint->LocalMatrix)) + return false; + + //joint->LocalAnimatedMatrix + //joint->LocalAnimatedMatrix.makeInverse(); + //joint->LocalMatrix=tmp*joint->LocalAnimatedMatrix; + } + else + if (objectName == "Mesh") + { + /* + frame.Meshes.push_back(SXMesh()); + if (!parseDataObjectMesh(frame.Meshes.getLast())) + return false; + */ + SXMesh *mesh=new SXMesh; + + mesh->AttachedJointID=JointID; + + Meshes.push_back(mesh); + + if (!parseDataObjectMesh(*mesh)) + return false; + } + else + { + os::Printer::log("Unknown data object in frame in x file", objectName.c_str(), ELL_WARNING); + if (!parseUnknownDataObject()) + return false; + } + } + + return true; +} + + +bool CXMeshFileLoader::parseDataObjectTransformationMatrix(core::matrix4 &mat) +{ +#ifdef _XREADER_DEBUG + os::Printer::log("CXFileReader: Reading Transformation Matrix", ELL_DEBUG); +#endif + + if (!readHeadOfDataObject()) + { + os::Printer::log("No opening brace in Transformation Matrix found in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + readMatrix(mat); + + if (!checkForOneFollowingSemicolons()) + { + os::Printer::log("No finishing semicolon in Transformation Matrix found in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + } + + if (!checkForClosingBrace()) + { + os::Printer::log("No closing brace in Transformation Matrix found in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + return true; +} + + +bool CXMeshFileLoader::parseDataObjectMesh(SXMesh &mesh) +{ + core::stringc name; + + if (!readHeadOfDataObject(&name)) + { +#ifdef _XREADER_DEBUG + os::Printer::log("CXFileReader: Reading mesh", ELL_DEBUG); +#endif + os::Printer::log("No opening brace in Mesh found in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + +#ifdef _XREADER_DEBUG + os::Printer::log("CXFileReader: Reading mesh", name.c_str(), ELL_DEBUG); +#endif + + // read vertex count + const u32 nVertices = readInt(); + + // read vertices + mesh.Vertices.set_used(nVertices); + for (u32 n=0; n polygonfaces; + u32 currentIndex = 0; + + for (u32 k=0; k>8)&0xf)*sizeof(core::vector2df); + for (u32 j=0; jgetAllJoints().size(); ++n) + { + if (AnimatedMesh->getAllJoints()[n]->Name==TransformNodeName) + { + joint=AnimatedMesh->getAllJoints()[n]; + break; + } + } + + if (!joint) + { +#ifdef _XREADER_DEBUG + os::Printer::log("creating joint for skinning ", TransformNodeName.c_str(), ELL_DEBUG); +#endif + n = AnimatedMesh->getAllJoints().size(); + joint=AnimatedMesh->addJoint(0); + joint->Name=TransformNodeName; + } + + // read vertex weights + const u32 nWeights = readInt(); + + // read vertex indices + u32 i; + + const u32 jointStart = joint->Weights.size(); + joint->Weights.reallocate(jointStart+nWeights); + + mesh.WeightJoint.reallocate( mesh.WeightJoint.size() + nWeights ); + mesh.WeightNum.reallocate( mesh.WeightNum.size() + nWeights ); + + for (i=0; iWeights.size()); + + CSkinnedMesh::SWeight *weight=AnimatedMesh->addWeight(joint); + + weight->buffer_id=0; + weight->vertex_id=readInt(); + } + + // read vertex weights + + for (i=jointStart; iWeights[i].strength = readFloat(); + + // read matrix offset + + // transforms the mesh vertices to the space of the bone + // When concatenated to the bone's transform, this provides the + // world space coordinates of the mesh as affected by the bone + core::matrix4& MatrixOffset = joint->GlobalInversedMatrix; + + readMatrix(MatrixOffset); + + if (!checkForOneFollowingSemicolons()) + { + os::Printer::log("No finishing semicolon in Skin Weights found in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + } + + if (!checkForClosingBrace()) + { + os::Printer::log("No closing brace in Skin Weights found in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + return true; +} + + +bool CXMeshFileLoader::parseDataObjectSkinMeshHeader(SXMesh& mesh) +{ +#ifdef _XREADER_DEBUG + os::Printer::log("CXFileReader: Reading skin mesh header", ELL_DEBUG); +#endif + + if (!readHeadOfDataObject()) + { + os::Printer::log("No opening brace in Skin Mesh header found in .x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + mesh.MaxSkinWeightsPerVertex = readInt(); + mesh.MaxSkinWeightsPerFace = readInt(); + mesh.BoneCount = readInt(); + + if (!BinaryFormat) + getNextToken(); // skip semicolon + + if (!checkForClosingBrace()) + { + os::Printer::log("No closing brace in skin mesh header in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + return true; +} + + +bool CXMeshFileLoader::parseDataObjectMeshNormals(SXMesh &mesh) +{ +#ifdef _XREADER_DEBUG + os::Printer::log("CXFileReader: reading mesh normals", ELL_DEBUG); +#endif + + if (!readHeadOfDataObject()) + { + os::Printer::log("No opening brace in Mesh Normals found in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + // read count + const u32 nNormals = readInt(); + core::array normals; + normals.set_used(nNormals); + + // read normals + for (u32 i=0; i normalIndices; + normalIndices.set_used(mesh.Indices.size()); + + // read face normal indices + const u32 nFNormals = readInt(); + + u32 normalidx = 0; + core::array polygonfaces; + for (u32 k=0; k=mesh.Vertices.size()) + { + os::Printer::log("index value in parseDataObjectMeshVertexColors out of bounds", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + readRGBA(mesh.Vertices[Index].Color); + checkForOneFollowingSemicolons(); + } + + if (!checkForOneFollowingSemicolons()) + { + os::Printer::log("No finishing semicolon in Mesh Vertex Colors Array found in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + } + + if (!checkForClosingBrace()) + { + os::Printer::log("No closing brace in Mesh Texture Coordinates Array found in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + return true; +} + + +bool CXMeshFileLoader::parseDataObjectMeshMaterialList(SXMesh &mesh) +{ +#ifdef _XREADER_DEBUG + os::Printer::log("CXFileReader: Reading mesh material list", ELL_DEBUG); +#endif + + if (!readHeadOfDataObject()) + { + os::Printer::log("No opening brace in Mesh Material List found in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + // read material count + mesh.Materials.reallocate(readInt()); + + // read non triangulated face material index count + const u32 nFaceIndices = readInt(); + + // There seems to be a compact representation of "all faces the same material" + // being represented as 1;1;0;; which means 1 material, 1 face with first material + // all the other faces have to obey then, so check is disabled + //if (nFaceIndices != mesh.IndexCountPerFace.size()) + // os::Printer::log("Index count per face not equal to face material index count in x file.", ELL_WARNING); + + // read non triangulated face indices and create triangulated ones + mesh.FaceMaterialIndices.set_used( mesh.Indices.size() / 3); + u32 triangulatedindex = 0; + u32 ind = 0; + for (u32 tfi=0; tfiexistFile(TextureFileName)) + material.setTexture(textureLayer, SceneManager->getVideoDriver()->getTexture(TextureFileName)); + // mesh path + else + { + TextureFileName=FilePath + FileSystem->getFileBasename(TextureFileName); + if (FileSystem->existFile(TextureFileName)) + material.setTexture(textureLayer, SceneManager->getVideoDriver()->getTexture(TextureFileName)); + // working directory + else + material.setTexture(textureLayer, SceneManager->getVideoDriver()->getTexture(FileSystem->getFileBasename(TextureFileName))); + } + ++textureLayer; + if (textureLayer==2) + material.MaterialType=video::EMT_LIGHTMAP; + } + else + if (objectName.equals_ignore_case("NormalmapFilename")) + { + // some exporters write "NormalmapFileName" instead. + core::stringc TextureFileName; + if (!parseDataObjectTextureFilename(TextureFileName)) + return false; + + // original name + if (FileSystem->existFile(TextureFileName)) + material.setTexture(1, SceneManager->getVideoDriver()->getTexture(TextureFileName)); + // mesh path + else + { + TextureFileName=FilePath + FileSystem->getFileBasename(TextureFileName); + if (FileSystem->existFile(TextureFileName)) + material.setTexture(1, SceneManager->getVideoDriver()->getTexture(TextureFileName)); + // working directory + else + material.setTexture(1, SceneManager->getVideoDriver()->getTexture(FileSystem->getFileBasename(TextureFileName))); + } + if (textureLayer==1) + ++textureLayer; + } + else + { + os::Printer::log("Unknown data object in material in .x file", objectName.c_str(), ELL_WARNING); + if (!parseUnknownDataObject()) + return false; + } + } + + return true; +} + + +bool CXMeshFileLoader::parseDataObjectAnimationSet() +{ +#ifdef _XREADER_DEBUG + os::Printer::log("CXFileReader: Reading animation set", ELL_DEBUG); +#endif + + core::stringc AnimationName; + + if (!readHeadOfDataObject(&AnimationName)) + { + os::Printer::log("No opening brace in Animation Set found in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + os::Printer::log("Reading animationset ", AnimationName, ELL_DEBUG); + + while(true) + { + core::stringc objectName = getNextToken(); + + if (objectName.size() == 0) + { + os::Printer::log("Unexpected ending found in Animation set in x file.", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + else + if (objectName == "}") + { + break; // animation set finished + } + else + if (objectName == "Animation") + { + if (!parseDataObjectAnimation()) + return false; + } + else + { + os::Printer::log("Unknown data object in animation set in x file", objectName.c_str(), ELL_WARNING); + if (!parseUnknownDataObject()) + return false; + } + } + return true; +} + + +bool CXMeshFileLoader::parseDataObjectAnimation() +{ +#ifdef _XREADER_DEBUG + os::Printer::log("CXFileReader: reading animation", ELL_DEBUG); +#endif + + if (!readHeadOfDataObject()) + { + os::Printer::log("No opening brace in Animation found in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + //anim.closed = true; + //anim.linearPositionQuality = true; + CSkinnedMesh::SJoint animationDump; + + core::stringc FrameName; + + while(true) + { + core::stringc objectName = getNextToken(); + + if (objectName.size() == 0) + { + os::Printer::log("Unexpected ending found in Animation in x file.", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + else + if (objectName == "}") + { + break; // animation finished + } + else + if (objectName == "AnimationKey") + { + if (!parseDataObjectAnimationKey(&animationDump)) + return false; + } + else + if (objectName == "AnimationOptions") + { + //TODO: parse options. + if (!parseUnknownDataObject()) + return false; + } + else + if (objectName == "{") + { + // read frame name + FrameName = getNextToken(); + + if (!checkForClosingBrace()) + { + os::Printer::log("Unexpected ending found in Animation in x file.", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + } + else + { + os::Printer::log("Unknown data object in animation in x file", objectName.c_str(), ELL_WARNING); + if (!parseUnknownDataObject()) + return false; + } + } + + if (FrameName.size() != 0) + { +#ifdef _XREADER_DEBUG + os::Printer::log("frame name", FrameName.c_str(), ELL_DEBUG); +#endif + CSkinnedMesh::SJoint *joint=0; + + u32 n; + for (n=0; n < AnimatedMesh->getAllJoints().size(); ++n) + { + if (AnimatedMesh->getAllJoints()[n]->Name==FrameName) + { + joint=AnimatedMesh->getAllJoints()[n]; + break; + } + } + + if (!joint) + { +#ifdef _XREADER_DEBUG + os::Printer::log("creating joint for animation ", FrameName.c_str(), ELL_DEBUG); +#endif + joint=AnimatedMesh->addJoint(0); + joint->Name=FrameName; + } + + joint->PositionKeys.reallocate(joint->PositionKeys.size()+animationDump.PositionKeys.size()); + for (n=0; nPositionKeys.push_back(animationDump.PositionKeys[n]); + } + + joint->ScaleKeys.reallocate(joint->ScaleKeys.size()+animationDump.ScaleKeys.size()); + for (n=0; nScaleKeys.push_back(animationDump.ScaleKeys[n]); + } + + joint->RotationKeys.reallocate(joint->RotationKeys.size()+animationDump.RotationKeys.size()); + for (n=0; nRotationKeys.push_back(animationDump.RotationKeys[n]); + } + } + else + os::Printer::log("joint name was never given", ELL_WARNING); + + return true; +} + + +bool CXMeshFileLoader::parseDataObjectAnimationKey(ISkinnedMesh::SJoint *joint) +{ +#ifdef _XREADER_DEBUG + os::Printer::log("CXFileReader: reading animation key", ELL_DEBUG); +#endif + + if (!readHeadOfDataObject()) + { + os::Printer::log("No opening brace in Animation Key found in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + // read key type + + const u32 keyType = readInt(); + + if (keyType > 4) + { + os::Printer::log("Unknown key type found in Animation Key in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + // read number of keys + const u32 numberOfKeys = readInt(); + + // eat the semicolon after the "0". if there are keys present, readInt() + // does this for us. If there aren't, we need to do it explicitly + if (numberOfKeys == 0) + checkForOneFollowingSemicolons(); + + for (u32 i=0; iaddRotationKey(joint); + key->frame=time; + key->rotation.set(X,Y,Z,W); + } + break; + case 1: //scale + case 2: //position + { + // read vectors + + // read count + if (readInt() != 3) + { + os::Printer::log("Expected 3 numbers in animation key in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + core::vector3df vector; + readVector3(vector); + + if (!checkForTwoFollowingSemicolons()) + { + os::Printer::log("No finishing semicolon after vector animation key in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + } + + if (keyType==2) + { + ISkinnedMesh::SPositionKey *key=AnimatedMesh->addPositionKey(joint); + key->frame=time; + key->position=vector; + } + else + { + ISkinnedMesh::SScaleKey *key=AnimatedMesh->addScaleKey(joint); + key->frame=time; + key->scale=vector; + } + } + break; + case 3: + case 4: + { + // read matrix + + // read count + if (readInt() != 16) + { + os::Printer::log("Expected 16 numbers in animation key in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + // read matrix + core::matrix4 mat(core::matrix4::EM4CONST_NOTHING); + readMatrix(mat); + + //mat=joint->LocalMatrix*mat; + + if (!checkForOneFollowingSemicolons()) + { + os::Printer::log("No finishing semicolon after matrix animation key in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + } + + //core::vector3df rotation = mat.getRotationDegrees(); + + ISkinnedMesh::SRotationKey *keyR=AnimatedMesh->addRotationKey(joint); + keyR->frame=time; + + // IRR_TEST_BROKEN_QUATERNION_USE: TODO - switched from mat to mat.getTransposed() for downward compatibility. + // Not tested so far if this was correct or wrong before quaternion fix! + keyR->rotation= core::quaternion(mat.getTransposed()); + + ISkinnedMesh::SPositionKey *keyP=AnimatedMesh->addPositionKey(joint); + keyP->frame=time; + keyP->position=mat.getTranslation(); + +/* + core::vector3df scale=mat.getScale(); + + if (scale.X==0) + scale.X=1; + if (scale.Y==0) + scale.Y=1; + if (scale.Z==0) + scale.Z=1; + ISkinnedMesh::SScaleKey *keyS=AnimatedMesh->addScaleKey(joint); + keyS->frame=time; + keyS->scale=scale; +*/ + } + break; + } // end switch + } + + if (!checkForOneFollowingSemicolons()) + --P; + + if (!checkForClosingBrace()) + { + os::Printer::log("No closing brace in animation key in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + return true; +} + + +bool CXMeshFileLoader::parseDataObjectTextureFilename(core::stringc& texturename) +{ +#ifdef _XREADER_DEBUG + os::Printer::log("CXFileReader: reading texture filename", ELL_DEBUG); +#endif + + if (!readHeadOfDataObject()) + { + os::Printer::log("No opening brace in Texture filename found in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + if (!getNextTokenAsString(texturename)) + { + os::Printer::log("Unknown syntax while reading texture filename string in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + if (!checkForClosingBrace()) + { + os::Printer::log("No closing brace in Texture filename found in x file", ELL_WARNING); + os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); + return false; + } + + return true; +} + + +bool CXMeshFileLoader::parseUnknownDataObject() +{ + // find opening delimiter + while(true) + { + core::stringc t = getNextToken(); + + if (t.size() == 0) + return false; + + if (t == "{") + break; + } + + u32 counter = 1; + + // parse until closing delimiter + + while(counter) + { + core::stringc t = getNextToken(); + + if (t.size() == 0) + return false; + + if (t == "{") + ++counter; + else + if (t == "}") + --counter; + } + + return true; +} + + +//! checks for closing curly brace, returns false if not there +bool CXMeshFileLoader::checkForClosingBrace() +{ + return (getNextToken() == "}"); +} + + +//! checks for one following semicolon, returns false if not there +bool CXMeshFileLoader::checkForOneFollowingSemicolons() +{ + if (BinaryFormat) + return true; + + if (getNextToken() == ";") + return true; + else + { + --P; + return false; + } +} + + +//! checks for two following semicolons, returns false if they are not there +bool CXMeshFileLoader::checkForTwoFollowingSemicolons() +{ + if (BinaryFormat) + return true; + + for (u32 k=0; k<2; ++k) + { + if (getNextToken() != ";") + { + --P; + return false; + } + } + + return true; +} + + +//! reads header of dataobject including the opening brace. +//! returns false if error happened, and writes name of object +//! if there is one +bool CXMeshFileLoader::readHeadOfDataObject(core::stringc* outname) +{ + core::stringc nameOrBrace = getNextToken(); + if (nameOrBrace != "{") + { + if (outname) + (*outname) = nameOrBrace; + + if (getNextToken() != "{") + return false; + } + + return true; +} + + +//! returns next parseable token. Returns empty string if no token there +core::stringc CXMeshFileLoader::getNextToken() +{ + core::stringc s; + + // process binary-formatted file + if (BinaryFormat) + { + // in binary mode it will only return NAME and STRING token + // and (correctly) skip over other tokens. + + s16 tok = readBinWord(); + u32 len; + + // standalone tokens + switch (tok) { + case 1: + // name token + len = readBinDWord(); + s = core::stringc(P, len); + P += len; + return s; + case 2: + // string token + len = readBinDWord(); + s = core::stringc(P, len); + P += (len + 2); + return s; + case 3: + // integer token + P += 4; + return ""; + case 5: + // GUID token + P += 16; + return ""; + case 6: + len = readBinDWord(); + P += (len * 4); + return ""; + case 7: + len = readBinDWord(); + P += (len * FloatSize); + return ""; + case 0x0a: + return "{"; + case 0x0b: + return "}"; + case 0x0c: + return "("; + case 0x0d: + return ")"; + case 0x0e: + return "["; + case 0x0f: + return "]"; + case 0x10: + return "<"; + case 0x11: + return ">"; + case 0x12: + return "."; + case 0x13: + return ","; + case 0x14: + return ";"; + case 0x1f: + return "template"; + case 0x28: + return "WORD"; + case 0x29: + return "DWORD"; + case 0x2a: + return "FLOAT"; + case 0x2b: + return "DOUBLE"; + case 0x2c: + return "CHAR"; + case 0x2d: + return "UCHAR"; + case 0x2e: + return "SWORD"; + case 0x2f: + return "SDWORD"; + case 0x30: + return "void"; + case 0x31: + return "string"; + case 0x32: + return "unicode"; + case 0x33: + return "cstring"; + case 0x34: + return "array"; + } + } + // process text-formatted file + else + { + findNextNoneWhiteSpace(); + + if (P >= End) + return s; + + while((P < End) && !core::isspace(P[0])) + { + // either keep token delimiters when already holding a token, or return if first valid char + if (P[0]==';' || P[0]=='}' || P[0]=='{' || P[0]==',') + { + if (!s.size()) + { + s.append(P[0]); + ++P; + } + break; // stop for delimiter + } + s.append(P[0]); + ++P; + } + } + return s; +} + + +//! places pointer to next begin of a token, which must be a number, +// and ignores comments +void CXMeshFileLoader::findNextNoneWhiteSpaceNumber() +{ + if (BinaryFormat) + return; + + while((P < End) && (P[0] != '-') && (P[0] != '.') && + !( core::isdigit(P[0]))) + { + // check if this is a comment + if ((P[0] == '/' && P[1] == '/') || P[0] == '#') + readUntilEndOfLine(); + else + ++P; + } +} + + +// places pointer to next begin of a token, and ignores comments +void CXMeshFileLoader::findNextNoneWhiteSpace() +{ + if (BinaryFormat) + return; + + while(true) + { + while((P < End) && core::isspace(P[0])) + { + if (*P=='\n') + ++Line; + ++P; + } + + if (P >= End) + return; + + // check if this is a comment + if ((P[0] == '/' && P[1] == '/') || + P[0] == '#') + readUntilEndOfLine(); + else + break; + } +} + + +//! reads a x file style string +bool CXMeshFileLoader::getNextTokenAsString(core::stringc& out) +{ + if (BinaryFormat) + { + out=getNextToken(); + return true; + } + findNextNoneWhiteSpace(); + + if (P >= End) + return false; + + if (P[0] != '"') + return false; + ++P; + + while(P < End && P[0]!='"') + { + out.append(P[0]); + ++P; + } + + if ( P[1] != ';' || P[0] != '"') + return false; + P+=2; + + return true; +} + + +void CXMeshFileLoader::readUntilEndOfLine() +{ + if (BinaryFormat) + return; + + while(P < End) + { + if (P[0] == '\n' || P[0] == '\r') + { + ++P; + ++Line; + return; + } + + ++P; + } +} + + +u16 CXMeshFileLoader::readBinWord() +{ +#ifdef __BIG_ENDIAN__ + const u16 tmp = os::Byteswap::byteswap(*(u16 *)P); +#else + const u16 tmp = *(u16 *)P; +#endif + P += 2; + return tmp; +} + + +u32 CXMeshFileLoader::readBinDWord() +{ +#ifdef __BIG_ENDIAN__ + const u32 tmp = os::Byteswap::byteswap(*(u32 *)P); +#else + const u32 tmp = *(u32 *)P; +#endif + P += 4; + return tmp; +} + + +u32 CXMeshFileLoader::readInt() +{ + if (BinaryFormat) + { + if (!BinaryNumCount) + { + const u16 tmp = readBinWord(); // 0x06 or 0x03 + if (tmp == 0x06) + BinaryNumCount = readBinDWord(); + else + BinaryNumCount = 1; // single int + } + --BinaryNumCount; + return readBinDWord(); + } + else + { + findNextNoneWhiteSpaceNumber(); + return core::strtoul10(P, &P); + } +} + + +f32 CXMeshFileLoader::readFloat() +{ + if (BinaryFormat) + { + if (!BinaryNumCount) + { + const u16 tmp = readBinWord(); // 0x07 or 0x42 + if (tmp == 0x07) + BinaryNumCount = readBinDWord(); + else + BinaryNumCount = 1; // single int + } + --BinaryNumCount; + if (FloatSize == 8) + { +#ifdef __BIG_ENDIAN__ + //TODO: Check if data is properly converted here + f32 ctmp[2]; + ctmp[1] = os::Byteswap::byteswap(*(f32*)P); + ctmp[0] = os::Byteswap::byteswap(*(f32*)P+4); + const f32 tmp = (f32)(*(f64*)(void*)ctmp); +#else + const f32 tmp = (f32)(*(f64 *)P); +#endif + P += 8; + return tmp; + } + else + { +#ifdef __BIG_ENDIAN__ + const f32 tmp = os::Byteswap::byteswap(*(f32 *)P); +#else + const f32 tmp = *(f32 *)P; +#endif + P += 4; + return tmp; + } + } + findNextNoneWhiteSpaceNumber(); + f32 ftmp; + P = core::fast_atof_move(P, ftmp); + return ftmp; +} + + +// read 2-dimensional vector. Stops at semicolon after second value for text file format +bool CXMeshFileLoader::readVector2(core::vector2df& vec) +{ + vec.X = readFloat(); + vec.Y = readFloat(); + return true; +} + + +// read 3-dimensional vector. Stops at semicolon after third value for text file format +bool CXMeshFileLoader::readVector3(core::vector3df& vec) +{ + vec.X = readFloat(); + vec.Y = readFloat(); + vec.Z = readFloat(); + return true; +} + + +// read color without alpha value. Stops after second semicolon after blue value +bool CXMeshFileLoader::readRGB(video::SColor& color) +{ + video::SColorf tmpColor; + tmpColor.r = readFloat(); + tmpColor.g = readFloat(); + tmpColor.b = readFloat(); + color = tmpColor.toSColor(); + return checkForOneFollowingSemicolons(); +} + + +// read color with alpha value. Stops after second semicolon after blue value +bool CXMeshFileLoader::readRGBA(video::SColor& color) +{ + video::SColorf tmpColor; + tmpColor.r = readFloat(); + tmpColor.g = readFloat(); + tmpColor.b = readFloat(); + tmpColor.a = readFloat(); + color = tmpColor.toSColor(); + return checkForOneFollowingSemicolons(); +} + + +// read matrix from list of floats +bool CXMeshFileLoader::readMatrix(core::matrix4& mat) +{ + for (u32 i=0; i<16; ++i) + mat[i] = readFloat(); + return checkForOneFollowingSemicolons(); +} + + +} // end namespace scene +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_X_LOADER_ + diff --git a/lib/irrlicht/source/Irrlicht/CXMeshFileLoader.h b/lib/irrlicht/source/Irrlicht/CXMeshFileLoader.h new file mode 100644 index 000000000..67fb0411a --- /dev/null +++ b/lib/irrlicht/source/Irrlicht/CXMeshFileLoader.h @@ -0,0 +1,198 @@ +// 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_X_MESH_FILE_LOADER_H_INCLUDED__ +#define __C_X_MESH_FILE_LOADER_H_INCLUDED__ + +#include "IMeshLoader.h" +#include "irrString.h" +#include "CSkinnedMesh.h" + + +namespace irr +{ +namespace io +{ + class IFileSystem; + class IReadFile; +} // end namespace io +namespace scene +{ +class IMeshManipulator; + +//! Meshloader capable of loading x meshes. +class CXMeshFileLoader : public IMeshLoader +{ +public: + + //! Constructor + CXMeshFileLoader(scene::ISceneManager* smgr, io::IFileSystem* fs); + + //! 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; + + //! 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); + + struct SXTemplateMaterial + { + core::stringc Name; // template name from Xfile + video::SMaterial Material; // material + }; + + struct SXMesh + { + SXMesh() : MaxSkinWeightsPerVertex(0), MaxSkinWeightsPerFace(0), BoneCount(0),AttachedJointID(-1),HasSkinning(false), HasVertexColors(false) {} + // this mesh contains triangulated texture data. + // because in an .x file, faces can be made of more than 3 + // vertices, the indices data structure is triangulated during the + // loading process. The IndexCountPerFace array is filled during + // this triangulation process and stores how much indices belong to + // every face. This data structure can be ignored, because all data + // in this structure is triangulated. + + core::stringc Name; + + u32 MaxSkinWeightsPerVertex; + u32 MaxSkinWeightsPerFace; + u32 BoneCount; + + core::array IndexCountPerFace; // default 3, but could be more + + core::array Buffers; + + core::array Vertices; + core::array TCoords2; + + core::array Indices; + + core::array FaceMaterialIndices; // index of material for each face + + core::array Materials; // material array + + core::array WeightJoint; + core::array WeightNum; + + s32 AttachedJointID; + + bool HasSkinning; + bool HasVertexColors; + }; + +private: + + bool load(io::IReadFile* file); + + bool readFileIntoMemory(io::IReadFile* file); + + bool parseFile(); + + bool parseDataObject(); + + bool parseDataObjectTemplate(); + + bool parseDataObjectFrame(CSkinnedMesh::SJoint *parent); + + bool parseDataObjectTransformationMatrix(core::matrix4 &mat); + + bool parseDataObjectMesh(SXMesh &mesh); + + bool parseDataObjectSkinWeights(SXMesh &mesh); + + bool parseDataObjectSkinMeshHeader(SXMesh &mesh); + + bool parseDataObjectMeshNormals(SXMesh &mesh); + + bool parseDataObjectMeshTextureCoords(SXMesh &mesh); + + bool parseDataObjectMeshVertexColors(SXMesh &mesh); + + bool parseDataObjectMeshMaterialList(SXMesh &mesh); + + bool parseDataObjectMaterial(video::SMaterial& material); + + bool parseDataObjectAnimationSet(); + + bool parseDataObjectAnimation(); + + bool parseDataObjectAnimationKey(ISkinnedMesh::SJoint *joint); + + bool parseDataObjectTextureFilename(core::stringc& texturename); + + bool parseUnknownDataObject(); + + //! places pointer to next begin of a token, and ignores comments + void findNextNoneWhiteSpace(); + + //! places pointer to next begin of a token, which must be a number, + // and ignores comments + void findNextNoneWhiteSpaceNumber(); + + //! returns next parseable token. Returns empty string if no token there + core::stringc getNextToken(); + + //! reads header of dataobject including the opening brace. + //! returns false if error happened, and writes name of object + //! if there is one + bool readHeadOfDataObject(core::stringc* outname=0); + + //! checks for closing curly brace, returns false if not there + bool checkForClosingBrace(); + + //! checks for one following semicolons, returns false if not there + bool checkForOneFollowingSemicolons(); + + //! checks for two following semicolons, returns false if they are not there + bool checkForTwoFollowingSemicolons(); + + //! reads a x file style string + bool getNextTokenAsString(core::stringc& out); + + void readUntilEndOfLine(); + + u16 readBinWord(); + u32 readBinDWord(); + u32 readInt(); + f32 readFloat(); + bool readVector2(core::vector2df& vec); + bool readVector3(core::vector3df& vec); + bool readMatrix(core::matrix4& mat); + bool readRGB(video::SColor& color); + bool readRGBA(video::SColor& color); + + ISceneManager* SceneManager; + io::IFileSystem* FileSystem; + + core::array *AllJoints; + + CSkinnedMesh* AnimatedMesh; + + c8* Buffer; + const c8* P; + c8* End; + // counter for number arrays in binary format + u32 BinaryNumCount; + u32 Line; + io::path FilePath; + + CSkinnedMesh::SJoint *CurFrame; + + core::array Meshes; + + core::array TemplateMaterials; + + u32 MajorVersion; + u32 MinorVersion; + bool BinaryFormat; + c8 FloatSize; +}; + +} // end namespace scene +} // end namespace irr + +#endif diff --git a/lib/irrlicht/source/Irrlicht/Irrlicht.cpp b/lib/irrlicht/source/Irrlicht/Irrlicht.cpp index 1e2b0753b..7f5d0a4cc 100644 --- a/lib/irrlicht/source/Irrlicht/Irrlicht.cpp +++ b/lib/irrlicht/source/Irrlicht/Irrlicht.cpp @@ -4,7 +4,7 @@ #include "IrrCompileConfig.h" -//static const char* const copyright = "Irrlicht Engine (c) 2002-2012 Nikolaus Gebhardt"; +static const char* const copyright = "Irrlicht Engine (c) 2002-2012 Nikolaus Gebhardt"; #ifdef _IRR_WINDOWS_ #include @@ -30,6 +30,10 @@ #include "CIrrDeviceLinux.h" #endif +#ifdef _IRR_COMPILE_WITH_IPHONE_DEVICE_ +#include "iOS/CIrrDeviceiOS.h" +#endif + #ifdef _IRR_COMPILE_WITH_SDL_DEVICE_ #include "CIrrDeviceSDL.h" #endif @@ -42,14 +46,18 @@ #include "CIrrDeviceConsole.h" #endif +#ifdef _IRR_COMPILE_WITH_ANDROID_DEVICE_ +#include "CIrrDeviceAndroid.h" +#include +#endif + namespace irr { //! stub for calling createDeviceEx IRRLICHT_API IrrlichtDevice* IRRCALLCONV createDevice(video::E_DRIVER_TYPE driverType, const core::dimension2d& windowSize, u32 bits, bool fullscreen, - bool stencilbuffer, bool vsync, IEventReceiver* res, - io::IFileSystem *file_system) + bool stencilbuffer, bool vsync, IEventReceiver* res) { SIrrlichtCreationParameters p; p.DriverType = driverType; @@ -59,7 +67,6 @@ namespace irr p.Stencilbuffer = stencilbuffer; p.Vsync = vsync; p.EventReceiver = res; - p.FileSystem = file_system; return createDeviceEx(p); } @@ -88,6 +95,11 @@ namespace irr if (params.DeviceType == EIDT_X11 || (!dev && params.DeviceType == EIDT_BEST)) dev = new CIrrDeviceLinux(params); #endif + +#ifdef _IRR_COMPILE_WITH_IPHONE_DEVICE_ + if (params.DeviceType == EIDT_IPHONE || (!dev && params.DeviceType == EIDT_BEST)) + dev = new CIrrDeviceIPhone(params); +#endif #ifdef _IRR_COMPILE_WITH_SDL_DEVICE_ if (params.DeviceType == EIDT_SDL || (!dev && params.DeviceType == EIDT_BEST)) @@ -99,6 +111,12 @@ namespace irr dev = new CIrrDeviceFB(params); #endif +#ifdef _IRR_COMPILE_WITH_ANDROID_DEVICE_ + if (params.DeviceType == EIDT_ANDROID || (!dev && params.DeviceType == EIDT_BEST)) { + dev = new CIrrDeviceAndroid(params); + } +#endif + #ifdef _IRR_COMPILE_WITH_CONSOLE_DEVICE_ if (params.DeviceType == EIDT_CONSOLE || (!dev && params.DeviceType == EIDT_BEST)) dev = new CIrrDeviceConsole(params); @@ -129,7 +147,7 @@ namespace video } // end namespace irr -#if defined(_IRR_WINDOWS_API_) && !defined(_IRR_STATIC_LIB_) +#if defined(_IRR_WINDOWS_API_) BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, diff --git a/lib/irrlicht/source/Irrlicht/os.cpp b/lib/irrlicht/source/Irrlicht/os.cpp index b847ffd5b..ed0a29803 100644 --- a/lib/irrlicht/source/Irrlicht/os.cpp +++ b/lib/irrlicht/source/Irrlicht/os.cpp @@ -142,6 +142,7 @@ namespace os #include #include #include +#include namespace irr { @@ -176,24 +177,30 @@ namespace os void Printer::log(const c8* message, ELOG_LEVEL ll) { + __android_log_print(ANDROID_LOG_VERBOSE, "native-activity", "%s", message); if (Logger) Logger->log(message, ll); } void Printer::log(const wchar_t* message, ELOG_LEVEL ll) { + char test[200]; + wcstombs(test, message, 200); + __android_log_print(ANDROID_LOG_VERBOSE, "native-activity", "%s", test); if (Logger) Logger->log(message, ll); } void Printer::log(const c8* message, const c8* hint, ELOG_LEVEL ll) { + __android_log_print(ANDROID_LOG_VERBOSE, "native-activity", "%s %s", message, hint); if (Logger) Logger->log(message, hint, ll); } void Printer::log(const c8* message, const io::path& hint, ELOG_LEVEL ll) { + __android_log_print(ANDROID_LOG_VERBOSE, "native-activity", "%s %s", message, core::stringc(hint).c_str()); if (Logger) Logger->log(message, hint.c_str(), ll); }