16#include <QResizeEvent>
24#include "WorldEditor.h"
25#include "EngineWindow.h"
27#include "aeongames/Renderer.hpp"
28#include "aeongames/Model.hpp"
29#include "aeongames/Animation.hpp"
30#include "aeongames/Mesh.hpp"
31#include "aeongames/ResourceCache.hpp"
33#include "aeongames/CRC.hpp"
34#include "aeongames/Node.hpp"
42 mFrustumVerticalHalfAngle{}, mStep{ 10 },
43 mCameraRotation ( QQuaternion::fromAxisAndAngle ( 0.0f, 0.0f, 1.0f, 45.0f ) * QQuaternion::fromAxisAndAngle ( 1.0f, 0.0f, 0.0f, -30.0f ) ),
45 mCameraLocation { -mCameraRotation.rotatedVector ( forward ) * 300.0f },
52 setSurfaceType ( QSurface::MetalSurface );
54 setSurfaceType ( QSurface::OpenGLSurface );
70 auto current_flags = flags();
71 if ( ! ( current_flags & Qt::MSWindowsOwnDC ) )
73 setFlags ( current_flags | Qt::MSWindowsOwnDC );
77 mWinId =
reinterpret_cast<void*
> ( winId() );
79 qWorldEditorApp->AttachWindowToRenderer ( mWinId );
80 connect ( &mTimer, SIGNAL ( timeout() ),
this, SLOT ( requestUpdate() ) );
83 settings.beginGroup (
"Camera" );
84 mFieldOfView = settings.value (
"FieldOfView", 60.0f ).toFloat();
85 mNear = settings.value (
"Near", 1.0f ).toFloat();
86 mFar = settings.value (
"Far", 1600.0f ).toFloat();
88 settings.beginGroup (
"Workspace" );
89 mHorizontalSpacing = settings.value (
"HorizontalSpacing", uint32_t ( 16 ) ).toUInt();
90 mVerticalSpacing = settings.value (
"VerticalSpacing", uint32_t ( 16 ) ).toUInt();
91 QColor background_color = settings.value (
"BackgroundColor", QColor ( 127, 127, 127 ) ).value<QColor>();
94 qWorldEditorApp->GetRenderer()->SetClearColor ( mWinId, background_color.redF(), background_color.greenF(), background_color.blueF(), 1.0f );
98 float half_radius = (
static_cast<float> ( geometry().size().width() ) /
static_cast<float> ( geometry().size().height() ) ) / 2;
99 float v1[2] = { 1, 0 };
100 float v2[2] = { 1, half_radius };
101 float length = sqrtf ( ( v2[0] * v2[0] ) + ( v2[1] * v2[1] ) );
104 mFrustumVerticalHalfAngle = acosf ( ( v1[0] * v2[0] ) + ( v1[1] * v2[1] ) );
114 qWorldEditorApp->DetachWindowFromRenderer ( mWinId );
117 std::cout <<
LogLevel::Info <<
"EngineWindow destroyed" << std::endl;
122 if ( mStopWatch.isValid() && mTimer.isActive() )
125 mStopWatch.invalidate();
131 if ( !mStopWatch.isValid() && !mTimer.isActive() )
144 mFieldOfView = aFieldOfView;
146 projection.
Perspective ( mFieldOfView, mAspectRatio, mNear, mFar );
147 qWorldEditorApp->GetRenderer()->SetProjectionMatrix ( mWinId, projection );
153 projection.
Perspective ( mFieldOfView, mAspectRatio, mNear, mFar );
154 qWorldEditorApp->GetRenderer()->SetProjectionMatrix ( mWinId, projection );
160 projection.
Perspective ( mFieldOfView, mAspectRatio, mNear, mFar );
161 qWorldEditorApp->GetRenderer()->SetProjectionMatrix ( mWinId, projection );
165 void EngineWindow::setModel (
const QString & filename )
168 mNode->AttachComponent ( ModelInstance::TypeId, {},
169 std::make_shared<ModelInstance> (
170 Get<Model> ( filename.toUtf8().constData(),
171 filename.toUtf8().constData() ) ) );
172 assert ( mNode->GetComponent ( ModelInstance::TypeId ) &&
"ModelInstance is a nullptr" );
173 mRenderer->Unload ( *mNode );
174 mRenderer->Load ( *mNode );
175 if ( ModelInstance * model_instance =
reinterpret_cast<ModelInstance *
> ( mNode->GetComponent ( ModelInstance::TypeId ) ) )
178 float diameter = model_instance->GetModel()->GetCenterRadii().GetRadii().GetMaxAxisLenght() * 2;
179 std::cout <<
"Diameter: " << diameter << std::endl;
181 float half_radius = (
static_cast<float> ( geometry().size().width() ) /
static_cast<float> ( geometry().size().height() ) ) / 2;
182 float v1[2] = { 1, 0 };
183 float v2[2] = { 1, half_radius };
184 float length = sqrtf ( ( v2[0] * v2[0] ) + ( v2[1] * v2[1] ) );
187 mFrustumVerticalHalfAngle = acosf ( ( v1[0] * v2[0] ) + ( v1[1] * v2[1] ) );
189 if ( mFrustumVerticalHalfAngle == 0.0f )
191 throw std::runtime_error (
"mFrustumVerticalHalfAngle is zero." );
194 float eye_length = ( diameter ) / std::tan ( mFrustumVerticalHalfAngle );
195 mCameraLocation = QVector4D (
197 model_instance->GetModel()->GetCenterRadii().GetCenter() [0],
198 model_instance->GetModel()->GetCenterRadii().GetCenter() [1],
199 model_instance->GetModel()->GetCenterRadii().GetCenter() [2] ) +
200 ( mCameraRotation.rotatedVector ( -forward ) * eye_length ), 1 );
202 mStep = eye_length / 100.0f;
207 void EngineWindow::resizeEvent ( QResizeEvent * aResizeEvent )
209 if ( mIsClosing || aResizeEvent->size().isEmpty() )
213 QWindow::resizeEvent ( aResizeEvent );
214 auto renderer = qWorldEditorApp->GetRenderer();
215 if ( renderer !=
nullptr )
217 QSize window_size{ aResizeEvent->size() };
218 renderer->ResizeViewport ( mWinId,
221 window_size.width() * devicePixelRatio(),
222 window_size.height() * devicePixelRatio() );
223 Matrix4x4 projection {};
224 mAspectRatio = (
static_cast<float> ( window_size.width() ) /
225 static_cast<float> ( window_size.height() ) );
226 projection.Perspective ( mFieldOfView, mAspectRatio, mNear, mFar );
227 renderer->SetProjectionMatrix ( mWinId, projection );
229 static const QMatrix4x4 flipMatrix (
230 1.0f, 0.0f, 0.0f, 0.0f,
231 0.0f, 0.0f, -1.0f, 0.0f,
232 0.0f, -1.0f, 0.0f, 0.0f,
233 0.0f, 0.0f, 0.0f, 1.0f );
234 mProjectionMatrix.setToIdentity();
235 float half_radius = (
static_cast<float> ( aResizeEvent->size().width() ) /
static_cast<float> ( aResizeEvent->size().height() ) ) / 2;
236 mProjectionMatrix.frustum ( -half_radius, half_radius, -0.5, 0.5, 1, 1600 );
237 mProjectionMatrix = mProjectionMatrix * flipMatrix;
238 qWorldEditorApp->GetRenderer()->SetProjectionMatrix ( mWinId, mProjectionMatrix.constData() );
240 float v1[2] = { 1, 0 };
241 float v2[2] = { 1, mWindow->GetHalfAspectRatio() };
242 float length = sqrtf ( ( v2[0] * v2[0] ) + ( v2[1] * v2[1] ) );
245 mFrustumVerticalHalfAngle = acosf ( ( v1[0] * v2[0] ) + ( v1[1] * v2[1] ) );
255 void EngineWindow::exposeEvent ( QExposeEvent * aExposeEvent )
257 Q_UNUSED ( aExposeEvent );
268 bool EngineWindow::event ( QEvent * aEvent )
270 switch ( aEvent->type() )
272 case QEvent::UpdateRequest:
273 if ( !geometry().width() || !geometry().height() || !qWorldEditorApp->GetRenderer() )
275 return QWindow::event ( aEvent );
279 if ( mStopWatch.isValid() )
281 delta = mStopWatch.restart() * 1e-3f;
289 const_cast<Scene*
> ( mScene )->Update ( delta );
291 qWorldEditorApp->GetRenderer()->BeginRender ( mWinId );
292 qWorldEditorApp->GetRenderer()->Render (
295 qWorldEditorApp->GetGridMesh(),
296 qWorldEditorApp->GetGridPipeline(),
298 mHorizontalSpacing + 1 );
299 qWorldEditorApp->GetRenderer()->Render (
302 qWorldEditorApp->GetGridMesh(),
303 qWorldEditorApp->GetGridPipeline(),
305 mVerticalSpacing + 1 );
309 if ( mScene && mScene->GetChildrenCount() )
311 const Frustum& frustum { qWorldEditorApp->GetRenderer()->GetFrustum ( mWinId ) };
312 mScene->LoopTraverseDFSPreOrder ( [
this, &frustum] (
const Node & aNode )
314 if ( &aNode == mScene->GetCamera() )
317 Matrix4x4 projection_matrix{};
318 projection_matrix.Perspective ( mScene->GetFieldOfView(), mAspectRatio, mScene->GetNear(), mScene->GetFar() );
319 projection_matrix.Invert();
320 qWorldEditorApp->GetRenderer()->Render (
322 aNode.GetGlobalTransform() * projection_matrix,
323 qWorldEditorApp->GetAABBWireMesh(),
324 qWorldEditorApp->GetSolidColorPipeline(),
325 &qWorldEditorApp->GetSolidColorMaterial(),
331 AABB transformed_aabb = aNode.GetGlobalTransform() * aNode.GetAABB();
332 if ( frustum.Intersects ( transformed_aabb ) )
335 aNode.Render ( *qWorldEditorApp->GetRenderer(), mWinId );
337 qWorldEditorApp->GetRenderer()->Render (
339 transformed_aabb.GetTransform(),
340 qWorldEditorApp->GetAABBWireMesh(),
341 qWorldEditorApp->GetSolidColorPipeline(),
342 &qWorldEditorApp->GetSolidColorMaterial(),
347 qWorldEditorApp->GetRenderer()->Render (
349 aNode.GetGlobalTransform(),
350 qWorldEditorApp->GetAABBWireMesh(),
351 qWorldEditorApp->GetSolidColorPipeline(),
352 &qWorldEditorApp->GetSolidColorMaterial(),
357 qWorldEditorApp->GetRenderer()->Render (
359 Transform{Vector3{1, 1, 1},
360 Quaternion{1, 0, 0, 0},
361 Vector3{transformed_aabb.GetCenter() }},
362 qWorldEditorApp->GetAABBWireMesh(),
363 qWorldEditorApp->GetSolidColorPipeline(),
364 &qWorldEditorApp->GetSolidColorMaterial(),
371 qWorldEditorApp->GetRenderer()->EndRender ( mWinId );
376 std::cout <<
LogLevel::Info <<
"EngineWindow received Close event" << std::endl;
381 return QWindow::event ( aEvent );
385 void EngineWindow::updateViewMatrix()
387 Transform view_transform;
388 view_transform.SetTranslation ( Vector3 ( mCameraLocation.x(), mCameraLocation.y(), mCameraLocation.z() ) );
389 view_transform.SetRotation ( Quaternion ( mCameraRotation.scalar(), mCameraRotation.x(), mCameraRotation.y(), mCameraRotation.z() ) );
390 qWorldEditorApp->GetRenderer()->SetViewMatrix ( mWinId, view_transform.GetInverted().GetMatrix() );
393 void EngineWindow::keyPressEvent ( QKeyEvent * event )
395 switch ( event->key() )
398 mCameraLocation += ( mCameraRotation.rotatedVector ( forward ) * mStep );
401 mCameraLocation -= ( mCameraRotation.rotatedVector ( forward ) * mStep );
404 mCameraLocation += ( mCameraRotation.rotatedVector ( right ) * mStep );
407 mCameraLocation -= ( mCameraRotation.rotatedVector ( right ) * mStep );
414 void EngineWindow::keyReleaseEvent ( QKeyEvent * event )
419 void EngineWindow::mouseMoveEvent ( QMouseEvent * event )
421 if ( event->buttons() & Qt::LeftButton )
423 QPointF movement =
event->globalPosition() - mLastCursorPosition;
424 mLastCursorPosition =
event->globalPosition();
425 mCameraRotation = QQuaternion::fromAxisAndAngle ( 0, 0, 1, - ( movement.x() / 2.0f ) ) * mCameraRotation;
426 mCameraRotation = mCameraRotation * QQuaternion::fromAxisAndAngle ( 1, 0, 0, - ( movement.y() / 2.0f ) );
432 void EngineWindow::mousePressEvent ( QMouseEvent * event )
434 if ( event->button() & Qt::LeftButton )
436 mLastCursorPosition =
event->globalPosition();
441 void EngineWindow::mouseReleaseEvent ( QMouseEvent * event )
446 void EngineWindow::wheelEvent ( QWheelEvent *event )
448 mCameraLocation += ( ( mCameraRotation.rotatedVector ( forward ) * mStep ) *
449 ( event->angleDelta().y() / std::abs ( event->angleDelta().y() ) ) );
Header for the frustum class.
Defines log severity levels and stream output for the AeonGames engine.
EngineWindow(QWindow *parent=nullptr)
Construct the engine window.
void SetNear(float aNear)
Set the near clipping plane distance.
void start()
Start the rendering loop.
~EngineWindow()
Destructor.
void SetFieldOfView(float aFieldOfView)
Set the camera field of view.
void stop()
Stop the rendering loop.
void setScene(const Scene *aScene)
Set the scene to render.
void SetFar(float aFar)
Set the far clipping plane distance.
4 by 4 matrix in colum mayor order.
DLL void Perspective(float aFieldOfVision, float aAspect, float aNear, float aFar)
Set up a symmetric perspective projection matrix.
Scene class. Scene is the container for all elements in a game level, takes care of collision,...
<- This is here just for the literals
@ LINE_LIST
Pairs of vertices forming individual lines.
@ Info
General informational messages.