Skip to content

Commit 7fffebd

Browse files
authored
Merge pull request #3 from Hopson97/feature/select-multiple-copy-paste
* Adds shift + right click to select multiple objects * Adds copy paste * Adds ability to move multiple objects * Adds zoom in/out for 2d view * Adds area selection, to select a large group of objects across multiple floors to be moved/ copy pasted * Adds 3d mouse picking * Makes moving objects around more efficient * General code improvements and refactoring
2 parents 790455d + 65ad38b commit 7fffebd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1794
-512
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#version 460
2+
3+
// The picker texture is just a single channel (red, GL_R32I) texture.
4+
// When the 3d view is right-clicked, each object's ID is written to the texture channel such that
5+
// the object ID can read-back via glReadPixels
6+
layout(location = 0) out int out_colour;
7+
8+
uniform int object_id;
9+
10+
void main() {
11+
out_colour = object_id;
12+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#version 450 core
2+
3+
layout(location = 0) in vec3 in_position;
4+
5+
layout(std430, binding = 0) readonly buffer Matrices
6+
{
7+
mat4 projection;
8+
mat4 view;
9+
} matrices;
10+
11+
void main()
12+
{
13+
gl_Position = matrices.projection * matrices.view * vec4(in_position, 1.0);
14+
}

classic-you.vcxproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,10 @@
157157
<ClCompile Include="deps\imgui_sfml\imgui_impl_opengl3.cpp" />
158158
<ClCompile Include="src\Editor\Actions.cpp" />
159159
<ClCompile Include="src\Editor\DrawingPad.cpp" />
160+
<ClCompile Include="src\Editor\EditorEventHandlers.cpp" />
160161
<ClCompile Include="src\Editor\EditorGUI.cpp" />
161162
<ClCompile Include="src\Editor\EditorLevel.cpp" />
163+
<ClCompile Include="src\Editor\EditorState.cpp" />
162164
<ClCompile Include="src\Editor\FloorManager.cpp" />
163165
<ClCompile Include="src\Editor\InfiniteGrid.cpp" />
164166
<ClCompile Include="src\Editor\LegacyFileConverter.cpp" />
@@ -230,6 +232,7 @@
230232
<ClInclude Include="src\Editor\Actions.h" />
231233
<ClInclude Include="src\Editor\DrawingPad.h" />
232234
<ClInclude Include="src\Editor\EditConstants.h" />
235+
<ClInclude Include="src\Editor\EditorEventHandlers.h" />
233236
<ClInclude Include="src\Editor\EditorGUI.h" />
234237
<ClInclude Include="src\Editor\EditorLevel.h" />
235238
<ClInclude Include="src\Editor\EditorState.h" />

imgui.ini

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Pos=1701,201
1616
Size=163,126
1717

1818
[Window][Camera]
19-
Pos=1450,864
19+
Pos=748,762
2020
Size=463,212
2121

2222
[Window][Shadow map preview]
@@ -92,16 +92,16 @@ IsChild=1
9292
Size=200,100
9393

9494
[Window][Editor]
95-
Pos=2,21
96-
Size=277,265
95+
Pos=33,530
96+
Size=289,373
9797

9898
[Window][Floor]
9999
Pos=5,27
100100
Size=254,347
101101

102102
[Window][Object Properties]
103-
Pos=1622,24
104-
Size=297,590
103+
Pos=1663,302
104+
Size=312,620
105105

106106
[Window][3d]
107107
Pos=60,60
@@ -111,3 +111,15 @@ Size=346,134
111111
Pos=251,430
112112
Size=177,65
113113

114+
[Window][Selection Options]
115+
Pos=1297,106
116+
Size=566,102
117+
118+
[Window][My Popup]
119+
Pos=938,516
120+
Size=79,70
121+
122+
[Window][picker bffer]
123+
Pos=1384,204
124+
Size=563,379
125+

src/Editor/Actions.cpp

Lines changed: 142 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ void ActionManager::clear()
9393
action_stack_.clear();
9494
}
9595

96+
// =======================================
97+
// AddObjectAction
98+
// =======================================
9699
AddObjectAction::AddObjectAction(const LevelObject& object, int floor)
97100
: object_(object)
98101
, floor_{floor}
@@ -101,28 +104,26 @@ AddObjectAction::AddObjectAction(const LevelObject& object, int floor)
101104

102105
void AddObjectAction::execute(EditorState& state, EditorLevel& level)
103106
{
104-
105107
// When redoing the action, this prevents using the default for this object type
106108
if (!executed_)
107109
{
108-
109110
auto& level_object = level.add_object(object_, floor_);
110111
id_ = level_object.object_id;
111112

112113
executed_ = true;
113-
state.p_active_object = &level_object;
114+
state.selection.set_selection(&level_object);
114115
}
115116
else
116117
{
117118
auto& level_object = level.add_object(object_, floor_);
118119
level.set_object_id(level_object.object_id, id_);
119-
state.p_active_object = &level_object;
120+
state.selection.set_selection(&level_object);
120121
}
121122
}
122123

123124
void AddObjectAction::undo(EditorState& state, EditorLevel& level)
124125
{
125-
state.p_active_object = nullptr;
126+
state.selection.clear_selection();
126127
level.remove_object(id_);
127128
}
128129

@@ -134,6 +135,71 @@ ActionStrings AddObjectAction::to_string() const
134135
};
135136
}
136137

138+
// =======================================
139+
// AddBulkObjectsAction
140+
// =======================================
141+
AddBulkObjectsAction::AddBulkObjectsAction(const std::vector<LevelObject>& objects,
142+
const std::vector<int>& floors)
143+
: objects_(objects)
144+
, floors_{floors}
145+
{
146+
}
147+
148+
void AddBulkObjectsAction::execute(EditorState& state, EditorLevel& level)
149+
{
150+
// New objects are selected - so clear the old selection
151+
152+
state.selection.clear_selection();
153+
// When redoing the action, this prevents using the default for this object type
154+
if (!executed_)
155+
{
156+
state.selection.clear_selection();
157+
object_ids.clear();
158+
for (int i = 0; i < objects_.size(); i++)
159+
{
160+
auto& level_object = level.add_object(objects_[i], floors_[i]);
161+
object_ids.push_back(level_object.object_id);
162+
state.selection.add_to_selection(level_object.object_id);
163+
}
164+
executed_ = true;
165+
}
166+
else
167+
{
168+
state.selection.clear_selection();
169+
for (int i = 0; i < objects_.size(); i++)
170+
{
171+
auto& level_object = level.add_object(objects_[i], floors_[i]);
172+
state.selection.add_to_selection(level_object.object_id);
173+
level.set_object_id(level_object.object_id, object_ids[i]);
174+
}
175+
}
176+
}
177+
178+
void AddBulkObjectsAction::undo(EditorState& state, EditorLevel& level)
179+
{
180+
state.selection.clear_selection();
181+
for (auto id : object_ids)
182+
{
183+
level.remove_object(id);
184+
}
185+
}
186+
187+
ActionStrings AddBulkObjectsAction::to_string() const
188+
{
189+
std::string body;
190+
for (auto& object : objects_)
191+
{
192+
body += object.to_string();
193+
}
194+
return {
195+
.title = std::format("Adding bulk {}", objects_.size()),
196+
.body = body,
197+
};
198+
}
199+
200+
// =======================================
201+
// UpdateObjectAction
202+
// =======================================
137203
UpdateObjectAction::UpdateObjectAction(const LevelObject& old_object, const LevelObject& new_object,
138204
int floor)
139205
: old_object_(old_object)
@@ -161,34 +227,91 @@ ActionStrings UpdateObjectAction::to_string() const
161227
};
162228
}
163229

164-
DeleteObjectAction::DeleteObjectAction(const LevelObject& object, int floor)
165-
: object_(object)
166-
, floor_{floor}
230+
BulkUpdateObjectAction::BulkUpdateObjectAction(const std::vector<LevelObject>& old_objects,
231+
const std::vector<LevelObject>& new_objects)
232+
: old_objects_(old_objects)
233+
, new_objects_(new_objects)
234+
{
235+
}
236+
237+
void BulkUpdateObjectAction::execute([[maybe_unused]] EditorState& state, EditorLevel& level)
238+
{
239+
for (auto& object : new_objects_)
240+
{
241+
level.update_object(object, 0);
242+
}
243+
}
244+
245+
void BulkUpdateObjectAction::undo([[maybe_unused]] EditorState& state, EditorLevel& level)
246+
{
247+
for (auto& object : old_objects_)
248+
{
249+
level.update_object(object, 0);
250+
}
251+
}
252+
253+
ActionStrings BulkUpdateObjectAction::to_string() const
254+
{
255+
std::string before;
256+
std::string after;
257+
258+
for (auto& object : old_objects_)
259+
{
260+
before += object.to_string();
261+
}
262+
for (auto& object : new_objects_)
263+
{
264+
after += object.to_string();
265+
}
266+
return {.title = std::format("Update {}", old_objects_.size()), // to_type_string()),
267+
.body = std::format("Before:\n{}\n\nAfter:\n{}", before, after)};
268+
}
269+
270+
// =======================================
271+
// DeleteObjectAction
272+
// =======================================
273+
DeleteObjectAction::DeleteObjectAction(const std::vector<LevelObject>& objects,
274+
const std::vector<int>& floors)
275+
: objects_(objects)
276+
, floors_{floors}
167277
{
168278
}
169279

170280
void DeleteObjectAction::execute(EditorState& state, EditorLevel& level)
171281
{
172-
state.p_active_object = nullptr;
173-
level.remove_object(object_.object_id);
282+
state.selection.clear_selection();
283+
for (auto& object : objects_)
284+
{
285+
level.remove_object(object.object_id);
286+
}
174287
}
175288

176289
void DeleteObjectAction::undo(EditorState& state, EditorLevel& level)
177290
{
178-
auto& new_object = level.add_object(object_, floor_);
179-
180-
// new_object.p = object_.props;
291+
state.selection.clear_selection();
292+
for (int i = 0; i < objects_.size(); i++)
293+
{
294+
auto& new_object = level.add_object(objects_[i], floors_[i]);
181295

182-
state.p_active_object = &new_object;
296+
level.set_object_id(new_object.object_id, objects_[i].object_id);
297+
assert(new_object.object_id == objects_[i].object_id);
183298

184-
level.set_object_id(new_object.object_id, object_.object_id);
185-
object_ = new_object;
299+
objects_[i] = new_object;
300+
state.selection.add_to_selection(new_object.object_id);
301+
}
186302
}
187303

188304
ActionStrings DeleteObjectAction::to_string() const
189305
{
306+
std::string body;
307+
308+
for (auto& object : objects_)
309+
{
310+
body += object.to_string();
311+
}
312+
190313
return {
191-
.title = std::format("Delete {}", object_.to_type_string()),
192-
.body = std::format("ID: {} ", object_.object_id),
314+
.title = std::format("Deleted {}", objects_.size()),
315+
.body = body,
193316
};
194-
}
317+
}

src/Editor/Actions.h

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,29 @@ class AddObjectAction final : public Action
5050
const int floor_;
5151
};
5252

53-
/// Action to update an existing object in the level.
53+
// For copy-paste functionality
54+
class AddBulkObjectsAction final : public Action
55+
{
56+
public:
57+
AddBulkObjectsAction(const std::vector<LevelObject>& objects, const std::vector<int>& floors);
58+
59+
void execute(EditorState& state, EditorLevel& level) override;
60+
void undo(EditorState& state, EditorLevel& level) override;
61+
62+
ActionStrings to_string() const override;
63+
64+
private:
65+
/// The objects to add
66+
std::vector<LevelObject> objects_;
67+
std::vector<int> floors_;
68+
69+
/// The ID of the object added to the level. This for undo/redo to ensure the ID is preserved.
70+
std::vector<ObjectId> object_ids;
71+
72+
// Flag for when re-doing this action, it uses the stored props rather than the default
73+
bool executed_ = false;
74+
};
75+
5476
class UpdateObjectAction final : public Action
5577
{
5678
public:
@@ -70,12 +92,30 @@ class UpdateObjectAction final : public Action
7092

7193
const int floor_;
7294
};
95+
class BulkUpdateObjectAction final : public Action
96+
{
97+
public:
98+
BulkUpdateObjectAction(const std::vector<LevelObject>& old_objects,
99+
const std::vector<LevelObject>& new_objects);
100+
101+
void execute(EditorState& state, EditorLevel& level) override;
102+
void undo(EditorState& state, EditorLevel& level) override;
103+
104+
ActionStrings to_string() const override;
105+
106+
private:
107+
/// The object before the update
108+
const std::vector<LevelObject> old_objects_;
109+
110+
/// The object after the update
111+
const std::vector<LevelObject> new_objects_;
112+
};
73113

74114
/// Action to delete an existing object from the level.
75115
class DeleteObjectAction final : public Action
76116
{
77117
public:
78-
DeleteObjectAction(const LevelObject& object, int floor);
118+
DeleteObjectAction(const std::vector<LevelObject>& objects, const std::vector<int>& floors);
79119

80120
void execute(EditorState& state, EditorLevel& level) override;
81121
void undo(EditorState& state, EditorLevel& level) override;
@@ -84,8 +124,8 @@ class DeleteObjectAction final : public Action
84124

85125
private:
86126
/// The object to delete
87-
LevelObject object_;
88-
const int floor_;
127+
std::vector<LevelObject> objects_;
128+
std::vector<int> floors_;
89129
};
90130

91131
/// Manager for storing the actions and handling undo/redo functionality.

0 commit comments

Comments
 (0)