Doxygen comments

This commit was merged in pull request #12.
This commit is contained in:
2022-11-26 18:24:38 +00:00
parent 443c09da7c
commit a04ebae42a
30 changed files with 1398 additions and 815 deletions

View File

@@ -1,56 +0,0 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: Classes for managing objects and data within a scene ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
##############################################################################*/
#ifndef QTK_SCENE_H
#define QTK_SCENE_H
#include <camera3d.h>
#include <meshrenderer.h>
#include <model.h>
#include <skybox.h>
#include <QMatrix4x4>
namespace Qtk {
class Scene : protected QOpenGLFunctions {
friend class MainWidget;
public:
Scene();
~Scene();
virtual void init() = 0;
virtual void draw() { privDraw(); };
virtual void update() = 0;
static Camera3D & Camera() { return mCamera; }
static QMatrix4x4 View() { return mCamera.toMatrix(); }
static QMatrix4x4 & Projection() { return mProjection; }
inline Skybox * getSkybox() { return mSkybox; }
inline void setSkybox(Skybox * skybox) { mSkybox = skybox; }
private:
static Camera3D mCamera;
static QMatrix4x4 mProjection;
bool mInit = false;
void privDraw();
protected:
Skybox * mSkybox {};
std::vector<MeshRenderer *> mMeshes {};
std::vector<Model *> mModels {};
};
} // namespace Qtk
#endif // QTK_SCENE_H

View File

@@ -32,22 +32,22 @@ const QMatrix4x4 & Camera3D::toMatrix() {
******************************************************************************/
QDataStream & operator<<(QDataStream & out, Camera3D & transform) {
out << transform.transform();
out << transform.getTransform();
return out;
}
QDataStream & operator>>(QDataStream & in, Camera3D & transform) {
in >> transform.transform();
in >> transform.getTransform();
return in;
}
QDebug operator<<(QDebug dbg, const Camera3D & transform) {
dbg << "Camera3D\n{\n";
dbg << "Position: <" << transform.translation().x() << ", "
<< transform.translation().y() << ", " << transform.translation().z()
<< ">\n";
dbg << "Rotation: <" << transform.rotation().x() << ", "
<< transform.rotation().y() << ", " << transform.rotation().z() << " | "
<< transform.rotation().scalar() << ">\n}";
dbg << "Position: <" << transform.getTranslation().x() << ", "
<< transform.getTranslation().y() << ", "
<< transform.getTranslation().z() << ">\n";
dbg << "Rotation: <" << transform.getRotation().x() << ", "
<< transform.getRotation().y() << ", " << transform.getRotation().z()
<< " | " << transform.getRotation().scalar() << ">\n}";
return dbg;
}

View File

@@ -17,19 +17,25 @@
namespace Qtk {
class QTKAPI Camera3D {
public:
// Constants
/*************************************************************************
* Constants
************************************************************************/
static const QVector3D LocalForward;
static const QVector3D LocalUp;
static const QVector3D LocalRight;
// Accessors
inline Transform3D & transform() { return mTransform; }
/*************************************************************************
* Accessors
************************************************************************/
[[nodiscard]] inline const QVector3D & translation() const {
inline Transform3D & getTransform() { return mTransform; }
[[nodiscard]] inline const QVector3D & getTranslation() const {
return mTransform.getTranslation();
}
[[nodiscard]] inline const QQuaternion & rotation() const {
[[nodiscard]] inline const QQuaternion & getRotation() const {
return mTransform.getRotation();
}
@@ -49,9 +55,17 @@ namespace Qtk {
}
private:
/*************************************************************************
* Private Members
************************************************************************/
Transform3D mTransform;
QMatrix4x4 mWorld;
/*************************************************************************
* Private Methods
************************************************************************/
#ifndef QT_NO_DATASTREAM
friend QDataStream & operator<<(QDataStream & out, Camera3D & transform);
friend QDataStream & operator>>(QDataStream & in, Camera3D & transform);

View File

@@ -17,10 +17,15 @@
namespace Qtk {
class QTKAPI Input {
public:
/*************************************************************************
* Typedefs
************************************************************************/
friend class Qtk::QtkWidget;
public:
// Possible key states
/**
* Possible key states
*/
enum InputState {
InputInvalid,
InputRegistered,
@@ -30,6 +35,10 @@ namespace Qtk {
InputReleased
};
/*************************************************************************
* Public Methods
************************************************************************/
// State checking
inline static bool keyTriggered(Qt::Key key) {
return keyState(key) == InputTriggered;
@@ -63,6 +72,10 @@ namespace Qtk {
static QPoint mouseDelta();
private:
/*************************************************************************
* Private Methods
************************************************************************/
// State updating
static void update();
static void registerKeyPress(int key);

View File

@@ -1,75 +0,0 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: Main window for Qt6 OpenGL widget application ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
##############################################################################*/
#ifndef QTK_MAINWIDGET_H
#define QTK_MAINWIDGET_H
#include <iostream>
#include <QMatrix4x4>
#include <QOpenGLDebugLogger>
#include <QOpenGLFunctions>
#include <QOpenGLWidget>
#define QTK_DEBUG
class MeshRenderer;
class Model;
class Object;
class Scene;
class Skybox;
class OpenGLTextureFactory;
class MainWidget : public QOpenGLWidget, protected QOpenGLFunctions {
Q_OBJECT;
public:
// Constructors
MainWidget();
explicit MainWidget(QWidget * parent);
explicit MainWidget(const QSurfaceFormat & format);
~MainWidget() override;
private:
void teardownGL();
void initObjects();
public:
// Inherited virtual Members
void paintGL() override;
void initializeGL() override;
void resizeGL(int width, int height) override;
protected slots:
void update();
void messageLogged(const QOpenGLDebugMessage & msg);
// Protected Helpers
protected:
void keyPressEvent(QKeyEvent * event) override;
void keyReleaseEvent(QKeyEvent * event) override;
void mousePressEvent(QMouseEvent * event) override;
void mouseReleaseEvent(QMouseEvent * event) override;
private:
// Private helpers
void initializeWidget();
void printContextInformation();
void updateCameraInput();
Scene * mScene;
Object * mObject;
QOpenGLDebugLogger * mDebugLogger;
};
#endif // QTK_MAINWIDGET_H

View File

@@ -13,6 +13,9 @@ using namespace Qtk;
Cube::Cube(DrawMode mode) {
mDrawMode = mode;
switch(mode) {
// The order of the following assignment values helps to visualize.
// clang-format off
// Cube data for use with glDrawArrays
case QTK_DRAW_ARRAYS:
mIndices = {/* No indices needed for glDrawArrays */};
@@ -20,51 +23,76 @@ Cube::Cube(DrawMode mode) {
mNormals = {FACE_FRONT, FACE_BACK, FACE_TOP,
FACE_BOTTOM, FACE_LEFT, FACE_RIGHT};
mVertices = {// Face 1 (Front)
VERTEX_FTR, VERTEX_FTL, VERTEX_FBL, VERTEX_FBL, VERTEX_FBR,
VERTEX_FTR,
// Face 2 (Back)
VERTEX_BBR, VERTEX_BTL, VERTEX_BTR, VERTEX_BTL, VERTEX_BBR,
VERTEX_BBL,
// Face 3 (Top)
VERTEX_FTR, VERTEX_BTR, VERTEX_BTL, VERTEX_BTL, VERTEX_FTL,
VERTEX_FTR,
// Face 4 (Bottom)
VERTEX_FBR, VERTEX_FBL, VERTEX_BBL, VERTEX_BBL, VERTEX_BBR,
VERTEX_FBR,
// Face 5 (Left)
VERTEX_FBL, VERTEX_FTL, VERTEX_BTL, VERTEX_FBL, VERTEX_BTL,
VERTEX_BBL,
// Face 6 (Right)
VERTEX_FTR, VERTEX_FBR, VERTEX_BBR, VERTEX_BBR, VERTEX_BTR,
VERTEX_FTR};
// We're drawing triangles to construct the geometry of a cube.
// Each triangle is made up of three points.
// The entire cube has 12 triangles to make 6 square faces of the cube.
mVertices = {
// Face 1 (Front)
VERTEX_FTR, VERTEX_FTL, VERTEX_FBL,
VERTEX_FBL, VERTEX_FBR, VERTEX_FTR,
// Face 2 (Back)
VERTEX_BBR, VERTEX_BTL, VERTEX_BTR,
VERTEX_BTL, VERTEX_BBR, VERTEX_BBL,
// Face 3 (Top)
VERTEX_FTR, VERTEX_BTR, VERTEX_BTL,
VERTEX_BTL, VERTEX_FTL, VERTEX_FTR,
// Face 4 (Bottom)
VERTEX_FBR, VERTEX_FBL, VERTEX_BBL,
VERTEX_BBL, VERTEX_BBR, VERTEX_FBR,
// Face 5 (Left)
VERTEX_FBL, VERTEX_FTL, VERTEX_BTL,
VERTEX_FBL, VERTEX_BTL, VERTEX_BBL,
// Face 6 (Right)
VERTEX_FTR, VERTEX_FBR, VERTEX_BBR,
VERTEX_BBR, VERTEX_BTR, VERTEX_FTR
};
mColors = {// Face 1 (Front)
RED, GREEN, BLUE, BLUE, WHITE, RED,
// Face 2 (Back)
YELLOW, CYAN, MAGENTA, CYAN, YELLOW, BLACK,
// Face 3 (Top)
RED, MAGENTA, CYAN, CYAN, GREEN, RED,
// Face 4 (Bottom)
WHITE, BLUE, BLACK, BLACK, YELLOW, WHITE,
// Face 5 (Left)
BLUE, GREEN, CYAN, BLUE, CYAN, BLACK,
// Face 6 (Right)
RED, WHITE, YELLOW, YELLOW, MAGENTA, RED};
// Setting colors for each vertex that we defined above.
// These are defaults and can be overriden by the caller with setColor().
// The colors below are interpolated from vertex to vertex.
mColors = {
// Face 1 (Front)
RED, GREEN, BLUE,
BLUE, WHITE, RED,
// Face 2 (Back)
YELLOW, CYAN, MAGENTA,
CYAN, YELLOW, BLACK,
// Face 3 (Top)
RED, MAGENTA, CYAN,
CYAN, GREEN, RED,
// Face 4 (Bottom)
WHITE, BLUE, BLACK,
BLACK, YELLOW, WHITE,
// Face 5 (Left)
BLUE, GREEN, CYAN,
BLUE, CYAN, BLACK,
// Face 6 (Right)
RED, WHITE, YELLOW,
YELLOW, MAGENTA, RED
};
mTexCoords = {// Face 1 (Front)
UV_TOP, UV_ORIGIN, UV_RIGHT, UV_RIGHT, UV_CORNER, UV_TOP,
// Face 2 (Back)
UV_TOP, UV_RIGHT, UV_CORNER, UV_RIGHT, UV_TOP, UV_ORIGIN,
// Face 3 (Top)
UV_CORNER, UV_TOP, UV_ORIGIN, UV_ORIGIN, UV_RIGHT,
UV_CORNER,
// Face 4 (Bottom)
UV_TOP, UV_ORIGIN, UV_RIGHT, UV_RIGHT, UV_CORNER, UV_TOP,
// Face 5 (Left)
UV_TOP, UV_CORNER, UV_RIGHT, UV_TOP, UV_RIGHT, UV_ORIGIN,
// Face 6 (Right)
UV_TOP, UV_CORNER, UV_RIGHT, UV_RIGHT, UV_ORIGIN, UV_TOP};
// Define texture coordinates for the cube.
// This defines the orientation of the texture when applied the object.
mTexCoords = {
// Face 1 (Front)
UV_TOP, UV_ORIGIN, UV_RIGHT,
UV_RIGHT, UV_CORNER, UV_TOP,
// Face 2 (Back)
UV_TOP, UV_RIGHT, UV_CORNER,
UV_RIGHT, UV_TOP, UV_ORIGIN,
// Face 3 (Top)
UV_CORNER, UV_TOP, UV_ORIGIN,
UV_ORIGIN, UV_RIGHT, UV_CORNER,
// Face 4 (Bottom)
UV_TOP, UV_ORIGIN, UV_RIGHT,
UV_RIGHT, UV_CORNER, UV_TOP,
// Face 5 (Left)
UV_TOP, UV_CORNER, UV_RIGHT,
UV_TOP, UV_RIGHT, UV_ORIGIN,
// Face 6 (Right)
UV_TOP, UV_CORNER, UV_RIGHT,
UV_RIGHT, UV_ORIGIN, UV_TOP
};
break;
@@ -81,56 +109,64 @@ Cube::Cube(DrawMode mode) {
VERTEX_FTR, VERTEX_FTL, VERTEX_FBL, VERTEX_FBR,
// 4 5 6 7
VERTEX_BTR, VERTEX_BTL, VERTEX_BBL, VERTEX_BBR};
mIndices = {// Face 1 (Front)
0, 1, 2, 2, 3, 0,
// Face 2 (Back)
7, 5, 4, 5, 7, 6,
// Face 3 (Top)
0, 4, 5, 5, 1, 0,
// Face 4 (Bottom)
3, 2, 6, 6, 7, 3,
// Face 5 (Left)
2, 1, 5, 2, 5, 6,
// Face 6 (Right)
0, 3, 7, 7, 4, 0};
mIndices = {
// Face 1 (Front)
0, 1, 2, 2, 3, 0,
// Face 2 (Back)
7, 5, 4, 5, 7, 6,
// Face 3 (Top)
0, 4, 5, 5, 1, 0,
// Face 4 (Bottom)
3, 2, 6, 6, 7, 3,
// Face 5 (Left)
2, 1, 5, 2, 5, 6,
// Face 6 (Right)
0, 3, 7, 7, 4, 0
};
break;
// Cube shape data for using normals and UVs with glDrawElements
case QTK_DRAW_ELEMENTS_NORMALS:
mColors = {RED, GREEN, BLUE, WHITE, YELLOW, CYAN, MAGENTA, BLACK};
mVertices = {// Face 1 (Front)
// 0 1 2 3
VERTEX_FTL, VERTEX_FBL, VERTEX_FBR, VERTEX_FTR,
// Face 2 (Back)
// 4 5 6 7
VERTEX_BTL, VERTEX_BBL, VERTEX_BBR, VERTEX_BTR,
// Face 3 (Top)
// 8 9 10 11
VERTEX_FTL, VERTEX_BTL, VERTEX_BTR, VERTEX_FTR,
// Face 4 (Bottom)
// 12 13 14 15
VERTEX_FBL, VERTEX_BBL, VERTEX_BBR, VERTEX_FBR,
// Face 5 (Left)
// 16 17 18 19
VERTEX_FBL, VERTEX_BBL, VERTEX_BTL, VERTEX_FTL,
// Face 6 (Right)
// 20 21 22 23
VERTEX_FBR, VERTEX_BBR, VERTEX_BTR, VERTEX_FTR};
mVertices = {
// Face 1 (Front)
// 0 1 2 3
VERTEX_FTL, VERTEX_FBL, VERTEX_FBR, VERTEX_FTR,
// Face 2 (Back)
// 4 5 6 7
VERTEX_BTL, VERTEX_BBL, VERTEX_BBR, VERTEX_BTR,
// Face 3 (Top)
// 8 9 10 11
VERTEX_FTL, VERTEX_BTL, VERTEX_BTR, VERTEX_FTR,
// Face 4 (Bottom)
// 12 13 14 15
VERTEX_FBL, VERTEX_BBL, VERTEX_BBR, VERTEX_FBR,
// Face 5 (Left)
// 16 17 18 19
VERTEX_FBL, VERTEX_BBL, VERTEX_BTL, VERTEX_FTL,
// Face 6 (Right)
// 20 21 22 23
VERTEX_FBR, VERTEX_BBR, VERTEX_BTR, VERTEX_FTR
};
mIndices = {// Face 1 (Front)
0, 1, 2, 2, 3, 0,
// Face 2 (Back)
4, 5, 6, 6, 7, 4,
// Face 3 (Top)
8, 9, 10, 10, 11, 8,
// Face 4 (Bottom)
12, 13, 14, 14, 15, 12,
mIndices = {
// Face 1 (Front)
0, 1, 2, 2, 3, 0,
// Face 2 (Back)
4, 5, 6, 6, 7, 4,
// Face 3 (Top)
8, 9, 10, 10, 11, 8,
// Face 4 (Bottom)
12, 13, 14, 14, 15, 12,
// Face 5 (Left)
16, 17, 18, 18, 19, 16,
// Face 6 (Right)
20, 21, 22, 22, 23, 20
};
// Face 5 (Left)
16, 17, 18, 18, 19, 16,
// Face 6 (Right)
20, 21, 22, 22, 23, 20};
mNormals = {
VECTOR_FORWARD, VECTOR_FORWARD, VECTOR_FORWARD, VECTOR_FORWARD,
@@ -143,50 +179,27 @@ Cube::Cube(DrawMode mode) {
mTexCoords = {
// Face 1 (Front)
UV_TOP,
UV_RIGHT,
UV_CORNER,
UV_RIGHT,
UV_TOP,
UV_ORIGIN,
UV_TOP, UV_RIGHT, UV_CORNER,
UV_RIGHT, UV_TOP, UV_ORIGIN,
// Face 2 (Back)
UV_TOP,
UV_RIGHT,
UV_CORNER,
UV_RIGHT,
UV_TOP,
UV_ORIGIN,
UV_TOP, UV_RIGHT, UV_CORNER,
UV_RIGHT, UV_TOP, UV_ORIGIN,
// Face 3 (Top)
UV_TOP,
UV_RIGHT,
UV_CORNER,
UV_RIGHT,
UV_TOP,
UV_ORIGIN,
UV_TOP, UV_RIGHT, UV_CORNER,
UV_RIGHT, UV_TOP, UV_ORIGIN,
// Face 4 (Bottom)
UV_TOP,
UV_RIGHT,
UV_CORNER,
UV_RIGHT,
UV_TOP,
UV_ORIGIN,
UV_TOP, UV_RIGHT, UV_CORNER,
UV_RIGHT, UV_TOP, UV_ORIGIN,
// Face 5 (Left)
UV_TOP,
UV_RIGHT,
UV_CORNER,
UV_RIGHT,
UV_TOP,
UV_ORIGIN,
UV_TOP, UV_RIGHT, UV_CORNER,
UV_RIGHT, UV_TOP, UV_ORIGIN,
// Face 6 (Right)
UV_TOP,
UV_RIGHT,
UV_CORNER,
UV_RIGHT,
UV_TOP,
UV_ORIGIN,
UV_TOP, UV_RIGHT, UV_CORNER,
UV_RIGHT, UV_TOP, UV_ORIGIN,
};
break;
// clang-format on
}
}
@@ -194,6 +207,8 @@ Triangle::Triangle(DrawMode mode) {
mDrawMode = mode;
const QVector3D triangleTop = QVector3D(0.0f, 0.5f, 0.0f);
switch(mode) {
// clang-format off
case QTK_DRAW_ARRAYS:
mIndices = {/* No indices needed for glDrawArrays */};
@@ -201,29 +216,17 @@ Triangle::Triangle(DrawMode mode) {
mVertices = {
// Bottom face (Base of the pyramid)
VERTEX_BBL,
VERTEX_BBR,
VERTEX_FBR,
VERTEX_FBR,
VERTEX_FBL,
VERTEX_BBL,
VERTEX_BBL, VERTEX_BBR, VERTEX_FBR,
VERTEX_FBR, VERTEX_FBL, VERTEX_BBL,
// Front face
VERTEX_FBL,
VERTEX_FBR,
triangleTop,
VERTEX_FBL, VERTEX_FBR, triangleTop,
// Back face
VERTEX_BBR,
VERTEX_BBL,
triangleTop,
VERTEX_BBR, VERTEX_BBL, triangleTop,
// Left face
VERTEX_BBL,
VERTEX_FBL,
triangleTop,
VERTEX_BBL, VERTEX_FBL, triangleTop,
// Right face
VERTEX_FBR,
VERTEX_BBR,
triangleTop,
VERTEX_FBR, VERTEX_BBR, triangleTop,
};
// Find normals for each triangle of the mesh
@@ -238,29 +241,17 @@ Triangle::Triangle(DrawMode mode) {
mTexCoords = {
// Bottom face (Base of the pyramid)
UV_ORIGIN,
UV_RIGHT,
UV_CORNER,
UV_CORNER,
UV_TOP,
UV_ORIGIN,
UV_ORIGIN, UV_RIGHT, UV_CORNER,
UV_CORNER, UV_TOP, UV_ORIGIN,
// Front face
UV_ORIGIN,
UV_RIGHT,
UV_CORNER,
UV_ORIGIN, UV_RIGHT, UV_CORNER,
// Back face
UV_ORIGIN,
UV_RIGHT,
UV_CORNER,
UV_ORIGIN, UV_RIGHT, UV_CORNER,
// Left face
UV_ORIGIN,
UV_RIGHT,
UV_CORNER,
UV_ORIGIN, UV_RIGHT, UV_CORNER,
// Right face
UV_ORIGIN,
UV_RIGHT,
UV_CORNER,
UV_ORIGIN, UV_RIGHT, UV_CORNER,
};
break;
@@ -296,34 +287,22 @@ Triangle::Triangle(DrawMode mode) {
mVertices = {
// Bottom face
// 0 1 2
VERTEX_FBL,
VERTEX_FBR,
VERTEX_BBL,
VERTEX_FBL, VERTEX_FBR, VERTEX_BBL,
// 3 4 5
VERTEX_BBR,
VERTEX_FBR,
VERTEX_BBL,
VERTEX_BBR, VERTEX_FBR, VERTEX_BBL,
// Front face
// 6 7 8
VERTEX_FBL,
VERTEX_FBR,
triangleTop,
VERTEX_FBL, VERTEX_FBR, triangleTop,
// Back face
// 9 10 11
VERTEX_BBR,
VERTEX_BBL,
triangleTop,
VERTEX_BBR, VERTEX_BBL, triangleTop,
// Left face
// 12 13 14
VERTEX_BBL,
VERTEX_FBL,
triangleTop,
VERTEX_BBL, VERTEX_FBL, triangleTop,
// Right face
// 15 16 17
VERTEX_FBR,
VERTEX_BBR,
triangleTop,
VERTEX_FBR, VERTEX_BBR, triangleTop,
};
mIndices = {
@@ -350,30 +329,19 @@ Triangle::Triangle(DrawMode mode) {
mTexCoords = {
// Bottom face
UV_ORIGIN,
UV_RIGHT,
UV_TOP,
UV_CORNER,
UV_RIGHT,
UV_TOP,
UV_ORIGIN, UV_RIGHT, UV_TOP,
UV_CORNER, UV_RIGHT, UV_TOP,
// Front face
UV_ORIGIN,
UV_RIGHT,
UV_CORNER,
UV_ORIGIN, UV_RIGHT, UV_CORNER,
// Back face
UV_ORIGIN,
UV_RIGHT,
UV_CORNER,
UV_ORIGIN, UV_RIGHT, UV_CORNER,
// Left face
UV_ORIGIN,
UV_RIGHT,
UV_CORNER,
UV_ORIGIN, UV_RIGHT, UV_CORNER,
// Right face
UV_ORIGIN,
UV_RIGHT,
UV_CORNER,
UV_ORIGIN, UV_RIGHT, UV_CORNER,
};
break;
// clang-format on
}
}

View File

@@ -46,21 +46,22 @@ namespace Qtk {
#define VECTOR_ONE QVector3D(1.0f, 1.0f, 1.0f)
#define VECTOR_ZERO QVector3D(0.0f, 0.0f, 0.0f)
// clang-format off
// A series of direction vectors to represent cube face normal
#define FACE_TOP \
VECTOR_UP, VECTOR_UP, VECTOR_UP, VECTOR_UP, VECTOR_UP, VECTOR_UP
#define FACE_BOTTOM \
VECTOR_DOWN, VECTOR_DOWN, VECTOR_DOWN, VECTOR_DOWN, VECTOR_DOWN, VECTOR_DOWN
#define FACE_LEFT \
VECTOR_LEFT, VECTOR_LEFT, VECTOR_LEFT, VECTOR_LEFT, VECTOR_LEFT, VECTOR_LEFT
#define FACE_RIGHT \
VECTOR_RIGHT, VECTOR_RIGHT, VECTOR_RIGHT, VECTOR_RIGHT, VECTOR_RIGHT, \
VECTOR_RIGHT
#define FACE_FRONT \
VECTOR_FORWARD, VECTOR_FORWARD, VECTOR_FORWARD, VECTOR_FORWARD, \
VECTOR_FORWARD, VECTOR_FORWARD
#define FACE_BACK \
VECTOR_BACK, VECTOR_BACK, VECTOR_BACK, VECTOR_BACK, VECTOR_BACK, VECTOR_BACK
#define FACE_TOP VECTOR_UP, VECTOR_UP, VECTOR_UP, \
VECTOR_UP, VECTOR_UP, VECTOR_UP
#define FACE_BOTTOM VECTOR_DOWN, VECTOR_DOWN, VECTOR_DOWN, \
VECTOR_DOWN, VECTOR_DOWN, VECTOR_DOWN
#define FACE_LEFT VECTOR_LEFT, VECTOR_LEFT, VECTOR_LEFT, \
VECTOR_LEFT, VECTOR_LEFT, VECTOR_LEFT
#define FACE_RIGHT VECTOR_RIGHT, VECTOR_RIGHT, VECTOR_RIGHT, \
VECTOR_RIGHT, VECTOR_RIGHT, VECTOR_RIGHT
#define FACE_FRONT VECTOR_FORWARD, VECTOR_FORWARD, VECTOR_FORWARD, \
VECTOR_FORWARD, VECTOR_FORWARD, VECTOR_FORWARD
#define FACE_BACK VECTOR_BACK, VECTOR_BACK, VECTOR_BACK, \
VECTOR_BACK, VECTOR_BACK, VECTOR_BACK
// clang-format on
// Colors using QVector3Ds as RGB values
#define WHITE VECTOR_ONE
@@ -84,13 +85,26 @@ namespace Qtk {
typedef std::vector<QVector2D> TexCoords;
typedef std::vector<QVector3D> Normals;
/**
* The OpenGL draw mode to initialize QTK shape data for.
* Different draw modes require different organization of data.
* This enum allows us to predefine simple geometry for different draw modes.
*/
enum DrawMode {
QTK_DRAW_ARRAYS,
QTK_DRAW_ELEMENTS,
QTK_DRAW_ELEMENTS_NORMALS
};
/**
* Base class for all simple shape objects.
*/
struct QTKAPI ShapeBase {
public:
/*************************************************************************
* Constructors / Destructors
************************************************************************/
explicit ShapeBase(
DrawMode mode = QTK_DRAW_ARRAYS, Vertices v = {}, Indices i = {},
Colors c = {}, TexCoords t = {}, Normals n = {}) :
@@ -99,6 +113,10 @@ namespace Qtk {
mIndices(std::move(i)), mTexCoords(std::move(t)),
mNormals(std::move(n)) {}
/*************************************************************************
* Accessors
************************************************************************/
[[nodiscard]] inline const Vertices & getVertices() const {
return mVertices;
}
@@ -122,6 +140,10 @@ namespace Qtk {
}
protected:
/*************************************************************************
* Protected Members
************************************************************************/
DrawMode mDrawMode;
Vertices mVertices {};
@@ -132,13 +154,26 @@ namespace Qtk {
};
struct Shape : public ShapeBase {
public:
/*************************************************************************
* Typedefs
************************************************************************/
friend MeshRenderer;
friend Object;
/*************************************************************************
* Constructors / Destructors
************************************************************************/
Shape() = default;
explicit Shape(const ShapeBase & rhs) : ShapeBase(rhs) {}
/*************************************************************************
* Setters
************************************************************************/
virtual inline void setVertices(const Vertices & value) {
mVertices = value;
}
@@ -160,13 +195,15 @@ namespace Qtk {
virtual inline void setShape(const Shape & value) { *this = value; }
};
// Primitives inherit from ShapeBase, does not allow setting of shape values
/* Primitives inherit from ShapeBase, doesn't allow setting shape values. */
class QTKAPI Mesh {};
/* Simple Cube shape. */
struct QTKAPI Cube : public ShapeBase {
explicit Cube(DrawMode mode = QTK_DRAW_ARRAYS);
};
/* Simple Triangle shape. */
struct QTKAPI Triangle : public ShapeBase {
explicit Triangle(DrawMode mode = QTK_DRAW_ARRAYS);
};

View File

@@ -8,8 +8,8 @@
#include <QImageReader>
#include <abstractscene.h>
#include <meshrenderer.h>
#include <scene.h>
#include <texture.h>
using namespace Qtk;
@@ -31,6 +31,13 @@ MeshRenderer::~MeshRenderer() {
// Static member function to retrieve instances of MeshRenderers
MeshRenderer * MeshRenderer::getInstance(const QString & name) {
if(!sInstances.contains(name)) {
#if QTK_DEBUG
qDebug() << "Attempt to access MeshRenderer instance that does not exist! ("
<< qPrintable(name) << ")\n";
#endif
return nullptr;
}
return sInstances[name];
}
@@ -126,8 +133,8 @@ void MeshRenderer::setShaders(
void MeshRenderer::setUniformMVP(
const char * model, const char * view, const char * projection) {
ShaderBindScope lock(&mProgram, mBound);
mProgram.setUniformValue(projection, Scene::Projection());
mProgram.setUniformValue(view, Scene::View());
mProgram.setUniformValue(projection, Scene::getProjectionMatrix());
mProgram.setUniformValue(view, Scene::getViewMatrix());
mProgram.setUniformValue(model, mTransform.toMatrix());
}
@@ -141,6 +148,8 @@ void MeshRenderer::setColor(const QVector3D & color) {
mShape.mColors[i] = color;
}
}
// TODO: Factor this out so we don't need to reinitialize
init();
}
void MeshRenderer::reallocateTexCoords(const TexCoords & t, unsigned dims) {

View File

@@ -15,31 +15,19 @@
#include <utility>
namespace Qtk {
class QTKAPI ShaderBindScope {
public:
explicit ShaderBindScope(
QOpenGLShaderProgram * program, bool was_locked) :
mWasBound(was_locked) {
mProgram = program;
if(!mWasBound) {
mProgram->bind();
}
}
~ShaderBindScope() {
if(!mWasBound) {
mProgram->release();
}
}
private:
QOpenGLShaderProgram * mProgram;
bool mWasBound;
};
class QTKAPI MeshRenderer : public Object {
public:
/*************************************************************************
* Typedefs
************************************************************************/
/* Static QHash of all mesh objects within the scene. */
typedef QHash<QString, MeshRenderer *> MeshManager;
/*************************************************************************
* Constructors / Destructors
************************************************************************/
// Delegate constructors
MeshRenderer(
const char * name, Vertices vertices, Indices indices,
@@ -54,12 +42,28 @@ namespace Qtk {
MeshRenderer(const char * name, const ShapeBase & shape);
~MeshRenderer() override;
// Retrieve a mesh by name stored within a static QHash
static MeshRenderer * getInstance(const QString & name);
/*************************************************************************
* Public Methods
************************************************************************/
void init();
void draw();
inline void enableAttributeArray(int location) {
ShaderBindScope lock(&mProgram, mBound);
mVAO.bind();
mProgram.enableAttributeArray(location);
mVAO.release();
}
void reallocateTexCoords(const TexCoords & t, unsigned dims = 2);
void reallocateNormals(const Normals & n, unsigned dims = 3);
/*************************************************************************
* Setters
************************************************************************/
// Draw types like GL_TRIANGLES, GL_POINTS, GL_LINES, etc
void setDrawType(int drawType) { mDrawType = drawType; }
@@ -105,21 +109,24 @@ namespace Qtk {
mVAO.release();
}
inline void enableAttributeArray(int location) {
ShaderBindScope lock(&mProgram, mBound);
mVAO.bind();
mProgram.enableAttributeArray(location);
mVAO.release();
}
/*************************************************************************
* Accessors
************************************************************************/
void reallocateTexCoords(const TexCoords & t, unsigned dims = 2);
/**
* Retrieve a mesh by name stored within static QHash private member
* @param name The name of the MeshRenderer we want to retrieve.
* @return Pointer to the MeshRenderer, or nullptr if not found.
*/
static MeshRenderer * getInstance(const QString & name);
void reallocateNormals(const Normals & n, unsigned dims = 3);
// Static QHash of all mesh objects within the scene
typedef QHash<QString, MeshRenderer *> MeshManager;
Transform3D & getTransform() { return mTransform; }
private:
/*************************************************************************
* Private Members
************************************************************************/
static MeshManager sInstances;
int mDrawType {};

View File

@@ -9,9 +9,9 @@
#include <QFileInfo>
#include <abstractscene.h>
#include <model.h>
#include <resourcemanager.h>
#include <scene.h>
#include <texture.h>
using namespace Qtk;
@@ -97,8 +97,8 @@ void ModelMesh::draw(QOpenGLShaderProgram & shader) {
// Set Model View Projection values
shader.setUniformValue("uModel", mTransform.toMatrix());
shader.setUniformValue("uView", Scene::View());
shader.setUniformValue("uProjection", Scene::Projection());
shader.setUniformValue("uView", Scene::getViewMatrix());
shader.setUniformValue("uProjection", Scene::getProjectionMatrix());
GLuint diffuseCount = 1;
GLuint specularCount = 1;
@@ -180,21 +180,6 @@ void Model::flipTexture(const std::string & fileName, bool flipX, bool flipY) {
* Model Private Member Functions
******************************************************************************/
/**
* Loads a model in .obj, .fbx, .gltf, and other formats
* For a full list of formats see assimp documentation:
* https://github.com/assimp/assimp/blob/master/doc/Fileformats.md
*
* Models should not be loaded into Qt resource system
* Instead pass an *absolute* path to this function
* Relative paths will break if Qtk is executed from different locations
*
* Models can also be loaded from the `qtk/resource` directory using qrc format
* loadModel(":/models/backpack/backpack.obj")
* See resourcemanager.h for more information
*
* @param path Absolute path to a model .obj or other format accepted by assimp
*/
void Model::loadModel(const std::string & path) {
Assimp::Importer import;
@@ -362,7 +347,7 @@ ModelMesh::Textures Model::loadMaterialTextures(
// If the texture has not yet been loaded
if(!skip) {
ModelTexture texture;
texture.mTexture = OpenGLTextureFactory::initTexture2D(
texture.mTexture = OpenGLTextureFactory::initTexture(
std::string(mDirectory + '/' + fileName.C_Str()).c_str(), false,
false);
texture.mID = texture.mTexture->textureId();
@@ -380,7 +365,7 @@ ModelMesh::Textures Model::loadMaterialTextures(
}
void Model::sortModels() {
auto cameraPos = Scene::Camera().transform();
auto cameraPos = Scene::getCamera().getTransform();
auto cameraDistance = [&cameraPos](const ModelMesh & a, const ModelMesh & b) {
// Sort by the first vertex position in the model
return (cameraPos.getTranslation().distanceToPoint(

View File

@@ -28,14 +28,20 @@
#include <transform3D.h>
namespace Qtk {
/**
* 3D models will store this data for each vertex in geometry.
*/
struct QTKAPI ModelVertex {
QVector3D mPosition;
QVector3D mNormal;
QVector2D mTextureCoord;
QVector3D mTangent;
QVector3D mBitangent;
QVector2D mTextureCoord;
};
/**
* Struct to store model textures. 3D Models may have multiple.
*/
struct QTKAPI ModelTexture {
GLuint mID {};
QOpenGLTexture * mTexture {};
@@ -45,14 +51,25 @@ namespace Qtk {
class Model;
/**
* Mesh class specialized for storing 3D model data.
* Eventually this can be consolidated into a more generic class.
*/
class QTKAPI ModelMesh : protected QOpenGLFunctions {
public:
/*************************************************************************
* Typedefs
************************************************************************/
friend Model;
typedef std::vector<ModelVertex> Vertices;
typedef std::vector<GLuint> Indices;
typedef std::vector<ModelTexture> Textures;
// Constructors, Destructors
/*************************************************************************
* Constructors, Destructors
************************************************************************/
ModelMesh(
Vertices vertices, Indices indices, Textures textures,
const char * vertexShader = ":/model-basic.vert",
@@ -68,78 +85,177 @@ namespace Qtk {
~ModelMesh() = default;
private:
void initMesh(const char * vert, const char * frag);
/*************************************************************************
* Public Methods
************************************************************************/
// ModelMesh Private Members
QOpenGLBuffer *mVBO, *mEBO;
QOpenGLVertexArrayObject * mVAO;
QOpenGLShaderProgram * mProgram;
public:
inline void draw() { draw(*mProgram); }
void draw(QOpenGLShaderProgram & shader);
// ModelMesh Public Members
/*************************************************************************
* Public Members
************************************************************************/
Vertices mVertices {};
Indices mIndices {};
Textures mTextures {};
Transform3D mTransform;
private:
/*************************************************************************
* Private Methods
************************************************************************/
void initMesh(const char * vert, const char * frag);
/*************************************************************************
* Private Members
************************************************************************/
QOpenGLBuffer *mVBO, *mEBO;
QOpenGLVertexArrayObject * mVAO;
QOpenGLShaderProgram * mProgram;
};
/**
* Model object that has a ModelMesh.
* Top-level object that represents 3D models stored within a scene.
*/
class QTKAPI Model : public QObject {
Q_OBJECT
public:
/*************************************************************************
* Typedefs
************************************************************************/
/* ModelManager typedef that will manage global model access. */
typedef QHash<QString, Model *> ModelManager;
/*************************************************************************
* Constructors, Destructors
************************************************************************/
// Default model shaders are provided but we can override them in the ctor
inline Model(
const char * name, const char * path,
const char * vertexShader = ":/model-basic.vert",
const char * fragmentShader = ":/model-basic.frag") :
mName(name),
mVertexShader(vertexShader), mFragmentShader(fragmentShader) {
mModelPath(path), mVertexShader(vertexShader),
mFragmentShader(fragmentShader) {
loadModel(path);
}
inline ~Model() override { mManager.remove(mName); }
/*************************************************************************
* Public Methods
************************************************************************/
void draw();
void draw(QOpenGLShaderProgram & shader);
/**
* Flip a texture associated with this model
*
* @param fileName The name of the texture to flip as it is stored on disk
* @param flipX Flip the texture along the X axis
* @param flipY Flip the texture along the Y axis
*/
void flipTexture(
const std::string & fileName, bool flipX = false, bool flipY = true);
/*************************************************************************
* Setters
************************************************************************/
/**
* Sets a uniform value
*
* @tparam T The type of the value we are settings
* @param location The uniform location
* @param value The value to assign to the uniform
*/
template <typename T> void setUniform(const char * location, T value) {
for(auto & mesh : mMeshes) {
mesh.mProgram->bind();
mesh.mProgram->setUniformValue(location, value);
mesh.mProgram->release();
}
}
Transform3D mTransform;
/*************************************************************************
* Accessors
************************************************************************/
/**
* Accessor function for retrieving a ModelMesh globally.
* The mesh is retrieved from the mManager private member.
*
* @param name The name of the model to load as it was constructed.
* @return Pointer to the model stored within the scene.
*/
static Model * getInstance(const char * name);
typedef QHash<QString, Model *> ModelManager;
Transform3D & getTransform() { return mTransform; }
private:
static ModelManager mManager;
/*************************************************************************
* Private Methods
************************************************************************/
/**
* Loads a model in .obj, .fbx, .gltf, and other formats.
* For a full list of formats see assimp documentation:
* https://github.com/assimp/assimp/blob/master/doc/Fileformats.md
*
* Models should not be loaded into Qt resource system.
* Instead pass an *absolute* path to this function.
* Relative paths will break if Qtk is executed from different locations.
*
* Models can also be loaded from the `qtk/resource` directory using qrc
* format loadModel(":/models/backpack/backpack.obj").
* This does not use Qt resource system, it just provides similar syntax
* for accessing files within the same `resources/` directory.
*
* See resourcemanager.h for more information on how this works.
*
* @param path Absolute path to a model in .obj or another format accepted
* by assimp.
*/
void loadModel(const std::string & path);
void processNode(aiNode * node, const aiScene * scene);
ModelMesh processMesh(aiMesh * mesh, const aiScene * scene);
ModelMesh::Textures loadMaterialTextures(
aiMaterial * mat, aiTextureType type, const std::string & typeName);
void sortModels();
// Model Private Members
/*************************************************************************
* Private Members
************************************************************************/
/* The position of this model in 3D space */
Transform3D mTransform;
/* Static QHash used to store and access models globally. */
static ModelManager mManager;
/* Container to store N loaded textures for this model. */
ModelMesh::Textures mTexturesLoaded {};
/* Container to store N loaded meshes for this model. */
std::vector<ModelMesh> mMeshes {};
/* The directory this model and it's textures are stored. */
std::string mDirectory {};
const char *mVertexShader, *mFragmentShader, *mName;
/* File names for shaders and 3D model on disk. */
const char *mVertexShader, *mFragmentShader, *mModelPath;
/* Name of the model object within the scene. */
const char * mName;
};
} // namespace Qtk

View File

@@ -18,12 +18,24 @@
#include <texture.h>
namespace Qtk {
/**
* Object base class for objects that can exist within a scene.
* An object could be a Cube, Skybox, 3D Model, or other standalone entities.
*/
class QTKAPI Object : public QObject {
Q_OBJECT
public:
/*************************************************************************
* Typedefs
************************************************************************/
friend MeshRenderer;
/*************************************************************************
* Constructors / Destructors
************************************************************************/
// Initialize an object with no shape data assigned
explicit Object(const char * name) :
mName(name), mVBO(QOpenGLBuffer::VertexBuffer), mBound(false) {}
@@ -35,19 +47,39 @@ namespace Qtk {
~Object() override = default;
inline const Colors & getColors() { return mShape.mColors; }
/*************************************************************************
* Accessors
************************************************************************/
inline const Indices & getIndexData() { return mShape.mIndices; }
[[nodiscard]] inline const Colors & getColors() const {
return mShape.mColors;
}
inline const Normals & getNormals() { return mShape.mNormals; }
[[nodiscard]] inline const Indices & getIndexData() const {
return mShape.mIndices;
}
[[nodiscard]] inline const Normals & getNormals() const {
return mShape.mNormals;
}
[[nodiscard]] inline const Shape & getShape() const { return mShape; }
inline const TexCoords & getTexCoords() { return mShape.mTexCoords; }
[[nodiscard]] inline const TexCoords & getTexCoords() const {
return mShape.mTexCoords;
}
inline Texture & getTexture() { return mTexture; }
[[nodiscard]] inline const Texture & getTexture() const {
return mTexture;
}
inline const Vertices & getVertices() { return mShape.mVertices; }
[[nodiscard]] inline const Vertices & getVertices() const {
return mShape.mVertices;
}
/*************************************************************************
* Setters
************************************************************************/
virtual inline void setColors(const Colors & value) {
mShape.mColors = value;
@@ -84,6 +116,10 @@ namespace Qtk {
mShape.mVertices = value;
}
/*************************************************************************
* Public Methods
************************************************************************/
virtual inline void bindShaders() {
mBound = true;
mProgram.bind();
@@ -94,21 +130,19 @@ namespace Qtk {
mProgram.release();
}
private:
/*************************************************************************
* Private Members
************************************************************************/
QOpenGLShaderProgram mProgram;
QOpenGLBuffer mVBO, mNBO;
QOpenGLVertexArrayObject mVAO;
Transform3D mTransform;
Shape mShape;
Texture mTexture;
const char * mName;
bool mBound;
private:
virtual inline void setTexture(QOpenGLTexture * value) {
mTexture.setTexture(value);
}
QOpenGLShaderProgram mProgram;
};
} // namespace Qtk

View File

@@ -8,10 +8,10 @@
#include <QKeyEvent>
#include <abstractscene.h>
#include <input.h>
#include <mesh.h>
#include <qtkwidget.h>
#include <scene.h>
using namespace Qtk;
@@ -23,7 +23,6 @@ QtkWidget::QtkWidget() : mScene(Q_NULLPTR), mDebugLogger(Q_NULLPTR) {
initializeWidget();
}
// Constructor for using this widget in QtDesigner
QtkWidget::QtkWidget(QWidget * parent) :
QOpenGLWidget(parent), mScene(Q_NULLPTR), mDebugLogger(Q_NULLPTR) {
initializeWidget();
@@ -41,27 +40,9 @@ QtkWidget::~QtkWidget() {
}
/*******************************************************************************
* Private Member Functions
* Public Inherited Virtual Methods
******************************************************************************/
void QtkWidget::teardownGL() {
// Nothing to teardown yet...
}
/*******************************************************************************
* Inherited Virtual Member Functions
******************************************************************************/
void QtkWidget::paintGL() {
// Clear buffers
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
// Draw the scene first, since it handles drawing our skybox
if(mScene != Q_NULLPTR) {
mScene->draw();
}
}
void QtkWidget::initializeGL() {
initializeOpenGLFunctions();
// Connect the frameSwapped signal to call the update() function
@@ -93,11 +74,19 @@ void QtkWidget::initializeGL() {
}
void QtkWidget::resizeGL(int width, int height) {
Scene::Projection().setToIdentity();
Scene::Projection().perspective(
Scene::getProjectionMatrix().setToIdentity();
Scene::getProjectionMatrix().perspective(
45.0f, float(width) / float(height), 0.1f, 1000.0f);
}
void QtkWidget::paintGL() {
// Clear buffers and draw the scene if it is valid.
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
if(mScene != Q_NULLPTR) {
mScene->draw();
}
}
/*******************************************************************************
* Protected Slots
******************************************************************************/
@@ -175,7 +164,7 @@ void QtkWidget::messageLogged(const QOpenGLDebugMessage & msg) {
}
/*******************************************************************************
* Protected Helpers
* Protected Methods
******************************************************************************/
void QtkWidget::keyPressEvent(QKeyEvent * event) {
@@ -204,7 +193,7 @@ void QtkWidget::mouseReleaseEvent(QMouseEvent * event) {
}
/*******************************************************************************
* Private Helpers
* Private Methods
******************************************************************************/
void QtkWidget::initializeWidget() {
@@ -265,31 +254,31 @@ void QtkWidget::updateCameraInput() {
static const float rotSpeed = 0.5f;
// Handle rotations
Scene::Camera().transform().rotate(
Scene::getCamera().getTransform().rotate(
-rotSpeed * Input::mouseDelta().x(), Camera3D::LocalUp);
Scene::Camera().transform().rotate(
-rotSpeed * Input::mouseDelta().y(), Scene::Camera().right());
Scene::getCamera().getTransform().rotate(
-rotSpeed * Input::mouseDelta().y(), Scene::getCamera().right());
// Handle translations
QVector3D translation;
if(Input::keyPressed(Qt::Key_W)) {
translation += Scene::Camera().forward();
translation += Scene::getCamera().forward();
}
if(Input::keyPressed(Qt::Key_S)) {
translation -= Scene::Camera().forward();
translation -= Scene::getCamera().forward();
}
if(Input::keyPressed(Qt::Key_A)) {
translation -= Scene::Camera().right();
translation -= Scene::getCamera().right();
}
if(Input::keyPressed(Qt::Key_D)) {
translation += Scene::Camera().right();
translation += Scene::getCamera().right();
}
if(Input::keyPressed(Qt::Key_Q)) {
translation -= Scene::Camera().up() / 2.0f;
translation -= Scene::getCamera().up() / 2.0f;
}
if(Input::keyPressed(Qt::Key_E)) {
translation += Scene::Camera().up() / 2.0f;
translation += Scene::getCamera().up() / 2.0f;
}
Scene::Camera().transform().translate(transSpeed * translation);
Scene::getCamera().getTransform().translate(transSpeed * translation);
}
}

View File

@@ -15,60 +15,141 @@
#include <QOpenGLFunctions>
#include <QOpenGLWidget>
#include <abstractscene.h>
#include <qtkapi.h>
#include <scene.h>
namespace Qtk {
/**
* QtkWidget class to define required QOpenGLWidget functionality.
*
* This object has a Scene attached which manages the objects to render.
* Client input is passed through this widget to control the camera view.
*/
class QTKAPI QtkWidget : public QOpenGLWidget, protected QOpenGLFunctions {
Q_OBJECT;
public:
// Constructors
/*************************************************************************
* Contructors / Destructors
************************************************************************/
/**
* Default ctor will configure a QSurfaceFormat with default settings.
*/
QtkWidget();
/**
* Qt Designer will call this ctor when creating this widget as a child.
*
* @param parent The parent QWidget
*/
explicit QtkWidget(QWidget * parent);
/**
* Allow constructing the widget with a preconfigured QSurfaceFormat.
*
* @param format QSurfaceFormat already configured by the caller.
*/
explicit QtkWidget(const QSurfaceFormat & format);
~QtkWidget() override;
private:
void teardownGL();
/*************************************************************************
* Private Methods
************************************************************************/
// clang-format off
void teardownGL() { /* Nothing to teardown yet... */ }
// clang-format on
public:
// Inherited virtual Members
void paintGL() override;
/*************************************************************************
* Public Inherited Virtual Methods
************************************************************************/
/**
* Called when the widget is first constructed.
*/
void initializeGL() override;
/**
* Called when the application window is resized.
*
* @param width The new width of the window.
* @param height The new height of the window.
*/
void resizeGL(int width, int height) override;
/**
* Called when OpenGL repaints the widget.
*/
void paintGL() override;
/*************************************************************************
* Accessors
************************************************************************/
inline Qtk::Scene * getScene() { return mScene; }
/*************************************************************************
* Setters
************************************************************************/
inline void setScene(Qtk::Scene * scene) {
delete mScene;
mScene = scene;
}
protected slots:
/*************************************************************************
* Qt Slots
************************************************************************/
/**
* Called when the `frameSwapped` signal is caught.
* See definition of initializeGL()
*/
void update();
#ifdef QTK_DEBUG
/**
* Called when the `messageLogged` signal is caught.
* See definition of initializeGL()
*
* @param msg The message logged.
*/
static void messageLogged(const QOpenGLDebugMessage & msg);
#endif
// Protected Helpers
protected:
/*************************************************************************
* Protected Methods
************************************************************************/
void keyPressEvent(QKeyEvent * event) override;
void keyReleaseEvent(QKeyEvent * event) override;
void mousePressEvent(QMouseEvent * event) override;
void mouseReleaseEvent(QMouseEvent * event) override;
private:
// Private helpers
/*************************************************************************
* Private Methods
************************************************************************/
void initializeWidget();
static void updateCameraInput();
Qtk::Scene * mScene;
#ifdef QTK_DEBUG
void printContextInformation();
QOpenGLDebugLogger * mDebugLogger;
#endif
/*************************************************************************
* Private Members
************************************************************************/
Qtk::Scene * mScene;
};
} // namespace Qtk

View File

@@ -6,9 +6,9 @@
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
##############################################################################*/
#include <abstractscene.h>
#include <camera3d.h>
#include <resourcemanager.h>
#include <scene.h>
#include <texture.h>
using namespace Qtk;
@@ -21,8 +21,8 @@ QMatrix4x4 Scene::mProjection;
******************************************************************************/
Scene::Scene() {
mCamera.transform().setTranslation(0.0f, 0.0f, 20.0f);
mCamera.transform().setRotation(-5.0f, 0.0f, 1.0f, 0.0f);
mCamera.getTransform().setTranslation(0.0f, 0.0f, 20.0f);
mCamera.getTransform().setRotation(-5.0f, 0.0f, 1.0f, 0.0f);
}
Scene::~Scene() {
@@ -32,11 +32,10 @@ Scene::~Scene() {
for(auto & model : mModels) {
delete model;
}
delete mSkybox;
}
void Scene::privDraw() {
void Scene::privateDraw() {
if(!mInit) {
initializeOpenGLFunctions();
init();

125
src/scene.h Normal file
View File

@@ -0,0 +1,125 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: Classes for managing objects and data within a scene ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
##############################################################################*/
#ifndef QTK_SCENE_H
#define QTK_SCENE_H
#include <camera3d.h>
#include <meshrenderer.h>
#include <model.h>
#include <skybox.h>
#include <QMatrix4x4>
namespace Qtk {
/**
* An abstract Scene class to inherit from when building new scenes.
*
* This class provides the following objects to any inheriting scene:
* Skybox, Camera
* This class also provides containers for N instances of these objects:
* MeshRenderers, Models
*
* To inherit from this class and define our own scene we must:
*
* Override and define the `init()` virtual member function. If we want our
* scene to render using a Skybox, we should also initialize the mSkybox
* member within the overridden definition of `init()` using
* `Scene::setSkybox(...)`
*
* If the scene is to render any kind of movement we are required to override
* the `update()` virtual method.
*
* If the child scene adds any objects which are not managed (drawn) by this
* base class, the child scene class must also override the `draw()` method.
*/
class Scene : protected QOpenGLFunctions {
public:
/*************************************************************************
* Contructors / Destructors
************************************************************************/
Scene();
~Scene();
/*************************************************************************
* Public Methods
************************************************************************/
/**
* Initialize objects within the scene
*/
virtual void init() = 0;
/**
* Function called during OpenGL drawing event.
*
* This function is only called when the widget is redrawn.
*/
virtual void draw() { privateDraw(); };
/**
* Function called to update the QOpenGLWidget. Does not trigger a redraw.
*
* Calling this several times will still result in only one repaint.
*/
virtual void update() {}
/*************************************************************************
* Accessors
************************************************************************/
static Camera3D & getCamera() { return mCamera; }
static QMatrix4x4 getViewMatrix() { return mCamera.toMatrix(); }
static QMatrix4x4 & getProjectionMatrix() { return mProjection; }
inline Skybox * getSkybox() { return mSkybox; }
/*************************************************************************
* Setters
************************************************************************/
inline void setSkybox(Skybox * skybox) { mSkybox = skybox; }
private:
/*************************************************************************
* Private Members
************************************************************************/
static Camera3D mCamera;
static QMatrix4x4 mProjection;
bool mInit = false;
/*************************************************************************
* Private Methods
************************************************************************/
/**
* Handles drawing members encapsulated by this base class.
* Child classes do not need to draw these objects manually.
*/
void privateDraw();
protected:
/*************************************************************************
* Protected Members
************************************************************************/
/* The skybox for this scene. */
Skybox * mSkybox {};
/* MeshRenderers used simple geometry. */
std::vector<MeshRenderer *> mMeshes {};
/* Models used for storing 3D models in the scene. */
std::vector<Model *> mModels {};
};
} // namespace Qtk
#endif // QTK_SCENE_H

View File

@@ -6,7 +6,7 @@
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
##############################################################################*/
#include <abstractscene.h>
#include <scene.h>
#include <skybox.h>
#include <texture.h>
@@ -32,8 +32,8 @@ Skybox::Skybox(const std::string & name) :
":/right.png", ":/top.png", ":/front.png", ":/left.png", ":/bottom.png",
":/back.png", name) {}
Skybox::Skybox(QOpenGLTexture * cubeMap, const std::string & name) :
mTexture(cubeMap) {
Skybox::Skybox(QOpenGLTexture * cubeMap, const std::string & name) {
mTexture.setTexture(cubeMap);
init();
}
@@ -49,8 +49,8 @@ void Skybox::draw() {
mProgram.bind();
mTexture.getOpenGLTexture().bind();
mProgram.setUniformValue("uProjectionMatrix", Scene::Projection());
mProgram.setUniformValue("uViewMatrix", Scene::Camera().toMatrix());
mProgram.setUniformValue("uProjectionMatrix", Scene::getProjectionMatrix());
mProgram.setUniformValue("uViewMatrix", Scene::getCamera().toMatrix());
mProgram.setUniformValue("uTexture", 0);
glDrawElements(
GL_TRIANGLES, mIndices.size(), GL_UNSIGNED_INT, mIndices.data());

View File

@@ -21,13 +21,23 @@
#include <texture.h>
namespace Qtk {
/**
* Skybox object for rendering a skybox within a Scene.
* A skybox is typically implemented using a cube map texture centered around
* the camera and projected outwards in all directions.
*/
class QTKAPI Skybox : protected QOpenGLFunctions {
public:
/*************************************************************************
* Constructors / Destructors
************************************************************************/
// Delegate this constructor to use default skybox images
explicit Skybox(const std::string & name = "Skybox");
explicit Skybox(
QOpenGLTexture * cubeMap, const std::string & name = "Skybox");
// Constructor, Destructor
Skybox(
const std::string & right, const std::string & top,
const std::string & front, const std::string & left,
@@ -36,11 +46,23 @@ namespace Qtk {
~Skybox() = default;
/*************************************************************************
* Public Methods
************************************************************************/
void draw();
private:
/*************************************************************************
* Private Methods
************************************************************************/
void init();
/*************************************************************************
* Private Members
************************************************************************/
Vertices mVertices {};
Indices mIndices {};

View File

@@ -28,7 +28,7 @@ QImage * OpenGLTextureFactory::initImage(
return loadedImage;
}
QOpenGLTexture * OpenGLTextureFactory::initTexture2D(
QOpenGLTexture * OpenGLTextureFactory::initTexture(
const char * texture, bool flipX, bool flipY) {
QImage * image = initImage(texture, flipX, flipY);
auto newTexture = new QOpenGLTexture(QOpenGLTexture::Target2D);

View File

@@ -9,30 +9,124 @@
#ifndef QTOPENGL_TEXTURE_H
#define QTOPENGL_TEXTURE_H
#include <QOpenGLShaderProgram>
#include <QOpenGLTexture>
#include <utility>
#include <qtkapi.h>
namespace Qtk {
/**
* Binds shader programs until the end of scope.
* Does nothing if the shader program was already bound.
*
* See MeshRenderer::setUniform() for example.
*/
class QTKAPI ShaderBindScope {
public:
/*************************************************************************
* Constructors / Destructors
************************************************************************/
explicit ShaderBindScope(
QOpenGLShaderProgram * program, bool was_locked) :
mWasBound(was_locked) {
mProgram = program;
if(!mWasBound) {
mProgram->bind();
}
}
~ShaderBindScope() {
if(!mWasBound) {
mProgram->release();
}
}
private:
/*************************************************************************
* Private Members
************************************************************************/
QOpenGLShaderProgram * mProgram;
bool mWasBound;
};
/**
* Factories for initializing various OpenGL textures
*/
class QTKAPI OpenGLTextureFactory {
public:
/*************************************************************************
* Constructors / Destructors
************************************************************************/
~OpenGLTextureFactory() = default;
// QImage
/*************************************************************************
* Texture Factories
************************************************************************/
/**
* QImage factory
*
* @param image Path to image we want to load.
* Can be absolute or Qt resource path.
* @param flipX If true the image will be flipped on X axis.
* @param flipY If true the image will be flipped on Y axis.
* @return Pointer to an initialized QImage object.
*/
static QImage * initImage(
const char * image, bool flipX = false, bool flipY = false);
// 2D Texture
static QOpenGLTexture * initTexture2D(
/**
* QOpenGLTexture factory
*
* @param texture Path to texture we want to load.
* Can be absolute or Qt resource path.
* @param flipX If true the image will be flipped on X axis.
* @param flipY If true the image will be flipped on Y axis.
* @return Pointer to an initialized QOpenGLTexture object.
*/
static QOpenGLTexture * initTexture(
const char * texture, bool flipX = false, bool flipY = false);
// Cube maps
/**
* Cube map factory for initializing all sides of a CubeMap.
* All of these parameters can be absolute or Qt resource paths.
*
* @param right Path to image for the right side of the CubeMap.
* @param top Path to image for the top side of the CubeMap.
* @param front Path to image for the front side of the CubeMap.
* @param left Path to image for the left side of the CubeMap.
* @param bottom Path to image for the bottom side of the CubeMap.
* @param back Path to image for the back side of the CubeMap.
* @return Pointer to an initialized QOpenGLTexture object.
*/
static QOpenGLTexture * initCubeMap(
const QImage & right, const QImage & top, const QImage & front,
const QImage & left, const QImage & bottom, const QImage & back);
// Overloads for cube map initialization
/**
* CubeMap factory for tiling the same image on all sides.
*
* @param tile Path to the image we want to make into a CubeMap.
* Can be absolute or Qt resource path.
* @return Pointer to an initialized QOpenGLTexture object.
*/
static QOpenGLTexture * initCubeMap(const char * tile);
/**
* Cube map factory for initializing all sides of a CubeMap.
* All of these parameters can be absolute or Qt resource paths.
*
* @param right Path to image for the right side of the CubeMap.
* @param top Path to image for the top side of the CubeMap.
* @param front Path to image for the front side of the CubeMap.
* @param left Path to image for the left side of the CubeMap.
* @param bottom Path to image for the bottom side of the CubeMap.
* @param back Path to image for the back side of the CubeMap.
* @return Pointer to an initialized QOpenGLTexture object.
*/
static QOpenGLTexture * initCubeMap(
const char * right, const char * top, const char * front,
const char * left, const char * bottom, const char * back);
@@ -42,48 +136,66 @@ namespace Qtk {
OpenGLTextureFactory() = default;
};
// TODO: Struct for (re)storing texture state
/**
* Texture object component class
*
* TODO: Struct for (re)storing texture state
* A struct to store flipX, flipY and other initial state needed to copy
*/
class Texture {
public:
/*************************************************************************
* Typedefs
************************************************************************/
friend class Skybox;
/*************************************************************************
* Constructors / Destructors
************************************************************************/
Texture() = default;
Texture(const Texture & value) {
mOpenGLTexture = OpenGLTextureFactory::initTexture2D(value.mPath);
mOpenGLTexture = OpenGLTextureFactory::initTexture(value.mPath);
mPath = value.mPath;
}
explicit Texture(
const char * path, bool flipX = false, bool flipY = false) :
mOpenGLTexture(
OpenGLTextureFactory::initTexture2D(path, flipX, flipY)),
mOpenGLTexture(OpenGLTextureFactory::initTexture(path, flipX, flipY)),
mPath(path) {}
explicit Texture(QOpenGLTexture * texture) : mOpenGLTexture(texture) {}
~Texture() { mOpenGLTexture->destroy(); }
/*************************************************************************
* Accessors
************************************************************************/
[[nodiscard]] inline QOpenGLTexture & getOpenGLTexture() const {
return *mOpenGLTexture;
}
[[nodiscard]] inline std::string getPath() const { return mPath; }
/*************************************************************************
* Setters
************************************************************************/
void setTexture(
const std::string & path, bool flipX = false, bool flipY = false) {
mOpenGLTexture =
OpenGLTextureFactory::initTexture2D(path.data(), flipX, flipY);
OpenGLTextureFactory::initTexture(path.data(), flipX, flipY);
mPath = path.data();
}
void setTexture(
const char * path, bool flipX = false, bool flipY = false) {
mOpenGLTexture =
OpenGLTextureFactory::initTexture2D(path, flipX, flipY);
mOpenGLTexture = OpenGLTextureFactory::initTexture(path, flipX, flipY);
mPath = path;
}
// TODO: This is unsafe because we don't have a path. Encapsulate it.
inline void setTexture(QOpenGLTexture * texture) {
mOpenGLTexture = texture;
}
virtual inline void setCubeMap(const char * path) {
mOpenGLTexture = OpenGLTextureFactory::initCubeMap(path);
mPath = path;
@@ -103,12 +215,24 @@ namespace Qtk {
right, top, front, left, bottom, back);
}
/*************************************************************************
* Public Methods
************************************************************************/
[[nodiscard]] inline bool hasTexture() const {
return mOpenGLTexture != Q_NULLPTR;
}
private:
/*************************************************************************
* Private Members
************************************************************************/
inline void setTexture(QOpenGLTexture * texture) {
mOpenGLTexture = texture;
}
QOpenGLTexture * mOpenGLTexture = Q_NULLPTR;
/* Path to this texture on disk or Qt resource. */
const char * mPath {};
};

View File

@@ -23,15 +23,22 @@
#include <qtkapi.h>
namespace Qtk {
/**
* Transform3D class to represent and modify object position in 3D space.
*/
class QTKAPI Transform3D {
public:
// Constructors
/*************************************************************************
* Constructors, Destructors
************************************************************************/
inline Transform3D() :
m_dirty(true), mScale(1.0f, 1.0f, 1.0f),
mTranslation(0.0f, 0.0f, 0.0f) {}
//
// Transformations
/*************************************************************************
* Transformations
************************************************************************/
void translate(const QVector3D & dt);
@@ -72,8 +79,9 @@ namespace Qtk {
grow(QVector3D(factor, factor, factor));
}
//
// Setters
/*************************************************************************
* Setters
************************************************************************/
// Set object position
void setTranslation(const QVector3D & t);
@@ -102,8 +110,9 @@ namespace Qtk {
setRotation(QQuaternion::fromAxisAndAngle(ax, ay, az, angle));
}
//
// Accessors
/*************************************************************************
* Getters
************************************************************************/
[[nodiscard]] inline const QVector3D & getTranslation() const {
return mTranslation;
@@ -121,9 +130,17 @@ namespace Qtk {
[[nodiscard]] QVector3D getUp() const;
[[nodiscard]] QVector3D getRight() const;
/*************************************************************************
* Public members
************************************************************************/
static const QVector3D LocalForward, LocalUp, LocalRight;
private:
/*************************************************************************
* Private members
************************************************************************/
QVector3D mTranslation;
QQuaternion mRotation;
QVector3D mScale;