part 2 since i forgot to stage changes lol.

This commit is contained in:
Anemunt
2025-12-16 19:53:15 -05:00
parent 6ecf2a5106
commit ed390e56c3
7 changed files with 155 additions and 8 deletions

View File

@@ -80,6 +80,7 @@ bool AudioSystem::ensureSoundFor(const SceneObject& obj) {
snd.clipPath = obj.audioSource.clipPath; snd.clipPath = obj.audioSource.clipPath;
snd.spatial = obj.audioSource.spatial; snd.spatial = obj.audioSource.spatial;
snd.started = false;
refreshSoundParams(obj, snd); refreshSoundParams(obj, snd);
activeSounds[obj.id] = std::move(snd); activeSounds[obj.id] = std::move(snd);
return true; 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_max_distance(&snd.sound, obj.audioSource.maxDistance);
ma_sound_set_position(&snd.sound, obj.position.x, obj.position.y, obj.position.z); 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); 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; 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 AudioSystem::loadPreview(const std::string& path) {
AudioClipPreview preview; AudioClipPreview preview;
preview.path = path; preview.path = path;

View File

@@ -33,11 +33,18 @@ public:
bool getPreviewTime(const std::string& path, double& cursorSeconds, double& durationSeconds) const; bool getPreviewTime(const std::string& path, double& cursorSeconds, double& durationSeconds) const;
bool seekPreview(const std::string& path, double seconds); 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: private:
struct ActiveSound { struct ActiveSound {
ma_sound sound; ma_sound sound;
std::string clipPath; std::string clipPath;
bool spatial = true; bool spatial = true;
bool started = false; // prevents auto-restart after manual stop
}; };
ma_engine engine{}; ma_engine engine{};

View File

@@ -1266,6 +1266,42 @@ bool Engine::teleportPhysicsActorFromScript(int id, const glm::vec3& position, c
return physics.setActorPose(id, position, rotationDeg); 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) { void Engine::compileScriptFile(const fs::path& scriptPath) {
if (!projectManager.currentProject.isLoaded) { if (!projectManager.currentProject.isLoaded) {
addConsoleMessage("No project is loaded", ConsoleMessageType::Warning); addConsoleMessage("No project is loaded", ConsoleMessageType::Warning);

View File

@@ -92,6 +92,7 @@ private:
bool isPlaying = false; bool isPlaying = false;
bool isPaused = false; bool isPaused = false;
bool showViewOutput = true; bool showViewOutput = true;
bool showSceneGizmos = true;
bool showGameViewport = true; bool showGameViewport = true;
int previewCameraId = -1; int previewCameraId = -1;
bool gameViewCursorLocked = false; bool gameViewCursorLocked = false;
@@ -221,4 +222,10 @@ public:
bool setRigidbodyVelocityFromScript(int id, const glm::vec3& velocity); bool setRigidbodyVelocityFromScript(int id, const glm::vec3& velocity);
bool getRigidbodyVelocityFromScript(int id, glm::vec3& outVelocity); bool getRigidbodyVelocityFromScript(int id, glm::vec3& outVelocity);
bool teleportPhysicsActorFromScript(int id, const glm::vec3& position, const glm::vec3& rotationDeg); 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);
}; };

View File

@@ -3576,6 +3576,7 @@ void Engine::renderViewport() {
} }
bool mouseOverViewportImage = false; bool mouseOverViewportImage = false;
bool blockSelection = false;
if (rendererInitialized) { if (rendererInitialized) {
glm::mat4 proj = glm::perspective( glm::mat4 proj = glm::perspective(
@@ -3687,6 +3688,11 @@ void Engine::renderViewport() {
if (clickedIdx >= 0) { if (clickedIdx >= 0) {
setCameraFacing(arrows[clickedIdx].dir); 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> { auto projectToScreen = [&](const glm::vec3& p) -> std::optional<ImVec2> {
@@ -4170,11 +4176,13 @@ void Engine::renderViewport() {
} }
}; };
if (showSceneGizmos) {
for (const auto& obj : sceneObjects) { for (const auto& obj : sceneObjects) {
if (obj.type == ObjectType::Camera) { if (obj.type == ObjectType::Camera) {
drawCameraDirection(obj); drawCameraDirection(obj);
} }
} }
}
// Light visualization overlays // Light visualization overlays
auto drawLightOverlays = [&](const SceneObject& lightObj) { auto drawLightOverlays = [&](const SceneObject& lightObj) {
@@ -4269,11 +4277,13 @@ void Engine::renderViewport() {
} }
}; };
if (showSceneGizmos) {
for (const auto& obj : sceneObjects) { for (const auto& obj : sceneObjects) {
if (obj.type == ObjectType::PointLight || obj.type == ObjectType::SpotLight || obj.type == ObjectType::AreaLight) { if (obj.type == ObjectType::PointLight || obj.type == ObjectType::SpotLight || obj.type == ObjectType::AreaLight) {
drawLightOverlays(obj); drawLightOverlays(obj);
} }
} }
}
// Toolbar // Toolbar
const float toolbarPadding = 6.0f; const float toolbarPadding = 6.0f;
@@ -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::EndGroup();
ImGui::PopStyleVar(); ImGui::PopStyleVar();
@@ -4420,10 +4438,16 @@ void Engine::renderViewport() {
splitter.Merge(toolbarDrawList); splitter.Merge(toolbarDrawList);
// Prevent viewport picking when clicking on the toolbar overlay.
if (ImGui::IsMouseHoveringRect(bgMin, bgMax)) {
blockSelection = true;
}
// Left-click picking inside viewport // Left-click picking inside viewport
if (mouseOverViewportImage && if (mouseOverViewportImage &&
ImGui::IsMouseClicked(ImGuiMouseButton_Left) && ImGui::IsMouseClicked(ImGuiMouseButton_Left) &&
!ImGuizmo::IsUsing() && !ImGuizmo::IsOver()) !ImGuizmo::IsUsing() && !ImGuizmo::IsOver() &&
!blockSelection)
{ {
glm::mat4 invViewProj = glm::inverse(proj * view); glm::mat4 invViewProj = glm::inverse(proj * view);
ImVec2 mousePos = ImGui::GetMousePos(); ImVec2 mousePos = ImGui::GetMousePos();

View File

@@ -108,6 +108,42 @@ bool ScriptContext::TeleportRigidbody(const glm::vec3& pos, const glm::vec3& rot
return engine->teleportPhysicsActorFromScript(object->id, pos, object->rotation); 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 { std::string ScriptContext::GetSetting(const std::string& key, const std::string& fallback) const {
if (!script) return fallback; if (!script) return fallback;
auto it = std::find_if(script->settings.begin(), script->settings.end(), auto it = std::find_if(script->settings.begin(), script->settings.end(),

View File

@@ -40,6 +40,13 @@ struct ScriptContext {
bool SetRigidbodyVelocity(const glm::vec3& velocity); bool SetRigidbodyVelocity(const glm::vec3& velocity);
bool GetRigidbodyVelocity(glm::vec3& outVelocity) const; bool GetRigidbodyVelocity(glm::vec3& outVelocity) const;
bool TeleportRigidbody(const glm::vec3& pos, const glm::vec3& rotDeg); 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) // Settings helpers (auto-mark dirty)
std::string GetSetting(const std::string& key, const std::string& fallback = "") const; std::string GetSetting(const std::string& key, const std::string& fallback = "") const;
void SetSetting(const std::string& key, const std::string& value); void SetSetting(const std::string& key, const std::string& value);