Compare commits
10 Commits
f78e41dc76
...
8906a4c508
Author | SHA1 | Date |
---|---|---|
Shaun Reed | 8906a4c508 | |
Shaun Reed | 697cdd0e75 | |
Shaun Reed | 99b4f9355b | |
Shaun Reed | 0f372f71f4 | |
Shaun Reed | ad4d4636a4 | |
Shaun Reed | 86b3f78368 | |
Shaun Reed | 44d9092306 | |
Shaun Reed | f3406ee749 | |
Shaun Reed | 249a2b4446 | |
Shaun Reed | 432bf9919c |
|
@ -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,148 @@
|
||||||
|
# Generated from CLion Inspection settings
|
||||||
|
---
|
||||||
|
Checks: '-*,
|
||||||
|
bugprone-argument-comment,
|
||||||
|
bugprone-assert-side-effect,
|
||||||
|
bugprone-bad-signal-to-kill-thread,
|
||||||
|
bugprone-branch-clone,
|
||||||
|
bugprone-copy-constructor-init,
|
||||||
|
bugprone-dangling-handle,
|
||||||
|
bugprone-dynamic-static-initializers,
|
||||||
|
bugprone-fold-init-type,
|
||||||
|
bugprone-forward-declaration-namespace,
|
||||||
|
bugprone-forwarding-reference-overload,
|
||||||
|
bugprone-inaccurate-erase,
|
||||||
|
bugprone-incorrect-roundings,
|
||||||
|
bugprone-integer-division,
|
||||||
|
bugprone-lambda-function-name,
|
||||||
|
bugprone-macro-parentheses,
|
||||||
|
bugprone-macro-repeated-side-effects,
|
||||||
|
bugprone-misplaced-operator-in-strlen-in-alloc,
|
||||||
|
bugprone-misplaced-pointer-arithmetic-in-alloc,
|
||||||
|
bugprone-misplaced-widening-cast,
|
||||||
|
bugprone-move-forwarding-reference,
|
||||||
|
bugprone-multiple-statement-macro,
|
||||||
|
bugprone-no-escape,
|
||||||
|
bugprone-not-null-terminated-result,
|
||||||
|
bugprone-parent-virtual-call,
|
||||||
|
bugprone-posix-return,
|
||||||
|
bugprone-reserved-identifier,
|
||||||
|
bugprone-sizeof-container,
|
||||||
|
bugprone-sizeof-expression,
|
||||||
|
bugprone-spuriously-wake-up-functions,
|
||||||
|
bugprone-string-constructor,
|
||||||
|
bugprone-string-integer-assignment,
|
||||||
|
bugprone-string-literal-with-embedded-nul,
|
||||||
|
bugprone-suspicious-enum-usage,
|
||||||
|
bugprone-suspicious-include,
|
||||||
|
bugprone-suspicious-memory-comparison,
|
||||||
|
bugprone-suspicious-memset-usage,
|
||||||
|
bugprone-suspicious-missing-comma,
|
||||||
|
bugprone-suspicious-semicolon,
|
||||||
|
bugprone-suspicious-string-compare,
|
||||||
|
bugprone-swapped-arguments,
|
||||||
|
bugprone-terminating-continue,
|
||||||
|
bugprone-throw-keyword-missing,
|
||||||
|
bugprone-too-small-loop-variable,
|
||||||
|
bugprone-undefined-memory-manipulation,
|
||||||
|
bugprone-undelegated-constructor,
|
||||||
|
bugprone-unhandled-self-assignment,
|
||||||
|
bugprone-unused-raii,
|
||||||
|
bugprone-unused-return-value,
|
||||||
|
bugprone-use-after-move,
|
||||||
|
bugprone-virtual-near-miss,
|
||||||
|
cert-dcl21-cpp,
|
||||||
|
cert-dcl58-cpp,
|
||||||
|
cert-err34-c,
|
||||||
|
cert-err52-cpp,
|
||||||
|
cert-err60-cpp,
|
||||||
|
cert-flp30-c,
|
||||||
|
cert-msc50-cpp,
|
||||||
|
cert-msc51-cpp,
|
||||||
|
cert-str34-c,
|
||||||
|
cppcoreguidelines-interfaces-global-init,
|
||||||
|
cppcoreguidelines-narrowing-conversions,
|
||||||
|
cppcoreguidelines-pro-type-member-init,
|
||||||
|
cppcoreguidelines-pro-type-static-cast-downcast,
|
||||||
|
cppcoreguidelines-slicing,
|
||||||
|
google-default-arguments,
|
||||||
|
google-explicit-constructor,
|
||||||
|
google-runtime-operator,
|
||||||
|
hicpp-exception-baseclass,
|
||||||
|
hicpp-multiway-paths-covered,
|
||||||
|
misc-misplaced-const,
|
||||||
|
misc-new-delete-overloads,
|
||||||
|
misc-no-recursion,
|
||||||
|
misc-non-copyable-objects,
|
||||||
|
misc-throw-by-value-catch-by-reference,
|
||||||
|
misc-unconventional-assign-operator,
|
||||||
|
misc-uniqueptr-reset-release,
|
||||||
|
modernize-avoid-bind,
|
||||||
|
modernize-concat-nested-namespaces,
|
||||||
|
modernize-deprecated-headers,
|
||||||
|
modernize-deprecated-ios-base-aliases,
|
||||||
|
modernize-loop-convert,
|
||||||
|
modernize-make-shared,
|
||||||
|
modernize-make-unique,
|
||||||
|
modernize-pass-by-value,
|
||||||
|
modernize-raw-string-literal,
|
||||||
|
modernize-redundant-void-arg,
|
||||||
|
modernize-replace-auto-ptr,
|
||||||
|
modernize-replace-disallow-copy-and-assign-macro,
|
||||||
|
modernize-replace-random-shuffle,
|
||||||
|
modernize-return-braced-init-list,
|
||||||
|
modernize-shrink-to-fit,
|
||||||
|
modernize-unary-static-assert,
|
||||||
|
modernize-use-auto,
|
||||||
|
modernize-use-bool-literals,
|
||||||
|
modernize-use-emplace,
|
||||||
|
modernize-use-equals-default,
|
||||||
|
modernize-use-equals-delete,
|
||||||
|
modernize-use-nodiscard,
|
||||||
|
modernize-use-noexcept,
|
||||||
|
modernize-use-nullptr,
|
||||||
|
modernize-use-override,
|
||||||
|
modernize-use-transparent-functors,
|
||||||
|
modernize-use-uncaught-exceptions,
|
||||||
|
mpi-buffer-deref,
|
||||||
|
mpi-type-mismatch,
|
||||||
|
openmp-use-default-none,
|
||||||
|
performance-faster-string-find,
|
||||||
|
performance-for-range-copy,
|
||||||
|
performance-implicit-conversion-in-loop,
|
||||||
|
performance-inefficient-algorithm,
|
||||||
|
performance-inefficient-string-concatenation,
|
||||||
|
performance-inefficient-vector-operation,
|
||||||
|
performance-move-const-arg,
|
||||||
|
performance-move-constructor-init,
|
||||||
|
performance-no-automatic-move,
|
||||||
|
performance-noexcept-move-constructor,
|
||||||
|
performance-trivially-destructible,
|
||||||
|
performance-type-promotion-in-math-fn,
|
||||||
|
performance-unnecessary-copy-initialization,
|
||||||
|
performance-unnecessary-value-param,
|
||||||
|
portability-simd-intrinsics,
|
||||||
|
readability-avoid-const-params-in-decls,
|
||||||
|
readability-const-return-type,
|
||||||
|
readability-container-size-empty,
|
||||||
|
readability-convert-member-functions-to-static,
|
||||||
|
readability-delete-null-pointer,
|
||||||
|
readability-deleted-default,
|
||||||
|
readability-inconsistent-declaration-parameter-name,
|
||||||
|
readability-make-member-function-const,
|
||||||
|
readability-misleading-indentation,
|
||||||
|
readability-misplaced-array-index,
|
||||||
|
readability-non-const-parameter,
|
||||||
|
readability-redundant-control-flow,
|
||||||
|
readability-redundant-declaration,
|
||||||
|
readability-redundant-function-ptr-dereference,
|
||||||
|
readability-braces-around-statements,
|
||||||
|
readability-redundant-smartptr-get,
|
||||||
|
readability-redundant-string-cstr,
|
||||||
|
readability-redundant-string-init,
|
||||||
|
readability-simplify-subscript-expr,
|
||||||
|
readability-static-accessed-through-instance,
|
||||||
|
readability-static-definition-in-anonymous-namespace,
|
||||||
|
readability-string-compare,
|
||||||
|
readability-uniqueptr-delete-release,
|
||||||
|
readability-use-anyofallof'
|
|
@ -10,12 +10,14 @@ jobs:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, macos-latest]
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
include:
|
include:
|
||||||
- os: ubuntu-latest
|
- os: ubuntu-latest
|
||||||
CMAKE_PARAMS: -DCMAKE_PREFIX_PATH=/home/runner/work/qtk/Qt/6.3.1/gcc_64/
|
cmake: -DCMAKE_PREFIX_PATH="/home/runner/work/qtk/Qt/6.3.1/gcc_64/"
|
||||||
|
- os: windows-latest
|
||||||
|
cmake: -DCMAKE_PREFIX_PATH="D:/a/qtk/qtk/Qt/6.3.1/mingw81_64/"
|
||||||
- os: macos-latest
|
- os: macos-latest
|
||||||
CMAKE_PARAMS: -DCMAKE_PREFIX_PATH=/home/runner/work/qtk/Qt/6.3.1/gcc_64/ -DASSIMP_NEW_INTERFACE=on
|
cmake: -DCMAKE_PREFIX_PATH="/home/runner/work/qtk/Qt/6.3.1/gcc_64/"
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
|
@ -26,11 +28,37 @@ jobs:
|
||||||
with:
|
with:
|
||||||
version: '6.3.1'
|
version: '6.3.1'
|
||||||
|
|
||||||
- name: Install Assimp Linux
|
- name: Chocolatey Action
|
||||||
if: matrix.os == 'ubuntu-latest'
|
if: matrix.os == 'windows-latest'
|
||||||
|
uses: crazy-max/ghaction-chocolatey@v2.0.0
|
||||||
|
with:
|
||||||
|
args: install pkgconfiglite
|
||||||
|
|
||||||
|
- name: Build Qtk
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
sudo apt install libassimp-dev -y
|
cmake -S . -B build/ ${{ matrix.cmake }} && cmake --build build/ \
|
||||||
|
--target qtk-main
|
||||||
|
|
||||||
|
Build-Qtk-Assimp-Targets:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, macos-latest]
|
||||||
|
include:
|
||||||
|
- os: ubuntu-latest
|
||||||
|
cmake: -DCMAKE_PREFIX_PATH="/home/runner/work/qtk/Qt/6.3.1/gcc_64/" -DQTK_UPDATE_SUBMODULES=OFF
|
||||||
|
- os: macos-latest
|
||||||
|
cmake: -DCMAKE_PREFIX_PATH="/home/runner/work/qtk/Qt/6.3.1/gcc_64/" -DASSIMP_NEW_INTERFACE=ON -DQTK_UPDATE_SUBMODULES=OFF
|
||||||
|
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Install Qt
|
||||||
|
uses: jurplel/install-qt-action@v2
|
||||||
|
with:
|
||||||
|
version: '6.3.1'
|
||||||
|
|
||||||
- name: Install Assimp MacOS
|
- name: Install Assimp MacOS
|
||||||
if: matrix.os == 'macos-latest'
|
if: matrix.os == 'macos-latest'
|
||||||
|
@ -38,8 +66,14 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
brew install assimp
|
brew install assimp
|
||||||
|
|
||||||
|
- name: Install Assimp Ubuntu
|
||||||
|
if: matrix.os == 'ubuntu-latest'
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
sudo apt install libassimp-dev
|
||||||
|
|
||||||
- name: Build Qtk
|
- name: Build Qtk
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
mkdir build && cd build
|
cmake -S . -B build/ ${{ matrix.cmake }} && cmake --build build/ \
|
||||||
cmake .. ${{ matrix.CMAKE_PARAMS }} && cmake --build .
|
--target qtk-main
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "extern/assimp/assimp"]
|
||||||
|
path = extern/assimp/assimp
|
||||||
|
url = https://github.com/assimp/assimp.git
|
233
CMakeLists.txt
233
CMakeLists.txt
|
@ -3,7 +3,7 @@
|
||||||
## ##
|
## ##
|
||||||
## Project for working with OpenGL and Qt6 widgets ##
|
## Project for working with OpenGL and Qt6 widgets ##
|
||||||
################################################################################
|
################################################################################
|
||||||
cmake_minimum_required(VERSION 3.5)
|
cmake_minimum_required(VERSION 3.2)
|
||||||
|
|
||||||
project(
|
project(
|
||||||
#[[NAME]] Qtk
|
#[[NAME]] Qtk
|
||||||
|
@ -16,72 +16,213 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
set(CMAKE_AUTOUIC ON)
|
set(CMAKE_AUTOUIC ON)
|
||||||
set(CMAKE_AUTOMOC ON)
|
set(CMAKE_AUTOMOC ON)
|
||||||
set(CMAKE_AUTORCC ON)
|
set(CMAKE_AUTORCC ON)
|
||||||
set(CMAKE_CXX_STANDARD 11)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||||
|
|
||||||
# For CLion builds, point CMAKE_PREFIX_PATH to Qt6 install directory
|
if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
||||||
list(APPEND CMAKE_PREFIX_PATH $ENV{HOME}/Code/Clones/Qt/6.3.1/gcc_64/)
|
add_compile_options(/wd4131 /wd4127)
|
||||||
find_package(Qt6 COMPONENTS OpenGLWidgets)
|
|
||||||
if (NOT Qt6_FOUND)
|
|
||||||
message(SEND_ERROR "Unable to find Qt6 at CMAKE_PREFIX_PATH: ${CMAKE_PREFIX_PATH}")
|
|
||||||
message(FATAL_ERROR "Specify path to Qt6 with `cmake -DCMAKE_PREFIX_PATH=/path/to/Qt/6.x.x/gcc_64 -S /path/to/qtk -B /path/to/qtk/build && cmake --build /path/to/qtk/build -j $(nprocs)`")
|
|
||||||
endif()
|
endif()
|
||||||
|
message(STATUS "[Qtk] Compiling with ${CMAKE_CXX_COMPILER_ID}")
|
||||||
|
|
||||||
|
# Qtk build options
|
||||||
|
option(QTK_DEBUG "Enable debugger" ON)
|
||||||
|
message(STATUS "[Qtk] Compiling with QTK_DEBUG=${QTK_DEBUG}")
|
||||||
|
option(QTK_UPDATE_SUBMODULES "Update external project (assimp) submodule" ON)
|
||||||
|
message(
|
||||||
|
STATUS
|
||||||
|
"[Qtk] Compiling with QTK_UPDATE_SUBMODULES=${QTK_UPDATE_SUBMODULES}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Qt options
|
||||||
|
set(QT_DIR "$ENV{HOME}/Code/Clones/Qt/6.3.1/gcc_64/" CACHE PATH "Path to Qt6")
|
||||||
|
|
||||||
|
# Options for bringing your own assimp installation; Otherwise not needed
|
||||||
|
# + If assimp is available system-wide we can just set QTK_UPDATE_SUBMODULES OFF
|
||||||
|
option(ASSIMP_NEW_INTERFACE "Use the assimp::assimp interface (WIN / OSX)" OFF)
|
||||||
|
message(
|
||||||
|
STATUS
|
||||||
|
"[Qtk] Compiling with ASSIMP_NEW_INTERFACE=${ASSIMP_NEW_INTERFACE}"
|
||||||
|
)
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# External Libraries
|
# External Libraries
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
# https://github.com/assimp/assimp/commit/6ac8279977c3a54118551e549d77329497116f66
|
# For CLion builds, point CMAKE_PREFIX_PATH to Qt6 install directory
|
||||||
find_package(assimp REQUIRED)
|
# + QtCreator will handle this for you if that is used instead
|
||||||
option(ASSIMP_NEW_INTERFACE "Use assimp::assimp as target instead of assimp" OFF)
|
list(APPEND CMAKE_PREFIX_PATH "${QT_DIR}")
|
||||||
|
|
||||||
|
# Find Qt
|
||||||
|
find_package(Qt6 COMPONENTS OpenGLWidgets)
|
||||||
|
if (NOT Qt6_FOUND)
|
||||||
|
message(
|
||||||
|
SEND_ERROR "[Qtk] Error: Unable to find Qt6 at CMAKE_PREFIX_PATH: "
|
||||||
|
"${CMAKE_PREFIX_PATH}"
|
||||||
|
)
|
||||||
|
message(
|
||||||
|
FATAL_ERROR
|
||||||
|
"[Qtk] Error: Specify path to Qt6 with `cmake "
|
||||||
|
"-DCMAKE_PREFIX_PATH=/path/to/Qt/6.x.x/gcc_64 -S /path/to/qtk -B "
|
||||||
|
"/path/to/qtk/build && cmake --build /path/to/qtk/build -j $(nprocs)`"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (QTK_UPDATE_SUBMODULES)
|
||||||
|
message(STATUS "[Qtk] Updating submodules...")
|
||||||
|
include("${CMAKE_SOURCE_DIR}/cmake/include/git_submodule.cmake")
|
||||||
|
submodule_update("${CMAKE_CURRENT_SOURCE_DIR}/extern/assimp/assimp/")
|
||||||
|
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/extern/assimp/assimp/")
|
||||||
|
else()
|
||||||
|
find_package(assimp REQUIRED)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# Qtk
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
set(
|
||||||
|
PUBLIC_HEADERS
|
||||||
|
src/qtkwidget.h
|
||||||
|
src/abstractscene.h
|
||||||
|
src/camera3d.h
|
||||||
|
src/mesh.h
|
||||||
|
src/meshrenderer.h
|
||||||
|
src/model.h
|
||||||
|
src/object.h
|
||||||
|
src/skybox.h
|
||||||
|
src/texture.h
|
||||||
|
src/transform3D.h
|
||||||
|
)
|
||||||
|
|
||||||
|
set(
|
||||||
|
SOURCE_FILES
|
||||||
|
src/qtkwidget.cpp
|
||||||
|
src/abstractscene.cpp
|
||||||
|
src/camera3d.cpp
|
||||||
|
src/input.cpp
|
||||||
|
src/input.h
|
||||||
|
src/mesh.cpp
|
||||||
|
src/meshrenderer.cpp
|
||||||
|
src/model.cpp
|
||||||
|
src/object.cpp
|
||||||
|
src/qtkapi.h
|
||||||
|
src/skybox.cpp
|
||||||
|
src/texture.cpp
|
||||||
|
src/transform3D.cpp
|
||||||
|
)
|
||||||
|
|
||||||
include(GenerateExportHeader)
|
include(GenerateExportHeader)
|
||||||
|
|
||||||
|
add_library(qtk-widget STATIC ${PUBLIC_HEADERS} ${SOURCE_FILES})
|
||||||
|
target_include_directories(qtk-widget PRIVATE src/ app/)
|
||||||
|
|
||||||
|
set_target_properties(qtk-widget PROPERTIES
|
||||||
|
PUBLIC_HEADER "${PUBLIC_HEADERS}"
|
||||||
|
VERSION ${PROJECT_VERSION}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(qtk-widget PUBLIC Qt6::OpenGLWidgets)
|
||||||
|
target_link_libraries(qtk-widget PUBLIC Qt6::Widgets)
|
||||||
|
|
||||||
|
if (QTK_UPDATE_SUBMODULES OR NOT ASSIMP_NEW_INTERFACE)
|
||||||
|
target_link_libraries(qtk-widget PUBLIC assimp)
|
||||||
|
elseif(ASSIMP_NEW_INTERFACE)
|
||||||
|
target_link_libraries(qtk-widget PUBLIC assimp::assimp)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(QTK_DEBUG)
|
||||||
|
message(STATUS "[Qtk] Building with QTK_DEBUG=${QTK_DEBUG}")
|
||||||
|
target_compile_definitions(qtk-widget PUBLIC QTK_DEBUG)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
find_package(OpenGL REQUIRED)
|
||||||
|
target_link_libraries(qtk-widget PUBLIC OpenGL::GL)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Install files
|
||||||
|
install(TARGETS qtk-widget
|
||||||
|
# Associate qtk-widget target with qtk-export
|
||||||
|
EXPORT qtk-export
|
||||||
|
# <prefix>/bin on DLL systems and <prefix>/lib on non-dll systems
|
||||||
|
LIBRARY DESTINATION lib
|
||||||
|
ARCHIVE DESTINATION lib/static
|
||||||
|
RUNTIME DESTINATION bin
|
||||||
|
PUBLIC_HEADER DESTINATION include
|
||||||
|
)
|
||||||
|
|
||||||
|
# Install export
|
||||||
|
# qtkTargets.cmake will only be installed when one of the CONFIGURATIONS is installed
|
||||||
|
# + The generated import will only reference that qtk configuration
|
||||||
|
install(EXPORT qtk-export
|
||||||
|
FILE qtkTargets.cmake
|
||||||
|
CONFIGURATIONS Debug|Release
|
||||||
|
DESTINATION ${CMAKE_INSTALL_PREFIX}/cmake
|
||||||
|
)
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# Final Application
|
# Final Application
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
# Add our Qt resources.qrc file to our application
|
set(QTK_RESOURCES "${CMAKE_SOURCE_DIR}/resources")
|
||||||
set(SOURCES app/main.cpp)
|
configure_file(
|
||||||
qt6_add_big_resources(SOURCES resources.qrc)
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/qtkresources.h.in"
|
||||||
qt_add_executable(qtk ${SOURCES})
|
"${CMAKE_CURRENT_BINARY_DIR}/src/qtkresources.h"
|
||||||
|
@ONLY
|
||||||
set(SOURCES
|
|
||||||
src/mainwidget.cpp src/mainwidget.h
|
|
||||||
src/mainwindow.cpp src/mainwindow.h src/mainwindow.ui
|
|
||||||
src/input.cpp src/input.h
|
|
||||||
src/mesh.cpp src/mesh.h
|
|
||||||
src/texture.cpp src/texture.h
|
|
||||||
src/object.cpp src/object.h
|
|
||||||
src/meshrenderer.cpp src/meshrenderer.h
|
|
||||||
src/camera3d.cpp src/camera3d.h
|
|
||||||
src/skybox.cpp src/skybox.h
|
|
||||||
src/transform3D.cpp src/transform3D.h
|
|
||||||
src/model.cpp src/model.h
|
|
||||||
src/scene.cpp src/scene.h
|
|
||||||
src/resourcemanager.cpp src/resourcemanager.h
|
|
||||||
)
|
)
|
||||||
qt_add_library(main-widget STATIC ${SOURCES})
|
|
||||||
|
|
||||||
target_include_directories(main-widget PUBLIC src/)
|
# Add our Qt resources.qrc file to our application
|
||||||
if(ASSIMP_NEW_INTERFACE)
|
set(QTK_APP_SOURCES app/main.cpp
|
||||||
target_link_libraries(main-widget PRIVATE assimp::assimp)
|
app/examplescene.cpp app/examplescene.h
|
||||||
else()
|
app/mainwindow.cpp app/mainwindow.h app/mainwindow.ui
|
||||||
target_link_libraries(main-widget PRIVATE assimp)
|
app/resourcemanager.h
|
||||||
endif()
|
src/qtkresources.h.in
|
||||||
target_link_libraries(main-widget PUBLIC Qt6::OpenGLWidgets)
|
)
|
||||||
if(WIN32)
|
qt6_add_big_resources(QTK_APP_SOURCES resources.qrc)
|
||||||
find_package(OpenGL REQUIRED)
|
|
||||||
target_link_libraries(main-widget PUBLIC OpenGL::GL)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
target_link_libraries(qtk PUBLIC main-widget)
|
qt_add_executable(qtk-main ${QTK_APP_SOURCES})
|
||||||
|
target_include_directories(qtk-main PRIVATE src/ app/)
|
||||||
|
|
||||||
# Link qtk executable to main main-widget library
|
# Link qtk-main executable to main qtk-widget library
|
||||||
set_target_properties(qtk PROPERTIES
|
target_link_libraries(qtk-main PUBLIC qtk-widget)
|
||||||
|
|
||||||
|
set_target_properties(qtk-main PROPERTIES
|
||||||
WIN32_EXECUTABLE TRUE
|
WIN32_EXECUTABLE TRUE
|
||||||
MACOSX_BUNDLE TRUE
|
MACOSX_BUNDLE TRUE
|
||||||
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
|
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
|
||||||
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
|
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
|
||||||
)
|
)
|
||||||
|
install(TARGETS qtk-main
|
||||||
|
BUNDLE DESTINATION .
|
||||||
|
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
|
)
|
||||||
|
|
||||||
generate_export_header(main-widget)
|
generate_export_header(qtk-widget)
|
||||||
|
if(WIN32)
|
||||||
|
get_target_property(_qt6_qmake_location Qt6::qmake IMPORTED_LOCATION)
|
||||||
|
execute_process(COMMAND "${_qt6_qmake_location}" -query QT_INSTALL_PREFIX RESULT_VARIABLE return_code OUTPUT_VARIABLE qt6_install_prefix OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
file(TO_NATIVE_PATH "${qt6_install_prefix}/bin" qt6_install_prefix)
|
||||||
|
if(TARGET Qt6::windeployqt)
|
||||||
|
add_custom_command(TARGET qtk-main
|
||||||
|
POST_BUILD
|
||||||
|
COMMAND set PATH=%PATH%$<SEMICOLON>${qt6_install_prefix}
|
||||||
|
COMMAND Qt6::windeployqt --dir "${CMAKE_BINARY_DIR}/windeployqt" "$<TARGET_FILE_DIR:qtk-main>/$<TARGET_FILE_NAME:qtk-main>"
|
||||||
|
)
|
||||||
|
install(DIRECTORY "${CMAKE_BINARY_DIR}/windeployqt/" DESTINATION bin)
|
||||||
|
endif()
|
||||||
|
if(MSVC AND TARGET Qt6::qmake)
|
||||||
|
set(VSUSER_FILE ${CMAKE_CURRENT_BINARY_DIR}/qtk-main.vcxproj.user)
|
||||||
|
file(TO_NATIVE_PATH "${CMAKE_BINARY_DIR}/extern/assimp/assimp/bin" assimp_bin)
|
||||||
|
file(WRITE ${VSUSER_FILE} "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n")
|
||||||
|
file(APPEND ${VSUSER_FILE} "<Project xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n")
|
||||||
|
file(APPEND ${VSUSER_FILE} " <PropertyGroup>\n")
|
||||||
|
file(APPEND ${VSUSER_FILE} " <LocalDebuggerEnvironment>Path=$(SolutionDir)\\lib\\$(Configuration);${qt6_install_prefix};${assimp_bin};$(Path)\n")
|
||||||
|
file(APPEND ${VSUSER_FILE} "$(LocalDebuggerEnvironment)</LocalDebuggerEnvironment>\n")
|
||||||
|
file(APPEND ${VSUSER_FILE} " <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>\n")
|
||||||
|
file(APPEND ${VSUSER_FILE} " </PropertyGroup>\n")
|
||||||
|
file(APPEND ${VSUSER_FILE} "</Project>\n")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
130
README.md
130
README.md
|
@ -3,31 +3,110 @@
|
||||||
Practice project for learning about using OpenGL in Qt widget applications.
|
Practice project for learning about using OpenGL in Qt widget applications.
|
||||||
Model loader using [Assimp](https://assimp.org/) within a Qt widget application.
|
Model loader using [Assimp](https://assimp.org/) within a Qt widget application.
|
||||||
|
|
||||||
You can import your own models within `mainwdget.cpp`, inside the
|
You can import your own models within `app/examplescene.cpp`, inside the
|
||||||
`MainWidget::initObjects()` function. I've commented throughout the code there
|
`ExampleScene::init()` function. Rotations and translations
|
||||||
to explain which model or example I'm modifying. Rotations and translations
|
happen in `ExampleScene::update()`.
|
||||||
happen in `MainWidget::update()`, to get textures loading on models look into
|
|
||||||
[material files](http://www.paulbourke.net/dataformats/mtl/) and see some
|
|
||||||
examples in the `resources/models/` directory. For more in-depth examples, see
|
|
||||||
`scene.h` and `scene.cpp`
|
|
||||||
|
|
||||||
Can be built with cmake manually or using
|
To get textures loading on models look into [material files](http://www.paulbourke.net/dataformats/mtl/)
|
||||||
[Qt Creator](https://github.com/qt-creator/qt-creator).
|
and see some examples in the `resources/models/` directory.
|
||||||
For the build to be successful, I've found through testing on VMs that the system requires around 6GB of RAM.
|
|
||||||
This is mostly due to the large .obj files that are built into the project using [Qt Resource System](https://doc.qt.io/qt-6/resources.html)
|
|
||||||
|
### Source Builds
|
||||||
|
|
||||||
|
Builds are configured for CLion or [Qt Creator](https://github.com/qt-creator/qt-creator).
|
||||||
|
Simply open the root `CMakeLists.txt` with either of these editors and configurations will be loaded.
|
||||||
|
|
||||||
This project has been ported to Qt6, which is not yet available in Ubuntu apt repositories.
|
This project has been ported to Qt6, which is not yet available in Ubuntu apt repositories.
|
||||||
To run this project, you will *need* to install [Qt6 Open Source Binaries](https://www.qt.io/download-qt-installer) for your system.
|
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.
|
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 -
|
Once Qt6 is installed, to build and run `qtk` on Ubuntu -
|
||||||
|
```bash
|
||||||
|
sudo apt update -y && sudo apt install libassimp-dev cmake build-essential git
|
||||||
|
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
|
||||||
|
```
|
||||||
|
|
||||||
|
By default, the build will initialize Assimp as a git submodule and build from source.
|
||||||
|
We can turn this off by setting the `-DQTK_UPDATE_SUBMODULES=OFF` flag when running CMake.
|
||||||
|
This will greatly increase build speed, but we will need to make sure Assimp is available either system-wide or using a custom `CMAKE_PREFIX_PATH`.
|
||||||
|
Using `-DQTK_UPDATE_SUBMODULES=ON` supports providing assimp on cross-platform builds (Windows / Mac / Linux) and may be easier to configure.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo apt update -y && sudo apt install freeglut3-dev libassimp-dev cmake build-essential git
|
sudo apt update -y && sudo apt install freeglut3-dev libassimp-dev cmake build-essential git
|
||||||
git clone https://gitlab.com/shaunrd0/qtk
|
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 $(nprocs)
|
cmake -DQTK_UPDATE_SUBMODULES=OFF -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
|
# We can also provide a path to assimp -
|
||||||
|
#cmake -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
|
||||||
|
./qtk/build/qtk-main
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Windows / MacOS
|
||||||
|
|
||||||
|
If you are building on **Windows / Mac** and bringing your own installation of Assimp, consider setting the `-DASSIMP_NEW_INTERFACE` build flag.
|
||||||
|
```bash
|
||||||
|
cmake -DASSIMP_NEW_INTERFACE=ON -DQTK_UPDATE_SUBMODULES=OFF -DCMAKE_PREFIX_PATH=$HOME/Qt/6.3.1/gcc_64;/path/to/assimp/ -S qtk/ -B qtk/build/ && cmake --build qtk/build/ -j $(nproc --ignore=2) --target qtk-main
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
#### Development
|
||||||
|
|
||||||
|
This project uses version `15.0.5` of `clang-format` and `clang-tidy`.
|
||||||
|
Before merging any branch we should run `clang-tidy` followed by `clang-format`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone git@github.com:llvm/llvm-project.git -b llvmorg-15.0.5
|
||||||
|
cd llvm-project
|
||||||
|
cmake -B build -DLLVM_ENABLE_PROJECTS=clang -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi" -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" llvm
|
||||||
|
cmake --build build -j $(nproc --ignore=2)
|
||||||
|
sudo cmake --build build -j $(nproc --ignore=2) --target install
|
||||||
|
```
|
||||||
|
|
||||||
|
After this is done, we can check that for the correct version of `15.0.5`.
|
||||||
|
If this version is any earlier than `15.0.0`, running `clang-format` will fail because this project uses configuration options made available since `15.0.0`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
clang-format --version
|
||||||
|
clang-format version 15.0.5 (git@github.com:llvm/llvm-project.git 154e88af7ec97d9b9f389e55d45bf07108a9a097)
|
||||||
|
```
|
||||||
|
|
||||||
|
CLion has integration for IDE code reformatting actions with `clang-format`. If you're using CLion, the `.clang-format` configuration will be picked up by CLion automatically.
|
||||||
|
|
||||||
|
`clang-tidy` can be run with the following commands.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Move to the root of the repo
|
||||||
|
cd qtk
|
||||||
|
# Build
|
||||||
|
cmake -B build && cmake --build build
|
||||||
|
cd build
|
||||||
|
# Run clang-tidy from within build directory
|
||||||
|
clang-tidy --fix --config-file=../.clang-tidy ../src/*.cpp ../src/*.h ../app/*.cpp ../app/*.h
|
||||||
|
```
|
||||||
|
|
||||||
|
And finally `clang-format` can be run with git integration (or CLion if you prefer).
|
||||||
|
Don't forget to commit the reformatted files.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# If we want to format the last N commits
|
||||||
|
# git clang-format HEAD~N
|
||||||
|
# 3 commits
|
||||||
|
git clang-format HEAD~3
|
||||||
|
changed files:
|
||||||
|
app/examplescene.h
|
||||||
|
app/mainwindow.h
|
||||||
|
src/abstractscene.cpp
|
||||||
|
src/skybox.h
|
||||||
|
src/texture.cpp
|
||||||
|
src/texture.h
|
||||||
|
src/transform3D.h
|
||||||
|
```
|
||||||
|
|
||||||
|
### Controls
|
||||||
|
|
||||||
You can fly around the scene if you hold the right mouse button and use WASD.
|
You can fly around the scene if you hold the right mouse button and use WASD.
|
||||||
If you see a small triangle floating by a model it represents the light source
|
If you see a small triangle floating by a model it represents the light source
|
||||||
that is being used for the shader rendering the model. These appear on models
|
that is being used for the shader rendering the model. These appear on models
|
||||||
|
@ -43,8 +122,30 @@ Spartan with normals -
|
||||||
|
|
||||||
![](resources/spartan-normals.png)
|
![](resources/spartan-normals.png)
|
||||||
|
|
||||||
## Model Artists
|
|
||||||
|
|
||||||
|
### QtkWidget in Qt Creator
|
||||||
|
|
||||||
|
The `QtkWidget` class is exported as a shared library for use in Qt Creator's design mode.
|
||||||
|
We can add more QtkWidgets to view and render the scene from multiple perspectives.
|
||||||
|
There is still some work to be done here, so there isn't a builtin way to add an additional view within the application.
|
||||||
|
|
||||||
|
![](resources/qtk-views.png)
|
||||||
|
|
||||||
|
After building Qtk, we can drag and drop an `OpenGL Widget` onto the `mainwindow.ui`.
|
||||||
|
Then right-click the new OpenGLWidget and `Promote To->QtkWidget` to add a second view.
|
||||||
|
|
||||||
|
![](resources/qtk-views-setup.png)
|
||||||
|
|
||||||
|
If we demote or delete all widgets in `mainwindow.ui` and rebuild the project, Qt Creator will drop `QtkWidget` from the list of possible promoted widgets.
|
||||||
|
Add an `OpenGL Widget` to the UI, right-click it and navigate to `Promote Widget...` and enter the information below.
|
||||||
|
|
||||||
|
![](resources/qtk-reference.png)
|
||||||
|
|
||||||
|
After you fill out the `New Promoted Class` form, click `Add` *and*`Promote`, then rebuild.
|
||||||
|
After following these steps Qt Creator will list `QtkWidget` as an option to promote `OpenGL Widgets` again.
|
||||||
|
|
||||||
|
|
||||||
|
## Model Artists
|
||||||
|
|
||||||
"Alien Hominid" (https://skfb.ly/onStx) by Nwilly_art is licensed under Creative Commons Attribution (http://creativecommons.org/licenses/by/4.0/).
|
"Alien Hominid" (https://skfb.ly/onStx) by Nwilly_art is licensed under Creative Commons Attribution (http://creativecommons.org/licenses/by/4.0/).
|
||||||
|
|
||||||
|
@ -59,4 +160,3 @@ Modified (learnopengl.com) material assignment (Joey de Vries) for easier load i
|
||||||
"Terror-bird (NHMW-Geo 2012/0007/0001)" (https://skfb.ly/onAWy) by Natural History Museum Vienna is licensed under Creative Commons Attribution-NonCommercial (http://creativecommons.org/licenses/by-nc/4.0/).
|
"Terror-bird (NHMW-Geo 2012/0007/0001)" (https://skfb.ly/onAWy) by Natural History Museum Vienna is licensed under Creative Commons Attribution-NonCommercial (http://creativecommons.org/licenses/by-nc/4.0/).
|
||||||
|
|
||||||
"Golden Lion Sitting OBJ Low Poly FREE" (https://skfb.ly/onZAH) by LordSamueliSolo is licensed under Creative Commons Attribution (http://creativecommons.org/licenses/by/4.0/).
|
"Golden Lion Sitting OBJ Low Poly FREE" (https://skfb.ly/onZAH) by LordSamueliSolo is licensed under Creative Commons Attribution (http://creativecommons.org/licenses/by/4.0/).
|
||||||
|
|
||||||
|
|
|
@ -6,50 +6,49 @@
|
||||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||||
##############################################################################*/
|
##############################################################################*/
|
||||||
|
|
||||||
|
#include <abstractscene.h>
|
||||||
#include <camera3d.h>
|
#include <camera3d.h>
|
||||||
#include <texture.h>
|
#include <examplescene.h>
|
||||||
#include <meshrenderer.h>
|
#include <meshrenderer.h>
|
||||||
#include <model.h>
|
#include <model.h>
|
||||||
#include <resourcemanager.h>
|
#include <resourcemanager.h>
|
||||||
|
#include <texture.h>
|
||||||
|
|
||||||
#include <scene.h>
|
using namespace Qtk;
|
||||||
|
|
||||||
|
|
||||||
Camera3D Scene::mCamera;
|
|
||||||
QMatrix4x4 Scene::mProjection;
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Constructors, Destructors
|
* Constructors, Destructors
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
Scene::Scene()
|
ExampleScene::ExampleScene() {
|
||||||
{
|
Camera().transform().setTranslation(0.0f, 0.0f, 20.0f);
|
||||||
mCamera.transform().setTranslation(0.0f, 0.0f, 20.0f);
|
Camera().transform().setRotation(-5.0f, 0.0f, 1.0f, 0.0f);
|
||||||
mCamera.transform().setRotation(-5.0f, 0.0f, 1.0f, 0.0f);
|
|
||||||
|
|
||||||
init();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Scene::~Scene()
|
ExampleScene::~ExampleScene() {
|
||||||
{
|
|
||||||
delete mTestPhong;
|
delete mTestPhong;
|
||||||
delete mTestSpecular;
|
delete mTestSpecular;
|
||||||
delete mTestDiffuse;
|
delete mTestDiffuse;
|
||||||
delete mTestAmbient;
|
delete mTestAmbient;
|
||||||
for (auto & mesh : mMeshes) delete mesh;
|
for(auto & mesh : mMeshes) {
|
||||||
for (auto & model : mModels) delete model;
|
delete mesh;
|
||||||
|
}
|
||||||
|
for(auto & model : mModels) {
|
||||||
|
delete model;
|
||||||
|
}
|
||||||
|
delete mSkybox;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Public Member Functions
|
* Public Member Functions
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
void Scene::init()
|
void ExampleScene::init() {
|
||||||
{
|
auto * sb = new Qtk::Skybox("Skybox");
|
||||||
|
setSkybox(sb);
|
||||||
|
|
||||||
// Initialize Phong example cube
|
// Initialize Phong example cube
|
||||||
mTestPhong = new MeshRenderer("phong", Cube());
|
mTestPhong = new Qtk::MeshRenderer("phong", Qtk::Cube());
|
||||||
mTestPhong->mTransform.setTranslation(3.0f, 0.0f, -2.0f);
|
mTestPhong->mTransform.setTranslation(3.0f, 0.0f, -2.0f);
|
||||||
mTestPhong->setShaders(":/solid-phong.vert", ":/solid-phong.frag");
|
mTestPhong->setShaders(":/solid-phong.vert", ":/solid-phong.frag");
|
||||||
mTestPhong->init();
|
mTestPhong->init();
|
||||||
|
@ -64,18 +63,17 @@ void Scene::init()
|
||||||
mTestPhong->mNBO.create();
|
mTestPhong->mNBO.create();
|
||||||
mTestPhong->mNBO.setUsagePattern(QOpenGLBuffer::StaticDraw);
|
mTestPhong->mNBO.setUsagePattern(QOpenGLBuffer::StaticDraw);
|
||||||
mTestPhong->mNBO.bind();
|
mTestPhong->mNBO.bind();
|
||||||
mTestPhong->mNBO.allocate(mTestPhong->getNormals().data(),
|
mTestPhong->mNBO.allocate(
|
||||||
mTestPhong->getNormals().size()
|
mTestPhong->getNormals().data(),
|
||||||
* sizeof(mTestPhong->getNormals()[0]));
|
mTestPhong->getNormals().size() * sizeof(mTestPhong->getNormals()[0]));
|
||||||
mTestPhong->mProgram.enableAttributeArray(1);
|
mTestPhong->mProgram.enableAttributeArray(1);
|
||||||
mTestPhong->mProgram.setAttributeBuffer(1, GL_FLOAT, 0, 3, sizeof(QVector3D));
|
mTestPhong->mProgram.setAttributeBuffer(1, GL_FLOAT, 0, 3, sizeof(QVector3D));
|
||||||
mTestPhong->mNBO.release();
|
mTestPhong->mNBO.release();
|
||||||
mTestPhong->mVAO.release();
|
mTestPhong->mVAO.release();
|
||||||
mTestPhong->mProgram.release();
|
mTestPhong->mProgram.release();
|
||||||
|
|
||||||
|
|
||||||
// Initialize Ambient example cube
|
// Initialize Ambient example cube
|
||||||
mTestAmbient = new MeshRenderer("ambient", Cube());
|
mTestAmbient = new Qtk::MeshRenderer("ambient", Cube());
|
||||||
mTestAmbient->mTransform.setTranslation(7.0f, 0.0f, -2.0f);
|
mTestAmbient->mTransform.setTranslation(7.0f, 0.0f, -2.0f);
|
||||||
mTestAmbient->setShaders(":/solid-ambient.vert", ":/solid-ambient.frag");
|
mTestAmbient->setShaders(":/solid-ambient.vert", ":/solid-ambient.frag");
|
||||||
mTestAmbient->init();
|
mTestAmbient->init();
|
||||||
|
@ -88,18 +86,19 @@ void Scene::init()
|
||||||
mTestAmbient->mNBO.create();
|
mTestAmbient->mNBO.create();
|
||||||
mTestAmbient->mNBO.setUsagePattern(QOpenGLBuffer::StaticDraw);
|
mTestAmbient->mNBO.setUsagePattern(QOpenGLBuffer::StaticDraw);
|
||||||
mTestAmbient->mNBO.bind();
|
mTestAmbient->mNBO.bind();
|
||||||
mTestAmbient->mNBO.allocate(mTestAmbient->getNormals().data(),
|
mTestAmbient->mNBO.allocate(
|
||||||
mTestAmbient->getNormals().size()
|
mTestAmbient->getNormals().data(),
|
||||||
* sizeof(mTestAmbient->getNormals()[0]));
|
mTestAmbient->getNormals().size()
|
||||||
|
* sizeof(mTestAmbient->getNormals()[0]));
|
||||||
mTestAmbient->mProgram.enableAttributeArray(1);
|
mTestAmbient->mProgram.enableAttributeArray(1);
|
||||||
mTestAmbient->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
|
mTestAmbient->mProgram.setAttributeBuffer(
|
||||||
3, sizeof(QVector3D));
|
1, GL_FLOAT, 0, 3, sizeof(QVector3D));
|
||||||
mTestAmbient->mNBO.release();
|
mTestAmbient->mNBO.release();
|
||||||
mTestAmbient->mVAO.release();
|
mTestAmbient->mVAO.release();
|
||||||
mTestAmbient->mProgram.release();
|
mTestAmbient->mProgram.release();
|
||||||
|
|
||||||
// Initialize Diffuse example cube
|
// Initialize Diffuse example cube
|
||||||
mTestDiffuse = new MeshRenderer("diffuse", Cube());
|
mTestDiffuse = new Qtk::MeshRenderer("diffuse", Cube());
|
||||||
mTestDiffuse->mTransform.setTranslation(9.0f, 0.0f, -2.0f);
|
mTestDiffuse->mTransform.setTranslation(9.0f, 0.0f, -2.0f);
|
||||||
mTestDiffuse->setShaders(":/solid-diffuse.vert", ":/solid-diffuse.frag");
|
mTestDiffuse->setShaders(":/solid-diffuse.vert", ":/solid-diffuse.frag");
|
||||||
mTestDiffuse->init();
|
mTestDiffuse->init();
|
||||||
|
@ -112,18 +111,19 @@ void Scene::init()
|
||||||
mTestDiffuse->mNBO.create();
|
mTestDiffuse->mNBO.create();
|
||||||
mTestDiffuse->mNBO.setUsagePattern(QOpenGLBuffer::StaticDraw);
|
mTestDiffuse->mNBO.setUsagePattern(QOpenGLBuffer::StaticDraw);
|
||||||
mTestDiffuse->mNBO.bind();
|
mTestDiffuse->mNBO.bind();
|
||||||
mTestDiffuse->mNBO.allocate(mTestDiffuse->getNormals().data(),
|
mTestDiffuse->mNBO.allocate(
|
||||||
mTestDiffuse->getNormals().size()
|
mTestDiffuse->getNormals().data(),
|
||||||
* sizeof(mTestDiffuse->getNormals()[0]));
|
mTestDiffuse->getNormals().size()
|
||||||
|
* sizeof(mTestDiffuse->getNormals()[0]));
|
||||||
mTestDiffuse->mProgram.enableAttributeArray(1);
|
mTestDiffuse->mProgram.enableAttributeArray(1);
|
||||||
mTestDiffuse->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
|
mTestDiffuse->mProgram.setAttributeBuffer(
|
||||||
3, sizeof(QVector3D));
|
1, GL_FLOAT, 0, 3, sizeof(QVector3D));
|
||||||
mTestDiffuse->mNBO.release();
|
mTestDiffuse->mNBO.release();
|
||||||
mTestDiffuse->mVAO.release();
|
mTestDiffuse->mVAO.release();
|
||||||
mTestDiffuse->mProgram.release();
|
mTestDiffuse->mProgram.release();
|
||||||
|
|
||||||
// Initialize Specular example cube
|
// Initialize Specular example cube
|
||||||
mTestSpecular = new MeshRenderer("specular", Cube());
|
mTestSpecular = new Qtk::MeshRenderer("specular", Cube());
|
||||||
mTestSpecular->mTransform.setTranslation(11.0f, 0.0f, -2.0f);
|
mTestSpecular->mTransform.setTranslation(11.0f, 0.0f, -2.0f);
|
||||||
mTestSpecular->setShaders(":/solid-specular.vert", ":/solid-specular.frag");
|
mTestSpecular->setShaders(":/solid-specular.vert", ":/solid-specular.frag");
|
||||||
mTestSpecular->init();
|
mTestSpecular->init();
|
||||||
|
@ -138,12 +138,13 @@ void Scene::init()
|
||||||
mTestSpecular->mNBO.create();
|
mTestSpecular->mNBO.create();
|
||||||
mTestSpecular->mNBO.setUsagePattern(QOpenGLBuffer::StaticDraw);
|
mTestSpecular->mNBO.setUsagePattern(QOpenGLBuffer::StaticDraw);
|
||||||
mTestSpecular->mNBO.bind();
|
mTestSpecular->mNBO.bind();
|
||||||
mTestSpecular->mNBO.allocate(mTestSpecular->getNormals().data(),
|
mTestSpecular->mNBO.allocate(
|
||||||
mTestSpecular->getNormals().size()
|
mTestSpecular->getNormals().data(),
|
||||||
* sizeof(mTestSpecular->getNormals()[0]));
|
mTestSpecular->getNormals().size()
|
||||||
|
* sizeof(mTestSpecular->getNormals()[0]));
|
||||||
mTestSpecular->mProgram.enableAttributeArray(1);
|
mTestSpecular->mProgram.enableAttributeArray(1);
|
||||||
mTestSpecular->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
|
mTestSpecular->mProgram.setAttributeBuffer(
|
||||||
3, sizeof(QVector3D));
|
1, GL_FLOAT, 0, 3, sizeof(QVector3D));
|
||||||
mTestSpecular->mNBO.release();
|
mTestSpecular->mNBO.release();
|
||||||
mTestSpecular->mVAO.release();
|
mTestSpecular->mVAO.release();
|
||||||
mTestSpecular->mProgram.release();
|
mTestSpecular->mProgram.release();
|
||||||
|
@ -151,51 +152,52 @@ void Scene::init()
|
||||||
//
|
//
|
||||||
// Model loading
|
// Model loading
|
||||||
|
|
||||||
mModels.push_back(new 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
|
// Sometimes model textures need flipped in certain directions
|
||||||
mModels.back()->flipTexture("diffuse.jpg", false, true);
|
mModels.back()->flipTexture("diffuse.jpg", false, true);
|
||||||
mModels.back()->mTransform.setTranslation(0.0f, 0.0f, -10.0f);
|
mModels.back()->mTransform.setTranslation(0.0f, 0.0f, -10.0f);
|
||||||
|
|
||||||
mModels.push_back(new Model("bird", ":/models/bird/bird.obj"));
|
mModels.push_back(new Qtk::Model("bird", ":/models/bird/bird.obj"));
|
||||||
mModels.back()->mTransform.setTranslation(2.0f, 2.0f, -10.0f);
|
mModels.back()->mTransform.setTranslation(2.0f, 2.0f, -10.0f);
|
||||||
// Sometimes the models are very large
|
// Sometimes the models are very large
|
||||||
mModels.back()->mTransform.scale(0.0025f);
|
mModels.back()->mTransform.scale(0.0025f);
|
||||||
mModels.back()->mTransform.rotate(-110.0f, 0.0f, 1.0f, 0.0f);
|
mModels.back()->mTransform.rotate(-110.0f, 0.0f, 1.0f, 0.0f);
|
||||||
|
|
||||||
mModels.push_back(new Model("lion", ":/models/lion/lion.obj"));
|
mModels.push_back(new Qtk::Model("lion", ":/models/lion/lion.obj"));
|
||||||
mModels.back()->mTransform.setTranslation(-3.0f, -1.0f, -10.0f);
|
mModels.back()->mTransform.setTranslation(-3.0f, -1.0f, -10.0f);
|
||||||
mModels.back()->mTransform.scale(0.15f);
|
mModels.back()->mTransform.scale(0.15f);
|
||||||
|
|
||||||
mModels.push_back(new 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.setTranslation(2.0f, -1.0f, -5.0f);
|
||||||
mModels.back()->mTransform.scale(0.15f);
|
mModels.back()->mTransform.scale(0.15f);
|
||||||
|
|
||||||
mModels.push_back(new Model("scythe", ":/models/scythe/scythe.obj"));
|
mModels.push_back(new Qtk::Model("scythe", ":/models/scythe/scythe.obj"));
|
||||||
mModels.back()->mTransform.setTranslation(-6.0f, 0.0f, -10.0f);
|
mModels.back()->mTransform.setTranslation(-6.0f, 0.0f, -10.0f);
|
||||||
mModels.back()->mTransform.rotate(-90.0f, 1.0f, 0.0f, 0.0f);
|
mModels.back()->mTransform.rotate(-90.0f, 1.0f, 0.0f, 0.0f);
|
||||||
mModels.back()->mTransform.rotate(90.0f, 0.0f, 1.0f, 0.0f);
|
mModels.back()->mTransform.rotate(90.0f, 0.0f, 1.0f, 0.0f);
|
||||||
|
|
||||||
mModels.push_back(new 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);
|
mModels.back()->mTransform.setTranslation(-1.5f, 0.5f, -2.0f);
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Building example mesh objects
|
// Building example mesh objects
|
||||||
|
|
||||||
// Render an alien with specular
|
// Render an alien with specular
|
||||||
// Test alien Model with phong lighting and specular mapping
|
// Test alien Model with phong lighting and specular mapping
|
||||||
mMeshes.push_back(
|
mMeshes.push_back(new Qtk::MeshRenderer(
|
||||||
new MeshRenderer("alienTestLight", Triangle(QTK_DRAW_ELEMENTS)));
|
"alienTestLight", Triangle(Qtk::QTK_DRAW_ELEMENTS)));
|
||||||
mMeshes.back()->mTransform.setTranslation(4.0f, 1.5f, 10.0f);
|
mMeshes.back()->mTransform.setTranslation(4.0f, 1.5f, 10.0f);
|
||||||
mMeshes.back()->mTransform.scale(0.25f);
|
mMeshes.back()->mTransform.scale(0.25f);
|
||||||
// This function changes values we have allocated in a buffer, so init() after
|
// This function changes values we have allocated in a buffer, so init() after
|
||||||
mMeshes.back()->setColor(GREEN);
|
mMeshes.back()->setColor(GREEN);
|
||||||
mMeshes.back()->init();
|
mMeshes.back()->init();
|
||||||
|
|
||||||
mModels.push_back(
|
mModels.push_back(new Qtk::Model(
|
||||||
new Model("alienTest", ":/models/alien-hominid/alien.obj",
|
"alienTest", ":/models/alien-hominid/alien.obj", ":/model-specular.vert",
|
||||||
":/model-specular.vert", ":/model-specular.frag")
|
":/model-specular.frag"));
|
||||||
);
|
|
||||||
mModels.back()->mTransform.setTranslation(3.0f, -1.0f, 10.0f);
|
mModels.back()->mTransform.setTranslation(3.0f, -1.0f, 10.0f);
|
||||||
mModels.back()->mTransform.scale(0.15f);
|
mModels.back()->mTransform.scale(0.15f);
|
||||||
mModels.back()->setUniform("uMaterial.ambient", QVector3D(1.0f, 1.0f, 1.0f));
|
mModels.back()->setUniform("uMaterial.ambient", QVector3D(1.0f, 1.0f, 1.0f));
|
||||||
|
@ -210,21 +212,18 @@ void Scene::init()
|
||||||
mModels.back()->setUniform("uLight.diffuse", QVector3D(1.0f, 1.0f, 1.0f));
|
mModels.back()->setUniform("uLight.diffuse", QVector3D(1.0f, 1.0f, 1.0f));
|
||||||
mModels.back()->setUniform("uLight.specular", QVector3D(1.0f, 1.0f, 1.0f));
|
mModels.back()->setUniform("uLight.specular", QVector3D(1.0f, 1.0f, 1.0f));
|
||||||
|
|
||||||
|
|
||||||
// Test spartan Model with phong lighting, specular and normal mapping
|
// Test spartan Model with phong lighting, specular and normal mapping
|
||||||
mMeshes.push_back(
|
mMeshes.push_back(
|
||||||
new 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.setTranslation(1.0f, 1.5f, 10.0f);
|
||||||
mMeshes.back()->mTransform.scale(0.25f);
|
mMeshes.back()->mTransform.scale(0.25f);
|
||||||
// This function changes values we have allocated in a buffer, so init() after
|
// This function changes values we have allocated in a buffer, so init() after
|
||||||
mMeshes.back()->setColor(GREEN);
|
mMeshes.back()->setColor(GREEN);
|
||||||
mMeshes.back()->init();
|
mMeshes.back()->init();
|
||||||
|
|
||||||
mModels.push_back(
|
mModels.push_back(new Qtk::Model(
|
||||||
new Model("spartanTest", ":/models/spartan/spartan.obj",
|
"spartanTest", ":/models/spartan/spartan.obj", ":/model-normals.vert",
|
||||||
":/model-normals.vert", ":/model-normals.frag")
|
":/model-normals.frag"));
|
||||||
);
|
|
||||||
mModels.back()->mTransform.setTranslation(0.0f, -1.0f, 10.0f);
|
mModels.back()->mTransform.setTranslation(0.0f, -1.0f, 10.0f);
|
||||||
mModels.back()->mTransform.scale(2.0f);
|
mModels.back()->mTransform.scale(2.0f);
|
||||||
mModels.back()->setUniform("uMaterial.ambient", QVector3D(1.0f, 1.0f, 1.0f));
|
mModels.back()->setUniform("uMaterial.ambient", QVector3D(1.0f, 1.0f, 1.0f));
|
||||||
|
@ -238,9 +237,9 @@ void Scene::init()
|
||||||
mModels.back()->setUniform("uLight.diffuse", QVector3D(1.0f, 1.0f, 1.0f));
|
mModels.back()->setUniform("uLight.diffuse", QVector3D(1.0f, 1.0f, 1.0f));
|
||||||
mModels.back()->setUniform("uLight.specular", QVector3D(1.0f, 1.0f, 1.0f));
|
mModels.back()->setUniform("uLight.specular", QVector3D(1.0f, 1.0f, 1.0f));
|
||||||
|
|
||||||
|
|
||||||
// Test basic cube with phong.vert and phong.frag shaders
|
// Test basic cube with phong.vert and phong.frag shaders
|
||||||
mMeshes.push_back(new MeshRenderer("testLight", Triangle(QTK_DRAW_ELEMENTS)));
|
mMeshes.push_back(
|
||||||
|
new Qtk::MeshRenderer("testLight", Triangle(QTK_DRAW_ELEMENTS)));
|
||||||
mMeshes.back()->mTransform.setTranslation(5.0f, 1.25f, 10.0f);
|
mMeshes.back()->mTransform.setTranslation(5.0f, 1.25f, 10.0f);
|
||||||
mMeshes.back()->mTransform.scale(0.25f);
|
mMeshes.back()->mTransform.scale(0.25f);
|
||||||
mMeshes.back()->setDrawType(GL_LINE_LOOP);
|
mMeshes.back()->setDrawType(GL_LINE_LOOP);
|
||||||
|
@ -248,7 +247,7 @@ void Scene::init()
|
||||||
mMeshes.back()->setColor(GREEN);
|
mMeshes.back()->setColor(GREEN);
|
||||||
mMeshes.back()->init();
|
mMeshes.back()->init();
|
||||||
|
|
||||||
mMeshes.push_back(new 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()->mTransform.setTranslation(5.0f, 0.0f, 10.0f);
|
||||||
mMeshes.back()->setShaders(":/phong.vert", ":/phong.frag");
|
mMeshes.back()->setShaders(":/phong.vert", ":/phong.frag");
|
||||||
mMeshes.back()->setColor(QVector3D(0.0f, 0.25f, 0.0f));
|
mMeshes.back()->setColor(QVector3D(0.0f, 0.25f, 0.0f));
|
||||||
|
@ -259,12 +258,13 @@ void Scene::init()
|
||||||
mMeshes.back()->mNBO.create();
|
mMeshes.back()->mNBO.create();
|
||||||
mMeshes.back()->mNBO.bind();
|
mMeshes.back()->mNBO.bind();
|
||||||
|
|
||||||
mMeshes.back()->mNBO.allocate(mMeshes.back()->getNormals().data(),
|
mMeshes.back()->mNBO.allocate(
|
||||||
mMeshes.back()->getNormals().size()
|
mMeshes.back()->getNormals().data(),
|
||||||
* sizeof(mMeshes.back()->getNormals()[0]));
|
mMeshes.back()->getNormals().size()
|
||||||
|
* sizeof(mMeshes.back()->getNormals()[0]));
|
||||||
mMeshes.back()->mProgram.enableAttributeArray(1);
|
mMeshes.back()->mProgram.enableAttributeArray(1);
|
||||||
mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
|
mMeshes.back()->mProgram.setAttributeBuffer(
|
||||||
3, sizeof(QVector3D));
|
1, GL_FLOAT, 0, 3, sizeof(QVector3D));
|
||||||
|
|
||||||
mMeshes.back()->mNBO.release();
|
mMeshes.back()->mNBO.release();
|
||||||
mMeshes.back()->mVAO.release();
|
mMeshes.back()->mVAO.release();
|
||||||
|
@ -288,24 +288,25 @@ void Scene::init()
|
||||||
// Create simple shapes using MeshRenderer class and data in mesh.h
|
// Create simple shapes using MeshRenderer class and data in mesh.h
|
||||||
|
|
||||||
mMeshes.push_back(
|
mMeshes.push_back(
|
||||||
new MeshRenderer("rightTriangle", Triangle(QTK_DRAW_ELEMENTS)));
|
new Qtk::MeshRenderer("rightTriangle", Triangle(QTK_DRAW_ELEMENTS)));
|
||||||
mMeshes.back()->mTransform.setTranslation(-5.0f, 0.0f, -2.0f);
|
mMeshes.back()->mTransform.setTranslation(-5.0f, 0.0f, -2.0f);
|
||||||
|
|
||||||
mMeshes.push_back(new MeshRenderer("centerCube", Cube(QTK_DRAW_ELEMENTS)));
|
mMeshes.push_back(
|
||||||
|
new Qtk::MeshRenderer("centerCube", Cube(QTK_DRAW_ELEMENTS)));
|
||||||
mMeshes.back()->mTransform.setTranslation(-7.0f, 0.0f, -2.0f);
|
mMeshes.back()->mTransform.setTranslation(-7.0f, 0.0f, -2.0f);
|
||||||
|
|
||||||
mMeshes.push_back(
|
mMeshes.push_back(
|
||||||
new MeshRenderer("leftTriangle", Triangle(QTK_DRAW_ELEMENTS)));
|
new Qtk::MeshRenderer("leftTriangle", Triangle(QTK_DRAW_ELEMENTS)));
|
||||||
mMeshes.back()->mTransform.setTranslation(-9.0f, 0.0f, -2.0f);
|
mMeshes.back()->mTransform.setTranslation(-9.0f, 0.0f, -2.0f);
|
||||||
mMeshes.back()->setDrawType(GL_LINE_LOOP);
|
mMeshes.back()->setDrawType(GL_LINE_LOOP);
|
||||||
|
|
||||||
mMeshes.push_back(
|
mMeshes.push_back(
|
||||||
new MeshRenderer("topTriangle", Triangle(QTK_DRAW_ELEMENTS)));
|
new Qtk::MeshRenderer("topTriangle", Triangle(QTK_DRAW_ELEMENTS)));
|
||||||
mMeshes.back()->mTransform.setTranslation(-7.0f, 2.0f, -2.0f);
|
mMeshes.back()->mTransform.setTranslation(-7.0f, 2.0f, -2.0f);
|
||||||
mMeshes.back()->mTransform.scale(0.25f);
|
mMeshes.back()->mTransform.scale(0.25f);
|
||||||
|
|
||||||
mMeshes.push_back(
|
mMeshes.push_back(
|
||||||
new MeshRenderer("bottomTriangle", Triangle(QTK_DRAW_ELEMENTS)));
|
new Qtk::MeshRenderer("bottomTriangle", Triangle(QTK_DRAW_ELEMENTS)));
|
||||||
mMeshes.back()->mTransform.setTranslation(-7.0f, -2.0f, -2.0f);
|
mMeshes.back()->mTransform.setTranslation(-7.0f, -2.0f, -2.0f);
|
||||||
mMeshes.back()->mTransform.scale(0.25f);
|
mMeshes.back()->mTransform.scale(0.25f);
|
||||||
mMeshes.back()->setDrawType(GL_LINE_LOOP);
|
mMeshes.back()->setDrawType(GL_LINE_LOOP);
|
||||||
|
@ -318,7 +319,7 @@ void Scene::init()
|
||||||
|
|
||||||
// RGB Normals cube to show normals are correct with QTK_DRAW_ARRAYS
|
// RGB Normals cube to show normals are correct with QTK_DRAW_ARRAYS
|
||||||
mMeshes.push_back(
|
mMeshes.push_back(
|
||||||
new MeshRenderer("rgbNormalsCubeArraysTest", Cube(QTK_DRAW_ARRAYS)));
|
new Qtk::MeshRenderer("rgbNormalsCubeArraysTest", Cube(QTK_DRAW_ARRAYS)));
|
||||||
mMeshes.back()->mTransform.setTranslation(5.0f, 0.0f, 4.0f);
|
mMeshes.back()->mTransform.setTranslation(5.0f, 0.0f, 4.0f);
|
||||||
mMeshes.back()->setShaders(":/rgb-normals.vert", ":/rgb-normals.frag");
|
mMeshes.back()->setShaders(":/rgb-normals.vert", ":/rgb-normals.frag");
|
||||||
mMeshes.back()->init();
|
mMeshes.back()->init();
|
||||||
|
@ -327,21 +328,21 @@ void Scene::init()
|
||||||
mMeshes.back()->mNBO.bind();
|
mMeshes.back()->mNBO.bind();
|
||||||
mMeshes.back()->mProgram.bind();
|
mMeshes.back()->mProgram.bind();
|
||||||
|
|
||||||
mMeshes.back()->mNBO.allocate(mMeshes.back()->getNormals().data(),
|
mMeshes.back()->mNBO.allocate(
|
||||||
mMeshes.back()->getNormals().size()
|
mMeshes.back()->getNormals().data(),
|
||||||
* sizeof(mMeshes.back()->getNormals()[0]));
|
mMeshes.back()->getNormals().size()
|
||||||
|
* sizeof(mMeshes.back()->getNormals()[0]));
|
||||||
mMeshes.back()->mProgram.enableAttributeArray(1);
|
mMeshes.back()->mProgram.enableAttributeArray(1);
|
||||||
mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
|
mMeshes.back()->mProgram.setAttributeBuffer(
|
||||||
3, sizeof(QVector3D));
|
1, GL_FLOAT, 0, 3, sizeof(QVector3D));
|
||||||
|
|
||||||
mMeshes.back()->mProgram.release();
|
mMeshes.back()->mProgram.release();
|
||||||
mMeshes.back()->mNBO.release();
|
mMeshes.back()->mNBO.release();
|
||||||
mMeshes.back()->mVAO.release();
|
mMeshes.back()->mVAO.release();
|
||||||
|
|
||||||
// RGB Normals cube to show normals are correct with QTK_DRAW_ELEMENTS_NORMALS
|
// RGB Normals cube to show normals are correct with QTK_DRAW_ELEMENTS_NORMALS
|
||||||
mMeshes.push_back(
|
mMeshes.push_back(new Qtk::MeshRenderer(
|
||||||
new MeshRenderer("rgbNormalsCubeElementsTest",
|
"rgbNormalsCubeElementsTest", Cube(QTK_DRAW_ELEMENTS_NORMALS)));
|
||||||
Cube(QTK_DRAW_ELEMENTS_NORMALS)));
|
|
||||||
mMeshes.back()->mTransform.setTranslation(5.0f, 0.0f, 2.0f);
|
mMeshes.back()->mTransform.setTranslation(5.0f, 0.0f, 2.0f);
|
||||||
mMeshes.back()->setShaders(":/rgb-normals.vert", ":/rgb-normals.frag");
|
mMeshes.back()->setShaders(":/rgb-normals.vert", ":/rgb-normals.frag");
|
||||||
mMeshes.back()->init();
|
mMeshes.back()->init();
|
||||||
|
@ -350,48 +351,52 @@ void Scene::init()
|
||||||
mMeshes.back()->mNBO.bind();
|
mMeshes.back()->mNBO.bind();
|
||||||
mMeshes.back()->mProgram.bind();
|
mMeshes.back()->mProgram.bind();
|
||||||
|
|
||||||
mMeshes.back()->mNBO.allocate(mMeshes.back()->getNormals().data(),
|
mMeshes.back()->mNBO.allocate(
|
||||||
mMeshes.back()->getNormals().size()
|
mMeshes.back()->getNormals().data(),
|
||||||
* sizeof(mMeshes.back()->getNormals()[0]));
|
mMeshes.back()->getNormals().size()
|
||||||
|
* sizeof(mMeshes.back()->getNormals()[0]));
|
||||||
mMeshes.back()->mProgram.enableAttributeArray(1);
|
mMeshes.back()->mProgram.enableAttributeArray(1);
|
||||||
mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
|
mMeshes.back()->mProgram.setAttributeBuffer(
|
||||||
3, sizeof(QVector3D));
|
1, GL_FLOAT, 0, 3, sizeof(QVector3D));
|
||||||
|
|
||||||
mMeshes.back()->mProgram.release();
|
mMeshes.back()->mProgram.release();
|
||||||
mMeshes.back()->mNBO.release();
|
mMeshes.back()->mNBO.release();
|
||||||
mMeshes.back()->mVAO.release();
|
mMeshes.back()->mVAO.release();
|
||||||
|
|
||||||
// Texturing a cube using texture coordinates and glDrawArrays
|
// 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
|
// + UVs required duplicating element position data from QTK_DRAW_ELEMENTS
|
||||||
// + This is because the same position must use different UV coordinates
|
// + This is because the same position must use different UV coordinates
|
||||||
mMeshes.push_back(
|
mMeshes.push_back(
|
||||||
new MeshRenderer("uvCubeArraysTest", Cube(QTK_DRAW_ARRAYS)));
|
new Qtk::MeshRenderer("uvCubeArraysTest", Cube(QTK_DRAW_ARRAYS)));
|
||||||
mMeshes.back()->mTransform.setTranslation(-3.0f, 0.0f, -2.0f);
|
mMeshes.back()->mTransform.setTranslation(-3.0f, 0.0f, -2.0f);
|
||||||
mMeshes.back()->setShaders(":/texture2d.vert", ":/texture2d.frag");
|
mMeshes.back()->setShaders(":/texture2d.vert", ":/texture2d.frag");
|
||||||
mMeshes.back()->init();
|
mMeshes.back()->init();
|
||||||
mMeshes.back()->mProgram.bind();
|
mMeshes.back()->mProgram.bind();
|
||||||
|
|
||||||
mMeshes.back()->setTexture(OpenGLTextureFactory::initTexture2D(":/crate.png"));
|
mMeshes.back()->setTexture(
|
||||||
|
OpenGLTextureFactory::initTexture2D(":/crate.png"));
|
||||||
mMeshes.back()->setUniform("uTexture", 0);
|
mMeshes.back()->setUniform("uTexture", 0);
|
||||||
|
|
||||||
mMeshes.back()->mVAO.bind();
|
mMeshes.back()->mVAO.bind();
|
||||||
mMeshes.back()->mNBO.destroy();
|
mMeshes.back()->mNBO.destroy();
|
||||||
mMeshes.back()->mNBO.create();
|
mMeshes.back()->mNBO.create();
|
||||||
mMeshes.back()->mNBO.bind();
|
mMeshes.back()->mNBO.bind();
|
||||||
mMeshes.back()->mNBO.allocate(mMeshes.back()->mShape.getTexCoords().data(),
|
mMeshes.back()->mNBO.allocate(
|
||||||
mMeshes.back()->mShape.getTexCoords().size()
|
mMeshes.back()->mShape.getTexCoords().data(),
|
||||||
* sizeof(mMeshes.back()->mShape.getTexCoords()[0]));
|
mMeshes.back()->mShape.getTexCoords().size()
|
||||||
|
* sizeof(mMeshes.back()->mShape.getTexCoords()[0]));
|
||||||
mMeshes.back()->mProgram.enableAttributeArray(1);
|
mMeshes.back()->mProgram.enableAttributeArray(1);
|
||||||
mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
|
mMeshes.back()->mProgram.setAttributeBuffer(
|
||||||
2, sizeof(QVector2D));
|
1, GL_FLOAT, 0, 2, sizeof(QVector2D));
|
||||||
mMeshes.back()->mNBO.release();
|
mMeshes.back()->mNBO.release();
|
||||||
mMeshes.back()->mVAO.release();
|
mMeshes.back()->mVAO.release();
|
||||||
mMeshes.back()->mProgram.release();
|
mMeshes.back()->mProgram.release();
|
||||||
|
|
||||||
// Test drawing a cube with texture coordinates using glDrawElements
|
// Test drawing a cube with texture coordinates using glDrawElements
|
||||||
mMeshes.push_back(
|
mMeshes.push_back(new Qtk::MeshRenderer(
|
||||||
new MeshRenderer("uvCubeElementsTest", Cube(QTK_DRAW_ELEMENTS_NORMALS)));
|
"uvCubeElementsTest", Cube(QTK_DRAW_ELEMENTS_NORMALS)));
|
||||||
mMeshes.back()->mTransform.setTranslation(-1.7f, 0.0f, -2.0f);
|
mMeshes.back()->mTransform.setTranslation(-1.7f, 0.0f, -2.0f);
|
||||||
mMeshes.back()->setShaders(":/texture2d.vert", ":/texture2d.frag");
|
mMeshes.back()->setShaders(":/texture2d.vert", ":/texture2d.frag");
|
||||||
mMeshes.back()->init();
|
mMeshes.back()->init();
|
||||||
|
@ -400,13 +405,15 @@ void Scene::init()
|
||||||
mMeshes.back()->mNBO.bind();
|
mMeshes.back()->mNBO.bind();
|
||||||
mMeshes.back()->mProgram.bind();
|
mMeshes.back()->mProgram.bind();
|
||||||
|
|
||||||
mMeshes.back()->mNBO.allocate(mMeshes.back()->getTexCoords().data(),
|
mMeshes.back()->mNBO.allocate(
|
||||||
mMeshes.back()->getTexCoords().size()
|
mMeshes.back()->getTexCoords().data(),
|
||||||
* sizeof(mMeshes.back()->getTexCoords()[0]));
|
mMeshes.back()->getTexCoords().size()
|
||||||
|
* sizeof(mMeshes.back()->getTexCoords()[0]));
|
||||||
mMeshes.back()->mProgram.enableAttributeArray(1);
|
mMeshes.back()->mProgram.enableAttributeArray(1);
|
||||||
mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
|
mMeshes.back()->mProgram.setAttributeBuffer(
|
||||||
3, sizeof(QVector3D));
|
1, GL_FLOAT, 0, 3, sizeof(QVector3D));
|
||||||
mMeshes.back()->setTexture(OpenGLTextureFactory::initTexture2D(":/crate.png"));
|
mMeshes.back()->setTexture(
|
||||||
|
OpenGLTextureFactory::initTexture2D(":/crate.png"));
|
||||||
|
|
||||||
mMeshes.back()->mProgram.setUniformValue("uTexture", 0);
|
mMeshes.back()->mProgram.setUniformValue("uTexture", 0);
|
||||||
mMeshes.back()->mProgram.release();
|
mMeshes.back()->mProgram.release();
|
||||||
|
@ -417,10 +424,11 @@ void Scene::init()
|
||||||
// Texturing a cube using a cube map
|
// Texturing a cube using a cube map
|
||||||
// + Cube map texturing works with both QTK_DRAW_ARRAYS and QTK_DRAW_ELEMENTS
|
// + Cube map texturing works with both QTK_DRAW_ARRAYS and QTK_DRAW_ELEMENTS
|
||||||
mMeshes.push_back(
|
mMeshes.push_back(
|
||||||
new MeshRenderer("testCubeMap", Cube(QTK_DRAW_ELEMENTS)));
|
new Qtk::MeshRenderer("testCubeMap", Cube(QTK_DRAW_ELEMENTS)));
|
||||||
mMeshes.back()->mTransform.setTranslation(-3.0f, 1.0f, -2.0f);
|
mMeshes.back()->mTransform.setTranslation(-3.0f, 1.0f, -2.0f);
|
||||||
mMeshes.back()->mTransform.setRotation(45.0f, 0.0f, 1.0f, 0.0f);
|
mMeshes.back()->mTransform.setRotation(45.0f, 0.0f, 1.0f, 0.0f);
|
||||||
mMeshes.back()->setShaders(":/texture-cubemap.vert", ":/texture-cubemap.frag");
|
mMeshes.back()->setShaders(
|
||||||
|
":/texture-cubemap.vert", ":/texture-cubemap.frag");
|
||||||
mMeshes.back()->init();
|
mMeshes.back()->init();
|
||||||
mMeshes.back()->mProgram.bind();
|
mMeshes.back()->mProgram.bind();
|
||||||
|
|
||||||
|
@ -431,19 +439,21 @@ void Scene::init()
|
||||||
mMeshes.back()->mNBO.destroy();
|
mMeshes.back()->mNBO.destroy();
|
||||||
mMeshes.back()->mNBO.create();
|
mMeshes.back()->mNBO.create();
|
||||||
mMeshes.back()->mNBO.bind();
|
mMeshes.back()->mNBO.bind();
|
||||||
mMeshes.back()->mNBO.allocate(mMeshes.back()->mShape.getTexCoords().data(),
|
mMeshes.back()->mNBO.allocate(
|
||||||
mMeshes.back()->mShape.getTexCoords().size()
|
mMeshes.back()->mShape.getTexCoords().data(),
|
||||||
* sizeof(mMeshes.back()->mShape.getTexCoords()[0]));
|
mMeshes.back()->mShape.getTexCoords().size()
|
||||||
|
* sizeof(mMeshes.back()->mShape.getTexCoords()[0]));
|
||||||
mMeshes.back()->mProgram.enableAttributeArray(1);
|
mMeshes.back()->mProgram.enableAttributeArray(1);
|
||||||
mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
|
mMeshes.back()->mProgram.setAttributeBuffer(
|
||||||
2, sizeof(QVector2D));
|
1, GL_FLOAT, 0, 2, sizeof(QVector2D));
|
||||||
mMeshes.back()->mNBO.release();
|
mMeshes.back()->mNBO.release();
|
||||||
mMeshes.back()->mVAO.release();
|
mMeshes.back()->mVAO.release();
|
||||||
mMeshes.back()->mProgram.release();
|
mMeshes.back()->mProgram.release();
|
||||||
|
|
||||||
// Create a cube with custom shaders
|
// Create a cube with custom shaders
|
||||||
// + Apply RGB normals shader and spin the cube for a neat effect
|
// + Apply RGB normals shader and spin the cube for a neat effect
|
||||||
mMeshes.push_back(new MeshRenderer("rgbNormalsCube", Cube(QTK_DRAW_ARRAYS)));
|
mMeshes.push_back(
|
||||||
|
new Qtk::MeshRenderer("rgbNormalsCube", Cube(QTK_DRAW_ARRAYS)));
|
||||||
mMeshes.back()->mTransform.setTranslation(5.0f, 2.0f, -2.0f);
|
mMeshes.back()->mTransform.setTranslation(5.0f, 2.0f, -2.0f);
|
||||||
mMeshes.back()->setShaders(":/rgb-normals.vert", ":/rgb-normals.frag");
|
mMeshes.back()->setShaders(":/rgb-normals.vert", ":/rgb-normals.frag");
|
||||||
mMeshes.back()->init();
|
mMeshes.back()->init();
|
||||||
|
@ -452,20 +462,21 @@ void Scene::init()
|
||||||
mMeshes.back()->mNBO.bind();
|
mMeshes.back()->mNBO.bind();
|
||||||
mMeshes.back()->mProgram.bind();
|
mMeshes.back()->mProgram.bind();
|
||||||
|
|
||||||
mMeshes.back()->mNBO.allocate(mMeshes.back()->getNormals().data(),
|
mMeshes.back()->mNBO.allocate(
|
||||||
mMeshes.back()->getNormals().size()
|
mMeshes.back()->getNormals().data(),
|
||||||
* sizeof(mMeshes.back()->getNormals()[0]));
|
mMeshes.back()->getNormals().size()
|
||||||
|
* sizeof(mMeshes.back()->getNormals()[0]));
|
||||||
mMeshes.back()->mProgram.enableAttributeArray(1);
|
mMeshes.back()->mProgram.enableAttributeArray(1);
|
||||||
mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
|
mMeshes.back()->mProgram.setAttributeBuffer(
|
||||||
3, sizeof(QVector3D));
|
1, GL_FLOAT, 0, 3, sizeof(QVector3D));
|
||||||
|
|
||||||
mMeshes.back()->mProgram.release();
|
mMeshes.back()->mProgram.release();
|
||||||
mMeshes.back()->mNBO.release();
|
mMeshes.back()->mNBO.release();
|
||||||
mMeshes.back()->mVAO.release();
|
mMeshes.back()->mVAO.release();
|
||||||
|
|
||||||
// RGB Normals triangle to show normals are correct with QTK_DRAW_ARRAYS
|
// RGB Normals triangle to show normals are correct with QTK_DRAW_ARRAYS
|
||||||
mMeshes.push_back(
|
mMeshes.push_back(new Qtk::MeshRenderer(
|
||||||
new MeshRenderer("rgbTriangleArraysTest", Triangle(QTK_DRAW_ARRAYS)));
|
"rgbTriangleArraysTest", Triangle(QTK_DRAW_ARRAYS)));
|
||||||
mMeshes.back()->mTransform.setTranslation(7.0f, 0.0f, 2.0f);
|
mMeshes.back()->mTransform.setTranslation(7.0f, 0.0f, 2.0f);
|
||||||
mMeshes.back()->setShaders(":/rgb-normals.vert", ":/rgb-normals.frag");
|
mMeshes.back()->setShaders(":/rgb-normals.vert", ":/rgb-normals.frag");
|
||||||
mMeshes.back()->init();
|
mMeshes.back()->init();
|
||||||
|
@ -474,20 +485,20 @@ void Scene::init()
|
||||||
mMeshes.back()->mVAO.bind();
|
mMeshes.back()->mVAO.bind();
|
||||||
mMeshes.back()->mNBO.create();
|
mMeshes.back()->mNBO.create();
|
||||||
mMeshes.back()->mNBO.bind();
|
mMeshes.back()->mNBO.bind();
|
||||||
mMeshes.back()->mNBO.allocate(mMeshes.back()->getNormals().data(),
|
mMeshes.back()->mNBO.allocate(
|
||||||
mMeshes.back()->getNormals().size()
|
mMeshes.back()->getNormals().data(),
|
||||||
* sizeof(mMeshes.back()->getNormals()[0]));
|
mMeshes.back()->getNormals().size()
|
||||||
|
* sizeof(mMeshes.back()->getNormals()[0]));
|
||||||
mMeshes.back()->mProgram.enableAttributeArray(1);
|
mMeshes.back()->mProgram.enableAttributeArray(1);
|
||||||
mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
|
mMeshes.back()->mProgram.setAttributeBuffer(
|
||||||
3, sizeof(QVector3D));
|
1, GL_FLOAT, 0, 3, sizeof(QVector3D));
|
||||||
mMeshes.back()->mNBO.release();
|
mMeshes.back()->mNBO.release();
|
||||||
mMeshes.back()->mVAO.release();
|
mMeshes.back()->mVAO.release();
|
||||||
mMeshes.back()->mProgram.release();
|
mMeshes.back()->mProgram.release();
|
||||||
|
|
||||||
// RGB Normals triangle to show normals are correct with QTK_DRAW_ELEMENTS
|
// RGB Normals triangle to show normals are correct with QTK_DRAW_ELEMENTS
|
||||||
mMeshes.push_back(
|
mMeshes.push_back(new Qtk::MeshRenderer(
|
||||||
new MeshRenderer("rgbTriangleElementsTest",
|
"rgbTriangleElementsTest", Triangle(QTK_DRAW_ELEMENTS_NORMALS)));
|
||||||
Triangle(QTK_DRAW_ELEMENTS_NORMALS)));
|
|
||||||
mMeshes.back()->mTransform.setTranslation(7.0f, 0.0f, 4.0f);
|
mMeshes.back()->mTransform.setTranslation(7.0f, 0.0f, 4.0f);
|
||||||
mMeshes.back()->setShaders(":/rgb-normals.vert", ":/rgb-normals.frag");
|
mMeshes.back()->setShaders(":/rgb-normals.vert", ":/rgb-normals.frag");
|
||||||
mMeshes.back()->init();
|
mMeshes.back()->init();
|
||||||
|
@ -496,54 +507,52 @@ void Scene::init()
|
||||||
mMeshes.back()->mVAO.bind();
|
mMeshes.back()->mVAO.bind();
|
||||||
mMeshes.back()->mNBO.create();
|
mMeshes.back()->mNBO.create();
|
||||||
mMeshes.back()->mNBO.bind();
|
mMeshes.back()->mNBO.bind();
|
||||||
mMeshes.back()->mNBO.allocate(mMeshes.back()->getNormals().data(),
|
mMeshes.back()->mNBO.allocate(
|
||||||
mMeshes.back()->getNormals().size()
|
mMeshes.back()->getNormals().data(),
|
||||||
* sizeof(mMeshes.back()->getNormals()[0]));
|
mMeshes.back()->getNormals().size()
|
||||||
|
* sizeof(mMeshes.back()->getNormals()[0]));
|
||||||
mMeshes.back()->mProgram.enableAttributeArray(1);
|
mMeshes.back()->mProgram.enableAttributeArray(1);
|
||||||
mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
|
mMeshes.back()->mProgram.setAttributeBuffer(
|
||||||
3, sizeof(QVector3D));
|
1, GL_FLOAT, 0, 3, sizeof(QVector3D));
|
||||||
mMeshes.back()->mNBO.release();
|
mMeshes.back()->mNBO.release();
|
||||||
mMeshes.back()->mVAO.release();
|
mMeshes.back()->mVAO.release();
|
||||||
mMeshes.back()->mProgram.release();
|
mMeshes.back()->mProgram.release();
|
||||||
|
|
||||||
// Test drawing triangle with glDrawArrays with texture coordinates
|
// Test drawing triangle with glDrawArrays with texture coordinates
|
||||||
mMeshes.push_back(
|
mMeshes.push_back(
|
||||||
new MeshRenderer("testTriangleArraysUV", Triangle(QTK_DRAW_ARRAYS)));
|
new Qtk::MeshRenderer("testTriangleArraysUV", Triangle(QTK_DRAW_ARRAYS)));
|
||||||
mMeshes.back()->mTransform.setTranslation(-3.0f, 2.0f, -2.0f);
|
mMeshes.back()->mTransform.setTranslation(-3.0f, 2.0f, -2.0f);
|
||||||
mMeshes.back()->setShaders(":/texture2d.vert", ":/texture2d.frag");
|
mMeshes.back()->setShaders(":/texture2d.vert", ":/texture2d.frag");
|
||||||
mMeshes.back()->init();
|
mMeshes.back()->init();
|
||||||
mMeshes.back()->mProgram.bind();
|
mMeshes.back()->mProgram.bind();
|
||||||
|
|
||||||
mMeshes.back()->setTexture(":/crate.png");
|
mMeshes.back()->setTexture(":/crate.png");
|
||||||
|
|
||||||
// Test assignment of Texture
|
|
||||||
mMeshes.back()->mTexture = Texture(":/crate.png");
|
|
||||||
mMeshes.back()->setUniform("uTexture", 0);
|
mMeshes.back()->setUniform("uTexture", 0);
|
||||||
|
|
||||||
mMeshes.back()->mVAO.bind();
|
mMeshes.back()->mVAO.bind();
|
||||||
mMeshes.back()->mNBO.destroy();
|
mMeshes.back()->mNBO.destroy();
|
||||||
mMeshes.back()->mNBO.create();
|
mMeshes.back()->mNBO.create();
|
||||||
mMeshes.back()->mNBO.bind();
|
mMeshes.back()->mNBO.bind();
|
||||||
mMeshes.back()->mNBO.allocate(mMeshes.back()->mShape.getTexCoords().data(),
|
mMeshes.back()->mNBO.allocate(
|
||||||
mMeshes.back()->mShape.getTexCoords().size()
|
mMeshes.back()->mShape.getTexCoords().data(),
|
||||||
* sizeof(mMeshes.back()->mShape.getTexCoords()[0]));
|
mMeshes.back()->mShape.getTexCoords().size()
|
||||||
|
* sizeof(mMeshes.back()->mShape.getTexCoords()[0]));
|
||||||
mMeshes.back()->mProgram.enableAttributeArray(1);
|
mMeshes.back()->mProgram.enableAttributeArray(1);
|
||||||
mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
|
mMeshes.back()->mProgram.setAttributeBuffer(
|
||||||
2, sizeof(QVector2D));
|
1, GL_FLOAT, 0, 2, sizeof(QVector2D));
|
||||||
mMeshes.back()->mNBO.release();
|
mMeshes.back()->mNBO.release();
|
||||||
mMeshes.back()->mVAO.release();
|
mMeshes.back()->mVAO.release();
|
||||||
mMeshes.back()->mProgram.release();
|
mMeshes.back()->mProgram.release();
|
||||||
|
|
||||||
// Test drawing triangle with glDrawElements with texture coordinates
|
// Test drawing triangle with glDrawElements with texture coordinates
|
||||||
mMeshes.push_back(
|
mMeshes.push_back(new Qtk::MeshRenderer(
|
||||||
new MeshRenderer("testTriangleElementsUV",
|
"testTriangleElementsUV", Triangle(QTK_DRAW_ELEMENTS_NORMALS)));
|
||||||
Triangle(QTK_DRAW_ELEMENTS_NORMALS)));
|
|
||||||
mMeshes.back()->mTransform.setTranslation(-2.5f, 0.0f, -1.0f);
|
mMeshes.back()->mTransform.setTranslation(-2.5f, 0.0f, -1.0f);
|
||||||
mMeshes.back()->setShaders(":/texture2d.vert", ":/texture2d.frag");
|
mMeshes.back()->setShaders(":/texture2d.vert", ":/texture2d.frag");
|
||||||
mMeshes.back()->init();
|
mMeshes.back()->init();
|
||||||
mMeshes.back()->mProgram.bind();
|
mMeshes.back()->mProgram.bind();
|
||||||
|
|
||||||
// mMeshes.back()->setTexture(OpenGLTextureFactory::initTexture2D(":/crate.png"));
|
// mMeshes.back()->setTexture(OpenGLTextureFactory::initTexture2D(":/crate.png"));
|
||||||
mMeshes.back()->mTexture.setTexture(":/crate.png");
|
mMeshes.back()->mTexture.setTexture(":/crate.png");
|
||||||
mMeshes.back()->setUniform("uTexture", 0);
|
mMeshes.back()->setUniform("uTexture", 0);
|
||||||
|
|
||||||
|
@ -551,12 +560,13 @@ void Scene::init()
|
||||||
mMeshes.back()->mNBO.destroy();
|
mMeshes.back()->mNBO.destroy();
|
||||||
mMeshes.back()->mNBO.create();
|
mMeshes.back()->mNBO.create();
|
||||||
mMeshes.back()->mNBO.bind();
|
mMeshes.back()->mNBO.bind();
|
||||||
mMeshes.back()->mNBO.allocate(mMeshes.back()->mShape.getTexCoords().data(),
|
mMeshes.back()->mNBO.allocate(
|
||||||
mMeshes.back()->mShape.getTexCoords().size()
|
mMeshes.back()->mShape.getTexCoords().data(),
|
||||||
* sizeof(mMeshes.back()->mShape.getTexCoords()[0]));
|
mMeshes.back()->mShape.getTexCoords().size()
|
||||||
|
* sizeof(mMeshes.back()->mShape.getTexCoords()[0]));
|
||||||
mMeshes.back()->mProgram.enableAttributeArray(1);
|
mMeshes.back()->mProgram.enableAttributeArray(1);
|
||||||
mMeshes.back()->mProgram.setAttributeBuffer(1, GL_FLOAT, 0,
|
mMeshes.back()->mProgram.setAttributeBuffer(
|
||||||
2, sizeof(QVector2D));
|
1, GL_FLOAT, 0, 2, sizeof(QVector2D));
|
||||||
mMeshes.back()->mNBO.release();
|
mMeshes.back()->mNBO.release();
|
||||||
mMeshes.back()->mVAO.release();
|
mMeshes.back()->mVAO.release();
|
||||||
mMeshes.back()->mProgram.release();
|
mMeshes.back()->mProgram.release();
|
||||||
|
@ -565,11 +575,10 @@ void Scene::init()
|
||||||
// Lighting cube examples
|
// Lighting cube examples
|
||||||
|
|
||||||
// Example of a cube with no lighting applied
|
// Example of a cube with no lighting applied
|
||||||
mMeshes.push_back(
|
mMeshes.push_back(new Qtk::MeshRenderer("noLight", Cube(QTK_DRAW_ELEMENTS)));
|
||||||
new MeshRenderer("noLight", Cube(QTK_DRAW_ELEMENTS)));
|
|
||||||
mMeshes.back()->mTransform.setTranslation(5.0f, 0.0f, -2.0f);
|
mMeshes.back()->mTransform.setTranslation(5.0f, 0.0f, -2.0f);
|
||||||
mMeshes.back()->setShaders(":/solid-perspective.vert",
|
mMeshes.back()->setShaders(
|
||||||
":/solid-perspective.frag");
|
":/solid-perspective.vert", ":/solid-perspective.frag");
|
||||||
mMeshes.back()->init();
|
mMeshes.back()->init();
|
||||||
mMeshes.back()->mProgram.bind();
|
mMeshes.back()->mProgram.bind();
|
||||||
mMeshes.back()->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f));
|
mMeshes.back()->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f));
|
||||||
|
@ -577,54 +586,59 @@ void Scene::init()
|
||||||
|
|
||||||
// Create objects that represent light sources for lighting examples
|
// Create objects that represent light sources for lighting examples
|
||||||
mMeshes.push_back(
|
mMeshes.push_back(
|
||||||
new MeshRenderer("phongLight", Triangle(QTK_DRAW_ELEMENTS)));
|
new Qtk::MeshRenderer("phongLight", Triangle(QTK_DRAW_ELEMENTS)));
|
||||||
mMeshes.back()->mTransform.setTranslation(3.0f, 2.0f, -2.0f);
|
mMeshes.back()->mTransform.setTranslation(3.0f, 2.0f, -2.0f);
|
||||||
mMeshes.back()->mTransform.scale(0.25f);
|
mMeshes.back()->mTransform.scale(0.25f);
|
||||||
|
|
||||||
mMeshes.push_back(
|
mMeshes.push_back(
|
||||||
new MeshRenderer("diffuseLight", Triangle(QTK_DRAW_ELEMENTS)));
|
new Qtk::MeshRenderer("diffuseLight", Triangle(QTK_DRAW_ELEMENTS)));
|
||||||
mMeshes.back()->mTransform.setTranslation(9.0f, 2.0f, -2.0f);
|
mMeshes.back()->mTransform.setTranslation(9.0f, 2.0f, -2.0f);
|
||||||
mMeshes.back()->mTransform.scale(0.25f);
|
mMeshes.back()->mTransform.scale(0.25f);
|
||||||
|
|
||||||
mMeshes.push_back(
|
mMeshes.push_back(
|
||||||
new MeshRenderer("specularLight", Triangle(QTK_DRAW_ELEMENTS)));
|
new Qtk::MeshRenderer("specularLight", Triangle(QTK_DRAW_ELEMENTS)));
|
||||||
mMeshes.back()->mTransform.setTranslation(11.0f, 2.0f, -2.0f);
|
mMeshes.back()->mTransform.setTranslation(11.0f, 2.0f, -2.0f);
|
||||||
mMeshes.back()->mTransform.scale(0.25f);
|
mMeshes.back()->mTransform.scale(0.25f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scene::draw()
|
void ExampleScene::draw() {
|
||||||
{
|
Scene::draw();
|
||||||
mSkybox.draw();
|
|
||||||
|
|
||||||
for (const auto & model : mModels) model->draw();
|
for(const auto & model : mModels) {
|
||||||
|
model->draw();
|
||||||
|
}
|
||||||
|
|
||||||
for (const auto & mesh : mMeshes) mesh->draw();
|
for(const auto & mesh : mMeshes) {
|
||||||
|
mesh->draw();
|
||||||
|
}
|
||||||
|
|
||||||
mTestPhong->mProgram.bind();
|
mTestPhong->mProgram.bind();
|
||||||
mTestPhong->setUniform("uModelInverseTransposed",
|
mTestPhong->setUniform(
|
||||||
mTestPhong->mTransform.toMatrix().normalMatrix());
|
"uModelInverseTransposed",
|
||||||
|
mTestPhong->mTransform.toMatrix().normalMatrix());
|
||||||
mTestPhong->setUniform(
|
mTestPhong->setUniform(
|
||||||
"uLightPosition",
|
"uLightPosition",
|
||||||
MeshRenderer::getInstance("phongLight")->mTransform.getTranslation());
|
MeshRenderer::getInstance("phongLight")->mTransform.getTranslation());
|
||||||
mTestPhong->setUniform("uCameraPosition",
|
mTestPhong->setUniform(
|
||||||
Scene::Camera().transform().getTranslation());
|
"uCameraPosition", ExampleScene::Camera().transform().getTranslation());
|
||||||
mTestPhong->mProgram.release();
|
mTestPhong->mProgram.release();
|
||||||
mTestPhong->draw();
|
mTestPhong->draw();
|
||||||
|
|
||||||
mTestAmbient->mProgram.bind();
|
mTestAmbient->mProgram.bind();
|
||||||
mTestAmbient->setUniform("uCameraPosition",
|
mTestAmbient->setUniform(
|
||||||
Scene::Camera().transform().getTranslation());
|
"uCameraPosition", ExampleScene::Camera().transform().getTranslation());
|
||||||
mTestAmbient->mProgram.release();
|
mTestAmbient->mProgram.release();
|
||||||
mTestAmbient->draw();
|
mTestAmbient->draw();
|
||||||
|
|
||||||
mTestDiffuse->mProgram.bind();
|
mTestDiffuse->mProgram.bind();
|
||||||
mTestDiffuse->setUniform("uModelInverseTransposed",
|
mTestDiffuse->setUniform(
|
||||||
mTestDiffuse->mTransform.toMatrix().normalMatrix());
|
"uModelInverseTransposed",
|
||||||
|
mTestDiffuse->mTransform.toMatrix().normalMatrix());
|
||||||
mTestDiffuse->setUniform(
|
mTestDiffuse->setUniform(
|
||||||
"uLightPosition",
|
"uLightPosition",
|
||||||
MeshRenderer::getInstance("diffuseLight")->mTransform.getTranslation());
|
MeshRenderer::getInstance("diffuseLight")->mTransform.getTranslation());
|
||||||
mTestDiffuse->setUniform("uCameraPosition",
|
mTestDiffuse->setUniform(
|
||||||
Scene::Camera().transform().getTranslation());
|
"uCameraPosition", ExampleScene::Camera().transform().getTranslation());
|
||||||
mTestDiffuse->mProgram.release();
|
mTestDiffuse->mProgram.release();
|
||||||
mTestDiffuse->draw();
|
mTestDiffuse->draw();
|
||||||
|
|
||||||
|
@ -635,67 +649,66 @@ void Scene::draw()
|
||||||
mTestSpecular->setUniform(
|
mTestSpecular->setUniform(
|
||||||
"uLightPosition",
|
"uLightPosition",
|
||||||
MeshRenderer::getInstance("specularLight")->mTransform.getTranslation());
|
MeshRenderer::getInstance("specularLight")->mTransform.getTranslation());
|
||||||
mTestSpecular->setUniform("uCameraPosition",
|
mTestSpecular->setUniform(
|
||||||
Scene::Camera().transform().getTranslation());
|
"uCameraPosition", ExampleScene::Camera().transform().getTranslation());
|
||||||
mTestSpecular->mProgram.release();
|
mTestSpecular->mProgram.release();
|
||||||
mTestSpecular->draw();
|
mTestSpecular->draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scene::update()
|
void ExampleScene::update() {
|
||||||
{
|
auto position =
|
||||||
auto position = MeshRenderer::getInstance(
|
MeshRenderer::getInstance("alienTestLight")->mTransform.getTranslation();
|
||||||
"alienTestLight")->mTransform.getTranslation();
|
Model::getInstance("alienTest")->setUniform("uLight.position", position);
|
||||||
Model::getInstance("alienTest")->setUniform(
|
Model::getInstance("alienTest")
|
||||||
"uLight.position", position);
|
->setUniform(
|
||||||
Model::getInstance("alienTest")->setUniform(
|
"uCameraPosition",
|
||||||
"uCameraPosition", Scene::Camera().transform().getTranslation());
|
ExampleScene::Camera().transform().getTranslation());
|
||||||
auto posMatrix = Model::getInstance("alienTest")->mTransform.toMatrix();
|
auto posMatrix = Model::getInstance("alienTest")->mTransform.toMatrix();
|
||||||
Model::getInstance("alienTest")->setUniform(
|
Model::getInstance("alienTest")
|
||||||
"uMVP.normalMatrix", posMatrix.normalMatrix());
|
->setUniform("uMVP.normalMatrix", posMatrix.normalMatrix());
|
||||||
Model::getInstance("alienTest")->setUniform(
|
Model::getInstance("alienTest")->setUniform("uMVP.model", posMatrix);
|
||||||
"uMVP.model", posMatrix);
|
Model::getInstance("alienTest")
|
||||||
Model::getInstance("alienTest")->setUniform(
|
->setUniform("uMVP.view", ExampleScene::Camera().toMatrix());
|
||||||
"uMVP.view", Scene::Camera().toMatrix());
|
Model::getInstance("alienTest")
|
||||||
Model::getInstance("alienTest")->setUniform(
|
->setUniform("uMVP.projection", ExampleScene::Projection());
|
||||||
"uMVP.projection", Scene::Projection());
|
|
||||||
Model::getInstance("alienTest")->mTransform.rotate(0.75f, 0.0f, 1.0f, 0.0f);
|
Model::getInstance("alienTest")->mTransform.rotate(0.75f, 0.0f, 1.0f, 0.0f);
|
||||||
|
|
||||||
position = MeshRenderer::getInstance(
|
position = MeshRenderer::getInstance("spartanTestLight")
|
||||||
"spartanTestLight")->mTransform.getTranslation();
|
->mTransform.getTranslation();
|
||||||
Model::getInstance("spartanTest")->setUniform(
|
Model::getInstance("spartanTest")->setUniform("uLight.position", position);
|
||||||
"uLight.position", position);
|
Model::getInstance("spartanTest")
|
||||||
Model::getInstance("spartanTest")->setUniform(
|
->setUniform(
|
||||||
"uCameraPosition", Scene::Camera().transform().getTranslation());
|
"uCameraPosition",
|
||||||
|
ExampleScene::Camera().transform().getTranslation());
|
||||||
posMatrix = Model::getInstance("spartanTest")->mTransform.toMatrix();
|
posMatrix = Model::getInstance("spartanTest")->mTransform.toMatrix();
|
||||||
Model::getInstance("spartanTest")->setUniform(
|
Model::getInstance("spartanTest")
|
||||||
"uMVP.normalMatrix", posMatrix.normalMatrix());
|
->setUniform("uMVP.normalMatrix", posMatrix.normalMatrix());
|
||||||
Model::getInstance("spartanTest")->setUniform(
|
Model::getInstance("spartanTest")->setUniform("uMVP.model", posMatrix);
|
||||||
"uMVP.model", posMatrix);
|
Model::getInstance("spartanTest")
|
||||||
Model::getInstance("spartanTest")->setUniform(
|
->setUniform("uMVP.view", ExampleScene::Camera().toMatrix());
|
||||||
"uMVP.view", Scene::Camera().toMatrix());
|
Model::getInstance("spartanTest")
|
||||||
Model::getInstance("spartanTest")->setUniform(
|
->setUniform("uMVP.projection", ExampleScene::Projection());
|
||||||
"uMVP.projection", Scene::Projection());
|
|
||||||
Model::getInstance("spartanTest")->mTransform.rotate(0.75f, 0.0f, 1.0f, 0.0f);
|
Model::getInstance("spartanTest")->mTransform.rotate(0.75f, 0.0f, 1.0f, 0.0f);
|
||||||
|
|
||||||
|
MeshRenderer::getInstance("testPhong")
|
||||||
|
->mTransform.rotate(0.75f, 1.0f, 0.5f, 0.0f);
|
||||||
MeshRenderer::getInstance("testPhong")->mTransform.rotate(
|
|
||||||
0.75f, 1.0f, 0.5f, 0.0f);
|
|
||||||
MeshRenderer::getInstance("testPhong")->mProgram.bind();
|
MeshRenderer::getInstance("testPhong")->mProgram.bind();
|
||||||
position = MeshRenderer::getInstance("testLight")->mTransform.getTranslation();
|
position =
|
||||||
MeshRenderer::getInstance("testPhong")->setUniform(
|
MeshRenderer::getInstance("testLight")->mTransform.getTranslation();
|
||||||
"uLight.position", position);
|
MeshRenderer::getInstance("testPhong")
|
||||||
MeshRenderer::getInstance("testPhong")->setUniform(
|
->setUniform("uLight.position", position);
|
||||||
"uCameraPosition", Scene::Camera().transform().getTranslation());
|
MeshRenderer::getInstance("testPhong")
|
||||||
|
->setUniform(
|
||||||
|
"uCameraPosition",
|
||||||
|
ExampleScene::Camera().transform().getTranslation());
|
||||||
posMatrix = MeshRenderer::getInstance("testPhong")->mTransform.toMatrix();
|
posMatrix = MeshRenderer::getInstance("testPhong")->mTransform.toMatrix();
|
||||||
MeshRenderer::getInstance("testPhong")->setUniform(
|
MeshRenderer::getInstance("testPhong")
|
||||||
"uMVP.normalMatrix", posMatrix.normalMatrix());
|
->setUniform("uMVP.normalMatrix", posMatrix.normalMatrix());
|
||||||
MeshRenderer::getInstance("testPhong")->setUniform(
|
MeshRenderer::getInstance("testPhong")->setUniform("uMVP.model", posMatrix);
|
||||||
"uMVP.model", posMatrix);
|
MeshRenderer::getInstance("testPhong")
|
||||||
MeshRenderer::getInstance("testPhong")->setUniform(
|
->setUniform("uMVP.view", ExampleScene::Camera().toMatrix());
|
||||||
"uMVP.view", Scene::Camera().toMatrix());
|
MeshRenderer::getInstance("testPhong")
|
||||||
MeshRenderer::getInstance("testPhong")->setUniform(
|
->setUniform("uMVP.projection", ExampleScene::Projection());
|
||||||
"uMVP.projection", Scene::Projection());
|
|
||||||
MeshRenderer::getInstance("testPhong")->mProgram.release();
|
MeshRenderer::getInstance("testPhong")->mProgram.release();
|
||||||
|
|
||||||
// Rotate lighting example cubes
|
// Rotate lighting example cubes
|
||||||
|
@ -709,36 +722,36 @@ void Scene::update()
|
||||||
// Examples of various translations and rotations
|
// Examples of various translations and rotations
|
||||||
|
|
||||||
// Rotate in multiple directions simultaneously
|
// Rotate in multiple directions simultaneously
|
||||||
MeshRenderer::getInstance("rgbNormalsCube")->mTransform.rotate(
|
MeshRenderer::getInstance("rgbNormalsCube")
|
||||||
0.75f, 0.2f, 0.4f, 0.6f);
|
->mTransform.rotate(0.75f, 0.2f, 0.4f, 0.6f);
|
||||||
|
|
||||||
// Pitch forward and roll sideways
|
// Pitch forward and roll sideways
|
||||||
MeshRenderer::getInstance("leftTriangle")->mTransform.rotate(
|
MeshRenderer::getInstance("leftTriangle")
|
||||||
0.75f, 1.0f, 0.0f, 0.0f);
|
->mTransform.rotate(0.75f, 1.0f, 0.0f, 0.0f);
|
||||||
MeshRenderer::getInstance("rightTriangle")->mTransform.rotate(
|
MeshRenderer::getInstance("rightTriangle")
|
||||||
0.75f, 0.0f, 0.0f, 1.0f);
|
->mTransform.rotate(0.75f, 0.0f, 0.0f, 1.0f);
|
||||||
|
|
||||||
// Move between two positions over time
|
// Move between two positions over time
|
||||||
static float translateX = 0.025f;
|
static float translateX = 0.025f;
|
||||||
float limit = -9.0f; // Origin position.x - 2.0f
|
float limit = -9.0f; // Origin position.x - 2.0f
|
||||||
float posX =
|
float posX =
|
||||||
MeshRenderer::getInstance("topTriangle")->mTransform.getTranslation().x();
|
MeshRenderer::getInstance("topTriangle")->mTransform.getTranslation().x();
|
||||||
if (posX < limit || posX > limit + 4.0f) {
|
if(posX < limit || posX > limit + 4.0f) {
|
||||||
translateX = -translateX;
|
translateX = -translateX;
|
||||||
}
|
}
|
||||||
MeshRenderer::getInstance("topTriangle")->mTransform.translate(
|
MeshRenderer::getInstance("topTriangle")
|
||||||
translateX, 0.0f, 0.0f);
|
->mTransform.translate(translateX, 0.0f, 0.0f);
|
||||||
MeshRenderer::getInstance("bottomTriangle")->mTransform.translate(
|
MeshRenderer::getInstance("bottomTriangle")
|
||||||
-translateX, 0.0f, 0.0f);
|
->mTransform.translate(-translateX, 0.0f, 0.0f);
|
||||||
// And lets rotate the triangles in two directions at once
|
// And lets rotate the triangles in two directions at once
|
||||||
MeshRenderer::getInstance("topTriangle")->mTransform.rotate(
|
MeshRenderer::getInstance("topTriangle")
|
||||||
0.75f, 0.2f, 0.0f, 0.4f);
|
->mTransform.rotate(0.75f, 0.2f, 0.0f, 0.4f);
|
||||||
MeshRenderer::getInstance("bottomTriangle")->mTransform.rotate(
|
MeshRenderer::getInstance("bottomTriangle")
|
||||||
0.75f, 0.0f, 0.2f, 0.4f);
|
->mTransform.rotate(0.75f, 0.0f, 0.2f, 0.4f);
|
||||||
// And make the bottom triangle green, instead of RGB
|
// And make the bottom triangle green, instead of RGB
|
||||||
|
|
||||||
// Rotate center cube in several directions simultaneously
|
// Rotate center cube in several directions simultaneously
|
||||||
// + Not subject to gimbal lock since we are using quaternions :)
|
// + Not subject to gimbal lock since we are using quaternions :)
|
||||||
MeshRenderer::getInstance("centerCube")->mTransform.rotate(
|
MeshRenderer::getInstance("centerCube")
|
||||||
0.75f, 0.2f, 0.4f, 0.6f);
|
->mTransform.rotate(0.75f, 0.2f, 0.4f, 0.6f);
|
||||||
}
|
}
|
|
@ -6,40 +6,29 @@
|
||||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||||
##############################################################################*/
|
##############################################################################*/
|
||||||
|
|
||||||
#ifndef QTK_SCENE_H
|
#ifndef QTK_EXAMPLE_SCENE_H
|
||||||
#define QTK_SCENE_H
|
#define QTK_EXAMPLE_SCENE_H
|
||||||
|
|
||||||
|
#include <abstractscene.h>
|
||||||
#include <camera3d.h>
|
#include <camera3d.h>
|
||||||
#include <skybox.h>
|
#include <skybox.h>
|
||||||
|
|
||||||
#include <QMatrix4x4>
|
#include <QMatrix4x4>
|
||||||
|
|
||||||
class MeshRenderer;
|
class ExampleScene : public Qtk::Scene {
|
||||||
class Model;
|
public:
|
||||||
|
ExampleScene();
|
||||||
|
~ExampleScene();
|
||||||
|
|
||||||
class Scene {
|
void init() override;
|
||||||
public:
|
void draw() override;
|
||||||
Scene();
|
void update() override;
|
||||||
~Scene();
|
|
||||||
|
|
||||||
void init();
|
private:
|
||||||
void draw();
|
Qtk::MeshRenderer * mTestPhong {};
|
||||||
void update();
|
Qtk::MeshRenderer * mTestSpecular {};
|
||||||
|
Qtk::MeshRenderer * mTestDiffuse {};
|
||||||
static Camera3D & Camera() { return mCamera;}
|
Qtk::MeshRenderer * mTestAmbient {};
|
||||||
static QMatrix4x4 View() { return mCamera.toMatrix();}
|
|
||||||
static QMatrix4x4 & Projection() { return mProjection;}
|
|
||||||
private:
|
|
||||||
static Camera3D mCamera;
|
|
||||||
static QMatrix4x4 mProjection;
|
|
||||||
|
|
||||||
Skybox mSkybox;
|
|
||||||
MeshRenderer * mTestPhong;
|
|
||||||
MeshRenderer * mTestSpecular;
|
|
||||||
MeshRenderer * mTestDiffuse;
|
|
||||||
MeshRenderer * mTestAmbient;
|
|
||||||
std::vector<MeshRenderer *> mMeshes;
|
|
||||||
std::vector<Model *> mModels;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // QTK_SCENE_H
|
#endif // QTK_EXAMPLE_SCENE_H
|
14
app/main.cpp
14
app/main.cpp
|
@ -8,13 +8,12 @@
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QSurfaceFormat>
|
|
||||||
|
|
||||||
#include <mainwindow.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);
|
QApplication a(argc, argv);
|
||||||
|
|
||||||
// Set OpenGL Version information
|
// Set OpenGL Version information
|
||||||
|
@ -22,19 +21,18 @@ int main(int argc, char *argv[])
|
||||||
QSurfaceFormat format;
|
QSurfaceFormat format;
|
||||||
format.setRenderableType(QSurfaceFormat::OpenGL);
|
format.setRenderableType(QSurfaceFormat::OpenGL);
|
||||||
format.setProfile(QSurfaceFormat::CoreProfile);
|
format.setProfile(QSurfaceFormat::CoreProfile);
|
||||||
format.setVersion(4,5);
|
format.setVersion(4, 5);
|
||||||
// Set the number of samples used for glEnable(GL_MULTISAMPLING)
|
// Set the number of samples used for glEnable(GL_MULTISAMPLING)
|
||||||
format.setSamples(4);
|
format.setSamples(4);
|
||||||
// Set the size of the depth bufer for glEnable(GL_DEPTH_TEST)
|
// Set the size of the depth bufer for glEnable(GL_DEPTH_TEST)
|
||||||
format.setDepthBufferSize(16);
|
format.setDepthBufferSize(16);
|
||||||
#ifdef QTK_DEBUG
|
#ifdef QTK_DEBUG
|
||||||
format.setOption(QSurfaceFormat::DebugContext);
|
format.setOption(QSurfaceFormat::DebugContext);
|
||||||
#endif // QTK_DEBUG
|
#endif // QTK_DEBUG
|
||||||
|
|
||||||
// Create window for Qt application using custom mainwindow.h
|
// Create window for Qt application using custom mainwindow.h
|
||||||
MainWindow w;
|
MainWindow w;
|
||||||
w.show();
|
w.show();
|
||||||
|
|
||||||
return a.exec();
|
return QApplication::exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
#include <mainwindow.h>
|
||||||
|
#include <qtkwidget.h>
|
||||||
|
#include "ui_mainwindow.h"
|
||||||
|
|
||||||
|
MainWindow::MainWindow(QWidget * parent) :
|
||||||
|
QMainWindow(parent), ui(new Ui::MainWindow) {
|
||||||
|
ui->setupUi(this);
|
||||||
|
// For use in design mode using Qt Creator
|
||||||
|
// + We can use the `ui` member to access nested widgets by name
|
||||||
|
for(const auto widget : ui->qWidget->children()) {
|
||||||
|
auto qtkWidget = dynamic_cast<Qtk::QtkWidget *>(widget);
|
||||||
|
if(qtkWidget != nullptr) {
|
||||||
|
std::string key = qtkWidget->objectName().toStdString();
|
||||||
|
if(mScenes[key] == nullptr) {
|
||||||
|
mScenes[qtkWidget->objectName().toStdString()] = new ExampleScene();
|
||||||
|
}
|
||||||
|
qtkWidget->setScene(mScenes[qtkWidget->objectName().toStdString()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setWindowIcon(QIcon("../resources/icon.png"));
|
||||||
|
}
|
||||||
|
|
||||||
|
MainWindow::~MainWindow() {
|
||||||
|
delete ui;
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
#ifndef MAINWINDOW_H
|
||||||
|
#define MAINWINDOW_H
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include <QMainWindow>
|
||||||
|
|
||||||
|
#include <examplescene.h>
|
||||||
|
#include "qtk-widget_export.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class MainWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
class QTK_WIDGET_EXPORT MainWindow
|
||||||
|
|
||||||
|
: public QMainWindow {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit MainWindow(QWidget * parent = nullptr);
|
||||||
|
~MainWindow() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::MainWindow * ui {};
|
||||||
|
std::unordered_map<std::string, Qtk::Scene *> mScenes;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MAINWINDOW_H
|
|
@ -0,0 +1,114 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>MainWindow</class>
|
||||||
|
<widget class="QMainWindow" name="MainWindow">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>800</width>
|
||||||
|
<height>600</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Qtk - MainWindow</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="centralwidget">
|
||||||
|
<widget class="QWidget" name="qWidget" native="true">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>801</width>
|
||||||
|
<height>561</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<widget class="Qtk::QtkWidget" name="openGLWidget">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>10</x>
|
||||||
|
<y>10</y>
|
||||||
|
<width>781</width>
|
||||||
|
<height>541</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenuBar" name="menubar">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>800</width>
|
||||||
|
<height>22</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<widget class="QMenu" name="menuTest">
|
||||||
|
<property name="title">
|
||||||
|
<string>File</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionOpen"/>
|
||||||
|
<addaction name="actionSave_2"/>
|
||||||
|
<addaction name="actionSave_as"/>
|
||||||
|
<addaction name="actionExit"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menuView">
|
||||||
|
<property name="title">
|
||||||
|
<string>View</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionShow_Console"/>
|
||||||
|
</widget>
|
||||||
|
<addaction name="menuTest"/>
|
||||||
|
<addaction name="menuView"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QStatusBar" name="statusbar"/>
|
||||||
|
<action name="actionOtherTest">
|
||||||
|
<property name="text">
|
||||||
|
<string>Save</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSave">
|
||||||
|
<property name="text">
|
||||||
|
<string>Save</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionOpen">
|
||||||
|
<property name="text">
|
||||||
|
<string>Open...</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSave_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Save</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSave_as">
|
||||||
|
<property name="text">
|
||||||
|
<string>Save as...</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionExit">
|
||||||
|
<property name="text">
|
||||||
|
<string>Exit</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionShow_Console">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Show Console</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>Qtk::QtkWidget</class>
|
||||||
|
<extends>QOpenGLWidget</extends>
|
||||||
|
<header>qtkwidget.h</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*##############################################################################
|
||||||
|
## Author: Shaun Reed ##
|
||||||
|
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
|
||||||
|
## About: Manage files and resources used by qtk ##
|
||||||
|
## ##
|
||||||
|
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||||
|
##############################################################################*/
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <src/qtkresources.h>
|
||||||
|
|
||||||
|
#ifndef QTK_RESOURCEMANAGER_H
|
||||||
|
#define QTK_RESOURCEMANAGER_H
|
||||||
|
|
||||||
|
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
|
||||||
|
* 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'
|
||||||
|
* @return Absoulte system path to a qtk asset
|
||||||
|
*/
|
||||||
|
static std::string getPath(const std::string & path) {
|
||||||
|
// Only construct qtk resource path if in qrc format; else return it as-is
|
||||||
|
return path[0] == ':' ? QTK_RESOURCES + path.substr(1) : path;
|
||||||
|
}
|
||||||
|
} RM;
|
||||||
|
|
||||||
|
#endif // QTK_RESOURCEMANAGER_H
|
|
@ -0,0 +1,32 @@
|
||||||
|
################################################################################
|
||||||
|
## Author: Shaun Reed | Contact: shaunrd0@gmail.com | URL: www.shaunreed.com ##
|
||||||
|
## ##
|
||||||
|
## CMake function to update git submodules ##
|
||||||
|
################################################################################
|
||||||
|
include_guard()
|
||||||
|
|
||||||
|
find_package(Git)
|
||||||
|
|
||||||
|
# _PATH: Path to git submodule location that we want to update
|
||||||
|
# + submodule_update(extern/assimp)
|
||||||
|
function(submodule_update _PATH)
|
||||||
|
if (NOT QTK_UPDATE_SUBMODULES)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT GIT_FOUND)
|
||||||
|
message(FATAL_ERROR "[Qtk] Error: No git executable found")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${GIT_EXECUTABLE} submodule update --init --force "${_PATH}"
|
||||||
|
RESULT_VARIABLE result
|
||||||
|
)
|
||||||
|
|
||||||
|
if (NOT result EQUAL 0)
|
||||||
|
message(
|
||||||
|
FATAL_ERROR
|
||||||
|
"[Qtk] Error: Unable to update git submodule at ${_PATH}"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
endfunction()
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit bd64cc88dff17f118ecf32ebcbacaf566f6b6449
|
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
Binary file not shown.
After Width: | Height: | Size: 89 KiB |
Binary file not shown.
After Width: | Height: | Size: 263 KiB |
|
@ -0,0 +1,54 @@
|
||||||
|
/*##############################################################################
|
||||||
|
## Author: Shaun Reed ##
|
||||||
|
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
|
||||||
|
## About: Classes for managing objects and data within a scene ##
|
||||||
|
## ##
|
||||||
|
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||||
|
##############################################################################*/
|
||||||
|
|
||||||
|
#include <abstractscene.h>
|
||||||
|
#include <camera3d.h>
|
||||||
|
#include <resourcemanager.h>
|
||||||
|
#include <texture.h>
|
||||||
|
|
||||||
|
using namespace Qtk;
|
||||||
|
|
||||||
|
Camera3D Scene::mCamera;
|
||||||
|
QMatrix4x4 Scene::mProjection;
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Constructors, Destructors
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*##############################################################################
|
||||||
|
## Author: Shaun Reed ##
|
||||||
|
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
|
||||||
|
## About: Classes for managing objects and data within a scene ##
|
||||||
|
## ##
|
||||||
|
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||||
|
##############################################################################*/
|
||||||
|
|
||||||
|
#ifndef QTK_SCENE_H
|
||||||
|
#define QTK_SCENE_H
|
||||||
|
|
||||||
|
#include <camera3d.h>
|
||||||
|
#include <meshrenderer.h>
|
||||||
|
#include <model.h>
|
||||||
|
#include <skybox.h>
|
||||||
|
|
||||||
|
#include <QMatrix4x4>
|
||||||
|
|
||||||
|
namespace Qtk {
|
||||||
|
class Scene : protected QOpenGLFunctions {
|
||||||
|
friend class MainWidget;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Scene();
|
||||||
|
~Scene();
|
||||||
|
|
||||||
|
virtual void init() = 0;
|
||||||
|
|
||||||
|
virtual void draw() { privDraw(); };
|
||||||
|
virtual void update() = 0;
|
||||||
|
|
||||||
|
static Camera3D & Camera() { return mCamera; }
|
||||||
|
|
||||||
|
static QMatrix4x4 View() { return mCamera.toMatrix(); }
|
||||||
|
|
||||||
|
static QMatrix4x4 & Projection() { return mProjection; }
|
||||||
|
|
||||||
|
inline Skybox * getSkybox() { return mSkybox; }
|
||||||
|
|
||||||
|
inline void setSkybox(Skybox * skybox) { mSkybox = skybox; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
static Camera3D mCamera;
|
||||||
|
static QMatrix4x4 mProjection;
|
||||||
|
bool mInit = false;
|
||||||
|
|
||||||
|
void privDraw();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Skybox * mSkybox {};
|
||||||
|
std::vector<MeshRenderer *> mMeshes;
|
||||||
|
std::vector<Model *> mModels;
|
||||||
|
};
|
||||||
|
} // namespace Qtk
|
||||||
|
|
||||||
|
#endif // QTK_SCENE_H
|
|
@ -8,19 +8,18 @@
|
||||||
|
|
||||||
#include <camera3d.h>
|
#include <camera3d.h>
|
||||||
|
|
||||||
|
using namespace Qtk;
|
||||||
|
|
||||||
const QVector3D Camera3D::LocalForward(0.0f, 0.0f, -1.0f);
|
const QVector3D Camera3D::LocalForward(0.0f, 0.0f, -1.0f);
|
||||||
const QVector3D Camera3D::LocalUp(0.0f, 1.0f, 0.0f);
|
const QVector3D Camera3D::LocalUp(0.0f, 1.0f, 0.0f);
|
||||||
const QVector3D Camera3D::LocalRight(1.0f, 0.0f, 0.0f);
|
const QVector3D Camera3D::LocalRight(1.0f, 0.0f, 0.0f);
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Accessors
|
* Accessors
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
// Produces worldToView matrix
|
// Produces worldToView matrix
|
||||||
const QMatrix4x4 & Camera3D::toMatrix()
|
const QMatrix4x4 & Camera3D::toMatrix() {
|
||||||
{
|
|
||||||
mWorld.setToIdentity();
|
mWorld.setToIdentity();
|
||||||
// Qt6 renamed QMatrix4x4::conjugate() to conjugated()
|
// Qt6 renamed QMatrix4x4::conjugate() to conjugated()
|
||||||
mWorld.rotate(mTransform.getRotation().conjugated());
|
mWorld.rotate(mTransform.getRotation().conjugated());
|
||||||
|
@ -28,32 +27,27 @@ const QMatrix4x4 & Camera3D::toMatrix()
|
||||||
return mWorld;
|
return mWorld;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Qt Streams
|
* Qt Streams
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
QDataStream & operator<<(QDataStream & out, Camera3D & transform)
|
QDataStream & operator<<(QDataStream & out, Camera3D & transform) {
|
||||||
{
|
|
||||||
out << transform.transform();
|
out << transform.transform();
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
QDataStream & operator>>(QDataStream & in, Camera3D & transform)
|
QDataStream & operator>>(QDataStream & in, Camera3D & transform) {
|
||||||
{
|
|
||||||
in >> transform.transform();
|
in >> transform.transform();
|
||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
|
|
||||||
QDebug operator<<(QDebug dbg, const Camera3D & transform)
|
QDebug operator<<(QDebug dbg, const Camera3D & transform) {
|
||||||
{
|
|
||||||
dbg << "Camera3D\n{\n";
|
dbg << "Camera3D\n{\n";
|
||||||
dbg << "Position: <" << transform.translation().x() << ", "
|
dbg << "Position: <" << transform.translation().x() << ", "
|
||||||
<< transform.translation().y() << ", "
|
<< transform.translation().y() << ", " << transform.translation().z()
|
||||||
<< transform.translation().z() << ">\n";
|
<< ">\n";
|
||||||
dbg << "Rotation: <" << transform.rotation().x() << ", "
|
dbg << "Rotation: <" << transform.rotation().x() << ", "
|
||||||
<< transform.rotation().y() << ", "
|
<< transform.rotation().y() << ", " << transform.rotation().z() << " | "
|
||||||
<< transform.rotation().z() << " | "
|
|
||||||
<< transform.rotation().scalar() << ">\n}";
|
<< transform.rotation().scalar() << ">\n}";
|
||||||
return dbg;
|
return dbg;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,52 +11,64 @@
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
|
#include <qtkapi.h>
|
||||||
#include <transform3D.h>
|
#include <transform3D.h>
|
||||||
|
|
||||||
|
namespace Qtk {
|
||||||
|
class QTKAPI Camera3D {
|
||||||
|
public:
|
||||||
|
// Constants
|
||||||
|
static const QVector3D LocalForward;
|
||||||
|
static const QVector3D LocalUp;
|
||||||
|
static const QVector3D LocalRight;
|
||||||
|
|
||||||
class Camera3D {
|
// Accessors
|
||||||
public:
|
inline Transform3D & transform() { return mTransform; }
|
||||||
// Constants
|
|
||||||
static const QVector3D LocalForward;
|
|
||||||
static const QVector3D LocalUp;
|
|
||||||
static const QVector3D LocalRight;
|
|
||||||
|
|
||||||
// Accessors
|
[[nodiscard]] inline const QVector3D & translation() const {
|
||||||
inline Transform3D & transform() { return mTransform;}
|
return mTransform.getTranslation();
|
||||||
inline const QVector3D & translation() const
|
}
|
||||||
{ return mTransform.getTranslation();}
|
|
||||||
inline const QQuaternion & rotation() const
|
|
||||||
{ return mTransform.getRotation();}
|
|
||||||
const QMatrix4x4 & toMatrix();
|
|
||||||
|
|
||||||
// Queries
|
[[nodiscard]] inline const QQuaternion & rotation() const {
|
||||||
inline QVector3D forward() const
|
return mTransform.getRotation();
|
||||||
{ return mTransform.getRotation().rotatedVector(LocalForward);}
|
}
|
||||||
inline QVector3D right() const
|
|
||||||
{ return mTransform.getRotation().rotatedVector(LocalRight);}
|
|
||||||
inline QVector3D up() const
|
|
||||||
{ return mTransform.getRotation().rotatedVector(LocalUp);}
|
|
||||||
|
|
||||||
private:
|
const QMatrix4x4 & toMatrix();
|
||||||
Transform3D mTransform;
|
|
||||||
QMatrix4x4 mWorld;
|
// Queries
|
||||||
|
[[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;
|
||||||
|
QMatrix4x4 mWorld;
|
||||||
|
|
||||||
#ifndef QT_NO_DATASTREAM
|
#ifndef QT_NO_DATASTREAM
|
||||||
friend QDataStream & operator<<(QDataStream & out, Camera3D & transform);
|
friend QDataStream & operator<<(QDataStream & out, Camera3D & transform);
|
||||||
friend QDataStream & operator>>(QDataStream & in, Camera3D & transform);
|
friend QDataStream & operator>>(QDataStream & in, Camera3D & transform);
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_TYPEINFO(Camera3D, Q_MOVABLE_TYPE);
|
|
||||||
|
|
||||||
// Qt Streams
|
// Qt Streams
|
||||||
#ifndef QT_NO_DATASTREAM
|
#ifndef QT_NO_DATASTREAM
|
||||||
QDataStream & operator<<(QDataStream & out, const Camera3D & transform);
|
QDataStream & operator<<(QDataStream & out, const Camera3D & transform);
|
||||||
QDataStream & operator>>(QDataStream & in, Camera3D & transform);
|
QDataStream & operator>>(QDataStream & in, Camera3D & transform);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef QT_NO_DEBUG_STREAM
|
#ifndef QT_NO_DEBUG_STREAM
|
||||||
QDebug operator<<(QDebug dbg, const Camera3D & transform);
|
QDebug operator<<(QDebug dbg, const Camera3D & transform);
|
||||||
#endif
|
#endif
|
||||||
|
} // namespace Qtk
|
||||||
|
|
||||||
#endif // QTK_CAMERA3D_H
|
Q_DECLARE_TYPEINFO(Qtk::Camera3D, Q_MOVABLE_TYPE);
|
||||||
|
|
||||||
|
#endif // QTK_CAMERA3D_H
|
||||||
|
|
|
@ -13,23 +13,24 @@
|
||||||
|
|
||||||
#include <input.h>
|
#include <input.h>
|
||||||
|
|
||||||
|
using namespace Qtk;
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Static Helper Structs
|
* Static Helper Structs
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
template <typename T>
|
template <typename T> struct InputInstance : std::pair<T, Input::InputState> {
|
||||||
struct InputInstance : std::pair<T, Input::InputState>
|
typedef std::pair<T, Input::InputState> base_class;
|
||||||
{
|
|
||||||
typedef std::pair<T, Input::InputState> base_class;
|
|
||||||
|
|
||||||
inline InputInstance(T value)
|
// Disable clang-tidy from marking this ctor explicit
|
||||||
: base_class(value, Input::InputInvalid) {}
|
// NOLINTNEXTLINE
|
||||||
|
inline InputInstance(T value) : base_class(value, Input::InputInvalid) {}
|
||||||
|
|
||||||
inline InputInstance(T value, Input::InputState state)
|
inline InputInstance(T value, Input::InputState state) :
|
||||||
: base_class(value, state) {}
|
base_class(value, state) {}
|
||||||
|
|
||||||
inline bool operator==(const InputInstance & rhs) const
|
inline bool operator==(const InputInstance & rhs) const {
|
||||||
{ return this->first == rhs.first;}
|
return this->first == rhs.first;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Key, button instance typedefs
|
// Key, button instance typedefs
|
||||||
|
@ -48,26 +49,20 @@ static QPoint sg_mouseCurrPosition;
|
||||||
static QPoint sg_mousePrevPosition;
|
static QPoint sg_mousePrevPosition;
|
||||||
static QPoint sg_mouseDelta;
|
static QPoint sg_mouseDelta;
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Static Inline Helper Functions
|
* 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);
|
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);
|
return std::find(sg_buttonInstances.begin(), sg_buttonInstances.end(), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TPair>
|
template <typename TPair> static inline void UpdateStates(TPair & instance) {
|
||||||
static inline void UpdateStates(TPair & instance)
|
switch(instance.second) {
|
||||||
{
|
|
||||||
switch (instance.second)
|
|
||||||
{
|
|
||||||
case Input::InputRegistered:
|
case Input::InputRegistered:
|
||||||
instance.second = Input::InputTriggered;
|
instance.second = Input::InputTriggered;
|
||||||
break;
|
break;
|
||||||
|
@ -83,19 +78,16 @@ static inline void UpdateStates(TPair & instance)
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TPair>
|
template <typename TPair>
|
||||||
static inline bool CheckReleased(const TPair & instance)
|
static inline bool CheckReleased(const TPair & instance) {
|
||||||
{
|
|
||||||
return instance.second == Input::InputReleased;
|
return instance.second == Input::InputReleased;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Container>
|
template <typename Container> static inline void Update(Container & container) {
|
||||||
static inline void Update(Container & container)
|
|
||||||
{
|
|
||||||
typedef typename Container::iterator Iter;
|
typedef typename Container::iterator Iter;
|
||||||
typedef typename Container::value_type TPair;
|
typedef typename Container::value_type TPair;
|
||||||
|
|
||||||
// Remove old data
|
// Remove old data
|
||||||
Iter remove =
|
auto remove =
|
||||||
std::remove_if(container.begin(), container.end(), &CheckReleased<TPair>);
|
std::remove_if(container.begin(), container.end(), &CheckReleased<TPair>);
|
||||||
container.erase(remove, container.end());
|
container.erase(remove, container.end());
|
||||||
|
|
||||||
|
@ -103,35 +95,29 @@ static inline void Update(Container & container)
|
||||||
std::for_each(container.begin(), container.end(), &UpdateStates<TPair>);
|
std::for_each(container.begin(), container.end(), &UpdateStates<TPair>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Input Implementation
|
* Input Implementation
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
Input::InputState Input::keyState(Qt::Key k)
|
Input::InputState Input::keyState(Qt::Key k) {
|
||||||
{
|
auto it = FindKey(k);
|
||||||
KeyContainer::iterator it = FindKey(k);
|
|
||||||
return (it != sg_keyInstances.end()) ? it->second : InputInvalid;
|
return (it != sg_keyInstances.end()) ? it->second : InputInvalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
Input::InputState Input::buttonState(Qt::MouseButton k)
|
Input::InputState Input::buttonState(Qt::MouseButton k) {
|
||||||
{
|
auto it = FindButton(k);
|
||||||
ButtonContainer::iterator it = FindButton(k);
|
|
||||||
return (it != sg_buttonInstances.end()) ? it->second : InputInvalid;
|
return (it != sg_buttonInstances.end()) ? it->second : InputInvalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPoint Input::mousePosition()
|
QPoint Input::mousePosition() {
|
||||||
{
|
|
||||||
return QCursor::pos();
|
return QCursor::pos();
|
||||||
}
|
}
|
||||||
|
|
||||||
QPoint Input::mouseDelta()
|
QPoint Input::mouseDelta() {
|
||||||
{
|
|
||||||
return sg_mouseDelta;
|
return sg_mouseDelta;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Input::update()
|
void Input::update() {
|
||||||
{
|
|
||||||
// Update Mouse Delta
|
// Update Mouse Delta
|
||||||
sg_mousePrevPosition = sg_mouseCurrPosition;
|
sg_mousePrevPosition = sg_mouseCurrPosition;
|
||||||
sg_mouseCurrPosition = QCursor::pos();
|
sg_mouseCurrPosition = QCursor::pos();
|
||||||
|
@ -142,44 +128,35 @@ void Input::update()
|
||||||
Update(sg_keyInstances);
|
Update(sg_keyInstances);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Input::registerKeyPress(int k)
|
void Input::registerKeyPress(int k) {
|
||||||
{
|
auto it = FindKey((Qt::Key)k);
|
||||||
KeyContainer::iterator it = FindKey((Qt::Key)k);
|
if(it == sg_keyInstances.end()) {
|
||||||
if (it == sg_keyInstances.end())
|
|
||||||
{
|
|
||||||
sg_keyInstances.push_back(KeyInstance((Qt::Key)k, InputRegistered));
|
sg_keyInstances.push_back(KeyInstance((Qt::Key)k, InputRegistered));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Input::registerKeyRelease(int k)
|
void Input::registerKeyRelease(int k) {
|
||||||
{
|
auto it = FindKey((Qt::Key)k);
|
||||||
KeyContainer::iterator it = FindKey((Qt::Key)k);
|
if(it != sg_keyInstances.end()) {
|
||||||
if (it != sg_keyInstances.end())
|
|
||||||
{
|
|
||||||
it->second = InputUnregistered;
|
it->second = InputUnregistered;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Input::registerMousePress(Qt::MouseButton btn)
|
void Input::registerMousePress(Qt::MouseButton btn) {
|
||||||
{
|
auto it = FindButton(btn);
|
||||||
ButtonContainer::iterator it = FindButton(btn);
|
if(it == sg_buttonInstances.end()) {
|
||||||
if (it == sg_buttonInstances.end())
|
|
||||||
{
|
|
||||||
sg_buttonInstances.push_back(ButtonInstance(btn, InputRegistered));
|
sg_buttonInstances.push_back(ButtonInstance(btn, InputRegistered));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Input::registerMouseRelease(Qt::MouseButton btn)
|
void Input::registerMouseRelease(Qt::MouseButton btn) {
|
||||||
{
|
auto it = FindButton(btn);
|
||||||
ButtonContainer::iterator it = FindButton(btn);
|
if(it != sg_buttonInstances.end()) {
|
||||||
if (it != sg_buttonInstances.end())
|
|
||||||
{
|
|
||||||
it->second = InputUnregistered;
|
it->second = InputUnregistered;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Input::reset()
|
void Input::reset() {
|
||||||
{
|
|
||||||
sg_keyInstances.clear();
|
sg_keyInstances.clear();
|
||||||
sg_buttonInstances.clear();
|
sg_buttonInstances.clear();
|
||||||
}
|
}
|
||||||
|
|
103
src/input.h
103
src/input.h
|
@ -12,52 +12,65 @@
|
||||||
#include <QPoint>
|
#include <QPoint>
|
||||||
#include <Qt>
|
#include <Qt>
|
||||||
|
|
||||||
|
#include <qtkapi.h>
|
||||||
|
#include <qtkwidget.h>
|
||||||
|
|
||||||
class Input {
|
namespace Qtk {
|
||||||
friend class MainWidget;
|
class QTKAPI Input {
|
||||||
public:
|
friend class Qtk::QtkWidget;
|
||||||
|
|
||||||
// Possible key states
|
public:
|
||||||
enum InputState
|
// Possible key states
|
||||||
{
|
enum InputState {
|
||||||
InputInvalid,
|
InputInvalid,
|
||||||
InputRegistered,
|
InputRegistered,
|
||||||
InputUnregistered,
|
InputUnregistered,
|
||||||
InputTriggered,
|
InputTriggered,
|
||||||
InputPressed,
|
InputPressed,
|
||||||
InputReleased
|
InputReleased
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implementation
|
||||||
|
static InputState keyState(Qt::Key key);
|
||||||
|
static InputState buttonState(Qt::MouseButton button);
|
||||||
|
|
||||||
|
static QPoint mousePosition();
|
||||||
|
static QPoint mouseDelta();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// State updating
|
||||||
|
static void update();
|
||||||
|
static void registerKeyPress(int key);
|
||||||
|
static void registerKeyRelease(int key);
|
||||||
|
static void registerMousePress(Qt::MouseButton button);
|
||||||
|
static void registerMouseRelease(Qt::MouseButton button);
|
||||||
|
static void reset();
|
||||||
};
|
};
|
||||||
|
} // namespace Qtk
|
||||||
|
|
||||||
// State checking
|
#endif // QTOPENGL_INPUT_H
|
||||||
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);
|
|
||||||
static InputState buttonState(Qt::MouseButton button);
|
|
||||||
|
|
||||||
static QPoint mousePosition();
|
|
||||||
static QPoint mouseDelta();
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
// State updating
|
|
||||||
static void update();
|
|
||||||
static void registerKeyPress(int key);
|
|
||||||
static void registerKeyRelease(int key);
|
|
||||||
static void registerMousePress(Qt::MouseButton button);
|
|
||||||
static void registerMouseRelease(Qt::MouseButton button);
|
|
||||||
static void reset();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // QTOPENGL_INPUT_H
|
|
||||||
|
|
|
@ -18,54 +18,58 @@
|
||||||
#define QTK_DEBUG
|
#define QTK_DEBUG
|
||||||
|
|
||||||
class MeshRenderer;
|
class MeshRenderer;
|
||||||
|
|
||||||
class Model;
|
class Model;
|
||||||
|
|
||||||
class Object;
|
class Object;
|
||||||
|
|
||||||
class Scene;
|
class Scene;
|
||||||
|
|
||||||
class Skybox;
|
class Skybox;
|
||||||
|
|
||||||
class OpenGLTextureFactory;
|
class OpenGLTextureFactory;
|
||||||
|
|
||||||
class MainWidget : public QOpenGLWidget,
|
class MainWidget : public QOpenGLWidget, protected QOpenGLFunctions {
|
||||||
protected QOpenGLFunctions {
|
Q_OBJECT;
|
||||||
Q_OBJECT;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Constructors
|
// Constructors
|
||||||
MainWidget();
|
MainWidget();
|
||||||
explicit MainWidget(QWidget *parent);
|
explicit MainWidget(QWidget * parent);
|
||||||
explicit MainWidget(const QSurfaceFormat &format);
|
explicit MainWidget(const QSurfaceFormat & format);
|
||||||
~MainWidget() override;
|
~MainWidget() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void teardownGL();
|
void teardownGL();
|
||||||
void initObjects();
|
void initObjects();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Inherited virtual Members
|
// Inherited virtual Members
|
||||||
void paintGL() override;
|
void paintGL() override;
|
||||||
void initializeGL() override;
|
void initializeGL() override;
|
||||||
void resizeGL(int width, int height) override;
|
void resizeGL(int width, int height) override;
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void update();
|
void update();
|
||||||
void messageLogged(const QOpenGLDebugMessage &msg);
|
void messageLogged(const QOpenGLDebugMessage & msg);
|
||||||
|
|
||||||
// Protected Helpers
|
// Protected Helpers
|
||||||
protected:
|
protected:
|
||||||
void keyPressEvent(QKeyEvent *event);
|
void keyPressEvent(QKeyEvent * event);
|
||||||
void keyReleaseEvent(QKeyEvent *event);
|
void keyReleaseEvent(QKeyEvent * event);
|
||||||
void mousePressEvent(QMouseEvent *event);
|
void mousePressEvent(QMouseEvent * event);
|
||||||
void mouseReleaseEvent(QMouseEvent *event);
|
void mouseReleaseEvent(QMouseEvent * event);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Private helpers
|
// Private helpers
|
||||||
void initializeWidget();
|
void initializeWidget();
|
||||||
void printContextInformation();
|
void printContextInformation();
|
||||||
void updateCameraInput();
|
void updateCameraInput();
|
||||||
|
|
||||||
Scene * mScene;
|
Scene * mScene;
|
||||||
Object * mObject;
|
Object * mObject;
|
||||||
|
|
||||||
QOpenGLDebugLogger * mDebugLogger;
|
QOpenGLDebugLogger * mDebugLogger;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // QTK_MAINWIDGET_H
|
#endif // QTK_MAINWIDGET_H
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
#include "mainwindow.h"
|
|
||||||
#include "ui_mainwindow.h"
|
|
||||||
|
|
||||||
MainWindow::MainWindow(QWidget *parent) :
|
|
||||||
QMainWindow(parent),
|
|
||||||
ui(new Ui::MainWindow)
|
|
||||||
{
|
|
||||||
ui->setupUi(this);
|
|
||||||
setWindowIcon(QIcon("../resources/icon.png"));
|
|
||||||
}
|
|
||||||
|
|
||||||
MainWindow::~MainWindow()
|
|
||||||
{
|
|
||||||
delete ui;
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
#ifndef MAINWINDOW_H
|
|
||||||
#define MAINWINDOW_H
|
|
||||||
|
|
||||||
#include <QMainWindow>
|
|
||||||
|
|
||||||
#include "main-widget_export.h"
|
|
||||||
|
|
||||||
namespace Ui {
|
|
||||||
class MainWindow;
|
|
||||||
}
|
|
||||||
|
|
||||||
class MAIN_WIDGET_EXPORT MainWindow : public QMainWindow
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit MainWindow(QWidget *parent = nullptr);
|
|
||||||
~MainWindow();
|
|
||||||
|
|
||||||
private:
|
|
||||||
Ui::MainWindow *ui;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // MAINWINDOW_H
|
|
|
@ -1,104 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<ui version="4.0">
|
|
||||||
<class>MainWindow</class>
|
|
||||||
<widget class="QMainWindow" name="MainWindow">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>800</width>
|
|
||||||
<height>600</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string>Qtk - MainWindow</string>
|
|
||||||
</property>
|
|
||||||
<widget class="QWidget" name="centralwidget">
|
|
||||||
<widget class="MainWidget" name="openGLWidget">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>10</x>
|
|
||||||
<y>10</y>
|
|
||||||
<width>775</width>
|
|
||||||
<height>550</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</widget>
|
|
||||||
<widget class="QMenuBar" name="menubar">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>800</width>
|
|
||||||
<height>22</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<widget class="QMenu" name="menuTest">
|
|
||||||
<property name="title">
|
|
||||||
<string>File</string>
|
|
||||||
</property>
|
|
||||||
<addaction name="actionOpen"/>
|
|
||||||
<addaction name="actionSave_2"/>
|
|
||||||
<addaction name="actionSave_as"/>
|
|
||||||
<addaction name="actionExit"/>
|
|
||||||
</widget>
|
|
||||||
<widget class="QMenu" name="menuView">
|
|
||||||
<property name="title">
|
|
||||||
<string>View</string>
|
|
||||||
</property>
|
|
||||||
<addaction name="actionShow_Console"/>
|
|
||||||
</widget>
|
|
||||||
<addaction name="menuTest"/>
|
|
||||||
<addaction name="menuView"/>
|
|
||||||
</widget>
|
|
||||||
<widget class="QStatusBar" name="statusbar"/>
|
|
||||||
<action name="actionOtherTest">
|
|
||||||
<property name="text">
|
|
||||||
<string>Save</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="actionSave">
|
|
||||||
<property name="text">
|
|
||||||
<string>Save</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="actionOpen">
|
|
||||||
<property name="text">
|
|
||||||
<string>Open...</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="actionSave_2">
|
|
||||||
<property name="text">
|
|
||||||
<string>Save</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="actionSave_as">
|
|
||||||
<property name="text">
|
|
||||||
<string>Save as...</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="actionExit">
|
|
||||||
<property name="text">
|
|
||||||
<string>Exit</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="actionShow_Console">
|
|
||||||
<property name="checkable">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Show Console</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
</widget>
|
|
||||||
<customwidgets>
|
|
||||||
<customwidget>
|
|
||||||
<class>MainWidget</class>
|
|
||||||
<extends>QOpenGLWidget</extends>
|
|
||||||
<header>mainwidget.h</header>
|
|
||||||
</customwidget>
|
|
||||||
</customwidgets>
|
|
||||||
<resources/>
|
|
||||||
<connections/>
|
|
||||||
</ui>
|
|
435
src/mesh.cpp
435
src/mesh.cpp
|
@ -8,329 +8,372 @@
|
||||||
|
|
||||||
#include <mesh.h>
|
#include <mesh.h>
|
||||||
|
|
||||||
|
using namespace Qtk;
|
||||||
|
|
||||||
Cube::Cube(DrawMode mode)
|
Cube::Cube(DrawMode mode) {
|
||||||
{
|
|
||||||
mDrawMode = mode;
|
mDrawMode = mode;
|
||||||
switch(mode) {
|
switch(mode) {
|
||||||
// Cube data for use with glDrawArrays
|
// Cube data for use with glDrawArrays
|
||||||
case QTK_DRAW_ARRAYS:
|
case QTK_DRAW_ARRAYS:
|
||||||
mIndices = { /* No indices needed for glDrawArrays */ };
|
mIndices = {/* No indices needed for glDrawArrays */};
|
||||||
|
|
||||||
mNormals =
|
mNormals = {FACE_FRONT, FACE_BACK, FACE_TOP,
|
||||||
{FACE_FRONT, FACE_BACK, FACE_TOP, FACE_BOTTOM, FACE_LEFT, FACE_RIGHT};
|
FACE_BOTTOM, FACE_LEFT, FACE_RIGHT};
|
||||||
|
|
||||||
mVertices = {
|
mVertices = {// Face 1 (Front)
|
||||||
// Face 1 (Front)
|
VERTEX_FTR, VERTEX_FTL, VERTEX_FBL, VERTEX_FBL, VERTEX_FBR,
|
||||||
VERTEX_FTR, VERTEX_FTL, VERTEX_FBL,
|
VERTEX_FTR,
|
||||||
VERTEX_FBL, VERTEX_FBR, VERTEX_FTR,
|
// Face 2 (Back)
|
||||||
// Face 2 (Back)
|
VERTEX_BBR, VERTEX_BTL, VERTEX_BTR, VERTEX_BTL, VERTEX_BBR,
|
||||||
VERTEX_BBR, VERTEX_BTL, VERTEX_BTR,
|
VERTEX_BBL,
|
||||||
VERTEX_BTL, VERTEX_BBR, VERTEX_BBL,
|
// Face 3 (Top)
|
||||||
// Face 3 (Top)
|
VERTEX_FTR, VERTEX_BTR, VERTEX_BTL, VERTEX_BTL, VERTEX_FTL,
|
||||||
VERTEX_FTR, VERTEX_BTR, VERTEX_BTL,
|
VERTEX_FTR,
|
||||||
VERTEX_BTL, VERTEX_FTL, VERTEX_FTR,
|
// Face 4 (Bottom)
|
||||||
// Face 4 (Bottom)
|
VERTEX_FBR, VERTEX_FBL, VERTEX_BBL, VERTEX_BBL, VERTEX_BBR,
|
||||||
VERTEX_FBR, VERTEX_FBL, VERTEX_BBL,
|
VERTEX_FBR,
|
||||||
VERTEX_BBL, VERTEX_BBR, VERTEX_FBR,
|
// Face 5 (Left)
|
||||||
// Face 5 (Left)
|
VERTEX_FBL, VERTEX_FTL, VERTEX_BTL, VERTEX_FBL, VERTEX_BTL,
|
||||||
VERTEX_FBL, VERTEX_FTL, VERTEX_BTL,
|
VERTEX_BBL,
|
||||||
VERTEX_FBL, VERTEX_BTL, VERTEX_BBL,
|
// Face 6 (Right)
|
||||||
// Face 6 (Right)
|
VERTEX_FTR, VERTEX_FBR, VERTEX_BBR, VERTEX_BBR, VERTEX_BTR,
|
||||||
VERTEX_FTR, VERTEX_FBR, VERTEX_BBR,
|
VERTEX_FTR};
|
||||||
VERTEX_BBR, VERTEX_BTR, VERTEX_FTR
|
|
||||||
};
|
|
||||||
|
|
||||||
mColors = {
|
mColors = {// Face 1 (Front)
|
||||||
// Face 1 (Front)
|
RED, GREEN, BLUE, BLUE, WHITE, RED,
|
||||||
RED, GREEN, BLUE,
|
// Face 2 (Back)
|
||||||
BLUE, WHITE, RED,
|
YELLOW, CYAN, MAGENTA, CYAN, YELLOW, BLACK,
|
||||||
// Face 2 (Back)
|
// Face 3 (Top)
|
||||||
YELLOW, CYAN, MAGENTA,
|
RED, MAGENTA, CYAN, CYAN, GREEN, RED,
|
||||||
CYAN, YELLOW, BLACK,
|
// Face 4 (Bottom)
|
||||||
// Face 3 (Top)
|
WHITE, BLUE, BLACK, BLACK, YELLOW, WHITE,
|
||||||
RED, MAGENTA, CYAN,
|
// Face 5 (Left)
|
||||||
CYAN, GREEN, RED,
|
BLUE, GREEN, CYAN, BLUE, CYAN, BLACK,
|
||||||
// Face 4 (Bottom)
|
// Face 6 (Right)
|
||||||
WHITE, BLUE, BLACK,
|
RED, WHITE, YELLOW, YELLOW, MAGENTA, RED};
|
||||||
BLACK, YELLOW, WHITE,
|
|
||||||
// Face 5 (Left)
|
|
||||||
BLUE, GREEN, CYAN,
|
|
||||||
BLUE, CYAN, BLACK,
|
|
||||||
// Face 6 (Right)
|
|
||||||
RED, WHITE, YELLOW,
|
|
||||||
YELLOW, MAGENTA, RED
|
|
||||||
};
|
|
||||||
|
|
||||||
mTexCoords = {
|
mTexCoords = {// Face 1 (Front)
|
||||||
// Face 1 (Front)
|
UV_TOP, UV_ORIGIN, UV_RIGHT, UV_RIGHT, UV_CORNER, UV_TOP,
|
||||||
UV_TOP, UV_ORIGIN, UV_RIGHT,
|
// Face 2 (Back)
|
||||||
UV_RIGHT, UV_CORNER, UV_TOP,
|
UV_TOP, UV_RIGHT, UV_CORNER, UV_RIGHT, UV_TOP, UV_ORIGIN,
|
||||||
// Face 2 (Back)
|
// Face 3 (Top)
|
||||||
UV_TOP, UV_RIGHT, UV_CORNER,
|
UV_CORNER, UV_TOP, UV_ORIGIN, UV_ORIGIN, UV_RIGHT,
|
||||||
UV_RIGHT, UV_TOP, UV_ORIGIN,
|
UV_CORNER,
|
||||||
// Face 3 (Top)
|
// Face 4 (Bottom)
|
||||||
UV_CORNER, UV_TOP, UV_ORIGIN,
|
UV_TOP, UV_ORIGIN, UV_RIGHT, UV_RIGHT, UV_CORNER, UV_TOP,
|
||||||
UV_ORIGIN, UV_RIGHT, UV_CORNER,
|
// Face 5 (Left)
|
||||||
// Face 4 (Bottom)
|
UV_TOP, UV_CORNER, UV_RIGHT, UV_TOP, UV_RIGHT, UV_ORIGIN,
|
||||||
UV_TOP, UV_ORIGIN, UV_RIGHT,
|
// Face 6 (Right)
|
||||||
UV_RIGHT, UV_CORNER, UV_TOP,
|
UV_TOP, UV_CORNER, UV_RIGHT, UV_RIGHT, UV_ORIGIN, UV_TOP};
|
||||||
// Face 5 (Left)
|
|
||||||
UV_TOP, UV_CORNER, UV_RIGHT,
|
|
||||||
UV_TOP, UV_RIGHT, UV_ORIGIN,
|
|
||||||
// Face 6 (Right)
|
|
||||||
UV_TOP, UV_CORNER, UV_RIGHT,
|
|
||||||
UV_RIGHT, UV_ORIGIN, UV_TOP
|
|
||||||
};
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
// Cube data for use with glDrawElements
|
// Cube data for use with glDrawElements
|
||||||
case QTK_DRAW_ELEMENTS:
|
case QTK_DRAW_ELEMENTS:
|
||||||
mNormals =
|
mNormals = {
|
||||||
{/* For normals and glDrawElements, see QTK_DRAW_ELEMENTS_NORMALS */};
|
/* For normals and glDrawElements, see QTK_DRAW_ELEMENTS_NORMALS */};
|
||||||
mTexCoords =
|
mTexCoords = {
|
||||||
{ /* For UVs and glDrawElements, see QTK_DRAW_ELEMENTS_NORMALS */ };
|
/* For UVs and glDrawElements, see QTK_DRAW_ELEMENTS_NORMALS */};
|
||||||
|
|
||||||
mColors = {RED, GREEN, BLUE, WHITE, YELLOW, CYAN, MAGENTA, BLACK};
|
mColors = {RED, GREEN, BLUE, WHITE, YELLOW, CYAN, MAGENTA, BLACK};
|
||||||
|
|
||||||
mVertices = {
|
mVertices = {// 0 1 2 3
|
||||||
// 0 1 2 3
|
VERTEX_FTR, VERTEX_FTL, VERTEX_FBL, VERTEX_FBR,
|
||||||
VERTEX_FTR, VERTEX_FTL, VERTEX_FBL, VERTEX_FBR,
|
// 4 5 6 7
|
||||||
// 4 5 6 7
|
VERTEX_BTR, VERTEX_BTL, VERTEX_BBL, VERTEX_BBR};
|
||||||
VERTEX_BTR, VERTEX_BTL, VERTEX_BBL, VERTEX_BBR
|
mIndices = {// Face 1 (Front)
|
||||||
};
|
0, 1, 2, 2, 3, 0,
|
||||||
mIndices = {
|
// Face 2 (Back)
|
||||||
// Face 1 (Front)
|
7, 5, 4, 5, 7, 6,
|
||||||
0, 1, 2, 2, 3, 0,
|
// Face 3 (Top)
|
||||||
// Face 2 (Back)
|
0, 4, 5, 5, 1, 0,
|
||||||
7, 5, 4, 5, 7, 6,
|
// Face 4 (Bottom)
|
||||||
// Face 3 (Top)
|
3, 2, 6, 6, 7, 3,
|
||||||
0, 4, 5, 5, 1, 0,
|
// Face 5 (Left)
|
||||||
// Face 4 (Bottom)
|
2, 1, 5, 2, 5, 6,
|
||||||
3, 2, 6, 6, 7, 3,
|
// Face 6 (Right)
|
||||||
// Face 5 (Left)
|
0, 3, 7, 7, 4, 0};
|
||||||
2, 1, 5, 2, 5, 6,
|
|
||||||
// Face 6 (Right)
|
|
||||||
0, 3, 7, 7, 4, 0
|
|
||||||
};
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Cube shape data for using normals and UVs with glDrawElements
|
// Cube shape data for using normals and UVs with glDrawElements
|
||||||
case QTK_DRAW_ELEMENTS_NORMALS:
|
case QTK_DRAW_ELEMENTS_NORMALS:
|
||||||
mColors = {RED, GREEN, BLUE, WHITE, YELLOW, CYAN, MAGENTA, BLACK};
|
mColors = {RED, GREEN, BLUE, WHITE, YELLOW, CYAN, MAGENTA, BLACK};
|
||||||
|
|
||||||
mVertices = {
|
mVertices = {// Face 1 (Front)
|
||||||
// Face 1 (Front)
|
// 0 1 2 3
|
||||||
// 0 1 2 3
|
VERTEX_FTL, VERTEX_FBL, VERTEX_FBR, VERTEX_FTR,
|
||||||
VERTEX_FTL, VERTEX_FBL, VERTEX_FBR, VERTEX_FTR,
|
// Face 2 (Back)
|
||||||
// Face 2 (Back)
|
// 4 5 6 7
|
||||||
// 4 5 6 7
|
VERTEX_BTL, VERTEX_BBL, VERTEX_BBR, VERTEX_BTR,
|
||||||
VERTEX_BTL, VERTEX_BBL, VERTEX_BBR, VERTEX_BTR,
|
// Face 3 (Top)
|
||||||
// Face 3 (Top)
|
// 8 9 10 11
|
||||||
// 8 9 10 11
|
VERTEX_FTL, VERTEX_BTL, VERTEX_BTR, VERTEX_FTR,
|
||||||
VERTEX_FTL, VERTEX_BTL, VERTEX_BTR, VERTEX_FTR,
|
// Face 4 (Bottom)
|
||||||
// Face 4 (Bottom)
|
// 12 13 14 15
|
||||||
// 12 13 14 15
|
VERTEX_FBL, VERTEX_BBL, VERTEX_BBR, VERTEX_FBR,
|
||||||
VERTEX_FBL, VERTEX_BBL, VERTEX_BBR, VERTEX_FBR,
|
// Face 5 (Left)
|
||||||
// Face 5 (Left)
|
// 16 17 18 19
|
||||||
// 16 17 18 19
|
VERTEX_FBL, VERTEX_BBL, VERTEX_BTL, VERTEX_FTL,
|
||||||
VERTEX_FBL, VERTEX_BBL, VERTEX_BTL, VERTEX_FTL,
|
// Face 6 (Right)
|
||||||
// Face 6 (Right)
|
// 20 21 22 23
|
||||||
// 20 21 22 23
|
VERTEX_FBR, VERTEX_BBR, VERTEX_BTR, VERTEX_FTR};
|
||||||
VERTEX_FBR, VERTEX_BBR, VERTEX_BTR, VERTEX_FTR
|
|
||||||
};
|
|
||||||
|
|
||||||
mIndices = {
|
mIndices = {// Face 1 (Front)
|
||||||
// Face 1 (Front)
|
0, 1, 2, 2, 3, 0,
|
||||||
0, 1, 2, 2, 3, 0,
|
// Face 2 (Back)
|
||||||
// Face 2 (Back)
|
4, 5, 6, 6, 7, 4,
|
||||||
4, 5, 6, 6, 7, 4,
|
// Face 3 (Top)
|
||||||
// Face 3 (Top)
|
8, 9, 10, 10, 11, 8,
|
||||||
8, 9, 10, 10, 11, 8,
|
// Face 4 (Bottom)
|
||||||
// Face 4 (Bottom)
|
12, 13, 14, 14, 15, 12,
|
||||||
12, 13, 14, 14, 15, 12,
|
|
||||||
|
|
||||||
// Face 5 (Left)
|
// Face 5 (Left)
|
||||||
16, 17, 18, 18, 19, 16,
|
16, 17, 18, 18, 19, 16,
|
||||||
// Face 6 (Right)
|
// Face 6 (Right)
|
||||||
20, 21, 22, 22, 23, 20
|
20, 21, 22, 22, 23, 20};
|
||||||
};
|
|
||||||
|
|
||||||
mNormals = {
|
mNormals = {
|
||||||
VECTOR_FORWARD, VECTOR_FORWARD, VECTOR_FORWARD, VECTOR_FORWARD,
|
VECTOR_FORWARD, VECTOR_FORWARD, VECTOR_FORWARD, VECTOR_FORWARD,
|
||||||
VECTOR_BACK, VECTOR_BACK, VECTOR_BACK, VECTOR_BACK,
|
VECTOR_BACK, VECTOR_BACK, VECTOR_BACK, VECTOR_BACK,
|
||||||
VECTOR_UP, VECTOR_UP, VECTOR_UP, VECTOR_UP,
|
VECTOR_UP, VECTOR_UP, VECTOR_UP, VECTOR_UP,
|
||||||
VECTOR_DOWN, VECTOR_DOWN, VECTOR_DOWN, VECTOR_DOWN,
|
VECTOR_DOWN, VECTOR_DOWN, VECTOR_DOWN, VECTOR_DOWN,
|
||||||
VECTOR_LEFT, VECTOR_LEFT, VECTOR_LEFT, VECTOR_LEFT,
|
VECTOR_LEFT, VECTOR_LEFT, VECTOR_LEFT, VECTOR_LEFT,
|
||||||
VECTOR_RIGHT, VECTOR_RIGHT, VECTOR_RIGHT, VECTOR_RIGHT,
|
VECTOR_RIGHT, VECTOR_RIGHT, VECTOR_RIGHT, VECTOR_RIGHT,
|
||||||
};
|
};
|
||||||
|
|
||||||
mTexCoords = {
|
mTexCoords = {
|
||||||
// Face 1 (Front)
|
// Face 1 (Front)
|
||||||
UV_TOP, UV_RIGHT, UV_CORNER,
|
UV_TOP,
|
||||||
UV_RIGHT, UV_TOP, UV_ORIGIN,
|
UV_RIGHT,
|
||||||
|
UV_CORNER,
|
||||||
|
UV_RIGHT,
|
||||||
|
UV_TOP,
|
||||||
|
UV_ORIGIN,
|
||||||
// Face 2 (Back)
|
// Face 2 (Back)
|
||||||
UV_TOP, UV_RIGHT, UV_CORNER,
|
UV_TOP,
|
||||||
UV_RIGHT, UV_TOP, UV_ORIGIN,
|
UV_RIGHT,
|
||||||
|
UV_CORNER,
|
||||||
|
UV_RIGHT,
|
||||||
|
UV_TOP,
|
||||||
|
UV_ORIGIN,
|
||||||
// Face 3 (Top)
|
// Face 3 (Top)
|
||||||
UV_TOP, UV_RIGHT, UV_CORNER,
|
UV_TOP,
|
||||||
UV_RIGHT, UV_TOP, UV_ORIGIN,
|
UV_RIGHT,
|
||||||
|
UV_CORNER,
|
||||||
|
UV_RIGHT,
|
||||||
|
UV_TOP,
|
||||||
|
UV_ORIGIN,
|
||||||
// Face 4 (Bottom)
|
// Face 4 (Bottom)
|
||||||
UV_TOP, UV_RIGHT, UV_CORNER,
|
UV_TOP,
|
||||||
UV_RIGHT, UV_TOP, UV_ORIGIN,
|
UV_RIGHT,
|
||||||
|
UV_CORNER,
|
||||||
|
UV_RIGHT,
|
||||||
|
UV_TOP,
|
||||||
|
UV_ORIGIN,
|
||||||
// Face 5 (Left)
|
// Face 5 (Left)
|
||||||
UV_TOP, UV_RIGHT, UV_CORNER,
|
UV_TOP,
|
||||||
UV_RIGHT, UV_TOP, UV_ORIGIN,
|
UV_RIGHT,
|
||||||
|
UV_CORNER,
|
||||||
|
UV_RIGHT,
|
||||||
|
UV_TOP,
|
||||||
|
UV_ORIGIN,
|
||||||
// Face 6 (Right)
|
// Face 6 (Right)
|
||||||
UV_TOP, UV_RIGHT, UV_CORNER,
|
UV_TOP,
|
||||||
UV_RIGHT, UV_TOP, UV_ORIGIN,
|
UV_RIGHT,
|
||||||
|
UV_CORNER,
|
||||||
|
UV_RIGHT,
|
||||||
|
UV_TOP,
|
||||||
|
UV_ORIGIN,
|
||||||
};
|
};
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Triangle::Triangle(DrawMode mode)
|
Triangle::Triangle(DrawMode mode) {
|
||||||
{
|
|
||||||
mDrawMode = mode;
|
mDrawMode = mode;
|
||||||
const QVector3D triangleTop = QVector3D(0.0f, 0.5f, 0.0f);
|
const QVector3D triangleTop = QVector3D(0.0f, 0.5f, 0.0f);
|
||||||
switch(mode) {
|
switch(mode) {
|
||||||
case QTK_DRAW_ARRAYS:
|
case QTK_DRAW_ARRAYS:
|
||||||
mIndices = { /* No indices needed for glDrawArrays */ };
|
mIndices = {/* No indices needed for glDrawArrays */};
|
||||||
|
|
||||||
mColors = { RED, GREEN, BLUE, WHITE, YELLOW, CYAN, MAGENTA, BLACK };
|
mColors = {RED, GREEN, BLUE, WHITE, YELLOW, CYAN, MAGENTA, BLACK};
|
||||||
|
|
||||||
mVertices = {
|
mVertices = {
|
||||||
// Bottom face (Base of the pyramid)
|
// Bottom face (Base of the pyramid)
|
||||||
VERTEX_BBL, VERTEX_BBR, VERTEX_FBR,
|
VERTEX_BBL,
|
||||||
VERTEX_FBR, VERTEX_FBL, VERTEX_BBL,
|
VERTEX_BBR,
|
||||||
|
VERTEX_FBR,
|
||||||
|
VERTEX_FBR,
|
||||||
|
VERTEX_FBL,
|
||||||
|
VERTEX_BBL,
|
||||||
|
|
||||||
// Front face
|
// Front face
|
||||||
VERTEX_FBL, VERTEX_FBR, triangleTop,
|
VERTEX_FBL,
|
||||||
|
VERTEX_FBR,
|
||||||
|
triangleTop,
|
||||||
// Back face
|
// Back face
|
||||||
VERTEX_BBR, VERTEX_BBL, triangleTop,
|
VERTEX_BBR,
|
||||||
|
VERTEX_BBL,
|
||||||
|
triangleTop,
|
||||||
// Left face
|
// Left face
|
||||||
VERTEX_BBL, VERTEX_FBL, triangleTop,
|
VERTEX_BBL,
|
||||||
|
VERTEX_FBL,
|
||||||
|
triangleTop,
|
||||||
// Right face
|
// Right face
|
||||||
VERTEX_FBR, VERTEX_BBR, triangleTop,
|
VERTEX_FBR,
|
||||||
|
VERTEX_BBR,
|
||||||
|
triangleTop,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Find normals for each triangle of the mesh
|
// Find normals for each triangle of the mesh
|
||||||
for (int i = 0; i < mVertices.size(); i += 3) {
|
for(int i = 0; i < mVertices.size(); i += 3) {
|
||||||
QVector3D vertexNormal =
|
QVector3D vertexNormal =
|
||||||
QVector3D::normal(mVertices[i], mVertices[i+1], mVertices[i+2]);
|
QVector3D::normal(mVertices[i], mVertices[i + 1], mVertices[i + 2]);
|
||||||
// Three points share this normal
|
// Three points share this normal
|
||||||
for (int j = 0; j < 3; j++) {
|
for(int j = 0; j < 3; j++) {
|
||||||
mNormals.push_back(vertexNormal);
|
mNormals.push_back(vertexNormal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mTexCoords = {
|
mTexCoords = {
|
||||||
// Bottom face (Base of the pyramid)
|
// Bottom face (Base of the pyramid)
|
||||||
UV_ORIGIN, UV_RIGHT, UV_CORNER,
|
UV_ORIGIN,
|
||||||
UV_CORNER, UV_TOP, UV_ORIGIN,
|
UV_RIGHT,
|
||||||
|
UV_CORNER,
|
||||||
|
UV_CORNER,
|
||||||
|
UV_TOP,
|
||||||
|
UV_ORIGIN,
|
||||||
|
|
||||||
// Front face
|
// Front face
|
||||||
UV_ORIGIN, UV_RIGHT, UV_CORNER,
|
UV_ORIGIN,
|
||||||
|
UV_RIGHT,
|
||||||
|
UV_CORNER,
|
||||||
// Back face
|
// Back face
|
||||||
UV_ORIGIN, UV_RIGHT, UV_CORNER,
|
UV_ORIGIN,
|
||||||
|
UV_RIGHT,
|
||||||
|
UV_CORNER,
|
||||||
// Left face
|
// Left face
|
||||||
UV_ORIGIN, UV_RIGHT, UV_CORNER,
|
UV_ORIGIN,
|
||||||
|
UV_RIGHT,
|
||||||
|
UV_CORNER,
|
||||||
// Right face
|
// Right face
|
||||||
UV_ORIGIN, UV_RIGHT, UV_CORNER,
|
UV_ORIGIN,
|
||||||
|
UV_RIGHT,
|
||||||
|
UV_CORNER,
|
||||||
};
|
};
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Triangle shape data for using glDrawElements
|
// Triangle shape data for using glDrawElements
|
||||||
case QTK_DRAW_ELEMENTS:
|
case QTK_DRAW_ELEMENTS:
|
||||||
mColors = { RED, GREEN, BLUE, WHITE, YELLOW, CYAN, MAGENTA, BLACK };
|
mColors = {RED, GREEN, BLUE, WHITE, YELLOW, CYAN, MAGENTA, BLACK};
|
||||||
|
|
||||||
mVertices = {VERTEX_FBL, VERTEX_FBR, VERTEX_BBL, VERTEX_BBR, triangleTop};
|
mVertices = {VERTEX_FBL, VERTEX_FBR, VERTEX_BBL, VERTEX_BBR, triangleTop};
|
||||||
|
|
||||||
mIndices = {
|
mIndices = {
|
||||||
// Bottom face (Base of the pyramid)
|
// Bottom face (Base of the pyramid)
|
||||||
2, 3, 1, // Use customVertexes[2], then 3, 1...
|
2, 3, 1, // Use customVertexes[2], then 3, 1...
|
||||||
1, 0, 2, // Use customVertexes[1], then 0, 2
|
1, 0, 2, // Use customVertexes[1], then 0, 2
|
||||||
|
|
||||||
0, 1, 4, // Front face
|
0, 1, 4, // Front face
|
||||||
3, 2, 4, // Back face
|
3, 2, 4, // Back face
|
||||||
2, 0, 4, // Left face
|
2, 0, 4, // Left face
|
||||||
1, 3, 4, // Right face
|
1, 3, 4, // Right face
|
||||||
};
|
};
|
||||||
|
|
||||||
mNormals =
|
mNormals = {
|
||||||
{/* Use QTK_DRAW_ELEMENTS_NORMALS for normals with glDrawElements */};
|
/* Use QTK_DRAW_ELEMENTS_NORMALS for normals with glDrawElements */};
|
||||||
|
|
||||||
mTexCoords = { /* No UVs for triangle with glDrawElements */ };
|
mTexCoords = {/* No UVs for triangle with glDrawElements */};
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Triangle shape data for using normals and UVs with glDrawElements
|
// Triangle shape data for using normals and UVs with glDrawElements
|
||||||
case QTK_DRAW_ELEMENTS_NORMALS:
|
case QTK_DRAW_ELEMENTS_NORMALS:
|
||||||
mColors = { RED, GREEN, BLUE, WHITE, YELLOW, CYAN, MAGENTA, BLACK };
|
mColors = {RED, GREEN, BLUE, WHITE, YELLOW, CYAN, MAGENTA, BLACK};
|
||||||
|
|
||||||
mVertices = {
|
mVertices = {
|
||||||
// Bottom face
|
// Bottom face
|
||||||
// 0 1 2
|
// 0 1 2
|
||||||
VERTEX_FBL, VERTEX_FBR, VERTEX_BBL,
|
VERTEX_FBL,
|
||||||
|
VERTEX_FBR,
|
||||||
|
VERTEX_BBL,
|
||||||
// 3 4 5
|
// 3 4 5
|
||||||
VERTEX_BBR, VERTEX_FBR, VERTEX_BBL,
|
VERTEX_BBR,
|
||||||
|
VERTEX_FBR,
|
||||||
|
VERTEX_BBL,
|
||||||
|
|
||||||
// Front face
|
// Front face
|
||||||
// 6 7 8
|
// 6 7 8
|
||||||
VERTEX_FBL, VERTEX_FBR, triangleTop,
|
VERTEX_FBL,
|
||||||
|
VERTEX_FBR,
|
||||||
|
triangleTop,
|
||||||
// Back face
|
// Back face
|
||||||
// 9 10 11
|
// 9 10 11
|
||||||
VERTEX_BBR, VERTEX_BBL, triangleTop,
|
VERTEX_BBR,
|
||||||
|
VERTEX_BBL,
|
||||||
|
triangleTop,
|
||||||
// Left face
|
// Left face
|
||||||
// 12 13 14
|
// 12 13 14
|
||||||
VERTEX_BBL, VERTEX_FBL, triangleTop,
|
VERTEX_BBL,
|
||||||
|
VERTEX_FBL,
|
||||||
|
triangleTop,
|
||||||
// Right face
|
// Right face
|
||||||
// 15 16 17
|
// 15 16 17
|
||||||
VERTEX_FBR, VERTEX_BBR, triangleTop,
|
VERTEX_FBR,
|
||||||
|
VERTEX_BBR,
|
||||||
|
triangleTop,
|
||||||
};
|
};
|
||||||
|
|
||||||
mIndices = {
|
mIndices = {
|
||||||
// Bottom face (Base of the pyramid)
|
// Bottom face (Base of the pyramid)
|
||||||
0, 1, 2, // Use customVertexes[2], then 3, 1...
|
0, 1, 2, // Use customVertexes[2], then 3, 1...
|
||||||
3, 4, 5, // Use customVertexes[1], then 0, 2
|
3, 4, 5, // Use customVertexes[1], then 0, 2
|
||||||
|
|
||||||
6, 7, 8, // Front face
|
6, 7, 8, // Front face
|
||||||
9, 10, 11, // Back face
|
9, 10, 11, // Back face
|
||||||
12, 13, 14, // Left face
|
12, 13, 14, // Left face
|
||||||
15, 16, 17, // Right face
|
15, 16, 17, // Right face
|
||||||
};
|
};
|
||||||
|
|
||||||
// Find normals for each triangle of the mesh
|
// Find normals for each triangle of the mesh
|
||||||
for (int i = 0; i < mVertices.size(); i += 3) {
|
for(int i = 0; i < mVertices.size(); i += 3) {
|
||||||
QVector3D vertexNormal =
|
QVector3D vertexNormal = QVector3D::normal(
|
||||||
QVector3D::normal(mVertices[mIndices[i]],
|
mVertices[mIndices[i]], mVertices[mIndices[i + 1]],
|
||||||
mVertices[mIndices[i+1]],
|
mVertices[mIndices[i + 2]]);
|
||||||
mVertices[mIndices[i+2]]);
|
|
||||||
// Three points share this normal
|
// Three points share this normal
|
||||||
for (int j = 0; j < 3; j++) {
|
for(int j = 0; j < 3; j++) {
|
||||||
mNormals.push_back(vertexNormal);
|
mNormals.push_back(vertexNormal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mTexCoords = {
|
mTexCoords = {
|
||||||
// Bottom face
|
// Bottom face
|
||||||
UV_ORIGIN, UV_RIGHT, UV_TOP,
|
UV_ORIGIN,
|
||||||
UV_CORNER, UV_RIGHT, UV_TOP,
|
UV_RIGHT,
|
||||||
|
UV_TOP,
|
||||||
|
UV_CORNER,
|
||||||
|
UV_RIGHT,
|
||||||
|
UV_TOP,
|
||||||
|
|
||||||
// Front face
|
// Front face
|
||||||
UV_ORIGIN, UV_RIGHT, UV_CORNER,
|
UV_ORIGIN,
|
||||||
|
UV_RIGHT,
|
||||||
|
UV_CORNER,
|
||||||
// Back face
|
// Back face
|
||||||
UV_ORIGIN, UV_RIGHT, UV_CORNER,
|
UV_ORIGIN,
|
||||||
|
UV_RIGHT,
|
||||||
|
UV_CORNER,
|
||||||
// Left face
|
// Left face
|
||||||
UV_ORIGIN, UV_RIGHT, UV_CORNER,
|
UV_ORIGIN,
|
||||||
|
UV_RIGHT,
|
||||||
|
UV_CORNER,
|
||||||
// Right face
|
// Right face
|
||||||
UV_ORIGIN, UV_RIGHT, UV_CORNER,
|
UV_ORIGIN,
|
||||||
|
UV_RIGHT,
|
||||||
|
UV_CORNER,
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
196
src/mesh.h
196
src/mesh.h
|
@ -11,24 +11,28 @@
|
||||||
#include <QOpenGLWidget>
|
#include <QOpenGLWidget>
|
||||||
#include <QVector2D>
|
#include <QVector2D>
|
||||||
#include <QVector3D>
|
#include <QVector3D>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include <qtkapi.h>
|
||||||
#include <transform3D.h>
|
#include <transform3D.h>
|
||||||
|
|
||||||
class MeshRenderer;
|
namespace Qtk {
|
||||||
class Object;
|
class MeshRenderer;
|
||||||
|
|
||||||
|
class Object;
|
||||||
|
|
||||||
// Define vertices for drawing a cube using two faces (8 vertex points)
|
// Define vertices for drawing a cube using two faces (8 vertex points)
|
||||||
// Front Vertices
|
// Front Vertices
|
||||||
#define VERTEX_FTR QVector3D( 0.5f, 0.5f, 0.5f) // 1
|
#define VERTEX_FTR QVector3D(0.5f, 0.5f, 0.5f) // 1
|
||||||
#define VERTEX_FTL QVector3D(-0.5f, 0.5f, 0.5f) // 2
|
#define VERTEX_FTL QVector3D(-0.5f, 0.5f, 0.5f) // 2
|
||||||
#define VERTEX_FBL QVector3D(-0.5f, -0.5f, 0.5f) // 3
|
#define VERTEX_FBL QVector3D(-0.5f, -0.5f, 0.5f) // 3
|
||||||
#define VERTEX_FBR QVector3D( 0.5f, -0.5f, 0.5f) // 4
|
#define VERTEX_FBR QVector3D(0.5f, -0.5f, 0.5f) // 4
|
||||||
|
|
||||||
// Back Vertices
|
// Back Vertices
|
||||||
#define VERTEX_BTR QVector3D( 0.5f, 0.5f, -0.5f) // 5
|
#define VERTEX_BTR QVector3D(0.5f, 0.5f, -0.5f) // 5
|
||||||
#define VERTEX_BTL QVector3D(-0.5f, 0.5f, -0.5f) // 6
|
#define VERTEX_BTL QVector3D(-0.5f, 0.5f, -0.5f) // 6
|
||||||
#define VERTEX_BBL QVector3D(-0.5f, -0.5f, -0.5f) // 7
|
#define VERTEX_BBL QVector3D(-0.5f, -0.5f, -0.5f) // 7
|
||||||
#define VERTEX_BBR QVector3D( 0.5f, -0.5f, -0.5f) // 8
|
#define VERTEX_BBR QVector3D(0.5f, -0.5f, -0.5f) // 8
|
||||||
|
|
||||||
// Direction vectors
|
// Direction vectors
|
||||||
#define VECTOR_UP QVector3D(0.0f, 1.0f, 0.0f)
|
#define VECTOR_UP QVector3D(0.0f, 1.0f, 0.0f)
|
||||||
|
@ -39,94 +43,128 @@ class Object;
|
||||||
#define VECTOR_BACK QVector3D(0.0f, 0.0f, -1.0f)
|
#define VECTOR_BACK QVector3D(0.0f, 0.0f, -1.0f)
|
||||||
|
|
||||||
// Identity and zero vectors
|
// Identity and zero vectors
|
||||||
#define VECTOR_ONE QVector3D(1.0f, 1.0f, 1.0f)
|
#define VECTOR_ONE QVector3D(1.0f, 1.0f, 1.0f)
|
||||||
#define VECTOR_ZERO QVector3D(0.0f, 0.0f, 0.0f)
|
#define VECTOR_ZERO QVector3D(0.0f, 0.0f, 0.0f)
|
||||||
|
|
||||||
// A series of direction vectors to represent cube face normal
|
// A series of direction vectors to represent cube face normal
|
||||||
#define FACE_TOP VECTOR_UP, VECTOR_UP, VECTOR_UP, \
|
#define FACE_TOP \
|
||||||
VECTOR_UP, VECTOR_UP, VECTOR_UP
|
VECTOR_UP, VECTOR_UP, VECTOR_UP, VECTOR_UP, VECTOR_UP, VECTOR_UP
|
||||||
#define FACE_BOTTOM VECTOR_DOWN, VECTOR_DOWN, VECTOR_DOWN, \
|
#define FACE_BOTTOM \
|
||||||
VECTOR_DOWN, VECTOR_DOWN, VECTOR_DOWN
|
VECTOR_DOWN, VECTOR_DOWN, VECTOR_DOWN, VECTOR_DOWN, VECTOR_DOWN, VECTOR_DOWN
|
||||||
#define FACE_LEFT VECTOR_LEFT, VECTOR_LEFT, VECTOR_LEFT, \
|
#define FACE_LEFT \
|
||||||
VECTOR_LEFT, VECTOR_LEFT, VECTOR_LEFT
|
VECTOR_LEFT, VECTOR_LEFT, VECTOR_LEFT, VECTOR_LEFT, VECTOR_LEFT, VECTOR_LEFT
|
||||||
#define FACE_RIGHT VECTOR_RIGHT, VECTOR_RIGHT, VECTOR_RIGHT, \
|
#define FACE_RIGHT \
|
||||||
VECTOR_RIGHT, VECTOR_RIGHT, VECTOR_RIGHT
|
VECTOR_RIGHT, VECTOR_RIGHT, VECTOR_RIGHT, VECTOR_RIGHT, VECTOR_RIGHT, \
|
||||||
#define FACE_FRONT VECTOR_FORWARD, VECTOR_FORWARD, VECTOR_FORWARD, \
|
VECTOR_RIGHT
|
||||||
VECTOR_FORWARD, VECTOR_FORWARD, VECTOR_FORWARD
|
#define FACE_FRONT \
|
||||||
#define FACE_BACK VECTOR_BACK, VECTOR_BACK, VECTOR_BACK, \
|
VECTOR_FORWARD, VECTOR_FORWARD, VECTOR_FORWARD, VECTOR_FORWARD, \
|
||||||
VECTOR_BACK, VECTOR_BACK, VECTOR_BACK
|
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
|
// Colors using QVector3Ds as RGB values
|
||||||
#define WHITE VECTOR_ONE
|
#define WHITE VECTOR_ONE
|
||||||
#define BLACK VECTOR_ZERO
|
#define BLACK VECTOR_ZERO
|
||||||
#define RED QVector3D(1.0f, 0.0f, 0.0f)
|
#define RED QVector3D(1.0f, 0.0f, 0.0f)
|
||||||
#define GREEN QVector3D(0.0f, 1.0f, 0.0f)
|
#define GREEN QVector3D(0.0f, 1.0f, 0.0f)
|
||||||
#define BLUE QVector3D(0.0f, 0.0f, 1.0f)
|
#define BLUE QVector3D(0.0f, 0.0f, 1.0f)
|
||||||
#define YELLOW QVector3D(1.0f, 1.0f, 0.0f)
|
#define YELLOW QVector3D(1.0f, 1.0f, 0.0f)
|
||||||
#define CYAN QVector3D(0.0f, 1.0f, 1.0f)
|
#define CYAN QVector3D(0.0f, 1.0f, 1.0f)
|
||||||
#define MAGENTA QVector3D(1.0f, 0.0f, 1.0f)
|
#define MAGENTA QVector3D(1.0f, 0.0f, 1.0f)
|
||||||
|
|
||||||
#define UV_ORIGIN QVector2D(0.0f, 0.0f)
|
#define UV_ORIGIN QVector2D(0.0f, 0.0f)
|
||||||
#define UV_TOP QVector2D(1.0f, 0.0f)
|
#define UV_TOP QVector2D(1.0f, 0.0f)
|
||||||
#define UV_RIGHT QVector2D(0.0f, 1.0f)
|
#define UV_RIGHT QVector2D(0.0f, 1.0f)
|
||||||
#define UV_CORNER QVector2D(1.0f, 1.0f)
|
#define UV_CORNER QVector2D(1.0f, 1.0f)
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
typedef std::vector<QVector3D> Vertices;
|
enum DrawMode {
|
||||||
typedef std::vector<QVector3D> Colors;
|
QTK_DRAW_ARRAYS,
|
||||||
typedef std::vector<GLuint> Indices;
|
QTK_DRAW_ELEMENTS,
|
||||||
typedef std::vector<QVector2D> TexCoords;
|
QTK_DRAW_ELEMENTS_NORMALS
|
||||||
typedef std::vector<QVector3D> Normals;
|
};
|
||||||
|
|
||||||
enum DrawMode { QTK_DRAW_ARRAYS, QTK_DRAW_ELEMENTS, QTK_DRAW_ELEMENTS_NORMALS };
|
struct QTKAPI ShapeBase {
|
||||||
|
explicit ShapeBase(
|
||||||
|
DrawMode mode = QTK_DRAW_ARRAYS, Vertices v = {}, Indices i = {},
|
||||||
|
Colors c = {}, TexCoords t = {}, Normals n = {}) :
|
||||||
|
mVertices(std::move(std::move(v))),
|
||||||
|
mColors(std::move(std::move(c))), mIndices(std::move(std::move(i))),
|
||||||
|
mTexCoords(std::move(std::move(t))),
|
||||||
|
mNormals(std::move(std::move(n))) {}
|
||||||
|
|
||||||
struct ShapeBase {
|
[[nodiscard]] inline const Vertices & getVertices() const {
|
||||||
ShapeBase(DrawMode mode=QTK_DRAW_ARRAYS, Vertices v={},Indices i={}, Colors c={},
|
return mVertices;
|
||||||
TexCoords t={}, Normals n={})
|
}
|
||||||
: mVertices(v), mColors(c), mIndices(i), mTexCoords(t), mNormals(n)
|
|
||||||
{}
|
|
||||||
|
|
||||||
inline const Vertices & getVertices() const { return mVertices;}
|
[[nodiscard]] inline const Indices & getIndexData() const {
|
||||||
inline const Indices & getIndexData() const { return mIndices;}
|
return mIndices;
|
||||||
inline const Colors & getColors() const { return mColors;}
|
}
|
||||||
inline const TexCoords & getTexCoords() const { return mTexCoords;}
|
|
||||||
inline const Normals & getNormals() const { return mNormals;}
|
|
||||||
|
|
||||||
protected:
|
[[nodiscard]] inline const Colors & getColors() const { return mColors; }
|
||||||
DrawMode mDrawMode;
|
|
||||||
|
|
||||||
Vertices mVertices;
|
[[nodiscard]] inline const TexCoords & getTexCoords() const {
|
||||||
Colors mColors;
|
return mTexCoords;
|
||||||
Indices mIndices;
|
}
|
||||||
TexCoords mTexCoords;
|
|
||||||
Normals mNormals;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Shape : public ShapeBase {
|
[[nodiscard]] inline const Normals & getNormals() const {
|
||||||
friend MeshRenderer;
|
return mNormals;
|
||||||
friend Object;
|
}
|
||||||
Shape () {}
|
|
||||||
Shape(const ShapeBase & rhs) : ShapeBase(rhs) {}
|
|
||||||
|
|
||||||
virtual inline void setVertices(const Vertices & value) {mVertices = value;}
|
protected:
|
||||||
virtual inline void setIndices(const Indices & value) {mIndices = value;}
|
DrawMode mDrawMode;
|
||||||
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 setShape(const Shape & value) { *this = value;}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Primitives inherit from ShapeBase, does not allow setting of shape values
|
Vertices mVertices;
|
||||||
class Mesh {
|
Colors mColors;
|
||||||
|
Indices mIndices;
|
||||||
|
TexCoords mTexCoords;
|
||||||
|
Normals mNormals;
|
||||||
|
};
|
||||||
|
|
||||||
};
|
struct Shape : public ShapeBase {
|
||||||
|
friend MeshRenderer;
|
||||||
|
friend Object;
|
||||||
|
|
||||||
struct Cube : public ShapeBase {
|
Shape() = default;
|
||||||
Cube(DrawMode mode=QTK_DRAW_ARRAYS);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Triangle : public ShapeBase {
|
explicit Shape(const ShapeBase & rhs) : ShapeBase(rhs) {}
|
||||||
Triangle(DrawMode mode=QTK_DRAW_ARRAYS);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // QTK_MESH_H
|
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 setShape(const Shape & value) { *this = value; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Primitives inherit from ShapeBase, does not allow setting of shape values
|
||||||
|
class QTKAPI Mesh {};
|
||||||
|
|
||||||
|
struct QTKAPI Cube : public ShapeBase {
|
||||||
|
explicit Cube(DrawMode mode = QTK_DRAW_ARRAYS);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct QTKAPI Triangle : public ShapeBase {
|
||||||
|
explicit Triangle(DrawMode mode = QTK_DRAW_ARRAYS);
|
||||||
|
};
|
||||||
|
} // namespace Qtk
|
||||||
|
|
||||||
|
#endif // QTK_MESH_H
|
||||||
|
|
|
@ -8,54 +8,56 @@
|
||||||
|
|
||||||
#include <QImageReader>
|
#include <QImageReader>
|
||||||
|
|
||||||
#include <scene.h>
|
#include <abstractscene.h>
|
||||||
|
#include <meshrenderer.h>
|
||||||
#include <texture.h>
|
#include <texture.h>
|
||||||
|
|
||||||
#include <meshrenderer.h>
|
using namespace Qtk;
|
||||||
|
|
||||||
|
|
||||||
// Static QHash that holds all MeshRenderer instances using their mName as keys
|
// Static QHash that holds all MeshRenderer instances using their mName as keys
|
||||||
MeshRenderer::MeshManager MeshRenderer::sInstances;
|
Qtk::MeshRenderer::MeshManager Qtk::MeshRenderer::sInstances;
|
||||||
|
|
||||||
MeshRenderer::MeshRenderer(const char * name, const ShapeBase & shape)
|
MeshRenderer::MeshRenderer(const char * name, const ShapeBase & shape) :
|
||||||
: Object(name, shape), mVertexShader(":/multi-color.vert"),
|
Object(name, shape), mVertexShader(":/multi-color.vert"),
|
||||||
mFragmentShader(":/multi-color.frag"), mDrawType(GL_TRIANGLES),
|
mFragmentShader(":/multi-color.frag"), mDrawType(GL_TRIANGLES),
|
||||||
mHasTexture(false)
|
mHasTexture(false) {
|
||||||
{
|
|
||||||
mShape = Shape(shape);
|
mShape = Shape(shape);
|
||||||
init();
|
init();
|
||||||
sInstances.insert(name, this);
|
sInstances.insert(name, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshRenderer::~MeshRenderer()
|
MeshRenderer::~MeshRenderer() {
|
||||||
{
|
|
||||||
sInstances.remove(mName);
|
sInstances.remove(mName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Static member function to retrieve instances of MeshRenderers
|
// Static member function to retrieve instances of MeshRenderers
|
||||||
MeshRenderer * MeshRenderer::getInstance(const QString & name)
|
MeshRenderer * MeshRenderer::getInstance(const QString & name) {
|
||||||
{ return sInstances[name];}
|
return sInstances[name];
|
||||||
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Public Member Functions
|
* Public Member Functions
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
void MeshRenderer::init()
|
void MeshRenderer::init() {
|
||||||
{
|
if(mVAO.isCreated()) {
|
||||||
if (mVAO.isCreated()) mVAO.destroy();
|
mVAO.destroy();
|
||||||
if (mProgram.isLinked()) mProgram.removeAllShaders();
|
}
|
||||||
if (mVBO.isCreated()) mVBO.destroy();
|
if(mProgram.isLinked()) {
|
||||||
|
mProgram.removeAllShaders();
|
||||||
|
}
|
||||||
|
if(mVBO.isCreated()) {
|
||||||
|
mVBO.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
mVAO.create();
|
mVAO.create();
|
||||||
mVAO.bind();
|
mVAO.bind();
|
||||||
|
|
||||||
mProgram.create();
|
mProgram.create();
|
||||||
mProgram.addShaderFromSourceFile(QOpenGLShader::Vertex,
|
mProgram.addShaderFromSourceFile(
|
||||||
mVertexShader.c_str());
|
QOpenGLShader::Vertex, mVertexShader.c_str());
|
||||||
mProgram.addShaderFromSourceFile(QOpenGLShader::Fragment,
|
mProgram.addShaderFromSourceFile(
|
||||||
mFragmentShader.c_str());
|
QOpenGLShader::Fragment, mFragmentShader.c_str());
|
||||||
mProgram.link();
|
mProgram.link();
|
||||||
mProgram.bind();
|
mProgram.bind();
|
||||||
|
|
||||||
|
@ -69,18 +71,16 @@ void MeshRenderer::init()
|
||||||
combined.insert(combined.end(), getVertices().begin(), getVertices().end());
|
combined.insert(combined.end(), getVertices().begin(), getVertices().end());
|
||||||
combined.insert(combined.end(), getColors().begin(), getColors().end());
|
combined.insert(combined.end(), getColors().begin(), getColors().end());
|
||||||
|
|
||||||
mVBO.allocate(combined.data(),
|
mVBO.allocate(combined.data(), combined.size() * sizeof(combined[0]));
|
||||||
combined.size() * sizeof(combined[0]));
|
|
||||||
|
|
||||||
// Enable position attribute
|
// Enable position attribute
|
||||||
mProgram.enableAttributeArray(0);
|
mProgram.enableAttributeArray(0);
|
||||||
mProgram.setAttributeBuffer(0, GL_FLOAT, 0,
|
mProgram.setAttributeBuffer(0, GL_FLOAT, 0, 3, sizeof(QVector3D));
|
||||||
3, sizeof(QVector3D));
|
|
||||||
// Enable color attribute, setting offset to total size of vertices()
|
// Enable color attribute, setting offset to total size of vertices()
|
||||||
mProgram.enableAttributeArray(1);
|
mProgram.enableAttributeArray(1);
|
||||||
mProgram.setAttributeBuffer(1, GL_FLOAT,
|
mProgram.setAttributeBuffer(
|
||||||
getVertices().size() * sizeof(getVertices()[0]),
|
1, GL_FLOAT, getVertices().size() * sizeof(getVertices()[0]), 3,
|
||||||
3, sizeof(QVector3D));
|
sizeof(QVector3D));
|
||||||
|
|
||||||
mVBO.release();
|
mVBO.release();
|
||||||
|
|
||||||
|
@ -88,8 +88,7 @@ void MeshRenderer::init()
|
||||||
mVAO.release();
|
mVAO.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshRenderer::draw()
|
void MeshRenderer::draw() {
|
||||||
{
|
|
||||||
mProgram.bind();
|
mProgram.bind();
|
||||||
mVAO.bind();
|
mVAO.bind();
|
||||||
|
|
||||||
|
@ -100,13 +99,14 @@ void MeshRenderer::draw()
|
||||||
// TODO: Automate uniforms some other way
|
// TODO: Automate uniforms some other way
|
||||||
setUniformMVP();
|
setUniformMVP();
|
||||||
|
|
||||||
if (mShape.mDrawMode == QTK_DRAW_ARRAYS) {
|
if(mShape.mDrawMode == QTK_DRAW_ARRAYS) {
|
||||||
glDrawArrays(mDrawType, 0, getVertices().size());
|
glDrawArrays(mDrawType, 0, getVertices().size());
|
||||||
}
|
} else if(
|
||||||
else if (mShape.mDrawMode == QTK_DRAW_ELEMENTS
|
mShape.mDrawMode == QTK_DRAW_ELEMENTS
|
||||||
|| mShape.mDrawMode == QTK_DRAW_ELEMENTS_NORMALS) {
|
|| mShape.mDrawMode == QTK_DRAW_ELEMENTS_NORMALS) {
|
||||||
glDrawElements(mDrawType, mShape.mIndices.size(),
|
glDrawElements(
|
||||||
GL_UNSIGNED_INT, mShape.mIndices.data());
|
mDrawType, mShape.mIndices.size(), GL_UNSIGNED_INT,
|
||||||
|
mShape.mIndices.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mTexture.hasTexture()) {
|
if(mTexture.hasTexture()) {
|
||||||
|
@ -117,41 +117,36 @@ void MeshRenderer::draw()
|
||||||
mProgram.release();
|
mProgram.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshRenderer::setShaders(const std::string & vert, const std::string & frag)
|
void MeshRenderer::setShaders(
|
||||||
{
|
const std::string & vert, const std::string & frag) {
|
||||||
mVertexShader = vert;
|
mVertexShader = vert;
|
||||||
mFragmentShader = frag;
|
mFragmentShader = frag;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshRenderer::setUniformMVP(const char * model, const char * view,
|
void MeshRenderer::setUniformMVP(
|
||||||
const char * projection)
|
const char * model, const char * view, const char * projection) {
|
||||||
{
|
|
||||||
mProgram.setUniformValue(projection, Scene::Projection());
|
mProgram.setUniformValue(projection, Scene::Projection());
|
||||||
mProgram.setUniformValue(view, Scene::View());
|
mProgram.setUniformValue(view, Scene::View());
|
||||||
mProgram.setUniformValue(model, mTransform.toMatrix());
|
mProgram.setUniformValue(model, mTransform.toMatrix());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshRenderer::setColor(const QVector3D & color)
|
void MeshRenderer::setColor(const QVector3D & color) {
|
||||||
{
|
if(mShape.mColors.empty()) {
|
||||||
if (mShape.mColors.empty()) {
|
for(const auto & vertex : mShape.getVertices()) {
|
||||||
for (const auto & vertex : mShape.getVertices()) {
|
|
||||||
mShape.mColors.push_back(color);
|
mShape.mColors.push_back(color);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
for(int i = 0; i < mShape.getColors().size(); i++) {
|
||||||
for (int i = 0; i < mShape.getColors().size(); i++) {
|
|
||||||
mShape.mColors[i] = color;
|
mShape.mColors[i] = color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Inherited Virtual Member Functions
|
* Inherited Virtual Member Functions
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
void MeshRenderer::setShape(const Shape & value)
|
void MeshRenderer::setShape(const Shape & value) {
|
||||||
{
|
|
||||||
Object::setShape(value);
|
Object::setShape(value);
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,65 +10,77 @@
|
||||||
|
|
||||||
#include <mesh.h>
|
#include <mesh.h>
|
||||||
#include <object.h>
|
#include <object.h>
|
||||||
|
#include <qtkapi.h>
|
||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
namespace Qtk {
|
||||||
|
class QTKAPI MeshRenderer : public Object {
|
||||||
|
public:
|
||||||
|
// Delegate constructors
|
||||||
|
MeshRenderer(
|
||||||
|
const char * name, Vertices vertices, Indices indices,
|
||||||
|
DrawMode mode = QTK_DRAW_ARRAYS) :
|
||||||
|
MeshRenderer(
|
||||||
|
name, ShapeBase(mode, std::move(vertices), std::move(indices))) {}
|
||||||
|
|
||||||
class MeshRenderer : public Object {
|
explicit MeshRenderer(const char * name) :
|
||||||
public:
|
MeshRenderer(name, Cube(QTK_DRAW_ELEMENTS)) {}
|
||||||
// Delegate constructors
|
|
||||||
MeshRenderer(const char * name, Vertices vertices, Indices indices,
|
|
||||||
DrawMode mode=QTK_DRAW_ARRAYS)
|
|
||||||
: MeshRenderer(name, ShapeBase(mode, std::move(vertices), std::move(indices)))
|
|
||||||
{}
|
|
||||||
explicit MeshRenderer(const char * name)
|
|
||||||
: MeshRenderer(name, Cube(QTK_DRAW_ELEMENTS))
|
|
||||||
{}
|
|
||||||
// Constructor
|
|
||||||
MeshRenderer(const char * name, const ShapeBase &shape);
|
|
||||||
~MeshRenderer();
|
|
||||||
|
|
||||||
// Retrieve a mesh by name stored within a static QHash
|
// Constructor
|
||||||
static MeshRenderer * getInstance(const QString & name);
|
MeshRenderer(const char * name, const ShapeBase & shape);
|
||||||
|
~MeshRenderer() override;
|
||||||
|
|
||||||
void init();
|
// Retrieve a mesh by name stored within a static QHash
|
||||||
void draw();
|
static MeshRenderer * getInstance(const QString & name);
|
||||||
|
|
||||||
// Draw types like GL_TRIANGLES, GL_POINTS, GL_LINES, etc
|
void init();
|
||||||
void setDrawType(int drawType) { mDrawType = drawType;}
|
void draw();
|
||||||
|
|
||||||
// Shader settings
|
// Draw types like GL_TRIANGLES, GL_POINTS, GL_LINES, etc
|
||||||
inline void setShaderVertex(const std::string & vert) { mVertexShader = vert;}
|
void setDrawType(int drawType) { mDrawType = drawType; }
|
||||||
inline void setShaderFragment(const std::string & frag)
|
|
||||||
{ mFragmentShader = frag;}
|
|
||||||
void setShaders(const std::string & vert, const std::string & frag);
|
|
||||||
|
|
||||||
template <typename T>
|
// Shader settings
|
||||||
inline void setUniform(int location, T value)
|
inline void setShaderVertex(const std::string & vert) {
|
||||||
{ mProgram.setUniformValue(location, value);}
|
mVertexShader = vert;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
inline void setShaderFragment(const std::string & frag) {
|
||||||
inline void setUniform(const char * location, T value)
|
mFragmentShader = frag;
|
||||||
{ mProgram.setUniformValue(location, value);}
|
}
|
||||||
|
|
||||||
// Set MVP matrix using this Object's transform
|
void setShaders(const std::string & vert, const std::string & frag);
|
||||||
// + View and projection provided by MainWidget static members
|
|
||||||
void setUniformMVP(const char * model="uModel", const char * view="uView",
|
|
||||||
const char * projection="uProjection");
|
|
||||||
|
|
||||||
// These functions modify data stored in a VBO
|
template <typename T> inline void setUniform(int location, T value) {
|
||||||
// + After calling them, the VBO will need to be reallocated
|
mProgram.setUniformValue(location, value);
|
||||||
void setShape(const Shape & value) override;
|
}
|
||||||
void setColor(const QVector3D & color);
|
|
||||||
|
|
||||||
// Static QHash of all mesh objects within the scene
|
template <typename T>
|
||||||
typedef QHash<QString, MeshRenderer *> MeshManager;
|
inline void setUniform(const char * location, T value) {
|
||||||
private:
|
mProgram.setUniformValue(location, value);
|
||||||
static MeshManager sInstances;
|
}
|
||||||
|
|
||||||
int mDrawType;
|
// Set MVP matrix using this Object's transform
|
||||||
bool mHasTexture;
|
// + View and projection provided by MainWidget static members
|
||||||
std::string mVertexShader, mFragmentShader;
|
void setUniformMVP(
|
||||||
};
|
const char * model = "uModel", const char * view = "uView",
|
||||||
|
const char * projection = "uProjection");
|
||||||
|
|
||||||
#endif // QTK_MESHRENDERER_H
|
// 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);
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
};
|
||||||
|
} // namespace Qtk
|
||||||
|
|
||||||
|
#endif // QTK_MESHRENDERER_H
|
||||||
|
|
199
src/model.cpp
199
src/model.cpp
|
@ -9,28 +9,25 @@
|
||||||
|
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
|
||||||
#include <scene.h>
|
#include <abstractscene.h>
|
||||||
#include <texture.h>
|
|
||||||
#include <resourcemanager.h>
|
|
||||||
|
|
||||||
#include <model.h>
|
#include <model.h>
|
||||||
|
#include <resourcemanager.h>
|
||||||
|
#include <texture.h>
|
||||||
|
|
||||||
|
using namespace Qtk;
|
||||||
|
|
||||||
Model::ModelManager Model::mManager;
|
Model::ModelManager Model::mManager;
|
||||||
|
|
||||||
// Static function to access ModelManager for getting Models by name
|
// 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];
|
return mManager[name];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* ModelMesh Private Member Functions
|
* ModelMesh Private Member Functions
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
void ModelMesh::initMesh(const char * vert, const char * frag)
|
void ModelMesh::initMesh(const char * vert, const char * frag) {
|
||||||
{
|
|
||||||
initializeOpenGLFunctions();
|
initializeOpenGLFunctions();
|
||||||
|
|
||||||
// Create VAO, VBO, EBO
|
// Create VAO, VBO, EBO
|
||||||
|
@ -44,14 +41,12 @@ void ModelMesh::initMesh(const char * vert, const char * frag)
|
||||||
mVBO->setUsagePattern(QOpenGLBuffer::StaticDraw);
|
mVBO->setUsagePattern(QOpenGLBuffer::StaticDraw);
|
||||||
mVBO->bind();
|
mVBO->bind();
|
||||||
|
|
||||||
mVBO->allocate(mVertices.data(),
|
mVBO->allocate(mVertices.data(), mVertices.size() * sizeof(mVertices[0]));
|
||||||
mVertices.size() * sizeof(mVertices[0]));
|
|
||||||
|
|
||||||
// Allocate EBO
|
// Allocate EBO
|
||||||
mEBO->setUsagePattern(QOpenGLBuffer::StaticDraw);
|
mEBO->setUsagePattern(QOpenGLBuffer::StaticDraw);
|
||||||
mEBO->bind();
|
mEBO->bind();
|
||||||
mEBO->allocate(mIndices.data(),
|
mEBO->allocate(mIndices.data(), mIndices.size() * sizeof(mIndices[0]));
|
||||||
mIndices.size() * sizeof(mIndices[0]));
|
|
||||||
mEBO->release();
|
mEBO->release();
|
||||||
|
|
||||||
// Load and link shaders
|
// Load and link shaders
|
||||||
|
@ -62,46 +57,40 @@ void ModelMesh::initMesh(const char * vert, const char * frag)
|
||||||
|
|
||||||
// Positions
|
// Positions
|
||||||
mProgram->enableAttributeArray(0);
|
mProgram->enableAttributeArray(0);
|
||||||
mProgram->setAttributeBuffer(0, GL_FLOAT,
|
mProgram->setAttributeBuffer(
|
||||||
offsetof(ModelVertex, mPosition), 3,
|
0, GL_FLOAT, offsetof(ModelVertex, mPosition), 3, sizeof(ModelVertex));
|
||||||
sizeof(ModelVertex));
|
|
||||||
|
|
||||||
// Normals
|
// Normals
|
||||||
mProgram->enableAttributeArray(1);
|
mProgram->enableAttributeArray(1);
|
||||||
mProgram->setAttributeBuffer(1, GL_FLOAT,
|
mProgram->setAttributeBuffer(
|
||||||
offsetof(ModelVertex, mNormal), 3,
|
1, GL_FLOAT, offsetof(ModelVertex, mNormal), 3, sizeof(ModelVertex));
|
||||||
sizeof(ModelVertex));
|
|
||||||
|
|
||||||
// Texture Coordinates
|
// Texture Coordinates
|
||||||
mProgram->enableAttributeArray(2);
|
mProgram->enableAttributeArray(2);
|
||||||
mProgram->setAttributeBuffer(2, GL_FLOAT,
|
mProgram->setAttributeBuffer(
|
||||||
offsetof(ModelVertex, mTextureCoord), 2,
|
2, GL_FLOAT, offsetof(ModelVertex, mTextureCoord), 2,
|
||||||
sizeof(ModelVertex));
|
sizeof(ModelVertex));
|
||||||
|
|
||||||
// Vertex tangents
|
// Vertex tangents
|
||||||
mProgram->enableAttributeArray(3);
|
mProgram->enableAttributeArray(3);
|
||||||
mProgram->setAttributeBuffer(3, GL_FLOAT,
|
mProgram->setAttributeBuffer(
|
||||||
offsetof(ModelVertex, mTangent), 3,
|
3, GL_FLOAT, offsetof(ModelVertex, mTangent), 3, sizeof(ModelVertex));
|
||||||
sizeof(ModelVertex));
|
|
||||||
|
|
||||||
// Vertex bitangents
|
// Vertex bitangents
|
||||||
mProgram->enableAttributeArray(4);
|
mProgram->enableAttributeArray(4);
|
||||||
mProgram->setAttributeBuffer(4, GL_FLOAT,
|
mProgram->setAttributeBuffer(
|
||||||
offsetof(ModelVertex, mBitangent), 3,
|
4, GL_FLOAT, offsetof(ModelVertex, mBitangent), 3, sizeof(ModelVertex));
|
||||||
sizeof(ModelVertex));
|
|
||||||
|
|
||||||
mProgram->release();
|
mProgram->release();
|
||||||
mVBO->release();
|
mVBO->release();
|
||||||
mVAO->release();
|
mVAO->release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* ModelMesh Public Member Functions
|
* ModelMesh Public Member Functions
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
void ModelMesh::draw(QOpenGLShaderProgram & shader)
|
void ModelMesh::draw(QOpenGLShaderProgram & shader) {
|
||||||
{
|
|
||||||
mVAO->bind();
|
mVAO->bind();
|
||||||
// Bind shader
|
// Bind shader
|
||||||
shader.bind();
|
shader.bind();
|
||||||
|
@ -114,7 +103,7 @@ void ModelMesh::draw(QOpenGLShaderProgram & shader)
|
||||||
GLuint diffuseCount = 1;
|
GLuint diffuseCount = 1;
|
||||||
GLuint specularCount = 1;
|
GLuint specularCount = 1;
|
||||||
GLuint normalCount = 1;
|
GLuint normalCount = 1;
|
||||||
for (GLuint i = 0; i < mTextures.size(); i++) {
|
for(GLuint i = 0; i < mTextures.size(); i++) {
|
||||||
// Activate the current texture index by adding offset to GL_TEXTURE0
|
// Activate the current texture index by adding offset to GL_TEXTURE0
|
||||||
glActiveTexture(GL_TEXTURE0 + i);
|
glActiveTexture(GL_TEXTURE0 + i);
|
||||||
mTextures[i].mTexture->bind();
|
mTextures[i].mTexture->bind();
|
||||||
|
@ -124,20 +113,26 @@ void ModelMesh::draw(QOpenGLShaderProgram & shader)
|
||||||
// Specular: material.texture_specular1, material.texture_specular2, ...
|
// Specular: material.texture_specular1, material.texture_specular2, ...
|
||||||
std::string number;
|
std::string number;
|
||||||
std::string name = mTextures[i].mType;
|
std::string name = mTextures[i].mType;
|
||||||
if (name == "texture_diffuse") number = std::to_string(diffuseCount++);
|
if(name == "texture_diffuse") {
|
||||||
if (name == "texture_specular") number = std::to_string(specularCount++);
|
number = std::to_string(diffuseCount++);
|
||||||
if (name == "texture_normal") number = std::to_string(normalCount++);
|
}
|
||||||
|
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
|
// Set the uniform to track this texture ID using our naming convention
|
||||||
shader.setUniformValue((name + number).c_str(), i);
|
shader.setUniformValue((name + number).c_str(), i);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw the mesh
|
// Draw the mesh
|
||||||
glDrawElements(GL_TRIANGLES, mIndices.size(),
|
glDrawElements(
|
||||||
GL_UNSIGNED_INT, mIndices.data());
|
GL_TRIANGLES, mIndices.size(), GL_UNSIGNED_INT, mIndices.data());
|
||||||
|
|
||||||
// Release shader, textures
|
// Release shader, textures
|
||||||
for (const auto & texture : mTextures) {
|
for(const auto & texture : mTextures) {
|
||||||
texture.mTexture->release();
|
texture.mTexture->release();
|
||||||
}
|
}
|
||||||
shader.release();
|
shader.release();
|
||||||
|
@ -145,33 +140,29 @@ void ModelMesh::draw(QOpenGLShaderProgram & shader)
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Model Public Member Functions
|
* Model Public Member Functions
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
void Model::draw()
|
void Model::draw() {
|
||||||
{
|
for(auto & mMeshe : mMeshes) {
|
||||||
for (GLuint i = 0; i < mMeshes.size(); i++) {
|
mMeshe.mTransform = mTransform;
|
||||||
mMeshes[i].mTransform = mTransform;
|
mMeshe.draw();
|
||||||
mMeshes[i].draw();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::draw(QOpenGLShaderProgram & shader)
|
void Model::draw(QOpenGLShaderProgram & shader) {
|
||||||
{
|
for(auto & mMeshe : mMeshes) {
|
||||||
for (GLuint i = 0; i < mMeshes.size(); i++) {
|
mMeshe.mTransform = mTransform;
|
||||||
mMeshes[i].mTransform = mTransform;
|
mMeshe.draw(shader);
|
||||||
mMeshes[i].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;
|
bool modified = false;
|
||||||
std::string fullPath = mDirectory + '/' + fileName;
|
std::string fullPath = mDirectory + '/' + fileName;
|
||||||
for (auto & texture : mTexturesLoaded) {
|
for(auto & texture : mTexturesLoaded) {
|
||||||
if (texture.mPath == fileName) {
|
if(texture.mPath == fileName) {
|
||||||
texture.mTexture->destroy();
|
texture.mTexture->destroy();
|
||||||
texture.mTexture->create();
|
texture.mTexture->create();
|
||||||
texture.mTexture->setData(
|
texture.mTexture->setData(
|
||||||
|
@ -179,14 +170,12 @@ void Model::flipTexture(const std::string & fileName, bool flipX, bool flipY)
|
||||||
modified = true;
|
modified = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!modified) {
|
if(!modified) {
|
||||||
qDebug() << "Attempt to flip texture that doesn't exist: "
|
qDebug() << "Attempt to flip texture that doesn't exist: "
|
||||||
<< fullPath.c_str() << "\n";
|
<< fullPath.c_str() << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Model Private Member Functions
|
* Model Private Member Functions
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
@ -206,31 +195,25 @@ 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
|
* @param path Absolute path to a model .obj or other format accepted by assimp
|
||||||
*/
|
*/
|
||||||
void Model::loadModel(const std::string & path)
|
void Model::loadModel(const std::string & path) {
|
||||||
{
|
|
||||||
Assimp::Importer import;
|
Assimp::Importer import;
|
||||||
|
|
||||||
// JIC a relative path was used, get the absolute file path
|
// JIC a relative path was used, get the absolute file path
|
||||||
QFileInfo info(path.c_str());
|
QFileInfo info(path.c_str());
|
||||||
info.makeAbsolute();
|
info.makeAbsolute();
|
||||||
mDirectory = path[0] == ':' ? RM::getPath(path)
|
mDirectory = path[0] == ':' ? RM::getPath(path)
|
||||||
: info.absoluteFilePath().toStdString();
|
: info.absoluteFilePath().toStdString();
|
||||||
|
|
||||||
// Import the model, converting non-triangular geometry to triangles
|
// Import the model, converting non-triangular geometry to triangles
|
||||||
// + And flipping texture UVs, etc..
|
// + And flipping texture UVs, etc..
|
||||||
// Assimp options: http://assimp.sourceforge.net/lib_html/postprocess_8h.html
|
// Assimp options: http://assimp.sourceforge.net/lib_html/postprocess_8h.html
|
||||||
const aiScene * scene =
|
const aiScene * scene = import.ReadFile(
|
||||||
import.ReadFile(mDirectory, aiProcess_Triangulate
|
mDirectory, aiProcess_Triangulate | aiProcess_FlipUVs
|
||||||
| aiProcess_FlipUVs
|
| aiProcess_GenSmoothNormals | aiProcess_CalcTangentSpace
|
||||||
| aiProcess_GenSmoothNormals
|
| aiProcess_OptimizeMeshes | aiProcess_SplitLargeMeshes);
|
||||||
| aiProcess_CalcTangentSpace
|
|
||||||
| aiProcess_OptimizeMeshes
|
|
||||||
| aiProcess_SplitLargeMeshes
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
// If there were errors, print and return
|
// If there were errors, print and return
|
||||||
if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) {
|
if(!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) {
|
||||||
qDebug() << "Error::ASSIMP::" << import.GetErrorString() << "\n";
|
qDebug() << "Error::ASSIMP::" << import.GetErrorString() << "\n";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -250,28 +233,26 @@ void Model::loadModel(const std::string & path)
|
||||||
mManager.insert(mName, this);
|
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
|
// Process each mesh that is available for this node
|
||||||
for (GLuint i = 0; i < node->mNumMeshes; i++) {
|
for(GLuint i = 0; i < node->mNumMeshes; i++) {
|
||||||
aiMesh * mesh = scene->mMeshes[node->mMeshes[i]];
|
aiMesh * mesh = scene->mMeshes[node->mMeshes[i]];
|
||||||
mMeshes.push_back(processMesh(mesh, scene));
|
mMeshes.push_back(processMesh(mesh, scene));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process each child node for this mesh using recursion
|
// Process each child node for this mesh using recursion
|
||||||
for (GLuint i = 0; i < node->mNumChildren; i++) {
|
for(GLuint i = 0; i < node->mNumChildren; i++) {
|
||||||
processNode(node->mChildren[i], scene);
|
processNode(node->mChildren[i], scene);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ModelMesh Model::processMesh(aiMesh * mesh, const aiScene * scene)
|
ModelMesh Model::processMesh(aiMesh * mesh, const aiScene * scene) {
|
||||||
{
|
|
||||||
ModelMesh::Vertices vertices;
|
ModelMesh::Vertices vertices;
|
||||||
ModelMesh::Indices indices;
|
ModelMesh::Indices indices;
|
||||||
ModelMesh::Textures textures;
|
ModelMesh::Textures textures;
|
||||||
|
|
||||||
// For each vertex in the aiMesh
|
// For each vertex in the aiMesh
|
||||||
for (GLuint i = 0; i < mesh->mNumVertices; i++) {
|
for(GLuint i = 0; i < mesh->mNumVertices; i++) {
|
||||||
// Create a local vertex object for positions, normals, and texture coords
|
// Create a local vertex object for positions, normals, and texture coords
|
||||||
ModelVertex vertex;
|
ModelVertex vertex;
|
||||||
|
|
||||||
|
@ -285,7 +266,7 @@ ModelMesh Model::processMesh(aiMesh * mesh, const aiScene * scene)
|
||||||
// Set the position of our local vertex to the local vector object
|
// Set the position of our local vertex to the local vector object
|
||||||
vertex.mPosition = vector3D;
|
vertex.mPosition = vector3D;
|
||||||
|
|
||||||
if (mesh->HasNormals()) {
|
if(mesh->HasNormals()) {
|
||||||
// Initialize vertex normal
|
// Initialize vertex normal
|
||||||
vector3D.setX(mesh->mNormals[i].x);
|
vector3D.setX(mesh->mNormals[i].x);
|
||||||
vector3D.setY(mesh->mNormals[i].y);
|
vector3D.setY(mesh->mNormals[i].y);
|
||||||
|
@ -295,7 +276,7 @@ ModelMesh Model::processMesh(aiMesh * mesh, const aiScene * scene)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize texture coordinates, if any are available
|
// Initialize texture coordinates, if any are available
|
||||||
if (mesh->mTextureCoords[0]) {
|
if(mesh->mTextureCoords[0]) {
|
||||||
QVector2D vector2D;
|
QVector2D vector2D;
|
||||||
// Texture coordinates
|
// Texture coordinates
|
||||||
vector2D.setX(mesh->mTextureCoords[0][i].x);
|
vector2D.setX(mesh->mTextureCoords[0][i].x);
|
||||||
|
@ -313,8 +294,7 @@ ModelMesh Model::processMesh(aiMesh * mesh, const aiScene * scene)
|
||||||
vector3D.setY(mesh->mBitangents[i].y);
|
vector3D.setY(mesh->mBitangents[i].y);
|
||||||
vector3D.setZ(mesh->mBitangents[i].z);
|
vector3D.setZ(mesh->mBitangents[i].z);
|
||||||
vertex.mBitangent = vector3D;
|
vertex.mBitangent = vector3D;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
vertex.mTextureCoord = {0.0f, 0.0f};
|
vertex.mTextureCoord = {0.0f, 0.0f};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,62 +303,56 @@ ModelMesh Model::processMesh(aiMesh * mesh, const aiScene * scene)
|
||||||
}
|
}
|
||||||
|
|
||||||
// For each face on the mesh, process its indices
|
// For each face on the mesh, process its indices
|
||||||
for (GLuint i = 0; i < mesh->mNumFaces; i++) {
|
for(GLuint i = 0; i < mesh->mNumFaces; i++) {
|
||||||
aiFace face = mesh->mFaces[i];
|
aiFace face = mesh->mFaces[i];
|
||||||
for (GLuint j = 0; j < face.mNumIndices; j++) {
|
for(GLuint j = 0; j < face.mNumIndices; j++) {
|
||||||
// Add the index to out container of indices
|
// Add the index to out container of indices
|
||||||
indices.push_back(face.mIndices[j]);
|
indices.push_back(face.mIndices[j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process material
|
// Process material
|
||||||
if (mesh->mMaterialIndex >= 0) {
|
if(mesh->mMaterialIndex >= 0) {
|
||||||
// Get the material attached to the model using Assimp
|
// Get the material attached to the model using Assimp
|
||||||
aiMaterial * material = scene->mMaterials[mesh->mMaterialIndex];
|
aiMaterial * material = scene->mMaterials[mesh->mMaterialIndex];
|
||||||
|
|
||||||
// Get all diffuse textures from the material
|
// Get all diffuse textures from the material
|
||||||
ModelMesh::Textures diffuseMaps =
|
ModelMesh::Textures diffuseMaps = loadMaterialTextures(
|
||||||
loadMaterialTextures(material, aiTextureType_DIFFUSE,
|
material, aiTextureType_DIFFUSE, "texture_diffuse");
|
||||||
"texture_diffuse");
|
|
||||||
// Insert all diffuse textures found into our textures container
|
// Insert all diffuse textures found into our textures container
|
||||||
textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());
|
textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());
|
||||||
|
|
||||||
// Get all specular textures from the material
|
// Get all specular textures from the material
|
||||||
ModelMesh::Textures specularMaps =
|
ModelMesh::Textures specularMaps = loadMaterialTextures(
|
||||||
loadMaterialTextures(material, aiTextureType_SPECULAR,
|
material, aiTextureType_SPECULAR, "texture_specular");
|
||||||
"texture_specular");
|
|
||||||
// Insert all specular textures found into our textures container
|
// Insert all specular textures found into our textures container
|
||||||
textures.insert(textures.end(), specularMaps.begin(), specularMaps.end());
|
textures.insert(textures.end(), specularMaps.begin(), specularMaps.end());
|
||||||
|
|
||||||
// Get all normal textures from the material
|
// Get all normal textures from the material
|
||||||
ModelMesh::Textures normalMaps =
|
ModelMesh::Textures normalMaps =
|
||||||
loadMaterialTextures(material, aiTextureType_HEIGHT,
|
loadMaterialTextures(material, aiTextureType_HEIGHT, "texture_normal");
|
||||||
"texture_normal");
|
|
||||||
// Insert all normal maps found into our textures container
|
// Insert all normal maps found into our textures container
|
||||||
textures.insert(textures.end(), normalMaps.begin(), normalMaps.end());
|
textures.insert(textures.end(), normalMaps.begin(), normalMaps.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
return ModelMesh(vertices, indices, textures,
|
return {vertices, indices, textures, mVertexShader, mFragmentShader};
|
||||||
mVertexShader, mFragmentShader);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ModelMesh::Textures Model::loadMaterialTextures(
|
ModelMesh::Textures Model::loadMaterialTextures(
|
||||||
aiMaterial * mat, aiTextureType type, const std::string & typeName)
|
aiMaterial * mat, aiTextureType type, const std::string & typeName) {
|
||||||
{
|
|
||||||
ModelMesh::Textures textures;
|
ModelMesh::Textures textures;
|
||||||
|
|
||||||
for (GLuint i = 0; i < mat->GetTextureCount(type); i++) {
|
for(GLuint i = 0; i < mat->GetTextureCount(type); i++) {
|
||||||
|
|
||||||
// Call GetTexture to get the name of the texture file to load
|
// Call GetTexture to get the name of the texture file to load
|
||||||
aiString fileName;
|
aiString fileName;
|
||||||
mat->GetTexture(type, i, &fileName);
|
mat->GetTexture(type, i, &fileName);
|
||||||
|
|
||||||
// Check if we have already loaded this texture
|
// Check if we have already loaded this texture
|
||||||
bool skip = false;
|
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 the path to the texture already exists in m_texturesLoaded, skip it
|
||||||
if (std::strcmp(mTexturesLoaded[j].mPath.data(), fileName.C_Str()) == 0) {
|
if(std::strcmp(j.mPath.data(), fileName.C_Str()) == 0) {
|
||||||
textures.push_back(mTexturesLoaded[j]);
|
textures.push_back(j);
|
||||||
// If we have loaded the texture, do not load it again
|
// If we have loaded the texture, do not load it again
|
||||||
skip = true;
|
skip = true;
|
||||||
break;
|
break;
|
||||||
|
@ -386,11 +360,11 @@ ModelMesh::Textures Model::loadMaterialTextures(
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the texture has not yet been loaded
|
// If the texture has not yet been loaded
|
||||||
if (!skip) {
|
if(!skip) {
|
||||||
ModelTexture texture;
|
ModelTexture texture;
|
||||||
texture.mTexture = OpenGLTextureFactory::initTexture2D(
|
texture.mTexture = OpenGLTextureFactory::initTexture2D(
|
||||||
std::string(mDirectory + '/' + fileName.C_Str()).c_str(),
|
std::string(mDirectory + '/' + fileName.C_Str()).c_str(), false,
|
||||||
false, false);
|
false);
|
||||||
texture.mID = texture.mTexture->textureId();
|
texture.mID = texture.mTexture->textureId();
|
||||||
texture.mType = typeName;
|
texture.mType = typeName;
|
||||||
texture.mPath = fileName.C_Str();
|
texture.mPath = fileName.C_Str();
|
||||||
|
@ -399,23 +373,20 @@ ModelMesh::Textures Model::loadMaterialTextures(
|
||||||
// Add the texture to the loaded textures to avoid loading it twice
|
// Add the texture to the loaded textures to avoid loading it twice
|
||||||
mTexturesLoaded.push_back(texture);
|
mTexturesLoaded.push_back(texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the resulting textures
|
// Return the resulting textures
|
||||||
return textures;
|
return textures;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::sortModels()
|
void Model::sortModels() {
|
||||||
{
|
|
||||||
auto cameraPos = Scene::Camera().transform();
|
auto cameraPos = Scene::Camera().transform();
|
||||||
auto cameraDistance =
|
auto cameraDistance = [&cameraPos](const ModelMesh & a, const ModelMesh & b) {
|
||||||
[&cameraPos](const ModelMesh &a, const ModelMesh &b)
|
// Sort by the first vertex position in the model
|
||||||
{
|
return (cameraPos.getTranslation().distanceToPoint(
|
||||||
// Sort by the first vertex position in the model
|
a.mVertices[0].mPosition))
|
||||||
return (cameraPos.getTranslation().distanceToPoint(a.mVertices[0].mPosition))
|
< (cameraPos.getTranslation().distanceToPoint(
|
||||||
< (cameraPos.getTranslation().distanceToPoint(b.mVertices[0].mPosition));
|
b.mVertices[0].mPosition));
|
||||||
};
|
};
|
||||||
std::sort(mMeshes.begin(), mMeshes.end(), cameraDistance);
|
std::sort(mMeshes.begin(), mMeshes.end(), cameraDistance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
189
src/model.h
189
src/model.h
|
@ -16,126 +16,131 @@
|
||||||
#include <QOpenGLShaderProgram>
|
#include <QOpenGLShaderProgram>
|
||||||
#include <QOpenGLTexture>
|
#include <QOpenGLTexture>
|
||||||
#include <QOpenGLVertexArrayObject>
|
#include <QOpenGLVertexArrayObject>
|
||||||
#include <QOpenGLFunctions>
|
|
||||||
|
|
||||||
// Assimp
|
// Assimp
|
||||||
#include <assimp/Importer.hpp>
|
|
||||||
#include <assimp/postprocess.h>
|
#include <assimp/postprocess.h>
|
||||||
#include <assimp/scene.h>
|
#include <assimp/scene.h>
|
||||||
|
#include <assimp/Importer.hpp>
|
||||||
|
|
||||||
// QTK
|
// QTK
|
||||||
#include <transform3D.h>
|
|
||||||
#include <object.h>
|
#include <object.h>
|
||||||
|
#include <qtkapi.h>
|
||||||
|
#include <transform3D.h>
|
||||||
|
|
||||||
|
namespace Qtk {
|
||||||
|
struct QTKAPI ModelVertex {
|
||||||
|
QVector3D mPosition;
|
||||||
|
QVector3D mNormal;
|
||||||
|
QVector3D mTangent;
|
||||||
|
QVector3D mBitangent;
|
||||||
|
QVector2D mTextureCoord;
|
||||||
|
};
|
||||||
|
|
||||||
struct ModelVertex {
|
struct QTKAPI ModelTexture {
|
||||||
QVector3D mPosition;
|
GLuint mID;
|
||||||
QVector3D mNormal;
|
QOpenGLTexture * mTexture;
|
||||||
QVector3D mTangent;
|
std::string mType;
|
||||||
QVector3D mBitangent;
|
std::string mPath;
|
||||||
QVector2D mTextureCoord;
|
};
|
||||||
};
|
|
||||||
|
|
||||||
struct ModelTexture {
|
class Model;
|
||||||
GLuint mID;
|
|
||||||
QOpenGLTexture * mTexture;
|
|
||||||
std::string mType;
|
|
||||||
std::string mPath;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Model;
|
class QTKAPI ModelMesh : protected QOpenGLFunctions {
|
||||||
|
public:
|
||||||
|
friend Model;
|
||||||
|
typedef std::vector<ModelVertex> Vertices;
|
||||||
|
typedef std::vector<GLuint> Indices;
|
||||||
|
typedef std::vector<ModelTexture> Textures;
|
||||||
|
|
||||||
class ModelMesh : protected QOpenGLFunctions {
|
// Constructors, Destructors
|
||||||
public:
|
ModelMesh(
|
||||||
friend Model;
|
Vertices vertices, Indices indices, Textures textures,
|
||||||
typedef std::vector<ModelVertex> Vertices;
|
const char * vertexShader = ":/model-basic.vert",
|
||||||
typedef std::vector<GLuint> Indices;
|
const char * fragmentShader = ":/model-basic.frag") :
|
||||||
typedef std::vector<ModelTexture> Textures;
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
// Constructors, Destructors
|
~ModelMesh() = default;
|
||||||
ModelMesh(Vertices vertices, Indices indices, Textures textures,
|
|
||||||
const char * vertexShader=":/model-basic.vert",
|
|
||||||
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() {}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void initMesh(const char * vert, const char * frag);
|
void initMesh(const char * vert, const char * frag);
|
||||||
|
|
||||||
// ModelMesh Private Members
|
// ModelMesh Private Members
|
||||||
QOpenGLBuffer * mVBO, * mEBO;
|
QOpenGLBuffer *mVBO, *mEBO;
|
||||||
QOpenGLVertexArrayObject * mVAO;
|
QOpenGLVertexArrayObject * mVAO;
|
||||||
QOpenGLShaderProgram * mProgram;
|
QOpenGLShaderProgram * mProgram;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
inline void draw() { draw(*mProgram);}
|
inline void draw() { draw(*mProgram); }
|
||||||
void draw(QOpenGLShaderProgram & shader);
|
|
||||||
|
|
||||||
// ModelMesh Public Members
|
void draw(QOpenGLShaderProgram & shader);
|
||||||
Vertices mVertices;
|
|
||||||
Indices mIndices;
|
|
||||||
Textures mTextures;
|
|
||||||
Transform3D mTransform;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
// ModelMesh Public Members
|
||||||
|
Vertices mVertices;
|
||||||
|
Indices mIndices;
|
||||||
|
Textures mTextures;
|
||||||
|
Transform3D mTransform;
|
||||||
|
};
|
||||||
|
|
||||||
class Model : public QObject {
|
class QTKAPI Model : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
inline Model(const char * name, const char * path,
|
inline Model(
|
||||||
const char * vertexShader=":/model-basic.vert",
|
const char * name, const char * path,
|
||||||
const char * fragmentShader=":/model-basic.frag")
|
const char * vertexShader = ":/model-basic.vert",
|
||||||
: mName(name), mVertexShader(vertexShader),
|
const char * fragmentShader = ":/model-basic.frag") :
|
||||||
mFragmentShader(fragmentShader)
|
mName(name),
|
||||||
{ loadModel(path);}
|
mVertexShader(vertexShader), mFragmentShader(fragmentShader) {
|
||||||
inline ~Model() { mManager.remove(mName);}
|
loadModel(path);
|
||||||
|
}
|
||||||
|
|
||||||
void draw();
|
inline ~Model() override { mManager.remove(mName); }
|
||||||
void draw(QOpenGLShaderProgram & shader);
|
|
||||||
|
|
||||||
void flipTexture(const std::string & fileName,
|
void draw();
|
||||||
bool flipX=false, bool flipY=true);
|
void draw(QOpenGLShaderProgram & shader);
|
||||||
|
|
||||||
template <typename T>
|
void flipTexture(
|
||||||
void setUniform(const char * location, T value)
|
const std::string & fileName, bool flipX = false, bool flipY = true);
|
||||||
{
|
|
||||||
for (auto & mesh : mMeshes) {
|
|
||||||
mesh.mProgram->bind();
|
|
||||||
|
|
||||||
mesh.mProgram->setUniformValue(location, value);
|
template <typename T> void setUniform(const char * location, T value) {
|
||||||
|
for(auto & mesh : mMeshes) {
|
||||||
|
mesh.mProgram->bind();
|
||||||
|
|
||||||
mesh.mProgram->release();
|
mesh.mProgram->setUniformValue(location, value);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Transform3D mTransform;
|
mesh.mProgram->release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static Model * getInstance(const char * name);
|
Transform3D mTransform;
|
||||||
|
|
||||||
typedef QHash<QString, Model *> ModelManager;
|
static Model * getInstance(const char * name);
|
||||||
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);
|
|
||||||
void sortModels();
|
|
||||||
|
|
||||||
// Model Private Members
|
typedef QHash<QString, Model *> ModelManager;
|
||||||
|
|
||||||
ModelMesh::Textures mTexturesLoaded;
|
private:
|
||||||
std::vector<ModelMesh> mMeshes;
|
static ModelManager mManager;
|
||||||
std::string mDirectory;
|
void loadModel(const std::string & path);
|
||||||
const char * mVertexShader, * mFragmentShader, * mName;
|
void processNode(aiNode * node, const aiScene * scene);
|
||||||
};
|
ModelMesh processMesh(aiMesh * mesh, const aiScene * scene);
|
||||||
|
ModelMesh::Textures loadMaterialTextures(
|
||||||
|
aiMaterial * mat, aiTextureType type, const std::string & typeName);
|
||||||
|
void sortModels();
|
||||||
|
|
||||||
#endif // QTK_MODEL_H
|
// Model Private Members
|
||||||
|
|
||||||
|
ModelMesh::Textures mTexturesLoaded;
|
||||||
|
std::vector<ModelMesh> mMeshes;
|
||||||
|
std::string mDirectory;
|
||||||
|
const char *mVertexShader, *mFragmentShader, *mName;
|
||||||
|
};
|
||||||
|
} // namespace Qtk
|
||||||
|
|
||||||
|
#endif // QTK_MODEL_H
|
||||||
|
|
|
@ -7,3 +7,5 @@
|
||||||
##############################################################################*/
|
##############################################################################*/
|
||||||
|
|
||||||
#include <object.h>
|
#include <object.h>
|
||||||
|
|
||||||
|
using namespace Qtk;
|
||||||
|
|
106
src/object.h
106
src/object.h
|
@ -14,52 +14,82 @@
|
||||||
#include <QOpenGLVertexArrayObject>
|
#include <QOpenGLVertexArrayObject>
|
||||||
|
|
||||||
#include <mesh.h>
|
#include <mesh.h>
|
||||||
|
#include <qtkapi.h>
|
||||||
#include <texture.h>
|
#include <texture.h>
|
||||||
|
|
||||||
|
namespace Qtk {
|
||||||
|
class QTKAPI Object : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
class Object : public QObject {
|
public:
|
||||||
Q_OBJECT
|
friend MeshRenderer;
|
||||||
|
|
||||||
public:
|
// Initialize an object with no shape data assigned
|
||||||
friend MeshRenderer;
|
explicit Object(const char * name) :
|
||||||
// Initialize an object with no shape data assigned
|
mName(name), mVBO(QOpenGLBuffer::VertexBuffer) {}
|
||||||
Object(const char * name)
|
|
||||||
: mName(name), mVBO(QOpenGLBuffer::VertexBuffer)
|
|
||||||
{ }
|
|
||||||
// Initialize an object with shape data assigned
|
|
||||||
Object(const char * name, const ShapeBase & shape)
|
|
||||||
: mName(name), mVBO(QOpenGLBuffer::VertexBuffer), mShape(shape)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
~Object() {}
|
// Initialize an object with shape data assigned
|
||||||
|
Object(const char * name, const ShapeBase & shape) :
|
||||||
|
mName(name), mVBO(QOpenGLBuffer::VertexBuffer), mShape(shape) {}
|
||||||
|
|
||||||
inline const Colors & getColors() { return mShape.mColors;}
|
~Object() override = default;
|
||||||
inline const Indices & getIndexData() { return mShape.mIndices;}
|
|
||||||
inline const Normals & getNormals() { return mShape.mNormals;}
|
|
||||||
inline const Shape & getShape() { 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;}
|
inline const Colors & getColors() { return mShape.mColors; }
|
||||||
virtual inline void setIndices(const Indices & value) { mShape.mIndices = value;}
|
|
||||||
virtual inline void setNormals(const Normals & value) { mShape.mNormals = value;}
|
|
||||||
virtual inline void setShape(const Shape & value) { mShape = value;}
|
|
||||||
virtual inline void setTexCoords(const TexCoords & value) { mShape.mTexCoords = value;}
|
|
||||||
virtual inline void setTexture(const char * path, bool flipX=false, bool flipY=false)
|
|
||||||
{ mTexture.setTexture(OpenGLTextureFactory::initTexture2D(path, flipX, flipY));}
|
|
||||||
virtual inline void setTexture(QOpenGLTexture * value) { mTexture.setTexture(value);}
|
|
||||||
virtual inline void setVertices(const Vertices & value) { mShape.mVertices = value;}
|
|
||||||
|
|
||||||
QOpenGLBuffer mVBO, mNBO;
|
inline const Indices & getIndexData() { return mShape.mIndices; }
|
||||||
QOpenGLVertexArrayObject mVAO;
|
|
||||||
QOpenGLShaderProgram mProgram;
|
|
||||||
|
|
||||||
Transform3D mTransform;
|
inline const Normals & getNormals() { return mShape.mNormals; }
|
||||||
Shape mShape;
|
|
||||||
Texture mTexture;
|
|
||||||
|
|
||||||
const char * mName;
|
[[nodiscard]] inline const Shape & getShape() const { return mShape; }
|
||||||
};
|
|
||||||
|
|
||||||
#endif // QTK_OBJECT_H
|
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 setShape(const Shape & value) { mShape = value; }
|
||||||
|
|
||||||
|
virtual inline void setTexCoords(const TexCoords & value) {
|
||||||
|
mShape.mTexCoords = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual inline void setTexture(
|
||||||
|
const char * path, bool flipX = false, bool flipY = false) {
|
||||||
|
mTexture.setTexture(
|
||||||
|
OpenGLTextureFactory::initTexture2D(path, flipX, flipY));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual inline void setTexture(QOpenGLTexture * value) {
|
||||||
|
mTexture.setTexture(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual inline void setVertices(const Vertices & value) {
|
||||||
|
mShape.mVertices = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
QOpenGLBuffer mVBO, mNBO;
|
||||||
|
QOpenGLVertexArrayObject mVAO;
|
||||||
|
QOpenGLShaderProgram mProgram;
|
||||||
|
|
||||||
|
Transform3D mTransform;
|
||||||
|
Shape mShape;
|
||||||
|
Texture mTexture;
|
||||||
|
|
||||||
|
const char * mName;
|
||||||
|
};
|
||||||
|
} // namespace Qtk
|
||||||
|
|
||||||
|
#endif // QTK_OBJECT_H
|
||||||
|
|
|
@ -1,24 +1,23 @@
|
||||||
/*##############################################################################
|
/*##############################################################################
|
||||||
## Author: Shaun Reed ##
|
## Author: Shaun Reed ##
|
||||||
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
|
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
|
||||||
## About: Manage files and resources used by qtk ##
|
## About: Main window for Qt6 OpenGL widget application ##
|
||||||
## ##
|
## ##
|
||||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||||
##############################################################################*/
|
##############################################################################*/
|
||||||
|
#ifndef QTK_QTKAPI_H
|
||||||
|
#define QTK_QTKAPI_H
|
||||||
|
|
||||||
#include "resourcemanager.h"
|
#include <QtCore/QtGlobal>
|
||||||
#include <algorithm>
|
|
||||||
#include <string>
|
|
||||||
#include <QtGlobal>
|
|
||||||
|
|
||||||
static std::string nixPath(std::string path)
|
#ifdef QTK_SHARED
|
||||||
{
|
# if defined(QTK_EXPORT)
|
||||||
#ifdef Q_OS_WINDOWS
|
# define QTKAPI Q_DECL_EXPORT
|
||||||
std::replace(path.begin(), path.end(), '\\', '/');
|
# else
|
||||||
|
# define QTKAPI Q_DECL_IMPORT
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define QTKAPI
|
||||||
#endif
|
#endif
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string RM::resourcesDir =
|
#endif // QTK_QTKAPI_H
|
||||||
std::string(__FILE__).substr(0, nixPath(__FILE__).find("src/"))
|
|
||||||
+ "resources/";
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
|
||||||
|
#define QTK_RESOURCES "@QTK_RESOURCES@"
|
|
@ -8,124 +8,61 @@
|
||||||
|
|
||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
|
|
||||||
|
#include <abstractscene.h>
|
||||||
#include <input.h>
|
#include <input.h>
|
||||||
#include <mesh.h>
|
#include <mesh.h>
|
||||||
#include <object.h>
|
#include <qtkwidget.h>
|
||||||
#include <scene.h>
|
|
||||||
|
|
||||||
#include <mainwidget.h>
|
|
||||||
|
|
||||||
|
using namespace Qtk;
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Constructors, Destructors
|
* Constructors, Destructors
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
MainWidget::MainWidget() : mDebugLogger(Q_NULLPTR)
|
QtkWidget::QtkWidget() : mScene(Q_NULLPTR), mDebugLogger(Q_NULLPTR) {
|
||||||
{
|
|
||||||
initializeWidget();
|
initializeWidget();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Constructor for using this widget in QtDesigner
|
// Constructor for using this widget in QtDesigner
|
||||||
MainWidget::MainWidget(QWidget *parent) : QOpenGLWidget(parent), mDebugLogger(Q_NULLPTR)
|
QtkWidget::QtkWidget(QWidget * parent) :
|
||||||
{
|
QOpenGLWidget(parent), mScene(Q_NULLPTR), mDebugLogger(Q_NULLPTR) {
|
||||||
initializeWidget();
|
initializeWidget();
|
||||||
}
|
}
|
||||||
|
|
||||||
MainWidget::MainWidget(const QSurfaceFormat &format)
|
QtkWidget::QtkWidget(const QSurfaceFormat & format) :
|
||||||
: mDebugLogger(Q_NULLPTR)
|
mScene(Q_NULLPTR), mDebugLogger(Q_NULLPTR) {
|
||||||
{
|
|
||||||
setFormat(format);
|
setFormat(format);
|
||||||
setFocusPolicy(Qt::ClickFocus);
|
setFocusPolicy(Qt::ClickFocus);
|
||||||
}
|
}
|
||||||
|
|
||||||
MainWidget::~MainWidget()
|
QtkWidget::~QtkWidget() {
|
||||||
{
|
|
||||||
makeCurrent();
|
makeCurrent();
|
||||||
teardownGL();
|
teardownGL();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Private Member Functions
|
* Private Member Functions
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
void MainWidget::teardownGL()
|
void QtkWidget::teardownGL() {
|
||||||
{
|
|
||||||
// Nothing to teardown yet...
|
// Nothing to teardown yet...
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::initObjects()
|
|
||||||
{
|
|
||||||
mScene = new Scene;
|
|
||||||
|
|
||||||
// Drawing a primitive object using Qt and OpenGL
|
|
||||||
// The Object class only stores basic QOpenGL* members and shape data
|
|
||||||
// + Within mainwidget, mObject serves as a basic QOpenGL example
|
|
||||||
mObject = new Object("testObject");
|
|
||||||
mObject->setVertices(Cube(QTK_DRAW_ELEMENTS).getVertices());
|
|
||||||
mObject->setIndices(Cube(QTK_DRAW_ELEMENTS).getIndexData());
|
|
||||||
mObject->mProgram.create();
|
|
||||||
mObject->mProgram.addShaderFromSourceFile(QOpenGLShader::Vertex,
|
|
||||||
":/solid-ambient.vert");
|
|
||||||
mObject->mProgram.addShaderFromSourceFile(QOpenGLShader::Fragment,
|
|
||||||
":/solid-ambient.frag");
|
|
||||||
mObject->mProgram.link();
|
|
||||||
mObject->mProgram.bind();
|
|
||||||
|
|
||||||
mObject->mVAO.create();
|
|
||||||
mObject->mVAO.bind();
|
|
||||||
|
|
||||||
mObject->mVBO.create();
|
|
||||||
mObject->mVBO.setUsagePattern(QOpenGLBuffer::StaticDraw);
|
|
||||||
mObject->mVBO.bind();
|
|
||||||
|
|
||||||
mObject->mVBO.allocate(
|
|
||||||
mObject->getVertices().data(),
|
|
||||||
mObject->getVertices().size() * sizeof(mObject->getVertices()[0])
|
|
||||||
);
|
|
||||||
|
|
||||||
mObject->mProgram.enableAttributeArray(0);
|
|
||||||
mObject->mProgram.setAttributeBuffer(
|
|
||||||
0, GL_FLOAT, 0, 3, sizeof(mObject->getVertices()[0])
|
|
||||||
);
|
|
||||||
mObject->mProgram.setUniformValue("uColor", QVector3D(1.0f, 0.0f, 0.0f));
|
|
||||||
mObject->mProgram.setUniformValue("uLightColor", WHITE);
|
|
||||||
mObject->mProgram.setUniformValue("uAmbientStrength", 0.75f);
|
|
||||||
|
|
||||||
mObject->mVBO.release();
|
|
||||||
mObject->mVAO.release();
|
|
||||||
mObject->mProgram.release();
|
|
||||||
|
|
||||||
mObject->mTransform.setTranslation(13.0f, 0.0f, -2.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Inherited Virtual Member Functions
|
* Inherited Virtual Member Functions
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
void MainWidget::paintGL()
|
void QtkWidget::paintGL() {
|
||||||
{
|
|
||||||
// Clear buffers
|
// Clear buffers
|
||||||
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
|
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
// Draw the scene first, since it handles drawing our skybox
|
// Draw the scene first, since it handles drawing our skybox
|
||||||
mScene->draw();
|
if(mScene != Q_NULLPTR) {
|
||||||
|
mScene->draw();
|
||||||
// Draw any additional objects within mainwidget manually
|
}
|
||||||
mObject->mProgram.bind();
|
|
||||||
mObject->mVAO.bind();
|
|
||||||
mObject->mProgram.setUniformValue("uModel", mObject->mTransform.toMatrix());
|
|
||||||
mObject->mProgram.setUniformValue("uView", Scene::Camera().toMatrix());
|
|
||||||
mObject->mProgram.setUniformValue("uProjection", Scene::Projection());
|
|
||||||
glDrawElements(GL_TRIANGLES, mObject->getIndexData().size(),
|
|
||||||
GL_UNSIGNED_INT, mObject->getIndexData().data());
|
|
||||||
mObject->mVAO.release();
|
|
||||||
mObject->mProgram.release();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::initializeGL()
|
void QtkWidget::initializeGL() {
|
||||||
{
|
|
||||||
initializeOpenGLFunctions();
|
initializeOpenGLFunctions();
|
||||||
// Connect the frameSwapped signal to call the update() function
|
// Connect the frameSwapped signal to call the update() function
|
||||||
connect(this, SIGNAL(frameSwapped()), this, SLOT(update()));
|
connect(this, SIGNAL(frameSwapped()), this, SLOT(update()));
|
||||||
|
@ -133,17 +70,18 @@ void MainWidget::initializeGL()
|
||||||
// Initialize OpenGL debug context
|
// Initialize OpenGL debug context
|
||||||
#ifdef QTK_DEBUG
|
#ifdef QTK_DEBUG
|
||||||
mDebugLogger = new QOpenGLDebugLogger(this);
|
mDebugLogger = new QOpenGLDebugLogger(this);
|
||||||
if (mDebugLogger->initialize()) {
|
if(mDebugLogger->initialize()) {
|
||||||
qDebug() << "GL_DEBUG Debug Logger" << mDebugLogger << "\n";
|
qDebug() << "GL_DEBUG Debug Logger" << mDebugLogger << "\n";
|
||||||
connect(mDebugLogger, SIGNAL(messageLogged(QOpenGLDebugMessage)),
|
connect(
|
||||||
this, SLOT(messageLogged(QOpenGLDebugMessage)));
|
mDebugLogger, SIGNAL(messageLogged(QOpenGLDebugMessage)), this,
|
||||||
|
SLOT(messageLogged(QOpenGLDebugMessage)));
|
||||||
mDebugLogger->startLogging();
|
mDebugLogger->startLogging();
|
||||||
}
|
}
|
||||||
#endif // QTK_DEBUG
|
#endif // QTK_DEBUG
|
||||||
|
|
||||||
printContextInformation();
|
printContextInformation();
|
||||||
|
|
||||||
// Initialize opengl settings
|
// Initialize opengl settings
|
||||||
glEnable(GL_MULTISAMPLE);
|
glEnable(GL_MULTISAMPLE);
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
glDepthMask(GL_TRUE);
|
glDepthMask(GL_TRUE);
|
||||||
|
@ -152,40 +90,33 @@ void MainWidget::initializeGL()
|
||||||
glClearDepth(1.0f);
|
glClearDepth(1.0f);
|
||||||
glClearColor(0.0f, 0.25f, 0.0f, 0.0f);
|
glClearColor(0.0f, 0.25f, 0.0f, 0.0f);
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
// Initialize default objects within the scene
|
|
||||||
initObjects();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::resizeGL(int width, int height)
|
void QtkWidget::resizeGL(int width, int height) {
|
||||||
{
|
|
||||||
Scene::Projection().setToIdentity();
|
Scene::Projection().setToIdentity();
|
||||||
Scene::Projection().perspective(45.0f,
|
Scene::Projection().perspective(
|
||||||
float(width) / float(height),
|
45.0f, float(width) / float(height), 0.1f, 1000.0f);
|
||||||
0.1f, 1000.0f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Protected Slots
|
* Protected Slots
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
void MainWidget::update()
|
void QtkWidget::update() {
|
||||||
{
|
|
||||||
updateCameraInput();
|
updateCameraInput();
|
||||||
|
|
||||||
mScene->update();
|
if(mScene != Q_NULLPTR) {
|
||||||
|
mScene->update();
|
||||||
|
}
|
||||||
|
|
||||||
QWidget::update();
|
QWidget::update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::messageLogged(const QOpenGLDebugMessage &msg)
|
void QtkWidget::messageLogged(const QOpenGLDebugMessage & msg) {
|
||||||
{
|
|
||||||
QString error;
|
QString error;
|
||||||
|
|
||||||
// Format based on severity
|
// Format based on severity
|
||||||
switch (msg.severity())
|
switch(msg.severity()) {
|
||||||
{
|
|
||||||
case QOpenGLDebugMessage::NotificationSeverity:
|
case QOpenGLDebugMessage::NotificationSeverity:
|
||||||
error += "--";
|
error += "--";
|
||||||
break;
|
break;
|
||||||
|
@ -203,9 +134,11 @@ void MainWidget::messageLogged(const QOpenGLDebugMessage &msg)
|
||||||
error += " (";
|
error += " (";
|
||||||
|
|
||||||
// Format based on source
|
// Format based on source
|
||||||
#define CASE(c) case QOpenGLDebugMessage::c: error += #c; break
|
#define CASE(c) \
|
||||||
switch (msg.source())
|
case QOpenGLDebugMessage::c: \
|
||||||
{
|
error += #c; \
|
||||||
|
break
|
||||||
|
switch(msg.source()) {
|
||||||
CASE(APISource);
|
CASE(APISource);
|
||||||
CASE(WindowSystemSource);
|
CASE(WindowSystemSource);
|
||||||
CASE(ShaderCompilerSource);
|
CASE(ShaderCompilerSource);
|
||||||
|
@ -219,9 +152,11 @@ void MainWidget::messageLogged(const QOpenGLDebugMessage &msg)
|
||||||
error += " : ";
|
error += " : ";
|
||||||
|
|
||||||
// Format based on type
|
// Format based on type
|
||||||
#define CASE(c) case QOpenGLDebugMessage::c: error += #c; break
|
#define CASE(c) \
|
||||||
switch (msg.type())
|
case QOpenGLDebugMessage::c: \
|
||||||
{
|
error += #c; \
|
||||||
|
break
|
||||||
|
switch(msg.type()) {
|
||||||
CASE(InvalidType);
|
CASE(InvalidType);
|
||||||
CASE(ErrorType);
|
CASE(ErrorType);
|
||||||
CASE(DeprecatedBehaviorType);
|
CASE(DeprecatedBehaviorType);
|
||||||
|
@ -239,14 +174,12 @@ void MainWidget::messageLogged(const QOpenGLDebugMessage &msg)
|
||||||
qDebug() << qPrintable(error) << "\n" << qPrintable(msg.message()) << "\n";
|
qDebug() << qPrintable(error) << "\n" << qPrintable(msg.message()) << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Protected Helpers
|
* Protected Helpers
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
void MainWidget::keyPressEvent(QKeyEvent *event)
|
void QtkWidget::keyPressEvent(QKeyEvent * event) {
|
||||||
{
|
if(event->isAutoRepeat()) {
|
||||||
if (event->isAutoRepeat()) {
|
|
||||||
// Do not repeat input while a key is held down
|
// Do not repeat input while a key is held down
|
||||||
event->ignore();
|
event->ignore();
|
||||||
} else {
|
} else {
|
||||||
|
@ -254,32 +187,27 @@ void MainWidget::keyPressEvent(QKeyEvent *event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::keyReleaseEvent(QKeyEvent *event)
|
void QtkWidget::keyReleaseEvent(QKeyEvent * event) {
|
||||||
{
|
if(event->isAutoRepeat()) {
|
||||||
if (event->isAutoRepeat()) {
|
|
||||||
event->ignore();
|
event->ignore();
|
||||||
} else {
|
} else {
|
||||||
Input::registerKeyRelease(event->key());
|
Input::registerKeyRelease(event->key());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::mousePressEvent(QMouseEvent *event)
|
void QtkWidget::mousePressEvent(QMouseEvent * event) {
|
||||||
{
|
|
||||||
Input::registerMousePress(event->button());
|
Input::registerMousePress(event->button());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::mouseReleaseEvent(QMouseEvent *event)
|
void QtkWidget::mouseReleaseEvent(QMouseEvent * event) {
|
||||||
{
|
|
||||||
Input::registerMouseRelease(event->button());
|
Input::registerMouseRelease(event->button());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Private Helpers
|
* Private Helpers
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
void MainWidget::initializeWidget()
|
void QtkWidget::initializeWidget() {
|
||||||
{
|
|
||||||
QSurfaceFormat format;
|
QSurfaceFormat format;
|
||||||
format.setRenderableType(QSurfaceFormat::OpenGL);
|
format.setRenderableType(QSurfaceFormat::OpenGL);
|
||||||
format.setProfile(QSurfaceFormat::CoreProfile);
|
format.setProfile(QSurfaceFormat::CoreProfile);
|
||||||
|
@ -296,8 +224,7 @@ void MainWidget::initializeWidget()
|
||||||
setFocusPolicy(Qt::ClickFocus);
|
setFocusPolicy(Qt::ClickFocus);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::printContextInformation()
|
void QtkWidget::printContextInformation() {
|
||||||
{
|
|
||||||
QString glType;
|
QString glType;
|
||||||
QString glVersion;
|
QString glVersion;
|
||||||
QString glProfile;
|
QString glProfile;
|
||||||
|
@ -305,65 +232,62 @@ void MainWidget::printContextInformation()
|
||||||
QString glVendor;
|
QString glVendor;
|
||||||
QString glRenderer;
|
QString glRenderer;
|
||||||
|
|
||||||
|
|
||||||
// Get Version Information
|
// Get Version Information
|
||||||
glType = (context()->isOpenGLES()) ? "OpenGL ES" : "OpenGL";
|
glType = (context()->isOpenGLES()) ? "OpenGL ES" : "OpenGL";
|
||||||
glVersion = reinterpret_cast<const char *>(glGetString(GL_VERSION));
|
glVersion = reinterpret_cast<const char *>(glGetString(GL_VERSION));
|
||||||
glVendor =
|
glVendor = reinterpret_cast<const char *>(glGetString(GL_VENDOR));
|
||||||
reinterpret_cast<const char *>(glGetString(GL_VENDOR));
|
glRenderer = reinterpret_cast<const char *>(glGetString(GL_RENDERER));
|
||||||
glRenderer =
|
|
||||||
reinterpret_cast<const char *>(glGetString(GL_RENDERER));
|
|
||||||
|
|
||||||
// Get Profile Information
|
// Get Profile Information
|
||||||
#define CASE(c) case QSurfaceFormat::c: glProfile = #c; break
|
#define CASE(c) \
|
||||||
switch (format().profile()) {
|
case QSurfaceFormat::c: \
|
||||||
|
glProfile = #c; \
|
||||||
|
break
|
||||||
|
switch(format().profile()) {
|
||||||
CASE(NoProfile);
|
CASE(NoProfile);
|
||||||
CASE(CoreProfile);
|
CASE(CoreProfile);
|
||||||
CASE(CompatibilityProfile);
|
CASE(CompatibilityProfile);
|
||||||
}
|
}
|
||||||
#undef CASE
|
#undef CASE
|
||||||
|
|
||||||
// qPrintable() will print our QString w/o quotes around it.
|
// qPrintable() will print our QString w/o quotes around it.
|
||||||
qDebug() << qPrintable(glType) << qPrintable(glVersion) << "("
|
qDebug() << qPrintable(glType) << qPrintable(glVersion) << "("
|
||||||
<< qPrintable(glProfile) << ")"
|
<< qPrintable(glProfile) << ")"
|
||||||
<< "\nOpenGL Vendor: " << qPrintable(glVendor)
|
<< "\nOpenGL Vendor: " << qPrintable(glVendor)
|
||||||
<< "\nRendering Device: " << qPrintable(glRenderer) << "\n";
|
<< "\nRendering Device: " << qPrintable(glRenderer) << "\n";
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::updateCameraInput()
|
void QtkWidget::updateCameraInput() {
|
||||||
{
|
|
||||||
Input::update();
|
Input::update();
|
||||||
// Camera Transformation
|
// Camera Transformation
|
||||||
if (Input::buttonPressed(Qt::RightButton)) {
|
if(Input::buttonPressed(Qt::RightButton)) {
|
||||||
static const float transSpeed = 0.1f;
|
static const float transSpeed = 0.1f;
|
||||||
static const float rotSpeed = 0.5f;
|
static const float rotSpeed = 0.5f;
|
||||||
|
|
||||||
// Handle rotations
|
// Handle rotations
|
||||||
Scene::Camera().transform().rotate(-rotSpeed * Input::mouseDelta().x(),
|
Scene::Camera().transform().rotate(
|
||||||
Camera3D::LocalUp);
|
-rotSpeed * Input::mouseDelta().x(), Camera3D::LocalUp);
|
||||||
Scene::Camera().transform().rotate(-rotSpeed * Input::mouseDelta().y(),
|
Scene::Camera().transform().rotate(
|
||||||
Scene::Camera().right());
|
-rotSpeed * Input::mouseDelta().y(), Scene::Camera().right());
|
||||||
|
|
||||||
// Handle translations
|
// Handle translations
|
||||||
QVector3D translation;
|
QVector3D translation;
|
||||||
if (Input::keyPressed(Qt::Key_W)) {
|
if(Input::keyPressed(Qt::Key_W)) {
|
||||||
translation += Scene::Camera().forward();
|
translation += Scene::Camera().forward();
|
||||||
}
|
}
|
||||||
if (Input::keyPressed(Qt::Key_S)) {
|
if(Input::keyPressed(Qt::Key_S)) {
|
||||||
translation -= Scene::Camera().forward();
|
translation -= Scene::Camera().forward();
|
||||||
}
|
}
|
||||||
if (Input::keyPressed(Qt::Key_A)) {
|
if(Input::keyPressed(Qt::Key_A)) {
|
||||||
translation -= Scene::Camera().right();
|
translation -= Scene::Camera().right();
|
||||||
}
|
}
|
||||||
if (Input::keyPressed(Qt::Key_D)) {
|
if(Input::keyPressed(Qt::Key_D)) {
|
||||||
translation += Scene::Camera().right();
|
translation += Scene::Camera().right();
|
||||||
}
|
}
|
||||||
if (Input::keyPressed(Qt::Key_Q)) {
|
if(Input::keyPressed(Qt::Key_Q)) {
|
||||||
translation -= Scene::Camera().up() / 2.0f;
|
translation -= Scene::Camera().up() / 2.0f;
|
||||||
}
|
}
|
||||||
if (Input::keyPressed(Qt::Key_E)) {
|
if(Input::keyPressed(Qt::Key_E)) {
|
||||||
translation += Scene::Camera().up() / 2.0f;
|
translation += Scene::Camera().up() / 2.0f;
|
||||||
}
|
}
|
||||||
Scene::Camera().transform().translate(transSpeed * translation);
|
Scene::Camera().transform().translate(transSpeed * translation);
|
|
@ -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_QTKWIDGET_H
|
||||||
|
#define QTK_QTKWIDGET_H
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <QMatrix4x4>
|
||||||
|
#include <QOpenGLDebugLogger>
|
||||||
|
#include <QOpenGLFunctions>
|
||||||
|
#include <QOpenGLWidget>
|
||||||
|
|
||||||
|
#include <abstractscene.h>
|
||||||
|
#include <qtkapi.h>
|
||||||
|
|
||||||
|
namespace Qtk {
|
||||||
|
class QTKAPI QtkWidget : public QOpenGLWidget, protected QOpenGLFunctions {
|
||||||
|
Q_OBJECT;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Constructors
|
||||||
|
QtkWidget();
|
||||||
|
explicit QtkWidget(QWidget * parent);
|
||||||
|
explicit QtkWidget(const QSurfaceFormat & format);
|
||||||
|
~QtkWidget() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void teardownGL();
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Inherited virtual Members
|
||||||
|
void paintGL() override;
|
||||||
|
void initializeGL() override;
|
||||||
|
void resizeGL(int width, int height) override;
|
||||||
|
|
||||||
|
inline Qtk::Scene * getScene() { return mScene; }
|
||||||
|
|
||||||
|
inline void setScene(Qtk::Scene * scene) {
|
||||||
|
delete mScene;
|
||||||
|
|
||||||
|
mScene = scene;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected slots:
|
||||||
|
void update();
|
||||||
|
#ifdef QTK_DEBUG
|
||||||
|
static void messageLogged(const QOpenGLDebugMessage & msg);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
static void updateCameraInput();
|
||||||
|
|
||||||
|
Qtk::Scene * mScene;
|
||||||
|
#ifdef QTK_DEBUG
|
||||||
|
void printContextInformation();
|
||||||
|
QOpenGLDebugLogger * mDebugLogger;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
} // namespace Qtk
|
||||||
|
|
||||||
|
#endif // QTK_QTKWIDGET_H
|
|
@ -1,34 +0,0 @@
|
||||||
/*##############################################################################
|
|
||||||
## Author: Shaun Reed ##
|
|
||||||
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
|
|
||||||
## About: Manage files and resources used by qtk ##
|
|
||||||
## ##
|
|
||||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
|
||||||
##############################################################################*/
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#ifndef QTK_RESOURCEMANAGER_H
|
|
||||||
#define QTK_RESOURCEMANAGER_H
|
|
||||||
|
|
||||||
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
|
|
||||||
* 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'
|
|
||||||
* @return Absoulte system path to a qtk asset
|
|
||||||
*/
|
|
||||||
static std::string getPath(const std::string & path)
|
|
||||||
// Only construct qtk resource path if in qrc format; else return it as-is
|
|
||||||
{ return path[0] == ':' ? resourcesDir + path.substr(2) : path; }
|
|
||||||
|
|
||||||
static std::string resourcesDir;
|
|
||||||
} RM;
|
|
||||||
|
|
||||||
#endif //QTK_RESOURCEMANAGER_H
|
|
|
@ -6,40 +6,42 @@
|
||||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||||
##############################################################################*/
|
##############################################################################*/
|
||||||
|
|
||||||
#include <scene.h>
|
#include <abstractscene.h>
|
||||||
|
#include <skybox.h>
|
||||||
#include <texture.h>
|
#include <texture.h>
|
||||||
|
|
||||||
#include <skybox.h>
|
using namespace Qtk;
|
||||||
|
|
||||||
|
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 = OpenGLTextureFactory::initCubeMap(
|
||||||
|
QImage(right.c_str()).mirrored(), QImage(top.c_str()),
|
||||||
|
QImage(front.c_str()), QImage(left.c_str()), QImage(bottom.c_str()),
|
||||||
|
QImage(back.c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
Skybox::Skybox(std::string right, std::string top, std::string front,
|
Skybox::Skybox(const std::string & name) :
|
||||||
std::string left, std::string bottom, std::string back,
|
Skybox(
|
||||||
const std::string & name)
|
":/right.png", ":/top.png", ":/front.png", ":/left.png", ":/bottom.png",
|
||||||
: mCubeMap(OpenGLTextureFactory::initCubeMap(
|
":/back.png", name) {}
|
||||||
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()))),
|
|
||||||
mVBO(QOpenGLBuffer::VertexBuffer),
|
|
||||||
mVertices(Cube(QTK_DRAW_ELEMENTS).getVertices()),
|
|
||||||
mIndices(Cube(QTK_DRAW_ELEMENTS).getIndexData())
|
|
||||||
{ init();}
|
|
||||||
|
|
||||||
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(QOpenGLTexture * cubeMap, const std::string & name) :
|
||||||
|
mCubeMap(cubeMap) {
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Public Member Functions
|
* Public Member Functions
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
void Skybox::draw()
|
void Skybox::draw() {
|
||||||
{
|
|
||||||
glDepthFunc(GL_LEQUAL);
|
glDepthFunc(GL_LEQUAL);
|
||||||
glDepthMask(GL_FALSE);
|
glDepthMask(GL_FALSE);
|
||||||
|
|
||||||
|
@ -50,8 +52,8 @@ void Skybox::draw()
|
||||||
mProgram.setUniformValue("uProjectionMatrix", Scene::Projection());
|
mProgram.setUniformValue("uProjectionMatrix", Scene::Projection());
|
||||||
mProgram.setUniformValue("uViewMatrix", Scene::Camera().toMatrix());
|
mProgram.setUniformValue("uViewMatrix", Scene::Camera().toMatrix());
|
||||||
mProgram.setUniformValue("uTexture", 0);
|
mProgram.setUniformValue("uTexture", 0);
|
||||||
glDrawElements(GL_TRIANGLES, mIndices.size(),
|
glDrawElements(
|
||||||
GL_UNSIGNED_INT, mIndices.data());
|
GL_TRIANGLES, mIndices.size(), GL_UNSIGNED_INT, mIndices.data());
|
||||||
|
|
||||||
mCubeMap->release();
|
mCubeMap->release();
|
||||||
mProgram.release();
|
mProgram.release();
|
||||||
|
@ -62,13 +64,11 @@ void Skybox::draw()
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Private Member Functions
|
* Private Member Functions
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
void Skybox::init()
|
void Skybox::init() {
|
||||||
{
|
|
||||||
initializeOpenGLFunctions();
|
initializeOpenGLFunctions();
|
||||||
|
|
||||||
// Set up shader program
|
// Set up shader program
|
||||||
|
@ -87,13 +87,11 @@ void Skybox::init()
|
||||||
mVBO.setUsagePattern(QOpenGLBuffer::StaticDraw);
|
mVBO.setUsagePattern(QOpenGLBuffer::StaticDraw);
|
||||||
mVBO.bind();
|
mVBO.bind();
|
||||||
// Allocate vertex positions into VBO
|
// Allocate vertex positions into VBO
|
||||||
mVBO.allocate(mVertices.data(),
|
mVBO.allocate(mVertices.data(), mVertices.size() * sizeof(mVertices[0]));
|
||||||
mVertices.size() * sizeof(mVertices[0]));
|
|
||||||
|
|
||||||
// Enable attribute array for vertex positions
|
// Enable attribute array for vertex positions
|
||||||
mProgram.enableAttributeArray(0);
|
mProgram.enableAttributeArray(0);
|
||||||
mProgram.setAttributeBuffer(0, GL_FLOAT, 0,
|
mProgram.setAttributeBuffer(0, GL_FLOAT, 0, 3, sizeof(QVector3D));
|
||||||
3, sizeof(QVector3D));
|
|
||||||
// Set shader texture unit to 0
|
// Set shader texture unit to 0
|
||||||
mProgram.setUniformValue("uTexture", 0);
|
mProgram.setUniformValue("uTexture", 0);
|
||||||
|
|
||||||
|
|
54
src/skybox.h
54
src/skybox.h
|
@ -10,39 +10,47 @@
|
||||||
|
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
#include <QOpenGLBuffer>
|
#include <QOpenGLBuffer>
|
||||||
|
#include <QOpenGLFunctions>
|
||||||
#include <QOpenGLShaderProgram>
|
#include <QOpenGLShaderProgram>
|
||||||
#include <QOpenGLTexture>
|
#include <QOpenGLTexture>
|
||||||
#include <QOpenGLVertexArrayObject>
|
#include <QOpenGLVertexArrayObject>
|
||||||
#include <QOpenGLFunctions>
|
|
||||||
|
|
||||||
#include <camera3d.h>
|
#include <camera3d.h>
|
||||||
#include <mesh.h>
|
#include <mesh.h>
|
||||||
|
#include <qtkapi.h>
|
||||||
|
|
||||||
|
namespace Qtk {
|
||||||
|
class QTKAPI Skybox : protected QOpenGLFunctions {
|
||||||
|
public:
|
||||||
|
// Delegate this constructor to use default skybox images
|
||||||
|
// + This allows creating a skybox with no arguments ( auto s = new
|
||||||
|
// Skybox;
|
||||||
|
// )
|
||||||
|
explicit Skybox(const std::string & name = "Skybox");
|
||||||
|
explicit Skybox(
|
||||||
|
QOpenGLTexture * cubeMap, const std::string & name = "Skybox");
|
||||||
|
// Constructor, Destructor
|
||||||
|
Skybox(
|
||||||
|
const std::string & right, const std::string & top,
|
||||||
|
const std::string & front, const std::string & left,
|
||||||
|
const std::string & bottom, const std::string & back,
|
||||||
|
const std::string & name = "Skybox");
|
||||||
|
|
||||||
class Skybox : protected QOpenGLFunctions {
|
~Skybox() = default;
|
||||||
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");
|
|
||||||
// Constructor, Destructor
|
|
||||||
Skybox(std::string right, std::string top, std::string front,
|
|
||||||
std::string left, std::string bottom, std::string back,
|
|
||||||
const std::string & name="Skybox");
|
|
||||||
~Skybox() {}
|
|
||||||
|
|
||||||
void draw();
|
void draw();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
Vertices mVertices;
|
Vertices mVertices;
|
||||||
Indices mIndices;
|
Indices mIndices;
|
||||||
|
|
||||||
QOpenGLShaderProgram mProgram;
|
QOpenGLShaderProgram mProgram;
|
||||||
QOpenGLVertexArrayObject mVAO;
|
QOpenGLVertexArrayObject mVAO;
|
||||||
QOpenGLBuffer mVBO;
|
QOpenGLBuffer mVBO;
|
||||||
QOpenGLTexture * mCubeMap;
|
QOpenGLTexture * mCubeMap;
|
||||||
};
|
};
|
||||||
|
} // namespace Qtk
|
||||||
|
|
||||||
#endif // QTK_SKYBOX_H
|
#endif // QTK_SKYBOX_H
|
||||||
|
|
|
@ -8,17 +8,18 @@
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QImageReader>
|
#include <QImageReader>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include <texture.h>
|
#include <texture.h>
|
||||||
|
|
||||||
std::unordered_map<std::string, Texture *> TM::textureMap;
|
using namespace Qtk;
|
||||||
|
|
||||||
QImage * OpenGLTextureFactory::initImage(const char * image, bool flipX, bool flipY)
|
QImage * OpenGLTextureFactory::initImage(
|
||||||
{
|
const char * image, bool flipX, bool flipY) {
|
||||||
// Qt6 limits loaded images to 256MB by default
|
// Qt6 limits loaded images to 256MB by default
|
||||||
QImageReader::setAllocationLimit(512);
|
QImageReader::setAllocationLimit(512);
|
||||||
auto loadedImage = new QImage(QImage(image).mirrored(flipX, flipY));
|
auto loadedImage = new QImage(QImage(image).mirrored(flipX, flipY));
|
||||||
if (loadedImage->isNull()) {
|
if(loadedImage->isNull()) {
|
||||||
qDebug() << "Error loading image: " << image << "\n";
|
qDebug() << "Error loading image: " << image << "\n";
|
||||||
qDebug() << QImageReader::supportedImageFormats();
|
qDebug() << QImageReader::supportedImageFormats();
|
||||||
return Q_NULLPTR;
|
return Q_NULLPTR;
|
||||||
|
@ -27,46 +28,39 @@ QImage * OpenGLTextureFactory::initImage(const char * image, bool flipX, bool fl
|
||||||
return loadedImage;
|
return loadedImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
QOpenGLTexture * OpenGLTextureFactory::initTexture2D(const char * texture,
|
QOpenGLTexture * OpenGLTextureFactory::initTexture2D(
|
||||||
bool flipX, bool flipY)
|
const char * texture, bool flipX, bool flipY) {
|
||||||
{
|
|
||||||
QImage * image = initImage(texture, flipX, flipY);
|
QImage * image = initImage(texture, flipX, flipY);
|
||||||
auto newTexture = new QOpenGLTexture(QOpenGLTexture::Target2D);
|
auto newTexture = new QOpenGLTexture(QOpenGLTexture::Target2D);
|
||||||
newTexture->setData(*image);
|
newTexture->setData(*image);
|
||||||
newTexture->setWrapMode(QOpenGLTexture::Repeat);
|
newTexture->setWrapMode(QOpenGLTexture::Repeat);
|
||||||
newTexture->setMinMagFilters(QOpenGLTexture::LinearMipMapLinear,
|
newTexture->setMinMagFilters(
|
||||||
QOpenGLTexture::Linear);
|
QOpenGLTexture::LinearMipMapLinear, QOpenGLTexture::Linear);
|
||||||
delete image;
|
delete image;
|
||||||
return newTexture;
|
return newTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
QOpenGLTexture * OpenGLTextureFactory::initCubeMap(const char * tile)
|
QOpenGLTexture * OpenGLTextureFactory::initCubeMap(const char * tile) {
|
||||||
{
|
return initCubeMap(
|
||||||
return initCubeMap(QImage(tile), QImage(tile),
|
QImage(tile), QImage(tile), QImage(tile), QImage(tile), QImage(tile),
|
||||||
QImage(tile), QImage(tile),
|
QImage(tile));
|
||||||
QImage(tile), QImage(tile));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QOpenGLTexture * OpenGLTextureFactory::initCubeMap(
|
QOpenGLTexture * OpenGLTextureFactory::initCubeMap(
|
||||||
const char * right, const char * top,
|
const char * right, const char * top, const char * front, const char * left,
|
||||||
const char * front, const char * left,
|
const char * bottom, const char * back) {
|
||||||
const char * bottom, const char * back)
|
return initCubeMap(
|
||||||
{
|
QImage(right), QImage(top), QImage(front), QImage(left), QImage(bottom),
|
||||||
return initCubeMap(QImage(right), QImage(top),
|
QImage(back));
|
||||||
QImage(front), QImage(left),
|
|
||||||
QImage(bottom), QImage(back));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QOpenGLTexture * OpenGLTextureFactory::initCubeMap(
|
QOpenGLTexture * OpenGLTextureFactory::initCubeMap(
|
||||||
QImage right, QImage top,
|
QImage right, QImage top, QImage front, QImage left, QImage bottom,
|
||||||
QImage front, QImage left,
|
QImage back) {
|
||||||
QImage bottom, QImage back)
|
|
||||||
{
|
|
||||||
auto texture = new QOpenGLTexture(QOpenGLTexture::TargetCubeMap);
|
auto texture = new QOpenGLTexture(QOpenGLTexture::TargetCubeMap);
|
||||||
std::vector<QImage> faceTextures = {
|
std::vector<QImage> faceTextures = {std::move(right), std::move(top),
|
||||||
right, top, front,
|
std::move(front), std::move(left),
|
||||||
left, bottom, back
|
std::move(bottom), std::move(back)};
|
||||||
};
|
|
||||||
// Initialize skybox cubemap texture
|
// Initialize skybox cubemap texture
|
||||||
texture->create();
|
texture->create();
|
||||||
texture->bind();
|
texture->bind();
|
||||||
|
@ -74,27 +68,27 @@ QOpenGLTexture * OpenGLTextureFactory::initCubeMap(
|
||||||
std::vector<QOpenGLTexture::CubeMapFace> faces = {
|
std::vector<QOpenGLTexture::CubeMapFace> faces = {
|
||||||
QOpenGLTexture::CubeMapPositiveX, QOpenGLTexture::CubeMapPositiveY,
|
QOpenGLTexture::CubeMapPositiveX, QOpenGLTexture::CubeMapPositiveY,
|
||||||
QOpenGLTexture::CubeMapPositiveZ, QOpenGLTexture::CubeMapNegativeX,
|
QOpenGLTexture::CubeMapPositiveZ, QOpenGLTexture::CubeMapNegativeX,
|
||||||
QOpenGLTexture::CubeMapNegativeY, QOpenGLTexture::CubeMapNegativeZ
|
QOpenGLTexture::CubeMapNegativeY, QOpenGLTexture::CubeMapNegativeZ};
|
||||||
};
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (const auto & face : faces) {
|
for(const auto & face : faces) {
|
||||||
QImage faceImage(faceTextures[i]);
|
QImage faceImage(faceTextures[i]);
|
||||||
if (faceImage.isNull()) {
|
if(faceImage.isNull()) {
|
||||||
qDebug() << "Error loading cube map image\n";
|
qDebug() << "Error loading cube map image\n";
|
||||||
}
|
}
|
||||||
faceImage = faceImage.convertToFormat(QImage::Format_RGBA8888);
|
faceImage = faceImage.convertToFormat(QImage::Format_RGBA8888);
|
||||||
|
|
||||||
// On the first iteration, set format and allocate texture storage
|
// On the first iteration, set format and allocate texture storage
|
||||||
if (face == QOpenGLTexture::CubeMapPositiveX) {
|
if(face == QOpenGLTexture::CubeMapPositiveX) {
|
||||||
// This also needs to happen on the first iteration, anyways
|
// 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->setFormat(QOpenGLTexture::RGBA8_UNorm);
|
||||||
texture->allocateStorage();
|
texture->allocateStorage();
|
||||||
}
|
}
|
||||||
|
|
||||||
texture->setData(0, 0, face,
|
texture->setData(
|
||||||
QOpenGLTexture::RGBA, QOpenGLTexture::UInt8,
|
0, 0, face, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8,
|
||||||
faceImage.constBits());
|
faceImage.constBits());
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
128
src/texture.h
128
src/texture.h
|
@ -11,81 +11,77 @@
|
||||||
|
|
||||||
#include <QOpenGLTexture>
|
#include <QOpenGLTexture>
|
||||||
|
|
||||||
class OpenGLTextureFactory {
|
#include <qtkapi.h>
|
||||||
public:
|
|
||||||
~OpenGLTextureFactory() = default;
|
|
||||||
|
|
||||||
// QImage
|
namespace Qtk {
|
||||||
static QImage * initImage(const char * image,
|
class QTKAPI OpenGLTextureFactory {
|
||||||
bool flipX=false, bool flipY=false);
|
public:
|
||||||
|
~OpenGLTextureFactory() = default;
|
||||||
|
|
||||||
// 2D Texture
|
// QImage
|
||||||
static QOpenGLTexture * initTexture2D(const char * texture,
|
static QImage * initImage(
|
||||||
bool flipX=false, bool flipY=false);
|
const char * image, bool flipX = false, bool flipY = false);
|
||||||
|
|
||||||
// Cube maps
|
// 2D Texture
|
||||||
static QOpenGLTexture * initCubeMap(QImage right, QImage top,
|
static QOpenGLTexture * initTexture2D(
|
||||||
QImage front, QImage left,
|
const char * texture, bool flipX = false, bool flipY = false);
|
||||||
QImage bottom, QImage back);
|
|
||||||
// Overloads for cube map initialization
|
|
||||||
static QOpenGLTexture * initCubeMap(const char * tile);
|
|
||||||
static QOpenGLTexture * initCubeMap(const char * right, const char * top,
|
|
||||||
const char * front, const char * left,
|
|
||||||
const char * bottom, const char * back);
|
|
||||||
|
|
||||||
private:
|
// Cube maps
|
||||||
// Private ctor to prevent creating instances of this class
|
static QOpenGLTexture * initCubeMap(
|
||||||
OpenGLTextureFactory() = default;
|
QImage right, QImage top, QImage front, QImage left, QImage bottom,
|
||||||
};
|
QImage back);
|
||||||
|
// Overloads for cube map initialization
|
||||||
|
static QOpenGLTexture * initCubeMap(const char * tile);
|
||||||
|
static QOpenGLTexture * initCubeMap(
|
||||||
|
const char * right, const char * top, const char * front,
|
||||||
|
const char * left, const char * bottom, const char * back);
|
||||||
|
|
||||||
class Texture;
|
private:
|
||||||
typedef class TextureManager {
|
// Private ctor to prevent creating instances of this class
|
||||||
public:
|
OpenGLTextureFactory() = default;
|
||||||
static inline Texture * getInstance(std::string path)
|
};
|
||||||
{ return textureMap.count(path) > 0 ? textureMap[path] : Q_NULLPTR; }
|
|
||||||
static inline bool addInstance(const std::string & path, Texture * texture)
|
|
||||||
{ return textureMap.emplace(path, texture).second ? true : false; }
|
|
||||||
|
|
||||||
private:
|
class Texture {
|
||||||
static std::unordered_map<std::string, Texture *> textureMap;
|
public:
|
||||||
} TM;
|
Texture() = default;
|
||||||
|
Texture(const Texture & value) = delete;
|
||||||
|
|
||||||
class Texture {
|
// Texture(const Texture & value) {
|
||||||
// explicit Texture(QOpenGLTexture * texture) : mOpenGLTexture(texture) { }
|
// mOpenGLTexture = OpenGLTextureFactory::initTexture2D(value.mPath);
|
||||||
public:
|
// mPath = value.mPath;
|
||||||
Texture() = default;
|
// }
|
||||||
Texture(const Texture & value) {
|
explicit Texture(
|
||||||
if (TM::getInstance(value.mPath)) {
|
const char * path, bool flipX = false, bool flipY = false) :
|
||||||
mOpenGLTexture = TM::getInstance(value.mPath)->mOpenGLTexture;
|
mOpenGLTexture(
|
||||||
}
|
OpenGLTextureFactory::initTexture2D(path, flipX, flipY)),
|
||||||
else {
|
mPath(path) {}
|
||||||
mOpenGLTexture = OpenGLTextureFactory::initTexture2D(value.mPath);
|
|
||||||
TM::addInstance(value.mPath, this);
|
|
||||||
}
|
|
||||||
mPath = value.mPath;
|
|
||||||
}
|
|
||||||
explicit Texture(const char * path, bool flipX=false, bool flipY=false) :
|
|
||||||
mPath(path) {
|
|
||||||
if (TM::getInstance(path) == Q_NULLPTR) {
|
|
||||||
mOpenGLTexture = OpenGLTextureFactory::initTexture2D(path, flipX, flipY);
|
|
||||||
TM::addInstance(path, this);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
mOpenGLTexture = TM::getInstance(path)->mOpenGLTexture;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// ~Texture() { if (mOpenGLTexture) mOpenGLTexture->destroy();}
|
|
||||||
|
|
||||||
inline QOpenGLTexture & getOpenGLTexture() { return *mOpenGLTexture;}
|
// explicit Texture(QOpenGLTexture * texture) : mOpenGLTexture(texture) {
|
||||||
|
// }
|
||||||
|
~Texture() { mOpenGLTexture->destroy(); }
|
||||||
|
|
||||||
inline void setTexture(const char * path, bool flipX=false, bool flipY=false)
|
[[nodiscard]] inline QOpenGLTexture & getOpenGLTexture() const {
|
||||||
{ mOpenGLTexture = OpenGLTextureFactory::initTexture2D(path, flipX, flipY);}
|
return *mOpenGLTexture;
|
||||||
inline void setTexture(QOpenGLTexture * texture) { mOpenGLTexture = texture;}
|
}
|
||||||
|
|
||||||
inline bool hasTexture() const { return mOpenGLTexture != Q_NULLPTR;}
|
void setTexture(
|
||||||
|
const char * path, bool flipX = false, bool flipY = false) {
|
||||||
|
mOpenGLTexture =
|
||||||
|
OpenGLTextureFactory::initTexture2D(path, flipX, flipY);
|
||||||
|
}
|
||||||
|
|
||||||
QOpenGLTexture * mOpenGLTexture = Q_NULLPTR;
|
inline void setTexture(QOpenGLTexture * texture) {
|
||||||
const char * mPath;
|
mOpenGLTexture = texture;
|
||||||
};
|
}
|
||||||
|
|
||||||
#endif // QTOPENGL_TEXTURE_H
|
[[nodiscard]] inline bool hasTexture() const {
|
||||||
|
return mOpenGLTexture != Q_NULLPTR;
|
||||||
|
}
|
||||||
|
|
||||||
|
QOpenGLTexture * mOpenGLTexture = Q_NULLPTR;
|
||||||
|
const char * mPath {};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Qtk
|
||||||
|
|
||||||
|
#endif // QTOPENGL_TEXTURE_H
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include <transform3D.h>
|
#include <transform3D.h>
|
||||||
|
|
||||||
|
using namespace Qtk;
|
||||||
|
|
||||||
const QVector3D Transform3D::LocalForward(0.0f, 0.0f, 1.0f);
|
const QVector3D Transform3D::LocalForward(0.0f, 0.0f, 1.0f);
|
||||||
const QVector3D Transform3D::LocalUp(0.0f, 1.0f, 0.0f);
|
const QVector3D Transform3D::LocalUp(0.0f, 1.0f, 0.0f);
|
||||||
|
@ -18,64 +19,53 @@ const QVector3D Transform3D::LocalRight(1.0f, 0.0f, 0.0f);
|
||||||
* Transformations
|
* Transformations
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
void Transform3D::translate(const QVector3D & dt)
|
void Transform3D::translate(const QVector3D & dt) {
|
||||||
{
|
|
||||||
m_dirty = true;
|
m_dirty = true;
|
||||||
mTranslation += dt;
|
mTranslation += dt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transform3D::scale(const QVector3D & ds)
|
void Transform3D::scale(const QVector3D & ds) {
|
||||||
{
|
|
||||||
m_dirty = true;
|
m_dirty = true;
|
||||||
mScale *= ds;
|
mScale *= ds;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transform3D::rotate(const QQuaternion & dr)
|
void Transform3D::rotate(const QQuaternion & dr) {
|
||||||
{
|
|
||||||
m_dirty = true;
|
m_dirty = true;
|
||||||
mRotation = dr * mRotation;
|
mRotation = dr * mRotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transform3D::grow(const QVector3D & ds)
|
void Transform3D::grow(const QVector3D & ds) {
|
||||||
{
|
|
||||||
m_dirty = true;
|
m_dirty = true;
|
||||||
mScale += ds;
|
mScale += ds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Setters
|
* Setters
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
void Transform3D::setTranslation(const QVector3D & t)
|
void Transform3D::setTranslation(const QVector3D & t) {
|
||||||
{
|
|
||||||
m_dirty = true;
|
m_dirty = true;
|
||||||
mTranslation = t;
|
mTranslation = t;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transform3D::setScale(const QVector3D & s)
|
void Transform3D::setScale(const QVector3D & s) {
|
||||||
{
|
|
||||||
m_dirty = true;
|
m_dirty = true;
|
||||||
mScale = s;
|
mScale = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transform3D::setRotation(const QQuaternion & r)
|
void Transform3D::setRotation(const QQuaternion & r) {
|
||||||
{
|
|
||||||
m_dirty = true;
|
m_dirty = true;
|
||||||
mRotation = r;
|
mRotation = r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Accessors
|
* Accessors
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
// Produces modelToWorld matrix using current set of transformations
|
// Produces modelToWorld matrix using current set of transformations
|
||||||
// Transformation * rotation * scale = modelToWorld
|
// Transformation * rotation * scale = modelToWorld
|
||||||
const QMatrix4x4 & Transform3D::toMatrix()
|
const QMatrix4x4 & Transform3D::toMatrix() {
|
||||||
{
|
if(m_dirty) {
|
||||||
if (m_dirty)
|
|
||||||
{
|
|
||||||
m_dirty = false;
|
m_dirty = false;
|
||||||
mWorld.setToIdentity();
|
mWorld.setToIdentity();
|
||||||
mWorld.translate(mTranslation);
|
mWorld.translate(mTranslation);
|
||||||
|
@ -85,60 +75,63 @@ const QMatrix4x4 & Transform3D::toMatrix()
|
||||||
return mWorld;
|
return mWorld;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Queries
|
* Queries
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
QVector3D Transform3D::getForward() const
|
QVector3D Transform3D::getForward() const {
|
||||||
{
|
|
||||||
return mRotation.rotatedVector(LocalForward);
|
return mRotation.rotatedVector(LocalForward);
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector3D Transform3D::getUp() const
|
QVector3D Transform3D::getUp() const {
|
||||||
{
|
|
||||||
return mRotation.rotatedVector(LocalUp);
|
return mRotation.rotatedVector(LocalUp);
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector3D Transform3D::getRight() const
|
QVector3D Transform3D::getRight() const {
|
||||||
{
|
|
||||||
return mRotation.rotatedVector(LocalRight);
|
return mRotation.rotatedVector(LocalRight);
|
||||||
|
while(true) {
|
||||||
|
int xx;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* QT Streams
|
* QT Streams
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
QDebug operator<<(QDebug dbg, const Transform3D & transform)
|
namespace Qtk {
|
||||||
{
|
#ifndef QT_NO_DEBUG_STREAM
|
||||||
dbg << "Transform3D\n{\n";
|
|
||||||
dbg << "Position: <" << transform.getTranslation().x() << ", "
|
|
||||||
<< transform.getTranslation().y() << ", "
|
|
||||||
<< transform.getTranslation().z() << ">\n";
|
|
||||||
dbg << "Scale: <" << transform.getScale().x() << ", "
|
|
||||||
<< transform.getScale().y() << ", "
|
|
||||||
<< transform.getScale().z() << ">\n";
|
|
||||||
dbg << "Rotation: <" << transform.getRotation().x() << ", "
|
|
||||||
<< transform.getRotation().y() << ", "
|
|
||||||
<< transform.getRotation().z() << " | " <<
|
|
||||||
transform.getRotation().scalar() << ">\n}";
|
|
||||||
return dbg;
|
|
||||||
}
|
|
||||||
|
|
||||||
QDataStream & operator<<(QDataStream & out, const Transform3D & transform)
|
QDebug operator<<(QDebug dbg, const Transform3D & transform) {
|
||||||
{
|
dbg << "Transform3D\n{\n";
|
||||||
out << transform.mTranslation;
|
dbg << "Position: <" << transform.getTranslation().x() << ", "
|
||||||
out << transform.mScale;
|
<< transform.getTranslation().y() << ", "
|
||||||
out << transform.mRotation;
|
<< transform.getTranslation().z() << ">\n";
|
||||||
return out;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
QDataStream & operator>>(QDataStream & in, Transform3D & transform)
|
#endif
|
||||||
{
|
|
||||||
in >> transform.mTranslation;
|
#ifndef QT_NO_DATASTREAM
|
||||||
in >> transform.mScale;
|
QDataStream & operator<<(QDataStream & out, const Transform3D & transform) {
|
||||||
in >> transform.mRotation;
|
out << transform.mTranslation;
|
||||||
transform.m_dirty = true;
|
out << transform.mScale;
|
||||||
return in;
|
out << transform.mRotation;
|
||||||
}
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDataStream & operator>>(QDataStream & in, Transform3D & transform) {
|
||||||
|
in >> transform.mTranslation;
|
||||||
|
in >> transform.mScale;
|
||||||
|
in >> transform.mRotation;
|
||||||
|
transform.m_dirty = true;
|
||||||
|
return in;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
} // namespace Qtk
|
||||||
|
|
|
@ -10,108 +10,146 @@
|
||||||
#ifndef QTK_TRANSFORM3D_H
|
#ifndef QTK_TRANSFORM3D_H
|
||||||
#define QTK_TRANSFORM3D_H
|
#define QTK_TRANSFORM3D_H
|
||||||
|
|
||||||
#include <QDebug>
|
|
||||||
#include <QMatrix4x4>
|
#include <QMatrix4x4>
|
||||||
#include <QQuaternion>
|
#include <QQuaternion>
|
||||||
#include <QVector3D>
|
#include <QVector3D>
|
||||||
|
|
||||||
|
#ifndef QT_NO_DEBUG_STREAM
|
||||||
|
|
||||||
class Transform3D
|
#include <QDebug>
|
||||||
{
|
|
||||||
public:
|
|
||||||
// Constructors
|
|
||||||
inline Transform3D() : m_dirty(true),
|
|
||||||
mScale(1.0f, 1.0f, 1.0f),
|
|
||||||
mTranslation(0.0f, 0.0f, 0.0f) { }
|
|
||||||
|
|
||||||
//
|
#endif
|
||||||
// Transformations
|
|
||||||
|
|
||||||
void translate(const QVector3D & dt);
|
#include <qtkapi.h>
|
||||||
inline void translate(float dx, float dy, float dz)
|
|
||||||
{ translate(QVector3D(dx, dy, dz));}
|
|
||||||
|
|
||||||
// Scale object with multiplication
|
namespace Qtk {
|
||||||
void scale(const QVector3D & ds);
|
class QTKAPI Transform3D {
|
||||||
inline void scale(float dx, float dy, float dz)
|
public:
|
||||||
{ scale(QVector3D(dx, dy, dz));}
|
// Constructors
|
||||||
inline void scale(float factor)
|
inline Transform3D() :
|
||||||
{ scale(QVector3D(factor, factor, factor));}
|
m_dirty(true), mScale(1.0f, 1.0f, 1.0f),
|
||||||
|
mTranslation(0.0f, 0.0f, 0.0f) {}
|
||||||
|
|
||||||
// Multiplying by a rotation
|
//
|
||||||
void rotate(const QQuaternion & dr);
|
// Transformations
|
||||||
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 translate(const QVector3D & dt);
|
||||||
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 translate(float dx, float dy, float dz) {
|
||||||
// Setters
|
translate(QVector3D(dx, dy, dz));
|
||||||
|
}
|
||||||
|
|
||||||
// Set object position
|
// Scale object with multiplication
|
||||||
void setTranslation(const QVector3D & t);
|
void scale(const QVector3D & ds);
|
||||||
inline void setTranslation(float x, float y, float z)
|
|
||||||
{ setTranslation(QVector3D(x, y, z));}
|
|
||||||
|
|
||||||
// Set object scale
|
inline void scale(float dx, float dy, float dz) {
|
||||||
void setScale(const QVector3D & s);
|
scale(QVector3D(dx, dy, dz));
|
||||||
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
|
inline void scale(float factor) {
|
||||||
void setRotation(const QQuaternion & r);
|
scale(QVector3D(factor, factor, factor));
|
||||||
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));}
|
|
||||||
|
|
||||||
//
|
// Multiplying by a rotation
|
||||||
// Accessors
|
void rotate(const QQuaternion & dr);
|
||||||
|
|
||||||
inline const QVector3D & getTranslation() const { return mTranslation;}
|
inline void rotate(float angle, const QVector3D & axis) {
|
||||||
inline const QVector3D & getScale() const { return mScale; }
|
rotate(QQuaternion::fromAxisAndAngle(axis, angle));
|
||||||
inline const QQuaternion & getRotation() const { return mRotation; }
|
}
|
||||||
const QMatrix4x4 & toMatrix();
|
|
||||||
|
|
||||||
QVector3D getForward() const;
|
inline void rotate(float angle, float ax, float ay, float az) {
|
||||||
QVector3D getUp() const;
|
rotate(QQuaternion::fromAxisAndAngle(ax, ay, az, angle));
|
||||||
QVector3D getRight() const;
|
}
|
||||||
|
|
||||||
static const QVector3D LocalForward, LocalUp, LocalRight;
|
// Scale object by addition
|
||||||
|
void grow(const QVector3D & ds);
|
||||||
|
|
||||||
private:
|
inline void grow(float dx, float dy, float dz) {
|
||||||
QVector3D mTranslation;
|
grow(QVector3D(dx, dy, dz));
|
||||||
QQuaternion mRotation;
|
}
|
||||||
QVector3D mScale;
|
|
||||||
QMatrix4x4 mWorld;
|
|
||||||
|
|
||||||
bool m_dirty;
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)); }
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Accessors
|
||||||
|
|
||||||
|
[[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();
|
||||||
|
|
||||||
|
[[nodiscard]] QVector3D getForward() const;
|
||||||
|
[[nodiscard]] QVector3D getUp() const;
|
||||||
|
[[nodiscard]] QVector3D getRight() const;
|
||||||
|
|
||||||
|
static const QVector3D LocalForward, LocalUp, LocalRight;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QVector3D mTranslation;
|
||||||
|
QQuaternion mRotation;
|
||||||
|
QVector3D mScale;
|
||||||
|
QMatrix4x4 mWorld;
|
||||||
|
|
||||||
|
bool m_dirty;
|
||||||
|
|
||||||
#ifndef QT_NO_DATASTREAM
|
#ifndef QT_NO_DATASTREAM
|
||||||
friend QDataStream &operator<<(QDataStream & out, const Transform3D & transform);
|
friend QDataStream & operator<<(
|
||||||
friend QDataStream &operator>>(QDataStream & in, Transform3D & transform);
|
QDataStream & out, const Transform3D & transform);
|
||||||
|
friend QDataStream & operator>>(
|
||||||
|
QDataStream & in, Transform3D & transform);
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_TYPEINFO(Transform3D, Q_MOVABLE_TYPE);
|
|
||||||
|
|
||||||
// Qt Streams
|
// Qt Streams
|
||||||
#ifndef QT_NO_DEBUG_STREAM
|
#ifndef QT_NO_DEBUG_STREAM
|
||||||
QDebug operator<<(QDebug dbg, const Transform3D & transform);
|
QDebug operator<<(QDebug dbg, const Transform3D & transform);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef QT_NO_DATASTREAM
|
#ifndef QT_NO_DATASTREAM
|
||||||
QDataStream &operator<<(QDataStream & out, const Transform3D & transform);
|
QDataStream & operator<<(QDataStream & out, const Transform3D & transform);
|
||||||
QDataStream &operator>>(QDataStream & in, Transform3D & transform);
|
QDataStream & operator>>(QDataStream & in, Transform3D & transform);
|
||||||
#endif
|
#endif
|
||||||
|
} // namespace Qtk
|
||||||
|
|
||||||
#endif // QTK_TRANSFORM3D_H
|
Q_DECLARE_TYPEINFO(Qtk::Transform3D, Q_MOVABLE_TYPE);
|
||||||
|
|
||||||
|
#endif // QTK_TRANSFORM3D_H
|
||||||
|
|
Loading…
Reference in New Issue