ingame gui; fullscreen; 4K screenshot; cleanup

This commit is contained in:
Mikulas Florek 2019-08-14 18:04:02 +02:00
parent 9bd32bd6bb
commit 32d4529c55
15 changed files with 285 additions and 149 deletions

View file

@ -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

View file

@ -798,10 +798,7 @@ void AssetBrowser::endSaveResource(Resource& resource, OutputMemoryStream& strea
}
}
// TODO selected_path_hash == null is bad UX
bool AssetBrowser::resourceList(Span<char> buf, Ref<u32> selected_path_hash, ResourceType type, float height, bool can_create_new) const
{
bool AssetBrowser::resourceList(Span<char> buf, Ref<u32> 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<char> buf, Ref<u32> selected_path_hash, Res
const HashMap<u32, AssetCompiler::ResourceItem>& 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<char> buf, Ref<u32> selected_path_hash, Res
if(selected) selected_path = res.path;
ResourceLocator rl(res.path.c_str());
StaticString<MAX_PATH_LENGTH> 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)) {

View file

@ -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";

View file

@ -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<Action*> m_actions;
Array<Action*> m_window_actions;
Array<Action*> m_toolbar_actions;

View file

@ -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();

View file

@ -4,7 +4,6 @@
#include "engine/path_utils.h"
#include "engine/string.h"
#define UNICODE
#include <cASSERT>
#pragma warning(push)
#pragma warning(disable : 4091)
#include <ShlObj.h>
@ -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)
{

View file

@ -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;
}

View file

@ -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<MAX_PATH_LENGTH> 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<TranslationKey> positions(allocator);
Array<RotationKey> 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<MAX_PATH_LENGTH> anim_path(anim.name, ":", src);
compiler.writeCompiledResource(anim_path, Span((u8*)out_file.getData(), (i32)out_file.getPos()));
}
}

View file

@ -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<const Material*> 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<MeshImpl*>(node)->pose = this;
}
return true;
}
struct AnimationCurveNodeImpl : AnimationCurveNode
{
AnimationCurveNodeImpl(const Scene& _scene, const IElement& _element)
@ -1557,6 +1596,23 @@ struct OptionalError<Object*> parseTexture(const Scene& scene, const Element& el
}
struct OptionalError<Object*> 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 <typename T>
static OptionalError<Object*> 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;
}
}

View file

@ -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;
};

View file

@ -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()
{

View file

@ -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<u8> 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);

View file

@ -108,7 +108,6 @@ struct LUMIX_RENDERER_API Mesh
Type type;
Array<u8> indices;
Array<Vec3> vertices;
Array<Vec2> uvs;
Array<Skin> skin;
FlagSet<Flags, u8> flags;
u32 sort_key;

View file

@ -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<u32> 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<MAX_PATH_LENGTH> 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<u8> 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);

View file

@ -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));