From 4c06807f8607ee40984aab76fcb5651aa175b63f Mon Sep 17 00:00:00 2001 From: dfranx <30801537+dfranx@users.noreply.github.com> Date: Sun, 14 Jul 2019 18:36:31 +0200 Subject: [PATCH] Add Preview.Duplicate and Preview.SelectAll shortcuts and functions --- CHANGELOG.txt | 34 +++++---- Objects/PipelineManager.cpp | 30 +++++++- Objects/PipelineManager.h | 1 + README.md | 7 +- UI/PreviewUI.cpp | 145 ++++++++++++++++++++++++++++++++++++ UI/PreviewUI.h | 1 + data/settings.ini | 2 +- data/shortcuts.kb | 2 + data/workspace.dat | 2 +- 9 files changed, 200 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index ac81cbb1..4396f29b 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,24 +1,26 @@ +[v1.1.0] +... working on OpenGL port ... + [v1.0.3] ++ add ability to duplicate selected items ++ add shift+click to select multiple items ++ add bounding box ++ add option to open shaders in an external text editor ++ add a more flexible GLSL file extension system + add mute button for audio files -+ add DPI scale text in the options -+ add wrapped text in popup windows -+ add minor changes to UI design in Options -+ add CTRL+click shortcut to delete the shortcut in the options -+ fix an error that occurs when loading audio file on a PC with no audio output device -+ add a more flexible GLSL extension system -+ add "collapsed" attribute to shader passes in the project file + add context menu in ObjectListUI and PipelineUI -+ fix item picking -+ fix gizmo (different model for scale and rotation transforms, change color on hover, etc...) -+ show degrees (rather than radians) in PropertyUI for OBJModel and Geometry ++ add "collapsed" attribute to shader passes in the project file + add a wheel UI when rotating an object using GizmoObject + add option to snap transformations with gizmo -+ add bounding box -+ add shift+click to select multiple items -+ add "Double click on an item selects it" option -+ add "Double click on an item opens it in properties window" option -+ add option to open shaders in an external text editor -... ++ add minor changes to UI design in Options ++ add CTRL+click shortcut to delete the shortcut in the options ++ add DPI scale text in the options ++ add wrapped text in popup windows ++ show degrees (rather than radians) in PropertyUI for OBJModel and Geometry ++ fix gizmo (different model for scale and rotation transforms, change color on hover, etc...) ++ fix item picking ++ fix an error that occurs when loading audio file on a PC with no audio output device ++ fix PipelineManager::Has -> it was possible to have two or more items with the same name [v1.0.2] + add ability to load audio files diff --git a/Objects/PipelineManager.cpp b/Objects/PipelineManager.cpp index 27b7a6e7..45369f26 100644 --- a/Objects/PipelineManager.cpp +++ b/Objects/PipelineManager.cpp @@ -92,16 +92,42 @@ namespace ed } bool PipelineManager::Has(const char * name) { - for (int i = 0; i < m_items.size(); i++) + for (int i = 0; i < m_items.size(); i++) { if (strcmp(m_items[i]->Name, name) == 0) return true; + else { + pipe::ShaderPass* data = (pipe::ShaderPass*)m_items[i]->Data; + for (int j = 0; j < data->Items.size(); j++) + if (strcmp(data->Items[j]->Name, name) == 0) + return true; + } + } return false; } + char* PipelineManager::GetItemOwner(const char* name) + { + for (int i = 0; i < m_items.size(); i++) { + pipe::ShaderPass* data = (pipe::ShaderPass*)m_items[i]->Data; + for (int j = 0; j < data->Items.size(); j++) { + if (strcmp(data->Items[j]->Name, name) == 0) { + return m_items[i]->Name; + } + } + } + return nullptr; + } PipelineItem* PipelineManager::Get(const char* name) { - for (int i = 0; i < m_items.size(); i++) + for (int i = 0; i < m_items.size(); i++) { if (strcmp(m_items[i]->Name, name) == 0) return m_items[i]; + else { + pipe::ShaderPass* data = (pipe::ShaderPass*)m_items[i]->Data; + for (int j = 0; j < data->Items.size(); j++) + if (strcmp(data->Items[j]->Name, name) == 0) + return data->Items[j]; + } + } return nullptr; } void PipelineManager::New(bool openTemplate) diff --git a/Objects/PipelineManager.h b/Objects/PipelineManager.h index 35ad6989..13bf20bb 100644 --- a/Objects/PipelineManager.h +++ b/Objects/PipelineManager.h @@ -21,6 +21,7 @@ namespace ed void Remove(const char* name); bool Has(const char* name); PipelineItem* Get(const char* name); + char* GetItemOwner(const char* name); inline std::vector& GetList() { return m_items; } void New(bool openTemplate = true); diff --git a/README.md b/README.md index 72ec1665..3444c3cb 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,10 @@ SHADERed is a lightweight tool for creating and testing **HLSL and GLSL shaders* open source and frequently updated with new features. It has many **features** that the competition is lacking. - +**NOTE**: There will be a lack of commits on this repo in the next couple of weeks - I am working on +an OpenGL port. -**NOTE**: SHADERed has a built-in text editor but I would suggest using some external text editor -as currently the one that is built-in is slow, buggy and doesn't have some basic features. + ## Features @@ -164,7 +164,6 @@ There are also some features that I am looking to implement: - support #include and macros - buffers read from file or built using in-app buffer editor - magnifier tool & pixel inspector - - duplicate objects - text geometry diff --git a/UI/PreviewUI.cpp b/UI/PreviewUI.cpp index 56d37436..96734eb7 100644 --- a/UI/PreviewUI.cpp +++ b/UI/PreviewUI.cpp @@ -5,6 +5,7 @@ #include "../Objects/DefaultState.h" #include "../Objects/SystemVariableManager.h" #include "../Objects/KeyboardShortcuts.h" +#include #include #define STATUSBAR_HEIGHT 25 * Settings::Instance().DPIScale @@ -152,6 +153,24 @@ namespace ed KeyboardShortcuts::Instance().SetCallback("Preview.Unselect", [=]() { m_picks.clear(); }); + KeyboardShortcuts::Instance().SetCallback("Preview.Duplicate", [=]() { + Duplicate(); + }); + KeyboardShortcuts::Instance().SetCallback("Preview.SelectAll", [=]() { + // clear the list + Pick(nullptr); + + // select all geometry and mesh items + std::vector& pass = m_data->Pipeline.GetList(); + for (int i = 0; i < pass.size(); i++) { + ed::pipe::ShaderPass* pdata = (ed::pipe::ShaderPass*)pass[i]->Data; + for (int j = 0; j < pdata->Items.size(); j++) { + if (pdata->Items[j]->Type == PipelineItem::ItemType::Geometry || + pdata->Items[j]->Type == PipelineItem::ItemType::OBJModel) + Pick(pdata->Items[j], true); + } + } + }); } void PreviewUI::m_setupBoundingBox() { ml::Window* wnd = m_data->GetOwner(); @@ -541,6 +560,132 @@ namespace ed } } } + void PreviewUI::Duplicate() + { + if (m_picks.size() == 0) + return; + + // store pointers to these objects as we will select them after duplication + std::vector duplicated; + + // duplicate each item + for (int i = 0; i < m_picks.size(); i++) { + ed::PipelineItem* item = m_picks[i]; + + // first find a name that is not used + std::string name = std::string(item->Name); + + // remove numbers at the end of the string + size_t lastOfLetter = std::string::npos; + for (size_t j = name.size()-1; j > 0; j--) + if (!std::isdigit(name[j])) { + lastOfLetter = j + 1; + break; + } + if (lastOfLetter != std::string::npos) + name = name.substr(0, lastOfLetter); + + // add number to the string and check if it already exists + for (size_t j = 2; /*WE WILL BRAKE FROM INSIDE ONCE WE FIND THE NAME*/;j++) { + std::string newName = name + std::to_string(j); + bool has = m_data->Pipeline.Has(newName.c_str()); + + if (!has) { + name = newName; + break; + } + } + + // get item owner + char* owner = m_data->Pipeline.GetItemOwner(item->Name); + + // once we found a name, duplicate the properties: + // duplicate geometry object: + if (item->Type == PipelineItem::ItemType::Geometry) { + pipe::GeometryItem* data = new pipe::GeometryItem(); + pipe::GeometryItem* origData = (pipe::GeometryItem*)item->Data; + + data->Position = origData->Position; + data->Rotation = origData->Rotation; + data->Scale = origData->Scale; + data->Size = origData->Size; + data->Topology = origData->Topology; + data->Type = origData->Type; + + if (data->Type == pipe::GeometryItem::GeometryType::Cube) + data->Geometry = ml::GeometryFactory::CreateCube(data->Size.x, data->Size.y, data->Size.z, *m_data->GetOwner()); + else if (data->Type == pipe::GeometryItem::Circle) { + data->Geometry = ml::GeometryFactory::CreateCircle(0, 0, data->Size.x, data->Size.y, *m_data->GetOwner()); + data->Topology = ml::Topology::TriangleStrip; + } + else if (data->Type == pipe::GeometryItem::Plane) + data->Geometry = ml::GeometryFactory::CreatePlane(data->Size.x, data->Size.y, *m_data->GetOwner()); + else if (data->Type == pipe::GeometryItem::Rectangle) + data->Geometry = ml::GeometryFactory::CreatePlane(1, 1, *m_data->GetOwner()); + else if (data->Type == pipe::GeometryItem::Sphere) + data->Geometry = ml::GeometryFactory::CreateSphere(data->Size.x, *m_data->GetOwner()); + else if (data->Type == pipe::GeometryItem::Triangle) + data->Geometry = ml::GeometryFactory::CreateTriangle(0, 0, data->Size.x, *m_data->GetOwner()); + + m_data->Pipeline.AddItem(owner, name.c_str(), item->Type, data); + } + + // duplicate OBJModel: + else if (item->Type == PipelineItem::ItemType::OBJModel) { + pipe::OBJModel* data = new pipe::OBJModel(); + pipe::OBJModel* origData = (pipe::OBJModel*)item->Data; + + strcpy(data->Filename, origData->Filename); + strcpy(data->GroupName, origData->GroupName); + data->OnlyGroup = origData->OnlyGroup; + data->Scale = origData->Scale; + data->Position = origData->Position; + data->Rotation = origData->Rotation; + + + if (strlen(data->Filename) > 0) { + std::string objMem = m_data->Parser.LoadProjectFile(data->Filename); + ml::OBJModel* mdl = m_data->Parser.LoadModel(data->Filename); + + bool loaded = mdl != nullptr; + if (loaded) + data->Mesh = *mdl; + else m_data->Messages.Add(ed::MessageStack::Type::Error, owner, "Failed to create .obj model " + std::string(item->Name)); + + // TODO: if (!loaded) error "Failed to load a mesh" + + if (loaded) { + ml::OBJModel::Vertex* verts = data->Mesh.GetVertexData(); + ml::UInt32 vertCount = data->Mesh.GetVertexCount(); + + if (data->OnlyGroup) { + verts = data->Mesh.GetGroupVertices(data->GroupName); + vertCount = data->Mesh.GetGroupVertexCount(data->GroupName); + + if (verts == nullptr) { + verts = data->Mesh.GetObjectVertices(data->GroupName); + vertCount = data->Mesh.GetObjectVertexCount(data->GroupName); + + // TODO: if (verts == nullptr) error "failed to find a group with that name" + } + } + + data->VertCount = vertCount; + data->Vertices.Create(*m_data->GetOwner(), verts, vertCount, ml::Resource::Immutable); + } + // TODO: else error "failed to load" + } + + m_data->Pipeline.AddItem(owner, name.c_str(), item->Type, data); + } + + + duplicated.push_back(m_data->Pipeline.Get(name.c_str())); + } + + // select the newly created items + m_picks = duplicated; + } void PreviewUI::m_buildBoundingBox() { diff --git a/UI/PreviewUI.h b/UI/PreviewUI.h index 5415d058..3434d417 100644 --- a/UI/PreviewUI.h +++ b/UI/PreviewUI.h @@ -28,6 +28,7 @@ namespace ed virtual void OnEvent(const ml::Event& e); virtual void Update(float delta); + void Duplicate(); void Pick(PipelineItem* item, bool add = false); inline bool IsPicked(PipelineItem* item) { return std::count(m_picks.begin(), m_picks.end(), item) > 0; } diff --git a/data/settings.ini b/data/settings.ini index 3822ed38..d3d51ed1 100644 --- a/data/settings.ini +++ b/data/settings.ini @@ -21,7 +21,7 @@ glslext=glsl vert frag geom vs px [preview] fxaa=0 switchleftrightclick=0 -boundingbox=0 +boundingbox=1 gizmo=1 gizmorotaui=1 gizmosnaptrans=0 diff --git a/data/shortcuts.kb b/data/shortcuts.kb index 1e165754..9195b9ca 100644 --- a/data/shortcuts.kb +++ b/data/shortcuts.kb @@ -24,7 +24,9 @@ Gizmo.Position CTRL G P Gizmo.Rotation CTRL G R Gizmo.Scale CTRL G S Preview.Delete CTRL DELETE +Preview.Duplicate SHIFT D Preview.SaveImage CTRL R +Preview.SelectAll SHIFT A Preview.ToggleStatusbar CTRL ALT F3 Preview.Unselect CTRL SHIFT DELETE Project.New CTRL N N diff --git a/data/workspace.dat b/data/workspace.dat index 149c4816..c96794d8 100644 --- a/data/workspace.dat +++ b/data/workspace.dat @@ -57,7 +57,7 @@ Collapsed=0 DockId=0x00000001,0 [Window][Options] -Pos=493,88 +Pos=493,19 Size=979,647 Collapsed=0