Aeon Engine c550894
AeonGames Open Source Game Engine
Loading...
Searching...
No Matches
SceneModel.cpp
1/*
2Copyright (C) 2015,2018-2020,2025 Rodrigo Jose Hernandez Cordoba
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17#include <QIcon>
18#include <QFile>
19#include <QMimeData>
20#include <QDataStream>
21#include <QByteArray>
22#include <QXmlStreamWriter>
23#include <QTextStream>
24#include "SceneModel.h"
25#include "aeongames/Scene.hpp"
26#include "aeongames/Node.hpp"
27
28namespace AeonGames
29{
31 QAbstractItemModel ( parent ) {}
32
33 SceneModel::~SceneModel() = default;
34
35 QVariant SceneModel::headerData ( int section, Qt::Orientation orientation, int role ) const
36 {
37 if ( ( orientation == Qt::Horizontal ) && ( role == Qt::DisplayRole ) )
38 {
39 switch ( section )
40 {
41 case 0:
42 return QString ( "Node" );
43 default:
44 return QVariant();
45 }
46 }
47 return QVariant();
48 }
49
50 QModelIndex SceneModel::index ( int row, int column, const QModelIndex & parent ) const
51 {
52 if ( !parent.isValid() )
53 {
54 if ( row < static_cast<int> ( mScene.GetChildrenCount() ) )
55 {
56 return createIndex ( row, column, &const_cast<SceneModel*> ( this )->mScene[row] );
57 }
58 }
59 else
60 {
61 Node* node = reinterpret_cast<Node*> ( parent.internalPointer() );
62 if ( row < static_cast<int> ( node->GetChildrenCount() ) )
63 {
64 return createIndex ( row, column, node->GetChild ( row ) );
65 }
66 }
67 return QModelIndex();
68 }
69
70 QModelIndex SceneModel::parent ( const QModelIndex & index ) const
71 {
72 if ( index.isValid() )
73 {
74 Node* node = reinterpret_cast<Node*> ( index.internalPointer() );
75 Node* node_parent = GetNodePtr ( node->GetParent() );
76 if ( node_parent != nullptr )
77 {
78 return createIndex ( static_cast<int> ( node->GetIndex() ), 0, node_parent );
79 }
80 }
81 return QModelIndex();
82 }
83
84 int SceneModel::rowCount ( const QModelIndex & index ) const
85 {
86 if ( index.isValid() )
87 {
88 return static_cast<int> ( reinterpret_cast<Node*> ( index.internalPointer() )->GetChildrenCount() );
89 }
90 return static_cast<int> ( mScene.GetChildrenCount() );
91 }
92
93 int SceneModel::columnCount ( const QModelIndex & index ) const
94 {
95 return 1;
96 }
97
98 bool SceneModel::hasChildren ( const QModelIndex & index ) const
99 {
100 if ( index.isValid() )
101 {
102 return ( reinterpret_cast<Node*> ( index.internalPointer() )->GetChildrenCount() > 0 );
103 }
104 return ( mScene.GetChildrenCount() > 0 );
105 }
106
107 QVariant SceneModel::data ( const QModelIndex & index, int role ) const
108 {
109 if ( ( role == Qt::DisplayRole ) || ( role == Qt::EditRole ) )
110 {
111 if ( index.isValid() )
112 {
113 switch ( index.column() )
114 {
115 case 0:
116 return QString ( reinterpret_cast<Node*> ( index.internalPointer() )->GetName().c_str() );
117 break;
118 }
119 }
120 }
121 else if ( role == Qt::DecorationRole )
122 {
123 if ( mScene.GetCamera() != reinterpret_cast<Node * > ( index.internalPointer() ) )
124 {
125 return QIcon ( ":/icons/icon_node" );
126 }
127 return QIcon ( ":/icons/icon_camera" );
128 }
129 else if ( role == Qt::UserRole )
130 {
131 return QVariant::fromValue ( index.internalPointer() );
132 }
133 return QVariant();
134 }
135
136 Qt::ItemFlags SceneModel::flags ( const QModelIndex & index ) const
137 {
138 if ( index.isValid() )
139 {
140 return QAbstractItemModel::flags ( index ) | Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
141 }
142 return QAbstractItemModel::flags ( index ) | Qt::ItemIsDropEnabled;
143 }
144
145 bool SceneModel::setData ( const QModelIndex & index, const QVariant & value, int role )
146 {
147 Node* node = reinterpret_cast<Node*> ( index.internalPointer() );
148 if ( role == Qt::EditRole )
149 {
150 node->SetName ( value.toString().toUtf8().constData() );
151 emit dataChanged ( index, index );
152 return true;
153 }
154 return false;
155 }
156
157 bool SceneModel::moveRows ( const QModelIndex & sourceParent, int sourceRow, int count, const QModelIndex & destinationParent, int destinationRow )
158 {
159 if ( sourceParent.isValid() && destinationParent.isValid() )
160 {
161 // Moving between nodes
162 Node* source = reinterpret_cast<Node*> ( sourceParent.internalPointer() );
163 Node* destination = reinterpret_cast<Node*> ( destinationParent.internalPointer() );
164 if ( beginMoveRows ( sourceParent, sourceRow, ( sourceRow + count ) - 1, destinationParent, destinationRow ) )
165 {
166 for ( int i = 0; i < count; ++i )
167 {
168 destination->Insert ( destinationRow + i, source->RemoveByIndex ( sourceRow ) );
169 }
170 endMoveRows();
171 }
172 else
173 {
174 return false;
175 }
176 }
177 else if ( sourceParent.isValid() )
178 {
179 // Moving from a node to the scene
180 Node* source = reinterpret_cast<Node*> ( sourceParent.internalPointer() );
181 if ( beginMoveRows ( sourceParent, sourceRow, ( sourceRow + count ) - 1, destinationParent, destinationRow ) )
182 {
183 for ( int i = 0; i < count; ++i )
184 {
185 mScene.Insert ( destinationRow + i, source->RemoveByIndex ( sourceRow ) );
186 }
187 endMoveRows();
188 }
189 else
190 {
191 return false;
192 }
193 }
194 else if ( destinationParent.isValid() )
195 {
196 // Moving from the scene to a node
197 Node* destination = reinterpret_cast<Node*> ( destinationParent.internalPointer() );
198 if ( beginMoveRows ( sourceParent, sourceRow, ( sourceRow + count ) - 1, destinationParent, destinationRow ) )
199 {
200 for ( int i = 0; i < count; ++i )
201 {
202 destination->Insert ( destinationRow + i, mScene.RemoveByIndex ( sourceRow ) );
203 }
204 endMoveRows();
205 }
206 else
207 {
208 return false;
209 }
210 }
211 else
212 {
213 /* This is the case when a row is moved up or down directly at the scene*/
214 if ( beginMoveRows ( sourceParent, sourceRow, ( sourceRow + count ) - 1, destinationParent, destinationRow ) )
215 {
216 for ( int i = 0; i < count; ++i )
217 {
218 mScene.Insert ( destinationRow + i, mScene.RemoveByIndex ( sourceRow ) );
219 }
220 endMoveRows();
221 }
222 else
223 {
224 return false;
225 }
226 }
227 return true;
228 }
229
230 Qt::DropActions SceneModel::supportedDropActions() const
231 {
232 return Qt::MoveAction;
233 }
234
235 bool SceneModel::dropMimeData ( const QMimeData * data, Qt::DropAction action, int row, int column, const QModelIndex & parent )
236 {
237 QString format ( "application/x-aeon-engine-node" );
238 // check if the action is supported
239 if ( !data || ( action != Qt::MoveAction ) )
240 {
241 return false;
242 }
243 // check if the format is supported
244 if ( !data->hasFormat ( format ) )
245 {
246 return false;
247 }
248 if ( ( row > rowCount ( parent ) ) || ( row < 0 ) )
249 {
250 row = rowCount ( parent );
251 }
252 QByteArray byteArray = data->data ( format );
253 QDataStream dataStream ( &byteArray, QIODevice::ReadOnly );
254 int count;
255 dataStream >> count;
256 for ( int i = 0; i < count; ++i )
257 {
258 Node* pointer;
259 dataStream.readRawData ( reinterpret_cast<char*> ( &pointer ), sizeof ( void* ) );
260 QModelIndex model_index = createIndex ( static_cast<int> ( pointer->GetIndex() ), column, pointer );
261 moveRow ( this->parent ( model_index ), static_cast<int> ( pointer->GetIndex() ), parent, row );
262 }
263 return true;
264 }
265
266 QMimeData * SceneModel::mimeData ( const QModelIndexList & indexes ) const
267 {
268 QMimeData* data = nullptr;
269 if ( !indexes.isEmpty() )
270 {
271 QByteArray byteArray;
272 byteArray.reserve ( ( indexes.count() + 1 ) *sizeof ( void* ) );
273 QDataStream dataStream ( &byteArray, QIODevice::WriteOnly );
274 dataStream << indexes.count();
275 for ( auto i = indexes.cbegin(); i != indexes.cend(); ++i )
276 {
277 void* pointer = ( *i ).internalPointer();
278 dataStream.writeRawData ( reinterpret_cast<char*> ( &pointer ), sizeof ( void* ) );
279 }
280 QStringList types = mimeTypes();
281 data = new QMimeData();
282 data->setData ( types[0], byteArray );
283 }
284 return data;
285 }
286
287 QStringList SceneModel::mimeTypes() const
288 {
289 QStringList types;
290 types << "application/x-aeon-engine-node";
291 return types;
292 }
293
294 void SceneModel::InsertNode ( int row, const QModelIndex & parent, std::unique_ptr<Node> aNode )
295 {
296 beginInsertRows ( parent, row, row );
297 if ( parent.isValid() )
298 {
299 reinterpret_cast<Node*> ( parent.internalPointer() )->Insert ( static_cast<size_t> ( row ), ( ( aNode ) ? std::move ( aNode ) : std::make_unique<Node>() ) );
300 }
301 else
302 {
303 mScene.Insert ( static_cast<size_t> ( row ), ( ( aNode ) ? std::move ( aNode ) : std::make_unique<Node>() ) );
304 }
305 endInsertRows();
306 }
307
308 void SceneModel::RemoveNode ( int row, const QModelIndex & parent )
309 {
310 beginRemoveRows ( parent, row, row );
311 if ( parent.isValid() )
312 {
313 reinterpret_cast<Node*> ( parent.internalPointer() )->RemoveByIndex ( static_cast<size_t> ( row ) );
314 }
315 else
316 {
317 mScene.RemoveByIndex ( static_cast<size_t> ( row ) );
318 }
319 endRemoveRows();
320 }
321
322 void SceneModel::SetCameraNode ( const QModelIndex & index )
323 {
324 beginResetModel();
325 if ( index.isValid() )
326 {
327 mScene.SetCamera ( reinterpret_cast<Node*> ( index.internalPointer() ) );
328 }
329 else
330 {
331 mScene.SetCamera ( nullptr );
332 }
333 endResetModel();
334 }
335
336 std::string SceneModel::Serialize ( bool aAsBinary ) const
337 {
338 return mScene.Serialize ( aAsBinary );
339 }
340
341 void SceneModel::Deserialize ( const std::string& aSerializedScene )
342 {
343 beginResetModel();
344 mScene.Deserialize ( aSerializedScene );
345 endResetModel();
346 }
347
349 {
350 return mScene;
351 }
352}
Header for the Scene class.
Scene graph node representing an entity in the game world.
Definition Node.hpp:54
DLL size_t GetIndex() const
Get this node's index within its parent's child list.
Definition Node.cpp:77
DLL Node * GetChild(size_t aIndex) const
Get a child node by index.
Definition Node.cpp:69
DLL void SetName(const std::string &aName)
Set the name of this node.
Definition Node.cpp:199
DLL const std::string & GetName() const
Get the name of this node.
Definition Node.cpp:205
DLL NodeParent GetParent() const
Get this node's parent.
Definition Node.cpp:73
DLL Node * Insert(size_t aIndex, std::unique_ptr< Node > aNode)
Insert a child node at a specific index.
Definition Node.cpp:317
DLL std::unique_ptr< Node > RemoveByIndex(size_t aIndex)
Remove a child node by index.
Definition Node.cpp:379
DLL size_t GetChildrenCount() const
Get the number of direct child nodes.
Definition Node.cpp:56
Scene class. Scene is the container for all elements in a game level, takes care of collision,...
Definition Scene.hpp:40
QMimeData * mimeData(const QModelIndexList &indexes) const override
Return serialized MIME data for the given model indexes.
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override
Handle data supplied by a drag-and-drop operation.
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
Return the index of the item at the given row and column under parent.
int rowCount(const QModelIndex &index=QModelIndex()) const override
Return the number of rows under the given parent.
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
Return the header data for the given section, orientation, and role.
const Scene & GetScene() const
Get a const reference to the underlying scene.
std::string Serialize(bool aAsBinary=true) const
Serialize the scene to a string.
bool setData(const QModelIndex &index, const QVariant &value, int role) override
Set the data for the given index and role.
void Deserialize(const std::string &aSerializedScene)
Deserialize a scene from a string.
QModelIndex parent(const QModelIndex &index) const override
Return the parent of the given model index.
int columnCount(const QModelIndex &index=QModelIndex()) const override
Return the number of columns for children of the given parent.
void InsertNode(int row, const QModelIndex &parent=QModelIndex(), std::unique_ptr< Node > aNode={})
Insert a node into the scene tree.
bool hasChildren(const QModelIndex &index=QModelIndex()) const override
Return whether the given parent index has any children.
Qt::ItemFlags flags(const QModelIndex &index) const override
Return the item flags for the given model index.
SceneModel(QObject *parent=nullptr)
Construct the scene model.
bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationRow) override
Move rows from one parent to another.
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
Return the data for the given index and role.
void SetCameraNode(const QModelIndex &index=QModelIndex())
Set the camera to the node at the given index.
Qt::DropActions supportedDropActions() const override
Return the drop actions supported by this model.
void RemoveNode(int row, const QModelIndex &parent=QModelIndex())
Remove a node from the scene tree.
virtual ~SceneModel()
Destructor.
QStringList mimeTypes() const override
Return the list of MIME types that can be used to describe model indexes.
<- This is here just for the literals
Definition AABB.hpp:31
Node * GetNodePtr(const NodeParent &aNodeParent)
Extract the Node pointer from a NodeParent variant.
Definition Node.hpp:41