diff --git a/Makefile b/Makefile index 65437580..1c283186 100644 --- a/Makefile +++ b/Makefile @@ -12,9 +12,9 @@ CLIENT_SRC_DIR = ./client UF_LIBS = # EXT_LIBS = -lpng16 -lz -lsfml-main -lsfml-system -lsfml-window -lsfml-graphics # EXT_LIBS = -lpng16 -lz -lassimp -lsfml-main -lsfml-system -lsfml-window -lsfml-graphics -llua52 -EXT_LIBS = -lpng16 -lz -lassimp -ljsoncpp +EXT_LIBS = -lpng16 -lz -lassimp -ljsoncpp -lopenal32 -lalut -lvorbis -lvorbisfile -logg #FLAGS = -std=c++0x -Wall -g -DUF_USE_JSON -DUF_USE_NCURSES -DUF_USE_OPENGL -DUF_USE_GLEW -FLAGS = -std=c++0x -Wall -g -DUF_USE_JSON -DUF_USE_NCURSES -DUF_USE_OPENGL -DUF_USE_GLEW -DUF_USE_ASSIMP -O2 +FLAGS = -std=c++0x -Wall -g -DUF_USE_JSON -DUF_USE_NCURSES -DUF_USE_OPENGL -DUF_USE_GLEW -DUF_USE_OPENAL -DUF_USE_VORBIS -DUF_USE_ASSIMP -O2 #-march=native LIB_NAME = uf EXT_LIB_NAME = ext diff --git a/client/client/ext.cpp b/client/client/ext.cpp index c2bd2ce4..75f855c4 100644 --- a/client/client/ext.cpp +++ b/client/client/ext.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -116,6 +117,14 @@ void client::initialize() { ambient.w = client::config["light"]["ambient"]["a"].asDouble(); glClearColor(ambient.x, ambient.y, ambient.z, ambient.w); } + + /* Initialize OpenAL */ { + if ( !ext::oal.initialize() ) { + std::cerr << "[ERROR] AL failed to initialize!" << std::endl; + std::exit(EXIT_SUCCESS); + return; + } + } /* Initialize hooks */ { if ( client::config["hook"]["mode"] == "Both" || client::config["hook"]["mode"] == "Readable" ) { @@ -212,4 +221,10 @@ void client::render() { void client::terminate() { client::window.terminate(); spec::Context::globalCleanup(); + + if ( !ext::oal.terminate() ) { + std::cerr << "[ERROR] AL failed to terminate!" << std::endl; + std::exit(EXIT_SUCCESS); + return; + } } \ No newline at end of file diff --git a/engine/inc/AL/alut.h b/engine/inc/AL/alut.h new file mode 100644 index 00000000..4b05a3cb --- /dev/null +++ b/engine/inc/AL/alut.h @@ -0,0 +1,126 @@ +#if !defined(AL_ALUT_H) +#define AL_ALUT_H + +#if defined(_MSC_VER) +#include +#include +#elif defined(__APPLE__) +#include +#include +#else +#include +#include +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +#if defined(_WIN32) && !defined(_XBOX) + #if defined (ALUT_BUILD_LIBRARY) + #define ALUT_API __declspec(dllexport) + #else + #define ALUT_API __declspec(dllimport) + #endif +#else + #if defined(ALUT_BUILD_LIBRARY) && defined(HAVE_GCC_VISIBILITY) + #define ALUT_API __attribute__((visibility("default"))) + #else + #define ALUT_API extern + #endif +#endif + +#if defined(_WIN32) + #define ALUT_APIENTRY __cdecl +#else + #define ALUT_APIENTRY +#endif + +#if defined(__MWERKS_) + #pragma export on +#endif + +/* Flag deprecated functions if possible (VisualC++ .NET and GCC >= 3.1.1). */ +#if defined(_MSC_VER) && _MSC_VER >= 1300 && !defined(MIDL_PASS) +#define ALUT_ATTRIBUTE_DEPRECATED __declspec(deprecated) +#elif defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && (__GNUC_MINOR__ > 1 || (__GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ >= 1)))) +#define ALUT_ATTRIBUTE_DEPRECATED __attribute__((deprecated)) +#else +#define ALUT_ATTRIBUTE_DEPRECATED +#endif + +#define ALUT_API_MAJOR_VERSION 1 +#define ALUT_API_MINOR_VERSION 1 + +#define ALUT_ERROR_NO_ERROR 0 +#define ALUT_ERROR_OUT_OF_MEMORY 0x200 +#define ALUT_ERROR_INVALID_ENUM 0x201 +#define ALUT_ERROR_INVALID_VALUE 0x202 +#define ALUT_ERROR_INVALID_OPERATION 0x203 +#define ALUT_ERROR_NO_CURRENT_CONTEXT 0x204 +#define ALUT_ERROR_AL_ERROR_ON_ENTRY 0x205 +#define ALUT_ERROR_ALC_ERROR_ON_ENTRY 0x206 +#define ALUT_ERROR_OPEN_DEVICE 0x207 +#define ALUT_ERROR_CLOSE_DEVICE 0x208 +#define ALUT_ERROR_CREATE_CONTEXT 0x209 +#define ALUT_ERROR_MAKE_CONTEXT_CURRENT 0x20A +#define ALUT_ERROR_DESTROY_CONTEXT 0x20B +#define ALUT_ERROR_GEN_BUFFERS 0x20C +#define ALUT_ERROR_BUFFER_DATA 0x20D +#define ALUT_ERROR_IO_ERROR 0x20E +#define ALUT_ERROR_UNSUPPORTED_FILE_TYPE 0x20F +#define ALUT_ERROR_UNSUPPORTED_FILE_SUBTYPE 0x210 +#define ALUT_ERROR_CORRUPT_OR_TRUNCATED_DATA 0x211 + +#define ALUT_WAVEFORM_SINE 0x100 +#define ALUT_WAVEFORM_SQUARE 0x101 +#define ALUT_WAVEFORM_SAWTOOTH 0x102 +#define ALUT_WAVEFORM_WHITENOISE 0x103 +#define ALUT_WAVEFORM_IMPULSE 0x104 + +#define ALUT_LOADER_BUFFER 0x300 +#define ALUT_LOADER_MEMORY 0x301 + +ALUT_API ALboolean ALUT_APIENTRY alutInit (int *argcp, char **argv); +ALUT_API ALboolean ALUT_APIENTRY alutInitWithoutContext (int *argcp, char **argv); +ALUT_API ALboolean ALUT_APIENTRY alutExit (void); + +ALUT_API ALenum ALUT_APIENTRY alutGetError (void); +ALUT_API const char *ALUT_APIENTRY alutGetErrorString (ALenum error); + +ALUT_API ALuint ALUT_APIENTRY alutCreateBufferFromFile (const char *fileName); +ALUT_API ALuint ALUT_APIENTRY alutCreateBufferFromFileImage (const ALvoid *data, ALsizei length); +ALUT_API ALuint ALUT_APIENTRY alutCreateBufferHelloWorld (void); +ALUT_API ALuint ALUT_APIENTRY alutCreateBufferWaveform (ALenum waveshape, ALfloat frequency, ALfloat phase, ALfloat duration); + +ALUT_API ALvoid *ALUT_APIENTRY alutLoadMemoryFromFile (const char *fileName, ALenum *format, ALsizei *size, ALfloat *frequency); +ALUT_API ALvoid *ALUT_APIENTRY alutLoadMemoryFromFileImage (const ALvoid *data, ALsizei length, ALenum *format, ALsizei *size, ALfloat *frequency); +ALUT_API ALvoid *ALUT_APIENTRY alutLoadMemoryHelloWorld (ALenum *format, ALsizei *size, ALfloat *frequency); +ALUT_API ALvoid *ALUT_APIENTRY alutLoadMemoryWaveform (ALenum waveshape, ALfloat frequency, ALfloat phase, ALfloat duration, ALenum *format, ALsizei *size, ALfloat *freq); + +ALUT_API const char *ALUT_APIENTRY alutGetMIMETypes (ALenum loader); + +ALUT_API ALint ALUT_APIENTRY alutGetMajorVersion (void); +ALUT_API ALint ALUT_APIENTRY alutGetMinorVersion (void); + +ALUT_API ALboolean ALUT_APIENTRY alutSleep (ALfloat duration); + +/* Nasty Compatibility stuff, WARNING: THESE FUNCTIONS ARE STRONGLY DEPRECATED */ +#if defined(__APPLE__) +ALUT_API ALUT_ATTRIBUTE_DEPRECATED void ALUT_APIENTRY alutLoadWAVFile (ALbyte *fileName, ALenum *format, void **data, ALsizei *size, ALsizei *frequency); +ALUT_API ALUT_ATTRIBUTE_DEPRECATED void ALUT_APIENTRY alutLoadWAVMemory (ALbyte *buffer, ALenum *format, void **data, ALsizei *size, ALsizei *frequency); +#else +ALUT_API ALUT_ATTRIBUTE_DEPRECATED void ALUT_APIENTRY alutLoadWAVFile (ALbyte *fileName, ALenum *format, void **data, ALsizei *size, ALsizei *frequency, ALboolean *loop); +ALUT_API ALUT_ATTRIBUTE_DEPRECATED void ALUT_APIENTRY alutLoadWAVMemory (ALbyte *buffer, ALenum *format, void **data, ALsizei *size, ALsizei *frequency, ALboolean *loop); +#endif +ALUT_API ALUT_ATTRIBUTE_DEPRECATED void ALUT_APIENTRY alutUnloadWAV (ALenum format, ALvoid *data, ALsizei size, ALsizei frequency); + +#if defined(__MWERKS_) + #pragma export off +#endif + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/engine/inc/uf/engine/entity/entity.h b/engine/inc/uf/engine/entity/entity.h index 433a12a3..da99d19b 100644 --- a/engine/inc/uf/engine/entity/entity.h +++ b/engine/inc/uf/engine/entity/entity.h @@ -19,7 +19,7 @@ namespace uf { public: Entity( bool = false ); virtual ~Entity(); - + template T& getParent(); template T& getRootParent(); template const T& getParent() const; @@ -28,7 +28,10 @@ namespace uf { void setParent( uf::Entity& parent = null ); void addChild( uf::Entity& child ); + void moveChild( uf::Entity& child ); + void removeChild( uf::Entity& child ); uf::Entity::container_t& getChildren(); + const uf::Entity::container_t& getChildren() const; virtual void initialize(); virtual void destroy(); diff --git a/engine/inc/uf/ext/oal/oal.h b/engine/inc/uf/ext/oal/oal.h new file mode 100644 index 00000000..730dd158 --- /dev/null +++ b/engine/inc/uf/ext/oal/oal.h @@ -0,0 +1,78 @@ +#pragma once + +#include +#if defined(UF_USE_OPENAL) + +#include +#include +#include + +#include +#include + +#include + +namespace ext { + class UF_API AL { + protected: + bool m_initialized; + ALCdevice* m_device; + ALCcontext* m_context; + public: + AL(); + ~AL(); + + bool initialize(); + bool terminate(); + + void listener( ALenum, std::vector ); + void listener( const std::string, std::vector ); + + void checkError( const std::string& = "", int = 0, const std::string& = "" ) const; + std::string getError() const; + }; + namespace al { + class UF_API Source { + protected: + ALuint m_index; + public: + Source(); + ~Source(); + + void generate(); + void destroy(); + + ALuint& getIndex(); + ALuint getIndex() const; + + void source( ALenum, std::vector ); + void source( const std::string, std::vector ); + + void source( ALenum, std::vector ); + void source( const std::string, std::vector ); + + void play(); + void stop(); + bool playing(); + }; + class UF_API Buffer { + protected: + ALuint m_index; + public: + Buffer(); + ~Buffer(); + + ALuint& getIndex(); + ALuint getIndex() const; + + void buffer(ALenum, const ALvoid*, ALsizei, ALsizei); + + void generate(); + void destroy(); + }; + } + + extern UF_API ext::AL oal; +} + +#endif \ No newline at end of file diff --git a/engine/inc/uf/ext/vorbis/vorbis.h b/engine/inc/uf/ext/vorbis/vorbis.h new file mode 100644 index 00000000..d3af874b --- /dev/null +++ b/engine/inc/uf/ext/vorbis/vorbis.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#if defined(UF_USE_VORBIS) + +#include + +#include +#include + +namespace ext { + class UF_API Vorbis { + public: + static int BUFFER; + protected: + std::vector m_buffer; + int m_format; + int m_frequency; + public: + void load( const std::string& ); + + std::vector& getBuffer(); + const std::vector& getBuffer() const; + int getFormat() const; + int getFrequency() const; + }; +} + +#endif \ No newline at end of file diff --git a/engine/inc/uf/utils/audio/audio.h b/engine/inc/uf/utils/audio/audio.h new file mode 100644 index 00000000..f4ea3b71 --- /dev/null +++ b/engine/inc/uf/utils/audio/audio.h @@ -0,0 +1,48 @@ +#pragma once + +#include + +#if defined(UF_USE_OPENAL) + +#include + +#include +#include + +#include +#include + +namespace uf { + class UF_API Audio { + protected: + std::string m_filename; + ext::al::Source m_source; + ext::al::Buffer m_buffer; + public: + Audio( const std::string& = "" ); + + bool initialized(); + bool playing(); + + void load( const std::string& = "" ); + void play(); + void stop(); + + void setPosition( const pod::Vector3& ); + void setOrientation( const pod::Quaternion<>& ); + }; + class UF_API SoundEmitter { + public: + typedef std::map container_t; + protected: + uf::SoundEmitter::container_t m_container; + public: + uf::Audio& add( const std::string& ); + uf::Audio& get( const std::string& ); + const uf::Audio& get( const std::string& ) const; + + void cleanup( bool = false ); + }; +} + +#endif \ No newline at end of file diff --git a/engine/inc/uf/utils/math/collision.h b/engine/inc/uf/utils/math/collision.h new file mode 100644 index 00000000..320f720f --- /dev/null +++ b/engine/inc/uf/utils/math/collision.h @@ -0,0 +1,174 @@ +#pragma once + +#include + +#include +#include + +// #include +namespace pod { + struct UF_API Simplex { + public: + struct UF_API SupportPoint { + pod::Vector3 a, b, v; + bool operator==( const pod::Simplex::SupportPoint& r ) const { + return v == r.v; + } + pod::Vector3 operator-( const pod::Simplex::SupportPoint& r ) const { + return v - r.v; + } + pod::Vector3 operator*( float r ) const { + return v * r; + } + pod::Vector3 operator-( const pod::Vector3& r ) const { + return v - r; + } + float dot( const pod::Vector3& r ) const { + return uf::vector::dot(v, r); + } + pod::Vector3 cross( const pod::Simplex::SupportPoint& r ) const { + return uf::vector::cross(v, r.v); + } + pod::Vector3 cross( const pod::Vector3& r ) const { + return uf::vector::cross(v, r); + } + }; + int size = 0; + pod::Simplex::SupportPoint b, c, d; + /* pod::Vector3 b, c, d; + Simplex( const pod::Vector3& = pod::Vector3(), const pod::Vector3& = pod::Vector3(), const pod::Vector3& = pod::Vector3() ); + void add( const pod::Vector3& ); + void set( const pod::Vector3& = pod::Vector3(), const pod::Vector3& = pod::Vector3(), const pod::Vector3& = pod::Vector3() ); + */ + }; +} +namespace uf { + class UF_API Collider { + protected: + public: + struct UF_API Manifold { + const uf::Collider* a; + const uf::Collider* b; + pod::Vector3 normal; + float depth; + bool colliding; + + Manifold() { + this->normal = pod::Vector3{0.0f, 0.0f, 0.0f}; + this->depth = -0.1f; + this->colliding = false; + } + Manifold( const uf::Collider& a, const uf::Collider& b ) { + this->a = &a; + this->b = &b; + this->normal = pod::Vector3{0.0f, 0.0f, 0.0f}; + this->depth = -0.1f; + this->colliding = false; + } + Manifold( const uf::Collider& a, const uf::Collider& b, const pod::Vector3& normal, float depth, bool colliding ) { + this->a = &a; + this->b = &b; + this->normal = normal; + this->depth = depth; + this->colliding = colliding; + } + }; + virtual ~Collider(); + virtual std::string type() const; + virtual pod::Vector3* expand() const = 0; + virtual pod::Vector3 support( const pod::Vector3& ) const = 0; + virtual uf::Collider::Manifold intersects( const uf::Collider& ) const; + }; + + class UF_API AABBox : public uf::Collider { + protected: + pod::Vector3 m_origin; + pod::Vector3 m_corner; + public: + AABBox( const pod::Vector3&, const pod::Vector3& ); + virtual std::string type() const; + virtual pod::Vector3* expand() const; + virtual pod::Vector3 support( const pod::Vector3& ) const; + virtual uf::Collider::Manifold intersects( const uf::AABBox& ) const; + }; + class UF_API SphereCollider : public uf::Collider { + protected: + float m_radius; + pod::Vector3 m_origin; + public: + SphereCollider( float = 1.0f, const pod::Vector3& = pod::Vector3{} ); + + float getRadius() const; + const pod::Vector3& getOrigin() const; + + void setRadius( float = 1.0f ); + void setOrigin( const pod::Vector3& ); + + virtual std::string type() const; + virtual pod::Vector3* expand() const; + virtual pod::Vector3 support( const pod::Vector3& ) const; + virtual uf::Collider::Manifold intersects( const uf::SphereCollider& ) const; + }; +/* + class UF_API MeshCollider : public uf::Collider { + protected: + uf::Mesh& mesh; + uf::Mesh::vertices_t::vector_t raw; + public: + MeshCollider( uf::Mesh& ); + + uf::Mesh& getMesh(); + const uf::Mesh& getMesh() const; + void setMesh( const uf::Mesh& ); + + virtual std::string type() const; + virtual pod::Vector3* expand() const; + virtual pod::Vector3 support( const pod::Vector3& ) const; + }; +*/ + class UF_API ModularCollider : public uf::Collider { + public: + typedef std::function function_expand_t; + typedef std::function function_support_t; + protected: + uint m_len; + pod::Vector3* m_container; + + bool m_should_free; + + uf::ModularCollider::function_expand_t m_function_expand; + uf::ModularCollider::function_support_t m_function_support; + public: + ModularCollider( uint len = 0, pod::Vector3* = NULL, bool = false, const uf::ModularCollider::function_expand_t& = NULL, const uf::ModularCollider::function_support_t& = NULL ); + ~ModularCollider(); + + void setExpand( const uf::ModularCollider::function_expand_t& = NULL ); + void setSupport( const uf::ModularCollider::function_support_t& = NULL ); + + pod::Vector3* getContainer(); + uint getSize() const; + void setContainer( pod::Vector3*, uint ); + + virtual std::string type() const; + virtual pod::Vector3* expand() const; + virtual pod::Vector3 support( const pod::Vector3& ) const; + }; + class UF_API CollisionBody { + public: + typedef std::vector container_t; + protected: + uf::CollisionBody::container_t m_container; + public: + ~CollisionBody(); + void clear(); + + void add( uf::Collider* ); + uf::CollisionBody::container_t& getContainer(); + const uf::CollisionBody::container_t& getContainer() const; + + std::size_t getSize() const; + + std::vector intersects( const uf::CollisionBody& ) const; + std::vector intersects( const uf::Collider& ) const; + }; +} \ No newline at end of file diff --git a/engine/inc/uf/utils/math/physics/pod.inl b/engine/inc/uf/utils/math/physics/pod.inl index 57563a1a..022a408f 100644 --- a/engine/inc/uf/utils/math/physics/pod.inl +++ b/engine/inc/uf/utils/math/physics/pod.inl @@ -1,8 +1,9 @@ +#include template pod::Transform& uf::physics::update( pod::Transform& transform, pod::Physics& physics ) { physics.previous = transform; if ( physics.linear.acceleration != pod::Vector3t{0,0,0} ) - physics.linear.velocity += (physics.linear.acceleration*uf::physics::time::delta); + physics.linear.velocity += (physics.linear.acceleration*uf::physics::time::delta); if ( physics.rotational.acceleration != pod::Quaternion{0,0,0,0} ) { physics.rotational.velocity = uf::quaternion::multiply(physics.rotational.velocity, physics.rotational.acceleration*uf::physics::time::delta); } diff --git a/engine/src/engine/entity/entity.cpp b/engine/src/engine/entity/entity.cpp index f623521b..d8d72b4b 100644 --- a/engine/src/engine/entity/entity.cpp +++ b/engine/src/engine/entity/entity.cpp @@ -15,9 +15,28 @@ void uf::Entity::addChild( uf::Entity& child ) { this->m_children.push_back(&child); child.setParent(*this); } +void uf::Entity::removeChild( uf::Entity& child ) { + for ( uf::Entity::container_t::iterator it = this->m_children.begin(); it != this->m_children.end(); ++it ) { + uf::Entity* entity = *it; + if ( &child == entity ) { + *it = NULL; + it = this->m_children.erase( it ); + return; + } + } +} +void uf::Entity::moveChild( uf::Entity& child ) { + if ( !child.m_parent ) return; + uf::Entity& parent = *child.m_parent; + parent.removeChild( child ); + this->addChild( child ); +} uf::Entity::container_t& uf::Entity::getChildren() { return this->m_children; } +const uf::Entity::container_t& uf::Entity::getChildren() const { + return this->m_children; +} const std::string& uf::Entity::getName() const { return this->m_name; } diff --git a/engine/src/ext/oal/oal.cpp b/engine/src/ext/oal/oal.cpp new file mode 100644 index 00000000..51771189 --- /dev/null +++ b/engine/src/ext/oal/oal.cpp @@ -0,0 +1,191 @@ +#include +#if defined(UF_USE_OPENAL) + +#include +#include + +ext::AL ext::oal; +UF_API_CALL ext::AL::AL() : m_initialized(false), m_device(NULL) { +} +ext::AL::~AL() { + this->terminate(); +} + +bool UF_API_CALL ext::AL::initialize() { +/* + this->m_device = alcOpenDevice(NULL); + if ( !this->m_device ) { this->checkError(__LINE__); + return false; + } + + ALboolean enumeration = alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT"); + if (enumeration == AL_FALSE) { this->checkError(__LINE__); + // do something + std::cout << "Device enumeration not available" << std::endl; + } + + this->m_context = alcCreateContext(this->m_device, NULL); + if ( !alcMakeContextCurrent(this->m_context) ) { + this->checkError(__LINE__); + return false; + } + return this->m_initialized = true; +*/ + bool res = this->m_initialized = (alutInit(NULL, NULL) == AL_TRUE); + this->checkError(__FUNCTION__, __LINE__); + return res; +} +bool UF_API_CALL ext::AL::terminate() { +/* + this->m_device = alcGetContextsDevice(this->m_context); + alcMakeContextCurrent(NULL); + alcDestroyContext(this->m_context); + alcCloseDevice(this->m_device); +*/ + return alutExit(); +} +void UF_API_CALL ext::AL::checkError( const std::string& function, int line, const std::string& aux ) const { + std::string error = this->getError(); + if ( error != "AL_NO_ERROR" ) std::cerr << "AL error @ " << function << ":" << line << ": "<<(aux!=""?"("+aux+") ":"")<< error << std::endl; +} +std::string UF_API_CALL ext::AL::getError() const { + ALCenum error = alGetError(); + switch (error) { + case AL_NO_ERROR: return "AL_NO_ERROR"; + case AL_INVALID_NAME: return "AL_INVALID_NAME"; // a bad name (ID) was passed to an OpenAL function + case AL_INVALID_ENUM: return "AL_INVALID_ENUM"; // an invalid enum value was passed to an OpenAL function + case AL_INVALID_VALUE: return "AL_INVALID_VALUE"; // an invalid value was passed to an OpenAL function + case AL_INVALID_OPERATION: return "AL_INVALID_OPERATION"; // the requested operation is not valid + case AL_OUT_OF_MEMORY: return "AL_OUT_OF_MEMORY"; // the requested operation resulted in OpenAL running out ofmemory + } + return "AL_UNKNOWN"; +} +void UF_API_CALL ext::AL::listener( ALenum name, std::vector parameters ) { + switch ( parameters.size() ) { + case 1: alListenerf( name, parameters[0] ); break; + case 3: alListener3f( name, parameters[0], parameters[1], parameters[2] ); break; + default: alListenerfv( name, ¶meters[0] ); break; + } + ext::oal.checkError(__FUNCTION__, __LINE__); +} +void UF_API_CALL ext::AL::listener( const std::string string, std::vector parameters ) { + if ( string == "GAIN" ) return this->listener( AL_GAIN, parameters ); + + if ( string == "POSITION" ) return this->listener( AL_POSITION, parameters ); + if ( string == "VELOCITY" ) return this->listener( AL_VELOCITY, parameters ); + + if ( string == "ORIENTATION" ) return this->listener( AL_ORIENTATION, parameters ); +} + +//////// +UF_API_CALL ext::al::Source::Source() : m_index(0) { +} +ext::al::Source::~Source() { + this->destroy(); +} + +void UF_API_CALL ext::al::Source::generate() { + if ( this->m_index ) this->destroy(); + alGenSources(1, &this->m_index); + ext::oal.checkError(__FUNCTION__, __LINE__); +} +void UF_API_CALL ext::al::Source::destroy() { + if ( this->m_index && alIsSource(this->m_index) ) { + alDeleteSources(1, &this->m_index); + ext::oal.checkError(__FUNCTION__, __LINE__); + } + this->m_index = 0; +} +ALuint& UF_API_CALL ext::al::Source::getIndex() { return this->m_index; } +ALuint UF_API_CALL ext::al::Source::getIndex() const { return this->m_index; } + +void UF_API_CALL ext::al::Source::source( ALenum name, std::vector parameters ) { + if ( !this->m_index ) this->generate(); + switch ( parameters.size() ) { + case 1: alSourcef( this->m_index, name, parameters[0] ); break; + case 3: alSource3f( this->m_index, name, parameters[0], parameters[1], parameters[2] ); break; + default: alSourcefv( this->m_index, name, ¶meters[0] ); break; + } + ext::oal.checkError(__FUNCTION__, __LINE__); +} +void UF_API_CALL ext::al::Source::source( const std::string string, std::vector parameters ) { + // alSourcef + if ( string == "PITCH" ) return this->source( AL_PITCH, parameters ); + if ( string == "GAIN" ) return this->source( AL_GAIN, parameters ); + if ( string == "MIN_GAIN" ) return this->source( AL_MIN_GAIN, parameters ); + if ( string == "MAX_GAIN" ) return this->source( AL_MAX_GAIN, parameters ); + if ( string == "MAX_DISTANCE" ) return this->source( AL_MAX_DISTANCE, parameters ); + if ( string == "ROLLOFF_FACTOR" ) return this->source( AL_ROLLOFF_FACTOR, parameters ); + if ( string == "CONE_OUTER_GAIN" ) return this->source( AL_CONE_OUTER_GAIN, parameters ); + if ( string == "CONE_INNER_ANGLE" ) return this->source( AL_CONE_INNER_ANGLE, parameters ); + if ( string == "CONE_OUTER_ANGLE" ) return this->source( AL_CONE_OUTER_ANGLE, parameters ); + if ( string == "REFERENCE_DISTANCE" ) return this->source( AL_REFERENCE_DISTANCE, parameters ); + // alSource3f + // alSourcefv + if ( string == "POSITION" ) return this->source( AL_POSITION, parameters ); + if ( string == "VELOCITY" ) return this->source( AL_VELOCITY, parameters ); + if ( string == "DIRECTION" ) return this->source( AL_DIRECTION, parameters ); +} +void UF_API_CALL ext::al::Source::source( ALenum name, std::vector parameters ) { + if ( !this->m_index ) this->generate(); + switch ( parameters.size() ) { + case 1: alSourcei( this->m_index, name, parameters[0] ); break; + case 3: alSource3i( this->m_index, name, parameters[0], parameters[1], parameters[2] ); break; + default: alSourceiv( this->m_index, name, ¶meters[0] ); break; + } + ext::oal.checkError(__FUNCTION__, __LINE__); +} +void UF_API_CALL ext::al::Source::source( const std::string string, std::vector parameters ) { + // alSourcei + if ( string == "SOURCE_RELATIVE" ) return this->source( AL_SOURCE_RELATIVE, parameters ); + if ( string == "CONE_INNER_ANGLE" ) return this->source( AL_CONE_INNER_ANGLE, parameters ); + if ( string == "CONE_OUTER_ANGLE" ) return this->source( AL_CONE_OUTER_ANGLE, parameters ); + if ( string == "LOOPING" ) return this->source( AL_LOOPING, parameters ); + if ( string == "BUFFER" ) return this->source( AL_BUFFER, parameters ); + if ( string == "SOURCE_STATE" ) return this->source( AL_SOURCE_STATE, parameters ); + // alSource3i + // alSourceiv + if ( string == "POSITION" ) return this->source( AL_POSITION, parameters ); + if ( string == "VELOCITY" ) return this->source( AL_VELOCITY, parameters ); + if ( string == "DIRECTION" ) return this->source( AL_DIRECTION, parameters ); +} +void UF_API_CALL ext::al::Source::play() { + alSourcePlay(this->m_index); ext::oal.checkError(__FUNCTION__, __LINE__, std::to_string(this->m_index)); +} +void UF_API_CALL ext::al::Source::stop() { + alSourceStop(this->m_index); ext::oal.checkError(__FUNCTION__, __LINE__, std::to_string(this->m_index)); +} +bool UF_API_CALL ext::al::Source::playing() { + ALCenum state; alGetSourcei(this->m_index, AL_SOURCE_STATE, &state); + return state == AL_PLAYING; +} + +//////// +UF_API_CALL ext::al::Buffer::Buffer() : m_index(0) { +} +ext::al::Buffer::~Buffer() { + this->destroy(); +} + +void UF_API_CALL ext::al::Buffer::generate() { + if ( this->m_index ) this->destroy(); + alGenBuffers(1, &this->m_index); + ext::oal.checkError(__FUNCTION__, __LINE__); +} +void UF_API_CALL ext::al::Buffer::destroy() { + if ( this->m_index && alIsBuffer(this->m_index) ) { + alDeleteBuffers(1, &this->m_index); + ext::oal.checkError(__FUNCTION__, __LINE__); + } + this->m_index = 0; +} +ALuint& UF_API_CALL ext::al::Buffer::getIndex() { return this->m_index; } +ALuint UF_API_CALL ext::al::Buffer::getIndex() const { return this->m_index; } + +void UF_API_CALL ext::al::Buffer::buffer(ALenum format, const ALvoid* data, ALsizei size, ALsizei frequency) { + if ( !this->m_index ) this->generate(); + alBufferData(this->m_index, format, data, size, frequency); ext::oal.checkError(__FUNCTION__, __LINE__, std::to_string(format) + " @ " + std::to_string(size) + " @ " + std::to_string(frequency)); +} + + +#endif \ No newline at end of file diff --git a/engine/src/ext/vorbis/vorbis.cpp b/engine/src/ext/vorbis/vorbis.cpp new file mode 100644 index 00000000..b2dc94c9 --- /dev/null +++ b/engine/src/ext/vorbis/vorbis.cpp @@ -0,0 +1,55 @@ +#include +#if defined(UF_USE_VORBIS) + +#include +#include +#include +#include + +int ext::Vorbis::BUFFER = 32768; + +void UF_API_CALL ext::Vorbis::load( const std::string& filename ) { + int endian = 0; + int bitStream; + long bytes; + char buffer[ext::Vorbis::BUFFER]; + FILE* fp = fopen( filename.c_str(), "rb" ); + + if ( !fp ) { + std::cerr << "Vorbis: failed to open `" << filename << "`. File error." << std::endl; + return; + } + + OggVorbis_File file; +// ov_open( fp, &file, NULL, 0 ); + if( ov_open_callbacks(fp, &file, NULL, 0, OV_CALLBACKS_DEFAULT) < 0 ) { + std::cerr << "Vorbis: failed to open `" << filename << "`. Not Ogg." << std::endl; + return; + } + + vorbis_info* info = ov_info(&file, -1); + this->m_format = info->channels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16; + this->m_frequency = info->rate; + + do { + bytes = ov_read( &file, buffer, ext::Vorbis::BUFFER, endian, 2, 1, &bitStream ); + this->m_buffer.insert( this->m_buffer.end(), buffer, buffer + bytes ); + } while ( bytes > 0 ); + + ov_clear(&file); +} + +std::vector& UF_API_CALL ext::Vorbis::getBuffer() { + return this->m_buffer; +} +const std::vector& UF_API_CALL ext::Vorbis::getBuffer() const { + return this->m_buffer; +} +int UF_API_CALL ext::Vorbis::getFormat() const { + return this->m_format; +} +int UF_API_CALL ext::Vorbis::getFrequency() const { + return this->m_frequency; +} + +#endif \ No newline at end of file diff --git a/engine/src/utils/audio/audio.cpp b/engine/src/utils/audio/audio.cpp new file mode 100644 index 00000000..7c8adf70 --- /dev/null +++ b/engine/src/utils/audio/audio.cpp @@ -0,0 +1,75 @@ +#include +#include + +#if defined(UF_USE_OPENAL) +#include +#endif + +UF_API uf::Audio::Audio( const std::string& filename ) : m_filename(filename) { +} +bool UF_API uf::Audio::initialized() { + if ( !this->m_source.getIndex() ) return false; + if ( !this->m_buffer.getIndex() ) return false; + return true; +} +bool UF_API uf::Audio::playing() { + if ( !this->initialized() ) return false; + if ( !this->m_source.playing() ) return false; + return true; +} +void UF_API uf::Audio::load( const std::string& filename ) { if ( filename != "" ) this->m_filename = filename; + std::string extension = uf::string::extension( this->m_filename ); + + std::vector buffer; ALenum format; ALsizei frequency; + if ( extension == "ogg" ) { + ext::Vorbis vorbis; vorbis.load( this->m_filename ); + + buffer = vorbis.getBuffer(); + format = vorbis.getFormat(); + frequency = vorbis.getFrequency(); + + this->m_buffer.generate(); + this->m_source.generate(); + + this->m_buffer.buffer( format, &buffer[0], buffer.size(), frequency ); + this->m_source.source( "BUFFER", std::vector{ this->m_buffer.getIndex() } ); + + this->m_source.source( "PITCH", std::vector{ 1 } ); + this->m_source.source( "GAIN", std::vector{ 1 } ); + this->m_source.source( "LOOPING", std::vector{ AL_FALSE } ); + } + +} +void UF_API uf::Audio::play() { + this->m_source.play(); +} +void UF_API uf::Audio::stop() { + this->m_source.stop(); +} +void UF_API uf::Audio::setPosition( const pod::Vector3& position ) { + this->m_source.source("POSITION", std::vector{position.x, position.y, position.z} ); +} +void UF_API uf::Audio::setOrientation( const pod::Quaternion<>& orientation ) { + +} + +uf::Audio& UF_API uf::SoundEmitter::add( const std::string& filename ) { + if ( this->m_container.find( filename ) != this->m_container.end() ) return this->get(filename); + uf::Audio& sound = this->m_container[filename]; + sound.load(filename); + return sound; +} +uf::Audio& UF_API uf::SoundEmitter::get( const std::string& filename ) { + return this->m_container[filename]; +} +const uf::Audio& UF_API uf::SoundEmitter::get( const std::string& filename ) const { + return this->m_container.at(filename); +} + +void UF_API uf::SoundEmitter::cleanup( bool purge ) { +/* + for ( uf::Audio& k : this->m_container ) { + if ( !k.playing() ) this->m_container.erase(k); + } +*/ +} \ No newline at end of file diff --git a/engine/src/utils/math/collider.cpp b/engine/src/utils/math/collider.cpp new file mode 100644 index 00000000..89b3c0d2 --- /dev/null +++ b/engine/src/utils/math/collider.cpp @@ -0,0 +1,414 @@ +#include +#include + +/* +pod::Simplex::Simplex( const pod::Vector3& b, const pod::Vector3& c, const pod::Vector3& d ) { + this->set(b, c, d); +} +void pod::Simplex::add( const pod::Vector3& a ) { + this->d = this->c; + this->c = this->b; + this->b = a; +} +void pod::Simplex::set( const pod::Vector3& b, const pod::Vector3& c, const pod::Vector3& d ) { + this->b = b; + this->c = c; + this->d = d; + if ( b != pod::Vector3{} ) this->size++; + if ( c != pod::Vector3{} ) this->size++; + if ( d != pod::Vector3{} ) this->size++; +} +*/ +uf::Collider::~Collider(){} +std::string UF_API uf::Collider::type() const { return ""; } +uf::Collider::Manifold UF_API uf::Collider::intersects( const uf::Collider& y ) const { + const uf::Collider& x = *this; + pod::Simplex simplex; + pod::Vector3 direction = pod::Vector3{ 1.0f, 0.0f, 0.0f }; + + uf::Collider::Manifold manifold(x, y); + double dot = -0.1; + uint iterations = 0; + uint iterations_cap = 25; + while ( iterations++ < iterations_cap ) { + direction = uf::vector::normalize(direction); + + pod::Simplex::SupportPoint a; + a.a = x.support(direction); + a.b = y.support(-direction); + a.v = a.a - a.b; + + if ( (dot = a.dot(direction)) < 0 ) { + return manifold; + } + if( simplex.size == 0 ) { + simplex.b = a; + + direction = direction * -1; + simplex.size = 1; + continue; + } + if ( simplex.size == 1 ) { + direction = uf::vector::cross(a.cross(simplex.b), a.v); + simplex.c = simplex.b; + simplex.b = a; + simplex.size = 2; + continue; + } + if ( simplex.size == 2 ) { + pod::Vector3 ao = a * -1; + pod::Vector3 ab = simplex.b - a; + pod::Vector3 ac = simplex.c - a; + pod::Vector3 abc = uf::vector::cross(ab, ac); + pod::Vector3 abP = uf::vector::cross(ab, abc); + if ( uf::vector::dot(abP, ao) > 0 ) { + simplex.c = simplex.b; + simplex.b = a; + + direction = uf::vector::cross(ab, ao); + continue; + } + pod::Vector3 acP = uf::vector::cross(abc, ac); + if ( uf::vector::dot(acP, ao) > 0 ) { + simplex.b = a; + + direction = uf::vector::cross(ac, ao); + continue; + } + if ( uf::vector::dot(abc, ao) > 0 ) { + simplex.d = simplex.c; + simplex.c = simplex.b; + simplex.b = a; + + direction = abc; + continue; + } + simplex.d = simplex.b; + simplex.b = a; + + direction = abc * -1; + simplex.size = 3; + continue; + } + if ( simplex.size == 3 ) { + pod::Vector3 ao = a * -1; + pod::Vector3 ab = simplex.b - a; + pod::Vector3 ac = simplex.c - a; + pod::Vector3 abc = uf::vector::cross(ab, ac); + pod::Vector3 ad, acd, adb; + if ( uf::vector::dot(abc, ao) > 0 ) { + goto check_face; + } + ad = simplex.d - a; + acd = uf::vector::cross(ac, ad); + if ( uf::vector::dot(acd, ao) > 0 ) { + simplex.b = simplex.c; + simplex.c = simplex.d; + + ab = ac; + ac = ad; + abc = acd; + + goto check_face; + } + goto EPA; + + check_face: + pod::Vector3 abP = uf::vector::cross(ab, abc); + if ( uf::vector::dot(abP, ao) > 0 ) { + simplex.c = simplex.b; + simplex.b = a; + + direction = uf::vector::cross(uf::vector::cross(ab, ao), ab); + simplex.size = 2; + continue; + } + pod::Vector3 acP = uf::vector::cross(abc, ac); + if ( uf::vector::dot(acP, ao) > 0 ) { + simplex.b = a; + direction = uf::vector::cross(uf::vector::cross(ac, ao), ac); + simplex.size = 2; + continue; + } + simplex.d = simplex.c; + simplex.c = simplex.b; + simplex.b = a; + direction = abc; + simplex.size = 3; + continue; + } + } + goto EPA; + +EPA: + manifold.colliding = true; + manifold.normal = direction; + manifold.depth = dot; + return manifold; +} +/* + +*/ +UF_API uf::AABBox::AABBox( const pod::Vector3& origin, const pod::Vector3& corner ) { + this->m_origin = origin; + this->m_corner = corner; +} +std::string UF_API uf::AABBox::type() const { return "AABBox"; } +pod::Vector3* UF_API uf::AABBox::expand() const { + pod::Vector3* raw = new pod::Vector3[8]; + raw[0] = pod::Vector3{ this->m_corner.x, this->m_corner.y, this->m_corner.z}; + raw[1] = pod::Vector3{ this->m_corner.x, this->m_corner.y, -this->m_corner.z}; + raw[2] = pod::Vector3{ -this->m_corner.x, this->m_corner.y, -this->m_corner.z}; + raw[3] = pod::Vector3{ -this->m_corner.x, this->m_corner.y, this->m_corner.z}; + raw[4] = pod::Vector3{ -this->m_corner.x, -this->m_corner.y, this->m_corner.z}; + raw[5] = pod::Vector3{ this->m_corner.x, -this->m_corner.y, this->m_corner.z}; + raw[6] = pod::Vector3{ this->m_corner.x, -this->m_corner.y, -this->m_corner.z}; + raw[7] = pod::Vector3{ -this->m_corner.x, -this->m_corner.y, this->m_corner.z}; + + for ( uint i = 0; i < 8; i++ ) raw[0] += this->m_origin; + + return raw; +} +pod::Vector3 UF_API uf::AABBox::support( const pod::Vector3& direction ) const { + pod::Vector3 res; + + res[0] = this->m_origin.x + this->m_corner.x * (direction.x >= 0 ? 1 : -1); + res[1] = this->m_origin.y + this->m_corner.y * (direction.y >= 0 ? 1 : -1); + res[2] = this->m_origin.z + this->m_corner.z * (direction.z >= 0 ? 1 : -1); + + return res; +} + +uf::Collider::Manifold UF_API uf::AABBox::intersects( const uf::AABBox& b ) const { + const uf::AABBox& a = *this; + uf::Collider::Manifold manifold(a, b); + + float a_left = a.m_origin.x - a.m_corner.x; + float a_right = a.m_origin.x + a.m_corner.x; + float a_bottom = a.m_origin.y - a.m_corner.y; + float a_top = a.m_origin.y + a.m_corner.y; + float a_back = a.m_origin.z - a.m_corner.z; + float a_front = a.m_origin.z + a.m_corner.z; + + + float b_left = b.m_origin.x - b.m_corner.x; + float b_right = b.m_origin.x + b.m_corner.x; + float b_bottom = b.m_origin.y - b.m_corner.y; + float b_top = b.m_origin.y + b.m_corner.y; + float b_back = b.m_origin.z - b.m_corner.z; + float b_front = b.m_origin.z + b.m_corner.z; + + if ( a_right < b_left ) return manifold; + if ( a_left > b_right ) return manifold; + + if ( a_top < b_bottom ) return manifold; + if ( a_bottom > b_top ) return manifold; + + if ( a_front < b_back ) return manifold; + if ( a_back > b_front ) return manifold; + + pod::Vector3* a_points = a.expand(); + pod::Vector3* b_points = b.expand(); + + float smallest = 9E9; + for ( uint b = 0; b < 8; b++ ) { + for ( uint a = 0; a < 8; a++ ) { + float distance = uf::vector::distanceSquared(a_points[a], b_points[b]); + if ( smallest > distance ) smallest = distance; + } + } + delete[] a_points; + delete[] b_points; + + manifold.depth = sqrt(smallest); + manifold.normal = b.m_origin - a.m_origin; + manifold.colliding = true; + + return manifold; +} +/* + +*/ +UF_API uf::SphereCollider::SphereCollider( float r, const pod::Vector3& origin ) { + this->m_radius = r; + this->m_origin = origin; +} +std::string UF_API uf::SphereCollider::type() const { return "Sphere"; } +float UF_API uf::SphereCollider::getRadius() const { + return this->m_radius; +} +const pod::Vector3& UF_API uf::SphereCollider::getOrigin() const { + return this->m_origin; +} + +void UF_API uf::SphereCollider::setRadius( float r ) { + this->m_radius = r; +} +void UF_API uf::SphereCollider::setOrigin( const pod::Vector3& origin ) { + this->m_origin = origin; +} + +pod::Vector3* UF_API uf::SphereCollider::expand() const { + return NULL; +} +pod::Vector3 UF_API uf::SphereCollider::support( const pod::Vector3& direction ) const { + return this->m_origin + direction * (this->m_radius/uf::vector::magnitude(direction)); +} +uf::Collider::Manifold uf::SphereCollider::intersects( const uf::SphereCollider& b ) const { + const uf::SphereCollider& a = *this; + uf::Collider::Manifold manifold(a, b); + float distance = uf::vector::distance(a.m_origin, b.m_origin); + float sum = a.m_radius + b.m_radius; + + if ( distance >= sum ) return manifold; + + manifold.depth = fabs(b.m_radius - a.m_radius); + manifold.normal = b.m_origin - a.m_origin; + manifold.colliding = true; + return manifold; +} +/* + +*/ +/* +uf::MeshCollider::MeshCollider( uf::Mesh& mesh ) : mesh(mesh) { + const uf::Mesh::vertices_t verts = this->m_mesh.getVertices(); + this->m_raw = verts.get(); +} +std::string UF_API uf::Collider::type() const { return "Mesh"; } +uf::Mesh& uf::MeshCollider::getMesh() { + return this->m_mesh; +} +const uf::Mesh& uf::MeshCollider::getMesh() const { + return this->m_mesh; +} +void uf::MeshCollider::setMesh( const uf::Mesh& mesh ) { + this->m_mesh = mesh; + const uf::Mesh::vertices_t verts = this->m_mesh.getVertices(); + this->m_raw = verts.get(); +} + +pod::Vector3* uf::MeshCollider::expand() const { + return (pod::Vector3*) &this->m_raw[0]; +} +pod::Vector3 uf::MeshCollider::support( const pod::Vector3& direction ) const { + uint len = this->m_raw.size(); + pod::Vector3* points = this->m_expand(); + + uint best = 0; + float best_dot = points[0].dot(direction); + + for ( uint i = 1; i < len; i++ ) { + float dot = points[i].dot(direction); + if ( dot > best_dot ) { + best = i; + best_dot = dot; + } + } + return points[best]; +} +*/ +/* + +*/ +UF_API uf::ModularCollider::ModularCollider( uint len, pod::Vector3* container, bool should_free, const uf::ModularCollider::function_expand_t& expand, const uf::ModularCollider::function_support_t& support ) { + this->m_len = len; + this->m_container = container; + this->m_should_free = should_free; + this->m_function_expand = expand; + this->m_function_support = support; +} +UF_API uf::ModularCollider::~ModularCollider() { + if ( this->m_container != NULL && this->m_should_free ) delete[] this->m_container; +} +std::string UF_API uf::ModularCollider::type() const { return "Modular"; } +void UF_API uf::ModularCollider::setExpand( const uf::ModularCollider::function_expand_t& expand ) { + this->m_function_expand = expand; +} +void UF_API uf::ModularCollider::setSupport( const uf::ModularCollider::function_support_t& support ) { + this->m_function_support = support; +} + +pod::Vector3* UF_API uf::ModularCollider::getContainer() { + return this->m_container; +} +uint UF_API uf::ModularCollider::getSize() const { + return this->m_len; +} +void UF_API uf::ModularCollider::setContainer( pod::Vector3* container, uint len ) { + this->m_container = container; + this->m_len = len; +} + +pod::Vector3* UF_API uf::ModularCollider::expand() const { + return this->m_function_expand ? this->m_function_expand() : this->m_container; +} +pod::Vector3 UF_API uf::ModularCollider::support( const pod::Vector3& direction ) const { + if ( this->m_function_support ) return this->m_function_support(direction); + uint len = this->m_len; + pod::Vector3* points = this->expand(); + + uint best = 0; + float best_dot = uf::vector::dot(points[0], direction); + + for ( uint i = 1; i < len; i++ ) { + float dot = uf::vector::dot(points[i], direction); + if ( dot > best_dot ) { + best = i; + best_dot = dot; + } + } + return points[best]; +} + +uf::CollisionBody::~CollisionBody() { + this->clear(); +} +void UF_API uf::CollisionBody::clear() { + for ( uf::Collider* pointer : this->m_container ) delete pointer; + this->m_container.clear(); +} + +void UF_API uf::CollisionBody::add( uf::Collider* pointer ) { + this->m_container.push_back(pointer); +} +uf::CollisionBody::container_t& UF_API uf::CollisionBody::getContainer() { + return this->m_container; +} +const uf::CollisionBody::container_t& UF_API uf::CollisionBody::getContainer() const { + return this->m_container; +} + +std::size_t UF_API uf::CollisionBody::getSize() const { + return this->m_container.size(); +} + +std::vector UF_API uf::CollisionBody::intersects( const uf::CollisionBody& body ) const { + std::vector manifolds; + for ( const uf::Collider* pointer : body.m_container ) { + std::vector result = this->intersects( *pointer ); + manifolds.insert( manifolds.end(), result.begin(), result.end() ); + } + return manifolds; +} + +std::vector UF_API uf::CollisionBody::intersects( const uf::Collider& body ) const { + std::vector manifolds; + for ( const uf::Collider* pointer : this->m_container ) { + uf::Collider::Manifold manifold; + if ( pointer->type() == body.type() ) { + if ( pointer->type() == "AABBox" ) { + const uf::AABBox& a = *((const uf::AABBox*) pointer); + const uf::AABBox& b = *((const uf::AABBox*) &body); + manifold = a.intersects(b); + } else if ( pointer->type() == "Sphere" ) { + const uf::SphereCollider& a = *((const uf::SphereCollider*) pointer); + const uf::SphereCollider& b = *((const uf::SphereCollider*) &body); + manifold = a.intersects(b); + } + else manifold = pointer->intersects( body ); + } else manifold = pointer->intersects( body ); + manifolds.push_back( manifold ); + } + return manifolds; +} \ No newline at end of file diff --git a/ext/inits/camera.inl b/ext/inits/camera.inl deleted file mode 100644 index 2460e57d..00000000 --- a/ext/inits/camera.inl +++ /dev/null @@ -1,110 +0,0 @@ -#pragma once - -/* Load camera */ { - struct { - uf::Serializer file; - uf::Serializer fallback; - uf::Serializer merged; - uf::Serializer sys = ext::getConfig(); - struct { - uf::Serializer file, embedded; - } fallbacks; - } config; - struct { - bool exists = false; - std::string directory = "cfg/"; - std::string localFilename = "./camera.json"; - std::string filename = directory + localFilename; - } file; - /* Read from file */ { - file.exists = config.file.readFromFile(file.filename); - } - /* Initialize fallback */ { - config.fallback["fov"] = 90.0; - config.fallback["clip"]["near"] = 0.01; - config.fallback["clip"]["far"] = 100.0; - config.fallback["size"] = config.sys["window"]["size"]; - config.fallback["size"]["auto"] = true; - - config.fallback["position"]["x"] = 0; - config.fallback["position"]["y"] = 0; - config.fallback["position"]["z"] = 0; - - config.fallback["orientation"]["x"] = 0; - config.fallback["orientation"]["y"] = 0; - config.fallback["orientation"]["z"] = 0; - config.fallback["orientation"]["w"] = 1.0; - - config.fallback["up"]["x"] = 0; - config.fallback["up"]["y"] = 1; - config.fallback["up"]["z"] = 0; - - config.fallback["right"]["x"] = 1; - config.fallback["right"]["y"] = 0; - config.fallback["right"]["z"] = 0; - - config.fallback["forward"]["x"] = 0; - config.fallback["forward"]["y"] = 0; - config.fallback["forward"]["z"] = 1; - - config.fallback["offset"]["x"] = 0; - config.fallback["offset"]["y"] = 0; - config.fallback["offset"]["z"] = 0; - } - - /* Merge */ if ( file.exists ){ - config.merged = config.file; - config.merged.merge( config.fallback, true ); - } else { - config.merged = config.fallback; - } - /* if ( file.exists ) */ { - struct { - pod::Math::num_t fov; - pod::Vector2 size; - pod::Vector2 bounds; - pod::Vector3 offset; - pod::Vector3 offsetScale; - } settings; - settings.fov = config.merged["fov"].asDouble(); - settings.bounds.x = config.merged["clip"]["near"].asDouble(); - settings.bounds.y = config.merged["clip"]["far"].asDouble(); - - if ( config.merged["size"]["auto"].asBool() ) { - config.merged["size"]["x"] = config.fallback["size"]["x"]; - config.merged["size"]["y"] = config.fallback["size"]["y"]; - } - settings.size.x = config.merged["size"]["x"].asDouble(); - settings.size.y = config.merged["size"]["y"].asDouble(); - - settings.offset.x = config.merged["offset"]["x"].asDouble(); - settings.offset.y = config.merged["offset"]["y"].asDouble(); - settings.offset.z = config.merged["offset"]["z"].asDouble(); - - settings.offset.x = config.merged["offset"]["x"].asDouble(); - settings.offset.y = config.merged["offset"]["y"].asDouble(); - settings.offset.z = config.merged["offset"]["z"].asDouble(); - - pod::Transform<>& transform = ::world.master.getPlayer().getComponent>(); - /* Transform initialization */ { - transform.position.x = config.merged["position"]["x"].asDouble(); - transform.position.y = config.merged["position"]["y"].asDouble(); - transform.position.z = config.merged["position"]["z"].asDouble(); - - transform.orientation.x = config.merged["orientation"]["x"].asDouble(); - transform.orientation.y = config.merged["orientation"]["y"].asDouble(); - transform.orientation.z = config.merged["orientation"]["z"].asDouble(); - transform.orientation.w = config.merged["orientation"]["w"].asDouble(); - } - - uf::Camera& camera = ::world.master.getPlayer().getComponent(); - camera.setFov(settings.fov); - camera.setSize(settings.size); - camera.setOffset(settings.offset); - camera.update(true); - - } - /* Write default to file */ { - // config.merged.writeToFile(file.filename); - } -} \ No newline at end of file diff --git a/ext/inits/hooks.inl b/ext/inits/hooks.inl deleted file mode 100644 index 559bbd38..00000000 --- a/ext/inits/hooks.inl +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -/* Initialize hooks */ { - if ( persistent.hook.mode == "Both" || persistent.hook.mode == "Readable" ) { - uf::hooks.addHook( "system:Tick", [&](const std::string& event)->std::string{ - times.prevTime = times.curTime; - times.curTime = times.sys.elapsed().asDouble(); - times.deltaTime = times.curTime - times.prevTime; - return "true"; - }); - uf::hooks.addHook( "window:Text.Entered", [&](const std::string& event)->std::string{ - uf::Serializer json = event; - - uint32_t utf32 = json["text"]["uint32_t"].asUInt64(); - if ( utf32 == '\n' || utf32 == '\r' ) io.input += '\n'; - else if ( utf32 == '\b' ) io.input--; - else io.input += utf32; - - return "true"; - } ); - uf::hooks.addHook( "window:Title.Changed", [&](const std::string& event)->std::string{ - uf::Serializer json = event; - if ( json["invoker"] != "ext") persistent.window.title = json["window"]["title"].asString(); - return "true"; - } ); - } -} \ No newline at end of file diff --git a/ext/main.cpp b/ext/main.cpp index 3a954ee4..5baa7a70 100644 --- a/ext/main.cpp +++ b/ext/main.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include diff --git a/ext/world/body/body.cpp b/ext/world/body/body.cpp deleted file mode 100644 index ab0c0141..00000000 --- a/ext/world/body/body.cpp +++ /dev/null @@ -1 +0,0 @@ -// \ No newline at end of file diff --git a/ext/world/body/body.h b/ext/world/body/body.h deleted file mode 100644 index 3dedf39f..00000000 --- a/ext/world/body/body.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include -#include -#include - -#include -#include - -namespace ext { - class EXT_API Body { - public: - void setBounds( const uf::Mesh& ); - - int collide( const ext::Body& ) const; - bool elastic() const; - }; -} \ No newline at end of file diff --git a/ext/world/craeture/craeture.cpp b/ext/world/craeture/craeture.cpp index af45a458..925fa428 100644 --- a/ext/world/craeture/craeture.cpp +++ b/ext/world/craeture/craeture.cpp @@ -14,17 +14,20 @@ namespace { void ext::Craeture::initialize() { ext::Object::initialize(); + this->addComponent(); this->addComponent>(); - this->addComponent(); { - pod::Transform<>& transform = this->getComponent>(); - transform = uf::transform::initialize(transform); + this->addComponent(); + + pod::Transform<>& transform = this->getComponent>(); + transform = uf::transform::initialize(transform); { this->getComponent().getTransform().reference = this->getComponentPointer>(); } + pod::Physics& physics = this->getComponent(); physics.linear.velocity = {0,0,0}; - physics.linear.acceleration = {0,0,0}; + physics.linear.acceleration = {0,-9.81,0}; physics.rotational.velocity = uf::quaternion::axisAngle( {0,1,0}, (pod::Math::num_t) 0 ); physics.rotational.acceleration = {0,0,0,0}; @@ -34,6 +37,9 @@ void ext::Craeture::initialize() { if ( this->m_animation.transforms.find(name) == this->m_animation.transforms.end() ) this->m_animation.transforms[name]; } } + /* Collider */ { + uf::CollisionBody& collider = this->getComponent(); + } } void ext::Craeture::tick() { ext::Object::tick(); @@ -44,6 +50,44 @@ void ext::Craeture::tick() { if ( it->asBool() ) serializer["animation"]["status"]["rest"] = false; } this->animate(); + + if ( uf::Window::isKeyPressed("P") ) { + pod::Transform<> transform = uf::transform::flatten(this->getComponent().getTransform()); + std::cout << transform.position.x << ", " << transform.position.y << ", " << transform.position.z << std::endl; + } + + /* Collision */ if ( this->m_parent ) { + uf::Entity& parent = this->getParent(); + if ( this->hasComponent() && parent.hasComponent() ) { + uf::CollisionBody& collider = this->getComponent(); + uf::CollisionBody& pCollider = parent.getComponent(); + + pod::Transform<>& transform = this->getComponent>(); { + collider.clear(); + uf::Collider* box = new uf::AABBox( uf::vector::add({0, 1.5, 0}, transform.position), {0.5, 1.5, 0.5} ); + collider.add(box); + } + + pod::Physics& physics = this->getComponent(); + auto result = pCollider.intersects(collider); + uf::Collider::Manifold strongest; + for ( auto manifold : result ) { + if ( manifold.colliding && manifold.depth > 0 ) { + if ( strongest.depth < manifold.depth ) strongest = manifold; + pod::Vector3 mag = uf::vector::normalize(manifold.normal * manifold.depth) * pod::Vector3{0.02, 0.0005, 0.02}; + transform.position += mag; + + // transform = physics.previous; + } + } + if ( strongest.colliding && strongest.depth > 0 ) { + // std::cout << "Collision!\n\tNormal: " << strongest.normal.x << ", " << strongest.normal.y << ", " << strongest.normal.z << "\n\tDepth: " << strongest.depth << std::endl; + physics.linear.velocity = {0,0,0}; + } else { + physics.linear.acceleration = {0,-9.81,0}; + } + } + } } void ext::Craeture::render() { if ( !this->m_parent ) return; diff --git a/ext/world/gui/gui.cpp b/ext/world/gui/gui.cpp index 7e023f6c..160fd1b7 100644 --- a/ext/world/gui/gui.cpp +++ b/ext/world/gui/gui.cpp @@ -81,16 +81,16 @@ void ext::Gui::render() { shader.bind(); { int i = 0; for ( auto& texture : buffer.getBuffers() ) { texture.bind(i); - shader.push("buffer_"+texture.getName(), i++); + shader.push("buffers."+texture.getName(), i++); } - texture.bind(i); - shader.push("gui_element", i++); - shader.push("offset", offset); - shader.push("model", matrix); + texture.bind(i); shader.push("gui.texture", i++); + shader.push("gui.offset", offset); + shader.push("parameters.window", camera.getSize()); + shader.push("parameters.depth", metadata["gui"]["depth"].asBool()); + shader.push("matrices.model", matrix); if ( metadata["gui"]["world"].asBool() ) { - shader.push("projection", camera.getProjection()); - shader.push("view", camera.getView()); - shader.push("model", matrix); + shader.push("matrices.projection", camera.getProjection()); + shader.push("matrices.view", camera.getView()); } } diff --git a/ext/world/light/light.cpp b/ext/world/light/light.cpp index 53fc3916..7317b386 100644 --- a/ext/world/light/light.cpp +++ b/ext/world/light/light.cpp @@ -14,6 +14,24 @@ const pod::Vector3& ext::Light::getColor() const { void ext::Light::setColor( const pod::Vector3& color ) { this->m_color = color; } +const pod::Vector3& ext::Light::getSpecular() const { + return this->m_specular; +} +void ext::Light::setSpecular( const pod::Vector3& specular ) { + this->m_specular = specular; +} +float ext::Light::getAttenuation() const { + return this->m_attenuation; +} +void ext::Light::setAttenuation( float attenuation ) { + this->m_attenuation = attenuation; +} +float ext::Light::getPower() const { + return this->m_power; +} +void ext::Light::setPower( float power ) { + this->m_power = power; +} void ext::Light::initialize() { this->addComponent(); { @@ -75,6 +93,22 @@ void ext::Light::initialize() { camera.update(true); metadata["light"]["state"] = 0; + + /* Attenuation */ { + if ( metadata["light"]["attenuation"] != Json::nullValue ) this->setAttenuation( metadata["light"]["attenuation"].asFloat() ); + } + /* Power */ { + if ( metadata["light"]["power"] != Json::nullValue ) this->setPower(metadata["light"]["power"].asFloat() ); + } + /* Specular */ { + if ( metadata["light"]["specular"] != Json::nullValue ) { + pod::Vector3 specular; + specular.x = metadata["light"]["specular"][0].asDouble(); + specular.y = metadata["light"]["specular"][1].asDouble(); + specular.z = metadata["light"]["specular"][2].asDouble(); + this->setSpecular(specular); + } + } if ( metadata["light"]["dedicated"].asBool() ) { uf::GeometryBuffer& buffer = this->getComponent(); { diff --git a/ext/world/light/light.h b/ext/world/light/light.h index 941f4e21..1c16dbfd 100644 --- a/ext/world/light/light.h +++ b/ext/world/light/light.h @@ -17,6 +17,9 @@ namespace ext { class EXT_API Light : public ext::Object { protected: pod::Vector3 m_color = {1, 1, 1}; + pod::Vector3 m_specular = {1, 1, 1}; + float m_attenuation = 0.00125f; + float m_power = 100.0f; uint m_state = 0; public: void initialize(); @@ -25,5 +28,14 @@ namespace ext { void setColor( const pod::Vector3& ); const pod::Vector3& getColor() const; + + void setSpecular( const pod::Vector3& ); + const pod::Vector3& getSpecular() const; + + void setAttenuation( float ); + float getAttenuation() const; + + void setPower( float ); + float getPower() const; }; } \ No newline at end of file diff --git a/ext/world/object/object.h b/ext/world/object/object.h index 1ba0b968..c7831576 100644 --- a/ext/world/object/object.h +++ b/ext/world/object/object.h @@ -12,6 +12,7 @@ #include #include +#include namespace ext { class EXT_API Object : public uf::Entity { diff --git a/ext/world/player/player.cpp b/ext/world/player/player.cpp index 6f728cea..5b41f0c9 100644 --- a/ext/world/player/player.cpp +++ b/ext/world/player/player.cpp @@ -6,6 +6,7 @@ #include #include #include +#include namespace { bool lockMouse = true; @@ -213,6 +214,23 @@ void ext::Player::tick() { serializer["animation"]["status"]["rest"] = true; } + if ( walking ) { + uf::SoundEmitter& emitter = this->getComponent(); + int cycle = rand() % serializer["audio"]["footsteps"].size(); + std::string filename = serializer["audio"]["footsteps"][cycle].asString(); + uf::Audio& footstep = emitter.add(filename); + + bool playing = false; + for ( uint i = 0; i < serializer["audio"]["footsteps"].size(); ++i ) { + uf::Audio& audio = emitter.add(serializer["audio"]["footsteps"][i].asString()); + if ( audio.playing() ) playing = true; + } + if ( !playing ) { + footstep.play(); + footstep.setPosition( transform.position ); + } + } + /* Lock Mouse */ { static uf::Timer timer(false); if ( !timer.running() ) timer.start(); diff --git a/ext/world/terrain/generator.cpp b/ext/world/terrain/generator.cpp index f4fe2cf6..bda46c6b 100644 --- a/ext/world/terrain/generator.cpp +++ b/ext/world/terrain/generator.cpp @@ -27,14 +27,13 @@ void ext::TerrainGenerator::destroy(){ if ( !this->m_voxels ) return; this->m_voxels = NULL; } void ext::TerrainGenerator::generate(){ if ( this->m_voxels ) return; - this->m_voxels = new ext::TerrainVoxel::uid_t**[this->m_size.x]; - struct { ext::TerrainVoxel::uid_t floor = ext::TerrainVoxelFloor().uid(); ext::TerrainVoxel::uid_t wall = ext::TerrainVoxelWall().uid(); ext::TerrainVoxel::uid_t ceiling = ext::TerrainVoxelCeiling().uid(); } atlas; + this->m_voxels = new ext::TerrainVoxel::uid_t**[this->m_size.x]; for ( uint x = 0; x < this->m_size.x; ++x ) { this->m_voxels[x] = new ext::TerrainVoxel::uid_t*[this->m_size.y]; for ( uint y = 0; y < this->m_size.y; ++y ) { this->m_voxels[x][y] = new ext::TerrainVoxel::uid_t[this->m_size.z]; for ( uint z = 0; z < this->m_size.z; ++z ) { ext::TerrainVoxel::uid_t voxel = 0; @@ -48,12 +47,17 @@ void ext::TerrainGenerator::generate(){ if ( this->m_voxels ) return; if ( z > 4 && z < this->m_size.z - 4 ) voxel = 0; } + // if ( x > 2 && x < 6 && z > 2 && z < 6 ) voxel = atlas.wall; // if ( y > 3 ) voxel = 0; + this->m_voxels[x][y][z] = voxel; } } } } +ext::TerrainVoxel::uid_t*** ext::TerrainGenerator::getVoxels() { + return this->m_voxels; +} void ext::TerrainGenerator::rasterize( uf::Mesh& mesh, const ext::Region& region ){ if ( !this->m_voxels ) this->generate(); diff --git a/ext/world/terrain/generator.h b/ext/world/terrain/generator.h index 8ba38cd3..2576de88 100644 --- a/ext/world/terrain/generator.h +++ b/ext/world/terrain/generator.h @@ -20,5 +20,6 @@ namespace ext { void generate(); void rasterize( uf::Mesh&, const ext::Region& ); + ext::TerrainVoxel::uid_t*** getVoxels(); }; } \ No newline at end of file diff --git a/ext/world/terrain/region.cpp b/ext/world/terrain/region.cpp index 62ee3d46..24a93b43 100644 --- a/ext/world/terrain/region.cpp +++ b/ext/world/terrain/region.cpp @@ -27,12 +27,13 @@ void ext::Region::load() { size.z = metadata["region"]["size"][2].asUInt(); } generator.initialize(size); + generator.generate(); float r = (rand() % 100) / 100.0; - bool addLight = r > 0.95; - if ( metadata["region"]["location"][0].asInt() == 0 && metadata["region"]["location"][1].asInt() == 0 && metadata["region"]["location"][2].asInt() == 0 ) addLight = true; + bool addLight = r < metadata["region"]["light"]["random"].asFloat(); +// if ( metadata["region"]["location"][0].asInt() == 0 && metadata["region"]["location"][1].asInt() == 0 && metadata["region"]["location"][2].asInt() == 0 ) addLight = true; // if ( metadata["region"]["location"][0].asInt() % 2 != 0 || metadata["region"]["location"][2].asInt() % 2 != 0 ) addLight = false; - static bool first = false; if ( !first ) first = addLight = true; else addLight = false; +// static bool first = false; if ( !first ) first = addLight = true; else addLight = false; // addLight = false; if ( addLight ) { // std::cout << metadata["region"]["location"][0] << ", " << metadata["region"]["location"][1] << ", " << metadata["region"]["location"][2] << std::endl; @@ -43,7 +44,7 @@ void ext::Region::load() { color = uf::vector::normalize( color ); } - int radius = 3; + int radius = metadata["region"]["light"]["radius"].asInt(); for ( int i = 0; i < radius; ++i ) { uf::Entity* entity = new ext::Light; if ( !((ext::Object*) entity)->load("./light/config.json") ) { uf::iostream << "Error loading `" << "./light/config.json" << "!" << "\n"; delete entity; return; } @@ -51,44 +52,47 @@ void ext::Region::load() { entity->initialize(); pod::Transform<>& parent = this->getComponent>(); - pod::Transform<>& transform = entity->getComponent().getTransform(); + pod::Transform<>& transform = entity->getComponent>();//entity->getComponent().getTransform(); + entity->getComponent().getTransform().reference = &transform; transform = uf::transform::initialize( transform ); transform.position = parent.position; - transform.position.y += size.y / 3 * 2; + transform.position.y += size.y / 2; uf::transform::rotate( transform, transform.up, (360.0 / radius) * (3.1415926/180.0) * i ); entity->getComponent().update(true); ((ext::Light*)entity)->setColor( color ); } - /* Up */ if ( false ) { + /* Up */ if ( metadata["region"]["light"]["up"].asBool() ) { uf::Entity* entity = new ext::Light; if ( !((ext::Object*) entity)->load("./light/config.json") ) { uf::iostream << "Error loading `" << "./light/config.json" << "!" << "\n"; delete entity; return; } this->addChild(*entity); entity->initialize(); pod::Transform<>& parent = this->getComponent>(); - pod::Transform<>& transform = entity->getComponent().getTransform(); + pod::Transform<>& transform = entity->getComponent>();//entity->getComponent().getTransform(); + entity->getComponent().getTransform().reference = &transform; transform = uf::transform::initialize( transform ); transform.position = parent.position; - transform.position.y += size.y / 3 * 2; + transform.position.y += size.y / 2; uf::transform::rotate( transform, transform.right, 1.5708 * 1 ); entity->getComponent().setFov(120); entity->getComponent().update(true); ((ext::Light*)entity)->setColor( color ); } - /* Down */ if ( false ) { + /* Down */ if ( metadata["region"]["light"]["down"].asBool() ) { uf::Entity* entity = new ext::Light; if ( !((ext::Object*) entity)->load("./light/config.json") ) { uf::iostream << "Error loading `" << "./light/config.json" << "!" << "\n"; delete entity; return; } this->addChild(*entity); entity->initialize(); pod::Transform<>& parent = this->getComponent>(); - pod::Transform<>& transform = entity->getComponent().getTransform(); + pod::Transform<>& transform = entity->getComponent>();//entity->getComponent().getTransform(); + entity->getComponent().getTransform().reference = &transform; transform = uf::transform::initialize( transform ); transform.position = parent.position; - transform.position.y += size.y / 3 * 2; + transform.position.y += size.y / 2; uf::transform::rotate( transform, transform.right, 1.5708 * 3 ); entity->getComponent().setFov(120); entity->getComponent().update(true); @@ -96,9 +100,40 @@ void ext::Region::load() { } } + + /* Collider */ { + pod::Transform<>& transform = this->getComponent>(); + uf::CollisionBody& collider = this->getComponent(); +/* + uf::Collider* box = new uf::AABBox( uf::vector::add({0, 1, 0}, transform.position), {0.5, 0.5, 0.5} ); + // uf::Collider* box = new uf::SphereCollider( 1, uf::vector::add({0, 1, 0}, transform.position) ); + collider.add(box); +*/ + auto*** voxels = generator.getVoxels(); + for ( uint x = 0; x < size.x; ++x ) { + for ( uint y = 0; y < size.y; ++y ) { + for ( uint z = 0; z < size.z; ++z ) { + pod::Vector3 offset = transform.position; + offset.x += x - (size.x / 2.0f); + offset.y += y; // - (size.y / 2.0f); + offset.z += z - (size.z / 2.0f); + + const ext::TerrainVoxel& voxel = ext::TerrainVoxel::atlas(voxels[x][y][z]); + + if ( !voxel.opaque() ) continue; + + uf::Collider* box = new uf::AABBox( offset, {0.5, 0.5, 0.5} ); + collider.add(box); + } + } + } + } + // generator.rasterize(mesh, *this); } void ext::Region::render() { + uf::Entity::render(); + if ( !this->m_parent ) return; ext::World& parent = this->getRootParent(); diff --git a/ext/world/terrain/terrain.cpp b/ext/world/terrain/terrain.cpp index 25ffc30a..32497551 100644 --- a/ext/world/terrain/terrain.cpp +++ b/ext/world/terrain/terrain.cpp @@ -52,12 +52,52 @@ void ext::Terrain::tick() { generator.rasterize(mesh, *kv); } } + + this->relocatePlayer(); } void ext::Terrain::render() { if ( !this->m_parent ) return; if ( this->m_children.empty() ) return; uf::Entity::render(); } +void ext::Terrain::relocatePlayer() { + ext::World& parent = this->getRootParent(); + ext::Player& player = parent.getPlayer(); + const pod::Transform<>& transform = player.getComponent>(); + uf::Serializer& metadata = this->getComponent(); + pod::Vector3ui size = { + metadata["region"]["size"][0].asUInt(), + metadata["region"]["size"][1].asUInt(), + metadata["region"]["size"][2].asUInt(), + }; + pod::Vector3 pointf = uf::vector::divide(transform.position, {size.x, size.y, size.z}); + pod::Vector3i point = { + (int) (pointf.x + (pointf.x > 0 ? 0.5 : -0.5)), + (int) (pointf.y + (pointf.y > 0 ? 0.5 : -0.5)), + (int) (pointf.z + (pointf.z > 0 ? 0.5 : -0.5)), + }; + + + if ( !this->exists(point) ) return; // oops + ext::Region& region = *this->at(point); + bool should = false; + if ( player.getParent().getName() != "Region" ) should = true; + else { + ext::Region& current = player.getParent(); + const pod::Transform<>& t = current.getComponent>(); + pod::Vector3i location = { + (int) (t.position.x / size.x), + (int) (t.position.y / size.y), + (int) (t.position.z / size.z), + }; + if ( !uf::vector::equals( point, location ) ) should = true; + } + if ( should ) { + region.moveChild(player); + std::cout << "Relocating to (" << point.x << ", " << point.y << ", " << point.z << ")" << std::endl; + } +} + bool ext::Terrain::exists( const pod::Vector3i& position ) const { const uf::Serializer& metadata = this->getComponent(); pod::Vector3i size = { @@ -77,6 +117,7 @@ bool ext::Terrain::exists( const pod::Vector3i& position ) const { } return false; } + bool ext::Terrain::inBounds( const pod::Vector3i& position ) const { const ext::World& parent = this->getRootParent(); const pod::Transform<>& player = parent.getPlayer().getComponent>(); @@ -202,6 +243,18 @@ void ext::Terrain::degenerate( const pod::Vector3i& position ) { (int) (transform.position.z / size.z), }; if ( uf::vector::equals( location, position ) ) { + for ( uf::Entity* e : kv->getChildren() ) if ( e->getName() == "Player" ) { + this->getRootParent().moveChild(*e); + std::cout << "Emergency Provisions" << std::endl; + std::function recurse = [&]( const uf::Entity* parent, int indent ) { + for ( const uf::Entity* entity : parent->getChildren() ) { + for ( int i = 0; i < indent; ++i ) std::cout<<"\t"; + std::cout<getName()<getRootParent(), 0); + std::cout << "Emergency Provisions" << std::endl; + } delete kv; *it = NULL; this->m_children.erase(it); // uf::iostream << "Degenerating Region @ ( " << position.x << ", " << position.y << ", " << position.z << ")" << "\n"; diff --git a/ext/world/terrain/terrain.h b/ext/world/terrain/terrain.h index 8e8f95c4..26969587 100644 --- a/ext/world/terrain/terrain.h +++ b/ext/world/terrain/terrain.h @@ -23,6 +23,8 @@ namespace ext { void render(); void tick(); + void relocatePlayer(); + bool exists( const pod::Vector3i& ) const; bool inBounds( const pod::Vector3i& ) const; ext::Region* at( const pod::Vector3i& ) const; diff --git a/ext/world/world.cpp b/ext/world/world.cpp index ce841cc1..02f0ea32 100644 --- a/ext/world/world.cpp +++ b/ext/world/world.cpp @@ -9,6 +9,8 @@ #include "./light/light.h" #include "./gui/gui.h" +#include + namespace { uf::Camera* camera; uf::GeometryBuffer light; @@ -21,10 +23,14 @@ void ext::World::initialize() { } void ext::World::tick() { + static bool first = true; if ( first ) { first = false; + uf::physics::tick(); + } + uf::Entity::tick(); { - static float x = 6.66992, y = 24.7805; + static float x = 1.07986, y = 24.7805; if ( uf::Window::isKeyPressed("L") ) x += 0.01; if ( uf::Window::isKeyPressed("J") ) x -= 0.01; if ( uf::Window::isKeyPressed("I") ) y += 0.01; @@ -32,6 +38,24 @@ void ext::World::tick() { if ( uf::Window::isKeyPressed("O") ) std::cout << x << ", " << y << std::endl; glPolygonOffset(x, y); } + if (uf::Window::isKeyPressed("U")) { + std::function recurse = [&]( const uf::Entity* parent, int indent ) { + for ( const uf::Entity* entity : parent->getChildren() ) { + for ( int i = 0; i < indent; ++i ) std::cout<<"\t"; + std::cout<getName()<getPlayer(); + pod::Transform<>& transform = player.getComponent>(); + + ext::oal.listener( "POSITION", { transform.position.x, transform.position.y, transform.position.z } ); + ext::oal.listener( "VELOCITY", { 0, 0, 0 } ); + ext::oal.listener( "ORIENTATION", { 0, 0, 1, 1, 0, 0 } ); + + } } @@ -46,18 +70,6 @@ void ext::World::render() { { ::camera = this->getPlayer().getComponentPointer(); } - if (uf::Window::isKeyPressed("U")) { - std::function recurse = [&]( uf::Entity* parent, int indent ) { - for ( uf::Entity* entity : parent->getChildren() ) { - if ( entity->getName() == "Light" ) { - ::camera = entity->getComponentPointer(); - return; - } - recurse(entity, indent + 1); - } - }; - recurse(this, 0); - } /* Prepare Geometry Buffer */ { buffer.bind(); @@ -97,71 +109,88 @@ void ext::World::render() { uf::GeometryBuffer& lightBuffer = metadata["light"]["dedicated"].asBool() ? light.getComponent() : ::light; uf::Camera& lightCam = light.getComponent(); - if ( false ) { // override - pod::Transform<>& t = lightCam.getTransform(); - uf::Matrix4t<> translation, rotation; - pod::Transform<> flatten = uf::transform::flatten(t, true); - rotation = uf::quaternion::matrix( flatten.orientation ); - flatten.position += uf::quaternion::rotate( flatten.orientation, lightCam.getOffset() ); - translation = uf::matrix::translate( uf::matrix::identity(), -flatten.position ); - - pod::Matrix4 m = rotation * translation; - lightCam.setView(m); - } lightCam.updateView(); - if ( !light.hasComponent() || renderedState == 0 ){ + + if ( !light.hasComponent() || metadata["light"]["render_state"].asInt() == 0 ){ lightBuffer.bind(); glClear(GL_DEPTH_BUFFER_BIT); ::camera = light.getComponentPointer(); glViewport( 0, 0, ::camera->getSize().x, ::camera->getSize().y ); glEnable(GL_POLYGON_OFFSET_FILL); + glDisable(GL_CULL_FACE); uf::Entity::render(); glDisable(GL_POLYGON_OFFSET_FILL); + glEnable(GL_CULL_FACE); ::camera = this->getPlayer().getComponentPointer(); - if (uf::Window::isKeyPressed("U")) { - std::function recurse = [&]( uf::Entity* parent, int indent ) { - for ( uf::Entity* entity : parent->getChildren() ) { - if ( entity->getName() == "Light" ) { - ::camera = entity->getComponentPointer(); - return; - } - recurse(entity, indent + 1); - } - }; - recurse(this, 0); - } glViewport( 0, 0, ::camera->getSize().x, ::camera->getSize().y ); } - if ( renderedState++ >= metadata["light"]["rate"].asInt() ) renderedState = 0; + if ( (metadata["light"]["render_state"]=metadata["light"]["render_state"].asInt()+1).asInt()-1 >= metadata["light"]["rate"].asInt() ) metadata["light"]["render_state"]= 0; { ::light.bind(); - glEnable(GL_BLEND); - glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + if ( metadata["light"]["blend"] != Json::nullValue ) { + glEnable(GL_BLEND); + GLenum parameters[4] = { + GL_ONE, + GL_ONE, + GL_ONE, + GL_ONE, + }; + for ( int i = 0; i < metadata["light"]["blend"].size(); ++i ) { + if ( metadata["light"]["blend"][i] == "ZERO" || metadata["light"]["blend"][i] == "GL_ZERO" ) parameters[i] = GL_ZERO; + if ( metadata["light"]["blend"][i] == "ONE" || metadata["light"]["blend"][i] == "GL_ONE" ) parameters[i] = GL_ONE; + if ( metadata["light"]["blend"][i] == "SRC_COLOR" || metadata["light"]["blend"][i] == "GL_SRC_COLOR" ) parameters[i] = GL_SRC_COLOR; + if ( metadata["light"]["blend"][i] == "ONE_MINUS_SRC_COLOR" || metadata["light"]["blend"][i] == "GL_ONE_MINUS_SRC_COLOR" ) parameters[i] = GL_ONE_MINUS_SRC_COLOR; + if ( metadata["light"]["blend"][i] == "DST_COLOR" || metadata["light"]["blend"][i] == "GL_DST_COLOR" ) parameters[i] = GL_DST_COLOR; + if ( metadata["light"]["blend"][i] == "ONE_MINUS_DST_COLOR" || metadata["light"]["blend"][i] == "GL_ONE_MINUS_DST_COLOR" ) parameters[i] = GL_ONE_MINUS_DST_COLOR; + if ( metadata["light"]["blend"][i] == "SRC_ALPHA" || metadata["light"]["blend"][i] == "GL_SRC_ALPHA" ) parameters[i] = GL_SRC_ALPHA; + if ( metadata["light"]["blend"][i] == "ONE_MINUS_SRC_ALPHA" || metadata["light"]["blend"][i] == "GL_ONE_MINUS_SRC_ALPHA" ) parameters[i] = GL_ONE_MINUS_SRC_ALPHA; + if ( metadata["light"]["blend"][i] == "DST_ALPHA" || metadata["light"]["blend"][i] == "GL_DST_ALPHA" ) parameters[i] = GL_DST_ALPHA; + if ( metadata["light"]["blend"][i] == "ONE_MINUS_DST_ALPHA" || metadata["light"]["blend"][i] == "GL_ONE_MINUS_DST_ALPHA" ) parameters[i] = GL_ONE_MINUS_DST_ALPHA; + if ( metadata["light"]["blend"][i] == "CONSTANT_COLOR" || metadata["light"]["blend"][i] == "GL_CONSTANT_COLOR" ) parameters[i] = GL_CONSTANT_COLOR; + if ( metadata["light"]["blend"][i] == "ONE_MINUS_CONSTANT_COLOR" || metadata["light"]["blend"][i] == "GL_ONE_MINUS_CONSTANT_COLOR" ) parameters[i] = GL_ONE_MINUS_CONSTANT_COLOR; + if ( metadata["light"]["blend"][i] == "CONSTANT_ALPHA" || metadata["light"]["blend"][i] == "GL_CONSTANT_ALPHA" ) parameters[i] = GL_CONSTANT_ALPHA; + if ( metadata["light"]["blend"][i] == "ONE_MINUS_CONSTANT_ALPHA" || metadata["light"]["blend"][i] == "GL_ONE_MINUS_CONSTANT_ALPHA" ) parameters[i] = GL_ONE_MINUS_CONSTANT_ALPHA; + if ( metadata["light"]["blend"][i] == "SRC_ALPHA_SATURATE" || metadata["light"]["blend"][i] == "GL_SRC_ALPHA_SATURATE" ) parameters[i] = GL_SRC_ALPHA_SATURATE; + if ( metadata["light"]["blend"][i] == "SRC1_COLOR" || metadata["light"]["blend"][i] == "GL_SRC1_COLOR" ) parameters[i] = GL_SRC1_COLOR; + if ( metadata["light"]["blend"][i] == "ONE_MINUS_SRC_COLOR" || metadata["light"]["blend"][i] == "GL_ONE_MINUS_SRC_COLOR" ) parameters[i] = GL_ONE_MINUS_SRC_COLOR; + if ( metadata["light"]["blend"][i] == "SRC1_ALPHA" || metadata["light"]["blend"][i] == "GL_SRC1_ALPHA" ) parameters[i] = GL_SRC1_ALPHA; + if ( metadata["light"]["blend"][i] == "ONE_MINUS_SRC_ALPHA" || metadata["light"]["blend"][i] == "GL_ONE_MINUS_SRC_ALPHA" ) parameters[i] = GL_ONE_MINUS_SRC_ALPHA; + } + + if ( metadata["light"]["blend"].size() == 2 ) { + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(parameters[0], parameters[1]); + } else if ( metadata["light"]["blend"].size() == 4 ) { + glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD); + glBlendFuncSeparate(parameters[0], parameters[1], parameters[2], parameters[3]); + } + } + uf::Shader& shader = light.getComponent(); uf::Mesh& mesh = buffer.getComponent(); + pod::Transform<>& lightTransform = light.getComponent>(); + shader.bind(); { int i = 0; for ( auto& texture : buffer.getBuffers() ) { texture.bind(i); - shader.push("buffer_"+texture.getName(), i++); + shader.push("buffers.geom_"+texture.getName(), i++); } for ( auto& texture : lightBuffer.getBuffers() ) { texture.bind(i); - shader.push("lightBuffer_"+texture.getName(), i++); - } - pod::Vector2 projectionParameters; { - float cameraNear = this->getPlayer().getComponent().getBounds().x; - float cameraFar = this->getPlayer().getComponent().getBounds().y; - projectionParameters.x = cameraFar / ( cameraFar - cameraNear ); - projectionParameters.y = ( -cameraFar * cameraNear ) / ( cameraFar - cameraNear ); + shader.push("buffers.light_"+texture.getName(), i++); } - shader.push("view", this->getPlayer().getComponent().getView()); - shader.push("projection", this->getPlayer().getComponent().getProjection()); - shader.push("projectionInverse", uf::matrix::inverse(this->getPlayer().getComponent().getProjection())); - shader.push("projectionParameters", projectionParameters); - shader.push("lightColor", light.getColor()); - shader.push("lightView", lightCam.getView()); - shader.push("lightProjection", lightCam.getProjection()); + shader.push("matrices.view", this->getPlayer().getComponent().getView()); + shader.push("matrices.projection", this->getPlayer().getComponent().getProjection()); + shader.push("matrices.projectionInverse", uf::matrix::inverse(this->getPlayer().getComponent().getProjection())); + + shader.push("parameters.color", light.getColor()); + shader.push("parameters.attenuation", light.getAttenuation()); + shader.push("parameters.power", light.getPower()); + shader.push("parameters.specular", light.getSpecular()); + shader.push("parameters.position", lightTransform.position); + + shader.push("parameters.view", lightCam.getView()); + shader.push("parameters.projection", lightCam.getProjection()); } mesh.render(); glDisable(GL_BLEND); @@ -174,23 +203,17 @@ void ext::World::render() { uf::Mesh& mesh = buffer.getComponent(); shader.bind(); { int i = 0; for ( auto& texture : buffer.getBuffers() ) { texture.bind(i); - shader.push("buffer_"+texture.getName(), i++); + shader.push("buffers.geom_"+texture.getName(), i++); } for ( auto& texture : ::light.getBuffers() ) { texture.bind(i); - shader.push("lightBuffer_"+texture.getName(), i++); - } - pod::Vector2 projectionParameters; { - float cameraNear = this->getPlayer().getComponent().getBounds().x; - float cameraFar = this->getPlayer().getComponent().getBounds().y; - projectionParameters.x = cameraFar / ( cameraFar - cameraNear ); - projectionParameters.y = ( -cameraFar * cameraNear ) / ( cameraFar - cameraNear ); + shader.push("buffers.light_"+texture.getName(), i++); } - shader.push("view", camera.getView()); - shader.push("projection", camera.getProjection()); - shader.push("projectionInverse", uf::matrix::inverse(this->getPlayer().getComponent().getProjection())); - shader.push("projectionParameters", projectionParameters); - shader.push("lightMapped", !lights.empty()); + shader.push("matrices.view", camera.getView()); + shader.push("matrices.projection", camera.getProjection()); + shader.push("matrices.projectionInverse", uf::matrix::inverse(this->getPlayer().getComponent().getProjection())); + + shader.push("parameters.light", !lights.empty()); } mesh.render(); } @@ -209,14 +232,28 @@ void ext::World::render() { } ext::Player& ext::World::getPlayer() { - for ( uf::Entity* kv : this->m_children ) if ( kv->getName() == "Player" ) return *((ext::Player*) kv); - std::cout << "??" << std::endl; - return this->m_player; + std::function recurse = [&]( uf::Entity* parent, int indent ) { + for ( uf::Entity* entity : parent->getChildren() ) { + if ( entity->getName() == "Player" ) return entity; + uf::Entity* p = recurse(entity, indent + 1); + if ( p ) return p; + } + return (uf::Entity*) NULL; + }; + uf::Entity* pointer = recurse(this, 0); + return *((ext::Player*) pointer); } const ext::Player& ext::World::getPlayer() const { - for ( const uf::Entity* kv : this->m_children ) if ( kv->getName() == "Player" ) return *((const ext::Player*) kv); - std::cout << "??" << std::endl; - return this->m_player; + std::function recurse = [&]( const uf::Entity* parent, int indent ) { + for ( const uf::Entity* entity : parent->getChildren() ) { + if ( entity->getName() == "Player" ) return entity; + const uf::Entity* p = recurse(entity, indent + 1); + if ( p ) return p; + } + return (const uf::Entity*) NULL; + }; + const uf::Entity* pointer = recurse(this, 0); return + *((const ext::Player*) pointer); } bool ext::World::load() { diff --git a/ext/world/world.h b/ext/world/world.h index 0a19af28..9ef9861e 100644 --- a/ext/world/world.h +++ b/ext/world/world.h @@ -10,8 +10,6 @@ namespace ext { class EXT_API World : public uf::Entity { - protected: - ext::Player m_player; public: ext::Player& getPlayer(); const ext::Player& getPlayer() const;