Commit 798955ec authored by Dario Seyb's avatar Dario Seyb

added scene system and moved main code to OrbitalsScene

parent c55e66af
Pipeline #471 skipped
......@@ -11,8 +11,6 @@
#include <engine/graphics/RendererSystem.hpp>
class OrbitalSimulationSystem : public System {
private:
EventSystem* m_events;
......
#pragma once
#include <engine/core/Context.hpp>
#include <engine/core/System.hpp>
#include <engine/events/EventSystem.hpp>
#include <engine/scene/SceneGraphSystem.hpp>
#include <engine/core/SimulateEvent.hpp>
#include <engine/scene/Entity.hpp>
#include <engine/scene/Planet.hpp>
<<<<<<< HEAD
#include <engine/graphics/RendererSystem.hpp>
=======
#include <vector>
#include <engine/graphics/RendererSystem.hpp>
>>>>>>> master
class OrbitalSimulationSystem : public System {
private:
EventSystem* m_events;
SceneGraphSystem *m_scene;
RendererSystem *m_renderer;
<<<<<<< HEAD
=======
>>>>>>> master
Geometry defaultGeom;
Geometry orbitTorus;
Material defaultMat;
Material defaultMat2;
std::vector<Entity> trajectories;
glm::vec3 applyKepler(Planet::Handle planet, float dt);
public:
CONSTRUCT_SYSTEM(OrbitalSimulationSystem) {}
const float solarRadius = 696342;
const float scaleFactor = 0.001;
const float distanceScale = 0.01;
Entity addPlanet(Transform::Handle sun, std::string n, double m, double r, double e, double a, double i, double N, double P, double T);
bool startup() override;
void shutdown() override;
void simulateOrbitals(float dt, float totalTime);
float solarToWorld(double solar);
float AUToWorld(double au);
double solarToAU(double s);
double AUToSolar(double au);
void enableTrajectories();
};
\ No newline at end of file
#pragma once
#include <engine/core/Context.hpp>
#include <engine/core/System.hpp>
#include <engine/events/EventSystem.hpp>
#include <engine/audio/AudioSystem.hpp>
#include <engine/graphics/RendererSystem.hpp>
#include <engine/ui/UISystem.hpp>
#define CONSTRUCT_SCENE(scene) scene(Context* context, std::string iniFile) : Scene(context, iniFile)
class Scene : public System {
protected:
EventSystem* m_events;
RendererSystem* m_renderer;
SceneGraphSystem* m_sceneGraph;
AudioSystem* m_audio;
std::string m_name;
std::unordered_map<std::string, void*> m_iniValues;
public:
CONSTRUCT_SYSTEM(Scene, std::string iniFile) { }
std::string getName() { return m_name; }
bool startup() override {
RESOLVE_DEPENDENCY(m_events);
RESOLVE_DEPENDENCY(m_renderer);
RESOLVE_DEPENDENCY(m_sceneGraph);
RESOLVE_DEPENDENCY(m_audio);
}
};
\ No newline at end of file
#pragma once
#include <engine/scene/Entity.hpp>
#include <ACGL/Math/Math.hh>
#include <engine/graphics/DrawCall.hpp>
struct Transform : Component<Transform> {
Transform::Handle parent;
......
#pragma once
#include <engine/scene/Scene.hpp>
#include <engine/scene/OrbitalSimulationSystem.hpp>
#include <engine/scene/PlayerSystem.hpp>
#include <engine/audio/SoundSource.hpp>
class OrbitsScene : public Scene {
private:
OrbitalSimulationSystem* m_orbitals;
PlayerSystem* m_player;
SoundSource::Handle soundSource;
Entity sun;
Entity mercury;
Entity venus;
Entity earth;
Entity mars;
Entity jupiter;
Entity saturn;
Entity uranus;
Entity neptune;
public:
CONSTRUCT_SCENE(OrbitsScene) { };
bool startup() override;
void shutdown() override;
};
\ No newline at end of file
#pragma once
#include <GL/gl.h>
#include <ACGL/OpenGL/GL.hh>
class Tile {
......
#include <engine/scene/OrbitalSimulationSystem.hpp>
#include <ACGL/ACGL.hh>
#include <ACGL/OpenGL/Creator/ShaderProgramCreator.hh>
#include <ACGL/OpenGL/Creator/VertexArrayObjectCreator.hh>
#include <ACGL/OpenGL/Creator/Texture2DCreator.hh>
#include <ACGL/OpenGL/Objects.hh>
#include <ACGL/Base/Settings.hh>
#include <ACGL/Math/Math.hh>
#include <ACGL/OpenGL/Data/TextureLoadStore.hh>
#include <ACGL/OpenGL/Managers.hh>
#include <engine/scene/Drawable.hpp>
#include <engine/scene/Transform.hpp>
#include <math.h>
#include <iostream>
bool OrbitalSimulationSystem::startup() {
RESOLVE_DEPENDENCY(m_events);
RESOLVE_DEPENDENCY(m_scene);
RESOLVE_DEPENDENCY(m_renderer);
m_events->subscribe<SimulateEvent>([this](const SimulateEvent &e) { simulateOrbitals(e.dt, e.totalTime); });
// Make a default geometry (TODO)
auto vaoSphere = VertexArrayObjectCreator("uvsphere.obj").create();
auto texture = Texture2DFileManager::the()->get(Texture2DCreator("checkerboard.png"));
// Debug lines
auto vaoCircle = VertexArrayObjectCreator("circle.obj").create();
orbitTorus = { vaoCircle };
orbitTorus.vao->setMode(GL_LINES);
defaultGeom = { vaoSphere };
<<<<<<< HEAD
auto pbrShader = ShaderProgramFileManager::the()->get(ShaderProgramCreator("PBR").
attributeLocations(vaoSphere->getAttributeLocations()).
fragmentDataLocations(m_renderer->getGBufferLocations()));
=======
auto pbrShader = ShaderProgramFileManager::the()->get(ShaderProgramCreator("PBR")
.attributeLocations(vaoSphere->getAttributeLocations())
.fragmentDataLocations(m_renderer->getGBufferLocations()));
>>>>>>> master
auto testShader = ShaderProgramFileManager::the()->get(ShaderProgramCreator("lines")
.attributeLocations(vaoCircle->getAttributeLocations())
.fragmentDataLocations(m_renderer->getGBufferLocations()));
defaultMat = { glm::vec4(1, 1, 1, 1), glm::vec4(0.1, 0.1, 0.1, 1), texture, pbrShader };
defaultMat2 = { glm::vec4(1, 1, 1, 1), glm::vec4(1, 0, 0, 1), texture, testShader };
return true;
}
void OrbitalSimulationSystem::enableTrajectories() {
}
glm::vec3 OrbitalSimulationSystem::applyKepler(Planet::Handle planet, float dt) {
// compute the mean anomaly
double meanAnomaly = planet->M0 + planet->dailyMotion * (dt);
meanAnomaly = meanAnomaly - 2 * PI * floor(meanAnomaly / (2 * PI)); // Normalize angle
planet->M0 = meanAnomaly;
// Compute the eccentric anomaly
double eccentricAnomaly = meanAnomaly + planet->eccentricity * sin(meanAnomaly) * (1.0 + planet->eccentricity * cos(meanAnomaly));
if (planet->eccentricity > 0.06) {
int limit = 10;
double E_0 = eccentricAnomaly;
double E_1 = E_0;
do {
E_0 = E_1;
E_1 = E_0 - (E_0 - planet->eccentricity * sin(E_0) - meanAnomaly) / (1 - planet->eccentricity * cos(E_0));
limit--;
} while (fabs(E_1 - E_0) > 0.000000001 && limit > 0);
eccentricAnomaly = E_1;
}
double xv = planet->semimajor * (cos(eccentricAnomaly) - planet->eccentricity);
double yv = planet->semimajor * (sqrt(1.0 - planet->eccentricity * planet->eccentricity) * sin(eccentricAnomaly));
// Calculate the true anomaly
double trueAnomaly = atan2(yv, xv);
// Radial distance to sun
double r = sqrt(xv*xv + yv*yv);
glm::vec3 position;
position.x = r*(cos(planet->ascendingNode)*cos(planet->longitudePerihelion + trueAnomaly) -
sin(planet->ascendingNode)*sin(planet->longitudePerihelion + trueAnomaly)*cos(planet->inclination));
position.z = r*(sin(planet->ascendingNode)*cos(planet->longitudePerihelion + trueAnomaly) +
cos(planet->ascendingNode)*sin(planet->longitudePerihelion + trueAnomaly)*cos(planet->inclination));
position.y = r*(sin(planet->longitudePerihelion + trueAnomaly)*sin(planet->inclination));
return position;
}
void OrbitalSimulationSystem::simulateOrbitals(float dt, float totalTime) {
auto planets = m_scene->entities_with_components<Planet, Transform>();
Planet::Handle planet;
Transform::Handle transform;
glm::vec3 position;
for (auto p : planets) {
p.unpack<Planet, Transform>(planet, transform);
// dt here is interpreted as a DAY NUMBER. TODO: Conversion/scale
position = applyKepler(planet, dt*5 );
position = glm::vec3(AUToWorld(position.x), AUToWorld(position.y), AUToWorld(position.z));
// TODO: Natural conversion from au to world coords
transform->position = glm::vec3(position.x, position.y, position.z);
}
}
// Mass is in solar masses!
Entity OrbitalSimulationSystem::addPlanet(Transform::Handle sun, std::string n, double m, double r, double e, double a, double i, double N, double P, double T) {
// Mass, Radius, Eccentricity, Semimajor axis, Inclination, Ascending Node, Arg. of Periapsis, time at perihelion
auto planetEntity = m_scene->create();
auto planetTransform = planetEntity.assign<Transform>();
planetTransform->parent = sun;
planetEntity.assign<Drawable>(defaultGeom, defaultMat);
//planetEntity.assign<Light>(glm::vec4(1, 1, 1, 1), glm::vec3(1, 0, 0), false);
// Mass, Radius, Eccentricity, Semimajor axis, Inclination, Ascending Node, Arg. of Periapsis, time at perihelion
auto planetComponent = planetEntity.assign<Planet>(n, m, r, e, a, i, N, P, T);
// Move the planet to the right position:
glm::vec3 pos = applyKepler(planetComponent, 0);
pos = glm::vec3(AUToWorld(pos.x), AUToWorld(pos.y), AUToWorld(pos.z));
planetTransform->scale = glm::vec3(solarToWorld(r), solarToWorld(r), solarToWorld(r));
planetTransform->position = pos;
// Let's add a moon!
auto moon = m_scene->create();
auto moonTransform = moon.assign<Transform>();
moonTransform->parent = planetTransform;
moon.assign<Drawable>(defaultGeom, defaultMat);
auto moonComponent = moon.assign<Planet>("Moon", 0.000000036939686, 0.003505316091954, 0.205633, 0.08, 0.0898041713, 5.4583095414, 1.671072474, 0 );
// change starting point
//float t = static_cast <float> (rand()) / static_cast <float> (RAND_MAX / 10.0f);
pos = applyKepler(moonComponent, 0);
pos = glm::vec3(AUToWorld(pos.x), AUToWorld(pos.y), AUToWorld(pos.z));
moonTransform->position = pos;
moonTransform->scale = glm::vec3(1, 1, 1);
// Add the transformation matrixes to calculate the trajectory from a standard circle:
glm::vec3 tScale = glm::vec3(AUToWorld(a), 1, AUToWorld(a * 0.5));
auto traj = m_scene->create();
auto trajTransform = traj.assign<Transform>();
traj.assign<Drawable>(orbitTorus, defaultMat2);
trajTransform->scale = tScale;
return planetEntity;
}
// Right now planets are 10 times closer to each other than in reality and 10 times bigger
float OrbitalSimulationSystem::AUToWorld(double au) {
return distanceScale * solarToWorld(AUToSolar(au));
}
float OrbitalSimulationSystem::solarToWorld(double solar) {
return static_cast <float> (solar) * solarRadius * scaleFactor;
}
double OrbitalSimulationSystem::solarToAU(double s) {
return s * 0.004652472637379;
}
double OrbitalSimulationSystem::AUToSolar(double au) {
return au * 214.9394693836;
}
void OrbitalSimulationSystem::shutdown() {}
#include <engine/scene/PlayerSystem.hpp>
glm::vec3 rotate(glm::vec3 vec, glm::mat4 mat);
bool PlayerSystem::startup() {
RESOLVE_DEPENDENCY(m_events);
RESOLVE_DEPENDENCY(m_scene);
RESOLVE_DEPENDENCY(m_renderer);
RESOLVE_DEPENDENCY(m_audio);
RESOLVE_DEPENDENCY(m_ui);
// Create an entity that is used to position the camera in the scene
player = m_scene->create();
cameraTransform = player.assign<Transform>();
player.assign<Camera>(75, 0.1f, 100000);
cameraTransform->position = glm::vec3(0, 0, 1000);
m_renderer->setMainCamera(player);
m_audio->setListener(player);
m_events->subscribe<KeyboardEvent>([this](const KeyboardEvent& e) { handleKeyboard(e); });
m_events->subscribe<MouseEvent>([this](const MouseEvent& e) { handleMouse(e); });
m_events->subscribe<SimulateEvent>([this](const SimulateEvent& e) { update(e.dt); });
for (int i = 0; i < SDL_NUM_SCANCODES; i++) {
m_keyState[i] = false;
}
return true;
}
void PlayerSystem::handleKeyboard(KeyboardEvent e) {
if (e.originalEvent.key.repeat != 0) {
return;
}
if (e.originalEvent.key.keysym.scancode < SDL_NUM_SCANCODES && e.originalEvent.key.keysym.scancode >= 0) {
m_keyState[e.originalEvent.key.keysym.scancode] = e.originalEvent.key.type == SDL_KEYDOWN;
}
switch (e.originalEvent.key.keysym.scancode) {
case SDL_SCANCODE_ESCAPE:
// Make the mouse freely movable on escape
if (e.originalEvent.key.type == SDL_KEYDOWN) {
SDL_SetRelativeMouseMode(SDL_FALSE);
}
break;
<<<<<<< HEAD
=======
case SDL_SCANCODE_W:
wDown = e.originalEvent.key.type == SDL_KEYDOWN;
break;
case SDL_SCANCODE_S:
sDown = e.originalEvent.key.type == SDL_KEYDOWN;
break;
case SDL_SCANCODE_D:
dDown = e.originalEvent.key.type == SDL_KEYDOWN;
break;
case SDL_SCANCODE_A:
aDown = e.originalEvent.key.type == SDL_KEYDOWN;
break;
case SDL_SCANCODE_SPACE:
spaceDown = e.originalEvent.key.type == SDL_KEYDOWN;
break;
case SDL_SCANCODE_LSHIFT:
shiftDown = e.originalEvent.key.type == SDL_KEYDOWN;;
>>>>>>> master
default:
break;
}
}
void PlayerSystem::handleMouse(MouseEvent e) {
switch (e.originalEvent.type) {
// Capture the mouse when we click on the window
case SDL_MOUSEBUTTONDOWN:
// As long as we are not over any UI (because we might want to click on that)
if (!ImGui::GetIO().WantCaptureMouse) {
SDL_SetRelativeMouseMode(SDL_TRUE);
}
break;
case SDL_MOUSEMOTION: {
// If the mouse is captured
if (SDL_GetRelativeMouseMode()) {
// Rotate the camera based on the mouse movement
auto mouseMove = glm::vec2(-(float)e.originalEvent.motion.xrel, -(float)e.originalEvent.motion.yrel);
auto up = rotate(glm::vec3(0, 1, 0), glm::inverse(cameraTransform->rotation));
cameraTransform->rotation = glm::rotate(cameraTransform->rotation, mouseMove.x * 0.001f, up);
cameraTransform->rotation = glm::rotate(cameraTransform->rotation, mouseMove.y * 0.001f, glm::vec3(1, 0, 0));
}
break;
}
default:
break;
}
}
void PlayerSystem::update(float dt) {
glm::vec3 moveDir(0);
<<<<<<< HEAD
glm::vec2 rotDir(0);
// Move the camera based on WASD keyboard input
if (!ImGui::GetIO().WantCaptureKeyboard) {
if (m_keyState[SDL_SCANCODE_W]) moveDir -= glm::vec3(0, 0, 1);
if (m_keyState[SDL_SCANCODE_S]) moveDir += glm::vec3(0, 0, 1);
if (m_keyState[SDL_SCANCODE_A]) moveDir -= glm::vec3(1, 0, 0);
if (m_keyState[SDL_SCANCODE_D]) moveDir += glm::vec3(1, 0, 0);
if (m_keyState[SDL_SCANCODE_LEFT]) rotDir += glm::vec2(1, 0);
if (m_keyState[SDL_SCANCODE_RIGHT]) rotDir -= glm::vec2(1, 0);
if (m_keyState[SDL_SCANCODE_UP]) rotDir += glm::vec2(0, 1);
if (m_keyState[SDL_SCANCODE_DOWN]) rotDir -= glm::vec2(0, 1);
// Rotate the camera based on the mouse movement
auto up = rotate(glm::vec3(0, 1, 0), glm::inverse(cameraTransform->rotation));
cameraTransform->rotation = glm::rotate(cameraTransform->rotation, rotDir.x * 0.05f, up);
cameraTransform->rotation = glm::rotate(cameraTransform->rotation, rotDir.y * 0.05f, glm::vec3(1, 0, 0));
=======
float speedMod = 1.0f;
// Move the camera based on WASD keyboard input
if (!ImGui::GetIO().WantCaptureKeyboard) {
if (wDown) moveDir -= glm::vec3(0, 0, 1);
if (sDown) moveDir += glm::vec3(0, 0, 1);
if (aDown) moveDir -= glm::vec3(1, 0, 0);
if (dDown) moveDir += glm::vec3(1, 0, 0);
if (spaceDown) moveDir += glm::vec3(0, 1, 0);
if (shiftDown) speedMod = 100;
glm::normalize(moveDir);
>>>>>>> master
if (moveDir != glm::vec3(0, 0, 0)) {
moveDir = rotate(glm::normalize(moveDir), cameraTransform->rotation);
cameraTransform->position += moveDir * dt * speed * speedMod;
}
}
// Check if we have to move the player to a different coordinate system.
// Hack to check if the parent is not sun or we don't have a parent (FIXME)
if (cameraTransform->parent.valid() && cameraTransform->parent->parent.valid()) {
if (glm::length(cameraTransform->position) > 200) {
cameraTransform->position += cameraTransform->parent->position;
cameraTransform->parent = cameraTransform->parent->parent;
parentName = "Sun";
}
}
// We're NOT following a planet
else {
auto planets = m_scene->entities_with_components<Planet, Transform>();
Planet::Handle planet;
Transform::Handle transform;
for (auto p : planets){
p.unpack<Planet, Transform>(planet, transform);
// Excluding moons FIXME
if (planet->mass > 0.000000100000) {
if (glm::length( cameraTransform->position - transform->position) < 150 ){
cameraTransform->position = cameraTransform->position - transform->position;
cameraTransform->parent = transform;
parentName = planet->name;
}
}
}
}
}
void PlayerSystem::shutdown() {}
glm::vec3 rotate(glm::vec3 vec, glm::mat4 mat) {
auto temp = mat * glm::vec4(vec.x, vec.y, vec.z, 0);
return glm::vec3(temp.x, temp.y, temp.z);
}
\ No newline at end of file
#include <engine/scene/scenes/OrbitsScene.hpp>
#include <engine/ui/UISystem.hpp>
#include <ACGL/ACGL.hh>
#include <ACGL/OpenGL/Objects.hh>
#include <ACGL/Base/Settings.hh>
#include <ACGL/Math/Math.hh>
#include <ACGL/OpenGL/Data/TextureLoadStore.hh>
#include <ACGL/OpenGL/Managers.hh>
#include <ACGL/OpenGL/Creator/ShaderProgramCreator.hh>
#include <ACGL/OpenGL/Creator/VertexArrayObjectCreator.hh>
#include <ACGL/OpenGL/Creator/Texture2DCreator.hh>
#include <engine/scene/Transform.hpp>
#include <engine/scene/Drawable.hpp>
#include <engine/scene/Planet.hpp>
#include <engine/events/MouseEvent.hpp>
#include <engine/events/KeyboardEvent.hpp>
#include <engine/graphics/BloomPostFX.hpp>
using namespace ACGL::OpenGL;
using namespace ACGL::Base;
using namespace ACGL::Utils;
bool OrbitsScene::startup() {
if (!Scene::startup()) {
return false;
}
RESOLVE_DEPENDENCY(m_orbitals);
RESOLVE_DEPENDENCY(m_player);
m_renderer->addEffect<BloomPostFX>();
// load the geometry of the stanford bunny and build a VAO:
auto vaoTeapot = VertexArrayObjectCreator("teapot.obj").create();
// load a test scene
auto vaoCube = VertexArrayObjectCreator("cube.obj").create();
auto vaoSun = VertexArrayObjectCreator("uvsphere.obj").create();
auto vaoTestScene = VertexArrayObjectCreator("test_scene.obj").create();
// load a texture:
auto checkboardTexture = Texture2DFileManager::the()->get(Texture2DCreator("checkerboard.png"));
auto testTransparencyTexture = Texture2DFileManager::the()->get(Texture2DCreator("transparency_test.png"));
// look up all shader files starting with 'PBR' and build a ShaderProgram from it:
auto pbrShader = ShaderProgramCreator("PBR")
.attributeLocations(vaoTeapot->getAttributeLocations())
.fragmentDataLocations(m_renderer->getGBufferLocations()).create();
// Create geometry objects that point to the previously initialized vaos
Geometry geom1 = { vaoSun };
Geometry geom2 = { vaoTeapot };
// Create a material that uses the loaded shader program
Material sunMaterial = { glm::vec4{ 1, 1, 1, 1 }, glm::vec4{ 1, 0, 0, 1 }, checkboardTexture, pbrShader };
Material transparentMat = { glm::vec4{ 1, 1, 1, 1 }, glm::vec4{ 0, 0, 0, 1 }, testTransparencyTexture, pbrShader };
// Let's create a placeholder sun
auto scene = m_sceneGraph->create();
// Add a transform component to it so we are able to position it in space
auto sceneTransform = scene.assign<Transform>();
// Add a Drawable component to it so the renderer has something to draw
auto sceneDrawable = scene.assign<Drawable>(Geometry{ vaoTestScene }, transparentMat);
float scale = m_orbitals->solarRadius * m_orbitals->scaleFactor * 0.1;
sceneTransform->scale = glm::vec3(scale);
sceneTransform->position = glm::vec3(0, -600, 0);
sceneDrawable->visible = false;
auto light = m_sceneGraph->create();
light.assign<Transform>()->position = glm::vec3(0, -200, 0);
auto lightComp = light.assign<Light>(glm::vec4(1, 1, 1, 2000), glm::vec3(0, -1, 0), true);
// Let's create a placeholder sun
sun = m_sceneGraph->create();
// Add a transform component to it so we are able to position it in space
auto sunTransform = sun.assign<Transform>();
// Add a Drawable component to it so the renderer has something to draw
sun.assign<Drawable>(geom1, sunMaterial);
sunTransform->scale = glm::vec3(scale);
sun.assign<Light>(glm::vec4(1, 1, 1, 12000), glm::vec3(1, 0, 0), false);
// create a planet!
// Mass in solar masses, Radius in solar radii, Eccentricity, Semimajor axis, Inclination, Ascending Node, Arg. of Periapsis, time at perihelion
// mass radius e a i N w
mercury = m_orbitals->addPlanet(sunTransform, "Mercury", 0.000000165956, 0.003505316091954, 0.205633, 0.387098, 0.1222500, 0.84153, 0.50768, 0);
venus = m_orbitals->addPlanet(sunTransform, "Venus", 0.00000243522, 0.008695402298851, 0.006778, 0.723330, 0.0592500, 1.33679, 0.95717, 0);
earth = m_orbitals->addPlanet(sunTransform, "Earth", 0.000002988, 0.009153735632184, 0.016713, 1.000000, 0.0000000, 0.00000, 4.93533, 0);
mars = m_orbitals->addPlanet(sunTransform, "Mars", 0.000000319716, 0.004870689655172, 0.093396, 1.523688, 0.0322851, 0.02333, 4.99858, 0);
jupiter = m_orbitals->addPlanet(sunTransform, "Jupiter", 0.000954265748, 0.1004468390805, 0.048482, 5.202560, 0.0227500, 1.75150, 4.77905, 0);
saturn = m_orbitals->addPlanet(sunTransform, "Saturn", 0.00028386, 0.08366666666667, 0.055580, 9.554750, 0.0434412, 1.98230, 5.92169, 0);
uranus = m_orbitals->addPlanet(sunTransform, "Uranus", 0.00004344552, 0.03643965517241, 0.047292, 19.18176, 0.0134948, 1.29060, 1.68516, 0);
neptune = m_orbitals->addPlanet(sunTransform, "Neptune", 0.0000512442, 0.03537643678161, 0.008598, 30.05814, 0.0002355, 2.29810, 4.76243, 0);
// Load a sound and enable 3D positioning for it
auto testSound = m_audio->createSound("test.wav", SoundMode::MODE_3D);