From c398fa4da448a6ac728c11a50556beece97b2a0f Mon Sep 17 00:00:00 2001 From: CarlDenisAndersen Date: Wed, 23 Oct 2013 00:09:17 +0200 Subject: [PATCH] First commit --- Engine/Collision/Box.cpp | 65 ++ Engine/Collision/Box.h | 44 + Engine/Collision/BoxAxisAligned.cpp | 59 ++ Engine/Collision/BoxAxisAligned.h | 38 + Engine/Collision/Collision.cpp | 665 +++++++++++++++ Engine/Collision/Collision.h | 104 +++ Engine/Collision/Frustrum.cpp | 234 ++++++ Engine/Collision/Frustrum.h | 45 ++ Engine/Collision/ICollideable.h | 49 ++ Engine/Collision/Line.cpp | 40 + Engine/Collision/Line.h | 39 + Engine/Collision/OysterCollision.h | 11 + Engine/Collision/Plane.cpp | 56 ++ Engine/Collision/Plane.h | 38 + Engine/Collision/Point.cpp | 51 ++ Engine/Collision/Point.h | 37 + Engine/Collision/Ray.cpp | 54 ++ Engine/Collision/Ray.h | 42 + Engine/Collision/Sphere.cpp | 53 ++ Engine/Collision/Sphere.h | 37 + Engine/Core/Buffer.cpp | 202 +++++ Engine/Core/Buffer.h | 76 ++ Engine/Core/Core.cpp | 164 ++++ Engine/Core/Core.h | 30 + Engine/Core/CoreIncludes.h | 40 + Engine/Engine.cpp | 539 +++++++++++++ Engine/Engine.h | 177 ++++ Engine/EngineIncludes.h | 38 + Engine/FileLoader/ObjReader.cpp | 268 ++++++ Engine/FileLoader/ObjReader.h | 42 + Engine/Game/CollisionHandler.h | 356 ++++++++ Engine/Game/GameObject.cpp | 1 + Engine/Game/GameObject.h | 22 + Engine/Game/MoveAble.cpp | 119 +++ Engine/Game/MoveAble.h | 57 ++ Engine/Game/OysterGame.h | 3 + Engine/Game/SateliteCamera.cpp | 307 +++++++ Engine/Game/SateliteCamera.h | 72 ++ Engine/Input/InputController.cpp | 284 +++++++ Engine/Input/InputController.h | 63 ++ Engine/Math/LinearMath.h | 268 ++++++ Engine/Math/Matrix.h | 761 ++++++++++++++++++ Engine/Math/OysterMath.cpp | 32 + Engine/Math/OysterMath.h | 220 +++++ Engine/Math/Quaternion.h | 183 +++++ Engine/Math/Vector.h | 659 +++++++++++++++ Engine/Misc/Utilities.cpp | 216 +++++ Engine/Misc/Utilities.h | 80 ++ Engine/Misc/WinTimer.cpp | 75 ++ Engine/Misc/WinTimer.h | 32 + Engine/Render/Camera.cpp | 157 ++++ Engine/Render/Camera.h | 61 ++ Engine/Render/Lights.h | 8 + Engine/Render/Model.cpp | 0 Engine/Render/Model.h | 32 + Engine/Render/ModelInfo.h | 29 + Engine/Render/TextBox.cpp | 165 ++++ Engine/Render/TextBox.h | 67 ++ Engine/Resourses/Buffers.cpp | 44 + Engine/Resourses/Buffers.h | 22 + Engine/Resourses/GraphicsDefinitions.h | 34 + Engine/Resourses/Manager.cpp | 47 ++ Engine/Resourses/Manager.h | 20 + Engine/Resourses/PipelineResources.cpp | 228 ++++++ Engine/Resourses/PipelineResources.h | 66 ++ Engine/Resourses/ShaderEffects.cpp | 100 +++ Engine/Resourses/ShaderEffects.h | 23 + Engine/Shader/Shader.cpp | 253 ++++++ Engine/Shader/Shader.h | 78 ++ Engine/Window/Window.cpp | 164 ++++ Engine/Window/Window.h | 46 ++ GameLogic/Bullet.cpp | 154 ++++ GameLogic/Bullet.h | 58 ++ GameLogic/EffectCarrier.cpp | 67 ++ GameLogic/EffectCarrier.h | 77 ++ GameLogic/GameLUA.cpp | 297 +++++++ GameLogic/GameLUA.h | 32 + GameLogic/GameLogic.cpp | 12 + GameLogic/GameLogic.h | 14 + GameLogic/InstanceBlueprint.cpp | 300 +++++++ GameLogic/InstanceBlueprint.h | 43 + GameLogic/MoveAble.h | 46 ++ GameLogic/Object.cpp | 485 +++++++++++ GameLogic/Object.h | 147 ++++ GameLogic/Player.cpp | 241 ++++++ GameLogic/Player.h | 83 ++ GameLogic/Protocoll.cpp | 320 ++++++++ GameLogic/Protocoll.h | 161 ++++ GameLogic/Session.cpp | 576 +++++++++++++ GameLogic/Session.h | 72 ++ GameLogic/Ship.cpp | 66 ++ GameLogic/Ship.h | 37 + GameLogic/Weapon.cpp | 12 + GameLogic/Weapon.h | 28 + Into The Void client/GameEndedMenu.cpp | 114 +++ Into The Void client/GameEndedMenu.h | 40 + Into The Void client/GameState.h | 33 + Into The Void client/GameStateStack.cpp | 114 +++ Into The Void client/GameStateStack.h | 34 + Into The Void client/GraphicStructs.h | 25 + Into The Void client/IngameMenu.cpp | 120 +++ Into The Void client/IngameMenu.h | 35 + Into The Void client/IntoTheVoid.cpp | 530 ++++++++++++ Into The Void client/IntoTheVoid.h | 70 ++ Into The Void client/Lobby.cpp | 153 ++++ Into The Void client/Lobby.h | 33 + Into The Void client/MainMenu.cpp | 166 ++++ Into The Void client/MainMenu.h | 45 ++ Into The Void client/NetworkConnection.cpp | 337 ++++++++ Into The Void client/NetworkConnection.h | 114 +++ Into The Void client/Player.cpp | 141 ++++ Into The Void client/Player.h | 56 ++ Into The Void client/RenderEngine.cpp | 369 +++++++++ Into The Void client/RenderEngine.h | 38 + Into The Void client/SoundSystem.h | 47 ++ Into The Void client/TailCamera.cpp | 58 ++ Into The Void client/TailCamera.h | 26 + Into The Void client/Time.cpp | 32 + Into The Void client/Time.h | 21 + Into The Void client/UserInterface.cpp | 167 ++++ Into The Void client/UserInterface.h | 45 ++ Into The Void client/main.cpp | 69 ++ Into The Void server/Into The Void server.cpp | 2 + Into The Void.sln | 168 ++++ Network/Client/ClientDataHandler.cpp | 112 +++ Network/Client/ClientInitFunctions.cpp | 79 ++ Network/Client/ClientMain.cpp | 79 ++ Network/Client/ClientTCPSpecific.cpp | 39 + Network/Client/ClientUDPSpecific.cpp | 39 + Network/Client/SocketClient.cpp | 133 +++ Network/Client/SocketClient.h | 147 ++++ Network/NetworkDependencies/Event.cpp | 262 ++++++ Network/NetworkDependencies/Event.h | 142 ++++ Network/NetworkDependencies/EventStructs.h | 55 ++ Network/NetworkDependencies/Network.h | 11 + .../NetworkDependencies/NetworkConstants.h | 11 + Network/NetworkDependencies/NetworkIncludes.h | 23 + .../NetworkDependencies/NetworkInitStructs.h | 70 ++ .../NetworkMiscFunctions.cpp | 12 + .../NetworkMiscFunctions.h | 9 + Network/NetworkDependencies/NetworkTimer.cpp | 85 ++ Network/NetworkDependencies/NetworkTimer.h | 25 + .../NetworkUpdateStructs.h | 62 ++ Network/NetworkDependencies/UpdateStructs.cpp | 1 + Network/Server/Game.cpp | 113 +++ Network/Server/Game.h | 51 ++ Network/Server/Lobby.cpp | 73 ++ Network/Server/Lobby.h | 27 + Network/Server/ServerDataHandler.cpp | 219 +++++ Network/Server/ServerInclude.h | 19 + Network/Server/ServerMain.cpp | 47 ++ Network/Server/ServerTCPSpecific.cpp | 66 ++ Network/Server/ServerTimer.cpp | 85 ++ Network/Server/ServerTimer.h | 25 + Network/Server/ServerUDPSpecific.cpp | 55 ++ Network/Server/Servercore.cpp | 420 ++++++++++ Network/Server/SessionRelatedFunctions.cpp | 255 ++++++ Network/Server/SocketServer.h | 126 +++ Network/Server/User.cpp | 50 ++ Network/Server/User.h | 42 + Sound/Listener.cpp | 29 + Sound/Listener.h | 15 + Sound/SoundEngine.cpp | 380 +++++++++ Sound/SoundEngine.h | 74 ++ Sound/SoundResource.h | 70 ++ Sound/SoundResourceWAV.cpp | 185 +++++ Sound/SoundResourceWAV.h | 39 + Sound/SoundSource.cpp | 198 +++++ Sound/SoundSource.h | 62 ++ Sound/ThreadPool.cpp | 56 ++ Sound/ThreadPool.h | 36 + Sound/Util.h | 39 + TemplateMain.cpp | 254 ++++++ stdafx.h | 75 ++ 174 files changed, 19902 insertions(+) create mode 100644 Engine/Collision/Box.cpp create mode 100644 Engine/Collision/Box.h create mode 100644 Engine/Collision/BoxAxisAligned.cpp create mode 100644 Engine/Collision/BoxAxisAligned.h create mode 100644 Engine/Collision/Collision.cpp create mode 100644 Engine/Collision/Collision.h create mode 100644 Engine/Collision/Frustrum.cpp create mode 100644 Engine/Collision/Frustrum.h create mode 100644 Engine/Collision/ICollideable.h create mode 100644 Engine/Collision/Line.cpp create mode 100644 Engine/Collision/Line.h create mode 100644 Engine/Collision/OysterCollision.h create mode 100644 Engine/Collision/Plane.cpp create mode 100644 Engine/Collision/Plane.h create mode 100644 Engine/Collision/Point.cpp create mode 100644 Engine/Collision/Point.h create mode 100644 Engine/Collision/Ray.cpp create mode 100644 Engine/Collision/Ray.h create mode 100644 Engine/Collision/Sphere.cpp create mode 100644 Engine/Collision/Sphere.h create mode 100644 Engine/Core/Buffer.cpp create mode 100644 Engine/Core/Buffer.h create mode 100644 Engine/Core/Core.cpp create mode 100644 Engine/Core/Core.h create mode 100644 Engine/Core/CoreIncludes.h create mode 100644 Engine/Engine.cpp create mode 100644 Engine/Engine.h create mode 100644 Engine/EngineIncludes.h create mode 100644 Engine/FileLoader/ObjReader.cpp create mode 100644 Engine/FileLoader/ObjReader.h create mode 100644 Engine/Game/CollisionHandler.h create mode 100644 Engine/Game/GameObject.cpp create mode 100644 Engine/Game/GameObject.h create mode 100644 Engine/Game/MoveAble.cpp create mode 100644 Engine/Game/MoveAble.h create mode 100644 Engine/Game/OysterGame.h create mode 100644 Engine/Game/SateliteCamera.cpp create mode 100644 Engine/Game/SateliteCamera.h create mode 100644 Engine/Input/InputController.cpp create mode 100644 Engine/Input/InputController.h create mode 100644 Engine/Math/LinearMath.h create mode 100644 Engine/Math/Matrix.h create mode 100644 Engine/Math/OysterMath.cpp create mode 100644 Engine/Math/OysterMath.h create mode 100644 Engine/Math/Quaternion.h create mode 100644 Engine/Math/Vector.h create mode 100644 Engine/Misc/Utilities.cpp create mode 100644 Engine/Misc/Utilities.h create mode 100644 Engine/Misc/WinTimer.cpp create mode 100644 Engine/Misc/WinTimer.h create mode 100644 Engine/Render/Camera.cpp create mode 100644 Engine/Render/Camera.h create mode 100644 Engine/Render/Lights.h create mode 100644 Engine/Render/Model.cpp create mode 100644 Engine/Render/Model.h create mode 100644 Engine/Render/ModelInfo.h create mode 100644 Engine/Render/TextBox.cpp create mode 100644 Engine/Render/TextBox.h create mode 100644 Engine/Resourses/Buffers.cpp create mode 100644 Engine/Resourses/Buffers.h create mode 100644 Engine/Resourses/GraphicsDefinitions.h create mode 100644 Engine/Resourses/Manager.cpp create mode 100644 Engine/Resourses/Manager.h create mode 100644 Engine/Resourses/PipelineResources.cpp create mode 100644 Engine/Resourses/PipelineResources.h create mode 100644 Engine/Resourses/ShaderEffects.cpp create mode 100644 Engine/Resourses/ShaderEffects.h create mode 100644 Engine/Shader/Shader.cpp create mode 100644 Engine/Shader/Shader.h create mode 100644 Engine/Window/Window.cpp create mode 100644 Engine/Window/Window.h create mode 100644 GameLogic/Bullet.cpp create mode 100644 GameLogic/Bullet.h create mode 100644 GameLogic/EffectCarrier.cpp create mode 100644 GameLogic/EffectCarrier.h create mode 100644 GameLogic/GameLUA.cpp create mode 100644 GameLogic/GameLUA.h create mode 100644 GameLogic/GameLogic.cpp create mode 100644 GameLogic/GameLogic.h create mode 100644 GameLogic/InstanceBlueprint.cpp create mode 100644 GameLogic/InstanceBlueprint.h create mode 100644 GameLogic/MoveAble.h create mode 100644 GameLogic/Object.cpp create mode 100644 GameLogic/Object.h create mode 100644 GameLogic/Player.cpp create mode 100644 GameLogic/Player.h create mode 100644 GameLogic/Protocoll.cpp create mode 100644 GameLogic/Protocoll.h create mode 100644 GameLogic/Session.cpp create mode 100644 GameLogic/Session.h create mode 100644 GameLogic/Ship.cpp create mode 100644 GameLogic/Ship.h create mode 100644 GameLogic/Weapon.cpp create mode 100644 GameLogic/Weapon.h create mode 100644 Into The Void client/GameEndedMenu.cpp create mode 100644 Into The Void client/GameEndedMenu.h create mode 100644 Into The Void client/GameState.h create mode 100644 Into The Void client/GameStateStack.cpp create mode 100644 Into The Void client/GameStateStack.h create mode 100644 Into The Void client/GraphicStructs.h create mode 100644 Into The Void client/IngameMenu.cpp create mode 100644 Into The Void client/IngameMenu.h create mode 100644 Into The Void client/IntoTheVoid.cpp create mode 100644 Into The Void client/IntoTheVoid.h create mode 100644 Into The Void client/Lobby.cpp create mode 100644 Into The Void client/Lobby.h create mode 100644 Into The Void client/MainMenu.cpp create mode 100644 Into The Void client/MainMenu.h create mode 100644 Into The Void client/NetworkConnection.cpp create mode 100644 Into The Void client/NetworkConnection.h create mode 100644 Into The Void client/Player.cpp create mode 100644 Into The Void client/Player.h create mode 100644 Into The Void client/RenderEngine.cpp create mode 100644 Into The Void client/RenderEngine.h create mode 100644 Into The Void client/SoundSystem.h create mode 100644 Into The Void client/TailCamera.cpp create mode 100644 Into The Void client/TailCamera.h create mode 100644 Into The Void client/Time.cpp create mode 100644 Into The Void client/Time.h create mode 100644 Into The Void client/UserInterface.cpp create mode 100644 Into The Void client/UserInterface.h create mode 100644 Into The Void client/main.cpp create mode 100644 Into The Void server/Into The Void server.cpp create mode 100644 Into The Void.sln create mode 100644 Network/Client/ClientDataHandler.cpp create mode 100644 Network/Client/ClientInitFunctions.cpp create mode 100644 Network/Client/ClientMain.cpp create mode 100644 Network/Client/ClientTCPSpecific.cpp create mode 100644 Network/Client/ClientUDPSpecific.cpp create mode 100644 Network/Client/SocketClient.cpp create mode 100644 Network/Client/SocketClient.h create mode 100644 Network/NetworkDependencies/Event.cpp create mode 100644 Network/NetworkDependencies/Event.h create mode 100644 Network/NetworkDependencies/EventStructs.h create mode 100644 Network/NetworkDependencies/Network.h create mode 100644 Network/NetworkDependencies/NetworkConstants.h create mode 100644 Network/NetworkDependencies/NetworkIncludes.h create mode 100644 Network/NetworkDependencies/NetworkInitStructs.h create mode 100644 Network/NetworkDependencies/NetworkMiscFunctions.cpp create mode 100644 Network/NetworkDependencies/NetworkMiscFunctions.h create mode 100644 Network/NetworkDependencies/NetworkTimer.cpp create mode 100644 Network/NetworkDependencies/NetworkTimer.h create mode 100644 Network/NetworkDependencies/NetworkUpdateStructs.h create mode 100644 Network/NetworkDependencies/UpdateStructs.cpp create mode 100644 Network/Server/Game.cpp create mode 100644 Network/Server/Game.h create mode 100644 Network/Server/Lobby.cpp create mode 100644 Network/Server/Lobby.h create mode 100644 Network/Server/ServerDataHandler.cpp create mode 100644 Network/Server/ServerInclude.h create mode 100644 Network/Server/ServerMain.cpp create mode 100644 Network/Server/ServerTCPSpecific.cpp create mode 100644 Network/Server/ServerTimer.cpp create mode 100644 Network/Server/ServerTimer.h create mode 100644 Network/Server/ServerUDPSpecific.cpp create mode 100644 Network/Server/Servercore.cpp create mode 100644 Network/Server/SessionRelatedFunctions.cpp create mode 100644 Network/Server/SocketServer.h create mode 100644 Network/Server/User.cpp create mode 100644 Network/Server/User.h create mode 100644 Sound/Listener.cpp create mode 100644 Sound/Listener.h create mode 100644 Sound/SoundEngine.cpp create mode 100644 Sound/SoundEngine.h create mode 100644 Sound/SoundResource.h create mode 100644 Sound/SoundResourceWAV.cpp create mode 100644 Sound/SoundResourceWAV.h create mode 100644 Sound/SoundSource.cpp create mode 100644 Sound/SoundSource.h create mode 100644 Sound/ThreadPool.cpp create mode 100644 Sound/ThreadPool.h create mode 100644 Sound/Util.h create mode 100644 TemplateMain.cpp create mode 100644 stdafx.h diff --git a/Engine/Collision/Box.cpp b/Engine/Collision/Box.cpp new file mode 100644 index 00000000..3c1b416e --- /dev/null +++ b/Engine/Collision/Box.cpp @@ -0,0 +1,65 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#include "Box.h" +#include "Collision.h" + +using namespace ::Oyster::Collision; +using namespace ::Oyster::Math; + +Box::Box( ) : ICollideable(ICollideable::Box), orientation(Float4x4::identity), boundingOffset() {} + +Box::Box( const Box &box ) : ICollideable(ICollideable::Box), orientation(box.orientation), boundingOffset(box.boundingOffset) +{ + this->orientation = box.orientation; +} + +Box::Box( const Float4x4 &o, const Float3 &s ) : ICollideable(ICollideable::Box), orientation(o), boundingOffset(s*0.5) +{ + this->orientation = o; +} +Box::~Box( ) { /*Nothing needs to be done here*/ } + +Box & Box::operator = ( const Box &box ) +{ + this->orientation = box.orientation; + this->boundingOffset = box.boundingOffset; + return *this; +} + +ICollideable* Box::clone( ) const +{ return new Box( *this ); } + +bool Box::Intersects( const ICollideable *target ) const +{ + switch( target->type ) + { + case ICollideable::Point: return Utility::intersect( *this, *(Collision::Point*)target ); + case ICollideable::Ray: return Utility::intersect( *this, *(Collision::Ray*)target, ((Collision::Ray*)target)->collisionDistance ); + case ICollideable::Sphere: return Utility::intersect( *this, *(Collision::Sphere*)target ); + case ICollideable::Plane: return Utility::intersect( *this, *(Collision::Plane*)target ); + case ICollideable::Triangle: return false; // TODO + case ICollideable::BoxAxisAligned: return Utility::intersect( *this, *(Collision::BoxAxisAligned*)target ); + case ICollideable::Box: return Utility::intersect( *this, *(Collision::Box*)target ); + case ICollideable::Frustrum: return false; // TODO + default: return false; + } +} + +bool Box::Contains( const ICollideable *target ) const +{ + switch( target->type ) + { + case ICollideable::Point: return Utility::intersect( *this, *(Collision::Point*)target ); + case ICollideable::Sphere: return false; // TODO + case ICollideable::Triangle: return false; // TODO + case ICollideable::BoxAxisAligned: return false; // TODO + case ICollideable::Box: return false; // TODO + case ICollideable::Frustrum: return false; // TODO + default: return false; + } +} + +ICollideable::State Box::Advanced( const ICollideable *target ) const +{ return ICollideable::Missed; } //Not supported returns 0 \ No newline at end of file diff --git a/Engine/Collision/Box.h b/Engine/Collision/Box.h new file mode 100644 index 00000000..8e60b875 --- /dev/null +++ b/Engine/Collision/Box.h @@ -0,0 +1,44 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef OYSTER_COLLISION_BOX_H +#define OYSTER_COLLISION_BOX_H + +#include "OysterMath.h" +#include "ICollideable.h" + +namespace Oyster { namespace Collision +{ + class Box : public ICollideable + { + public: + union + { + struct{ ::Oyster::Math::Float4x4 orientation; ::Oyster::Math::Float3 boundingOffset; }; + struct + { + ::Oyster::Math::Float3 xAxis; ::Oyster::Math::Float paddingA; + ::Oyster::Math::Float3 yAxis; ::Oyster::Math::Float paddingB; + ::Oyster::Math::Float3 zAxis; ::Oyster::Math::Float paddingC; + ::Oyster::Math::Float3 center; + }; + char byte[sizeof(::Oyster::Math::Float4x4) + sizeof(::Oyster::Math::Float3)]; + }; + + Box( ); + Box( const Box &box ); + Box( const ::Oyster::Math::Float4x4 &orientation, const ::Oyster::Math::Float3 &size ); + ~Box( ); + + Box & operator = ( const Box &box ); + + ICollideable* clone( ) const; + bool Intersects( const ICollideable *target ) const; + bool Contains( const ICollideable *target ) const; + ICollideable::State Advanced( const ICollideable *target ) const; //Not supported returns 0; + }; +} } + +#endif \ No newline at end of file diff --git a/Engine/Collision/BoxAxisAligned.cpp b/Engine/Collision/BoxAxisAligned.cpp new file mode 100644 index 00000000..42630656 --- /dev/null +++ b/Engine/Collision/BoxAxisAligned.cpp @@ -0,0 +1,59 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#include "BoxAxisAligned.h" +#include "Collision.h" + +using namespace ::Oyster::Collision; +using namespace ::Oyster::Math; + +BoxAxisAligned::BoxAxisAligned( ) : ICollideable(ICollideable::BoxAxisAligned), minVertex(-0.5f,-0.5f,-0.5f), maxVertex(0.5f,0.5f,0.5f) {} +BoxAxisAligned::BoxAxisAligned( const BoxAxisAligned &box ) : ICollideable(ICollideable::BoxAxisAligned), minVertex(box.minVertex), maxVertex(box.maxVertex) {} +BoxAxisAligned::BoxAxisAligned( const Float3 &_minVertex, const Float3 &_maxVertex ) : ICollideable(ICollideable::BoxAxisAligned), minVertex(_minVertex), maxVertex(_maxVertex) {} +BoxAxisAligned::BoxAxisAligned( const Float &leftClip, const Float &rightClip, const Float &topClip, const Float &bottomClip, const Float &nearClip, const Float &farClip ) + : ICollideable(ICollideable::BoxAxisAligned), minVertex(leftClip, bottomClip, nearClip), maxVertex(rightClip, topClip, farClip) {} +BoxAxisAligned::~BoxAxisAligned( ) { /*Nothing needs to be done here*/ } + +BoxAxisAligned & BoxAxisAligned::operator = ( const BoxAxisAligned &box ) +{ + this->minVertex = box.minVertex; + this->maxVertex = box.maxVertex; + return *this; +} + +ICollideable* BoxAxisAligned::clone( ) const +{ return new BoxAxisAligned( *this ); } + +bool BoxAxisAligned::Intersects( const ICollideable *target ) const +{ + switch( target->type ) + { + case ICollideable::Point: return Utility::intersect( *this, *(Collision::Point*)target ); + case ICollideable::Ray: return Utility::intersect( *this, *(Collision::Ray*)target, ((Collision::Ray*)target)->collisionDistance ); + case ICollideable::Sphere: return Utility::intersect( *this, *(Collision::Sphere*)target ); + case ICollideable::Plane: return Utility::intersect( *this, *(Collision::Plane*)target ); + case ICollideable::Triangle: return false; // TODO + case ICollideable::BoxAxisAligned: return Utility::intersect( *this, *(Collision::BoxAxisAligned*)target ); + case ICollideable::Box: return false; // TODO + case ICollideable::Frustrum: return false; // TODO + default: return false; + } +} + +bool BoxAxisAligned::Contains( const ICollideable *target ) const +{ + switch( target->type ) + { + case ICollideable::Point: return false; // TODO + case ICollideable::Sphere: return false; // TODO + case ICollideable::Triangle: return false; // TODO + case ICollideable::BoxAxisAligned: return false; // TODO + case ICollideable::Box: return false; // TODO + case ICollideable::Frustrum: return false; // TODO + default: return false; + } +} + +ICollideable::State BoxAxisAligned::Advanced( const ICollideable *target ) const +{ return ICollideable::Missed; } //Not supported returns 0 \ No newline at end of file diff --git a/Engine/Collision/BoxAxisAligned.h b/Engine/Collision/BoxAxisAligned.h new file mode 100644 index 00000000..712f75fb --- /dev/null +++ b/Engine/Collision/BoxAxisAligned.h @@ -0,0 +1,38 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef OYSTER_COLLISION_BOXAXISALIGNED_H +#define OYSTER_COLLISION_BOXAXISALIGNED_H + +#include "OysterMath.h" +#include "ICollideable.h" + +namespace Oyster { namespace Collision +{ + class BoxAxisAligned : public ICollideable + { + public: + union + { + struct{ ::Oyster::Math::Float3 minVertex, maxVertex; }; + char byte[2*sizeof(::Oyster::Math::Float3)]; + }; + + BoxAxisAligned( ); + BoxAxisAligned( const BoxAxisAligned &box ); + BoxAxisAligned( const ::Oyster::Math::Float3 &minVertex, const ::Oyster::Math::Float3 &maxVertex ); + BoxAxisAligned( const ::Oyster::Math::Float &leftClip, const ::Oyster::Math::Float &rightClip, const ::Oyster::Math::Float &topClip, const ::Oyster::Math::Float &bottomClip, const ::Oyster::Math::Float &nearClip, const ::Oyster::Math::Float &farClip ); + ~BoxAxisAligned( ); + + BoxAxisAligned & operator = ( const BoxAxisAligned &box ); + + ICollideable* clone( ) const; + bool Intersects( const ICollideable *target ) const; + bool Contains( const ICollideable *target ) const; + ICollideable::State Advanced( const ICollideable *target ) const; //Not supported returns 0; + }; +} } + +#endif \ No newline at end of file diff --git a/Engine/Collision/Collision.cpp b/Engine/Collision/Collision.cpp new file mode 100644 index 00000000..41eea873 --- /dev/null +++ b/Engine/Collision/Collision.cpp @@ -0,0 +1,665 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#include "Collision.h" +#include "Utilities.h" +#include + +using namespace Oyster::Math; + +namespace Oyster { namespace Collision { namespace Utility +{ + +// PRIVATE HEADER /////////////////////////////////////////////////// + namespace Private + { + const Float epsilon = (const Float)1e-20; + + // Float calculations can suffer roundingerrors. Which is where epsilon = 1e-20 comes into the picture + inline bool equalsZero( const Float &value ) + { // by Dan Andersson + return ::Utility::Value::abs( value ) < epsilon; + } + + // Float calculations can suffer roundingerrors. Which is where epsilon = 1e-20 comes into the picture + inline bool notEqualsZero( const Float &value ) + { // by Dan Andersson + return ::Utility::Value::abs( value ) > epsilon; + } + + // returns true if miss/reject + bool boxVsRayPerSlabCheck( const Float3 &axis, const Float &boundingOffset, const Float3 &deltaPos, const Float3 rayDirection, Float &tMin, Float &tMax ) + { // by Dan Andersson + Float e = axis.dot( deltaPos ), + f = axis.dot( rayDirection ); + if( equalsZero(f) ) // if axis is not parallell with ray + { + Float t1 = e + boundingOffset, + t2 = e - boundingOffset; + t1 /= f; t2 /= f; + if( t1 > t2 ) ::Utility::Element::swap( t1, t2 ); + tMin = ::Utility::Value::max( tMin, t1 ); + tMax = ::Utility::Value::min( tMax, t2 ); + if( tMin > tMax ) return true; + if( tMax < 0.0f ) return true; + } + else if( boundingOffset < -e ) return true; + else if( boundingOffset < e ) return true; + + return false; + } + + inline bool contains( const Plane &container, const Float3 &pos ) + { // by Dan Andersson + return equalsZero( container.normal.dot( pos ) + container.phasing ); + } + + inline void compare( Float &connectOffset, const Plane &plane, const Float3 &pos ) + { // by Dan Andersson + connectOffset = plane.normal.dot(pos); + connectOffset += plane.phasing; + } + + void compare( Float &boxExtend, Float ¢erDistance, const Plane &plane, const BoxAxisAligned &box ) + { // by Dan Andersson + Float3 c = (box.maxVertex + box.minVertex) * 0.5f, // box.Center + h = (box.maxVertex - box.minVertex) * 0.5f; // box.halfSize + boxExtend = h.x * ::Utility::Value::abs(plane.normal.x); // Box max extending towards plane + boxExtend += h.y * ::Utility::Value::abs(plane.normal.y); + boxExtend += h.z * ::Utility::Value::abs(plane.normal.z); + centerDistance = c.dot(plane.normal) + plane.phasing; // distance between box center and plane + } + + void compare( Float &boxExtend, Float ¢erDistance, const Plane &plane, const Box &box ) + { // by Dan Andersson + boxExtend = box.boundingOffset.x * ::Utility::Value::abs(plane.normal.dot(box.orientation.v[0].xyz)); // Box max extending towards plane + boxExtend += box.boundingOffset.y * ::Utility::Value::abs(plane.normal.dot(box.orientation.v[1].xyz)); + boxExtend += box.boundingOffset.z * ::Utility::Value::abs(plane.normal.dot(box.orientation.v[2].xyz)); + + centerDistance = box.orientation.v[3].xyz.dot(plane.normal) + plane.phasing; // distance between box center and plane + } + + bool fifteenAxisVsAlignedAxisOverlappingChecks( const Float3 &boundingOffsetA, const Float3 &boundingOffsetB, const Float4x4 &orientationB ) + { // by Dan Andersson + Float4x4 absOrientationB; + { + Float4x4 tO = orientationB.getTranspose(); + absOrientationB.v[0] = ::Utility::Value::abs(tO.v[0]); + if( absOrientationB.v[0].w > boundingOffsetA.x + boundingOffsetB.dot(absOrientationB.v[0].xyz) ) return false; + absOrientationB.v[1] = ::Utility::Value::abs(tO.v[1]); + if( absOrientationB.v[1].w > boundingOffsetA.y + boundingOffsetB.dot(absOrientationB.v[1].xyz) ) return false; + absOrientationB.v[2] = ::Utility::Value::abs(tO.v[2]); + if( absOrientationB.v[2].w > boundingOffsetA.z + boundingOffsetB.dot(absOrientationB.v[2].xyz) ) return false; + } + + absOrientationB.transpose(); + if( ::Utility::Value::abs(orientationB.v[3].dot(orientationB.v[0])) > boundingOffsetB.x + boundingOffsetA.dot(absOrientationB.v[0].xyz) ) return false; + if( ::Utility::Value::abs(orientationB.v[3].dot(orientationB.v[1])) > boundingOffsetB.x + boundingOffsetA.dot(absOrientationB.v[1].xyz) ) return false; + if( ::Utility::Value::abs(orientationB.v[3].dot(orientationB.v[2])) > boundingOffsetB.x + boundingOffsetA.dot(absOrientationB.v[2].xyz) ) return false; + + // ( 1,0,0 ) x orientationB.v[0].xyz: + Float d = boundingOffsetA.y * absOrientationB.v[0].z; + d += boundingOffsetA.z * absOrientationB.v[0].y; + d += boundingOffsetB.y * absOrientationB.v[2].x; + d += boundingOffsetB.z * absOrientationB.v[1].x; + if( ::Utility::Value::abs(orientationB.v[3].z*orientationB.v[0].y - orientationB.v[3].y*orientationB.v[0].z) > d ) return false; + + // ( 1,0,0 ) x orientationB.v[1].xyz: + d = boundingOffsetA.y * absOrientationB.v[1].z; + d += boundingOffsetA.z * absOrientationB.v[1].y; + d += boundingOffsetB.x * absOrientationB.v[2].x; + d += boundingOffsetB.z * absOrientationB.v[0].x; + if( ::Utility::Value::abs(orientationB.v[3].z*orientationB.v[1].y - orientationB.v[3].y*orientationB.v[1].z) > d ) return false; + + // ( 1,0,0 ) x orientationB.v[2].xyz: + d = boundingOffsetA.y * absOrientationB.v[2].z; + d += boundingOffsetA.z * absOrientationB.v[2].y; + d += boundingOffsetB.x * absOrientationB.v[1].x; + d += boundingOffsetB.y * absOrientationB.v[0].x; + if( ::Utility::Value::abs(orientationB.v[3].z*orientationB.v[2].y - orientationB.v[3].y*orientationB.v[2].z) > d ) return false; + + // ( 0,1,0 ) x orientationB.v[0].xyz: + d = boundingOffsetA.x * absOrientationB.v[0].z; + d += boundingOffsetA.z * absOrientationB.v[0].x; + d += boundingOffsetB.y * absOrientationB.v[2].y; + d += boundingOffsetB.z * absOrientationB.v[1].y; + if( ::Utility::Value::abs(orientationB.v[3].x*orientationB.v[0].z - orientationB.v[3].z*orientationB.v[0].x) > d ) return false; + + // ( 0,1,0 ) x orientationB.v[1].xyz: + d = boundingOffsetA.x * absOrientationB.v[1].z; + d += boundingOffsetA.z * absOrientationB.v[1].x; + d += boundingOffsetB.x * absOrientationB.v[2].y; + d += boundingOffsetB.z * absOrientationB.v[0].y; + if( ::Utility::Value::abs(orientationB.v[3].x*orientationB.v[1].z - orientationB.v[3].z*orientationB.v[1].x) > d ) return false; + + // ( 0,1,0 ) x orientationB.v[2].xyz: + d = boundingOffsetA.x * absOrientationB.v[2].z; + d += boundingOffsetA.z * absOrientationB.v[2].x; + d += boundingOffsetB.x * absOrientationB.v[1].y; + d += boundingOffsetB.y * absOrientationB.v[0].y; + if( ::Utility::Value::abs(orientationB.v[3].x*orientationB.v[2].z - orientationB.v[3].z*orientationB.v[2].x) > d ) return false; + + // ( 0,0,1 ) x orientationB.v[0].xyz: + d = boundingOffsetA.x * absOrientationB.v[0].y; + d += boundingOffsetA.y * absOrientationB.v[0].x; + d += boundingOffsetB.y * absOrientationB.v[2].z; + d += boundingOffsetB.z * absOrientationB.v[1].z; + if( ::Utility::Value::abs(orientationB.v[3].y*orientationB.v[0].x - orientationB.v[3].x*orientationB.v[0].y) > d ) return false; + + // ( 0,0,1 ) x orientationB.v[1].xyz: + d = boundingOffsetA.x * absOrientationB.v[1].y; + d += boundingOffsetA.y * absOrientationB.v[1].x; + d += boundingOffsetB.x * absOrientationB.v[2].z; + d += boundingOffsetB.z * absOrientationB.v[0].z; + if( ::Utility::Value::abs(orientationB.v[3].y*orientationB.v[1].x - orientationB.v[3].x*orientationB.v[1].y) > d ) return false; + + // ( 0,0,1 ) x orientationB.v[2].xyz: + d = boundingOffsetA.x * absOrientationB.v[2].y; + d += boundingOffsetA.y * absOrientationB.v[2].x; + d += boundingOffsetB.x * absOrientationB.v[1].z; + d += boundingOffsetB.y * absOrientationB.v[0].z; + if( ::Utility::Value::abs(orientationB.v[3].y*orientationB.v[2].x - orientationB.v[3].x*orientationB.v[2].y) > d ) return false; + + return true; + } + } + +// PUBLIC BODY ////////////////////////////////////////////////////// + + void compare( Float &connectDistance, Float &connectOffsetSquared, const Ray &ray, const Point &point ) + { // by Dan Andersson + Float3 dP = point.position - ray.origin; + + connectDistance = dP.dot( ray.direction ); + connectDistance /= ray.direction.dot( ray.direction ); + + dP -= ( connectDistance * ray.direction ); + connectOffsetSquared = dP.dot( dP ); + } + + void compare( Float &connectDistanceA, Float &connectDistanceB, Float &connectOffsetSquared, const Ray &rayA, const Ray &rayB ) + { // by Dan Andersson + Float3 dP = rayB.origin - rayA.origin; + connectDistanceA = rayA.direction.dot( dP ); + connectDistanceA /= rayA.direction.dot( rayA.direction ); + + dP *= -1.0f; + connectDistanceB = rayB.direction.dot( dP ); + connectDistanceB /= rayB.direction.dot( rayB.direction ); + + dP = rayA.direction * connectDistanceA; + dP += rayA.origin; + dP -= rayB.direction * connectDistanceB; + dP -= rayB.origin; + + connectOffsetSquared = dP.dot( dP ); + } + + void compare( Float &connectOffset, const Plane &plane, const Point &point ) + { // by Dan Andersson + Private::compare( connectOffset, plane, point.position ); + } + + bool intersect( const Point &pointA, const Point &pointB ) + { // by Fredrick Johansson + if (pointA.position.x != pointB.position.x) return false; + if (pointA.position.y != pointB.position.y) return false; + if (pointA.position.z != pointB.position.z) return false; + return true; // Passed all tests, is in same position + } + + bool intersect( const Ray &ray, const Point &point, Float &connectDistance ) + { // by Dan Andersson + Float connectOffsetSquared; + compare( connectDistance, connectOffsetSquared, ray, point ); + + if( Private::equalsZero(connectOffsetSquared) ) + { + connectOffsetSquared = 0.0f; + return true; + } + + connectDistance = 0.0f; + return false; + } + + bool intersect( const Ray &rayA, const Ray &rayB, Float &connectDistanceA, Float &connectDistanceB ) + { // by Dan Andersson + Float connectOffsetSquared; + compare( connectDistanceA, connectDistanceB, connectOffsetSquared, rayA, rayB ); + + if( Private::equalsZero(connectOffsetSquared) ) + { + connectOffsetSquared = 0.0f; + return true; + } + + connectDistanceA = connectDistanceB = 0.0f; + return false; + } + + bool intersect( const Sphere &sphere, const Point &point ) + { // by Dan Andersson + Float3 dP = point.position - sphere.center; + if( dP.dot(dP) > (sphere.radius * sphere.radius) ) + return false; + return true; + } + + bool intersect( const Sphere &sphere, const Ray &ray, Float &connectDistance ) + {// by Dan Andersson + Float3 dP = sphere.center - ray.origin; + Float s = dP.dot( ray.direction ), + dSquared = dP.dot( dP ), + rSquared = sphere.radius * sphere.radius; + + if( dSquared <= rSquared ) { connectDistance = 0.0f; return true; } + else if( s < 0.0f ) { connectDistance = 0.0f; return false; } + + Float mSquared = dSquared - (s*s); + if( mSquared > rSquared ) { connectDistance = 0.0f; return false; } + + Float q = ::std::sqrt( rSquared - mSquared ); + if( dSquared > rSquared ) connectDistance = s - q; + else connectDistance = s + q; + + return true; + } + + bool intersect( const Sphere &sphereA, const Sphere &sphereB ) + { // by Fredrick Johansson + Float3 C = sphereA.center; + C -= sphereB.center; + Float r = (sphereA.radius + sphereB.radius); + + if (r*r >= C.dot(C)) + { + return true; // Intersect detected! + } + + return false; + } + + bool intersect( const Plane &plane, const Point &point ) + { // by Dan Andersson + Float connectOffset; + Private::compare( connectOffset, plane, point.position ); + return Private::equalsZero(connectOffset); + } + + bool intersect( const Plane &plane, const Ray &ray, Float &connectDistance ) + { // by Dan Andersson + Float c = plane.normal.dot(ray.direction); + if( Private::equalsZero(c) ) + { // ray is parallell with the plane. (ray direction orthogonal with the planar normal) + connectDistance = 0.0f; + return contains( plane, ray.origin ); + } + + connectDistance = -plane.phasing; + connectDistance -= plane.normal.dot( ray.origin ); + connectDistance /= c; + + if( connectDistance > 0.0f ) + return true; + + connectDistance = 0.0f; + return false; + } + + bool intersect( const Plane &plane, const Sphere &sphere ) + { // by Dan Andersson + Float connectOffset; + Private::compare( connectOffset, plane, sphere.center ); + return (connectOffset <= sphere.radius); + } + + bool intersect( const Plane &planeA, const Plane &planeB ) + { // by Dan Andersson + if( planeA.normal == planeB.normal ) // they are parallell + return (planeA.phasing == planeB.phasing); + else if( planeA.normal == -planeB.normal ) // they are still parallell + return (planeA.phasing == -planeB.phasing); + return true; // none parallell planes ALWAYS intersects somewhere + } + + bool intersect( const BoxAxisAligned &box, const Point &point ) + { // by Dan Andersson + if( point.position.x < box.minVertex.x ) return false; + if( point.position.x > box.maxVertex.x ) return false; + if( point.position.y < box.minVertex.y ) return false; + if( point.position.y > box.maxVertex.y ) return false; + if( point.position.z < box.minVertex.z ) return false; + if( point.position.z > box.maxVertex.z ) return false; + return true; + } + + bool intersect( const BoxAxisAligned &box, const Ray &ray, Float &connectDistance ) + { // by Dan Andersson + Float tMin = ::std::numeric_limits::max(), + tMax = -tMin; // initiating to extremevalues + + Float3 boundingOffset = ((box.maxVertex - box.minVertex) * 0.5f), + dP = ((box.maxVertex + box.minVertex) * 0.5f) - ray.origin; + if( Private::boxVsRayPerSlabCheck( Float3::standardUnitX, boundingOffset.x, dP, ray.direction, tMin, tMax ) ) { connectDistance = 0.0f; return false; } + if( Private::boxVsRayPerSlabCheck( Float3::standardUnitY, boundingOffset.y, dP, ray.direction, tMin, tMax ) ) { connectDistance = 0.0f; return false; } + if( Private::boxVsRayPerSlabCheck( Float3::standardUnitZ, boundingOffset.z, dP, ray.direction, tMin, tMax ) ) { connectDistance = 0.0f; return false; } + + if( tMin > 0.0f ) connectDistance = tMin; + else connectDistance = tMax; + return true; + } + + bool intersect( const BoxAxisAligned &box, const Sphere &sphere ) + { // by Dan Andersson + Float3 e = ::Utility::Value::max( box.minVertex - sphere.center, Float3::null ); + e += ::Utility::Value::max( sphere.center - box.maxVertex, Float3::null ); + + if( e.dot(e) > (sphere.radius * sphere.radius) ) return false; + return true; + } + + bool intersect( const BoxAxisAligned &box, const Plane &plane ) + { // by Dan Andersson + Float e, d; + Private::compare( e, d, plane, box ); + if( d - e > 0.0f ) return false; // is beneath + if( d + e < 0.0f ) return false; // is above + return true; + } + +// bool intersect( const BoxAxisAligned &box, const Triangle &triangle ) +// { return false; /* TODO */ } + + bool intersect( const BoxAxisAligned &boxA, const BoxAxisAligned &boxB ) + { // by Dan Andersson + if( boxA.maxVertex.x < boxB.minVertex.x ) return false; + if( boxA.minVertex.x > boxB.maxVertex.x ) return false; + if( boxA.maxVertex.y < boxB.minVertex.y ) return false; + if( boxA.minVertex.y > boxB.maxVertex.y ) return false; + if( boxA.maxVertex.z < boxB.minVertex.z ) return false; + if( boxA.minVertex.z > boxB.maxVertex.z ) return false; + return true; + } + + bool intersect( const Box &box, const Point &point ) + { // by Dan Andersson + Float3 dPos = point.position - box.orientation.v[3].xyz; + + Float coordinate = dPos.dot( box.orientation.v[0].xyz ); + if( coordinate > box.boundingOffset.x ) return false; + if( coordinate < -box.boundingOffset.x ) return false; + + coordinate = dPos.dot( box.orientation.v[1].xyz ); + if( coordinate > box.boundingOffset.y ) return false; + if( coordinate < -box.boundingOffset.y ) return false; + + coordinate = dPos.dot( box.orientation.v[2].xyz ); + if( coordinate > box.boundingOffset.z ) return false; + if( coordinate < -box.boundingOffset.z ) return false; + + return true; + } + + bool intersect( const Box &box, const Ray &ray, Float &connectDistance ) + { // by Dan Andersson + Float tMin = ::std::numeric_limits::max(), + tMax = -tMin; // initiating to extremevalues + + Float3 dP = box.center - ray.origin; + if( Private::boxVsRayPerSlabCheck( box.xAxis, box.boundingOffset.x, dP, ray.direction, tMin, tMax ) ) { connectDistance = 0.0f; return false; } + if( Private::boxVsRayPerSlabCheck( box.yAxis, box.boundingOffset.y, dP, ray.direction, tMin, tMax ) ) { connectDistance = 0.0f; return false; } + if( Private::boxVsRayPerSlabCheck( box.zAxis, box.boundingOffset.z, dP, ray.direction, tMin, tMax ) ) { connectDistance = 0.0f; return false; } + + if( tMin > 0.0f ) connectDistance = tMin; + else connectDistance = tMax; + return true; + } + + bool intersect( const Box &box, const Sphere &sphere ) + { // by Dan Andersson + Float3 e = sphere.center - box.orientation.v[3].xyz, + centerL = Float3( e.dot(box.orientation.v[0].xyz), e.dot(box.orientation.v[1].xyz), e.dot(box.orientation.v[2].xyz) ); + + e = ::Utility::Value::max( (box.boundingOffset + centerL)*=-1.0f, Float3::null ); + e += ::Utility::Value::max( centerL - box.boundingOffset, Float3::null ); + + if( e.dot(e) > (sphere.radius * sphere.radius) ) return false; + return true; + } + + bool intersect( const Box &box, const Plane &plane ) + {// by Dan Andersson + Float e, d; + Private::compare( e, d, plane, box ); + if( d - e > 0.0f ) return false; // is beneath + if( d + e < 0.0f ) return false; // is above + return true; + } + + bool intersect( const Box &boxA, const BoxAxisAligned &boxB ) + { // by Dan Andersson + Float3 alignedOffsetBoundaries = boxB.maxVertex - boxB.minVertex; + Float4x4 translated = boxA.orientation; + translated.v[3].xyz -= boxB.minVertex; + translated.v[3].xyz += alignedOffsetBoundaries * 0.5f; + alignedOffsetBoundaries = ::Utility::Value::abs(alignedOffsetBoundaries); + return Private::fifteenAxisVsAlignedAxisOverlappingChecks( alignedOffsetBoundaries, boxA.boundingOffset, translated ); + } + + bool intersect( const Box &boxA, const Box &boxB ) + { // by Dan Andersson + Float4x4 M; + inverseRigidBodyMatrix( M, boxA.orientation ); + transformMatrix( M, boxB.orientation, M ); + return Private::fifteenAxisVsAlignedAxisOverlappingChecks( boxA.boundingOffset, boxB.boundingOffset, M ); + } + + bool intersect( const Frustrum &frustrum, const Point &point ) + { // by Dan Andersson + Float connectOffset; + + Private::compare( connectOffset, frustrum.leftPlane, point.position ); + if( connectOffset < 0.0f ) return false; + + Private::compare( connectOffset, frustrum.rightPlane, point.position ); + if( connectOffset < 0.0f ) return false; + + Private::compare( connectOffset, frustrum.bottomPlane, point.position ); + if( connectOffset < 0.0f) return false; + + Private::compare( connectOffset, frustrum.topPlane, point.position ); + if( connectOffset < 0.0f) return false; + + Private::compare( connectOffset, frustrum.nearPlane, point.position ); + if( connectOffset < 0.0f ) return false; + + Private::compare( connectOffset, frustrum.farPlane, point.position ); + if( connectOffset < 0.0f ) return false; + + return true; + } + + bool intersect( const Frustrum &frustrum, const Ray &ray, Float &connectDistance ) + { // by Dan Andersson + bool intersected = false; + Float distance = 0.0f; + connectDistance = ::std::numeric_limits::max(); + + if( intersect(frustrum.leftPlane, ray, distance) ) + { + intersected = true; + connectDistance = ::Utility::Value::min( connectDistance, distance ); + } + + if( intersect(frustrum.rightPlane, ray, distance) ) + { + intersected = true; + connectDistance = ::Utility::Value::min( connectDistance, distance ); + } + + if( intersect(frustrum.bottomPlane, ray, distance) ) + { + intersected = true; + connectDistance = ::Utility::Value::min( connectDistance, distance ); + } + + if( intersect(frustrum.topPlane, ray, distance) ) + { + intersected = true; + connectDistance = ::Utility::Value::min( connectDistance, distance ); + } + + if( intersect(frustrum.nearPlane, ray, distance) ) + { + intersected = true; + connectDistance = ::Utility::Value::min( connectDistance, distance ); + } + + if( intersect(frustrum.farPlane, ray, distance) ) + { + intersected = true; + connectDistance = ::Utility::Value::min( connectDistance, distance ); + } + + if( intersected ) return true; + + connectDistance = 0.0f; + return false; + } + + bool intersect( const Frustrum &frustrum, const Sphere &sphere ) + { // by Dan Andersson + Float connectOffset; + + Private::compare( connectOffset, frustrum.leftPlane, sphere.center ); + if( connectOffset < -sphere.radius ) return false; + + Private::compare( connectOffset, frustrum.rightPlane, sphere.center ); + if( connectOffset < -sphere.radius ) return false; + + Private::compare( connectOffset, frustrum.bottomPlane, sphere.center ); + if( connectOffset < -sphere.radius ) return false; + + Private::compare( connectOffset, frustrum.topPlane, sphere.center ); + if( connectOffset < -sphere.radius ) return false; + + Private::compare( connectOffset, frustrum.nearPlane, sphere.center ); + if( connectOffset < -sphere.radius ) return false; + + Private::compare( connectOffset, frustrum.farPlane, sphere.center ); + if( connectOffset < -sphere.radius ) return false; + + return true; + } + + bool intersect( const Frustrum &frustrum, const Plane &plane ) + { + return false; // TODO + } + +// bool intersect( const Frustrum &frustrum, const Triangle &triangle, ? ); + + bool intersect( const Frustrum &frustrum, const BoxAxisAligned &box ) + { // by Dan Andersson + Float e, d; + + Private::compare( e, d, frustrum.leftPlane, box ); + if( d - e > 0.0f ) return false; // is beneath + + Private::compare( e, d, frustrum.rightPlane, box ); + if( d - e > 0.0f ) return false; // is beneath + + Private::compare( e, d, frustrum.bottomPlane, box ); + if( d - e > 0.0f ) return false; // is beneath + + Private::compare( e, d, frustrum.topPlane, box ); + if( d - e > 0.0f ) return false; // is beneath + + Private::compare( e, d, frustrum.nearPlane, box ); + if( d - e > 0.0f ) return false; // is beneath + + Private::compare( e, d, frustrum.farPlane, box ); + if( d - e > 0.0f ) return false; // is beneath + + return true; + } + + bool intersect( const Frustrum &frustrum, const Box &box ) + { // by Dan Andersson + Float e, d; + + Private::compare( e, d, frustrum.leftPlane, box ); + if( d - e > 0.0f ) return false; // is beneath + + Private::compare( e, d, frustrum.rightPlane, box ); + if( d - e > 0.0f ) return false; // is beneath + + Private::compare( e, d, frustrum.bottomPlane, box ); + if( d - e > 0.0f ) return false; // is beneath + + Private::compare( e, d, frustrum.topPlane, box ); + if( d - e > 0.0f ) return false; // is beneath + + Private::compare( e, d, frustrum.nearPlane, box ); + if( d - e > 0.0f ) return false; // is beneath + + Private::compare( e, d, frustrum.farPlane, box ); + if( d - e > 0.0f ) return false; // is beneath + + return true; + } + + bool intersect( const Frustrum &frustrumA, const Frustrum &frustrumB ) + { + return false; // TODO + } + + bool contains( const Ray &container, const Ray &ray ) + { + return false; /*TODO*/ + } + + bool contains( const Sphere &sphereA, const Sphere &sphereB ) + { // by Fredrick Johansson + // Check if SphereB is larger than sphereA + if (sphereA.radius < sphereB.radius) + { + return false; // Is impossible, yes + } + + // Calc distance from center to center + Float3 d = sphereB.center - sphereA.center; + Float deltaR = sphereA.radius - sphereB.radius; + + // Check if contained + if (d.dot(d) <= (deltaR*deltaR)) + { + return true; + } + + // Not contained + return false; + } + + bool contains( const Plane &container, const Point &point ) + { // by Dan Andersson + return Private::contains( container, point.position ); + } + + bool contains( const Plane &container, const Ray &ray ) + { // by Dan Andersson + if( Private::notEqualsZero(container.normal.dot(ray.direction)) ) return false; + return contains( container, ray.origin ); + } + + bool contains( const Plane &container, const Plane &plane ) + { // by Dan Andersson + if( container.phasing == plane.phasing ) + return container.normal == plane.normal; + if( container.phasing == -plane.phasing ) + return container.normal == -plane.normal; + return false; + } +} } } \ No newline at end of file diff --git a/Engine/Collision/Collision.h b/Engine/Collision/Collision.h new file mode 100644 index 00000000..cd1838e4 --- /dev/null +++ b/Engine/Collision/Collision.h @@ -0,0 +1,104 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef OYSTER_COLLISION_UTILITY_H +#define OYSTER_COLLISION_UTILITY_H + +#include "ICollideable.h" +#include "Point.h" +#include "Ray.h" +#include "Sphere.h" +#include "Plane.h" +//#include "Triangle.h" +#include "BoxAxisAligned.h" +#include "Box.h" +#include "Frustrum.h" + +namespace Oyster { namespace Collision { namespace Utility +{ + void compare( ::Oyster::Math::Float &connectDistance, ::Oyster::Math::Float &connectOffsetSquared, const Ray &ray, const Point &point ); + void compare( ::Oyster::Math::Float &connectDistanceA, ::Oyster::Math::Float &connectDistanceB, ::Oyster::Math::Float &connectOffsetSquared, const Ray &rayA, const Ray &rayB ); + void compare( ::Oyster::Math::Float &connectOffset, const Plane &plane, const Point &point ); + + bool intersect( const Point &pointA, const Point &pointB ); + + bool intersect( const Ray &ray, const Point &point, ::Oyster::Math::Float &connectDistance ); + bool intersect( const Ray &rayA, const Ray &rayB, ::Oyster::Math::Float &connectDistanceA, ::Oyster::Math::Float &connectDistanceB ); + + bool intersect( const Sphere &sphere, const Point &point ); + bool intersect( const Sphere &sphere, const Ray &ray, ::Oyster::Math::Float &connectDistance ); + bool intersect( const Sphere &sphereA, const Sphere &sphereB ); + + bool intersect( const Plane &plane, const Point &point ); + bool intersect( const Plane &plane, const Ray &ray, ::Oyster::Math::Float &connectDistance ); + bool intersect( const Plane &plane, const Sphere &sphere ); + bool intersect( const Plane &planeA, const Plane &planeB ); + +// bool intersect( const Triangle &triangle, const Point &point, ? ); +// bool intersect( const Triangle &triangle, const Ray &ray, ? ); +// bool intersect( const Triangle &triangle, const Sphere &sphere, ? ); +// bool intersect( const Triangle &triangle, const Plane &plane, ? ); +// bool intersect( const Triangle &triangleA, const Triangle &triangleB, ? ); + + bool intersect( const BoxAxisAligned &box, const Point &point ); + bool intersect( const BoxAxisAligned &box, const Ray &ray, ::Oyster::Math::Float &connectDistance ); + bool intersect( const BoxAxisAligned &box, const Sphere &sphere ); + bool intersect( const BoxAxisAligned &box, const Plane &plane ); +// bool intersect( const BoxAxisAligned &box, const Triangle &triangle ); + bool intersect( const BoxAxisAligned &boxA, const BoxAxisAligned &boxB ); + + bool intersect( const Box &box, const Point &point ); + bool intersect( const Box &box, const Ray &ray, ::Oyster::Math::Float &connectDistance ); + bool intersect( const Box &box, const Sphere &sphere ); + bool intersect( const Box &box, const Plane &plane ); +// bool intersect( const Box &box, const Triangle &triangle, ? ); + bool intersect( const Box &boxA, const BoxAxisAligned &boxB ); + bool intersect( const Box &boxA, const Box &boxB ); + + bool intersect( const Frustrum &frustrum, const Point &point ); + bool intersect( const Frustrum &frustrum, const Ray &ray, ::Oyster::Math::Float &connectDistance ); + bool intersect( const Frustrum &frustrum, const Sphere &sphere ); + bool intersect( const Frustrum &frustrum, const Plane &plane ); +// bool intersect( const Frustrum &frustrum, const Triangle &triangle, ? ); + bool intersect( const Frustrum &frustrum, const BoxAxisAligned &box ); + bool intersect( const Frustrum &frustrum, const Box &box ); + bool intersect( const Frustrum &frustrumA, const Frustrum &frustrumB ); + + bool contains( const Ray &container, const Ray &ray ); + + bool contains( const Sphere &container, const Sphere &sphere ); +// bool contains( const Sphere &container, const Triangle &triangle ); +// bool contains( const Sphere &container, const BoxAxisAligned &box ); +// bool contains( const Sphere &container, const Box &box ); +// bool contains( const Sphere &container, const Frustrum &frustrum ); + + bool contains( const Plane &container, const Point &point ); + bool contains( const Plane &container, const Ray &ray ); + bool contains( const Plane &container, const Plane &plane ); +// bool contains( const Plane &container, const Triangle &triangle ); + +// bool contains( const Triangle &container, const Point &point ); +// bool contains( const Triangle &container, const Triangle &triangle ); + +// bool contains( const BoxAxisAligned &container, const Sphere &sphere ); +// bool contains( const BoxAxisAligned &container, const Triangle &triangle ); +// bool contains( const BoxAxisAligned &container, const BoxAxisAligned &box ); +// bool contains( const BoxAxisAligned &container, const Box &box ); +// bool contains( const BoxAxisAligned &container, const Frustrum &frustrum ); + +// bool contains( const Box &container, const Sphere &sphere ); +// bool contains( const Box &container, const Triangle &triangle ); +// bool contains( const Box &container, const BoxAxisAligned &box ); +// bool contains( const Box &container, const Box &box ); +// bool contains( const Box &container, const Frustrum &frustrum ); + +// bool contains( const Frustrum &container, const Sphere &sphere ); +// bool contains( const Frustrum &container, const Triangle &triangle ); +// bool contains( const Frustrum &container, const BoxAxisAligned &box ); +// bool contains( const Frustrum &container, const Box &box ); +// bool contains( const Frustrum &container, const Frustrum &frustrum ); +} } } + +#endif \ No newline at end of file diff --git a/Engine/Collision/Frustrum.cpp b/Engine/Collision/Frustrum.cpp new file mode 100644 index 00000000..3e99db90 --- /dev/null +++ b/Engine/Collision/Frustrum.cpp @@ -0,0 +1,234 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#include "Frustrum.h" +#include "Collision.h" + +using namespace Oyster::Math; +using namespace Oyster::Collision; + +namespace PrivateStatic +{ + inline void vpToPlanes( Plane &lp, Plane &rp, Plane &bp, Plane &tp, Plane &np, Plane &fp, const Float4x4 &vp ) + { + Float4x4 m = vp.getTranspose(); + + // left + lp.normal = m.v[3].xyz + m.v[0].xyz; + lp.phasing = lp.normal.length(); + lp.normal /= lp.phasing; + lp.phasing = (m.v[3].w + m.v[0].w) / lp.phasing; + + // right + rp.normal = m.v[3].xyz - m.v[0].xyz; + rp.phasing = rp.normal.length(); + rp.normal /= rp.phasing; + rp.phasing = (m.v[3].w - m.v[0].w) / rp.phasing; + + // bottom + bp.normal = m.v[3].xyz + m.v[1].xyz; + bp.phasing = bp.normal.length(); + bp.normal /= bp.phasing; + bp.phasing = (m.v[3].w + m.v[1].w) / bp.phasing; + + // top + tp.normal = m.v[3].xyz - m.v[1].xyz; + tp.phasing = tp.normal.length(); + tp.normal /= tp.phasing; + tp.phasing = (m.v[3].w - m.v[1].w) / tp.phasing; + + // near leftHanded DirectX + np.normal = m.v[2].xyz; + np.phasing = np.normal.length(); + np.normal /= np.phasing; + np.phasing = m.v[2].w / np.phasing; + + // far lefthanded + fp.normal = m.v[3].xyz - m.v[2].xyz; + fp.phasing = fp.normal.length(); + fp.normal /= fp.phasing; + fp.phasing = (m.v[3].w - m.v[2].w) / fp.phasing; + + /*/ near rightHanded openGL + np.normal = m.v[3].xyz + m.v[2].xyz; + np.phasing = np.normal.length(); + np.normal /= np.phasing; + np.phasing = -(m.v[3].w + m.v[2].w) / np.phasing; + + // far rightHanded + fp.normal = m.v[3].xyz - m.v[2].xyz; + fp.phasing = fp.normal.length(); + fp.normal /= fp.phasing; + fp.phasing = -(m.v[3].w - m.v[2].w) / fp.phasing;*/ + } + + void interpolatePlanes( Plane &target, const Plane &planeA, const Plane &planeB, float interpolation ) + { + float counterInterpol = 1.0f - interpolation; + target.normal = counterInterpol * planeA.normal; + target.normal += interpolation * planeB.normal; + target.phasing = counterInterpol * planeA.phasing; + target.phasing += interpolation * planeB.phasing; + target.normal.normalize(); + } +} + +Frustrum::Frustrum( ) : ICollideable(ICollideable::Frustrum), + leftPlane(Float3::standardUnitX, -0.5f), rightPlane(-Float3::standardUnitX, 0.5f), + bottomPlane(Float3::standardUnitY, -0.5f), topPlane(-Float3::standardUnitY, 0.5f), + nearPlane(Float3::standardUnitZ, -0.5f), farPlane(-Float3::standardUnitZ, 0.5f) {} + +Frustrum::Frustrum( const Frustrum &frustrum ) : ICollideable(ICollideable::Frustrum), + leftPlane(frustrum.leftPlane), rightPlane(frustrum.rightPlane), + bottomPlane(frustrum.bottomPlane), topPlane(frustrum.topPlane), + nearPlane(frustrum.nearPlane), farPlane(frustrum.farPlane) {} + +Frustrum::Frustrum( const Float4x4 &vp ) : ICollideable(ICollideable::Frustrum) +{ PrivateStatic::vpToPlanes( this->leftPlane, this->rightPlane, this->bottomPlane, this->topPlane, this->nearPlane, this->farPlane, vp ); } + +Frustrum::~Frustrum( ) {} + +Frustrum & Frustrum::operator = ( const Frustrum &frustrum ) +{ + this->leftPlane = frustrum.leftPlane; + this->rightPlane = frustrum.rightPlane; + this->bottomPlane = frustrum.bottomPlane; + this->topPlane = frustrum.topPlane; + this->nearPlane = frustrum.nearPlane; + this->farPlane = frustrum.farPlane; + return *this; +} + +Frustrum & Frustrum::operator = ( const Float4x4 &vp ) +{ + PrivateStatic::vpToPlanes( this->leftPlane, this->rightPlane, this->bottomPlane, this->topPlane, this->nearPlane, this->farPlane, vp ); + return *this; +} + +void Frustrum::split( Frustrum target[], unsigned int numX, unsigned int numY, unsigned int numZ ) const +{ + float incrementX = 1.0f / numX, + incrementY = 1.0f / numY, + incrementZ = 1.0f / numZ, + interpolX = 0.0f, + interpolY = 0.0f, + interpolZ = 0.0f; + + unsigned int i = 0U, + stepY = numX, + stepZ = numX * numY; + + Collision::Plane invRight( -this->rightPlane.normal, -this->rightPlane.phasing ), + invBottom( -this->bottomPlane.normal, -this->bottomPlane.phasing ), + invFar( -this->farPlane.normal, -this->farPlane.phasing ); + + for( unsigned int iz = 0U; iz < numZ; ++iz ) + { + interpolY = 0.0f; + for( unsigned int iy = 0U; iy < numY; ++iy ) + { + interpolX = 0.0f; + for( unsigned int ix = 0U; ix < numX; ++ix ) + { + if( ix == 0 ) + target[i].leftPlane = this->leftPlane; + else + { + PrivateStatic::interpolatePlanes( target[i].leftPlane, this->leftPlane, invRight, interpolX ); + + unsigned int iLeft = i - 1; + target[iLeft].rightPlane.normal = -target[i].leftPlane.normal; + target[iLeft].rightPlane.phasing = -target[i].leftPlane.phasing; + } + if( ix == numX - 1 ) + target[i].rightPlane = this->rightPlane; + + if( iy == 0 ) + target[i].topPlane = this->topPlane; + else + { + PrivateStatic::interpolatePlanes( target[i].topPlane, this->topPlane, invBottom, interpolY ); + + unsigned int iAbove = i - stepY; + target[iAbove].bottomPlane.normal = -target[i].topPlane.normal; + target[iAbove].bottomPlane.phasing = -target[i].topPlane.phasing; + } + if( iy == numY - 1 ) + target[i].bottomPlane = this->bottomPlane; + + if( iz == 0 ) + target[i].nearPlane = this->nearPlane; + else + { + PrivateStatic::interpolatePlanes( target[i].nearPlane, this->nearPlane, invFar, interpolZ ); + + unsigned int iCloser = i - stepZ; + target[iCloser].farPlane.normal = -target[i].nearPlane.normal; + target[iCloser].farPlane.phasing = -target[i].nearPlane.phasing; + } + if( iz == numZ - 1 ) + target[i].farPlane = this->farPlane; + + ++i; + interpolX += incrementX; + } + interpolY += incrementY; + } + interpolZ += incrementZ; + } +} + +void Frustrum::writeToByte( unsigned char targetMem[], unsigned int &nextIndex ) const +{ + Float *fMem = (Float*)&targetMem[nextIndex]; + for( int p = 0; p < 6; ++p ) + { + fMem[0] = this->plane[p].element[0]; + fMem[1] = this->plane[p].element[1]; + fMem[2] = this->plane[p].element[2]; + fMem[3] = this->plane[p].element[3]; + fMem = &fMem[4]; + } + nextIndex += 6 * ::Utility::StaticArray::numElementsOf( this->plane[0].byte ); +} + +ICollideable* Frustrum::clone( ) const +{ return new Frustrum(*this); } + +bool Frustrum::Intersects( const ICollideable *target ) const +{ + switch( target->type ) + { + case ICollideable::Point: return Utility::intersect( *this, *(Collision::Point*)target ); + case ICollideable::Ray: return Utility::intersect( *this, *(Collision::Ray*)target, ((Collision::Ray*)target)->collisionDistance ); + case ICollideable::Sphere: return Utility::intersect( *this, *(Collision::Sphere*)target ); + case ICollideable::Plane: return Utility::intersect( *this, *(Collision::Plane*)target ); + case ICollideable::Triangle: return false; // TODO + case ICollideable::BoxAxisAligned: return Utility::intersect( *this, *(Collision::BoxAxisAligned*)target ); + case ICollideable::Box: return Utility::intersect( *this, *(Collision::Box*)target ); + case ICollideable::Frustrum: return Utility::intersect( *this, *(Collision::Frustrum*)target ); + case ICollideable::Line: return false; // TODO + default: return false; + } +} + +bool Frustrum::Contains( const ICollideable *target ) const +{ + switch( target->type ) + { + case ICollideable::Point: return Utility::intersect( *this, *(Collision::Point*)target ); + case ICollideable::Ray: return false; // TODO + case ICollideable::Sphere: return false; // TODO + case ICollideable::Plane: return false; // TODO + case ICollideable::Triangle: return false; // TODO + case ICollideable::BoxAxisAligned: return false; // TODO + case ICollideable::Box: return false; // TODO + case ICollideable::Frustrum: return false; // TODO + case ICollideable::Line: return false; // TODO + default: return false; + } +} + +ICollideable::State Frustrum::Advanced( const ICollideable *target ) const +{ return ICollideable::Missed; } //Not supported returns 0 \ No newline at end of file diff --git a/Engine/Collision/Frustrum.h b/Engine/Collision/Frustrum.h new file mode 100644 index 00000000..5610356d --- /dev/null +++ b/Engine/Collision/Frustrum.h @@ -0,0 +1,45 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef OYSTER_COLLISION_FRUSTRUM_H +#define OYSTER_COLLISION_FRUSTRUM_H + +#include "OysterMath.h" +#include "ICollideable.h" +#include "Plane.h" + +namespace Oyster { namespace Collision +{ + + class Frustrum : public ICollideable + { + public: + + union + { + struct{ class Plane plane[6]; }; + struct + { class Plane leftPlane, rightPlane, bottomPlane, topPlane, nearPlane, farPlane; }; + }; + + Frustrum( ); + Frustrum( const Frustrum &frustrum ); + Frustrum( const ::Oyster::Math::Float4x4 &viewProjection ); + ~Frustrum( ); + + Frustrum & operator = ( const Frustrum &frustrum ); + Frustrum & operator = ( const ::Oyster::Math::Float4x4 &viewProjection ); + + void split( Frustrum targetList[], unsigned int numX, unsigned int numY = 1U, unsigned int numZ = 1u ) const; + void writeToByte( unsigned char targetMem[], unsigned int &nextIndex ) const; + + ICollideable* clone( ) const; + bool Intersects( const ICollideable *target ) const; + bool Contains( const ICollideable *target ) const; + ICollideable::State Advanced( const ICollideable *target ) const; //Not supported returns 0; + }; +} } + +#endif \ No newline at end of file diff --git a/Engine/Collision/ICollideable.h b/Engine/Collision/ICollideable.h new file mode 100644 index 00000000..1aa1a195 --- /dev/null +++ b/Engine/Collision/ICollideable.h @@ -0,0 +1,49 @@ +///////////////////////////////////////////////////////////////////// +// Created by Pär Hammarstrand 2013 +// Edited by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef OYSTER_COLLISION_ICOLLIDEABLE_H +#define OYSTER_COLLISION_ICOLLIDEABLE_H + +namespace Oyster { namespace Collision +{ + class ICollideable + { + public: + enum CollisionType + { + Point, + Ray, + Sphere, + Plane, + Triangle, + BoxAxisAligned, + Box, + Frustrum, + Line + }; + + enum State + { + Missed = 0, + Contained, + Intersected + }; + + ICollideable( CollisionType _type ) : type(_type) {}; + + const CollisionType type; + + virtual ICollideable* clone( ) const = 0; + + virtual bool Intersects( const ICollideable *target ) const = 0; + + virtual bool Contains( const ICollideable *target ) const = 0; + + //Not supported returns 0; + virtual State Advanced( const ICollideable *target ) const = 0; + }; +} } +#endif \ No newline at end of file diff --git a/Engine/Collision/Line.cpp b/Engine/Collision/Line.cpp new file mode 100644 index 00000000..47ab884e --- /dev/null +++ b/Engine/Collision/Line.cpp @@ -0,0 +1,40 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#include "Line.h" +#include "Collision.h" + +using namespace ::Oyster::Collision; +using namespace ::Oyster::Math; + +Line::Line( ) : ICollideable(ICollideable::Line), ray(), length(0.0f) {} +Line::Line( const Line &_line ) : ICollideable(ICollideable::Line), ray(_line.ray), length(_line.length) {} +Line::Line( const class Ray &_ray, const Float &_length ) : ICollideable(ICollideable::Line), ray(_ray), length(_length) {} +Line::Line( const Float3 &origin, const Float3 &normalizedDirection, const Float &_length ) : ICollideable(ICollideable::Line), ray(origin, normalizedDirection), length(_length) {} +Line::~Line( ) { /*Nothing needs to be done here*/ } + +Line & Line::operator = ( const Line &line ) +{ + this->ray = line.ray; + this->length = line.length; + return *this; +} + +ICollideable* Line::clone( ) const +{ return new Line(*this); } + +bool Line::Intersects( const ICollideable *target ) const +{ + if( this->ray.Intersects( target ) ) if( this->ray.collisionDistance >= 0.0f ) if( this->ray.collisionDistance <= this->length ) + return true; + + this->ray.collisionDistance = 0.0f; + return false; +} + +bool Line::Contains( const ICollideable *target ) const +{ /*TODO*/ return false; } + +ICollideable::State Line::Advanced( const ICollideable *target ) const +{ return ICollideable::Missed; } //Not supported returns 0 \ No newline at end of file diff --git a/Engine/Collision/Line.h b/Engine/Collision/Line.h new file mode 100644 index 00000000..1cfa92a5 --- /dev/null +++ b/Engine/Collision/Line.h @@ -0,0 +1,39 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef OYSTER_COLLISION_LINE_H +#define OYSTER_COLLISION_LINE_H + +#include "OysterMath.h" +#include "ICollideable.h" +#include "Ray.h" + +namespace Oyster { namespace Collision +{ + class Line : public ICollideable + { + public: + union + { + struct { class Ray ray; ::Oyster::Math::Float length; }; + char byte[sizeof(class Ray) + sizeof(::Oyster::Math::Float)]; + }; + + Line( ); + Line( const Line &line ); + Line( const class Ray &ray, const ::Oyster::Math::Float &length ); + Line( const ::Oyster::Math::Float3 &origin, const ::Oyster::Math::Float3 &normalizedDirection, const ::Oyster::Math::Float &length ); + ~Line( ); + + Line & operator = ( const Line &line ); + + ICollideable* clone( ) const; + bool Intersects( const ICollideable *target ) const; + bool Contains( const ICollideable *target ) const; + ICollideable::State Advanced( const ICollideable *target ) const; //Not supported returns 0; + }; +} } + +#endif \ No newline at end of file diff --git a/Engine/Collision/OysterCollision.h b/Engine/Collision/OysterCollision.h new file mode 100644 index 00000000..051fddea --- /dev/null +++ b/Engine/Collision/OysterCollision.h @@ -0,0 +1,11 @@ +#include "ICollideable.h" +#include "Point.h" +#include "Ray.h" +#include "Plane.h" +#include "Sphere.h" +#include "BoxAxisAligned.h" +#include "Box.h" +#include "Frustrum.h" +#include "Line.h" + +#include "Collision.h" \ No newline at end of file diff --git a/Engine/Collision/Plane.cpp b/Engine/Collision/Plane.cpp new file mode 100644 index 00000000..6a60ea0a --- /dev/null +++ b/Engine/Collision/Plane.cpp @@ -0,0 +1,56 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#include "Plane.h" +#include "Collision.h" + +using namespace ::Oyster::Collision; +using namespace ::Oyster::Math; + +Plane::Plane( ) : ICollideable(ICollideable::Plane), normal(), phasing(0.0f) {} +Plane::Plane( const Plane &plane ) : ICollideable(ICollideable::Plane), normal(plane.normal), phasing(plane.phasing) {} +Plane::Plane( const Float3 &n, const Float &p ) : ICollideable(ICollideable::Plane), normal(n), phasing(p) {} +Plane::~Plane( ) { /*Nothing needs to be done here*/ } + +Plane & Plane::operator = ( const Plane &plane ) +{ + this->normal = plane.normal; + this->phasing = plane.phasing; + return *this; +} + +ICollideable* Plane::clone( ) const +{ return new Plane( *this ); } + +bool Plane::Intersects( const ICollideable *target ) const +{ + switch( target->type ) + { + case ICollideable::Point: return Utility::intersect( *this, *(Collision::Point*)target ); + case ICollideable::Ray: return Utility::intersect( *this, *(Collision::Ray*)target, ((Collision::Ray*)target)->collisionDistance ); + case ICollideable::Sphere: return Utility::intersect( *this, *(Collision::Sphere*)target ); + case ICollideable::Plane: return Utility::intersect( *this, *(Collision::Plane*)target ); + case ICollideable::Triangle: return false; // TODO + case ICollideable::BoxAxisAligned: return Utility::intersect( *(Collision::BoxAxisAligned*)target, *this ); + case ICollideable::Box: return Utility::intersect( *(Collision::Box*)target, *this ); + case ICollideable::Frustrum: return false; // TODO + case ICollideable::Line: return false; // TODO + default: return false; + } +} + +bool Plane::Contains( const ICollideable *target ) const +{ + switch( target->type ) + { + case ICollideable::Point: return Utility::intersect( *this, *(Collision::Point*)target ); + case ICollideable::Ray: return Utility::contains( *this, *(Collision::Ray*)target ); + case ICollideable::Plane: return Utility::contains( *this, *(Collision::Plane*)target ); + case ICollideable::Triangle: return false; // TODO + default: return false; + } +} + +ICollideable::State Plane::Advanced( const ICollideable *target ) const +{ return ICollideable::Missed; } //Not supported returns 0 \ No newline at end of file diff --git a/Engine/Collision/Plane.h b/Engine/Collision/Plane.h new file mode 100644 index 00000000..8dc4e894 --- /dev/null +++ b/Engine/Collision/Plane.h @@ -0,0 +1,38 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef OYSTER_COLLISION_PLANE_H +#define OYSTER_COLLISION_PLANE_H + +#include "OysterMath.h" +#include "ICollideable.h" + +namespace Oyster { namespace Collision +{ + class Plane : public ICollideable + { + public: + union + { + struct{ ::Oyster::Math::Float3 normal; ::Oyster::Math::Float phasing; }; + ::Oyster::Math::Float element[4]; + char byte[sizeof(::Oyster::Math::Float3) + sizeof(::Oyster::Math::Float)]; + }; + + Plane( ); + Plane( const Plane &plane ); + Plane( const ::Oyster::Math::Float3 &normal, const ::Oyster::Math::Float &phasing ); + ~Plane( ); + + Plane & operator = ( const Plane &plane ); + + ICollideable* clone( ) const; + bool Intersects( const ICollideable *target ) const; + bool Contains( const ICollideable *target ) const; + ICollideable::State Advanced( const ICollideable *target ) const; //Not supported returns 0; + }; +} } + +#endif \ No newline at end of file diff --git a/Engine/Collision/Point.cpp b/Engine/Collision/Point.cpp new file mode 100644 index 00000000..6a239ae2 --- /dev/null +++ b/Engine/Collision/Point.cpp @@ -0,0 +1,51 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#include "Point.h" +#include "Collision.h" + +using namespace ::Oyster::Collision; +using namespace ::Oyster::Math; + +Point::Point( ) : ICollideable(ICollideable::Point), position() {} +Point::Point( const Point &point ) : ICollideable(ICollideable::Point), position(point.position) {} +Point::Point( const Float3 &pos ) : ICollideable(ICollideable::Point), position(pos) {} +Point::~Point( ) { /*Nothing needs to be done here*/ } + +Point & Point::operator = ( const Point &point ) +{ + this->position = point.position; + return *this; +} + +ICollideable* Point::clone( ) const +{ return new Point( *this ); } + +bool Point::Intersects( const ICollideable *target ) const +{ + switch( target->type ) + { + case ICollideable::Point: return Utility::intersect( *this, *(Collision::Point*)target ); + case ICollideable::Ray: return Utility::intersect( *(Collision::Ray*)target, *this, ((Collision::Ray*)target)->collisionDistance ); + case ICollideable::Sphere: Utility::intersect( *(Collision::Sphere*)target, *this ); + case ICollideable::Plane: return Utility::intersect( *(Collision::Plane*)target, *this ); + case ICollideable::Triangle: return false; // TODO + case ICollideable::BoxAxisAligned: return Utility::intersect( *(Collision::BoxAxisAligned*)target, *this ); + case ICollideable::Box: return Utility::intersect( *(Collision::Box*)target, *this ); + case ICollideable::Frustrum: return false; // TODO + default: return false; + } +} + +bool Point::Contains( const ICollideable *target ) const +{ + switch( target->type ) + { + case ICollideable::Point: return Utility::intersect( *this, *(Collision::Point*)target ); + default: return false; + } +} + +ICollideable::State Point::Advanced( const ICollideable *target ) const +{ return ICollideable::Missed; } //Not supported returns 0 \ No newline at end of file diff --git a/Engine/Collision/Point.h b/Engine/Collision/Point.h new file mode 100644 index 00000000..079161da --- /dev/null +++ b/Engine/Collision/Point.h @@ -0,0 +1,37 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef OYSTER_COLLISION_POINT_H +#define OYSTER_COLLISION_POINT_H + +#include "OysterMath.h" +#include "ICollideable.h" + +namespace Oyster { namespace Collision +{ + class Point : public ICollideable + { + public: + union + { + struct{ ::Oyster::Math::Float3 position; }; + char byte[sizeof(::Oyster::Math::Float3)]; + }; + + Point( ); + Point( const Point &point ); + Point( const ::Oyster::Math::Float3 &position ); + ~Point( ); + + Point & operator = ( const Point &point ); + + ICollideable* clone( ) const; + bool Intersects( const ICollideable *target ) const; + bool Contains( const ICollideable *target ) const; + ICollideable::State Advanced( const ICollideable *target ) const; //Not supported returns 0; + }; +} } + +#endif \ No newline at end of file diff --git a/Engine/Collision/Ray.cpp b/Engine/Collision/Ray.cpp new file mode 100644 index 00000000..56ea1c9a --- /dev/null +++ b/Engine/Collision/Ray.cpp @@ -0,0 +1,54 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#include "Ray.h" +#include "Collision.h" + +using namespace ::Oyster::Collision; +using namespace ::Oyster::Math; + +Ray::Ray( ) : ICollideable(ICollideable::Ray), origin(), direction(), collisionDistance(0.0f) {} +Ray::Ray( const Ray &ray ) : ICollideable(ICollideable::Ray), origin(ray.origin), direction(ray.direction), collisionDistance(0.0f) {} +Ray::Ray( const Float3 &o, const ::Oyster::Math::Float3 &d ) : ICollideable(ICollideable::Ray), origin(o), direction(d), collisionDistance(0.0f) {} +Ray::~Ray( ) { /*Nothing needs to be done here*/ } + +Ray & Ray::operator = ( const Ray &ray ) +{ + this->origin = ray.origin; + this->direction = ray.direction; + this->collisionDistance = ray.collisionDistance; + return *this; +} + +ICollideable* Ray::clone( ) const +{ return new Ray( *this ); } + +bool Ray::Intersects( const ICollideable *target ) const +{ + switch( target->type ) + { + case ICollideable::Point: return Utility::intersect( *this, *(Collision::Point*)target, this->collisionDistance ); + case ICollideable::Ray: return Utility::intersect( *this, *(Collision::Ray*)target, this->collisionDistance, ((Collision::Ray*)target)->collisionDistance ); + case ICollideable::Sphere: return Utility::intersect( *(Collision::Sphere*)target, *this, this->collisionDistance ); + case ICollideable::Plane: return Utility::intersect( *(Collision::Plane*)target, *this, this->collisionDistance ); + case ICollideable::Triangle: return false; // TODO + case ICollideable::BoxAxisAligned: return Utility::intersect( *(Collision::BoxAxisAligned*)target, *this, this->collisionDistance ); + case ICollideable::Box: return Utility::intersect( *(Collision::Box*)target, *this, this->collisionDistance ); + case ICollideable::Frustrum: return false; // TODO + default: return false; + } +} + +bool Ray::Contains( const ICollideable *target ) const +{ + switch( target->type ) + { + case ICollideable::Point: return Utility::intersect( *this, *(Collision::Point*)target, this->collisionDistance ); + case ICollideable::Ray: Utility::contains( *this, *(Collision::Ray*)target ); + default: return false; + } +} + +ICollideable::State Ray::Advanced( const ICollideable *target ) const +{ return ICollideable::Missed; } //Not supported returns 0 \ No newline at end of file diff --git a/Engine/Collision/Ray.h b/Engine/Collision/Ray.h new file mode 100644 index 00000000..a0d88ce4 --- /dev/null +++ b/Engine/Collision/Ray.h @@ -0,0 +1,42 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +/* + Ray::direction is assumed to be normalized! + - Dan +*/ +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef OYSTER_COLLISION_RAY_H +#define OYSTER_COLLISION_RAY_H + +#include "OysterMath.h" +#include "ICollideable.h" + +namespace Oyster { namespace Collision +{ + class Ray : public ICollideable + { + public: + union + { + struct{ ::Oyster::Math::Float3 origin, direction; }; + char byte[2*sizeof(::Oyster::Math::Float3)]; + }; + mutable float collisionDistance; + + Ray( ); + Ray( const Ray &ray ); + Ray( const ::Oyster::Math::Float3 &origin, const ::Oyster::Math::Float3 &normalizedDirection ); + ~Ray( ); + + Ray & operator = ( const Ray &ray ); + + ICollideable* clone( ) const; + bool Intersects( const ICollideable *target ) const; + bool Contains( const ICollideable *target ) const; + ICollideable::State Advanced( const ICollideable *target ) const; //Not supported returns 0; + }; +} } + +#endif \ No newline at end of file diff --git a/Engine/Collision/Sphere.cpp b/Engine/Collision/Sphere.cpp new file mode 100644 index 00000000..c6ccc31f --- /dev/null +++ b/Engine/Collision/Sphere.cpp @@ -0,0 +1,53 @@ +#include "Sphere.h" +#include "Collision.h" + +using namespace ::Oyster::Collision; +using namespace ::Oyster::Math; + +Sphere::Sphere( ) : ICollideable(ICollideable::Sphere), center(), radius(0.0f) { } +Sphere::Sphere( const Sphere &sphere ) : ICollideable(ICollideable::Sphere), center(sphere.center), radius(sphere.radius) {} +Sphere::Sphere( const Float3 &_position, const Float &_radius ) : ICollideable(ICollideable::Sphere), center(_position), radius(_radius) {} +Sphere::~Sphere( ) { /*Nothing needs to be done here*/ } + +Sphere & Sphere::operator = ( const Sphere &sphere ) +{ + this->center = sphere.center; + this->radius = sphere.radius; + return *this; +} + +ICollideable* Sphere::clone( ) const +{ return new Sphere( *this ); } + +bool Sphere::Intersects( const ICollideable *target ) const +{ + switch( target->type ) + { + case ICollideable::Point: return Utility::intersect( *this, *(Collision::Point*)target ); + case ICollideable::Ray: return Utility::intersect( *this, *(Collision::Ray*)target, ((Collision::Ray*)target)->collisionDistance ); + case ICollideable::Sphere: Utility::intersect( *this, *(Collision::Sphere*)target ); + case ICollideable::Plane: return Utility::intersect( *(Collision::Plane*)target, *this ); + case ICollideable::Triangle: return false; // TODO + case ICollideable::BoxAxisAligned: return Utility::intersect( *(Collision::BoxAxisAligned*)target, *this ); + case ICollideable::Box: return Utility::intersect( *(Collision::Box*)target, *this ); + case ICollideable::Frustrum: return false; // TODO + default: return false; + } +} + +bool Sphere::Contains( const ICollideable *target ) const +{ + switch( target->type ) + { + case ICollideable::Point: return Utility::intersect( *this, *(Collision::Point*)target ); + case ICollideable::Sphere: return Utility::contains( *this, *(Collision::Sphere*)target ); + case ICollideable::Triangle: return false; // TODO + case ICollideable::BoxAxisAligned: return false; // TODO + case ICollideable::Box: return false; // TODO + case ICollideable::Frustrum: return false; // TODO + default: return false; + } +} + +ICollideable::State Sphere::Advanced( const ICollideable *target ) const +{ return ICollideable::Missed; } //Not supported returns 0 \ No newline at end of file diff --git a/Engine/Collision/Sphere.h b/Engine/Collision/Sphere.h new file mode 100644 index 00000000..b33ad216 --- /dev/null +++ b/Engine/Collision/Sphere.h @@ -0,0 +1,37 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef OYSTER_COLLISION_SPHERE_H +#define OYSTER_COLLISION_SPHERE_H + +#include "OysterMath.h" +#include "ICollideable.h" + +namespace Oyster { namespace Collision +{ + class Sphere : public ICollideable + { + public: + union + { + struct{ ::Oyster::Math::Float3 center; ::Oyster::Math::Float radius; }; + char byte[sizeof(::Oyster::Math::Float3) + sizeof(::Oyster::Math::Float)]; + }; + + Sphere( ); + Sphere( const Sphere &point ); + Sphere( const ::Oyster::Math::Float3 &position, const ::Oyster::Math::Float &radius ); + ~Sphere( ); + + Sphere & operator = ( const Sphere &sphere ); + + ICollideable* clone( ) const; + bool Intersects( const ICollideable *target ) const; + bool Contains( const ICollideable *target ) const; + ICollideable::State Advanced( const ICollideable *target ) const; //Not supported returns 0; + }; +} } + +#endif \ No newline at end of file diff --git a/Engine/Core/Buffer.cpp b/Engine/Core/Buffer.cpp new file mode 100644 index 00000000..50759848 --- /dev/null +++ b/Engine/Core/Buffer.cpp @@ -0,0 +1,202 @@ +#include "Buffer.h" +#include "Core.h" +using namespace Oyster; + +Buffer::Buffer() +{ + mBuffer = NULL; +} + +Buffer::~Buffer() +{ + SAFE_RELEASE(mBuffer); +} + +HRESULT Buffer::Apply(UINT32 misc) const +{ + HRESULT hr = S_OK; + + switch(mType) + { + case VERTEX_BUFFER: + { + UINT32 vertexSize = mElementSize; + UINT32 offset = 0; + Oyster::Core::DeviceContext->IASetVertexBuffers(misc, 1, &mBuffer, &vertexSize, &offset ); + } + break; + case INDEX_BUFFER: + { + Oyster::Core::DeviceContext->IASetIndexBuffer(mBuffer, DXGI_FORMAT_R32_UINT, 0); + } + break; + case CONSTANT_BUFFER_VS: + { + Oyster::Core::DeviceContext->VSSetConstantBuffers(misc, 1, &mBuffer); + } + break; + case CONSTANT_BUFFER_GS: + { + Oyster::Core::DeviceContext->GSSetConstantBuffers(misc, 1, &mBuffer); + } + break; + case CONSTANT_BUFFER_PS: + { + Oyster::Core::DeviceContext->PSSetConstantBuffers(misc, 1, &mBuffer); + } + break; + case CONSTANT_BUFFER_CS: + { + Oyster::Core::DeviceContext->CSSetConstantBuffers(misc,1,&mBuffer); + } + break; + default: + hr = E_FAIL; + break; + }; + + return hr; +} + +HRESULT Buffer::Init(const BUFFER_INIT_DESC& initDesc) +{ + D3D11_BUFFER_DESC bufferDesc; + + mType = initDesc.Type; + switch(mType) + { + case VERTEX_BUFFER: + { + bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + + if(initDesc.Usage == BUFFER_STREAM_OUT_TARGET) + bufferDesc.BindFlags |= D3D11_BIND_STREAM_OUTPUT; + } + break; + case INDEX_BUFFER: + { + bufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; + } + break; + case STRUCTURED_BUFFER: + { + bufferDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + } + break; + case CONSTANT_BUFFER_CS: + case CONSTANT_BUFFER_VS: + case CONSTANT_BUFFER_GS: + case CONSTANT_BUFFER_PS: + { + bufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + } + break; + default: + return E_FAIL; + break; + }; + + mUsage = initDesc.Usage; + mElementSize = initDesc.ElementSize; + mElementCount = initDesc.NumElements; + + bufferDesc.CPUAccessFlags = 0; + bufferDesc.Usage = D3D11_USAGE_DEFAULT; + + if(mUsage == BUFFER_CPU_READ) + { + bufferDesc.Usage = D3D11_USAGE_DYNAMIC; + bufferDesc.CPUAccessFlags |= D3D11_CPU_ACCESS_READ; + } + else if(mUsage == BUFFER_CPU_WRITE) + { + bufferDesc.Usage = D3D11_USAGE_DYNAMIC; + bufferDesc.CPUAccessFlags |= D3D11_CPU_ACCESS_WRITE; + } + else if(mUsage == BUFFER_CPU_WRITE_DISCARD) + { + bufferDesc.Usage = D3D11_USAGE_DYNAMIC; + bufferDesc.CPUAccessFlags |= D3D11_CPU_ACCESS_WRITE; + } + + //Desc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + bufferDesc.MiscFlags = 0; + bufferDesc.ByteWidth = initDesc.NumElements * initDesc.ElementSize; + bufferDesc.StructureByteStride=0; + if(mType== STRUCTURED_BUFFER) + { + bufferDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; + bufferDesc.StructureByteStride=initDesc.ElementSize; + } + //set at least 16 bytes + if(bufferDesc.ByteWidth < 16) + bufferDesc.ByteWidth = 16; + + HRESULT hr = S_OK; + if(initDesc.InitData) + { + D3D11_SUBRESOURCE_DATA data; + data.pSysMem = initDesc.InitData; + data.SysMemPitch=0; + data.SysMemSlicePitch = 0; + hr = Oyster::Core::Device->CreateBuffer(&bufferDesc, &data, &mBuffer); + } + else + { + hr = Oyster::Core::Device->CreateBuffer(&bufferDesc, NULL, &mBuffer); + } + + if(FAILED(hr)) + { + MessageBox(NULL, "Unable to create buffer.", "Slenda Error", MB_ICONERROR | MB_OK); + } + + return hr; +} + +void* Buffer::Map() +{ + void* ret = NULL; + if(mUsage == BUFFER_CPU_WRITE || mUsage == BUFFER_CPU_READ || mUsage == BUFFER_CPU_WRITE_DISCARD) + { + D3D11_MAPPED_SUBRESOURCE MappedResource; + UINT32 mapType = 0; + + if(mUsage == BUFFER_CPU_READ) mapType = D3D11_MAP_READ; + else if(mUsage == BUFFER_CPU_WRITE) mapType = D3D11_MAP_WRITE; + else if(mUsage == BUFFER_CPU_WRITE_DISCARD) mapType = D3D11_MAP_WRITE_DISCARD; + + HRESULT hr = S_OK; + if(FAILED(hr = Oyster::Core::DeviceContext->Map( + mBuffer, + 0, + (D3D11_MAP)mapType, + 0, + &MappedResource))) + { + ret = NULL; + } + else + { + ret = MappedResource.pData; + } + } + + return ret; + +} + +void Buffer::Unmap() +{ + Oyster::Core::DeviceContext->Unmap( mBuffer, 0 ); +} + +Buffer::operator ID3D11Buffer *() +{ + return this->mBuffer; +} + +Buffer::operator const ID3D11Buffer *() const +{ + return this->mBuffer; +} \ No newline at end of file diff --git a/Engine/Core/Buffer.h b/Engine/Core/Buffer.h new file mode 100644 index 00000000..712c7ac4 --- /dev/null +++ b/Engine/Core/Buffer.h @@ -0,0 +1,76 @@ +#pragma once +#ifndef CoreBuffer +#define CoreBuffer + +#include "Core.h" + +namespace Oyster +{ + class Buffer + { + public: + enum BUFFER_TYPE + { + VERTEX_BUFFER, + INDEX_BUFFER, + CONSTANT_BUFFER_VS, + CONSTANT_BUFFER_GS, + CONSTANT_BUFFER_PS, + CONSTANT_BUFFER_CS, + STRUCTURED_BUFFER, + BUFFER_TYPE_COUNT + }; + + enum BUFFER_USAGE + { + BUFFER_DEFAULT, + BUFFER_STREAM_OUT_TARGET, + BUFFER_CPU_WRITE, + BUFFER_CPU_WRITE_DISCARD, + BUFFER_CPU_READ, + BUFFER_USAGE_COUNT + }; + + struct BUFFER_INIT_DESC + { + BUFFER_TYPE Type; + UINT32 NumElements; + UINT32 ElementSize; + BUFFER_USAGE Usage; + void* InitData; + + BUFFER_INIT_DESC() + { + InitData = NULL; + Usage = BUFFER_DEFAULT; + } + }; + protected: + ID3D11Buffer* mBuffer; + BUFFER_TYPE mType; + BUFFER_USAGE mUsage; + + UINT32 mElementSize; + UINT32 mElementCount; + public: + Buffer(); + virtual ~Buffer(); + + HRESULT Init(const BUFFER_INIT_DESC& initDesc); + + void* Map(); + void Unmap(); + + operator ID3D11Buffer*(); + operator const ID3D11Buffer*() const; + + HRESULT Apply(UINT32 misc = 0) const; + + ID3D11Buffer* GetBufferPointer(); + UINT32 GetVertexSize(); + UINT32 GetElementCount(); + }; + +} + +#endif \ No newline at end of file diff --git a/Engine/Core/Core.cpp b/Engine/Core/Core.cpp new file mode 100644 index 00000000..feb7a65c --- /dev/null +++ b/Engine/Core/Core.cpp @@ -0,0 +1,164 @@ +#include "Core.h" +#include "..\Window\Window.h" + +using namespace Oyster; +using std::string; + +//GPU +ID3D11Device *Core::Device = NULL; + +//API +ID3D11DeviceContext *Core::DeviceContext = NULL; + +//SwapChain +IDXGISwapChain* Core::SwapChain = NULL; + +std::stringstream Log; + +inline std::stringstream* AccesLog(){return &Log;} + +bool Core::Init(bool SingleThreaded, bool Reference,bool ForceDX11) +{ + UINT createDeviceFlags = 0; + + if( SingleThreaded ) + createDeviceFlags = ::D3D11_CREATE_DEVICE_SINGLETHREADED; + + ::D3D_DRIVER_TYPE driverType = ::D3D_DRIVER_TYPE_HARDWARE; + + if(Reference) + driverType = D3D_DRIVER_TYPE_REFERENCE; + + /*#if defined(DEBUG) || defined(_DEBUG) + Log << "DirectX running in debug mode.\n"; + createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; + #endif*/ + + + D3D_FEATURE_LEVEL featureLevelsToTry[] = + { + D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_1, + D3D_FEATURE_LEVEL_10_0 + }; + D3D_FEATURE_LEVEL initiatedFeatureLevel; + + if( FAILED( ::D3D11CreateDevice( NULL, // default adapter + driverType, + NULL, // no software device + createDeviceFlags, + featureLevelsToTry, 3, // default feature level array. DX11 support assumed + D3D11_SDK_VERSION, + &Device, // device + &initiatedFeatureLevel, + &DeviceContext ) ) ) // context + { // if failed + if( DeviceContext ) { DeviceContext->Release(); DeviceContext = NULL; } // safe cleanup + if( Device ) { Device->Release(); Device = NULL; } // safe cleanup + } + + if( driverType == ::D3D_DRIVER_TYPE_HARDWARE ) + Log << "D3D_DRIVER_TYPE_HARDWARE support discovered.\n"; + else + Log << "D3D_DRIVER_TYPE_REFERENCE support discovered.\n"; + + if( initiatedFeatureLevel == ::D3D_FEATURE_LEVEL_11_0 ) + { + Log << "DirectX Featurelevel 11.0 supported.\n"; + } + else + { + if(ForceDX11) + return false; + if( initiatedFeatureLevel == ::D3D_FEATURE_LEVEL_10_1 ) + { + Log << "DirectX Featurelevel 10.1 supported.\n"; + } + else + { + if( initiatedFeatureLevel == ::D3D_FEATURE_LEVEL_10_0 ) + { + Log << "DirectX Featurelevel 10.0 supported.\n"; + } + } + } + if(Device) + return true; + + return false; +} + +bool Core::CreateSwapChain(HWND Window, int NrofBuffers,bool MSAA_Quality,bool Fullscreen) +{ + //generate static Swapchain Desc + DXGI_SWAP_CHAIN_DESC desc; + desc.OutputWindow=Window; + desc.BufferCount=NrofBuffers; + desc.Windowed=!Fullscreen; + desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_UNORDERED_ACCESS; + desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + desc.Flags=0; + desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; + desc.BufferDesc.Scaling = DXGI_MODE_SCALING_CENTERED; + desc.BufferDesc.RefreshRate.Denominator=1; + desc.BufferDesc.RefreshRate.Numerator=60; + desc.BufferDesc.Height = Window::Size.bottom; + desc.BufferDesc.Width = Window::Size.left; + + //Check and Set multiSampling + if(MSAA_Quality) + { + if(FAILED(Device->CheckMultisampleQualityLevels(DXGI_FORMAT_R8G8B8A8_UNORM,4,&desc.SampleDesc.Quality))) + { + Log<< "Failed to check multisample quality levels (MSAAQuality).\n"; + return false; + } + desc.SampleDesc.Count=4; + --desc.SampleDesc.Quality; + Log << "Supported multisample quality levels (MSAAQuality): " << desc.SampleDesc.Quality+1 << "x\n"; + } + else + { + desc.SampleDesc.Count=1; + desc.SampleDesc.Quality=0; + } + + //Get Device Factory + ::IDXGIDevice *dxgiDevice = NULL; + if( FAILED( Device->QueryInterface( __uuidof( IDXGIDevice ), (void**)&dxgiDevice ) ) ) + { + Log << "Failed to Query for the GPU's dxgiDevice.\nFailed to create swapChain for the GPU.\n"; + return false; + } + + ::IDXGIAdapter *dxgiAdapter = NULL; + if( FAILED( dxgiDevice->GetParent( __uuidof( IDXGIAdapter ), (void**)&dxgiAdapter ) ) ) + { + dxgiDevice->Release(); + Log << "Failed to get GPU's parent dxgiAdapter.\nFailed to create swapChain for the GPU.\n"; + return false; + } + dxgiDevice->Release(); + + ::IDXGIFactory *dxgiFactory = NULL; + if( FAILED( dxgiAdapter->GetParent( __uuidof( IDXGIFactory ), (void**)&dxgiFactory ) ) ) + { + dxgiAdapter->Release(); + Log << "Failed to get GPU's parent dxgiFactory.\nFailed to create swapChain for the GPU.\n"; + return false; + } + dxgiAdapter->Release(); + + //Create SwapChain + if( FAILED( dxgiFactory->CreateSwapChain( Device, &desc, &SwapChain ) ) ) + { + dxgiFactory->Release(); + Log << "Failed to create swapChain for the GPU.\n"; + return false; + } + + dxgiFactory->Release(); + + return true; +} \ No newline at end of file diff --git a/Engine/Core/Core.h b/Engine/Core/Core.h new file mode 100644 index 00000000..7cca37fb --- /dev/null +++ b/Engine/Core/Core.h @@ -0,0 +1,30 @@ +#pragma once + +#ifndef Core_h +#define Core_h + + +#include "CoreIncludes.h" +#include +namespace Oyster +{ + class Core + { + public: + + static ID3D11Device* Device; + + static ID3D11DeviceContext* DeviceContext; + + static IDXGISwapChain* SwapChain; + + static std::stringstream* AccesLog(); + + static bool Init(bool SingleThreaded,bool Reference,bool ForceDX11); + + static bool CreateSwapChain(HWND Window, int NrofBuffers,bool MSAA_Quality,bool Fullscreen); + }; +} + + +#endif \ No newline at end of file diff --git a/Engine/Core/CoreIncludes.h b/Engine/Core/CoreIncludes.h new file mode 100644 index 00000000..68a0c683 --- /dev/null +++ b/Engine/Core/CoreIncludes.h @@ -0,0 +1,40 @@ +#pragma once +#ifndef CORE_INCLUDE +#define CORE_INCLUDE + +#define NOMINMAX // Because I hate Microsoft now. ~Angry Dan. +// http://lolengine.net/blog/2011/3/4/fuck-you-microsoft-near-far-macros +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define SAFE_RELEASE(x) if( x ) { (x)->Release(); (x) = NULL; } +#define SAFE_DELETE(x) if( x ) { delete(x); (x) = NULL; } +#define SAFE_DELETE_ARRAY(x) if( x ) { delete[](x); (x) = NULL; } +#define PI (3.14159265358979323846f) + +#pragma comment(lib, "d3d11.lib") +#pragma comment(lib, "d3dcompiler.lib") +#pragma comment (lib,"dxerr.lib") + +#ifdef _DEBUG +#pragma comment(lib, "d3dx11d.lib") +#pragma comment(lib, "Effects11D.lib") +#pragma comment(lib, "d3dx10d.lib") +#else +#pragma comment(lib, "d3dx11.lib") +#pragma comment(lib, "Effects11.lib") +#pragma comment(lib, "d3dx10.lib") +#endif + + +#endif \ No newline at end of file diff --git a/Engine/Engine.cpp b/Engine/Engine.cpp new file mode 100644 index 00000000..4dd2aad0 --- /dev/null +++ b/Engine/Engine.cpp @@ -0,0 +1,539 @@ +#include "Engine.h" + +bool CreateDepthStencil(bool MSAA_Quality); +bool CreateRenderTarget(); +void SetViewPort(); + +class oysterPrivates +{ +public: + bool instance,swapChained; + ID3D11DepthStencilView* depth; + ID3D11RenderTargetView *rtv; + ID3D11UnorderedAccessView *uav; + ID3D11ShaderResourceView* depthTexture; + DXGI_SAMPLE_DESC sampleDesc; + D3D11_VIEWPORT viewPort; + oysterPrivates():instance(false),swapChained(false),depth(NULL),rtv(NULL), depthTexture(NULL){}; + class State + { + public: + int NrOfSamples; + int SampleSpread; + int NrOfPointlights; + }States; + +}instance; + +Oyster::Engine::Engine() +{ +} + +Oyster::Engine::~Engine() +{ +} + +//Init +bool Oyster::Engine::Init::IsInstanced() +{ + return instance.instance; +} + +bool Oyster::Engine::Init::Instance(bool SingleThreaded,bool Reference,bool ForceDX11) +{ + if(!instance.instance) + if(Oyster::Core::Init(SingleThreaded,Reference,ForceDX11)) + instance.instance=true; + + return instance.instance; +} + +bool Oyster::Engine::Init::HasSwapChain() +{ + return instance.swapChained; +} + +bool Oyster::Engine::Init::CreateSwapChain(HWND Window,int NrofBuffers,bool MSAA_Quality,bool Fullscreen) +{ + if(Window==0) + { + if(Oyster::Window::Handle==0) + return false; + else + Window = Oyster::Window::Handle; + } + if(!instance.swapChained) + { + if(Oyster::Core::CreateSwapChain(Window,NrofBuffers,MSAA_Quality,Fullscreen)) + instance.swapChained=true; + } + + return instance.swapChained; +} + +bool Oyster::Engine::Init::InitializeWindow(const LPCSTR appName, const LPCSTR className,const HINSTANCE &hInstance, const int &nCmdShow, WNDPROC wProc, bool handleLoop ) +{ + return Oyster::Window::init(appName,className,hInstance,nCmdShow,wProc,handleLoop); +} + +bool Oyster::Engine::Init::FullInit(const Setup& setup) +{ + if(!Oyster::Engine::Init::Instance(setup.Common.SingleThreaded,setup.Common.Reference,setup.Common.ForceDX11)) + return false; + if(setup.Window.InitWindow) + if(!Oyster::Engine::Init::InitializeWindow(setup.Window.appname,setup.Window.classname,setup.Window.hinstance,setup.Window.nCmdShow,setup.Window.wProc, true)) + return false; + if(!Oyster::Engine::Init::CreateSwapChain(NULL,setup.Common.NrOfBuffers,setup.Common.MSAA_Quality,setup.Common.Fullscreen)) + return false; + if(!Oyster::Shader::InitShaders()) + return false; + if(setup.Common.GenerateDepthStencil) + if(!CreateDepthStencil(setup.Common.MSAA_Quality)) + return false; + if(!CreateRenderTarget()) + return false; + if(!Oyster::Render::Textbox::Init()) + return false; + SetViewPort(); + if(setup.Common.BindDefault) + Oyster::Engine::PrepareForRendering::BindRenderTargets(&instance.rtv,1,instance.depth); + + instance.States.NrOfSamples = 14; + instance.States.SampleSpread = 4; + instance.States.NrOfPointlights = 1024; + + Oyster::Resources::Buffers::Init(); + Oyster::Resources::ShaderEffects::Init(); + Oyster::Resources::PipeLineResourses::Init(); + return true; + +} + +Oyster::Buffer* Oyster::Engine::Init::Buffers::CreateBuffer(const Oyster::Buffer::BUFFER_INIT_DESC desc) +{ + Oyster::Buffer *buffy = new Oyster::Buffer(); + buffy->Init(desc); + return buffy; +} + + +//PrepareForRendering +void Oyster::Engine::PrepareForRendering::BindRenderTargets(ID3D11RenderTargetView** RenderTargets,int NrOfTargets,ID3D11DepthStencilView* depth) +{ + Oyster::Core::DeviceContext->OMSetRenderTargets(NrOfTargets,RenderTargets,depth); +} + +void Oyster::Engine::PrepareForRendering::BindRenderTargets(ID3D11RenderTargetView** RenderTargets,int NrOfTargets) +{ + Oyster::Core::DeviceContext->OMSetRenderTargets(NrOfTargets,RenderTargets,instance.depth); +} + +void Oyster::Engine::PrepareForRendering::BindBackBufferAsUAV() +{ + Oyster::Core::DeviceContext->CSSetUnorderedAccessViews(0,1,&instance.uav,0); +} + +void Oyster::Engine::PrepareForRendering::BindUAV(ID3D11UnorderedAccessView** uav, int NrOfUavs) +{ + Oyster::Core::DeviceContext->CSSetUnorderedAccessViews(0,NrOfUavs,uav,0); +} + +void Oyster::Engine::PrepareForRendering::ClearBackBuffer(Math::Float4 color) +{ + Oyster::Core::DeviceContext->ClearRenderTargetView(instance.rtv,(float*)color); + Oyster::Core::DeviceContext->ClearDepthStencilView(instance.depth,1,1,0); +} + +void Oyster::Engine::PrepareForRendering::BindBackBuffer(ID3D11DepthStencilView* depth) +{ + Oyster::Core::DeviceContext->OMSetRenderTargets(1,&instance.rtv,depth); +} + +void Oyster::Engine::PrepareForRendering::BindBackBuffer() +{ + Oyster::Core::DeviceContext->OMSetRenderTargets(1,&instance.rtv,instance.depth); +} + +void Oyster::Engine::PrepareForRendering::Begin2DRender() +{ + Oyster::Resources::Buffers::V2DSprites.Apply(); + Oyster::Resources::Buffers::CBufferGs.Apply(); + Shader::SetShaderEffect(Oyster::Resources::ShaderEffects::BasicSprite); +} + +void Oyster::Engine::PrepareForRendering::Begin2DTextRender() +{ + Oyster::Render::Textbox::TextBuffer.Apply(); + Oyster::Resources::Buffers::CBufferGs.Apply(); + Oyster::Shader::SetShaderEffect(Oyster::Resources::ShaderEffects::Text2DEffect); +} + + +//Render +void Oyster::Engine::Render::PresentScene() +{ + Core::SwapChain->Present(0,0); +} + +void Oyster::Engine::Render::Geometry(const Oyster::Render::Model* models,int count,Oyster::Buffer* cBufferEveryObject, int slot) +{ + if(cBufferEveryObject) + cBufferEveryObject->Apply(slot); + for(int i=0;iMap(); + memcpy(data,&(models[i].World->getTranspose()),64); + cBufferEveryObject->Unmap(); + } + Oyster::Core::DeviceContext->PSSetShaderResources(0,models[i].info->Material.size(),&(models[i].info->Material[0])); + + models[i].info->Vertices.Apply(); + if(models[i].info->Indexed) + { + models[i].info->Indecies.Apply(); + Oyster::Core::DeviceContext->DrawIndexed(models[i].info->VertexCount,0,0); + } + else + Oyster::Core::DeviceContext->Draw(models[i].info->VertexCount,0); + } + } +} + +void Oyster::Engine::Render::Text(std::string text, Oyster::Math::Float2 size, Oyster::Math::Float3 Pos) +{ + Pos.x -= Oyster::Window::Size.left/2; + Pos.x += size.x; + + Pos.y -= Oyster::Window::Size.bottom/2; + Pos.y += size.y; + + Matrix m; + Math::identityMatrix(m); + float width = (1.0f/(Window::Size.left/2.0f)); + float height = (1.0f/(Window::Size.bottom/2.0f)); + m.m41=Pos.x * width; + m.m42=-Pos.y * height; + m.m43=Pos.z; + m.m11=width*size.x; + m.m22=height*size.y; + void* dest = Resources::Buffers::CBufferGs.Map(); + memcpy(dest,&m.getTranspose(),64); + Resources::Buffers::CBufferGs.Unmap(); + Oyster::Render::Textbox::Update(text, size.x); + Oyster::Engine::PrepareForRendering::Begin2DTextRender(); + Oyster::Core::DeviceContext->PSSetShaderResources(0,1,&(Oyster::Render::Textbox::Texture)); + //Should be able to be outside of the for loop. Keeping it here for now though. + Oyster::Core::DeviceContext->Draw(Oyster::Render::Textbox::NumLetters, 0); +} + +void Oyster::Engine::Render::ScreenQuad(ID3D11ShaderResourceView* srv, float ZPos) +{ + + Oyster::Core::DeviceContext->PSSetShaderResources(0,1,&srv); + + Matrix m; + Math::identityMatrix(m); + m.m43=ZPos; + + void* dest = Resources::Buffers::CBufferGs.Map(); + memcpy(dest,&m.getTranspose(),64); + Resources::Buffers::CBufferGs.Unmap(); + + Oyster::Core::DeviceContext->Draw(1,0); +} + +void Oyster::Engine::Render::Sprite(ID3D11ShaderResourceView* srv, Oyster::Math::Float2 size, Oyster::Math::Float3 Pos) +{ + + Oyster::Core::DeviceContext->PSSetShaderResources(0,1,&srv); + + Pos.x -= Oyster::Window::Size.left/2; + Pos.x += size.x/2; + + Pos.y -= Oyster::Window::Size.bottom/2; + Pos.y += size.y/2; + + Matrix m; + Math::identityMatrix(m); + float width = (1.0f/(Window::Size.left/2.0f)); + float height = (1.0f/(Window::Size.bottom/2.0f)); + m.m41=Pos.x * width; + m.m42=-Pos.y * height; + m.m43=Pos.z; + m.m11=width*size.x/2; + m.m22=height*size.y/2; + + void* dest = Resources::Buffers::CBufferGs.Map(); + memcpy(dest,&m.getTranspose(),64); + Resources::Buffers::CBufferGs.Unmap(); + + Oyster::Core::DeviceContext->Draw(1,0); +} + +//Misc +bool CreateDepthStencil(bool MSAA_Quality) +{ + + D3D11_TEXTURE2D_DESC desc; + desc.MipLevels=1; + desc.ArraySize=1; + desc.Format = DXGI_FORMAT_D32_FLOAT; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_DEPTH_STENCIL; + desc.CPUAccessFlags=0; + desc.MiscFlags=0; + desc.Height = Oyster::Window::Size.bottom; + desc.Width = Oyster::Window::Size.left; + + + //Check and Set multiSampling + if(MSAA_Quality) + { + if(FAILED(Oyster::Core::Device->CheckMultisampleQualityLevels(DXGI_FORMAT_R8G8B8A8_UNORM,4,&desc.SampleDesc.Quality))) + { + //Log<< "Failed to check multisample quality levels (MSAAQuality).\n"; + return false; + } + desc.SampleDesc.Count=4; + --desc.SampleDesc.Quality; + //Log << "Supported multisample quality levels (MSAAQuality): " << desc.SampleDesc.Quality+1 << "x\n"; + } + else + { + desc.SampleDesc.Count=1; + desc.SampleDesc.Quality=0; + } + + ID3D11Texture2D* depthstencil; + + if(FAILED(Oyster::Core::Device->CreateTexture2D(&desc,0,&depthstencil))) + return false; + if(FAILED(Oyster::Core::Device->CreateDepthStencilView(depthstencil,0,&instance.depth))) + { + depthstencil->Release(); + return false; + } + depthstencil->Release(); + + + + return true; +} + +bool CreateRenderTarget() +{ + D3D11_UNORDERED_ACCESS_VIEW_DESC descView; + ZeroMemory( &descView, sizeof(descView) ); + descView.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2D; + descView.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + descView.Texture2D.MipSlice=0; + + ID3D11Texture2D* backBuffer; + if(FAILED(Oyster::Core::SwapChain->GetBuffer(0,__uuidof(ID3D11Texture2D),reinterpret_cast(&backBuffer)))) + return false; + if(FAILED(Oyster::Core::Device->CreateRenderTargetView(backBuffer,0,&instance.rtv))) + { + backBuffer->Release(); + return false; + } + if(FAILED(Oyster::Core::Device->CreateUnorderedAccessView(backBuffer,0,&instance.uav))) + { + backBuffer->Release(); + return false; + } + + backBuffer->Release(); + + return true; +} + +void SetViewPort() +{ + instance.viewPort.TopLeftX = 0.0f; + instance.viewPort.TopLeftY = 0.0f; + instance.viewPort.Width = (float)Oyster::Window::Size.left; + instance.viewPort.Height = (float)Oyster::Window::Size.bottom; + instance.viewPort.MinDepth = 0.0f; + instance.viewPort.MaxDepth = 1.0f; + + Oyster::Core::DeviceContext->RSSetViewports(1,&instance.viewPort); +} + +void Blur(int target) +{ + //TODO: proper size calculation + + //bind input + Oyster::Core::DeviceContext->CSSetShaderResources(0,1,&Oyster::Resources::PipeLineResourses::LightOut[target]); + Oyster::Engine::PrepareForRendering::BindUAV(&Oyster::Resources::PipeLineResourses::TempUav,1); + + //dispatch blurr horizontal + Oyster::Shader::Set::SetCompute(Oyster::Shader::Get::GetCompute("BlurHorizontal")); + Oyster::Core::DeviceContext->Dispatch(7,Oyster::Window::Size.bottom,1); + + //clean Pipeline + Oyster::Core::DeviceContext->CSSetShaderResources(0,16,&Oyster::Resources::PipeLineResourses::SrvNulls[0]); + Oyster::Core::DeviceContext->CSSetUnorderedAccessViews(0,8,&Oyster::Resources::PipeLineResourses::uavNULL[0],0); + + //bind input + Oyster::Core::DeviceContext->CSSetShaderResources(0,1,&Oyster::Resources::PipeLineResourses::TempSrv); + Oyster::Engine::PrepareForRendering::BindUAV(&Oyster::Resources::PipeLineResourses::LightTarget[target],1); + + //dispatch blurr vertical + Oyster::Shader::Set::SetCompute(Oyster::Shader::Get::GetCompute("BlurVertical")); + Oyster::Core::DeviceContext->Dispatch(Oyster::Window::Size.left,5,1); + + //clean Pipeline + Oyster::Core::DeviceContext->CSSetShaderResources(0,16,&Oyster::Resources::PipeLineResourses::SrvNulls[0]); + Oyster::Core::DeviceContext->CSSetUnorderedAccessViews(0,8,&Oyster::Resources::PipeLineResourses::uavNULL[0],0); +} + + +//Pipeline Render +void Oyster::Engine::Pipeline::Deffered_Lightning::NewFrame(const Float4& col, const Matrix& View, const Matrix& Projection) +{ + //diffuse + Oyster::Core::DeviceContext->ClearRenderTargetView( Oyster::Resources::PipeLineResourses::GeometryTarget[0], col); + + //Specular + Oyster::Core::DeviceContext->ClearRenderTargetView( Oyster::Resources::PipeLineResourses::GeometryTarget[1], col); + + //Glow + Oyster::Core::DeviceContext->ClearRenderTargetView( Oyster::Resources::PipeLineResourses::GeometryTarget[2], col); + + //Pos + Oyster::Core::DeviceContext->ClearRenderTargetView( Oyster::Resources::PipeLineResourses::GeometryTarget[3], col); + + //Normal + Oyster::Core::DeviceContext->ClearRenderTargetView( Oyster::Resources::PipeLineResourses::GeometryTarget[4], col); + + Oyster::Engine::PrepareForRendering::ClearBackBuffer(col); + + //Upload Camera to Resources + + Matrix P = Oyster::Math::Float4x4(Projection); + Matrix V = Oyster::Math::Float4x4(View); + Matrix VP = V*P; + + Oyster::Resources::PipeLineResourses::LightData.projectionMatrix = P.getTranspose(); + Oyster::Resources::PipeLineResourses::LightData.viewMatrix = V; + + Oyster::Collision::Frustrum( VP ).split(Oyster::Resources::PipeLineResourses::SubFrustrums, Oyster::Resources::PipeLineResourses::FrustrumDimensions.x, Oyster::Resources::PipeLineResourses::FrustrumDimensions.y, Oyster::Resources::PipeLineResourses::FrustrumDimensions.z ); + + void* dest = Oyster::Resources::ShaderEffects::ModelEffect.CBuffers.Vertex[0]->Map(); + memcpy(dest,&VP.getTranspose(),64); + Oyster::Resources::ShaderEffects::ModelEffect.CBuffers.Vertex[0]->Unmap(); + + dest= Oyster::Resources::ShaderEffects::ModelEffect.CBuffers.Vertex[1]->Map(); + memcpy(dest,&V.getTranspose(),64); + Oyster::Resources::ShaderEffects::ModelEffect.CBuffers.Vertex[1]->Unmap(); + + dest = Oyster::Resources::PipeLineResourses::Resources[0]->Map(); + unsigned int bytes=0; + for(int i=0;iUnmap(); + + dest = Oyster::Resources::Buffers::CBufferPipelineCs.Map(); + memcpy(dest, &Oyster::Resources::PipeLineResourses::LightData, sizeof( Oyster::Resources::BufferDefinitions::LightStructureBuffer ) ); + Oyster::Resources::Buffers::CBufferPipelineCs.Unmap(); + +} + +void Oyster::Engine::Pipeline::Deffered_Lightning::BeginRenderGeometry() +{ + Oyster::Engine::PrepareForRendering::BindRenderTargets( Oyster::Resources::PipeLineResourses::GeometryTarget, 5 ); + Oyster::Shader::SetShaderEffect( Oyster::Resources::ShaderEffects::ModelEffect ); +} + +void Oyster::Engine::Pipeline::Deffered_Lightning::RenderGeometry(const Oyster::Render::Model* models,int count) +{ + //TODO: Add sorting to minimiza state changes + Render::Geometry( models, count, &Oyster::Resources::Buffers::CbufferVS, 2 ); +} + +void Oyster::Engine::Pipeline::Deffered_Lightning::EndRenderGeometry() +{ + //TODO: Actualy Render data from previous pass + Oyster::Engine::PrepareForRendering::BindRenderTargets( Oyster::Resources::PipeLineResourses::RtvNulls, 8, NULL ); + Oyster::Core::DeviceContext->PSSetShaderResources(0, 16, Oyster::Resources::PipeLineResourses::SrvNulls); +} + +void Oyster::Engine::Pipeline::Deffered_Lightning::InputPointLights(Oyster::Resources::BufferDefinitions::PointLightDescription *p, int nr) +{ + void* dest = Oyster::Resources::PipeLineResourses::Resources[1]->Map(); + memcpy(dest, p, sizeof(Oyster::Resources::BufferDefinitions::PointLightDescription) * nr ); + Oyster::Resources::PipeLineResourses::Resources[1]->Unmap(); +} + +void Oyster::Engine::Pipeline::Deffered_Lightning::RenderLightning() +{ + Oyster::Engine::PrepareForRendering::BindUAV( Oyster::Resources::PipeLineResourses::LightTarget, 4 ); + Oyster::Core::DeviceContext->CSSetShaderResources(0,5, Oyster::Resources::PipeLineResourses::GeometryOut); + Oyster::Resources::Buffers::CBufferPipelineCs.Apply(); + Oyster::Core::DeviceContext->CSSetShaderResources( 6, 4, Oyster::Resources::PipeLineResourses::ComputeResources ); + Oyster::Shader::Set::SetCompute( Oyster::Shader::Get::GetCompute("Pass0") ); + + Oyster::Core::DeviceContext->Dispatch( 49, 36, 1 ); + + //clean Pipeline + Oyster::Core::DeviceContext->CSSetShaderResources( 0, 16, Oyster::Resources::PipeLineResourses::SrvNulls ); + Oyster::Core::DeviceContext->CSSetUnorderedAccessViews( 0, 8, Oyster::Resources::PipeLineResourses::uavNULL, 0 ); + + //Blurr + //Blur( 2 ); + //Blur( 3 ); + + //clean Pipeline + Oyster::Core::DeviceContext->CSSetShaderResources( 0, 16, Oyster::Resources::PipeLineResourses::SrvNulls ); + Oyster::Core::DeviceContext->CSSetUnorderedAccessViews( 0, 8, Oyster::Resources::PipeLineResourses::uavNULL, 0 ); + + //prepare and render final pass + Oyster::Engine::PrepareForRendering::BindBackBufferAsUAV(); + Oyster::Shader::Set::SetCompute( Oyster::Shader::Get::GetCompute("Pass1") ); + Oyster::Core::DeviceContext->CSSetShaderResources( 0, 4, Oyster::Resources::PipeLineResourses::LightOut ); + + Oyster::Core::DeviceContext->Dispatch( 49, 36, 1 ); + + //clean Pipeline + Oyster::Core::DeviceContext->CSSetShaderResources( 0, 16, Oyster::Resources::PipeLineResourses::SrvNulls ); + Oyster::Core::DeviceContext->CSSetUnorderedAccessViews( 0, 8, Oyster::Resources::PipeLineResourses::uavNULL, 0 ); +} + + +//States +int Oyster::Engine::States::GetNrOfSSAOSamples() +{ + return instance.States.NrOfSamples; +} + +void Oyster::Engine::States::SetNrOfSSAOSamples(int nr) +{ + instance.States.NrOfSamples = nr; +} + +int Oyster::Engine::States::GetSSAOSampleSpread() +{ + return instance.States.SampleSpread; +} + +void Oyster::Engine::States::SetSSAOSampleSpread(int spread) +{ + instance.States.SampleSpread = spread; +} + +int Oyster::Engine::States::GetMaxPointlights() +{ + return instance.States.NrOfPointlights; +} + +void Oyster::Engine::States::SetMaxPointlights(int nr) +{ + instance.States.NrOfPointlights = nr; +} \ No newline at end of file diff --git a/Engine/Engine.h b/Engine/Engine.h new file mode 100644 index 00000000..a9ef953c --- /dev/null +++ b/Engine/Engine.h @@ -0,0 +1,177 @@ +#pragma once + +#ifndef Engine_h +#define Engine_h + +#define NOMINMAX // Because I hate Microsoft now. ~Angry Dan. http://lolengine.net/blog/2011/3/4/fuck-you-microsoft-near-far-macros + +#include "EngineIncludes.h" + +namespace Oyster +{ + class Engine + { + private: + Engine(); + ~Engine(); + + public: + class Init + { + public: + struct Setup + { + struct + { + bool InitWindow; + LPCSTR appname; + LPCSTR classname; + HINSTANCE hinstance; + int nCmdShow; + WNDPROC wProc; + bool ManageWindow; + }Window; + struct + { + int NrOfBuffers; + bool MSAA_Quality; + bool Fullscreen; + bool SingleThreaded; + bool Reference; + bool ForceDX11; + bool GenerateDepthStencil; + bool BindDefault; + }Common; + //all but Window params have Default Values + Setup() + { + Common.NrOfBuffers=1; + Common.MSAA_Quality = false; + Common.Fullscreen = true; + Common.SingleThreaded = true; + Common.Reference = false; + Common.ForceDX11 = false; + Common.GenerateDepthStencil = true; + Common.BindDefault = true; + } + + }; + + static bool IsInstanced(); + + //Creates Device and DeviceContext, if not Initialized + static bool Instance(bool SingleThreaded=true,bool Reference=false,bool ForceDX11=false); + static bool HasSwapChain(); + + //Creates Swapchain, if not Aready Created + static bool CreateSwapChain(HWND Window, int NrofBuffers=1,bool MSAA_Quality=false,bool Fullscreen=true); + + //CreateWindow, if Not Already Created + static bool InitializeWindow(const LPCSTR appName, const LPCSTR className,const HINSTANCE &hInstance, const int &nCmdShow, WNDPROC wProc, bool HandleLoop = false ); + + //Performs a full initialization of a rendering pipeline, including a Window + static bool FullInit(const Setup& setup); + struct Buffers + { + static Buffer* CreateBuffer(const Buffer::BUFFER_INIT_DESC BufferDesc); + }; + private: + Init(); + ~Init(); + }; + + class States + { + public: + //SSAO Quality + static void SetNrOfSSAOSamples(int); + static int GetNrOfSSAOSamples(); + + //SSAO Frequency + static void SetSSAOSampleSpread(int); + static int GetSSAOSampleSpread(); + + //PointLights + static void SetMaxPointlights(int); + static int GetMaxPointlights(); + + + private: + States(); + ~States(); + }; + + class Render + { + public: + /// Render a number of models, setting the Per model data to the included cBuffer + /// specify NULL if no such data exists + static void Geometry(const Oyster::Render::Model* models,int count,Oyster::Buffer* cBufferEveryObject, int slot); + static void Text(std::string text, Oyster::Math::Float2 size, Oyster::Math::Float3 Pos); + //static void TextBox(const Oyster::Render:: + + //ensure that a compatible 2D shadereffect is applied + static void ScreenQuad(ID3D11ShaderResourceView* srv, float ZPos=1); + + //ensure that a compatible 2D shadereffect is applied and that pos.z is between 0 and 1 + static void Sprite(ID3D11ShaderResourceView* srv, Oyster::Math::Float2 size, Oyster::Math::Float3 Pos); + + static void PresentScene(); + + private: + Render(); + ~Render(); + }; + + class PrepareForRendering + { + public: + //Binds several rendertargets and a depthstencil + static void BindRenderTargets(ID3D11RenderTargetView** RenderTargets,int NrOfTargets,ID3D11DepthStencilView* depth); + + //Binds several Rendertargest and a default depthstencil + static void BindRenderTargets(ID3D11RenderTargetView** RenderTargets,int NrOfTargets); + + //Binds the backbuffer and a depthstencil + static void BindBackBuffer(ID3D11DepthStencilView* depth); + + //Binds the backbuffer and a default depthstencil + static void BindBackBuffer(); + + //Binds the backbuffer to the compute shader + static void BindBackBufferAsUAV(); + + //binds several UAV to the computeshader + static void BindUAV(ID3D11UnorderedAccessView** uav, int NrOfUavs); + + //Clears the backbuffer and default depthstencil + static void ClearBackBuffer(Math::Float4 color); + + static void Begin2DRender(); + + static void Begin2DTextRender(); + }; + + class Pipeline + { + public: + class Deffered_Lightning + { + public: + //Basic Setup + static void NewFrame(const Float4& Color, const Matrix& View, const Matrix& Projection); + + //Geometry Pass + static void BeginRenderGeometry(); + static void RenderGeometry(const Oyster::Render::Model* models,int count); + static void EndRenderGeometry(); + + //Lightning Pass + static void InputPointLights(Oyster::Resources::BufferDefinitions::PointLightDescription *p, int NrOfPointlights ); + static void RenderLightning(); + }; + }; + }; +}; + +#endif \ No newline at end of file diff --git a/Engine/EngineIncludes.h b/Engine/EngineIncludes.h new file mode 100644 index 00000000..e1a763db --- /dev/null +++ b/Engine/EngineIncludes.h @@ -0,0 +1,38 @@ +//Oyster + +// Render +#include "Render\Model.h" +#include "Render\Camera.h" +#include "Render\TextBox.h" + +// Core +#include "Core\Core.h" +#include "Core\Buffer.h" + +// Shader +#include "Shader\Shader.h" + +// Math +#include "Math\OysterMath.h" + +// FileLoader +#include "FileLoader\ObjReader.h" + +// Windows +#include "Window\Window.h" + +// Input +#include "Input\InputController.h" + +// Collision +#include "Collision\Collision.h" + +// Game Definitions +#include "Game\OysterGame.h" + +// Resources +#include "Resourses\ShaderEffects.h" +#include "Resourses\Buffers.h" +#include "Resourses\PipelineResources.h" +#include "Resourses\GraphicsDefinitions.h" +#include "Resourses\Manager.h" \ No newline at end of file diff --git a/Engine/FileLoader/ObjReader.cpp b/Engine/FileLoader/ObjReader.cpp new file mode 100644 index 00000000..e4d12b91 --- /dev/null +++ b/Engine/FileLoader/ObjReader.cpp @@ -0,0 +1,268 @@ +#include "ObjReader.h" +#include "Utilities.h" +#include "..\Core\Core.h" +#include +#include + +using namespace std; +using namespace Oyster::FileLoaders; +using namespace Oyster; +using namespace Oyster::Math; + +ObjReader *ObjReader::LoadFile(std::string fileName, Oyster::Math::Float4x4 transform) +{ + static std::map cache; + + ObjReader *reader = NULL; + + if (cache.count(fileName)) + { + reader = cache[fileName]; + } + else + { + reader = new ObjReader(); + reader->ParseFile(fileName, transform); + + cache[fileName] = reader; + } + + return reader; +} + +ObjReader::ObjReader(void) +{ +} + + +ObjReader::~ObjReader(void) +{ +} + +void ObjReader::ParseFile(std::string fileName, Float4x4 transform) +{ + ifstream input; + input.open(fileName.c_str()); + + if(!input.is_open()) + { + return; + } + + string path; + Utility::String::extractDirPath(path,fileName,'\\'); + + std::vector VertexList; + std::vector vList; + std::vector nList; + std::vector uvList; + Vertex vertex1, vertex2, vertex3; + Float3 face[3]; + Float3 position, normal; + Float2 uv; + string s; + + while(!input.eof()) + { + getline(input,s); + int offset = (int)s.find(' '); + + if(offset!=-1) + { + string c = s.substr(0,offset); + + if(c=="v") + { + position = readVertex(offset,s); + vList.push_back(position); + } + else if(c=="vt") + { + uv = readUV(offset,s); + uvList.push_back(uv); + } + else if(c=="vn") + { + normal = readNormal(offset,s); + nList.push_back(normal); + } + else if(c=="f") + { + readFace(offset, s, face); + + vertex1.Position = vList[(int)face[0].x]; + vertex1.UV = uvList[(int)face[0].y]; + vertex1.Normal = nList[(int)face[0].z]; + + vertex2.Position = vList[(int)face[1].x]; + vertex2.UV = uvList[(int)face[1].y]; + vertex2.Normal = nList[(int)face[1].z]; + + vertex3.Position = vList[(int)face[2].x]; + vertex3.UV = uvList[(int)face[2].y]; + vertex3.Normal = nList[(int)face[2].z]; + + VertexList.push_back(vertex1); + VertexList.push_back(vertex3); + VertexList.push_back(vertex2); + } + else if(c=="mtllib") + { + this->materials = GetMaterials(path+s.substr(offset+1)); + } + } + } + + input.close(); + + this->numVertices = VertexList.size(); + this->vertices = new Vertex[this->numVertices]; + + for(size_t i=0;inumVertices;++i) + { + vertices[i].Position=Math::transformVector(Math::Float4(VertexList[i].Position,1),transform); + vertices[i].Normal=Math::transformVector(Math::Float4(VertexList[i].Normal,0),transform); + vertices[i].UV = VertexList[i].UV; + } +} + +void ObjReader::GetVertexData(Vertex **vertex,int &numVertex, std::map &Textures) +{ + numVertex=(int)this->numVertices; + (*vertex)=this->vertices; + Textures = this->materials; +} + +Float3 ObjReader::extract(std::string d) +{ + Float3 data; + int offset=(int)d.find('/'); + data.x=(float)atoi(d.substr(1,offset).c_str())-1; + + int newOffset = (int)d.find('/',offset+1); + string d2=d.substr(offset+1,newOffset-offset-1); + data.y=(float)atoi(d2.c_str())-1; + offset=newOffset; + + newOffset = (int)d.find('/',offset+1); + string d3=d.substr(offset+1,newOffset-offset-1); + data.z=(float)atoi(d3.c_str())-1; + + return data; +} + +Float3 ObjReader::readVertex(int offset,string s) +{ + int newOffset = (int)s.find(' ',offset+1); + Float3 vertex; + string d = s.substr(offset,newOffset-offset); + vertex.x = (float)atof(d.c_str()); + offset=newOffset; + + newOffset = (int)s.find(' ',offset+1); + vertex.y = (float)atof(s.substr(offset,newOffset-offset).c_str()); + offset=newOffset; + + newOffset = (int)s.find(' ',offset+1); + vertex.z = (float)-atof(s.substr(offset,newOffset-offset).c_str()); + + return vertex; +} + +Float2 ObjReader::readUV(int offset,string s) +{ + int newOffset = (int)s.find(' ',offset+1); + Float2 uv; + string d = s.substr(offset,newOffset-offset); + uv.x =(float)atof(d.c_str()); + offset=newOffset; + + newOffset = (int)s.find(' ',offset+1); + d = s.substr(offset,newOffset-offset); + uv.y =1- (float)atof(d.c_str()); + offset=newOffset; + + return uv; +} + +Float3 ObjReader::readNormal(int offset,string s) +{ + int newOffset = (int)s.find(' ',offset+1); + Float3 vertex; + string d = s.substr(offset,newOffset-offset); + vertex.x = (float)atof(d.c_str()); + offset=newOffset; + + newOffset = (int)s.find(' ',offset+1); + vertex.y = (float)atof(s.substr(offset,newOffset-offset).c_str()); + offset=newOffset; + + newOffset = (int)s.find(' ',offset+1); + vertex.z = (float)-atof(s.substr(offset,newOffset-offset).c_str()); + + return vertex; +} + +void ObjReader::readFace(int offset,string s, Oyster::Math::Float3 face[3]) +{ + int newOffset = (int)s.find(' ',offset+1); + string point1 = s.substr(offset,newOffset-offset); + + offset = newOffset; + newOffset = (int)s.find(' ',offset+1); + string point2 = s.substr(offset,newOffset-offset); + + offset = newOffset; + newOffset = (int)s.find(' ',offset+1); + string point3 = s.substr(offset,newOffset-offset); + + face[0] = extract(point1); + face[1] = extract(point2); + face[2] = extract(point3); +} + +std::map ObjReader::GetMaterials(std::string fileName) +{ + ifstream input; + input.open(fileName.c_str()); + + std::map materials; + ID3D11ShaderResourceView *srv; + string texture; + string s; + string path; + Utility::String::extractDirPath(path,fileName,'\\'); + if(!input.is_open()) + return materials; + + while(!input.eof()) + { + getline(input,s); + int offset = (int)s.find(' '); + if(offset!=-1) + { + string c = s.substr(0,offset); + if(c=="map_Kd") + { + texture = path+s.substr(offset+1); + D3DX11CreateShaderResourceViewFromFile(Oyster::Core::Device,texture.c_str(), NULL, NULL, &srv, NULL); + materials["Diffuse"] = srv; + } + if(c=="map_G") + { + texture = path+s.substr(offset+1); + D3DX11CreateShaderResourceViewFromFile(Oyster::Core::Device,texture.c_str(), NULL, NULL, &srv, NULL); + materials["Glow"] = srv; + } + if(c=="map_Ks") + { + texture = path+s.substr(offset+1); + D3DX11CreateShaderResourceViewFromFile(Oyster::Core::Device,texture.c_str(), NULL, NULL, &srv, NULL); + materials["Specular"] = srv; + } + } + } + input.close(); + + return materials; +} diff --git a/Engine/FileLoader/ObjReader.h b/Engine/FileLoader/ObjReader.h new file mode 100644 index 00000000..a846181e --- /dev/null +++ b/Engine/FileLoader/ObjReader.h @@ -0,0 +1,42 @@ +#pragma once +#include "..\Core\CoreIncludes.h" +#include "..\Math\OysterMath.h" + +namespace Oyster +{ + namespace FileLoaders + { + class ObjReader + { + public: + struct Vertex + { + Oyster::Math::Float3 Position; + Oyster::Math::Float3 Normal; + Oyster::Math::Float2 UV; + }; + + static ObjReader *LoadFile(std::string fileName, Oyster::Math::Float4x4 transform = Oyster::Math::Float4x4::identity); + + ObjReader(void); + ~ObjReader(void); + + void GetVertexData(Vertex **vertex,int &numVertex, std::map &textures); + + private: + Vertex *vertices; + size_t numVertices; + std::map materials; + + void ParseFile(std::string fileName, Oyster::Math::Float4x4 transform = Oyster::Math::Float4x4::identity); + + Oyster::Math::Float3 extract(std::string d); + Oyster::Math::Float3 readVertex(int offset,std::string s); + Oyster::Math::Float2 readUV(int offset,std::string s); + Oyster::Math::Float3 readNormal(int offset,std::string s); + void readFace(int offset,std::string s, Oyster::Math::Float3 face[3]); + + std::map GetMaterials(std::string fileName); + }; + } +} \ No newline at end of file diff --git a/Engine/Game/CollisionHandler.h b/Engine/Game/CollisionHandler.h new file mode 100644 index 00000000..06544904 --- /dev/null +++ b/Engine/Game/CollisionHandler.h @@ -0,0 +1,356 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef OYSTER_COLLISIONHANDLER_H +#define OYSTER_COLLISIONHANDLER_H + +#include "OysterMath.h" +#include "Sphere.h" + +using namespace Oyster::Math; +using namespace Oyster::Collision; + +namespace Oyster { namespace Game +{ +// HEAD ///////////////////////////////////////////////////////////// + + template + class CollisionHandler + { + public: + class Reference + { + friend class CollisionHandler; + public: + static const Reference invalid; + + Reference( const Reference &ref ); + ~Reference( ); + + bool operator == ( const Reference &ref ) const; + bool operator != ( const Reference &ref ) const; + + Float getBoundaryReach( ) const; + const Float3 & getPosition( ) const; +// const Float & getScaling( ) const; + const unsigned int & getChannel( ) const; + CollisionHandler * getHandler( ) const; + + void setBoundaryReach( const Float &radius ); + void setPosition( const Float3 &position ); +// void setScale( const Float &scale ); + + void moveToLimbo( ); + void leaveLimbo( ); + + bool isActive( ) const; + bool isInLimbo( ) const; + + private: + CollisionHandler *handler; + unsigned int ref; + + Reference( CollisionHandler *handler = NULL, unsigned int ref = 0 ); + }; + static const typename Reference outOfSlots; + + class VisitingInstance + { + public: + virtual ~VisitingInstance( ) {}; + virtual void action( Entity *hitEntity ) = 0; + }; + + typedef void (*VisitingAction)( Entity *visitor, Entity *hitEntity ); + + CollisionHandler( ); + virtual ~CollisionHandler( ); + + void emptyAndReInit( unsigned int maxNumEntities, unsigned int numChannels ); + void update( ); + + Reference addEntity( unsigned int channel, Entity *entity, const ::Oyster::Collision::Sphere &collisionBubble, const Float &scale = 1.0f ); + void visit( unsigned int *channels, unsigned int numChannels, const ::Oyster::Collision::ICollideable *sampler, VisitingInstance *visitor ); + void visit( unsigned int *channels, unsigned int numChannels, const ::Oyster::Collision::ICollideable *sampler, Entity *visitor, VisitingAction action ); + bool collidesWithSomething( unsigned int *channels, unsigned int numChannels, const ::Oyster::Collision::ICollideable *sampler ); + + private: + enum State { Updated, Changed, Limbo, Vacant }; + struct Data { Entity *entity; unsigned int channel, numHooks; Float scale; State state; } *data; + ::Oyster::Collision::Sphere *presence; + unsigned int maxNumEntities, numEntities; + + // TODO: Optimize by implementing a BSP oct tree here below (A) + + struct Channel { Channel(); unsigned int *content, num; } *channel; + unsigned int numChannels; + + bool simpleCollisionConfirmation( const typename Entity &entity, const ::Oyster::Collision::ICollideable *sampler ); + }; + +// BODY ///////////////////////////////////////////////////////////// + template + const typename CollisionHandler::Reference CollisionHandler::outOfSlots = CollisionHandler::Reference(); + + template + CollisionHandler::CollisionHandler( ) : data(NULL), presence(NULL), maxNumEntities(0), numEntities(0), channel(NULL), numChannels(0) {} + + template + CollisionHandler::~CollisionHandler( ) + { + if( this->data ) delete [] this->data; + if( this->presence ) delete [] this->presence; + + // TODO: Optimize by implementing a BSP oct tree here below (B) + if( this->channel ) + { + for( unsigned int i = 0; i < this->numChannels; ++i ) if( this->channel[i].content ) + delete [] this->channel[i].content; + delete [] this->channel; + } + } + + template + void CollisionHandler::emptyAndReInit( unsigned int maxNumEntities, unsigned int numChannels ) + { + if( this->data ) delete [] this->data; + if( this->presence ) delete [] this->presence; + + this->maxNumEntities = maxNumEntities; + this->numEntities = 0; + if( maxNumEntities > 0 ) + { + this->data = new CollisionHandler::Data[maxNumEntities]; + this->presence = new Sphere[maxNumEntities]; + } + else + { + this->data = NULL; + this->presence = NULL; + } + + // TODO: Optimize by implementing a BSP oct tree here below (C) + if( this->channel ) + { + for( unsigned int i = 0; i < this->numChannels; ++i ) if( this->channel[i].content ) + delete [] this->channel[i].content; + delete [] this->channel; + } + this->numChannels = numChannels; + this->channel = numChannels > 0 ? new CollisionHandler::Channel[numChannels] : NULL; + } + + template + void CollisionHandler::update( ) + { + // TODO: Optimize by implementing a BSP oct tree here below (D) + for( unsigned int i = 0; i < this->numEntities; ++i ) if( this->data[i].state == CollisionHandler::Changed ) + this->data[i].state = CollisionHandler::Updated; + } + + template + typename CollisionHandler::Reference CollisionHandler::addEntity( unsigned int channel, typename Entity *entity, const ::Oyster::Collision::Sphere &collisionBubble, const Float &scale ) + { + if( this->numEntities < this->maxNumEntities ) + { + this->data[this->numEntities].entity = entity; + this->data[this->numEntities].channel = channel; + this->data[this->numEntities].numHooks = 0; + this->data[this->numEntities].scale = scale; + this->data[this->numEntities].state = CollisionHandler::Updated; + this->presence[this->numEntities] = collisionBubble; + + // TODO: Optimize by implementing a BSP oct tree here below (E) + + if( this->channel[channel].content == NULL ) + { + this->channel[channel].content = new unsigned int[this->maxNumEntities]; + this->channel[channel].num = 0; + } + + this->channel[channel].content[this->channel[channel].num] = this->numEntities; + ++this->channel[channel].num; + + ////// + return CollisionHandler::Reference( this, this->numEntities++ ); + } + else return CollisionHandler::outOfSlots; + } + + template + void CollisionHandler::visit( unsigned int *_channel, unsigned int _numChannels, const ::Oyster::Collision::ICollideable *sampler, typename CollisionHandler::VisitingInstance *visitor ) + { + // TODO: Optimize by implementing a BSP oct tree here below (F1) + for( unsigned int ch = 0; ch < _numChannels; ++ch ) + for( unsigned int i = 0; i < this->channel[_channel[ch]].num; ++i ) + if( this->data[this->channel[ch].content[i]].state != CollisionHandler::Limbo && this->data[this->channel[ch].content[i]].state != CollisionHandler::Vacant ) + if( sampler->Intersects( &this->presence[this->channel[ch].content[i]] ) ) + visitor->action( this->data[this->channel[ch].content[i]].entity ); + } + + template + void CollisionHandler::visit( unsigned int *_channel, unsigned int _numChannels, const ::Oyster::Collision::ICollideable *sampler, typename Entity *visitor, typename CollisionHandler::VisitingAction action ) + { + // TODO: Optimize by implementing a BSP oct tree here below (F2) + for( unsigned int ch = 0; ch < _numChannels; ++ch ) + for( unsigned int i = 0; i < this->channel[_channel[ch]].num; ++i ) + if( this->data[this->channel[ch].content[i]].state != CollisionHandler::Limbo && this->data[this->channel[ch].content[i]].state != CollisionHandler::Vacant ) + if( sampler->Intersects( &this->presence[this->channel[ch].content[i]] ) ) + action( visitor, this->data[this->channel[ch].content[i]].entity ); + } + + template + bool CollisionHandler::collidesWithSomething( unsigned int *_channel, unsigned int _numChannels, const ::Oyster::Collision::ICollideable *sampler ) + { + // TODO: Optimize by implementing a BSP oct tree here below (F3) + for( unsigned int ch = 0; ch < _numChannels; ++ch ) + for( unsigned int i = 0; i < this->channel[_channel[ch]].num; ++i ) + if( this->data[this->channel[ch].content[i]].state != CollisionHandler::Limbo && this->data[this->channel[ch].content[i]].state != CollisionHandler::Vacant ) + if( sampler->Intersects( &this->presence[this->channel[ch].content[i]] ) ) + if( this->simpleCollisionConfirmation(*this->data[this->channel[ch].content[i]].entity, sampler) ) + return true; + return false; + } + + template + bool CollisionHandler::simpleCollisionConfirmation( const typename Entity &entity, const ::Oyster::Collision::ICollideable *sampler ) + { return true; } + + // CollisionHandler::Channel //////////////////////////////////// + template + CollisionHandler::Channel::Channel( ) : content(NULL), num(0) {} + + // CollisionHandler::Reference //////////////////////////// + + template const typename CollisionHandler::Reference CollisionHandler::Reference::invalid = CollisionHandler::Reference(); + + template + CollisionHandler::Reference::Reference( CollisionHandler *_handler, unsigned int _ref ) + : handler(_handler), ref(_ref) + { /* TODO : implement a slot allocation system */ + if( this->handler ) + { + ++this->handler->data[this->ref].numHooks; + if( this->handler->data[this->ref].state == CollisionHandler::Vacant ) + this->handler->data[this->ref].state = CollisionHandler::Limbo; + } + } + + template + CollisionHandler::Reference::Reference( const Reference &ref ) + : handler(ref.handler), ref(ref.ref) + { /* TODO : implement a slot allocation system */ + if( this->handler ) + { + ++this->handler->data[this->ref].numHooks; + if( this->handler->data[this->ref].state == CollisionHandler::Vacant ) + this->handler->data[this->ref].state = CollisionHandler::Limbo; + } + } + + template + CollisionHandler::Reference::~Reference( ) + { /* TODO : implement a slot allocation system */ + if( this->handler ) + { + if( this->handler->data[this->ref].numHooks > 0 ) + if( --this->handler->data[this->ref].numHooks == 0 ) + this->handler->data[this->ref].state = CollisionHandler::Vacant; + } + } + + template + bool CollisionHandler::Reference::operator == ( const typename CollisionHandler::Reference &ref ) const + { + if( this->handler != ref.handler ) return false; + if( this->ref != ref.ref ) return false; + return true; + } + + template + bool CollisionHandler::Reference::operator != ( const typename CollisionHandler::Reference &ref ) const + { + if( this->handler != ref.handler ) return true; + if( this->ref != ref.ref ) return true; + return false; + } + + template + Float CollisionHandler::Reference::getBoundaryReach( ) const + { return this->handler->presence[this->ref].radius; }// / this->handler->data[this->ref].scale; } + + template + const Float3 & CollisionHandler::Reference::getPosition( ) const + { return this->handler->presence[this->ref].center; } + +// template +// const Float & CollisionHandler::Reference::getScaling( ) const +// { return this->handler->data[this->ref].scale; } + + template + const unsigned int & CollisionHandler::Reference::getChannel( ) const + { return this->handler->data[this->ref].channel; } + + template + CollisionHandler * CollisionHandler::Reference::getHandler( ) const + { return this->handler; } + + template + void CollisionHandler::Reference::setBoundaryReach( const Float &radius ) + { + this->handler->presence[this->ref].radius = radius; // * this->handler->data[this->ref].scale; + if( this->handler->data[this->ref].state != CollisionHandler::Limbo ) + this->handler->data[this->ref].state = CollisionHandler::Changed; // TODO : implement a queue system + } + + template + void CollisionHandler::Reference::setPosition( const Float3 &position ) + { + this->handler->presence[this->ref].center = position; + if( this->handler->data[this->ref].state != CollisionHandler::Limbo ) + this->handler->data[this->ref].state = CollisionHandler::Changed; // TODO : implement a queue system + } + +// template +// void CollisionHandler::Reference::setScale( const Float &scale ) +// { +// this->handler->presence[this->ref].radius *= scale / this->handler->data[this->ref].scale; +// this->handler->data[this->ref].scale = scale; +// +// if( this->handler->data[this->ref].state != CollisionHandler::Limbo ) +// this->handler->data[this->ref].state = CollisionHandler::Changed; // TODO : implement a queue system +// } + + template + void CollisionHandler::Reference::moveToLimbo( ) + { /* TODO : implement a limbo system */ + this->handler->data[this->ref].state = CollisionHandler::Limbo; + } + + template + void CollisionHandler::Reference::leaveLimbo( ) + { /* TODO : implement a limbo system */ + this->handler->data[this->ref].state = CollisionHandler::Changed; + } + + template + bool CollisionHandler::Reference::isActive( ) const + { + switch( this->handler->data[this->ref].state ) + { + case Updated: + case Changed: + return true; + default: + return false; + } + } + + template + bool CollisionHandler::Reference::isInLimbo( ) const + { return ( this->handler->data[this->ref].state == Limbo ); } +} } + +#endif \ No newline at end of file diff --git a/Engine/Game/GameObject.cpp b/Engine/Game/GameObject.cpp new file mode 100644 index 00000000..b2f27c87 --- /dev/null +++ b/Engine/Game/GameObject.cpp @@ -0,0 +1 @@ +#include "GameObject.h" \ No newline at end of file diff --git a/Engine/Game/GameObject.h b/Engine/Game/GameObject.h new file mode 100644 index 00000000..949f9398 --- /dev/null +++ b/Engine/Game/GameObject.h @@ -0,0 +1,22 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +// to be removed +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef OYSTER_GAME_GAMEOBJECT_H +#define OYSTER_GAME_GAMEOBJECT_H + +#include "OysterMath.h" + +namespace Oyster { namespace Game +{ + class GameObject + { + public: + + private: + }; +} } + +#endif \ No newline at end of file diff --git a/Engine/Game/MoveAble.cpp b/Engine/Game/MoveAble.cpp new file mode 100644 index 00000000..d1d09fec --- /dev/null +++ b/Engine/Game/MoveAble.cpp @@ -0,0 +1,119 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#include "MoveAble.h" + +using namespace ::Oyster::Game; +using namespace ::Oyster::Math; +using namespace ::Oyster::Collision; + +namespace PrivateStatic +{ + Float timeSlice = 1.0f; +} + +void MoveAble::setDiscreteTimeSlice( const Float &seconds ) +{ PrivateStatic::timeSlice = seconds; } + +const Float & MoveAble::getDiscreteTimeSlice( ) +{ return PrivateStatic::timeSlice; } + +MoveAble::MoveAble( ) : body(Float4x4::identity, Float3(1.0f)), rotationPivot(Float3::null), speed(Float3::null), rotationalSpeed(Float3::null), acceleration(Float3::null), rotationalAcceleration(Float3::null) +{ + this->speed = Float3::null; +} + +MoveAble::MoveAble( const MoveAble &obj ) : body(obj.body), rotationPivot(obj.rotationPivot), speed(obj.speed), rotationalSpeed(obj.rotationalSpeed), acceleration(obj.acceleration), rotationalAcceleration(obj.rotationalAcceleration) +{ + this->speed = obj.speed; +} + +MoveAble::MoveAble( const Float4x4 &orientation, const Float3 &_rotationPivot ) : body(orientation, Float3(1.0f)), rotationPivot(_rotationPivot), speed(Float3::null), rotationalSpeed(Float3::null), acceleration(Float3::null), rotationalAcceleration(Float3::null) +{ + this->speed = Float3::null; +} + +MoveAble::MoveAble( const Box &_body, const Float3 &_rotationPivot ) : body(_body), rotationPivot(_rotationPivot), speed(Float3::null), rotationalSpeed(Float3::null), acceleration(Float3::null), rotationalAcceleration(Float3::null) +{ + this->speed = Float3::null; +} + +MoveAble::~MoveAble( ) { /* Nothing needed here */ } + +MoveAble & MoveAble::operator = ( const MoveAble &obj ) +{ + this->body = obj.body; + this->rotationPivot = obj.rotationPivot; + this->speed = obj.speed; + this->rotationalSpeed = obj.rotationalSpeed; + this->acceleration = obj.acceleration; + this->rotationalAcceleration = obj.rotationalAcceleration; + return *this; +} + +void MoveAble::accelerate( const Float3 &deltaSpeed, const Float3 &lever ) +{ + this->acceleration += vectorProjection( deltaSpeed, lever ); + this->rotationalAcceleration += deltaAngularAxis( deltaSpeed, lever ); +} + +void MoveAble::accelerate( const Float3 &deltaSpeed ) +{ this->acceleration += deltaSpeed; } + +void MoveAble::accelerateTurn( const Float3 &deltaAngularSpeed ) +{ this->rotationalAcceleration += deltaAngularSpeed; } + +void MoveAble::stop( ) +{ this->speed = this->rotationalSpeed = Float3::null; } + +void MoveAble::stopRotation( ) +{ this->rotationalSpeed = Float3::null; } + +void MoveAble::stopMovement( ) +{ this->speed = Float3::null; } + +void MoveAble::setSize( const Float3 &size ) +{ this->body.boundingOffset = size * 0.5f; } + +Float3 MoveAble::getSize( ) const +{ return this->body.boundingOffset * 2.0f; } + +void MoveAble::setOrientation( const Float4x4 & orientation ) +{ +// if( (this->body.orientation.v[3].xyz - orientation.v[3].xyz).length() >= 500.0f ) +// { // BUG HUNT illegal Teleportation trap +// const char * debug = "Illegal Teleportation Occured?"; +// } + + this->body.orientation = orientation; +} + +const Float4x4 & MoveAble::getOrientation( ) const +{ + return this->body.orientation; +} + +Float3 MoveAble::getMovement( const Float3 &offset ) const +{ return this->speed + particleRotationMovement( this->rotationalSpeed, offset ); } + +const Float3 & MoveAble::getMovement( ) const +{ return this->speed; } + +const Float3 & MoveAble::getRotation( ) const +{ return this->rotationalSpeed; } + +void MoveAble::update( ) +{ + this->speed += this->acceleration * PrivateStatic::timeSlice; + this->rotationalSpeed += this->rotationalAcceleration * PrivateStatic::timeSlice; + this->acceleration = this->rotationalAcceleration = Float3::null; // clearing acceleration every discrete timeslice (update) + + Float4x4 m; + rigidBodyMatrix( m, this->rotationalSpeed * PrivateStatic::timeSlice, + ( this->speed * PrivateStatic::timeSlice ) + this->body.orientation.v[3].xyz, + this->rotationPivot ); + this->body.orientation.v[3].xyz = Float3::null; + + transformMatrix( this->body.orientation, this->body.orientation, m ); +} \ No newline at end of file diff --git a/Engine/Game/MoveAble.h b/Engine/Game/MoveAble.h new file mode 100644 index 00000000..e74054d2 --- /dev/null +++ b/Engine/Game/MoveAble.h @@ -0,0 +1,57 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef GAME_MOVEABLE_H +#define GAME_MOVEABLE_H + +#include "OysterMath.h" +#include "OysterCollision.h" + +namespace Oyster { namespace Game +{ + class MoveAble + { + public: + static void setDiscreteTimeSlice( const ::Oyster::Math::Float &seconds ); + static const ::Oyster::Math::Float & getDiscreteTimeSlice( ); + + MoveAble( ); + MoveAble( const MoveAble &obj ); + MoveAble( const ::Oyster::Math::Float4x4 &orientation, const ::Oyster::Math::Float3 &rotationPivot = ::Oyster::Math::Float3::null ); + MoveAble( const ::Oyster::Collision::Box &body, const ::Oyster::Math::Float3 &rotationPivot = ::Oyster::Math::Float3::null ); + virtual ~MoveAble( ); + + virtual MoveAble & operator = ( const MoveAble &obj ); + + void accelerate( const ::Oyster::Math::Float3 &deltaSpeed, const ::Oyster::Math::Float3 &lever ); + void accelerate( const ::Oyster::Math::Float3 &deltaSpeed ); + void accelerateTurn( const ::Oyster::Math::Float3 &deltaRotationalSpeed ); + + void stop( ); + void stopRotation( ); + void stopMovement( ); + + void setSize( const ::Oyster::Math::Float3 &size ); + ::Oyster::Math::Float3 getSize( ) const; + + virtual void setOrientation( const ::Oyster::Math::Float4x4 & orientation ); + const ::Oyster::Math::Float4x4 & getOrientation( ) const; + + ::Oyster::Math::Float3 getMovement( const ::Oyster::Math::Float3 &offset ) const; + const ::Oyster::Math::Float3 & getMovement( ) const; + const ::Oyster::Math::Float3 & getRotation( ) const; + + virtual void update( ); + + protected: + ::Oyster::Collision::Box body; + ::Oyster::Math::Float3 rotationPivot; + + ::Oyster::Math::Float3 speed, rotationalSpeed; + ::Oyster::Math::Float3 acceleration, rotationalAcceleration; + }; +} } + +#endif \ No newline at end of file diff --git a/Engine/Game/OysterGame.h b/Engine/Game/OysterGame.h new file mode 100644 index 00000000..5615f3c9 --- /dev/null +++ b/Engine/Game/OysterGame.h @@ -0,0 +1,3 @@ +#include "MoveAble.h" +#include "CollisionHandler.h" +#include "SateliteCamera.h" \ No newline at end of file diff --git a/Engine/Game/SateliteCamera.cpp b/Engine/Game/SateliteCamera.cpp new file mode 100644 index 00000000..3cf3a138 --- /dev/null +++ b/Engine/Game/SateliteCamera.cpp @@ -0,0 +1,307 @@ +#include "SateliteCamera.h" + +using namespace Oyster::Game; +using namespace Oyster::Math; +using namespace Oyster::Collision; + +namespace PrivateStatic +{ + inline void towardsZero( Float &target, const Float &maxStep ) + { + if( target > maxStep ) target -= maxStep; + else if( target < -maxStep ) target += maxStep; + else target = 0.0f; + } +} + +SateliteCamera::SateliteCamera( const Float4x4 *rigidBody, const Float3 &offsetPos, const Float3 &upVector, const Float4x4 &_projection ) + : offsetRadian(Float3::null), offsetPan(Float3::null), offsetDistance(0.0f), focus(rigidBody), + defaultRelation(Float4x4::identity), projection(_projection), view(), viewProjection(), + sampler(), viewIsOutOfDate(true), viewProjectionIsOutOfDate(true), samplerIsOutOfDate(true) +{ + this->defaultRelation.v[3].xyz = offsetPos; + this->defaultRelation.v[2].xyz = offsetPos.getNormalized() * -1.0f; + this->defaultRelation.v[1].xyz = (upVector - ( this->defaultRelation.v[2].xyz * this->defaultRelation.v[2].xyz.dot(upVector) )).getNormalized(); + this->defaultRelation.v[0].xyz = this->defaultRelation.v[1].xyz.cross( this->defaultRelation.v[2].xyz ); +} + +void SateliteCamera::setFocus( const Float4x4 *rigidBody, const Float3 &offsetPos, const Float3 &upVector ) +{ + this->defaultRelation.v[3].xyz = offsetPos; + this->defaultRelation.v[2].xyz = offsetPos.getNormalized(); + this->defaultRelation.v[1].xyz = (upVector - ( this->defaultRelation.v[2].xyz * this->defaultRelation.v[2].xyz.dot(upVector) )).getNormalized(); + this->defaultRelation.v[0].xyz = this->defaultRelation.v[1].xyz.cross( this->defaultRelation.v[2].xyz ); + this->defaultRelation.v[2].xyz *= -1.0f; + + this->focus = rigidBody; + this->viewIsOutOfDate = true; + this->viewProjectionIsOutOfDate = true; + this->samplerIsOutOfDate = true; +} + +void SateliteCamera::setProjection( const Float4x4 &transform ) +{ + this->projection = transform; + this->viewProjectionIsOutOfDate = true; + this->samplerIsOutOfDate = true; +} + +const ::Oyster::Math::Float4x4 & SateliteCamera::getView( ) const +{ +// if( this->viewIsOutOfDate ) + { + Float4x4 world = this->defaultRelation; + + if( this->offsetDistance != 0.0f ) + world.v[3].xyz += world.v[2].xyz * this->offsetDistance; + + if( this->offsetRadian != Float3::null || this->offsetPan != Float3::null ) + { + Float4x4 m; + rigidBodyMatrix( m, this->offsetRadian, offsetPan ); + transformMatrix( world, world, m ); + } + + transformMatrix( world, world, *this->focus ); + inverseRigidBodyMatrix( this->view, world ); + + this->viewIsOutOfDate = false; + } + return this->view; +} + +const Float4x4 & SateliteCamera::getProjection( ) const +{ return this->projection; } + +const Float4x4 & SateliteCamera::getViewProjection( ) const +{ +// if( this->viewProjectionIsOutOfDate ) + { + viewProjectionMatrix( this->viewProjection, this->getView(), this->projection ); + this->viewProjectionIsOutOfDate = false; + } + return this->viewProjection; +} + +const Frustrum & SateliteCamera::getSampler( ) const +{ + if( this->samplerIsOutOfDate ) + { + this->sampler = this->getViewProjection(); + this->samplerIsOutOfDate = false; + } + return this->sampler; +} + +void SateliteCamera::revolveLeft( const Float &deltaRadian ) +{ + this->offsetRadian.y += deltaRadian; + this->viewIsOutOfDate = true; + this->viewProjectionIsOutOfDate = true; + this->samplerIsOutOfDate = true; +} + +void SateliteCamera::revolveRight( const Float &deltaRadian ) +{ + this->offsetRadian.y -= deltaRadian; + this->viewIsOutOfDate = true; + this->viewProjectionIsOutOfDate = true; + this->samplerIsOutOfDate = true; +} + +void SateliteCamera::revolveUp( const Float &deltaRadian ) +{ + this->offsetRadian.x += deltaRadian; + this->viewIsOutOfDate = true; + this->viewProjectionIsOutOfDate = true; + this->samplerIsOutOfDate = true; +} + +void SateliteCamera::revolveDown( const Float &deltaRadian ) +{ + this->offsetRadian.x -= deltaRadian; + this->viewIsOutOfDate = true; + this->viewProjectionIsOutOfDate = true; + this->samplerIsOutOfDate = true; +} + +void SateliteCamera::revolveRollLeft( const Float &deltaRadian ) +{ + this->offsetRadian.z += deltaRadian; + this->viewIsOutOfDate = true; + this->viewProjectionIsOutOfDate = true; + this->samplerIsOutOfDate = true; +} + +void SateliteCamera::revolveRollRight( const Float &deltaRadian ) +{ + this->offsetRadian.z -= deltaRadian; + this->viewIsOutOfDate = true; + this->viewProjectionIsOutOfDate = true; + this->samplerIsOutOfDate = true; +} + +void SateliteCamera::setHorizontalRevolution( const Float &radian ) +{ + this->offsetRadian.y = radian; + this->viewIsOutOfDate = true; + this->viewProjectionIsOutOfDate = true; + this->samplerIsOutOfDate = true; +} + +void SateliteCamera::setVerticalRevolution( const Float &radian ) +{ + this->offsetRadian.x = radian; + this->viewIsOutOfDate = true; + this->viewProjectionIsOutOfDate = true; + this->samplerIsOutOfDate = true; +} + +void SateliteCamera::setRollRevolution( const Float &radian ) +{ + this->offsetRadian.z = radian; + this->viewIsOutOfDate = true; + this->viewProjectionIsOutOfDate = true; + this->samplerIsOutOfDate = true; +} + +void SateliteCamera::moveIn( const Float &deltaLength ) +{ + this->offsetDistance -= deltaLength; + this->viewIsOutOfDate = true; + this->viewProjectionIsOutOfDate = true; + this->samplerIsOutOfDate = true; +} + +void SateliteCamera::moveOut( const Float &deltaLength ) +{ + this->offsetDistance += deltaLength; + this->viewIsOutOfDate = true; + this->viewProjectionIsOutOfDate = true; + this->samplerIsOutOfDate = true; +} + +void SateliteCamera::panForward( const Float &deltaLength ) +{ + this->offsetPan.z += deltaLength; + this->viewIsOutOfDate = true; + this->viewProjectionIsOutOfDate = true; + this->samplerIsOutOfDate = true; +} + +void SateliteCamera::panBackward( const Float &deltaLength ) +{ + this->offsetPan.z -= deltaLength; + this->viewIsOutOfDate = true; + this->viewProjectionIsOutOfDate = true; + this->samplerIsOutOfDate = true; +} + +void SateliteCamera::panLeft( const Float &deltaLength ) +{ + this->offsetPan.x -= deltaLength; + this->viewIsOutOfDate = true; + this->viewProjectionIsOutOfDate = true; + this->samplerIsOutOfDate = true; +} + +void SateliteCamera::panRight( const Float &deltaLength ) +{ + this->offsetPan.x += deltaLength; + this->viewIsOutOfDate = true; + this->viewProjectionIsOutOfDate = true; + this->samplerIsOutOfDate = true; +} + +void SateliteCamera::panUp( const Float &deltaLength ) +{ + this->offsetPan.y += deltaLength; + this->viewIsOutOfDate = true; + this->viewProjectionIsOutOfDate = true; + this->samplerIsOutOfDate = true; +} + +void SateliteCamera::panDown( const Float &deltaLength ) +{ + this->offsetPan.y -= deltaLength; + this->viewIsOutOfDate = true; + this->viewProjectionIsOutOfDate = true; + this->samplerIsOutOfDate = true; +} + +void SateliteCamera::stabiliseRoll( const Float &deltaRadian ) +{ + if( this->offsetRadian.z != 0.0f ) + { + PrivateStatic::towardsZero( this->offsetRadian.z, deltaRadian ); + this->viewIsOutOfDate = true; + this->viewProjectionIsOutOfDate = true; + this->samplerIsOutOfDate = true; + } +} + +void SateliteCamera::stabiliseHorizontally( const Float &deltaRadian ) +{ + if( this->offsetRadian.y != 0.0f ) + { + PrivateStatic::towardsZero( this->offsetRadian.y, deltaRadian ); + this->viewIsOutOfDate = true; + this->viewProjectionIsOutOfDate = true; + this->samplerIsOutOfDate = true; + } +} + +void SateliteCamera::stabiliseVertically( const Float &deltaRadian ) +{ + if( this->offsetRadian.x != 0.0f ) + { + PrivateStatic::towardsZero( this->offsetRadian.x, deltaRadian ); + this->viewIsOutOfDate = true; + this->viewProjectionIsOutOfDate = true; + this->samplerIsOutOfDate = true; + } +} + +void SateliteCamera::stabiliseDistance( const Float &deltaLength ) +{ + if( this->offsetDistance != 0.0f ) + { + PrivateStatic::towardsZero( this->offsetDistance, deltaLength ); + this->viewIsOutOfDate = true; + this->viewProjectionIsOutOfDate = true; + this->samplerIsOutOfDate = true; + } +} + +void SateliteCamera::stabilisePanX( const Float &deltaLength ) +{ + if( this->offsetPan.x != 0.0f ) + { + PrivateStatic::towardsZero( this->offsetPan.x, deltaLength ); + this->viewIsOutOfDate = true; + this->viewProjectionIsOutOfDate = true; + this->samplerIsOutOfDate = true; + } +} + +void SateliteCamera::stabilisePanY( const Float &deltaLength ) +{ + if( this->offsetPan.y != 0.0f ) + { + PrivateStatic::towardsZero( this->offsetPan.y, deltaLength ); + this->viewIsOutOfDate = true; + this->viewProjectionIsOutOfDate = true; + this->samplerIsOutOfDate = true; + } +} + +void SateliteCamera::stabilisePanZ( const Float &deltaLength ) +{ + if( this->offsetPan.z != 0.0f ) + { + PrivateStatic::towardsZero( this->offsetPan.z, deltaLength ); + this->viewIsOutOfDate = true; + this->viewProjectionIsOutOfDate = true; + this->samplerIsOutOfDate = true; + } +} \ No newline at end of file diff --git a/Engine/Game/SateliteCamera.h b/Engine/Game/SateliteCamera.h new file mode 100644 index 00000000..e7ab70c3 --- /dev/null +++ b/Engine/Game/SateliteCamera.h @@ -0,0 +1,72 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +/* + Target use is by example tail camera, 3rd person perspective + and such. +*/ +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef OYSTER_GAME_SATELITECAMERA_H +#define OYSTER_GAME_SATELITECAMERA_H + +#include "OysterMath.h" +#include "Frustrum.h" + +namespace Oyster { namespace Game +{ + class SateliteCamera + { + public: + SateliteCamera( const ::Oyster::Math::Float4x4 *rigidBody, const ::Oyster::Math::Float3 &offsetPos, const ::Oyster::Math::Float3 &upVector, const ::Oyster::Math::Float4x4 &projection ); + + void setFocus( const ::Oyster::Math::Float4x4 *rigidBody, const ::Oyster::Math::Float3 &offsetPos, const ::Oyster::Math::Float3 &upVector ); + void setProjection( const ::Oyster::Math::Float4x4 &transform ); + + const ::Oyster::Math::Float4x4 & getView( ) const; + const ::Oyster::Math::Float4x4 & getProjection( ) const; + const ::Oyster::Math::Float4x4 & getViewProjection( ) const; + const ::Oyster::Collision::Frustrum & getSampler( ) const; + + void revolveLeft( const ::Oyster::Math::Float &deltaRadian ); + void revolveRight( const ::Oyster::Math::Float &deltaRadian ); + void revolveUp( const ::Oyster::Math::Float &deltaRadian ); + void revolveDown( const ::Oyster::Math::Float &deltaRadian ); + void revolveRollLeft( const ::Oyster::Math::Float &deltaRadian ); + void revolveRollRight( const ::Oyster::Math::Float &deltaRadian ); + void setHorizontalRevolution( const ::Oyster::Math::Float &radian ); + void setVerticalRevolution( const ::Oyster::Math::Float &radian ); + void setRollRevolution( const ::Oyster::Math::Float &radian ); + + void moveIn( const ::Oyster::Math::Float &deltaLength ); + void moveOut( const ::Oyster::Math::Float &deltaLength ); + + void panForward( const ::Oyster::Math::Float &deltaLength ); + void panBackward( const ::Oyster::Math::Float &deltaLength ); + void panLeft( const ::Oyster::Math::Float &deltaLength ); + void panRight( const ::Oyster::Math::Float &deltaLength ); + void panUp( const ::Oyster::Math::Float &deltaLength ); + void panDown( const ::Oyster::Math::Float &deltaLength ); + + void stabiliseRoll( const ::Oyster::Math::Float &deltaRadian ); + void stabiliseHorizontally( const ::Oyster::Math::Float &deltaRadian ); + void stabiliseVertically( const ::Oyster::Math::Float &deltaRadian ); + void stabiliseDistance( const ::Oyster::Math::Float &deltaLength ); + void stabilisePanX( const ::Oyster::Math::Float &deltaLength ); + void stabilisePanY( const ::Oyster::Math::Float &deltaLength ); + void stabilisePanZ( const ::Oyster::Math::Float &deltaLength ); + + protected: + mutable ::Oyster::Math::Float3 offsetRadian; + mutable ::Oyster::Math::Float3 offsetPan; + mutable ::Oyster::Math::Float offsetDistance; + private: + const ::Oyster::Math::Float4x4 *focus; + ::Oyster::Math::Float4x4 defaultRelation, projection; + mutable ::Oyster::Math::Float4x4 view, viewProjection; + mutable ::Oyster::Collision::Frustrum sampler; + mutable bool viewIsOutOfDate, viewProjectionIsOutOfDate, samplerIsOutOfDate; + }; +} } + +#endif \ No newline at end of file diff --git a/Engine/Input/InputController.cpp b/Engine/Input/InputController.cpp new file mode 100644 index 00000000..d534a073 --- /dev/null +++ b/Engine/Input/InputController.cpp @@ -0,0 +1,284 @@ +#include "InputController.h" +using namespace Oyster::Input; + +namespace +{ + bool keys[256] = {0}; + bool prevs[256]= {0}; + bool mouse[5] = {0}; + bool mPrev[5] = {0}; + int XPos,YPos,PrevX,PrevY,DeltaX,DeltaY; +} + +void Controller::KeyPressed(const WPARAM &Key) +{ + prevs[Key]=false; + keys[Key]=true; +} + +void Controller::KeyReleased(const WPARAM &Key) +{ + prevs[Key]=true; + keys[Key] = false; +} + +bool Controller::isKeyDown(const WPARAM &Key) +{ + return keys[Key]; +} + +bool Controller::isKeyPressed(const WPARAM &Key) +{ + if(keys[Key] && !prevs[Key]) + { + prevs[Key] = keys[Key]; + return true; + } + return false; +} + +bool Controller::isKeyReleased(const WPARAM &Key) +{ + if(!keys[Key] && prevs[Key]) + { + prevs[Key] = keys[Key]; + return true; + } + return false; +} + +void Controller::MouseBtnPressed(const WPARAM &btn) +{ + switch(btn) + { + case MK_LBUTTON: + mouse[0] = true; + mPrev[0] = false; + break; + case MK_RBUTTON: + mouse[1] = true; + mPrev[1] = false; + break; + case MK_MBUTTON: + mouse[2] = true; + mPrev[2] = false; + break; + case MK_XBUTTON1: + mouse[3] = true; + mPrev[3] = false; + break; + case MK_XBUTTON2: + mouse[4] = true; + mPrev[4] = false; + break; + } +} + +void Controller::MouseBtnReleased(const WPARAM &btn) +{ + switch(btn) + { + case MK_LBUTTON: + mouse[0] = false; + mPrev[0] = true; + break; + case MK_RBUTTON: + mouse[1] = false; + mPrev[1] = true; + break; + case MK_MBUTTON: + mouse[2] = false; + mPrev[2] = true; + break; + case MK_XBUTTON1: + mouse[3] = false; + mPrev[3] = true; + break; + case MK_XBUTTON2: + mouse[4] = false; + mPrev[4] = true; + break; + } +} + + +bool Controller::isMouseBtnDown(const WPARAM &Btn) +{ + switch(Btn) + { + case MK_LBUTTON: + return mouse[0]; + case MK_RBUTTON: + return mouse[1]; + case MK_MBUTTON: + return mouse[2]; + case MK_XBUTTON1: + return mouse[3]; + case MK_XBUTTON2: + return mouse[4]; + } + + return false; +} + +bool Controller::isMouseBtnPressed(const WPARAM &Btn) +{ + switch(Btn) + { + case MK_LBUTTON: + if(mouse[0] && !mPrev[0]) + { + mPrev[0] = mouse[0]; + return true; + } + return false; + case MK_RBUTTON: + if(mouse[1] && !mPrev[1]) + { + mPrev[1] = mouse[1]; + return true; + } + return false; + case MK_MBUTTON: + if(mouse[2] && !mPrev[2]) + { + mPrev[2] = mouse[2]; + return true; + } + return false; + case MK_XBUTTON1: + if(mouse[3] && !mPrev[3]) + { + mPrev[3] = mouse[3]; + return true; + } + return false; + case MK_XBUTTON2: + if(mouse[4] && !mPrev[4]) + { + mPrev[4] = mouse[4]; + return true; + } + return false; + } + + return false; +} + +bool Controller::isMouseBtnReleased(const WPARAM &Btn) +{ + switch(Btn) + { + case MK_LBUTTON: + if(!mouse[0] && mPrev[0]) + { + mPrev[0] = mouse[0]; + return true; + } + return false; + case MK_RBUTTON: + if(!mouse[1] && mPrev[1]) + { + mPrev[1] = mouse[1]; + return true; + } + return false; + case MK_MBUTTON: + if(!mouse[2] && mPrev[2]) + { + mPrev[2] = mouse[2]; + return true; + } + return false; + case MK_XBUTTON1: + if(!mouse[3] && mPrev[3]) + { + mPrev[3] = mouse[3]; + return true; + } + return false; + case MK_XBUTTON2: + if(!mouse[4] && mPrev[4]) + { + mPrev[4] = mouse[4]; + return true; + } + return false; + } + + return false; +} + +void Controller::MouseMove(int x,int y) +{ + PrevY = YPos; + PrevX = XPos; + XPos = x; + YPos = y; + DeltaY = YPos - PrevY; + DeltaX = XPos - PrevX; +} + +int Controller::GetY() +{ + return YPos; +} + +int Controller::GetX() +{ + return XPos; +} + +float Controller::GetAnalogX() +{ + float f = (float)XPos; + f /=( Window::Size.left/2); + return f; +} + +float Controller::GetAnalogY() +{ + float f = (float)YPos; + f /=( Window::Size.top/2); + return f; +} + +int Controller::GetDeltaY() +{ + return DeltaY; +} + +int Controller::GetDeltaX() +{ + return DeltaX; +} + +void Controller::ResetDeltaX() +{ + DeltaX = 0; +} + +void Controller::ResetDeltaY() +{ + DeltaY = 0; +} + +void Controller::RestrictMouse(bool restrict) +{ + Oyster::Window::CaptureMouse(restrict); +} + +//sets x=0,y=0 to be the center oc the client area +void Controller::OrigoCenter() +{ + int x = Window::Size.left/2; + int y = Window::Size.top/2; + + Window::SetMouseOffset(-x,-y); +} + +//default +void Controller::OrigoTopLeft() +{ + Oyster::Window::SetMouseOffset(0,0); +} \ No newline at end of file diff --git a/Engine/Input/InputController.h b/Engine/Input/InputController.h new file mode 100644 index 00000000..5b4292c6 --- /dev/null +++ b/Engine/Input/InputController.h @@ -0,0 +1,63 @@ +#pragma once + +#ifndef InputController_H +#define InputController_H + +#include "../Window/Window.h" +//READ http://msdn.microsoft.com/en-us/library/windows/desktop/ms648380(v=vs.85).aspx#_win32_Confining_a_Cursor + +namespace Oyster +{ + class Window; + namespace Input + { + class Controller + { + friend class ::Oyster::Window; + private: + //Keybord events from Oyster::Window + static void KeyPressed(const WPARAM &Key); + //Keybord events from Oyster::Window + static void KeyReleased(const WPARAM &Key); + + + //Mouse events from Oyster::Window + static void MouseMove(int x,int y); + //Mouse events from Oyster::Window + static void MouseBtnPressed(const WPARAM &Btn); + static void MouseBtnReleased(const WPARAM &Btn); + public: + //Polling Functions + static bool isKeyDown(const WPARAM &Key); + static bool isKeyPressed(const WPARAM &Key); + static bool isKeyReleased(const WPARAM &Key); + + static bool isMouseBtnDown(const WPARAM &Btn); + static bool isMouseBtnPressed(const WPARAM &Btn); + static bool isMouseBtnReleased(const WPARAM &Btn); + + static int GetX(); + static int GetY(); + + static float GetAnalogX(); + static float GetAnalogY(); + + static int GetDeltaX(); + static int GetDeltaY(); + + //Controll Functions + static void ResetDeltaX(); + static void ResetDeltaY(); + + //off by default + static void RestrictMouse(bool b = true); + + //sets x=0,y=0 to be the center oc the client area + static void OrigoCenter(); + + //default + static void OrigoTopLeft(); + }; + } +} +#endif \ No newline at end of file diff --git a/Engine/Math/LinearMath.h b/Engine/Math/LinearMath.h new file mode 100644 index 00000000..a9bdef25 --- /dev/null +++ b/Engine/Math/LinearMath.h @@ -0,0 +1,268 @@ +///////////////////////////////////////////////////////////////////// +// Collection of Linear Math Stuff +// © Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef LINEARMATH_H +#define LINEARMATH_H + +#include "Vector.h" +#include "Matrix.h" +#include "Quaternion.h" +#include + +namespace LinearAlgebra +{ + // x2 + template + Matrix2x2 operator * ( const Matrix2x2 &left, const Matrix2x2 &right ) + { return Matrix2x2( (left.m11 * right.m11) + (left.m21 * right.m12), (left.m11 * right.m21) + (left.m21 * right.m22), (left.m12 * right.m11) + (left.m22 * right.m12), (left.m12 * right.m21) + (left.m22 * right.m22) ); } + + template + Vector2 operator * ( const Matrix2x2 &matrix, const Vector2 &vector ) + { return Vector2( (matrix.m11 * vector.x) + (matrix.m21 * vector.y), (matrix.m12 * vector.x) + (matrix.m22 * vector.y) ); } + + template + Vector2 operator * ( const Vector2 &vector, const Matrix2x2 &left ) + { return Vector2( (vector.x * matrix.m11) + (vector.y * matrix.m12), (vector.x * matrix.m21) + (vector.y * matrix.m22) ); } + + // x3 + template + Matrix3x3 operator * ( const Matrix3x3 &left, const Matrix3x3 &right ) + { + Matrix3x3 product, leftT = left.getTranspose(); + for( int i = 0; i < 3; ++i ) for( int j = 0; j < 3; ++j ) + product.m[i][j] = leftT.v[i].dot(right.v[j]); + return product; + } + + template + Vector3 operator * ( const Matrix3x3 &matrix, const Vector3 &vector ) + { return Vector3( (matrix.m11 * vector.x) + (matrix.m21 * vector.y) + (matrix.m31 * vector.z), (matrix.m12 * vector.x) + (matrix.m22 * vector.y) + (matrix.m32 * vector.z), (matrix.m13 * vector.x) + (matrix.m23 * vector.y) + (matrix.m33 * vector.z) ); } + + template + Vector3 operator * ( const Vector3 &vector, const Matrix3x3 &left ) + { return Vector3( (vector.x * matrix.m11) + (vector.y * matrix.m12) + (vector.z * matrix.m13), (vector.x * matrix.m21) + (vector.y * matrix.m22) + (vector.z * matrix.m23), (vector.x * matrix.m31) + (vector.y * matrix.m32) + (vector.z * matrix.m33) ); } + + // x4 + template + Matrix4x4 operator * ( const Matrix4x4 &left, const Matrix4x4 &right ) + { + Matrix4x4 product, rightT = right.getTranspose(); + for( int i = 0; i < 4; ++i ) + { + product.m[i][0] = left.v[i].dot(rightT.v[0]); + product.m[i][1] = left.v[i].dot(rightT.v[1]); + product.m[i][2] = left.v[i].dot(rightT.v[2]); + product.m[i][3] = left.v[i].dot(rightT.v[3]); + } + return product; + } + + template + Vector4 operator * ( const Matrix4x4 &matrix, const Vector4 &vector ) + { return Vector4( (matrix.m11 * vector.x) + (matrix.m21 * vector.y) + (matrix.m31 * vector.z) + (matrix.m41 * vector.w), (matrix.m12 * vector.x) + (matrix.m22 * vector.y) + (matrix.m32 * vector.z) + (matrix.m42 * vector.w), (matrix.m13 * vector.x) + (matrix.m23 * vector.y) + (matrix.m33 * vector.z) + (matrix.m43 * vector.w), (matrix.m14 * vector.x) + (matrix.m24 * vector.y) + (matrix.m34 * vector.z) + (matrix.m44 * vector.w) ); } + + template // works for column weighted matrixes + Vector4 operator * ( const Vector4 &vector, const Matrix4x4 &matrix ) + { return Vector4( (vector.x * matrix.m11) + (vector.y * matrix.m12) + (vector.z * matrix.m13) + (vector.w * matrix.m14), (vector.x * matrix.m21) + (vector.y * matrix.m22) + (vector.z * matrix.m23) + (vector.w * matrix.m24), (vector.x * matrix.m31) + (vector.y * matrix.m32) + (vector.z * matrix.m33) + (vector.w * matrix.m34), (vector.x * matrix.m41) + (vector.y * matrix.m42) + (vector.z * matrix.m43) + (vector.w * matrix.m44) ); } + + namespace _2D + { + template + inline void translationMatrix( Matrix3x3 &output, const Vector2 &position ) +// { output = Matrix3x3( 1, 0, position.x, 0, 1, position.y, 0, 0, 1 ); } + { output = Matrix3x3( 1, 0, 0, 0, 1, 0, position.x, position.y, 1 ); } + + template + void rotationMatrix( Matrix2x2 &output, const ElementType &radian ) + { + ElementType s = std::sin( radian ), + c = std::cos( radian ); +// output = Matrix2x2( c, -s, s, c ); + output = Matrix2x2( c, s, -s, c ); + } + + template + void rotationMatrix( Matrix3x3 &output, const ElementType &radian ) + { + ElementType s = std::sin( radian ), + c = std::cos( radian ); +// output = Matrix3x3( c, -s, 0, s, c, 0, 0, 0, 1 ); + output = Matrix3x3( c, s, 0, -s, c, 0, 0, 0, 1 ); + } + + template + void rigidBodyMatrix( Matrix3x3 &output, const ElementType &radian, const Vector2 &position ) + { + ElementType s = std::sin( radian ), + c = std::cos( radian ); +// output = Matrix3x3( c, -s, position.x, s, c, position.y, 0, 0, 1 ); + output = Matrix3x3( c, s, 0, -s, c, 0, position.x, position.y, 1 ); + } + } + + namespace _3D + { + template + inline void translationMatrix( Matrix4x4 &output, const Vector3 &position ) +// { output = Matrix4x4( 1, 0, 0, position.x, 0, 1, 0, position.y, 0, 0, 1, position.z, 0, 0, 0, 1 ); } + { output = Matrix4x4( 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, position.x, position.y, position.z, 1 ); } + + template + void inverseRigidBody( Matrix4x4 &output, const Matrix4x4 &rigidBody ) + { + output = Matrix4x4( rigidBody.m11, rigidBody.m21, rigidBody.m31, 0, + rigidBody.m12, rigidBody.m22, rigidBody.m32, 0, + rigidBody.m13, rigidBody.m23, rigidBody.m33, 0, + -rigidBody.v[3].xyz.dot(rigidBody.v[0].xyz), + -rigidBody.v[3].xyz.dot(rigidBody.v[1].xyz), + -rigidBody.v[3].xyz.dot(rigidBody.v[2].xyz), 1 ); + } + + template + void rotationMatrix_AxisX( Matrix3x3 &output, const ElementType &radian ) + { + ElementType s = std::sin( radian ), + c = std::cos( radian ); +// output = Matrix3x3( 1, 0, 0, 0, c, -s, 0, s, c ); + output = Matrix3x3( 1, 0, 0, 0, c, s, 0, -s, c ); + } + + template + void rotationMatrix_AxisX( Matrix4x4 &output, const ElementType &radian ) + { + ElementType s = std::sin( radian ), + c = std::cos( radian ); +// output = Matrix4x4( 1, 0, 0, 0, 0, c, -s, 0, 0, s, c, 0, 0, 0, 0, 1 ); + output = Matrix4x4( 1, 0, 0, 0, 0, c, s, 0, 0, -s, c, 0, 0, 0, 0, 1 ); + } + + template + void rotationMatrix_AxisY( Matrix3x3 &output, const ElementType &radian ) + { + ElementType s = std::sin( radian ), + c = std::cos( radian ); +// output = Matrix3x3( c, 0, s, 0, 1, 0, -s, 0, c ); + output = Matrix3x3( c, 0, -s, 0, 1, 0, s, 0, c ); + } + + template + void rotationMatrix_AxisY( Matrix4x4 &output, const ElementType &radian ) + { + ElementType s = std::sin( radian ), + c = std::cos( radian ); +// output = Matrix4x4( c, 0, s, 0, 0, 1, 0, 0, -s, 0, c, 0, 0, 0, 0, 1 ); + output = Matrix4x4( c, 0, -s, 0, 0, 1, 0, 0, s, 0, c, 0, 0, 0, 0, 1 ); + } + + template + inline void rotationMatrix_AxisZ( Matrix3x3 &output, const ElementType &radian ) + { ::LinearAlgebra::_2D::rotationMatrix( output, radian ); } + + template + void rotationMatrix_AxisZ( Matrix4x4 &output, const ElementType &radian ) + { + ElementType s = std::sin( radian ), + c = std::cos( radian ); +// output = Matrix4x4( c, -s, 0, 0, s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ); + output = Matrix4x4( c, s, 0, 0, -s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ); + } + + template + void rotationMatrix( Matrix4x4 &output, const Vector3 &normalizedAxis, const ElementType &radian ) + { // TODO : Optimize + ElementType r = radian * 0.5f, + s = std::sin( r ), + c = std::cos( r ); + Quaternion q( normalizedAxis * s, c ), + qConj = q.getConjugate(); + + output.v[0] = Vector4( (q*Vector3(1,0,0)*qConj).imaginary, 0 ); + output.v[1] = Vector4( (q*Vector3(0,1,0)*qConj).imaginary, 0 ); + output.v[2] = Vector4( (q*Vector3(0,0,1)*qConj).imaginary, 0 ); + output.v[3] = Vector4( 0, 0, 0, 1 ); + } + + /* + returns a deltaAngularAxis which is a vectorProduct of the movementVector and leverVector. + angular: (1/I) * L, there I is known as the "moment of inertia", L as the "angular momentum vector". + lever: Displacement vector relative to the rotation pivot. + Recommended reading: http://en.wikipedia.org/wiki/Torque + */ + template + inline Vector3 deltaAngularAxis( const Vector3 &movement, const Vector3 &lever ) + { return movement.cross( lever ); } + + template + inline Vector3 particleRotationMovement( const Vector3 &deltaRadian, const Vector3 &lever ) + { return lever.cross(deltaRadian) /= lever.dot(lever); } + + template + inline Vector3 vectorProjection( const Vector3 &vector, const Vector3 &axis ) + { return axis * ( vector.dot(axis) / axis.dot(axis) ); } + + /* + output; is set to a rigibody matrix that revolve/rotate around centerOfMass and then translates. + sumDeltaAngularAxis: Sum of all ( (1/I) * ( L x D ) )-vectorproducts. There I is known as "moment of inertia", L as "angular momentum vector" and D the "lever vector". + sumTranslation: Sum of all the translation vectors. + centerOfMass: The point the particles is to revolve around, prior to translation. Default set to null vector aka origo. + Recommended reading: http://en.wikipedia.org/wiki/Torque + */ + template + void rigidBodyMatrix( Matrix4x4 &output, const Vector3 &sumDeltaAngularAxis, const Vector3 &sumTranslation, const Vector3 ¢erOfMass = Vector3::null ) + { + ElementType deltaRadian = sumDeltaAngularAxis.length(); + if( deltaRadian != 0 ) + { + Vector3 axis = sumDeltaAngularAxis / deltaRadian; + rotationMatrix( output, axis, deltaRadian ); + + output.v[3].xyz = centerOfMass; + output.v[3].x -= centerOfMass.dot( output.v[0].xyz ); + output.v[3].y -= centerOfMass.dot( output.v[1].xyz ); + output.v[3].z -= centerOfMass.dot( output.v[2].xyz ); + } + else output = Matrix4x4::identity; + + output.v[3].xyz += sumTranslation; + } + + /* + output; is set to an orthographic projection matrix. + width; of the projection sample volume. + height; of the projection sample volume. + nearClip: Distance to the nearClippingPlane. + farClip: Distance to the farClippingPlane + */ + template + void projectionMatrix_Orthographic( Matrix4x4 &output, const ElementType &width, const ElementType &height, const ElementType &nearClip, const ElementType &farClip ) + { + ElementType c = 1; + c /= nearClip - farClip; + output = Matrix4x4( 2/width, 0, 0, 0, + 0, 2/height, 0, 0, + 0, 0, -c, 0, 0, + 0, nearClip*c, 1 ); + } + + /* + output; is set to a perspective transform matrix. + vertFoV; is the vertical field of vision in radians. (se FoV Hor+ ) + aspect; is the screenratio width/height (example 16/9 or 16/10 ) + nearClip: Distance to the nearClippingPlane + farClip: Distance to the farClippingPlane + */ + template + void projectionMatrix_Perspective( Matrix4x4 &output, const ElementType &vertFoV, const ElementType &aspect, const ElementType &nearClip, const ElementType &farClip ) + { + ElementType fov = 1 / ::std::tan( vertFoV * 0.5f ), + dDepth = farClip; + dDepth /= farClip - nearClip; + output = Matrix4x4( fov / aspect, 0, 0, 0, 0, fov, 0, 0, 0, 0, dDepth, 1, 0, 0, -(dDepth * nearClip), 0 ); + } + } +} + +#endif \ No newline at end of file diff --git a/Engine/Math/Matrix.h b/Engine/Math/Matrix.h new file mode 100644 index 00000000..ba7b5767 --- /dev/null +++ b/Engine/Math/Matrix.h @@ -0,0 +1,761 @@ +///////////////////////////////////////////////////////////////////// +// Linear Math Matrixes +// © Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef LINEARALGEBRA_MATRIX_H +#define LINEARALGEBRA_MATRIX_H + +#include "Vector.h" +#include "Utilities.h" + +namespace LinearAlgebra +{ + template + class Matrix2x2 + { + public: + union + { + ElementType m[2][2]; + struct{ Vector2 v[2]; }; +// struct{ ElementType m11, m21, m12, m22; }; + struct{ ElementType m11, m12, m21, m22; }; + ElementType element[4]; + char byte[sizeof(ElementType[4])]; + }; + + static const Matrix2x2 identity, null; + + Matrix2x2( ); + Matrix2x2( const ElementType &m11, const ElementType &m12, + const ElementType &m21, const ElementType &m22 ); + Matrix2x2( const Vector2 vec[2] ); + Matrix2x2( const Vector2 &vec1, const Vector2 &vec2 ); + Matrix2x2( const ElementType element[4] ); + Matrix2x2( const Matrix2x2 &matrix ); + + operator ElementType* ( ); + operator const ElementType* ( ) const; + + Matrix2x2 & operator = ( const Vector2 vec[2] ); + Matrix2x2 & operator = ( const ElementType element[4] ); + Matrix2x2 & operator = ( const Matrix2x2 &matrix ); + Matrix2x2 & operator += ( const Matrix2x2 &matrix ); + Matrix2x2 & operator -= ( const Matrix2x2 &matrix ); + Matrix2x2 & operator *= ( const ElementType &scalar ); + Matrix2x2 & operator /= ( const ElementType &scalar ); + Matrix2x2 operator + ( const Matrix2x2 &matrix ) const; + Matrix2x2 operator - ( const Matrix2x2 &matrix ) const; + Matrix2x2 operator * ( const ElementType &scalar ) const; + Matrix2x2 operator / ( const ElementType &scalar ) const; + Matrix2x2 operator - ( ) const; // unary negation + + ElementType getDeterminant( ) const; + Matrix2x2 getAdjoint( ) const; + Matrix2x2 getTranspose( ) const; + Matrix2x2 & transpose( ); + Matrix2x2 getInverse( ) const; + Matrix2x2 getInverse( ElementType &determinant ) const; + Matrix2x2 & invert( ); + Matrix2x2 & invert( ElementType &determinant ); + Vector2 getRowVector( unsigned int rowID ) const; + const Vector2 & getColumnVector( unsigned int colID ) const; + }; + + template + class Matrix3x3 + { + public: + union + { + ElementType m[3][3]; + struct{ Vector3 v[3]; }; +// struct{ ElementType m11, m21, m31, m12, m22, m32, m13, m23, m33; }; + struct{ ElementType m11, m12, m13, m21, m22, m23, m31, m32, m33; }; + ElementType element[9]; + char byte[sizeof(ElementType[9])]; + }; + + static const Matrix3x3 identity, null; + + Matrix3x3( ); + Matrix3x3( const ElementType &m11, const ElementType &m12, const ElementType &m13, + const ElementType &m21, const ElementType &m22, const ElementType &m23, + const ElementType &m31, const ElementType &m32, const ElementType &m33 ); + Matrix3x3( const Vector3 vec[3] ); + Matrix3x3( const Vector3 &vec1, const Vector3 &vec2, const Vector3 &vec3 ); + Matrix3x3( const ElementType element[9] ); + Matrix3x3( const Matrix3x3 &matrix ); + + operator ElementType* ( ); + operator const ElementType* ( ) const; + + Matrix3x3 & operator = ( const Vector3 vec[3] ); + Matrix3x3 & operator = ( const ElementType element[9] ); + Matrix3x3 & operator = ( const Matrix3x3 &matrix ); + Matrix3x3 & operator += ( const Matrix3x3 &matrix ); + Matrix3x3 & operator -= ( const Matrix3x3 &matrix ); + Matrix3x3 & operator *= ( const ElementType &scalar ); + Matrix3x3 & operator /= ( const ElementType &scalar ); + Matrix3x3 operator + ( const Matrix3x3 &matrix ) const; + Matrix3x3 operator - ( const Matrix3x3 &matrix ) const; + Matrix3x3 operator * ( const ElementType &scalar ) const; + Matrix3x3 operator / ( const ElementType &scalar ) const; + Matrix3x3 operator - ( ) const; // unary negation + + ElementType getDeterminant( ) const; + Matrix3x3 getAdjoint( ) const; + Matrix3x3 getTranspose( ) const; + Matrix3x3 & transpose( ); + Matrix3x3 getInverse( ) const; + Matrix3x3 getInverse( ElementType &determinant ) const; + Matrix3x3 & invert( ); + Matrix3x3 & invert( ElementType &determinant ); + Vector3 getRowVector( unsigned int rowID ) const; + const Vector3 & getColumnVector( unsigned int colID ) const; + }; + + template + class Matrix4x4 + { + public: + union + { + ElementType m[4][4]; + struct{ Vector4 v[4]; }; +// struct{ ElementType m11, m21, m31, m41, m12, m22, m32, m42, m13, m23, m33, m43, m14, m24, m34, m44; }; + struct{ ElementType m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44; }; + ElementType element[16]; + char byte[sizeof(ElementType[16])]; + }; + + static const Matrix4x4 identity, null; + + Matrix4x4( ); + Matrix4x4( const ElementType &m11, const ElementType &m12, const ElementType &m13, const ElementType &m14, + const ElementType &m21, const ElementType &m22, const ElementType &m23, const ElementType &m24, + const ElementType &m31, const ElementType &m32, const ElementType &m33, const ElementType &m34, + const ElementType &m41, const ElementType &m42, const ElementType &m43, const ElementType &m44 ); + Matrix4x4( const Vector4 vec[4] ); + Matrix4x4( const Vector4 &vec1, const Vector4 &vec2, const Vector4 &vec3, const Vector4 &vec4 ); + Matrix4x4( const ElementType element[16] ); + Matrix4x4( const Matrix4x4 &matrix ); + + operator ElementType* ( ); + operator const ElementType* ( ) const; + + Matrix4x4 & operator = ( const Vector4 vec[4] ); + Matrix4x4 & operator = ( const ElementType element[16] ); + Matrix4x4 & operator = ( const Matrix4x4 &matrix ); + Matrix4x4 & operator += ( const Matrix4x4 &matrix ); + Matrix4x4 & operator -= ( const Matrix4x4 &matrix ); + Matrix4x4 & operator *= ( const ElementType &scalar ); + Matrix4x4 & operator /= ( const ElementType &scalar ); + Matrix4x4 operator + ( const Matrix4x4 &matrix ) const; + Matrix4x4 operator - ( const Matrix4x4 &matrix ) const; + Matrix4x4 operator * ( const ElementType &scalar ) const; + Matrix4x4 operator / ( const ElementType &scalar ) const; + Matrix4x4 operator - ( ) const; // unary negation + + ElementType getDeterminant( ) const; + Matrix4x4 getAdjoint( ) const; + Matrix4x4 getTranspose( ) const; + Matrix4x4 & transpose( ); + Matrix4x4 getInverse( ) const; + Matrix4x4 getInverse( ElementType &determinant ) const; + Matrix4x4 & invert( ); + Matrix4x4 & invert( ElementType &determinant ); + Vector4 getRowVector( unsigned int rowID ) const; + const Vector4 & getColumnVector( unsigned int colID ) const; + }; + +/////////////////////////////////////////////////////////////////////////////////// +// Body +/////////////////////////////////////////////////////////////////////////////////// + +// Matrix2x2 /////////////////////////////////////// + template + const Matrix2x2 Matrix2x2::identity = Matrix2x2( 1, 0, 0, 1 ); + + template + const Matrix2x2 Matrix2x2::null = Matrix2x2( 0, 0, 0, 0 ); + + template + Matrix2x2::Matrix2x2( ) : m11(0), m21(0), m12(0), m22(0) {} + + template + Matrix2x2::Matrix2x2( const ElementType &_m11, const ElementType &_m12, const ElementType &_m21, const ElementType &_m22 ) + : m11(_m11), m21(_m21), m12(_m12), m22(_m22) {} + + template + Matrix2x2::Matrix2x2( const Vector2 vec[2] ) + : m11(vec[0].x), m21(vec[0].y), m12(vec[1].x), m22(vec[1].y) {} + + template + Matrix2x2::Matrix2x2( const Vector2 &vec1, const Vector2 &vec2 ) + : m11(vec1.x), m21(vec1.y), m12(vec2.x), m22(vec2.y) {} + + template + Matrix2x2::Matrix2x2( const ElementType _element[4] ) +// : m11(_element[0]), m21(_element[1]), m12(_element[2]), m22(_element[3]) {} + : m11(_element[0]), m12(_element[1]), m21(_element[2]), m22(_element[3]) {} + + template + Matrix2x2::Matrix2x2( const Matrix2x2 &matrix ) + : m11(matrix.m11), m21(matrix.m12), m12(matrix.m21), m22(matrix.m22) {} + + template + inline Matrix2x2::operator ElementType* ( ) + { return this->element; } + + template + inline Matrix2x2::operator const ElementType* ( ) const + { return this->element; } + + template + Matrix2x2 & Matrix2x2::operator = ( const Vector2 vec[2] ) + { + this->v[0] = vec[0]; + this->v[1] = vec[1]; + return *this; + } + + template + Matrix2x2 & Matrix2x2::operator = ( const ElementType element[4] ) + { + for( int i = 0; i < 4; ++i ) + this->element[i] = element[i]; + return *this; + } + + template + Matrix2x2 & Matrix2x2::operator = ( const Matrix2x2 &matrix ) + { + this->v[0] = matrix.v[0]; + this->v[1] = matrix.v[1]; + return *this; + } + + template + Matrix2x2 & Matrix2x2::operator += ( const Matrix2x2 &matrix ) + { + this->v[0] += matrix.v[0]; + this->v[1] += matrix.v[1]; + return *this; + } + + template + Matrix2x2 & Matrix2x2::operator -= ( const Matrix2x2 &matrix ) + { + this->v[0] -= matrix.v[0]; + this->v[1] -= matrix.v[1]; + return *this; + } + + template + Matrix2x2 & Matrix2x2::operator *= ( const ElementType &scalar ) + { + this->v[0] *= scalar; + this->v[1] *= scalar; + return *this; + } + + template + Matrix2x2 & Matrix2x2::operator /= ( const ElementType &scalar ) + { + this->v[0] /= scalar; + this->v[1] /= scalar; + return *this; + } + + template + inline Matrix2x2 Matrix2x2::operator + ( const Matrix2x2 &matrix ) const + { return Matrix2x2(*this) += matrix; } + + template + inline Matrix2x2 Matrix2x2::operator - ( const Matrix2x2 &matrix ) const + { return Matrix2x2(*this) -= matrix; } + + template + inline Matrix2x2 Matrix2x2::operator * ( const ElementType &scalar ) const + { return Matrix2x2(*this) *= scalar; } + + template + inline Matrix2x2 Matrix2x2::operator / ( const ElementType &scalar ) const + { return Matrix2x2(*this) /= scalar; } + + template + inline Matrix2x2 Matrix2x2::operator - ( ) const + { return Matrix2x2(-this->v[0], -this->v[1]); } + + template + ElementType Matrix2x2::getDeterminant( ) const + { + ElementType determinant = (this->m11 * this->m22); + return determinant -= (this->m12 * this->m21); + } + + template + Matrix2x2 Matrix2x2::getAdjoint( ) const + { return Matrix2x2( this->m22, -this->m21, -this->m12, this->m11 ); } + + template + inline Matrix2x2 Matrix2x2::getTranspose( ) const + { return Matrix2x2( this->element[0], this->element[1], this->element[2], this->element[3] ); } + + template + Matrix2x2 & Matrix2x2::transpose( ) + { + ElementType swapSpace; + Utility::Element::swap( this->m12, this->m21, swapSpace ); + return *this; + } + + template + inline Matrix2x2 Matrix2x2::getInverse( ) const + { return this->getAdjoint() /= this->getDeterminant(); } + + template + Matrix2x2 Matrix2x2::getInverse( ElementType &determinant ) const + { + determinant = this->getDeterminant(); + if( determinant != 0 ) + return this->getAdjoint() / determinant; + return Matrix2x2(); + } + + template + Matrix2x2 & Matrix2x2::invert( ) + { + *this /= this->getDeterminant(); + this->m12 *= -1; this->m21 *= -1; + + ElementType swapSpace; + Utility::Element::swap( this->m12, this->m21, swapSpace ); + Utility::Element::swap( this->m11, this->m22, swapSpace ); + return *this; + } + + template + Matrix2x2 & Matrix2x2::invert( ElementType &determinant ) + { + determinant = this->getDeterminant(); + + if( determinant != 0 ) + { + *this /= determinant; + this->m12 *= -1; this->m21 *= -1; + + ElementType swapSpace; + Utility::Element::swap( this->m12, this->m21, swapSpace ); + Utility::Element::swap( this->m11, this->m22, swapSpace ); + } + return *this; + } + + template + inline Vector2 Matrix2x2::getRowVector( unsigned int rowID ) const + { return Vector2( this->m[0][rowID], this->m[1][rowID] ); } + + template + inline const Vector2 & Matrix2x2::getColumnVector( unsigned int colID ) const + { return this->v[colID]; } + +// Matrix3x3 /////////////////////////////////////// + template + const Matrix3x3 Matrix3x3::identity = Matrix3x3( 1, 0, 0, 0, 1, 0, 0, 0, 1 ); + + template + const Matrix3x3 Matrix3x3::null = Matrix3x3( 0, 0, 0, 0, 0, 0, 0, 0, 0 ); + + template + Matrix3x3::Matrix3x3( ) : m11(0), m21(0), m31(0), m12(0), m22(0), m32(0), m13(0), m23(0), m33(0) {} + + template + Matrix3x3::Matrix3x3( const ElementType &_m11, const ElementType &_m12, const ElementType &_m13, const ElementType &_m21, const ElementType &_m22, const ElementType &_m23, const ElementType &_m31, const ElementType &_m32, const ElementType &_m33 ) + : m11(_m11), m21(_m21), m31(_m31), m12(_m12), m22(_m22), m32(_m32), m13(_m13), m23(_m23), m33(_m33) {} + + template + Matrix3x3::Matrix3x3( const Vector3 vec[3] ) + : m11(vec[0].x), m21(vec[0].y), m31(vec[0].z), m12(vec[1].x), m22(vec[1].y), m32(vec[1].z), m13(vec[2].x), m23(vec[2].y), m33(vec[2].z) {} + + template + Matrix3x3::Matrix3x3( const Vector3 &vec1, const Vector3 &vec2, const Vector3 &vec3 ) + : m11(vec1.x), m21(vec1.y), m31(vec1.z), m12(vec2.x), m22(vec2.y), m32(vec2.z), m13(vec3.x), m23(vec3.y), m33(vec3.z) {} + + template + Matrix3x3::Matrix3x3( const ElementType _element[9] ) +// : m11(_element[0]), m21(_element[1]), m31(_element[2]), m12(_element[3]), m22(_element[4]), m32(_element[5]), m13(_element[6]), m23(_element[7]), m33(_element[8]) {} + : m11(_element[0]), m12(_element[1]), m13(_element[2]), m21(_element[3]), m22(_element[4]), m23(_element[5]), m31(_element[6]), m32(_element[7]), m33(_element[8]) {} + + template + Matrix3x3::Matrix3x3( const Matrix3x3 &matrix ) + : m11(matrix.m11), m21(matrix.m21), m31(matrix.m31), m12(matrix.m12), m22(matrix.m22), m32(matrix.m32), m13(matrix.m13), m23(matrix.m23), m33(matrix.m33) {} + + template + inline Matrix3x3::operator ElementType* ( ) + { return this->element; } + + template + inline Matrix3x3::operator const ElementType* ( ) const + { return this->element; } + + template + Matrix3x3 & Matrix3x3::operator = ( const Vector3 vec[3] ) + { + this->v[0] = vec[0]; + this->v[1] = vec[1]; + this->v[2] = vec[2]; + return *this; + } + + template + Matrix3x3 & Matrix3x3::operator = ( const ElementType element[9] ) + { + for( int i = 0; i < 9; ++i ) + this->element[i] = element[i]; + return *this; + } + + template + Matrix3x3 & Matrix3x3::operator = ( const Matrix3x3 &matrix ) + { + this->v[0] = matrix.v[0]; + this->v[1] = matrix.v[1]; + this->v[2] = matrix.v[2]; + return *this; + } + + template + Matrix3x3 & Matrix3x3::operator += ( const Matrix3x3 &matrix ) + { + this->v[0] += matrix.v[0]; + this->v[1] += matrix.v[1]; + this->v[2] += matrix.v[2]; + return *this; + } + + template + Matrix3x3 & Matrix3x3::operator -= ( const Matrix3x3 &matrix ) + { + this->v[0] -= matrix.v[0]; + this->v[1] -= matrix.v[1]; + this->v[2] -= matrix.v[2]; + return *this; + } + + template + Matrix3x3 & Matrix3x3::operator *= ( const ElementType &scalar ) + { + this->v[0] *= scalar; + this->v[1] *= scalar; + this->v[2] *= scalar; + return *this; + } + + template + Matrix3x3 & Matrix3x3::operator /= ( const ElementType &scalar ) + { + this->v[0] /= scalar; + this->v[1] /= scalar; + this->v[2] /= scalar; + return *this; + } + + template + inline Matrix3x3 Matrix3x3::operator + ( const Matrix3x3 &matrix ) const + { return Matrix3x3(*this) += matrix; } + + template + inline Matrix3x3 Matrix3x3::operator - ( const Matrix3x3 &matrix ) const + { return Matrix3x3(*this) -= matrix; } + + template + inline Matrix3x3 Matrix3x3::operator * ( const ElementType &scalar ) const + { return Matrix3x3(*this) *= scalar; } + + template + inline Matrix3x3 Matrix3x3::operator / ( const ElementType &scalar ) const + { return Matrix3x3(*this) /= scalar; } + + template + inline Matrix3x3 Matrix3x3::operator - ( ) const + { return Matrix3x3(-this->v[0], -this->v[1], -this->v[2]); } + + template + ElementType Matrix3x3::getDeterminant( ) const + { + ElementType determinant = (this->m11 * this->m22 * this->m33); + determinant += (this->m12 * this->m23 * this->m31); + determinant += (this->m13 * this->m21 * this->m32); + determinant -= (this->m11 * this->m23 * this->m32); + determinant -= (this->m12 * this->m21 * this->m33); + return determinant -= (this->m13 * this->m22 * this->m31); + } + + template + Matrix3x3 Matrix3x3::getAdjoint( ) const + { + return Matrix3x3( (this->m22*this->m33 - this->m23*this->m32), (this->m13*this->m32 - this->m12*this->m33), (this->m12*this->m23 - this->m13*this->m22), + (this->m23*this->m31 - this->m21*this->m33), (this->m11*this->m33 - this->m13*this->m31), (this->m13*this->m21 - this->m11*this->m23), + (this->m21*this->m32 - this->m22*this->m31), (this->m12*this->m31 - this->m11*this->m32), (this->m11*this->m22 - this->m12*this->m21) ); + } + + template + inline Matrix3x3 Matrix3x3::getTranspose( ) const + { + return Matrix3x3( this->m11, this->m21, this->m31, + this->m12, this->m22, this->m32, + this->m13, this->m23, this->m33 ); + } + + template + Matrix3x3 & Matrix3x3::transpose( ) + { + ElementType swapSpace; + Utility::Element::swap( this->m12, this->m21, swapSpace ); + Utility::Element::swap( this->m13, this->m31, swapSpace ); + Utility::Element::swap( this->m23, this->m32, swapSpace ); + return *this; + } + + template + Matrix3x3 Matrix3x3::getInverse( ) const + { return this->getAdjoint() /= this->getDeterminant(); } + + template + Matrix3x3 Matrix3x3::getInverse( ElementType &determinant ) const + { + determinant = this->getDeterminant(); + if( determinant != 0 ) + return this->getAdjoint() /= determinant; + else return Matrix3x3(); + } + + template + Matrix3x3 & Matrix3x3::invert( ) + { return *this = this->getAdjoint() /= this->getDeterminant(); } + + template + Matrix3x3 & Matrix3x3::invert( ElementType &determinant ) + { + determinant = this->getDeterminant(); + if( determinant != 0 ) + return *this = this->getAdjoint() /= determinant; + return *this; + } + + template + inline Vector3 Matrix3x3::getRowVector( unsigned int rowID ) const + { return Vector3( this->m[0][rowID], this->m[1][rowID], this->m[2][rowID] ); } + + template + inline const Vector3 & Matrix3x3::getColumnVector( unsigned int colID ) const + { return this->v[colID]; } + +// Matrix4x4 /////////////////////////////////////// + template + const Matrix4x4 Matrix4x4::identity = Matrix4x4( 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ); + + template + const Matrix4x4 Matrix4x4::null = Matrix4x4( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); + + template + Matrix4x4::Matrix4x4( ) + : m11(0), m21(0), m31(0), m41(0), m12(0), m22(0), m32(0), m42(0), m13(0), m23(0), m33(0), m43(0), m14(0), m24(0), m34(0), m44(0) {} + + template + Matrix4x4::Matrix4x4( const ElementType &_m11, const ElementType &_m12, const ElementType &_m13, const ElementType &_m14, const ElementType &_m21, const ElementType &_m22, const ElementType &_m23, const ElementType &_m24, const ElementType &_m31, const ElementType &_m32, const ElementType &_m33, const ElementType &_m34, const ElementType &_m41, const ElementType &_m42, const ElementType &_m43, const ElementType &_m44 ) + : m11(_m11), m21(_m21), m31(_m31), m41(_m41), m12(_m12), m22(_m22), m32(_m32), m42(_m42), m13(_m13), m23(_m23), m33(_m33), m43(_m43), m14(_m14), m24(_m24), m34(_m34), m44(_m44) {} + + template + Matrix4x4::Matrix4x4( const Vector4 vec[4] ) + : m11(vec[0].x), m21(vec[0].y), m31(vec[0].z), m41(vec[0].w), m12(vec[1].x), m22(vec[1].y), m32(vec[1].z), m42(vec[1].w), m13(vec[2].x), m23(vec[2].y), m33(vec[2].z), m43(vec[2].w), m14(vec[3].x), m24(vec[3].y), m34(vec[3].z), m44(vec[3].w) {} + + template + Matrix4x4::Matrix4x4( const Vector4 &vec1, const Vector4 &vec2, const Vector4 &vec3, const Vector4 &vec4 ) + : m11(vec1.x), m21(vec1.y), m31(vec1.z), m41(vec1.w), m12(vec2.x), m22(vec2.y), m32(vec2.z), m42(vec2.w), m13(vec3.x), m23(vec3.y), m33(vec3.z), m43(vec3.w), m14(vec4.x), m24(vec4.y), m34(vec4.z), m44(vec4.w) {} + + template + Matrix4x4::Matrix4x4( const ElementType _element[16] ) +// : m11(_element[0]), m21(_element[1]), m31(_element[2]), m41(_element[3]), m12(_element[4]), m22(_element[5]), m32(_element[6]), m42(_element[7]), m13(_element[8]), m23(_element[9]), m33(_element[10]), m43(_element[11]), m14(_element[12]), m24(_element[13]), m34(_element[14]), m44(_element[15]) {} + : m11(_element[0]), m12(_element[1]), m13(_element[2]), m14(_element[3]), m21(_element[4]), m22(_element[5]), m23(_element[6]), m24(_element[7]), m31(_element[8]), m32(_element[9]), m33(_element[10]), m34(_element[11]), m41(_element[12]), m42(_element[13]), m43(_element[14]), m44(_element[15]) {} + + template + Matrix4x4::Matrix4x4( const Matrix4x4 &matrix ) + : m11(matrix.m11), m21(matrix.m21), m31(matrix.m31), m41(matrix.m41), m12(matrix.m12), m22(matrix.m22), m32(matrix.m32), m42(matrix.m42), m13(matrix.m13), m23(matrix.m23), m33(matrix.m33), m43(matrix.m43), m14(matrix.m14), m24(matrix.m24), m34(matrix.m34), m44(matrix.m44) {} + + template + inline Matrix4x4::operator ElementType* ( ) + { return this->element; } + + template + inline Matrix4x4::operator const ElementType* ( ) const + { return this->element; } + + template + Matrix4x4 & Matrix4x4::operator = ( const Vector4 vec[4] ) + { + this->v[0] = vec[0]; + this->v[1] = vec[1]; + this->v[2] = vec[2]; + this->v[3] = vec[3]; + return *this; + } + + template + Matrix4x4 & Matrix4x4::operator = ( const ElementType element[16] ) + { + for( int i = 0; i < 16; ++i ) + this->element[i] = element[i]; + return *this; + } + + template + Matrix4x4 & Matrix4x4::operator = ( const Matrix4x4 &matrix ) + { + this->v[0] = matrix.v[0]; + this->v[1] = matrix.v[1]; + this->v[2] = matrix.v[2]; + this->v[3] = matrix.v[3]; + return *this; + } + + template + Matrix4x4 & Matrix4x4::operator += ( const Matrix4x4 &matrix ) + { + this->v[0] += matrix.v[0]; + this->v[1] += matrix.v[1]; + this->v[2] += matrix.v[2]; + this->v[3] += matrix.v[3]; + return *this; + } + + template + Matrix4x4 & Matrix4x4::operator -= ( const Matrix4x4 &matrix ) + { + this->v[0] -= matrix.v[0]; + this->v[1] -= matrix.v[1]; + this->v[2] -= matrix.v[2]; + this->v[3] -= matrix.v[3]; + return *this; + } + + template + Matrix4x4 & Matrix4x4::operator *= ( const ElementType &scalar ) + { + this->v[0] *= scalar; + this->v[1] *= scalar; + this->v[2] *= scalar; + this->v[3] *= scalar; + return *this; + } + + template + Matrix4x4 & Matrix4x4::operator /= ( const ElementType &scalar ) + { + this->v[0] /= scalar; + this->v[1] /= scalar; + this->v[2] /= scalar; + this->v[3] /= scalar; + return *this; + } + + template + inline Matrix4x4 Matrix4x4::operator + ( const Matrix4x4 &matrix ) const + { return Matrix4x4(*this) += matrix; } + + template + inline Matrix4x4 Matrix4x4::operator - ( const Matrix4x4 &matrix ) const + { return Matrix4x4(*this) -= matrix; } + + template + inline Matrix4x4 Matrix4x4::operator * ( const ElementType &scalar ) const + { return Matrix4x4(*this) *= scalar; } + + template + inline Matrix4x4 Matrix4x4::operator / ( const ElementType &scalar ) const + { return Matrix4x4(*this) /= scalar; } + + template + inline Matrix4x4 Matrix4x4::operator - ( ) const + { return Matrix4x4(-this->v[0], -this->v[1], -this->v[2], -this->v[3]); } + + template + ElementType Matrix4x4::getDeterminant( ) const + { + ElementType determinant = this->m11 * Matrix3x3(this->m22, this->m23, this->m24, this->m32, this->m33, this->m34, this->m42, this->m43, this->m44).getDeterminant(); + determinant -= this->m12 * Matrix3x3(this->m21, this->m23, this->m24, this->m31, this->m33, this->m34, this->m41, this->m43, this->m44).getDeterminant(); + determinant += this->m13 * Matrix3x3(this->m21, this->m22, this->m24, this->m31, this->m32, this->m34, this->m41, this->m42, this->m44).getDeterminant(); + return determinant -= this->m14 * Matrix3x3(this->m21, this->m22, this->m23, this->m31, this->m32, this->m33, this->m41, this->m42, this->m43).getDeterminant(); + } + + template + Matrix4x4 Matrix4x4::getAdjoint( ) const + { + return Matrix4x4( Matrix3x3(this->m22, this->m23, this->m24, this->m32, this->m33, this->m34, this->m42, this->m43, this->m44).getDeterminant(), -Matrix3x3(this->m12, this->m13, this->m14, this->m32, this->m33, this->m34, this->m42, this->m43, this->m44).getDeterminant(), Matrix3x3(this->m12, this->m13, this->m14, this->m22, this->m23, this->m24, this->m42, this->m43, this->m44).getDeterminant(), -Matrix3x3(this->m12, this->m13, this->m14, this->m22, this->m23, this->m24, this->m32, this->m33, this->m34).getDeterminant(), + -Matrix3x3(this->m21, this->m23, this->m24, this->m31, this->m33, this->m34, this->m41, this->m43, this->m44).getDeterminant(), Matrix3x3(this->m11, this->m13, this->m14, this->m31, this->m33, this->m34, this->m41, this->m43, this->m44).getDeterminant(), -Matrix3x3(this->m11, this->m13, this->m14, this->m21, this->m23, this->m24, this->m41, this->m43, this->m44).getDeterminant(), Matrix3x3(this->m11, this->m13, this->m14, this->m21, this->m23, this->m24, this->m31, this->m33, this->m34).getDeterminant(), + Matrix3x3(this->m21, this->m22, this->m24, this->m31, this->m32, this->m34, this->m41, this->m42, this->m44).getDeterminant(), -Matrix3x3(this->m11, this->m12, this->m14, this->m31, this->m32, this->m34, this->m41, this->m42, this->m44).getDeterminant(), Matrix3x3(this->m11, this->m12, this->m14, this->m21, this->m22, this->m24, this->m41, this->m42, this->m44).getDeterminant(), -Matrix3x3(this->m11, this->m12, this->m14, this->m21, this->m22, this->m24, this->m31, this->m32, this->m34).getDeterminant(), + -Matrix3x3(this->m21, this->m22, this->m23, this->m31, this->m32, this->m33, this->m41, this->m42, this->m43).getDeterminant(), Matrix3x3(this->m11, this->m12, this->m13, this->m31, this->m32, this->m33, this->m41, this->m42, this->m43).getDeterminant(), -Matrix3x3(this->m11, this->m12, this->m13, this->m21, this->m22, this->m23, this->m41, this->m42, this->m43).getDeterminant(), Matrix3x3(this->m11, this->m12, this->m13, this->m21, this->m22, this->m23, this->m31, this->m32, this->m33).getDeterminant() ); + } + + template + inline Matrix4x4 Matrix4x4::getTranspose( ) const + { + return Matrix4x4( this->m11, this->m21, this->m31, this->m41, + this->m12, this->m22, this->m32, this->m42, + this->m13, this->m23, this->m33, this->m43, + this->m14, this->m24, this->m34, this->m44 ); + } + + template + Matrix4x4 & Matrix4x4::transpose( ) + { + ElementType swapSpace; + ::Utility::Element::swap( this->m12, this->m21, swapSpace ); + ::Utility::Element::swap( this->m13, this->m31, swapSpace ); + ::Utility::Element::swap( this->m14, this->m41, swapSpace ); + ::Utility::Element::swap( this->m23, this->m32, swapSpace ); + ::Utility::Element::swap( this->m24, this->m42, swapSpace ); + ::Utility::Element::swap( this->m34, this->m43, swapSpace ); + return *this; + } + + template + inline Matrix4x4 Matrix4x4::getInverse( ) const + { return this->getAdjoint() /= this->getDeterminant() ; } + + template + Matrix4x4 Matrix4x4::getInverse( ElementType &determinant ) const + { + determinant = this->getDeterminant(); + if( determinant != 0.0f ) + return this->getAdjoint() /= determinant; + return Matrix4x4(); + } + + template + Matrix4x4 & Matrix4x4::invert( ) + { return *this = this->getAdjoint() /= this->getDeterminant(); } + + template + Matrix4x4 & Matrix4x4::invert( ElementType &determinant ) + { + determinant = this->getDeterminant(); + if( determinant != 0.0f ) + return *this = this->getAdjoint() /= determinant; + return *this; + } + + template + inline Vector4 Matrix4x4::getRowVector( unsigned int rowID ) const + { return Vector4( this->m[0][rowID], this->m[1][rowID], this->m[2][rowID], this->m[3][rowID] ); } + + template + inline const Vector4 & Matrix4x4::getColumnVector( unsigned int colID ) const + { return this->v[colID]; } +} + +#endif \ No newline at end of file diff --git a/Engine/Math/OysterMath.cpp b/Engine/Math/OysterMath.cpp new file mode 100644 index 00000000..43ec9cde --- /dev/null +++ b/Engine/Math/OysterMath.cpp @@ -0,0 +1,32 @@ +///////////////////////////////////////////////////////////////////// +// by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#include "OysterMath.h" + +namespace Oyster { namespace Math +{ + Float2 & operator *= ( Float2 &left, const Float2 &right ) + { + left.x *= right.x; + left.y *= right.y; + return left; + } + + Float3 & operator *= ( Float3 &left, const Float3 &right ) + { + left.x *= right.x; + left.y *= right.y; + left.z *= right.z; + return left; + } + + Float4 & operator *= ( Float4 &left, const Float4 &right ) + { + left.x *= right.x; + left.y *= right.y; + left.z *= right.z; + left.w *= right.w; + return left; + } +} } \ No newline at end of file diff --git a/Engine/Math/OysterMath.h b/Engine/Math/OysterMath.h new file mode 100644 index 00000000..821312fc --- /dev/null +++ b/Engine/Math/OysterMath.h @@ -0,0 +1,220 @@ +///////////////////////////////////////////////////////////////////// +// by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef OYSTER_MATH_H +#define OYSTER_MATH_H + +#include "Utilities.h" +#include "LinearMath.h" +#include + +namespace Oyster { namespace Math +{ + typedef float Float; + + typedef ::LinearAlgebra::Vector2 Float2; + typedef ::LinearAlgebra::Vector3 Float3; + typedef ::LinearAlgebra::Vector4 Float4; + + typedef ::LinearAlgebra::Matrix2x2 Float2x2; + typedef ::LinearAlgebra::Matrix3x3 Float3x3; + typedef ::LinearAlgebra::Matrix4x4 Float4x4; + + typedef Float4x4 Matrix; + typedef Float2 Vector2; + typedef Float3 Vector3; + typedef Float4 Vector4; + + + + Float2 & operator *= ( Float2 &left, const Float2 &right ); + + inline Float2 operator * ( const Float2 &left, const Float2 &right ) + { return Float2(left) *= right; } + + inline Float2 operator * ( const Float &left, const Float2 &right ) + { return Float2(right) *= left; } + + Float3 & operator *= ( Float3 &left, const Float3 &right ); + + inline Float3 operator * ( const Float3 &left, const Float3 &right ) + { return Float3(left) *= right; } + + inline Float3 operator * ( const Float &left, const Float3 &right ) + { return Float3(right) *= left; } + + Float4 & operator *= ( Float4 &left, const Float4 &right ); + + inline Float4 operator * ( const Float4 &left, const Float4 &right ) + { return Float4(left) *= right; } + + inline Float4 operator * ( const Float &left, const Float4 &right ) + { return Float4(right) *= left; } + + inline Float2x2 operator * ( const Float &left, const Float2x2 &right ) + { return Float2x2(right) *= left; } + + inline Float3x3 operator * ( const Float &left, const Float3x3 &right ) + { return Float3x3(right) *= left; } + + inline Float4x4 operator * ( const Float &left, const Float4x4 &right ) + { return Float4x4(right) *= left; } + + // Deprecated function! Use the static const member identity instead. + inline void identityMatrix( Float2x2 &output ) + { output = Float2x2::identity; } + + // Deprecated function! Use the static const member identity instead. + inline void identityMatrix( Float3x3 &output ) + { output = Float3x3::identity; } + + // Deprecated function! Use the static const member identity instead. + inline void identityMatrix( Float4x4 &output ) + { output = Float4x4::identity; } + + // If rigidBody is assumed to be by all definitions a rigid body matrix. Then this is a faster inverse method. + inline void inverseRigidBodyMatrix( Float4x4 &output, const Float4x4 &rigidBody ) + { ::LinearAlgebra::_3D::inverseRigidBody( output, rigidBody ); } + + inline void translationMatrix( Float4x4 &output, const Float3 &position ) + { ::LinearAlgebra::_3D::translationMatrix( output, position ); } + + // counterclockwise rotation around X axis + inline void rotationMatrix_AxisX( Float4x4 &output, const Float &radian ) + { ::LinearAlgebra::_3D::rotationMatrix_AxisX( output, radian ); } + + // counterclockwise rotation around Y axis + inline void rotationMatrix_AxisY( Float4x4 &output, const Float &radian ) + { ::LinearAlgebra::_3D::rotationMatrix_AxisY( output, radian ); } + + // counterclockwise rotation around Z axis + inline void rotationMatrix_AxisZ( Float4x4 &output, const Float &radian ) + { ::LinearAlgebra::_3D::rotationMatrix_AxisZ( output, radian ); } + + // counterclockwise rotation around any given Float3 vector (normalizedAxis). Please make sure it is normalized. + inline void rotationMatrix( Float4x4 &output, const Float &radian, const Float3 &normalizedAxis ) + { ::LinearAlgebra::_3D::rotationMatrix( output, normalizedAxis, radian ); } + + /* + returns a deltaAngularAxis which is a vectorProduct of the particleMovementVector and leverVector. + angular: (1/I) * L, there I is known as the "moment of inertia", L as the "angular momentum vector". + lever: Displacement vector relative to the center of mass. + Recommended reading: http://en.wikipedia.org/wiki/Torque + */ + inline Float3 deltaAngularAxis( const Float3 &movement, const Float3 &lever ) + { return ::LinearAlgebra::_3D::deltaAngularAxis( movement, lever ); } + + inline Float3 particleRotationMovement( const Float3 &deltaRadian, const Float3 &lever ) + { return ::LinearAlgebra::_3D::particleRotationMovement( deltaRadian, lever ); } + + inline Float3 vectorProjection( const Float3 &vector, const Float3 &axis ) + { return ::LinearAlgebra::_3D::vectorProjection( vector, axis ); } + + /* + output: is set to a rigibody matrix that revolve/rotate around centerOfMass and then translates. + sumDeltaAngularAxis: sum of all ( (1/I) * ( L x D ) )-vectorproducts. There I is known as "moment of inertia", L as "angular momentum vector" and D the "lever vector". + sumTranslation: sum of all the translation vectors. + centerOfMass: the point the particles is to revolve around, prior to translation. Default set to null vector aka origo. + Recommended reading: http://en.wikipedia.org/wiki/Torque + */ + inline void rigidBodyMatrix( Float4x4 &output, const Float3 &sumDeltaAngularAxis, const Float3 &sumTranslation, const Float3 ¢erOfMass = Float3::null ) + { ::LinearAlgebra::_3D::rigidBodyMatrix( output, sumDeltaAngularAxis, sumTranslation, centerOfMass ); } + + /* + output; is set to an orthographic projection matrix. + width; of the projection sample volume. + height; of the projection sample volume. + near: Distance to the nearPlane. + far: Distance to the farPlane + */ + inline void projectionMatrix_Orthographic( Float4x4 &output, const Float &width, const Float &height, const Float &nearClip = ::std::numeric_limits::epsilon(), const Float &farClip = ::std::numeric_limits::max() ) + { ::LinearAlgebra::_3D::projectionMatrix_Orthographic( output, width, height, nearClip, farClip ); } + + /* + output; is set to a perspective transform matrix. + vertFoV; is the vertical field of vision in radians. (se FoV Hor+ ) + aspect; is the screenratio width/height (example 16/9 or 16/10 ) + near: Distance to the nearPlane + far: Distance to the farPlane + */ + inline void projectionMatrix_Perspective( Float4x4 &output, const Float &verticalFoV, const Float &aspectRatio, const Float &nearClip = ::std::numeric_limits::epsilon(), const Float &farClip = ::std::numeric_limits::max() ) + { ::LinearAlgebra::_3D::projectionMatrix_Perspective( output, verticalFoV, aspectRatio, nearClip, farClip ); } + + inline Float4x4 & viewProjectionMatrix( Float4x4 &output, const Float4x4 &view, const Float4x4 &projection ) + { return output = (view * projection).getTranspose(); } + + inline Float4x4 & transformMatrix( Float4x4 &output, const Float4x4 &transformee, const Float4x4 &transformer ) + { return output = transformee * transformer; } + + inline Float4x4 transformMatrix( const Float4x4 &transformee, const Float4x4 &transformer ) + { return transformee * transformer; } + + inline Float4 & transformVector( Float4 &output, const Float4 &transformee, const Float4x4 &transformer ) + { return output = transformer * transformee; } + + inline Float4 transformVector( const Float4 &transformee, const Float4x4 &transformer ) + { return transformee * transformer; } +} } + +namespace Utility { namespace Value +{ // Utility Value Specializations + using namespace ::Oyster::Math; + + template< > inline Float2 abs( const Float2 &value ) + { return Float2( abs(value.x), abs(value.y) ); } + + template< > inline Float2 max( const Float2 &valueA, const Float2 &valueB ) + { return Float2( max(valueA.x, valueB.x), max(valueA.y, valueB.y) ); } + + template< > inline Float2 min( const Float2 &valueA, const Float2 &valueB ) + { return Float2( min(valueA.x, valueB.x), min(valueA.y, valueB.y) ); } + + template< > inline Float3 abs( const Float3 &value ) + { return Float3( abs(value.xy), abs(value.z) ); } + + template< > inline Float3 max( const Float3 &valueA, const Float3 &valueB ) + { return Float3( max(valueA.xy, valueB.xy), max(valueA.z, valueB.z) ); } + + template< > inline Float3 min( const Float3 &valueA, const Float3 &valueB ) + { return Float3( min(valueA.xy, valueB.xy), min(valueA.z, valueB.z) ); } + + template< > inline Float4 abs( const Float4 &value ) + { return Float4( abs(value.xyz), abs(value.w) ); } + + template< > inline Float4 max( const Float4 &valueA, const Float4 &valueB ) + { return Float4( max(valueA.xyz, valueB.xyz), max(valueA.w, valueB.w) ); } + + template< > inline Float4 min( const Float4 &valueA, const Float4 &valueB ) + { return Float4( min(valueA.xyz, valueB.xyz), min(valueA.w, valueB.w) ); } + + template< > inline Float2x2 abs( const Float2x2 &value ) + { return Float2x2( abs(value.v[0]), abs(value.v[1]) ); } + + template< > inline Float2x2 max( const Float2x2 &valueA, const Float2x2 &valueB ) + { return Float2x2( max(valueA.v[0], valueB.v[0]), max(valueA.v[1], valueB.v[1]) ); } + + template< > inline Float2x2 min( const Float2x2 &valueA, const Float2x2 &valueB ) + { return Float2x2( min(valueA.v[0], valueB.v[0]), min(valueA.v[1], valueB.v[1]) ); } + + template< > inline Float3x3 abs( const Float3x3 &value ) + { return Float3x3( abs(value.v[0]), abs(value.v[1]), abs(value[2]) ); } + + template< > inline Float3x3 max( const Float3x3 &valueA, const Float3x3 &valueB ) + { return Float3x3( max(valueA.v[0], valueB.v[0]), max(valueA.v[1], valueB.v[1]), max(valueA.v[2], valueB.v[2]) ); } + + template< > inline Float3x3 min( const Float3x3 &valueA, const Float3x3 &valueB ) + { return Float3x3( min(valueA.v[0], valueB.v[0]), min(valueA.v[1], valueB.v[1]), min(valueA.v[2], valueB.v[2]) ); } + + template< > inline Float4x4 abs( const Float4x4 &value ) + { return Float4x4( abs(value.v[0]), abs(value.v[1]), abs(value[2]), abs(value[3]) ); } + + template< > inline Float4x4 max( const Float4x4 &valueA, const Float4x4 &valueB ) + { return Float4x4( max(valueA.v[0], valueB.v[0]), max(valueA.v[1], valueB.v[1]), max(valueA.v[2], valueB.v[2]), max(valueA.v[3], valueB.v[3]) ); } + + template< > inline Float4x4 min( const Float4x4 &valueA, const Float4x4 &valueB ) + { return Float4x4( min(valueA.v[0], valueB.v[0]), min(valueA.v[1], valueB.v[1]), min(valueA.v[2], valueB.v[2]), min(valueA.v[3], valueB.v[3]) ); } +} } + +#endif \ No newline at end of file diff --git a/Engine/Math/Quaternion.h b/Engine/Math/Quaternion.h new file mode 100644 index 00000000..383c0245 --- /dev/null +++ b/Engine/Math/Quaternion.h @@ -0,0 +1,183 @@ +///////////////////////////////////////////////////////////////////// +// Linear Math Quaternions +// © Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef LINEARALGEBRA_QUATERNION_H +#define LINEARALGEBRA_QUATERNION_H + +#include "Vector.h" +#include + +namespace LinearAlgebra +{ + template + class Quaternion + { + public: + union + { + struct{ Vector3 imaginary; ElementType real; }; + ElementType element[4]; + char byte[sizeof(ElementType[2])]; + }; + + Quaternion( ); + Quaternion( const Quaternion &quaternion ); + Quaternion( const Vector3 &imaginary, const ElementType &real ); + ~Quaternion( ); + + operator ElementType* ( ); + operator const ElementType* ( ) const; + operator char* ( ); + operator const char* ( ) const; + ElementType & operator [] ( int i ); + const ElementType & operator [] ( int i ) const; + + Quaternion & operator = ( const Quaternion &quaternion ); + Quaternion & operator *= ( const ElementType &scalar ); + Quaternion & operator /= ( const ElementType &scalar ); + Quaternion & operator += ( const Quaternion &quaternion ); + Quaternion & operator -= ( const Quaternion &quaternion ); + Quaternion operator * ( const Quaternion &quaternion ) const; + Quaternion operator * ( const Vector3 &vector ) const; + Quaternion operator * ( const ElementType &scalar ) const; + Quaternion operator / ( const ElementType &scalar ) const; + Quaternion operator + ( const Quaternion &quaternion ) const; + Quaternion operator - ( const Quaternion &quaternion ) const; + Quaternion operator - ( ) const; + + Quaternion getConjugate( ) const; + }; + +/////////////////////////////////////////////////////////////////////////////////// +// Body +/////////////////////////////////////////////////////////////////////////////////// + + template + Quaternion::Quaternion( ) : imaginary(0,0,0), real(0) {} + + template + Quaternion::Quaternion( const Quaternion &quaternion ) : imaginary(quaternion.imaginary), real(quaternion.real) {} + + template + Quaternion::Quaternion( const Vector3 &_imaginary, const ElementType &_real ) : imaginary(_imaginary), real(_real) {} + + template + Quaternion::~Quaternion( ) { /* Nothing that needs to be done */ } + + template + inline Quaternion::operator ElementType* ( ) + { return this->element; } + + template + inline Quaternion::operator const ElementType* ( ) const + { return this->element; } + + template + inline Quaternion::operator char* ( ) + { return this->byte; } + + template + inline Quaternion::operator const char* ( ) const + { return this->byte; } + + template + inline ElementType & Quaternion::operator [] ( int i ) + { return this->element[i]; } + + template + inline const ElementType & Quaternion::operator [] ( int i ) const + { return this->element[i]; } + + template + Quaternion & Quaternion::operator = ( const Quaternion &quaternion ) + { + this->imaginary = quaternion.imaginary; + this->real = quaternion.real; + return *this; + } + + template + Quaternion & Quaternion::operator *= ( const ElementType &scalar ) + { + this->imaginary *= scalar; + this->real *= scalar; + return *this; + } + + template + Quaternion & Quaternion::operator /= ( const ElementType &scalar ) + { + this->imaginary /= scalar; + this->real /= scalar; + return *this; + } + + template + Quaternion & Quaternion::operator += ( const Quaternion &quaternion ) + { + this->imaginary += quaternion.imaginary; + this->real += quaternion.real; + return *this; + } + + template + Quaternion & Quaternion::operator -= ( const Quaternion &quaternion ) + { + this->imaginary -= quaternion.imaginary; + this->real -= quaternion.real; + return *this; + } + + template + Quaternion Quaternion::operator * ( const Quaternion &quaternion ) const + { + Vector3 im = this->imaginary.cross( quaternion.imaginary ); + im += (quaternion.imaginary * this->real); + im += (this->imaginary * quaternion.real); + + ElementType re = this->real * quaternion.real; + re -= this->imaginary.dot( quaternion.imaginary ); + + return Quaternion( im, re ); + } + + template + Quaternion Quaternion::operator * ( const Vector3 &vector ) const + { + Vector3 im = this->imaginary.cross( vector ); + im += (vector * this->real); + + ElementType re = this->imaginary.dot( vector ) * -1; + + return Quaternion( im, re ); + } + + template + inline Quaternion Quaternion::operator * ( const ElementType &scalar ) const + { return Quaternion(*this) *= scalar; } + + template + inline Quaternion Quaternion::operator / ( const ElementType &scalar ) const + { return Quaternion(*this) /= scalar; } + + template + inline Quaternion Quaternion::operator + ( const Quaternion &quaternion ) const + { return Quaternion(*this) += quaternion; } + + template + inline Quaternion Quaternion::operator - ( const Quaternion &quaternion ) const + { return Quaternion(*this) -= quaternion; } + + template + inline Quaternion Quaternion::operator - ( ) const + { return Quaternion(-this->imaginary, -this->real); } + + template + inline Quaternion Quaternion::getConjugate( ) const + { return Quaternion(this->imaginary * -1, this->real ); } +} + +#endif \ No newline at end of file diff --git a/Engine/Math/Vector.h b/Engine/Math/Vector.h new file mode 100644 index 00000000..086ed7d8 --- /dev/null +++ b/Engine/Math/Vector.h @@ -0,0 +1,659 @@ +///////////////////////////////////////////////////////////////////// +// Linear Math Vectors +// © Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef LINEARALGEBRA_VECTOR_H +#define LINEARALGEBRA_VECTOR_H + +#include + +namespace LinearAlgebra +{ + template + class Vector2 + { + public: + union + { + struct { ElementType x, y; }; + ElementType element[2]; + char byte[sizeof(ElementType[2])]; + }; + + static const Vector2 null; + static const Vector2 standardUnitX; + static const Vector2 standardUnitY; + + Vector2( ); + Vector2( const Vector2 &vector ); + Vector2( const ElementType &element ); + Vector2( const ElementType element[2] ); + Vector2( const ElementType &x, const ElementType &y ); + ~Vector2( ); + + operator ElementType* ( ); + operator const ElementType* ( ) const; + operator char* ( ); + operator const char* ( ) const; + ElementType & operator [] ( int i ); + const ElementType & operator [] ( int i ) const; + + Vector2 & operator = ( const Vector2 &vector ); + Vector2 & operator = ( const ElementType element[2] ); + Vector2 & operator *= ( const ElementType &scalar ); + Vector2 & operator /= ( const ElementType &scalar ); + Vector2 & operator += ( const Vector2 &vector ); + Vector2 & operator -= ( const Vector2 &vector ); + Vector2 operator * ( const ElementType &scalar ) const; + Vector2 operator / ( const ElementType &scalar ) const; + Vector2 operator + ( const Vector2 &vector ) const; + Vector2 operator - ( const Vector2 &vector ) const; + Vector2 operator - ( ) const; // unary negation + + bool operator == ( const Vector2 &vector ) const; + bool operator != ( const Vector2 &vector ) const; + + ElementType length( ) const; + ElementType dot( const Vector2 &vector ) const; + + Vector2 & normalize( ); + Vector2 getNormalized( ) const; + }; + + template + class Vector3 + { + public: + union + { + struct { ElementType x, y, z; }; + struct { Vector2 xy; }; + ElementType element[3]; + char byte[sizeof(ElementType[3])]; + }; + + static const Vector3 null; + static const Vector3 standardUnitX; + static const Vector3 standardUnitY; + static const Vector3 standardUnitZ; + + Vector3( ); + Vector3( const Vector3 &vector ); + Vector3( const Vector2 &vector, const ElementType &z ); + Vector3( const ElementType &element ); + Vector3( const ElementType element[3] ); + Vector3( const ElementType &x, const ElementType &y, const ElementType &z ); + ~Vector3( ); + + operator ElementType* (); + operator const ElementType* () const; + operator char* ( ); + operator const char* ( ) const; + ElementType & operator [] ( int i ); + const ElementType & operator [] ( int i ) const; + + Vector3 & operator = ( const Vector3 &vector ); + Vector3 & operator = ( const ElementType element[3] ); + Vector3 & operator *= ( const ElementType &scalar ); + Vector3 & operator /= ( const ElementType &scalar ); + Vector3 & operator += ( const Vector3 &vector ); + Vector3 & operator -= ( const Vector3 &vector ); + Vector3 operator * ( const ElementType &scalar ) const; + Vector3 operator / ( const ElementType &scalar ) const; + Vector3 operator + ( const Vector3 &vector ) const; + Vector3 operator - ( const Vector3 &vector ) const; + Vector3 operator - ( ) const; // unary negation + + bool operator == ( const Vector3 &vector ) const; + bool operator != ( const Vector3 &vector ) const; + + ElementType length( ) const; + ElementType dot( const Vector3 &vector ) const; + Vector3 cross( const Vector3 &vector ) const; + + Vector3 & normalize( ); + Vector3 getNormalized( ) const; + }; + + template + class Vector4 + { + public: + union + { + struct { ElementType x, y, z, w; }; + struct { Vector2 xy; }; + struct { Vector3 xyz; }; + ElementType element[4]; + char byte[sizeof(ElementType[4])]; + }; + + static const Vector4 null; + static const Vector4 standardUnitX; + static const Vector4 standardUnitY; + static const Vector4 standardUnitZ; + static const Vector4 standardUnitW; + + Vector4( ); + Vector4( const Vector4 &vector ); + Vector4( const Vector3 &vector, const ElementType &w ); + Vector4( const Vector2 &vector, const ElementType &z, const ElementType &w ); + Vector4( const ElementType &element ); + Vector4( const ElementType element[4] ); + Vector4( const ElementType &x, const ElementType &y, const ElementType &z, const ElementType &w ); + ~Vector4( ); + + operator ElementType* (); + operator const ElementType* () const; + operator char* ( ); + operator const char* ( ) const; + ElementType & operator [] ( int i ); + const ElementType & operator [] ( int i ) const; + + Vector4 & operator = ( const Vector4 &vector ); + Vector4 & operator = ( const ElementType element[4] ); + Vector4 & operator *= ( const ElementType &scalar ); + Vector4 & operator /= ( const ElementType &scalar ); + Vector4 & operator += ( const Vector4 &vector ); + Vector4 & operator -= ( const Vector4 &vector ); + Vector4 operator * ( const ElementType &scalar ) const; + Vector4 operator / ( const ElementType &scalar ) const; + Vector4 operator + ( const Vector4 &vector ) const; + Vector4 operator - ( const Vector4 &vector ) const; + Vector4 operator - ( ) const; // unary negation + + bool operator == ( const Vector4 &vector ) const; + bool operator != ( const Vector4 &vector ) const; + + ElementType length( ) const; + ElementType dot( const Vector4 &vector ) const; + + Vector4 & normalize( ); + Vector4 getNormalized( ) const; + }; + +/////////////////////////////////////////////////////////////////////////////////// +// Body +/////////////////////////////////////////////////////////////////////////////////// + +// Vector2 /////////////////////////////////////// + template const Vector2 Vector2::null = Vector2( ); + template const Vector2 Vector2::standardUnitX = Vector2( 1, 0 ); + template const Vector2 Vector2::standardUnitY = Vector2( 0, 1 ); + + template + Vector2::Vector2( ) : x(0), y(0) {} + + template + Vector2::Vector2( const Vector2 &vector ) : x(vector.x), y(vector.y) + { this->x = vector.x; this->y = vector.y; } + + template + Vector2::Vector2( const ElementType &_element ) : x(_element), y(_element) + { this->x = this->y = _element; } + + template + Vector2::Vector2( const ElementType _element[2] ) : x(_element[0]), y(_element[1]) {} + + template + Vector2::Vector2( const ElementType &_x, const ElementType &_y ) : x(_x), y(_y) {} + + template + Vector2::~Vector2( ) { /* Nothing that needs to be done */ } + + template + inline Vector2::operator ElementType* () + { return this->element; } + + template + inline Vector2::operator const ElementType* () const + { return this->element; } + + template + inline Vector2::operator char* ( ) + { return this->byte; } + + template + inline Vector2::operator const char* ( ) const + { return this->byte; } + + template + inline ElementType & Vector2::operator [] ( int i ) + { return this->element[i]; } + + template + inline const ElementType & Vector2::operator [] ( int i ) const + { return this->element[i]; } + + template + Vector2 & Vector2::operator = ( const Vector2 &vector ) + { + this->element[0] = vector.element[0]; + this->element[1] = vector.element[1]; + return *this; + } + + template + Vector2 & Vector2::operator = ( const ElementType _element[2] ) + { + this->element[0] = _element[0]; + this->element[1] = _element[1]; + return *this; + } + + template + Vector2 & Vector2::operator *= ( const ElementType &scalar ) + { + this->element[0] *= scalar; + this->element[1] *= scalar; + return *this; + } + + template + Vector2 & Vector2::operator /= ( const ElementType &scalar ) + { + this->element[0] /= scalar; + this->element[1] /= scalar; + return *this; + } + + template + Vector2 & Vector2::operator += ( const Vector2 &vector ) + { + this->element[0] += vector.element[0]; + this->element[1] += vector.element[1]; + return *this; + } + + template + Vector2 & Vector2::operator -= ( const Vector2 &vector ) + { + this->element[0] -= vector.element[0]; + this->element[1] -= vector.element[1]; + return *this; + } + + template + inline Vector2 Vector2::operator * ( const ElementType &scalar ) const + { return Vector2(*this) *= scalar; } + + template + inline Vector2 Vector2::operator / ( const ElementType &scalar ) const + { return Vector2(*this) /= scalar; } + + template + inline Vector2 Vector2::operator + ( const Vector2 &vector ) const + { return Vector2(*this) += vector; } + + template + inline Vector2 Vector2::operator - ( const Vector2 &vector ) const + { return Vector2(*this) -= vector; } + + template + inline Vector2 Vector2::operator - ( ) const + { return Vector2(-this->x, -this->y); } + + template + bool Vector2::operator == ( const Vector2 &vector ) const + { + if( this->x != vector.x ) return false; + if( this->y != vector.y ) return false; + return true; + } + + template + bool Vector2::operator != ( const Vector2 &vector ) const + { + if( this->x != vector.x ) return true; + if( this->y != vector.y ) return true; + return false; + } + + template + inline ElementType Vector2::length( ) const + { return (ElementType) ::sqrt( this->dot(*this) ); } + + template + ElementType Vector2::dot( const Vector2 &vector ) const + { + ElementType value = 0; + value += this->element[0] * vector.element[0]; + value += this->element[1] * vector.element[1]; + return value; + } + + template + inline Vector2 & Vector2::normalize( ) + { return (*this) /= this->length(); } + + template + inline Vector2 Vector2::getNormalized( ) const + { return Vector2(*this).normalize(); } + +// Vector3 /////////////////////////////////////// + template const Vector3 Vector3::null = Vector3( ); + template const Vector3 Vector3::standardUnitX = Vector3( 1, 0, 0 ); + template const Vector3 Vector3::standardUnitY = Vector3( 0, 1, 0 ); + template const Vector3 Vector3::standardUnitZ = Vector3( 0, 0, 1 ); + + template + Vector3::Vector3( ) : x(0), y(0), z(0) {} + + template + Vector3::Vector3( const Vector3 &vector ) : x(vector.x), y(vector.y), z(vector.z) + { this->x = vector.x; this->y = vector.y; this->z = vector.z; } + + template + Vector3::Vector3( const Vector2 &vector, const ElementType &_z ) : x(vector.x), y(vector.y), z(_z) + { this->x = vector.x; this->y = vector.y; } + + template + Vector3::Vector3( const ElementType &_element ) : x(_element), y(_element), z(_element) + { this->x = this->y = this->z = _element; } + + template + Vector3::Vector3( const ElementType _element[3] ) : x(_element[0]), y(_element[1]), z(_element[2]) {} + + template + Vector3::Vector3( const ElementType &_x, const ElementType &_y, const ElementType &_z ) : x(_x), y(_y), z(_z) + { this->x = _x; this->y = _y; this->z = _z; } + + template + Vector3::~Vector3( ) { /* Nothing that needs to be done */ } + + template + inline Vector3::operator ElementType* () + { return this->element; } + + template + inline Vector3::operator const ElementType* () const + { return this->element; } + + template + inline ElementType & Vector3::operator [] ( int i ) + { return this->element[i]; } + + template + inline const ElementType & Vector3::operator [] ( int i ) const + { return this->element[i]; } + + template + Vector3 & Vector3::operator = ( const Vector3 &vector ) + { + for( int i = 0; i < 3; ++i ) + this->element[i] = vector.element[i]; + return *this; + } + + template + Vector3 & Vector3::operator = ( const ElementType element[3] ) + { + for( int i = 0; i < 3; ++i ) + this->element[i] = element[i]; + return *this; + } + + template + Vector3 & Vector3::operator *= ( const ElementType &scalar ) + { + for( int i = 0; i < 3; ++i ) + this->element[i] *= scalar; + return *this; + } + + template + Vector3 & Vector3::operator /= ( const ElementType &scalar ) + { + for( int i = 0; i < 3; ++i ) + this->element[i] /= scalar; + return *this; + } + + template + Vector3 & Vector3::operator += ( const Vector3 &vector ) + { + for( int i = 0; i < 3; ++i ) + this->element[i] += vector.element[i]; + return *this; + } + + template + Vector3 & Vector3::operator -= ( const Vector3 &vector ) + { + for( int i = 0; i < 3; ++i ) + this->element[i] -= vector.element[i]; + return *this; + } + + template + inline Vector3 Vector3::operator * ( const ElementType &scalar ) const + { return Vector3(*this) *= scalar; } + + template + inline Vector3 Vector3::operator / ( const ElementType &scalar ) const + { return Vector3(*this) /= scalar; } + + template + inline Vector3 Vector3::operator + ( const Vector3 &vector ) const + { return Vector3(*this) += vector; } + + template + inline Vector3 Vector3::operator - ( const Vector3 &vector ) const + { return Vector3(*this) -= vector; } + + template + inline Vector3 Vector3::operator - ( ) const + { return Vector3(-this->x, -this->y, -this->z); } + + template + bool Vector3::operator == ( const Vector3 &vector ) const + { + if( this->x != vector.x ) return false; + if( this->y != vector.y ) return false; + if( this->z != vector.z ) return false; + return true; + } + + template + bool Vector3::operator != ( const Vector3 &vector ) const + { + if( this->x != vector.x ) return true; + if( this->y != vector.y ) return true; + if( this->z != vector.z ) return true; + return false; + } + + template + inline ElementType Vector3::length( ) const + { return (ElementType) ::sqrt( this->dot(*this) ); } + + template + ElementType Vector3::dot( const Vector3 &vector ) const + { + ElementType value = 0; + for( int i = 0; i < 3; ++i ) + value += this->element[i] * vector.element[i]; + return value; + } + + template + Vector3 Vector3::cross( const Vector3 &vector ) const + { + return Vector3( (this->y*vector.z) - (this->z*vector.y), + (this->z*vector.x) - (this->x*vector.z), + (this->x*vector.y) - (this->y*vector.x) ); + } + + template + inline Vector3 & Vector3::normalize( ) + { return (*this) /= this->length(); } + + template + inline Vector3 Vector3::getNormalized( ) const + { return Vector3(*this).normalize(); } + +// Vector4 /////////////////////////////////////// + template const Vector4 Vector4::null = Vector4( ); + template const Vector4 Vector4::standardUnitX = Vector4( 1, 0, 0, 0 ); + template const Vector4 Vector4::standardUnitY = Vector4( 0, 1, 0, 0 ); + template const Vector4 Vector4::standardUnitZ = Vector4( 0, 0, 1, 0 ); + template const Vector4 Vector4::standardUnitW = Vector4( 0, 0, 0, 1 ); + + template + Vector4::Vector4( ) : x(0), y(0), z(0), w(0) {} + + template + Vector4::Vector4( const Vector4 &vector ) : x(vector.x), y(vector.y), z(vector.z), w(vector.z) + { this->x = vector.x; this->y = vector.y; this->z = vector.z; this->w = vector.w; } + + template + Vector4::Vector4( const Vector3 &vector, const ElementType &_w ) : x(vector.x), y(vector.y), z(vector.z), w(_w) + { this->x = vector.x; this->y = vector.y; this->z = vector.z; } + + template + Vector4::Vector4( const Vector2 &vector, const ElementType &_z, const ElementType &_w ) : x(vector.x), y(vector.y), z(_z), w(_w) + { this->x = vector.x; this->y = vector.y; this->z = _z; this->w = _w; } + + template + Vector4::Vector4( const ElementType &_element ) : x(_element), y(_element), z(_element), w(_element) + { this->x = this->y = this->z = this->w = _element; } + + template + Vector4::Vector4( const ElementType _element[4] ) : x(_element[0]), y(_element[1]), z(_element[2]), w(_element[3]) {} + + template + Vector4::Vector4( const ElementType &_x, const ElementType &_y, const ElementType &_z, const ElementType &_w ) : x(_x), y(_y), z(_z), w(_w) + { this->x = _x; this->y = _y; this->z = _z; this->w = _w; } + + template + Vector4::~Vector4( ) { /* Nothing that needs to be done */ } + + template + inline Vector4::operator ElementType* () + { return this->element; } + + template + inline Vector4::operator const ElementType* () const + { return this->element; } + + template + inline ElementType & Vector4::operator [] ( int i ) + { return this->element[i]; } + + template + inline const ElementType & Vector4::operator [] ( int i ) const + { return this->element[i]; } + + template + Vector4 & Vector4::operator = ( const Vector4 &vector ) + { + for( int i = 0; i < 4; ++i ) + this->element[i] = vector.element[i]; + return *this; + } + + template + Vector4 & Vector4::operator = ( const ElementType element[4] ) + { + for( int i = 0; i < 4; ++i ) + this->element[i] = element[i]; + return *this; + } + + template + Vector4 & Vector4::operator *= ( const ElementType &scalar ) + { + for( int i = 0; i < 4; ++i ) + this->element[i] *= scalar; + return *this; + } + + template + Vector4 & Vector4::operator /= ( const ElementType &scalar ) + { + for( int i = 0; i < 4; ++i ) + this->element[i] /= scalar; + return *this; + } + + template + Vector4 & Vector4::operator += ( const Vector4 &vector ) + { + for( int i = 0; i < 4; ++i ) + this->element[i] += vector.element[i]; + return *this; + } + + template + Vector4 & Vector4::operator -= ( const Vector4 &vector ) + { + for( int i = 0; i < 4; ++i ) + this->element[i] -= vector.element[i]; + return *this; + } + + template + inline Vector4 Vector4::operator * ( const ElementType &scalar ) const + { return Vector4(*this) *= scalar; } + + template + inline Vector4 Vector4::operator / ( const ElementType &scalar ) const + { return Vector4(*this) /= scalar; } + + template + inline Vector4 Vector4::operator + ( const Vector4 &vector ) const + { return Vector4(*this) += vector; } + + template + inline Vector4 Vector4::operator - ( const Vector4 &vector ) const + { return Vector4(*this) -= vector; } + + template + inline Vector4 Vector4::operator - ( ) const + { return Vector4(-this->x, -this->y, -this->z, -this->w); } + + template + bool Vector4::operator == ( const Vector4 &vector ) const + { + if( this->x != vector.x ) return false; + if( this->y != vector.y ) return false; + if( this->z != vector.z ) return false; + if( this->w != vector.w ) return false; + return true; + } + + template + bool Vector4::operator != ( const Vector4 &vector ) const + { + if( this->x != vector.x ) return true; + if( this->y != vector.y ) return true; + if( this->z != vector.z ) return true; + if( this->w != vector.w ) return true; + return false; + } + + template + inline ElementType Vector4::length( ) const + { return (ElementType) ::sqrt( this->dot(*this) ); } + + template + ElementType Vector4::dot( const Vector4 &vector ) const + { + ElementType value = 0; + for( int i = 0; i < 4; ++i ) + value += this->element[i] * vector.element[i]; + return value; + } + + template + inline Vector4 & Vector4::normalize( ) + { return (*this) /= this->length(); } + + template + inline Vector4 Vector4::getNormalized( ) const + { return Vector4(*this).normalize(); } +} + +#endif \ No newline at end of file diff --git a/Engine/Misc/Utilities.cpp b/Engine/Misc/Utilities.cpp new file mode 100644 index 00000000..c3046aeb --- /dev/null +++ b/Engine/Misc/Utilities.cpp @@ -0,0 +1,216 @@ +///////////////////////////////////////////////////////////////////// +// Utility Collection of Miscellanious Handy Functions +// © Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#include "Utilities.h" +#include +#include + +using ::std::vector; +using ::std::string; + +namespace Utility +{ +// PRIVATE STATIC //////////////////////////////////////////////////// + namespace PrivateStatic + { + const ::std::locale systemDefaultLocale = ::std::locale(); + } + +// STRING //////////////////////////////////////////////////////////// + namespace String + { + vector & split( vector &output, const string &str, char delim, string::size_type offset ) + { + if( str.length() > 0 ) + { + while( offset < str.length() ) // trim + { + if( str[offset] == delim ) + ++offset; + else break; + } + + string::size_type delimPos = str.find_first_of( delim, offset ); + if( delimPos == string::npos ) + { + if( str.length() > offset ) + output.push_back( str.substr( offset, str.length() - offset ) ); + } + else + { + if( delimPos > offset ) + output.push_back( str.substr( offset, delimPos - offset ) ); + String::split( output, str, delim, delimPos + 1 ); + } + } + return output; + } + + vector & split( vector &output, const string &str, const string &delim, string::size_type offset ) + { + if( str.length() > 0 ) + { + string::size_type delimPos = str.find_first_of( delim, offset ); + if( delimPos == string::npos ) + { + if( str.length() > offset ) + output.push_back( str.substr( offset, str.length() - offset ) ); + } + else + { + if( delimPos > offset ) + output.push_back( str.substr( offset, delimPos - offset ) ); + String::split( output, str, delim, delimPos + delim.length() ); + } + } + return output; + } + + vector & split( vector &output, const string &str, const vector &delim, string::size_type offset ) + { + if( str.length() > 0 ) + { + string::size_type firstDelimPos = str.length(), delimPos; + + vector::size_type numDelims = delim.size(), delimRef = 0; + for( vector::size_type i = 0; i < numDelims ; ++i ) + { + delimPos = str.find_first_of( delim[i], offset ); + if( delimPos != string::npos ) if( delimPos < firstDelimPos ) + { + delimRef = i; + firstDelimPos = delimPos; + } + } + + if( firstDelimPos == str.length() ) + { + if( str.length() > offset ) + output.push_back( str.substr( offset, str.length() - offset ) ); + } + else + { + if( firstDelimPos > offset ) + output.push_back( str.substr( offset, firstDelimPos - offset ) ); + String::split( output, str, delim, firstDelimPos + delim[delimRef].length() ); + } + } + return output; + } + + string trim( const string &str ) + { + string::size_type first = 0, + last = str.length(); + + if( last == 0 ) return str; + + while( first < last ) + { + if( str[first] == ' ' || str[first] == '\t' || str[first] == '\r' || str[first] == '\n' ) + ++first; + else break; + } + + --last; + while( last > first ) + { + if( str[last] == ' ' || str[last] == '\t' || str[last] == '\r' || str[last] == '\n' ) + --last; + else break; + } + + if( first == last ) if( str[first] == ' ' || str[first] == '\t' || str[first] == '\r' || str[first] == '\n' ) + return ""; + + return str.substr( first, (++last) - first ); + } + + string & toLowerCase( string &output, const string &str ) + { + int length = (int)str.length(); + output.resize( length ); + for( int i = 0; i < length; ++i ) + output[i] = ::std::tolower( str[i], ::std::locale() ); + return output; + } + + string & toLowerCase( string &str ) + { + int length = (int)str.length(); + for( int i = 0; i < length; ++i ) + str[i] = ::std::tolower( str[i], ::std::locale() ); + return str; + } + + string & toUpperCase( string &output, const string &str ) + { + int length = (int)str.length(); + output.resize( length ); + for( int i = 0; i < length; ++i ) + output[i] = ::std::toupper( str[i], ::std::locale() ); + return output; + } + + string & toUpperCase( string &str ) + { + int length = (int)str.length(); + for( int i = 0; i < length; ++i ) + str[i] = ::std::toupper( str[i], ::std::locale() ); + return str; + } + + string & extractDirPath( string &output, const string &file, char dirDelimeter ) + { + string d = " "; + d[0] = dirDelimeter; + return String::extractDirPath( output, file, d ); + } + + string & extractDirPath( string &output, const string &file, const string &dirDelimeter ) + { + string::size_type end = file.find_last_of( dirDelimeter ); + if( end == string::npos ) + output = ""; + else + { + ++end; + output.resize( end ); + for( string::size_type i = 0; i < end; ++i ) + output[i] = file[i]; + } + + return output; + } + + string & replaceCharacters( string &str, char characterToReplace, char newCharacter, const string::size_type &offset, const string::size_type &end ) + { + string::size_type i = offset; + while( true ) + { + i = str.find_first_of( characterToReplace, i ); + if( i >= end ) break; + + str[i++] = newCharacter; + } + return str; + } + } + + // STREAM //////////////////////////////////////////////////////////// + namespace Stream + { + float* readFloats( float *output, ::std::istream &input, unsigned int numFloats ) + { + string str; + for( unsigned int i = 0; i < numFloats; ++i ) + { + input >> str; + output[i] = (float)::std::atof( str.c_str() ); + } + return output; + } + } +} \ No newline at end of file diff --git a/Engine/Misc/Utilities.h b/Engine/Misc/Utilities.h new file mode 100644 index 00000000..aa9128c3 --- /dev/null +++ b/Engine/Misc/Utilities.h @@ -0,0 +1,80 @@ +///////////////////////////////////////////////////////////////////// +// Utility Collection of Miscellanious Handy Functions +// © Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef UTILITIES_H +#define UTILITIES_H + +#include +#include +#include +#include + +namespace Utility +{ + namespace String + { + // note to self: add a whitespaceSplit method? + ::std::vector<::std::string> & split( ::std::vector<::std::string> &output, const ::std::string &str, char delim, ::std::string::size_type offset = 0 ); + ::std::vector<::std::string> & split( ::std::vector<::std::string> &output, const ::std::string &str, const ::std::string &delim, ::std::string::size_type offset = 0 ); + ::std::vector<::std::string> & split( ::std::vector<::std::string> &output, const ::std::string &str, const ::std::vector<::std::string> &delim, ::std::string::size_type offset = 0 ); + ::std::string trim( const ::std::string &str ); + ::std::string & toLowerCase( ::std::string &output, const ::std::string &str ); + ::std::string & toLowerCase( ::std::string &str ); + ::std::string & toUpperCase( ::std::string &output, const ::std::string &str ); + ::std::string & toUpperCase( ::std::string &str ); + ::std::string & extractDirPath( ::std::string &output, const ::std::string &file, char dirDelimeter ); + ::std::string & extractDirPath( ::std::string &output, const ::std::string &file, const ::std::string &dirDelimeter ); + ::std::string & replaceCharacters( ::std::string &str, char characterToReplace, char newCharacter, const ::std::string::size_type &offset = 0, const ::std::string::size_type &end = ::std::string::npos ); + } + + namespace Stream + { + float* readFloats( float *output, ::std::istream &input, unsigned int numFloats ); + } + + namespace StaticArray + { + template + inline unsigned int numElementsOf( const ElementType(&)[num] ) + { return num; } + } + + namespace Element + { + template + inline void swap( ElementType &elementA, ElementType &elementB, ElementType &swapSpace ) + { swapSpace = elementA; elementA = elementB; elementB = swapSpace; } + + template + inline void swap( ElementType &elementA, ElementType &elementB ) + { ElementType swapSpace; swap( elementA, elementB, swapSpace ); } + } + + namespace Value + { + template + inline ValueType abs( const ValueType &value ) + { return value < 0 ? value * -1 : value; } + + template + inline ValueType max( const ValueType &valueA, const ValueType &valueB ) + { return valueA > valueB ? valueA : valueB; } + + template + inline ValueType min( const ValueType &valueA, const ValueType &valueB ) + { return valueA < valueB ? valueA : valueB; } + + template + inline ValueType radian( const ValueType °ree ) + { return degree * (3.1415926535897932384626433832795f / 180.0f); } + + template + inline ValueType degree( const ValueType &radian ) + { return radian * (180.0f / 3.1415926535897932384626433832795f); } + } +} + +#endif \ No newline at end of file diff --git a/Engine/Misc/WinTimer.cpp b/Engine/Misc/WinTimer.cpp new file mode 100644 index 00000000..d8ccfbb2 --- /dev/null +++ b/Engine/Misc/WinTimer.cpp @@ -0,0 +1,75 @@ +#include "WinTimer.h" + +using namespace ::Utility; + +namespace PrivateStatic +{ + LARGE_INTEGER ticksPerSecond = { 0 }; + double secondsPerTick = 0.0f; + + class WatchDog + { + public: + WatchDog( ) + { + if( QueryPerformanceFrequency( &ticksPerSecond ) > 0 ) + secondsPerTick = ((double)1.0f) / (double) ticksPerSecond.QuadPart; + } + } watchDog; +} + +WinTimer::WinTimer( ) : isPaused(false) +{ this->reset(); } + +void WinTimer::reset( ) +{ + this->isPaused = false; + this->pauseCount.QuadPart = 0; + QueryPerformanceCounter( &this->startTick ); +} + +void WinTimer::pause( ) +{ + if( !this->isPaused ) + { + this->isPaused = true; + QueryPerformanceCounter( &this->pauseStart ); + } +} + +void WinTimer::resume( ) +{ + if( this->isPaused ) + { + this->isPaused = false; + LARGE_INTEGER currentTick; + QueryPerformanceCounter( ¤tTick ); + this->pauseCount.QuadPart += currentTick.QuadPart - this->pauseStart.QuadPart; + } +} + +double WinTimer::getElapsedSeconds( ) const +{ + if( this->isPaused ) + { + LARGE_INTEGER totalTick = this->pauseStart; + totalTick.QuadPart -= this->startTick.QuadPart; + totalTick.QuadPart -= this->pauseCount.QuadPart; + return PrivateStatic::secondsPerTick * (double)totalTick.QuadPart; + } + else + { + LARGE_INTEGER currentTick; + QueryPerformanceCounter( ¤tTick ); + currentTick.QuadPart -= this->startTick.QuadPart; + currentTick.QuadPart -= this->pauseCount.QuadPart; + return PrivateStatic::secondsPerTick * (double)currentTick.QuadPart; + } +} + +LARGE_INTEGER WinTimer::getCurrentTick( ) const +{ + LARGE_INTEGER currentTick; + QueryPerformanceCounter( ¤tTick ); + return currentTick; +} \ No newline at end of file diff --git a/Engine/Misc/WinTimer.h b/Engine/Misc/WinTimer.h new file mode 100644 index 00000000..73e9091f --- /dev/null +++ b/Engine/Misc/WinTimer.h @@ -0,0 +1,32 @@ +///////////////////////////////////////////////////////////////////// +// Instanciable Timer class for windows +// © Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef WINTIMER_H +#define WINTIMER_H + +#include + +namespace Utility +{ + class WinTimer + { + public: + WinTimer( ); + + void reset( ); + void pause( ); + void resume( ); + + double getElapsedSeconds( ) const; + LARGE_INTEGER getCurrentTick( ) const; + + private: + LARGE_INTEGER startTick, pauseStart, pauseCount; + bool isPaused; + }; +} + +#endif \ No newline at end of file diff --git a/Engine/Render/Camera.cpp b/Engine/Render/Camera.cpp new file mode 100644 index 00000000..19f85136 --- /dev/null +++ b/Engine/Render/Camera.cpp @@ -0,0 +1,157 @@ +#include "Camera.h" +//Hack: temp include, calc proj matrix properly later +#include "..\Core\CoreIncludes.h" + +using namespace Oyster; +using namespace Render; +using namespace Oyster::Math; +Camera::Camera(void) +{ +} + + +Camera::~Camera(void) +{ +} + +Math::Float3 Camera::GetPosition() {return pos;} +void Camera::SetPosition(Math::Float3 p){ pos=p;} + +//axis +Math::Float3 Camera::GetRight() {return right;} +Math::Float3 Camera::GetUp() {return up;} +Math::Float3 Camera::GetLook() {return look;} + +//frustrum +float Camera::GetNearZ(){return nearZ;} +float Camera::GetFarZ(){return farZ;} +float Camera::GetAspect(){return aspect;} +float Camera::GetFovY(){return fovY;} +float Camera::GetFovX(){return fovX;} + +//set frustrum +void Camera::SetLens(float fovY, float aspect, float zn, float zf) +{ + this->fovY=fovY; + this->aspect=aspect; + nearZ=zn; + farZ=zf; + D3DXMATRIX P; + D3DXMatrixPerspectiveFovLH(&P,fovY,aspect,zn,zf); + mProj = Math::Float4x4(P); +} + +//normal LookAt +void Camera::LookAt(Math::Float3 pos, Math::Float3 target, Math::Float3 worldUp) +{ + look=target; + up=worldUp; + this->pos=pos; + right = up.cross(look); +} + +//Get Matrices +Matrix Camera::View(){return mView;} +Matrix Camera::Proj(){return mProj;} +Matrix Camera::ViewProj() +{ + return (mView * mProj).transpose(); // edited by Dan 04-19 +} + +//Move Camera +//FIX: Multiply Add not working +//FIX: Single Float Duplicate Creation +void Camera::Strafe(float d) +{ + Math::Float3 s= Math::Float3(d,d,d); + pos= (Math::operator*(s,right)) + pos; +} +void Camera::Walk(float d) +{ + Math::Float3 s= Math::Float3(d,d,d); + pos= (Math::operator*(s,look)) + pos; +} +void Camera::Fly(float d) +{ + Math::Float3 s= Math::Float3(d,d,d); + pos= (Math::operator*(s,up)) + pos; +} + +//Rotate Camera +//FIX: Float3 * float4x4 +void Camera::Pitch(float angle) +{ + Matrix m; + Math::rotationMatrix(m,angle,right); + m = m.getAdjoint().getInverse(); + + up = (Math::Float4(up,0) * m).xyz; + look = (Math::Float4(look,0) * m).xyz; +} +void Camera::Yaw(float angle) +{ + + Matrix m; + Math::rotationMatrix(m,angle,up); + m = m.getAdjoint().getInverse(); + + right = (Math::Float4(right,0) * m).xyz; + look = (Math::Float4(look,0) * m).xyz; +} +void Camera::Roll(float angle) +{ + Matrix m; + Math::rotationMatrix(m, angle,look); + m = m.getAdjoint().getInverse(); + + up = (Math::Float4(up,0) * m).xyz; + right = (Math::Float4(right,0) * m).xyz; +} +void Camera::RotateY(float angle) +{ + Matrix m; + + Math::rotationMatrix_AxisY(m, angle); + + m = m.getAdjoint().getInverse(); + + up = (Math::Float4(up,0) * m).xyz; + look = (Math::Float4(look,0) * m).xyz; + right = (Math::Float4(right,0) * m).xyz; +} + +void Camera::UpdateViewMatrix() +{ + look.normalize(); + + up = look.cross(right); + up.normalize(); + + right = up.cross(look); + + float x = -pos.dot(right); + float y = -pos.dot(up); + float z = -pos.dot(look); + + mView.m[0][0] = right.x; + mView.m[1][0] = right.y; + mView.m[2][0] = right.z; + mView.m[3][0] = x; + + mView.m[0][1] = up.x; + mView.m[1][1] = up.y; + mView.m[2][1] = up.z; + mView.m[3][1] = y; + + mView.m[0][2] = look.x; + mView.m[1][2] = look.y; + mView.m[2][2] = look.z; + mView.m[3][2] = z; + + mView.m[0][3] = 0.0f; + mView.m[1][3] = 0.0f; + mView.m[2][3] = 0.0f; + mView.m[3][3] = 1.0f; +} + + diff --git a/Engine/Render/Camera.h b/Engine/Render/Camera.h new file mode 100644 index 00000000..cc558144 --- /dev/null +++ b/Engine/Render/Camera.h @@ -0,0 +1,61 @@ +#pragma once + +#include "..\Math\OysterMath.h" + +namespace Oyster +{ + namespace Render + { + class Camera + { + public: + Camera(void); + ~Camera(void); + + //position + Math::Float3 GetPosition(); + void SetPosition(Math::Float3); + + //axis + Math::Float3 GetRight(); + Math::Float3 GetUp(); + Math::Float3 GetLook(); + + //frustrum + float GetNearZ(); + float GetFarZ(); + float GetAspect(); + float GetFovY(); + float GetFovX(); + + //set frustrum + void SetLens(float fovY, float aspect, float zn, float zf); + + //normal LookAt + void LookAt(Math::Float3 pos, Math::Float3 target, Math::Float3 worldUp); + + //Get Matrices + Math::Matrix View(); + Math::Matrix Proj(); + Math::Matrix ViewProj(); + + //Move Camera + void Strafe(float d); + void Walk(float d); + void Fly(float d); + + //Rotate Camera + void Pitch(float angle); + void Yaw(float angle); + void Roll(float angle); + void RotateY(float angle); + + void UpdateViewMatrix(); + + private: + Math::Vector3 pos, right, up, look; + float nearZ,farZ,aspect,fovX,fovY; + Math::Matrix mView, mProj; + }; + } +} diff --git a/Engine/Render/Lights.h b/Engine/Render/Lights.h new file mode 100644 index 00000000..78c70838 --- /dev/null +++ b/Engine/Render/Lights.h @@ -0,0 +1,8 @@ +#pragma once +#include "Engine\Math\OysterMath.h" + +struct DirectionalLight +{ + Oyster::Math::Float4 Irradiance; + Oyster::Math::Float4 Direction; +}; \ No newline at end of file diff --git a/Engine/Render/Model.cpp b/Engine/Render/Model.cpp new file mode 100644 index 00000000..e69de29b diff --git a/Engine/Render/Model.h b/Engine/Render/Model.h new file mode 100644 index 00000000..c6f59050 --- /dev/null +++ b/Engine/Render/Model.h @@ -0,0 +1,32 @@ +#pragma once +#ifndef Mesh_h +#define Mesh_h + +//#include "../Engine.h" + + +//#include "..\Core\CoreIncludes.h" +//#include "..\Core\Buffer.h" +#include "OysterMath.h" +//#include "ICollideable.h" +#include "ModelInfo.h" + +using namespace Oyster::Math; + +namespace Oyster +{ + namespace Render + { + + struct Model + { + ModelInfo* info; + Float4x4 *World; + bool Visible; + }; + + + }; +}; + +#endif \ No newline at end of file diff --git a/Engine/Render/ModelInfo.h b/Engine/Render/ModelInfo.h new file mode 100644 index 00000000..a4702ca1 --- /dev/null +++ b/Engine/Render/ModelInfo.h @@ -0,0 +1,29 @@ +#pragma once +#ifndef MODELINFO_h +#define MODELINFO_h + +//#include "../Engine.h" + + +#include "..\Core\CoreIncludes.h" +#include "..\Core\Buffer.h" +//#include "OysterMath.h" +//#include "ICollideable.h" + +using namespace Oyster::Math; + +namespace Oyster +{ + namespace Render + { + struct ModelInfo + { + std::vector Material; + Oyster::Buffer Vertices,Indecies; + bool Indexed; + int VertexCount; + }; + }; +}; + +#endif \ No newline at end of file diff --git a/Engine/Render/TextBox.cpp b/Engine/Render/TextBox.cpp new file mode 100644 index 00000000..1cd162c6 --- /dev/null +++ b/Engine/Render/TextBox.cpp @@ -0,0 +1,165 @@ +#include "Textbox.h" +using namespace Oyster::Render; + +//int Textbox::NumTextfields=0; +Oyster::Buffer Textbox::TextBuffer; +int Textbox::NumLetters; +//std::vector Textbox::TextInstances; +ID3D11ShaderResourceView* Textbox::Texture=NULL; +bool Textbox::Init() +{ + //NumTextfields = 0; + //NumVertices = 0; + //HRESULT test=HRESULT_FAI + if(FAILED(CreateVertexBuffer())) + { + return false; + } + //update(_str, _pos); + return true; + //return true; +} +bool Textbox::SetTexture(const char* _file) +{ + if(FAILED(D3DX11CreateShaderResourceViewFromFileA(Oyster::Core::Device, _file, NULL, NULL, &Texture, NULL))) + { + return false; + } + return true; +} +bool Textbox::UpdateTextField(std::string _str) +{ + //DEPRECATED + //Update(_str); + return false; + /*UINT _id=TextInstances.size(); + //TextInstances.resize(_id+1); + Text2D newD; + TextInstances.push_back(newD); + if(FAILED(CreateTextfield(_id))) + { + return false; + } + Update(_id, _str, _pos); + TextInstances[_id].Visible=true; + TextInstances[_id].World=Float4x4::identity; + NumTextfields++; + return true;*/ +} + +HRESULT Textbox::CreateVertexBuffer() +{ + HRESULT result; + //Create vertices + /* + std::vector mVertices; + mVertices.resize(4); + D3DXVECTOR3 testloc=D3DXVECTOR3(0,0,0); + mVertices[0].pos = testloc+D3DXVECTOR3(0.0f, 0.0f, 0.0f); + mVertices[1].pos = testloc+D3DXVECTOR3(TEXT_SIZE, 0.0f, 0.0f); + mVertices[2].pos = testloc+D3DXVECTOR3(0.0f, TEXT_SIZE, 0.0f); + mVertices[3].pos = testloc+D3DXVECTOR3(TEXT_SIZE, TEXT_SIZE, 0.0f); + float normaloffset=(1.0f/TEXT_NR_LETTERS); + mVertices[0].uv=D3DXVECTOR2(normaloffset,1); + mVertices[1].uv=D3DXVECTOR2(0,1); + mVertices[2].uv=D3DXVECTOR2(normaloffset,0); + mVertices[3].uv=D3DXVECTOR2(0,0); + */ + + //Oyster::Buffer::BUFFER_INIT_DESC desc; + //desc.ElementSize=sizeof(TextData); + //desc.NumElements = mVertices.size(); + //desc.Type = Oyster::Buffer::BUFFER_TYPE::VERTEX_BUFFER; + //desc.Usage = Oyster::Buffer::BUFFER_USAGE::BUFFER_DEFAULT; + //desc.InitData = &mVertices[0]; + + //result=TextBuffer.Init(desc); + //NumVertices=mVertices.size(); + //TextInstances[_id].NumLetters=0; + /*Text2D tmp; + tmp.coff=0; + tmp.offset=0; + tmp.Pos=Float2(0,0);*/ + Oyster::Buffer::BUFFER_INIT_DESC desc; + desc.ElementSize=sizeof(Text2D); + desc.NumElements = MAX_LETTER_COUNT; + desc.Type = Oyster::Buffer::BUFFER_TYPE::VERTEX_BUFFER; + desc.Usage = Oyster::Buffer::BUFFER_USAGE::BUFFER_CPU_WRITE_DISCARD; + desc.InitData = 0; + result=TextBuffer.Init(desc); + NumLetters=0; + return result; +} +HRESULT Textbox::CreateTextfield(int _id) +{ + HRESULT result=E_FAIL; + /*if (TextInstances.size()>_id) + { + TextInstances[_id].NumLetters=0; + + Oyster::Buffer::BUFFER_INIT_DESC desc; + desc.ElementSize=sizeof(Text2D); + desc.NumElements = MAX_LETTER_COUNT; + desc.Type = Oyster::Buffer::BUFFER_TYPE::VERTEX_BUFFER; + desc.Usage = Oyster::Buffer::BUFFER_USAGE::BUFFER_CPU_WRITE_DISCARD; + desc.InitData = 0; + + result=TextInstances[_id].InstanceBuffer.Init(desc); + }*/ + return result; +} +void Textbox::Update(std::string _str, float _xscale) +{ + UINT instances=0; + Text2D tmpInst; + + void* dest = TextBuffer.Map(); + Text2D* dataView = reinterpret_cast(dest); + //tmpInst.charOffset=_pos; + for (unsigned int i=0; i<_str.length(); i++) + { + tmpInst.coff=(1.0f/TEXT_NR_LETTERS); + tmpInst.offset=(_str[i]-32); + tmpInst.Pos=i*(0.005f*_xscale); + //float tst=getCharID(_str[i]); + //tmpInst.offset=tst; + //tmpInst.charOffset.x=_pos.x-i*TEXT_SIZE; + //tmpInst.data=tst; + dataView[instances]=tmpInst; + instances++; + } + NumLetters=instances; + //TextInstances[_id].NumLetters=instances; + TextBuffer.Unmap(); +} +float Textbox::getCharID(char _in) +{ + //int charid=_in; + //float charid=((_in-'0')-32); + return ((_in-32)*(1.0f/TEXT_NR_LETTERS)); + //return _in-'0'; +} +void Textbox::Apply(int _id) +{ + //Check if the subset exists, so we don't try to pain something that isn't there resulting in a crash + //if (NumTextfields>_id) + //{ + //Oyster::Core::DeviceContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + //Set the size of each vertex "jump", and the start point for the shader + //unsigned int strides[2]; + //offsets start at 0. + //unsigned int offsets[2]={0,0}; + + //Load the strides with the size of each type + //strides[0] = sizeof(TextData); + //strides[1] = sizeof(PerCharData); + + //Create an array which points to the buffers needed. + //ID3D11Buffer* bufferPointers[2]; + //bufferPointers[0] = TextBuffer; + //bufferPointers[1] = TextInstances[_id].InstanceBuffer; + //Load the vertex buffer into the shader + //Oyster::Core::DeviceContext->IASetVertexBuffers(0, 2, bufferPointers, strides, offsets); + //Get the basic info of the technique that's loaded + //} +} \ No newline at end of file diff --git a/Engine/Render/TextBox.h b/Engine/Render/TextBox.h new file mode 100644 index 00000000..633d0366 --- /dev/null +++ b/Engine/Render/TextBox.h @@ -0,0 +1,67 @@ +#pragma once + +#include "..\Engine.h" +const int MAX_LETTER_COUNT=60; +const int TEXT_NR_LETTERS=95; +const float TEXT_SIZE=2.5; +struct Text2D +{ + Oyster::Math::Float Pos; + int offset; + float coff; +}; +/*struct TextInstanceData +{ + Oyster::Buffer InstanceBuffer; + bool Visible; + int NumLetters; + Oyster::Math::Float4x4 World; +};*/ +/*struct TextData +{ + Oyster::Math::Float3 pos; + Oyster::Math::Float2 uv; +}; + +struct PerCharData +{ + float data; + Oyster::Math::Float3 charOffset; +}; +struct TextInstanceData +{ + Oyster::Buffer InstanceBuffer; + bool Visible; + int NumLetters; + Oyster::Math::Float4x4 World; +};*/ + +namespace Oyster +{ + namespace Render + { + class Textbox + { + private: + static float getCharID(char _in); + static HRESULT CreateVertexBuffer(); + static HRESULT CreateTextfield(int _id); + public: + //static Oyster::Buffer TextBuffer; + //static int NumVertices; + //static std::vector TextInstances; + static Oyster::Buffer TextBuffer; + static int NumLetters; + static ID3D11ShaderResourceView* Texture; + + static bool Init(); + static bool UpdateTextField(std::string _str); + static bool SetTexture(const char* _file); + //Updates a textbox with the certain id + static void Update(std::string _str, float _scale); + //Removes all old instances and recreates it with the input data + static HRESULT Reset(int _count, std::string* _str, Float3* _pos); + static void Apply(int _id); + }; + } +} diff --git a/Engine/Resourses/Buffers.cpp b/Engine/Resourses/Buffers.cpp new file mode 100644 index 00000000..e36b3790 --- /dev/null +++ b/Engine/Resourses/Buffers.cpp @@ -0,0 +1,44 @@ +#include "Buffers.h" + +namespace Oyster +{ + namespace Resources + { + Buffer Buffers::V2DSprites = Buffer(); + Buffer Buffers::CbufferVS = Buffer(); + Buffer Buffers::CBufferGs = Buffer(); + Buffer Buffers::CBufferPipelineCs = Buffer(); + + void Buffers::Init() + { + Buffer::BUFFER_INIT_DESC desc; + + desc.ElementSize=sizeof(Math::Float2); + desc.NumElements=1; + desc.Type = Buffer::BUFFER_TYPE::VERTEX_BUFFER; + desc.Usage = Buffer::BUFFER_USAGE::BUFFER_DEFAULT; + desc.InitData = &Math::Float2(0,0); + + V2DSprites.Init(desc); + + desc.Type=Buffer::BUFFER_TYPE::CONSTANT_BUFFER_VS; + desc.Usage = Buffer::BUFFER_USAGE::BUFFER_CPU_WRITE_DISCARD; + desc.ElementSize=sizeof(Math::Float4x4); + desc.InitData=0; + + CbufferVS.Init(desc); + + desc.Type = Buffer::BUFFER_TYPE::CONSTANT_BUFFER_GS; + + CBufferGs.Init(desc); + + desc.ElementSize=sizeof(Oyster::Resources::BufferDefinitions::LightStructureBuffer); + desc.NumElements=1; + desc.Type = Buffer::BUFFER_TYPE::CONSTANT_BUFFER_CS; + desc.Usage = Buffer::BUFFER_USAGE::BUFFER_CPU_WRITE_DISCARD; + desc.InitData = NULL; + + CBufferPipelineCs.Init(desc); + } + } +} \ No newline at end of file diff --git a/Engine/Resourses/Buffers.h b/Engine/Resourses/Buffers.h new file mode 100644 index 00000000..ec445b6c --- /dev/null +++ b/Engine/Resourses/Buffers.h @@ -0,0 +1,22 @@ +#pragma once + +#include "../EngineIncludes.h" + +namespace Oyster +{ + namespace Resources + { + struct Buffers + { + static Buffer V2DSprites; + + static Buffer CbufferVS; + + static Buffer CBufferGs; + + static Buffer CBufferPipelineCs; + + static void Init(); + }; + } +} \ No newline at end of file diff --git a/Engine/Resourses/GraphicsDefinitions.h b/Engine/Resourses/GraphicsDefinitions.h new file mode 100644 index 00000000..12a85d5f --- /dev/null +++ b/Engine/Resourses/GraphicsDefinitions.h @@ -0,0 +1,34 @@ +#pragma once + + +#include "..\EngineIncludes.h" + +namespace Oyster +{ + namespace Resources + { + + namespace BufferDefinitions + { + struct LightStructureBuffer + { + ::Oyster::Math::Float4x4 viewMatrix, projectionMatrix; + ::LinearAlgebra::Vector3 numDispatches; + unsigned int reservedPadding; + }; + + struct ScreenTileFrustrum + { + ::Oyster::Math::Float rawElement[6 * 4]; + }; + + class PointLightDescription + { + public: + struct{ ::Oyster::Math::Float3 center; ::Oyster::Math::Float radius; } pos; + ::Oyster::Math::Float3 color; + ::Oyster::Math::Float intensty; + }; + }; + } +} \ No newline at end of file diff --git a/Engine/Resourses/Manager.cpp b/Engine/Resourses/Manager.cpp new file mode 100644 index 00000000..c4132fba --- /dev/null +++ b/Engine/Resourses/Manager.cpp @@ -0,0 +1,47 @@ +#include "Manager.h" + +std::unordered_map< std::string, Oyster::Render::ModelInfo*> Oyster::Resources::Manager::loadedModels = std::unordered_map< std::string, Oyster::Render::ModelInfo*>(); + +Oyster::Render::Model* Oyster::Resources::Manager::LoadModel(std::string Filename, Matrix Scale) +{ + //TODO: Add redundncy sheck, to ensure not recreating model + + //Loop to find filename + + //If found Return Model + + //else Create Model + + Oyster::FileLoaders::ObjReader *reader = Oyster::FileLoaders::ObjReader::LoadFile(Filename, Scale); + Oyster::FileLoaders::ObjReader::Vertex** vertex = new Oyster::FileLoaders::ObjReader::Vertex*[1]; + int vcount; + std::map textures; + reader->GetVertexData( vertex, vcount, textures ); + + Oyster::Buffer::BUFFER_INIT_DESC desc; + desc.ElementSize=sizeof(Oyster::FileLoaders::ObjReader::Vertex); + desc.NumElements = vcount; + desc.InitData = *vertex; + desc.Type = Oyster::Buffer::VERTEX_BUFFER; + desc.Usage = Oyster::Buffer::BUFFER_DEFAULT; + + ID3D11ShaderResourceView *srv = textures["Diffuse"]; + + Oyster::Render::ModelInfo* m = new Oyster::Render::ModelInfo(); + + m->Vertices = *(Oyster::Engine::Init::Buffers::CreateBuffer(desc)); + m->VertexCount = vcount; + m->Material.push_back(srv); + srv = textures["Specular"]; + m->Material.push_back(srv); + srv = textures["Glow"]; + m->Material.push_back(srv); + m->Indexed=false; + + Oyster::Render::Model* model = new Oyster::Render::Model(); + model->info=m; + model->Visible = true; + model->World = &Oyster::Math::Float4x4(Oyster::Math::Float4x4::identity); + return model; +} + diff --git a/Engine/Resourses/Manager.h b/Engine/Resourses/Manager.h new file mode 100644 index 00000000..6de367e3 --- /dev/null +++ b/Engine/Resourses/Manager.h @@ -0,0 +1,20 @@ +#pragma once + +#include "../EngineIncludes.h" +#include + +namespace Oyster +{ + namespace Resources + { + struct Manager + { + //Expects to be deleted either trough manager or after a clean + static Oyster::Render::Model* LoadModel(std::string Filename, Matrix Scale); + static void Clean(); + + private: + static std::unordered_map< std::string, Oyster::Render::ModelInfo*> loadedModels; + }; + } +} \ No newline at end of file diff --git a/Engine/Resourses/PipelineResources.cpp b/Engine/Resourses/PipelineResources.cpp new file mode 100644 index 00000000..291c3c7c --- /dev/null +++ b/Engine/Resourses/PipelineResources.cpp @@ -0,0 +1,228 @@ +#include "PipelineResources.h" + +using namespace Oyster::Resources; + +ID3D11UnorderedAccessView* PipeLineResourses::TempUav = 0; +ID3D11ShaderResourceView* PipeLineResourses::TempSrv = 0; + +ID3D11ShaderResourceView* PipeLineResourses::GeometryOut[5] = {0}; +ID3D11RenderTargetView* PipeLineResourses::GeometryTarget[5] = {0}; + +ID3D11ShaderResourceView* PipeLineResourses::ComputeResources[4] = {0}; +Oyster::Buffer* PipeLineResourses::Resources[2] = {0}; + +ID3D11ShaderResourceView* PipeLineResourses::LightOut[4] = {0}; +ID3D11UnorderedAccessView* PipeLineResourses::LightTarget[4] = {0}; + +ID3D11RenderTargetView* PipeLineResourses::RtvNulls[16] = {0}; +ID3D11ShaderResourceView* PipeLineResourses::SrvNulls[16] = {0}; +ID3D11UnorderedAccessView* PipeLineResourses::uavNULL[16] = {0}; + +Oyster::Collision::Frustrum* PipeLineResourses::SubFrustrums = 0; +int PipeLineResourses::FrustrumSize = 0; +LinearAlgebra::Vector3 PipeLineResourses::FrustrumDimensions = LinearAlgebra::Vector3(); + +Oyster::Resources::BufferDefinitions::LightStructureBuffer PipeLineResourses::LightData = Oyster::Resources::BufferDefinitions::LightStructureBuffer(); + +void PipeLineResourses::Init() +{ + InitGeometry(); + + InitSSAOData(); + InitSubFrustrums(); + InitPointLights(); + InitLightData(); + + InitLighting(); +} + +void PipeLineResourses::InitGeometry() +{ + D3D11_TEXTURE2D_DESC Tdesc; + Tdesc.Width = Oyster::Window::Size.left; + Tdesc.Height = Oyster::Window::Size.bottom; + Tdesc.MipLevels = Tdesc.ArraySize = 1; + Tdesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; + Tdesc.SampleDesc.Count = 1; + Tdesc.SampleDesc.Quality=0; + Tdesc.Usage = D3D11_USAGE_DEFAULT; + Tdesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; + Tdesc.CPUAccessFlags = 0; + Tdesc.MiscFlags = 0; + + ID3D11Texture2D *pTexture; + HRESULT hr; + + //Geometry stage resourses + for( int i = 0; i < 5; ++i ) + { + hr = Oyster::Core::Device->CreateTexture2D( &Tdesc, NULL, &pTexture ); + hr = Oyster::Core::Device->CreateShaderResourceView(pTexture,0,&GeometryOut[i]); + hr = Oyster::Core::Device->CreateRenderTargetView(pTexture,0,&GeometryTarget[i]); + pTexture->Release(); + } +} + +void PipeLineResourses::InitSSAOData() +{ + //create Half Spheres and Random Data + + Oyster::Buffer::BUFFER_INIT_DESC desc; + HRESULT hr; + + int NrOfSamples = Oyster::Engine::States::GetNrOfSSAOSamples(); + int SampleSpread = Oyster::Engine::States::GetSSAOSampleSpread(); + + Oyster::Math::Vector3* kernel = new Oyster::Math::Vector3[ NrOfSamples ]; + Oyster::Math::Vector3* random = new Oyster::Math::Vector3[ SampleSpread ]; + + for(int i = 0; i < NrOfSamples; ++i) + { + kernel[i] = Oyster::Math::Vector3::null; + while( kernel[i] == Oyster::Math::Vector3::null ) + { + kernel[i] = Oyster::Math::Vector3( + (float)rand() / (RAND_MAX + 1) * (1 - -1) + -1, + (float)rand() / (RAND_MAX + 1) * (1 - -1) + -1, + (float)rand() / (RAND_MAX + 1) * (1 - 0) + 0); + } + kernel[i].normalize(); + + float scale = float(i) / float(NrOfSamples); + scale = (0.1f*(1 - scale * scale) + 1.0f *( scale * scale)); + kernel[i] *= scale; + + if( i < SampleSpread) + { + random[i] = Oyster::Math::Vector3::null; + while( random[i] == Oyster::Math::Vector3::null ) + { + random[i] = Oyster::Math::Vector3( + (float)rand() / (RAND_MAX + 1) * (1 - -1)+ -1, + (float)rand() / (RAND_MAX + 1) * (1 - -1)+ -1, + 0.0f); + } + random[i].normalize(); + } + } + + + D3D11_TEXTURE1D_DESC T1desc; + T1desc.Width = NrOfSamples; + T1desc.MipLevels = T1desc.ArraySize = 1; + T1desc.Format = DXGI_FORMAT_R32G32B32_FLOAT; + T1desc.Usage = D3D11_USAGE_DEFAULT; + T1desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + T1desc.CPUAccessFlags = 0; + T1desc.MiscFlags = 0; + + D3D11_SUBRESOURCE_DATA sphere; + sphere.pSysMem = kernel; + + D3D11_SUBRESOURCE_DATA rnd; + rnd.pSysMem = random; + + + ID3D11Texture1D *pTexture1[2]; + + hr = Oyster::Core::Device->CreateTexture1D( &T1desc, &sphere, &pTexture1[0] ); + hr = Oyster::Core::Device->CreateShaderResourceView( pTexture1[0], 0, &ComputeResources[3] ); + pTexture1[0]->Release(); + delete[] kernel; + + T1desc.Width = SampleSpread; + hr = Oyster::Core::Device->CreateTexture1D( &T1desc, &rnd, &pTexture1[1] ); + hr = Oyster::Core::Device->CreateShaderResourceView( (pTexture1[1]), 0, &ComputeResources[2] ); + pTexture1[1]->Release(); + delete[] random; +} + +void PipeLineResourses::InitSubFrustrums() +{ + FrustrumDimensions.x = (::Oyster::Window::Size.left + 15U) / 16U; + FrustrumDimensions.y = (::Oyster::Window::Size.bottom + 15U) / 16U; + FrustrumDimensions.z = 1; + FrustrumSize = FrustrumDimensions.x * FrustrumDimensions.y * FrustrumDimensions.z; + if(SubFrustrums!=0) + delete[] SubFrustrums; + SubFrustrums = new Frustrum[ FrustrumSize ]; + + Oyster::Buffer::BUFFER_INIT_DESC desc; + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + + //buffer description for SubFrustrums + desc.Usage = Oyster::Buffer::BUFFER_CPU_WRITE_DISCARD; + desc.Type = Oyster::Buffer::STRUCTURED_BUFFER; + desc.ElementSize = sizeof( ::Oyster::Resources::BufferDefinitions::ScreenTileFrustrum); + desc.NumElements = FrustrumSize; + desc.InitData = NULL; + + //create matching srv + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; + srvDesc.Format = DXGI_FORMAT_UNKNOWN; + srvDesc.Buffer.FirstElement = 0; + srvDesc.Buffer.NumElements = FrustrumSize; + + PipeLineResourses::Resources[0] = Oyster::Engine::Init::Buffers::CreateBuffer(desc); + + HRESULT hr = Oyster::Core::Device->CreateShaderResourceView( *PipeLineResourses::Resources[0], &srvDesc, &Oyster::Resources::PipeLineResourses::ComputeResources[0] ); +} + +void PipeLineResourses::InitPointLights() +{ + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + Oyster::Buffer::BUFFER_INIT_DESC desc; + HRESULT hr; + + //buffer description for pointlight + desc.Usage = Oyster::Buffer::BUFFER_CPU_WRITE_DISCARD; + desc.Type = Oyster::Buffer::STRUCTURED_BUFFER; + desc.ElementSize = sizeof(Oyster::Resources::BufferDefinitions::PointLightDescription); + desc.NumElements = Oyster::Engine::States::GetMaxPointlights(); + desc.InitData = NULL; + + PipeLineResourses::Resources[1] = Oyster::Engine::Init::Buffers::CreateBuffer(desc); + + //create matching srv + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; + srvDesc.Format = DXGI_FORMAT_UNKNOWN; + srvDesc.Buffer.FirstElement = 0; + srvDesc.Buffer.NumElements = Oyster::Engine::States::GetMaxPointlights(); + + hr = Oyster::Core::Device->CreateShaderResourceView( *PipeLineResourses::Resources[1], &srvDesc, &Oyster::Resources::PipeLineResourses::ComputeResources[1] ); +} + +void PipeLineResourses::InitLightData() +{ + LightData.numDispatches = FrustrumDimensions; +} + +void PipeLineResourses::InitLighting() +{ + D3D11_TEXTURE2D_DESC Tdesc; + Tdesc.Width = Oyster::Window::Size.left; + Tdesc.Height = Oyster::Window::Size.bottom; + Tdesc.MipLevels = Tdesc.ArraySize = 1; + Tdesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; + Tdesc.SampleDesc.Count = 1; + Tdesc.SampleDesc.Quality=0; + Tdesc.Usage = D3D11_USAGE_DEFAULT; + Tdesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS; + Tdesc.CPUAccessFlags = 0; + Tdesc.MiscFlags = 0; + + ID3D11Texture2D *pTexture; + HRESULT hr; + for(int i = 0; i < 4; ++i ) + { + hr = Oyster::Core::Device->CreateTexture2D( &Tdesc, NULL, &pTexture ); + hr = Oyster::Core::Device->CreateShaderResourceView( pTexture, 0, &(LightOut[i]) ); + hr = Oyster::Core::Device->CreateUnorderedAccessView( pTexture, 0, &(LightTarget[i]) ); + pTexture->Release(); + } + + hr = Oyster::Core::Device->CreateTexture2D( &Tdesc, NULL, &pTexture ); + hr = Oyster::Core::Device->CreateShaderResourceView( pTexture, 0, &TempSrv ); + hr = Oyster::Core::Device->CreateUnorderedAccessView( pTexture, 0, &TempUav ); + pTexture->Release(); +} \ No newline at end of file diff --git a/Engine/Resourses/PipelineResources.h b/Engine/Resourses/PipelineResources.h new file mode 100644 index 00000000..b7f4a858 --- /dev/null +++ b/Engine/Resourses/PipelineResources.h @@ -0,0 +1,66 @@ +#pragma once + +#ifndef PipeLineResources_H +#define PipeLineResources_H + +#include "..\EngineIncludes.h" + +namespace Oyster +{ + namespace Resources + { + struct PipeLineResourses + { + //0 = Diffuse + //1 = Specular + //2 = Glow + //3 = Pos + //4 = Normal + static ID3D11ShaderResourceView* GeometryOut[5]; + static ID3D11RenderTargetView* GeometryTarget[5]; + + + //0 = TileBuffer + //1 = PointList + //2 = Random + //3 = Sphere + static ID3D11ShaderResourceView* ComputeResources[4]; + static Oyster::Buffer* Resources[2]; + + + //0 = Diffuse + //1 = Specular + //2 = Glow + //3 = SSAO + static ID3D11ShaderResourceView* LightOut[4]; + static ID3D11UnorderedAccessView* LightTarget[4]; + + //0 = BlurTempStorage + static ID3D11UnorderedAccessView* TempUav; + static ID3D11ShaderResourceView* TempSrv; + + static ID3D11RenderTargetView* RtvNulls[16]; + static ID3D11ShaderResourceView* SrvNulls[16]; + static ID3D11UnorderedAccessView* uavNULL[16]; + + static Oyster::Collision::Frustrum* SubFrustrums; + static int FrustrumSize; + static LinearAlgebra::Vector3 FrustrumDimensions; + + static Oyster::Resources::BufferDefinitions::LightStructureBuffer LightData; + + static void Init(); + + static void InitGeometry(); + + static void InitSSAOData(); + static void InitSubFrustrums(); + static void InitPointLights(); + static void InitLightData(); + + static void InitLighting(); + }; + } +} + +#endif \ No newline at end of file diff --git a/Engine/Resourses/ShaderEffects.cpp b/Engine/Resourses/ShaderEffects.cpp new file mode 100644 index 00000000..8e09956b --- /dev/null +++ b/Engine/Resourses/ShaderEffects.cpp @@ -0,0 +1,100 @@ +#include "ShaderEffects.h" + +namespace Oyster +{ + namespace Resources + { + Shader::ShaderEffect ShaderEffects::BasicSprite = Shader::ShaderEffect(); + Shader::ShaderEffect ShaderEffects::Text2DEffect = Shader::ShaderEffect(); + Shader::ShaderEffect ShaderEffects::ModelEffect = Shader::ShaderEffect(); + + void ShaderEffects::Init() + { + BasicSprite.IAStage.Topology = D3D11_PRIMITIVE_TOPOLOGY_POINTLIST; + BasicSprite.Shaders.Vertex = Oyster::Shader::Get::GetVertex("2D"); + BasicSprite.Shaders.Geometry = Oyster::Shader::Get::GetGeometry("2D"); + BasicSprite.Shaders.Pixel = Oyster::Shader::Get::GetPixel("Texture0"); + + D3D11_BLEND_DESC blendDesc; + blendDesc.AlphaToCoverageEnable=false; + blendDesc.IndependentBlendEnable=false; + blendDesc.RenderTarget[0].BlendEnable=true; + + blendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; + blendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; + blendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; + + blendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; + blendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ONE; + blendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_MAX; + + blendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + + ID3D11BlendState* blender; + + Oyster::Core::Device->CreateBlendState(&blendDesc,&blender); + + BasicSprite.RenderStates.BlendState = blender; + + ID3D11InputLayout* layout; + + Oyster::Shader::CreateInputLayout(SpriteVertexDesc,1,Oyster::Shader::Get::GetVertex("2D"),layout); + + BasicSprite.IAStage.Layout = layout; + + Text2DEffect.IAStage.Topology=D3D11_PRIMITIVE_TOPOLOGY_POINTLIST; + Text2DEffect.Shaders.Vertex = Oyster::Shader::Get::GetVertex("Text"); + Text2DEffect.Shaders.Geometry = Oyster::Shader::Get::GetGeometry("Text"); + Text2DEffect.Shaders.Pixel = Oyster::Shader::Get::GetPixel("Texture0"); + + Oyster::Shader::CreateInputLayout(Text2DDesc,3,Oyster::Shader::Get::GetVertex("Text"),layout); + + Text2DEffect.IAStage.Layout = layout; + + blendDesc.AlphaToCoverageEnable = true; + Oyster::Core::Device->CreateBlendState(&blendDesc,&blender); + Text2DEffect.RenderStates.BlendState = blender; + + ModelEffect.IAStage.Topology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST; + Oyster::Shader::CreateInputLayout(ModelDesc,3,Oyster::Shader::Get::GetVertex("OBJ"),layout); + ModelEffect.IAStage.Layout = layout; + + ModelEffect.Shaders.Vertex = Oyster::Shader::Get::GetVertex("OBJ"); + ModelEffect.Shaders.Pixel = Oyster::Shader::Get::GetPixel("OBJDEF"); + + Oyster::Buffer::BUFFER_INIT_DESC desc; + + desc.ElementSize=sizeof(Oyster::Math::Float4x4); + desc.NumElements = 1; + desc.Usage = Oyster::Buffer::BUFFER_CPU_WRITE_DISCARD; + desc.Type = Oyster::Buffer::CONSTANT_BUFFER_VS; + desc.InitData = NULL; + + ModelEffect.CBuffers.Vertex.push_back(Oyster::Engine::Init::Buffers::CreateBuffer(desc)); + ModelEffect.CBuffers.Vertex.push_back(Oyster::Engine::Init::Buffers::CreateBuffer(desc)); + + //use Oyster::Resources::Buffers::CbufferVS for per object data + //perObject = Oyster::Engine::Init::Buffers::CreateBuffer(desc); + + } + + D3D11_INPUT_ELEMENT_DESC ShaderEffects::SpriteVertexDesc[1] = + { + {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, + }; + + D3D11_INPUT_ELEMENT_DESC ShaderEffects::Text2DDesc[3] = + { + {"Position",0, DXGI_FORMAT_R32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"Offset",0, DXGI_FORMAT_R32_SINT, 0, 4, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"CharOffset",0, DXGI_FORMAT_R32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0}, + }; + + D3D11_INPUT_ELEMENT_DESC ShaderEffects::ModelDesc[3] = + { + {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0}, + }; + } +} \ No newline at end of file diff --git a/Engine/Resourses/ShaderEffects.h b/Engine/Resourses/ShaderEffects.h new file mode 100644 index 00000000..7377bb7f --- /dev/null +++ b/Engine/Resourses/ShaderEffects.h @@ -0,0 +1,23 @@ +#pragma once + +#include "../Engine.h" +#include "Buffers.h" + +namespace Oyster +{ + namespace Resources + { + struct ShaderEffects + { + static Oyster::Shader::ShaderEffect BasicSprite; + static Oyster::Shader::ShaderEffect Text2DEffect; + static Oyster::Shader::ShaderEffect ModelEffect; + + static void Init(); + + static D3D11_INPUT_ELEMENT_DESC SpriteVertexDesc[1]; + static D3D11_INPUT_ELEMENT_DESC Text2DDesc[3]; + static D3D11_INPUT_ELEMENT_DESC ModelDesc[3]; + }; + } +} \ No newline at end of file diff --git a/Engine/Shader/Shader.cpp b/Engine/Shader/Shader.cpp new file mode 100644 index 00000000..cc939e74 --- /dev/null +++ b/Engine/Shader/Shader.cpp @@ -0,0 +1,253 @@ +#include "Shader.h" +#include "../Core/Core.h" +#include "Utilities.h" +#include +#include +namespace Oyster +{ + namespace + { + std::vector PS; + std::map PSMap; + + std::vector GS; + std::map GSMap; + + std::vector CS; + std::map CSMap; + + std::vector VS; + std::vector VBlob; + std::map VSMap; + + std::stringstream log; + } + + bool Oyster::Shader::InitShaders(const std::string &name) + { + std::ifstream input; + input.open(name.c_str()); + std::string s, file,method; + std::vector line; + if(!input.is_open()) + return false; + while(!input.eof()) + { + getline(input,s); + line.clear(); + Utility::String::split(line,s,' '); + if(line.size()) + { + if(line[0]=="F") + { + file = line[1]; + } + if(line[0]=="P") + { + ID3D10Blob *Shader,*Error; + if(!PSMap.count(line[2])) + { + PSMap[line[2]]=(int)PS.size(); + ID3D11PixelShader* pixel; + if(FAILED(D3DX11CompileFromFileA(file.c_str(),NULL,NULL,line[1].c_str(),"ps_5_0",0,0,NULL,&Shader,&Error,NULL))) + { + std::string fel = (char*)Error->GetBufferPointer(); + PSMap.erase(line[2]); + Error->Release(); + return false; + } + if(FAILED(Oyster::Core::Device->CreatePixelShader(Shader->GetBufferPointer(),Shader->GetBufferSize(),NULL,&pixel))) + { + PSMap.erase(line[2]); + Error->Release(); + Shader->Release(); + return false; + } + Shader->Release(); + PS.push_back(pixel); + } + } + if(line[0]=="V") + { + ID3D10Blob *Shader,*Error; + if(!VSMap.count(line[2])) + { + int i = (int)VS.size(); + VSMap[line[2]]= i; + ID3D11VertexShader* vertex; + if(FAILED(D3DX11CompileFromFileA(file.c_str(),NULL,NULL,line[1].c_str(),"vs_5_0",0,0,NULL,&Shader,&Error,NULL))) + { + log //<< "Shader Compilation Warning(s)/Error(s)\n-----------------------------\n" + << (char*) Error->GetBufferPointer(); + // << "-----------------------------\n"; + s = log.str(); + VSMap.erase(line[2]); + Error->Release(); + return false; + } + if(FAILED(Oyster::Core::Device->CreateVertexShader + (Shader->GetBufferPointer(), + Shader->GetBufferSize(), + NULL, + &vertex))) + { + VSMap.erase(line[2]); + Error->Release(); + Shader->Release(); + return false; + } + VS.push_back(vertex); + VBlob.push_back(Shader); + } + } + if(line[0]=="G") + { + ID3D10Blob *Shader,*Error; + if(!GSMap.count(line[2])) + { + GSMap[line[2]]=(int)GS.size(); + ID3D11GeometryShader* pixel; + if(FAILED(D3DX11CompileFromFileA(file.c_str(),NULL,NULL,line[1].c_str(),"gs_5_0",0,0,NULL,&Shader,&Error,NULL))) + { + std::string fel = (char*)Error->GetBufferPointer(); + GSMap.erase(line[2]); + Error->Release(); + return false; + } + if(FAILED(Oyster::Core::Device->CreateGeometryShader(Shader->GetBufferPointer(),Shader->GetBufferSize(),NULL,&pixel))) + { + GSMap.erase(line[2]); + Error->Release(); + Shader->Release(); + return false; + } + Shader->Release(); + GS.push_back(pixel); + } + } + if(line[0]=="C") + { + ID3D10Blob *Shader,*Error; + if(!CSMap.count(line[2])) + { + CSMap[line[2]]=(int)CS.size(); + ID3D11ComputeShader* comp; + if(FAILED(D3DX11CompileFromFileA(file.c_str(),NULL,NULL,line[1].c_str(),"cs_5_0",0,0,NULL,&Shader,&Error,NULL))) + { + std::string fel = (char*)Error->GetBufferPointer(); + CSMap.erase(line[2]); + Error->Release(); + return false; + } + if(FAILED(Oyster::Core::Device->CreateComputeShader(Shader->GetBufferPointer(),Shader->GetBufferSize(),NULL,&comp))) + { + CSMap.erase(line[2]); + Error->Release(); + Shader->Release(); + return false; + } + Shader->Release(); + CS.push_back(comp); + } + } + } + } + return true; + } + + void Oyster::Shader::SetShaderEffect(ShaderEffect se) + { + Shader::Set::SetPixel(se.Shaders.Pixel); + Shader::Set::SetVertex(se.Shaders.Vertex); + Shader::Set::SetGeometry(se.Shaders.Geometry); + Shader::Set::SetCompute(se.Shaders.Compute); + Oyster::Core::DeviceContext->IASetInputLayout(se.IAStage.Layout); + Oyster::Core::DeviceContext->IASetPrimitiveTopology(se.IAStage.Topology); + for(unsigned int i=0;iApply(i); + for(unsigned int i=0;iApply(i); + for(unsigned int i=0;iApply(i); + Oyster::Core::DeviceContext->RSSetState(se.RenderStates.Rasterizer); + Oyster::Core::DeviceContext->PSSetSamplers(0,se.RenderStates.SampleCount,se.RenderStates.SampleState); + float test[4] = {0}; + Oyster::Core::DeviceContext->OMSetBlendState(se.RenderStates.BlendState,test,-1); + } + void Oyster::Shader::Set::SetPixel(int Index) + { + if(Index==-1) + Oyster::Core::DeviceContext->PSSetShader( NULL,NULL,0); + else + Oyster::Core::DeviceContext->PSSetShader( PS[Index],NULL,0); + } + void Oyster::Shader::Set::SetVertex(int Index) + { + if(Index==-1) + Oyster::Core::DeviceContext->VSSetShader(NULL,NULL,0); + else + Oyster::Core::DeviceContext->VSSetShader(VS[Index],NULL,0); + } + void Oyster::Shader::Set::SetGeometry(int Index) + { + if(Index==-1) + Oyster::Core::DeviceContext->GSSetShader(NULL,NULL,0); + else + Oyster::Core::DeviceContext->GSSetShader(GS[Index],NULL,0); + } + void Oyster::Shader::Set::SetCompute(int Index) + { + if(Index==-1) + Oyster::Core::DeviceContext->CSSetShader(NULL,NULL,0); + else + Oyster::Core::DeviceContext->CSSetShader(CS[Index],NULL,0); + } + void Oyster::Shader::Set::SetHull(int Index) + { + } + void Oyster::Shader::Set::SetDomain(int Index) + { + } + + int Oyster::Shader::Get::GetPixel(std::string Name) + { + if(PSMap.count(Name)) + return PSMap[Name]; + return -1; + } + int Oyster::Shader::Get::GetVertex(std::string Name) + { + if(VSMap.count(Name)) + return VSMap[Name]; + return -1; + } + int Oyster::Shader::Get::GetGeometry(std::string Name) + { + if(GSMap.count(Name)) + return GSMap[Name]; + return -1; + } + int Oyster::Shader::Get::GetCompute(std::string Name) + { + if(CSMap.count(Name)) + return CSMap[Name]; + return -1; + } + int Oyster::Shader::Get::GetHull(std::string Name) + { + return -1; + } + int Oyster::Shader::Get::GetDomain(std::string Name) + { + return -1; + } + void Oyster::Shader::CreateInputLayout(const D3D11_INPUT_ELEMENT_DESC *desc, int ElementCount,int VertexIndex,ID3D11InputLayout *&Layout) + { + if(VertexIndex==-1) + { + Layout=0; + return; + } + Oyster::Core::Device->CreateInputLayout(desc,ElementCount,VBlob[VertexIndex]->GetBufferPointer(),VBlob[VertexIndex]->GetBufferSize(),&Layout); + } +} \ No newline at end of file diff --git a/Engine/Shader/Shader.h b/Engine/Shader/Shader.h new file mode 100644 index 00000000..957d4314 --- /dev/null +++ b/Engine/Shader/Shader.h @@ -0,0 +1,78 @@ +#pragma once + +#include "..\Core\Buffer.h" + +namespace Oyster +{ + class Shader + { + public: + struct ShaderEffect + { + struct + { + int Pixel,Vertex,Geometry,Compute,Hull,Domain; + }Shaders; + struct IAStage_ + { + ID3D11InputLayout* Layout; + D3D11_PRIMITIVE_TOPOLOGY Topology; + }IAStage; + struct RenderStates_ + { + ID3D11DepthStencilState *DepthStencil; + ID3D11RasterizerState *Rasterizer; + ID3D11SamplerState **SampleState; + int SampleCount; + ID3D11BlendState *BlendState; + }RenderStates; + struct + { + std::vector Vertex; + std::vector Geometry; + std::vector Pixel; + }CBuffers; + ShaderEffect() + { + RenderStates.BlendState=NULL; + RenderStates.DepthStencil=NULL; + RenderStates.Rasterizer=NULL; + RenderStates.SampleState=NULL; + RenderStates.SampleCount=0; + Shaders.Compute=-1; + Shaders.Domain=-1; + Shaders.Geometry=-1; + Shaders.Hull=-1; + Shaders.Pixel=-1; + Shaders.Vertex=-1; + } + }; + static bool InitShaders(const std::string &name = "..\\Shaders\\ShaderConfig.txt"); + + static void SetShaderEffect(ShaderEffect); + + static void CreateInputLayout(const D3D11_INPUT_ELEMENT_DESC *desc, int ElementCount,int VertexIndex,ID3D11InputLayout *&Layout); + + struct Set + { + static void SetPixel(int Index); + static void SetVertex(int Index); + static void SetGeometry(int Index); + static void SetCompute(int Index); + static void SetHull(int Index); + static void SetDomain(int Index); + }; + + struct Get + { + static int GetPixel(std::string Name); + static int GetVertex(std::string Name); + static int GetGeometry(std::string Name); + static int GetCompute(std::string Name); + static int GetHull(std::string Name); + static int GetDomain(std::string Name); + }; + + static std::stringstream* AccesLog(); + }; +} \ No newline at end of file diff --git a/Engine/Window/Window.cpp b/Engine/Window/Window.cpp new file mode 100644 index 00000000..3ff58129 --- /dev/null +++ b/Engine/Window/Window.cpp @@ -0,0 +1,164 @@ +#include "Window.h" +#include + +using namespace Oyster; + +HWND Window::Handle = NULL; +std::stringstream Window::Log = std::stringstream(); +RECT Window::WindowRect = RECT(); +RECT Window::Size = RECT(); +RECT Window::ClientRect = RECT(); +WNDPROC Window::wndProc = NULL; +bool Window::isCaptured = false; +bool Window::shouldCapture = false; +int Window::OffsetMouseX=0; +int Window::OffsetMouseY=0; + +bool Window::init( const LPCSTR appName, const LPCSTR className, const HINSTANCE &hInstance, const int &nCmdShow, WNDPROC wProc, bool handleLoop ) +{ + if( Handle != NULL ) + { + Log<< "Faulty Init, First window Exists"; + return true; + } + + // Register window class + WNDCLASSEXA window = { 0 }; + window.cbSize = sizeof( WNDCLASSEXA ); + window.style = CS_HREDRAW | CS_VREDRAW; + window.lpfnWndProc = wProc; + if(handleLoop) + { + window.lpfnWndProc = Window::InputMethod; + Window::wndProc = wProc; + } + window.hInstance = hInstance; + window.hIcon = LoadIcon( NULL, IDI_APPLICATION ); + window.hCursor = LoadCursor( NULL, IDC_ARROW ); + window.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + window.lpszMenuName = NULL; + window.lpszClassName = className; + + if( !RegisterClassExA( &window ) ) + { + Log << "Failed to Register Window.\n"; + return false; + } + + Handle = CreateWindowEx( NULL, + className, + appName, + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, + CW_USEDEFAULT, + 800, //rc.right - rc.left, + 600, //rc.bottom - rc.top, + NULL, + NULL, + hInstance, + NULL ); + + if( Handle == NULL ) + { + Log << "Failed to Init Window.\n"; + return false; + } + WINDOWINFO wi; + wi.cbSize = sizeof(WINDOWINFO); + GetWindowInfo(Handle,&wi); + WindowRect = wi.rcClient; + Size.right = Size.left = WindowRect.right - WindowRect.left; + Size.top = Size.bottom = WindowRect.bottom - WindowRect.top; + ClientRect.left= ClientRect.top=0; + ClientRect.right = Size.left; + ClientRect.bottom = Size.top; + ShowWindow( Handle, nCmdShow ); + return true; +} + +void Window::deFocus( ) { SetFocus( GetDesktopWindow() ); } +bool Window::isInFocus( ) { return Handle == GetFocus( ); } +bool Window::mouseIsInWindow(POINT point ) +{ + return PtInRect( &WindowRect, point )!=0; +} + +LRESULT CALLBACK Window::InputMethod( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) +{ + switch (message) + { + + case WM_KEYDOWN: + Oyster::Input::Controller::KeyPressed(wParam); + break; + case WM_KEYUP: + Oyster::Input::Controller::KeyReleased(wParam); + break; + case WM_MOUSEMOVE: + if(!isCaptured) + if(shouldCapture) + SetCapture(Handle); + POINT pt; + pt.x = GET_X_LPARAM(lParam); + pt.y = GET_Y_LPARAM(lParam); + if(PtInRect(&ClientRect,pt)!=0) + Oyster::Input::Controller::MouseMove(GET_X_LPARAM(lParam)+OffsetMouseX,GET_Y_LPARAM(lParam)+OffsetMouseY); + else + { + if(shouldCapture) + { + pt.x = Input::Controller::GetX(); + pt.y = Input::Controller::GetY(); + ClientToScreen(Handle, &pt); + SetCursorPos(pt.x-OffsetMouseX,pt.y-OffsetMouseY); + } + } + break; + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_XBUTTONDOWN: + { + Oyster::Input::Controller::MouseBtnPressed(wParam); + break; + } + case WM_LBUTTONUP: + { + Oyster::Input::Controller::MouseBtnReleased(MK_LBUTTON); + break; + } + case WM_MBUTTONUP: + { + Oyster::Input::Controller::MouseBtnReleased(MK_MBUTTON); + break; + } + case WM_RBUTTONUP: + { + Oyster::Input::Controller::MouseBtnReleased(MK_RBUTTON); + break; + } + case WM_XBUTTONUP: + { + Oyster::Input::Controller::MouseBtnReleased(wParam); + break; + } + default: + return wndProc(hWnd, message, wParam, lParam); + } + + return 0; +} + +void Window::CaptureMouse(bool b) +{ + shouldCapture=b; + isCaptured=false; + if(!b) + SetCapture(NULL); +} + +void Window::SetMouseOffset(int x,int y) +{ + OffsetMouseX=x; + OffsetMouseY=y; +} \ No newline at end of file diff --git a/Engine/Window/Window.h b/Engine/Window/Window.h new file mode 100644 index 00000000..9ca7eb0b --- /dev/null +++ b/Engine/Window/Window.h @@ -0,0 +1,46 @@ +#pragma once + +#define NOMINMAX // Because I hate Microsoft now. ~Angry Dan. +// http://lolengine.net/blog/2011/3/4/fuck-you-microsoft-near-far-macros + +#include +#include +#include +#include "..\Input\InputController.h" + +namespace Oyster +{ + namespace Input + { + class Controller; + } + class Window + { + friend class ::Oyster::Input::Controller; + private: + Window(); + ~Window(); + static void CaptureMouse(bool b = true); + static bool shouldCapture; + static bool isCaptured; + static int OffsetMouseX; + static int OffsetMouseY; + public: + static bool init( const LPCSTR appName, const LPCSTR className, const HINSTANCE &hInstance,const int &nCmdShow, WNDPROC wProc, bool ManageWindow=false ); + + static void deFocus( ); + static bool isInFocus( ); + static bool mouseIsInWindow(POINT point ); + + static HWND Handle; + static std::stringstream Log; + static RECT WindowRect; + static RECT Size; + static RECT ClientRect; + static WNDPROC wndProc; + + static LRESULT CALLBACK InputMethod(HWND h,UINT i, WPARAM w,LPARAM l); + + static void SetMouseOffset(int x,int y); + }; +} \ No newline at end of file diff --git a/GameLogic/Bullet.cpp b/GameLogic/Bullet.cpp new file mode 100644 index 00000000..c6e4050a --- /dev/null +++ b/GameLogic/Bullet.cpp @@ -0,0 +1,154 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#include "OysterMath.h" +#include "Bullet.h" +#include "GameLUA.h" +#include "Event.h" +#include "Session.h" + +using namespace ::Oyster::Math; +using namespace ::Oyster::Collision; +using namespace ::GameLogic; + +namespace PrivateStatic +{ + // note current position is actually at the end of the lineOfEffect + inline void updatePosition( Ray &trail, const Float &distance ) + { trail.origin += trail.direction * distance; } + + inline Float3 posAt( const Ray &ray, const Float &distance ) + { return ray.origin + (ray.direction * distance); } +} + +Bullet::BulletCollector::BulletCollector( const Line *_sampler, int capacity ) + : EffectCarrier::Collector(capacity), sampler(_sampler), closest(::std::numeric_limits::max()) {} + +Bullet::BulletCollector::~BulletCollector( ) {} + +void Bullet::BulletCollector::action( Object *hitObject ) +{ + if( this->hitObjects.size() == 0 ) + { + this->closest = this->sampler->ray.collisionDistance; + this->hitObjects.push_back( hitObject ); + this->hitPosW.push_back( PrivateStatic::posAt(this->sampler->ray, this->sampler->ray.collisionDistance) ); + } + else if( this->closest > this->sampler->ray.collisionDistance ) + { + this->closest = this->sampler->ray.collisionDistance; + this->hitObjects.push_back( this->hitObjects[0] ); + this->hitPosW.push_back( this->hitPosW[0] ); + this->hitObjects[0] = hitObject; + this->hitPosW[0] = PrivateStatic::posAt( this->sampler->ray, this->sampler->ray.collisionDistance ); + } + else + { + this->hitObjects.push_back( hitObject ); + this->hitPosW.push_back( PrivateStatic::posAt(this->sampler->ray, this->sampler->ray.collisionDistance) ); + } +} + +Bullet::Bullet( Player *owner, const Float3 &origin, const Float3 &normalizedDirection, const Float &_speed, Weapon::Type weapon, const Float &lifeTime ) + : EffectCarrier(owner, weapon), lineOfEffect(origin, normalizedDirection, _speed), speed(_speed), lifeCountDown(lifeTime), modelID(-1) {} +Bullet::Bullet( const Bullet &bullet ) : EffectCarrier(bullet), lineOfEffect(bullet.lineOfEffect), speed(bullet.speed), lifeCountDown(bullet.lifeCountDown), modelID(bullet.modelID) {} +Bullet::~Bullet( ) {} + +Bullet & Bullet::operator = ( const Bullet &bullet ) +{ + EffectCarrier::operator=( bullet ); + this->lineOfEffect = bullet.lineOfEffect; + this->speed = bullet.speed; + this->lifeCountDown = bullet.lifeCountDown; + this->modelID = bullet.modelID; + return *this; +} + +void Bullet::setDirection( const Float3 &normalizedVector ) +{ this->lineOfEffect.ray.direction = normalizedVector; } + +void Bullet::setSpeed( const Float &coordLengthPerSecond ) +{ this->speed = coordLengthPerSecond; } + +void Bullet::setLifeTime( const Float &seconds ) +{ this->lifeCountDown = seconds; } + +void Bullet::setModelID( int ID ) +{ this->modelID = ID; } + +Float3 Bullet::getDirection() const +{ + return this->lineOfEffect.ray.direction; +} + +EffectCarrier::State Bullet::update( const Float &deltaTime ) +{ + switch( this->state ) + { + case Deployed: this->state = Armed; + default: case Armed: + if( (this->lifeCountDown -= deltaTime) <= 0.0f ) + { + this->state = Dead; + printf("gammal och gaggig\n"); + } + else + { + ::PrivateStatic::updatePosition( this->lineOfEffect.ray, this->lineOfEffect.length ); + this->lineOfEffect.length = this->speed * deltaTime; + } + case Dead: break; + }; + + return this->state; +} + +const ICollideable * Bullet::getVolumeOfEffect( ) const +{ return &this->lineOfEffect; } + +EffectCarrier * Bullet::clone( ) const +{ return new Bullet(*this); } + +EffectCarrier::Result Bullet::writeToKeyFrame( KeyFrame &buffer ) const +{ + if( buffer.numParticles < (int)::Utility::StaticArray::numElementsOf( buffer.Particle ) ) + { + if( this->modelID >= 0 ) if( this->state != Dead ) + { + buffer.Particle[buffer.numParticles].Head = this->lineOfEffect.ray.origin + (this->lineOfEffect.ray.direction * this->lineOfEffect.length); + buffer.Particle[buffer.numParticles].Tail = this->lineOfEffect.ray.origin; + buffer.Particle[buffer.numParticles].EffectType = this->modelID; + ++buffer.numParticles; + } + return Success; + } + return Failure; +} + +EffectCarrier::Result Bullet::writeToNetEffect( Network::EffectData &buffer ) const +{ + if( this->modelID >= 0 ) if( this->state != Dead ) + { + buffer.head = this->lineOfEffect.ray.origin + (this->lineOfEffect.ray.direction * /* this->lineOfEffect.length*/ 500); + buffer.tail = this->lineOfEffect.ray.origin; + buffer.identifier = 0; + return Success; + } + return Failure; +} + +using ::std::vector; +EffectCarrier::State Bullet::onHit( const vector &target, const vector &hitPosW ) +{ + this->state = Dead; + + //target[0]->applyDamage( 10, *this->owner ); + //target[0]->applyForceW( this->lineOfEffect.ray.direction * 100.0f, hitPosW[0] ); + + Player *owner = (Player *)this->owner; + Event::BulletHit *hitEvent = new Event::BulletHit(owner->getPlayerID(), ((Player *)target[0])->getPlayerID()/*, target[0]->getOrientation().v[3].xyz*/); + owner->getSession()->addEvent(hitEvent); + + return EffectCarrier::onHit( target, hitPosW ); +} \ No newline at end of file diff --git a/GameLogic/Bullet.h b/GameLogic/Bullet.h new file mode 100644 index 00000000..2d2e8552 --- /dev/null +++ b/GameLogic/Bullet.h @@ -0,0 +1,58 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef GAME_BULLET_H +#define GAME_BULLET_H + +#include "EffectCarrier.h" +#include "Line.h" + +namespace GameLogic +{ + class Bullet : public EffectCarrier + { + public: + class BulletCollector : public EffectCarrier::Collector + { + public: + BulletCollector( const ::Oyster::Collision::Line *sampler, int capacity = 0 ); + virtual ~BulletCollector( ); + virtual void action( Object *hitObject ); + + const ::Oyster::Collision::Line *sampler; + ::Oyster::Math::Float closest; + }; + + Bullet( Player *owner, const ::Oyster::Math::Float3 &origin, const ::Oyster::Math::Float3 &normalizedDirection, const ::Oyster::Math::Float &speed, Weapon::Type weapon, const ::Oyster::Math::Float &lifeTime = 0.0f ); + Bullet( const Bullet &bullet ); + virtual ~Bullet( ); + + Bullet & operator = ( const Bullet &bullet ); + + void setDirection( const ::Oyster::Math::Float3 &normalizedVector ); + void setSpeed( const ::Oyster::Math::Float &coordLengthPerSecond ); + void setLifeTime( const ::Oyster::Math::Float &seconds ); + void setModelID( int ID ); + + Float3 getDirection() const; + + virtual State update( const ::Oyster::Math::Float &deltaTime ); + virtual const ::Oyster::Collision::ICollideable * getVolumeOfEffect( ) const; + virtual EffectCarrier * clone( ) const; + + virtual Result writeToKeyFrame( KeyFrame &buffer ) const; + virtual Result writeToNetEffect( Network::EffectData &buffer ) const; + virtual Type getType( ) const { return EffectCarrier::Bullet; } + + virtual State onHit( const ::std::vector &targets, const ::std::vector<::Oyster::Math::Float3> &hitPosW ); + + private: + ::Oyster::Collision::Line lineOfEffect; // note current position is actually at the end of the lineOfEffect + ::Oyster::Math::Float speed, lifeCountDown; + int modelID; + }; +} + +#endif \ No newline at end of file diff --git a/GameLogic/EffectCarrier.cpp b/GameLogic/EffectCarrier.cpp new file mode 100644 index 00000000..b6948893 --- /dev/null +++ b/GameLogic/EffectCarrier.cpp @@ -0,0 +1,67 @@ +#include "EffectCarrier.h" +#include "GameLUA.h" +#include "Bullet.h" +#include "Event.h" +#include "Session.h" + +using namespace ::GameLogic; +using ::std::vector; + +// STATIC FACTORIES ///////////////////////////////////////////////// +EffectCarrier * EffectCarrier::createBullet( Player *owner, Weapon::Type weapon, const Float3 &origin, const Float3 &normalizedDirection, const Float &speed, const Float &lifeTime, const ::std::string &modelRef ) +{ + class Bullet *carrier = new class Bullet( owner, origin, normalizedDirection, speed, weapon, lifeTime ); + + // TODO have a modelID lib to ask + carrier->setModelID( 10240 ); + + Event::BulletCreated *bulletEvent = new Event::BulletCreated(owner->getPlayerID(), origin, normalizedDirection); + owner->getSession()->addEvent(bulletEvent); + + return carrier; +} + +// INSTANCE ///////////////////////////////////////////////////////// +EffectCarrier::Collector::Collector( int capacity ) : hitObjects(), hitPosW() +{ + if( capacity > 0 ) + { + this->hitObjects.reserve( capacity ); + this->hitPosW.reserve( capacity ); + } +} + +EffectCarrier::Collector::~Collector( ) {} + +void EffectCarrier::Collector::action( Object *hitObject ) +{ + this->hitObjects.push_back( hitObject ); + this->hitPosW.push_back( hitObject->getOrientation().v[3].xyz ); +} + +EffectCarrier::EffectCarrier( Object *_owner, Weapon::Type _weapon ) : weapon(_weapon), state(Deployed), owner(_owner) {} +EffectCarrier::EffectCarrier( const EffectCarrier &carrier ) : weapon(carrier.weapon), state(carrier.state), owner(carrier.owner) {} +EffectCarrier::~EffectCarrier( ) { } + +EffectCarrier & EffectCarrier::operator = ( const EffectCarrier & carrier ) +{ + this->weapon = carrier.weapon; + this->state = carrier.state; + this->owner = carrier.owner; + return *this; +} + +void EffectCarrier::setState( const State &state ) +{ this->state = state; } + +void EffectCarrier::setWeaponType( Weapon::Type weapon ) +{ this->weapon = weapon; } + +Object * EffectCarrier::accessOwner( ) const +{ return this->owner; } + +EffectCarrier::State EffectCarrier::onHit( const vector &targets, const vector &hitPosW ) +{ + GameLUA::executeOnHitScript( this->weapon, this, targets, hitPosW ); + return this->state; +} \ No newline at end of file diff --git a/GameLogic/EffectCarrier.h b/GameLogic/EffectCarrier.h new file mode 100644 index 00000000..b52bff41 --- /dev/null +++ b/GameLogic/EffectCarrier.h @@ -0,0 +1,77 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef GAME_EFFECT_H +#define GAME_EFFECT_H + +#include +#include "OysterMath.h" +#include "OysterCollision.h" +#include "OysterGame.h" +#include "Object.h" +#include "Protocoll.h" +#include "Weapon.h" +#include "Player.h" +#include "NetworkUpdateStructs.h" +namespace GameLogic +{ + class EffectCarrier + { + public: + enum State { Deployed, Armed, Dead }; + enum Result { Success, Failure }; + enum Type { Undefined, Bullet }; + + class Collector : public ::Oyster::Game::CollisionHandler::VisitingInstance + { + public: + Collector( int capacity = 0 ); + virtual ~Collector( ); + virtual void action( Object *hitObject ); + + ::std::vector hitObjects; + ::std::vector hitPosW; + }; + + // STATIC FACTORIES ///////////////////////////////////////// + + static EffectCarrier * createBullet( Player *owner, + Weapon::Type weapon, + const ::Oyster::Math::Float3 &originW, + const ::Oyster::Math::Float3 &normalizedDirectionW, + const ::Oyster::Math::Float &speed, + const ::Oyster::Math::Float &lifeTime, + const ::std::string &modelRef ); + + // INSTANCE ///////////////////////////////////////////////// + + EffectCarrier( Object *owner, Weapon::Type weapon = Weapon::Undefined ); + EffectCarrier( const EffectCarrier &carrier ); + virtual ~EffectCarrier( ); + + EffectCarrier & operator = ( const EffectCarrier & carrier ); + + void setState( const State &state ); + void setWeaponType( Weapon::Type weapon ); + + Object * accessOwner( ) const; + + virtual State update( const ::Oyster::Math::Float &deltaTime ) = 0; + virtual State onHit( const ::std::vector &targets, const ::std::vector<::Oyster::Math::Float3> &hitPosW ); + virtual const ::Oyster::Collision::ICollideable * getVolumeOfEffect( ) const = 0; + virtual EffectCarrier * clone( ) const = 0; + virtual Result writeToKeyFrame( KeyFrame &buffer ) const = 0; + virtual Result writeToNetEffect(Network::EffectData &data) const = 0; + + virtual Type getType( ) const { return Undefined; } + + protected: + Weapon::Type weapon; + State state; + Object *owner; + }; +} + +#endif \ No newline at end of file diff --git a/GameLogic/GameLUA.cpp b/GameLogic/GameLUA.cpp new file mode 100644 index 00000000..f128e0a5 --- /dev/null +++ b/GameLogic/GameLUA.cpp @@ -0,0 +1,297 @@ +#include "GameLUA.h" +#include "Object.h" +#include "OysterMath.h" +#include "EffectCarrier.h" +#include "Weapon.h" +#include "Player.h" +#include "Session.h" +#include "Bullet.h" + +using namespace ::Oyster::Math; +using namespace ::GameLogic; +using ::std::vector; +using ::std::string; + +lua_State *GameLUA::luaState = NULL; +Weapon::Type GameLUA::activeScriptWeapon = Weapon::Undefined; + +namespace GameInterface { void registerBindings(lua_State *lua, const char *nameSpace); } + +Float3 lua_tofloat3(lua_State *lua, int index); +void lua_pushfloat3(lua_State *lua, const Float3 &value); +template +void lua_pushstdvector(lua_State *lua, const std::vector &values); +void lua_pushstdvector(lua_State *lua, const std::vector &values); + +bool GameLUA::init() +{ + if (luaState == NULL) + { + luaState = luaL_newstate(); + luaL_openlibs(luaState); + + GameInterface::registerBindings(luaState, "engine"); + + // Load all weapon scripts. + for(int i = 0; i < Weapon::Count; i++) + { + GameLUA::loadScript(Weapon::weapons[i].scriptFile); + } + } + + return true; +} + +void GameLUA::release() +{ + if (luaState != NULL) + { + lua_close(luaState); + luaState = NULL; + } +} + +bool GameLUA::loadScript(const std::string &file) +{ + if (luaL_loadfile(luaState, file.c_str()) != LUA_OK) + { + printf("Failed to load script '%s'\n%s\n", file.c_str(), lua_tostring(luaState, -1)); + return false; + } + + if (lua_pcall(luaState, 0, 0, 0) != LUA_OK) + { + printf("Failed to run script '%s'\n%s\n", file.c_str(), lua_tostring(luaState, -1)); + return false; + } + + return true; +} + +void GameLUA::executeOnFireScript( Weapon::Type weapon, const Player &owner ) +{ + lua_getglobal( luaState, Weapon::weapons[weapon].onFireFunction ); + + int numArguments = 1; + lua_pushlightuserdata(luaState, (void *)&owner); + + int numReturnValues = 0; + + activeScriptWeapon = weapon; + + if (lua_pcall(luaState, numArguments, numReturnValues, 0) != LUA_OK) + printf("Failed to run scriptfunction '%s'\n%s\n", Weapon::weapons[weapon].onFireFunction, lua_tostring(luaState, -1)); + + activeScriptWeapon = Weapon::Undefined; +} + +void GameLUA::executeOnUpdateScript( Weapon::Type weapon, Object *object, const Float &deltaTime ) +{ + lua_getglobal( luaState, Weapon::weapons[weapon].onUpdateFunction ); + + int numArguments = 2; + lua_pushlightuserdata(luaState, object); + lua_pushnumber(luaState, deltaTime); + + int numReturnValues = 0; + + activeScriptWeapon = weapon; + + if (lua_pcall(luaState, numArguments, numReturnValues, 0) != LUA_OK) + printf("Failed to run scriptfunction '%s'\n%s\n", Weapon::weapons[weapon].onUpdateFunction, lua_tostring(luaState, -1)); + + activeScriptWeapon = Weapon::Undefined; +} + +void GameLUA::executeOnHitScript( Weapon::Type weapon, EffectCarrier *effect, const ::std::vector &targets, const vector &hitPosW ) +{ + lua_getglobal( luaState, Weapon::weapons[weapon].onHitFunction ); + int numArguments = 4; + lua_pushlightuserdata(luaState, effect); + lua_pushlightuserdata(luaState, effect->accessOwner()); + lua_pushstdvector(luaState, targets); + lua_pushstdvector(luaState, hitPosW); + + int numReturnValues = 0; + + activeScriptWeapon = weapon; + + if (lua_pcall(luaState, numArguments, numReturnValues, 0) != LUA_OK) + printf("Failed to run scriptfunction '%s'\n%s\n", Weapon::weapons[weapon].onHitFunction, lua_tostring(luaState, -1)); + + activeScriptWeapon = Weapon::Undefined; +} + + +Float3 lua_tofloat3(lua_State *lua, int index) +{ + Float3 value; + + lua_rawgeti(lua, index, 1); + value.x = (float)lua_tonumber(lua, -1); + lua_pop(lua, 1); + + lua_rawgeti(lua, index, 2); + value.y = (float)lua_tonumber(lua, -1); + lua_pop(lua, 1); + + lua_rawgeti(lua, index, 3); + value.z = (float)lua_tonumber(lua, -1); + lua_pop(lua, 1); + + return value; +} + +void lua_pushfloat3(lua_State *lua, const Float3 &value) +{ + lua_createtable(lua, 3, 0); + + lua_pushnumber(lua, value.x); + lua_rawseti(lua, -2, 1); + lua_pushnumber(lua, value.y); + lua_rawseti(lua, -2, 2); + lua_pushnumber(lua, value.z); + lua_rawseti(lua, -2, 3); +} + +template +void lua_pushstdvector(lua_State *lua, const std::vector &values) +{ + lua_createtable(lua, (int)values.size(), 0); + + for(int i = 0; i < (int)values.size(); i++) + { + lua_pushlightuserdata(lua, values[i]); + lua_rawseti(lua, -2, i + 1); + } +} + +void lua_pushstdvector(lua_State *lua, const std::vector &values) +{ + lua_createtable(lua, (int)values.size(), 0); + + for(int i = 0; i < (int)values.size(); i++) + { + lua_pushfloat3(lua, values[i]); + lua_rawseti(lua, -2, i + 1); + } +} + + +namespace GameInterface +{ + int applyDamage( lua_State *lua ) + { + Object *object = (Object*)lua_touserdata( lua, -3 ); + unsigned int magnitude = lua_tounsigned( lua, -2 ); + Object *attacker = (Object*)lua_touserdata( lua, -1 ); + + object->applyDamage( magnitude, *attacker ); + return 0; + } + + int applyHeal( lua_State *lua ) + { + Object *object = (Object*)lua_touserdata( lua, -2 ); + unsigned int magnitude = lua_tounsigned( lua, -1 ); + + object->applyHeal( magnitude ); + return 0; + } + + int applyForce( lua_State *lua ) + { + Object *object = (Object*) lua_touserdata( lua, -3 ); + Float3 force = lua_tofloat3(lua, -2); + Float3 position = lua_tofloat3(lua, -1); + + object->applyForceW( force, position ); + + return 0; + } + + int createBullet(lua_State *lua) + { + Weapon::Type weapon = GameLUA::activeScriptWeapon; + + if (weapon == Weapon::Undefined) + return 0; + + Player *owner = (Player *)lua_touserdata(lua, -6); + Float4 position = Float4(lua_tofloat3(lua, -5), 1.0f); + Float4 direction = Float4(lua_tofloat3(lua, -4), 0.0f); + float speed = (float)lua_tonumber(lua, -3); + float lifeTime = (float)lua_tonumber(lua, -2); + std::string modelRef = lua_tostring(lua, -1); + + // transform local to world + transformVector( position, position, owner->getOrientation() ); + transformVector( direction, direction, owner->getOrientation() ); + + // we want projectiles to move relative to the Players movement at the time + direction.xyz *= speed; + //direction.xyz += owner->getMovement(); + speed = direction.xyz.length(); + direction.xyz /= speed; + + EffectCarrier *bullet = EffectCarrier::createBullet( owner, weapon, position.xyz, direction.xyz, speed, lifeTime, modelRef ); + owner->getSession()->addEffect(*bullet); + + return 0; + } + + int getBulletDirection(lua_State *lua) + { + Bullet *bullet = (Bullet *)lua_touserdata(lua, -1); + + lua_pushfloat3(lua, bullet->getDirection()); + + return 1; + } + + int setWeaponCooldown(lua_State *lua) + { + Player *player = (Player *)lua_touserdata(lua, -2); + float cooldown = (float)lua_tonumber(lua, -1); + + player->setPrimaryWeaponCooldown(cooldown); + + return 0; + } + + struct FunctionBinding + { + const char *name; + lua_CFunction function; + }; + + static const FunctionBinding functionBindings[] = + { + {"applyDamage", applyDamage}, + {"applyHeal", applyHeal}, + {"applyForce", applyForce}, + {"createBullet", createBullet}, + {"getBulletDirection", getBulletDirection}, + {"setWeaponCooldown", setWeaponCooldown}, + {NULL, NULL} + }; + + void registerBindings(lua_State *lua, const char *nameSpace) + { + int i = 0; + + lua_newtable(lua); + + while(functionBindings[i].name != NULL) + { + lua_pushstring(lua, functionBindings[i].name); + lua_pushcfunction(lua, functionBindings[i].function); + + lua_rawset(lua, -3); + + i++; + } + + lua_setglobal(lua, nameSpace); + } +} \ No newline at end of file diff --git a/GameLogic/GameLUA.h b/GameLogic/GameLUA.h new file mode 100644 index 00000000..c5bb8c46 --- /dev/null +++ b/GameLogic/GameLUA.h @@ -0,0 +1,32 @@ +#ifndef GAMELUA_h +#define GAMELUA_h + +#include +#include +#include + +#include "EffectCarrier.h" +#include "Weapon.h" +#include "Player.h" + +namespace GameLogic +{ + class GameLUA + { + public: + static bool init(); + static void release(); + + static bool loadScript(const ::std::string &file); + + static void executeOnFireScript( Weapon::Type weapon, const Player &owner ); + static void executeOnUpdateScript( Weapon::Type weapon, Object *object, const ::Oyster::Math::Float &deltaTime ); + static void executeOnHitScript( Weapon::Type weapon, EffectCarrier *effect, const ::std::vector &targets, const std::vector &hitPosW ); + + static Weapon::Type activeScriptWeapon; + private: + static lua_State *luaState; + }; +} + +#endif diff --git a/GameLogic/GameLogic.cpp b/GameLogic/GameLogic.cpp new file mode 100644 index 00000000..6056ccd1 --- /dev/null +++ b/GameLogic/GameLogic.cpp @@ -0,0 +1,12 @@ +#include "GameLogic.h" + +using ::std::string; + +namespace GameLogic +{ + Result init( const string &iniFile ) + { + // TODO + return Success; + } +} \ No newline at end of file diff --git a/GameLogic/GameLogic.h b/GameLogic/GameLogic.h new file mode 100644 index 00000000..0bc512ae --- /dev/null +++ b/GameLogic/GameLogic.h @@ -0,0 +1,14 @@ +#pragma once +#ifndef GAMELOGIC_H +#define GAMELOGIC_H + +#include +#include "Ship.h" + +namespace GameLogic +{ + enum Result { Success, Failure }; + Result init( const ::std::string &iniFile ); +} + +#endif \ No newline at end of file diff --git a/GameLogic/InstanceBlueprint.cpp b/GameLogic/InstanceBlueprint.cpp new file mode 100644 index 00000000..15365a00 --- /dev/null +++ b/GameLogic/InstanceBlueprint.cpp @@ -0,0 +1,300 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +/* // TODO + + Painting + hitPoints = 0 + armour = 0 + centerOfMass = 0 0 0 + mass = 0 + ../entities/models/painting_0.obj + +A painting of a brunette.@@She has brown eyes... + + + + +*/ + +#include "InstanceBlueprint.h" +#include "Utilities.h" +#include +#include + +using namespace ::GameLogic; +using namespace ::Oyster::Math; +using ::std::string; +using ::std::vector; +using ::std::ifstream; +using ::std::stringstream; + +namespace PrivateStatic +{ + bool seekNextObject( string &idNameOutput, ::std::istream &source ) + { + string str; + vector splitString; + + while( !source.eof() ) + { + source >> str; + if( str.size() == 0 ) continue; + if( str[0] == '#' ) + { // rest of line is all commentary + ::std::getline( source, str ); + continue; + } + if( str[0] != '<' ) continue; + + if( str.size() == 1 ) + { if( !source.eof() ) source >> str; } + else str = str.substr( 1 ); + + ::Utility::String::toLowerCase( str ); + if( str != "object" ) continue; + + if( source.eof() ) return false; + source >> str; + + ::Utility::String::split( splitString, str, '\"' ); + // since str have no prefix whitespaces, we can safely assume + // splitString[0] is the string we want. the rest is garbage. + idNameOutput = ::Utility::String::trim( splitString[0] ); + return true; + } + return false; + } + + void fillInstanceBlueprint( InstanceBlueprint &targetMem, ::std::istream &source, const Float4x4 &transform ) + { + string line; + vector splitString; + vector tagDelims(2); + tagDelims[0] = "<"; + tagDelims[1] = ">"; + + Float4 minPoint = Float4( Float3(::std::numeric_limits::max()), 1.0f ), + maxPoint = Float4( Float3(-::std::numeric_limits::max()), 1.0f ), + centerOfMass = Float4( Float3::null, 1.0f ); + + while( !source.eof() ) + { + ::std::getline( source, line ); + + line = ::Utility::String::trim( line ); + + if( line.length() == 0 ) continue; + if( line[0] == '#' ) continue; + + splitString = vector(); + ::Utility::String::split( splitString, line, '#' ); + line = ::Utility::String::trim( splitString[0] ); + + if( line.length() == 0 ) + continue; // just to be sure + + if( line[0] == '<' ) + { // it's possibly , , , or + splitString = vector(); + ::Utility::String::split( splitString, line, tagDelims ); + line = ::Utility::String::toLowerCase( ::Utility::String::trim(splitString[0]) ); + if( line == "displayname" ) + { // Painting + targetMem.name = ::Utility::String::trim(splitString[1]); + } + else if( line == "model" ) + { // ../entities/models/painting_0.obj + targetMem.objFileName = ::Utility::String::replaceCharacters( ::Utility::String::trim(splitString[1]), '/', '\\' ); + } + else if( line == "description" ) + { /* + A painting of a brunette.@@She has brown eyes... + */ + + if( splitString.size() > 1 ) + line = ::Utility::String::trim( splitString[1] ); + else + { + if( source.eof() ) return; + ::std::getline( source, line ); + } + + splitString = vector(); + ::Utility::String::split( splitString, line, "@@" ); + stringstream strBuilder( splitString[0] ); + + vector::size_type numSplits = splitString.size(); + for( vector::size_type i = 1; i < numSplits; ++i ) + { + if( i > 1 ) strBuilder << '\n'; + strBuilder << splitString[i]; + } + + targetMem.description = strBuilder.str(); + } + else if( line.find_first_of("box") == 0 ) + { /* + */ + + stringstream stream( line ); + stream >> line; + if( line != "box" ) + continue; + + Float3 point; + ::Utility::Stream::readFloats( point.element, stream, 3 ); + minPoint.xyz = ::Utility::Value::min( minPoint.xyz, point ); + maxPoint.xyz = ::Utility::Value::max( maxPoint.xyz, point ); + + ::Utility::Stream::readFloats( point.element, stream, 3 ); + minPoint.xyz = ::Utility::Value::min( minPoint.xyz, point ); + maxPoint.xyz = ::Utility::Value::max( maxPoint.xyz, point ); + } + else if( line == "/object" ) + break; + + continue; // no point to continue further down + } // end of "if( line[0] == '<' )" + + splitString = vector(); + + ::Utility::String::split( splitString, line, '=' ); + if( splitString.size() > 1 ) + { + splitString[0] = ::Utility::String::toLowerCase( ::Utility::String::trim(splitString[0]) ); + if( splitString[0] == "hitpoints" ) + { // hitPoints = 0 + splitString[1] = ::Utility::String::trim(splitString[1]); + targetMem.hullPoints = ::std::atoi( splitString[1].c_str() ); + } + else if( splitString[0] == "armour" ) // ?? + { // armour = 0 + splitString[1] = ::Utility::String::trim(splitString[1]); + targetMem.shieldPoints = ::std::atoi( splitString[1].c_str() ); + } + else if( splitString[0] == "mass" ) + { // mass = 0 + splitString[1] = ::Utility::String::trim(splitString[1]); + targetMem.mass = (float)::std::atof( splitString[1].c_str() ); + if( targetMem.mass == 0.0f ) + targetMem.mass = ::std::numeric_limits::max(); + } + else if( splitString[0] == "centerofmass" ) + { // centerOfMass = 0 0 0 + stringstream stream( splitString[1] ); + ::Utility::Stream::readFloats( centerOfMass.element, stream, 3 ); + } + else if( splitString[0] == "maxspeed" ) + { // maxspeed = [ float of top speed: default 400.0 ] + stringstream stream( splitString[1] ); + string value; + stream >> value; + targetMem.movementProperty.maxSpeed = (float)::std::atof( value.c_str() ); + } + else if( splitString[0] == "deacceleration" ) + { // deacceleration = [ float of acceleration : default 50.0 ] + stringstream stream( splitString[1] ); + string value; + stream >> value; + targetMem.movementProperty.deAcceleration = (float)::std::atof( value.c_str() ); + } + else if( splitString[0] == "forward" ) + { // forward = [ float of acceleration : default 50.0 ] + stringstream stream( splitString[1] ); + string value; + stream >> value; + targetMem.movementProperty.acceleration.forward = (float)::std::atof( value.c_str() ); + } + else if( splitString[0] == "backward" ) + { // backward = [ float of acceleration : default 25.0 ] + stringstream stream( splitString[1] ); + string value; + stream >> value; + targetMem.movementProperty.acceleration.backward = (float)::std::atof( value.c_str() ); + } + else if( splitString[0] == "strafe" ) + { // strafe = [ float of acceleration : default 25.0 ] + stringstream stream( splitString[1] ); + string sValue; + stream >> sValue; + float fValue = (float)::std::atof( sValue.c_str() ); + targetMem.movementProperty.acceleration.horizontal = fValue; + targetMem.movementProperty.acceleration.vertical = fValue; + } + else if( splitString[0] == "turnspeed" ) + { // turnspeed = [ float in degrees : default 90.0 ] + stringstream stream( splitString[1] ); + string sValue; + stream >> sValue; + float fValue = ::Utility::Value::radian( (float)::std::atof(sValue.c_str()) ); + targetMem.rotationProperty.maxSpeed = fValue; + targetMem.rotationProperty.deAcceleration = 2.0f * fValue; + targetMem.rotationProperty.acceleration.pitch = fValue; + targetMem.rotationProperty.acceleration.yaw = fValue; + targetMem.rotationProperty.acceleration.roll = fValue; + } + } + } + + targetMem.centerOfMass = transformVector( centerOfMass, centerOfMass, transform ).xyz; + + if( minPoint != Float4( Float3(::std::numeric_limits::max()), 1.0f ) ) + if( maxPoint != Float4( Float3(-::std::numeric_limits::max()), 1.0f ) ) + { + transformVector( minPoint, minPoint, transform ); + transformVector( maxPoint, maxPoint, transform ); + + targetMem.hitBox.position = (maxPoint.xyz - minPoint.xyz) * 0.5f; + targetMem.hitBox.halfSize = ::Utility::Value::abs( targetMem.hitBox.position ); + targetMem.hitBox.position += minPoint.xyz; + } + } +} + +InstanceBlueprint::Result InstanceBlueprint::loadFromFile( vector &output, vector &idOutput, const string &entityFile, const Float4x4 &transform ) +{ + ifstream file( entityFile ); + + if( file.is_open() ) + { + string idName, workingDir; + ::Utility::String::extractDirPath( workingDir, entityFile, '\\' ); + + while( PrivateStatic::seekNextObject(idName, file) ) + { + InstanceBlueprint* blueprint = new InstanceBlueprint(); + PrivateStatic::fillInstanceBlueprint( *blueprint, file, transform ); + if( blueprint->objFileName.length() > 0 ) + blueprint->objFileName = workingDir + blueprint->objFileName; + output.push_back( blueprint ); + idOutput.push_back( idName ); + } + file.close( ); + + return Success; + } + else return Failure; +} + +InstanceBlueprint::InstanceBlueprint( ) + : name(), objFileName(), description(), mass(::std::numeric_limits::max()), centerOfMass(Float3::null), + hullPoints(255), shieldPoints(255) +{ + this->hitBox.halfSize = Float3::null; + this->hitBox.position = Float3::null; + + this->movementProperty.maxSpeed = 400.0f; + this->movementProperty.deAcceleration = 50.0f; + this->movementProperty.acceleration.forward = 50.0f; + this->movementProperty.acceleration.backward = 25.0f; + this->movementProperty.acceleration.horizontal = 25.0f; + this->movementProperty.acceleration.vertical = 25.0f; + + this->rotationProperty.maxSpeed = ::Utility::Value::radian( 90.0f ); + this->rotationProperty.deAcceleration = ::Utility::Value::radian( 180.0f ); + this->rotationProperty.acceleration.pitch = ::Utility::Value::radian( 90.0f ); + this->rotationProperty.acceleration.yaw = ::Utility::Value::radian( 90.0f ); + this->rotationProperty.acceleration.roll = ::Utility::Value::radian( 90.0f ); +} \ No newline at end of file diff --git a/GameLogic/InstanceBlueprint.h b/GameLogic/InstanceBlueprint.h new file mode 100644 index 00000000..b4d03bb2 --- /dev/null +++ b/GameLogic/InstanceBlueprint.h @@ -0,0 +1,43 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef GAME_INSTANCEBLUEPRINT_H +#define GAME_INSTANCEBLUEPRINT_H + +#include +#include +#include "OysterMath.h" + +namespace GameLogic +{ + struct InstanceBlueprint + { + enum Result { Success, Failure }; + static Result loadFromFile( ::std::vector &output, ::std::vector<::std::string> &idOutput, const ::std::string &entityFile, const ::Oyster::Math::Float4x4 &transform = ::Oyster::Math::Float4x4::identity ); + + ::std::string name, objFileName, description; + float mass; + ::Oyster::Math::Float3 centerOfMass; + struct { ::Oyster::Math::Float3 halfSize, position; } hitBox; + // engineData + int hullPoints, shieldPoints; + + struct + { + ::Oyster::Math::Float maxSpeed, deAcceleration; + struct{ ::Oyster::Math::Float forward, backward, horizontal, vertical; } acceleration; + } movementProperty; + + struct + { + ::Oyster::Math::Float maxSpeed, deAcceleration; + struct{ ::Oyster::Math::Float pitch, yaw, roll; } acceleration; + } rotationProperty; + + InstanceBlueprint( ); + }; +} + +#endif \ No newline at end of file diff --git a/GameLogic/MoveAble.h b/GameLogic/MoveAble.h new file mode 100644 index 00000000..20b85ff2 --- /dev/null +++ b/GameLogic/MoveAble.h @@ -0,0 +1,46 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef GAME_MOVEABLE_H +#define GAME_MOVEABLE_H + +#include "OysterMath.h" + +namespace Game +{ + using namespace Oyster::Math; + + class MoveAble + { + public: + MoveAble( ); + MoveAble( const Float4x4 &orientation, const Float3 ¢erOfMass = Float3::null ); + virtual ~MoveAble( ); + + void move( const Float3 &movement, const Float3 &displacement ); + void move( const Float3 &movement ); + void turn( const Float3 &deltaAngular ); + void stop( ); + + protected: + union + { + struct{ Float4x4 orientation; }; + struct{ Float3 axisX; Float paddingX; + Float3 axisY; Float paddingY; + Float3 axisZ; Float paddingZ; + Float3 position; Float paddingP; }; + }; + Float3 centerOfMass; + + void updateOrientation( ); + + private: + Float3 sumDeltaAngular, + sumMovement; + }; +} + +#endif \ No newline at end of file diff --git a/GameLogic/Object.cpp b/GameLogic/Object.cpp new file mode 100644 index 00000000..d18f9774 --- /dev/null +++ b/GameLogic/Object.cpp @@ -0,0 +1,485 @@ +#include "Object.h" + +#include +#include +#include + +using namespace ::Oyster::Math; +using namespace ::Oyster::Collision; +using namespace ::Oyster::Game; +using ::std::string; +using ::std::vector; +using ::std::map; + +namespace GameLogic +{ + namespace PrivateStatic + { + struct EntityFileState + { + bool isLoaded; + vector bluePrintRef; + EntityFileState() : isLoaded(false), bluePrintRef() {} + }; + + map loadedEntityFileLibrary; + map blueprintIndex = map(); + vector blueprint = vector(); + const InstanceBlueprint invalidBluePrint = InstanceBlueprint(); + unsigned int numCreatedObjects = 0; + + class WatchDog + { + public: + WatchDog( ) {} + ~WatchDog( ) + { + vector::size_type numBluePrints = PrivateStatic::blueprint.size(); + for( vector::size_type i = 0; i < numBluePrints; ++i ) delete PrivateStatic::blueprint[i]; + } + } watchDog; + } + + const unsigned int Object::invalidID = ::std::numeric_limits::max(); + + Object::Result Object::init( const string &iniFile ) + {/* + if( PrivateStatic::blueprint.size() > 0 ) + { // ReInit friendly + vector::size_type numBluePrints = PrivateStatic::blueprint.size(); + for( vector::size_type i = 0; i < numBluePrints; ++i ) delete PrivateStatic::blueprint[i]; + PrivateStatic::blueprint = vector(); + }*/ + + // remove? + return Success; + } + + Object::Result Object::importEntities( vector &outputConfigID, const string &entityFile, const Float4x4 &transform ) + { + outputConfigID.resize( 0 ); + + PrivateStatic::EntityFileState *entityFileState = &PrivateStatic::loadedEntityFileLibrary[entityFile]; + + if( entityFileState->isLoaded ) + { + outputConfigID = entityFileState->bluePrintRef; + return Success; + } + + vector loadedBlueprint; + vector loadedBlueprintRefNames; + if( InstanceBlueprint::loadFromFile( loadedBlueprint, loadedBlueprintRefNames, entityFile, transform ) == InstanceBlueprint::Success ) + { + vector::size_type i = 0, + numLoaded = loadedBlueprint.size(); + + for( ; i < numLoaded; ++i ) + { + outputConfigID.push_back( (unsigned int)PrivateStatic::blueprint.size() ); + PrivateStatic::blueprintIndex[ ::Utility::String::toLowerCase(loadedBlueprintRefNames[i]) ] = (unsigned int)PrivateStatic::blueprint.size(); + PrivateStatic::blueprint.push_back( loadedBlueprint[i] ); + } + + entityFileState->isLoaded = true; + entityFileState->bluePrintRef = outputConfigID; + return Success; + } + return Failure; + } + + void Object::clearEntityresources( ) + { + PrivateStatic::loadedEntityFileLibrary.clear(); + + vector::size_type numBluePrints = PrivateStatic::blueprint.size(); + for( vector::size_type i = 0; i < numBluePrints; ++i ) + delete PrivateStatic::blueprint[i]; + + PrivateStatic::blueprint.resize( 0 ); + } + + unsigned int Object::getNumObjectsCreated( ) + { return PrivateStatic::numCreatedObjects; } + + const InstanceBlueprint & Object::getConfig( unsigned int id ) + { + if( id < PrivateStatic::blueprint.size() ) + return *PrivateStatic::blueprint[id]; + else + return PrivateStatic::invalidBluePrint; + } + + const InstanceBlueprint & Object::getConfig( const ::std::string &handle ) + { + map::const_iterator i = PrivateStatic::blueprintIndex.find( ::Utility::String::toLowerCase(string(handle)) ); + if( i != PrivateStatic::blueprintIndex.end() ) + return *PrivateStatic::blueprint[i->second]; + else + return PrivateStatic::invalidBluePrint; + } + + void Object::onCollisionAction( Object *visitor, Object *hitEntity ) + { + if( visitor == hitEntity ) return; + if( visitor->body.Intersects( &hitEntity->body ) ) + { + Float3 pushVector = (visitor->body.orientation.v[3].xyz - hitEntity->body.orientation.v[3].xyz).getNormalized(); + pushVector = vectorProjection( visitor->speed, pushVector ); + pushVector *= 2.0f; + visitor->speed -= pushVector; + visitor->acceleration=Float3::null; + } + } + +// INSTANCE ///////////////////////////////////////////////////////// + + Object::Object( ) + : MoveAble(), objectID(PrivateStatic::numCreatedObjects++), configID(Object::invalidID), + physicsID(CollisionHandler::Reference::invalid), mass(1.0f), disableReduceMovementCount(0), + disableReduceRotationCount(0), scaling(1.0f, 1.0f, 1.0f), view(Float4x4::identity), world(Float4x4::identity), viewIsOutOfDate(true), worldIsOutOfDate(true) + { + this->movementProperty.maxSpeed = this->movementProperty.deAcceleration = this->movementProperty.acceleration.forward = this->movementProperty.acceleration.backward = this->movementProperty.acceleration.horizontal = this->movementProperty.acceleration.vertical = 0.0f; + this->rotationProperty.maxSpeed = this->rotationProperty.deAcceleration = this->rotationProperty.acceleration.pitch = this->rotationProperty.acceleration.yaw = this->rotationProperty.acceleration.roll = 0.0f; + } + + Object::Object( const Object &object ) + : MoveAble(object), objectID(object.objectID), configID(object.configID), physicsID(object.physicsID), mass(object.mass), + movementProperty(object.movementProperty), rotationProperty(object.rotationProperty), + disableReduceMovementCount(object.disableReduceMovementCount), disableReduceRotationCount(object.disableReduceRotationCount), + scaling(object.scaling), view(object.view), world(object.world), viewIsOutOfDate(object.viewIsOutOfDate), worldIsOutOfDate(object.worldIsOutOfDate) {} + + Object::Object( const Float4x4 &orientation, const Float3 ¢erOfMass ) + : MoveAble(orientation, centerOfMass), objectID(PrivateStatic::numCreatedObjects++), configID(invalidID), + physicsID(CollisionHandler::Reference::invalid), mass(1.0f), disableReduceMovementCount(0), + disableReduceRotationCount(0), scaling(1.0f, 1.0f, 1.0f), view(Float4x4::identity), world(Float4x4::identity), viewIsOutOfDate(true), worldIsOutOfDate(true) + { this->movementProperty.maxSpeed = this->movementProperty.deAcceleration = this->movementProperty.acceleration.forward = this->movementProperty.acceleration.backward = this->movementProperty.acceleration.horizontal = this->movementProperty.acceleration.vertical = 0.0f; } + + Object::Object( const Box &body, const Float3 ¢erOfMass ) + : MoveAble(body, centerOfMass), objectID(PrivateStatic::numCreatedObjects++), configID(invalidID), + physicsID(CollisionHandler::Reference::invalid), mass(1.0f), disableReduceMovementCount(0), + disableReduceRotationCount(0), scaling(1.0f, 1.0f, 1.0f), view(Float4x4::identity), world(Float4x4::identity), viewIsOutOfDate(true), worldIsOutOfDate(true) + { + this->movementProperty.maxSpeed = this->movementProperty.deAcceleration = this->movementProperty.acceleration.forward = this->movementProperty.acceleration.backward = this->movementProperty.acceleration.horizontal = this->movementProperty.acceleration.vertical = 0.0f; + this->rotationProperty.maxSpeed = this->rotationProperty.deAcceleration = this->rotationProperty.acceleration.pitch = this->rotationProperty.acceleration.yaw = this->rotationProperty.acceleration.roll = 0.0f; + } + + Object::~Object( ) {} + + Object & Object::operator = ( const Object &object ) + { + MoveAble::operator=(object); + this->objectID = object.objectID; + this->configID = object.configID; + this->physicsID = object.physicsID; + this->mass = object.mass; + this->movementProperty = object.movementProperty; + this->rotationProperty = object.rotationProperty; + this->disableReduceMovementCount = object.disableReduceMovementCount; + this->disableReduceRotationCount = object.disableReduceRotationCount; + this->scaling = object.scaling; + + if( !object.viewIsOutOfDate ) + this->view = object.view; + if( !object.worldIsOutOfDate ) + this->world = object.world; + this->viewIsOutOfDate = object.viewIsOutOfDate; + this->worldIsOutOfDate = object.worldIsOutOfDate; + + return *this; + } + + Object * Object::clone( ) const + { return new Object(*this); } + + Object::Type Object::getType( ) const + { return Undefined; } + + const unsigned int & Object::getObjectID( ) const + { return this->objectID; } + + const unsigned int & Object::getConfigID( ) const + { return this->configID; } + + const CollisionHandler::Reference & Object::getPhysicsID( ) const + { return this->physicsID; } + + const Float & Object::getMass( ) const + { return this->mass; } + + const Float3 & Object::getCenterOfMass( ) const + { return this->rotationPivot; } + + Float3 Object::getInertia( const Float3 &offset ) const + { return MoveAble::getMovement( offset ) *= this->mass; } + + const Box & Object::getCollisionBox( ) const + { return this->body; } + + bool Object::isActive( ) const + { return this->physicsID.isActive(); } + + void Object::setConfig( unsigned int id ) + { + this->configID = id; + this->loadConfig(); + } + + void Object::setConfig( const ::std::string &id ) + { + map::const_iterator ref = PrivateStatic::blueprintIndex.find( ::Utility::String::toLowerCase(string(id)) ); + if( ref != PrivateStatic::blueprintIndex.end() ) + { + this->configID = ref->second; + this->loadConfig(); + } + } + + void Object::loadConfig( ) + { + if( this->configID != Object::invalidID ) + this->loadConfig( *PrivateStatic::blueprint[this->configID] ); + } + + void Object::setPhysicsID( const CollisionHandler::Reference &id ) + { this->physicsID = id; } + + void Object::setMass( const Float &mass ) + { this->mass = mass; } + + void Object::setCenterOfMass( const Float3 &localPos ) + { this->rotationPivot = localPos; } + + void Object::setScaling( const ::Oyster::Math::Float3 &scaleL ) + { + this->body.boundingOffset.x /= this->scaling.x; + this->body.boundingOffset.y /= this->scaling.y; + this->body.boundingOffset.z /= this->scaling.z; + this->body.boundingOffset *= scaleL; + + if( this->physicsID != CollisionHandler::Reference::invalid ) + this->physicsID.setBoundaryReach( this->body.boundingOffset.length() ); + + this->scaling = scaleL; + this->worldIsOutOfDate = this->viewIsOutOfDate = true; + } + + void Object::applyForceL( const Float3 &localForce, const Float3 &localPos ) + { MoveAble::accelerate( localForce / this->mass, localPos ); } + + void Object::applyForceW( const Float3 &worldForce, const Float3 &worldPos ) + { + Float4 localForce, localPos; + transformVector( localForce, Float4(worldForce, 0.0f), this->getViewNormalMatrix() ); + transformVector( localPos, Float4(worldPos, 1.0f), this->getViewPointMatrix() ); + + MoveAble::accelerate( localForce.xyz / this->mass, localPos.xyz ); + } + + void Object::moveToLimbo( ) + { + Float4x4 m = this->getOrientation(); + m.v[0]=m.v[1]=m.v[2]=m.v[3] = Float4::null; + this->setOrientation(m); + this->stop(); + this->physicsID.moveToLimbo(); + } + + void Object::releaseFromLimbo( ) + { + this->physicsID.leaveLimbo(); + } + + void Object::update( ) + { + // Speed Control + Float speedSquared = this->speed.dot( this->speed ); + + if( speedSquared > ( this->movementProperty.maxSpeed * this->movementProperty.maxSpeed ) ) + { // drop the speed to max and kill acceleration this update + this->speed *= ( this->movementProperty.maxSpeed / ::std::sqrt(speedSquared) ); + //this->acceleration = Float3::null; + } + if( this->disableReduceMovementCount == 0 ) + { // kill movement if moving slow enough, or deAccelerate + Float deAccelerate = this->movementProperty.deAcceleration * MoveAble::getDiscreteTimeSlice(); + + if( speedSquared <= ( deAccelerate * deAccelerate ) ) + this->speed = Float3::null; + else + { + speedSquared = ::std::sqrt(speedSquared); + this->speed *= (speedSquared - deAccelerate) / speedSquared; + } + } + + // Rotation Control + speedSquared = this->rotationalSpeed.dot( this->rotationalSpeed ); + + if( speedSquared > ( this->rotationProperty.maxSpeed * this->rotationProperty.maxSpeed ) ) + { // drop the rotationSpeed to max and kill acceleration this update + this->rotationalSpeed *= ( this->rotationProperty.maxSpeed / ::std::sqrt(speedSquared) ); + this->rotationalAcceleration = Float3::null; + } + if( this->disableReduceRotationCount == 0 ) + { // kill rotation if moving slow enough, or deAccelerate + Float deAccelerate = this->rotationProperty.deAcceleration * MoveAble::getDiscreteTimeSlice(); + + if( speedSquared <= ( deAccelerate * deAccelerate ) ) + this->rotationalSpeed = Float3::null; + else + { + speedSquared = ::std::sqrt(speedSquared); + this->rotationalSpeed *= (speedSquared - deAccelerate) / speedSquared; + } + } + + MoveAble::update(); + if( this->physicsID != CollisionHandler::Reference::invalid ) + this->physicsID.setPosition( this->body.orientation.v[3].xyz ); + this->worldIsOutOfDate = this->viewIsOutOfDate = true; + } + + void Object::pitchUp( ) + { this->accelerateTurn( this->body.orientation.v[0].xyz * -this->rotationProperty.acceleration.pitch ); } + + void Object::pitchDown( ) + { this->accelerateTurn( this->body.orientation.v[0].xyz * this->rotationProperty.acceleration.pitch ); } + + void Object::yawLeft( ) + { this->accelerateTurn( this->body.orientation.v[1].xyz * -this->rotationProperty.acceleration.yaw ); } + + void Object::yawRight( ) + { this->accelerateTurn( this->body.orientation.v[1].xyz * this->rotationProperty.acceleration.yaw ); } + + void Object::rollLeft( ) + { this->accelerateTurn( this->body.orientation.v[2].xyz * this->rotationProperty.acceleration.roll ); } + + void Object::rollRight( ) + { this->accelerateTurn( this->body.orientation.v[2].xyz * -this->rotationProperty.acceleration.roll ); } + + void Object::thrustForward( ) + { this->accelerate( this->body.orientation.v[2].xyz * this->movementProperty.acceleration.forward ); } + + void Object::thrustBackward( ) + { this->accelerate( this->body.orientation.v[2].xyz * -this->movementProperty.acceleration.backward ); } + + void Object::strafeLeft( ) + { this->accelerate( this->body.orientation.v[0].xyz * -this->movementProperty.acceleration.horizontal ); } + + void Object::strafeRight( ) + { this->accelerate( this->body.orientation.v[0].xyz * this->movementProperty.acceleration.horizontal ); } + + void Object::climb( ) + { this->accelerate( this->body.orientation.v[1].xyz * this->movementProperty.acceleration.vertical ); } + + void Object::dive( ) + { this->accelerate( this->body.orientation.v[1].xyz * -this->movementProperty.acceleration.vertical ); } + + void Object::disableMovementReduction( ) + { ++this->disableReduceMovementCount; } + + void Object::enableMovementReduction( bool forceIt ) + { + if( forceIt ) + this->disableReduceMovementCount = 0; + else if( --this->disableReduceMovementCount < 0) this->disableReduceMovementCount = 0; + } + + void Object::disableRotationReduction( ) + { ++this->disableReduceRotationCount; } + + void Object::enableRotationReduction( bool forceIt ) + { + if( forceIt ) + this->disableReduceRotationCount = 0; + else if( --this->disableReduceRotationCount < 0) this->disableReduceRotationCount = 0; + } + + Object::Result Object::writeToKeyFrame( KeyFrame &buffer ) const + { + if( buffer.numObjects < (signed)::Utility::StaticArray::numElementsOf( buffer.Objects ) ) + { + buffer.Objects[buffer.numObjects].id = this->objectID; + buffer.Objects[buffer.numObjects].TypeId = this->configID; + buffer.Objects[buffer.numObjects].RotationVec = this->rotationalSpeed; + buffer.Objects[buffer.numObjects].MoveVec = this->speed; + + //TODO: edit to world when they are avaliable + buffer.Objects[buffer.numObjects].World = this->body.orientation; + + //buffer.Objects[buffer.numObjects].ForwardVec = this->body.orientation.v[2].xyz; + //buffer.Objects[buffer.numObjects].UpVec = this->body.orientation.v[1].xyz; + + ++buffer.numObjects; + return Success; + } + return Failure; + } + + const Float4x4 & Object::getWorldPointMatrix( ) const + { + if( this->worldIsOutOfDate ) + { + transformMatrix( this->world, + Float4x4( Float4::standardUnitX * this->scaling.x, + Float4::standardUnitY * this->scaling.y, + Float4::standardUnitZ * this->scaling.z, + Float4::standardUnitW ), + this->body.orientation ); + this->worldIsOutOfDate = false; + } + return this->world; + } + + const Float4x4 & Object::getViewPointMatrix( ) const + { + if( this->viewIsOutOfDate ) + { + this->view = this->getWorldPointMatrix().getInverse(); + this->viewIsOutOfDate = false; + } + return this->view; + } + + void Object::setOrientation( const Float4x4 & orientation ) + { + MoveAble::setOrientation( orientation ); + if( this->physicsID != CollisionHandler::Reference::invalid ) + this->physicsID.setPosition( orientation.v[3].xyz ); + this->worldIsOutOfDate = this->viewIsOutOfDate = true; + } + + const InstanceBlueprint & Object::getConfigData( unsigned int configID ) + { return *PrivateStatic::blueprint[configID]; } + + void Object::loadConfig( const InstanceBlueprint &config ) + { + this->mass = (Float)config.mass; + this->setCenterOfMass( config.centerOfMass ); + this->body.boundingOffset = ::Utility::Value::abs( config.hitBox.position ) + config.hitBox.halfSize; + + this->movementProperty.maxSpeed = config.movementProperty.maxSpeed; + this->movementProperty.deAcceleration = config.movementProperty.deAcceleration; + this->movementProperty.acceleration.forward = config.movementProperty.acceleration.forward; + this->movementProperty.acceleration.backward = config.movementProperty.acceleration.backward; + this->movementProperty.acceleration.horizontal = config.movementProperty.acceleration.horizontal; + this->movementProperty.acceleration.vertical = config.movementProperty.acceleration.vertical; + + this->rotationProperty.maxSpeed = config.rotationProperty.maxSpeed; + this->rotationProperty.deAcceleration = config.rotationProperty.deAcceleration; + this->rotationProperty.acceleration.pitch = config.rotationProperty.acceleration.pitch; + this->rotationProperty.acceleration.yaw = config.rotationProperty.acceleration.yaw; + this->rotationProperty.acceleration.roll = config.rotationProperty.acceleration.roll; + + if( this->physicsID != CollisionHandler::Reference::invalid ) + this->physicsID.setBoundaryReach( this->body.boundingOffset.length() ); + } +} + +namespace Oyster { namespace Game +{ + template <> + bool CollisionHandler<::GameLogic::Object>::simpleCollisionConfirmation( const typename ::GameLogic::Object &entity, const ::Oyster::Collision::ICollideable *sampler ) + { return sampler->Intersects( &entity.getCollisionBox() ); } +} } \ No newline at end of file diff --git a/GameLogic/Object.h b/GameLogic/Object.h new file mode 100644 index 00000000..30d83e8a --- /dev/null +++ b/GameLogic/Object.h @@ -0,0 +1,147 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef GAME_OBJECT_H +#define GAME_OBJECT_H + +#include +#include "OysterMath.h" +#include "OysterCollision.h" +#include "OysterGame.h" +#include "Protocoll.h" +#include "InstanceBlueprint.h" + +namespace GameLogic +{ + class Object : public ::Oyster::Game::MoveAble + { + public: + enum Result { Success, Failure }; + enum Type { Player = 0, Static = 1, Destructable = 3, Undefined = 4 }; + static Result init( const ::std::string &iniFile ); // needed anymore? + static Result importEntities( ::std::vector &outputConfigID, const ::std::string &entityFile, const ::Oyster::Math::Float4x4 &transform = ::Oyster::Math::Float4x4::identity ); + static void clearEntityresources( ); + static unsigned int getNumObjectsCreated( ); + static const InstanceBlueprint &getConfig( unsigned int id ); + static const InstanceBlueprint &getConfig( const ::std::string &handle ); + + static void onCollisionAction( Object *visitor, Object *hitEntity ); + + static const unsigned int invalidID; + + struct + { + ::Oyster::Math::Float maxSpeed, deAcceleration; + struct{ ::Oyster::Math::Float forward, backward, horizontal, vertical; } acceleration; + } movementProperty; + + struct + { + ::Oyster::Math::Float maxSpeed, deAcceleration; + struct{ ::Oyster::Math::Float pitch, yaw, roll; } acceleration; + } rotationProperty; + + Object( ); + Object( const Object &object ); + Object( const ::Oyster::Math::Float4x4 &orientation, const ::Oyster::Math::Float3 ¢erOfMass = ::Oyster::Math::Float3::null ); + Object( const ::Oyster::Collision::Box &body, const ::Oyster::Math::Float3 ¢erOfMass = ::Oyster::Math::Float3::null ); + virtual ~Object( ); + + Object & operator = ( const Object &object ); + virtual Object * clone( ) const; + + virtual Type getType( ) const; + const unsigned int & getObjectID( ) const; + const unsigned int & getConfigID( ) const; + const ::Oyster::Game::CollisionHandler::Reference & getPhysicsID( ) const; + const ::Oyster::Math::Float & getMass( ) const; + const ::Oyster::Math::Float3 & getCenterOfMass( ) const; + ::Oyster::Math::Float3 getInertia( const ::Oyster::Math::Float3 &offset ) const; + const ::Oyster::Collision::Box & getCollisionBox( ) const; + bool isActive( ) const; + + void setConfig( unsigned int id ); + void setConfig( const ::std::string &id ); + void loadConfig( ); + + void setPhysicsID( const ::Oyster::Game::CollisionHandler::Reference &id ); + void setMass( const ::Oyster::Math::Float &mass ); + void setCenterOfMass( const ::Oyster::Math::Float3 &localPos ); + void setScaling( const ::Oyster::Math::Float3 &scaleL ); + + void applyForceL( const ::Oyster::Math::Float3 &localForce, const ::Oyster::Math::Float3 &localPos ); + void applyForceW( const ::Oyster::Math::Float3 &worldForce, const ::Oyster::Math::Float3 &worldPos ); + virtual void applyDamage( unsigned char magnitude, Object &attacker ) {} + virtual void applyHeal( unsigned char magnitude ) {} + virtual void HealShield( unsigned char magnitude ) {} + virtual void DamageShield( unsigned char magnitude ) {} + virtual void onDeath( Object &killer ) {} + virtual void onKill( Object &victim ) {} + + void moveToLimbo( ); + void releaseFromLimbo( ); + + virtual void update( ); + + virtual void firePrimaryWeapon( ) {} + virtual void fireSecondaryWeapon( ) {} + virtual void fireSpecial( ) {} + virtual void lockTarget( unsigned int objectID ) {} + + inline void activateMovementStabilisator( ) { this->enableMovementReduction( true ); } + inline void deactivateMovementStabilisator( ) { this->disableMovementReduction(); } + + void pitchUp( ); + void pitchDown( ); + void yawLeft( ); + void yawRight( ); + void rollLeft( ); + void rollRight( ); + + void thrustForward( ); + void thrustBackward( ); + void strafeLeft( ); + void strafeRight( ); + void climb( ); + void dive( ); + + void disableMovementReduction( ); + void enableMovementReduction( bool forceIt = false ); + + void disableRotationReduction( ); + void enableRotationReduction( bool forceIt = false ); + + virtual Result writeToKeyFrame( KeyFrame &buffer ) const; + + + const ::Oyster::Math::Float4x4 & getWorldPointMatrix( ) const; + const ::Oyster::Math::Float4x4 & getViewPointMatrix( ) const; + inline ::Oyster::Math::Float4x4 getWorldNormalMatrix( ) const { return this->getViewPointMatrix().getTranspose(); } + inline ::Oyster::Math::Float4x4 getViewNormalMatrix( ) const { return this->getWorldPointMatrix().getTranspose(); } + virtual void setOrientation( const ::Oyster::Math::Float4x4 & orientation ); + + protected: + static const InstanceBlueprint & getConfigData( unsigned int configID ); + + virtual void loadConfig( const InstanceBlueprint &config ); + + private: + unsigned int objectID, configID; + ::Oyster::Game::CollisionHandler::Reference physicsID; + ::Oyster::Math::Float mass; + int disableReduceMovementCount, disableReduceRotationCount; + + ::Oyster::Math::Float3 scaling; + mutable ::Oyster::Math::Float4x4 view, world; mutable bool viewIsOutOfDate, worldIsOutOfDate; + }; +} + +namespace Oyster { namespace Game +{ + template <> + bool CollisionHandler<::GameLogic::Object>::simpleCollisionConfirmation( const typename ::GameLogic::Object &entity, const ::Oyster::Collision::ICollideable *sampler ); +} } + +#endif \ No newline at end of file diff --git a/GameLogic/Player.cpp b/GameLogic/Player.cpp new file mode 100644 index 00000000..a4f619de --- /dev/null +++ b/GameLogic/Player.cpp @@ -0,0 +1,241 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#include "Player.h" +#include "Session.h" +#include "GameLUA.h" + +#include // TODO: to be removed + +using namespace ::GameLogic; +using namespace ::Oyster::Math; +using namespace ::Oyster::Collision; +using ::std::string; + +const unsigned char Player::noTeam = 255; + +Player::Player( ) : Object(), session(NULL), name(), playerID(-1), teamID(Player::noTeam), killCount(0), teamKillCount(0), deathCount(0), lockedTarget(NULL), hullPoints(255), shieldPoints(0), specialID(255), primaryWeapon(Weapon::Test), primaryWeaponCooldown(0.0f) {} +Player::Player( const Player &player ) : Object(player), session(player.session), name(player.name), playerID(player.playerID), teamID(player.teamID), killCount(player.killCount), teamKillCount(player.teamKillCount), deathCount(player.deathCount), lockedTarget(player.lockedTarget), hullPoints(player.hullPoints), shieldPoints(player.shieldPoints), specialID(player.specialID), primaryWeapon(player.primaryWeapon), primaryWeaponCooldown(player.primaryWeaponCooldown) {} +Player::Player( const Float4x4 &orientation, const Float3 ¢erOfMass ) : Object(orientation, centerOfMass), session(NULL), name(), playerID(-1), teamID(Player::noTeam), killCount(0), teamKillCount(0), deathCount(0), lockedTarget(NULL), hullPoints(255), shieldPoints(0), specialID(255), primaryWeapon(Weapon::Test), primaryWeaponCooldown(0.0f) {} +Player::Player( const Box &body, const Float3 ¢erOfMass ) : Object(body, centerOfMass), session(NULL), name(), playerID(-1), teamID(Player::noTeam), killCount(0), teamKillCount(0), deathCount(0), lockedTarget(NULL), hullPoints(255), shieldPoints(0), specialID(255), primaryWeapon(Weapon::Test), primaryWeaponCooldown(0.0f) {} +Player::~Player( ) {} + +Player & Player::operator = ( const Player &player ) +{ + Object::operator=( player ); + this->session = player.session; + this->name = player.name; + this->playerID = player.playerID; + this->teamID = player.teamID; + this->killCount = player.killCount; + this->teamKillCount = player.teamKillCount; + this->deathCount = player.deathCount; + this->hullPoints = player.hullPoints; + this->shieldPoints = player.shieldPoints; + this->specialID = player.specialID; + this->primaryWeapon = player.primaryWeapon; + this->primaryWeaponCooldown = player.primaryWeaponCooldown; + + return *this; +} + +Object * Player::clone( ) const +{ return new Player(*this); } + +void Player::update( float deltaTime ) +{ + Object::update( ); + + if (primaryWeaponCooldown > 0.0f) + primaryWeaponCooldown -= deltaTime; +} + +void Player::firePrimaryWeapon( ) +{ + if (primaryWeaponCooldown <= 0.0f) + GameLUA::executeOnFireScript( primaryWeapon, *this ); +} + +void Player::fireSecondaryWeapon( ) +{ + /* TODO */ +} + +void Player::fireSpecial( ) +{ + /* TODO */ +} + +void Player::lockTarget( unsigned int objectID ) +{ this->lockedTarget = this->session->objectIDLib[objectID]; } + +void Player::setPrimaryWeapon(Weapon::Type weapon) +{ + primaryWeapon = weapon; +} + +void Player::setPrimaryWeaponCooldown(float cooldown) +{ + primaryWeaponCooldown = cooldown; +} + +Object::Type Player::getType( ) const +{ return Object::Player; } + +const string & Player::getName( ) const +{ return this->name; } + +int Player::getPlayerID( ) const +{ + return this->playerID; +} + +unsigned char Player::getTeamID( ) const +{ return this->teamID; } + +unsigned int Player::getNumKills( ) const +{ return this->killCount; } + +unsigned int Player::getNumTeamKills( ) const +{ return this->teamKillCount; } + +unsigned int Player::getNumDeaths( ) const +{ return this->deathCount; } + +Session *Player::getSession( ) const +{ return this->session; } + +unsigned char Player::getHullPoints( ) const +{ return this->hullPoints; } + +unsigned char Player::getShieldPoints( ) const +{ return this->shieldPoints; } + +void Player::setName( const string &name ) +{ this->name = name; } + +void Player::setPlayerID( int id ) +{ + playerID = id; +} + +void Player::setTeam( unsigned char teamID ) +{ this->teamID = teamID; } + +void Player::setHullPoints( unsigned char value ) +{ + this->hullPoints = value; + + if( value == 0 ) + this->onDeath( *this ); +} + +void Player::setShieldPoints( unsigned char value ) +{ this->shieldPoints = value; } + +void Player::resetScores( ) +{ this->killCount = this->teamKillCount = this->deathCount = 0; } + +void Player::applyDamage( unsigned char magnitude, Object &attacker ) +{ + if( this->shieldPoints > 0 ) + { + magnitude = (unsigned char)(unsigned int)((float)magnitude * ( (float)this->shieldPoints / (float)this->getConfigData( this->getConfigID() ).shieldPoints )); + + if( magnitude == 0 ) + magnitude = 1; + + if( this->shieldPoints >= magnitude ) + { + this->shieldPoints -= magnitude; + return; + } + else + { + magnitude -= this->shieldPoints; + this->shieldPoints = 0; + } + } + + if( this->hullPoints <= magnitude ) + { + this->hullPoints = 0; + this->onDeath( attacker ); + } + else + this->hullPoints -= magnitude; +} + +void Player::applyHeal( unsigned char magnitude ) +{ + this->hullPoints += magnitude; + + unsigned int id = this->getConfigID(); + if( id != Object::invalidID ) + this->hullPoints = ::Utility::Value::min( this->hullPoints, (unsigned char)this->getConfigData(id).hullPoints ); +} + +void Player::onDeath( Object &killer ) +{ + killer.onKill( *this ); + ++this->deathCount; + Player* p = dynamic_cast(&killer); + Event::ShipDestroyed* e = new Event::ShipDestroyed(this->playerID,p->playerID); + for(int i=0;i < PLAYER_MAX_COUNT; ++i) + { + e->setScore(i,this->session->player[i].killCount, this->session->player[i].deathCount, this->session->player[i].teamKillCount); + } + this->session->eventList.push_back(e); + + this->moveToLimbo(); + + this->spawn(); +} + +void Player::onKill( Object &victim ) +{ + if( victim.getType() == Object::Player ) + { + Player *v = (Player*)&victim; + if( this->teamID == Player::noTeam || this->teamID != v->teamID ) + ++this->killCount; + else + ++this->teamKillCount; + } +} + +void Player::spawn( ) +{ + int num = (int)this->session->spawnPoint.size(); + this->stop(); + + if( num > 0 ) + { + int spawnRef = rand() % (int)num; + Box spawnZone = this->body; + unsigned int channel = (unsigned int)Object::Player; + + for( int i = 0; i < num; ++i ) + { + spawnZone.orientation = this->session->spawnPoint[spawnRef]; + if( this->session->world.collidesWithSomething(&channel, 1, &spawnZone) ) + spawnRef = (spawnRef + 1) % (int)num; + else + { + this->setOrientation( spawnZone.orientation ); + this->setConfig(this->getConfigID()); + this->releaseFromLimbo(); + return; + } + } + } + this->moveToLimbo(); +} + +void Player::loadConfig( const InstanceBlueprint &config ) +{ + Object::loadConfig( config ); + this->hullPoints = config.hullPoints; + this->shieldPoints = config.shieldPoints; +} \ No newline at end of file diff --git a/GameLogic/Player.h b/GameLogic/Player.h new file mode 100644 index 00000000..913cdde6 --- /dev/null +++ b/GameLogic/Player.h @@ -0,0 +1,83 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef GAMELOGIC_PLAYER_H +#define GAMELOGIC_PLAYER_H + +#include +#include "Object.h" +#include "Weapon.h" + +namespace GameLogic +{ + class Session; + + class Player : public Object + { + friend class Session; + public: + enum State { Vacant, Active, Dead, Limbo }; + static const unsigned char noTeam; + + Player( ); + Player( const Player &player ); + Player( const ::Oyster::Math::Float4x4 &orientation, const ::Oyster::Math::Float3 ¢erOfMass = ::Oyster::Math::Float3::null ); + Player( const ::Oyster::Collision::Box &body, const ::Oyster::Math::Float3 ¢erOfMass = ::Oyster::Math::Float3::null ); + virtual ~Player( ); + + Player & operator = ( const Player &player ); + virtual Object * clone( ) const; + + virtual void update( float deltaTime ); + + virtual void firePrimaryWeapon( ); + virtual void fireSecondaryWeapon( ); + virtual void fireSpecial( ); + virtual void lockTarget( unsigned int objectID ); + void setPrimaryWeapon(Weapon::Type weapon); + void setPrimaryWeaponCooldown(float cooldown); + + virtual Object::Type getType( ) const; + const ::std::string & getName( ) const; + int getPlayerID( ) const; + unsigned char getTeamID( ) const; + unsigned int getNumKills( ) const; + unsigned int getNumTeamKills( ) const; + unsigned int getNumDeaths( ) const; + Session *getSession( ) const; + unsigned char getHullPoints( ) const; + unsigned char getShieldPoints( ) const; + + void setName( const ::std::string &name ); + void setPlayerID( int id ); + void setTeam( unsigned char teamID ); + void setHullPoints( unsigned char value ); + void setShieldPoints( unsigned char value ); + void resetScores( ); + + virtual void applyDamage( unsigned char magnitude, Object &attacker ); + virtual void applyHeal( unsigned char magnitude ); + virtual void onDeath( Object &killer ); + virtual void onKill( Object &victim ); + + // teleports a player to a random unblocked spawnpoint and release from Limbo. Will end up in limbo if unable to find a spawnpoint + void spawn( ); + + protected: + virtual void loadConfig( const InstanceBlueprint &config ); + + private: + Session *session; + ::std::string name; + int playerID; + unsigned int killCount, teamKillCount, deathCount; + const Object *lockedTarget; + unsigned char teamID, hullPoints, shieldPoints, specialID; + Weapon::Type primaryWeapon; + float primaryWeaponCooldown; + }; +} + +#endif \ No newline at end of file diff --git a/GameLogic/Protocoll.cpp b/GameLogic/Protocoll.cpp new file mode 100644 index 00000000..150f7988 --- /dev/null +++ b/GameLogic/Protocoll.cpp @@ -0,0 +1,320 @@ +#include "Protocoll.h" + +KeyFrame::KeyFrame() +{ + numObjects=numParticles=0; +} + +KeyFrame::KeyFrame(char* data) +{ + int i = 0; + int size= sizeof(int); + int* nums = &this->numObjects; + memcpy(&numObjects,data,size); + i+=size; + memcpy(&numParticles,data+i,size); + i+=size; + size=sizeof(Player); + + memcpy(&Players,data+i,size*8); + i+=size*8; + + size = sizeof(Object); + memcpy(&Objects,data+i,size*numObjects); + i+=size*numObjects; + + size = sizeof(Effect); + memcpy(&Particle,&(data[i]),size*numParticles); + i+=size; +} + +int KeyFrame::GetSize() +{ + int i=1; + i+=sizeof(int)*2; + i+=sizeof(Player)*8; + i+=sizeof(Object)*numObjects; + i+=sizeof(Effect)*numParticles; + return i; +} + +void KeyFrame::Pack(char * startPointer) +{ + int i=0; + i+=sizeof(int)*2; + + memcpy(startPointer,this,sizeof(int)*2); + memcpy(startPointer+i,this->Players,sizeof(Player)*8); + i+=sizeof(Player)*8; + memcpy(startPointer+i,this->Objects,sizeof(Object)*numObjects); + i+=sizeof(Object)*numObjects; + memcpy(startPointer+i,this->Particle,sizeof(Effect)*numParticles); +} + +namespace Protocol +{ + using ::std::string; + using ::std::vector; + using ::std::map; + using ::Oyster::Math::Float4x4; + + Mesh::Mesh( const string &_objFile ) : objFile(_objFile) {} + + void Mesh::setObjFile( const string &fileName ) + { this->objFile = fileName; } + + const string & Mesh::getObjFileName( ) const + { return this->objFile; } + + unsigned int Mesh::getRequiredBufferSize( ) const + { return (unsigned int)(this->objFile.length() + 1); } + + void Mesh::fillBuffer( void *targetBuffer ) const + { + char *buffer = (char*)targetBuffer; + + for( unsigned int i = 0; i < this->objFile.length(); ++i ) + buffer[i] = this->objFile[i]; + buffer[this->objFile.length()] = '\0'; + } + + void Mesh::readFromBuffer( const void *buffer ) + { this->objFile = (const char*)buffer; } + + Object::Object( unsigned int _meshRef, const Float4x4 &_world ) + : meshRef(_meshRef), world(_world) {} + + void Object::setMeshRef( unsigned int ref ) + { this->meshRef = ref; } + + void Object::setWorldMatrix( const Float4x4 &matrix ) + { this->world = matrix; } + + unsigned int Object::getMeshRef( ) const + { return this->meshRef; } + + const Float4x4 & Object::getWorldMatrix( ) const + { return this->world; } + + unsigned int Object::getRequiredBufferSize( ) const + { return (unsigned int)(sizeof(unsigned int) + sizeof(Float4x4)); } + + void Object::fillBuffer( void *targetBuffer ) const + { + char *cBuffer = (char*)targetBuffer; + unsigned int *uiBuffer = (unsigned int*)targetBuffer; + + uiBuffer[0] = this->meshRef; + + cBuffer += sizeof(unsigned int); + + for( unsigned int i = 0; i < sizeof(Float4x4); ++i ) + cBuffer[i] = this->world.byte[i]; + } + + void Object::readFromBuffer( const void *buffer ) + { + const char *cBuffer = (const char*)buffer; + const unsigned int *uiBuffer = (const unsigned int*)buffer; + + this->meshRef = uiBuffer[0]; + + cBuffer += sizeof(unsigned int); + + for( unsigned int i = 0; i < sizeof(Float4x4); ++i ) + this->world.byte[i] = cBuffer[i]; + } + + MapRenderData::MapRenderData( ) + : mesh(), object(), index() + { this->requiredBufferSize = 2 * sizeof(unsigned int); } + + void MapRenderData::clear( ) + { + this->requiredBufferSize = 2 * sizeof(unsigned int); + this->mesh.clear(); + this->object.clear(); + this->index.clear(); + } + + void MapRenderData::add( const Float4x4 &worldMatrix, const string &objFile ) + { + unsigned int ref; + map::const_iterator i = this->index.find( objFile ); + if( i == this->index.end() ) + { + ref = this->index[objFile] = (unsigned int)this->mesh.size(); + this->mesh.push_back( Mesh(objFile) ); + this->requiredBufferSize += this->mesh[ref].getRequiredBufferSize(); + } + else ref = i->second; + + this->object.push_back( Object(ref, worldMatrix) ); + this->requiredBufferSize += this->object[this->object.size()-1].getRequiredBufferSize(); + } + + const vector & MapRenderData::getMeshList( ) const + { return this->mesh; } + + const vector & MapRenderData::getObjectList( ) const + { return this->object; } + + unsigned int MapRenderData::getRequiredBufferSize( ) const + { return this->requiredBufferSize; } + + void MapRenderData::fillBuffer( void *targetBuffer ) const + { + unsigned int *uiBuffer = (unsigned int*)targetBuffer; + uiBuffer[0] = (unsigned int)this->mesh.size(); + uiBuffer[1] = (unsigned int)this->object.size(); + + char *cBuffer = (char*)&uiBuffer[2]; + + for( vector::size_type i = 0; i < this->mesh.size(); ++i ) + { + this->mesh[i].fillBuffer( cBuffer ); + cBuffer += this->mesh[i].getRequiredBufferSize(); + } + + for( vector::size_type i = 0; i < this->object.size(); ++i ) + { + this->object[i].fillBuffer( cBuffer ); + cBuffer += this->object[i].getRequiredBufferSize(); + } + } + + void MapRenderData::readFromBuffer( const void *buffer ) + { + this->clear(); + + const unsigned int *uiBuffer = (const unsigned int*)buffer; + const char *cBuffer = (const char*)&uiBuffer[2]; + + this->mesh.reserve( uiBuffer[0] ); + for( unsigned int i = 0; i < uiBuffer[0]; ++i ) + { + vector::size_type ref = this->mesh.size(); + this->mesh.push_back( Mesh() ); + this->mesh[ref].readFromBuffer( cBuffer ); + this->requiredBufferSize += this->mesh[ref].getRequiredBufferSize(); + cBuffer += this->mesh[ref].getRequiredBufferSize(); + + this->index[this->mesh[ref].getObjFileName()] = (unsigned int)ref; + } + + this->object.reserve( uiBuffer[1] ); + for( unsigned int i = 0; i < uiBuffer[1]; ++i ) + { + vector::size_type ref = this->object.size(); + this->object.push_back( Object() ); + this->object[ref].readFromBuffer( cBuffer ); + this->requiredBufferSize += this->object[ref].getRequiredBufferSize(); + cBuffer += this->object[ref].getRequiredBufferSize(); + } + } + + + PlayerRenderData::PlayerRenderData( ) + : mesh(), playerMeshRef(), index() + { this->requiredBufferSize = (unsigned int)(2 * sizeof(unsigned int)); } + + void PlayerRenderData::clear( ) + { + this->requiredBufferSize = (unsigned int)(2 * sizeof(unsigned int)); + this->mesh.clear(); + this->playerMeshRef.clear(); + this->index.clear(); + } + + void PlayerRenderData::addPlayer( const string &objFile ) + { + unsigned int ref; + map::const_iterator i = this->index.find( objFile ); + if( i == this->index.end() ) + { + ref = this->index[objFile] = (unsigned int)this->mesh.size(); + this->mesh.push_back( Mesh(objFile) ); + this->requiredBufferSize += this->mesh[ref].getRequiredBufferSize(); + } + else ref = i->second; + + this->playerMeshRef.push_back( ref ); + this->requiredBufferSize += sizeof(unsigned int); + } + + const vector & PlayerRenderData::getMeshList( ) const + { return this->mesh; } + + const vector & PlayerRenderData::getPlayerMeshRefList( ) const + { return this->playerMeshRef; } + + unsigned int PlayerRenderData::getRequiredBufferSize( ) const + { return this->requiredBufferSize; } + + void PlayerRenderData::fillBuffer( void *targetBuffer ) const + { + unsigned int *uiBuffer = (unsigned int*)targetBuffer; + uiBuffer[0] = (unsigned int)this->mesh.size(); + uiBuffer[1] = (unsigned int)this->playerMeshRef.size(); + + char *cBuffer = (char*)&uiBuffer[2]; + + for( vector::size_type i = 0; i < this->mesh.size(); ++i ) + { + this->mesh[i].fillBuffer( cBuffer ); + cBuffer += this->mesh[i].getRequiredBufferSize(); + } + + uiBuffer = (unsigned int*)cBuffer; + for( vector::size_type i = 0; i < this->playerMeshRef.size(); ++i ) + { + *uiBuffer = this->playerMeshRef[i]; + ++uiBuffer; + } + } + + void PlayerRenderData::readFromBuffer( const void *buffer ) + { + this->clear(); + + const unsigned int *uiBuffer = (const unsigned int*)buffer; + const char *cBuffer = (const char*)&uiBuffer[2]; + + this->mesh.reserve( uiBuffer[0] ); + for( unsigned int i = 0; i < uiBuffer[0]; ++i ) + { + vector::size_type ref = this->mesh.size(); + this->mesh.push_back( Mesh() ); + this->mesh[ref].readFromBuffer( cBuffer ); + this->requiredBufferSize += this->mesh[ref].getRequiredBufferSize(); + cBuffer += this->mesh[ref].getRequiredBufferSize(); + + this->index[this->mesh[ref].getObjFileName()] = (unsigned int)ref; + } + + const unsigned int *uiBuffer2 = (const unsigned int*)cBuffer; + for( unsigned int i = 0; i < uiBuffer[1]; ++i ) + { + this->playerMeshRef.push_back( uiBuffer2[i] ); + this->requiredBufferSize += sizeof(unsigned int); + } + } + + RenderData::RenderData( ) : mapData(), playerData() {} + + void RenderData::fillBuffer( void *targetBuffer ) const + { + char *cBuffer = (char*)targetBuffer; + this->mapData.fillBuffer( cBuffer ); + cBuffer += this->mapData.getRequiredBufferSize(); + this->playerData.fillBuffer( cBuffer ); + } + + void RenderData::readFromBuffer( const void *buffer ) + { + const char *cBuffer = (const char*)buffer; + this->mapData.readFromBuffer( cBuffer ); + cBuffer += this->mapData.getRequiredBufferSize(); + this->playerData.readFromBuffer( cBuffer ); + } +} \ No newline at end of file diff --git a/GameLogic/Protocoll.h b/GameLogic/Protocoll.h new file mode 100644 index 00000000..72776de2 --- /dev/null +++ b/GameLogic/Protocoll.h @@ -0,0 +1,161 @@ +#pragma once +#include "OysterMath.h" + +using Oyster::Math::Float3; + +struct KeyFrame +{ + //header + //numobj cap?500 + + //per object + //id+rotationvec+movevec+ forwardvec+upvec+pos+typeID + + //per particle + //pos1,pos2,EffectID + + + //per player + //hp, shield, specialAmmo? + int numObjects,numParticles; + + struct Player + { + unsigned char Hp,Shield,Special; + }Players[8]; + + + struct Object + { + unsigned int id, TypeId; + Float3 RotationVec; + Float3 MoveVec; + Oyster::Math::Float4x4 World; + }Objects[500]; + + struct Effect + { + Float3 Head,Tail; + int EffectType; + }Particle[160]; + + //return number of bytes from start to send over network + //set numofobjects + void Pack(char * startPointer); + + int GetSize(); + + + + KeyFrame(); + + //unpacks the char array as if it was a compressed keyframe + KeyFrame(char* data); +}; + +#include +#include +#include +#include "OysterMath.h" + +namespace Protocol +{ + class Mesh + { + public: + Mesh( const ::std::string &objFile = "" ); + + void setObjFile( const ::std::string &fileName ); + + const ::std::string & getObjFileName( ) const; + unsigned int getRequiredBufferSize( ) const; + + void fillBuffer( void *targetBuffer ) const; + void readFromBuffer( const void *buffer ); + + private: + ::std::string objFile; + }; + + class Object + { + public: + Object( unsigned int meshRef = 0, const ::Oyster::Math::Float4x4 &world = ::Oyster::Math::Float4x4::identity ); + + void setMeshRef( unsigned int ref ); + void setWorldMatrix( const ::Oyster::Math::Float4x4 &matrix ); + + unsigned int getMeshRef( ) const; + const ::Oyster::Math::Float4x4 & getWorldMatrix( ) const; + unsigned int getRequiredBufferSize( ) const; + + void fillBuffer( void *targetBuffer ) const; + void readFromBuffer( const void *buffer ); + + private: + unsigned int meshRef; + ::Oyster::Math::Float4x4 world; + }; + + class MapRenderData + { + public: + MapRenderData( ); + + void clear( ); + void add( const ::Oyster::Math::Float4x4 &worldMatrix, const ::std::string &objFile ); + + const ::std::vector & getMeshList( ) const; + const ::std::vector & getObjectList( ) const; + unsigned int getRequiredBufferSize( ) const; + + void fillBuffer( void *targetBuffer ) const; + void readFromBuffer( const void *buffer ); + + private: + unsigned int requiredBufferSize; + ::std::vector mesh; + ::std::vector object; + ::std::map<::std::string, unsigned int> index; + }; + + class PlayerRenderData + { + public: + PlayerRenderData( ); + + void clear( ); + void addPlayer( const ::std::string &objFile ); + + const ::std::vector & getMeshList( ) const; + const ::std::vector & getPlayerMeshRefList( ) const; + unsigned int getRequiredBufferSize( ) const; + + void fillBuffer( void *targetBuffer ) const; + void readFromBuffer( const void *buffer ); + + private: + unsigned int requiredBufferSize; + ::std::vector mesh; + ::std::vector playerMeshRef; + ::std::map<::std::string, unsigned int> index; + }; + + class RenderData + { + public: + MapRenderData mapData; + PlayerRenderData playerData; + + RenderData( ); + + inline void RenderData::clear( ) + { this->mapData.clear(); this->playerData.clear(); } + + inline unsigned int RenderData::getRequiredBufferSize( ) const + { return this->mapData.getRequiredBufferSize() + this->playerData.getRequiredBufferSize(); } + + void fillBuffer( void *targetBuffer ) const; + void readFromBuffer( const void *buffer ); + }; +} \ No newline at end of file diff --git a/GameLogic/Session.cpp b/GameLogic/Session.cpp new file mode 100644 index 00000000..defb496e --- /dev/null +++ b/GameLogic/Session.cpp @@ -0,0 +1,576 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#include "Session.h" +#include "Bullet.h" +#include "GameLUA.h" +#include +#include +#include + +/* +// BENCHMARK BLOCK +#include "WinTimer.h" +#include +namespace Benchmark +{ + struct + { + double averageTime, totalTime, minTime, maxTime; unsigned int numSamples; + } timerData[10] = { 0.0f, 0.0f, ::std::numeric_limits::max(), -::std::numeric_limits::max(), 0 }; + + void sampleTime( const ::Utility::WinTimer &timer, unsigned char ref ) + { + double elapsedTime = timer.getElapsedSeconds(); + timerData[ref].totalTime += elapsedTime; + timerData[ref].minTime = ::Utility::Value::min( timerData[ref].minTime, elapsedTime ); + timerData[ref].maxTime = ::Utility::Value::max( timerData[ref].maxTime, elapsedTime ); + ++timerData[ref].numSamples; + timerData[ref].averageTime = timerData[ref].totalTime / (double) timerData[ref].numSamples; + } + + void print( ) + { + ::std::ofstream file; + file.open( "BenchMarkData.txt", ::std::ios_base::app | ::std::ios_base::out ); + + if( file.is_open() ) + { + file << "minTime\t\t: maxTime\t: averageTime\t\ttotalTime\tnumSamples\n"; + for( unsigned char i = 0; i < 3; ++i ) + file << timerData[i].minTime << (timerData[i].minTime == 0.0f ? "\t\t: " : "\t: ") << timerData[i].maxTime << "\t: " << timerData[i].averageTime << "\t\t" << timerData[i].totalTime << '\t' << timerData[i].numSamples <<'\n'; + file << ::std::endl; + file.close(); + ::std::cout << "Benchmark data saved." << ::std::endl; + } + } +} +// END BENCHMARK BLOCK /**/ + +using namespace ::GameLogic; +using namespace ::Oyster::Math; +using namespace ::Oyster::Collision; +using namespace ::Oyster::Game; +using ::std::string; +using ::std::set; +using ::std::vector; +using ::std::ifstream; +using ::std::istream; +using ::std::stringstream; + +namespace PrivateStatic +{ + enum Channel { Player, Static }; + + inline Float3 getPositionOf( const Object &object ) + { return object.getOrientation().v[3].xyz; } + + inline Float getPhysicalRangeOf( const Object &object ) + { return object.getSize().length() * 0.5f; } + + inline Sphere getBubbleOf( const Object &object ) + { return Sphere( getPositionOf(object), getPhysicalRangeOf(object) ); } + + void append( vector &destination, const vector &source ) + { + for( vector::size_type i = 0; i < source.size(); ++i ) + destination.push_back( source[i] ); + } + + void readOrientation( Float4x4 &output, istream &stream, const Float4x4 &transform ) + { + output = Float4x4::identity; + + ::Utility::Stream::readFloats( output.v[3], stream, 3 ); // position + ::Utility::Stream::readFloats( output.v[2], stream, 3 ); // forward + ::Utility::Stream::readFloats( output.v[1], stream, 3 ); // up + + transformVector( output.v[3], output.v[3], transform ); // position + + if( output.v[2].xyz != Float3::null && output.v[1].xyz != Float3::null ) + { + // forward + transformVector( output.v[2], output.v[2], transform ); + output.v[2].xyz.normalize(); + + // up + transformVector( output.v[1], output.v[1], transform ); + output.v[1].xyz -= vectorProjection( output.v[1].xyz, output.v[2].xyz ); + output.v[1].xyz.normalize(); + + // right + output.v[0].xyz = output.v[1].xyz.cross( output.v[2].xyz ).getNormalized(); + } + else + { + output.v[0].xyz = Float3::standardUnitX; + output.v[1].xyz = Float3::standardUnitY; + output.v[2].xyz = Float3::standardUnitZ; + } + } + + Session::InitResult loadWorldFile( vector &spawnPoints, vector &mapObjects, string &name, string &description, const string &fileName, const Float4x4 &transform ) + { + spawnPoints.resize( 0 ); + spawnPoints.reserve( 128 ); + mapObjects.resize( 0 ); + mapObjects.reserve( 1024 ); + + string workingDir; + ::Utility::String::extractDirPath( workingDir, fileName, '\\' ); + + ifstream file( fileName ); + if( file.is_open() ) + { + string str; + vector splitString; + stringstream subStream; + + if( !file.eof() ) ::std::getline( file, name ); + if( !file.eof() ) ::std::getline( file, str ); // gonna skip the handlername + if( !file.eof() ) + { + ::std::getline( file, description ); + ::Utility::String::split( splitString, description, "@@" ); + for( vector::size_type i = 0; i < splitString.size(); ++i ) + { + if( i != 0 ) subStream << '\n'; + subStream << ::Utility::String::trim( splitString[i] ); + } + + description = subStream.str(); + + subStream = stringstream(); + } + + while( !file.eof() ) + { + ::std::getline( file, str ); + + if( str.length() == 0 ) continue; + if( str[0] == '#' ) continue; + + splitString = vector(); + ::Utility::String::split( splitString, str, '#' ); + + if( splitString.size() == 0 ) continue; + if( splitString[0].length() == 0 ) continue; + + subStream = stringstream( splitString[0] ); + subStream >> str; + ::Utility::String::toLowerCase( str ); + + if( str == "obj" ) + { + vector notUsed; + subStream >> str; + Object::importEntities( notUsed, workingDir + ::Utility::String::replaceCharacters(str, '/', '\\') + ".entity", transform ); + } + else if( str == "o" ) + { + subStream >> str; + string lowerCased = str; + ::Utility::String::toLowerCase( lowerCased ); + if( lowerCased == "spawnpoint" ) + { + vector::size_type i = spawnPoints.size(); + spawnPoints.resize( i + 1 ); + readOrientation( spawnPoints[i], subStream, transform ); + } + else + { + Float4x4 orientation; + readOrientation( orientation, subStream, transform ); + + vector::size_type i = mapObjects.size(); + mapObjects.resize( i + 1 ); + + mapObjects[i].setConfig( str ); + if( mapObjects[i].getConfigID() == Object::invalidID ) + { // config handle not defined + mapObjects.resize( i ); + } + else + { + Float3 scale = Float3( 1.0f ); + ::Utility::Stream::readFloats( scale, subStream, 3 ); + + mapObjects[i].setScaling( scale ); + mapObjects[i].setOrientation( orientation ); + } + } + } + } + + file.close(); + return Session::Success; + } + + return Session::Failure; + } +} + +Session::Session( ) + : world(), effect(), objectIDLib(), state(MissingMap), player(), elapsedUpdatePeriod(0.0f), + spawnPoint(), staticObjects(), name(), description(), spawnPointOBJFile(), eventList(), nrPlayers(1), killsRequired(1) {} + +Session::~Session( ) +{ + if ( this->effect.size() > 0 ) + { + set::iterator i = this->effect.begin(), + end = this->effect.end(); + for( ; i != end; ++i ) + delete (*i); + } +} + +Session::InitResult Session::load( const string &cMapFile ) +{ + this->state = Loading; + + GameLUA::init(); + + this->effect = std::set(); + this->objectIDLib = ::std::map(); + + + Float4x4 transform; + { + Float scale = 0.1f; + rotationMatrix_AxisY( transform, ::Utility::Value::radian(180.0f) ); + transformMatrix( transform, scale * Float4x4::identity, transform ); + transform.m44 = 1.0f; + } + + string mapFile(cMapFile); + ::Utility::String::replaceCharacters( mapFile, '/', '\\' ); + + // importing world content + if( PrivateStatic::loadWorldFile( this->spawnPoint, this->staticObjects, this->name, this->description, mapFile, transform ) == Failure ) + { + this->state = MissingMap; + return Failure; + } + this->spawnPointOBJFile = Object::getConfig( "spawnpoint" ).objFileName; + + // importing player character content + vector terrariConfigs, eldarishConfigs; + { + srand(time(0)); + const char *terrariShipFiles[] = { "ship_TerrariCruiser.entity", "ship_TerrariInterceptor.entity", "ship_TerrariSniper.entity", "ship_TerrariSupport.entity" }; + const char *eldarishShipFiles[] = { "ship_EldarishCruiser.entity", "ship_EldarishInterceptor.entity", "ship_EldarishSniper.entity", "ship_EldarishSupport.entity" }; + + string workingDir; + ::Utility::String::extractDirPath( workingDir, mapFile, '\\' ); + workingDir += "..\\entities\\"; + + vector configIDOutput; + + for( unsigned int i = 0; i < ::Utility::StaticArray::numElementsOf(terrariShipFiles); ++i ) + { + if( Object::importEntities( configIDOutput, workingDir + terrariShipFiles[i], transform ) == Object::Failure ) + return Failure; + PrivateStatic::append( terrariConfigs, configIDOutput ); + } + + for( unsigned int i = 0; i < ::Utility::StaticArray::numElementsOf(eldarishShipFiles); ++i ) + { + if( Object::importEntities( configIDOutput, workingDir + eldarishShipFiles[i], transform ) == Object::Failure ) + return Failure; + PrivateStatic::append( eldarishConfigs, configIDOutput ); + } + } + + // resetting the physical world + this->world.emptyAndReInit( ::Utility::StaticArray::numElementsOf(this->player) + (unsigned int)this->staticObjects.size(), 2 ); + + // introduce players + for( unsigned char i = 0; i < ::Utility::StaticArray::numElementsOf(this->player); ++i ) + { + this->player[i].session = this; + this->player[i].setPlayerID(i); + this->objectIDLib[this->player[i].getObjectID()] = &this->player[i]; + + if( i % 2 == 0 ) + { // lives and dies for the eldarish henceforth! + this->player[i].setConfig( eldarishConfigs[::std::rand() % eldarishConfigs.size()] ); + this->player[i].setTeam( 0 ); + } + else + { // lives and dies for the terrari henceforth! + this->player[i].setConfig( terrariConfigs[::std::rand() % terrariConfigs.size()] ); + this->player[i].setTeam( 1 ); + } + + this->player[i].setPhysicsID( this->world.addEntity( PrivateStatic::Player, &this->player[i], PrivateStatic::getBubbleOf(this->player[i]) ) ); + this->player[i].moveToLimbo(); + + this->player[i].setPrimaryWeapon(Weapon::Test); + //this->player[i].setPrimaryWeapon(Weapon::Shotgun); + } + + // introduce static objects + for( vector::size_type i = 0; i < this->staticObjects.size(); ++i ) + { + this->objectIDLib[this->staticObjects[i].getObjectID()] = &this->staticObjects[i]; + this->staticObjects[i].setPhysicsID( this->world.addEntity( PrivateStatic::Static, &this->staticObjects[i], PrivateStatic::getBubbleOf(this->staticObjects[i]) ) ); + this->staticObjects[i].releaseFromLimbo(); + } + + this->state = Running; + return Success; +} + +unsigned char Session::getNumMaxPlayers( ) const +{ return ::Utility::StaticArray::numElementsOf(this->player); } + +Player & Session::accessPlayer( unsigned int id ) +{ + return this->player[id]; +} + +void Session::putInWorld( unsigned char playerID ) +{ this->player[playerID].releaseFromLimbo(); } + +void Session::putInLimbo( unsigned char playerID ) +{ this->player[playerID].moveToLimbo(); } + +void Session::addEffect( const EffectCarrier &effect ) +{ this->effect.insert( effect.clone() ); } + +const Session::State & Session::update( const Float &deltaTime ) +{ + float timeSlice = MoveAble::getDiscreteTimeSlice(); + this->elapsedUpdatePeriod += deltaTime; + this->state = Idle; + + // BENCHMARK BLOCK + //::Utility::WinTimer updateTimer; + // END BENCHMARK BLOCK + + while( this->elapsedUpdatePeriod >= timeSlice ) + { // only perform update at a certain discrete updatePeriodicy. Several times if needing to catch up + this->elapsedUpdatePeriod -= timeSlice; + this->state = Updated; + + // BENCHMARK BLOCK + //::Utility::WinTimer physicsTimer; + // END BENCHMARK BLOCK + + { // Update Effects + bool effectErased; + set::iterator i = this->effect.begin(), + end = this->effect.end(); + while(i != end) + { + effectErased = false; + + switch( (*i)->update( timeSlice ) ) + { + case EffectCarrier::Dead: + delete (*i); + i = this->effect.erase( i ); + effectErased = true; + + break; + case EffectCarrier::Armed: + { + switch( (*i)->getType() ) + { + case EffectCarrier::Bullet: + { + Bullet::BulletCollector collector( (const Line*)(*i)->getVolumeOfEffect(), ::Utility::StaticArray::numElementsOf(this->player) ); + unsigned int channel[] = { (unsigned int)Object::Player, (unsigned int)Object::Static }; + + this->world.visit( channel, ::Utility::StaticArray::numElementsOf(channel), (*i)->getVolumeOfEffect(), &collector ); + if( collector.hitObjects.size() > 0 ) + (*i)->onHit( collector.hitObjects, collector.hitPosW ); + } + break; + default: case EffectCarrier::Undefined: break; + } + } + break; + default: break; + } + + if (!effectErased) + i++; + } + } + + // BENCHMARK BLOCK + //Benchmark::sampleTime( physicsTimer, 1 ); + //physicsTimer.reset(); + // END BENCHMARK BLOCK + + { // Update Players + // Iterating Player vs Object Collision physics + unsigned int channel[] = { (unsigned int)Object::Player, (unsigned int)Object::Static }; + for( unsigned int i = 0; i < ::Utility::StaticArray::numElementsOf(this->player); ++i ) + if( this->player[i].isActive() ) + this->world.visit( channel, ::Utility::StaticArray::numElementsOf(channel), &this->player[i].body, &this->player[i], &Object::onCollisionAction ); + + // Apply accumulated physics and move players + for( unsigned int i = 0; i < ::Utility::StaticArray::numElementsOf(this->player); ++i ) + { + if( this->player[i].isActive() ) + this->player[i].update( timeSlice ); + else if( i < nrPlayers ) + this->player[i].spawn(); + } + } + + // BENCHMARK BLOCK + //Benchmark::sampleTime( physicsTimer, 2 ); + // END BENCHMARK BLOCK + + // TODO: recommended placement for powerUp manager update here + + // move everything to their proper collision positions + this->world.update(); + } + // How do we know when the game is over? + + //This is how you end the game + /* + //GameEnded constructors takes the winning team ID as a variable + Event::GameEnded* test = new Event::GameEnded(0); + for (int i=0; isetScore(i, player[i].getNumKills(), player[i].getNumDeaths(), player[i].getNumTeamKills()); + test->setScore(i, rand()%15, rand()%10, rand()%5); + } + //Sort the score properly (should be done clientside instead really) + test->sortScore(); + //Add it onto the event queue + eventList.push_back(test); + */ + + //Client will now realize that the game is over once this packet is received + + //printf("Exiting from update\n"); + + // BENCHMARK BLOCK + //Benchmark::sampleTime( updateTimer, 0 ); + // END BENCHMARK BLOCK + + // BENCHMARK BLOCK + //if( Benchmark::timerData[0].numSamples % 1000 == 0 ) + // Benchmark::print(); + // END BENCHMARK BLOCK + //Has a team won? Return -1 if not + int ct = CheckWinConditions(); + if( -1 < ct ) + { + Event::GameEvent *evt = new Event::GameEnded( ct ); + addEvent( evt ); + + this->state = Over; + } + return this->state; +} + +void Session::writeToKeyFrame( KeyFrame &buffer ) +{ + // resetting buffer + buffer.numObjects = buffer.numParticles = 0; + + // adding the Players + int numPlayers = ::Utility::Value::min( ::Utility::StaticArray::numElementsOf( this->player ), + ::Utility::StaticArray::numElementsOf( buffer.Players ) ); + for( int i = 0; i < numPlayers; ++i ) + { + buffer.Players[i].Hp = this->player[i].hullPoints; + buffer.Players[i].Shield = this->player[i].shieldPoints; + buffer.Players[i].Special = this->player[i].specialID; + + if( this->player[i].writeToKeyFrame( buffer ) == Object::Failure ) + break; + } + + // adding the particles + set::const_iterator i = this->effect.begin(), + end = this->effect.end(); + for( ; i != end; ++i ) + if( (*i)->writeToKeyFrame( buffer ) == EffectCarrier::Failure ) + break; +} + +void Session::writeToRenderResourceData( ::Protocol::RenderData &data ) +{ + data.clear(); + if( this->state == Session::Running ) + { + for( vector::size_type i = 0; i < this->staticObjects.size(); ++i ) + { if( Object::getConfig( this->staticObjects[i].getConfigID() ).objFileName.length() > 0 ) + data.mapData.add( this->staticObjects[i].getWorldPointMatrix(), Object::getConfig(this->staticObjects[i].getConfigID()).objFileName ); + } + + if( this->spawnPointOBJFile.length() > 0 ) + { for( vector::size_type i = 0; i < this->spawnPoint.size(); ++i ) + data.mapData.add( this->spawnPoint[i], this->spawnPointOBJFile ); + } + + for( unsigned int i = 0; i < ::Utility::StaticArray::numElementsOf(this->player); ++i ) + data.playerData.addPlayer( Object::getConfig( this->player[i].getConfigID() ).objFileName ); + } +} + +void Session::addEvent(Event::GameEvent *gameEvent) +{ + eventList.push_back(gameEvent); +} + +void Session::fetchEvents(std::vector &list) +{ + list=eventList; + eventList.resize(0); +} +void Session::fetchEffectData(std::vector &effData) +{ + // adding the effects + //int test= effect.size(); + //effData.resize(effect.size()); + //effData. + //int count=0; + effData.resize(0); + Network::EffectData tmp; + set::const_iterator i = this->effect.begin(), + end = this->effect.end(); + for( ; i != end; ++i ) + { + if( (*i)->writeToNetEffect( tmp ) != EffectCarrier::Failure ) + { + //effData[count]=tmp; + effData.push_back(tmp); + //count++; + //break; + } + } +} +int Session::CheckWinConditions() +{ + int count=0; + for (int i=0; i=killsRequired) + { + return 0; + } + count=0; + for (int i=1; i=killsRequired) + { + return 1; + } + return -1; +} \ No newline at end of file diff --git a/GameLogic/Session.h b/GameLogic/Session.h new file mode 100644 index 00000000..1a3c1e76 --- /dev/null +++ b/GameLogic/Session.h @@ -0,0 +1,72 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef GAME_SESSION_H +#define GAME_SESSION_H + +#include +#include +#include "OysterGame.h" +#include "OysterMath.h" +#include "Object.h" +#include "EffectCarrier.h" +#include "Player.h" +#include "Network.h" + +namespace GameLogic +{ + class Session + { + friend class Player; + public: + enum InitResult { Success, Failure }; + enum State { MissingMap, Loading, Running, Updated, Idle, Over }; + + Session( ); + ~Session( ); + + InitResult load( const ::std::string &mapFile ); + + unsigned char getNumMaxPlayers( ) const; + Player & accessPlayer( unsigned int id ); + void putInWorld( unsigned char playerID ); + void putInLimbo( unsigned char playerID ); + + void addEffect( const EffectCarrier &effect ); + + void writeToKeyFrame( KeyFrame &buffer ); + void writeToRenderResourceData( ::Protocol::RenderData &data ); + + const State & update( const ::Oyster::Math::Float &deltaTime ); + + void addEvent(Event::GameEvent *gameEvent); + void fetchEvents(std::vector &list); + void fetchEffectData(std::vector &effData); + + //No need for mutex etc, this should only be called before start + void setNrPlayers(int pc){nrPlayers=pc;} + void setKillsRequired(int kr){killsRequired=kr;} + + int CheckWinConditions(); + private: + //Different from max nr, it's the actual count + int nrPlayers; + int killsRequired; + ::Oyster::Game::CollisionHandler world; + ::std::set effect; + ::std::map objectIDLib; + State state; + Player player[8]; + ::Oyster::Math::Float elapsedUpdatePeriod; + + ::std::vector<::Oyster::Math::Float4x4> spawnPoint; + ::std::vector staticObjects; + ::std::string name, description, spawnPointOBJFile; + + std::vector eventList; + }; +} + +#endif \ No newline at end of file diff --git a/GameLogic/Ship.cpp b/GameLogic/Ship.cpp new file mode 100644 index 00000000..18154a36 --- /dev/null +++ b/GameLogic/Ship.cpp @@ -0,0 +1,66 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#include "Ship.h" +#include "OysterMath.h" +#include "SoundEngine.h" + +using namespace ::Game; +using namespace ::GameLogic; +using namespace ::Oyster; +using namespace ::Oyster::Math; + +Ship::Ship( const Float4x4 &orientation, const Float3 ¢erOfMass ) : + Object(orientation, centerOfMass), transform(Math::Float4x4::identity), worldOutOfDate(true), updatePeriod(0.0f) +{ + this->engineSound = SoundEngine::CreateSoundSource(); + this->engineSound->SetResource("..\\Content\\Sounds\\engine.wav"); + this->engineSound->SetLooping(true); + this->engineSound->SetVolume(1.0f); + //this->engineSound->Play(); +} + +Ship::~Ship( ) +{ + SoundEngine::DestroySoundSource(this->engineSound); +} + +void Ship::update( const ::Oyster::Math::Float &deltaTime ) +{ + this->updatePeriod += deltaTime; + if( this->updatePeriod >= MoveAble::getDiscreteTimeSlice() ) + { + this->updatePeriod -= MoveAble::getDiscreteTimeSlice(); + Object::update( ); + } + + Math::transformMatrix( this->world, this->transform, this->body.orientation ); + this->worldOutOfDate = false; + + this->engineSound->SetPosition( this->body.orientation.v[3] ); +} + +const Math::Float4x4 & Ship::getWorldMatrix( ) const +{ + if( this->worldOutOfDate ) + { + Math::transformMatrix( this->world, this->transform, this->body.orientation ); + this->worldOutOfDate = false; + } + return this->world; +} + +void Ship::setMutation( const Math::Float4x4 &matrix ) +{ + this->transform = matrix; + this->worldOutOfDate = true; +} + +void Ship::applyDamage( unsigned int magnitude, const Object &attacker ) +{ +} + +void Ship::applyHeal( unsigned int magnitude ) +{ +} diff --git a/GameLogic/Ship.h b/GameLogic/Ship.h new file mode 100644 index 00000000..90932600 --- /dev/null +++ b/GameLogic/Ship.h @@ -0,0 +1,37 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef GAME_SHIP_H +#define GAME_SHIP_H + +#include "Object.h" +#include "SoundSource.h" + +namespace Game +{ + class Ship : public ::GameLogic::Object + { + public: + Ship( const ::Oyster::Math::Float4x4 &orientation = ::Oyster::Math::Float4x4::identity, const ::Oyster::Math::Float3 ¢erOfMass = ::Oyster::Math::Float3::null ); + virtual ~Ship( ); + + virtual void update( const ::Oyster::Math::Float &deltaTime ); + const ::Oyster::Math::Float4x4 & getWorldMatrix( ) const; + void setMutation( const ::Oyster::Math::Float4x4 &matrix ); + + virtual void applyDamage( unsigned int magnitude, const Object &attacker ); + virtual void applyHeal( unsigned int magnitude ); + + private: + ::Oyster::Math::Float4x4 transform; + mutable ::Oyster::Math::Float4x4 world; + mutable bool worldOutOfDate; + ::Oyster::Math::Float updatePeriod; + + SoundSource *engineSound; + }; +} + +#endif \ No newline at end of file diff --git a/GameLogic/Weapon.cpp b/GameLogic/Weapon.cpp new file mode 100644 index 00000000..e82cc30e --- /dev/null +++ b/GameLogic/Weapon.cpp @@ -0,0 +1,12 @@ +#include + +#include "Weapon.h" + +using namespace GameLogic; + +const Weapon Weapon::weapons[Weapon::Count] = +{ + {"../Content/Scripts/weapon_test.lua", "test_OnFire", "test_OnUpdate", "test_OnHit"}, // WeaponType::Test + {"../Content/Scripts/weapon_shotgun.lua", "shotgun_OnFire", "shotgun_OnUpdate", "shotgun_OnHit"}, // WeaponType::Shotgun + {"../Content/Scripts/PowerUpManager.lua", "PowerUp_OnFire", "PowerUp_OnUpdate", "PowerUp_OnHit"} // WeaponType::PowerUpManager +}; diff --git a/GameLogic/Weapon.h b/GameLogic/Weapon.h new file mode 100644 index 00000000..b32ba5df --- /dev/null +++ b/GameLogic/Weapon.h @@ -0,0 +1,28 @@ +#ifndef WEAPON_H +#define WEAPON_H + +namespace GameLogic +{ + class Weapon + { + public: + enum Type + { + Test = 0, + Shotgun, + Powerup, + Count, + Undefined + }; + + const char *scriptFile; + const char *onFireFunction; + const char *onUpdateFunction; + const char *onHitFunction; + + public: + static const Weapon weapons[Weapon::Count]; + }; +}; + +#endif diff --git a/Into The Void client/GameEndedMenu.cpp b/Into The Void client/GameEndedMenu.cpp new file mode 100644 index 00000000..635681bb --- /dev/null +++ b/Into The Void client/GameEndedMenu.cpp @@ -0,0 +1,114 @@ +#include "GameEndedMenu.h" +#include "RenderEngine.h" +#include "Input\InputController.h" +#include "Window\Window.h" +#include "Lobby.h" + +Oyster::Math::Float3 MainMenuPos, WinnerPos; + + + + +GameEndedMenu::GameEndedMenu(Player *players[], Score* scores, int winningTeam) +{ + m_stateStack = NULL; + winner=winningTeam; + for (int i=0; i< PLAYER_MAX_COUNT; i++) + { + this->scoreboard[i]=scores[i]; + playerList[i]=players[i]; + } +} + +GameEndedMenu::~GameEndedMenu() +{ +} + +void GameEndedMenu::Enter(GameStateStack *stateStack) +{ + + Oyster::Input::Controller::OrigoTopLeft(); + Oyster::Input::Controller::RestrictMouse(false); + + m_stateStack = stateStack; + + Oyster::Math::Float2 windowSize; + windowSize.x = (float)Oyster::Window::Size.right; + windowSize.y = (float)Oyster::Window::Size.top; + + D3DX11CreateShaderResourceViewFromFile(Oyster::Core::Device, "..\\Content\\GUI\\button_darkblue_250x64.png", NULL, NULL, &m_quitTextures[0], NULL); + D3DX11CreateShaderResourceViewFromFile(Oyster::Core::Device, "..\\Content\\GUI\\button_250x64.png", NULL, NULL, &m_quitTextures[1], NULL); + D3DX11CreateShaderResourceViewFromFile(Oyster::Core::Device, "..\\Content\\GUI\\lobby_bg_screen.png", NULL, NULL, &m_backgroundOverlay.texture, NULL); + + m_backgroundOverlay.size = windowSize; + m_backgroundOverlay.position.x = 0.0f; + m_backgroundOverlay.position.y = 0.0f; + m_backgroundOverlay.position.z = 0.5f; + + + + m_quitOverlay.texture = m_quitTextures[0]; + m_quitOverlay.size = Oyster::Math::Float2(132.0f, 83.0f); + m_quitOverlay.position.x = windowSize.x / 2.0f - m_quitOverlay.size.x / 2.0f; + m_quitOverlay.position.y = windowSize.y - m_quitOverlay.size.y - 20.0f; + m_quitOverlay.position.z = 0.0f; + + MainMenuPos = m_quitOverlay.position; + MainMenuPos.x+=10; + MainMenuPos.y+=5; + + WinnerPos.x = 120.0f; + WinnerPos.y = 10.0f; + WinnerPos.z = 0.0f; +} + +void GameEndedMenu::Exit() +{ + m_stateStack = NULL; +} + +void GameEndedMenu::Suspend() +{ +} + +void GameEndedMenu::Resume() +{ + Oyster::Input::Controller::OrigoTopLeft(); + Oyster::Input::Controller::RestrictMouse(false); +} + +void GameEndedMenu::Update(float timeDelta) +{ + + Oyster::Math::Float2 cursorPosition = Oyster::Math::Float2((float)Oyster::Input::Controller::GetX(), (float)Oyster::Input::Controller::GetY()); + + + + if (IntersectsOverlay(m_quitOverlay, cursorPosition)) + m_quitOverlay.texture = m_quitTextures[1]; + else + m_quitOverlay.texture = m_quitTextures[0]; + + if (Oyster::Input::Controller::isMouseBtnPressed(MK_LBUTTON)) + { + if (IntersectsOverlay(m_quitOverlay, cursorPosition)) + { + m_stateStack->SetState(new MainMenu()); + } + } +} + +void GameEndedMenu::Render() const +{ + RenderEngine::RenderScoreboard(this->scoreboard, PLAYER_MAX_COUNT, playerList); + Oyster::Engine::PrepareForRendering::Begin2DTextRender(); + //Oyster::Engine::Render::Text("Into The Void!",Oyster::Math::Float2(20,50), TitlePos); + Oyster::Engine::Render::Text(SSTR("Team "< + +#include "GameState.h" +#include "OysterMath.h" +#include "RenderEngine.h" +#include "NetworkConstants.h" +#include "NetworkMiscFunctions.h" +#include "MainMenu.h" + + + + +class GameEndedMenu : public GameState +{ +public: + GameEndedMenu(Player *players[], Score* scores, int winningTeam); + virtual ~GameEndedMenu(); + + void Enter(GameStateStack *stateStack); + void Exit(); + + void Suspend(); + void Resume(); + + void Update(float timeDelta); + void Render() const; + +private: + int winner; + Score scoreboard[PLAYER_MAX_COUNT]; + Player *playerList[PLAYER_MAX_COUNT]; + GameStateStack *m_stateStack; + + ID3D11ShaderResourceView *m_quitTextures[2]; + + Overlay m_backgroundOverlay; + Overlay m_quitOverlay; +}; diff --git a/Into The Void client/GameState.h b/Into The Void client/GameState.h new file mode 100644 index 00000000..fcf12494 --- /dev/null +++ b/Into The Void client/GameState.h @@ -0,0 +1,33 @@ +#pragma once +#ifndef GAMESTATE_H +#define GAMESTATE_H + +#include "GameStateStack.h" + +class GameState +{ +public: + virtual ~GameState() {} + + virtual void Enter(GameStateStack *stateStack) = 0; + virtual void Exit() = 0; + + virtual void Suspend() = 0; + virtual void Resume() = 0; + + virtual void Update(float timeDelta) = 0; + virtual void Render() const = 0; + + // If this function returns true, the GameState will recieve updates even while it's suspended. + virtual bool WantsBackgroundUpdates() const + { + return false; + } + + virtual bool IsTransparent() const + { + return false; + } +}; + +#endif diff --git a/Into The Void client/GameStateStack.cpp b/Into The Void client/GameStateStack.cpp new file mode 100644 index 00000000..3bd62afb --- /dev/null +++ b/Into The Void client/GameStateStack.cpp @@ -0,0 +1,114 @@ +#include +#include + +#include "GameStateStack.h" +#include "GameState.h" + +GameStateStack::GameStateStack(GameState *initialState) +{ + PushState(initialState); +} + +GameStateStack::~GameStateStack() +{ + GameState *state; + + while(!m_stack.empty()) + { + state = m_stack.back(); + m_stack.pop_back(); + + state->Exit(); + delete state; + } +} + +void GameStateStack::Update(float timeDelta) +{ + if (m_stack.empty()) + return; + + m_stack.back()->Update(timeDelta); + + for(int i = 0; i < std::max((int)m_stack.size() - 1, 0); i++) + { + if (m_stack[i]->WantsBackgroundUpdates()) + m_stack[i]->Update(timeDelta); + } +} + +void GameStateStack::Render() +{ + if (m_stack.empty()) + return; + + size_t lastOpaque = m_stack.size() - 1; + + while(lastOpaque > 0 && m_stack[lastOpaque]->IsTransparent()) + { + lastOpaque--; + } + + for(size_t i = lastOpaque; i < m_stack.size(); i++) + { + m_stack[i]->Render(); + } +} + +GameState *GameStateStack::CurrentState() +{ + return m_stack.back(); +} + +size_t GameStateStack::GetStackSize() +{ + return m_stack.size(); +} + +bool GameStateStack::isEmpty() +{ + return m_stack.empty(); +} + +void GameStateStack::SetState(GameState *state) +{ + GameState *oldState; + + while(!m_stack.empty()) + { + oldState = m_stack.back(); + m_stack.pop_back(); + + oldState->Exit(); + delete oldState; + } + + if (state) + { + m_stack.push_back(state); + state->Enter(this); + } +} + +void GameStateStack::PushState(GameState *state) +{ + if (!m_stack.empty()) + m_stack.back()->Suspend(); + + m_stack.push_back(state); + state->Enter(this); +} + +void GameStateStack::PopState() +{ + assert(!m_stack.empty()); + + GameState *state = m_stack.back(); + m_stack.pop_back(); + + state->Exit(); + delete state; + + if (!m_stack.empty()) + m_stack.back()->Resume(); +} diff --git a/Into The Void client/GameStateStack.h b/Into The Void client/GameStateStack.h new file mode 100644 index 00000000..69eeb312 --- /dev/null +++ b/Into The Void client/GameStateStack.h @@ -0,0 +1,34 @@ +#pragma once +#ifndef GAMESTATESTACK_H +#define GAMESTATESTACK_H + +#include + +class GameState; + +class GameStateStack +{ +public: + GameStateStack(GameState *initialState); + virtual ~GameStateStack(); + + void Update(float timeDelta); + void Render(); + + GameState *CurrentState(); + size_t GetStackSize(); + + bool isEmpty(); + + // The GameStateStack takes ownership of the state when it's pushed on the stack, and will delete it when it's popped. + + // SetState pops all gamestates currently on the stack and then pushes the new state on the stack. + void SetState(GameState *state); + void PushState(GameState *state); + void PopState(); + +private: + std::vector m_stack; +}; + +#endif diff --git a/Into The Void client/GraphicStructs.h b/Into The Void client/GraphicStructs.h new file mode 100644 index 00000000..2ea259bd --- /dev/null +++ b/Into The Void client/GraphicStructs.h @@ -0,0 +1,25 @@ +#pragma once +#ifndef GRAHIC_STRUCTS_H +#define GRAHIC_STRUCTS_H + +#include "OysterCollision.h" + +namespace GraphicStruct +{ + + struct PointLight + { + struct{ ::Oyster::Math::Float3 center; ::Oyster::Math::Float radius; } pos; + ::Oyster::Math::Float3 color; + ::Oyster::Math::Float intensty; + }; + + struct LightData + { + ::Oyster::Math::Float4x4 viewMatrix, projectionMatrix; + ::LinearAlgebra::Vector3 numDispatches; + unsigned int reservedPadding; + }; +} + +#endif \ No newline at end of file diff --git a/Into The Void client/IngameMenu.cpp b/Into The Void client/IngameMenu.cpp new file mode 100644 index 00000000..70666565 --- /dev/null +++ b/Into The Void client/IngameMenu.cpp @@ -0,0 +1,120 @@ +#include "IngameMenu.h" +#include "RenderEngine.h" +#include "Input\InputController.h" +#include "Window\Window.h" + +IngameMenu::IngameMenu() +{ + m_stateStack = NULL; + m_backgroundOverlay.texture=NULL; + m_resumeOverlay.texture=NULL; + m_disconnectOverlay.texture=NULL; +} + +IngameMenu::~IngameMenu() +{ + SAFE_RELEASE(m_textures[0]); + SAFE_RELEASE(m_textures[1]); + SAFE_RELEASE(m_textures[2]); +} + +void IngameMenu::Enter(GameStateStack *stateStack) +{ + Oyster::Input::Controller::OrigoTopLeft(); + Oyster::Input::Controller::RestrictMouse(false); + + m_stateStack = stateStack; + + Oyster::Math::Float2 windowSize; + windowSize.x = (float)Oyster::Window::Size.right; + windowSize.y = (float)Oyster::Window::Size.top; + + D3DX11CreateShaderResourceViewFromFile(Oyster::Core::Device, "..\\Content\\Gui\\button_darkblue_250x64.png", NULL, NULL, &m_textures[0], NULL); + D3DX11CreateShaderResourceViewFromFile(Oyster::Core::Device, "..\\Content\\Gui\\button_250x64.png", NULL, NULL, &m_textures[1], NULL); + D3DX11CreateShaderResourceViewFromFile(Oyster::Core::Device, "..\\Content\\Gui\\lobby_bg_screen.png", NULL, NULL, &m_textures[2], NULL); + + m_backgroundOverlay.texture = m_textures[2]; + m_backgroundOverlay.size = Oyster::Math::Float2(350.0f, 200.0f); + m_backgroundOverlay.position.x = windowSize.x / 2.0f - m_backgroundOverlay.size.x / 2.0f; + m_backgroundOverlay.position.y = windowSize.y / 2.0f - m_backgroundOverlay.size.y / 2.0f; + m_backgroundOverlay.position.z = 0.01f; + + m_resumeOverlay.texture = m_textures[0]; + m_resumeOverlay.size = Oyster::Math::Float2(256.0f, 64.0f); + m_resumeOverlay.position.x = m_backgroundOverlay.position.x + (m_backgroundOverlay.size.x - m_resumeOverlay.size.x) / 2.0f; + m_resumeOverlay.position.y = m_backgroundOverlay.position.y + 20.0f; + m_resumeOverlay.position.z = 0.0f; + + m_disconnectOverlay.texture = m_textures[0]; + m_disconnectOverlay.size = Oyster::Math::Float2(256.0f, 64.0f); + m_disconnectOverlay.position.x = m_backgroundOverlay.position.x + (m_backgroundOverlay.size.x - m_disconnectOverlay.size.x) / 2.0f; + m_disconnectOverlay.position.y = m_resumeOverlay.position.y + m_resumeOverlay.size.y + 40.0f; + m_disconnectOverlay.position.z = 0.0f; +} + +void IngameMenu::Exit() +{ + m_stateStack = NULL; +} + +void IngameMenu::Suspend() +{ +} + +void IngameMenu::Resume() +{ + Oyster::Input::Controller::OrigoTopLeft(); + Oyster::Input::Controller::RestrictMouse(false); +} + +void IngameMenu::Update(float timeDelta) +{ + if (Oyster::Input::Controller::isKeyPressed(VK_ESCAPE)) + { + m_stateStack->PopState(); + return; + } + + Oyster::Math::Float2 cursorPosition = Oyster::Math::Float2((float)Oyster::Input::Controller::GetX(), (float)Oyster::Input::Controller::GetY()); + + if (IntersectsOverlay(m_resumeOverlay, cursorPosition)) + m_resumeOverlay.texture = m_textures[1]; + else + m_resumeOverlay.texture = m_textures[0]; + + if (IntersectsOverlay(m_disconnectOverlay, cursorPosition)) + m_disconnectOverlay.texture = m_textures[1]; + else + m_disconnectOverlay.texture = m_textures[0]; + + if (Oyster::Input::Controller::isMouseBtnPressed(MK_LBUTTON)) + { + if (IntersectsOverlay(m_resumeOverlay, cursorPosition)) + { + m_stateStack->PopState(); + return; + } + else if (IntersectsOverlay(m_disconnectOverlay, cursorPosition)) + { + m_stateStack->SetState(new MainMenu()); + return; + } + } +} + +void IngameMenu::Render() const +{ + Oyster::Engine::Render::Text("Resume", Float2(15.0f, 30.0f), m_resumeOverlay.position + Float3(15.0f,5.0f,0)); + Oyster::Engine::Render::Text("Disconnect", Float2(10.0f, 30.0f), m_disconnectOverlay.position + Float3(15.0f,5.0f,0)); + + Oyster::Engine::PrepareForRendering::Begin2DRender(); + + Oyster::Engine::Render::Sprite(m_backgroundOverlay.texture, m_backgroundOverlay.size, m_backgroundOverlay.position); + Oyster::Engine::Render::Sprite(m_resumeOverlay.texture, m_resumeOverlay.size, m_resumeOverlay.position); + Oyster::Engine::Render::Sprite(m_disconnectOverlay.texture, m_disconnectOverlay.size, m_disconnectOverlay.position); +} + +bool IngameMenu::IsTransparent() const +{ + return true; +} diff --git a/Into The Void client/IngameMenu.h b/Into The Void client/IngameMenu.h new file mode 100644 index 00000000..825db60f --- /dev/null +++ b/Into The Void client/IngameMenu.h @@ -0,0 +1,35 @@ +#pragma once + +#include + +#include "GameState.h" +#include "OysterMath.h" +#include "RenderEngine.h" +#include "MainMenu.h" + +class IngameMenu : public GameState +{ +public: + IngameMenu(); + virtual ~IngameMenu(); + + void Enter(GameStateStack *stateStack); + void Exit(); + + void Suspend(); + void Resume(); + + void Update(float timeDelta); + void Render() const; + + bool IsTransparent() const; + +private: + GameStateStack *m_stateStack; + + ID3D11ShaderResourceView *m_textures[3]; + + Overlay m_backgroundOverlay; + Overlay m_resumeOverlay; + Overlay m_disconnectOverlay; +}; diff --git a/Into The Void client/IntoTheVoid.cpp b/Into The Void client/IntoTheVoid.cpp new file mode 100644 index 00000000..8e5a5bf1 --- /dev/null +++ b/Into The Void client/IntoTheVoid.cpp @@ -0,0 +1,530 @@ +#include + +#include "IntoTheVoid.h" +#include "Player.h" +#include "UserInterface.h" +#include "RenderEngine.h" +#include "SoundSystem.h" +#include "NetworkConnection.h" +#include "NetworkUpdateStructs.h" +#include "IngameMenu.h" +#include "Misc\Utilities.h" +#include "Input\InputController.h" +#include "Protocoll.h" + +#include "Session.h" + +using namespace ::Oyster::Math; + +void loadPlayerResources( Player **player, int shipID[], const ::Protocol::RenderData &renderData, const Float4x4 &transform ); + +IntoTheVoid::IntoTheVoid(NetworkConnection *connection) + : updatePeriod(1.0f), elapsedUpdatePeriod(0.0f), readOnly(false), + camera(NULL), isSuspended(true) +{ + assert(connection->getConnectionStatus() == ONLINE_INGAME); + + this->connection = connection; + this->connection->setIntoTheVoid(this); + + for(int i = 0; i < MAX_PLAYERS; i++) + { + this->players[i] = NULL; + } + + this->staticObject.num = 0; + this->staticObject.model = NULL; + this->staticObject.world = NULL; + + Initialized = false; +} + +IntoTheVoid::~IntoTheVoid() +{ + if( this->connection ) + { + this->connection->disconnect(); + delete this->connection; + } + + for(int i = 0; i < MAX_PLAYERS; i++) + { + if (this->players[i]) + delete this->players[i]; + } + + if( this->staticObject.model ) + { + /*for( unsigned int i = 0; i < this->staticObject.num; ++i ) + { + ::std::vector::size_type j = 0; + for( ; j < this->staticObject.model[i].Material.size(); ++i ) + this->staticObject.model[i].Material[j]->Release(); + }*/ + + delete [] this->staticObject.model; + } + if( this->staticObject.world ) + delete [] this->staticObject.world; + + if( this->camera ) delete this->camera; +} + +void IntoTheVoid::Enter(GameStateStack *stateStack) +{ + Oyster::Input::Controller::OrigoCenter(); + Oyster::Input::Controller::RestrictMouse(true); + + gameRunning=true; + this->isSuspended = false; + this->stateStack = stateStack; + + // setting up the update periodicy + this->updatePeriod = 1.0f / 120.0f; + this->elapsedUpdatePeriod = 0.0f; + ::Oyster::Game::MoveAble::setDiscreteTimeSlice( this->updatePeriod ); + + this->isFirstUpdate = true; + + this->SetRenderData( *this->connection->GetRenderData() ); + delete this->connection->GetRenderData(); + + this->playerID = connection->getPlayerID(); + LobbyInitData lobbyData = this->connection->getLobbyData(); + + for(int i = 0; i < MAX_PLAYERS; i++) + { + this->players[i]->setName(lobbyData.players[i].usrName); + + this->scores[i].id = i; + this->scores[i].kills = 0; + this->scores[i].deaths = 0; + this->scores[i].teamkills = 0; + } + + // Set the local player's weapon sound to always be where the listener is. Otherwise + // if we are we are moving fast the listener's and weapon sound's positions will slightly + // move relative to each other every update, causing crackling to be heard. + //this->players[this->playerID]->getWeaponSound()->SetIsRelativeToListener(true); + //this->players[this->playerID]->getWeaponSound()->SetPosition(Float3::null.element); + + //this->self.accessShip().movementProperty = players[this->playerID]->accessShip().movementProperty; + //this->self.accessShip().rotationProperty = players[this->playerID]->accessShip().rotationProperty; + + if( this->camera == NULL ) + { // only create a camera if there is none there already + + ::Oyster::Math::Float distance, + nearClip = 128.0f, + farClip = 102400.0f; + + switch( this->playerID ) + { + case 0: distance = nearClip + 256.0f; break; + case 1: distance = nearClip + 256.0f; break; + case 2: distance = nearClip + 256.0f; break; + case 3: distance = nearClip + 256.0f; break; + case 4: distance = nearClip + 256.0f; break; + case 5: distance = nearClip + 256.0f; break; + case 6: distance = nearClip + 256.0f; break; + case 7: distance = nearClip + 256.0f; break; + default: distance = nearClip; break; + } + + Float4x4 projection; + camera = new TailCamera( players[this->playerID]->accessShip().getOrientation(), Float3(0.0f, 0.0f, -distance), Float3(0.0f, 1.0f, 0.0f), Float4x4::identity ); + ::Oyster::Math::projectionMatrix_Perspective( projection, 3.14f * 0.4f,( ::Oyster::Window::Size.right / (float)::Oyster::Window::Size.top), nearClip, farClip ); + camera->setProjection( projection ); + camera->setMaxOffsetDistance( 10.0f ); + camera->setMaxOffsetRadian( ::Utility::Value::radian(20.0f) ); // +-20 degrees + } + connection->doneLoading(); + this->Initialized=true; +} + +void IntoTheVoid::Exit() +{ + if( this->connection ) + { + this->connection->disconnect(); + delete this->connection; + this->connection = NULL; + } + + for(int i = 0; i < MAX_PLAYERS; i++) + { + if( this->players[i] ) + { + delete this->players[i]; + this->players[i] = NULL; + } + } + + if( this->camera ) { delete this->camera; this->camera = NULL; } + + this->stateStack = NULL; + this->isSuspended = true; +} + +void IntoTheVoid::Suspend() +{ + this->isSuspended = true; +} + +void IntoTheVoid::Resume() +{ + Oyster::Input::Controller::OrigoCenter(); + Oyster::Input::Controller::RestrictMouse(true); + + this->isSuspended = false; +} + +bool IntoTheVoid::WantsBackgroundUpdates() const +{ + return true; +} + +void IntoTheVoid::Update(float timeDelta) +{ + // ignorera den första uppdateringen då timeDelta är på flera sekunder för att vi har laddat in alla resurser. + if (this->isFirstUpdate) + { + for(int i =0; iplayers[i]->accessShip().setOrientation(connection->getPosition(i)); + this->isFirstUpdate = false; + return; + } + + if (Oyster::Input::Controller::isKeyPressed(VK_ESCAPE)) + this->stateStack->PushState(new IngameMenu()); + + ClientToServerUpdateData update; + + if (!this->isSuspended) + UserInterface::Update(*camera, timeDelta, update); + + int owner; + //Event::BulletCreated *bulletCreated; + //Event::BulletHit *bulletHit; + std::vector eventList; + connection->fetchEvents(eventList); + + for(size_t i = 0; i < eventList.size(); i++) + { + switch(Event::getEventType(eventList[i])) + { + case Event::eBulletCreated: + { + Event::BulletCreated* bulletCreated = (Event::BulletCreated *)eventList[i]; + owner = ((Event::BulletCreated *)eventList[i])->GetOwner();/*bulletCreated->GetOwner();*/ + + //if (!players[owner]->getWeaponSound()->IsPlaying()) + //players[owner]->getWeaponSound()->Play(); + + //bulletCreated->getPosition(); + + break; + } + case Event::eBulletHit: + //bulletHit = (Event::BulletHit *)eventList[i]; + + if (((Event::BulletHit *)eventList[i])->getHitTargetID() == playerID) + { + RenderEngine::Damaged(); + } + break; + case Event::eShipSpawned: + break; + case Event::eShipDestroyed: + { + Event::ShipDestroyed* e = (Event::ShipDestroyed*)eventList[i]; + Oyster::Math::Float4x4 m = players[e->getDestroyedID()]->accessShip().getOrientation(); + + players[e->getDestroyedID()]->accessShip().setOrientation(m); + + for(int i = 0; i < MAX_PLAYERS; i++) + { + this->scores[i] = e->GetAsStruct().scoreboard[i]; + } + } + break; + case Event::eGameEnded: + if (gameRunning) + { + connection->disconnect(); + gameRunning=false; + { + EventStruct::GameEndedStruct str= ((Event::GameEnded*)eventList[i])->GetAsStruct(); + stateStack->PushState(new GameEndedMenu(this->players, this->scores, str.winningTeam )); + } + } + break; + case Event::eScoreUpdate: + for(int i = 0; i < MAX_PLAYERS; i++) + { + this->scores[i] = ((Event::ScoreUpdate*)eventList[i])->GetAsStruct().scoreboard[i]; + } + break; + default: + break; + } + + delete eventList[i]; + } + if(gameRunning) + { + // Fixed Update period + bool atLeastOneWhileLoop = false; + this->elapsedUpdatePeriod += timeDelta; + + while( this->elapsedUpdatePeriod >= this->updatePeriod ) + { + atLeastOneWhileLoop = true; + + this->elapsedUpdatePeriod -= this->updatePeriod; + + { // data critical section + this->lockMutex(); + for(int i=0;i< PLAYER_MAX_COUNT;++i) + { + Network::ServerToClientUpdateData data = connection->getUpdate(i); + Player* p = players[i]; + p->accessShip().setOrientation( data.position ); + + if( data.pid == playerID && p->HP > data.hp ) + RenderEngine::Damaged(); + + p->HP = data.hp; + p->Shield = data.shield; + p->Speed = data.dirVecLen; + } + this->releaseMutex(); + } + } + + this->lockMutex(); + RenderEngine::update( camera->getView(),camera->getProjection(), timeDelta, connection ); + this->releaseMutex(); + + if( atLeastOneWhileLoop ) + { + connection->sendData(update); + + SoundSystem::setTransformation(players[this->playerID]->getOrientation()); + } + } + +} + +void IntoTheVoid::Render() const +{ + this->lockMutex(); + + RenderEngine::RenderGame(this->players,this->MAX_PLAYERS, this->playerID, this->staticObject.model, this->staticObject.num ); + + if (Oyster::Input::Controller::isKeyDown(VK_TAB)) + RenderEngine::RenderScoreboard(this->scores, this->MAX_PLAYERS, this->players); + + this->releaseMutex(); +} + +void IntoTheVoid::lockMutex( ) const +{ + while( this->readOnly ); + this->readOnly = true; +} + +void IntoTheVoid::releaseMutex( ) const +{ this->readOnly = false; } + +void IntoTheVoid::SetPlayerPosition(unsigned int id, const Oyster::Math::Float4x4 &position) +{ + this->lockMutex(); + players[id]->accessShip().setOrientation( position ); + this->releaseMutex(); + + if (id != playerID) + players[id]->getWeaponSound()->SetPosition(position.v[3].xyz); +} + +void IntoTheVoid::SetPlayerUpdate( Network::ServerToClientUpdateData &data ) +{ + this->lockMutex(); + Player* p = this->players[data.pid]; + if (data.pid==0) + { + int a=0; + } + else if(data.pid==1) + { + int a=0; + } + p->accessShip().setOrientation( data.position ); + + if( data.pid == playerID && p->HP > data.hp ) + RenderEngine::Damaged(); + + p->HP = data.hp; + p->Shield = data.shield; + p->Speed = data.dirVecLen; + + this->releaseMutex(); + + if ( data.pid != playerID ) + p->getWeaponSound()->SetPosition( data.position.v[3].xyz ); +} + +void IntoTheVoid::SetRenderData( const Protocol::RenderData &renderData ) +{ + Float scale = 0.1f; + Float4x4 transform; + rotationMatrix_AxisY( transform, ::Utility::Value::radian(180.0f) ); + transformMatrix( transform, scale * Float4x4::identity, transform ); + transform.m44 = 1.0f; + + // setup Players + loadPlayerResources( this->players, connection->teamID, renderData, transform ); + + // setup Static Objects, starting with clearing away any old stuff + if( this->staticObject.model ) + { + /*for( unsigned int i = 0; i < this->staticObject.num; ++i ) + { + ::std::vector::size_type j = 0; + for( ; j < this->staticObject.model[i].Material.size(); ++i ) + this->staticObject.model[i].Material[j]->Release(); + }*/ + + delete [] this->staticObject.model; + } + if( this->staticObject.world ) + delete [] this->staticObject.world; + + ::std::vector::size_type i = 0, num = renderData.mapData.getObjectList().size(); + if( num > 0 ) + { + this->staticObject.num = (unsigned int) num; + this->staticObject.model = new ::Oyster::Render::Model[num]; + this->staticObject.world = new Float4x4[num]; + + for( ; i < num; ++i ) + { + + this->staticObject.model[i] = *Oyster::Resources::Manager::LoadModel( + renderData.mapData.getMeshList()[ renderData.mapData.getObjectList()[i].getMeshRef() ].getObjFileName(), + transform ); + + //::Oyster::FileLoaders::ObjReader *reader = Oyster::FileLoaders::ObjReader::LoadFile( + // renderData.mapData.getMeshList()[ renderData.mapData.getObjectList()[i].getMeshRef() ].getObjFileName(), + // transform ); + + //int vcount; + //::Oyster::FileLoaders::ObjReader::Vertex** vertex = new Oyster::FileLoaders::ObjReader::Vertex*[1]; + //::std::map textures; + //reader->GetVertexData( vertex, vcount, textures ); + + //Oyster::Buffer::BUFFER_INIT_DESC desc; + //{ + // desc.ElementSize= sizeof(Oyster::FileLoaders::ObjReader::Vertex); + // desc.NumElements = vcount; + // desc.InitData = *vertex; + // desc.Type = Oyster::Buffer::VERTEX_BUFFER; + // desc.Usage = Oyster::Buffer::BUFFER_DEFAULT; + //} + + //this->staticObject.model[i].Vertices = *(Oyster::Engine::Init::Buffers::CreateBuffer(desc)); + //this->staticObject.model[i].VertexCount = vcount; + //this->staticObject.model[i].Material.push_back( textures["Diffuse"] ); + //this->staticObject.model[i].Material.push_back( textures["Specular"] ); + //this->staticObject.model[i].Material.push_back( textures["Glow"] ); + + //this->staticObject.model[i].Visible = true; + //this->staticObject.model[i].Indexed = false; + + this->staticObject.model[i].World = &this->staticObject.world[i]; + this->staticObject.world[i] = renderData.mapData.getObjectList()[i].getWorldMatrix(); + } + } + else + { + this->staticObject.num = 0; + this->staticObject.model = NULL; + this->staticObject.world = NULL; + } +} + +void IntoTheVoid::RecievedKeyFrame(const KeyFrame &keyframe) +{ + if (!this->Initialized) + return; + + for(int i = 0; i < MAX_PLAYERS; i++) + { + this->players[i]->HP = keyframe.Players[i].Hp; + } +} + +//////////////////////////////// + +void loadPlayerResources( Player **player, int shipID[], const ::Protocol::RenderData &renderData, const Float4x4 &transform ) +{ // Loading player resources + + ::Game::Ship *ship; + player[0] = new Player( renderData.playerData.getMeshList()[ renderData.playerData.getPlayerMeshRefList()[0] ].getObjFileName(), transform ); + { + ship = &player[0]->accessShip(); + ship->movementProperty.maxSpeed = 400.0f; + ship->movementProperty.deAcceleration = 50.0f; + ship->movementProperty.acceleration.forward = 50.0f; + ship->movementProperty.acceleration.backward = 25.0f; + ship->movementProperty.acceleration.horizontal = 25.0f; + ship->movementProperty.acceleration.vertical = 25.0f; + ship->rotationProperty.maxSpeed = ::Utility::Value::radian( 90.0f ); + ship->rotationProperty.deAcceleration = ::Utility::Value::radian( 180.0f ); + ship->rotationProperty.acceleration.pitch = ::Utility::Value::radian( 90.0f ); + ship->rotationProperty.acceleration.yaw = ::Utility::Value::radian( 90.0f ); + ship->rotationProperty.acceleration.roll = ::Utility::Value::radian( 90.0f ); + } + player[1] = new Player( renderData.playerData.getMeshList()[ renderData.playerData.getPlayerMeshRefList()[1] ].getObjFileName(), transform ); + { + ship = &player[1]->accessShip(); + ship->movementProperty = player[0]->accessShip().movementProperty; + ship->rotationProperty = player[0]->accessShip().rotationProperty; + } + player[2] = new Player( renderData.playerData.getMeshList()[ renderData.playerData.getPlayerMeshRefList()[2] ].getObjFileName(), transform ); + { + ship = &player[2]->accessShip(); + ship->movementProperty = player[0]->accessShip().movementProperty; + ship->rotationProperty = player[0]->accessShip().rotationProperty; + } + player[3] = new Player( renderData.playerData.getMeshList()[ renderData.playerData.getPlayerMeshRefList()[3] ].getObjFileName(), transform ); + { + ship = &player[3]->accessShip(); + ship->movementProperty = player[0]->accessShip().movementProperty; + ship->rotationProperty = player[0]->accessShip().rotationProperty; + } + player[4] = new Player( renderData.playerData.getMeshList()[ renderData.playerData.getPlayerMeshRefList()[4] ].getObjFileName(), transform ); + { + ship = &player[4]->accessShip(); + ship->movementProperty = player[0]->accessShip().movementProperty; + ship->rotationProperty = player[0]->accessShip().rotationProperty; + } + player[5] = new Player( renderData.playerData.getMeshList()[ renderData.playerData.getPlayerMeshRefList()[5] ].getObjFileName(), transform ); + { + ship = &player[5]->accessShip(); + ship->movementProperty = player[0]->accessShip().movementProperty; + ship->rotationProperty = player[0]->accessShip().rotationProperty; + } + player[6] = new Player( renderData.playerData.getMeshList()[ renderData.playerData.getPlayerMeshRefList()[6] ].getObjFileName(), transform ); + { + ship = &player[6]->accessShip(); + ship->movementProperty = player[0]->accessShip().movementProperty; + ship->rotationProperty = player[0]->accessShip().rotationProperty; + } + player[7] = new Player( renderData.playerData.getMeshList()[ renderData.playerData.getPlayerMeshRefList()[7] ].getObjFileName(), transform ); + { + ship = &player[7]->accessShip(); + ship->movementProperty = player[0]->accessShip().movementProperty; + ship->rotationProperty = player[0]->accessShip().rotationProperty; + } +} diff --git a/Into The Void client/IntoTheVoid.h b/Into The Void client/IntoTheVoid.h new file mode 100644 index 00000000..1f2a2246 --- /dev/null +++ b/Into The Void client/IntoTheVoid.h @@ -0,0 +1,70 @@ +#pragma once + +#include "NetworkConnection.h" +#include "GameState.h" +#include "TailCamera.h" +#include "Player.h" +#include "Protocoll.h" +#include "GameEndedMenu.h" + +class RenderEngine; + +class IntoTheVoid : public GameState +{ +public: + friend class RenderEngine; + //friend class NetworkConnection; + + // IntoTheVoid takes ownership of the connection. + IntoTheVoid(NetworkConnection *connection); + virtual ~IntoTheVoid(); + + void Enter(GameStateStack *stateStack); + void Exit(); + + void Suspend(); + void Resume(); + + bool WantsBackgroundUpdates() const; + + void Update(float timeDelta); + void Render() const; + + void SetPlayerPosition( unsigned int id, const Oyster::Math::Float4x4 &position ); + void SetPlayerUpdate( Network::ServerToClientUpdateData& data ); + void RecievedKeyFrame( const KeyFrame &keyframe ); + + bool Initialized; + + bool gameRunning; +private: + float updatePeriod, elapsedUpdatePeriod; + mutable bool readOnly; + + bool isSuspended; + bool isFirstUpdate; + + GameStateStack *stateStack; + NetworkConnection *connection; + + unsigned int playerID; + + static const int MAX_PLAYERS = 8; + Player *players[MAX_PLAYERS]; // the data send from from the server. + //Player self; // For the second time; SUPERIMPORTANT!! Do not remove! It is the physical data that is manipulated by the player before sending it back to the server. ~Dan + + struct + { + unsigned int num; + ::Oyster::Render::Model *model; + ::Oyster::Math::Float4x4 *world; + } staticObject; + + TailCamera *camera; + + Score scores[MAX_PLAYERS]; + + void lockMutex( ) const; + void releaseMutex( ) const; + void SetRenderData( const Protocol::RenderData &renderData ); +}; diff --git a/Into The Void client/Lobby.cpp b/Into The Void client/Lobby.cpp new file mode 100644 index 00000000..beea5d2d --- /dev/null +++ b/Into The Void client/Lobby.cpp @@ -0,0 +1,153 @@ +#include + +#include "Lobby.h" +#include "RenderEngine.h" +#include "Input\InputController.h" +#include "Window\Window.h" +#include "IntoTheVoid.h" + +Lobby::Lobby(NetworkConnection *connection) +{ + assert(connection->getConnectionStatus() != OFFLINE); + + m_stateStack = NULL; + m_connection = connection; + nrPlayers = m_connection->getLobbyData().playerCount; +} + +Lobby::~Lobby() +{ +} + +void Lobby::Enter(GameStateStack *stateStack) +{ + Oyster::Input::Controller::OrigoTopLeft(); + Oyster::Input::Controller::RestrictMouse(false); + + m_stateStack = stateStack; + + Oyster::Math::Float2 windowSize; + windowSize.x = (float)Oyster::Window::Size.right; + windowSize.y = (float)Oyster::Window::Size.top; + + D3DX11CreateShaderResourceViewFromFile(Oyster::Core::Device, "..\\Content\\Gui\\button_darkblue_250x64.png", NULL, NULL, &m_queueTextures[0], NULL); + D3DX11CreateShaderResourceViewFromFile(Oyster::Core::Device, "..\\Content\\Gui\\button_250x64.png", NULL, NULL, &m_queueTextures[1], NULL); + D3DX11CreateShaderResourceViewFromFile(Oyster::Core::Device, "..\\Content\\Gui\\lobby_bg_screen.png", NULL, NULL, &m_queueTextures[2], NULL); + + m_queueOverlay.texture = m_queueTextures[0]; + m_queueOverlay.size = Oyster::Math::Float2(230.0f, 64.0f); + m_queueOverlay.position.x = windowSize.x / 2.0f - m_queueOverlay.size.x / 2.0f; + m_queueOverlay.position.y = 20.0f; + m_queueOverlay.position.z = 0.0f; +} + +void Lobby::Exit() +{ + m_stateStack = NULL; +} + +void Lobby::Suspend() +{ +} + +void Lobby::Resume() +{ + Oyster::Input::Controller::OrigoTopLeft(); + Oyster::Input::Controller::RestrictMouse(false); +} + +void Lobby::Update(float timeDelta) +{ + if (m_connection->getConnectionStatus() == ONLINE_INGAME) + { + Oyster::Engine::PrepareForRendering::ClearBackBuffer(Oyster::Math::Float4(0, 0, 0, 1)); + Oyster::Engine::PrepareForRendering::Begin2DRender(); + Oyster::Engine::Render::ScreenQuad(m_queueTextures[2],0.5f); + Oyster::Engine::Render::Text("Game found, loading...", Float2(10.0f, 15.0f), Float3(175.0f, 250.0f, 0)); + Oyster::Engine::Render::PresentScene(); + + m_stateStack->SetState(new IntoTheVoid(m_connection)); + return; + } + + Oyster::Math::Float2 cursorPosition = Oyster::Math::Float2((float)Oyster::Input::Controller::GetX(), (float)Oyster::Input::Controller::GetY()); + + if (IntersectsOverlay(m_queueOverlay, cursorPosition)) + m_queueOverlay.texture = m_queueTextures[1]; + else + m_queueOverlay.texture = m_queueTextures[0]; + + if (Oyster::Input::Controller::isMouseBtnPressed(MK_LBUTTON)) + { + if (IntersectsOverlay(m_queueOverlay, cursorPosition) && m_connection->getConnectionStatus() == ONLINE_MAINMENU) + { + m_connection->startQueue(); + } + } +} + +void Lobby::Render() const +{ + LobbyInitData lobbyData; + + Oyster::Engine::PrepareForRendering::Begin2DRender(); + Oyster::Engine::Render::ScreenQuad(m_queueTextures[2],0.5f); + + Oyster::Engine::PrepareForRendering::Begin2DTextRender(); + + switch(m_connection->getConnectionStatus()) + { + case ONLINE_MAINMENU: + Oyster::Engine::Render::Text("Queue", Float2(15.0f, 30.0f), m_queueOverlay.position + Float3(15.0f,5.0f,0)); + + Oyster::Engine::PrepareForRendering::Begin2DRender(); + Oyster::Engine::Render::Sprite(m_queueOverlay.texture, m_queueOverlay.size, m_queueOverlay.position); + break; + case ONLINE_QUEUEING: + Oyster::Engine::Render::Text("Queueing...", Float2(10.0f, 30.0f), m_queueOverlay.position + Float3(15.0f,5.0f,0)); + + Oyster::Engine::PrepareForRendering::Begin2DRender(); + Oyster::Engine::Render::Sprite(m_queueOverlay.texture, m_queueOverlay.size, m_queueOverlay.position); + break; + case ONLINE_INLOBBY: + lobbyData = m_connection->getLobbyData(); + Float2 textSize=Float2(10,10); + Float3 textPos=Float3(300,40,0); + Oyster::Engine::Render::Text("In lobby", textSize, textPos); + + textPos.y=60; + textPos.x=180; + Oyster::Engine::Render::Text(SSTR("Starting in "<lobbySecondsLeft()<<" seconds."), textSize, textPos) ; + + + textPos.y=100; + textPos.x=80; + + Oyster::Engine::Render::Text("Team 1", textSize, textPos); + for (int i=0; i 0) + { + textPos.y+=15; + Oyster::Engine::Render::Text( lobbyData.players[i].usrName, + textSize, + textPos); + } + } + textPos.y=100; + textPos.x=450; + Oyster::Engine::Render::Text("Team 2", textSize, textPos); + for (int i=1; i 0) + { + textPos.y+=15; + Oyster::Engine::Render::Text( lobbyData.players[i].usrName, + textSize, + textPos); + } + } + + break; + } +} diff --git a/Into The Void client/Lobby.h b/Into The Void client/Lobby.h new file mode 100644 index 00000000..201f113b --- /dev/null +++ b/Into The Void client/Lobby.h @@ -0,0 +1,33 @@ +#pragma once + +#include + +#include "GameState.h" +#include "OysterMath.h" +#include "RenderEngine.h" +#include "MainMenu.h" +#include "NetworkMiscFunctions.h" + +class Lobby : public GameState +{ +public: + // Lobby takes ownership of the connection. + Lobby(NetworkConnection *connection); + virtual ~Lobby(); + + void Enter(GameStateStack *stateStack); + void Exit(); + + void Suspend(); + void Resume(); + + void Update(float timeDelta); + void Render() const; + int nrPlayers; +private: + GameStateStack *m_stateStack; + NetworkConnection *m_connection; + ID3D11ShaderResourceView *m_queueTextures[3]; + + Overlay m_queueOverlay; +}; diff --git a/Into The Void client/MainMenu.cpp b/Into The Void client/MainMenu.cpp new file mode 100644 index 00000000..4735a75e --- /dev/null +++ b/Into The Void client/MainMenu.cpp @@ -0,0 +1,166 @@ +#include "MainMenu.h" +#include "RenderEngine.h" +#include "Input\InputController.h" +#include "Window\Window.h" +#include "Lobby.h" + +Oyster::Math::Float3 ConnectPos, QuitPos, TitlePos; + +bool IntersectsOverlay(const Overlay &overlay, Oyster::Math::Float2 point) +{ + if (point.x >= overlay.position.x && point.x <= (overlay.position.x + overlay.size.x) && + point.y >= overlay.position.y && point.y <= (overlay.position.y + overlay.size.y)) + { + return true; + } + + return false; +} + + +MainMenu::MainMenu() +{ + m_stateStack = NULL; + m_connection = NULL; +} + +MainMenu::~MainMenu() +{ +} + +void MainMenu::Enter(GameStateStack *stateStack) +{ + Oyster::Input::Controller::OrigoTopLeft(); + Oyster::Input::Controller::RestrictMouse(false); + + m_stateStack = stateStack; + m_connection = NULL; + + Oyster::Math::Float2 windowSize; + windowSize.x = (float)Oyster::Window::Size.right; + windowSize.y = (float)Oyster::Window::Size.top; + + D3DX11CreateShaderResourceViewFromFile(Oyster::Core::Device, "..\\Content\\GUI\\button_darkblue_250x64.png", NULL, NULL, &m_connectTextures[0], NULL); + D3DX11CreateShaderResourceViewFromFile(Oyster::Core::Device, "..\\Content\\GUI\\button_250x64.png", NULL, NULL, &m_connectTextures[1], NULL); + D3DX11CreateShaderResourceViewFromFile(Oyster::Core::Device, "..\\Content\\GUI\\button_darkblue_250x64.png", NULL, NULL, &m_quitTextures[0], NULL); + D3DX11CreateShaderResourceViewFromFile(Oyster::Core::Device, "..\\Content\\GUI\\button_250x64.png", NULL, NULL, &m_quitTextures[1], NULL); + D3DX11CreateShaderResourceViewFromFile(Oyster::Core::Device, "..\\Content\\GUI\\lobby_bg_screen.png", NULL, NULL, &m_backgroundOverlay.texture, NULL); + + m_backgroundOverlay.size = windowSize; + m_backgroundOverlay.position.x = 0.0f; + m_backgroundOverlay.position.y = 0.0f; + m_backgroundOverlay.position.z = 0.5f; + + m_connectOverlay.texture = m_connectTextures[0]; + m_connectOverlay.size = Oyster::Math::Float2(229.0f, 80.0f); + m_connectOverlay.position.x = windowSize.x / 2.0f - m_connectOverlay.size.x / 2.0f; + m_connectOverlay.position.y = 200.0f; + m_connectOverlay.position.z = 0.0f; + + ConnectPos = m_connectOverlay.position; + ConnectPos.x+=10; + + m_quitOverlay.texture = m_quitTextures[0]; + m_quitOverlay.size = Oyster::Math::Float2(132.0f, 83.0f); + m_quitOverlay.position.x = windowSize.x / 2.0f - m_quitOverlay.size.x / 2.0f; + m_quitOverlay.position.y = windowSize.y - m_quitOverlay.size.y - 20.0f; + m_quitOverlay.position.z = 0.0f; + + QuitPos = m_quitOverlay.position; + QuitPos.x+=10; + QuitPos.y+=5; + + TitlePos.x = 120.0f; + TitlePos.y = 10.0f; + TitlePos.z = 0.0f; +} + +void MainMenu::Exit() +{ + m_stateStack = NULL; + m_connection = NULL; +} + +void MainMenu::Suspend() +{ +} + +void MainMenu::Resume() +{ + Oyster::Input::Controller::OrigoTopLeft(); + Oyster::Input::Controller::RestrictMouse(false); +} + +void MainMenu::Update(float timeDelta) +{ + if (m_connection) + { + if (m_connection->getConnectionStatus() != OFFLINE) + { + m_stateStack->SetState(new Lobby(m_connection)); + return; + } + else + { + m_connectTimer += timeDelta; + + // If we haven't established a connection after 5 seconds, stop trying. + if (m_connectTimer >= 5.0f) + { + m_connection->disconnect(); + delete m_connection; + m_connection = NULL; + } + } + } + + Oyster::Math::Float2 cursorPosition = Oyster::Math::Float2((float)Oyster::Input::Controller::GetX(), (float)Oyster::Input::Controller::GetY()); + + if (IntersectsOverlay(m_connectOverlay, cursorPosition)) + m_connectOverlay.texture = m_connectTextures[1]; + else + m_connectOverlay.texture = m_connectTextures[0]; + + if (IntersectsOverlay(m_quitOverlay, cursorPosition)) + m_quitOverlay.texture = m_quitTextures[1]; + else + m_quitOverlay.texture = m_quitTextures[0]; + + if (Oyster::Input::Controller::isMouseBtnPressed(MK_LBUTTON)) + { + if (!m_connection && IntersectsOverlay(m_connectOverlay, cursorPosition)) + { + m_connection = new NetworkConnection(); + m_connectTimer = 0.0f; + + if (m_connection->connectWithFileData("../Connectiondata.txt")== NetworkConnection::Failure) + { + delete m_connection; + m_connection = NULL; + } + } + else if (IntersectsOverlay(m_quitOverlay, cursorPosition)) + { + m_stateStack->PopState(); + } + } +} + +void MainMenu::Render() const +{ + Oyster::Engine::PrepareForRendering::Begin2DTextRender(); + Oyster::Engine::Render::Text("Into The Void!",Oyster::Math::Float2(20,50), TitlePos); + Oyster::Engine::Render::Text("Quit",Oyster::Math::Float2(15,40),QuitPos); + + if (m_connection) + Oyster::Engine::Render::Text("Connecting",Oyster::Math::Float2(10,50),ConnectPos); + else + Oyster::Engine::Render::Text("Connect",Oyster::Math::Float2(15,50),ConnectPos); + + Oyster::Engine::PrepareForRendering::Begin2DRender(); + + Oyster::Engine::Render::Sprite(m_backgroundOverlay.texture, m_backgroundOverlay.size, m_backgroundOverlay.position); + Oyster::Engine::Render::Sprite(m_connectOverlay.texture, m_connectOverlay.size, m_connectOverlay.position); + Oyster::Engine::Render::Sprite(m_quitOverlay.texture, m_quitOverlay.size, m_quitOverlay.position); + +} diff --git a/Into The Void client/MainMenu.h b/Into The Void client/MainMenu.h new file mode 100644 index 00000000..6efca8de --- /dev/null +++ b/Into The Void client/MainMenu.h @@ -0,0 +1,45 @@ +#pragma once + +#include + +#include "GameState.h" +#include "OysterMath.h" +#include "RenderEngine.h" + +struct Overlay +{ + ID3D11ShaderResourceView *texture; + Oyster::Math::Float3 position; + Oyster::Math::Float2 size; +}; + +bool IntersectsOverlay(const Overlay &overlay, Oyster::Math::Float2 point); + + +class MainMenu : public GameState +{ +public: + MainMenu(); + virtual ~MainMenu(); + + void Enter(GameStateStack *stateStack); + void Exit(); + + void Suspend(); + void Resume(); + + void Update(float timeDelta); + void Render() const; + +private: + GameStateStack *m_stateStack; + NetworkConnection *m_connection; + float m_connectTimer; + + ID3D11ShaderResourceView *m_connectTextures[2]; + ID3D11ShaderResourceView *m_quitTextures[2]; + + Overlay m_backgroundOverlay; + Overlay m_connectOverlay; + Overlay m_quitOverlay; +}; diff --git a/Into The Void client/NetworkConnection.cpp b/Into The Void client/NetworkConnection.cpp new file mode 100644 index 00000000..0c90a214 --- /dev/null +++ b/Into The Void client/NetworkConnection.cpp @@ -0,0 +1,337 @@ +#include "NetworkConnection.h" +#include "Player.h" +#include "IntoTheVoid.h" + +NetworkConnection::NetworkConnection() + : + SocketClient() +{ + this->intoTheVoid = NULL; + mutex = new Mutex(); + eventMutex = new Mutex(); + effectMutex = new Mutex(); + updateMutex=new Mutex(); + connStatus=OFFLINE; + lastServerUpdate=-1; + curClientUpdate=0; + + lobbyRenderSync=0; + renderData = 0; + //client.setPlayerContPtr(this); +} + +NetworkConnection::~NetworkConnection() +{ + delete mutex; + delete eventMutex; +} + +void NetworkConnection::setIntoTheVoid(IntoTheVoid *intoTheVoid) +{ + this->intoTheVoid = intoTheVoid; +} + +void NetworkConnection::receiveConnStatus(ConnectionStatus cs) +{ + connStatus=cs; +} +bool LoadConnectionData(char* filename, char* &usr, char* &ip, int &port ) +{ + port=-1; + bool userSet=false; + bool ipSet=false; + std::ifstream ifs; + char in[50]; + std::vector cont; + ifs.open(filename); + if(!ifs.is_open()) + { + return false; + } + while(!ifs.eof()) + { + ifs.getline(in, 100); + cont=splitString(in, '='); + if (cont.size()==2) + { + if(!strcmp("ipaddress", cont[0].c_str())) + { + ipSet=true; + strcpy(ip, cont[1].c_str()); + + } + else if(!strcmp("username", cont[0].c_str())) + { + userSet=true; + strcpy(usr, cont[1].c_str()); + } + else if(!strcmp("portrange", cont[0].c_str())) + { + cont=splitString(cont[1].c_str(),'-'); + if(cont.size()>1) + { + int min=atoi(cont[0].c_str()); + int range=atoi(cont[1].c_str())-min; + port=(rand()%range)+min; + } + else + { + port=atoi(cont[0].c_str()); + } + } + } + + } + ifs.close(); + if(ipSet && port>0 && userSet) + return true; + return false; +} +NetworkConnection::Result NetworkConnection::connect(const char *ip, int listenPort, char *userName) +{ + //MSG msg; + gameOver=false; + startRecvLoop(); + if(connectToIP(ip, listenPort, userName, (int)strlen(userName))) + return Success; + return Failure; +} +NetworkConnection::Result NetworkConnection::connectWithFileData(char* file) +{ + //MSG msg; + char* userName=new char[100]; + + char* ip=new char[100]; + int port; + if(LoadConnectionData(file, userName, ip, port)) + { + return connect(ip, port, userName); + } else + return connect("127.0.0.1", 22222, "FILE_NOT_FOUND"); + return Failure; +} +void NetworkConnection::startQueue() +{ + sendMessage("/qst"); +} +void NetworkConnection::stopQueue() +{ + sendMessage("/qed"); +} +void NetworkConnection::receiveKeyframe(char* kfd, int size) +{ + //Key frams aren't used right now. + /*KeyFrame kf = KeyFrame(kfd); + mutex->Lock(); + if (intoTheVoid) + intoTheVoid->RecievedKeyFrame(kf); + mutex->Unlock(); + int test=0;*/ +} +void NetworkConnection::receiveEvent(char* evd) +{ + Event::GameEvent* newEvent; + Event::Type eTest; + memcpy(&eTest, evd, sizeof(Event::Type)); + switch (eTest) + { + case Event::Type::eBulletHit: + newEvent=new Event::BulletHit(); + break; + case Event::Type::eBulletCreated: + newEvent=new Event::BulletCreated(); + break; + case Event::Type::eShipSpawned: + newEvent=new Event::ShipSpawned(); + break; + case Event::Type::eGameEnded: + newEvent=new Event::GameEnded(); + gameOver=true; + break; + case Event::Type::eShipDestroyed: + newEvent=new Event::ShipDestroyed(); + break; + default://Invalid data + return; + } + newEvent->LoadRawData(evd+4); + + eventMutex->Lock(); + eventList.push_back(newEvent); + eventMutex->Unlock(); +} +void NetworkConnection::receiveRenderData(char* data, int size) +{ + renderData=new Protocol::RenderData(); + renderData->readFromBuffer(data); + //SetRenderData does not exist at the moment + lobbyRenderSync++; + if (lobbyRenderSync==2) + if (connStatus!= ONLINE_INGAME) + connStatus=ONLINE_INLOBBY; +} +void NetworkConnection::receiveEffectData(char* data, int size) +{ + int count=size/sizeof(Network::EffectData); + int offset=sizeof(Network::EffectData); + Network::EffectData test; + effectMutex->Lock(); + effectList.resize(count); + for (int i=0; iUnlock(); + +} +void NetworkConnection::receiveLobbyInitData(char* data, int size) +{ + lobbyTimer.start(); + lobbyTimer.reset(); + LobbyInitData lobby; + memcpy(&lobby, data, size); + lobbyTotalTime=lobby.timer; + id=lobby.pid; + + for(unsigned int i=0; iSetPlayerPosition(i, init.pos[i].position); + + //positions[i]=init.pos[i].position; + } + lobbyData=lobby; + lobbyRenderSync++; + if (lobbyRenderSync==2) + if (connStatus!= ONLINE_INGAME) + connStatus=ONLINE_INLOBBY; +} +int NetworkConnection::lobbySecondsLeft() +{ + lobbyTimer.tick(); + int timeLeft=(int)( (lobbyTotalTime-lobbyTimer.getGameTime()) ); + if(timeLeft>0) + return timeLeft; + else + return 0; +} +void NetworkConnection::disconnect() +{ + sendMessage("/dc"); + closeConnection(); +} +void NetworkConnection::doneLoading() +{ + sendMessage("/rdy"); +} + +NetworkConnection::Result NetworkConnection::startSendLoop() +{ + //startSendDataThread(); + return Failure; +} + +NetworkConnection::Result NetworkConnection::startRecvLoop() +{ + startReceiveThread(); + return Success; +} + + +void NetworkConnection::receivePlayerUpdate(char* ps, int size) +{ + ServerToClientUpdateData recv; + int count=size/Network::SERVER_PLAYER_DATA_SIZE; + for (int i=0; iLock(); + memcpy( &recvStruct[i], ps+i*Network::SERVER_PLAYER_DATA_SIZE, SERVER_PLAYER_DATA_SIZE ); + updateMutex->Unlock(); + if ( lastServerUpdate < recv.updateCount ) + { + setUpdate(recv,recv.pid); + if(id==1) + { + int a=0; + if(recvStruct[i].pid==1) + { + int b=0; + } + } + //intoTheVoid->SetPlayerUpdate( recvStruct[i] ); + lastServerUpdate = recv.updateCount; + } + } +} +void NetworkConnection::setUpdate(ServerToClientUpdateData data, int i) +{ + updateMutex->Lock(); + recvStruct[i]=data; + updateMutex->Unlock(); +} +const ServerToClientUpdateData NetworkConnection::getUpdate(int i) +{ + updateMutex->Lock(); + ServerToClientUpdateData data=recvStruct[i]; + updateMutex->Unlock(); + return data; +} +Oyster::Math::Float4x4 NetworkConnection::getPosition(int i) +{ + return positions[i]; +} + +unsigned int NetworkConnection::getPlayerID() +{ + return id; +} + + +void NetworkConnection::fetchEvents(std::vector &list) +{ + eventMutex->Lock(); + list=eventList; + eventList.resize(0); + eventMutex->Unlock(); +} +void NetworkConnection::fetchEffects(std::vector &list) +{ + effectMutex->Lock(); + list=effectList; + //effectList.resize(0); + effectMutex->Unlock(); +} + +void NetworkConnection::receiveGameInitData(char* data) +{ + GameInitData init; + int c=sizeof(init); + memcpy(&init, data, sizeof(init)); + id=init.pid; + + for(unsigned int i=0; iSetPlayerPosition(i, init.player[i].position); + teamID[i]=init.player[i].teamid; + positions[i]=init.player[i].position; + } + connStatus=ONLINE_INGAME; +} + +char* NetworkConnection::getPlayerData() +{ + return "Not yet implemented"; +} +void NetworkConnection::sendData(ClientToServerUpdateData &data) +{ + if(!gameOver) + { + data.pid=id; + data.updateCount=curClientUpdate; + curClientUpdate++; + sendUserData((char*)&data, sizeof(data)); + } +} + diff --git a/Into The Void client/NetworkConnection.h b/Into The Void client/NetworkConnection.h new file mode 100644 index 00000000..db0a8643 --- /dev/null +++ b/Into The Void client/NetworkConnection.h @@ -0,0 +1,114 @@ +#pragma once +#ifndef NETWORKCONNECTION_H +#define NETWORKCONNECTION_H + +#include "SocketClient.h" +#include "Protocoll.h" +#include "ThreadPool.h" +#include "Network.h" +#include "NetworkInitStructs.h" +using namespace Network; + +class IntoTheVoid; + + + +class NetworkConnection : private SocketClient +{ +private: + ConnectionStatus connStatus; + Oyster::Math::Float4x4 positions[PLAYER_MAX_COUNT]; + Mutex *mutex; + Mutex *eventMutex; + Mutex *effectMutex; + Mutex *updateMutex; + ServerToClientUpdateData recvStruct[PLAYER_MAX_COUNT]; + ClientToServerUpdateData sendStruct; + unsigned int id; + bool gameOver; + IntoTheVoid *intoTheVoid; + + Oyster::Math::Float4x4 testVar; + void setPosition(Oyster::Math::Float4x4 pos, int i); + LobbyInitData lobbyData; + std::vector eventList; + std::vector effectList; + long lastServerUpdate; + long curClientUpdate; + __int8 lobbyRenderSync; + Protocol::RenderData* renderData; + void setUpdate(ServerToClientUpdateData data, int i); + + NetworkTimer lobbyTimer; + int lobbyTotalTime; +public: + int lobbySecondsLeft(); + + const ServerToClientUpdateData getUpdate(int i); + Protocol::RenderData* GetRenderData() const + { + while(!renderData) + Sleep(100); + + return renderData; + } + int teamID[PLAYER_MAX_COUNT]; + LobbyInitData getLobbyData() {return lobbyData;} + ConnectionStatus getConnectionStatus() const {return connStatus;} + void receiveConnStatus(ConnectionStatus cs); + Oyster::Math::Float4x4 getPosition(int i); + + NetworkConnection(); + virtual ~NetworkConnection(); + + enum Result { Success, Failure }; + //Starts the receive thread. + Result startRecvLoop(); + + void setIntoTheVoid(IntoTheVoid *intoTheVoid); + + //Step 1: connect to server IP + Result connectWithFileData(char* file); + Result connect( const char *ip, int listenPort, char *userName = "anonymous" ); + //You should now be in a server lobby. + //Step 2: Press queue button. Will tell the server to set user state to queueing/stop queueing + void startQueue(); + void stopQueue(); + //Step 3:Server will tell the client that he/she has connected to a game + //This data will contain things such as other players names, shipIDs and so on + void receiveLobbyInitData(char* data, int size); + //Step 4: Select ship. + //During this time you'll be able to receive other players ship IDswhen they change + void selectShip(int sid); + void receiveShipID(int pid, int sid); + //Step 5: Game start, receive init data + //Init data will come with final selection data together with positions of players. + void receiveGameInitData(char* data); + void receiveRenderData(char* data, int size); + void doneLoading(); + //Step 6: In this step, you will send event data as well as receive it from other players. + //void sendData(Oyster::Math::Float4x4 pos); + void sendData(ClientToServerUpdateData &data); + void receivePlayerUpdate(char* upd, int size); + void receiveEvent(char* evd); + void receiveEffectData(char* data, int size); + void receiveKeyframe(char* kfd, int size); + //Step 7: Game finished. Receive data from server that we may want. TBD. + void receiveGameFinishedData(char* data); + + //Other functions without listed use + void disconnect(); + Result startSendLoop(); + //void sendMessage(char* msg); + //void prepareSend( const Float4x4 &orientation ); + + unsigned int getPlayerID(); + + void fetchEvents(std::vector &list); + void fetchEffects(std::vector &list); + + //Client calls on these functions + char* getPlayerData(); +}; + +#endif \ No newline at end of file diff --git a/Into The Void client/Player.cpp b/Into The Void client/Player.cpp new file mode 100644 index 00000000..1dafcf2d --- /dev/null +++ b/Into The Void client/Player.cpp @@ -0,0 +1,141 @@ +#include "Player.h" + +using namespace ::Oyster::Math; + +Player::Result Player::init( ) +{ /* TODO */ return Player::Success; } + +Player::Player( const std::string &objFilename, const Float4x4 &transform ) : renderAvatar(), logicAvatar(Oyster::Math::Float4x4::identity), orientationPointer(NULL) +{ + this->orientationPointer = const_cast(&this->logicAvatar.getOrientation()); + this->renderAvatar = new Oyster::Render::Model; + this->renderAvatar->World = this->orientationPointer; + + if( objFilename == "" ) return; + + //Oyster::FileLoaders::ObjReader *reader = Oyster::FileLoaders::ObjReader::LoadFile(objFilename, transform); + //Oyster::FileLoaders::ObjReader::Vertex** vertex = new Oyster::FileLoaders::ObjReader::Vertex*[1]; + //int vcount; + //std::map textures; + //reader->GetVertexData( vertex, vcount, textures ); + + //Oyster::Buffer::BUFFER_INIT_DESC desc; + //desc.ElementSize=sizeof(Oyster::FileLoaders::ObjReader::Vertex); + //desc.NumElements = vcount; + //desc.InitData = *vertex; + //desc.Type = Oyster::Buffer::VERTEX_BUFFER; + //desc.Usage = Oyster::Buffer::BUFFER_DEFAULT; + // + //ID3D11ShaderResourceView *srv = textures["Diffuse"]; + // + //renderAvatar.Vertices = *(Oyster::Engine::Init::Buffers::CreateBuffer(desc)); + //renderAvatar.VertexCount = vcount; + //renderAvatar.Material.push_back(srv); + //srv = textures["Specular"]; + //renderAvatar.Material.push_back(srv); + //srv = textures["Glow"]; + //renderAvatar.Material.push_back(srv); + //renderAvatar.Indexed=false; + //renderAvatar.Visible=true; + + renderAvatar = Oyster::Resources::Manager::LoadModel(objFilename, transform); + + weaponSound = SoundEngine::CreateSoundSource(); + weaponSound->SetResource("..\\Content\\Sounds\\pew_pew.wav"); + weaponSound->SetLooping(false); + weaponSound->SetVolume(1.0f); + + this->HP=255; + this->Score=0; +} + +Player::~Player() {/* TODO ? */ } + +Game::Ship & Player::accessShip( ) +{ + return this->logicAvatar; +} + +const Game::Ship & Player::accessShip( ) const +{ + return this->logicAvatar; +} + +void Player::update( const ::Oyster::Math::Float &deltaTime, ClientToServerUpdateData &update ) +{ + /*if(update.forward>0) + this->logicAvatar.thrustForward(); + if(update.forward<0) + this->logicAvatar.thrustBackward(); + + if(update.straferight>0) + this->logicAvatar.strafeRight(); + if(update.straferight<0) + this->logicAvatar.strafeLeft(); + + if(update.strafeup>0) + this->logicAvatar.climb(); + if(update.strafeup<0) + this->logicAvatar.dive(); + */ + + if(update.roll>0) + { + ::Oyster::Math::Float baseAcceleration = this->logicAvatar.rotationProperty.acceleration.roll; + this->logicAvatar.rotationProperty.acceleration.roll /= ::Oyster::Game::MoveAble::getDiscreteTimeSlice(); + + this->logicAvatar.rollLeft(); + this->logicAvatar.rotationProperty.acceleration.roll = baseAcceleration; + } + if(update.roll<0) + { + ::Oyster::Math::Float baseAcceleration = this->logicAvatar.rotationProperty.acceleration.roll; + this->logicAvatar.rotationProperty.acceleration.roll /= ::Oyster::Game::MoveAble::getDiscreteTimeSlice(); + + this->logicAvatar.rollRight(); + + this->logicAvatar.rotationProperty.acceleration.roll = baseAcceleration; + } + + /* + if(update.braking) + this->logicAvatar.enableMovementReduction( true ); + else + this->logicAvatar.disableMovementReduction(); + */ + + this->logicAvatar.enableRotationReduction( true ); + this->logicAvatar.update( deltaTime ); +} + +void Player::render( ) const +{ +} + +SoundSource *Player::getWeaponSound() const +{ + return weaponSound; +} + +const Oyster::Math::Float4x4 *Player::getOrientation() +{ + return this->orientationPointer; +} + +void Player::setMutation(const Oyster::Math::Float4x4 &transform) +{ + this->logicAvatar.setMutation(transform); +} + +void Player::copyLogicFrom( const Player &player ) +{ this->logicAvatar = player.logicAvatar; } + +std::string Player::getName() const +{ + return this->name; +} + +void Player::setName(const std::string &name) +{ + this->name = name; +} diff --git a/Into The Void client/Player.h b/Into The Void client/Player.h new file mode 100644 index 00000000..1e785af2 --- /dev/null +++ b/Into The Void client/Player.h @@ -0,0 +1,56 @@ +#pragma once +#ifndef PLAYER_H +#define PLAYER_H + +#include "RenderEngine.h" +#include "SoundSystem.h" +#include "GameLogic.h" +#include "Engine.h" +#include "NetworkConnection.h" +#include "NetworkUpdateStructs.h" + +class Player +{ +// friend class NetworkConnection; +// friend class IntoTheVoid; + friend class RenderEngine; + +private: + Oyster::Render::Model* renderAvatar; + Game::Ship logicAvatar; + Oyster::Math::Float4x4 *orientationPointer; + + std::string name; + SoundSource *weaponSound; + +public: + enum Result { Success, Failure }; + static Result init( ); + + Player( const std::string &objFile = "", const ::Oyster::Math::Float4x4 &transform = ::Oyster::Math::Float4x4::identity ); + virtual ~Player(); + + Game::Ship & accessShip( ); + const Game::Ship & accessShip( ) const; + + void update( const ::Oyster::Math::Float &deltaTime , ClientToServerUpdateData &update); + void render( ) const; + + SoundSource *getWeaponSound() const; + const Oyster::Math::Float4x4 *getOrientation(); + + // transform is a matrix that is supposed to change the shape of the ship. Scaling as an example + void setMutation(const Oyster::Math::Float4x4 &transform); + + void copyLogicFrom( const Player &player ); // Not garbage .. grrrrr ~Dan + + std::string getName() const; + void setName(const std::string &name); + + int HP,Score, Shield;// evul public /Par + + float Speed; + +}; + +#endif \ No newline at end of file diff --git a/Into The Void client/RenderEngine.cpp b/Into The Void client/RenderEngine.cpp new file mode 100644 index 00000000..c9991d39 --- /dev/null +++ b/Into The Void client/RenderEngine.cpp @@ -0,0 +1,369 @@ +#include + +#include "RenderEngine.h" +#include "IntoTheVoid.h" +#include "Player.h" +#include "GraphicStructs.h" + +#define PRETTY_GRAPHICS 1 +#define NrOfLights 512 + +Oyster::Buffer* RenderEngine::camera = NULL; +Oyster::Buffer* RenderEngine::perObject = NULL; +//Oyster::Buffer* CSBuff = NULL; +Oyster::Buffer* Vertex = NULL; +Oyster::Buffer* RenderEngine::View = NULL; +Oyster::Shader::ShaderEffect BasicEffect; +Oyster::Shader::ShaderEffect DefferedEffect; +Oyster::Shader::ShaderEffect LazerEffect; +ID3D11ShaderResourceView* damageOverlay, *GuiOverlay, *scoreboardBackground; + +ID3D11ShaderResourceView* SrvNulls[16]; +ID3D11RenderTargetView* RtvNulls[16]; +ID3D11UnorderedAccessView* uavNULL[16]; + +ID3D11ShaderResourceView* ComputeInternalResources[4]; +ID3D11UnorderedAccessView* ComputeOutput[4]; + +ID3D11UnorderedAccessView* ComputeStorageOut; +ID3D11ShaderResourceView* ComputeStorageIn; + +Oyster::Resources::BufferDefinitions::PointLightDescription pls[1024]; + +std::string HP; +std::string Shield; +std::string fps; +std::string mps; +Oyster::Math::Float3 speedPos = Oyster::Math::Float3(410,538,0); +Oyster::Math::Float3 HPPos = Oyster::Math::Float3(33,538,0); +Oyster::Math::Float3 ShieldPos = Oyster::Math::Float3(690,538,0); +Oyster::Math::Float3 offset = Oyster::Math::Float3::null; +float fpsUpdateTimer = 0.0f; +float damageOverlayTime = 0.0f; +Oyster::Math::Float3 Bullet[2]; +Oyster::Math::Float4x4 V; +Oyster::Math::Float4x4 P; +std::vector effects; + + +void Init_ComputeExternalResources() +{ + + //create pointlights data + for(int i = 0; i < 1023; ++i ) + { + pls[i].color = Float3::null; + while( pls[i].color == Float3::null ) + pls[i].color = Oyster::Math::Vector3((double)rand() / (RAND_MAX + 1) * (256 - 0)+ 0,(double)rand() / (RAND_MAX + 1) * (256 - 0)+ 0,(double)rand() / (RAND_MAX + 1) * (256 - 0)+ 0); + + pls[i].pos.center = Oyster::Math::Vector3( + (double)rand() / (RAND_MAX + 1) * (10000 - -10000)+ -10000, + (double)rand() / (RAND_MAX + 1) * (10000 - -10000)+ -10000, + (double)rand() / (RAND_MAX + 1) * (10000 - -10000)+ -10000); + pls[i].pos.radius = 15000; + pls[i].intensty = pls[i].pos.radius; + pls[i].intensty += 12.566370614359172953850573533118f * pls[i].pos.radius * pls[i].pos.radius; + pls[i].intensty /= 256.0f * 256.0f; + } + //upload Pointlights to graphic memory + Oyster::Engine::Pipeline::Deffered_Lightning::InputPointLights(pls, NrOfLights); + +} + +void Init_ComputeInternalResources() +{ + /*D3D11_TEXTURE2D_DESC Tdesc; + Tdesc.Width = Oyster::Window::Size.left; + Tdesc.Height = Oyster::Window::Size.bottom; + Tdesc.MipLevels = Tdesc.ArraySize = 1; + Tdesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; + Tdesc.SampleDesc.Count = 1; + Tdesc.SampleDesc.Quality=0; + Tdesc.Usage = D3D11_USAGE_DEFAULT; + Tdesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS; + Tdesc.CPUAccessFlags = 0; + Tdesc.MiscFlags = 0; + + ID3D11Texture2D *pTexture; + HRESULT hr; + for(int i = 0; i < 4; ++i ) + { + hr = Oyster::Core::Device->CreateTexture2D( &Tdesc, NULL, &pTexture ); + hr = Oyster::Core::Device->CreateShaderResourceView( pTexture, 0, &(ComputeInternalResources[i]) ); + hr = Oyster::Core::Device->CreateUnorderedAccessView( pTexture, 0, &(ComputeOutput[i]) ); + pTexture->Release(); + } + + hr = Oyster::Core::Device->CreateTexture2D( &Tdesc, NULL, &pTexture ); + hr = Oyster::Core::Device->CreateShaderResourceView( pTexture, 0, &ComputeStorageIn ); + hr = Oyster::Core::Device->CreateUnorderedAccessView( pTexture, 0, &ComputeStorageOut ); + pTexture->Release();*/ +} + + +RenderEngine::Result RenderEngine::init( HINSTANCE thisInstance, LPSTR cmdLine, int showCommand, WNDPROC wProc ) +{ + Oyster::Engine::Init::Setup setup; + setup.Window.appname = "Into The Void!"; + setup.Window.classname = "OysterDemo"; + setup.Window.hinstance = thisInstance; + setup.Window.nCmdShow = showCommand; + setup.Window.wProc = wProc; + setup.Window.InitWindow = true; + setup.Common.Fullscreen = false; + if(!Oyster::Engine::Init::FullInit(setup)) + return Result::Failure; + ID3D11InputLayout* layout; + Oyster::Buffer::BUFFER_INIT_DESC desc; + + + desc.ElementSize=sizeof(Oyster::Math::Float4x4); + desc.NumElements = 1; + desc.Usage = Oyster::Buffer::BUFFER_CPU_WRITE_DISCARD; + desc.Type = Oyster::Buffer::CONSTANT_BUFFER_VS; + desc.InitData = NULL; + + + perObject = Oyster::Engine::Init::Buffers::CreateBuffer(desc); + + LazerEffect.Shaders.Vertex=Oyster::Shader::Get::GetVertex("LazerV"); + LazerEffect.Shaders.Geometry= Oyster::Shader::Get::GetGeometry("LazerG"); + LazerEffect.Shaders.Pixel =Oyster::Shader::Get::GetPixel("PS"); + LazerEffect.IAStage.Topology = D3D11_PRIMITIVE_TOPOLOGY_LINELIST; + + D3D11_INPUT_ELEMENT_DESC ElemDescLazer[] = + { + {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, + }; + + Oyster::Shader::CreateInputLayout(ElemDescLazer,1,Oyster::Shader::Get::GetVertex("LazerV"),layout); + LazerEffect.IAStage.Layout = layout; + + LazerEffect.CBuffers.Geometry.push_back(&Oyster::Resources::Buffers::CBufferGs); + desc.ElementSize=sizeof(Oyster::Math::Float3); + desc.NumElements=2; + desc.Type = Oyster::Buffer::VERTEX_BUFFER; + + + Vertex = Oyster::Engine::Init::Buffers::CreateBuffer(desc); + + DefferedEffect.Shaders.Compute= Oyster::Shader::Get::GetCompute("Comp"); + + D3DX11CreateShaderResourceViewFromFile(Oyster::Core::Device, "..\\Content\\overlay-red.png", NULL, NULL, &damageOverlay, NULL); + D3DX11CreateShaderResourceViewFromFile(Oyster::Core::Device, "..\\Content\\GUI\\camera_lense_border_B_729x590.png", NULL, NULL, &GuiOverlay, NULL); + D3DX11CreateShaderResourceViewFromFile(Oyster::Core::Device, "..\\Content\\GUI\\lobby_bg_screen.png", NULL, NULL, &scoreboardBackground, NULL); + + for(int i=0;i<16;++i) + { + RtvNulls[i]=NULL; + SrvNulls[i]=NULL; + uavNULL[i] = NULL; + } + + Init_ComputeExternalResources(); + Init_ComputeInternalResources(); + + return Result::Success; +} + +RenderEngine::Result RenderEngine::update(const Oyster::Math::Float4x4 &ViewMatrix, const Oyster::Math::Float4x4 &Projection, float dt, NetworkConnection* conn) +{ + conn->fetchEffects(effects); + P = Oyster::Math::Float4x4(Projection); + V = Oyster::Math::Float4x4(ViewMatrix); + + Float4 col = Float4(0,0,0,1); + + Oyster::Engine::Pipeline::Deffered_Lightning::NewFrame(col, ViewMatrix, Projection); + + fpsUpdateTimer -= dt; + + if (fpsUpdateTimer <= 0.0f) + { + dt=1/dt; + fps = "P: X:"; + char c[10]; + int i = (int)ViewMatrix.v[3].x; + _itoa_s(i,c,10); + fps+=c; + fps+=" Y:"; + i = (int)ViewMatrix.v[3].y; + _itoa_s(i,c,10); + fps+=c; + fps+=" Z:"; + i = (int)ViewMatrix.v[3].z; + _itoa_s(i,c,10); + fps+=c; + fpsUpdateTimer = 0.1f; + } + + if (damageOverlayTime > 0.0f) + damageOverlayTime -= dt; + + return Result::Success; +} + +void RenderEngine::PrepareRendering() +{ + Oyster::Engine::PrepareForRendering::ClearBackBuffer(Oyster::Math::Float4(0, 0, 0, 1)); +} + +void RenderEngine::Present() +{ + Oyster::Engine::Render::PresentScene(); +} + +void RenderLazer() +{ + // Oyster::Engine::PrepareForRendering::BindRenderTargets(&DefferedTargets[0], 1); + // //Oyster::Engine::PrepareForRendering::BindBackBuffer(NULL); + // Oyster::Shader::SetShaderEffect(LazerEffect); + // + // void* dst = Oyster::Resources::Buffers::CBufferGs.Map(); + // memcpy(dst,&(P),64); + // Oyster::Resources::Buffers::CBufferGs.Unmap(); + // + // //render per lazer + // Vertex->Apply(); + // for(size_t i=0;iMap(); + // memcpy(dst,&effects[i].head,sizeof(Oyster::Math::Float3)*2); + // Vertex->Unmap(); + // Oyster::Core::DeviceContext->Draw(2,0); + // } + // + // + // Oyster::Engine::PrepareForRendering::BindRenderTargets(&DefferedTargets[1], 1); + // + // for(size_t i=0;iMap(); + // memcpy(dst,&effects[i].head,sizeof(Oyster::Math::Float3)*2); + // Vertex->Unmap(); + // Oyster::Core::DeviceContext->Draw(2,0); +} + + +void RenderEngine::RenderGame( const Player* const *p, int nr, int localPlayerID, const ::Oyster::Render::Model* const staticObject, unsigned int numStaticObjects ) +{ + int i =(int)(p[localPlayerID]->Speed * 10); + char c[100]; + _itoa_s( i, c, 10 ); + mps = c; + + i = p[localPlayerID]->HP; + _itoa_s( i, c, 10 ); + HP = c; + + i = p[localPlayerID]->Shield; + _itoa_s( i, c, 10 ); + Shield = c; + offset.x = Shield.size() * 10; + + Oyster::Engine::Pipeline::Deffered_Lightning::BeginRenderGeometry(); + + //render to g-Buffers + for(int i = 0; i < nr; i++) + { + Oyster::Engine::Pipeline::Deffered_Lightning::RenderGeometry( (p[i]->renderAvatar), 1 ); + } + + Oyster::Engine::Pipeline::Deffered_Lightning::RenderGeometry( staticObject, numStaticObjects ); + + RenderLazer(); + + Oyster::Engine::Pipeline::Deffered_Lightning::EndRenderGeometry(); + + Oyster::Engine::Pipeline::Deffered_Lightning::RenderLightning(); + + //render Gui + Oyster::Engine::PrepareForRendering::BindBackBuffer(NULL); + Oyster::Engine::PrepareForRendering::Begin2DRender(); + + //Oyster::Engine::Render::ScreenQuad( GeometryResources[3], 0.5f ); + //Oyster::Engine::Render::ScreenQuad( ComputeExternalResources[0], 0.5f ); + //Oyster::Engine::Render::ScreenQuad( ComputeInternalResources[0], 0.5f ); + + Oyster::Engine::Render::ScreenQuad(GuiOverlay,0.11f); + + if (damageOverlayTime > 0.0f) + { + Oyster::Engine::Render::ScreenQuad(damageOverlay, 0.1f); + } + + + Oyster::Engine::PrepareForRendering::Begin2DTextRender(); + Oyster::Engine::Render::Text(fps,Oyster::Math::Float2(10,10),Oyster::Math::Float3::null); + + Oyster::Engine::Render::Text(mps,Oyster::Math::Float2(10,10),speedPos); + + Oyster::Engine::Render::Text(HP,Oyster::Math::Float2(10,10),HPPos); + + Oyster::Engine::Render::Text(Shield,Oyster::Math::Float2(10,10),ShieldPos+offset); + + + + + //Testing to make sure it renders + + //leave for debug + //Oyster::Engine::PrepareForRendering::Begin2DRender(); + //Oyster::Engine::Render::ScreenQuad(DefferedResourses[4],0.99f); + //Oyster::Engine::Render::Sprite(p[0]->renderAvatar.Material[1],Oyster::Math::Float2(100,100),Oyster::Math::Float3(100,100,0)); + +} + +void RenderEngine::RenderScoreboard(const Score scores[], int count, const Player * const * players) +{ + Float2 textSize = Float2(10, 10); + Float3 textPosition = Float3(100, 100, 0); + std::stringstream stream; + std::string name; + int teamPos; + //TEMP score variable + Score totScores[2]; + for(int i = 0; i < count; i++) + { + + teamPos=i%2; + textPosition.y = 170+teamPos*90+10*i; + name = players[scores[i].id]->getName(); + + if (!name.length()) + continue; + + stream.str(""); + stream << name; + stream << ": K/D/TK: "; + stream << scores[i].kills << "/"; + stream << scores[i].deaths << "/"; + stream << scores[i].teamkills; + totScores[teamPos]+=scores[i]; + Oyster::Engine::Render::Text(stream.str(), textSize, textPosition); + } + //Oyster::Engine::Render::Text("Team 1", textSize, textPosition); + //textPosition.y+=90; + //Oyster::Engine::Render::Text("Team 2", textSize, textPosition); + for (int i=0; i<2; i++) + { + textPosition.y=155+i*90; + stream.str(""); + stream << "Team "; + stream << i+1; + stream << ": K/D/TK: "; + stream << totScores[i].kills << "/"; + stream << totScores[i].deaths << "/"; + stream << totScores[i].teamkills; + + Oyster::Engine::Render::Text(stream.str(), textSize, textPosition); + } + + Oyster::Engine::PrepareForRendering::Begin2DRender(); + Oyster::Engine::Render::Sprite(scoreboardBackground, Float2(650.0f, 240.0f), textPosition - Float3(20.0f, 120.0f, 0.0f)); +} + +void RenderEngine::Damaged() +{ + damageOverlayTime = 550.5f; +} diff --git a/Into The Void client/RenderEngine.h b/Into The Void client/RenderEngine.h new file mode 100644 index 00000000..0aeb1d91 --- /dev/null +++ b/Into The Void client/RenderEngine.h @@ -0,0 +1,38 @@ +// Wrapper class for the Graphic Render System + +#pragma once +#ifndef RENDERENGINE_H +#define RENDERENGINE_H + +#include "Engine.h" +#include "Player.h" +#include "Protocoll.h" +#include "NetworkConnection.h" +#include "Event.h" + +class Player; + +class RenderEngine +{ +public: + enum Result { Success, Failure, Idle }; + static Result init( HINSTANCE thisInstance, LPSTR cmdLine, int showCommand, WNDPROC wProc ); + + static Result update(const Oyster::Math::Float4x4 &View, const Oyster::Math::Float4x4 &Projection, float deltaTime, NetworkConnection* conn); + + static void PrepareRendering(); + static void Present(); + + static void RenderGame( const Player* const *p, int nrOfp, int localPlayerID, const ::Oyster::Render::Model* const staticObject , unsigned int numStaticObjects ); + static void RenderText(Oyster::Render::Textbox* t, int nrOft); + static void RenderScoreboard(const Score scores[], int count, const Player * const * players); + static void Damaged(); + + static Oyster::Buffer *perObject; + +private: + static Oyster::Buffer *camera; + static Oyster::Buffer *View; +}; + +#endif \ No newline at end of file diff --git a/Into The Void client/SoundSystem.h b/Into The Void client/SoundSystem.h new file mode 100644 index 00000000..ea30b5ee --- /dev/null +++ b/Into The Void client/SoundSystem.h @@ -0,0 +1,47 @@ +// Wrapper class for the soundsystem + +#pragma once +#ifndef SOUNDSYSTEM_H +#define SOUNDSYSTEM_H + +#include "SoundEngine.h" +#include "SoundSource.h" +#include "Listener.h" + +#include "OysterMath.h" + +class SoundSystem +{ +public: + enum Result { Success, Failure }; + + static Result init( ) + { + if (!SoundEngine::Init()) + return Failure; + + return Success; + } + + static void release( ) + { + SoundEngine::Release(); + } + + static void update( ) + { + SoundEngine::Update(); + } + + static void setTransformation(const Oyster::Math::Float4x4 *transformation) + { + const float *position = transformation->v[3].xyz.element; + const float *forward = (-transformation->v[2]).xyz.element; + const float *up = transformation->v[1].xyz.element; + + Listener::SetPosition(position); + Listener::SetOrientation(forward, up); + } +}; + +#endif diff --git a/Into The Void client/TailCamera.cpp b/Into The Void client/TailCamera.cpp new file mode 100644 index 00000000..5a9e9eb6 --- /dev/null +++ b/Into The Void client/TailCamera.cpp @@ -0,0 +1,58 @@ +#include "TailCamera.h" + +using namespace Oyster::Game; +using namespace Oyster::Math; + +namespace PrivateStatic +{ + inline void applyOffsetBoundary( Float &target, const Float &boundary ) + { + if( target > boundary ) target = boundary; + else if( target < -boundary ) target = -boundary; + } +} + +TailCamera::TailCamera( const Float4x4 &rigidBody, const Float3 &offsetPos, const Float3 &upVector, const Float4x4 &projection ) + : SateliteCamera(&rigidBody, offsetPos, upVector, projection), maxOffsetRadian(1.5f), maxOffsetDistance(1.5f) {} + +const Float4x4 & TailCamera::getView( ) const +{ + PrivateStatic::applyOffsetBoundary( this->offsetDistance, this->maxOffsetDistance ); + + PrivateStatic::applyOffsetBoundary( this->offsetRadian.x, this->maxOffsetRadian ); + PrivateStatic::applyOffsetBoundary( this->offsetRadian.y, this->maxOffsetRadian ); + PrivateStatic::applyOffsetBoundary( this->offsetRadian.z, this->maxOffsetRadian ); + + PrivateStatic::applyOffsetBoundary( this->offsetPan.x, this->maxOffsetDistance ); + PrivateStatic::applyOffsetBoundary( this->offsetPan.y, this->maxOffsetDistance ); + PrivateStatic::applyOffsetBoundary( this->offsetPan.z, this->maxOffsetDistance ); + + return SateliteCamera::getView(); +} + +const Float4x4 & TailCamera::getViewProjection( ) const +{ + PrivateStatic::applyOffsetBoundary( this->offsetDistance, this->maxOffsetDistance ); + + PrivateStatic::applyOffsetBoundary( this->offsetRadian.x, this->maxOffsetRadian ); + PrivateStatic::applyOffsetBoundary( this->offsetRadian.y, this->maxOffsetRadian ); + PrivateStatic::applyOffsetBoundary( this->offsetRadian.z, this->maxOffsetRadian ); + + PrivateStatic::applyOffsetBoundary( this->offsetPan.x, this->maxOffsetDistance ); + PrivateStatic::applyOffsetBoundary( this->offsetPan.y, this->maxOffsetDistance ); + PrivateStatic::applyOffsetBoundary( this->offsetPan.z, this->maxOffsetDistance ); + + return SateliteCamera::getViewProjection(); +} + +void TailCamera::setMaxOffsetRadian( Float radian ) +{ this->maxOffsetRadian = radian; } + +void TailCamera::setMaxOffsetDistance( Float distance ) +{ this->maxOffsetDistance = distance; } + +void TailCamera::setRevolution( const Float &unitHorizontal, const Float &unitVertical ) +{ + SateliteCamera::setHorizontalRevolution( unitHorizontal * this->maxOffsetRadian ); + SateliteCamera::setVerticalRevolution( unitVertical * this->maxOffsetRadian ); +} \ No newline at end of file diff --git a/Into The Void client/TailCamera.h b/Into The Void client/TailCamera.h new file mode 100644 index 00000000..1f21a55c --- /dev/null +++ b/Into The Void client/TailCamera.h @@ -0,0 +1,26 @@ +#pragma once +#ifndef TAILCAMERA_H +#define TAILCAMERA_H + +#include "SateliteCamera.h" +#include "OysterMath.h" + +class TailCamera : public ::Oyster::Game::SateliteCamera +{ +public: + TailCamera( const ::Oyster::Math::Float4x4 &rigidBody, const ::Oyster::Math::Float3 &offsetPos, const ::Oyster::Math::Float3 &upVector, const ::Oyster::Math::Float4x4 &projection ); + + const ::Oyster::Math::Float4x4 & getView( ) const; + const ::Oyster::Math::Float4x4 & getViewProjection( ) const; + + void setMaxOffsetRadian( ::Oyster::Math::Float radian ); + void setMaxOffsetDistance( ::Oyster::Math::Float distance ); + + void setRevolution( const ::Oyster::Math::Float &unitHorizontal, const ::Oyster::Math::Float &unitVertical ); + +private: + ::Oyster::Math::Float maxOffsetRadian; + ::Oyster::Math::Float maxOffsetDistance; +}; + +#endif \ No newline at end of file diff --git a/Into The Void client/Time.cpp b/Into The Void client/Time.cpp new file mode 100644 index 00000000..9e670d9e --- /dev/null +++ b/Into The Void client/Time.cpp @@ -0,0 +1,32 @@ +#include "Time.h" +#include "Engine.h" + +float Time::secsPerCnt = 1.0f; +__int64 Time::prevTimeStamp = 0; +float Time::deltaTime = 0.0f; + +Time::Result Time::init( ) +{ + __int64 cntsPerSec = 0; + QueryPerformanceFrequency((LARGE_INTEGER*)&cntsPerSec); + secsPerCnt = 1.0f / (float)cntsPerSec; + + QueryPerformanceCounter((LARGE_INTEGER*)&prevTimeStamp); + + return Result::Success; +} + +void Time::update( ) +{ + __int64 currTimeStamp = 0; + QueryPerformanceCounter((LARGE_INTEGER*)&currTimeStamp); + + deltaTime = (currTimeStamp - prevTimeStamp) * secsPerCnt; + + prevTimeStamp = currTimeStamp; +} + +float Time::getDeltaTime_Seconds( ) +{ + return deltaTime; +} \ No newline at end of file diff --git a/Into The Void client/Time.h b/Into The Void client/Time.h new file mode 100644 index 00000000..80c03fdd --- /dev/null +++ b/Into The Void client/Time.h @@ -0,0 +1,21 @@ +#pragma once +#ifndef TIME_H +#define TIME_H + +class Time +{ +public: + enum Result { Failure, Success }; + static Result init( ); + + static void update( ); + + static float getDeltaTime_Seconds( ); + +private: + static float secsPerCnt; + static __int64 prevTimeStamp; + static float deltaTime; +}; + +#endif \ No newline at end of file diff --git a/Into The Void client/UserInterface.cpp b/Into The Void client/UserInterface.cpp new file mode 100644 index 00000000..f1179bd7 --- /dev/null +++ b/Into The Void client/UserInterface.cpp @@ -0,0 +1,167 @@ +#include "UserInterface.h" +#include "IntoTheVoid.h" +#include "Player.h" +#include "Input\InputController.h" +float MoveSpeed = 2.0f; +::Oyster::Math::Float UserInterface::elapsedUpdatePeriod = 0.0f; + +UserInterface::InitResult UserInterface::init( ) +{ + Oyster::Input::Controller::RestrictMouse(); + Oyster::Input::Controller::OrigoCenter(); + return UserInterface::Success; +} + +UserInterface::UpdateResult UserInterface::MessageLoop( ) +{ + MSG message; + + if( PeekMessage( &message, NULL, NULL, NULL, PM_REMOVE ) ) + { + TranslateMessage( &message ); + DispatchMessage( &message ); + + if( message.message == WM_QUIT ) + return UserInterface::ShutDown; + + return UserInterface::Updated; + } + + return UserInterface::Idle; +} + +void UserInterface::Update(TailCamera &T, float DeltaTime, Network::ClientToServerUpdateData& update) +{ + if(Oyster::Input::Controller::isMouseBtnDown(MK_LBUTTON)) + update.firePrim=true; + + if( UserInterface::isMovingForward() ) + { + T.panBackward( 0.5f * MoveSpeed * DeltaTime ); + ++update.forward; + } + else if( UserInterface::isMovingBackward() ) + { + T.panForward( 0.5f * MoveSpeed * DeltaTime ); + --update.forward; + } + else T.stabilisePanZ( 0.5f * MoveSpeed * DeltaTime ); + + if( UserInterface::isStrafingLeft() ) + { + T.panRight( 0.5f * MoveSpeed * DeltaTime ); + --update.straferight; + } + else if( UserInterface::isStrafingRight() ) + { + T.panLeft( 0.5f * MoveSpeed * DeltaTime ); + ++update.straferight; + } + else T.stabilisePanX( 0.5f * MoveSpeed * DeltaTime ); + + if( UserInterface::isStrafingUp() ) + { + T.panDown( 0.5f * MoveSpeed * DeltaTime ); + ++update.strafeup; + } + else if( UserInterface::isStrafingDown() ) + { + T.panUp( 0.5f * MoveSpeed * DeltaTime ); + --update.strafeup; + } + else T.stabilisePanY( 0.5f * MoveSpeed * DeltaTime ); + + if( UserInterface::isRollingLeft() ) + { + T.revolveRollRight( 0.5f * DeltaTime ); + ++update.roll; + } + else if( UserInterface::isRollingRight() ) + { + T.revolveRollLeft( 0.5f * DeltaTime ); + --update.roll; + } + else T.stabiliseRoll( 0.5f * DeltaTime ); + + if(Oyster::Input::Controller::isKeyDown(' ')) + { + update.braking=true; + } + else + { + } + ResolvePitchAndYaw(T,Oyster::Game::MoveAble::getDiscreteTimeSlice(),update); +} + +LRESULT CALLBACK UserInterface::wndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) +{ + /* TODO */ + + if( message == WM_DESTROY ) + { + PostQuitMessage( 0 ); + return 0; + } + return DefWindowProc(hWnd, message, wParam, lParam); +} + +bool UserInterface::isMovingForward( ) {return Oyster::Input::Controller::isKeyDown('W');} +bool UserInterface::isMovingBackward( ) {return Oyster::Input::Controller::isKeyDown('S');} +bool UserInterface::isStrafingLeft( ) {return Oyster::Input::Controller::isKeyDown('A');} +bool UserInterface::isStrafingRight( ) {return Oyster::Input::Controller::isKeyDown('D');} +bool UserInterface::isStrafingUp( ) {return Oyster::Input::Controller::isKeyDown('R');} +bool UserInterface::isStrafingDown( ) {return Oyster::Input::Controller::isKeyDown('F');} +bool UserInterface::isPitchingUp( ) {return Oyster::Input::Controller::GetAnalogY()<-0.05f;} +bool UserInterface::isPitchingDown( ) {return Oyster::Input::Controller::GetAnalogY()>0.05f;} +bool UserInterface::isYawingLeft( ) {return Oyster::Input::Controller::GetAnalogX()<-0.05f;} +bool UserInterface::isYawingRight( ) {return Oyster::Input::Controller::GetAnalogX()>0.05f;} +bool UserInterface::isRollingLeft( ) {return Oyster::Input::Controller::isKeyDown('Q');} +bool UserInterface::isRollingRight( ) {return Oyster::Input::Controller::isKeyDown('E');} + +void UserInterface::ResolvePitchAndYaw(TailCamera &T, float DeltaTime, Network::ClientToServerUpdateData& data) +{ + + T.setVerticalRevolution(-Oyster::Input::Controller::GetAnalogY() * 0.3f); + if( UserInterface::isPitchingUp() || UserInterface::isPitchingDown()) + { + + data.TurnVer=Oyster::Input::Controller::GetAnalogY(); + //::Oyster::Math::Float baseAcceleration = s.rotationProperty.acceleration.pitch; + //s.rotationProperty.acceleration.pitch *= -Oyster::Input::Controller::GetAnalogY() / ::Oyster::Game::MoveAble::getDiscreteTimeSlice(); + //s.pitchUp( ); + //s.disableRotationReduction(); + //s.rotationProperty.acceleration.pitch = baseAcceleration; + + } + /*else if( UserInterface::isPitchingDown() ) + { + ::Oyster::Math::Float baseAcceleration = s.rotationProperty.acceleration.pitch; + s.rotationProperty.acceleration.pitch *= Oyster::Input::Controller::GetAnalogY() / ::Oyster::Game::MoveAble::getDiscreteTimeSlice(); + s.pitchDown( ); + s.disableRotationReduction(); + s.rotationProperty.acceleration.pitch = baseAcceleration; + + }*/ + + + T.setHorizontalRevolution(-Oyster::Input::Controller::GetAnalogX()*0.3f); + if( UserInterface::isYawingLeft() || UserInterface::isYawingRight() ) + { + data.TurnHor= Oyster::Input::Controller::GetAnalogX(); + /*::Oyster::Math::Float baseAcceleration = s.rotationProperty.acceleration.yaw; + s.rotationProperty.acceleration.yaw *= -Oyster::Input::Controller::GetAnalogX() / ::Oyster::Game::MoveAble::getDiscreteTimeSlice(); + s.yawLeft( ); + s.disableRotationReduction(); + s.rotationProperty.acceleration.yaw = baseAcceleration;*/ + + } + /*else if( UserInterface::isYawingRight() ) + { + ::Oyster::Math::Float baseAcceleration = s.rotationProperty.acceleration.yaw; + s.rotationProperty.acceleration.yaw *= Oyster::Input::Controller::GetAnalogX() / ::Oyster::Game::MoveAble::getDiscreteTimeSlice(); + s.yawRight( ); + s.disableRotationReduction(); + s.rotationProperty.acceleration.yaw = baseAcceleration; + + }*/ +} diff --git a/Into The Void client/UserInterface.h b/Into The Void client/UserInterface.h new file mode 100644 index 00000000..aaaf37d9 --- /dev/null +++ b/Into The Void client/UserInterface.h @@ -0,0 +1,45 @@ +// Wrapper for User Interface System + +#pragma once +#ifndef USERINTERFACE_H +#define USERINTERFACE_H + +#include "Engine.h" +#include "Ship.h" +#include "TailCamera.h" +#include "NetworkUpdateStructs.h" + +class UserInterface +{ +public: + enum InitResult { Success, Failure }; + static InitResult init( ); + + enum UpdateResult { ShutDown, Updated, Idle }; + static UpdateResult MessageLoop( ); + + static void Update(TailCamera &T, float DeltaTime, Network::ClientToServerUpdateData& data); + + static LRESULT CALLBACK wndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ); + + static bool isMovingForward( ); + static bool isMovingBackward( ); + static bool isStrafingLeft( ); + static bool isStrafingRight( ); + static bool isStrafingUp( ); + static bool isStrafingDown( ); + static bool isPitchingUp( ); + static bool isPitchingDown( ); + static void ResetPitch(); + static bool isYawingLeft( ); + static bool isYawingRight( ); + static bool isRollingLeft( ); + static bool isRollingRight( ); + +private: + static ::Oyster::Math::Float elapsedUpdatePeriod; + + static void ResolvePitchAndYaw(TailCamera &T, float DeltaTime, Network::ClientToServerUpdateData& data); +}; + +#endif \ No newline at end of file diff --git a/Into The Void client/main.cpp b/Into The Void client/main.cpp new file mode 100644 index 00000000..f94eee72 --- /dev/null +++ b/Into The Void client/main.cpp @@ -0,0 +1,69 @@ +#include "Time.h" +#include "UserInterface.h" +#include "RenderEngine.h" +#include "SoundSystem.h" + +#include "GameStateStack.h" +#include "IntoTheVoid.h" +#include "MainMenu.h" + +float elapsedRenderPeriod=0.0f; +float RenderPeriod = 1.0f/60.0f; + +void appUpdate( GameStateStack *stack ); + +int WINAPI WinMain( HINSTANCE thisInstance, HINSTANCE previousInstance, LPSTR cmdLine, int showCommand ) +{ + srand((unsigned int)(time(0))); + if( Time::init() == Time::Failure ) return 0; + if( RenderEngine::init( thisInstance, cmdLine, showCommand, &UserInterface::wndProc ) == RenderEngine::Failure ) return 0; + if( UserInterface::init() == UserInterface::Failure ) return 0; + if( SoundSystem::init() == SoundSystem::Failure ) return 0; + + Oyster::Render::Textbox::SetTexture("..\\Content\\Textbox.png"); + + GameState *initialState = new MainMenu(); + GameStateStack *stack = new GameStateStack(initialState); + + bool done = false; + + while( !done && !stack->isEmpty() ) + { + switch( UserInterface::MessageLoop() ) + { + case UserInterface::Idle: + appUpdate( stack ); + break; + case UserInterface::ShutDown: + done = true; + break; + case UserInterface::Updated: + default: + break; + }; + } + + delete stack; + + SoundSystem::release(); + + return 0; +} + +void appUpdate( GameStateStack *stack ) +{ + Time::update(); + float deltaTime = Time::getDeltaTime_Seconds(); + + stack->Update(deltaTime); + SoundSystem::update(); + + elapsedRenderPeriod +=deltaTime; + if(elapsedRenderPeriod>= RenderPeriod) + { + RenderEngine::PrepareRendering(); + stack->Render(); + RenderEngine::Present(); + elapsedRenderPeriod=0.0f; + } +} diff --git a/Into The Void server/Into The Void server.cpp b/Into The Void server/Into The Void server.cpp new file mode 100644 index 00000000..1bcd1cd7 --- /dev/null +++ b/Into The Void server/Into The Void server.cpp @@ -0,0 +1,2 @@ +int main( ) +{ return 0; } \ No newline at end of file diff --git a/Into The Void.sln b/Into The Void.sln new file mode 100644 index 00000000..91e4e250 --- /dev/null +++ b/Into The Void.sln @@ -0,0 +1,168 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OysterEngine", "Template.vcxproj", "{B7AEB38F-D2BD-4897-AA11-B3B499DAD9E7}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OysterCollision", "Engine\Collision\Collision.vcxproj", "{BC646956-0319-4873-A750-B86733879BE5}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OysterMath", "Engine\Math\Math.vcxproj", "{6103F11F-54F3-45F7-9B27-F633CF287404}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Misc", "Engine\Misc\Misc.vcxproj", "{8298782E-BCE5-475B-BA33-D1F44FE9B57A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GameLogic", "GameLogic\GameLogic.vcxproj", "{85F3FFDE-CF48-43C6-9493-23FB1ACC2C35}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{49A4CF74-E06C-4D19-8749-D853559C7307}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Client", "Network\Client\Client.vcxproj", "{49F8095A-9CBA-4457-8F28-D56BE5E683CE}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Server", "Network\Server\Server.vcxproj", "{3B2C0E74-F1B7-4A60-B1E3-A11689AE11E4}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Sound", "Sound\Sound.vcxproj", "{6C92DF5A-9BBE-4590-BC12-287183FA5BCB}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OysterGame", "Engine\Game\OysterGame.vcxproj", "{287AA590-D40E-476F-94AF-2AD737E2B936}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Into The Void server", "Into The Void server\Into The Void server.vcxproj", "{34819C39-FF1F-4011-9FC2-4F2A5907FFC5}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Into The Void client", "Into The Void client\Into The Void client.vcxproj", "{07FAAFFF-77F2-4CB5-81EC-4875D305ED6E}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NetworkDependencies", "Network\NetworkDependencies\NetworkDependencies.vcxproj", "{6028444E-01B9-4EEA-8408-605487E601D9}" +EndProject +Global + GlobalSection(SubversionScc) = preSolution + Svn-Managed = True + Manager = AnkhSVN - Subversion Support for Visual Studio + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B7AEB38F-D2BD-4897-AA11-B3B499DAD9E7}.Debug|Win32.ActiveCfg = Debug|Win32 + {B7AEB38F-D2BD-4897-AA11-B3B499DAD9E7}.Debug|Win32.Build.0 = Debug|Win32 + {B7AEB38F-D2BD-4897-AA11-B3B499DAD9E7}.Debug|x64.ActiveCfg = Debug|x64 + {B7AEB38F-D2BD-4897-AA11-B3B499DAD9E7}.Debug|x64.Build.0 = Debug|x64 + {B7AEB38F-D2BD-4897-AA11-B3B499DAD9E7}.Debug|x86.ActiveCfg = Debug|x64 + {B7AEB38F-D2BD-4897-AA11-B3B499DAD9E7}.Release|Win32.ActiveCfg = Release|Win32 + {B7AEB38F-D2BD-4897-AA11-B3B499DAD9E7}.Release|Win32.Build.0 = Release|Win32 + {B7AEB38F-D2BD-4897-AA11-B3B499DAD9E7}.Release|x64.ActiveCfg = Release|x64 + {B7AEB38F-D2BD-4897-AA11-B3B499DAD9E7}.Release|x64.Build.0 = Release|x64 + {B7AEB38F-D2BD-4897-AA11-B3B499DAD9E7}.Release|x86.ActiveCfg = Release|x64 + {BC646956-0319-4873-A750-B86733879BE5}.Debug|Win32.ActiveCfg = Debug|Win32 + {BC646956-0319-4873-A750-B86733879BE5}.Debug|Win32.Build.0 = Debug|Win32 + {BC646956-0319-4873-A750-B86733879BE5}.Debug|x64.ActiveCfg = Debug|x64 + {BC646956-0319-4873-A750-B86733879BE5}.Debug|x64.Build.0 = Debug|x64 + {BC646956-0319-4873-A750-B86733879BE5}.Debug|x86.ActiveCfg = Debug|x64 + {BC646956-0319-4873-A750-B86733879BE5}.Release|Win32.ActiveCfg = Release|Win32 + {BC646956-0319-4873-A750-B86733879BE5}.Release|Win32.Build.0 = Release|Win32 + {BC646956-0319-4873-A750-B86733879BE5}.Release|x64.ActiveCfg = Release|x64 + {BC646956-0319-4873-A750-B86733879BE5}.Release|x64.Build.0 = Release|x64 + {BC646956-0319-4873-A750-B86733879BE5}.Release|x86.ActiveCfg = Release|x64 + {6103F11F-54F3-45F7-9B27-F633CF287404}.Debug|Win32.ActiveCfg = Debug|Win32 + {6103F11F-54F3-45F7-9B27-F633CF287404}.Debug|Win32.Build.0 = Debug|Win32 + {6103F11F-54F3-45F7-9B27-F633CF287404}.Debug|x64.ActiveCfg = Debug|x64 + {6103F11F-54F3-45F7-9B27-F633CF287404}.Debug|x64.Build.0 = Debug|x64 + {6103F11F-54F3-45F7-9B27-F633CF287404}.Debug|x86.ActiveCfg = Debug|x64 + {6103F11F-54F3-45F7-9B27-F633CF287404}.Release|Win32.ActiveCfg = Release|Win32 + {6103F11F-54F3-45F7-9B27-F633CF287404}.Release|Win32.Build.0 = Release|Win32 + {6103F11F-54F3-45F7-9B27-F633CF287404}.Release|x64.ActiveCfg = Release|x64 + {6103F11F-54F3-45F7-9B27-F633CF287404}.Release|x64.Build.0 = Release|x64 + {6103F11F-54F3-45F7-9B27-F633CF287404}.Release|x86.ActiveCfg = Release|x64 + {8298782E-BCE5-475B-BA33-D1F44FE9B57A}.Debug|Win32.ActiveCfg = Debug|Win32 + {8298782E-BCE5-475B-BA33-D1F44FE9B57A}.Debug|Win32.Build.0 = Debug|Win32 + {8298782E-BCE5-475B-BA33-D1F44FE9B57A}.Debug|x64.ActiveCfg = Debug|x64 + {8298782E-BCE5-475B-BA33-D1F44FE9B57A}.Debug|x64.Build.0 = Debug|x64 + {8298782E-BCE5-475B-BA33-D1F44FE9B57A}.Debug|x86.ActiveCfg = Debug|x64 + {8298782E-BCE5-475B-BA33-D1F44FE9B57A}.Release|Win32.ActiveCfg = Release|Win32 + {8298782E-BCE5-475B-BA33-D1F44FE9B57A}.Release|Win32.Build.0 = Release|Win32 + {8298782E-BCE5-475B-BA33-D1F44FE9B57A}.Release|x64.ActiveCfg = Release|x64 + {8298782E-BCE5-475B-BA33-D1F44FE9B57A}.Release|x64.Build.0 = Release|x64 + {8298782E-BCE5-475B-BA33-D1F44FE9B57A}.Release|x86.ActiveCfg = Release|x64 + {85F3FFDE-CF48-43C6-9493-23FB1ACC2C35}.Debug|Win32.ActiveCfg = Debug|Win32 + {85F3FFDE-CF48-43C6-9493-23FB1ACC2C35}.Debug|Win32.Build.0 = Debug|Win32 + {85F3FFDE-CF48-43C6-9493-23FB1ACC2C35}.Debug|x64.ActiveCfg = Debug|x64 + {85F3FFDE-CF48-43C6-9493-23FB1ACC2C35}.Debug|x64.Build.0 = Debug|x64 + {85F3FFDE-CF48-43C6-9493-23FB1ACC2C35}.Debug|x86.ActiveCfg = Debug|x64 + {85F3FFDE-CF48-43C6-9493-23FB1ACC2C35}.Release|Win32.ActiveCfg = Release|Win32 + {85F3FFDE-CF48-43C6-9493-23FB1ACC2C35}.Release|Win32.Build.0 = Release|Win32 + {85F3FFDE-CF48-43C6-9493-23FB1ACC2C35}.Release|x64.ActiveCfg = Release|x64 + {85F3FFDE-CF48-43C6-9493-23FB1ACC2C35}.Release|x64.Build.0 = Release|x64 + {85F3FFDE-CF48-43C6-9493-23FB1ACC2C35}.Release|x86.ActiveCfg = Release|x64 + {49F8095A-9CBA-4457-8F28-D56BE5E683CE}.Debug|Win32.ActiveCfg = Debug|Win32 + {49F8095A-9CBA-4457-8F28-D56BE5E683CE}.Debug|Win32.Build.0 = Debug|Win32 + {49F8095A-9CBA-4457-8F28-D56BE5E683CE}.Debug|x64.ActiveCfg = Debug|x64 + {49F8095A-9CBA-4457-8F28-D56BE5E683CE}.Debug|x64.Build.0 = Debug|x64 + {49F8095A-9CBA-4457-8F28-D56BE5E683CE}.Debug|x86.ActiveCfg = Debug|x64 + {49F8095A-9CBA-4457-8F28-D56BE5E683CE}.Release|Win32.ActiveCfg = Release|Win32 + {49F8095A-9CBA-4457-8F28-D56BE5E683CE}.Release|Win32.Build.0 = Release|Win32 + {49F8095A-9CBA-4457-8F28-D56BE5E683CE}.Release|x64.ActiveCfg = Release|x64 + {49F8095A-9CBA-4457-8F28-D56BE5E683CE}.Release|x64.Build.0 = Release|x64 + {49F8095A-9CBA-4457-8F28-D56BE5E683CE}.Release|x86.ActiveCfg = Release|x64 + {3B2C0E74-F1B7-4A60-B1E3-A11689AE11E4}.Debug|Win32.ActiveCfg = Debug|Win32 + {3B2C0E74-F1B7-4A60-B1E3-A11689AE11E4}.Debug|Win32.Build.0 = Debug|Win32 + {3B2C0E74-F1B7-4A60-B1E3-A11689AE11E4}.Debug|x64.ActiveCfg = Debug|x64 + {3B2C0E74-F1B7-4A60-B1E3-A11689AE11E4}.Debug|x64.Build.0 = Debug|x64 + {3B2C0E74-F1B7-4A60-B1E3-A11689AE11E4}.Debug|x86.ActiveCfg = Debug|x64 + {3B2C0E74-F1B7-4A60-B1E3-A11689AE11E4}.Release|Win32.ActiveCfg = Release|Win32 + {3B2C0E74-F1B7-4A60-B1E3-A11689AE11E4}.Release|Win32.Build.0 = Release|Win32 + {3B2C0E74-F1B7-4A60-B1E3-A11689AE11E4}.Release|x64.ActiveCfg = Release|x64 + {3B2C0E74-F1B7-4A60-B1E3-A11689AE11E4}.Release|x64.Build.0 = Release|x64 + {3B2C0E74-F1B7-4A60-B1E3-A11689AE11E4}.Release|x86.ActiveCfg = Release|x64 + {6C92DF5A-9BBE-4590-BC12-287183FA5BCB}.Debug|Win32.ActiveCfg = Debug|Win32 + {6C92DF5A-9BBE-4590-BC12-287183FA5BCB}.Debug|Win32.Build.0 = Debug|Win32 + {6C92DF5A-9BBE-4590-BC12-287183FA5BCB}.Debug|x64.ActiveCfg = Debug|x64 + {6C92DF5A-9BBE-4590-BC12-287183FA5BCB}.Debug|x64.Build.0 = Debug|x64 + {6C92DF5A-9BBE-4590-BC12-287183FA5BCB}.Debug|x86.ActiveCfg = Debug|x64 + {6C92DF5A-9BBE-4590-BC12-287183FA5BCB}.Release|Win32.ActiveCfg = Release|Win32 + {6C92DF5A-9BBE-4590-BC12-287183FA5BCB}.Release|Win32.Build.0 = Release|Win32 + {6C92DF5A-9BBE-4590-BC12-287183FA5BCB}.Release|x64.ActiveCfg = Release|x64 + {6C92DF5A-9BBE-4590-BC12-287183FA5BCB}.Release|x64.Build.0 = Release|x64 + {6C92DF5A-9BBE-4590-BC12-287183FA5BCB}.Release|x86.ActiveCfg = Release|x64 + {287AA590-D40E-476F-94AF-2AD737E2B936}.Debug|Win32.ActiveCfg = Debug|Win32 + {287AA590-D40E-476F-94AF-2AD737E2B936}.Debug|Win32.Build.0 = Debug|Win32 + {287AA590-D40E-476F-94AF-2AD737E2B936}.Debug|x64.ActiveCfg = Debug|x64 + {287AA590-D40E-476F-94AF-2AD737E2B936}.Debug|x64.Build.0 = Debug|x64 + {287AA590-D40E-476F-94AF-2AD737E2B936}.Debug|x86.ActiveCfg = Debug|x64 + {287AA590-D40E-476F-94AF-2AD737E2B936}.Release|Win32.ActiveCfg = Release|Win32 + {287AA590-D40E-476F-94AF-2AD737E2B936}.Release|Win32.Build.0 = Release|Win32 + {287AA590-D40E-476F-94AF-2AD737E2B936}.Release|x64.ActiveCfg = Release|x64 + {287AA590-D40E-476F-94AF-2AD737E2B936}.Release|x64.Build.0 = Release|x64 + {287AA590-D40E-476F-94AF-2AD737E2B936}.Release|x86.ActiveCfg = Release|x64 + {34819C39-FF1F-4011-9FC2-4F2A5907FFC5}.Debug|Win32.ActiveCfg = Debug|Win32 + {34819C39-FF1F-4011-9FC2-4F2A5907FFC5}.Debug|Win32.Build.0 = Debug|Win32 + {34819C39-FF1F-4011-9FC2-4F2A5907FFC5}.Debug|x64.ActiveCfg = Debug|x64 + {34819C39-FF1F-4011-9FC2-4F2A5907FFC5}.Debug|x64.Build.0 = Debug|x64 + {34819C39-FF1F-4011-9FC2-4F2A5907FFC5}.Debug|x86.ActiveCfg = Debug|x64 + {34819C39-FF1F-4011-9FC2-4F2A5907FFC5}.Release|Win32.ActiveCfg = Release|Win32 + {34819C39-FF1F-4011-9FC2-4F2A5907FFC5}.Release|Win32.Build.0 = Release|Win32 + {34819C39-FF1F-4011-9FC2-4F2A5907FFC5}.Release|x64.ActiveCfg = Release|x64 + {34819C39-FF1F-4011-9FC2-4F2A5907FFC5}.Release|x64.Build.0 = Release|x64 + {34819C39-FF1F-4011-9FC2-4F2A5907FFC5}.Release|x86.ActiveCfg = Release|x64 + {07FAAFFF-77F2-4CB5-81EC-4875D305ED6E}.Debug|Win32.ActiveCfg = Debug|Win32 + {07FAAFFF-77F2-4CB5-81EC-4875D305ED6E}.Debug|Win32.Build.0 = Debug|Win32 + {07FAAFFF-77F2-4CB5-81EC-4875D305ED6E}.Debug|x64.ActiveCfg = Debug|x64 + {07FAAFFF-77F2-4CB5-81EC-4875D305ED6E}.Debug|x64.Build.0 = Debug|x64 + {07FAAFFF-77F2-4CB5-81EC-4875D305ED6E}.Debug|x86.ActiveCfg = Debug|x64 + {07FAAFFF-77F2-4CB5-81EC-4875D305ED6E}.Release|Win32.ActiveCfg = Release|Win32 + {07FAAFFF-77F2-4CB5-81EC-4875D305ED6E}.Release|Win32.Build.0 = Release|Win32 + {07FAAFFF-77F2-4CB5-81EC-4875D305ED6E}.Release|x64.ActiveCfg = Release|x64 + {07FAAFFF-77F2-4CB5-81EC-4875D305ED6E}.Release|x64.Build.0 = Release|x64 + {07FAAFFF-77F2-4CB5-81EC-4875D305ED6E}.Release|x86.ActiveCfg = Release|x64 + {6028444E-01B9-4EEA-8408-605487E601D9}.Debug|Win32.ActiveCfg = Debug|Win32 + {6028444E-01B9-4EEA-8408-605487E601D9}.Debug|Win32.Build.0 = Debug|Win32 + {6028444E-01B9-4EEA-8408-605487E601D9}.Debug|x64.ActiveCfg = Debug|x64 + {6028444E-01B9-4EEA-8408-605487E601D9}.Debug|x64.Build.0 = Debug|x64 + {6028444E-01B9-4EEA-8408-605487E601D9}.Debug|x86.ActiveCfg = Debug|x64 + {6028444E-01B9-4EEA-8408-605487E601D9}.Release|Win32.ActiveCfg = Release|Win32 + {6028444E-01B9-4EEA-8408-605487E601D9}.Release|Win32.Build.0 = Release|Win32 + {6028444E-01B9-4EEA-8408-605487E601D9}.Release|x64.ActiveCfg = Release|x64 + {6028444E-01B9-4EEA-8408-605487E601D9}.Release|x64.Build.0 = Release|x64 + {6028444E-01B9-4EEA-8408-605487E601D9}.Release|x86.ActiveCfg = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Network/Client/ClientDataHandler.cpp b/Network/Client/ClientDataHandler.cpp new file mode 100644 index 00000000..52d0f2ff --- /dev/null +++ b/Network/Client/ClientDataHandler.cpp @@ -0,0 +1,112 @@ +#include "SocketClient.h" + +#pragma once +#ifndef SOCKET_DATA_CPP +#define SOCKET_DATA_CPP + +/*std::vector splitString(char* p_inStr, char p_delim) +{ +std::stringstream ss(p_inStr); +std::vector elems; +std::string item; +while(std::getline(ss, item, p_delim)) +{ +elems.push_back(item); +} +return elems; +}*/ + +void SocketClient::parseReceivedData(/*char* data, int size*/) +{ + switch (recvBuffer[0]) // TODO: runtime error occured here when shutting down client. recvBuffer invalid pointer. ~Dan 2013-05-14 + { + case 1://It's data + parseData(); + break; + case 2://For the moment, this is only for init data + parseGameInitData(); + break; + case 3://It's a chat message + parseMessage(); + break; + case 4://It's a server message + parseServermessage(); + break; + case 5://Player has been connected to a game lobby + parseLobbyInitData(); + break; + case 6://It's an event + parseReceivedEvent(); + break; + case 7: + parseReceivedEffect(); + break; + case 8: + parseRenderData(); + break; + default: + int a=0; + + } +} +void SocketClient::parseRenderData() +{ + receiveRenderData(recvBuffer+1, recvBufLen-1); +} +void SocketClient::parseReceivedEffect() +{ + receiveEffectData(recvBuffer+1, recvBufLen-1); +} +void SocketClient::parseReceivedEvent() +{ + receiveEvent(recvBuffer+1); +} +void SocketClient::parseGameInitData() +{ + receiveGameInitData(recvBuffer+1); + connectStatus=true; +} + +void SocketClient::parseLobbyInitData() +{ + receiveLobbyInitData(recvBuffer+1, recvBufLen-1); + connectStatus=true; +} + +void SocketClient::parseServermessage() +{ + recvBuffer[recvBufLen]='\0'; + if(!strcmp(recvBuffer+1, "connected")) + { + connectStatus=true; + connStatus=ONLINE_MAINMENU; + receiveConnStatus(ONLINE_MAINMENU); + } + else if(!strcmp(recvBuffer+1, "qst")) + { + connStatus=ONLINE_QUEUEING; + receiveConnStatus(ONLINE_QUEUEING); + } + else if(!strcmp(recvBuffer+1, "qed")) + { + connStatus=ONLINE_MAINMENU; + receiveConnStatus(ONLINE_MAINMENU); + } + //Server message of some sort +} + +void SocketClient::parseData() +{ + //memcpy(&tmpPlayer,buffer+1,playerDataSize); + //playerContPtr->setPlayerStruct(tmpPlayer); + receivePlayerUpdate(recvBuffer+1, recvBufLen-1); +} + +void SocketClient::parseMessage() +{ + //std::string message; + //message="[Chat] "+users[pid].getUsername()+": "+(buffer+1); + printf("%s\n",recvBuffer+1); +} + +#endif diff --git a/Network/Client/ClientInitFunctions.cpp b/Network/Client/ClientInitFunctions.cpp new file mode 100644 index 00000000..e2c4b920 --- /dev/null +++ b/Network/Client/ClientInitFunctions.cpp @@ -0,0 +1,79 @@ +#include "SocketClient.h" + +#pragma once +#ifndef SOCKET_INIT_CPP +#define SOCKET_INIT_CPP + +bool SocketClient::startReceiveThread() +{ + threadhandle[0]=CreateThread( + NULL, + 0, + (LPTHREAD_START_ROUTINE)&receiveDataThreadV, + (LPVOID) this, + 0, + NULL); + return true; +} + +bool SocketClient::startSendDataThread() +{ + threadhandle[1]=CreateThread( + NULL, + 0, + (LPTHREAD_START_ROUTINE)&receiveDataThreadV, + (LPVOID) this, + 0, + NULL); + return true; +} +bool SocketClient::init(int listenPort) +{ + return initUDPSocket(listenPort); +} +bool SocketClient::connectToIP(const char* ip, int listenPort, char* initData, int initDataSize) +{ + init(listenPort); + //--------------------------------------------- + // Set up the port and IP of the server + //Port starts up as a different one from when connected, it changes once the server has exchanged some info with the client + + UDPsendAddr.sin_family = AF_INET; + UDPsendAddr.sin_port = htons(UDPSendPort); + UDPsendAddr.sin_addr.s_addr = inet_addr(ip); + + TCPsendAddr.sin_family = AF_INET; + TCPsendAddr.sin_port = htons(TCPSendPort); + TCPsendAddr.sin_addr.s_addr = inet_addr(ip); + /*iResult=connect(connTCP, (SOCKADDR *) &TCPsendAddr, addrSize); + if (iResult == SOCKET_ERROR) { + int test=WSAGetLastError(); + wprintf(L"connect failed with error: %d\n", WSAGetLastError()); + //closesocket(connTCP); + //WSACleanup(); + return false; + }/* + iResult=send(connTCP, initData, initDataSize, 0); + if (iResult == SOCKET_ERROR) { + int test=WSAGetLastError(); + wprintf(L"connect failed with error: %d\n", WSAGetLastError()); + //closesocket(connTCP); + //WSACleanup(); + return false; + }*/ + + iResult = sendto(connUDP, + initData, initDataSize, 0, (SOCKADDR *) & UDPsendAddr, addrSize); + if (iResult == SOCKET_ERROR) { + wprintf(L"Client UDP sendto failed with error: %d\n", WSAGetLastError()); + //closesocket(connUDP); + //WSACleanup(); + return false; + } + //connectStatus=true; + connectStatus=false; + return true; +} + + +#endif diff --git a/Network/Client/ClientMain.cpp b/Network/Client/ClientMain.cpp new file mode 100644 index 00000000..5c297686 --- /dev/null +++ b/Network/Client/ClientMain.cpp @@ -0,0 +1,79 @@ +#include "SocketClient.h" +const int maxThreadCount=2; +bool validateIpAddress(const std::string ipAddress) +{ + struct sockaddr_in sa; + int result = inet_pton(AF_INET, ipAddress.c_str(), &(sa.sin_addr)); + return result != 0; +} +/*int main(int argc, char *argv[]) +{ + std::string tst; + bool test=true; + //Multithreading variables + //int nThreads = 0; + //DWORD dwThreadId[maxThreadCount]; + //HANDLE threadhandle; + + GameClass game; + SocketClient client; + //Sets up the link to the GameClass class. + client.setPlayerContPtr(&game); + //This is the loop which makes the user enter the server address. + while (!client.isReady()); + do + { + if (!test) + { + printf("Could not connect to server. Try another IP.\n"); + } + else + { + printf("Enter the server ip. \n"); + } + getline(std::cin, tst); + if (tst.length()==0) + { + tst="127.0.0.1"; + } + if (validateIpAddress(tst)) + { + //Tmp init connection message: set username + char* tmp=new char[30]; + printf("What is your desired username?\n"); + std::cin.getline(tmp,30); + if (strlen(tmp)==0) + { + tmp="Anonymous"; + } + printf("Username set to %s\n", tmp); + + test=client.connectToIP(tst.c_str(), tmp, strlen(tmp)); + } + else + { + printf("Invalid IPaddress. Please enter a new IPaddress.\n"); + test=false; + } + } while (!test); + while (!client.isConnected()); + Sleep(1000); + //Starts the receive loop + //threadhandle=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)&client.receiveDataThreadV,(LPVOID) &client,0,&dwThreadId[0]); + client.startReceiveThread(); + //GetExitCodeThread(threadhandle, eCode); + //This is just a loop to receive user input which creates a natural delay for sendUserData. + printf("Write what you want to send\n"); + tst="tmp init message"; + while (tst.length()>0) + { + client.sendMessage(tst); + client.sendUserData(); + getline(std::cin, tst); + } + //Kills off the thread and connection + //DWORD eCode=0; + //TerminateThread(threadhandle, eCode); + client.closeConnection(); + return 0; +}*/ \ No newline at end of file diff --git a/Network/Client/ClientTCPSpecific.cpp b/Network/Client/ClientTCPSpecific.cpp new file mode 100644 index 00000000..1e8b7216 --- /dev/null +++ b/Network/Client/ClientTCPSpecific.cpp @@ -0,0 +1,39 @@ +#include "SocketClient.h" + +bool SocketClient::initTCPSocket(int listenPort) +{ + TCPrecvAddr.sin_family = AF_INET; + TCPrecvAddr.sin_addr.s_addr = htonl(INADDR_ANY); + TCPrecvAddr.sin_port = htons(/*TCPRecvPort*/listenPort); + + connTCP = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (connTCP == INVALID_SOCKET) + { + wprintf(L"socket function failed with error: %ld\n", WSAGetLastError()); + WSACleanup(); + return false; + } + + iResult = bind(connTCP, (SOCKADDR *) & TCPrecvAddr, addrSize); + if (iResult == SOCKET_ERROR) + { + int tst=WSAGetLastError(); + wprintf(L"bind function failed with error %d\n", WSAGetLastError()); + iResult = closesocket(connTCP); + if (iResult == SOCKET_ERROR) + wprintf(L"closesocket function failed with error %d\n", WSAGetLastError()); + //WSACleanup(); + return false; + } + return true; +} +bool SocketClient::sendDataTCP(const char* data, int size) +{ + iResult = sendto(connTCP, + data, size, 0, (SOCKADDR *) & TCPsendAddr, addrSize); + if (iResult == SOCKET_ERROR) { + wprintf(L"TCP sendto failed with error: %d\n", WSAGetLastError()); + return false; + } + return true; +} \ No newline at end of file diff --git a/Network/Client/ClientUDPSpecific.cpp b/Network/Client/ClientUDPSpecific.cpp new file mode 100644 index 00000000..9cab63ae --- /dev/null +++ b/Network/Client/ClientUDPSpecific.cpp @@ -0,0 +1,39 @@ +#include "SocketClient.h" +bool SocketClient::initUDPSocket(int listenPort) +{ + UDPrecvAddr.sin_family = AF_INET; + UDPrecvAddr.sin_addr.s_addr = htonl(INADDR_ANY); + UDPrecvAddr.sin_port = htons(listenPort); + //--------------------------------------------- + // Create a socket for sending data + connUDP = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (connUDP == INVALID_SOCKET) + { + wprintf(L"socket failed with error: %ld\n", WSAGetLastError()); + WSACleanup(); + return false; + } + iResult = bind(connUDP, (SOCKADDR *) & UDPrecvAddr, addrSize); + if (iResult == SOCKET_ERROR) + { + wprintf(L"bind function failed with error %d\n", WSAGetLastError()); + iResult = closesocket(connUDP); + if (iResult == SOCKET_ERROR) + wprintf(L"closesocket function failed with error %d\n", WSAGetLastError()); + WSACleanup(); + return false; + } + return true; +} +bool SocketClient::sendDataUDP(const char* data, int size) +{ + iResult = sendto(connUDP, + data, size, 0, (SOCKADDR *) & UDPsendAddr, addrSize); + if (iResult == SOCKET_ERROR) { + wprintf(L"sendto failed with error: %d\n", WSAGetLastError()); + //closesocket(connUDP); + //WSACleanup(); + return false; + } + return true; +} \ No newline at end of file diff --git a/Network/Client/SocketClient.cpp b/Network/Client/SocketClient.cpp new file mode 100644 index 00000000..cde039cf --- /dev/null +++ b/Network/Client/SocketClient.cpp @@ -0,0 +1,133 @@ +#include "SocketClient.h" +#pragma once +#ifndef SOCKET_CLIENT_CPP +#define SOCKET_CLIENT_CPP + +SocketClient::SocketClient() +{ + playerDataSize=Network::CLIENT_PLAYER_DATA_SIZE; + sendDelayMS=10; + connUDP = INVALID_SOCKET; + connTCP = INVALID_SOCKET; + //sendBuffer=new char[BUFFER_MAX_SIZE]; + //sendBufLen=BUFFER_MAX_SIZE; + //ZeroMemory(sendBuffer,sendBufLen); + recvBuffer=new char[BUFFER_MAX_SIZE]; + recvBufLen=BUFFER_MAX_SIZE; + ZeroMemory(recvBuffer,recvBufLen); + + dataBuf=new char[playerDataSize+1]; + dataBuf[0]=1; + //ZeroMemory(b,sizeof(buffer)); + //---------------------- + // Initialize Winsock + iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); + if (iResult != NO_ERROR) { + printf("WSAStartup failed with error: %d\n", iResult); + } + + + + addrSize=sizeof(sockaddr_in); + connectStatus=false; +} + + + +bool SocketClient::sendUserData() +{ + //memcpy(dataBuf+1,&playerContPtr->getPlayerData(),playerDataSize); + //return sendData(dataBuf, playerDataSize+1); + printf("NOT YET IMPLEMENTED"); + return false; +} + +bool SocketClient::sendUserData(char* data, int size) +{ + memcpy(dataBuf+1,data,size); + return sendDataUDP(dataBuf, size+1); +} + +bool SocketClient::sendMessage(std::string msg) +{ + if (msg[0]=='/') + { + //Server command + msg[0]=2; + + } + else + { + //Chat message + msg='1'+msg; + msg[0]=3; + } + return sendDataUDP(msg.c_str(), (int)msg.size()); +} + +bool SocketClient::closeConnection() +{ + connectStatus=false; + Sleep(5); + //Give the threads 5 ms to quit themselves before terminating them + DWORD eCode=0; + TerminateThread(threadhandle[0], eCode); + TerminateThread(threadhandle[1], eCode); + //--------------------------------------------- + // When the application is finished sending, close the socket. + setupStatus=false; + printf("Finished sending. Closing socket.\n"); + iResult = closesocket(connUDP); + if (iResult == SOCKET_ERROR) + { + wprintf(L"closesocket failed with error: %d\n", WSAGetLastError()); + WSACleanup(); + return false; + } + //--------------------------------------------- + // Clean up and quit. + printf("Exiting.\n"); + WSACleanup(); + return true; +} + +void SocketClient::receiveDataThreadV(SocketClient* ptr) +{ + while(true) + { + ptr->recvBufLen=recvfrom(ptr->connUDP, ptr->recvBuffer, BUFFER_MAX_SIZE, 0, (SOCKADDR *) & ptr->UDPsendAddr, &ptr->addrSize); + if (ptr->recvBufLen == SOCKET_ERROR) + { + wprintf(L"recv failed with error %d\n", WSAGetLastError()); + } + //ptr->buffer[ptr->iResult]='\0'; + else + ptr->parseReceivedData(); + } +} + + +void SocketClient::receiveDataWaitOnResponse() +{ + recvBufLen=recvfrom(connUDP, recvBuffer, BUFFER_MAX_SIZE, 0, (SOCKADDR *) & UDPsendAddr, &addrSize); + if (recvBufLen == SOCKET_ERROR) + { + wprintf(L"recv failed with error %d\n", WSAGetLastError()); + } + //buffer[iResult]='\0'; + else + parseReceivedData(); +} + +void SocketClient::sendDataThreadV(SocketClient* ptr) +{ + printf("NOT YET IMPLEMENTED"); + /*while(ptr->connectStatus) + { + memcpy(ptr->dataBuf+1,&ptr->playerContPtr->getPlayerData(),playerDataSize); + ptr->sendData(ptr->dataBuf, playerDataSize+1); + Sleep(ptr->sendDelayMS); + }*/ +} + +#endif \ No newline at end of file diff --git a/Network/Client/SocketClient.h b/Network/Client/SocketClient.h new file mode 100644 index 00000000..46c57d8d --- /dev/null +++ b/Network/Client/SocketClient.h @@ -0,0 +1,147 @@ +#pragma once +//Start by defining unicode +//#ifndef UNICODE +//#define UNICODE +//#endif +//defining WIN32_LEAN_AND_MEAN this early is REQUIRED if you want to avoid a certain winsock error. +//#define WIN32_LEAN_AND_MEAN +//#define NOMINMAX +//#include +//#include "GameClassExample.h" +//These includes are required for winsock +#include "Network.h" +//#include +//#include +//#include +//#include +//#include "OysterMath.h" +//These are optional includes for various useful features +#include +#include +#include +#include + +//ws2_32.lib is a lib file the linker requires for winsock compilation +#pragma comment(lib, "Ws2_32.lib") + +//constants used by the socket client to avoid hard coding and/or mass variable declaration +const short TCPSendPort = 11110; +const short TCPRecvPort = 11111; +const short UDPSendPort = 11000; +const short UDPRecvPort = 11001; +const int BUFFER_MAX_SIZE = 4096; + +enum ConnectionStatus +{ + OFFLINE, + ONLINE_MAINMENU, + ONLINE_QUEUEING, + ONLINE_INLOBBY, + ONLINE_INGAME +}; +class SocketClient +{ +private: + HANDLE threadhandle[2]; + int sendDelayMS; + + //2 bools used to verify the activation of the client so threads can't start too early + ConnectionStatus connStatus; + bool setupStatus; + bool connectStatus; + + //iResult is used to check error codes + int iResult; + //wsaData records error messages and errors which winsock might encounter + WSADATA wsaData; + + //Main socket + SOCKET connUDP; + SOCKET connTCP; + + //Addresses used for data transfer + sockaddr_in TCPrecvAddr; + sockaddr_in TCPsendAddr; + //UDPrecvAddr marks the port and IP adress the server is supposed to return data to. + sockaddr_in UDPrecvAddr; + //UDPsendAddr marks which IP and port the client is supposed to send data to. + sockaddr_in UDPsendAddr; + //size of a sockaddr_in. This might as well be a constant, but i'm keeping it in the class for performance reasons. + int addrSize; + + //buffer which is filled when data receive happens. + char* recvBuffer; + //this variable tracks the buffer length. + int recvBufLen; + + //dataBuf is a buffer solely for sending your own user data. It never changes size in order to increase performance. + //char* sendBuffer; + //int sendBufLen; + //PlayerStruct tmpPlayer; + char* dataBuf; + int playerDataSize; +public: + void setPlayerDataSize(int pds){playerDataSize=pds;} + //Constructor + SocketClient(); + + //Initiation for sockets. + bool init(int listenPort); + bool initTCPSocket(int listenPort); + bool initUDPSocket(int listenPort); + //Connects to a server of a user-defined IP. Can only be called after an initXSocket has gone through. + //The 2 remaining variables are init data and size of said data. Currently username. + bool connectToIP(const char* ip, int listenPort, char* initData, int initDataSize); + //sends an undefined data type of (variable#2) size to the server. + bool sendDataUDP(const char*, int); + bool sendDataTCP(const char*, int); + //sends a text string to the server. + bool sendMessage(std::string str); + bool sendServerMessage(std::string str); + //sends user data to the server + bool sendUserData(); + bool sendUserData(char* data, int size); + + //Closes connection, kills off the socket. + bool closeConnection(); + + //Simple ifBoolIsTrue checks + bool isReady() const {return setupStatus;} + bool isConnected() const {return connectStatus;} + void receiveDataWaitOnResponse(); + //Sends data periodically + static void sendDataThreadV(SocketClient* ptr); + //Receive loop. This is event-based and is on its own thread. + static void receiveDataThreadV(SocketClient* ptr); + //Once data is received, it calls on the parseReceivedData function. + void parseReceivedData(); + //void parseReceivedKeyframe(); + //If an event is called from the server, this function will be called. + void parseReceivedEvent(); + void parseReceivedEffect(); + //It is then sent to one of the following functions based on the first byte of the buffer. + + //Servermessage + void parseServermessage(); + //single user data + void parseData(); + //string (character data) + void parseMessage(); + //init data which sets the start position etc of all characters. + void parseLobbyInitData(); + void parseGameInitData(); + void parseRenderData(); + + bool startReceiveThread(); + bool startSendDataThread(); + void setSendDelay(int ms){sendDelayMS=ms;} + + //virtual functions + virtual void receiveGameInitData(char*)=0; + virtual void receiveLobbyInitData(char*, int)=0; + virtual void receivePlayerUpdate(char*, int)=0; + virtual void receiveRenderData(char*, int)=0; + virtual void receiveEffectData(char*, int)=0; + virtual void receiveConnStatus(ConnectionStatus)=0; + virtual void receiveEvent(char*)=0; +}; \ No newline at end of file diff --git a/Network/NetworkDependencies/Event.cpp b/Network/NetworkDependencies/Event.cpp new file mode 100644 index 00000000..33e92bbf --- /dev/null +++ b/Network/NetworkDependencies/Event.cpp @@ -0,0 +1,262 @@ +#include "Event.h" +using namespace Event; + + +//---------------------------- +// BulletCreated class definitions +BulletCreated::BulletCreated(int ownerID, Float3 position, Float3 direction) + : + GameEvent() +{ + data.owner=ownerID; + data.head=direction; +} +void BulletCreated::LoadRawData(char* d) +{ + memcpy(&data, d, GetSize()); + /*int offset=0; + memcpy(&data.position, data, sizeof(Float3)); + offset+=sizeof(Float3); + + memcpy(&data.head, d+offset, sizeof(Float3)); + offset+=sizeof(Float3); + memcpy(&data.owner, d+offset, sizeof(int));*/ +} +void BulletCreated::SaveRawData(char* d) +{ + memcpy(d, &data, GetSize()); +} + +//---------------------------- +// BulletHit class definitions +BulletHit::BulletHit(int attacker, int hitPlayer) + : + GameEvent() +{ + data.hitTarget=hitPlayer; + data.attackingTarget=attacker; + //this->hpLeft=hl; + //this->shieldLeft=sl; +} +void BulletHit::LoadRawData(char* d) +{ + memcpy(&data, d, GetSize()); +} +void BulletHit::SaveRawData(char* d) +{ + memcpy(d, &data, GetSize()); +} + +ScoreUpdate::ScoreUpdate(Score* scores) +{ + for (int i=0; iGetSize()); + /*int offset=0; + memcpy(&data.position, data, sizeof(Float3)); + offset+=sizeof(Float3); + + memcpy(&playerID, data+offset, sizeof(int));*/ +} +void ShipSpawned::SaveRawData(char* d) +{ + memcpy(d, &data, GetSize()); +} + + +//---------------------------- +// GameEnded class definitions +GameEnded::GameEnded() + : + GameEvent() +{ +} +GameEnded::GameEnded(int winner) + : + GameEvent() +{ + data.winningTeam=winner; +} +void GameEnded::LoadRawData(char* d) +{ + memcpy(&data, d, GetSize()); + /*int offset=0; + memcpy(&eventPosition, data, sizeof(Float3)); + offset+=sizeof(Float3); + + memcpy(&winningTeam, data+offset, sizeof(int)); + offset+=sizeof(int); + + for (int i=0; i +#include +#include +#include +#include +#include +#include +#include + +#include "OysterMath.h" +using namespace Oyster::Math; + +//ws2_32.lib is a lib file the linker requires for winsock compilation +#pragma comment(lib, "Ws2_32.lib") +#endif \ No newline at end of file diff --git a/Network/NetworkDependencies/NetworkInitStructs.h b/Network/NetworkDependencies/NetworkInitStructs.h new file mode 100644 index 00000000..7ef04ed1 --- /dev/null +++ b/Network/NetworkDependencies/NetworkInitStructs.h @@ -0,0 +1,70 @@ +#ifndef NET_INIT_STRUCTS_H +#define NET_INIT_STRUCTS_H +#include "NetworkIncludes.h" +#include "NetworkConstants.h" +struct PlayerInitStruct +{ + INT8 pid; + int teamid; + Oyster::Math::Float4x4 position; + PlayerInitStruct() + { + pid=0; + //position=Oyster::Math::Float4x4::identity; + } +}; + +struct GameInitData +{ + INT8 pid; + //std::string playerNames[PLAYER_MAX_COUNT]; + PlayerInitStruct player[PLAYER_MAX_COUNT]; +}; + +struct LobbyUserStruct +{ + INT8 pid; + INT8 shipID; + char usrName[15]; + LobbyUserStruct() + { + pid=0; + shipID=0; + usrName[0]='\0'; + } + void setName(const char* n) + { + strcpy_s(usrName, n); + } + int size() + { + int sz=sizeof(pid); + sz+=sizeof(shipID); + int tmp=(int)strlen(usrName); + sz+=(int)strlen(usrName); + return sz; + } +}; +struct LobbyInitData +{ + INT8 pid; + INT8 playerCount; + int timer; + LobbyUserStruct players[PLAYER_MAX_COUNT]; + LobbyInitData() + { + pid=0; + for (int i=0; i splitString(const char* p_inStr, char p_delim) +{ + std::stringstream ss(p_inStr); + std::vector elems; + std::string item; + while(std::getline(ss, item, p_delim)) + { + elems.push_back(item); + } + return elems; +} \ No newline at end of file diff --git a/Network/NetworkDependencies/NetworkMiscFunctions.h b/Network/NetworkDependencies/NetworkMiscFunctions.h new file mode 100644 index 00000000..a6959020 --- /dev/null +++ b/Network/NetworkDependencies/NetworkMiscFunctions.h @@ -0,0 +1,9 @@ +#ifndef NET_MISC_FNC_H +#define NET_MISC_FNC_H +#include +#include +#include +std::vector splitString(const char* p_inStr, char p_delim); +#define SSTR( x ) dynamic_cast< std::ostringstream & >( \ + ( std::ostringstream() << std::dec << x ) ).str() +#endif \ No newline at end of file diff --git a/Network/NetworkDependencies/NetworkTimer.cpp b/Network/NetworkDependencies/NetworkTimer.cpp new file mode 100644 index 00000000..42b8a143 --- /dev/null +++ b/Network/NetworkDependencies/NetworkTimer.cpp @@ -0,0 +1,85 @@ +#include "NetworkTimer.h" +NetworkTimer::NetworkTimer() + : + c_SecondsPerCount(0.0), + c_DeltaTime(-1.0), + c_BaseTime(0), + c_PausedTime(0), + c_PrevTime(0), + c_CurrTime(0), + c_Stopped(false) +{ + __int64 countsPerSec; + QueryPerformanceFrequency((LARGE_INTEGER*)&countsPerSec); + c_SecondsPerCount =1.0 / (double)countsPerSec; + + QueryPerformanceCounter((LARGE_INTEGER*)&c_PrevTime); +} + +void NetworkTimer::start() +{ + __int64 p_StartTime; + QueryPerformanceCounter((LARGE_INTEGER*)&p_StartTime); + if(c_Stopped) + { + c_PausedTime += (p_StartTime-c_StopTime); + c_PrevTime = p_StartTime; + c_StopTime = 0; + c_Stopped = false; + } +} +__int64 NetworkTimer::getTime() +{ + __int64 testInt; + return QueryPerformanceCounter((LARGE_INTEGER*)&testInt); + return testInt; +} + +void NetworkTimer::stop() +{ + if(!c_Stopped) + { + __int64 p_CurrTime; + QueryPerformanceCounter((LARGE_INTEGER*)&p_CurrTime); + c_StopTime = p_CurrTime; + c_Stopped = true; + } +} +void NetworkTimer::reset() +{ + __int64 p_CurrTime; + QueryPerformanceCounter((LARGE_INTEGER*)&p_CurrTime); + c_BaseTime = p_CurrTime; + c_PrevTime = p_CurrTime; + c_StopTime = 0; + c_Stopped = false; +} +void NetworkTimer::tick() +{ + if (c_Stopped) + { + c_DeltaTime= 0.0; + return; + } + __int64 p_CurrTime; + QueryPerformanceCounter((LARGE_INTEGER*)&p_CurrTime); + c_CurrTime=p_CurrTime; + + c_DeltaTime=(c_CurrTime-c_PrevTime)*c_SecondsPerCount; + c_PrevTime=c_CurrTime; + if(c_DeltaTime<0.0) c_DeltaTime=0.0; +} +float NetworkTimer::getGameTime() const +{ + if(c_Stopped) + { + return (float)((c_StopTime-c_BaseTime)*c_SecondsPerCount); + } else + { + return (float)(((c_CurrTime-c_PausedTime)-c_BaseTime)*c_SecondsPerCount); + } +} +float NetworkTimer::getDeltaTime() const +{ + return (float)c_DeltaTime; +} \ No newline at end of file diff --git a/Network/NetworkDependencies/NetworkTimer.h b/Network/NetworkDependencies/NetworkTimer.h new file mode 100644 index 00000000..c4581c50 --- /dev/null +++ b/Network/NetworkDependencies/NetworkTimer.h @@ -0,0 +1,25 @@ +#include "NetworkIncludes.h" +#ifndef _NET_TIMER_H +#define _NET_TIMER_H +class NetworkTimer +{ +private: + double c_SecondsPerCount; + double c_DeltaTime; + __int64 c_BaseTime; + __int64 c_PausedTime; + __int64 c_StopTime; + __int64 c_PrevTime; + __int64 c_CurrTime; + bool c_Stopped; +public: + NetworkTimer(); + __int64 getTime(); + void start(); + void stop(); + void reset(); + void tick(); + float getGameTime() const; + float getDeltaTime() const; +}; +#endif \ No newline at end of file diff --git a/Network/NetworkDependencies/NetworkUpdateStructs.h b/Network/NetworkDependencies/NetworkUpdateStructs.h new file mode 100644 index 00000000..97f2037d --- /dev/null +++ b/Network/NetworkDependencies/NetworkUpdateStructs.h @@ -0,0 +1,62 @@ +#ifndef NET_UPD_STRUCTS_H +#define NET_UPD_STRUCTS_H +#include "NetworkIncludes.h" +namespace Network +{ + struct EffectData + { + int identifier; + Float3 head; + Float3 tail; + }; + struct ServerToClientUpdateData + { + int pid; + Oyster::Math::Float4x4 position; + float dirVecLen; + int hp; + int shield; + long updateCount; + ServerToClientUpdateData() + { + pid=0; + updateCount=0; + hp=0; + shield=0; + } + }; + const int SERVER_PLAYER_DATA_SIZE = 84; + struct ClientToServerUpdateData + { + __int8 pid; + //Oyster::Math::Float4x4 position; + __int8 forward; + __int8 roll; + __int8 straferight; + __int8 strafeup; + bool firePrim; + bool fireSecond; + bool fireSpecial; + long updateCount; + bool braking; + float TurnHor; + float TurnVer; + ClientToServerUpdateData() + { + pid=0; + forward=0; + roll=0; + straferight=0; + strafeup=0; + firePrim=false; + fireSecond=false; + fireSpecial=false; + updateCount=0; + braking=false; + TurnHor= 0.0f; + TurnVer= 0.0f; + } + }; + const int CLIENT_PLAYER_DATA_SIZE = sizeof(ClientToServerUpdateData); +} +#endif \ No newline at end of file diff --git a/Network/NetworkDependencies/UpdateStructs.cpp b/Network/NetworkDependencies/UpdateStructs.cpp new file mode 100644 index 00000000..05209a9c --- /dev/null +++ b/Network/NetworkDependencies/UpdateStructs.cpp @@ -0,0 +1 @@ +#include "NetworkUpdateStructs.h" \ No newline at end of file diff --git a/Network/Server/Game.cpp b/Network/Server/Game.cpp new file mode 100644 index 00000000..7948603d --- /dev/null +++ b/Network/Server/Game.cpp @@ -0,0 +1,113 @@ +#include "Game.h" +Game::Game() +{ + playerCount=0; + started=false; + for (int i=0; i usr, int nrOfPlayers) +{ + /*for (int i=0; isetGame(2); + //init.players[i]=players[i]; + } + return init; +} +void Game::addUser(int uid) +{ + userID[playerCount++]=uid; +} +bool Game::startGame() +{ + started=true; + return started; +} +void Game::update(float dt) +{ + +} \ No newline at end of file diff --git a/Network/Server/Game.h b/Network/Server/Game.h new file mode 100644 index 00000000..d162a322 --- /dev/null +++ b/Network/Server/Game.h @@ -0,0 +1,51 @@ +#pragma once +#ifndef GAME_H +#define GAME_H +#include "User.h" +#include "ServerInclude.h" +const int MUTEX_COUNT =2; +//Mutex #0=playerPos setGet +//Mutex #1= + +//#include "Session.h" + +class Game +{ +private: + bool started; + //ClientToServerUpdateData players[PLAYER_MAX_COUNT]; + User* users[PLAYER_MAX_COUNT]; + int userID[PLAYER_MAX_COUNT]; + bool ready[PLAYER_MAX_COUNT]; + int playerCount; + + //Tracks which ship each user has + int shipID[PLAYER_MAX_COUNT]; + HANDLE mutex[MUTEX_COUNT]; + //::Game::Session *session; + int sessionID; +public: + //Will reset all data + //playerIDs is an array of int which points toward each users connection. + void setReady(int pid, bool rdy){ready[pid]=rdy;} + bool allReady(){for (int i=0; i players, int nrOfPlayers); + GameInitData getInitData(); + bool startGame(); + bool isStarted(){return started;} + Game(); + //Float4x4 getPlayerPos(int id); + //void setPlayerPos(int id, Float4x4 pos); + //bool checkMoveValidity(ClientToServerUpdateData plr); + //ClientToServerUpdateData getPlayerData(int id); + //void setPlayerData(int id, ClientToServerUpdateData ps); + + int getPlayerCount() {return playerCount;} + int getUserID(int i) {return userID[i];} + + void initLUA(char* file); + void update(float dt); + void addUser(int uid); + void removeUser(int uid){playerCount--;} +}; +#endif \ No newline at end of file diff --git a/Network/Server/Lobby.cpp b/Network/Server/Lobby.cpp new file mode 100644 index 00000000..ade4b120 --- /dev/null +++ b/Network/Server/Lobby.cpp @@ -0,0 +1,73 @@ +#include "Lobby.h" + +Lobby::Lobby() +{ + timerStarted=false; + nrUsers=0; + timerMutex = CreateMutex( + NULL, // default security attributes + FALSE, // initially not owned + NULL); // unnamed mutex + + if (timerMutex == NULL) + { + printf("CreateMutex error: %d\n", GetLastError()); + } + for(int i=0; i0) + return timeLeft; + else + return 0; + } + ReleaseMutex(timerMutex); +} \ No newline at end of file diff --git a/Network/Server/Lobby.h b/Network/Server/Lobby.h new file mode 100644 index 00000000..a17e771c --- /dev/null +++ b/Network/Server/Lobby.h @@ -0,0 +1,27 @@ +#include "ServerInclude.h" +#include "User.h" +#ifndef LOBBY_H +#define LOBBY_H +class Lobby +{ +private: + int nrUsers; + int userID[PLAYER_MAX_COUNT]; + ServerTimer countdownTimer; + float countdownLimit; + LobbyUserStruct userData[PLAYER_MAX_COUNT]; + bool timerStarted; + HANDLE timerMutex; +public: + Lobby(); + void addUser(User usr, int i); + int getUserID(int i) const {return userID[i];} + int getNrPlayers() const {return nrUsers;} + void removeUser(); + void updateUserData(LobbyUserStruct); + LobbyInitData getLobbyInitData(); + void startLobbyCountdown(float seconds); + float timeLeft(); + +}; +#endif \ No newline at end of file diff --git a/Network/Server/ServerDataHandler.cpp b/Network/Server/ServerDataHandler.cpp new file mode 100644 index 00000000..55c36a02 --- /dev/null +++ b/Network/Server/ServerDataHandler.cpp @@ -0,0 +1,219 @@ +#include "SocketServer.h" + + + +void SocketServer::parseReceivedData(int threadID/*char* data, int size*/) +{ + bool test=false; + for(unsigned int i=0; isrcAddr); + data->buffer[data->dataSize]='\0'; + usr.setUsername(data->buffer); + users.push_back(usr); + sendData(((int)users.size())-1, "\4connected",10); + std::string asd=users[users.size()-1].getUsername(); + printf("Username:%s, IP:%s\n",users[users.size()-1].getUsername().c_str(), inet_ntoa(users[users.size()-1].getAddr().sin_addr)); +} +void SocketServer::removeUser(int id) +{ + games[users[id].getGame()].removeUser(id); + users.erase(users.begin()+id); +} +void SocketServer::parseServercommand(int pid, int threadID) +{ + connData[threadID].buffer[connData[threadID].dataSize]='\0'; + wprintf(L"User %d sent a server command.\n", pid); + printf("The command is the following:%s.\n", connData[threadID].buffer+1); + std::vector list=splitString(connData[threadID].buffer+1, ' '); + bool validcommand=false; + if(list.size()==0) + { + //Ignore case 1, to avoid vector subscript out of range errors + } + //First variable: Command + else if(!list[0].compare(" ")) + { + //Add rest ignore cases here + } + else if(!list[0].compare("help")) + { + validcommand=true; + } + //else if(!list[0].compare("startgame")) + //{ + //validcommand=true; + //Do more than just sending init data here + //sendInitData(); + //} + else if (!list[0].compare("exit")) + { + validcommand=true; + //User #pid needs to be removed here, and data needs to be sorted accordingly. + } + else if (!list[0].compare("qst")) + { + validcommand=true; + if (users[pid].getState()==ONLINE) + { + sendData(pid, "\4qst",4); + users[pid].setState(ONLINE_QUEUEING); + } + } + else if (!list[0].compare("qed")) + { + validcommand=true; + if (users[pid].getState()==ONLINE_QUEUEING) + { + sendData(pid, "\4qed",4); + users[pid].setState(ONLINE); + } + } + else if (!list[0].compare("rdy")) + { + if (users[pid].getState()==ONLINE_INGAME) + { + games[users[pid].getGame()].setReady(pid, true); + } + } + else if (!list[0].compare("dc")) + { + validcommand=true; + printf("User %s (ID:%d) has disconnected.",users[pid].getUsername().c_str(), pid); + users[pid].setState(OFFLINE); + removeUser(pid); + //Tell games that he might be in here taht he's down + //users.erase(users.begin() + } + else if((!list[0].compare("w")||!list[0].compare("whisper")||!list[0].compare("msg")) && list.size()>2) + { + validcommand=true; + for(unsigned int i=0; i1) + { + users[pid].setUsername(list[1]); + //list[1]="\3Your username has been changed to "+list[1]; + //sendData(pid,list[1].c_str(), list[1].length()); + validcommand=true; + } + } + if(!validcommand) + { + int a=0; + //sendData(pid, "\3Invalid server command.", 24); + //Tell user that the server command was invalid + } +} +void SocketServer::parseData(int pid, int gid, int threadID) +{ + memcpy(&connData[threadID].tmpdata,connData[threadID].buffer+1,CLIENT_PLAYER_DATA_SIZE); + //No old packets + if (users[pid].getLastUpdate()accessPlayer(pid),connData[threadID].tmpdata); + } +} +void SocketServer::parseMessage(int pid, int threadID) +{ + std::string message; + message="\3[Chat] "+users[pid].getUsername()+": "+(connData[threadID].buffer+1); + sendData(-1,message.c_str(), (int)message.length()); +} +void SocketServer::sendInitData(int gid) +{ + GameInitData init=games[gid].getInitData(); + //int test=session->getNumPlayers(); // getNumPlayers is removed + for (int i=0; iaccessPlayer(i).getOrientation(); + } + char* gd=new char[sizeof(init)+1]; + gd[0]=2; + for (int i=0; i +#define DEBUG_NEW new(_NORMAL_BLOCK ,__FILE__, __LINE__) +#else +#define DEBUG_NEW new +#endif + +#include +#include +#include +#include +#include "OysterMath.h" +#include "Session.h" +#include "ServerTimer.h" +using namespace Network; + +const float GAME_UPDATEDELAY=1.0f/120.0f; diff --git a/Network/Server/ServerMain.cpp b/Network/Server/ServerMain.cpp new file mode 100644 index 00000000..6c3d7f56 --- /dev/null +++ b/Network/Server/ServerMain.cpp @@ -0,0 +1,47 @@ +#include +#include "SocketServer.h" +#include "ServerTimer.h" +#include +#include +#include +//#ifdef WINDOWS +#include +#include "ServerInclude.h" +#define GetCurrentDir _getcwd +//#else + //For other OS than windows; can't be found on + //all windows setups so it's commented for now + //#include + //#define GetCurrentDir getcwd + //#endif + +char* getCurDir() +{ + char* cCurrentPath; + cCurrentPath=new char[FILENAME_MAX]; + int test=sizeof(cCurrentPath); + if (!GetCurrentDir(cCurrentPath, FILENAME_MAX)) + { + return "ERROR"; + } + cCurrentPath[FILENAME_MAX - 1] = '\0'; + return cCurrentPath; +} +int main(int argc, char *argv[]) +{ + srand((unsigned int)time(0)); + ::Oyster::Game::MoveAble::setDiscreteTimeSlice( GAME_UPDATEDELAY ); + + SocketServer server; + server.loadMapList("..\\Content\\Maplist.txt"); + while (!server.isReady()); + server.startThreads(); + GameLogic::Object::init("NOT_IMPLEMENTED"); + server.startGameCreateLoop(50); + while(true) + { + server.updateServers(); + } + server.closeConnection(); + return 0; +} \ No newline at end of file diff --git a/Network/Server/ServerTCPSpecific.cpp b/Network/Server/ServerTCPSpecific.cpp new file mode 100644 index 00000000..eb6987c9 --- /dev/null +++ b/Network/Server/ServerTCPSpecific.cpp @@ -0,0 +1,66 @@ +#include "SocketServer.h" +bool SocketServer::initTCPSocket() +{ + //---------------------- + // Create a SOCKET for listening for incoming connection requests. + TCPSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (TCPSocket == INVALID_SOCKET) { + wprintf(L"TCP socket function failed with error: %ld\n", WSAGetLastError()); + WSACleanup(); + return false; + } + + iResult = bind(TCPSocket, (SOCKADDR *) & TCPRecvAddr, addrSize); + if (iResult == SOCKET_ERROR) { + wprintf(L"TCP bind function failed with error %d\n", WSAGetLastError()); + iResult = closesocket(TCPSocket); + if (iResult == SOCKET_ERROR) + wprintf(L"TCP closesocket function failed with error %d\n", WSAGetLastError()); + WSACleanup(); + return false; + } + return true; +} +DWORD SocketServer::activateTCPConnectLoop(ThreadArguments* tra) +{ + while (true) + { + (tra->ptr)->receiveConnection(tra->threadID); + } +} +void SocketServer::receiveConnection(int threadID) +{ + User tmp; + //---------------------- + // Listen for incoming connection requests + // on the created socket + if (listen(TCPSocket, SOMAXCONN) == SOCKET_ERROR) + { + wprintf(L"listen function failed with error: %d\n", WSAGetLastError()); + return; + } + + printf("Starting TCP connection loop.\n"); + int a=0; + while(a==0) + { + a=1; + tmp.connection=accept(TCPSocket, (struct sockaddr*)&TCPRecvAddr, &addrSize); + printf("Accepted a TCP connection from IP %s.\n", inet_ntoa(TCPRecvAddr.sin_addr)); + tcpData[threadID].dataSize=recv( + tmp.connection, + tcpData[threadID].buffer, + tcpData[threadID].bufLen, + 0); + connData[threadID].buffer[connData[threadID].dataSize]='\0'; + tmp.setUsername(tcpData[threadID].buffer); + if (tcpData[threadID].dataSize == SOCKET_ERROR) + { + wprintf(L"TCP recv failed with error %d\n", WSAGetLastError()); + } + printf("TCP Thread #%d received connData from %s\n", threadID, inet_ntoa(tcpData[threadID].srcAddr.sin_addr)); + //connData[threadID].buffer[connData[threadID].dataSize]='\0'; + //AddUser(&tcpData[threadID]); + //parseReceivedData(threadID); + } +} \ No newline at end of file diff --git a/Network/Server/ServerTimer.cpp b/Network/Server/ServerTimer.cpp new file mode 100644 index 00000000..4dc3d286 --- /dev/null +++ b/Network/Server/ServerTimer.cpp @@ -0,0 +1,85 @@ +#include "ServerTimer.h" +ServerTimer::ServerTimer() + : + c_SecondsPerCount(0.0), + c_DeltaTime(-1.0), + c_BaseTime(0), + c_PausedTime(0), + c_PrevTime(0), + c_CurrTime(0), + c_Stopped(false) +{ + __int64 countsPerSec; + QueryPerformanceFrequency((LARGE_INTEGER*)&countsPerSec); + c_SecondsPerCount =1.0 / (double)countsPerSec; + + QueryPerformanceCounter((LARGE_INTEGER*)&c_PrevTime); +} + +void ServerTimer::start() +{ + __int64 p_StartTime; + QueryPerformanceCounter((LARGE_INTEGER*)&p_StartTime); + if(c_Stopped) + { + c_PausedTime += (p_StartTime-c_StopTime); + c_PrevTime = p_StartTime; + c_StopTime = 0; + c_Stopped = false; + } +} +__int64 ServerTimer::getTime() +{ + __int64 testInt; + return QueryPerformanceCounter((LARGE_INTEGER*)&testInt); + return testInt; +} + +void ServerTimer::stop() +{ + if(!c_Stopped) + { + __int64 p_CurrTime; + QueryPerformanceCounter((LARGE_INTEGER*)&p_CurrTime); + c_StopTime = p_CurrTime; + c_Stopped = true; + } +} +void ServerTimer::reset() +{ + __int64 p_CurrTime; + QueryPerformanceCounter((LARGE_INTEGER*)&p_CurrTime); + c_BaseTime = p_CurrTime; + c_PrevTime = p_CurrTime; + c_StopTime = 0; + c_Stopped = false; +} +void ServerTimer::tick() +{ + if (c_Stopped) + { + c_DeltaTime= 0.0; + return; + } + __int64 p_CurrTime; + QueryPerformanceCounter((LARGE_INTEGER*)&p_CurrTime); + c_CurrTime=p_CurrTime; + + c_DeltaTime=(c_CurrTime-c_PrevTime)*c_SecondsPerCount; + c_PrevTime=c_CurrTime; + if(c_DeltaTime<0.0) c_DeltaTime=0.0; +} +float ServerTimer::getGameTime() const +{ + if(c_Stopped) + { + return (float)((c_StopTime-c_BaseTime)*c_SecondsPerCount); + } else + { + return (float)(((c_CurrTime-c_PausedTime)-c_BaseTime)*c_SecondsPerCount); + } +} +float ServerTimer::getDeltaTime() const +{ + return (float)c_DeltaTime; +} \ No newline at end of file diff --git a/Network/Server/ServerTimer.h b/Network/Server/ServerTimer.h new file mode 100644 index 00000000..660c1799 --- /dev/null +++ b/Network/Server/ServerTimer.h @@ -0,0 +1,25 @@ +#include "ServerInclude.h" +#ifndef _GAME_TIMER_H +#define _GAME_TIMER_H +class ServerTimer +{ +private: + double c_SecondsPerCount; + double c_DeltaTime; + __int64 c_BaseTime; + __int64 c_PausedTime; + __int64 c_StopTime; + __int64 c_PrevTime; + __int64 c_CurrTime; + bool c_Stopped; +public: + ServerTimer(); + __int64 getTime(); + void start(); + void stop(); + void reset(); + void tick(); + float getGameTime() const; + float getDeltaTime() const; +}; +#endif \ No newline at end of file diff --git a/Network/Server/ServerUDPSpecific.cpp b/Network/Server/ServerUDPSpecific.cpp new file mode 100644 index 00000000..1ffdf624 --- /dev/null +++ b/Network/Server/ServerUDPSpecific.cpp @@ -0,0 +1,55 @@ +#include "SocketServer.h" +bool SocketServer::initUDPSocket() +{ + //--------------------------------------------- + // Create a socket for sending data + UDPSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (UDPSocket == INVALID_SOCKET) { + wprintf(L"UDP socket failed with error: %ld\n", WSAGetLastError()); + WSACleanup(); + return false; + } + //--------------------------------------------- + // Bind socket to IP + iResult = bind(UDPSocket, (SOCKADDR *) & UDPRecvAddr, addrSize); + if (iResult == SOCKET_ERROR) { + wprintf(L"UDP bind failed with error: %d\n", WSAGetLastError()); + closesocket(UDPSocket); + WSACleanup(); + return false; + } + return true; +} +DWORD SocketServer::activateUDPReceiveLoop(ThreadArguments* tra) +{ + (tra->ptr)->serverUDPReceiveLoopActive=true;//weird crash //PAR + (tra->ptr)->receiveDataUDP(tra->threadID); + return 0; +} +void SocketServer::stopUDPReceiveLoops() +{ + serverUDPReceiveLoopActive=false; + WaitForMultipleObjects(NR_CONNECTTHREADS, udpDataHandle, true, INFINITE); + printf("All UDP data recv threads stopped.\n"); +} +void SocketServer::receiveDataUDP(int threadID) +{ + while(serverUDPReceiveLoopActive) + { + connData[threadID].dataSize=recvfrom( + UDPSocket, + connData[threadID].buffer, + connData[threadID].bufLen, + 0, + (SOCKADDR *)&connData[threadID].srcAddr, + &addrSize); + if (connData[threadID].dataSize == SOCKET_ERROR) + { + wprintf(L"recvfrom failed with error %d\n", WSAGetLastError()); + } + //printf("Thread #%d received data from %s\n", threadID, inet_ntoa(connData[threadID].srcAddr.sin_addr)); + //connData[threadID].buffer[connData[threadID].dataSize]='\0'; + else + parseReceivedData(threadID); + } +} \ No newline at end of file diff --git a/Network/Server/Servercore.cpp b/Network/Server/Servercore.cpp new file mode 100644 index 00000000..6dd855fd --- /dev/null +++ b/Network/Server/Servercore.cpp @@ -0,0 +1,420 @@ +#include "SocketServer.h" +#include +bool SocketServer::loadMapList(char* maploc) +{ + ::std::string workDir; + ::Utility::String::extractDirPath( workDir, maploc, '\\' ); + + //maploc is the filename of the list which contains all maps + //load all map file names into the server, but don't load the maps themselves. + std::ifstream file; + file.open(maploc); + if (!file.is_open()) + return false; + ::std::string str; + while(!file.eof()) + { + ::std::getline( file, str ); + maps.push_back( workDir + str ); + } + + /* + maps.push_back("map1test.map"); + maps.push_back("map2 test.map"); + */ + return true; +} +bool SocketServer::LoadInitData(char* maploc) +{ + std::vector cont; + char* in=new char[100]; + std::ifstream ifs; + ifs.open(maploc); + if(!ifs.is_open()) + { + return false; + } + while(!ifs.eof()) + { + ifs.getline(in, 100); + cont=splitString(in, '='); + if (cont.size()==2) + { + if(!strcmp("nr_players_per_session", cont[0].c_str())) + { + playersPerSessionCount=atoi(cont[1].c_str()); + } + else if(!strcmp("nr_kills_to_win", cont[0].c_str())) + { + killsRequiredPerSession=atoi(cont[1].c_str()); + } + else if(!strcmp("match_type", cont[0].c_str())) + { + //Isn't used + } + } + + } + ifs.close(); +} +SocketServer::~SocketServer() +{ + serverTCPConnectionLoopActive=false; + serverUDPReceiveLoopActive=false; + serverTCPReceiveLoopActive=false; + for (int i=0; iptr)->serverGameCreationLoop(tra->threadID); + return 0; +} +bool SocketServer::serverGameCreationLoop(int delay) +{ // TODO: Mem access Violoation Crash 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ... delay = -858993460 + //Mem access violation in a thread can also be caused by failure from something else instead of it, + //it still breaks at header even if, for example, server->load or lobby.startLobbyCountdown breaks it + //If you get an error here, make sure that isn't the problem. + int count; + while(serverGameCreationActive) + { + if (nrActiveSessions==0) + { + count=0; + for (unsigned int i=0; i=playersPerSessionCount) + { + games.resize(1); + //lobby.resize(games.size()+1); + session =new GameLogic::Session(); + lobby = Lobby(); + timer.resize(1); + timeTillUpdate.resize(1); + timeTillUpdate[0]=GAME_UPDATEDELAY; + updateCount.resize(1); + updateCount[0]=0; + int curID=(int)games.size()-1; + int mapid=rand()%maps.size(); + session->setNrPlayers(playersPerSessionCount); + session->setKillsRequired(killsRequiredPerSession); + session->load(maps[mapid]); + printf("Map nr %d loaded, name %s.\n",mapid, maps[mapid].c_str()); + count=0; + for (unsigned int i=0; countaccessPlayer(i).spawn(); + count++; + } + } + lobbyActive=true; + sendLobbyInitData(curID); + lobby.startLobbyCountdown(LOBBY_WAIT_TIME); + sendRenderData(curID); + //return true; + } + if(lobbyActive) + { + for (int i=0; i<1; i++) + { + float ttimer=lobby.timeLeft(); + if (ttimer==0) + { + printf("Starting game.\n"); + games[i].initGame(users,playersPerSessionCount); + sendInitData(i); + nrActiveSessions++; + lobbyActive=false; + //serverGameCreationActive=false; + } + } + } + } + Sleep(delay); + } + printf("Maximum server count reached, shutting down the sever creation thread.\n"); + return false; +} +SocketServer::SocketServer() +{ + UDPSocket = INVALID_SOCKET; + nrActiveSessions=0; + serverGameCreationActive=false; + serverTCPConnectionLoopActive=false; + serverTCPReceiveLoopActive=false; + serverUDPReceiveLoopActive=false; + killsRequiredPerSession=10; + playersPerSessionCount=1; + LoadInitData("../ServerData.dat"); + //--------------------------------------------- + // Set up the port and IP of the server + //Port starts up as a different one from when UDPSocketected, it changes once the server has exchanged some info with the client + UDPRecvAddr.sin_family = AF_INET; + UDPRecvAddr.sin_port = htons(UDPRecvPort); + UDPRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY); + + sessionEvents=std::vector(0); + sessionEffects=std::vector(0); + TCPRecvAddr.sin_family = AF_INET; + TCPRecvAddr.sin_port = htons(TCPRecvPort); + TCPRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY); + + addrSize=sizeof(sockaddr_in); + for (int i=0; i=users.size()) + { + //User doesn't exist + printf("UDP sendData(%d) sendto failed because the specified user does not exist\n", uid); + } + else + { + iResult = sendto(UDPSocket, data, size, 0, (SOCKADDR *) & users[uid].getAddr(), addrSize); + if (iResult == SOCKET_ERROR) + { + wprintf(L"UDP sendData(%d) sendto failed with error: %d\n", uid, WSAGetLastError()); + closesocket(UDPSocket); + WSACleanup(); + return false; + } + } + } + return true; +} +bool SocketServer::sendKeyFrameData(int size, const char* data) +{ + for (int i=0; i +#include +namespace Benchmark +{ + struct + { + double averageTime, totalTime, minTime, maxTime; unsigned int numSamples; + } timerData[10] = { 0.0f, 0.0f, ::std::numeric_limits::max(), -::std::numeric_limits::max(), 0 }; + + void sampleTime( const ::Utility::WinTimer &timer, unsigned char ref ) + { + double elapsedTime = timer.getElapsedSeconds(); + timerData[ref].totalTime += elapsedTime; + timerData[ref].minTime = ::Utility::Value::min( timerData[ref].minTime, elapsedTime ); + timerData[ref].maxTime = ::Utility::Value::max( timerData[ref].maxTime, elapsedTime ); + ++timerData[ref].numSamples; + timerData[ref].averageTime = timerData[ref].totalTime / (double) timerData[ref].numSamples; + } + + void print( ) + { + ::std::ofstream file; + file.open( "BenchMarkData.txt", ::std::ios_base::app | ::std::ios_base::out ); + + if( file.is_open() ) + { + file << "minTime\t\t: maxTime\t: averageTime\t\ttotalTime\tnumSamples\n"; + for( unsigned char i = 0; i < 1; ++i ) + file << timerData[i].minTime << (timerData[i].minTime == 0.0f ? "\t\t: " : "\t: ") << timerData[i].maxTime << "\t: " << timerData[i].averageTime << "\t\t" << timerData[i].totalTime << '\t' << timerData[i].numSamples <<'\n'; + file << ::std::endl; + file.close(); + ::std::cout << "Benchmark data saved." << ::std::endl; + } + } +} +// END BENCHMARK BLOCK/**/ + +void SocketServer::updateServers() +{ + for(int i=0; iupdate( timer[i].getDeltaTime() ) ) + { + case ::GameLogic::Session::Updated: + // BENCHMARK BLOCK + //processTimer.reset(); + // END BENCHMARK BLOCK + + processSessionPlayerData(i); + processAllSessionEvents(i); + processAllSessionEffects(i); + + // BENCHMARK BLOCK + //Benchmark::sampleTime( processTimer, 0 ); + // END BENCHMARK BLOCK + + DEBUGCTR=0; + updateCount[i]++; + default: + break; + case ::GameLogic::Session::Over: + processAllSessionEvents(i); + nrActiveSessions=0; + if(users.size()==0) + { + printf("Game with id %d done, shutting down the game.\n", 0); + Sleep(10); + + } + break; + } + + // BENCHMARK BLOCK + //if( Benchmark::timerData[0].numSamples % 1000 == 1 ) + // Benchmark::print(); + // END BENCHMARK BLOCK + } + } + if(nrActiveSessions==0) + { + Sleep(50); + } +} +void SocketServer::processSessionPlayerData(int serverID) +{ + sendGameDataStruct.updateCount=updateCount[serverID]; + int offset=1; + for (int i=0; iaccessPlayer(i).getOrientation(); + sendGameDataStruct.hp=session->accessPlayer(i).getHullPoints(); + sendGameDataStruct.shield=session->accessPlayer(i).getShieldPoints(); + sendGameDataStruct.dirVecLen=session->accessPlayer(i).getMovement().length(); + sendGameDataStruct.pid=i; + memcpy(sendGameDataBuffer+offset, &sendGameDataStruct, SERVER_PLAYER_DATA_SIZE); + offset+=SERVER_PLAYER_DATA_SIZE; + } + sendData(-1,sendGameDataBuffer, sendGameDataBufferSize); +} +void SocketServer::processAllSessionEvents(int serverID) +{ + session->fetchEvents(sessionEvents); + for (int i=0; i<(int)sessionEvents.size(); i++) + { + sendEventData(serverID, i); + delete sessionEvents[i]; + } + sessionEvents.resize(0); +} +bool SocketServer::sendGameData(int serverID) +{ + //data[0]=1; + for (int i=0; iGetSize(); + int size1=sizeof(Event::BulletCreated); + int tst=sizeof(Event::Type); + char* ed=new char[size+1+tst]; + ed[0]=6; + sessionEvents[sid]->SaveRawData(ed+(1+tst)); + + Event::Type eTest=Event::getEventType(sessionEvents[sid]); + memcpy(ed+1, &eTest, sizeof(Event::Type)); + + sendData(-1, ed, size+1+tst); + delete ed; +} +void SocketServer::sendRenderData(int gid) +{ + Protocol::RenderData data; + session->writeToRenderResourceData(data); + int size=data.getRequiredBufferSize()+1; + char* sendChar=new char[size]; + data.fillBuffer(sendChar+1); + sendChar[0]=8; + sendData(-1, sendChar, size); + delete sendChar; +} +void SocketServer::processAllSessionEffects(int gid) +{ + session->fetchEffectData(sessionEffects); + + if (sessionEffects.size()>0) + { + int size=(int)sessionEffects.size()*sizeof(Network::EffectData) + 1; + delete sendEffectDataBuffer; + sendEffectDataBuffer=new char[size]; + for (size_t i=0; i0) + p.thrustForward(); + if(update.forward<0) + p.thrustBackward(); + + if(update.straferight>0) + p.strafeRight(); + if(update.straferight<0) + p.strafeLeft(); + + if(update.strafeup>0) + p.climb(); + if(update.strafeup<0) + p.dive(); + + if(update.roll>0) + { + ::Oyster::Math::Float baseAcceleration = p.rotationProperty.acceleration.roll; + p.rotationProperty.acceleration.roll /= ::Oyster::Game::MoveAble::getDiscreteTimeSlice(); + + p.rollLeft(); + p.rotationProperty.acceleration.roll = baseAcceleration; + } + if(update.roll<0) + { + ::Oyster::Math::Float baseAcceleration = p.rotationProperty.acceleration.roll; + p.rotationProperty.acceleration.roll /= ::Oyster::Game::MoveAble::getDiscreteTimeSlice(); + p.rollRight(); + p.rotationProperty.acceleration.roll = baseAcceleration; + } + if(update.roll==0) + { + p.stopRotation(); + } + + if(update.TurnVer!=0.0f) + { + ::Oyster::Math::Float baseAcceleration = p.rotationProperty.acceleration.pitch; + p.rotationProperty.acceleration.pitch *= -update.TurnVer / ::Oyster::Game::MoveAble::getDiscreteTimeSlice(); + p.pitchUp( ); + p.disableRotationReduction(); + p.rotationProperty.acceleration.pitch = baseAcceleration; + } + + if(update.TurnHor!=0.0f) + { + ::Oyster::Math::Float baseAcceleration = p.rotationProperty.acceleration.yaw; + p.rotationProperty.acceleration.yaw *= -update.TurnHor / ::Oyster::Game::MoveAble::getDiscreteTimeSlice(); + p.yawLeft( ); + p.disableRotationReduction(); + p.rotationProperty.acceleration.yaw = baseAcceleration; + } + if(update.firePrim) + p.firePrimaryWeapon(); +} + diff --git a/Network/Server/SocketServer.h b/Network/Server/SocketServer.h new file mode 100644 index 00000000..28c19058 --- /dev/null +++ b/Network/Server/SocketServer.h @@ -0,0 +1,126 @@ +#include "Game.h" +#include "Lobby.h" +void ControlPlayer( GameLogic::Player& p,const ClientToServerUpdateData &update); +const int NR_CONNECTTHREADS=1; +const int NR_SIMULTCPCONNECTS=1; +//threads can only take 1 argument +struct ThreadArguments; +struct ConnThreadData +{ + sockaddr_in srcAddr; + + ClientToServerUpdateData tmpdata; + char* buffer; + int bufLen; + int dataSize; +}; +// Link with ws2_32.lib +#pragma comment(lib, "Ws2_32.lib") +const short TCPSendPort = 11111; +const short TCPRecvPort = 11110; +const short UDPSendPort = 11001; +const short UDPRecvPort = 11000; + +class SocketServer +{ +private: + bool serverGameCreationActive; + HANDLE gameCreateHandle; + bool serverTCPConnectionLoopActive; + bool serverUDPReceiveLoopActive; + bool serverTCPReceiveLoopActive; + bool setupStatus; + int iResult; + WSADATA wsaData; + + SOCKET UDPSocket; + SOCKET TCPSocket; + + sockaddr_in TCPRecvAddr; + sockaddr_in UDPRecvAddr; + + int addrSize; + + HANDLE tcpDataHandle[NR_SIMULTCPCONNECTS]; + ConnThreadData tcpData[NR_SIMULTCPCONNECTS]; + + HANDLE udpDataHandle[NR_CONNECTTHREADS]; + ConnThreadData connData[NR_CONNECTTHREADS]; + + int dataSize; + + + char* sendEffectDataBuffer; + char* sendGameDataBuffer; + int sendGameDataBufferSize; + ServerToClientUpdateData sendGameDataStruct; + std::vector users; + std::vector games; + Lobby lobby; + int nrActiveSessions; + std::vector sessionEvents; + std::vector sessionEffects; + GameLogic::Session* session; + std::vector timer; + int DEBUGCTR; + std::vector updateCount; + std::vector timeTillUpdate; + std::vector<::std::string> maps; + std::string text; + int playersPerSessionCount; + int killsRequiredPerSession; + bool lobbyActive; +public: + virtual ~SocketServer(); + //Debug force modify functions + void processAllSessionEvents(int serverID); + void processAllSessionEffects(int gid); + void processSessionPlayerData(int serverID); + //End of debug items + void updateServers(); + SocketServer(); + bool checkConnection(int userID); + bool initUDPSocket(); + bool initTCPSocket(); + //void firstTimeConnect(); + bool loadMapList(char* map); + bool serverGameCreationLoop(int delay); + bool startThreads(); + static DWORD activateUDPReceiveLoop(ThreadArguments* tra); + void stopUDPReceiveLoops(); + //TCP functions + static DWORD activateTCPConnectLoop(ThreadArguments* tra); + void receiveConnection(int threadID); + //End of TCP functions + bool sendData(int uid, const char*, int); + bool sendGameData(int serverID); + bool sendKeyFrameData(int size, const char* data); + void sendInitData(int gid); + void sendRenderData(int gid); + void sendEventData(int gid, int size); + void sendLobbyInitData(int lid); + bool closeConnection(); + void receiveDataUDP(int threadID); + + static DWORD activateServerGameLoop(ThreadArguments* tra); + void startGameCreateLoop(int delay); + void stopGameCreateLoop(); + void parseReceivedData(int threadID/*char*, int*/);//char and int required if i don't want to use the class buffer + void ParseReceivedData(ConnThreadData* data); + + void parseServercommand(int pid, int threadID); + void parseData(int pid, int gid, int threadID); + void parseMessage(int pid, int threadID); + + void addUser(int threadID); + void AddUser(ConnThreadData* data); + void removeUser(int id); + + bool isReady() const {return setupStatus;} + bool LoadInitData(char* maploc); +}; +struct ThreadArguments +{ + SocketServer* ptr; + int threadID; +}; \ No newline at end of file diff --git a/Network/Server/User.cpp b/Network/Server/User.cpp new file mode 100644 index 00000000..5dcbdf8d --- /dev/null +++ b/Network/Server/User.cpp @@ -0,0 +1,50 @@ +#include "User.h" +User::User(int i, sockaddr_in add, std::string usr) +{ + addr=add; + username=usr; + curGame=-1; + connection=NULL; + state=ONLINE; + lastUpdate=-1; + updMutex = CreateMutex( + NULL, // default security attributes + FALSE, // initially not owned + NULL); // unnamed mutex + + if (updMutex == NULL) + { + printf("CreateMutex error: %d\n", GetLastError()); + } +} +User::User() +{ + username=""; + curGame=-1; + connection=NULL; + state=ONLINE; + lastUpdate=-1; + updMutex = CreateMutex( + NULL, // default security attributes + FALSE, // initially not owned + NULL); // unnamed mutex + + if (updMutex == NULL) + { + printf("CreateMutex error: %d\n", GetLastError()); + } + lastUpdateData.pid=-1; +} +void User::setLastUpdateData(Network::ClientToServerUpdateData data) +{ + WaitForSingleObject(updMutex, INFINITE); + lastUpdateData=data; + ReleaseMutex(updMutex); +} +Network::ClientToServerUpdateData User::getLastUpdateData() +{ + WaitForSingleObject(updMutex, INFINITE); + Network::ClientToServerUpdateData data=lastUpdateData; + ReleaseMutex(updMutex); + return data; +} \ No newline at end of file diff --git a/Network/Server/User.h b/Network/Server/User.h new file mode 100644 index 00000000..1a68b950 --- /dev/null +++ b/Network/Server/User.h @@ -0,0 +1,42 @@ +#include "ServerInclude.h" +#ifndef USER_H +#define USER_H +enum UserState +{ + OFFLINE, + OFFLINE_INGAME, + ONLINE, + ONLINE_QUEUEING, + ONLINE_INLOBBY, + ONLINE_INGAME +}; +class User +{ +private: + std::string username; + int curGame; + sockaddr_in addr; + UserState state; + long lastUpdate; + HANDLE updMutex; + Network::ClientToServerUpdateData lastUpdateData; +public: + void setLastUpdateData(Network::ClientToServerUpdateData data); + Network::ClientToServerUpdateData getLastUpdateData(); + void setLastUpdate(long upd){lastUpdate=upd;} + long getLastUpdate() {return lastUpdate;} + HANDLE threadHandle; + SOCKET connection; + User(); + User(int id, sockaddr_in addr, std::string usr="Unknown"); + //SOCKET getTCPSocket() const {return connection;} + sockaddr_in getAddr() const {return addr;} + std::string getUsername() const {return username;} + void setUsername(std::string usr){username=usr;} + void setState(UserState st){state=st;} + UserState getState(){return state;} + void setGame(int gid){curGame=gid;} + bool isIngame() {return state==ONLINE_INGAME;} + int getGame(){return curGame;} +}; +#endif \ No newline at end of file diff --git a/Sound/Listener.cpp b/Sound/Listener.cpp new file mode 100644 index 00000000..5255c5b0 --- /dev/null +++ b/Sound/Listener.cpp @@ -0,0 +1,29 @@ +#include +#include + +#include + +#include "Listener.h" +#include "SoundEngine.h" + +void Listener::SetMasterVolume(float volume) +{ + alListenerf(AL_GAIN, volume); +} + +void Listener::SetPosition(const float position[3]) +{ + const float scaledPosition[3] = {position[0] * SOUNDENGINE_POSITION_SCALE, position[1] * SOUNDENGINE_POSITION_SCALE, position[2] * SOUNDENGINE_POSITION_SCALE}; + alListenerfv(AL_POSITION, scaledPosition); +} + +void Listener::SetOrientation(const float forward[3], const float up[3]) +{ + float values[6] = {forward[0], forward[1], forward[2], up[0], up[1], up[2]}; + alListenerfv(AL_ORIENTATION, values); +} + +void Listener::SetVelocity(const float velocity[3]) +{ + alListenerfv(AL_VELOCITY, velocity); +} diff --git a/Sound/Listener.h b/Sound/Listener.h new file mode 100644 index 00000000..35ecfa50 --- /dev/null +++ b/Sound/Listener.h @@ -0,0 +1,15 @@ +#ifndef LISTENER_H +#define LISTENER_H + +class Listener +{ +public: + static void SetMasterVolume(float volume); + + static void SetPosition(const float position[3]); + static void SetOrientation(const float forward[3], const float up[3]); + // Used for the doppler effect, should be in the same unit as the speed of sound set in SoundEngine. + static void SetVelocity(const float velocity[3]); +}; + +#endif diff --git a/Sound/SoundEngine.cpp b/Sound/SoundEngine.cpp new file mode 100644 index 00000000..19048a1d --- /dev/null +++ b/Sound/SoundEngine.cpp @@ -0,0 +1,380 @@ +#include +#include +#include + +#include + +#include "ThreadPool.h" +#include "SoundEngine.h" +#include "SoundSource.h" +#include "SoundResource.h" +#include "SoundResourceWAV.h" + +ALCdevice *SoundEngine::m_device = NULL; +ALCcontext *SoundEngine::m_context = NULL; + +ThreadPool *SoundEngine::m_threadPool = NULL; + +ALuint SoundEngine::m_bufferPool[SOUNDENGINE_BUFFER_POOL_SIZE]; +size_t SoundEngine::m_bufferPoolSize = 0; + +Mutex *SoundEngine::m_bufferPoolMutex = NULL; +Mutex *SoundEngine::m_resourceMutex = NULL; + +std::vector> SoundEngine::m_soundResources; +std::vector SoundEngine::m_soundSources; + +std::vector SoundEngine::m_sourcesPendingDeletion; + +bool SoundEngine::Init() +{ + m_device = alcOpenDevice(NULL); + + if (!m_device) + { + printf("Failed to open OpenAL device\n"); + return false; + } + + m_context = alcCreateContext(m_device, NULL); + + if (!m_context) + { + printf("Failed to create OpenAL context\n"); + alcCloseDevice(m_device); + return false; + } + + alcMakeContextCurrent(m_context); + + printf("OpenAL '%s' running on '%s'\n", alGetString(AL_VERSION), alGetString(AL_RENDERER)); + +#if 1 + ALCenum error = alcGetError(m_device); + + if (error != ALC_NO_ERROR) + printf("alcGetError=%s\n", alcGetString(m_device, error)); +#endif + + m_threadPool = new ThreadPool(); + + alGenBuffers(SOUNDENGINE_BUFFER_POOL_SIZE, m_bufferPool); + m_bufferPoolSize = SOUNDENGINE_BUFFER_POOL_SIZE; + + m_bufferPoolMutex = new Mutex(); + m_resourceMutex = new Mutex(); + + return true; +} + +void SoundEngine::Release() +{ +#if 1 + ALCenum error = alcGetError(m_device); + + if (error != ALC_NO_ERROR) + printf("alcGetError=%s\n", alcGetString(m_device, error)); +#endif + + // I think all currently queued tasks on the thread pool are canceled if we free it. + delete m_threadPool; + +#if 0 + SoundSource *source; + + while(!m_soundSources.empty()) + { + source = m_soundSources.back(); + m_soundSources.pop_back(); + + printf("Releasing sound source in SoundEngine::Release\n"); + + delete source; + } + + while(!m_sourcesPendingDeletion.empty()) + { + source = m_sourcesPendingDeletion.back(); + m_sourcesPendingDeletion.pop_back(); + + printf("Releasing sound source in SoundEngine::Release\n"); + + delete source; + } + + SoundResource *resource; + + while(!m_soundResources.empty()) + { + resource = m_soundResources.back().GetValue(); + m_soundResources.pop_back(); + + printf("Releasing resource '%s' in SoundEngine::Release\n", resource->GetName().c_str()); + + delete resource; + } +#endif + + //assert(m_bufferPoolSize == SOUNDENGINE_BUFFER_POOL_SIZE); + printf("%i buffers missing from the pool at SoundEngine::Release\n", SOUNDENGINE_BUFFER_POOL_SIZE - (int)m_bufferPoolSize); + + alDeleteBuffers((ALsizei)m_bufferPoolSize, m_bufferPool); + + alcMakeContextCurrent(NULL); + alcDestroyContext(m_context); + alcCloseDevice(m_device); + + delete m_bufferPoolMutex; + delete m_resourceMutex; +} + +SoundResource *SoundEngine::GetSoundResource(const std::string &name) +{ + SoundResource *resource = NULL; + + m_resourceMutex->Lock(); + + for(auto i = m_soundResources.begin(); i != m_soundResources.end(); i++) + { + if ((*i).GetValue()->GetName() == name) + { + (*i).IncRefCount(); + resource = (*i).GetValue(); + + break; + } + } + + m_resourceMutex->Unlock(); + + if (!resource) + { + resource = SoundResourceWAV::Load(name); + + if (resource) + { + m_resourceMutex->Lock(); + m_soundResources.push_back(RefCounted(resource)); + m_resourceMutex->Unlock(); + } + } + + return resource; +} + +void SoundEngine::ReleaseSoundResource(SoundResource *resource) +{ + m_resourceMutex->Lock(); + + for(auto i = m_soundResources.begin(); i != m_soundResources.end(); i++) + { + if ((*i).GetValue() == resource) + { + int refCount = (*i).DecRefCount(); + + if (refCount == 0) + { + //printf("'%s' reached refcount 0, deleting\n", (*i).GetValue()->GetName().c_str()); + + delete (*i).GetValue(); + m_soundResources.erase(i); + } + + break; + } + } + + m_resourceMutex->Unlock(); +} + +void SoundEngine::SetDopplerFactor(float dopplerFactor) +{ + alDopplerFactor(dopplerFactor); +} + +void SoundEngine::SetSpeedOfSound(float speed) +{ + alSpeedOfSound(speed); +} + +SoundSource *SoundEngine::CreateSoundSource() +{ + SoundSource *source = new SoundSource(); + m_soundSources.push_back(source); + + return source; +} + +void SoundEngine::DestroySoundSource(SoundSource *source) +{ + for(auto i = m_soundSources.begin(); i != m_soundSources.end(); i++) + { + if ((*i) == source) + { + m_soundSources.erase(i); + break; + } + } + + // If we delete it immediately then the resource/buffer loading task will try to access the freed memory. + if (source->m_isLoadingBuffer || source->m_isLoadingResource) + { + alSourceStop(source->m_source); + m_sourcesPendingDeletion.push_back(source); + } + else + { + delete source; + } +} + +ALuint SoundEngine::GetBuffer() +{ + ALuint buffer = AL_NONE; + + m_bufferPoolMutex->Lock(); + + if (m_bufferPoolSize > 0) + { + m_bufferPoolSize--; + buffer = m_bufferPool[m_bufferPoolSize]; + } + else + { + printf("The sound buffer pool is empty!\n"); + } + + m_bufferPoolMutex->Unlock(); + + return buffer; +} + +void SoundEngine::ReleaseBuffer(ALuint buffer) +{ + // Free the data stored in the buffer. + alBufferData(buffer, AL_FORMAT_MONO8, NULL, 0, 0); + + m_bufferPoolMutex->Lock(); + assert(m_bufferPoolSize < SOUNDENGINE_BUFFER_POOL_SIZE); + m_bufferPool[m_bufferPoolSize++] = buffer; + m_bufferPoolMutex->Unlock(); +} + +void SoundEngine::Update() +{ + SoundSource *source; + SoundResource *resource; + ALint state; + ALuint buffer = AL_NONE; + size_t sampleOffset, sampleCount; + bool hasReachedEnd, shouldStop; + int processedCount = 0; + int queuedCount = 0; + int j; + + for(size_t i = 0; i < m_sourcesPendingDeletion.size(); i++) + { + source = m_sourcesPendingDeletion[i]; + + if (!source->m_isLoadingBuffer && !source->m_isLoadingResource) + { + m_sourcesPendingDeletion.erase(m_sourcesPendingDeletion.begin() + i); + i--; + + delete source; + + // printf("Deleted source in m_sourcesPendingDeletion\n"); + } + } + + for(auto i = m_soundSources.begin(); i != m_soundSources.end(); i++) + { + source = (*i); + resource = source->m_resource; + + if (!resource) + continue; + + if (!resource->IsStreaming()) + { + alGetSourcei(source->m_source, AL_SOURCE_STATE, &state); + + if (!source->m_isLoadingResource && source->m_isPlaying && state != AL_PLAYING) + { + source->m_isPlaying = false; + + //printf("Reached end of non-streaming source\n"); + } + } + else + { + alGetSourcei(source->m_source, AL_BUFFERS_PROCESSED, &processedCount); + + for(j = 0; j < processedCount; j++) + { + alSourceUnqueueBuffers(source->m_source, 1, &buffer); + ReleaseBuffer(buffer); + } + + alGetSourcei(source->m_source, AL_BUFFERS_QUEUED, &queuedCount); + hasReachedEnd = (source->m_nextSample == resource->GetTotalSampleCount()); + shouldStop = (hasReachedEnd && !source->IsLooping()); + + if (shouldStop && queuedCount == 0) + { + source->m_isPlaying = false; + // Immediately start loading samples from the beginning again. + shouldStop = false; + } + + if (!source->m_isLoadingBuffer && !shouldStop && queuedCount < SOUNDENGINE_STREAMING_BUFFER_COUNT) + { + if (hasReachedEnd) + source->m_nextSample = 0; + + sampleOffset = source->m_nextSample; + sampleCount = resource->GetSampleCountForTime(SOUNDENGINE_STREAMING_BUFFER_SIZE); + sampleCount = std::min(sampleCount, resource->GetTotalSampleCount() - sampleOffset); + + assert(sampleCount > 0); + + std::function task = [source, resource, sampleOffset, sampleCount]() { + if (source->m_cancelBufferLoading) + { + source->m_cancelBufferLoading = false; + source->m_isLoadingBuffer = false; + + printf("Buffer loading was canceled\n"); + + return; + } + + ALuint buffer = GetBuffer(); + resource->FillBuffer(buffer, sampleOffset, sampleCount); + alSourceQueueBuffers(source->m_source, 1, &buffer); + + ALint state; + alGetSourcei(source->m_source, AL_SOURCE_STATE, &state); + + // If we were playing but ran out of buffers, restart playback. + if (source->m_isPlaying && state != AL_PLAYING) + source->Play(); + + source->m_nextSample = sampleOffset + sampleCount; + source->m_cancelBufferLoading = false; + source->m_isLoadingBuffer = false; + }; + + source->m_isLoadingBuffer = true; + m_threadPool->EnqueueTask(task); + } + } + } + +#if 1 + ALenum error = alGetError(); + + if (error != AL_NO_ERROR) + printf("alGetError=%s (0x%x)\n", alGetString(error), error); +#endif +} diff --git a/Sound/SoundEngine.h b/Sound/SoundEngine.h new file mode 100644 index 00000000..9ad6177c --- /dev/null +++ b/Sound/SoundEngine.h @@ -0,0 +1,74 @@ +#ifndef SOUNDENGINE_H +#define SOUNDENGINE_H + +#include +#include + +#include +#include + +#include "Listener.h" +#include "SoundSource.h" +#include "SoundResource.h" +#include "ThreadPool.h" +#include "Util.h" + +#define SOUNDENGINE_POSITION_SCALE 0.01f +#define SOUNDENGINE_BUFFER_POOL_SIZE 128 +// Sound files larger than this will be streamed. +#define SOUNDENGINE_STREAMING_SIZE_LIMIT (1 * 1024 * 1024) +// Maximum number of buffers that can be queued at once for a streaming source. +#define SOUNDENGINE_STREAMING_BUFFER_COUNT 3 +// How many samples, in seconds, each buffer will hold for streaming resources. +#define SOUNDENGINE_STREAMING_BUFFER_SIZE 0.25 + +class SoundEngine +{ +public: + static bool Init(); + static void Release(); + + static void SetDopplerFactor(float dopplerFactor); + // Used for the doppler effect, default value is 343.3 (Sound travels through air at ~343m/s) + static void SetSpeedOfSound(float speed); + + static SoundSource *CreateSoundSource(); + static void DestroySoundSource(SoundSource *source); + + static void Update(); + +private: + // Allow SoundSources to get SoundResources. + friend class SoundSource; + + // If the resource is not currently loaded, this function will block while reading the resource from disk. + // These functions are thread safe. + static SoundResource *GetSoundResource(const std::string &name); + static void ReleaseSoundResource(SoundResource *resource); + + // Allow SoundResources to use the buffer pool. + friend class SoundResourceWAV; + + // These functions are thread safe. + static ALuint GetBuffer(); + static void ReleaseBuffer(ALuint buffer); + +private: + static ALCdevice *m_device; + static ALCcontext *m_context; + + static ThreadPool *m_threadPool; + + static ALuint m_bufferPool[SOUNDENGINE_BUFFER_POOL_SIZE]; + static size_t m_bufferPoolSize; + + static Mutex *m_bufferPoolMutex; + static Mutex *m_resourceMutex; + + static std::vector> m_soundResources; + static std::vector m_soundSources; + + static std::vector m_sourcesPendingDeletion; +}; + +#endif diff --git a/Sound/SoundResource.h b/Sound/SoundResource.h new file mode 100644 index 00000000..0e32a24b --- /dev/null +++ b/Sound/SoundResource.h @@ -0,0 +1,70 @@ +#ifndef SOUNDRESOURCE_H +#define SOUNDRESOURCE_H + +#include +#include + +#include + +struct SoundResourceInfo +{ + ALenum format; + size_t totalSamples; + int channels; + int sampleRate; + int bitDepth; +}; + +class SoundResource +{ +public: + virtual ~SoundResource() + { + } + std::string GetName() + { + return m_name; + } + bool IsStreaming() + { + return m_isStreaming; + } + float GetDuration() + { + return m_duration; + } + // time is in seconds. + size_t GetSampleCountForTime(float time) + { + assert(time >= 0.0f); + + return (size_t)(time * m_info.sampleRate * m_info.channels); + } + size_t GetTotalSampleCount() + { + return m_info.totalSamples; + } + + virtual ALuint GetBuffer() = 0; + // This function will block while it's reading from the disk. + virtual void FillBuffer(ALuint buffer, size_t sampleOffset, size_t sampleCount) = 0; + +protected: + SoundResource(const std::string &name, const SoundResourceInfo &info, bool isStreaming) + { + m_name = name; + m_info = info; + m_isStreaming = isStreaming; + m_duration = (info.totalSamples / info.channels) / (float)info.sampleRate; + + //printf("Created SoundResouce '%s'\n", name.c_str()); + //printf("streaming=%s, duration=%.2fs, channels=%i, sampleRate=%.1fkHz, bitDepth=%i\n", (isStreaming? "true" : "false"), m_duration, info.channels, info.sampleRate / 1000.0f, info.bitDepth); + } + + std::string m_name; + SoundResourceInfo m_info; + bool m_isStreaming; + float m_duration; +}; + +#endif diff --git a/Sound/SoundResourceWAV.cpp b/Sound/SoundResourceWAV.cpp new file mode 100644 index 00000000..4cd2dbba --- /dev/null +++ b/Sound/SoundResourceWAV.cpp @@ -0,0 +1,185 @@ +#include +#include +#include +#include + +#include "SoundResourceWAV.h" +#include "SoundEngine.h" +#include "Util.h" + +#ifndef WAVE_FORMAT_PCM +#define WAVE_FORMAT_PCM 0x0001 +#endif + +struct ChunkHeader +{ + uint32_t fourcc; + uint32_t size; +}; + +struct HeaderChunk +{ + ChunkHeader base; + uint32_t format; +}; + +struct FormatChunk +{ + ChunkHeader base; + uint16_t format; + uint16_t channels; + uint32_t sampleRate; + uint32_t byteRate; + uint16_t blockAlign; + uint16_t bitDepth; +}; + +SoundResourceWAV *SoundResourceWAV::Load(const std::string &name) +{ + std::fstream file; + file.open(name, std::ios_base::in | std::ios_base::binary); + + if (!file.is_open()) + { + printf("Failed to open file %s\n", name.c_str()); + return NULL; + } + + HeaderChunk header; + file.read((char *)&header, sizeof(header)); + + if (header.base.fourcc != FOURCC('R', 'I', 'F', 'F') || header.format != FOURCC('W', 'A', 'V', 'E')) + { + printf("%s is not a valid wav file!\n", name.c_str()); + file.close(); + return NULL; + } + + FormatChunk format; + file.read((char *)&format, sizeof(format)); + + if (format.base.fourcc != FOURCC('f', 'm', 't', ' ') || format.base.size != 16 || format.format != WAVE_FORMAT_PCM) + { + printf("%s is not a valid LPCM wav file!\n", name.c_str()); + file.close(); + return NULL; + } + + if (format.bitDepth != 8 && format.bitDepth != 16) + { + printf("%s has unsupported bitdepth!\n", name.c_str()); + file.close(); + return NULL; + } + + ALenum bufferFormat; + + switch(format.channels) + { + case 1: + bufferFormat = (format.bitDepth == 8? AL_FORMAT_MONO8 : AL_FORMAT_MONO16); + break; + case 2: + bufferFormat = (format.bitDepth == 8? AL_FORMAT_STEREO8 : AL_FORMAT_STEREO16); + break; + default: + printf("%s has unsupported number of channels!\n", name.c_str()); + file.close(); + return NULL; + } + + ChunkHeader dataHeader; + file.read((char *)&dataHeader, sizeof(dataHeader)); + + while(dataHeader.fourcc != FOURCC('d', 'a', 't', 'a')) + { + file.seekg((uint32_t)file.tellg() + dataHeader.size); + file.read((char *)&dataHeader, sizeof(dataHeader)); + + if (file.eof()) + { + printf("Failed to find data chunk in file %s!\n", name.c_str()); + file.close(); + return NULL; + } + } + + SoundResourceInfo info; + info.format = bufferFormat; + info.totalSamples = dataHeader.size / (format.bitDepth / 8); + info.channels = format.channels; + info.sampleRate = format.sampleRate; + info.bitDepth = format.bitDepth; + + bool shouldStream = (dataHeader.size > SOUNDENGINE_STREAMING_SIZE_LIMIT? true : false); + SoundResourceWAV *resource; + + if (shouldStream) + { + size_t dataOffset = (size_t)file.tellg(); + file.close(); + + resource = new SoundResourceWAV(name, dataOffset, info); + } + else + { + char *data = new char[dataHeader.size]; + file.read(data, dataHeader.size); + file.close(); + + resource = new SoundResourceWAV(name, data, (size_t)dataHeader.size, info); + + delete[] data; + } + + return resource; +} + +SoundResourceWAV::SoundResourceWAV(const std::string &name, const char *data, size_t size, const SoundResourceInfo &info) : + SoundResource(name, info, false) +{ + m_buffer = SoundEngine::GetBuffer(); + alBufferData(m_buffer, info.format, data, (ALsizei)size, info.sampleRate); +} + +SoundResourceWAV::SoundResourceWAV(const std::string &name, size_t dataOffset, const SoundResourceInfo &info) : + SoundResource(name, info, true) +{ + m_file.open(name, std::ios_base::in | std::ios_base::binary); + m_dataOffset = dataOffset; + + assert(m_file.is_open()); +} + +SoundResourceWAV::~SoundResourceWAV() +{ + if (m_isStreaming) + m_file.close(); + else + SoundEngine::ReleaseBuffer(m_buffer); +} + +ALuint SoundResourceWAV::GetBuffer() +{ + assert(!m_isStreaming); + + return m_buffer; +} + +void SoundResourceWAV::FillBuffer(ALuint buffer, size_t sampleOffset, size_t sampleCount) +{ + assert(m_isStreaming); + assert(m_file.is_open()); + assert(sampleOffset + sampleCount <= m_info.totalSamples); + + size_t offset = m_dataOffset + sampleOffset * (m_info.bitDepth / 8); + size_t size = sampleCount * (m_info.bitDepth / 8); + + char *data = new char[size]; + m_file.seekg(offset); + m_file.read(data, size); + + alBufferData(buffer, m_info.format, data, (ALsizei)size, m_info.sampleRate); + + delete[] data; +} diff --git a/Sound/SoundResourceWAV.h b/Sound/SoundResourceWAV.h new file mode 100644 index 00000000..f5c47a25 --- /dev/null +++ b/Sound/SoundResourceWAV.h @@ -0,0 +1,39 @@ +#ifndef SOUNDRESOURCEWAV_H +#define SOUNDRESOURCEWAV_H + +#include +#include + +#include + +#include "SoundResource.h" + +class SoundResourceWAV : public SoundResource +{ +public: + virtual ~SoundResourceWAV(); + + ALuint GetBuffer(); + void FillBuffer(ALuint buffer, size_t sampleOffset, size_t sampleCount); + +private: + // Limit creating SoundResources to the SoundEngine. + friend class SoundEngine; + + static SoundResourceWAV *Load(const std::string &name); + + // Constructor for non-streaming. + SoundResourceWAV(const std::string &name, const char *data, size_t size, const SoundResourceInfo &info); + // Constructor for streaming. + SoundResourceWAV(const std::string &name, size_t dataOffset, const SoundResourceInfo &info); + +private: + // Non-streaming specific members. + ALuint m_buffer; + + // Streaming specific members. + std::fstream m_file; + size_t m_dataOffset; +}; + +#endif diff --git a/Sound/SoundSource.cpp b/Sound/SoundSource.cpp new file mode 100644 index 00000000..95da2d68 --- /dev/null +++ b/Sound/SoundSource.cpp @@ -0,0 +1,198 @@ +#include +#include +#include + +#include "SoundSource.h" +#include "SoundResource.h" +#include "SoundEngine.h" +#include "ThreadPool.h" + +SoundSource::SoundSource() +{ + alGenSources(1, &m_source); + m_resource = NULL; + m_isPlaying = false; + m_isLooping = false; + m_isLoadingBuffer = false; + m_isLoadingResource = false; + m_cancelBufferLoading = false; + m_nextSample = 0; + m_pendingSeek = -1.0f; +} + +SoundSource::~SoundSource() +{ + SetResource(NULL); + alDeleteSources(1, &m_source); +} + +void SoundSource::ReleaseAllQueuedBuffers() +{ + if (!m_resource || !m_resource->IsStreaming()) + return; + + int count = 0; + ALuint buffer = AL_NONE; + + alSourceStop(m_source); + alGetSourcei(m_source, AL_BUFFERS_QUEUED, &count); + + for(int i = 0; i < count; i++) + { + alSourceUnqueueBuffers(m_source, 1, &buffer); + SoundEngine::ReleaseBuffer(buffer); + } +} + +void SoundSource::SetResource(const char *name) +{ + if (m_isLoadingResource) + { + printf("SoundSource::SetResource(\"%s\"), another resource is already being loaded!\n", name); + return; + } + + if (name && m_resource && m_resource->GetName() == std::string(name)) + return; + + if (m_isLoadingBuffer) + m_cancelBufferLoading = true; + + // The source must be stopped before we can change any buffers. + alSourceStop(m_source); + + if (m_resource) + { + ReleaseAllQueuedBuffers(); + alSourcei(m_source, AL_BUFFER, AL_NONE); + SoundEngine::ReleaseSoundResource(m_resource); + } + + m_resource = NULL; + + if (name) + { + SoundSource *source = this; + + std::function task = [source, name]() { + SoundResource *resource = SoundEngine::GetSoundResource(name); + + if (resource) + { + if (!resource->IsStreaming()) + { + alSourcei(source->m_source, AL_BUFFER, resource->GetBuffer()); + alSourcei(source->m_source, AL_LOOPING, (source->m_isLooping? AL_TRUE : AL_FALSE)); + } + else + { + source->m_nextSample = 0; + alSourcei(source->m_source, AL_LOOPING, AL_FALSE); + } + + if (source->m_isPlaying) + source->Play(); + } + + source->m_resource = resource; + source->m_isLoadingResource = false; + + if (source->m_pendingSeek > 0.0f) + { + source->Seek(source->m_pendingSeek); + source->m_pendingSeek = -1.0f; + } + }; + + m_isLoadingResource = true; + SoundEngine::m_threadPool->EnqueueTask(task); + } +} + +SoundResource *SoundSource::GetResource() +{ + return m_resource; +} + +bool SoundSource::IsPlaying() +{ + return m_isPlaying; +} + +bool SoundSource::IsLooping() +{ + return m_isLooping; +} + +void SoundSource::Play() +{ + alSourcePlay(m_source); + m_isPlaying = true; +} + +void SoundSource::Pause() +{ + alSourcePause(m_source); + m_isPlaying = false; +} + +void SoundSource::Seek(float time) +{ + if (m_isLoadingResource) + { + m_pendingSeek = time; + return; + } + + if (!m_resource) + return; + + size_t sample = std::min(m_resource->GetSampleCountForTime(std::max(time, 0.0f)), m_resource->GetTotalSampleCount() - 1); + + if (!m_resource->IsStreaming()) + { + alSourcei(m_source, AL_SAMPLE_OFFSET, (ALint)sample); + } + else + { + if (m_isLoadingBuffer) + m_cancelBufferLoading = true; + + ReleaseAllQueuedBuffers(); + m_nextSample = sample; + } +} + +void SoundSource::SetPosition(const float position[3]) +{ + const float scaledPosition[3] = {position[0] * SOUNDENGINE_POSITION_SCALE, position[1] * SOUNDENGINE_POSITION_SCALE, position[2] * SOUNDENGINE_POSITION_SCALE}; + alSourcefv(m_source, AL_POSITION, scaledPosition); +} + +void SoundSource::SetVelocity(const float velocity[3]) +{ + alSourcefv(m_source, AL_VELOCITY, velocity); +} + +void SoundSource::SetVolume(float volume) +{ + alSourcef(m_source, AL_GAIN, volume); +} + +void SoundSource::SetLooping(bool looping) +{ + m_isLooping = looping; + + if (m_resource && !m_resource->IsStreaming()) + alSourcei(m_source, AL_LOOPING, (looping? AL_TRUE : AL_FALSE)); +} + +void SoundSource::SetPitch(float pitch) +{ + alSourcef(m_source, AL_PITCH, pitch); +} + +void SoundSource::SetIsRelativeToListener(bool relative) +{ + alSourcei(m_source, AL_SOURCE_RELATIVE, (relative? AL_TRUE : AL_FALSE)); +} diff --git a/Sound/SoundSource.h b/Sound/SoundSource.h new file mode 100644 index 00000000..711489c2 --- /dev/null +++ b/Sound/SoundSource.h @@ -0,0 +1,62 @@ +#ifndef SOUNDSOURCE_H +#define SOUNDSOURCE_H + +#include + +#include + +class SoundEngine; +class SoundResource; + +class SoundSource +{ +public: + virtual ~SoundSource(); + + void SetResource(const char *name); + SoundResource *GetResource(); + + bool IsPlaying(); + bool IsLooping(); + + void Play(); + void Pause(); + + // time is in seconds. + void Seek(float time); + + void SetPosition(const float position[3]); + // Used for the doppler effect, should be in the same unit as the speed of sound set in SoundEngine. + void SetVelocity(const float velocity[3]); + + void SetVolume(float volume); + void SetLooping(bool looping); + void SetPitch(float pitch); + + // Sets whether position and velocity should be relative to the listener or not. + void SetIsRelativeToListener(bool relative); + +private: + // Limit creating SoundSources to the SoundEngine. + friend class SoundEngine; + + SoundSource(); + + void ReleaseAllQueuedBuffers(); + +private: + ALuint m_source; + SoundResource *m_resource; + + bool m_isPlaying; + bool m_isLooping; + + bool m_isLoadingBuffer; + bool m_isLoadingResource; + bool m_cancelBufferLoading; + + size_t m_nextSample; + float m_pendingSeek; +}; + +#endif diff --git a/Sound/ThreadPool.cpp b/Sound/ThreadPool.cpp new file mode 100644 index 00000000..69b42e1f --- /dev/null +++ b/Sound/ThreadPool.cpp @@ -0,0 +1,56 @@ +#include "ThreadPool.h" + +static VOID CALLBACK TaskCallback(PTP_CALLBACK_INSTANCE instance, PVOID parameter, PTP_WORK work) +{ + std::function *task = (std::function *)parameter; + + (*task)(); + + delete task; +} + +ThreadPool::ThreadPool() +{ + m_pool = CreateThreadpool(NULL); + SetThreadpoolThreadMinimum(m_pool, 1); + // FIXME: Don't hardcode this. + SetThreadpoolThreadMaximum(m_pool, 4); + + InitializeThreadpoolEnvironment(&m_environment); + SetThreadpoolCallbackPool(&m_environment, m_pool); +} + +ThreadPool::~ThreadPool() +{ + DestroyThreadpoolEnvironment(&m_environment); + CloseThreadpool(m_pool); +} + +void ThreadPool::EnqueueTask(const std::function &task) +{ + std::function *data = new std::function(task); + + PTP_WORK work = CreateThreadpoolWork(TaskCallback, (void *)data, &m_environment); + SubmitThreadpoolWork(work); + CloseThreadpoolWork(work); +} + +Mutex::Mutex() +{ + m_mutex = CreateMutex(NULL, false, NULL); +} + +Mutex::~Mutex() +{ + CloseHandle(m_mutex); +} + +void Mutex::Lock() +{ + WaitForSingleObject(m_mutex, INFINITE); +} + +void Mutex::Unlock() +{ + ReleaseMutex(m_mutex); +} diff --git a/Sound/ThreadPool.h b/Sound/ThreadPool.h new file mode 100644 index 00000000..967f7967 --- /dev/null +++ b/Sound/ThreadPool.h @@ -0,0 +1,36 @@ +#ifndef THREADPOOL_H +#define THREADPOOL_H + +#include + +#define WIN32_LEAN_AND_MEAN +#define NOMINMAX +#include + +class ThreadPool +{ +public: + ThreadPool(); + virtual ~ThreadPool(); + + void EnqueueTask(const std::function &task); + +private: + PTP_POOL m_pool; + TP_CALLBACK_ENVIRON m_environment; +}; + +class Mutex +{ +public: + Mutex(); + virtual ~Mutex(); + + void Lock(); + void Unlock(); + +private: + HANDLE m_mutex; +}; + +#endif diff --git a/Sound/Util.h b/Sound/Util.h new file mode 100644 index 00000000..f89e18f1 --- /dev/null +++ b/Sound/Util.h @@ -0,0 +1,39 @@ +#ifndef UTIL_H +#define UTIL_H + +#include + +#define FOURCC(a, b, c, d) ((uint32_t)(((d) << 24) | ((c) << 16) | ((b) << 8) | (a))) + +template +class RefCounted +{ +public: + RefCounted(T value) + { + m_value = value; + m_refCount = 1; + } + ~RefCounted() + { + } + T GetValue() + { + return m_value; + } + void IncRefCount() + { + m_refCount++; + } + int DecRefCount() + { + assert(m_refCount > 0); + + return --m_refCount; + } +private: + T m_value; + unsigned int m_refCount; +}; + +#endif diff --git a/TemplateMain.cpp b/TemplateMain.cpp new file mode 100644 index 00000000..3ae7ad2c --- /dev/null +++ b/TemplateMain.cpp @@ -0,0 +1,254 @@ +//-------------------------------------------------------------------------------------- +// File: TemplateMain.cpp +// +// BTH-D3D-Template +// +// Copyright (c) Stefan Petersson 2011. All rights reserved. +//-------------------------------------------------------------------------------------- +#include "Engine\Engine.h" +using namespace Oyster; +using namespace Oyster::Render; +//-------------------------------------------------------------------------------------- +// Forward declarations +//-------------------------------------------------------------------------------------- +LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); +bool InitDX11(HINSTANCE hInstance,int nCmdShow); +HRESULT Render(float deltaTime); +HRESULT Update(float deltaTime); + +Oyster::Buffer *cb; +Oyster::Buffer *camBuffer1; +Oyster::Buffer *camBuffer2; +bool cam1Buffered = true; +Model m[2]; +std::vector models = std::vector(10); +Oyster::Render::Camera cam = Oyster::Render::Camera(); + +struct PerObjectBuffer +{ + Oyster::Math::Float4x4 matrix; +}; + + +//-------------------------------------------------------------------------------------- +// Entry point to the program. Initializes everything and goes into a message processing +// loop. Idle time is used to render the scene. +//-------------------------------------------------------------------------------------- +int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow ) +{ + if(!InitDX11(hInstance,nCmdShow)) + return 0; + + __int64 cntsPerSec = 0; + QueryPerformanceFrequency((LARGE_INTEGER*)&cntsPerSec); + float secsPerCnt = 1.0f / (float)cntsPerSec; + + __int64 prevTimeStamp = 0; + QueryPerformanceCounter((LARGE_INTEGER*)&prevTimeStamp); + + // Main message loop + MSG msg = {0}; + while(WM_QUIT != msg.message) + { + if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE) ) + { + TranslateMessage( &msg ); + DispatchMessage( &msg ); + } + else + { + __int64 currTimeStamp = 0; + QueryPerformanceCounter((LARGE_INTEGER*)&currTimeStamp); + float dt = (currTimeStamp - prevTimeStamp) * secsPerCnt; + + //render + Update(dt); + ::Render(dt); + + prevTimeStamp = currTimeStamp; + } + } + + return (int) msg.wParam; +} + +bool InitDX11(HINSTANCE hInstance,int nCmdShow) +{ + Engine::Init::Setup setup=Engine::Init::Setup(); + setup.Window.appname = "OysterDemo"; + setup.Window.classname = "OysterDemo"; + setup.Window.hinstance = hInstance; + setup.Window.nCmdShow = nCmdShow; + setup.Window.wProc = &WndProc; + setup.Window.InitWindow = true; + setup.Common.Fullscreen = false; + if(!Oyster::Engine::Init::FullInit(setup)) + return 0; + + Oyster::Math::Float4x4 matrix = Oyster::Math::Float4x4(); + cam.LookAt(Oyster::Math::Float3(0,0,-70),Oyster::Math::Float3(0,0,1),Oyster::Math::Float3(0,1,0)); + //cam.SetLens(PI/4,1024.0f / 768.0f,1,200); + cam.SetLens(PI/4,1920.0f / 1080.0f,1,200); + cam.UpdateViewMatrix(); + matrix=cam.ViewProj(); + + Oyster::Shader::ShaderEffect se; + se.Shaders.Vertex = Oyster::Shader::Get::GetVertex("VSObj"); + se.Shaders.Pixel = Oyster::Shader::Get::GetPixel("PSObj"); + se.IAStage.Topology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST; + + ID3D11InputLayout* layout; + + D3D11_INPUT_ELEMENT_DESC ElemDesc[] = + { + {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0}, + }; + Oyster::Shader::CreateInputLayout(ElemDesc,3,Oyster::Shader::Get::GetVertex("VSObj"),layout); + se.IAStage.Layout = layout; + + Oyster::Buffer::BUFFER_INIT_DESC desc; + + desc.ElementSize=sizeof(Oyster::Math::Float4x4); + desc.NumElements = 1; + desc.Usage = Oyster::Buffer::BUFFER_CPU_WRITE_DISCARD; + desc.Type = Oyster::Buffer::CONSTANT_BUFFER_VS; + desc.InitData = matrix; + + camBuffer1 = Oyster::Engine::Init::Buffers::CreateBuffer(desc); + se.CBuffers.Vertex.push_back(camBuffer1); + + Oyster::Shader::SetShaderEffect(se); + + //create Buffers + Oyster::FileLoaders::ObjReader *reader = Oyster::FileLoaders::ObjReader::LoadFile("bth.OBJ"); + Oyster::FileLoaders::ObjReader::Vertex** vertex = new Oyster::FileLoaders::ObjReader::Vertex*[1]; + int vcount; + std::map textures; + reader->GetVertexData(vertex,vcount,textures); + + desc.ElementSize=sizeof(Oyster::FileLoaders::ObjReader::Vertex); + desc.NumElements = vcount; + desc.InitData = *vertex; + desc.Type = Oyster::Buffer::VERTEX_BUFFER; + desc.Usage = Oyster::Buffer::BUFFER_DEFAULT; + + Oyster::Buffer *VB = Oyster::Engine::Init::Buffers::CreateBuffer(desc); + + ID3D11ShaderResourceView *srv = textures["Diffuse"]; + + Oyster::Math::Float4x4 *world = new Oyster::Math::Float4x4(); + Oyster::Math::identityMatrix(*world); + + world->m43 = 20; // edited by Dan 04-19 : Still not good :/ + world->m11 = 0.5f; + world->m22 = 0.5f; + world->m33 = 0.5f; + + desc.ElementSize=64; + desc.NumElements=1; + desc.Type = Oyster::Buffer::CONSTANT_BUFFER_VS; + desc.Usage = Oyster::Buffer::BUFFER_CPU_WRITE_DISCARD; + desc.InitData = NULL; + + cb = Oyster::Engine::Init::Buffers::CreateBuffer(desc); + + m[0] = *(new Oyster::Render::Model()); + + m[0].World = world; + m[0].info->VertexCount = vcount; + m[0].info->Material.push_back(srv); + m[0].info->Indexed=false; + m[0].Visible=true; + m[0].info->Vertices=*VB; + + models.push_back(m[0]); + + world = new Oyster::Math::Float4x4(*world); + + m[1] = * (new Oyster::Render::Model(m[0])); + world->m43 = 00; + m[1].World=world; + + //models.push_back(m[1]); + + return true; +} + +HRESULT Update(float deltaTime) +{ + //Early Exit + if(Oyster::Input::Controller::isKeyReleased(VK_ESCAPE)) + PostQuitMessage(0); + if(Oyster::Input::Controller::isKeyDown(87)) + cam.Walk(10*deltaTime); + if(Oyster::Input::Controller::isKeyDown(0x53)) + cam.Walk(-10*deltaTime); + if(Oyster::Input::Controller::isKeyDown(0x41)) + cam.Strafe(-10*deltaTime); + if(Oyster::Input::Controller::isKeyDown(0x44)) + cam.Strafe(10*deltaTime); + if(Oyster::Input::Controller::isKeyDown(0x10)) + cam.Fly(-10*deltaTime); + if(Oyster::Input::Controller::isKeyDown(0x20)) + cam.Fly(10*deltaTime); + + Matrix rot; + Oyster::Math::rotationMatrix_AxisY(rot,deltaTime*PI/4); + *(m[1].World) =rot * *(m[1].World); + + Oyster::Math::rotationMatrix_AxisX(rot,deltaTime*PI/4); + *(m[0].World) = rot * *(m[0].World); + + cam.UpdateViewMatrix(); + + + void* temp = camBuffer1->Map(); + if(temp) + { + memcpy(temp,&cam.ViewProj(),sizeof(Matrix)); + camBuffer1->Unmap(); + } + + + + return S_OK; +} + +HRESULT Render(float deltaTime) +{ + Oyster::Engine::PrepareForRendering::ClearBackBuffer(Oyster::Math::Float4(0,0,1,1)); + + Oyster::Engine::Render::Geometry(m,2,cb,1); + + Oyster::Engine::Render::PresentScene(); + + return S_OK; +} + +//-------------------------------------------------------------------------------------- +// Called every time the application receives a message +//-------------------------------------------------------------------------------------- +LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) +{ + PAINTSTRUCT ps; + HDC hdc; + + switch (message) + { + case WM_PAINT: + hdc = BeginPaint(hWnd, &ps); + EndPaint(hWnd, &ps); + break; + + case WM_DESTROY: + PostQuitMessage(0); + break; + + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + + return 0; +} \ No newline at end of file diff --git a/stdafx.h b/stdafx.h new file mode 100644 index 00000000..1e73f366 --- /dev/null +++ b/stdafx.h @@ -0,0 +1,75 @@ +#ifndef _STDAFX__H +#define _STDAFX__H + +#define NOMINMAX // Because I hate Microsoft now. ~Angry Dan. +// http://lolengine.net/blog/2011/3/4/fuck-you-microsoft-near-far-macros + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define SAFE_RELEASE(x) if( x ) { (x)->Release(); (x) = NULL; } +#define SAFE_DELETE(x) if( x ) { delete(x); (x) = NULL; } +#define SAFE_DELETE_ARRAY(x) if( x ) { delete[](x); (x) = NULL; } +#define PI (3.14159265358979323846f) + +#pragma comment(lib, "d3d11.lib") +#pragma comment(lib, "d3dcompiler.lib") +#pragma comment (lib,"dxerr.lib") + +#ifdef _DEBUG +#pragma comment(lib, "d3dx11d.lib") +#pragma comment(lib, "Effects11D.lib") +#pragma comment(lib, "d3dx10d.lib") +#else +#pragma comment(lib, "d3dx11.lib") +#pragma comment(lib, "Effects11.lib") +#pragma comment(lib, "d3dx10.lib") +#endif + + + +////////////////////////////////////////////////////////////////////////// +// to find memory leaks +////////////////////////////////////////////////////////////////////////// +#define _CRTDBG_MAP_ALLOC +#include +#include + +#ifdef _DEBUG +#define myMalloc(s) _malloc_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__) +#define myCalloc(c, s) _calloc_dbg(c, s, _NORMAL_BLOCK, __FILE__, __LINE__) +#define myRealloc(p, s) _realloc_dbg(p, s, _NORMAL_BLOCK, __FILE__, __LINE__) +#define myExpand(p, s) _expand_dbg(p, s, _NORMAL_BLOCK, __FILE__, __LINE__) +#define myFree(p) _free_dbg(p, _NORMAL_BLOCK) +#define myMemSize(p) _msize_dbg(p, _NORMAL_BLOCK) +#define new new(_NORMAL_BLOCK, __FILE__, __LINE__) +#define myDelete delete // Set to dump leaks at the program exit. +#define myInitMemoryCheck() \ + _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF) +#define myDumpMemoryLeaks() \ + _CrtDumpMemoryLeaks() +#else +#define myMalloc malloc +#define myCalloc calloc +#define myRealloc realloc +#define myExpand _expand +#define myFree free +#define myMemSize _msize +#define myNew new +#define myDelete delete +#define myInitMemoryCheck() +#define myDumpMemoryLeaks() +#endif +////////////////////////////////////////////////////////////////////////// + +#endif