Adds audio component with spatialization
Adds a new audio component with support for loading, playing, pausing, stopping, and controlling audio properties such as volume, pan, pitch, and looping. Implements spatialization using FMOD, enabling 3D audio effects based on object and camera positions. Includes file selection dialog and UI controls for audio properties.
This commit is contained in:
15
.idea/.idea.KhaoticEngineReborn/.idea/workspace.xml
generated
15
.idea/.idea.KhaoticEngineReborn/.idea/workspace.xml
generated
@@ -6,9 +6,13 @@
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="e81d6e08-efc7-40a0-909d-ec4943d948e9" name="Changes" comment="">
|
||||
<change beforePath="$PROJECT_DIR$/.idea/.idea.KhaoticEngineReborn/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/.idea.KhaoticEngineReborn/.idea/workspace.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/enginecustom/enginecustom.vcxproj" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/enginecustom.vcxproj" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/enginecustom/enginecustom.vcxproj.filters" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/enginecustom.vcxproj.filters" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/enginecustom/src/inc/system/camera_class.h" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/src/inc/system/camera_class.h" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/enginecustom/src/inc/system/ecs/component.h" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/src/inc/system/ecs/component.h" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/enginecustom/src/inc/system/ecs/components/audio_component.h" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/src/inc/system/ecs/components/audio_component.h" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/enginecustom/src/inc/system/ecs/components/transform_component.h" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/src/inc/system/ecs/components/transform_component.h" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/enginecustom/src/inc/system/ecs/entity.h" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/src/inc/system/ecs/entity.h" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/enginecustom/src/inc/system/ecs/entity_manager.h" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/src/inc/system/ecs/entity_manager.h" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/enginecustom/src/src/system/application_class.cpp" beforeDir="false" afterPath="$PROJECT_DIR$/enginecustom/src/src/system/application_class.cpp" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
@@ -38,6 +42,7 @@
|
||||
<setting file="file://$PROJECT_DIR$/enginecustom/src/inc/system/ecs/entity.h" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$PROJECT_DIR$/enginecustom/src/inc/system/ecs/entity_manager.h" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$PROJECT_DIR$/enginecustom/src/inc/system/ecs/systems/render_system.h" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$PROJECT_DIR$/enginecustom/src/inc/system/ecs/systems/types.h" root0="FORCE_HIGHLIGHTING" />
|
||||
<setting file="file://$PROJECT_DIR$/../../IDE_VS/VC/Tools/MSVC/14.38.33130/include/type_traits" root0="SKIP_HIGHLIGHTING" />
|
||||
</component>
|
||||
<component name="KubernetesApiPersistence">{}</component>
|
||||
@@ -250,7 +255,11 @@
|
||||
<workItem from="1757449929378" duration="1107000" />
|
||||
<workItem from="1757456559331" duration="2094000" />
|
||||
<workItem from="1757458683204" duration="3628000" />
|
||||
<workItem from="1757938327874" duration="1257000" />
|
||||
<workItem from="1757938327874" duration="2045000" />
|
||||
<workItem from="1757952605657" duration="117000" />
|
||||
<workItem from="1757952791669" duration="4499000" />
|
||||
<workItem from="1757959923169" duration="1930000" />
|
||||
<workItem from="1757961888820" duration="8937000" />
|
||||
</task>
|
||||
<task id="LOCAL-00001" summary="Minor update - viewport window tweak">
|
||||
<option name="closed" value="true" />
|
||||
|
||||
73
enginecustom/assets/sounds/imgui.ini
Normal file
73
enginecustom/assets/sounds/imgui.ini
Normal file
@@ -0,0 +1,73 @@
|
||||
[Window][DockSpace]
|
||||
Pos=0,0
|
||||
Size=1584,861
|
||||
Collapsed=0
|
||||
|
||||
[Window][Debug##Default]
|
||||
Pos=60,60
|
||||
Size=400,400
|
||||
Collapsed=0
|
||||
|
||||
[Window][Khaotic Engine]
|
||||
Pos=1267,19
|
||||
Size=317,842
|
||||
Collapsed=0
|
||||
DockId=0x00000005,0
|
||||
|
||||
[Window][render Stats]
|
||||
Pos=0,630
|
||||
Size=1584,231
|
||||
Collapsed=0
|
||||
DockId=0x00000009,0
|
||||
|
||||
[Window][Objects]
|
||||
Pos=0,19
|
||||
Size=234,842
|
||||
Collapsed=0
|
||||
DockId=0x0000000B,0
|
||||
|
||||
[Window][Terrain]
|
||||
Pos=0,19
|
||||
Size=266,842
|
||||
Collapsed=0
|
||||
DockId=0x00000007,0
|
||||
|
||||
[Window][Log Window]
|
||||
Pos=0,630
|
||||
Size=1584,231
|
||||
Collapsed=0
|
||||
DockId=0x0000000A,0
|
||||
|
||||
[Window][Light]
|
||||
Pos=0,19
|
||||
Size=234,609
|
||||
Collapsed=0
|
||||
DockId=0x0000000B,0
|
||||
|
||||
[Window][Engine Settings]
|
||||
Pos=1267,462
|
||||
Size=317,166
|
||||
Collapsed=0
|
||||
DockId=0x00000006,0
|
||||
|
||||
[Window][Inspector]
|
||||
Pos=1267,19
|
||||
Size=317,842
|
||||
Collapsed=0
|
||||
DockId=0x00000005,1
|
||||
|
||||
[Docking][Data]
|
||||
DockSpace ID=0xCCBD8CF7 Window=0x3DA2F1DE Pos=0,19 Size=1584,842 Split=Y
|
||||
DockNode ID=0x00000003 Parent=0xCCBD8CF7 SizeRef=1584,609 Split=X
|
||||
DockNode ID=0x0000000B Parent=0x00000003 SizeRef=234,842 Selected=0x031DC75C
|
||||
DockNode ID=0x0000000C Parent=0x00000003 SizeRef=1348,842 Split=X
|
||||
DockNode ID=0x00000007 Parent=0x0000000C SizeRef=266,842 Selected=0x393905AB
|
||||
DockNode ID=0x00000008 Parent=0x0000000C SizeRef=1316,842 Split=X
|
||||
DockNode ID=0x00000001 Parent=0x00000008 SizeRef=1265,842 CentralNode=1
|
||||
DockNode ID=0x00000002 Parent=0x00000008 SizeRef=317,842 Split=Y Selected=0x9F035453
|
||||
DockNode ID=0x00000005 Parent=0x00000002 SizeRef=317,441 Selected=0x36DC96AB
|
||||
DockNode ID=0x00000006 Parent=0x00000002 SizeRef=317,166 Selected=0x0B098C4B
|
||||
DockNode ID=0x00000004 Parent=0xCCBD8CF7 SizeRef=1584,231 Split=X Selected=0xF5D1BB37
|
||||
DockNode ID=0x00000009 Parent=0x00000004 SizeRef=792,231 Selected=0xF5D1BB37
|
||||
DockNode ID=0x0000000A Parent=0x00000004 SizeRef=790,231 Selected=0xAB74BEE9
|
||||
|
||||
@@ -82,6 +82,36 @@ public:
|
||||
*/
|
||||
void get_reflection_view_matrix(XMMATRIX&) const;
|
||||
|
||||
XMFLOAT3 get_forward() const {
|
||||
float pitch = XMConvertToRadians(rotation_x_);
|
||||
float yaw = XMConvertToRadians(rotation_y_);
|
||||
XMMATRIX rotMatrix = XMMatrixRotationRollPitchYaw(pitch, yaw, 0.0f);
|
||||
XMVECTOR forward = -rotMatrix.r[2];
|
||||
forward = XMVector3Normalize(forward);
|
||||
XMFLOAT3 forwardVec;
|
||||
XMStoreFloat3(&forwardVec, forward);
|
||||
return forwardVec;
|
||||
}
|
||||
|
||||
|
||||
XMFLOAT3 get_up() const {
|
||||
// Construire matrice rotation <20> partir des angles
|
||||
XMMATRIX rot = XMMatrixRotationRollPitchYaw(
|
||||
XMConvertToRadians(rotation_x_),
|
||||
XMConvertToRadians(rotation_y_),
|
||||
XMConvertToRadians(rotation_z_));
|
||||
|
||||
// Extraire le vecteur up, 2e colonne
|
||||
XMVECTOR up = rot.r[1]; // colonne up
|
||||
up = XMVector3Normalize(up);
|
||||
|
||||
XMFLOAT3 upF;
|
||||
XMStoreFloat3(&upF, up);
|
||||
return upF;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private:
|
||||
float position_x_, position_y_, position_z_;
|
||||
float rotation_x_, rotation_y_, rotation_z_;
|
||||
|
||||
@@ -3,11 +3,13 @@
|
||||
#include <typeindex>
|
||||
#include <typeinfo>
|
||||
#include <imgui.h>
|
||||
#include "entity.h"
|
||||
|
||||
/**
|
||||
* namespace for the Entity-Component-System (ECS)
|
||||
*/
|
||||
namespace ecs {
|
||||
class Entity;
|
||||
|
||||
// Classe de base pour tous les composants
|
||||
class Component {
|
||||
@@ -31,6 +33,7 @@ public:
|
||||
/**
|
||||
* Virtual function to update the component.
|
||||
* @param deltaTime Time since the last update.
|
||||
* @param entity The entity this component is attached to.
|
||||
*/
|
||||
virtual void Update(float deltaTime) {}
|
||||
|
||||
@@ -52,6 +55,21 @@ public:
|
||||
* This can be overridden by derived components to provide custom UI.
|
||||
*/
|
||||
virtual void OnImGuiRender() { /* Default implementation does nothing */ }
|
||||
|
||||
/**
|
||||
* Set the parent entity of this component.
|
||||
* @param parent A shared pointer to the parent entity.
|
||||
*/
|
||||
void SetParent(std::shared_ptr<Entity> parent) { m_parent = parent; }
|
||||
|
||||
/**
|
||||
* Get the parent entity of this component.
|
||||
* @return A shared pointer to the parent entity, or nullptr if it has been destroyed.
|
||||
*/
|
||||
std::shared_ptr<Entity> GetParent() const { return m_parent.lock(); }
|
||||
|
||||
private:
|
||||
std::weak_ptr<Entity> m_parent;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -4,6 +4,14 @@
|
||||
#include <Fmod/core/inc/fmod.hpp>
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#include <Shlwapi.h>
|
||||
#pragma comment(lib, "Shlwapi.lib")
|
||||
#include <commdlg.h> // Pour GetOpenFileName
|
||||
|
||||
#include "camera_class.h"
|
||||
#include "transform_component.h"
|
||||
|
||||
namespace ecs {
|
||||
class AudioComponent : public Component {
|
||||
@@ -25,38 +33,51 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
result = m_system->init(512, FMOD_INIT_NORMAL, nullptr);
|
||||
result = m_system->init(512, FMOD_INIT_NORMAL | FMOD_INIT_3D_RIGHTHANDED, nullptr);
|
||||
if (result != FMOD_OK) {
|
||||
m_lastError = "<EFBFBD>chec de l'initialisation du syst<73>me FMOD: " + std::to_string(result);
|
||||
m_system->release();
|
||||
m_system = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
auto parent = GetParent();
|
||||
if (parent && parent->GetCamera())
|
||||
{
|
||||
SetCamera(parent->GetCamera());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool Load(const std::string& path) {
|
||||
if (!m_system) {
|
||||
Initialize();
|
||||
if (!m_system) return false; // L'erreur est d<>j<EFBFBD> d<>finie dans Initialize()
|
||||
if (!m_system) return false;
|
||||
}
|
||||
|
||||
m_soundPath = path;
|
||||
|
||||
// V<>rifier si le fichier existe
|
||||
if (!std::filesystem::exists(path)) {
|
||||
m_lastError = "Fichier non trouv<75>: " + path;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Lib<69>rer le son pr<70>c<EFBFBD>dent s'il existe
|
||||
if (m_sound) {
|
||||
m_sound->release();
|
||||
m_sound = nullptr;
|
||||
}
|
||||
|
||||
// Essayer de charger avec le chemin absolu
|
||||
FMOD_MODE mode = FMOD_DEFAULT;
|
||||
if (m_spatialized)
|
||||
mode |= FMOD_3D;
|
||||
if (m_looping)
|
||||
mode |= FMOD_LOOP_NORMAL;
|
||||
else
|
||||
mode |= FMOD_LOOP_OFF;
|
||||
|
||||
std::filesystem::path absolutePath = std::filesystem::absolute(path);
|
||||
FMOD_RESULT result = m_system->createSound(absolutePath.string().c_str(), FMOD_DEFAULT, nullptr, &m_sound);
|
||||
|
||||
FMOD_RESULT result = m_system->createSound(absolutePath.string().c_str(), mode, nullptr, &m_sound);
|
||||
if (result != FMOD_OK) {
|
||||
m_lastError = "<EFBFBD>chec du chargement du son: " + std::to_string(result) +
|
||||
" (chemin: " + absolutePath.string() + ")";
|
||||
@@ -67,8 +88,41 @@ public:
|
||||
}
|
||||
|
||||
void Play() {
|
||||
if (m_system && m_sound)
|
||||
if (m_system && m_sound) {
|
||||
bool isPlaying = false;
|
||||
if (m_channel) {
|
||||
m_channel->isPlaying(&isPlaying);
|
||||
}
|
||||
|
||||
if (isPlaying) {
|
||||
m_channel->stop();
|
||||
}
|
||||
|
||||
m_system->playSound(m_sound, nullptr, false, &m_channel);
|
||||
|
||||
if (m_channel) {
|
||||
m_channel->setVolume(m_volume);
|
||||
m_channel->setPan(m_pan);
|
||||
m_channel->setPitch(m_pitch);
|
||||
m_channel->setMute(m_muted);
|
||||
m_channel->setPriority(m_priority);
|
||||
m_channel->setPaused(m_paused);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Pause() {
|
||||
if (m_channel) {
|
||||
m_paused = true;
|
||||
m_channel->setPaused(true);
|
||||
}
|
||||
}
|
||||
|
||||
void Resume() {
|
||||
if (m_channel) {
|
||||
m_paused = false;
|
||||
m_channel->setPaused(false);
|
||||
}
|
||||
}
|
||||
|
||||
void Stop() {
|
||||
@@ -76,49 +130,288 @@ public:
|
||||
m_channel->stop();
|
||||
}
|
||||
|
||||
void OnImGuiRender() override {
|
||||
// Afficher le r<>pertoire de travail actuel
|
||||
std::string currentDir = std::filesystem::current_path().string();
|
||||
ImGui::Text("R<EFBFBD>pertoire actuel: %s", currentDir.c_str());
|
||||
void SetCamera(camera_class* camera) {m_camera = camera; }
|
||||
|
||||
if (m_sound) {
|
||||
ImGui::Text("Son charg<72>: %s", m_soundPath.c_str());
|
||||
if (ImGui::Button("Jouer")) {
|
||||
void Update(float deltaTime) override {
|
||||
if (!m_spatialized) return;
|
||||
|
||||
if (!m_system || !m_camera) return;
|
||||
|
||||
auto parent = GetParent();
|
||||
if (!parent) return;
|
||||
|
||||
auto transform = parent->GetComponent<TransformComponent>();
|
||||
if (!transform) return;
|
||||
|
||||
XMVECTOR pos = transform->GetPosition();
|
||||
|
||||
m_position.x = XMVectorGetX(pos);
|
||||
m_position.y = XMVectorGetY(pos);
|
||||
m_position.z = XMVectorGetZ(pos);
|
||||
|
||||
if (m_channel) {
|
||||
FMOD_VECTOR velocity = { 0.f, 0.f, 0.f }; // <20> am<61>liorer si possible - calculer depuis d<>placement temps+position ?
|
||||
m_channel->set3DAttributes(&m_position, &velocity);
|
||||
}
|
||||
|
||||
// Mise <20> jour du listener FMOD
|
||||
XMFLOAT3 camPos = m_camera->get_position();
|
||||
XMFLOAT3 camForward = m_camera->get_forward();
|
||||
XMFLOAT3 camUp = m_camera->get_up();
|
||||
|
||||
FMOD_VECTOR listenerPos = { camPos.x, camPos.y, camPos.z };
|
||||
FMOD_VECTOR forward = { camForward.x, camForward.y, camForward.z };
|
||||
FMOD_VECTOR up = { camUp.x, camUp.y, camUp.z };
|
||||
|
||||
FMOD_VECTOR listenerVel = { 0.f, 0.f, 0.f };
|
||||
|
||||
if (m_use_velocity)
|
||||
{
|
||||
static XMFLOAT3 lastCamPos = camPos;
|
||||
XMFLOAT3 currentCamPos = camPos;
|
||||
|
||||
float deltaTimeSec = deltaTime > 0.0001f ? deltaTime : 0.016f; // <20>viter division par z<>ro
|
||||
|
||||
XMFLOAT3 listenerVelocity = {
|
||||
(currentCamPos.x - lastCamPos.x) / deltaTimeSec,
|
||||
(currentCamPos.y - lastCamPos.y) / deltaTimeSec,
|
||||
(currentCamPos.z - lastCamPos.z) / deltaTimeSec
|
||||
};
|
||||
lastCamPos = currentCamPos;
|
||||
|
||||
listenerVel = { listenerVelocity.x, listenerVelocity.y, listenerVelocity.z };
|
||||
}
|
||||
|
||||
m_system->set3DListenerAttributes(0, &listenerPos, &listenerVel, &forward, &up);
|
||||
m_system->update();
|
||||
}
|
||||
|
||||
|
||||
void OnImGuiRender() override {
|
||||
if (!m_sound) {
|
||||
ImGui::Text("No audio file loaded");
|
||||
|
||||
if (ImGui::Button("Load audio file")) {
|
||||
OPENFILENAME ofn;
|
||||
wchar_t szFile[MAX_PATH] = L"";
|
||||
ZeroMemory(&ofn, sizeof(ofn));
|
||||
ofn.lStructSize = sizeof(ofn);
|
||||
ofn.hwndOwner = NULL; // Renseigner si possible avec handle de la fen<65>tre
|
||||
ofn.lpstrFile = szFile;
|
||||
ofn.nMaxFile = MAX_PATH;
|
||||
ofn.lpstrFilter = L"Audio Files\0*.mp3;*.wav;*.ogg;*.flac\0All Files\0*.*\0";
|
||||
ofn.nFilterIndex = 1;
|
||||
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
|
||||
|
||||
if (GetOpenFileName(&ofn)) {
|
||||
wchar_t exePath[MAX_PATH];
|
||||
GetModuleFileName(NULL, exePath, MAX_PATH);
|
||||
PathRemoveFileSpec(exePath);
|
||||
|
||||
std::wstring targetDir = std::wstring(exePath) + L"\\assets\\sounds";
|
||||
|
||||
DWORD ftyp = GetFileAttributes(targetDir.c_str());
|
||||
if (ftyp == INVALID_FILE_ATTRIBUTES) {
|
||||
CreateDirectory((std::wstring(exePath) + L"\\assets").c_str(), NULL);
|
||||
CreateDirectory(targetDir.c_str(), NULL);
|
||||
}
|
||||
|
||||
const wchar_t* filename = wcsrchr(szFile, L'\\');
|
||||
std::wstring fileNameStr = filename ? (filename + 1) : szFile;
|
||||
|
||||
std::wstring targetPath = targetDir + L"\\" + fileNameStr;
|
||||
|
||||
if (!CopyFile(szFile, targetPath.c_str(), FALSE)) {
|
||||
MessageBox(NULL, L"Erreur lors de la copie du fichier audio.", L"Erreur", MB_OK | MB_ICONERROR);
|
||||
} else {
|
||||
int utf8size = WideCharToMultiByte(CP_UTF8, 0, targetPath.c_str(), -1, NULL, 0, NULL, NULL);
|
||||
std::string pathStr(utf8size, 0);
|
||||
WideCharToMultiByte(CP_UTF8, 0, targetPath.c_str(), -1, &pathStr[0], utf8size, NULL, NULL);
|
||||
pathStr.resize(utf8size - 1);
|
||||
|
||||
if (!Load(pathStr)) {
|
||||
// erreur dans m_lastError
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_lastError.empty()) {
|
||||
ImGui::TextColored(ImVec4(1, 0, 0, 1), "Error: %s", m_lastError.c_str());
|
||||
}
|
||||
} else {
|
||||
ImGui::Text("Loaded: %s", m_soundPath.c_str());
|
||||
|
||||
if (ImGui::Button("Change audio")) {
|
||||
OPENFILENAME ofn;
|
||||
wchar_t szFile[MAX_PATH] = L"";
|
||||
ZeroMemory(&ofn, sizeof(ofn));
|
||||
ofn.lStructSize = sizeof(ofn);
|
||||
ofn.hwndOwner = NULL;
|
||||
ofn.lpstrFile = szFile;
|
||||
ofn.nMaxFile = MAX_PATH;
|
||||
ofn.lpstrFilter = L"Audio Files\0*.mp3;*.wav;*.ogg;*.flac\0All Files\0*.*\0";
|
||||
ofn.nFilterIndex = 1;
|
||||
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
|
||||
|
||||
if (GetOpenFileName(&ofn)) {
|
||||
wchar_t exePath[MAX_PATH];
|
||||
GetModuleFileName(NULL, exePath, MAX_PATH);
|
||||
PathRemoveFileSpec(exePath);
|
||||
|
||||
std::wstring targetDir = std::wstring(exePath) + L"\\assets\\sounds";
|
||||
|
||||
DWORD ftyp = GetFileAttributes(targetDir.c_str());
|
||||
if (ftyp == INVALID_FILE_ATTRIBUTES) {
|
||||
CreateDirectory((std::wstring(exePath) + L"\\assets").c_str(), NULL);
|
||||
CreateDirectory(targetDir.c_str(), NULL);
|
||||
}
|
||||
|
||||
const wchar_t* filename = wcsrchr(szFile, L'\\');
|
||||
std::wstring fileNameStr = filename ? (filename + 1) : szFile;
|
||||
|
||||
std::wstring targetPath = targetDir + L"\\" + fileNameStr;
|
||||
|
||||
if (!CopyFile(szFile, targetPath.c_str(), FALSE)) {
|
||||
MessageBox(NULL, L"Erreur lors de la copie du fichier audio.", L"Erreur", MB_OK | MB_ICONERROR);
|
||||
} else {
|
||||
int utf8size = WideCharToMultiByte(CP_UTF8, 0, targetPath.c_str(), -1, NULL, 0, NULL, NULL);
|
||||
std::string pathStr(utf8size, 0);
|
||||
WideCharToMultiByte(CP_UTF8, 0, targetPath.c_str(), -1, &pathStr[0], utf8size, NULL, NULL);
|
||||
pathStr.resize(utf8size - 1);
|
||||
|
||||
if (!Load(pathStr)) {
|
||||
// erreur dans m_lastError
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Remove audio")) {
|
||||
Stop();
|
||||
if (m_sound) m_sound->release();
|
||||
m_sound = nullptr;
|
||||
m_soundPath.clear();
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::Button("Play")) {
|
||||
Play();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Arr<EFBFBD>ter")) {
|
||||
if (ImGui::Button(m_paused ? "Resume" : "Pause")) {
|
||||
if (m_paused) Resume();
|
||||
else Pause();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Stop")) {
|
||||
Stop();
|
||||
}
|
||||
} else {
|
||||
ImGui::Text("Aucun son charg<72>");
|
||||
|
||||
// Montrer l'erreur s'il y en a une
|
||||
if (!m_lastError.empty()) {
|
||||
ImGui::TextColored(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), "Erreur: %s", m_lastError.c_str());
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::SliderFloat("Volume", &m_volume, 0.0f, 1.0f)) {
|
||||
if (m_channel) m_channel->setVolume(m_volume);
|
||||
}
|
||||
|
||||
// exe path + assets/sounds/default.mp3
|
||||
std::filesystem::path defaultSoundPath = std::filesystem::current_path() / "assets" / "sounds" / "default.mp3";
|
||||
std::string defaultSoundPathStr = defaultSoundPath.string();// Input text with default path
|
||||
char path[260];
|
||||
strncpy_s(path, m_soundPath.empty() ? defaultSoundPathStr.c_str() : m_soundPath.c_str(), sizeof(path));
|
||||
path[sizeof(path) - 1] = '\0'; // Assurer la termination nulle
|
||||
ImGui::InputText("Chemin du fichier", path, sizeof(path));
|
||||
|
||||
if (ImGui::Button("Charger le son")) {
|
||||
if (!Load(path)) {
|
||||
// L'erreur est d<>j<EFBFBD> d<>finie dans Load()
|
||||
if (ImGui::SliderFloat("Pan", &m_pan, -1.0f, 1.0f)) {
|
||||
if (m_channel) m_channel->setPan(m_pan);
|
||||
}
|
||||
|
||||
if (ImGui::SliderFloat("Pitch", &m_pitch, 0.5f, 2.0f)) {
|
||||
if (m_channel) m_channel->setPitch(m_pitch);
|
||||
}
|
||||
|
||||
if (ImGui::Checkbox("Looping", &m_looping)) {
|
||||
// Recharger le son pour appliquer le mode loop
|
||||
Load(m_soundPath);
|
||||
}
|
||||
|
||||
if (ImGui::Checkbox("Spatialization 3D", &m_spatialized)) {
|
||||
if (!m_soundPath.empty()) {
|
||||
Load(m_soundPath); // Recharger le son avec ou sans 3D selon le choix
|
||||
}
|
||||
}
|
||||
|
||||
// check box to use velocity for doppler effect (only if spatialized)
|
||||
if (m_spatialized) {
|
||||
ImGui::SameLine();
|
||||
ImGui::Checkbox("Use Velocity for Doppler", &m_use_velocity);
|
||||
}
|
||||
|
||||
if (ImGui::Checkbox("Mute", &m_muted)) {
|
||||
if (m_channel) m_channel->setMute(m_muted);
|
||||
}
|
||||
|
||||
if (ImGui::SliderInt("Priority", &m_priority, 0, 256)) {
|
||||
if (m_channel) m_channel->setPriority(m_priority);
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (m_channel && m_sound) {
|
||||
unsigned int pos = 0, len = 0;
|
||||
m_channel->getPosition(&pos, FMOD_TIMEUNIT_MS);
|
||||
m_sound->getLength(&len, FMOD_TIMEUNIT_MS);
|
||||
|
||||
float progress = (len > 0) ? (float)pos / len : 0.0f;
|
||||
ImGui::ProgressBar(progress, ImVec2(300, 0), nullptr);
|
||||
|
||||
auto to_minsec = [](unsigned int ms) {
|
||||
unsigned int totalSec = ms / 1000;
|
||||
return std::make_pair(totalSec / 60, totalSec % 60);
|
||||
};
|
||||
auto [curMin, curSec] = to_minsec(pos);
|
||||
auto [lenMin, lenSec] = to_minsec(len);
|
||||
|
||||
ImGui::Text("%02u:%02u / %02u:%02u", curMin, curSec, lenMin, lenSec);
|
||||
}
|
||||
|
||||
// afficher la position de l'objet et de la camera ainsi que la rotaion de la camera si spatialis<69>
|
||||
if (m_spatialized) {
|
||||
auto parent = GetParent();
|
||||
if (parent) {
|
||||
auto transform = parent->GetComponent<TransformComponent>();
|
||||
if (transform) {
|
||||
XMVECTOR pos = transform->GetPosition();
|
||||
ImGui::Text("Object Position: (%.2f, %.2f, %.2f)", XMVectorGetX(pos), XMVectorGetY(pos), XMVectorGetZ(pos));
|
||||
}
|
||||
}
|
||||
if (m_camera) {
|
||||
XMFLOAT3 camPos = m_camera->get_position();
|
||||
XMFLOAT3 camRot = m_camera->get_rotation();
|
||||
ImGui::Text("Camera Position: (%.2f, %.2f, %.2f)", camPos.x, camPos.y, camPos.z);
|
||||
ImGui::Text("Camera Rotation: (%.2f, %.2f, %.2f)", camRot.x, camRot.y, camRot.z);
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_lastError.empty()) {
|
||||
ImGui::TextColored(ImVec4(1,0,0,1), "Error: %s", m_lastError.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private:
|
||||
FMOD::System* m_system;
|
||||
FMOD::Sound* m_sound;
|
||||
FMOD::Channel* m_channel;
|
||||
std::string m_soundPath;
|
||||
std::string m_lastError;
|
||||
|
||||
float m_volume = 1.0f;
|
||||
float m_pan = 0.0f;
|
||||
float m_pitch = 1.0f;
|
||||
bool m_looping = false;
|
||||
bool m_muted = false;
|
||||
bool m_paused = false;
|
||||
int m_priority = 128;
|
||||
bool m_spatialized = false;
|
||||
bool m_use_velocity = false;
|
||||
|
||||
FMOD_VECTOR m_position = {0.0f, 0.0f, 0.0f};
|
||||
camera_class* m_camera = nullptr;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include "../component.h"
|
||||
#include <DirectXMath.h>
|
||||
#include <sstream>
|
||||
|
||||
using namespace DirectX;
|
||||
|
||||
|
||||
@@ -6,13 +6,15 @@
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
||||
#include "camera_class.h"
|
||||
|
||||
namespace ecs {
|
||||
/**
|
||||
* Type alias for a unique identifier for an entity.
|
||||
*/
|
||||
using EntityID = uint32_t;
|
||||
|
||||
class Entity {
|
||||
class Entity : public std::enable_shared_from_this<Entity> {
|
||||
public:
|
||||
/**
|
||||
* Builder for an Entity with a unique ID.
|
||||
@@ -59,6 +61,9 @@ public:
|
||||
// Cr<43>er et ajouter le composant
|
||||
auto component = std::make_shared<T>(std::forward<Args>(args)...);
|
||||
m_Components[typeID] = component;
|
||||
|
||||
component->SetParent(shared_from_this());
|
||||
|
||||
|
||||
// Initialiser le composant
|
||||
component->Initialize();
|
||||
@@ -132,6 +137,9 @@ public:
|
||||
return m_Components;
|
||||
}
|
||||
|
||||
void SetCamera(camera_class* camera) {m_camera = camera; }
|
||||
camera_class* GetCamera() const { return m_camera; }
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
@@ -143,6 +151,9 @@ private:
|
||||
* The key is the type ID of the component, and the value is a shared pointer to the component.
|
||||
*/
|
||||
std::unordered_map<ComponentTypeID, ComponentPtr> m_Components;
|
||||
|
||||
// camera
|
||||
camera_class* m_camera = nullptr;
|
||||
};
|
||||
|
||||
} // namespace ecs
|
||||
|
||||
@@ -31,6 +31,7 @@ public:
|
||||
}
|
||||
|
||||
auto entity = std::make_shared<Entity>(id);
|
||||
entity->SetCamera(camera_);
|
||||
m_Entities[id] = entity;
|
||||
|
||||
return entity;
|
||||
@@ -144,10 +145,14 @@ public:
|
||||
|
||||
}
|
||||
|
||||
void SetCamera(camera_class* camera) { camera_ = camera; }
|
||||
camera_class* GetCamera() const { return camera_; }
|
||||
|
||||
private:
|
||||
EntityID m_NextEntityID;
|
||||
std::unordered_map<EntityID, std::shared_ptr<Entity>> m_Entities;
|
||||
std::queue<EntityID> m_FreeIDs; // IDs <20> r<>utiliser
|
||||
camera_class* camera_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace ecs
|
||||
|
||||
@@ -504,6 +504,9 @@ bool application_class::initialize(int screenWidth, int screenHeight, HWND hwnd,
|
||||
culling_active_ = true;
|
||||
culling_thread_ = std::thread(&application_class::culling_thread_function, this);
|
||||
|
||||
entity_manager_->SetCamera(camera_);
|
||||
|
||||
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
@@ -858,6 +861,7 @@ bool application_class::frame(input_class* Input)
|
||||
}
|
||||
|
||||
active_camera_->render();
|
||||
entity_manager_->UpdateEntities(frameTime);
|
||||
|
||||
// render the static graphics scene.
|
||||
result = render(rotation, x, y, z, textureTranslation);
|
||||
|
||||
Reference in New Issue
Block a user