Rebase and format

+ clang-tidy, clang-format
This commit is contained in:
Shaun Reed 2022-11-19 16:00:20 -05:00
parent 697cdd0e75
commit 8906a4c508
34 changed files with 1950 additions and 1563 deletions

76
.clang-format Normal file
View File

@ -0,0 +1,76 @@
---
# clang-format off
BasedOnStyle: Google
# clang-format on
AlignAfterOpenBracket: AlwaysBreak
AlignArrayOfStructures: Left
AlignConsecutiveAssignments: None
AlignConsecutiveDeclarations: None
AlignConsecutiveMacros: Consecutive
AlignEscapedNewlines: Left
AlignOperands: Align
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Inline
AllowShortIfStatementsOnASingleLine: Never
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: false
AlwaysBreakTemplateDeclarations: MultiLine
InsertBraces: true
IndentAccessModifiers: true
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
BinPackArguments: true
BinPackParameters: true
BreakBeforeBinaryOperators: NonAssignment
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: AfterColon
BreakInheritanceList: AfterColon
BreakStringLiterals: true
ColumnLimit: 80
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
QualifierAlignment: Left
ReferenceAlignment: Middle
DerivePointerAlignment: false
SpaceAroundPointerQualifiers: Both
FixNamespaceComments: true
IncludeBlocks: Preserve
IndentCaseLabels: true
IndentPPDirectives: None
IndentWidth: 2
IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: false
Language: Cpp
MaxEmptyLinesToKeep: 2
NamespaceIndentation: All
ObjCBlockIndentWidth: 2
PointerAlignment: Middle
ReflowComments: true
SortIncludes: CaseSensitive
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: true
SpaceBeforeCtorInitializerColon: true
SpaceBeforeParens: Never
SpaceBeforeRangeBasedForLoopColon: true
SpacesBeforeTrailingComments: 2
SpaceInEmptyParentheses: false
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Latest
TabWidth: 2
UseTab: Never
...

148
.clang-tidy Normal file
View File

@ -0,0 +1,148 @@
# Generated from CLion Inspection settings
---
Checks: '-*,
bugprone-argument-comment,
bugprone-assert-side-effect,
bugprone-bad-signal-to-kill-thread,
bugprone-branch-clone,
bugprone-copy-constructor-init,
bugprone-dangling-handle,
bugprone-dynamic-static-initializers,
bugprone-fold-init-type,
bugprone-forward-declaration-namespace,
bugprone-forwarding-reference-overload,
bugprone-inaccurate-erase,
bugprone-incorrect-roundings,
bugprone-integer-division,
bugprone-lambda-function-name,
bugprone-macro-parentheses,
bugprone-macro-repeated-side-effects,
bugprone-misplaced-operator-in-strlen-in-alloc,
bugprone-misplaced-pointer-arithmetic-in-alloc,
bugprone-misplaced-widening-cast,
bugprone-move-forwarding-reference,
bugprone-multiple-statement-macro,
bugprone-no-escape,
bugprone-not-null-terminated-result,
bugprone-parent-virtual-call,
bugprone-posix-return,
bugprone-reserved-identifier,
bugprone-sizeof-container,
bugprone-sizeof-expression,
bugprone-spuriously-wake-up-functions,
bugprone-string-constructor,
bugprone-string-integer-assignment,
bugprone-string-literal-with-embedded-nul,
bugprone-suspicious-enum-usage,
bugprone-suspicious-include,
bugprone-suspicious-memory-comparison,
bugprone-suspicious-memset-usage,
bugprone-suspicious-missing-comma,
bugprone-suspicious-semicolon,
bugprone-suspicious-string-compare,
bugprone-swapped-arguments,
bugprone-terminating-continue,
bugprone-throw-keyword-missing,
bugprone-too-small-loop-variable,
bugprone-undefined-memory-manipulation,
bugprone-undelegated-constructor,
bugprone-unhandled-self-assignment,
bugprone-unused-raii,
bugprone-unused-return-value,
bugprone-use-after-move,
bugprone-virtual-near-miss,
cert-dcl21-cpp,
cert-dcl58-cpp,
cert-err34-c,
cert-err52-cpp,
cert-err60-cpp,
cert-flp30-c,
cert-msc50-cpp,
cert-msc51-cpp,
cert-str34-c,
cppcoreguidelines-interfaces-global-init,
cppcoreguidelines-narrowing-conversions,
cppcoreguidelines-pro-type-member-init,
cppcoreguidelines-pro-type-static-cast-downcast,
cppcoreguidelines-slicing,
google-default-arguments,
google-explicit-constructor,
google-runtime-operator,
hicpp-exception-baseclass,
hicpp-multiway-paths-covered,
misc-misplaced-const,
misc-new-delete-overloads,
misc-no-recursion,
misc-non-copyable-objects,
misc-throw-by-value-catch-by-reference,
misc-unconventional-assign-operator,
misc-uniqueptr-reset-release,
modernize-avoid-bind,
modernize-concat-nested-namespaces,
modernize-deprecated-headers,
modernize-deprecated-ios-base-aliases,
modernize-loop-convert,
modernize-make-shared,
modernize-make-unique,
modernize-pass-by-value,
modernize-raw-string-literal,
modernize-redundant-void-arg,
modernize-replace-auto-ptr,
modernize-replace-disallow-copy-and-assign-macro,
modernize-replace-random-shuffle,
modernize-return-braced-init-list,
modernize-shrink-to-fit,
modernize-unary-static-assert,
modernize-use-auto,
modernize-use-bool-literals,
modernize-use-emplace,
modernize-use-equals-default,
modernize-use-equals-delete,
modernize-use-nodiscard,
modernize-use-noexcept,
modernize-use-nullptr,
modernize-use-override,
modernize-use-transparent-functors,
modernize-use-uncaught-exceptions,
mpi-buffer-deref,
mpi-type-mismatch,
openmp-use-default-none,
performance-faster-string-find,
performance-for-range-copy,
performance-implicit-conversion-in-loop,
performance-inefficient-algorithm,
performance-inefficient-string-concatenation,
performance-inefficient-vector-operation,
performance-move-const-arg,
performance-move-constructor-init,
performance-no-automatic-move,
performance-noexcept-move-constructor,
performance-trivially-destructible,
performance-type-promotion-in-math-fn,
performance-unnecessary-copy-initialization,
performance-unnecessary-value-param,
portability-simd-intrinsics,
readability-avoid-const-params-in-decls,
readability-const-return-type,
readability-container-size-empty,
readability-convert-member-functions-to-static,
readability-delete-null-pointer,
readability-deleted-default,
readability-inconsistent-declaration-parameter-name,
readability-make-member-function-const,
readability-misleading-indentation,
readability-misplaced-array-index,
readability-non-const-parameter,
readability-redundant-control-flow,
readability-redundant-declaration,
readability-redundant-function-ptr-dereference,
readability-braces-around-statements,
readability-redundant-smartptr-get,
readability-redundant-string-cstr,
readability-redundant-string-init,
readability-simplify-subscript-expr,
readability-static-accessed-through-instance,
readability-static-definition-in-anonymous-namespace,
readability-string-compare,
readability-uniqueptr-delete-release,
readability-use-anyofallof'

View File

@ -18,6 +18,7 @@ set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
add_compile_options(/wd4131 /wd4127)

View File

@ -20,6 +20,8 @@ This project has been ported to Qt6, which is not yet available in Ubuntu apt re
To run this project, you will *need* to install [Qt6 Open Source Binaries](https://www.qt.io/download-qt-installer) for your system.
Be sure to take note of the Qt6 installation directory, as we will need it to correctly set our `CMAKE_PREFIX_PATH` in the next steps.
#### Linux
Once Qt6 is installed, to build and run `qtk` on Ubuntu -
```bash
sudo apt update -y && sudo apt install libassimp-dev cmake build-essential git
@ -42,12 +44,67 @@ cmake -DQTK_UPDATE_SUBMODULES=OFF -DCMAKE_PREFIX_PATH=$HOME/Qt/6.3.1/gcc_64 -S q
./qtk/build/qtk-main
```
#### Windows / MacOS
If you are building on **Windows / Mac** and bringing your own installation of Assimp, consider setting the `-DASSIMP_NEW_INTERFACE` build flag.
```bash
cmake -DASSIMP_NEW_INTERFACE=ON -DQTK_UPDATE_SUBMODULES=OFF -DCMAKE_PREFIX_PATH=$HOME/Qt/6.3.1/gcc_64;/path/to/assimp/ -S qtk/ -B qtk/build/ && cmake --build qtk/build/ -j $(nproc --ignore=2) --target qtk-main
```
#### Development
This project uses version `15.0.5` of `clang-format` and `clang-tidy`.
Before merging any branch we should run `clang-tidy` followed by `clang-format`.
```bash
git clone git@github.com:llvm/llvm-project.git -b llvmorg-15.0.5
cd llvm-project
cmake -B build -DLLVM_ENABLE_PROJECTS=clang -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi" -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" llvm
cmake --build build -j $(nproc --ignore=2)
sudo cmake --build build -j $(nproc --ignore=2) --target install
```
After this is done, we can check that for the correct version of `15.0.5`.
If this version is any earlier than `15.0.0`, running `clang-format` will fail because this project uses configuration options made available since `15.0.0`.
```bash
clang-format --version
clang-format version 15.0.5 (git@github.com:llvm/llvm-project.git 154e88af7ec97d9b9f389e55d45bf07108a9a097)
```
CLion has integration for IDE code reformatting actions with `clang-format`. If you're using CLion, the `.clang-format` configuration will be picked up by CLion automatically.
`clang-tidy` can be run with the following commands.
```bash
# Move to the root of the repo
cd qtk
# Build
cmake -B build && cmake --build build
cd build
# Run clang-tidy from within build directory
clang-tidy --fix --config-file=../.clang-tidy ../src/*.cpp ../src/*.h ../app/*.cpp ../app/*.h
```
And finally `clang-format` can be run with git integration (or CLion if you prefer).
Don't forget to commit the reformatted files.
```bash
# If we want to format the last N commits
# git clang-format HEAD~N
# 3 commits
git clang-format HEAD~3
changed files:
app/examplescene.h
app/mainwindow.h
src/abstractscene.cpp
src/skybox.h
src/texture.cpp
src/texture.h
src/transform3D.h
```
### Controls
You can fly around the scene if you hold the right mouse button and use WASD.

View File

@ -8,10 +8,10 @@
#include <abstractscene.h>
#include <camera3d.h>
#include <examplescene.h>
#include <meshrenderer.h>
#include <model.h>
#include <resourcemanager.h>
#include <examplescene.h>
#include <texture.h>
using namespace Qtk;
@ -20,31 +20,31 @@ using namespace Qtk;
* Constructors, Destructors
******************************************************************************/
ExampleScene::ExampleScene()
{
ExampleScene::ExampleScene() {
Camera().transform().setTranslation(0.0f, 0.0f, 20.0f);
Camera().transform().setRotation(-5.0f, 0.0f, 1.0f, 0.0f);
}
ExampleScene::~ExampleScene()
{
ExampleScene::~ExampleScene() {
delete mTestPhong;
delete mTestSpecular;
delete mTestDiffuse;
delete mTestAmbient;
for (auto & mesh : mMeshes) delete mesh;
for (auto & model : mModels) delete model;
for(auto & mesh : mMeshes) {
delete mesh;
}
for(auto & model : mModels) {
delete model;
}
delete mSkybox;
}
/*******************************************************************************
* Public Member Functions
******************************************************************************/
void ExampleScene::init()
{
Qtk::Skybox * sb = new Qtk::Skybox("Skybox");
void ExampleScene::init() {
auto * sb = new Qtk::Skybox("Skybox");
setSkybox(sb);
// Initialize Phong example cube
@ -63,16 +63,15 @@ void ExampleScene::init()
mTestPhong->mNBO.create();
mTestPhong->mNBO.setUsagePattern(QOpenGLBuffer::StaticDraw);
mTestPhong->mNBO.bind();
mTestPhong->mNBO.allocate(mTestPhong->getNormals().data(),
mTestPhong->getNormals().size()
* sizeof(mTestPhong->getNormals()[0]));
mTestPhong->mNBO.allocate(
mTestPhong->getNormals().data(),
mTestPhong->getNormals().size() * sizeof(mTestPhong->getNormals()[0]));
mTestPhong->mProgram.enableAttributeArray(1);
mTestPhong->mProgram.setAttributeBuffer(1, GL_FLOAT, 0, 3, sizeof(QVector3D));
mTestPhong->mNBO.release();
mTestPhong->mVAO.release();
mTestPhong->mProgram.release();
// Initialize Ambient example cube
mTestAmbient = new Qtk::MeshRenderer("ambient", Cube());
mTestAmbient->mTransform.setTranslation(7.0f, 0.0f, -2.0f);
@ -87,12 +86,13 @@ void ExampleScene::init()
mTestAmbient->mNBO.create();
mTestAmbient->mNBO.setUsagePattern(QOpenGLBuffer::StaticDraw);
mTestAmbient->mNBO.bind();
mTestAmbient->mNBO.allocate(mTestAmbient->getNormals().data(),
mTestAmbient->mNBO.allocate(
mTestAmbient->getNormals().data(),
mTestAmbient->getNormals().size()
* sizeof(mTestAmbient->getNormals()[0]));
mTestAmbient->mProgram.enableAttributeArray(1);
mTestAmbient->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
3, sizeof(QVector3D));
mTestAmbient->mProgram.setAttributeBuffer(
1, GL_FLOAT, 0, 3, sizeof(QVector3D));
mTestAmbient->mNBO.release();
mTestAmbient->mVAO.release();
mTestAmbient->mProgram.release();
@ -111,12 +111,13 @@ void ExampleScene::init()
mTestDiffuse->mNBO.create();
mTestDiffuse->mNBO.setUsagePattern(QOpenGLBuffer::StaticDraw);
mTestDiffuse->mNBO.bind();
mTestDiffuse->mNBO.allocate(mTestDiffuse->getNormals().data(),
mTestDiffuse->mNBO.allocate(
mTestDiffuse->getNormals().data(),
mTestDiffuse->getNormals().size()
* sizeof(mTestDiffuse->getNormals()[0]));
mTestDiffuse->mProgram.enableAttributeArray(1);
mTestDiffuse->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
3, sizeof(QVector3D));
mTestDiffuse->mProgram.setAttributeBuffer(
1, GL_FLOAT, 0, 3, sizeof(QVector3D));
mTestDiffuse->mNBO.release();
mTestDiffuse->mVAO.release();
mTestDiffuse->mProgram.release();
@ -137,12 +138,13 @@ void ExampleScene::init()
mTestSpecular->mNBO.create();
mTestSpecular->mNBO.setUsagePattern(QOpenGLBuffer::StaticDraw);
mTestSpecular->mNBO.bind();
mTestSpecular->mNBO.allocate(mTestSpecular->getNormals().data(),
mTestSpecular->mNBO.allocate(
mTestSpecular->getNormals().data(),
mTestSpecular->getNormals().size()
* sizeof(mTestSpecular->getNormals()[0]));
mTestSpecular->mProgram.enableAttributeArray(1);
mTestSpecular->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
3, sizeof(QVector3D));
mTestSpecular->mProgram.setAttributeBuffer(
1, GL_FLOAT, 0, 3, sizeof(QVector3D));
mTestSpecular->mNBO.release();
mTestSpecular->mVAO.release();
mTestSpecular->mProgram.release();
@ -150,7 +152,8 @@ void ExampleScene::init()
//
// Model loading
mModels.push_back(new Qtk::Model("backpack", ":/models/backpack/backpack.obj"));
mModels.push_back(
new Qtk::Model("backpack", ":/models/backpack/backpack.obj"));
// Sometimes model textures need flipped in certain directions
mModels.back()->flipTexture("diffuse.jpg", false, true);
mModels.back()->mTransform.setTranslation(0.0f, 0.0f, -10.0f);
@ -165,7 +168,8 @@ void ExampleScene::init()
mModels.back()->mTransform.setTranslation(-3.0f, -1.0f, -10.0f);
mModels.back()->mTransform.scale(0.15f);
mModels.push_back(new Qtk::Model("alien", ":/models/alien-hominid/alien.obj"));
mModels.push_back(
new Qtk::Model("alien", ":/models/alien-hominid/alien.obj"));
mModels.back()->mTransform.setTranslation(2.0f, -1.0f, -5.0f);
mModels.back()->mTransform.scale(0.15f);
@ -174,27 +178,26 @@ void ExampleScene::init()
mModels.back()->mTransform.rotate(-90.0f, 1.0f, 0.0f, 0.0f);
mModels.back()->mTransform.rotate(90.0f, 0.0f, 1.0f, 0.0f);
mModels.push_back(new Qtk::Model("masterChief", ":/models/spartan/spartan.obj"));
mModels.push_back(
new Qtk::Model("masterChief", ":/models/spartan/spartan.obj"));
mModels.back()->mTransform.setTranslation(-1.5f, 0.5f, -2.0f);
//
// Building example mesh objects
// Render an alien with specular
// Test alien Model with phong lighting and specular mapping
mMeshes.push_back(
new Qtk::MeshRenderer("alienTestLight", Triangle(Qtk::QTK_DRAW_ELEMENTS)));
mMeshes.push_back(new Qtk::MeshRenderer(
"alienTestLight", Triangle(Qtk::QTK_DRAW_ELEMENTS)));
mMeshes.back()->mTransform.setTranslation(4.0f, 1.5f, 10.0f);
mMeshes.back()->mTransform.scale(0.25f);
// This function changes values we have allocated in a buffer, so init() after
mMeshes.back()->setColor(GREEN);
mMeshes.back()->init();
mModels.push_back(
new Qtk::Model("alienTest", ":/models/alien-hominid/alien.obj",
":/model-specular.vert", ":/model-specular.frag")
);
mModels.push_back(new Qtk::Model(
"alienTest", ":/models/alien-hominid/alien.obj", ":/model-specular.vert",
":/model-specular.frag"));
mModels.back()->mTransform.setTranslation(3.0f, -1.0f, 10.0f);
mModels.back()->mTransform.scale(0.15f);
mModels.back()->setUniform("uMaterial.ambient", QVector3D(1.0f, 1.0f, 1.0f));
@ -209,21 +212,18 @@ void ExampleScene::init()
mModels.back()->setUniform("uLight.diffuse", QVector3D(1.0f, 1.0f, 1.0f));
mModels.back()->setUniform("uLight.specular", QVector3D(1.0f, 1.0f, 1.0f));
// Test spartan Model with phong lighting, specular and normal mapping
mMeshes.push_back(
new Qtk::MeshRenderer("spartanTestLight", Triangle(QTK_DRAW_ELEMENTS))
);
new Qtk::MeshRenderer("spartanTestLight", Triangle(QTK_DRAW_ELEMENTS)));
mMeshes.back()->mTransform.setTranslation(1.0f, 1.5f, 10.0f);
mMeshes.back()->mTransform.scale(0.25f);
// This function changes values we have allocated in a buffer, so init() after
mMeshes.back()->setColor(GREEN);
mMeshes.back()->init();
mModels.push_back(
new Qtk::Model("spartanTest", ":/models/spartan/spartan.obj",
":/model-normals.vert", ":/model-normals.frag")
);
mModels.push_back(new Qtk::Model(
"spartanTest", ":/models/spartan/spartan.obj", ":/model-normals.vert",
":/model-normals.frag"));
mModels.back()->mTransform.setTranslation(0.0f, -1.0f, 10.0f);
mModels.back()->mTransform.scale(2.0f);
mModels.back()->setUniform("uMaterial.ambient", QVector3D(1.0f, 1.0f, 1.0f));
@ -237,7 +237,6 @@ void ExampleScene::init()
mModels.back()->setUniform("uLight.diffuse", QVector3D(1.0f, 1.0f, 1.0f));
mModels.back()->setUniform("uLight.specular", QVector3D(1.0f, 1.0f, 1.0f));
// Test basic cube with phong.vert and phong.frag shaders
mMeshes.push_back(
new Qtk::MeshRenderer("testLight", Triangle(QTK_DRAW_ELEMENTS)));
@ -248,8 +247,7 @@ void ExampleScene::init()
mMeshes.back()->setColor(GREEN);
mMeshes.back()->init();
mMeshes.push_back(
new Qtk::MeshRenderer("testPhong", Cube(QTK_DRAW_ARRAYS)));
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));
@ -260,12 +258,13 @@ void ExampleScene::init()
mMeshes.back()->mNBO.create();
mMeshes.back()->mNBO.bind();
mMeshes.back()->mNBO.allocate(mMeshes.back()->getNormals().data(),
mMeshes.back()->mNBO.allocate(
mMeshes.back()->getNormals().data(),
mMeshes.back()->getNormals().size()
* sizeof(mMeshes.back()->getNormals()[0]));
mMeshes.back()->mProgram.enableAttributeArray(1);
mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
3, sizeof(QVector3D));
mMeshes.back()->mProgram.setAttributeBuffer(
1, GL_FLOAT, 0, 3, sizeof(QVector3D));
mMeshes.back()->mNBO.release();
mMeshes.back()->mVAO.release();
@ -329,20 +328,21 @@ void ExampleScene::init()
mMeshes.back()->mNBO.bind();
mMeshes.back()->mProgram.bind();
mMeshes.back()->mNBO.allocate(mMeshes.back()->getNormals().data(),
mMeshes.back()->mNBO.allocate(
mMeshes.back()->getNormals().data(),
mMeshes.back()->getNormals().size()
* sizeof(mMeshes.back()->getNormals()[0]));
mMeshes.back()->mProgram.enableAttributeArray(1);
mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
3, sizeof(QVector3D));
mMeshes.back()->mProgram.setAttributeBuffer(
1, GL_FLOAT, 0, 3, sizeof(QVector3D));
mMeshes.back()->mProgram.release();
mMeshes.back()->mNBO.release();
mMeshes.back()->mVAO.release();
// RGB Normals cube to show normals are correct with QTK_DRAW_ELEMENTS_NORMALS
mMeshes.push_back(
new Qtk::MeshRenderer("rgbNormalsCubeElementsTest", Cube(QTK_DRAW_ELEMENTS_NORMALS)));
mMeshes.push_back(new Qtk::MeshRenderer(
"rgbNormalsCubeElementsTest", Cube(QTK_DRAW_ELEMENTS_NORMALS)));
mMeshes.back()->mTransform.setTranslation(5.0f, 0.0f, 2.0f);
mMeshes.back()->setShaders(":/rgb-normals.vert", ":/rgb-normals.frag");
mMeshes.back()->init();
@ -351,19 +351,21 @@ void ExampleScene::init()
mMeshes.back()->mNBO.bind();
mMeshes.back()->mProgram.bind();
mMeshes.back()->mNBO.allocate(mMeshes.back()->getNormals().data(),
mMeshes.back()->mNBO.allocate(
mMeshes.back()->getNormals().data(),
mMeshes.back()->getNormals().size()
* sizeof(mMeshes.back()->getNormals()[0]));
mMeshes.back()->mProgram.enableAttributeArray(1);
mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
3, sizeof(QVector3D));
mMeshes.back()->mProgram.setAttributeBuffer(
1, GL_FLOAT, 0, 3, sizeof(QVector3D));
mMeshes.back()->mProgram.release();
mMeshes.back()->mNBO.release();
mMeshes.back()->mVAO.release();
// Texturing a cube using texture coordinates and glDrawArrays
// + Texturing with UVs using glDrawElements requires QTK_DRAW_ELEMENTS_NORMALS
// + Texturing with UVs using glDrawElements requires
// QTK_DRAW_ELEMENTS_NORMALS
// + UVs required duplicating element position data from QTK_DRAW_ELEMENTS
// + This is because the same position must use different UV coordinates
mMeshes.push_back(
@ -373,26 +375,28 @@ void ExampleScene::init()
mMeshes.back()->init();
mMeshes.back()->mProgram.bind();
mMeshes.back()->setTexture(OpenGLTextureFactory::initTexture2D(":/crate.png"));
mMeshes.back()->setTexture(
OpenGLTextureFactory::initTexture2D(":/crate.png"));
mMeshes.back()->setUniform("uTexture", 0);
mMeshes.back()->mVAO.bind();
mMeshes.back()->mNBO.destroy();
mMeshes.back()->mNBO.create();
mMeshes.back()->mNBO.bind();
mMeshes.back()->mNBO.allocate(mMeshes.back()->mShape.getTexCoords().data(),
mMeshes.back()->mNBO.allocate(
mMeshes.back()->mShape.getTexCoords().data(),
mMeshes.back()->mShape.getTexCoords().size()
* sizeof(mMeshes.back()->mShape.getTexCoords()[0]));
mMeshes.back()->mProgram.enableAttributeArray(1);
mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
2, sizeof(QVector2D));
mMeshes.back()->mProgram.setAttributeBuffer(
1, GL_FLOAT, 0, 2, sizeof(QVector2D));
mMeshes.back()->mNBO.release();
mMeshes.back()->mVAO.release();
mMeshes.back()->mProgram.release();
// Test drawing a cube with texture coordinates using glDrawElements
mMeshes.push_back(
new Qtk::MeshRenderer("uvCubeElementsTest", Cube(QTK_DRAW_ELEMENTS_NORMALS)));
mMeshes.push_back(new Qtk::MeshRenderer(
"uvCubeElementsTest", Cube(QTK_DRAW_ELEMENTS_NORMALS)));
mMeshes.back()->mTransform.setTranslation(-1.7f, 0.0f, -2.0f);
mMeshes.back()->setShaders(":/texture2d.vert", ":/texture2d.frag");
mMeshes.back()->init();
@ -401,13 +405,15 @@ void ExampleScene::init()
mMeshes.back()->mNBO.bind();
mMeshes.back()->mProgram.bind();
mMeshes.back()->mNBO.allocate(mMeshes.back()->getTexCoords().data(),
mMeshes.back()->mNBO.allocate(
mMeshes.back()->getTexCoords().data(),
mMeshes.back()->getTexCoords().size()
* sizeof(mMeshes.back()->getTexCoords()[0]));
mMeshes.back()->mProgram.enableAttributeArray(1);
mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
3, sizeof(QVector3D));
mMeshes.back()->setTexture(OpenGLTextureFactory::initTexture2D(":/crate.png"));
mMeshes.back()->mProgram.setAttributeBuffer(
1, GL_FLOAT, 0, 3, sizeof(QVector3D));
mMeshes.back()->setTexture(
OpenGLTextureFactory::initTexture2D(":/crate.png"));
mMeshes.back()->mProgram.setUniformValue("uTexture", 0);
mMeshes.back()->mProgram.release();
@ -421,7 +427,8 @@ void ExampleScene::init()
new Qtk::MeshRenderer("testCubeMap", Cube(QTK_DRAW_ELEMENTS)));
mMeshes.back()->mTransform.setTranslation(-3.0f, 1.0f, -2.0f);
mMeshes.back()->mTransform.setRotation(45.0f, 0.0f, 1.0f, 0.0f);
mMeshes.back()->setShaders(":/texture-cubemap.vert", ":/texture-cubemap.frag");
mMeshes.back()->setShaders(
":/texture-cubemap.vert", ":/texture-cubemap.frag");
mMeshes.back()->init();
mMeshes.back()->mProgram.bind();
@ -432,12 +439,13 @@ void ExampleScene::init()
mMeshes.back()->mNBO.destroy();
mMeshes.back()->mNBO.create();
mMeshes.back()->mNBO.bind();
mMeshes.back()->mNBO.allocate(mMeshes.back()->mShape.getTexCoords().data(),
mMeshes.back()->mNBO.allocate(
mMeshes.back()->mShape.getTexCoords().data(),
mMeshes.back()->mShape.getTexCoords().size()
* sizeof(mMeshes.back()->mShape.getTexCoords()[0]));
mMeshes.back()->mProgram.enableAttributeArray(1);
mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
2, sizeof(QVector2D));
mMeshes.back()->mProgram.setAttributeBuffer(
1, GL_FLOAT, 0, 2, sizeof(QVector2D));
mMeshes.back()->mNBO.release();
mMeshes.back()->mVAO.release();
mMeshes.back()->mProgram.release();
@ -454,20 +462,21 @@ void ExampleScene::init()
mMeshes.back()->mNBO.bind();
mMeshes.back()->mProgram.bind();
mMeshes.back()->mNBO.allocate(mMeshes.back()->getNormals().data(),
mMeshes.back()->mNBO.allocate(
mMeshes.back()->getNormals().data(),
mMeshes.back()->getNormals().size()
* sizeof(mMeshes.back()->getNormals()[0]));
mMeshes.back()->mProgram.enableAttributeArray(1);
mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
3, sizeof(QVector3D));
mMeshes.back()->mProgram.setAttributeBuffer(
1, GL_FLOAT, 0, 3, sizeof(QVector3D));
mMeshes.back()->mProgram.release();
mMeshes.back()->mNBO.release();
mMeshes.back()->mVAO.release();
// RGB Normals triangle to show normals are correct with QTK_DRAW_ARRAYS
mMeshes.push_back(
new Qtk::MeshRenderer("rgbTriangleArraysTest", Triangle(QTK_DRAW_ARRAYS)));
mMeshes.push_back(new Qtk::MeshRenderer(
"rgbTriangleArraysTest", Triangle(QTK_DRAW_ARRAYS)));
mMeshes.back()->mTransform.setTranslation(7.0f, 0.0f, 2.0f);
mMeshes.back()->setShaders(":/rgb-normals.vert", ":/rgb-normals.frag");
mMeshes.back()->init();
@ -476,20 +485,20 @@ void ExampleScene::init()
mMeshes.back()->mVAO.bind();
mMeshes.back()->mNBO.create();
mMeshes.back()->mNBO.bind();
mMeshes.back()->mNBO.allocate(mMeshes.back()->getNormals().data(),
mMeshes.back()->mNBO.allocate(
mMeshes.back()->getNormals().data(),
mMeshes.back()->getNormals().size()
* sizeof(mMeshes.back()->getNormals()[0]));
mMeshes.back()->mProgram.enableAttributeArray(1);
mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
3, sizeof(QVector3D));
mMeshes.back()->mProgram.setAttributeBuffer(
1, GL_FLOAT, 0, 3, sizeof(QVector3D));
mMeshes.back()->mNBO.release();
mMeshes.back()->mVAO.release();
mMeshes.back()->mProgram.release();
// RGB Normals triangle to show normals are correct with QTK_DRAW_ELEMENTS
mMeshes.push_back(
new Qtk::MeshRenderer("rgbTriangleElementsTest",
Triangle(QTK_DRAW_ELEMENTS_NORMALS)));
mMeshes.push_back(new Qtk::MeshRenderer(
"rgbTriangleElementsTest", Triangle(QTK_DRAW_ELEMENTS_NORMALS)));
mMeshes.back()->mTransform.setTranslation(7.0f, 0.0f, 4.0f);
mMeshes.back()->setShaders(":/rgb-normals.vert", ":/rgb-normals.frag");
mMeshes.back()->init();
@ -498,12 +507,13 @@ void ExampleScene::init()
mMeshes.back()->mVAO.bind();
mMeshes.back()->mNBO.create();
mMeshes.back()->mNBO.bind();
mMeshes.back()->mNBO.allocate(mMeshes.back()->getNormals().data(),
mMeshes.back()->mNBO.allocate(
mMeshes.back()->getNormals().data(),
mMeshes.back()->getNormals().size()
* sizeof(mMeshes.back()->getNormals()[0]));
mMeshes.back()->mProgram.enableAttributeArray(1);
mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
3, sizeof(QVector3D));
mMeshes.back()->mProgram.setAttributeBuffer(
1, GL_FLOAT, 0, 3, sizeof(QVector3D));
mMeshes.back()->mNBO.release();
mMeshes.back()->mVAO.release();
mMeshes.back()->mProgram.release();
@ -523,20 +533,20 @@ void ExampleScene::init()
mMeshes.back()->mNBO.destroy();
mMeshes.back()->mNBO.create();
mMeshes.back()->mNBO.bind();
mMeshes.back()->mNBO.allocate(mMeshes.back()->mShape.getTexCoords().data(),
mMeshes.back()->mNBO.allocate(
mMeshes.back()->mShape.getTexCoords().data(),
mMeshes.back()->mShape.getTexCoords().size()
* sizeof(mMeshes.back()->mShape.getTexCoords()[0]));
mMeshes.back()->mProgram.enableAttributeArray(1);
mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
2, sizeof(QVector2D));
mMeshes.back()->mProgram.setAttributeBuffer(
1, GL_FLOAT, 0, 2, sizeof(QVector2D));
mMeshes.back()->mNBO.release();
mMeshes.back()->mVAO.release();
mMeshes.back()->mProgram.release();
// Test drawing triangle with glDrawElements with texture coordinates
mMeshes.push_back(
new Qtk::MeshRenderer("testTriangleElementsUV",
Triangle(QTK_DRAW_ELEMENTS_NORMALS)));
mMeshes.push_back(new Qtk::MeshRenderer(
"testTriangleElementsUV", Triangle(QTK_DRAW_ELEMENTS_NORMALS)));
mMeshes.back()->mTransform.setTranslation(-2.5f, 0.0f, -1.0f);
mMeshes.back()->setShaders(":/texture2d.vert", ":/texture2d.frag");
mMeshes.back()->init();
@ -550,12 +560,13 @@ void ExampleScene::init()
mMeshes.back()->mNBO.destroy();
mMeshes.back()->mNBO.create();
mMeshes.back()->mNBO.bind();
mMeshes.back()->mNBO.allocate(mMeshes.back()->mShape.getTexCoords().data(),
mMeshes.back()->mNBO.allocate(
mMeshes.back()->mShape.getTexCoords().data(),
mMeshes.back()->mShape.getTexCoords().size()
* sizeof(mMeshes.back()->mShape.getTexCoords()[0]));
mMeshes.back()->mProgram.enableAttributeArray(1);
mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
2, sizeof(QVector2D));
mMeshes.back()->mProgram.setAttributeBuffer(
1, GL_FLOAT, 0, 2, sizeof(QVector2D));
mMeshes.back()->mNBO.release();
mMeshes.back()->mVAO.release();
mMeshes.back()->mProgram.release();
@ -564,11 +575,10 @@ void ExampleScene::init()
// Lighting cube examples
// Example of a cube with no lighting applied
mMeshes.push_back(
new Qtk::MeshRenderer("noLight", Cube(QTK_DRAW_ELEMENTS)));
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()->setShaders(
":/solid-perspective.vert", ":/solid-perspective.frag");
mMeshes.back()->init();
mMeshes.back()->mProgram.bind();
mMeshes.back()->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f));
@ -591,39 +601,44 @@ void ExampleScene::init()
mMeshes.back()->mTransform.scale(0.25f);
}
void ExampleScene::draw()
{
void ExampleScene::draw() {
Scene::draw();
for (const auto & model : mModels) model->draw();
for(const auto & model : mModels) {
model->draw();
}
for (const auto & mesh : mMeshes) mesh->draw();
for(const auto & mesh : mMeshes) {
mesh->draw();
}
mTestPhong->mProgram.bind();
mTestPhong->setUniform("uModelInverseTransposed",
mTestPhong->setUniform(
"uModelInverseTransposed",
mTestPhong->mTransform.toMatrix().normalMatrix());
mTestPhong->setUniform(
"uLightPosition",
MeshRenderer::getInstance("phongLight")->mTransform.getTranslation());
mTestPhong->setUniform("uCameraPosition",
ExampleScene::Camera().transform().getTranslation());
mTestPhong->setUniform(
"uCameraPosition", ExampleScene::Camera().transform().getTranslation());
mTestPhong->mProgram.release();
mTestPhong->draw();
mTestAmbient->mProgram.bind();
mTestAmbient->setUniform("uCameraPosition",
ExampleScene::Camera().transform().getTranslation());
mTestAmbient->setUniform(
"uCameraPosition", ExampleScene::Camera().transform().getTranslation());
mTestAmbient->mProgram.release();
mTestAmbient->draw();
mTestDiffuse->mProgram.bind();
mTestDiffuse->setUniform("uModelInverseTransposed",
mTestDiffuse->setUniform(
"uModelInverseTransposed",
mTestDiffuse->mTransform.toMatrix().normalMatrix());
mTestDiffuse->setUniform(
"uLightPosition",
MeshRenderer::getInstance("diffuseLight")->mTransform.getTranslation());
mTestDiffuse->setUniform("uCameraPosition",
ExampleScene::Camera().transform().getTranslation());
mTestDiffuse->setUniform(
"uCameraPosition", ExampleScene::Camera().transform().getTranslation());
mTestDiffuse->mProgram.release();
mTestDiffuse->draw();
@ -634,67 +649,66 @@ void ExampleScene::draw()
mTestSpecular->setUniform(
"uLightPosition",
MeshRenderer::getInstance("specularLight")->mTransform.getTranslation());
mTestSpecular->setUniform("uCameraPosition",
ExampleScene::Camera().transform().getTranslation());
mTestSpecular->setUniform(
"uCameraPosition", ExampleScene::Camera().transform().getTranslation());
mTestSpecular->mProgram.release();
mTestSpecular->draw();
}
void ExampleScene::update()
{
auto position = MeshRenderer::getInstance(
"alienTestLight")->mTransform.getTranslation();
Model::getInstance("alienTest")->setUniform(
"uLight.position", position);
Model::getInstance("alienTest")->setUniform(
"uCameraPosition", ExampleScene::Camera().transform().getTranslation());
void ExampleScene::update() {
auto position =
MeshRenderer::getInstance("alienTestLight")->mTransform.getTranslation();
Model::getInstance("alienTest")->setUniform("uLight.position", position);
Model::getInstance("alienTest")
->setUniform(
"uCameraPosition",
ExampleScene::Camera().transform().getTranslation());
auto posMatrix = Model::getInstance("alienTest")->mTransform.toMatrix();
Model::getInstance("alienTest")->setUniform(
"uMVP.normalMatrix", posMatrix.normalMatrix());
Model::getInstance("alienTest")->setUniform(
"uMVP.model", posMatrix);
Model::getInstance("alienTest")->setUniform(
"uMVP.view", ExampleScene::Camera().toMatrix());
Model::getInstance("alienTest")->setUniform(
"uMVP.projection", ExampleScene::Projection());
Model::getInstance("alienTest")
->setUniform("uMVP.normalMatrix", posMatrix.normalMatrix());
Model::getInstance("alienTest")->setUniform("uMVP.model", posMatrix);
Model::getInstance("alienTest")
->setUniform("uMVP.view", ExampleScene::Camera().toMatrix());
Model::getInstance("alienTest")
->setUniform("uMVP.projection", ExampleScene::Projection());
Model::getInstance("alienTest")->mTransform.rotate(0.75f, 0.0f, 1.0f, 0.0f);
position = MeshRenderer::getInstance(
"spartanTestLight")->mTransform.getTranslation();
Model::getInstance("spartanTest")->setUniform(
"uLight.position", position);
Model::getInstance("spartanTest")->setUniform(
"uCameraPosition", ExampleScene::Camera().transform().getTranslation());
position = MeshRenderer::getInstance("spartanTestLight")
->mTransform.getTranslation();
Model::getInstance("spartanTest")->setUniform("uLight.position", position);
Model::getInstance("spartanTest")
->setUniform(
"uCameraPosition",
ExampleScene::Camera().transform().getTranslation());
posMatrix = Model::getInstance("spartanTest")->mTransform.toMatrix();
Model::getInstance("spartanTest")->setUniform(
"uMVP.normalMatrix", posMatrix.normalMatrix());
Model::getInstance("spartanTest")->setUniform(
"uMVP.model", posMatrix);
Model::getInstance("spartanTest")->setUniform(
"uMVP.view", ExampleScene::Camera().toMatrix());
Model::getInstance("spartanTest")->setUniform(
"uMVP.projection", ExampleScene::Projection());
Model::getInstance("spartanTest")
->setUniform("uMVP.normalMatrix", posMatrix.normalMatrix());
Model::getInstance("spartanTest")->setUniform("uMVP.model", posMatrix);
Model::getInstance("spartanTest")
->setUniform("uMVP.view", ExampleScene::Camera().toMatrix());
Model::getInstance("spartanTest")
->setUniform("uMVP.projection", ExampleScene::Projection());
Model::getInstance("spartanTest")->mTransform.rotate(0.75f, 0.0f, 1.0f, 0.0f);
MeshRenderer::getInstance("testPhong")->mTransform.rotate(
0.75f, 1.0f, 0.5f, 0.0f);
MeshRenderer::getInstance("testPhong")
->mTransform.rotate(0.75f, 1.0f, 0.5f, 0.0f);
MeshRenderer::getInstance("testPhong")->mProgram.bind();
position = MeshRenderer::getInstance("testLight")->mTransform.getTranslation();
MeshRenderer::getInstance("testPhong")->setUniform(
"uLight.position", position);
MeshRenderer::getInstance("testPhong")->setUniform(
"uCameraPosition", ExampleScene::Camera().transform().getTranslation());
position =
MeshRenderer::getInstance("testLight")->mTransform.getTranslation();
MeshRenderer::getInstance("testPhong")
->setUniform("uLight.position", position);
MeshRenderer::getInstance("testPhong")
->setUniform(
"uCameraPosition",
ExampleScene::Camera().transform().getTranslation());
posMatrix = MeshRenderer::getInstance("testPhong")->mTransform.toMatrix();
MeshRenderer::getInstance("testPhong")->setUniform(
"uMVP.normalMatrix", posMatrix.normalMatrix());
MeshRenderer::getInstance("testPhong")->setUniform(
"uMVP.model", posMatrix);
MeshRenderer::getInstance("testPhong")->setUniform(
"uMVP.view", ExampleScene::Camera().toMatrix());
MeshRenderer::getInstance("testPhong")->setUniform(
"uMVP.projection", ExampleScene::Projection());
MeshRenderer::getInstance("testPhong")
->setUniform("uMVP.normalMatrix", posMatrix.normalMatrix());
MeshRenderer::getInstance("testPhong")->setUniform("uMVP.model", posMatrix);
MeshRenderer::getInstance("testPhong")
->setUniform("uMVP.view", ExampleScene::Camera().toMatrix());
MeshRenderer::getInstance("testPhong")
->setUniform("uMVP.projection", ExampleScene::Projection());
MeshRenderer::getInstance("testPhong")->mProgram.release();
// Rotate lighting example cubes
@ -708,14 +722,14 @@ void ExampleScene::update()
// Examples of various translations and rotations
// Rotate in multiple directions simultaneously
MeshRenderer::getInstance("rgbNormalsCube")->mTransform.rotate(
0.75f, 0.2f, 0.4f, 0.6f);
MeshRenderer::getInstance("rgbNormalsCube")
->mTransform.rotate(0.75f, 0.2f, 0.4f, 0.6f);
// Pitch forward and roll sideways
MeshRenderer::getInstance("leftTriangle")->mTransform.rotate(
0.75f, 1.0f, 0.0f, 0.0f);
MeshRenderer::getInstance("rightTriangle")->mTransform.rotate(
0.75f, 0.0f, 0.0f, 1.0f);
MeshRenderer::getInstance("leftTriangle")
->mTransform.rotate(0.75f, 1.0f, 0.0f, 0.0f);
MeshRenderer::getInstance("rightTriangle")
->mTransform.rotate(0.75f, 0.0f, 0.0f, 1.0f);
// Move between two positions over time
static float translateX = 0.025f;
@ -725,19 +739,19 @@ void ExampleScene::update()
if(posX < limit || posX > limit + 4.0f) {
translateX = -translateX;
}
MeshRenderer::getInstance("topTriangle")->mTransform.translate(
translateX, 0.0f, 0.0f);
MeshRenderer::getInstance("bottomTriangle")->mTransform.translate(
-translateX, 0.0f, 0.0f);
MeshRenderer::getInstance("topTriangle")
->mTransform.translate(translateX, 0.0f, 0.0f);
MeshRenderer::getInstance("bottomTriangle")
->mTransform.translate(-translateX, 0.0f, 0.0f);
// And lets rotate the triangles in two directions at once
MeshRenderer::getInstance("topTriangle")->mTransform.rotate(
0.75f, 0.2f, 0.0f, 0.4f);
MeshRenderer::getInstance("bottomTriangle")->mTransform.rotate(
0.75f, 0.0f, 0.2f, 0.4f);
MeshRenderer::getInstance("topTriangle")
->mTransform.rotate(0.75f, 0.2f, 0.0f, 0.4f);
MeshRenderer::getInstance("bottomTriangle")
->mTransform.rotate(0.75f, 0.0f, 0.2f, 0.4f);
// And make the bottom triangle green, instead of RGB
// Rotate center cube in several directions simultaneously
// + Not subject to gimbal lock since we are using quaternions :)
MeshRenderer::getInstance("centerCube")->mTransform.rotate(
0.75f, 0.2f, 0.4f, 0.6f);
MeshRenderer::getInstance("centerCube")
->mTransform.rotate(0.75f, 0.2f, 0.4f, 0.6f);
}

View File

@ -15,22 +15,20 @@
#include <QMatrix4x4>
class ExampleScene : public Qtk::Scene {
public:
ExampleScene();
~ExampleScene();
virtual void init();
virtual void draw() override;
virtual void update();
void init() override;
void draw() override;
void update() override;
private:
Qtk::MeshRenderer * mTestPhong;
Qtk::MeshRenderer * mTestSpecular;
Qtk::MeshRenderer * mTestDiffuse;
Qtk::MeshRenderer * mTestAmbient;
Qtk::MeshRenderer * mTestPhong {};
Qtk::MeshRenderer * mTestSpecular {};
Qtk::MeshRenderer * mTestDiffuse {};
Qtk::MeshRenderer * mTestAmbient {};
};
#endif // QTK_EXAMPLE_SCENE_H

View File

@ -9,13 +9,11 @@
#include <QApplication>
#include <QLabel>
#include <qtkwidget.h>
#include <mainwindow.h>
#include <qtkwidget.h>
#include <QSurfaceFormat>
int main(int argc, char *argv[])
{
int main(int argc, char * argv[]) {
QApplication a(argc, argv);
// Set OpenGL Version information
@ -36,6 +34,5 @@ int main(int argc, char *argv[])
MainWindow w;
w.show();
return a.exec();
return QApplication::exec();
}

View File

@ -3,9 +3,7 @@
#include "ui_mainwindow.h"
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
// + We can use the `ui` member to access nested widgets by name
@ -22,7 +20,6 @@ MainWindow::MainWindow(QWidget *parent) :
setWindowIcon(QIcon("../resources/icon.png"));
}
MainWindow::~MainWindow()
{
MainWindow::~MainWindow() {
delete ui;
}

View File

@ -5,24 +5,24 @@
#include <QMainWindow>
#include "qtk-widget_export.h"
#include <examplescene.h>
#include "qtk-widget_export.h"
namespace Ui {
class MainWindow;
}
class QTK_WIDGET_EXPORT MainWindow : public QMainWindow
{
class QTK_WIDGET_EXPORT MainWindow
: public QMainWindow {
Q_OBJECT
public:
explicit MainWindow(QWidget * parent = nullptr);
~MainWindow();
~MainWindow() override;
private:
Ui::MainWindow *ui;
Ui::MainWindow * ui {};
std::unordered_map<std::string, Qtk::Scene *> mScenes;
};

View File

@ -15,15 +15,15 @@
typedef class ResourceManager {
public:
/**
* Takes a path using qrc format and constructs full system path to qtk assets
* Qrc format prefix ':/' is trimmed from the path for the caller
* Takes a path using qrc format and constructs full system path to qtk
* assets Qrc format prefix ':/' is trimmed from the path for the caller
* Assets used with RM may (or may not) appear in qtk/resources.qrc
*
* @param path Path relative to qtk/resources/; ie) ':/models/backpack/backpack.obj'
* An asset at location qtk/resources/path/to/asset.obj
* Should be given in qrc format: ':/path/to/asset.obj'
* @param path Path relative to qtk/resources/; ie)
* ':/models/backpack/backpack.obj' An asset at location
* qtk/resources/path/to/asset.obj Should be given in qrc format:
* ':/path/to/asset.obj'
* @return Absoulte system path to a qtk asset
*/
static std::string getPath(const std::string & path) {

View File

@ -16,33 +16,39 @@ using namespace Qtk;
Camera3D Scene::mCamera;
QMatrix4x4 Scene::mProjection;
/*******************************************************************************
* Constructors, Destructors
******************************************************************************/
Scene::Scene()
{
Scene::Scene() {
mCamera.transform().setTranslation(0.0f, 0.0f, 20.0f);
mCamera.transform().setRotation(-5.0f, 0.0f, 1.0f, 0.0f);
}
Scene::~Scene()
{
for (auto & mesh : mMeshes) delete mesh;
for (auto & model : mModels) delete model;
if (mSkybox != Q_NULLPTR) delete mSkybox;
Scene::~Scene() {
for(auto & mesh : mMeshes) {
delete mesh;
}
for(auto & model : mModels) {
delete model;
}
void Scene::privDraw()
{
delete mSkybox;
}
void Scene::privDraw() {
if(!mInit) {
initializeOpenGLFunctions();
init();
mInit = true;
}
if (mSkybox != Q_NULLPTR) mSkybox->draw();
for (auto & model : mModels) model->draw();
for (const auto & mesh : mMeshes) mesh->draw();
if(mSkybox != Q_NULLPTR) {
mSkybox->draw();
}
for(auto & model : mModels) {
model->draw();
}
for(const auto & mesh : mMeshes) {
mesh->draw();
}
}

View File

@ -16,7 +16,6 @@
#include <QMatrix4x4>
namespace Qtk {
class Scene : protected QOpenGLFunctions {
friend class MainWidget;
@ -26,17 +25,19 @@ namespace Qtk {
~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;
}
inline void setSkybox(Skybox * skybox) { mSkybox = skybox; }
private:
static Camera3D mCamera;
@ -46,10 +47,10 @@ namespace Qtk {
void privDraw();
protected:
Skybox * mSkybox;
Skybox * mSkybox {};
std::vector<MeshRenderer *> mMeshes;
std::vector<Model *> mModels;
};
}
} // namespace Qtk
#endif // QTK_SCENE_H

View File

@ -14,14 +14,12 @@ const QVector3D Camera3D::LocalForward(0.0f, 0.0f, -1.0f);
const QVector3D Camera3D::LocalUp(0.0f, 1.0f, 0.0f);
const QVector3D Camera3D::LocalRight(1.0f, 0.0f, 0.0f);
/*******************************************************************************
* Accessors
******************************************************************************/
// Produces worldToView matrix
const QMatrix4x4 & Camera3D::toMatrix()
{
const QMatrix4x4 & Camera3D::toMatrix() {
mWorld.setToIdentity();
// Qt6 renamed QMatrix4x4::conjugate() to conjugated()
mWorld.rotate(mTransform.getRotation().conjugated());
@ -29,32 +27,27 @@ const QMatrix4x4 & Camera3D::toMatrix()
return mWorld;
}
/*******************************************************************************
* Qt Streams
******************************************************************************/
QDataStream & operator<<(QDataStream & out, Camera3D & transform)
{
QDataStream & operator<<(QDataStream & out, Camera3D & transform) {
out << transform.transform();
return out;
}
QDataStream & operator>>(QDataStream & in, Camera3D & transform)
{
QDataStream & operator>>(QDataStream & in, Camera3D & transform) {
in >> transform.transform();
return in;
}
QDebug operator<<(QDebug dbg, const Camera3D & transform)
{
QDebug operator<<(QDebug dbg, const Camera3D & transform) {
dbg << "Camera3D\n{\n";
dbg << "Position: <" << transform.translation().x() << ", "
<< transform.translation().y() << ", "
<< transform.translation().z() << ">\n";
<< transform.translation().y() << ", " << transform.translation().z()
<< ">\n";
dbg << "Rotation: <" << transform.rotation().x() << ", "
<< transform.rotation().y() << ", "
<< transform.rotation().z() << " | "
<< transform.rotation().y() << ", " << transform.rotation().z() << " | "
<< transform.rotation().scalar() << ">\n}";
return dbg;
}

View File

@ -11,8 +11,8 @@
#include <QDebug>
#include <transform3D.h>
#include <qtkapi.h>
#include <transform3D.h>
namespace Qtk {
class QTKAPI Camera3D {
@ -24,19 +24,29 @@ namespace Qtk {
// Accessors
inline Transform3D & transform() { return mTransform; }
inline const QVector3D & translation() const
{ return mTransform.getTranslation();}
inline const QQuaternion & rotation() const
{ return mTransform.getRotation();}
[[nodiscard]] inline const QVector3D & translation() const {
return mTransform.getTranslation();
}
[[nodiscard]] inline const QQuaternion & rotation() const {
return mTransform.getRotation();
}
const QMatrix4x4 & toMatrix();
// Queries
inline QVector3D forward() const
{ return mTransform.getRotation().rotatedVector(LocalForward);}
inline QVector3D right() const
{ return mTransform.getRotation().rotatedVector(LocalRight);}
inline QVector3D up() const
{ return mTransform.getRotation().rotatedVector(LocalUp);}
[[nodiscard]] inline QVector3D forward() const {
return mTransform.getRotation().rotatedVector(LocalForward);
}
[[nodiscard]] inline QVector3D right() const {
return mTransform.getRotation().rotatedVector(LocalRight);
}
[[nodiscard]] inline QVector3D up() const {
return mTransform.getRotation().rotatedVector(LocalUp);
}
private:
Transform3D mTransform;
@ -57,7 +67,7 @@ namespace Qtk {
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const Camera3D & transform);
#endif
}
} // namespace Qtk
Q_DECLARE_TYPEINFO(Qtk::Camera3D, Q_MOVABLE_TYPE);

View File

@ -18,19 +18,19 @@ using namespace Qtk;
/*******************************************************************************
* Static Helper Structs
******************************************************************************/
template <typename T>
struct InputInstance : std::pair<T, Input::InputState>
{
template <typename T> struct InputInstance : std::pair<T, Input::InputState> {
typedef std::pair<T, Input::InputState> base_class;
inline InputInstance(T value)
: base_class(value, Input::InputInvalid) {}
// Disable clang-tidy from marking this ctor explicit
// NOLINTNEXTLINE
inline InputInstance(T value) : base_class(value, Input::InputInvalid) {}
inline InputInstance(T value, Input::InputState state)
: base_class(value, state) {}
inline InputInstance(T value, Input::InputState state) :
base_class(value, state) {}
inline bool operator==(const InputInstance & rhs) const
{ return this->first == rhs.first;}
inline bool operator==(const InputInstance & rhs) const {
return this->first == rhs.first;
}
};
// Key, button instance typedefs
@ -49,26 +49,20 @@ static QPoint sg_mouseCurrPosition;
static QPoint sg_mousePrevPosition;
static QPoint sg_mouseDelta;
/*******************************************************************************
* Static Inline Helper Functions
******************************************************************************/
static inline KeyContainer::iterator FindKey(Qt::Key value)
{
static inline KeyContainer::iterator FindKey(Qt::Key value) {
return std::find(sg_keyInstances.begin(), sg_keyInstances.end(), value);
}
static inline ButtonContainer::iterator FindButton(Qt::MouseButton value)
{
static inline ButtonContainer::iterator FindButton(Qt::MouseButton value) {
return std::find(sg_buttonInstances.begin(), sg_buttonInstances.end(), value);
}
template <typename TPair>
static inline void UpdateStates(TPair & instance)
{
switch (instance.second)
{
template <typename TPair> static inline void UpdateStates(TPair & instance) {
switch(instance.second) {
case Input::InputRegistered:
instance.second = Input::InputTriggered;
break;
@ -84,19 +78,16 @@ static inline void UpdateStates(TPair & instance)
}
template <typename TPair>
static inline bool CheckReleased(const TPair & instance)
{
static inline bool CheckReleased(const TPair & instance) {
return instance.second == Input::InputReleased;
}
template <typename Container>
static inline void Update(Container & container)
{
template <typename Container> static inline void Update(Container & container) {
typedef typename Container::iterator Iter;
typedef typename Container::value_type TPair;
// Remove old data
Iter remove =
auto remove =
std::remove_if(container.begin(), container.end(), &CheckReleased<TPair>);
container.erase(remove, container.end());
@ -104,35 +95,29 @@ static inline void Update(Container & container)
std::for_each(container.begin(), container.end(), &UpdateStates<TPair>);
}
/*******************************************************************************
* Input Implementation
******************************************************************************/
Input::InputState Input::keyState(Qt::Key k)
{
KeyContainer::iterator it = FindKey(k);
Input::InputState Input::keyState(Qt::Key k) {
auto it = FindKey(k);
return (it != sg_keyInstances.end()) ? it->second : InputInvalid;
}
Input::InputState Input::buttonState(Qt::MouseButton k)
{
ButtonContainer::iterator it = FindButton(k);
Input::InputState Input::buttonState(Qt::MouseButton k) {
auto it = FindButton(k);
return (it != sg_buttonInstances.end()) ? it->second : InputInvalid;
}
QPoint Input::mousePosition()
{
QPoint Input::mousePosition() {
return QCursor::pos();
}
QPoint Input::mouseDelta()
{
QPoint Input::mouseDelta() {
return sg_mouseDelta;
}
void Input::update()
{
void Input::update() {
// Update Mouse Delta
sg_mousePrevPosition = sg_mouseCurrPosition;
sg_mouseCurrPosition = QCursor::pos();
@ -143,44 +128,35 @@ void Input::update()
Update(sg_keyInstances);
}
void Input::registerKeyPress(int k)
{
KeyContainer::iterator it = FindKey((Qt::Key)k);
if (it == sg_keyInstances.end())
{
void Input::registerKeyPress(int k) {
auto it = FindKey((Qt::Key)k);
if(it == sg_keyInstances.end()) {
sg_keyInstances.push_back(KeyInstance((Qt::Key)k, InputRegistered));
}
}
void Input::registerKeyRelease(int k)
{
KeyContainer::iterator it = FindKey((Qt::Key)k);
if (it != sg_keyInstances.end())
{
void Input::registerKeyRelease(int k) {
auto it = FindKey((Qt::Key)k);
if(it != sg_keyInstances.end()) {
it->second = InputUnregistered;
}
}
void Input::registerMousePress(Qt::MouseButton btn)
{
ButtonContainer::iterator it = FindButton(btn);
if (it == sg_buttonInstances.end())
{
void Input::registerMousePress(Qt::MouseButton btn) {
auto it = FindButton(btn);
if(it == sg_buttonInstances.end()) {
sg_buttonInstances.push_back(ButtonInstance(btn, InputRegistered));
}
}
void Input::registerMouseRelease(Qt::MouseButton btn)
{
ButtonContainer::iterator it = FindButton(btn);
if (it != sg_buttonInstances.end())
{
void Input::registerMouseRelease(Qt::MouseButton btn) {
auto it = FindButton(btn);
if(it != sg_buttonInstances.end()) {
it->second = InputUnregistered;
}
}
void Input::reset()
{
void Input::reset() {
sg_keyInstances.clear();
sg_buttonInstances.clear();
}

View File

@ -18,10 +18,10 @@
namespace Qtk {
class QTKAPI Input {
friend class Qtk::QtkWidget;
public:
// Possible key states
enum InputState
{
enum InputState {
InputInvalid,
InputRegistered,
InputUnregistered,
@ -31,18 +31,29 @@ namespace Qtk {
};
// State checking
inline static bool keyTriggered(Qt::Key key)
{ return keyState(key) == InputTriggered;}
inline static bool keyPressed(Qt::Key key)
{ return keyState(key) == InputPressed;}
inline static bool keyReleased(Qt::Key key)
{ return keyState(key) == InputReleased;}
inline static bool buttonTriggered(Qt::MouseButton button)
{ return buttonState(button) == InputTriggered;}
inline static bool buttonPressed(Qt::MouseButton button)
{ return buttonState(button) == InputPressed;}
inline static bool buttonReleased(Qt::MouseButton button)
{ return buttonState(button) == InputReleased;}
inline static bool keyTriggered(Qt::Key key) {
return keyState(key) == InputTriggered;
}
inline static bool keyPressed(Qt::Key key) {
return keyState(key) == InputPressed;
}
inline static bool keyReleased(Qt::Key key) {
return keyState(key) == InputReleased;
}
inline static bool buttonTriggered(Qt::MouseButton button) {
return buttonState(button) == InputTriggered;
}
inline static bool buttonPressed(Qt::MouseButton button) {
return buttonState(button) == InputPressed;
}
inline static bool buttonReleased(Qt::MouseButton button) {
return buttonState(button) == InputReleased;
}
// Implementation
static InputState keyState(Qt::Key key);
@ -60,6 +71,6 @@ namespace Qtk {
static void registerMouseRelease(Qt::MouseButton button);
static void reset();
};
}
} // namespace Qtk
#endif // QTOPENGL_INPUT_H

View File

@ -18,14 +18,18 @@
#define QTK_DEBUG
class MeshRenderer;
class Model;
class Object;
class Scene;
class Skybox;
class OpenGLTextureFactory;
class MainWidget : public QOpenGLWidget,
protected QOpenGLFunctions {
class MainWidget : public QOpenGLWidget, protected QOpenGLFunctions {
Q_OBJECT;
public:

View File

@ -10,100 +10,78 @@
using namespace Qtk;
Cube::Cube(DrawMode mode)
{
Cube::Cube(DrawMode mode) {
mDrawMode = mode;
switch(mode) {
// Cube data for use with glDrawArrays
case QTK_DRAW_ARRAYS:
mIndices = {/* No indices needed for glDrawArrays */};
mNormals =
{FACE_FRONT, FACE_BACK, FACE_TOP, FACE_BOTTOM, FACE_LEFT, FACE_RIGHT};
mNormals = {FACE_FRONT, FACE_BACK, FACE_TOP,
FACE_BOTTOM, FACE_LEFT, FACE_RIGHT};
mVertices = {
// Face 1 (Front)
VERTEX_FTR, VERTEX_FTL, VERTEX_FBL,
VERTEX_FBL, VERTEX_FBR, VERTEX_FTR,
mVertices = {// Face 1 (Front)
VERTEX_FTR, VERTEX_FTL, VERTEX_FBL, VERTEX_FBL, VERTEX_FBR,
VERTEX_FTR,
// Face 2 (Back)
VERTEX_BBR, VERTEX_BTL, VERTEX_BTR,
VERTEX_BTL, VERTEX_BBR, VERTEX_BBL,
VERTEX_BBR, VERTEX_BTL, VERTEX_BTR, VERTEX_BTL, VERTEX_BBR,
VERTEX_BBL,
// Face 3 (Top)
VERTEX_FTR, VERTEX_BTR, VERTEX_BTL,
VERTEX_BTL, VERTEX_FTL, VERTEX_FTR,
VERTEX_FTR, VERTEX_BTR, VERTEX_BTL, VERTEX_BTL, VERTEX_FTL,
VERTEX_FTR,
// Face 4 (Bottom)
VERTEX_FBR, VERTEX_FBL, VERTEX_BBL,
VERTEX_BBL, VERTEX_BBR, VERTEX_FBR,
VERTEX_FBR, VERTEX_FBL, VERTEX_BBL, VERTEX_BBL, VERTEX_BBR,
VERTEX_FBR,
// Face 5 (Left)
VERTEX_FBL, VERTEX_FTL, VERTEX_BTL,
VERTEX_FBL, VERTEX_BTL, VERTEX_BBL,
VERTEX_FBL, VERTEX_FTL, VERTEX_BTL, VERTEX_FBL, VERTEX_BTL,
VERTEX_BBL,
// Face 6 (Right)
VERTEX_FTR, VERTEX_FBR, VERTEX_BBR,
VERTEX_BBR, VERTEX_BTR, VERTEX_FTR
};
VERTEX_FTR, VERTEX_FBR, VERTEX_BBR, VERTEX_BBR, VERTEX_BTR,
VERTEX_FTR};
mColors = {
// Face 1 (Front)
RED, GREEN, BLUE,
BLUE, WHITE, RED,
mColors = {// Face 1 (Front)
RED, GREEN, BLUE, BLUE, WHITE, RED,
// Face 2 (Back)
YELLOW, CYAN, MAGENTA,
CYAN, YELLOW, BLACK,
YELLOW, CYAN, MAGENTA, CYAN, YELLOW, BLACK,
// Face 3 (Top)
RED, MAGENTA, CYAN,
CYAN, GREEN, RED,
RED, MAGENTA, CYAN, CYAN, GREEN, RED,
// Face 4 (Bottom)
WHITE, BLUE, BLACK,
BLACK, YELLOW, WHITE,
WHITE, BLUE, BLACK, BLACK, YELLOW, WHITE,
// Face 5 (Left)
BLUE, GREEN, CYAN,
BLUE, CYAN, BLACK,
BLUE, GREEN, CYAN, BLUE, CYAN, BLACK,
// Face 6 (Right)
RED, WHITE, YELLOW,
YELLOW, MAGENTA, RED
};
RED, WHITE, YELLOW, YELLOW, MAGENTA, RED};
mTexCoords = {
// Face 1 (Front)
UV_TOP, UV_ORIGIN, UV_RIGHT,
UV_RIGHT, UV_CORNER, UV_TOP,
mTexCoords = {// Face 1 (Front)
UV_TOP, UV_ORIGIN, UV_RIGHT, UV_RIGHT, UV_CORNER, UV_TOP,
// Face 2 (Back)
UV_TOP, UV_RIGHT, UV_CORNER,
UV_RIGHT, UV_TOP, UV_ORIGIN,
UV_TOP, UV_RIGHT, UV_CORNER, UV_RIGHT, UV_TOP, UV_ORIGIN,
// Face 3 (Top)
UV_CORNER, UV_TOP, UV_ORIGIN,
UV_ORIGIN, UV_RIGHT, UV_CORNER,
UV_CORNER, UV_TOP, UV_ORIGIN, UV_ORIGIN, UV_RIGHT,
UV_CORNER,
// Face 4 (Bottom)
UV_TOP, UV_ORIGIN, UV_RIGHT,
UV_RIGHT, UV_CORNER, UV_TOP,
UV_TOP, UV_ORIGIN, UV_RIGHT, UV_RIGHT, UV_CORNER, UV_TOP,
// Face 5 (Left)
UV_TOP, UV_CORNER, UV_RIGHT,
UV_TOP, UV_RIGHT, UV_ORIGIN,
UV_TOP, UV_CORNER, UV_RIGHT, UV_TOP, UV_RIGHT, UV_ORIGIN,
// Face 6 (Right)
UV_TOP, UV_CORNER, UV_RIGHT,
UV_RIGHT, UV_ORIGIN, UV_TOP
};
UV_TOP, UV_CORNER, UV_RIGHT, UV_RIGHT, UV_ORIGIN, UV_TOP};
break;
// Cube data for use with glDrawElements
case QTK_DRAW_ELEMENTS:
mNormals =
{/* For normals and glDrawElements, see QTK_DRAW_ELEMENTS_NORMALS */};
mTexCoords =
{ /* For UVs and glDrawElements, see QTK_DRAW_ELEMENTS_NORMALS */ };
mNormals = {
/* For normals and glDrawElements, see QTK_DRAW_ELEMENTS_NORMALS */};
mTexCoords = {
/* For UVs and glDrawElements, see QTK_DRAW_ELEMENTS_NORMALS */};
mColors = {RED, GREEN, BLUE, WHITE, YELLOW, CYAN, MAGENTA, BLACK};
mVertices = {
// 0 1 2 3
mVertices = {// 0 1 2 3
VERTEX_FTR, VERTEX_FTL, VERTEX_FBL, VERTEX_FBR,
// 4 5 6 7
VERTEX_BTR, VERTEX_BTL, VERTEX_BBL, VERTEX_BBR
};
mIndices = {
// Face 1 (Front)
VERTEX_BTR, VERTEX_BTL, VERTEX_BBL, VERTEX_BBR};
mIndices = {// Face 1 (Front)
0, 1, 2, 2, 3, 0,
// Face 2 (Back)
7, 5, 4, 5, 7, 6,
@ -114,16 +92,14 @@ Cube::Cube(DrawMode mode)
// Face 5 (Left)
2, 1, 5, 2, 5, 6,
// Face 6 (Right)
0, 3, 7, 7, 4, 0
};
0, 3, 7, 7, 4, 0};
break;
// Cube shape data for using normals and UVs with glDrawElements
case QTK_DRAW_ELEMENTS_NORMALS:
mColors = {RED, GREEN, BLUE, WHITE, YELLOW, CYAN, MAGENTA, BLACK};
mVertices = {
// Face 1 (Front)
mVertices = {// Face 1 (Front)
// 0 1 2 3
VERTEX_FTL, VERTEX_FBL, VERTEX_FBR, VERTEX_FTR,
// Face 2 (Back)
@ -140,11 +116,9 @@ Cube::Cube(DrawMode mode)
VERTEX_FBL, VERTEX_BBL, VERTEX_BTL, VERTEX_FTL,
// Face 6 (Right)
// 20 21 22 23
VERTEX_FBR, VERTEX_BBR, VERTEX_BTR, VERTEX_FTR
};
VERTEX_FBR, VERTEX_BBR, VERTEX_BTR, VERTEX_FTR};
mIndices = {
// Face 1 (Front)
mIndices = {// Face 1 (Front)
0, 1, 2, 2, 3, 0,
// Face 2 (Back)
4, 5, 6, 6, 7, 4,
@ -156,8 +130,7 @@ Cube::Cube(DrawMode mode)
// Face 5 (Left)
16, 17, 18, 18, 19, 16,
// Face 6 (Right)
20, 21, 22, 22, 23, 20
};
20, 21, 22, 22, 23, 20};
mNormals = {
VECTOR_FORWARD, VECTOR_FORWARD, VECTOR_FORWARD, VECTOR_FORWARD,
@ -170,31 +143,54 @@ Cube::Cube(DrawMode mode)
mTexCoords = {
// Face 1 (Front)
UV_TOP, UV_RIGHT, UV_CORNER,
UV_RIGHT, UV_TOP, UV_ORIGIN,
UV_TOP,
UV_RIGHT,
UV_CORNER,
UV_RIGHT,
UV_TOP,
UV_ORIGIN,
// Face 2 (Back)
UV_TOP, UV_RIGHT, UV_CORNER,
UV_RIGHT, UV_TOP, UV_ORIGIN,
UV_TOP,
UV_RIGHT,
UV_CORNER,
UV_RIGHT,
UV_TOP,
UV_ORIGIN,
// Face 3 (Top)
UV_TOP, UV_RIGHT, UV_CORNER,
UV_RIGHT, UV_TOP, UV_ORIGIN,
UV_TOP,
UV_RIGHT,
UV_CORNER,
UV_RIGHT,
UV_TOP,
UV_ORIGIN,
// Face 4 (Bottom)
UV_TOP, UV_RIGHT, UV_CORNER,
UV_RIGHT, UV_TOP, UV_ORIGIN,
UV_TOP,
UV_RIGHT,
UV_CORNER,
UV_RIGHT,
UV_TOP,
UV_ORIGIN,
// Face 5 (Left)
UV_TOP, UV_RIGHT, UV_CORNER,
UV_RIGHT, UV_TOP, UV_ORIGIN,
UV_TOP,
UV_RIGHT,
UV_CORNER,
UV_RIGHT,
UV_TOP,
UV_ORIGIN,
// Face 6 (Right)
UV_TOP, UV_RIGHT, UV_CORNER,
UV_RIGHT, UV_TOP, UV_ORIGIN,
UV_TOP,
UV_RIGHT,
UV_CORNER,
UV_RIGHT,
UV_TOP,
UV_ORIGIN,
};
break;
}
}
Triangle::Triangle(DrawMode mode)
{
Triangle::Triangle(DrawMode mode) {
mDrawMode = mode;
const QVector3D triangleTop = QVector3D(0.0f, 0.5f, 0.0f);
switch(mode) {
@ -205,17 +201,29 @@ Triangle::Triangle(DrawMode mode)
mVertices = {
// Bottom face (Base of the pyramid)
VERTEX_BBL, VERTEX_BBR, VERTEX_FBR,
VERTEX_FBR, VERTEX_FBL, VERTEX_BBL,
VERTEX_BBL,
VERTEX_BBR,
VERTEX_FBR,
VERTEX_FBR,
VERTEX_FBL,
VERTEX_BBL,
// Front face
VERTEX_FBL, VERTEX_FBR, triangleTop,
VERTEX_FBL,
VERTEX_FBR,
triangleTop,
// Back face
VERTEX_BBR, VERTEX_BBL, triangleTop,
VERTEX_BBR,
VERTEX_BBL,
triangleTop,
// Left face
VERTEX_BBL, VERTEX_FBL, triangleTop,
VERTEX_BBL,
VERTEX_FBL,
triangleTop,
// Right face
VERTEX_FBR, VERTEX_BBR, triangleTop,
VERTEX_FBR,
VERTEX_BBR,
triangleTop,
};
// Find normals for each triangle of the mesh
@ -230,17 +238,29 @@ Triangle::Triangle(DrawMode mode)
mTexCoords = {
// Bottom face (Base of the pyramid)
UV_ORIGIN, UV_RIGHT, UV_CORNER,
UV_CORNER, UV_TOP, UV_ORIGIN,
UV_ORIGIN,
UV_RIGHT,
UV_CORNER,
UV_CORNER,
UV_TOP,
UV_ORIGIN,
// Front face
UV_ORIGIN, UV_RIGHT, UV_CORNER,
UV_ORIGIN,
UV_RIGHT,
UV_CORNER,
// Back face
UV_ORIGIN, UV_RIGHT, UV_CORNER,
UV_ORIGIN,
UV_RIGHT,
UV_CORNER,
// Left face
UV_ORIGIN, UV_RIGHT, UV_CORNER,
UV_ORIGIN,
UV_RIGHT,
UV_CORNER,
// Right face
UV_ORIGIN, UV_RIGHT, UV_CORNER,
UV_ORIGIN,
UV_RIGHT,
UV_CORNER,
};
break;
@ -262,8 +282,8 @@ Triangle::Triangle(DrawMode mode)
1, 3, 4, // Right face
};
mNormals =
{/* Use QTK_DRAW_ELEMENTS_NORMALS for normals with glDrawElements */};
mNormals = {
/* Use QTK_DRAW_ELEMENTS_NORMALS for normals with glDrawElements */};
mTexCoords = {/* No UVs for triangle with glDrawElements */};
@ -276,22 +296,34 @@ Triangle::Triangle(DrawMode mode)
mVertices = {
// Bottom face
// 0 1 2
VERTEX_FBL, VERTEX_FBR, VERTEX_BBL,
VERTEX_FBL,
VERTEX_FBR,
VERTEX_BBL,
// 3 4 5
VERTEX_BBR, VERTEX_FBR, VERTEX_BBL,
VERTEX_BBR,
VERTEX_FBR,
VERTEX_BBL,
// Front face
// 6 7 8
VERTEX_FBL, VERTEX_FBR, triangleTop,
VERTEX_FBL,
VERTEX_FBR,
triangleTop,
// Back face
// 9 10 11
VERTEX_BBR, VERTEX_BBL, triangleTop,
VERTEX_BBR,
VERTEX_BBL,
triangleTop,
// Left face
// 12 13 14
VERTEX_BBL, VERTEX_FBL, triangleTop,
VERTEX_BBL,
VERTEX_FBL,
triangleTop,
// Right face
// 15 16 17
VERTEX_FBR, VERTEX_BBR, triangleTop,
VERTEX_FBR,
VERTEX_BBR,
triangleTop,
};
mIndices = {
@ -307,9 +339,8 @@ Triangle::Triangle(DrawMode mode)
// Find normals for each triangle of the mesh
for(int i = 0; i < mVertices.size(); i += 3) {
QVector3D vertexNormal =
QVector3D::normal(mVertices[mIndices[i]],
mVertices[mIndices[i+1]],
QVector3D vertexNormal = QVector3D::normal(
mVertices[mIndices[i]], mVertices[mIndices[i + 1]],
mVertices[mIndices[i + 2]]);
// Three points share this normal
for(int j = 0; j < 3; j++) {
@ -319,19 +350,30 @@ Triangle::Triangle(DrawMode mode)
mTexCoords = {
// Bottom face
UV_ORIGIN, UV_RIGHT, UV_TOP,
UV_CORNER, UV_RIGHT, UV_TOP,
UV_ORIGIN,
UV_RIGHT,
UV_TOP,
UV_CORNER,
UV_RIGHT,
UV_TOP,
// Front face
UV_ORIGIN, UV_RIGHT, UV_CORNER,
UV_ORIGIN,
UV_RIGHT,
UV_CORNER,
// Back face
UV_ORIGIN, UV_RIGHT, UV_CORNER,
UV_ORIGIN,
UV_RIGHT,
UV_CORNER,
// Left face
UV_ORIGIN, UV_RIGHT, UV_CORNER,
UV_ORIGIN,
UV_RIGHT,
UV_CORNER,
// Right face
UV_ORIGIN, UV_RIGHT, UV_CORNER,
UV_ORIGIN,
UV_RIGHT,
UV_CORNER,
};
break;
}
}

View File

@ -11,12 +11,14 @@
#include <QOpenGLWidget>
#include <QVector2D>
#include <QVector3D>
#include <utility>
#include <qtkapi.h>
#include <transform3D.h>
namespace Qtk {
class MeshRenderer;
class Object;
// Define vertices for drawing a cube using two faces (8 vertex points)
@ -45,18 +47,20 @@ namespace Qtk {
#define VECTOR_ZERO QVector3D(0.0f, 0.0f, 0.0f)
// A series of direction vectors to represent cube face normal
#define FACE_TOP VECTOR_UP, VECTOR_UP, VECTOR_UP, \
VECTOR_UP, VECTOR_UP, VECTOR_UP
#define FACE_BOTTOM VECTOR_DOWN, VECTOR_DOWN, VECTOR_DOWN, \
VECTOR_DOWN, VECTOR_DOWN, VECTOR_DOWN
#define FACE_LEFT VECTOR_LEFT, VECTOR_LEFT, VECTOR_LEFT, \
VECTOR_LEFT, VECTOR_LEFT, VECTOR_LEFT
#define FACE_RIGHT VECTOR_RIGHT, VECTOR_RIGHT, VECTOR_RIGHT, \
VECTOR_RIGHT, VECTOR_RIGHT, VECTOR_RIGHT
#define FACE_FRONT VECTOR_FORWARD, VECTOR_FORWARD, VECTOR_FORWARD, \
VECTOR_FORWARD, VECTOR_FORWARD, VECTOR_FORWARD
#define FACE_BACK VECTOR_BACK, VECTOR_BACK, VECTOR_BACK, \
VECTOR_BACK, VECTOR_BACK, VECTOR_BACK
#define FACE_TOP \
VECTOR_UP, VECTOR_UP, VECTOR_UP, VECTOR_UP, VECTOR_UP, VECTOR_UP
#define FACE_BOTTOM \
VECTOR_DOWN, VECTOR_DOWN, VECTOR_DOWN, VECTOR_DOWN, VECTOR_DOWN, VECTOR_DOWN
#define FACE_LEFT \
VECTOR_LEFT, VECTOR_LEFT, VECTOR_LEFT, VECTOR_LEFT, VECTOR_LEFT, VECTOR_LEFT
#define FACE_RIGHT \
VECTOR_RIGHT, VECTOR_RIGHT, VECTOR_RIGHT, VECTOR_RIGHT, VECTOR_RIGHT, \
VECTOR_RIGHT
#define FACE_FRONT \
VECTOR_FORWARD, VECTOR_FORWARD, VECTOR_FORWARD, VECTOR_FORWARD, \
VECTOR_FORWARD, VECTOR_FORWARD
#define FACE_BACK \
VECTOR_BACK, VECTOR_BACK, VECTOR_BACK, VECTOR_BACK, VECTOR_BACK, VECTOR_BACK
// Colors using QVector3Ds as RGB values
#define WHITE VECTOR_ONE
@ -79,19 +83,38 @@ namespace Qtk {
typedef std::vector<QVector2D> TexCoords;
typedef std::vector<QVector3D> Normals;
enum DrawMode { QTK_DRAW_ARRAYS, QTK_DRAW_ELEMENTS, QTK_DRAW_ELEMENTS_NORMALS };
enum DrawMode {
QTK_DRAW_ARRAYS,
QTK_DRAW_ELEMENTS,
QTK_DRAW_ELEMENTS_NORMALS
};
struct QTKAPI ShapeBase {
ShapeBase(DrawMode mode=QTK_DRAW_ARRAYS, Vertices v={},Indices i={}, Colors c={},
TexCoords t={}, Normals n={})
: mVertices(v), mColors(c), mIndices(i), mTexCoords(t), mNormals(n)
{}
explicit ShapeBase(
DrawMode mode = QTK_DRAW_ARRAYS, Vertices v = {}, Indices i = {},
Colors c = {}, TexCoords t = {}, Normals n = {}) :
mVertices(std::move(std::move(v))),
mColors(std::move(std::move(c))), mIndices(std::move(std::move(i))),
mTexCoords(std::move(std::move(t))),
mNormals(std::move(std::move(n))) {}
inline const Vertices & getVertices() const { return mVertices;}
inline const Indices & getIndexData() const { return mIndices;}
inline const Colors & getColors() const { return mColors;}
inline const TexCoords & getTexCoords() const { return mTexCoords;}
inline const Normals & getNormals() const { return mNormals;}
[[nodiscard]] inline const Vertices & getVertices() const {
return mVertices;
}
[[nodiscard]] inline const Indices & getIndexData() const {
return mIndices;
}
[[nodiscard]] inline const Colors & getColors() const { return mColors; }
[[nodiscard]] inline const TexCoords & getTexCoords() const {
return mTexCoords;
}
[[nodiscard]] inline const Normals & getNormals() const {
return mNormals;
}
protected:
DrawMode mDrawMode;
@ -106,29 +129,42 @@ namespace Qtk {
struct Shape : public ShapeBase {
friend MeshRenderer;
friend Object;
Shape () {}
Shape(const ShapeBase & rhs) : ShapeBase(rhs) {}
virtual inline void setVertices(const Vertices & value) {mVertices = value;}
virtual inline void setIndices(const Indices & value) {mIndices = value;}
Shape() = default;
explicit Shape(const ShapeBase & rhs) : ShapeBase(rhs) {}
virtual inline void setVertices(const Vertices & value) {
mVertices = value;
}
virtual inline void setIndices(const Indices & value) {
mIndices = value;
}
virtual inline void setColors(const Colors & value) { mColors = value; }
virtual inline void setTexCoords(const TexCoords & value) {mTexCoords = value;}
virtual inline void setNormals(const Normals & value) {mNormals = value;}
virtual inline void setTexCoords(const TexCoords & value) {
mTexCoords = value;
}
virtual inline void setNormals(const Normals & value) {
mNormals = value;
}
virtual inline void setShape(const Shape & value) { *this = value; }
};
// Primitives inherit from ShapeBase, does not allow setting of shape values
class QTKAPI Mesh {
};
class QTKAPI Mesh {};
struct QTKAPI Cube : public ShapeBase {
Cube(DrawMode mode=QTK_DRAW_ARRAYS);
explicit Cube(DrawMode mode = QTK_DRAW_ARRAYS);
};
struct QTKAPI Triangle : public ShapeBase {
Triangle(DrawMode mode=QTK_DRAW_ARRAYS);
explicit Triangle(DrawMode mode = QTK_DRAW_ARRAYS);
};
}
} // namespace Qtk
#endif // QTK_MESH_H

View File

@ -17,45 +17,47 @@ using namespace Qtk;
// Static QHash that holds all MeshRenderer instances using their mName as keys
Qtk::MeshRenderer::MeshManager Qtk::MeshRenderer::sInstances;
MeshRenderer::MeshRenderer(const char * name, const ShapeBase & shape)
: Object(name, shape), mVertexShader(":/multi-color.vert"),
MeshRenderer::MeshRenderer(const char * name, const ShapeBase & shape) :
Object(name, shape), mVertexShader(":/multi-color.vert"),
mFragmentShader(":/multi-color.frag"), mDrawType(GL_TRIANGLES),
mHasTexture(false)
{
mHasTexture(false) {
mShape = Shape(shape);
init();
sInstances.insert(name, this);
}
MeshRenderer::~MeshRenderer()
{
MeshRenderer::~MeshRenderer() {
sInstances.remove(mName);
}
// Static member function to retrieve instances of MeshRenderers
MeshRenderer * MeshRenderer::getInstance(const QString & name)
{ return sInstances[name];}
MeshRenderer * MeshRenderer::getInstance(const QString & name) {
return sInstances[name];
}
/*******************************************************************************
* Public Member Functions
******************************************************************************/
void MeshRenderer::init()
{
if (mVAO.isCreated()) mVAO.destroy();
if (mProgram.isLinked()) mProgram.removeAllShaders();
if (mVBO.isCreated()) mVBO.destroy();
void MeshRenderer::init() {
if(mVAO.isCreated()) {
mVAO.destroy();
}
if(mProgram.isLinked()) {
mProgram.removeAllShaders();
}
if(mVBO.isCreated()) {
mVBO.destroy();
}
mVAO.create();
mVAO.bind();
mProgram.create();
mProgram.addShaderFromSourceFile(QOpenGLShader::Vertex,
mVertexShader.c_str());
mProgram.addShaderFromSourceFile(QOpenGLShader::Fragment,
mFragmentShader.c_str());
mProgram.addShaderFromSourceFile(
QOpenGLShader::Vertex, mVertexShader.c_str());
mProgram.addShaderFromSourceFile(
QOpenGLShader::Fragment, mFragmentShader.c_str());
mProgram.link();
mProgram.bind();
@ -69,18 +71,16 @@ void MeshRenderer::init()
combined.insert(combined.end(), getVertices().begin(), getVertices().end());
combined.insert(combined.end(), getColors().begin(), getColors().end());
mVBO.allocate(combined.data(),
combined.size() * sizeof(combined[0]));
mVBO.allocate(combined.data(), combined.size() * sizeof(combined[0]));
// Enable position attribute
mProgram.enableAttributeArray(0);
mProgram.setAttributeBuffer(0, GL_FLOAT, 0,
3, sizeof(QVector3D));
mProgram.setAttributeBuffer(0, GL_FLOAT, 0, 3, sizeof(QVector3D));
// Enable color attribute, setting offset to total size of vertices()
mProgram.enableAttributeArray(1);
mProgram.setAttributeBuffer(1, GL_FLOAT,
getVertices().size() * sizeof(getVertices()[0]),
3, sizeof(QVector3D));
mProgram.setAttributeBuffer(
1, GL_FLOAT, getVertices().size() * sizeof(getVertices()[0]), 3,
sizeof(QVector3D));
mVBO.release();
@ -88,8 +88,7 @@ void MeshRenderer::init()
mVAO.release();
}
void MeshRenderer::draw()
{
void MeshRenderer::draw() {
mProgram.bind();
mVAO.bind();
@ -102,11 +101,12 @@ void MeshRenderer::draw()
if(mShape.mDrawMode == QTK_DRAW_ARRAYS) {
glDrawArrays(mDrawType, 0, getVertices().size());
}
else if (mShape.mDrawMode == QTK_DRAW_ELEMENTS
} else if(
mShape.mDrawMode == QTK_DRAW_ELEMENTS
|| mShape.mDrawMode == QTK_DRAW_ELEMENTS_NORMALS) {
glDrawElements(mDrawType, mShape.mIndices.size(),
GL_UNSIGNED_INT, mShape.mIndices.data());
glDrawElements(
mDrawType, mShape.mIndices.size(), GL_UNSIGNED_INT,
mShape.mIndices.data());
}
if(mTexture.hasTexture()) {
@ -117,41 +117,36 @@ void MeshRenderer::draw()
mProgram.release();
}
void MeshRenderer::setShaders(const std::string & vert, const std::string & frag)
{
void MeshRenderer::setShaders(
const std::string & vert, const std::string & frag) {
mVertexShader = vert;
mFragmentShader = frag;
}
void MeshRenderer::setUniformMVP(const char * model, const char * view,
const char * projection)
{
void MeshRenderer::setUniformMVP(
const char * model, const char * view, const char * projection) {
mProgram.setUniformValue(projection, Scene::Projection());
mProgram.setUniformValue(view, Scene::View());
mProgram.setUniformValue(model, mTransform.toMatrix());
}
void MeshRenderer::setColor(const QVector3D & color)
{
void MeshRenderer::setColor(const QVector3D & color) {
if(mShape.mColors.empty()) {
for(const auto & vertex : mShape.getVertices()) {
mShape.mColors.push_back(color);
}
}
else {
} else {
for(int i = 0; i < mShape.getColors().size(); i++) {
mShape.mColors[i] = color;
}
}
}
/*******************************************************************************
* Inherited Virtual Member Functions
******************************************************************************/
void MeshRenderer::setShape(const Shape & value)
{
void MeshRenderer::setShape(const Shape & value) {
Object::setShape(value);
init();
}

View File

@ -14,21 +14,22 @@
#include <utility>
namespace Qtk {
class QTKAPI MeshRenderer : public Object {
public:
// Delegate constructors
MeshRenderer(const char * name, Vertices vertices, Indices indices,
DrawMode mode=QTK_DRAW_ARRAYS)
: MeshRenderer(name, ShapeBase(mode, std::move(vertices), std::move(indices)))
{}
explicit MeshRenderer(const char * name)
: MeshRenderer(name, Cube(QTK_DRAW_ELEMENTS))
{}
MeshRenderer(
const char * name, Vertices vertices, Indices indices,
DrawMode mode = QTK_DRAW_ARRAYS) :
MeshRenderer(
name, ShapeBase(mode, std::move(vertices), std::move(indices))) {}
explicit MeshRenderer(const char * name) :
MeshRenderer(name, Cube(QTK_DRAW_ELEMENTS)) {}
// Constructor
MeshRenderer(const char * name, const ShapeBase & shape);
~MeshRenderer();
~MeshRenderer() override;
// Retrieve a mesh by name stored within a static QHash
static MeshRenderer * getInstance(const QString & name);
@ -40,22 +41,29 @@ namespace Qtk {
void setDrawType(int drawType) { mDrawType = drawType; }
// Shader settings
inline void setShaderVertex(const std::string & vert) { mVertexShader = vert;}
inline void setShaderFragment(const std::string & frag)
{ mFragmentShader = frag;}
inline void setShaderVertex(const std::string & vert) {
mVertexShader = vert;
}
inline void setShaderFragment(const std::string & frag) {
mFragmentShader = frag;
}
void setShaders(const std::string & vert, const std::string & frag);
template <typename T>
inline void setUniform(int location, T value)
{ mProgram.setUniformValue(location, value);}
template <typename T> inline void setUniform(int location, T value) {
mProgram.setUniformValue(location, value);
}
template <typename T>
inline void setUniform(const char * location, T value)
{ mProgram.setUniformValue(location, value);}
inline void setUniform(const char * location, T value) {
mProgram.setUniformValue(location, value);
}
// Set MVP matrix using this Object's transform
// + View and projection provided by MainWidget static members
void setUniformMVP(const char * model="uModel", const char * view="uView",
void setUniformMVP(
const char * model = "uModel", const char * view = "uView",
const char * projection = "uProjection");
// These functions modify data stored in a VBO
@ -65,6 +73,7 @@ namespace Qtk {
// Static QHash of all mesh objects within the scene
typedef QHash<QString, MeshRenderer *> MeshManager;
private:
static MeshManager sInstances;
@ -72,6 +81,6 @@ namespace Qtk {
bool mHasTexture;
std::string mVertexShader, mFragmentShader;
};
}
} // namespace Qtk
#endif // QTK_MESHRENDERER_H

View File

@ -19,18 +19,15 @@ using namespace Qtk;
Model::ModelManager Model::mManager;
// Static function to access ModelManager for getting Models by name
Model * Model::getInstance(const char * name)
{
Model * Model::getInstance(const char * name) {
return mManager[name];
}
/*******************************************************************************
* ModelMesh Private Member Functions
******************************************************************************/
void ModelMesh::initMesh(const char * vert, const char * frag)
{
void ModelMesh::initMesh(const char * vert, const char * frag) {
initializeOpenGLFunctions();
// Create VAO, VBO, EBO
@ -44,14 +41,12 @@ void ModelMesh::initMesh(const char * vert, const char * frag)
mVBO->setUsagePattern(QOpenGLBuffer::StaticDraw);
mVBO->bind();
mVBO->allocate(mVertices.data(),
mVertices.size() * sizeof(mVertices[0]));
mVBO->allocate(mVertices.data(), mVertices.size() * sizeof(mVertices[0]));
// Allocate EBO
mEBO->setUsagePattern(QOpenGLBuffer::StaticDraw);
mEBO->bind();
mEBO->allocate(mIndices.data(),
mIndices.size() * sizeof(mIndices[0]));
mEBO->allocate(mIndices.data(), mIndices.size() * sizeof(mIndices[0]));
mEBO->release();
// Load and link shaders
@ -62,46 +57,40 @@ void ModelMesh::initMesh(const char * vert, const char * frag)
// Positions
mProgram->enableAttributeArray(0);
mProgram->setAttributeBuffer(0, GL_FLOAT,
offsetof(ModelVertex, mPosition), 3,
sizeof(ModelVertex));
mProgram->setAttributeBuffer(
0, GL_FLOAT, offsetof(ModelVertex, mPosition), 3, sizeof(ModelVertex));
// Normals
mProgram->enableAttributeArray(1);
mProgram->setAttributeBuffer(1, GL_FLOAT,
offsetof(ModelVertex, mNormal), 3,
sizeof(ModelVertex));
mProgram->setAttributeBuffer(
1, GL_FLOAT, offsetof(ModelVertex, mNormal), 3, sizeof(ModelVertex));
// Texture Coordinates
mProgram->enableAttributeArray(2);
mProgram->setAttributeBuffer(2, GL_FLOAT,
offsetof(ModelVertex, mTextureCoord), 2,
mProgram->setAttributeBuffer(
2, GL_FLOAT, offsetof(ModelVertex, mTextureCoord), 2,
sizeof(ModelVertex));
// Vertex tangents
mProgram->enableAttributeArray(3);
mProgram->setAttributeBuffer(3, GL_FLOAT,
offsetof(ModelVertex, mTangent), 3,
sizeof(ModelVertex));
mProgram->setAttributeBuffer(
3, GL_FLOAT, offsetof(ModelVertex, mTangent), 3, sizeof(ModelVertex));
// Vertex bitangents
mProgram->enableAttributeArray(4);
mProgram->setAttributeBuffer(4, GL_FLOAT,
offsetof(ModelVertex, mBitangent), 3,
sizeof(ModelVertex));
mProgram->setAttributeBuffer(
4, GL_FLOAT, offsetof(ModelVertex, mBitangent), 3, sizeof(ModelVertex));
mProgram->release();
mVBO->release();
mVAO->release();
}
/*******************************************************************************
* ModelMesh Public Member Functions
******************************************************************************/
void ModelMesh::draw(QOpenGLShaderProgram & shader)
{
void ModelMesh::draw(QOpenGLShaderProgram & shader) {
mVAO->bind();
// Bind shader
shader.bind();
@ -124,17 +113,23 @@ void ModelMesh::draw(QOpenGLShaderProgram & shader)
// Specular: material.texture_specular1, material.texture_specular2, ...
std::string number;
std::string name = mTextures[i].mType;
if (name == "texture_diffuse") number = std::to_string(diffuseCount++);
if (name == "texture_specular") number = std::to_string(specularCount++);
if (name == "texture_normal") number = std::to_string(normalCount++);
if(name == "texture_diffuse") {
number = std::to_string(diffuseCount++);
}
if(name == "texture_specular") {
number = std::to_string(specularCount++);
}
if(name == "texture_normal") {
number = std::to_string(normalCount++);
}
// Set the uniform to track this texture ID using our naming convention
shader.setUniformValue((name + number).c_str(), i);
}
// Draw the mesh
glDrawElements(GL_TRIANGLES, mIndices.size(),
GL_UNSIGNED_INT, mIndices.data());
glDrawElements(
GL_TRIANGLES, mIndices.size(), GL_UNSIGNED_INT, mIndices.data());
// Release shader, textures
for(const auto & texture : mTextures) {
@ -145,29 +140,25 @@ void ModelMesh::draw(QOpenGLShaderProgram & shader)
glActiveTexture(GL_TEXTURE0);
}
/*******************************************************************************
* Model Public Member Functions
******************************************************************************/
void Model::draw()
{
for (GLuint i = 0; i < mMeshes.size(); i++) {
mMeshes[i].mTransform = mTransform;
mMeshes[i].draw();
void Model::draw() {
for(auto & mMeshe : mMeshes) {
mMeshe.mTransform = mTransform;
mMeshe.draw();
}
}
void Model::draw(QOpenGLShaderProgram & shader)
{
for (GLuint i = 0; i < mMeshes.size(); i++) {
mMeshes[i].mTransform = mTransform;
mMeshes[i].draw(shader);
void Model::draw(QOpenGLShaderProgram & shader) {
for(auto & mMeshe : mMeshes) {
mMeshe.mTransform = mTransform;
mMeshe.draw(shader);
}
}
void Model::flipTexture(const std::string & fileName, bool flipX, bool flipY)
{
void Model::flipTexture(const std::string & fileName, bool flipX, bool flipY) {
bool modified = false;
std::string fullPath = mDirectory + '/' + fileName;
for(auto & texture : mTexturesLoaded) {
@ -183,10 +174,8 @@ void Model::flipTexture(const std::string & fileName, bool flipX, bool flipY)
qDebug() << "Attempt to flip texture that doesn't exist: "
<< fullPath.c_str() << "\n";
}
}
/*******************************************************************************
* Model Private Member Functions
******************************************************************************/
@ -206,8 +195,7 @@ void Model::flipTexture(const std::string & fileName, bool flipX, bool flipY)
*
* @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;
// JIC a relative path was used, get the absolute file path
@ -219,15 +207,10 @@ void Model::loadModel(const std::string & path)
// Import the model, converting non-triangular geometry to triangles
// + And flipping texture UVs, etc..
// Assimp options: http://assimp.sourceforge.net/lib_html/postprocess_8h.html
const aiScene * scene =
import.ReadFile(mDirectory, aiProcess_Triangulate
| aiProcess_FlipUVs
| aiProcess_GenSmoothNormals
| aiProcess_CalcTangentSpace
| aiProcess_OptimizeMeshes
| aiProcess_SplitLargeMeshes
);
const aiScene * scene = import.ReadFile(
mDirectory, aiProcess_Triangulate | aiProcess_FlipUVs
| aiProcess_GenSmoothNormals | aiProcess_CalcTangentSpace
| aiProcess_OptimizeMeshes | aiProcess_SplitLargeMeshes);
// If there were errors, print and return
if(!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) {
@ -250,8 +233,7 @@ void Model::loadModel(const std::string & path)
mManager.insert(mName, this);
}
void Model::processNode(aiNode * node, const aiScene * scene)
{
void Model::processNode(aiNode * node, const aiScene * scene) {
// Process each mesh that is available for this node
for(GLuint i = 0; i < node->mNumMeshes; i++) {
aiMesh * mesh = scene->mMeshes[node->mMeshes[i]];
@ -264,8 +246,7 @@ void Model::processNode(aiNode * node, const aiScene * scene)
}
}
ModelMesh Model::processMesh(aiMesh * mesh, const aiScene * scene)
{
ModelMesh Model::processMesh(aiMesh * mesh, const aiScene * scene) {
ModelMesh::Vertices vertices;
ModelMesh::Indices indices;
ModelMesh::Textures textures;
@ -313,8 +294,7 @@ ModelMesh Model::processMesh(aiMesh * mesh, const aiScene * scene)
vector3D.setY(mesh->mBitangents[i].y);
vector3D.setZ(mesh->mBitangents[i].z);
vertex.mBitangent = vector3D;
}
else {
} else {
vertex.mTextureCoord = {0.0f, 0.0f};
}
@ -337,48 +317,42 @@ ModelMesh Model::processMesh(aiMesh * mesh, const aiScene * scene)
aiMaterial * material = scene->mMaterials[mesh->mMaterialIndex];
// Get all diffuse textures from the material
ModelMesh::Textures diffuseMaps =
loadMaterialTextures(material, aiTextureType_DIFFUSE,
"texture_diffuse");
ModelMesh::Textures diffuseMaps = loadMaterialTextures(
material, aiTextureType_DIFFUSE, "texture_diffuse");
// Insert all diffuse textures found into our textures container
textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());
// Get all specular textures from the material
ModelMesh::Textures specularMaps =
loadMaterialTextures(material, aiTextureType_SPECULAR,
"texture_specular");
ModelMesh::Textures specularMaps = loadMaterialTextures(
material, aiTextureType_SPECULAR, "texture_specular");
// Insert all specular textures found into our textures container
textures.insert(textures.end(), specularMaps.begin(), specularMaps.end());
// Get all normal textures from the material
ModelMesh::Textures normalMaps =
loadMaterialTextures(material, aiTextureType_HEIGHT,
"texture_normal");
loadMaterialTextures(material, aiTextureType_HEIGHT, "texture_normal");
// Insert all normal maps found into our textures container
textures.insert(textures.end(), normalMaps.begin(), normalMaps.end());
}
return ModelMesh(vertices, indices, textures,
mVertexShader, mFragmentShader);
return {vertices, indices, textures, mVertexShader, mFragmentShader};
}
ModelMesh::Textures Model::loadMaterialTextures(
aiMaterial * mat, aiTextureType type, const std::string & typeName)
{
aiMaterial * mat, aiTextureType type, const std::string & typeName) {
ModelMesh::Textures textures;
for(GLuint i = 0; i < mat->GetTextureCount(type); i++) {
// Call GetTexture to get the name of the texture file to load
aiString fileName;
mat->GetTexture(type, i, &fileName);
// Check if we have already loaded this texture
bool skip = false;
for (GLuint j = 0; j < mTexturesLoaded.size(); j++) {
for(auto & j : mTexturesLoaded) {
// If the path to the texture already exists in m_texturesLoaded, skip it
if (std::strcmp(mTexturesLoaded[j].mPath.data(), fileName.C_Str()) == 0) {
textures.push_back(mTexturesLoaded[j]);
if(std::strcmp(j.mPath.data(), fileName.C_Str()) == 0) {
textures.push_back(j);
// If we have loaded the texture, do not load it again
skip = true;
break;
@ -389,8 +363,8 @@ ModelMesh::Textures Model::loadMaterialTextures(
if(!skip) {
ModelTexture texture;
texture.mTexture = OpenGLTextureFactory::initTexture2D(
std::string(mDirectory + '/' + fileName.C_Str()).c_str(),
false, false);
std::string(mDirectory + '/' + fileName.C_Str()).c_str(), false,
false);
texture.mID = texture.mTexture->textureId();
texture.mType = typeName;
texture.mPath = fileName.C_Str();
@ -399,23 +373,20 @@ ModelMesh::Textures Model::loadMaterialTextures(
// Add the texture to the loaded textures to avoid loading it twice
mTexturesLoaded.push_back(texture);
}
}
// Return the resulting textures
return textures;
}
void Model::sortModels()
{
void Model::sortModels() {
auto cameraPos = Scene::Camera().transform();
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
return (cameraPos.getTranslation().distanceToPoint(a.mVertices[0].mPosition))
< (cameraPos.getTranslation().distanceToPoint(b.mVertices[0].mPosition));
return (cameraPos.getTranslation().distanceToPoint(
a.mVertices[0].mPosition))
< (cameraPos.getTranslation().distanceToPoint(
b.mVertices[0].mPosition));
};
std::sort(mMeshes.begin(), mMeshes.end(), cameraDistance);
}

View File

@ -18,14 +18,14 @@
#include <QOpenGLVertexArrayObject>
// Assimp
#include <assimp/Importer.hpp>
#include <assimp/postprocess.h>
#include <assimp/scene.h>
#include <assimp/Importer.hpp>
// QTK
#include <object.h>
#include <qtkapi.h>
#include <transform3D.h>
#include <object.h>
namespace Qtk {
struct QTKAPI ModelVertex {
@ -53,18 +53,20 @@ namespace Qtk {
typedef std::vector<ModelTexture> Textures;
// Constructors, Destructors
ModelMesh(Vertices vertices, Indices indices, Textures textures,
ModelMesh(
Vertices vertices, Indices indices, Textures textures,
const char * vertexShader = ":/model-basic.vert",
const char * fragmentShader=":/model-basic.frag")
: mProgram(new QOpenGLShaderProgram),
const char * fragmentShader = ":/model-basic.frag") :
mProgram(new QOpenGLShaderProgram),
mVAO(new QOpenGLVertexArrayObject),
mVBO(new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer)),
mEBO(new QOpenGLBuffer(QOpenGLBuffer::IndexBuffer)),
mVertices(std::move(vertices)),
mIndices(std::move(indices)),
mTextures(std::move(textures))
{ initMesh(vertexShader, fragmentShader);}
~ModelMesh() {}
mVertices(std::move(vertices)), mIndices(std::move(indices)),
mTextures(std::move(textures)) {
initMesh(vertexShader, fragmentShader);
}
~ModelMesh() = default;
private:
void initMesh(const char * vert, const char * frag);
@ -76,6 +78,7 @@ namespace Qtk {
public:
inline void draw() { draw(*mProgram); }
void draw(QOpenGLShaderProgram & shader);
// ModelMesh Public Members
@ -85,28 +88,28 @@ namespace Qtk {
Transform3D mTransform;
};
class QTKAPI Model : public QObject {
Q_OBJECT
public:
inline Model(const char * name, const char * path,
inline Model(
const char * name, const char * path,
const char * vertexShader = ":/model-basic.vert",
const char * fragmentShader=":/model-basic.frag")
: mName(name), mVertexShader(vertexShader),
mFragmentShader(fragmentShader)
{ loadModel(path);}
inline ~Model() { mManager.remove(mName);}
const char * fragmentShader = ":/model-basic.frag") :
mName(name),
mVertexShader(vertexShader), mFragmentShader(fragmentShader) {
loadModel(path);
}
inline ~Model() override { mManager.remove(mName); }
void draw();
void draw(QOpenGLShaderProgram & shader);
void flipTexture(const std::string & fileName,
bool flipX=false, bool flipY=true);
void flipTexture(
const std::string & fileName, bool flipX = false, bool flipY = true);
template <typename T>
void setUniform(const char * location, T value)
{
template <typename T> void setUniform(const char * location, T value) {
for(auto & mesh : mMeshes) {
mesh.mProgram->bind();
@ -121,13 +124,14 @@ namespace Qtk {
static Model * getInstance(const char * name);
typedef QHash<QString, Model *> ModelManager;
private:
static ModelManager mManager;
void loadModel(const std::string & path);
void processNode(aiNode * node, const aiScene * scene);
ModelMesh processMesh(aiMesh * mesh, const aiScene * scene);
ModelMesh::Textures loadMaterialTextures(aiMaterial * mat, aiTextureType type,
const std::string & typeName);
ModelMesh::Textures loadMaterialTextures(
aiMaterial * mat, aiTextureType type, const std::string & typeName);
void sortModels();
// Model Private Members
@ -137,6 +141,6 @@ namespace Qtk {
std::string mDirectory;
const char *mVertexShader, *mFragmentShader, *mName;
};
}
} // namespace Qtk
#endif // QTK_MODEL_H

View File

@ -14,8 +14,8 @@
#include <QOpenGLVertexArrayObject>
#include <mesh.h>
#include <texture.h>
#include <qtkapi.h>
#include <texture.h>
namespace Qtk {
class QTKAPI Object : public QObject {
@ -23,34 +23,62 @@ namespace Qtk {
public:
friend MeshRenderer;
// Initialize an object with no shape data assigned
Object(const char * name)
: mName(name), mVBO(QOpenGLBuffer::VertexBuffer)
{ }
// Initialize an object with shape data assigned
Object(const char * name, const ShapeBase & shape)
: mName(name), mVBO(QOpenGLBuffer::VertexBuffer), mShape(shape)
{ }
~Object() {}
// Initialize an object with no shape data assigned
explicit Object(const char * name) :
mName(name), mVBO(QOpenGLBuffer::VertexBuffer) {}
// Initialize an object with shape data assigned
Object(const char * name, const ShapeBase & shape) :
mName(name), mVBO(QOpenGLBuffer::VertexBuffer), mShape(shape) {}
~Object() override = default;
inline const Colors & getColors() { return mShape.mColors; }
inline const Indices & getIndexData() { return mShape.mIndices; }
inline const Normals & getNormals() { return mShape.mNormals; }
inline const Shape & getShape() { return mShape;}
[[nodiscard]] inline const Shape & getShape() const { return mShape; }
inline const TexCoords & getTexCoords() { return mShape.mTexCoords; }
inline Texture & getTexture() { return mTexture; }
inline const Vertices & getVertices() { return mShape.mVertices; }
virtual inline void setColors(const Colors & value) { mShape.mColors = value;}
virtual inline void setIndices(const Indices & value) { mShape.mIndices = value;}
virtual inline void setNormals(const Normals & value) { mShape.mNormals = value;}
virtual inline void setColors(const Colors & value) {
mShape.mColors = value;
}
virtual inline void setIndices(const Indices & value) {
mShape.mIndices = value;
}
virtual inline void setNormals(const Normals & value) {
mShape.mNormals = value;
}
virtual inline void setShape(const Shape & value) { mShape = value; }
virtual inline void setTexCoords(const TexCoords & value) { mShape.mTexCoords = value;}
virtual inline void setTexture(const char * path, bool flipX=false, bool flipY=false)
{ mTexture.setTexture(OpenGLTextureFactory::initTexture2D(path, flipX, flipY));}
virtual inline void setTexture(QOpenGLTexture * value) { mTexture.setTexture(value);}
virtual inline void setVertices(const Vertices & value) { mShape.mVertices = value;}
virtual inline void setTexCoords(const TexCoords & value) {
mShape.mTexCoords = value;
}
virtual inline void setTexture(
const char * path, bool flipX = false, bool flipY = false) {
mTexture.setTexture(
OpenGLTextureFactory::initTexture2D(path, flipX, flipY));
}
virtual inline void setTexture(QOpenGLTexture * value) {
mTexture.setTexture(value);
}
virtual inline void setVertices(const Vertices & value) {
mShape.mVertices = value;
}
QOpenGLBuffer mVBO, mNBO;
QOpenGLVertexArrayObject mVAO;
@ -61,6 +89,7 @@ namespace Qtk {
Texture mTexture;
const char * mName;
};}
};
} // namespace Qtk
#endif // QTK_OBJECT_H

View File

@ -8,10 +8,10 @@
#include <QKeyEvent>
#include <input.h>
#include <qtkwidget.h>
#include <mesh.h>
#include <abstractscene.h>
#include <input.h>
#include <mesh.h>
#include <qtkwidget.h>
using namespace Qtk;
@ -19,57 +19,50 @@ using namespace Qtk;
* Constructors, Destructors
******************************************************************************/
QtkWidget::QtkWidget() : mScene(Q_NULLPTR), mDebugLogger(Q_NULLPTR)
{
QtkWidget::QtkWidget() : mScene(Q_NULLPTR), mDebugLogger(Q_NULLPTR) {
initializeWidget();
}
// Constructor for using this widget in QtDesigner
QtkWidget::QtkWidget(QWidget *parent) : QOpenGLWidget(parent),
mScene(Q_NULLPTR), mDebugLogger(Q_NULLPTR)
{
QtkWidget::QtkWidget(QWidget * parent) :
QOpenGLWidget(parent), mScene(Q_NULLPTR), mDebugLogger(Q_NULLPTR) {
initializeWidget();
}
QtkWidget::QtkWidget(const QSurfaceFormat &format)
: mScene(Q_NULLPTR), mDebugLogger(Q_NULLPTR)
{
QtkWidget::QtkWidget(const QSurfaceFormat & format) :
mScene(Q_NULLPTR), mDebugLogger(Q_NULLPTR) {
setFormat(format);
setFocusPolicy(Qt::ClickFocus);
}
QtkWidget::~QtkWidget()
{
QtkWidget::~QtkWidget() {
makeCurrent();
teardownGL();
}
/*******************************************************************************
* Private Member Functions
******************************************************************************/
void QtkWidget::teardownGL()
{
void QtkWidget::teardownGL() {
// Nothing to teardown yet...
}
/*******************************************************************************
* Inherited Virtual Member Functions
******************************************************************************/
void QtkWidget::paintGL()
{
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();
if(mScene != Q_NULLPTR) {
mScene->draw();
}
}
void QtkWidget::initializeGL()
{
void QtkWidget::initializeGL() {
initializeOpenGLFunctions();
// Connect the frameSwapped signal to call the update() function
connect(this, SIGNAL(frameSwapped()), this, SLOT(update()));
@ -79,8 +72,9 @@ void QtkWidget::initializeGL()
mDebugLogger = new QOpenGLDebugLogger(this);
if(mDebugLogger->initialize()) {
qDebug() << "GL_DEBUG Debug Logger" << mDebugLogger << "\n";
connect(mDebugLogger, SIGNAL(messageLogged(QOpenGLDebugMessage)),
this, SLOT(messageLogged(QOpenGLDebugMessage)));
connect(
mDebugLogger, SIGNAL(messageLogged(QOpenGLDebugMessage)), this,
SLOT(messageLogged(QOpenGLDebugMessage)));
mDebugLogger->startLogging();
}
#endif // QTK_DEBUG
@ -98,35 +92,31 @@ void QtkWidget::initializeGL()
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
void QtkWidget::resizeGL(int width, int height)
{
void QtkWidget::resizeGL(int width, int height) {
Scene::Projection().setToIdentity();
Scene::Projection().perspective(45.0f,
float(width) / float(height),
0.1f, 1000.0f);
Scene::Projection().perspective(
45.0f, float(width) / float(height), 0.1f, 1000.0f);
}
/*******************************************************************************
* Protected Slots
******************************************************************************/
void QtkWidget::update()
{
void QtkWidget::update() {
updateCameraInput();
if (mScene != Q_NULLPTR) mScene->update();
if(mScene != Q_NULLPTR) {
mScene->update();
}
QWidget::update();
}
void QtkWidget::messageLogged(const QOpenGLDebugMessage &msg)
{
void QtkWidget::messageLogged(const QOpenGLDebugMessage & msg) {
QString error;
// Format based on severity
switch (msg.severity())
{
switch(msg.severity()) {
case QOpenGLDebugMessage::NotificationSeverity:
error += "--";
break;
@ -144,9 +134,11 @@ void QtkWidget::messageLogged(const QOpenGLDebugMessage &msg)
error += " (";
// Format based on source
#define CASE(c) case QOpenGLDebugMessage::c: error += #c; break
switch (msg.source())
{
#define CASE(c) \
case QOpenGLDebugMessage::c: \
error += #c; \
break
switch(msg.source()) {
CASE(APISource);
CASE(WindowSystemSource);
CASE(ShaderCompilerSource);
@ -160,9 +152,11 @@ void QtkWidget::messageLogged(const QOpenGLDebugMessage &msg)
error += " : ";
// Format based on type
#define CASE(c) case QOpenGLDebugMessage::c: error += #c; break
switch (msg.type())
{
#define CASE(c) \
case QOpenGLDebugMessage::c: \
error += #c; \
break
switch(msg.type()) {
CASE(InvalidType);
CASE(ErrorType);
CASE(DeprecatedBehaviorType);
@ -180,13 +174,11 @@ void QtkWidget::messageLogged(const QOpenGLDebugMessage &msg)
qDebug() << qPrintable(error) << "\n" << qPrintable(msg.message()) << "\n";
}
/*******************************************************************************
* Protected Helpers
******************************************************************************/
void QtkWidget::keyPressEvent(QKeyEvent *event)
{
void QtkWidget::keyPressEvent(QKeyEvent * event) {
if(event->isAutoRepeat()) {
// Do not repeat input while a key is held down
event->ignore();
@ -195,8 +187,7 @@ void QtkWidget::keyPressEvent(QKeyEvent *event)
}
}
void QtkWidget::keyReleaseEvent(QKeyEvent *event)
{
void QtkWidget::keyReleaseEvent(QKeyEvent * event) {
if(event->isAutoRepeat()) {
event->ignore();
} else {
@ -204,23 +195,19 @@ void QtkWidget::keyReleaseEvent(QKeyEvent *event)
}
}
void QtkWidget::mousePressEvent(QMouseEvent *event)
{
void QtkWidget::mousePressEvent(QMouseEvent * event) {
Input::registerMousePress(event->button());
}
void QtkWidget::mouseReleaseEvent(QMouseEvent *event)
{
void QtkWidget::mouseReleaseEvent(QMouseEvent * event) {
Input::registerMouseRelease(event->button());
}
/*******************************************************************************
* Private Helpers
******************************************************************************/
void QtkWidget::initializeWidget()
{
void QtkWidget::initializeWidget() {
QSurfaceFormat format;
format.setRenderableType(QSurfaceFormat::OpenGL);
format.setProfile(QSurfaceFormat::CoreProfile);
@ -237,8 +224,7 @@ void QtkWidget::initializeWidget()
setFocusPolicy(Qt::ClickFocus);
}
void QtkWidget::printContextInformation()
{
void QtkWidget::printContextInformation() {
QString glType;
QString glVersion;
QString glProfile;
@ -246,17 +232,17 @@ void QtkWidget::printContextInformation()
QString glVendor;
QString glRenderer;
// Get Version Information
glType = (context()->isOpenGLES()) ? "OpenGL ES" : "OpenGL";
glVersion = reinterpret_cast<const char *>(glGetString(GL_VERSION));
glVendor =
reinterpret_cast<const char *>(glGetString(GL_VENDOR));
glRenderer =
reinterpret_cast<const char *>(glGetString(GL_RENDERER));
glVendor = reinterpret_cast<const char *>(glGetString(GL_VENDOR));
glRenderer = reinterpret_cast<const char *>(glGetString(GL_RENDERER));
// Get Profile Information
#define CASE(c) case QSurfaceFormat::c: glProfile = #c; break
#define CASE(c) \
case QSurfaceFormat::c: \
glProfile = #c; \
break
switch(format().profile()) {
CASE(NoProfile);
CASE(CoreProfile);
@ -269,12 +255,9 @@ void QtkWidget::printContextInformation()
<< qPrintable(glProfile) << ")"
<< "\nOpenGL Vendor: " << qPrintable(glVendor)
<< "\nRendering Device: " << qPrintable(glRenderer) << "\n";
}
void QtkWidget::updateCameraInput()
{
void QtkWidget::updateCameraInput() {
Input::update();
// Camera Transformation
if(Input::buttonPressed(Qt::RightButton)) {
@ -282,10 +265,10 @@ void QtkWidget::updateCameraInput()
static const float rotSpeed = 0.5f;
// Handle rotations
Scene::Camera().transform().rotate(-rotSpeed * Input::mouseDelta().x(),
Camera3D::LocalUp);
Scene::Camera().transform().rotate(-rotSpeed * Input::mouseDelta().y(),
Scene::Camera().right());
Scene::Camera().transform().rotate(
-rotSpeed * Input::mouseDelta().x(), Camera3D::LocalUp);
Scene::Camera().transform().rotate(
-rotSpeed * Input::mouseDelta().y(), Scene::Camera().right());
// Handle translations
QVector3D translation;

View File

@ -15,12 +15,11 @@
#include <QOpenGLFunctions>
#include <QOpenGLWidget>
#include <qtkapi.h>
#include <abstractscene.h>
#include <qtkapi.h>
namespace Qtk {
class QTKAPI QtkWidget : public QOpenGLWidget,
protected QOpenGLFunctions {
class QTKAPI QtkWidget : public QOpenGLWidget, protected QOpenGLFunctions {
Q_OBJECT;
public:
@ -40,28 +39,30 @@ namespace Qtk {
void resizeGL(int width, int height) override;
inline Qtk::Scene * getScene() { return mScene; }
inline void setScene(Qtk::Scene * scene) {
if (mScene != Q_NULLPTR) delete mScene;
delete mScene;
mScene = scene;
}
protected slots:
void update();
#ifdef QTK_DEBUG
void messageLogged(const QOpenGLDebugMessage &msg);
static void messageLogged(const QOpenGLDebugMessage & msg);
#endif
// Protected Helpers
protected:
void keyPressEvent(QKeyEvent *event);
void keyReleaseEvent(QKeyEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
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 updateCameraInput();
static void updateCameraInput();
Qtk::Scene * mScene;
#ifdef QTK_DEBUG
@ -69,6 +70,6 @@ namespace Qtk {
QOpenGLDebugLogger * mDebugLogger;
#endif
};
}
} // namespace Qtk
#endif // QTK_QTKWIDGET_H

View File

@ -12,36 +12,36 @@
using namespace Qtk;
Skybox::Skybox(std::string right, std::string top, std::string front,
std::string left, std::string bottom, std::string back,
const std::string & name)
: mVBO(QOpenGLBuffer::VertexBuffer),
Skybox::Skybox(
const std::string & right, const std::string & top,
const std::string & front, const std::string & left,
const std::string & bottom, const std::string & back,
const std::string & name) :
mVBO(QOpenGLBuffer::VertexBuffer),
mVertices(Cube(QTK_DRAW_ELEMENTS).getVertices()),
mIndices(Cube(QTK_DRAW_ELEMENTS).getIndexData())
{
mIndices(Cube(QTK_DRAW_ELEMENTS).getIndexData()) {
init();
mCubeMap = OpenGLTextureFactory::initCubeMap(
QImage(right.c_str()).mirrored(), QImage(top.c_str()),
QImage(front.c_str()), QImage(left.c_str()),
QImage(bottom.c_str()), QImage(back.c_str()));
QImage(front.c_str()), QImage(left.c_str()), QImage(bottom.c_str()),
QImage(back.c_str()));
}
Skybox::Skybox(std::string name)
: Skybox(":/right.png", ":/top.png", ":/front.png",
":/left.png", ":/bottom.png", ":/back.png",
name)
{}
Skybox::Skybox(QOpenGLTexture * cubeMap, const std::string & name)
: mCubeMap(cubeMap) { init();}
Skybox::Skybox(const std::string & name) :
Skybox(
":/right.png", ":/top.png", ":/front.png", ":/left.png", ":/bottom.png",
":/back.png", name) {}
Skybox::Skybox(QOpenGLTexture * cubeMap, const std::string & name) :
mCubeMap(cubeMap) {
init();
}
/*******************************************************************************
* Public Member Functions
******************************************************************************/
void Skybox::draw()
{
void Skybox::draw() {
glDepthFunc(GL_LEQUAL);
glDepthMask(GL_FALSE);
@ -52,8 +52,8 @@ void Skybox::draw()
mProgram.setUniformValue("uProjectionMatrix", Scene::Projection());
mProgram.setUniformValue("uViewMatrix", Scene::Camera().toMatrix());
mProgram.setUniformValue("uTexture", 0);
glDrawElements(GL_TRIANGLES, mIndices.size(),
GL_UNSIGNED_INT, mIndices.data());
glDrawElements(
GL_TRIANGLES, mIndices.size(), GL_UNSIGNED_INT, mIndices.data());
mCubeMap->release();
mProgram.release();
@ -64,13 +64,11 @@ void Skybox::draw()
glActiveTexture(GL_TEXTURE0);
}
/*******************************************************************************
* Private Member Functions
******************************************************************************/
void Skybox::init()
{
void Skybox::init() {
initializeOpenGLFunctions();
// Set up shader program

View File

@ -19,19 +19,24 @@
#include <mesh.h>
#include <qtkapi.h>
namespace Qtk {
class QTKAPI Skybox : protected QOpenGLFunctions {
public:
// Delegate this constructor to use default skybox images
// + This allows creating a skybox with no arguments ( auto s = new Skybox; )
explicit Skybox(std::string name="Skybox");
explicit Skybox(QOpenGLTexture * cubeMap, const std::string & name="Skybox");
// + This allows creating a skybox with no arguments ( auto s = new
// Skybox;
// )
explicit Skybox(const std::string & name = "Skybox");
explicit Skybox(
QOpenGLTexture * cubeMap, const std::string & name = "Skybox");
// Constructor, Destructor
Skybox(std::string right, std::string top, std::string front,
std::string left, std::string bottom, std::string back,
Skybox(
const std::string & right, const std::string & top,
const std::string & front, const std::string & left,
const std::string & bottom, const std::string & back,
const std::string & name = "Skybox");
~Skybox() {}
~Skybox() = default;
void draw();
@ -46,6 +51,6 @@ namespace Qtk {
QOpenGLBuffer mVBO;
QOpenGLTexture * mCubeMap;
};
}
} // namespace Qtk
#endif // QTK_SKYBOX_H

View File

@ -8,13 +8,14 @@
#include <QDebug>
#include <QImageReader>
#include <utility>
#include <texture.h>
using namespace Qtk;
QImage * OpenGLTextureFactory::initImage(const char * image, bool flipX, bool flipY)
{
QImage * OpenGLTextureFactory::initImage(
const char * image, bool flipX, bool flipY) {
// Qt6 limits loaded images to 256MB by default
QImageReader::setAllocationLimit(512);
auto loadedImage = new QImage(QImage(image).mirrored(flipX, flipY));
@ -27,46 +28,39 @@ QImage * OpenGLTextureFactory::initImage(const char * image, bool flipX, bool fl
return loadedImage;
}
QOpenGLTexture * OpenGLTextureFactory::initTexture2D(const char * texture,
bool flipX, bool flipY)
{
QOpenGLTexture * OpenGLTextureFactory::initTexture2D(
const char * texture, bool flipX, bool flipY) {
QImage * image = initImage(texture, flipX, flipY);
auto newTexture = new QOpenGLTexture(QOpenGLTexture::Target2D);
newTexture->setData(*image);
newTexture->setWrapMode(QOpenGLTexture::Repeat);
newTexture->setMinMagFilters(QOpenGLTexture::LinearMipMapLinear,
QOpenGLTexture::Linear);
newTexture->setMinMagFilters(
QOpenGLTexture::LinearMipMapLinear, QOpenGLTexture::Linear);
delete image;
return newTexture;
}
QOpenGLTexture * OpenGLTextureFactory::initCubeMap(const char * tile)
{
return initCubeMap(QImage(tile), QImage(tile),
QImage(tile), QImage(tile),
QImage(tile), QImage(tile));
QOpenGLTexture * OpenGLTextureFactory::initCubeMap(const char * tile) {
return initCubeMap(
QImage(tile), QImage(tile), QImage(tile), QImage(tile), QImage(tile),
QImage(tile));
}
QOpenGLTexture * OpenGLTextureFactory::initCubeMap(
const char * right, const char * top,
const char * front, const char * left,
const char * bottom, const char * back)
{
return initCubeMap(QImage(right), QImage(top),
QImage(front), QImage(left),
QImage(bottom), QImage(back));
const char * right, const char * top, const char * front, const char * left,
const char * bottom, const char * back) {
return initCubeMap(
QImage(right), QImage(top), QImage(front), QImage(left), QImage(bottom),
QImage(back));
}
QOpenGLTexture * OpenGLTextureFactory::initCubeMap(
QImage right, QImage top,
QImage front, QImage left,
QImage bottom, QImage back)
{
QImage right, QImage top, QImage front, QImage left, QImage bottom,
QImage back) {
auto texture = new QOpenGLTexture(QOpenGLTexture::TargetCubeMap);
std::vector<QImage> faceTextures = {
right, top, front,
left, bottom, back
};
std::vector<QImage> faceTextures = {std::move(right), std::move(top),
std::move(front), std::move(left),
std::move(bottom), std::move(back)};
// Initialize skybox cubemap texture
texture->create();
texture->bind();
@ -74,8 +68,7 @@ QOpenGLTexture * OpenGLTextureFactory::initCubeMap(
std::vector<QOpenGLTexture::CubeMapFace> faces = {
QOpenGLTexture::CubeMapPositiveX, QOpenGLTexture::CubeMapPositiveY,
QOpenGLTexture::CubeMapPositiveZ, QOpenGLTexture::CubeMapNegativeX,
QOpenGLTexture::CubeMapNegativeY, QOpenGLTexture::CubeMapNegativeZ
};
QOpenGLTexture::CubeMapNegativeY, QOpenGLTexture::CubeMapNegativeZ};
int i = 0;
for(const auto & face : faces) {
QImage faceImage(faceTextures[i]);
@ -87,13 +80,14 @@ QOpenGLTexture * OpenGLTextureFactory::initCubeMap(
// On the first iteration, set format and allocate texture storage
if(face == QOpenGLTexture::CubeMapPositiveX) {
// This also needs to happen on the first iteration, anyways
texture->setSize(faceImage.width(), faceImage.height(), faceImage.depth());
texture->setSize(
faceImage.width(), faceImage.height(), faceImage.depth());
texture->setFormat(QOpenGLTexture::RGBA8_UNorm);
texture->allocateStorage();
}
texture->setData(0, 0, face,
QOpenGLTexture::RGBA, QOpenGLTexture::UInt8,
texture->setData(
0, 0, face, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8,
faceImage.constBits());
i++;
}

View File

@ -19,22 +19,22 @@ namespace Qtk {
~OpenGLTextureFactory() = default;
// QImage
static QImage * initImage(const char * image,
bool flipX=false, bool flipY=false);
static QImage * initImage(
const char * image, bool flipX = false, bool flipY = false);
// 2D Texture
static QOpenGLTexture * initTexture2D(const char * texture,
bool flipX=false, bool flipY=false);
static QOpenGLTexture * initTexture2D(
const char * texture, bool flipX = false, bool flipY = false);
// Cube maps
static QOpenGLTexture * initCubeMap(QImage right, QImage top,
QImage front, QImage left,
QImage bottom, QImage back);
static QOpenGLTexture * initCubeMap(
QImage right, QImage top, QImage front, QImage left, QImage bottom,
QImage back);
// Overloads for cube map initialization
static QOpenGLTexture * initCubeMap(const char * tile);
static QOpenGLTexture * initCubeMap(const char * right, const char * top,
const char * front, const char * left,
const char * bottom, const char * back);
static QOpenGLTexture * initCubeMap(
const char * right, const char * top, const char * front,
const char * left, const char * bottom, const char * back);
private:
// Private ctor to prevent creating instances of this class
@ -45,28 +45,43 @@ class Texture {
public:
Texture() = default;
Texture(const Texture & value) = delete;
// Texture(const Texture & value) {
// mOpenGLTexture = OpenGLTextureFactory::initTexture2D(value.mPath);
// mPath = value.mPath;
// }
explicit Texture(const char * path, bool flipX=false, bool flipY=false) :
mOpenGLTexture(OpenGLTextureFactory::initTexture2D(path, flipX, flipY)),
explicit Texture(
const char * path, bool flipX = false, bool flipY = false) :
mOpenGLTexture(
OpenGLTextureFactory::initTexture2D(path, flipX, flipY)),
mPath(path) {}
// explicit Texture(QOpenGLTexture * texture) : mOpenGLTexture(texture) { }
// explicit Texture(QOpenGLTexture * texture) : mOpenGLTexture(texture) {
// }
~Texture() { mOpenGLTexture->destroy(); }
inline QOpenGLTexture & getOpenGLTexture() { return *mOpenGLTexture;}
void setTexture(const char * path, bool flipX=false, bool flipY=false)
{ mOpenGLTexture = OpenGLTextureFactory::initTexture2D(path, flipX, flipY);}
inline void setTexture(QOpenGLTexture * texture) { mOpenGLTexture = texture;}
inline bool hasTexture() const { return mOpenGLTexture != Q_NULLPTR;}
QOpenGLTexture * mOpenGLTexture = Q_NULLPTR;
const char * mPath;
};
[[nodiscard]] inline QOpenGLTexture & getOpenGLTexture() const {
return *mOpenGLTexture;
}
void setTexture(
const char * path, bool flipX = false, bool flipY = false) {
mOpenGLTexture =
OpenGLTextureFactory::initTexture2D(path, flipX, flipY);
}
inline void setTexture(QOpenGLTexture * texture) {
mOpenGLTexture = texture;
}
[[nodiscard]] inline bool hasTexture() const {
return mOpenGLTexture != Q_NULLPTR;
}
QOpenGLTexture * mOpenGLTexture = Q_NULLPTR;
const char * mPath {};
};
} // namespace Qtk
#endif // QTOPENGL_TEXTURE_H

View File

@ -19,64 +19,53 @@ const QVector3D Transform3D::LocalRight(1.0f, 0.0f, 0.0f);
* Transformations
******************************************************************************/
void Transform3D::translate(const QVector3D & dt)
{
void Transform3D::translate(const QVector3D & dt) {
m_dirty = true;
mTranslation += dt;
}
void Transform3D::scale(const QVector3D & ds)
{
void Transform3D::scale(const QVector3D & ds) {
m_dirty = true;
mScale *= ds;
}
void Transform3D::rotate(const QQuaternion & dr)
{
void Transform3D::rotate(const QQuaternion & dr) {
m_dirty = true;
mRotation = dr * mRotation;
}
void Transform3D::grow(const QVector3D & ds)
{
void Transform3D::grow(const QVector3D & ds) {
m_dirty = true;
mScale += ds;
}
/*******************************************************************************
* Setters
******************************************************************************/
void Transform3D::setTranslation(const QVector3D & t)
{
void Transform3D::setTranslation(const QVector3D & t) {
m_dirty = true;
mTranslation = t;
}
void Transform3D::setScale(const QVector3D & s)
{
void Transform3D::setScale(const QVector3D & s) {
m_dirty = true;
mScale = s;
}
void Transform3D::setRotation(const QQuaternion & r)
{
void Transform3D::setRotation(const QQuaternion & r) {
m_dirty = true;
mRotation = r;
}
/*******************************************************************************
* Accessors
******************************************************************************/
// Produces modelToWorld matrix using current set of transformations
// Transformation * rotation * scale = modelToWorld
const QMatrix4x4 & Transform3D::toMatrix()
{
if (m_dirty)
{
const QMatrix4x4 & Transform3D::toMatrix() {
if(m_dirty) {
m_dirty = false;
mWorld.setToIdentity();
mWorld.translate(mTranslation);
@ -86,66 +75,63 @@ const QMatrix4x4 & Transform3D::toMatrix()
return mWorld;
}
/*******************************************************************************
* Queries
******************************************************************************/
QVector3D Transform3D::getForward() const
{
QVector3D Transform3D::getForward() const {
return mRotation.rotatedVector(LocalForward);
}
QVector3D Transform3D::getUp() const
{
QVector3D Transform3D::getUp() const {
return mRotation.rotatedVector(LocalUp);
}
QVector3D Transform3D::getRight() const
{
QVector3D Transform3D::getRight() const {
return mRotation.rotatedVector(LocalRight);
while(true) {
int xx;
};
}
/*******************************************************************************
* QT Streams
******************************************************************************/
namespace Qtk {
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const Transform3D & transform)
{
QDebug operator<<(QDebug dbg, const Transform3D & transform) {
dbg << "Transform3D\n{\n";
dbg << "Position: <" << transform.getTranslation().x() << ", "
<< transform.getTranslation().y() << ", "
<< transform.getTranslation().z() << ">\n";
dbg << "Scale: <" << transform.getScale().x() << ", "
<< transform.getScale().y() << ", "
<< transform.getScale().z() << ">\n";
<< transform.getScale().y() << ", " << transform.getScale().z()
<< ">\n";
dbg << "Rotation: <" << transform.getRotation().x() << ", "
<< transform.getRotation().y() << ", "
<< transform.getRotation().z() << " | " <<
transform.getRotation().scalar() << ">\n}";
<< transform.getRotation().y() << ", " << transform.getRotation().z()
<< " | " << transform.getRotation().scalar() << ">\n}";
return dbg;
}
#endif
#ifndef QT_NO_DATASTREAM
QDataStream & operator<<(QDataStream & out, const Transform3D & transform)
{
QDataStream & operator<<(QDataStream & out, const Transform3D & transform) {
out << transform.mTranslation;
out << transform.mScale;
out << transform.mRotation;
return out;
}
QDataStream & operator>>(QDataStream & in, Transform3D & transform)
{
QDataStream & operator>>(QDataStream & in, Transform3D & transform) {
in >> transform.mTranslation;
in >> transform.mScale;
in >> transform.mRotation;
transform.m_dirty = true;
return in;
}
#endif
}
} // namespace Qtk

View File

@ -15,81 +15,111 @@
#include <QVector3D>
#ifndef QT_NO_DEBUG_STREAM
#include <QDebug>
#endif
#include <qtkapi.h>
namespace Qtk {
class QTKAPI Transform3D
{
class QTKAPI Transform3D {
public:
// Constructors
inline Transform3D() : m_dirty(true),
mScale(1.0f, 1.0f, 1.0f),
inline Transform3D() :
m_dirty(true), mScale(1.0f, 1.0f, 1.0f),
mTranslation(0.0f, 0.0f, 0.0f) {}
//
// Transformations
void translate(const QVector3D & dt);
inline void translate(float dx, float dy, float dz)
{ translate(QVector3D(dx, dy, dz));}
inline void translate(float dx, float dy, float dz) {
translate(QVector3D(dx, dy, dz));
}
// Scale object with multiplication
void scale(const QVector3D & ds);
inline void scale(float dx, float dy, float dz)
{ scale(QVector3D(dx, dy, dz));}
inline void scale(float factor)
{ scale(QVector3D(factor, factor, factor));}
inline void scale(float dx, float dy, float dz) {
scale(QVector3D(dx, dy, dz));
}
inline void scale(float factor) {
scale(QVector3D(factor, factor, factor));
}
// Multiplying by a rotation
void rotate(const QQuaternion & dr);
inline void rotate(float angle, const QVector3D & axis)
{ rotate(QQuaternion::fromAxisAndAngle(axis, angle));}
inline void rotate(float angle, float ax, float ay, float az)
{ rotate(QQuaternion::fromAxisAndAngle(ax, ay, az, angle));}
inline void rotate(float angle, const QVector3D & axis) {
rotate(QQuaternion::fromAxisAndAngle(axis, angle));
}
inline void rotate(float angle, float ax, float ay, float az) {
rotate(QQuaternion::fromAxisAndAngle(ax, ay, az, angle));
}
// Scale object by addition
void grow(const QVector3D & ds);
inline void grow(float dx, float dy, float dz)
{ grow(QVector3D(dx, dy, dz));}
inline void grow(float factor)
{ grow(QVector3D(factor, factor, factor));}
inline void grow(float dx, float dy, float dz) {
grow(QVector3D(dx, dy, dz));
}
inline void grow(float factor) {
grow(QVector3D(factor, factor, factor));
}
//
// Setters
// Set object position
void setTranslation(const QVector3D & t);
inline void setTranslation(float x, float y, float z)
{ setTranslation(QVector3D(x, y, z));}
inline void setTranslation(float x, float y, float z) {
setTranslation(QVector3D(x, y, z));
}
// Set object scale
void setScale(const QVector3D & s);
inline void setScale(float x, float y, float z)
{ setScale(QVector3D(x, y, z));}
inline void setScale(float k)
{ setScale(QVector3D(k, k, k));}
inline void setScale(float x, float y, float z) {
setScale(QVector3D(x, y, z));
}
inline void setScale(float k) { setScale(QVector3D(k, k, k)); }
// Set object rotation
void setRotation(const QQuaternion & r);
inline void setRotation(float angle, const QVector3D & axis)
{ setRotation(QQuaternion::fromAxisAndAngle(axis, angle));}
inline void setRotation(float angle, float ax, float ay, float az)
{ setRotation(QQuaternion::fromAxisAndAngle(ax, ay, az, angle));}
inline void setRotation(float angle, const QVector3D & axis) {
setRotation(QQuaternion::fromAxisAndAngle(axis, angle));
}
inline void setRotation(float angle, float ax, float ay, float az) {
setRotation(QQuaternion::fromAxisAndAngle(ax, ay, az, angle));
}
//
// Accessors
inline const QVector3D & getTranslation() const { return mTranslation;}
inline const QVector3D & getScale() const { return mScale; }
inline const QQuaternion & getRotation() const { return mRotation; }
[[nodiscard]] inline const QVector3D & getTranslation() const {
return mTranslation;
}
[[nodiscard]] inline const QVector3D & getScale() const { return mScale; }
[[nodiscard]] inline const QQuaternion & getRotation() const {
return mRotation;
}
const QMatrix4x4 & toMatrix();
QVector3D getForward() const;
QVector3D getUp() const;
QVector3D getRight() const;
[[nodiscard]] QVector3D getForward() const;
[[nodiscard]] QVector3D getUp() const;
[[nodiscard]] QVector3D getRight() const;
static const QVector3D LocalForward, LocalUp, LocalRight;
@ -101,14 +131,14 @@ namespace Qtk {
bool m_dirty;
#ifndef QT_NO_DATASTREAM
friend QDataStream &operator<<(QDataStream & out, const Transform3D & transform);
friend QDataStream &operator>>(QDataStream & in, Transform3D & transform);
friend QDataStream & operator<<(
QDataStream & out, const Transform3D & transform);
friend QDataStream & operator>>(
QDataStream & in, Transform3D & transform);
#endif
};
// Qt Streams
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const Transform3D & transform);
@ -118,7 +148,7 @@ namespace Qtk {
QDataStream & operator<<(QDataStream & out, const Transform3D & transform);
QDataStream & operator>>(QDataStream & in, Transform3D & transform);
#endif
}
} // namespace Qtk
Q_DECLARE_TYPEINFO(Qtk::Transform3D, Q_MOVABLE_TYPE);