diff --git a/.gitignore b/.gitignore index 1774c281..0df2db42 100755 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,11 @@ bin/ lib/ # Because apparently nobody has any self control *.orig + +*.suo +*.sdf +tools/MayaExporter/MayaExporter/x64/Debug/ +tools/MayaExporter/x64/Debug/ + +tools/MayaExporter/MayaExporter/Debug/ +tools/MayaExporter/MayaExporter/GeneratedFiles/ diff --git a/assets b/assets index e8174f63..068fbb2d 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit e8174f630fc3242e15ada1346b42c72f44cbc854 +Subproject commit 068fbb2d20682dd60f186c82172d7731e60ed7e9 diff --git a/include/Engine/Collision/Collision.h b/include/Engine/Collision/Collision.h index 148f688d..194a18dc 100644 --- a/include/Engine/Collision/Collision.h +++ b/include/Engine/Collision/Collision.h @@ -10,7 +10,8 @@ #include "../Core/Ray.h" #include "../Core/AABB.h" -#include "../Rendering/RawModel.h" +#include "Rendering/RawModelCustom.h" +//#include "Rendering/RawModelAssimp.h" #include "../Core/Transform.h" #include "../Core/Entity.h" #include "../Core/EntityWrapper.h" diff --git a/include/Engine/Core/EPlayerSpawned.h b/include/Engine/Core/EPlayerSpawned.h new file mode 100644 index 00000000..a5700ed3 --- /dev/null +++ b/include/Engine/Core/EPlayerSpawned.h @@ -0,0 +1,19 @@ +#ifndef EPlayerSpawned_h__ +#define EPlayerSpawned_h__ + +#include "Core/Event.h" +#include "Core/EntityWrapper.h" + +namespace Events +{ + +struct PlayerSpawned : Event +{ + int PlayerID; + EntityWrapper Player; + EntityWrapper Spawner; +}; + +} + +#endif \ No newline at end of file diff --git a/include/Engine/Core/EntityWrapper.h b/include/Engine/Core/EntityWrapper.h index 3ba4e087..711f5045 100644 --- a/include/Engine/Core/EntityWrapper.h +++ b/include/Engine/Core/EntityWrapper.h @@ -25,6 +25,8 @@ struct EntityWrapper bool HasComponent(const std::string& componentName); EntityWrapper Parent(); + EntityWrapper FirstChildByName(const std::string& name); + bool IsChildOf(EntityWrapper potentialParent); bool Valid(); ComponentWrapper operator[](const char* componentName); diff --git a/include/Engine/Core/Octree.h b/include/Engine/Core/Octree.h index bbd27b3c..8bac5503 100644 --- a/include/Engine/Core/Octree.h +++ b/include/Engine/Core/Octree.h @@ -111,7 +111,7 @@ struct Child std::vector& m_StaticObjectsRef; std::vector& m_DynamicObjectsRef; - inline bool hasChildren() const; + bool hasChildren() const; int childIndexContainingPoint(const glm::vec3& point) const; std::vector childIndicesContainingBox(const AABB& box) const; }; diff --git a/include/Engine/Core/ResourceManager.h b/include/Engine/Core/ResourceManager.h index 15a551e7..10529819 100644 --- a/include/Engine/Core/ResourceManager.h +++ b/include/Engine/Core/ResourceManager.h @@ -32,10 +32,10 @@ public: }; struct FailedLoadingException : public std::exception { - virtual const char* what() const throw() - { - return "Resource is failed to load."; - } + FailedLoadingException(char const* const _Message) + : std::exception(_Message) + { } + FailedLoadingException() :std::exception("Resource failed to load.") { }; }; // Pretend that this is a pure virtual function that you have to implement diff --git a/include/Engine/Core/Transform.h b/include/Engine/Core/Transform.h index 474a7bdb..3b0811c9 100644 --- a/include/Engine/Core/Transform.h +++ b/include/Engine/Core/Transform.h @@ -3,13 +3,18 @@ #include "../GLM.h" #include "World.h" +#include "EntityWrapper.h" namespace Transform { +glm::vec3 AbsolutePosition(EntityWrapper entity); glm::vec3 AbsolutePosition(World* world, EntityID entity); +glm::quat AbsoluteOrientation(EntityWrapper entity); glm::quat AbsoluteOrientation(World* world, EntityID entity); +glm::vec3 AbsoluteScale(EntityWrapper entity); glm::vec3 AbsoluteScale(World* world, EntityID entity); +glm::mat4 ModelMatrix(EntityWrapper entity); glm::mat4 ModelMatrix(EntityID entity, World* world); } diff --git a/include/Engine/Editor/EditorCameraInputController.h b/include/Engine/Editor/EditorCameraInputController.h new file mode 100644 index 00000000..66c7952a --- /dev/null +++ b/include/Engine/Editor/EditorCameraInputController.h @@ -0,0 +1,115 @@ +#ifndef EditorCameraInputController_h__ +#define EditorCameraInputController_h__ + +#include +#include "../Input/FirstPersonInputController.h" +#include "../Core/EMousePress.h" +#include "../Core/EMouseRelease.h" +#include "../Core/EMouseScroll.h" +#include "../Core/ConfigFile.h" + +template +class EditorCameraInputController : public FirstPersonInputController +{ +public: + EditorCameraInputController(EventBroker* eventBroker, unsigned int playerID) + : FirstPersonInputController(eventBroker, playerID) + { + EVENT_SUBSCRIBE_MEMBER(m_EMousePress, &EditorCameraInputController::OnMousePress); + EVENT_SUBSCRIBE_MEMBER(m_EMouseRelease, &EditorCameraInputController::OnMouseRelease); + EVENT_SUBSCRIBE_MEMBER(m_EMouseScroll, &EditorCameraInputController::OnMouseScroll); + + m_Config = ResourceManager::Load("Config.ini"); + m_SpeedMultiplier = m_Config->Get("Editor.CameraSpeed", 3.f); + } + + virtual const glm::vec3 Movement() const override { return m_Movement * m_SpeedMultiplier; } + + void Enable() { m_Enabled = true; } + void Disable() { m_Enabled = false; } + + virtual bool OnCommand(const Events::InputCommand& e) override + { + if (glm::abs(e.Value) > 0 && !m_MouseLocked) { + return false; + } + + ImGuiIO& io = ImGui::GetIO(); + if (glm::abs(e.Value) > 0 && (io.WantCaptureKeyboard || io.WantCaptureMouse)) { + return false; + } + + if (e.Command == "Jump") { + if (e.Value > 0) { + m_Movement.y = glm::max(e.Value, 1.f); + } else { + m_Movement.y = 0.f; + } + } + + if (e.Command == "Crouch") { + if (e.Value > 0) { + m_Movement.y = glm::min(-e.Value, -1.f); + } else { + m_Movement.y = 0.f; + } + } + + if (e.Command == "Sprint") { + if (e.Value > 0) { + m_SpeedMultiplier *= 2.f; + } else { + m_SpeedMultiplier /= 2.f; + } + } + + return FirstPersonInputController::OnCommand(e); + } + +protected: + ConfigFile* m_Config; + bool m_Enabled = false; + float m_SpeedMultiplier = 1.f; + + EventRelay m_EMousePress; + bool OnMousePress(const Events::MousePress& e) + { + if (!m_Enabled) { + return false; + } + + if (e.Button == GLFW_MOUSE_BUTTON_2) { + ImGuiIO& io = ImGui::GetIO(); + if (!io.WantCaptureMouse) { + LockMouse(); + } + } + return true; + } + EventRelay m_EMouseRelease; + bool OnMouseRelease(const Events::MouseRelease& e) + { + if (!m_Enabled) { + return false; + } + + if (e.Button == GLFW_MOUSE_BUTTON_2) { + UnlockMouse(); + } + return true; + } + EventRelay m_EMouseScroll; + bool OnMouseScroll(const Events::MouseScroll& e) + { + if (!m_Enabled) { + return false; + } + + m_SpeedMultiplier += e.DeltaY * (0.1f * m_SpeedMultiplier); + m_Config->Set("Editor.CameraSpeed", m_SpeedMultiplier); + m_Config->SaveToDisk(); + return true; + } +}; + +#endif \ No newline at end of file diff --git a/include/Engine/Editor/EditorSystem.h b/include/Engine/Editor/EditorSystem.h index b354ddf3..2db24ba3 100644 --- a/include/Engine/Editor/EditorSystem.h +++ b/include/Engine/Editor/EditorSystem.h @@ -1,7 +1,6 @@ #include "../Core/System.h" #include "../Rendering/IRenderer.h" #include "../Rendering/Camera.h" -#include "../Rendering/DebugCameraInputController.h" #include "../Rendering/ESetCamera.h" #include "../Core/World.h" #include "../Core/SystemPipeline.h" @@ -10,8 +9,10 @@ #include "../Core/EntityFileParser.h" #include "../Core/EntityFileWriter.h" #include "../Core/EMousePress.h" +#include "../Input/EInputCommand.h" #include "EditorGUI.h" #include "EditorStats.h" +#include "EditorCameraInputController.h" class EditorSystem : public ImpureSystem { @@ -21,18 +22,24 @@ public: void Update(double dt); + void Enable(); + void Disable(); + private: IRenderer* m_Renderer; RenderFrame* m_RenderFrame; World* m_EditorWorld; SystemPipeline* m_EditorWorldSystemPipeline; - Camera* m_EditorCamera; - EntityWrapper m_Camera = EntityWrapper::Invalid; - DebugCameraInputController* m_DebugCameraInputController; + //Camera* m_EditorCamera; + EntityWrapper m_EditorCamera = EntityWrapper::Invalid; + EntityWrapper m_ActualCamera = EntityWrapper::Invalid; + EditorCameraInputController* m_EditorCameraInputController; EditorGUI* m_EditorGUI; EditorStats* m_EditorStats; // State + double m_LastTime = 0.f; + bool m_Enabled = true; EditorGUI::WidgetMode m_WidgetMode = EditorGUI::WidgetMode::Translate; EntityWrapper m_Widget = EntityWrapper::Invalid; EntityWrapper m_CurrentSelection = EntityWrapper::Invalid; @@ -56,4 +63,8 @@ private: bool OnMousePress(const Events::MousePress& e); EventRelay m_EWidgetDelta; bool OnWidgetDelta(const Events::WidgetDelta& e); + EventRelay m_EInputCommand; + bool OnInputCommand(const Events::InputCommand& e); + EventRelay m_ESetCamera; + bool OnSetCamera(const Events::SetCamera& e); }; \ No newline at end of file diff --git a/include/Engine/Input/EInputCommand.h b/include/Engine/Input/EInputCommand.h index 9ec897d3..1e150786 100644 --- a/include/Engine/Input/EInputCommand.h +++ b/include/Engine/Input/EInputCommand.h @@ -9,7 +9,7 @@ namespace Events struct InputCommand : Event { /** Numerical ID of the player. */ - unsigned int PlayerID; + int PlayerID; /** The command that was sent. */ std::string Command; /** The value of the command. */ diff --git a/include/Engine/Input/FirstPersonInputController.h b/include/Engine/Input/FirstPersonInputController.h index d8584494..426670c4 100644 --- a/include/Engine/Input/FirstPersonInputController.h +++ b/include/Engine/Input/FirstPersonInputController.h @@ -9,62 +9,119 @@ template class FirstPersonInputController : public InputController { public: - FirstPersonInputController(EventBroker* eventBroker, unsigned int playerID) - : InputController(eventBroker) - , m_PlayerID(playerID) - { - EVENT_SUBSCRIBE_MEMBER(m_ELockMouse, &FirstPersonInputController::OnLockMouse); - EVENT_SUBSCRIBE_MEMBER(m_EUnlockMouse, &FirstPersonInputController::OnUnlockMouse); - } + FirstPersonInputController(EventBroker* eventBroker, int playerID); - const glm::quat Orientation() const { return m_Orientation; } + virtual const glm::vec3 Movement() const { return m_Movement; } + virtual const glm::vec3 Rotation() const { return m_Rotation; } + virtual bool Jumping() const { return m_Jumping; } + virtual bool Crouching() const { return m_Crouching; } - void LockMouse() - { - Events::LockMouse e; - m_EventBroker->Publish(e); - m_MouseLocked = true; - } + void LockMouse(); + void UnlockMouse(); + virtual bool OnCommand(const Events::InputCommand& e) override; + virtual void Reset(); - void UnlockMouse() - { - Events::UnlockMouse e; - m_EventBroker->Publish(e); - m_MouseLocked = false; - } +protected: + const int m_PlayerID; + bool m_MouseLocked = false; + glm::vec3 m_Rotation; + glm::vec3 m_Movement; + bool m_Jumping = false; + bool m_Crouching = false; + + EventRelay m_ELockMouse; + bool OnLockMouse(const Events::LockMouse& e); + EventRelay m_EUnlockMouse; + bool OnUnlockMouse(const Events::UnlockMouse& e); +}; - virtual bool OnCommand(const Events::InputCommand& e) override - { - if (m_PlayerID != e.PlayerID) { - return false; - } +template +FirstPersonInputController::FirstPersonInputController(EventBroker* eventBroker, int playerID) + : InputController(eventBroker) + , m_PlayerID(playerID) +{ + EVENT_SUBSCRIBE_MEMBER(m_ELockMouse, &FirstPersonInputController::OnLockMouse); + EVENT_SUBSCRIBE_MEMBER(m_EUnlockMouse, &FirstPersonInputController::OnUnlockMouse); +} - if (m_MouseLocked) { - if (e.Command == "Pitch") { - float val = glm::radians(e.Value); - m_Orientation = m_Orientation * glm::angleAxis(-val, glm::vec3(1, 0, 0)); - return true; - } +template +void FirstPersonInputController::Reset() +{ + m_Rotation = glm::vec3(0.f, 0.f, 0.f); + m_Jumping = false; +} - if (e.Command == "Yaw") { - float val = glm::radians(e.Value); - m_Orientation = glm::angleAxis(-val, glm::vec3(0, 1, 0)) * m_Orientation; - return true; - } - } +template +void FirstPersonInputController::LockMouse() +{ + Events::LockMouse e; + m_EventBroker->Publish(e); + m_MouseLocked = true; +} +template +void FirstPersonInputController::UnlockMouse() +{ + Events::UnlockMouse e; + m_EventBroker->Publish(e); + m_MouseLocked = false; +} + +template +bool FirstPersonInputController::OnCommand(const Events::InputCommand& e) +{ + if (m_PlayerID != e.PlayerID) { return false; } -protected: - const unsigned int m_PlayerID; - glm::quat m_Orientation; - bool m_MouseLocked = false; - - EventRelay m_ELockMouse; - bool OnLockMouse(const Events::LockMouse& e) { m_MouseLocked = true; return true; } - EventRelay m_EUnlockMouse; - bool OnUnlockMouse(const Events::UnlockMouse& e) { m_MouseLocked = false; return true; } -}; + if (e.Command == "Pitch") { + float val = glm::radians(e.Value); + m_Rotation.x += -val; + //m_Rotation.x = glm::clamp(m_Rotation.x, -glm::half_pi(), glm::half_pi()); + } + + if (e.Command == "Yaw") { + float val = glm::radians(e.Value); + m_Rotation.y += -val; + } + + if (e.Command == "Forward" || e.Command == "Right") { + if (e.Command == "Forward") { + float val = glm::clamp(e.Value, -1.f, 1.f); + m_Movement.z = -val; + } + if (e.Command == "Right") { + float val = glm::clamp(e.Value, -1.f, 1.f); + m_Movement.x = val; + } + if (glm::length2(m_Movement) > 0) { + m_Movement = glm::normalize(m_Movement); + } + } + + if (e.Command == "Jump") { + m_Jumping = e.Value > 0; + } + + if (e.Command == "Crouch") { + m_Crouching = e.Value > 0; + } + + return true; +} + +template +bool FirstPersonInputController::OnUnlockMouse(const Events::UnlockMouse& e) +{ + m_MouseLocked = false; + return true; +} + +template +bool FirstPersonInputController::OnLockMouse(const Events::LockMouse& e) +{ + m_MouseLocked = true; + return true; +} #endif \ No newline at end of file diff --git a/include/Engine/Network/Client.h b/include/Engine/Network/Client.h index 96511baa..92d78f4a 100644 --- a/include/Engine/Network/Client.h +++ b/include/Engine/Network/Client.h @@ -20,6 +20,7 @@ #include "Input/EInputCommand.h" #include "Core/EPlayerDamage.h" #include "Network/EInterpolate.h" +#include "Core/EPlayerSpawned.h" class Client : public Network { @@ -39,14 +40,14 @@ private: char readBuf[INPUTSIZE] = { 0 }; // Packet loss logic - unsigned int m_PacketID = 0; - unsigned int m_PreviousPacketID = 0; - unsigned int m_SendPacketID = 0; + PacketID m_PacketID = 0; + PacketID m_PreviousPacketID = 0; + PacketID m_SendPacketID = 0; // Game logic World* m_World; std::string m_PlayerName; - int m_PlayerID = -1; + PlayerID m_PlayerID = -1; EntityID m_ServerEntityID = std::numeric_limits::max(); bool m_IsConnected = false; // Server Client Lookup map @@ -57,25 +58,27 @@ private: std::unordered_map m_ClientIDToServerID; // Network logic - PlayerDefinition m_PlayerDefinitions[MAXCONNECTIONS]; + PlayerDefinition m_PlayerDefinitions[8]; SnapshotDefinitions m_NextSnapshot; double m_DurationOfPingTime; std::clock_t m_StartPingTime; + std::clock_t m_TimeSinceSentInputs; + unsigned int m_SendInputIntervalMs; std::vector m_InputCommandBuffer; // Private member functions void readFromServer(); - int receive(char* data, size_t length); + int receive(char* data); void send(Packet& packet); void connect(); void disconnect(); - void ping(); void parseMessageType(Packet& packet); void updateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID, const std::string& componentType); void parseConnect(Packet& packet); void parsePlayerConnected(Packet& packet); void parsePing(); - void parseServerPing(); + void parseKick(); + void parsePlayersSpawned(Packet& packet); void InterpolateFields(Packet & packet, const ComponentInfo & componentInfo, const EntityID & entityID, const std::string & componentType); void parseSnapshot(Packet& packet); void identifyPacketLoss(); diff --git a/include/Engine/Network/EPlayerDisconnected.h b/include/Engine/Network/EPlayerDisconnected.h new file mode 100644 index 00000000..278a7b1f --- /dev/null +++ b/include/Engine/Network/EPlayerDisconnected.h @@ -0,0 +1,18 @@ +#ifndef Events_PlayerDisconnected +#define Events_PlayerDisconnected + +#include "Core/EventBroker.h" +#include "Core/Entity.h" + +namespace Events +{ + +struct PlayerDisconnected : public Event +{ + unsigned int PlayerID; + EntityID Entity; +}; + +} + +#endif diff --git a/include/Engine/Network/MessageType.h b/include/Engine/Network/MessageType.h index f0026190..13ac5e9d 100644 --- a/include/Engine/Network/MessageType.h +++ b/include/Engine/Network/MessageType.h @@ -5,16 +5,17 @@ // Used to determine what type of message was sent. enum class MessageType { - Connect, - Disconnect, - ClientPing, - ServerPing, - Message, - Snapshot, + Connect, + Disconnect, + Ping, + Message, + Snapshot, OnInputCommand, OnPlayerDamage, PlayerConnected, - BecomePlayer + BecomePlayer, + Kick, + OnPlayerSpawned }; #endif diff --git a/include/Engine/Network/Network.h b/include/Engine/Network/Network.h index 1464a96f..480ac602 100644 --- a/include/Engine/Network/Network.h +++ b/include/Engine/Network/Network.h @@ -1,13 +1,21 @@ #ifndef Network_h__ #define Network_h__ +#include + #include "Core/World.h" #include "Core/EventBroker.h" #include "Network/Packet.h" +#include "Network/NetworkData.h" +#include "Core/ResourceManager.h" +#include "Core/ConfigFile.h" +#include +#include -#define MAXCONNECTIONS 8 #define INPUTSIZE 4097 -#define TIMEOUTMS 15000 +typedef unsigned int PlayerID; +typedef unsigned int PacketID; +typedef unsigned int UserID; class Network { @@ -15,6 +23,17 @@ public: virtual ~Network() { }; virtual void Start(World* m_world, EventBroker *eventBroker) = 0; virtual void Update() = 0; +protected: + // For Debug + bool isReadingData = false; + NetworkData m_NetworkData; + unsigned int m_SaveDataIntervalMs = 1000; + std::clock_t m_SaveDataTimer; + unsigned int m_MaxConnections; + unsigned int m_TimeoutMs; + void saveToFile(); + void updateNetworkData(); + void initialize(); }; #endif \ No newline at end of file diff --git a/include/Engine/Network/NetworkData.h b/include/Engine/Network/NetworkData.h new file mode 100644 index 00000000..87f7a215 --- /dev/null +++ b/include/Engine/Network/NetworkData.h @@ -0,0 +1,18 @@ +#ifndef NetworkData_h__ +#define NetworkData_h__ +#include + +struct NetworkData { + unsigned int TotalTime = 0; + unsigned int TotalDataReceived = 0; + unsigned int TotalDataSent = 0; + unsigned int AmountOfMessagesReceived = 0; + unsigned int AmountOfMessagesSent = 0; + // Interval based + unsigned int DataReceivedThisInterval = 0; + unsigned int DataSentThisInterval = 0; + // pair: first=reveived, second=send + std::vector> BandwidthBytes; +}; + +#endif diff --git a/include/Engine/Network/Packet.h b/include/Engine/Network/Packet.h index 2891bf87..d38ddf58 100644 --- a/include/Engine/Network/Packet.h +++ b/include/Engine/Network/Packet.h @@ -55,12 +55,14 @@ public: char* Data() { return m_Data; }; unsigned int DataReadSize() { return m_ReturnDataOffset; } unsigned int MaxSize() { return m_MaxPacketSize; } + unsigned int HeaderSize() { return m_HeaderSize; } private: char* m_Data; unsigned int m_ReturnDataOffset = 0; int m_Offset = 0; unsigned int m_MaxPacketSize = 512; + unsigned int m_HeaderSize = 0; void resizeData(); }; diff --git a/include/Engine/Network/Server.h b/include/Engine/Network/Server.h index 8aabceba..e7c745e7 100644 --- a/include/Engine/Network/Server.h +++ b/include/Engine/Network/Server.h @@ -14,6 +14,8 @@ #include "../Network/Network.h" #include "Input/EInputCommand.h" #include "Core/EPlayerDamage.h" +#include "Network/EPlayerDisconnected.h" +#include "Core/EPlayerSpawned.h" class Server : public Network { @@ -29,7 +31,7 @@ private: boost::asio::ip::udp::socket m_Socket; // Sending messages to client logic - PlayerDefinition m_PlayerDefinitions[MAXCONNECTIONS]; + PlayerDefinition m_PlayerDefinitions[8]; // std::vector m_ConnectedUsers; char readBuffer[INPUTSIZE] = { 0 }; int bytesRead = 0; @@ -38,8 +40,8 @@ private: std::clock_t previousSnapshotMessage = std::clock(); std::clock_t timOutTimer = std::clock(); // How often we send messages (milliseconds) - int intervalMs = 1000; - int snapshotInterval = 50; + int pingIntervalMs; + int snapshotInterval; int checkTimeOutInterval = 100; //Timers @@ -50,32 +52,36 @@ private: EventBroker* m_EventBroker; // Packet loss logic - unsigned int m_PacketID = 0; - unsigned int m_PreviousPacketID = 0; + PacketID m_PacketID = 0; + PacketID m_PreviousPacketID = 0; // Private member functions - int receive(char* data, size_t length); + int receive(char* data); void readFromClients(); - void send(Packet& packet, int playerID); + void send(Packet& packet, UserID user); + void send(PlayerID player, Packet& packet); void send(Packet& packet); void broadcast(Packet& packet); void sendSnapshot(); void sendPing(); void checkForTimeOuts(); - void disconnect(int i); + void disconnect(UserID user); void parseMessageType(Packet& packet); void parseOnInputCommand(Packet& packet); void parseOnPlayerDamage(Packet& packet); void parseConnect(Packet& packet); void parseDisconnect(); void parseClientPing(); - void parseServerPing(); + void parsePing(); void identifyPacketLoss(); void createPlayer(); - int GetPlayerIDFromEndpoint(boost::asio::ip::udp::endpoint endpoint); + void kick(PlayerID player); + PlayerID GetPlayerIDFromEndpoint(boost::asio::ip::udp::endpoint endpoint); // Debug event EventRelay m_EInputCommand; bool OnInputCommand(const Events::InputCommand& e); + EventRelay m_EPlayerSpawned; + bool OnPlayerSpawned(const Events::PlayerSpawned& e); }; #endif diff --git a/include/Engine/Rendering/DebugCameraInputController.h b/include/Engine/Rendering/DebugCameraInputController.h deleted file mode 100644 index 5ce85b3f..00000000 --- a/include/Engine/Rendering/DebugCameraInputController.h +++ /dev/null @@ -1,84 +0,0 @@ -#ifndef DebugCameraInputController_h__ -#define DebugCameraInputController_h__ - -#include -#include "../Input/FirstPersonInputController.h" -#include "../Core/EMousePress.h" -#include "../Core/EMouseRelease.h" - -template -class DebugCameraInputController : public FirstPersonInputController -{ -public: - DebugCameraInputController(EventBroker* eventBroker, unsigned int playerID) - : FirstPersonInputController(eventBroker, playerID) - { - EVENT_SUBSCRIBE_MEMBER(m_EMousePress, &DebugCameraInputController::OnMousePress); - EVENT_SUBSCRIBE_MEMBER(m_EMouseRelease, &DebugCameraInputController::OnMouseRelease); - } - - void SetPosition(const glm::vec3 position) { m_Position = position; } - void SetOrientation(const glm::quat orientation) { m_Orientation = orientation; } - - const glm::vec3 Position() const { return m_Position; } - void SetBaseSpeed(float speed) { m_BaseSpeed = speed; } - - virtual bool OnCommand(const Events::InputCommand& e) override - { - ImGuiIO& io = ImGui::GetIO(); - - if (!io.WantCaptureKeyboard) { - if (e.Command == "Right") { - float value = std::max(-1.f, std::min(e.Value, 1.f)); - m_Velocity.x = value; - } - if (e.Command == "Forward") { - float value = std::max(-1.f, std::min(e.Value, 1.f)); - m_Velocity.z = -value; - } - if (e.Command == "Sprint") { - if (e.Value > 0.f) { - m_Speed = m_BaseSpeed * 2.f * (e.Value); - } else { - m_Speed = m_BaseSpeed; - } - } - } - - return FirstPersonInputController::OnCommand(e); - } - - void Update(double dt) - { - if (glm::length2(m_Velocity) > 0) { - m_Position += m_Orientation * (glm::normalize(m_Velocity) * m_Speed * (float)dt); - } - } - -protected: - glm::vec3 m_Position = glm::vec3(0, 0, 0); - glm::vec3 m_Velocity = glm::vec3(0, 0, 0); - float m_BaseSpeed = 2.0f; - float m_Speed = m_BaseSpeed; - EventRelay m_EMousePress; - bool OnMousePress(const Events::MousePress& e) - { - if (e.Button == GLFW_MOUSE_BUTTON_2) { - ImGuiIO& io = ImGui::GetIO(); - if (!io.WantCaptureMouse) { - LockMouse(); - } - } - return true; - } - EventRelay m_EMouseRelease; - bool OnMouseRelease(const Events::MouseRelease& e) - { - if (e.Button == GLFW_MOUSE_BUTTON_2) { - UnlockMouse(); - } - return true; - } -}; - -#endif \ No newline at end of file diff --git a/include/Engine/Rendering/Model.h b/include/Engine/Rendering/Model.h index 280fe5af..f751a8cc 100644 --- a/include/Engine/Rendering/Model.h +++ b/include/Engine/Rendering/Model.h @@ -1,7 +1,8 @@ #ifndef Model_h__ #define Model_h__ -#include "RawModel.h" +#include "Rendering/RawModelCustom.h" +//#include "Rendering/RawModelAssimp.h" #include "../OpenGL.h" class Model : public ThreadUnsafeResource @@ -19,12 +20,11 @@ public: GLuint VAO; GLuint ElementBuffer; + RawModel* m_RawModel; private: - RawModel* m_RawModel; + GLuint VertexBuffer; - GLuint DiffuseVertexColorBuffer; - GLuint SpecularVertexColorBuffer; GLuint NormalBuffer; GLuint TangentNormalsBuffer; GLuint BiTangentNormalsBuffer; diff --git a/include/Engine/Rendering/ModelJob.h b/include/Engine/Rendering/ModelJob.h index 6b8bd55b..35832536 100644 --- a/include/Engine/Rendering/ModelJob.h +++ b/include/Engine/Rendering/ModelJob.h @@ -24,6 +24,10 @@ struct ModelJob : RenderJob DiffuseTexture = matGroup.Texture.get(); NormalTexture = matGroup.NormalMap.get(); SpecularTexture = matGroup.SpecularMap.get(); + IncandescenceTexture = matGroup.IncandescenceMap.get(); + DiffuseColor = matGroup.DiffuseColor; + SpecularColor = matGroup.SpecularColor; + IncandescenceColor = matGroup.IncandescenceColor; StartIndex = matGroup.StartIndex; EndIndex = matGroup.EndIndex; Matrix = matrix; @@ -47,9 +51,13 @@ struct ModelJob : RenderJob const Texture* DiffuseTexture; const Texture* NormalTexture; const Texture* SpecularTexture; + const Texture* IncandescenceTexture; float Shininess = 0.f; glm::vec4 Color; const ::Model* Model = nullptr; + glm::vec4 DiffuseColor; + glm::vec4 SpecularColor; + glm::vec4 IncandescenceColor; unsigned int StartIndex = 0; unsigned int EndIndex = 0; World* World; diff --git a/include/Engine/Rendering/RawModel.h b/include/Engine/Rendering/RawModelAssimp.h similarity index 78% rename from include/Engine/Rendering/RawModel.h rename to include/Engine/Rendering/RawModelAssimp.h index 0477edb1..08df818d 100644 --- a/include/Engine/Rendering/RawModel.h +++ b/include/Engine/Rendering/RawModelAssimp.h @@ -1,5 +1,7 @@ -#ifndef RawModel_h__ -#define RawModel_h__ +#ifndef RawModelAssimp_h__ +#define RawModelAssimp_h__ + +#ifdef USING_ASSIMP_AS_IMPORTER #include #include @@ -18,29 +20,27 @@ #include "Texture.h" #include "Skeleton.h" -class RawModel : public Resource +#define RawModel RawModelAssimp + +class RawModelAssimp : public Resource { friend class ResourceManager; protected: - RawModel(std::string fileName); + RawModelAssimp(std::string fileName); public: - ~RawModel(); + ~RawModelAssimp(); struct Vertex { glm::vec3 Position; glm::vec3 Normal; glm::vec3 Tangent; - glm::vec3 BiTangent; + glm::vec3 BiNormal; glm::vec2 TextureCoords; - glm::vec4 DiffuseVertexColor; - glm::vec4 SpecularVertexColor; - glm::vec4 BoneIndices1; - glm::vec4 BoneIndices2; - glm::vec4 BoneWeights1; - glm::vec4 BoneWeights2; + glm::vec4 BoneIndices; + glm::vec4 BoneWeights; }; struct MaterialGroup @@ -68,8 +68,6 @@ private: std::vector BoneIndices; std::vector BoneWeights; std::vector Normals; - std::vector DiffuseVertexColor; - std::vector SpecularVertexColor; std::vector TangentNormals; std::vector BiTangentNormals; std::vector TextureCoords; @@ -78,3 +76,4 @@ private: }; #endif +#endif \ No newline at end of file diff --git a/include/Engine/Rendering/RawModelCustom.h b/include/Engine/Rendering/RawModelCustom.h new file mode 100644 index 00000000..f1bc0e24 --- /dev/null +++ b/include/Engine/Rendering/RawModelCustom.h @@ -0,0 +1,102 @@ +#ifndef RawModelCustom_h__ +#define RawModelCustom_h__ + +#ifndef USING_ASSIMP_AS_IMPORTER + +#define RawModel RawModelCustom + +#include +#include +#include +#include +#include + +#include + +#include "../Common.h" +#include "../GLM.h" +#include "../Core/ResourceManager.h" +#include "Texture.h" +#include "Skeleton.h" + +#include "boost\endian\buffers.hpp" + + + +class RawModelCustom : public Resource +{ + friend class ResourceManager; + +protected: + RawModelCustom(std::string fileName); + +public: + ~RawModelCustom(); + + struct Vertex + { + glm::vec3 Position; + glm::vec3 Normal; + glm::vec3 Tangent; + glm::vec3 BiNormal; + glm::vec2 TextureCoords; + glm::vec4 BoneIndices; + glm::vec4 BoneWeights; + }; + + struct MaterialGroup + { + float SpecularExponent; + float ReflectionFactor; + glm::vec4 DiffuseColor{ 1.0f, 1.0f, 1.0f, 1.0f }; + glm::vec4 SpecularColor{ 1.0f, 1.0f, 1.0f, 1.0f }; + glm::vec4 IncandescenceColor{ 1.0f, 1.0f, 1.0f, 1.0f }; + unsigned int StartIndex; + unsigned int EndIndex; + //float Transparency; + std::string TexturePath; + std::shared_ptr<::Texture> Texture; + std::string NormalMapPath; + std::shared_ptr<::Texture> NormalMap; + std::string SpecularMapPath; + std::shared_ptr<::Texture> SpecularMap; + std::string IncandescenceMapPath; + std::shared_ptr<::Texture> IncandescenceMap; + }; + + std::vector MaterialGroups; + + std::vector m_Vertices; + std::vector m_Indices; + Skeleton* m_Skeleton = nullptr; + glm::mat4 m_Matrix; + +private: + + + void ReadMeshFile(std::string filePath); + void ReadMeshFileHeader(unsigned int& offset, char* fileData, unsigned int& fileByteSize); + void ReadMesh(unsigned int& offset, char* fileData, unsigned int& fileByteSize); + void ReadVertices(unsigned int& offset, char* fileData, unsigned int& fileByteSize); + void ReadIndices(unsigned int& offset, char* fileData, unsigned int& fileByteSize); + + void ReadMaterialFile(std::string filePath); + void ReadMaterials(unsigned int &offset, char* fileData, unsigned int& fileByteSize); + void ReadMaterialSingle(unsigned int &offset, char* fileData, unsigned int& fileByteSize); + + void ReadAnimationFile(std::string filePath); + void ReadAnimationBindPoses(unsigned int &offset, char* fileData, unsigned int& fileByteSize); + void ReadAnimationJoint(unsigned int &offset, char* fileData, unsigned int& fileByteSize); + void ReadAnimationClips(unsigned int &offset, char* fileData, unsigned int& fileByteSize, unsigned int numberOfClips); + void ReadAnimationClipSingle(unsigned int &offset, char* fileData, unsigned int& fileByteSize, unsigned int clipIndex); + void ReadAnimationKeyFrame(unsigned int &offset, char* fileData, unsigned int& fileByteSize, unsigned int numberOfJoints, Skeleton::Animation& animation); + + //void CreateSkeleton(std::vector> &boneInfo, std::map &boneNameMapping, aiNode* node, int parentID); +}; + +#else + +#include "RawModelAssimp.h" + +#endif +#endif \ No newline at end of file diff --git a/include/Engine/Rendering/RenderSystem.h b/include/Engine/Rendering/RenderSystem.h index 2fd5b694..37f99341 100644 --- a/include/Engine/Rendering/RenderSystem.h +++ b/include/Engine/Rendering/RenderSystem.h @@ -15,7 +15,7 @@ #include "Renderer.h" #include "PointLightJob.h" #include "../Core/Transform.h" -#include "DebugCameraInputController.h" +#include "../Core/EPlayerSpawned.h" class RenderSystem : public ImpureSystem { @@ -29,8 +29,9 @@ private: const IRenderer* m_Renderer; RenderFrame* m_RenderFrame; Camera* m_Camera; - EntityWrapper m_CurrentCamera = EntityWrapper::Invalid; World* m_World; + EntityWrapper m_CurrentCamera = EntityWrapper::Invalid; + EntityWrapper m_LocalPlayer = EntityWrapper::Invalid; EventRelay m_ESetCamera; bool OnSetCamera(Events::SetCamera &event); @@ -42,6 +43,9 @@ private: void fillModels(std::list>& jobs); void fillLight(std::list>& jobs); + + EventRelay m_EPlayerSpawned; + bool OnPlayerSpawned(Events::PlayerSpawned& e); }; #endif \ No newline at end of file diff --git a/include/Engine/Rendering/Skeleton.h b/include/Engine/Rendering/Skeleton.h index 73d407dd..3b89b89b 100644 --- a/include/Engine/Rendering/Skeleton.h +++ b/include/Engine/Rendering/Skeleton.h @@ -4,6 +4,7 @@ #include #include "Common.h" #include "../GLM.h" +#include //struct Bone //{ @@ -38,9 +39,9 @@ public: , OffsetMatrix(offsetMatrix) { } - int ID; std::string Name; glm::mat4 OffsetMatrix; + int ID; Bone* Parent; std::vector Children; diff --git a/include/Game/Systems/InterpolationSystem.h b/include/Game/Systems/InterpolationSystem.h index 4b05571b..1e345c91 100644 --- a/include/Game/Systems/InterpolationSystem.h +++ b/include/Game/Systems/InterpolationSystem.h @@ -10,11 +10,12 @@ #include "Common.h" #include "Core/System.h" #include "Core/EventBroker.h" +#include "Core/ResourceManager.h" +#include "Core/ConfigFile.h" +#include "Core/EPlayerSpawned.h" #include "Network/EInterpolate.h" -#define SNAPSHOTINTERVAL 0.05f - class InterpolationSystem : public PureSystem { struct Transform @@ -25,29 +26,28 @@ class InterpolationSystem : public PureSystem double interpolationTime; }; public: - InterpolationSystem(World* world, EventBroker* eventBroker) - : System(world, eventBroker) - , PureSystem("Transform") - { - EVENT_SUBSCRIBE_MEMBER(m_EInterpolate, &InterpolationSystem::OnInterpolate); - } + InterpolationSystem(World* world, EventBroker* eventBroker); ~InterpolationSystem() { } virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& transform, double dt) override; private: std::unordered_map m_NextTransform; std::unordered_map m_LastReceivedTransform; + EntityWrapper m_LocalPlayer = EntityWrapper::Invalid; //glm::vec3 vectorInterpolation(glm::vec3 prev, glm::vec3 next, double currentTime); template T vectorInterpolation(T prev, T next, double currentTime) { T difference = next - prev; - T vector = (difference / SNAPSHOTINTERVAL) * static_cast(currentTime); + T vector = (difference / m_SnapshotInterval) * static_cast(currentTime); return vector; } + float m_SnapshotInterval; EventRelay m_EInterpolate; bool InterpolationSystem::OnInterpolate(const Events::Interpolate& e); + EventRelay m_EPlayerSpawned; + bool OnPlayerSpawned(Events::PlayerSpawned& e); }; #endif diff --git a/include/Game/Systems/PlayerMovementSystem.h b/include/Game/Systems/PlayerMovementSystem.h index 1be61bdd..f39740ec 100644 --- a/include/Game/Systems/PlayerMovementSystem.h +++ b/include/Game/Systems/PlayerMovementSystem.h @@ -1,14 +1,23 @@ #include "Common.h" #include "GLM.h" #include "Core/System.h" +#include "Core/EPlayerSpawned.h" +#include "Input/FirstPersonInputController.h" +#include -class PlayerMovementSystem : public PureSystem +class PlayerMovementSystem : public ImpureSystem, PureSystem { public: - PlayerMovementSystem(World* world, EventBroker* eventBroker) - : System(world, eventBroker) - , PureSystem("Player") - { } + PlayerMovementSystem(World* world, EventBroker* eventBroker); + ~PlayerMovementSystem(); + virtual void Update(double dt) override; virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt); + +private: + // State + std::unordered_map*> m_PlayerInputControllers; + + EventRelay m_EPlayerSpawned; + bool OnPlayerSpawned(Events::PlayerSpawned& e); }; \ No newline at end of file diff --git a/include/Game/Systems/PlayerSpawnSystem.h b/include/Game/Systems/PlayerSpawnSystem.h index 8ade03a6..b0ff1d79 100644 --- a/include/Game/Systems/PlayerSpawnSystem.h +++ b/include/Game/Systems/PlayerSpawnSystem.h @@ -2,6 +2,9 @@ #include "Input/EInputCommand.h" #include "Systems/SpawnerSystem.h" #include "Events/ESpawnerSpawn.h" +#include "Core/EPlayerSpawned.h" +#include "Rendering/ESetCamera.h" +#include "Core/ConfigFile.h" class PlayerSpawnSystem : public ImpureSystem { @@ -11,8 +14,18 @@ public: virtual void Update(double dt) override; private: + struct SpawnRequest + { + int PlayerID; + ComponentInfo::EnumType Team; + }; + + bool m_NetworkEnabled = false; + std::vector m_SpawnRequests; + std::map m_PlayerEntities; + EventRelay m_OnInputCommand; bool OnInputCommand(const Events::InputCommand& e); - - std::vector m_SpawnRequests; + EventRelay m_OnPlayerSpawnerd; + bool OnPlayerSpawned(Events::PlayerSpawned& e); }; \ No newline at end of file diff --git a/resources/DefaultConfig.ini b/resources/DefaultConfig.ini index fb490ec8..86dc735c 100644 --- a/resources/DefaultConfig.ini +++ b/resources/DefaultConfig.ini @@ -1,11 +1,13 @@ [Debug] LogLevel=1 LoadMap= -EditorEnabled=false ; if true -> Pool allocation is not used when calling Allocate/Free, just use regular dynamic allocation. ; if false -> Use pool allocation. DisableMemoryPool=false +[Editor] +CameraSpeed=3 + [Video] Fullscreen=false VSYNC=false @@ -19,6 +21,11 @@ IsServer=false Name=Bob Address=127.0.0.1 Port=13 +MaxConnections=8 +SnapshotInterval=0.05 +SendInputIntervalMs=33 +PingIntervalMs= 1000 +TimeoutMs=15000 [Multithreading] ResourceLoading=true diff --git a/resources/Schema/Components/Player.xml b/resources/Schema/Components/Player.xml index caefd6e6..b51326aa 100644 --- a/resources/Schema/Components/Player.xml +++ b/resources/Schema/Components/Player.xml @@ -1,8 +1,5 @@ - - false - false - false - false + 3 + 1.5 \ No newline at end of file diff --git a/resources/Schema/Components/Player.xsd b/resources/Schema/Components/Player.xsd index 1a315a35..13948dc2 100644 --- a/resources/Schema/Components/Player.xsd +++ b/resources/Schema/Components/Player.xsd @@ -9,11 +9,8 @@ - - - - - + + diff --git a/resources/Schema/Entities/AnimatedArmy.xml b/resources/Schema/Entities/AnimatedArmy.xml new file mode 100644 index 00000000..b711a0fe --- /dev/null +++ b/resources/Schema/Entities/AnimatedArmy.xml @@ -0,0 +1,273 @@ + + + + + + + + + + + + + + + + + + + + + + + models/dummyscene.mesh + + + + + + + + + + + models/animtest. + + + + + + + + + + + models/animTest.mesh + + + + + + + + + + + models/animTest.mesh + + + + + + + + + + + models/animTest.mesh + + + + + + + + + + + 0.13000047206878662 + + + + + + + + + + + + 0.30000001192092896 + + + + + + + + + + + + 5 + + + + + + + + + + + + 5 + 0.80000001192092896 + + + + + + + + + + + + 5 + + + + + + + + + + + + 5 + + + + + + + + + + + + + 0.50999981164932251 + + + + + + + + + + + + + 5 + 5 + + + + + + + + + + + + 5 + + + + + + + + + + + + 5 + + + + + + + + + + + + 5 + + + + + + + + + + + + 5 + + + + + + + + + + + + 5 + + + + + + + + + + + + 5 + + + + + + + + + + + 5 + + + + + + + + + + + + 5 + + + + + + + + + + + + diff --git a/resources/Schema/Entities/CaptureTest.xml b/resources/Schema/Entities/CaptureTest.xml index 70a8ae14..5f657e51 100644 --- a/resources/Schema/Entities/CaptureTest.xml +++ b/resources/Schema/Entities/CaptureTest.xml @@ -9,7 +9,7 @@ - ../assets/Models/DummyScene.obj + ../assets/Models/DummyScene.mesh @@ -41,7 +41,7 @@ 3 - ../assets/Models/Core/UnitSphere.obj + ../assets/Models/Core/UnitSphere.mesh @@ -61,7 +61,7 @@ 1 - ../assets/Models/Core/UnitSphere.obj + ../assets/Models/Core/UnitSphere.mesh @@ -81,7 +81,7 @@ 2 - ../assets/Models/Core/UnitSphere.obj + ../assets/Models/Core/UnitSphere.mesh @@ -102,7 +102,7 @@ 3 - ../assets/Models/Core/UnitSphere.obj + ../assets/Models/Core/UnitSphere.mesh @@ -120,7 +120,7 @@ - ../assets/Models/Core/UnitCube.obj + ../assets/Models/Core/UnitCube.mesh @@ -138,7 +138,7 @@ - ../assets/Models/Core/UnitCube.obj + ../assets/Models/Core/UnitCube.mesh diff --git a/resources/Schema/Entities/CaptureTestState1.xml b/resources/Schema/Entities/CaptureTestState1.xml index 75b14858..ffabd5c2 100644 --- a/resources/Schema/Entities/CaptureTestState1.xml +++ b/resources/Schema/Entities/CaptureTestState1.xml @@ -9,7 +9,7 @@ - ../assets/Models/DummyScene.obj + ../assets/Models/DummyScene.mesh @@ -42,7 +42,7 @@ 6.9158446328696002 - ../assets/Models/Core/UnitSphere.obj + ../assets/Models/Core/UnitSphere.mesh @@ -63,7 +63,7 @@ 1 - ../assets/Models/Core/UnitSphere.obj + ../assets/Models/Core/UnitSphere.mesh @@ -83,7 +83,7 @@ 2 - ../assets/Models/Core/UnitSphere.obj + ../assets/Models/Core/UnitSphere.mesh @@ -104,7 +104,7 @@ 3 - ../assets/Models/Core/UnitSphere.obj + ../assets/Models/Core/UnitSphere.mesh @@ -122,7 +122,7 @@ - ../assets/Models/Core/UnitCube.obj + ../assets/Models/Core/UnitCube.mesh @@ -140,7 +140,7 @@ - ../assets/Models/Core/UnitCube.obj + ../assets/Models/Core/UnitCube.mesh diff --git a/resources/Schema/Entities/CaptureTestState2.xml b/resources/Schema/Entities/CaptureTestState2.xml index 77673324..29abdfbd 100644 --- a/resources/Schema/Entities/CaptureTestState2.xml +++ b/resources/Schema/Entities/CaptureTestState2.xml @@ -9,7 +9,7 @@ - ../assets/Models/DummyScene.obj + ../assets/Models/DummyScene.mesh @@ -41,7 +41,7 @@ 3 - ../assets/Models/Core/UnitSphere.obj + ../assets/Models/Core/UnitSphere.mesh @@ -61,7 +61,7 @@ 1 - ../assets/Models/Core/UnitSphere.obj + ../assets/Models/Core/UnitSphere.mesh @@ -79,7 +79,7 @@ 2 - ../assets/Models/Core/UnitSphere.obj + ../assets/Models/Core/UnitSphere.mesh @@ -98,7 +98,7 @@ 3 - ../assets/Models/Core/UnitSphere.obj + ../assets/Models/Core/UnitSphere.mesh @@ -116,7 +116,7 @@ - ../assets/Models/Core/UnitCube.obj + ../assets/Models/Core/UnitCube.mesh @@ -134,7 +134,7 @@ - ../assets/Models/Core/UnitCube.obj + ../assets/Models/Core/UnitCube.mesh diff --git a/resources/Schema/Entities/CaptureTestState3.xml b/resources/Schema/Entities/CaptureTestState3.xml index 99da90a6..ff875dc4 100644 --- a/resources/Schema/Entities/CaptureTestState3.xml +++ b/resources/Schema/Entities/CaptureTestState3.xml @@ -9,7 +9,7 @@ - ../assets/Models/DummyScene.obj + ../assets/Models/DummyScene.mesh @@ -41,7 +41,7 @@ 3 - ../assets/Models/Core/UnitSphere.obj + ../assets/Models/Core/UnitSphere.mesh @@ -61,7 +61,7 @@ 1 - ../assets/Models/Core/UnitSphere.obj + ../assets/Models/Core/UnitSphere.mesh @@ -81,7 +81,7 @@ 2 - ../assets/Models/Core/UnitSphere.obj + ../assets/Models/Core/UnitSphere.mesh @@ -101,7 +101,7 @@ 3 - ../assets/Models/Core/UnitSphere.obj + ../assets/Models/Core/UnitSphere.mesh @@ -122,7 +122,7 @@ 4 - ../assets/Models/Core/UnitSphere.obj + ../assets/Models/Core/UnitSphere.mesh @@ -140,7 +140,7 @@ - ../assets/Models/Core/UnitCube.obj + ../assets/Models/Core/UnitCube.mesh @@ -158,7 +158,7 @@ - ../assets/Models/Core/UnitCube.obj + ../assets/Models/Core/UnitCube.mesh @@ -176,7 +176,7 @@ - ../assets/Models/Core/UnitCube.obj + ../assets/Models/Core/UnitCube.mesh @@ -194,7 +194,7 @@ - ../assets/Models/Core/UnitCube.obj + ../assets/Models/Core/UnitCube.mesh diff --git a/resources/Schema/Entities/CaptureTestState4.xml b/resources/Schema/Entities/CaptureTestState4.xml index 695df52e..740d7e7b 100644 --- a/resources/Schema/Entities/CaptureTestState4.xml +++ b/resources/Schema/Entities/CaptureTestState4.xml @@ -9,7 +9,7 @@ - ../assets/Models/DummyScene.obj + ../assets/Models/DummyScene.mesh @@ -41,7 +41,7 @@ 3 - ../assets/Models/Core/UnitSphere.obj + ../assets/Models/Core/UnitSphere.mesh @@ -61,7 +61,7 @@ 1 - ../assets/Models/Core/UnitSphere.obj + ../assets/Models/Core/UnitSphere.mesh @@ -79,7 +79,7 @@ 2 - ../assets/Models/Core/UnitSphere.obj + ../assets/Models/Core/UnitSphere.mesh @@ -96,7 +96,7 @@ 3 - ../assets/Models/Core/UnitSphere.obj + ../assets/Models/Core/UnitSphere.mesh @@ -115,7 +115,7 @@ 4 - ../assets/Models/Core/UnitSphere.obj + ../assets/Models/Core/UnitSphere.mesh @@ -133,7 +133,7 @@ - ../assets/Models/Core/UnitCube.obj + ../assets/Models/Core/UnitCube.mesh @@ -151,7 +151,7 @@ - ../assets/Models/Core/UnitCube.obj + ../assets/Models/Core/UnitCube.mesh @@ -169,7 +169,7 @@ - ../assets/Models/Core/UnitCube.obj + ../assets/Models/Core/UnitCube.mesh @@ -187,7 +187,7 @@ - ../assets/Models/Core/UnitCube.obj + ../assets/Models/Core/UnitCube.mesh diff --git a/resources/Schema/Entities/CollidableCube.xml b/resources/Schema/Entities/CollidableCube.xml new file mode 100644 index 00000000..ebba54be --- /dev/null +++ b/resources/Schema/Entities/CollidableCube.xml @@ -0,0 +1,15 @@ + + + + + + + + Models/Core/UnitCube.obj + + + + + + + diff --git a/resources/Schema/Entities/CollisionTest1.xml b/resources/Schema/Entities/CollisionTest1.xml index f0b310e1..e731a17a 100644 --- a/resources/Schema/Entities/CollisionTest1.xml +++ b/resources/Schema/Entities/CollisionTest1.xml @@ -24,7 +24,7 @@ false - Models/Core/UnitCube.obj + Models/Core/UnitCube.mesh diff --git a/resources/Schema/Entities/CollisionTestLevel.xml b/resources/Schema/Entities/CollisionTestLevel.xml index d5e932c2..e58ab6ce 100644 --- a/resources/Schema/Entities/CollisionTestLevel.xml +++ b/resources/Schema/Entities/CollisionTestLevel.xml @@ -6,7 +6,7 @@ - Models/DummyScene.obj + Models/DummyScene.mesh @@ -17,7 +17,7 @@ - Models/Core/UnitSphere.obj + Models/Core/UnitSphere.mesh @@ -28,7 +28,7 @@ - Models/RotationWidgetX.obj + Models/RotationWidgetX.mesh @@ -43,7 +43,7 @@ - Models/Core/UnitCube.obj + Models/Core/UnitCube.mesh @@ -69,7 +69,7 @@ - Models/Core/UnitRaptor.obj + Models/Core/UnitRaptor.mesh @@ -94,7 +94,7 @@ - Models/Core/UnitCube.obj + Models/Core/UnitCube.mesh @@ -107,7 +107,7 @@ - Models/Core/UnitCube.obj + Models/Core/UnitCube.mesh diff --git a/resources/Schema/Entities/EditorTestWorld.xml b/resources/Schema/Entities/EditorTestWorld.xml index 2e95d626..5649a630 100755 --- a/resources/Schema/Entities/EditorTestWorld.xml +++ b/resources/Schema/Entities/EditorTestWorld.xml @@ -9,7 +9,7 @@ - Models/Core/UnitCube.obj + Models/Core/UnitCube.mesh @@ -58,7 +58,7 @@ - Models/DirectionalLightWidget.obj + Models/DirectionalLightWidget.mesh @@ -70,7 +70,7 @@ - Models/Assault.obj + Models/Assault.mesh @@ -94,7 +94,7 @@ - Models/Core/UnitSphere.obj + Models/Core/UnitSphere.mesh diff --git a/resources/Schema/Entities/EditorWidgetRotate.xml b/resources/Schema/Entities/EditorWidgetRotate.xml index b918794e..88452aac 100644 --- a/resources/Schema/Entities/EditorWidgetRotate.xml +++ b/resources/Schema/Entities/EditorWidgetRotate.xml @@ -18,7 +18,7 @@ - Models/RotationWidgetX.obj + Models/RotationWidgetX.mesh @@ -33,7 +33,7 @@ - Models/RotationWidgetY.obj + Models/RotationWidgetY.mesh @@ -48,7 +48,7 @@ - Models/RotationWidgetZ.obj + Models/RotationWidgetZ.mesh diff --git a/resources/Schema/Entities/EditorWidgetScale.xml b/resources/Schema/Entities/EditorWidgetScale.xml index 15bcb38b..786b079e 100644 --- a/resources/Schema/Entities/EditorWidgetScale.xml +++ b/resources/Schema/Entities/EditorWidgetScale.xml @@ -3,7 +3,7 @@ - Models/ScaleWidgetOrigin.obj + Models/ScaleWidgetOrigin.mesh @@ -20,7 +20,7 @@ - Models/ScaleWidgetX.obj + Models/ScaleWidgetX.mesh @@ -34,7 +34,7 @@ - Models/ScaleWidgetY.obj + Models/ScaleWidgetY.mesh @@ -48,7 +48,7 @@ - Models/ScaleWidgetZ.obj + Models/ScaleWidgetZ.mesh diff --git a/resources/Schema/Entities/EditorWidgetTranslate.xml b/resources/Schema/Entities/EditorWidgetTranslate.xml index a9b7eaff..d4ed5e76 100644 --- a/resources/Schema/Entities/EditorWidgetTranslate.xml +++ b/resources/Schema/Entities/EditorWidgetTranslate.xml @@ -3,7 +3,7 @@ - Models/TranslationWidgetOrigin.obj + Models/TranslationWidgetOrigin.mesh @@ -18,7 +18,7 @@ - Models/TranslationWidgetX.obj + Models/TranslationWidgetX.mesh @@ -30,7 +30,7 @@ - Models/TranslationWidgetY.obj + Models/TranslationWidgetY.mesh @@ -42,7 +42,7 @@ - Models/TranslationWidgetZ.obj + Models/TranslationWidgetZ.mesh @@ -54,7 +54,7 @@ - Models/WidgetPlaneX.obj + Models/WidgetPlaneX.mesh @@ -66,7 +66,7 @@ - Models/WidgetPlaneY.obj + Models/WidgetPlaneY.mesh @@ -78,7 +78,7 @@ - Models/WidgetPlaneZ.obj + Models/WidgetPlaneZ.mesh diff --git a/resources/Schema/Entities/Empty.xml b/resources/Schema/Entities/Empty.xml index 6efd8318..c9b8924f 100644 --- a/resources/Schema/Entities/Empty.xml +++ b/resources/Schema/Entities/Empty.xml @@ -5,6 +5,16 @@ - + + + + + + + + + + + diff --git a/resources/Schema/Entities/Model.xml b/resources/Schema/Entities/Model.xml new file mode 100644 index 00000000..57856cbd --- /dev/null +++ b/resources/Schema/Entities/Model.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + models/animTest.mesh + + + + + + + + diff --git a/resources/Schema/Entities/MovementTest.xml b/resources/Schema/Entities/MovementTest.xml index 93b4d374..40de747a 100644 --- a/resources/Schema/Entities/MovementTest.xml +++ b/resources/Schema/Entities/MovementTest.xml @@ -6,66 +6,178 @@ - + - + + + + Models/Core/UnitCube.mesh + + false + + + + + + + + + + + + + Schema/Entities/Player.xml + + + + + + + + + + + + + + + + Models/Assault.mesh + + + + + + + + + + + + + Models/Assault.mesh + + + + + + + + + + + + + + + Models/DirectionalLightWidget.mesh + + + + + + + + + + + + Models/Test/ObstacleCourse.mesh + - + - Models/Core/UnitCube.obj - + Models/Core/UnitCube.mesh + false - - + + - - - - - - - - - - Models/Assault.obj - - - - - - - - - - + - - - - Models/Core/UnitCube.obj - + Models/Core/UnitCube.mesh + false - - - + + + + + + + + Models/Core/UnitCube.mesh + false + + + + + + + + + + + + + Schema/Entities/Player.xml + + + + + + + + + + + + + + + + + Models/Assault.mesh + + + + + + + + + + + + + Models/Assault.mesh + + + + + + + + + + diff --git a/resources/Schema/Entities/OctreeTest.xml b/resources/Schema/Entities/OctreeTest.xml index 4d7fe709..a510a98c 100644 --- a/resources/Schema/Entities/OctreeTest.xml +++ b/resources/Schema/Entities/OctreeTest.xml @@ -11,7 +11,7 @@ - Models/Core/UnitCube.obj + Models/Core/UnitCube.mesh @@ -27,7 +27,7 @@ false - Models/Core/UnitCube.obj + Models/Core/UnitCube.mesh @@ -42,7 +42,7 @@ false - Models/Core/UnitCube.obj + Models/Core/UnitCube.mesh diff --git a/resources/Schema/Entities/Player.xml b/resources/Schema/Entities/Player.xml index 6c3b39c3..4316091b 100644 --- a/resources/Schema/Entities/Player.xml +++ b/resources/Schema/Entities/Player.xml @@ -2,17 +2,120 @@ - - + + + + - - Models/Core/UnitSphere.obj - - - - + + + + + + 5 + + + + + + + + + + - + + + + + + + + + + + + + + Fonts/DroidSans.ttf,100 + + false + + + + + + + + + + + + + Models/Camera.mesh + + + + + + + + + + + + + + + Models/Camera.mesh + false + + + + + + + + + + + + Models/AssaultHeadless.mesh + + + + + + + + + + + Models/Core/UnitCube.mesh + + false + + + + + + + + + + + + Models/Core/UnitCube.mesh + + false + + + + + + + + diff --git a/resources/Schema/Entities/RaptorCopter.xml b/resources/Schema/Entities/RaptorCopter.xml index 0ee62368..82aa0efa 100644 --- a/resources/Schema/Entities/RaptorCopter.xml +++ b/resources/Schema/Entities/RaptorCopter.xml @@ -7,7 +7,7 @@ - Models/Core/UnitRaptor.obj + Models/Core/UnitRaptor.mesh @@ -31,7 +31,7 @@ - Models/Core/UnitCylinder.obj + Models/Core/UnitCylinder.mesh @@ -44,7 +44,7 @@ - Models/Core/UnitCube.obj + Models/Core/UnitCube.mesh @@ -57,7 +57,7 @@ - Models/Core/UnitCube.obj + Models/Core/UnitCube.mesh diff --git a/resources/Schema/Entities/RenderingWorld.xml b/resources/Schema/Entities/RenderingWorld.xml index 73cafdb9..20301d5f 100644 --- a/resources/Schema/Entities/RenderingWorld.xml +++ b/resources/Schema/Entities/RenderingWorld.xml @@ -35,7 +35,7 @@ 80 - Models/Camera.obj + Models/Camera.mesh @@ -58,70 +58,16 @@ - Models/Core/UnitHexagon.obj + Models/Core/UnitHexagon.mesh - + - - - - Models/Core/UnitHexagon.obj - - - - - - - - - - - - Models/SecondaryWeapon.fbx - - - - - - - - - - - - - - - Models/Core/UnitHexagon.obj - - - - - - - - - - - - Models/SecondaryWeapon.fbx - - - - - - - - - - - @@ -165,25 +111,6 @@ - - - - - 0.65990006923675537 - - - - Models/Core/UnitRaptor.obj - - - - - - - - - - @@ -193,7 +120,7 @@ - Models/Core/UnitPlane.obj + Models/Core/UnitPlane.mesh @@ -205,7 +132,7 @@ - Models/Assault.obj + Models/Assault.mesh @@ -234,7 +161,7 @@ - + @@ -381,7 +308,7 @@ - Models/Assault.obj + Models/Assault.mesh @@ -397,7 +324,7 @@ 0.10000000149011612 - Models/DirectionalLightWidget.obj + Models/DirectionalLightWidget.mesh @@ -410,7 +337,7 @@ - Models/Core/UnitCube.obj + Models/Core/UnitCube.mesh diff --git a/resources/Schema/Entities/ShootEventTest.xml b/resources/Schema/Entities/ShootEventTest.xml index eae333b6..9e9adf50 100644 --- a/resources/Schema/Entities/ShootEventTest.xml +++ b/resources/Schema/Entities/ShootEventTest.xml @@ -9,7 +9,7 @@ - ../assets/Models/DummyScene.obj + ../assets/Models/DummyScene.mesh @@ -41,7 +41,7 @@ 3 - ../assets/Models/Core/UnitSphere.obj + ../assets/Models/Core/UnitSphere.mesh @@ -61,7 +61,7 @@ 1 - ../assets/Models/Core/UnitSphere.obj + ../assets/Models/Core/UnitSphere.mesh @@ -79,7 +79,7 @@ 2 - ../assets/Models/Core/UnitSphere.obj + ../assets/Models/Core/UnitSphere.mesh @@ -96,7 +96,7 @@ 3 - ../assets/Models/Core/UnitSphere.obj + ../assets/Models/Core/UnitSphere.mesh @@ -115,7 +115,7 @@ 4 - ../assets/Models/Core/UnitSphere.obj + ../assets/Models/Core/UnitSphere.mesh @@ -133,7 +133,7 @@ - ../assets/Models/Core/UnitCube.obj + ../assets/Models/Core/UnitCube.mesh @@ -151,7 +151,7 @@ - ../assets/Models/Core/UnitCube.obj + ../assets/Models/Core/UnitCube.mesh @@ -171,7 +171,7 @@ - ../assets/Models/Core/UnitCube.obj + ../assets/Models/Core/UnitCube.mesh @@ -191,7 +191,7 @@ - ../assets/Models/Core/UnitCube.obj + ../assets/Models/Core/UnitCube.mesh diff --git a/resources/Schema/Entities/SoundTestLevel.xml b/resources/Schema/Entities/SoundTestLevel.xml index 366ae81b..4e9c3093 100644 --- a/resources/Schema/Entities/SoundTestLevel.xml +++ b/resources/Schema/Entities/SoundTestLevel.xml @@ -12,7 +12,7 @@ - Models/Core/UnitCube.obj + Models/Core/UnitCube.mesh diff --git a/resources/Schema/Entities/SpawnTest.xml b/resources/Schema/Entities/SpawnTest.xml index a5574027..16608b47 100644 --- a/resources/Schema/Entities/SpawnTest.xml +++ b/resources/Schema/Entities/SpawnTest.xml @@ -24,7 +24,7 @@ - Models/Core/UnitSphere.obj + Models/Core/UnitSphere.mesh @@ -37,7 +37,7 @@ - Models/Core/UnitSphere.obj + Models/Core/UnitSphere.mesh diff --git a/resources/Schema/Entities/Test.xml b/resources/Schema/Entities/Test.xml index 42e2660e..1f8da1a3 100644 --- a/resources/Schema/Entities/Test.xml +++ b/resources/Schema/Entities/Test.xml @@ -6,7 +6,7 @@ - Models/DummyScene.obj + Models/DummyScene.mesh @@ -19,7 +19,7 @@ - Models/Camera.obj + Models/Camera.mesh diff --git a/resources/Schema/Types.xsd b/resources/Schema/Types.xsd index fb584c64..8d9bf289 100644 --- a/resources/Schema/Types.xsd +++ b/resources/Schema/Types.xsd @@ -16,6 +16,9 @@ + + + diff --git a/resources/Shaders/BasicForward.vert.glsl b/resources/Shaders/BasicForward.vert.glsl index 96f081f4..cb231e45 100644 --- a/resources/Shaders/BasicForward.vert.glsl +++ b/resources/Shaders/BasicForward.vert.glsl @@ -9,18 +9,14 @@ layout(location = 1) in vec3 Normal; layout(location = 2) in vec3 Tangent; layout(location = 3) in vec3 BiTangent; layout(location = 4) in vec2 TextureCoords; -layout(location = 5) in vec4 DiffuseVertexColor; -layout(location = 6) in vec4 SpecularVertexColor; -layout(location = 7) in vec4 BoneIndices1; -layout(location = 8) in vec4 BoneIndices2; -layout(location = 9) in vec4 BoneWeights1; -layout(location = 10) in vec4 BoneWeights2; +layout(location = 5) in vec4 BoneIndices; +layout(location = 6) in vec4 BoneWeights; + out VertexData{ vec3 Position; vec3 Normal; vec2 TextureCoordinate; - vec4 DiffuseColor; }Output; void main() @@ -30,5 +26,4 @@ void main() Output.Position = Position; Output.TextureCoordinate = TextureCoords; Output.Normal = Normal; - Output.DiffuseColor = DiffuseVertexColor; } \ No newline at end of file diff --git a/resources/Shaders/ForwardPlus.frag.glsl b/resources/Shaders/ForwardPlus.frag.glsl index c08e4d0c..f33d870b 100644 --- a/resources/Shaders/ForwardPlus.frag.glsl +++ b/resources/Shaders/ForwardPlus.frag.glsl @@ -4,6 +4,7 @@ uniform mat4 M; uniform mat4 V; uniform mat4 P; uniform vec4 Color; +uniform vec4 DiffuseColor; uniform vec2 ScreenDimensions; uniform vec4 FillColor; uniform float FillPercentage; @@ -49,7 +50,6 @@ in VertexData{ vec3 Position; vec3 Normal; vec2 TextureCoordinate; - vec4 DiffuseColor; }Input; out vec4 sceneColor; @@ -138,7 +138,7 @@ void main() } //sceneColor += Input.DiffuseColor; - vec4 color_result = Input.DiffuseColor * (totalLighting.Diffuse + totalLighting.Specular) * diffuseTexel * Color; + vec4 color_result = DiffuseColor * (totalLighting.Diffuse + totalLighting.Specular) * diffuseTexel * Color; float pos = ((P * vec4(Input.Position, 1)).y + 1.0)/2.0; diff --git a/resources/Shaders/ForwardPlus.vert.glsl b/resources/Shaders/ForwardPlus.vert.glsl index d3b8ba16..c51216cb 100644 --- a/resources/Shaders/ForwardPlus.vert.glsl +++ b/resources/Shaders/ForwardPlus.vert.glsl @@ -3,32 +3,37 @@ uniform mat4 M; uniform mat4 V; uniform mat4 P; +uniform mat4 Bones[100]; layout(location = 0) in vec3 Position; layout(location = 1) in vec3 Normal; layout(location = 2) in vec3 Tangent; layout(location = 3) in vec3 BiTangent; layout(location = 4) in vec2 TextureCoords; -layout(location = 5) in vec4 DiffuseVertexColor; -layout(location = 6) in vec4 SpecularVertexColor; -layout(location = 7) in vec4 BoneIndices1; -layout(location = 8) in vec4 BoneIndices2; -layout(location = 9) in vec4 BoneWeights1; -layout(location = 10) in vec4 BoneWeights2; +layout(location = 5) in vec4 BoneIndices; +layout(location = 6) in vec4 BoneWeights; out VertexData{ vec3 Position; vec3 Normal; vec2 TextureCoordinate; - vec4 DiffuseColor; }Output; void main() { - gl_Position = P*V*M * vec4(Position, 1.0); - Output.Position = Position; + + mat4 boneTransform = mat4(1); + if(BoneWeights[0] > 0.0f){ + boneTransform = BoneWeights[0] * Bones[int(BoneIndices[0])] + + BoneWeights[1] * Bones[int(BoneIndices[1])] + + BoneWeights[2] * Bones[int(BoneIndices[2])] + + BoneWeights[3] * Bones[int(BoneIndices[3])]; + } + + gl_Position = P*V*M*boneTransform * vec4(Position, 1.0); + + Output.Position = (boneTransform * vec4(Position, 1.0)).xyz; Output.TextureCoordinate = TextureCoords; Output.Normal = vec3(M * vec4(Normal, 0.0)); - Output.DiffuseColor = DiffuseVertexColor; } \ No newline at end of file diff --git a/src/Engine/Collision/CollisionSystem.cpp b/src/Engine/Collision/CollisionSystem.cpp index 0c77c306..ba841e36 100644 --- a/src/Engine/Collision/CollisionSystem.cpp +++ b/src/Engine/Collision/CollisionSystem.cpp @@ -31,7 +31,7 @@ void CollisionSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& c } if (Collision::AABBVsAABB(boxA, boxB, resolutionVector)) { (glm::vec3&)cTransform["Position"] += resolutionVector; - cPhysics["Velocity"] = glm::vec3(0, 0, 0); + ((glm::vec3&)cPhysics["Velocity"]).y = 0.f; } } diff --git a/src/Engine/Core/EntityWrapper.cpp b/src/Engine/Core/EntityWrapper.cpp index 98b9c7d4..55d341e1 100644 --- a/src/Engine/Core/EntityWrapper.cpp +++ b/src/Engine/Core/EntityWrapper.cpp @@ -5,6 +5,9 @@ const EntityWrapper EntityWrapper::Invalid = EntityWrapper(nullptr, EntityID_Inv bool EntityWrapper::HasComponent(const std::string& componentName) { + if (!Valid()) { + return false; + } return World->HasComponent(ID, componentName); } @@ -17,6 +20,34 @@ EntityWrapper EntityWrapper::Parent() } } +EntityWrapper EntityWrapper::FirstChildByName(const std::string& name) +{ + auto itPair = this->World->GetChildren(this->ID); + if (itPair.first == itPair.second) { + return EntityWrapper::Invalid; + } + + for (auto it = itPair.first; it != itPair.second; ++it) { + if (this->World->GetName(it->second) == name) { + return EntityWrapper(this->World, it->second); + } + } + + return EntityWrapper::Invalid; +} + +bool EntityWrapper::IsChildOf(EntityWrapper potentialParent) +{ + EntityWrapper entity = *this; + while (entity.Parent().Valid()) { + entity = entity.Parent(); + if (entity == potentialParent) { + return true; + } + } + return false; +} + bool EntityWrapper::Valid() { if (this->World == nullptr) { diff --git a/src/Engine/Core/Octree.cpp b/src/Engine/Core/Octree.cpp index d7feba45..18effea5 100644 --- a/src/Engine/Core/Octree.cpp +++ b/src/Engine/Core/Octree.cpp @@ -276,7 +276,7 @@ std::vector Child::childIndicesContainingBox(const AABB& box) const } } -inline bool Child::hasChildren() const +bool Child::hasChildren() const { return m_Children[0] != nullptr; } diff --git a/src/Engine/Core/Transform.cpp b/src/Engine/Core/Transform.cpp index cbc405a3..c9869014 100644 --- a/src/Engine/Core/Transform.cpp +++ b/src/Engine/Core/Transform.cpp @@ -1,5 +1,10 @@ #include "Core/Transform.h" +glm::vec3 Transform::AbsolutePosition(EntityWrapper entity) +{ + return AbsolutePosition(entity.World, entity.ID); +} + glm::vec3 Transform::AbsolutePosition(World* world, EntityID entity) { glm::vec3 position; @@ -14,6 +19,11 @@ glm::vec3 Transform::AbsolutePosition(World* world, EntityID entity) return position; } +glm::quat Transform::AbsoluteOrientation(EntityWrapper entity) +{ + return AbsoluteOrientation(entity.World, entity.ID); +} + glm::quat Transform::AbsoluteOrientation(World* world, EntityID entity) { glm::quat orientation; @@ -27,6 +37,11 @@ glm::quat Transform::AbsoluteOrientation(World* world, EntityID entity) return orientation; } +glm::vec3 Transform::AbsoluteScale(EntityWrapper entity) +{ + return AbsoluteScale(entity.World, entity.ID); +} + glm::vec3 Transform::AbsoluteScale(World* world, EntityID entity) { glm::vec3 scale(1.f); @@ -40,6 +55,11 @@ glm::vec3 Transform::AbsoluteScale(World* world, EntityID entity) return scale; } +glm::mat4 Transform::ModelMatrix(EntityWrapper entity) +{ + return ModelMatrix(entity.ID, entity.World); +} + glm::mat4 Transform::ModelMatrix(EntityID entity, World* world) { glm::vec3 position = Transform::AbsolutePosition(world, entity); diff --git a/src/Engine/Editor/EditorRenderSystem.cpp b/src/Engine/Editor/EditorRenderSystem.cpp index 9e9b5206..2aad1340 100644 --- a/src/Engine/Editor/EditorRenderSystem.cpp +++ b/src/Engine/Editor/EditorRenderSystem.cpp @@ -39,7 +39,7 @@ void EditorRenderSystem::Update(double dt) continue; } catch (const std::exception&) { try { - model = ResourceManager::Load<::Model>("Models/Core/Error.obj"); + model = ResourceManager::Load<::Model>("Models/Core/Error.mesh"); } catch (const std::exception&) { continue; } diff --git a/src/Engine/Editor/EditorSystem.cpp b/src/Engine/Editor/EditorSystem.cpp index 35b8a361..9c0e2e47 100644 --- a/src/Engine/Editor/EditorSystem.cpp +++ b/src/Engine/Editor/EditorSystem.cpp @@ -14,10 +14,11 @@ EditorSystem::EditorSystem(World* world, EventBroker* eventBroker, IRenderer* re m_EditorWorldSystemPipeline->AddSystem(0, m_Renderer); m_EditorWorldSystemPipeline->AddSystem(1, m_Renderer, m_RenderFrame); - m_Camera = importEntity(EntityWrapper(m_EditorWorld, EntityID_Invalid), "Schema/Entities/Empty.xml"); - m_EditorWorld->AttachComponent(m_Camera.ID, "Transform"); - m_EditorWorld->AttachComponent(m_Camera.ID, "Camera"); - m_DebugCameraInputController = new DebugCameraInputController(m_EventBroker, -1); + m_EditorCamera = importEntity(EntityWrapper(m_EditorWorld, EntityID_Invalid), "Schema/Entities/Empty.xml"); + m_ActualCamera = m_EditorCamera; + m_EditorWorld->AttachComponent(m_EditorCamera.ID, "Transform"); + m_EditorWorld->AttachComponent(m_EditorCamera.ID, "Camera"); + m_EditorCameraInputController = new EditorCameraInputController(m_EventBroker, -1); m_EditorGUI = new EditorGUI(m_World, m_EventBroker); m_EditorGUI->SetEntitySelectedCallback(std::bind(&EditorSystem::OnEntitySelected, this, std::placeholders::_1)); @@ -33,38 +34,70 @@ EditorSystem::EditorSystem(World* world, EventBroker* eventBroker, IRenderer* re EVENT_SUBSCRIBE_MEMBER(m_EMousePress, &EditorSystem::OnMousePress); EVENT_SUBSCRIBE_MEMBER(m_EWidgetDelta, &EditorSystem::OnWidgetDelta); + EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &EditorSystem::OnInputCommand); + EVENT_SUBSCRIBE_MEMBER(m_ESetCamera, &EditorSystem::OnSetCamera); m_EditorStats = new EditorStats(); - Events::SetCamera e; - e.CameraEntity = m_Camera; - m_EventBroker->Publish(e); + if (m_Enabled) { + Enable(); + } } EditorSystem::~EditorSystem() { delete m_EditorStats; delete m_EditorGUI; - delete m_DebugCameraInputController; + delete m_EditorCameraInputController; delete m_EditorWorldSystemPipeline; delete m_EditorWorld; } void EditorSystem::Update(double dt) { - m_EventBroker->Process(); - m_EditorGUI->Draw(); - m_EditorStats->Draw(dt); + double now = glfwGetTime(); + double actualDelta = now - m_LastTime; + m_LastTime = now; - if (m_CurrentSelection.Valid() && m_Widget.Valid()) { - (glm::vec3&)m_Widget["Transform"]["Position"] = Transform::AbsolutePosition(m_CurrentSelection.World, m_CurrentSelection.ID); + if (m_Enabled) { + m_EventBroker->Process(); + m_EditorGUI->Draw(); + m_EditorStats->Draw(actualDelta); + + if (m_CurrentSelection.Valid() && m_Widget.Valid()) { + (glm::vec3&)m_Widget["Transform"]["Position"] = Transform::AbsolutePosition(m_CurrentSelection.World, m_CurrentSelection.ID); + } + + m_EditorWorldSystemPipeline->Update(actualDelta); + + ComponentWrapper& cameraTransform = m_EditorCamera["Transform"]; + glm::vec3& ori = cameraTransform["Orientation"]; + ori.x = m_EditorCameraInputController->Rotation().x; + ori.y = m_EditorCameraInputController->Rotation().y; + glm::vec3& pos = cameraTransform["Position"]; + pos += m_EditorCameraInputController->Movement() * glm::inverse(glm::quat(ori)) * (float)actualDelta; } +} - m_EditorWorldSystemPipeline->Update(dt); +void EditorSystem::Enable() +{ + m_EditorCameraInputController->Enable(); + m_EventBroker->Publish(Events::UnlockMouse()); + Events::SetCamera e; + e.CameraEntity = m_EditorCamera; + m_EventBroker->Publish(e); + (glm::vec3&)m_EditorCamera["Transform"]["Position"] = Transform::AbsolutePosition(m_ActualCamera); + m_Enabled = true; +} - m_DebugCameraInputController->Update(dt); - m_Camera["Transform"]["Position"] = m_DebugCameraInputController->Position(); - m_Camera["Transform"]["Orientation"] = glm::eulerAngles(m_DebugCameraInputController->Orientation()); +void EditorSystem::Disable() +{ + m_EditorCameraInputController->Disable(); + m_EventBroker->Publish(Events::LockMouse()); + Events::SetCamera e; + e.CameraEntity = m_ActualCamera; + m_EventBroker->Publish(e); + m_Enabled = false; } void EditorSystem::OnEntitySelected(EntityWrapper entity) @@ -148,6 +181,33 @@ bool EditorSystem::OnWidgetDelta(const Events::WidgetDelta& e) return true; } +bool EditorSystem::OnInputCommand(const Events::InputCommand& e) +{ + if (e.PlayerID != -1) { + return false; + } + + if (e.Command == "ToggleEditor" && e.Value > 0) { + if (m_Enabled) { + Disable(); + } else { + Enable(); + } + } + return true; +} + +bool EditorSystem::OnSetCamera(const Events::SetCamera& e) +{ + if (m_Enabled && e.CameraEntity != m_EditorCamera) { + m_ActualCamera = e.CameraEntity; + Events::SetCamera e2; + e2.CameraEntity = m_EditorCamera; + m_EventBroker->Publish(e2); + } + return true; +} + EntityWrapper EditorSystem::importEntity(EntityWrapper parent, boost::filesystem::path filePath) { if (parent.World == nullptr) { diff --git a/src/Engine/Network/Client.cpp b/src/Engine/Network/Client.cpp index 10432bba..49964128 100644 --- a/src/Engine/Network/Client.cpp +++ b/src/Engine/Network/Client.cpp @@ -5,14 +5,20 @@ using namespace boost::asio::ip; Client::Client(ConfigFile* config) : m_Socket(m_IOService) { + Network::initialize(); + // Asumes root node is EntityID 0 insertIntoServerClientMaps(0, 0); + // Init timer + m_TimeSinceSentInputs = std::clock(); // Default is local host std::string address = config->Get("Networking.Address", "127.0.0.1"); int port = config->Get("Networking.Port", 13); m_ReceiverEndpoint = udp::endpoint(boost::asio::ip::address::from_string(address), port); // Set up network stream m_PlayerName = config->Get("Networking.Name", "Raptorcopter"); + m_SendInputIntervalMs = config->Get("Networking.SendInputIntervalMs", 33); + } Client::~Client() @@ -37,19 +43,24 @@ void Client::Update() readFromServer(); if (m_IsConnected) { hasServerTimedOut(); + // Don't sent 1 input in 1 packet, bunch em up. + if (m_SendInputIntervalMs < (1000 * (std::clock() - m_TimeSinceSentInputs) / (double)CLOCKS_PER_SEC)) { + sendInputCommands(); + m_TimeSinceSentInputs = std::clock(); + } } + Network::Update(); } void Client::readFromServer() { while (m_Socket.available()) { - bytesRead = receive(readBuf, INPUTSIZE); + bytesRead = receive(readBuf); if (bytesRead > 0) { Packet packet(readBuf, bytesRead); parseMessageType(packet); } } - sendInputCommands(); } void Client::parseMessageType(Packet& packet) @@ -66,12 +77,9 @@ void Client::parseMessageType(Packet& packet) case MessageType::Connect: parseConnect(packet); break; - case MessageType::ClientPing: + case MessageType::Ping: parsePing(); break; - case MessageType::ServerPing: - parseServerPing(); - break; case MessageType::Message: break; case MessageType::Snapshot: @@ -81,6 +89,13 @@ void Client::parseMessageType(Packet& packet) break; case MessageType::PlayerConnected: parsePlayerConnected(packet); + break; + case MessageType::Kick: + parseKick(); + break; + case MessageType::OnPlayerSpawned: + parsePlayersSpawned(packet); + break; default: break; } @@ -99,11 +114,6 @@ void Client::parsePlayerConnected(Packet & packet) } void Client::parsePing() -{ - -} - -void Client::parseServerPing() { // Might miss connect message so set it here instead. m_IsConnected = true; @@ -112,11 +122,26 @@ void Client::parseServerPing() LOG_INFO("%i: response time with ctime(ms): %f", m_PacketID, m_DurationOfPingTime); m_StartPingTime = std::clock(); - Packet packet(MessageType::ServerPing, m_SendPacketID); + Packet packet(MessageType::Ping, m_SendPacketID); packet.WriteString("Ping recieved"); send(packet); } +void Client::parseKick() +{ + LOG_WARNING("You have been kicked from the server."); + m_IsConnected = false; +} + +void Client::parsePlayersSpawned(Packet& packet) +{ + Events::PlayerSpawned e; + e.Player = EntityWrapper(m_World, m_ServerIDToClientID[packet.ReadPrimitive()]); + e.Spawner = EntityWrapper(m_World, m_ServerIDToClientID[packet.ReadPrimitive()]); + e.PlayerID = -1; + m_EventBroker->Publish(e); +} + // Fields with strings will not work right now void Client::InterpolateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID, const std::string& componentType) { @@ -153,8 +178,12 @@ void Client::parseSnapshot(Packet& packet) { std::string componentType = packet.ReadString(); while (packet.DataReadSize() < packet.Size()) { + // HACK + std::string entityName = packet.ReadString(); // Components EntityID EntityID receivedEntityID = packet.ReadPrimitive(); + // HACK + m_World->SetName(receivedEntityID, entityName); // Parents EntityID EntityID receivedParentEntityID = packet.ReadPrimitive(); ComponentInfo componentInfo = m_World->GetComponents(componentType)->ComponentInfo(); @@ -211,15 +240,20 @@ void Client::parseSnapshot(Packet& packet) } } -int Client::receive(char* data, size_t length) +int Client::receive(char* data) { boost::system::error_code error; int bytesReceived = m_Socket.receive_from(boost - ::asio::buffer((void*)data, length), + ::asio::buffer((void*)data, INPUTSIZE), m_ReceiverEndpoint, 0, error); - + // Network Debug data + if (isReadingData) { + m_NetworkData.TotalDataReceived += bytesReceived; + m_NetworkData.DataReceivedThisInterval += bytesReceived; + m_NetworkData.AmountOfMessagesReceived++; + } if (error) { //LOG_ERROR("receive: %s", error.message().c_str()); } @@ -232,6 +266,12 @@ void Client::send(Packet& packet) packet.Data(), packet.Size()), m_ReceiverEndpoint, 0); + // Network Debug data + if (isReadingData) { + m_NetworkData.TotalDataSent += packet.Size(); + m_NetworkData.DataSentThisInterval += packet.Size(); + m_NetworkData.AmountOfMessagesSent++; + } } void Client::connect() @@ -250,14 +290,6 @@ void Client::disconnect() send(packet); } -void Client::ping() -{ - //Packet packet(MessageType::Connect, m_SendPacketID); - //packet.WriteString("Ping"); - //m_StartPingTime = std::clock(); - //send(packet); -} - bool Client::OnInputCommand(const Events::InputCommand & e) { if (e.Command == "ConnectToServer") { // Connect for now @@ -275,6 +307,15 @@ bool Client::OnInputCommand(const Events::InputCommand & e) if (e.Value > 0) { becomePlayer(); } + } else if (e.Command == "LogNetworkBandwidth") { + if (e.Value > 0) { + // Save to file if we no longer want to read data. + if (isReadingData) { + saveToFile(); + } + isReadingData = !isReadingData; + m_SaveDataTimer = std::clock(); + } } else { m_InputCommandBuffer.push_back(e); //LOG_DEBUG("Client::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID); @@ -305,7 +346,7 @@ bool Client::hasServerTimedOut() { // Time in ms float timeSincePing = 1000 * (std::clock() - m_StartPingTime) / static_cast(CLOCKS_PER_SEC); - if (timeSincePing > TIMEOUTMS) { + if (timeSincePing > m_TimeoutMs) { // Clear everything and go to menu. LOG_INFO("Server has timed out, returning to menu, Beep Boop."); m_IsConnected = false; @@ -319,7 +360,7 @@ EntityID Client::createPlayer() EntityID entityID = m_World->CreateEntity(); ComponentWrapper transform = m_World->AttachComponent(entityID, "Transform"); ComponentWrapper model = m_World->AttachComponent(entityID, "Model"); - model["Resource"] = "Models/Core/UnitSphere.obj"; + model["Resource"] = "Models/Core/UnitSphere.mesh"; ComponentWrapper player = m_World->AttachComponent(entityID, "Player"); return entityID; } diff --git a/src/Engine/Network/Network.cpp b/src/Engine/Network/Network.cpp new file mode 100644 index 00000000..f4dcd1a2 --- /dev/null +++ b/src/Engine/Network/Network.cpp @@ -0,0 +1,68 @@ +#include "Network/Network.h" + +void Network::Update() +{ + updateNetworkData(); +} + +void Network::saveToFile() +{ + std::ofstream outfile; + time_t t = time(0); + // get time now + struct tm * now = localtime(&t); + // Get current time and date + std::string dateAndTime = "BandwidthData - " + std::to_string(now->tm_year + 1900) + '-' + + std::to_string(now->tm_mon + 1) + '-' + + std::to_string(now->tm_mday) + '_' + + std::to_string(now->tm_hour) + "h." + + std::to_string(now->tm_min) + "m." + + std::to_string(now->tm_sec) + 's'; + + outfile.open(dateAndTime + ".csv"); + outfile << "Total time," + std::to_string(m_NetworkData.TotalTime) + "\n"; + outfile << "Total data received," + std::to_string(m_NetworkData.TotalDataReceived) + "\n"; + outfile << "Total data sent," + std::to_string(m_NetworkData.TotalDataSent) + "\n"; + outfile << "Total messages received," + std::to_string(m_NetworkData.AmountOfMessagesReceived) + "\n"; + outfile << "Total messages sent," + std::to_string(m_NetworkData.AmountOfMessagesSent) + "\n"; + + float messagesReceivedPerSec = (float)m_NetworkData.AmountOfMessagesReceived / (m_NetworkData.TotalTime / 1000); + float messagesSentPerSec = (float)m_NetworkData.AmountOfMessagesSent / (m_NetworkData.TotalTime / 1000); + float dataReceivedPerSec = (float)m_NetworkData.TotalDataReceived / (m_NetworkData.TotalTime / 1000); + float dataSentPerSec = (float)m_NetworkData.TotalDataSent / (m_NetworkData.TotalTime / 1000); + outfile << "Avarage messages received / s: " + std::to_string(messagesReceivedPerSec) + "\n"; + outfile << "Avarage messages sents / s: " + std::to_string(messagesSentPerSec) + "\n"; + outfile << "Avarage data received B/s: " + std::to_string(dataReceivedPerSec) + "\n"; + outfile << "Avarage data sents B/s: " + std::to_string(dataSentPerSec) + "\n"; + + outfile << "time, avg receive B, avg send B\n"; + for (int i = 0; i < m_NetworkData.BandwidthBytes.size(); i++) { + outfile << std::to_string(i) + ","; + outfile << std::to_string(m_NetworkData.BandwidthBytes[i].first) + ","; + outfile << std::to_string(m_NetworkData.BandwidthBytes[i].second) + "\n"; + } + outfile.close(); + +} + +void Network::updateNetworkData() +{ + std::clock_t currentTime = std::clock(); + // Send snapshot + if (m_SaveDataIntervalMs < (1000 * (currentTime - m_SaveDataTimer) / (double)CLOCKS_PER_SEC)) { + // Set values + m_NetworkData.TotalTime += (1000 * (currentTime - m_SaveDataTimer) / (double)CLOCKS_PER_SEC); + m_NetworkData.BandwidthBytes.push_back(std::pair(m_NetworkData.DataReceivedThisInterval, m_NetworkData.DataSentThisInterval)); + // Reset interval stuff + m_SaveDataTimer = std::clock(); + m_NetworkData.DataSentThisInterval = 0; + m_NetworkData.DataReceivedThisInterval = 0; + } +} + +void Network::initialize() +{ + ConfigFile* config = ResourceManager::Load("Config.ini"); + m_MaxConnections = config->Get("Networking.MaxConnections", 8); + m_TimeoutMs = config->Get("Networking.TimeoutMs", 20000); +} diff --git a/src/Engine/Network/Packet.cpp b/src/Engine/Network/Packet.cpp index 6308a130..d40a1b32 100644 --- a/src/Engine/Network/Packet.cpp +++ b/src/Engine/Network/Packet.cpp @@ -39,6 +39,7 @@ void Packet::Init(MessageType type, unsigned int & packetID) Packet::WritePrimitive(messageType); Packet::WritePrimitive(packetID); packetID++; + m_HeaderSize = m_Offset; } void Packet::WriteString(const std::string& str) diff --git a/src/Engine/Network/Server.cpp b/src/Engine/Network/Server.cpp index f4373a83..3ab3dd5f 100644 --- a/src/Engine/Network/Server.cpp +++ b/src/Engine/Network/Server.cpp @@ -1,7 +1,13 @@ #include "Network/Server.h" -Server::Server() : m_Socket(m_IOService, boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 13)) -{ } +Server::Server() : m_Socket(m_IOService, boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 27666)) +{ + Network::initialize(); + ConfigFile* config = ResourceManager::Load("Config.ini"); + snapshotInterval = 1000 * config->Get("Networking.SnapshotInterval", 0.05); + pingIntervalMs = config->Get("Networking.PingIntervalMs", 1000); + +} Server::~Server() { @@ -14,7 +20,8 @@ void Server::Start(World* world, EventBroker* eventBroker) m_EventBroker = eventBroker; // Subscribe to events EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &Server::OnInputCommand); - for (size_t i = 0; i < MAXCONNECTIONS; i++) { + EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &Server::OnPlayerSpawned); + for (size_t i = 0; i < m_MaxConnections; i++) { m_PlayerDefinitions[i].StopTime = std::clock(); } LOG_INFO("I am Server. BIP BOP\n"); @@ -24,14 +31,17 @@ void Server::Update() { readFromClients(); m_EventBroker->Process(); -} + if (isReadingData) { + Network::Update(); + } +} void Server::readFromClients() { while (m_Socket.available()) { try { - bytesRead = receive(readBuffer, INPUTSIZE); + bytesRead = receive(readBuffer); Packet packet(readBuffer, bytesRead); parseMessageType(packet); } catch (const std::exception& err) { @@ -46,7 +56,7 @@ void Server::readFromClients() } // Send pings each - if (intervalMs < (1000 * (currentTime - previousePingMessage) / (double)CLOCKS_PER_SEC)) { + if (pingIntervalMs < (1000 * (currentTime - previousePingMessage) / (double)CLOCKS_PER_SEC)) { sendPing(); previousePingMessage = currentTime; } @@ -70,11 +80,8 @@ void Server::parseMessageType(Packet& packet) case MessageType::Connect: parseConnect(packet); break; - case MessageType::ClientPing: - //parseClientPing(); - break; - case MessageType::ServerPing: - parseServerPing(); + case MessageType::Ping: + parsePing(); break; case MessageType::Message: break; @@ -97,21 +104,47 @@ void Server::parseMessageType(Packet& packet) } } -int Server::receive(char * data, size_t length) +int Server::receive(char * data) { - length = m_Socket.receive_from( + unsigned int length = m_Socket.receive_from( boost::asio::buffer((void*)data - , length) + , INPUTSIZE) , m_ReceiverEndpoint, 0); + // Network Debug data + if (isReadingData) { + m_NetworkData.TotalDataReceived += length; + m_NetworkData.DataReceivedThisInterval += length; + m_NetworkData.AmountOfMessagesReceived++; + } return length; } -void Server::send(Packet& packet, int userID) +void Server::send(Packet& packet, UserID user) { int bytesSent = m_Socket.send_to( boost::asio::buffer(packet.Data(), packet.Size()), - m_ConnectedUsers[userID].Endpoint, + m_ConnectedUsers[user].Endpoint, 0); + // Network Debug data + if (isReadingData) { + m_NetworkData.TotalDataSent += packet.Size(); + m_NetworkData.DataSentThisInterval += packet.Size(); + m_NetworkData.AmountOfMessagesSent++; + } +} + +void Server::send(PlayerID player, Packet& packet) +{ + int bytesSent = m_Socket.send_to( + boost::asio::buffer(packet.Data(), packet.Size()), + m_PlayerDefinitions[player].Endpoint, + 0); + // Network Debug data + if (isReadingData) { + m_NetworkData.TotalDataSent += packet.Size(); + m_NetworkData.DataSentThisInterval += packet.Size(); + m_NetworkData.AmountOfMessagesSent++; + } } void Server::send(Packet & packet) @@ -122,6 +155,11 @@ void Server::send(Packet & packet) packet.Size()), m_ReceiverEndpoint, 0); + if (isReadingData) { + // Network Debug data + m_NetworkData.TotalDataSent += packet.Size(); + m_NetworkData.DataSentThisInterval += packet.Size(); + } } void Server::broadcast(Packet& packet) @@ -143,9 +181,12 @@ void Server::sendSnapshot() Packet packet(MessageType::Snapshot); ComponentPool* componentPool = it.second; ComponentInfo componentInfo = componentPool->ComponentInfo(); + // Component Type packet.WriteString(componentInfo.Name); for (auto& componentWrapper : *componentPool) { + // HACK: Send entity name + packet.WriteString(m_World->GetName(componentWrapper.EntityID)); // Components EntityID packet.WritePrimitive(componentWrapper.EntityID); // Parents EntityID @@ -160,7 +201,9 @@ void Server::sendSnapshot() } } } - broadcast(packet); + if (packet.Size() > packet.HeaderSize() + componentInfo.Name.size()) { + broadcast(packet); + } } } @@ -174,7 +217,7 @@ void Server::sendPing() } } // Create ping message - Packet packet(MessageType::ServerPing); + Packet packet(MessageType::Ping); packet.WriteString("Ping from server"); // Time message m_StartPingTime = std::clock(); @@ -191,7 +234,7 @@ void Server::checkForTimeOuts() if (m_ConnectedUsers[i].Endpoint.address() != boost::asio::ip::address()) { int stopPing = 1000 * m_ConnectedUsers[i].StopTime / static_cast(CLOCKS_PER_SEC); - if (startPing > stopPing + TIMEOUTMS) { + if (startPing > stopPing + m_TimeoutMs) { LOG_INFO("User %i timed out!", i); disconnect(i); } @@ -199,35 +242,40 @@ void Server::checkForTimeOuts() } } -void Server::disconnect(int i) +void Server::disconnect(UserID user) { //broadcast("A player disconnected"); - LOG_INFO("User %s disconnected/timed out", m_PlayerDefinitions[i].Name.c_str()); + LOG_INFO("User %s disconnected/timed out", m_PlayerDefinitions[user].Name.c_str()); // Remove enteties and stuff (When we can remove entity, remove it and tell clients to remove the copy they have) - m_PlayerDefinitions[i].Endpoint = boost::asio::ip::udp::endpoint(); - m_PlayerDefinitions[i].EntityID = -1; - m_PlayerDefinitions[i].Name = ""; - m_PlayerDefinitions[i].PacketID = 0; - m_ConnectedUsers.erase(m_ConnectedUsers.begin() + i); + Events::PlayerDisconnected e; + e.Entity = m_PlayerDefinitions[user].EntityID; + e.PlayerID = user; + m_EventBroker->Publish(e); + + m_PlayerDefinitions[user].Endpoint = boost::asio::ip::udp::endpoint(); + m_PlayerDefinitions[user].EntityID = -1; + m_PlayerDefinitions[user].Name = ""; + m_PlayerDefinitions[user].PacketID = 0; + m_ConnectedUsers.erase(m_ConnectedUsers.begin() + user); } void Server::parseOnInputCommand(Packet& packet) { - int playerID = -1; + PlayerID player = -1; // Check which player it was who sent the message - for (int i = 0; i < MAXCONNECTIONS; i++) { + for (int i = 0; i < m_MaxConnections; i++) { // if the player is connected set playerID to the correct PlayerID if (m_PlayerDefinitions[i].Endpoint.address() == m_ReceiverEndpoint.address() && m_PlayerDefinitions[i].Endpoint.port() == m_ReceiverEndpoint.port()) { - playerID = i; + player = i; break; } } - if (playerID != -1) { + if (player != -1) { while (packet.DataReadSize() < packet.Size()) { Events::InputCommand e; e.Command = packet.ReadString(); - e.PlayerID = playerID; // Set correct player id + e.PlayerID = player; // Set correct player id e.Value = packet.ReadPrimitive(); m_EventBroker->Publish(e); //LOG_INFO("Server::parseOnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID); @@ -292,17 +340,17 @@ void Server::parseDisconnect() void Server::parseClientPing() { LOG_INFO("%i: Parsing ping", m_PacketID); - int playerID = GetPlayerIDFromEndpoint(m_ReceiverEndpoint); - if (playerID == -1) { + PlayerID player = GetPlayerIDFromEndpoint(m_ReceiverEndpoint); + if (player == -1) { return; } // Return ping - Packet packet(MessageType::ClientPing, m_PlayerDefinitions[playerID].PacketID); + Packet packet(MessageType::Ping, m_PlayerDefinitions[player].PacketID); packet.WriteString("Ping received"); send(packet); } -void Server::parseServerPing() +void Server::parsePing() { for (int i = 0; i < m_ConnectedUsers.size(); i++) { if (m_ConnectedUsers[i].Endpoint.address() == m_ReceiverEndpoint.address()) { @@ -328,7 +376,7 @@ void Server::createPlayer() LOG_WARNING("Already connected!"); return; } - int userIndex; + UserID userIndex; for (userIndex = 0; userIndex < m_ConnectedUsers.size(); userIndex++) { if (m_ConnectedUsers[userIndex].Endpoint.address() == m_ReceiverEndpoint.address() && m_ConnectedUsers[userIndex].Endpoint.port() == m_ReceiverEndpoint.port()) { @@ -340,14 +388,14 @@ void Server::createPlayer() LOG_WARNING("Not a recognized user!"); return; } - for (int playerIndex = 0; playerIndex < MAXCONNECTIONS; playerIndex++) { + for (PlayerID playerIndex = 0; playerIndex < m_MaxConnections; playerIndex++) { if (m_PlayerDefinitions[playerIndex].Endpoint.address() == boost::asio::ip::address()) { m_PlayerDefinitions[playerIndex] = m_ConnectedUsers[userIndex]; EntityID entityID = m_World->CreateEntity(); ComponentWrapper transform = m_World->AttachComponent(entityID, "Transform"); transform["Position"] = glm::vec3(-1.5f, 0.f, 0.f); ComponentWrapper model = m_World->AttachComponent(entityID, "Model"); - model["Resource"] = "Models/Core/UnitSphere.obj"; + model["Resource"] = "Models/Core/UnitSphere.mesh"; model["Color"] = glm::vec4(rand()%255 / 255.f, rand()%255 / 255.f, rand() %255 / 255.f, 1.f); ComponentWrapper player = m_World->AttachComponent(entityID, "Player"); m_PlayerDefinitions[playerIndex].EntityID = entityID; @@ -355,12 +403,19 @@ void Server::createPlayer() } } LOG_WARNING("Server is full!"); - + } -int Server::GetPlayerIDFromEndpoint(boost::asio::ip::udp::endpoint endpoint) +void Server::kick(PlayerID player) { - for (int i = 0; i < MAXCONNECTIONS; i++) { + disconnect(player); + Packet packet = Packet(MessageType::Kick); + send(packet); +} + +PlayerID Server::GetPlayerIDFromEndpoint(boost::asio::ip::udp::endpoint endpoint) +{ + for (int i = 0; i < m_MaxConnections; i++) { if (m_PlayerDefinitions[i].Endpoint.address() == endpoint.address() && m_PlayerDefinitions[i].Endpoint.port() == endpoint.port()) { return i; @@ -372,5 +427,25 @@ int Server::GetPlayerIDFromEndpoint(boost::asio::ip::udp::endpoint endpoint) bool Server::OnInputCommand(const Events::InputCommand & e) { //LOG_DEBUG("Server::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID); + if (e.Command == "LogNetworkBandwidth" && e.Value > 0) { + if (isReadingData) { + saveToFile(); + } + isReadingData = !isReadingData; + m_SaveDataTimer = std::clock(); + } + if (e.Command == "KickPlayer" && e.Value > 0) { + kick(0); + } + return true; } + +bool Server::OnPlayerSpawned(const Events::PlayerSpawned & e) +{ + Packet packet = Packet(MessageType::OnPlayerSpawned); + packet.WritePrimitive(e.Player.ID); + packet.WritePrimitive(e.Spawner.ID); + send(e.PlayerID, packet); + return false; +} diff --git a/src/Engine/Rendering/DrawBloomPass.cpp b/src/Engine/Rendering/DrawBloomPass.cpp index 1ad97eb5..8fe1d807 100644 --- a/src/Engine/Rendering/DrawBloomPass.cpp +++ b/src/Engine/Rendering/DrawBloomPass.cpp @@ -4,7 +4,7 @@ DrawBloomPass::DrawBloomPass(IRenderer* renderer) { m_Renderer = renderer; - m_ScreenQuad = ResourceManager::Load("Models/Core/ScreenQuad.obj"); + m_ScreenQuad = ResourceManager::Load("Models/Core/ScreenQuad.mesh"); InitializeTextures(); InitializeBuffers(); diff --git a/src/Engine/Rendering/DrawColorCorrectionPass.cpp b/src/Engine/Rendering/DrawColorCorrectionPass.cpp index c9789602..ba9efe3e 100644 --- a/src/Engine/Rendering/DrawColorCorrectionPass.cpp +++ b/src/Engine/Rendering/DrawColorCorrectionPass.cpp @@ -4,8 +4,8 @@ DrawColorCorrectionPass::DrawColorCorrectionPass(IRenderer* renderer) { m_Renderer = renderer; - m_ScreenQuad = ResourceManager::Load("Models/Core/ScreenQuad.obj"); - m_Exposure = 1; //TODO: Renderer: Fixa så att denna går att ändra på genom komponent eller setting. + m_ScreenQuad = ResourceManager::Load("Models/Core/ScreenQuad.mesh"); + m_Exposure = 0.4; //TODO: Renderer: Fixa så att denna går att ändra på genom komponent eller setting. InitializeShaderPrograms(); } diff --git a/src/Engine/Rendering/DrawFinalPass.cpp b/src/Engine/Rendering/DrawFinalPass.cpp index 290d699f..fb28ae12 100644 --- a/src/Engine/Rendering/DrawFinalPass.cpp +++ b/src/Engine/Rendering/DrawFinalPass.cpp @@ -65,6 +65,7 @@ void DrawFinalPass::Draw(RenderScene& scene) glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "P"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ProjectionMatrix())); glUniform2f(glGetUniformLocation(shaderHandle, "ScreenDimensions"), m_Renderer->Resolution().Width, m_Renderer->Resolution().Height); + //TODO: Render: Add code for more jobs than modeljobs. for (auto &job : scene.ForwardJobs) { auto modelJob = std::dynamic_pointer_cast(job); @@ -72,6 +73,7 @@ void DrawFinalPass::Draw(RenderScene& scene) //TODO: Kolla upp "header/include/common" shader saken så man slipper skicka in asmycket uniforms glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "M"), 1, GL_FALSE, glm::value_ptr(modelJob->Matrix)); glUniform4fv(glGetUniformLocation(shaderHandle, "Color"), 1, glm::value_ptr(modelJob->Color)); + glUniform4fv(glGetUniformLocation(shaderHandle, "DiffuseColor"), 1, glm::value_ptr(modelJob->DiffuseColor)); glUniform4fv(glGetUniformLocation(shaderHandle, "FillColor"), 1, glm::value_ptr(modelJob->FillColor)); glUniform1f(glGetUniformLocation(shaderHandle, "FillPercentage"), modelJob->FillPercentage); @@ -84,22 +86,35 @@ void DrawFinalPass::Draw(RenderScene& scene) glBindTexture(GL_TEXTURE_2D, m_WhiteTexture->m_Texture); } glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, m_BlackTexture->m_Texture); - - /*if(modelJob->GlowMap != nullptr) { - glBindTexture(GL_TEXTURE_2D, modelJob->GlowMap->m_Texture); + if (modelJob->IncandescenceTexture != nullptr) { + glBindTexture(GL_TEXTURE_2D, modelJob->IncandescenceTexture->m_Texture); } else { glBindTexture(GL_TEXTURE_2D, m_BlackTexture->m_Texture); + } + + /*if(modelJob->GlowMap != nullptr) { + glBindTexture(GL_TEXTURE_2D, modelJob->GlowMap->m_Texture); + } else { + glBindTexture(GL_TEXTURE_2D, m_BlackTexture->m_Texture); }*/ + //TODO: Fixa så att modelsJobs kan spela upp olika animationer och så att den kan få in en tid istället för 1.0f - Hälsningar Johan och Andreas :) + if (modelJob->Model->m_RawModel->m_Skeleton != nullptr) { + auto animation = modelJob->Model->m_RawModel->m_Skeleton->GetAnimation("running"); + if (animation != nullptr) { + std::vector frameBones = modelJob->Model->m_RawModel->m_Skeleton->GetFrameBones( + *animation, + 0.0f + ); + glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0])); + } + } + glBindVertexArray(modelJob->Model->VAO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, modelJob->Model->ElementBuffer); - glDrawElementsBaseVertex(GL_TRIANGLES, modelJob->EndIndex - modelJob->StartIndex + 1, GL_UNSIGNED_INT, 0, modelJob->StartIndex); - - continue; + glDrawElements(GL_TRIANGLES, modelJob->EndIndex - modelJob->StartIndex + 1, GL_UNSIGNED_INT, (void*)(modelJob->StartIndex * sizeof(unsigned int))); } } - m_FinalPassFrameBuffer.Unbind(); GLERROR("DrawFinalPass::Draw: END"); delete state; } @@ -137,4 +152,4 @@ void DrawFinalPass::GenerateMipMapTexture(GLuint* texture, GLenum wrapping, glm: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); GLERROR("MipMap Texture initialization failed"); -} +} \ No newline at end of file diff --git a/src/Engine/Rendering/DrawScreenQuadPass.cpp b/src/Engine/Rendering/DrawScreenQuadPass.cpp index 4b155fc9..b17f5e29 100644 --- a/src/Engine/Rendering/DrawScreenQuadPass.cpp +++ b/src/Engine/Rendering/DrawScreenQuadPass.cpp @@ -4,7 +4,7 @@ DrawScreenQuadPass::DrawScreenQuadPass(IRenderer* renderer) { m_Renderer = renderer; - m_ScreenQuad = ResourceManager::Load("Models/Core/ScreenQuad.obj"); + m_ScreenQuad = ResourceManager::Load("Models/Core/ScreenQuad.mesh"); InitializeShaderPrograms(); } diff --git a/src/Engine/Rendering/Model.cpp b/src/Engine/Rendering/Model.cpp index 33539a14..cf4923a3 100644 --- a/src/Engine/Rendering/Model.cpp +++ b/src/Engine/Rendering/Model.cpp @@ -15,6 +15,9 @@ Model::Model(std::string fileName) if (!group.SpecularMapPath.empty()) { group.SpecularMap = std::shared_ptr(ResourceManager::Load(group.SpecularMapPath)); } + if (!group.IncandescenceMapPath.empty()) { + group.IncandescenceMap = std::shared_ptr(ResourceManager::Load(group.IncandescenceMapPath)); + } } // Generate GL buffers @@ -32,7 +35,7 @@ Model::Model(std::string fileName) GLERROR("GLEW: BufferFail4"); glBindBuffer(GL_ARRAY_BUFFER, buffer); - std::vector structSizes = { 3, 3, 3, 3, 2, 4, 4, 4, 4, 4, 4 }; + std::vector structSizes = { 3, 3, 3, 3, 2, 4, 4 }; int stride = 0; for (int size : structSizes) { stride += size; @@ -48,10 +51,6 @@ Model::Model(std::string fileName) glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++; glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++; glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++; - glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++; - glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++; - glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++; - glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++; } GLERROR("GLEW: BufferFail5"); @@ -62,10 +61,6 @@ Model::Model(std::string fileName) glEnableVertexAttribArray(4); glEnableVertexAttribArray(5); glEnableVertexAttribArray(6); - glEnableVertexAttribArray(7); - glEnableVertexAttribArray(8); - glEnableVertexAttribArray(9); - glEnableVertexAttribArray(10); GLERROR("GLEW: BufferFail5"); //CreateBuffers(); diff --git a/src/Engine/Rendering/RawModel.cpp b/src/Engine/Rendering/RawModelAssimp.cpp similarity index 89% rename from src/Engine/Rendering/RawModel.cpp rename to src/Engine/Rendering/RawModelAssimp.cpp index 256346f1..7bf72a22 100644 --- a/src/Engine/Rendering/RawModel.cpp +++ b/src/Engine/Rendering/RawModelAssimp.cpp @@ -1,6 +1,8 @@ -#include "Rendering/RawModel.h" +#include "Rendering/RawModelAssimp.h" -RawModel::RawModel(std::string fileName) +#ifdef USING_ASSIMP_AS_IMPORTER + +RawModelAssimp::RawModelAssimp(std::string fileName) { Assimp::Importer importer; const aiScene* scene = importer.ReadFile(fileName, aiProcess_CalcTangentSpace | aiProcess_Triangulate); @@ -38,7 +40,7 @@ RawModel::RawModel(std::string fileName) //LOG_DEBUG("Index count %i", numIndices); //LOG_DEBUG("Model has %i embedded textures", scene->mNumTextures); - + std::vector> boneInfo; std::map boneNameMapping; @@ -74,21 +76,7 @@ RawModel::RawModel(std::string fileName) auto uv = mesh->mTextureCoords[0][vertexIndex]; desc.TextureCoords = glm::vec2(uv.x, uv.y); } - - // Material diffuse color - aiColor3D diffuse; - material->Get(AI_MATKEY_COLOR_DIFFUSE, diffuse); - float opacity; - material->Get(AI_MATKEY_OPACITY, opacity); - desc.DiffuseVertexColor = glm::vec4(diffuse.r, diffuse.g, diffuse.b, opacity); - - desc.DiffuseVertexColor = glm::vec4(diffuse.r, diffuse.g, diffuse.b, opacity); - // Material specular color - aiColor3D specular; - material->Get(AI_MATKEY_COLOR_SPECULAR, specular); - desc.SpecularVertexColor = glm::vec4(specular.r, specular.g, specular.b, 1.f); - m_Vertices.push_back(desc); } @@ -128,7 +116,7 @@ RawModel::RawModel(std::string fileName) } for (auto& vertex : m_Vertices) { vertex.Tangent = glm::normalize(vertex.Tangent); - vertex.BiTangent = glm::normalize(glm::cross(vertex.Tangent, glm::normalize(vertex.Normal))); + vertex.BiNormal = glm::normalize(glm::cross(vertex.Tangent, glm::normalize(vertex.Normal))); } // Material info @@ -201,10 +189,7 @@ RawModel::RawModel(std::string fileName) LOG_WARNING("Vertex weights (%i) greater than max weights per vertex (%i)", weights.size(), maxWeights); } for (int weightIndex = 0; weightIndex < weights.size() && weightIndex < maxWeights && weightIndex < 4; ++weightIndex) { - std::tie(desc.BoneIndices1[weightIndex], desc.BoneWeights1[weightIndex]) = weights[weightIndex]; - } - for (int weightIndex = 4; weightIndex < weights.size() && weightIndex < maxWeights && weightIndex < 8; ++weightIndex) { - std::tie(desc.BoneIndices2[weightIndex - 4], desc.BoneWeights2[weightIndex - 4]) = weights[weightIndex]; + std::tie(desc.BoneIndices[weightIndex], desc.BoneWeights[weightIndex]) = weights[weightIndex]; } } @@ -290,14 +275,14 @@ RawModel::RawModel(std::string fileName) } } -RawModel::~RawModel() +RawModelAssimp::~RawModelAssimp() { if (m_Skeleton) { delete m_Skeleton; } } -void RawModel::CreateSkeleton(std::vector> &boneInfo, std::map &boneNameMapping, aiNode* node, int parentID) +void RawModelAssimp::CreateSkeleton(std::vector> &boneInfo, std::map &boneNameMapping, aiNode* node, int parentID) { std::string nodeName = node->mName.C_Str(); @@ -317,3 +302,5 @@ void RawModel::CreateSkeleton(std::vector> &b CreateSkeleton(boneInfo, boneNameMapping, child, parentID); } } + +#endif \ No newline at end of file diff --git a/src/Engine/Rendering/RawModelCustom.cpp b/src/Engine/Rendering/RawModelCustom.cpp new file mode 100644 index 00000000..83f6e703 --- /dev/null +++ b/src/Engine/Rendering/RawModelCustom.cpp @@ -0,0 +1,381 @@ +#include "Rendering/RawModelCustom.h" + +#ifndef USING_ASSIMP_AS_IMPORTER + +RawModelCustom::RawModelCustom(std::string fileName) +{ + if(fileName.substr(fileName.find_last_of(".")).compare(".mesh") != 0) { + throw Resource::FailedLoadingException("Unknown model file format. Please use \".mesh\" files."); + } + fileName = fileName.erase(fileName.find_last_of("."), fileName.find_last_of(".") - fileName.size()); + ReadMeshFile(fileName); + ReadMaterialFile(fileName); + ReadAnimationFile(fileName); +} + +void RawModelCustom::ReadMeshFile(std::string filePath) +{ + char* fileData; + filePath += ".mesh"; + std::ifstream in(filePath.c_str(), std::ios_base::binary | std::ios_base::ate); + + if (!in.is_open()) { + throw Resource::FailedLoadingException("Open mesh file failed"); + } + unsigned int fileByteSize = in.tellg(); + in.seekg(0, std::ios_base::beg); + + fileData = new char[fileByteSize]; + in.read(fileData, fileByteSize); + in.close(); + + unsigned int offset = 0; + if (fileByteSize > 0) { + ReadMeshFileHeader(offset, fileData, fileByteSize); + ReadMesh(offset, fileData, fileByteSize); + } + delete fileData; +} + +void RawModelCustom::ReadMeshFileHeader(unsigned int& offset, char* fileData, unsigned int& fileByteSize) +{ +#ifdef BOOST_LITTLE_ENDIAN + m_Vertices.resize(*(unsigned int*)(fileData + offset)); + offset += sizeof(unsigned int); + m_Indices.resize(*(unsigned int*)(fileData + offset)); + offset += sizeof(unsigned int); +#else +#endif +} + +void RawModelCustom::ReadMesh(unsigned int& offset, char* fileData, unsigned int& fileByteSize) +{ + ReadVertices(offset, fileData, fileByteSize); + ReadIndices(offset, fileData, fileByteSize); +} + +void RawModelCustom::ReadVertices(unsigned int& offset, char* fileData, unsigned int& fileByteSize) +{ +#ifdef BOOST_LITTLE_ENDIAN + if (offset + m_Vertices.size() * sizeof(Vertex) > fileByteSize) { + throw Resource::FailedLoadingException("Reading vertices failed"); + } + + memcpy(&m_Vertices[0], fileData + offset, m_Vertices.size() * sizeof(Vertex)); + offset += m_Vertices.size() * sizeof(Vertex); +#else +#endif +} + +void RawModelCustom::ReadIndices(unsigned int& offset, char* fileData, unsigned int& fileByteSize) +{ +#ifdef BOOST_LITTLE_ENDIAN + if (offset + m_Indices.size() * sizeof(unsigned int) > fileByteSize) { + throw Resource::FailedLoadingException("Reading indices failed"); + } + + memcpy(&m_Indices[0], fileData + offset, m_Indices.size() * sizeof(unsigned int)); + offset += m_Indices.size() * sizeof(unsigned int); + +#else +#endif +} + +void RawModelCustom::ReadMaterialFile(std::string filePath) +{ + char* fileData; + filePath += ".mtrl"; + std::ifstream in(filePath.c_str(), std::ios_base::binary | std::ios_base::ate); + + if (!in.is_open()) { + throw Resource::FailedLoadingException("Open material file failed"); + } + unsigned int fileByteSize = in.tellg(); + in.seekg(0, std::ios_base::beg); + + fileData = new char[fileByteSize]; + in.read(fileData, fileByteSize); + in.close(); + + unsigned int offset = 0; + if (fileByteSize > 0) { + ReadMaterials(offset, fileData, fileByteSize); + } + delete fileData; +} + +void RawModelCustom::ReadMaterials(unsigned int& offset, char* fileData, unsigned int& fileByteSize) +{ +#ifdef BOOST_LITTLE_ENDIAN + unsigned int* numMaterials = (unsigned int*)(fileData); + MaterialGroups.reserve(*numMaterials); + offset += sizeof(unsigned int); + + for (int i = 0; i < *numMaterials; i++) { + ReadMaterialSingle(offset, fileData, fileByteSize); + } +#else +#endif +} + +void RawModelCustom::ReadMaterialSingle(unsigned int &offset, char* fileData, unsigned int& fileByteSize) +{ + MaterialGroup newMaterial; + +#ifdef BOOST_LITTLE_ENDIAN + + if (offset + sizeof(unsigned int) * 4 > fileByteSize) { + throw Resource::FailedLoadingException("Reading Material texture names length failed"); + } + + unsigned int* nameLengths = (unsigned int*)(fileData + offset); + offset += sizeof(unsigned int) * 4; + + if (offset + sizeof(float) * 11 + sizeof(unsigned int) * 2 > fileByteSize) { + throw Resource::FailedLoadingException("Reading Material specular, reflection, color and start and end index values failed"); + } + + newMaterial.SpecularExponent = *(float*)(fileData + offset); + offset += sizeof(float); + newMaterial.ReflectionFactor = *(float*)(fileData + offset); + offset += sizeof(float); + + memcpy(&newMaterial.DiffuseColor[0], fileData + offset, sizeof(float) * 3); + offset += sizeof(float) * 3; + memcpy(&newMaterial.SpecularColor[0], fileData + offset, sizeof(float) * 3); + offset += sizeof(float) * 3; + memcpy(&newMaterial.IncandescenceColor[0], fileData + offset, sizeof(float) * 3); + offset += sizeof(float) * 3; + + newMaterial.StartIndex = *(unsigned int*)(fileData + offset); + offset += sizeof(unsigned int); + newMaterial.EndIndex = *(unsigned int*)(fileData + offset); + offset += sizeof(unsigned int); + + if (nameLengths[0] > 0) { + if (offset + nameLengths[0] > fileByteSize) { + throw Resource::FailedLoadingException("Reading Material texture path failed"); + } + + newMaterial.TexturePath = "Textures/"; + newMaterial.TexturePath += (fileData + offset); + newMaterial.TexturePath += ".png"; + offset += nameLengths[0]; + } + + if (nameLengths[1] > 0) { + if (offset + nameLengths[1] > fileByteSize) { + throw Resource::FailedLoadingException("Reading Material NormalMap path failed"); + } + newMaterial.NormalMapPath = "Textures/"; + newMaterial.NormalMapPath += (fileData + offset); + newMaterial.NormalMapPath += ".png"; + offset += nameLengths[1]; + } + + if (nameLengths[2] > 0) { + if (offset + nameLengths[2] > fileByteSize) { + throw Resource::FailedLoadingException("Reading Material SpecularMap path failed"); + } + newMaterial.SpecularMapPath = "Textures/"; + newMaterial.SpecularMapPath += (fileData + offset); + newMaterial.SpecularMapPath += ".png"; + offset += nameLengths[2]; + } + + if (nameLengths[3] > 0) { + if (offset + nameLengths[3] > fileByteSize) { + throw Resource::FailedLoadingException("Reading Material IncandescenceMap path failed"); + } + newMaterial.IncandescenceMapPath = "Textures/"; + newMaterial.IncandescenceMapPath += (fileData + offset); + newMaterial.IncandescenceMapPath += ".png"; + offset += nameLengths[3]; + } + +#else +#endif + + MaterialGroups.push_back(newMaterial); +} + +void RawModelCustom::ReadAnimationFile(std::string filePath) +{ + char* fileData; + filePath += ".anim"; + std::ifstream in(filePath.c_str(), std::ios_base::binary | std::ios_base::ate); + + if (!in.is_open()) { + //throw Resource::FailedLoadingException("Open animation file failed"); + return; + } + + unsigned int fileByteSize = in.tellg(); + in.seekg(0, std::ios_base::beg); + + fileData = new char[fileByteSize]; + in.read(fileData, fileByteSize); + in.close(); + + unsigned int offset = 0; + if (fileByteSize > 0) { + m_Skeleton = new Skeleton(); + +#ifdef BOOST_LITTLE_ENDIAN + unsigned int numBindPoses = *(unsigned int*)(fileData); + offset += sizeof(unsigned int); + unsigned int numAnimations = *(unsigned int*)(fileData + offset); + offset += sizeof(unsigned int); +#else +#endif + + ReadAnimationBindPoses(offset, fileData, fileByteSize); + ReadAnimationClips(offset, fileData, fileByteSize, numAnimations); + } + delete fileData; +} + +void RawModelCustom::ReadAnimationBindPoses(unsigned int &offset, char* fileData, unsigned int& fileByteSize) +{ +#ifdef BOOST_LITTLE_ENDIAN + unsigned int* numBones = (unsigned int*)(fileData + offset); + offset += sizeof(unsigned int); + + for (unsigned int i = 0; i < *numBones; i++) { + ReadAnimationJoint(offset, fileData, fileByteSize); + } +#else +#endif +} + +void RawModelCustom::ReadAnimationJoint(unsigned int &offset, char* fileData, unsigned int& fileByteSize) +{ +#ifdef BOOST_LITTLE_ENDIAN + if (offset + sizeof(unsigned int) > fileByteSize) { + throw Resource::FailedLoadingException("Reading Joint name length failed"); + } + unsigned int jointNameLength = *(unsigned int*)(fileData + offset); + offset += sizeof(unsigned int); + + if (offset + jointNameLength > fileByteSize) { + throw Resource::FailedLoadingException("Reading Joint name failed"); + } + std::string jointName = (fileData + offset); + offset += jointNameLength; + + if (offset + sizeof(float) * 4 * 4 > fileByteSize) { + throw Resource::FailedLoadingException("Reading Joint offset matrix failed"); + } + glm::mat4 offsetMatrix; + memcpy(&offsetMatrix, fileData + offset, sizeof(float) * 4 * 4); + offset += sizeof(float) * 4 * 4; + + if (offset + sizeof(int) > fileByteSize) { + throw Resource::FailedLoadingException("Reading Joint ID failed"); + } + int jointID = *(int*)(fileData + offset); + offset += sizeof(int); + + if (offset + sizeof(int) > fileByteSize) { + throw Resource::FailedLoadingException("Reading Joint Parent ID failed"); + } + int jointParentID = *(int*)(fileData + offset); + offset += sizeof(int); + + // Adding joint to the Skeleton + m_Skeleton->CreateBone(jointID, jointParentID, jointName, offsetMatrix); + + +#else +#endif +} + +void RawModelCustom::ReadAnimationClips(unsigned int &offset, char* fileData, unsigned int& fileByteSize, unsigned int numberOfClips) +{ + for (unsigned int i = 0; i < numberOfClips; i++) { + ReadAnimationClipSingle(offset, fileData, fileByteSize, i); + } +} + +void RawModelCustom::ReadAnimationClipSingle(unsigned int &offset, char* fileData, unsigned int& fileByteSize, unsigned int clipIndex) +{ +#ifdef BOOST_LITTLE_ENDIAN + Skeleton::Animation newAnimation; + + if (offset + sizeof(unsigned int) > fileByteSize) { + throw Resource::FailedLoadingException("Reading AnimationClip name length failed"); + } + unsigned int clipNameLength = *(unsigned int*)(fileData + offset); + offset += sizeof(unsigned int); + + if (offset + clipNameLength > fileByteSize) { + throw Resource::FailedLoadingException("Reading AnimationClip name failed"); + } + newAnimation.Name = (fileData + offset); + offset += clipNameLength; + + if (offset + sizeof(float) > fileByteSize) { + throw Resource::FailedLoadingException("Reading AnimationClip duration failed"); + } + + newAnimation.Duration = *(float*)(fileData + offset); + offset += sizeof(float); + + if (offset + sizeof(unsigned int) > fileByteSize) { + throw Resource::FailedLoadingException("Reading AnimationClip NrOfKeyframes failed"); + } + unsigned int nrOfKeyframes = *(unsigned int*)(fileData + offset); + offset += sizeof(unsigned int); + + if (offset + sizeof(unsigned int) > fileByteSize) { + throw Resource::FailedLoadingException("Reading AnimationClip NrOfJoints failed"); + } + unsigned int nrOfJoints = *(unsigned int*)(fileData + offset); + offset += sizeof(unsigned int); + + newAnimation.Keyframes.reserve(nrOfKeyframes); + for (unsigned int i = 0; i < nrOfKeyframes; i++) { + ReadAnimationKeyFrame(offset, fileData, fileByteSize, nrOfJoints, newAnimation); + } + m_Skeleton->Animations[newAnimation.Name] = newAnimation; +#else +#endif +} + +void RawModelCustom::ReadAnimationKeyFrame(unsigned int &offset, char* fileData, unsigned int& fileByteSize, unsigned int nrOfJoints, Skeleton::Animation& animation) +{ + Skeleton::Animation::Keyframe newKeyFrame; + + if (offset + sizeof(int) > fileByteSize) { + throw Resource::FailedLoadingException("Reading AnimationKeyFrame index failed"); + } + newKeyFrame.Index = *(int*)(fileData + offset); + offset += sizeof(int); + + if (offset + sizeof(float) > fileByteSize) { + throw Resource::FailedLoadingException("Reading AnimationKeyFrame time failed"); + } + newKeyFrame.Time = *(float*)(fileData + offset); + offset += sizeof(float); + + if (offset + sizeof(Skeleton::Animation::Keyframe::BoneProperty) * nrOfJoints> fileByteSize) { + throw Resource::FailedLoadingException("Reading AnimationKeyFrame joints failed"); + } + + Skeleton::Animation::Keyframe::BoneProperty newBone; + for (unsigned int i = 0; i < nrOfJoints; i++) { + memcpy(&newBone, (fileData + offset), sizeof(Skeleton::Animation::Keyframe::BoneProperty)); + offset += sizeof(Skeleton::Animation::Keyframe::BoneProperty); + newKeyFrame.BoneProperties[newBone.ID] = newBone; + } + animation.Keyframes.push_back(newKeyFrame); +} + +RawModelCustom::~RawModelCustom() +{ + if (m_Skeleton != nullptr) { + delete m_Skeleton; + } +} + +#endif \ No newline at end of file diff --git a/src/Engine/Rendering/RenderSystem.cpp b/src/Engine/Rendering/RenderSystem.cpp index 577fddf6..27f19452 100644 --- a/src/Engine/Rendering/RenderSystem.cpp +++ b/src/Engine/Rendering/RenderSystem.cpp @@ -8,6 +8,7 @@ RenderSystem::RenderSystem(World* world, EventBroker* eventBroker, const IRender { EVENT_SUBSCRIBE_MEMBER(m_ESetCamera, &RenderSystem::OnSetCamera); EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &RenderSystem::OnInputCommand); + EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &RenderSystem::OnPlayerSpawned); m_Camera = new Camera((float)m_Renderer->Resolution().Width / m_Renderer->Resolution().Height, glm::radians(45.f), 0.01f, 5000.f); } @@ -47,15 +48,22 @@ void RenderSystem::fillModels(std::list>& jobs) continue; } + EntityWrapper entity(m_World, modelComponent.EntityID); + + // Don't render the local player + if (entity == m_LocalPlayer || entity.IsChildOf(m_LocalPlayer)) { + continue; + } + Model* model; try { model = ResourceManager::Load<::Model, true>(resource); } catch (const Resource::StillLoadingException&) { //continue; - model = ResourceManager::Load<::Model>("Models/Core/UnitRaptor.obj"); + model = ResourceManager::Load<::Model>("Models/Core/UnitRaptor.mesh"); } catch (const std::exception&) { try { - model = ResourceManager::Load<::Model>("Models/Core/Error.obj"); + model = ResourceManager::Load<::Model>("Models/Core/Error.mesh"); } catch (const std::exception&) { continue; } @@ -81,6 +89,14 @@ void RenderSystem::fillModels(std::list>& jobs) } } +bool RenderSystem::OnPlayerSpawned(Events::PlayerSpawned& e) +{ + if (e.PlayerID == -1) { + m_LocalPlayer = e.Player; + } + return true; +} + void RenderSystem::fillPointLights(std::list>& jobs, World* world) { auto pointLights = m_World->GetComponents("PointLight"); @@ -168,12 +184,13 @@ void RenderSystem::Update(double dt) { m_EventBroker->Process(); - if (m_CurrentCamera) { - ComponentWrapper cameraTransform = m_CurrentCamera["Transform"]; - m_Camera->SetPosition(cameraTransform["Position"]); - m_Camera->SetOrientation(glm::quat((const glm::vec3&)cameraTransform["Orientation"])); + // Update the current camera used for rendering + if (m_CurrentCamera.Valid()) { + m_Camera->SetPosition(Transform::AbsolutePosition(m_CurrentCamera)); + m_Camera->SetOrientation(Transform::AbsoluteOrientation(m_CurrentCamera)); } + RenderScene scene; scene.Camera = m_Camera; scene.Viewport = Rectangle(1280, 720); diff --git a/src/Engine/Rendering/Renderer.cpp b/src/Engine/Rendering/Renderer.cpp index 770baabf..4f687a99 100644 --- a/src/Engine/Rendering/Renderer.cpp +++ b/src/Engine/Rendering/Renderer.cpp @@ -13,9 +13,9 @@ void Renderer::Initialize() m_TextPass->Initialize(); - m_ScreenQuad = ResourceManager::Load("Models/Core/ScreenQuad.obj"); + /* m_ScreenQuad = ResourceManager::Load("Models/Core/ScreenQuad.obj"); m_UnitQuad = ResourceManager::Load("Models/Core/UnitQuad.obj"); - m_UnitSphere = ResourceManager::Load("Models/Core/UnitSphere.obj"); + m_UnitSphere = ResourceManager::Load("Models/Core/UnitSphere.obj");*/ m_ImGuiRenderPass = new ImGuiRenderPass(this, m_EventBroker); } diff --git a/src/Engine/Rendering/Skeleton.cpp b/src/Engine/Rendering/Skeleton.cpp index 44276308..cebabb67 100644 --- a/src/Engine/Rendering/Skeleton.cpp +++ b/src/Engine/Rendering/Skeleton.cpp @@ -68,7 +68,7 @@ std::vector Skeleton::GetFrameBones(const Animation& animation, doubl void Skeleton::AccumulateBoneTransforms(bool noRootMotion, const Animation::Keyframe ¤tFrame, const Animation::Keyframe &nextFrame, float progress, std::map &boneMatrices, const Bone* bone, glm::mat4 parentMatrix) { - glm::mat4 boneMatrix; + glm::mat4 boneMatrix; if (currentFrame.BoneProperties.find(bone->ID) != currentFrame.BoneProperties.end() || nextFrame.BoneProperties.find(bone->ID) != nextFrame.BoneProperties.end()) { Animation::Keyframe::BoneProperty currentBoneProperty = currentFrame.BoneProperties.at(bone->ID); @@ -84,10 +84,13 @@ void Skeleton::AccumulateBoneTransforms(bool noRootMotion, const Animation::Keyf positionInterp.z = 0; } + boneMatrix = parentMatrix * (glm::translate(positionInterp) * glm::toMat4(rotationInterp) * glm::scale(scaleInterp)); boneMatrices[bone->ID] = boneMatrix * bone->OffsetMatrix; } else { - boneMatrix = parentMatrix * bone->Parent->OffsetMatrix; // * glm::inverse(bone->OffsetMatrix); + if (bone->Parent) { + boneMatrix = parentMatrix; // * glm::inverse(bone->OffsetMatrix); + } boneMatrices[bone->ID] = boneMatrix; // * bone->OffsetMatrix; } @@ -95,6 +98,7 @@ void Skeleton::AccumulateBoneTransforms(bool noRootMotion, const Animation::Keyf std::string name = child->Name; AccumulateBoneTransforms(noRootMotion, currentFrame, nextFrame, progress, boneMatrices, child, boneMatrix); } + } int Skeleton::GetBoneID(std::string name) diff --git a/src/Engine/Sound/SoundSystem.cpp b/src/Engine/Sound/SoundSystem.cpp index 1292e0b1..a55c1fee 100644 --- a/src/Engine/Sound/SoundSystem.cpp +++ b/src/Engine/Sound/SoundSystem.cpp @@ -198,7 +198,7 @@ bool SoundSystem::OnPlaySoundOnPosition(const Events::PlaySoundOnPosition & e) (float&)(double)emitter["RollOffFactor"] = e.RollOffFactor; (float&)(double)emitter["ReferenceDistance"] = e.ReferenceDistance; auto model = m_World->AttachComponent(emitterID, "Model"); - (std::string&)model["Resource"] = "Models/Core/UnitCube.obj"; + (std::string&)model["Resource"] = "Models/Core/UnitCube.mesh"; // 360NoScope UnitCube source->Type = SoundType::SFX; m_Sources[emitterID] = source; playSound(source); diff --git a/src/Game/Systems/InterpolationSystem.cpp b/src/Game/Systems/InterpolationSystem.cpp index 75f68678..2b6e82f2 100644 --- a/src/Game/Systems/InterpolationSystem.cpp +++ b/src/Game/Systems/InterpolationSystem.cpp @@ -1,24 +1,14 @@ #include "Systems/InterpolationSystem.h" -//void InterpolationSystem::UpdateComponent(World * world, ComponentWrapper & transform, double dt) -//{ -// if (m_InterpolationPoints[transform.EntityID].size() > 0) { -// Transform& sTransform = m_InterpolationPoints[transform.EntityID].front(); -// sTransform.interpolationTime += dt; -// if (sTransform.interpolationTime > 0.05) { -// double time = std::fmod(sTransform.interpolationTime, 0.05f); -// m_InterpolationPoints[transform.EntityID].pop(); -// if (m_InterpolationPoints[transform.EntityID].size() <= 0) { -// return; -// } -// sTransform = m_InterpolationPoints[transform.EntityID].front(); -// sTransform.interpolationTime = time; -// } -// glm::vec3 nextPosition = sTransform.Position; -// glm::vec3 currentPosition = static_cast(transform["Position"]); -// transform["Position"] = vectorInterpolation(currentPosition, nextPosition, sTransform.interpolationTime); -// } -//} +InterpolationSystem::InterpolationSystem(World* world, EventBroker* eventBroker) + : System(world, eventBroker) + , PureSystem("Transform") +{ + ConfigFile* config = ResourceManager::Load("Config.ini"); + m_SnapshotInterval = config->Get("Networking.SnapshotInterval", 0.05); + EVENT_SUBSCRIBE_MEMBER(m_EInterpolate, &InterpolationSystem::OnInterpolate); + EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &InterpolationSystem::OnPlayerSpawned); +} void InterpolationSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& transform, double dt) { @@ -26,10 +16,10 @@ void InterpolationSystem::UpdateComponent(EntityWrapper& entity, ComponentWrappe m_NextTransform[transform.EntityID].interpolationTime += dt; Transform sTransform = m_NextTransform[transform.EntityID]; double time = sTransform.interpolationTime; - if (time > SNAPSHOTINTERVAL) { + if (time > m_SnapshotInterval) { if (m_LastReceivedTransform.find(transform.EntityID) != m_LastReceivedTransform.end()) { m_NextTransform[transform.EntityID] = m_LastReceivedTransform[transform.EntityID]; - m_NextTransform[transform.EntityID].interpolationTime = time - SNAPSHOTINTERVAL; + m_NextTransform[transform.EntityID].interpolationTime = time - m_SnapshotInterval; sTransform = m_NextTransform[transform.EntityID]; m_LastReceivedTransform.erase(transform.EntityID); } else { @@ -37,14 +27,22 @@ void InterpolationSystem::UpdateComponent(EntityWrapper& entity, ComponentWrappe } } if (transform.Info.Name == "Transform") { + bool isLocalPlayer = entity == m_LocalPlayer || entity.IsChildOf(m_LocalPlayer); // Position glm::vec3 nextPosition = sTransform.Position; glm::vec3 currentPosition = static_cast(transform["Position"]); + // HACK: Hardcoded tolerance value for player position desync = 1 + if (isLocalPlayer && glm::length(nextPosition - currentPosition) < 1.f) { + return; + } (glm::vec3&)transform["Position"] += vectorInterpolation(currentPosition, nextPosition, sTransform.interpolationTime); // Orientation - glm::quat nextOrientation = sTransform.Orientation; - glm::quat currentOrientation = glm::quat(static_cast(transform["Orientation"])); - (glm::vec3&)transform["Orientation"] = glm::eulerAngles(glm::slerp(currentOrientation, nextOrientation, sTransform.interpolationTime / SNAPSHOTINTERVAL)); + // Don't force orientation for players + if (!isLocalPlayer) { + glm::quat nextOrientation = sTransform.Orientation; + glm::quat currentOrientation = glm::quat(static_cast(transform["Orientation"])); + (glm::vec3&)transform["Orientation"] = glm::eulerAngles(glm::slerp(currentOrientation, nextOrientation, sTransform.interpolationTime / m_SnapshotInterval)); + } // Scale glm::vec3 nextScale = sTransform.Scale; glm::vec3 currentScale = static_cast(transform["Scale"]); @@ -53,6 +51,12 @@ void InterpolationSystem::UpdateComponent(EntityWrapper& entity, ComponentWrappe } } +bool InterpolationSystem::OnPlayerSpawned(Events::PlayerSpawned& e) +{ + m_LocalPlayer = e.Player; + return true; +} + bool InterpolationSystem::OnInterpolate(const Events::Interpolate & e) { Transform transform; @@ -72,15 +76,5 @@ bool InterpolationSystem::OnInterpolate(const Events::Interpolate & e) } else { // Did not m_NextTransform[e.Entity] = transform; } - // Check if queue already exists - //if (m_InterpolationPoints.find(e.Entity) != m_InterpolationPoints.end()) { // Did exist, push to queue - // m_InterpolationPoints[e.Entity].push(transform); - //} - - //else { // Did not exist, create queue - // std::queue transformQueue; - // transformQueue.push(transform); - // m_InterpolationPoints[e.Entity] = transformQueue; - //} return false; } diff --git a/src/Game/Systems/PlayerMovementSystem.cpp b/src/Game/Systems/PlayerMovementSystem.cpp index e14cd146..5c75a673 100644 --- a/src/Game/Systems/PlayerMovementSystem.cpp +++ b/src/Game/Systems/PlayerMovementSystem.cpp @@ -1,18 +1,132 @@ #include "Systems/PlayerMovementSystem.h" +PlayerMovementSystem::PlayerMovementSystem(World* world, EventBroker* eventBroker) + : System(world, eventBroker) + , PureSystem("Player") +{ + EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &PlayerMovementSystem::OnPlayerSpawned); +} + +PlayerMovementSystem::~PlayerMovementSystem() +{ + for (auto& kv : m_PlayerInputControllers) { + delete kv.second; + } +} + +void PlayerMovementSystem::Update(double dt) +{ + for (auto& kv : m_PlayerInputControllers) { + EntityWrapper player = kv.first; + auto& controller = kv.second; + + if (!player.Valid()) { + continue; + } + + EntityWrapper cameraEntity = player.FirstChildByName("Camera"); + if (cameraEntity.Valid()) { + glm::vec3& cameraOrientation = cameraEntity["Transform"]["Orientation"]; + cameraOrientation.x += controller->Rotation().x; + // Limit camera pitch so we don't break our necks + cameraOrientation.x = glm::clamp(cameraOrientation.x, -glm::half_pi(), glm::half_pi()); + } + + ComponentWrapper& cTransform = player["Transform"]; + glm::vec3& ori = cTransform["Orientation"]; + ori.y += controller->Rotation().y; + + if (player.HasComponent("Physics")) { + ComponentWrapper cPhysics = player["Physics"]; + + glm::vec3 wishDirection = controller->Movement() * glm::inverse(glm::quat(ori)); + float wishSpeed; + if (controller->Crouching()) { + wishSpeed = player["Player"]["CrouchSpeed"]; + } else { + wishSpeed = player["Player"]["MovementSpeed"]; + } + glm::vec3& velocity = cPhysics["Velocity"]; + ImGui::Text("velocity: (%f, %f, %f)", velocity.x, velocity.y, velocity.z); + glm::vec3 groundVelocity(0.f, 0.f, 0.f); + groundVelocity.x = glm::dot(velocity, glm::vec3(1.f, 0.f, 0.f)); + groundVelocity.z = glm::dot(velocity, glm::vec3(0.f, 0.f, 1.f)); + ImGui::Text("groundVelocity: (%f, %f, %f) |%f|", groundVelocity.x, groundVelocity.y, groundVelocity.z, glm::length(wishDirection)); + ImGui::Text("wishDirection: (%f, %f, %f) |%f|", wishDirection.x, wishDirection.y, wishDirection.z, glm::length(wishDirection)); + float currentSpeedProj = glm::dot(groundVelocity, wishDirection); + float addSpeed = wishSpeed - currentSpeedProj; + ImGui::Text("currentSpeedProj: %f", currentSpeedProj); + ImGui::Text("wishSpeed: %f", wishSpeed); + ImGui::Text("addSpeed: %f", addSpeed); + + if (addSpeed > 0) { + static float accel = 15.f; + ImGui::InputFloat("accel", &accel); + static float airAccel = 0.5f; + ImGui::InputFloat("airAccel", &airAccel); + float actualAccel = (velocity.y != 0) ? airAccel : accel; + static float surfaceFriction = 5.f; + ImGui::InputFloat("surfaceFriction", &surfaceFriction); + float accelerationSpeed = actualAccel * (float)dt * wishSpeed * surfaceFriction; + accelerationSpeed = glm::min(accelerationSpeed, addSpeed); + velocity += accelerationSpeed * wishDirection; + ImGui::Text("velocity: (%f, %f, %f) |%f|", velocity.x, velocity.y, velocity.z, glm::length(velocity)); + } + + if (controller->Jumping() && !controller->Crouching() && velocity.y == 0.f) { + velocity.y += 4.f; + } + + //if (player.HasComponent("AABB")) { + // glm::vec3& size = player["AABB"]["Size"]; + // if (controller->Crouching()) { + // size = glm::vec3(1.f, 1.f, 1.f); + // } else { + // size = glm::vec3(1.f, 1.6f, 1.f); + // } + //} + } + + controller->Reset(); + } +} + void PlayerMovementSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) { ComponentWrapper& cTransform = entity["Transform"]; if (!entity.HasComponent("Physics")) { return; } - ComponentWrapper& cPhysics = entity["Physics"]; + ComponentWrapper& cPhysics = entity["Physics"]; glm::vec3& velocity = cPhysics["Velocity"]; + + // Ground friction + float speed = glm::length(velocity); + static float groundFriction = 7.f; + ImGui::InputFloat("groundFriction", &groundFriction); + static float airFriction = 0.f; + ImGui::InputFloat("airFriction", &airFriction); + float friction = (velocity.y != 0) ? airFriction : groundFriction; + if (speed > 0) { + float drop = speed * friction * (float)dt; + float multiplier = glm::max(speed - drop, 0.f) / speed; + velocity.x *= multiplier; + velocity.z *= multiplier; + } + if (cPhysics["Gravity"]) { - velocity.y -= 9.82 * dt; + velocity.y -= 9.82f * (float)dt; } glm::vec3& position = cTransform["Position"]; position += velocity * (float)dt; -} \ No newline at end of file +} + +bool PlayerMovementSystem::OnPlayerSpawned(Events::PlayerSpawned& e) +{ + // When a player spawns, create an input controller for them + m_PlayerInputControllers[e.Player] = new FirstPersonInputController(m_EventBroker, e.PlayerID); + + return true; +} diff --git a/src/Game/Systems/PlayerSpawnSystem.cpp b/src/Game/Systems/PlayerSpawnSystem.cpp index 4224d46c..84dce05c 100644 --- a/src/Game/Systems/PlayerSpawnSystem.cpp +++ b/src/Game/Systems/PlayerSpawnSystem.cpp @@ -4,6 +4,8 @@ PlayerSpawnSystem::PlayerSpawnSystem(World* m_World, EventBroker* eventBroker) : System(m_World, eventBroker) { EVENT_SUBSCRIBE_MEMBER(m_OnInputCommand, &PlayerSpawnSystem::OnInputCommand); + EVENT_SUBSCRIBE_MEMBER(m_OnPlayerSpawnerd, &PlayerSpawnSystem::OnPlayerSpawned); + m_NetworkEnabled = ResourceManager::Load("Config.ini")->Get("Networking.StartNetwork", false); } void PlayerSpawnSystem::Update(double dt) @@ -13,7 +15,7 @@ void PlayerSpawnSystem::Update(double dt) return; } - for (auto& team : m_SpawnRequests) { + for (auto& req : m_SpawnRequests) { for (auto& cPlayerSpawn : *playerSpawns) { EntityWrapper spawner(m_World, cPlayerSpawn.EntityID); if (!spawner.HasComponent("Spawner")) { @@ -22,7 +24,7 @@ void PlayerSpawnSystem::Update(double dt) // If the spawner has a team affiliation, check it if (spawner.HasComponent("Team")) { - if ((int)spawner["Team"]["Team"] != team) { + if ((int)spawner["Team"]["Team"] != req.Team) { continue; } } @@ -30,7 +32,15 @@ void PlayerSpawnSystem::Update(double dt) // Spawn the player! EntityWrapper player = SpawnerSystem::Spawn(spawner); // Set the player team affiliation - player["Team"]["Team"] = team; + player["Team"]["Team"] = req.Team; + + // Publish a PlayerSpawned event + Events::PlayerSpawned e; + e.PlayerID = req.PlayerID; + e.Player = player; + e.Spawner = spawner; + m_EventBroker->Publish(e); + } } m_SpawnRequests.clear(); @@ -42,10 +52,60 @@ bool PlayerSpawnSystem::OnInputCommand(const Events::InputCommand& e) return false; } + // Team picks should be processed ONLY server-side! + // Don't make a spawn request if PlayerID is -1, i.e. we're the client. + if (e.PlayerID == -1 && m_NetworkEnabled) { + return false; + } + if (e.Value != 0) { - m_SpawnRequests.push_back((int)e.Value); + SpawnRequest req; + req.PlayerID = e.PlayerID; + req.Team = (ComponentInfo::EnumType)e.Value; + m_SpawnRequests.push_back(req); } return true; } +bool PlayerSpawnSystem::OnPlayerSpawned(Events::PlayerSpawned& e) +{ + // When a player is actually spawned (since the actual spawning is handled on the server) + + // Check if a player already exists + if (m_PlayerEntities.count(e.PlayerID) != 0) { + // TODO: Disallow infinite respawning here + m_World->DeleteEntity(m_PlayerEntities[e.PlayerID].ID); + } + + // Store the player for future reference + m_PlayerEntities[e.PlayerID] = e.Player; + + // Set the camera to the correct entity + EntityWrapper cameraEntity = e.Player.FirstChildByName("Camera"); + if (cameraEntity.Valid()) { + Events::SetCamera e; + e.CameraEntity = cameraEntity; + m_EventBroker->Publish(e); + } + + // HACK: Set the player model color to team color + EntityWrapper playerModel = e.Player.FirstChildByName("PlayerModel"); + if (playerModel.Valid() && e.Player.HasComponent("Team")) { + ComponentWrapper cTeam = e.Player["Team"]; + ComponentWrapper cModel = playerModel["Model"]; + if ((ComponentInfo::EnumType)cTeam["Team"] == cTeam["Team"].Enum("Red")) { + cModel["Color"] = glm::vec3(1.f, 0.f, 0.f); + } else if ((ComponentInfo::EnumType)cTeam["Team"] == cTeam["Team"].Enum("Blue")) { + cModel["Color"] = glm::vec3(0.f, 0.25f, 1.f); + } + } + + // TODO: Set the player name to whatever + //EntityWrapper playerName = e.Player.FirstChildByName("PlayerName"); + //if (playerName.Valid()) { + // playerName["Text"]["Content"] = ???; + //} + + return true; +} \ No newline at end of file diff --git a/src/Tests/CollisionTest.cpp b/src/Tests/CollisionTest.cpp index 9f522c06..67b6ce19 100644 --- a/src/Tests/CollisionTest.cpp +++ b/src/Tests/CollisionTest.cpp @@ -27,7 +27,9 @@ using boost::unit_test_framework::test_case; void RayTest(std::string fileName) { //simple box test Ray ray(glm::vec3(-50, 0, 0), glm::vec3(1, 0, 0)); - //using a rawmodel here, else we have to init the renderingsystem + //using a + + here, else we have to init the renderingsystem ResourceManager::RegisterType("RawModel"); auto unitBox = ResourceManager::Load(fileName); BOOST_REQUIRE(unitBox != nullptr); @@ -106,7 +108,7 @@ BOOST_AUTO_TEST_CASE(collisionTest2) BOOST_AUTO_TEST_CASE(rayVsModelTest) { //simple box test - RayTest("Models/Core/UnitCube.obj"); + RayTest("Models/Core/UnitCube.mesh"); // 360NoScope Unitcube } BOOST_AUTO_TEST_CASE(rayVsModelTest2) @@ -128,7 +130,7 @@ BOOST_AUTO_TEST_CASE(rayVsModelTest2) someAABB = AABB(minPos, maxPos); //using a rawmodel here, else we have to init the renderingsystem ResourceManager::RegisterType("RawModel"); - auto unitBox = ResourceManager::Load("Models/Core/UnitCube.obj"); + auto unitBox = ResourceManager::Load("Models/Core/UnitCube.mesh"); // 360NoScope unitcube BOOST_CHECK(unitBox != nullptr); for (size_t i = 0; i < 1000000; i++) @@ -187,19 +189,19 @@ BOOST_AUTO_TEST_CASE(rayVsModelTest2) BOOST_AUTO_TEST_CASE(rayVsModelTest3) { //simple test - RayTest("Models/Core/UnitSphere.obj"); + RayTest("Models/Core/UnitSphere.mesh"); // 360NoScope unitSphere } BOOST_AUTO_TEST_CASE(rayVsModelTest4) { //simple test - RayTest("Models/Core/UnitCylinder.obj"); + RayTest("Models/Core/UnitCylinder.mesh"); // 360NoScope unitCylinder } BOOST_AUTO_TEST_CASE(rayVsModelTest5) { //simple test - RayTest("Models/Core/UnitRaptor.obj"); + RayTest("Models/Core/UnitRaptor.mesh"); // 360NoScope unitRaptor } BOOST_AUTO_TEST_CASE(octTest) { diff --git a/src/Tests/HealthSystemTest.cpp b/src/Tests/HealthSystemTest.cpp index b28a14ba..bdd9ba4b 100644 --- a/src/Tests/HealthSystemTest.cpp +++ b/src/Tests/HealthSystemTest.cpp @@ -56,7 +56,7 @@ GameHealthSystemTest::GameHealthSystemTest() EntityID playerID = m_World->CreateEntity(); ComponentWrapper transform = m_World->AttachComponent(playerID, "Transform"); ComponentWrapper model = m_World->AttachComponent(playerID, "Model"); - model["Resource"] = "Models/Core/UnitSphere.obj"; + model["Resource"] = "Models/Core/UnitSphere.mesh"; // 360NoScope UnitSphere ComponentWrapper player = m_World->AttachComponent(playerID, "Player"); ComponentWrapper health = m_World->AttachComponent(playerID, "Health"); healthsID = playerID; @@ -81,7 +81,7 @@ GameHealthSystemTest::GameHealthSystemTest() EntityID playerID2 = m_World->CreateEntity(); ComponentWrapper transform2 = m_World->AttachComponent(playerID2, "Transform"); ComponentWrapper model2 = m_World->AttachComponent(playerID2, "Model"); - model2["Resource"] = "Models/Core/UnitSphere.obj"; + model2["Resource"] = "Models/Core/UnitSphere.mesh"; // 360NoScope UnitSphere ComponentWrapper player2 = m_World->AttachComponent(playerID2, "Player"); ComponentWrapper health2 = m_World->AttachComponent(playerID2, "Health"); //END TEST diff --git a/src/Tests/OldOctTree.cpp b/src/Tests/OldOctTree.cpp index 16ecec65..8970988c 100644 --- a/src/Tests/OldOctTree.cpp +++ b/src/Tests/OldOctTree.cpp @@ -112,7 +112,7 @@ void OctTree::Update(float dt, World* world, Camera* cam) ComponentWrapper transform = world->AttachComponent(m_BoxID, "Transform"); transform["Scale"] = boxSize; ComponentWrapper model = world->AttachComponent(m_BoxID, "Model"); - model["Resource"] = "Models/Core/UnitBox.obj"; + model["Resource"] = "Models/Core/UnitBox.mesh"; // 360NoScope UnitBox m_UpdatedOnce = true; } diff --git a/src/Tests/ResourceManagerTest.cpp b/src/Tests/ResourceManagerTest.cpp index df1fd76d..1f9f4991 100644 --- a/src/Tests/ResourceManagerTest.cpp +++ b/src/Tests/ResourceManagerTest.cpp @@ -26,7 +26,7 @@ BOOST_AUTO_TEST_CASE(resourceManagerTest) BOOST_CHECK(!ResourceManager::IsResourceLoaded("ConfigFile", "Config.ini")); //configfile without register - BOOST_CHECK_THROW(ResourceManager::Load("Models/Core/ScreenQuad.obj"),Resource::FailedLoadingException); + BOOST_CHECK_THROW(ResourceManager::Load("Models/Core/ScreenQuad.mesh"),Resource::FailedLoadingException); //there is no error feedback to check if you try to release the wrong resources - hence that cant be tested either } diff --git a/tools/MayaExporter/MayaExporter/Export.cpp b/tools/MayaExporter/MayaExporter/Export.cpp new file mode 100644 index 00000000..d8f1abd4 --- /dev/null +++ b/tools/MayaExporter/MayaExporter/Export.cpp @@ -0,0 +1,224 @@ +#include "Export.h" + +Export::Export() +{ + +} + +bool Export::Meshes(std::string pathName, bool selectedOnly) +{ + MStatus status; + if (pathName.empty()) { + MGlobal::displayError(MString() + "Export::Meshes() got no pathName. Do not know where to write file"); + return false; + } + + MSelectionList selectedOnStart; + MGlobal::getActiveSelectionList(selectedOnStart); + if (selectedOnStart.length() > 0) { + for (int i = 0; i < selectedOnStart.length(); i++) { + MObject item; + selectedOnStart.getDependNode(i, item); + MGlobal::unselect(item); + } + } + MGlobal::displayInfo(MString() + "Disabel IKSolvers"); + status = MGlobal::executeCommand("doEnableNodeItems false all;"); + if (status != MS::kSuccess) { + MGlobal::displayError(MString() + "EnableNodeItems false all failed: " + status.errorString()); + } + MGlobal::displayInfo(MString() + "Has disabel IKSolvers"); + MObjectArray Objects; + if (selectedOnly) { + // Retrieving the objects we currently have selected + + // Loop through or list of selection(s) + for (unsigned int i = 0; i < selectedOnStart.length(); i++) { + MObject object; + selectedOnStart.getDependNode(i, object); + + if (object.hasFn(MFn::kMesh)) { + MFnMesh shape(object); + + for (unsigned int k = 0; k < shape.parentCount(); k++) { + MFnDependencyNode thisNode(object); + MPlugArray connections; + thisNode.findPlug("inMesh").connectedTo(connections, true, true); + + for (unsigned int i = 0; i < connections.length(); i++) { + if (connections[i].node().apiType() == MFn::kSkinClusterFilter) { + MGlobal::select(shape.parent(i), MGlobal::kReplaceList); + MGlobal::displayInfo(MString() + "Moving " + thisNode.name() + " to bindPose."); + status = MGlobal::executeCommand("GoToBindPose;"); + if (status != MS::kSuccess) { + MGlobal::displayError(MString() + "GoToBindPose: " + status.errorString()); + } + MGlobal::displayInfo(MString() + "Has moved " + thisNode.name() + " to bindPose."); + } + } + } + Objects.append(object); + } + } + } else { + // Loop through all nodes in the scene + MItDependencyNodes it(MFn::kMesh); + for (; !it.isDone(); it.next()) { + MObject node = it.thisNode(); + MFnDependencyNode thisNode(node); + MPlugArray connections; + thisNode.findPlug("inMesh").connectedTo(connections, true, true); + + for (unsigned int i = 0; i < connections.length(); i++) { + if (connections[i].node().apiType() == MFn::kSkinClusterFilter) { + MGlobal::select(node); + MGlobal::displayInfo(MString() + "Moving " + thisNode.name() + " to bindPose."); + MGlobal::executeCommand("GoToBindPose"); + MGlobal::displayInfo(MString() + "Has moved " + thisNode.name() + " to bindPose."); + } + } + + Objects.append(node); + } + } + GetMeshData(Objects); + WriteMeshData(pathName); + MGlobal::displayInfo(MString() + "Enabling IKSolvers"); + status = MGlobal::executeCommand("doEnableNodeItems true all;"); + if (status != MS::kSuccess) { + MGlobal::displayError(MString() + "doEnableNodeItems true all: " + status.errorString()); + } + MGlobal::displayInfo(MString() + "Has enabling IKSolvers"); + if (selectedOnStart.length() > 0) { + for (int i = 0; i < selectedOnStart.length(); i++) { + MObject item; + selectedOnStart.getDependNode(i, item); + MGlobal::select(item); + } + } + return true; +} + +bool Export::Materials(std::string pathName) +{ + if (!GetMaterialData()) + return false; + WriteMaterialData(pathName); + return true; +} + +bool Export::Animations(std::string pathName, std::vector animInfo) +{ + if (MAnimControl::currentTime().unit() != MTime::kNTSCField) { + + MGlobal::displayError(MString() + "Please change to 60 FPS under Preferences/Settings!"); + return false; + } + + if (pathName.empty()) { + MGlobal::displayError(MString() + "Export::Animations() got no pathName. Do not know where to write file"); + return false; + } + allBindPoses = m_SkeletonHandler.GetBindPoses(); + + for (auto clip : animInfo) { + if (!GetAnimationData(clip)) { + MGlobal::displayError(MString() + "Export::Animations() failed to export " + clip.Name.c_str()); + return false; + } + } + WriteAnimData(pathName); + return true; +} + +bool Export::GetMeshData(MObjectArray object) +{ + meshes = m_MeshHandler.GetMeshData(object); + return true; +} + +bool Export::GetMaterialData() +{ + // Traverse scene and return vector with all materials + AllMaterials = m_MaterialHandler.DoIt(meshes); + + return true; +} + +bool Export::GetAnimationData(AnimationInfo animInfo) +{ + if (animInfo.Name.empty()) { + MGlobal::displayError(MString() + "A clip does not have a name"); + return false; + } + if (animInfo.End - animInfo.Start <= 0) { + MGlobal::displayError(MString() + "A clip ends before it starts or contains 0 frames"); + return false; + } + + allAnimations.push_back(m_SkeletonHandler.GetAnimData(animInfo.Name, animInfo.Start, animInfo.End)); + return true; +} + +void Export::WriteMeshData(std::string pathName) +{ + m_MeshFile.ASCIIFilePath(pathName +"_mesh.txt"); + m_MeshFile.binaryFilePath(pathName + ".mesh"); + + m_MeshFile.OpenFiles(); + + m_MeshFile.writeToFiles((OutputData*)&meshes); + + m_MeshFile.CloseFiles(); +} + +void Export::WriteAnimData(std::string pathName) +{ + if (allBindPoses.size() > 0) { + m_AnimFile.ASCIIFilePath(pathName + "_anim.txt"); + m_AnimFile.binaryFilePath(pathName + ".anim"); + + m_AnimFile.OpenFiles(); + int size = allBindPoses.size(); + m_AnimFile.writeToFiles(&size); + + + size = allAnimations.size(); + m_AnimFile.writeToFiles(&size); + + //print out all bind poses + for (auto aBindPose : allBindPoses) { + m_AnimFile.writeToFiles((OutputData*)&aBindPose); + } + for (auto aAnimation : allAnimations) { + m_AnimFile.writeToFiles((OutputData*)&aAnimation); + } + + m_AnimFile.CloseFiles(); + } else + MGlobal::displayInfo("Export::WriteAnimData() got called when allBindPoses contained no data, did not write nor created them"); +} + +void Export::WriteMaterialData(std::string pathName) +{ + m_MtrlFile.ASCIIFilePath(pathName +"_mtrl.txt"); + m_MtrlFile.binaryFilePath(pathName + ".mtrl"); + + m_MtrlFile.OpenFiles(); + + int size = (*AllMaterials).size(); + m_MtrlFile.writeToFiles(&size); + + for (auto aMaterial : *AllMaterials) { + m_MtrlFile.writeToFiles((OutputData*)&aMaterial); + } + m_MtrlFile.CloseFiles(); +} + +Export::~Export() +{ + /* delete m_MaterialHandler; + delete m_SkeletonHandler; + delete m_MeshHandler;*/ + +} \ No newline at end of file diff --git a/tools/MayaExporter/MayaExporter/Export.h b/tools/MayaExporter/MayaExporter/Export.h new file mode 100644 index 00000000..42b40445 --- /dev/null +++ b/tools/MayaExporter/MayaExporter/Export.h @@ -0,0 +1,58 @@ +#ifndef Export_Export_h__ +#define Export_Export_h__ + +#include +#include + +#include "MayaIncludes.h" +#include "Material.h" +#include "Mesh.h" +#include "Skeleton.h" +#include "WriteToFile.h" + +class Export { +public: + Export(); + + ~Export(); + + struct AnimationInfo { + std::string Name; + int Start; + int End; + }; + + bool Meshes(std::string pathName, bool selectedOnly = false); + bool Materials(std::string pathName); + bool Animations(std::string pathName, std::vector animInfo); + +private: + bool GetMeshData(MObjectArray object); + bool GetMaterialData(); + bool GetAnimationData(AnimationInfo info); + + void WriteMeshData(std::string pathName); + void WriteAnimData(std::string pathName); + void WriteMaterialData(std::string pathName); + + Material m_MaterialHandler; + Skeleton m_SkeletonHandler; + MeshClass m_MeshHandler; + + + //File export + WriteToFile m_MeshFile; + WriteToFile m_AnimFile; + WriteToFile m_MtrlFile; + + //Mesh Data + Mesh meshes; + + //Animation Data + std::vector allBindPoses; + std::vector allAnimations; + + //Material Data + std::vector* AllMaterials; +}; +#endif \ No newline at end of file diff --git a/tools/MayaExporter/MayaExporter/GeneratedFiles/Debug/moc_Menu.cpp b/tools/MayaExporter/MayaExporter/GeneratedFiles/Debug/moc_Menu.cpp index aef8d533..c7879431 100644 --- a/tools/MayaExporter/MayaExporter/GeneratedFiles/Debug/moc_Menu.cpp +++ b/tools/MayaExporter/MayaExporter/GeneratedFiles/Debug/moc_Menu.cpp @@ -22,7 +22,7 @@ static const uint qt_meta_data_Menu[] = { 6, // revision 0, // classname 0, 0, // classinfo - 7, 14, // methods + 5, 14, // methods 0, 0, // properties 0, 0, // enums/sets 0, 0, // constructors @@ -30,22 +30,19 @@ static const uint qt_meta_data_Menu[] = { 0, // signalCount // slots: signature, parameters, type, tag, flags - 14, 6, 5, 5, 0x08, - 35, 5, 5, 5, 0x08, - 59, 5, 5, 5, 0x08, + 6, 5, 5, 5, 0x08, + 30, 5, 5, 5, 0x08, + 51, 5, 5, 5, 0x08, 75, 5, 5, 5, 0x08, - 95, 5, 5, 5, 0x08, - 116, 5, 5, 5, 0x08, - 137, 5, 5, 5, 0x08, + 91, 5, 5, 5, 0x08, 0 // eod }; static const char qt_meta_stringdata_Menu[] = { - "Menu\0\0checked\0ExportSelected(bool)\0" - "ExportPathClicked(bool)\0ExportAll(bool)\0" - "CancelClicked(bool)\0Button1Clicked(bool)\0" - "Button2Clicked(bool)\0Button3Clicked(bool)\0" + "Menu\0\0ExportPathClicked(bool)\0" + "AddClipClicked(bool)\0RemoveClipClicked(bool)\0" + "ExportAll(bool)\0CancelClicked(bool)\0" }; void Menu::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) @@ -54,13 +51,11 @@ void Menu::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void * Q_ASSERT(staticMetaObject.cast(_o)); Menu *_t = static_cast(_o); switch (_id) { - case 0: _t->ExportSelected((*reinterpret_cast< bool(*)>(_a[1]))); break; - case 1: _t->ExportPathClicked((*reinterpret_cast< bool(*)>(_a[1]))); break; - case 2: _t->ExportAll((*reinterpret_cast< bool(*)>(_a[1]))); break; - case 3: _t->CancelClicked((*reinterpret_cast< bool(*)>(_a[1]))); break; - case 4: _t->Button1Clicked((*reinterpret_cast< bool(*)>(_a[1]))); break; - case 5: _t->Button2Clicked((*reinterpret_cast< bool(*)>(_a[1]))); break; - case 6: _t->Button3Clicked((*reinterpret_cast< bool(*)>(_a[1]))); break; + case 0: _t->ExportPathClicked((*reinterpret_cast< bool(*)>(_a[1]))); break; + case 1: _t->AddClipClicked((*reinterpret_cast< bool(*)>(_a[1]))); break; + case 2: _t->RemoveClipClicked((*reinterpret_cast< bool(*)>(_a[1]))); break; + case 3: _t->ExportAll((*reinterpret_cast< bool(*)>(_a[1]))); break; + case 4: _t->CancelClicked((*reinterpret_cast< bool(*)>(_a[1]))); break; default: ; } } @@ -98,9 +93,9 @@ int Menu::qt_metacall(QMetaObject::Call _c, int _id, void **_a) if (_id < 0) return _id; if (_c == QMetaObject::InvokeMetaMethod) { - if (_id < 7) + if (_id < 5) qt_static_metacall(this, _c, _id, _a); - _id -= 7; + _id -= 5; } return _id; } diff --git a/tools/MayaExporter/MayaExporter/Material.cpp b/tools/MayaExporter/MayaExporter/Material.cpp new file mode 100644 index 00000000..03521231 --- /dev/null +++ b/tools/MayaExporter/MayaExporter/Material.cpp @@ -0,0 +1,237 @@ +#include "Material.h" + +void Material::grabLambertProperties(MaterialNode& material_node, MFnDependencyNode& node) +{ + material_node.Name = node.name().asChar(); + + if (!findColorTexture(material_node, node)) { + node.findPlug("colorR").getValue(material_node.DiffuseColor[0]); + node.findPlug("colorG").getValue(material_node.DiffuseColor[1]); + node.findPlug("colorB").getValue(material_node.DiffuseColor[2]); + + } + + + if (!findIncandescenceTexture(material_node, node)) { + node.findPlug("incandescenceR").getValue(material_node.IncandescenceColor[0]); + node.findPlug("incandescenceG").getValue(material_node.IncandescenceColor[1]); + node.findPlug("incandescenceB").getValue(material_node.IncandescenceColor[2]); + } + + if (findNormalTexture(material_node, node)) { + MGlobal::displayWarning(MString() + "Material " + node.name() + " has no normal texture."); + } +} + +void Material::grabBlinnProperties(MaterialNode& material_node, MFnDependencyNode& node) +{ + if (!findSpecularTexture(material_node, node)) { + node.findPlug("specularColorR").getValue(material_node.SpecularColor[0]); + node.findPlug("specularColorG").getValue(material_node.SpecularColor[1]); + node.findPlug("specularColorB").getValue(material_node.SpecularColor[2]); + } + + m_Plug = node.findPlug("reflectivity"); + m_Plug.getValue(material_node.ReflectionFactor); + + m_Plug = node.findPlug("eccentricity"); + float TempEccent; + m_Plug.getValue(TempEccent); + + // Blinn works differently from Phong which is used in-game. + // This is some magic numbers and math to make a conversion estimate between the two. + // There is no exact conversion between the two, so there are errors. + + // Phong min/max is around Blinn 0.7/0.1 + TempEccent = std::max(std::min(TempEccent, 0.7f), 0.1f); + + material_node.SpecularExponent = std::max(std::min(((2.66f) + (427.0f) * exp((-14.8f) * TempEccent)), 100.0f), 2.0f); +} + +void Material::grabPhongProperties(MaterialNode& material_node, MFnDependencyNode& node) +{ + if (!findSpecularTexture(material_node, node)) { + node.findPlug("specularColorR").getValue(material_node.SpecularColor[0]); + node.findPlug("specularColorG").getValue(material_node.SpecularColor[1]); + node.findPlug("specularColorB").getValue(material_node.SpecularColor[2]); + } + + m_Plug = node.findPlug("reflectivity"); + m_Plug.getValue(material_node.ReflectionFactor); + + m_Plug = node.findPlug("cosinePower "); + m_Plug.getValue(material_node.SpecularExponent); +} + +bool Material::findColorTexture(MaterialNode& material_node, MFnDependencyNode& node) +{ + MPlugArray AllConnections; + + m_Plug = node.findPlug("color", true); + m_Plug.connectedTo(AllConnections, true, false); + + for (int i = 0; i < AllConnections.length(); i++) { + if (AllConnections[i].node().hasFn(MFn::kFileTexture)) { + MFnDependencyNode TextureNode(AllConnections[i].node()); + + std::string FullPath = TextureNode.findPlug("fileTextureName").asString().asChar(); + m_TexturePaths.push_back(FullPath); + + MString workspace; + MStatus status = MGlobal::executeCommand(MString("workspace -q -rd;"), + workspace); + FullPath = FullPath.substr(workspace.length()); + FullPath = FullPath.substr(FullPath.find_first_of("/") + 1); + material_node.ColorMapFile = FullPath.erase(FullPath.find_last_of("."), FullPath.find_last_of(".") - FullPath.size()); + + material_node.ColorMapFileLength = material_node.ColorMapFile.length() + 1; + // Test + MGlobal::displayInfo(MString() + "getAbsolutePathToResources: " + workspace); + MGlobal::displayInfo(MString() + "Texture file: " + FullPath.c_str()); + return true; + } + } + + return false; +} + +bool Material::findNormalTexture(MaterialNode& material_node, MFnDependencyNode& node) +{ + MPlugArray AllConnections; + MPlugArray AllBumpConnections; + + m_Plug = node.findPlug("normalCamera", true); + m_Plug.connectedTo(AllConnections, true, false); + + for (int i = 0; i < AllConnections.length(); i++) { + if (AllConnections[i].node().apiType() == MFn::kBump) { + MFnDependencyNode BumpNode(AllConnections[i].node()); + + BumpNode.findPlug("bumpValue").connectedTo(AllBumpConnections, true, false); + for (int j = 0; j < AllBumpConnections.length(); j++) { + if (AllBumpConnections[j].node().hasFn(MFn::kFileTexture)) { + MFnDependencyNode TextureNode(AllBumpConnections[j].node()); + + std::string FullPath = TextureNode.findPlug("ftn").asString().asChar(); + m_TexturePaths.push_back(FullPath); + + MString workspace; + MStatus status = MGlobal::executeCommand(MString("workspace -q -rd;"), + workspace); + FullPath = FullPath.substr(workspace.length()); + FullPath = FullPath.substr(FullPath.find_first_of("/") + 1); + material_node.NormalMapFile = FullPath.erase(FullPath.find_last_of("."), FullPath.find_last_of(".") - FullPath.size()); + material_node.NormalMapFileLength = material_node.NormalMapFile.length() + 1; + return true; + } + } + } + } + + return false; +} + +bool Material::findSpecularTexture(MaterialNode& material_node, MFnDependencyNode& node) +{ + MPlugArray AllConnections; + + m_Plug = node.findPlug("specularColor", true); + m_Plug.connectedTo(AllConnections, true, false); + + for (int i = 0; i < AllConnections.length(); i++) { + if (AllConnections[i].node().hasFn(MFn::kFileTexture)) { + MFnDependencyNode TextureNode(AllConnections[i].node()); + + std::string FullPath = TextureNode.findPlug("ftn").asString().asChar(); + m_TexturePaths.push_back(FullPath); + + MString workspace; + MStatus status = MGlobal::executeCommand(MString("workspace -q -rd;"), + workspace); + FullPath = FullPath.substr(workspace.length()); + FullPath = FullPath.substr(FullPath.find_first_of("/") + 1); + material_node.SpecularMapFile = FullPath.erase(FullPath.find_last_of("."), FullPath.find_last_of(".") - FullPath.size()); + material_node.SpecularMapFileLength = material_node.SpecularMapFile.length() + 1; + return true; + } + } + return false; +} + +bool Material::findIncandescenceTexture(MaterialNode& material_node, MFnDependencyNode& node) +{ + MPlugArray AllConnections; + + m_Plug = node.findPlug("incandescence", true); + m_Plug.connectedTo(AllConnections, true, false); + + for (int i = 0; i < AllConnections.length(); i++) { + if (AllConnections[i].node().hasFn(MFn::kFileTexture)) { + MFnDependencyNode TextureNode(AllConnections[i].node()); + + std::string FullPath = TextureNode.findPlug("ftn").asString().asChar(); + m_TexturePaths.push_back(FullPath); + + MString workspace; + MStatus status = MGlobal::executeCommand(MString("workspace -q -rd;"), + workspace); + FullPath = FullPath.substr(workspace.length()); + FullPath = FullPath.substr(FullPath.find_first_of("/") + 1); + material_node.IncandescenceMapFile = FullPath.erase(FullPath.find_last_of("."), FullPath.find_last_of(".") - FullPath.size()); + material_node.IncandescenceMapFileLength = material_node.IncandescenceMapFile.length() + 1; + return true; + } + } + return false; +} + +// Returns the absolute path for all textures. Use for copying texture files. +std::vector* Material::TexturePaths() +{ + return &m_TexturePaths; +} + +// Traverse the DAG and grab all the materials +std::vector* Material::DoIt(Mesh mesh) +{ + // All materials we care about inherit from Lambert + MItDependencyNodes matIt(MFn::kLambert); + m_AllMaterials.clear(); + while (!matIt.isDone()) { + MFnDependencyNode MaterialFnDN(matIt.thisNode()); + MaterialNode MaterialStorage; + bool meshHasMaterial = false; + //Mesh Indices is a map with : indices> + int totalIndices = 0; + for (auto aMeshMaterial : mesh.Indices) { + MGlobal::displayInfo(MString() + "Material: " + aMeshMaterial.first.c_str() + " " + MaterialFnDN.name().asChar()); + if (aMeshMaterial.first.compare(MaterialFnDN.name().asChar()) == 0) { + meshHasMaterial = true; + MaterialStorage.IndexStart = totalIndices; + MaterialStorage.IndexEnd = totalIndices + aMeshMaterial.second.size() - 1; + break; + } + totalIndices += aMeshMaterial.second.size(); + } + if (meshHasMaterial) { + grabLambertProperties(MaterialStorage, MaterialFnDN); + + if (matIt.thisNode().hasFn(MFn::kPhong)) { + grabPhongProperties(MaterialStorage, MaterialFnDN); + + } else if (matIt.thisNode().hasFn(MFn::kBlinn)) { + grabBlinnProperties(MaterialStorage, MaterialFnDN); + + } else if (matIt.thisNode().hasFn(MFn::kLambert)) { + MaterialStorage.ReflectionFactor = 0.0f; + MaterialStorage.SpecularExponent = 0.0f; + } + + m_AllMaterials.push_back(MaterialStorage); + } + matIt.next(); + } + + return &m_AllMaterials; +} + diff --git a/tools/MayaExporter/MayaExporter/Material.h b/tools/MayaExporter/MayaExporter/Material.h new file mode 100644 index 00000000..e405dd07 --- /dev/null +++ b/tools/MayaExporter/MayaExporter/Material.h @@ -0,0 +1,115 @@ +#ifndef Material_Material_h__ +#define Material_Material_h__ + +#include +#include +#include +#include +#include + +#include "MayaIncludes.h" +#include "OutputData.h" +#include "Mesh.h" + +class MaterialNode : public OutputData +{ +public: + std::string Name; + + float ReflectionFactor; + float SpecularExponent; + + float DiffuseColor[3]{ 1.0f, 1.0f, 1.0f }; + unsigned int ColorMapFileLength = 0; + std::string ColorMapFile; + + float SpecularColor[3]{ 1.0f, 1.0f, 1.0f }; + unsigned int SpecularMapFileLength = 0; + std::string SpecularMapFile; + + unsigned int NormalMapFileLength = 0; + std::string NormalMapFile; + + float IncandescenceColor[3]{ 1.0f, 1.0f, 1.0f }; + unsigned int IncandescenceMapFileLength = 0; + std::string IncandescenceMapFile; + + unsigned int IndexStart; + unsigned int IndexEnd; + + virtual void WriteBinary(std::ostream& out) + { + out.write((char*)&ColorMapFileLength, sizeof(unsigned int)); + out.write((char*)&NormalMapFileLength, sizeof(unsigned int)); + out.write((char*)&SpecularMapFileLength, sizeof(unsigned int)); + out.write((char*)&IncandescenceMapFileLength, sizeof(unsigned int)); + + out.write((char*)&SpecularExponent, sizeof(float)); + out.write((char*)&ReflectionFactor, sizeof(float)); + out.write((char*)&DiffuseColor, sizeof(float) * 3); + out.write((char*)&SpecularColor, sizeof(float) * 3); + out.write((char*)&IncandescenceColor, sizeof(float) * 3); + out.write((char*)&IndexStart, sizeof(unsigned int)); + out.write((char*)&IndexEnd, sizeof(unsigned int)); + + out.write(ColorMapFile.c_str(), ColorMapFileLength); + out.write(NormalMapFile.c_str(), NormalMapFileLength); + out.write(SpecularMapFile.c_str(), SpecularMapFileLength); + out.write(IncandescenceMapFile.c_str(), IncandescenceMapFileLength); + } + + virtual void WriteASCII(std::ostream& out) const + { + out << "New Material _ not in binary" << endl; + out << "number of indices: " << Name << " _ not in binary" << endl; + + out << "ColorMapFile length: " << ColorMapFileLength << endl; + out << "NormalMapFile length: " << NormalMapFileLength << endl; + out << "SpecularMapFile length: " << SpecularMapFileLength << endl; + out << "IncandescenceMapFile length: " << IncandescenceMapFileLength << endl; + + out << "SpecularExponent: " << SpecularExponent << endl; + out << "ReflectionFactor: " << ReflectionFactor << endl; + out << "DiffuseColor: " << DiffuseColor[0] << " " << DiffuseColor[1] << " " << DiffuseColor[2] << endl; + out << "SpecularColor: " << SpecularColor[0] << " " << SpecularColor[1] << " " << SpecularColor[2] << endl; + out << "IncandescenceColor: " << IncandescenceColor[0] << " " << IncandescenceColor[1] << " " << IncandescenceColor[2] << endl; + out << "IndexStart: " << IndexStart << endl; + out << "IndexEnd: " << IndexEnd << endl; + + if (ColorMapFileLength > 0) + out << "ColorMapFile: " << ColorMapFile << endl; + + if (NormalMapFileLength > 0) + out << "NormalMapFile: " << NormalMapFile << endl; + + if (SpecularMapFileLength > 0) + out << "SpecularMapFile: " << SpecularMapFile << endl; + + if (IncandescenceMapFileLength > 0) + out << "IncandescenceMapFile: " << IncandescenceMapFile << endl; + } +}; + +class Material +{ +public: + Material() {}; + ~Material() {}; + std::vector* DoIt(Mesh mesh); + std::vector* TexturePaths(); +private: + MPlug m_Plug; + + std::vector m_AllMaterials; + std::vector m_TexturePaths; + + bool findColorTexture(MaterialNode& material_node, MFnDependencyNode& node); + bool findNormalTexture(MaterialNode& material_node, MFnDependencyNode& node); + bool findSpecularTexture(MaterialNode& material_node, MFnDependencyNode& node); + bool findIncandescenceTexture(MaterialNode& material_node, MFnDependencyNode& node); + void grabLambertProperties(MaterialNode& material_node, MFnDependencyNode& node); + void grabBlinnProperties(MaterialNode& material_node, MFnDependencyNode& node); + void grabPhongProperties(MaterialNode& material_node, MFnDependencyNode& node); +}; + +#endif // Material_Material_h__ \ No newline at end of file diff --git a/tools/MayaExporter/MayaExporter/MayaExporter.vcxproj b/tools/MayaExporter/MayaExporter/MayaExporter.vcxproj index 42b1b45a..4a7ac07e 100644 --- a/tools/MayaExporter/MayaExporter/MayaExporter.vcxproj +++ b/tools/MayaExporter/MayaExporter/MayaExporter.vcxproj @@ -140,6 +140,7 @@ MultiThreadedDLL true + Disabled Windows @@ -152,6 +153,8 @@ + + true @@ -172,6 +175,9 @@ true + + + @@ -194,6 +200,11 @@ + + + + + Moc%27ing Menu.h... .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp @@ -213,6 +224,7 @@ $(QTDIR)\bin\moc.exe;%(FullPath);$(QTDIR)\bin\moc.exe;%(FullPath) + diff --git a/tools/MayaExporter/MayaExporter/MayaExporter.vcxproj.filters b/tools/MayaExporter/MayaExporter/MayaExporter.vcxproj.filters index d5bcfd00..ae3d2478 100644 --- a/tools/MayaExporter/MayaExporter/MayaExporter.vcxproj.filters +++ b/tools/MayaExporter/MayaExporter/MayaExporter.vcxproj.filters @@ -50,6 +50,21 @@ Source Files + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + @@ -69,5 +84,23 @@ Generated Files + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + \ No newline at end of file diff --git a/tools/MayaExporter/MayaExporter/MayaIncludes.h b/tools/MayaExporter/MayaExporter/MayaIncludes.h index 3573d30d..7322bdc5 100644 --- a/tools/MayaExporter/MayaExporter/MayaIncludes.h +++ b/tools/MayaExporter/MayaExporter/MayaIncludes.h @@ -30,6 +30,21 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // Wrappers @@ -58,5 +73,6 @@ #pragma comment(lib,"Foundation.lib") #pragma comment(lib,"OpenMaya.lib") #pragma comment(lib,"OpenMayaUI.lib") +#pragma comment (lib, "OpenMayaAnim.lib") #endif \ No newline at end of file diff --git a/tools/MayaExporter/MayaExporter/Menu.cpp b/tools/MayaExporter/MayaExporter/Menu.cpp index 6af300aa..9cc6de91 100644 --- a/tools/MayaExporter/MayaExporter/Menu.cpp +++ b/tools/MayaExporter/MayaExporter/Menu.cpp @@ -10,223 +10,200 @@ Menu::Menu() Menu::Menu(QDialog* dialog) { // Save the dialog pointer. Needed when the application gets destroyed - dialogPointer = dialog; + m_DialogPointer = dialog; // Create QpushButtons & give them names - exportSelectedButton = new QPushButton("&Export Selected", this); - browseButton = new QPushButton("&...", this); - exportAllButton = new QPushButton("&Export All", this); - cancelButton = new QPushButton("&Cancel", this); + m_BrowseButton = new QPushButton("&...", this); + m_ExportAllButton = new QPushButton("&Export", this); + m_CancelButton = new QPushButton("&Cancel", this); + m_AddClipsButton = new QPushButton("&Add Clips", this); + m_RemoveClipsButton = new QPushButton("&Remove Latest Clip", this); // Option box and checkboxes QGroupBox *optionsBox = new QGroupBox(tr("Options")); - exportAnimationsButton = new QCheckBox(tr("&Export Animations")); - copyTexturesButton = new QCheckBox(tr("&Copy Textures")); - button3 = new QCheckBox(tr("option3")); + m_ExportSelectedButton = new QCheckBox(tr("&Export Selected")); + m_ExportAnimationsButton = new QCheckBox(tr("&Export Animations")); + m_ExportMaterialButton = new QCheckBox(tr("&Export Material"));; - exportAnimationsButton->setChecked(true); - copyTexturesButton->setChecked(true); + m_ExportAnimationsButton->setChecked(true); + m_ExportMaterialButton->setChecked(true); QVBoxLayout *vbox = new QVBoxLayout; - vbox->addWidget(exportAnimationsButton); - vbox->addWidget(copyTexturesButton); - vbox->addWidget(button3); + vbox->addWidget(m_ExportSelectedButton); + vbox->addWidget(m_ExportAnimationsButton); + vbox->addWidget(m_ExportMaterialButton); + vbox->addStretch(1); optionsBox->setLayout(vbox); // Connect the buttons with signals & functions - connect(exportSelectedButton, SIGNAL(clicked(bool)), this, SLOT(ExportSelected(bool))); - connect(browseButton, SIGNAL(clicked(bool)), this, SLOT(ExportPathClicked(bool))); - connect(exportAllButton, SIGNAL(clicked(bool)), this, SLOT(ExportAll(bool))); - connect(cancelButton, SIGNAL(clicked(bool)), this, SLOT(CancelClicked(bool))); + connect(m_BrowseButton, SIGNAL(clicked(bool)), this, SLOT(ExportPathClicked(bool))); + connect(m_ExportAllButton, SIGNAL(clicked(bool)), this, SLOT(ExportAll(bool))); + connect(m_CancelButton, SIGNAL(clicked(bool)), this, SLOT(CancelClicked(bool))); + connect(m_AddClipsButton, SIGNAL(clicked(bool)), this, SLOT(AddClipClicked(bool))); + connect(m_RemoveClipsButton, SIGNAL(clicked(bool)), this, SLOT(RemoveClipClicked(bool))); - connect(exportAnimationsButton, SIGNAL(clicked(bool)), this, SLOT(Button1Clicked(bool))); - connect(copyTexturesButton, SIGNAL(clicked(bool)), this, SLOT(Button2Clicked(bool))); - connect(button3, SIGNAL(clicked(bool)), this, SLOT(Button3Clicked(bool))); + connect(m_ExportSelectedButton, SIGNAL(clicked(bool)), this, SLOT(NULL)); + connect(m_ExportAnimationsButton, SIGNAL(clicked(bool)), this, SLOT(NULL)); + connect(m_ExportMaterialButton, SIGNAL(clicked(bool)), this, SLOT(NULL)); // Creating several layouts, adding widgets & adding them to one layout in the end QHBoxLayout* topLayout = new QHBoxLayout; QVBoxLayout* midLayout = new QVBoxLayout; QHBoxLayout* botLayout = new QHBoxLayout; QVBoxLayout* baseLayout = new QVBoxLayout; + QHBoxLayout* clipButtonLayout = new QHBoxLayout; + QHBoxLayout* startEndLabelLayout = new QHBoxLayout; + m_ClipLayout = new QVBoxLayout; - exportPath = new QLineEdit; - fileDialog = new QFileDialog; + + m_ExportPath = new QLineEdit; + m_FileDialog = new QFileDialog; + QString tmpPath("C:/Users/Nickelodion/Desktop/workspace/tacticalZ/assets/models/"); + m_ExportPath->setText(tmpPath); QLabel* exportLabel = new QLabel; exportLabel->setText("Export Path:"); - + QLabel* nameLabel = new QLabel; + nameLabel->setText("Name:"); + QLabel* startLabel = new QLabel; + startLabel->setText("Start:"); + QLabel* endLabel = new QLabel; + endLabel->setText("End:"); + + //exportLabel->setText("Export Path:"); + midLayout->addWidget(optionsBox); topLayout->addWidget(exportLabel); - topLayout->addWidget(exportPath); - topLayout->addWidget(browseButton); + topLayout->addWidget(m_ExportPath); + topLayout->addWidget(m_BrowseButton); - botLayout->addWidget(exportSelectedButton); - botLayout->addWidget(exportAllButton); - botLayout->addWidget(cancelButton); + botLayout->addWidget(m_ExportAllButton); + botLayout->addWidget(m_CancelButton); + + startEndLabelLayout->addWidget(nameLabel); + startEndLabelLayout->addWidget(startLabel); + startEndLabelLayout->addWidget(endLabel); + + clipButtonLayout->addWidget(m_AddClipsButton); + clipButtonLayout->addWidget(m_RemoveClipsButton); baseLayout->addLayout(topLayout); baseLayout->addLayout(midLayout); baseLayout->addSpacing(10); - baseLayout->addLayout(botLayout); + + baseLayout->addSpacing(10); + baseLayout->addLayout(clipButtonLayout); + baseLayout->addLayout(startEndLabelLayout); + baseLayout->addLayout(m_ClipLayout); baseLayout->addStretch(); // Set the layout for our window dialog->setLayout(baseLayout); -} + this->AddClipClicked(true); + //for (unsigned int i = 0; i < 3; i++) { + // this->AddClipClicked(true); + //} -void Menu::ExportSelected(bool checked) -{ - // Retrieving the objects we currently have selected - MSelectionList selected; - MGlobal::getActiveSelectionList(selected); - - // Loop through or list of selection(s) - for (unsigned int i = 0; i < selected.length();i++) - { - MObject object; - selected.getDependNode(i, object); - MFnDependencyNode thisNode(object); - - cout << thisNode.name().asChar() << endl; - GetMeshData(object); - } - if (exportPath->text().isEmpty()) - cout << "Please select a folder." << endl; - else - cout << exportPath->text().toLocal8Bit().constData() << endl; } void Menu::ExportPathClicked(bool) { // Opens up a file dialog. Save/Changes the name in the exportPath - fileDialog->setFileMode(QFileDialog::Directory); - fileDialog->setOption(QFileDialog::ShowDirsOnly); - QString fileName = fileDialog->getExistingDirectory(this, "Select", "/home", QFileDialog::ShowDirsOnly); - exportPath->setText(fileName); + m_FileDialog->setFileMode(QFileDialog::Directory); + m_FileDialog->setOption(QFileDialog::ShowDirsOnly); + QString fileName = m_FileDialog->getExistingDirectory(this, "Select", "/home", QFileDialog::ShowDirsOnly); + m_ExportPath->setText(fileName); +} + +void Menu::AddClipClicked(bool) +{ + QHBoxLayout* tempLayout = new QHBoxLayout; + + QLineEdit* nameLineEdit = new QLineEdit; + QLineEdit* startLineEdit = new QLineEdit; + QLineEdit* endLineEdit = new QLineEdit; + + m_AnimationClipName.push_back(nameLineEdit); + m_StartFrameLines.push_back(startLineEdit); + m_EndFrameLines.push_back(endLineEdit); + + tempLayout->addWidget(nameLineEdit); + tempLayout->addWidget(startLineEdit); + tempLayout->addWidget(endLineEdit); + + m_ClipLayout->addLayout(tempLayout); + //m_ClipLayout->update(); + layouts.push_back(tempLayout); +} + +void Menu::RemoveClipClicked(bool) +{ + if (m_StartFrameLines.size() > 0) { + QLayoutItem* tempWidget;// = m_ClipLayout->itemAt(0); + + for (unsigned int i = 0; i < layouts.size(); i++) { + while ((tempWidget = layouts[layouts.size() - 1]->takeAt(0)) != 0) { + delete tempWidget->widget(); + delete tempWidget; + } + } + + m_ClipLayout->removeItem(tempWidget); + m_ClipLayout->update(); + + layouts.pop_back(); + m_StartFrameLines.pop_back(); + m_EndFrameLines.pop_back(); + m_AnimationClipName.pop_back(); + } } void Menu::ExportAll(bool) { - MDagPath path; - - // Loop through all nodes in the scene - MItDependencyNodes it(MFn::kInvalid); - for (;!it.isDone();it.next()) - { - MObject node = it.thisNode(); - if (node.hasFn(MFn::kMesh)) - { - MFnDependencyNode thisNode(node); + if (m_ExportPath->text().isEmpty()) { + MGlobal::displayError(MString() + "Please select a folder."); + return; + } - cout << thisNode.name().asChar() << endl; - GetMeshData(node); - } - } - if (exportPath->text().isEmpty()) - cout << "Please select a folder." << endl; - else - cout << exportPath->text().toLocal8Bit().constData() << endl; + //Export meshes + if (!m_Export.Meshes(m_ExportPath->text().toLocal8Bit().constData(), m_ExportSelectedButton->isChecked())) { + MGlobal::displayError(MString() + "Could not export mesh"); + return; + } + + if (m_ExportMaterialButton->isChecked()) { + if (!m_Export.Materials(m_ExportPath->text().toLocal8Bit().constData())) { + MGlobal::displayError(MString() + "Could not export materials"); + return; + } + } + + std::vector animations; + for (unsigned int i = 0; i < m_AnimationClipName.size(); i++) { + Export::AnimationInfo thisClip; + thisClip.Name = std::string(m_AnimationClipName[i]->text().toLocal8Bit().constData()); + thisClip.Start = m_StartFrameLines[i]->text().toInt(); + thisClip.End = m_EndFrameLines[i]->text().toInt(); + + animations.push_back(thisClip); + } + if (m_ExportAnimationsButton->isChecked()) { + //Export Animations + if (!m_Export.Animations(m_ExportPath->text().toLocal8Bit().constData(), animations)) { + MGlobal::displayError(MString() + "Could not export animations"); + return; + } + } } void Menu::CancelClicked(bool) { - dialogPointer->close(); -} - -void Menu::Button1Clicked(bool) -{ - if(exportAnimationsButton->isChecked()) - cout << "1 checked!" << endl; - else - cout << "1 unchecked!" << endl; -} - -void Menu::Button2Clicked(bool) -{ - if (copyTexturesButton->isChecked()) - cout << "2 checked!" << endl; - else - cout << "2 unchecked!" << endl; -} - -void Menu::Button3Clicked(bool) -{ - if (button3->isChecked()) - cout << "3 checked!" << endl; - else - cout << "3 unchecked!" << endl; -} - -void Menu::GetMeshData(MObject object) -{ - // In here, we retrieve triangulated polygons from the mesh - MFnMesh mesh(object); - - map> vertexToIndex; - - vector verticesData; - vectorindexArray; - - MIntArray intdexOffsetVertexCount, vertices, triangleList; - MPointArray dummy; - - UINT vertexIndex; - MVector normal; - MPoint pos; - float2 UV; - VertexLayout thisVertex; - - for (MItMeshPolygon meshPolyIter(object); !meshPolyIter.isDone(); meshPolyIter.next()) - { - vector localVertexToGlobalIndex; - meshPolyIter.getVertices(vertices); - - meshPolyIter.getTriangles(dummy, triangleList); - UINT indexOffset = verticesData.size(); - - for (UINT i = 0; i < vertices.length(); i++) - { - vertexIndex = meshPolyIter.vertexIndex(i); - pos = meshPolyIter.point(i); - pos.get(thisVertex.pos); - - meshPolyIter.getNormal(i, normal); - thisVertex.normal[0] = normal[0]; - thisVertex.normal[1] = normal[1]; - thisVertex.normal[2] = normal[2]; - - meshPolyIter.getUV(i, UV); - thisVertex.uv[0] = UV[0]; - thisVertex.uv[1] = UV[1]; - - verticesData.push_back(thisVertex); - localVertexToGlobalIndex.push_back(vertexIndex); - - cout << "Pos: " << thisVertex.pos[0] << "/" << thisVertex.pos[1] << "/" << thisVertex.pos[2] << endl; - cout << "Normals: " << thisVertex.normal[0] << "/" << thisVertex.normal[1] << "/" << thisVertex.normal[2] << endl; - cout << "UV: " << thisVertex.uv[0] << "/" << thisVertex.uv[1] << endl; - } - for (UINT i = 0; i < triangleList.length(); i++) - { - UINT k = 0; - while (localVertexToGlobalIndex[k] != triangleList[i]) - k++; - indexArray.push_back(indexOffset + k); - } - } - -} - -void Menu::exportMaterial(MObject object) -{ - MItDependencyNodes matIt(MFn::kLambert); - - + m_DialogPointer->close(); } Menu::~Menu() @@ -235,5 +212,8 @@ Menu::~Menu() //delete browseButton; //delete exportPath; //delete fileDialog; - fileDialog->~QFileDialog(); + m_FileDialog->~QFileDialog(); + + //delete m_Export; + //delete MaterialHandler; } \ No newline at end of file diff --git a/tools/MayaExporter/MayaExporter/Menu.h b/tools/MayaExporter/MayaExporter/Menu.h index 44eca702..fb95a953 100644 --- a/tools/MayaExporter/MayaExporter/Menu.h +++ b/tools/MayaExporter/MayaExporter/Menu.h @@ -1,10 +1,9 @@ -#ifndef BUTTONS_H -#define BUTTONS_H +#ifndef Menu_Menu_h__ +#define Menu_Menu_h__ #include #include -#include "MayaIncludes.h" // Qt #pragma comment(lib, "QtCore4") #pragma comment(lib, "QtGui4") @@ -30,13 +29,11 @@ #include #include #include +#include +#include -struct VertexLayout -{ - float pos[3]; - float normal[3]; - float uv[2]; -}; +#include "MayaIncludes.h" +#include "Export.h" class Menu : public QWidget { @@ -45,35 +42,36 @@ public: Menu(QDialog* dialog); ~Menu(); - void GetMeshData(MObject object); - void exportMaterial(MObject object); - private slots: - void ExportSelected(bool checked); void ExportPathClicked(bool); + void AddClipClicked(bool); + void RemoveClipClicked(bool); void ExportAll(bool); void CancelClicked(bool); - void Button1Clicked(bool); - void Button2Clicked(bool); - void Button3Clicked(bool); - - private: Menu(); - QPushButton* exportSelectedButton; - QPushButton* browseButton; - QPushButton* exportAllButton; - QPushButton* cancelButton; + std::vector m_AnimationClipName; + std:: vector m_StartFrameLines; + std::vector m_EndFrameLines; + std::vector layouts; + QVBoxLayout* m_ClipLayout; - QCheckBox* exportAnimationsButton; - QCheckBox* copyTexturesButton; - QCheckBox* button3; + QPushButton* m_BrowseButton = nullptr; + QPushButton* m_ExportAllButton = nullptr; + QPushButton* m_CancelButton = nullptr; + QPushButton* m_AddClipsButton = nullptr; + QPushButton* m_RemoveClipsButton = nullptr; - QLineEdit* exportPath; - QFileDialog* fileDialog; - QDialog* dialogPointer; + QCheckBox* m_ExportSelectedButton = nullptr; + QCheckBox* m_ExportAnimationsButton = nullptr; + QCheckBox* m_ExportMaterialButton = nullptr; + QLineEdit* m_ExportPath = nullptr; + QFileDialog* m_FileDialog = nullptr; + QDialog* m_DialogPointer = nullptr; + + Export m_Export; }; #endif \ No newline at end of file diff --git a/tools/MayaExporter/MayaExporter/Mesh.cpp b/tools/MayaExporter/MayaExporter/Mesh.cpp new file mode 100644 index 00000000..6af8a557 --- /dev/null +++ b/tools/MayaExporter/MayaExporter/Mesh.cpp @@ -0,0 +1,402 @@ +#pragma once +#include "Mesh.h" + +using namespace std; + +MeshClass::MeshClass() +{ + +} + +std::map MeshClass::GetWeightData() +{ + MS status; + map weightMap; + + MItDependencyNodes it(MFn::kSkinClusterFilter); + + while (!it.isDone()) { + + MObject object = it.thisNode(&status); + if (status != MS::kSuccess) { + MGlobal::displayError(MString() + " it.thisNode() ERROR: " + status.errorString()); + break; + } + MFnSkinCluster skinCluster(object, &status); + if (status != MS::kSuccess) { + MGlobal::displayError(MString() + "skinCluster() ERROR: " + status.errorString()); + break; + } + MDagPathArray influences; + + unsigned int nrOfInfluences = skinCluster.influenceObjects(influences,&status); + if (status != MS::kSuccess) { + MGlobal::displayError(MString() + "skinCluster.influenceObjects() ERROR: " + status.errorString()); + break; + } + + unsigned int index; + index = skinCluster.indexForOutputConnection(0,&status); + if (status != MS::kSuccess) { + MGlobal::displayError(MString() + "skinCluster.indexForOutputConnection() ERROR: " + status.errorString()); + break; + } + MDagPath skinPath; + status = skinCluster.getPathAtIndex(index, skinPath); + if (status != MS::kSuccess) { + MGlobal::displayError(MString() + "skinCluster.getPathAtIndex() ERROR: " + status.errorString()); + break; + } + + MItGeometry geomIter(skinPath); + //for (unsigned int i = 0; i < nrOfInfluences; i++) { + // MGlobal::displayInfo(MString() + " Influence object name: " + influences[i].partialPathName().asChar()); + //} + WeightInfo weightInfo; + + while (!geomIter.isDone()) { + MObject comp = geomIter.component(&status); + if (status != MS::kSuccess) { + MGlobal::displayError(MString() + "geomIter.component() ERROR: " + status.errorString()); + break; + } + MFloatArray weights; + unsigned int influenceCount; + status = skinCluster.getWeights(skinPath, comp, weights, influenceCount); + if (status != MS::kSuccess) { + MGlobal::displayError(MString() + "skinCluster.getWeights() ERROR: " + status.errorString()); + break; + } + MFnDependencyNode test(comp); + unsigned int nrOfWeights = 0; + + for (unsigned int j = 0; j < weights.length() && nrOfWeights != 4; j++) { + if (weights[j] > 0.00001) { + weightInfo.BoneWeights[nrOfWeights] = weights[j]; + weightInfo.BoneIndices[nrOfWeights] = j; + nrOfWeights++; + } + } + + float totalWeight = 0.0f; + for (unsigned int i = 0; i < 4; i++) { + totalWeight += weightInfo.BoneWeights[i]; + } + for (unsigned int i = 0; i < 4; i++) { + weightInfo.BoneWeights[i] /= totalWeight; + } + weightMap[geomIter.index()] = weightInfo; + + + for (unsigned int k = 0; k!=nrOfWeights; k++) { + MGlobal::displayInfo(MString() + "influence: " + weightInfo.BoneIndices[k] + " weight: " + weightInfo.BoneWeights[k]); + } + geomIter.next(); + } + it.next(); + } + return weightMap; +} + +Mesh MeshClass::GetMeshData(MObjectArray object) +{ + MS status; + Mesh newMesh; + vector& vertexList = newMesh.Vertices; + map>& indexLists = newMesh.Indices; + for (int ObjectID = 0; ObjectID < object.length(); ObjectID++) { + if (!object[ObjectID].hasFn(MFn::kMesh)) + continue; + + MObject node = object[ObjectID]; + MFnDependencyNode thisNode(node); + MPlugArray connections; + thisNode.findPlug("inMesh").connectedTo(connections, true, true); + MGlobal::displayInfo(MString() + "inMesh"); + bool hasSkin = false; + MPlug weightList, weights; + MObject weightListObject; + for (unsigned int i = 0; i < connections.length(); i++) { + if (connections[i].node().apiType() == MFn::kSkinClusterFilter) { + MFnSkinCluster skinCluster(connections[i].node()); + weightList = skinCluster.findPlug("weightList", &status); + weightListObject = weightList.attribute(); + weights = skinCluster.findPlug("weights"); + hasSkin = true; + break; + } + } + + + // In here, we retrieve triangulated polygons from the mesh + MFnMesh mesh(object[ObjectID]); + MDagPathArray dagPaths; + status = MDagPath::getAllPathsTo(object[ObjectID], dagPaths); + if (status != MS::kSuccess) { + MGlobal::displayError(MString() + "MDagPath::getAllPathsTo() ERROR: " + status.errorString()); + break; + } + + for (int pathID = 0; pathID < dagPaths.length(); pathID++) { + MGlobal::displayInfo(dagPaths[pathID].fullPathName()); + MDagPath thisMeshPath(dagPaths[pathID]); + + MMatrix transformMatrix = thisMeshPath.inclusiveMatrix(&status); + if (status != MS::kSuccess) { + MGlobal::displayError(MString() + "thisMeshPath.inclusiveMatrix() ERROR: " + status.errorString() + " for " + thisMeshPath.fullPathName()); + break; + } + + map> vertexToIndex;; + + MIntArray intdexOffsetVertexCount, vertices, triangleList; + MPointArray dummy; + unsigned int vertexIndex; + MVector normal; + MPoint pos; + float2 UV; + double biTangent[3]; + double biNormal[3]; + MFloatVectorArray Tangents; + MFloatVectorArray biNormals; + + MObjectArray shaderList; + MIntArray shaderIndexList; + status = mesh.getConnectedShaders(0, shaderList, shaderIndexList); + if (status != MS::kSuccess) { + MGlobal::displayError(MString() + "mesh.getConnectedShaders() ERROR: " + status.errorString() + " for " + thisMeshPath.fullPathName()); + break; + } + + if (shaderList.length() == 0) { + MGlobal::displayError(MString() + "Object: \"" + thisMeshPath.fullPathName() + "\" have no material and will not be exported"); + break; + } + map> materialFaceIDs; + MGlobal::displayInfo(MString() + "shaderIndexList: " + shaderIndexList.length()); + MGlobal::displayInfo(MString() + "shaderList: " + shaderList.length()); + MPlugArray plugArray; + for (int i = 0; i < shaderIndexList.length(); i++) { + MFnDependencyNode shader(shaderList[shaderIndexList[i]]); + MPlug p_Plug = shader.findPlug("surfaceShader", status); + if (status != MS::kSuccess) { + MGlobal::displayError(MString() + "shader.findPlug(\"surfaceShader\") ERROR: " + status.errorString() + " for " + thisMeshPath.fullPathName()); + continue; + } + if (p_Plug.connectedTo(plugArray, true, false, &status)) { + if (status != MS::kSuccess) { + MGlobal::displayError(MString() + "p_Plug.connectedTo() ERROR in if: " + status.errorString() + " for " + thisMeshPath.fullPathName()); + continue; + } + MFnDependencyNode node = plugArray[0].node(); + materialFaceIDs[node.name().asChar()].push_back(i); + } + if (status != MS::kSuccess) { + MGlobal::displayError(MString() + "p_Plug.connectedTo() ERROR: " + status.errorString() + " for " + thisMeshPath.fullPathName()); + continue; + } + } + + // map vertexWeights = GetWeightData(); + status = mesh.getTangents(Tangents, MSpace::kObject); + if (status != MS::kSuccess) { + MGlobal::displayError(MString() + "mesh.getTangents ERROR: " + status.errorString() + " for " + thisMeshPath.fullPathName()); + continue; + } + status = mesh.getBinormals(biNormals, MSpace::kObject); + if (status != MS::kSuccess) { + MGlobal::displayError(MString() + "mesh.getBinormals ERROR: " + status.errorString() + " for " + thisMeshPath.fullPathName()); + continue; + } + if(Tangents.length() == 0 || biNormals.length() == 0){ + MGlobal::displayError(MString() + "Unknown ERROR with " + thisMeshPath.fullPathName()); + continue; + } + MItMeshFaceVertex faceVert(object[ObjectID]); + int intDummy = 0; + + MItMeshPolygon meshPolyIter(object[ObjectID]); + MFloatPointArray positions; + + mesh.getPoints(positions); + + for (auto aMaterial : materialFaceIDs) { + for (auto faceID : aMaterial.second) { + vector> localVertexToGlobalIndex; + + status = meshPolyIter.setIndex(faceID, intDummy); + if (status != MS::kSuccess) { + MGlobal::displayError(MString() + " meshPolyIter.setIndex() ERROR: " + status.errorString() + " for faceID " + faceID + " in mesh " + thisMeshPath.fullPathName()); + break; + } + + status = meshPolyIter.getVertices(vertices); + if (status != MS::kSuccess) { + MGlobal::displayError(MString() + " meshPolyIter.getVertices() ERROR: " + status.errorString() + " for faceID " + faceID + " in mesh " + thisMeshPath.fullPathName()); + break; + } + + status = meshPolyIter.getTriangles(dummy, triangleList); + if (status != MS::kSuccess) { + MGlobal::displayError(MString() + " meshPolyIter.getTriangles() ERROR: " + status.errorString() + " for faceID " + faceID + " in mesh " + thisMeshPath.fullPathName()); + break; + } + //MGlobal::displayInfo("Befor Second Loop"); + for (unsigned int i = 0; i < vertices.length(); i++) { + VertexLayout thisVertex; + + vertexIndex = meshPolyIter.vertexIndex(i, &status); + if (status != MS::kSuccess) { + MGlobal::displayError(MString() + " meshPolyIter.vertexIndex() ERROR: " + status.errorString() + "for local vertex " + i + " in " + faceID + " in mesh " + thisMeshPath.fullPathName()); + break; + } + + status = faceVert.setIndex(meshPolyIter.index(), i, intDummy, intDummy); + if (status != MS::kSuccess) { + MGlobal::displayError(MString() + "faceVert.setIndex() ERROR: " + status.errorString() + "for local vertex " + i + " in " + faceID + " in mesh " + thisMeshPath.fullPathName()); + break; + } + //MGlobal::displayInfo("In Second Loop"); + //pos = faceVert.position(MSpace::kTransform); + //mesh.getPoint(vertexIndex, pos, MSpace::kPostTransform); + pos = positions[vertexIndex]; + pos = pos * transformMatrix; + if (abs(pos.x) > 0.0001) + thisVertex.Pos[0] = pos.x; + if (abs(pos.y) > 0.0001) + thisVertex.Pos[1] = pos.y; + if (abs(pos.z) > 0.0001) + thisVertex.Pos[2] = pos.z; + + status = faceVert.getNormal(normal, MSpace::kObject); + if (status != MS::kSuccess) { + MGlobal::displayError(MString() + "faceVert.getNormal() ERROR: " + status.errorString() + "for local vertex " + i + " in " + faceID + " in mesh " + thisMeshPath.fullPathName()); + break; + } + if (abs(normal[0]) > 0.0001) + thisVertex.Normal[0] = normal[0]; + if (abs(normal[1]) > 0.0001) + thisVertex.Normal[1] = normal[1]; + if (abs(normal[2]) > 0.0001) + thisVertex.Normal[2] = normal[2]; + + MFloatVector Tangent = Tangents[faceVert.tangentId()]; + //MVector tmp = faceVert.getTangent(MSpace::kObject, NULL); + //tmp.get(biTangent); + if (abs(Tangent[0]) > 0.0001) + thisVertex.Tangent[0] = Tangent[0]; + if (abs(Tangent[1]) > 0.0001) + thisVertex.Tangent[1] = Tangent[1]; + if (abs(Tangent[2]) > 0.0001) + thisVertex.Tangent[2] = Tangent[2]; + + MFloatVector biNormal = biNormals[faceVert.tangentId()]; + //faceVert.getBinormal().get(biNormal); + if (abs(biNormal[0]) > 0.0001) + thisVertex.BiNormal[0] = biNormal[0]; + if (abs(biNormal[1]) > 0.0001) + thisVertex.BiNormal[1] = biNormal[1]; + if (abs(biNormal[2]) > 0.0001) + thisVertex.BiNormal[2] = biNormal[2]; + + status = faceVert.getUV(UV); + if (status != MS::kSuccess) { + MGlobal::displayError(MString() + " faceVert.getUV() ERROR: " + status.errorString() + "for local vertex " + i + " in " + faceID + " in mesh " + thisMeshPath.fullPathName()); + break; + } + thisVertex.Uv[0] = UV[0]; + thisVertex.Uv[1] = UV[1]; + + + if (hasSkin) { + float totalWeight = 0.0f; + unsigned int totalBones = 0; + MIntArray jointIDs /* ??? */; + weights.selectAncestorLogicalIndex(vertexIndex, weightListObject); + weights.getExistingArrayAttributeIndices(jointIDs); + for (unsigned int i = 0; i < jointIDs.length() && i < 4; i++) { + if (weights[i].asFloat() > 0.001f) { + thisVertex.BoneIndices[totalBones] = jointIDs[i]; + thisVertex.BoneWeights[totalBones] = weights[i].asFloat(); + totalWeight = totalWeight + weights[i].asFloat(); + totalBones++; + } + } + + for (unsigned int i = 0; i < 4; i++) { + thisVertex.BoneWeights[i] = thisVertex.BoneWeights[i] / totalWeight; + } + } + + //float totalWeight = thisVertex.BoneWeights[0] + thisVertex.BoneWeights[1] + thisVertex.BoneWeights[2] + thisVertex.BoneWeights[3]; + //if (totalWeight > 0.0001f) { + // thisVertex.BoneWeights[0] /= totalWeight; + // thisVertex.BoneWeights[1] /= totalWeight; + // thisVertex.BoneWeights[2] /= totalWeight; + // thisVertex.BoneWeights[3] /= totalWeight; + //} + + std::vector::iterator it = std::find(vertexList.begin(), vertexList.end(), thisVertex); + array tmp; + if (it != vertexList.end()) { + tmp[0] = vertexIndex; + tmp[1] = it - vertexList.begin(); + localVertexToGlobalIndex.push_back(tmp); + } else { + tmp[0] = vertexIndex; + tmp[1] = vertexList.size(); + localVertexToGlobalIndex.push_back(tmp); + vertexList.push_back(thisVertex); + } + //MGlobal::displayInfo(MString() + "localVertexToGlobalIndex[localVertexToGlobalIndex.size()-1]: " + localVertexToGlobalIndex[localVertexToGlobalIndex.size()-1][0] + " " + localVertexToGlobalIndex[localVertexToGlobalIndex.size()-1][1]); + //cout << "Pos: " << thisVertex.Pos[0] << "/" << thisVertex.Pos[1] << "/" << thisVertex.Pos[2] << endl; + //cout << "Normals: " << thisVertex.Normal[0] << "/" << thisVertex.Normal[1] << "/" << thisVertex.Normal[2] << endl; + //cout << "Bi-Normals: " << thisVertex.BiNormal[0] << "/" << thisVertex.BiNormal[1] << "/" << thisVertex.BiNormal[2] << endl; + //cout << "Bi-Tangents: " << thisVertex.BiTangent[0] << "/" << thisVertex.BiTangent[1] << "/" << thisVertex.BiTangent[2] << endl; + //cout << "UV: " << thisVertex.Uv[0] << "/" << thisVertex.Uv[1] << endl; + } + for (unsigned int i = 0; i < triangleList.length(); i++) { + unsigned int k = 0; + if (localVertexToGlobalIndex.size() > 0) { + //MGlobal::displayInfo(MString() + "triangleList[i] : " + triangleList[i]); + while (localVertexToGlobalIndex[k][0] != triangleList[i] && k < localVertexToGlobalIndex.size()) { + k++; + } + //MGlobal::displayInfo(MString() + "localVertexToGlobalIndex[k] : " + localVertexToGlobalIndex[k][0] + " " + localVertexToGlobalIndex[k][1]); + indexLists[aMaterial.first.c_str()].push_back(localVertexToGlobalIndex[k][1]); + } + } + } + // MGlobal::displayInfo( MString() + "localVertexToGlobalIndex.size(): " + localVertexToGlobalIndex.size()); + // if (localVertexToGlobalIndex.size() > 0) { + // MGlobal::displayInfo(MString() + "triangleList.length(): " + triangleList.length()); + // for (unsigned int i = triangleList.length() - 1; i >= 0; i--) { + // MGlobal::displayInfo(MString() + "i: " + i); + // unsigned int k = localVertexToGlobalIndex.size() - 1; + // MGlobal::displayInfo(MString() + "triangleList[i] : " + triangleList[i]); + // while (localVertexToGlobalIndex[k] != triangleList[i] && k >= 0) { + // MGlobal::displayInfo(MString() + "k: " + k); + // k--; + // } + // MGlobal::displayInfo(MString() + "localVertexToGlobalIndex[k] : " + localVertexToGlobalIndex[k]); + // indexList.push_back(indexOffset + k); + // } + // } + } + } + } + + int totalIndices = 0; + for (auto aList : newMesh.Indices) { + totalIndices += aList.second.size(); + } + newMesh.NumIndices = totalIndices; + newMesh.NumVertices = newMesh.Vertices.size(); + + return newMesh; +} + +MeshClass::~MeshClass() +{ + +} \ No newline at end of file diff --git a/tools/MayaExporter/MayaExporter/Mesh.h b/tools/MayaExporter/MayaExporter/Mesh.h new file mode 100644 index 00000000..11f6bcf8 --- /dev/null +++ b/tools/MayaExporter/MayaExporter/Mesh.h @@ -0,0 +1,117 @@ +#ifndef Mesh_Mesh_h__ +#define Mesh_Mesh_h__ + +#include +#include +#include + +#include "OutputData.h" +#include "MayaIncludes.h" + +class VertexLayout : public OutputData +{ +public: + float Pos[3]{ 0 }; + float Normal[3]{ 0 }; + float Tangent[3]{ 0 }; + float BiNormal[3]{ 0 }; + float Uv[2]{ 0 }; + float BoneIndices[4]{ 0 }; + float BoneWeights[4]{ 0 }; + + virtual void WriteBinary(std::ostream& out) + { + out.write((char*)&Pos, sizeof(float) * 3); + out.write((char*)&Normal, sizeof(float) * 3); + out.write((char*)&Tangent, sizeof(float) * 3); + out.write((char*)&BiNormal, sizeof(float) * 3); + out.write((char*)&Uv, sizeof(float) * 2); + out.write((char*)&BoneIndices, sizeof(float) * 4); + out.write((char*)&BoneWeights, sizeof(float) * 4); + } + + virtual void WriteASCII(std::ostream& out) const + { + out << Pos[0] << " " << Pos[1] << " " << Pos[2] << endl; + out << Normal[0] << " " << Normal[1] << " " << Normal[2] << endl; + out << Tangent[0] << " " << Tangent[1] << " " << Tangent[2] << endl; + out << BiNormal[0] << " " << BiNormal[1] << " " << BiNormal[2] << endl; + out << Uv[0] << " " << Uv[1] << endl; + out << BoneIndices[0] << " " << BoneIndices[1] << " " << BoneIndices[2] << " " << BoneIndices[3] << endl; + out << BoneWeights[0] << " " << BoneWeights[1] << " " << BoneWeights[2] << " " << BoneWeights[3] << endl; + + } + bool operator==(const VertexLayout& right) + { + return + this->Pos[0] == right.Pos[0] && this->Pos[1] == right.Pos[1] && this->Pos[2] == right.Pos[2] && + this->Normal[0] == right.Normal[0] && this->Normal[1] == right.Normal[1] && this->Normal[2] == right.Normal[2] && + this->Tangent[0] == right.Tangent[0] && this->Tangent[1] == right.Tangent[1] && this->Tangent[2] == right.Tangent[2] && + this->BiNormal[0] == right.BiNormal[0] && this->BiNormal[1] == right.BiNormal[1] && this->BiNormal[2] == right.BiNormal[2] && + this->Uv[0] == right.Uv[0] && this->Uv[1] == right.Uv[1] && + this->BoneIndices[0] == right.BoneIndices[0] && this->BoneIndices[1] == right.BoneIndices[1] && this->BoneIndices[2] == right.BoneIndices[2] && this->BoneIndices[3] == right.BoneIndices[3] && + this->BoneWeights[0] == right.BoneWeights[0] && this->BoneWeights[1] == right.BoneWeights[1] && this->BoneWeights[2] == right.BoneWeights[2] && this->BoneWeights[3] == right.BoneWeights[3] + ; + } +}; + +class Mesh : public OutputData { +public: + unsigned int NumVertices; + unsigned int NumIndices; + std::vector Vertices; + std::map> Indices; + + virtual void WriteBinary(std::ostream& out) + { + out.write((char*)&NumVertices, sizeof(int)); + out.write((char*)&NumIndices, sizeof(int)); + for (auto aVertex : Vertices) { + aVertex.WriteBinary(out); + } + for (auto aIndex : Indices) { + //for (std::map>::reverse_iterator aIndex = Indices.rbegin(); aIndex != Indices.rend(); aIndex++){ + //out.write((char*)(*aIndex).second.data(), sizeof(int) * (*aIndex).second.size()); + out.write((char*)aIndex.second.data(), sizeof(int) * aIndex.second.size()); + } + } + + virtual void WriteASCII(std::ostream& out) const + { + out << "New Mesh _ not in binary" << endl; + out << "Number of vertices: " << NumVertices << endl; + out << "number of indices: " << NumIndices << endl; + int vertexNumber = 0; + for (auto aVertex : Vertices) { + out << "New vertex number: " << vertexNumber << " _ not in binary" << endl; + aVertex.WriteASCII(out); + vertexNumber++; + } + out << "New vertex Triangels: " << NumIndices/3 << " _ not in binary" << endl; + for (auto aIndexList : Indices) { + out << "Using Material: " << aIndexList.first << " _ not in binary" << endl; + for (int i = 0; i < aIndexList.second.size(); i += 3) { + out << aIndexList.second[i] << " " << aIndexList.second[i+1] << " " << aIndexList.second[i + 2] << endl; + } + } + } +}; + + + +class MeshClass +{ +public: + MeshClass(); + Mesh GetMeshData(MObjectArray Object); + ~MeshClass(); +private: + struct WeightInfo { + float BoneIndices[4] = { 0 }; + float BoneWeights[4] = { 0 }; + }; + std::map GetWeightData(); + +}; + +#endif \ No newline at end of file diff --git a/tools/MayaExporter/MayaExporter/OutputData.h b/tools/MayaExporter/MayaExporter/OutputData.h new file mode 100644 index 00000000..60159340 --- /dev/null +++ b/tools/MayaExporter/MayaExporter/OutputData.h @@ -0,0 +1,23 @@ +#ifndef OutputData_OutputData_h__ +#define OutputData_OutputData_h__ +#include +//template +class OutputData +{ +public://std::ostream& out, const OutputData& obj + //OutputData(T& object) + // : m_Object(object) + //{}; + + friend std::ostream& operator<<(std::ostream& out, const OutputData& obj) + { + obj.WriteASCII(out); + return out; + }; + virtual void WriteBinary(std::ostream& out) = 0; + virtual void WriteASCII(std::ostream& out) const = 0; + + //T& m_Object = nullptr; +}; + +#endif \ No newline at end of file diff --git a/tools/MayaExporter/MayaExporter/Skeleton.cpp b/tools/MayaExporter/MayaExporter/Skeleton.cpp new file mode 100644 index 00000000..c30311b8 --- /dev/null +++ b/tools/MayaExporter/MayaExporter/Skeleton.cpp @@ -0,0 +1,342 @@ +#include "Skeleton.h" + + + + +//std::vector Skeleton::DoIt() +//{ +// std::vector m_AllSkeletons; +// +// MItDag jointIt(MItDag::TraversalType::kDepthFirst, MFn::kJoint); +// SkeletonNode SkeletonStorage; +// +// while (!jointIt.isDone()) { +// MFnTransform TransformNode(jointIt.currentItem()); +// Joint NewJoint; +// +// if (MFnDependencyNode(TransformNode.parent(0)).name() == "world") { +// if (SkeletonStorage.Joints.size() != 0) { +// m_AllSkeletons.push_back(SkeletonStorage); +// +// SkeletonStorage.Joints.clear(); +// SkeletonStorage.Name.clear(); +// } +// +// SkeletonStorage.Name = TransformNode.name().asChar(); +// +// //NewJoint.ParentIndex = -1; // This joint is root +// } +// +// //NewJoint.Name = TransformNode.name().asChar(); +// +// MMatrix Matrix = TransformNode.transformationMatrix(); +// +// //double tmp[3]; +// //((MTransformationMatrix)Matrix).eulerRotation().asVector().get(tmp); +// //NewJoint.Rotation[0] = tmp[0]; +// //NewJoint.Rotation[1] = tmp[1]; +// //NewJoint.Rotation[2] = tmp[2]; +// //((MTransformationMatrix)Matrix).getScale(tmp, MSpace::Space::kTransform); +// //NewJoint.Scale[0] = tmp[0]; +// //NewJoint.Scale[1] = tmp[1]; +// //NewJoint.Scale[2] = tmp[2]; +// //((MTransformationMatrix)Matrix).getTranslation(MSpace::Space::kTransform).get(tmp); +// //NewJoint.Translation[0] = tmp[0]; +// //NewJoint.Translation[1] = tmp[1]; +// //NewJoint.Translation[2] = tmp[2]; +// +// for (int i = 0; i < 4; i++) { +// for (int j = 0; j < 4; j++) { +// NewJoint.OffsetMatrix[i][j] = Matrix.matrix[i][j]; +// } +// } +// +// SkeletonStorage.Joints.push_back(NewJoint); +// +// jointIt.next(); +// } +// +// m_AllSkeletons.push_back(SkeletonStorage); +// +// return m_AllSkeletons; +//} +std::string attr[9] = { "scaleX", "scaleY", "scaleZ", "translateX", "translateY", "translateZ", "rotateX", "rotateY", "rotateZ" }; + +Animation Skeleton::GetAnimData(std::string animationName, int startFrame, int endFrame) +{ + MStatus status; + std::vector animatedJoints; + std::vector m_Hierarchy; + + Animation returnData; + double oneDivSixty = 1 / 60.0; + returnData.Name = animationName; + returnData.nameLength = animationName.size() + 1; + returnData.Duration = (endFrame - startFrame) * oneDivSixty; + + MItDag jointIt(MItDag::TraversalType::kDepthFirst, MFn::kJoint); + while (!jointIt.isDone()) + { + m_Hierarchy.push_back(jointIt.item()); + + MFnDependencyNode depNode(jointIt.item()); + for (int i = 0; i < 9; i++) + { + MStatus tmp; + MPlug plug = depNode.findPlug(attr[i].c_str(), &tmp); + + MPlugArray connections; + plug.connectedTo(connections, true, false, 0); + for (int j = 0; j != connections.length(); j++) { + MObject connected = connections[j].node(); + + if (connected.hasFn(MFn::kAnimCurve)) { + + MFnAnimCurve jointAnim(connected); + + unsigned int startKeyFrameIndex = jointAnim.findClosest(MTime(startFrame, MTime::kNTSCField), &tmp); + + if (tmp == MStatus::kFailure) + MGlobal::displayInfo(MString() + "Fail :c"); + + if (startFrame * oneDivSixty <= jointAnim.time(startKeyFrameIndex).value() && jointAnim.time(startKeyFrameIndex).value() <= endFrame * oneDivSixty) { + animatedJoints.push_back(jointIt.item()); + i = 9; + break; + } + + unsigned int endKeyFrameIndex = jointAnim.findClosest(MTime(endFrame, MTime::kNTSCField)); + MGlobal::displayInfo(MString() + startKeyFrameIndex + " " + endKeyFrameIndex); + + if (startFrame * oneDivSixty <= jointAnim.time(endKeyFrameIndex).value() && jointAnim.time(endKeyFrameIndex).value() <= endFrame * oneDivSixty || endKeyFrameIndex - startKeyFrameIndex > 0) { + animatedJoints.push_back(jointIt.item()); + i = 9; + break; + } + + MFnTransform MayaJoint(jointIt.item()); + + MPlug BindPose = MayaJoint.findPlug("bindPose"); + MDataHandle DataHandle; + BindPose.getValue(DataHandle); + MFnMatrixData MartixFn(DataHandle.data()); + MMatrix BindPoseMatrix = MartixFn.matrix(); + + if (!BindPoseMatrix.isEquivalent(MayaJoint.transformationMatrix())) + { + MGlobal::displayError(MString() + animationName.c_str() + " is using " + MayaJoint.name() + " that is not in bind pose nor is it key framed in the animation, the exported animation will NOT correspond to the animation in Maya"); + } + } + } + } + + jointIt.next(); + } + + int currentFrame = startFrame; + while (currentFrame != endFrame + 1) { // ANDREAS + Animation::Keyframe thisKeyFrame; + thisKeyFrame.Index = currentFrame - startFrame; + thisKeyFrame.Time = thisKeyFrame.Index * oneDivSixty; + + MAnimControl::setCurrentTime(MTime(currentFrame, MTime::kNTSCField)); + MTime time = MAnimControl::currentTime(); + + for (auto aJoint : animatedJoints){ + MFnTransform thisJoint(aJoint); + Animation::Keyframe::JointProperty joint; + + auto it = std::find(m_Hierarchy.begin(), m_Hierarchy.end(), thisJoint.object()); + if (it != m_Hierarchy.end()) { + joint.ID = it - m_Hierarchy.begin(); + } + else { + MGlobal::displayError(MString() + "Could not find joint ID for: " + thisJoint.name()); + } + + MTransformationMatrix Matrix = thisJoint.transformation(); + MPlug BindPose = thisJoint.findPlug("bindPose"); + MDataHandle DataHandle; + BindPose.getValue(DataHandle); + MFnMatrixData MartixFn(DataHandle.data()); + MMatrix BindPoseMatrix = MartixFn.matrix(); + Matrix = Matrix.asMatrix(); + + MObject jointOrientObj = thisJoint.attribute("jointOrient"); + MFnNumericAttribute jointOrient(jointOrientObj); + double jointOrientDouble[3]; + jointOrient.getDefault(jointOrientDouble[0], jointOrientDouble[1], jointOrientDouble[2]); + //MGlobal::displayError(MString() + "Joint Matrix: "); + //MGlobal::displayError(MString() + Matrix.asMatrix()[0][0] + " " + Matrix.asMatrix()[0][1] + " " + Matrix.asMatrix()[0][2] + " " + Matrix.asMatrix()[0][3]); + //MGlobal::displayError(MString() + Matrix.asMatrix()[1][0] + " " + Matrix.asMatrix()[1][1] + " " + Matrix.asMatrix()[1][2] + " " + Matrix.asMatrix()[1][3]); + //MGlobal::displayError(MString() + Matrix.asMatrix()[2][0] + " " + Matrix.asMatrix()[2][1] + " " + Matrix.asMatrix()[2][2] + " " + Matrix.asMatrix()[2][3]); + //MGlobal::displayError(MString() + Matrix.asMatrix()[3][0] + " " + Matrix.asMatrix()[3][1] + " " + Matrix.asMatrix()[3][2] + " " + Matrix.asMatrix()[3][3]); + + MEulerRotation joEuler(jointOrientDouble[0], jointOrientDouble[1], jointOrientDouble[2]); + MQuaternion jo = joEuler.asQuaternion(); + + double tmp[4]; + Matrix.getRotationQuaternion(tmp[0], tmp[1], tmp[2], tmp[3]); + MQuaternion rotation(tmp); + + rotation = rotation * jo; + rotation.get(tmp); + + joint.Rotation[0] = tmp[0]; + joint.Rotation[1] = tmp[1]; + joint.Rotation[2] = tmp[2]; + joint.Rotation[3] = tmp[3]; + Matrix.getTranslation(MSpace::kTransform).get(tmp); + joint.Position[0] = tmp[0]; + joint.Position[1] = tmp[1]; + joint.Position[2] = tmp[2]; + Matrix.getScale(tmp, MSpace::kTransform); + joint.Scale[0] = tmp[0]; + joint.Scale[1] = tmp[1]; + joint.Scale[2] = tmp[2]; + + thisKeyFrame.JointProperties.push_back(joint); + } + returnData.Keyframes.push_back(thisKeyFrame); + currentFrame++; + } + + returnData.NumKeyFrames = returnData.Keyframes.size(); + returnData.NumberOfJoints = animatedJoints.size(); + + return returnData; +} + +std::vector Skeleton::GetBindPoses() +{ + MStatus status; + std::vector m_AllSkeletons; + std::vector m_Hierarchy; + + MItDag jointIt(MItDag::TraversalType::kDepthFirst, MFn::kJoint); + BindPoseSkeletonNode SkeletonStorage; + while (!jointIt.isDone()) { + MFnTransform MayaJoint(jointIt.currentItem()); + BindPoseSkeletonNode::BindPoseJoint NewJoint; + + if (MFnDependencyNode(MayaJoint.parent(0)).name() == "world") { + if (SkeletonStorage.Joints.size() != 0) { + m_AllSkeletons.push_back(SkeletonStorage); + + SkeletonStorage.Joints.clear(); + SkeletonStorage.Name.clear(); + } + SkeletonStorage.Name = std::string(MayaJoint.name().asChar()); + NewJoint.ParentID = -1; // This joint is root + } + else { + auto it = std::find(m_Hierarchy.begin(), m_Hierarchy.end(), MayaJoint.parent(0)); + if (it != m_Hierarchy.end()) { + NewJoint.ParentID = it - m_Hierarchy.begin(); + } + else { + MGlobal::displayError(MString() + "Could not find joint parent for: " + MayaJoint.name()); + } + } + m_Hierarchy.push_back(MayaJoint.object()); + + MPlug BindPose = MayaJoint.findPlug("bindPose", &status); + if (status != MS::kSuccess) { + MGlobal::displayError(MString() + "Could not find bindPose plug: " + status.errorString()); + } + MDataHandle DataHandle; + BindPose.getValue(DataHandle); + MFnMatrixData MartixFn(DataHandle.data()); + MMatrix Matrix = MartixFn.matrix(); + + + MVector tmp = MayaJoint.transformation().getTranslation(MSpace::kObject); + MGlobal::displayError(MString() + "translation befor: " + tmp[0] + " " + tmp[1] + " " + tmp[2]); + //Matrix[3][0] *= -1; + //Matrix[3][2] *= -1; + //Matrix[3][1] *= -1; + + double test[3]; + MayaJoint.transformation().getScale(test, MSpace::kObject); + MGlobal::displayError(MString() + "scale: " + test[0] + " " + test[1] + " " + test[2]); + + MTransformationMatrix::RotationOrder order = MTransformationMatrix::RotationOrder::kXYZ; + MayaJoint.transformation().getRotation(test, order); + MGlobal::displayError(MString() + "rotation: " + test[0] + " " + test[1] + " " + test[2]); + + //----- test + + + //MDataHandle DataHandle; + //MObject jointObject(jointIt.currentItem()); + //MFnDependencyNode jointDependNode(jointObject); + //MPlug worldMatrixArray(jointObject, jointDependNode.attribute("worldMatrix")); + + //MMatrix Matrix; + //for (int i = 0; i < worldMatrixArray.numElements(); i++) { + // MPlugArray connections; + + // MPlug element = worldMatrixArray[i]; + // unsigned int logicalIndex = element.logicalIndex(); + + // MItDependencyGraph it(element, MFn::kSkinClusterFilter); + + // for (; !it.isDone(); it.next()) { + // MFnSkinCluster skinCluster(it.thisNode()); + + // MPlug bindPreMatrixArrayPlug = + // skinCluster.findPlug("bindPreMatrix", &status); + + // if (status != MS::kSuccess) { + // MGlobal::displayError(MString() + "Could not find bindPreMatrix plug: " + status.errorString()); + // break; + // } + + // MPlug bindPreMatrixPlug = + // bindPreMatrixArrayPlug.elementByLogicalIndex(logicalIndex); + // MObject dataObject; + // bindPreMatrixPlug.getValue(dataObject); + + // MFnMatrixData matDataFn(dataObject); + + // MMatrix invMat = matDataFn.matrix(); + // Matrix = invMat.inverse(); + // } + //} + + + //----- end test + + + Matrix = Matrix.inverse(); + + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + NewJoint.OffsetMatrix[i][j] = Matrix.matrix[i][j]; + } + } + + NewJoint.Name = MayaJoint.name().asChar(); + NewJoint.NameLength = MayaJoint.name().length() + 1; + NewJoint.ID = SkeletonStorage.Joints.size(); + //double tmp[3]; + //((MTransformationMatrix)Matrix).eulerRotation().asVector().get(tmp); + //NewJoint.Rotation[0] = tmp[0]; + //NewJoint.Rotation[1] = tmp[1]; + //NewJoint.Rotation[2] = tmp[2]; + //((MTransformationMatrix)Matrix).getScale(tmp, MSpace::Space::kTransform); + //NewJoint.Scale[0] = tmp[0]; + //NewJoint.Scale[1] = tmp[1]; + //NewJoint.Scale[2] = tmp[2]; + //((MTransformationMatrix)Matrix).getTranslation(MSpace::Space::kTransform).get(tmp); + //NewJoint.Translation[0] = tmp[0]; + //NewJoint.Translation[1] = tmp[1]; + //NewJoint.Translation[2] = tmp[2]; + SkeletonStorage.Joints.push_back(NewJoint); + SkeletonStorage.numBones++; + jointIt.next(); + } + m_AllSkeletons.push_back(SkeletonStorage); + + return m_AllSkeletons; +} \ No newline at end of file diff --git a/tools/MayaExporter/MayaExporter/Skeleton.h b/tools/MayaExporter/MayaExporter/Skeleton.h new file mode 100644 index 00000000..6a288c8a --- /dev/null +++ b/tools/MayaExporter/MayaExporter/Skeleton.h @@ -0,0 +1,129 @@ +#ifndef Skeleton_Skeleton_h__ +#define Skeleton_Skeleton_h__ + +#include +#include +#include +#include "MayaIncludes.h" +#include "OutputData.h" + +class Animation : public OutputData { +public: + struct Keyframe + { + struct JointProperty + { + int ID = 0; + float Position[3]{ 0 }; + float Rotation[4]{ 0 }; + float Scale[3]{ 0 }; + }; + + int Index = 0; + float Time = 0; + std::vector JointProperties; + }; + + std::string Name; + int nameLength = 0; + float Duration = 0; + int NumKeyFrames = 0; + int NumberOfJoints = 0; + std::vector Keyframes; + + virtual void WriteBinary(std::ostream& out) + { + out.write((char*)&nameLength, sizeof(int)); + out.write(Name.c_str(), Name.size() + 1); + out.write((char*)&Duration, sizeof(float)); + out.write((char*)&NumKeyFrames, sizeof(int)); + out.write((char*)&NumberOfJoints, sizeof(int)); + //Här under loopas alla key frames igenom + for (auto aKeyframe : Keyframes) { + out.write((char*)&aKeyframe.Index, sizeof(int)); + out.write((char*)&aKeyframe.Time, sizeof(float)); + for (auto aJoint : aKeyframe.JointProperties) { + out.write((char*)&aJoint.ID, sizeof(int)); + out.write((char*)aJoint.Position, sizeof(float) * 3); + out.write((char*)aJoint.Rotation, sizeof(float) * 4); + out.write((char*)aJoint.Scale, sizeof(float) * 3); + } + } + } + + virtual void WriteASCII(std::ostream& out) const + { + out << "Animation Name: " << Name << endl; + out << "Duration: " << Duration << endl; + out << "Number of KeyFrames: " << NumKeyFrames << endl; + out << "Number of Joints: " << NumberOfJoints << endl; + for (auto aKeyframe : Keyframes) { + out << "Frame: " << aKeyframe.Index << endl; + out << "Time: " << aKeyframe.Time << endl; + for (auto aJoint : aKeyframe.JointProperties) { + out << "Joint ID: " << aJoint.ID << endl; + out << aJoint.Position[0] << " " << aJoint.Position[1] << " " << aJoint.Position[2] << endl; + out << aJoint.Rotation[0] << " " << aJoint.Rotation[1] << " " << aJoint.Rotation[2] << " " << aJoint.Rotation[3] << endl; + out << aJoint.Scale[0] << " " << aJoint.Scale[1] << " " << aJoint.Scale[2] << endl; + } + } + + } +}; + +class BindPoseSkeletonNode : public OutputData { +public: + struct BindPoseJoint + { + int NameLength; + std::string Name; + float OffsetMatrix[4][4]{ 0 }; + int ID = 0; + int ParentID = 0; + }; + int numBones = 0; + std::string Name; + std::vector Joints; + virtual void WriteBinary(std::ostream& out) + { + out.write((char*)&numBones, sizeof(int)); + for (auto Joint:Joints) + { + out.write((char*)&Joint.NameLength, sizeof(int)); + out.write(Joint.Name.c_str(), Joint.Name.size() + 1); + out.write((char*)&Joint.OffsetMatrix, sizeof(float) * 4 * 4); + out.write((char*)&Joint.ID, sizeof(int)); + out.write((char*)&Joint.ParentID, sizeof(int)); + } + + } + + virtual void WriteASCII(std::ostream& out) const + { + out << "Bind Pose: " << Name << " _ not in binary" << endl; + out << "numberOfBones: " << numBones << endl; + for (auto Joint : Joints) + { + out << "Joint NameLength " << Joint.NameLength << endl; + out << "Joint name " << Joint.Name << endl; + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++){ + out << Joint.OffsetMatrix[i][j] << " "; + } + out << endl; + } + out << Joint.ID << endl; + out << Joint.ParentID << endl; + } + }; +}; + +class Skeleton { +public: + //std::vector DoIt(); + Animation GetAnimData(std::string animationName, int startFrame, int endFrame); + std::vector GetBindPoses(); +private: +}; + +#endif //Skeleton_Skeleton_h__ \ No newline at end of file diff --git a/tools/MayaExporter/MayaExporter/WriteToFile.cpp b/tools/MayaExporter/MayaExporter/WriteToFile.cpp new file mode 100644 index 00000000..a0368c4f --- /dev/null +++ b/tools/MayaExporter/MayaExporter/WriteToFile.cpp @@ -0,0 +1,41 @@ +#include "WriteToFile.h" + +WriteToFile::~WriteToFile() +{ + CloseFiles(); +} + +bool WriteToFile::binaryFilePath(string filePathAndFileName) +{ + binFileName = filePathAndFileName; + ofstream binFile(filePathAndFileName, ofstream::binary); + if (!binFile) + return false; + return true; +} + +bool WriteToFile::ASCIIFilePath(string filePathAndFileName) +{ + ASCIIFileName = filePathAndFileName; + ofstream ASCIIFile(filePathAndFileName); + if (!ASCIIFile) + return false; + return true; +} + +void WriteToFile::OpenFiles() +{ + if (binFile) { + binFile.open(binFileName, ofstream::binary); + } + if (ASCIIFile){ + ASCIIFile.open(ASCIIFileName); + ASCIIFile << std::fixed << std::setprecision(3); + } +} + +void WriteToFile::CloseFiles() +{ + binFile.close(); + ASCIIFile.close(); +} \ No newline at end of file diff --git a/tools/MayaExporter/MayaExporter/WriteToFile.h b/tools/MayaExporter/MayaExporter/WriteToFile.h new file mode 100644 index 00000000..216fcfc9 --- /dev/null +++ b/tools/MayaExporter/MayaExporter/WriteToFile.h @@ -0,0 +1,64 @@ +#ifndef WriteToFile_WriteToFile_h__ +#define WriteToFile_WriteToFile_h__ + +#include "MayaIncludes.h" +#include "OutputData.h" +#include +#include +#include + +using namespace std; + +class WriteToFile +{ +public: + ~WriteToFile(); + bool binaryFilePath(string filePathAndFileName); + bool ASCIIFilePath(string filePathAndFileName); + + void writeToFiles(OutputData* toWrite, unsigned int numOfElementToWrite = 1, unsigned int startIndex = 0) + { + MGlobal::displayInfo("WriteToFile::writeToFiles(OutputData*)"); + if (ASCIIFile.is_open()) + { + for (unsigned int i = startIndex; i < numOfElementToWrite + startIndex; i++) + ASCIIFile << toWrite[i] << endl; + } + + if (binFile.is_open()) + { + for (unsigned int i = startIndex; i < numOfElementToWrite + startIndex; i++) + toWrite[i].WriteBinary(binFile); + } + + } + + template + void writeToFiles(T* toWrite, unsigned int numOfElementToWrite = 1, unsigned int startIndex = 0) + { + MGlobal::displayInfo("WriteToFile::writeToFiles(T*) - Template T"); + if (ASCIIFile.is_open()) { + for (unsigned int i = startIndex; i < numOfElementToWrite + startIndex; i++) + ASCIIFile << toWrite[i] << endl; + } + + if (binFile.is_open()) { + for (unsigned int i = startIndex; i < numOfElementToWrite + startIndex; i++) + binFile.write((char*)toWrite, sizeof(T)); + } + + } + + void OpenFiles(); + void CloseFiles(); + +private: + string binFileName; + string ASCIIFileName; + ofstream binFile; + ofstream ASCIIFile; +}; + + + +#endif \ No newline at end of file