ingame gui; fullscreen; 4K screenshot; cleanup
This commit is contained in:
parent
9bd32bd6bb
commit
32d4529c55
15 changed files with 285 additions and 149 deletions
|
@ -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
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
Loading…
Reference in a new issue