Compare commits
3 Commits
Author | SHA1 | Date |
---|---|---|
Transporter | d0c8316f79 | |
Shaun Reed | ad59d9149e | |
Shaun Reed | e889785b65 |
|
@ -5,19 +5,27 @@ on:
|
|||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
QT_VERSION: 6.6.0
|
||||
|
||||
jobs:
|
||||
Build-Qtk:
|
||||
Qtk:
|
||||
env:
|
||||
CONFIG: -DQTK_SUBMODULES=ON -DQTK_DEBUG=OFF -DQTK_CCACHE=OFF -DQTK_GUI=ON -DQTK_PLUGINS=OFF -DQTK_EXAMPLE=ON
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
cmake: -DCMAKE_PREFIX_PATH="/home/runner/work/qtk/Qt/6.3.1/gcc_64/"
|
||||
cmake: -DCMAKE_PREFIX_PATH=/home/runner/work/qtk/Qt/$QT_VERSION/gcc_64/ $CONFIG
|
||||
flags: -j $(nproc)
|
||||
- os: windows-latest
|
||||
cmake: -DCMAKE_PREFIX_PATH="D:/a/qtk/qtk/Qt/6.3.1/mingw81_64/"
|
||||
cmake: -DCMAKE_PREFIX_PATH=D:/a/qtk/qtk/Qt/$QT_VERSION/mingw81_64/ $CONFIG
|
||||
flags: ''
|
||||
- os: macos-latest
|
||||
cmake: -DCMAKE_PREFIX_PATH="/home/runner/work/qtk/Qt/6.3.1/gcc_64/"
|
||||
cmake: -DCMAKE_PREFIX_PATH=/home/runner/work/qtk/Qt/$QT_VERSION/gcc_64/ $CONFIG
|
||||
flags: -j $(nproc)
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
|
@ -26,30 +34,273 @@ jobs:
|
|||
- name: Install Qt
|
||||
uses: jurplel/install-qt-action@v2
|
||||
with:
|
||||
version: '6.3.1'
|
||||
version: ${{ env.QT_VERSION }}
|
||||
|
||||
# Windows
|
||||
|
||||
- name: Chocolatey Action
|
||||
if: matrix.os == 'windows-latest'
|
||||
uses: crazy-max/ghaction-chocolatey@v2.0.0
|
||||
uses: crazy-max/ghaction-chocolatey@v2
|
||||
with:
|
||||
args: install pkgconfiglite --checksum e87b5ea3c9142256af60f2d5b917aa63b571e6a0 --checksum-type sha1
|
||||
|
||||
- name: Build Qtk
|
||||
- name: Install Debian packaging dependencies
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
run: |
|
||||
sudo apt update -y
|
||||
sudo apt install libxcb-cursor0 -y
|
||||
|
||||
- name: Configure Qtk Application
|
||||
shell: bash
|
||||
run: cmake -B build/ ${{ matrix.cmake }}
|
||||
|
||||
- name: Build Qtk Application
|
||||
shell: bash
|
||||
run: cmake --build build/ --config Release --target qtk_gui ${{ matrix.flags }}
|
||||
|
||||
- name: Build Qtk Example
|
||||
if: matrix.os != 'windows-latest'
|
||||
shell: bash
|
||||
run: cmake --build build/ --config Release --target qtk_example ${{ matrix.flags }}
|
||||
|
||||
# Packaging
|
||||
|
||||
- name: Install Qtk Application
|
||||
shell: bash
|
||||
run: cmake --install build/ --config Release --component qtk_gui
|
||||
|
||||
- name: Package Qtk Application
|
||||
shell: bash
|
||||
run: cmake --build build/ --target package --config Release
|
||||
|
||||
- name: Package Qtk (DEB)
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
shell: bash
|
||||
run: |
|
||||
cmake -S . -B build/ ${{ matrix.cmake }} && cmake --build build/ \
|
||||
--target qtk-main
|
||||
cd build
|
||||
cpack -C Release -G DEB
|
||||
|
||||
Build-Qtk-Assimp-Targets:
|
||||
- name: Upload package artifacts (DEB)
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: qtk-gui-${{ matrix.os }}
|
||||
path: |
|
||||
build/packages/*.deb
|
||||
|
||||
- name: Package Qtk (WIN)
|
||||
if: matrix.os == 'windows-latest'
|
||||
shell: bash
|
||||
run: |
|
||||
cd build
|
||||
cpack -C Release -G NSIS
|
||||
|
||||
- name: Upload package artifacts (WIN)
|
||||
if: matrix.os == 'windows-latest'
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: qtk-gui-${{ matrix.os }}
|
||||
path: |
|
||||
build/packages/*.exe
|
||||
|
||||
- name: Package Qtk (OSX)
|
||||
if: matrix.os == 'macos-latest'
|
||||
shell: bash
|
||||
run: |
|
||||
cd build
|
||||
cpack -C Release -G TGZ
|
||||
|
||||
- name: Upload package artifacts (OSX)
|
||||
if: matrix.os == 'macos-latest'
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: qtk-gui-${{ matrix.os }}
|
||||
path: |
|
||||
build/packages/*.tar.gz
|
||||
|
||||
- name: Upload Qtk install directory
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: qtk-gui-${{ matrix.os }}-install
|
||||
path: install/*
|
||||
|
||||
# TODO: Enable after trimming resources.
|
||||
# - name: Package Qtk Application Sources
|
||||
# if: matrix.os != 'macos-latest'
|
||||
# shell: bash
|
||||
# run: |
|
||||
# cmake --build build/ --target package_source
|
||||
#
|
||||
# - name: Upload package artifacts
|
||||
# uses: actions/upload-artifact@v3
|
||||
# with:
|
||||
# name: qtk-${{ matrix.os }}-packages
|
||||
# path: |
|
||||
# build/packages/*
|
||||
# !build/packages/_CPack_Packages/*
|
||||
|
||||
Qtk-Library:
|
||||
env:
|
||||
CONFIG: -DQTK_SUBMODULES=ON -DQTK_DEBUG=OFF -DQTK_CCACHE=OFF -DQTK_GUI=OFF -DQTK_PLUGINS=OFF -DQTK_EXAMPLE=OFF
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
cmake: -DCMAKE_PREFIX_PATH=/home/runner/work/qtk/Qt/$QT_VERSION/gcc_64/ $CONFIG
|
||||
flags: -j $(nproc)
|
||||
- os: windows-latest
|
||||
cmake: -DCMAKE_PREFIX_PATH=D:/a/qtk/qtk/Qt/$QT_VERSION/mingw81_64/ $CONFIG
|
||||
flags: ''
|
||||
- os: macos-latest
|
||||
cmake: -DCMAKE_PREFIX_PATH=/home/runner/work/qtk/Qt/$QT_VERSION/gcc_64/ $CONFIG
|
||||
flags: -j $(nproc)
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Install Qt
|
||||
uses: jurplel/install-qt-action@v2
|
||||
with:
|
||||
version: ${{ env.QT_VERSION }}
|
||||
|
||||
# Windows
|
||||
|
||||
- name: Chocolatey Action
|
||||
if: matrix.os == 'windows-latest'
|
||||
uses: crazy-max/ghaction-chocolatey@v2
|
||||
with:
|
||||
args: install pkgconfiglite --checksum e87b5ea3c9142256af60f2d5b917aa63b571e6a0 --checksum-type sha1
|
||||
|
||||
- name: Configure Qtk Library
|
||||
shell: bash
|
||||
run: cmake -B build/ ${{ matrix.cmake }}
|
||||
|
||||
- name: Build Qtk Library
|
||||
shell: bash
|
||||
run: cmake --build build/ --config Release --target qtk_library -- ${{ matrix.flags }}
|
||||
|
||||
# Packaging
|
||||
|
||||
- name: Install Qtk Library
|
||||
shell: bash
|
||||
run: cmake --install build/ --config Release --prefix=$(pwd)/install --component qtk_library
|
||||
|
||||
- name: Package Qtk Library
|
||||
shell: bash
|
||||
run: cmake --build build/ --target package --config Release
|
||||
|
||||
- name: Package Qtk Library (DEB)
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
shell: bash
|
||||
run: |
|
||||
cd build
|
||||
cpack -C Release -G DEB
|
||||
|
||||
- name: Upload package artifacts (DEB)
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: libqtk-${{ matrix.os }}
|
||||
path: |
|
||||
build/packages/*.deb
|
||||
|
||||
- name: Package Qtk Library (WIN)
|
||||
if: matrix.os == 'windows-latest'
|
||||
shell: bash
|
||||
run: |
|
||||
cd build
|
||||
cpack -C Release -G NSIS
|
||||
|
||||
- name: Upload package artifacts (WIN)
|
||||
if: matrix.os == 'windows-latest'
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: qtk-${{ matrix.os }}
|
||||
path: |
|
||||
build/packages/*.exe
|
||||
|
||||
- name: Package Qtk Library (OSX)
|
||||
if: matrix.os == 'macos-latest'
|
||||
shell: bash
|
||||
run: |
|
||||
cd build
|
||||
cpack -C Release -G TGZ
|
||||
|
||||
- name: Upload package artifacts (OSX)
|
||||
if: matrix.os == 'macos-latest'
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: qtk-${{ matrix.os }}
|
||||
path: |
|
||||
build/packages/*.tar.gz
|
||||
|
||||
- name: Upload libqtk install
|
||||
uses: actions/upload-artifact@v3
|
||||
if: always()
|
||||
with:
|
||||
name: libqtk-${{ matrix.os }}-install
|
||||
path: install/*
|
||||
|
||||
Qtk-Plugins:
|
||||
env:
|
||||
CONFIG: -DQTK_SUBMODULES=ON -DQTK_DEBUG=OFF -DQTK_CCACHE=OFF -DQTK_GUI=OFF -DQTK_PLUGINS=ON -DQTK_EXAMPLE=OFF
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
cmake: -DCMAKE_PREFIX_PATH=/home/runner/work/qtk/Qt/$QT_VERSION/gcc_64/ $CONFIG
|
||||
flags: -j $(nproc)
|
||||
- os: windows-latest
|
||||
cmake: -DCMAKE_PREFIX_PATH=D:/a/qtk/qtk/Qt/$QT_VERSION/mingw81_64/ $CONFIG
|
||||
flags: ''
|
||||
- os: macos-latest
|
||||
cmake: -DCMAKE_PREFIX_PATH=/home/runner/work/qtk/Qt/$QT_VERSION/gcc_64/ $CONFIG
|
||||
flags: -j $(nproc)
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Install Qt
|
||||
uses: jurplel/install-qt-action@v2
|
||||
with:
|
||||
version: ${{ env.QT_VERSION }}
|
||||
|
||||
- name: Chocolatey Action
|
||||
if: matrix.os == 'windows-latest'
|
||||
uses: crazy-max/ghaction-chocolatey@v2
|
||||
with:
|
||||
args: install pkgconfiglite --checksum e87b5ea3c9142256af60f2d5b917aa63b571e6a0 --checksum-type sha1
|
||||
|
||||
- name: Configure Qtk Plugins
|
||||
shell: bash
|
||||
run: cmake -B build/ ${{ matrix.cmake }}
|
||||
|
||||
- name: Build Qtk Plugins
|
||||
shell: bash
|
||||
run: cmake --build build/ --config Release --target qtk_plugins -- ${{ matrix.flags }}
|
||||
|
||||
# Packaging
|
||||
|
||||
- name: Install Qtk Plugins
|
||||
shell: bash
|
||||
run: cmake --install build/ --config Release --component qtk_plugins
|
||||
|
||||
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
|
||||
cmake: -DCMAKE_PREFIX_PATH=/home/runner/work/qtk/Qt/$QT_VERSION/gcc_64/
|
||||
- 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
|
||||
cmake: -DCMAKE_PREFIX_PATH=/home/runner/work/qtk/Qt/$QT_VERSION/gcc_64/
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
|
@ -58,7 +309,7 @@ jobs:
|
|||
- name: Install Qt
|
||||
uses: jurplel/install-qt-action@v2
|
||||
with:
|
||||
version: '6.3.1'
|
||||
version: ${{ env.QT_VERSION }}
|
||||
|
||||
- name: Install Assimp MacOS
|
||||
if: matrix.os == 'macos-latest'
|
||||
|
@ -72,8 +323,10 @@ jobs:
|
|||
run: |
|
||||
sudo apt install libassimp-dev
|
||||
|
||||
- name: Configure Qtk
|
||||
shell: bash
|
||||
run: cmake -B build/ ${{ matrix.cmake }} -DQTK_CCACHE=OFF -DQTK_ASSIMP_NEW_INTERFACE=ON
|
||||
|
||||
- name: Build Qtk
|
||||
shell: bash
|
||||
run: |
|
||||
cmake -S . -B build/ ${{ matrix.cmake }} && cmake --build build/ \
|
||||
--target qtk-main
|
||||
run: cmake --build build/ --config Release
|
||||
|
|
|
@ -14,14 +14,15 @@ jobs:
|
|||
- name: Install Qt
|
||||
uses: jurplel/install-qt-action@v2
|
||||
with:
|
||||
version: '6.3.1'
|
||||
version: '6.5.0'
|
||||
|
||||
- name: Install Assimp Ubuntu
|
||||
run: sudo apt install libassimp-dev
|
||||
|
||||
- name: Build Qtk
|
||||
run: |
|
||||
cmake -B build -DQTK_UPDATE_SUBMODULES=OFF && cmake --build build
|
||||
cmake -B build -DQTK_SUBMODULES=OFF -DQTK_CCACHE=OFF -DQTK_PLUGINS=OFF -DQTK_GUI=ON
|
||||
cmake --build build --target qtk_gui -- -j $(nproc)
|
||||
|
||||
- uses: cpp-linter/cpp-linter-action@v2
|
||||
id: linter
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
# CLion
|
||||
**/.idea/**
|
||||
|
||||
# VS Code
|
||||
**/.vscode/**
|
||||
|
||||
# CMake build files
|
||||
**/cmake-build-debug/**
|
||||
**/build/**
|
||||
install
|
||||
|
||||
# C++ objects and libs
|
||||
*.slo
|
||||
|
|
345
CMakeLists.txt
|
@ -1,17 +1,14 @@
|
|||
################################################################################
|
||||
## Author: Shaun Reed | Contact: shaunrd0@gmail.com | URL: www.shaunreed.com ##
|
||||
## ##
|
||||
## Project for working with OpenGL and Qt6 widgets ##
|
||||
## ##
|
||||
## Author: Shaun Reed | Contact: shaunrd0@gmail.com | URL: www.shaunreed.com ##
|
||||
## All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
################################################################################
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
|
||||
project(
|
||||
#[[NAME]] Qtk
|
||||
VERSION 1.0
|
||||
DESCRIPTION "An example project using QT and OpenGL"
|
||||
LANGUAGES CXX C
|
||||
)
|
||||
cmake_minimum_required(VERSION 3.23)
|
||||
|
||||
################################################################################
|
||||
# Constants
|
||||
################################################################################
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
set(CMAKE_AUTOUIC ON)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
|
@ -19,221 +16,185 @@ set(CMAKE_AUTORCC ON)
|
|||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
set(CMAKE_MACOSX_BUNDLE ON)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
||||
if(WIN32)
|
||||
set(CMAKE_COMPILE_WARNING_AS_ERROR OFF)
|
||||
add_compile_options(/wd4131 /wd4127)
|
||||
endif()
|
||||
message(STATUS "[Qtk] Compiling with ${CMAKE_CXX_COMPILER_ID}")
|
||||
add_compile_options(-fPIC)
|
||||
|
||||
# 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}"
|
||||
################################################################################
|
||||
# Project
|
||||
################################################################################
|
||||
project(
|
||||
#[[NAME]] Qtk
|
||||
VERSION 0.2
|
||||
DESCRIPTION "Qt OpenGL library and desktop application."
|
||||
LANGUAGES CXX C
|
||||
)
|
||||
|
||||
################################################################################
|
||||
# External Libraries
|
||||
# Includes
|
||||
################################################################################
|
||||
include("${CMAKE_SOURCE_DIR}/cmake/include/git_submodule.cmake")
|
||||
include(CMakePackageConfigHelpers)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# For CLion builds, point CMAKE_PREFIX_PATH to Qt6 install directory
|
||||
# + QtCreator will handle this for you if that is used instead
|
||||
list(APPEND CMAKE_PREFIX_PATH "${QT_DIR}")
|
||||
################################################################################
|
||||
# Options
|
||||
################################################################################
|
||||
option(QTK_DEBUG "Enable debugger" OFF)
|
||||
option(QTK_SUBMODULES "Update external project (assimp) submodule" OFF)
|
||||
option(QTK_GUI "Build the Qtk desktop application" ON)
|
||||
option(QTK_PLUGINS "Install Qtk plugins to Qt Creator path." OFF)
|
||||
option(QTK_EXAMPLE "Build the Qtk example desktop application" ON)
|
||||
option(QTK_CCACHE "Enable ccache" ON)
|
||||
|
||||
if (QTK_CCACHE)
|
||||
set(CMAKE_CXX_COMPILER_LAUNCHER ccache)
|
||||
endif()
|
||||
|
||||
# Install Qtk for use within Qt Creator projects only, instead of system-wide.
|
||||
option(QTK_PREFIX_QTCREATOR "Install Qtk to Qt Creator. Untested." OFF)
|
||||
|
||||
# Option for bringing your own assimp installation; Otherwise not needed
|
||||
# + If assimp is available system-wide we can just set QTK_SUBMODULES OFF
|
||||
option(
|
||||
QTK_ASSIMP_NEW_INTERFACE
|
||||
"Use the assimp::assimp interface (WIN / OSX)"
|
||||
OFF
|
||||
)
|
||||
|
||||
if(QTK_DEBUG OR CMAKE_BUILD_TYPE MATCHES "^[Dd][Ee][Bb][Uu][Gg]$")
|
||||
set(QTK_DEBUG ON)
|
||||
set(CMAKE_BUILD_TYPE Debug)
|
||||
else()
|
||||
set(QTK_DEBUG OFF)
|
||||
set(CMAKE_BUILD_TYPE Release)
|
||||
endif()
|
||||
|
||||
# This should be set to your Qt6 installation directory.
|
||||
set(QT_INSTALL_DIR "$ENV{HOME}/Qt/6.5.0/gcc_64/lib/cmake" CACHE PATH "Path to Qt6 install.")
|
||||
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
|
||||
set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/install")
|
||||
endif ()
|
||||
|
||||
set(QTK_RESOURCES "${CMAKE_SOURCE_DIR}/resources")
|
||||
set(QTK_OSX_ICONS ${CMAKE_SOURCE_DIR}/resources/icons/osx/kilroy.icns)
|
||||
|
||||
# Point CMAKE_PREFIX_PATH to Qt6 install directory
|
||||
# If Qtk is built within Qt Creator this is not required.
|
||||
list(APPEND CMAKE_PREFIX_PATH "${QT_INSTALL_DIR}")
|
||||
if (QTK_PREFIX_QTCREATOR)
|
||||
# TODO: This might be a bit strange and needs more testing.
|
||||
set(CMAKE_INSTALL_PREFIX "${QT_INSTALL_DIR}")
|
||||
endif()
|
||||
|
||||
set(
|
||||
QT_CREATOR_DIR
|
||||
"${QT_INSTALL_DIR}/../../Tools/QtCreator"
|
||||
CACHE PATH "Qt Creator path used to install Qtk plugins for Qt Designer."
|
||||
)
|
||||
|
||||
# Print all QTK options and their values at the end of configuration.
|
||||
# We initialize this list here so that we can append to it as needed.
|
||||
# All variables in this list will be printed at the end of configuration.
|
||||
get_cmake_property(VAR_NAMES VARIABLES)
|
||||
list(FILTER VAR_NAMES INCLUDE REGEX "^[qQ][tT][kK]_.*$")
|
||||
list(SORT VAR_NAMES)
|
||||
|
||||
################################################################################
|
||||
# External Dependencies
|
||||
################################################################################
|
||||
# Find Qt
|
||||
find_package(Qt6 COMPONENTS OpenGLWidgets)
|
||||
find_package(Qt6 COMPONENTS Core UiPlugin OpenGLWidgets)
|
||||
qt_standard_project_setup()
|
||||
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 "
|
||||
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)
|
||||
#
|
||||
# To use custom plugins, set QT_PLUGIN_PATH environment variable before running designer
|
||||
# Or, we can install plugins to the designer for use across all projects.
|
||||
# Qt Creator on linux will look here for widget plugins in the integrated designer
|
||||
# /home/shaun/Qt/Tools/QtCreator/lib/Qt/lib
|
||||
# Qt Designer will use the following path on linux
|
||||
# /home/shaun/Qt/6.5.0/gcc_64/plugins/designer/
|
||||
# We can use this path after find_package(Qt6) to install our plugins on all systems
|
||||
# ${QT6_INSTALL_PREFIX}/${QT6_INSTALL_PLUGINS}/designer
|
||||
# And run designer at ${QT6_INSTALL_PREFIX}/bin/designer
|
||||
# Use cmake -DQTK_PLUGIN_INSTALL_DIR=/some/path to override this install path
|
||||
set(
|
||||
QTK_PLUGIN_INSTALL_DIR
|
||||
"${QT6_INSTALL_PREFIX}/${QT6_INSTALL_PLUGINS}/designer" CACHE PATH
|
||||
"Path to install Qtk plugin collection."
|
||||
)
|
||||
# See cmake configure output for values of these variables on your system
|
||||
set(
|
||||
VAR_PATHS
|
||||
CMAKE_PREFIX_PATH CMAKE_INSTALL_PREFIX QTK_PLUGIN_INSTALL_DIR QT6_INSTALL_PREFIX
|
||||
QT_INSTALL_DIR
|
||||
)
|
||||
# Add QT6_INSTALL_PLUGINS to VAR_NAMES so it is printed at end of configuration.
|
||||
list(APPEND VAR_NAMES QT6_INSTALL_PLUGINS)
|
||||
|
||||
# Find Assimp.
|
||||
if(QTK_SUBMODULES)
|
||||
# Required to statically link.
|
||||
add_compile_options(-fPIC)
|
||||
set(BUILD_SHARED_LIBS OFF CACHE STRING "Build static assimp libs" FORCE)
|
||||
set(ASSIMP_BUILD_ZLIB ON CACHE STRING "Build Zlib with assimp." FORCE)
|
||||
set(
|
||||
ASSIMP_INSTALL
|
||||
OFF CACHE STRING "Disable to use assimp as a submodule."
|
||||
FORCE
|
||||
)
|
||||
set(ASSIMP_NO_EXPORT ON CACHE STRING "Disable to export assimp." FORCE)
|
||||
set(ASSIMP_WARNINGS_AS_ERRORS OFF CACHE STRING "No warnings as errors." FORCE)
|
||||
set(ASSIMP_BUILD_TESTS OFF CACHE STRING "Do not build assimp tests." FORCE)
|
||||
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/")
|
||||
add_subdirectory(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/extern/assimp/assimp/"
|
||||
EXCLUDE_FROM_ALL
|
||||
)
|
||||
else()
|
||||
find_package(assimp REQUIRED)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
find_package(OpenGL REQUIRED)
|
||||
endif()
|
||||
|
||||
################################################################################
|
||||
# Qtk
|
||||
################################################################################
|
||||
add_subdirectory(src)
|
||||
|
||||
set(
|
||||
PUBLIC_HEADERS
|
||||
src/qtkwidget.h
|
||||
src/scene.h
|
||||
src/camera3d.h
|
||||
src/mesh.h
|
||||
src/meshrenderer.h
|
||||
src/model.h
|
||||
src/object.h
|
||||
src/skybox.h
|
||||
src/texture.h
|
||||
src/transform3D.h
|
||||
)
|
||||
|
||||
set(
|
||||
SOURCE_FILES
|
||||
src/qtkwidget.cpp
|
||||
src/scene.cpp
|
||||
src/camera3d.cpp
|
||||
src/input.cpp
|
||||
src/input.h
|
||||
src/mesh.cpp
|
||||
src/meshrenderer.cpp
|
||||
src/model.cpp
|
||||
src/object.cpp
|
||||
src/qtkapi.h
|
||||
src/skybox.cpp
|
||||
src/texture.cpp
|
||||
src/transform3D.cpp
|
||||
)
|
||||
|
||||
include(GenerateExportHeader)
|
||||
|
||||
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)
|
||||
if(QTK_EXAMPLE)
|
||||
# Create a namespaced alias for linking with qtk_library in the example.
|
||||
add_library(${PROJECT_NAME}::qtk_library ALIAS qtk_library)
|
||||
add_subdirectory(example-app EXCLUDE_FROM_ALL)
|
||||
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
|
||||
################################################################################
|
||||
|
||||
set(QTK_RESOURCES "${CMAKE_SOURCE_DIR}/resources")
|
||||
configure_file(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/qtkresources.h.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/src/qtkresources.h"
|
||||
@ONLY
|
||||
)
|
||||
|
||||
# Add our Qt resources.qrc file to our application
|
||||
set(
|
||||
QTK_APP_SOURCES
|
||||
app/main.cpp
|
||||
app/examplescene.cpp
|
||||
app/examplescene.h
|
||||
app/mainwindow.cpp
|
||||
app/mainwindow.h
|
||||
app/mainwindow.ui
|
||||
app/resourcemanager.h
|
||||
src/qtkresources.h.in
|
||||
)
|
||||
qt6_add_big_resources(QTK_APP_SOURCES resources.qrc)
|
||||
|
||||
qt_add_executable(qtk-main ${QTK_APP_SOURCES})
|
||||
target_include_directories(qtk-main PRIVATE src/ app/)
|
||||
|
||||
# Link qtk-main executable to main qtk-widget library
|
||||
target_link_libraries(qtk-main PUBLIC qtk-widget)
|
||||
|
||||
set_target_properties(
|
||||
qtk-main PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
|
||||
)
|
||||
install(
|
||||
TARGETS qtk-main
|
||||
BUNDLE DESTINATION .
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
)
|
||||
|
||||
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)
|
||||
# Print all QTK options and their values at the end of configuration. This also
|
||||
# prints any additional variables that we have added to VAR_NAMES and VAR_PATHS.
|
||||
foreach(VAR_NAME IN LISTS VAR_NAMES VAR_PATHS)
|
||||
if(VAR_NAME IN_LIST VAR_PATHS)
|
||||
# Print absolute if variable is path
|
||||
get_filename_component(VAR_REALPATH "${${VAR_NAME}}" REALPATH)
|
||||
message(STATUS "[Qtk] ${VAR_NAME}=${VAR_REALPATH}")
|
||||
else()
|
||||
message(STATUS "[Qtk] ${VAR_NAME}=${${VAR_NAME}}")
|
||||
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()
|
||||
endforeach()
|
||||
|
|
357
README.md
|
@ -1,92 +1,205 @@
|
|||
# Qtk
|
||||
|
||||
[![All Builds](https://github.com/shaunrd0/qtk/actions/workflows/all-builds.yml/badge.svg)](https://github.com/shaunrd0/qtk/actions/workflows/all-builds.yml)
|
||||
[![Linting](https://github.com/shaunrd0/qtk/actions/workflows/linting.yml/badge.svg)](https://github.com/shaunrd0/qtk/actions/workflows/linting.yml)
|
||||
|
||||
Model loader using [Assimp](https://assimp.org/) within a Qt widget application.
|
||||
Qtk is a Qt OpenGL graphics library created primarily for my own learning
|
||||
purposes. The library wraps some QOpenGL functionality in convenience classes
|
||||
that allow rendering geometry in 2D and 3D using custom GLSL shader programs.
|
||||
|
||||
You can import your own models within `app/examplescene.cpp`, inside the
|
||||
`ExampleScene::init()` function. Rotations and translations
|
||||
happen in `ExampleScene::update()`.
|
||||
The long-term goal for this project is to create a tool that I can use to
|
||||
practice shader coding or graphics programming techniques. In doing this I hope
|
||||
to also learn more about the Qt UI framework, and the CMake build system.
|
||||
|
||||
To get textures loading on models look into [material files](http://www.paulbourke.net/dataformats/mtl/)
|
||||
Key features that are planned:
|
||||
|
||||
* Runtime loading of `.obj` or similar 3D models.
|
||||
* Drag-and-drop interaction for adding objects to the scene.
|
||||
* Runtime reloading of modified GLSL shaders attached to objects within scenes.
|
||||
* Multiple views of a scene at one time.
|
||||
* Camera control modes such as panning, orbiting, or following objects.
|
||||
* Save / load for scene data. The current inheritance model is temporary.
|
||||
* Basic text editor for quickly modifying shaders attached to objects.
|
||||
* Shader / object properties panel to modify related settings.
|
||||
* Reduce size of application resources and git references.
|
||||
|
||||
The Qtk desktop application provides a model loader
|
||||
using [Assimp](https://assimp.org/) within a Qt widget application.
|
||||
|
||||
For examples of using the Qtk API, see the `example-app` project in the root of
|
||||
this repository.
|
||||
|
||||
To get textures loading on models look
|
||||
into [material files](http://www.paulbourke.net/dataformats/mtl/)
|
||||
and see some examples in the `resources/models/` directory.
|
||||
|
||||
The syntax for adding shapes and models is seen in the example below.
|
||||
This would result in a scene with a red cube and a miniature spartan model placed on top.
|
||||
|
||||
```C++
|
||||
// From: qtk/app/examplescene.cpp
|
||||
|
||||
void ExampleScene::init() {
|
||||
// Add a skybox to the scene using default cube map images and settings.
|
||||
setSkybox(new Qtk::Skybox("Skybox"));
|
||||
|
||||
/* Create a red cube with a mini master chief on top. */
|
||||
auto myCube = new MeshRenderer("My cube", Cube(Qtk::QTK_DRAW_ELEMENTS));
|
||||
myCube->setColor(RED);
|
||||
mMeshes.push_back(myCube);
|
||||
|
||||
auto mySpartan = new Model("My spartan", ":/models/spartan/spartan.obj");
|
||||
mySpartan->getTransform().setTranslation(0.0f, 0.5f, 0.0f);
|
||||
mySpartan->getTransform().setScale(0.5f);
|
||||
mModels.push_back(mySpartan);
|
||||
}
|
||||
```
|
||||
|
||||
If we want to make our spartan spin, we need to apply rotation in `update`
|
||||
|
||||
```C++
|
||||
// From: qtk/app/examplescene.cpp
|
||||
|
||||
void ExampleScene::update() {
|
||||
auto mySpartan = Model::getInstance("My spartan");
|
||||
mySpartan->getTransform().rotate(0.75f, 0.0f, 1.0f, 0.0f);
|
||||
|
||||
auto myCube = MeshRenderer::getInstance("My cube");
|
||||
myCube->getTransform().rotate(-0.75f, 0.0f, 1.0f, 0.0f);
|
||||
}
|
||||
```
|
||||
|
||||
### Source Builds
|
||||
|
||||
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.
|
||||
Qtk was developed and tested using CLion
|
||||
and [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.
|
||||
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.
|
||||
This project has been ported to **Qt 6.6.0**, 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, **version 6.6.0** or later.
|
||||
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
|
||||
If you are building on **Windows / Mac**, consider setting
|
||||
the `-DQTK_ASSIMP_NEW_INTERFACE` cmake build option.
|
||||
|
||||
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.
|
||||
If the build is configured with all options enabled, we can subsequently install
|
||||
individual components as needed with cmake.
|
||||
|
||||
```bash
|
||||
sudo apt update -y && sudo apt install freeglut3-dev libassimp-dev cmake build-essential git
|
||||
git clone https://gitlab.com/shaunrd0/qtk
|
||||
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
|
||||
# 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
|
||||
```
|
||||
sudo apt update -y && sudo apt install libassimp-dev cmake build-essential git ccache libgl1-mesa-dev libglvnd-dev zlib1g-dev -y
|
||||
git clone https://github.com/shaunrd0/qtk
|
||||
cd qtk
|
||||
# Configure the build with all components enabled
|
||||
cmake -B build-all -DQTK_GUI=ON -DQTK_PLUGINS=ON -DQTK_EXAMPLE=ON -DCMAKE_PREFIX_PATH=$HOME/Qt/6.6.0/gcc_64
|
||||
# Build all targets
|
||||
cmake --build build-all/
|
||||
````
|
||||
|
||||
#### Windows / MacOS
|
||||
By default, the build will not initialize Assimp as a git submodule and build
|
||||
from source.
|
||||
We can turn this on by setting the `-DQTK_SUBMODULES=ON` flag when running
|
||||
CMake.
|
||||
Building using this option will fetch and build Assimp for us, but builds will
|
||||
take longer as a result.
|
||||
Using `-DQTK_SUBMODULES=ON` supports providing assimp on cross-platform builds (
|
||||
Windows / Mac / Linux) and may be easier
|
||||
to configure.
|
||||
|
||||
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
|
||||
cmake -B build-all -DQTK_GUI=ON -DQTK_PLUGINS=ON -DQTK_EXAMPLE=ON -DQTK_SUBMODULES=ON -DCMAKE_PREFIX_PATH=$HOME/Qt/6.6.0/gcc_64
|
||||
```
|
||||
|
||||
#### Qtk GUI
|
||||
|
||||
```bash
|
||||
cmake --build build-all/ --target qtk_gui -- -j $(nproc)
|
||||
# Install Qtk desktop application (output removed)
|
||||
# Installation prefix path must be absolute, since Qtk uses Qt deploy tools.
|
||||
cmake --install build-all/ --component qtk_gui --prefix=$(pwd)/install
|
||||
./install/bin/qtk_gui
|
||||
```
|
||||
|
||||
If any errors are encountered loading plugins, we can debug plugin loading by
|
||||
setting the following environment variable -
|
||||
|
||||
```bash
|
||||
QT_DEBUG_PLUGINS=1 ./install/bin/qtk_gui
|
||||
```
|
||||
|
||||
#### Qtk Library
|
||||
|
||||
Qtk provides a simple library for working with QOpenGL.
|
||||
We can install this library on a system path or a custom path and then
|
||||
set `CMAKE_PREFIX_PATH` to point to this location when building an application
|
||||
using libqtk.
|
||||
|
||||
```bash
|
||||
# Install libqtk only
|
||||
cmake --build build-all/ --target qtk_library -- -j $(nproc)
|
||||
cmake --install build-all/ --component qtk_library --prefix=/usr/local
|
||||
-- Install configuration: "Release"
|
||||
-- Installing: /usr/local/lib/cmake/Qtk/QtkConfig.cmake
|
||||
-- Installing: /usr/local/lib/cmake/Qtk/QtkConfigVersion.cmake
|
||||
-- Installing: /usr/local/lib/cmake/Qtk/QtkTargets.cmake
|
||||
-- Installing: /usr/local/lib/cmake/Qtk/QtkTargets-release.cmake
|
||||
-- Installing: /usr/local/lib/static/libqtk_library.a
|
||||
-- Installing: /usr/local/include/qtk/camera3d.h
|
||||
-- Installing: /usr/local/include/qtk/input.h
|
||||
-- Installing: /usr/local/include/qtk/meshrenderer.h
|
||||
-- Installing: /usr/local/include/qtk/model.h
|
||||
-- Installing: /usr/local/include/qtk/modelmesh.h
|
||||
-- Installing: /usr/local/include/qtk/object.h
|
||||
-- Installing: /usr/local/include/qtk/qtkapi.h
|
||||
-- Installing: /usr/local/include/qtk/qtkiostream.h
|
||||
-- Installing: /usr/local/include/qtk/qtkiosystem.h
|
||||
-- Installing: /usr/local/include/qtk/scene.h
|
||||
-- Installing: /usr/local/include/qtk/shape.h
|
||||
-- Installing: /usr/local/include/qtk/skybox.h
|
||||
-- Installing: /usr/local/include/qtk/texture.h
|
||||
-- Installing: /usr/local/include/qtk/transform3D.h
|
||||
```
|
||||
|
||||
#### Qtk Plugin Collection
|
||||
|
||||
This project defines a collection of widget plugins for use with Qt Designer.
|
||||
These plugins were used to build the interface for the Qtk desktop application.
|
||||
Qt Designer will list Qtk widgets in the side panel when editing a UI file
|
||||
within the designer.
|
||||
Qtk widgets will also render and behave correctly within the UI preview in
|
||||
designer.
|
||||
The widgets in the Qtk collection were created by implementing
|
||||
the [QDesignerCustomWidgetInterface](https://doc.qt.io/qt-6/qdesignercustomwidgetinterface.html#details)
|
||||
and [QDesignerCustomWidgetCollectionInterface](https://doc.qt.io/qt-6/qdesignercustomwidgetcollectioninterface.html)
|
||||
interfaces.
|
||||
|
||||
To build and install the Qtk plugin collection -
|
||||
|
||||
```bash
|
||||
cmake --build build-all/ --target qtk_plugins -- -j $(nproc)
|
||||
# Install Qtk widget collection to use Qt Designer
|
||||
# The path here should be initialized during build configuration, so no need for --prefix
|
||||
cmake --install build-all/ --component qtk_plugins
|
||||
-- Install configuration: "Release"
|
||||
-- Up-to-date: /home/shaun/Qt/6.6.0/gcc_64/../../Tools/QtCreator/lib/Qt/lib/libqtk_library.a
|
||||
-- Up-to-date: /home/shaun/Qt/6.6.0/gcc_64/../../Tools/QtCreator/lib/Qt/lib/libqtk_plugin_library.a
|
||||
-- Up-to-date: /home/shaun/Qt/6.6.0/gcc_64/../../Tools/QtCreator/lib/Qt/plugins/designer/libqtk_collection.so
|
||||
```
|
||||
|
||||
To uninstall after a previous installation, we can run the following command
|
||||
from the root of the repository.
|
||||
|
||||
```bash
|
||||
xargs rm < build/install_manifest.txt
|
||||
```
|
||||
|
||||
#### Qtk Example
|
||||
|
||||
There is a simple example of using libqtk in the [example-app/](example-app)
|
||||
directory. The example can be built standalone using `find_package` or as a
|
||||
target within any qtk build.
|
||||
|
||||
```bash
|
||||
# Build the example from a configured qtk build tree
|
||||
cmake --build build-all/ --target qtk_example -- -j $(nproc)
|
||||
cmake --install build-all/ --component qtk_example --prefix=install
|
||||
./install/bin/qtk_example
|
||||
```
|
||||
|
||||
See the README in the [example-app/](example-app) subdirectory for instructions
|
||||
on standalone builds.
|
||||
|
||||
### Controls
|
||||
|
||||
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
|
||||
that is being used for the shader rendering the model. These appear on models
|
||||
using phong, specular, and diffuse lighting techniques.
|
||||
|
||||
Object names can be double-clicked in the tree view panel for quick camera
|
||||
navigation. All panels and toolbars are dockable widgets that can be popped out
|
||||
and reorganized as needed. Panels can be stacked to create a docked widget with
|
||||
tabs. The central widget that provides the camera view into the scene cannot be
|
||||
detached from the main window in this way. See the `View` menu to enable debug
|
||||
console widgets for open scenes or reopen previously closed panels.
|
||||
|
||||
![](resources/screenshot.png)
|
||||
|
||||
Spartan with no normals -
|
||||
|
||||
![](resources/spartan-specular.png)
|
||||
|
||||
Spartan with normals -
|
||||
|
||||
![](resources/spartan-normals.png)
|
||||
|
||||
#### Development
|
||||
|
||||
|
@ -101,7 +214,9 @@ cmake --build build -j $(nproc --ignore=2)
|
|||
sudo cmake --build build -j $(nproc --ignore=2) --target install
|
||||
```
|
||||
|
||||
If this version is any earlier than `15.0.0`, running `clang-format` will fail because this project uses configuration options made available since `15.0.0`.
|
||||
If the `clang-format` 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
|
||||
|
@ -109,7 +224,8 @@ clang-format version 15.0.5 (git@github.com:llvm/llvm-project.git 154e88af7ec97d
|
|||
```
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
|
@ -117,7 +233,7 @@ If you're using CLion, the `.clang-format` configuration will be picked up by CL
|
|||
# Move to the root of the repo
|
||||
cd qtk
|
||||
# Build
|
||||
cmake -B build && cmake --build build
|
||||
cmake -B build && cmake --build build -- -j $(nproc)
|
||||
clang-tidy -p build/ --fix --config-file=.clang-tidy src/*.cpp src/*.h app/*.cpp app/*.h
|
||||
```
|
||||
|
||||
|
@ -125,7 +241,7 @@ Last we need to run `clang-format`, this can be done with the command directly.
|
|||
This will reformat all the code in the repository.
|
||||
|
||||
```bash
|
||||
clang-format -i --style=file:.clang-format src/*.cpp src/*.h app/*.cpp app/*.h
|
||||
clang-format -i --style=file:.clang-format src/app/*.cpp src/app/*.h src/qtk/*.cpp src/qtk/*.h example-app/*.cpp example-app/*.h
|
||||
```
|
||||
|
||||
`clang-format` can be run with git integration (or CLion if you prefer).
|
||||
|
@ -146,57 +262,86 @@ changed files:
|
|||
src/transform3D.h
|
||||
```
|
||||
|
||||
### Controls
|
||||
##### Packaging
|
||||
|
||||
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
|
||||
that is being used for the shader rendering the model. These appear on models
|
||||
using phong, specular, and diffuse lighting techniques.
|
||||
Packaging for Qtk is in early development.
|
||||
This section documents how to package Qtk, but only source builds have been
|
||||
verified on Windows / Mac / Linux.
|
||||
For this reason, it is recommended to install Qtk by strictly building from
|
||||
source at this time.
|
||||
|
||||
![](resources/screenshot.png)
|
||||
Below are the steps to package a Qtk release.
|
||||
|
||||
Spartan with no normals -
|
||||
```bash
|
||||
cd /path/to/qtk && cmake -B build
|
||||
# Package Qtk
|
||||
cmake --build build --target package
|
||||
# Package Qtk including source files
|
||||
cmake --build build --target package_source
|
||||
```
|
||||
|
||||
![](resources/spartan-specular.png)
|
||||
Alternatively, we can use `cpack` directly -
|
||||
|
||||
Spartan with normals -
|
||||
```bash
|
||||
cd /path/to/qtk && cmake -B build
|
||||
# Generate all install packages
|
||||
cpack -C Release
|
||||
# Generate a specific archive package (ZIP)
|
||||
cpack -C Release -G ZIP
|
||||
# Generate a specific archive package (TGZ)
|
||||
cpack -C Release -G TGZ
|
||||
# Generate debian package (DEB)
|
||||
cpack -C Release -G DEB
|
||||
# Generate NSIS install package (NSIS)
|
||||
cpack -C Release -G NSIS
|
||||
```
|
||||
|
||||
![](resources/spartan-normals.png)
|
||||
Any of the above options can be appended with `--trace-expand` to debug package
|
||||
generation issues.
|
||||
The contents of all packages will depend on how the build was configured.
|
||||
|
||||
To generate packages for Qtk desktop application, we should
|
||||
set `-DQTK_GUI=ON`. If this option is not set we will only package libqtk.
|
||||
|
||||
### QtkWidget in Qt Creator
|
||||
The NSIS installer will allow component-specific path modification for all of
|
||||
these installation components through a GUI install application.
|
||||
|
||||
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
|
||||
|
||||
![](resources/qtk-views.png)
|
||||
Some useful links and resources that I have found while working on this project.
|
||||
|
||||
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.
|
||||
[Qt Designer UI file format](https://doc.qt.io/qt-6/designer-ui-file-format.html)
|
||||
|
||||
![](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.
|
||||
[QtPlugin Import / Export plugins](https://doc.qt.io/qt-6/qtplugin.html)
|
||||
|
||||
[KDAB](https://www.kdab.com/)
|
||||
|
||||
## 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/).
|
||||
|
||||
"Scythe World Of Warcraft" (https://skfb.ly/6UooG) by Warcraft-3D-Models is licensed under Creative Commons Attribution (http://creativecommons.org/licenses/by/4.0/).
|
||||
"Scythe World Of Warcraft" (https://skfb.ly/6UooG) by Warcraft-3D-Models is
|
||||
licensed under Creative Commons
|
||||
Attribution (http://creativecommons.org/licenses/by/4.0/).
|
||||
|
||||
"Spartan Armour MKV - Halo Reach" (https://skfb.ly/6QVvM) by McCarthy3D is licensed under Creative Commons Attribution (http://creativecommons.org/licenses/by/4.0/).
|
||||
"Spartan Armour MKV - Halo Reach" (https://skfb.ly/6QVvM) by McCarthy3D is
|
||||
licensed under Creative Commons
|
||||
Attribution (http://creativecommons.org/licenses/by/4.0/).
|
||||
|
||||
"Survival Guitar Backpack (Low Poly)" (https://skfb.ly/6RnCB) by Berk Gedik is licensed under Creative Commons Attribution (http://creativecommons.org/licenses/by/4.0/).
|
||||
Model by Berk Gedik, from: https://sketchfab.com/3d-models/survival-guitar-backpack-low-poly-799f8c4511f84fab8c3f12887f7e6b36
|
||||
Modified (learnopengl.com) material assignment (Joey de Vries) for easier load in OpenGL model loading chapter, and renamed albedo to diffuse and metallic to specular to match non-PBR lighting setup.
|
||||
"Survival Guitar Backpack (Low Poly)" (https://skfb.ly/6RnCB) by Berk Gedik is
|
||||
licensed under Creative Commons
|
||||
Attribution (http://creativecommons.org/licenses/by/4.0/).
|
||||
Model by Berk Gedik,
|
||||
from: https://sketchfab.com/3d-models/survival-guitar-backpack-low-poly-799f8c4511f84fab8c3f12887f7e6b36
|
||||
Modified (learnopengl.com) material assignment (Joey de Vries) for easier load
|
||||
in OpenGL model loading chapter, and renamed albedo to diffuse and metallic to
|
||||
specular to match non-PBR lighting setup.
|
||||
|
||||
"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/).
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
|
||||
## About: MainWindow for creating an example Qt application ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
|
||||
#include <mainwindow.h>
|
||||
#include <qtkwidget.h>
|
||||
#include "ui_mainwindow.h"
|
||||
|
||||
MainWindow::MainWindow(QWidget * parent) :
|
||||
QMainWindow(parent), ui(new Ui::MainWindow) {
|
||||
// For use in design mode using Qt Creator
|
||||
// + We can use the `ui` member to access nested widgets by name
|
||||
ui->setupUi(this);
|
||||
|
||||
// Find all QtkWidgets in this QMainWindow and initialize their scenes.
|
||||
for(const auto widget : ui->qWidget->children()) {
|
||||
auto qtkWidget = dynamic_cast<Qtk::QtkWidget *>(widget);
|
||||
if(qtkWidget != nullptr) {
|
||||
std::string key = qtkWidget->objectName().toStdString();
|
||||
// Initialize each scene into a map if it doesn't exist.
|
||||
if(mScenes[key] == nullptr) {
|
||||
mScenes[key] = new ExampleScene();
|
||||
}
|
||||
// Set the QtkWidget to use the scene associated with this widget.
|
||||
qtkWidget->setScene(mScenes[key]);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the window icon used for Qtk.
|
||||
// TODO: Update this to be something other than kilroy.
|
||||
setWindowIcon(QIcon("../resources/icon.png"));
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow() {
|
||||
delete ui;
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
|
||||
## About: MainWindow for creating an example Qt application ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include <QMainWindow>
|
||||
|
||||
#include <examplescene.h>
|
||||
#include "qtk-widget_export.h"
|
||||
|
||||
namespace Ui {
|
||||
class MainWindow;
|
||||
}
|
||||
|
||||
/**
|
||||
* MainWindow class to provide an example of using a QtkWidget within a Qt
|
||||
* window application.
|
||||
*/
|
||||
class QTK_WIDGET_EXPORT MainWindow : public QMainWindow {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/***************************************************************************
|
||||
* Contructors / Destructors
|
||||
**************************************************************************/
|
||||
|
||||
/**
|
||||
* This ctor also initializes the Scene for each QtkWidget in the window.
|
||||
* To load a different scene this would need to be updated.
|
||||
*
|
||||
* @param parent The parent for this QMainWindow
|
||||
*/
|
||||
explicit MainWindow(QWidget * parent = nullptr);
|
||||
~MainWindow() override;
|
||||
|
||||
private:
|
||||
/***************************************************************************
|
||||
* Private Members
|
||||
**************************************************************************/
|
||||
|
||||
Ui::MainWindow * ui {};
|
||||
std::unordered_map<std::string, Qtk::Scene *> mScenes {};
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
|
@ -1,114 +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="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>
|
|
@ -1,48 +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>
|
||||
|
||||
#include <src/qtkresources.h>
|
||||
|
||||
#ifndef QTK_RESOURCEMANAGER_H
|
||||
#define QTK_RESOURCEMANAGER_H
|
||||
|
||||
/**
|
||||
* ResourceManager class used to construct absolute paths to files within the Qt
|
||||
* resources path. There is no need to manually call this method.
|
||||
* Model::loadModel(...) will use this method if a Qt resource path is provided.
|
||||
* The Model constructor behaves the same. If a path is prefixed with `:/` this
|
||||
* static method will be used to resolve a full system path.
|
||||
*
|
||||
* This will likely be deprecated. It has a single call site and it is not
|
||||
* meant for public use. It is public only for convenience.
|
||||
*
|
||||
* RM::getPath(":/models/alien-hominid/alien.obj") =
|
||||
* /full/path/to/models/alien-hominid/alien.obj
|
||||
*/
|
||||
typedef class ResourceManager {
|
||||
public:
|
||||
/**
|
||||
* 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 Absolute system path to a qtk asset
|
||||
*/
|
||||
static std::string getPath(const std::string & path) {
|
||||
// Only construct qtk resource path if in qrc format; else return it as-is
|
||||
return path[0] == ':' ? QTK_RESOURCES + path.substr(1) : path;
|
||||
}
|
||||
} RM;
|
||||
|
||||
#endif // QTK_RESOURCEMANAGER_H
|
|
@ -10,7 +10,7 @@ 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)
|
||||
if (NOT QTK_SUBMODULES)
|
||||
return()
|
||||
endif()
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
@PACKAGE_INIT@
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/QtkTargets.cmake")
|
||||
|
||||
set_and_check(QTK_EXECUTABLE "${PACKAGE_PREFIX_DIR}/bin/qtk_gui")
|
||||
set_and_check(QTK_INCLUDE_DIR "${PACKAGE_PREFIX_DIR}/include")
|
||||
set_and_check(QTK_LIBRARIES "${PACKAGE_PREFIX_DIR}/lib")
|
||||
|
||||
set_and_check(Qtk_EXECUTABLE "${PACKAGE_PREFIX_DIR}/bin/qtk_gui")
|
||||
set_and_check(Qtk_INCLUDE_DIR "${PACKAGE_PREFIX_DIR}/include")
|
||||
set_and_check(Qtk_LIBRARIES "${PACKAGE_PREFIX_DIR}/lib")
|
||||
|
||||
check_required_components(Qtk)
|
|
@ -0,0 +1,96 @@
|
|||
################################################################################
|
||||
## Example client project using qtk ##
|
||||
## ##
|
||||
## Author: Shaun Reed | Contact: shaunrd0@gmail.com | URL: www.shaunreed.com ##
|
||||
## All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
################################################################################
|
||||
cmake_minimum_required(VERSION 3.23)
|
||||
|
||||
################################################################################
|
||||
# Constants
|
||||
################################################################################
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
||||
add_compile_options(/wd4131 /wd4127)
|
||||
endif()
|
||||
|
||||
# If you did not install Qtk on a system path, point cmake to installation.
|
||||
set(
|
||||
QTK_PATH ../build/install/lib/cmake/Qtk
|
||||
CACHE PATH "Path to installation of Qtk"
|
||||
FORCE
|
||||
)
|
||||
|
||||
# If you did not install Qt6 on a system path, point cmake to installation.
|
||||
set(QT_INSTALL_DIR "$ENV{HOME}/Qt/6.5.0/gcc_64/" CACHE PATH "Path to Qt6")
|
||||
|
||||
################################################################################
|
||||
# Project
|
||||
################################################################################
|
||||
project(
|
||||
#[[NAME]] QtkClient
|
||||
VERSION 0.1
|
||||
DESCRIPTION "An example project using Qtk"
|
||||
LANGUAGES CXX C
|
||||
)
|
||||
|
||||
list(APPEND CMAKE_PREFIX_PATH "${QTK_PATH}")
|
||||
list(APPEND CMAKE_PREFIX_PATH "${QT_INSTALL_DIR}")
|
||||
|
||||
# Print all QTK variables
|
||||
if (NOT Qtk_IS_TOP_LEVEL)
|
||||
get_cmake_property(VAR_NAMES VARIABLES)
|
||||
list(FILTER VAR_NAMES INCLUDE REGEX "^Q[tT][kK]_.*$")
|
||||
list(SORT VAR_NAMES)
|
||||
foreach(VAR_NAME ${VAR_NAMES})
|
||||
message(STATUS "[Qtk] ${VAR_NAME}=${${VAR_NAME}}")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# Allow add_subdirectory on this project to use target ALIAS if available.
|
||||
# If this example project is opened standalone we will use find_package.
|
||||
if(NOT TARGET Qtk::qtk_library)
|
||||
find_package(Qtk 0.2 REQUIRED)
|
||||
endif()
|
||||
|
||||
find_package(Qt6 COMPONENTS Core Widgets OpenGLWidgets REQUIRED)
|
||||
|
||||
set(
|
||||
EXAMPLE_SOURCES
|
||||
main.cpp
|
||||
examplescene.cpp examplescene.h
|
||||
examplewidget.cpp examplewidget.h
|
||||
)
|
||||
|
||||
configure_file(
|
||||
#[[INPUT]] "${CMAKE_CURRENT_SOURCE_DIR}/resources.h.in"
|
||||
#[[OUTPUT]] "${CMAKE_CURRENT_BINARY_DIR}/resources.h"
|
||||
@ONLY
|
||||
)
|
||||
|
||||
qt_add_executable(qtk_example ${EXAMPLE_SOURCES})
|
||||
target_link_libraries(qtk_example PUBLIC Qt6::Widgets Qt6::OpenGLWidgets Qt6::Core)
|
||||
target_link_libraries(qtk_example PUBLIC Qtk::qtk_library)
|
||||
target_include_directories(qtk_example PRIVATE "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
|
||||
install(
|
||||
TARGETS qtk_example
|
||||
COMPONENT qtk_example
|
||||
BUNDLE DESTINATION .
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib/static
|
||||
RUNTIME DESTINATION bin
|
||||
)
|
||||
qt_generate_deploy_app_script(
|
||||
TARGET qtk_example
|
||||
OUTPUT_SCRIPT QTK_EXAMPLE_DEPLOY_SCRIPT
|
||||
NO_UNSUPPORTED_PLATFORM_ERROR
|
||||
)
|
||||
install(SCRIPT ${QTK_EXAMPLE_DEPLOY_SCRIPT} COMPONENT qtk_example)
|
|
@ -0,0 +1,73 @@
|
|||
This is an example application that is using the Qtk API to create custom Qt
|
||||
OpenGL widgets. This is very similar to `QtkWidget` in the Qtk desktop
|
||||
application source code, but could be modified for different uses if needed.
|
||||
|
||||
There are no camera controls supported in this example. The camera is fixed.
|
||||
If these controls are desired, they can be implemented by the client.
|
||||
|
||||
You can import your own models within `examplescene.cpp`, inside the
|
||||
`ExampleScene::init()` function. Rotations and translations
|
||||
are applied in `ExampleScene::update()`.
|
||||
|
||||
The syntax for adding shapes and models is seen in the example below.
|
||||
This would result in a scene with a red cube and a miniature spartan model
|
||||
placed on top.
|
||||
|
||||
```C++
|
||||
void ExampleScene::init() {
|
||||
// Add a skybox to the scene using default cube map images and settings.
|
||||
setSkybox(new Qtk::Skybox("Skybox"));
|
||||
|
||||
/* Create a red cube with a mini master chief on top. */
|
||||
auto myCube = new MeshRenderer("My cube", Cube(Qtk::QTK_DRAW_ELEMENTS));
|
||||
myCube->setColor(RED);
|
||||
mMeshes.push_back(myCube);
|
||||
|
||||
auto mySpartan = new Model("My spartan", "/path/to/spartan/spartan.obj");
|
||||
mySpartan->getTransform().setTranslation(0.0f, 0.5f, 0.0f);
|
||||
mySpartan->getTransform().setScale(0.5f);
|
||||
mModels.push_back(mySpartan);
|
||||
}
|
||||
```
|
||||
|
||||
If we want to make our spartan spin, we need to apply rotation in `update`
|
||||
|
||||
```C++
|
||||
void ExampleScene::update() {
|
||||
auto mySpartan = Model::getInstance("My spartan");
|
||||
mySpartan->getTransform().rotate(0.75f, 0.0f, 1.0f, 0.0f);
|
||||
|
||||
auto myCube = MeshRenderer::getInstance("My cube");
|
||||
myCube->getTransform().rotate(-0.75f, 0.0f, 1.0f, 0.0f);
|
||||
}
|
||||
```
|
||||
|
||||
Other examples can be found in the source files for this example project.
|
||||
|
||||
## Build Instructions
|
||||
|
||||
Currently, this application requires manual build and installation of Qtk.
|
||||
In the future, once a release is published, I will be able to use `FetchContent`
|
||||
or similar cmake functionality to remove this requirement.
|
||||
|
||||
For Qtk build instructions, see the README in the root of this repository.
|
||||
|
||||
```bash
|
||||
cmake -S /path/to/qtk/example-app/ -B /path/to/qtk/example-app/build
|
||||
cmake --build /path/to/qtk/example-app/build
|
||||
```
|
||||
|
||||
If Qtk was not installed system-wide, we can set `QTK_PATH` to point to the
|
||||
custom installation directory.
|
||||
|
||||
```bash
|
||||
cmake -S /path/to/qtk/example-app/ -B /path/to/qtk/example-app/build -DQTK_PATH=/path/to/qtk/install/
|
||||
cmake --build /path/to/qtk/example-app/build --target qtk_example -- -j $(nproc)
|
||||
cmake --install build/ --component qtk_example
|
||||
```
|
||||
|
||||
After this, we can run the example application -
|
||||
|
||||
```bash
|
||||
./path/to/qtk/example-app/build/install/bin/example
|
||||
```
|
|
@ -0,0 +1,97 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Example Qtk scene ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
|
||||
#include "examplescene.h"
|
||||
#include <resources.h>
|
||||
|
||||
using namespace Qtk;
|
||||
|
||||
ExampleScene::ExampleScene(Qtk::Scene * scene) : Qtk::SceneInterface(scene) {
|
||||
setSceneName("Example Scene");
|
||||
getCamera().getTransform().setTranslation(-8.0f, 0.0f, 10.0f);
|
||||
getCamera().getTransform().setRotation(-5.0f, 0.0f, 1.0f, 0.0f);
|
||||
}
|
||||
|
||||
ExampleScene::~ExampleScene() {}
|
||||
|
||||
void ExampleScene::init() {
|
||||
auto skybox = new Qtk::Skybox("Skybox");
|
||||
setSkybox(skybox);
|
||||
|
||||
std::string spartanPath = QTK_EXAMPLE_SOURCE_DIR;
|
||||
spartanPath += "/resources/models/spartan/spartan.obj";
|
||||
auto spartan = new Model("spartan", spartanPath.c_str());
|
||||
addObject(spartan);
|
||||
spartan->getTransform().setTranslation(-4.0f, 0.0f, 0.0f);
|
||||
|
||||
auto mesh = addObject(
|
||||
new Qtk::MeshRenderer("rightTriangle", Triangle(QTK_DRAW_ARRAYS)));
|
||||
mesh->getTransform().setTranslation(-5.0f, 0.0f, -2.0f);
|
||||
|
||||
// QTK_DRAW_ARRAYS is the default for generic shapes in qtk/shape.h
|
||||
addObject(new Qtk::MeshRenderer("centerCube", Cube(QTK_DRAW_ARRAYS)))
|
||||
->getTransform()
|
||||
.setTranslation(-7.0f, 0.0f, -2.0f);
|
||||
|
||||
mesh = addObject(
|
||||
new Qtk::MeshRenderer("leftTriangle", Triangle(QTK_DRAW_ELEMENTS)));
|
||||
mesh->getTransform().setTranslation(-9.0f, 0.0f, -2.0f);
|
||||
mesh->setDrawType(GL_LINE_LOOP);
|
||||
|
||||
mesh = addObject(
|
||||
new Qtk::MeshRenderer("topTriangle", Triangle(QTK_DRAW_ELEMENTS)));
|
||||
mesh->getTransform().setTranslation(-7.0f, 2.0f, -2.0f);
|
||||
mesh->getTransform().scale(0.25f);
|
||||
|
||||
mesh = addObject(
|
||||
new Qtk::MeshRenderer("bottomTriangle", Triangle(QTK_DRAW_ELEMENTS)));
|
||||
mesh->getTransform().setTranslation(-7.0f, -2.0f, -2.0f);
|
||||
mesh->getTransform().scale(0.25f);
|
||||
mesh->setDrawType(GL_LINE_LOOP);
|
||||
mesh->setColor(GREEN);
|
||||
}
|
||||
|
||||
void ExampleScene::draw() {
|
||||
Scene::draw();
|
||||
}
|
||||
|
||||
void ExampleScene::update() {
|
||||
// Pitch forward and roll sideways
|
||||
MeshRenderer::getInstance("leftTriangle")
|
||||
->getTransform()
|
||||
.rotate(0.75f, 1.0f, 0.0f, 0.0f);
|
||||
MeshRenderer::getInstance("rightTriangle")
|
||||
->getTransform()
|
||||
.rotate(0.75f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
static float translateX = 0.025f;
|
||||
float limit = -9.0f; // Origin position.x - 2.0f
|
||||
float posX = MeshRenderer::getInstance("topTriangle")
|
||||
->getTransform()
|
||||
.getTranslation()
|
||||
.x();
|
||||
if(posX < limit || posX > limit + 4.0f) {
|
||||
translateX = -translateX;
|
||||
}
|
||||
MeshRenderer::getInstance("topTriangle")
|
||||
->getTransform()
|
||||
.translate(translateX, 0.0f, 0.0f);
|
||||
MeshRenderer::getInstance("bottomTriangle")
|
||||
->getTransform()
|
||||
.translate(-translateX, 0.0f, 0.0f);
|
||||
MeshRenderer::getInstance("topTriangle")
|
||||
->getTransform()
|
||||
.rotate(0.75f, 0.2f, 0.0f, 0.4f);
|
||||
MeshRenderer::getInstance("bottomTriangle")
|
||||
->getTransform()
|
||||
.rotate(0.75f, 0.0f, 0.2f, 0.4f);
|
||||
|
||||
MeshRenderer::getInstance("centerCube")
|
||||
->getTransform()
|
||||
.rotate(0.75f, 0.2f, 0.4f, 0.6f);
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Example Qtk scene ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
|
||||
#ifndef QTK_EXAMPLE_SCENE_H
|
||||
#define QTK_EXAMPLE_SCENE_H
|
||||
|
||||
#include <qtk/scene.h>
|
||||
|
||||
class ExampleScene : public Qtk::SceneInterface {
|
||||
public:
|
||||
ExampleScene(Qtk::Scene * scene);
|
||||
|
||||
~ExampleScene();
|
||||
|
||||
void init() override;
|
||||
|
||||
void draw() override;
|
||||
|
||||
void update() override;
|
||||
};
|
||||
|
||||
#endif // QTK_EXAMPLE_SCENE_H
|
|
@ -0,0 +1,57 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Example Qtk widget ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
|
||||
#include <qtk/scene.h>
|
||||
|
||||
#include "examplewidget.h"
|
||||
|
||||
ExampleWidget::ExampleWidget(QWidget * parent) :
|
||||
QOpenGLWidget(parent), mScene(new ExampleScene(new Qtk::SceneEmpty)) {
|
||||
// NOTE: The decorator pattern is used to save / load scenes in Qtk currently.
|
||||
// The initializer above sets mScene to the concrete decorator ExampleScene.
|
||||
// Qtk::SceneEmpty provides an empty scene as the concrete component.
|
||||
// ExampleScene is defined in client source, deriving Qtk::SceneInterface.
|
||||
|
||||
QSurfaceFormat format;
|
||||
format.setRenderableType(QSurfaceFormat::OpenGL);
|
||||
format.setProfile(QSurfaceFormat::CoreProfile);
|
||||
format.setVersion(4, 6);
|
||||
format.setSamples(4);
|
||||
format.setDepthBufferSize(16);
|
||||
setFormat(format);
|
||||
setFocusPolicy(Qt::ClickFocus);
|
||||
}
|
||||
|
||||
void ExampleWidget::initializeGL() {
|
||||
initializeOpenGLFunctions();
|
||||
connect(this, SIGNAL(frameSwapped()), this, SLOT(update()));
|
||||
glEnable(GL_MULTISAMPLE);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthMask(GL_TRUE);
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
glDepthRange(0.1f, 1.0f);
|
||||
glClearDepth(1.0f);
|
||||
glClearColor(0.0f, 0.25f, 0.0f, 0.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
void ExampleWidget::resizeGL(int width, int height) {
|
||||
Qtk::Scene::getProjectionMatrix().setToIdentity();
|
||||
Qtk::Scene::getProjectionMatrix().perspective(
|
||||
45.0f, float(width) / float(height), 0.1f, 1000.0f);
|
||||
}
|
||||
|
||||
void ExampleWidget::paintGL() {
|
||||
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
|
||||
mScene->draw();
|
||||
}
|
||||
|
||||
void ExampleWidget::update() {
|
||||
mScene->update();
|
||||
QWidget::update();
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Example Qtk widget ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
|
||||
#ifndef QTKCLIENT_EXAMPLEWIDGET_H
|
||||
#define QTKCLIENT_EXAMPLEWIDGET_H
|
||||
|
||||
#include <QOpenGLFunctions>
|
||||
#include <QOpenGLWidget>
|
||||
|
||||
#include "examplescene.h"
|
||||
|
||||
class ExampleWidget : public QOpenGLWidget, protected QOpenGLFunctions {
|
||||
Q_OBJECT;
|
||||
|
||||
public:
|
||||
explicit ExampleWidget(QWidget * parent = nullptr);
|
||||
|
||||
~ExampleWidget() = default;
|
||||
|
||||
void initializeGL() override;
|
||||
|
||||
void resizeGL(int width, int height) override;
|
||||
|
||||
void paintGL() override;
|
||||
|
||||
protected slots:
|
||||
void update();
|
||||
|
||||
private:
|
||||
Qtk::Scene * mScene;
|
||||
};
|
||||
|
||||
#endif // QTKCLIENT_EXAMPLEWIDGET_H
|
|
@ -1,23 +1,22 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
|
||||
## About: Main window for Qt6 OpenGL widget application ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Example Qt desktop application using Qtk ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
#ifndef QTK_QTKAPI_H
|
||||
#define QTK_QTKAPI_H
|
||||
|
||||
#include <QtCore/QtGlobal>
|
||||
#include <QApplication>
|
||||
#include <QMainWindow>
|
||||
|
||||
#ifdef QTK_SHARED
|
||||
#if defined(QTK_EXPORT)
|
||||
#define QTKAPI Q_DECL_EXPORT
|
||||
#else
|
||||
#define QTKAPI Q_DECL_IMPORT
|
||||
#endif
|
||||
#else
|
||||
#define QTKAPI
|
||||
#endif
|
||||
#include "examplewidget.h"
|
||||
|
||||
#endif // QTK_QTKAPI_H
|
||||
int main(int argc, char * argv[]) {
|
||||
QApplication app(argc, argv);
|
||||
|
||||
auto window = new QMainWindow;
|
||||
window->setCentralWidget(new ExampleWidget);
|
||||
window->show();
|
||||
|
||||
app.exec();
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef QTK_RESOURCES_H_IN_H
|
||||
#define QTK_RESOURCES_H_IN_H
|
||||
|
||||
#define QTK_EXAMPLE_SOURCE_DIR "@CMAKE_SOURCE_DIR@"
|
||||
|
||||
#endif // QTK_RESOURCES_H_IN_H
|
|
@ -1 +1 @@
|
|||
Subproject commit bd64cc88dff17f118ecf32ebcbacaf566f6b6449
|
||||
Subproject commit 5d5496f1ad895297cede723b3c96b513263f82ed
|
|
@ -1,81 +0,0 @@
|
|||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<!--3DModel test shader-->
|
||||
<file alias="model.frag">resources/shaders/fragment/model.frag</file>
|
||||
<file alias="model.vert">resources/shaders/vertex/model.vert</file>
|
||||
<!--Phong test shader-->
|
||||
<file alias="phong.frag">resources/shaders/fragment/phong.frag</file>
|
||||
<file alias="phong.vert">resources/shaders/vertex/phong.vert</file>
|
||||
|
||||
|
||||
<!--Simple Solid Shader-->
|
||||
<file alias="solid.frag">resources/shaders/fragment/solid.frag</file>
|
||||
<file alias="solid.vert">resources/shaders/vertex/solid.vert</file>
|
||||
|
||||
<!--Solid Color Shader-->
|
||||
<file alias="solid-perspective.frag">resources/shaders/fragment/solid-perspective.frag</file>
|
||||
<file alias="solid-perspective.vert">resources/shaders/vertex/solid-perspective.vert</file>
|
||||
|
||||
<!--Multi-color Shader-->
|
||||
<file alias="multi-color.frag">resources/shaders/fragment/multi-color.frag</file>
|
||||
<file alias="multi-color.vert">resources/shaders/vertex/multi-color.vert</file>
|
||||
|
||||
<!--RGB Normals Shader-->
|
||||
<file alias="rgb-normals.frag">resources/shaders/fragment/rgb-normals.frag</file>
|
||||
<file alias="rgb-normals.vert">resources/shaders/vertex/rgb-normals.vert</file>
|
||||
|
||||
<!--CubeMap Texture Shader-->
|
||||
<file alias="texture-cubemap.frag">resources/shaders/fragment/texture-cubemap.frag</file>
|
||||
<file alias="texture-cubemap.vert">resources/shaders/vertex/texture-cubemap.vert</file>
|
||||
|
||||
<!--2D Texture Shader-->
|
||||
<file alias="texture2d.frag">resources/shaders/fragment/texture2d.frag</file>
|
||||
<file alias="texture2d.vert">resources/shaders/vertex/texture2d.vert</file>
|
||||
|
||||
|
||||
<!--Ambient Shader-->
|
||||
<file alias="solid-ambient.frag">resources/shaders/fragment/solid-ambient.frag</file>
|
||||
<file alias="solid-ambient.vert">resources/shaders/vertex/solid-ambient.vert</file>
|
||||
<!--Diffuse Shader-->
|
||||
<file alias="solid-diffuse.frag">resources/shaders/fragment/solid-diffuse.frag</file>
|
||||
<file alias="solid-diffuse.vert">resources/shaders/vertex/solid-diffuse.vert</file>
|
||||
<!--Specular Shader-->
|
||||
<file alias="solid-specular.frag">resources/shaders/fragment/solid-specular.frag</file>
|
||||
<file alias="solid-specular.vert">resources/shaders/vertex/solid-specular.vert</file>
|
||||
<!--Basic Phong Shader-->
|
||||
<file alias="solid-phong.frag">resources/shaders/fragment/solid-phong.frag</file>
|
||||
<file alias="solid-phong.vert">resources/shaders/vertex/solid-phong.vert</file>
|
||||
|
||||
|
||||
<!--3DModel Basic Shader-->
|
||||
<file alias="model-basic.frag">resources/shaders/fragment/model-basic.frag</file>
|
||||
<file alias="model-basic.vert">resources/shaders/vertex/model-basic.vert</file>
|
||||
|
||||
<!--3DModel shader with specular mapping-->
|
||||
<file alias="model-specular.frag">resources/shaders/fragment/model-specular.frag</file>
|
||||
<file alias="model-specular.vert">resources/shaders/vertex/model-specular.vert</file>
|
||||
|
||||
<!--3DModel shader with normal mapping-->
|
||||
<file alias="model-normals.frag">resources/shaders/fragment/model-normals.frag</file>
|
||||
<file alias="model-normals.vert">resources/shaders/vertex/model-normals.vert</file>
|
||||
|
||||
|
||||
|
||||
<!-- Skybox Shaders-->
|
||||
<file alias="skybox.frag">resources/skybox/skybox.frag</file>
|
||||
<file alias="skybox.vert">resources/skybox/skybox.vert</file>
|
||||
|
||||
|
||||
<!--Texture Images-->
|
||||
<file alias="crate.png">resources/images/crate.png</file>
|
||||
<file alias="stone.png">resources/images/stone.png</file>
|
||||
<file alias="wood.png">resources/images/wood.png</file>
|
||||
<!-- Skybox Images-->
|
||||
<file alias="back.png">resources/skybox/back.png</file>
|
||||
<file alias="bottom.png">resources/skybox/bottom.png</file>
|
||||
<file alias="front.png">resources/skybox/front.png</file>
|
||||
<file alias="left.png">resources/skybox/left.png</file>
|
||||
<file alias="right.png">resources/skybox/right.png</file>
|
||||
<file alias="top.png">resources/skybox/top.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
|
@ -0,0 +1,165 @@
|
|||
Fonticons, Inc. (https://fontawesome.com)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Font Awesome Free License
|
||||
|
||||
Font Awesome Free is free, open source, and GPL friendly. You can use it for
|
||||
commercial projects, open source projects, or really almost whatever you want.
|
||||
Full Font Awesome Free license: https://fontawesome.com/license/free.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
# Icons: CC BY 4.0 License (https://creativecommons.org/licenses/by/4.0/)
|
||||
|
||||
The Font Awesome Free download is licensed under a Creative Commons
|
||||
Attribution 4.0 International License and applies to all icons packaged
|
||||
as SVG and JS file types.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
# Fonts: SIL OFL 1.1 License
|
||||
|
||||
In the Font Awesome Free download, the SIL OFL license applies to all icons
|
||||
packaged as web and desktop font files.
|
||||
|
||||
Copyright (c) 2022 Fonticons, Inc. (https://fontawesome.com)
|
||||
with Reserved Font Name: "Font Awesome".
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
SIL OPEN FONT LICENSE
|
||||
Version 1.1 - 26 February 2007
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting — in part or in whole — any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
# Code: MIT License (https://opensource.org/licenses/MIT)
|
||||
|
||||
In the Font Awesome Free download, the MIT license applies to all non-font and
|
||||
non-icon files.
|
||||
|
||||
Copyright 2022 Fonticons, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without limitation the rights to use, copy,
|
||||
modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so, subject to the
|
||||
following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
# Attribution
|
||||
|
||||
Attribution is required by MIT, SIL OFL, and CC BY licenses. Downloaded Font
|
||||
Awesome Free files already contain embedded comments with sufficient
|
||||
attribution, so you shouldn't need to do anything additional when using these
|
||||
files normally.
|
||||
|
||||
We've kept attribution comments terse, so we ask that you do not actively work
|
||||
to remove them from files, especially code. They're a great way for folks to
|
||||
learn about Font Awesome.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
# Brand Icons
|
||||
|
||||
All brand icons are trademarks of their respective owners. The use of these
|
||||
trademarks does not indicate endorsement of the trademark holder by Font
|
||||
Awesome, nor vice versa. **Please do not use brand logos for any purpose except
|
||||
to represent the company, product, or service to which they refer.**
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M439.55 236.05L244 40.45a28.87 28.87 0 0 0-40.81 0l-40.66 40.63 51.52 51.52c27.06-9.14 52.68 16.77 43.39 43.68l49.66 49.66c34.23-11.8 61.18 31 35.47 56.69-26.49 26.49-70.21-2.87-56-37.34L240.22 199v121.85c25.3 12.54 22.26 41.85 9.08 55a34.34 34.34 0 0 1-48.55 0c-17.57-17.6-11.07-46.91 11.25-56v-123c-20.8-8.51-24.6-30.74-18.64-45L142.57 101 8.45 235.14a28.86 28.86 0 0 0 0 40.81l195.61 195.6a28.86 28.86 0 0 0 40.8 0l194.69-194.69a28.86 28.86 0 0 0 0-40.81z"/></svg>
|
After Width: | Height: | Size: 749 B |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M224 256c-35.2 0-64 28.8-64 64c0 35.2 28.8 64 64 64c35.2 0 64-28.8 64-64C288 284.8 259.2 256 224 256zM433.1 129.1l-83.9-83.9C341.1 37.06 328.8 32 316.1 32H64C28.65 32 0 60.65 0 96v320c0 35.35 28.65 64 64 64h320c35.35 0 64-28.65 64-64V163.9C448 151.2 442.9 138.9 433.1 129.1zM128 80h144V160H128V80zM400 416c0 8.836-7.164 16-16 16H64c-8.836 0-16-7.164-16-16V96c0-8.838 7.164-16 16-16h16v104c0 13.25 10.75 24 24 24h192C309.3 208 320 197.3 320 184V83.88l78.25 78.25C399.4 163.2 400 164.8 400 166.3V416z"/></svg>
|
After Width: | Height: | Size: 789 B |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Free 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M572.6 270.3l-96 192C471.2 473.2 460.1 480 447.1 480H64c-35.35 0-64-28.66-64-64V96c0-35.34 28.65-64 64-64h117.5c16.97 0 33.25 6.742 45.26 18.75L275.9 96H416c35.35 0 64 28.66 64 64v32h-48V160c0-8.824-7.178-16-16-16H256L192.8 84.69C189.8 81.66 185.8 80 181.5 80H64C55.18 80 48 87.18 48 96v288l71.16-142.3C124.6 230.8 135.7 224 147.8 224h396.2C567.7 224 583.2 249 572.6 270.3z"/></svg>
|
After Width: | Height: | Size: 664 B |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M160 400C160 408.8 152.8 416 144 416C135.2 416 128 408.8 128 400V192C128 183.2 135.2 176 144 176C152.8 176 160 183.2 160 192V400zM240 400C240 408.8 232.8 416 224 416C215.2 416 208 408.8 208 400V192C208 183.2 215.2 176 224 176C232.8 176 240 183.2 240 192V400zM320 400C320 408.8 312.8 416 304 416C295.2 416 288 408.8 288 400V192C288 183.2 295.2 176 304 176C312.8 176 320 183.2 320 192V400zM317.5 24.94L354.2 80H424C437.3 80 448 90.75 448 104C448 117.3 437.3 128 424 128H416V432C416 476.2 380.2 512 336 512H112C67.82 512 32 476.2 32 432V128H24C10.75 128 0 117.3 0 104C0 90.75 10.75 80 24 80H93.82L130.5 24.94C140.9 9.357 158.4 0 177.1 0H270.9C289.6 0 307.1 9.358 317.5 24.94H317.5zM151.5 80H296.5L277.5 51.56C276 49.34 273.5 48 270.9 48H177.1C174.5 48 171.1 49.34 170.5 51.56L151.5 80zM80 432C80 449.7 94.33 464 112 464H336C353.7 464 368 449.7 368 432V128H80V432z"/></svg>
|
After Width: | Height: | Size: 1.1 KiB |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M234.5 5.7c13.9-5 29.1-5 43.1 0l192 68.6C495 83.4 512 107.5 512 134.6V377.4c0 27-17 51.2-42.5 60.3l-192 68.6c-13.9 5-29.1 5-43.1 0l-192-68.6C17 428.6 0 404.5 0 377.4V134.6c0-27 17-51.2 42.5-60.3l192-68.6zM256 66L82.3 128 256 190l173.7-62L256 66zm32 368.6l160-57.1v-188L288 246.6v188z"/></svg>
|
After Width: | Height: | Size: 574 B |
|
@ -0,0 +1,13 @@
|
|||
|
||||
```bash
|
||||
sudo apt install icnsutils
|
||||
```
|
||||
|
||||
```bash
|
||||
convert icon.png -resize 32x32 kilroy_32.png
|
||||
convert icon.png -resize 16x16 kilroy_16.png
|
||||
convert icon.png -resize 48x48 kilroy_48.png
|
||||
convert icon.png -resize 128x128 kilroy_128.png
|
||||
convert icon.png -resize 256x256 kilroy_256.png
|
||||
png2icns png2icns kilroy.icns kilroy_*.png
|
||||
```
|
After Width: | Height: | Size: 7.4 KiB |
After Width: | Height: | Size: 512 B |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 869 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 3.8 MiB |
|
@ -1,5 +1,5 @@
|
|||
# Created by RapidCompact v4.3.2 | www.rapidcompact.com
|
||||
mtllib rapid.mtl
|
||||
mtllib bird.mtl
|
||||
o mesh_0
|
||||
v 290.631131412626928068 748.484123578408002686 -224.342122210487644907
|
||||
v 282.356783853739386814 751.945844816198814442 -222.136356657249308455
|
||||
|
|
Before Width: | Height: | Size: 1.1 MiB |
Before Width: | Height: | Size: 254 KiB |
|
@ -1,16 +0,0 @@
|
|||
# Blender MTL File: 'None'
|
||||
# Material Count: 1
|
||||
|
||||
newmtl Lion
|
||||
Ns 500.000001
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.800000 0.800000 0.800000
|
||||
Ks 0.800000 0.800000 0.800000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.450000
|
||||
d 1.000000
|
||||
illum 2
|
||||
map_Bump normal.jpg
|
||||
map_Kd diffuse.jpg
|
||||
map_Ns roughness.jpg
|
||||
refl specular.jpg
|
Before Width: | Height: | Size: 484 KiB |
Before Width: | Height: | Size: 562 KiB |
Before Width: | Height: | Size: 134 KiB |
|
@ -0,0 +1,131 @@
|
|||
<RCC>
|
||||
<qresource prefix="/textures">
|
||||
<file alias="plaster.png">images/plaster.png</file>
|
||||
<file alias="crate.png">images/crate.png</file>
|
||||
<file alias="stone.png">images/stone.png</file>
|
||||
<file alias="wood.png">images/wood.png</file>
|
||||
<file>skybox/back.png</file>
|
||||
<file>skybox/bottom.png</file>
|
||||
<file>skybox/front.png</file>
|
||||
<file>skybox/left.png</file>
|
||||
<file>skybox/right.png</file>
|
||||
<file>skybox/top.png</file>
|
||||
</qresource>
|
||||
<qresource prefix="/icons">
|
||||
<file>fontawesome-free-6.2.1-desktop/svgs/solid/cube.svg</file>
|
||||
<file>fontawesome-free-6.2.1-desktop/svgs/regular/trash-can.svg</file>
|
||||
<file>fontawesome-free-6.2.1-desktop/svgs/regular/folder-open.svg</file>
|
||||
<file>fontawesome-free-6.2.1-desktop/svgs/regular/floppy-disk.svg</file>
|
||||
<file>fontawesome-free-6.2.1-desktop/svgs/brands/git-alt.svg</file>
|
||||
<file>icon.png</file>
|
||||
</qresource>
|
||||
<qresource prefix="/shaders">
|
||||
<file alias="model.frag">shaders/fragment/model.frag</file>
|
||||
<file alias="model.vert">shaders/vertex/model.vert</file>
|
||||
<file alias="phong.frag">shaders/fragment/phong.frag</file>
|
||||
<file alias="phong.vert">shaders/vertex/phong.vert</file>
|
||||
<file alias="solid.frag">shaders/fragment/solid.frag</file>
|
||||
<file alias="solid.vert">shaders/vertex/solid.vert</file>
|
||||
<file alias="solid-perspective.frag">shaders/fragment/solid-perspective.frag</file>
|
||||
<file alias="solid-perspective.vert">shaders/vertex/solid-perspective.vert</file>
|
||||
<file alias="multi-color.frag">shaders/fragment/multi-color.frag</file>
|
||||
<file alias="multi-color.vert">shaders/vertex/multi-color.vert</file>
|
||||
<file alias="rgb-normals.frag">shaders/fragment/rgb-normals.frag</file>
|
||||
<file alias="rgb-normals.vert">shaders/vertex/rgb-normals.vert</file>
|
||||
<file alias="texture-cubemap.frag">shaders/fragment/texture-cubemap.frag</file>
|
||||
<file alias="texture-cubemap.vert">shaders/vertex/texture-cubemap.vert</file>
|
||||
<file alias="texture2d.frag">shaders/fragment/texture2d.frag</file>
|
||||
<file alias="texture2d.vert">shaders/vertex/texture2d.vert</file>
|
||||
<file alias="solid-ambient.frag">shaders/fragment/solid-ambient.frag</file>
|
||||
<file alias="solid-ambient.vert">shaders/vertex/solid-ambient.vert</file>
|
||||
<file alias="solid-diffuse.frag">shaders/fragment/solid-diffuse.frag</file>
|
||||
<file alias="solid-diffuse.vert">shaders/vertex/solid-diffuse.vert</file>
|
||||
<file alias="solid-specular.frag">shaders/fragment/solid-specular.frag</file>
|
||||
<file alias="solid-specular.vert">shaders/vertex/solid-specular.vert</file>
|
||||
<file alias="solid-phong.frag">shaders/fragment/solid-phong.frag</file>
|
||||
<file alias="solid-phong.vert">shaders/vertex/solid-phong.vert</file>
|
||||
<file alias="model-basic.frag">shaders/fragment/model-basic.frag</file>
|
||||
<file alias="model-basic.vert">shaders/vertex/model-basic.vert</file>
|
||||
<file alias="model-specular.frag">shaders/fragment/model-specular.frag</file>
|
||||
<file alias="model-specular.vert">shaders/vertex/model-specular.vert</file>
|
||||
<file alias="model-normals.frag">shaders/fragment/model-normals.frag</file>
|
||||
<file alias="model-normals.vert">shaders/vertex/model-normals.vert</file>
|
||||
<file alias="skybox.frag">skybox/skybox.frag</file>
|
||||
<file alias="skybox.vert">skybox/skybox.vert</file>
|
||||
</qresource>
|
||||
<qresource prefix="/models">
|
||||
<file>models/spartan/spartan.obj</file>
|
||||
<file>models/alien-hominid/alien.obj</file>
|
||||
<file>models/spartan/spartan.mtl</file>
|
||||
<file>models/spartan/Spartan_Ears_Mat_BaseColor.png</file>
|
||||
<file>models/spartan/Spartan_Undersuit_Mat_Specular.png</file>
|
||||
<file>models/spartan/Spartan_Undersuit_Mat_Roughness.png</file>
|
||||
<file>models/spartan/Spartan_Undersuit_Mat_Normal.png</file>
|
||||
<file>models/spartan/Spartan_Undersuit_Mat_Metallic.png</file>
|
||||
<file>models/spartan/Spartan_Undersuit_Mat_BaseColor.png</file>
|
||||
<file>models/spartan/Spartan_Undersuit_Mat_AO.png</file>
|
||||
<file>models/spartan/Spartan_Shoulder_Mat_Specular.png</file>
|
||||
<file>models/spartan/Spartan_Shoulder_Mat_Roughness.png</file>
|
||||
<file>models/spartan/Spartan_Shoulder_Mat_Normal.png</file>
|
||||
<file>models/spartan/Spartan_Shoulder_Mat_Metallic.png</file>
|
||||
<file>models/spartan/Spartan_Shoulder_Mat_BaseColor.png</file>
|
||||
<file>models/spartan/Spartan_Shoulder_Mat_AO.png</file>
|
||||
<file>models/spartan/Spartan_Legs_Mat_Specular.png</file>
|
||||
<file>models/spartan/Spartan_Legs_Mat_Roughness.png</file>
|
||||
<file>models/spartan/Spartan_Legs_Mat_Normal.png</file>
|
||||
<file>models/spartan/Spartan_Legs_Mat_Metallic.png</file>
|
||||
<file>models/spartan/Spartan_Legs_Mat_BaseColor.png</file>
|
||||
<file>models/spartan/Spartan_Legs_Mat_AO.png</file>
|
||||
<file>models/spartan/Spartan_Helmet_Mat_Specular.png</file>
|
||||
<file>models/spartan/Spartan_Helmet_Mat_Roughness.png</file>
|
||||
<file>models/spartan/Spartan_Helmet_Mat_Normal.png</file>
|
||||
<file>models/spartan/Spartan_Helmet_Mat_Metallic.png</file>
|
||||
<file>models/spartan/Spartan_Helmet_Mat_BaseColor.png</file>
|
||||
<file>models/spartan/Spartan_Helmet_Mat_AO.png</file>
|
||||
<file>models/spartan/Spartan_Ears_Mat_Specular.png</file>
|
||||
<file>models/spartan/Spartan_Ears_Mat_Roughness.png</file>
|
||||
<file>models/spartan/Spartan_Ears_Mat_Normal.png</file>
|
||||
<file>models/spartan/Spartan_Ears_Mat_Metallic.png</file>
|
||||
<file>models/spartan/Spartan_Ears_Mat_AO.png</file>
|
||||
<file>models/spartan/Spartan_Chest_Mat_Specular.png</file>
|
||||
<file>models/spartan/Spartan_Chest_Mat_Roughness.png</file>
|
||||
<file>models/spartan/Spartan_Chest_Mat_Normal.png</file>
|
||||
<file>models/spartan/Spartan_Chest_Mat_Metallic.png</file>
|
||||
<file>models/spartan/Spartan_Chest_Mat_BaseColor.png</file>
|
||||
<file>models/spartan/Spartan_Chest_Mat_AO.png</file>
|
||||
<file>models/spartan/Spartan_Arms_Mat_Specular.png</file>
|
||||
<file>models/spartan/Spartan_Arms_Mat_Roughness.png</file>
|
||||
<file>models/spartan/Spartan_Arms_Mat_Normal.png</file>
|
||||
<file>models/spartan/Spartan_Arms_Mat_Metallic.png</file>
|
||||
<file>models/spartan/Spartan_Arms_Mat_BaseColor.png</file>
|
||||
<file>models/spartan/Spartan_Arms_Mat_AO.png</file>
|
||||
<file>models/spartan/lambert1_Roughness.png</file>
|
||||
<file>models/spartan/lambert1_Nrm.png</file>
|
||||
<file>models/spartan/lambert1_Colour-Opacity.png</file>
|
||||
<file>models/backpack/specular.jpg</file>
|
||||
<file>models/backpack/roughness.jpg</file>
|
||||
<file>models/backpack/diffuse.jpg</file>
|
||||
<file>models/backpack/normal.png</file>
|
||||
<file>models/backpack/backpack.obj</file>
|
||||
<file>models/backpack/backpack.mtl</file>
|
||||
<file>models/backpack/ao.jpg</file>
|
||||
<file>models/alien-hominid/specular.png</file>
|
||||
<file>models/alien-hominid/roughness.png</file>
|
||||
<file>models/alien-hominid/normal.png</file>
|
||||
<file>models/alien-hominid/diffuse.png</file>
|
||||
<file>models/alien-hominid/blaster_specular.png</file>
|
||||
<file>models/alien-hominid/blaster_roughness.png</file>
|
||||
<file>models/alien-hominid/blaster_normal.png</file>
|
||||
<file>models/alien-hominid/blaster_emissive.png</file>
|
||||
<file>models/alien-hominid/blaster_diffuse.png</file>
|
||||
<file>models/alien-hominid/alien.mtl</file>
|
||||
<file>models/scythe/scythe.obj</file>
|
||||
<file>models/scythe/scythe.mtl</file>
|
||||
<file>models/scythe/diffuse.png</file>
|
||||
<file>models/bird/occlusion.jpg</file>
|
||||
<file>models/bird/normal.jpg</file>
|
||||
<file>models/bird/diffuse.jpg</file>
|
||||
<file>models/bird/bird.obj</file>
|
||||
<file>models/bird/bird.mtl</file>
|
||||
</qresource>
|
||||
</RCC>
|
Before Width: | Height: | Size: 406 KiB After Width: | Height: | Size: 316 KiB |
|
@ -0,0 +1,157 @@
|
|||
################################################################################
|
||||
## Project for working with OpenGL and Qt6 widgets ##
|
||||
## ##
|
||||
## Author: Shaun Reed | Contact: shaunrd0@gmail.com | URL: www.shaunreed.com ##
|
||||
## All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
################################################################################
|
||||
|
||||
# Qtk Library
|
||||
|
||||
# We always build libqtk since the plugins and GUI both depend on it.
|
||||
add_subdirectory(qtk)
|
||||
install(
|
||||
FILES
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
|
||||
COMPONENT qtk_library
|
||||
DESTINATION lib/cmake/${PROJECT_NAME}
|
||||
)
|
||||
install(
|
||||
EXPORT qtk_export
|
||||
FILE ${PROJECT_NAME}Targets.cmake
|
||||
NAMESPACE ${PROJECT_NAME}::
|
||||
COMPONENT qtk_library
|
||||
DESTINATION lib/cmake/${PROJECT_NAME}
|
||||
)
|
||||
# System install for qtk_library
|
||||
install(
|
||||
TARGETS qtk_library
|
||||
# Associate qtk_library target with qtk-export
|
||||
EXPORT qtk_export
|
||||
COMPONENT qtk_library
|
||||
FILE_SET HEADERS DESTINATION include
|
||||
INCLUDES DESTINATION include
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib
|
||||
RUNTIME DESTINATION bin
|
||||
)
|
||||
|
||||
# Qtk Application
|
||||
if(QTK_GUI OR QTK_PLUGINS)
|
||||
add_subdirectory(app)
|
||||
endif()
|
||||
|
||||
if(QTK_PLUGINS)
|
||||
install(
|
||||
TARGETS qtk_plugins qtk_library qtk_plugin_library
|
||||
COMPONENT qtk_plugins
|
||||
LIBRARY DESTINATION "${QTK_PLUGIN_INSTALL_DIR}"
|
||||
ARCHIVE DESTINATION "${QTK_PLUGIN_INSTALL_DIR}"
|
||||
RUNTIME DESTINATION "${QTK_PLUGIN_INSTALL_DIR}"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(QTK_GUI)
|
||||
install(
|
||||
TARGETS qtk_gui
|
||||
COMPONENT qtk_gui
|
||||
BUNDLE DESTINATION .
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib
|
||||
RUNTIME DESTINATION bin
|
||||
)
|
||||
|
||||
qt_generate_deploy_app_script(
|
||||
TARGET qtk_gui
|
||||
OUTPUT_SCRIPT QTK_DEPLOY_SCRIPT
|
||||
NO_UNSUPPORTED_PLATFORM_ERROR
|
||||
)
|
||||
install(SCRIPT ${QTK_DEPLOY_SCRIPT} COMPONENT qtk_gui)
|
||||
|
||||
if(WIN32)
|
||||
if(MSVC AND TARGET Qt6::qmake)
|
||||
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)
|
||||
|
||||
set(VSUSER_FILE "${CMAKE_CURRENT_BINARY_DIR}/qtk_gui.vcxproj.user")
|
||||
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};$(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()
|
||||
endif()
|
||||
|
||||
write_basic_package_version_file(
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
|
||||
COMPATIBILITY AnyNewerVersion
|
||||
)
|
||||
configure_package_config_file(
|
||||
"${CMAKE_SOURCE_DIR}/cmake/templates/Config.cmake.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
|
||||
INSTALL_DESTINATION lib/cmake/${PROJECT_NAME}
|
||||
)
|
||||
|
||||
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE")
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}")
|
||||
set(CPACK_PACKAGE_VERSION_MINOR "${PROJECT_VERSION_MINOR}")
|
||||
set(CPACK_PACKAGE_VENDOR "Shaun Reed")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Qt OpenGL 3D graphics library.")
|
||||
set(CPACK_PACKAGE_HOMEPAGE_URL "https://github.com/shaunrd0/qtk")
|
||||
set(CPACK_SOURCE_IGNORE_FILES build*;install;\.git;\.github;\.idea)
|
||||
set(CPACK_PACKAGE_DIRECTORY packages/)
|
||||
set(CPACK_PACKAGE_CONTACT "shaunreed.com")
|
||||
#set(CPACK_PACKAGE_ICON "${CMAKE_SOURCE_DIR}/resources/icon.png")
|
||||
set(CPACK_THREADS 0)
|
||||
set(CPACK_PACKAGE_INSTALL_DIRECTORY "Qtk")
|
||||
|
||||
# Remove any assimp components if defined by submodule.
|
||||
if (QTK_SUBMODULES)
|
||||
get_cmake_property(CPACK_COMPONENTS_ALL COMPONENTS)
|
||||
list(FILTER CPACK_COMPONENTS_ALL EXCLUDE REGEX .*assimp.*)
|
||||
list(REMOVE_ITEM CPACK_COMPONENTS_ALL Unspecified)
|
||||
endif()
|
||||
|
||||
# Windows
|
||||
set(CPACK_NSIS_MODIFY_PATH ON)
|
||||
set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL ON)
|
||||
# https://nsis.sourceforge.io/Reference/CreateShortCut
|
||||
set(
|
||||
CPACK_NSIS_CREATE_ICONS_EXTRA
|
||||
"CreateShortCut '$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Qtk.lnk' '$INSTDIR\\\\bin\\\\qtk_gui.exe'"
|
||||
)
|
||||
set(
|
||||
CPACK_NSIS_DELETE_ICONS_EXTRA
|
||||
"Delete '$SMPROGRAMS\\\\$START_MENU\\\\Qtk.lnk'"
|
||||
)
|
||||
# TODO: Icons for NSIS installer.
|
||||
#set(CPACK_NSIS_MUI_ICON "${CMAKE_SOURCE_DIR}/resources/icon.png")
|
||||
#set(CPACK_NSIS_MUI_UNIICON "${CMAKE_SOURCE_DIR}/resources/icon.png")
|
||||
|
||||
# Debian
|
||||
set(CPACK_DEBIAN_PACKAGE_HOMEPAGE ${CPACK_PACKAGE_HOMEPAGE_URL})
|
||||
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
|
||||
|
||||
# OSX
|
||||
set(CPACK_BUNDLE_NAME ${PROJECT_NAME})
|
||||
set(CPACK_BUNDLE_PLIST $<TARGET_BUNDLE_CONTENT_DIR:qtk_gui>/Info.plist)
|
||||
set(CPACK_BUNDLE_ICON ${QTK_OSX_ICONS})
|
||||
|
||||
# Platform defaults for source bundles.
|
||||
if(WIN32)
|
||||
set(CPACK_SOURCE_GENERATOR ZIP)
|
||||
else()
|
||||
set(CPACK_SOURCE_GENERATOR TGZ)
|
||||
endif()
|
||||
|
||||
include(CPack)
|
|
@ -0,0 +1,71 @@
|
|||
################################################################################
|
||||
## Project for working with OpenGL and Qt6 widgets ##
|
||||
## ##
|
||||
## Author: Shaun Reed | Contact: shaunrd0@gmail.com | URL: www.shaunreed.com ##
|
||||
## All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
################################################################################
|
||||
|
||||
################################################################################
|
||||
# Qtk Widget Library
|
||||
################################################################################
|
||||
# Create a library of widgets used to build Qtk GUI
|
||||
set(
|
||||
QTK_PLUGIN_LIBRARY_SOURCES
|
||||
qtkwidget.cpp
|
||||
debugconsole.cpp debugconsole.ui
|
||||
toolbox.cpp toolbox.ui
|
||||
treeview.cpp treeview.ui
|
||||
qtkmainwindow.cpp qtkmainwindow.h qtkmainwindow.ui
|
||||
)
|
||||
set(
|
||||
QTK_PLUGIN_LIBRARY_HEADERS
|
||||
qtkwidget.h
|
||||
debugconsole.h
|
||||
toolbox.h
|
||||
treeview.h
|
||||
)
|
||||
qt_add_library(qtk_plugin_library STATIC EXCLUDE_FROM_ALL)
|
||||
target_sources(
|
||||
qtk_plugin_library PRIVATE
|
||||
"${QTK_PLUGIN_LIBRARY_SOURCES}"
|
||||
"${QTK_PLUGIN_LIBRARY_HEADERS}"
|
||||
)
|
||||
target_link_libraries(qtk_plugin_library PUBLIC Qt6::UiPlugin qtk_library)
|
||||
|
||||
################################################################################
|
||||
# Qtk Widget Plugins
|
||||
################################################################################
|
||||
# Create a Qt Designer plugin for a collection of widgets from our library.
|
||||
qt_add_plugin(qtk_plugins SHARED)
|
||||
target_sources(
|
||||
qtk_plugins PRIVATE
|
||||
widgetplugincollection.cpp widgetplugincollection.h
|
||||
widgetplugin.cpp widgetplugin.h
|
||||
)
|
||||
target_link_libraries(qtk_plugins PUBLIC qtk_plugin_library)
|
||||
|
||||
################################################################################
|
||||
# Final Qtk Application
|
||||
################################################################################
|
||||
|
||||
set(
|
||||
QTK_GUI_SOURCES
|
||||
qtkscene.cpp qtkscene.h
|
||||
main.cpp
|
||||
)
|
||||
|
||||
qt_add_executable(qtk_gui ${QTK_GUI_SOURCES})
|
||||
target_link_libraries(qtk_gui PRIVATE qtk_plugin_library)
|
||||
|
||||
set_target_properties(
|
||||
qtk_gui PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
MACOSX_BUNDLE_BUNDLE_NAME Qtk
|
||||
MACOSX_BUNDLE_ICON_FILE ${QTK_OSX_ICONS}
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER ${CMAKE_PROJECT_NAME}
|
||||
MACOSX_BUNDLE_INFO_STRING ${CMAKE_PROJECT_DESCRIPTION}
|
||||
MACOSX_BUNDLE_COPYRIGHT "All Content (c) 2023 Shaun Reed, all rights reserved"
|
||||
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
|
||||
)
|
|
@ -0,0 +1,33 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Debug console for qtk views ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QWindow>
|
||||
|
||||
#include "debugconsole.h"
|
||||
#include "ui_debugconsole.h"
|
||||
|
||||
using namespace Qtk;
|
||||
|
||||
DebugConsole::DebugConsole(QWidget * owner, const QString & key) :
|
||||
DebugConsole(owner, key, key + "Debugger") {}
|
||||
|
||||
DebugConsole::DebugConsole(
|
||||
QWidget * owner, const QString & key, const QString & name) {
|
||||
ui_ = new Ui::DebugConsole;
|
||||
ui_->setupUi(this);
|
||||
setObjectName(name);
|
||||
mConsole = ui_->textEdit;
|
||||
setWidget(mConsole);
|
||||
setWindowTitle(name + " Debug Console");
|
||||
|
||||
auto qtkWidget = dynamic_cast<QtkWidget *>(owner);
|
||||
if(qtkWidget) {
|
||||
connect(qtkWidget, &QtkWidget::sendLog, this, &DebugConsole::sendLog);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Debug console for qtk views ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
|
||||
#ifndef QTK_DEBUGCONSOLE_H
|
||||
#define QTK_DEBUGCONSOLE_H
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDockWidget>
|
||||
#include <QPlainTextEdit>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "qtkwidget.h"
|
||||
|
||||
namespace Ui {
|
||||
class DebugConsole;
|
||||
}
|
||||
|
||||
namespace Qtk {
|
||||
class DebugConsole : public QDockWidget {
|
||||
Q_OBJECT;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Construct a new DebugConsole.
|
||||
* Assigns a default name to the console using `key + "Debugger"`
|
||||
*
|
||||
* @param owner Parent widget for this console or nullptr if no parent.
|
||||
* If this parameter inherits from QMainWindow we will add this dock
|
||||
* widget to the window.
|
||||
* @param key The objectName associated with the attached QtkWidget.
|
||||
*/
|
||||
DebugConsole(QWidget * owner, const QString & key);
|
||||
|
||||
/**
|
||||
* Construct a new DebugConsole.
|
||||
*
|
||||
* @param owner Parent widget for this console or nullptr if no parent.
|
||||
* If this parameter inherits from QMainWindow we will add this dock
|
||||
* widget to the window.
|
||||
* @param key The objectName associated with the attached QtkWidget.
|
||||
* @param name The objectName to associate with this DebugConsole.
|
||||
*/
|
||||
DebugConsole(QWidget * owner, const QString & key, const QString & name);
|
||||
|
||||
~DebugConsole() = default;
|
||||
|
||||
public slots:
|
||||
/*************************************************************************
|
||||
* Public Qt slots
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* Log a message to the DebugConsole text view.
|
||||
*
|
||||
* @param message The message to log.
|
||||
* @param context The DebugContext to use for the message.
|
||||
* Default value is Status.
|
||||
*/
|
||||
inline void sendLog(QString message, DebugContext context = Status) {
|
||||
mConsole->setTextColor(logColor(context));
|
||||
mConsole->append(logPrefix(message, context));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the window title for the DebugConsole. This will appear in the
|
||||
* widget title bar and within any context menu actions.
|
||||
*
|
||||
* @param name Base name for the DebugConsole window.
|
||||
*/
|
||||
inline void setTitle(QString name) {
|
||||
setWindowTitle(name + " Debug Console");
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* @param context Log context severity level.
|
||||
* @return QColor corresponding with the message context.
|
||||
*/
|
||||
[[nodiscard]] QColor logColor(const DebugContext & context) const {
|
||||
switch(context) {
|
||||
case Status:
|
||||
return Qt::GlobalColor::darkGray;
|
||||
case Debug:
|
||||
return Qt::GlobalColor::white;
|
||||
case Warn:
|
||||
return Qt::GlobalColor::yellow;
|
||||
case Error:
|
||||
return Qt::GlobalColor::red;
|
||||
case Fatal:
|
||||
return Qt::GlobalColor::magenta;
|
||||
default:
|
||||
return Qt::GlobalColor::darkYellow;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefixes a log message to add context level.
|
||||
*
|
||||
* @param message The message to prefix.
|
||||
* @param context The log context severity level.
|
||||
* @return The log message prefixed with the DebugContext level.
|
||||
*/
|
||||
[[nodiscard]] QString logPrefix(
|
||||
QString & message, const DebugContext & context) {
|
||||
QString prefix;
|
||||
switch(context) {
|
||||
case Status:
|
||||
prefix = "[Status]: ";
|
||||
break;
|
||||
case Debug:
|
||||
prefix = "[Debug]: ";
|
||||
break;
|
||||
case Warn:
|
||||
prefix = "[Warn]: ";
|
||||
break;
|
||||
case Error:
|
||||
prefix = "[Error]: ";
|
||||
break;
|
||||
case Fatal:
|
||||
prefix = "[Fatal]: ";
|
||||
break;
|
||||
default:
|
||||
prefix = "[No Context]: ";
|
||||
break;
|
||||
}
|
||||
message = prefix + message.replace("\n", "\t\n" + prefix);
|
||||
return message;
|
||||
}
|
||||
|
||||
Ui::DebugConsole * ui_;
|
||||
QTextEdit * mConsole;
|
||||
};
|
||||
} // namespace Qtk
|
||||
|
||||
#endif // QTK_DEBUGCONSOLE_H
|
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>DebugConsole</class>
|
||||
<widget class="QDockWidget" name="DebugConsole">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Debug Console</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="dockWidgetContents">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QTextEdit" name="textEdit">
|
||||
<property name="autoFillBackground">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -1,24 +1,28 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Main program for practice using Qt6 widgets and OpenGL ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
|
||||
#include <QApplication>
|
||||
#include <QLabel>
|
||||
|
||||
#include <mainwindow.h>
|
||||
#include <qtkwidget.h>
|
||||
#include <QSurfaceFormat>
|
||||
#include "qtkmainwindow.h"
|
||||
#include "qtkscene.h"
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
Q_INIT_RESOURCE(resources);
|
||||
|
||||
QApplication a(argc, argv);
|
||||
|
||||
// Create window for Qt application using custom mainwindow.h
|
||||
MainWindow w;
|
||||
w.show();
|
||||
auto window = MainWindow::getMainWindow();
|
||||
|
||||
// Qtk currently uses the decorator pattern to save / load scenes.
|
||||
// This is a temporary solution and will be improved in the future.
|
||||
auto emptyScene = new Qtk::SceneEmpty;
|
||||
window->getQtkWidget()->setScene(new QtkScene(emptyScene));
|
||||
|
||||
window->show();
|
||||
return QApplication::exec();
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: MainWindow for Qtk application ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
|
||||
#include "qtkmainwindow.h"
|
||||
#include "qtkscene.h"
|
||||
#include "ui_qtkmainwindow.h"
|
||||
|
||||
MainWindow * MainWindow::mainWindow_ = Q_NULLPTR;
|
||||
|
||||
/*******************************************************************************
|
||||
* Constructors / Destructors
|
||||
******************************************************************************/
|
||||
|
||||
MainWindow::MainWindow(QWidget * parent) : QMainWindow(parent) {
|
||||
ui_ = new Ui::MainWindow;
|
||||
setObjectName("MainWindow");
|
||||
// For use in design mode using Qt Creator
|
||||
// + We can use the `ui` member to access nested widgets by name
|
||||
ui_->setupUi(this);
|
||||
ui_->menuView->addAction(ui_->toolBar->toggleViewAction());
|
||||
|
||||
// Initialize static container for all active QtkWidgets
|
||||
auto qtkWidgets = findChildren<Qtk::QtkWidget *>();
|
||||
for(auto & qtkWidget : qtkWidgets) {
|
||||
qtkWidget->setScene(new Qtk::SceneEmpty);
|
||||
views_.emplace(qtkWidget->getScene()->getSceneName(), qtkWidget);
|
||||
|
||||
// Add GUI 'view' toolbar option to show debug console.
|
||||
ui_->menuView->addAction(qtkWidget->getActionToggleConsole());
|
||||
// Refresh GUI widgets when scene or objects are updated.
|
||||
connect(
|
||||
qtkWidget->getScene(), &Qtk::Scene::sceneUpdated, this,
|
||||
&MainWindow::refreshScene);
|
||||
connect(
|
||||
qtkWidget, &Qtk::QtkWidget::objectFocusChanged, ui_->qtk__ToolBox,
|
||||
&Qtk::ToolBox::updateFocus);
|
||||
}
|
||||
|
||||
// TODO: Fix / use MainWindow in Qt Designer to add these dock widgets.
|
||||
// For now we will add them manually, but we should be able to do this in the
|
||||
// designer. At the moment if you edit the UI in designer the dock widget
|
||||
// areas below will override the designer settings.
|
||||
|
||||
// Dock the toolbox widget to the main window.
|
||||
addDockWidget(Qt::LeftDockWidgetArea, ui_->qtk__ToolBox);
|
||||
// Add an option to toggle active widgets in the GUI's toolbar 'view' menu.
|
||||
ui_->menuView->addAction(ui_->qtk__ToolBox->toggleViewAction());
|
||||
|
||||
addDockWidget(Qt::RightDockWidgetArea, ui_->qtk__TreeView);
|
||||
ui_->menuView->addAction(ui_->qtk__TreeView->toggleViewAction());
|
||||
|
||||
// Set the window icon used for Qtk.
|
||||
setWindowIcon(Qtk::getIcon());
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow() {
|
||||
delete ui_;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Public Methods
|
||||
******************************************************************************/
|
||||
|
||||
MainWindow * MainWindow::getMainWindow() {
|
||||
if(mainWindow_ == Q_NULLPTR) {
|
||||
mainWindow_ = new MainWindow;
|
||||
}
|
||||
return mainWindow_;
|
||||
}
|
||||
|
||||
Qtk::QtkWidget * MainWindow::getQtkWidget(int64_t index) {
|
||||
if(views_.size() <= index) {
|
||||
return Q_NULLPTR;
|
||||
}
|
||||
return views_.begin(index)->second;
|
||||
}
|
||||
|
||||
Qtk::QtkWidget * MainWindow::getQtkWidget(const QString & name) {
|
||||
if(!views_.count(name)) {
|
||||
return Q_NULLPTR;
|
||||
}
|
||||
return views_[name];
|
||||
}
|
||||
|
||||
void MainWindow::refreshScene(const QString & sceneName) {
|
||||
// TODO: Select TreeView using sceneName
|
||||
ui_->qtk__TreeView->updateView(getQtkWidget()->getScene());
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: MainWindow for Qtk application ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QPlainTextEdit>
|
||||
|
||||
#include "debugconsole.h"
|
||||
#include "qtkwidget.h"
|
||||
|
||||
namespace Ui {
|
||||
class MainWindow;
|
||||
}
|
||||
|
||||
/**
|
||||
* MainWindow class to provide an example of using a QtkWidget within a Qt
|
||||
* window application.
|
||||
*/
|
||||
class MainWindow : public QMainWindow {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/***************************************************************************
|
||||
* Contructors / Destructors
|
||||
**************************************************************************/
|
||||
|
||||
/**
|
||||
* This ctor also initializes the Scene for each QtkWidget in the window.
|
||||
* To load a different scene this would need to be updated.
|
||||
*
|
||||
* @param parent The parent for this QMainWindow
|
||||
*/
|
||||
explicit MainWindow(QWidget * parent = nullptr);
|
||||
|
||||
~MainWindow() override;
|
||||
|
||||
/***************************************************************************
|
||||
* Public Methods
|
||||
**************************************************************************/
|
||||
|
||||
/**
|
||||
* Allows widgets to retrieve an instance of this root QMainWindow.
|
||||
* @return this
|
||||
*/
|
||||
static MainWindow * getMainWindow();
|
||||
|
||||
Qtk::QtkWidget * getQtkWidget(int64_t index = 0);
|
||||
|
||||
/**
|
||||
* Accessor for retrieving a QtkWidget by it's objectName.
|
||||
* This function will not construct a new QtkWidget if none is found.
|
||||
*
|
||||
* @param name The objectName associated with the QtkWidget.
|
||||
* @return Pointer to an active QtkWidget or Q_NULLPTR is not found.
|
||||
*/
|
||||
Qtk::QtkWidget * getQtkWidget(const QString & name);
|
||||
|
||||
public slots:
|
||||
/**
|
||||
* Trigger a refresh for widgets related to a scene that has been updated.
|
||||
* @param sceneName The name of the scene that has been modified.
|
||||
*/
|
||||
void refreshScene(const QString & sceneName);
|
||||
|
||||
private:
|
||||
/***************************************************************************
|
||||
* Private Members
|
||||
**************************************************************************/
|
||||
|
||||
/** Do not allow copying */
|
||||
MainWindow(const MainWindow &) {};
|
||||
|
||||
Ui::MainWindow * ui_ {};
|
||||
static MainWindow * mainWindow_;
|
||||
|
||||
/**
|
||||
* Maps a scene name to the QtkWidget viewing it.
|
||||
* TODO: Value should be a vector of QtkWidget * for multiple scene views.
|
||||
*/
|
||||
std::unordered_map<QString, Qtk::QtkWidget *> views_ {};
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
|
@ -0,0 +1,348 @@
|
|||
<?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>1034</width>
|
||||
<height>601</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>1</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Qtk - MainWindow</string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset>
|
||||
<normaloff>../resources/icon.png</normaloff>../resources/icon.png</iconset>
|
||||
</property>
|
||||
<property name="unifiedTitleAndToolBarOnMac">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="Qtk::ToolBox" name="qtk::ToolBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Object details and configuration panel.</string>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>When an object is double-clicked in the TreeView for a scene, this panel will display relevant details and options.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>3</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="movable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab">
|
||||
<attribute name="title">
|
||||
<string>View 1</string>
|
||||
</attribute>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="Qtk::QtkWidget" name="qtk::QtkWidget">
|
||||
<property name="toolTip">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Qtk scene view rendered using OpenGL.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_2">
|
||||
<attribute name="title">
|
||||
<string>View 2</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Qtk::TreeView" name="qtk::TreeView">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>TreeView of objects within the current scene.</string>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>TreeView of objects within the current scene. Double-click to select an object and snap to it's position.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1034</width>
|
||||
<height>22</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuTest">
|
||||
<property name="title">
|
||||
<string>File</string>
|
||||
</property>
|
||||
<addaction name="actionNew"/>
|
||||
<addaction name="actionOpen"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionSave"/>
|
||||
<addaction name="actionSave_as"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionExit"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuView">
|
||||
<property name="title">
|
||||
<string>View</string>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuTab_Position">
|
||||
<property name="title">
|
||||
<string>Tab Position</string>
|
||||
</property>
|
||||
<addaction name="actionTop"/>
|
||||
<addaction name="actionBottom"/>
|
||||
<addaction name="actionLeft"/>
|
||||
<addaction name="actionRight"/>
|
||||
</widget>
|
||||
<addaction name="menuTab_Position"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuEdit">
|
||||
<property name="title">
|
||||
<string>Edit</string>
|
||||
</property>
|
||||
<addaction name="actionUndo"/>
|
||||
<addaction name="actionRedo"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuHelp">
|
||||
<property name="title">
|
||||
<string>Help</string>
|
||||
</property>
|
||||
<addaction name="actionAbout"/>
|
||||
</widget>
|
||||
<addaction name="menuTest"/>
|
||||
<addaction name="menuEdit"/>
|
||||
<addaction name="menuView"/>
|
||||
<addaction name="menuHelp"/>
|
||||
</widget>
|
||||
<widget class="QToolBar" name="toolBar">
|
||||
<property name="windowTitle">
|
||||
<string>toolBar</string>
|
||||
</property>
|
||||
<property name="autoFillBackground">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="movable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonIconOnly</enum>
|
||||
</property>
|
||||
<property name="floatable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="toolBarArea">
|
||||
<enum>TopToolBarArea</enum>
|
||||
</attribute>
|
||||
<attribute name="toolBarBreak">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<addaction name="actionLoad_Model"/>
|
||||
<addaction name="actionDelete_Object"/>
|
||||
</widget>
|
||||
<action name="actionOpen">
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:/icons/fontawesome-free-6.2.1-desktop/svgs/regular/folder-open.svg</normaloff>:/icons/fontawesome-free-6.2.1-desktop/svgs/regular/folder-open.svg</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Open...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSave">
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:/icons/fontawesome-free-6.2.1-desktop/svgs/regular/floppy-disk.svg</normaloff>:/icons/fontawesome-free-6.2.1-desktop/svgs/regular/floppy-disk.svg</iconset>
|
||||
</property>
|
||||
<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>
|
||||
<action name="actionLoad_Model">
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:/icons/fontawesome-free-6.2.1-desktop/svgs/solid/cube.svg</normaloff>:/icons/fontawesome-free-6.2.1-desktop/svgs/solid/cube.svg</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Load Model</string>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font/>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDelete_Object">
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:/icons/fontawesome-free-6.2.1-desktop/svgs/regular/trash-can.svg</normaloff>:/icons/fontawesome-free-6.2.1-desktop/svgs/regular/trash-can.svg</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Delete Object</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionNew">
|
||||
<property name="text">
|
||||
<string>New</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionTop">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Top</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionBottom">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Bottom</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionLeft">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Left</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionRight">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Right</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionAbout">
|
||||
<property name="text">
|
||||
<string>About</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionNested_Widgets">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Nested Widgets</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionUndo">
|
||||
<property name="text">
|
||||
<string>Undo</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionRedo">
|
||||
<property name="text">
|
||||
<string>Redo</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>Qtk::QtkWidget</class>
|
||||
<extends>QOpenGLWidget</extends>
|
||||
<header>qtkwidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>Qtk::TreeView</class>
|
||||
<extends>QDockWidget</extends>
|
||||
<header>treeview.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>Qtk::ToolBox</class>
|
||||
<extends>QDockWidget</extends>
|
||||
<header>toolbox.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>actionExit</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>MainWindow</receiver>
|
||||
<slot>close()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>411</x>
|
||||
<y>300</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
|
@ -1,18 +1,12 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
|
||||
## About: Classes for managing objects and data within a scene ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Example Qtk scene ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
|
||||
#include <camera3d.h>
|
||||
#include <examplescene.h>
|
||||
#include <meshrenderer.h>
|
||||
#include <model.h>
|
||||
#include <resourcemanager.h>
|
||||
#include <scene.h>
|
||||
#include <texture.h>
|
||||
#include "qtkscene.h"
|
||||
|
||||
using namespace Qtk;
|
||||
|
||||
|
@ -20,104 +14,97 @@ using namespace Qtk;
|
|||
* Constructors, Destructors
|
||||
******************************************************************************/
|
||||
|
||||
ExampleScene::ExampleScene() {
|
||||
QtkScene::QtkScene(Qtk::Scene * scene) : Qtk::SceneInterface(scene) {
|
||||
setSceneName("Qtk Scene");
|
||||
getCamera().getTransform().setTranslation(0.0f, 0.0f, 20.0f);
|
||||
getCamera().getTransform().setRotation(-5.0f, 0.0f, 1.0f, 0.0f);
|
||||
}
|
||||
|
||||
ExampleScene::~ExampleScene() {
|
||||
QtkScene::~QtkScene() {
|
||||
delete mTestPhong;
|
||||
delete mTestSpecular;
|
||||
delete mTestDiffuse;
|
||||
delete mTestAmbient;
|
||||
for(auto & mesh : mMeshes) {
|
||||
delete mesh;
|
||||
}
|
||||
for(auto & model : mModels) {
|
||||
delete model;
|
||||
}
|
||||
delete mSkybox;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Public Member Functions
|
||||
******************************************************************************/
|
||||
|
||||
void ExampleScene::init() {
|
||||
void QtkScene::init() {
|
||||
// Add a skybox to the scene using default cube map images and settings.
|
||||
setSkybox(new Qtk::Skybox("Skybox"));
|
||||
|
||||
/* Create a red cube with a mini master chief on top. */
|
||||
auto myCube = new MeshRenderer("My cube", Cube(Qtk::QTK_DRAW_ELEMENTS));
|
||||
myCube->setColor(RED);
|
||||
mMeshes.push_back(myCube);
|
||||
myCube->getTransform().setTranslation(5.0f, 0.0f, 0.0f);
|
||||
addObject(myCube);
|
||||
|
||||
auto mySpartan = new Model("My spartan", ":/models/spartan/spartan.obj");
|
||||
mySpartan->getTransform().setTranslation(0.0f, 0.5f, 0.0f);
|
||||
auto mySpartan =
|
||||
new Model("My spartan", ":/models/models/spartan/spartan.obj");
|
||||
mySpartan->getTransform().setTranslation(5.0f, 0.5f, 0.0f);
|
||||
mySpartan->getTransform().setScale(0.5f);
|
||||
mModels.push_back(mySpartan);
|
||||
addObject(mySpartan);
|
||||
|
||||
//
|
||||
// Create simple shapes using MeshRenderer class and data in mesh.h
|
||||
|
||||
mMeshes.push_back(
|
||||
auto mesh = addObject(
|
||||
new Qtk::MeshRenderer("rightTriangle", Triangle(QTK_DRAW_ELEMENTS)));
|
||||
mMeshes.back()->getTransform().setTranslation(-5.0f, 0.0f, -2.0f);
|
||||
mesh->getTransform().setTranslation(-5.0f, 0.0f, -2.0f);
|
||||
|
||||
mMeshes.push_back(
|
||||
new Qtk::MeshRenderer("centerCube", Cube(QTK_DRAW_ELEMENTS)));
|
||||
mMeshes.back()->getTransform().setTranslation(-7.0f, 0.0f, -2.0f);
|
||||
mesh =
|
||||
addObject(new Qtk::MeshRenderer("centerCube", Cube(QTK_DRAW_ELEMENTS)));
|
||||
mesh->getTransform().setTranslation(-7.0f, 0.0f, -2.0f);
|
||||
|
||||
mMeshes.push_back(
|
||||
mesh = addObject(
|
||||
new Qtk::MeshRenderer("leftTriangle", Triangle(QTK_DRAW_ELEMENTS)));
|
||||
mMeshes.back()->getTransform().setTranslation(-9.0f, 0.0f, -2.0f);
|
||||
mMeshes.back()->setDrawType(GL_LINE_LOOP);
|
||||
mesh->getTransform().setTranslation(-9.0f, 0.0f, -2.0f);
|
||||
mesh->setDrawType(GL_LINE_LOOP);
|
||||
|
||||
mMeshes.push_back(
|
||||
mesh = addObject(
|
||||
new Qtk::MeshRenderer("topTriangle", Triangle(QTK_DRAW_ELEMENTS)));
|
||||
mMeshes.back()->getTransform().setTranslation(-7.0f, 2.0f, -2.0f);
|
||||
mMeshes.back()->getTransform().scale(0.25f);
|
||||
mesh->getTransform().setTranslation(-7.0f, 2.0f, -2.0f);
|
||||
mesh->getTransform().scale(0.25f);
|
||||
|
||||
mMeshes.push_back(
|
||||
mesh = addObject(
|
||||
new Qtk::MeshRenderer("bottomTriangle", Triangle(QTK_DRAW_ELEMENTS)));
|
||||
mMeshes.back()->getTransform().setTranslation(-7.0f, -2.0f, -2.0f);
|
||||
mMeshes.back()->getTransform().scale(0.25f);
|
||||
mMeshes.back()->setDrawType(GL_LINE_LOOP);
|
||||
mMeshes.back()->setColor(GREEN);
|
||||
mesh->getTransform().setTranslation(-7.0f, -2.0f, -2.0f);
|
||||
mesh->getTransform().scale(0.25f);
|
||||
mesh->setDrawType(GL_LINE_LOOP);
|
||||
mesh->setColor(GREEN);
|
||||
|
||||
|
||||
//
|
||||
// 3D Model loading
|
||||
|
||||
mModels.push_back(
|
||||
new Qtk::Model("backpack", ":/models/backpack/backpack.obj"));
|
||||
auto model = addObject(
|
||||
new Qtk::Model("backpack", ":/models/models/backpack/backpack.obj"));
|
||||
// Sometimes model textures need flipped in certain directions
|
||||
mModels.back()->flipTexture("diffuse.jpg", false, true);
|
||||
mModels.back()->getTransform().setTranslation(0.0f, 0.0f, -10.0f);
|
||||
model->flipTexture("diffuse.jpg", false, true);
|
||||
model->getTransform().setTranslation(0.0f, 0.0f, -10.0f);
|
||||
|
||||
mModels.push_back(new Qtk::Model("bird", ":/models/bird/bird.obj"));
|
||||
mModels.back()->getTransform().setTranslation(2.0f, 2.0f, -10.0f);
|
||||
model = addObject(new Qtk::Model("bird", ":/models/models/bird/bird.obj"));
|
||||
model->getTransform().setTranslation(2.0f, 2.0f, -10.0f);
|
||||
// Sometimes the models are very large
|
||||
mModels.back()->getTransform().scale(0.0025f);
|
||||
mModels.back()->getTransform().rotate(-110.0f, 0.0f, 1.0f, 0.0f);
|
||||
model->getTransform().scale(0.0025f);
|
||||
model->getTransform().rotate(-110.0f, 0.0f, 1.0f, 0.0f);
|
||||
|
||||
mModels.push_back(new Qtk::Model("lion", ":/models/lion/lion.obj"));
|
||||
mModels.back()->getTransform().setTranslation(-3.0f, -1.0f, -10.0f);
|
||||
mModels.back()->getTransform().scale(0.15f);
|
||||
model = addObject(
|
||||
new Qtk::Model("alien", ":/models/models/alien-hominid/alien.obj"));
|
||||
model->getTransform().setTranslation(2.0f, -1.0f, -5.0f);
|
||||
model->getTransform().scale(0.15f);
|
||||
|
||||
mModels.push_back(
|
||||
new Qtk::Model("alien", ":/models/alien-hominid/alien.obj"));
|
||||
mModels.back()->getTransform().setTranslation(2.0f, -1.0f, -5.0f);
|
||||
mModels.back()->getTransform().scale(0.15f);
|
||||
model = addObject(
|
||||
new Qtk::Model("My scythe", ":/models/models/scythe/scythe.obj"));
|
||||
model->getTransform().setTranslation(-6.0f, 0.0f, -10.0f);
|
||||
model->getTransform().rotate(-90.0f, 1.0f, 0.0f, 0.0f);
|
||||
model->getTransform().rotate(90.0f, 0.0f, 1.0f, 0.0f);
|
||||
|
||||
mModels.push_back(new Qtk::Model("scythe", ":/models/scythe/scythe.obj"));
|
||||
mModels.back()->getTransform().setTranslation(-6.0f, 0.0f, -10.0f);
|
||||
mModels.back()->getTransform().rotate(-90.0f, 1.0f, 0.0f, 0.0f);
|
||||
mModels.back()->getTransform().rotate(90.0f, 0.0f, 1.0f, 0.0f);
|
||||
|
||||
mModels.push_back(
|
||||
new Qtk::Model("masterChief", ":/models/spartan/spartan.obj"));
|
||||
mModels.back()->getTransform().setTranslation(-1.5f, 0.5f, -2.0f);
|
||||
model = addObject(
|
||||
new Qtk::Model("masterChief", ":/models/models/spartan/spartan.obj"));
|
||||
model->getTransform().setTranslation(-1.5f, 0.5f, -2.0f);
|
||||
|
||||
|
||||
//
|
||||
|
@ -129,7 +116,8 @@ void ExampleScene::init() {
|
|||
// NOTE: You no longer need to manually bind shader program to set uniforms.
|
||||
// + You can still bind it if you want to for performance reasons.
|
||||
// + Qtk will only bind / release if the shader program is not already bound.
|
||||
mTestPhong->setShaders(":/solid-phong.vert", ":/solid-phong.frag");
|
||||
mTestPhong->setShaders(
|
||||
":/shaders/solid-phong.vert", ":/shaders/solid-phong.frag");
|
||||
|
||||
// For example this would technically not be efficient, because each one of
|
||||
// these calls will bind, set, release. We could instead bind, set N uniforms,
|
||||
|
@ -147,23 +135,24 @@ void ExampleScene::init() {
|
|||
|
||||
// Phong lighting example light source. This is just for visual reference.
|
||||
// + We refer to the position of this object in draw() to update lighting.
|
||||
mMeshes.push_back(
|
||||
mesh = addObject(
|
||||
new Qtk::MeshRenderer("phongLight", Triangle(QTK_DRAW_ELEMENTS)));
|
||||
mMeshes.back()->getTransform().setTranslation(3.0f, 2.0f, -2.0f);
|
||||
mMeshes.back()->getTransform().scale(0.25f);
|
||||
mesh->getTransform().setTranslation(3.0f, 2.0f, -2.0f);
|
||||
mesh->getTransform().scale(0.25f);
|
||||
|
||||
/* Example of a cube with no lighting applied */
|
||||
mMeshes.push_back(new Qtk::MeshRenderer("noLight", Cube(QTK_DRAW_ELEMENTS)));
|
||||
mMeshes.back()->getTransform().setTranslation(5.0f, 0.0f, -2.0f);
|
||||
mMeshes.back()->setShaders(
|
||||
":/solid-perspective.vert", ":/solid-perspective.frag");
|
||||
mMeshes.back()->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f));
|
||||
mesh = addObject(new Qtk::MeshRenderer("noLight", Cube(QTK_DRAW_ELEMENTS)));
|
||||
mesh->getTransform().setTranslation(5.0f, 0.0f, -2.0f);
|
||||
mesh->setShaders(
|
||||
":/shaders/solid-perspective.vert", ":/shaders/solid-perspective.frag");
|
||||
mesh->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f));
|
||||
// No light source needed for this lighting technique
|
||||
|
||||
/* Initialize Ambient example cube */
|
||||
mTestAmbient = new Qtk::MeshRenderer("ambient", Cube());
|
||||
mTestAmbient->getTransform().setTranslation(7.0f, 0.0f, -2.0f);
|
||||
mTestAmbient->setShaders(":/solid-ambient.vert", ":/solid-ambient.frag");
|
||||
mTestAmbient->setShaders(
|
||||
":/shaders/solid-ambient.vert", ":/shaders/solid-ambient.frag");
|
||||
// Changing these uniform values will alter lighting effects.
|
||||
mTestAmbient->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f));
|
||||
mTestAmbient->setUniform("uLightColor", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
|
@ -174,22 +163,24 @@ void ExampleScene::init() {
|
|||
/* Initialize Diffuse example cube */
|
||||
mTestDiffuse = new Qtk::MeshRenderer("diffuse", Cube());
|
||||
mTestDiffuse->getTransform().setTranslation(9.0f, 0.0f, -2.0f);
|
||||
mTestDiffuse->setShaders(":/solid-diffuse.vert", ":/solid-diffuse.frag");
|
||||
mTestDiffuse->setShaders(
|
||||
":/shaders/solid-diffuse.vert", ":/shaders/solid-diffuse.frag");
|
||||
mTestDiffuse->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f));
|
||||
mTestDiffuse->setUniform("uLightColor", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
mTestDiffuse->setUniform("uAmbientStrength", 0.2f);
|
||||
mTestDiffuse->reallocateNormals(mTestDiffuse->getNormals());
|
||||
|
||||
// Diffuse lighting example light source. This is just for visual reference.
|
||||
mMeshes.push_back(
|
||||
mesh = addObject(
|
||||
new Qtk::MeshRenderer("diffuseLight", Triangle(QTK_DRAW_ELEMENTS)));
|
||||
mMeshes.back()->getTransform().setTranslation(9.0f, 2.0f, -2.0f);
|
||||
mMeshes.back()->getTransform().scale(0.25f);
|
||||
mesh->getTransform().setTranslation(9.0f, 2.0f, -2.0f);
|
||||
mesh->getTransform().scale(0.25f);
|
||||
|
||||
/* Initialize Specular example cube */
|
||||
mTestSpecular = new Qtk::MeshRenderer("specular", Cube());
|
||||
mTestSpecular->getTransform().setTranslation(11.0f, 0.0f, -2.0f);
|
||||
mTestSpecular->setShaders(":/solid-specular.vert", ":/solid-specular.frag");
|
||||
mTestSpecular->setShaders(
|
||||
":/shaders/solid-specular.vert", ":/shaders/solid-specular.frag");
|
||||
mTestSpecular->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f));
|
||||
mTestSpecular->setUniform("uLightColor", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
mTestSpecular->setUniform("uAmbientStrength", 0.2f);
|
||||
|
@ -198,217 +189,209 @@ void ExampleScene::init() {
|
|||
mTestSpecular->reallocateNormals(mTestSpecular->getNormals());
|
||||
|
||||
// Specular lighting example light source. This is just for visual reference.
|
||||
mMeshes.push_back(
|
||||
mesh = addObject(
|
||||
new Qtk::MeshRenderer("specularLight", Triangle(QTK_DRAW_ELEMENTS)));
|
||||
mMeshes.back()->getTransform().setTranslation(11.0f, 2.0f, -2.0f);
|
||||
mMeshes.back()->getTransform().scale(0.25f);
|
||||
mesh->getTransform().setTranslation(11.0f, 2.0f, -2.0f);
|
||||
mesh->getTransform().scale(0.25f);
|
||||
|
||||
|
||||
/* Test basic cube with phong.vert and phong.frag shaders */
|
||||
mMeshes.push_back(new Qtk::MeshRenderer("testPhong", Cube(QTK_DRAW_ARRAYS)));
|
||||
mMeshes.back()->getTransform().setTranslation(5.0f, 0.0f, 10.0f);
|
||||
mMeshes.back()->setShaders(":/phong.vert", ":/phong.frag");
|
||||
mesh = addObject(new Qtk::MeshRenderer("testPhong", Cube(QTK_DRAW_ARRAYS)));
|
||||
mesh->getTransform().setTranslation(5.0f, 0.0f, 10.0f);
|
||||
mesh->setShaders(":/shaders/phong.vert", ":/shaders/phong.frag");
|
||||
// WARNING: Set color before reallocating normals.
|
||||
mMeshes.back()->setColor(QVector3D(0.0f, 0.25f, 0.0f));
|
||||
mMeshes.back()->reallocateNormals(mMeshes.back()->getNormals());
|
||||
mesh->setColor(QVector3D(0.0f, 0.25f, 0.0f));
|
||||
mesh->reallocateNormals(mesh->getNormals());
|
||||
|
||||
mMeshes.back()->setUniform("uMaterial.ambient", QVector3D(0.0f, 0.3f, 0.0f));
|
||||
mMeshes.back()->setUniform("uMaterial.diffuse", QVector3D(0.0f, 0.2f, 0.0f));
|
||||
mMeshes.back()->setUniform("uMaterial.specular", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
mMeshes.back()->setUniform("uMaterial.ambientStrength", 1.0f);
|
||||
mMeshes.back()->setUniform("uMaterial.diffuseStrength", 1.0f);
|
||||
mMeshes.back()->setUniform("uMaterial.specularStrength", 1.0f);
|
||||
mMeshes.back()->setUniform("uMaterial.shine", 64.0f);
|
||||
mMeshes.back()->setUniform("uLight.ambient", QVector3D(0.25f, 0.2f, 0.075f));
|
||||
mMeshes.back()->setUniform("uLight.diffuse", QVector3D(0.75f, 0.6f, 0.22f));
|
||||
mMeshes.back()->setUniform("uLight.specular", QVector3D(0.62f, 0.55f, 0.37f));
|
||||
mMeshes.back()->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f));
|
||||
mesh->setUniform("uMaterial.ambient", QVector3D(0.0f, 0.3f, 0.0f));
|
||||
mesh->setUniform("uMaterial.diffuse", QVector3D(0.0f, 0.2f, 0.0f));
|
||||
mesh->setUniform("uMaterial.specular", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
mesh->setUniform("uMaterial.ambientStrength", 1.0f);
|
||||
mesh->setUniform("uMaterial.diffuseStrength", 1.0f);
|
||||
mesh->setUniform("uMaterial.specularStrength", 1.0f);
|
||||
mesh->setUniform("uMaterial.shine", 64.0f);
|
||||
mesh->setUniform("uLight.ambient", QVector3D(0.25f, 0.2f, 0.075f));
|
||||
mesh->setUniform("uLight.diffuse", QVector3D(0.75f, 0.6f, 0.22f));
|
||||
mesh->setUniform("uLight.specular", QVector3D(0.62f, 0.55f, 0.37f));
|
||||
mesh->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f));
|
||||
|
||||
// Light source for testPhong cube
|
||||
mMeshes.push_back(
|
||||
mesh = addObject(
|
||||
new Qtk::MeshRenderer("testLight", Triangle(QTK_DRAW_ELEMENTS)));
|
||||
mMeshes.back()->getTransform().setTranslation(5.0f, 1.25f, 10.0f);
|
||||
mMeshes.back()->getTransform().scale(0.25f);
|
||||
mMeshes.back()->setDrawType(GL_LINE_LOOP);
|
||||
mMeshes.back()->setColor(RED);
|
||||
mesh->getTransform().setTranslation(5.0f, 1.25f, 10.0f);
|
||||
mesh->getTransform().scale(0.25f);
|
||||
mesh->setDrawType(GL_LINE_LOOP);
|
||||
mesh->setColor(RED);
|
||||
|
||||
|
||||
//
|
||||
// Building more complex objects for showing examples of lighting techniques
|
||||
|
||||
/* Test alien Model with phong lighting and specular mapping. */
|
||||
mModels.push_back(new Qtk::Model(
|
||||
"alienTest", ":/models/alien-hominid/alien.obj", ":/model-specular.vert",
|
||||
":/model-specular.frag"));
|
||||
mModels.back()->getTransform().setTranslation(3.0f, -1.0f, 10.0f);
|
||||
mModels.back()->getTransform().scale(0.15f);
|
||||
mModels.back()->setUniform("uMaterial.ambient", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
mModels.back()->setUniform("uMaterial.diffuse", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
mModels.back()->setUniform("uMaterial.specular", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
mModels.back()->setUniform("uMaterial.ambientStrength", 0.8f);
|
||||
mModels.back()->setUniform("uMaterial.diffuseStrength", 0.8f);
|
||||
mModels.back()->setUniform("uMaterial.specularStrength", 1.0f);
|
||||
mModels.back()->setUniform("uMaterial.shine", 32.0f);
|
||||
model = addObject(new Qtk::Model(
|
||||
"alienTest", ":/models/models/alien-hominid/alien.obj",
|
||||
":/shaders/model-specular.vert", ":/shaders/model-specular.frag"));
|
||||
model->getTransform().setTranslation(3.0f, -1.0f, 10.0f);
|
||||
model->getTransform().scale(0.15f);
|
||||
model->setUniform("uMaterial.ambient", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
model->setUniform("uMaterial.diffuse", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
model->setUniform("uMaterial.specular", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
model->setUniform("uMaterial.ambientStrength", 0.8f);
|
||||
model->setUniform("uMaterial.diffuseStrength", 0.8f);
|
||||
model->setUniform("uMaterial.specularStrength", 1.0f);
|
||||
model->setUniform("uMaterial.shine", 32.0f);
|
||||
|
||||
mModels.back()->setUniform("uLight.ambient", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
mModels.back()->setUniform("uLight.diffuse", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
mModels.back()->setUniform("uLight.specular", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
model->setUniform("uLight.ambient", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
model->setUniform("uLight.diffuse", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
model->setUniform("uLight.specular", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
|
||||
// Light source for alienTest object.
|
||||
mMeshes.push_back(new Qtk::MeshRenderer(
|
||||
mesh = addObject(new Qtk::MeshRenderer(
|
||||
"alienTestLight", Triangle(Qtk::QTK_DRAW_ELEMENTS)));
|
||||
mMeshes.back()->getTransform().setTranslation(4.0f, 1.5f, 10.0f);
|
||||
mMeshes.back()->getTransform().scale(0.25f);
|
||||
mesh->getTransform().setTranslation(4.0f, 1.5f, 10.0f);
|
||||
mesh->getTransform().scale(0.25f);
|
||||
// This function changes values we have allocated in a buffer, so init() after
|
||||
mMeshes.back()->setColor(GREEN);
|
||||
mesh->setColor(GREEN);
|
||||
|
||||
/* Test spartan Model with phong lighting, specular and normal mapping. */
|
||||
mModels.push_back(new Qtk::Model(
|
||||
"spartanTest", ":/models/spartan/spartan.obj", ":/model-normals.vert",
|
||||
":/model-normals.frag"));
|
||||
mModels.back()->getTransform().setTranslation(0.0f, -1.0f, 10.0f);
|
||||
mModels.back()->getTransform().scale(2.0f);
|
||||
mModels.back()->setUniform("uMaterial.ambient", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
mModels.back()->setUniform("uMaterial.diffuse", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
mModels.back()->setUniform("uMaterial.specular", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
mModels.back()->setUniform("uMaterial.ambientStrength", 1.0f);
|
||||
mModels.back()->setUniform("uMaterial.diffuseStrength", 1.0f);
|
||||
mModels.back()->setUniform("uMaterial.specularStrength", 1.0f);
|
||||
mModels.back()->setUniform("uMaterial.shine", 128.0f);
|
||||
mModels.back()->setUniform("uLight.ambient", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
mModels.back()->setUniform("uLight.diffuse", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
mModels.back()->setUniform("uLight.specular", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
model = addObject(new Qtk::Model(
|
||||
"spartanTest", ":/models/models/spartan/spartan.obj",
|
||||
":/shaders/model-normals.vert", ":/shaders/model-normals.frag"));
|
||||
model->getTransform().setTranslation(0.0f, -1.0f, 10.0f);
|
||||
model->getTransform().scale(2.0f);
|
||||
model->setUniform("uMaterial.ambient", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
model->setUniform("uMaterial.diffuse", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
model->setUniform("uMaterial.specular", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
model->setUniform("uMaterial.ambientStrength", 1.0f);
|
||||
model->setUniform("uMaterial.diffuseStrength", 1.0f);
|
||||
model->setUniform("uMaterial.specularStrength", 1.0f);
|
||||
model->setUniform("uMaterial.shine", 128.0f);
|
||||
model->setUniform("uLight.ambient", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
model->setUniform("uLight.diffuse", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
model->setUniform("uLight.specular", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
|
||||
// Light source for spartanTest object.
|
||||
mMeshes.push_back(
|
||||
mesh = addObject(
|
||||
new Qtk::MeshRenderer("spartanTestLight", Triangle(QTK_DRAW_ELEMENTS)));
|
||||
mMeshes.back()->getTransform().setTranslation(1.0f, 1.5f, 10.0f);
|
||||
mMeshes.back()->getTransform().scale(0.25f);
|
||||
mesh->getTransform().setTranslation(1.0f, 1.5f, 10.0f);
|
||||
mesh->getTransform().scale(0.25f);
|
||||
// This function changes values we have allocated in a buffer, so init() after
|
||||
mMeshes.back()->setColor(GREEN);
|
||||
mesh->setColor(GREEN);
|
||||
|
||||
|
||||
//
|
||||
// Test drawing simple geometry with various OpenGL drawing modes
|
||||
|
||||
// RGB Normals cube to show normals are correct with QTK_DRAW_ARRAYS
|
||||
mMeshes.push_back(
|
||||
mesh = addObject(
|
||||
new Qtk::MeshRenderer("rgbNormalsCubeArraysTest", Cube(QTK_DRAW_ARRAYS)));
|
||||
mMeshes.back()->getTransform().setTranslation(5.0f, 0.0f, 4.0f);
|
||||
mMeshes.back()->setShaders(":/rgb-normals.vert", ":/rgb-normals.frag");
|
||||
mMeshes.back()->reallocateNormals(mMeshes.back()->getNormals());
|
||||
mesh->getTransform().setTranslation(5.0f, 0.0f, 4.0f);
|
||||
mesh->setShaders(":/shaders/rgb-normals.vert", ":/shaders/rgb-normals.frag");
|
||||
mesh->reallocateNormals(mesh->getNormals());
|
||||
|
||||
// RGB Normals cube to show normals are correct with QTK_DRAW_ELEMENTS_NORMALS
|
||||
mMeshes.push_back(new Qtk::MeshRenderer(
|
||||
mesh = addObject(new Qtk::MeshRenderer(
|
||||
"rgbNormalsCubeElementsTest", Cube(QTK_DRAW_ELEMENTS_NORMALS)));
|
||||
mMeshes.back()->getTransform().setTranslation(5.0f, 0.0f, 2.0f);
|
||||
mMeshes.back()->setShaders(":/rgb-normals.vert", ":/rgb-normals.frag");
|
||||
mMeshes.back()->reallocateNormals(mMeshes.back()->getNormals());
|
||||
mesh->getTransform().setTranslation(5.0f, 0.0f, 2.0f);
|
||||
mesh->setShaders(":/shaders/rgb-normals.vert", ":/shaders/rgb-normals.frag");
|
||||
mesh->reallocateNormals(mesh->getNormals());
|
||||
|
||||
Texture crateTexture;
|
||||
crateTexture.setTexture(":/crate.png");
|
||||
crateTexture.setTexture(":/textures/crate.png");
|
||||
Cube cube;
|
||||
auto * m = new MeshRenderer("Test Crate", Cube(QTK_DRAW_ARRAYS));
|
||||
m->getTransform().setTranslation(0, 0, 13);
|
||||
m->setShaders(":/texture2d.vert", ":/texture2d.frag");
|
||||
m->setShaders(":/shaders/texture2d.vert", ":/shaders/texture2d.frag");
|
||||
m->setTexture(crateTexture);
|
||||
m->setUniform("uTexture", 0);
|
||||
m->reallocateTexCoords(cube.getTexCoords());
|
||||
mMeshes.push_back(m);
|
||||
addObject(m);
|
||||
|
||||
// Texturing a cube using texture coordinates and glDrawArrays
|
||||
// + Texturing with UVs using glDrawElements requires
|
||||
// QTK_DRAW_ELEMENTS_NORMALS
|
||||
// + UVs required duplicating element position data from QTK_DRAW_ELEMENTS
|
||||
// + This is because the same position must use different UV coordinates
|
||||
mMeshes.push_back(
|
||||
mesh = addObject(
|
||||
new Qtk::MeshRenderer("uvCubeArraysTest", Cube(QTK_DRAW_ARRAYS)));
|
||||
mMeshes.back()->getTransform().setTranslation(-3.0f, 0.0f, -2.0f);
|
||||
mMeshes.back()->setShaders(":/texture2d.vert", ":/texture2d.frag");
|
||||
mMeshes.back()->setTexture(crateTexture);
|
||||
mMeshes.back()->setUniform("uTexture", 0);
|
||||
mMeshes.back()->reallocateTexCoords(mMeshes.back()->getTexCoords());
|
||||
mesh->getTransform().setTranslation(-3.0f, 0.0f, -2.0f);
|
||||
mesh->setShaders(":/shaders/texture2d.vert", ":/shaders/texture2d.frag");
|
||||
mesh->setTexture(crateTexture);
|
||||
mesh->setUniform("uTexture", 0);
|
||||
mesh->reallocateTexCoords(mesh->getTexCoords());
|
||||
|
||||
// Test drawing a cube with texture coordinates using glDrawElements
|
||||
mMeshes.push_back(new Qtk::MeshRenderer(
|
||||
mesh = addObject(new Qtk::MeshRenderer(
|
||||
"uvCubeElementsTest", Cube(QTK_DRAW_ELEMENTS_NORMALS)));
|
||||
mMeshes.back()->getTransform().setTranslation(-1.7f, 0.0f, -2.0f);
|
||||
mMeshes.back()->setTexture(":/crate.png");
|
||||
mMeshes.back()->setShaders(":/texture2d.vert", ":/texture2d.frag");
|
||||
mMeshes.back()->bindShaders();
|
||||
mMeshes.back()->setUniform("uTexture", 0);
|
||||
mMeshes.back()->reallocateNormals(mMeshes.back()->getNormals());
|
||||
mMeshes.back()->reallocateTexCoords(mMeshes.back()->getTexCoords(), 3);
|
||||
mMeshes.back()->releaseShaders();
|
||||
mMeshes.back()->getTransform().rotate(45.0f, 0.0f, 1.0f, 0.0f);
|
||||
mesh->getTransform().setTranslation(-1.7f, 0.0f, -2.0f);
|
||||
mesh->setTexture(":/textures/crate.png");
|
||||
mesh->setShaders(":/shaders/texture2d.vert", ":/shaders/texture2d.frag");
|
||||
mesh->bindShaders();
|
||||
mesh->setUniform("uTexture", 0);
|
||||
mesh->reallocateNormals(mesh->getNormals());
|
||||
mesh->reallocateTexCoords(mesh->getTexCoords(), 3);
|
||||
mesh->releaseShaders();
|
||||
mesh->getTransform().rotate(45.0f, 0.0f, 1.0f, 0.0f);
|
||||
|
||||
// Texturing a cube using a cube map
|
||||
// + Cube map texturing works with both QTK_DRAW_ARRAYS and QTK_DRAW_ELEMENTS
|
||||
mMeshes.push_back(
|
||||
new Qtk::MeshRenderer("testCubeMap", Cube(QTK_DRAW_ELEMENTS)));
|
||||
mMeshes.back()->getTransform().setTranslation(-3.0f, 1.0f, -2.0f);
|
||||
mMeshes.back()->getTransform().setRotation(45.0f, 0.0f, 1.0f, 0.0f);
|
||||
mMeshes.back()->setShaders(
|
||||
":/texture-cubemap.vert", ":/texture-cubemap.frag");
|
||||
mMeshes.back()->setCubeMap(":/crate.png");
|
||||
mMeshes.back()->setUniform("uTexture", 0);
|
||||
mMeshes.back()->reallocateTexCoords(mMeshes.back()->getTexCoords());
|
||||
mesh =
|
||||
addObject(new Qtk::MeshRenderer("testCubeMap", Cube(QTK_DRAW_ELEMENTS)));
|
||||
mesh->getTransform().setTranslation(-3.0f, 1.0f, -2.0f);
|
||||
mesh->getTransform().setRotation(45.0f, 0.0f, 1.0f, 0.0f);
|
||||
mesh->setShaders(
|
||||
":/shaders/texture-cubemap.vert", ":/shaders/texture-cubemap.frag");
|
||||
mesh->setCubeMap(":/textures/crate.png");
|
||||
mesh->setUniform("uTexture", 0);
|
||||
mesh->reallocateTexCoords(mesh->getTexCoords());
|
||||
|
||||
// Create a cube with custom shaders
|
||||
// + Apply RGB normals shader and spin the cube for a neat effect
|
||||
mMeshes.push_back(
|
||||
new Qtk::MeshRenderer("rgbNormalsCube", Cube(QTK_DRAW_ARRAYS)));
|
||||
mMeshes.back()->getTransform().setTranslation(5.0f, 2.0f, -2.0f);
|
||||
mMeshes.back()->setShaders(":/rgb-normals.vert", ":/rgb-normals.frag");
|
||||
mMeshes.back()->reallocateNormals(mMeshes.back()->getNormals());
|
||||
mesh =
|
||||
addObject(new Qtk::MeshRenderer("rgbNormalsCube", Cube(QTK_DRAW_ARRAYS)));
|
||||
mesh->getTransform().setTranslation(5.0f, 2.0f, -2.0f);
|
||||
mesh->setShaders(":/shaders/rgb-normals.vert", ":/shaders/rgb-normals.frag");
|
||||
mesh->reallocateNormals(mesh->getNormals());
|
||||
|
||||
// RGB Normals triangle to show normals are correct with QTK_DRAW_ARRAYS
|
||||
mMeshes.push_back(new Qtk::MeshRenderer(
|
||||
mesh = addObject(new Qtk::MeshRenderer(
|
||||
"rgbTriangleArraysTest", Triangle(QTK_DRAW_ARRAYS)));
|
||||
mMeshes.back()->getTransform().setTranslation(7.0f, 0.0f, 2.0f);
|
||||
mMeshes.back()->setShaders(":/rgb-normals.vert", ":/rgb-normals.frag");
|
||||
mMeshes.back()->reallocateNormals(mMeshes.back()->getNormals());
|
||||
mesh->getTransform().setTranslation(7.0f, 0.0f, 2.0f);
|
||||
mesh->setShaders(":/shaders/rgb-normals.vert", ":/shaders/rgb-normals.frag");
|
||||
mesh->reallocateNormals(mesh->getNormals());
|
||||
|
||||
// RGB Normals triangle to show normals are correct with QTK_DRAW_ELEMENTS
|
||||
mMeshes.push_back(new Qtk::MeshRenderer(
|
||||
mesh = addObject(new Qtk::MeshRenderer(
|
||||
"rgbTriangleElementsTest", Triangle(QTK_DRAW_ELEMENTS_NORMALS)));
|
||||
mMeshes.back()->getTransform().setTranslation(7.0f, 0.0f, 4.0f);
|
||||
mMeshes.back()->setShaders(":/rgb-normals.vert", ":/rgb-normals.frag");
|
||||
mMeshes.back()->reallocateNormals(mMeshes.back()->getNormals());
|
||||
mesh->getTransform().setTranslation(7.0f, 0.0f, 4.0f);
|
||||
mesh->setShaders(":/shaders/rgb-normals.vert", ":/shaders/rgb-normals.frag");
|
||||
mesh->reallocateNormals(mesh->getNormals());
|
||||
|
||||
// Test drawing triangle with glDrawArrays with texture coordinates
|
||||
mMeshes.push_back(
|
||||
mesh = addObject(
|
||||
new Qtk::MeshRenderer("testTriangleArraysUV", Triangle(QTK_DRAW_ARRAYS)));
|
||||
mMeshes.back()->getTransform().setTranslation(-3.0f, 2.0f, -2.0f);
|
||||
mMeshes.back()->setShaders(":/texture2d.vert", ":/texture2d.frag");
|
||||
mesh->getTransform().setTranslation(-3.0f, 2.0f, -2.0f);
|
||||
mesh->setShaders(":/shaders/texture2d.vert", ":/shaders/texture2d.frag");
|
||||
|
||||
mMeshes.back()->setTexture(":/crate.png");
|
||||
mMeshes.back()->setUniform("uTexture", 0);
|
||||
mMeshes.back()->reallocateTexCoords(mMeshes.back()->getTexCoords());
|
||||
mesh->setTexture(":/textures/crate.png");
|
||||
mesh->setUniform("uTexture", 0);
|
||||
mesh->reallocateTexCoords(mesh->getTexCoords());
|
||||
|
||||
// Test drawing triangle with glDrawElements with texture coordinates
|
||||
mMeshes.push_back(new Qtk::MeshRenderer(
|
||||
mesh = addObject(new Qtk::MeshRenderer(
|
||||
"testTriangleElementsUV", Triangle(QTK_DRAW_ELEMENTS_NORMALS)));
|
||||
mMeshes.back()->getTransform().setTranslation(-2.5f, 0.0f, -1.0f);
|
||||
mMeshes.back()->setShaders(":/texture2d.vert", ":/texture2d.frag");
|
||||
mMeshes.back()->setTexture(":/crate.png");
|
||||
mMeshes.back()->setUniform("uTexture", 0);
|
||||
mMeshes.back()->reallocateTexCoords(mMeshes.back()->getTexCoords());
|
||||
mesh->getTransform().setTranslation(-2.5f, 0.0f, -1.0f);
|
||||
mesh->setShaders(":/shaders/texture2d.vert", ":/shaders/texture2d.frag");
|
||||
mesh->setTexture(":/textures/crate.png");
|
||||
mesh->setUniform("uTexture", 0);
|
||||
mesh->reallocateTexCoords(mesh->getTexCoords());
|
||||
}
|
||||
|
||||
void ExampleScene::draw() {
|
||||
void QtkScene::draw() {
|
||||
// WARNING: We must call the base class draw() function first.
|
||||
// + This will handle rendering core scene components like the Skybox.
|
||||
Scene::draw();
|
||||
|
||||
for(const auto & model : mModels) {
|
||||
model->draw();
|
||||
}
|
||||
|
||||
for(const auto & mesh : mMeshes) {
|
||||
mesh->draw();
|
||||
}
|
||||
|
||||
mTestPhong->bindShaders();
|
||||
mTestPhong->setUniform(
|
||||
"uModelInverseTransposed",
|
||||
|
@ -417,15 +400,13 @@ void ExampleScene::draw() {
|
|||
"uLightPosition",
|
||||
MeshRenderer::getInstance("phongLight")->getTransform().getTranslation());
|
||||
mTestPhong->setUniform(
|
||||
"uCameraPosition",
|
||||
ExampleScene::getCamera().getTransform().getTranslation());
|
||||
"uCameraPosition", QtkScene::getCamera().getTransform().getTranslation());
|
||||
mTestPhong->releaseShaders();
|
||||
mTestPhong->draw();
|
||||
|
||||
mTestAmbient->bindShaders();
|
||||
mTestAmbient->setUniform(
|
||||
"uCameraPosition",
|
||||
ExampleScene::getCamera().getTransform().getTranslation());
|
||||
"uCameraPosition", QtkScene::getCamera().getTransform().getTranslation());
|
||||
mTestAmbient->releaseShaders();
|
||||
mTestAmbient->draw();
|
||||
|
||||
|
@ -438,8 +419,7 @@ void ExampleScene::draw() {
|
|||
->getTransform()
|
||||
.getTranslation());
|
||||
mTestDiffuse->setUniform(
|
||||
"uCameraPosition",
|
||||
ExampleScene::getCamera().getTransform().getTranslation());
|
||||
"uCameraPosition", QtkScene::getCamera().getTransform().getTranslation());
|
||||
mTestDiffuse->releaseShaders();
|
||||
mTestDiffuse->draw();
|
||||
|
||||
|
@ -452,13 +432,12 @@ void ExampleScene::draw() {
|
|||
->getTransform()
|
||||
.getTranslation());
|
||||
mTestSpecular->setUniform(
|
||||
"uCameraPosition",
|
||||
ExampleScene::getCamera().getTransform().getTranslation());
|
||||
"uCameraPosition", QtkScene::getCamera().getTransform().getTranslation());
|
||||
mTestSpecular->releaseShaders();
|
||||
mTestSpecular->draw();
|
||||
}
|
||||
|
||||
void ExampleScene::update() {
|
||||
void QtkScene::update() {
|
||||
auto mySpartan = Model::getInstance("My spartan");
|
||||
mySpartan->getTransform().rotate(0.75f, 0.0f, 1.0f, 0.0f);
|
||||
|
||||
|
@ -471,13 +450,12 @@ void ExampleScene::update() {
|
|||
auto alien = Model::getInstance("alienTest");
|
||||
alien->setUniform("uLight.position", position);
|
||||
alien->setUniform(
|
||||
"uCameraPosition",
|
||||
ExampleScene::getCamera().getTransform().getTranslation());
|
||||
"uCameraPosition", QtkScene::getCamera().getTransform().getTranslation());
|
||||
auto posMatrix = alien->getTransform().toMatrix();
|
||||
alien->setUniform("uMVP.normalMatrix", posMatrix.normalMatrix());
|
||||
alien->setUniform("uMVP.model", posMatrix);
|
||||
alien->setUniform("uMVP.view", ExampleScene::getCamera().toMatrix());
|
||||
alien->setUniform("uMVP.projection", ExampleScene::getProjectionMatrix());
|
||||
alien->setUniform("uMVP.view", QtkScene::getCamera().toMatrix());
|
||||
alien->setUniform("uMVP.projection", QtkScene::getProjectionMatrix());
|
||||
alien->getTransform().rotate(0.75f, 0.0f, 1.0f, 0.0f);
|
||||
|
||||
position = MeshRenderer::getInstance("spartanTestLight")
|
||||
|
@ -486,13 +464,12 @@ void ExampleScene::update() {
|
|||
auto spartan = Model::getInstance("spartanTest");
|
||||
spartan->setUniform("uLight.position", position);
|
||||
spartan->setUniform(
|
||||
"uCameraPosition",
|
||||
ExampleScene::getCamera().getTransform().getTranslation());
|
||||
"uCameraPosition", QtkScene::getCamera().getTransform().getTranslation());
|
||||
posMatrix = spartan->getTransform().toMatrix();
|
||||
spartan->setUniform("uMVP.normalMatrix", posMatrix.normalMatrix());
|
||||
spartan->setUniform("uMVP.model", posMatrix);
|
||||
spartan->setUniform("uMVP.view", ExampleScene::getCamera().toMatrix());
|
||||
spartan->setUniform("uMVP.projection", ExampleScene::getProjectionMatrix());
|
||||
spartan->setUniform("uMVP.view", QtkScene::getCamera().toMatrix());
|
||||
spartan->setUniform("uMVP.projection", QtkScene::getProjectionMatrix());
|
||||
spartan->getTransform().rotate(0.75f, 0.0f, 1.0f, 0.0f);
|
||||
|
||||
auto phong = MeshRenderer::getInstance("testPhong");
|
||||
|
@ -502,13 +479,12 @@ void ExampleScene::update() {
|
|||
MeshRenderer::getInstance("testLight")->getTransform().getTranslation();
|
||||
phong->setUniform("uLight.position", position);
|
||||
phong->setUniform(
|
||||
"uCameraPosition",
|
||||
ExampleScene::getCamera().getTransform().getTranslation());
|
||||
"uCameraPosition", QtkScene::getCamera().getTransform().getTranslation());
|
||||
posMatrix = phong->getTransform().toMatrix();
|
||||
phong->setUniform("uMVP.normalMatrix", posMatrix.normalMatrix());
|
||||
phong->setUniform("uMVP.model", posMatrix);
|
||||
phong->setUniform("uMVP.view", ExampleScene::getCamera().toMatrix());
|
||||
phong->setUniform("uMVP.projection", ExampleScene::getProjectionMatrix());
|
||||
phong->setUniform("uMVP.view", QtkScene::getCamera().toMatrix());
|
||||
phong->setUniform("uMVP.projection", QtkScene::getProjectionMatrix());
|
||||
phong->releaseShaders();
|
||||
|
||||
// Rotate lighting example cubes
|
|
@ -1,7 +1,7 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
|
||||
## About: Classes for managing objects and data within a scene ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Example Qtk scene ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
|
@ -9,11 +9,7 @@
|
|||
#ifndef QTK_EXAMPLE_SCENE_H
|
||||
#define QTK_EXAMPLE_SCENE_H
|
||||
|
||||
#include <camera3d.h>
|
||||
#include <scene.h>
|
||||
#include <skybox.h>
|
||||
|
||||
#include <QMatrix4x4>
|
||||
#include <qtk/scene.h>
|
||||
|
||||
/**
|
||||
* Example scene using QtkWidget to render 3D models and simple geometry within
|
||||
|
@ -33,14 +29,15 @@
|
|||
*
|
||||
* To create your own Scene from scratch see Qtk::Scene.
|
||||
*/
|
||||
class ExampleScene : public Qtk::Scene {
|
||||
class QtkScene : public Qtk::SceneInterface {
|
||||
public:
|
||||
/***************************************************************************
|
||||
* Contructors / Destructors
|
||||
**************************************************************************/
|
||||
|
||||
ExampleScene();
|
||||
~ExampleScene();
|
||||
QtkScene(Qtk::Scene * scene);
|
||||
|
||||
~QtkScene();
|
||||
|
||||
/***************************************************************************
|
||||
* Inherited Public Overrides
|
||||
|
@ -50,6 +47,7 @@ class ExampleScene : public Qtk::Scene {
|
|||
* Initialize objects within the scene
|
||||
*/
|
||||
void init() override;
|
||||
|
||||
/**
|
||||
* Called when OpenGL repaints the widget.
|
||||
*/
|
|
@ -1,17 +1,27 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
|
||||
## About: Main window for Qt6 OpenGL widget application ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: QtkWidget for Qt desktop application ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
|
||||
#include <QKeyEvent>
|
||||
#include <QMimeData>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include <input.h>
|
||||
#include <mesh.h>
|
||||
#include <qtkwidget.h>
|
||||
#include <scene.h>
|
||||
#include <qtk/input.h>
|
||||
#include <qtk/scene.h>
|
||||
#include <qtk/shape.h>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include <qtk/input.h>
|
||||
#include <qtk/scene.h>
|
||||
#include <qtk/shape.h>
|
||||
|
||||
#include "debugconsole.h"
|
||||
#include "qtkmainwindow.h"
|
||||
#include "qtkwidget.h"
|
||||
|
||||
using namespace Qtk;
|
||||
|
||||
|
@ -19,17 +29,27 @@ using namespace Qtk;
|
|||
* Constructors, Destructors
|
||||
******************************************************************************/
|
||||
|
||||
QtkWidget::QtkWidget() : mScene(Q_NULLPTR), mDebugLogger(Q_NULLPTR) {
|
||||
initializeWidget();
|
||||
}
|
||||
QtkWidget::QtkWidget(QWidget * parent) : QtkWidget(parent, "QtkWidget") {}
|
||||
|
||||
QtkWidget::QtkWidget(QWidget * parent) :
|
||||
QOpenGLWidget(parent), mScene(Q_NULLPTR), mDebugLogger(Q_NULLPTR) {
|
||||
initializeWidget();
|
||||
}
|
||||
QtkWidget::QtkWidget(QWidget * parent, const QString & name) :
|
||||
QtkWidget(parent, name, Q_NULLPTR) {}
|
||||
|
||||
QtkWidget::QtkWidget(const QSurfaceFormat & format) :
|
||||
mScene(Q_NULLPTR), mDebugLogger(Q_NULLPTR) {
|
||||
QtkWidget::QtkWidget(QWidget * parent, const QString & name, Scene * scene) :
|
||||
QOpenGLWidget(parent), mDebugLogger(Q_NULLPTR),
|
||||
mConsole(new DebugConsole(this, name)), mScene(Q_NULLPTR) {
|
||||
setAcceptDrops(true);
|
||||
setScene(scene);
|
||||
setObjectName(name);
|
||||
QSurfaceFormat format;
|
||||
format.setRenderableType(QSurfaceFormat::OpenGL);
|
||||
format.setProfile(QSurfaceFormat::CoreProfile);
|
||||
format.setVersion(4, 6);
|
||||
// Set the number of samples used for glEnable(GL_MULTISAMPLING)
|
||||
format.setSamples(4);
|
||||
// Set the size of the depth bufer for glEnable(GL_DEPTH_TEST)
|
||||
format.setDepthBufferSize(16);
|
||||
// If QTK_DEBUG is set, enable debug context
|
||||
format.setOption(QSurfaceFormat::DebugContext);
|
||||
setFormat(format);
|
||||
setFocusPolicy(Qt::ClickFocus);
|
||||
}
|
||||
|
@ -40,16 +60,25 @@ QtkWidget::~QtkWidget() {
|
|||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Public Inherited Virtual Methods
|
||||
* Public Methods
|
||||
******************************************************************************/
|
||||
|
||||
QAction * QtkWidget::getActionToggleConsole() {
|
||||
auto action = new QAction(mScene->getSceneName() + " debug console");
|
||||
action->setCheckable(true);
|
||||
action->setChecked(mConsoleActive);
|
||||
action->setStatusTip("Add a debug console for this QtkWidget.");
|
||||
connect(action, &QAction::triggered, this, &QtkWidget::toggleConsole);
|
||||
return action;
|
||||
}
|
||||
|
||||
void QtkWidget::initializeGL() {
|
||||
initializeOpenGLFunctions();
|
||||
// Connect the frameSwapped signal to call the update() function
|
||||
connect(this, SIGNAL(frameSwapped()), this, SLOT(update()));
|
||||
|
||||
toggleConsole();
|
||||
// Initialize OpenGL debug context
|
||||
#ifdef QTK_DEBUG
|
||||
mDebugLogger = new QOpenGLDebugLogger(this);
|
||||
if(mDebugLogger->initialize()) {
|
||||
qDebug() << "GL_DEBUG Debug Logger" << mDebugLogger << "\n";
|
||||
|
@ -58,7 +87,6 @@ void QtkWidget::initializeGL() {
|
|||
SLOT(messageLogged(QOpenGLDebugMessage)));
|
||||
mDebugLogger->startLogging();
|
||||
}
|
||||
#endif // QTK_DEBUG
|
||||
|
||||
printContextInformation();
|
||||
|
||||
|
@ -87,10 +115,91 @@ void QtkWidget::paintGL() {
|
|||
}
|
||||
}
|
||||
|
||||
void QtkWidget::setScene(Scene * scene) {
|
||||
if(mScene != Q_NULLPTR) {
|
||||
delete mScene;
|
||||
connect(
|
||||
scene, &Scene::sceneUpdated, MainWindow::getMainWindow(),
|
||||
&MainWindow::refreshScene);
|
||||
}
|
||||
|
||||
mScene = scene;
|
||||
if(mScene != Q_NULLPTR) {
|
||||
mConsole->setTitle(mScene->getSceneName());
|
||||
} else {
|
||||
mConsole->setTitle("Null Scene");
|
||||
}
|
||||
}
|
||||
|
||||
void QtkWidget::toggleConsole() {
|
||||
if(mConsoleActive) {
|
||||
mConsole->setHidden(true);
|
||||
mConsoleActive = false;
|
||||
} else {
|
||||
MainWindow::getMainWindow()->addDockWidget(
|
||||
Qt::DockWidgetArea::BottomDockWidgetArea, mConsole);
|
||||
mConsole->setHidden(false);
|
||||
mConsoleActive = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Protected Slots
|
||||
* Protected Methods
|
||||
******************************************************************************/
|
||||
|
||||
void QtkWidget::dragEnterEvent(QDragEnterEvent * event) {
|
||||
if(event->mimeData()->hasFormat("text/plain")) {
|
||||
event->acceptProposedAction();
|
||||
}
|
||||
}
|
||||
|
||||
void QtkWidget::dropEvent(QDropEvent * event) {
|
||||
mConsole->sendLog(event->mimeData()->text());
|
||||
auto urls = event->mimeData()->urls();
|
||||
if(!urls.isEmpty()) {
|
||||
if(urls.size() > 1) {
|
||||
qDebug() << "Cannot accept drop of multiple files.";
|
||||
event->ignore();
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Support other object types.
|
||||
auto url = urls.front();
|
||||
if(url.fileName().endsWith(".obj")) {
|
||||
mScene->loadModel(url);
|
||||
event->acceptProposedAction();
|
||||
} else {
|
||||
qDebug() << "Unsupported file type: " + url.fileName() + "\n";
|
||||
event->ignore();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QtkWidget::keyPressEvent(QKeyEvent * event) {
|
||||
if(event->isAutoRepeat()) {
|
||||
// Do not repeat input while a key is held down
|
||||
event->ignore();
|
||||
} else {
|
||||
Input::registerKeyPress(event->key());
|
||||
}
|
||||
}
|
||||
|
||||
void QtkWidget::keyReleaseEvent(QKeyEvent * event) {
|
||||
if(event->isAutoRepeat()) {
|
||||
event->ignore();
|
||||
} else {
|
||||
Input::registerKeyRelease(event->key());
|
||||
}
|
||||
}
|
||||
|
||||
void QtkWidget::mousePressEvent(QMouseEvent * event) {
|
||||
Input::registerMousePress(event->button());
|
||||
}
|
||||
|
||||
void QtkWidget::mouseReleaseEvent(QMouseEvent * event) {
|
||||
Input::registerMouseRelease(event->button());
|
||||
}
|
||||
|
||||
void QtkWidget::update() {
|
||||
updateCameraInput();
|
||||
|
||||
|
@ -104,19 +213,24 @@ void QtkWidget::update() {
|
|||
void QtkWidget::messageLogged(const QOpenGLDebugMessage & msg) {
|
||||
QString error;
|
||||
|
||||
DebugContext context;
|
||||
// Format based on severity
|
||||
switch(msg.severity()) {
|
||||
case QOpenGLDebugMessage::NotificationSeverity:
|
||||
error += "--";
|
||||
context = Status;
|
||||
break;
|
||||
case QOpenGLDebugMessage::HighSeverity:
|
||||
error += "!!";
|
||||
context = Fatal;
|
||||
break;
|
||||
case QOpenGLDebugMessage::MediumSeverity:
|
||||
error += "!~";
|
||||
context = Error;
|
||||
break;
|
||||
case QOpenGLDebugMessage::LowSeverity:
|
||||
error += "~~";
|
||||
context = Warn;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -159,58 +273,54 @@ void QtkWidget::messageLogged(const QOpenGLDebugMessage & msg) {
|
|||
}
|
||||
#undef CASE
|
||||
|
||||
error += ")";
|
||||
qDebug() << qPrintable(error) << "\n" << qPrintable(msg.message()) << "\n";
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Protected Methods
|
||||
******************************************************************************/
|
||||
|
||||
void QtkWidget::keyPressEvent(QKeyEvent * event) {
|
||||
if(event->isAutoRepeat()) {
|
||||
// Do not repeat input while a key is held down
|
||||
event->ignore();
|
||||
} else {
|
||||
Input::registerKeyPress(event->key());
|
||||
}
|
||||
}
|
||||
|
||||
void QtkWidget::keyReleaseEvent(QKeyEvent * event) {
|
||||
if(event->isAutoRepeat()) {
|
||||
event->ignore();
|
||||
} else {
|
||||
Input::registerKeyRelease(event->key());
|
||||
}
|
||||
}
|
||||
|
||||
void QtkWidget::mousePressEvent(QMouseEvent * event) {
|
||||
Input::registerMousePress(event->button());
|
||||
}
|
||||
|
||||
void QtkWidget::mouseReleaseEvent(QMouseEvent * event) {
|
||||
Input::registerMouseRelease(event->button());
|
||||
error += ")\n" + msg.message() + "\n";
|
||||
qDebug() << qPrintable(error);
|
||||
sendLog("(OpenGL) " + error.replace("\n", "\n(OpenGL) "), context);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Private Methods
|
||||
******************************************************************************/
|
||||
|
||||
void QtkWidget::initializeWidget() {
|
||||
QSurfaceFormat format;
|
||||
format.setRenderableType(QSurfaceFormat::OpenGL);
|
||||
format.setProfile(QSurfaceFormat::CoreProfile);
|
||||
format.setVersion(4, 6);
|
||||
// Set the number of samples used for glEnable(GL_MULTISAMPLING)
|
||||
format.setSamples(4);
|
||||
// Set the size of the depth bufer for glEnable(GL_DEPTH_TEST)
|
||||
format.setDepthBufferSize(16);
|
||||
// If QTK_DEBUG is set, enable debug context
|
||||
#ifdef QTK_DEBUG
|
||||
format.setOption(QSurfaceFormat::DebugContext);
|
||||
#endif
|
||||
setFormat(format);
|
||||
setFocusPolicy(Qt::ClickFocus);
|
||||
void QtkWidget::teardownGL() { /* Nothing to teardown yet... */
|
||||
}
|
||||
|
||||
void QtkWidget::updateCameraInput() {
|
||||
Input::update();
|
||||
// Camera Transformation
|
||||
if(Input::buttonPressed(Qt::LeftButton)
|
||||
|| Input::buttonPressed(Qt::RightButton)) {
|
||||
static const float transSpeed = 0.1f;
|
||||
static const float rotSpeed = 0.5f;
|
||||
|
||||
// Handle rotations
|
||||
Scene::getCamera().getTransform().rotate(
|
||||
-rotSpeed * Input::mouseDelta().x(), Camera3D::LocalUp);
|
||||
Scene::getCamera().getTransform().rotate(
|
||||
-rotSpeed * Input::mouseDelta().y(), Scene::getCamera().getRight());
|
||||
|
||||
// Handle translations
|
||||
QVector3D translation;
|
||||
if(Input::keyPressed(Qt::Key_W)) {
|
||||
translation += Scene::getCamera().getForward();
|
||||
}
|
||||
if(Input::keyPressed(Qt::Key_S)) {
|
||||
translation -= Scene::getCamera().getForward();
|
||||
}
|
||||
if(Input::keyPressed(Qt::Key_A)) {
|
||||
translation -= Scene::getCamera().getRight();
|
||||
}
|
||||
if(Input::keyPressed(Qt::Key_D)) {
|
||||
translation += Scene::getCamera().getRight();
|
||||
}
|
||||
if(Input::keyPressed(Qt::Key_Q)) {
|
||||
translation -= Scene::getCamera().getUp() / 2.0f;
|
||||
}
|
||||
if(Input::keyPressed(Qt::Key_E)) {
|
||||
translation += Scene::getCamera().getUp() / 2.0f;
|
||||
}
|
||||
Scene::getCamera().getTransform().translate(transSpeed * translation);
|
||||
}
|
||||
}
|
||||
|
||||
void QtkWidget::printContextInformation() {
|
||||
|
@ -239,46 +349,9 @@ void QtkWidget::printContextInformation() {
|
|||
}
|
||||
#undef CASE
|
||||
|
||||
// qPrintable() will print our QString w/o quotes around it.
|
||||
qDebug() << qPrintable(glType) << qPrintable(glVersion) << "("
|
||||
<< qPrintable(glProfile) << ")"
|
||||
<< "\nOpenGL Vendor: " << qPrintable(glVendor)
|
||||
<< "\nRendering Device: " << qPrintable(glRenderer) << "\n";
|
||||
}
|
||||
|
||||
void QtkWidget::updateCameraInput() {
|
||||
Input::update();
|
||||
// Camera Transformation
|
||||
if(Input::buttonPressed(Qt::RightButton)) {
|
||||
static const float transSpeed = 0.1f;
|
||||
static const float rotSpeed = 0.5f;
|
||||
|
||||
// Handle rotations
|
||||
Scene::getCamera().getTransform().rotate(
|
||||
-rotSpeed * Input::mouseDelta().x(), Camera3D::LocalUp);
|
||||
Scene::getCamera().getTransform().rotate(
|
||||
-rotSpeed * Input::mouseDelta().y(), Scene::getCamera().right());
|
||||
|
||||
// Handle translations
|
||||
QVector3D translation;
|
||||
if(Input::keyPressed(Qt::Key_W)) {
|
||||
translation += Scene::getCamera().forward();
|
||||
}
|
||||
if(Input::keyPressed(Qt::Key_S)) {
|
||||
translation -= Scene::getCamera().forward();
|
||||
}
|
||||
if(Input::keyPressed(Qt::Key_A)) {
|
||||
translation -= Scene::getCamera().right();
|
||||
}
|
||||
if(Input::keyPressed(Qt::Key_D)) {
|
||||
translation += Scene::getCamera().right();
|
||||
}
|
||||
if(Input::keyPressed(Qt::Key_Q)) {
|
||||
translation -= Scene::getCamera().up() / 2.0f;
|
||||
}
|
||||
if(Input::keyPressed(Qt::Key_E)) {
|
||||
translation += Scene::getCamera().up() / 2.0f;
|
||||
}
|
||||
Scene::getCamera().getTransform().translate(transSpeed * translation);
|
||||
}
|
||||
auto message = QString(glType) + glVersion + "(" + glProfile + ")"
|
||||
+ "\nOpenGL Vendor: " + glVendor
|
||||
+ "\nRendering Device: " + glRenderer;
|
||||
qDebug() << qPrintable(message);
|
||||
sendLog("(OpenGL) " + message.replace("\n", "\n(OpenGL) "), Status);
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
|
||||
## About: Main window for Qt6 OpenGL widget application ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: QtkWidget for Qt desktop application ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
|
@ -10,22 +10,26 @@
|
|||
|
||||
#include <iostream>
|
||||
|
||||
#include <QDockWidget>
|
||||
#include <QMatrix4x4>
|
||||
#include <QOpenGLDebugLogger>
|
||||
#include <QOpenGLFunctions>
|
||||
#include <QOpenGLWidget>
|
||||
#include <QPlainTextEdit>
|
||||
|
||||
#include <qtkapi.h>
|
||||
#include <scene.h>
|
||||
#include <qtk/qtkapi.h>
|
||||
#include <qtk/scene.h>
|
||||
|
||||
namespace Qtk {
|
||||
class DebugConsole;
|
||||
|
||||
/**
|
||||
* QtkWidget class to define required QOpenGLWidget functionality.
|
||||
*
|
||||
* This object has a Scene attached which manages the objects to render.
|
||||
* Client input is passed through this widget to control the camera view.
|
||||
*/
|
||||
class QTKAPI QtkWidget : public QOpenGLWidget, protected QOpenGLFunctions {
|
||||
class QtkWidget : public QOpenGLWidget, protected QOpenGLFunctions {
|
||||
Q_OBJECT;
|
||||
|
||||
public:
|
||||
|
@ -33,40 +37,41 @@ namespace Qtk {
|
|||
* Contructors / Destructors
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* Default ctor will configure a QSurfaceFormat with default settings.
|
||||
*/
|
||||
QtkWidget();
|
||||
|
||||
/**
|
||||
* Qt Designer will call this ctor when creating this widget as a child.
|
||||
*
|
||||
* @param parent The parent QWidget
|
||||
* @param parent Pointer to a parent widget for this QtkWidget or nullptr.
|
||||
*/
|
||||
explicit QtkWidget(QWidget * parent);
|
||||
explicit QtkWidget(QWidget * parent = nullptr);
|
||||
|
||||
/**
|
||||
* Allow constructing the widget with a preconfigured QSurfaceFormat.
|
||||
* Default construct a QtkWidget.
|
||||
*
|
||||
* @param format QSurfaceFormat already configured by the caller.
|
||||
* @param parent Pointer to a parent widget or nullptr if no parent.
|
||||
* @param name An objectName for the new QtkWidget.
|
||||
*/
|
||||
explicit QtkWidget(const QSurfaceFormat & format);
|
||||
explicit QtkWidget(QWidget * parent, const QString & name);
|
||||
|
||||
~QtkWidget() override;
|
||||
/**
|
||||
* Construct a custom QtkWidget.
|
||||
*
|
||||
* @param parent Pointer to a parent widget or nullptr if no parent.
|
||||
* @param name An objectName for the new QtkWidget.
|
||||
* @param scene Pointer to a custom class inheriting from Qtk::Scene.
|
||||
*/
|
||||
QtkWidget(QWidget * parent, const QString & name, Qtk::Scene * scene);
|
||||
|
||||
~QtkWidget();
|
||||
|
||||
private:
|
||||
/*************************************************************************
|
||||
* Private Methods
|
||||
* Public Methods
|
||||
************************************************************************/
|
||||
|
||||
// clang-format off
|
||||
void teardownGL() { /* Nothing to teardown yet... */ }
|
||||
// clang-format on
|
||||
|
||||
public:
|
||||
/*************************************************************************
|
||||
* Public Inherited Virtual Methods
|
||||
************************************************************************/
|
||||
/**
|
||||
* Constructs a QAction to hide / show this DebugConsole.
|
||||
* @return QAction to toggle visibility of this DebugConsole.
|
||||
*/
|
||||
QAction * getActionToggleConsole();
|
||||
|
||||
/**
|
||||
* Called when the widget is first constructed.
|
||||
|
@ -90,66 +95,119 @@ namespace Qtk {
|
|||
* Accessors
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* @return The active scene being viewed in this widget.
|
||||
*/
|
||||
inline Qtk::Scene * getScene() { return mScene; }
|
||||
|
||||
/**
|
||||
* @return Pointer to the QOpenGLDebugLogger attached to this widget.
|
||||
*/
|
||||
inline QOpenGLDebugLogger * getOpenGLDebugLogger() {
|
||||
return mDebugLogger;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* Setters
|
||||
************************************************************************/
|
||||
|
||||
inline void setScene(Qtk::Scene * scene) {
|
||||
delete mScene;
|
||||
mScene = scene;
|
||||
}
|
||||
/**
|
||||
* @param scene The new scene to view.
|
||||
*/
|
||||
void setScene(Qtk::Scene * scene);
|
||||
|
||||
protected slots:
|
||||
/*************************************************************************
|
||||
* Qt Slots
|
||||
************************************************************************/
|
||||
public slots:
|
||||
|
||||
/**
|
||||
* Called when the `frameSwapped` signal is caught.
|
||||
* See definition of initializeGL()
|
||||
* Toggle visibility of the DebugConsole associated with this QtkWidget.
|
||||
*/
|
||||
void update();
|
||||
void toggleConsole();
|
||||
|
||||
#ifdef QTK_DEBUG
|
||||
signals:
|
||||
/**
|
||||
* Called when the `messageLogged` signal is caught.
|
||||
* See definition of initializeGL()
|
||||
*
|
||||
* @param msg The message logged.
|
||||
* Log a message to the DebugConsole associated with this widget.
|
||||
* @param message The message to log.
|
||||
* @param context The context of the log message.
|
||||
*/
|
||||
static void messageLogged(const QOpenGLDebugMessage & msg);
|
||||
#endif
|
||||
void sendLog(const QString & message, DebugContext context = Status);
|
||||
|
||||
// TODO: Use this signal in treeview and toolbox to update object
|
||||
// properties
|
||||
void objectFocusChanged(const QString objectName);
|
||||
|
||||
protected:
|
||||
/*************************************************************************
|
||||
* Protected Methods
|
||||
************************************************************************/
|
||||
|
||||
void dragEnterEvent(QDragEnterEvent * event) override;
|
||||
|
||||
void dropEvent(QDropEvent * event) override;
|
||||
|
||||
/**
|
||||
* @param event Key press event to update camera input manager.
|
||||
*/
|
||||
void keyPressEvent(QKeyEvent * event) override;
|
||||
|
||||
/**
|
||||
* @param event Key release event to update camera input manager.
|
||||
*/
|
||||
void keyReleaseEvent(QKeyEvent * event) override;
|
||||
|
||||
/**
|
||||
* @param event Mouse button press event to update camera input manager.
|
||||
*/
|
||||
void mousePressEvent(QMouseEvent * event) override;
|
||||
|
||||
/**
|
||||
* @param event Mouse button release event to update camera input manager.
|
||||
*/
|
||||
void mouseReleaseEvent(QMouseEvent * event) override;
|
||||
|
||||
protected slots:
|
||||
/**
|
||||
* Called when the `frameSwapped` signal is caught.
|
||||
* See definition of initializeGL()
|
||||
*/
|
||||
void update();
|
||||
|
||||
/**
|
||||
* Called when the `messageLogged` signal is caught.
|
||||
* See definition of initializeGL()
|
||||
* https://doc.qt.io/qt-6/qopengldebuglogger.html#signals
|
||||
*
|
||||
* @param msg The message logged.
|
||||
*/
|
||||
void messageLogged(const QOpenGLDebugMessage & msg);
|
||||
|
||||
private:
|
||||
/*************************************************************************
|
||||
* Private Methods
|
||||
************************************************************************/
|
||||
|
||||
void initializeWidget();
|
||||
/**
|
||||
* Deconstruct any resources we have allocated for this widget.
|
||||
*/
|
||||
void teardownGL();
|
||||
|
||||
/**
|
||||
* Callback function to update input for camera controls
|
||||
*/
|
||||
static void updateCameraInput();
|
||||
|
||||
#ifdef QTK_DEBUG
|
||||
/**
|
||||
* Prints OpenGL context information at start of debug session.
|
||||
*/
|
||||
void printContextInformation();
|
||||
QOpenGLDebugLogger * mDebugLogger;
|
||||
#endif
|
||||
|
||||
/*************************************************************************
|
||||
* Private Members
|
||||
************************************************************************/
|
||||
|
||||
QOpenGLDebugLogger * mDebugLogger;
|
||||
Qtk::Scene * mScene;
|
||||
Qtk::DebugConsole * mConsole;
|
||||
bool mConsoleActive = false;
|
||||
};
|
||||
} // namespace Qtk
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef QTK_RESOURCES_H_IN_H
|
||||
#define QTK_RESOURCES_H_IN_H
|
||||
|
||||
// Not currently in use, but will be in the future.
|
||||
|
||||
#endif // QTK_RESOURCES_H_IN_H
|
|
@ -0,0 +1,149 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Toolbox plugin for object details and options ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
################################################################################
|
||||
*/
|
||||
|
||||
#include "toolbox.h"
|
||||
#include "qtkmainwindow.h"
|
||||
#include "ui_toolbox.h"
|
||||
|
||||
#include <QFormLayout>
|
||||
#include <QLabel>
|
||||
|
||||
using namespace Qtk;
|
||||
|
||||
ToolBox::ToolBox(QWidget * parent) : QDockWidget(parent), ui(new Ui::ToolBox) {
|
||||
ui->setupUi(this);
|
||||
setMinimumWidth(350);
|
||||
}
|
||||
|
||||
void ToolBox::updateFocus(const QString & name) {
|
||||
auto object =
|
||||
MainWindow::getMainWindow()->getQtkWidget()->getScene()->getObject(name);
|
||||
if(object != Q_NULLPTR) {
|
||||
removePages();
|
||||
createPageProperties(object);
|
||||
createPageShader(object);
|
||||
}
|
||||
}
|
||||
|
||||
ToolBox::~ToolBox() {
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void ToolBox::removePages() {
|
||||
// Remove all existing pages.
|
||||
for(size_t i = 0; i < ui->toolBox->count(); i++) {
|
||||
delete ui->toolBox->widget(i);
|
||||
ui->toolBox->removeItem(i);
|
||||
}
|
||||
}
|
||||
|
||||
void ToolBox::createPageProperties(const Object * object) {
|
||||
auto transform = object->getTransform();
|
||||
auto type = object->getType();
|
||||
auto * widget = new QWidget;
|
||||
ui->toolBox->addItem(widget, "Properties");
|
||||
ui->toolBox->setCurrentWidget(widget);
|
||||
|
||||
auto * layout = new QFormLayout;
|
||||
layout->addRow(
|
||||
new QLabel(tr("Name:")), new QLabel(object->getName().c_str()));
|
||||
|
||||
layout->addRow(
|
||||
new QLabel(tr("Type:")),
|
||||
new QLabel(type == Object::Type::QTK_MESH ? "Mesh" : "Model"));
|
||||
|
||||
auto rowLayout = new QHBoxLayout;
|
||||
rowLayout->addWidget(new QLabel(tr("Translation:")));
|
||||
int minWidth = 75;
|
||||
for(size_t i = 0; i < 3; i++) {
|
||||
auto spinBox = new QDoubleSpinBox;
|
||||
spinBox->setMinimum(std::numeric_limits<double>::lowest());
|
||||
spinBox->setSingleStep(0.1);
|
||||
spinBox->setValue(transform.getTranslation()[i]);
|
||||
spinBox->setFixedWidth(minWidth);
|
||||
rowLayout->addWidget(spinBox);
|
||||
|
||||
if(i == 0) {
|
||||
connect(
|
||||
spinBox, &QDoubleSpinBox::valueChanged, object,
|
||||
&Object::setTranslationX);
|
||||
} else if(i == 1) {
|
||||
connect(
|
||||
spinBox, &QDoubleSpinBox::valueChanged, object,
|
||||
&Object::setTranslationY);
|
||||
} else if(i == 2) {
|
||||
connect(
|
||||
spinBox, &QDoubleSpinBox::valueChanged, object,
|
||||
&Object::setTranslationZ);
|
||||
}
|
||||
}
|
||||
layout->addRow(rowLayout);
|
||||
|
||||
rowLayout = new QHBoxLayout;
|
||||
rowLayout->addWidget(new QLabel(tr("Scale:")));
|
||||
for(size_t i = 0; i < 3; i++) {
|
||||
auto spinBox = new QDoubleSpinBox;
|
||||
spinBox->setMinimum(std::numeric_limits<double>::lowest());
|
||||
spinBox->setSingleStep(0.1);
|
||||
spinBox->setValue(transform.getScale()[i]);
|
||||
spinBox->setFixedWidth(minWidth);
|
||||
rowLayout->addWidget(spinBox);
|
||||
|
||||
if(i == 0) {
|
||||
connect(
|
||||
spinBox, &QDoubleSpinBox::valueChanged, object, &Object::setScaleX);
|
||||
} else if(i == 1) {
|
||||
connect(
|
||||
spinBox, &QDoubleSpinBox::valueChanged, object, &Object::setScaleY);
|
||||
} else if(i == 2) {
|
||||
connect(
|
||||
spinBox, &QDoubleSpinBox::valueChanged, object, &Object::setScaleZ);
|
||||
}
|
||||
}
|
||||
layout->addRow(rowLayout);
|
||||
widget->setLayout(layout);
|
||||
}
|
||||
|
||||
void ToolBox::createPageShader(const Object * object) {
|
||||
// Shaders page.
|
||||
auto widget = new QWidget;
|
||||
ui->toolBox->addItem(widget, "Shaders");
|
||||
auto mainLayout = new QFormLayout;
|
||||
auto rowLayout = new QHBoxLayout;
|
||||
rowLayout->addWidget(new QLabel("Vertex Shader:"));
|
||||
rowLayout->addWidget(new QLabel(object->getVertexShader().c_str()));
|
||||
mainLayout->addRow(rowLayout);
|
||||
|
||||
auto shaderView = new QTextEdit;
|
||||
shaderView->setReadOnly(true);
|
||||
auto vertexFile = QFile(object->getVertexShader().c_str());
|
||||
if(vertexFile.exists()) {
|
||||
vertexFile.open(QIODeviceBase::ReadOnly);
|
||||
shaderView->setText(vertexFile.readAll());
|
||||
vertexFile.close();
|
||||
mainLayout->addRow(shaderView);
|
||||
}
|
||||
|
||||
rowLayout = new QHBoxLayout;
|
||||
rowLayout->addWidget(new QLabel("Fragment Shader:"));
|
||||
rowLayout->addWidget(new QLabel(object->getFragmentShader().c_str()));
|
||||
mainLayout->addRow(rowLayout);
|
||||
|
||||
shaderView = new QTextEdit;
|
||||
shaderView->setReadOnly(true);
|
||||
auto fragmentfile = QFile(object->getFragmentShader().c_str());
|
||||
if(fragmentfile.exists()) {
|
||||
fragmentfile.open(QIODeviceBase::ReadOnly);
|
||||
shaderView->setText(fragmentfile.readAll());
|
||||
fragmentfile.close();
|
||||
mainLayout->addRow(shaderView);
|
||||
}
|
||||
|
||||
widget->setLayout(mainLayout);
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Toolbox plugin for object details and options ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
################################################################################
|
||||
*/
|
||||
|
||||
#ifndef TOOLBOX_H
|
||||
#define TOOLBOX_H
|
||||
|
||||
#include <QDesignerExportWidget>
|
||||
#include <QDockWidget>
|
||||
#include <QDoubleSpinBox>
|
||||
#include <QGroupBox>
|
||||
|
||||
|
||||
#include "qtk/scene.h"
|
||||
|
||||
namespace Ui {
|
||||
class ToolBox;
|
||||
}
|
||||
|
||||
namespace Qtk {
|
||||
class ToolBox : public QDockWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/*************************************************************************
|
||||
* Contructors / Destructors
|
||||
*************************************************************************/
|
||||
|
||||
explicit ToolBox(QWidget * parent = nullptr);
|
||||
|
||||
~ToolBox();
|
||||
|
||||
void removePages();
|
||||
|
||||
void createPageProperties(const Object * object);
|
||||
|
||||
void createPageShader(const Object * object);
|
||||
|
||||
void updateFocus(const QString & name);
|
||||
|
||||
|
||||
private:
|
||||
/*************************************************************************
|
||||
* Private Members
|
||||
************************************************************************/
|
||||
|
||||
Ui::ToolBox * ui;
|
||||
};
|
||||
} // namespace Qtk
|
||||
|
||||
#endif // TOOLBOX_H
|
|
@ -0,0 +1,83 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ToolBox</class>
|
||||
<widget class="QDockWidget" name="ToolBox">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>86</width>
|
||||
<height>167</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Object Details</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="dockWidgetContents">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QToolBox" name="toolBox">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="page_properties">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>382</width>
|
||||
<height>201</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<attribute name="label">
|
||||
<string>Properties</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
<widget class="QWidget" name="page_shaders">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>382</width>
|
||||
<height>201</height>
|
||||
</rect>
|
||||
</property>
|
||||
<attribute name="label">
|
||||
<string>Shaders</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -0,0 +1,72 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: TreeView plugin for scene hierarchy ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
################################################################################
|
||||
*/
|
||||
|
||||
#include "treeview.h"
|
||||
#include "qtkmainwindow.h"
|
||||
#include "ui_treeview.h"
|
||||
|
||||
/*******************************************************************************
|
||||
* Constructors, Destructors
|
||||
******************************************************************************/
|
||||
|
||||
Qtk::TreeView::TreeView(QWidget * parent) :
|
||||
QDockWidget(parent), ui(new Ui::TreeView) {
|
||||
ui->setupUi(this);
|
||||
connect(
|
||||
ui->treeWidget, &QTreeWidget::itemDoubleClicked, this,
|
||||
&TreeView::itemFocus);
|
||||
}
|
||||
|
||||
Qtk::TreeView::~TreeView() {
|
||||
delete ui;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Public Methods
|
||||
******************************************************************************/
|
||||
|
||||
void Qtk::TreeView::updateView(const Qtk::Scene * scene) {
|
||||
ui->treeWidget->clear();
|
||||
ui->treeWidget->setColumnCount(1);
|
||||
mSceneName = scene->getSceneName();
|
||||
auto objects = scene->getObjects();
|
||||
for(const auto & object : objects) {
|
||||
auto item =
|
||||
new QTreeWidgetItem(QStringList(QString(object->getName().c_str())));
|
||||
ui->treeWidget->insertTopLevelItem(0, item);
|
||||
}
|
||||
}
|
||||
|
||||
void Qtk::TreeView::itemFocus(QTreeWidgetItem * item, int column) {
|
||||
QString name = item->text(column);
|
||||
auto scene = MainWindow::getMainWindow()->getQtkWidget()->getScene();
|
||||
auto & transform = scene->getCamera().getTransform();
|
||||
auto object = scene->getObject(name);
|
||||
Transform3D * objectTransform;
|
||||
// If the object is a mesh or model, focus the camera on it.
|
||||
if(object == Q_NULLPTR) {
|
||||
qDebug() << "Attempt to get non-existing object with name '" << name
|
||||
<< "'\n";
|
||||
} else if(object->getType() == Object::QTK_MESH) {
|
||||
objectTransform = &dynamic_cast<MeshRenderer *>(object)->getTransform();
|
||||
} else if(object->getType() == Object::QTK_MODEL) {
|
||||
objectTransform = &dynamic_cast<Model *>(object)->getTransform();
|
||||
}
|
||||
auto focusScale = objectTransform->getScale();
|
||||
float width = focusScale.x() / 2.0f;
|
||||
float height = focusScale.y() / 2.0f;
|
||||
QVector3D pos = objectTransform->getTranslation();
|
||||
// pos.setX(pos.x() + width);
|
||||
pos.setY(pos.y() + height);
|
||||
transform.setTranslation(pos);
|
||||
transform.translate(0.0f, 0.0f, 3.0f);
|
||||
|
||||
// Emit signal from qtk widget for new object focus. Triggers GUI updates.
|
||||
emit MainWindow::getMainWindow()->getQtkWidget()->objectFocusChanged(name);
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: TreeView plugin for scene hierarchy ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
################################################################################
|
||||
*/
|
||||
|
||||
#ifndef TREEVIEW_H
|
||||
#define TREEVIEW_H
|
||||
|
||||
#include <QDesignerCustomWidgetInterface>
|
||||
#include <QDesignerExportWidget>
|
||||
#include <QDockWidget>
|
||||
|
||||
#include <qtk/scene.h>
|
||||
#include <QTreeWidgetItem>
|
||||
|
||||
namespace Ui {
|
||||
class TreeView;
|
||||
}
|
||||
|
||||
namespace Qtk {
|
||||
class TreeView : public QDockWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/*************************************************************************
|
||||
* Constructors / Destructors
|
||||
************************************************************************/
|
||||
|
||||
explicit TreeView(QWidget * parent = nullptr);
|
||||
|
||||
~TreeView();
|
||||
|
||||
/*************************************************************************
|
||||
* Public Methods
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* Updates the QTreeWidget with all objects within the scene.
|
||||
* @param scene The scene to load objects from.
|
||||
*/
|
||||
void updateView(const Scene * scene);
|
||||
|
||||
public slots:
|
||||
/**
|
||||
* Focus the camera on an item when it is double clicked.
|
||||
* Triggered by QTreeWidget::itemDoubleClicked signal.
|
||||
*
|
||||
* @param item The item that was double clicked
|
||||
* @param column The column of the item that was double clicked.
|
||||
* This param is currently not used but required for this signal.
|
||||
*/
|
||||
void itemFocus(QTreeWidgetItem * item, int column);
|
||||
|
||||
private:
|
||||
/*************************************************************************
|
||||
* Private Members
|
||||
************************************************************************/
|
||||
|
||||
Ui::TreeView * ui;
|
||||
|
||||
/**
|
||||
* The name of the scene last loaded by this TreeWidget.
|
||||
* Used to load object data from a target scene.
|
||||
*/
|
||||
QString mSceneName;
|
||||
};
|
||||
} // namespace Qtk
|
||||
|
||||
#endif // TREEVIEW_H
|
|
@ -0,0 +1,44 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TreeView</class>
|
||||
<widget class="QDockWidget" name="TreeView">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Scene Tree View</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="dockWidgetContents">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QTreeWidget" name="treeWidget">
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="indentation">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="sortingEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="headerVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string notr="true">1</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -0,0 +1,98 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Generic Qt Designer widget plugin ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
################################################################################
|
||||
*/
|
||||
|
||||
#include <QIcon>
|
||||
#include <QtPlugin>
|
||||
#include <utility>
|
||||
|
||||
#include <qtk/qtkapi.h>
|
||||
|
||||
#include "widgetplugin.h"
|
||||
|
||||
/*******************************************************************************
|
||||
* Constructors, Destructors
|
||||
******************************************************************************/
|
||||
|
||||
WidgetPlugin::WidgetPlugin(
|
||||
QString group, QString class_name, QString include,
|
||||
WidgetPlugin::Factory factory) :
|
||||
m_group(std::move(group)),
|
||||
m_className(std::move(class_name)), m_includeFile(std::move(include)),
|
||||
m_factory(std::move(factory)), m_objectName(class_name) {}
|
||||
|
||||
WidgetPlugin::WidgetPlugin(QObject * parent) : QObject(parent) {}
|
||||
|
||||
/*******************************************************************************
|
||||
* Public Methods
|
||||
******************************************************************************/
|
||||
|
||||
QString WidgetPlugin::group() const {
|
||||
return m_group;
|
||||
}
|
||||
|
||||
QString WidgetPlugin::name() const {
|
||||
return m_className;
|
||||
}
|
||||
|
||||
QString WidgetPlugin::includeFile() const {
|
||||
return m_includeFile;
|
||||
}
|
||||
|
||||
QWidget * WidgetPlugin::createWidget(QWidget * parent) {
|
||||
return m_factory(parent);
|
||||
}
|
||||
|
||||
QString WidgetPlugin::toolTip() const {
|
||||
return QStringLiteral("A custom widget tool tip.");
|
||||
}
|
||||
|
||||
QString WidgetPlugin::whatsThis() const {
|
||||
return QStringLiteral("Custom widget what's this?");
|
||||
}
|
||||
|
||||
QIcon WidgetPlugin::icon() const {
|
||||
return Qtk::getIcon();
|
||||
}
|
||||
|
||||
bool WidgetPlugin::isContainer() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WidgetPlugin::isInitialized() const {
|
||||
return m_initialized;
|
||||
}
|
||||
|
||||
void WidgetPlugin::initialize(QDesignerFormEditorInterface *) {
|
||||
if(m_initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_initialized = true;
|
||||
}
|
||||
QString WidgetPlugin::domXml() const {
|
||||
return
|
||||
"<ui language=\"c++\">\n"
|
||||
" <widget class=\"" + m_className + "\" name=\"" + m_objectName + "\">\n"
|
||||
" <property name=\"geometry\">\n"
|
||||
" <rect>\n"
|
||||
" <x>0</x>\n"
|
||||
" <y>0</y>\n"
|
||||
" <width>100</width>\n"
|
||||
" <height>100</height>\n"
|
||||
" </rect>\n"
|
||||
" </property>\n"
|
||||
" <property name=\"toolTip\" >\n"
|
||||
" <string>" + toolTip() + "</string>\n"
|
||||
" </property>\n"
|
||||
" <property name=\"whatsThis\" >\n"
|
||||
" <string>" + whatsThis() + "</string>\n"
|
||||
" </property>\n"
|
||||
" </widget>\n"
|
||||
"</ui>\n";
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Generic Qt Designer widget plugin ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
################################################################################
|
||||
*/
|
||||
|
||||
#ifndef QTK_WIDGETPLUGIN_H
|
||||
#define QTK_WIDGETPLUGIN_H
|
||||
|
||||
#include <QDesignerCustomWidgetInterface>
|
||||
#include <QDesignerExportWidget>
|
||||
|
||||
class QDESIGNER_WIDGET_EXPORT WidgetPlugin :
|
||||
public QObject,
|
||||
public QDesignerCustomWidgetInterface {
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(QDesignerCustomWidgetInterface)
|
||||
|
||||
using Factory = std::function<QWidget *(QWidget *)>;
|
||||
|
||||
public:
|
||||
/***************************************************************************
|
||||
* Contructors / Destructors
|
||||
**************************************************************************/
|
||||
|
||||
WidgetPlugin(
|
||||
QString group, QString class_name, QString include, Factory factory);
|
||||
|
||||
explicit WidgetPlugin(QObject * parent = nullptr);
|
||||
|
||||
~WidgetPlugin() = default;
|
||||
|
||||
/***************************************************************************
|
||||
* Public Methods
|
||||
**************************************************************************/
|
||||
|
||||
/**
|
||||
* @return The name of the group to which this widget belongs.
|
||||
*/
|
||||
[[nodiscard]] QString group() const override;
|
||||
|
||||
/**
|
||||
* Must return the _class name_ of the widget.
|
||||
*
|
||||
* @return The class name for the associated widget.
|
||||
*/
|
||||
[[nodiscard]] QString name() const override;
|
||||
|
||||
/**
|
||||
* If this path changes for a custom widget, it must be removed and added
|
||||
* back in Qt Designer for the XML surrounding this value to be regenerated.
|
||||
*
|
||||
* See the `<customwidget>` XML in any `.ui` file using a custom widget.
|
||||
*
|
||||
* @return Path to the include file for UIC to use when generating code.
|
||||
*/
|
||||
[[nodiscard]] QString includeFile() const override;
|
||||
|
||||
/**
|
||||
* @param parent Parent widget to the new instance of this widget.
|
||||
* @return A new instance of this custom widget.
|
||||
*/
|
||||
[[nodiscard]] QWidget * createWidget(QWidget * parent) override;
|
||||
|
||||
/**
|
||||
* @return Short description used in Qt Designer tool tips.
|
||||
*/
|
||||
[[nodiscard]] QString toolTip() const override;
|
||||
|
||||
/**
|
||||
* @return Widget description used in `What's this?` within Qt Creator.
|
||||
*/
|
||||
[[nodiscard]] QString whatsThis() const override;
|
||||
|
||||
/**
|
||||
* @return Icon used to represent the widget in Qt Designer's GUI.
|
||||
*/
|
||||
[[nodiscard]] QIcon icon() const override;
|
||||
|
||||
/**
|
||||
* Whether or not this widget should act as a container for other widgets.
|
||||
*
|
||||
* @return True if this custom widget is meant to be a container.
|
||||
*/
|
||||
[[nodiscard]] bool isContainer() const override;
|
||||
|
||||
/**
|
||||
* @return True if this widget has been initialized.
|
||||
*/
|
||||
[[nodiscard]] bool isInitialized() const override;
|
||||
|
||||
/**
|
||||
* Initializes an instance of this custom widget.
|
||||
* @param core
|
||||
*/
|
||||
void initialize(QDesignerFormEditorInterface * core) override;
|
||||
|
||||
/**
|
||||
* Default XML for an instance of this custom widget within a `.ui` file.
|
||||
*
|
||||
* Any property available for the widget in Qt Designer can be set using XML
|
||||
* properties, as seen here with `toolTip` and `whatsThis`.
|
||||
*
|
||||
* @return XML inserted for each instance of this widget.
|
||||
*/
|
||||
[[nodiscard]] QString domXml() const override;
|
||||
|
||||
private:
|
||||
/***************************************************************************
|
||||
* Private Members
|
||||
**************************************************************************/
|
||||
|
||||
bool m_initialized = false;
|
||||
QString m_group;
|
||||
QString m_className;
|
||||
QString m_objectName;
|
||||
QString m_includeFile;
|
||||
Factory m_factory;
|
||||
};
|
||||
|
||||
#endif // QTK_WIDGETPLUGIN_H
|
|
@ -0,0 +1,43 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Collection of widget plugins for Qt Designer ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
################################################################################
|
||||
*/
|
||||
|
||||
#include "widgetplugincollection.h"
|
||||
#include "debugconsole.h"
|
||||
#include "qtkwidget.h"
|
||||
#include "toolbox.h"
|
||||
#include "treeview.h"
|
||||
#include "widgetplugin.h"
|
||||
|
||||
/*******************************************************************************
|
||||
* Constructors, Destructors
|
||||
******************************************************************************/
|
||||
|
||||
WidgetPluginCollection::WidgetPluginCollection(QObject * parent) :
|
||||
QObject(parent), m_collectionName("Qtk Widget Collection") {
|
||||
m_collection = {
|
||||
new WidgetPlugin(
|
||||
m_collectionName, "Qtk::QtkWidget", "qtkwidget.h",
|
||||
[](QWidget * parent) { return new Qtk::QtkWidget(parent); }),
|
||||
new WidgetPlugin(
|
||||
m_collectionName, "Qtk::TreeView", "treeview.h",
|
||||
[](QWidget * parent) { return new Qtk::TreeView(parent); }),
|
||||
new WidgetPlugin(
|
||||
m_collectionName, "Qtk::ToolBox", "toolbox.h",
|
||||
[](QWidget * parent) { return new Qtk::ToolBox(parent); }),
|
||||
};
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Public Methods
|
||||
******************************************************************************/
|
||||
|
||||
QList<QDesignerCustomWidgetInterface *> WidgetPluginCollection::customWidgets()
|
||||
const {
|
||||
return m_collection;
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Collection of widget plugins for Qt Designer ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
################################################################################
|
||||
*/
|
||||
|
||||
#ifndef QTK_WIDGETPLUGINCOLLECTION_H
|
||||
#define QTK_WIDGETPLUGINCOLLECTION_H
|
||||
|
||||
#include <QDesignerCustomWidgetCollectionInterface>
|
||||
|
||||
class WidgetPluginCollection :
|
||||
public QObject,
|
||||
public QDesignerCustomWidgetCollectionInterface {
|
||||
Q_OBJECT
|
||||
// Since we're exporting a collection, this is the only plugin metadata
|
||||
// needed. We don't need this for-each widget in the collection.
|
||||
Q_PLUGIN_METADATA(IID "com.Klips.WidgetPluginCollection")
|
||||
// Tell Qt Object system that we're implementing an interface.
|
||||
Q_INTERFACES(QDesignerCustomWidgetCollectionInterface)
|
||||
|
||||
public:
|
||||
/***************************************************************************
|
||||
* Contructors / Destructors
|
||||
**************************************************************************/
|
||||
|
||||
explicit WidgetPluginCollection(QObject * parent = nullptr);
|
||||
|
||||
/***************************************************************************
|
||||
* Public Methods
|
||||
**************************************************************************/
|
||||
|
||||
/**
|
||||
* @return QList of all custom widgets pointers.
|
||||
*/
|
||||
[[nodiscard]] QList<QDesignerCustomWidgetInterface *> customWidgets() const;
|
||||
|
||||
private:
|
||||
/***************************************************************************
|
||||
* Private Members
|
||||
**************************************************************************/
|
||||
|
||||
QList<QDesignerCustomWidgetInterface *> m_collection;
|
||||
QString m_collectionName;
|
||||
};
|
||||
|
||||
#endif // QTK_WIDGETPLUGINCOLLECTION_H
|
89
src/input.h
|
@ -1,89 +0,0 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
|
||||
## About: Input class from tutorials followed at trentreed.net ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
|
||||
#ifndef QTOPENGL_INPUT_H
|
||||
#define QTOPENGL_INPUT_H
|
||||
|
||||
#include <QPoint>
|
||||
#include <Qt>
|
||||
|
||||
#include <qtkapi.h>
|
||||
#include <qtkwidget.h>
|
||||
|
||||
namespace Qtk {
|
||||
class QTKAPI Input {
|
||||
public:
|
||||
/*************************************************************************
|
||||
* Typedefs
|
||||
************************************************************************/
|
||||
friend class Qtk::QtkWidget;
|
||||
|
||||
/**
|
||||
* Possible key states
|
||||
*/
|
||||
enum InputState {
|
||||
InputInvalid,
|
||||
InputRegistered,
|
||||
InputUnregistered,
|
||||
InputTriggered,
|
||||
InputPressed,
|
||||
InputReleased
|
||||
};
|
||||
|
||||
/*************************************************************************
|
||||
* Public Methods
|
||||
************************************************************************/
|
||||
|
||||
// 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:
|
||||
/*************************************************************************
|
||||
* Private Methods
|
||||
************************************************************************/
|
||||
|
||||
// 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
|
||||
|
||||
#endif // QTOPENGL_INPUT_H
|
|
@ -1,137 +0,0 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
|
||||
## About: MeshRenderer class for quick object creation and drawing ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
#ifndef QTK_MESHRENDERER_H
|
||||
#define QTK_MESHRENDERER_H
|
||||
|
||||
#include <mesh.h>
|
||||
#include <object.h>
|
||||
#include <qtkapi.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace Qtk {
|
||||
class QTKAPI MeshRenderer : public Object {
|
||||
public:
|
||||
/*************************************************************************
|
||||
* Typedefs
|
||||
************************************************************************/
|
||||
|
||||
/* Static QHash of all mesh objects within the scene. */
|
||||
typedef QHash<QString, MeshRenderer *> MeshManager;
|
||||
|
||||
/*************************************************************************
|
||||
* Constructors / Destructors
|
||||
************************************************************************/
|
||||
|
||||
// Delegate constructors
|
||||
MeshRenderer(
|
||||
const char * name, Vertices vertices, Indices indices,
|
||||
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() override;
|
||||
|
||||
/*************************************************************************
|
||||
* Public Methods
|
||||
************************************************************************/
|
||||
|
||||
void init();
|
||||
void draw();
|
||||
|
||||
inline void enableAttributeArray(int location) {
|
||||
ShaderBindScope lock(&mProgram, mBound);
|
||||
mVAO.bind();
|
||||
mProgram.enableAttributeArray(location);
|
||||
mVAO.release();
|
||||
}
|
||||
|
||||
void reallocateTexCoords(const TexCoords & t, unsigned dims = 2);
|
||||
|
||||
void reallocateNormals(const Normals & n, unsigned dims = 3);
|
||||
|
||||
/*************************************************************************
|
||||
* Setters
|
||||
************************************************************************/
|
||||
|
||||
// Draw types like GL_TRIANGLES, GL_POINTS, GL_LINES, etc
|
||||
void setDrawType(int drawType) { mDrawType = drawType; }
|
||||
|
||||
// Shader settings
|
||||
inline void setShaderVertex(const std::string & vert) {
|
||||
mVertexShader = vert;
|
||||
}
|
||||
|
||||
inline void setShaderFragment(const std::string & frag) {
|
||||
mFragmentShader = frag;
|
||||
}
|
||||
|
||||
void setShaders(const std::string & vert, const std::string & frag);
|
||||
|
||||
template <typename T> inline void setUniform(int location, T value) {
|
||||
ShaderBindScope lock(&mProgram, mBound);
|
||||
mProgram.setUniformValue(location, value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void setUniform(const char * location, T value) {
|
||||
ShaderBindScope lock(&mProgram, mBound);
|
||||
mProgram.setUniformValue(location, value);
|
||||
}
|
||||
|
||||
// Set MVP matrix using this Object's transform
|
||||
// + View and projection provided by MainWidget static members
|
||||
void setUniformMVP(
|
||||
const char * model = "uModel", const char * view = "uView",
|
||||
const char * projection = "uProjection");
|
||||
|
||||
// These functions modify data stored in a VBO
|
||||
// + After calling them, the VBO will need to be reallocated
|
||||
void setShape(const Shape & value) override;
|
||||
void setColor(const QVector3D & color);
|
||||
|
||||
void setAttributeBuffer(
|
||||
int location, GLenum type, int offset, int tupleSize,
|
||||
int stride = 0) {
|
||||
ShaderBindScope lock(&mProgram, mBound);
|
||||
mVAO.bind();
|
||||
mProgram.setAttributeBuffer(location, type, offset, tupleSize, stride);
|
||||
mVAO.release();
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* Accessors
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* Retrieve a mesh by name stored within static QHash private member
|
||||
* @param name The name of the MeshRenderer we want to retrieve.
|
||||
* @return Pointer to the MeshRenderer, or nullptr if not found.
|
||||
*/
|
||||
static MeshRenderer * getInstance(const QString & name);
|
||||
|
||||
Transform3D & getTransform() { return mTransform; }
|
||||
|
||||
private:
|
||||
/*************************************************************************
|
||||
* Private Members
|
||||
************************************************************************/
|
||||
|
||||
static MeshManager sInstances;
|
||||
|
||||
int mDrawType {};
|
||||
std::string mVertexShader {}, mFragmentShader {};
|
||||
};
|
||||
} // namespace Qtk
|
||||
|
||||
#endif // QTK_MESHRENDERER_H
|
262
src/model.h
|
@ -1,262 +0,0 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
|
||||
## About: Model classes for importing with Assimp ##
|
||||
## From following tutorials on learnopengl.com ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
#ifndef QTK_MODEL_H
|
||||
#define QTK_MODEL_H
|
||||
|
||||
// QT
|
||||
#include <QObject>
|
||||
#include <QOpenGLBuffer>
|
||||
#include <QOpenGLFunctions>
|
||||
#include <QOpenGLShaderProgram>
|
||||
#include <QOpenGLTexture>
|
||||
#include <QOpenGLVertexArrayObject>
|
||||
|
||||
// Assimp
|
||||
#include <assimp/postprocess.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/Importer.hpp>
|
||||
|
||||
// QTK
|
||||
#include <object.h>
|
||||
#include <qtkapi.h>
|
||||
#include <transform3D.h>
|
||||
|
||||
namespace Qtk {
|
||||
/**
|
||||
* 3D models will store this data for each vertex in geometry.
|
||||
*/
|
||||
struct QTKAPI ModelVertex {
|
||||
QVector3D mPosition;
|
||||
QVector3D mNormal;
|
||||
QVector2D mTextureCoord;
|
||||
QVector3D mTangent;
|
||||
QVector3D mBitangent;
|
||||
};
|
||||
|
||||
/**
|
||||
* Struct to store model textures. 3D Models may have multiple.
|
||||
*/
|
||||
struct QTKAPI ModelTexture {
|
||||
GLuint mID {};
|
||||
QOpenGLTexture * mTexture {};
|
||||
std::string mType {};
|
||||
std::string mPath {};
|
||||
};
|
||||
|
||||
class Model;
|
||||
|
||||
/**
|
||||
* Mesh class specialized for storing 3D model data.
|
||||
* Eventually this can be consolidated into a more generic class.
|
||||
*/
|
||||
class QTKAPI ModelMesh : protected QOpenGLFunctions {
|
||||
public:
|
||||
/*************************************************************************
|
||||
* Typedefs
|
||||
************************************************************************/
|
||||
|
||||
friend Model;
|
||||
typedef std::vector<ModelVertex> Vertices;
|
||||
typedef std::vector<GLuint> Indices;
|
||||
typedef std::vector<ModelTexture> Textures;
|
||||
|
||||
/*************************************************************************
|
||||
* Constructors, Destructors
|
||||
************************************************************************/
|
||||
|
||||
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() = default;
|
||||
|
||||
/*************************************************************************
|
||||
* Public Methods
|
||||
************************************************************************/
|
||||
|
||||
inline void draw() { draw(*mProgram); }
|
||||
|
||||
void draw(QOpenGLShaderProgram & shader);
|
||||
|
||||
/*************************************************************************
|
||||
* Public Members
|
||||
************************************************************************/
|
||||
|
||||
Vertices mVertices {};
|
||||
Indices mIndices {};
|
||||
Textures mTextures {};
|
||||
Transform3D mTransform;
|
||||
|
||||
private:
|
||||
/*************************************************************************
|
||||
* Private Methods
|
||||
************************************************************************/
|
||||
|
||||
void initMesh(const char * vert, const char * frag);
|
||||
|
||||
/*************************************************************************
|
||||
* Private Members
|
||||
************************************************************************/
|
||||
|
||||
QOpenGLBuffer *mVBO, *mEBO;
|
||||
QOpenGLVertexArrayObject * mVAO;
|
||||
QOpenGLShaderProgram * mProgram;
|
||||
};
|
||||
|
||||
/**
|
||||
* Model object that has a ModelMesh.
|
||||
* Top-level object that represents 3D models stored within a scene.
|
||||
*/
|
||||
class QTKAPI Model : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/*************************************************************************
|
||||
* Typedefs
|
||||
************************************************************************/
|
||||
|
||||
/* ModelManager typedef that will manage global model access. */
|
||||
typedef QHash<QString, Model *> ModelManager;
|
||||
|
||||
/*************************************************************************
|
||||
* Constructors, Destructors
|
||||
************************************************************************/
|
||||
|
||||
// Default model shaders are provided but we can override them in the ctor
|
||||
inline Model(
|
||||
const char * name, const char * path,
|
||||
const char * vertexShader = ":/model-basic.vert",
|
||||
const char * fragmentShader = ":/model-basic.frag") :
|
||||
mName(name),
|
||||
mModelPath(path), mVertexShader(vertexShader),
|
||||
mFragmentShader(fragmentShader) {
|
||||
loadModel(path);
|
||||
}
|
||||
|
||||
inline ~Model() override { mManager.remove(mName); }
|
||||
|
||||
/*************************************************************************
|
||||
* Public Methods
|
||||
************************************************************************/
|
||||
|
||||
void draw();
|
||||
void draw(QOpenGLShaderProgram & shader);
|
||||
|
||||
/**
|
||||
* Flip a texture associated with this model
|
||||
*
|
||||
* @param fileName The name of the texture to flip as it is stored on disk
|
||||
* @param flipX Flip the texture along the X axis
|
||||
* @param flipY Flip the texture along the Y axis
|
||||
*/
|
||||
void flipTexture(
|
||||
const std::string & fileName, bool flipX = false, bool flipY = true);
|
||||
|
||||
/*************************************************************************
|
||||
* Setters
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* Sets a uniform value
|
||||
*
|
||||
* @tparam T The type of the value we are settings
|
||||
* @param location The uniform location
|
||||
* @param value The value to assign to the uniform
|
||||
*/
|
||||
template <typename T> void setUniform(const char * location, T value) {
|
||||
for(auto & mesh : mMeshes) {
|
||||
mesh.mProgram->bind();
|
||||
mesh.mProgram->setUniformValue(location, value);
|
||||
mesh.mProgram->release();
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* Accessors
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* Accessor function for retrieving a ModelMesh globally.
|
||||
* The mesh is retrieved from the mManager private member.
|
||||
*
|
||||
* @param name The name of the model to load as it was constructed.
|
||||
* @return Pointer to the model stored within the scene.
|
||||
*/
|
||||
static Model * getInstance(const char * name);
|
||||
|
||||
Transform3D & getTransform() { return mTransform; }
|
||||
|
||||
private:
|
||||
/*************************************************************************
|
||||
* Private Methods
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* Loads a model in .obj, .fbx, .gltf, and other formats.
|
||||
* For a full list of formats see assimp documentation:
|
||||
* https://github.com/assimp/assimp/blob/master/doc/Fileformats.md
|
||||
*
|
||||
* Models should not be loaded into Qt resource system.
|
||||
* Instead pass an *absolute* path to this function.
|
||||
* Relative paths will break if Qtk is executed from different locations.
|
||||
*
|
||||
* Models can also be loaded from the `qtk/resource` directory using qrc
|
||||
* format loadModel(":/models/backpack/backpack.obj").
|
||||
* This does not use Qt resource system, it just provides similar syntax
|
||||
* for accessing files within the same `resources/` directory.
|
||||
*
|
||||
* See resourcemanager.h for more information on how this works.
|
||||
*
|
||||
* @param path Absolute path to a model in .obj or another format accepted
|
||||
* by assimp.
|
||||
*/
|
||||
void loadModel(const std::string & path);
|
||||
|
||||
void processNode(aiNode * node, const aiScene * scene);
|
||||
|
||||
ModelMesh processMesh(aiMesh * mesh, const aiScene * scene);
|
||||
|
||||
ModelMesh::Textures loadMaterialTextures(
|
||||
aiMaterial * mat, aiTextureType type, const std::string & typeName);
|
||||
|
||||
void sortModels();
|
||||
|
||||
/*************************************************************************
|
||||
* Private Members
|
||||
************************************************************************/
|
||||
|
||||
/* The position of this model in 3D space */
|
||||
Transform3D mTransform;
|
||||
|
||||
/* Static QHash used to store and access models globally. */
|
||||
static ModelManager mManager;
|
||||
|
||||
/* Container to store N loaded textures for this model. */
|
||||
ModelMesh::Textures mTexturesLoaded {};
|
||||
/* Container to store N loaded meshes for this model. */
|
||||
std::vector<ModelMesh> mMeshes {};
|
||||
/* The directory this model and it's textures are stored. */
|
||||
std::string mDirectory {};
|
||||
/* File names for shaders and 3D model on disk. */
|
||||
const char *mVertexShader, *mFragmentShader, *mModelPath;
|
||||
/* Name of the model object within the scene. */
|
||||
const char * mName;
|
||||
};
|
||||
} // namespace Qtk
|
||||
|
||||
#endif // QTK_MODEL_H
|
|
@ -0,0 +1,79 @@
|
|||
################################################################################
|
||||
## Project for working with OpenGL and Qt6 widgets ##
|
||||
## ##
|
||||
## Author: Shaun Reed | Contact: shaunrd0@gmail.com | URL: www.shaunreed.com ##
|
||||
## All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
################################################################################
|
||||
|
||||
################################################################################
|
||||
# Qtk Library
|
||||
################################################################################
|
||||
set(
|
||||
QTK_LIBRARY_PUBLIC_HEADERS
|
||||
camera3d.h
|
||||
input.h
|
||||
meshrenderer.h
|
||||
model.h
|
||||
modelmesh.h
|
||||
object.h
|
||||
qtkapi.h
|
||||
qtkiostream.h
|
||||
qtkiosystem.h
|
||||
scene.h
|
||||
shape.h
|
||||
skybox.h
|
||||
texture.h
|
||||
transform3D.h
|
||||
)
|
||||
|
||||
set(
|
||||
QTK_LIBRARY_SOURCES
|
||||
camera3d.cpp
|
||||
input.cpp
|
||||
meshrenderer.cpp
|
||||
model.cpp
|
||||
modelmesh.cpp
|
||||
object.cpp
|
||||
qtkiostream.cpp
|
||||
qtkiosystem.cpp
|
||||
scene.cpp
|
||||
shape.cpp
|
||||
skybox.cpp
|
||||
texture.cpp
|
||||
transform3D.cpp
|
||||
)
|
||||
|
||||
qt6_add_big_resources(QTK_LIBRARY_SOURCES "${QTK_RESOURCES}/resources.qrc")
|
||||
qt_add_library(qtk_library STATIC EXCLUDE_FROM_ALL)
|
||||
target_sources(qtk_library PRIVATE ${QTK_LIBRARY_SOURCES})
|
||||
target_sources(
|
||||
qtk_library PUBLIC
|
||||
FILE_SET HEADERS
|
||||
BASE_DIRS $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/src>
|
||||
BASE_DIRS $<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/include>
|
||||
FILES ${QTK_LIBRARY_PUBLIC_HEADERS}
|
||||
)
|
||||
|
||||
if(QTK_DEBUG)
|
||||
target_compile_definitions(qtk_library PUBLIC QTK_DEBUG)
|
||||
endif()
|
||||
|
||||
set_target_properties(
|
||||
qtk_library PROPERTIES
|
||||
VERSION ${PROJECT_VERSION}
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
qtk_library PUBLIC
|
||||
Qt6::Core Qt6::OpenGLWidgets Qt6::Widgets
|
||||
)
|
||||
|
||||
if(QTK_SUBMODULES OR NOT QTK_ASSIMP_NEW_INTERFACE)
|
||||
target_link_libraries(qtk_library PUBLIC assimp)
|
||||
elseif(QTK_ASSIMP_NEW_INTERFACE)
|
||||
target_link_libraries(qtk_library PUBLIC assimp::assimp)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(qtk_library PUBLIC OpenGL::GL)
|
||||
endif()
|
|
@ -1,24 +1,27 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Fly camera class from tutorials followed at trentreed.net ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
|
||||
#include <camera3d.h>
|
||||
#include "camera3d.h"
|
||||
|
||||
using namespace Qtk;
|
||||
|
||||
/*******************************************************************************
|
||||
* Static Public Constants
|
||||
******************************************************************************/
|
||||
|
||||
const QVector3D Camera3D::LocalForward(0.0f, 0.0f, -1.0f);
|
||||
const QVector3D Camera3D::LocalUp(0.0f, 1.0f, 0.0f);
|
||||
const QVector3D Camera3D::LocalRight(1.0f, 0.0f, 0.0f);
|
||||
|
||||
/*******************************************************************************
|
||||
* Accessors
|
||||
* Public Methods
|
||||
******************************************************************************/
|
||||
|
||||
// Produces worldToView matrix
|
||||
const QMatrix4x4 & Camera3D::toMatrix() {
|
||||
mWorld.setToIdentity();
|
||||
// Qt6 renamed QMatrix4x4::conjugate() to conjugated()
|
|
@ -1,6 +1,6 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Fly camera class from tutorials followed at trentreed.net ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
|
@ -11,14 +11,14 @@
|
|||
|
||||
#include <QDebug>
|
||||
|
||||
#include <qtkapi.h>
|
||||
#include <transform3D.h>
|
||||
#include "qtkapi.h"
|
||||
#include "transform3D.h"
|
||||
|
||||
namespace Qtk {
|
||||
class QTKAPI Camera3D {
|
||||
public:
|
||||
/*************************************************************************
|
||||
* Constants
|
||||
* Static Public Constants
|
||||
************************************************************************/
|
||||
|
||||
static const QVector3D LocalForward;
|
||||
|
@ -29,39 +29,56 @@ namespace Qtk {
|
|||
* Accessors
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* @return Transform3D associated with this camera.
|
||||
*/
|
||||
inline Transform3D & getTransform() { return mTransform; }
|
||||
|
||||
/**
|
||||
* @return Current translation of the camera as a QVector3D.
|
||||
*/
|
||||
[[nodiscard]] inline const QVector3D & getTranslation() const {
|
||||
return mTransform.getTranslation();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Current rotation of this camera as a QQuaternion.
|
||||
*/
|
||||
[[nodiscard]] inline const QQuaternion & getRotation() const {
|
||||
return mTransform.getRotation();
|
||||
}
|
||||
|
||||
const QMatrix4x4 & toMatrix();
|
||||
|
||||
// Queries
|
||||
[[nodiscard]] inline QVector3D forward() const {
|
||||
/**
|
||||
* @return QVector3D for the forward vector of the camera.
|
||||
*/
|
||||
[[nodiscard]] inline QVector3D getForward() const {
|
||||
return mTransform.getRotation().rotatedVector(LocalForward);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline QVector3D right() const {
|
||||
/**
|
||||
* @return QVector3D for the right vector of the camera.
|
||||
*/
|
||||
[[nodiscard]] inline QVector3D getRight() const {
|
||||
return mTransform.getRotation().rotatedVector(LocalRight);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline QVector3D up() const {
|
||||
/**
|
||||
* @return QVector3D for the up vector of the camera.
|
||||
*/
|
||||
[[nodiscard]] inline QVector3D getUp() const {
|
||||
return mTransform.getRotation().rotatedVector(LocalUp);
|
||||
}
|
||||
|
||||
private:
|
||||
/*************************************************************************
|
||||
* Private Members
|
||||
* Public Methods
|
||||
************************************************************************/
|
||||
|
||||
Transform3D mTransform;
|
||||
QMatrix4x4 mWorld;
|
||||
/**
|
||||
* @return World To View matrix for this camera.
|
||||
*/
|
||||
const QMatrix4x4 & toMatrix();
|
||||
|
||||
private:
|
||||
/*************************************************************************
|
||||
* Private Methods
|
||||
************************************************************************/
|
||||
|
@ -70,6 +87,13 @@ namespace Qtk {
|
|||
friend QDataStream & operator<<(QDataStream & out, Camera3D & transform);
|
||||
friend QDataStream & operator>>(QDataStream & in, Camera3D & transform);
|
||||
#endif
|
||||
|
||||
/*************************************************************************
|
||||
* Private Members
|
||||
************************************************************************/
|
||||
|
||||
Transform3D mTransform;
|
||||
QMatrix4x4 mWorld;
|
||||
};
|
||||
|
||||
// Qt Streams
|
|
@ -1,6 +1,6 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Input class from tutorials followed at trentreed.net ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
|
@ -11,13 +11,20 @@
|
|||
|
||||
#include <QCursor>
|
||||
|
||||
#include <input.h>
|
||||
#include "input.h"
|
||||
|
||||
using namespace Qtk;
|
||||
|
||||
/*******************************************************************************
|
||||
* Static Helper Structs
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* Struct to hold key input state. When a key is pressed we construct this and
|
||||
* store it within a KeyContainer (or ButtonContainer for mouse buttons).
|
||||
*
|
||||
* @tparam T Qt::Key or Qt::MouseButton input type for this instance.
|
||||
*/
|
||||
template <typename T> struct InputInstance : std::pair<T, Input::InputState> {
|
||||
typedef std::pair<T, Input::InputState> base_class;
|
||||
|
||||
|
@ -28,6 +35,7 @@ template <typename T> struct InputInstance : std::pair<T, Input::InputState> {
|
|||
inline InputInstance(T value, Input::InputState state) :
|
||||
base_class(value, state) {}
|
||||
|
||||
// Allows use of std::find to search for a key's InputInstance
|
||||
inline bool operator==(const InputInstance & rhs) const {
|
||||
return this->first == rhs.first;
|
||||
}
|
||||
|
@ -53,14 +61,44 @@ static QPoint sg_mouseDelta;
|
|||
* Static Inline Helper Functions
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* Search for the InputInstance of a key.
|
||||
*
|
||||
* @param value The key to search for.
|
||||
* @return Iterator to the found element or the end iterator if not found.
|
||||
*/
|
||||
static inline KeyContainer::iterator FindKey(Qt::Key value) {
|
||||
return std::find(sg_keyInstances.begin(), sg_keyInstances.end(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for the InputInstance of a mouse button.
|
||||
*
|
||||
* @param value The mouse button to search for.
|
||||
* @return Iterator to the found element or the end iterator if not found.
|
||||
*/
|
||||
static inline ButtonContainer::iterator FindButton(Qt::MouseButton value) {
|
||||
return std::find(sg_buttonInstances.begin(), sg_buttonInstances.end(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check an InputInstance for the InputReleased state.
|
||||
*
|
||||
* @tparam TPair KeyInstance or ButtonInstance
|
||||
* @param instance Instance to check for InputReleased state.
|
||||
* @return True if the InputInstance is in the released state.
|
||||
*/
|
||||
template <typename TPair>
|
||||
static inline bool CheckReleased(const TPair & instance) {
|
||||
return instance.second == Input::InputReleased;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an InputInstance and applies transitions if needed.
|
||||
*
|
||||
* @tparam TPair KeyInstance or ButtonInstance.
|
||||
* @param instance The InputInstance to update.
|
||||
*/
|
||||
template <typename TPair> static inline void UpdateStates(TPair & instance) {
|
||||
switch(instance.second) {
|
||||
case Input::InputRegistered:
|
||||
|
@ -77,11 +115,12 @@ template <typename TPair> static inline void UpdateStates(TPair & instance) {
|
|||
}
|
||||
}
|
||||
|
||||
template <typename TPair>
|
||||
static inline bool CheckReleased(const TPair & instance) {
|
||||
return instance.second == Input::InputReleased;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates InputInstance containers to track input state.
|
||||
*
|
||||
* @tparam Container The type of container, KeyContainer or ButtonContainer.
|
||||
* @param container The InputInstance container to update.
|
||||
*/
|
||||
template <typename Container> static inline void Update(Container & container) {
|
||||
typedef typename Container::iterator Iter;
|
||||
typedef typename Container::value_type TPair;
|
||||
|
@ -96,27 +135,9 @@ template <typename Container> static inline void Update(Container & container) {
|
|||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Input Implementation
|
||||
* Static Public Methods
|
||||
******************************************************************************/
|
||||
|
||||
Input::InputState Input::keyState(Qt::Key k) {
|
||||
auto it = FindKey(k);
|
||||
return (it != sg_keyInstances.end()) ? it->second : InputInvalid;
|
||||
}
|
||||
|
||||
Input::InputState Input::buttonState(Qt::MouseButton k) {
|
||||
auto it = FindButton(k);
|
||||
return (it != sg_buttonInstances.end()) ? it->second : InputInvalid;
|
||||
}
|
||||
|
||||
QPoint Input::mousePosition() {
|
||||
return QCursor::pos();
|
||||
}
|
||||
|
||||
QPoint Input::mouseDelta() {
|
||||
return sg_mouseDelta;
|
||||
}
|
||||
|
||||
void Input::update() {
|
||||
// Update Mouse Delta
|
||||
sg_mousePrevPosition = sg_mouseCurrPosition;
|
||||
|
@ -160,3 +181,21 @@ void Input::reset() {
|
|||
sg_keyInstances.clear();
|
||||
sg_buttonInstances.clear();
|
||||
}
|
||||
|
||||
Input::InputState Input::keyState(Qt::Key k) {
|
||||
auto it = FindKey(k);
|
||||
return (it != sg_keyInstances.end()) ? it->second : InputInvalid;
|
||||
}
|
||||
|
||||
Input::InputState Input::buttonState(Qt::MouseButton k) {
|
||||
auto it = FindButton(k);
|
||||
return (it != sg_buttonInstances.end()) ? it->second : InputInvalid;
|
||||
}
|
||||
|
||||
QPoint Input::mousePosition() {
|
||||
return QCursor::pos();
|
||||
}
|
||||
|
||||
QPoint Input::mouseDelta() {
|
||||
return sg_mouseDelta;
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Input class from tutorials followed at trentreed.net ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
|
||||
#ifndef QTOPENGL_INPUT_H
|
||||
#define QTOPENGL_INPUT_H
|
||||
|
||||
#include <QPoint>
|
||||
#include <Qt>
|
||||
|
||||
#include "qtkapi.h"
|
||||
|
||||
namespace Qtk {
|
||||
class QTKAPI Input {
|
||||
public:
|
||||
/*************************************************************************
|
||||
* Typedefs
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* Possible key states. See UpdateStates for state transitions.
|
||||
*
|
||||
* When a key is pressed we enter states Registered->Triggered->Pressed.
|
||||
* InputTriggered state will be met only once if a key is pressed or held.
|
||||
* While a key is held down the state is InputPressed.
|
||||
*
|
||||
* When a key is released we enter InputUnregistered->InputReleased
|
||||
* When an active InputInstance for a key has this state it is removed.
|
||||
*/
|
||||
enum InputState {
|
||||
InputInvalid,
|
||||
InputRegistered, // Initial state. Transitions to InputTriggered
|
||||
InputUnregistered, // Transition to InputReleased
|
||||
InputTriggered, // Transition to InputPressed
|
||||
InputPressed, // State of a key while it is held down.
|
||||
InputReleased // Released keys are removed from state containers.
|
||||
};
|
||||
|
||||
/*************************************************************************
|
||||
* Public Methods
|
||||
************************************************************************/
|
||||
|
||||
//
|
||||
// State updating.
|
||||
|
||||
/**
|
||||
* Update state for all mouse button and key instances.
|
||||
*/
|
||||
static void update();
|
||||
|
||||
/**
|
||||
* @param key Key to set InputRegistered state.
|
||||
*/
|
||||
static void registerKeyPress(int key);
|
||||
|
||||
/**
|
||||
* @param key Key to set InputReleased state.
|
||||
*/
|
||||
static void registerKeyRelease(int key);
|
||||
|
||||
/**
|
||||
* @param button Mouse button to set InputRegistered state.
|
||||
*/
|
||||
static void registerMousePress(Qt::MouseButton button);
|
||||
|
||||
/**
|
||||
* @param button Mouse button to set InputReleased state.
|
||||
*/
|
||||
static void registerMouseRelease(Qt::MouseButton button);
|
||||
|
||||
/**
|
||||
* Reset input state for all key and mouse buttons.
|
||||
*/
|
||||
static void reset();
|
||||
|
||||
//
|
||||
// State Checking.
|
||||
|
||||
/**
|
||||
* @param key Key to check state.
|
||||
* @return True if the key is in InputTriggered state.
|
||||
*/
|
||||
inline static bool keyTriggered(Qt::Key key) {
|
||||
return keyState(key) == InputTriggered;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key Key to check state.
|
||||
* @return True if the key is in InputPressed state.
|
||||
*/
|
||||
inline static bool keyPressed(Qt::Key key) {
|
||||
return keyState(key) == InputPressed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key Key to check state.
|
||||
* @return True if the key is in InputReleased state.
|
||||
*/
|
||||
inline static bool keyReleased(Qt::Key key) {
|
||||
return keyState(key) == InputReleased;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param button Mouse button to check state.
|
||||
* @return True if the key is in InputTriggered state.
|
||||
*/
|
||||
inline static bool buttonTriggered(Qt::MouseButton button) {
|
||||
return buttonState(button) == InputTriggered;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param button Mouse button to check state.
|
||||
* @return True if the key is in InputPressed state.
|
||||
*/
|
||||
inline static bool buttonPressed(Qt::MouseButton button) {
|
||||
return buttonState(button) == InputPressed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param button Mouse button to check state.
|
||||
* @return True if the key is in InputReleased state.
|
||||
*/
|
||||
inline static bool buttonReleased(Qt::MouseButton button) {
|
||||
return buttonState(button) == InputReleased;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key The key to check InputState.
|
||||
* @return The current InputState for the given key.
|
||||
*/
|
||||
static InputState keyState(Qt::Key key);
|
||||
|
||||
/**
|
||||
* @param button The mouse button to check InputState.
|
||||
* @return The current InputState for the mouse button.
|
||||
*/
|
||||
static InputState buttonState(Qt::MouseButton button);
|
||||
|
||||
/**
|
||||
* @return QPoint representing the mouse position within the widget.
|
||||
*/
|
||||
static QPoint mousePosition();
|
||||
|
||||
/**
|
||||
* @return Delta movement of mouse from previous to current position.
|
||||
*/
|
||||
static QPoint mouseDelta();
|
||||
};
|
||||
} // namespace Qtk
|
||||
|
||||
#endif // QTOPENGL_INPUT_H
|
|
@ -1,6 +1,6 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: MeshRenderer class for quick object creation and drawing ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
|
@ -8,41 +8,41 @@
|
|||
|
||||
#include <QImageReader>
|
||||
|
||||
#include <meshrenderer.h>
|
||||
#include <scene.h>
|
||||
#include <texture.h>
|
||||
#include "meshrenderer.h"
|
||||
#include "scene.h"
|
||||
#include "texture.h"
|
||||
|
||||
using namespace Qtk;
|
||||
|
||||
// Static QHash that holds all MeshRenderer instances using their mName as keys
|
||||
Qtk::MeshRenderer::MeshManager Qtk::MeshRenderer::sInstances;
|
||||
|
||||
/*******************************************************************************
|
||||
* Constructors / Destructors
|
||||
******************************************************************************/
|
||||
|
||||
MeshRenderer::MeshRenderer(
|
||||
const char * name, Vertices vertices, Indices indices, DrawMode mode) :
|
||||
MeshRenderer(
|
||||
name, ShapeBase(mode, std::move(vertices), std::move(indices))) {}
|
||||
|
||||
MeshRenderer::MeshRenderer(const char * name) :
|
||||
MeshRenderer(name, Cube(QTK_DRAW_ELEMENTS)) {}
|
||||
|
||||
MeshRenderer::MeshRenderer(const char * name, const ShapeBase & shape) :
|
||||
Object(name, shape), mVertexShader(":/multi-color.vert"),
|
||||
mFragmentShader(":/multi-color.frag"), mDrawType(GL_TRIANGLES) {
|
||||
Object(name, shape, QTK_MESH), mVertexShader(":/shaders/multi-color.vert"),
|
||||
mFragmentShader(":/shaders/multi-color.frag"), mDrawType(GL_TRIANGLES) {
|
||||
mShape = Shape(shape);
|
||||
init();
|
||||
sInstances.insert(name, this);
|
||||
}
|
||||
|
||||
MeshRenderer::~MeshRenderer() {
|
||||
sInstances.remove(mName);
|
||||
}
|
||||
|
||||
// Static member function to retrieve instances of MeshRenderers
|
||||
MeshRenderer * MeshRenderer::getInstance(const QString & name) {
|
||||
if(!sInstances.contains(name)) {
|
||||
#if QTK_DEBUG
|
||||
qDebug() << "Attempt to access MeshRenderer instance that does not exist! ("
|
||||
<< qPrintable(name) << ")\n";
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
return sInstances[name];
|
||||
sInstances.remove(mName.c_str());
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Public Member Functions
|
||||
* Public Methods
|
||||
******************************************************************************/
|
||||
|
||||
void MeshRenderer::init() {
|
||||
|
@ -123,33 +123,11 @@ void MeshRenderer::draw() {
|
|||
releaseShaders();
|
||||
}
|
||||
|
||||
void MeshRenderer::setShaders(
|
||||
const std::string & vert, const std::string & frag) {
|
||||
mVertexShader = vert;
|
||||
mFragmentShader = frag;
|
||||
init();
|
||||
}
|
||||
|
||||
void MeshRenderer::setUniformMVP(
|
||||
const char * model, const char * view, const char * projection) {
|
||||
void MeshRenderer::enableAttributeArray(int location) {
|
||||
ShaderBindScope lock(&mProgram, mBound);
|
||||
mProgram.setUniformValue(projection, Scene::getProjectionMatrix());
|
||||
mProgram.setUniformValue(view, Scene::getViewMatrix());
|
||||
mProgram.setUniformValue(model, mTransform.toMatrix());
|
||||
}
|
||||
|
||||
void MeshRenderer::setColor(const QVector3D & color) {
|
||||
if(mShape.mColors.empty()) {
|
||||
for(const auto & vertex : mShape.getVertices()) {
|
||||
mShape.mColors.push_back(color);
|
||||
}
|
||||
} else {
|
||||
for(int i = 0; i < mShape.getColors().size(); i++) {
|
||||
mShape.mColors[i] = color;
|
||||
}
|
||||
}
|
||||
// TODO: Factor this out so we don't need to reinitialize
|
||||
init();
|
||||
mVAO.bind();
|
||||
mProgram.enableAttributeArray(location);
|
||||
mVAO.release();
|
||||
}
|
||||
|
||||
void MeshRenderer::reallocateTexCoords(const TexCoords & t, unsigned dims) {
|
||||
|
@ -185,11 +163,60 @@ void MeshRenderer::reallocateNormals(const Normals & n, unsigned dims) {
|
|||
mVAO.release();
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Inherited Virtual Member Functions
|
||||
******************************************************************************/
|
||||
void MeshRenderer::setShaders(
|
||||
const std::string & vert, const std::string & frag) {
|
||||
mVertexShader = vert;
|
||||
mFragmentShader = frag;
|
||||
init();
|
||||
}
|
||||
|
||||
void MeshRenderer::setUniformMVP(
|
||||
const char * model, const char * view, const char * projection) {
|
||||
ShaderBindScope lock(&mProgram, mBound);
|
||||
mProgram.setUniformValue(projection, Scene::getProjectionMatrix());
|
||||
mProgram.setUniformValue(view, Scene::getViewMatrix());
|
||||
mProgram.setUniformValue(model, mTransform.toMatrix());
|
||||
}
|
||||
|
||||
void MeshRenderer::setShape(const Shape & value) {
|
||||
Object::setShape(value);
|
||||
init();
|
||||
}
|
||||
|
||||
void MeshRenderer::setColor(const QVector3D & color) {
|
||||
if(mShape.mColors.empty()) {
|
||||
for(const auto & vertex : mShape.getVertices()) {
|
||||
mShape.mColors.push_back(color);
|
||||
}
|
||||
} else {
|
||||
for(int i = 0; i < mShape.getColors().size(); i++) {
|
||||
mShape.mColors[i] = color;
|
||||
}
|
||||
}
|
||||
// TODO: Factor this out so we don't need to reinitialize
|
||||
init();
|
||||
}
|
||||
|
||||
void MeshRenderer::setAttributeBuffer(
|
||||
int location, GLenum type, int offset, int tupleSize, int stride) {
|
||||
ShaderBindScope lock(&mProgram, mBound);
|
||||
mVAO.bind();
|
||||
mProgram.setAttributeBuffer(location, type, offset, tupleSize, stride);
|
||||
mVAO.release();
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Static Public Methods
|
||||
******************************************************************************/
|
||||
|
||||
// Static member function to retrieve instances of MeshRenderers
|
||||
MeshRenderer * MeshRenderer::getInstance(const QString & name) {
|
||||
if(!sInstances.contains(name)) {
|
||||
#if QTK_DEBUG
|
||||
qDebug() << "Attempt to access MeshRenderer instance that does not exist! ("
|
||||
<< qPrintable(name) << ")\n";
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
return sInstances[name];
|
||||
}
|
|
@ -0,0 +1,234 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: MeshRenderer class for quick object creation and drawing ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
#ifndef QTK_MESHRENDERER_H
|
||||
#define QTK_MESHRENDERER_H
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "object.h"
|
||||
#include "qtkapi.h"
|
||||
#include "shape.h"
|
||||
|
||||
namespace Qtk {
|
||||
class QTKAPI MeshRenderer : public Object {
|
||||
public:
|
||||
/*************************************************************************
|
||||
* Typedefs
|
||||
************************************************************************/
|
||||
|
||||
/** Static QHash of all mesh objects within the scene. */
|
||||
typedef QHash<QString, MeshRenderer *> MeshManager;
|
||||
|
||||
/*************************************************************************
|
||||
* Constructors / Destructors
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* Delegate constructor.
|
||||
* Constructs a MeshRenderer with custom vertices and indices for more
|
||||
* complex geometry.
|
||||
*
|
||||
* @param name Name to use for the new QObject.
|
||||
* @param vertices Vertices to use for initializing geometry shape.
|
||||
* @param indices Indicess to use for initializes geometry shape.
|
||||
* @param mode OpenGL draw mode. Supported modes are prefixed with QTK_*
|
||||
*/
|
||||
MeshRenderer(
|
||||
const char * name, Vertices vertices, Indices indices,
|
||||
DrawMode mode = QTK_DRAW_ARRAYS);
|
||||
|
||||
/**
|
||||
* Delegate constructor.
|
||||
* Constructs a MeshRenderer with a default shape of a cube.
|
||||
*
|
||||
* @param name Name to use for the new QObject.
|
||||
*/
|
||||
explicit MeshRenderer(const char * name);
|
||||
|
||||
/**
|
||||
* Construct a MeshRenderer.
|
||||
* Default shaders will be used unless subsequently set by the caller.
|
||||
*
|
||||
* @param name Name to use for the new QObject.
|
||||
* @param shape The shape of the MeshRenderer.
|
||||
* For models this can be set using ShapeBase ctors.
|
||||
*/
|
||||
MeshRenderer(const char * name, const ShapeBase & shape);
|
||||
|
||||
~MeshRenderer();
|
||||
|
||||
/*************************************************************************
|
||||
* Public Methods
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* Initializes OpenGL buffers and settings for this MeshRenderer.
|
||||
*/
|
||||
void init();
|
||||
|
||||
/**
|
||||
* Draws this MeshRenderer.
|
||||
*/
|
||||
void draw();
|
||||
|
||||
/**
|
||||
* Enables shader attribute array from the MeshRenderer's VAO.
|
||||
* @param location Index location of the attribute array to enable.
|
||||
*/
|
||||
void enableAttributeArray(int location);
|
||||
|
||||
/**
|
||||
* Reallocates texture coordinates to the mNBO member object.
|
||||
*
|
||||
* @param t Texture coordinates to reallocate.
|
||||
* @param dims Number of dimensions to use for the coordinates.
|
||||
*/
|
||||
void reallocateTexCoords(const TexCoords & t, unsigned dims = 2);
|
||||
|
||||
/**
|
||||
* Reallocates normals to the mNBO member object.
|
||||
*
|
||||
* @param n Normal coordinate to reallocate.
|
||||
* @param dims Number of dimensions to use for the coordinates.
|
||||
*/
|
||||
void reallocateNormals(const Normals & n, unsigned dims = 3);
|
||||
|
||||
/*************************************************************************
|
||||
* Setters
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* Set OpenGL draw type. GL_TRIANGLES, GL_POINTS, GL_LINES, etc.
|
||||
*
|
||||
* @param drawType The draw type to use for this MeshRenderer.
|
||||
*/
|
||||
inline void setDrawType(int drawType) { mDrawType = drawType; }
|
||||
|
||||
/**
|
||||
* @param vert Path to vertex shader to use for this MeshRenderer.
|
||||
*/
|
||||
inline void setShaderVertex(const std::string & vert) {
|
||||
mVertexShader = vert;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param frag Path to fragment shader to use for this MeshRenderer.
|
||||
*/
|
||||
inline void setShaderFragment(const std::string & frag) {
|
||||
mFragmentShader = frag;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param vert Path to vertex shader to use for this MeshRenderer.
|
||||
* @param frag Path to fragment shader to use for this MeshRenderer.
|
||||
*/
|
||||
void setShaders(const std::string & vert, const std::string & frag);
|
||||
|
||||
/**
|
||||
* @tparam T Type of the uniform value to set.
|
||||
* @param location Index location of the uniform value we are setting.
|
||||
* @param value The value to use for the uniform.
|
||||
*/
|
||||
template <typename T> inline void setUniform(int location, T value) {
|
||||
ShaderBindScope lock(&mProgram, mBound);
|
||||
mProgram.setUniformValue(location, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @tparam T Type of the uniform value to set.
|
||||
* @param location Name of the uniform value we are setting.
|
||||
* @param value The value to use for the uniform.
|
||||
*/
|
||||
template <typename T>
|
||||
inline void setUniform(const char * location, T value) {
|
||||
ShaderBindScope lock(&mProgram, mBound);
|
||||
mProgram.setUniformValue(location, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the MVP matrices for this object within the scene.
|
||||
* Model matrix is provided by this model's transform.
|
||||
* View and Projection matrices are provided by the scene.
|
||||
*
|
||||
* @param model Name of the uniform to store the Model matrix.
|
||||
* @param view Name of the uniform to store the View matrix.
|
||||
* @param projection Name of the uniform to store the Projection matrix.
|
||||
*/
|
||||
void setUniformMVP(
|
||||
const char * model = "uModel", const char * view = "uView",
|
||||
const char * projection = "uProjection");
|
||||
|
||||
/**
|
||||
* Sets the shape of the MeshRenderer using the Object base class method.
|
||||
* The MeshRenderer will be reinitialized after this call using `init()`.
|
||||
*
|
||||
* @param value Shape to use for this MeshRenderer.
|
||||
*/
|
||||
void setShape(const Shape & value) override;
|
||||
|
||||
/**
|
||||
* Sets all vertices in the mesh to a color.
|
||||
* The MeshRenderer will be reinitialized after this call using `init()`.
|
||||
*
|
||||
* @param color The color to use for the entire mesh.
|
||||
*/
|
||||
void setColor(const QVector3D & color);
|
||||
|
||||
/**
|
||||
* Updates an attribute buffer. This should be called whenever related
|
||||
* buffers are reallocated. If the new buffer uses an identical format
|
||||
* this may not be required.
|
||||
*
|
||||
* @param location Index location of the attribute buffer to set.
|
||||
* @param type The type of the values within the attribute buffer.
|
||||
* @param offset Offset to the beginning of the buffer.
|
||||
* @param tupleSize Size of each group of elements in the buffer.
|
||||
* For (x, y) positions this would be 2, (x, y, z) would be 3, etc.
|
||||
* @param stride Stride between groups of elements in the buffer.
|
||||
* For example (x, y) data stride is `2 * sizeof(type)`
|
||||
*/
|
||||
void setAttributeBuffer(
|
||||
int location, GLenum type, int offset, int tupleSize, int stride = 0);
|
||||
|
||||
/*************************************************************************
|
||||
* Accessors
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* Retrieve a mesh by name stored within static QHash private member
|
||||
* @param name The name of the MeshRenderer we want to retrieve.
|
||||
* @return Pointer to the MeshRenderer, or nullptr if not found.
|
||||
*/
|
||||
static MeshRenderer * getInstance(const QString & name);
|
||||
|
||||
/**
|
||||
* @return Transform3D attached to this MeshRenderer.
|
||||
*/
|
||||
inline Transform3D & getTransform() { return mTransform; }
|
||||
|
||||
inline std::string getVertexShader() const override {
|
||||
return mVertexShader;
|
||||
}
|
||||
|
||||
inline std::string getFragmentShader() const override {
|
||||
return mFragmentShader;
|
||||
}
|
||||
|
||||
private:
|
||||
/*************************************************************************
|
||||
* Private Members
|
||||
************************************************************************/
|
||||
|
||||
static MeshManager sInstances;
|
||||
|
||||
int mDrawType {};
|
||||
std::string mVertexShader {}, mFragmentShader {};
|
||||
};
|
||||
} // namespace Qtk
|
||||
|
||||
#endif // QTK_MESHRENDERER_H
|
|
@ -1,160 +1,37 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
|
||||
## About: Model classes for importing with Assimp ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Model class for importing with Assimp ##
|
||||
## From following tutorials on learnopengl.com ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
|
||||
#include <QFileInfo>
|
||||
|
||||
#include <model.h>
|
||||
#include <resourcemanager.h>
|
||||
#include <scene.h>
|
||||
#include <texture.h>
|
||||
#include "model.h"
|
||||
#include "qtkiosystem.h"
|
||||
#include "scene.h"
|
||||
#include "texture.h"
|
||||
|
||||
using namespace Qtk;
|
||||
|
||||
/** Static QHash used to store and access models globally. */
|
||||
Model::ModelManager Model::mManager;
|
||||
|
||||
// Static function to access ModelManager for getting Models by name
|
||||
Model * Model::getInstance(const char * name) {
|
||||
return mManager[name];
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* ModelMesh Private Member Functions
|
||||
******************************************************************************/
|
||||
|
||||
void ModelMesh::initMesh(const char * vert, const char * frag) {
|
||||
initializeOpenGLFunctions();
|
||||
|
||||
// Create VAO, VBO, EBO
|
||||
mVAO->create();
|
||||
mVBO->create();
|
||||
mEBO->create();
|
||||
|
||||
mVAO->bind();
|
||||
|
||||
// Allocate VBO
|
||||
mVBO->setUsagePattern(QOpenGLBuffer::StaticDraw);
|
||||
mVBO->bind();
|
||||
|
||||
mVBO->allocate(mVertices.data(), mVertices.size() * sizeof(mVertices[0]));
|
||||
|
||||
// Allocate EBO
|
||||
mEBO->setUsagePattern(QOpenGLBuffer::StaticDraw);
|
||||
mEBO->bind();
|
||||
mEBO->allocate(mIndices.data(), mIndices.size() * sizeof(mIndices[0]));
|
||||
mEBO->release();
|
||||
|
||||
// Load and link shaders
|
||||
mProgram->addShaderFromSourceFile(QOpenGLShader::Vertex, vert);
|
||||
mProgram->addShaderFromSourceFile(QOpenGLShader::Fragment, frag);
|
||||
mProgram->link();
|
||||
mProgram->bind();
|
||||
|
||||
// Positions
|
||||
mProgram->enableAttributeArray(0);
|
||||
mProgram->setAttributeBuffer(
|
||||
0, GL_FLOAT, offsetof(ModelVertex, mPosition), 3, sizeof(ModelVertex));
|
||||
|
||||
// Normals
|
||||
mProgram->enableAttributeArray(1);
|
||||
mProgram->setAttributeBuffer(
|
||||
1, GL_FLOAT, offsetof(ModelVertex, mNormal), 3, sizeof(ModelVertex));
|
||||
|
||||
// Texture Coordinates
|
||||
mProgram->enableAttributeArray(2);
|
||||
mProgram->setAttributeBuffer(
|
||||
2, GL_FLOAT, offsetof(ModelVertex, mTextureCoord), 2,
|
||||
sizeof(ModelVertex));
|
||||
|
||||
// Vertex tangents
|
||||
mProgram->enableAttributeArray(3);
|
||||
mProgram->setAttributeBuffer(
|
||||
3, GL_FLOAT, offsetof(ModelVertex, mTangent), 3, sizeof(ModelVertex));
|
||||
|
||||
// Vertex bitangents
|
||||
mProgram->enableAttributeArray(4);
|
||||
mProgram->setAttributeBuffer(
|
||||
4, GL_FLOAT, offsetof(ModelVertex, mBitangent), 3, sizeof(ModelVertex));
|
||||
|
||||
mProgram->release();
|
||||
mVBO->release();
|
||||
mVAO->release();
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* ModelMesh Public Member Functions
|
||||
******************************************************************************/
|
||||
|
||||
void ModelMesh::draw(QOpenGLShaderProgram & shader) {
|
||||
mVAO->bind();
|
||||
// Bind shader
|
||||
shader.bind();
|
||||
|
||||
// Set Model View Projection values
|
||||
shader.setUniformValue("uModel", mTransform.toMatrix());
|
||||
shader.setUniformValue("uView", Scene::getViewMatrix());
|
||||
shader.setUniformValue("uProjection", Scene::getProjectionMatrix());
|
||||
|
||||
GLuint diffuseCount = 1;
|
||||
GLuint specularCount = 1;
|
||||
GLuint normalCount = 1;
|
||||
for(GLuint i = 0; i < mTextures.size(); i++) {
|
||||
// Activate the current texture index by adding offset to GL_TEXTURE0
|
||||
glActiveTexture(GL_TEXTURE0 + i);
|
||||
mTextures[i].mTexture->bind();
|
||||
|
||||
// Get a name for the texture using a known convention -
|
||||
// Diffuse: material.texture_diffuse1, material.texture_diffuse2, ...
|
||||
// Specular: material.texture_specular1, material.texture_specular2, ...
|
||||
std::string number;
|
||||
std::string name = mTextures[i].mType;
|
||||
if(name == "texture_diffuse") {
|
||||
number = std::to_string(diffuseCount++);
|
||||
}
|
||||
if(name == "texture_specular") {
|
||||
number = std::to_string(specularCount++);
|
||||
}
|
||||
if(name == "texture_normal") {
|
||||
number = std::to_string(normalCount++);
|
||||
}
|
||||
|
||||
// Set the uniform to track this texture ID using our naming convention
|
||||
shader.setUniformValue((name + number).c_str(), i);
|
||||
}
|
||||
|
||||
// Draw the mesh
|
||||
glDrawElements(
|
||||
GL_TRIANGLES, mIndices.size(), GL_UNSIGNED_INT, mIndices.data());
|
||||
|
||||
// Release shader, textures
|
||||
for(const auto & texture : mTextures) {
|
||||
texture.mTexture->release();
|
||||
}
|
||||
shader.release();
|
||||
mVAO->release();
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Model Public Member Functions
|
||||
* Public Member Functions
|
||||
******************************************************************************/
|
||||
|
||||
void Model::draw() {
|
||||
for(auto & mMeshe : mMeshes) {
|
||||
mMeshe.mTransform = mTransform;
|
||||
mMeshe.draw();
|
||||
for(auto & mesh : mMeshes) {
|
||||
mesh.mTransform = mTransform;
|
||||
mesh.draw();
|
||||
}
|
||||
}
|
||||
|
||||
void Model::draw(QOpenGLShaderProgram & shader) {
|
||||
for(auto & mMeshe : mMeshes) {
|
||||
mMeshe.mTransform = mTransform;
|
||||
mMeshe.draw(shader);
|
||||
for(auto & mesh : mMeshes) {
|
||||
mesh.mTransform = mTransform;
|
||||
mesh.draw(shader);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -166,7 +43,7 @@ void Model::flipTexture(const std::string & fileName, bool flipX, bool flipY) {
|
|||
texture.mTexture->destroy();
|
||||
texture.mTexture->create();
|
||||
texture.mTexture->setData(
|
||||
*OpenGLTextureFactory::initImage(fullPath.c_str(), flipX, flipY));
|
||||
OpenGLTextureFactory::initImage(fullPath.c_str(), flipX, flipY));
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
|
@ -176,34 +53,38 @@ void Model::flipTexture(const std::string & fileName, bool flipX, bool flipY) {
|
|||
}
|
||||
}
|
||||
|
||||
// Static function to access ModelManager for getting Models by name
|
||||
Model * Qtk::Model::getInstance(const char * name) {
|
||||
return mManager[name];
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Model Private Member Functions
|
||||
* Private Member Functions
|
||||
******************************************************************************/
|
||||
|
||||
void Model::loadModel(const std::string & path) {
|
||||
Assimp::Importer import;
|
||||
|
||||
// JIC a relative path was used, get the absolute file path
|
||||
QFileInfo info(path.c_str());
|
||||
info.makeAbsolute();
|
||||
mDirectory = path[0] == ':' ? RM::getPath(path)
|
||||
: info.absoluteFilePath().toStdString();
|
||||
// If using a Qt Resource path, use QtkIOSystem for file handling.
|
||||
if(path.front() == ':') {
|
||||
import.SetIOHandler(new QtkIOSystem());
|
||||
}
|
||||
// Used as base path for loading model textures.
|
||||
mDirectory = path.substr(0, path.find_last_of('/'));
|
||||
|
||||
// Import the model, converting non-triangular geometry to triangles
|
||||
// + And flipping texture UVs, etc..
|
||||
// Assimp options: http://assimp.sourceforge.net/lib_html/postprocess_8h.html
|
||||
const aiScene * scene = import.ReadFile(
|
||||
mDirectory, aiProcess_Triangulate | aiProcess_FlipUVs
|
||||
| aiProcess_GenSmoothNormals | aiProcess_CalcTangentSpace
|
||||
| aiProcess_OptimizeMeshes | aiProcess_SplitLargeMeshes);
|
||||
path.c_str(), aiProcess_Triangulate | aiProcess_FlipUVs
|
||||
| aiProcess_GenSmoothNormals
|
||||
| aiProcess_CalcTangentSpace | aiProcess_OptimizeMeshes
|
||||
| aiProcess_SplitLargeMeshes);
|
||||
|
||||
// If there were errors, print and return
|
||||
if(!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) {
|
||||
qDebug() << "Error::ASSIMP::" << import.GetErrorString() << "\n";
|
||||
return;
|
||||
}
|
||||
// If there were no errors, find the directory that contains this model
|
||||
mDirectory = mDirectory.substr(0, mDirectory.find_last_of('/'));
|
||||
|
||||
// Pass the pointers to the root node and the scene to recursive function
|
||||
// + Base case breaks when no nodes left to process on model
|
||||
|
@ -212,10 +93,10 @@ void Model::loadModel(const std::string & path) {
|
|||
// Sort models by their distance from the camera
|
||||
// Optimizes drawing so that overlapping objects are not overwritten
|
||||
// + Since the topmost object will be drawn first
|
||||
sortModels();
|
||||
sortModelMeshes();
|
||||
|
||||
// Object finished loading, insert it into ModelManager
|
||||
mManager.insert(mName, this);
|
||||
mManager.insert(getName().c_str(), this);
|
||||
}
|
||||
|
||||
void Model::processNode(aiNode * node, const aiScene * scene) {
|
||||
|
@ -300,7 +181,6 @@ ModelMesh Model::processMesh(aiMesh * mesh, const aiScene * scene) {
|
|||
if(mesh->mMaterialIndex >= 0) {
|
||||
// Get the material attached to the model using Assimp
|
||||
aiMaterial * material = scene->mMaterials[mesh->mMaterialIndex];
|
||||
|
||||
// Get all diffuse textures from the material
|
||||
ModelMesh::Textures diffuseMaps = loadMaterialTextures(
|
||||
material, aiTextureType_DIFFUSE, "texture_diffuse");
|
||||
|
@ -320,7 +200,9 @@ ModelMesh Model::processMesh(aiMesh * mesh, const aiScene * scene) {
|
|||
textures.insert(textures.end(), normalMaps.begin(), normalMaps.end());
|
||||
}
|
||||
|
||||
return {vertices, indices, textures, mVertexShader, mFragmentShader};
|
||||
return {
|
||||
vertices, indices, textures, mVertexShader.c_str(),
|
||||
mFragmentShader.c_str()};
|
||||
}
|
||||
|
||||
ModelMesh::Textures Model::loadMaterialTextures(
|
||||
|
@ -356,7 +238,7 @@ ModelMesh::Textures Model::loadMaterialTextures(
|
|||
// Add the texture to the textures container
|
||||
textures.push_back(texture);
|
||||
// Add the texture to the loaded textures to avoid loading it twice
|
||||
mTexturesLoaded.push_back(texture);
|
||||
mTexturesLoaded.push_back(textures.back());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -364,7 +246,7 @@ ModelMesh::Textures Model::loadMaterialTextures(
|
|||
return textures;
|
||||
}
|
||||
|
||||
void Model::sortModels() {
|
||||
void Model::sortModelMeshes() {
|
||||
auto cameraPos = Scene::getCamera().getTransform();
|
||||
auto cameraDistance = [&cameraPos](const ModelMesh & a, const ModelMesh & b) {
|
||||
// Sort by the first vertex position in the model
|
|
@ -0,0 +1,215 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Model class for importing with Assimp ##
|
||||
## From following tutorials on learnopengl.com ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
#ifndef QTK_MODEL_H
|
||||
#define QTK_MODEL_H
|
||||
|
||||
// Qt
|
||||
#include <QOpenGLFunctions>
|
||||
|
||||
// Assimp
|
||||
#include <assimp/postprocess.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/Importer.hpp>
|
||||
|
||||
// Qtk
|
||||
#include <QFileInfo>
|
||||
|
||||
|
||||
#include "modelmesh.h"
|
||||
#include "qtkapi.h"
|
||||
|
||||
namespace Qtk {
|
||||
/**
|
||||
* Model object that has a ModelMesh.
|
||||
* Top-level object that represents 3D models stored within a scene.
|
||||
*/
|
||||
class QTKAPI Model : public Object {
|
||||
public:
|
||||
/*************************************************************************
|
||||
* Typedefs
|
||||
************************************************************************/
|
||||
|
||||
/** ModelManager typedef that will manage global model access. */
|
||||
typedef QHash<QString, Model *> ModelManager;
|
||||
|
||||
/*************************************************************************
|
||||
* Constructors, Destructors
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* Constructs a Model
|
||||
* If no shaders are provided we will use default shaders.
|
||||
*
|
||||
* @param name Name to use for the Model's objectName.
|
||||
* @param path Path to the model to load for construction.
|
||||
* @param vertexShader Optional path to custom vertex shader.
|
||||
* @param fragmentShader Optional path to custom fragment shader.
|
||||
*/
|
||||
inline Model(
|
||||
const char * name, const char * path,
|
||||
const char * vertexShader = ":/shaders/model-basic.vert",
|
||||
const char * fragmentShader = ":/shaders/model-basic.frag") :
|
||||
Object(name, QTK_MODEL),
|
||||
mModelPath(path), mVertexShader(vertexShader),
|
||||
mFragmentShader(fragmentShader) {
|
||||
loadModel(mModelPath);
|
||||
}
|
||||
|
||||
inline ~Model() override { mManager.remove(getName().c_str()); }
|
||||
|
||||
/*************************************************************************
|
||||
* Public Methods
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* Draws the model using attached shader program.
|
||||
*/
|
||||
void draw();
|
||||
|
||||
/**
|
||||
* Draws the model using a custom shader program.
|
||||
*
|
||||
* @param shader Shader program to use to draw the model.
|
||||
*/
|
||||
void draw(QOpenGLShaderProgram & shader);
|
||||
|
||||
/**
|
||||
* Flip a texture associated with this model
|
||||
*
|
||||
* @param fileName The name of the texture to flip as it is stored on disk
|
||||
* @param flipX Flip the texture along the X axis
|
||||
* @param flipY Flip the texture along the Y axis
|
||||
*/
|
||||
void flipTexture(
|
||||
const std::string & fileName, bool flipX = false, bool flipY = true);
|
||||
|
||||
/*************************************************************************
|
||||
* Setters
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* Sets a uniform value for each ModelMesh within this Model.
|
||||
*
|
||||
* @tparam T The type of the value we are settings
|
||||
* @param location The uniform location
|
||||
* @param value The value to assign to the uniform
|
||||
*/
|
||||
template <typename T>
|
||||
inline void setUniform(const char * location, T value) {
|
||||
for(auto & mesh : mMeshes) {
|
||||
mesh.mProgram->bind();
|
||||
mesh.mProgram->setUniformValue(location, value);
|
||||
mesh.mProgram->release();
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* Accessors
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* Accessor function for retrieving a ModelMesh globally.
|
||||
* The mesh is retrieved from the mManager private member.
|
||||
*
|
||||
* @param name The name of the model to load as it was constructed.
|
||||
* @return Pointer to the model stored within the scene.
|
||||
*/
|
||||
[[nodiscard]] static Model * getInstance(const char * name);
|
||||
|
||||
/**
|
||||
* @return Transform3D attached to this Model.
|
||||
*/
|
||||
inline Transform3D & getTransform() { return mTransform; }
|
||||
|
||||
inline std::string getVertexShader() const override {
|
||||
return mVertexShader;
|
||||
}
|
||||
|
||||
inline std::string getFragmentShader() const override {
|
||||
return mFragmentShader;
|
||||
}
|
||||
|
||||
private:
|
||||
/*************************************************************************
|
||||
* Private Methods
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* Loads a model in .obj, .fbx, .gltf, and other formats.
|
||||
* For a full list of formats see assimp documentation:
|
||||
* https://github.com/assimp/assimp/blob/master/doc/Fileformats.md
|
||||
*
|
||||
* Large models should not be loaded into Qt resource system.
|
||||
* Instead pass an *absolute* path to this function.
|
||||
* Relative paths will break if Qtk is executed from different locations.
|
||||
*
|
||||
* @param path Absolute path to a model in .obj or another format accepted
|
||||
* by assimp.
|
||||
*/
|
||||
void loadModel(const std::string & path);
|
||||
|
||||
/**
|
||||
* Process a node in the model's geometry using Assimp.
|
||||
*
|
||||
* @param node The Assimp node to process.
|
||||
* @param scene The Assimp scene for the loaded model.
|
||||
*/
|
||||
void processNode(aiNode * node, const aiScene * scene);
|
||||
|
||||
/**
|
||||
* Process a mesh within a node using Assimp.
|
||||
*
|
||||
* @param mesh The Assimp mesh to process.
|
||||
* @param scene The Assimp scene for the loaded model.
|
||||
* @return
|
||||
*/
|
||||
ModelMesh processMesh(aiMesh * mesh, const aiScene * scene);
|
||||
|
||||
/**
|
||||
* Load a collection of material texture using Assimp.
|
||||
* This function loads diffuse, specular, and narmal material textures.
|
||||
* A Mesh may have many of any or all of the texture types above.
|
||||
* Models can have many Meshes attached.
|
||||
* This function returns all textures for a single Mesh within a Model.
|
||||
*
|
||||
* @param mat Loaded Assimp material.
|
||||
* @param type Type of the material.
|
||||
* @param typeName Texture type name in string format.
|
||||
* @return Collection of all textures for a single ModelMesh.
|
||||
*/
|
||||
ModelMesh::Textures loadMaterialTextures(
|
||||
aiMaterial * mat, aiTextureType type, const std::string & typeName);
|
||||
|
||||
/**
|
||||
* Sorts each mesh in the Model based on distance from the camera.
|
||||
* This is for efficient drawing in OpenGL by preventing the drawing of
|
||||
* objects not visible due to being partially or entirely behind another
|
||||
* object.
|
||||
*/
|
||||
void sortModelMeshes();
|
||||
|
||||
/*************************************************************************
|
||||
* Private Members
|
||||
************************************************************************/
|
||||
|
||||
/** Static QHash used to store and access models globally. */
|
||||
static ModelManager mManager;
|
||||
|
||||
/** Container to store N loaded textures for this model. */
|
||||
ModelMesh::Textures mTexturesLoaded {};
|
||||
/** Container to store N loaded meshes for this model. */
|
||||
std::vector<ModelMesh> mMeshes {};
|
||||
/** The directory this model and it's textures are stored. */
|
||||
std::string mDirectory {};
|
||||
/** File names for shaders and 3D model on disk. */
|
||||
std::string mVertexShader, mFragmentShader, mModelPath;
|
||||
};
|
||||
} // namespace Qtk
|
||||
|
||||
#endif // QTK_MODEL_H
|
|
@ -0,0 +1,132 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: ModelMesh class for importing 3D models with Assimp ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
|
||||
#include "modelmesh.h"
|
||||
#include "scene.h"
|
||||
|
||||
using namespace Qtk;
|
||||
|
||||
/*******************************************************************************
|
||||
* Public Member Functions
|
||||
******************************************************************************/
|
||||
|
||||
void ModelMesh::draw(QOpenGLShaderProgram & shader) {
|
||||
mVAO->bind();
|
||||
// Bind shader
|
||||
shader.bind();
|
||||
|
||||
// Set Model View Projection values
|
||||
shader.setUniformValue("uModel", mTransform.toMatrix());
|
||||
shader.setUniformValue("uView", Scene::getViewMatrix());
|
||||
shader.setUniformValue("uProjection", Scene::getProjectionMatrix());
|
||||
|
||||
GLuint diffuseCount = 1;
|
||||
GLuint specularCount = 1;
|
||||
GLuint normalCount = 1;
|
||||
for(GLuint i = 0; i < mTextures.size(); i++) {
|
||||
// Activate the current texture index by adding offset to GL_TEXTURE0
|
||||
glActiveTexture(GL_TEXTURE0 + i);
|
||||
mTextures[i].mTexture->bind();
|
||||
|
||||
// Get a name for the texture using a known convention -
|
||||
// Diffuse: material.texture_diffuse1, material.texture_diffuse2, ...
|
||||
// Specular: material.texture_specular1, material.texture_specular2, ...
|
||||
std::string number;
|
||||
std::string name = mTextures[i].mType;
|
||||
if(name == "texture_diffuse") {
|
||||
number = std::to_string(diffuseCount++);
|
||||
}
|
||||
if(name == "texture_specular") {
|
||||
number = std::to_string(specularCount++);
|
||||
}
|
||||
if(name == "texture_normal") {
|
||||
number = std::to_string(normalCount++);
|
||||
}
|
||||
|
||||
// Set the uniform to track this texture ID using our naming convention
|
||||
shader.setUniformValue((name + number).c_str(), i);
|
||||
}
|
||||
|
||||
// Always reset active texture to GL_TEXTURE0 before we draw.
|
||||
// This is important for models with no textures.
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
// Draw the mesh
|
||||
glDrawElements(
|
||||
GL_TRIANGLES, mIndices.size(), GL_UNSIGNED_INT, mIndices.data());
|
||||
|
||||
// Release shader, textures
|
||||
for(const auto & texture : mTextures) {
|
||||
texture.mTexture->release();
|
||||
}
|
||||
shader.release();
|
||||
mVAO->release();
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Private Member Functions
|
||||
******************************************************************************/
|
||||
|
||||
void ModelMesh::initMesh(const char * vert, const char * frag) {
|
||||
initializeOpenGLFunctions();
|
||||
|
||||
// Create VAO, VBO, EBO
|
||||
bool status = mVAO->create();
|
||||
mVBO->create();
|
||||
mEBO->create();
|
||||
|
||||
mVAO->bind();
|
||||
|
||||
// Allocate VBO
|
||||
mVBO->setUsagePattern(QOpenGLBuffer::StaticDraw);
|
||||
mVBO->bind();
|
||||
|
||||
mVBO->allocate(mVertices.data(), mVertices.size() * sizeof(mVertices[0]));
|
||||
|
||||
// Allocate EBO
|
||||
mEBO->setUsagePattern(QOpenGLBuffer::StaticDraw);
|
||||
mEBO->bind();
|
||||
mEBO->allocate(mIndices.data(), mIndices.size() * sizeof(mIndices[0]));
|
||||
mEBO->release();
|
||||
|
||||
// Load and link shaders
|
||||
mProgram->addShaderFromSourceFile(QOpenGLShader::Vertex, vert);
|
||||
mProgram->addShaderFromSourceFile(QOpenGLShader::Fragment, frag);
|
||||
mProgram->link();
|
||||
mProgram->bind();
|
||||
|
||||
// Positions
|
||||
mProgram->enableAttributeArray(0);
|
||||
mProgram->setAttributeBuffer(
|
||||
0, GL_FLOAT, offsetof(ModelVertex, mPosition), 3, sizeof(ModelVertex));
|
||||
|
||||
// Normals
|
||||
mProgram->enableAttributeArray(1);
|
||||
mProgram->setAttributeBuffer(
|
||||
1, GL_FLOAT, offsetof(ModelVertex, mNormal), 3, sizeof(ModelVertex));
|
||||
|
||||
// Texture Coordinates
|
||||
mProgram->enableAttributeArray(2);
|
||||
mProgram->setAttributeBuffer(
|
||||
2, GL_FLOAT, offsetof(ModelVertex, mTextureCoord), 2,
|
||||
sizeof(ModelVertex));
|
||||
|
||||
// Vertex tangents
|
||||
mProgram->enableAttributeArray(3);
|
||||
mProgram->setAttributeBuffer(
|
||||
3, GL_FLOAT, offsetof(ModelVertex, mTangent), 3, sizeof(ModelVertex));
|
||||
|
||||
// Vertex bitangents
|
||||
mProgram->enableAttributeArray(4);
|
||||
mProgram->setAttributeBuffer(
|
||||
4, GL_FLOAT, offsetof(ModelVertex, mBitangent), 3, sizeof(ModelVertex));
|
||||
|
||||
mProgram->release();
|
||||
mVBO->release();
|
||||
mVAO->release();
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: ModelMesh class for importing 3D models with Assimp ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
|
||||
#ifndef QTK_MODELMESH_H
|
||||
#define QTK_MODELMESH_H
|
||||
|
||||
#include <QOpenGLFunctions>
|
||||
|
||||
#include "object.h"
|
||||
#include "transform3D.h"
|
||||
|
||||
namespace Qtk {
|
||||
/**
|
||||
* 3D models will store this data for each vertex in geometry.
|
||||
*/
|
||||
struct QTKAPI ModelVertex {
|
||||
QVector3D mPosition;
|
||||
QVector3D mNormal;
|
||||
QVector2D mTextureCoord;
|
||||
QVector3D mTangent;
|
||||
QVector3D mBitangent;
|
||||
};
|
||||
|
||||
/**
|
||||
* Struct to store model textures. 3D Models may have multiple.
|
||||
*/
|
||||
struct QTKAPI ModelTexture {
|
||||
ModelTexture() = default;
|
||||
|
||||
/**
|
||||
* Construct a ModelTexture.
|
||||
*
|
||||
* @param id Texture ID for this texture.
|
||||
* @param type Type of texture in string format.
|
||||
* @param path Path to the texture on disk.
|
||||
*/
|
||||
ModelTexture(const std::string & type, const std::string & path) :
|
||||
mType(type), mPath(path) {
|
||||
mTexture = OpenGLTextureFactory::initTexture(path.c_str());
|
||||
mID = mTexture->textureId();
|
||||
}
|
||||
|
||||
/** Texture ID for for this texture. */
|
||||
GLuint mID {};
|
||||
QOpenGLTexture * mTexture {};
|
||||
|
||||
/**
|
||||
* Type of this texture in string format.
|
||||
* See calls to Model::loadMaterialTexture in Model::processMesh
|
||||
*/
|
||||
std::string mType {};
|
||||
/** Path to the model on disk. */
|
||||
std::string mPath {};
|
||||
};
|
||||
|
||||
class Model;
|
||||
|
||||
/**
|
||||
* Mesh class specialized for storing 3D model data.
|
||||
* Eventually this can be consolidated into a more generic class.
|
||||
*/
|
||||
class QTKAPI ModelMesh : protected QOpenGLFunctions {
|
||||
public:
|
||||
/*************************************************************************
|
||||
* Typedefs
|
||||
************************************************************************/
|
||||
|
||||
friend Model;
|
||||
typedef std::vector<ModelVertex> Vertices;
|
||||
typedef std::vector<GLuint> Indices;
|
||||
typedef std::vector<ModelTexture> Textures;
|
||||
|
||||
/*************************************************************************
|
||||
* Constructors, Destructors
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* Construct a ModelMesh.
|
||||
* If no shaders are provided defaults will be used.
|
||||
*
|
||||
* @param vertices Vertex data to use for this ModelMesh.
|
||||
* @param indices Index data to use for this ModelMesh.
|
||||
* @param textures Collection of ModelTextures for this ModelMesh.
|
||||
* @param vertexShader Path to vertex shader for this ModelMesh.
|
||||
* @param fragmentShader Path to fragment shader for this ModelMesh.
|
||||
*/
|
||||
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() = default;
|
||||
|
||||
/*************************************************************************
|
||||
* Public Methods
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* Draw the model with the attached shader program.
|
||||
*/
|
||||
inline void draw() { draw(*mProgram); }
|
||||
|
||||
/**
|
||||
* Draw the model with a custom shader program.
|
||||
* @param shader The shader program to use for drawing the object.
|
||||
*/
|
||||
void draw(QOpenGLShaderProgram & shader);
|
||||
|
||||
/*************************************************************************
|
||||
* Public Members
|
||||
************************************************************************/
|
||||
|
||||
Vertices mVertices {};
|
||||
Indices mIndices {};
|
||||
Textures mTextures {};
|
||||
Transform3D mTransform;
|
||||
|
||||
private:
|
||||
/*************************************************************************
|
||||
* Private Methods
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* Initializes the buffers and shaders for this model mesh.
|
||||
*
|
||||
* @param vert Path to vertex shader to use for this model.
|
||||
* @param frag Path to fragment shader to use for this model.
|
||||
*/
|
||||
void initMesh(const char * vert, const char * frag);
|
||||
|
||||
/*************************************************************************
|
||||
* Private Members
|
||||
************************************************************************/
|
||||
|
||||
QOpenGLBuffer *mVBO, *mEBO;
|
||||
QOpenGLVertexArrayObject * mVAO;
|
||||
QOpenGLShaderProgram * mProgram;
|
||||
};
|
||||
} // namespace Qtk
|
||||
|
||||
#endif // QTK_MODELMESH_H
|
|
@ -1,11 +1,11 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Object class for storing object data ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
|
||||
#include <object.h>
|
||||
#include "object.h"
|
||||
|
||||
using namespace Qtk;
|
|
@ -1,6 +1,6 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Object class for storing object data ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
|
@ -13,11 +13,13 @@
|
|||
#include <QOpenGLTexture>
|
||||
#include <QOpenGLVertexArrayObject>
|
||||
|
||||
#include <mesh.h>
|
||||
#include <qtkapi.h>
|
||||
#include <texture.h>
|
||||
#include "qtkapi.h"
|
||||
#include "shape.h"
|
||||
#include "texture.h"
|
||||
|
||||
namespace Qtk {
|
||||
class Model;
|
||||
|
||||
/**
|
||||
* Object base class for objects that can exist within a scene.
|
||||
* An object could be a Cube, Skybox, 3D Model, or other standalone entities.
|
||||
|
@ -31,19 +33,32 @@ namespace Qtk {
|
|||
************************************************************************/
|
||||
|
||||
friend MeshRenderer;
|
||||
friend Model;
|
||||
|
||||
/**
|
||||
* Enum flag to identify Object type without casting.
|
||||
*/
|
||||
enum Type { QTK_OBJECT, QTK_MESH, QTK_MODEL };
|
||||
|
||||
/*************************************************************************
|
||||
* Constructors / Destructors
|
||||
************************************************************************/
|
||||
|
||||
// Initialize an object with no shape data assigned
|
||||
explicit Object(const char * name) :
|
||||
mName(name), mVBO(QOpenGLBuffer::VertexBuffer), mBound(false) {}
|
||||
explicit Object(const char * name, Type type) :
|
||||
mName(name), mVBO(QOpenGLBuffer::VertexBuffer), mBound(false),
|
||||
mType(type) {
|
||||
initResources();
|
||||
setObjectName(name);
|
||||
}
|
||||
|
||||
// Initialize an object with shape data assigned
|
||||
Object(const char * name, const ShapeBase & shape) :
|
||||
Object(const char * name, const ShapeBase & shape, Type type) :
|
||||
mName(name), mVBO(QOpenGLBuffer::VertexBuffer), mShape(shape),
|
||||
mBound(false) {}
|
||||
mBound(false), mType(type) {
|
||||
initResources();
|
||||
setObjectName(name);
|
||||
}
|
||||
|
||||
~Object() override = default;
|
||||
|
||||
|
@ -77,10 +92,28 @@ namespace Qtk {
|
|||
return mShape.mVertices;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::string getName() const { return mName; }
|
||||
|
||||
[[nodiscard]] inline const Type & getType() const { return mType; }
|
||||
|
||||
[[nodiscard]] inline virtual const Transform3D & getTransform() const {
|
||||
return mTransform;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline virtual std::string getVertexShader() const {
|
||||
return "Base Object has no vertex shader.";
|
||||
}
|
||||
|
||||
virtual inline std::string getFragmentShader() const {
|
||||
return "Base Object has no fragment shader.";
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* Setters
|
||||
************************************************************************/
|
||||
|
||||
virtual inline void setName(const std::string & name) { mName = name; }
|
||||
|
||||
virtual inline void setColors(const Colors & value) {
|
||||
mShape.mColors = value;
|
||||
}
|
||||
|
@ -116,6 +149,39 @@ namespace Qtk {
|
|||
mShape.mVertices = value;
|
||||
}
|
||||
|
||||
inline void setScaleX(double x) {
|
||||
mTransform.setScale(
|
||||
x, mTransform.getScale().y(), mTransform.getScale().z());
|
||||
}
|
||||
|
||||
inline void setScaleY(double y) {
|
||||
mTransform.setScale(
|
||||
mTransform.getScale().x(), y, mTransform.getScale().z());
|
||||
}
|
||||
|
||||
inline void setScaleZ(double z) {
|
||||
mTransform.setScale(
|
||||
mTransform.getScale().x(), mTransform.getScale().y(), z);
|
||||
}
|
||||
|
||||
inline void setTranslationX(double x) {
|
||||
mTransform.setTranslation(
|
||||
x, mTransform.getTranslation().y(),
|
||||
mTransform.getTranslation().z());
|
||||
}
|
||||
|
||||
inline void setTranslationY(double y) {
|
||||
mTransform.setTranslation(
|
||||
mTransform.getTranslation().x(), y,
|
||||
mTransform.getTranslation().z());
|
||||
}
|
||||
|
||||
inline void setTranslationZ(double z) {
|
||||
mTransform.setTranslation(
|
||||
mTransform.getTranslation().x(), mTransform.getTranslation().y(),
|
||||
z);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* Public Methods
|
||||
************************************************************************/
|
||||
|
@ -141,8 +207,9 @@ namespace Qtk {
|
|||
Transform3D mTransform;
|
||||
Shape mShape;
|
||||
Texture mTexture;
|
||||
const char * mName;
|
||||
std::string mName;
|
||||
bool mBound;
|
||||
Type mType = QTK_OBJECT;
|
||||
};
|
||||
} // namespace Qtk
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2023 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_QTKAPI_H
|
||||
#define QTK_QTKAPI_H
|
||||
|
||||
#include <QFile>
|
||||
#include <QWidget>
|
||||
#include <QtCore/QtGlobal>
|
||||
|
||||
#ifdef QTK_SHARED
|
||||
#if defined(QTK_EXPORT)
|
||||
#define QTKAPI Q_DECL_EXPORT
|
||||
#else
|
||||
#define QTKAPI Q_DECL_IMPORT
|
||||
#endif
|
||||
#else
|
||||
#define QTKAPI
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Initialize Qt resources required by the Qtk library.
|
||||
* This cannot be defined within any namespace, but can be called by ctors.
|
||||
* See object.h for example.
|
||||
*/
|
||||
inline void initResources() {
|
||||
Q_INIT_RESOURCE(resources);
|
||||
}
|
||||
|
||||
namespace Qtk {
|
||||
/**
|
||||
* Flag to set context for debug messages.
|
||||
*/
|
||||
enum DebugContext { Status, Debug, Warn, Error, Fatal };
|
||||
|
||||
/**
|
||||
* Find top level parent for a widget.
|
||||
*
|
||||
* @param widget Widget to start the search from.
|
||||
* @return Top level parent widget or Q_NULLPTR if no parent
|
||||
*/
|
||||
static QWidget * topLevelParent(QWidget * widget) {
|
||||
QString name = widget->objectName();
|
||||
while(widget->parentWidget() != Q_NULLPTR) {
|
||||
widget = widget->parentWidget();
|
||||
}
|
||||
return widget;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Default icon to use for Qtk desktop application.
|
||||
*/
|
||||
static QIcon getIcon() {
|
||||
return QIcon(":/icons/icon.png");
|
||||
}
|
||||
} // namespace Qtk
|
||||
|
||||
#endif // QTK_QTKAPI_H
|
|
@ -0,0 +1,78 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Custom IO stream for Qtk to support Qt Resource paths in Assimp ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
|
||||
#include "qtkiostream.h"
|
||||
|
||||
using namespace Qtk;
|
||||
|
||||
/*******************************************************************************
|
||||
* Constructors, Destructors
|
||||
******************************************************************************/
|
||||
|
||||
QtkIOStream::QtkIOStream(const char * pFile, const char * pMode) :
|
||||
mFile(pFile) {
|
||||
QString mode(pMode);
|
||||
bool open = false;
|
||||
if(mode == "w" || mode == "wb") {
|
||||
open = mFile.open(QIODeviceBase::WriteOnly);
|
||||
} else if(mode == "r" || mode == "rb") {
|
||||
open = mFile.open(QIODeviceBase::ReadOnly);
|
||||
} else if(mode == "wt") {
|
||||
open = mFile.open(QIODeviceBase::WriteOnly | QIODeviceBase::Text);
|
||||
} else if(mode == "rt") {
|
||||
open = mFile.open(QIODeviceBase::ReadOnly | QIODeviceBase::Text);
|
||||
} else {
|
||||
open = false;
|
||||
qDebug() << "[Qtk::QtkIOStream] Invalid file open mode: " << mode << "\n";
|
||||
}
|
||||
if(!open) {
|
||||
qDebug() << "[Qtk::QtkIOStream] Could not open file: " << QString(pFile)
|
||||
<< "\n";
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Public Member Functions
|
||||
******************************************************************************/
|
||||
|
||||
size_t QtkIOStream::Read(void * pvBuffer, size_t pSize, size_t pCount) {
|
||||
qint64 readSize = mFile.read((char *)pvBuffer, pSize * pCount);
|
||||
if(readSize < 0) {
|
||||
qDebug() << "[Qtk::QtkIOStream] Failed to read (" << pSize
|
||||
<< ") bytes from file at: " << mFile.filesystemFileName().c_str()
|
||||
<< "\n";
|
||||
return -1;
|
||||
}
|
||||
return readSize;
|
||||
}
|
||||
|
||||
size_t QtkIOStream::Write(const void * pvBuffer, size_t pSize, size_t pCount) {
|
||||
qint64 writeSize = mFile.write((char *)pvBuffer, pSize * pCount);
|
||||
if(writeSize < 0) {
|
||||
qDebug() << "[Qtk::QtkIOStream] Failed to write buffer with size (" << pSize
|
||||
<< ") to file at: " << mFile.filesystemFileName().c_str() << "\n";
|
||||
return -1;
|
||||
}
|
||||
return writeSize;
|
||||
}
|
||||
|
||||
aiReturn QtkIOStream::Seek(size_t pOffset, aiOrigin pOrigin) {
|
||||
return mFile.seek(pOffset) ? aiReturn_SUCCESS : aiReturn_FAILURE;
|
||||
}
|
||||
|
||||
size_t QtkIOStream::Tell() const {
|
||||
return mFile.pos();
|
||||
}
|
||||
|
||||
size_t QtkIOStream::FileSize() const {
|
||||
return mFile.size();
|
||||
}
|
||||
|
||||
void QtkIOStream::Flush() {
|
||||
mFile.flush();
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Custom IO stream for Qtk to support Qt Resource paths in Assimp ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
|
||||
#include <assimp/IOStream.hpp>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
|
||||
#ifndef QTK_QTKIOSTREAM_H
|
||||
#define QTK_QTKIOSTREAM_H
|
||||
|
||||
namespace Qtk {
|
||||
/**
|
||||
* Custom Assimp IO stream to support QtkIOSystem file handling.
|
||||
* Allows direct use of Qt Resource paths for loading models in Assimp.
|
||||
*/
|
||||
class QtkIOStream : public Assimp::IOStream {
|
||||
friend class QtkIOSystem;
|
||||
|
||||
protected:
|
||||
/** Constructor protected for private usage by QtkIOSystem */
|
||||
QtkIOStream(const char * pFile, const char * pMode);
|
||||
|
||||
public:
|
||||
~QtkIOStream() = default;
|
||||
|
||||
/**
|
||||
* Reads data into pvBuffer in pCount batches of length pSize.
|
||||
* The final pvBuffer will contain data read from all batches.
|
||||
*
|
||||
* @param pvBuffer Buffer to read data into.
|
||||
* @param pSize Size in bytes for each read.
|
||||
* @param pCount Number of reads to perform.
|
||||
* @return Length of total bytes read into pvBuffer, or -1 on failure.
|
||||
*/
|
||||
size_t Read(void * pvBuffer, size_t pSize, size_t pCount) override;
|
||||
|
||||
/**
|
||||
* Writes data from pvBuffer in pCount batches of length pSize.
|
||||
* The final mFile member will contain all input data from pvBuffer.
|
||||
*
|
||||
* @param pvBuffer Buffer to write data from.
|
||||
* @param pSize Size in bytes for each write.
|
||||
* @param pCount Number of writes to perfom.
|
||||
* @return Length of total bytes wrote into buffer, or -1 on failure.
|
||||
*/
|
||||
size_t Write(const void * pvBuffer, size_t pSize, size_t pCount) override;
|
||||
|
||||
/**
|
||||
* Change the current read position in the mFile Qt resource.
|
||||
*
|
||||
* @param pOffset Offset position to set.
|
||||
* @param pOrigin Origin position to use for relative offset.
|
||||
* @return aiReturn_SUCCESS, or aiReturn_FAILURE on failure.
|
||||
*/
|
||||
aiReturn Seek(size_t pOffset, aiOrigin pOrigin) override;
|
||||
|
||||
/**
|
||||
* @return The current position in mFile.
|
||||
*/
|
||||
[[nodiscard]] size_t Tell() const override;
|
||||
|
||||
/**
|
||||
* @return The total size of mFile.
|
||||
*/
|
||||
[[nodiscard]] size_t FileSize() const override;
|
||||
|
||||
/**
|
||||
* Flushes buffered data to mFile.
|
||||
*/
|
||||
void Flush() override;
|
||||
|
||||
private:
|
||||
// Corresponding file for Qt Resource path.
|
||||
QFile mFile;
|
||||
};
|
||||
} // namespace Qtk
|
||||
|
||||
#endif // QTK_QTKIOSTREAM_H
|
|
@ -0,0 +1,36 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Custom IO system for Qtk to support Qt Resource paths in Assimp ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
|
||||
#include "qtkiosystem.h"
|
||||
#include <QDir>
|
||||
|
||||
using namespace Qtk;
|
||||
|
||||
/*******************************************************************************
|
||||
* Public Member Functions
|
||||
******************************************************************************/
|
||||
|
||||
bool QtkIOSystem::Exists(const char * pFile) const {
|
||||
return QFileInfo::exists(pFile);
|
||||
}
|
||||
|
||||
char QtkIOSystem::getOsSeparator() const {
|
||||
return QDir::separator().toLatin1();
|
||||
}
|
||||
|
||||
Assimp::IOStream * QtkIOSystem::Open(const char * pFile, const char * pMode) {
|
||||
if(!Exists(pFile)) {
|
||||
qDebug() << "[Qtk::QtkIOSystem] failed to open file: " << pFile << "\n";
|
||||
return nullptr;
|
||||
}
|
||||
return new QtkIOStream(pFile, pMode);
|
||||
}
|
||||
|
||||
void QtkIOSystem::Close(Assimp::IOStream * pFile) {
|
||||
delete pFile;
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Custom IO system for Qtk to support Qt Resource paths in Assimp ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
|
||||
#include <assimp/IOStream.hpp>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
|
||||
#include "qtkapi.h"
|
||||
#include "qtkiostream.h"
|
||||
|
||||
#ifndef QTK_QTKIOSYSTEM_H
|
||||
#define QTK_QTKIOSYSTEM_H
|
||||
|
||||
namespace Qtk {
|
||||
/**
|
||||
* Assimp IO system for loading models with assimp, using Qt Resource paths.
|
||||
*/
|
||||
class QtkIOSystem : public Assimp::IOSystem {
|
||||
public:
|
||||
QtkIOSystem() = default;
|
||||
~QtkIOSystem() = default;
|
||||
|
||||
/**
|
||||
* @param pFile File path to check.
|
||||
* @return True if the file exists, else false.
|
||||
*/
|
||||
bool Exists(const char * pFile) const override;
|
||||
|
||||
/**
|
||||
* @return Path separator for platform OS.
|
||||
*/
|
||||
[[nodiscard]] char getOsSeparator() const override;
|
||||
|
||||
/**
|
||||
* @param pFile File to open for read / writing.
|
||||
* @param pMode Mode to open file. See `man fopen`.
|
||||
* @return QtkIOStream for the opened file.
|
||||
*/
|
||||
Assimp::IOStream * Open(
|
||||
const char * pFile, const char * pMode = "rb") override;
|
||||
|
||||
/**
|
||||
* @param pFile File to close.
|
||||
*/
|
||||
void Close(Assimp::IOStream * pFile) override;
|
||||
};
|
||||
} // namespace Qtk
|
||||
|
||||
#endif // QTK_QTKIOSYSTEM_H
|
|
@ -0,0 +1,119 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2023 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 "scene.h"
|
||||
#include "camera3d.h"
|
||||
|
||||
using namespace Qtk;
|
||||
|
||||
Camera3D Scene::mCamera;
|
||||
QMatrix4x4 Scene::mProjection;
|
||||
|
||||
/*******************************************************************************
|
||||
* Constructors / Destructors
|
||||
******************************************************************************/
|
||||
|
||||
Scene::Scene() : mSceneName("Default Scene") {
|
||||
mCamera.getTransform().setTranslation(0.0f, 0.0f, 20.0f);
|
||||
mCamera.getTransform().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;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Public Methods
|
||||
******************************************************************************/
|
||||
|
||||
template <> MeshRenderer * Scene::addObject(MeshRenderer * object) {
|
||||
initSceneObjectName(object);
|
||||
mMeshes.push_back(object);
|
||||
sceneUpdated(mSceneName);
|
||||
return object;
|
||||
}
|
||||
|
||||
template <> Model * Scene::addObject(Model * object) {
|
||||
initSceneObjectName(object);
|
||||
mModels.push_back(object);
|
||||
sceneUpdated(mSceneName);
|
||||
return object;
|
||||
}
|
||||
|
||||
void Scene::draw() {
|
||||
if(!mInit) {
|
||||
initializeOpenGLFunctions();
|
||||
init();
|
||||
mInit = true;
|
||||
}
|
||||
|
||||
while(!mModelLoadQueue.empty()) {
|
||||
auto modelSpec = mModelLoadQueue.front();
|
||||
// Load the model and add it to the scene.
|
||||
addObject(new Model(modelSpec.first.c_str(), modelSpec.second.c_str()));
|
||||
mModelLoadQueue.pop();
|
||||
}
|
||||
|
||||
if(mPause) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(mSkybox != Q_NULLPTR) {
|
||||
mSkybox->draw();
|
||||
}
|
||||
for(const auto & model : mModels) {
|
||||
model->draw();
|
||||
}
|
||||
for(const auto & mesh : mMeshes) {
|
||||
mesh->draw();
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Object *> Scene::getObjects() const {
|
||||
// All scene objects must inherit from Qtk::Object.
|
||||
std::vector<Object *> objects(mMeshes.begin(), mMeshes.end());
|
||||
for(const auto & model : mModels) {
|
||||
objects.push_back(model);
|
||||
if(objects.back() == nullptr) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
return objects;
|
||||
}
|
||||
|
||||
Object * Scene::getObject(const QString & name) const {
|
||||
for(const auto & object : getObjects()) {
|
||||
if(object->getName() == name.toStdString()) {
|
||||
return object;
|
||||
}
|
||||
}
|
||||
return Q_NULLPTR;
|
||||
}
|
||||
|
||||
void Scene::setSkybox(Skybox * skybox) {
|
||||
delete mSkybox;
|
||||
mSkybox = skybox;
|
||||
}
|
||||
|
||||
void Scene::initSceneObjectName(Object * object) {
|
||||
if(!mObjectCount.count(object->getName())) {
|
||||
mObjectCount[object->getName()] = 1;
|
||||
} else {
|
||||
mObjectCount[object->getName()]++;
|
||||
}
|
||||
auto count = mObjectCount[object->getName()];
|
||||
if(count > 1) {
|
||||
object->setName(object->getName() + " (" + std::to_string(count) + ")");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,268 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2023 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 <QMatrix4x4>
|
||||
#include <QUrl>
|
||||
|
||||
#include <queue>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
#include "camera3d.h"
|
||||
#include "meshrenderer.h"
|
||||
#include "model.h"
|
||||
#include "skybox.h"
|
||||
|
||||
namespace Qtk {
|
||||
/**
|
||||
* An abstract Scene class to inherit from when building new scenes.
|
||||
*
|
||||
* This class provides the following objects to any inheriting scene:
|
||||
* Skybox, Camera
|
||||
* This class also provides containers for N instances of these objects:
|
||||
* MeshRenderers, Models
|
||||
*
|
||||
* To inherit from this class and define our own scene we must:
|
||||
*
|
||||
* Override and define the `init()` virtual member function. If we want our
|
||||
* scene to render using a Skybox, we should also initialize the mSkybox
|
||||
* member within the overridden definition of `init()` using
|
||||
* `Scene::setSkybox(...)`
|
||||
*
|
||||
* If the scene is to render any kind of movement we are required to override
|
||||
* the `update()` virtual method.
|
||||
*
|
||||
* If the child scene adds any objects which are not managed (drawn) by this
|
||||
* base class, the child scene class must also override the `draw()` method.
|
||||
*/
|
||||
class Scene : public QObject, protected QOpenGLFunctions {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/*************************************************************************
|
||||
* Contructors / Destructors
|
||||
************************************************************************/
|
||||
|
||||
Scene();
|
||||
|
||||
virtual ~Scene();
|
||||
|
||||
/*************************************************************************
|
||||
* Public Methods
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* Initialize objects within the scene
|
||||
*/
|
||||
virtual void init() = 0;
|
||||
|
||||
/**
|
||||
* Function called during OpenGL drawing event.
|
||||
*
|
||||
* This function is only called when the widget is redrawn.
|
||||
*/
|
||||
virtual void draw();
|
||||
|
||||
/**
|
||||
* Function called to update the QOpenGLWidget. Does not trigger a redraw.
|
||||
*
|
||||
* Calling this several times will still result in only one repaint.
|
||||
*/
|
||||
virtual void update() {}
|
||||
|
||||
void loadModel(const QUrl & url) {
|
||||
auto fileName = url.fileName().replace(".obj", "").toStdString();
|
||||
auto filePath = url.toLocalFile().toStdString();
|
||||
loadModel(fileName, filePath);
|
||||
}
|
||||
|
||||
void loadModel(const std::string & name, const std::string & path) {
|
||||
// Add the dropped model to the load queue.
|
||||
// This is consumed during rendering of the scene if not empty.
|
||||
mModelLoadQueue.emplace(name, path);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* Accessors
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* @return All Qtk::Objects within the scene.
|
||||
* If any object is invalid, we return an empty vector.
|
||||
*/
|
||||
[[nodiscard]] std::vector<Object *> getObjects() const;
|
||||
|
||||
/**
|
||||
* Retrieve and object from the scene by it's objectName.
|
||||
*
|
||||
* @param name The objectName to look for within this scene.
|
||||
* @return The found object or Q_NULLPTR if none found.
|
||||
*/
|
||||
[[nodiscard]] Object * getObject(const QString & name) const;
|
||||
|
||||
/**
|
||||
* @return The number of objects within the scene with the given name.
|
||||
*/
|
||||
[[nodiscard]] uint64_t getObjectCount(const QString & name) {
|
||||
return mObjectCount.count(name.toStdString())
|
||||
? mObjectCount[name.toStdString()]
|
||||
: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Camera attached to this scene.
|
||||
*/
|
||||
[[nodiscard]] inline static Camera3D & getCamera() { return mCamera; }
|
||||
|
||||
/**
|
||||
* @return View matrix for the camera attached to this scene.
|
||||
*/
|
||||
[[nodiscard]] inline static QMatrix4x4 getViewMatrix() {
|
||||
return mCamera.toMatrix();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Projection matrix for the current view into the scene.
|
||||
*/
|
||||
[[nodiscard]] inline static QMatrix4x4 & getProjectionMatrix() {
|
||||
return mProjection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The active skybox for this scene.
|
||||
*/
|
||||
[[nodiscard]] inline Skybox * getSkybox() { return mSkybox; }
|
||||
|
||||
/**
|
||||
* @return The name for this scene. This is entirely user defined and not
|
||||
* a Qt objectName.
|
||||
*/
|
||||
[[nodiscard]] inline QString getSceneName() const { return mSceneName; }
|
||||
|
||||
/**
|
||||
* @return All MeshRenderers within the scene.
|
||||
*/
|
||||
[[nodiscard]] inline const std::vector<MeshRenderer *> & getMeshes()
|
||||
const {
|
||||
return mMeshes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return All Models within the scene.
|
||||
*/
|
||||
[[nodiscard]] inline const std::vector<Model *> & getModels() const {
|
||||
return mModels;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* Setters
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* @param skybox New skybox to use for this scene.
|
||||
*/
|
||||
void setSkybox(Skybox * skybox);
|
||||
|
||||
/**
|
||||
* Adds objects to the scene.
|
||||
* This template provides explicit specializations for valid types.
|
||||
* Adding any object other than these types will cause errors.
|
||||
* TODO: Refactor to use Object base class container for scene objects.
|
||||
*
|
||||
* If creating a new object type for a scene, it must inherit Qtk::Object
|
||||
* and provide a specialization for this method.
|
||||
*
|
||||
* @param object The new object to add to the scene.
|
||||
* @return The object added to the scene.
|
||||
*/
|
||||
template <typename T> T * addObject(T * object);
|
||||
|
||||
/**
|
||||
* @param name The name to use for this scene.
|
||||
*/
|
||||
inline void setSceneName(QString name) { mSceneName = std::move(name); }
|
||||
|
||||
inline void setPause(bool pause) { mPause = pause; }
|
||||
|
||||
signals:
|
||||
/**
|
||||
* Signal thrown when the scene is modified by adding or removing objects.
|
||||
* This can be caught by a main application to update any associated data.
|
||||
*
|
||||
* @param sceneName The scene that has been updated.
|
||||
*/
|
||||
void sceneUpdated(QString sceneName);
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* Public Members
|
||||
************************************************************************/
|
||||
public:
|
||||
/* Models used for storing 3D models in the scene. */
|
||||
std::vector<Model *> mModels {};
|
||||
|
||||
/* Queue of models requested to load at runtime. */
|
||||
std::queue<std::pair<std::string, std::string>> mModelLoadQueue;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Initialize an object name relative to other objects already loaded.
|
||||
* Protects against having two objects with the same name.
|
||||
*
|
||||
* @param object Qtk Object to name within this scene.
|
||||
*/
|
||||
void initSceneObjectName(Qtk::Object * object);
|
||||
|
||||
/*************************************************************************
|
||||
* Private Members
|
||||
************************************************************************/
|
||||
|
||||
static Camera3D mCamera;
|
||||
static QMatrix4x4 mProjection;
|
||||
bool mInit = false;
|
||||
/* Pause rendering of the scene. */
|
||||
bool mPause = false;
|
||||
|
||||
QString mSceneName;
|
||||
/* The skybox for this scene. */
|
||||
Skybox * mSkybox {};
|
||||
/* MeshRenderers used simple geometry. */
|
||||
std::vector<MeshRenderer *> mMeshes {};
|
||||
/* Track count of objects with same initial name. */
|
||||
std::unordered_map<std::string, uint64_t> mObjectCount;
|
||||
};
|
||||
|
||||
class SceneEmpty : public Scene {
|
||||
public:
|
||||
void init() override { setSceneName("Empty Scene"); }
|
||||
|
||||
void draw() override { Scene::draw(); }
|
||||
|
||||
void update() override { Scene::update(); }
|
||||
};
|
||||
|
||||
class SceneInterface : public Scene {
|
||||
public:
|
||||
explicit SceneInterface(Scene * scene) : mScene(scene) {}
|
||||
|
||||
void init() override { mScene->init(); }
|
||||
|
||||
void draw() override { mScene->draw(); }
|
||||
|
||||
void update() override { mScene->update(); }
|
||||
|
||||
protected:
|
||||
Scene * mScene;
|
||||
};
|
||||
|
||||
} // namespace Qtk
|
||||
|
||||
#endif // QTK_SCENE_H
|
|
@ -1,12 +1,12 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Collection of static mesh data for quick initialization ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
|
||||
#include <mesh.h>
|
||||
#include "shape.h"
|
||||
|
||||
using namespace Qtk;
|
||||
|
|
@ -1,25 +1,21 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Collection of static mesh data for quick initialization ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
#ifndef QTK_MESH_H
|
||||
#define QTK_MESH_H
|
||||
#ifndef QTK_SHAPE_H
|
||||
#define QTK_SHAPE_H
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include <QOpenGLWidget>
|
||||
#include <QVector2D>
|
||||
#include <QVector3D>
|
||||
#include <utility>
|
||||
|
||||
#include <qtkapi.h>
|
||||
#include <transform3D.h>
|
||||
|
||||
namespace Qtk {
|
||||
class MeshRenderer;
|
||||
|
||||
class Object;
|
||||
#include "qtkapi.h"
|
||||
#include "transform3D.h"
|
||||
|
||||
// Define vertices for drawing a cube using two faces (8 vertex points)
|
||||
// Front Vertices
|
||||
|
@ -62,7 +58,6 @@ namespace Qtk {
|
|||
VECTOR_BACK, VECTOR_BACK, VECTOR_BACK
|
||||
// clang-format on
|
||||
|
||||
|
||||
// Colors using QVector3Ds as RGB values
|
||||
#define WHITE VECTOR_ONE
|
||||
#define BLACK VECTOR_ZERO
|
||||
|
@ -78,6 +73,11 @@ namespace Qtk {
|
|||
#define UV_RIGHT QVector2D(0.0f, 1.0f)
|
||||
#define UV_CORNER QVector2D(1.0f, 1.0f)
|
||||
|
||||
namespace Qtk {
|
||||
class MeshRenderer;
|
||||
|
||||
class Object;
|
||||
|
||||
// TODO: Vertices.getData(); Vertices.getStride();
|
||||
typedef std::vector<QVector3D> Vertices;
|
||||
typedef std::vector<QVector3D> Colors;
|
||||
|
@ -105,6 +105,15 @@ namespace Qtk {
|
|||
* Constructors / Destructors
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
*
|
||||
* @param mode OpenGL draw mode to use for this shape.
|
||||
* @param v Vertex data for this shape.
|
||||
* @param i Index data for this shape.
|
||||
* @param c Color data for this shape.
|
||||
* @param t Texture coordinates for this shape.
|
||||
* @param n Normals for this shape.
|
||||
*/
|
||||
explicit ShapeBase(
|
||||
DrawMode mode = QTK_DRAW_ARRAYS, Vertices v = {}, Indices i = {},
|
||||
Colors c = {}, TexCoords t = {}, Normals n = {}) :
|
||||
|
@ -117,24 +126,42 @@ namespace Qtk {
|
|||
* Accessors
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* @return Vertex data for this shape.
|
||||
*/
|
||||
[[nodiscard]] inline const Vertices & getVertices() const {
|
||||
return mVertices;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Index data for this shape.
|
||||
*/
|
||||
[[nodiscard]] inline const Indices & getIndexData() const {
|
||||
return mIndices;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Color data for this shape.
|
||||
*/
|
||||
[[nodiscard]] inline const Colors & getColors() const { return mColors; }
|
||||
|
||||
/**
|
||||
* @return Texture coordinates for this shape.
|
||||
*/
|
||||
[[nodiscard]] inline const TexCoords & getTexCoords() const {
|
||||
return mTexCoords;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Normals for this shape.
|
||||
*/
|
||||
[[nodiscard]] inline const Normals & getNormals() const {
|
||||
return mNormals;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Stride for texture coordinates on this shape.
|
||||
*/
|
||||
[[nodiscard]] inline size_t getTexCoordsStride() const {
|
||||
return mTexCoords.size() * sizeof(mTexCoords[0]);
|
||||
}
|
||||
|
@ -145,7 +172,6 @@ namespace Qtk {
|
|||
************************************************************************/
|
||||
|
||||
DrawMode mDrawMode;
|
||||
|
||||
Vertices mVertices {};
|
||||
Colors mColors {};
|
||||
Indices mIndices {};
|
||||
|
@ -160,6 +186,7 @@ namespace Qtk {
|
|||
************************************************************************/
|
||||
|
||||
friend MeshRenderer;
|
||||
|
||||
friend Object;
|
||||
|
||||
/*************************************************************************
|
||||
|
@ -174,30 +201,45 @@ namespace Qtk {
|
|||
* Setters
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* @param value Vertex data to use for this shape.
|
||||
*/
|
||||
virtual inline void setVertices(const Vertices & value) {
|
||||
mVertices = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value Index data to use for this shape.
|
||||
*/
|
||||
virtual inline void setIndices(const Indices & value) {
|
||||
mIndices = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value Color data to use for this shape.
|
||||
*/
|
||||
virtual inline void setColors(const Colors & value) { mColors = value; }
|
||||
|
||||
/**
|
||||
* @param value Texture coordinates to use for this shape.
|
||||
*/
|
||||
virtual inline void setTexCoords(const TexCoords & value) {
|
||||
mTexCoords = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value Normals to use for this shape.
|
||||
*/
|
||||
virtual inline void setNormals(const Normals & value) {
|
||||
mNormals = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value Shape to copy into this Shape.
|
||||
*/
|
||||
virtual inline void setShape(const Shape & value) { *this = value; }
|
||||
};
|
||||
|
||||
/* Primitives inherit from ShapeBase, doesn't allow setting shape values. */
|
||||
class QTKAPI Mesh {};
|
||||
|
||||
/* Simple Cube shape. */
|
||||
struct QTKAPI Cube : public ShapeBase {
|
||||
explicit Cube(DrawMode mode = QTK_DRAW_ARRAYS);
|
||||
|
@ -209,4 +251,4 @@ namespace Qtk {
|
|||
};
|
||||
} // namespace Qtk
|
||||
|
||||
#endif // QTK_MESH_H
|
||||
#endif // QTK_SHAPE_H
|
|
@ -1,17 +1,32 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Skybox class using QtOpenGL ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
|
||||
#include <scene.h>
|
||||
#include <skybox.h>
|
||||
#include <texture.h>
|
||||
#include "skybox.h"
|
||||
#include "scene.h"
|
||||
#include "texture.h"
|
||||
|
||||
using namespace Qtk;
|
||||
|
||||
/*******************************************************************************
|
||||
* Constructors / Destructors
|
||||
******************************************************************************/
|
||||
|
||||
Skybox::Skybox(const std::string & name) :
|
||||
Skybox(
|
||||
":/textures/skybox/right.png", ":/textures/skybox/top.png",
|
||||
":/textures/skybox/front.png", ":/textures/skybox/left.png",
|
||||
":/textures/skybox/bottom.png", ":/textures/skybox/back.png", name) {}
|
||||
|
||||
Skybox::Skybox(QOpenGLTexture * cubeMap, const std::string & name) {
|
||||
mTexture.setTexture(cubeMap);
|
||||
init();
|
||||
}
|
||||
|
||||
Skybox::Skybox(
|
||||
const std::string & right, const std::string & top,
|
||||
const std::string & front, const std::string & left,
|
||||
|
@ -27,16 +42,6 @@ Skybox::Skybox(
|
|||
QImage(back.c_str()));
|
||||
}
|
||||
|
||||
Skybox::Skybox(const std::string & name) :
|
||||
Skybox(
|
||||
":/right.png", ":/top.png", ":/front.png", ":/left.png", ":/bottom.png",
|
||||
":/back.png", name) {}
|
||||
|
||||
Skybox::Skybox(QOpenGLTexture * cubeMap, const std::string & name) {
|
||||
mTexture.setTexture(cubeMap);
|
||||
init();
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Public Member Functions
|
||||
******************************************************************************/
|
||||
|
@ -73,8 +78,10 @@ void Skybox::init() {
|
|||
|
||||
// Set up shader program
|
||||
mProgram.create();
|
||||
mProgram.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/skybox.vert");
|
||||
mProgram.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/skybox.frag");
|
||||
mProgram.addShaderFromSourceFile(
|
||||
QOpenGLShader::Vertex, ":/shaders/skybox.vert");
|
||||
mProgram.addShaderFromSourceFile(
|
||||
QOpenGLShader::Fragment, ":/shaders/skybox.frag");
|
||||
mProgram.link();
|
||||
mProgram.bind();
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Skybox class using QtOpenGL ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
|
@ -15,10 +15,10 @@
|
|||
#include <QOpenGLTexture>
|
||||
#include <QOpenGLVertexArrayObject>
|
||||
|
||||
#include <camera3d.h>
|
||||
#include <mesh.h>
|
||||
#include <qtkapi.h>
|
||||
#include <texture.h>
|
||||
#include "camera3d.h"
|
||||
#include "qtkapi.h"
|
||||
#include "shape.h"
|
||||
#include "texture.h"
|
||||
|
||||
namespace Qtk {
|
||||
/**
|
||||
|
@ -33,11 +33,35 @@ namespace Qtk {
|
|||
************************************************************************/
|
||||
|
||||
// Delegate this constructor to use default skybox images
|
||||
|
||||
/**
|
||||
* Construct Skybox using default images.
|
||||
*
|
||||
* @param name The objectName to use for the Skybox.
|
||||
*/
|
||||
explicit Skybox(const std::string & name = "Skybox");
|
||||
|
||||
/**
|
||||
* Construct a skybox with an existing QOpenGLTexture.
|
||||
* The texture should be a fully initialized cube map.
|
||||
*
|
||||
* @param cubeMap QOpenGLTexture to use for the new Skybox.
|
||||
* @param name The objectName to use for the Skybox.
|
||||
*/
|
||||
explicit Skybox(
|
||||
QOpenGLTexture * cubeMap, const std::string & name = "Skybox");
|
||||
|
||||
/**
|
||||
* Construct a Skybox.
|
||||
*
|
||||
* @param right Image to use for the right side of the Skybox.
|
||||
* @param top Image to use for the top side of the Skybox.
|
||||
* @param front Image to use for the front side of the Skybox.
|
||||
* @param left Image to use for the left side of the Skybox.
|
||||
* @param bottom Image to use for the bottom side of the Skybox.
|
||||
* @param back Image to use for the back side of the Skybox.
|
||||
* @param name The objectName to use for this Skybox.
|
||||
*/
|
||||
Skybox(
|
||||
const std::string & right, const std::string & top,
|
||||
const std::string & front, const std::string & left,
|
||||
|
@ -50,6 +74,9 @@ namespace Qtk {
|
|||
* Public Methods
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* Draws the skybox.
|
||||
*/
|
||||
void draw();
|
||||
|
||||
private:
|
||||
|
@ -57,6 +84,9 @@ namespace Qtk {
|
|||
* Private Methods
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* Initializes OpenGL buffers and shaders for this skybox.
|
||||
*/
|
||||
void init();
|
||||
|
||||
/*************************************************************************
|
|
@ -1,6 +1,6 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Texture class to help with texture and image initializations ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
|
@ -8,21 +8,19 @@
|
|||
|
||||
#include <QDebug>
|
||||
#include <QImageReader>
|
||||
#include <utility>
|
||||
|
||||
#include <texture.h>
|
||||
#include "app/qtkmainwindow.h"
|
||||
#include "texture.h"
|
||||
|
||||
using namespace Qtk;
|
||||
|
||||
QImage * OpenGLTextureFactory::initImage(
|
||||
QImage OpenGLTextureFactory::initImage(
|
||||
const char * image, bool flipX, bool flipY) {
|
||||
// Qt6 limits loaded images to 256MB by default
|
||||
QImageReader::setAllocationLimit(512);
|
||||
auto loadedImage = new QImage(QImage(image).mirrored(flipX, flipY));
|
||||
if(loadedImage->isNull()) {
|
||||
qDebug() << "Error loading image: " << image << "\n";
|
||||
qDebug() << QImageReader::supportedImageFormats();
|
||||
return Q_NULLPTR;
|
||||
QImageReader::setAllocationLimit(1024);
|
||||
auto loadedImage = QImage(image).mirrored(flipX, flipY);
|
||||
if(loadedImage.isNull()) {
|
||||
return defaultTexture();
|
||||
}
|
||||
|
||||
return loadedImage;
|
||||
|
@ -30,13 +28,12 @@ QImage * OpenGLTextureFactory::initImage(
|
|||
|
||||
QOpenGLTexture * OpenGLTextureFactory::initTexture(
|
||||
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);
|
||||
newTexture->setData(*image);
|
||||
newTexture->setData(image);
|
||||
newTexture->setWrapMode(QOpenGLTexture::Repeat);
|
||||
newTexture->setMinMagFilters(
|
||||
QOpenGLTexture::LinearMipMapLinear, QOpenGLTexture::Linear);
|
||||
delete image;
|
||||
return newTexture;
|
||||
}
|
||||
|
||||
|
@ -58,9 +55,7 @@ QOpenGLTexture * OpenGLTextureFactory::initCubeMap(
|
|||
const QImage & right, const QImage & top, const QImage & front,
|
||||
const QImage & left, const QImage & bottom, const QImage & back) {
|
||||
auto texture = new QOpenGLTexture(QOpenGLTexture::TargetCubeMap);
|
||||
std::vector<QImage> faceTextures = {std::move(right), std::move(top),
|
||||
std::move(front), std::move(left),
|
||||
std::move(bottom), std::move(back)};
|
||||
std::vector<QImage> faceTextures = {right, top, front, left, bottom, back};
|
||||
// Initialize skybox cubemap texture
|
||||
texture->create();
|
||||
texture->bind();
|
||||
|
@ -74,6 +69,7 @@ QOpenGLTexture * OpenGLTextureFactory::initCubeMap(
|
|||
QImage faceImage(faceTextures[i]);
|
||||
if(faceImage.isNull()) {
|
||||
qDebug() << "Error loading cube map image\n";
|
||||
faceImage = defaultTexture();
|
||||
}
|
||||
faceImage = faceImage.convertToFormat(QImage::Format_RGBA8888);
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Texture class to help with texture and image initializations ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
|
@ -9,11 +9,12 @@
|
|||
#ifndef QTOPENGL_TEXTURE_H
|
||||
#define QTOPENGL_TEXTURE_H
|
||||
|
||||
#include <QOpenGLShaderProgram>
|
||||
#include <QOpenGLTexture>
|
||||
#include <utility>
|
||||
|
||||
#include <qtkapi.h>
|
||||
#include <QOpenGLShaderProgram>
|
||||
#include <QOpenGLTexture>
|
||||
|
||||
#include "qtkapi.h"
|
||||
|
||||
namespace Qtk {
|
||||
/**
|
||||
|
@ -73,9 +74,9 @@ namespace Qtk {
|
|||
* Can be absolute or Qt resource path.
|
||||
* @param flipX If true the image will be flipped on X axis.
|
||||
* @param flipY If true the image will be flipped on Y axis.
|
||||
* @return Pointer to an initialized QImage object.
|
||||
* @return QImage object.
|
||||
*/
|
||||
static QImage * initImage(
|
||||
static QImage initImage(
|
||||
const char * image, bool flipX = false, bool flipY = false);
|
||||
|
||||
/**
|
||||
|
@ -131,6 +132,14 @@ namespace Qtk {
|
|||
const char * right, const char * top, const char * front,
|
||||
const char * left, const char * bottom, const char * back);
|
||||
|
||||
/// The texture used in place of a missing texture.
|
||||
static QImage defaultTexture() {
|
||||
// Use plaster for default texture if image fails to load.
|
||||
// This prevents segfaults when loading a texture that doesn't exist.
|
||||
// TODO: Replace with a '?' texture to indicate missing texture.
|
||||
return QImage(":/textures/plaster.png");
|
||||
}
|
||||
|
||||
private:
|
||||
// Private ctor to prevent creating instances of this class
|
||||
OpenGLTextureFactory() = default;
|
||||
|
@ -155,52 +164,109 @@ namespace Qtk {
|
|||
|
||||
Texture() = default;
|
||||
|
||||
/**
|
||||
* Copies an existing Texture object.
|
||||
*
|
||||
* @param value Texture to copy.
|
||||
*/
|
||||
Texture(const Texture & value) {
|
||||
mOpenGLTexture = OpenGLTextureFactory::initTexture(value.mPath);
|
||||
mPath = value.mPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param path Path to texture to load on disk.
|
||||
* @param flipX True if texture is to be flipped on the X axis.
|
||||
* @param flipY True if texture is to be flipped on the Y axis.
|
||||
*/
|
||||
explicit Texture(
|
||||
const char * path, bool flipX = false, bool flipY = false) :
|
||||
mOpenGLTexture(OpenGLTextureFactory::initTexture(path, flipX, flipY)),
|
||||
mPath(path) {}
|
||||
|
||||
/**
|
||||
* Construct a Texture using an existing QOpenGLTexture.
|
||||
*
|
||||
* @param texture OpenGL texture to use for this Texture.
|
||||
*/
|
||||
explicit Texture(QOpenGLTexture * texture) : mOpenGLTexture(texture) {}
|
||||
|
||||
~Texture() { mOpenGLTexture->destroy(); }
|
||||
|
||||
/*************************************************************************
|
||||
* Public Methods
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* @return True if the OpenGL texture has been initialized.
|
||||
*/
|
||||
[[nodiscard]] inline bool hasTexture() const {
|
||||
return mOpenGLTexture != Q_NULLPTR;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* Accessors
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* @return QOpenGLTexture associated with this Texture.
|
||||
*/
|
||||
[[nodiscard]] inline QOpenGLTexture & getOpenGLTexture() const {
|
||||
return *mOpenGLTexture;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Path to this Texture on disk.
|
||||
*/
|
||||
[[nodiscard]] inline std::string getPath() const { return mPath; }
|
||||
|
||||
/*************************************************************************
|
||||
* Setters
|
||||
************************************************************************/
|
||||
|
||||
void setTexture(
|
||||
/**
|
||||
* Replaces the current texture with a new texture.
|
||||
*
|
||||
* @param path Path to the new texture to load.
|
||||
* @param flipX True if texture is to be flipped on the X axis.
|
||||
* @param flipY True if texture is to be flipped on the Y axis.
|
||||
*/
|
||||
inline void setTexture(
|
||||
const std::string & path, bool flipX = false, bool flipY = false) {
|
||||
mOpenGLTexture =
|
||||
OpenGLTextureFactory::initTexture(path.data(), flipX, flipY);
|
||||
mPath = path.data();
|
||||
setTexture(path.c_str(), flipX, flipY);
|
||||
}
|
||||
|
||||
void setTexture(
|
||||
/**
|
||||
* @param path Path to the new texture to load.
|
||||
* @param flipX True if texture is to be flipped on the X axis.
|
||||
* @param flipY True if texture is to be flipped on the Y axis.
|
||||
*/
|
||||
inline void setTexture(
|
||||
const char * path, bool flipX = false, bool flipY = false) {
|
||||
mOpenGLTexture = OpenGLTextureFactory::initTexture(path, flipX, flipY);
|
||||
mPath = path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this Texture to be a cube map with all identical sides.
|
||||
*
|
||||
* @param path Path to texture to use for all sides of the cube map.
|
||||
*/
|
||||
virtual inline void setCubeMap(const char * path) {
|
||||
mOpenGLTexture = OpenGLTextureFactory::initCubeMap(path);
|
||||
mPath = path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this Texture to be a cube map with provided sides.
|
||||
*
|
||||
* @param right Path to texture to use for right cube map side.
|
||||
* @param top Path to texture to use for top cube map side.
|
||||
* @param front Path to texture to use for front cube map side.
|
||||
* @param left Path to texture to use for left cube map side.
|
||||
* @param bottom Path to texture to use for bottom cube map side.
|
||||
* @param back Path to texture to use for back cube map side.
|
||||
*/
|
||||
virtual inline void setCubeMap(
|
||||
const char * right, const char * top, const char * front,
|
||||
const char * left, const char * bottom, const char * back) {
|
||||
|
@ -208,6 +274,16 @@ namespace Qtk {
|
|||
right, top, front, left, bottom, back);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this Texture to be a cube map with provided sides.
|
||||
*
|
||||
* @param right Path to texture to use for right cube map side.
|
||||
* @param top Path to texture to use for top cube map side.
|
||||
* @param front Path to texture to use for front cube map side.
|
||||
* @param left Path to texture to use for left cube map side.
|
||||
* @param bottom Path to texture to use for bottom cube map side.
|
||||
* @param back Path to texture to use for back cube map side.
|
||||
*/
|
||||
virtual inline void setCubeMap(
|
||||
const QImage & right, const QImage & top, const QImage & front,
|
||||
const QImage & left, const QImage & bottom, const QImage & back) {
|
||||
|
@ -215,18 +291,14 @@ namespace Qtk {
|
|||
right, top, front, left, bottom, back);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* Public Methods
|
||||
************************************************************************/
|
||||
|
||||
[[nodiscard]] inline bool hasTexture() const {
|
||||
return mOpenGLTexture != Q_NULLPTR;
|
||||
}
|
||||
|
||||
private:
|
||||
/*************************************************************************
|
||||
* Private Members
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* @param texture QOpenGLTexture to use for this Texture.
|
||||
*/
|
||||
inline void setTexture(QOpenGLTexture * texture) {
|
||||
mOpenGLTexture = texture;
|
||||
}
|
||||
|
@ -235,7 +307,6 @@ namespace Qtk {
|
|||
/* Path to this texture on disk or Qt resource. */
|
||||
const char * mPath {};
|
||||
};
|
||||
|
||||
} // namespace Qtk
|
||||
|
||||
#endif // QTOPENGL_TEXTURE_H
|
|
@ -1,13 +1,13 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Transform3D class to represent object position in 3D space ##
|
||||
## From following tutorials at trentreed.net ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
|
||||
#include <transform3D.h>
|
||||
#include "transform3D.h"
|
||||
|
||||
using namespace Qtk;
|
||||
|
||||
|
@ -16,7 +16,7 @@ const QVector3D Transform3D::LocalUp(0.0f, 1.0f, 0.0f);
|
|||
const QVector3D Transform3D::LocalRight(1.0f, 0.0f, 0.0f);
|
||||
|
||||
/*******************************************************************************
|
||||
* Transformations
|
||||
* Public Methods
|
||||
******************************************************************************/
|
||||
|
||||
void Transform3D::translate(const QVector3D & dt) {
|
||||
|
@ -29,19 +29,16 @@ void Transform3D::scale(const QVector3D & ds) {
|
|||
mScale *= ds;
|
||||
}
|
||||
|
||||
void Transform3D::rotate(const QQuaternion & dr) {
|
||||
m_dirty = true;
|
||||
mRotation = dr * mRotation;
|
||||
}
|
||||
|
||||
void Transform3D::grow(const QVector3D & ds) {
|
||||
m_dirty = true;
|
||||
mScale += ds;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Setters
|
||||
******************************************************************************/
|
||||
void Transform3D::rotate(const QQuaternion & dr) {
|
||||
m_dirty = true;
|
||||
mRotation = dr * mRotation;
|
||||
}
|
||||
|
||||
void Transform3D::setTranslation(const QVector3D & t) {
|
||||
m_dirty = true;
|
||||
|
@ -58,12 +55,6 @@ void Transform3D::setRotation(const QQuaternion & r) {
|
|||
mRotation = r;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Accessors
|
||||
******************************************************************************/
|
||||
|
||||
// Produces modelToWorld matrix using current set of transformations
|
||||
// Transformation * rotation * scale = modelToWorld
|
||||
const QMatrix4x4 & Transform3D::toMatrix() {
|
||||
if(m_dirty) {
|
||||
m_dirty = false;
|
||||
|
@ -75,10 +66,6 @@ const QMatrix4x4 & Transform3D::toMatrix() {
|
|||
return mWorld;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Queries
|
||||
******************************************************************************/
|
||||
|
||||
QVector3D Transform3D::getForward() const {
|
||||
return mRotation.rotatedVector(LocalForward);
|
||||
}
|
||||
|
@ -89,13 +76,10 @@ QVector3D Transform3D::getUp() const {
|
|||
|
||||
QVector3D Transform3D::getRight() const {
|
||||
return mRotation.rotatedVector(LocalRight);
|
||||
while(true) {
|
||||
int xx;
|
||||
};
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* QT Streams
|
||||
* Private Methods
|
||||
******************************************************************************/
|
||||
|
||||
namespace Qtk {
|
|
@ -1,6 +1,6 @@
|
|||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Transform3D class to represent object position in 3D space ##
|
||||
## From following tutorials at trentreed.net ##
|
||||
## ##
|
||||
|
@ -15,12 +15,10 @@
|
|||
#include <QVector3D>
|
||||
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#endif
|
||||
|
||||
#include <qtkapi.h>
|
||||
#include "qtkapi.h"
|
||||
|
||||
namespace Qtk {
|
||||
/**
|
||||
|
@ -37,75 +35,154 @@ namespace Qtk {
|
|||
mTranslation(0.0f, 0.0f, 0.0f) {}
|
||||
|
||||
/*************************************************************************
|
||||
* Transformations
|
||||
* Public Methods
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* @param dt Translation from last to current position.
|
||||
*/
|
||||
void translate(const QVector3D & dt);
|
||||
|
||||
/**
|
||||
* @param dx X translation from last to current position.
|
||||
* @param dy Y translation from last to current position.
|
||||
* @param dz Z translation from last to current position.
|
||||
*/
|
||||
inline void translate(float dx, float dy, float dz) {
|
||||
translate(QVector3D(dx, dy, dz));
|
||||
}
|
||||
|
||||
// Scale object with multiplication
|
||||
/**
|
||||
* Scale the object size.
|
||||
*
|
||||
* @param ds Scalar vector to apply to the transform.
|
||||
*/
|
||||
void scale(const QVector3D & ds);
|
||||
|
||||
/**
|
||||
* Scale the object size.
|
||||
*
|
||||
* @param dx Amount to scale on the X axis.
|
||||
* @param dy Amount to scale on the Y axis.
|
||||
* @param dz Amount to scale on the Z axis.
|
||||
*/
|
||||
inline void scale(float dx, float dy, float dz) {
|
||||
scale(QVector3D(dx, dy, dz));
|
||||
}
|
||||
|
||||
/**
|
||||
* Scale the object size.
|
||||
*
|
||||
* @param factor Scalar to apply to all axis of the object.
|
||||
*/
|
||||
inline void scale(float factor) {
|
||||
scale(QVector3D(factor, factor, factor));
|
||||
}
|
||||
|
||||
// Multiplying by a rotation
|
||||
void rotate(const QQuaternion & dr);
|
||||
|
||||
inline void rotate(float angle, const QVector3D & axis) {
|
||||
rotate(QQuaternion::fromAxisAndAngle(axis, angle));
|
||||
}
|
||||
|
||||
inline void rotate(float angle, float ax, float ay, float az) {
|
||||
rotate(QQuaternion::fromAxisAndAngle(ax, ay, az, angle));
|
||||
}
|
||||
|
||||
// Scale object by addition
|
||||
/**
|
||||
* @param ds 3D vector to add to scale axis.
|
||||
*/
|
||||
void grow(const QVector3D & ds);
|
||||
|
||||
/**
|
||||
* @param dx Amount to grow X axis.
|
||||
* @param dy Amount to grow Y axis.
|
||||
* @param dz Amount to grow Z axis.
|
||||
*/
|
||||
inline void grow(float dx, float dy, float dz) {
|
||||
grow(QVector3D(dx, dy, dz));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param factor Amount to grow all axis equally.
|
||||
*/
|
||||
inline void grow(float factor) {
|
||||
grow(QVector3D(factor, factor, factor));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param dr Rotation to apply to the transform.
|
||||
*/
|
||||
void rotate(const QQuaternion & dr);
|
||||
|
||||
/**
|
||||
* @param angle Angle to rotate.
|
||||
* @param axis Axis to rotate apply the rotation on.
|
||||
*/
|
||||
inline void rotate(float angle, const QVector3D & axis) {
|
||||
rotate(QQuaternion::fromAxisAndAngle(axis, angle));
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply rotation upon an axis represented by the 3D vector (x, y, z)
|
||||
*
|
||||
* @param angle Angle to rotate.
|
||||
* @param ax X axis to apply the rotation on.
|
||||
* @param ay Y axis to apply the rotation on.
|
||||
* @param az Z axis to apply the rotation on.
|
||||
*/
|
||||
inline void rotate(float angle, float ax, float ay, float az) {
|
||||
rotate(QQuaternion::fromAxisAndAngle(ax, ay, az, angle));
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* Setters
|
||||
************************************************************************/
|
||||
|
||||
// Set object position
|
||||
/**
|
||||
* @param t Position to move the transform to.
|
||||
*/
|
||||
void setTranslation(const QVector3D & t);
|
||||
|
||||
/**
|
||||
* @param x X position to set transform.
|
||||
* @param y Y position to set transform.
|
||||
* @param z Z position to set transform.
|
||||
*/
|
||||
inline void setTranslation(float x, float y, float z) {
|
||||
setTranslation(QVector3D(x, y, z));
|
||||
}
|
||||
|
||||
// Set object scale
|
||||
/**
|
||||
* @param s Scale to set for this transform.
|
||||
*/
|
||||
void setScale(const QVector3D & s);
|
||||
|
||||
/**
|
||||
* @param x X axis scale to set for this transform.
|
||||
* @param y Y axis scale to set for this transform.
|
||||
* @param z Z axis scale to set for this transform.
|
||||
*/
|
||||
inline void setScale(float x, float y, float z) {
|
||||
setScale(QVector3D(x, y, z));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param k Scale to set for all axis on this transform.
|
||||
*/
|
||||
inline void setScale(float k) { setScale(QVector3D(k, k, k)); }
|
||||
|
||||
// Set object rotation
|
||||
/**
|
||||
* @param r Rotation to set for this transform.
|
||||
*/
|
||||
void setRotation(const QQuaternion & r);
|
||||
|
||||
/**
|
||||
* @param angle Angle to set for rotation.
|
||||
* @param axis Axis to set rotation for.
|
||||
*/
|
||||
inline void setRotation(float angle, const QVector3D & axis) {
|
||||
setRotation(QQuaternion::fromAxisAndAngle(axis, angle));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a rotation upon an axis represented by the 3D vector (x, y, z)
|
||||
*
|
||||
* @param angle Angle to set rotation.
|
||||
* @param ax X axis to set angle for.
|
||||
* @param ay Y axis to set angle for.
|
||||
* @param az Z axis to set angle for.
|
||||
*/
|
||||
inline void setRotation(float angle, float ax, float ay, float az) {
|
||||
setRotation(QQuaternion::fromAxisAndAngle(ax, ay, az, angle));
|
||||
}
|
||||
|
@ -114,31 +191,55 @@ namespace Qtk {
|
|||
* Getters
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* @return Translation for this transform.
|
||||
*/
|
||||
[[nodiscard]] inline const QVector3D & getTranslation() const {
|
||||
return mTranslation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Scale for this transform.
|
||||
*/
|
||||
[[nodiscard]] inline const QVector3D & getScale() const { return mScale; }
|
||||
|
||||
/**
|
||||
* @return Rotation for this transform.
|
||||
*/
|
||||
[[nodiscard]] inline const QQuaternion & getRotation() const {
|
||||
return mRotation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Model to world matrix for this transform.
|
||||
* transformation * rotation * scale = ModelToWorld
|
||||
*/
|
||||
const QMatrix4x4 & toMatrix();
|
||||
|
||||
/**
|
||||
* @return Forward vector for this transform.
|
||||
*/
|
||||
[[nodiscard]] QVector3D getForward() const;
|
||||
|
||||
/**
|
||||
* @return Up vector for this transform.
|
||||
*/
|
||||
[[nodiscard]] QVector3D getUp() const;
|
||||
|
||||
/**
|
||||
* @return Right vector for this transform.
|
||||
*/
|
||||
[[nodiscard]] QVector3D getRight() const;
|
||||
|
||||
/*************************************************************************
|
||||
* Public members
|
||||
* Public Members
|
||||
************************************************************************/
|
||||
|
||||
static const QVector3D LocalForward, LocalUp, LocalRight;
|
||||
|
||||
private:
|
||||
/*************************************************************************
|
||||
* Private members
|
||||
* Private Members
|
||||
************************************************************************/
|
||||
|
||||
QVector3D mTranslation;
|
||||
|
@ -156,7 +257,6 @@ namespace Qtk {
|
|||
#endif
|
||||
};
|
||||
|
||||
// Qt Streams
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
QDebug operator<<(QDebug dbg, const Transform3D & transform);
|
||||
#endif
|