Skip to content

Commit

Permalink
Add Preview.Duplicate and Preview.SelectAll shortcuts and functions
Browse files Browse the repository at this point in the history
  • Loading branch information
dfranx committed Jul 14, 2019
1 parent b70e309 commit 4c06807
Show file tree
Hide file tree
Showing 9 changed files with 200 additions and 24 deletions.
34 changes: 18 additions & 16 deletions CHANGELOG.txt
Original file line number Diff line number Diff line change
@@ -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
Expand Down
30 changes: 28 additions & 2 deletions Objects/PipelineManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions Objects/PipelineManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<PipelineItem*>& GetList() { return m_items; }

void New(bool openTemplate = true);
Expand Down
7 changes: 3 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

<img src="./Screenshots/IMG2.png"/>
**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.
<img src="./Screenshots/IMG2.png"/>

## Features

Expand Down Expand Up @@ -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


Expand Down
145 changes: 145 additions & 0 deletions UI/PreviewUI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "../Objects/DefaultState.h"
#include "../Objects/SystemVariableManager.h"
#include "../Objects/KeyboardShortcuts.h"
#include <MoonLight/Base/GeometryFactory.h>
#include <imgui/imgui_internal.h>

#define STATUSBAR_HEIGHT 25 * Settings::Instance().DPIScale
Expand Down Expand Up @@ -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<PipelineItem*>& 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();
Expand Down Expand Up @@ -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<PipelineItem*> 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()
{
Expand Down
1 change: 1 addition & 0 deletions UI/PreviewUI.h
Original file line number Diff line number Diff line change
Expand Up @@ -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; }

Expand Down
2 changes: 1 addition & 1 deletion data/settings.ini
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions data/shortcuts.kb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion data/workspace.dat
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ Collapsed=0
DockId=0x00000001,0

[Window][Options]
Pos=493,88
Pos=493,19
Size=979,647
Collapsed=0

Expand Down

0 comments on commit 4c06807

Please sign in to comment.