diff --git a/.gitignore b/.gitignore index 4f30c2a..3b5dc2e 100755 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,7 @@ ipch/ [Dd]ebug*/ [Rr]elease*/ Ankh.NoLoad +*.orig assets/ !libs/*.lib \ No newline at end of file diff --git a/src/Camera.cpp b/src/Camera.cpp index 2db69de..1256e64 100755 --- a/src/Camera.cpp +++ b/src/Camera.cpp @@ -77,7 +77,7 @@ void Camera::UpdateProjectionMatrix() void Camera::UpdateViewMatrix() { - m_ViewMatrix = glm::translate(glm::toMat4(m_Orientation), -m_Position); + m_ViewMatrix = glm::toMat4(glm::inverse(m_Orientation)) * glm::translate(-m_Position); } void Camera::FOV(float val) diff --git a/src/Components/Physics.h b/src/Components/Physics.h index 956ae7a..df819c4 100644 --- a/src/Components/Physics.h +++ b/src/Components/Physics.h @@ -9,9 +9,10 @@ namespace Components struct Physics : Component { Physics() - : Mass(0.f) { } + : Mass(0.f), Static(false){} float Mass; + bool Static; }; } diff --git a/src/Components/Vehicle.h b/src/Components/Vehicle.h new file mode 100644 index 0000000..e61c713 --- /dev/null +++ b/src/Components/Vehicle.h @@ -0,0 +1,26 @@ +#ifndef Components_Vehicle_h__ +#define Components_Vehicle_h__ + +#include "Component.h" + + +namespace Components +{ + +struct Vehicle : Component +{ + Vehicle() + : MaxTorque(500.0f), MinRPM(1000.0f), OptimalRPM(5500.0f), MaxRPM(7500.0f), MaxSteeringAngle(35), TopSpeed(50.0f) { } + + float MaxTorque; + float MinRPM; + float OptimalRPM; + float MaxRPM; + // Degrees + float MaxSteeringAngle; + float TopSpeed; +}; + +} + +#endif // Components_Vehicle_h__ diff --git a/src/Components/Wheel.h b/src/Components/Wheel.h new file mode 100644 index 0000000..d4917db --- /dev/null +++ b/src/Components/Wheel.h @@ -0,0 +1,40 @@ +#ifndef Components_Wheel_h__ +#define Components_Wheel_h__ + +#include "Component.h" + +namespace Systems { class PhysicsSystem; } + +namespace Components +{ + +struct Wheel : Component +{ + friend class Systems::PhysicsSystem; + + Wheel() + : AxleID(0), Radius(0), Width(0), Mass(0), Steering(false), DownDirection(glm::vec3(0, -1, 0)), Friction(1.5f), SlipAngle(0.0f), + MaxBreakingTorque(1500.0f), ConnectedToHandbrake(false), SuspensionStrength(50.0f) { } + + // The Hardpoint MUST be positioned INSIDE the chassis. + glm::vec3 Hardpoint; + unsigned int AxleID; + float Radius; + float Width; + float Mass; + bool Steering; + glm::vec3 DownDirection; + + float SuspensionStrength; + float Friction; + float SlipAngle; + float MaxBreakingTorque; + bool ConnectedToHandbrake; + +private: + int ID; + glm::quat OriginalOrientation; +}; + +} +#endif // Components_Wheel_h__ diff --git a/src/GameWorld.cpp b/src/GameWorld.cpp index 48a65a5..18ab5a2 100755 --- a/src/GameWorld.cpp +++ b/src/GameWorld.cpp @@ -27,10 +27,9 @@ void GameWorld::Initialize() auto transform = AddComponent(camera, "Transform"); transform->Position.z = 20.f; transform->Position.y = 20.f; - transform->Orientation = glm::quat(glm::vec3(glm::pi() / 8.f, 0.f, 0.f)); + //transform->Orientation = glm::quat(glm::vec3(glm::pi() / 8.f, 0.f, 0.f)); auto cameraComp = AddComponent(camera, "Camera"); cameraComp->FarClip = 2000.f; - AddComponent(camera, "Input"); auto freeSteering = AddComponent(camera, "FreeSteering"); CommitEntity(camera); } @@ -39,65 +38,219 @@ void GameWorld::Initialize() { auto ground = CreateEntity(); auto transform = AddComponent(ground, "Transform"); - transform->Position = glm::vec3(0, 0, 0); - transform->Scale = glm::vec3(1000.0f, 1.0f, 1000.0f); + transform->Position = glm::vec3(0, -5, 0); + transform->Scale = glm::vec3(400.0f, 10.0f, 400.0f); transform->Orientation = glm::quat(glm::vec3(0.0f, 0.0f, 0.0f)); auto model = AddComponent(ground, "Model"); model->ModelFile = "Models/Placeholders/PhysicsTest/Cube.obj"; auto box = AddComponent(ground, "Box"); - box->Width = 500; - box->Height = 0.5; - box->Depth = 500; + box->Width = 200; + box->Height = 5; + box->Depth = 200; auto physics = AddComponent(ground, "Physics"); physics->Mass = 10; + physics->Static = true; + CommitEntity(ground); } - { - auto TankTest = CreateEntity(); - auto transform = AddComponent(TankTest, "Transform"); - transform->Position = glm::vec3(1.5f, 0.7f, 5.f); - auto model = AddComponent(TankTest, "Model"); - model->ModelFile = "Models/Placeholders/tank/Chassi.obj"; - CommitEntity(TankTest); + { + auto jeep = CreateEntity(); + auto transform = AddComponent(jeep, "Transform"); + transform->Position = glm::vec3(0, 2, 0); + + auto physics = AddComponent(jeep, "Physics"); + physics->Mass = 1200; + auto box = AddComponent(jeep, "Box"); + box->Width = 1.487f; + box->Height = 0.727f; + box->Depth = 2.594f; + auto vehicle = AddComponent(jeep, "Vehicle"); + + AddComponent(jeep, "Input"); + + { + auto chassis = CreateEntity(jeep); + auto transform = AddComponent(chassis, "Transform"); + transform->Position = glm::vec3(0, -0.6577f, 0); + auto model = AddComponent(chassis, "Model"); + model->ModelFile = "Models/JeepV2/Chassi/chassi.OBJ"; + + } + + { + auto wheel = CreateEntity(jeep); + auto transform = AddComponent(wheel, "Transform"); + transform->Position = glm::vec3(1.4f, 0.5546f - 0.6577f - 0.2, -0.9242f); + transform->Scale = glm::vec3(1.0f); + auto model = AddComponent(wheel, "Model"); + model->ModelFile = "Models/JeepV2/WheelFront/wheelFront.obj"; + auto Wheel = AddComponent(wheel, "Wheel"); + Wheel->Hardpoint = transform->Position + glm::vec3(0.f, 1.f, 0.f); + Wheel->AxleID = 0; + Wheel->Mass = 50; + Wheel->Radius = 0.837f; + Wheel->Steering = true; + Wheel->SuspensionStrength = 40.f; + Wheel->Friction = 4.0f; + Wheel->ConnectedToHandbrake = true; + CommitEntity(wheel); + } + + { + auto wheel = CreateEntity(jeep); + auto transform = AddComponent(wheel, "Transform"); + transform->Position = glm::vec3(-1.4f, 0.5546f - 0.6577f - 0.2, -0.9242f); + transform->Scale = glm::vec3(1.0f); + transform->Orientation = glm::angleAxis(glm::pi(), glm::vec3(0, 0, 1)); + auto model = AddComponent(wheel, "Model"); + model->ModelFile = "Models/JeepV2/WheelFront/wheelFront.obj"; + auto Wheel = AddComponent(wheel, "Wheel"); + Wheel->Hardpoint = transform->Position + glm::vec3(0.f, 1.f, 0.f); + Wheel->AxleID = 0; + Wheel->Mass = 50; + Wheel->Radius = 0.837f; + Wheel->Steering = true; + Wheel->SuspensionStrength = 40.f; + Wheel->Friction = 4.0f; + Wheel->ConnectedToHandbrake = true; + CommitEntity(wheel); + } + + { + auto wheel = CreateEntity(jeep); + auto transform = AddComponent(wheel, "Transform"); + transform->Position = glm::vec3(0.2726f, 0.2805f - 0.6577f, 1.9307f); + auto model = AddComponent(wheel, "Model"); + model->ModelFile = "Models/JeepV2/WheelBack/wheelBack.obj"; + auto Wheel = AddComponent(wheel, "Wheel"); + Wheel->Hardpoint = transform->Position + glm::vec3(0.f, 1.f, 0.f); + Wheel->AxleID = 1; + Wheel->Mass = 10; + Wheel->Radius = 0.737f; + Wheel->Steering = false; + Wheel->SuspensionStrength = 50.f; + Wheel->Friction = 4.0f; + CommitEntity(wheel); + } + + { + auto wheel = CreateEntity(jeep); + auto transform = AddComponent(wheel, "Transform"); + transform->Position = glm::vec3(-0.2726f, 0.2805f - 0.6577f, 1.9307f); + transform->Orientation = glm::angleAxis(glm::pi(), glm::vec3(0, 0, 1)); + auto model = AddComponent(wheel, "Model"); + model->ModelFile = "Models/JeepV2/WheelBack/wheelBack.obj"; + auto Wheel = AddComponent(wheel, "Wheel"); + Wheel->Hardpoint = transform->Position + glm::vec3(0.f, 1.f, 0.f); + Wheel->AxleID = 1; + Wheel->Mass = 10; + Wheel->Radius = 0.737f; + Wheel->Steering = false; + Wheel->SuspensionStrength = 50.f; + Wheel->Friction = 4.0f; + CommitEntity(wheel); + } + CommitEntity(jeep); } - /*for(int i = 0; i < 83; i++) +/* + + { + // Front Right Wheel + auto ent = CreateEntity(car); + auto transform = AddComponent(ent, "Transform"); + transform->Scale = glm::vec3(1)/glm::vec3(3, 1, 5); + transform->Position = glm::vec3(1.1f, -1.5f, -1.3f); + auto Wheel = AddComponent(ent, "Wheel"); + Wheel->Hardpoint = glm::vec3(1.1f, 0.f, -1.3f);// HACK: make into component + Wheel->AxleID = 0; + Wheel->Mass = 10; + Wheel->Radius = 0.5f; + Wheel->Steering = true; + Wheel->SuspensionStrength = 20.f; + auto model = AddComponent(ent, "Model"); + model->ModelFile = "Models/Placeholders/PhysicsTest/Cube2.obj"; + CommitEntity(ent); + } + { + // Front Left Wheel + auto ent = CreateEntity(car); + auto transform = AddComponent(ent, "Transform"); + transform->Scale = glm::vec3(1)/glm::vec3(3, 1, 5); + transform->Position = glm::vec3(-1.1f, -1.5f, -1.3f); + auto Wheel = AddComponent(ent, "Wheel"); + Wheel->Hardpoint = glm::vec3(-1.1f, 0.f, -1.3f); + Wheel->AxleID = 0; + Wheel->Mass = 10; + Wheel->Radius = 0.5f; + Wheel->Steering = true; + Wheel->SuspensionStrength = 20.f; + auto model = AddComponent(ent, "Model"); + model->ModelFile = "Models/Placeholders/PhysicsTest/Cube2.obj"; + CommitEntity(ent); + } + { + // Back Right Wheel + auto ent = CreateEntity(car); + auto transform = AddComponent(ent, "Transform"); + transform->Scale = glm::vec3(1)/glm::vec3(3, 1, 5); + transform->Position = glm::vec3(1.1f, -1.5f, 1.3f); + auto Wheel = AddComponent(ent, "Wheel"); + Wheel->Hardpoint = glm::vec3(1.1f, 0.f, 1.3f); + Wheel->AxleID = 1; + Wheel->Mass = 10; + Wheel->Radius = 0.5f; + Wheel->Steering = false; + Wheel->ConnectedToHandbrake = true; + Wheel->SuspensionStrength = 20.f; + auto model = AddComponent(ent, "Model"); + model->ModelFile = "Models/Placeholders/PhysicsTest/Cube2.obj"; + CommitEntity(ent); + } + { + // Back Left Wheel + auto ent = CreateEntity(car); + auto transform = AddComponent(ent, "Transform"); + transform->Scale = glm::vec3(1)/glm::vec3(3, 1, 5); + transform->Position = glm::vec3(-1.1f, -1.5f, 1.3f); + auto Wheel = AddComponent(ent, "Wheel"); + Wheel->Hardpoint = glm::vec3(-1.1f, 0.f, 1.3f); + Wheel->AxleID = 1; + Wheel->Mass = 10; + Wheel->Radius = 0.5f; + Wheel->Steering = false; + Wheel->ConnectedToHandbrake = true; + Wheel->SuspensionStrength = 20.f; + auto model = AddComponent(ent, "Model"); + model->ModelFile = "Models/Placeholders/PhysicsTest/Cube2.obj"; + CommitEntity(ent); + } + + CommitEntity(car); + } +*/ + + for (int i = 0; i < 10; i++) { - auto light = CreateEntity(); - auto transform = AddComponent(light, "Transform"); - transform->Position = glm::vec3((float)(2*i)*glm::sin((float)i), 3, (float)(2*i)*glm::cos((float)i)); - - auto pointLight = AddComponent(light, "PointLight"); - pointLight->Specular = glm::vec3(0.1f, 0.1f, 0.1f); - pointLight->Diffuse = glm::vec3(0.05f, 0.36f, 1.f); - pointLight->constantAttenuation = 0.03f; - pointLight->linearAttenuation = 0.009f; - pointLight->quadraticAttenuation = 0.07f; - pointLight->spotExponent = 0.0f; - - auto model = AddComponent(light, "Model"); - model->ModelFile = "Models/Placeholders/PhysicsTest/PointLight.obj"; - CommitEntity(light); - } - - for(int i = 0; i < 500; i++) - { - auto ball = CreateEntity(); - auto transform = AddComponent(ball, "Transform"); - transform->Position = glm::vec3(i/5.f, 5 + i*2, i/5.f); - transform->Scale = glm::vec3(1.0f, 1.0f, 1.0f); + auto cube = CreateEntity(); + auto transform = AddComponent(cube, "Transform"); + transform->Position = glm::vec3(20, 10 + i * 2, 0); + transform->Scale = glm::vec3(1); transform->Orientation = glm::quat(glm::vec3(0.0f, 0.0f, 0.0f)); - auto model = AddComponent(ball, "Model"); - model->ModelFile = "Models/Placeholders/PhysicsTest/Sphere.obj"; - auto sphere = AddComponent(ball, "Sphere"); - sphere->Radius = 0.5; - auto physics = AddComponent(ball, "Physics"); - physics->Mass = 1; - CommitEntity(ball); - }*/ + auto model = AddComponent(cube, "Model"); + model->ModelFile = "Models/Placeholders/PhysicsTest/Cube2.obj"; + + auto physics = AddComponent(cube, "Physics"); + physics->Mass = 100; + auto box = AddComponent(cube, "Box"); + box->Width = 0.5f; + box->Height = 0.5f; + box->Depth = 0.5f; + CommitEntity(cube); + } { auto entity = CreateEntity(); @@ -106,6 +259,7 @@ void GameWorld::Initialize() emitter->Path = "Sounds/korvring.wav"; emitter->Loop = true; //GetSystem("SoundSystem")->PlaySound(emitter); + CommitEntity(entity); } } @@ -118,8 +272,6 @@ void GameWorld::RegisterComponents() { m_ComponentFactory.Register("Transform", []() { return new Components::Transform(); }); m_ComponentFactory.Register("Template", []() { return new Components::Template(); }); - m_ComponentFactory.Register("Sphere", []() { return new Components::Sphere(); }); - m_ComponentFactory.Register("Box", []() { return new Components::Box (); }); } void GameWorld::RegisterSystems() diff --git a/src/GameWorld.h b/src/GameWorld.h index 355c9b1..6a1d25b 100755 --- a/src/GameWorld.h +++ b/src/GameWorld.h @@ -30,6 +30,8 @@ #include "Components/Physics.h" #include "Components/Sphere.h" #include "Components/Box.h" +#include "Components/Vehicle.h" +#include "Components/Wheel.h" class GameWorld : public World { diff --git a/src/Model.cpp b/src/Model.cpp index 5f10f29..547e940 100755 --- a/src/Model.cpp +++ b/src/Model.cpp @@ -17,11 +17,19 @@ Model::Model(OBJ &obj, ResourceManager* rm) if (face.Material != currentMaterial) { currentMaterial = face.Material; + // Load texture - auto texture = std::shared_ptr(rm->Load("Texture", currentMaterial->TextureFile)); + auto texture = std::shared_ptr(rm->Load("Texture", currentMaterial->DiffuseTexture.FileName)); + // TODO: Load normal map + std::shared_ptr normalMap = nullptr; + // Load specular map + std::shared_ptr specularMap = nullptr; + if (!currentMaterial->SpecularMap.FileName.empty()) + specularMap = std::shared_ptr(rm->Load("Texture", currentMaterial->SpecularMap.FileName)); + // TODO: Load material parameters // Create new texture group (start index of new group is upcoming index) - TextureGroup texGroup = { texture, index, index }; + TextureGroup texGroup = { texture, normalMap, specularMap, index, index }; TextureGroups.push_back(texGroup); currentTexGroup = &TextureGroups.back(); } diff --git a/src/Model.h b/src/Model.h index e1d7fa6..8d94a7d 100755 --- a/src/Model.h +++ b/src/Model.h @@ -21,7 +21,9 @@ public: struct TextureGroup { - std::shared_ptr Texture; + std::shared_ptr<::Texture> Texture; + std::shared_ptr<::Texture> NormalMap; + std::shared_ptr<::Texture> SpecularMap; unsigned int StartIndex; unsigned int EndIndex; }; diff --git a/src/OBJ.cpp b/src/OBJ.cpp index 683f9e2..a8b9f03 100755 --- a/src/OBJ.cpp +++ b/src/OBJ.cpp @@ -126,9 +126,11 @@ void OBJ::ParseMaterial() std::string currentMaterialName; MaterialInfo* currentMaterial = nullptr; + unsigned int currentLine = 0; std::string line; while (std::getline(file, line)) { + currentLine++; if (line.length() == 0) continue; @@ -140,19 +142,7 @@ void OBJ::ParseMaterial() // Create a new material definition if (prefix == "newmtl") { - MaterialInfo mat = - { - "", - std::make_tuple(0.2f, 0.2f, 0.2f), - std::make_tuple(0.8f, 0.8f, 0.8f), - std::make_tuple(1.0f, 1.0f, 1.0f), - std::make_tuple(1.0f, 1.0f, 1.0f), - 1.0f, - 1.0f, - 0.0f, - 0, - }; - + MaterialInfo mat; ss >> currentMaterialName; LOG_INFO("Parsing material %s", currentMaterialName.c_str()); Materials[currentMaterialName] = mat; @@ -243,14 +233,177 @@ void OBJ::ParseMaterial() currentMaterial->IlluminationModel = illum; continue; } - // Texture file - // TODO: - if (prefix == "map_Ka" || prefix == "map_Kd") + // Diffuse texture + if (prefix == "map_Kd") { - std::string textureFile; - ss >> textureFile; - currentMaterial->TextureFile = (m_MaterialPath.branch_path() / textureFile).string(); + MaterialInfo::ColorMap colorMap; + + std::string fileName; + std::string arg; + while (ss >> arg) + { + ParseColorMap(currentLine, ss, prefix, arg, colorMap); + } + + // HACK: Should we really have to specify the full path here? + colorMap.FileName = (m_MaterialPath.branch_path() / colorMap.FileName).string(); + currentMaterial->DiffuseTexture = colorMap; + continue; + } + // Specular map + if (prefix == "map_Ks") + { + MaterialInfo::ColorMap colorMap; + + std::string fileName; + std::string arg; + while (ss >> arg) + { + ParseColorMap(currentLine, ss, prefix, arg, colorMap); + } + + // HACK: Should we really have to specify the full path here? + colorMap.FileName = (m_MaterialPath.branch_path() / colorMap.FileName).string(); + currentMaterial->SpecularMap = colorMap; + continue; + } + // Normal map (bump map) + if (prefix == "bump") + { + MaterialInfo::BumpMap bumpMap; + + std::string fileName; + std::string arg; + while (ss >> arg) + { + ParseBumpMap(currentLine, ss, prefix, arg, bumpMap); + } + + // HACK: Should we really have to specify the full path here? + bumpMap.FileName = (m_MaterialPath.branch_path() / bumpMap.FileName).string(); + currentMaterial->NormalMap = bumpMap; continue; } } } + +void OBJ::ParseTextureMap(unsigned int line, std::stringstream &ss, std::string prefix, std::string arg, MaterialInfo::TextureMap &textureMap) +{ + if (arg == "-blendu") + { + std::string val; + ss >> val; + if (val == "off") + textureMap.blendu = false; + else if (val == "on") + textureMap.blendu = true; + else + LOG_ERROR("Unrecognized MTL value \"%s\" to argument \"%s %s\" on line %i", val.c_str(), prefix.c_str(), arg.c_str(), line); + } + else if (arg == "-blendv") + { + std::string val; + ss >> val; + if (val == "off") + textureMap.blendv = false; + else if (val == "on") + textureMap.blendv = true; + else + LOG_ERROR("Unrecognized MTL value \"%s\" to argument \"%s %s\" on line %i", val.c_str(), prefix.c_str(), arg.c_str(), line); + } + else if (arg == "-clamp") + { + std::string val; + ss >> val; + if (val == "off") + textureMap.clamp = false; + else if (val == "on") + textureMap.clamp = true; + else + LOG_ERROR("Unrecognized MTL value \"%s\" to argument \"%s %s\" on line %i", val.c_str(), prefix.c_str(), arg.c_str(), line); + } + else if (arg == "-o") + { + float u, v, w; + if (ss >> u >> v >> w) + { + textureMap.o = std::make_tuple(u, v, w); + } + else + { + LOG_ERROR("Unrecognized MTL value to argument \"%s %s\" on line %i", prefix.c_str(), arg.c_str(), line); + } + } + else if (arg == "-s") + { + float u, v, w; + if (ss >> u >> v >> w) + { + textureMap.s = std::make_tuple(u, v, w); + } + else + { + LOG_ERROR("Unrecognized MTL value to argument \"%s %s\" on line %i", prefix.c_str(), arg.c_str(), line); + } + } + // Assume unrecognized options is part of the file name + else + { + if (!textureMap.FileName.empty()) + textureMap.FileName += " "; + textureMap.FileName += arg; + } +} + +void OBJ::ParseColorMap(unsigned int line, std::stringstream &ss, std::string prefix, std::string arg, MaterialInfo::ColorMap &colorMap) +{ + if (arg == "-cc") + { + if (prefix != "map_Kd" || prefix != "map_Ks") + { + LOG_ERROR("Invalid MTL argument \"%s\" to option \"%s\" on line %i", arg.c_str(), prefix.c_str(), line); + return; + } + + std::string val; + if (ss >> val) + { + if (val == "off") + colorMap.cc = false; + else if (val == "on") + colorMap.cc = true; + else + LOG_ERROR("Unrecognized MTL value \"%s\" to argument \"%s %s\" on line %i", val.c_str(), prefix.c_str(), arg.c_str(), line); + } + else + { + LOG_ERROR("Unrecognized MTL value to argument \"%s %s\" on line %i", prefix.c_str(), arg.c_str(), line); + } + } + else + { + ParseTextureMap(line, ss, prefix, arg, colorMap); + } +} + +void OBJ::ParseBumpMap(unsigned int line, std::stringstream &ss, std::string prefix, std::string arg, MaterialInfo::BumpMap &bumpMap) +{ + if (arg == "-bm") + { + if (prefix != "bump") + { + LOG_ERROR("Invalid MTL argument \"%s\" to option \"%s\" on line %i", arg.c_str(), prefix.c_str(), line); + return; + } + + float val; + if (ss >> val) + bumpMap.bm = val; + else + LOG_ERROR("Unrecognized MTL value to argument \"%s %s\" on line %i", prefix.c_str(), arg.c_str(), line); + } + else + { + ParseTextureMap(line, ss, prefix, arg, bumpMap); + } +} \ No newline at end of file diff --git a/src/OBJ.h b/src/OBJ.h index 62bce8d..2ef10e0 100755 --- a/src/OBJ.h +++ b/src/OBJ.h @@ -10,21 +10,78 @@ #include #include +#include class OBJ { public: struct MaterialInfo { - std::string TextureFile; - std::tuple AmbientColor; - std::tuple DiffuseColor; - std::tuple SpecularColor; - std::tuple TransmissionFilter; - float OpticalDensity; - float Alpha; - float Shininess; - int IlluminationModel; + struct TextureMap + { + TextureMap() + : blendu(true) + , blendv(true) + , clamp(false) + , o(std::make_tuple(0.f, 0.f, 0.f)) + , s(std::make_tuple(1.f, 1.f, 1.f)) { } + + std::string FileName; + + // http://paulbourke.net/dataformats/mtl/ + // "These options are described in detail in 'Options for texture map statements' on page 5-18." + + // Horizontal texture blending + bool blendu; // = true + // Vertical texture blending + bool blendv; // = true + // Clamping + bool clamp; // = false + // Offset + std::tuple o; // = (0, 0, 0) + // Scale + std::tuple s; // = (1, 1, 1) + }; + + struct ColorMap : public TextureMap + { + ColorMap() + : cc(false) { } + + // Color correction + bool cc; // = false + }; + + struct BumpMap : public TextureMap + { + BumpMap() + : bm(1.f) { } + + // Bump multiplier + float bm; // = 1? + }; + + MaterialInfo() + : AmbientColor(std::make_tuple(0.2f, 0.2f, 0.2f)) + , DiffuseColor(std::make_tuple(0.8f, 0.8f, 0.8f)) + , SpecularColor(std::make_tuple(1.0f, 1.0f, 1.0f)) + , TransmissionFilter(std::make_tuple(1.0f, 1.0f, 1.0f)) + , OpticalDensity(1.0f) + , Alpha(1.0f) + , Shininess(0.0f) + , IlluminationModel(0) { } + + ColorMap DiffuseTexture; + ColorMap SpecularMap; + BumpMap NormalMap; + std::tuple AmbientColor; // = (0.2, 0.2, 0.2) + std::tuple DiffuseColor; // = (0.8, 0.8, 0.8) + std::tuple SpecularColor; // = (1, 1, 1) + std::tuple TransmissionFilter; // = (1, 1, 1) + float OpticalDensity; // = 1 + float Alpha; // = 1 + float Shininess; // = 0 + int IlluminationModel; // = 0 }; struct FaceDefinition @@ -59,6 +116,9 @@ private: MaterialInfo* m_CurrentMaterial; void ParseMaterial(); + void ParseTextureMap(unsigned int line, std::stringstream &ss, std::string prefix, std::string arg, MaterialInfo::TextureMap &textureMap); + void ParseColorMap(unsigned int line, std::stringstream &ss, std::string prefix, std::string arg, MaterialInfo::ColorMap &textureMap); + void ParseBumpMap(unsigned int line, std::stringstream &ss, std::string prefix, std::string arg, MaterialInfo::BumpMap &textureMap); }; #endif // OBJ_h__ \ No newline at end of file diff --git a/src/Physics/VehicleSetup.cpp b/src/Physics/VehicleSetup.cpp new file mode 100644 index 0000000..1768b1e --- /dev/null +++ b/src/Physics/VehicleSetup.cpp @@ -0,0 +1,296 @@ +#include "PrecompiledHeader.h" +#include "Physics/VehicleSetup.h" + + + + + +void VehicleSetup::buildVehicle(World *world, const hkpWorld* physicsWorld, hkpVehicleInstance& vehicle, EntityID vehicleEntity, std::vector wheelEntities) +{ + auto vehicleComponent = world->GetComponent(vehicleEntity, "Vehicle"); + + WheelData wheelData; + for (int i = 0; i < wheelEntities.size(); i++) + { + wheelData.WheelComponent = world->GetComponent(wheelEntities[i], "Wheel"); + wheelData.TransformComponent = world->GetComponent(wheelEntities[i], "Transform"); + m_Wheels.push_back(wheelData); + } + + // + // All memory allocations are made here. + // + vehicle.m_data = new hkpVehicleData; + vehicle.m_driverInput = new hkpVehicleDefaultAnalogDriverInput; + vehicle.m_steering = new hkpVehicleDefaultSteering; + vehicle.m_engine = new hkpVehicleDefaultEngine; + vehicle.m_transmission = new hkpVehicleDefaultTransmission; + vehicle.m_brake = new hkpVehicleDefaultBrake; + vehicle.m_suspension = new hkpVehicleDefaultSuspension; + vehicle.m_aerodynamics = new hkpVehicleDefaultAerodynamics; + vehicle.m_velocityDamper = new hkpVehicleDefaultVelocityDamper; + + // For illustrative purposes we use a custom hkpVehicleRayCastWheelCollide + // which implements varying 'ground' friction in a very simple way. + vehicle.m_wheelCollide = new hkpVehicleRayCastWheelCollide; + + setupVehicleData(physicsWorld, *vehicle.m_data); + + + setupComponent(*vehicle.m_data, *static_cast(vehicle.m_driverInput)); + setupComponent(*vehicle.m_data, *static_cast(vehicle.m_steering), *vehicleComponent); + setupComponent(*vehicle.m_data, *static_cast(vehicle.m_engine), *vehicleComponent); + setupComponent(*vehicle.m_data, *static_cast(vehicle.m_transmission), *vehicleComponent); + setupComponent(*vehicle.m_data, *static_cast(vehicle.m_brake), *vehicleComponent); + setupComponent(*vehicle.m_data, *static_cast(vehicle.m_suspension), *vehicleComponent); + setupComponent(*vehicle.m_data, *static_cast(vehicle.m_aerodynamics), *vehicleComponent); + setupComponent(*vehicle.m_data, *static_cast(vehicle.m_velocityDamper), *vehicleComponent); + + setupWheelCollide(physicsWorld, vehicle, *static_cast(vehicle.m_wheelCollide)); + + + // + // Check that all components are present. + // + HK_ASSERT(0x0 , vehicle.m_data); + HK_ASSERT(0x7708674a, vehicle.m_driverInput); + HK_ASSERT(0x5a324a2d, vehicle.m_steering); + HK_ASSERT(0x7bcb2aff, vehicle.m_engine); + HK_ASSERT(0x29bddb50, vehicle.m_transmission); + HK_ASSERT(0x2b0323a2, vehicle.m_brake); + HK_ASSERT(0x7a7ade23, vehicle.m_suspension); + HK_ASSERT(0x6ec4d0ed, vehicle.m_aerodynamics); + HK_ASSERT(0x67161206, vehicle.m_wheelCollide); + + // + // Set up any variables that store cached data. + // + + + // Give driver input default values so that the vehicle (if this input is a default for non + // player cars) will drive, even if it is in circles! + + // Steering Defaults + vehicle.m_deviceStatus = new hkpVehicleDriverInputAnalogStatus; + hkpVehicleDriverInputAnalogStatus* deviceStatus = (hkpVehicleDriverInputAnalogStatus*)vehicle.m_deviceStatus; + deviceStatus->m_positionY = 0.f; + deviceStatus->m_positionX = 0.f; + deviceStatus->m_handbrakeButtonPressed = false; + deviceStatus->m_reverseButtonPressed = false; + + // + // Don't forget to call init! (This function is necessary to set up derived data) + // + vehicle.init(); +} + +void VehicleSetup::setupVehicleData(const hkpWorld* world, hkpVehicleData& data ) +{ + data.m_gravity = world->getGravity(); + + // + // The vehicleData contains information about the chassis. + // + + // The coordinates of the chassis system, used for steering the vehicle. + // up forward right + data.m_chassisOrientation.setCols(hkVector4(0, 1, 0), hkVector4(0, 0, -1), hkVector4(1, 0, 0)); + + data.m_frictionEqualizer = 0.5f; + + + // Inertia tensor for each axis is calculated by using : + // (1 / chassis_mass) * (torque(axis)Factor / chassisUnitInertia) + data.m_torqueRollFactor = 0.625f; + data.m_torquePitchFactor = 0.5f; + data.m_torqueYawFactor = 0.35f; + + data.m_chassisUnitInertiaYaw = 1.0f; + data.m_chassisUnitInertiaRoll = 1.0f; + data.m_chassisUnitInertiaPitch = 1.0f; + + // Adds or removes torque around the yaw axis + // based on the current steering angle. This will + // affect steering. + data.m_extraTorqueFactor = -0.5f; + data.m_maxVelocityForPositionalFriction = 0.0f; + + // + // Wheel specifications + // + data.m_numWheels = m_Wheels.size(); + + data.m_wheelParams.setSize(data.m_numWheels); + + for (int i = 0; i < m_Wheels.size(); i++) + { + data.m_wheelParams[i].m_axle = m_Wheels[i].WheelComponent->AxleID; + data.m_wheelParams[i].m_friction = m_Wheels[i].WheelComponent->Friction; + data.m_wheelParams[i].m_slipAngle = m_Wheels[i].WheelComponent->SlipAngle; + + // This value is also used to calculate the m_primaryTransmissionRatio. + data.m_wheelParams[i].m_radius = m_Wheels[i].WheelComponent->Radius; + data.m_wheelParams[i].m_width = m_Wheels[i].WheelComponent->Width; + data.m_wheelParams[i].m_mass = m_Wheels[i].WheelComponent->Mass; + + + // May be in wheelcomponent later + data.m_wheelParams[i].m_viscosityFriction = 0.25f; + data.m_wheelParams[i].m_maxFriction = 2.0f * data.m_wheelParams[i].m_friction; + data.m_wheelParams[i].m_forceFeedbackMultiplier = 0.1f; + data.m_wheelParams[i].m_maxContactBodyAcceleration = hkReal(data.m_gravity.length3()) * 2; + } + + + + +} + +void VehicleSetup::setupComponent(const hkpVehicleData& data, hkpVehicleDefaultAnalogDriverInput& driverInput) +{ + // We also use an analog "driver input" class to help converting user input to vehicle behavior. + + driverInput.m_slopeChangePointX = 0.8f; + driverInput.m_initialSlope = 0.7f; + driverInput.m_deadZone = 0.0f; + driverInput.m_autoReverse = true; +} + +void VehicleSetup::setupComponent(const hkpVehicleData& data, hkpVehicleDefaultSteering& steering, Components::Vehicle vehicleComponent ) +{ + steering.m_doesWheelSteer.setSize(data.m_numWheels); + + // degrees + steering.m_maxSteeringAngle = vehicleComponent.MaxSteeringAngle * (HK_REAL_PI / 180); + + // [mph/h] The steering angle decreases linearly + // based on your overall max speed of the vehicle. + steering.m_maxSpeedFullSteeringAngle = 70.0f * (1.605f / 3.6f); //MPH???! + + for (int i = 0; i < m_Wheels.size(); i++) + { + steering.m_doesWheelSteer[i] = m_Wheels[i].WheelComponent->Steering; + } +} + +void VehicleSetup::setupComponent(const hkpVehicleData& data, hkpVehicleDefaultEngine& engine, Components::Vehicle vehicleComponent) +{ + engine.m_maxTorque = vehicleComponent.MaxTorque; + + engine.m_minRPM = vehicleComponent.MinRPM; + engine.m_optRPM = vehicleComponent.OptimalRPM; + + // This value is also used to calculate the m_primaryTransmissionRatio. + engine.m_maxRPM = vehicleComponent.MaxRPM; + + + + engine.m_torqueFactorAtMinRPM = 0.8f; + engine.m_torqueFactorAtMaxRPM = 0.8f; + engine.m_resistanceFactorAtMinRPM = 0.05f; + engine.m_resistanceFactorAtOptRPM = 0.1f; + engine.m_resistanceFactorAtMaxRPM = 0.3f; +} + +void VehicleSetup::setupComponent(const hkpVehicleData& data, hkpVehicleDefaultTransmission& transmission, Components::Vehicle vehicleComponent ) +{ + int numberOfGears = 4; + transmission.m_gearsRatio.setSize(numberOfGears); + transmission.m_wheelsTorqueRatio.setSize(data.m_numWheels); + + transmission.m_downshiftRPM = 3500.0f; + transmission.m_upshiftRPM = 6500.0f; + + transmission.m_clutchDelayTime = 0.0f; + transmission.m_reverseGearRatio = 1.0f; + transmission.m_gearsRatio[0] = 2.0f; + transmission.m_gearsRatio[1] = 1.5f; + transmission.m_gearsRatio[2] = 1.0f; + transmission.m_gearsRatio[3] = 0.75f; + transmission.m_wheelsTorqueRatio[0] = 0.2f; + transmission.m_wheelsTorqueRatio[1] = 0.2f; + transmission.m_wheelsTorqueRatio[2] = 0.3f; + transmission.m_wheelsTorqueRatio[3] = 0.3f; + + + transmission.m_primaryTransmissionRatio = hkpVehicleDefaultTransmission::calculatePrimaryTransmissionRatio( + vehicleComponent.TopSpeed, + m_Wheels[0].WheelComponent->Radius, // HACK: All wheels are the same size right? + vehicleComponent.MaxRPM, + transmission.m_gearsRatio[numberOfGears - 1]); +} + +void VehicleSetup::setupComponent(const hkpVehicleData& data, hkpVehicleDefaultBrake& brake, Components::Vehicle vehicleComponent ) +{ + brake.m_wheelBrakingProperties.setSize(data.m_numWheels); + + for (int i = 0; i < m_Wheels.size(); i++) + { + brake.m_wheelBrakingProperties[i].m_maxBreakingTorque = m_Wheels[i].WheelComponent->MaxBreakingTorque; + brake.m_wheelBrakingProperties[i].m_isConnectedToHandbrake = m_Wheels[i].WheelComponent->ConnectedToHandbrake; + + brake.m_wheelBrakingProperties[i].m_minPedalInputToBlock = 0.9f; + } + + brake.m_wheelsMinTimeToBlock = 1000.0f; +} + +void VehicleSetup::setupComponent(const hkpVehicleData& data, hkpVehicleDefaultSuspension& suspension, Components::Vehicle vehicleComponent) +{ + suspension.m_wheelParams.setSize(data.m_numWheels); + suspension.m_wheelSpringParams.setSize(data.m_numWheels); + + for (int i = 0; i < m_Wheels.size(); i++) + { + float suspensionLength = glm::length(m_Wheels[i].TransformComponent->Position - m_Wheels[i].WheelComponent->Hardpoint); + suspension.m_wheelParams[i].m_length = suspensionLength; + suspension.m_wheelSpringParams[i].m_strength = m_Wheels[i].WheelComponent->SuspensionStrength; + + const float wd = 3.0f; + suspension.m_wheelSpringParams[i].m_dampingCompression = wd; + suspension.m_wheelSpringParams[i].m_dampingRelaxation = wd; + + + suspension.m_wheelParams[i].m_hardpointChassisSpace.set(m_Wheels[i].WheelComponent->Hardpoint.x, m_Wheels[i].WheelComponent->Hardpoint.y, m_Wheels[i].WheelComponent->Hardpoint.z); + + suspension.m_wheelParams[i].m_directionChassisSpace = hkVector4(m_Wheels[i].WheelComponent->DownDirection.x, m_Wheels[i].WheelComponent->DownDirection.y, m_Wheels[i].WheelComponent->DownDirection.z); + } +} + +void VehicleSetup::setupComponent(const hkpVehicleData& data, hkpVehicleDefaultAerodynamics& aerodynamics, Components::Vehicle vehicleComponent ) +{ + aerodynamics.m_airDensity = 1.3f; + // In m^2. + aerodynamics.m_frontalArea = 1.0f; + + aerodynamics.m_dragCoefficient = 0.7f; + aerodynamics.m_liftCoefficient = -0.3f; + + // Extra gavity applies in world space (independent of m_chassisCoordinateSystem). + aerodynamics.m_extraGravityws.set(0.0f, -5.0f, 0.0f); +} + +void VehicleSetup::setupComponent(const hkpVehicleData& data, hkpVehicleDefaultVelocityDamper& velocityDamper, Components::Vehicle vehicleComponent) +{ + // Caution: setting negative damping values will add energy to system. + // Setting the value to 0 will not affect the angular velocity. + + // Damping the change of the chassis angular velocity when below m_collisionThreshold. + // This will affect turning radius and steering. + velocityDamper.m_normalSpinDamping = 0.0f; + + // Positive numbers dampen the rotation of the chassis and + // reduce the reaction of the chassis in a collision. + velocityDamper.m_collisionSpinDamping = 4.0f; + + // The threshold in m/s at which the algorithm switches from + // using the normalSpinDamping to the collisionSpinDamping. + velocityDamper.m_collisionThreshold = 1.0f; +} + +void VehicleSetup::setupWheelCollide(const hkpWorld* world, const hkpVehicleInstance& vehicle, hkpVehicleRayCastWheelCollide& wheelCollide) +{ + // Set the wheels to have the same collision filter info as the chassis. + wheelCollide.m_wheelCollisionFilterInfo = vehicle.getChassis()->getCollisionFilterInfo(); +} + diff --git a/src/Physics/VehicleSetup.h b/src/Physics/VehicleSetup.h new file mode 100644 index 0000000..b54adbd --- /dev/null +++ b/src/Physics/VehicleSetup.h @@ -0,0 +1,63 @@ +#ifndef Physics_Vehicle_h__ +#define Physics_Vehicle_h__ + +//#include "PrecompiledHeader.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +// Vehicle page 425 in documentation +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "World.h" +#include "Components/Vehicle.h" +#include "Components/Wheel.h" +#include "Components/Transform.h" + +class VehicleSetup +{ +public: + virtual void VehicleSetup::buildVehicle(World *world, const hkpWorld* physicsWorld, hkpVehicleInstance& vehicle, EntityID vehicleEntity, std::vector wheelEntities); + +public: + struct WheelData + { + Components::Wheel* WheelComponent; + Components::Transform* TransformComponent; + }; + + std::vector m_Wheels; + + virtual void setupVehicleData(const hkpWorld* world, hkpVehicleData& data); + virtual void setupComponent(const hkpVehicleData& data, hkpVehicleDefaultAnalogDriverInput& driverInput); + virtual void setupComponent(const hkpVehicleData& data, hkpVehicleDefaultEngine& engine, Components::Vehicle vehicleComponent); + virtual void setupComponent(const hkpVehicleData& data, hkpVehicleDefaultSteering& steering, Components::Vehicle vehicleComponent); + + virtual void setupComponent(const hkpVehicleData& data, hkpVehicleDefaultTransmission& transmission, Components::Vehicle vehicleComponent); + virtual void setupComponent(const hkpVehicleData& data, hkpVehicleDefaultBrake& brake, Components::Vehicle vehicleComponent ); + virtual void setupComponent(const hkpVehicleData& data, hkpVehicleDefaultSuspension& suspension, Components::Vehicle vehicleComponent); + virtual void setupComponent(const hkpVehicleData& data, hkpVehicleDefaultAerodynamics& aerodynamics, Components::Vehicle vehicleComponent ); + virtual void setupComponent(const hkpVehicleData& data, hkpVehicleDefaultVelocityDamper& velocityDamper, Components::Vehicle vehicleComponent); + + virtual void setupWheelCollide(const hkpWorld* world, const hkpVehicleInstance& vehicle, hkpVehicleRayCastWheelCollide& wheelCollide); +}; + +#endif // Physics_Vehicle_h__ diff --git a/src/ResourceManager.cpp b/src/ResourceManager.cpp index 4b864d6..1361c11 100644 --- a/src/ResourceManager.cpp +++ b/src/ResourceManager.cpp @@ -9,10 +9,6 @@ Resource* ResourceManager::CreateResource(std::string resourceType, std::string LOG_ERROR("Failed to load resource \"%s\" of type \"%s\": Type not registered", resourceName.c_str(), resourceType.c_str()); return nullptr; } - - auto resIt = m_ResourceCache.find(resourceName); - if (resIt != m_ResourceCache.end()) - return resIt->second; // Call the factory function Resource* resource = facIt->second(resourceName); @@ -32,7 +28,16 @@ void ResourceManager::RegisterType(std::string resourceType, std::function factoryFunction); // Loads a resource and caches it for future use void Preload(std::string resourceType, std::string resourceName); - + + // Checks if a resource is in cache + bool IsResourceLoaded(std::string resourceName); + template // Hot-loads a resource and caches it for future use T* Load(std::string resourceType, std::string resourceName); @@ -44,6 +47,8 @@ private: std::unordered_map m_ResourceTypeIDs; // Number of resources of a type. Doubles as local ID. std::unordered_map m_ResourceCount; + // Flag to suppress hot-load warnings when a preloading resource chain loads another resource + bool m_Preloading; unsigned int GetTypeID(std::string resourceType); unsigned int GetNewResourceID(unsigned int typeID); @@ -55,20 +60,34 @@ private: template T* ResourceManager::Load(std::string resourceType, std::string resourceName) { + auto it = m_ResourceCache.find(resourceName); + if (it != m_ResourceCache.end()) + return static_cast(it->second); + + if (m_Preloading) + { + LOG_INFO("Preloading resource \"%s\"", resourceName.c_str()); + } + else + { + LOG_WARNING("Hot-loading resource \"%s\"", resourceName.c_str()); + } + return static_cast(CreateResource(resourceType, resourceName)); } template T* ResourceManager::Fetch(std::string resourceName) const { - if (m_ResourceCache.find(resourceName) == m_ResourceCache.end()) + auto it = m_ResourceCache.find(resourceName); + if (it == m_ResourceCache.end()) { LOG_ERROR("Failed to fetch resource \"%s\": Resource not loaded!", resourceName.c_str()); return nullptr; } else { - return static_cast(m_ResourceCache.at(resourceName)); + return static_cast(it->second); } } diff --git a/src/Shaders/Fragment.glsl b/src/Shaders/Fragment.glsl index 11a43ab..1909e84 100755 --- a/src/Shaders/Fragment.glsl +++ b/src/Shaders/Fragment.glsl @@ -52,7 +52,7 @@ void main() //float bias = 0.001 * tan(acos(cosTheta)); // cosTheta is dot( n,l ), clamped between 0 and 1 //bias = clamp(bias, 0.0, 0.01); float visibility = 1.0; - if (Input.ShadowCoord.x >= 0.0 && Input.ShadowCoord.x <= 1.0 && Input.ShadowCoord.y >= 0.0 && Input.ShadowCoord.y <= 1.0) + /*if (Input.ShadowCoord.x >= 0.0 && Input.ShadowCoord.x <= 1.0 && Input.ShadowCoord.y >= 0.0 && Input.ShadowCoord.y <= 1.0) { float bias = 0.00005; vec4 shadowMapValue = texture(shadowMap, Input.ShadowCoord.xy); @@ -60,7 +60,7 @@ void main() { visibility = 0.3; } - } + }*/ vec3 totalLighting = La * Ka * visibility; diff --git a/src/Systems/FreeSteeringSystem.cpp b/src/Systems/FreeSteeringSystem.cpp index f1ed04e..b382b23 100755 --- a/src/Systems/FreeSteeringSystem.cpp +++ b/src/Systems/FreeSteeringSystem.cpp @@ -24,8 +24,8 @@ void Systems::FreeSteeringSystem::UpdateEntity(double dt, EntityID entity, Entit { auto transform = m_World->GetComponent(entity, "Transform"); - glm::vec3 cameraRight = glm::vec3(glm::vec4(1, 0, 0, 0) * m_InputController->Orientation); - glm::vec3 cameraForward = glm::vec3(glm::vec4(0, 0, -1, 0) * m_InputController->Orientation); + glm::vec3 cameraRight = glm::vec3(m_InputController->Orientation * glm::vec4(1, 0, 0, 0)); + glm::vec3 cameraForward = glm::vec3(m_InputController->Orientation * glm::vec4(0, 0, -1, 0)); glm::vec3 movement; movement += cameraRight * m_InputController->Movement.x; movement.y += m_InputController->Movement.y; @@ -124,7 +124,7 @@ bool Systems::FreeSteeringSystem::FreeSteeringInputController::OnMouseMove(const { // TOUCHING THIS CODE MIGHT CAUSE THE UNIVERSE TO IMPLODE, ALSO DRAGONS //--------------------------------------------------------------------- - Orientation = glm::angleAxis(event.DeltaY / 300.f, glm::vec3(1, 0, 0)) * Orientation * glm::angleAxis(event.DeltaX / 300.f, glm::vec3(0, 1, 0)); + Orientation = glm::angleAxis(event.DeltaX / 300.f, glm::vec3(0, -1, 0)) * Orientation * glm::angleAxis(event.DeltaY / 300.f, glm::vec3(-1, 0, 0)); //--------------------------------------------------------------------- // TOUCHING THIS CODE MIGHT CAUSE THE UNIVERSE TO IMPLODE, ALSO DRAGONS } diff --git a/src/Systems/PhysicsSystem.cpp b/src/Systems/PhysicsSystem.cpp index ff3607c..dfb7a8b 100644 --- a/src/Systems/PhysicsSystem.cpp +++ b/src/Systems/PhysicsSystem.cpp @@ -25,10 +25,9 @@ #include "PhysicsSystem.h" #include "World.h" - - void Systems::PhysicsSystem::Initialize() { + m_Accumulator = 0; { hkMemorySystem::FrameInfo finfo(500 * 1024); // Allocate 500KB of Physics solver buffer hkMemoryRouter* memoryRouter = hkMemoryInitUtil::initDefault(hkMallocAllocator::m_defaultMallocAllocator, finfo); @@ -41,7 +40,7 @@ void Systems::PhysicsSystem::Initialize() worldInfo.m_broadPhaseBorderBehaviour = hkpWorldCinfo::BROADPHASE_BORDER_FIX_ENTITY; // just fix the entity if the object falls off too far // You must specify the size of the broad phase - objects should not be simulated outside this region - worldInfo.setBroadPhaseWorldSize(10000.0f); + worldInfo.setBroadPhaseWorldSize(1000.0f); m_PhysicsWorld = new hkpWorld(worldInfo); } // Register all collision agents, even though only box - box will be used in this particular example. @@ -64,11 +63,39 @@ void Systems::PhysicsSystem::Initialize() void Systems::PhysicsSystem::RegisterComponents(ComponentFactory* cf) { cf->Register("Physics", []() { return new Components::Physics(); }); + cf->Register("Box", []() { return new Components::Box(); }); + cf->Register("Sphere", []() { return new Components::Sphere(); }); + cf->Register("Vehicle", []() { return new Components::Vehicle(); }); + cf->Register("Wheel", []() { return new Components::Wheel(); }); } void Systems::PhysicsSystem::Update(double dt) { - static const double timestep = 1 / 60.0; + for (auto pair : *m_World->GetEntities()) + { + EntityID entity = pair.first; + + if (m_RigidBodies.find(entity) == m_RigidBodies.end()) + continue; + + auto transformComponent = m_World->GetComponent(entity, "Transform"); + if (!transformComponent) + continue; + + + if(m_RigidBodies[entity]->isActive()) + { + hkVector4 position(transformComponent->Position.x, transformComponent->Position.y, transformComponent->Position.z); + hkQuaternion rotation(transformComponent->Orientation.x, transformComponent->Orientation.y, transformComponent->Orientation.z, transformComponent->Orientation.w); + m_RigidBodies[entity]->setPositionAndRotation(position, rotation); + } + + } + + + + + static const double timestep = 1 / 30.0; m_Accumulator += dt; while (m_Accumulator >= timestep) { @@ -85,21 +112,170 @@ void Systems::PhysicsSystem::UpdateEntity(double dt, EntityID entity, EntityID p auto transformComponent = m_World->GetComponent(entity, "Transform"); if (!transformComponent) return; - - if (m_RigidBodies.find(entity) == m_RigidBodies.end()) + + auto wheelComponent = m_World->GetComponent(entity, "Wheel"); + if (wheelComponent) { - SetUpPhysicsState(entity, parent); + EntityID car = m_World->GetEntityParent(entity); + if(m_Vehicles.find(car) != m_Vehicles.end()) + { + m_Vehicles[car]->getChassis()->activate(); + + hkVector4 hardPoint = m_Vehicles[car]->m_suspension->m_wheelParams[wheelComponent->ID].m_hardpointChassisSpace; + hkVector4 suspensionDirection = m_Vehicles[car]->m_suspension->m_wheelParams[wheelComponent->ID].m_directionChassisSpace; + hkReal suspensionLength = m_Vehicles[car]->m_wheelsInfo[wheelComponent->ID].m_currentSuspensionLength; + glm::vec3 position = glm::vec3(hardPoint(0) + (suspensionDirection(0) * suspensionLength), hardPoint(1) + (suspensionDirection(1) * suspensionLength), hardPoint(2) + (suspensionDirection(2) * suspensionLength)); + transformComponent->Position = position; + + hkQuaternion steeringOrientation = m_Vehicles[car]->m_wheelsInfo[wheelComponent->ID].m_steeringOrientationChassisSpace; + hkReal spinAngle = -m_Vehicles[car]->m_wheelsInfo[wheelComponent->ID].m_spinAngle; + glm::quat orientation = glm::quat(steeringOrientation(3), steeringOrientation(0), steeringOrientation(1), steeringOrientation(2)) * glm::angleAxis(spinAngle, glm::vec3(1, 0, 0)); + transformComponent->Orientation = orientation * wheelComponent->OriginalOrientation; + } } - else + else if(m_Vehicles.find(entity) != m_Vehicles.end()) { hkVector4 position = m_RigidBodies[entity]->getPosition(); transformComponent->Position = glm::vec3(position(0), position(1), position(2)); hkQuaternion orientation = m_RigidBodies[entity]->getRotation(); transformComponent->Orientation = glm::quat(orientation(3),orientation(0), orientation(1), orientation(2)); + + } + else if(m_RigidBodies.find(entity) != m_RigidBodies.end()) + { + if(m_RigidBodies[entity]->isActive()) + { + hkVector4 position = m_RigidBodies[entity]->getPosition(); + transformComponent->Position = glm::vec3(position(0), position(1), position(2)); + hkQuaternion orientation = m_RigidBodies[entity]->getRotation(); + transformComponent->Orientation = glm::quat(orientation(3),orientation(0), orientation(1), orientation(2)); + } + } + + + // HACK: Vehicle test-controls + auto vehicleComponent = m_World->GetComponent(entity, "Vehicle"); + auto inputComponent = m_World->GetComponent(entity, "Input"); + if (vehicleComponent && inputComponent) + { + hkpVehicleDriverInputAnalogStatus* deviceStatus = (hkpVehicleDriverInputAnalogStatus*)m_Vehicles[entity]->m_deviceStatus; + deviceStatus->m_positionY = inputComponent->KeyState[GLFW_KEY_UP] * -1 + inputComponent->KeyState[GLFW_KEY_DOWN] * 1; + deviceStatus->m_positionX = inputComponent->KeyState[GLFW_KEY_LEFT] * -1 + inputComponent->KeyState[GLFW_KEY_RIGHT] * 1; + deviceStatus->m_handbrakeButtonPressed = inputComponent->KeyState[GLFW_KEY_RIGHT_CONTROL]; + } +} + +void Systems::PhysicsSystem::OnEntityCommit( EntityID entity ) +{ + auto transformComponent = m_World->GetComponent(entity, "Transform"); + if (!transformComponent) + return; + + + auto wheelComponent = m_World->GetComponent(entity, "Wheel"); + if (wheelComponent) + { + wheelComponent->ID = m_Wheels.size(); + wheelComponent->OriginalOrientation = transformComponent->Orientation; + m_Wheels.push_back(entity); } + auto physicsComponent = m_World->GetComponent(entity, "Physics"); + if (!physicsComponent) + return; + auto sphereComponent = m_World->GetComponent(entity, "Sphere"); + auto boxComponent = m_World->GetComponent(entity, "Box"); + + + hkpConvexShape* shape; + hkpRigidBodyCinfo rigidBodyInfo; + hkMassProperties massProperties; + + if (sphereComponent) + { + shape = new hkpSphereShape(sphereComponent->Radius); + rigidBodyInfo.m_shape = shape; + + if (physicsComponent->Static) + { + rigidBodyInfo.m_motionType = hkpMotion::MOTION_FIXED; + } + else + { + rigidBodyInfo.m_motionType = hkpMotion::MOTION_SPHERE_INERTIA; + } + + hkpInertiaTensorComputer::computeSphereVolumeMassProperties(sphereComponent->Radius, physicsComponent->Mass, massProperties); + + } + else if (boxComponent) + { + hkReal thickness = 0.05; + shape = new hkpBoxShape(hkVector4(boxComponent->Width - thickness, boxComponent->Height - thickness, boxComponent->Depth - thickness)); + rigidBodyInfo.m_shape = shape; + if (physicsComponent->Static) + { + rigidBodyInfo.m_motionType = hkpMotion::MOTION_FIXED; + } + else + { + rigidBodyInfo.m_motionType = hkpMotion::MOTION_BOX_INERTIA; + } + hkpInertiaTensorComputer::computeBoxSurfaceMassProperties(hkVector4(boxComponent->Width - thickness, boxComponent->Height - thickness, boxComponent->Depth - thickness), physicsComponent->Mass, thickness, massProperties); + } + else + { + return; + } + + rigidBodyInfo.m_position.set(transformComponent->Position.x, transformComponent->Position.y, transformComponent->Position.z); + rigidBodyInfo.m_inertiaTensor = massProperties.m_inertiaTensor; + rigidBodyInfo.m_centerOfMass = massProperties.m_centerOfMass; + rigidBodyInfo.m_mass = massProperties.m_mass; + + // Create RigidBody + hkpRigidBody* rigidBody = new hkpRigidBody(rigidBodyInfo); + + + auto vehicleComponent = m_World->GetComponent(entity, "Vehicle"); + if (vehicleComponent && m_Vehicles.find(entity) == m_Vehicles.end()) + { + for (int i = 0; i < m_Wheels.size(); i++) + { + if(m_World->GetEntityParent(m_Wheels[i]) != entity) + { + m_Wheels.erase(m_Wheels.begin() + i); + i--; + } + } + VehicleSetup vehicleSetup; + + // Create the basic vehicle. + m_Vehicles[entity] = new hkpVehicleInstance(rigidBody); + vehicleSetup.buildVehicle(m_World, m_PhysicsWorld, *m_Vehicles[entity], entity, m_Wheels); + // Add the vehicle's entities and phantoms to the world + m_Vehicles[entity]->addToWorld(m_PhysicsWorld); + + m_RigidBodies[entity] = rigidBody; + + // The vehicle is an action + m_PhysicsWorld->addAction(m_Vehicles[entity]); + + //m_Vehicles[entity]->m_rpm = 0.0f; // Not sure why this one should be here + m_Wheels.clear(); + shape->removeReference(); + rigidBody->removeReference(); + } + else + { + m_PhysicsWorld->addEntity(rigidBody); + m_RigidBodies[entity] = rigidBody; + shape->removeReference(); + rigidBody->removeReference(); + } } +/* void Systems::PhysicsSystem::SetUpPhysicsState(EntityID entity, EntityID parent) { @@ -124,17 +300,32 @@ void Systems::PhysicsSystem::SetUpPhysicsState(EntityID entity, EntityID parent) { shape = new hkpSphereShape(sphereComponent->Radius); rigidBodyInfo.m_shape = shape; - rigidBodyInfo.m_motionType = hkpMotion::MOTION_SPHERE_INERTIA; + + if (physicsComponent->Static) + { + rigidBodyInfo.m_motionType = hkpMotion::MOTION_FIXED; + } + else + { + rigidBodyInfo.m_motionType = hkpMotion::MOTION_SPHERE_INERTIA; + } hkpInertiaTensorComputer::computeSphereVolumeMassProperties(sphereComponent->Radius, physicsComponent->Mass, massProperties); } else if (boxComponent) { - shape = new hkpBoxShape(hkVector4(boxComponent->Width, boxComponent->Height, boxComponent->Depth)); + hkReal thickness = 0.05; + shape = new hkpBoxShape(hkVector4(boxComponent->Width - thickness, boxComponent->Height - thickness, boxComponent->Depth - thickness)); rigidBodyInfo.m_shape = shape; - rigidBodyInfo.m_motionType = hkpMotion::MOTION_FIXED; - hkReal thickness = 0.1; + if (physicsComponent->Static) + { + rigidBodyInfo.m_motionType = hkpMotion::MOTION_FIXED; + } + else + { + rigidBodyInfo.m_motionType = hkpMotion::MOTION_BOX_INERTIA; + } hkpInertiaTensorComputer::computeBoxSurfaceMassProperties(hkVector4(boxComponent->Width - thickness, boxComponent->Height - thickness, boxComponent->Depth - thickness), physicsComponent->Mass, thickness, massProperties); } else @@ -149,13 +340,41 @@ void Systems::PhysicsSystem::SetUpPhysicsState(EntityID entity, EntityID parent) // Create RigidBody hkpRigidBody* rigidBody = new hkpRigidBody(rigidBodyInfo); - shape->removeReference(); + - m_PhysicsWorld->addEntity(rigidBody); - m_RigidBodies[entity] = rigidBody; - rigidBody->removeReference(); + auto vehicleComponent = m_World->GetComponent(entity, "Vehicle"); + if (vehicleComponent && m_Vehicles.find(entity) == m_Vehicles.end()) + { + VehicleSetup vehicleSetup; + // Create the basic vehicle. + m_Vehicles[entity] = new hkpVehicleInstance(rigidBody); + vehicleSetup.buildVehicle(m_PhysicsWorld, *m_Vehicles[entity]); + // Add the vehicle's entities and phantoms to the world + m_Vehicles[entity]->addToWorld(m_PhysicsWorld); + + m_RigidBodies[entity] = rigidBody; + + // The vehicle is an action + m_PhysicsWorld->addAction(m_Vehicles[entity]); + + //m_Vehicles[entity]->m_rpm = 0.0f; // Not sure why this one should be here + + shape->removeReference(); + rigidBody->removeReference(); + } + else + { + m_PhysicsWorld->addEntity(rigidBody); + m_RigidBodies[entity] = rigidBody; + shape->removeReference(); + rigidBody->removeReference(); + } } +*/ + + + void Systems::PhysicsSystem::TearDownPhysicsState(EntityID entity, EntityID parent) { @@ -201,5 +420,6 @@ void Systems::PhysicsSystem::StepVisualDebugger() void HK_CALL Systems::PhysicsSystem::HavokErrorReport(const char* msg, void*) { - LOG_DEBUG("%s", msg); + LOG_INFO("%s", msg); } + diff --git a/src/Systems/PhysicsSystem.h b/src/Systems/PhysicsSystem.h index 0544b13..c6ebe4a 100644 --- a/src/Systems/PhysicsSystem.h +++ b/src/Systems/PhysicsSystem.h @@ -1,18 +1,15 @@ #ifndef PhysicsSystem_h__ #define PhysicsSystem_h__ - - - - #include "System.h" #include "Components/Transform.h" #include "Components/Physics.h" #include "Components/Sphere.h" #include "Components/Box.h" +#include "Components/Vehicle.h" +#include "Components/Input.h" // Math and base include - #include #include #include @@ -29,8 +26,6 @@ #include #include - - #include #include #include @@ -39,6 +34,8 @@ #include #include +#include "Physics/VehicleSetup.h" + #include namespace Systems { @@ -56,10 +53,9 @@ public: void UpdateEntity(double dt, EntityID entity, EntityID parent) override; void OnComponentCreated(std::string type, std::shared_ptr component) override; void OnComponentRemoved(std::string type, Component* component) override; - + void OnEntityCommit(EntityID entity) override; private: - double m_Accumulator; hkpWorld* m_PhysicsWorld; @@ -73,7 +69,10 @@ private: void SetupPhysics(hkpWorld* physicsWorld); std::unordered_map m_RigidBodies; + std::unordered_map m_Vehicles; + std::vector m_Wheels; + hkpVehicleInstance* Systems::PhysicsSystem::createVehicle(VehicleSetup& vehicleSetup, hkpRigidBody* chassis); }; } diff --git a/src/Systems/RenderSystem.cpp b/src/Systems/RenderSystem.cpp index d8c3c19..fe254f4 100755 --- a/src/Systems/RenderSystem.cpp +++ b/src/Systems/RenderSystem.cpp @@ -47,8 +47,8 @@ void Systems::RenderSystem::UpdateEntity(double dt, EntityID entity, EntityID pa auto cameraComponent = m_World->GetComponent(entity, "Camera"); if (cameraComponent != nullptr) { - m_Renderer->GetCamera()->Position(transformComponent->Position); - m_Renderer->GetCamera()->Orientation(transformComponent->Orientation); + m_Renderer->GetCamera()->Position(m_TransformSystem->AbsolutePosition(entity)); + m_Renderer->GetCamera()->Orientation(m_TransformSystem->AbsoluteOrientation(entity)); m_Renderer->GetCamera()->FOV(cameraComponent->FOV); m_Renderer->GetCamera()->NearClip(cameraComponent->NearClip); diff --git a/src/Systems/TransformSystem.cpp b/src/Systems/TransformSystem.cpp index a23d92b..494acd0 100755 --- a/src/Systems/TransformSystem.cpp +++ b/src/Systems/TransformSystem.cpp @@ -40,7 +40,7 @@ glm::quat Systems::TransformSystem::AbsoluteOrientation(EntityID entity) do { auto transform = m_World->GetComponent(entity, "Transform"); - absOrientation *= transform->Orientation; + absOrientation = transform->Orientation * absOrientation; entity = m_World->GetEntityParent(entity); } while (entity != 0); diff --git a/src/World.h b/src/World.h index fd496cd..3581be1 100755 --- a/src/World.h +++ b/src/World.h @@ -143,7 +143,16 @@ std::shared_ptr World::AddComponent(EntityID entity, std::string componentTyp template T* World::GetComponent(EntityID entity, std::string componentType) { - return (T*)m_EntityComponents[entity][componentType].get(); + auto components = m_EntityComponents[entity]; + auto it = components.find(componentType); + if (it != components.end()) + { + return static_cast(it->second.get()); + } + else + { + return nullptr; + } } #endif // World_h__ \ No newline at end of file diff --git a/vs11/Returngeance/Returngeance.vcxproj b/vs11/Returngeance/Returngeance.vcxproj index 88d37ff..f9a533a 100755 --- a/vs11/Returngeance/Returngeance.vcxproj +++ b/vs11/Returngeance/Returngeance.vcxproj @@ -65,7 +65,7 @@ true - OpenAL32.lib;opengl32.lib;glu32.lib;SOIL.lib;glew32d.lib;glfw3.lib;hkBase.lib;hkVisualize.lib;hkInternal.lib;hkSerialize.lib;hkGeometryUtilities.lib;hkcdInternal.lib;hkcdCollide.lib;hkpCollide.lib;hkpConstraint.lib;hkpConstraintSolver.lib;hkpDynamics.lib;hkpInternal.lib;hkpUtilities.lib;hkSceneData.lib;%(AdditionalDependencies) + OpenAL32.lib;opengl32.lib;glu32.lib;SOIL.lib;glew32d.lib;glfw3.lib;hkBase.lib;hkVisualize.lib;hkInternal.lib;hkSerialize.lib;hkGeometryUtilities.lib;hkcdInternal.lib;hkcdCollide.lib;hkpCollide.lib;hkpConstraint.lib;hkpConstraintSolver.lib;hkpDynamics.lib;hkpInternal.lib;hkpUtilities.lib;hkSceneData.lib;hkpVehicle.lib;%(AdditionalDependencies) /ignore:4221 @@ -89,7 +89,7 @@ true true true - OpenAL32.lib;opengl32.lib;glu32.lib;SOIL.lib;glew32.lib;glfw3.lib;hkaAnimation.lib;hkaInternal.lib;hkaPhysics2012Bridge.lib;hkBase.lib;hkcdCollide.lib;hkcdInternal.lib;hkCompat.lib;hkgBridge.lib;hkgCommon.lib;hkgDx11.lib;hkgDx9s.lib;hkGeometryUtilities.lib;hkgOglES.lib;hkgOglES2.lib;hkgOgls.lib;hkgSoundCommon.lib;hkgSoundXAudio2.lib;hkInternal.lib;hkpCollide.lib;hkpConstraint.lib;hkpConstraintSolver.lib;hkpDynamics.lib;hkpInternal.lib;hkpUtilities.lib;hkpVehicle.lib;hkSceneData.lib;hkSerialize.lib;hkVisualize.lib;%(AdditionalDependencies) + OpenAL32.lib;opengl32.lib;glu32.lib;SOIL.lib;glew32.lib;glfw3.lib;hkBase.lib;hkVisualize.lib;hkInternal.lib;hkSerialize.lib;hkGeometryUtilities.lib;hkcdInternal.lib;hkcdCollide.lib;hkpCollide.lib;hkpConstraint.lib;hkpConstraintSolver.lib;hkpDynamics.lib;hkpInternal.lib;hkpUtilities.lib;hkSceneData.lib;hkpVehicle.lib;%(AdditionalDependencies) @@ -102,6 +102,7 @@ + @@ -136,6 +137,8 @@ + + @@ -156,6 +159,7 @@ + diff --git a/vs11/Returngeance/Returngeance.vcxproj.filters b/vs11/Returngeance/Returngeance.vcxproj.filters index f76cb42..f0145be 100755 --- a/vs11/Returngeance/Returngeance.vcxproj.filters +++ b/vs11/Returngeance/Returngeance.vcxproj.filters @@ -51,6 +51,7 @@ + Input @@ -225,8 +226,19 @@ Audio - - + + + Physics\Components + + + Physics\Components + + + Physics\Components + + + Physics\Components + GUI