added audio stuff
This commit is contained in:
10
TSE_Core/src/BehaviourScripts/AudioListener.cpp
Normal file
10
TSE_Core/src/BehaviourScripts/AudioListener.cpp
Normal file
@@ -0,0 +1,10 @@
|
||||
#include "AudioListener.hpp"
|
||||
#include "Vector3.hpp"
|
||||
#include "elements/Transformable.hpp"
|
||||
#include "elements/AudioEngine.hpp"
|
||||
|
||||
void TSE::AudioListener::OnUpdate()
|
||||
{
|
||||
Vector3 pos = baseObject->GetGlobalPosition();
|
||||
ma_engine_listener_set_position(AudioEngine::engine, 0, pos.x, pos.y, -pos.z);
|
||||
}
|
||||
17
TSE_Core/src/BehaviourScripts/AudioListener.hpp
Normal file
17
TSE_Core/src/BehaviourScripts/AudioListener.hpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#define AUDIOLISTENER typeid(AudioListener).name()
|
||||
|
||||
#include "elements/BehaviourScript.hpp"
|
||||
|
||||
namespace TSE
|
||||
{
|
||||
class AudioListener : public BehaviourScript
|
||||
{
|
||||
void OnUpdate() override;
|
||||
inline const char* GetName() override
|
||||
{
|
||||
return "Audio Listener";
|
||||
}
|
||||
};
|
||||
} // namespace TSE
|
||||
135
TSE_Core/src/BehaviourScripts/AudioSource.cpp
Normal file
135
TSE_Core/src/BehaviourScripts/AudioSource.cpp
Normal file
@@ -0,0 +1,135 @@
|
||||
#include "AudioSource.hpp"
|
||||
#include "Vector3.hpp"
|
||||
#include "elements/Transformable.hpp"
|
||||
|
||||
float TSE::AudioSource::GetMinDistance()
|
||||
{
|
||||
return minDistance;
|
||||
}
|
||||
|
||||
float TSE::AudioSource::GetMaxDistance()
|
||||
{
|
||||
return maxDistance;
|
||||
}
|
||||
|
||||
bool TSE::AudioSource::GetGlobal()
|
||||
{
|
||||
return global;
|
||||
}
|
||||
|
||||
void TSE::AudioSource::SetGlobal(bool v)
|
||||
{
|
||||
if(global != v)
|
||||
{
|
||||
auto it = sounds.begin();
|
||||
for (int j = 0; j < sounds.size(); j++)
|
||||
{
|
||||
it->second;
|
||||
ma_sound_set_spatialization_enabled(it->second, !v);
|
||||
it++;
|
||||
}
|
||||
}
|
||||
global = v;
|
||||
}
|
||||
|
||||
void TSE::AudioSource::SetMinDistance(float v)
|
||||
{
|
||||
minDistance = v;
|
||||
auto it = sounds.begin();
|
||||
for (int j = 0; j < sounds.size(); j++)
|
||||
{
|
||||
it->second;
|
||||
ma_sound_set_min_distance(it->second, minDistance);
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
void TSE::AudioSource::SetMaxDistance(float v)
|
||||
{
|
||||
maxDistance = v;
|
||||
auto it = sounds.begin();
|
||||
for (int j = 0; j < sounds.size(); j++)
|
||||
{
|
||||
it->second;
|
||||
ma_sound_set_max_distance(it->second, maxDistance);
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
void TSE::AudioSource::AddClip(AudioClip *clip)
|
||||
{
|
||||
clips[clip->name] = clip;
|
||||
ma_sound* s = clip->GetAudioSound();
|
||||
ma_sound_set_spatialization_enabled(s, !global);
|
||||
ma_sound_set_attenuation_model(s, ma_attenuation_model_linear);
|
||||
ma_sound_set_rolloff(s, 1.0f);
|
||||
ma_sound_set_min_distance(s, minDistance);
|
||||
ma_sound_set_max_distance(s, maxDistance);
|
||||
ma_sound_set_min_gain(s, 0.0f);
|
||||
ma_sound_set_max_gain(s, 1.0f);
|
||||
sounds[clip->name] = s;
|
||||
}
|
||||
|
||||
void TSE::AudioSource::RemoveClip(std::string name)
|
||||
{
|
||||
if(currentlyPlaying == name) StopPlaying();
|
||||
clips[name]->DestroyAudioSound(sounds[name]);
|
||||
clips.erase(name);
|
||||
sounds.erase(name);
|
||||
}
|
||||
|
||||
void TSE::AudioSource::StartClip(std::string name, bool forceRestart)
|
||||
{
|
||||
if(currentlyPlaying != name){
|
||||
StopPlaying();
|
||||
}
|
||||
else if(forceRestart)
|
||||
{
|
||||
ma_sound_seek_to_pcm_frame(sounds[name], 0);
|
||||
}
|
||||
ma_sound_start(sounds[name]);
|
||||
currentlyPlaying = name;
|
||||
}
|
||||
|
||||
void TSE::AudioSource::StopPlaying()
|
||||
{
|
||||
if(currentlyPlaying == "") return;
|
||||
ma_sound_stop(sounds[currentlyPlaying]);
|
||||
ma_sound_seek_to_pcm_frame(sounds[currentlyPlaying], 0);
|
||||
currentlyPlaying = "";
|
||||
}
|
||||
|
||||
void TSE::AudioSource::PausePlaying()
|
||||
{
|
||||
if(currentlyPlaying == "") return;
|
||||
ma_sound_stop(sounds[currentlyPlaying]);
|
||||
}
|
||||
|
||||
TSE::AudioClip *TSE::AudioSource::GetClipAt(int i)
|
||||
{
|
||||
auto it = clips.begin();
|
||||
for (int j = 0; j < i; j++)
|
||||
{
|
||||
it++;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
TSE::AudioSource::~AudioSource()
|
||||
{
|
||||
int count = clips.size();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
std::string name = GetClipAt(0)->name;
|
||||
RemoveClip(name);
|
||||
}
|
||||
}
|
||||
|
||||
void TSE::AudioSource::OnUpdate()
|
||||
{
|
||||
if(!global)
|
||||
{
|
||||
Vector3 pos = baseObject->GetGlobalPosition();
|
||||
ma_sound_set_position(sounds[currentlyPlaying], pos.x, pos.y, -pos.z);
|
||||
}
|
||||
}
|
||||
50
TSE_Core/src/BehaviourScripts/AudioSource.hpp
Normal file
50
TSE_Core/src/BehaviourScripts/AudioSource.hpp
Normal file
@@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
|
||||
#define AUDIOSOURCE typeid(AudioSource).name()
|
||||
|
||||
#include "Types.hpp"
|
||||
#include "elements/AudioClip.hpp"
|
||||
#include "elements/BehaviourScript.hpp"
|
||||
#include "miniaudio.h"
|
||||
#include <unordered_map>
|
||||
|
||||
namespace TSE
|
||||
{
|
||||
class AudioSource : public BehaviourScript
|
||||
{
|
||||
public:
|
||||
std::unordered_map<string, AudioClip*> clips;
|
||||
string currentlyPlaying = "";
|
||||
|
||||
private:
|
||||
bool global = false;
|
||||
float minDistance = 5;
|
||||
float maxDistance = 8;
|
||||
std::unordered_map<std::string, ma_sound*> sounds;
|
||||
|
||||
public:
|
||||
float GetMinDistance();
|
||||
float GetMaxDistance();
|
||||
bool GetGlobal();
|
||||
void SetGlobal(bool v);
|
||||
void SetMinDistance(float v);
|
||||
void SetMaxDistance(float v);
|
||||
|
||||
void AddClip(AudioClip* clip);
|
||||
void RemoveClip(std::string name);
|
||||
|
||||
void StartClip(std::string name, bool forceRestart = true);
|
||||
void StopPlaying();
|
||||
void PausePlaying();
|
||||
|
||||
AudioClip* GetClipAt(int i);
|
||||
|
||||
~AudioSource();
|
||||
|
||||
void OnUpdate() override;
|
||||
inline const char* GetName() override
|
||||
{
|
||||
return "Audio Source";
|
||||
}
|
||||
};
|
||||
} // namespace TSE
|
||||
70
TSE_Core/src/elements/AudioClip.cpp
Normal file
70
TSE_Core/src/elements/AudioClip.cpp
Normal file
@@ -0,0 +1,70 @@
|
||||
#include "AudioClip.hpp"
|
||||
#include "Debug.hpp"
|
||||
#include <filesystem>
|
||||
#include "AudioEngine.hpp"
|
||||
|
||||
TSE::AudioClip::AudioClip(string path)
|
||||
{
|
||||
description.path = path;
|
||||
}
|
||||
|
||||
TSE::AudioClip::AudioClip(byte *stream, size_t size)
|
||||
{
|
||||
description.audiostream = stream;
|
||||
description.dataSize = size;
|
||||
}
|
||||
|
||||
ma_sound *TSE::AudioClip::GetAudioSound()
|
||||
{
|
||||
if(description.path != ""){
|
||||
if(std::filesystem::exists(description.path))
|
||||
{
|
||||
ma_result res;
|
||||
ma_sound* sound = (ma_sound*)malloc(sizeof(*sound));
|
||||
|
||||
res = ma_sound_init_from_file(AudioEngine::engine, description.path.c_str(), 0, nullptr, nullptr, sound);
|
||||
if (res != MA_SUCCESS) {
|
||||
TSE_WARNING("ma_sound_init_from_file failed: " + std::to_string(res));
|
||||
delete(sound);
|
||||
return nullptr;
|
||||
}
|
||||
return sound;
|
||||
}
|
||||
else
|
||||
{
|
||||
TSE_WARNING("Can't create ma_sound because the given path dose not exist: \n" + description.path);
|
||||
}
|
||||
}
|
||||
else if(description.audiostream != nullptr && description.dataSize > 0)
|
||||
{
|
||||
ma_result res;
|
||||
ma_decoder m_decoder;
|
||||
res = ma_decoder_init_memory(description.audiostream, description.dataSize, nullptr, &m_decoder);
|
||||
if (res != MA_SUCCESS) {
|
||||
TSE_WARNING("ma_decoder_init_memory failed: " + std::to_string(res));
|
||||
return nullptr;
|
||||
}
|
||||
ma_sound* sound = (ma_sound*)malloc(sizeof(*sound));
|
||||
res = ma_sound_init_from_data_source(AudioEngine::engine, &m_decoder, MA_SOUND_FLAG_STREAM, nullptr, sound);
|
||||
ma_decoder_uninit(&m_decoder);
|
||||
if (res != MA_SUCCESS) {
|
||||
TSE_WARNING("ma_sound_init_from_data_source failed: " + std::to_string(res));
|
||||
delete(sound);
|
||||
return nullptr;
|
||||
}
|
||||
return sound;
|
||||
}
|
||||
else
|
||||
{
|
||||
TSE_WARNING("Can't create ma_sound because description is not set, or unconfigured.");
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void TSE::AudioClip::DestroyAudioSound(ma_sound *sound)
|
||||
{
|
||||
if (!sound) return;
|
||||
|
||||
ma_sound_uninit(sound);
|
||||
delete sound;
|
||||
}
|
||||
28
TSE_Core/src/elements/AudioClip.hpp
Normal file
28
TSE_Core/src/elements/AudioClip.hpp
Normal file
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "Types.hpp"
|
||||
#include "miniaudio.h"
|
||||
|
||||
namespace TSE
|
||||
{
|
||||
struct AudioClipDescription
|
||||
{
|
||||
public:
|
||||
string path = "";
|
||||
byte* audiostream = nullptr;
|
||||
size_t dataSize = 0;
|
||||
};
|
||||
|
||||
class AudioClip
|
||||
{
|
||||
public:
|
||||
string name = "";
|
||||
AudioClipDescription description;
|
||||
|
||||
AudioClip(string path);
|
||||
AudioClip(byte* stream, size_t size);
|
||||
|
||||
ma_sound* GetAudioSound();
|
||||
void DestroyAudioSound(ma_sound* sound);
|
||||
};
|
||||
} // namespace TSE
|
||||
22
TSE_Core/src/elements/AudioEngine.cpp
Normal file
22
TSE_Core/src/elements/AudioEngine.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#include "AudioEngine.hpp"
|
||||
#include "Debug.hpp"
|
||||
|
||||
ma_engine* TSE::AudioEngine::engine = nullptr;
|
||||
|
||||
void TSE::AudioEngine::Init()
|
||||
{
|
||||
ma_result res;
|
||||
engine = (ma_engine*)malloc(sizeof(*engine));
|
||||
res = ma_engine_init(nullptr, engine);
|
||||
if(res != MA_SUCCESS)
|
||||
{
|
||||
TSE_WARNING("Couldn't init audio engine. error code: " + std::to_string(res));
|
||||
}
|
||||
}
|
||||
|
||||
void TSE::AudioEngine::Destroy()
|
||||
{
|
||||
ma_engine_uninit(engine);
|
||||
delete(engine);
|
||||
engine = nullptr;
|
||||
}
|
||||
15
TSE_Core/src/elements/AudioEngine.hpp
Normal file
15
TSE_Core/src/elements/AudioEngine.hpp
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "miniaudio.h"
|
||||
|
||||
namespace TSE
|
||||
{
|
||||
class AudioEngine
|
||||
{
|
||||
public:
|
||||
static ma_engine* engine;
|
||||
|
||||
static void Init();
|
||||
static void Destroy();
|
||||
};
|
||||
} // namespace TSE
|
||||
2
TSE_Core/src/extern/miniaudio.c
vendored
Normal file
2
TSE_Core/src/extern/miniaudio.c
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
#define MINIAUDIO_IMPLEMENTATION
|
||||
#include "miniaudio.h"
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "utils/Time.hpp"
|
||||
#include "version.h"
|
||||
#include "IInputManager.hpp"
|
||||
#include "elements/AudioEngine.hpp"
|
||||
|
||||
TSE::IWindow* TSE::IWindow::lastWindow = nullptr;
|
||||
|
||||
@@ -12,6 +13,7 @@ bool TSE::IWindow::BaseInit() const
|
||||
LuaStateHandler::InitLuaState();
|
||||
Debug::Init();
|
||||
Debug::Log("TSE:" + TSE_VERSION_STRING);
|
||||
AudioEngine::Init();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -22,6 +24,7 @@ void TSE::IWindow::BaseUpdate() const
|
||||
|
||||
TSE::IWindow::~IWindow()
|
||||
{
|
||||
AudioEngine::Destroy();
|
||||
IInputManager::instance()->Delete();
|
||||
Time::Destroy();
|
||||
Debug::Close();
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "EditorSubsystem.hpp"
|
||||
|
||||
#include "BehaviourScriptRegistry.hpp"
|
||||
#include "BehaviourScripts/AudioListener.hpp"
|
||||
#include "BehaviourScripts/AudioSource.hpp"
|
||||
|
||||
TSE::EDITOR::EditorSubsystem::EditorSubsystem() : sv(nullptr), editorLayer("")
|
||||
{
|
||||
@@ -21,6 +23,8 @@ TSE::EDITOR::EditorSubsystem::EditorSubsystem() : sv(nullptr), editorLayer("")
|
||||
BehaviourScriptRegistry::RegisterBehaviourScript("Renderable", []() -> BehaviourScript* {return new Renderable();});
|
||||
BehaviourScriptRegistry::RegisterBehaviourScript("Particle System", []() -> BehaviourScript* {return new ParticleSystem();});
|
||||
BehaviourScriptRegistry::RegisterBehaviourScript("Camera", []() -> BehaviourScript* {return new Camera();});
|
||||
BehaviourScriptRegistry::RegisterBehaviourScript("Audio Listener", []() -> BehaviourScript* {return new AudioListener();});
|
||||
BehaviourScriptRegistry::RegisterBehaviourScript("Audio Source", []() -> BehaviourScript* {return new AudioSource();});
|
||||
|
||||
#pragma region camerastuff
|
||||
|
||||
|
||||
@@ -191,6 +191,10 @@ namespace TSE::EDITOR
|
||||
{
|
||||
Draw((RectBase*)element, debug);
|
||||
}
|
||||
else if (name == "Audio Source")
|
||||
{
|
||||
Draw((AudioSource*)element, debug);
|
||||
}
|
||||
else if (name == "Camera")
|
||||
{
|
||||
Draw((Camera*)element, debug);
|
||||
@@ -478,6 +482,78 @@ namespace TSE::EDITOR
|
||||
if(small) DrawImageAnimationSetCompact(element, debug, label);
|
||||
else DrawImageAnimationSetNormal(element, debug, label);
|
||||
}
|
||||
void ElementDrawer::Draw(AudioSource *element, const bool &debug)
|
||||
{
|
||||
float availWidth = ImGui::GetContentRegionAvail().x;
|
||||
int buttonCount = 3;
|
||||
float spacing = ImGui::GetStyle().ItemSpacing.x;
|
||||
float buttonWidth = (availWidth - (buttonCount - 1) * spacing) / buttonCount;
|
||||
float buttonHeight = 0.0f; // 0.0 = default height
|
||||
|
||||
if (ImGui::Button("Play", ImVec2(buttonWidth, buttonHeight)))
|
||||
{
|
||||
element->StartClip(element->currentlyPlaying, false);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Pause", ImVec2(buttonWidth, buttonHeight)))
|
||||
{
|
||||
element->PausePlaying();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Stop", ImVec2(buttonWidth, buttonHeight)))
|
||||
{
|
||||
element->StopPlaying();
|
||||
}
|
||||
ImGui::Separator();
|
||||
bool global = element->GetGlobal();
|
||||
if(ImGui::Checkbox("Global", &global))
|
||||
{
|
||||
element->SetGlobal(global);
|
||||
}
|
||||
float minDistance = element->GetMinDistance();
|
||||
if(ImGui::DragFloat("Cutoff Distance", &minDistance))
|
||||
{
|
||||
element->SetMinDistance(minDistance);
|
||||
}
|
||||
float maxDistance = element->GetMaxDistance();
|
||||
if(ImGui::DragFloat("Falloff Distance", &maxDistance))
|
||||
{
|
||||
element->SetMaxDistance(maxDistance);
|
||||
}
|
||||
|
||||
BeginList("Audio Clips");
|
||||
//if(ListAddBtn()) { } // --> no add function for now maybe when asset manager is done
|
||||
for(int i = 0; i < element->clips.size(); i++)
|
||||
{
|
||||
BeginListItem("subcomponent##" + std::to_string(i));
|
||||
Draw(element->GetClipAt(i), debug, "", true);
|
||||
if (ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows))
|
||||
{
|
||||
// Check auf Doppelclick mit linker Maustaste
|
||||
if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left))
|
||||
{
|
||||
element->StopPlaying();
|
||||
element->currentlyPlaying = element->GetClipAt(i)->name;
|
||||
}
|
||||
}
|
||||
EndListItem();
|
||||
if(ListItemXBotton("x##" + std::to_string(i)))
|
||||
{
|
||||
element->RemoveClip(element->GetClipAt(i)->name);
|
||||
}
|
||||
}
|
||||
EndList();
|
||||
}
|
||||
void ElementDrawer::Draw(AudioClip *element, const bool &debug, const std::string &label, const bool small)
|
||||
{
|
||||
if(element == nullptr)
|
||||
{
|
||||
ImGui::Text("No Audio Clip Asigned");
|
||||
return;
|
||||
}
|
||||
if(small) DrawAudioClipCompact(element, debug, label);
|
||||
else DrawAudioClipNormal(element, debug, label);
|
||||
}
|
||||
void ElementDrawer::Draw(Camera *element, const bool &debug)
|
||||
{
|
||||
const bool isMain = (Camera::mainCamera == element);
|
||||
@@ -737,6 +813,39 @@ namespace TSE::EDITOR
|
||||
ImGui::Unindent(20.0f);
|
||||
}
|
||||
}
|
||||
void ElementDrawer::DrawAudioClipCompact(AudioClip *element, const bool &debug, const std::string &label)
|
||||
{
|
||||
float item_spacing = ImGui::GetStyle().ItemSpacing.x;
|
||||
ImVec2 label_size = ImGui::CalcTextSize(label.c_str());
|
||||
|
||||
float available_width = ImGui::GetContentRegionAvail().x;
|
||||
float field_width = available_width - label_size.x - item_spacing;
|
||||
|
||||
ImVec2 field_size = ImVec2(field_width, label_size.y + 4);
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetColorU32(ImGuiCol_FrameBg)); // gleiche Farbe wie InputText
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, ImGui::GetStyle().FrameRounding);
|
||||
|
||||
ImGui::BeginChild("##FakeInput", field_size, true, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);
|
||||
|
||||
ImGui::SetCursorPos(ImVec2(2, 2));
|
||||
ImGui::TextUnformatted(element->name.c_str());
|
||||
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::PopStyleVar();
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
ImGui::SameLine();
|
||||
ImVec2 cursorCurrent = ImGui::GetCursorPos();
|
||||
cursorCurrent.y += 2;
|
||||
ImGui::SetCursorPos(cursorCurrent);
|
||||
ImGui::TextUnformatted(label.c_str());
|
||||
}
|
||||
void ElementDrawer::DrawAudioClipNormal(AudioClip *element, const bool &debug, const std::string &label)
|
||||
{
|
||||
//TODO implement
|
||||
}
|
||||
void ElementDrawer::DrawImageAnimationSetCompact(ImageAnimationSet *element, const bool &debug, const std::string &label)
|
||||
{
|
||||
float item_spacing = ImGui::GetStyle().ItemSpacing.x;
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
#include "BehaviourScripts/ImageAnimation.hpp"
|
||||
#include "BehaviourScripts/RectBase.hpp"
|
||||
#include "BehaviourScripts/ParticleSystem.hpp"
|
||||
#include "BehaviourScripts/AudioListener.hpp"
|
||||
#include "BehaviourScripts/AudioSource.hpp"
|
||||
|
||||
namespace TSE::EDITOR
|
||||
{
|
||||
@@ -73,10 +75,13 @@ namespace TSE::EDITOR
|
||||
static void Draw(Sprite* element, const bool& debug, const std::string& label = "", const bool small = false);
|
||||
static void Draw(Mesh* element, const bool& debug, const std::string& label = "", const bool small = false);
|
||||
static void Draw(ImageAnimationSet* element, const bool& debug, const std::string& label = "", const bool small = false);
|
||||
static void Draw(AudioSource* element, const bool& debug);
|
||||
static void Draw(AudioClip* element, const bool& debug, const std::string& label = "", const bool small = false);
|
||||
static void Draw(Camera* element, const bool& debug);
|
||||
static void Draw(ParticleSystem* element, const bool& debug);
|
||||
|
||||
|
||||
static void DrawAudioClipCompact(AudioClip* element, const bool& debug, const std::string& label);
|
||||
static void DrawAudioClipNormal(AudioClip* element, const bool& debug, const std::string& label);
|
||||
static void DrawImageAnimationSetCompact(ImageAnimationSet* element, const bool& debug, const std::string& label);
|
||||
static void DrawImageAnimationSetNormal(ImageAnimationSet* element, const bool& debug, const std::string& label);
|
||||
static void DrawMeshCompact(Mesh* element, const bool& debug, const std::string& label);
|
||||
|
||||
Reference in New Issue
Block a user