Doxygen comments

This commit is contained in:
Shaun Reed 2022-11-26 18:24:38 +00:00
parent 443c09da7c
commit a04ebae42a
30 changed files with 1398 additions and 815 deletions

View File

@ -1,8 +1,5 @@
---
# clang-format off
BasedOnStyle: Google
# clang-format on
AlignAfterOpenBracket: AlwaysBreak
AlignArrayOfStructures: Left
AlignConsecutiveAssignments: None

View File

@ -30,8 +30,8 @@ option(QTK_DEBUG "Enable debugger" ON)
message(STATUS "[Qtk] Compiling with QTK_DEBUG=${QTK_DEBUG}")
option(QTK_UPDATE_SUBMODULES "Update external project (assimp) submodule" ON)
message(
STATUS
"[Qtk] Compiling with QTK_UPDATE_SUBMODULES=${QTK_UPDATE_SUBMODULES}"
STATUS
"[Qtk] Compiling with QTK_UPDATE_SUBMODULES=${QTK_UPDATE_SUBMODULES}"
)
# Qt options
@ -55,7 +55,7 @@ list(APPEND CMAKE_PREFIX_PATH "${QT_DIR}")
# Find Qt
find_package(Qt6 COMPONENTS OpenGLWidgets)
if (NOT Qt6_FOUND)
if(NOT Qt6_FOUND)
message(
SEND_ERROR "[Qtk] Error: Unable to find Qt6 at CMAKE_PREFIX_PATH: "
"${CMAKE_PREFIX_PATH}"
@ -68,7 +68,7 @@ if (NOT Qt6_FOUND)
)
endif()
if (QTK_UPDATE_SUBMODULES)
if(QTK_UPDATE_SUBMODULES)
message(STATUS "[Qtk] Updating submodules...")
include("${CMAKE_SOURCE_DIR}/cmake/include/git_submodule.cmake")
submodule_update("${CMAKE_CURRENT_SOURCE_DIR}/extern/assimp/assimp/")
@ -83,34 +83,34 @@ endif()
################################################################################
set(
PUBLIC_HEADERS
src/qtkwidget.h
src/abstractscene.h
src/camera3d.h
src/mesh.h
src/meshrenderer.h
src/model.h
src/object.h
src/skybox.h
src/texture.h
src/transform3D.h
PUBLIC_HEADERS
src/qtkwidget.h
src/scene.h
src/camera3d.h
src/mesh.h
src/meshrenderer.h
src/model.h
src/object.h
src/skybox.h
src/texture.h
src/transform3D.h
)
set(
SOURCE_FILES
src/qtkwidget.cpp
src/abstractscene.cpp
src/camera3d.cpp
src/input.cpp
src/input.h
src/mesh.cpp
src/meshrenderer.cpp
src/model.cpp
src/object.cpp
src/qtkapi.h
src/skybox.cpp
src/texture.cpp
src/transform3D.cpp
SOURCE_FILES
src/qtkwidget.cpp
src/scene.cpp
src/camera3d.cpp
src/input.cpp
src/input.h
src/mesh.cpp
src/meshrenderer.cpp
src/model.cpp
src/object.cpp
src/qtkapi.h
src/skybox.cpp
src/texture.cpp
src/transform3D.cpp
)
include(GenerateExportHeader)
@ -118,7 +118,8 @@ include(GenerateExportHeader)
add_library(qtk-widget STATIC ${PUBLIC_HEADERS} ${SOURCE_FILES})
target_include_directories(qtk-widget PRIVATE src/ app/)
set_target_properties(qtk-widget PROPERTIES
set_target_properties(
qtk-widget PROPERTIES
PUBLIC_HEADER "${PUBLIC_HEADERS}"
VERSION ${PROJECT_VERSION}
)
@ -126,7 +127,7 @@ set_target_properties(qtk-widget PROPERTIES
target_link_libraries(qtk-widget PUBLIC Qt6::OpenGLWidgets)
target_link_libraries(qtk-widget PUBLIC Qt6::Widgets)
if (QTK_UPDATE_SUBMODULES OR NOT ASSIMP_NEW_INTERFACE)
if(QTK_UPDATE_SUBMODULES OR NOT ASSIMP_NEW_INTERFACE)
target_link_libraries(qtk-widget PUBLIC assimp)
elseif(ASSIMP_NEW_INTERFACE)
target_link_libraries(qtk-widget PUBLIC assimp::assimp)
@ -144,7 +145,8 @@ if(WIN32)
endif()
# Install files
install(TARGETS qtk-widget
install(
TARGETS qtk-widget
# Associate qtk-widget target with qtk-export
EXPORT qtk-export
# <prefix>/bin on DLL systems and <prefix>/lib on non-dll systems
@ -157,7 +159,8 @@ install(TARGETS qtk-widget
# Install export
# qtkTargets.cmake will only be installed when one of the CONFIGURATIONS is installed
# + The generated import will only reference that qtk configuration
install(EXPORT qtk-export
install(
EXPORT qtk-export
FILE qtkTargets.cmake
CONFIGURATIONS Debug|Release
DESTINATION ${CMAKE_INSTALL_PREFIX}/cmake
@ -175,9 +178,14 @@ configure_file(
)
# Add our Qt resources.qrc file to our application
set(QTK_APP_SOURCES app/main.cpp
app/examplescene.cpp app/examplescene.h
app/mainwindow.cpp app/mainwindow.h app/mainwindow.ui
set(
QTK_APP_SOURCES
app/main.cpp
app/examplescene.cpp
app/examplescene.h
app/mainwindow.cpp
app/mainwindow.h
app/mainwindow.ui
app/resourcemanager.h
src/qtkresources.h.in
)
@ -189,13 +197,15 @@ target_include_directories(qtk-main PRIVATE src/ app/)
# Link qtk-main executable to main qtk-widget library
target_link_libraries(qtk-main PUBLIC qtk-widget)
set_target_properties(qtk-main PROPERTIES
set_target_properties(
qtk-main PROPERTIES
WIN32_EXECUTABLE TRUE
MACOSX_BUNDLE TRUE
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
)
install(TARGETS qtk-main
install(
TARGETS qtk-main
BUNDLE DESTINATION .
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
@ -206,17 +216,18 @@ if(WIN32)
execute_process(COMMAND "${_qt6_qmake_location}" -query QT_INSTALL_PREFIX RESULT_VARIABLE return_code OUTPUT_VARIABLE qt6_install_prefix OUTPUT_STRIP_TRAILING_WHITESPACE)
file(TO_NATIVE_PATH "${qt6_install_prefix}/bin" qt6_install_prefix)
if(TARGET Qt6::windeployqt)
add_custom_command(TARGET qtk-main
add_custom_command(
TARGET qtk-main
POST_BUILD
COMMAND set PATH=%PATH%$<SEMICOLON>${qt6_install_prefix}
COMMAND Qt6::windeployqt --dir "${CMAKE_BINARY_DIR}/windeployqt" "$<TARGET_FILE_DIR:qtk-main>/$<TARGET_FILE_NAME:qtk-main>"
)
)
install(DIRECTORY "${CMAKE_BINARY_DIR}/windeployqt/" DESTINATION bin)
endif()
if(MSVC AND TARGET Qt6::qmake)
set(VSUSER_FILE ${CMAKE_CURRENT_BINARY_DIR}/qtk-main.vcxproj.user)
file(TO_NATIVE_PATH "${CMAKE_BINARY_DIR}/extern/assimp/assimp/bin" assimp_bin)
file(WRITE ${VSUSER_FILE} "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n")
file(WRITE ${VSUSER_FILE} "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n")
file(APPEND ${VSUSER_FILE} "<Project xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n")
file(APPEND ${VSUSER_FILE} " <PropertyGroup>\n")
file(APPEND ${VSUSER_FILE} " <LocalDebuggerEnvironment>Path=$(SolutionDir)\\lib\\$(Configuration);${qt6_install_prefix};${assimp_bin};$(Path)\n")

View File

@ -2,7 +2,6 @@
[![All Builds](https://github.com/shaunrd0/qtk/actions/workflows/all-builds.yml/badge.svg)](https://github.com/shaunrd0/qtk/actions/workflows/all-builds.yml)
[![Linting](https://github.com/shaunrd0/qtk/actions/workflows/linting.yml/badge.svg)](https://github.com/shaunrd0/qtk/actions/workflows/linting.yml)
Practice project for learning about using OpenGL in Qt widget applications.
Model loader using [Assimp](https://assimp.org/) within a Qt widget application.
You can import your own models within `app/examplescene.cpp`, inside the
@ -12,6 +11,41 @@ happen in `ExampleScene::update()`.
To get textures loading on models look into [material files](http://www.paulbourke.net/dataformats/mtl/)
and see some examples in the `resources/models/` directory.
The syntax for adding shapes and models is seen in the example below.
This would result in a scene with a red cube and a miniature spartan model placed on top.
```C++
// From: qtk/app/examplescene.cpp
void ExampleScene::init() {
// Add a skybox to the scene using default cube map images and settings.
setSkybox(new Qtk::Skybox("Skybox"));
/* Create a red cube with a mini master chief on top. */
auto myCube = new MeshRenderer("My cube", Cube(Qtk::QTK_DRAW_ELEMENTS));
myCube->setColor(RED);
mMeshes.push_back(myCube);
auto mySpartan = new Model("My spartan", ":/models/spartan/spartan.obj");
mySpartan->getTransform().setTranslation(0.0f, 0.5f, 0.0f);
mySpartan->getTransform().setScale(0.5f);
mModels.push_back(mySpartan);
}
```
If we want to make our spartan spin, we need to apply rotation in `update`
```C++
// From: qtk/app/examplescene.cpp
void ExampleScene::update() {
auto mySpartan = Model::getInstance("My spartan");
mySpartan->getTransform().rotate(0.75f, 0.0f, 1.0f, 0.0f);
auto myCube = MeshRenderer::getInstance("My cube");
myCube->getTransform().rotate(-0.75f, 0.0f, 1.0f, 0.0f);
}
```
### Source Builds
@ -132,7 +166,6 @@ Spartan with normals -
### QtkWidget in Qt Creator
The `QtkWidget` class is exported as a shared library for use in Qt Creator's design mode.
We can add more QtkWidgets to view and render the scene from multiple perspectives.
There is still some work to be done here, so there isn't a builtin way to add an additional view within the application.

View File

@ -6,12 +6,12 @@
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
##############################################################################*/
#include <abstractscene.h>
#include <camera3d.h>
#include <examplescene.h>
#include <meshrenderer.h>
#include <model.h>
#include <resourcemanager.h>
#include <scene.h>
#include <texture.h>
using namespace Qtk;
@ -21,8 +21,8 @@ using namespace Qtk;
******************************************************************************/
ExampleScene::ExampleScene() {
Camera().transform().setTranslation(0.0f, 0.0f, 20.0f);
Camera().transform().setRotation(-5.0f, 0.0f, 1.0f, 0.0f);
getCamera().getTransform().setTranslation(0.0f, 0.0f, 20.0f);
getCamera().getTransform().setRotation(-5.0f, 0.0f, 1.0f, 0.0f);
}
ExampleScene::~ExampleScene() {
@ -44,50 +44,152 @@ ExampleScene::~ExampleScene() {
******************************************************************************/
void ExampleScene::init() {
auto * sb = new Qtk::Skybox("Skybox");
setSkybox(sb);
// Add a skybox to the scene using default cube map images and settings.
setSkybox(new Qtk::Skybox("Skybox"));
// Initialize Phong example cube
/* Create a red cube with a mini master chief on top. */
auto myCube = new MeshRenderer("My cube", Cube(Qtk::QTK_DRAW_ELEMENTS));
myCube->setColor(RED);
mMeshes.push_back(myCube);
auto mySpartan = new Model("My spartan", ":/models/spartan/spartan.obj");
mySpartan->getTransform().setTranslation(0.0f, 0.5f, 0.0f);
mySpartan->getTransform().setScale(0.5f);
mModels.push_back(mySpartan);
//
// Create simple shapes using MeshRenderer class and data in mesh.h
mMeshes.push_back(
new Qtk::MeshRenderer("rightTriangle", Triangle(QTK_DRAW_ELEMENTS)));
mMeshes.back()->getTransform().setTranslation(-5.0f, 0.0f, -2.0f);
mMeshes.push_back(
new Qtk::MeshRenderer("centerCube", Cube(QTK_DRAW_ELEMENTS)));
mMeshes.back()->getTransform().setTranslation(-7.0f, 0.0f, -2.0f);
mMeshes.push_back(
new Qtk::MeshRenderer("leftTriangle", Triangle(QTK_DRAW_ELEMENTS)));
mMeshes.back()->getTransform().setTranslation(-9.0f, 0.0f, -2.0f);
mMeshes.back()->setDrawType(GL_LINE_LOOP);
mMeshes.push_back(
new Qtk::MeshRenderer("topTriangle", Triangle(QTK_DRAW_ELEMENTS)));
mMeshes.back()->getTransform().setTranslation(-7.0f, 2.0f, -2.0f);
mMeshes.back()->getTransform().scale(0.25f);
mMeshes.push_back(
new Qtk::MeshRenderer("bottomTriangle", Triangle(QTK_DRAW_ELEMENTS)));
mMeshes.back()->getTransform().setTranslation(-7.0f, -2.0f, -2.0f);
mMeshes.back()->getTransform().scale(0.25f);
mMeshes.back()->setDrawType(GL_LINE_LOOP);
mMeshes.back()->setColor(GREEN);
//
// 3D Model loading
mModels.push_back(
new Qtk::Model("backpack", ":/models/backpack/backpack.obj"));
// Sometimes model textures need flipped in certain directions
mModels.back()->flipTexture("diffuse.jpg", false, true);
mModels.back()->getTransform().setTranslation(0.0f, 0.0f, -10.0f);
mModels.push_back(new Qtk::Model("bird", ":/models/bird/bird.obj"));
mModels.back()->getTransform().setTranslation(2.0f, 2.0f, -10.0f);
// Sometimes the models are very large
mModels.back()->getTransform().scale(0.0025f);
mModels.back()->getTransform().rotate(-110.0f, 0.0f, 1.0f, 0.0f);
mModels.push_back(new Qtk::Model("lion", ":/models/lion/lion.obj"));
mModels.back()->getTransform().setTranslation(-3.0f, -1.0f, -10.0f);
mModels.back()->getTransform().scale(0.15f);
mModels.push_back(
new Qtk::Model("alien", ":/models/alien-hominid/alien.obj"));
mModels.back()->getTransform().setTranslation(2.0f, -1.0f, -5.0f);
mModels.back()->getTransform().scale(0.15f);
mModels.push_back(new Qtk::Model("scythe", ":/models/scythe/scythe.obj"));
mModels.back()->getTransform().setTranslation(-6.0f, 0.0f, -10.0f);
mModels.back()->getTransform().rotate(-90.0f, 1.0f, 0.0f, 0.0f);
mModels.back()->getTransform().rotate(90.0f, 0.0f, 1.0f, 0.0f);
mModels.push_back(
new Qtk::Model("masterChief", ":/models/spartan/spartan.obj"));
mModels.back()->getTransform().setTranslation(-1.5f, 0.5f, -2.0f);
//
// Simple cube lighting examples.
/* Phong lighting example on a basic cube. */
mTestPhong = new Qtk::MeshRenderer("phong", Qtk::Cube());
mTestPhong->mTransform.setTranslation(3.0f, 0.0f, -2.0f);
mTestPhong->getTransform().setTranslation(3.0f, 0.0f, -2.0f);
// NOTE: You no longer need to manually bind shader program to set uniforms.
// + You can still bind it if you want to for performance reasons.
// + Qtk will only bind / release if the shader program is not already bound.
mTestPhong->setShaders(":/solid-phong.vert", ":/solid-phong.frag");
// You no longer need to manually bind shader program.
// + But, you can still bind it if you want to.
// For example this would technically not be efficient, because each one of
// these calls will bind, set, release. We could instead bind, set N uniforms,
// and release when we are finished.
// mTestPhong->bindShaders();
mTestPhong->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f));
mTestPhong->setUniform("uLightColor", QVector3D(1.0f, 1.0f, 1.0f));
mTestPhong->setUniform("uAmbientStrength", 0.2f);
mTestPhong->setUniform("uSpecularStrength", 0.50f);
mTestPhong->setUniform("uSpecularShine", 256);
mTestPhong->reallocateNormals(mTestPhong->getNormals());
// mTestPhong->releaseShaders();
mTestPhong->reallocateNormals(mTestPhong->getNormals());
// NOTE: This is only an example and I won't worry about this kind of
// efficiency while initializing the following objects.
// Initialize Ambient example cube
// Phong lighting example light source. This is just for visual reference.
// + We refer to the position of this object in draw() to update lighting.
mMeshes.push_back(
new Qtk::MeshRenderer("phongLight", Triangle(QTK_DRAW_ELEMENTS)));
mMeshes.back()->getTransform().setTranslation(3.0f, 2.0f, -2.0f);
mMeshes.back()->getTransform().scale(0.25f);
/* Example of a cube with no lighting applied */
mMeshes.push_back(new Qtk::MeshRenderer("noLight", Cube(QTK_DRAW_ELEMENTS)));
mMeshes.back()->getTransform().setTranslation(5.0f, 0.0f, -2.0f);
mMeshes.back()->setShaders(
":/solid-perspective.vert", ":/solid-perspective.frag");
mMeshes.back()->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f));
// No light source needed for this lighting technique
/* Initialize Ambient example cube */
mTestAmbient = new Qtk::MeshRenderer("ambient", Cube());
mTestAmbient->mTransform.setTranslation(7.0f, 0.0f, -2.0f);
mTestAmbient->getTransform().setTranslation(7.0f, 0.0f, -2.0f);
mTestAmbient->setShaders(":/solid-ambient.vert", ":/solid-ambient.frag");
mTestAmbient->init();
// Changing these uniform values will alter lighting effects.
mTestAmbient->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f));
mTestAmbient->setUniform("uLightColor", QVector3D(1.0f, 1.0f, 1.0f));
mTestAmbient->setUniform("uAmbientStrength", 0.2f);
mTestAmbient->reallocateNormals(mTestAmbient->getNormals());
// No light source needed for this lighting technique
// Initialize Diffuse example cube
/* Initialize Diffuse example cube */
mTestDiffuse = new Qtk::MeshRenderer("diffuse", Cube());
mTestDiffuse->mTransform.setTranslation(9.0f, 0.0f, -2.0f);
mTestDiffuse->getTransform().setTranslation(9.0f, 0.0f, -2.0f);
mTestDiffuse->setShaders(":/solid-diffuse.vert", ":/solid-diffuse.frag");
mTestDiffuse->init();
mTestDiffuse->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f));
mTestDiffuse->setUniform("uLightColor", QVector3D(1.0f, 1.0f, 1.0f));
mTestDiffuse->setUniform("uAmbientStrength", 0.2f);
mTestDiffuse->reallocateNormals(mTestDiffuse->getNormals());
// Initialize Specular example cube
// Diffuse lighting example light source. This is just for visual reference.
mMeshes.push_back(
new Qtk::MeshRenderer("diffuseLight", Triangle(QTK_DRAW_ELEMENTS)));
mMeshes.back()->getTransform().setTranslation(9.0f, 2.0f, -2.0f);
mMeshes.back()->getTransform().scale(0.25f);
/* Initialize Specular example cube */
mTestSpecular = new Qtk::MeshRenderer("specular", Cube());
mTestSpecular->mTransform.setTranslation(11.0f, 0.0f, -2.0f);
mTestSpecular->getTransform().setTranslation(11.0f, 0.0f, -2.0f);
mTestSpecular->setShaders(":/solid-specular.vert", ":/solid-specular.frag");
mTestSpecular->init();
mTestSpecular->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f));
mTestSpecular->setUniform("uLightColor", QVector3D(1.0f, 1.0f, 1.0f));
mTestSpecular->setUniform("uAmbientStrength", 0.2f);
@ -95,105 +197,18 @@ void ExampleScene::init() {
mTestSpecular->setUniform("uSpecularShine", 256);
mTestSpecular->reallocateNormals(mTestSpecular->getNormals());
//
// Model loading
mModels.push_back(
new Qtk::Model("backpack", ":/models/backpack/backpack.obj"));
// Sometimes model textures need flipped in certain directions
mModels.back()->flipTexture("diffuse.jpg", false, true);
mModels.back()->mTransform.setTranslation(0.0f, 0.0f, -10.0f);
mModels.push_back(new Qtk::Model("bird", ":/models/bird/bird.obj"));
mModels.back()->mTransform.setTranslation(2.0f, 2.0f, -10.0f);
// Sometimes the models are very large
mModels.back()->mTransform.scale(0.0025f);
mModels.back()->mTransform.rotate(-110.0f, 0.0f, 1.0f, 0.0f);
mModels.push_back(new Qtk::Model("lion", ":/models/lion/lion.obj"));
mModels.back()->mTransform.setTranslation(-3.0f, -1.0f, -10.0f);
mModels.back()->mTransform.scale(0.15f);
mModels.push_back(
new Qtk::Model("alien", ":/models/alien-hominid/alien.obj"));
mModels.back()->mTransform.setTranslation(2.0f, -1.0f, -5.0f);
mModels.back()->mTransform.scale(0.15f);
mModels.push_back(new Qtk::Model("scythe", ":/models/scythe/scythe.obj"));
mModels.back()->mTransform.setTranslation(-6.0f, 0.0f, -10.0f);
mModels.back()->mTransform.rotate(-90.0f, 1.0f, 0.0f, 0.0f);
mModels.back()->mTransform.rotate(90.0f, 0.0f, 1.0f, 0.0f);
mModels.push_back(
new Qtk::Model("masterChief", ":/models/spartan/spartan.obj"));
mModels.back()->mTransform.setTranslation(-1.5f, 0.5f, -2.0f);
//
// Building example mesh objects
// Render an alien with specular
// Test alien Model with phong lighting and specular mapping
mMeshes.push_back(new Qtk::MeshRenderer(
"alienTestLight", Triangle(Qtk::QTK_DRAW_ELEMENTS)));
mMeshes.back()->mTransform.setTranslation(4.0f, 1.5f, 10.0f);
mMeshes.back()->mTransform.scale(0.25f);
// This function changes values we have allocated in a buffer, so init() after
mMeshes.back()->setColor(GREEN);
mModels.push_back(new Qtk::Model(
"alienTest", ":/models/alien-hominid/alien.obj", ":/model-specular.vert",
":/model-specular.frag"));
mModels.back()->mTransform.setTranslation(3.0f, -1.0f, 10.0f);
mModels.back()->mTransform.scale(0.15f);
mModels.back()->setUniform("uMaterial.ambient", QVector3D(1.0f, 1.0f, 1.0f));
mModels.back()->setUniform("uMaterial.diffuse", QVector3D(1.0f, 1.0f, 1.0f));
mModels.back()->setUniform("uMaterial.specular", QVector3D(1.0f, 1.0f, 1.0f));
mModels.back()->setUniform("uMaterial.ambientStrength", 0.8f);
mModels.back()->setUniform("uMaterial.diffuseStrength", 0.8f);
mModels.back()->setUniform("uMaterial.specularStrength", 1.0f);
mModels.back()->setUniform("uMaterial.shine", 32.0f);
mModels.back()->setUniform("uLight.ambient", QVector3D(1.0f, 1.0f, 1.0f));
mModels.back()->setUniform("uLight.diffuse", QVector3D(1.0f, 1.0f, 1.0f));
mModels.back()->setUniform("uLight.specular", QVector3D(1.0f, 1.0f, 1.0f));
// Test spartan Model with phong lighting, specular and normal mapping
// Specular lighting example light source. This is just for visual reference.
mMeshes.push_back(
new Qtk::MeshRenderer("spartanTestLight", Triangle(QTK_DRAW_ELEMENTS)));
mMeshes.back()->mTransform.setTranslation(1.0f, 1.5f, 10.0f);
mMeshes.back()->mTransform.scale(0.25f);
// This function changes values we have allocated in a buffer, so init() after
mMeshes.back()->setColor(GREEN);
new Qtk::MeshRenderer("specularLight", Triangle(QTK_DRAW_ELEMENTS)));
mMeshes.back()->getTransform().setTranslation(11.0f, 2.0f, -2.0f);
mMeshes.back()->getTransform().scale(0.25f);
mModels.push_back(new Qtk::Model(
"spartanTest", ":/models/spartan/spartan.obj", ":/model-normals.vert",
":/model-normals.frag"));
mModels.back()->mTransform.setTranslation(0.0f, -1.0f, 10.0f);
mModels.back()->mTransform.scale(2.0f);
mModels.back()->setUniform("uMaterial.ambient", QVector3D(1.0f, 1.0f, 1.0f));
mModels.back()->setUniform("uMaterial.diffuse", QVector3D(1.0f, 1.0f, 1.0f));
mModels.back()->setUniform("uMaterial.specular", QVector3D(1.0f, 1.0f, 1.0f));
mModels.back()->setUniform("uMaterial.ambientStrength", 1.0f);
mModels.back()->setUniform("uMaterial.diffuseStrength", 1.0f);
mModels.back()->setUniform("uMaterial.specularStrength", 1.0f);
mModels.back()->setUniform("uMaterial.shine", 128.0f);
mModels.back()->setUniform("uLight.ambient", QVector3D(1.0f, 1.0f, 1.0f));
mModels.back()->setUniform("uLight.diffuse", QVector3D(1.0f, 1.0f, 1.0f));
mModels.back()->setUniform("uLight.specular", QVector3D(1.0f, 1.0f, 1.0f));
// Test basic cube with phong.vert and phong.frag shaders
mMeshes.push_back(
new Qtk::MeshRenderer("testLight", Triangle(QTK_DRAW_ELEMENTS)));
mMeshes.back()->mTransform.setTranslation(5.0f, 1.25f, 10.0f);
mMeshes.back()->mTransform.scale(0.25f);
mMeshes.back()->setDrawType(GL_LINE_LOOP);
// This function changes values we have allocated in a buffer, so init() after
mMeshes.back()->setColor(GREEN);
/* Test basic cube with phong.vert and phong.frag shaders */
mMeshes.push_back(new Qtk::MeshRenderer("testPhong", Cube(QTK_DRAW_ARRAYS)));
mMeshes.back()->mTransform.setTranslation(5.0f, 0.0f, 10.0f);
mMeshes.back()->getTransform().setTranslation(5.0f, 0.0f, 10.0f);
mMeshes.back()->setShaders(":/phong.vert", ":/phong.frag");
// WARNING: Set color before reallocating normals.
mMeshes.back()->setColor(QVector3D(0.0f, 0.25f, 0.0f));
mMeshes.back()->reallocateNormals(mMeshes.back()->getNormals());
@ -209,50 +224,84 @@ void ExampleScene::init() {
mMeshes.back()->setUniform("uLight.specular", QVector3D(0.62f, 0.55f, 0.37f));
mMeshes.back()->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f));
// Light source for testPhong cube
mMeshes.push_back(
new Qtk::MeshRenderer("testLight", Triangle(QTK_DRAW_ELEMENTS)));
mMeshes.back()->getTransform().setTranslation(5.0f, 1.25f, 10.0f);
mMeshes.back()->getTransform().scale(0.25f);
mMeshes.back()->setDrawType(GL_LINE_LOOP);
mMeshes.back()->setColor(RED);
//
// Create simple shapes using MeshRenderer class and data in mesh.h
// Building more complex objects for showing examples of lighting techniques
mMeshes.push_back(
new Qtk::MeshRenderer("rightTriangle", Triangle(QTK_DRAW_ELEMENTS)));
mMeshes.back()->mTransform.setTranslation(-5.0f, 0.0f, -2.0f);
/* Test alien Model with phong lighting and specular mapping. */
mModels.push_back(new Qtk::Model(
"alienTest", ":/models/alien-hominid/alien.obj", ":/model-specular.vert",
":/model-specular.frag"));
mModels.back()->getTransform().setTranslation(3.0f, -1.0f, 10.0f);
mModels.back()->getTransform().scale(0.15f);
mModels.back()->setUniform("uMaterial.ambient", QVector3D(1.0f, 1.0f, 1.0f));
mModels.back()->setUniform("uMaterial.diffuse", QVector3D(1.0f, 1.0f, 1.0f));
mModels.back()->setUniform("uMaterial.specular", QVector3D(1.0f, 1.0f, 1.0f));
mModels.back()->setUniform("uMaterial.ambientStrength", 0.8f);
mModels.back()->setUniform("uMaterial.diffuseStrength", 0.8f);
mModels.back()->setUniform("uMaterial.specularStrength", 1.0f);
mModels.back()->setUniform("uMaterial.shine", 32.0f);
mMeshes.push_back(
new Qtk::MeshRenderer("centerCube", Cube(QTK_DRAW_ELEMENTS)));
mMeshes.back()->mTransform.setTranslation(-7.0f, 0.0f, -2.0f);
mModels.back()->setUniform("uLight.ambient", QVector3D(1.0f, 1.0f, 1.0f));
mModels.back()->setUniform("uLight.diffuse", QVector3D(1.0f, 1.0f, 1.0f));
mModels.back()->setUniform("uLight.specular", QVector3D(1.0f, 1.0f, 1.0f));
mMeshes.push_back(
new Qtk::MeshRenderer("leftTriangle", Triangle(QTK_DRAW_ELEMENTS)));
mMeshes.back()->mTransform.setTranslation(-9.0f, 0.0f, -2.0f);
mMeshes.back()->setDrawType(GL_LINE_LOOP);
mMeshes.push_back(
new Qtk::MeshRenderer("topTriangle", Triangle(QTK_DRAW_ELEMENTS)));
mMeshes.back()->mTransform.setTranslation(-7.0f, 2.0f, -2.0f);
mMeshes.back()->mTransform.scale(0.25f);
mMeshes.push_back(
new Qtk::MeshRenderer("bottomTriangle", Triangle(QTK_DRAW_ELEMENTS)));
mMeshes.back()->mTransform.setTranslation(-7.0f, -2.0f, -2.0f);
mMeshes.back()->mTransform.scale(0.25f);
mMeshes.back()->setDrawType(GL_LINE_LOOP);
// Light source for alienTest object.
mMeshes.push_back(new Qtk::MeshRenderer(
"alienTestLight", Triangle(Qtk::QTK_DRAW_ELEMENTS)));
mMeshes.back()->getTransform().setTranslation(4.0f, 1.5f, 10.0f);
mMeshes.back()->getTransform().scale(0.25f);
// This function changes values we have allocated in a buffer, so init() after
mMeshes.back()->setColor(GREEN);
/* Test spartan Model with phong lighting, specular and normal mapping. */
mModels.push_back(new Qtk::Model(
"spartanTest", ":/models/spartan/spartan.obj", ":/model-normals.vert",
":/model-normals.frag"));
mModels.back()->getTransform().setTranslation(0.0f, -1.0f, 10.0f);
mModels.back()->getTransform().scale(2.0f);
mModels.back()->setUniform("uMaterial.ambient", QVector3D(1.0f, 1.0f, 1.0f));
mModels.back()->setUniform("uMaterial.diffuse", QVector3D(1.0f, 1.0f, 1.0f));
mModels.back()->setUniform("uMaterial.specular", QVector3D(1.0f, 1.0f, 1.0f));
mModels.back()->setUniform("uMaterial.ambientStrength", 1.0f);
mModels.back()->setUniform("uMaterial.diffuseStrength", 1.0f);
mModels.back()->setUniform("uMaterial.specularStrength", 1.0f);
mModels.back()->setUniform("uMaterial.shine", 128.0f);
mModels.back()->setUniform("uLight.ambient", QVector3D(1.0f, 1.0f, 1.0f));
mModels.back()->setUniform("uLight.diffuse", QVector3D(1.0f, 1.0f, 1.0f));
mModels.back()->setUniform("uLight.specular", QVector3D(1.0f, 1.0f, 1.0f));
// Light source for spartanTest object.
mMeshes.push_back(
new Qtk::MeshRenderer("spartanTestLight", Triangle(QTK_DRAW_ELEMENTS)));
mMeshes.back()->getTransform().setTranslation(1.0f, 1.5f, 10.0f);
mMeshes.back()->getTransform().scale(0.25f);
// This function changes values we have allocated in a buffer, so init() after
mMeshes.back()->setColor(GREEN);
//
// Testing for normals, texture coordinates
// Test drawing simple geometry with various OpenGL drawing modes
// RGB Normals cube to show normals are correct with QTK_DRAW_ARRAYS
mMeshes.push_back(
new Qtk::MeshRenderer("rgbNormalsCubeArraysTest", Cube(QTK_DRAW_ARRAYS)));
mMeshes.back()->mTransform.setTranslation(5.0f, 0.0f, 4.0f);
mMeshes.back()->getTransform().setTranslation(5.0f, 0.0f, 4.0f);
mMeshes.back()->setShaders(":/rgb-normals.vert", ":/rgb-normals.frag");
mMeshes.back()->reallocateNormals(mMeshes.back()->getNormals());
// RGB Normals cube to show normals are correct with QTK_DRAW_ELEMENTS_NORMALS
mMeshes.push_back(new Qtk::MeshRenderer(
"rgbNormalsCubeElementsTest", Cube(QTK_DRAW_ELEMENTS_NORMALS)));
mMeshes.back()->mTransform.setTranslation(5.0f, 0.0f, 2.0f);
mMeshes.back()->getTransform().setTranslation(5.0f, 0.0f, 2.0f);
mMeshes.back()->setShaders(":/rgb-normals.vert", ":/rgb-normals.frag");
mMeshes.back()->reallocateNormals(mMeshes.back()->getNormals());
@ -260,7 +309,7 @@ void ExampleScene::init() {
crateTexture.setTexture(":/crate.png");
Cube cube;
auto * m = new MeshRenderer("Test Crate", Cube(QTK_DRAW_ARRAYS));
m->mTransform.setTranslation(0, 0, 13);
m->getTransform().setTranslation(0, 0, 13);
m->setShaders(":/texture2d.vert", ":/texture2d.frag");
m->setTexture(crateTexture);
m->setUniform("uTexture", 0);
@ -274,7 +323,7 @@ void ExampleScene::init() {
// + This is because the same position must use different UV coordinates
mMeshes.push_back(
new Qtk::MeshRenderer("uvCubeArraysTest", Cube(QTK_DRAW_ARRAYS)));
mMeshes.back()->mTransform.setTranslation(-3.0f, 0.0f, -2.0f);
mMeshes.back()->getTransform().setTranslation(-3.0f, 0.0f, -2.0f);
mMeshes.back()->setShaders(":/texture2d.vert", ":/texture2d.frag");
mMeshes.back()->setTexture(crateTexture);
mMeshes.back()->setUniform("uTexture", 0);
@ -283,7 +332,7 @@ void ExampleScene::init() {
// Test drawing a cube with texture coordinates using glDrawElements
mMeshes.push_back(new Qtk::MeshRenderer(
"uvCubeElementsTest", Cube(QTK_DRAW_ELEMENTS_NORMALS)));
mMeshes.back()->mTransform.setTranslation(-1.7f, 0.0f, -2.0f);
mMeshes.back()->getTransform().setTranslation(-1.7f, 0.0f, -2.0f);
mMeshes.back()->setTexture(":/crate.png");
mMeshes.back()->setShaders(":/texture2d.vert", ":/texture2d.frag");
mMeshes.back()->bindShaders();
@ -291,14 +340,14 @@ void ExampleScene::init() {
mMeshes.back()->reallocateNormals(mMeshes.back()->getNormals());
mMeshes.back()->reallocateTexCoords(mMeshes.back()->getTexCoords(), 3);
mMeshes.back()->releaseShaders();
mMeshes.back()->mTransform.rotate(45.0f, 0.0f, 1.0f, 0.0f);
mMeshes.back()->getTransform().rotate(45.0f, 0.0f, 1.0f, 0.0f);
// Texturing a cube using a cube map
// + Cube map texturing works with both QTK_DRAW_ARRAYS and QTK_DRAW_ELEMENTS
mMeshes.push_back(
new Qtk::MeshRenderer("testCubeMap", Cube(QTK_DRAW_ELEMENTS)));
mMeshes.back()->mTransform.setTranslation(-3.0f, 1.0f, -2.0f);
mMeshes.back()->mTransform.setRotation(45.0f, 0.0f, 1.0f, 0.0f);
mMeshes.back()->getTransform().setTranslation(-3.0f, 1.0f, -2.0f);
mMeshes.back()->getTransform().setRotation(45.0f, 0.0f, 1.0f, 0.0f);
mMeshes.back()->setShaders(
":/texture-cubemap.vert", ":/texture-cubemap.frag");
mMeshes.back()->setCubeMap(":/crate.png");
@ -309,28 +358,28 @@ void ExampleScene::init() {
// + Apply RGB normals shader and spin the cube for a neat effect
mMeshes.push_back(
new Qtk::MeshRenderer("rgbNormalsCube", Cube(QTK_DRAW_ARRAYS)));
mMeshes.back()->mTransform.setTranslation(5.0f, 2.0f, -2.0f);
mMeshes.back()->getTransform().setTranslation(5.0f, 2.0f, -2.0f);
mMeshes.back()->setShaders(":/rgb-normals.vert", ":/rgb-normals.frag");
mMeshes.back()->reallocateNormals(mMeshes.back()->getNormals());
// RGB Normals triangle to show normals are correct with QTK_DRAW_ARRAYS
mMeshes.push_back(new Qtk::MeshRenderer(
"rgbTriangleArraysTest", Triangle(QTK_DRAW_ARRAYS)));
mMeshes.back()->mTransform.setTranslation(7.0f, 0.0f, 2.0f);
mMeshes.back()->getTransform().setTranslation(7.0f, 0.0f, 2.0f);
mMeshes.back()->setShaders(":/rgb-normals.vert", ":/rgb-normals.frag");
mMeshes.back()->reallocateNormals(mMeshes.back()->getNormals());
// RGB Normals triangle to show normals are correct with QTK_DRAW_ELEMENTS
mMeshes.push_back(new Qtk::MeshRenderer(
"rgbTriangleElementsTest", Triangle(QTK_DRAW_ELEMENTS_NORMALS)));
mMeshes.back()->mTransform.setTranslation(7.0f, 0.0f, 4.0f);
mMeshes.back()->getTransform().setTranslation(7.0f, 0.0f, 4.0f);
mMeshes.back()->setShaders(":/rgb-normals.vert", ":/rgb-normals.frag");
mMeshes.back()->reallocateNormals(mMeshes.back()->getNormals());
// Test drawing triangle with glDrawArrays with texture coordinates
mMeshes.push_back(
new Qtk::MeshRenderer("testTriangleArraysUV", Triangle(QTK_DRAW_ARRAYS)));
mMeshes.back()->mTransform.setTranslation(-3.0f, 2.0f, -2.0f);
mMeshes.back()->getTransform().setTranslation(-3.0f, 2.0f, -2.0f);
mMeshes.back()->setShaders(":/texture2d.vert", ":/texture2d.frag");
mMeshes.back()->setTexture(":/crate.png");
@ -340,40 +389,16 @@ void ExampleScene::init() {
// Test drawing triangle with glDrawElements with texture coordinates
mMeshes.push_back(new Qtk::MeshRenderer(
"testTriangleElementsUV", Triangle(QTK_DRAW_ELEMENTS_NORMALS)));
mMeshes.back()->mTransform.setTranslation(-2.5f, 0.0f, -1.0f);
mMeshes.back()->getTransform().setTranslation(-2.5f, 0.0f, -1.0f);
mMeshes.back()->setShaders(":/texture2d.vert", ":/texture2d.frag");
mMeshes.back()->setTexture(":/crate.png");
mMeshes.back()->setUniform("uTexture", 0);
mMeshes.back()->reallocateTexCoords(mMeshes.back()->getTexCoords());
//
// Lighting cube examples
// Example of a cube with no lighting applied
mMeshes.push_back(new Qtk::MeshRenderer("noLight", Cube(QTK_DRAW_ELEMENTS)));
mMeshes.back()->mTransform.setTranslation(5.0f, 0.0f, -2.0f);
mMeshes.back()->setShaders(
":/solid-perspective.vert", ":/solid-perspective.frag");
mMeshes.back()->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f));
// Create objects that represent light sources for lighting examples
mMeshes.push_back(
new Qtk::MeshRenderer("phongLight", Triangle(QTK_DRAW_ELEMENTS)));
mMeshes.back()->mTransform.setTranslation(3.0f, 2.0f, -2.0f);
mMeshes.back()->mTransform.scale(0.25f);
mMeshes.push_back(
new Qtk::MeshRenderer("diffuseLight", Triangle(QTK_DRAW_ELEMENTS)));
mMeshes.back()->mTransform.setTranslation(9.0f, 2.0f, -2.0f);
mMeshes.back()->mTransform.scale(0.25f);
mMeshes.push_back(
new Qtk::MeshRenderer("specularLight", Triangle(QTK_DRAW_ELEMENTS)));
mMeshes.back()->mTransform.setTranslation(11.0f, 2.0f, -2.0f);
mMeshes.back()->mTransform.scale(0.25f);
}
void ExampleScene::draw() {
// WARNING: We must call the base class draw() function first.
// + This will handle rendering core scene components like the Skybox.
Scene::draw();
for(const auto & model : mModels) {
@ -387,129 +412,156 @@ void ExampleScene::draw() {
mTestPhong->bindShaders();
mTestPhong->setUniform(
"uModelInverseTransposed",
mTestPhong->mTransform.toMatrix().normalMatrix());
mTestPhong->getTransform().toMatrix().normalMatrix());
mTestPhong->setUniform(
"uLightPosition",
MeshRenderer::getInstance("phongLight")->mTransform.getTranslation());
MeshRenderer::getInstance("phongLight")->getTransform().getTranslation());
mTestPhong->setUniform(
"uCameraPosition", ExampleScene::Camera().transform().getTranslation());
"uCameraPosition",
ExampleScene::getCamera().getTransform().getTranslation());
mTestPhong->releaseShaders();
mTestPhong->draw();
mTestAmbient->bindShaders();
mTestAmbient->setUniform(
"uCameraPosition", ExampleScene::Camera().transform().getTranslation());
"uCameraPosition",
ExampleScene::getCamera().getTransform().getTranslation());
mTestAmbient->releaseShaders();
mTestAmbient->draw();
mTestDiffuse->bindShaders();
mTestDiffuse->setUniform(
"uModelInverseTransposed",
mTestDiffuse->mTransform.toMatrix().normalMatrix());
mTestDiffuse->getTransform().toMatrix().normalMatrix());
mTestDiffuse->setUniform(
"uLightPosition",
MeshRenderer::getInstance("diffuseLight")->mTransform.getTranslation());
"uLightPosition", MeshRenderer::getInstance("diffuseLight")
->getTransform()
.getTranslation());
mTestDiffuse->setUniform(
"uCameraPosition", ExampleScene::Camera().transform().getTranslation());
"uCameraPosition",
ExampleScene::getCamera().getTransform().getTranslation());
mTestDiffuse->releaseShaders();
mTestDiffuse->draw();
mTestSpecular->bindShaders();
mTestSpecular->setUniform(
"uModelInverseTransposed",
mTestSpecular->mTransform.toMatrix().normalMatrix());
mTestSpecular->getTransform().toMatrix().normalMatrix());
mTestSpecular->setUniform(
"uLightPosition",
MeshRenderer::getInstance("specularLight")->mTransform.getTranslation());
"uLightPosition", MeshRenderer::getInstance("specularLight")
->getTransform()
.getTranslation());
mTestSpecular->setUniform(
"uCameraPosition", ExampleScene::Camera().transform().getTranslation());
"uCameraPosition",
ExampleScene::getCamera().getTransform().getTranslation());
mTestSpecular->releaseShaders();
mTestSpecular->draw();
}
void ExampleScene::update() {
auto position =
MeshRenderer::getInstance("alienTestLight")->mTransform.getTranslation();
auto mySpartan = Model::getInstance("My spartan");
mySpartan->getTransform().rotate(0.75f, 0.0f, 1.0f, 0.0f);
auto myCube = MeshRenderer::getInstance("My cube");
myCube->getTransform().rotate(-0.75f, 0.0f, 1.0f, 0.0f);
auto position = MeshRenderer::getInstance("alienTestLight")
->getTransform()
.getTranslation();
auto alien = Model::getInstance("alienTest");
alien->setUniform("uLight.position", position);
alien->setUniform(
"uCameraPosition", ExampleScene::Camera().transform().getTranslation());
auto posMatrix = alien->mTransform.toMatrix();
"uCameraPosition",
ExampleScene::getCamera().getTransform().getTranslation());
auto posMatrix = alien->getTransform().toMatrix();
alien->setUniform("uMVP.normalMatrix", posMatrix.normalMatrix());
alien->setUniform("uMVP.model", posMatrix);
alien->setUniform("uMVP.view", ExampleScene::Camera().toMatrix());
alien->setUniform("uMVP.projection", ExampleScene::Projection());
alien->mTransform.rotate(0.75f, 0.0f, 1.0f, 0.0f);
alien->setUniform("uMVP.view", ExampleScene::getCamera().toMatrix());
alien->setUniform("uMVP.projection", ExampleScene::getProjectionMatrix());
alien->getTransform().rotate(0.75f, 0.0f, 1.0f, 0.0f);
position = MeshRenderer::getInstance("spartanTestLight")
->mTransform.getTranslation();
->getTransform()
.getTranslation();
auto spartan = Model::getInstance("spartanTest");
spartan->setUniform("uLight.position", position);
spartan->setUniform(
"uCameraPosition", ExampleScene::Camera().transform().getTranslation());
posMatrix = spartan->mTransform.toMatrix();
"uCameraPosition",
ExampleScene::getCamera().getTransform().getTranslation());
posMatrix = spartan->getTransform().toMatrix();
spartan->setUniform("uMVP.normalMatrix", posMatrix.normalMatrix());
spartan->setUniform("uMVP.model", posMatrix);
spartan->setUniform("uMVP.view", ExampleScene::Camera().toMatrix());
spartan->setUniform("uMVP.projection", ExampleScene::Projection());
spartan->mTransform.rotate(0.75f, 0.0f, 1.0f, 0.0f);
spartan->setUniform("uMVP.view", ExampleScene::getCamera().toMatrix());
spartan->setUniform("uMVP.projection", ExampleScene::getProjectionMatrix());
spartan->getTransform().rotate(0.75f, 0.0f, 1.0f, 0.0f);
auto phong = MeshRenderer::getInstance("testPhong");
phong->mTransform.rotate(0.75f, 1.0f, 0.5f, 0.0f);
phong->getTransform().rotate(0.75f, 1.0f, 0.5f, 0.0f);
phong->bindShaders();
position =
MeshRenderer::getInstance("testLight")->mTransform.getTranslation();
MeshRenderer::getInstance("testLight")->getTransform().getTranslation();
phong->setUniform("uLight.position", position);
phong->setUniform(
"uCameraPosition", ExampleScene::Camera().transform().getTranslation());
posMatrix = phong->mTransform.toMatrix();
"uCameraPosition",
ExampleScene::getCamera().getTransform().getTranslation());
posMatrix = phong->getTransform().toMatrix();
phong->setUniform("uMVP.normalMatrix", posMatrix.normalMatrix());
phong->setUniform("uMVP.model", posMatrix);
phong->setUniform("uMVP.view", ExampleScene::Camera().toMatrix());
phong->setUniform("uMVP.projection", ExampleScene::Projection());
phong->setUniform("uMVP.view", ExampleScene::getCamera().toMatrix());
phong->setUniform("uMVP.projection", ExampleScene::getProjectionMatrix());
phong->releaseShaders();
// Rotate lighting example cubes
mTestPhong->mTransform.rotate(0.75f, 0.5f, 0.3f, 0.2f);
MeshRenderer::getInstance("noLight")->mTransform.rotate(
mTestPhong->getTransform().rotate(0.75f, 0.5f, 0.3f, 0.2f);
MeshRenderer::getInstance("noLight")->getTransform().rotate(
0.75f, 0.5f, 0.3f, 0.2f);
mTestAmbient->mTransform.rotate(0.75f, 0.5f, 0.3f, 0.2f);
mTestDiffuse->mTransform.rotate(0.75f, 0.5f, 0.3f, 0.2f);
mTestSpecular->mTransform.rotate(0.75f, 0.5f, 0.3f, 0.2f);
mTestAmbient->getTransform().rotate(0.75f, 0.5f, 0.3f, 0.2f);
mTestDiffuse->getTransform().rotate(0.75f, 0.5f, 0.3f, 0.2f);
mTestSpecular->getTransform().rotate(0.75f, 0.5f, 0.3f, 0.2f);
// Examples of various translations and rotations
// Rotate in multiple directions simultaneously
MeshRenderer::getInstance("rgbNormalsCube")
->mTransform.rotate(0.75f, 0.2f, 0.4f, 0.6f);
->getTransform()
.rotate(0.75f, 0.2f, 0.4f, 0.6f);
// Pitch forward and roll sideways
MeshRenderer::getInstance("leftTriangle")
->mTransform.rotate(0.75f, 1.0f, 0.0f, 0.0f);
->getTransform()
.rotate(0.75f, 1.0f, 0.0f, 0.0f);
MeshRenderer::getInstance("rightTriangle")
->mTransform.rotate(0.75f, 0.0f, 0.0f, 1.0f);
->getTransform()
.rotate(0.75f, 0.0f, 0.0f, 1.0f);
// Move between two positions over time
static float translateX = 0.025f;
float limit = -9.0f; // Origin position.x - 2.0f
float posX =
MeshRenderer::getInstance("topTriangle")->mTransform.getTranslation().x();
float posX = MeshRenderer::getInstance("topTriangle")
->getTransform()
.getTranslation()
.x();
if(posX < limit || posX > limit + 4.0f) {
translateX = -translateX;
}
MeshRenderer::getInstance("topTriangle")
->mTransform.translate(translateX, 0.0f, 0.0f);
->getTransform()
.translate(translateX, 0.0f, 0.0f);
MeshRenderer::getInstance("bottomTriangle")
->mTransform.translate(-translateX, 0.0f, 0.0f);
->getTransform()
.translate(-translateX, 0.0f, 0.0f);
// And lets rotate the triangles in two directions at once
MeshRenderer::getInstance("topTriangle")
->mTransform.rotate(0.75f, 0.2f, 0.0f, 0.4f);
->getTransform()
.rotate(0.75f, 0.2f, 0.0f, 0.4f);
MeshRenderer::getInstance("bottomTriangle")
->mTransform.rotate(0.75f, 0.0f, 0.2f, 0.4f);
->getTransform()
.rotate(0.75f, 0.0f, 0.2f, 0.4f);
// And make the bottom triangle green, instead of RGB
// Rotate center cube in several directions simultaneously
// + Not subject to gimbal lock since we are using quaternions :)
MeshRenderer::getInstance("centerCube")
->mTransform.rotate(0.75f, 0.2f, 0.4f, 0.6f);
->getTransform()
.rotate(0.75f, 0.2f, 0.4f, 0.6f);
}

View File

@ -9,22 +9,65 @@
#ifndef QTK_EXAMPLE_SCENE_H
#define QTK_EXAMPLE_SCENE_H
#include <abstractscene.h>
#include <camera3d.h>
#include <scene.h>
#include <skybox.h>
#include <QMatrix4x4>
/**
* Example scene using QtkWidget to render 3D models and simple geometry within
* QtOpenGLWidgets. This scene also shows some examples of using GLSL shaders to
* apply the basic lighting techniques leading up to Phong.
*
* The Qtk::Scene base class provides containers for N pointers to MeshRenderer
* and Model objects. We can create and insert as many as we like within this
* child class implementation. This child class does not need to manually draw
* objects inserted into these containers. The child class would only need to
* update uniform or other data that may change per-frame.
* See scene.h and `init()` for more information.
*
* To modify the scene objects should be initialized within the `init()` public
* method. Any required movement or updates should be applied within `draw()` or
* `update()`.
*
* To create your own Scene from scratch see Qtk::Scene.
*/
class ExampleScene : public Qtk::Scene {
public:
/***************************************************************************
* Contructors / Destructors
**************************************************************************/
ExampleScene();
~ExampleScene();
/***************************************************************************
* Inherited Public Overrides
**************************************************************************/
/**
* Initialize objects within the scene
*/
void init() override;
/**
* Called when OpenGL repaints the widget.
*/
void draw() override;
/**
* Called when the Qt `frameSwapped` signal is caught.
* See definition of `QtkWidget::initializeGL()`
*/
void update() override;
private:
/***************************************************************************
* Private Members
**************************************************************************/
// Additional example objects created within this example.
// + The base class Scene manages objects stored within mMeshes or mModels
Qtk::MeshRenderer * mTestPhong {};
Qtk::MeshRenderer * mTestSpecular {};
Qtk::MeshRenderer * mTestDiffuse {};

View File

@ -16,20 +16,6 @@
int main(int argc, char * argv[]) {
QApplication a(argc, argv);
// Set OpenGL Version information
// Note: This format must be set before show() is called.
QSurfaceFormat format;
format.setRenderableType(QSurfaceFormat::OpenGL);
format.setProfile(QSurfaceFormat::CoreProfile);
format.setVersion(4, 5);
// Set the number of samples used for glEnable(GL_MULTISAMPLING)
format.setSamples(4);
// Set the size of the depth bufer for glEnable(GL_DEPTH_TEST)
format.setDepthBufferSize(16);
#ifdef QTK_DEBUG
format.setOption(QSurfaceFormat::DebugContext);
#endif // QTK_DEBUG
// Create window for Qt application using custom mainwindow.h
MainWindow w;
w.show();

View File

@ -1,22 +1,37 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: MainWindow for creating an example Qt application ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
##############################################################################*/
#include <mainwindow.h>
#include <qtkwidget.h>
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget * parent) :
QMainWindow(parent), ui(new Ui::MainWindow) {
ui->setupUi(this);
// For use in design mode using Qt Creator
// + We can use the `ui` member to access nested widgets by name
ui->setupUi(this);
// Find all QtkWidgets in this QMainWindow and initialize their scenes.
for(const auto widget : ui->qWidget->children()) {
auto qtkWidget = dynamic_cast<Qtk::QtkWidget *>(widget);
if(qtkWidget != nullptr) {
std::string key = qtkWidget->objectName().toStdString();
// Initialize each scene into a map if it doesn't exist.
if(mScenes[key] == nullptr) {
mScenes[qtkWidget->objectName().toStdString()] = new ExampleScene();
mScenes[key] = new ExampleScene();
}
qtkWidget->setScene(mScenes[qtkWidget->objectName().toStdString()]);
// Set the QtkWidget to use the scene associated with this widget.
qtkWidget->setScene(mScenes[key]);
}
}
// Set the window icon used for Qtk.
// TODO: Update this to be something other than kilroy.
setWindowIcon(QIcon("../resources/icon.png"));
}

View File

@ -1,3 +1,11 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: MainWindow for creating an example Qt application ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
##############################################################################*/
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
@ -12,16 +20,32 @@ namespace Ui {
class MainWindow;
}
class QTK_WIDGET_EXPORT MainWindow
: public QMainWindow {
/**
* MainWindow class to provide an example of using a QtkWidget within a Qt
* window application.
*/
class QTK_WIDGET_EXPORT MainWindow : public QMainWindow {
Q_OBJECT
public:
/***************************************************************************
* Contructors / Destructors
**************************************************************************/
/**
* This ctor also initializes the Scene for each QtkWidget in the window.
* To load a different scene this would need to be updated.
*
* @param parent The parent for this QMainWindow
*/
explicit MainWindow(QWidget * parent = nullptr);
~MainWindow() override;
private:
/***************************************************************************
* Private Members
**************************************************************************/
Ui::MainWindow * ui {};
std::unordered_map<std::string, Qtk::Scene *> mScenes {};
};

View File

@ -13,6 +13,19 @@
#ifndef QTK_RESOURCEMANAGER_H
#define QTK_RESOURCEMANAGER_H
/**
* ResourceManager class used to construct absolute paths to files within the Qt
* resources path. There is no need to manually call this method.
* Model::loadModel(...) will use this method if a Qt resource path is provided.
* The Model constructor behaves the same. If a path is prefixed with `:/` this
* static method will be used to resolve a full system path.
*
* This will likely be deprecated. It has a single call site and it is not
* meant for public use. It is public only for convenience.
*
* RM::getPath(":/models/alien-hominid/alien.obj") =
* /full/path/to/models/alien-hominid/alien.obj
*/
typedef class ResourceManager {
public:
/**
@ -24,7 +37,7 @@ typedef class ResourceManager {
* ':/models/backpack/backpack.obj' An asset at location
* qtk/resources/path/to/asset.obj Should be given in qrc format:
* ':/path/to/asset.obj'
* @return Absoulte system path to a qtk asset
* @return Absolute system path to a qtk asset
*/
static std::string getPath(const std::string & path) {
// Only construct qtk resource path if in qrc format; else return it as-is

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;