MORPH INTO: Gear Cutter

This commit is contained in:
numzero 2026-10-17 21:27:16 +03:00
parent 068e2fb2e4
commit 42b37369f5
22 changed files with 50 additions and 223 deletions

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 4.2)
project(PROJECT-NAME VERSION 1.0.0 LANGUAGES CXX)
project(gear-cutter VERSION 1.0.0 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

44
Cargo.lock generated
View File

@ -2,28 +2,6 @@
# It is not intended for manual editing.
version = 4
[[package]]
name = "PROJECT-NAME"
version = "0.1.0"
dependencies = [
"bytemuck",
"glam",
"pollster",
"wgpu",
"winit",
]
[[package]]
name = "PROJECT-NAME-impl"
version = "0.1.0"
dependencies = [
"PROJECT-NAME",
"glam",
"pollster",
"raw-window-handle",
"wgpu",
]
[[package]]
name = "ab_glyph"
version = "0.2.32"
@ -489,6 +467,28 @@ dependencies = [
"slab",
]
[[package]]
name = "gear-cutter"
version = "0.1.0"
dependencies = [
"bytemuck",
"glam",
"pollster",
"wgpu",
"winit",
]
[[package]]
name = "gear-cutter-impl"
version = "0.1.0"
dependencies = [
"gear-cutter",
"glam",
"pollster",
"raw-window-handle",
"wgpu",
]
[[package]]
name = "gethostname"
version = "1.1.0"

View File

@ -2,7 +2,7 @@
members = ["ui"]
[package]
name = "PROJECT-NAME"
name = "gear-cutter"
version = "0.1.0"
edition = "2024"

View File

@ -1,24 +1 @@
# Qt6+WGPU skeleton program
This example combines Qt6 GUI (C++) with WGPU rendering (Rust). It doesn’t do much of either but it’s the bridging what’s relevant.
Currently only X11 (XCB) is supported but it should be easy to extend to other platforms.
![Screenshot](screenshot.png)
## Usage
This program is intended as a starting point rather than a dependency, so just copy it.
1. Fetch this code:
* clone the repo: `git clone https://gitea.noteuclid.ru/noteuclid/qt-wgpu-skel.git`
* or, download and unpack the [tarball](https://gitea.noteuclid.ru/noteuclid/qt-wgpu-skel/archive/master.tar.gz).
2. Rename the directory to your liking
3. Run `init.sh` with the project name, like:
* `./init.sh 'My FANCY Project'`, or
* `./init.sh 'My FANCY Project' 'fancy-project'`.
Running `init.sh` without arguments prints the help.
If you want to use Qt5, change the version in both `CMakeLists.txt`, as well as the KF version.
If you don’t want to depend on KDE, remove the ECM and KF5 dependencies, as well as `KColorCombo inBackground` from the UI. You’ll need to replace `inBackground->color()` with something else though.
# Gear Cutter

83
init.sh
View File

@ -1,83 +0,0 @@
#!/bin/sh
# set -x # debug
set -e # abort on errors
cd "${0%/*}" # where this script is located
usage() {
{
echo "Usage:"
echo
echo " ./init.sh 'Project Name' [ internal-name ]"
echo
echo "Project name may be anything you like, in any language, with spaces (but not other control characters), etc."
echo
echo "Technical name must be ASCII alphanumeric (a-z, 0-9, also _ and - are allowed), preferably all-lowercase. If omitted, it will be generated from the project name (but that only works if the latter is ASCII too)."
echo
echo "Running this script with no arguments shows this message"
} | fold -s 2>&1
}
name="$1"
[ -n "$name" ] || { usage; exit 0; } 2>&1
echo -n "$name" | LC_ALL=C grep '[[:cntrl:]]' && { echo 'Project name must not contain any control characters'; exit 2; } 2>&1
name="$(echo -n $name)" # normalize whitespace
techname="$2"
if [ -z "$techname" ]; then
techname=$(
echo -n $name |
LC_ALL=C tr ' ' '-' |
LC_ALL=C tr -d -c '[:alnum:]-_' |
LC_ALL=C tr '[:upper:]' '[:lower:]' |
cat
)
echo "Technical name not specified; autogenerated: \"$techname\"" >&2
fi
echo -n $techname | LC_ALL=C grep '[^0-9A-Za-z_-]' && { echo 'Technical name must be ASCII alphanumeric'; exit 2; } 2>&1
echo -n $techname | LC_ALL=C grep -q '^[A-Za-z]' || { echo 'Technical name must start with an ASCII letter'; exit 2; } 2>&1
echo -n $techname | LC_ALL=C grep -q '[A-Za-z0-9]$' || { echo 'Technical name must end with an ASCII letter or digit'; exit 2; } 2>&1
echo "Project name: $name"
echo "Internal name: $techname"
if ! [ -e .git ]; then
alias git='echo skipping:'
fi
# detach from the skeleton repository
# oldurl="$(git remote -v get-url origin)"
git remote remove origin
# remove this script from the project (but keep on disk for now)
git rm --cached init.sh
git rm -r skel-test
# replace the README with a stub
echo "# $name" >| README.md
git rm screenshot.png
# escape HTML special characters (&, <, and >), but also sed special characters (& again, \, and /)
htmlname=$(echo -n "$name" | sed 's/&/\&amp;/g; s/</\&lt;/g; s/>/\&gt;/g; s:[\\/&]:\\&:g')
sed -i "s/PROJECT NAME/$htmlname/" ui/src/main_window.ui
# escape Rust special characters (" and \; don't worry of the others as they are unlikely enough and easy to fix manually), and also sed special characters (&, \, and /)
quotname=$(echo -n "$name" | sed 's/"/\\"/g; s:[\\/&]:\\&:g')
sed -i "s/PROJECT NAME/$quotname/" src/main.rs
# $techname is alphanumeric, nothing to escape
grep -l -r PROJECT-NAME | xargs sed -i "s/PROJECT-NAME/$techname/g"
# replace - with _ to form a valid snake_case identifier
ident=$(echo -n $techname | LC_ALL=C tr '-' '_')
grep -l -r PROJECT_NAME | xargs sed -i "s/PROJECT_NAME/$ident/g"
# black magic to convert snake_case to PascalCase
pascal=$(echo -n $ident | LC_ALL=C tr '_' '\n' | LC_ALL=C awk -v FIELDWIDTHS='1 1000' -v ORS='' '{print toupper($1) $2}')
grep -l -r PROJECTNAME | xargs sed -i "s/PROJECTNAME/$pascal/g"
# another hack, to update Cargo.lock
cargo tree >/dev/null
git commit -a -m "MORPH INTO: $name"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

View File

@ -1,3 +0,0 @@
# Self-tests
This directory contains self-tests for the skeleton itself. It should be removed when starting a new project.

View File

@ -1,5 +0,0 @@
#!/bin/sh
set -E
exec cargo check

View File

@ -1,8 +0,0 @@
#!/bin/sh
set -x
set -E
mkdir build
cmake -S . -B build -G Ninja -D CMAKE_BUILD_TYPE=Debug
ninja -C build

View File

@ -1,17 +0,0 @@
#!/bin/zsh
set -e
trap 'echo Test failed!' ERR
name='<Test/+> "Example"'
dir=${0%/*}
root=$dir/..
tmp=$(mktemp -d)
trap 'rm -rf $tmp' EXIT
rsync -a --exclude=/.git --exclude-from=$root/.gitignore $root/. $tmp/
cd $tmp
echo "Initializing in $tmp"
./init.sh $name
echo "Starting the shell in $tmp"
echo "Review the files, then exit the shell"
${SHELL:-/bin/sh} -i
echo "Review successful, cleaning up"

View File

@ -1,16 +0,0 @@
#!/bin/zsh
set -e
trap 'echo Test failed!' ERR
name='<Test/+> "Example"'
root=$(realpath ${0%/*}/..)
tmp=$(mktemp -d)
trap 'rm -rf $tmp' EXIT
cd $tmp
git -C $root archive HEAD | tar -x
echo "Initializing in $tmp"
./init.sh $name
echo "Starting the shell in $tmp"
echo "Review the files, then exit the shell"
${SHELL:-/bin/sh} -i
echo "Review successful, cleaning up"

View File

@ -1,18 +0,0 @@
#!/bin/zsh
set -e
trap 'echo Test failed!' ERR
name='<Test/+> "Example"'
dir=${0%/*}
root=$dir/..
tmp=$(mktemp -d)
trap 'rm -rf $tmp' EXIT
rsync -a --exclude-from=$root/.gitignore $root/. $tmp/
cd $tmp
git clean -fxdq
echo "Initializing in $tmp"
./init.sh $name
echo "Starting the shell in $tmp"
echo "Review the files, then exit the shell"
${SHELL:-/bin/sh} -i
echo "Review successful, cleaning up"

View File

@ -1,6 +1,6 @@
use std::sync::Arc;
use PROJECT_NAME::{Core, RedrawArgs, init_gpu_inner};
use gear_cutter::{Core, RedrawArgs, init_gpu_inner};
use glam::uvec2;
use winit::{
application::ApplicationHandler,
@ -9,7 +9,7 @@ use winit::{
window::Window,
};
const TITLE: &str = "PROJECT NAME";
const TITLE: &str = "Gear Cutter";
struct MainWindow {
window: Arc<Window>,

View File

@ -1,6 +1,6 @@
include(impl.cmake)
qt_add_executable(PROJECT-NAME
qt_add_executable(gear-cutter
src/api.cxx
src/main.cxx
src/main_window.cxx
@ -8,6 +8,6 @@ qt_add_executable(PROJECT-NAME
src/viewport.cxx
)
target_link_libraries(PROJECT-NAME PRIVATE Qt6::Gui Qt6::Widgets)
target_link_libraries(PROJECT-NAME PRIVATE PROJECT_NAME_impl)
target_include_directories(PROJECT-NAME PRIVATE src)
target_link_libraries(gear-cutter PRIVATE Qt6::Gui Qt6::Widgets)
target_link_libraries(gear-cutter PRIVATE gear_cutter_impl)
target_include_directories(gear-cutter PRIVATE src)

View File

@ -1,5 +1,5 @@
[package]
name = "PROJECT-NAME-impl"
name = "gear-cutter-impl"
version = "0.1.0"
edition = "2024"
@ -7,7 +7,7 @@ edition = "2024"
crate-type = ["staticlib"]
[dependencies]
PROJECT-NAME = {path = "../"}
gear-cutter = {path = "../"}
glam = { version = "0.30" }
pollster = "0.4.0"

View File

@ -8,7 +8,7 @@ language = "C++"
[parse]
parse_deps = true
include = ["PROJECT-NAME"]
include = ["gear-cutter"]
[export]
exclude = ["Box"]

View File

@ -1,9 +1,9 @@
# build the Rust side as a static library
set(impl_basename "${CARGO_TARGET_DIR}/release/libPROJECT_NAME_impl")
set(impl_basename "${CARGO_TARGET_DIR}/release/libgear_cutter_impl")
add_custom_command(
OUTPUT ${impl_basename}.a
COMMAND env CARGO_TARGET_DIR=${CARGO_TARGET_DIR} ${CARGO} build --release --package PROJECT-NAME-impl
COMMAND env CARGO_TARGET_DIR=${CARGO_TARGET_DIR} ${CARGO} build --release --package gear-cutter-impl
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
DEPFILE ${impl_basename}.d
USES_TERMINAL
@ -17,9 +17,9 @@ add_custom_target(build_impl
DEPENDS ${impl_basename}.a
)
add_library(PROJECT_NAME_impl STATIC IMPORTED)
add_library(gear_cutter_impl STATIC IMPORTED)
set_target_properties(PROJECT_NAME_impl PROPERTIES
set_target_properties(gear_cutter_impl PROPERTIES
IMPORTED_LOCATION ${impl_basename}.a
)
@ -37,9 +37,9 @@ add_custom_command(
DEPENDS_EXPLICIT_ONLY
)
target_sources(PROJECT_NAME_impl INTERFACE
target_sources(gear_cutter_impl INTERFACE
${bindings_basename}.hxx
)
target_include_directories(PROJECT_NAME_impl INTERFACE
target_include_directories(gear_cutter_impl INTERFACE
"${CMAKE_CURRENT_BINARY_DIR}/include"
)

View File

@ -1,6 +1,6 @@
use std::{ffi::c_void, num::NonZero, ptr::NonNull};
use PROJECT_NAME::{Core, RedrawArgs, init_gpu_inner};
use gear_cutter::{Core, RedrawArgs, init_gpu_inner};
use glam::{UVec2, uvec2};
use raw_window_handle::{RawDisplayHandle, RawWindowHandle, XcbDisplayHandle, XcbWindowHandle};

View File

@ -8,7 +8,7 @@ int main(int argc, char* argv[]) {
QApplication app(argc, argv);
auto w = new PROJECTNAME;
auto w = new GearCutter;
w->show();
return app.exec();

View File

@ -2,16 +2,16 @@
#include "ui_main_window.h"
PROJECTNAME::PROJECTNAME(QWidget* parent)
GearCutter::GearCutter(QWidget* parent)
: QMainWindow(parent),
m_ui(new Ui::MainWindow) {
m_ui->setupUi(this);
updateView();
}
PROJECTNAME::~PROJECTNAME() = default;
GearCutter::~GearCutter() = default;
void PROJECTNAME::updateView() {
void GearCutter::updateView() {
RedrawArgs args{
.cam_yaw = qDegreesToRadians((float)m_ui->camYaw->value()),
.cam_pitch = qDegreesToRadians((float)m_ui->camPitch->value()),
@ -21,7 +21,7 @@ void PROJECTNAME::updateView() {
m_ui->viewport->setView(args);
}
void PROJECTNAME::updateViewIf(bool update) {
void GearCutter::updateViewIf(bool update) {
if (update)
updateView();
}

View File

@ -7,12 +7,12 @@ namespace Ui {
class MainWindow;
}
class PROJECTNAME : public QMainWindow {
class GearCutter : public QMainWindow {
Q_OBJECT
public:
explicit PROJECTNAME(QWidget* parent = nullptr);
~PROJECTNAME() override;
explicit GearCutter(QWidget* parent = nullptr);
~GearCutter() override;
public slots:
void updateView();

View File

@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
<string>PROJECT NAME</string>
<string>Gear Cutter</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QHBoxLayout" name="horizontalLayout_2">