Working on 3d preview of meshes

This commit is contained in:
Chewico 2025-12-09 17:07:38 +01:00
parent a6328299ec
commit 90f5569855
17 changed files with 189 additions and 144 deletions

View File

@ -92,6 +92,9 @@ namespace Deer {
}
static Resource<T> loadResourceFromData(const typename ResourceBuilder<T>::BaseDataType& resourceData, const std::string& storageId) {
if (resourceCache.contains(storageId))
return resourceCache[storageId];
Scope<T> data = ResourceBuilder<T>::buildResource(resourceData);
Resource<T> resource = Resource<T>::unsafeFromId(resources.size());

View File

@ -60,15 +60,15 @@ namespace Deer {
RenderUtils::m_lineShader->bind();
RenderUtils::m_lineShader->uploadUniformMat4("u_viewMatrix", cameraProjectionMatrix);
RenderUtils::m_lineShader->uploadUniformFloat3("u_color", glm::vec3(.5f, .5f, .5f));
for (int x = 0; x < CHUNK_SIZE_X + 1; x++) {
RenderUtils::m_lineShader->uploadUniformFloat3("u_posA", glm::vec3(x, 0, 0));
RenderUtils::m_lineShader->uploadUniformFloat3("u_posB", glm::vec3(x, 0, CHUNK_SIZE_Z));
for (int x = -8; x < 8 + 1; x++) {
RenderUtils::m_lineShader->uploadUniformFloat3("u_posA", glm::vec3(x, 0, -8));
RenderUtils::m_lineShader->uploadUniformFloat3("u_posB", glm::vec3(x, 0, 8));
Render::submitLine(*RenderUtils::m_lineVertexArray.get());
}
for (int z = 0; z < CHUNK_SIZE_Z + 1; z++) {
RenderUtils::m_lineShader->uploadUniformFloat3("u_posA", glm::vec3(0, 0, z));
RenderUtils::m_lineShader->uploadUniformFloat3("u_posB", glm::vec3(CHUNK_SIZE_X, 0, z));
for (int z = -8; z < 8 + 1; z++) {
RenderUtils::m_lineShader->uploadUniformFloat3("u_posA", glm::vec3(-8, 0, z));
RenderUtils::m_lineShader->uploadUniformFloat3("u_posB", glm::vec3(8, 0, z));
Render::submitLine(*RenderUtils::m_lineVertexArray.get());
}

View File

@ -2,6 +2,8 @@
#include "DeerRender/Tools/TypeDefs.h"
namespace Deer {
class Environment;
namespace StudioAPI {
struct EnvironmentHandleStruct {
EnvironmentHandleStruct(int32_t _id = -1) : environmentId(_id) {}
@ -16,6 +18,7 @@ namespace Deer {
int32_t environmentId;
bool assertEntity(const char* funcName);
Environment* getEntityEnvironment();
};
struct FrameBufferHandleStruct {

View File

@ -25,6 +25,8 @@ namespace Deer {
bool buttonEnd(std::string&);
bool cartIconButton(const std::string& label, const std::string& icon, int iconSize, int width);
bool cartIconButton_frameBuffer(const std::string& label, FrameBufferHandleStruct frameBuffer, int iconSize, int width);
void text(std::string&);
void textCenter(std::string&);

View File

@ -12,7 +12,7 @@ namespace Deer {
for (uint32_t typeId = 0; typeId < typeCount; typeId++) {
asITypeInfo* typeInfo = angelscriptModule->GetObjectTypeByIndex(typeId);
if (ImplementsInterface(serviceBaseType, serviceBaseType)) {
if (ImplementsInterface(typeInfo, serviceBaseType)) {
services.push_back({typeInfo});
} else if (ImplementsInterface(typeInfo, panelBaseType)) {
panels.push_back({typeInfo});

View File

@ -14,6 +14,7 @@ namespace Deer {
REGISTER_GLOBAL_FUNC("bool buttonEnd(const string& in text)", StudioAPI::buttonEnd);
REGISTER_GLOBAL_FUNC("bool cartIconButton(const string& in label, const string& in icon, int iconSize, int width)", StudioAPI::cartIconButton);
REGISTER_GLOBAL_FUNC("bool cartIconButton(const string& in label, FrameBuffer frameBuffer, int iconSize, int width)", StudioAPI::cartIconButton_frameBuffer);
// Checkboxes
REGISTER_GLOBAL_FUNC("bool checkbox(const string& in text, bool value)", StudioAPI::checkbox);

View File

@ -57,7 +57,7 @@ namespace Deer {
std::ifstream file(path);
if (!file.is_open()) {
DEER_CORE_ERROR("Failed to open metadata file '{}' for reading", path.string().c_str());
DEER_CORE_TRACE("Failed to open metadata file '{}' for reading", path.string().c_str());
return metadata;
}
@ -100,7 +100,7 @@ namespace Deer {
std::ofstream file(path, std::ios::out | std::ios::trunc);
if (!file.is_open()) {
DEER_CORE_ERROR("Failed to open metadata file '{}' for writing", path.string().c_str());
DEER_CORE_TRACE("Failed to open metadata file '{}' for writing", path.string().c_str());
return;
}

View File

@ -46,11 +46,18 @@ namespace Deer {
EntityStruct::EntityStruct(uint16_t _entId, int32_t _envId) : EntityHandleStruct(_entId, _envId) {}
Environment* EntityHandleStruct::getEntityEnvironment() {
if (environmentId < 0)
return &Scene::environment;
return &Resource<Environment>::unsafeFromId(environmentId).getData();
}
bool EntityHandleStruct::assertEntity(const char* funcName) {
if (!Scene::environment.entityExists(entityId)) {
Environment* env = getEntityEnvironment();
if (!env->entityExists(entityId)) {
DEER_EDITOR_ENGINE_ERROR(
"Error, invalid entity calling {0}, entityId : {1}",
funcName, entityId);
"Error, invalid entity calling {0}, entityId : {1}, environmentId : {2}",
funcName, entityId, environmentId);
AngelScriptEngine::raiseError();
return false;
}
@ -188,7 +195,14 @@ namespace Deer {
bool MeshComponentStruct::assertMeshComponent(const char* funcName) {
if (!assertEntity(funcName))
return false;
Entity& ent = Scene::environment.getEntity(entityId);
Environment* env;
if (environmentId < 0)
env = &Scene::environment;
else
env = &Resource<Environment>::unsafeFromId(environmentId).getData();
Entity& ent = env->getEntity(entityId);
if (!ent.hasComponent<MeshComponent>()) {
DEER_EDITOR_ENGINE_ERROR(
@ -227,12 +241,15 @@ namespace Deer {
EntityHandleStruct EntityStruct::createChild(std::string& name) {
ASSERT_ENTITY("createChild()", return *this);
Entity& newEnt = Scene::environment.createEntity(name);
DEER_CORE_INFO("Creating child on env {}", environmentId);
Environment* entityEnv = getEntityEnvironment();
Entity& newEnt = entityEnv->createEntity(name);
Entity& me = GET_ENTITY(environmentId, entityId);
newEnt.setParent(me);
return EntityStruct(newEnt.getId());
return EntityStruct(newEnt.getId(), environmentId);
}
EntityHandleStruct EntityStruct::getMeshComponent() {
@ -421,7 +438,9 @@ namespace Deer {
bool ShaderComponentStruct::assertShaderComponent(const char* funcName) {
if (!assertEntity(funcName))
return false;
Entity& ent = Scene::environment.getEntity(entityId);
Environment* env = getEntityEnvironment();
Entity& ent = env->getEntity(entityId);
if (!ent.hasComponent<ShaderComponent>()) {
DEER_EDITOR_ENGINE_ERROR(
@ -470,7 +489,9 @@ namespace Deer {
bool CameraComponentStruct::assertCameraComponent(const char* funcName) {
if (!assertEntity(funcName))
return false;
Entity& ent = Scene::environment.getEntity(entityId);
Environment* env = getEntityEnvironment();
Entity& ent = env->getEntity(entityId);
if (!ent.hasComponent<CameraComponent>()) {
DEER_EDITOR_ENGINE_ERROR(

View File

@ -23,9 +23,7 @@ namespace Deer {
if (environmentId < 0) {
envPtr = &Scene::environment;
} else {
Resource<Environment> environmentResource =
Resource<Environment>::unsafeFromId(environmentId);
Resource<Environment> environmentResource = Resource<Environment>::unsafeFromId(environmentId);
envPtr = &environmentResource.getData();
}

View File

@ -16,7 +16,7 @@ namespace Deer {
if (extension == ".obj" || extension == ".fbx" || extension == ".dae" ||
extension == ".3ds" || extension == ".ply" || extension == ".stl" ||
extension == ".glb" || extension == ".gltf") {
extension == ".glb" || extension == ".gltf"|| extension == ".mtl") {
return ResourceType::MESH;
}

View File

@ -142,6 +142,60 @@ namespace Deer {
return pressed;
}
bool cartIconButton_frameBuffer(const std::string& label, FrameBufferHandleStruct icon, int iconSize, int width)
{
ImGui::BeginGroup();
int offset = 16;
float textHeight = ImGui::GetTextLineHeight();
float itemWidth = width;
float itemHeight = iconSize + textHeight + offset * 2;
// Clickable area uses the full width
ImGui::InvisibleButton(label.c_str(), ImVec2(itemWidth, itemHeight));
bool hovered = ImGui::IsItemHovered();
bool pressed = ImGui::IsItemClicked();
ImDrawList* dl = ImGui::GetWindowDrawList();
ImVec2 p = ImGui::GetItemRectMin();
ImVec2 q = ImGui::GetItemRectMax();
// Background
dl->AddRectFilled(
p, q,
hovered ? IM_COL32(255,255,255,30) : IM_COL32(255,255,255,10),
4.0f
);
// Center icon horizontally
ImVec2 iconPos(
p.x + (itemWidth - iconSize) * 0.5f,
p.y + 2.0f + offset
);
FrameBuffer& frameBuffer = Resource<FrameBuffer>::unsafeFromId(icon.frameBufferId).getData();
frameBuffer.bind();
ImTextureID texId = frameBuffer.getTextureBufferID();
dl->AddImage(
(ImTextureID)texId,
iconPos,
ImVec2(iconPos.x + iconSize, iconPos.y + iconSize),
ImVec2(0,1),
ImVec2(1,0)
);
frameBuffer.unbind();
// Center text
ImVec2 textSize = ImGui::CalcTextSize(label.c_str());
ImVec2 textPos(
p.x + (itemWidth - textSize.x) * 0.5f,
iconPos.y + iconSize + 2.0f
);
dl->AddText(textPos, ImGui::GetColorU32(ImGuiCol_Text), label.c_str());
ImGui::EndGroup();
return pressed;
}
void textColor(float r, float g, float b, std::string& msg) {
ImGui::TextColored(ImVec4(r, g, b, 1.0f), "%s", msg.c_str());
@ -228,8 +282,7 @@ namespace Deer {
frameBuffer.bind();
int frameBufferId = frameBuffer.getTextureBufferID(0);
ImGui::Image((void*)(uint64_t)frameBufferId, ImVec2(sizeX, sizeY),
ImVec2(0, 1), ImVec2(1, 0));
ImGui::Image((void*)(uint64_t)frameBufferId, ImVec2(sizeX, sizeY), ImVec2(0, 1), ImVec2(1, 0));
frameBuffer.unbind();
}

View File

@ -1,7 +1,43 @@
void do() {
RenderService@ mainRenderService;
array<int> arrayInt;
FrameBuffer renderMeshPreview(GPUMesh mesh) {
return mainRenderService.renderMeshPreview(mesh);
}
void setSceneCamera (SceneCamera sc) {
}
class RenderService : Service {
void init() {
@mainRenderService = this;
env = Resource::createLoadEnvironment("PreviewerEnv");
child = env.getRootEntity().createChild("Render");
meshC = child.createMeshComponent();
ShaderComponent shaderC = child.createShaderComponent();
shaderC.shader = Resource::loadShader("shader.glsl");
Engine::print("CAM : " + sceneCamera.transform.position.x + " " + sceneCamera.transform.scale.x + " : " + sceneCamera.camera.aspect);
sceneCamera.transform.position.z = -3;
sceneCamera.transform.position.y = 1;
}
FrameBuffer renderMeshPreview(GPUMesh mesh) {
FrameBuffer buffer = Resource::createLoadRGBA8FrameBuffer(mesh.path, 128, 128, 4);
buffer.clearRGBA(0, 0, 0, 0);
meshC.meshResource = mesh;
mainRenderService.env.render(buffer, mainRenderService.sceneCamera);
return buffer;
}
Environment env;
SceneCamera sceneCamera;
MeshComponent meshC;
Entity child;
}

View File

@ -1,92 +0,0 @@
bool drawFolder(string&in name) {
bool click = false;
UI::drawIconCentered("folder.png", 64);
if (UI::isItemClicked(0) and UI::isMouseDoubleClicked(0)) {
click = true;
}
UI::textCenter(name);
UI::nextColumn();
return click;
}
bool drawIcon(string&in name, string&in iconName) {
bool click = false;
UI::drawIconCentered(iconName, 64);
if (UI::isItemClicked(0) and UI::isMouseDoubleClicked(0)) {
click = true;
}
UI::textCenter(name);
UI::nextColumn();
return click;
}
bool drawFile(string&in name) {
bool click = false;
UI::drawIconCentered("file.png", 64);
if (UI::isItemClicked(0) and UI::isMouseDoubleClicked(0)) {
click = true;
}
UI::textCenter(name);
UI::nextColumn();
return click;
}
bool drawFile(string&in name, string&in dragId, any dragData, string&in overlay) {
bool click = false;
UI::drawIconCentered("file.png", 64);
if (UI::isItemClicked(0) and UI::isMouseDoubleClicked(0)) {
click = true;
}
UI::dragDropSource(dragId,
dragData,
overlay);
UI::textCenter(name);
UI::nextColumn();
return click;
}
bool drawFileIcon(string&in name, string&in dragId, any dragData, string&in overlay, string&in icon, bool selected = false) {
bool click = false;
if (selected) {
UI::drawIconCenteredHighlight(icon, 64);
} else {
UI::drawIconCentered(icon, 64);
}
if (UI::isItemClicked(0) and UI::isMouseDoubleClicked(0)) {
click = true;
}
UI::dragDropSource(dragId,
dragData,
overlay);
UI::textCenter(name);
UI::nextColumn();
return click;
}
bool drawTextureIcon(string&in name, string&in dragId, any dragData, string&in overlay, Texture texture, bool selected = false) {
bool click = false;
if (selected) {
UI::drawIconCenteredHighlight(texture, 64);
} else {
UI::drawIconCentered(texture, 64);
}
if (UI::isItemClicked(0) and UI::isMouseDoubleClicked(0)) {
click = true;
}
UI::dragDropSource(dragId,
dragData,
overlay);
UI::textCenter(name);
UI::nextColumn();
return click;
}

View File

@ -1,30 +1,36 @@
import FrameBuffer renderMeshPreview(GPUMesh mesh) from "Previewer";
string selectedResource = "";
class ResourceExplorer : Panel {
string currentPath = "";
array<string> subFolders;
array<string> subFiles;
bool alreadyRendered = false;
dictionary meshFrameBuffer;
void init() {
setPath("");
}
void setPath(string&in path) {
meshFrameBuffer.deleteAll();
currentPath = path;
subFolders = Resource::getResourceFolders(path);
subFiles = Resource::getResourceFiles(path);
}
void render() {
alreadyRendered = false;
renderMenuBar();
UI::space();
UI::automaticColumns(160);
UI::automaticColumns(182);
string temp_path = currentPath;
// Render navigation folders
for (uint i = 0; i < subFolders.length(); i++) {
if (UI::cartIconButton(Path::getName(subFolders[i]), "folder.png", 64, UI::getAvailableSizeX())) {
if (UI::cartIconButton(Path::getName(subFolders[i]), "folder.png", 128, UI::getAvailableSizeX())) {
setPath(subFolders[i]);
}
UI::nextColumn();
@ -39,32 +45,46 @@ class ResourceExplorer : Panel {
ResourceType resType = Resource::getResourceType(filename);
bool selected = filename == selectedResource;
if (resType == ResourceType::Mesh) {
if (UI::cartIconButton(Path::getName(filename), "mesh.png", 64, UI::getAvailableSizeX())) {
if (resType == ResourceType::Mesh && !alreadyRendered) {
FrameBuffer frameBuffer;
if (meshFrameBuffer.exists(filename)) {
frameBuffer = FrameBuffer(meshFrameBuffer[filename]);
} else {
GPUMesh mesh = Resource::loadGPUMesh(filename);
frameBuffer = renderMeshPreview(mesh);
meshFrameBuffer[filename] = frameBuffer;
alreadyRendered = true;
}
if (UI::cartIconButton(Path::getName(filename), frameBuffer, 128, UI::getAvailableSizeX())) {
selectedResource = filename;
}
UI::dragDropSource("MESH", any(filename), filename);
UI::nextColumn();
return;
}
if (resType == ResourceType::Shader) {
if (UI::cartIconButton(Path::getName(filename), "shader.png", 64, UI::getAvailableSizeX())) {
if (UI::cartIconButton(Path::getName(filename), "shader.png", 128, UI::getAvailableSizeX())) {
selectedResource = filename;
}
UI::dragDropSource("SHADER", any(filename), filename);
UI::nextColumn();
return;
}
if (resType == ResourceType::Texture) {
Texture texture = Resource::loadTexture(filename);
if (UI::cartIconButton(Path::getName(filename), "texture.png", 64, UI::getAvailableSizeX())) {
if (UI::cartIconButton(Path::getName(filename), "texture.png", 128, UI::getAvailableSizeX())) {
selectedResource = filename;
}
UI::dragDropSource("TEXTURE", any(filename), filename);
UI::nextColumn();
return;
}
UI::cartIconButton(Path::getName(filename), "file.png", 64, UI::getAvailableSizeX());
UI::cartIconButton(Path::getName(filename), "file.png", 128, UI::getAvailableSizeX());
UI::nextColumn();
}

View File

@ -1,3 +1,5 @@
import void setSceneCamera (SceneCamera sc) from "Previewer";
class ViewportPanel : Panel {
FrameBuffer frameBuffer;
SceneCamera sceneCamera;
@ -24,7 +26,6 @@ class ViewportPanel : Panel {
mainEnv.render(frameBuffer, sceneCamera);
UI::drawFrameBufferCentered(frameBuffer, x, y);
if (!UI::isPanelActive())
return;
@ -67,10 +68,11 @@ class ViewportPanel : Panel {
vertically--;
sceneCamera.transform.position = sceneCamera.transform.position + vec3(0, vertically * vel, 0);
setSceneCamera(sceneCamera);
}
void init() {
frameBuffer = Resource::createLoadRGBA8FrameBuffer("MainFrameBuffer", 400, 400);
frameBuffer = Resource::createLoadRGBA8FrameBuffer("MainFrameBuffer", 1000, 1000);
mainEnv = Resource::getMainEnvironment();
sceneCamera.transform.position = vec3(0, 1, -2);

View File

@ -36,9 +36,7 @@ void main()
vec3 lightDir = normalize(vec3(1.0, 7.0, 3.0)) * 0.2f + 0.8f;
float light = clamp(dot(normalize(normal), lightDir), 0.1, 1.0);
vec4 texColor = texture(u_Texture, uv);
fragColor = vec4(texColor.rgb * light, texColor.a);
fragColor = vec4(uv.r, uv.g, light, 1);
// fragColor = vec4(uv.r, uv.g, 0, 1);
objectID = u_objectID;
}

View File

@ -5,7 +5,7 @@ Collapsed=0
[Window][ViewportPanel]
Pos=433,34
Size=1057,615
Size=927,428
Collapsed=0
DockId=0x00000004,1
@ -16,13 +16,13 @@ Collapsed=0
[Window][TreePanel]
Pos=0,34
Size=431,615
Size=431,428
Collapsed=0
DockId=0x00000001,0
[Window][ResourceExplorer]
Pos=0,651
Size=1920,359
Pos=0,464
Size=1920,546
Collapsed=0
DockId=0x00000006,0
@ -33,8 +33,8 @@ Collapsed=0
DockId=0xA1672E74,1
[Window][PropertiesPanel]
Pos=1492,34
Size=428,615
Pos=1362,34
Size=558,428
Collapsed=0
DockId=0x00000003,0
@ -61,17 +61,17 @@ Collapsed=0
[Window][Dear ImGui Metrics/Debugger]
Pos=433,34
Size=1057,615
Size=927,428
Collapsed=0
DockId=0x00000004,0
[Docking][Data]
DockSpace ID=0x0AC2E849 Window=0xD0388BC8 Pos=0,34 Size=1920,976 Split=Y
DockNode ID=0x00000005 Parent=0x0AC2E849 SizeRef=1920,615 Split=X
DockNode ID=0x00000002 Parent=0x00000005 SizeRef=1490,645 Split=X Selected=0xD9E076F4
DockNode ID=0x00000005 Parent=0x0AC2E849 SizeRef=1920,428 Split=X
DockNode ID=0x00000002 Parent=0x00000005 SizeRef=1360,645 Split=X Selected=0xD9E076F4
DockNode ID=0x00000001 Parent=0x00000002 SizeRef=431,976 Selected=0x16E3C1E7
DockNode ID=0x00000004 Parent=0x00000002 SizeRef=1057,976 CentralNode=1 Selected=0xD9E076F4
DockNode ID=0x00000003 Parent=0x00000005 SizeRef=428,645 Selected=0x9876A79B
DockNode ID=0x00000006 Parent=0x0AC2E849 SizeRef=1920,359 Selected=0x018A0F9B
DockNode ID=0x00000004 Parent=0x00000002 SizeRef=927,976 CentralNode=1 Selected=0xD9E076F4
DockNode ID=0x00000003 Parent=0x00000005 SizeRef=558,645 Selected=0x9876A79B
DockNode ID=0x00000006 Parent=0x0AC2E849 SizeRef=1920,546 Selected=0x018A0F9B
DockSpace ID=0xA1672E74 Pos=0,34 Size=1920,976 CentralNode=1 Selected=0x9ED090AF