diff --git a/data/pipelines/main.pln b/data/pipelines/main.pln index c71f73133..ef7c59f64 100644 --- a/data/pipelines/main.pln +++ b/data/pipelines/main.pln @@ -6,6 +6,7 @@ local selection_outline_shader = preloadShader("pipelines/selection_outline.shd" local local_light_shader = preloadShader("pipelines/local_light.shd") local blur_shader = preloadShader("pipelines/blur.shd") local debug_shadowmap = false +local screenshot_request = 0 local decal_state = { blending = "add", @@ -260,22 +261,49 @@ function main() res = postprocess("post_tonemap", res, gbuffer0, gbuffer1, gbuffer2, gbuffer_depth, shadowmap) end + if GAME_VIEW or APP then + renderIngameGUI() + end + debugPass(res, shadowmap) - if renderGizmos ~= nil then + if SCENE_VIEW ~= nil then pass(getCameraParams()) - setRenderTargets(res, gbuffer_depth) - clear(CLEAR_DEPTH, 0, 0, 0, 1, 0) - renderGizmos() - render2D() + setRenderTargets(res, gbuffer_depth) + clear(CLEAR_DEPTH, 0, 0, 0, 1, 0) + renderGizmos() + end + + render2D() + + if SCENE_VIEW ~= nil then renderIcons() renderDebugShapes() renderSelectionOutline(res) end setOutput(res) + + if screenshot_request > 1 then + -- we have to wait for a few frames to propagate changed resolution + -- only then we can take a screeshot + screenshot_request = screenshot_request - 1 + GameView.forceViewport(true, 4096, 2160) + elseif screenshot_request == 1 then + saveRenderbuffer(res, "screenshot.tga") + GameView.forceViewport(false, 0, 0) + screenshot_request = 0 + end end function onGUI() + if GAME_VIEW then + ImGui.SameLine() + if ImGui.Button("Screenshot") then + screenshot_request = 2 + end + return + end + if ImGui.Button("Debug") then ImGui.OpenPopup("debug_popup") end diff --git a/src/editor/asset_browser.cpp b/src/editor/asset_browser.cpp index 5672ade3b..6d94651ed 100644 --- a/src/editor/asset_browser.cpp +++ b/src/editor/asset_browser.cpp @@ -798,10 +798,7 @@ void AssetBrowser::endSaveResource(Resource& resource, OutputMemoryStream& strea } } - -// TODO selected_path_hash == null is bad UX -bool AssetBrowser::resourceList(Span buf, Ref selected_path_hash, ResourceType type, float height, bool can_create_new) const -{ +bool AssetBrowser::resourceList(Span buf, Ref selected_path_hash, ResourceType type, float height, bool can_create_new) const { auto iter = m_plugins.find(type); if (!iter.isValid()) return false; @@ -824,8 +821,7 @@ bool AssetBrowser::resourceList(Span buf, Ref selected_path_hash, Res const HashMap& resourcs = compiler.lockResources(); Path selected_path; - for (const auto& res : resourcs) - { + for (const auto& res : resourcs) { if(res.type != type) continue; if (filter[0] != '\0' && strstr(res.path.c_str(), filter) == nullptr) continue; @@ -833,8 +829,7 @@ bool AssetBrowser::resourceList(Span buf, Ref selected_path_hash, Res if(selected) selected_path = res.path; ResourceLocator rl(res.path.c_str()); StaticString label("", rl.name, "##h", res.path.getHash()); - if (ImGui::Selectable(label, selected, ImGuiSelectableFlags_AllowDoubleClick)) - { + if (ImGui::Selectable(label, selected, ImGuiSelectableFlags_AllowDoubleClick)) { selected_path_hash = res.path.getHash(); if (selected || ImGui::IsMouseDoubleClicked(0)) { diff --git a/src/editor/asset_compiler.cpp b/src/editor/asset_compiler.cpp index 67fff27c4..ac228bc61 100644 --- a/src/editor/asset_compiler.cpp +++ b/src/editor/asset_compiler.cpp @@ -107,8 +107,7 @@ struct AssetCompilerImpl : AssetCompiler { OS::OutputFile file; FileSystem& fs = m_app.getWorldEditor().getEngine().getFileSystem(); - // TODO make this safe - i.e. handle case when program gets interrupted while writing the file - if (fs.open(".lumix/assets/_list.txt", Ref(file))) { + if (fs.open(".lumix/assets/_list.txt_tmp", Ref(file))) { file << "resources = {\n"; for (const ResourceItem& ri : m_resources) { file << "\"" << ri.path.c_str() << "\",\n"; @@ -124,7 +123,9 @@ struct AssetCompilerImpl : AssetCompiler } file << "}\n"; - file.close(); + file.close(); + fs.deleteFile(".lumix/assets/_list.txt"); + fs.moveFile(".lumix/assets/_list.txt_tmp", ".lumix/assets/_list.txt"); } else { logError("Editor") << "Could not save .lumix/assets/_list.txt"; diff --git a/src/editor/studio_app.cpp b/src/editor/studio_app.cpp index 3b717641a..6a6c6056c 100644 --- a/src/editor/studio_app.cpp +++ b/src/editor/studio_app.cpp @@ -310,10 +310,6 @@ public: ImGui::CreateContext(); loadSettings(); initIMGUI(); -#ifdef _WIN32 -// TODO -// ImGui::GetPlatformIO().ImeWindowHandle = m_window; -#endif m_custom_pivot_action = LUMIX_NEW(m_editor->getAllocator(), Action)("Set Custom Pivot", "Set Custom Pivot", @@ -1572,8 +1568,12 @@ public: void setFullscreen(bool fullscreen) override { - ASSERT(false); // TODO - // SDL_SetWindowFullscreen(m_window, fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0); + if(fullscreen) { + m_fullscreen_restore_state = OS::setFullscreen(m_window); + } + else { + OS::restore(m_window, m_fullscreen_restore_state); + } } @@ -2793,6 +2793,7 @@ public: Debug::Allocator m_allocator; Engine* m_engine; OS::WindowHandle m_window; + OS::WindowState m_fullscreen_restore_state; Array m_actions; Array m_window_actions; Array m_toolbar_actions; diff --git a/src/engine/os.h b/src/engine/os.h index 7de912c31..e7249d7d6 100644 --- a/src/engine/os.h +++ b/src/engine/os.h @@ -142,6 +142,11 @@ struct FileInfo { struct FileIterator; +struct WindowState { + u64 style; + Rect rect; +}; + LUMIX_ENGINE_API void* memReserve(size_t size); LUMIX_ENGINE_API void memCommit(void* ptr, size_t size); LUMIX_ENGINE_API void memRelease(void* ptr); @@ -187,6 +192,8 @@ LUMIX_ENGINE_API Point getWindowClientSize(WindowHandle win); LUMIX_ENGINE_API void setWindowScreenRect(WindowHandle win, const Rect& rect); LUMIX_ENGINE_API void setWindowTitle(WindowHandle win, const char* title); LUMIX_ENGINE_API void maximizeWindow(WindowHandle win); +LUMIX_ENGINE_API WindowState setFullscreen(WindowHandle win); +LUMIX_ENGINE_API void restore(WindowHandle win, WindowState state); LUMIX_ENGINE_API bool isMaximized(WindowHandle win); LUMIX_ENGINE_API WindowHandle getFocused(); diff --git a/src/engine/win/os.cpp b/src/engine/win/os.cpp index 96e57a92e..dc908228a 100644 --- a/src/engine/win/os.cpp +++ b/src/engine/win/os.cpp @@ -4,7 +4,6 @@ #include "engine/path_utils.h" #include "engine/string.h" #define UNICODE -#include #pragma warning(push) #pragma warning(disable : 4091) #include @@ -615,15 +614,27 @@ WindowHandle getFocused() return GetActiveWindow(); } - -bool isMaximized(WindowHandle win) -{ +bool isMaximized(WindowHandle win) { WINDOWPLACEMENT placement; BOOL res = GetWindowPlacement((HWND)win, &placement); ASSERT(res); return placement.showCmd == SW_SHOWMAXIMIZED; } +void restore(WindowHandle win, WindowState state) { + SetWindowLongPtr((HWND)win, GWL_STYLE, state.style); + OS::setWindowScreenRect(win, state.rect); +} + +WindowState setFullscreen(WindowHandle win) { + WindowState res; + res.rect = OS::getWindowScreenRect(win); + res.style = SetWindowLongPtr((HWND)win, GWL_STYLE, WS_VISIBLE | WS_POPUP); + int w = GetSystemMetrics(SM_CXSCREEN); + int h = GetSystemMetrics(SM_CYSCREEN); + SetWindowPos((HWND)win, HWND_TOP, 0, 0, w, h, SWP_FRAMECHANGED); + return res; +} void maximizeWindow(WindowHandle win) { diff --git a/src/gui/gui_scene.cpp b/src/gui/gui_scene.cpp index 680f988bf..1fed372c2 100644 --- a/src/gui/gui_scene.cpp +++ b/src/gui/gui_scene.cpp @@ -928,12 +928,12 @@ struct GUISceneImpl final : public GUIScene void handleTextInput(const InputSystem::Event& event) { - /*const GUIRect* rect = getInput(m_focused_entity); + const GUIRect* rect = getInput(m_focused_entity); if (!rect) return; - rect->text->text.insert(rect->input_field->cursor, event.data.text.text); - rect->input_field->cursor += stringLength(event.data.text.text);*/ - // TODO - ASSERT(false); + char tmp[5]; + OS::UTF32ToUTF8(event.data.text.utf32, tmp); + rect->text->text.insert(rect->input_field->cursor, tmp); + ++rect->input_field->cursor; } diff --git a/src/renderer/editor/fbx_importer.cpp b/src/renderer/editor/fbx_importer.cpp index fd170f3a5..2c53121fb 100644 --- a/src/renderer/editor/fbx_importer.cpp +++ b/src/renderer/editor/fbx_importer.cpp @@ -89,6 +89,10 @@ static ofbx::Matrix getBindPoseMatrix(const FBXImporter::ImportMesh* mesh, const if (!mesh) return node->getGlobalTransform(); if (!mesh->fbx) return makeOFBXIdentity(); + if (mesh->fbx->getPose()) { + return mesh->fbx->getPose()->getMatrix(); + } + auto* skin = mesh->fbx->getGeometry()->getSkin(); if (!skin) return node->getGlobalTransform(); @@ -945,36 +949,32 @@ static int getDepth(const ofbx::Object* bone) void FBXImporter::writeAnimations(const char* src, const ImportConfig& cfg) { PROFILE_FUNCTION(); - for (FBXImporter::ImportAnimation& anim : getAnimations()) { - StaticString anim_path(anim.name, ":", src); + for (const FBXImporter::ImportAnimation& anim : getAnimations()) { ASSERT(anim.import); const ofbx::AnimationStack* stack = anim.fbx; const ofbx::IScene& scene = *anim.scene; const ofbx::TakeInfo* take_info = scene.getTakeInfo(stack->name); + if(!take_info && startsWith(stack->name, "AnimStack::")) { + take_info = scene.getTakeInfo(stack->name + 11); + } float fbx_frame_rate = scene.getSceneFrameRate(); if (fbx_frame_rate < 0) fbx_frame_rate = 24; float scene_frame_rate = fbx_frame_rate / time_scale; float sampling_period = 1.0f / scene_frame_rate; int all_frames_count = 0; - if (take_info) - { + if (take_info) { all_frames_count = int((take_info->local_time_to - take_info->local_time_from) / sampling_period + 0.5f); } - else - { - ASSERT(false); - // TODO - // scene->GetGlobalSettings().GetTimelineDefaultTimeSpan(time_spawn); + else if(scene.getGlobalSettings()) { + all_frames_count = int(scene.getGlobalSettings()->TimeSpanStop / sampling_period + 0.5f); + } + else { + logError("Renderer") << "Unsupported animation in " << src; + continue; } - // TODO - /*FbxTime::EMode mode = scene->GetGlobalSettings().GetTimeMode(); - float scene_frame_rate = - (float)((mode == FbxTime::eCustom) ? scene->GetGlobalSettings().GetCustomFrameRate() - : FbxTime::GetFrameRate(mode)); - */ out_file.clear(); Animation::Header header; @@ -987,8 +987,7 @@ void FBXImporter::writeAnimations(const char* src, const ImportConfig& cfg) write(all_frames_count); int used_bone_count = 0; - for (const ofbx::Object* bone : bones) - { + for (const ofbx::Object* bone : bones) { if (&bone->getScene() != &scene) continue; const ofbx::AnimationLayer* layer = stack->getLayer(0); @@ -1000,8 +999,7 @@ void FBXImporter::writeAnimations(const char* src, const ImportConfig& cfg) write(used_bone_count); Array positions(allocator); Array rotations(allocator); - for (const ofbx::Object* bone : bones) - { + for (const ofbx::Object* bone : bones) { if (&bone->getScene() != &scene) continue; const ofbx::Object* root_bone = anim.root_motion_bone_idx >= 0 ? bones[anim.root_motion_bone_idx] : nullptr; @@ -1019,14 +1017,11 @@ void FBXImporter::writeAnimations(const char* src, const ImportConfig& cfg) write(positions.size()); for (TranslationKey& key : positions) write(key.frame); - for (TranslationKey& key : positions) - { - if (bone == root_bone) - { + for (TranslationKey& key : positions) { + if (bone == root_bone) { write(fixRootOrientation(key.pos * cfg.mesh_scale)); } - else - { + else { write(fixOrientation(key.pos * cfg.mesh_scale)); } } @@ -1035,19 +1030,17 @@ void FBXImporter::writeAnimations(const char* src, const ImportConfig& cfg) write(rotations.size()); for (RotationKey& key : rotations) write(key.frame); - for (RotationKey& key : rotations) - { - if (bone == root_bone) - { + for (RotationKey& key : rotations) { + if (bone == root_bone) { write(fixRootOrientation(key.rot)); } - else - { + else { write(fixOrientation(key.rot)); } } } + const StaticString anim_path(anim.name, ":", src); compiler.writeCompiledResource(anim_path, Span((u8*)out_file.getData(), (i32)out_file.getPos())); } } diff --git a/src/renderer/editor/ofbx.cpp b/src/renderer/editor/ofbx.cpp index 29974d075..e5f7d7717 100644 --- a/src/renderer/editor/ofbx.cpp +++ b/src/renderer/editor/ofbx.cpp @@ -1008,11 +1008,13 @@ struct MeshImpl : Mesh Type getType() const override { return Type::MESH; } + const Pose* getPose() const override { return pose; } const Geometry* getGeometry() const override { return geometry; } const Material* getMaterial(int index) const override { return materials[index]; } int getMaterialCount() const override { return (int)materials.size(); } + const Pose* pose = nullptr; const Geometry* geometry = nullptr; const Scene& scene; std::vector materials; @@ -1308,6 +1310,33 @@ Texture::Texture(const Scene& _scene, const IElement& _element) } +Pose::Pose(const Scene& _scene, const IElement& _element) + : Object(_scene, _element) +{ +} + + +struct PoseImpl : Pose +{ + PoseImpl(const Scene& _scene, const IElement& _element) + : Pose(_scene, _element) + { + } + + bool postprocess(Scene* scene); + + + Matrix getMatrix() const override { return matrix; } + const Object* getNode() const override { return node; } + + Type getType() const override { return Type::POSE; } + + Matrix matrix; + Object* node = nullptr; + DataView node_id; +}; + + struct TextureImpl : Texture { TextureImpl(const Scene& _scene, const IElement& _element) @@ -1428,6 +1457,16 @@ struct Scene : IScene }; +bool PoseImpl::postprocess(Scene* scene) +{ + node = scene->m_object_map[node_id.toU64()].object; + if (node && node->getType() == Object::Type::MESH) { + static_cast(node)->pose = this; + } + return true; +} + + struct AnimationCurveNodeImpl : AnimationCurveNode { AnimationCurveNodeImpl(const Scene& _scene, const IElement& _element) @@ -1557,6 +1596,23 @@ struct OptionalError parseTexture(const Scene& scene, const Element& el } +struct OptionalError parsePose(const Scene& scene, const Element& element) +{ + PoseImpl* pose = new PoseImpl(scene, element); + const Element* pose_node = findChild(element, "PoseNode"); + if (pose_node) { + const Element* node = findChild(*pose_node, "Node"); + const Element* matrix = findChild(*pose_node, "Matrix"); + + if (matrix->first_property) { + parseArrayRaw(*matrix->first_property, &pose->matrix, sizeof(pose->matrix)); + } + pose->node_id = node->first_property->value; + } + return pose; +} + + template static OptionalError parse(const Scene& scene, const Element& element) { @@ -2542,6 +2598,16 @@ static void parseGlobalSettings(const Element& root, Scene* scene) } \ } + #define get_time_property(name, field, type, getter) if(node->first_property->value == name) \ + { \ + ofbx::IElementProperty* prop = node->getProperty(4); \ + if (prop) \ + { \ + ofbx::DataView value = prop->getValue(); \ + scene->m_settings.field = fbxTimeToSeconds((type)value.getter()); \ + } \ + } + get_property("UpAxis", UpAxis, UpVector, toInt); get_property("UpAxisSign", UpAxisSign, int, toInt); get_property("FrontAxis", FrontAxis, FrontVector, toInt); @@ -2552,8 +2618,8 @@ static void parseGlobalSettings(const Element& root, Scene* scene) get_property("OriginalUpAxisSign", OriginalUpAxisSign, int, toInt); get_property("UnitScaleFactor", UnitScaleFactor, float, toDouble); get_property("OriginalUnitScaleFactor", OriginalUnitScaleFactor, float, toDouble); - get_property("TimeSpanStart", TimeSpanStart, u64, toU64); - get_property("TimeSpanStop", TimeSpanStop, u64, toU64); + get_time_property("TimeSpanStart", TimeSpanStart, u64, toU64); + get_time_property("TimeSpanStop", TimeSpanStop, u64, toU64); get_property("TimeMode", TimeMode, FrameRate, toInt); get_property("CustomFrameRate", CustomFrameRate, float, toDouble); @@ -2677,6 +2743,10 @@ static bool parseObjects(const Element& root, Scene* scene, u64 flags) { obj = parseTexture(*scene, *iter.second.element); } + else if (iter.second.element->id == "Pose") + { + obj = parsePose(*scene, *iter.second.element); + } if (obj.isError()) return false; @@ -2832,16 +2902,24 @@ static bool parseObjects(const Element& root, Scene* scene, u64 flags) } } - for (auto iter : scene->m_object_map) - { - Object* obj = iter.second.object; - if (!obj) continue; - if (obj->getType() == Object::Type::CLUSTER) + if (!ignore_geometry) { + for (auto iter : scene->m_object_map) { - if (!((ClusterImpl*)iter.second.object)->postprocess()) - { - Error::s_message = "Failed to postprocess cluster"; - return false; + Object* obj = iter.second.object; + if (!obj) continue; + switch (obj->getType()) { + case Object::Type::CLUSTER: + if (!((ClusterImpl*)iter.second.object)->postprocess()) { + Error::s_message = "Failed to postprocess cluster"; + return false; + } + break; + case Object::Type::POSE: + if (!((PoseImpl*)iter.second.object)->postprocess(scene)) { + Error::s_message = "Failed to postprocess pose"; + return false; + } + break; } } } @@ -2980,7 +3058,8 @@ Object* Object::resolveObjectLinkReverse(Object::Type type) const { if (connection.from == id && connection.to != 0) { - Object* obj = scene.m_object_map.find(connection.to)->second.object; + const Scene::ObjectPair& pair = scene.m_object_map.find(connection.to)->second; + Object* obj = pair.object; if (obj && obj->getType() == type) return obj; } } diff --git a/src/renderer/editor/ofbx.h b/src/renderer/editor/ofbx.h index af10e6ceb..ac63ba044 100644 --- a/src/renderer/editor/ofbx.h +++ b/src/renderer/editor/ofbx.h @@ -162,7 +162,8 @@ struct Object ANIMATION_STACK, ANIMATION_LAYER, ANIMATION_CURVE, - ANIMATION_CURVE_NODE + ANIMATION_CURVE_NODE, + POSE }; Object(const Scene& _scene, const IElement& _element); @@ -209,6 +210,15 @@ protected: }; +struct Pose : Object { + static const Type s_type = Type::POSE; + Pose(const Scene& _scene, const IElement& _element); + + virtual Matrix getMatrix() const = 0; + virtual const Object* getNode() const = 0; +}; + + struct Texture : Object { enum TextureType @@ -305,6 +315,7 @@ struct Mesh : Object Mesh(const Scene& _scene, const IElement& _element); + virtual const Pose* getPose() const = 0; virtual const Geometry* getGeometry() const = 0; virtual Matrix getGeometricMatrix() const = 0; virtual const Material* getMaterial(int idx) const = 0; @@ -424,8 +435,8 @@ struct GlobalSettings int OriginalUpAxisSign = 1; float UnitScaleFactor = 1; float OriginalUnitScaleFactor = 1; - u64 TimeSpanStart = 0L; - u64 TimeSpanStop = 0L; + double TimeSpanStart = 0L; + double TimeSpanStop = 0L; FrameRate TimeMode = FrameRate_DEFAULT; float CustomFrameRate = -1.0f; }; diff --git a/src/renderer/ffr/ffr.cpp b/src/renderer/ffr/ffr.cpp index 7e2ea0fd8..c3c174c3e 100644 --- a/src/renderer/ffr/ffr.cpp +++ b/src/renderer/ffr/ffr.cpp @@ -1889,55 +1889,6 @@ void pushDebugGroup(const char* msg) CHECK_GL(glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, -1, msg)); } -// TODO -/* -void bindLayer(FramebufferHandle fb, TextureHandle rb, u32 layer) -{ - checkThread(); - - int color_attachment_idx = 0; - bool depth_bound = false; - const GLuint t = g_ffr.textures[rb.value].handle; - CHECK_GL(glBindTexture(GL_TEXTURE_2D_ARRAY, t)); - GLint internal_format; - CHECK_GL(glGetTexLevelParameteriv(GL_TEXTURE_2D_ARRAY, 0, GL_TEXTURE_INTERNAL_FORMAT, &internal_format)); - - CHECK_GL(glBindTexture(GL_TEXTURE_2D_ARRAY, 0)); - switch(internal_format) { - case GL_DEPTH24_STENCIL8: - CHECK_GL(glNamedFramebufferRenderbuffer(fb.value, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0)); - CHECK_GL(glNamedFramebufferTextureLayer(fb.value, GL_DEPTH_STENCIL_ATTACHMENT, t, 0, layer)); - depth_bound = true; - break; - case GL_DEPTH_COMPONENT24: - case GL_DEPTH_COMPONENT32: - CHECK_GL(glNamedFramebufferRenderbuffer(fb.value, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0)); - CHECK_GL(glNamedFramebufferTextureLayer(fb.value, GL_DEPTH_ATTACHMENT, t, 0, layer)); - depth_bound = true; - break; - default: - CHECK_GL(glNamedFramebufferTextureLayer(fb.value, GL_COLOR_ATTACHMENT0 + color_attachment_idx, t, 0, layer)); - ++color_attachment_idx; - break; - } - - GLint max_attachments = 0; - glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &max_attachments); - for(int i = color_attachment_idx; i < max_attachments; ++i) { - glNamedFramebufferRenderbuffer(fb.value, GL_COLOR_ATTACHMENT0 + i, GL_RENDERBUFFER, 0); - } - - if (!depth_bound) { - glNamedFramebufferRenderbuffer(fb.value, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0); - glNamedFramebufferRenderbuffer(fb.value, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0); - } - - glBindFramebuffer(GL_FRAMEBUFFER, fb.value); - auto xx = glCheckFramebufferStatus(GL_FRAMEBUFFER); - ASSERT(xx == GL_FRAMEBUFFER_COMPLETE); - glBindFramebuffer(GL_FRAMEBUFFER, 0); -}*/ - QueryHandle createQuery() { diff --git a/src/renderer/model.cpp b/src/renderer/model.cpp index 458232f48..bf346d0ef 100644 --- a/src/renderer/model.cpp +++ b/src/renderer/model.cpp @@ -46,7 +46,6 @@ Mesh::Mesh(Material* mat, , material(mat) , indices(allocator) , vertices(allocator) - , uvs(allocator) , skin(allocator) { render_data = LUMIX_NEW(renderer.getAllocator(), RenderData); @@ -290,6 +289,7 @@ static u8 getIndexBySemantic(Mesh::AttributeSemantic semantic) { case Mesh::AttributeSemantic::TANGENT: return 3; case Mesh::AttributeSemantic::INDICES: return 4; case Mesh::AttributeSemantic::WEIGHTS: return 5; + case Mesh::AttributeSemantic::COLOR0: return 6; } ASSERT(false); return 0; @@ -515,7 +515,6 @@ bool Model::parseMeshes(InputMemoryStream& file, FileVersion version) file.read(&mesh.indices[0], mesh.indices.size()); if (index_size == 2) mesh.flags.set(Mesh::Flags::INDICES_16_BIT); - // TODO do not copy, allocate in advance const Renderer::MemRef mem = m_renderer.copy(&mesh.indices[0], mesh.indices.size()); mesh.render_data->index_buffer_handle = m_renderer.createBuffer(mem, (u32)ffr::BufferFlags::DYNAMIC_STORAGE); mesh.render_data->index_type = index_size == 2 ? ffr::DataType::U16 : ffr::DataType::U32; @@ -526,22 +525,19 @@ bool Model::parseMeshes(InputMemoryStream& file, FileVersion version) Mesh& mesh = m_meshes[i]; int data_size; file.read(data_size); - Array vertices_mem(m_allocator); - vertices_mem.resize(data_size); - file.read(&vertices_mem[0], data_size); + Renderer::MemRef vertices_mem = m_renderer.allocate(data_size); + file.read(vertices_mem.data, data_size); int position_attribute_offset = getAttributeOffset(mesh, Mesh::AttributeSemantic::POSITION); - int uv_attribute_offset = getAttributeOffset(mesh, Mesh::AttributeSemantic::TEXCOORD0); int weights_attribute_offset = getAttributeOffset(mesh, Mesh::AttributeSemantic::WEIGHTS); int bone_indices_attribute_offset = getAttributeOffset(mesh, Mesh::AttributeSemantic::INDICES); bool keep_skin = hasAttribute(mesh, Mesh::AttributeSemantic::WEIGHTS) && hasAttribute(mesh, Mesh::AttributeSemantic::INDICES); int vertex_size = mesh.render_data->vb_stride; - int mesh_vertex_count = vertices_mem.size() / vertex_size; + int mesh_vertex_count = data_size / vertex_size; mesh.vertices.resize(mesh_vertex_count); - mesh.uvs.resize(mesh_vertex_count); if (keep_skin) mesh.skin.resize(mesh_vertex_count); - const u8* vertices = &vertices_mem[0]; + const u8* vertices = (const u8*)vertices_mem.data; for (int j = 0; j < mesh_vertex_count; ++j) { int offset = j * vertex_size; @@ -553,11 +549,8 @@ bool Model::parseMeshes(InputMemoryStream& file, FileVersion version) sizeof(mesh.skin[j].indices)); } mesh.vertices[j] = *(const Vec3*)&vertices[offset + position_attribute_offset]; - mesh.uvs[j] = *(const Vec2*)&vertices[offset + uv_attribute_offset]; } - // TODO do not copy, allocate in advance - const Renderer::MemRef mem = m_renderer.copy(&vertices_mem[0], vertices_mem.size()); - mesh.render_data->vertex_buffer_handle = m_renderer.createBuffer(mem, (u32)ffr::BufferFlags::DYNAMIC_STORAGE); + mesh.render_data->vertex_buffer_handle = m_renderer.createBuffer(vertices_mem, (u32)ffr::BufferFlags::DYNAMIC_STORAGE); } file.read(m_bounding_radius); file.read(m_aabb); diff --git a/src/renderer/model.h b/src/renderer/model.h index a4fe742c1..d85d9861e 100644 --- a/src/renderer/model.h +++ b/src/renderer/model.h @@ -108,7 +108,6 @@ struct LUMIX_RENDERER_API Mesh Type type; Array indices; Array vertices; - Array uvs; Array skin; FlagSet flags; u32 sort_key; diff --git a/src/renderer/pipeline.cpp b/src/renderer/pipeline.cpp index b946bdcad..e26973410 100644 --- a/src/renderer/pipeline.cpp +++ b/src/renderer/pipeline.cpp @@ -2332,12 +2332,6 @@ struct PipelineImpl final : Pipeline const u8 edge_define_idx = m_pipeline->m_renderer.getShaderDefineIdx("EDGE"); u64 state = m_render_state; - static bool b = false; // TODO - if (b) state |= (u64)ffr::StateFlags::WIREFRAME; - - static int stat; - stat = 0; - for (Instance& inst : m_instances) { const ffr::ProgramHandle p = Shader::getProgram(inst.shader, ffr::VertexDecl(), deferred_define_mask); if (!p.isValid()) continue; @@ -2382,7 +2376,6 @@ struct PipelineImpl final : Pipeline dc_data.lod = i; ffr::update(m_pipeline->m_drawcall_ub, &dc_data, 0, sizeof(dc_data)); ffr::drawArrays(0, (subto.x - subfrom.x) * (subto.y - subfrom.y), ffr::PrimitiveType::POINTS); - stat += (subto.x - subfrom.x) * (subto.y - subfrom.y); }; if (i > 0) { @@ -3135,7 +3128,80 @@ struct PipelineImpl final : Pipeline lua_pop(m_lua_state, 1); } - + + void saveRenderbuffer(int render_buffer, const char* out_path) + { + struct Cmd : Renderer::RenderJob { + Cmd(IAllocator& allocator) : allocator(allocator) {} + void setup() override {} + void execute() override { + PROFILE_FUNCTION(); + Array pixels(allocator); + pixels.resize(w * h); + ffr::getTextureImage(handle, pixels.byte_size(), pixels.begin()); + + OS::OutputFile file; + if (fs->open(path, Ref(file))) { + Texture::saveTGA(&file, w, h, 4, (u8*)pixels.begin(), Path(path), allocator); + file.close(); + } + else { + logError("Renderer") << "Failed to save " << path; + } + } + + IAllocator& allocator; + u32 w, h; + ffr::TextureHandle handle; + FileSystem* fs; + StaticString path; + }; + + Cmd* cmd = LUMIX_NEW(m_renderer.getAllocator(), Cmd)(m_renderer.getAllocator()); + cmd->handle = m_renderbuffers[render_buffer].handle; + cmd->w = m_viewport.w; + cmd->h = m_viewport.h; + cmd->path = out_path; + cmd->fs = &m_renderer.getEngine().getFileSystem(); + m_renderer.queue(cmd, m_profiler_link); + + + + /*FrameBuffer* fb = getFramebuffer(framebuffer); + if (!fb) + { + g_log_error.log("Renderer") << "saveRenderbuffer: Framebuffer " << framebuffer << " not found."; + return; + } + + bgfx::TextureHandle texture = bgfx::createTexture2D( + fb->getWidth(), fb->getHeight(), false, 1, bgfx::TextureFormat::RGBA8, BGFX_TEXTURE_READ_BACK); + m_renderer.viewCounterAdd(); + bgfx::touch(m_renderer.getViewCounter()); + bgfx::setViewName(m_renderer.getViewCounter(), "saveRenderbuffer_blit"); + bgfx::TextureHandle rb = fb->getRenderbufferHandle(render_buffer_index); + bgfx::blit(m_renderer.getViewCounter(), texture, 0, 0, rb); + + m_renderer.viewCounterAdd(); + bgfx::setViewName(m_renderer.getViewCounter(), "saveRenderbuffer_read"); + Array data(m_renderer.getEngine().getAllocator()); + data.resize(fb->getWidth() * fb->getHeight() * 4); + bgfx::readTexture(texture, &data[0]); + bgfx::touch(m_renderer.getViewCounter()); + + bgfx::frame(); // submit + bgfx::frame(); // wait for gpu + + FS::FileSystem& fs = m_renderer.getEngine().getFileSystem(); + FS::IFile* file = fs.open(fs.getDefaultDevice(), Path(out_path), FS::Mode::CREATE_AND_WRITE); + Texture::saveTGA(file, fb->getWidth(), fb->getHeight(), 4, &data[0], Path(out_path), m_renderer.getEngine().getAllocator()); + + fs.close(*file); + + bgfx::destroy(texture);*/ + } + + void registerLuaAPI(lua_State* L) { lua_rawgeti(m_lua_state, LUA_REGISTRYINDEX, m_lua_env); @@ -3169,6 +3235,7 @@ struct PipelineImpl final : Pipeline REGISTER_FUNCTION(renderDebugShapes); REGISTER_FUNCTION(renderLocalLights); REGISTER_FUNCTION(renderTextMeshes); + REGISTER_FUNCTION(saveRenderbuffer); REGISTER_FUNCTION(setOutput); REGISTER_FUNCTION(viewport); diff --git a/src/renderer/texture.cpp b/src/renderer/texture.cpp index 55272143a..c9c95dcb9 100644 --- a/src/renderer/texture.cpp +++ b/src/renderer/texture.cpp @@ -203,7 +203,7 @@ bool Texture::saveTGA(IOutputStream* file, header.height = (short)height; header.width = (short)width; header.dataType = 2; - header.imageDescriptor = 32; + header.imageDescriptor = 0; file->write(&header, sizeof(header));