From b746631f8ce12515292a477ad85bfaa69e17519a Mon Sep 17 00:00:00 2001 From: Mathias Gottschlag Date: Wed, 7 Jan 2009 20:53:07 +0100 Subject: [PATCH] Imported more code from the old engine. --- CMakeLists.txt | 38 +- engine/include/core/Buffer.h | 215 ++++ engine/include/core/GameEngine.h | 4 +- engine/include/network/BroadcastClient.h | 117 ++ engine/include/network/BroadcastHost.h | 75 ++ engine/include/network/Connection.h | 107 ++ engine/include/network/NetworkClient.h | 79 ++ engine/include/network/NetworkHost.h | 77 ++ engine/include/support/IrrCompileConfig.h | 314 ++++++ engine/include/support/aabbox3d.h | 292 +++++ engine/include/support/dimension2d.h | 78 ++ engine/include/support/irrMath.h | 445 ++++++++ engine/include/support/irrTypes.h | 160 +++ engine/include/support/line3d.h | 126 +++ engine/include/support/matrix4.h | 1639 +++++++++++++++++++++++++++++ engine/include/support/plane3d.h | 224 ++++ engine/include/support/position2d.h | 116 ++ engine/include/support/quaternion.h | 563 ++++++++++ engine/include/support/rect.h | 257 +++++ engine/include/support/vector2d.h | 256 +++++ engine/include/support/vector3d.h | 286 +++++ engine/src/core/Buffer.cpp | 278 +++++ engine/src/network/BroadcastClient.cpp | 206 ++++ engine/src/network/BroadcastHost.cpp | 97 ++ engine/src/network/Connection.cpp | 88 ++ engine/src/network/NetworkClient.cpp | 140 +++ engine/src/network/NetworkHost.cpp | 146 +++ test/src/main.cpp | 6 + 28 files changed, 6423 insertions(+), 6 deletions(-) rewrite CMakeLists.txt (100%) create mode 100644 engine/include/core/Buffer.h create mode 100644 engine/include/network/BroadcastClient.h create mode 100644 engine/include/network/BroadcastHost.h create mode 100644 engine/include/network/Connection.h create mode 100644 engine/include/network/NetworkClient.h create mode 100644 engine/include/network/NetworkHost.h create mode 100644 engine/include/support/IrrCompileConfig.h create mode 100644 engine/include/support/aabbox3d.h create mode 100644 engine/include/support/dimension2d.h create mode 100644 engine/include/support/irrMath.h create mode 100644 engine/include/support/irrTypes.h create mode 100644 engine/include/support/line3d.h create mode 100644 engine/include/support/matrix4.h create mode 100644 engine/include/support/plane3d.h create mode 100644 engine/include/support/position2d.h create mode 100644 engine/include/support/quaternion.h create mode 100644 engine/include/support/rect.h create mode 100644 engine/include/support/vector2d.h create mode 100644 engine/include/support/vector3d.h create mode 100644 engine/src/core/Buffer.cpp create mode 100644 engine/src/network/BroadcastClient.cpp create mode 100644 engine/src/network/BroadcastHost.cpp create mode 100644 engine/src/network/Connection.cpp create mode 100644 engine/src/network/NetworkClient.cpp create mode 100644 engine/src/network/NetworkHost.cpp create mode 100644 test/src/main.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt dissimilarity index 100% index 17dd6d1..25990e4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,34 @@ -project (peakengine) -set (CMAKE_VERBOSE_MAKEFILES on) -add_subdirectory (engine) -add_subdirectory (tests) + +cmake_minimum_required(VERSION 2.6) + +project(peakengine C CXX) + +set(SRC +engine/src/core/Address.cpp +engine/src/core/Buffer.cpp +engine/src/core/Color.cpp +engine/src/core/File.cpp +engine/src/core/FileSystem.cpp +#engine/src/core/Game.cpp +#engine/src/core/GameEngine.cpp +engine/src/core/IniFile.cpp +engine/src/core/Logger.cpp +engine/src/core/Quaternion.cpp +engine/src/core/SettingsManager.cpp +engine/src/core/Util.cpp +engine/src/core/Vector2D.cpp +engine/src/core/Vector2DI.cpp +engine/src/core/Vector3D.cpp +engine/src/network/BroadcastClient.cpp +engine/src/network/BroadcastHost.cpp +engine/src/network/Connection.cpp +engine/src/network/NetworkClient.cpp +engine/src/network/NetworkHost.cpp +test/src/main.cpp +) + +set(CMAKE_CXX_FLAGS "-Wall -Wextra -W -Wno-long-long -Itest/include -Iengine/include -Wno-unused-parameter") + +add_executable(peaktest ${SRC}) +target_link_libraries(peaktest m Horde3D Horde3DUtils enet) + diff --git a/engine/include/core/Buffer.h b/engine/include/core/Buffer.h new file mode 100644 index 0000000..83b5b12 --- /dev/null +++ b/engine/include/core/Buffer.h @@ -0,0 +1,215 @@ +/* +Copyright (C) 2008 Mathias Gottschlag, Lukas Kropatschek + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in the +Software without restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the +Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef _BUFFER_H_ +#define _BUFFER_H_ + +#include + +#include "core/Vector3D.h" +#include "core/Vector2D.h" +#include "core/Quaternion.h" + +//tolua_begin +namespace peak +{ + /** + * \brief Dynamically sized buffer for network data etc. + */ + class Buffer + { + public: + Buffer(); + Buffer(unsigned int size); + Buffer(void *data, unsigned int size); + Buffer(const Buffer &buf); + ~Buffer(); + + /** + * \brief Sets buffer size. + * + * If there is more data than the new size, the data is truncated. + * \param size New size + */ + void setSize(unsigned int size); + /** + * \brief Returns the buffer size. + * \return Buffer size + */ + unsigned int getSize(void); + /** + * \brief Returns the size of the data stored in the buffer. + * \return Data size + */ + unsigned int getDataSize(void); + + /** + * \brief Returns the current write/read position. + * \return Position + */ + unsigned int getPosition(void); + /** + * \brief Sets the current write/read position. + * \param position New position + * \param relative If set, add the current position to the new position + */ + void setPosition(unsigned int position, bool relative = false); + + /** + * \brief Reads raw data from the current position. + * + * Might read less than size bytes if there is not enough data. + * \param dest Memory to hold the data. Must be at least size bytes long. + * \param size Size to be read + * \return Number of bytes read + */ + int readData(void *dest, unsigned int size); + /** + * \brief Write data to the buffer. + * + * Might write less then size bytes if resize is not set. + * \param source Pointer to the data. + * \param size Size to be written + * \param resize If set, resize the buffer if it is not big enougth to hold the data + * \return Number of bytes written + */ + int writeData(const void *source, unsigned int size, + bool resize = true); + + /** + * \brief Write integer to the buffer. + * \param value Number to be written + */ + void writeInt(int value); + /** + * \brief Read integer from the buffer. + * \return Value of the integer + */ + int readInt(void); + /** + * \brief Write float to the buffer. + * \param value Number to be written + */ + void writeFloat(float value); + /** + * \brief Read float from the buffer. + * \return Value of the float + */ + float readFloat(void); + /** + * \brief Write string to the buffer. + * \param str String to be written + */ + void writeString(std::string str); + /** + * \brief Read string from the buffer. + * \return String which was read + */ + std::string readString(void); + /** + * \brief Write single byte to the buffer. + * \param value Byte to be written + */ + void writeByte(unsigned char value); + /** + * \brief Read single byte from the buffer. + * \return Value of the byte + */ + unsigned char readByte(void); + /** + * \brief Write word (2 bytes) to the buffer. + * \param value Word to be written + */ + void writeWord(short value); + /** + * \brief Read word (2 bytes) from the buffer. + * \return Value of the word + */ + short readWord(void); + /** + * \brief Write a bool variable to the buffer. + * \param flag bool variable to be written. + */ + void writeBool(bool flag); + /** + * \brief Read a bool variable from the buffer. + * \return Value of the bool variable. + */ + bool readBool(void); + /** + * \brief Write 2-dimensional vector to the buffer. + * \param v Vector to be written + */ + void writeVector2D(Vector2D v); + /** + * \brief Read 2-dimensional vector from the buffer. + * \return Value of the vector. + */ + Vector2D readVector2D(void); + /** + * \brief Write vector to the buffer. + * \param v Vector to be written + */ + void writeVector3D(Vector3D v); + /** + * \brief Read vector from the buffer. + * \return Value of the vector + */ + Vector3D readVector3D(void); + /** + * \brief Write quaternion to the buffer. + * \param q Quaternion to be written + */ + void writeQuaternion(Quaternion q); + /** + * \brief Read quaternion from the buffer. + * \return Value of the quaternion + */ + Quaternion readQuaternion(void); + + /** + * \brief Returns pointer to the raw buffer data. + * \return Pointer to buffer data + */ + char *getData(void); + + /** + * \brief Clear the buffer and free the data. + */ + void clear(void); + + //tolua_end + Buffer &operator=(const Buffer &buf); + Buffer &operator+=(const Buffer &buf); + Buffer &operator<<(const Buffer &buf); + Buffer &operator<<(int &data); + Buffer &operator<<(float &data); + private: + char *data; + unsigned int size; + unsigned int datasize; + unsigned int position; + //tolua_begin + }; +} +//tolua_end + +#endif diff --git a/engine/include/core/GameEngine.h b/engine/include/core/GameEngine.h index 0c10cbf..d9a97e5 100644 --- a/engine/include/core/GameEngine.h +++ b/engine/include/core/GameEngine.h @@ -22,7 +22,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #ifndef _GAMEENGINE_H_ #define _GAMEENGINE_H_ -#include "core/Config.h" +//#include "core/Config.h" #include @@ -129,7 +129,7 @@ namespace peak /** * \brief Main game engine class. Calls the other parts of the engine. */ - class PEAK_API GameEngine + class GameEngine { public: /** diff --git a/engine/include/network/BroadcastClient.h b/engine/include/network/BroadcastClient.h new file mode 100644 index 0000000..5508282 --- /dev/null +++ b/engine/include/network/BroadcastClient.h @@ -0,0 +1,117 @@ +/* +Copyright (C) 2008 Mathias Gottschlag + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in the +Software without restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the +Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef _BROADCASTCLIENT_H_ +#define _BROADCASTCLIENT_H_ + +#include +#include +#include + +#include "core/Address.h" + +//tolua_begin +namespace peak +{ + class Script; + + /** + * \brief Socket which sends broadcast messages at a fixed interval to get the + * address of local network servers. + */ + class BroadcastClient + { + public: + BroadcastClient(); + ~BroadcastClient(); + + /** + * \brief Starts broadcasting. + * \param port Port to send messages at + */ + void start(int port); + /** + * \brief Stops broadcasting + */ + void stop(void); + + /** + * \brief Clears server list. + */ + void clearList(void); + + /** + * \brief Returns the number of found servers. + */ + int getServerCount(void); + /** + * \brief Returns the server info of one server. + * \param index Index of the server, can be in the range 0..getServerCount(). + * \return Server reply + */ + std::string getServerInfo(int index); + /** + * \brief Returns the address of one server. + * \param index Index of the server, can be in the range 0..getServerCount(). + * \return Server address + */ + Address getServerAddress(int index); + + /** + * \brief Sets a callback function which gets called everytime the + * server list changes. + * \param script Lua script which defines the function + * \param function Function to call + */ + void setCallback(Script *script, std::string function); + + /** + * \brief Sends a broadcast message if needed, handles incoming responses. + * \param msecs Passed time since last call of this function + */ + void doWork(float msecs = 0); + + /** + * \brief Updates all broadcast clients. + * \param msecs Passed time since last call of this function + */ + static void doAllWork(float msecs); + private: + //tolua_end + ENetSocket socket; + int port; + + float updatetime; + + Script *cbscript; + std::string cbfunc; + + std::vector serverinfo; + std::vector
serveraddr; + + static std::vector bcclients; + //tolua_begin + }; +} +//tolua_end + +#endif + diff --git a/engine/include/network/BroadcastHost.h b/engine/include/network/BroadcastHost.h new file mode 100644 index 0000000..9e54c32 --- /dev/null +++ b/engine/include/network/BroadcastHost.h @@ -0,0 +1,75 @@ +/* +Copyright (C) 2008 Mathias Gottschlag + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in the +Software without restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the +Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef _BROADCASTHOST_H_ +#define _BROADCASTHOST_H_ + +#include +#include + +//tolua_begin +namespace peak +{ + /** + * \brief Socket which automatically replies to broadcast messages. + */ + class BroadcastHost + { + public: + BroadcastHost(); + ~BroadcastHost(); + + /** + * \brief Initializes the broadcast host. + * \param port Port on which the socket listens + */ + bool init(int port); + /** + * \brief Destroys the broadcast host. + */ + bool shutdown(void); + + /** + * \brief Sets the reply of the broadcast host. + * \param info Reply string + */ + void setInfo(std::string info); + /** + * \brief Returns the used reply string. + */ + std::string getInfo(void); + + /** + * \brief Listens for incoming data and sends replies. + */ + void doWork(void); + private: + //tolua_end + ENetSocket bcastsocket; + + std::string info; + //tolua_begin + }; +} +//tolua_end + +#endif + diff --git a/engine/include/network/Connection.h b/engine/include/network/Connection.h new file mode 100644 index 0000000..aebf3ac --- /dev/null +++ b/engine/include/network/Connection.h @@ -0,0 +1,107 @@ +/* +Copyright (C) 2008 Mathias Gottschlag + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in the +Software without restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the +Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef _CONNECTION_H_ +#define _CONNECTION_H_ + +#include "core/Buffer.h" + +#include +#include + +//tolua_begin +namespace peak +{ + /** + * \brief Base class for any client/server connection + */ + class Connection + { + public: + Connection(ENetPeer *peer); + virtual ~Connection(); + + /** + * \brief Destroys the connection and frees all data. + */ + virtual void destroy(void); + + /** + * \brief Closes the connection. + */ + virtual void disconnect(void); + /** + * \brief Reads whether the connection is established or not. + * \return Returns false if the connection was closed. + */ + virtual bool isConnected(void); + + /** + * \brief Returns whether there is incoming data waiting to be read. + * \return Returns true if there is incoming data. + */ + virtual bool hasNewData(void); + /** + * \brief Reads incoming data. + * + * This function returns a buffer which has to be deleted by the user. + * \return Incoming data + */ + virtual Buffer *readData(void); + /** + * \brief Sends data. + * + * You must not delete the buffer for the connection takes care of it. + * \param data Pointer to a Buffer created via new + * \param reliable If set to true, a reliable connection is used + * \return Returns false if the data could not be sent. + */ + virtual bool sendData(Buffer *data, bool reliable = true); + + /** + * \brief Injects incoming data. + * + * Because of the design of enet, connections do not receive the data + * themselves. + * + * For internal use only. + * \param data Incoming data + */ + virtual void injectData(Buffer *data); + /** + * \brief Returns the peer structure used by enet. + * + * For internal use only. + * \return Peer structure + */ + virtual ENetPeer *getPeer(void); + private: + //tolua_end + ENetPeer *peer; + + std::queue received; + //tolua_begin + }; +} +//tolua_end + +#endif + diff --git a/engine/include/network/NetworkClient.h b/engine/include/network/NetworkClient.h new file mode 100644 index 0000000..ac8eb99 --- /dev/null +++ b/engine/include/network/NetworkClient.h @@ -0,0 +1,79 @@ +/* +Copyright (C) 2008 Mathias Gottschlag + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in the +Software without restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the +Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef _NETWORKCLIENT_H_ +#define _NETWORKCLIENT_H_ + +#include "core/Address.h" +#include + +namespace peak +{ + class Connection; + + + /** + * \brief Network client which can connect to a NetworkServer. + */ + class NetworkClient + { + public: + NetworkClient(); + ~NetworkClient(); + + /** + * \brief Connects to a local server. + * \return Connection to the server, 0 if no connection could be created + */ + Connection *init(void); + /** + * \brief Connects to a remote server. + * \return Connection to the server, 0 if no connection could be created + */ + Connection *init(Address addr); + /** + * \brief Disconnects from the server. + */ + void shutdown(void); + + /** + * \brief Returns whether the client is connected to a server. + */ + bool isConnected(void); + + /** + * \brief Returns the connection to the server. + */ + Connection *getConnection(void); + + /** + * \brief Receives incoming data. + */ + bool doWork(void); + private: + ENetHost *host; + ENetPeer *peer; + Connection *conn; + }; +} + +#endif + diff --git a/engine/include/network/NetworkHost.h b/engine/include/network/NetworkHost.h new file mode 100644 index 0000000..69100c5 --- /dev/null +++ b/engine/include/network/NetworkHost.h @@ -0,0 +1,77 @@ +/* +Copyright (C) 2008 Mathias Gottschlag + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in the +Software without restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the +Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef _NETWORKHOST_H_ +#define _NETWORKHOST_H_ + +#include +#include +#include + +namespace peak +{ + class Connection; + class NetworkConnection; + + + /** + * \brief Network host which acts as a network server. + */ + class NetworkHost + { + public: + NetworkHost(); + ~NetworkHost(); + + /** + * \brief Initializes the host at a given port. + * \param port Port used for the host + */ + bool init(int port); + /** + * \brief Destroys the host, disconnecting all clients. + */ + bool shutdown(void); + + /** + * \brief Returns a new connection if there is any. + */ + Connection *getNewConnection(void); + /** + * \brief Closes the connection to a client. + * \param conn Connection to be closed + */ + void closeConnection(Connection *conn); + + /** + * \brief Receives incoming data. + */ + bool doWork(void); + private: + ENetHost *host; + + std::queue newconnections; + std::vector connections; + }; +} + +#endif + diff --git a/engine/include/support/IrrCompileConfig.h b/engine/include/support/IrrCompileConfig.h new file mode 100644 index 0000000..d752acc --- /dev/null +++ b/engine/include/support/IrrCompileConfig.h @@ -0,0 +1,314 @@ +// Copyright (C) 2002-2007 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_COMPILE_CONFIG_H_INCLUDED__ +#define __IRR_COMPILE_CONFIG_H_INCLUDED__ + +//! Irrlicht SDK Version +#define IRRLICHT_SDK_VERSION "1.4" + +//! The defines for different operating system are: +//! _IRR_XBOX_PLATFORM_ for XBox +//! _IRR_WINDOWS_ for all irrlicht supported Windows versions +//! _IRR_WINDOWS_API_ for Windows or XBox +//! _IRR_LINUX_PLATFORM_ for Linux (it is defined here if no other os is defined) +//! _IRR_SOLARIS_PLATFORM_ for Solaris +//! _IRR_POSIX_API_ for Posix compatible systems +//! _IRR_USE_SDL_DEVICE_ for platform independent SDL framework +//! _IRR_USE_WINDOWS_DEVICE_ for Windows API based device +//! _IRR_USE_LINUX_DEVICE_ for X11 based device +//! MACOSX for Mac OS X + +//#define _IRR_USE_SDL_DEVICE_ 1 + +//! WIN32 for Windows32 +//! WIN64 for Windows64 +#if defined(WIN32) || defined(WIN64) +#define _IRR_WINDOWS_ +#define _IRR_WINDOWS_API_ +#ifndef _IRR_USE_SDL_DEVICE_ +#define _IRR_USE_WINDOWS_DEVICE_ +#endif +#endif + +#if defined(_XBOX) +#define _IRR_XBOX_PLATFORM_ +#define _IRR_WINDOWS_API_ +#endif + +#if !defined(_IRR_WINDOWS_API_) && !defined(MACOSX) +#if defined(__sparc__) || defined(__sun__) +#define __BIG_ENDIAN__ +#define _IRR_SOLARIS_PLATFORM_ +#else +#define _IRR_LINUX_PLATFORM_ +#endif +#define _IRR_POSIX_API_ + +#ifndef _IRR_USE_SDL_DEVICE_ +#define _IRR_USE_LINUX_DEVICE_ +#endif +#endif + +#include // TODO: Although included elsewhere this is required at least for mingw + +//! Define _IRR_COMPILE_WITH_DIRECT3D_8_ and _IRR_COMPILE_WITH_DIRECT3D_9_ to +//! compile the Irrlicht engine with Direct3D8 and/or DIRECT3D9. +/** If you only want to use the software device or opengl this can be useful. +This switch is mostly disabled because people do not get the g++ compiler compile +directX header files, and directX is only available on windows platforms. If you +are using Dev-Cpp, and want to compile this using a DX dev pack, you can define +_IRR_COMPILE_WITH_DX9_DEV_PACK_. So you simply need to add something like this +to the compiler settings: -DIRR_COMPILE_WITH_DX9_DEV_PACK +and this to the linker settings: -ld3dx9 -ld3dx8 **/ +#if defined(_IRR_WINDOWS_API_) && (!defined(__GNUC__) || defined(IRR_COMPILE_WITH_DX9_DEV_PACK)) + +#define _IRR_COMPILE_WITH_DIRECT3D_8_ +#define _IRR_COMPILE_WITH_DIRECT3D_9_ + +#endif + +//! Define _IRR_COMPILE_WITH_OPENGL_ to compile the Irrlicht engine with OpenGL. +/** If you do not wish the engine to be compiled with OpengGL, comment this +define out. */ +#define _IRR_COMPILE_WITH_OPENGL_ + +//! Define _IRR_COMPILE_WITH_SOFTWARE_ to compile the Irrlicht engine with software driver +/** If you do not need the software driver, or want to use Burning's Video instead, +comment this define out */ +#define _IRR_COMPILE_WITH_SOFTWARE_ + +//! Define _IRR_COMPILE_WITH_BURNINGSVIDEO_ to compile the Irrlicht engine with Burning's video driver +/** If you do not need this software driver, you can comment this define out. */ +#define _IRR_COMPILE_WITH_BURNINGSVIDEO_ + +//! Define _IRR_COMPILE_WITH_X11_ to compile the Irrlicht engine with X11 support. +/** If you do not wish the engine to be compiled with X11, comment this +define out. */ +// Only used in LinuxDevice. +#define _IRR_COMPILE_WITH_X11_ + +//! Define _IRR_OPENGL_USE_EXTPOINTER_ if the OpenGL renderer should use OpenGL extensions via function pointers. +/** On some systems there is no support for the dynamic extension of OpenGL + via function pointers such that this has to be undef'ed. */ +#if !defined(MACOSX) && !defined(_IRR_SOLARIS_PLATFORM_) +#define _IRR_OPENGL_USE_EXTPOINTER_ +#endif + +//! On some Linux systems the XF86 vidmode extension or X11 RandR are missing. Use these flags +//! to remove the dependencies such that Irrlicht will compile on those systems, too. +#if defined(_IRR_LINUX_PLATFORM_) +#define _IRR_LINUX_X11_VIDMODE_ +//#define _IRR_LINUX_X11_RANDR_ +#endif + +//! Define _IRR_COMPILE_WITH_GUI_ to compile the engine with the built-in GUI +/** Disable this if you are using an external library to draw the GUI. If you disable this then +you will not be able to use anything provided by the GUI Environment, including loading fonts. */ +#define _IRR_COMPILE_WITH_GUI_ + +//! Define _IRR_COMPILE_WITH_ZLIB_ to enable compiling the engine using zlib. +/** This enables the engine to read from compressed .zip archives. If you +disable this feature, the engine can still read archives, but only uncompressed +ones. */ +#define _IRR_COMPILE_WITH_ZLIB_ + +//! Define _IRR_USE_NON_SYSTEM_ZLIB_ to let irrlicht use the zlib which comes with irrlicht. +/** If this is commented out, Irrlicht will try to compile using the zlib installed in the system. + This is only used when _IRR_COMPILE_WITH_ZLIB_ is defined. */ +#define _IRR_USE_NON_SYSTEM_ZLIB_ + + +//! Define _IRR_COMPILE_WITH_JPEGLIB_ to enable compiling the engine using libjpeg. +/** This enables the engine to read jpeg images. If you comment this out, +the engine will no longer read .jpeg images. */ +#define _IRR_COMPILE_WITH_LIBJPEG_ + +//! Define _IRR_USE_NON_SYSTEM_JPEG_LIB_ to let irrlicht use the jpeglib which comes with irrlicht. +/** If this is commented out, Irrlicht will try to compile using the jpeg lib installed in the system. + This is only used when _IRR_COMPILE_WITH_LIBJPEG_ is defined. */ +#define _IRR_USE_NON_SYSTEM_JPEG_LIB_ + + +//! Define _IRR_COMPILE_WITH_LIBPNG_ to enable compiling the engine using libpng. +/** This enables the engine to read png images. If you comment this out, +the engine will no longer read .png images. */ +#define _IRR_COMPILE_WITH_LIBPNG_ + +//! Define _IRR_USE_NON_SYSTEM_LIBPNG_ to let irrlicht use the libpng which comes with irrlicht. +/** If this is commented out, Irrlicht will try to compile using the libpng installed in the system. + This is only used when _IRR_COMPILE_WITH_LIBPNG_ is defined. */ +#define _IRR_USE_NON_SYSTEM_LIB_PNG_ + + +//! Define _IRR_D3D_NO_SHADER_DEBUGGING to disable shader debugging in D3D9 +/** If _IRR_D3D_NO_SHADER_DEBUGGING is undefined in IrrCompileConfig.h, +it is possible to debug all D3D9 shaders in VisualStudio. All shaders +(which have been generated in memory or read from archives for example) will be emitted +into a temporary file at runtime for this purpose. To debug your shaders, choose +Debug->Direct3D->StartWithDirect3DDebugging in Visual Studio, and for every shader a +file named 'irr_dbg_shader_%%.vsh' or 'irr_dbg_shader_%%.psh' will be created. Drag'n'drop +the file you want to debug into visual studio. That's it. You can now set breakpoints and +watch registers, variables etc. This works with ASM, HLSL, and both with pixel and vertex shaders. +Note that the engine will run in D3D REF for this, which is a lot slower than HAL. */ +#define _IRR_D3D_NO_SHADER_DEBUGGING + + +#ifdef _IRR_WINDOWS_API_ + +#ifndef _IRR_STATIC_LIB_ +#ifdef IRRLICHT_EXPORTS +#define IRRLICHT_API __declspec(dllexport) +#else +#define IRRLICHT_API __declspec(dllimport) +#endif // IRRLICHT_EXPORT +#else +#define IRRLICHT_API +#endif // _IRR_STATIC_LIB_ + +// Declare the calling convention. +#if defined(_STDCALL_SUPPORTED) +#define IRRCALLCONV __stdcall +#else +#define IRRCALLCONV __cdecl +#endif // STDCALL_SUPPORTED + +#else +#define IRRLICHT_API +#define IRRCALLCONV +#endif // _IRR_WINDOWS_API_ + +// We need to disable DIRECT3D9 support for Visual Studio 6.0 because +// those $%&$!! disabled support for it since Dec. 2004 and users are complaining +// about linker errors. Comment this out only if you are knowing what you are +// doing. (Which means you have an old DX9 SDK and VisualStudio6). +#ifdef _MSC_VER +#if (_MSC_VER < 1300 && !defined(__GNUC__)) +#undef _IRR_COMPILE_WITH_DIRECT3D_9_ +#pragma message("Compiling Irrlicht with Visual Studio 6.0, support for DX9 is disabled.") +#endif +#endif + +//! Define one of the three setting for Burning's Video Software Rasterizer +/** So if we were marketing guys we could says Irrlicht has 4 Software-Rasterizers. + In a Nutshell: + All Burnings Rasterizers use 32 Bit Backbuffer, 32Bit Texture & 32 Bit Z or WBuffer, + 16 Bit/32 Bit can be adjusted on a global flag. + + BURNINGVIDEO_RENDERER_BEAUTIFUL + 32 Bit + Vertexcolor + Lighting + Per Pixel Perspective Correct + SubPixel/SubTexel Correct + + Bilinear Texturefiltering + WBuffer + + BURNINGVIDEO_RENDERER_FAST + 32 Bit + Per Pixel Perspective Correct + SubPixel/SubTexel Correct + WBuffer + + Bilinear Dithering TextureFiltering + WBuffer + + BURNINGVIDEO_RENDERER_ULTRA_FAST + 16Bit + SubPixel/SubTexel Correct + ZBuffer +*/ + +#define BURNINGVIDEO_RENDERER_BEAUTIFUL +//#define BURNINGVIDEO_RENDERER_FAST +//#define BURNINGVIDEO_RENDERER_ULTRA_FAST + + +//! Define _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_ if you want to use bone based +/** animated meshes. If you compile without this, you will be unable to load +B3D, MS3D or X meshes */ +#define _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_ + +#ifdef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_ +//! Define _IRR_COMPILE_WITH_B3D_LOADER_ if you want to use Blitz3D files +#define _IRR_COMPILE_WITH_B3D_LOADER_ +//! Define _IRR_COMPILE_WITH_B3D_LOADER_ if you want to Milkshape files +#define _IRR_COMPILE_WITH_MS3D_LOADER_ +//! Define _IRR_COMPILE_WITH_X_LOADER_ if you want to use Microsoft X files +#define _IRR_COMPILE_WITH_X_LOADER_ +#endif + +//! Define _IRR_COMPILE_WITH_IRR_MESH_LOADER_ if you want to load Irrlicht Engine .irrmesh files +#define _IRR_COMPILE_WITH_IRR_MESH_LOADER_ + +//! Define _IRR_COMPILE_WITH_MD2_LOADER_ if you want to load Quake 2 animated files +#define _IRR_COMPILE_WITH_MD2_LOADER_ +//! Define _IRR_COMPILE_WITH_MD3_LOADER_ if you want to load Quake 3 animated files +#define _IRR_COMPILE_WITH_MD3_LOADER_ + +//! Define _IRR_COMPILE_WITH_3DS_LOADER_ if you want to load 3D Studio Max files +#define _IRR_COMPILE_WITH_3DS_LOADER_ +//! Define _IRR_COMPILE_WITH_COLLADA_LOADER_ if you want to load Collada files +#define _IRR_COMPILE_WITH_COLLADA_LOADER_ +//! Define _IRR_COMPILE_WITH_CSM_LOADER_ if you want to load Cartography Shop files +#define _IRR_COMPILE_WITH_CSM_LOADER_ +//! Define _IRR_COMPILE_WITH_BSP_LOADER_ if you want to load Quake 3 BSP files +#define _IRR_COMPILE_WITH_BSP_LOADER_ +//! Define _IRR_COMPILE_WITH_DMF_LOADER_ if you want to load DeleD files +#define _IRR_COMPILE_WITH_DMF_LOADER_ +//! Define _IRR_COMPILE_WITH_LMTS_LOADER_ if you want to load LMTools files +#define _IRR_COMPILE_WITH_LMTS_LOADER_ +//! Define _IRR_COMPILE_WITH_MY3D_LOADER_ if you want to load MY3D files +#define _IRR_COMPILE_WITH_MY3D_LOADER_ +//! Define _IRR_COMPILE_WITH_OBJ_LOADER_ if you want to load Wavefront OBJ files +#define _IRR_COMPILE_WITH_OBJ_LOADER_ +//! Define _IRR_COMPILE_WITH_OCT_LOADER_ if you want to load FSRad OCT files +#define _IRR_COMPILE_WITH_OCT_LOADER_ +//! Define _IRR_COMPILE_WITH_OGRE_LOADER_ if you want to load Ogre 3D files +#define _IRR_COMPILE_WITH_OGRE_LOADER_ +//! Define _IRR_COMPILE_WITH_STL_LOADER_ if you want to load .stl files +#define _IRR_COMPILE_WITH_STL_LOADER_ + +//! Define _IRR_COMPILE_WITH_IRR_WRITER_ if you want to write static .irr files +#define _IRR_COMPILE_WITH_IRR_WRITER_ +//! Define _IRR_COMPILE_WITH_COLLADA_WRITER_ if you want to write Collada files +#define _IRR_COMPILE_WITH_COLLADA_WRITER_ +//! Define _IRR_COMPILE_WITH_STL_WRITER_ if you want to write .stl files +#define _IRR_COMPILE_WITH_STL_WRITER_ + +//! Define _IRR_COMPILE_WITH_BMP_LOADER_ if you want to load .bmp files +#define _IRR_COMPILE_WITH_BMP_LOADER_ +//! Define _IRR_COMPILE_WITH_JPG_LOADER_ if you want to load .jpg files +#define _IRR_COMPILE_WITH_JPG_LOADER_ +//! Define _IRR_COMPILE_WITH_PCX_LOADER_ if you want to load .pcx files +#define _IRR_COMPILE_WITH_PCX_LOADER_ +//! Define _IRR_COMPILE_WITH_PNG_LOADER_ if you want to load .png files +#define _IRR_COMPILE_WITH_PNG_LOADER_ +//! Define _IRR_COMPILE_WITH_PPM_LOADER_ if you want to load .ppm/.pgm/.pbm files +#define _IRR_COMPILE_WITH_PPM_LOADER_ +//! Define _IRR_COMPILE_WITH_PSD_LOADER_ if you want to load .psd files +#define _IRR_COMPILE_WITH_PSD_LOADER_ +//! Define _IRR_COMPILE_WITH_TGA_LOADER_ if you want to load .tga files +#define _IRR_COMPILE_WITH_TGA_LOADER_ + +//! Define _IRR_COMPILE_WITH_BMP_WRITER_ if you want to write .bmp files +#define _IRR_COMPILE_WITH_BMP_WRITER_ +//! Define _IRR_COMPILE_WITH_JPG_WRITER_ if you want to write .jpg files +#define _IRR_COMPILE_WITH_JPG_WRITER_ +//! Define _IRR_COMPILE_WITH_PCX_WRITER_ if you want to write .pcx files +#define _IRR_COMPILE_WITH_PCX_WRITER_ +//! Define _IRR_COMPILE_WITH_PNG_WRITER_ if you want to write .png files +#define _IRR_COMPILE_WITH_PNG_WRITER_ +//! Define _IRR_COMPILE_WITH_PPM_WRITER_ if you want to write .ppm files +#define _IRR_COMPILE_WITH_PPM_WRITER_ +//! Define _IRR_COMPILE_WITH_PSD_WRITER_ if you want to write .psd files +#define _IRR_COMPILE_WITH_PSD_WRITER_ +//! Define _IRR_COMPILE_WITH_TGA_WRITER_ if you want to write .tga files +#define _IRR_COMPILE_WITH_TGA_WRITER_ + +//! Set FPU settings +/** Irrlicht should use approximate float and integer fpu techniques +precision will be lower but speed higher. currently X86 only +*/ +#if !defined(MACOSX) && !defined(_IRR_SOLARIS_PLATFORM_) + //#define IRRLICHT_FAST_MATH +#endif + +// Some cleanup +// XBox does not have OpenGL or DirectX9 +#if defined(_IRR_XBOX_PLATFORM_) +#undef _IRR_COMPILE_WITH_OPENGL_ +#undef _IRR_COMPILE_WITH_DIRECT3D_9_ +#endif + +#endif // __IRR_COMPILE_CONFIG_H_INCLUDED__ + diff --git a/engine/include/support/aabbox3d.h b/engine/include/support/aabbox3d.h new file mode 100644 index 0000000..2827bad --- /dev/null +++ b/engine/include/support/aabbox3d.h @@ -0,0 +1,292 @@ +// Copyright (C) 2002-2007 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_AABBOX_3D_H_INCLUDED__ +#define __IRR_AABBOX_3D_H_INCLUDED__ + +#include "irrMath.h" +#include "plane3d.h" +#include "line3d.h" + +namespace irr +{ +namespace core +{ + +//! Axis aligned bounding box in 3d dimensional space. +/** Has some useful methods used with occlusion culling or clipping. +*/ +template +class aabbox3d +{ + public: + + // Constructors + + aabbox3d(): MinEdge(-1,-1,-1), MaxEdge(1,1,1) {} + aabbox3d(const vector3d& min, const vector3d& max): MinEdge(min), MaxEdge(max) {} + aabbox3d(const vector3d& init): MinEdge(init), MaxEdge(init) {} + aabbox3d(T minx, T miny, T minz, T maxx, T maxy, T maxz): MinEdge(minx, miny, minz), MaxEdge(maxx, maxy, maxz) {} + + // operators + + inline bool operator==(const aabbox3d& other) const { return (MinEdge == other.MinEdge && other.MaxEdge == MaxEdge);}; + inline bool operator!=(const aabbox3d& other) const { return !(MinEdge == other.MinEdge && other.MaxEdge == MaxEdge);}; + + // functions + + //! Adds a point to the bounding box, causing it to grow bigger, + //! if point is outside of the box + //! \param p: Point to add into the box. + void addInternalPoint(const vector3d& p) + { + addInternalPoint(p.X, p.Y, p.Z); + } + + //! Adds an other bounding box to the bounding box, causing it to grow bigger, + //! if the box is outside of the box + //! \param b: Other bounding box to add into this box. + void addInternalBox(const aabbox3d& b) + { + addInternalPoint(b.MaxEdge); + addInternalPoint(b.MinEdge); + } + + //! Resets the bounding box. + void reset(T x, T y, T z) + { + MaxEdge.set(x,y,z); + MinEdge = MaxEdge; + } + + //! Resets the bounding box. + void reset(const aabbox3d& initValue) + { + *this = initValue; + } + + //! Resets the bounding box. + void reset(const vector3d& initValue) + { + MaxEdge = initValue; + MinEdge = initValue; + } + + //! Adds a point to the bounding box, causing it to grow bigger, + //! if point is outside of the box. + //! \param x: X Coordinate of the point to add to this box. + //! \param y: Y Coordinate of the point to add to this box. + //! \param z: Z Coordinate of the point to add to this box. + void addInternalPoint(T x, T y, T z) + { + if (x>MaxEdge.X) MaxEdge.X = x; + if (y>MaxEdge.Y) MaxEdge.Y = y; + if (z>MaxEdge.Z) MaxEdge.Z = z; + + if (x& p) const + { + return (p.X >= MinEdge.X && p.X <= MaxEdge.X && + p.Y >= MinEdge.Y && p.Y <= MaxEdge.Y && + p.Z >= MinEdge.Z && p.Z <= MaxEdge.Z); + }; + + //! Determinates if a point is within this box and its borders. + //! \param p: Point to check. + //! \return Returns true if the point is withing the box, and false if it is not. + bool isPointTotalInside(const vector3d& p) const + { + return (p.X > MinEdge.X && p.X < MaxEdge.X && + p.Y > MinEdge.Y && p.Y < MaxEdge.Y && + p.Z > MinEdge.Z && p.Z < MaxEdge.Z); + }; + + //! Determinates if the box intersects with an other box. + //! \param other: Other box to check a intersection with. + //! \return Returns true if there is a intersection with the other box, + //! otherwise false. + bool intersectsWithBox(const aabbox3d& other) const + { + return (MinEdge <= other.MaxEdge && MaxEdge >= other.MinEdge); + } + + //! Returns if this box is completely inside the 'other' box. + bool isFullInside(const aabbox3d& other) const + { + return MinEdge >= other.MinEdge && MaxEdge <= other.MaxEdge; + } + + //! Tests if the box intersects with a line + //! \param line: Line to test intersection with. + //! \return Returns true if there is an intersection and false if not. + bool intersectsWithLine(const line3d& line) const + { + return intersectsWithLine(line.getMiddle(), line.getVector().normalize(), + (T)(line.getLength() * 0.5)); + } + + //! Tests if the box intersects with a line + //! \return Returns true if there is an intersection and false if not. + bool intersectsWithLine(const vector3d& linemiddle, + const vector3d& linevect, + T halflength) const + { + const vector3d e = getExtent() * (T)0.5; + const vector3d t = getCenter() - linemiddle; + + if ((fabs(t.X) > e.X + halflength * fabs(linevect.X)) || + (fabs(t.Y) > e.Y + halflength * fabs(linevect.Y)) || + (fabs(t.Z) > e.Z + halflength * fabs(linevect.Z)) ) + return false; + + T r = e.Y * (T)fabs(linevect.Z) + e.Z * (T)fabs(linevect.Y); + if (fabs(t.Y*linevect.Z - t.Z*linevect.Y) > r ) + return false; + + r = e.X * (T)fabs(linevect.Z) + e.Z * (T)fabs(linevect.X); + if (fabs(t.Z*linevect.X - t.X*linevect.Z) > r ) + return false; + + r = e.X * (T)fabs(linevect.Y) + e.Y * (T)fabs(linevect.X); + if (fabs(t.X*linevect.Y - t.Y*linevect.X) > r) + return false; + + return true; + } + + //! Classifies a relation with a plane. + //! \param plane: Plane to classify relation to. + //! \return Returns ISREL3D_FRONT if the box is in front of the plane, + //! ISREL3D_BACK if the box is behind the plane, and + //! ISREL3D_CLIPPED if it is on both sides of the plane. + EIntersectionRelation3D classifyPlaneRelation(const plane3d& plane) const + { + vector3d nearPoint(MaxEdge); + vector3d farPoint(MinEdge); + + if (plane.Normal.X > (T)0) + { + nearPoint.X = MinEdge.X; + farPoint.X = MaxEdge.X; + } + + if (plane.Normal.Y > (T)0) + { + nearPoint.Y = MinEdge.Y; + farPoint.Y = MaxEdge.Y; + } + + if (plane.Normal.Z > (T)0) + { + nearPoint.Z = MinEdge.Z; + farPoint.Z = MaxEdge.Z; + } + + if (plane.Normal.dotProduct(nearPoint) + plane.D > (T)0) + return ISREL3D_FRONT; + + if (plane.Normal.dotProduct(farPoint) + plane.D > (T)0) + return ISREL3D_CLIPPED; + + return ISREL3D_BACK; + } + + + //! returns center of the bounding box + vector3d getCenter() const + { + return (MinEdge + MaxEdge) / 2; + } + + //! returns extend of the box + vector3d getExtent() const + { + return MaxEdge - MinEdge; + } + + + //! stores all 8 edges of the box into a array + //! \param edges: Pointer to array of 8 edges + void getEdges(vector3d *edges) const + { + const core::vector3d middle = getCenter(); + const core::vector3d diag = middle - MaxEdge; + + /* + Edges are stored in this way: + Hey, am I an ascii artist, or what? :) niko. + /3--------/7 + / | / | + / | / | + 1---------5 | + | 2- - -| -6 + | / | / + |/ | / + 0---------4/ + */ + + edges[0].set(middle.X + diag.X, middle.Y + diag.Y, middle.Z + diag.Z); + edges[1].set(middle.X + diag.X, middle.Y - diag.Y, middle.Z + diag.Z); + edges[2].set(middle.X + diag.X, middle.Y + diag.Y, middle.Z - diag.Z); + edges[3].set(middle.X + diag.X, middle.Y - diag.Y, middle.Z - diag.Z); + edges[4].set(middle.X - diag.X, middle.Y + diag.Y, middle.Z + diag.Z); + edges[5].set(middle.X - diag.X, middle.Y - diag.Y, middle.Z + diag.Z); + edges[6].set(middle.X - diag.X, middle.Y + diag.Y, middle.Z - diag.Z); + edges[7].set(middle.X - diag.X, middle.Y - diag.Y, middle.Z - diag.Z); + } + + + //! returns if the box is empty, which means that there is + //! no space within the min and the max edge. + bool isEmpty() const + { + return MinEdge.equals ( MaxEdge ); + } + + //! repairs the box, if for example MinEdge and MaxEdge are swapped. + void repair() + { + T t; + + if (MinEdge.X > MaxEdge.X) + { t=MinEdge.X; MinEdge.X = MaxEdge.X; MaxEdge.X=t; } + if (MinEdge.Y > MaxEdge.Y) + { t=MinEdge.Y; MinEdge.Y = MaxEdge.Y; MaxEdge.Y=t; } + if (MinEdge.Z > MaxEdge.Z) + { t=MinEdge.Z; MinEdge.Z = MaxEdge.Z; MaxEdge.Z=t; } + } + + //! Calculates a new interpolated bounding box. + //! \param other: other box to interpolate between + //! \param d: value between 0.0f and 1.0f. + aabbox3d getInterpolated(const aabbox3d& other, f32 d) const + { + f32 inv = 1.0f - d; + return aabbox3d((other.MinEdge*inv) + (MinEdge*d), + (other.MaxEdge*inv) + (MaxEdge*d)); + } + + // member variables + + vector3d MinEdge; + vector3d MaxEdge; +}; + + //! Typedef for a f32 3d bounding box. + typedef aabbox3d aabbox3df; + //! Typedef for an integer 3d bounding box. + typedef aabbox3d aabbox3di; + +} // end namespace core +} // end namespace irr + +#endif + diff --git a/engine/include/support/dimension2d.h b/engine/include/support/dimension2d.h new file mode 100644 index 0000000..977685c --- /dev/null +++ b/engine/include/support/dimension2d.h @@ -0,0 +1,78 @@ +// Copyright (C) 2002-2007 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_DIMENSION2D_H_INCLUDED__ +#define __IRR_DIMENSION2D_H_INCLUDED__ + +#include "irrTypes.h" + +namespace irr +{ +namespace core +{ + + //! Specifies a 2 dimensional size. + template + class dimension2d + { + public: + dimension2d() : Width(0), Height(0) {} + + dimension2d(const T& width, const T& height) + : Width(width), Height(height) {} + + bool operator == (const dimension2d& other) const + { + return Width == other.Width && Height == other.Height; + } + + bool operator != (const dimension2d& other) const + { + return ! (*this == other); + } + + dimension2d& set(const T& width, const T& height) + { + Width = width; + Height = height; + return *this; + } + + dimension2d& operator/=(const T& scale) + { + Width /= scale; + Height /= scale; + return *this; + } + + dimension2d operator/(const T& scale) const + { + return dimension2d(Width/scale, Height/scale); + } + + dimension2d& operator*=(const T& scale) + { + Width *= scale; + Height *= scale; + return *this; + } + + dimension2d operator*(const T& scale) const + { + return dimension2d(Width*scale, Height*scale); + } + + T Width, Height; + }; + + //! Typedef for a f32 dimension. + typedef dimension2d dimension2df; + //! Typedef for an integer dimension. + typedef dimension2d dimension2di; + +} // end namespace core +} // end namespace irr + +#endif + diff --git a/engine/include/support/irrMath.h b/engine/include/support/irrMath.h new file mode 100644 index 0000000..568880d --- /dev/null +++ b/engine/include/support/irrMath.h @@ -0,0 +1,445 @@ +// Copyright (C) 2002-2007 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_MATH_H_INCLUDED__ +#define __IRR_MATH_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#include "irrTypes.h" +#include + +#if defined(_IRR_SOLARIS_PLATFORM_) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__) + #define sqrtf(X) (f32)sqrt((f64)(X)) + #define sinf(X) (f32)sin((f64)(X)) + #define cosf(X) (f32)cos((f64)(X)) + #define ceilf(X) (f32)ceil((f64)(X)) + #define floorf(X) (f32)floor((f64)(X)) + #define powf(X,Y) (f32)pow((f64)(X),(f64)(Y)) + #define fmodf(X,Y) (f32)fmod((f64)(X),(f64)(Y)) + #define fabsf(X) (f32)fabs((f64)(X)) +#endif + +namespace irr +{ +namespace core +{ + + //! Rounding error constant often used when comparing f32 values. + +#ifdef IRRLICHT_FAST_MATH + const f32 ROUNDING_ERROR_32 = 0.00005f; + const f64 ROUNDING_ERROR_64 = 0.000005f; +#else + const f32 ROUNDING_ERROR_32 = 0.000001f; + const f64 ROUNDING_ERROR_64 = 0.00000001f; +#endif + + //! Constant for PI. + const f32 PI = 3.14159265359f; + + //! Constant for reciprocal of PI. + const f32 RECIPROCAL_PI = 1.0f/PI; + + //! Constant for half of PI. + const f32 HALF_PI = PI/2.0f; + + //! Constant for 64bit PI. + const f64 PI64 = 3.1415926535897932384626433832795028841971693993751; + + //! Constant for 64bit reciprocal of PI. + const f64 RECIPROCAL_PI64 = 1.0/PI64; + + //! 32bit Constant for converting from degrees to radians + const f32 DEGTORAD = PI / 180.0f; + + //! 32bit constant for converting from radians to degrees (formally known as GRAD_PI) + const f32 RADTODEG = 180.0f / PI; + + //! 64bit constant for converting from degrees to radians (formally known as GRAD_PI2) + const f64 DEGTORAD64 = PI64 / 180.0; + + //! 64bit constant for converting from radians to degrees + const f64 RADTODEG64 = 180.0 / PI64; + + //! returns minimum of two values. Own implementation to get rid of the STL (VS6 problems) + template + inline const T& min_(const T& a, const T& b) + { + return a < b ? a : b; + } + + //! returns minimum of three values. Own implementation to get rid of the STL (VS6 problems) + template + inline const T& min_(const T& a, const T& b, const T& c) + { + return a < b ? min_(a, c) : min_(b, c); + } + + //! returns maximum of two values. Own implementation to get rid of the STL (VS6 problems) + template + inline const T& max_(const T& a, const T& b) + { + return a < b ? b : a; + } + + //! returns maximum of three values. Own implementation to get rid of the STL (VS6 problems) + template + inline const T& max_(const T& a, const T& b, const T& c) + { + return a < b ? max_(b, c) : max_(a, c); + } + + //! returns abs of two values. Own implementation to get rid of STL (VS6 problems) + template + inline T abs_(const T& a) + { + return a < (T)0 ? -a : a; + } + + //! returns linear interpolation of a and b with ratio t + //! \return: a if t==0, b if t==1, and the linear interpolation else + template + inline T lerp(const T& a, const T& b, const f32 t) + { + return (a*(1.f-t)) + (b*t); + } + + //! clamps a value between low and high + template + inline const T clamp (const T& value, const T& low, const T& high) + { + return min_ (max_(value,low), high); + } + + //! returns if a equals b, taking possible rounding errors into account + inline bool equals(const f32 a, const f32 b, const f32 tolerance = ROUNDING_ERROR_32) + { + return (a + tolerance >= b) && (a - tolerance <= b); + } + + //! returns if a equals b, taking possible rounding errors into account + inline bool equals(const s32 a, const s32 b, const s32 tolerance = 0) + { + return (a + tolerance >= b) && (a - tolerance <= b); + } + + //! returns if a equals b, taking possible rounding errors into account + inline bool equals(const u32 a, const u32 b, const u32 tolerance = 0) + { + return (a + tolerance >= b) && (a - tolerance <= b); + } + + //! returns if a equals zero, taking rounding errors into account + inline bool iszero(const f32 a, const f32 tolerance = ROUNDING_ERROR_32) + { + return fabsf ( a ) <= tolerance; + } + + //! returns if a equals zero, taking rounding errors into account + inline bool iszero(const s32 a, const s32 tolerance = 0) + { + return ( a & 0x7ffffff ) <= tolerance; + } + + //! returns if a equals zero, taking rounding errors into account + inline bool iszero(const u32 a, const u32 tolerance = 0) + { + return a <= tolerance; + } + + inline s32 s32_min ( s32 a, s32 b) + { + s32 mask = (a - b) >> 31; + return (a & mask) | (b & ~mask); + } + + inline s32 s32_max ( s32 a, s32 b) + { + s32 mask = (a - b) >> 31; + return (b & mask) | (a & ~mask); + } + + inline s32 s32_clamp (s32 value, s32 low, s32 high) + { + return s32_min (s32_max(value,low), high); + } + + /* + + float IEEE-754 bit represenation + + 0 0x00000000 + 1.0 0x3f800000 + 0.5 0x3f000000 + 3 0x40400000 + +inf 0x7f800000 + -inf 0xff800000 + +NaN 0x7fc00000 or 0x7ff00000 + in general: number = (sign ? -1:1) * 2^(exponent) * 1.(mantissa bits) + */ + + #define F32_AS_S32(f) (*((s32 *) &(f))) + #define F32_AS_U32(f) (*((u32 *) &(f))) + #define F32_AS_U32_POINTER(f) ( ((u32 *) &(f))) + + #define F32_VALUE_0 0x00000000 + #define F32_VALUE_1 0x3f800000 + #define F32_SIGN_BIT 0x80000000U + #define F32_EXPON_MANTISSA 0x7FFFFFFFU + + //! code is taken from IceFPU + //! Integer representation of a floating-point value. + #define IR(x) ((u32&)(x)) + + //! Absolute integer representation of a floating-point value + #define AIR(x) (IR(x)&0x7fffffff) + + //! Floating-point representation of an integer value. + #define FR(x) ((f32&)(x)) + + #define IEEE_1_0 0x3f800000 //!< integer representation of 1.0 + #define IEEE_255_0 0x437f0000 //!< integer representation of 255.0 + +#ifdef IRRLICHT_FAST_MATH + #define F32_LOWER_0(f) (F32_AS_U32(f) > F32_SIGN_BIT) + #define F32_LOWER_EQUAL_0(f) (F32_AS_S32(f) <= F32_VALUE_0) + #define F32_GREATER_0(f) (F32_AS_S32(f) > F32_VALUE_0) + #define F32_GREATER_EQUAL_0(f) (F32_AS_U32(f) <= F32_SIGN_BIT) + #define F32_EQUAL_1(f) (F32_AS_U32(f) == F32_VALUE_1) + #define F32_EQUAL_0(f) ( (F32_AS_U32(f) & F32_EXPON_MANTISSA ) == F32_VALUE_0) + + // only same sign + #define F32_A_GREATER_B(a,b) (F32_AS_S32((a)) > F32_AS_S32((b))) +#else + #define F32_LOWER_0(n) ((n) < 0.0f) + #define F32_LOWER_EQUAL_0(n) ((n) <= 0.0f) + #define F32_GREATER_0(n) ((n) > 0.0f) + #define F32_GREATER_EQUAL_0(n) ((n) >= 0.0f) + #define F32_EQUAL_1(n) ((n) == 1.0f) + #define F32_EQUAL_0(n) ((n) == 0.0f) + #define F32_A_GREATER_B(a,b) ((a) > (b)) +#endif + + +#ifndef REALINLINE + #ifdef _MSC_VER + #define REALINLINE __forceinline + #else + #define REALINLINE inline + #endif +#endif + + + //! conditional set based on mask and arithmetic shift + REALINLINE u32 if_c_a_else_b ( const s32 condition, const u32 a, const u32 b ) + { + return ( ( -condition >> 31 ) & ( a ^ b ) ) ^ b; + } + + //! conditional set based on mask and arithmetic shift + REALINLINE u32 if_c_a_else_0 ( const s32 condition, const u32 a ) + { + return ( -condition >> 31 ) & a; + } + + /* + if (condition) state |= m; else state &= ~m; + */ + REALINLINE void setbit ( u32 &state, s32 condition, u32 mask ) + { + // 0, or any postive to mask + //s32 conmask = -condition >> 31; + state ^= ( ( -condition >> 31 ) ^ state ) & mask; + } + + + + inline f32 round_( f32 x ) + { + return floorf( x + 0.5f ); + } + + REALINLINE void clearFPUException () + { +#ifdef IRRLICHT_FAST_MATH +#ifdef feclearexcept + feclearexcept(FE_ALL_EXCEPT); +#elif defined(_MSC_VER) + __asm fnclex; +#elif defined(__GNUC__) && defined(__x86__) + __asm__ __volatile__ ("fclex \n\t"); +#else +# warn clearFPUException not supported. +#endif +#endif + } + + REALINLINE f32 reciprocal_squareroot(const f32 x) + { +#ifdef IRRLICHT_FAST_MATH + // comes from Nvidia +#if 1 + u32 tmp = (u32(IEEE_1_0 << 1) + IEEE_1_0 - *(u32*)&x) >> 1; + f32 y = *(f32*)&tmp; + return y * (1.47f - 0.47f * x * y * y); +#elif defined(_MSC_VER) + // an sse2 version + __asm + { + movss xmm0, x + rsqrtss xmm0, xmm0 + movss x, xmm0 + } + return x; +#endif +#else // no fast math + return 1.f / sqrtf ( x ); +#endif + } + + + + REALINLINE f32 reciprocal ( const f32 f ) + { +#ifdef IRRLICHT_FAST_MATH + //! i do not divide through 0.. (fpu expection) + // instead set f to a high value to get a return value near zero.. + // -1000000000000.f.. is use minus to stay negative.. + // must test's here (plane.normal dot anything ) checks on <= 0.f + return 1.f / f; + //u32 x = (-(AIR(f) != 0 ) >> 31 ) & ( IR(f) ^ 0xd368d4a5 ) ^ 0xd368d4a5; + //return 1.f / FR ( x ); +#else // no fast math + return 1.f / f; +#endif + } + + + REALINLINE f32 reciprocal_approxim ( const f32 p ) + { +#ifdef IRRLICHT_FAST_MATH + register u32 x = 0x7F000000 - IR ( p ); + const f32 r = FR ( x ); + return r * (2.0f - p * r); +#else // no fast math + return 1.f / p; +#endif + } + + + REALINLINE s32 floor32(f32 x) + { +#ifdef IRRLICHT_FAST_MATH + const f32 h = 0.5f; + + s32 t; + +#if defined(_MSC_VER) + __asm + { + fld x + fsub h + fistp t + } +#elif defined(__GNUC__) + __asm__ __volatile__ ( + "fsub %2 \n\t" + "fistpl %0" + : "=m" (t) + : "t" (x), "f" (h) + : "st" + ); +#else +# warn IRRLICHT_FAST_MATH not supported. + return (s32) floorf ( x ); +#endif + return t; +#else // no fast math + return (s32) floorf ( x ); +#endif + } + + + REALINLINE s32 ceil32 ( f32 x ) + { +#ifdef IRRLICHT_FAST_MATH + const f32 h = 0.5f; + + s32 t; + +#if defined(_MSC_VER) + __asm + { + fld x + fadd h + fistp t + } +#elif defined(__GNUC__) + __asm__ __volatile__ ( + "fadd %2 \n\t" + "fistpl %0 \n\t" + : "=m"(t) + : "t"(x), "f"(h) + : "st" + ); +#else +# warn IRRLICHT_FAST_MATH not supported. + return (s32) ceilf ( x ); +#endif + return t; +#else // not fast math + return (s32) ceilf ( x ); +#endif + } + + + + REALINLINE s32 round32(f32 x) + { +#if defined(IRRLICHT_FAST_MATH) + s32 t; + +#if defined(_MSC_VER) + __asm + { + fld x + fistp t + } +#elif defined(__GNUC__) + __asm__ __volatile__ ( + "fistpl %0 \n\t" + : "=m"(t) + : "t"(x) + : "st" + ); +#else +# warn IRRLICHT_FAST_MATH not supported. + return (s32) round_(x); +#endif + return t; +#else // no fast math + return (s32) round_(x); +#endif + } + + inline f32 f32_max3(const f32 a, const f32 b, const f32 c) + { + return a > b ? (a > c ? a : c) : (b > c ? b : c); + } + + inline f32 f32_min3(const f32 a, const f32 b, const f32 c) + { + return a < b ? (a < c ? a : c) : (b < c ? b : c); + } + + inline f32 fract ( f32 x ) + { + return x - floorf ( x ); + } + +} // end namespace core +} // end namespace irr + +#endif + diff --git a/engine/include/support/irrTypes.h b/engine/include/support/irrTypes.h new file mode 100644 index 0000000..98b9f9d --- /dev/null +++ b/engine/include/support/irrTypes.h @@ -0,0 +1,160 @@ +// Copyright (C) 2002-2007 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_TYPES_H_INCLUDED__ +#define __IRR_TYPES_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +namespace irr +{ + +//! 8 bit unsigned variable. +/** This is a typedef for unsigned char, it ensures portability of the engine. */ +typedef unsigned char u8; + +//! 8 bit signed variable. +/** This is a typedef for signed char, it ensures portability of the engine. */ +typedef signed char s8; + +//! 8 bit character variable. +/** This is a typedef for char, it ensures portability of the engine. */ +typedef char c8; + + + +//! 16 bit unsigned variable. +/** This is a typedef for unsigned short, it ensures portability of the engine. */ +typedef unsigned short u16; + +//! 16 bit signed variable. +/** This is a typedef for signed short, it ensures portability of the engine. */ +typedef signed short s16; + + + +//! 32 bit unsigned variable. +/** This is a typedef for unsigned int, it ensures portability of the engine. */ +typedef unsigned int u32; + +//! 32 bit signed variable. +/** This is a typedef for signed int, it ensures portability of the engine. */ +typedef signed int s32; + + + +// 64 bit signed variable. +// This is a typedef for __int64, it ensures portability of the engine. +// This type is currently not used by the engine and not supported by compilers +// other than Microsoft Compilers, so it is outcommented. +//typedef __int64 s64; + + + +//! 32 bit floating point variable. +/** This is a typedef for float, it ensures portability of the engine. */ +typedef float f32; + +//! 64 bit floating point variable. +/** This is a typedef for double, it ensures portability of the engine. */ +typedef double f64; + + +} // end namespace irr + + +#include +#ifdef _IRR_WINDOWS_API_ +//! Defines for s{w,n}printf because these methods do not match the ISO C +//! standard on Windows platforms, but it does on all others. +//! These should be int snprintf(char *str, size_t size, const char *format, ...); +//! and int swprintf(wchar_t *wcs, size_t maxlen, const wchar_t *format, ...); +#if defined(_MSC_VER) && _MSC_VER > 1310 +#define swprintf swprintf_s +#define snprintf sprintf_s +#else +#define swprintf _snwprintf +#define snprintf _snprintf +#endif + +// define the wchar_t type if not already built in. +#ifdef _MSC_VER +#ifndef _WCHAR_T_DEFINED +//! A 16 bit wide character type. +/** + Defines the wchar_t-type. + In VS6, its not possible to tell + the standard compiler to treat wchar_t as a built-in type, and + sometimes we just don't want to include the huge stdlib.h or wchar.h, + so we'll use this. +*/ +typedef unsigned short wchar_t; +#define _WCHAR_T_DEFINED +#endif // wchar is not defined +#endif // microsoft compiler +#endif // _IRR_WINDOWS_API_ + +//! define a break macro for debugging. +#if defined(_DEBUG) +#if defined(_IRR_WINDOWS_API_) && defined(_MSC_VER) +#define _IRR_DEBUG_BREAK_IF( _CONDITION_ ) if (_CONDITION_) {_asm int 3} +#else +#include "assert.h" +#define _IRR_DEBUG_BREAK_IF( _CONDITION_ ) assert( !(_CONDITION_) ); +#endif +#else +#define _IRR_DEBUG_BREAK_IF( _CONDITION_ ) +#endif + +//! Defines a small statement to work around a microsoft compiler bug. +/** The microsft compiler 7.0 - 7.1 has a bug: +When you call unmanaged code that returns a bool type value of false from managed code, +the return value may appear as true. See +http://support.microsoft.com/default.aspx?kbid=823071 for details. +Compiler version defines: VC6.0 : 1200, VC7.0 : 1300, VC7.1 : 1310, VC8.0 : 1400*/ +#if defined(_IRR_WINDOWS_API_) && defined(_MSC_VER) && (_MSC_VER > 1299) && (_MSC_VER < 1400) +#define _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX __asm mov eax,100 +#else +#define _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX +#endif // _IRR_MANAGED_MARSHALLING_BUGFIX + + +// memory debugging +#if defined(_DEBUG) && defined(IRRLICHT_EXPORTS) && defined(_MSC_VER) && \ + (_MSC_VER > 1299) && !defined(_IRR_DONT_DO_MEMORY_DEBUGGING_HERE) + + #define CRTDBG_MAP_ALLOC + #define _CRTDBG_MAP_ALLOC + #define DEBUG_CLIENTBLOCK new( _CLIENT_BLOCK, __FILE__, __LINE__) + #include + #include + #define new DEBUG_CLIENTBLOCK +#endif + +// disable truncated debug information warning in visual studio 6 by default +#if defined(_MSC_VER) && (_MSC_VER < 1300 ) +#pragma warning( disable: 4786) +#endif // _MSC + + +//! ignore VC8 warning deprecated +/** The microsoft compiler */ +#if defined(_IRR_WINDOWS_API_) && defined(_MSC_VER) && (_MSC_VER >= 1400) + //#pragma warning( disable: 4996) + //#define _CRT_SECURE_NO_DEPRECATE 1 + //#define _CRT_NONSTDC_NO_DEPRECATE 1 +#endif + + +//! creates four CC codes used in Irrlicht for simple ids +/** some compilers can create those by directly writing the +code like 'code', but some generate warnings so we use this macro here */ +#define MAKE_IRR_ID(c0, c1, c2, c3) \ + ((u32)(u8)(c0) | ((u32)(u8)(c1) << 8) | \ + ((u32)(u8)(c2) << 16) | ((u32)(u8)(c3) << 24 )) + + +#endif // __IRR_TYPES_H_INCLUDED__ + + diff --git a/engine/include/support/line3d.h b/engine/include/support/line3d.h new file mode 100644 index 0000000..b5eff0c --- /dev/null +++ b/engine/include/support/line3d.h @@ -0,0 +1,126 @@ +// Copyright (C) 2002-2007 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_LINE_3D_H_INCLUDED__ +#define __IRR_LINE_3D_H_INCLUDED__ + +#include "irrTypes.h" +#include "vector3d.h" + +namespace irr +{ +namespace core +{ + +//! 3D line between two points with intersection methods. +template +class line3d +{ + public: + + // Constructors + + line3d() : start(0,0,0), end(1,1,1) {} + line3d(T xa, T ya, T za, T xb, T yb, T zb) : start(xa, ya, za), end(xb, yb, zb) {} + line3d(const vector3d& start, const vector3d& end) : start(start), end(end) {} + + // operators + + line3d operator+(const vector3d& point) const { return line3d(start + point, end + point); } + line3d& operator+=(const vector3d& point) { start += point; end += point; return *this; } + + line3d operator-(const vector3d& point) const { return line3d(start - point, end - point); } + line3d& operator-=(const vector3d& point) { start -= point; end -= point; return *this; } + + bool operator==(const line3d& other) const { return (start==other.start && end==other.end) || (end==other.start && start==other.end);} + bool operator!=(const line3d& other) const { return !(start==other.start && end==other.end) || (end==other.start && start==other.end);} + + // functions + + void setLine(const T& xa, const T& ya, const T& za, const T& xb, const T& yb, const T& zb) {start.set(xa, ya, za); end.set(xb, yb, zb);} + void setLine(const vector3d& nstart, const vector3d& nend) {start.set(nstart); end.set(nend);} + void setLine(const line3d& line) {start.set(line.start); end.set(line.end);} + + //! Returns length of line + //! \return Returns length of line. + T getLength() const { return start.getDistanceFrom(end); } + + //! Returns sqared length of line + //! \return Returns sqared length of line. + T getLengthSQ() const { return start.getDistanceFromSQ(end); } + + //! Returns middle of line + vector3d getMiddle() const + { + return (start + end) * (T)0.5; + } + + //! Returns vector of line + vector3d getVector() const + { + return end - start; + } + + //! Returns if the given point is between start and end of the + //! line. Assumes that the point is already somewhere on the line. + bool isPointBetweenStartAndEnd(const vector3d& point) const + { + return point.isBetweenPoints(start, end); + } + + //! Returns the closest point on this line to a point + vector3d getClosestPoint(const vector3d& point) const + { + vector3d c = point - start; + vector3d v = end - start; + T d = (T)v.getLength(); + v /= d; + T t = v.dotProduct(c); + + if (t < (T)0.0) + return start; + if (t > d) + return end; + + v *= t; + return start + v; + } + + //! Returns if the line intersects with a shpere + //! \param sorigin: Origin of the shpere. + //! \param sradius: Radius of the sphere. + //! \param outdistance: The distance to the first intersection point. + //! \return Returns true if there is an intersection. + //! If there is one, the distance to the first intersection point + //! is stored in outdistance. + bool getIntersectionWithSphere(vector3d sorigin, T sradius, f64& outdistance) const + { + const vector3d q = sorigin - start; + T c = q.getLength(); + T v = q.dotProduct(getVector().normalize()); + T d = sradius * sradius - (c*c - v*v); + + if (d < 0.0) + return false; + + outdistance = v - sqrt((f64)d); + return true; + } + + // member variables + + vector3d start; + vector3d end; +}; + + //! Typedef for an f32 line. + typedef line3d line3df; + //! Typedef for an integer line. + typedef line3d line3di; + +} // end namespace core +} // end namespace irr + +#endif + diff --git a/engine/include/support/matrix4.h b/engine/include/support/matrix4.h new file mode 100644 index 0000000..a943759 --- /dev/null +++ b/engine/include/support/matrix4.h @@ -0,0 +1,1639 @@ +// Copyright (C) 2002-2007 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_MATRIX_H_INCLUDED__ +#define __IRR_MATRIX_H_INCLUDED__ + +#include "irrTypes.h" +#include "vector3d.h" +#include "vector2d.h" +#include "plane3d.h" +#include "aabbox3d.h" +#include "rect.h" +#include + +namespace irr +{ +namespace core +{ + + //! 4x4 matrix. Mostly used as transformation matrix for 3d calculations. + /* Matrix4 is mainly used by the Irrlicht engine for doing transformations. + The matrix is a D3D style matrix, row major with translations in the 4th row. + */ + template + class CMatrix4 + { + public: + + //! Constructor Flags + enum eConstructor + { + EM4CONST_NOTHING = 0, + EM4CONST_COPY, + EM4CONST_IDENTITY, + EM4CONST_TRANSPOSED, + EM4CONST_INVERSE, + EM4CONST_INVERSE_TRANSPOSED + }; + + CMatrix4( eConstructor constructor = EM4CONST_IDENTITY ); + CMatrix4( const CMatrix4& other,eConstructor constructor = EM4CONST_COPY); + + //! Simple operator for directly accessing every element of the matrix. + T& operator()(const s32 row, const s32 col) { definitelyIdentityMatrix=false; return M[ row * 4 + col ]; } + + //! Simple operator for directly accessing every element of the matrix. + const T& operator()(const s32 row, const s32 col) const { return M[row * 4 + col]; } + + //! Simple operator for linearly accessing every element of the matrix. + T& operator[](u32 index) { definitelyIdentityMatrix=false; return M[index]; } + + //! Simple operator for linearly accessing every element of the matrix. + const T& operator[](u32 index) const { return M[index]; } + + //! Sets this matrix equal to the other matrix. + inline CMatrix4& operator=(const CMatrix4 &other); + + //! Sets all elements of this matrix to the value. + inline CMatrix4& operator=(const T& scalar); + + //! Returns pointer to internal array + const T* pointer() const { return M; } + T* pointer() { definitelyIdentityMatrix=false; return M; } + + //! Returns true if other matrix is equal to this matrix. + bool operator==(const CMatrix4 &other) const; + + //! Returns true if other matrix is not equal to this matrix. + bool operator!=(const CMatrix4 &other) const; + + //! Add another matrix. + CMatrix4 operator+(const CMatrix4& other) const; + + //! Add another matrix. + CMatrix4& operator+=(const CMatrix4& other); + + //! Subtract another matrix. + CMatrix4 operator-(const CMatrix4& other) const; + + //! Subtract another matrix. + CMatrix4& operator-=(const CMatrix4& other); + + //! set this matrix to the product of two matrices + inline void setbyproduct(const CMatrix4& other_a,const CMatrix4& other_b ); + + //! set this matrix to the product of two matrices, no logical optimation + //! use it if you know you never have a identity matrix + void setbyproduct_nocheck(const CMatrix4& other_a,const CMatrix4& other_b ); + + //! Multiply by another matrix. + CMatrix4 operator*(const CMatrix4& other) const; + + //! Multiply by another matrix. + CMatrix4& operator*=(const CMatrix4& other); + + //! Multiply by scalar. + CMatrix4 operator*(const T& scalar) const; + + //! Multiply by scalar. + CMatrix4& operator*=(const T& scalar); + + //! Set matrix to identity. + inline void makeIdentity(); + + //! Returns true if the matrix is the identity matrix + inline bool isIdentity() const; + + //! Returns true if the matrix is the identity matrix + bool isIdentity_integer_base () const; + + //! Set the translation of the current matrix. Will erase any previous values. + void setTranslation( const vector3d& translation ); + + //! Gets the current translation + vector3d getTranslation() const; + + //! Set the inverse translation of the current matrix. Will erase any previous values. + void setInverseTranslation( const vector3d& translation ); + + //! Make a rotation matrix from Euler angles. The 4th row and column are unmodified. + inline void setRotationRadians( const vector3d& rotation ); + + //! Make a rotation matrix from Euler angles. The 4th row and column are unmodified. + void setRotationDegrees( const vector3d& rotation ); + + //! Returns the rotation, as set by setRotation(). This code was orginally written by by Chev. + core::vector3d getRotationDegrees() const; + + //! Make an inverted rotation matrix from Euler angles. The 4th row and column are unmodified. + inline void setInverseRotationRadians( const vector3d& rotation ); + + //! Make an inverted rotation matrix from Euler angles. The 4th row and column are unmodified. + void setInverseRotationDegrees( const vector3d& rotation ); + + //! Set Scale + void setScale( const vector3d& scale ); + + //! Get Scale + core::vector3d getScale() const; + + //! Translate a vector by the inverse of the translation part of this matrix. + void inverseTranslateVect( vector3df& vect ) const; + + //! Rotate a vector by the inverse of the rotation part of this matrix. + void inverseRotateVect( vector3df& vect ) const; + + //! Rotate a vector by the rotation part of this matrix. + void rotateVect( vector3df& vect ) const; + + //! An alternate transform vector method, writing into a second vector + void rotateVect(vector3df& out,const core::vector3df& in) const; + + //! An alternate transform vector method, writing into an array of 3 floats + void rotateVect(T *out,const core::vector3df &in) const; + + //! Transforms the vector by this matrix + void transformVect( vector3df& vect) const; + + //! Transforms input vector by this matrix and stores result in output vector + void transformVect( vector3df& out, const vector3df& in ) const; + + //! An alternate transform vector method, writing into an array of 4 floats + void transformVect(T *out,const core::vector3df &in) const; + + //! Translate a vector by the translation part of this matrix. + void translateVect( vector3df& vect ) const; + + //! Transforms a plane by this matrix + void transformPlane( core::plane3d &plane) const; + + //! Transforms a plane by this matrix ( some problems to solve..) + void transformPlane_new( core::plane3d &plane) const; + + //! Transforms a plane by this matrix + void transformPlane( const core::plane3d &in, core::plane3d &out) const; + + //! Transforms a axis aligned bounding box + /** The result box of this operation may not be very accurate. For + accurate results, use transformBoxEx() */ + void transformBox(core::aabbox3d& box) const; + + //! Transforms a axis aligned bounding box more accurately than transformBox() + /** The result box of this operation should by quite accurate, but this operation + is slower than transformBox(). */ + void transformBoxEx(core::aabbox3d& box) const; + + //! Multiplies this matrix by a 1x4 matrix + void multiplyWith1x4Matrix(T* matrix) const; + + //! Calculates inverse of matrix. Slow. + //! \return Returns false if there is no inverse matrix. + bool makeInverse(); + + + //! Inverts a primitive matrix which only contains a translation and a rotation + //! \param out: where result matrix is written to. + bool getInversePrimitive ( CMatrix4& out ) const; + + //! returns the inversed matrix of this one + //! \param out: where result matrix is written to. + //! \return Returns false if there is no inverse matrix. + bool getInverse(CMatrix4& out) const; + + //! Builds a right-handed perspective projection matrix based on a field of view + void buildProjectionMatrixPerspectiveFovRH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar); + + //! Builds a left-handed perspective projection matrix based on a field of view + void buildProjectionMatrixPerspectiveFovLH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar); + + //! Builds a right-handed perspective projection matrix. + void buildProjectionMatrixPerspectiveRH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar); + + //! Builds a left-handed perspective projection matrix. + void buildProjectionMatrixPerspectiveLH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar); + + //! Builds a left-handed orthogonal projection matrix. + void buildProjectionMatrixOrthoLH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar); + + //! Builds a right-handed orthogonal projection matrix. + void buildProjectionMatrixOrthoRH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar); + + //! Builds a left-handed look-at matrix. + void buildCameraLookAtMatrixLH(const vector3df& position, const vector3df& target, const vector3df& upVector); + + //! Builds a right-handed look-at matrix. + void buildCameraLookAtMatrixRH(const vector3df& position, const vector3df& target, const vector3df& upVector); + + //! Builds a matrix that flattens geometry into a plane. + //! \param light: light source + //! \param plane: plane into which the geometry if flattened into + //! \param point: value between 0 and 1, describing the light source. + //! If this is 1, it is a point light, if it is 0, it is a directional light. + void buildShadowMatrix(const core::vector3df& light, core::plane3df plane, f32 point=1.0f); + + //! Builds a matrix which transforms a normalized Device Coordinate to Device Coordinates. + /** Used to scale <-1,-1><1,1> to viewport, for example from von <-1,-1> <1,1> to the viewport <0,0><0,640> */ + void buildNDCToDCMatrix( const core::rect& area, f32 zScale); + + //! creates a new matrix as interpolated matrix from two other ones. + //! \param b: other matrix to interpolate with + //! \param time: Must be a value between 0 and 1. + CMatrix4 interpolate(const core::CMatrix4& b, f32 time) const; + + //! returns transposed matrix + CMatrix4 getTransposed() const; + + //! returns transposed matrix to a plain 4x4 float matrix + inline void getTransposed( CMatrix4& dest ) const; + + /*! + construct 2D Texture transformations + rotate about center, scale, and transform. + */ + void setTextureScale( f32 sx, f32 sy ); + + void setTextureRotationCenter( f32 radAngle ); + void setTextureScaleCenter( f32 sx, f32 sy ); + + void setTextureTranslate( f32 x, f32 y ); + + void buildTextureTransform( f32 rotateRad, + const core::vector2df &rotatecenter, + const core::vector2df &translate, + const core::vector2df &scale); + + //! sets all matrix data members at once + void setM(const T* data); + + //! sets if the matrix is definitely identity matrix + void setDefinitelyIdentityMatrix( bool isDefinitelyIdentityMatrix); + + //! gets if the matrix is definitely identity matrix + bool getDefinitelyIdentityMatrix() const; + + private: + //! Matrix data, stored in row-major order + T M[16]; + mutable bool definitelyIdentityMatrix; + }; + + template + inline CMatrix4::CMatrix4( eConstructor constructor ) : definitelyIdentityMatrix(false) + { + switch ( constructor ) + { + case EM4CONST_NOTHING: + case EM4CONST_COPY: + break; + case EM4CONST_IDENTITY: + case EM4CONST_INVERSE: + default: + makeIdentity(); + break; + } + } + + template + inline CMatrix4::CMatrix4( const CMatrix4& other, eConstructor constructor) : definitelyIdentityMatrix(false) + { + switch ( constructor ) + { + case EM4CONST_IDENTITY: + makeIdentity(); + break; + case EM4CONST_NOTHING: + break; + case EM4CONST_COPY: + *this = other; + break; + case EM4CONST_TRANSPOSED: + other.getTransposed(*this); + break; + case EM4CONST_INVERSE: + if (!other.getInverse(*this)) + memset(M, 0, 16*sizeof(T)); + break; + case EM4CONST_INVERSE_TRANSPOSED: + if (!other.getInverse(*this)) + memset(M, 0, 16*sizeof(T)); + else + *this=getTransposed(); + break; + } + } + + //! Add another matrix. + template + inline CMatrix4 CMatrix4::operator+(const CMatrix4& other) const + { + CMatrix4 temp ( EM4CONST_NOTHING ); + + temp[0] = M[0]+other[0]; + temp[1] = M[1]+other[1]; + temp[2] = M[2]+other[2]; + temp[3] = M[3]+other[3]; + temp[4] = M[4]+other[4]; + temp[5] = M[5]+other[5]; + temp[6] = M[6]+other[6]; + temp[7] = M[7]+other[7]; + temp[8] = M[8]+other[8]; + temp[9] = M[9]+other[9]; + temp[10] = M[10]+other[10]; + temp[11] = M[11]+other[11]; + temp[12] = M[12]+other[12]; + temp[13] = M[13]+other[13]; + temp[14] = M[14]+other[14]; + temp[15] = M[15]+other[15]; + + return temp; + } + + //! Add another matrix. + template + inline CMatrix4& CMatrix4::operator+=(const CMatrix4& other) + { + M[0]+=other[0]; + M[1]+=other[1]; + M[2]+=other[2]; + M[3]+=other[3]; + M[4]+=other[4]; + M[5]+=other[5]; + M[6]+=other[6]; + M[7]+=other[7]; + M[8]+=other[8]; + M[9]+=other[9]; + M[10]+=other[10]; + M[11]+=other[11]; + M[12]+=other[12]; + M[13]+=other[13]; + M[14]+=other[14]; + M[15]+=other[15]; + + return *this; + } + + //! Subtract another matrix. + template + inline CMatrix4 CMatrix4::operator-(const CMatrix4& other) const + { + CMatrix4 temp ( EM4CONST_NOTHING ); + + temp[0] = M[0]-other[0]; + temp[1] = M[1]-other[1]; + temp[2] = M[2]-other[2]; + temp[3] = M[3]-other[3]; + temp[4] = M[4]-other[4]; + temp[5] = M[5]-other[5]; + temp[6] = M[6]-other[6]; + temp[7] = M[7]-other[7]; + temp[8] = M[8]-other[8]; + temp[9] = M[9]-other[9]; + temp[10] = M[10]-other[10]; + temp[11] = M[11]-other[11]; + temp[12] = M[12]-other[12]; + temp[13] = M[13]-other[13]; + temp[14] = M[14]-other[14]; + temp[15] = M[15]-other[15]; + + return temp; + } + + //! Subtract another matrix. + template + inline CMatrix4& CMatrix4::operator-=(const CMatrix4& other) + { + M[0]-=other[0]; + M[1]-=other[1]; + M[2]-=other[2]; + M[3]-=other[3]; + M[4]-=other[4]; + M[5]-=other[5]; + M[6]-=other[6]; + M[7]-=other[7]; + M[8]-=other[8]; + M[9]-=other[9]; + M[10]-=other[10]; + M[11]-=other[11]; + M[12]-=other[12]; + M[13]-=other[13]; + M[14]-=other[14]; + M[15]-=other[15]; + + return *this; + } + + //! Multiply by scalar. + template + inline CMatrix4 CMatrix4::operator*(const T& scalar) const + { + CMatrix4 temp ( EM4CONST_NOTHING ); + + temp[0] = M[0]*scalar; + temp[1] = M[1]*scalar; + temp[2] = M[2]*scalar; + temp[3] = M[3]*scalar; + temp[4] = M[4]*scalar; + temp[5] = M[5]*scalar; + temp[6] = M[6]*scalar; + temp[7] = M[7]*scalar; + temp[8] = M[8]*scalar; + temp[9] = M[9]*scalar; + temp[10] = M[10]*scalar; + temp[11] = M[11]*scalar; + temp[12] = M[12]*scalar; + temp[13] = M[13]*scalar; + temp[14] = M[14]*scalar; + temp[15] = M[15]*scalar; + + return temp; + } + + //! Multiply by scalar. + template + inline CMatrix4& CMatrix4::operator*=(const T& scalar) + { + M[0]*=scalar; + M[1]*=scalar; + M[2]*=scalar; + M[3]*=scalar; + M[4]*=scalar; + M[5]*=scalar; + M[6]*=scalar; + M[7]*=scalar; + M[8]*=scalar; + M[9]*=scalar; + M[10]*=scalar; + M[11]*=scalar; + M[12]*=scalar; + M[13]*=scalar; + M[14]*=scalar; + M[15]*=scalar; + + return *this; + } + + //! Multiply by another matrix. + template + inline CMatrix4& CMatrix4::operator*=(const CMatrix4& other) + { + // do chacks on your own in order to avoid copy creation + if ( !other.isIdentity() ) + { + if ( this->isIdentity() ) + { + *this = other; + } + else + { + CMatrix4 temp ( *this ); + setbyproduct_nocheck( temp, other ); + } + } + return *this; + } + + //! multiply by another matrix + // set this matrix to the product of two other matrices + // goal is to reduce stack use and copy + template + inline void CMatrix4::setbyproduct_nocheck(const CMatrix4& other_a,const CMatrix4& other_b ) + { + const T *m1 = other_a.M; + const T *m2 = other_b.M; + + M[0] = m1[0]*m2[0] + m1[4]*m2[1] + m1[8]*m2[2] + m1[12]*m2[3]; + M[1] = m1[1]*m2[0] + m1[5]*m2[1] + m1[9]*m2[2] + m1[13]*m2[3]; + M[2] = m1[2]*m2[0] + m1[6]*m2[1] + m1[10]*m2[2] + m1[14]*m2[3]; + M[3] = m1[3]*m2[0] + m1[7]*m2[1] + m1[11]*m2[2] + m1[15]*m2[3]; + + M[4] = m1[0]*m2[4] + m1[4]*m2[5] + m1[8]*m2[6] + m1[12]*m2[7]; + M[5] = m1[1]*m2[4] + m1[5]*m2[5] + m1[9]*m2[6] + m1[13]*m2[7]; + M[6] = m1[2]*m2[4] + m1[6]*m2[5] + m1[10]*m2[6] + m1[14]*m2[7]; + M[7] = m1[3]*m2[4] + m1[7]*m2[5] + m1[11]*m2[6] + m1[15]*m2[7]; + + M[8] = m1[0]*m2[8] + m1[4]*m2[9] + m1[8]*m2[10] + m1[12]*m2[11]; + M[9] = m1[1]*m2[8] + m1[5]*m2[9] + m1[9]*m2[10] + m1[13]*m2[11]; + M[10] = m1[2]*m2[8] + m1[6]*m2[9] + m1[10]*m2[10] + m1[14]*m2[11]; + M[11] = m1[3]*m2[8] + m1[7]*m2[9] + m1[11]*m2[10] + m1[15]*m2[11]; + + M[12] = m1[0]*m2[12] + m1[4]*m2[13] + m1[8]*m2[14] + m1[12]*m2[15]; + M[13] = m1[1]*m2[12] + m1[5]*m2[13] + m1[9]*m2[14] + m1[13]*m2[15]; + M[14] = m1[2]*m2[12] + m1[6]*m2[13] + m1[10]*m2[14] + m1[14]*m2[15]; + M[15] = m1[3]*m2[12] + m1[7]*m2[13] + m1[11]*m2[14] + m1[15]*m2[15]; + definitelyIdentityMatrix=false; + } + + + //! multiply by another matrix + // set this matrix to the product of two other matrices + // goal is to reduce stack use and copy + template + inline void CMatrix4::setbyproduct(const CMatrix4& other_a,const CMatrix4& other_b ) + { + if ( other_a.isIdentity () ) + { + *this = other_b; + return; + } + else + if ( other_b.isIdentity () ) + { + *this = other_a; + return; + } + setbyproduct_nocheck(other_a,other_b); + } + + //! multiply by another matrix + template + inline CMatrix4 CMatrix4::operator*(const CMatrix4& m2) const + { + // Testing purpose.. + if ( this->isIdentity() ) + return m2; + if ( m2.isIdentity() ) + return *this; + + CMatrix4 m3 ( EM4CONST_NOTHING ); + + const T *m1 = M; + + m3[0] = m1[0]*m2[0] + m1[4]*m2[1] + m1[8]*m2[2] + m1[12]*m2[3]; + m3[1] = m1[1]*m2[0] + m1[5]*m2[1] + m1[9]*m2[2] + m1[13]*m2[3]; + m3[2] = m1[2]*m2[0] + m1[6]*m2[1] + m1[10]*m2[2] + m1[14]*m2[3]; + m3[3] = m1[3]*m2[0] + m1[7]*m2[1] + m1[11]*m2[2] + m1[15]*m2[3]; + + m3[4] = m1[0]*m2[4] + m1[4]*m2[5] + m1[8]*m2[6] + m1[12]*m2[7]; + m3[5] = m1[1]*m2[4] + m1[5]*m2[5] + m1[9]*m2[6] + m1[13]*m2[7]; + m3[6] = m1[2]*m2[4] + m1[6]*m2[5] + m1[10]*m2[6] + m1[14]*m2[7]; + m3[7] = m1[3]*m2[4] + m1[7]*m2[5] + m1[11]*m2[6] + m1[15]*m2[7]; + + m3[8] = m1[0]*m2[8] + m1[4]*m2[9] + m1[8]*m2[10] + m1[12]*m2[11]; + m3[9] = m1[1]*m2[8] + m1[5]*m2[9] + m1[9]*m2[10] + m1[13]*m2[11]; + m3[10] = m1[2]*m2[8] + m1[6]*m2[9] + m1[10]*m2[10] + m1[14]*m2[11]; + m3[11] = m1[3]*m2[8] + m1[7]*m2[9] + m1[11]*m2[10] + m1[15]*m2[11]; + + m3[12] = m1[0]*m2[12] + m1[4]*m2[13] + m1[8]*m2[14] + m1[12]*m2[15]; + m3[13] = m1[1]*m2[12] + m1[5]*m2[13] + m1[9]*m2[14] + m1[13]*m2[15]; + m3[14] = m1[2]*m2[12] + m1[6]*m2[13] + m1[10]*m2[14] + m1[14]*m2[15]; + m3[15] = m1[3]*m2[12] + m1[7]*m2[13] + m1[11]*m2[14] + m1[15]*m2[15]; + return m3; + } + + + + template + inline vector3d CMatrix4::getTranslation() const + { + return vector3d(M[12], M[13], M[14]); + } + + + template + inline void CMatrix4::setTranslation( const vector3d& translation ) + { + M[12] = translation.X; + M[13] = translation.Y; + M[14] = translation.Z; + definitelyIdentityMatrix=false; + } + + template + inline void CMatrix4::setInverseTranslation( const vector3d& translation ) + { + M[12] = -translation.X; + M[13] = -translation.Y; + M[14] = -translation.Z; + definitelyIdentityMatrix=false; + } + + template + inline void CMatrix4::setScale( const vector3d& scale ) + { + M[0] = scale.X; + M[5] = scale.Y; + M[10] = scale.Z; + definitelyIdentityMatrix=false; + } + + template + inline vector3d CMatrix4::getScale() const + { + return vector3d(M[0],M[5],M[10]); + } + + template + inline void CMatrix4::setRotationDegrees( const vector3d& rotation ) + { + setRotationRadians( rotation * core::DEGTORAD ); + } + + template + inline void CMatrix4::setInverseRotationDegrees( const vector3d& rotation ) + { + setInverseRotationRadians( rotation * core::DEGTORAD ); + } + + template + inline void CMatrix4::setRotationRadians( const vector3d& rotation ) + { + f64 cr = cos( rotation.X ); + f64 sr = sin( rotation.X ); + f64 cp = cos( rotation.Y ); + f64 sp = sin( rotation.Y ); + f64 cy = cos( rotation.Z ); + f64 sy = sin( rotation.Z ); + + M[0] = (T)( cp*cy ); + M[1] = (T)( cp*sy ); + M[2] = (T)( -sp ); + + f64 srsp = sr*sp; + f64 crsp = cr*sp; + + M[4] = (T)( srsp*cy-cr*sy ); + M[5] = (T)( srsp*sy+cr*cy ); + M[6] = (T)( sr*cp ); + + M[8] = (T)( crsp*cy+sr*sy ); + M[9] = (T)( crsp*sy-sr*cy ); + M[10] = (T)( cr*cp ); + definitelyIdentityMatrix=false; + } + + + + //! Returns the rotation, as set by setRotation(). This code was sent + //! in by Chev. + template + inline core::vector3d CMatrix4::getRotationDegrees() const + { + const CMatrix4 &mat = *this; + + f64 Y = -asin(mat(0,2)); + f64 C = cos(Y); + Y *= RADTODEG64; + + f64 rotx, roty, X, Z; + + if (fabs(C)>0.0005f) + { + rotx = mat(2,2) / C; + roty = mat(1,2) / C; + X = atan2( roty, rotx ) * RADTODEG64; + rotx = mat(0,0) / C; + roty = mat(0,1) / C; + Z = atan2( roty, rotx ) * RADTODEG64; + } + else + { + X = 0.0; + rotx = mat(1,1); + roty = -mat(1,0); + Z = atan2( roty, rotx ) * RADTODEG64; + } + + // fix values that get below zero + // before it would set (!) values to 360 + // that where above 360: + if (X < 0.0) X += 360.0; + if (Y < 0.0) Y += 360.0; + if (Z < 0.0) Z += 360.0; + + return vector3d((f32)X,(f32)Y,(f32)Z); + } + + template + inline void CMatrix4::setInverseRotationRadians( const vector3d& rotation ) + { + f64 cr = cos( rotation.X ); + f64 sr = sin( rotation.X ); + f64 cp = cos( rotation.Y ); + f64 sp = sin( rotation.Y ); + f64 cy = cos( rotation.Z ); + f64 sy = sin( rotation.Z ); + + M[0] = (T)( cp*cy ); + M[4] = (T)( cp*sy ); + M[8] = (T)( -sp ); + + f64 srsp = sr*sp; + f64 crsp = cr*sp; + + M[1] = (T)( srsp*cy-cr*sy ); + M[5] = (T)( srsp*sy+cr*cy ); + M[9] = (T)( sr*cp ); + + M[2] = (T)( crsp*cy+sr*sy ); + M[6] = (T)( crsp*sy-sr*cy ); + M[10] = (T)( cr*cp ); + definitelyIdentityMatrix=false; + } + + + /*! + */ + template + inline void CMatrix4::makeIdentity() + { + memset(M, 0, 16*sizeof(T)); + M[0] = M[5] = M[10] = M[15] = (T)1; + definitelyIdentityMatrix=true; + } + + + /* + check identity with epsilon + solve floating range problems.. + */ + template + inline bool CMatrix4::isIdentity() const + { + if (definitelyIdentityMatrix) + return true; + if ( !equals ( M[ 0], (T)1 ) || + !equals ( M[ 5], (T)1 ) || + !equals ( M[10], (T)1 ) || + !equals ( M[15], (T)1 ) + ) + return false; + + for (s32 i=0; i<4; ++i) + for (s32 j=0; j<4; ++j) + if (j != i) + if (!iszero((*this)(i,j))) + return false; + + definitelyIdentityMatrix=true; + return true; + } + + /* + doesn't solve floating range problems.. + but takes care on +/- 0 on translation because we are changing it.. + reducing floating point branches + but it needs the floats in memory.. + */ + template + inline bool CMatrix4::isIdentity_integer_base() const + { + if (definitelyIdentityMatrix) + return true; + if(IR(M[0])!=F32_VALUE_1) return false; + if(IR(M[1])!=0) return false; + if(IR(M[2])!=0) return false; + if(IR(M[3])!=0) return false; + + if(IR(M[4])!=0) return false; + if(IR(M[5])!=F32_VALUE_1) return false; + if(IR(M[6])!=0) return false; + if(IR(M[7])!=0) return false; + + if(IR(M[8])!=0) return false; + if(IR(M[9])!=0) return false; + if(IR(M[10])!=F32_VALUE_1) return false; + if(IR(M[11])!=0) return false; + + if(IR(M[12])!=0) return false; + if(IR(M[13])!=0) return false; + if(IR(M[13])!=0) return false; + if(IR(M[15])!=F32_VALUE_1) return false; + definitelyIdentityMatrix=true; + return true; + } + + + + template + inline void CMatrix4::rotateVect( vector3df& vect ) const + { + vector3df tmp = vect; + vect.X = tmp.X*M[0] + tmp.Y*M[4] + tmp.Z*M[8]; + vect.Y = tmp.X*M[1] + tmp.Y*M[5] + tmp.Z*M[9]; + vect.Z = tmp.X*M[2] + tmp.Y*M[6] + tmp.Z*M[10]; + } + + //! An alternate transform vector method, writing into a second vector + template + inline void CMatrix4::rotateVect(core::vector3df& out, const core::vector3df& in) const + { + out.X = in.X*M[0] + in.Y*M[4] + in.Z*M[8]; + out.Y = in.X*M[1] + in.Y*M[5] + in.Z*M[9]; + out.Z = in.X*M[2] + in.Y*M[6] + in.Z*M[10]; + } + + //! An alternate transform vector method, writing into an array of 3 floats + template + inline void CMatrix4::rotateVect(T *out, const core::vector3df& in) const + { + out[0] = in.X*M[0] + in.Y*M[4] + in.Z*M[8]; + out[1] = in.X*M[1] + in.Y*M[5] + in.Z*M[9]; + out[2] = in.X*M[2] + in.Y*M[6] + in.Z*M[10]; + } + + template + inline void CMatrix4::inverseRotateVect( vector3df& vect ) const + { + vector3df tmp = vect; + vect.X = tmp.X*M[0] + tmp.Y*M[1] + tmp.Z*M[2]; + vect.Y = tmp.X*M[4] + tmp.Y*M[5] + tmp.Z*M[6]; + vect.Z = tmp.X*M[8] + tmp.Y*M[9] + tmp.Z*M[10]; + } + + template + inline void CMatrix4::transformVect( vector3df& vect) const + { + f32 vector[3]; + + vector[0] = vect.X*M[0] + vect.Y*M[4] + vect.Z*M[8] + M[12]; + vector[1] = vect.X*M[1] + vect.Y*M[5] + vect.Z*M[9] + M[13]; + vector[2] = vect.X*M[2] + vect.Y*M[6] + vect.Z*M[10] + M[14]; + + vect.X = vector[0]; + vect.Y = vector[1]; + vect.Z = vector[2]; + } + + template + inline void CMatrix4::transformVect( vector3df& out, const vector3df& in) const + { + out.X = in.X*M[0] + in.Y*M[4] + in.Z*M[8] + M[12]; + out.Y = in.X*M[1] + in.Y*M[5] + in.Z*M[9] + M[13]; + out.Z = in.X*M[2] + in.Y*M[6] + in.Z*M[10] + M[14]; + } + + + template + inline void CMatrix4::transformVect(T *out,const vector3df &in) const + { + out[0] = in.X*M[0] + in.Y*M[4] + in.Z*M[8] + M[12]; + out[1] = in.X*M[1] + in.Y*M[5] + in.Z*M[9] + M[13]; + out[2] = in.X*M[2] + in.Y*M[6] + in.Z*M[10] + M[14]; + out[3] = in.X*M[3] + in.Y*M[7] + in.Z*M[11] + M[15]; + } + + + //! Transforms a plane by this matrix + template + inline void CMatrix4::transformPlane( core::plane3d &plane) const + { + vector3df member; + transformVect(member, plane.getMemberPoint()); + + vector3df origin(0,0,0); + transformVect(plane.Normal); + transformVect(origin); + + plane.Normal -= origin; + plane.D = - member.dotProduct(plane.Normal); + } + + //! Transforms a plane by this matrix + template + inline void CMatrix4::transformPlane_new( core::plane3d &plane) const + { + // rotate normal -> rotateVect ( plane.n ); + vector3df n; + n.X = plane.Normal.X*M[0] + plane.Normal.Y*M[4] + plane.Normal.Z*M[8]; + n.Y = plane.Normal.X*M[1] + plane.Normal.Y*M[5] + plane.Normal.Z*M[9]; + n.Z = plane.Normal.X*M[2] + plane.Normal.Y*M[6] + plane.Normal.Z*M[10]; + + // compute new d. -> getTranslation(). dotproduct ( plane.n ) + plane.D -= M[12] * n.X + M[13] * n.Y + M[14] * n.Z; + plane.Normal.X = n.X; + plane.Normal.Y = n.Y; + plane.Normal.Z = n.Z; + } + + //! Transforms a plane by this matrix + template + inline void CMatrix4::transformPlane( const core::plane3d &in, core::plane3d &out) const + { + out = in; + transformPlane( out ); + } + + //! Transforms a axis aligned bounding box + template + inline void CMatrix4::transformBox(core::aabbox3d& box) const + { + if (isIdentity() ) + return; + + transformVect(box.MinEdge); + transformVect(box.MaxEdge); + box.repair(); + } + + //! Transforms a axis aligned bounding box more accurately than transformBox() + template + inline void CMatrix4::transformBoxEx(core::aabbox3d& box) const + { + f32 Amin[3]; + f32 Amax[3]; + f32 Bmin[3]; + f32 Bmax[3]; + + Amin[0] = box.MinEdge.X; + Amin[1] = box.MinEdge.Y; + Amin[2] = box.MinEdge.Z; + + Amax[0] = box.MaxEdge.X; + Amax[1] = box.MaxEdge.Y; + Amax[2] = box.MaxEdge.Z; + + Bmin[0] = Bmax[0] = M[12]; + Bmin[1] = Bmax[1] = M[13]; + Bmin[2] = Bmax[2] = M[14]; + + u32 i, j; + const CMatrix4 &m = *this; + + for (i = 0; i < 3; ++i) + { + for (j = 0; j < 3; ++j) + { + f32 a = m(j,i) * Amin[j]; + f32 b = m(j,i) * Amax[j]; + + if (a < b) + { + Bmin[i] += a; + Bmax[i] += b; + } + else + { + Bmin[i] += b; + Bmax[i] += a; + } + } + } + + box.MinEdge.X = Bmin[0]; + box.MinEdge.Y = Bmin[1]; + box.MinEdge.Z = Bmin[2]; + + box.MaxEdge.X = Bmax[0]; + box.MaxEdge.Y = Bmax[1]; + box.MaxEdge.Z = Bmax[2]; + } + + + //! Multiplies this matrix by a 1x4 matrix + template + inline void CMatrix4::multiplyWith1x4Matrix(T* matrix) const + { + /* + 0 1 2 3 + 4 5 6 7 + 8 9 10 11 + 12 13 14 15 + */ + + T mat[4]; + mat[0] = matrix[0]; + mat[1] = matrix[1]; + mat[2] = matrix[2]; + mat[3] = matrix[3]; + + matrix[0] = M[0]*mat[0] + M[4]*mat[1] + M[8]*mat[2] + M[12]*mat[3]; + matrix[1] = M[1]*mat[0] + M[5]*mat[1] + M[9]*mat[2] + M[13]*mat[3]; + matrix[2] = M[2]*mat[0] + M[6]*mat[1] + M[10]*mat[2] + M[14]*mat[3]; + matrix[3] = M[3]*mat[0] + M[7]*mat[1] + M[11]*mat[2] + M[15]*mat[3]; + } + + template + inline void CMatrix4::inverseTranslateVect( vector3df& vect ) const + { + vect.X = vect.X-M[12]; + vect.Y = vect.Y-M[13]; + vect.Z = vect.Z-M[14]; + } + + template + inline void CMatrix4::translateVect( vector3df& vect ) const + { + vect.X = vect.X+M[12]; + vect.Y = vect.Y+M[13]; + vect.Z = vect.Z+M[14]; + } + + + template + inline bool CMatrix4::getInverse(CMatrix4& out) const + { + /// Calculates the inverse of this Matrix + /// The inverse is calculated using Cramers rule. + /// If no inverse exists then 'false' is returned. + + if ( this->isIdentity() ) + { + out=*this; + return true; + } + + const CMatrix4 &m = *this; + + f32 d = (m(0, 0) * m(1, 1) - m(0, 1) * m(1, 0)) * (m(2, 2) * m(3, 3) - m(2, 3) * m(3, 2)) - + (m(0, 0) * m(1, 2) - m(0, 2) * m(1, 0)) * (m(2, 1) * m(3, 3) - m(2, 3) * m(3, 1)) + + (m(0, 0) * m(1, 3) - m(0, 3) * m(1, 0)) * (m(2, 1) * m(3, 2) - m(2, 2) * m(3, 1)) + + (m(0, 1) * m(1, 2) - m(0, 2) * m(1, 1)) * (m(2, 0) * m(3, 3) - m(2, 3) * m(3, 0)) - + (m(0, 1) * m(1, 3) - m(0, 3) * m(1, 1)) * (m(2, 0) * m(3, 2) - m(2, 2) * m(3, 0)) + + (m(0, 2) * m(1, 3) - m(0, 3) * m(1, 2)) * (m(2, 0) * m(3, 1) - m(2, 1) * m(3, 0)); + + if( core::iszero ( d ) ) + return false; + + d = core::reciprocal ( d ); + + out(0, 0) = d * (m(1, 1) * (m(2, 2) * m(3, 3) - m(2, 3) * m(3, 2)) + m(1, 2) * (m(2, 3) * m(3, 1) - m(2, 1) * m(3, 3)) + m(1, 3) * (m(2, 1) * m(3, 2) - m(2, 2) * m(3, 1))); + out(0, 1) = d * (m(2, 1) * (m(0, 2) * m(3, 3) - m(0, 3) * m(3, 2)) + m(2, 2) * (m(0, 3) * m(3, 1) - m(0, 1) * m(3, 3)) + m(2, 3) * (m(0, 1) * m(3, 2) - m(0, 2) * m(3, 1))); + out(0, 2) = d * (m(3, 1) * (m(0, 2) * m(1, 3) - m(0, 3) * m(1, 2)) + m(3, 2) * (m(0, 3) * m(1, 1) - m(0, 1) * m(1, 3)) + m(3, 3) * (m(0, 1) * m(1, 2) - m(0, 2) * m(1, 1))); + out(0, 3) = d * (m(0, 1) * (m(1, 3) * m(2, 2) - m(1, 2) * m(2, 3)) + m(0, 2) * (m(1, 1) * m(2, 3) - m(1, 3) * m(2, 1)) + m(0, 3) * (m(1, 2) * m(2, 1) - m(1, 1) * m(2, 2))); + out(1, 0) = d * (m(1, 2) * (m(2, 0) * m(3, 3) - m(2, 3) * m(3, 0)) + m(1, 3) * (m(2, 2) * m(3, 0) - m(2, 0) * m(3, 2)) + m(1, 0) * (m(2, 3) * m(3, 2) - m(2, 2) * m(3, 3))); + out(1, 1) = d * (m(2, 2) * (m(0, 0) * m(3, 3) - m(0, 3) * m(3, 0)) + m(2, 3) * (m(0, 2) * m(3, 0) - m(0, 0) * m(3, 2)) + m(2, 0) * (m(0, 3) * m(3, 2) - m(0, 2) * m(3, 3))); + out(1, 2) = d * (m(3, 2) * (m(0, 0) * m(1, 3) - m(0, 3) * m(1, 0)) + m(3, 3) * (m(0, 2) * m(1, 0) - m(0, 0) * m(1, 2)) + m(3, 0) * (m(0, 3) * m(1, 2) - m(0, 2) * m(1, 3))); + out(1, 3) = d * (m(0, 2) * (m(1, 3) * m(2, 0) - m(1, 0) * m(2, 3)) + m(0, 3) * (m(1, 0) * m(2, 2) - m(1, 2) * m(2, 0)) + m(0, 0) * (m(1, 2) * m(2, 3) - m(1, 3) * m(2, 2))); + out(2, 0) = d * (m(1, 3) * (m(2, 0) * m(3, 1) - m(2, 1) * m(3, 0)) + m(1, 0) * (m(2, 1) * m(3, 3) - m(2, 3) * m(3, 1)) + m(1, 1) * (m(2, 3) * m(3, 0) - m(2, 0) * m(3, 3))); + out(2, 1) = d * (m(2, 3) * (m(0, 0) * m(3, 1) - m(0, 1) * m(3, 0)) + m(2, 0) * (m(0, 1) * m(3, 3) - m(0, 3) * m(3, 1)) + m(2, 1) * (m(0, 3) * m(3, 0) - m(0, 0) * m(3, 3))); + out(2, 2) = d * (m(3, 3) * (m(0, 0) * m(1, 1) - m(0, 1) * m(1, 0)) + m(3, 0) * (m(0, 1) * m(1, 3) - m(0, 3) * m(1, 1)) + m(3, 1) * (m(0, 3) * m(1, 0) - m(0, 0) * m(1, 3))); + out(2, 3) = d * (m(0, 3) * (m(1, 1) * m(2, 0) - m(1, 0) * m(2, 1)) + m(0, 0) * (m(1, 3) * m(2, 1) - m(1, 1) * m(2, 3)) + m(0, 1) * (m(1, 0) * m(2, 3) - m(1, 3) * m(2, 0))); + out(3, 0) = d * (m(1, 0) * (m(2, 2) * m(3, 1) - m(2, 1) * m(3, 2)) + m(1, 1) * (m(2, 0) * m(3, 2) - m(2, 2) * m(3, 0)) + m(1, 2) * (m(2, 1) * m(3, 0) - m(2, 0) * m(3, 1))); + out(3, 1) = d * (m(2, 0) * (m(0, 2) * m(3, 1) - m(0, 1) * m(3, 2)) + m(2, 1) * (m(0, 0) * m(3, 2) - m(0, 2) * m(3, 0)) + m(2, 2) * (m(0, 1) * m(3, 0) - m(0, 0) * m(3, 1))); + out(3, 2) = d * (m(3, 0) * (m(0, 2) * m(1, 1) - m(0, 1) * m(1, 2)) + m(3, 1) * (m(0, 0) * m(1, 2) - m(0, 2) * m(1, 0)) + m(3, 2) * (m(0, 1) * m(1, 0) - m(0, 0) * m(1, 1))); + out(3, 3) = d * (m(0, 0) * (m(1, 1) * m(2, 2) - m(1, 2) * m(2, 1)) + m(0, 1) * (m(1, 2) * m(2, 0) - m(1, 0) * m(2, 2)) + m(0, 2) * (m(1, 0) * m(2, 1) - m(1, 1) * m(2, 0))); + out.definitelyIdentityMatrix = definitelyIdentityMatrix; + return true; + } + + + //! Inverts a primitive matrix which only contains a translation and a rotation + //! \param out: where result matrix is written to. + template + inline bool CMatrix4::getInversePrimitive ( CMatrix4& out ) const + { + out.M[0 ] = M[0]; + out.M[1 ] = M[4]; + out.M[2 ] = M[8]; + out.M[3 ] = 0; + + out.M[4 ] = M[1]; + out.M[5 ] = M[5]; + out.M[6 ] = M[9]; + out.M[7 ] = 0; + + out.M[8 ] = M[2]; + out.M[9 ] = M[6]; + out.M[10] = M[10]; + out.M[11] = 0; + + out.M[12] = (T)-(M[12]*M[0] + M[13]*M[1] + M[14]*M[2]); + out.M[13] = (T)-(M[12]*M[4] + M[13]*M[5] + M[14]*M[6]); + out.M[14] = (T)-(M[12]*M[8] + M[13]*M[9] + M[14]*M[10]); + out.M[15] = 1; + out.definitelyIdentityMatrix = definitelyIdentityMatrix; + return true; + } + + /*! + */ + template + inline bool CMatrix4::makeInverse() + { + if (definitelyIdentityMatrix) + return true; + + CMatrix4 temp ( EM4CONST_NOTHING ); + + if (getInverse(temp)) + { + *this = temp; + return true; + } + + return false; + } + + + + template + inline CMatrix4& CMatrix4::operator=(const CMatrix4 &other) + { + if (this==&other) + return *this; + memcpy(M, other.M, 16*sizeof(T)); + definitelyIdentityMatrix=other.definitelyIdentityMatrix; + return *this; + } + + + + template + inline CMatrix4& CMatrix4::operator=(const T& scalar) + { + for (s32 i = 0; i < 16; ++i) + M[i]=scalar; + definitelyIdentityMatrix=false; + return *this; + } + + + + template + inline bool CMatrix4::operator==(const CMatrix4 &other) const + { + if (definitelyIdentityMatrix && other.definitelyIdentityMatrix) + return true; + for (s32 i = 0; i < 16; ++i) + if (M[i] != other.M[i]) + return false; + + return true; + } + + + + template + inline bool CMatrix4::operator!=(const CMatrix4 &other) const + { + return !(*this == other); + } + + + + //! Builds a right-handed perspective projection matrix based on a field of view + template + inline void CMatrix4::buildProjectionMatrixPerspectiveFovRH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar) + { + f64 h = 1.0/tan(fieldOfViewRadians/2.0); + T w = h / aspectRatio; + + M[0] = w; + M[1] = 0; + M[2] = 0; + M[3] = 0; + + M[4] = 0; + M[5] = (T)h; + M[6] = 0; + M[7] = 0; + + M[8] = 0; + M[9] = 0; + M[10] = (T)(zFar/(zNear-zFar)); // DirectX version +// M[10] = (T)(zFar+zNear/(zNear-zFar)); // OpenGL version + M[11] = -1; + + M[12] = 0; + M[13] = 0; + M[14] = (T)(zNear*zFar/(zNear-zFar)); // DirectX version +// M[14] = (T)(2.0f*zNear*zFar/(zNear-zFar)); // OpenGL version + M[15] = 0; + definitelyIdentityMatrix=false; + } + + + + //! Builds a left-handed perspective projection matrix based on a field of view + template + inline void CMatrix4::buildProjectionMatrixPerspectiveFovLH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar) + { + f64 h = 1.0/tan(fieldOfViewRadians/2.0); + T w = (T)(h / aspectRatio); + + M[0] = w; + M[1] = 0; + M[2] = 0; + M[3] = 0; + + M[4] = 0; + M[5] = (T)h; + M[6] = 0; + M[7] = 0; + + M[8] = 0; + M[9] = 0; + M[10] = (T)(zFar/(zFar-zNear)); + M[11] = 1; + + M[12] = 0; + M[13] = 0; + M[14] = (T)(-zNear*zFar/(zFar-zNear)); + M[15] = 0; + definitelyIdentityMatrix=false; + } + + + + //! Builds a left-handed orthogonal projection matrix. + template + inline void CMatrix4::buildProjectionMatrixOrthoLH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar) + { + M[0] = (T)(2/widthOfViewVolume); + M[1] = 0; + M[2] = 0; + M[3] = 0; + + M[4] = 0; + M[5] = (T)(2/heightOfViewVolume); + M[6] = 0; + M[7] = 0; + + M[8] = 0; + M[9] = 0; + M[10] = (T)(1/(zFar-zNear)); + M[11] = 0; + + M[12] = 0; + M[13] = 0; + M[14] = (T)(zNear/(zNear-zFar)); + M[15] = 1; + definitelyIdentityMatrix=false; + } + + + + //! Builds a right-handed orthogonal projection matrix. + template + inline void CMatrix4::buildProjectionMatrixOrthoRH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar) + { + M[0] = (T)(2/widthOfViewVolume); + M[1] = 0; + M[2] = 0; + M[3] = 0; + + M[4] = 0; + M[5] = (T)(2/heightOfViewVolume); + M[6] = 0; + M[7] = 0; + + M[8] = 0; + M[9] = 0; + M[10] = (T)(1/(zNear-zFar)); + M[11] = 0; + + M[12] = 0; + M[13] = 0; + M[14] = (T)(zNear/(zNear-zFar)); + M[15] = -1; + definitelyIdentityMatrix=false; + } + + + //! Builds a right-handed perspective projection matrix. + template + inline void CMatrix4::buildProjectionMatrixPerspectiveRH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar) + { + M[0] = (T)(2*zNear/widthOfViewVolume); + M[1] = 0; + M[2] = 0; + M[3] = 0; + + M[4] = 0; + M[5] = (T)(2*zNear/heightOfViewVolume); + M[6] = 0; + M[7] = 0; + + M[8] = 0; + M[9] = 0; + M[10] = (T)(zFar/(zNear-zFar)); + M[11] = -1; + + M[12] = 0; + M[13] = 0; + M[14] = (T)(zNear*zFar/(zNear-zFar)); + M[15] = 0; + definitelyIdentityMatrix=false; + } + + + //! Builds a left-handed perspective projection matrix. + template + inline void CMatrix4::buildProjectionMatrixPerspectiveLH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar) + { + M[0] = (T)(2*zNear/widthOfViewVolume); + M[1] = 0; + M[2] = 0; + M[3] = 0; + + M[4] = 0; + M[5] = (T)(2*zNear/heightOfViewVolume); + M[6] = 0; + M[7] = 0; + + M[8] = 0; + M[9] = 0; + M[10] = (T)(zFar/(zFar-zNear)); + M[11] = 1; + + M[12] = 0; + M[13] = 0; + M[14] = (T)(zNear*zFar/(zNear-zFar)); + M[15] = 0; + definitelyIdentityMatrix=false; + } + + + //! Builds a matrix that flattens geometry into a plane. + template + inline void CMatrix4::buildShadowMatrix(const core::vector3df& light, core::plane3df plane, f32 point) + { + plane.Normal.normalize(); + f32 d = plane.Normal.dotProduct(light); + + M[ 0] = (T)(-plane.Normal.X * light.X + d); + M[ 1] = (T)(-plane.Normal.X * light.Y); + M[ 2] = (T)(-plane.Normal.X * light.Z); + M[ 3] = (T)(-plane.Normal.X * point); + + M[ 4] = (T)(-plane.Normal.Y * light.X); + M[ 5] = (T)(-plane.Normal.Y * light.Y + d); + M[ 6] = (T)(-plane.Normal.Y * light.Z); + M[ 7] = (T)(-plane.Normal.Y * point); + + M[ 8] = (T)(-plane.Normal.Z * light.X); + M[ 9] = (T)(-plane.Normal.Z * light.Y); + M[10] = (T)(-plane.Normal.Z * light.Z + d); + M[11] = (T)(-plane.Normal.Z * point); + + M[12] = (T)(-plane.D * light.X); + M[13] = (T)(-plane.D * light.Y); + M[14] = (T)(-plane.D * light.Z); + M[15] = (T)(-plane.D * point + d); + definitelyIdentityMatrix=false; + } + + //! Builds a left-handed look-at matrix. + template + inline void CMatrix4::buildCameraLookAtMatrixLH( + const vector3df& position, + const vector3df& target, + const vector3df& upVector) + { + vector3df zaxis = target - position; + zaxis.normalize(); + + vector3df xaxis = upVector.crossProduct(zaxis); + xaxis.normalize(); + + vector3df yaxis = zaxis.crossProduct(xaxis); + + M[0] = (T)xaxis.X; + M[1] = (T)yaxis.X; + M[2] = (T)zaxis.X; + M[3] = 0; + + M[4] = (T)xaxis.Y; + M[5] = (T)yaxis.Y; + M[6] = (T)zaxis.Y; + M[7] = 0; + + M[8] = (T)xaxis.Z; + M[9] = (T)yaxis.Z; + M[10] = (T)zaxis.Z; + M[11] = 0; + + M[12] = (T)-xaxis.dotProduct(position); + M[13] = (T)-yaxis.dotProduct(position); + M[14] = (T)-zaxis.dotProduct(position); + M[15] = 1; + definitelyIdentityMatrix=false; + } + + + + //! Builds a right-handed look-at matrix. + template + inline void CMatrix4::buildCameraLookAtMatrixRH( + const vector3df& position, + const vector3df& target, + const vector3df& upVector) + { + vector3df zaxis = position - target; + zaxis.normalize(); + + vector3df xaxis = upVector.crossProduct(zaxis); + xaxis.normalize(); + + vector3df yaxis = zaxis.crossProduct(xaxis); + + M[0] = (T)xaxis.X; + M[1] = (T)yaxis.X; + M[2] = (T)zaxis.X; + M[3] = 0; + + M[4] = (T)xaxis.Y; + M[5] = (T)yaxis.Y; + M[6] = (T)zaxis.Y; + M[7] = 0; + + M[8] = (T)xaxis.Z; + M[9] = (T)yaxis.Z; + M[10] = (T)zaxis.Z; + M[11] = 0; + + M[12] = (T)-xaxis.dotProduct(position); + M[13] = (T)-yaxis.dotProduct(position); + M[14] = (T)-zaxis.dotProduct(position); + M[15] = 1; + definitelyIdentityMatrix=false; + } + + + //! creates a new matrix as interpolated matrix from to other ones. + //! \param time: Must be a value between 0 and 1. + template + inline CMatrix4 CMatrix4::interpolate(const core::CMatrix4& b, f32 time) const + { + CMatrix4 mat ( EM4CONST_NOTHING ); + + for (u32 i=0; i < 16; i += 4) + { + mat.M[i+0] = (T)(M[i+0] + ( b.M[i+0] - M[i+0] ) * time); + mat.M[i+1] = (T)(M[i+1] + ( b.M[i+1] - M[i+1] ) * time); + mat.M[i+2] = (T)(M[i+2] + ( b.M[i+2] - M[i+2] ) * time); + mat.M[i+3] = (T)(M[i+3] + ( b.M[i+3] - M[i+3] ) * time); + } + return mat; + } + + //! returns transposed matrix + template + inline CMatrix4 CMatrix4::getTransposed() const + { + CMatrix4 t ( EM4CONST_NOTHING ); + getTransposed ( t ); + return t; + } + + //! returns transposed matrix + template + inline void CMatrix4::getTransposed( CMatrix4& o ) const + { + o[ 0] = M[ 0]; + o[ 1] = M[ 4]; + o[ 2] = M[ 8]; + o[ 3] = M[12]; + + o[ 4] = M[ 1]; + o[ 5] = M[ 5]; + o[ 6] = M[ 9]; + o[ 7] = M[13]; + + o[ 8] = M[ 2]; + o[ 9] = M[ 6]; + o[10] = M[10]; + o[11] = M[14]; + + o[12] = M[ 3]; + o[13] = M[ 7]; + o[14] = M[11]; + o[15] = M[15]; + o.definitelyIdentityMatrix=definitelyIdentityMatrix; + } + + + // used to scale <-1,-1><1,1> to viewport + template + inline void CMatrix4::buildNDCToDCMatrix( const core::rect& viewport, f32 zScale) + { + f32 scaleX = (viewport.getWidth() - 0.75f ) / 2.0f; + f32 scaleY = -(viewport.getHeight() - 0.75f ) / 2.0f; + + f32 dx = -0.5f + ( (viewport.UpperLeftCorner.X + viewport.LowerRightCorner.X ) / 2.0f ); + f32 dy = -0.5f + ( (viewport.UpperLeftCorner.Y + viewport.LowerRightCorner.Y ) / 2.0f ); + + makeIdentity(); + M[0] = (T)scaleX; + M[5] = (T)scaleY; + M[10] = (T)zScale; + M[12] = (T)dx; + M[13] = (T)dy; + definitelyIdentityMatrix=false; + } + + /*! + Generate texture coordinates as linear functions so that: + u = Ux*x + Uy*y + Uz*z + Uw + v = Vx*x + Vy*y + Vz*z + Vw + The matrix M for this case is: + Ux Vx 0 0 + Uy Vy 0 0 + Uz Vz 0 0 + Uw Vw 0 0 + */ + + template + inline void CMatrix4::buildTextureTransform( f32 rotateRad, + const core::vector2df &rotatecenter, + const core::vector2df &translate, + const core::vector2df &scale) + { + const f32 c = cosf(rotateRad); + const f32 s = sinf(rotateRad); + + M[0] = (T)(c * scale.X); + M[1] = (T)(s * scale.Y); + M[2] = 0; + M[3] = 0; + + M[4] = (T)(-s * scale.X); + M[5] = (T)(c * scale.Y); + M[6] = 0; + M[7] = 0; + + M[8] = (T)(c * scale.X * rotatecenter.X + -s * rotatecenter.Y + translate.X); + M[9] = (T)(s * scale.Y * rotatecenter.X + c * rotatecenter.Y + translate.Y); + M[10] = 1; + M[11] = 0; + + M[12] = 0; + M[13] = 0; + M[14] = 0; + M[15] = 1; + definitelyIdentityMatrix=false; + } + + //! rotate about z axis, center ( 0.5, 0.5 ) + template + inline void CMatrix4::setTextureRotationCenter( f32 rotateRad ) + { + const f32 c = cosf(rotateRad); + const f32 s = sinf(rotateRad); + M[0] = (T)c; + M[1] = (T)s; + M[2] = (T)(-0.5f * ( c + s) + 0.5f); + + M[4] = (T)-s; + M[5] = (T)c; + M[6] = (T)(-0.5f * (-s + c) + 0.5f); + definitelyIdentityMatrix=false; + } + + template + inline void CMatrix4::setTextureTranslate ( f32 x, f32 y ) + { + M[8] = (T)x; + M[9] = (T)y; + definitelyIdentityMatrix = definitelyIdentityMatrix && (x==0.0f) && (y==0.0f) ; + } + + template + inline void CMatrix4::setTextureScale ( f32 sx, f32 sy ) + { + M[0] = (T)sx; + M[5] = (T)sy; + definitelyIdentityMatrix = definitelyIdentityMatrix && (sx==1.0f) && (sy==1.0f) ; + } + + template + inline void CMatrix4::setTextureScaleCenter( f32 sx, f32 sy ) + { + M[0] = (T)sx; + M[2] = (T)(-0.5f * sx + 0.5f); + M[5] = (T)sy; + M[6] = (T)(-0.5f * sy + 0.5f); + definitelyIdentityMatrix = definitelyIdentityMatrix && (sx==1.0f) && (sy==1.0f) ; + } + + //! sets all matrix data members at once + template + inline void CMatrix4::setM(const T* data) + { + for (u32 i = 0; i < 16; ++i) + M[i] = data[i]; + + definitelyIdentityMatrix = false; + } + + //! sets if the matrix is definitely identity matrix + template + inline void CMatrix4::setDefinitelyIdentityMatrix( bool isDefinitelyIdentityMatrix) + { + definitelyIdentityMatrix = isDefinitelyIdentityMatrix; + } + + //! gets if the matrix is definitely identity matrix + template + inline bool CMatrix4::getDefinitelyIdentityMatrix() const + { + return definitelyIdentityMatrix; + } + + //! Multiply by scalar. + template + inline CMatrix4 operator*(const T scalar, const CMatrix4& mat) + { + return mat*scalar; + } + + typedef CMatrix4 matrix4; + const matrix4 IdentityMatrix(matrix4::EM4CONST_IDENTITY); + +} // end namespace core +} // end namespace irr + +#endif + diff --git a/engine/include/support/plane3d.h b/engine/include/support/plane3d.h new file mode 100644 index 0000000..d4d9526 --- /dev/null +++ b/engine/include/support/plane3d.h @@ -0,0 +1,224 @@ +// Copyright (C) 2002-2007 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_PLANE_3D_H_INCLUDED__ +#define __IRR_PLANE_3D_H_INCLUDED__ + +#include "irrMath.h" +#include "vector3d.h" + +namespace irr +{ +namespace core +{ + +//! Enumeration for intersection relations of 3d objects +enum EIntersectionRelation3D +{ + ISREL3D_FRONT = 0, + ISREL3D_BACK, + ISREL3D_PLANAR, + ISREL3D_SPANNING, + ISREL3D_CLIPPED +}; + +//! Template plane class with some intersection testing methods. +template +class plane3d +{ + public: + + // Constructors + + plane3d(): Normal(0,1,0) { recalculateD(vector3d(0,0,0)); } + plane3d(const vector3d& MPoint, const vector3d& Normal) : Normal(Normal) { recalculateD(MPoint); } + plane3d(T px, T py, T pz, T nx, T ny, T nz) : Normal(nx, ny, nz) { recalculateD(vector3d(px, py, pz)); } + plane3d(const vector3d& point1, const vector3d& point2, const vector3d& point3) { setPlane(point1, point2, point3); } + + // operators + + inline bool operator==(const plane3d& other) const { return (D==other.D && Normal==other.Normal);} + inline bool operator!=(const plane3d& other) const { return !(D==other.D && Normal==other.Normal);} + + // functions + + void setPlane(const vector3d& point, const vector3d& nvector) + { + Normal = nvector; + recalculateD(point); + } + + void setPlane(const vector3d& nvect, T d) + { + Normal = nvect; + D = d; + } + + void setPlane(const vector3d& point1, const vector3d& point2, const vector3d& point3) + { + // creates the plane from 3 memberpoints + Normal = (point2 - point1).crossProduct(point3 - point1); + Normal.normalize(); + + recalculateD(point1); + } + + + //! Returns an intersection with a 3d line. + //! \param lineVect: Vector of the line to intersect with. + //! \param linePoint: Point of the line to intersect with. + //! \param outIntersection: Place to store the intersection point, if there is one. + //! \return Returns true if there was an intersection, false if there was not. + bool getIntersectionWithLine(const vector3d& linePoint, const vector3d& lineVect, + vector3d& outIntersection) const + { + T t2 = Normal.dotProduct(lineVect); + + if (t2 == 0) + return false; + + T t =- (Normal.dotProduct(linePoint) + D) / t2; + outIntersection = linePoint + (lineVect * t); + return true; + } + + //! Returns where on a line between two points an intersection with this plane happened. + //! Only useful if known that there is an intersection. + //! \param linePoint1: Point1 of the line to intersect with. + //! \param linePoint2: Point2 of the line to intersect with. + //! \return Returns where on a line between two points an intersection with this plane happened. + //! For example, 0.5 is returned if the intersection happened exectly in the middle of the two points. + f32 getKnownIntersectionWithLine(const vector3d& linePoint1, + const vector3d& linePoint2) const + { + vector3d vect = linePoint2 - linePoint1; + T t2 = (f32)Normal.dotProduct(vect); + return (f32)-((Normal.dotProduct(linePoint1) + D) / t2); + } + + //! Returns an intersection with a 3d line, limited between two 3d points. + //! \param linePoint1: Point 1 of the line. + //! \param linePoint2: Point 2 of the line. + //! \param outIntersection: Place to store the intersection point, if there is one. + //! \return Returns true if there was an intersection, false if there was not. + bool getIntersectionWithLimitedLine( + const vector3d& linePoint1, + const vector3d& linePoint2, + vector3d& outIntersection) const + { + return (getIntersectionWithLine(linePoint1, linePoint2 - linePoint1, outIntersection) && + outIntersection.isBetweenPoints(linePoint1, linePoint2)); + } + + //! Classifies the relation of a point to this plane. + //! \param point: Point to classify its relation. + //! \return Returns ISREL3D_FRONT if the point is in front of the plane, + //! ISREL3D_BACK if the point is behind of the plane, and + //! ISREL3D_PLANAR if the point is within the plane. + EIntersectionRelation3D classifyPointRelation(const vector3d& point) const + { + const T d = Normal.dotProduct(point) + D; + + if (d < -ROUNDING_ERROR_32) + return ISREL3D_BACK; + + if (d > ROUNDING_ERROR_32) + return ISREL3D_FRONT; + + return ISREL3D_PLANAR; + } + + //! Recalculates the distance from origin by applying + //! a new member point to the plane. + void recalculateD(const vector3d& MPoint) + { + D = - MPoint.dotProduct(Normal); + } + + //! Returns a member point of the plane. + vector3d getMemberPoint() const + { + return Normal * -D; + } + + //! Tests if there is an intersection between with the other plane + //! \return Returns true if there is a intersection. + bool existsIntersection(const plane3d& other) const + { + vector3d cross = other.Normal.crossProduct(Normal); + return cross.getLength() > core::ROUNDING_ERROR_32; + } + + //! Intersects this plane with another. + //! \return Returns true if there is a intersection, false if not. + bool getIntersectionWithPlane(const plane3d& other, vector3d& outLinePoint, + vector3d& outLineVect) const + { + T fn00 = Normal.getLength(); + T fn01 = Normal.dotProduct(other.Normal); + T fn11 = other.Normal.getLength(); + f64 det = fn00*fn11 - fn01*fn01; + + if (fabs(det) < ROUNDING_ERROR_64 ) + return false; + + det = 1.0 / det; + f64 fc0 = (fn11*-D + fn01*other.D) * det; + f64 fc1 = (fn00*-other.D + fn01*D) * det; + + outLineVect = Normal.crossProduct(other.Normal); + outLinePoint = Normal*(T)fc0 + other.Normal*(T)fc1; + return true; + } + + //! Returns the intersection point with two other planes if there is one. + bool getIntersectionWithPlanes(const plane3d& o1, + const plane3d& o2, vector3d& outPoint) const + { + vector3d linePoint, lineVect; + if (getIntersectionWithPlane(o1, linePoint, lineVect)) + return o2.getIntersectionWithLine(linePoint, lineVect, outPoint); + + return false; + } + + //! Test if the triangle would be front or backfacing from any + //! point. Thus, this method assumes a camera position from + //! which the triangle is definitely visible when looking into + //! the given direction. + //! Note that this only works if the normal is Normalized. + //! Do not use this method with points as it will give wrong results! + //! \param lookDirection: Look direction. + //! \return Returns true if the plane is front facing and + //! false if it is backfacing. + bool isFrontFacing(const vector3d& lookDirection) const + { + const f32 d = Normal.dotProduct(lookDirection); + return F32_LOWER_EQUAL_0 ( d ); + } + + //! Returns the distance to a point. Note that this only + //! works if the normal is Normalized. + T getDistanceTo(const vector3d& point) const + { + return point.dotProduct(Normal) + D; + } + + // member variables + + vector3d Normal; // normal vector + T D; // distance from origin +}; + + +//! Typedef for a f32 3d plane. +typedef plane3d plane3df; +//! Typedef for an integer 3d plane. +typedef plane3d plane3di; + +} // end namespace core +} // end namespace irr + +#endif + diff --git a/engine/include/support/position2d.h b/engine/include/support/position2d.h new file mode 100644 index 0000000..5eb96c0 --- /dev/null +++ b/engine/include/support/position2d.h @@ -0,0 +1,116 @@ +// Copyright (C) 2002-2007 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_POSITION_H_INCLUDED__ +#define __IRR_POSITION_H_INCLUDED__ + +#include "irrTypes.h" +#include "dimension2d.h" + +namespace irr +{ +namespace core +{ + + //! Simple class for holding 2d coordinates. + /** Not supposed for doing geometric calculations. + use vector2d instead for things like that. + */ + template + class position2d + { + public: + position2d() : X(0), Y(0) {} + position2d(T x, T y) : X(x), Y(y) {} + position2d(const position2d& other) + : X(other.X), Y(other.Y) {} + + bool operator == (const position2d& other) const + { + return X == other.X && Y == other.Y; + } + + bool operator != (const position2d& other) const + { + return X != other.X || Y != other.Y; + } + + const position2d& operator+=(const position2d& other) + { + X += other.X; + Y += other.Y; + return *this; + } + + const position2d& operator-=(const position2d& other) + { + X -= other.X; + Y -= other.Y; + return *this; + } + + const position2d& operator+=(const dimension2d& other) + { + X += other.Width; + Y += other.Height; + return *this; + } + + const position2d& operator-=(const dimension2d& other) + { + X -= other.Width; + Y -= other.Height; + return *this; + } + + position2d operator-(const position2d& other) const + { + return position2d(X-other.X, Y-other.Y); + } + + position2d operator+(const position2d& other) const + { + return position2d(X+other.X, Y+other.Y); + } + + position2d operator*(const position2d& other) const + { + return position2d(X*other.X, Y*other.Y); + } + + position2d operator*(const T& scalar) const + { + return position2d(X*scalar, Y*scalar); + } + + position2d operator+(const dimension2d& other) const + { + return position2d(X+other.Width, Y+other.Height); + } + + position2d operator-(const dimension2d& other) const + { + return position2d(X-other.Width, Y-other.Height); + } + + const position2d& operator=(const position2d& other) + { + X = other.X; + Y = other.Y; + return *this; + } + + T X, Y; + }; + + //! Typedef for a f32 position. + typedef position2d position2df; + //! Typedef for an integer position. + typedef position2d position2di; + +} // end namespace core +} // end namespace irr + +#endif + diff --git a/engine/include/support/quaternion.h b/engine/include/support/quaternion.h new file mode 100644 index 0000000..354d6a8 --- /dev/null +++ b/engine/include/support/quaternion.h @@ -0,0 +1,563 @@ +// Copyright (C) 2002-2007 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_QUATERNION_H_INCLUDED__ +#define __IRR_QUATERNION_H_INCLUDED__ + +#include "irrTypes.h" +#include "irrMath.h" +#include "matrix4.h" +#include "vector3d.h" + +namespace irr +{ +namespace core +{ + +//! Quaternion class. +class quaternion +{ + public: + + //! Default Constructor + quaternion() : X(0.0f), Y(0.0f), Z(0.0f), W(1.0f) {} + + //! Constructor + quaternion(f32 x, f32 y, f32 z, f32 w) : X(x), Y(y), Z(z), W(w) { } + + //! Constructor which converts euler angles (radians) to a quaternion + quaternion(f32 x, f32 y, f32 z); + + //! Constructor which converts euler angles (radians) to a quaternion + quaternion(const vector3df& vec); + + //! Constructor which converts a matrix to a quaternion + quaternion(const matrix4& mat); + + //! equal operator + bool operator==(const quaternion& other) const; + + //! assignment operator + inline quaternion& operator=(const quaternion& other); + + //! matrix assignment operator + inline quaternion& operator=(const matrix4& other); + + //! add operator + quaternion operator+(const quaternion& other) const; + + //! multiplication operator + quaternion operator*(const quaternion& other) const; + + //! multiplication operator + quaternion operator*(f32 s) const; + + //! multiplication operator + quaternion& operator*=(f32 s); + + //! multiplication operator + vector3df operator* (const vector3df& v) const; + + //! multiplication operator + quaternion& operator*=(const quaternion& other); + + //! calculates the dot product + inline f32 getDotProduct(const quaternion& other) const; + + //! sets new quaternion + inline void set(f32 x, f32 y, f32 z, f32 w); + + //! sets new quaternion based on euler angles (radians) + inline void set(f32 x, f32 y, f32 z); + + //! sets new quaternion based on euler angles (radians) + inline void set(const core::vector3df& vec); + + //! normalizes the quaternion + inline quaternion& normalize(); + + //! Creates a matrix from this quaternion + matrix4 getMatrix() const; + + //! Creates a matrix from this quaternion + void getMatrix( matrix4 &dest ) const; + + //! Creates a matrix from this quaternion + void getMatrix_transposed( matrix4 &dest ) const; + + //! Inverts this quaternion + void makeInverse(); + + //! set this quaternion to the result of the interpolation between two quaternions + void slerp( quaternion q1, quaternion q2, f32 interpolate ); + + //! axis must be unit length + //! The quaternion representing the rotation is + //! q = cos(A/2)+sin(A/2)*(x*i+y*j+z*k) + void fromAngleAxis (f32 angle, const vector3df& axis); + + //! Fills an angle (radians) around an axis (unit vector) + void toAngleAxis (f32 &angle, vector3df& axis) const; + + //! Output this quaternion to an euler angle (radians) + void toEuler(vector3df& euler) const; + + //! set quaternion to identity + void makeIdentity(); + + //! sets quaternion to represent a rotation from one angle to another + void rotationFromTo(const vector3df& from, const vector3df& to); + + f32 X, Y, Z, W; +}; + + +//! Constructor which converts euler angles to a quaternion +inline quaternion::quaternion(f32 x, f32 y, f32 z) +{ + set(x,y,z); +} + + +//! Constructor which converts euler angles to a quaternion +inline quaternion::quaternion(const vector3df& vec) +{ + set(vec.X,vec.Y,vec.Z); +} + + +//! Constructor which converts a matrix to a quaternion +inline quaternion::quaternion(const matrix4& mat) +{ + (*this) = mat; +} + + +//! equal operator +inline bool quaternion::operator==(const quaternion& other) const +{ + if(X != other.X) + return false; + if(Y != other.Y) + return false; + if(Z != other.Z) + return false; + if(W != other.W) + return false; + + return true; +} + + +//! assignment operator +inline quaternion& quaternion::operator=(const quaternion& other) +{ + X = other.X; + Y = other.Y; + Z = other.Z; + W = other.W; + return *this; +} + + +//! matrix assignment operator +inline quaternion& quaternion::operator=(const matrix4& m) +{ + f32 diag = m(0,0) + m(1,1) + m(2,2) + 1; + f32 scale = 0.0f; + + if( diag > 0.0f ) + { + scale = sqrtf(diag) * 2.0f; // get scale from diagonal + + // TODO: speed this up + X = ( m(2,1) - m(1,2)) / scale; + Y = ( m(0,2) - m(2,0)) / scale; + Z = ( m(1,0) - m(0,1)) / scale; + W = 0.25f * scale; + } + else + { + if ( m(0,0) > m(1,1) && m(0,0) > m(2,2)) + { + // 1st element of diag is greatest value + // find scale according to 1st element, and double it + scale = sqrtf( 1.0f + m(0,0) - m(1,1) - m(2,2)) * 2.0f; + + // TODO: speed this up + X = 0.25f * scale; + Y = (m(0,1) + m(1,0)) / scale; + Z = (m(2,0) + m(0,2)) / scale; + W = (m(2,1) - m(1,2)) / scale; + } + else if ( m(1,1) > m(2,2)) + { + // 2nd element of diag is greatest value + // find scale according to 2nd element, and double it + scale = sqrtf( 1.0f + m(1,1) - m(0,0) - m(2,2)) * 2.0f; + + // TODO: speed this up + X = (m(0,1) + m(1,0) ) / scale; + Y = 0.25f * scale; + Z = (m(1,2) + m(2,1) ) / scale; + W = (m(0,2) - m(2,0) ) / scale; + } + else + { + // 3rd element of diag is greatest value + // find scale according to 3rd element, and double it + scale = sqrtf( 1.0f + m(2,2) - m(0,0) - m(1,1)) * 2.0f; + + // TODO: speed this up + X = (m(0,2) + m(2,0)) / scale; + Y = (m(1,2) + m(2,1)) / scale; + Z = 0.25f * scale; + W = (m(1,0) - m(0,1)) / scale; + } + } + + normalize(); + return *this; +} + + +//! multiplication operator +inline quaternion quaternion::operator*(const quaternion& other) const +{ + quaternion tmp; + + tmp.W = (other.W * W) - (other.X * X) - (other.Y * Y) - (other.Z * Z); + tmp.X = (other.W * X) + (other.X * W) + (other.Y * Z) - (other.Z * Y); + tmp.Y = (other.W * Y) + (other.Y * W) + (other.Z * X) - (other.X * Z); + tmp.Z = (other.W * Z) + (other.Z * W) + (other.X * Y) - (other.Y * X); + + return tmp; +} + + +//! multiplication operator +inline quaternion quaternion::operator*(f32 s) const +{ + return quaternion(s*X, s*Y, s*Z, s*W); +} + +//! multiplication operator +inline quaternion& quaternion::operator*=(f32 s) +{ + X *= s; Y*=s; Z*=s; W*=s; + return *this; +} + +//! multiplication operator +inline quaternion& quaternion::operator*=(const quaternion& other) +{ + *this = other * (*this); + return *this; +} + +//! add operator +inline quaternion quaternion::operator+(const quaternion& b) const +{ + return quaternion(X+b.X, Y+b.Y, Z+b.Z, W+b.W); +} + + +//! Creates a matrix from this quaternion +inline matrix4 quaternion::getMatrix() const +{ + core::matrix4 m; + + m(0,0) = 1.0f - 2.0f*Y*Y - 2.0f*Z*Z; + m(1,0) = 2.0f*X*Y + 2.0f*Z*W; + m(2,0) = 2.0f*X*Z - 2.0f*Y*W; + m(3,0) = 0.0f; + + m(0,1) = 2.0f*X*Y - 2.0f*Z*W; + m(1,1) = 1.0f - 2.0f*X*X - 2.0f*Z*Z; + m(2,1) = 2.0f*Z*Y + 2.0f*X*W; + m(3,1) = 0.0f; + + m(0,2) = 2.0f*X*Z + 2.0f*Y*W; + m(1,2) = 2.0f*Z*Y - 2.0f*X*W; + m(2,2) = 1.0f - 2.0f*X*X - 2.0f*Y*Y; + m(3,2) = 0.0f; + + m(0,3) = 0.0f; + m(1,3) = 0.0f; + m(2,3) = 0.0f; + m(3,3) = 1.0f; + + return m; +} + + +//! Creates a matrix from this quaternion +inline void quaternion::getMatrix( matrix4 &dest ) const +{ + dest[0] = 1.0f - 2.0f*Y*Y - 2.0f*Z*Z; + dest[1] = 2.0f*X*Y + 2.0f*Z*W; + dest[2] = 2.0f*X*Z - 2.0f*Y*W; + dest[3] = 0.0f; + + dest[4] = 2.0f*X*Y - 2.0f*Z*W; + dest[5] = 1.0f - 2.0f*X*X - 2.0f*Z*Z; + dest[6] = 2.0f*Z*Y + 2.0f*X*W; + dest[7] = 0.0f; + + dest[8] = 2.0f*X*Z + 2.0f*Y*W; + dest[9] = 2.0f*Z*Y - 2.0f*X*W; + dest[10] = 1.0f - 2.0f*X*X - 2.0f*Y*Y; + dest[11] = 0.0f; + + dest[12] = 0.f; + dest[13] = 0.f; + dest[14] = 0.f; + dest[15] = 1.f; +} + +//! Creates a matrix from this quaternion +inline void quaternion::getMatrix_transposed( matrix4 &dest ) const +{ + dest[0] = 1.0f - 2.0f*Y*Y - 2.0f*Z*Z; + dest[4] = 2.0f*X*Y + 2.0f*Z*W; + dest[8] = 2.0f*X*Z - 2.0f*Y*W; + dest[12] = 0.0f; + + dest[1] = 2.0f*X*Y - 2.0f*Z*W; + dest[5] = 1.0f - 2.0f*X*X - 2.0f*Z*Z; + dest[9] = 2.0f*Z*Y + 2.0f*X*W; + dest[13] = 0.0f; + + dest[2] = 2.0f*X*Z + 2.0f*Y*W; + dest[6] = 2.0f*Z*Y - 2.0f*X*W; + dest[10] = 1.0f - 2.0f*X*X - 2.0f*Y*Y; + dest[14] = 0.0f; + + dest[3] = 0.f; + dest[7] = 0.f; + dest[11] = 0.f; + dest[15] = 1.f; +} + + + +//! Inverts this quaternion +inline void quaternion::makeInverse() +{ + X = -X; Y = -Y; Z = -Z; +} + +//! sets new quaternion +inline void quaternion::set(f32 x, f32 y, f32 z, f32 w) +{ + X = x; + Y = y; + Z = z; + W = w; +} + + +//! sets new quaternion based on euler angles +inline void quaternion::set(f32 x, f32 y, f32 z) +{ + f64 angle; + + angle = x * 0.5; + f64 sr = (f32)sin(angle); + f64 cr = (f32)cos(angle); + + angle = y * 0.5; + f64 sp = (f32)sin(angle); + f64 cp = (f32)cos(angle); + + angle = z * 0.5; + f64 sy = (f32)sin(angle); + f64 cy = (f32)cos(angle); + + f64 cpcy = cp * cy; + f64 spcy = sp * cy; + f64 cpsy = cp * sy; + f64 spsy = sp * sy; + + X = (f32)(sr * cpcy - cr * spsy); + Y = (f32)(cr * spcy + sr * cpsy); + Z = (f32)(cr * cpsy - sr * spcy); + W = (f32)(cr * cpcy + sr * spsy); + + normalize(); +} + +//! sets new quaternion based on euler angles +inline void quaternion::set(const core::vector3df& vec) +{ + set(vec.X, vec.Y, vec.Z); +} + +//! normalizes the quaternion +inline quaternion& quaternion::normalize() +{ + f32 n = X*X + Y*Y + Z*Z + W*W; + + if (n == 1) + return *this; + + //n = 1.0f / sqrtf(n); + n = reciprocal_squareroot ( n ); + X *= n; + Y *= n; + Z *= n; + W *= n; + + return *this; +} + + +// set this quaternion to the result of the interpolation between two quaternions +inline void quaternion::slerp( quaternion q1, quaternion q2, f32 time) +{ + f32 angle = q1.getDotProduct(q2); + + if (angle < 0.0f) + { + q1 *= -1.0f; + angle *= -1.0f; + } + + f32 scale; + f32 invscale; + + if ((angle + 1.0f) > 0.05f) + { + if ((1.0f - angle) >= 0.05f) // spherical interpolation + { + f32 theta = (f32)acos(angle); + f32 invsintheta = 1.0f / (f32)sin(theta); + scale = (f32)sin(theta * (1.0f-time)) * invsintheta; + invscale = (f32)sin(theta * time) * invsintheta; + } + else // linear interploation + { + scale = 1.0f - time; + invscale = time; + } + } + else + { + q2.set(-q1.Y, q1.X, -q1.W, q1.Z); + scale = (f32)sin(PI * (0.5f - time)); + invscale = (f32)sin(PI * time); + } + + *this = (q1*scale) + (q2*invscale); +} + + +//! calculates the dot product +inline f32 quaternion::getDotProduct(const quaternion& q2) const +{ + return (X * q2.X) + (Y * q2.Y) + (Z * q2.Z) + (W * q2.W); +} + + +inline void quaternion::fromAngleAxis(f32 angle, const vector3df& axis) +{ + f32 fHalfAngle = 0.5f*angle; + f32 fSin = (f32)sin(fHalfAngle); + W = (f32)cos(fHalfAngle); + X = fSin*axis.X; + Y = fSin*axis.Y; + Z = fSin*axis.Z; +} + +inline void quaternion::toAngleAxis(f32 &angle, core::vector3df &axis) const +{ + f32 scale = sqrtf(X*X + Y*Y + Z*Z); + + if (core::iszero(scale) || W > 1.0f || W < -1.0f) + { + angle = 0.0f; + axis.X = 0.0f; + axis.Y = 1.0f; + axis.Z = 0.0f; + } + else + { + angle = 2.0f * acos(W); + axis.X = X / scale; + axis.Y = Y / scale; + axis.Z = Z / scale; + } +} + +inline void quaternion::toEuler(vector3df& euler) const +{ + double sqw = W*W; + double sqx = X*X; + double sqy = Y*Y; + double sqz = Z*Z; + + // heading = rotation about z-axis + euler.Z = (f32) (atan2(2.0 * (X*Y +Z*W),(sqx - sqy - sqz + sqw))); + + // bank = rotation about x-axis + euler.X = (f32) (atan2(2.0 * (Y*Z +X*W),(-sqx - sqy + sqz + sqw))); + + // attitude = rotation about y-axis + euler.Y = (f32) (asin( clamp(-2.0 * (X*Z - Y*W), -1.0, 1.0) )); +} + +inline vector3df quaternion::operator* (const vector3df& v) const +{ + // nVidia SDK implementation + + vector3df uv, uuv; + vector3df qvec(X, Y, Z); + uv = qvec.crossProduct(v); + uuv = qvec.crossProduct(uv); + uv *= (2.0f * W); + uuv *= 2.0f; + + return v + uv + uuv; +} + +//! set quaterion to identity +inline void quaternion::makeIdentity() +{ + W = 1.f; + X = 0.f; + Y = 0.f; + Z = 0.f; +} + +inline void quaternion::rotationFromTo(const vector3df& from, const vector3df& to) +{ + // Based on Stan Melax's article in Game Programming Gems + // Copy, since cannot modify local + vector3df v0 = from; + vector3df v1 = to; + v0.normalize(); + v1.normalize(); + + vector3df c = v0.crossProduct(v1); + + f32 d = v0.dotProduct(v1); + if (d >= 1.0f) // If dot == 1, vectors are the same + { + *this=quaternion(0,0,0,1); //IDENTITY; + } + f32 s = sqrtf( (1+d)*2 ); // optimize inv_sqrt + f32 invs = 1 / s; + + X = c.X * invs; + Y = c.Y * invs; + Z = c.Z * invs; + W = s * 0.5f; +} + + +} // end namespace core +} // end namespace irr + +#endif + diff --git a/engine/include/support/rect.h b/engine/include/support/rect.h new file mode 100644 index 0000000..d145132 --- /dev/null +++ b/engine/include/support/rect.h @@ -0,0 +1,257 @@ +// Copyright (C) 2002-2007 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_RECT_H_INCLUDED__ +#define __IRR_RECT_H_INCLUDED__ + +#include "irrTypes.h" +#include "dimension2d.h" +#include "position2d.h" + +namespace irr +{ +namespace core +{ + + //! Rectangle template. + /** Mostly used by 2D GUI elements and for 2D drawing methods. + It has 2 positions instead of position and dimension and a fast + method for collision detection with other rectangles and points. + */ + template + class rect + { + public: + + rect() : UpperLeftCorner(0,0), LowerRightCorner(0,0) {} + + rect(T x, T y, T x2, T y2) + : UpperLeftCorner(x,y), LowerRightCorner(x2,y2) {} + + rect(const position2d& upperLeft, const position2d& lowerRight) + : UpperLeftCorner(upperLeft), LowerRightCorner(lowerRight) {} + + rect(const position2d& pos, const dimension2d& size) + : UpperLeftCorner(pos), LowerRightCorner(pos.X + size.Width, pos.Y + size.Height) {} + + + rect operator+(const position2d& pos) const + { + rect ret(*this); + return ret+=pos; + } + + rect& operator+=(const position2d& pos) + { + UpperLeftCorner += pos; + LowerRightCorner += pos; + return *this; + } + + rect operator-(const position2d& pos) const + { + rect ret(*this); + return ret-=pos; + } + + rect& operator-=(const position2d& pos) + { + UpperLeftCorner -= pos; + LowerRightCorner -= pos; + return *this; + } + + bool operator==(const rect& other) const + { + return (UpperLeftCorner == other.UpperLeftCorner && + LowerRightCorner == other.LowerRightCorner); + } + + + bool operator!=(const rect& other) const + { + return (UpperLeftCorner != other.UpperLeftCorner || + LowerRightCorner != other.LowerRightCorner); + } + + // compares size of rectangles + bool operator<(const rect& other) const + { + return getArea() < other.getArea(); + } + + //! Returns size of rectangle + T getArea() const + { + return getWidth() * getHeight(); + } + + //! Returns if a 2d point is within this rectangle. + //! \param pos: Position to test if it lies within this rectangle. + //! \return Returns true if the position is within the rectangle, false if not. + bool isPointInside(const position2d& pos) const + { + return (UpperLeftCorner.X <= pos.X && + UpperLeftCorner.Y <= pos.Y && + LowerRightCorner.X >= pos.X && + LowerRightCorner.Y >= pos.Y); + } + + //! Returns if the rectangle collides with another rectangle. + bool isRectCollided(const rect& other) const + { + return (LowerRightCorner.Y > other.UpperLeftCorner.Y && + UpperLeftCorner.Y < other.LowerRightCorner.Y && + LowerRightCorner.X > other.UpperLeftCorner.X && + UpperLeftCorner.X < other.LowerRightCorner.X); + } + + //! Clips this rectangle with another one. + void clipAgainst(const rect& other) + { + if (other.LowerRightCorner.X < LowerRightCorner.X) + LowerRightCorner.X = other.LowerRightCorner.X; + if (other.LowerRightCorner.Y < LowerRightCorner.Y) + LowerRightCorner.Y = other.LowerRightCorner.Y; + + if (other.UpperLeftCorner.X > UpperLeftCorner.X) + UpperLeftCorner.X = other.UpperLeftCorner.X; + if (other.UpperLeftCorner.Y > UpperLeftCorner.Y) + UpperLeftCorner.Y = other.UpperLeftCorner.Y; + + // correct possible invalid rect resulting from clipping + if (UpperLeftCorner.Y > LowerRightCorner.Y) + UpperLeftCorner.Y = LowerRightCorner.Y; + if (UpperLeftCorner.X > LowerRightCorner.X) + UpperLeftCorner.X = LowerRightCorner.X; + } + + //! Moves this rectangle to fit inside another one. + //! \return: returns true on success, false if not possible + bool constrainTo(const rect& other) + { + if (other.getWidth() < getWidth() || other.getHeight() < getHeight()) + return false; + + T diff = other.LowerRightCorner.X - LowerRightCorner.X; + if (diff < 0) + { + LowerRightCorner.X += diff; + UpperLeftCorner.X += diff; + } + + diff = other.LowerRightCorner.Y - LowerRightCorner.Y; + if (diff < 0) + { + LowerRightCorner.Y += diff; + UpperLeftCorner.Y += diff; + } + + diff = UpperLeftCorner.X - other.UpperLeftCorner.X; + if (diff < 0) + { + UpperLeftCorner.X -= diff; + LowerRightCorner.X -= diff; + } + + diff = UpperLeftCorner.Y - other.UpperLeftCorner.Y; + if (diff < 0) + { + UpperLeftCorner.Y -= diff; + LowerRightCorner.Y -= diff; + } + + return true; + } + + //! Returns width of rectangle. + T getWidth() const + { + return LowerRightCorner.X - UpperLeftCorner.X; + } + + //! Returns height of rectangle. + T getHeight() const + { + return LowerRightCorner.Y - UpperLeftCorner.Y; + } + + //! If the lower right corner of the rect is smaller then the + //! upper left, the points are swapped. + void repair() + { + if (LowerRightCorner.X < UpperLeftCorner.X) + { + T t = LowerRightCorner.X; + LowerRightCorner.X = UpperLeftCorner.X; + UpperLeftCorner.X = t; + } + + if (LowerRightCorner.Y < UpperLeftCorner.Y) + { + T t = LowerRightCorner.Y; + LowerRightCorner.Y = UpperLeftCorner.Y; + UpperLeftCorner.Y = t; + } + } + + //! Returns if the rect is valid to draw. It could be invalid + //! if the UpperLeftCorner is lower or more right than the + //! LowerRightCorner, or if any dimension is 0. + bool isValid() const + { + return ((LowerRightCorner.X >= UpperLeftCorner.X) && + (LowerRightCorner.Y >= UpperLeftCorner.Y)); + } + + //! Returns the center of the rectangle + position2d getCenter() const + { + return position2d((UpperLeftCorner.X + LowerRightCorner.X) / 2, + (UpperLeftCorner.Y + LowerRightCorner.Y) / 2); + } + + //! Returns the dimensions of the rectangle + dimension2d getSize() const + { + return dimension2d(getWidth(), getHeight()); + } + + + //! Adds a point to the rectangle, causing it to grow bigger, + //! if point is outside of the box + //! \param p: Point to add into the box. + void addInternalPoint(const position2d& p) + { + addInternalPoint(p.X, p.Y); + } + + //! Adds a point to the bounding rectangle, causing it to grow bigger, + //! if point is outside of the box. + //! \param x: X Coordinate of the point to add to this box. + //! \param y: Y Coordinate of the point to add to this box. + void addInternalPoint(T x, T y) + { + if (x>LowerRightCorner.X) + LowerRightCorner.X = x; + if (y>LowerRightCorner.Y) + LowerRightCorner.Y = y; + + if (x UpperLeftCorner; + position2d LowerRightCorner; + }; + + +} // end namespace core +} // end namespace irr + +#endif + diff --git a/engine/include/support/vector2d.h b/engine/include/support/vector2d.h new file mode 100644 index 0000000..5ab78d3 --- /dev/null +++ b/engine/include/support/vector2d.h @@ -0,0 +1,256 @@ +// Copyright (C) 2002-2007 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_POINT_2D_H_INCLUDED__ +#define __IRR_POINT_2D_H_INCLUDED__ + +#include "irrMath.h" + +namespace irr +{ +namespace core +{ + + +//! 2d vector template class with lots of operators and methods. +template +class vector2d +{ +public: + + vector2d() : X(0), Y(0) {} + vector2d(T nx, T ny) : X(nx), Y(ny) {} + vector2d(const vector2d& other) : X(other.X), Y(other.Y) {} + + // operators + + vector2d operator-() const { return vector2d(-X, -Y); } + + vector2d& operator=(const vector2d& other) { X = other.X; Y = other.Y; return *this; } + + vector2d operator+(const vector2d& other) const { return vector2d(X + other.X, Y + other.Y); } + vector2d& operator+=(const vector2d& other) { X+=other.X; Y+=other.Y; return *this; } + vector2d operator+(const T v) const { return vector2d(X + v, Y + v); } + vector2d& operator+=(const T v) { X+=v; Y+=v; return *this; } + + vector2d operator-(const vector2d& other) const { return vector2d(X - other.X, Y - other.Y); } + vector2d& operator-=(const vector2d& other) { X-=other.X; Y-=other.Y; return *this; } + vector2d operator-(const T v) const { return vector2d(X - v, Y - v); } + vector2d& operator-=(const T v) { X-=v; Y-=v; return *this; } + + vector2d operator*(const vector2d& other) const { return vector2d(X * other.X, Y * other.Y); } + vector2d& operator*=(const vector2d& other) { X*=other.X; Y*=other.Y; return *this; } + vector2d operator*(const T v) const { return vector2d(X * v, Y * v); } + vector2d& operator*=(const T v) { X*=v; Y*=v; return *this; } + + vector2d operator/(const vector2d& other) const { return vector2d(X / other.X, Y / other.Y); } + vector2d& operator/=(const vector2d& other) { X/=other.X; Y/=other.Y; return *this; } + vector2d operator/(const T v) const { return vector2d(X / v, Y / v); } + vector2d& operator/=(const T v) { X/=v; Y/=v; return *this; } + + bool operator<=(const vector2d&other) const { return X<=other.X && Y<=other.Y; } + bool operator>=(const vector2d&other) const { return X>=other.X && Y>=other.Y; } + + bool operator<(const vector2d&other) const { return X(const vector2d&other) const { return X>other.X && Y>other.Y; } + + bool operator==(const vector2d& other) const { return other.X==X && other.Y==Y; } + bool operator!=(const vector2d& other) const { return other.X!=X || other.Y!=Y; } + + // functions + + //! returns if this vector equals the other one, taking floating point rounding errors into account + bool equals(const vector2d& other) const + { + return core::equals(X, other.X) && core::equals(Y, other.Y); + } + + void set(T nx, T ny) {X=nx; Y=ny; } + void set(const vector2d& p) { X=p.X; Y=p.Y;} + + //! Returns the length of the vector + //! \return Returns the length of the vector. + T getLength() const { return (T)sqrt((f64)(X*X + Y*Y)); } + + //! Returns the squared length of this vector + /** This is useful because it is much faster than getLength(). */ + T getLengthSQ() const { return X*X + Y*Y; } + + //! Returns the dot product of this vector with another. + T dotProduct(const vector2d& other) const + { + return X*other.X + Y*other.Y; + } + + //! Returns distance from another point. Here, the vector is interpreted + //! as a point in 2 dimensional space. + T getDistanceFrom(const vector2d& other) const + { + return vector2d(X - other.X, Y - other.Y).getLength(); + } + + //! Returns squared distance from another point. Here, the vector is + //! interpreted as a point in 2 dimensional space. + T getDistanceFromSQ(const vector2d& other) const + { + return vector2d(X - other.X, Y - other.Y).getLengthSQ(); + } + + //! rotates the point around a center by an amount of degrees. + void rotateBy(f64 degrees, const vector2d& center) + { + degrees *= DEGTORAD64; + T cs = (T)cos(degrees); + T sn = (T)sin(degrees); + + X -= center.X; + Y -= center.Y; + + set(X*cs - Y*sn, X*sn + Y*cs); + + X += center.X; + Y += center.Y; + } + + //! normalizes the vector. + vector2d& normalize() + { + T l = X*X + Y*Y; + if (l == 0) + return *this; + l = core::reciprocal_squareroot ( (f32)l ); + X *= l; + Y *= l; + return *this; + } + + //! Calculates the angle of this vector in grad in the trigonometric sense. + //! This method has been suggested by Pr3t3nd3r. + //! \return Returns a value between 0 and 360. + f64 getAngleTrig() const + { + if (X == 0) + return Y < 0 ? 270 : 90; + else + if (Y == 0) + return X < 0 ? 180 : 0; + + if ( Y > 0) + if (X > 0) + return atan(Y/X) * RADTODEG64; + else + return 180.0-atan(Y/-X) * RADTODEG64; + else + if (X > 0) + return 360.0-atan(-Y/X) * RADTODEG64; + else + return 180.0+atan(-Y/-X) * RADTODEG64; + } + + //! Calculates the angle of this vector in grad in the counter trigonometric sense. + //! \return Returns a value between 0 and 360. + inline f64 getAngle() const + { + if (Y == 0) // corrected thanks to a suggestion by Jox + return X < 0 ? 180 : 0; + else if (X == 0) + return Y < 0 ? 90 : 270; + + f64 tmp = Y / getLength(); + tmp = atan(sqrt(1 - tmp*tmp) / tmp) * RADTODEG64; + + if (X>0 && Y>0) + return tmp + 270; + else + if (X>0 && Y<0) + return tmp + 90; + else + if (X<0 && Y<0) + return 90 - tmp; + else + if (X<0 && Y>0) + return 270 - tmp; + + return tmp; + } + + //! Calculates the angle between this vector and another one in grad. + //! \return Returns a value between 0 and 90. + inline f64 getAngleWith(const vector2d& b) const + { + f64 tmp = X*b.X + Y*b.Y; + + if (tmp == 0.0) + return 90.0; + + tmp = tmp / sqrt((f64)((X*X + Y*Y) * (b.X*b.X + b.Y*b.Y))); + if (tmp < 0.0) + tmp = -tmp; + + return atan(sqrt(1 - tmp*tmp) / tmp) * RADTODEG64; + } + + //! Returns if this vector interpreted as a point is on a line between two other points. + /** It is assumed that the point is on the line. */ + //! \param begin: Beginning vector to compare between. + //! \param end: Ending vector to compare between. + //! \return True if this vector is between begin and end. False if not. + bool isBetweenPoints(const vector2d& begin, const vector2d& end) const + { + T f = (end - begin).getLengthSQ(); + return getDistanceFromSQ(begin) < f && + getDistanceFromSQ(end) < f; + } + + //! returns interpolated vector + //! \param other: other vector to interpolate between + //! \param d: value between 0.0f and 1.0f. + vector2d getInterpolated(const vector2d& other, f32 d) const + { + T inv = (T) 1.0 - d; + return vector2d(other.X*inv + X*d, other.Y*inv + Y*d); + } + + //! Returns (quadratically) interpolated vector between this and the two given ones. + /** \param v2: second vector to interpolate with + \param v3: third vector to interpolate with + \param d: value between 0.0f and 1.0f. */ + vector2d getInterpolated_quadratic(const vector2d& v2, const vector2d& v3, const T d) const + { + // this*(1-d)*(1-d) + 2 * v2 * (1-d) + v3 * d * d; + const T inv = (T) 1.0 - d; + const T mul0 = inv * inv; + const T mul1 = (T) 2.0 * d * inv; + const T mul2 = d * d; + + return vector2d ( X * mul0 + v2.X * mul1 + v3.X * mul2, + Y * mul0 + v2.Y * mul1 + v3.Y * mul2); + } + + //! sets this vector to the linearly interpolated vector between a and b. + /** \param a: first vector to interpolate with + \param b: second vector to interpolate with + \param t: value between 0.0f and 1.0f. */ + void interpolate(const vector2d& a, const vector2d& b, const f32 t) + { + X = b.X + ( ( a.X - b.X ) * t ); + Y = b.Y + ( ( a.Y - b.Y ) * t ); + } + + // member variables + T X, Y; +}; + + //! Typedef for f32 2d vector. + typedef vector2d vector2df; + //! Typedef for integer 2d vector. + typedef vector2d vector2di; + + template vector2d operator*(const S scalar, const vector2d& vector) { return vector*scalar; } + +} // end namespace core +} // end namespace irr + +#endif + diff --git a/engine/include/support/vector3d.h b/engine/include/support/vector3d.h new file mode 100644 index 0000000..85a3ee3 --- /dev/null +++ b/engine/include/support/vector3d.h @@ -0,0 +1,286 @@ +// Copyright (C) 2002-2007 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __IRR_POINT_3D_H_INCLUDED__ +#define __IRR_POINT_3D_H_INCLUDED__ + +#include "irrMath.h" + +namespace irr +{ +namespace core +{ + + //! 3d vector template class with lots of operators and methods. + template + class vector3d + { + public: + + vector3d() : X(0), Y(0), Z(0) {} + vector3d(T nx, T ny, T nz) : X(nx), Y(ny), Z(nz) {} + vector3d(const vector3d& other) : X(other.X), Y(other.Y), Z(other.Z) {} + + // operators + + vector3d operator-() const { return vector3d(-X, -Y, -Z); } + + vector3d& operator=(const vector3d& other) { X = other.X; Y = other.Y; Z = other.Z; return *this; } + + vector3d operator+(const vector3d& other) const { return vector3d(X + other.X, Y + other.Y, Z + other.Z); } + vector3d& operator+=(const vector3d& other) { X+=other.X; Y+=other.Y; Z+=other.Z; return *this; } + + vector3d operator-(const vector3d& other) const { return vector3d(X - other.X, Y - other.Y, Z - other.Z); } + vector3d& operator-=(const vector3d& other) { X-=other.X; Y-=other.Y; Z-=other.Z; return *this; } + + vector3d operator*(const vector3d& other) const { return vector3d(X * other.X, Y * other.Y, Z * other.Z); } + vector3d& operator*=(const vector3d& other) { X*=other.X; Y*=other.Y; Z*=other.Z; return *this; } + vector3d operator*(const T v) const { return vector3d(X * v, Y * v, Z * v); } + vector3d& operator*=(const T v) { X*=v; Y*=v; Z*=v; return *this; } + + vector3d operator/(const vector3d& other) const { return vector3d(X / other.X, Y / other.Y, Z / other.Z); } + vector3d& operator/=(const vector3d& other) { X/=other.X; Y/=other.Y; Z/=other.Z; return *this; } + vector3d operator/(const T v) const { T i=(T)1.0/v; return vector3d(X * i, Y * i, Z * i); } + vector3d& operator/=(const T v) { T i=(T)1.0/v; X*=i; Y*=i; Z*=i; return *this; } + + bool operator<=(const vector3d&other) const { return X<=other.X && Y<=other.Y && Z<=other.Z;}; + bool operator>=(const vector3d&other) const { return X>=other.X && Y>=other.Y && Z>=other.Z;}; + bool operator<(const vector3d&other) const { return X(const vector3d&other) const { return X>other.X && Y>other.Y && Z>other.Z;}; + + //! use week float compare + //bool operator==(const vector3d& other) const { return other.X==X && other.Y==Y && other.Z==Z; } + //bool operator!=(const vector3d& other) const { return other.X!=X || other.Y!=Y || other.Z!=Z; } + + bool operator==(const vector3d& other) const + { + return this->equals(other); + } + + bool operator!=(const vector3d& other) const + { + return !this->equals(other); + } + + // functions + + //! returns if this vector equals the other one, taking floating point rounding errors into account + bool equals(const vector3d& other, const T tolerance = (T)ROUNDING_ERROR_32 ) const + { + return core::equals(X, other.X, tolerance) && + core::equals(Y, other.Y, tolerance) && + core::equals(Z, other.Z, tolerance); + } + + void set(const T nx, const T ny, const T nz) {X=nx; Y=ny; Z=nz; } + void set(const vector3d& p) { X=p.X; Y=p.Y; Z=p.Z;} + + //! Returns length of the vector. + T getLength() const { return (T) sqrt((f64)(X*X + Y*Y + Z*Z)); } + + //! Returns squared length of the vector. + /** This is useful because it is much faster than + getLength(). */ + T getLengthSQ() const { return X*X + Y*Y + Z*Z; } + + //! Returns the dot product with another vector. + T dotProduct(const vector3d& other) const + { + return X*other.X + Y*other.Y + Z*other.Z; + } + + //! Returns distance from another point. + /** Here, the vector is interpreted as point in 3 dimensional space. */ + T getDistanceFrom(const vector3d& other) const + { + return vector3d(X - other.X, Y - other.Y, Z - other.Z).getLength(); + } + + //! Returns squared distance from another point. + /** Here, the vector is interpreted as point in 3 dimensional space. */ + T getDistanceFromSQ(const vector3d& other) const + { + return vector3d(X - other.X, Y - other.Y, Z - other.Z).getLengthSQ(); + } + + //! Calculates the cross product with another vector + //! \param p: vector to multiply with. + //! \return Crossproduct of this vector with p. + vector3d crossProduct(const vector3d& p) const + { + return vector3d(Y * p.Z - Z * p.Y, Z * p.X - X * p.Z, X * p.Y - Y * p.X); + } + + //! Returns if this vector interpreted as a point is on a line between two other points. + /** It is assumed that the point is on the line. */ + //! \param begin: Beginning vector to compare between. + //! \param end: Ending vector to compare between. + //! \return True if this vector is between begin and end. False if not. + bool isBetweenPoints(const vector3d& begin, const vector3d& end) const + { + T f = (end - begin).getLengthSQ(); + return getDistanceFromSQ(begin) < f && + getDistanceFromSQ(end) < f; + } + + //! Normalizes the vector. In case of the 0 vector the result + //! is still 0, otherwise the length of the vector will be 1. + //! Todo: 64 Bit template doesnt work.. need specialized template + vector3d& normalize() + { + T l = X*X + Y*Y + Z*Z; + if (l == 0) + return *this; + l = (T) reciprocal_squareroot ( (f32)l ); + X *= l; + Y *= l; + Z *= l; + return *this; + } + + //! Sets the length of the vector to a new value + void setLength(T newlength) + { + normalize(); + *this *= newlength; + } + + //! Inverts the vector. + void invert() + { + X *= -1.0f; + Y *= -1.0f; + Z *= -1.0f; + } + + //! Rotates the vector by a specified number of degrees around the Y + //! axis and the specified center. + //! \param degrees: Number of degrees to rotate around the Y axis. + //! \param center: The center of the rotation. + void rotateXZBy(f64 degrees, const vector3d& center) + { + degrees *= DEGTORAD64; + T cs = (T)cos(degrees); + T sn = (T)sin(degrees); + X -= center.X; + Z -= center.Z; + set(X*cs - Z*sn, Y, X*sn + Z*cs); + X += center.X; + Z += center.Z; + } + + //! Rotates the vector by a specified number of degrees around the Z + //! axis and the specified center. + //! \param degrees: Number of degrees to rotate around the Z axis. + //! \param center: The center of the rotation. + void rotateXYBy(f64 degrees, const vector3d& center) + { + degrees *= DEGTORAD64; + T cs = (T)cos(degrees); + T sn = (T)sin(degrees); + X -= center.X; + Y -= center.Y; + set(X*cs - Y*sn, X*sn + Y*cs, Z); + X += center.X; + Y += center.Y; + } + + //! Rotates the vector by a specified number of degrees around the X + //! axis and the specified center. + //! \param degrees: Number of degrees to rotate around the X axis. + //! \param center: The center of the rotation. + void rotateYZBy(f64 degrees, const vector3d& center) + { + degrees *= DEGTORAD64; + T cs = (T)cos(degrees); + T sn = (T)sin(degrees); + Z -= center.Z; + Y -= center.Y; + set(X, Y*cs - Z*sn, Y*sn + Z*cs); + Z += center.Z; + Y += center.Y; + } + + //! Returns interpolated vector. + /** \param other: other vector to interpolate between + \param d: value between 0.0f and 1.0f. */ + vector3d getInterpolated(const vector3d& other, const T d) const + { + const T inv = (T) 1.0 - d; + return vector3d(other.X*inv + X*d, other.Y*inv + Y*d, other.Z*inv + Z*d); + } + + //! Returns interpolated vector. ( quadratic ) + /** \param v2: second vector to interpolate with + \param v3: third vector to interpolate with + \param d: value between 0.0f and 1.0f. */ + vector3d getInterpolated_quadratic(const vector3d& v2, const vector3d& v3, const T d) const + { + // this*(1-d)*(1-d) + 2 * v2 * (1-d) + v3 * d * d; + const T inv = (T) 1.0 - d; + const T mul0 = inv * inv; + const T mul1 = (T) 2.0 * d * inv; + const T mul2 = d * d; + + return vector3d ( X * mul0 + v2.X * mul1 + v3.X * mul2, + Y * mul0 + v2.Y * mul1 + v3.Y * mul2, + Z * mul0 + v2.Z * mul1 + v3.Z * mul2); + } + + //! Gets the Y and Z rotations of a vector. + /** Thanks to Arras on the Irrlicht forums to add this method. + \return A vector representing the rotation in degrees of + this vector. The Z component of the vector will always be 0. */ + vector3d getHorizontalAngle() + { + vector3d angle; + + angle.Y = (T)atan2(X, Z); + angle.Y *= (f32)RADTODEG64; + + if (angle.Y < 0.0f) angle.Y += 360.0f; + if (angle.Y >= 360.0f) angle.Y -= 360.0f; + + f32 z1 = sqrtf(X*X + Z*Z); + + angle.X = (T)atan2(z1, Y); + angle.X *= (f32)RADTODEG64; + angle.X -= 90.0f; + + if (angle.X < 0.0f) angle.X += 360.0f; + if (angle.X >= 360.0f) angle.X -= 360.0f; + + return angle; + } + + //! Fills an array of 4 values with the vector data (usually floats). + /** Useful for setting in shader constants for example. The fourth value + will always be 0. */ + void getAs4Values(T* array) const + { + array[0] = X; + array[1] = Y; + array[2] = Z; + array[3] = 0; + } + + + // member variables + + T X, Y, Z; + }; + + + //! Typedef for a f32 3d vector. + typedef vector3d vector3df; + //! Typedef for an integer 3d vector. + typedef vector3d vector3di; + + template vector3d operator*(const S scalar, const vector3d& vector) { return vector*scalar; } + +} // end namespace core +} // end namespace irr + +#endif + diff --git a/engine/src/core/Buffer.cpp b/engine/src/core/Buffer.cpp new file mode 100644 index 0000000..baa51fd --- /dev/null +++ b/engine/src/core/Buffer.cpp @@ -0,0 +1,278 @@ +/* +Copyright (C) 2008 Mathias Gottschlag + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in the +Software without restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the +Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "core/Buffer.h" + +#include +#include + +namespace peak +{ + Buffer::Buffer() + { + data = 0; + size = 0; + position = 0; + datasize = 0; + } + Buffer::Buffer(unsigned int size) + { + data = (char*)malloc(size); + size = size; + position = 0; + datasize = 0; + } + Buffer::Buffer(void *data, unsigned int size) + { + this->data = (char*)malloc(size); + size = size; + datasize = size; + position = 0; + memcpy(this->data, data, size); + } + Buffer::Buffer(const Buffer &buf) + { + data = 0; + size = 0; + datasize = 0; + position = 0; + *this += buf; + } + Buffer::~Buffer() + { + if (data) + free(data); + } + + void Buffer::setSize(unsigned int size) + { + data = (char*)realloc(data, size); + if (datasize > size) + datasize = size; + if (position > datasize) + position = datasize; + this->size = size; + + } + unsigned int Buffer::getSize(void) + { + return size; + } + unsigned int Buffer::getDataSize(void) + { + return datasize; + } + + unsigned int Buffer::getPosition(void) + { + return position; + } + void Buffer::setPosition(unsigned int position, bool relative) + { + if (!relative) + { + if (position > datasize) + position = datasize; + this->position = position; + } + else + { + if (this->position + position > datasize) + position = datasize - this->position; + this->position += position; + } + } + + int Buffer::readData(void *dest, unsigned int size) + { + if (datasize - position < size) + { + size = datasize - position; + } + memcpy(dest, data + position, size); + position += size; + return size; + } + int Buffer::writeData(const void *source, unsigned int size, bool resize) + { + if (this->size - datasize < size) + { + if (resize) + { + setSize(datasize + size); + } + else + { + size = this->size - datasize; + } + } + memcpy(data + datasize, source, size); + datasize += size; + return size; + } + + void Buffer::writeInt(int value) + { + writeData(&value, sizeof(int), true); + } + int Buffer::readInt(void) + { + int value; + readData(&value, sizeof(int)); + return value; + } + void Buffer::writeFloat(float value) + { + writeData(&value, sizeof(float), true); + } + float Buffer::readFloat(void) + { + float value; + readData(&value, sizeof(float)); + return value; + } + void Buffer::writeString(std::string str) + { + writeData(str.c_str(), str.length() + 1, true); + } + std::string Buffer::readString(void) + { + std::string str = data + position; + while (readByte()) + ; + return str; + } + void Buffer::writeByte(unsigned char value) + { + writeData(&value, sizeof(unsigned char), true); + } + unsigned char Buffer::readByte(void) + { + unsigned char value; + readData(&value, sizeof(unsigned char)); + return value; + } + void Buffer::writeWord(short value) + { + writeData(&value, sizeof(short), true); + } + short Buffer::readWord(void) + { + short value; + readData(&value, sizeof(short)); + return value; + } + void Buffer::writeBool(bool flag) + { + writeByte(flag); + } + bool Buffer::readBool(void) + { + bool flag = readByte(); + return flag; + } + void Buffer::writeVector2D(Vector2D v) + { + writeFloat(v.x); + writeFloat(v.y); + } + Vector2D Buffer::readVector2D(void) + { + Vector2D v; + v.x = readFloat(); + v.y = readFloat(); + return v; + } + void Buffer::writeVector3D(Vector3D v) + { + writeFloat(v.x); + writeFloat(v.y); + writeFloat(v.z); + } + Vector3D Buffer::readVector3D(void) + { + Vector3D v; + v.x = readFloat(); + v.y = readFloat(); + v.z = readFloat(); + return v; + } + void Buffer::writeQuaternion(Quaternion q) + { + writeWord((unsigned short)(q.x * (1<<15))); + writeWord((unsigned short)(q.y * (1<<15))); + writeWord((unsigned short)(q.z * (1<<15))); + writeWord((unsigned short)(q.w * (1<<15))); + } + Quaternion Buffer::readQuaternion(void) + { + Quaternion q; + q.x = (float)readWord() / (1<<15); + q.y = (float)readWord() / (1<<15); + q.z = (float)readWord() / (1<<15); + q.w = (float)readWord() / (1<<15); + return q; + } + + + char *Buffer::getData(void) + { + return data; + } + + void Buffer::clear(void) + { + if (data) + free(data); + data = 0; + size = 0; + datasize = 0; + position = 0; + } + + Buffer &Buffer::operator=(const Buffer &buf) + { + clear(); + *this += buf; + return *this; + } + Buffer &Buffer::operator+=(const Buffer &buf) + { + writeData(buf.data, buf.datasize, true); + return *this; + } + Buffer &Buffer::operator<<(const Buffer &buf) + { + writeData(buf.data, buf.datasize, true); + return *this; + } + Buffer &Buffer::operator<<(int &data) + { + writeData(&data, sizeof(int), true); + return *this; + } + Buffer &Buffer::operator<<(float &data) + { + writeData(&data, sizeof(float), true); + return *this; + } +} + diff --git a/engine/src/network/BroadcastClient.cpp b/engine/src/network/BroadcastClient.cpp new file mode 100644 index 0000000..0d3b8b4 --- /dev/null +++ b/engine/src/network/BroadcastClient.cpp @@ -0,0 +1,206 @@ +/* +Copyright (C) 2008 Mathias Gottschlag + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in the +Software without restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the +Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "network/BroadcastClient.h" +//#include "core/Script.h" +#include "core/Logger.h" + +#include + +namespace peak +{ + BroadcastClient::BroadcastClient() + { + port = 0; + bcclients.push_back(this); + //cbscript = 0; + } + BroadcastClient::~BroadcastClient() + { + for (unsigned int i = 0; i < bcclients.size(); i++) + { + if (bcclients[i] == this) + { + bcclients.erase(bcclients.begin() + i); + return; + } + } + } + + void BroadcastClient::start(int port) + { + // Create raw socket + ENetAddress address; + address.host = ENET_HOST_ANY; + address.port = ENET_PORT_ANY; + socket = enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM, &address); + // enet 1.2 needs ENET_SOCKOPT_NONBLOCK, enet 1.1 does not provide it. + #ifdef _ENET_1_2_ + enet_socket_set_option(socket, ENET_SOCKOPT_NONBLOCK, 1); + #endif + /*if (enet_socket_set_option(socket, ENET_SOCKOPT_BROADCAST, 1) == -1) + { + perror("ENET_SOCKOPT_BROADCAST"); + }*/ + this->port = port; + updatetime = 1000; + LERROR("Started broadcast client (%d).\n", port); + } + void BroadcastClient::stop(void) + { + enet_socket_destroy(socket); + port = 0; + } + + void BroadcastClient::clearList(void) + { + serverinfo.clear(); + serveraddr.clear(); + } + + int BroadcastClient::getServerCount(void) + { + return serverinfo.size(); + } + std::string BroadcastClient::getServerInfo(int index) + { + return serverinfo[index]; + } + Address BroadcastClient::getServerAddress(int index) + { + return serveraddr[index]; + } + + void BroadcastClient::setCallback(Script *script, std::string function) + { + cbscript = script; + cbfunc = function; + } + + void BroadcastClient::doWork(float msecs) + { + if (!port) + return; + + + //printf("BroadcastClient: doWork().\n"); + + ENetBuffer buffer; + buffer.data = malloc(1024); + buffer.dataLength = 1024; + ENetAddress remoteaddr; + // Broadcast address + ENetAddress bcaddr; + bcaddr.host = ENET_HOST_BROADCAST; + bcaddr.port = 14141; + enet_address_set_host(&bcaddr, "127.0.0.1"); + + // Message to be sent to all hosts + char msg[] = "PING"; + ENetBuffer msgbuffer; + msgbuffer.data = msg; + msgbuffer.dataLength = 4; + + + // Broadcast + updatetime += msecs; + if (updatetime > 250) + { + LERROR("Sending.\n"); + if (enet_socket_send(socket, &bcaddr, &msgbuffer, 1) == -1) + { + perror("Sending failed"); + } + updatetime = 0; + } + + + // Receive answers + bool listchanged = false; + int length; + while ((length = enet_socket_receive(socket, &remoteaddr, &buffer, 1) > 0) + != 0) + { + if (length < 0) + { + LERROR("Socket error: %d\n", errno); + break; + } + if (length > 0) + { + LDEBUG("Got broadcast response.\n"); + + + // Get address + char addrstr[16]; + enet_address_get_host_ip(&remoteaddr, addrstr, 16); + Address addr(addrstr); + // FIXME: We need the proper port here! + addr.setPort(0); + + + // Look if server is already known + bool newaddr = true; + for (unsigned int i = 0; i < serveraddr.size(); i++) + { + if (serveraddr[i] == addr) + { + newaddr = false; + if (serverinfo[i] != (char*)buffer.data) + { + listchanged = true; + serverinfo[i] = (char*)buffer.data; + } + break; + } + } + + + // Add server to list + if (newaddr) + { + serveraddr.push_back(addr); + serverinfo.push_back((char*)buffer.data); + listchanged = true; + } + + } + } + // Call calback function + /*if (listchanged && cbscript && (cbfunc != "")) + { + cbscript->callFunction(cbfunc); + }*/ + + free(buffer.data); + } + + void BroadcastClient::doAllWork(float msecs) + { + for (unsigned int i = 0; i < bcclients.size(); i++) + { + bcclients[i]->doWork(msecs); + } + } + + std::vector BroadcastClient::bcclients; +} + diff --git a/engine/src/network/BroadcastHost.cpp b/engine/src/network/BroadcastHost.cpp new file mode 100644 index 0000000..5f7e410 --- /dev/null +++ b/engine/src/network/BroadcastHost.cpp @@ -0,0 +1,97 @@ +/* +Copyright (C) 2008 Mathias Gottschlag + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in the +Software without restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the +Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "network/BroadcastHost.h" +#include "core/Logger.h" + +#include +#include + +namespace peak +{ + BroadcastHost::BroadcastHost() + { + } + BroadcastHost::~BroadcastHost() + { + } + + bool BroadcastHost::init(int port) + { + // Create raw socket + ENetAddress bcaddr; + bcaddr.host = ENET_HOST_ANY; + bcaddr.port = 14141; + bcastsocket = enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM, &bcaddr); + // FIXME: enet 1.2 needs ENET_SOCKOPT_NONBLOCK, enet 1.1 does not provide it. + #ifdef _ENET_1_2_ + enet_socket_set_option(bcastsocket, ENET_SOCKOPT_NONBLOCK, 1); + #endif + printf("Listening (%d).\n", port); + return true; + } + bool BroadcastHost::shutdown(void) + { + enet_socket_destroy(bcastsocket); + info = ""; + return true; + } + + void BroadcastHost::setInfo(std::string info) + { + this->info = info; + } + std::string BroadcastHost::getInfo(void) + { + return info; + } + + void BroadcastHost::doWork(void) + { + int length; + ENetAddress addr; + ENetBuffer bcbuffer; + bcbuffer.data = malloc(1024); + bcbuffer.dataLength = 1024; + //printf("BroadcastHost::doWork(void).\n"); + // Look for broadcast messages + while ((length = enet_socket_receive(bcastsocket, &addr, &bcbuffer, 1)) + != 0) + { + printf("Listening.\n"); + if (length < 0) + { + LERROR("Socket error: %d\n", errno); + break; + } + if (length > 0) + { + LDEBUG("Got broadcast message.\n"); + // Send answer + memcpy(bcbuffer.data, info.c_str(), info.size() + 1); + bcbuffer.dataLength = info.size() + 1; + enet_socket_send(bcastsocket, &addr, &bcbuffer, 1); + } + } + free(bcbuffer.data); + } +} + diff --git a/engine/src/network/Connection.cpp b/engine/src/network/Connection.cpp new file mode 100644 index 0000000..c7bec7e --- /dev/null +++ b/engine/src/network/Connection.cpp @@ -0,0 +1,88 @@ +/* +Copyright (C) 2008 Mathias Gottschlag + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in the +Software without restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the +Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "network/Connection.h" + +namespace peak +{ + Connection::Connection(ENetPeer *peer) + { + this->peer = peer; + } + Connection::~Connection() + { + } + + void Connection::destroy(void) + { + // TODO: delete received data + if (peer) + { + enet_peer_reset(peer); + peer = 0; + } + } + + void Connection::disconnect(void) + { + enet_peer_disconnect(peer, 0); + peer = 0; + } + bool Connection::isConnected(void) + { + return (peer != 0); + } + + bool Connection::hasNewData(void) + { + return !received.empty(); + } + Buffer *Connection::readData(void) + { + if (received.empty()) + { + return 0; + } + + Buffer *data = received.front(); + received.pop(); + return data; + } + bool Connection::sendData(Buffer *data, bool reliable) + { + //printf("Sending %d, %d\n", data->getDataSize(), data->readByte()); + ENetPacket *packet = enet_packet_create(data->getData(), + data->getDataSize(), reliable ? ENET_PACKET_FLAG_RELIABLE : 0); + enet_peer_send(peer, 0, packet); + enet_host_flush(peer->host); + return true; + } + + void Connection::injectData(Buffer *data) + { + received.push(data); + } + ENetPeer *Connection::getPeer(void) + { + return peer; + } +} + diff --git a/engine/src/network/NetworkClient.cpp b/engine/src/network/NetworkClient.cpp new file mode 100644 index 0000000..b10306f --- /dev/null +++ b/engine/src/network/NetworkClient.cpp @@ -0,0 +1,140 @@ +/* +Copyright (C) 2008 Mathias Gottschlag + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in the +Software without restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the +Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "network/NetworkClient.h" +#include "network/Connection.h" +#include "core/Logger.h" + +#include + +namespace peak +{ + NetworkClient::NetworkClient() + { + host = 0; + } + NetworkClient::~NetworkClient() + { + } + + Connection *NetworkClient::init(void) + { + return 0; + } + Connection *NetworkClient::init(Address addr) + { + // Create network host + ENetAddress address; + address.host = ENET_HOST_ANY; + address.port = ENET_PORT_ANY; + host = enet_host_create(NULL, 1, 0, 0); + if (!host) + { + return 0; + } + + + // Create network peer + //ENetAddress address; + enet_address_set_host(&address, addr.getAddressString(false).c_str()); + address.port = addr.getPort(); + LINFO("Client: Address: %X:%d\n", address.host, address.port); + peer = enet_host_connect(host, &address, 2); + if (!peer) + { + enet_host_destroy(host); + return 0; + } + conn = 0; + while (!conn) + { + doWork(); + } + LINFO("Connected.\n"); + return conn; + } + void NetworkClient::shutdown(void) + { + // Close connection + if (conn) + { + conn->destroy(); + delete conn; + conn = 0; + } + // Delete network host + if (host) + { + enet_host_destroy(host); + host = 0; + } + } + + bool NetworkClient::isConnected(void) + { + return (conn != 0); + } + Connection *NetworkClient::getConnection(void) + { + return conn; + } + + bool NetworkClient::doWork(void) + { + if (!host) + return false; + + + // Receive data + ENetEvent event; + while (enet_host_service(host, &event, 0) > 0) + { + switch (event.type) + { + case ENET_EVENT_TYPE_CONNECT: + conn = new Connection(peer); + LDEBUG("Client: Connected.\n"); + break; + case ENET_EVENT_TYPE_RECEIVE: + { + //printf("Client: Received data.\n"); + Buffer *buffer = new Buffer; + buffer->writeData(event.packet->data, event.packet->dataLength, + true); + conn->injectData(buffer); + break; + } + case ENET_EVENT_TYPE_DISCONNECT: + LDEBUG("Client: Disconnected.\n"); + conn->destroy(); + delete conn; + conn = 0; + return false; + break; + default: + break; + } + } + + return true; + } +} + diff --git a/engine/src/network/NetworkHost.cpp b/engine/src/network/NetworkHost.cpp new file mode 100644 index 0000000..3f0d4ce --- /dev/null +++ b/engine/src/network/NetworkHost.cpp @@ -0,0 +1,146 @@ +/* +Copyright (C) 2008 Mathias Gottschlag + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in the +Software without restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the +Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "network/NetworkHost.h" +#include "network/Connection.h" +#include "core/Logger.h" + +#include + +namespace peak +{ + NetworkHost::NetworkHost() + { + host = 0; + } + NetworkHost::~NetworkHost() + { + } + + bool NetworkHost::init(int port) + { + // Create network host + ENetAddress address; + address.host = ENET_HOST_ANY; + address.port = port; + host = enet_host_create(&address, 32, 200000, 20000); + if (!host) + { + LERROR("Could not create network host.\n"); + return false; + } + LINFO("Created network host.\n"); + return true; + } + bool NetworkHost::shutdown(void) + { + for (unsigned int i = 0; i < connections.size(); i++) + { + Connection *conn = connections[i]; + conn->destroy(); + delete connections[i]; + } + connections.clear(); + if (host) + enet_host_destroy(host); + host = 0; + return true; + } + + Connection *NetworkHost::getNewConnection(void) + { + if (newconnections.empty()) + { + return 0; + } + + Connection *conn = newconnections.front(); + newconnections.pop(); + return conn; + } + void NetworkHost::closeConnection(Connection *conn) + { + for (unsigned int i = 0; i < connections.size(); i++) + { + if (connections[i] == conn) + { + connections[i]->destroy(); + delete connections[i]; + connections.erase(connections.begin() + i); + return; + } + } + } + + bool NetworkHost::doWork(void) + { + if (!host) + return false; + + + // Receive data + ENetEvent event; + while (enet_host_service(host, &event, 0) > 0) + { + switch (event.type) + { + case ENET_EVENT_TYPE_CONNECT: + { + LINFO("Host: Someone connected.\n"); + Connection *newconn = new Connection(event.peer); + connections.push_back(newconn); + newconnections.push(newconn); + break; + } + case ENET_EVENT_TYPE_RECEIVE: + //printf("Host: Received data.\n"); + // Push received data into connection + for (unsigned int i = 0; i < connections.size(); i++) + { + if (event.peer == connections[i]->getPeer()) + { + Buffer *buffer = new Buffer; + buffer->writeData(event.packet->data, + event.packet->dataLength, true); + connections[i]->injectData(buffer); + } + } + break; + case ENET_EVENT_TYPE_DISCONNECT: + LINFO("Host: Someone disconnected.\n"); + for (unsigned int i = 0; i < connections.size(); i++) + { + if (event.peer == connections[i]->getPeer()) + { + connections[i]->destroy(); + } + } + break; + default: + break; + } + } + // Send data + + return true; + } +} + diff --git a/test/src/main.cpp b/test/src/main.cpp new file mode 100644 index 0000000..4a4b845 --- /dev/null +++ b/test/src/main.cpp @@ -0,0 +1,6 @@ + +int main(int argc, char **argv) +{ + return 0; +} + -- 2.11.4.GIT