Compare commits

5 Commits

Author SHA1 Message Date
8e7058625d update
Some checks failed
All Builds / Qtk (-DCMAKE_PREFIX_PATH=/home/runner/work/qtk/Qt/$QT_VERSION/gcc_64/ $CONFIG, -j $(nproc), macos-latest) (pull_request) Has been cancelled
All Builds / Qtk (-DCMAKE_PREFIX_PATH=/home/runner/work/qtk/Qt/$QT_VERSION/gcc_64/ $CONFIG, -j $(nproc), ubuntu-latest) (pull_request) Has been cancelled
All Builds / Qtk (-DCMAKE_PREFIX_PATH=D:/a/qtk/qtk/Qt/$QT_VERSION/mingw81_64/ $CONFIG, , windows-latest) (pull_request) Has been cancelled
All Builds / Qtk-Library (-DCMAKE_PREFIX_PATH=/home/runner/work/qtk/Qt/$QT_VERSION/gcc_64/ $CONFIG, -j $(nproc), macos-latest) (pull_request) Has been cancelled
All Builds / Qtk-Library (-DCMAKE_PREFIX_PATH=/home/runner/work/qtk/Qt/$QT_VERSION/gcc_64/ $CONFIG, -j $(nproc), ubuntu-latest) (pull_request) Has been cancelled
All Builds / Qtk-Library (-DCMAKE_PREFIX_PATH=D:/a/qtk/qtk/Qt/$QT_VERSION/mingw81_64/ $CONFIG, , windows-latest) (pull_request) Has been cancelled
All Builds / Qtk-Plugins (-DCMAKE_PREFIX_PATH=/home/runner/work/qtk/Qt/$QT_VERSION/gcc_64/ $CONFIG, -j $(nproc), macos-latest) (pull_request) Has been cancelled
All Builds / Qtk-Plugins (-DCMAKE_PREFIX_PATH=/home/runner/work/qtk/Qt/$QT_VERSION/gcc_64/ $CONFIG, -j $(nproc), ubuntu-latest) (pull_request) Has been cancelled
All Builds / Qtk-Plugins (-DCMAKE_PREFIX_PATH=D:/a/qtk/qtk/Qt/$QT_VERSION/mingw81_64/ $CONFIG, , windows-latest) (pull_request) Has been cancelled
All Builds / Qtk-Assimp-Targets (-DCMAKE_PREFIX_PATH=/home/runner/work/qtk/Qt/$QT_VERSION/gcc_64/, macos-latest) (pull_request) Has been cancelled
All Builds / Qtk-Assimp-Targets (-DCMAKE_PREFIX_PATH=/home/runner/work/qtk/Qt/$QT_VERSION/gcc_64/, ubuntu-latest) (pull_request) Has been cancelled
Linting / Format (app) (push) Failing after 1m14s
Linting / Tidy (push) Failing after 1m22s
Linting / Format (src) (push) Failing after 39s
2024-03-31 10:22:11 -04:00
7a6cf0e487 Add gitea CI.
Some checks failed
Linting / Tidy (push) Failing after 32s
All Builds / Qtk (-DCMAKE_PREFIX_PATH=/home/runner/work/qtk/Qt/$QT_VERSION/gcc_64/ $CONFIG, -j $(nproc), macos-latest) (pull_request) Has been cancelled
All Builds / Qtk (-DCMAKE_PREFIX_PATH=/home/runner/work/qtk/Qt/$QT_VERSION/gcc_64/ $CONFIG, -j $(nproc), ubuntu-latest) (pull_request) Has been cancelled
All Builds / Qtk (-DCMAKE_PREFIX_PATH=D:/a/qtk/qtk/Qt/$QT_VERSION/mingw81_64/ $CONFIG, , windows-latest) (pull_request) Has been cancelled
All Builds / Qtk-Library (-DCMAKE_PREFIX_PATH=/home/runner/work/qtk/Qt/$QT_VERSION/gcc_64/ $CONFIG, -j $(nproc), macos-latest) (pull_request) Has been cancelled
All Builds / Qtk-Library (-DCMAKE_PREFIX_PATH=/home/runner/work/qtk/Qt/$QT_VERSION/gcc_64/ $CONFIG, -j $(nproc), ubuntu-latest) (pull_request) Has been cancelled
All Builds / Qtk-Library (-DCMAKE_PREFIX_PATH=D:/a/qtk/qtk/Qt/$QT_VERSION/mingw81_64/ $CONFIG, , windows-latest) (pull_request) Has been cancelled
All Builds / Qtk-Plugins (-DCMAKE_PREFIX_PATH=/home/runner/work/qtk/Qt/$QT_VERSION/gcc_64/ $CONFIG, -j $(nproc), macos-latest) (pull_request) Has been cancelled
All Builds / Qtk-Plugins (-DCMAKE_PREFIX_PATH=/home/runner/work/qtk/Qt/$QT_VERSION/gcc_64/ $CONFIG, -j $(nproc), ubuntu-latest) (pull_request) Has been cancelled
All Builds / Qtk-Plugins (-DCMAKE_PREFIX_PATH=D:/a/qtk/qtk/Qt/$QT_VERSION/mingw81_64/ $CONFIG, , windows-latest) (pull_request) Has been cancelled
All Builds / Qtk-Assimp-Targets (-DCMAKE_PREFIX_PATH=/home/runner/work/qtk/Qt/$QT_VERSION/gcc_64/, macos-latest) (pull_request) Has been cancelled
All Builds / Qtk-Assimp-Targets (-DCMAKE_PREFIX_PATH=/home/runner/work/qtk/Qt/$QT_VERSION/gcc_64/, ubuntu-latest) (pull_request) Has been cancelled
Linting / Format (app) (push) Failing after 58s
Linting / Format (src) (push) Failing after 48s
2024-03-31 10:16:46 -04:00
Transporter
d0c8316f79 QtkIOSystem improvements 2024-01-25 00:21:03 -05:00
ad59d9149e Drag and drop model loading (#14) 2023-12-27 19:36:47 +00:00
e889785b65 Improve cmake and GUI (#13)
+ Packaging and CI for Windows, Mac, Linux
+ Debian package, NSIS Windows installer, OSX appbundle
+ Example application using libqtk
+ Component installation for `qtk`, `libqtk`, or `collection` with cmake
2023-03-12 02:02:26 +00:00
41 changed files with 1487 additions and 537 deletions

View File

@@ -0,0 +1,331 @@
name: All Builds
on:
pull_request:
workflow_dispatch:
env:
QT_VERSION: 6.6.0
jobs:
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/$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 Debian packaging dependencies
if: matrix.os == 'ubuntu-latest'
run: |
apt update -y
apt install libxcb-cursor0 python3 -y
- 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 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: |
cd build
cpack -C Release -G DEB
- 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/$QT_VERSION/gcc_64/
- os: macos-latest
cmake: -DCMAKE_PREFIX_PATH=/home/runner/work/qtk/Qt/$QT_VERSION/gcc_64/
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
- name: Install Qt
uses: jurplel/install-qt-action@v2
with:
version: ${{ env.QT_VERSION }}
- name: Install Assimp MacOS
if: matrix.os == 'macos-latest'
shell: bash
run: |
brew install assimp
- name: Install Assimp Ubuntu
if: matrix.os == 'ubuntu-latest'
shell: bash
run: |
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 --build build/ --config Release

View File

@@ -0,0 +1,76 @@
name: Linting
on:
push:
workflow_dispatch:
jobs:
Tidy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install Assimp Ubuntu
run: |
python3 --version
- name: Install Assimp Ubuntu
run: |
apt update -y
apt install libassimp-dev -y
- name: Install Qt
uses: jurplel/install-qt-action@v3
with:
version: '6.5.0'
- name: Build Qtk
run: |
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
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
# Use clang-tools 14
version: '14'
# Don't use clang-format with this action
# + Set to `file` to use .clang-format (Qtk formats with clang 15)
style: ''
# Use .clang-tidy file
tidy-checks: ''
# Check the entire repo for source files to tidy
files-changed-only: false
# Ignore qtk build and external assimp directories
ignore: '.github|build|extern/assimp/assimp'
# Point to compile_commands.json produced by build
database: 'build'
# Use thread comments as feedback
thread-comments: true
# Show file annotations on GH
file-annotations: true
- name: Fail CI if checks don't pass
if: steps.linter.outputs.checks-failed != 0
run: exit 1
Format:
runs-on: ubuntu-latest
strategy:
matrix:
path:
- 'src'
- 'app'
steps:
- uses: actions/checkout@v3
- name: Setup docker
uses: crazy-max/ghaction-setup-docker@v3
- name: clang-format Check
uses: jidicula/clang-format-action@v4.9.0
with:
clang-format-version: '15'
check-path: ${{ matrix.path }}

View File

@@ -5,21 +5,27 @@ on:
pull_request:
workflow_dispatch:
env:
QT_VERSION: 6.6.0
jobs:
Build-Qtk:
Qtk:
env:
CONFIG: -DQTK_UPDATE_SUBMODULES=ON -DQTK_DEBUG=OFF -DQTK_ENABLE_CCACHE=OFF -DQTK_INSTALL_GUI=ON -DQTK_INSTALL_LIB=ON -DQTK_INSTALL_PLUGINS=OFF
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.5.0/gcc_64/ $CONFIG
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.5.0/mingw81_64/ $CONFIG
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.5.0/gcc_64/ $CONFIG
cmake: -DCMAKE_PREFIX_PATH=/home/runner/work/qtk/Qt/$QT_VERSION/gcc_64/ $CONFIG
flags: -j $(nproc)
runs-on: ${{ matrix.os }}
steps:
@@ -28,7 +34,7 @@ jobs:
- name: Install Qt
uses: jurplel/install-qt-action@v2
with:
version: '6.5.0'
version: ${{ env.QT_VERSION }}
# Windows
@@ -38,43 +44,85 @@ jobs:
with:
args: install pkgconfiglite --checksum e87b5ea3c9142256af60f2d5b917aa63b571e6a0 --checksum-type sha1
- name: Configure Qtk Application (Windows)
if: matrix.os == 'windows-latest'
- 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 (Windows)
if: matrix.os == 'windows-latest'
- name: Build Qtk Application
shell: bash
run: cmake --build build/ --config Release
run: cmake --build build/ --config Release --target qtk_gui ${{ matrix.flags }}
# OSX / Linux
- name: Configure Qtk Application (OSX / Linux)
- name: Build Qtk Example
if: matrix.os != 'windows-latest'
shell: bash
run: cmake -B build/ ${{ matrix.cmake }}
- name: Build Qtk Application (OSX / Linux)
if: matrix.os != 'windows-latest'
shell: bash
run: cmake --build build/ --config Release --target qtk_main -- -j $(nproc)
run: cmake --build build/ --config Release --target qtk_example ${{ matrix.flags }}
# Packaging
- name: Install Qtk Application
shell: bash
run: cmake --install build/ --config Release --prefix=$(pwd)/install --component qtk_main
run: cmake --install build/ --config Release --component qtk_gui
- name: Package Qtk Application
shell: bash
run: cmake --build build/ --target package --config Release
# - uses: actions/upload-artifact@v3
# if: always()
# with:
# name: qtk-${{ matrix.os }}-install
# path: install/*
- name: Package Qtk (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: 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
@@ -82,38 +130,32 @@ jobs:
# shell: bash
# run: |
# cmake --build build/ --target package_source
#
# - name: Upload package artifacts
# uses: actions/upload-artifact@v3
# if: always()
# with:
# name: qtk-packages-${{ matrix.os }}
# name: qtk-${{ matrix.os }}-packages
# path: |
# build/packages/
# build/packages/*
# !build/packages/_CPack_Packages/*
- name: Upload logs on failure
uses: actions/upload-artifact@v3
if: ${{ failure() && matrix.os == 'windows-latest' }}
with:
name: qtk-failed-packages-${{ matrix.os }}
path: |
build/_CPack_Packages/win64/NSIS/NSISOutput.log
Build-Qtk-Library:
Qtk-Library:
env:
CONFIG: -DQTK_UPDATE_SUBMODULES=ON -DQTK_DEBUG=OFF -DQTK_ENABLE_CCACHE=OFF -DQTK_INSTALL_GUI=OFF -DQTK_INSTALL_LIB=ON -DQTK_INSTALL_PLUGINS=OFF
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/6.5.0/gcc_64/ $CONFIG
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.5.0/mingw81_64/ $CONFIG
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.5.0/gcc_64/ $CONFIG
cmake: -DCMAKE_PREFIX_PATH=/home/runner/work/qtk/Qt/$QT_VERSION/gcc_64/ $CONFIG
flags: -j $(nproc)
runs-on: ${{ matrix.os }}
steps:
@@ -122,7 +164,7 @@ jobs:
- name: Install Qt
uses: jurplel/install-qt-action@v2
with:
version: '6.5.0'
version: ${{ env.QT_VERSION }}
# Windows
@@ -132,27 +174,13 @@ jobs:
with:
args: install pkgconfiglite --checksum e87b5ea3c9142256af60f2d5b917aa63b571e6a0 --checksum-type sha1
- name: Configure Qtk Library (Windows)
if: matrix.os == 'windows-latest'
- name: Configure Qtk Library
shell: bash
run: cmake -B build/ ${{ matrix.cmake }}
- name: Build Qtk Library (Windows)
if: matrix.os == 'windows-latest'
- name: Build Qtk Library
shell: bash
run: cmake --build build/ --config Release
# OSX / Linux
- name: Configure Qtk Library (OSX / Linux)
if: matrix.os != 'windows-latest'
shell: bash
run: cmake -B build/ ${{ matrix.cmake }}
- name: Build Qtk Library (OSX / Linux)
if: matrix.os != 'windows-latest'
shell: bash
run: cmake --build build/ --config Release --target qtk_library -- -j $(nproc)
run: cmake --build build/ --config Release --target qtk_library -- ${{ matrix.flags }}
# Packaging
@@ -164,43 +192,75 @@ jobs:
shell: bash
run: cmake --build build/ --target package --config Release
# - uses: actions/upload-artifact@v3
# if: always()
# with:
# name: libqtk-${{ matrix.os }}-install
# path: install/*
- name: Package Qtk Library (DEB)
if: matrix.os == 'ubuntu-latest'
shell: bash
run: |
cd build
cpack -C Release -G DEB
# - name: Upload package artifacts
# uses: actions/upload-artifact@v3
# if: always()
# with:
# name: libqtk-packages-${{ matrix.os }}
# path: |
# build/packages/
# !build/packages/_CPack_Packages/*
- name: Upload logs on failure
- name: Upload package artifacts (DEB)
if: matrix.os == 'ubuntu-latest'
uses: actions/upload-artifact@v3
if: ${{ failure() && matrix.os == 'windows-latest' }}
with:
name: libqtk-failed-packages-${{ matrix.os }}
name: libqtk-${{ matrix.os }}
path: |
build/_CPack_Packages/win64/NSIS/NSISOutput.log
build/packages/*.deb
Build-Qtk-Plugins:
- 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_UPDATE_SUBMODULES=ON -DQTK_DEBUG=OFF -DQTK_ENABLE_CCACHE=OFF -DQTK_INSTALL_GUI=OFF -DQTK_INSTALL_LIB=OFF -DQTK_INSTALL_PLUGINS=ON
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/6.5.0/gcc_64/ $CONFIG
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.5.0/mingw81_64/ $CONFIG
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.5.0/gcc_64/ $CONFIG
cmake: -DCMAKE_PREFIX_PATH=/home/runner/work/qtk/Qt/$QT_VERSION/gcc_64/ $CONFIG
flags: -j $(nproc)
runs-on: ${{ matrix.os }}
steps:
@@ -209,9 +269,7 @@ jobs:
- name: Install Qt
uses: jurplel/install-qt-action@v2
with:
version: '6.5.0'
# Windows
version: ${{ env.QT_VERSION }}
- name: Chocolatey Action
if: matrix.os == 'windows-latest'
@@ -219,44 +277,30 @@ jobs:
with:
args: install pkgconfiglite --checksum e87b5ea3c9142256af60f2d5b917aa63b571e6a0 --checksum-type sha1
- name: Configure Qtk Plugins (Windows)
if: matrix.os == 'windows-latest'
- name: Configure Qtk Plugins
shell: bash
run: cmake -B build/ ${{ matrix.cmake }}
- name: Build Qtk Plugins (Windows)
if: matrix.os == 'windows-latest'
- name: Build Qtk Plugins
shell: bash
run: cmake --build build/ --config Release
# OSX / Linux
- name: Configure Qtk Plugins (OSX / Linux)
if: matrix.os != 'windows-latest'
shell: bash
run: cmake -B build/ ${{ matrix.cmake }}
- name: Build Qtk Plugins (OSX / Linux)
if: matrix.os != 'windows-latest'
shell: bash
run: cmake --build build/ --config Release --target qtk_collection -- -j $(nproc)
run: cmake --build build/ --config Release --target qtk_plugins -- ${{ matrix.flags }}
# Packaging
- name: Install Qtk Plugins
shell: bash
run: cmake --install build/ --config Release --prefix=$(pwd)/install --component qtk_collection
run: cmake --install build/ --config Release --component qtk_plugins
Build-Qtk-Assimp-Targets:
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.5.0/gcc_64/
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.5.0/gcc_64/ -DASSIMP_NEW_INTERFACE=ON
cmake: -DCMAKE_PREFIX_PATH=/home/runner/work/qtk/Qt/$QT_VERSION/gcc_64/
runs-on: ${{ matrix.os }}
steps:
@@ -265,7 +309,7 @@ jobs:
- name: Install Qt
uses: jurplel/install-qt-action@v2
with:
version: '6.5.0'
version: ${{ env.QT_VERSION }}
- name: Install Assimp MacOS
if: matrix.os == 'macos-latest'
@@ -279,24 +323,10 @@ jobs:
run: |
sudo apt install libassimp-dev
- name: Build Qtk
if: matrix.os == 'windows-latest'
- name: Configure Qtk
shell: bash
run: |
cmake -B build/ ${{ matrix.cmake }} -DQTK_DEBUG=OFF -DQTK_ENABLE_CCACHE=OFF
cmake --build build/ --config Release
run: cmake -B build/ ${{ matrix.cmake }} -DQTK_CCACHE=OFF -DQTK_ASSIMP_NEW_INTERFACE=ON
- name: Build Qtk
if: matrix.os != 'windows-latest'
shell: bash
run: |
cmake -B build/ ${{ matrix.cmake }} -DQTK_DEBUG=OFF -DQTK_ENABLE_CCACHE=OFF
cmake --build build/ --config Release -- -j $(nproc)
# TODO: Enable with tag only when done testing
# Release-Qtk:
# needs: Build-Qtk
# strategy:
# fail-fast: false
# matrix:
# os: [ubuntu-latest, windows-latest, macos-latest]
run: cmake --build build/ --config Release

View File

@@ -21,8 +21,8 @@ jobs:
- name: Build Qtk
run: |
cmake -B build -DQTK_UPDATE_SUBMODULES=OFF -DQTK_ENABLE_CCACHE=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

3
.gitignore vendored
View File

@@ -1,6 +1,9 @@
# CLion
**/.idea/**
# VS Code
**/.vscode/**
# CMake build files
**/cmake-build-debug/**
**/build/**

View File

@@ -23,6 +23,7 @@ if(WIN32)
set(CMAKE_COMPILE_WARNING_AS_ERROR OFF)
add_compile_options(/wd4131 /wd4127)
endif()
add_compile_options(-fPIC)
################################################################################
# Project
@@ -45,14 +46,13 @@ include(GNUInstallDirs)
# Options
################################################################################
option(QTK_DEBUG "Enable debugger" OFF)
option(QTK_UPDATE_SUBMODULES "Update external project (assimp) submodule" OFF)
option(QTK_INSTALL_GUI "Build the Qtk desktop application" ON)
option(QTK_INSTALL_LIB "Install libqtk to CMAKE_INSTALL_PREFIX path." ON)
option(QTK_INSTALL_PLUGINS "Install Qtk plugin collection to Qt Creator." OFF)
option(QTK_BUILD_EXAMPLE "Build the Qtk example desktop application" ON)
option(QTK_ENABLE_CCACHE "Enable ccache" ON)
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_ENABLE_CCACHE)
if (QTK_CCACHE)
set(CMAKE_CXX_COMPILER_LAUNCHER ccache)
endif()
@@ -60,26 +60,33 @@ endif()
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_UPDATE_SUBMODULES OFF
# + 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(NOT QTK_DEBUG)
set(CMAKE_BUILD_TYPE Release)
else()
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" CACHE PATH "Path to Qt6 install.")
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}")
# TODO: Remove if not using sdlibdeps.
#set(CMAKE_INSTALL_RPATH "${QT_INSTALL_DIR}/lib")
if (QTK_PREFIX_QTCREATOR)
# TODO: This might be a bit strange and needs more testing.
set(CMAKE_INSTALL_PREFIX "${QT_INSTALL_DIR}")
@@ -90,31 +97,13 @@ set(
"${QT_INSTALL_DIR}/../../Tools/QtCreator"
CACHE PATH "Qt Creator path used to install Qtk plugins for Qt Designer."
)
# Qt Designer will look in different locations if WIN / Unix.
# These paths are for using Qt Designer integrated within Qt Creator.
# Standalone Qt Designer may use different paths.
if (WIN32)
# These paths may be different on windows. I have not tested this.
set(QT_PLUGIN_INSTALL_DIR "${QT_CREATOR_DIR}/bin/plugins/designer")
set(QT_PLUGIN_LIBRARY_DIR "${QT_CREATOR_DIR}/lib/Qt/lib")
else()
set(QT_PLUGIN_INSTALL_DIR "${QT_CREATOR_DIR}/lib/Qt/plugins/designer")
set(QT_PLUGIN_LIBRARY_DIR "${QT_CREATOR_DIR}/lib/Qt/lib")
endif()
set(QTK_PLUGIN_LIBRARY_DIR "${QT_PLUGIN_LIBRARY_DIR}")
set(QTK_PLUGIN_INSTALL_DIR "${QT_PLUGIN_INSTALL_DIR}")
message(STATUS "[Qtk] CMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}")
set(QTK_RESOURCES "${CMAKE_SOURCE_DIR}/resources")
set(QTK_OSX_ICONS ${CMAKE_SOURCE_DIR}/resources/icons/osx/kilroy.icns)
# Print all QTK options and their values.
# 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 "^Q[tT][kK]_.*$")
list(FILTER VAR_NAMES INCLUDE REGEX "^[qQ][tT][kK]_.*$")
list(SORT VAR_NAMES)
foreach(VAR_NAME ${VAR_NAMES})
message(STATUS "[Qtk] ${VAR_NAME}=${${VAR_NAME}}")
endforeach()
################################################################################
# External Dependencies
@@ -134,8 +123,33 @@ if(NOT Qt6_FOUND)
)
endif()
#
# 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_UPDATE_SUBMODULES)
if(QTK_SUBMODULES)
# Required to statically link.
add_compile_options(-fPIC)
set(BUILD_SHARED_LIBS OFF CACHE STRING "Build static assimp libs" FORCE)
@@ -167,8 +181,20 @@ endif()
################################################################################
add_subdirectory(src)
if(QTK_BUILD_EXAMPLE)
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)
add_subdirectory(example-app EXCLUDE_FROM_ALL)
endif()
# 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()
endforeach()

211
README.md
View File

@@ -1,4 +1,5 @@
# 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)
@@ -11,72 +12,100 @@ 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.
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.
* 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/)
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.
### Source Builds
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.
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 **Qt 6.5.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.5.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.
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.
If you are building on **Windows / Mac**, consider setting
the `-DQTK_ASSIMP_NEW_INTERFACE` cmake build option.
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 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/
````
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.
```bash
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
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 ccache
git clone https://github.com/shaunrd0/qtk
cmake -S qtk/ -B qtk/build/ -DCMAKE_PREFIX_PATH=$HOME/Qt/6.5.0/gcc_64
cmake --build qtk/build/ -j $(nproc --ignore=2)
./qtk/build/bin/qtk-main
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
```
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_UPDATE_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_UPDATE_SUBMODULES=ON` supports providing assimp on cross-platform builds (Windows / Mac / Linux) and may be easier to configure.
If any errors are encountered loading plugins, we can debug plugin loading by
setting the following environment variable -
```bash
cmake -S qtk/ -B qtk/build/ -DQTK_UPDATE_SUBMODULES=ON -DCMAKE_PREFIX_PATH=$HOME/Qt/6.5.0/gcc_64
cmake --build qtk/build/ -j $(nproc --ignore=2)
./qtk/build/bin/qtk-main
```
If any errors are encountered loading plugins, we can debug plugin loading by setting the following environment variable -
```bash
QT_DEBUG_PLUGINS=1 ./qtk-main
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.
Below is an example of installing on a system path.
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
cmake -S qtk/ -B qtk/build/ -DCMAKE_PREFIX_PATH=$HOME/Qt/6.5.0/gcc_64 -DQTK_INSTALL_GUI=OFF -DQTK_INSTALL_PLUGINS=OFF -DQTK_DEBUG=OFF
cmake --build qtk/build/ -j $(nproc --ignore=2)
sudo cmake --install . --prefix=/usr/local
# 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
@@ -103,32 +132,51 @@ sudo cmake --install . --prefix=/usr/local
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.
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 -S /path/to/qtk -B /path/to/qtk/build -DCMAKE_PREFIX_PATH=$HOME/Qt/6.5.0/gcc_64 -DQTK_INSTALL_PLUGINS=ON -DQTK_INSTALL_GUI=OFF -DQTK_INSTALL_LIB=OFF
cmake --build /path/to/qtk/build
cmake --install /path/to/qtk/build
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.
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
#### Windows / MacOS
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.
If you are building on **Windows / Mac**, consider setting the `-DASSIMP_NEW_INTERFACE` build flag.
```bash
cmake -S qtk/ -B qtk/build/ -DASSIMP_NEW_INTERFACE=ON -DCMAKE_PREFIX_PATH=$HOME/Qt/6.5.0/gcc_64;/path/to/assimp/
cmake --build qtk/build/ -j $(nproc --ignore=2)
# 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.
@@ -166,7 +214,9 @@ cmake --build build -j $(nproc --ignore=2)
sudo cmake --build build -j $(nproc --ignore=2) --target install
```
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`.
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
@@ -174,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.
@@ -182,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
```
@@ -190,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).
@@ -214,8 +265,10 @@ changed files:
##### Packaging
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.
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.
Below are the steps to package a Qtk release.
@@ -228,6 +281,7 @@ cmake --build build --target package_source
```
Alternatively, we can use `cpack` directly -
```bash
cd /path/to/qtk && cmake -B build
# Generate all install packages
@@ -242,13 +296,15 @@ cpack -C Release -G DEB
cpack -C Release -G NSIS
```
Any of the above options can be appended with `--trace-expand` to debug package generation issues.
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.
If we are generating packages for *only* libqtk, we set `-DQTK_INSTALL_LIB=ON` during the cmake configuration step.
To generate packages for Qtk desktop application, we should set `-DQTK_INSTALL_GUI=ON`, and optionally `-DQTK_INSTALL_LIB=ON` if we would like to bundle libqtk with the desktop application.
To generate packages for Qtk desktop application, we should
set `-DQTK_GUI=ON`. If this option is not set we will only package libqtk.
The NSIS installer will allow component-specific path modification for all of these installation components through a GUI install application.
The NSIS installer will allow component-specific path modification for all of
these installation components through a GUI install application.
##### Resources
@@ -258,19 +314,34 @@ Some useful links and resources that I have found while working on this project.
[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/).

View File

@@ -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()

View File

@@ -2,8 +2,12 @@
include("${CMAKE_CURRENT_LIST_DIR}/QtkTargets.cmake")
set_and_check(QTK_EXECUTABLE "${PACKAGE_PREFIX_DIR}/bin/qtk_app")
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)

View File

@@ -22,7 +22,11 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
endif()
# If you did not install Qtk on a system path, point cmake to installation.
set(QTK_PATH /usr/local CACHE PATH "Path to installation of Qtk")
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")
@@ -40,12 +44,6 @@ project(
list(APPEND CMAKE_PREFIX_PATH "${QTK_PATH}")
list(APPEND CMAKE_PREFIX_PATH "${QT_INSTALL_DIR}")
# 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()
# Print all QTK variables
if (NOT Qtk_IS_TOP_LEVEL)
get_cmake_property(VAR_NAMES VARIABLES)
@@ -56,6 +54,12 @@ if (NOT Qtk_IS_TOP_LEVEL)
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(
@@ -65,6 +69,28 @@ set(
examplewidget.cpp examplewidget.h
)
add_executable(example_app ${EXAMPLE_SOURCES})
target_link_libraries(example_app PUBLIC Qt6::Widgets Qt6::OpenGLWidgets Qt6::Core)
target_link_libraries(example_app PUBLIC Qtk::qtk_library)
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)

View File

@@ -1,6 +1,5 @@
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
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.
@@ -11,7 +10,8 @@ You can import your own models within `examplescene.cpp`, inside the
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.
This would result in a scene with a red cube and a miniature spartan model
placed on top.
```C++
void ExampleScene::init() {
@@ -44,7 +44,6 @@ void ExampleScene::update() {
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.
@@ -58,14 +57,17 @@ 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.
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
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/bin/example
./path/to/qtk/example-app/build/install/bin/example
```

View File

@@ -7,6 +7,7 @@
##############################################################################*/
#include "examplescene.h"
#include <resources.h>
using namespace Qtk;
@@ -22,9 +23,11 @@ void ExampleScene::init() {
auto skybox = new Qtk::Skybox("Skybox");
setSkybox(skybox);
auto spartan = new Model(
"spartan", "/home/kapper/Code/qtk/resources/models/spartan/spartan.obj");
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)));

View File

@@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 MiB

View File

@@ -1,5 +1,6 @@
<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>

View File

@@ -6,68 +6,88 @@
################################################################################
# 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_INSTALL_GUI OR QTK_INSTALL_PLUGINS)
if(QTK_GUI OR QTK_PLUGINS)
add_subdirectory(app)
endif()
# Install custom Qtk plugins for Qt Designer.
if(QTK_INSTALL_PLUGINS)
install(
TARGETS qtk_library qtk_plugin_library
COMPONENT qtk_collection
LIBRARY DESTINATION "${QTK_PLUGIN_LIBRARY_DIR}"
ARCHIVE DESTINATION "${QTK_PLUGIN_LIBRARY_DIR}"
RUNTIME DESTINATION "${QTK_PLUGIN_LIBRARY_DIR}"
)
install(
TARGETS qtk_collection
COMPONENT qtk_collection
LIBRARY DESTINATION "${QTK_PLUGIN_INSTALL_DIR}"
ARCHIVE DESTINATION "${QTK_PLUGIN_INSTALL_DIR}"
RUNTIME DESTINATION "${QTK_PLUGIN_INSTALL_DIR}"
)
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_INSTALL_GUI)
install(
TARGETS qtk_app qtk_library
COMPONENT qtk
BUNDLE DESTINATION .
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib/static
RUNTIME DESTINATION bin
)
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_app
OUTPUT_SCRIPT QTK_DEPLOY_SCRIPT
NO_UNSUPPORTED_PLATFORM_ERROR
)
install(SCRIPT ${QTK_DEPLOY_SCRIPT} COMPONENT qtk)
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)
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_app.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()
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()
@@ -82,35 +102,6 @@ configure_package_config_file(
INSTALL_DESTINATION lib/cmake/${PROJECT_NAME}
)
if (QTK_INSTALL_LIB)
install(
FILES
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
COMPONENT libqtk
DESTINATION lib/cmake/${PROJECT_NAME}
)
install(
EXPORT qtk_export
FILE ${PROJECT_NAME}Targets.cmake
NAMESPACE ${PROJECT_NAME}::
COMPONENT libqtk
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 libqtk
FILE_SET HEADERS DESTINATION include
INCLUDES DESTINATION include
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib/static
RUNTIME DESTINATION bin
)
endif()
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}")
@@ -125,7 +116,7 @@ set(CPACK_THREADS 0)
set(CPACK_PACKAGE_INSTALL_DIRECTORY "Qtk")
# Remove any assimp components if defined by submodule.
if (QTK_UPDATE_SUBMODULES)
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)
@@ -137,7 +128,7 @@ 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_app.exe'"
"CreateShortCut '$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Qtk.lnk' '$INSTDIR\\\\bin\\\\qtk_gui.exe'"
)
set(
CPACK_NSIS_DELETE_ICONS_EXTRA
@@ -148,14 +139,12 @@ set(
#set(CPACK_NSIS_MUI_UNIICON "${CMAKE_SOURCE_DIR}/resources/icon.png")
# Debian
# TODO: Fix output sharedlib path.
set(CPACK_DEBIAN_PACKAGE_HOMEPAGE ${CPACK_PACKAGE_HOMEPAGE_URL})
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
#set(CPACK_PACKAGING_INSTALL_PREFIX /usr/local/)
# OSX
set(CPACK_BUNDLE_NAME ${PROJECT_NAME})
set(CPACK_BUNDLE_PLIST $<TARGET_BUNDLE_CONTENT_DIR:qtk_app>/Info.plist)
set(CPACK_BUNDLE_PLIST $<TARGET_BUNDLE_CONTENT_DIR:qtk_gui>/Info.plist)
set(CPACK_BUNDLE_ICON ${QTK_OSX_ICONS})
# Platform defaults for source bundles.

View File

@@ -33,39 +33,32 @@ target_sources(
target_link_libraries(qtk_plugin_library PUBLIC Qt6::UiPlugin qtk_library)
################################################################################
# Qtk Widget Collection Plugin
# Qtk Widget Plugins
################################################################################
# Create a Qt Designer plugin for a collection of widgets from our library.
qt_add_plugin(qtk_collection SHARED EXCLUDE_FROM_ALL)
qt_add_plugin(qtk_plugins SHARED)
target_sources(
qtk_collection PRIVATE
qtk_plugins PRIVATE
widgetplugincollection.cpp widgetplugincollection.h
widgetplugin.cpp widgetplugin.h
)
target_link_libraries(qtk_collection PUBLIC qtk_plugin_library)
target_link_libraries(qtk_plugins PUBLIC qtk_plugin_library)
################################################################################
# Final Qtk Application
################################################################################
set(
QTK_APP_SOURCES
QTK_GUI_SOURCES
qtkscene.cpp qtkscene.h
main.cpp
)
qt6_add_big_resources(QTK_APP_SOURCES "${QTK_RESOURCES}/resources.qrc")
configure_file(
resources.h.in
"${CMAKE_CURRENT_BINARY_DIR}/resources.h"
@ONLY
)
qt_add_executable(qtk_app ${QTK_APP_SOURCES})
target_link_libraries(qtk_app PRIVATE qtk_plugin_library)
qt_add_executable(qtk_gui ${QTK_GUI_SOURCES})
target_link_libraries(qtk_gui PRIVATE qtk_plugin_library)
set_target_properties(
qtk_app PROPERTIES
qtk_gui PROPERTIES
WIN32_EXECUTABLE TRUE
MACOSX_BUNDLE TRUE
MACOSX_BUNDLE_BUNDLE_NAME Qtk

View File

@@ -29,17 +29,30 @@ MainWindow::MainWindow(QWidget * parent) : QMainWindow(parent) {
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);
}
auto docks = findChildren<QDockWidget *>();
for(auto & dock : docks) {
addDockWidget(Qt::RightDockWidgetArea, dock);
ui_->menuView->addAction(dock->toggleViewAction());
}
// 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());
@@ -74,7 +87,7 @@ Qtk::QtkWidget * MainWindow::getQtkWidget(const QString & name) {
return views_[name];
}
void MainWindow::refreshScene(QString sceneName) {
// TODO: Select TreeView using sceneName>
void MainWindow::refreshScene(const QString & sceneName) {
// TODO: Select TreeView using sceneName
ui_->qtk__TreeView->updateView(getQtkWidget()->getScene());
}

View File

@@ -69,7 +69,7 @@ class MainWindow : public QMainWindow {
* 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(QString sceneName);
void refreshScene(const QString & sceneName);
private:
/***************************************************************************

View File

@@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>824</width>
<width>1034</width>
<height>601</height>
</rect>
</property>
@@ -28,11 +28,27 @@
</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>0</horstretch>
<horstretch>3</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
@@ -50,10 +66,10 @@
<item>
<widget class="Qtk::QtkWidget" name="qtk::QtkWidget">
<property name="toolTip">
<string>A custom widget tool tip.</string>
<string/>
</property>
<property name="whatsThis">
<string>Custom widget what's this?</string>
<string>Qtk scene view rendered using OpenGL.</string>
</property>
</widget>
</item>
@@ -67,28 +83,20 @@
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="Qtk::TreeView" name="qtk::TreeView">
<property name="toolTip">
<string>A custom widget tool tip.</string>
</property>
<property name="whatsThis">
<string>Custom widget what's this?</string>
</property>
</widget>
</item>
<item>
<widget class="Qtk::ToolBox" name="qtk::ToolBox">
<property name="toolTip">
<string>A custom widget tool tip.</string>
</property>
<property name="whatsThis">
<string>Custom widget what's this?</string>
</property>
</widget>
</item>
</layout>
<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>
@@ -97,7 +105,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>824</width>
<width>1034</width>
<height>22</height>
</rect>
</property>
@@ -179,7 +187,7 @@
</widget>
<action name="actionOpen">
<property name="icon">
<iconset resource="../../resources/resources.qrc">
<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">
@@ -188,7 +196,7 @@
</action>
<action name="actionSave">
<property name="icon">
<iconset resource="../../resources/resources.qrc">
<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">
@@ -215,7 +223,7 @@
</action>
<action name="actionLoad_Model">
<property name="icon">
<iconset resource="../../resources/resources.qrc">
<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">
@@ -227,7 +235,7 @@
</action>
<action name="actionDelete_Object">
<property name="icon">
<iconset resource="../../resources/resources.qrc">
<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">
@@ -318,9 +326,7 @@
<container>1</container>
</customwidget>
</customwidgets>
<resources>
<include location="../../resources/resources.qrc"/>
</resources>
<resources/>
<connections>
<connection>
<sender>actionExit</sender>

View File

@@ -7,7 +7,6 @@
##############################################################################*/
#include "qtkscene.h"
#include "resources.h"
using namespace Qtk;
@@ -15,8 +14,7 @@ using namespace Qtk;
* Constructors, Destructors
******************************************************************************/
QtkScene::QtkScene(Qtk::Scene * scene) :
Qtk::SceneInterface(scene) {
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);
@@ -40,11 +38,12 @@ void QtkScene::init() {
/* 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);
myCube->getTransform().setTranslation(5.0f, 0.0f, 0.0f);
addObject(myCube);
auto mySpartan =
new Model("My spartan", ":/models/models/spartan/spartan.obj");
mySpartan->getTransform().setTranslation(0.0f, 0.5f, 0.0f);
mySpartan->getTransform().setTranslation(5.0f, 0.5f, 0.0f);
mySpartan->getTransform().setScale(0.5f);
addObject(mySpartan);
@@ -97,8 +96,8 @@ void QtkScene::init() {
model->getTransform().setTranslation(2.0f, -1.0f, -5.0f);
model->getTransform().scale(0.15f);
model =
addObject(new Qtk::Model("My scythe", ":/models/models/scythe/scythe.obj"));
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);
@@ -401,15 +400,13 @@ void QtkScene::draw() {
"uLightPosition",
MeshRenderer::getInstance("phongLight")->getTransform().getTranslation());
mTestPhong->setUniform(
"uCameraPosition",
QtkScene::getCamera().getTransform().getTranslation());
"uCameraPosition", QtkScene::getCamera().getTransform().getTranslation());
mTestPhong->releaseShaders();
mTestPhong->draw();
mTestAmbient->bindShaders();
mTestAmbient->setUniform(
"uCameraPosition",
QtkScene::getCamera().getTransform().getTranslation());
"uCameraPosition", QtkScene::getCamera().getTransform().getTranslation());
mTestAmbient->releaseShaders();
mTestAmbient->draw();
@@ -422,8 +419,7 @@ void QtkScene::draw() {
->getTransform()
.getTranslation());
mTestDiffuse->setUniform(
"uCameraPosition",
QtkScene::getCamera().getTransform().getTranslation());
"uCameraPosition", QtkScene::getCamera().getTransform().getTranslation());
mTestDiffuse->releaseShaders();
mTestDiffuse->draw();
@@ -436,8 +432,7 @@ void QtkScene::draw() {
->getTransform()
.getTranslation());
mTestSpecular->setUniform(
"uCameraPosition",
QtkScene::getCamera().getTransform().getTranslation());
"uCameraPosition", QtkScene::getCamera().getTransform().getTranslation());
mTestSpecular->releaseShaders();
mTestSpecular->draw();
}
@@ -455,8 +450,7 @@ void QtkScene::update() {
auto alien = Model::getInstance("alienTest");
alien->setUniform("uLight.position", position);
alien->setUniform(
"uCameraPosition",
QtkScene::getCamera().getTransform().getTranslation());
"uCameraPosition", QtkScene::getCamera().getTransform().getTranslation());
auto posMatrix = alien->getTransform().toMatrix();
alien->setUniform("uMVP.normalMatrix", posMatrix.normalMatrix());
alien->setUniform("uMVP.model", posMatrix);
@@ -470,8 +464,7 @@ void QtkScene::update() {
auto spartan = Model::getInstance("spartanTest");
spartan->setUniform("uLight.position", position);
spartan->setUniform(
"uCameraPosition",
QtkScene::getCamera().getTransform().getTranslation());
"uCameraPosition", QtkScene::getCamera().getTransform().getTranslation());
posMatrix = spartan->getTransform().toMatrix();
spartan->setUniform("uMVP.normalMatrix", posMatrix.normalMatrix());
spartan->setUniform("uMVP.model", posMatrix);
@@ -486,8 +479,7 @@ void QtkScene::update() {
MeshRenderer::getInstance("testLight")->getTransform().getTranslation();
phong->setUniform("uLight.position", position);
phong->setUniform(
"uCameraPosition",
QtkScene::getCamera().getTransform().getTranslation());
"uCameraPosition", QtkScene::getCamera().getTransform().getTranslation());
posMatrix = phong->getTransform().toMatrix();
phong->setUniform("uMVP.normalMatrix", posMatrix.normalMatrix());
phong->setUniform("uMVP.model", posMatrix);

View File

@@ -7,6 +7,12 @@
##############################################################################*/
#include <QKeyEvent>
#include <QMimeData>
#include <QVBoxLayout>
#include <qtk/input.h>
#include <qtk/scene.h>
#include <qtk/shape.h>
#include <QVBoxLayout>
#include <qtk/input.h>
@@ -31,6 +37,7 @@ QtkWidget::QtkWidget(QWidget * parent, const QString & name) :
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;
@@ -70,6 +77,7 @@ void QtkWidget::initializeGL() {
// Connect the frameSwapped signal to call the update() function
connect(this, SIGNAL(frameSwapped()), this, SLOT(update()));
toggleConsole();
// Initialize OpenGL debug context
mDebugLogger = new QOpenGLDebugLogger(this);
if(mDebugLogger->initialize()) {
@@ -107,11 +115,11 @@ void QtkWidget::paintGL() {
}
}
void QtkWidget::setScene(Qtk::Scene * scene) {
if (mScene != Q_NULLPTR) {
void QtkWidget::setScene(Scene * scene) {
if(mScene != Q_NULLPTR) {
delete mScene;
connect(
scene, &Qtk::Scene::sceneUpdated, MainWindow::getMainWindow(),
scene, &Scene::sceneUpdated, MainWindow::getMainWindow(),
&MainWindow::refreshScene);
}
@@ -129,8 +137,7 @@ void QtkWidget::toggleConsole() {
mConsoleActive = false;
} else {
MainWindow::getMainWindow()->addDockWidget(
Qt::DockWidgetArea::BottomDockWidgetArea,
dynamic_cast<QDockWidget *>(mConsole));
Qt::DockWidgetArea::BottomDockWidgetArea, mConsole);
mConsole->setHidden(false);
mConsoleActive = true;
}
@@ -140,6 +147,34 @@ void QtkWidget::toggleConsole() {
* 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
@@ -253,7 +288,8 @@ void QtkWidget::teardownGL() { /* Nothing to teardown yet... */
void QtkWidget::updateCameraInput() {
Input::update();
// Camera Transformation
if(Input::buttonPressed(Qt::RightButton)) {
if(Input::buttonPressed(Qt::LeftButton)
|| Input::buttonPressed(Qt::RightButton)) {
static const float transSpeed = 0.1f;
static const float rotSpeed = 0.5f;

View File

@@ -131,11 +131,19 @@ namespace Qtk {
*/
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.
*/
@@ -166,6 +174,7 @@ namespace Qtk {
/**
* 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.
*/

View File

@@ -8,13 +8,142 @@
*/
#include "toolbox.h"
#include "qtkmainwindow.h"
#include "ui_toolbox.h"
Qtk::ToolBox::ToolBox(QWidget * parent) :
QDockWidget(parent), ui(new Ui::ToolBox) {
#include <QFormLayout>
#include <QLabel>
using namespace Qtk;
ToolBox::ToolBox(QWidget * parent) : QDockWidget(parent), ui(new Ui::ToolBox) {
ui->setupUi(this);
setMinimumWidth(350);
}
Qtk::ToolBox::~ToolBox() {
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);
}

View File

@@ -12,6 +12,11 @@
#include <QDesignerExportWidget>
#include <QDockWidget>
#include <QDoubleSpinBox>
#include <QGroupBox>
#include "qtk/scene.h"
namespace Ui {
class ToolBox;
@@ -30,6 +35,15 @@ namespace Qtk {
~ToolBox();
void removePages();
void createPageProperties(const Object * object);
void createPageShader(const Object * object);
void updateFocus(const QString & name);
private:
/*************************************************************************
* Private Members

View File

@@ -10,17 +10,57 @@
<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">
<layout class="QHBoxLayout" name="horizontalLayout">
<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">
<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>
@@ -33,19 +73,6 @@
<string>Shaders</string>
</attribute>
</widget>
<widget class="QWidget" name="page_2">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>382</width>
<height>201</height>
</rect>
</property>
<attribute name="label">
<string>Properties</string>
</attribute>
</widget>
</widget>
</item>
</layout>

View File

@@ -37,27 +37,36 @@ void Qtk::TreeView::updateView(const Qtk::Scene * scene) {
mSceneName = scene->getSceneName();
auto objects = scene->getObjects();
for(const auto & object : objects) {
auto item = new QTreeWidgetItem(QStringList(QString(object->getName().c_str())));
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 scene = MainWindow::getMainWindow()->getQtkWidget()->getScene();
auto & transform = scene->getCamera().getTransform();
auto object = scene->getObject(name);
if (object == Q_NULLPTR) {
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";
}
Transform3D * objectTransform;
if(object->getType() == Object::QTK_MESH) {
} 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();
}
transform.setTranslation(objectTransform->getTranslation());
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);
}

View File

@@ -68,15 +68,12 @@ target_link_libraries(
Qt6::Core Qt6::OpenGLWidgets Qt6::Widgets
)
if(QTK_UPDATE_SUBMODULES OR NOT ASSIMP_NEW_INTERFACE)
if(QTK_SUBMODULES OR NOT QTK_ASSIMP_NEW_INTERFACE)
target_link_libraries(qtk_library PUBLIC assimp)
elseif(ASSIMP_NEW_INTERFACE)
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()
#install(SCRIPT ${LIBQTK_DEPLOY_SCRIPT} COMPONENT libqtk)
## Install qtk_library to Qt Designer to support widget plugins.

View File

@@ -211,6 +211,14 @@ namespace Qtk {
*/
inline Transform3D & getTransform() { return mTransform; }
inline std::string getVertexShader() const override {
return mVertexShader;
}
inline std::string getFragmentShader() const override {
return mFragmentShader;
}
private:
/*************************************************************************
* Private Members

View File

@@ -43,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;
}
}
@@ -200,7 +200,9 @@ ModelMesh Model::processMesh(aiMesh * mesh, const aiScene * scene) {
textures.insert(textures.end(), normalMaps.begin(), normalMaps.end());
}
return {vertices, indices, textures, mVertexShader.c_str(), mFragmentShader.c_str()};
return {
vertices, indices, textures, mVertexShader.c_str(),
mFragmentShader.c_str()};
}
ModelMesh::Textures Model::loadMaterialTextures(
@@ -236,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());
}
}

View File

@@ -18,6 +18,9 @@
#include <assimp/Importer.hpp>
// Qtk
#include <QFileInfo>
#include "modelmesh.h"
#include "qtkapi.h"
@@ -124,6 +127,14 @@ namespace Qtk {
*/
inline Transform3D & getTransform() { return mTransform; }
inline std::string getVertexShader() const override {
return mVertexShader;
}
inline std::string getFragmentShader() const override {
return mFragmentShader;
}
private:
/*************************************************************************
* Private Methods

View File

@@ -52,6 +52,10 @@ void ModelMesh::draw(QOpenGLShaderProgram & shader) {
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());
@@ -62,7 +66,6 @@ void ModelMesh::draw(QOpenGLShaderProgram & shader) {
}
shader.release();
mVAO->release();
glActiveTexture(GL_TEXTURE0);
}
/*******************************************************************************

View File

@@ -30,6 +30,21 @@ namespace Qtk {
* 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 {};

View File

@@ -96,10 +96,24 @@ namespace Qtk {
[[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;
}
@@ -135,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
************************************************************************/

View File

@@ -17,17 +17,23 @@ using namespace Qtk;
QtkIOStream::QtkIOStream(const char * pFile, const char * pMode) :
mFile(pFile) {
QString mode(pMode);
bool read = mode.contains('r');
bool write = mode.contains('w');
if(read && write) {
mFile.open(QIODevice::ReadWrite);
} else if(read) {
mFile.open(QIODevice::ReadOnly);
} else if(write) {
mFile.open(QIODevice::WriteOnly);
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";
}
}
/*******************************************************************************
@@ -35,34 +41,24 @@ QtkIOStream::QtkIOStream(const char * pFile, const char * pMode) :
******************************************************************************/
size_t QtkIOStream::Read(void * pvBuffer, size_t pSize, size_t pCount) {
size_t read = 0;
do {
auto readSize = mFile.read((char *)pvBuffer + read, pSize);
if(readSize < 0) {
qDebug() << "[Qtk::QtkIOStream] Failed to read (" << pSize
<< ") bytes from file at: " << mFile.filesystemFileName().c_str()
<< "\n";
return -1;
}
read += readSize;
} while(pCount--);
return read;
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) {
size_t wrote = 0;
do {
auto writeSize = mFile.write((char *)pvBuffer + wrote, pSize);
if(writeSize < 0) {
qDebug() << "[Qtk::QtkIOStream] Failed to write buffer with size ("
<< pSize
<< ") to file at: " << mFile.filesystemFileName().c_str()
<< "\n";
return -1;
}
wrote += writeSize;
} while(pCount--);
return wrote;
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) {

View File

@@ -7,6 +7,7 @@
##############################################################################*/
#include "qtkiosystem.h"
#include <QDir>
using namespace Qtk;
@@ -19,15 +20,11 @@ bool QtkIOSystem::Exists(const char * pFile) const {
}
char QtkIOSystem::getOsSeparator() const {
#ifndef _WIN32
return '/';
#else
return '\\';
#endif
return QDir::separator().toLatin1();
}
Assimp::IOStream * QtkIOSystem::Open(const char * pFile, const char * pMode) {
if(!QFileInfo::exists(pFile)) {
if(!Exists(pFile)) {
qDebug() << "[Qtk::QtkIOSystem] failed to open file: " << pFile << "\n";
return nullptr;
}

View File

@@ -37,16 +37,42 @@ Scene::~Scene() {
* 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(auto & model : mModels) {
for(const auto & model : mModels) {
model->draw();
}
for(const auto & mesh : mMeshes) {
@@ -57,8 +83,8 @@ void Scene::draw() {
std::vector<Object *> Scene::getObjects() const {
// All scene objects must inherit from Qtk::Object.
std::vector<Object *> objects(mMeshes.begin(), mMeshes.end());
for(auto model : mModels) {
objects.push_back(dynamic_cast<Object *>(model));
for(const auto & model : mModels) {
objects.push_back(model);
if(objects.back() == nullptr) {
return {};
}
@@ -66,8 +92,8 @@ std::vector<Object *> Scene::getObjects() const {
return objects;
}
Object * Scene::getObject(const QString & name) {
for(auto object : getObjects()) {
Object * Scene::getObject(const QString & name) const {
for(const auto & object : getObjects()) {
if(object->getName() == name.toStdString()) {
return object;
}
@@ -80,14 +106,14 @@ void Scene::setSkybox(Skybox * skybox) {
mSkybox = skybox;
}
template <> MeshRenderer * Scene::addObject(MeshRenderer * object) {
mMeshes.push_back(object);
sceneUpdated(mSceneName);
return object;
}
template <> Model * Scene::addObject(Model * object) {
mModels.push_back(object);
sceneUpdated(mSceneName);
return object;
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) + ")");
}
}

View File

@@ -10,7 +10,10 @@
#define QTK_SCENE_H
#include <QMatrix4x4>
#include <QUrl>
#include <queue>
#include <unordered_map>
#include <utility>
#include "camera3d.h"
@@ -75,6 +78,18 @@ namespace Qtk {
*/
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
************************************************************************/
@@ -91,7 +106,16 @@ namespace Qtk {
* @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);
[[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.
@@ -166,7 +190,8 @@ namespace Qtk {
*/
inline void setSceneName(QString name) { mSceneName = std::move(name); }
std::vector<Model *> mModels {};
inline void setPause(bool pause) { mPause = pause; }
signals:
/**
* Signal thrown when the scene is modified by adding or removing objects.
@@ -176,7 +201,26 @@ namespace Qtk {
*/
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
************************************************************************/
@@ -184,20 +228,21 @@ namespace Qtk {
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 {};
/* Models used for storing 3D models in the scene. */
/* 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 init() override { setSceneName("Empty Scene"); }
void draw() override { Scene::draw(); }

View File

@@ -9,19 +9,18 @@
#include <QDebug>
#include <QImageReader>
#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() << "[Qtk::OpenGLTextureFactory] Error loading image: " << image
<< "\nSupported types: " << QImageReader::supportedImageFormats();
return Q_NULLPTR;
QImageReader::setAllocationLimit(1024);
auto loadedImage = QImage(image).mirrored(flipX, flipY);
if(loadedImage.isNull()) {
return defaultTexture();
}
return loadedImage;
@@ -29,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;
}
@@ -71,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);

View File

@@ -74,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);
/**
@@ -132,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;