Work on adding more doxygen comments #12

Merged
shaunrd0 merged 3 commits from docs into master 2022-11-26 18:24:39 +00:00
28 changed files with 1067 additions and 525 deletions
Showing only changes of commit d37484d75c - Show all commits

View File

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

View File

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

View File

@ -6,12 +6,12 @@
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
##############################################################################*/ ##############################################################################*/
#include <abstractscene.h>
#include <camera3d.h> #include <camera3d.h>
#include <examplescene.h> #include <examplescene.h>
#include <meshrenderer.h> #include <meshrenderer.h>
#include <model.h> #include <model.h>
#include <resourcemanager.h> #include <resourcemanager.h>
#include <scene.h>
#include <texture.h> #include <texture.h>
using namespace Qtk; using namespace Qtk;
@ -21,8 +21,8 @@ using namespace Qtk;
******************************************************************************/ ******************************************************************************/
ExampleScene::ExampleScene() { ExampleScene::ExampleScene() {
Camera().transform().setTranslation(0.0f, 0.0f, 20.0f); getCamera().getTransform().setTranslation(0.0f, 0.0f, 20.0f);
Camera().transform().setRotation(-5.0f, 0.0f, 1.0f, 0.0f); getCamera().getTransform().setRotation(-5.0f, 0.0f, 1.0f, 0.0f);
} }
ExampleScene::~ExampleScene() { ExampleScene::~ExampleScene() {
@ -44,60 +44,40 @@ ExampleScene::~ExampleScene() {
******************************************************************************/ ******************************************************************************/
void ExampleScene::init() { void ExampleScene::init() {
auto * sb = new Qtk::Skybox("Skybox"); setSkybox(new Qtk::Skybox("Skybox"));
setSkybox(sb);
// Initialize Phong example cube //
mTestPhong = new Qtk::MeshRenderer("phong", Qtk::Cube()); // Create simple shapes using MeshRenderer class and data in mesh.h
mTestPhong->mTransform.setTranslation(3.0f, 0.0f, -2.0f);
mTestPhong->setShaders(":/solid-phong.vert", ":/solid-phong.frag");
// You no longer need to manually bind shader program. mMeshes.push_back(
// + But, you can still bind it if you want to. new Qtk::MeshRenderer("rightTriangle", Triangle(QTK_DRAW_ELEMENTS)));
// mTestPhong->bindShaders(); mMeshes.back()->mTransform.setTranslation(-5.0f, 0.0f, -2.0f);
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();
// Initialize Ambient example cube mMeshes.push_back(
mTestAmbient = new Qtk::MeshRenderer("ambient", Cube()); new Qtk::MeshRenderer("centerCube", Cube(QTK_DRAW_ELEMENTS)));
mTestAmbient->mTransform.setTranslation(7.0f, 0.0f, -2.0f); mMeshes.back()->mTransform.setTranslation(-7.0f, 0.0f, -2.0f);
mTestAmbient->setShaders(":/solid-ambient.vert", ":/solid-ambient.frag");
mTestAmbient->init();
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());
// Initialize Diffuse example cube mMeshes.push_back(
mTestDiffuse = new Qtk::MeshRenderer("diffuse", Cube()); new Qtk::MeshRenderer("leftTriangle", Triangle(QTK_DRAW_ELEMENTS)));
mTestDiffuse->mTransform.setTranslation(9.0f, 0.0f, -2.0f); mMeshes.back()->mTransform.setTranslation(-9.0f, 0.0f, -2.0f);
mTestDiffuse->setShaders(":/solid-diffuse.vert", ":/solid-diffuse.frag"); mMeshes.back()->setDrawType(GL_LINE_LOOP);
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 mMeshes.push_back(
mTestSpecular = new Qtk::MeshRenderer("specular", Cube()); new Qtk::MeshRenderer("topTriangle", Triangle(QTK_DRAW_ELEMENTS)));
mTestSpecular->mTransform.setTranslation(11.0f, 0.0f, -2.0f); mMeshes.back()->mTransform.setTranslation(-7.0f, 2.0f, -2.0f);
mTestSpecular->setShaders(":/solid-specular.vert", ":/solid-specular.frag"); mMeshes.back()->mTransform.scale(0.25f);
mTestSpecular->init();
mTestSpecular->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f)); mMeshes.push_back(
mTestSpecular->setUniform("uLightColor", QVector3D(1.0f, 1.0f, 1.0f)); new Qtk::MeshRenderer("bottomTriangle", Triangle(QTK_DRAW_ELEMENTS)));
mTestSpecular->setUniform("uAmbientStrength", 0.2f); mMeshes.back()->mTransform.setTranslation(-7.0f, -2.0f, -2.0f);
mTestSpecular->setUniform("uSpecularStrength", 0.50f); mMeshes.back()->mTransform.scale(0.25f);
mTestSpecular->setUniform("uSpecularShine", 256); mMeshes.back()->setDrawType(GL_LINE_LOOP);
mTestSpecular->reallocateNormals(mTestSpecular->getNormals()); // This function changes values we have allocated in a buffer, so init() after
mMeshes.back()->setColor(GREEN);
// //
// Model loading // 3D Model loading
mModels.push_back( mModels.push_back(
new Qtk::Model("backpack", ":/models/backpack/backpack.obj")); new Qtk::Model("backpack", ":/models/backpack/backpack.obj"));
@ -129,18 +109,124 @@ void ExampleScene::init() {
new Qtk::Model("masterChief", ":/models/spartan/spartan.obj")); new Qtk::Model("masterChief", ":/models/spartan/spartan.obj"));
mModels.back()->mTransform.setTranslation(-1.5f, 0.5f, -2.0f); mModels.back()->mTransform.setTranslation(-1.5f, 0.5f, -2.0f);
// //
// Building example mesh objects // Simple cube lighting examples.
// Render an alien with specular /* Phong lighting example on a basic cube. */
// Test alien Model with phong lighting and specular mapping mTestPhong = new Qtk::MeshRenderer("phong", Qtk::Cube());
mMeshes.push_back(new Qtk::MeshRenderer( mTestPhong->mTransform.setTranslation(3.0f, 0.0f, -2.0f);
"alienTestLight", Triangle(Qtk::QTK_DRAW_ELEMENTS))); // NOTE: You no longer need to manually bind shader program to set uniforms.
mMeshes.back()->mTransform.setTranslation(4.0f, 1.5f, 10.0f); // + 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");
// 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->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.
// 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()->mTransform.setTranslation(3.0f, 2.0f, -2.0f);
mMeshes.back()->mTransform.scale(0.25f); mMeshes.back()->mTransform.scale(0.25f);
// This function changes values we have allocated in a buffer, so init() after
mMeshes.back()->setColor(GREEN);
/* 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));
// 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->setShaders(":/solid-ambient.vert", ":/solid-ambient.frag");
// 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 */
mTestDiffuse = new Qtk::MeshRenderer("diffuse", Cube());
mTestDiffuse->mTransform.setTranslation(9.0f, 0.0f, -2.0f);
mTestDiffuse->setShaders(":/solid-diffuse.vert", ":/solid-diffuse.frag");
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());
// Diffuse lighting example light source. This is just for visual reference.
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);
/* Initialize Specular example cube */
mTestSpecular = new Qtk::MeshRenderer("specular", Cube());
mTestSpecular->mTransform.setTranslation(11.0f, 0.0f, -2.0f);
mTestSpecular->setShaders(":/solid-specular.vert", ":/solid-specular.frag");
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);
mTestSpecular->setUniform("uSpecularStrength", 0.50f);
mTestSpecular->setUniform("uSpecularShine", 256);
mTestSpecular->reallocateNormals(mTestSpecular->getNormals());
// Specular lighting example light source. This is just for visual reference.
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);
/* 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()->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());
mMeshes.back()->setUniform("uMaterial.ambient", QVector3D(0.0f, 0.3f, 0.0f));
mMeshes.back()->setUniform("uMaterial.diffuse", QVector3D(0.0f, 0.2f, 0.0f));
mMeshes.back()->setUniform("uMaterial.specular", QVector3D(1.0f, 1.0f, 1.0f));
mMeshes.back()->setUniform("uMaterial.ambientStrength", 1.0f);
mMeshes.back()->setUniform("uMaterial.diffuseStrength", 1.0f);
mMeshes.back()->setUniform("uMaterial.specularStrength", 1.0f);
mMeshes.back()->setUniform("uMaterial.shine", 64.0f);
mMeshes.back()->setUniform("uLight.ambient", QVector3D(0.25f, 0.2f, 0.075f));
mMeshes.back()->setUniform("uLight.diffuse", QVector3D(0.75f, 0.6f, 0.22f));
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()->mTransform.setTranslation(5.0f, 1.25f, 10.0f);
mMeshes.back()->mTransform.scale(0.25f);
mMeshes.back()->setDrawType(GL_LINE_LOOP);
mMeshes.back()->setColor(RED);
//
// Building more complex objects for showing examples of lighting techniques
/* Test alien Model with phong lighting and specular mapping. */
mModels.push_back(new Qtk::Model( mModels.push_back(new Qtk::Model(
"alienTest", ":/models/alien-hominid/alien.obj", ":/model-specular.vert", "alienTest", ":/models/alien-hominid/alien.obj", ":/model-specular.vert",
":/model-specular.frag")); ":/model-specular.frag"));
@ -158,14 +244,15 @@ void ExampleScene::init() {
mModels.back()->setUniform("uLight.diffuse", 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)); mModels.back()->setUniform("uLight.specular", QVector3D(1.0f, 1.0f, 1.0f));
// Test spartan Model with phong lighting, specular and normal mapping // Light source for alienTest object.
mMeshes.push_back( mMeshes.push_back(new Qtk::MeshRenderer(
new Qtk::MeshRenderer("spartanTestLight", Triangle(QTK_DRAW_ELEMENTS))); "alienTestLight", Triangle(Qtk::QTK_DRAW_ELEMENTS)));
mMeshes.back()->mTransform.setTranslation(1.0f, 1.5f, 10.0f); mMeshes.back()->mTransform.setTranslation(4.0f, 1.5f, 10.0f);
mMeshes.back()->mTransform.scale(0.25f); mMeshes.back()->mTransform.scale(0.25f);
// This function changes values we have allocated in a buffer, so init() after // This function changes values we have allocated in a buffer, so init() after
mMeshes.back()->setColor(GREEN); mMeshes.back()->setColor(GREEN);
/* Test spartan Model with phong lighting, specular and normal mapping. */
mModels.push_back(new Qtk::Model( mModels.push_back(new Qtk::Model(
"spartanTest", ":/models/spartan/spartan.obj", ":/model-normals.vert", "spartanTest", ":/models/spartan/spartan.obj", ":/model-normals.vert",
":/model-normals.frag")); ":/model-normals.frag"));
@ -182,65 +269,17 @@ void ExampleScene::init() {
mModels.back()->setUniform("uLight.diffuse", 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)); mModels.back()->setUniform("uLight.specular", QVector3D(1.0f, 1.0f, 1.0f));
// Test basic cube with phong.vert and phong.frag shaders // Light source for spartanTest object.
mMeshes.push_back( mMeshes.push_back(
new Qtk::MeshRenderer("testLight", Triangle(QTK_DRAW_ELEMENTS))); new Qtk::MeshRenderer("spartanTestLight", Triangle(QTK_DRAW_ELEMENTS)));
mMeshes.back()->mTransform.setTranslation(5.0f, 1.25f, 10.0f); mMeshes.back()->mTransform.setTranslation(1.0f, 1.5f, 10.0f);
mMeshes.back()->mTransform.scale(0.25f); 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 // This function changes values we have allocated in a buffer, so init() after
mMeshes.back()->setColor(GREEN); mMeshes.back()->setColor(GREEN);
mMeshes.push_back(new Qtk::MeshRenderer("testPhong", Cube(QTK_DRAW_ARRAYS)));
mMeshes.back()->mTransform.setTranslation(5.0f, 0.0f, 10.0f);
mMeshes.back()->setShaders(":/phong.vert", ":/phong.frag");
mMeshes.back()->setColor(QVector3D(0.0f, 0.25f, 0.0f));
mMeshes.back()->reallocateNormals(mMeshes.back()->getNormals());
mMeshes.back()->setUniform("uMaterial.ambient", QVector3D(0.0f, 0.3f, 0.0f));
mMeshes.back()->setUniform("uMaterial.diffuse", QVector3D(0.0f, 0.2f, 0.0f));
mMeshes.back()->setUniform("uMaterial.specular", QVector3D(1.0f, 1.0f, 1.0f));
mMeshes.back()->setUniform("uMaterial.ambientStrength", 1.0f);
mMeshes.back()->setUniform("uMaterial.diffuseStrength", 1.0f);
mMeshes.back()->setUniform("uMaterial.specularStrength", 1.0f);
mMeshes.back()->setUniform("uMaterial.shine", 64.0f);
mMeshes.back()->setUniform("uLight.ambient", QVector3D(0.25f, 0.2f, 0.075f));
mMeshes.back()->setUniform("uLight.diffuse", QVector3D(0.75f, 0.6f, 0.22f));
mMeshes.back()->setUniform("uLight.specular", QVector3D(0.62f, 0.55f, 0.37f));
mMeshes.back()->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f));
// //
// Create simple shapes using MeshRenderer class and data in mesh.h // Test drawing simple geometry with various OpenGL drawing modes
mMeshes.push_back(
new Qtk::MeshRenderer("rightTriangle", Triangle(QTK_DRAW_ELEMENTS)));
mMeshes.back()->mTransform.setTranslation(-5.0f, 0.0f, -2.0f);
mMeshes.push_back(
new Qtk::MeshRenderer("centerCube", Cube(QTK_DRAW_ELEMENTS)));
mMeshes.back()->mTransform.setTranslation(-7.0f, 0.0f, -2.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);
// This function changes values we have allocated in a buffer, so init() after
mMeshes.back()->setColor(GREEN);
//
// Testing for normals, texture coordinates
// RGB Normals cube to show normals are correct with QTK_DRAW_ARRAYS // RGB Normals cube to show normals are correct with QTK_DRAW_ARRAYS
mMeshes.push_back( mMeshes.push_back(
@ -345,35 +384,11 @@ void ExampleScene::init() {
mMeshes.back()->setTexture(":/crate.png"); mMeshes.back()->setTexture(":/crate.png");
mMeshes.back()->setUniform("uTexture", 0); mMeshes.back()->setUniform("uTexture", 0);
mMeshes.back()->reallocateTexCoords(mMeshes.back()->getTexCoords()); 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() { 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(); Scene::draw();
for(const auto & model : mModels) { for(const auto & model : mModels) {
@ -392,13 +407,15 @@ void ExampleScene::draw() {
"uLightPosition", "uLightPosition",
MeshRenderer::getInstance("phongLight")->mTransform.getTranslation()); MeshRenderer::getInstance("phongLight")->mTransform.getTranslation());
mTestPhong->setUniform( mTestPhong->setUniform(
"uCameraPosition", ExampleScene::Camera().transform().getTranslation()); "uCameraPosition",
ExampleScene::getCamera().getTransform().getTranslation());
mTestPhong->releaseShaders(); mTestPhong->releaseShaders();
mTestPhong->draw(); mTestPhong->draw();
mTestAmbient->bindShaders(); mTestAmbient->bindShaders();
mTestAmbient->setUniform( mTestAmbient->setUniform(
"uCameraPosition", ExampleScene::Camera().transform().getTranslation()); "uCameraPosition",
ExampleScene::getCamera().getTransform().getTranslation());
mTestAmbient->releaseShaders(); mTestAmbient->releaseShaders();
mTestAmbient->draw(); mTestAmbient->draw();
@ -410,7 +427,8 @@ void ExampleScene::draw() {
"uLightPosition", "uLightPosition",
MeshRenderer::getInstance("diffuseLight")->mTransform.getTranslation()); MeshRenderer::getInstance("diffuseLight")->mTransform.getTranslation());
mTestDiffuse->setUniform( mTestDiffuse->setUniform(
"uCameraPosition", ExampleScene::Camera().transform().getTranslation()); "uCameraPosition",
ExampleScene::getCamera().getTransform().getTranslation());
mTestDiffuse->releaseShaders(); mTestDiffuse->releaseShaders();
mTestDiffuse->draw(); mTestDiffuse->draw();
@ -422,7 +440,8 @@ void ExampleScene::draw() {
"uLightPosition", "uLightPosition",
MeshRenderer::getInstance("specularLight")->mTransform.getTranslation()); MeshRenderer::getInstance("specularLight")->mTransform.getTranslation());
mTestSpecular->setUniform( mTestSpecular->setUniform(
"uCameraPosition", ExampleScene::Camera().transform().getTranslation()); "uCameraPosition",
ExampleScene::getCamera().getTransform().getTranslation());
mTestSpecular->releaseShaders(); mTestSpecular->releaseShaders();
mTestSpecular->draw(); mTestSpecular->draw();
} }
@ -433,12 +452,13 @@ void ExampleScene::update() {
auto alien = Model::getInstance("alienTest"); auto alien = Model::getInstance("alienTest");
alien->setUniform("uLight.position", position); alien->setUniform("uLight.position", position);
alien->setUniform( alien->setUniform(
"uCameraPosition", ExampleScene::Camera().transform().getTranslation()); "uCameraPosition",
ExampleScene::getCamera().getTransform().getTranslation());
auto posMatrix = alien->mTransform.toMatrix(); auto posMatrix = alien->mTransform.toMatrix();
alien->setUniform("uMVP.normalMatrix", posMatrix.normalMatrix()); alien->setUniform("uMVP.normalMatrix", posMatrix.normalMatrix());
alien->setUniform("uMVP.model", posMatrix); alien->setUniform("uMVP.model", posMatrix);
alien->setUniform("uMVP.view", ExampleScene::Camera().toMatrix()); alien->setUniform("uMVP.view", ExampleScene::getCamera().toMatrix());
alien->setUniform("uMVP.projection", ExampleScene::Projection()); alien->setUniform("uMVP.projection", ExampleScene::getProjectionMatrix());
alien->mTransform.rotate(0.75f, 0.0f, 1.0f, 0.0f); alien->mTransform.rotate(0.75f, 0.0f, 1.0f, 0.0f);
position = MeshRenderer::getInstance("spartanTestLight") position = MeshRenderer::getInstance("spartanTestLight")
@ -446,12 +466,13 @@ void ExampleScene::update() {
auto spartan = Model::getInstance("spartanTest"); auto spartan = Model::getInstance("spartanTest");
spartan->setUniform("uLight.position", position); spartan->setUniform("uLight.position", position);
spartan->setUniform( spartan->setUniform(
"uCameraPosition", ExampleScene::Camera().transform().getTranslation()); "uCameraPosition",
ExampleScene::getCamera().getTransform().getTranslation());
posMatrix = spartan->mTransform.toMatrix(); posMatrix = spartan->mTransform.toMatrix();
spartan->setUniform("uMVP.normalMatrix", posMatrix.normalMatrix()); spartan->setUniform("uMVP.normalMatrix", posMatrix.normalMatrix());
spartan->setUniform("uMVP.model", posMatrix); spartan->setUniform("uMVP.model", posMatrix);
spartan->setUniform("uMVP.view", ExampleScene::Camera().toMatrix()); spartan->setUniform("uMVP.view", ExampleScene::getCamera().toMatrix());
spartan->setUniform("uMVP.projection", ExampleScene::Projection()); spartan->setUniform("uMVP.projection", ExampleScene::getProjectionMatrix());
spartan->mTransform.rotate(0.75f, 0.0f, 1.0f, 0.0f); spartan->mTransform.rotate(0.75f, 0.0f, 1.0f, 0.0f);
auto phong = MeshRenderer::getInstance("testPhong"); auto phong = MeshRenderer::getInstance("testPhong");
@ -461,12 +482,13 @@ void ExampleScene::update() {
MeshRenderer::getInstance("testLight")->mTransform.getTranslation(); MeshRenderer::getInstance("testLight")->mTransform.getTranslation();
phong->setUniform("uLight.position", position); phong->setUniform("uLight.position", position);
phong->setUniform( phong->setUniform(
"uCameraPosition", ExampleScene::Camera().transform().getTranslation()); "uCameraPosition",
ExampleScene::getCamera().getTransform().getTranslation());
posMatrix = phong->mTransform.toMatrix(); posMatrix = phong->mTransform.toMatrix();
phong->setUniform("uMVP.normalMatrix", posMatrix.normalMatrix()); phong->setUniform("uMVP.normalMatrix", posMatrix.normalMatrix());
phong->setUniform("uMVP.model", posMatrix); phong->setUniform("uMVP.model", posMatrix);
phong->setUniform("uMVP.view", ExampleScene::Camera().toMatrix()); phong->setUniform("uMVP.view", ExampleScene::getCamera().toMatrix());
phong->setUniform("uMVP.projection", ExampleScene::Projection()); phong->setUniform("uMVP.projection", ExampleScene::getProjectionMatrix());
phong->releaseShaders(); phong->releaseShaders();
// Rotate lighting example cubes // Rotate lighting example cubes

View File

@ -9,22 +9,65 @@
#ifndef QTK_EXAMPLE_SCENE_H #ifndef QTK_EXAMPLE_SCENE_H
#define QTK_EXAMPLE_SCENE_H #define QTK_EXAMPLE_SCENE_H
#include <abstractscene.h>
#include <camera3d.h> #include <camera3d.h>
#include <scene.h>
#include <skybox.h> #include <skybox.h>
#include <QMatrix4x4> #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 { class ExampleScene : public Qtk::Scene {
public: public:
/***************************************************************************
* Contructors / Destructors
**************************************************************************/
ExampleScene(); ExampleScene();
~ExampleScene(); ~ExampleScene();
/***************************************************************************
* Inherited Public Overrides
**************************************************************************/
/**
* Initialize objects within the scene
*/
void init() override; void init() override;
/**
* Called when OpenGL repaints the widget.
*/
void draw() override; void draw() override;
/**
* Called when the Qt `frameSwapped` signal is caught.
* See definition of `QtkWidget::initializeGL()`
*/
void update() override; void update() override;
private: 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 * mTestPhong {};
Qtk::MeshRenderer * mTestSpecular {}; Qtk::MeshRenderer * mTestSpecular {};
Qtk::MeshRenderer * mTestDiffuse {}; Qtk::MeshRenderer * mTestDiffuse {};

View File

@ -16,20 +16,6 @@
int main(int argc, char * argv[]) { int main(int argc, char * argv[]) {
QApplication a(argc, 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 // Create window for Qt application using custom mainwindow.h
MainWindow w; MainWindow w;
w.show(); 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 using QtkWidget ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
##############################################################################*/
#include <mainwindow.h> #include <mainwindow.h>
#include <qtkwidget.h> #include <qtkwidget.h>
#include "ui_mainwindow.h" #include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget * parent) : MainWindow::MainWindow(QWidget * parent) :
QMainWindow(parent), ui(new Ui::MainWindow) { QMainWindow(parent), ui(new Ui::MainWindow) {
ui->setupUi(this);
// For use in design mode using Qt Creator // For use in design mode using Qt Creator
// + We can use the `ui` member to access nested widgets by name // + 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()) { for(const auto widget : ui->qWidget->children()) {
auto qtkWidget = dynamic_cast<Qtk::QtkWidget *>(widget); auto qtkWidget = dynamic_cast<Qtk::QtkWidget *>(widget);
if(qtkWidget != nullptr) { if(qtkWidget != nullptr) {
std::string key = qtkWidget->objectName().toStdString(); std::string key = qtkWidget->objectName().toStdString();
// Initialize each scene into a map if it doesn't exist.
if(mScenes[key] == nullptr) { 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")); 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 using QtkWidget ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
##############################################################################*/
#ifndef MAINWINDOW_H #ifndef MAINWINDOW_H
#define MAINWINDOW_H #define MAINWINDOW_H
@ -12,16 +20,32 @@ namespace Ui {
class MainWindow; class MainWindow;
} }
class QTK_WIDGET_EXPORT MainWindow /**
* MainWindow class to provide an example of using a QtkWidget within a Qt
: public QMainWindow { * window application.
*/
class QTK_WIDGET_EXPORT MainWindow : public QMainWindow {
Q_OBJECT Q_OBJECT
public: 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); explicit MainWindow(QWidget * parent = nullptr);
~MainWindow() override; ~MainWindow() override;
private: private:
/***************************************************************************
* Private Members
**************************************************************************/
Ui::MainWindow * ui {}; Ui::MainWindow * ui {};
std::unordered_map<std::string, Qtk::Scene *> mScenes {}; std::unordered_map<std::string, Qtk::Scene *> mScenes {};
}; };

View File

@ -13,6 +13,19 @@
#ifndef QTK_RESOURCEMANAGER_H #ifndef QTK_RESOURCEMANAGER_H
#define 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 { typedef class ResourceManager {
public: public:
/** /**
@ -24,7 +37,7 @@ typedef class ResourceManager {
* ':/models/backpack/backpack.obj' An asset at location * ':/models/backpack/backpack.obj' An asset at location
* qtk/resources/path/to/asset.obj Should be given in qrc format: * qtk/resources/path/to/asset.obj Should be given in qrc format:
* ':/path/to/asset.obj' * ':/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) { static std::string getPath(const std::string & path) {
// Only construct qtk resource path if in qrc format; else return it as-is // 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) { QDataStream & operator<<(QDataStream & out, Camera3D & transform) {
out << transform.transform(); out << transform.getTransform();
return out; return out;
} }
QDataStream & operator>>(QDataStream & in, Camera3D & transform) { QDataStream & operator>>(QDataStream & in, Camera3D & transform) {
in >> transform.transform(); in >> transform.getTransform();
return in; return in;
} }
QDebug operator<<(QDebug dbg, const Camera3D & transform) { QDebug operator<<(QDebug dbg, const Camera3D & transform) {
dbg << "Camera3D\n{\n"; dbg << "Camera3D\n{\n";
dbg << "Position: <" << transform.translation().x() << ", " dbg << "Position: <" << transform.getTranslation().x() << ", "
<< transform.translation().y() << ", " << transform.translation().z() << transform.getTranslation().y() << ", "
<< ">\n"; << transform.getTranslation().z() << ">\n";
dbg << "Rotation: <" << transform.rotation().x() << ", " dbg << "Rotation: <" << transform.getRotation().x() << ", "
<< transform.rotation().y() << ", " << transform.rotation().z() << " | " << transform.getRotation().y() << ", " << transform.getRotation().z()
<< transform.rotation().scalar() << ">\n}"; << " | " << transform.getRotation().scalar() << ">\n}";
return dbg; return dbg;
} }

View File

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

View File

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

@ -84,13 +84,26 @@ namespace Qtk {
typedef std::vector<QVector2D> TexCoords; typedef std::vector<QVector2D> TexCoords;
typedef std::vector<QVector3D> Normals; 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 { enum DrawMode {
QTK_DRAW_ARRAYS, QTK_DRAW_ARRAYS,
QTK_DRAW_ELEMENTS, QTK_DRAW_ELEMENTS,
QTK_DRAW_ELEMENTS_NORMALS QTK_DRAW_ELEMENTS_NORMALS
}; };
/**
* Base class for all simple shape objects.
*/
struct QTKAPI ShapeBase { struct QTKAPI ShapeBase {
public:
/*************************************************************************
* Constructors / Destructors
************************************************************************/
explicit ShapeBase( explicit ShapeBase(
DrawMode mode = QTK_DRAW_ARRAYS, Vertices v = {}, Indices i = {}, DrawMode mode = QTK_DRAW_ARRAYS, Vertices v = {}, Indices i = {},
Colors c = {}, TexCoords t = {}, Normals n = {}) : Colors c = {}, TexCoords t = {}, Normals n = {}) :
@ -99,6 +112,10 @@ namespace Qtk {
mIndices(std::move(i)), mTexCoords(std::move(t)), mIndices(std::move(i)), mTexCoords(std::move(t)),
mNormals(std::move(n)) {} mNormals(std::move(n)) {}
/*************************************************************************
* Accessors
************************************************************************/
[[nodiscard]] inline const Vertices & getVertices() const { [[nodiscard]] inline const Vertices & getVertices() const {
return mVertices; return mVertices;
} }
@ -122,6 +139,10 @@ namespace Qtk {
} }
protected: protected:
/*************************************************************************
* Protected Members
************************************************************************/
DrawMode mDrawMode; DrawMode mDrawMode;
Vertices mVertices {}; Vertices mVertices {};
@ -132,13 +153,26 @@ namespace Qtk {
}; };
struct Shape : public ShapeBase { struct Shape : public ShapeBase {
public:
/*************************************************************************
* Typedefs
************************************************************************/
friend MeshRenderer; friend MeshRenderer;
friend Object; friend Object;
/*************************************************************************
* Constructors / Destructors
************************************************************************/
Shape() = default; Shape() = default;
explicit Shape(const ShapeBase & rhs) : ShapeBase(rhs) {} explicit Shape(const ShapeBase & rhs) : ShapeBase(rhs) {}
/*************************************************************************
* Setters
************************************************************************/
virtual inline void setVertices(const Vertices & value) { virtual inline void setVertices(const Vertices & value) {
mVertices = value; mVertices = value;
} }
@ -160,13 +194,15 @@ namespace Qtk {
virtual inline void setShape(const Shape & value) { *this = value; } 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 {}; class QTKAPI Mesh {};
/* Simple Cube shape. */
struct QTKAPI Cube : public ShapeBase { struct QTKAPI Cube : public ShapeBase {
explicit Cube(DrawMode mode = QTK_DRAW_ARRAYS); explicit Cube(DrawMode mode = QTK_DRAW_ARRAYS);
}; };
/* Simple Triangle shape. */
struct QTKAPI Triangle : public ShapeBase { struct QTKAPI Triangle : public ShapeBase {
explicit Triangle(DrawMode mode = QTK_DRAW_ARRAYS); explicit Triangle(DrawMode mode = QTK_DRAW_ARRAYS);
}; };

View File

@ -8,8 +8,8 @@
#include <QImageReader> #include <QImageReader>
#include <abstractscene.h>
#include <meshrenderer.h> #include <meshrenderer.h>
#include <scene.h>
#include <texture.h> #include <texture.h>
using namespace Qtk; using namespace Qtk;
@ -31,6 +31,13 @@ MeshRenderer::~MeshRenderer() {
// Static member function to retrieve instances of MeshRenderers // Static member function to retrieve instances of MeshRenderers
MeshRenderer * MeshRenderer::getInstance(const QString & name) { 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]; return sInstances[name];
} }
@ -126,8 +133,8 @@ void MeshRenderer::setShaders(
void MeshRenderer::setUniformMVP( void MeshRenderer::setUniformMVP(
const char * model, const char * view, const char * projection) { const char * model, const char * view, const char * projection) {
ShaderBindScope lock(&mProgram, mBound); ShaderBindScope lock(&mProgram, mBound);
mProgram.setUniformValue(projection, Scene::Projection()); mProgram.setUniformValue(projection, Scene::getProjectionMatrix());
mProgram.setUniformValue(view, Scene::View()); mProgram.setUniformValue(view, Scene::getViewMatrix());
mProgram.setUniformValue(model, mTransform.toMatrix()); mProgram.setUniformValue(model, mTransform.toMatrix());
} }
@ -141,6 +148,8 @@ void MeshRenderer::setColor(const QVector3D & color) {
mShape.mColors[i] = 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) { void MeshRenderer::reallocateTexCoords(const TexCoords & t, unsigned dims) {

View File

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

View File

@ -9,9 +9,9 @@
#include <QFileInfo> #include <QFileInfo>
#include <abstractscene.h>
#include <model.h> #include <model.h>
#include <resourcemanager.h> #include <resourcemanager.h>
#include <scene.h>
#include <texture.h> #include <texture.h>
using namespace Qtk; using namespace Qtk;
@ -97,8 +97,8 @@ void ModelMesh::draw(QOpenGLShaderProgram & shader) {
// Set Model View Projection values // Set Model View Projection values
shader.setUniformValue("uModel", mTransform.toMatrix()); shader.setUniformValue("uModel", mTransform.toMatrix());
shader.setUniformValue("uView", Scene::View()); shader.setUniformValue("uView", Scene::getViewMatrix());
shader.setUniformValue("uProjection", Scene::Projection()); shader.setUniformValue("uProjection", Scene::getProjectionMatrix());
GLuint diffuseCount = 1; GLuint diffuseCount = 1;
GLuint specularCount = 1; GLuint specularCount = 1;
@ -180,21 +180,6 @@ void Model::flipTexture(const std::string & fileName, bool flipX, bool flipY) {
* Model Private Member Functions * 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) { void Model::loadModel(const std::string & path) {
Assimp::Importer import; Assimp::Importer import;
@ -362,7 +347,7 @@ ModelMesh::Textures Model::loadMaterialTextures(
// If the texture has not yet been loaded // If the texture has not yet been loaded
if(!skip) { if(!skip) {
ModelTexture texture; ModelTexture texture;
texture.mTexture = OpenGLTextureFactory::initTexture2D( texture.mTexture = OpenGLTextureFactory::initTexture(
std::string(mDirectory + '/' + fileName.C_Str()).c_str(), false, std::string(mDirectory + '/' + fileName.C_Str()).c_str(), false,
false); false);
texture.mID = texture.mTexture->textureId(); texture.mID = texture.mTexture->textureId();
@ -380,7 +365,7 @@ ModelMesh::Textures Model::loadMaterialTextures(
} }
void Model::sortModels() { void Model::sortModels() {
auto cameraPos = Scene::Camera().transform(); auto cameraPos = Scene::getCamera().getTransform();
auto cameraDistance = [&cameraPos](const ModelMesh & a, const ModelMesh & b) { auto cameraDistance = [&cameraPos](const ModelMesh & a, const ModelMesh & b) {
// Sort by the first vertex position in the model // Sort by the first vertex position in the model
return (cameraPos.getTranslation().distanceToPoint( return (cameraPos.getTranslation().distanceToPoint(

View File

@ -28,14 +28,20 @@
#include <transform3D.h> #include <transform3D.h>
namespace Qtk { namespace Qtk {
/**
* 3D models will store this data for each vertex in geometry
*/
struct QTKAPI ModelVertex { struct QTKAPI ModelVertex {
QVector3D mPosition; QVector3D mPosition;
QVector3D mNormal; QVector3D mNormal;
QVector2D mTextureCoord;
QVector3D mTangent; QVector3D mTangent;
QVector3D mBitangent; QVector3D mBitangent;
QVector2D mTextureCoord;
}; };
/**
* Struct to store model textures. 3D Models may have multiple.
*/
struct QTKAPI ModelTexture { struct QTKAPI ModelTexture {
GLuint mID {}; GLuint mID {};
QOpenGLTexture * mTexture {}; QOpenGLTexture * mTexture {};
@ -45,14 +51,25 @@ namespace Qtk {
class Model; 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 { class QTKAPI ModelMesh : protected QOpenGLFunctions {
public: public:
/*************************************************************************
* Typedefs
************************************************************************/
friend Model; friend Model;
typedef std::vector<ModelVertex> Vertices; typedef std::vector<ModelVertex> Vertices;
typedef std::vector<GLuint> Indices; typedef std::vector<GLuint> Indices;
typedef std::vector<ModelTexture> Textures; typedef std::vector<ModelTexture> Textures;
// Constructors, Destructors /*************************************************************************
* Constructors, Destructors
************************************************************************/
ModelMesh( ModelMesh(
Vertices vertices, Indices indices, Textures textures, Vertices vertices, Indices indices, Textures textures,
const char * vertexShader = ":/model-basic.vert", const char * vertexShader = ":/model-basic.vert",
@ -68,78 +85,180 @@ namespace Qtk {
~ModelMesh() = default; ~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); } inline void draw() { draw(*mProgram); }
void draw(QOpenGLShaderProgram & shader); void draw(QOpenGLShaderProgram & shader);
// ModelMesh Public Members /*************************************************************************
* Public Members
************************************************************************/
Vertices mVertices {}; Vertices mVertices {};
Indices mIndices {}; Indices mIndices {};
Textures mTextures {}; Textures mTextures {};
Transform3D mTransform; 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 { class QTKAPI Model : public QObject {
Q_OBJECT Q_OBJECT
public: 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( inline Model(
const char * name, const char * path, const char * name, const char * path,
const char * vertexShader = ":/model-basic.vert", const char * vertexShader = ":/model-basic.vert",
const char * fragmentShader = ":/model-basic.frag") : const char * fragmentShader = ":/model-basic.frag") :
mName(name), mName(name),
mVertexShader(vertexShader), mFragmentShader(fragmentShader) { mModelPath(path), mVertexShader(vertexShader),
mFragmentShader(fragmentShader) {
loadModel(path); loadModel(path);
} }
inline ~Model() override { mManager.remove(mName); } inline ~Model() override { mManager.remove(mName); }
/*************************************************************************
* Public Methods
************************************************************************/
void draw(); void draw();
void draw(QOpenGLShaderProgram & shader); 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( void flipTexture(
const std::string & fileName, bool flipX = false, bool flipY = true); 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) { template <typename T> void setUniform(const char * location, T value) {
for(auto & mesh : mMeshes) { for(auto & mesh : mMeshes) {
mesh.mProgram->bind(); mesh.mProgram->bind();
mesh.mProgram->setUniformValue(location, value); mesh.mProgram->setUniformValue(location, value);
mesh.mProgram->release(); 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); static Model * getInstance(const char * name);
typedef QHash<QString, Model *> ModelManager; /*************************************************************************
* Public Members
************************************************************************/
/* The position of this model in 3D space */
// TODO: Make private
Transform3D mTransform;
private: 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 loadModel(const std::string & path);
void processNode(aiNode * node, const aiScene * scene); void processNode(aiNode * node, const aiScene * scene);
ModelMesh processMesh(aiMesh * mesh, const aiScene * scene); ModelMesh processMesh(aiMesh * mesh, const aiScene * scene);
ModelMesh::Textures loadMaterialTextures( ModelMesh::Textures loadMaterialTextures(
aiMaterial * mat, aiTextureType type, const std::string & typeName); aiMaterial * mat, aiTextureType type, const std::string & typeName);
void sortModels(); void sortModels();
// Model Private Members /*************************************************************************
* Private Members
************************************************************************/
/* Static QHash used to store and access models globally. */
static ModelManager mManager;
/* Container to store N loaded textures for this model. */
ModelMesh::Textures mTexturesLoaded {}; ModelMesh::Textures mTexturesLoaded {};
/* Container to store N loaded meshes for this model. */
std::vector<ModelMesh> mMeshes {}; std::vector<ModelMesh> mMeshes {};
/* The directory this model and it's textures are stored. */
std::string mDirectory {}; 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 } // namespace Qtk

View File

@ -18,12 +18,24 @@
#include <texture.h> #include <texture.h>
namespace Qtk { 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 { class QTKAPI Object : public QObject {
Q_OBJECT Q_OBJECT
public: public:
/*************************************************************************
* Typedefs
************************************************************************/
friend MeshRenderer; friend MeshRenderer;
/*************************************************************************
* Constructors / Destructors
************************************************************************/
// Initialize an object with no shape data assigned // Initialize an object with no shape data assigned
explicit Object(const char * name) : explicit Object(const char * name) :
mName(name), mVBO(QOpenGLBuffer::VertexBuffer), mBound(false) {} mName(name), mVBO(QOpenGLBuffer::VertexBuffer), mBound(false) {}
@ -35,6 +47,10 @@ namespace Qtk {
~Object() override = default; ~Object() override = default;
/*************************************************************************
* Accessors
************************************************************************/
inline const Colors & getColors() { return mShape.mColors; } inline const Colors & getColors() { return mShape.mColors; }
inline const Indices & getIndexData() { return mShape.mIndices; } inline const Indices & getIndexData() { return mShape.mIndices; }
@ -49,6 +65,10 @@ namespace Qtk {
inline const Vertices & getVertices() { return mShape.mVertices; } inline const Vertices & getVertices() { return mShape.mVertices; }
/*************************************************************************
* Setters
************************************************************************/
virtual inline void setColors(const Colors & value) { virtual inline void setColors(const Colors & value) {
mShape.mColors = value; mShape.mColors = value;
} }
@ -84,6 +104,10 @@ namespace Qtk {
mShape.mVertices = value; mShape.mVertices = value;
} }
/*************************************************************************
* Public Methods
************************************************************************/
virtual inline void bindShaders() { virtual inline void bindShaders() {
mBound = true; mBound = true;
mProgram.bind(); mProgram.bind();
@ -94,6 +118,10 @@ namespace Qtk {
mProgram.release(); mProgram.release();
} }
/*************************************************************************
* Public Members
************************************************************************/
QOpenGLBuffer mVBO, mNBO; QOpenGLBuffer mVBO, mNBO;
QOpenGLVertexArrayObject mVAO; QOpenGLVertexArrayObject mVAO;
@ -104,9 +132,9 @@ namespace Qtk {
bool mBound; bool mBound;
private: private:
virtual inline void setTexture(QOpenGLTexture * value) { /*************************************************************************
mTexture.setTexture(value); * Private Members
} ************************************************************************/
QOpenGLShaderProgram mProgram; QOpenGLShaderProgram mProgram;
}; };

View File

@ -8,10 +8,10 @@
#include <QKeyEvent> #include <QKeyEvent>
#include <abstractscene.h>
#include <input.h> #include <input.h>
#include <mesh.h> #include <mesh.h>
#include <qtkwidget.h> #include <qtkwidget.h>
#include <scene.h>
using namespace Qtk; using namespace Qtk;
@ -23,7 +23,6 @@ QtkWidget::QtkWidget() : mScene(Q_NULLPTR), mDebugLogger(Q_NULLPTR) {
initializeWidget(); initializeWidget();
} }
// Constructor for using this widget in QtDesigner
QtkWidget::QtkWidget(QWidget * parent) : QtkWidget::QtkWidget(QWidget * parent) :
QOpenGLWidget(parent), mScene(Q_NULLPTR), mDebugLogger(Q_NULLPTR) { QOpenGLWidget(parent), mScene(Q_NULLPTR), mDebugLogger(Q_NULLPTR) {
initializeWidget(); 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() { void QtkWidget::initializeGL() {
initializeOpenGLFunctions(); initializeOpenGLFunctions();
// Connect the frameSwapped signal to call the update() function // Connect the frameSwapped signal to call the update() function
@ -93,11 +74,19 @@ void QtkWidget::initializeGL() {
} }
void QtkWidget::resizeGL(int width, int height) { void QtkWidget::resizeGL(int width, int height) {
Scene::Projection().setToIdentity(); Scene::getProjectionMatrix().setToIdentity();
Scene::Projection().perspective( Scene::getProjectionMatrix().perspective(
45.0f, float(width) / float(height), 0.1f, 1000.0f); 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 * Protected Slots
******************************************************************************/ ******************************************************************************/
@ -175,7 +164,7 @@ void QtkWidget::messageLogged(const QOpenGLDebugMessage & msg) {
} }
/******************************************************************************* /*******************************************************************************
* Protected Helpers * Protected Methods
******************************************************************************/ ******************************************************************************/
void QtkWidget::keyPressEvent(QKeyEvent * event) { void QtkWidget::keyPressEvent(QKeyEvent * event) {
@ -204,7 +193,7 @@ void QtkWidget::mouseReleaseEvent(QMouseEvent * event) {
} }
/******************************************************************************* /*******************************************************************************
* Private Helpers * Private Methods
******************************************************************************/ ******************************************************************************/
void QtkWidget::initializeWidget() { void QtkWidget::initializeWidget() {
@ -265,31 +254,31 @@ void QtkWidget::updateCameraInput() {
static const float rotSpeed = 0.5f; static const float rotSpeed = 0.5f;
// Handle rotations // Handle rotations
Scene::Camera().transform().rotate( Scene::getCamera().getTransform().rotate(
-rotSpeed * Input::mouseDelta().x(), Camera3D::LocalUp); -rotSpeed * Input::mouseDelta().x(), Camera3D::LocalUp);
Scene::Camera().transform().rotate( Scene::getCamera().getTransform().rotate(
-rotSpeed * Input::mouseDelta().y(), Scene::Camera().right()); -rotSpeed * Input::mouseDelta().y(), Scene::getCamera().right());
// Handle translations // Handle translations
QVector3D translation; QVector3D translation;
if(Input::keyPressed(Qt::Key_W)) { if(Input::keyPressed(Qt::Key_W)) {
translation += Scene::Camera().forward(); translation += Scene::getCamera().forward();
} }
if(Input::keyPressed(Qt::Key_S)) { if(Input::keyPressed(Qt::Key_S)) {
translation -= Scene::Camera().forward(); translation -= Scene::getCamera().forward();
} }
if(Input::keyPressed(Qt::Key_A)) { if(Input::keyPressed(Qt::Key_A)) {
translation -= Scene::Camera().right(); translation -= Scene::getCamera().right();
} }
if(Input::keyPressed(Qt::Key_D)) { if(Input::keyPressed(Qt::Key_D)) {
translation += Scene::Camera().right(); translation += Scene::getCamera().right();
} }
if(Input::keyPressed(Qt::Key_Q)) { if(Input::keyPressed(Qt::Key_Q)) {
translation -= Scene::Camera().up() / 2.0f; translation -= Scene::getCamera().up() / 2.0f;
} }
if(Input::keyPressed(Qt::Key_E)) { 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 <QOpenGLFunctions>
#include <QOpenGLWidget> #include <QOpenGLWidget>
#include <abstractscene.h>
#include <qtkapi.h> #include <qtkapi.h>
#include <scene.h>
namespace Qtk { 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 { class QTKAPI QtkWidget : public QOpenGLWidget, protected QOpenGLFunctions {
Q_OBJECT; Q_OBJECT;
public: public:
// Constructors /*************************************************************************
* Contructors / Destructors
************************************************************************/
/**
* Default ctor will configure a QSurfaceFormat with default settings.
*/
QtkWidget(); QtkWidget();
/**
* Qt Designer will call this ctor when creating this widget as a child.
*
* @param parent The parent QWidget
*/
explicit QtkWidget(QWidget * parent); 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); explicit QtkWidget(const QSurfaceFormat & format);
~QtkWidget() override; ~QtkWidget() override;
private: private:
void teardownGL(); /*************************************************************************
* Private Methods
************************************************************************/
// clang-format off
void teardownGL() { /* Nothing to teardown yet... */ }
// clang-format on
public: public:
// Inherited virtual Members /*************************************************************************
void paintGL() override; * Public Inherited Virtual Methods
************************************************************************/
/**
* Called when the widget is first constructed.
*/
void initializeGL() override; 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; void resizeGL(int width, int height) override;
/**
* Called when OpenGL repaints the widget.
*/
void paintGL() override;
/*************************************************************************
* Accessors
************************************************************************/
inline Qtk::Scene * getScene() { return mScene; } inline Qtk::Scene * getScene() { return mScene; }
/*************************************************************************
* Setters
************************************************************************/
inline void setScene(Qtk::Scene * scene) { inline void setScene(Qtk::Scene * scene) {
delete mScene; delete mScene;
mScene = scene; mScene = scene;
} }
protected slots: protected slots:
/*************************************************************************
* Qt Slots
************************************************************************/
/**
* Called when the `frameSwapped` signal is caught.
* See definition of initializeGL()
*/
void update(); void update();
#ifdef QTK_DEBUG #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); static void messageLogged(const QOpenGLDebugMessage & msg);
#endif #endif
// Protected Helpers
protected: protected:
/*************************************************************************
* Protected Methods
************************************************************************/
void keyPressEvent(QKeyEvent * event) override; void keyPressEvent(QKeyEvent * event) override;
void keyReleaseEvent(QKeyEvent * event) override; void keyReleaseEvent(QKeyEvent * event) override;
void mousePressEvent(QMouseEvent * event) override; void mousePressEvent(QMouseEvent * event) override;
void mouseReleaseEvent(QMouseEvent * event) override; void mouseReleaseEvent(QMouseEvent * event) override;
private: private:
// Private helpers /*************************************************************************
* Private Methods
************************************************************************/
void initializeWidget(); void initializeWidget();
static void updateCameraInput(); static void updateCameraInput();
Qtk::Scene * mScene;
#ifdef QTK_DEBUG #ifdef QTK_DEBUG
void printContextInformation(); void printContextInformation();
QOpenGLDebugLogger * mDebugLogger; QOpenGLDebugLogger * mDebugLogger;
#endif #endif
/*************************************************************************
* Private Members
************************************************************************/
Qtk::Scene * mScene;
}; };
} // namespace Qtk } // namespace Qtk

View File

@ -6,9 +6,9 @@
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
##############################################################################*/ ##############################################################################*/
#include <abstractscene.h>
#include <camera3d.h> #include <camera3d.h>
#include <resourcemanager.h> #include <resourcemanager.h>
#include <scene.h>
#include <texture.h> #include <texture.h>
using namespace Qtk; using namespace Qtk;
@ -21,8 +21,8 @@ QMatrix4x4 Scene::mProjection;
******************************************************************************/ ******************************************************************************/
Scene::Scene() { Scene::Scene() {
mCamera.transform().setTranslation(0.0f, 0.0f, 20.0f); mCamera.getTransform().setTranslation(0.0f, 0.0f, 20.0f);
mCamera.transform().setRotation(-5.0f, 0.0f, 1.0f, 0.0f); mCamera.getTransform().setRotation(-5.0f, 0.0f, 1.0f, 0.0f);
} }
Scene::~Scene() { Scene::~Scene() {
@ -32,11 +32,10 @@ Scene::~Scene() {
for(auto & model : mModels) { for(auto & model : mModels) {
delete model; delete model;
} }
delete mSkybox; delete mSkybox;
} }
void Scene::privDraw() { void Scene::privateDraw() {
if(!mInit) { if(!mInit) {
initializeOpenGLFunctions(); initializeOpenGLFunctions();
init(); 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 ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
##############################################################################*/ ##############################################################################*/
#include <abstractscene.h> #include <scene.h>
#include <skybox.h> #include <skybox.h>
#include <texture.h> #include <texture.h>
@ -32,8 +32,8 @@ Skybox::Skybox(const std::string & name) :
":/right.png", ":/top.png", ":/front.png", ":/left.png", ":/bottom.png", ":/right.png", ":/top.png", ":/front.png", ":/left.png", ":/bottom.png",
":/back.png", name) {} ":/back.png", name) {}
Skybox::Skybox(QOpenGLTexture * cubeMap, const std::string & name) : Skybox::Skybox(QOpenGLTexture * cubeMap, const std::string & name) {
mTexture(cubeMap) { mTexture.setTexture(cubeMap);
init(); init();
} }
@ -49,8 +49,8 @@ void Skybox::draw() {
mProgram.bind(); mProgram.bind();
mTexture.getOpenGLTexture().bind(); mTexture.getOpenGLTexture().bind();
mProgram.setUniformValue("uProjectionMatrix", Scene::Projection()); mProgram.setUniformValue("uProjectionMatrix", Scene::getProjectionMatrix());
mProgram.setUniformValue("uViewMatrix", Scene::Camera().toMatrix()); mProgram.setUniformValue("uViewMatrix", Scene::getCamera().toMatrix());
mProgram.setUniformValue("uTexture", 0); mProgram.setUniformValue("uTexture", 0);
glDrawElements( glDrawElements(
GL_TRIANGLES, mIndices.size(), GL_UNSIGNED_INT, mIndices.data()); GL_TRIANGLES, mIndices.size(), GL_UNSIGNED_INT, mIndices.data());

View File

@ -21,13 +21,23 @@
#include <texture.h> #include <texture.h>
namespace Qtk { 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 { class QTKAPI Skybox : protected QOpenGLFunctions {
public: public:
/*************************************************************************
* Constructors / Destructors
************************************************************************/
// Delegate this constructor to use default skybox images // Delegate this constructor to use default skybox images
explicit Skybox(const std::string & name = "Skybox"); explicit Skybox(const std::string & name = "Skybox");
explicit Skybox( explicit Skybox(
QOpenGLTexture * cubeMap, const std::string & name = "Skybox"); QOpenGLTexture * cubeMap, const std::string & name = "Skybox");
// Constructor, Destructor
Skybox( Skybox(
const std::string & right, const std::string & top, const std::string & right, const std::string & top,
const std::string & front, const std::string & left, const std::string & front, const std::string & left,
@ -36,11 +46,23 @@ namespace Qtk {
~Skybox() = default; ~Skybox() = default;
/*************************************************************************
* Public Methods
************************************************************************/
void draw(); void draw();
private: private:
/*************************************************************************
* Private Methods
************************************************************************/
void init(); void init();
/*************************************************************************
* Private Members
************************************************************************/
Vertices mVertices {}; Vertices mVertices {};
Indices mIndices {}; Indices mIndices {};

View File

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

View File

@ -9,30 +9,124 @@
#ifndef QTOPENGL_TEXTURE_H #ifndef QTOPENGL_TEXTURE_H
#define QTOPENGL_TEXTURE_H #define QTOPENGL_TEXTURE_H
#include <QOpenGLShaderProgram>
#include <QOpenGLTexture> #include <QOpenGLTexture>
#include <utility> #include <utility>
#include <qtkapi.h> #include <qtkapi.h>
namespace Qtk { 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 { class QTKAPI OpenGLTextureFactory {
public: public:
/*************************************************************************
* Constructors / Destructors
************************************************************************/
~OpenGLTextureFactory() = default; ~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( static QImage * initImage(
const char * image, bool flipX = false, bool flipY = false); 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); 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( static QOpenGLTexture * initCubeMap(
const QImage & right, const QImage & top, const QImage & front, const QImage & right, const QImage & top, const QImage & front,
const QImage & left, const QImage & bottom, const QImage & back); 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); 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( static QOpenGLTexture * initCubeMap(
const char * right, const char * top, const char * front, const char * right, const char * top, const char * front,
const char * left, const char * bottom, const char * back); const char * left, const char * bottom, const char * back);
@ -42,48 +136,66 @@ namespace Qtk {
OpenGLTextureFactory() = default; 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 { class Texture {
public: public:
/*************************************************************************
* Typedefs
************************************************************************/
friend class Skybox;
/*************************************************************************
* Constructors / Destructors
************************************************************************/
Texture() = default; Texture() = default;
Texture(const Texture & value) { Texture(const Texture & value) {
mOpenGLTexture = OpenGLTextureFactory::initTexture2D(value.mPath); mOpenGLTexture = OpenGLTextureFactory::initTexture(value.mPath);
mPath = value.mPath; mPath = value.mPath;
} }
explicit Texture( explicit Texture(
const char * path, bool flipX = false, bool flipY = false) : const char * path, bool flipX = false, bool flipY = false) :
mOpenGLTexture( mOpenGLTexture(OpenGLTextureFactory::initTexture(path, flipX, flipY)),
OpenGLTextureFactory::initTexture2D(path, flipX, flipY)),
mPath(path) {} mPath(path) {}
explicit Texture(QOpenGLTexture * texture) : mOpenGLTexture(texture) {} explicit Texture(QOpenGLTexture * texture) : mOpenGLTexture(texture) {}
~Texture() { mOpenGLTexture->destroy(); } ~Texture() { mOpenGLTexture->destroy(); }
/*************************************************************************
* Accessors
************************************************************************/
[[nodiscard]] inline QOpenGLTexture & getOpenGLTexture() const { [[nodiscard]] inline QOpenGLTexture & getOpenGLTexture() const {
return *mOpenGLTexture; return *mOpenGLTexture;
} }
[[nodiscard]] inline std::string getPath() const { return mPath; } [[nodiscard]] inline std::string getPath() const { return mPath; }
/*************************************************************************
* Setters
************************************************************************/
void setTexture( void setTexture(
const std::string & path, bool flipX = false, bool flipY = false) { const std::string & path, bool flipX = false, bool flipY = false) {
mOpenGLTexture = mOpenGLTexture =
OpenGLTextureFactory::initTexture2D(path.data(), flipX, flipY); OpenGLTextureFactory::initTexture(path.data(), flipX, flipY);
mPath = path.data(); mPath = path.data();
} }
void setTexture( void setTexture(
const char * path, bool flipX = false, bool flipY = false) { const char * path, bool flipX = false, bool flipY = false) {
mOpenGLTexture = mOpenGLTexture = OpenGLTextureFactory::initTexture(path, flipX, flipY);
OpenGLTextureFactory::initTexture2D(path, flipX, flipY);
mPath = path; 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) { virtual inline void setCubeMap(const char * path) {
mOpenGLTexture = OpenGLTextureFactory::initCubeMap(path); mOpenGLTexture = OpenGLTextureFactory::initCubeMap(path);
mPath = path; mPath = path;
@ -103,12 +215,24 @@ namespace Qtk {
right, top, front, left, bottom, back); right, top, front, left, bottom, back);
} }
/*************************************************************************
* Public Methods
************************************************************************/
[[nodiscard]] inline bool hasTexture() const { [[nodiscard]] inline bool hasTexture() const {
return mOpenGLTexture != Q_NULLPTR; return mOpenGLTexture != Q_NULLPTR;
} }
private: private:
/*************************************************************************
* Private Members
************************************************************************/
inline void setTexture(QOpenGLTexture * texture) {
mOpenGLTexture = texture;
}
QOpenGLTexture * mOpenGLTexture = Q_NULLPTR; QOpenGLTexture * mOpenGLTexture = Q_NULLPTR;
/* Path to this texture on disk or Qt resource. */
const char * mPath {}; const char * mPath {};
}; };

View File

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