Well, unfinished texture filtering system + Added Better Audio Source Loading and fixed up some stuff within the rendering.
This commit is contained in:
@@ -40,7 +40,7 @@ std::string getSetting(const ScriptContext& ctx, const std::string& key, const s
|
|||||||
|
|
||||||
void loadSettings(ScriptContext& ctx) {
|
void loadSettings(ScriptContext& ctx) {
|
||||||
if (!ctx.script || !ctx.object) return;
|
if (!ctx.script || !ctx.object) return;
|
||||||
if (settingsLoadedForId == ctx.object->id && settingsLoadedForScript == ctx.script) return;
|
if (settingsLoadedForId == ctx.object->id && settingsLoadedForScript == ctx.script) return;Segmentation fault (core dumped)
|
||||||
settingsLoadedForId = ctx.object->id;
|
settingsLoadedForId = ctx.object->id;
|
||||||
settingsLoadedForScript = ctx.script;
|
settingsLoadedForScript = ctx.script;
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,12 @@
|
|||||||
Available methods:
|
Available methods:
|
||||||
- `FindObjectByName`, `FindObjectById`
|
- `FindObjectByName`, `FindObjectById`
|
||||||
- `SetPosition`, `SetRotation`, `SetScale`
|
- `SetPosition`, `SetRotation`, `SetScale`
|
||||||
|
- `HasRigidbody`
|
||||||
|
- `SetRigidbodyVelocity`, `GetRigidbodyVelocity`
|
||||||
|
- `SetRigidbodyAngularVelocity`, `GetRigidbodyAngularVelocity`
|
||||||
|
- `AddRigidbodyForce`, `AddRigidbodyImpulse`
|
||||||
|
- `AddRigidbodyTorque`, `AddRigidbodyAngularImpulse`
|
||||||
|
- `SetRigidbodyRotation`, `TeleportRigidbody`
|
||||||
- `MarkDirty` (flags the project as having unsaved changes)
|
- `MarkDirty` (flags the project as having unsaved changes)
|
||||||
Fields:
|
Fields:
|
||||||
- `engine`: pointer to the Engine
|
- `engine`: pointer to the Engine
|
||||||
@@ -60,3 +66,15 @@ void Script_TickUpdate(ScriptContext& ctx, float dt) {
|
|||||||
- Scripts tick for all objects every frame, even if not selected.
|
- Scripts tick for all objects every frame, even if not selected.
|
||||||
- Spec/Test toggles are global (main menu → Scripts).
|
- Spec/Test toggles are global (main menu → Scripts).
|
||||||
- Compile scripts via the UI “Compile Script” button or run the build command; wrapper generation is automatic.
|
- Compile scripts via the UI “Compile Script” button or run the build command; wrapper generation is automatic.
|
||||||
|
|
||||||
|
## Manual compile (CLI)
|
||||||
|
Linux example:
|
||||||
|
```bash
|
||||||
|
g++ -std=c++20 -fPIC -O0 -g -I../src -I../include -c SampleInspector.cpp -o ../Cache/ScriptBin/SampleInspector.o
|
||||||
|
g++ -shared ../Cache/ScriptBin/SampleInspector.o -o ../Cache/ScriptBin/SampleInspector.so -ldl -lpthread
|
||||||
|
```
|
||||||
|
Windows example:
|
||||||
|
```bat
|
||||||
|
cl /nologo /std:c++20 /EHsc /MD /Zi /Od /I ..\\src /I ..\\include /c SampleInspector.cpp /Fo ..\\Cache\\ScriptBin\\SampleInspector.obj
|
||||||
|
link /nologo /DLL ..\\Cache\\ScriptBin\\SampleInspector.obj /OUT:..\\Cache\\ScriptBin\\SampleInspector.dll User32.lib Advapi32.lib
|
||||||
|
```
|
||||||
|
|||||||
@@ -30,7 +30,9 @@ void AudioSystem::shutdown() {
|
|||||||
|
|
||||||
void AudioSystem::destroyActiveSounds() {
|
void AudioSystem::destroyActiveSounds() {
|
||||||
for (auto& kv : activeSounds) {
|
for (auto& kv : activeSounds) {
|
||||||
ma_sound_uninit(&kv.second.sound);
|
if (kv.second) {
|
||||||
|
ma_sound_uninit(&kv.second->sound);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
activeSounds.clear();
|
activeSounds.clear();
|
||||||
}
|
}
|
||||||
@@ -42,7 +44,7 @@ void AudioSystem::onPlayStart(const std::vector<SceneObject>& objects) {
|
|||||||
if (!obj.enabled || !obj.hasAudioSource || obj.audioSource.clipPath.empty()) continue;
|
if (!obj.enabled || !obj.hasAudioSource || obj.audioSource.clipPath.empty()) continue;
|
||||||
if (!obj.audioSource.enabled) continue;
|
if (!obj.audioSource.enabled) continue;
|
||||||
if (ensureSoundFor(obj) && obj.audioSource.playOnStart) {
|
if (ensureSoundFor(obj) && obj.audioSource.playOnStart) {
|
||||||
ma_sound_start(&activeSounds[obj.id].sound);
|
ma_sound_start(&activeSounds[obj.id]->sound);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -54,44 +56,56 @@ void AudioSystem::onPlayStop() {
|
|||||||
bool AudioSystem::ensureSoundFor(const SceneObject& obj) {
|
bool AudioSystem::ensureSoundFor(const SceneObject& obj) {
|
||||||
auto it = activeSounds.find(obj.id);
|
auto it = activeSounds.find(obj.id);
|
||||||
if (it != activeSounds.end()) {
|
if (it != activeSounds.end()) {
|
||||||
if (it->second.clipPath == obj.audioSource.clipPath) {
|
if (it->second && it->second->clipPath == obj.audioSource.clipPath) {
|
||||||
refreshSoundParams(obj, it->second);
|
refreshSoundParams(obj, *it->second);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
ma_sound_uninit(&it->second.sound);
|
if (it->second) {
|
||||||
|
ma_sound_uninit(&it->second->sound);
|
||||||
|
}
|
||||||
activeSounds.erase(it);
|
activeSounds.erase(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!fs::exists(obj.audioSource.clipPath)) {
|
||||||
|
if (missingClips.insert(obj.audioSource.clipPath).second) {
|
||||||
|
std::cerr << "AudioSystem: clip not found " << obj.audioSource.clipPath << "\n";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
missingClips.erase(obj.audioSource.clipPath);
|
||||||
|
|
||||||
if (!initialized && !init()) return false;
|
if (!initialized && !init()) return false;
|
||||||
|
|
||||||
ActiveSound snd{};
|
auto snd = std::make_unique<ActiveSound>();
|
||||||
ma_result res = ma_sound_init_from_file(
|
ma_result res = ma_sound_init_from_file(
|
||||||
&engine,
|
&engine,
|
||||||
obj.audioSource.clipPath.c_str(),
|
obj.audioSource.clipPath.c_str(),
|
||||||
MA_SOUND_FLAG_STREAM,
|
MA_SOUND_FLAG_STREAM,
|
||||||
nullptr,
|
nullptr,
|
||||||
nullptr,
|
nullptr,
|
||||||
&snd.sound
|
&snd->sound
|
||||||
);
|
);
|
||||||
if (res != MA_SUCCESS) {
|
if (res != MA_SUCCESS) {
|
||||||
std::cerr << "AudioSystem: failed to load " << obj.audioSource.clipPath << " (" << res << ")\n";
|
std::cerr << "AudioSystem: failed to load " << obj.audioSource.clipPath << " (" << res << ")\n";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
snd.clipPath = obj.audioSource.clipPath;
|
snd->clipPath = obj.audioSource.clipPath;
|
||||||
snd.spatial = obj.audioSource.spatial;
|
snd->spatial = obj.audioSource.spatial;
|
||||||
snd.started = false;
|
snd->started = false;
|
||||||
refreshSoundParams(obj, snd);
|
refreshSoundParams(obj, *snd);
|
||||||
activeSounds[obj.id] = std::move(snd);
|
activeSounds.emplace(obj.id, std::move(snd));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioSystem::refreshSoundParams(const SceneObject& obj, ActiveSound& snd) {
|
void AudioSystem::refreshSoundParams(const SceneObject& obj, ActiveSound& snd) {
|
||||||
|
float minDist = std::max(0.1f, obj.audioSource.minDistance);
|
||||||
|
float maxDist = std::max(obj.audioSource.maxDistance, minDist + 0.5f);
|
||||||
ma_sound_set_looping(&snd.sound, obj.audioSource.loop ? MA_TRUE : MA_FALSE);
|
ma_sound_set_looping(&snd.sound, obj.audioSource.loop ? MA_TRUE : MA_FALSE);
|
||||||
ma_sound_set_volume(&snd.sound, obj.audioSource.volume);
|
ma_sound_set_volume(&snd.sound, obj.audioSource.volume);
|
||||||
ma_sound_set_spatialization_enabled(&snd.sound, obj.audioSource.spatial ? MA_TRUE : MA_FALSE);
|
ma_sound_set_spatialization_enabled(&snd.sound, obj.audioSource.spatial ? MA_TRUE : MA_FALSE);
|
||||||
ma_sound_set_min_distance(&snd.sound, obj.audioSource.minDistance);
|
ma_sound_set_min_distance(&snd.sound, minDist);
|
||||||
ma_sound_set_max_distance(&snd.sound, obj.audioSource.maxDistance);
|
ma_sound_set_max_distance(&snd.sound, maxDist);
|
||||||
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) && !snd.started && obj.audioSource.playOnStart && obj.audioSource.enabled) {
|
if (!ma_sound_is_playing(&snd.sound) && !snd.started && obj.audioSource.playOnStart && obj.audioSource.enabled) {
|
||||||
@@ -120,20 +134,24 @@ void AudioSystem::update(const std::vector<SceneObject>& objects, const Camera&
|
|||||||
auto eraseIt = activeSounds.find(obj.id);
|
auto eraseIt = activeSounds.find(obj.id);
|
||||||
if (!obj.enabled || !obj.audioSource.enabled || obj.audioSource.clipPath.empty()) {
|
if (!obj.enabled || !obj.audioSource.enabled || obj.audioSource.clipPath.empty()) {
|
||||||
if (eraseIt != activeSounds.end()) {
|
if (eraseIt != activeSounds.end()) {
|
||||||
ma_sound_uninit(&eraseIt->second.sound);
|
if (eraseIt->second) {
|
||||||
|
ma_sound_uninit(&eraseIt->second->sound);
|
||||||
|
}
|
||||||
activeSounds.erase(eraseIt);
|
activeSounds.erase(eraseIt);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ensureSoundFor(obj)) {
|
if (ensureSoundFor(obj)) {
|
||||||
refreshSoundParams(obj, activeSounds[obj.id]);
|
refreshSoundParams(obj, *activeSounds[obj.id]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto it = activeSounds.begin(); it != activeSounds.end(); ) {
|
for (auto it = activeSounds.begin(); it != activeSounds.end(); ) {
|
||||||
if (stillPresent.find(it->first) == stillPresent.end()) {
|
if (stillPresent.find(it->first) == stillPresent.end()) {
|
||||||
ma_sound_uninit(&it->second.sound);
|
if (it->second) {
|
||||||
|
ma_sound_uninit(&it->second->sound);
|
||||||
|
}
|
||||||
it = activeSounds.erase(it);
|
it = activeSounds.erase(it);
|
||||||
} else {
|
} else {
|
||||||
++it;
|
++it;
|
||||||
@@ -202,7 +220,7 @@ bool AudioSystem::seekPreview(const std::string& path, double seconds) {
|
|||||||
bool AudioSystem::playObjectSound(const SceneObject& obj) {
|
bool AudioSystem::playObjectSound(const SceneObject& obj) {
|
||||||
if (!obj.hasAudioSource || obj.audioSource.clipPath.empty() || !obj.audioSource.enabled) return false;
|
if (!obj.hasAudioSource || obj.audioSource.clipPath.empty() || !obj.audioSource.enabled) return false;
|
||||||
if (!ensureSoundFor(obj)) return false;
|
if (!ensureSoundFor(obj)) return false;
|
||||||
ActiveSound& snd = activeSounds[obj.id];
|
ActiveSound& snd = *activeSounds[obj.id];
|
||||||
snd.started = true;
|
snd.started = true;
|
||||||
return ma_sound_start(&snd.sound) == MA_SUCCESS;
|
return ma_sound_start(&snd.sound) == MA_SUCCESS;
|
||||||
}
|
}
|
||||||
@@ -210,19 +228,20 @@ bool AudioSystem::playObjectSound(const SceneObject& obj) {
|
|||||||
bool AudioSystem::stopObjectSound(int objectId) {
|
bool AudioSystem::stopObjectSound(int objectId) {
|
||||||
auto it = activeSounds.find(objectId);
|
auto it = activeSounds.find(objectId);
|
||||||
if (it == activeSounds.end()) return false;
|
if (it == activeSounds.end()) return false;
|
||||||
return ma_sound_stop(&it->second.sound) == MA_SUCCESS;
|
if (!it->second) return false;
|
||||||
|
return ma_sound_stop(&it->second->sound) == MA_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AudioSystem::setObjectLoop(const SceneObject& obj, bool loop) {
|
bool AudioSystem::setObjectLoop(const SceneObject& obj, bool loop) {
|
||||||
if (!ensureSoundFor(obj)) return false;
|
if (!ensureSoundFor(obj)) return false;
|
||||||
ActiveSound& snd = activeSounds[obj.id];
|
ActiveSound& snd = *activeSounds[obj.id];
|
||||||
ma_sound_set_looping(&snd.sound, loop ? MA_TRUE : MA_FALSE);
|
ma_sound_set_looping(&snd.sound, loop ? MA_TRUE : MA_FALSE);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AudioSystem::setObjectVolume(const SceneObject& obj, float volume) {
|
bool AudioSystem::setObjectVolume(const SceneObject& obj, float volume) {
|
||||||
if (!ensureSoundFor(obj)) return false;
|
if (!ensureSoundFor(obj)) return false;
|
||||||
ActiveSound& snd = activeSounds[obj.id];
|
ActiveSound& snd = *activeSounds[obj.id];
|
||||||
ma_sound_set_volume(&snd.sound, volume);
|
ma_sound_set_volume(&snd.sound, volume);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,8 +49,9 @@ private:
|
|||||||
|
|
||||||
ma_engine engine{};
|
ma_engine engine{};
|
||||||
bool initialized = false;
|
bool initialized = false;
|
||||||
std::unordered_map<int, ActiveSound> activeSounds;
|
std::unordered_map<int, std::unique_ptr<ActiveSound>> activeSounds;
|
||||||
std::unordered_map<std::string, AudioClipPreview> previewCache;
|
std::unordered_map<std::string, AudioClipPreview> previewCache;
|
||||||
|
std::unordered_set<std::string> missingClips;
|
||||||
|
|
||||||
ma_sound previewSound{};
|
ma_sound previewSound{};
|
||||||
bool previewActive = false;
|
bool previewActive = false;
|
||||||
|
|||||||
@@ -35,9 +35,22 @@ void Engine::renderHierarchyPanel() {
|
|||||||
ImGui::PushStyleColor(ImGuiCol_ChildBg, headerBg);
|
ImGui::PushStyleColor(ImGuiCol_ChildBg, headerBg);
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(8.0f, 4.0f));
|
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(8.0f, 4.0f));
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6.0f, 4.0f));
|
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6.0f, 4.0f));
|
||||||
ImGui::BeginChild("HierarchyHeader", ImVec2(0, 50), true, ImGuiWindowFlags_NoScrollbar);
|
ImGui::BeginChild("HierarchyHeader", ImVec2(0, 74), true, ImGuiWindowFlags_NoScrollbar);
|
||||||
ImGui::SetNextItemWidth(-1);
|
ImGui::SetNextItemWidth(-1);
|
||||||
ImGui::InputTextWithHint("##Search", "Search...", searchBuffer, sizeof(searchBuffer));
|
ImGui::InputTextWithHint("##Search", "Search...", searchBuffer, sizeof(searchBuffer));
|
||||||
|
ImGui::Spacing();
|
||||||
|
ImGui::Checkbox("Texture Preview", &hierarchyShowTexturePreview);
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::BeginDisabled(!hierarchyShowTexturePreview);
|
||||||
|
ImGui::TextDisabled("Filter");
|
||||||
|
ImGui::SameLine();
|
||||||
|
const char* filterOptions[] = { "Bilinear", "Nearest" };
|
||||||
|
int filterIndex = hierarchyPreviewNearest ? 1 : 0;
|
||||||
|
ImGui::SetNextItemWidth(120.0f);
|
||||||
|
if (ImGui::Combo("##HierarchyTexFilter", &filterIndex, filterOptions, IM_ARRAYSIZE(filterOptions))) {
|
||||||
|
hierarchyPreviewNearest = (filterIndex == 1);
|
||||||
|
}
|
||||||
|
ImGui::EndDisabled();
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
ImGui::PopStyleVar(2);
|
ImGui::PopStyleVar(2);
|
||||||
ImGui::PopStyleColor();
|
ImGui::PopStyleColor();
|
||||||
@@ -181,6 +194,38 @@ void Engine::renderObjectNode(SceneObject& obj, const std::string& filter) {
|
|||||||
ImGui::EndPopup();
|
ImGui::EndPopup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hierarchyShowTexturePreview) {
|
||||||
|
const std::string* previewPath = nullptr;
|
||||||
|
if (!obj.albedoTexturePath.empty()) {
|
||||||
|
previewPath = &obj.albedoTexturePath;
|
||||||
|
} else if (obj.useOverlay && !obj.overlayTexturePath.empty()) {
|
||||||
|
previewPath = &obj.overlayTexturePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (previewPath) {
|
||||||
|
auto overrideIt = texturePreviewFilterOverrides.find(*previewPath);
|
||||||
|
bool previewNearest = (overrideIt != texturePreviewFilterOverrides.end())
|
||||||
|
? overrideIt->second
|
||||||
|
: hierarchyPreviewNearest;
|
||||||
|
Texture* previewTex = renderer.getTexturePreview(*previewPath, previewNearest);
|
||||||
|
if (previewTex && previewTex->GetID()) {
|
||||||
|
ImGuiStyle& style = ImGui::GetStyle();
|
||||||
|
ImVec2 itemMin = ImGui::GetItemRectMin();
|
||||||
|
ImVec2 itemMax = ImGui::GetItemRectMax();
|
||||||
|
float lineHeight = itemMax.y - itemMin.y;
|
||||||
|
float previewSize = std::max(12.0f, lineHeight - 4.0f);
|
||||||
|
float rightEdge = ImGui::GetWindowPos().x + ImGui::GetWindowContentRegionMax().x;
|
||||||
|
float previewX = rightEdge - previewSize - style.WindowPadding.x;
|
||||||
|
float previewY = itemMin.y + (lineHeight - previewSize) * 0.5f;
|
||||||
|
ImVec2 pMin(previewX, previewY);
|
||||||
|
ImVec2 pMax(previewX + previewSize, previewY + previewSize);
|
||||||
|
ImGui::GetWindowDrawList()->AddImage(
|
||||||
|
(ImTextureID)(intptr_t)previewTex->GetID(),
|
||||||
|
pMin, pMax, ImVec2(0, 1), ImVec2(1, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (nodeOpen) {
|
if (nodeOpen) {
|
||||||
for (int childId : obj.childIds) {
|
for (int childId : obj.childIds) {
|
||||||
auto it = std::find_if(sceneObjects.begin(), sceneObjects.end(),
|
auto it = std::find_if(sceneObjects.begin(), sceneObjects.end(),
|
||||||
@@ -201,6 +246,8 @@ void Engine::renderInspectorPanel() {
|
|||||||
fs::path selectedAudioPath;
|
fs::path selectedAudioPath;
|
||||||
bool browserHasAudio = false;
|
bool browserHasAudio = false;
|
||||||
const AudioClipPreview* selectedAudioPreview = nullptr;
|
const AudioClipPreview* selectedAudioPreview = nullptr;
|
||||||
|
fs::path selectedTexturePath;
|
||||||
|
bool browserHasTexture = false;
|
||||||
if (!fileBrowser.selectedFile.empty() && fs::exists(fileBrowser.selectedFile)) {
|
if (!fileBrowser.selectedFile.empty() && fs::exists(fileBrowser.selectedFile)) {
|
||||||
fs::directory_entry entry(fileBrowser.selectedFile);
|
fs::directory_entry entry(fileBrowser.selectedFile);
|
||||||
FileCategory cat = fileBrowser.getFileCategory(entry);
|
FileCategory cat = fileBrowser.getFileCategory(entry);
|
||||||
@@ -229,6 +276,10 @@ void Engine::renderInspectorPanel() {
|
|||||||
browserHasAudio = true;
|
browserHasAudio = true;
|
||||||
selectedAudioPreview = audio.getPreview(selectedAudioPath.string());
|
selectedAudioPreview = audio.getPreview(selectedAudioPath.string());
|
||||||
}
|
}
|
||||||
|
if (cat == FileCategory::Texture) {
|
||||||
|
selectedTexturePath = entry.path();
|
||||||
|
browserHasTexture = true;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
inspectedMaterialPath.clear();
|
inspectedMaterialPath.clear();
|
||||||
inspectedMaterialValid = false;
|
inspectedMaterialValid = false;
|
||||||
@@ -555,11 +606,68 @@ void Engine::renderInspectorPanel() {
|
|||||||
ImGui::PopStyleColor();
|
ImGui::PopStyleColor();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
auto renderTextureAssetPanel = [&](const char* headerTitle) {
|
||||||
|
if (!browserHasTexture) return;
|
||||||
|
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.35f, 0.35f, 0.55f, 1.0f));
|
||||||
|
if (ImGui::CollapsingHeader(headerTitle, ImGuiTreeNodeFlags_DefaultOpen)) {
|
||||||
|
ImGui::Indent(8.0f);
|
||||||
|
|
||||||
|
ImGui::TextDisabled("%s", selectedTexturePath.filename().string().c_str());
|
||||||
|
ImGui::TextColored(ImVec4(0.8f, 0.65f, 0.95f, 1.0f), "%s", selectedTexturePath.string().c_str());
|
||||||
|
|
||||||
|
bool hasOverride = texturePreviewFilterOverrides.find(selectedTexturePath.string()) != texturePreviewFilterOverrides.end();
|
||||||
|
bool previewNearest = hasOverride ? texturePreviewFilterOverrides[selectedTexturePath.string()] : hierarchyPreviewNearest;
|
||||||
|
Texture* previewTex = renderer.getTexturePreview(selectedTexturePath.string(), previewNearest);
|
||||||
|
|
||||||
|
ImGui::Spacing();
|
||||||
|
if (previewTex && previewTex->GetID()) {
|
||||||
|
float maxWidth = ImGui::GetContentRegionAvail().x;
|
||||||
|
float size = std::min(maxWidth, 160.0f);
|
||||||
|
float aspect = previewTex->GetHeight() > 0 ? (previewTex->GetWidth() / static_cast<float>(previewTex->GetHeight())) : 1.0f;
|
||||||
|
ImVec2 imageSize(size, size);
|
||||||
|
if (aspect > 1.0f) {
|
||||||
|
imageSize.y = size / aspect;
|
||||||
|
} else if (aspect > 0.0f) {
|
||||||
|
imageSize.x = size * aspect;
|
||||||
|
}
|
||||||
|
ImGui::Image((ImTextureID)(intptr_t)previewTex->GetID(), imageSize, ImVec2(0, 1), ImVec2(1, 0));
|
||||||
|
ImGui::Text("Size: %d x %d", previewTex->GetWidth(), previewTex->GetHeight());
|
||||||
|
} else {
|
||||||
|
ImGui::TextColored(ImVec4(1.0f, 0.6f, 0.6f, 1.0f), "Unable to load texture preview.");
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Spacing();
|
||||||
|
if (ImGui::Checkbox("Override Hierarchy Filter", &hasOverride)) {
|
||||||
|
if (hasOverride) {
|
||||||
|
texturePreviewFilterOverrides[selectedTexturePath.string()] = hierarchyPreviewNearest;
|
||||||
|
} else {
|
||||||
|
texturePreviewFilterOverrides.erase(selectedTexturePath.string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::BeginDisabled(!hasOverride);
|
||||||
|
const char* filterOptions[] = { "Bilinear", "Nearest" };
|
||||||
|
int filterIndex = previewNearest ? 1 : 0;
|
||||||
|
if (ImGui::Combo("Preview Filter", &filterIndex, filterOptions, IM_ARRAYSIZE(filterOptions))) {
|
||||||
|
texturePreviewFilterOverrides[selectedTexturePath.string()] = (filterIndex == 1);
|
||||||
|
}
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
if (!hasOverride) {
|
||||||
|
ImGui::TextDisabled("Using global: %s", hierarchyPreviewNearest ? "Nearest" : "Bilinear");
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Unindent(8.0f);
|
||||||
|
}
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
};
|
||||||
|
|
||||||
if (selectedObjectIds.empty()) {
|
if (selectedObjectIds.empty()) {
|
||||||
if (browserHasMaterial) {
|
if (browserHasMaterial) {
|
||||||
renderMaterialAssetPanel("Material Asset", true);
|
renderMaterialAssetPanel("Material Asset", true);
|
||||||
} else if (browserHasAudio) {
|
} else if (browserHasAudio) {
|
||||||
renderAudioAssetPanel("Audio Clip", nullptr);
|
renderAudioAssetPanel("Audio Clip", nullptr);
|
||||||
|
} else if (browserHasTexture) {
|
||||||
|
renderTextureAssetPanel("Texture");
|
||||||
} else {
|
} else {
|
||||||
ImGui::TextDisabled("No object selected");
|
ImGui::TextDisabled("No object selected");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1281,10 +1281,34 @@ bool Engine::getRigidbodyVelocityFromScript(int id, glm::vec3& outVelocity) {
|
|||||||
return physics.getLinearVelocity(id, outVelocity);
|
return physics.getLinearVelocity(id, outVelocity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Engine::setRigidbodyAngularVelocityFromScript(int id, const glm::vec3& velocity) {
|
||||||
|
return physics.setAngularVelocity(id, velocity);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Engine::getRigidbodyAngularVelocityFromScript(int id, glm::vec3& outVelocity) {
|
||||||
|
return physics.getAngularVelocity(id, outVelocity);
|
||||||
|
}
|
||||||
|
|
||||||
bool Engine::teleportPhysicsActorFromScript(int id, const glm::vec3& position, const glm::vec3& rotationDeg) {
|
bool Engine::teleportPhysicsActorFromScript(int id, const glm::vec3& position, const glm::vec3& rotationDeg) {
|
||||||
return physics.setActorPose(id, position, rotationDeg);
|
return physics.setActorPose(id, position, rotationDeg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Engine::addRigidbodyForceFromScript(int id, const glm::vec3& force) {
|
||||||
|
return physics.addForce(id, force);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Engine::addRigidbodyImpulseFromScript(int id, const glm::vec3& impulse) {
|
||||||
|
return physics.addImpulse(id, impulse);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Engine::addRigidbodyTorqueFromScript(int id, const glm::vec3& torque) {
|
||||||
|
return physics.addTorque(id, torque);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Engine::addRigidbodyAngularImpulseFromScript(int id, const glm::vec3& impulse) {
|
||||||
|
return physics.addAngularImpulse(id, impulse);
|
||||||
|
}
|
||||||
|
|
||||||
bool Engine::playAudioFromScript(int id) {
|
bool Engine::playAudioFromScript(int id) {
|
||||||
SceneObject* obj = findObjectById(id);
|
SceneObject* obj = findObjectById(id);
|
||||||
if (!obj || !obj->hasAudioSource) return false;
|
if (!obj || !obj->hasAudioSource) return false;
|
||||||
|
|||||||
10
src/Engine.h
10
src/Engine.h
@@ -13,6 +13,7 @@
|
|||||||
#include "AudioSystem.h"
|
#include "AudioSystem.h"
|
||||||
#include "PackageManager.h"
|
#include "PackageManager.h"
|
||||||
#include "../include/Window/Window.h"
|
#include "../include/Window/Window.h"
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
void window_size_callback(GLFWwindow* window, int width, int height);
|
void window_size_callback(GLFWwindow* window, int width, int height);
|
||||||
|
|
||||||
@@ -98,6 +99,9 @@ private:
|
|||||||
float fileBrowserIconScale = 1.0f; // 0.5 to 2.0 range
|
float fileBrowserIconScale = 1.0f; // 0.5 to 2.0 range
|
||||||
bool showEnvironmentWindow = true;
|
bool showEnvironmentWindow = true;
|
||||||
bool showCameraWindow = true;
|
bool showCameraWindow = true;
|
||||||
|
bool hierarchyShowTexturePreview = false;
|
||||||
|
bool hierarchyPreviewNearest = false;
|
||||||
|
std::unordered_map<std::string, bool> texturePreviewFilterOverrides;
|
||||||
bool isPlaying = false;
|
bool isPlaying = false;
|
||||||
bool isPaused = false;
|
bool isPaused = false;
|
||||||
bool showViewOutput = true;
|
bool showViewOutput = true;
|
||||||
@@ -235,7 +239,13 @@ public:
|
|||||||
// Script-accessible physics helpers
|
// Script-accessible physics helpers
|
||||||
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 setRigidbodyAngularVelocityFromScript(int id, const glm::vec3& velocity);
|
||||||
|
bool getRigidbodyAngularVelocityFromScript(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);
|
||||||
|
bool addRigidbodyForceFromScript(int id, const glm::vec3& force);
|
||||||
|
bool addRigidbodyImpulseFromScript(int id, const glm::vec3& impulse);
|
||||||
|
bool addRigidbodyTorqueFromScript(int id, const glm::vec3& torque);
|
||||||
|
bool addRigidbodyAngularImpulseFromScript(int id, const glm::vec3& impulse);
|
||||||
// Audio control exposed to scripts
|
// Audio control exposed to scripts
|
||||||
bool playAudioFromScript(int id);
|
bool playAudioFromScript(int id);
|
||||||
bool stopAudioFromScript(int id);
|
bool stopAudioFromScript(int id);
|
||||||
|
|||||||
@@ -398,6 +398,20 @@ bool PhysicsSystem::setLinearVelocity(int id, const glm::vec3& velocity) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PhysicsSystem::setAngularVelocity(int id, const glm::vec3& velocity) {
|
||||||
|
#ifdef MODULARITY_ENABLE_PHYSX
|
||||||
|
auto it = mActors.find(id);
|
||||||
|
if (it == mActors.end()) return false;
|
||||||
|
ActorRecord& rec = it->second;
|
||||||
|
if (!rec.actor || !rec.isDynamic || rec.isKinematic) return false;
|
||||||
|
if (PxRigidDynamic* dyn = rec.actor->is<PxRigidDynamic>()) {
|
||||||
|
dyn->setAngularVelocity(ToPxVec3(velocity));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool PhysicsSystem::setActorYaw(int id, float yawDegrees) {
|
bool PhysicsSystem::setActorYaw(int id, float yawDegrees) {
|
||||||
#ifdef MODULARITY_ENABLE_PHYSX
|
#ifdef MODULARITY_ENABLE_PHYSX
|
||||||
auto it = mActors.find(id);
|
auto it = mActors.find(id);
|
||||||
@@ -428,6 +442,21 @@ bool PhysicsSystem::getLinearVelocity(int id, glm::vec3& outVelocity) const {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PhysicsSystem::getAngularVelocity(int id, glm::vec3& outVelocity) const {
|
||||||
|
#ifdef MODULARITY_ENABLE_PHYSX
|
||||||
|
auto it = mActors.find(id);
|
||||||
|
if (it == mActors.end()) return false;
|
||||||
|
const ActorRecord& rec = it->second;
|
||||||
|
if (!rec.actor || !rec.isDynamic || rec.isKinematic) return false;
|
||||||
|
if (const PxRigidDynamic* dyn = rec.actor->is<PxRigidDynamic>()) {
|
||||||
|
PxVec3 v = dyn->getAngularVelocity();
|
||||||
|
outVelocity = glm::vec3(v.x, v.y, v.z);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool PhysicsSystem::setActorPose(int id, const glm::vec3& position, const glm::vec3& rotationDeg) {
|
bool PhysicsSystem::setActorPose(int id, const glm::vec3& position, const glm::vec3& rotationDeg) {
|
||||||
#ifdef MODULARITY_ENABLE_PHYSX
|
#ifdef MODULARITY_ENABLE_PHYSX
|
||||||
auto it = mActors.find(id);
|
auto it = mActors.find(id);
|
||||||
@@ -443,6 +472,62 @@ bool PhysicsSystem::setActorPose(int id, const glm::vec3& position, const glm::v
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PhysicsSystem::addForce(int id, const glm::vec3& force) {
|
||||||
|
#ifdef MODULARITY_ENABLE_PHYSX
|
||||||
|
auto it = mActors.find(id);
|
||||||
|
if (it == mActors.end()) return false;
|
||||||
|
ActorRecord& rec = it->second;
|
||||||
|
if (!rec.actor || !rec.isDynamic || rec.isKinematic) return false;
|
||||||
|
if (PxRigidDynamic* dyn = rec.actor->is<PxRigidDynamic>()) {
|
||||||
|
dyn->addForce(ToPxVec3(force), PxForceMode::eFORCE);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PhysicsSystem::addImpulse(int id, const glm::vec3& impulse) {
|
||||||
|
#ifdef MODULARITY_ENABLE_PHYSX
|
||||||
|
auto it = mActors.find(id);
|
||||||
|
if (it == mActors.end()) return false;
|
||||||
|
ActorRecord& rec = it->second;
|
||||||
|
if (!rec.actor || !rec.isDynamic || rec.isKinematic) return false;
|
||||||
|
if (PxRigidDynamic* dyn = rec.actor->is<PxRigidDynamic>()) {
|
||||||
|
dyn->addForce(ToPxVec3(impulse), PxForceMode::eIMPULSE);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PhysicsSystem::addTorque(int id, const glm::vec3& torque) {
|
||||||
|
#ifdef MODULARITY_ENABLE_PHYSX
|
||||||
|
auto it = mActors.find(id);
|
||||||
|
if (it == mActors.end()) return false;
|
||||||
|
ActorRecord& rec = it->second;
|
||||||
|
if (!rec.actor || !rec.isDynamic || rec.isKinematic) return false;
|
||||||
|
if (PxRigidDynamic* dyn = rec.actor->is<PxRigidDynamic>()) {
|
||||||
|
dyn->addTorque(ToPxVec3(torque), PxForceMode::eFORCE);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PhysicsSystem::addAngularImpulse(int id, const glm::vec3& impulse) {
|
||||||
|
#ifdef MODULARITY_ENABLE_PHYSX
|
||||||
|
auto it = mActors.find(id);
|
||||||
|
if (it == mActors.end()) return false;
|
||||||
|
ActorRecord& rec = it->second;
|
||||||
|
if (!rec.actor || !rec.isDynamic || rec.isKinematic) return false;
|
||||||
|
if (PxRigidDynamic* dyn = rec.actor->is<PxRigidDynamic>()) {
|
||||||
|
dyn->addTorque(ToPxVec3(impulse), PxForceMode::eIMPULSE);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool PhysicsSystem::raycastClosest(const glm::vec3& origin, const glm::vec3& dir, float distance,
|
bool PhysicsSystem::raycastClosest(const glm::vec3& origin, const glm::vec3& dir, float distance,
|
||||||
int ignoreId, glm::vec3* hitPos, glm::vec3* hitNormal, float* hitDistance) const {
|
int ignoreId, glm::vec3* hitPos, glm::vec3* hitNormal, float* hitDistance) const {
|
||||||
#ifdef MODULARITY_ENABLE_PHYSX
|
#ifdef MODULARITY_ENABLE_PHYSX
|
||||||
@@ -544,8 +629,15 @@ bool PhysicsSystem::init() { return false; }
|
|||||||
void PhysicsSystem::shutdown() {}
|
void PhysicsSystem::shutdown() {}
|
||||||
bool PhysicsSystem::isReady() const { return false; }
|
bool PhysicsSystem::isReady() const { return false; }
|
||||||
bool PhysicsSystem::setLinearVelocity(int, const glm::vec3&) { return false; }
|
bool PhysicsSystem::setLinearVelocity(int, const glm::vec3&) { return false; }
|
||||||
|
bool PhysicsSystem::setAngularVelocity(int, const glm::vec3&) { return false; }
|
||||||
bool PhysicsSystem::setActorYaw(int, float) { return false; }
|
bool PhysicsSystem::setActorYaw(int, float) { return false; }
|
||||||
bool PhysicsSystem::getLinearVelocity(int, glm::vec3&) const { return false; }
|
bool PhysicsSystem::getLinearVelocity(int, glm::vec3&) const { return false; }
|
||||||
|
bool PhysicsSystem::getAngularVelocity(int, glm::vec3&) const { return false; }
|
||||||
|
bool PhysicsSystem::setActorPose(int, const glm::vec3&, const glm::vec3&) { return false; }
|
||||||
|
bool PhysicsSystem::addForce(int, const glm::vec3&) { return false; }
|
||||||
|
bool PhysicsSystem::addImpulse(int, const glm::vec3&) { return false; }
|
||||||
|
bool PhysicsSystem::addTorque(int, const glm::vec3&) { return false; }
|
||||||
|
bool PhysicsSystem::addAngularImpulse(int, const glm::vec3&) { return false; }
|
||||||
void PhysicsSystem::onPlayStart(const std::vector<SceneObject>&) {}
|
void PhysicsSystem::onPlayStart(const std::vector<SceneObject>&) {}
|
||||||
void PhysicsSystem::onPlayStop() {}
|
void PhysicsSystem::onPlayStop() {}
|
||||||
void PhysicsSystem::simulate(float, std::vector<SceneObject>&) {}
|
void PhysicsSystem::simulate(float, std::vector<SceneObject>&) {}
|
||||||
|
|||||||
@@ -16,9 +16,15 @@ public:
|
|||||||
void shutdown();
|
void shutdown();
|
||||||
bool isReady() const;
|
bool isReady() const;
|
||||||
bool setLinearVelocity(int id, const glm::vec3& velocity);
|
bool setLinearVelocity(int id, const glm::vec3& velocity);
|
||||||
|
bool setAngularVelocity(int id, const glm::vec3& velocity);
|
||||||
bool setActorYaw(int id, float yawDegrees);
|
bool setActorYaw(int id, float yawDegrees);
|
||||||
bool getLinearVelocity(int id, glm::vec3& outVelocity) const;
|
bool getLinearVelocity(int id, glm::vec3& outVelocity) const;
|
||||||
|
bool getAngularVelocity(int id, glm::vec3& outVelocity) const;
|
||||||
bool setActorPose(int id, const glm::vec3& position, const glm::vec3& rotationDeg);
|
bool setActorPose(int id, const glm::vec3& position, const glm::vec3& rotationDeg);
|
||||||
|
bool addForce(int id, const glm::vec3& force);
|
||||||
|
bool addImpulse(int id, const glm::vec3& impulse);
|
||||||
|
bool addTorque(int id, const glm::vec3& torque);
|
||||||
|
bool addAngularImpulse(int id, const glm::vec3& impulse);
|
||||||
bool raycastClosest(const glm::vec3& origin, const glm::vec3& dir, float distance,
|
bool raycastClosest(const glm::vec3& origin, const glm::vec3& dir, float distance,
|
||||||
int ignoreId, glm::vec3* hitPos = nullptr,
|
int ignoreId, glm::vec3* hitPos = nullptr,
|
||||||
glm::vec3* hitNormal = nullptr, float* hitDistance = nullptr) const;
|
glm::vec3* hitNormal = nullptr, float* hitDistance = nullptr) const;
|
||||||
|
|||||||
@@ -480,6 +480,23 @@ Texture* Renderer::getTexture(const std::string& path) {
|
|||||||
return raw;
|
return raw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Texture* Renderer::getTexturePreview(const std::string& path, bool nearest) {
|
||||||
|
if (path.empty()) return nullptr;
|
||||||
|
auto& cache = nearest ? previewTextureCacheNearest : previewTextureCacheLinear;
|
||||||
|
auto it = cache.find(path);
|
||||||
|
if (it != cache.end()) return it->second.get();
|
||||||
|
|
||||||
|
GLenum minFilter = nearest ? GL_NEAREST : GL_LINEAR_MIPMAP_LINEAR;
|
||||||
|
GLenum magFilter = nearest ? GL_NEAREST : GL_LINEAR;
|
||||||
|
auto tex = std::make_unique<Texture>(path, GL_REPEAT, GL_REPEAT, minFilter, magFilter);
|
||||||
|
if (!tex->GetID()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
Texture* raw = tex.get();
|
||||||
|
cache[path] = std::move(tex);
|
||||||
|
return raw;
|
||||||
|
}
|
||||||
|
|
||||||
void Renderer::initialize() {
|
void Renderer::initialize() {
|
||||||
shader = new Shader(defaultVertPath.c_str(), defaultFragPath.c_str());
|
shader = new Shader(defaultVertPath.c_str(), defaultFragPath.c_str());
|
||||||
defaultShader = shader;
|
defaultShader = shader;
|
||||||
|
|||||||
@@ -86,6 +86,8 @@ private:
|
|||||||
Texture* texture1 = nullptr;
|
Texture* texture1 = nullptr;
|
||||||
Texture* texture2 = nullptr;
|
Texture* texture2 = nullptr;
|
||||||
std::unordered_map<std::string, std::unique_ptr<Texture>> textureCache;
|
std::unordered_map<std::string, std::unique_ptr<Texture>> textureCache;
|
||||||
|
std::unordered_map<std::string, std::unique_ptr<Texture>> previewTextureCacheLinear;
|
||||||
|
std::unordered_map<std::string, std::unique_ptr<Texture>> previewTextureCacheNearest;
|
||||||
struct ShaderEntry {
|
struct ShaderEntry {
|
||||||
std::unique_ptr<Shader> shader;
|
std::unique_ptr<Shader> shader;
|
||||||
fs::file_time_type vertTime;
|
fs::file_time_type vertTime;
|
||||||
@@ -131,6 +133,7 @@ public:
|
|||||||
|
|
||||||
void initialize();
|
void initialize();
|
||||||
Texture* getTexture(const std::string& path);
|
Texture* getTexture(const std::string& path);
|
||||||
|
Texture* getTexturePreview(const std::string& path, bool nearest);
|
||||||
Shader* getShader(const std::string& vert, const std::string& frag);
|
Shader* getShader(const std::string& vert, const std::string& frag);
|
||||||
bool forceReloadShader(const std::string& vert, const std::string& frag);
|
bool forceReloadShader(const std::string& vert, const std::string& frag);
|
||||||
void setAmbientColor(const glm::vec3& color) { ambientColor = color; }
|
void setAmbientColor(const glm::vec3& color) { ambientColor = color; }
|
||||||
|
|||||||
@@ -122,6 +122,43 @@ bool ScriptContext::GetRigidbodyVelocity(glm::vec3& outVelocity) const {
|
|||||||
return engine->getRigidbodyVelocityFromScript(object->id, outVelocity);
|
return engine->getRigidbodyVelocityFromScript(object->id, outVelocity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ScriptContext::SetRigidbodyAngularVelocity(const glm::vec3& velocity) {
|
||||||
|
if (!engine || !object || !HasRigidbody()) return false;
|
||||||
|
return engine->setRigidbodyAngularVelocityFromScript(object->id, velocity);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScriptContext::GetRigidbodyAngularVelocity(glm::vec3& outVelocity) const {
|
||||||
|
if (!engine || !object || !HasRigidbody()) return false;
|
||||||
|
return engine->getRigidbodyAngularVelocityFromScript(object->id, outVelocity);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScriptContext::AddRigidbodyForce(const glm::vec3& force) {
|
||||||
|
if (!engine || !object || !HasRigidbody()) return false;
|
||||||
|
return engine->addRigidbodyForceFromScript(object->id, force);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScriptContext::AddRigidbodyImpulse(const glm::vec3& impulse) {
|
||||||
|
if (!engine || !object || !HasRigidbody()) return false;
|
||||||
|
return engine->addRigidbodyImpulseFromScript(object->id, impulse);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScriptContext::AddRigidbodyTorque(const glm::vec3& torque) {
|
||||||
|
if (!engine || !object || !HasRigidbody()) return false;
|
||||||
|
return engine->addRigidbodyTorqueFromScript(object->id, torque);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScriptContext::AddRigidbodyAngularImpulse(const glm::vec3& impulse) {
|
||||||
|
if (!engine || !object || !HasRigidbody()) return false;
|
||||||
|
return engine->addRigidbodyAngularImpulseFromScript(object->id, impulse);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScriptContext::SetRigidbodyRotation(const glm::vec3& rotDeg) {
|
||||||
|
if (!engine || !object || !HasRigidbody()) return false;
|
||||||
|
object->rotation = NormalizeEulerDegrees(rotDeg);
|
||||||
|
MarkDirty();
|
||||||
|
return engine->teleportPhysicsActorFromScript(object->id, object->position, object->rotation);
|
||||||
|
}
|
||||||
|
|
||||||
bool ScriptContext::TeleportRigidbody(const glm::vec3& pos, const glm::vec3& rotDeg) {
|
bool ScriptContext::TeleportRigidbody(const glm::vec3& pos, const glm::vec3& rotDeg) {
|
||||||
if (!engine || !object) return false;
|
if (!engine || !object) return false;
|
||||||
object->position = pos;
|
object->position = pos;
|
||||||
|
|||||||
@@ -39,6 +39,13 @@ struct ScriptContext {
|
|||||||
bool HasRigidbody() const;
|
bool HasRigidbody() const;
|
||||||
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 SetRigidbodyAngularVelocity(const glm::vec3& velocity);
|
||||||
|
bool GetRigidbodyAngularVelocity(glm::vec3& outVelocity) const;
|
||||||
|
bool AddRigidbodyForce(const glm::vec3& force);
|
||||||
|
bool AddRigidbodyImpulse(const glm::vec3& impulse);
|
||||||
|
bool AddRigidbodyTorque(const glm::vec3& torque);
|
||||||
|
bool AddRigidbodyAngularImpulse(const glm::vec3& impulse);
|
||||||
|
bool SetRigidbodyRotation(const glm::vec3& rotDeg);
|
||||||
bool TeleportRigidbody(const glm::vec3& pos, const glm::vec3& rotDeg);
|
bool TeleportRigidbody(const glm::vec3& pos, const glm::vec3& rotDeg);
|
||||||
// Audio helpers
|
// Audio helpers
|
||||||
bool HasAudioSource() const;
|
bool HasAudioSource() const;
|
||||||
|
|||||||
Reference in New Issue
Block a user