Refactor texture handling
This commit is contained in:
parent
0f372f71f4
commit
443c09da7c
|
@ -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
|
||||
...
|
|
@ -0,0 +1,146 @@
|
|||
# Generated from CLion Inspection settings
|
||||
---
|
||||
HeaderFilterRegex: "*.h"
|
||||
UseColor: true
|
||||
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-pro-type-member-init,
|
||||
cppcoreguidelines-pro-type-static-cast-downcast,
|
||||
cppcoreguidelines-slicing,
|
||||
google-explicit-constructor,
|
||||
google-runtime-operator,
|
||||
hicpp-exception-baseclass,
|
||||
hicpp-multiway-paths-covered,
|
||||
misc-misplaced-const,
|
||||
misc-new-delete-overloads,
|
||||
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-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'
|
|
@ -1,4 +1,4 @@
|
|||
name: Build Test
|
||||
name: All Builds
|
||||
|
||||
on:
|
||||
push:
|
||||
|
@ -32,7 +32,7 @@ jobs:
|
|||
if: matrix.os == 'windows-latest'
|
||||
uses: crazy-max/ghaction-chocolatey@v2.0.0
|
||||
with:
|
||||
args: install pkgconfiglite
|
||||
args: install pkgconfiglite --checksum e87b5ea3c9142256af60f2d5b917aa63b571e6a0 --checksum-type sha1
|
||||
|
||||
- name: Build Qtk
|
||||
shell: bash
|
|
@ -0,0 +1,67 @@
|
|||
name: Linting
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
Tidy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Install Qt
|
||||
uses: jurplel/install-qt-action@v2
|
||||
with:
|
||||
version: '6.3.1'
|
||||
|
||||
- name: Install Assimp Ubuntu
|
||||
run: sudo apt install libassimp-dev
|
||||
|
||||
- name: Build Qtk
|
||||
run: |
|
||||
cmake -B build -DQTK_UPDATE_SUBMODULES=OFF && cmake --build build
|
||||
|
||||
- uses: cpp-linter/cpp-linter-action@v2
|
||||
id: linter
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
# Use clang-tools 14
|
||||
version: '14'
|
||||
# Don't use clang-format with this action
|
||||
# + Set to `file` to use .clang-format (Qtk formats with clang 15)
|
||||
style: ''
|
||||
# Use .clang-tidy file
|
||||
tidy-checks: ''
|
||||
# Check the entire repo for source files to tidy
|
||||
files-changed-only: false
|
||||
# Ignore qtk build and external assimp directories
|
||||
ignore: '.github|build|extern/assimp/assimp'
|
||||
# Point to compile_commands.json produced by build
|
||||
database: 'build'
|
||||
# Use thread comments as feedback
|
||||
thread-comments: true
|
||||
# Show file annotations on GH
|
||||
file-annotations: true
|
||||
|
||||
- name: Fail CI if checks don't pass
|
||||
if: steps.linter.outputs.checks-failed != 0
|
||||
run: exit 1
|
||||
|
||||
Format:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
path:
|
||||
- 'src'
|
||||
- 'app'
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: clang-format Check
|
||||
uses: jidicula/clang-format-action@v4.9.0
|
||||
with:
|
||||
clang-format-version: '15'
|
||||
check-path: ${{ matrix.path }}
|
|
@ -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)
|
||||
|
|
66
README.md
66
README.md
|
@ -1,4 +1,6 @@
|
|||
# Qtk
|
||||
[![All Builds](https://github.com/shaunrd0/qtk/actions/workflows/all-builds.yml/badge.svg)](https://github.com/shaunrd0/qtk/actions/workflows/all-builds.yml)
|
||||
[![Linting](https://github.com/shaunrd0/qtk/actions/workflows/linting.yml/badge.svg)](https://github.com/shaunrd0/qtk/actions/workflows/linting.yml)
|
||||
|
||||
Practice project for learning about using OpenGL in Qt widget applications.
|
||||
Model loader using [Assimp](https://assimp.org/) within a Qt widget application.
|
||||
|
@ -20,9 +22,11 @@ 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 freeglut3-dev libassimp-dev cmake build-essential git
|
||||
sudo apt update -y && sudo apt install libassimp-dev cmake build-essential git
|
||||
git clone https://gitlab.com/shaunrd0/qtk
|
||||
cmake -DCMAKE_PREFIX_PATH=$HOME/Qt/6.3.1/gcc_64 -S qtk/ -B qtk/build/ && cmake --build qtk/build/ -j $(nproc --ignore=2) --target qtk-main
|
||||
./qtk/build/qtk-main
|
||||
|
@ -42,12 +46,72 @@ 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`.
|
||||
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
|
||||
```
|
||||
|
||||
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
|
||||
clang-tidy -p build/ --fix --config-file=.clang-tidy src/*.cpp src/*.h app/*.cpp app/*.h
|
||||
```
|
||||
|
||||
Last we need to run `clang-format`, this can be done with the command directly.
|
||||
This will reformat all the code in the repository.
|
||||
|
||||
```bash
|
||||
clang-format -i --style=file:.clang-format src/*.cpp src/*.h app/*.cpp app/*.h
|
||||
```
|
||||
|
||||
`clang-format` can be run with git integration (or CLion if you prefer).
|
||||
Git will only reformat the lines you modified, which can be useful.
|
||||
|
||||
```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.
|
||||
|
|
|
@ -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,138 +20,87 @@ 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
|
||||
mTestPhong = new Qtk::MeshRenderer("phong", Qtk::Cube());
|
||||
mTestPhong->mTransform.setTranslation(3.0f, 0.0f, -2.0f);
|
||||
mTestPhong->setShaders(":/solid-phong.vert", ":/solid-phong.frag");
|
||||
mTestPhong->init();
|
||||
mTestPhong->mProgram.bind();
|
||||
|
||||
// You no longer need to manually bind shader program.
|
||||
// + But, you can still bind it if you want to.
|
||||
// mTestPhong->bindShaders();
|
||||
mTestPhong->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f));
|
||||
mTestPhong->setUniform("uLightColor", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
mTestPhong->setUniform("uAmbientStrength", 0.2f);
|
||||
mTestPhong->setUniform("uSpecularStrength", 0.50f);
|
||||
mTestPhong->setUniform("uSpecularShine", 256);
|
||||
|
||||
mTestPhong->mVAO.bind();
|
||||
mTestPhong->mNBO.create();
|
||||
mTestPhong->mNBO.setUsagePattern(QOpenGLBuffer::StaticDraw);
|
||||
mTestPhong->mNBO.bind();
|
||||
mTestPhong->mNBO.allocate(mTestPhong->normals().data(),
|
||||
mTestPhong->normals().size()
|
||||
* sizeof(mTestPhong->normals()[0]));
|
||||
mTestPhong->mProgram.enableAttributeArray(1);
|
||||
mTestPhong->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
|
||||
3, sizeof(QVector3D));
|
||||
mTestPhong->mNBO.release();
|
||||
mTestPhong->mVAO.release();
|
||||
mTestPhong->mProgram.release();
|
||||
|
||||
mTestPhong->reallocateNormals(mTestPhong->getNormals());
|
||||
// mTestPhong->releaseShaders();
|
||||
|
||||
// Initialize Ambient example cube
|
||||
mTestAmbient = new Qtk::MeshRenderer("ambient", Cube());
|
||||
mTestAmbient->mTransform.setTranslation(7.0f, 0.0f, -2.0f);
|
||||
mTestAmbient->setShaders(":/solid-ambient.vert", ":/solid-ambient.frag");
|
||||
mTestAmbient->init();
|
||||
mTestAmbient->mProgram.bind();
|
||||
mTestAmbient->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f));
|
||||
mTestAmbient->setUniform("uLightColor", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
mTestAmbient->setUniform("uAmbientStrength", 0.2f);
|
||||
|
||||
mTestAmbient->mVAO.bind();
|
||||
mTestAmbient->mNBO.create();
|
||||
mTestAmbient->mNBO.setUsagePattern(QOpenGLBuffer::StaticDraw);
|
||||
mTestAmbient->mNBO.bind();
|
||||
mTestAmbient->mNBO.allocate(mTestAmbient->normals().data(),
|
||||
mTestAmbient->normals().size()
|
||||
* sizeof(mTestAmbient->normals()[0]));
|
||||
mTestAmbient->mProgram.enableAttributeArray(1);
|
||||
mTestAmbient->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
|
||||
3, sizeof(QVector3D));
|
||||
mTestAmbient->mNBO.release();
|
||||
mTestAmbient->mVAO.release();
|
||||
mTestAmbient->mProgram.release();
|
||||
mTestAmbient->reallocateNormals(mTestAmbient->getNormals());
|
||||
|
||||
// Initialize Diffuse example cube
|
||||
mTestDiffuse = new Qtk::MeshRenderer("diffuse", Cube());
|
||||
mTestDiffuse->mTransform.setTranslation(9.0f, 0.0f, -2.0f);
|
||||
mTestDiffuse->setShaders(":/solid-diffuse.vert", ":/solid-diffuse.frag");
|
||||
mTestDiffuse->init();
|
||||
mTestDiffuse->mProgram.bind();
|
||||
mTestDiffuse->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f));
|
||||
mTestDiffuse->setUniform("uLightColor", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
mTestDiffuse->setUniform("uAmbientStrength", 0.2f);
|
||||
|
||||
mTestDiffuse->mVAO.bind();
|
||||
mTestDiffuse->mNBO.create();
|
||||
mTestDiffuse->mNBO.setUsagePattern(QOpenGLBuffer::StaticDraw);
|
||||
mTestDiffuse->mNBO.bind();
|
||||
mTestDiffuse->mNBO.allocate(mTestDiffuse->normals().data(),
|
||||
mTestDiffuse->normals().size()
|
||||
* sizeof(mTestDiffuse->normals()[0]));
|
||||
mTestDiffuse->mProgram.enableAttributeArray(1);
|
||||
mTestDiffuse->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
|
||||
3, sizeof(QVector3D));
|
||||
mTestDiffuse->mNBO.release();
|
||||
mTestDiffuse->mVAO.release();
|
||||
mTestDiffuse->mProgram.release();
|
||||
mTestDiffuse->reallocateNormals(mTestDiffuse->getNormals());
|
||||
|
||||
// Initialize Specular example cube
|
||||
mTestSpecular = new Qtk::MeshRenderer("specular", Cube());
|
||||
mTestSpecular->mTransform.setTranslation(11.0f, 0.0f, -2.0f);
|
||||
mTestSpecular->setShaders(":/solid-specular.vert", ":/solid-specular.frag");
|
||||
mTestSpecular->init();
|
||||
mTestSpecular->mProgram.bind();
|
||||
mTestSpecular->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f));
|
||||
mTestSpecular->setUniform("uLightColor", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
mTestSpecular->setUniform("uAmbientStrength", 0.2f);
|
||||
mTestSpecular->setUniform("uSpecularStrength", 0.50f);
|
||||
mTestSpecular->setUniform("uSpecularShine", 256);
|
||||
mTestSpecular->reallocateNormals(mTestSpecular->getNormals());
|
||||
|
||||
mTestSpecular->mVAO.bind();
|
||||
mTestSpecular->mNBO.create();
|
||||
mTestSpecular->mNBO.setUsagePattern(QOpenGLBuffer::StaticDraw);
|
||||
mTestSpecular->mNBO.bind();
|
||||
mTestSpecular->mNBO.allocate(mTestSpecular->normals().data(),
|
||||
mTestSpecular->normals().size()
|
||||
* sizeof(mTestSpecular->normals()[0]));
|
||||
mTestSpecular->mProgram.enableAttributeArray(1);
|
||||
mTestSpecular->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
|
||||
3, sizeof(QVector3D));
|
||||
mTestSpecular->mNBO.release();
|
||||
mTestSpecular->mVAO.release();
|
||||
mTestSpecular->mProgram.release();
|
||||
|
||||
//
|
||||
// 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);
|
||||
|
@ -166,7 +115,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);
|
||||
|
||||
|
@ -175,27 +125,25 @@ 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));
|
||||
|
@ -210,21 +158,17 @@ 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));
|
||||
|
@ -238,7 +182,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)));
|
||||
|
@ -247,33 +190,15 @@ void ExampleScene::init()
|
|||
mMeshes.back()->setDrawType(GL_LINE_LOOP);
|
||||
// This function changes values we have allocated in a buffer, so init() after
|
||||
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));
|
||||
mMeshes.back()->init();
|
||||
mMeshes.back()->mProgram.bind();
|
||||
|
||||
mMeshes.back()->mVAO.bind();
|
||||
mMeshes.back()->mNBO.create();
|
||||
mMeshes.back()->mNBO.bind();
|
||||
|
||||
mMeshes.back()->mNBO.allocate(mMeshes.back()->normals().data(),
|
||||
mMeshes.back()->normals().size()
|
||||
* sizeof(mMeshes.back()->normals()[0]));
|
||||
mMeshes.back()->mProgram.enableAttributeArray(1);
|
||||
mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
|
||||
3, sizeof(QVector3D));
|
||||
|
||||
mMeshes.back()->mNBO.release();
|
||||
mMeshes.back()->mVAO.release();
|
||||
mMeshes.back()->reallocateNormals(mMeshes.back()->getNormals());
|
||||
|
||||
mMeshes.back()->setUniform("uMaterial.ambient", QVector3D(0.0f, 0.3f, 0.0f));
|
||||
mMeshes.back()->setUniform("uMaterial.diffuse", QVector3D(0.0f, 0.2f, 0.0f));
|
||||
|
||||
mMeshes.back()->setUniform("uMaterial.specular", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
mMeshes.back()->setUniform("uMaterial.ambientStrength", 1.0f);
|
||||
mMeshes.back()->setUniform("uMaterial.diffuseStrength", 1.0f);
|
||||
|
@ -284,7 +209,6 @@ void ExampleScene::init()
|
|||
mMeshes.back()->setUniform("uLight.specular", QVector3D(0.62f, 0.55f, 0.37f));
|
||||
mMeshes.back()->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f));
|
||||
|
||||
mMeshes.back()->mProgram.release();
|
||||
|
||||
//
|
||||
// Create simple shapes using MeshRenderer class and data in mesh.h
|
||||
|
@ -314,7 +238,6 @@ void ExampleScene::init()
|
|||
mMeshes.back()->setDrawType(GL_LINE_LOOP);
|
||||
// This function changes values we have allocated in a buffer, so init() after
|
||||
mMeshes.back()->setColor(GREEN);
|
||||
mMeshes.back()->init();
|
||||
|
||||
//
|
||||
// Testing for normals, texture coordinates
|
||||
|
@ -324,99 +247,50 @@ void ExampleScene::init()
|
|||
new Qtk::MeshRenderer("rgbNormalsCubeArraysTest", Cube(QTK_DRAW_ARRAYS)));
|
||||
mMeshes.back()->mTransform.setTranslation(5.0f, 0.0f, 4.0f);
|
||||
mMeshes.back()->setShaders(":/rgb-normals.vert", ":/rgb-normals.frag");
|
||||
mMeshes.back()->init();
|
||||
mMeshes.back()->mVAO.bind();
|
||||
mMeshes.back()->mNBO.create();
|
||||
mMeshes.back()->mNBO.bind();
|
||||
mMeshes.back()->mProgram.bind();
|
||||
|
||||
mMeshes.back()->mNBO.allocate(mMeshes.back()->normals().data(),
|
||||
mMeshes.back()->normals().size()
|
||||
* sizeof(mMeshes.back()->normals()[0]));
|
||||
mMeshes.back()->mProgram.enableAttributeArray(1);
|
||||
mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
|
||||
3, sizeof(QVector3D));
|
||||
|
||||
mMeshes.back()->mProgram.release();
|
||||
mMeshes.back()->mNBO.release();
|
||||
mMeshes.back()->mVAO.release();
|
||||
mMeshes.back()->reallocateNormals(mMeshes.back()->getNormals());
|
||||
|
||||
// RGB Normals cube to show normals are correct with QTK_DRAW_ELEMENTS_NORMALS
|
||||
mMeshes.push_back(
|
||||
new Qtk::MeshRenderer("rgbNormalsCubeElementsTest", Cube(QTK_DRAW_ELEMENTS_NORMALS)));
|
||||
mMeshes.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();
|
||||
mMeshes.back()->mVAO.bind();
|
||||
mMeshes.back()->mNBO.create();
|
||||
mMeshes.back()->mNBO.bind();
|
||||
mMeshes.back()->mProgram.bind();
|
||||
mMeshes.back()->reallocateNormals(mMeshes.back()->getNormals());
|
||||
|
||||
mMeshes.back()->mNBO.allocate(mMeshes.back()->normals().data(),
|
||||
mMeshes.back()->normals().size()
|
||||
* sizeof(mMeshes.back()->normals()[0]));
|
||||
mMeshes.back()->mProgram.enableAttributeArray(1);
|
||||
mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
|
||||
3, sizeof(QVector3D));
|
||||
|
||||
mMeshes.back()->mProgram.release();
|
||||
mMeshes.back()->mNBO.release();
|
||||
mMeshes.back()->mVAO.release();
|
||||
Texture crateTexture;
|
||||
crateTexture.setTexture(":/crate.png");
|
||||
Cube cube;
|
||||
auto * m = new MeshRenderer("Test Crate", Cube(QTK_DRAW_ARRAYS));
|
||||
m->mTransform.setTranslation(0, 0, 13);
|
||||
m->setShaders(":/texture2d.vert", ":/texture2d.frag");
|
||||
m->setTexture(crateTexture);
|
||||
m->setUniform("uTexture", 0);
|
||||
m->reallocateTexCoords(cube.getTexCoords());
|
||||
mMeshes.push_back(m);
|
||||
|
||||
// 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(
|
||||
new Qtk::MeshRenderer("uvCubeArraysTest", Cube(QTK_DRAW_ARRAYS)));
|
||||
mMeshes.back()->mTransform.setTranslation(-3.0f, 0.0f, -2.0f);
|
||||
mMeshes.back()->setShaders(":/texture2d.vert", ":/texture2d.frag");
|
||||
mMeshes.back()->init();
|
||||
mMeshes.back()->mProgram.bind();
|
||||
|
||||
mMeshes.back()->setTexture(Texture::initTexture2D(":/crate.png"));
|
||||
mMeshes.back()->setTexture(crateTexture);
|
||||
mMeshes.back()->setUniform("uTexture", 0);
|
||||
mMeshes.back()->texture().bind();
|
||||
|
||||
mMeshes.back()->texture().release();
|
||||
|
||||
mMeshes.back()->mVAO.bind();
|
||||
mMeshes.back()->mNBO.destroy();
|
||||
mMeshes.back()->mNBO.create();
|
||||
mMeshes.back()->mNBO.bind();
|
||||
mMeshes.back()->mNBO.allocate(mMeshes.back()->mShape.texCoords().data(),
|
||||
mMeshes.back()->mShape.texCoords().size()
|
||||
* sizeof(mMeshes.back()->mShape.texCoords()[0]));
|
||||
mMeshes.back()->mProgram.enableAttributeArray(1);
|
||||
mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
|
||||
2, sizeof(QVector2D));
|
||||
mMeshes.back()->mNBO.release();
|
||||
mMeshes.back()->mVAO.release();
|
||||
mMeshes.back()->mProgram.release();
|
||||
mMeshes.back()->reallocateTexCoords(mMeshes.back()->getTexCoords());
|
||||
|
||||
// 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()->setTexture(":/crate.png");
|
||||
mMeshes.back()->setShaders(":/texture2d.vert", ":/texture2d.frag");
|
||||
mMeshes.back()->init();
|
||||
mMeshes.back()->mVAO.bind();
|
||||
mMeshes.back()->mNBO.create();
|
||||
mMeshes.back()->mNBO.bind();
|
||||
mMeshes.back()->mProgram.bind();
|
||||
|
||||
mMeshes.back()->mNBO.allocate(mMeshes.back()->texCoords().data(),
|
||||
mMeshes.back()->texCoords().size()
|
||||
* sizeof(mMeshes.back()->texCoords()[0]));
|
||||
mMeshes.back()->mProgram.enableAttributeArray(1);
|
||||
mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
|
||||
3, sizeof(QVector3D));
|
||||
mMeshes.back()->setTexture(Texture::initTexture2D(":/crate.png"));
|
||||
|
||||
mMeshes.back()->mProgram.setUniformValue("uTexture", 0);
|
||||
mMeshes.back()->mProgram.release();
|
||||
mMeshes.back()->mNBO.release();
|
||||
mMeshes.back()->mVAO.release();
|
||||
mMeshes.back()->bindShaders();
|
||||
mMeshes.back()->setUniform("uTexture", 0);
|
||||
mMeshes.back()->reallocateNormals(mMeshes.back()->getNormals());
|
||||
mMeshes.back()->reallocateTexCoords(mMeshes.back()->getTexCoords(), 3);
|
||||
mMeshes.back()->releaseShaders();
|
||||
mMeshes.back()->mTransform.rotate(45.0f, 0.0f, 1.0f, 0.0f);
|
||||
|
||||
// Texturing a cube using a cube map
|
||||
|
@ -425,26 +299,11 @@ 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()->init();
|
||||
mMeshes.back()->mProgram.bind();
|
||||
|
||||
mMeshes.back()->setTexture(Texture::initCubeMap(":/crate.png"));
|
||||
mMeshes.back()->setShaders(
|
||||
":/texture-cubemap.vert", ":/texture-cubemap.frag");
|
||||
mMeshes.back()->setCubeMap(":/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.texCoords().data(),
|
||||
mMeshes.back()->mShape.texCoords().size()
|
||||
* sizeof(mMeshes.back()->mShape.texCoords()[0]));
|
||||
mMeshes.back()->mProgram.enableAttributeArray(1);
|
||||
mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
|
||||
2, sizeof(QVector2D));
|
||||
mMeshes.back()->mNBO.release();
|
||||
mMeshes.back()->mVAO.release();
|
||||
mMeshes.back()->mProgram.release();
|
||||
mMeshes.back()->reallocateTexCoords(mMeshes.back()->getTexCoords());
|
||||
|
||||
// Create a cube with custom shaders
|
||||
// + Apply RGB normals shader and spin the cube for a neat effect
|
||||
|
@ -452,136 +311,50 @@ void ExampleScene::init()
|
|||
new Qtk::MeshRenderer("rgbNormalsCube", Cube(QTK_DRAW_ARRAYS)));
|
||||
mMeshes.back()->mTransform.setTranslation(5.0f, 2.0f, -2.0f);
|
||||
mMeshes.back()->setShaders(":/rgb-normals.vert", ":/rgb-normals.frag");
|
||||
mMeshes.back()->init();
|
||||
mMeshes.back()->mVAO.bind();
|
||||
mMeshes.back()->mNBO.create();
|
||||
mMeshes.back()->mNBO.bind();
|
||||
mMeshes.back()->mProgram.bind();
|
||||
|
||||
mMeshes.back()->mNBO.allocate(mMeshes.back()->normals().data(),
|
||||
mMeshes.back()->normals().size()
|
||||
* sizeof(mMeshes.back()->normals()[0]));
|
||||
mMeshes.back()->mProgram.enableAttributeArray(1);
|
||||
mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
|
||||
3, sizeof(QVector3D));
|
||||
|
||||
mMeshes.back()->mProgram.release();
|
||||
mMeshes.back()->mNBO.release();
|
||||
mMeshes.back()->mVAO.release();
|
||||
mMeshes.back()->reallocateNormals(mMeshes.back()->getNormals());
|
||||
|
||||
// RGB Normals triangle to show normals are correct with QTK_DRAW_ARRAYS
|
||||
mMeshes.push_back(
|
||||
new Qtk::MeshRenderer("rgbTriangleArraysTest", Triangle(QTK_DRAW_ARRAYS)));
|
||||
mMeshes.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();
|
||||
mMeshes.back()->mProgram.bind();
|
||||
|
||||
mMeshes.back()->mVAO.bind();
|
||||
mMeshes.back()->mNBO.create();
|
||||
mMeshes.back()->mNBO.bind();
|
||||
mMeshes.back()->mNBO.allocate(mMeshes.back()->normals().data(),
|
||||
mMeshes.back()->normals().size()
|
||||
* sizeof(mMeshes.back()->normals()[0]));
|
||||
mMeshes.back()->mProgram.enableAttributeArray(1);
|
||||
mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
|
||||
3, sizeof(QVector3D));
|
||||
mMeshes.back()->mNBO.release();
|
||||
mMeshes.back()->mVAO.release();
|
||||
mMeshes.back()->mProgram.release();
|
||||
mMeshes.back()->reallocateNormals(mMeshes.back()->getNormals());
|
||||
|
||||
// RGB Normals triangle to show normals are correct with QTK_DRAW_ELEMENTS
|
||||
mMeshes.push_back(
|
||||
new Qtk::MeshRenderer("rgbTriangleElementsTest",
|
||||
Triangle(QTK_DRAW_ELEMENTS_NORMALS)));
|
||||
mMeshes.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();
|
||||
mMeshes.back()->mProgram.bind();
|
||||
|
||||
mMeshes.back()->mVAO.bind();
|
||||
mMeshes.back()->mNBO.create();
|
||||
mMeshes.back()->mNBO.bind();
|
||||
mMeshes.back()->mNBO.allocate(mMeshes.back()->normals().data(),
|
||||
mMeshes.back()->normals().size()
|
||||
* sizeof(mMeshes.back()->normals()[0]));
|
||||
mMeshes.back()->mProgram.enableAttributeArray(1);
|
||||
mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
|
||||
3, sizeof(QVector3D));
|
||||
mMeshes.back()->mNBO.release();
|
||||
mMeshes.back()->mVAO.release();
|
||||
mMeshes.back()->mProgram.release();
|
||||
mMeshes.back()->reallocateNormals(mMeshes.back()->getNormals());
|
||||
|
||||
// Test drawing triangle with glDrawArrays with texture coordinates
|
||||
mMeshes.push_back(
|
||||
new Qtk::MeshRenderer("testTriangleArraysUV", Triangle(QTK_DRAW_ARRAYS)));
|
||||
mMeshes.back()->mTransform.setTranslation(-3.0f, 2.0f, -2.0f);
|
||||
mMeshes.back()->setShaders(":/texture2d.vert", ":/texture2d.frag");
|
||||
mMeshes.back()->init();
|
||||
mMeshes.back()->mProgram.bind();
|
||||
|
||||
mMeshes.back()->setTexture(Texture::initTexture2D(":/crate.png"));
|
||||
mMeshes.back()->setTexture(":/crate.png");
|
||||
mMeshes.back()->setUniform("uTexture", 0);
|
||||
mMeshes.back()->texture().bind();
|
||||
|
||||
mMeshes.back()->texture().release();
|
||||
|
||||
mMeshes.back()->mVAO.bind();
|
||||
mMeshes.back()->mNBO.destroy();
|
||||
mMeshes.back()->mNBO.create();
|
||||
mMeshes.back()->mNBO.bind();
|
||||
mMeshes.back()->mNBO.allocate(mMeshes.back()->mShape.texCoords().data(),
|
||||
mMeshes.back()->mShape.texCoords().size()
|
||||
* sizeof(mMeshes.back()->mShape.texCoords()[0]));
|
||||
mMeshes.back()->mProgram.enableAttributeArray(1);
|
||||
mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
|
||||
2, sizeof(QVector2D));
|
||||
mMeshes.back()->mNBO.release();
|
||||
mMeshes.back()->mVAO.release();
|
||||
mMeshes.back()->mProgram.release();
|
||||
mMeshes.back()->reallocateTexCoords(mMeshes.back()->getTexCoords());
|
||||
|
||||
// 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();
|
||||
mMeshes.back()->mProgram.bind();
|
||||
|
||||
mMeshes.back()->setTexture(Texture::initTexture2D(":/crate.png"));
|
||||
mMeshes.back()->setTexture(":/crate.png");
|
||||
mMeshes.back()->setUniform("uTexture", 0);
|
||||
mMeshes.back()->texture().bind();
|
||||
|
||||
mMeshes.back()->texture().release();
|
||||
|
||||
mMeshes.back()->mVAO.bind();
|
||||
mMeshes.back()->mNBO.destroy();
|
||||
mMeshes.back()->mNBO.create();
|
||||
mMeshes.back()->mNBO.bind();
|
||||
mMeshes.back()->mNBO.allocate(mMeshes.back()->mShape.texCoords().data(),
|
||||
mMeshes.back()->mShape.texCoords().size()
|
||||
* sizeof(mMeshes.back()->mShape.texCoords()[0]));
|
||||
mMeshes.back()->mProgram.enableAttributeArray(1);
|
||||
mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
|
||||
2, sizeof(QVector2D));
|
||||
mMeshes.back()->mNBO.release();
|
||||
mMeshes.back()->mVAO.release();
|
||||
mMeshes.back()->mProgram.release();
|
||||
mMeshes.back()->reallocateTexCoords(mMeshes.back()->getTexCoords());
|
||||
|
||||
//
|
||||
// Lighting cube examples
|
||||
|
||||
// Example of a cube with no lighting applied
|
||||
mMeshes.push_back(
|
||||
new Qtk::MeshRenderer("noLight", Cube(QTK_DRAW_ELEMENTS)));
|
||||
mMeshes.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()->init();
|
||||
mMeshes.back()->mProgram.bind();
|
||||
mMeshes.back()->setShaders(
|
||||
":/solid-perspective.vert", ":/solid-perspective.frag");
|
||||
mMeshes.back()->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f));
|
||||
mMeshes.back()->mProgram.release();
|
||||
|
||||
// Create objects that represent light sources for lighting examples
|
||||
mMeshes.push_back(
|
||||
|
@ -600,103 +373,101 @@ void ExampleScene::init()
|
|||
mMeshes.back()->mTransform.scale(0.25f);
|
||||
}
|
||||
|
||||
void ExampleScene::draw()
|
||||
{
|
||||
void ExampleScene::draw() {
|
||||
Scene::draw();
|
||||
|
||||
mTestPhong->mProgram.bind();
|
||||
mTestPhong->setUniform("uModelInverseTransposed",
|
||||
for(const auto & model : mModels) {
|
||||
model->draw();
|
||||
}
|
||||
|
||||
for(const auto & mesh : mMeshes) {
|
||||
mesh->draw();
|
||||
}
|
||||
|
||||
mTestPhong->bindShaders();
|
||||
mTestPhong->setUniform(
|
||||
"uModelInverseTransposed",
|
||||
mTestPhong->mTransform.toMatrix().normalMatrix());
|
||||
mTestPhong->setUniform(
|
||||
"uLightPosition",
|
||||
MeshRenderer::getInstance("phongLight")->mTransform.translation());
|
||||
mTestPhong->setUniform("uCameraPosition",
|
||||
ExampleScene::Camera().transform().translation());
|
||||
mTestPhong->mProgram.release();
|
||||
MeshRenderer::getInstance("phongLight")->mTransform.getTranslation());
|
||||
mTestPhong->setUniform(
|
||||
"uCameraPosition", ExampleScene::Camera().transform().getTranslation());
|
||||
mTestPhong->releaseShaders();
|
||||
mTestPhong->draw();
|
||||
|
||||
mTestAmbient->mProgram.bind();
|
||||
mTestAmbient->setUniform("uCameraPosition",
|
||||
ExampleScene::Camera().transform().translation());
|
||||
mTestAmbient->mProgram.release();
|
||||
mTestAmbient->bindShaders();
|
||||
mTestAmbient->setUniform(
|
||||
"uCameraPosition", ExampleScene::Camera().transform().getTranslation());
|
||||
mTestAmbient->releaseShaders();
|
||||
mTestAmbient->draw();
|
||||
|
||||
mTestDiffuse->mProgram.bind();
|
||||
mTestDiffuse->setUniform("uModelInverseTransposed",
|
||||
mTestDiffuse->bindShaders();
|
||||
mTestDiffuse->setUniform(
|
||||
"uModelInverseTransposed",
|
||||
mTestDiffuse->mTransform.toMatrix().normalMatrix());
|
||||
mTestDiffuse->setUniform(
|
||||
"uLightPosition",
|
||||
MeshRenderer::getInstance("diffuseLight")->mTransform.translation());
|
||||
mTestDiffuse->setUniform("uCameraPosition", ExampleScene::Camera().transform().translation());
|
||||
mTestDiffuse->mProgram.release();
|
||||
MeshRenderer::getInstance("diffuseLight")->mTransform.getTranslation());
|
||||
mTestDiffuse->setUniform(
|
||||
"uCameraPosition", ExampleScene::Camera().transform().getTranslation());
|
||||
mTestDiffuse->releaseShaders();
|
||||
mTestDiffuse->draw();
|
||||
|
||||
mTestSpecular->mProgram.bind();
|
||||
mTestSpecular->bindShaders();
|
||||
mTestSpecular->setUniform(
|
||||
"uModelInverseTransposed",
|
||||
mTestSpecular->mTransform.toMatrix().normalMatrix());
|
||||
mTestSpecular->setUniform(
|
||||
"uLightPosition",
|
||||
MeshRenderer::getInstance("specularLight")->mTransform.translation());
|
||||
mTestSpecular->setUniform("uCameraPosition", ExampleScene::Camera().transform().translation());
|
||||
mTestSpecular->mProgram.release();
|
||||
MeshRenderer::getInstance("specularLight")->mTransform.getTranslation());
|
||||
mTestSpecular->setUniform(
|
||||
"uCameraPosition", ExampleScene::Camera().transform().getTranslation());
|
||||
mTestSpecular->releaseShaders();
|
||||
mTestSpecular->draw();
|
||||
}
|
||||
|
||||
void ExampleScene::update()
|
||||
{
|
||||
auto position = MeshRenderer::getInstance("alienTestLight")->mTransform.translation();
|
||||
Model::getInstance("alienTest")->setUniform(
|
||||
"uLight.position", position);
|
||||
Model::getInstance("alienTest")->setUniform(
|
||||
"uCameraPosition", ExampleScene::Camera().transform().translation());
|
||||
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")->mTransform.rotate(0.75f, 0.0f, 1.0f, 0.0f);
|
||||
void ExampleScene::update() {
|
||||
auto position =
|
||||
MeshRenderer::getInstance("alienTestLight")->mTransform.getTranslation();
|
||||
auto alien = Model::getInstance("alienTest");
|
||||
alien->setUniform("uLight.position", position);
|
||||
alien->setUniform(
|
||||
"uCameraPosition", ExampleScene::Camera().transform().getTranslation());
|
||||
auto posMatrix = alien->mTransform.toMatrix();
|
||||
alien->setUniform("uMVP.normalMatrix", posMatrix.normalMatrix());
|
||||
alien->setUniform("uMVP.model", posMatrix);
|
||||
alien->setUniform("uMVP.view", ExampleScene::Camera().toMatrix());
|
||||
alien->setUniform("uMVP.projection", ExampleScene::Projection());
|
||||
alien->mTransform.rotate(0.75f, 0.0f, 1.0f, 0.0f);
|
||||
|
||||
position = MeshRenderer::getInstance("spartanTestLight")->mTransform.translation();
|
||||
Model::getInstance("spartanTest")->setUniform(
|
||||
"uLight.position", position);
|
||||
Model::getInstance("spartanTest")->setUniform(
|
||||
"uCameraPosition", ExampleScene::Camera().transform().translation());
|
||||
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")->mTransform.rotate(0.75f, 0.0f, 1.0f, 0.0f);
|
||||
position = MeshRenderer::getInstance("spartanTestLight")
|
||||
->mTransform.getTranslation();
|
||||
auto spartan = Model::getInstance("spartanTest");
|
||||
spartan->setUniform("uLight.position", position);
|
||||
spartan->setUniform(
|
||||
"uCameraPosition", ExampleScene::Camera().transform().getTranslation());
|
||||
posMatrix = spartan->mTransform.toMatrix();
|
||||
spartan->setUniform("uMVP.normalMatrix", posMatrix.normalMatrix());
|
||||
spartan->setUniform("uMVP.model", posMatrix);
|
||||
spartan->setUniform("uMVP.view", ExampleScene::Camera().toMatrix());
|
||||
spartan->setUniform("uMVP.projection", ExampleScene::Projection());
|
||||
spartan->mTransform.rotate(0.75f, 0.0f, 1.0f, 0.0f);
|
||||
|
||||
|
||||
|
||||
MeshRenderer::getInstance("testPhong")->mTransform.rotate(
|
||||
0.75f, 1.0f, 0.5f, 0.0f);
|
||||
MeshRenderer::getInstance("testPhong")->mProgram.bind();
|
||||
position = MeshRenderer::getInstance("testLight")->mTransform.translation();
|
||||
MeshRenderer::getInstance("testPhong")->setUniform(
|
||||
"uLight.position", position);
|
||||
MeshRenderer::getInstance("testPhong")->setUniform(
|
||||
"uCameraPosition", ExampleScene::Camera().transform().translation());
|
||||
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")->mProgram.release();
|
||||
auto phong = MeshRenderer::getInstance("testPhong");
|
||||
phong->mTransform.rotate(0.75f, 1.0f, 0.5f, 0.0f);
|
||||
phong->bindShaders();
|
||||
position =
|
||||
MeshRenderer::getInstance("testLight")->mTransform.getTranslation();
|
||||
phong->setUniform("uLight.position", position);
|
||||
phong->setUniform(
|
||||
"uCameraPosition", ExampleScene::Camera().transform().getTranslation());
|
||||
posMatrix = phong->mTransform.toMatrix();
|
||||
phong->setUniform("uMVP.normalMatrix", posMatrix.normalMatrix());
|
||||
phong->setUniform("uMVP.model", posMatrix);
|
||||
phong->setUniform("uMVP.view", ExampleScene::Camera().toMatrix());
|
||||
phong->setUniform("uMVP.projection", ExampleScene::Projection());
|
||||
phong->releaseShaders();
|
||||
|
||||
// Rotate lighting example cubes
|
||||
mTestPhong->mTransform.rotate(0.75f, 0.5f, 0.3f, 0.2f);
|
||||
|
@ -709,36 +480,36 @@ 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;
|
||||
float limit = -9.0f; // Origin position.x - 2.0f
|
||||
float posX =
|
||||
MeshRenderer::getInstance("topTriangle")->mTransform.translation().x();
|
||||
MeshRenderer::getInstance("topTriangle")->mTransform.getTranslation().x();
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
10
app/main.cpp
10
app/main.cpp
|
@ -9,12 +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
|
||||
|
@ -35,6 +34,5 @@ int main(int argc, char *argv[])
|
|||
MainWindow w;
|
||||
w.show();
|
||||
|
||||
return a.exec();
|
||||
return QApplication::exec();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -5,25 +5,25 @@
|
|||
|
||||
#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;
|
||||
std::unordered_map<std::string, Qtk::Scene*> mScenes;
|
||||
Ui::MainWindow * ui {};
|
||||
std::unordered_map<std::string, Qtk::Scene *> mScenes {};
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
std::vector<MeshRenderer *> mMeshes;
|
||||
std::vector<Model *> mModels;
|
||||
Skybox * mSkybox {};
|
||||
std::vector<MeshRenderer *> mMeshes {};
|
||||
std::vector<Model *> mModels {};
|
||||
};
|
||||
}
|
||||
} // namespace Qtk
|
||||
|
||||
#endif // QTK_SCENE_H
|
||||
|
|
|
@ -14,47 +14,40 @@ 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.rotation().conjugated());
|
||||
mWorld.translate(-mTransform.translation());
|
||||
mWorld.rotate(mTransform.getRotation().conjugated());
|
||||
mWorld.translate(-mTransform.getTranslation());
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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.translation();}
|
||||
inline const QQuaternion & rotation() const
|
||||
{ return mTransform.rotation();}
|
||||
|
||||
[[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.rotation().rotatedVector(LocalForward);}
|
||||
inline QVector3D right() const
|
||||
{ return mTransform.rotation().rotatedVector(LocalRight);}
|
||||
inline QVector3D up() const
|
||||
{ return mTransform.rotation().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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
41
src/input.h
41
src/input.h
|
@ -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
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
|
||||
## About: Main window for Qt6 OpenGL widget application ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
#ifndef QTK_MAINWIDGET_H
|
||||
#define QTK_MAINWIDGET_H
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <QMatrix4x4>
|
||||
#include <QOpenGLDebugLogger>
|
||||
#include <QOpenGLFunctions>
|
||||
#include <QOpenGLWidget>
|
||||
|
||||
#define QTK_DEBUG
|
||||
|
||||
class MeshRenderer;
|
||||
|
||||
class Model;
|
||||
|
||||
class Object;
|
||||
|
||||
class Scene;
|
||||
|
||||
class Skybox;
|
||||
|
||||
class OpenGLTextureFactory;
|
||||
|
||||
class MainWidget : public QOpenGLWidget, protected QOpenGLFunctions {
|
||||
Q_OBJECT;
|
||||
|
||||
public:
|
||||
// Constructors
|
||||
MainWidget();
|
||||
explicit MainWidget(QWidget * parent);
|
||||
explicit MainWidget(const QSurfaceFormat & format);
|
||||
~MainWidget() override;
|
||||
|
||||
private:
|
||||
void teardownGL();
|
||||
void initObjects();
|
||||
|
||||
public:
|
||||
// Inherited virtual Members
|
||||
void paintGL() override;
|
||||
void initializeGL() override;
|
||||
void resizeGL(int width, int height) override;
|
||||
|
||||
protected slots:
|
||||
void update();
|
||||
void messageLogged(const QOpenGLDebugMessage & msg);
|
||||
|
||||
// Protected Helpers
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent * event) override;
|
||||
void keyReleaseEvent(QKeyEvent * event) override;
|
||||
void mousePressEvent(QMouseEvent * event) override;
|
||||
void mouseReleaseEvent(QMouseEvent * event) override;
|
||||
|
||||
private:
|
||||
// Private helpers
|
||||
void initializeWidget();
|
||||
void printContextInformation();
|
||||
void updateCameraInput();
|
||||
|
||||
Scene * mScene;
|
||||
Object * mObject;
|
||||
|
||||
QOpenGLDebugLogger * mDebugLogger;
|
||||
};
|
||||
|
||||
#endif // QTK_MAINWIDGET_H
|
270
src/mesh.cpp
270
src/mesh.cpp
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
119
src/mesh.h
119
src/mesh.h
|
@ -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
|
||||
|
@ -73,62 +77,99 @@ namespace Qtk {
|
|||
#define UV_RIGHT QVector2D(0.0f, 1.0f)
|
||||
#define UV_CORNER QVector2D(1.0f, 1.0f)
|
||||
|
||||
// TODO: Vertices.getData(); Vertices.getStride();
|
||||
typedef std::vector<QVector3D> Vertices;
|
||||
typedef std::vector<QVector3D> Colors;
|
||||
typedef std::vector<GLuint> Indices;
|
||||
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 = {}) :
|
||||
mDrawMode(mode),
|
||||
mVertices(std::move(v)), mColors(std::move(c)),
|
||||
mIndices(std::move(i)), mTexCoords(std::move(t)),
|
||||
mNormals(std::move(n)) {}
|
||||
|
||||
inline const Vertices & vertices() const { return mVertices;}
|
||||
inline const Indices & indices() const { return mIndices;}
|
||||
inline const Colors & colors() const { return mColors;}
|
||||
inline const TexCoords & texCoords() const { return mTexCoords;}
|
||||
inline const Normals & normals() 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;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline size_t getTexCoordsStride() const {
|
||||
return mTexCoords.size() * sizeof(mTexCoords[0]);
|
||||
}
|
||||
|
||||
protected:
|
||||
DrawMode mDrawMode;
|
||||
|
||||
Vertices mVertices;
|
||||
Colors mColors;
|
||||
Indices mIndices;
|
||||
TexCoords mTexCoords;
|
||||
Normals mNormals;
|
||||
Vertices mVertices {};
|
||||
Colors mColors {};
|
||||
Indices mIndices {};
|
||||
TexCoords mTexCoords {};
|
||||
Normals mNormals {};
|
||||
};
|
||||
|
||||
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
|
||||
|
|
|
@ -17,48 +17,46 @@ 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"),
|
||||
mFragmentShader(":/multi-color.frag"), mDrawType(GL_TRIANGLES),
|
||||
mHasTexture(false)
|
||||
{
|
||||
MeshRenderer::MeshRenderer(const char * name, const ShapeBase & shape) :
|
||||
Object(name, shape), mVertexShader(":/multi-color.vert"),
|
||||
mFragmentShader(":/multi-color.frag"), mDrawType(GL_TRIANGLES) {
|
||||
mShape = Shape(shape);
|
||||
init();
|
||||
sInstances.insert(name, this);
|
||||
}
|
||||
|
||||
MeshRenderer::~MeshRenderer()
|
||||
{
|
||||
if (mHasTexture) {
|
||||
mTexture->destroy();
|
||||
}
|
||||
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();
|
||||
|
||||
|
@ -68,22 +66,20 @@ void MeshRenderer::init()
|
|||
|
||||
// Combine position and color data into one vector, allowing us to use one VBO
|
||||
Vertices combined;
|
||||
combined.reserve(vertices().size() + colors().size());
|
||||
combined.insert(combined.end(), vertices().begin(), vertices().end());
|
||||
combined.insert(combined.end(), colors().begin(), colors().end());
|
||||
combined.reserve(getVertices().size() + getColors().size());
|
||||
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,
|
||||
vertices().size() * sizeof(vertices()[0]),
|
||||
3, sizeof(QVector3D));
|
||||
mProgram.setAttributeBuffer(
|
||||
1, GL_FLOAT, getVertices().size() * sizeof(getVertices()[0]), 3,
|
||||
sizeof(QVector3D));
|
||||
|
||||
mVBO.release();
|
||||
|
||||
|
@ -91,82 +87,100 @@ void MeshRenderer::init()
|
|||
mVAO.release();
|
||||
}
|
||||
|
||||
void MeshRenderer::draw()
|
||||
{
|
||||
mProgram.bind();
|
||||
void MeshRenderer::draw() {
|
||||
bindShaders();
|
||||
mVAO.bind();
|
||||
|
||||
if(mHasTexture) {
|
||||
mTexture->bind();
|
||||
if(mTexture.hasTexture()) {
|
||||
mTexture.getOpenGLTexture().bind();
|
||||
}
|
||||
|
||||
// TODO: Automate uniforms some other way
|
||||
setUniformMVP();
|
||||
|
||||
if(mShape.mDrawMode == QTK_DRAW_ARRAYS) {
|
||||
glDrawArrays(mDrawType, 0, vertices().size());
|
||||
}
|
||||
else if (mShape.mDrawMode == QTK_DRAW_ELEMENTS
|
||||
glDrawArrays(mDrawType, 0, getVertices().size());
|
||||
} 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(mHasTexture) {
|
||||
mTexture->release();
|
||||
if(mTexture.hasTexture()) {
|
||||
mTexture.getOpenGLTexture().release();
|
||||
}
|
||||
|
||||
mVAO.release();
|
||||
mProgram.release();
|
||||
releaseShaders();
|
||||
}
|
||||
|
||||
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;
|
||||
init();
|
||||
}
|
||||
|
||||
void MeshRenderer::setUniformMVP(const char * model, const char * view,
|
||||
const char * projection)
|
||||
{
|
||||
void MeshRenderer::setUniformMVP(
|
||||
const char * model, const char * view, const char * projection) {
|
||||
ShaderBindScope lock(&mProgram, mBound);
|
||||
mProgram.setUniformValue(projection, Scene::Projection());
|
||||
mProgram.setUniformValue(view, Scene::View());
|
||||
mProgram.setUniformValue(model, mTransform.toMatrix());
|
||||
}
|
||||
|
||||
void MeshRenderer::setColor(const QVector3D & color)
|
||||
{
|
||||
void MeshRenderer::setColor(const QVector3D & color) {
|
||||
if(mShape.mColors.empty()) {
|
||||
for (const auto & vertex : mShape.vertices()) {
|
||||
for(const auto & vertex : mShape.getVertices()) {
|
||||
mShape.mColors.push_back(color);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < mShape.colors().size(); i++) {
|
||||
} else {
|
||||
for(int i = 0; i < mShape.getColors().size(); i++) {
|
||||
mShape.mColors[i] = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MeshRenderer::setTexture(const char * path)
|
||||
{
|
||||
mTexture = new QOpenGLTexture(*Texture::initImage(path));
|
||||
mHasTexture = true;
|
||||
void MeshRenderer::reallocateTexCoords(const TexCoords & t, unsigned dims) {
|
||||
mVAO.bind();
|
||||
mNBO.destroy();
|
||||
mNBO.create();
|
||||
mNBO.bind();
|
||||
mNBO.allocate(t.data(), t.size() * sizeof(t[0]));
|
||||
enableAttributeArray(1);
|
||||
if(dims == 2) {
|
||||
setAttributeBuffer(1, GL_FLOAT, 0, 2, sizeof(QVector2D));
|
||||
} else if(dims == 3) {
|
||||
setAttributeBuffer(1, GL_FLOAT, 0, 3, sizeof(QVector3D));
|
||||
}
|
||||
mNBO.release();
|
||||
mVAO.release();
|
||||
}
|
||||
|
||||
void MeshRenderer::setTexture(QOpenGLTexture * texture)
|
||||
{
|
||||
mTexture = texture;
|
||||
mHasTexture = true;
|
||||
void MeshRenderer::reallocateNormals(const Normals & n, unsigned dims) {
|
||||
// TODO: Store state to track if buffer objects are bound
|
||||
mVAO.bind();
|
||||
mNBO.destroy();
|
||||
mNBO.create();
|
||||
mNBO.bind();
|
||||
mNBO.allocate(n.data(), n.size() * sizeof(n[0]));
|
||||
enableAttributeArray(1);
|
||||
if(dims == 2) {
|
||||
setAttributeBuffer(1, GL_FLOAT, 0, 2, sizeof(QVector2D));
|
||||
} else if(dims == 3) {
|
||||
setAttributeBuffer(1, GL_FLOAT, 0, 3, sizeof(QVector3D));
|
||||
}
|
||||
mNBO.release();
|
||||
mVAO.release();
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* Inherited Virtual Member Functions
|
||||
******************************************************************************/
|
||||
|
||||
void MeshRenderer::setShape(const Shape & value)
|
||||
{
|
||||
void MeshRenderer::setShape(const Shape & value) {
|
||||
Object::setShape(value);
|
||||
init();
|
||||
}
|
||||
|
|
|
@ -12,21 +12,47 @@
|
|||
#include <object.h>
|
||||
#include <qtkapi.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace Qtk {
|
||||
class QTKAPI ShaderBindScope {
|
||||
public:
|
||||
explicit ShaderBindScope(
|
||||
QOpenGLShaderProgram * program, bool was_locked) :
|
||||
mWasBound(was_locked) {
|
||||
mProgram = program;
|
||||
if(!mWasBound) {
|
||||
mProgram->bind();
|
||||
}
|
||||
}
|
||||
|
||||
~ShaderBindScope() {
|
||||
if(!mWasBound) {
|
||||
mProgram->release();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
QOpenGLShaderProgram * mProgram;
|
||||
bool mWasBound;
|
||||
};
|
||||
|
||||
|
||||
class QTKAPI MeshRenderer : public Object {
|
||||
public:
|
||||
// Delegate constructors
|
||||
MeshRenderer(const char * name, Vertices vertices, Indices indices,
|
||||
DrawMode mode=QTK_DRAW_ARRAYS)
|
||||
: MeshRenderer(name, ShapeBase(mode, vertices, indices))
|
||||
{}
|
||||
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);
|
||||
|
@ -38,43 +64,67 @@ 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) {
|
||||
ShaderBindScope lock(&mProgram, mBound);
|
||||
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) {
|
||||
ShaderBindScope lock(&mProgram, mBound);
|
||||
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");
|
||||
|
||||
// Sets the texture to the image at the given path
|
||||
// + Sets mHasTexture to enable texture binding in draw()
|
||||
void setTexture(const char * path);
|
||||
void setTexture(QOpenGLTexture * texture);
|
||||
|
||||
// These functions modify data stored in a VBO
|
||||
// + After calling them, the VBO will need to be reallocated
|
||||
void setShape(const Shape & value) override;
|
||||
void setColor(const QVector3D & color);
|
||||
|
||||
void setAttributeBuffer(
|
||||
int location, GLenum type, int offset, int tupleSize,
|
||||
int stride = 0) {
|
||||
ShaderBindScope lock(&mProgram, mBound);
|
||||
mVAO.bind();
|
||||
mProgram.setAttributeBuffer(location, type, offset, tupleSize, stride);
|
||||
mVAO.release();
|
||||
}
|
||||
|
||||
inline void enableAttributeArray(int location) {
|
||||
ShaderBindScope lock(&mProgram, mBound);
|
||||
mVAO.bind();
|
||||
mProgram.enableAttributeArray(location);
|
||||
mVAO.release();
|
||||
}
|
||||
|
||||
void reallocateTexCoords(const TexCoords & t, unsigned dims = 2);
|
||||
|
||||
void reallocateNormals(const Normals & n, unsigned dims = 3);
|
||||
|
||||
// Static QHash of all mesh objects within the scene
|
||||
typedef QHash<QString, MeshRenderer *> MeshManager;
|
||||
|
||||
private:
|
||||
static MeshManager sInstances;
|
||||
|
||||
int mDrawType;
|
||||
bool mHasTexture;
|
||||
std::string mVertexShader, mFragmentShader;
|
||||
int mDrawType {};
|
||||
std::string mVertexShader {}, mFragmentShader {};
|
||||
};
|
||||
}
|
||||
} // namespace Qtk
|
||||
|
||||
#endif // QTK_MESHRENDERER_H
|
||||
|
|
156
src/model.cpp
156
src/model.cpp
|
@ -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) {
|
||||
|
@ -175,7 +166,7 @@ void Model::flipTexture(const std::string & fileName, bool flipX, bool flipY)
|
|||
texture.mTexture->destroy();
|
||||
texture.mTexture->create();
|
||||
texture.mTexture->setData(
|
||||
*Texture::initImage(fullPath.c_str(), flipX, flipY));
|
||||
*OpenGLTextureFactory::initImage(fullPath.c_str(), flipX, flipY));
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -388,9 +362,9 @@ ModelMesh::Textures Model::loadMaterialTextures(
|
|||
// If the texture has not yet been loaded
|
||||
if(!skip) {
|
||||
ModelTexture texture;
|
||||
texture.mTexture = Texture::initTexture2D(
|
||||
std::string(mDirectory + '/' + fileName.C_Str()).c_str(),
|
||||
false, false);
|
||||
texture.mTexture = OpenGLTextureFactory::initTexture2D(
|
||||
std::string(mDirectory + '/' + fileName.C_Str()).c_str(), false,
|
||||
false);
|
||||
texture.mID = texture.mTexture->textureId();
|
||||
texture.mType = typeName;
|
||||
texture.mPath = fileName.C_Str();
|
||||
|
@ -399,22 +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)
|
||||
{
|
||||
// Sort by the first vertex position, since all transforms will be the same
|
||||
return (cameraPos.translation().distanceToPoint(a.mVertices[0].mPosition))
|
||||
< (cameraPos.translation().distanceToPoint(b.mVertices[0].mPosition));
|
||||
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));
|
||||
};
|
||||
std::sort(mMeshes.begin(), mMeshes.end(), cameraDistance);
|
||||
}
|
||||
|
||||
|
|
73
src/model.h
73
src/model.h
|
@ -18,11 +18,12 @@
|
|||
#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>
|
||||
|
||||
|
@ -36,10 +37,10 @@ namespace Qtk {
|
|||
};
|
||||
|
||||
struct QTKAPI ModelTexture {
|
||||
GLuint mID;
|
||||
QOpenGLTexture * mTexture;
|
||||
std::string mType;
|
||||
std::string mPath;
|
||||
GLuint mID {};
|
||||
QOpenGLTexture * mTexture {};
|
||||
std::string mType {};
|
||||
std::string mPath {};
|
||||
};
|
||||
|
||||
class Model;
|
||||
|
@ -52,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);
|
||||
|
@ -75,37 +78,38 @@ namespace Qtk {
|
|||
|
||||
public:
|
||||
inline void draw() { draw(*mProgram); }
|
||||
|
||||
void draw(QOpenGLShaderProgram & shader);
|
||||
|
||||
// ModelMesh Public Members
|
||||
Vertices mVertices;
|
||||
Indices mIndices;
|
||||
Textures mTextures;
|
||||
Vertices mVertices {};
|
||||
Indices mIndices {};
|
||||
Textures mTextures {};
|
||||
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();
|
||||
|
||||
|
@ -120,22 +124,23 @@ 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
|
||||
|
||||
ModelMesh::Textures mTexturesLoaded;
|
||||
std::vector<ModelMesh> mMeshes;
|
||||
std::string mDirectory;
|
||||
ModelMesh::Textures mTexturesLoaded {};
|
||||
std::vector<ModelMesh> mMeshes {};
|
||||
std::string mDirectory {};
|
||||
const char *mVertexShader, *mFragmentShader, *mName;
|
||||
};
|
||||
}
|
||||
} // namespace Qtk
|
||||
|
||||
#endif // QTK_MODEL_H
|
||||
|
|
96
src/object.h
96
src/object.h
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include <mesh.h>
|
||||
#include <qtkapi.h>
|
||||
#include <texture.h>
|
||||
|
||||
namespace Qtk {
|
||||
class QTKAPI Object : public QObject {
|
||||
|
@ -22,42 +23,93 @@ namespace Qtk {
|
|||
|
||||
public:
|
||||
friend MeshRenderer;
|
||||
|
||||
// Initialize an object with no shape data assigned
|
||||
Object(const char * name)
|
||||
: mName(name), mVBO(QOpenGLBuffer::VertexBuffer)
|
||||
{ }
|
||||
explicit Object(const char * name) :
|
||||
mName(name), mVBO(QOpenGLBuffer::VertexBuffer), mBound(false) {}
|
||||
|
||||
// Initialize an object with shape data assigned
|
||||
Object(const char * name, const ShapeBase & shape)
|
||||
: mName(name), mVBO(QOpenGLBuffer::VertexBuffer), mShape(shape)
|
||||
{ }
|
||||
Object(const char * name, const ShapeBase & shape) :
|
||||
mName(name), mVBO(QOpenGLBuffer::VertexBuffer), mShape(shape),
|
||||
mBound(false) {}
|
||||
|
||||
~Object() {}
|
||||
~Object() override = default;
|
||||
|
||||
inline const Vertices & vertices() { return mShape.mVertices;}
|
||||
inline const Indices & indices() { return mShape.mIndices;}
|
||||
inline const Colors & colors() { return mShape.mColors;}
|
||||
inline const TexCoords & texCoords() { return mShape.mTexCoords;}
|
||||
inline const Normals & normals() { return mShape.mNormals;}
|
||||
inline QOpenGLTexture & texture() const { return *mTexture;}
|
||||
inline const Colors & getColors() { return mShape.mColors; }
|
||||
|
||||
inline const Indices & getIndexData() { return mShape.mIndices; }
|
||||
|
||||
inline const Normals & getNormals() { return mShape.mNormals; }
|
||||
|
||||
[[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 setVertices(const Vertices & value) { mShape.mVertices = value;}
|
||||
virtual inline void setIndices(const Indices & value) { mShape.mIndices = value;}
|
||||
virtual inline void setColors(const Colors & value) { mShape.mColors = value;}
|
||||
virtual inline void setTexCoords(const TexCoords & value) { mShape.mTexCoords = 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(path, flipX, flipY);
|
||||
}
|
||||
|
||||
virtual inline void setCubeMap(const char * path) {
|
||||
mTexture.setCubeMap(path);
|
||||
}
|
||||
|
||||
virtual inline void setTexture(const Texture & t) {
|
||||
mTexture.setTexture(t.getPath());
|
||||
}
|
||||
|
||||
virtual inline void setVertices(const Vertices & value) {
|
||||
mShape.mVertices = value;
|
||||
}
|
||||
|
||||
virtual inline void bindShaders() {
|
||||
mBound = true;
|
||||
mProgram.bind();
|
||||
}
|
||||
|
||||
virtual inline void releaseShaders() {
|
||||
mBound = false;
|
||||
mProgram.release();
|
||||
}
|
||||
|
||||
QOpenGLBuffer mVBO, mNBO;
|
||||
QOpenGLVertexArrayObject mVAO;
|
||||
QOpenGLShaderProgram mProgram;
|
||||
|
||||
Transform3D mTransform;
|
||||
Shape mShape;
|
||||
|
||||
Texture mTexture;
|
||||
const char * mName;
|
||||
bool mBound;
|
||||
|
||||
private:
|
||||
QOpenGLTexture * mTexture;
|
||||
};
|
||||
virtual inline void setTexture(QOpenGLTexture * value) {
|
||||
mTexture.setTexture(value);
|
||||
}
|
||||
|
||||
QOpenGLShaderProgram mProgram;
|
||||
};
|
||||
} // namespace Qtk
|
||||
|
||||
#endif // QTK_OBJECT_H
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -12,50 +12,50 @@
|
|||
|
||||
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),
|
||||
mVertices(Cube(QTK_DRAW_ELEMENTS).vertices()),
|
||||
mIndices(Cube(QTK_DRAW_ELEMENTS).indices())
|
||||
{
|
||||
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()) {
|
||||
init();
|
||||
mCubeMap = Texture::initCubeMap(
|
||||
mTexture.setCubeMap(
|
||||
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) :
|
||||
mTexture(cubeMap) {
|
||||
init();
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Public Member Functions
|
||||
******************************************************************************/
|
||||
|
||||
void Skybox::draw()
|
||||
{
|
||||
void Skybox::draw() {
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
glDepthMask(GL_FALSE);
|
||||
|
||||
mVAO.bind();
|
||||
mProgram.bind();
|
||||
mCubeMap->bind();
|
||||
mTexture.getOpenGLTexture().bind();
|
||||
|
||||
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();
|
||||
mTexture.getOpenGLTexture().bind();
|
||||
mProgram.release();
|
||||
mVAO.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
|
||||
|
|
25
src/skybox.h
25
src/skybox.h
|
@ -18,34 +18,37 @@
|
|||
#include <camera3d.h>
|
||||
#include <mesh.h>
|
||||
#include <qtkapi.h>
|
||||
|
||||
#include <texture.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");
|
||||
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();
|
||||
|
||||
private:
|
||||
void init();
|
||||
|
||||
Vertices mVertices;
|
||||
Indices mIndices;
|
||||
Vertices mVertices {};
|
||||
Indices mIndices {};
|
||||
|
||||
QOpenGLShaderProgram mProgram;
|
||||
QOpenGLVertexArrayObject mVAO;
|
||||
QOpenGLBuffer mVBO;
|
||||
QOpenGLTexture * mCubeMap;
|
||||
Texture mTexture;
|
||||
};
|
||||
}
|
||||
} // namespace Qtk
|
||||
|
||||
#endif // QTK_SKYBOX_H
|
||||
|
|
|
@ -8,13 +8,14 @@
|
|||
|
||||
#include <QDebug>
|
||||
#include <QImageReader>
|
||||
#include <utility>
|
||||
|
||||
#include <texture.h>
|
||||
|
||||
using namespace Qtk;
|
||||
|
||||
QImage * Texture::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 * Texture::initImage(const char * image, bool flipX, bool flipY)
|
|||
return loadedImage;
|
||||
}
|
||||
|
||||
QOpenGLTexture * Texture::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 * Texture::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 * Texture::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));
|
||||
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));
|
||||
}
|
||||
|
||||
QOpenGLTexture * Texture::initCubeMap(
|
||||
QImage right, QImage top,
|
||||
QImage front, QImage left,
|
||||
QImage bottom, QImage back)
|
||||
{
|
||||
QOpenGLTexture * OpenGLTextureFactory::initCubeMap(
|
||||
const QImage & right, const QImage & top, const QImage & front,
|
||||
const QImage & left, const QImage & bottom, const 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 * Texture::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 * Texture::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++;
|
||||
}
|
||||
|
|
|
@ -10,36 +10,108 @@
|
|||
#define QTOPENGL_TEXTURE_H
|
||||
|
||||
#include <QOpenGLTexture>
|
||||
#include <utility>
|
||||
|
||||
#include <qtkapi.h>
|
||||
|
||||
namespace Qtk {
|
||||
class QTKAPI Texture {
|
||||
class QTKAPI OpenGLTextureFactory {
|
||||
public:
|
||||
~Texture() {}
|
||||
~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(
|
||||
const QImage & right, const QImage & top, const QImage & front,
|
||||
const QImage & left, const QImage & bottom, const 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
|
||||
Texture() {}
|
||||
OpenGLTextureFactory() = default;
|
||||
};
|
||||
|
||||
// TODO: Struct for (re)storing texture state
|
||||
class Texture {
|
||||
public:
|
||||
Texture() = default;
|
||||
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)),
|
||||
mPath(path) {}
|
||||
explicit Texture(QOpenGLTexture * texture) : mOpenGLTexture(texture) {}
|
||||
|
||||
~Texture() { mOpenGLTexture->destroy(); }
|
||||
|
||||
[[nodiscard]] inline QOpenGLTexture & getOpenGLTexture() const {
|
||||
return *mOpenGLTexture;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::string getPath() const { return mPath; }
|
||||
|
||||
void setTexture(
|
||||
const std::string & path, bool flipX = false, bool flipY = false) {
|
||||
mOpenGLTexture =
|
||||
OpenGLTextureFactory::initTexture2D(path.data(), flipX, flipY);
|
||||
mPath = path.data();
|
||||
}
|
||||
|
||||
void setTexture(
|
||||
const char * path, bool flipX = false, bool flipY = false) {
|
||||
mOpenGLTexture =
|
||||
OpenGLTextureFactory::initTexture2D(path, flipX, flipY);
|
||||
mPath = path;
|
||||
}
|
||||
|
||||
// TODO: This is unsafe because we don't have a path. Encapsulate it.
|
||||
inline void setTexture(QOpenGLTexture * texture) {
|
||||
mOpenGLTexture = texture;
|
||||
}
|
||||
|
||||
virtual inline void setCubeMap(const char * path) {
|
||||
mOpenGLTexture = OpenGLTextureFactory::initCubeMap(path);
|
||||
mPath = path;
|
||||
}
|
||||
|
||||
virtual inline void setCubeMap(
|
||||
const char * right, const char * top, const char * front,
|
||||
const char * left, const char * bottom, const char * back) {
|
||||
mOpenGLTexture = OpenGLTextureFactory::initCubeMap(
|
||||
right, top, front, left, bottom, back);
|
||||
}
|
||||
|
||||
virtual inline void setCubeMap(
|
||||
const QImage & right, const QImage & top, const QImage & front,
|
||||
const QImage & left, const QImage & bottom, const QImage & back) {
|
||||
mOpenGLTexture = OpenGLTextureFactory::initCubeMap(
|
||||
right, top, front, left, bottom, back);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool hasTexture() const {
|
||||
return mOpenGLTexture != Q_NULLPTR;
|
||||
}
|
||||
|
||||
private:
|
||||
QOpenGLTexture * mOpenGLTexture = Q_NULLPTR;
|
||||
const char * mPath {};
|
||||
};
|
||||
|
||||
} // namespace Qtk
|
||||
|
||||
#endif // QTOPENGL_TEXTURE_H
|
||||
|
|
|
@ -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::forward() const
|
||||
{
|
||||
QVector3D Transform3D::getForward() const {
|
||||
return mRotation.rotatedVector(LocalForward);
|
||||
}
|
||||
|
||||
QVector3D Transform3D::up() const
|
||||
{
|
||||
QVector3D Transform3D::getUp() const {
|
||||
return mRotation.rotatedVector(LocalUp);
|
||||
}
|
||||
|
||||
QVector3D Transform3D::right() 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.translation().x() << ", "
|
||||
<< transform.translation().y() << ", "
|
||||
<< transform.translation().z() << ">\n";
|
||||
dbg << "Scale: <" << transform.scale().x() << ", "
|
||||
<< transform.scale().y() << ", "
|
||||
<< transform.scale().z() << ">\n";
|
||||
dbg << "Rotation: <" << transform.rotation().x() << ", "
|
||||
<< transform.rotation().y() << ", "
|
||||
<< transform.rotation().z() << " | " <<
|
||||
transform.rotation().scalar() << ">\n}";
|
||||
dbg << "Position: <" << transform.getTranslation().x() << ", "
|
||||
<< transform.getTranslation().y() << ", "
|
||||
<< transform.getTranslation().z() << ">\n";
|
||||
dbg << "Scale: <" << transform.getScale().x() << ", "
|
||||
<< transform.getScale().y() << ", " << transform.getScale().z()
|
||||
<< ">\n";
|
||||
dbg << "Rotation: <" << transform.getRotation().x() << ", "
|
||||
<< 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
|
||||
|
|
|
@ -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 & translation() const { return mTranslation;}
|
||||
inline const QVector3D & scale() const { return mScale; }
|
||||
inline const QQuaternion & rotation() 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 forward() const;
|
||||
QVector3D up() const;
|
||||
QVector3D right() 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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue