part 2 since i forgot to stage changes lol.
This commit is contained in:
@@ -80,6 +80,7 @@ bool AudioSystem::ensureSoundFor(const SceneObject& obj) {
|
||||
|
||||
snd.clipPath = obj.audioSource.clipPath;
|
||||
snd.spatial = obj.audioSource.spatial;
|
||||
snd.started = false;
|
||||
refreshSoundParams(obj, snd);
|
||||
activeSounds[obj.id] = std::move(snd);
|
||||
return true;
|
||||
@@ -93,8 +94,9 @@ void AudioSystem::refreshSoundParams(const SceneObject& obj, ActiveSound& snd) {
|
||||
ma_sound_set_max_distance(&snd.sound, obj.audioSource.maxDistance);
|
||||
ma_sound_set_position(&snd.sound, obj.position.x, obj.position.y, obj.position.z);
|
||||
|
||||
if (!ma_sound_is_playing(&snd.sound) && obj.audioSource.playOnStart && obj.audioSource.enabled) {
|
||||
if (!ma_sound_is_playing(&snd.sound) && !snd.started && obj.audioSource.playOnStart && obj.audioSource.enabled) {
|
||||
ma_sound_start(&snd.sound);
|
||||
snd.started = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,6 +199,34 @@ bool AudioSystem::seekPreview(const std::string& path, double seconds) {
|
||||
return res == MA_SUCCESS;
|
||||
}
|
||||
|
||||
bool AudioSystem::playObjectSound(const SceneObject& obj) {
|
||||
if (!obj.hasAudioSource || obj.audioSource.clipPath.empty() || !obj.audioSource.enabled) return false;
|
||||
if (!ensureSoundFor(obj)) return false;
|
||||
ActiveSound& snd = activeSounds[obj.id];
|
||||
snd.started = true;
|
||||
return ma_sound_start(&snd.sound) == MA_SUCCESS;
|
||||
}
|
||||
|
||||
bool AudioSystem::stopObjectSound(int objectId) {
|
||||
auto it = activeSounds.find(objectId);
|
||||
if (it == activeSounds.end()) return false;
|
||||
return ma_sound_stop(&it->second.sound) == MA_SUCCESS;
|
||||
}
|
||||
|
||||
bool AudioSystem::setObjectLoop(const SceneObject& obj, bool loop) {
|
||||
if (!ensureSoundFor(obj)) return false;
|
||||
ActiveSound& snd = activeSounds[obj.id];
|
||||
ma_sound_set_looping(&snd.sound, loop ? MA_TRUE : MA_FALSE);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AudioSystem::setObjectVolume(const SceneObject& obj, float volume) {
|
||||
if (!ensureSoundFor(obj)) return false;
|
||||
ActiveSound& snd = activeSounds[obj.id];
|
||||
ma_sound_set_volume(&snd.sound, volume);
|
||||
return true;
|
||||
}
|
||||
|
||||
AudioClipPreview AudioSystem::loadPreview(const std::string& path) {
|
||||
AudioClipPreview preview;
|
||||
preview.path = path;
|
||||
|
||||
@@ -33,11 +33,18 @@ public:
|
||||
bool getPreviewTime(const std::string& path, double& cursorSeconds, double& durationSeconds) const;
|
||||
bool seekPreview(const std::string& path, double seconds);
|
||||
|
||||
// Scene audio control (runtime)
|
||||
bool playObjectSound(const SceneObject& obj);
|
||||
bool stopObjectSound(int objectId);
|
||||
bool setObjectLoop(const SceneObject& obj, bool loop);
|
||||
bool setObjectVolume(const SceneObject& obj, float volume);
|
||||
|
||||
private:
|
||||
struct ActiveSound {
|
||||
ma_sound sound;
|
||||
std::string clipPath;
|
||||
bool spatial = true;
|
||||
bool started = false; // prevents auto-restart after manual stop
|
||||
};
|
||||
|
||||
ma_engine engine{};
|
||||
|
||||
@@ -1266,6 +1266,42 @@ bool Engine::teleportPhysicsActorFromScript(int id, const glm::vec3& position, c
|
||||
return physics.setActorPose(id, position, rotationDeg);
|
||||
}
|
||||
|
||||
bool Engine::playAudioFromScript(int id) {
|
||||
SceneObject* obj = findObjectById(id);
|
||||
if (!obj || !obj->hasAudioSource) return false;
|
||||
return audio.playObjectSound(*obj);
|
||||
}
|
||||
|
||||
bool Engine::stopAudioFromScript(int id) {
|
||||
return audio.stopObjectSound(id);
|
||||
}
|
||||
|
||||
bool Engine::setAudioLoopFromScript(int id, bool loop) {
|
||||
SceneObject* obj = findObjectById(id);
|
||||
if (!obj || !obj->hasAudioSource) return false;
|
||||
obj->audioSource.loop = loop;
|
||||
markProjectDirty();
|
||||
return audio.setObjectLoop(*obj, loop);
|
||||
}
|
||||
|
||||
bool Engine::setAudioVolumeFromScript(int id, float volume) {
|
||||
SceneObject* obj = findObjectById(id);
|
||||
if (!obj || !obj->hasAudioSource) return false;
|
||||
obj->audioSource.volume = std::clamp(volume, 0.0f, 2.0f);
|
||||
markProjectDirty();
|
||||
return audio.setObjectVolume(*obj, obj->audioSource.volume);
|
||||
}
|
||||
|
||||
bool Engine::setAudioClipFromScript(int id, const std::string& path) {
|
||||
SceneObject* obj = findObjectById(id);
|
||||
if (!obj || !obj->hasAudioSource) return false;
|
||||
obj->audioSource.clipPath = path;
|
||||
markProjectDirty();
|
||||
// Ensure clip is loaded; do not auto-play unless PlayAudio is called.
|
||||
audio.setObjectLoop(*obj, obj->audioSource.loop);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Engine::compileScriptFile(const fs::path& scriptPath) {
|
||||
if (!projectManager.currentProject.isLoaded) {
|
||||
addConsoleMessage("No project is loaded", ConsoleMessageType::Warning);
|
||||
|
||||
@@ -92,6 +92,7 @@ private:
|
||||
bool isPlaying = false;
|
||||
bool isPaused = false;
|
||||
bool showViewOutput = true;
|
||||
bool showSceneGizmos = true;
|
||||
bool showGameViewport = true;
|
||||
int previewCameraId = -1;
|
||||
bool gameViewCursorLocked = false;
|
||||
@@ -221,4 +222,10 @@ public:
|
||||
bool setRigidbodyVelocityFromScript(int id, const glm::vec3& velocity);
|
||||
bool getRigidbodyVelocityFromScript(int id, glm::vec3& outVelocity);
|
||||
bool teleportPhysicsActorFromScript(int id, const glm::vec3& position, const glm::vec3& rotationDeg);
|
||||
// Audio control exposed to scripts
|
||||
bool playAudioFromScript(int id);
|
||||
bool stopAudioFromScript(int id);
|
||||
bool setAudioLoopFromScript(int id, bool loop);
|
||||
bool setAudioVolumeFromScript(int id, float volume);
|
||||
bool setAudioClipFromScript(int id, const std::string& path);
|
||||
};
|
||||
|
||||
@@ -3576,6 +3576,7 @@ void Engine::renderViewport() {
|
||||
}
|
||||
|
||||
bool mouseOverViewportImage = false;
|
||||
bool blockSelection = false;
|
||||
|
||||
if (rendererInitialized) {
|
||||
glm::mat4 proj = glm::perspective(
|
||||
@@ -3687,6 +3688,11 @@ void Engine::renderViewport() {
|
||||
if (clickedIdx >= 0) {
|
||||
setCameraFacing(arrows[clickedIdx].dir);
|
||||
}
|
||||
|
||||
// Prevent viewport picking when interacting with the axis widget.
|
||||
if (widgetHover) {
|
||||
blockSelection = true;
|
||||
}
|
||||
}
|
||||
|
||||
auto projectToScreen = [&](const glm::vec3& p) -> std::optional<ImVec2> {
|
||||
@@ -4170,9 +4176,11 @@ void Engine::renderViewport() {
|
||||
}
|
||||
};
|
||||
|
||||
for (const auto& obj : sceneObjects) {
|
||||
if (obj.type == ObjectType::Camera) {
|
||||
drawCameraDirection(obj);
|
||||
if (showSceneGizmos) {
|
||||
for (const auto& obj : sceneObjects) {
|
||||
if (obj.type == ObjectType::Camera) {
|
||||
drawCameraDirection(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4269,9 +4277,11 @@ void Engine::renderViewport() {
|
||||
}
|
||||
};
|
||||
|
||||
for (const auto& obj : sceneObjects) {
|
||||
if (obj.type == ObjectType::PointLight || obj.type == ObjectType::SpotLight || obj.type == ObjectType::AreaLight) {
|
||||
drawLightOverlays(obj);
|
||||
if (showSceneGizmos) {
|
||||
for (const auto& obj : sceneObjects) {
|
||||
if (obj.type == ObjectType::PointLight || obj.type == ObjectType::SpotLight || obj.type == ObjectType::AreaLight) {
|
||||
drawLightOverlays(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4406,6 +4416,14 @@ void Engine::renderViewport() {
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::SameLine(0.0f, toolbarSpacing * 1.25f);
|
||||
if (GizmoToolbar::ModeButton("Gizmos", showSceneGizmos, ImVec2(70, 24), baseCol, accentCol, textCol)) {
|
||||
showSceneGizmos = !showSceneGizmos;
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Toggle light/camera scene symbols");
|
||||
}
|
||||
|
||||
ImGui::EndGroup();
|
||||
ImGui::PopStyleVar();
|
||||
|
||||
@@ -4420,10 +4438,16 @@ void Engine::renderViewport() {
|
||||
|
||||
splitter.Merge(toolbarDrawList);
|
||||
|
||||
// Prevent viewport picking when clicking on the toolbar overlay.
|
||||
if (ImGui::IsMouseHoveringRect(bgMin, bgMax)) {
|
||||
blockSelection = true;
|
||||
}
|
||||
|
||||
// Left-click picking inside viewport
|
||||
if (mouseOverViewportImage &&
|
||||
ImGui::IsMouseClicked(ImGuiMouseButton_Left) &&
|
||||
!ImGuizmo::IsUsing() && !ImGuizmo::IsOver())
|
||||
!ImGuizmo::IsUsing() && !ImGuizmo::IsOver() &&
|
||||
!blockSelection)
|
||||
{
|
||||
glm::mat4 invViewProj = glm::inverse(proj * view);
|
||||
ImVec2 mousePos = ImGui::GetMousePos();
|
||||
|
||||
@@ -108,6 +108,42 @@ bool ScriptContext::TeleportRigidbody(const glm::vec3& pos, const glm::vec3& rot
|
||||
return engine->teleportPhysicsActorFromScript(object->id, pos, object->rotation);
|
||||
}
|
||||
|
||||
bool ScriptContext::HasAudioSource() const {
|
||||
return object && object->hasAudioSource && object->audioSource.enabled;
|
||||
}
|
||||
|
||||
bool ScriptContext::PlayAudio() {
|
||||
if (!engine || !object || !object->hasAudioSource) return false;
|
||||
return engine->playAudioFromScript(object->id);
|
||||
}
|
||||
|
||||
bool ScriptContext::StopAudio() {
|
||||
if (!engine || !object || !object->hasAudioSource) return false;
|
||||
return engine->stopAudioFromScript(object->id);
|
||||
}
|
||||
|
||||
bool ScriptContext::SetAudioLoop(bool loop) {
|
||||
if (!engine || !object || !object->hasAudioSource) return false;
|
||||
object->audioSource.loop = loop;
|
||||
engine->markProjectDirty();
|
||||
return engine->setAudioLoopFromScript(object->id, loop);
|
||||
}
|
||||
|
||||
bool ScriptContext::SetAudioVolume(float volume) {
|
||||
if (!engine || !object || !object->hasAudioSource) return false;
|
||||
float clamped = std::clamp(volume, 0.0f, 2.0f);
|
||||
object->audioSource.volume = clamped;
|
||||
engine->markProjectDirty();
|
||||
return engine->setAudioVolumeFromScript(object->id, clamped);
|
||||
}
|
||||
|
||||
bool ScriptContext::SetAudioClip(const std::string& path) {
|
||||
if (!engine || !object || !object->hasAudioSource) return false;
|
||||
object->audioSource.clipPath = path;
|
||||
engine->markProjectDirty();
|
||||
return engine->setAudioClipFromScript(object->id, path);
|
||||
}
|
||||
|
||||
std::string ScriptContext::GetSetting(const std::string& key, const std::string& fallback) const {
|
||||
if (!script) return fallback;
|
||||
auto it = std::find_if(script->settings.begin(), script->settings.end(),
|
||||
|
||||
@@ -40,6 +40,13 @@ struct ScriptContext {
|
||||
bool SetRigidbodyVelocity(const glm::vec3& velocity);
|
||||
bool GetRigidbodyVelocity(glm::vec3& outVelocity) const;
|
||||
bool TeleportRigidbody(const glm::vec3& pos, const glm::vec3& rotDeg);
|
||||
// Audio helpers
|
||||
bool HasAudioSource() const;
|
||||
bool PlayAudio();
|
||||
bool StopAudio();
|
||||
bool SetAudioLoop(bool loop);
|
||||
bool SetAudioVolume(float volume);
|
||||
bool SetAudioClip(const std::string& path);
|
||||
// Settings helpers (auto-mark dirty)
|
||||
std::string GetSetting(const std::string& key, const std::string& fallback = "") const;
|
||||
void SetSetting(const std::string& key, const std::string& value);
|
||||
|
||||
Reference in New Issue
Block a user