Compare commits
541 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 24631990bd | |||
| 0c8c0d24ba | |||
| 454b8a91ba | |||
| a74f1568e9 | |||
| 3f35d56be4 | |||
| 722fe2ccfb | |||
| d85737cc08 | |||
| ce29435831 | |||
| d3715eece8 | |||
| 335d79f2c4 | |||
| a9e33660cb | |||
| 8faf881399 | |||
| c4969a36cc | |||
| 26fcaf6e75 | |||
| a162002af2 | |||
| 9810fd51ab | |||
| 857c6b3d47 | |||
| e1498f538d | |||
| aa246eff94 | |||
| 5be21a21d5 | |||
| 8131bcd4d4 | |||
| 4ba11e3363 | |||
| acf2be3f66 | |||
| f5df0195e2 | |||
| d26995b48d | |||
| 617f8120ae | |||
| 06c517c9aa | |||
| 593ed6408c | |||
| fb7d3ed122 | |||
| 19b88ec858 | |||
| 160e65be7f | |||
| 079b0d2cf6 | |||
| 78f1310f41 | |||
| eb1974c113 | |||
| 551409a023 | |||
| a11e14daac | |||
| 7441e15e76 | |||
| 46506228a6 | |||
| 17c49c74cf | |||
| 3f8024d4db | |||
| 8675e44d28 | |||
| 1301d9a718 | |||
| da3db50ca8 | |||
| 2ca6780305 | |||
| be68fe5a35 | |||
| dc41c0e302 | |||
| 51388c90d5 | |||
| f8c9d33df2 | |||
| ed0420fdce | |||
| 47a6f396fa | |||
| 9edb2aa0c1 | |||
| 003b647d83 | |||
| 2849ff8844 | |||
| 9f3089742a | |||
| b286a9bbcd | |||
| 6204e745ba | |||
| bbe0e48d23 | |||
| 79054080c0 | |||
| 81024c4c09 | |||
| 9068d96130 | |||
| 6f47543720 | |||
| 5a08384ae1 | |||
| 45d8fda0e4 | |||
| a9e664492f | |||
| 3c8b6cb2cc | |||
| 2b3abbe13b | |||
| 241a52b94a | |||
| 82c300b077 | |||
| 0f8b629e20 | |||
| 36f6ac65f2 | |||
| a25871a849 | |||
| 57766a9104 | |||
| 3770ae1645 | |||
| d73edb403f | |||
| b14196ff0d | |||
| 88903fee94 | |||
| 1e8311fc04 | |||
| 2b78370cb8 | |||
| 8f78bba9e9 | |||
| 41a4be678e | |||
| 8b2b4b7c3d | |||
| 1f3a29f89d | |||
| c4c93097cd | |||
| eedb7769e6 | |||
| 98db62a4bc | |||
| df48c8e500 | |||
| db9cc0f4c6 | |||
| a79ee429b4 | |||
| 6acfca6d48 | |||
| 1cd6f4cb72 | |||
| 3271e8c7d6 | |||
| 0bcde064af | |||
| 957980b3c5 | |||
| 03eb328d81 | |||
| e1716a741f | |||
| e24707c847 | |||
| 7c4b8c307f | |||
| 109318aeaf | |||
| 1f2657cea0 | |||
| 382c435bac | |||
| 130fe4ca5d | |||
| 31ba3fe127 | |||
| f68b31158f | |||
| 653ca9a72d | |||
| ba7857f4df | |||
| 23e617ea21 | |||
| cdf5a5229c | |||
| f841a35a53 | |||
| efd31237be | |||
| 6502822583 | |||
| a9e6f2b2a5 | |||
| 510a94b42c | |||
| d805be47ce | |||
| f9ea8e380a | |||
| 5cb05beb30 | |||
| 677768e6ab | |||
| ed6c951783 | |||
| 54254348b8 | |||
| 782fd07a8d | |||
| a8fd55cb38 | |||
| d7f515575a | |||
| bafbf2ec2f | |||
| 7415944e0a | |||
| 1ff990ff44 | |||
| 73e73d8772 | |||
| 6d876bb767 | |||
| 2be0fe9f06 | |||
| e1fb082927 | |||
| 65ca5ae4c4 | |||
| 2cea43dc70 | |||
| 44a0700800 | |||
| 1613a378f1 | |||
| deed98a27d | |||
| 9d0cb8fb46 | |||
| d8fe0f6923 | |||
| 581dbc2b3c | |||
| 7301d2ad76 | |||
| 3232a14d1d | |||
| 84c1f88d42 | |||
| 3695b10e4b | |||
| 6da02b25fa | |||
| 3bc544fba1 | |||
| 368d370f49 | |||
| bb29c0edef | |||
| 6edcf75a0c | |||
| 31cc186424 | |||
| 0e94c1fa6d | |||
| 6d9e2dd3e1 | |||
| 4a4adeb3c8 | |||
| ff77f8cfa0 | |||
| 36db89c36e | |||
| a9948142ad | |||
| 8d05510584 | |||
| d373de7a29 | |||
| 1efa9a9f7b | |||
| 0fb3ba2f91 | |||
| 3b4c5b5153 | |||
| 9293aeeec8 | |||
| 03ae83b119 | |||
| abd63cc6cf | |||
| 2e43aa2c44 | |||
| 3d984e13c2 | |||
| 010900fe21 | |||
| ffed626447 | |||
| 61f69af35a | |||
| bd248ee91c | |||
| 194255bffe | |||
| 52ee627079 | |||
| bd4200e707 | |||
| 73e7d6c7f3 | |||
| a41b0e916b | |||
| 19f2a2c616 | |||
| 998601f722 | |||
| 7c3386cf3e | |||
| d161182997 | |||
| 1646dc2dbd | |||
| b640295be2 | |||
| b89ae2391b | |||
| a0fad441d0 | |||
| 340084dac3 | |||
| c78135aa09 | |||
| d19f8bbd30 | |||
| 4205899f5a | |||
| 7dd3940770 | |||
| 00d94e3015 | |||
| 7bacb3ee2b | |||
| 8e49be5ac4 | |||
| 3b94598d2c | |||
| bddc9af3b6 | |||
| 2451d73a7c | |||
| 1dd2efa182 | |||
| acea610773 | |||
| 8f2f1fd496 | |||
| 39c775872a | |||
| bdb3cbd109 | |||
| ff84ce2b04 | |||
| 225f405592 | |||
| 715ecffa18 | |||
| e51cdc8992 | |||
| 133685ea37 | |||
| 6aff98d555 | |||
| acdc524284 | |||
| 1ee5ec7b43 | |||
| 46a5403511 | |||
| 87bfb92576 | |||
| c7a3e5601c | |||
| 4009130f6e | |||
| c91243f6e9 | |||
| 0e3871ac26 | |||
| 55baafec8a | |||
| b5a66993ca | |||
| 0b570b5fd6 | |||
| 378227c377 | |||
| 650645eaff | |||
| 62c71f3fe6 | |||
| 041ec3d710 | |||
| 5f2d871bad | |||
| a30b151e4d | |||
| 5a651d2d1f | |||
| 4b3826edd9 | |||
| bae1ff3759 | |||
| fd82486431 | |||
| c9cd91cbd8 | |||
| c8abd374fe | |||
| 2b9ee8f721 | |||
| d02673e04a | |||
| f0117b8e6e | |||
| bb7c41c754 | |||
| efa583c154 | |||
| d16ea13c14 | |||
| 673d8e0a18 | |||
| 37cfdde1ee | |||
| 0778ffb57a | |||
| 42099f7241 | |||
| c52e1d22b7 | |||
| 0d7b0aadd1 | |||
| 4cd3355ef1 | |||
| 98d70b96d1 | |||
| 64735bdf43 | |||
| 7b87347b77 | |||
| b5b29d7061 | |||
| 9ec21f85a0 | |||
| da1a5a3f1b | |||
| 0885da8d44 | |||
| 8af961c6d3 | |||
| ef5febdde3 | |||
| 6d7fbd3926 | |||
| 2680d373d8 | |||
| 2b2ddb3cf2 | |||
| 85ff95296b | |||
| 314a2de41a | |||
| 26fafab47a | |||
| e56ff20e2d | |||
| 55d44f229d | |||
| 1c5e50cc4d | |||
| ea898da6c2 | |||
| dbb7e9f53c | |||
| cbb68a399d | |||
| 0e794f28b1 | |||
| 87d2d9123e | |||
| 6823a4ddb5 | |||
| 20a7c70081 | |||
| 9caa33b3bb | |||
| 2d7e61460a | |||
| a4b7fb3f44 | |||
| 70056cf4ca | |||
| 5f4ab71ade | |||
| f3adb3257b | |||
| 438edda7fd | |||
| d5b0441e6f | |||
| 9ba0ceb000 | |||
| 9474a68995 | |||
| 09c35f0aa6 | |||
| a2113442cb | |||
| d91808487f | |||
| 933949cc19 | |||
| 407620387d | |||
| 98947dea26 | |||
| ebff7af9b5 | |||
| b23c4b83ae | |||
| c0cff40628 | |||
| 97513e354c | |||
| c277ae7aff | |||
| e1835e6282 | |||
| 5ac21db997 | |||
| ca0e9fc3b2 | |||
| 66ebcb1608 | |||
| ff92a78dda | |||
| 7356286fe0 | |||
| 54e8e68f86 | |||
| d21cd7f78b | |||
| 1d7516982a | |||
| c77a11442c | |||
| 5bd43a4643 | |||
| 9b87dfa1a9 | |||
| 2e3173ea40 | |||
| 68eac7cf83 | |||
| 6709505630 | |||
| af6e962a5d | |||
| 18e6bdabaa | |||
| 9743942eae | |||
| 23062137a8 | |||
| 46f7fb5ccd | |||
| 9c90c49a6b | |||
| 4517b63557 | |||
| 58c239f4b4 | |||
| cc8845ba3e | |||
| 6b69ce2901 | |||
| 55300ed21c | |||
| 7346dd4339 | |||
| 2caf3b92ce | |||
| af2cd72a1f | |||
| 3d455ec1f8 | |||
| 15982d7735 | |||
| 5ae3542bd9 | |||
| b1b02ae24b | |||
| f0964e2c92 | |||
| e9661d2998 | |||
| ea6468f2a9 | |||
| a2b38d3b83 | |||
| d67ef02941 | |||
| 549ebe25d8 | |||
| 9a98348582 | |||
| c5f5b025a6 | |||
| 23eaffa3a7 | |||
| c161809248 | |||
| 4bf26dc818 | |||
| 5dd22fad6c | |||
| 2c3fdf7803 | |||
| e984b9f5d7 | |||
| a3c2e37b17 | |||
| edf1b5a0a3 | |||
| 8efdf59ebd | |||
| 5c4537b2fa | |||
| 71e6079054 | |||
| dd048d9b0d | |||
| 93074d653e | |||
| 9139c4350a | |||
| 38ce768168 | |||
| 82b3dc576c | |||
| 2167889f48 | |||
| e9b02c2acf | |||
| 9ee446431b | |||
| df106e3988 | |||
| d0a057e0ee | |||
| 8b49902bf6 | |||
| 71c1e56564 | |||
| 1b12e67de2 | |||
| 291bb4bb81 | |||
| 342ddb19f8 | |||
| 9c9d2d548e | |||
| d7a0bb4509 | |||
| 2b1a3323a8 | |||
| 99d030003c | |||
| 92a753560b | |||
| af9904c892 | |||
| e5e8c49f6c | |||
| b37e5f45ca | |||
| e1f08b07aa | |||
| 073ee8dca9 | |||
| a26e51cf46 | |||
| dfed732825 | |||
| 87aa70c6d2 | |||
| aa2979ffe7 | |||
| 236e16aa6d | |||
| 184bb970e6 | |||
| bd54469891 | |||
| 2f5dccc3ef | |||
| 592edb90a0 | |||
| 3db7e6b1b9 | |||
| 13c4df0d85 | |||
| ef25fb09da | |||
| 03cf4a9efe | |||
| 53dd36efdd | |||
| ad9e841a42 | |||
| 14f3f464c7 | |||
| cbe51cc8d0 | |||
| efaa3f6eea | |||
| 52cce9a3b0 | |||
| b7b390311e | |||
| c1eeddd14b | |||
| 1a7a55dfc3 | |||
| fe5927ea6a | |||
| 119c794ad7 | |||
| e2076b2c1c | |||
| 5208c5148e | |||
| d80660b097 | |||
| b916d0278b | |||
| d51e13e620 | |||
| 40ad4326ef | |||
| b8afc1684a | |||
| 8348b31ac8 | |||
| 411f2dbcce | |||
| ee89c08160 | |||
| 357607a89f | |||
| 8d6dc2df44 | |||
| 5207582ab3 | |||
| 71768e6154 | |||
| ecbe235523 | |||
| afef079d1e | |||
| df17696c69 | |||
| 065bf0908f | |||
| 5b6755e9cf | |||
| b08482acf1 | |||
| 80c9c1d389 | |||
| bb7db57bda | |||
| 6a83ac767c | |||
| 7e47ef9d74 | |||
| e7ec603526 | |||
| 2d8ae09bd8 | |||
| b2affbc0a7 | |||
| d50bc61ada | |||
| ec6b032b45 | |||
| bc72f48496 | |||
| dcf06fbd36 | |||
| 96311d72c2 | |||
| 07938cccc7 | |||
| 097c8c00f9 | |||
| aa5b41fe31 | |||
| 0d56859d94 | |||
| 1af5f238e4 | |||
| dd697d5650 | |||
| 5cf299a1c7 | |||
| 67bf825cc9 | |||
| 56e1696cd4 | |||
| d955fb6430 | |||
| dd910a31aa | |||
| 708c4d0ec3 | |||
| ad13d6c6a1 | |||
| 1c32158142 | |||
| 5cea284906 | |||
| 13dba8b604 | |||
| 22398ddcef | |||
| 94e2cc6210 | |||
| da3513f63d | |||
| 2c83e4ba9f | |||
| c862071126 | |||
| fed819e9b2 | |||
| c6f4518684 | |||
| 053778a502 | |||
| 78e1ae885a | |||
| 982d28a3e0 | |||
| c2cad858a5 | |||
| 794e0574ad | |||
| c190271565 | |||
| ae8a869f64 | |||
| 69d64eb8e4 | |||
| b2f2df650a | |||
| 6af570fab2 | |||
| 9ed902017c | |||
| 32b41c98e1 | |||
| 6bdb4ae30d | |||
| 25dc97e3cc | |||
| cc85983736 | |||
| 6e78ee188d | |||
| 9b73f1717f | |||
| c7b9a53535 | |||
| 2b9be6675c | |||
| fb93453482 | |||
| 81b08b2eba | |||
| d1b03c4cb3 | |||
| 9544d15a18 | |||
| 0392dd0e7f | |||
| 9c25fde548 | |||
| 2c9d0c6cff | |||
| 9897dbe031 | |||
| e78f117cfd | |||
| 07afc3813a | |||
| d788de8637 | |||
| d749ac8a91 | |||
| f71c271c97 | |||
| e1d7b7308f | |||
| 26a71a823a | |||
| 5e39097faa | |||
| 0df7845f2c | |||
| af5bf987c8 | |||
| 024ace1078 | |||
| 8d00fe9d16 | |||
| ab422b14dd | |||
| 95c0690216 | |||
| 6cb80e9e23 | |||
| 83b799caa8 | |||
| a793ac2ff7 | |||
| aec937b04b | |||
| 8ee46fd204 | |||
| 726233e55f | |||
| 7940f4c487 | |||
| b16dbaceec | |||
| f39b2060a8 | |||
| aed202ebf9 | |||
| a495179e5f | |||
| 4e1b404820 | |||
| 8c74ee31e0 | |||
| 77d3c54ebb | |||
| b5de39926b | |||
| 3a8dafbb91 | |||
| 6b22f547fe | |||
| de78be3e25 | |||
| 9f507be7bc | |||
| 9aaf271996 | |||
| b01c0d37b0 | |||
| 538079880d | |||
| fe0529d021 | |||
| d068f0f2c3 | |||
| f9a64b8d54 | |||
| 01cbfaae95 | |||
| f9006a90d5 | |||
| 7daeaee6b5 | |||
| 03218ce20f | |||
| 6f33522c1c | |||
| 3697cc3eef | |||
| 51a1077fda | |||
| 8740c2b165 | |||
| 6ed2bdd4c5 | |||
| c32df89490 | |||
| bd5a67676b | |||
| 903dab49e3 | |||
| 1668c4b0d2 | |||
| 2179a27bf5 | |||
| 6e7a0cba76 | |||
| 69b37b30bc | |||
| ae941a0fdb | |||
| 1b741a81e5 | |||
| edf321515b | |||
| c874e6c197 | |||
| 9a59c22288 | |||
| 750e8840f0 | |||
| cf59989167 | |||
| 7c194ab4b4 | |||
| be422d0a1e | |||
| 68b63d3007 | |||
| 8525138594 | |||
| 7b9f8b190e | |||
| 67f62daa9f | |||
| 0ec701f30b | |||
| c53439066e | |||
| 7278bd0c6f | |||
| b842e5821a | |||
| f7d4cce485 | |||
| 4f502b707f | |||
| 09f182228f |
@@ -1,82 +0,0 @@
|
|||||||
name: Build Dusk
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build-linux:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
- name: Install dependencies
|
|
||||||
run: |
|
|
||||||
apt-get update
|
|
||||||
apt-get install -y build-essential cmake python3 python3-pip python3-polib python3-pil libsdl2-dev libgl1-mesa-dev libzip-dev
|
|
||||||
- name: Configure CMake
|
|
||||||
run: cmake -S . -B build -DDUSK_TARGET_SYSTEM=linux
|
|
||||||
- name: Build
|
|
||||||
run: cmake --build build -- -j$(nproc)
|
|
||||||
- name: List build output
|
|
||||||
run: ls -lh build
|
|
||||||
- name: Upload Linux binary
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: dusk-linux
|
|
||||||
path: build/Dusk
|
|
||||||
if-no-files-found: error
|
|
||||||
|
|
||||||
build-psp:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
- name: Install dependencies
|
|
||||||
run: |
|
|
||||||
apt-get update
|
|
||||||
apt-get install -y build-essential cmake python3 python3-pip python3-polib python3-pil libsdl2-dev libgl1-mesa-dev libzip-dev
|
|
||||||
- name: Configure CMake
|
|
||||||
run: cmake -S . -B build -DDUSK_TARGET_SYSTEM=psp
|
|
||||||
- name: Build
|
|
||||||
run: cmake --build build -- -j$(nproc)
|
|
||||||
- name: Move EBOOT.PBP to Dusk subfolder
|
|
||||||
run: |
|
|
||||||
mkdir -p build/gitea/Dusk
|
|
||||||
mv build/EBOOT.PBP build/gitea/Dusk/EBOOT.PBP
|
|
||||||
- name: List build output
|
|
||||||
run: ls -lh build/gitea/Dusk
|
|
||||||
- name: Upload PSP binary
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: dusk-psp
|
|
||||||
path: build/gitea/
|
|
||||||
if-no-files-found: error
|
|
||||||
|
|
||||||
release:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs:
|
|
||||||
- build-linux
|
|
||||||
- build-psp
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
- name: Download Linux binary
|
|
||||||
uses: actions/download-artifact@v3
|
|
||||||
with:
|
|
||||||
name: dusk-linux
|
|
||||||
path: ./release-assets/linux
|
|
||||||
- name: Download PSP binary
|
|
||||||
uses: actions/download-artifact@v3
|
|
||||||
with:
|
|
||||||
name: dusk-psp
|
|
||||||
path: ./release-assets/psp
|
|
||||||
- name: Create Gitea Release
|
|
||||||
uses: akkuman/gitea-release-action@v1
|
|
||||||
env:
|
|
||||||
NODE_OPTIONS: '--experimental-fetch' # if nodejs < 18
|
|
||||||
files: ./release-assets/*
|
|
||||||
@@ -0,0 +1,174 @@
|
|||||||
|
name: Build Dusk
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- '*'
|
||||||
|
jobs:
|
||||||
|
run-tests:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
- name: Set up Docker
|
||||||
|
uses: docker/setup-docker-action@v5
|
||||||
|
- name: Run tests in Docker
|
||||||
|
run: ./scripts/test-linux-docker.sh
|
||||||
|
|
||||||
|
build-linux:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
- name: Set up Docker
|
||||||
|
uses: docker/setup-docker-action@v5
|
||||||
|
- name: Build Linux
|
||||||
|
run: ./scripts/build-linux-docker.sh
|
||||||
|
- name: Upload Linux binary
|
||||||
|
uses: actions/upload-artifact@v6
|
||||||
|
with:
|
||||||
|
name: dusk-linux
|
||||||
|
path: build-linux/Dusk
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
|
build-psp:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
- name: Set up Docker
|
||||||
|
uses: docker/setup-docker-action@v5
|
||||||
|
- name: Build psp
|
||||||
|
run: ./scripts/build-psp-docker.sh
|
||||||
|
- name: Move EBOOT.PBP to Dusk subfolder
|
||||||
|
run: |
|
||||||
|
mkdir -p ./git-artifcats/Dusk/PSP/GAME/Dusk
|
||||||
|
cp build-psp/EBOOT.PBP ./git-artifcats/Dusk/PSP/GAME/Dusk/EBOOT.PBP
|
||||||
|
- name: Upload psp binary
|
||||||
|
uses: actions/upload-artifact@v6
|
||||||
|
with:
|
||||||
|
name: dusk-psp
|
||||||
|
path: ./git-artifcats/Dusk
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
|
# build-vita:
|
||||||
|
# runs-on: ubuntu-latest
|
||||||
|
# steps:
|
||||||
|
# - name: Checkout repository
|
||||||
|
# uses: actions/checkout@v6
|
||||||
|
# - name: Set up Docker
|
||||||
|
# uses: docker/setup-docker-action@v5
|
||||||
|
# - name: Build Vita
|
||||||
|
# run: ./scripts/build-vita-docker.sh
|
||||||
|
# - name: Upload Vita binary
|
||||||
|
# uses: actions/upload-artifact@v6
|
||||||
|
# with:
|
||||||
|
# name: dusk-vita
|
||||||
|
# path: build-vita/Dusk.vpk
|
||||||
|
# if-no-files-found: error
|
||||||
|
|
||||||
|
build-knulli:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
- name: Set up Docker
|
||||||
|
uses: docker/setup-docker-action@v5
|
||||||
|
- name: Build knulli
|
||||||
|
run: ./scripts/build-knulli-docker.sh
|
||||||
|
- name: Move output to Dusk subfolder
|
||||||
|
run: |
|
||||||
|
mkdir -p ./git-artifcats/Dusk
|
||||||
|
cp -r build-knulli/dusk ./git-artifcats/Dusk
|
||||||
|
- name: Upload knulli binary
|
||||||
|
uses: actions/upload-artifact@v6
|
||||||
|
with:
|
||||||
|
name: dusk-knulli
|
||||||
|
path: ./git-artifcats/Dusk
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
|
build-gamecube:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
- name: Set up Docker
|
||||||
|
uses: docker/setup-docker-action@v5
|
||||||
|
- name: Build GameCube
|
||||||
|
run: ./scripts/build-gamecube-docker.sh
|
||||||
|
- name: Copy output files.
|
||||||
|
run: |
|
||||||
|
mkdir -p ./git-artifcats/Dusk
|
||||||
|
cp build-gamecube/Dusk.dol ./git-artifcats/Dusk/Dusk.dol
|
||||||
|
cp build-gamecube/dusk.dsk ./git-artifcats/Dusk/dusk.dsk
|
||||||
|
- name: Upload GameCube binary
|
||||||
|
uses: actions/upload-artifact@v6
|
||||||
|
with:
|
||||||
|
name: dusk-gamecube
|
||||||
|
path: ./git-artifcats/Dusk
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
|
build-gamecube-iso:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
- name: Set up Docker
|
||||||
|
uses: docker/setup-docker-action@v5
|
||||||
|
- name: Build GameCube ISO
|
||||||
|
run: ./scripts/build-gamecube-iso-docker.sh
|
||||||
|
- name: Copy output files.
|
||||||
|
run: |
|
||||||
|
mkdir -p ./git-artifcats/Dusk
|
||||||
|
cp build-gamecube-iso/Dusk-NTSC-J.iso ./git-artifcats/Dusk/Dusk-NTSC-J.iso
|
||||||
|
cp build-gamecube-iso/Dusk-NTSC-U.iso ./git-artifcats/Dusk/Dusk-NTSC-U.iso
|
||||||
|
cp build-gamecube-iso/Dusk-PAL.iso ./git-artifcats/Dusk/Dusk-PAL.iso
|
||||||
|
- name: Upload GameCube ISO
|
||||||
|
uses: actions/upload-artifact@v6
|
||||||
|
with:
|
||||||
|
name: dusk-gamecube-iso
|
||||||
|
path: ./git-artifcats/Dusk
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
|
build-wii:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
- name: Set up Docker
|
||||||
|
uses: docker/setup-docker-action@v5
|
||||||
|
- name: Build Wii
|
||||||
|
run: ./scripts/build-wii-docker.sh
|
||||||
|
- name: Copy output files.
|
||||||
|
run: |
|
||||||
|
mkdir -p ./git-artifcats/Dusk/apps/Dusk
|
||||||
|
cp build-wii/boot.dol ./git-artifcats/Dusk/apps/Dusk/boot.dol
|
||||||
|
cp build-wii/dusk.dsk ./git-artifcats/Dusk/apps/Dusk/dusk.dsk
|
||||||
|
cp build-wii/meta.xml ./git-artifcats/Dusk/apps/Dusk/meta.xml
|
||||||
|
- name: Upload Wii binary
|
||||||
|
uses: actions/upload-artifact@v6
|
||||||
|
with:
|
||||||
|
name: dusk-wii
|
||||||
|
path: ./git-artifcats/Dusk
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
|
build-wii-iso:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
- name: Set up Docker
|
||||||
|
uses: docker/setup-docker-action@v5
|
||||||
|
- name: Build Wii ISO
|
||||||
|
run: ./scripts/build-wii-iso-docker.sh
|
||||||
|
- name: Copy output files.
|
||||||
|
run: |
|
||||||
|
mkdir -p ./git-artifcats/Dusk
|
||||||
|
cp build-wii-iso/Dusk-NTSC-J.iso ./git-artifcats/Dusk/Dusk-NTSC-J.iso
|
||||||
|
cp build-wii-iso/Dusk-NTSC-U.iso ./git-artifcats/Dusk/Dusk-NTSC-U.iso
|
||||||
|
cp build-wii-iso/Dusk-PAL.iso ./git-artifcats/Dusk/Dusk-PAL.iso
|
||||||
|
- name: Upload Wii ISO
|
||||||
|
uses: actions/upload-artifact@v6
|
||||||
|
with:
|
||||||
|
name: dusk-wii-iso
|
||||||
|
path: ./git-artifcats/Dusk
|
||||||
|
if-no-files-found: error
|
||||||
+13
-1
@@ -83,7 +83,6 @@ assets/borrowed
|
|||||||
.VSCode*
|
.VSCode*
|
||||||
|
|
||||||
/vita
|
/vita
|
||||||
|
|
||||||
._*
|
._*
|
||||||
|
|
||||||
*~
|
*~
|
||||||
@@ -95,3 +94,16 @@ assets/borrowed
|
|||||||
# /archive
|
# /archive
|
||||||
|
|
||||||
__pycache__
|
__pycache__
|
||||||
|
|
||||||
|
package-lock.json
|
||||||
|
yarn-error.log
|
||||||
|
yarn.lock
|
||||||
|
|
||||||
|
.editor
|
||||||
|
.venv
|
||||||
|
|
||||||
|
/build2
|
||||||
|
/build*
|
||||||
|
/assets/test
|
||||||
|
/tools_old
|
||||||
|
/assets/test.png
|
||||||
@@ -0,0 +1,432 @@
|
|||||||
|
# Dusk — Claude Code rules
|
||||||
|
|
||||||
|
## File headers
|
||||||
|
Every C, H, and JS file starts with:
|
||||||
|
|
||||||
|
```c
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
```
|
||||||
|
|
||||||
|
JS files use `//` comment style instead.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## C conventions
|
||||||
|
|
||||||
|
### Types
|
||||||
|
Always use the project-defined aliases instead of bare C primitives:
|
||||||
|
|
||||||
|
| Use | Not |
|
||||||
|
|-----------|--------------|
|
||||||
|
| `bool_t` | `bool` |
|
||||||
|
| `int_t` | `int` |
|
||||||
|
| `float_t` | `float` |
|
||||||
|
| `char_t` | `char` |
|
||||||
|
|
||||||
|
Use `uint8_t`, `uint16_t`, `int32_t`, etc. for fixed-width integers.
|
||||||
|
All struct and enum types end in `_t` (`animation_t`, `errorret_t`, …).
|
||||||
|
|
||||||
|
### Naming
|
||||||
|
- **Functions** — snake_case, prefixed with their module:
|
||||||
|
`assetLock()`, `entityPositionInit()`, `moduleAssetBatchCtor()`
|
||||||
|
- **Struct fields** — camelCase: `keyframeCount`, `localPosition`
|
||||||
|
- **Macros / constants** — UPPER_SNAKE_CASE:
|
||||||
|
`ENTITY_ID_INVALID`, `ERROR_OK`, `COMPONENT_TYPE_COUNT`
|
||||||
|
- **Files** — snake_case matching the primary type: `entityposition.c`,
|
||||||
|
`moduleassetbatch.c`
|
||||||
|
|
||||||
|
### Header files (`.h`)
|
||||||
|
- Use `#pragma once` — no include guards.
|
||||||
|
- Declare every public function, `#define`, and `extern` global.
|
||||||
|
- Write a JSDoc block (`/** … */`) above every declaration explaining
|
||||||
|
purpose, `@param`s, and `@returns`.
|
||||||
|
- Only include headers that the `.h` file itself strictly requires for
|
||||||
|
the types it exposes. Move everything else to the `.c` file.
|
||||||
|
Do not use forward declarations as a workaround — use the real
|
||||||
|
include in the `.c` file instead.
|
||||||
|
|
||||||
|
### Implementation files (`.c`)
|
||||||
|
- Contain function bodies only; no declarations.
|
||||||
|
- Pull in whatever additional includes the implementation needs.
|
||||||
|
- Do not use `static` or `inline` on **functions**. Every function,
|
||||||
|
including internal helpers, must be declared in the matching `.h` and
|
||||||
|
defined in the `.c` file. Internal helpers belong near the bottom of
|
||||||
|
the `.c` file, not at the top with a `static` qualifier.
|
||||||
|
`static` and `inline` on functions are only appropriate when the
|
||||||
|
function body is written directly inside a `.h` file.
|
||||||
|
`static` on **variables** (file-scope state) is fine and expected.
|
||||||
|
|
||||||
|
### Formatting
|
||||||
|
- Hard-wrap all lines at **80 characters**.
|
||||||
|
|
||||||
|
### Error handling
|
||||||
|
Return `errorret_t` from fallible functions. Use these macros:
|
||||||
|
|
||||||
|
```c
|
||||||
|
errorOk(); // return success
|
||||||
|
errorThrow("msg %d", val); // return failure with message
|
||||||
|
errorChain(someCall()); // propagate failure, continue on success
|
||||||
|
errorIsOk(ret) / errorIsNotOk(ret) // test a result
|
||||||
|
errorCatch(ret); // handle + free an error
|
||||||
|
```
|
||||||
|
|
||||||
|
Never return raw error codes or use `errno` for in-engine errors.
|
||||||
|
|
||||||
|
### Memory
|
||||||
|
Use the project allocator — never raw `malloc`/`free`:
|
||||||
|
|
||||||
|
```c
|
||||||
|
memoryAllocate(size) // allocate
|
||||||
|
memoryFree(ptr) // free
|
||||||
|
memoryZero(dest, size) // zero a block
|
||||||
|
memoryCopy(dest, src, size) // copy
|
||||||
|
```
|
||||||
|
|
||||||
|
### Asserts
|
||||||
|
Prefer specific assert macros over bare `assert()`:
|
||||||
|
|
||||||
|
```c
|
||||||
|
assertNotNull(ptr, "msg");
|
||||||
|
assertTrue(cond, "msg");
|
||||||
|
assertFalse(cond, "msg");
|
||||||
|
assertUnreachable("msg");
|
||||||
|
assertIsMainThread("msg");
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Build system
|
||||||
|
Each subdirectory has its own `CMakeLists.txt` that adds sources with:
|
||||||
|
|
||||||
|
```cmake
|
||||||
|
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||||
|
PUBLIC
|
||||||
|
myfile.c
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
Never add source files to the root `CMakeLists.txt` directly.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Platform support
|
||||||
|
|
||||||
|
### Targets
|
||||||
|
Set `DUSK_TARGET_SYSTEM` at CMake configure time to select a platform:
|
||||||
|
|
||||||
|
| `DUSK_TARGET_SYSTEM` | Macro defined | Platform |
|
||||||
|
|----------------------|-------------------|------------------|
|
||||||
|
| `linux` | `DUSK_LINUX` | Linux desktop |
|
||||||
|
| `knulli` | `DUSK_KNULLI` | Knulli (handheld)|
|
||||||
|
| `psp` | `DUSK_PSP` | Sony PSP |
|
||||||
|
| `vita` | `DUSK_VITA` | PlayStation Vita |
|
||||||
|
| `gamecube` | `DUSK_GAMECUBE` | Nintendo GameCube|
|
||||||
|
| `wii` | `DUSK_WII` | Nintendo Wii |
|
||||||
|
|
||||||
|
### Layer structure
|
||||||
|
```
|
||||||
|
src/dusk/ core, platform-agnostic game logic
|
||||||
|
src/duskgl/ OpenGL abstraction (Linux, Knulli, PSP, Vita)
|
||||||
|
src/dusksdl2/ SDL2 window + input (Linux, Knulli, PSP, Vita)
|
||||||
|
src/dusklinux/ Linux + Knulli platform impl
|
||||||
|
src/duskpsp/ PSP platform impl
|
||||||
|
src/duskvita/ Vita platform impl
|
||||||
|
src/duskdolphin/ GameCube / Wii platform impl (no SDL2/OpenGL)
|
||||||
|
```
|
||||||
|
|
||||||
|
Dolphin is the only target that bypasses SDL2 and OpenGL entirely —
|
||||||
|
it uses native GameCube/Wii rendering and input APIs.
|
||||||
|
|
||||||
|
### Platform guards
|
||||||
|
Use the compile-time macros for platform-specific code:
|
||||||
|
|
||||||
|
```c
|
||||||
|
#ifdef DUSK_PSP
|
||||||
|
// PSP-only path
|
||||||
|
#elif defined(DUSK_GAMECUBE) || defined(DUSK_WII)
|
||||||
|
// GameCube / Wii path
|
||||||
|
#else
|
||||||
|
// Generic / Linux fallback
|
||||||
|
#endif
|
||||||
|
```
|
||||||
|
|
||||||
|
Additional capability macros set per-target:
|
||||||
|
`DUSK_SDL2`, `DUSK_OPENGL`, `DUSK_OPENGL_ES`, `DUSK_OPENGL_LEGACY`,
|
||||||
|
`DUSK_INPUT_GAMEPAD`, `DUSK_INPUT_KEYBOARD`, `DUSK_INPUT_POINTER`,
|
||||||
|
`DUSK_PLATFORM_ENDIAN_BIG` / `DUSK_PLATFORM_ENDIAN_LITTLE`.
|
||||||
|
|
||||||
|
### Abstraction pattern
|
||||||
|
Platform-specific implementations are wired in via `#define` macros in
|
||||||
|
each platform's `displayplatform.h` / `inputplatform.h` etc., which
|
||||||
|
the core calls through. Functions that a platform does not support are
|
||||||
|
simply left undefined — the core guards calls with `#ifdef`.
|
||||||
|
|
||||||
|
### Adding platform-specific code
|
||||||
|
- Put it under `src/dusk<platform>/` in the matching subsystem folder.
|
||||||
|
- Gate any core call-site with the appropriate `#ifdef DUSK_<PLATFORM>`
|
||||||
|
or capability macro.
|
||||||
|
- Keep the `src/dusk/` core free of platform ifdefs — delegate through
|
||||||
|
the platform header macros instead.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Adding a new asset loader type
|
||||||
|
1. Add an enum value to `assetloadertype_t` (before `_COUNT`) in
|
||||||
|
`src/dusk/asset/loader/assetloader.h`.
|
||||||
|
2. Add fields to the input/loading/output unions in `assetloader.h`.
|
||||||
|
3. Implement `assetXxxLoaderSync`, `assetXxxLoaderAsync`, and
|
||||||
|
`assetXxxDispose` in a new `src/dusk/asset/loader/xxx/` directory.
|
||||||
|
4. Register the three callbacks in `ASSET_LOADER_CALLBACKS[]` in
|
||||||
|
`src/dusk/asset/loader/assetloader.c`.
|
||||||
|
5. If user-facing, create a JS module (see below) and a `.d.ts` file.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Adding a new entity component
|
||||||
|
1. Create `src/dusk/entity/component/<category>/entityMyComp.h/.c` with
|
||||||
|
struct `entityMyComp_t`, `entityMyCompInit()`, and optionally
|
||||||
|
`entityMyCompDispose()`.
|
||||||
|
2. Add the include to `src/dusk/entity/componentlist.h` header block.
|
||||||
|
3. Add a row to `src/dusk/entity/componentlist.h`:
|
||||||
|
```c
|
||||||
|
X(MYCOMP, entityMyComp_t, myComp, entityMyCompInit, NULL, NULL)
|
||||||
|
```
|
||||||
|
This auto-generates the enum, union field, and definition entry.
|
||||||
|
4. If JS-facing, create the script module and `.d.ts` (see below).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Adding a new script (JS) module
|
||||||
|
1. Create `src/dusk/script/module/<category>/moduleMyMod.h/.c`.
|
||||||
|
- Declare `extern scriptproto_t MODULE_MYMOD_PROTO;` in the header.
|
||||||
|
- Use `moduleBaseFunction(name)` to define JS-callable functions.
|
||||||
|
- Register props/funcs in `moduleMyModInit()` with
|
||||||
|
`scriptProtoDefineProp` / `scriptProtoDefineFunc` /
|
||||||
|
`scriptProtoDefineStaticFunc`.
|
||||||
|
2. `#include` the header in
|
||||||
|
`src/dusk/script/module/modulelist.c` and call
|
||||||
|
`moduleMyModInit()` in `moduleListInit()` (and `Dispose` in
|
||||||
|
`moduleListDispose()`).
|
||||||
|
3. For component modules also register in
|
||||||
|
`src/dusk/script/module/entity/component/modulecomponentlist.c`
|
||||||
|
so `entity.add()` returns the typed wrapper.
|
||||||
|
4. Create `types/<category>/mymod.d.ts` and add a
|
||||||
|
`/// <reference path="..." />` line to `types/index.d.ts`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Script module type declarations
|
||||||
|
Whenever a `src/dusk/script/module/**/*.c` file is created or modified,
|
||||||
|
check whether the corresponding `types/**/*.d.ts` needs updating and
|
||||||
|
apply any changes before finishing the task.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## JavaScript (asset scripts)
|
||||||
|
- Use `var` for module-level state; `const` for values that never
|
||||||
|
change.
|
||||||
|
- Always use semicolons.
|
||||||
|
- Scene objects are plain objects (`var scene = {}`) with assigned
|
||||||
|
methods.
|
||||||
|
- Export via `module.exports = scene`.
|
||||||
|
- Async scene init should use `async function` and `await`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Coding style
|
||||||
|
|
||||||
|
### ASCII only
|
||||||
|
Source files (`.c`, `.h`, `.js`) must contain only ASCII characters (U+0000–U+007F).
|
||||||
|
Non-ASCII characters are banned even in comments and string literals.
|
||||||
|
Use ASCII-only substitutes instead:
|
||||||
|
- `--` or `-` instead of `—` (em dash)
|
||||||
|
- `->` instead of `→` (arrow)
|
||||||
|
- `x` or `*` instead of `×` (multiplication)
|
||||||
|
|
||||||
|
Only non-script asset files (e.g. `.po` locale files) may contain non-ASCII text.
|
||||||
|
|
||||||
|
### Indentation
|
||||||
|
2 spaces. No tabs.
|
||||||
|
|
||||||
|
### Keyword and operator spacing
|
||||||
|
No space between a keyword or function name and its opening parenthesis:
|
||||||
|
|
||||||
|
```c
|
||||||
|
if(!ptr) return;
|
||||||
|
for(uint8_t i = 0; i < count; i++) {
|
||||||
|
while(entry->state != DONE) {
|
||||||
|
switch(type) {
|
||||||
|
sizeof(assetbatch_t)
|
||||||
|
memoryZero(ptr, size)
|
||||||
|
```
|
||||||
|
|
||||||
|
Spaces around all binary operators and after every comma:
|
||||||
|
|
||||||
|
```c
|
||||||
|
pos->flags |= ENTITY_POSITION_FLAG_WORLD_DIRTY;
|
||||||
|
(size_t)end - (size_t)start
|
||||||
|
foo(a, b, c)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Braces
|
||||||
|
Opening brace on the **same line** as the statement (K&R style) for all
|
||||||
|
constructs — functions, `if`, `else`, `for`, `while`, `switch`:
|
||||||
|
|
||||||
|
```c
|
||||||
|
void assetEntryLock(assetentry_t *entry) {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dirty) {
|
||||||
|
...
|
||||||
|
} else {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Guard returns
|
||||||
|
Short guards go on one line with no braces:
|
||||||
|
|
||||||
|
```c
|
||||||
|
if(!ptr) return;
|
||||||
|
if(!b || !b->batch) return jerry_undefined();
|
||||||
|
if(!(flags & DIRTY)) return;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Blank lines
|
||||||
|
- One blank line between functions; no blank line at the start or end of
|
||||||
|
a function body.
|
||||||
|
- One blank line between logical blocks inside a function body.
|
||||||
|
- No trailing blank lines at the end of a file.
|
||||||
|
|
||||||
|
### Pointer placement
|
||||||
|
`*` is attached to the variable name, not the type:
|
||||||
|
|
||||||
|
```c
|
||||||
|
assetentry_t *entry
|
||||||
|
const char_t *name
|
||||||
|
void *ptr
|
||||||
|
uint8_t *d = (uint8_t *)dest;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Casts
|
||||||
|
Space between cast and operand:
|
||||||
|
|
||||||
|
```c
|
||||||
|
(assetbatch_t *)user
|
||||||
|
(uint8_t *)dest
|
||||||
|
(textureformat_t)v
|
||||||
|
```
|
||||||
|
|
||||||
|
### Return
|
||||||
|
No parentheses around the return value:
|
||||||
|
|
||||||
|
```c
|
||||||
|
return ptr;
|
||||||
|
return MEMORY_POINTERS_IN_USE;
|
||||||
|
```
|
||||||
|
|
||||||
|
### switch / case
|
||||||
|
`case` indented 2 spaces from `switch`; body indented 2 more from `case`:
|
||||||
|
|
||||||
|
```c
|
||||||
|
switch(type) {
|
||||||
|
case ASSET_LOADER_TYPE_TEXTURE:
|
||||||
|
descs[i].input.texture = (textureformat_t)v;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Multi-line function signatures
|
||||||
|
When parameters don't fit on one line, put each on its own line indented
|
||||||
|
2 spaces; the closing `) {` (definition) or `);` (declaration) goes on
|
||||||
|
its own line at column 0:
|
||||||
|
|
||||||
|
```c
|
||||||
|
void assetEntryInit(
|
||||||
|
assetentry_t *entry,
|
||||||
|
const char_t *name,
|
||||||
|
const assetloadertype_t type,
|
||||||
|
assetloaderinput_t *input
|
||||||
|
) {
|
||||||
|
|
||||||
|
errorret_t memoryCompare(
|
||||||
|
const void *a,
|
||||||
|
const void *b,
|
||||||
|
const size_t size
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Structs and enums
|
||||||
|
Anonymous inner struct or enum with a `typedef`, `_t` suffix, closing
|
||||||
|
brace and name on the same line:
|
||||||
|
|
||||||
|
```c
|
||||||
|
typedef struct {
|
||||||
|
errorcode_t code;
|
||||||
|
char_t *message;
|
||||||
|
} errorstate_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ASSET_LOADER_TYPE_NULL,
|
||||||
|
ASSET_LOADER_TYPE_COUNT
|
||||||
|
} assetloadertype_t;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Designated initialisers
|
||||||
|
Spaces inside braces; `.field = value`:
|
||||||
|
|
||||||
|
```c
|
||||||
|
jsassetentry_t e = { .entry = entry };
|
||||||
|
assetbatchloadedpend_t init = { .batch = batch };
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ternary operator
|
||||||
|
Spaces around `?` and `:`:
|
||||||
|
|
||||||
|
```c
|
||||||
|
const float val = psx > 0.0f ? pt[0][0] / psx : 0.0f;
|
||||||
|
```
|
||||||
|
|
||||||
|
### const placement
|
||||||
|
`const` before the type, `*` attached to the variable:
|
||||||
|
|
||||||
|
```c
|
||||||
|
const char_t *name
|
||||||
|
const void *src
|
||||||
|
const size_t size
|
||||||
|
```
|
||||||
|
|
||||||
|
### Comments in `.c` files
|
||||||
|
- Do not use section dividers (`/* ---- ... ---- */`). Just let the
|
||||||
|
functions follow one another with a single blank line between them.
|
||||||
|
- Multi-line explanatory comments inside function bodies use `//` lines:
|
||||||
|
```c
|
||||||
|
// Script modules are freed; orphaned JS wrapper objects now get GC'd
|
||||||
|
// so their finalizers fire before assetDispose() checks ref counts.
|
||||||
|
jerry_heap_gc(JERRY_GC_PRESSURE_HIGH);
|
||||||
|
```
|
||||||
|
- Do not use `/* */` for inline or inline-block comments inside `.c`
|
||||||
|
function bodies.
|
||||||
|
|
||||||
|
### Comments in `.h` files
|
||||||
|
Every public declaration gets a Javadoc block (`/** … */`) with
|
||||||
|
`@param` and `@returns` where relevant. Keep it on the lines immediately
|
||||||
|
above the declaration with no blank line in between.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tests
|
||||||
|
- Tests live in `test/` mirroring `src/dusk/` structure.
|
||||||
|
- Use cmocka; include `dusktest.h`.
|
||||||
|
- Test functions: `static void test_something(void **state)`.
|
||||||
|
- After each test, assert `memoryGetAllocatedCount() == 0` to catch
|
||||||
|
leaks.
|
||||||
|
- Build with `-DDUSK_BUILD_TESTS=ON`.
|
||||||
+85
-76
@@ -5,14 +5,19 @@
|
|||||||
|
|
||||||
# Setup
|
# Setup
|
||||||
cmake_minimum_required(VERSION 3.13)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
set(CMAKE_C_STANDARD 11)
|
set(CMAKE_C_STANDARD 11)
|
||||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules)
|
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules)
|
||||||
|
cmake_policy(SET CMP0079 NEW)
|
||||||
|
# set(FETCHCONTENT_UPDATES_DISCONNECTED ON)
|
||||||
|
|
||||||
if(NOT DEFINED DUSK_TARGET_SYSTEM)
|
option(DUSK_BUILD_TESTS "Enable tests" OFF)
|
||||||
set(DUSK_TARGET_SYSTEM "linux")
|
|
||||||
#set(DUSK_TARGET_SYSTEM "psp")
|
set(DUSK_GAME_NAME "Dusk" CACHE STRING "Game display name")
|
||||||
endif()
|
set(DUSK_GAME_AUTHOR "YourWishes" CACHE STRING "Game author / coder")
|
||||||
|
set(DUSK_GAME_SHORT_DESCRIPTION "Dusk game" CACHE STRING "One-line description")
|
||||||
|
set(DUSK_GAME_LONG_DESCRIPTION "No description yet." CACHE STRING "Full description")
|
||||||
|
|
||||||
# Prep cache
|
# Prep cache
|
||||||
set(DUSK_CACHE_TARGET "dusk-target")
|
set(DUSK_CACHE_TARGET "dusk-target")
|
||||||
@@ -21,101 +26,105 @@ set(DUSK_CACHE_TARGET "dusk-target")
|
|||||||
set(DUSK_ROOT_DIR "${CMAKE_SOURCE_DIR}")
|
set(DUSK_ROOT_DIR "${CMAKE_SOURCE_DIR}")
|
||||||
set(DUSK_BUILD_DIR "${CMAKE_BINARY_DIR}")
|
set(DUSK_BUILD_DIR "${CMAKE_BINARY_DIR}")
|
||||||
set(DUSK_SOURCES_DIR "${DUSK_ROOT_DIR}/src")
|
set(DUSK_SOURCES_DIR "${DUSK_ROOT_DIR}/src")
|
||||||
|
set(DUSK_TEST_DIR "${DUSK_ROOT_DIR}/test")
|
||||||
set(DUSK_TEMP_DIR "${DUSK_BUILD_DIR}/temp")
|
set(DUSK_TEMP_DIR "${DUSK_BUILD_DIR}/temp")
|
||||||
set(DUSK_TOOLS_DIR "${DUSK_ROOT_DIR}/tools")
|
set(DUSK_TOOLS_DIR "${DUSK_ROOT_DIR}/tools")
|
||||||
set(DUSK_DATA_DIR "${DUSK_ROOT_DIR}/data")
|
set(DUSK_DATA_DIR "${DUSK_ROOT_DIR}/data")
|
||||||
set(DUSK_ASSETS_DIR "${DUSK_ROOT_DIR}/assets")
|
set(DUSK_ASSETS_DIR "${DUSK_ROOT_DIR}/assets")
|
||||||
set(DUSK_BUILT_ASSETS_DIR "${DUSK_BUILD_DIR}/built_assets" CACHE INTERNAL ${DUSK_CACHE_TARGET})
|
set(DUSK_BUILT_ASSETS_DIR "${DUSK_BUILD_DIR}/built_assets" CACHE INTERNAL ${DUSK_CACHE_TARGET})
|
||||||
set(DUSK_GENERATED_HEADERS_DIR "${DUSK_BUILD_DIR}/generated")
|
set(DUSK_GENERATED_HEADERS_DIR "${DUSK_BUILD_DIR}/generated")
|
||||||
set(DUSK_TARGET_NAME "Dusk" CACHE INTERNAL ${DUSK_CACHE_TARGET})
|
|
||||||
set(DUSK_BUILD_BINARY ${DUSK_BUILD_DIR}/Dusk CACHE INTERNAL ${DUSK_CACHE_TARGET})
|
set(DUSK_BUILD_BINARY ${DUSK_BUILD_DIR}/Dusk CACHE INTERNAL ${DUSK_CACHE_TARGET})
|
||||||
set(DUSK_ASSETS "" CACHE INTERNAL ${DUSK_CACHE_TARGET})
|
set(DUSK_ASSETS "" CACHE INTERNAL ${DUSK_CACHE_TARGET})
|
||||||
|
set(DUSK_LIBRARY_TARGET_NAME "DuskCore" CACHE INTERNAL ${DUSK_CACHE_TARGET})
|
||||||
|
set(DUSK_BINARY_TARGET_NAME "Dusk" CACHE INTERNAL ${DUSK_CACHE_TARGET})
|
||||||
|
set(DUSK_ASSETS_ZIP "${DUSK_BUILD_DIR}/dusk.dsk" CACHE INTERNAL ${DUSK_CACHE_TARGET})
|
||||||
|
|
||||||
|
if(NOT DEFINED DUSK_TARGET_SYSTEM)
|
||||||
|
set(DUSK_TARGET_SYSTEM "linux")
|
||||||
|
endif()
|
||||||
|
|
||||||
# Create directories
|
# Create directories
|
||||||
file(MAKE_DIRECTORY ${DUSK_GENERATED_HEADERS_DIR})
|
file(MAKE_DIRECTORY ${DUSK_GENERATED_HEADERS_DIR})
|
||||||
|
file(MAKE_DIRECTORY ${DUSK_TEMP_DIR})
|
||||||
|
file(MAKE_DIRECTORY ${DUSK_BUILT_ASSETS_DIR})
|
||||||
|
|
||||||
# Find packages
|
# Required build packages
|
||||||
find_package(Python3 COMPONENTS Interpreter REQUIRED)
|
find_package(Python3 COMPONENTS Interpreter REQUIRED)
|
||||||
|
|
||||||
# Toolchains
|
# Init Project.
|
||||||
if(DUSK_TARGET_SYSTEM STREQUAL "psp")
|
project(${DUSK_LIBRARY_TARGET_NAME}
|
||||||
find_package(pspsdk REQUIRED)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Init Project
|
|
||||||
project(${DUSK_TARGET_NAME}
|
|
||||||
VERSION 1.0.0
|
VERSION 1.0.0
|
||||||
LANGUAGES C
|
LANGUAGES C
|
||||||
)
|
)
|
||||||
|
|
||||||
# Executable
|
# Either, create library and binary separately (used for tests), or make them
|
||||||
add_executable(${DUSK_TARGET_NAME})
|
# one in the same so all code is in the binary only.
|
||||||
|
# Binary Executable
|
||||||
|
add_executable(${DUSK_BINARY_TARGET_NAME} ${DUSK_SOURCES_DIR}/dusk/null.c)
|
||||||
|
|
||||||
|
if(DUSK_BUILD_TESTS)
|
||||||
|
# MainLibrary
|
||||||
|
add_library(${DUSK_LIBRARY_TARGET_NAME} STATIC)
|
||||||
|
|
||||||
|
# Link library to binary
|
||||||
|
target_link_libraries(${DUSK_BINARY_TARGET_NAME}
|
||||||
|
PUBLIC
|
||||||
|
${DUSK_LIBRARY_TARGET_NAME}
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
set(DUSK_LIBRARY_TARGET_NAME "${DUSK_BINARY_TARGET_NAME}" CACHE INTERNAL ${DUSK_CACHE_TARGET})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT DEFINED DUSK_VERSION)
|
||||||
|
string(TIMESTAMP DUSK_VERSION "debug-%y%m%d%H%M%S")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Definitions
|
||||||
|
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME}
|
||||||
|
PUBLIC
|
||||||
|
DUSK_TARGET_SYSTEM="${DUSK_TARGET_SYSTEM}"
|
||||||
|
DUSK_GAME_NAME="${DUSK_GAME_NAME}"
|
||||||
|
DUSK_GAME_AUTHOR="${DUSK_GAME_AUTHOR}"
|
||||||
|
DUSK_GAME_SHORT_DESCRIPTION="${DUSK_GAME_SHORT_DESCRIPTION}"
|
||||||
|
DUSK_GAME_LONG_DESCRIPTION="${DUSK_GAME_LONG_DESCRIPTION}"
|
||||||
|
DUSK_VERSION="${DUSK_VERSION}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Toolchains
|
||||||
|
include(cmake/targets/${DUSK_TARGET_SYSTEM}.cmake)
|
||||||
|
|
||||||
# Add tools
|
# Add tools
|
||||||
add_subdirectory(tools)
|
add_subdirectory(tools)
|
||||||
|
|
||||||
# Assets
|
# Include generated headers from tools.
|
||||||
add_subdirectory(assets)
|
target_include_directories(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||||
|
|
||||||
# Add libraries
|
|
||||||
if(DUSK_TARGET_SYSTEM STREQUAL "linux")
|
|
||||||
find_package(SDL2 REQUIRED)
|
|
||||||
find_package(OpenGL REQUIRED)
|
|
||||||
target_link_libraries(${DUSK_TARGET_NAME} PRIVATE
|
|
||||||
SDL2
|
|
||||||
OpenGL::GL
|
|
||||||
GL
|
|
||||||
)
|
|
||||||
|
|
||||||
elseif(DUSK_TARGET_SYSTEM STREQUAL "psp")
|
|
||||||
find_package(SDL2 REQUIRED)
|
|
||||||
find_package(OpenGL REQUIRED)
|
|
||||||
target_link_libraries(${DUSK_TARGET_NAME} PUBLIC
|
|
||||||
${SDL2_LIBRARIES}
|
|
||||||
SDL2
|
|
||||||
OpenGL::GL
|
|
||||||
zip
|
|
||||||
bz2
|
|
||||||
z
|
|
||||||
mbedtls
|
|
||||||
mbedcrypto
|
|
||||||
lzma
|
|
||||||
)
|
|
||||||
target_include_directories(${DUSK_TARGET_NAME} PRIVATE
|
|
||||||
${SDL2_INCLUDE_DIRS}
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Add code
|
|
||||||
add_subdirectory(src)
|
|
||||||
|
|
||||||
# Build assets
|
|
||||||
add_custom_target(DUSK_ASSETS_BUILT ALL
|
|
||||||
COMMAND
|
|
||||||
${Python3_EXECUTABLE} ${DUSK_TOOLS_DIR}/assetstool/main.py
|
|
||||||
--assets ${DUSK_GAME_ASSETS_DIR}
|
|
||||||
--build-type wad
|
|
||||||
--output-assets ${DUSK_BUILT_ASSETS_DIR}
|
|
||||||
--output-file ${DUSK_BUILD_DIR}/dusk.dsk
|
|
||||||
--headers-dir ${DUSK_GENERATED_HEADERS_DIR}
|
|
||||||
--input ${DUSK_ASSETS}
|
|
||||||
)
|
|
||||||
add_dependencies(${DUSK_TARGET_NAME} DUSK_ASSETS_BUILT)
|
|
||||||
|
|
||||||
# Include generated headers
|
|
||||||
target_include_directories(${DUSK_TARGET_NAME} PUBLIC
|
|
||||||
${DUSK_GENERATED_HEADERS_DIR}
|
${DUSK_GENERATED_HEADERS_DIR}
|
||||||
)
|
)
|
||||||
|
|
||||||
# Postbuild
|
# Add main code
|
||||||
if(DUSK_TARGET_SYSTEM STREQUAL "psp")
|
add_subdirectory(${DUSK_SOURCES_DIR})
|
||||||
create_pbp_file(
|
|
||||||
TARGET "${DUSK_TARGET_NAME}"
|
# Include generated headers
|
||||||
ICON_PATH NULL
|
target_include_directories(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||||
BACKGROUND_PATH NULL
|
${DUSK_GENERATED_HEADERS_DIR}
|
||||||
PREVIEW_PATH NULL
|
)
|
||||||
TITLE "${DUSK_TARGET_NAME}"
|
|
||||||
PSAR_PATH ${DUSK_BUILD_DIR}/dusk.dsk
|
# Handle tests
|
||||||
VERSION 01.00
|
if(DUSK_BUILD_TESTS)
|
||||||
)
|
enable_testing()
|
||||||
|
add_subdirectory(test)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Build assets
|
||||||
|
file(GLOB_RECURSE DUSK_ASSET_FILES CONFIGURE_DEPENDS "${DUSK_ASSETS_DIR}/*")
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT "${DUSK_ASSETS_ZIP}"
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E make_directory "${DUSK_ASSETS_DIR}"
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E rm -f "${DUSK_ASSETS_ZIP}"
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E tar "cf" "${DUSK_ASSETS_ZIP}" --format=zip -- .
|
||||||
|
WORKING_DIRECTORY "${DUSK_ASSETS_DIR}"
|
||||||
|
DEPENDS ${DUSK_ASSET_FILES}
|
||||||
|
VERBATIM
|
||||||
|
)
|
||||||
|
add_custom_target(DUSK_ASSETS_BUILT DEPENDS "${DUSK_ASSETS_ZIP}")
|
||||||
|
add_dependencies(${DUSK_LIBRARY_TARGET_NAME} DUSK_ASSETS_BUILT)
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# Dusk
|
||||||
|
RPG Game Project, small and able to run on a PSP.
|
||||||
|
|
||||||
|
# Building
|
||||||
|
Each build target has different requirements. You can take a look at the git
|
||||||
|
workflow to see how the builds are done for each target. In addition, for
|
||||||
|
accessing the editor and building the game on your host system, install the
|
||||||
|
following packages, depending on your system;
|
||||||
|
|
||||||
|
Fedora;
|
||||||
|
```
|
||||||
|
sudo dnf install git make gcc cmake python python-polib python3-pillow python3-dotenv python3-numpy python-qt5 python3-pyopengl SDL2-devel zlib-devel libzip-devel bzip2-devel openssl-devel lzma-sdk-devel xz xz-devel lua-devel
|
||||||
|
```
|
||||||
|
|
||||||
|
Ubuntu;
|
||||||
|
```
|
||||||
|
sudo apt-get install git build-essential gcc python python-polib python3-pillow python3-dotenv python3-numpy python3-pyqt5 python3-opengl
|
||||||
|
```
|
||||||
|
|
||||||
|
Arch Linux;
|
||||||
|
```
|
||||||
|
sudo pacman -S git base-devel gcc python python-polib python-pillow python-dotenv python-numpy python-pyqt5 python-opengl
|
||||||
|
```
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
# Copyright (c) 2025 Dominic Masters
|
|
||||||
#
|
|
||||||
# This software is released under the MIT License.
|
|
||||||
# https://opensource.org/licenses/MIT
|
|
||||||
|
|
||||||
set(DUSK_GAME_ASSETS_DIR "${CMAKE_CURRENT_SOURCE_DIR}" CACHE INTERNAL ${DUSK_CACHE_TARGET})
|
|
||||||
|
|
||||||
# Palette asset needs to be added before any images.
|
|
||||||
add_subdirectory(palette)
|
|
||||||
|
|
||||||
# Languages need to be added before anything that uses text.
|
|
||||||
add_subdirectory(locale)
|
|
||||||
|
|
||||||
add_subdirectory(entity)
|
|
||||||
add_subdirectory(map)
|
|
||||||
add_subdirectory(ui)
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 336 B |
@@ -1,4 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<tileset version="1.10" tiledversion="1.11.2" name="entities" tilewidth="16" tileheight="16" tilecount="64" columns="8">
|
|
||||||
<image source="entities.png" width="128" height="128"/>
|
|
||||||
</tileset>
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
// Copyright (c) 2026 Dominic Masters
|
||||||
|
//
|
||||||
|
// This software is released under the MIT License.
|
||||||
|
// https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
const platformNames = {
|
||||||
|
[System.PLATFORM_LINUX]: 'Linux',
|
||||||
|
[System.PLATFORM_KNULLI]: 'Knulli',
|
||||||
|
[System.PLATFORM_PSP]: 'PSP',
|
||||||
|
[System.PLATFORM_GAMECUBE]: 'GameCube',
|
||||||
|
[System.PLATFORM_WII]: 'Wii',
|
||||||
|
};
|
||||||
|
|
||||||
|
Console.print('Platform: ' + (platformNames[System.platform] || 'Unknown'));
|
||||||
|
|
||||||
|
UIFullboxOver.setColor(Color.BLACK);
|
||||||
|
|
||||||
|
requireAsync('testscene.js').then(Scene.set).catch(err => {
|
||||||
|
Console.print('Error loading scene: ' + err);
|
||||||
|
Engine.exit();
|
||||||
|
});
|
||||||
+54
-10
@@ -1,16 +1,60 @@
|
|||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Language: en_US\n"
|
"Project-Id-Version: ExampleApp 1.0\n"
|
||||||
"MIME-Version: 1.0\n"
|
"Language: en\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : n==2 ? 1 : (n<7 ? 2 : 3));\n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
|
||||||
|
|
||||||
msgid "ui.test"
|
#: ui/menu.c:10
|
||||||
msgstr "Hello this is a test."
|
msgid "ui.title"
|
||||||
|
msgstr ""
|
||||||
|
"Welcome"
|
||||||
|
|
||||||
msgid "map.test"
|
#: ui/user.c:22
|
||||||
msgstr "This is a map test."
|
msgid "ui.greeting"
|
||||||
|
msgstr "Hello, %s!"
|
||||||
|
|
||||||
msgid "test.test2"
|
#: ui/files.c:40
|
||||||
msgstr "This is another test."
|
msgid "ui.file_status"
|
||||||
|
msgstr "%s has %d files."
|
||||||
|
|
||||||
|
#: ui/cart.c:55
|
||||||
|
msgid "cart.item_count"
|
||||||
|
msgid_plural "cart.item_count"
|
||||||
|
msgstr[0] "%d item"
|
||||||
|
msgstr[1] "%d items (dual)"
|
||||||
|
msgstr[2] "%d items (few)"
|
||||||
|
msgstr[3] "%d items (many)"
|
||||||
|
|
||||||
|
#: ui/notifications.c:71
|
||||||
|
msgid ""
|
||||||
|
"ui.multiline_help"
|
||||||
|
msgstr ""
|
||||||
|
"Line one of the help text.\n"
|
||||||
|
"Line two continues here.\n"
|
||||||
|
"Line three ends here."
|
||||||
|
|
||||||
|
#: ui/errors.c:90
|
||||||
|
msgid ""
|
||||||
|
"error.upload_failed.long"
|
||||||
|
msgstr ""
|
||||||
|
"Upload failed for file \"%s\".\n"
|
||||||
|
"Please try again later or contact support."
|
||||||
|
|
||||||
|
#: ui/messages.c:110
|
||||||
|
msgid ""
|
||||||
|
"user.invite_status"
|
||||||
|
msgid_plural ""
|
||||||
|
"user.invite_status"
|
||||||
|
msgstr[0] ""
|
||||||
|
"%s invited %d user.\n"
|
||||||
|
"Please review the request."
|
||||||
|
msgstr[1] ""
|
||||||
|
"%s invited %d users (dual).\n"
|
||||||
|
"Please review the requests."
|
||||||
|
msgstr[2] ""
|
||||||
|
"%s invited %d users (few).\n"
|
||||||
|
"Please review the requests."
|
||||||
|
msgstr[3] ""
|
||||||
|
"%s invited %d users (many).\n"
|
||||||
|
"Please review the requests."
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
{
|
|
||||||
"tiles": [
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
|
|
||||||
1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
{
|
|
||||||
"tiles": [
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
|
||||||
]
|
|
||||||
}
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 241 B |
Binary file not shown.
@@ -0,0 +1,63 @@
|
|||||||
|
// Copyright (c) 2026 Dominic Masters
|
||||||
|
//
|
||||||
|
// This software is released under the MIT License.
|
||||||
|
// https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
const PLAYER_SPEED = 5.0;
|
||||||
|
// 1 world unit = 16 pixels.
|
||||||
|
const PIXEL_SCALE = 1.0 / 16.0;
|
||||||
|
// Player sprite is 32x32 px (test.png dimensions).
|
||||||
|
const PLAYER_W = 32 * PIXEL_SCALE;
|
||||||
|
const PLAYER_H = 32 * PIXEL_SCALE;
|
||||||
|
|
||||||
|
var player = {};
|
||||||
|
|
||||||
|
player.getAssets = () => {
|
||||||
|
return [
|
||||||
|
{ path: 'test.png', type: Asset.TYPE_TEXTURE, format: Texture.FORMAT_RGBA }
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
player.init = function(scene) {
|
||||||
|
var texture = scene.assets.getAssetByPath('test.png');
|
||||||
|
Console.print('Player init: got texture ' + texture);
|
||||||
|
|
||||||
|
_entity = Entity.create();
|
||||||
|
_position = _entity.add(Component.POSITION);
|
||||||
|
_physics = _entity.add(Component.PHYSICS);
|
||||||
|
|
||||||
|
_physics.bodyType = Physics.DYNAMIC;
|
||||||
|
_physics.shape = Physics.SHAPE_CUBE;
|
||||||
|
_physics.gravityScale = 1.0;
|
||||||
|
|
||||||
|
var r = _entity.add(Component.RENDERABLE);
|
||||||
|
r.texture = texture.texture;
|
||||||
|
r.type = Renderable.SPRITEBATCH;
|
||||||
|
r.color = new Color(220, 80, 80);
|
||||||
|
// Upright quad centered on X, bottom-aligned on Y.
|
||||||
|
r.sprites = [[-PLAYER_W/2, 0, 0, PLAYER_W/2, PLAYER_H, 0, 0, 1, 1, 0]];
|
||||||
|
|
||||||
|
_position.localPosition = new Vec3(0, PLAYER_H, 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
player.getPosition = function() {
|
||||||
|
return _position;
|
||||||
|
};
|
||||||
|
|
||||||
|
player.update = function() {
|
||||||
|
if(!_physics) return;
|
||||||
|
var vx = Input.axis(INPUT_ACTION_LEFT, INPUT_ACTION_RIGHT) * PLAYER_SPEED;
|
||||||
|
var vz = Input.axis(INPUT_ACTION_DOWN, INPUT_ACTION_UP) * PLAYER_SPEED;
|
||||||
|
// Preserve vertical velocity so gravity and landing work correctly.
|
||||||
|
var vy = _physics.velocity.y;
|
||||||
|
_physics.velocity = new Vec3(vx, vy, vz);
|
||||||
|
};
|
||||||
|
|
||||||
|
player.dispose = function() {
|
||||||
|
Entity.dispose(_entity);
|
||||||
|
_entity = null;
|
||||||
|
_position = null;
|
||||||
|
_physics = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = player;
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
// Copyright (c) 2026 Dominic Masters
|
||||||
|
//
|
||||||
|
// This software is released under the MIT License.
|
||||||
|
// https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
var scene = {};
|
||||||
|
|
||||||
|
// Pokemon DS-style camera: ~34 degrees elevation (atan(6/9)).
|
||||||
|
// CAM_HEIGHT / CAM_DIST ratio controls the tilt - keep it under 0.7 for
|
||||||
|
// the characteristically shallow DS angle.
|
||||||
|
const CAM_HEIGHT = 6;
|
||||||
|
const CAM_DIST = 9;
|
||||||
|
|
||||||
|
scene.init = async function() {
|
||||||
|
// Camera
|
||||||
|
scene.cam = Entity.create();
|
||||||
|
var camPos = scene.cam.add(Component.POSITION);
|
||||||
|
var cam = scene.cam.add(Component.CAMERA);
|
||||||
|
camPos.localPosition = new Vec3(3, 3, 3);
|
||||||
|
camPos.lookAt(new Vec3(0, 0, 0));
|
||||||
|
|
||||||
|
// Floor - large flat slab, no texture needed.
|
||||||
|
scene.floor = Entity.create();
|
||||||
|
var floorPos = scene.floor.add(Component.POSITION);
|
||||||
|
var floorR = scene.floor.add(Component.RENDERABLE);
|
||||||
|
floorR.type = Renderable.SHADER_MATERIAL;
|
||||||
|
floorR.color = Color.BLUE;
|
||||||
|
// floorPos.localScale = new Vec3(16, 0.2, 16);
|
||||||
|
// floorPos.localPosition = new Vec3(0, -0.1, 0);
|
||||||
|
|
||||||
|
await UIFullboxOver.transition(Color.BLACK, Color.TRANSPARENT, 1.0);
|
||||||
|
};
|
||||||
|
|
||||||
|
scene.update = function() {
|
||||||
|
};
|
||||||
|
|
||||||
|
scene.dispose = function() {
|
||||||
|
Entity.dispose(scene.floor);
|
||||||
|
Entity.dispose(scene.cam);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = scene;
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 758 B |
Binary file not shown.
@@ -1,4 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<tileset version="1.10" tiledversion="1.11.2" name="prarie" tilewidth="16" tileheight="16" tilecount="21" columns="7">
|
|
||||||
<image source="prarie.png" width="112" height="48"/>
|
|
||||||
</tileset>
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
# Copyright (c) 2025 Dominic Masters
|
|
||||||
#
|
|
||||||
# This software is released under the MIT License.
|
|
||||||
# https://opensource.org/licenses/MIT
|
|
||||||
|
|
||||||
add_asset(TILESET minogram.png type=PALETTIZED tileWidth=6 tileHeight=10 columns=16 rows=6)# Fixes PSP rendering
|
|
||||||
Binary file not shown.
@@ -0,0 +1,6 @@
|
|||||||
|
module = {
|
||||||
|
render() {
|
||||||
|
Text.draw(0, 0, "Hello World");
|
||||||
|
SpriteBatch.flush();
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"automappingRulesFile": "",
|
|
||||||
"commands": [
|
|
||||||
],
|
|
||||||
"compatibilityVersion": 1100,
|
|
||||||
"extensionsPath": "extensions",
|
|
||||||
"folders": [
|
|
||||||
"."
|
|
||||||
],
|
|
||||||
"properties": [
|
|
||||||
],
|
|
||||||
"propertyTypes": [
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
{
|
|
||||||
"Map/SizeTest": {
|
|
||||||
"height": 4300,
|
|
||||||
"width": 2
|
|
||||||
},
|
|
||||||
"activeFile": "map/untitled.tmx",
|
|
||||||
"expandedProjectPaths": [
|
|
||||||
"tileset",
|
|
||||||
".",
|
|
||||||
"map"
|
|
||||||
],
|
|
||||||
"file.lastUsedOpenFilter": "All Files (*)",
|
|
||||||
"fileStates": {
|
|
||||||
"entity/entities.tsx": {
|
|
||||||
"scaleInDock": 1,
|
|
||||||
"scaleInEditor": 1
|
|
||||||
},
|
|
||||||
"map/prarie.tsx": {
|
|
||||||
"scaleInDock": 1,
|
|
||||||
"scaleInEditor": 11
|
|
||||||
},
|
|
||||||
"map/untitled.tmx": {
|
|
||||||
"scale": 2,
|
|
||||||
"selectedLayer": 0,
|
|
||||||
"viewCenter": {
|
|
||||||
"x": 285.5,
|
|
||||||
"y": 162.75
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"tileset/prarie.tsx": {
|
|
||||||
"scaleInDock": 1,
|
|
||||||
"scaleInEditor": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"last.imagePath": "/home/yourwishes/htdocs/dusk/assets/tileset",
|
|
||||||
"map.lastUsedFormat": "tmx",
|
|
||||||
"map.tileHeight": 16,
|
|
||||||
"map.tileWidth": 16,
|
|
||||||
"openFiles": [
|
|
||||||
"entity/entities.tsx",
|
|
||||||
"map/untitled.tmx",
|
|
||||||
"tileset/prarie.tsx"
|
|
||||||
],
|
|
||||||
"project": "untitled.tiled-project",
|
|
||||||
"recentFiles": [
|
|
||||||
"entity/entities.tsx",
|
|
||||||
"tileset/prarie.tsx",
|
|
||||||
"map/untitled.tmx",
|
|
||||||
"map/prarie.tsx"
|
|
||||||
],
|
|
||||||
"tileset.lastUsedFormat": "tsx",
|
|
||||||
"tileset.tileSize": {
|
|
||||||
"height": 16,
|
|
||||||
"width": 16
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
include(FetchContent)
|
include(FetchContent)
|
||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
cglm
|
cglm
|
||||||
|
# GIT_REPOSITORY https://git.wish.moe/YourWishes/cglm.git
|
||||||
GIT_REPOSITORY https://github.com/recp/cglm.git
|
GIT_REPOSITORY https://github.com/recp/cglm.git
|
||||||
GIT_TAG v0.9.6
|
GIT_TAG v0.9.6
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
# Copyright (c) 2026 Dominic Masters
|
||||||
|
#
|
||||||
|
# This software is released under the MIT License.
|
||||||
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
include(FetchContent)
|
||||||
|
FetchContent_Declare(
|
||||||
|
cmocka
|
||||||
|
GIT_REPOSITORY https://gitlab.com/cmocka/cmocka.git
|
||||||
|
GIT_TAG cmocka-2.0.1
|
||||||
|
)
|
||||||
|
|
||||||
|
FetchContent_MakeAvailable(cmocka)
|
||||||
|
set(cmocka_FOUND ON)
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
# Copyright (c) 2025 Dominic Masters
|
|
||||||
#
|
|
||||||
# This software is released under the MIT License.
|
|
||||||
# https://opensource.org/licenses/MIT
|
|
||||||
|
|
||||||
if(NOT TARGET pspsdk)
|
|
||||||
message(STATUS "Looking for PSPSDK...")
|
|
||||||
|
|
||||||
set(PSPSDK_FOUND FALSE CACHE INTERNAL "PSPSDK found")
|
|
||||||
set(PSPSDK_DOWNLOAD_DIR "${CMAKE_BINARY_DIR}/_pspsdk")
|
|
||||||
set(PSPSDK_SEARCH_ROOTS
|
|
||||||
"${PSPSDK_ROOT}"
|
|
||||||
"$ENV{PSPDEV}"
|
|
||||||
"$ENV{HOME}/pspdev"
|
|
||||||
"/usr/local/pspdev"
|
|
||||||
"/opt/pspdev"
|
|
||||||
"/usr/pspdev"
|
|
||||||
"${PSPSDK_DOWNLOAD_DIR}/pspdev"
|
|
||||||
)
|
|
||||||
|
|
||||||
foreach(root IN LISTS PSPSDK_SEARCH_ROOTS)
|
|
||||||
list(APPEND PSPSDK_BIN_HINTS "${root}/bin")
|
|
||||||
list(APPEND PSPSDK_INCLUDE_HINTS "${root}/include")
|
|
||||||
list(APPEND PSPSDK_LIB_HINTS "${root}/lib")
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
# Find PSP GCC
|
|
||||||
find_program(PSPSDK_PSP_GCC NAMES psp-gcc HINTS ${PSPSDK_BIN_HINTS})
|
|
||||||
|
|
||||||
# If we did not find it, download it.
|
|
||||||
if(NOT PSPSDK_PSP_GCC)
|
|
||||||
message(STATUS "psp-gcc not found in system paths. Downloading PSPSDK tarball...")
|
|
||||||
file(DOWNLOAD
|
|
||||||
"https://github.com/pspdev/pspdev/releases/download/v20251101/pspdev-ubuntu-latest-x86_64.tar.gz"
|
|
||||||
"${CMAKE_BINARY_DIR}/pspsdk.tar.gz"
|
|
||||||
EXPECTED_HASH SHA256=8f8abc2a3008ec1e97c6ba706152a45e4f031c8d10db2102c3c68ce24fa6fcaf
|
|
||||||
SHOW_PROGRESS
|
|
||||||
)
|
|
||||||
|
|
||||||
# Make output dir
|
|
||||||
file(MAKE_DIRECTORY "${PSPSDK_DOWNLOAD_DIR}")
|
|
||||||
|
|
||||||
# Extract the tarball
|
|
||||||
execute_process(
|
|
||||||
COMMAND
|
|
||||||
${CMAKE_COMMAND} -E tar xzf "${CMAKE_BINARY_DIR}/pspsdk.tar.gz"
|
|
||||||
WORKING_DIRECTORY
|
|
||||||
"${PSPSDK_DOWNLOAD_DIR}"
|
|
||||||
RESULT_VARIABLE
|
|
||||||
tar_result
|
|
||||||
)
|
|
||||||
if(NOT tar_result EQUAL 0)
|
|
||||||
message(FATAL_ERROR "Failed to extract PSPSDK tarball")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Retry discovery with extracted fallback
|
|
||||||
find_program(PSPSDK_PSP_GCC NAMES psp-gcc HINTS ${PSPSDK_BIN_HINTS})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(PSPSDK_PSP_GCC)
|
|
||||||
get_filename_component(PSPSDK_BIN_ROOT "${PSPSDK_PSP_GCC}" DIRECTORY)
|
|
||||||
get_filename_component(PSPSDK_ROOT "${PSPSDK_BIN_ROOT}" DIRECTORY)
|
|
||||||
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
|
|
||||||
set(ENV{PSPDEV} "${PSPSDK_ROOT}")
|
|
||||||
set(CMAKE_TOOLCHAIN_FILE "${PSPSDK_ROOT}/psp/share/pspdev.cmake")
|
|
||||||
set(BUILD_PRX ON CACHE BOOL "Build PRX modules")
|
|
||||||
|
|
||||||
include("${PSPSDK_ROOT}/psp/share/pspdev.cmake")
|
|
||||||
set(CMAKE_C_COMPILER ${PSPSDK_BIN_ROOT}/psp-gcc)
|
|
||||||
set(CMAKE_CXX_COMPILER ${PSPSDK_BIN_ROOT}/psp-g++)
|
|
||||||
|
|
||||||
if(NOT DEFINED PSP)
|
|
||||||
message(FATAL_ERROR "PSP environment variable is not set correctly.")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_library(pspsdk INTERFACE IMPORTED)
|
|
||||||
set_target_properties(pspsdk PROPERTIES
|
|
||||||
INTERFACE_INCLUDE_DIRECTORIES "${PSPSDK_INCLUDE_DIR}"
|
|
||||||
INTERFACE_LINK_DIRECTORIES "${PSPSDK_LIB_DIR}"
|
|
||||||
)
|
|
||||||
target_include_directories(pspsdk
|
|
||||||
INTERFACE
|
|
||||||
${PSPDEV}/psp/include
|
|
||||||
${PSPDEV}/psp/sdk/include
|
|
||||||
)
|
|
||||||
target_link_directories(pspsdk
|
|
||||||
INTERFACE
|
|
||||||
${PSPDEV}/lib
|
|
||||||
${PSPDEV}/psp/lib
|
|
||||||
${PSPDEV}/psp/sdk/lib
|
|
||||||
)
|
|
||||||
target_link_libraries(pspsdk INTERFACE
|
|
||||||
pspdebug
|
|
||||||
pspdisplay
|
|
||||||
pspge
|
|
||||||
pspctrl
|
|
||||||
pspgu
|
|
||||||
pspaudio
|
|
||||||
pspaudiolib
|
|
||||||
psputility
|
|
||||||
pspvfpu
|
|
||||||
pspvram
|
|
||||||
psphprm
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
# Copyright (c) 2026 Dominic Masters
|
||||||
|
#
|
||||||
|
# This software is released under the MIT License.
|
||||||
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
include(FetchContent)
|
||||||
|
FetchContent_Declare(
|
||||||
|
stb
|
||||||
|
GIT_REPOSITORY https://github.com/nothings/stb.git
|
||||||
|
)
|
||||||
|
|
||||||
|
# Fetch stb if not already done
|
||||||
|
FetchContent_MakeAvailable(stb)
|
||||||
|
|
||||||
|
# Find the stb_image.h header
|
||||||
|
set(STB_INCLUDE_DIR "${stb_SOURCE_DIR}")
|
||||||
|
set(STB_IMAGE_HEADER "${stb_SOURCE_DIR}/stb_image.h")
|
||||||
|
|
||||||
|
if(EXISTS "${STB_IMAGE_HEADER}")
|
||||||
|
add_library(stb_image INTERFACE)
|
||||||
|
target_include_directories(stb_image INTERFACE "${STB_INCLUDE_DIR}")
|
||||||
|
set(STB_IMAGE_FOUND TRUE)
|
||||||
|
else()
|
||||||
|
set(STB_IMAGE_FOUND FALSE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Standard CMake variables
|
||||||
|
set(STB_IMAGE_INCLUDE_DIRS "${STB_INCLUDE_DIR}")
|
||||||
|
set(STB_IMAGE_LIBRARIES stb_image)
|
||||||
|
|
||||||
|
mark_as_advanced(STB_IMAGE_INCLUDE_DIRS STB_IMAGE_LIBRARIES STB_IMAGE_FOUND)
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
include(FetchContent)
|
||||||
|
|
||||||
|
if(NOT TARGET yyjson)
|
||||||
|
FetchContent_Declare(
|
||||||
|
yyjson
|
||||||
|
GIT_REPOSITORY https://github.com/ibireme/yyjson.git
|
||||||
|
GIT_TAG 0.12.0
|
||||||
|
)
|
||||||
|
FetchContent_MakeAvailable(yyjson)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Provide an imported target if not already available
|
||||||
|
if(NOT TARGET yyjson::yyjson)
|
||||||
|
add_library(yyjson::yyjson ALIAS yyjson)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Mark yyjson as found for find_package compatibility
|
||||||
|
set(yyjson_FOUND TRUE)
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
# Copyright (c) 2026 Dominic Masters
|
||||||
|
#
|
||||||
|
# This software is released under the MIT License.
|
||||||
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
find_package(cmocka REQUIRED)
|
||||||
|
|
||||||
|
# Function to create a test executable from a single .c file
|
||||||
|
function(dusktest TEST_C_FILE)
|
||||||
|
# Create target name from file name
|
||||||
|
get_filename_component(TEST_NAME ${TEST_C_FILE} NAME_WE)
|
||||||
|
|
||||||
|
# Create the executable target
|
||||||
|
add_executable(${TEST_NAME})
|
||||||
|
|
||||||
|
# Setup some compiler definitions.
|
||||||
|
target_compile_definitions(${TEST_NAME} PRIVATE
|
||||||
|
DUSK_TEST_ASSERT=1
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add the test file
|
||||||
|
target_sources(${TEST_NAME} PRIVATE ${TEST_C_FILE})
|
||||||
|
|
||||||
|
# Add sources, both common and test-specific
|
||||||
|
target_include_directories(${TEST_NAME} PUBLIC ${CMAKE_CURRENT_LIST_DIR} ${DUSK_TEST_DIR})
|
||||||
|
|
||||||
|
# Link against DuskCore and cmocka
|
||||||
|
target_link_libraries(${TEST_NAME} PUBLIC ${DUSK_LIBRARY_TARGET_NAME} cmocka)
|
||||||
|
|
||||||
|
# Add as a CTest
|
||||||
|
add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME})
|
||||||
|
endfunction()
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
# Build type: DOL (SD/USB via libfat) or ISO (DVD disc via libogc DVD driver)
|
||||||
|
set(DUSK_DOLPHIN_BUILD_TYPE "DOL" CACHE STRING "Dolphin asset source: DOL (SD/USB) or ISO (DVD disc)")
|
||||||
|
set_property(CACHE DUSK_DOLPHIN_BUILD_TYPE PROPERTY STRINGS "DOL" "ISO")
|
||||||
|
|
||||||
|
# Numeric tokens so #if DUSK_DOLPHIN_BUILD_TYPE == DOL works in C.
|
||||||
|
# DUSK_DOLPHIN_BUILD_TYPE is passed without quotes so it expands to the identifier.
|
||||||
|
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||||
|
DUSK_DOLPHIN
|
||||||
|
DUSK_INPUT_GAMEPAD
|
||||||
|
# DUSK_DISPLAY_WIDTH=640
|
||||||
|
# DUSK_DISPLAY_HEIGHT=480
|
||||||
|
DUSK_DISPLAY_WIDTH=320
|
||||||
|
DUSK_DISPLAY_HEIGHT=240
|
||||||
|
DUSK_DISPLAY_OVERSCAN=16
|
||||||
|
DUSK_THREAD_PTHREAD
|
||||||
|
DOL=1
|
||||||
|
ISO=2
|
||||||
|
DUSK_DOLPHIN_BUILD_TYPE=${DUSK_DOLPHIN_BUILD_TYPE}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Custom compiler flags
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti -fno-exceptions")
|
||||||
|
|
||||||
|
# Disable all warnings
|
||||||
|
target_compile_options(${DUSK_LIBRARY_TARGET_NAME} PRIVATE -w)
|
||||||
|
|
||||||
|
# cglm: fetched at source level via Findcglm.cmake (FetchContent, headers only)
|
||||||
|
find_package(cglm REQUIRED)
|
||||||
|
|
||||||
|
# Pre-create ZLIB::ZLIB so any downstream cmake module that resolves it
|
||||||
|
# (FindZLIB, pkg-config IMPORTED_TARGET Requires processing) gets plain -lz
|
||||||
|
# rather than an unresolvable IMPORTED target that the PPC linker rejects.
|
||||||
|
if(NOT TARGET ZLIB::ZLIB)
|
||||||
|
add_library(ZLIB::ZLIB INTERFACE IMPORTED GLOBAL)
|
||||||
|
set_target_properties(ZLIB::ZLIB PROPERTIES INTERFACE_LINK_LIBRARIES "z")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Mark libzip as found so src/dusk/CMakeLists.txt skips Findlibzip.cmake.
|
||||||
|
# Findlibzip.cmake calls find_package(ZLIB) which can recreate a broken
|
||||||
|
# ZLIB::ZLIB IMPORTED target, bypassing the shim above.
|
||||||
|
set(libzip_FOUND TRUE CACHE BOOL "libzip found (devkitpro portlibs)" FORCE)
|
||||||
|
|
||||||
|
# Locate zip.h in the devkitpro sysroot (respects CMAKE_FIND_ROOT_PATH).
|
||||||
|
find_path(_dusk_zip_inc NAMES zip.h)
|
||||||
|
if(_dusk_zip_inc)
|
||||||
|
target_include_directories(${DUSK_LIBRARY_TARGET_NAME} PRIVATE "${_dusk_zip_inc}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Link libraries.
|
||||||
|
# zip/z/lzma use target_link_options (raw flags) to bypass cmake target
|
||||||
|
# resolution - pkg-config-generated targets for these carry ZLIB::ZLIB in
|
||||||
|
# INTERFACE_LINK_LIBRARIES which breaks the PPC link step.
|
||||||
|
target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PRIVATE
|
||||||
|
cglm
|
||||||
|
m
|
||||||
|
zip
|
||||||
|
bz2
|
||||||
|
zstd
|
||||||
|
z
|
||||||
|
lzma
|
||||||
|
)
|
||||||
|
|
||||||
|
if(DUSK_DOLPHIN_BUILD_TYPE STREQUAL "ISO")
|
||||||
|
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC DUSK_DOLPHIN_BUILD_ISO)
|
||||||
|
else()
|
||||||
|
target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PRIVATE fat)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Postbuild: ELF -> DOL
|
||||||
|
set(DUSK_BINARY_TARGET_NAME_DOL "${DUSK_BUILD_DIR}/Dusk.dol")
|
||||||
|
add_custom_command(TARGET ${DUSK_BINARY_TARGET_NAME} POST_BUILD
|
||||||
|
COMMAND elf2dol
|
||||||
|
"$<TARGET_FILE:${DUSK_BINARY_TARGET_NAME}>"
|
||||||
|
"${DUSK_BINARY_TARGET_NAME_DOL}"
|
||||||
|
COMMENT "Generating ${DUSK_BINARY_TARGET_NAME_DOL} from ${DUSK_BINARY_TARGET_NAME}"
|
||||||
|
)
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
include(cmake/targets/dolphin.cmake)
|
||||||
|
|
||||||
|
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||||
|
DUSK_GAMECUBE
|
||||||
|
)
|
||||||
|
|
||||||
|
# Link libraries
|
||||||
|
target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PRIVATE
|
||||||
|
# bba
|
||||||
|
)
|
||||||
|
|
||||||
|
# ISO post-build: produce NTSC-J, NTSC-U and PAL disc images
|
||||||
|
if(DUSK_DOLPHIN_BUILD_TYPE STREQUAL "ISO")
|
||||||
|
add_custom_command(TARGET ${DUSK_BINARY_TARGET_NAME} POST_BUILD
|
||||||
|
COMMAND ${Python3_EXECUTABLE}
|
||||||
|
"${CMAKE_SOURCE_DIR}/tools/makedolphiniso.py"
|
||||||
|
"GCN"
|
||||||
|
"${DUSK_BINARY_TARGET_NAME_DOL}"
|
||||||
|
"${DUSK_ASSETS_ZIP}"
|
||||||
|
"${DUSK_GAME_NAME}"
|
||||||
|
"${DUSK_BUILD_DIR}"
|
||||||
|
COMMENT "Building GameCube ISO images (NTSC-J, NTSC-U, PAL)"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
# Find link platform-specific libraries
|
||||||
|
set(OpenGL_GL_PREFERENCE LEGACY)
|
||||||
|
find_package(SDL2 REQUIRED)
|
||||||
|
find_library(EGL_LIB EGL REQUIRED)
|
||||||
|
find_library(GL_LIB GL REQUIRED)
|
||||||
|
find_package(OpenGL REQUIRED)
|
||||||
|
|
||||||
|
# Setup endianess at compile time to optimize.
|
||||||
|
include(TestBigEndian)
|
||||||
|
test_big_endian(IS_BIG_ENDIAN)
|
||||||
|
if(IS_BIG_ENDIAN)
|
||||||
|
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||||
|
DUSK_PLATFORM_ENDIAN_BIG
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||||
|
DUSK_PLATFORM_ENDIAN_LITTLE
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Link required libraries.
|
||||||
|
target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PRIVATE
|
||||||
|
SDL2
|
||||||
|
pthread
|
||||||
|
OpenGL::GLES2
|
||||||
|
${GL_LIB}
|
||||||
|
${EGL_LIB}
|
||||||
|
m
|
||||||
|
)
|
||||||
|
|
||||||
|
# Define platform-specific macros.
|
||||||
|
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||||
|
DUSK_SDL2
|
||||||
|
DUSK_OPENGL
|
||||||
|
DUSK_OPENGL_ES
|
||||||
|
DUSK_LINUX
|
||||||
|
DUSK_KNULLI
|
||||||
|
DUSK_DISPLAY_SIZE_DYNAMIC
|
||||||
|
DUSK_DISPLAY_WIDTH_DEFAULT=640
|
||||||
|
DUSK_DISPLAY_HEIGHT_DEFAULT=480
|
||||||
|
DUSK_DISPLAY_SCREEN_HEIGHT=240
|
||||||
|
DUSK_INPUT_KEYBOARD
|
||||||
|
DUSK_INPUT_POINTER
|
||||||
|
DUSK_INPUT_GAMEPAD
|
||||||
|
DUSK_TIME_DYNAMIC
|
||||||
|
)
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
# Find link platform-specific libraries
|
||||||
|
find_package(SDL2 REQUIRED)
|
||||||
|
find_package(OpenGL REQUIRED)
|
||||||
|
# find_package(CURL REQUIRED)
|
||||||
|
|
||||||
|
# Setup endianess at compile time to optimize.
|
||||||
|
include(TestBigEndian)
|
||||||
|
test_big_endian(IS_BIG_ENDIAN)
|
||||||
|
if(IS_BIG_ENDIAN)
|
||||||
|
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||||
|
DUSK_PLATFORM_ENDIAN_BIG
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||||
|
DUSK_PLATFORM_ENDIAN_LITTLE
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Link required libraries.
|
||||||
|
target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||||
|
SDL2
|
||||||
|
pthread
|
||||||
|
OpenGL::GL
|
||||||
|
GL
|
||||||
|
m
|
||||||
|
# CURL::libcurl
|
||||||
|
)
|
||||||
|
|
||||||
|
set(DUSK_BACKTRACE ON CACHE BOOL "Enable backtrace support for assert failures.")
|
||||||
|
|
||||||
|
# Define platform-specific macros.
|
||||||
|
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||||
|
DUSK_SDL2
|
||||||
|
DUSK_OPENGL
|
||||||
|
DUSK_CONSOLE_POSIX
|
||||||
|
# DUSK_OPENGL_LEGACY
|
||||||
|
DUSK_LINUX
|
||||||
|
DUSK_DISPLAY_SIZE_DYNAMIC
|
||||||
|
DUSK_DISPLAY_WIDTH_DEFAULT=640
|
||||||
|
DUSK_DISPLAY_HEIGHT_DEFAULT=480
|
||||||
|
DUSK_DISPLAY_SCREEN_HEIGHT=240
|
||||||
|
DUSK_INPUT_KEYBOARD
|
||||||
|
DUSK_INPUT_POINTER
|
||||||
|
DUSK_INPUT_GAMEPAD
|
||||||
|
DUSK_TIME_DYNAMIC
|
||||||
|
DUSK_NETWORK_IPV6
|
||||||
|
DUSK_THREAD_PTHREAD
|
||||||
|
)
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
set(CMAKE_AR "$ENV{PSPDEV}/bin/psp-ar" CACHE FILEPATH "" FORCE)
|
||||||
|
set(CMAKE_RANLIB "$ENV{PSPDEV}/bin/psp-ranlib" CACHE FILEPATH "" FORCE)
|
||||||
|
set(CMAKE_C_COMPILER_AR "$ENV{PSPDEV}/bin/psp-ar" CACHE FILEPATH "" FORCE)
|
||||||
|
set(CMAKE_C_COMPILER_RANLIB "$ENV{PSPDEV}/bin/psp-ranlib" CACHE FILEPATH "" FORCE)
|
||||||
|
set(CMAKE_C_ARCHIVE_CREATE "$ENV{PSPDEV}/bin/psp-ar qc <TARGET> <LINK_FLAGS> <OBJECTS>")
|
||||||
|
set(CMAKE_C_ARCHIVE_APPEND "$ENV{PSPDEV}/bin/psp-ar q <TARGET> <LINK_FLAGS> <OBJECTS>")
|
||||||
|
set(CMAKE_C_ARCHIVE_FINISH "$ENV{PSPDEV}/bin/psp-ranlib <TARGET>")
|
||||||
|
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION OFF CACHE BOOL "" FORCE)
|
||||||
|
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_C OFF CACHE BOOL "" FORCE)
|
||||||
|
|
||||||
|
find_package(SDL2 REQUIRED)
|
||||||
|
find_package(OpenGL REQUIRED)
|
||||||
|
target_link_libraries(${DUSK_BINARY_TARGET_NAME} PUBLIC
|
||||||
|
${SDL2_LIBRARIES}
|
||||||
|
SDL2
|
||||||
|
pthread
|
||||||
|
OpenGL::GL
|
||||||
|
zip
|
||||||
|
bz2
|
||||||
|
z
|
||||||
|
mbedtls
|
||||||
|
mbedcrypto
|
||||||
|
lzma
|
||||||
|
m
|
||||||
|
|
||||||
|
pspdebug
|
||||||
|
pspdisplay
|
||||||
|
pspge
|
||||||
|
pspctrl
|
||||||
|
pspgu
|
||||||
|
pspaudio
|
||||||
|
pspaudiolib
|
||||||
|
psputility
|
||||||
|
pspvfpu
|
||||||
|
pspvram
|
||||||
|
psphprm
|
||||||
|
pspnet
|
||||||
|
pspnet_inet
|
||||||
|
pspnet_apctl
|
||||||
|
psphttp
|
||||||
|
pspssl
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(${DUSK_BINARY_TARGET_NAME} PRIVATE
|
||||||
|
${SDL2_INCLUDE_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_compile_definitions(${DUSK_BINARY_TARGET_NAME} PUBLIC
|
||||||
|
DUSK_SDL2
|
||||||
|
DUSK_OPENGL
|
||||||
|
DUSK_PSP
|
||||||
|
DUSK_INPUT_GAMEPAD
|
||||||
|
DUSK_PLATFORM_ENDIAN_LITTLE
|
||||||
|
DUSK_OPENGL_LEGACY
|
||||||
|
DUSK_DISPLAY_WIDTH=480
|
||||||
|
DUSK_DISPLAY_HEIGHT=272
|
||||||
|
DUSK_THREAD_PTHREAD
|
||||||
|
)
|
||||||
|
|
||||||
|
# Postbuild, create .pbp file for PSP.
|
||||||
|
create_pbp_file(
|
||||||
|
TARGET "${DUSK_BINARY_TARGET_NAME}"
|
||||||
|
ICON_PATH NULL
|
||||||
|
BACKGROUND_PATH NULL
|
||||||
|
PREVIEW_PATH NULL
|
||||||
|
TITLE "${DUSK_BINARY_TARGET_NAME}"
|
||||||
|
PSAR_PATH ${DUSK_ASSETS_ZIP}
|
||||||
|
VERSION 01.00
|
||||||
|
)
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
# Copyright (c) 2026 Dominic Masters
|
||||||
|
#
|
||||||
|
# This software is released under the MIT License.
|
||||||
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
if(NOT DEFINED ENV{VITASDK})
|
||||||
|
message(FATAL_ERROR "VITASDK environment variable is not set.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include("$ENV{VITASDK}/share/vita.cmake" REQUIRED)
|
||||||
|
|
||||||
|
set(VITA_APP_NAME "Dusk")
|
||||||
|
set(VITA_TITLEID "DUSK00001")
|
||||||
|
set(VITA_VERSION "01.00")
|
||||||
|
|
||||||
|
find_package(SDL2 REQUIRED)
|
||||||
|
|
||||||
|
# Custom flags for cglm
|
||||||
|
set(CGLM_SHARED OFF CACHE BOOL "Build cglm shared" FORCE)
|
||||||
|
set(CGLM_STATIC ON CACHE BOOL "Build cglm static" FORCE)
|
||||||
|
find_package(cglm REQUIRED)
|
||||||
|
|
||||||
|
# Link libraries
|
||||||
|
target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||||
|
${SDL2_LIBRARIES}
|
||||||
|
cglm
|
||||||
|
SDL2
|
||||||
|
SDL2main
|
||||||
|
zip
|
||||||
|
bz2
|
||||||
|
z
|
||||||
|
zstd
|
||||||
|
crypto
|
||||||
|
lzma
|
||||||
|
m
|
||||||
|
pthread
|
||||||
|
stdc++
|
||||||
|
vitaGL
|
||||||
|
mathneon
|
||||||
|
vitashark
|
||||||
|
kubridge_stub
|
||||||
|
SceAppMgr_stub
|
||||||
|
SceAudio_stub
|
||||||
|
SceCtrl_stub
|
||||||
|
SceCommonDialog_stub
|
||||||
|
SceDisplay_stub
|
||||||
|
SceKernelDmacMgr_stub
|
||||||
|
SceGxm_stub
|
||||||
|
SceShaccCg_stub
|
||||||
|
SceSysmodule_stub
|
||||||
|
ScePower_stub
|
||||||
|
SceTouch_stub
|
||||||
|
SceVshBridge_stub
|
||||||
|
SceIofilemgr_stub
|
||||||
|
SceShaccCgExt
|
||||||
|
libtaihen_stub.a
|
||||||
|
|
||||||
|
|
||||||
|
# SceKernel_stub
|
||||||
|
SceAppUtil_stub
|
||||||
|
SceHid_stub
|
||||||
|
SceRtc_stub
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(${DUSK_LIBRARY_TARGET_NAME} PRIVATE
|
||||||
|
${SDL2_INCLUDE_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||||
|
DUSK_SDL2
|
||||||
|
DUSK_OPENGL
|
||||||
|
DUSK_VITA
|
||||||
|
DUSK_INPUT_GAMEPAD
|
||||||
|
DUSK_PLATFORM_ENDIAN_LITTLE
|
||||||
|
DUSK_OPENGL_LEGACY
|
||||||
|
DUSK_DISPLAY_WIDTH=960
|
||||||
|
DUSK_DISPLAY_HEIGHT=544
|
||||||
|
)
|
||||||
|
|
||||||
|
# Post-build: create SELF from the ELF binary (UNSAFE = homebrew, no signing)
|
||||||
|
vita_create_self(${DUSK_BINARY_TARGET_NAME}.self ${DUSK_BINARY_TARGET_NAME} UNSAFE)
|
||||||
|
|
||||||
|
# Post-build: package SELF + assets into a .vpk installable on the Vita
|
||||||
|
vita_create_vpk(${DUSK_BINARY_TARGET_NAME}.vpk ${VITA_TITLEID} ${DUSK_BINARY_TARGET_NAME}.self
|
||||||
|
VERSION ${VITA_VERSION}
|
||||||
|
NAME ${VITA_APP_NAME}
|
||||||
|
FILE ${DUSK_ASSETS_ZIP} dusk.dsk
|
||||||
|
)
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
include(cmake/targets/dolphin.cmake)
|
||||||
|
|
||||||
|
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||||
|
DUSK_WII
|
||||||
|
)
|
||||||
|
|
||||||
|
# Generate Homebrew Channel meta.xml from project identity variables
|
||||||
|
string(TIMESTAMP DUSK_BUILD_DATE "%Y%m%d000000" UTC)
|
||||||
|
configure_file(
|
||||||
|
"${CMAKE_SOURCE_DIR}/docker/dolphin/meta.xml.in"
|
||||||
|
"${DUSK_BUILD_DIR}/meta.xml"
|
||||||
|
@ONLY
|
||||||
|
)
|
||||||
|
|
||||||
|
# ISO post-build: produce NTSC-J, NTSC-U and PAL disc images
|
||||||
|
if(DUSK_DOLPHIN_BUILD_TYPE STREQUAL "ISO")
|
||||||
|
add_custom_command(TARGET ${DUSK_BINARY_TARGET_NAME} POST_BUILD
|
||||||
|
COMMAND ${Python3_EXECUTABLE}
|
||||||
|
"${CMAKE_SOURCE_DIR}/tools/makedolphiniso.py"
|
||||||
|
"WII"
|
||||||
|
"${DUSK_BINARY_TARGET_NAME_DOL}"
|
||||||
|
"${DUSK_ASSETS_ZIP}"
|
||||||
|
"${DUSK_GAME_NAME}"
|
||||||
|
"${DUSK_BUILD_DIR}"
|
||||||
|
COMMENT "Building Wii ISO images (NTSC-J, NTSC-U, PAL)"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
set(CMAKE_SYSTEM_NAME Linux)
|
||||||
|
set(CMAKE_SYSTEM_PROCESSOR aarch64)
|
||||||
|
|
||||||
|
set(CMAKE_C_COMPILER aarch64-linux-gnu-gcc)
|
||||||
|
set(CMAKE_CXX_COMPILER aarch64-linux-gnu-g++)
|
||||||
|
set(CMAKE_ASM_COMPILER aarch64-linux-gnu-gcc)
|
||||||
|
|
||||||
|
set(CMAKE_SYSROOT /)
|
||||||
|
set(CMAKE_C_COMPILER_TARGET aarch64-linux-gnu)
|
||||||
|
set(CMAKE_CXX_COMPILER_TARGET aarch64-linux-gnu)
|
||||||
|
|
||||||
|
set(CMAKE_FIND_ROOT_PATH
|
||||||
|
/usr/aarch64-linux-gnu
|
||||||
|
/usr/lib/aarch64-linux-gnu
|
||||||
|
/usr/include/aarch64-linux-gnu
|
||||||
|
)
|
||||||
|
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
|
||||||
|
|
||||||
|
set(ENV{PKG_CONFIG_LIBDIR} "/usr/lib/aarch64-linux-gnu/pkgconfig:/usr/share/pkgconfig")
|
||||||
|
set(ENV{PKG_CONFIG_PATH} "/usr/lib/aarch64-linux-gnu/pkgconfig")
|
||||||
|
|
||||||
|
set(CMAKE_PREFIX_PATH "/usr/aarch64-linux-gnu;/usr/lib/aarch64-linux-gnu")
|
||||||
|
|
||||||
|
# Optional: helps some Find modules
|
||||||
|
set(SDL2_DIR "/usr/lib/aarch64-linux-gnu/cmake/SDL2" CACHE PATH "")
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
FROM ghcr.io/extremscorner/libogc2
|
||||||
|
WORKDIR /workdir
|
||||||
|
RUN apt update && \
|
||||||
|
dkp-pacman -Syu --noconfirm && \
|
||||||
|
apt install -y python3 python3-pip python3-polib python3-pil python3-dotenv python3-pyqt5 python3-opengl xorriso && \
|
||||||
|
dkp-pacman -S --needed --noconfirm gamecube-sdl2 ppc-liblzma ppc-libzip libogc2 gamecube-tools ppc-libmad ppc-zlib-ng ppc-liblzma ppc-bzip2 ppc-zstd
|
||||||
|
VOLUME ["/workdir"]
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<app version="1">
|
||||||
|
<name>@DUSK_GAME_NAME@</name>
|
||||||
|
<version>@PROJECT_VERSION@</version>
|
||||||
|
<release_date>@DUSK_BUILD_DATE@</release_date>
|
||||||
|
<coder>@DUSK_GAME_AUTHOR@</coder>
|
||||||
|
<short_description>@DUSK_GAME_SHORT_DESCRIPTION@</short_description>
|
||||||
|
<long_description>@DUSK_GAME_LONG_DESCRIPTION@</long_description>
|
||||||
|
<ahb_access/>
|
||||||
|
</app>
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
FROM debian:trixie
|
||||||
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
|
WORKDIR /workdir
|
||||||
|
RUN dpkg --add-architecture arm64 && \
|
||||||
|
apt-get update && \
|
||||||
|
apt-get install -y --no-install-recommends \
|
||||||
|
crossbuild-essential-arm64 \
|
||||||
|
ca-certificates \
|
||||||
|
pkg-config \
|
||||||
|
cmake \
|
||||||
|
make \
|
||||||
|
ninja-build \
|
||||||
|
git \
|
||||||
|
file \
|
||||||
|
python3 \
|
||||||
|
python3-pip \
|
||||||
|
python3-polib \
|
||||||
|
python3-pil \
|
||||||
|
python3-dotenv \
|
||||||
|
python3-pyqt5 \
|
||||||
|
python3-opengl \
|
||||||
|
liblua5.4-dev:arm64 \
|
||||||
|
xz-utils:arm64 \
|
||||||
|
libbz2-dev:arm64 \
|
||||||
|
zlib1g-dev:arm64 \
|
||||||
|
libzip-dev:arm64 \
|
||||||
|
libssl-dev:arm64 \
|
||||||
|
libsdl2-dev:arm64 \
|
||||||
|
liblzma-dev:arm64 \
|
||||||
|
libopengl0:arm64 \
|
||||||
|
libgl1:arm64 \
|
||||||
|
libegl1:arm64 \
|
||||||
|
libgles2:arm64 \
|
||||||
|
libgl1-mesa-dev:arm64 && \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
FROM ubuntu:latest
|
||||||
|
WORKDIR /workdir
|
||||||
|
RUN apt-get update
|
||||||
|
RUN apt-get install -y \
|
||||||
|
build-essential \
|
||||||
|
cmake \
|
||||||
|
python3 \
|
||||||
|
python3-pip \
|
||||||
|
python3-polib \
|
||||||
|
python3-pil \
|
||||||
|
libsdl2-dev \
|
||||||
|
libgl1-mesa-dev \
|
||||||
|
libzip-dev \
|
||||||
|
python3-dotenv \
|
||||||
|
python3-pyqt5 \
|
||||||
|
python3-opengl \
|
||||||
|
xz-utils \
|
||||||
|
liblzma-dev \
|
||||||
|
libbz2-dev \
|
||||||
|
zlib1g-dev \
|
||||||
|
libzip-dev \
|
||||||
|
libbz2-dev \
|
||||||
|
git \
|
||||||
|
libssl-dev
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
FROM pspdev/pspdev:latest
|
||||||
|
WORKDIR /workdir
|
||||||
|
RUN apk add --no-cache \
|
||||||
|
python3 \
|
||||||
|
py3-pip \
|
||||||
|
py3-dotenv
|
||||||
|
VOLUME ["/workdir"]
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
FROM vitasdk/vitasdk:latest
|
||||||
|
WORKDIR /workdir
|
||||||
|
|
||||||
|
# Install vitaGL and its dependencies (vitashark, SceShaccCg) via vdpm
|
||||||
|
RUN which vdpm
|
||||||
|
|
||||||
|
# Install Python (needed for Dusk code generation tools)
|
||||||
|
RUN apk add --no-cache \
|
||||||
|
python3 \
|
||||||
|
py3-pip \
|
||||||
|
py3-dotenv
|
||||||
|
|
||||||
|
VOLUME ["/workdir"]
|
||||||
Executable
+3
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
docker build -t dusk-dolphin -f docker/dolphin/Dockerfile .
|
||||||
|
docker run --rm -v "$(pwd):/workdir" dusk-dolphin /bin/bash -c "./scripts/build-gamecube.sh"
|
||||||
Executable
+3
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
docker build -t dusk-dolphin -f docker/dolphin/Dockerfile .
|
||||||
|
docker run --rm -v "$(pwd):/workdir" dusk-dolphin /bin/bash -c "./scripts/build-gamecube-iso.sh"
|
||||||
Executable
+13
@@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
if [ -z "$DEVKITPRO" ]; then
|
||||||
|
echo "DEVKITPRO environment variable is not set. Please set it to the path of your DEVKITPRO installation."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p build-gamecube-iso
|
||||||
|
cmake -S. -Bbuild-gamecube-iso \
|
||||||
|
-DDUSK_TARGET_SYSTEM=gamecube \
|
||||||
|
-DDUSK_DOLPHIN_BUILD_TYPE=ISO \
|
||||||
|
-DCMAKE_TOOLCHAIN_FILE="$DEVKITPRO/cmake/GameCube.cmake"
|
||||||
|
cd build-gamecube-iso
|
||||||
|
make -j$(nproc) VERBOSE=1
|
||||||
Executable
+14
@@ -0,0 +1,14 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
if [ -z "$DEVKITPRO" ]; then
|
||||||
|
echo "DEVKITPRO environment variable is not set. Please set it to the path of your DEVKITPRO installation."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p build-gamecube
|
||||||
|
cmake -S. -Bbuild-gamecube \
|
||||||
|
-DDUSK_TARGET_SYSTEM=gamecube \
|
||||||
|
-DDUSK_DOLPHIN_BUILD_TYPE=DOL \
|
||||||
|
-DCMAKE_TOOLCHAIN_FILE="$DEVKITPRO/cmake/GameCube.cmake" \
|
||||||
|
-DDKP_OGC_PLATFORM_LIBRARY=libogc2
|
||||||
|
cd build-gamecube
|
||||||
|
make -j$(nproc) VERBOSE=1
|
||||||
Executable
+3
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
docker build -t dusk-knulli -f docker/knulli/Dockerfile .
|
||||||
|
docker run --rm -v "$(pwd):/workdir" dusk-knulli /bin/bash -c "./scripts/build-knulli.sh"
|
||||||
Executable
+24
@@ -0,0 +1,24 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
cmake -S . -B build-knulli -G Ninja \
|
||||||
|
-DDUSK_BUILD_TESTS=ON \
|
||||||
|
-DDUSK_TARGET_SYSTEM=knulli \
|
||||||
|
-DCMAKE_TOOLCHAIN_FILE=./cmake/toolchains/aarch64-linux-gnu.cmake \
|
||||||
|
-DCMAKE_BUILD_TYPE=Release
|
||||||
|
cmake --build build-knulli -- -j$(nproc)
|
||||||
|
|
||||||
|
# Copy necessary libs out
|
||||||
|
mkdir -p ./build-knulli/dusk
|
||||||
|
cp ./build-knulli/Dusk ./build-knulli/dusk/Dusk
|
||||||
|
cp ./build-knulli/dusk.dsk ./build-knulli/dusk/dusk.dsk
|
||||||
|
echo '#!/bin/bash' > build-knulli/dusk/Dusk.sh
|
||||||
|
echo 'cd "$(dirname "$(readlink -f "$0")")"' >> build-knulli/dusk/Dusk.sh
|
||||||
|
echo 'export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$(dirname "$(readlink -f "$0")")' >> build-knulli/dusk/Dusk.sh
|
||||||
|
echo 'export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib/gl4es' >> build-knulli/dusk/Dusk.sh
|
||||||
|
echo 'export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib' >> build-knulli/dusk/Dusk.sh
|
||||||
|
echo '$(dirname "$(readlink -f "$0")")/Dusk' >> build-knulli/dusk/Dusk.sh
|
||||||
|
chmod +x build-knulli/dusk/Dusk.sh
|
||||||
|
cp /usr/lib/aarch64-linux-gnu/liblua5.4.so.0 build-knulli/dusk/
|
||||||
|
# cp /usr/lib/aarch64-linux-gnu/libSDL2-2.0.so.0 build-knulli/dusk/
|
||||||
|
# cp /usr/lib/aarch64-linux-gnu/libGL.so.1 build-knulli/dusk/
|
||||||
|
# cp /usr/lib/aarch64-linux-gnu/libEGL.so.1 build-knulli/dusk/
|
||||||
|
# cp /usr/lib/aarch64-linux-gnu/libGLESv2.so.2 build-knulli/dusk/
|
||||||
Executable
+3
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
docker build -t dusk-linux -f docker/linux/Dockerfile .
|
||||||
|
docker run --rm -v "$(pwd):/workdir" dusk-linux /bin/bash -c "./scripts/build-linux.sh"
|
||||||
Executable
+3
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
cmake -S . -B build-linux -DDUSK_BUILD_TESTS=ON -DDUSK_TARGET_SYSTEM=linux
|
||||||
|
cmake --build build-linux -- -j$(nproc)
|
||||||
Executable
+3
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
docker build -t dusk-psp -f docker/psp/Dockerfile .
|
||||||
|
docker run --rm -v "$(pwd):/workdir" dusk-psp /bin/bash -c "./scripts/build-psp.sh"
|
||||||
Executable
+12
@@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
if [ -z "$PSPDEV" ]; then
|
||||||
|
echo "PSPDEV environment variable is not set. Please set it to the path of your PSP development environment."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p build-psp
|
||||||
|
cd build-psp
|
||||||
|
psp-cmake -DDUSK_TARGET_SYSTEM=psp -DCMAKE_TOOLCHAIN_FILE=$PSPDEV/psp/share/pspdev.cmake -DBUILD_PRX=1 ..
|
||||||
|
make -j$(nproc)
|
||||||
|
# psp-cmake -DDUSK_TARGET_SYSTEM=psp -DCMAKE_TOOLCHAIN_FILE=$PSPDEV/psp/share/pspdev.cmake -DBUILD_PRX=1 -DCMAKE_BUILD_TYPE=Debug ..
|
||||||
|
# make
|
||||||
Executable
+3
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
docker build -t dusk-vita -f docker/vita/Dockerfile .
|
||||||
|
docker run --rm -v "$(pwd):/workdir" dusk-vita /bin/bash -c "./scripts/build-vita.sh"
|
||||||
Executable
+13
@@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
if [ -z "$VITASDK" ]; then
|
||||||
|
echo "VITASDK environment variable is not set. Please set it to the path of your VitaSDK installation."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p build-vita
|
||||||
|
cd build-vita
|
||||||
|
cmake \
|
||||||
|
-DCMAKE_TOOLCHAIN_FILE=$VITASDK/share/vita.toolchain.cmake \
|
||||||
|
-DDUSK_TARGET_SYSTEM=vita \
|
||||||
|
..
|
||||||
|
make -j$(nproc)
|
||||||
Executable
+3
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
docker build -t dusk-dolphin -f docker/dolphin/Dockerfile .
|
||||||
|
docker run --rm -v "$(pwd):/workdir" dusk-dolphin /bin/bash -c "./scripts/build-wii.sh"
|
||||||
Executable
+3
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
docker build -t dusk-dolphin -f docker/dolphin/Dockerfile .
|
||||||
|
docker run --rm -v "$(pwd):/workdir" dusk-dolphin /bin/bash -c "./scripts/build-wii-iso.sh"
|
||||||
Executable
+13
@@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
if [ -z "$DEVKITPRO" ]; then
|
||||||
|
echo "DEVKITPRO environment variable is not set. Please set it to the path of your DEVKITPRO installation."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p build-wii-iso
|
||||||
|
cmake -S. -Bbuild-wii-iso \
|
||||||
|
-DDUSK_TARGET_SYSTEM=wii \
|
||||||
|
-DDUSK_DOLPHIN_BUILD_TYPE=ISO \
|
||||||
|
-DCMAKE_TOOLCHAIN_FILE="$DEVKITPRO/cmake/Wii.cmake"
|
||||||
|
cd build-wii-iso
|
||||||
|
make -j$(nproc) VERBOSE=1
|
||||||
Executable
+14
@@ -0,0 +1,14 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
if [ -z "$DEVKITPRO" ]; then
|
||||||
|
echo "DEVKITPRO environment variable is not set. Please set it to the path of your DEVKITPRO installation."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p build-wii
|
||||||
|
cmake -S. -Bbuild-wii \
|
||||||
|
-DDUSK_TARGET_SYSTEM=wii \
|
||||||
|
-DCMAKE_TOOLCHAIN_FILE="$DEVKITPRO/cmake/Wii.cmake" \
|
||||||
|
-DDUSK_DOLPHIN_BUILD_TYPE=DOL
|
||||||
|
cd build-wii
|
||||||
|
make -j$(nproc) VERBOSE=1
|
||||||
|
mv Dusk.dol boot.dol
|
||||||
Executable
+7
@@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
docker build -t dusk-linux -f docker/linux/Dockerfile .
|
||||||
|
docker run \
|
||||||
|
--rm \
|
||||||
|
-v "${GITHUB_WORKSPACE}:/workdir" \
|
||||||
|
dusk-linux \
|
||||||
|
/bin/bash -c "./scripts/test-linux.sh"
|
||||||
Executable
+6
@@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
rm -rf build-tests
|
||||||
|
cmake -S . -B build-tests -DDUSK_BUILD_TESTS=ON -DDUSK_TARGET_SYSTEM=linux
|
||||||
|
cmake --build build-tests -- -j$(nproc)
|
||||||
|
ctest --output-on-failure --test-dir build-tests
|
||||||
+18
-36
@@ -1,44 +1,26 @@
|
|||||||
# Copyright (c) 2025 Dominic Masters
|
# Copyright (c) 2026 Dominic Masters
|
||||||
#
|
#
|
||||||
# This software is released under the MIT License.
|
# This software is released under the MIT License.
|
||||||
# https://opensource.org/licenses/MIT
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
find_package(cglm REQUIRED)
|
add_subdirectory(dusk)
|
||||||
find_package(libzip REQUIRED)
|
|
||||||
|
|
||||||
# Libs
|
if(DUSK_TARGET_SYSTEM STREQUAL "linux" OR DUSK_TARGET_SYSTEM STREQUAL "knulli")
|
||||||
target_link_libraries(${DUSK_TARGET_NAME}
|
add_subdirectory(dusklinux)
|
||||||
PUBLIC
|
add_subdirectory(dusksdl2)
|
||||||
m
|
add_subdirectory(duskgl)
|
||||||
cglm
|
|
||||||
zip
|
|
||||||
pthread
|
|
||||||
)
|
|
||||||
|
|
||||||
# Includes
|
elseif(DUSK_TARGET_SYSTEM STREQUAL "psp")
|
||||||
target_include_directories(${DUSK_TARGET_NAME}
|
add_subdirectory(duskpsp)
|
||||||
PRIVATE
|
add_subdirectory(dusksdl2)
|
||||||
${CMAKE_CURRENT_LIST_DIR}
|
add_subdirectory(duskgl)
|
||||||
)
|
|
||||||
|
|
||||||
# Sources
|
elseif(DUSK_TARGET_SYSTEM STREQUAL "vita")
|
||||||
target_sources(${DUSK_TARGET_NAME}
|
add_subdirectory(duskvita)
|
||||||
PRIVATE
|
add_subdirectory(dusksdl2)
|
||||||
main.c
|
add_subdirectory(duskgl)
|
||||||
)
|
|
||||||
|
|
||||||
# Subdirs
|
elseif(DUSK_TARGET_SYSTEM STREQUAL "wii" OR DUSK_TARGET_SYSTEM STREQUAL "gamecube")
|
||||||
add_subdirectory(assert)
|
add_subdirectory(duskdolphin)
|
||||||
add_subdirectory(asset)
|
|
||||||
add_subdirectory(debug)
|
endif()
|
||||||
add_subdirectory(display)
|
|
||||||
add_subdirectory(engine)
|
|
||||||
add_subdirectory(error)
|
|
||||||
add_subdirectory(input)
|
|
||||||
add_subdirectory(locale)
|
|
||||||
add_subdirectory(rpg)
|
|
||||||
add_subdirectory(scene)
|
|
||||||
add_subdirectory(thread)
|
|
||||||
add_subdirectory(time)
|
|
||||||
add_subdirectory(ui)
|
|
||||||
add_subdirectory(util)
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2023 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "assert.h"
|
|
||||||
#include "debug/debug.h"
|
|
||||||
|
|
||||||
#ifndef ASSERTIONS_FAKED
|
|
||||||
void assertTrueImpl(
|
|
||||||
const char *file,
|
|
||||||
const int32_t line,
|
|
||||||
const bool x,
|
|
||||||
const char *message
|
|
||||||
) {
|
|
||||||
if(x != true) {
|
|
||||||
debugPrint(
|
|
||||||
"Assertion Failed in %s:%i\n\n%s\n",
|
|
||||||
file,
|
|
||||||
line,
|
|
||||||
message
|
|
||||||
);
|
|
||||||
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void assertFalseImpl(
|
|
||||||
const char *file,
|
|
||||||
const int32_t line,
|
|
||||||
bool x,
|
|
||||||
const char *message
|
|
||||||
) {
|
|
||||||
assertTrueImpl(file, line, !x, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
void assertUnreachableImpl(
|
|
||||||
const char *file,
|
|
||||||
const int32_t line,
|
|
||||||
const char *message
|
|
||||||
) {
|
|
||||||
assertTrueImpl(file, line, false, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
void assertNotNullImpl(
|
|
||||||
const char *file,
|
|
||||||
const int32_t line,
|
|
||||||
const void *pointer,
|
|
||||||
const char *message
|
|
||||||
) {
|
|
||||||
assertTrueImpl(
|
|
||||||
file,
|
|
||||||
line,
|
|
||||||
pointer != NULL,
|
|
||||||
message
|
|
||||||
);
|
|
||||||
|
|
||||||
// Ensure we can touch it
|
|
||||||
volatile char temp;
|
|
||||||
temp = *((char*)pointer);
|
|
||||||
}
|
|
||||||
|
|
||||||
void assertNullImpl(
|
|
||||||
const char *file,
|
|
||||||
const int32_t line,
|
|
||||||
const void *pointer,
|
|
||||||
const char *message
|
|
||||||
) {
|
|
||||||
assertTrueImpl(
|
|
||||||
file,
|
|
||||||
line,
|
|
||||||
pointer == NULL,
|
|
||||||
message
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void assertDeprecatedImpl(
|
|
||||||
const char *file,
|
|
||||||
const int32_t line,
|
|
||||||
const char *message
|
|
||||||
) {
|
|
||||||
assertUnreachableImpl(file, line, message);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -1,143 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2023 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "dusk.h"
|
|
||||||
|
|
||||||
#ifndef ASSERTIONS_FAKED
|
|
||||||
/**
|
|
||||||
* Assert a given value to be true.
|
|
||||||
*
|
|
||||||
* @param file File that the assertion is being made from.
|
|
||||||
* @param line Line that the assertion is being made from.
|
|
||||||
* @param x Value to assert as true.
|
|
||||||
* @param message Message to throw against assertion failure.
|
|
||||||
*/
|
|
||||||
void assertTrueImpl(
|
|
||||||
const char *file,
|
|
||||||
const int32_t line,
|
|
||||||
const bool_t x,
|
|
||||||
const char *message
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Asserts a given statement to be false.
|
|
||||||
*
|
|
||||||
* @param file File that the assertion is being made from.
|
|
||||||
* @param line Line that the assertion is being made from.
|
|
||||||
* @param x Value to assert as false.
|
|
||||||
* @param message Message to throw against assertion failure.
|
|
||||||
*/
|
|
||||||
void assertFalseImpl(
|
|
||||||
const char *file,
|
|
||||||
const int32_t line,
|
|
||||||
const bool_t x,
|
|
||||||
const char *message
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Asserts that a given line of code is unreachable. Essentially a forced
|
|
||||||
* assertion failure, good for "edge cases"
|
|
||||||
*
|
|
||||||
* @param file File that the assertion is being made from.
|
|
||||||
* @param line Line that the assertion is being made from.
|
|
||||||
* @param message Message to throw against assertion failure.
|
|
||||||
*/
|
|
||||||
void assertUnreachableImpl(
|
|
||||||
const char *file,
|
|
||||||
const int32_t line,
|
|
||||||
const char *message
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Assert a given pointer to not point to a null pointer.
|
|
||||||
*
|
|
||||||
* @param file File that the assertion is being made from.
|
|
||||||
* @param line Line that the assertion is being made from.
|
|
||||||
* @param pointer Pointer to assert is not a null pointer.
|
|
||||||
* @param message Message to throw against assertion failure.
|
|
||||||
*/
|
|
||||||
void assertNotNullImpl(
|
|
||||||
const char *file,
|
|
||||||
const int32_t line,
|
|
||||||
const void *pointer,
|
|
||||||
const char *message
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Asserts a given pointer to be a nullptr.
|
|
||||||
*
|
|
||||||
* @param file File that the assertion is being made from.
|
|
||||||
* @param line Line that the assertion is being made from.
|
|
||||||
* @param pointer Pointer to assert is nullptr.
|
|
||||||
* @param message Message to throw against assertion failure.
|
|
||||||
*/
|
|
||||||
void assertNullImpl(
|
|
||||||
const char *file,
|
|
||||||
const int32_t line,
|
|
||||||
const void *pointer,
|
|
||||||
const char *message
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Asserts a function as being deprecated.
|
|
||||||
*
|
|
||||||
* @param file File that the assertion is being made from.
|
|
||||||
* @param line Line that the assertion is being made from.
|
|
||||||
* @param message Message to throw against assertion failure.
|
|
||||||
*/
|
|
||||||
void assertDeprecatedImpl(
|
|
||||||
const char *file,
|
|
||||||
const int32_t line,
|
|
||||||
const char *message
|
|
||||||
);
|
|
||||||
|
|
||||||
void assertMemoryRangeMatchesImpl(
|
|
||||||
const char *file,
|
|
||||||
const int32_t line,
|
|
||||||
const void *start,
|
|
||||||
const void *end,
|
|
||||||
const size_t size,
|
|
||||||
const char *message
|
|
||||||
);
|
|
||||||
|
|
||||||
#define assertTrue(x, message) \
|
|
||||||
assertTrueImpl(__FILE__, __LINE__, x, message)
|
|
||||||
|
|
||||||
#define assertFalse(x, message) \
|
|
||||||
assertFalseImpl(__FILE__, __LINE__, x, message)
|
|
||||||
|
|
||||||
#define assertUnreachable(message) \
|
|
||||||
assertUnreachableImpl(__FILE__, __LINE__, message)
|
|
||||||
|
|
||||||
#define assertNotNull(pointer, message) \
|
|
||||||
assertNotNullImpl(__FILE__, __LINE__, pointer, message)
|
|
||||||
|
|
||||||
#define assertNull(pointer, message) \
|
|
||||||
assertNullImpl(__FILE__, __LINE__, pointer, message)
|
|
||||||
|
|
||||||
#define assertDeprecated(message) \
|
|
||||||
assertDeprecatedImpl(__FILE__, __LINE__, message)
|
|
||||||
|
|
||||||
#define assertStrLenMax(str, len, message) \
|
|
||||||
assertTrue(strlen(str) < len, message)
|
|
||||||
|
|
||||||
#define assertStrLenMin(str, len, message) \
|
|
||||||
assertTrue(strlen(str) >= len, message)
|
|
||||||
|
|
||||||
#else
|
|
||||||
// If assertions are faked, we define the macros to do nothing.
|
|
||||||
#define assertTrue(x, message) ((void)0)
|
|
||||||
#define assertFalse(x, message) ((void)0)
|
|
||||||
#define assertUnreachable(message) ((void)0)
|
|
||||||
#define assertNotNull(pointer, message) ((void)0)
|
|
||||||
#define assertNull(pointer, message) ((void)0)
|
|
||||||
#define assertDeprecated(message) ((void)0)
|
|
||||||
#define assertStrLenMax(str, len, message) ((void)0)
|
|
||||||
#define assertStrLenMin(str, len, message) ((void)0)
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,270 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "asset.h"
|
|
||||||
#include "util/memory.h"
|
|
||||||
#include "util/string.h"
|
|
||||||
#include "assert/assert.h"
|
|
||||||
#include "asset/assettype.h"
|
|
||||||
#include "engine/engine.h"
|
|
||||||
#include "debug/debug.h"
|
|
||||||
|
|
||||||
errorret_t assetInit(void) {
|
|
||||||
memoryZero(&ASSET, sizeof(asset_t));
|
|
||||||
|
|
||||||
// Engine may have been provided the launch path
|
|
||||||
if(ENGINE.argc > 0) {
|
|
||||||
// This first arg is the executable, so on most platforms it is say
|
|
||||||
// "/path/file" or "C:\Path\file.exe". On PSP this would be something
|
|
||||||
// like "ms0:/PSP/GAME/DUSK/EBOOT.PBP" or if we are debugging it is
|
|
||||||
// "host0:/Dusk.prx"
|
|
||||||
|
|
||||||
// Get the directory of the executable
|
|
||||||
char_t buffer[FILENAME_MAX];
|
|
||||||
stringCopy(buffer, ENGINE.argv[0], FILENAME_MAX);
|
|
||||||
size_t len = strlen(buffer);
|
|
||||||
|
|
||||||
// Normalize slashes
|
|
||||||
for(size_t i = 0; i < FILENAME_MAX; i++) {
|
|
||||||
if(buffer[i] == '\0') break;
|
|
||||||
if(buffer[i] == '\\') buffer[i] = '/';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now find the last slash
|
|
||||||
char_t *end = buffer + len - 1;
|
|
||||||
do {
|
|
||||||
end--;
|
|
||||||
if(*end == '/') {
|
|
||||||
*end = '\0';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while(end != buffer);
|
|
||||||
|
|
||||||
|
|
||||||
// Did we find a slash?
|
|
||||||
if(end != buffer) {
|
|
||||||
// We found the directory, set as system path
|
|
||||||
stringCopy(ASSET.systemPath, buffer, FILENAME_MAX);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default system path, intended to be overridden by the platform
|
|
||||||
stringCopy(ASSET.systemPath, ".", FILENAME_MAX);
|
|
||||||
|
|
||||||
// PSP specific time.
|
|
||||||
#if PSP
|
|
||||||
assertTrue(ENGINE.argc >= 1, "PSP requires launch argument.");
|
|
||||||
|
|
||||||
// PSP is given either host0:/Dusk.prx (debugging) OR the PBP file.
|
|
||||||
if(
|
|
||||||
stringEndsWithCaseInsensitive(ENGINE.argv[0], ".pbp") ||
|
|
||||||
ASSET_PBP_READ_PBP_FROM_HOST
|
|
||||||
) {
|
|
||||||
const char_t *pbpPath = (
|
|
||||||
ASSET_PBP_READ_PBP_FROM_HOST ? "./EBOOT.PBP" : ENGINE.argv[0]
|
|
||||||
);
|
|
||||||
ASSET.pbpFile = fopen(pbpPath, "rb");
|
|
||||||
if(ASSET.pbpFile == NULL) {
|
|
||||||
errorThrow("Failed to open PBP file: %s", pbpPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get size of PBP file.
|
|
||||||
if(fseek(ASSET.pbpFile, 0, SEEK_END) != 0) {
|
|
||||||
fclose(ASSET.pbpFile);
|
|
||||||
errorThrow("Failed to seek to end of PBP file : %s", pbpPath);
|
|
||||||
}
|
|
||||||
size_t pbpSize = ftell(ASSET.pbpFile);
|
|
||||||
|
|
||||||
// Rewind to start
|
|
||||||
if(fseek(ASSET.pbpFile, 0, SEEK_SET) != 0) {
|
|
||||||
fclose(ASSET.pbpFile);
|
|
||||||
errorThrow("Failed to seek to start of PBP file : %s", pbpPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the PBP header
|
|
||||||
size_t read = fread(
|
|
||||||
&ASSET.pbpHeader,
|
|
||||||
1,
|
|
||||||
sizeof(assetpbp_t),
|
|
||||||
ASSET.pbpFile
|
|
||||||
);
|
|
||||||
if(read != sizeof(assetpbp_t)) {
|
|
||||||
fclose(ASSET.pbpFile);
|
|
||||||
errorThrow("Failed to read PBP header", pbpPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(memoryCompare(
|
|
||||||
ASSET.pbpHeader.signature,
|
|
||||||
ASSET_PBP_SIGNATURE,
|
|
||||||
sizeof(ASSET_PBP_SIGNATURE)
|
|
||||||
) != 0) {
|
|
||||||
fclose(ASSET.pbpFile);
|
|
||||||
errorThrow("Invalid PBP signature in file: %s", pbpPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we seek to the PSAR offset, we can read the WAD file from there
|
|
||||||
if(fseek(ASSET.pbpFile, ASSET.pbpHeader.psarOffset, SEEK_SET) != 0) {
|
|
||||||
fclose(ASSET.pbpFile);
|
|
||||||
errorThrow("Failed to seek to PSAR offset in PBP file: %s", pbpPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
zip_uint64_t zipPsarOffset = (zip_uint64_t)ASSET.pbpHeader.psarOffset;
|
|
||||||
zip_int64_t zipPsarSize = (zip_int64_t)(
|
|
||||||
pbpSize - ASSET.pbpHeader.psarOffset
|
|
||||||
);
|
|
||||||
|
|
||||||
zip_source_t *psarSource = zip_source_filep_create(
|
|
||||||
ASSET.pbpFile,
|
|
||||||
zipPsarOffset,
|
|
||||||
zipPsarSize,
|
|
||||||
NULL
|
|
||||||
);
|
|
||||||
if(psarSource == NULL) {
|
|
||||||
fclose(ASSET.pbpFile);
|
|
||||||
errorThrow("Failed to create zip source in PBP file: %s", pbpPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSET.zip = zip_open_from_source(
|
|
||||||
psarSource,
|
|
||||||
ZIP_RDONLY,
|
|
||||||
NULL
|
|
||||||
);
|
|
||||||
if(ASSET.zip == NULL) {
|
|
||||||
zip_source_free(psarSource);
|
|
||||||
fclose(ASSET.pbpFile);
|
|
||||||
errorThrow("Failed to open zip from PBP file: %s", pbpPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// Open zip file
|
|
||||||
char_t searchPath[FILENAME_MAX];
|
|
||||||
const char_t **path = ASSET_SEARCH_PATHS;
|
|
||||||
do {
|
|
||||||
sprintf(
|
|
||||||
searchPath,
|
|
||||||
*path,
|
|
||||||
ASSET.systemPath,
|
|
||||||
ASSET_FILE
|
|
||||||
);
|
|
||||||
|
|
||||||
// Try open
|
|
||||||
ASSET.zip = zip_open(searchPath, ZIP_RDONLY, NULL);
|
|
||||||
if(ASSET.zip == NULL) continue;
|
|
||||||
break;// Found!
|
|
||||||
} while(*(++path) != NULL);
|
|
||||||
|
|
||||||
// Did we open the asset?
|
|
||||||
if(ASSET.zip == NULL) errorThrow("Failed to open asset file.");
|
|
||||||
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool_t assetFileExists(const char_t *filename) {
|
|
||||||
assertStrLenMax(filename, FILENAME_MAX, "Filename too long.");
|
|
||||||
|
|
||||||
zip_int64_t idx = zip_name_locate(ASSET.zip, filename, 0);
|
|
||||||
if(idx < 0) return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
errorret_t assetLoad(const char_t *filename, void *output) {
|
|
||||||
assertStrLenMax(filename, FILENAME_MAX, "Filename too long.");
|
|
||||||
assertNotNull(output, "Output pointer cannot be NULL.");
|
|
||||||
|
|
||||||
// Try to open the file
|
|
||||||
zip_file_t *file = zip_fopen(ASSET.zip, filename, 0);
|
|
||||||
if(file == NULL) {
|
|
||||||
errorThrow("Failed to open asset file: %s", filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the header.
|
|
||||||
assetheader_t header;
|
|
||||||
memoryZero(&header, sizeof(assetheader_t));
|
|
||||||
zip_int64_t bytesRead = zip_fread(file, &header, sizeof(assetheader_t));
|
|
||||||
if(bytesRead != sizeof(assetheader_t)) {
|
|
||||||
zip_fclose(file);
|
|
||||||
errorThrow("Failed to read asset header for: %s", filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the asset type based on the header
|
|
||||||
const assettypedef_t *def = NULL;
|
|
||||||
for(uint_fast8_t i = 0; i < ASSET_TYPE_COUNT; i++) {
|
|
||||||
const assettypedef_t *cmp = &ASSET_TYPE_DEFINITIONS[i];
|
|
||||||
if(cmp->header == NULL) continue;
|
|
||||||
|
|
||||||
// strcmp didn't work because it's a fixed char_t[3] I think, or maybe
|
|
||||||
// because of the packed struct?
|
|
||||||
bool_t match = true;
|
|
||||||
for(size_t h = 0; h < ASSET_HEADER_SIZE; h++) {
|
|
||||||
if(header.header[h] == cmp->header[h]) continue;
|
|
||||||
match = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(!match) continue;
|
|
||||||
|
|
||||||
def = cmp;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(def == NULL) {
|
|
||||||
zip_fclose(file);
|
|
||||||
errorThrow("Unknown asset type for file: %s", filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We found the asset type, now load the asset data
|
|
||||||
switch(def->loadStrategy) {
|
|
||||||
case ASSET_LOAD_STRAT_ENTIRE:
|
|
||||||
assertNotNull(def->entire, "Asset load function cannot be NULL.");
|
|
||||||
void *data = memoryAllocate(def->dataSize);
|
|
||||||
bytesRead = zip_fread(file, data, def->dataSize);
|
|
||||||
if(bytesRead == 0 || bytesRead > def->dataSize) {
|
|
||||||
memoryFree(data);
|
|
||||||
zip_fclose(file);
|
|
||||||
errorThrow("Failed to read asset data for file: %s", filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close the file now we have the data
|
|
||||||
zip_fclose(file);
|
|
||||||
|
|
||||||
// Pass to the asset type loader
|
|
||||||
errorret_t ret = def->entire(data, output);
|
|
||||||
memoryFree(data);
|
|
||||||
errorChain(ret);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ASSET_LOAD_STRAT_CUSTOM:
|
|
||||||
assertNotNull(def->custom, "Asset load function cannot be NULL.");
|
|
||||||
assetcustom_t customData = {
|
|
||||||
.zipFile = file,
|
|
||||||
.output = output
|
|
||||||
};
|
|
||||||
errorChain(def->custom(customData));
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
assertUnreachable("Unknown asset load strategy.");
|
|
||||||
}
|
|
||||||
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
void assetDispose(void) {
|
|
||||||
if(ASSET.zip != NULL) {
|
|
||||||
zip_close(ASSET.zip);
|
|
||||||
ASSET.zip = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if PSP
|
|
||||||
if(ASSET.pbpFile != NULL) {
|
|
||||||
fclose(ASSET.pbpFile);
|
|
||||||
ASSET.pbpFile = NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "error/error.h"
|
|
||||||
#include "assettype.h"
|
|
||||||
|
|
||||||
#if ASSET_TYPE == wad
|
|
||||||
#if PSP
|
|
||||||
#define ASSET_PBP_READ_PBP_FROM_HOST 0
|
|
||||||
#define ASSET_PBP_SIGNATURE_SIZE 4
|
|
||||||
#define ASSET_PBP_SIGNATURE "\0PBP"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char_t signature[ASSET_PBP_SIGNATURE_SIZE];
|
|
||||||
uint32_t version;
|
|
||||||
uint32_t sfoOffset;
|
|
||||||
uint32_t icon0Offset;
|
|
||||||
uint32_t icon1Offset;
|
|
||||||
uint32_t pic0Offset;
|
|
||||||
uint32_t pic1Offset;
|
|
||||||
uint32_t snd0Offset;
|
|
||||||
uint32_t pspOffset;
|
|
||||||
uint32_t psarOffset;
|
|
||||||
} assetpbp_t;
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
#error "Unsupported ASSET_TYPE"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define ASSET_FILE "dusk.dsk"
|
|
||||||
#define ASSET_HEADER_SIZE 3
|
|
||||||
|
|
||||||
static const char_t *ASSET_SEARCH_PATHS[] = {
|
|
||||||
"%s/%s",
|
|
||||||
"%s",
|
|
||||||
"../%s",
|
|
||||||
"../../%s",
|
|
||||||
"data/%s",
|
|
||||||
"../data/%s",
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
|
||||||
typedef struct {
|
|
||||||
char_t header[ASSET_HEADER_SIZE];
|
|
||||||
} assetheader_t;
|
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
zip_t *zip;
|
|
||||||
char_t systemPath[FILENAME_MAX];
|
|
||||||
uint8_t assetCount;
|
|
||||||
|
|
||||||
#if PSP
|
|
||||||
FILE *pbpFile;
|
|
||||||
assetpbp_t pbpHeader;
|
|
||||||
#endif
|
|
||||||
} asset_t;
|
|
||||||
|
|
||||||
static asset_t ASSET;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the asset system.
|
|
||||||
*/
|
|
||||||
errorret_t assetInit(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if an asset file exists.
|
|
||||||
*
|
|
||||||
* @param filename The filename of the asset to check.
|
|
||||||
* @return true if the asset file exists, false otherwise.
|
|
||||||
*/
|
|
||||||
bool_t assetFileExists(const char_t *filename);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads an asset by its filename, the output type depends on the asset type.
|
|
||||||
*
|
|
||||||
* @param filename The filename of the asset to retrieve.
|
|
||||||
* @param output The output pointer to store the loaded asset data.
|
|
||||||
* @return An error code if the asset could not be loaded.
|
|
||||||
*/
|
|
||||||
errorret_t assetLoad(const char_t *filename, void *output);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disposes/cleans up the asset system.
|
|
||||||
*/
|
|
||||||
void assetDispose(void);
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "type/assetpaletteimage.h"
|
|
||||||
#include "type/assetalphaimage.h"
|
|
||||||
#include "type/assetlanguage.h"
|
|
||||||
#include "type/assetmap.h"
|
|
||||||
#include "type/assetchunk.h"
|
|
||||||
#include <zip.h>
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
ASSET_TYPE_NULL,
|
|
||||||
|
|
||||||
ASSET_TYPE_PALETTE_IMAGE,
|
|
||||||
ASSET_TYPE_ALPHA_IMAGE,
|
|
||||||
ASSET_TYPE_LANGUAGE,
|
|
||||||
ASSET_TYPE_MAP,
|
|
||||||
ASSET_TYPE_CHUNK,
|
|
||||||
|
|
||||||
ASSET_TYPE_COUNT,
|
|
||||||
} assettype_t;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
ASSET_LOAD_STRAT_ENTIRE,
|
|
||||||
ASSET_LOAD_STRAT_CUSTOM
|
|
||||||
} assetloadstrat_t;
|
|
||||||
|
|
||||||
typedef struct assetcustom_s {
|
|
||||||
zip_file_t *zipFile;
|
|
||||||
void *output;
|
|
||||||
} assetcustom_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
const char_t *header;
|
|
||||||
const size_t dataSize;
|
|
||||||
const assetloadstrat_t loadStrategy;
|
|
||||||
union {
|
|
||||||
errorret_t (*entire)(void *data, void *output);
|
|
||||||
errorret_t (*custom)(assetcustom_t custom);
|
|
||||||
};
|
|
||||||
} assettypedef_t;
|
|
||||||
|
|
||||||
static const assettypedef_t ASSET_TYPE_DEFINITIONS[ASSET_TYPE_COUNT] = {
|
|
||||||
[ASSET_TYPE_NULL] = {
|
|
||||||
0
|
|
||||||
},
|
|
||||||
|
|
||||||
[ASSET_TYPE_PALETTE_IMAGE] = {
|
|
||||||
.header = "DPI",
|
|
||||||
.loadStrategy = ASSET_LOAD_STRAT_ENTIRE,
|
|
||||||
.dataSize = sizeof(assetpaletteimage_t),
|
|
||||||
.entire = assetPaletteImageLoad
|
|
||||||
},
|
|
||||||
|
|
||||||
[ASSET_TYPE_ALPHA_IMAGE] = {
|
|
||||||
.header = "DAI",
|
|
||||||
.loadStrategy = ASSET_LOAD_STRAT_ENTIRE,
|
|
||||||
.dataSize = sizeof(assetalphaimage_t),
|
|
||||||
.entire = assetAlphaImageLoad
|
|
||||||
},
|
|
||||||
|
|
||||||
[ASSET_TYPE_LANGUAGE] = {
|
|
||||||
.header = "DLF",
|
|
||||||
.loadStrategy = ASSET_LOAD_STRAT_CUSTOM,
|
|
||||||
.custom = assetLanguageHandler
|
|
||||||
},
|
|
||||||
|
|
||||||
[ASSET_TYPE_MAP] = {
|
|
||||||
.header = "DMF",
|
|
||||||
.loadStrategy = ASSET_LOAD_STRAT_ENTIRE,
|
|
||||||
.dataSize = sizeof(1),
|
|
||||||
.entire = assetMapLoad
|
|
||||||
},
|
|
||||||
|
|
||||||
[ASSET_TYPE_CHUNK] = {
|
|
||||||
.header = "DCF",
|
|
||||||
.loadStrategy = ASSET_LOAD_STRAT_CUSTOM,
|
|
||||||
.custom = assetChunkLoad
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
# Copyright (c) 2025 Dominic Masters
|
|
||||||
#
|
|
||||||
# This software is released under the MIT License.
|
|
||||||
# https://opensource.org/licenses/MIT
|
|
||||||
|
|
||||||
# Sources
|
|
||||||
target_sources(${DUSK_TARGET_NAME}
|
|
||||||
PRIVATE
|
|
||||||
assetalphaimage.c
|
|
||||||
assetpaletteimage.c
|
|
||||||
assetlanguage.c
|
|
||||||
assetmap.c
|
|
||||||
assetchunk.c
|
|
||||||
)
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "assetalphaimage.h"
|
|
||||||
#include "assert/assert.h"
|
|
||||||
#include "display/texture.h"
|
|
||||||
|
|
||||||
errorret_t assetAlphaImageLoad(void *data, void *output) {
|
|
||||||
assertNotNull(data, "Data pointer cannot be NULL.");
|
|
||||||
assertNotNull(output, "Output pointer cannot be NULL.");
|
|
||||||
|
|
||||||
assetalphaimage_t *dataPtr = (assetalphaimage_t *)data;
|
|
||||||
texture_t *outputPtr = (texture_t *)output;
|
|
||||||
|
|
||||||
textureInit(
|
|
||||||
outputPtr,
|
|
||||||
dataPtr->width,
|
|
||||||
dataPtr->height,
|
|
||||||
TEXTURE_FORMAT_ALPHA,
|
|
||||||
(texturedata_t){ .alpha = { .data = dataPtr->pixels } }
|
|
||||||
);
|
|
||||||
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "error/error.h"
|
|
||||||
|
|
||||||
#define ASSET_ALPHA_IMAGE_WIDTH_MAX 256
|
|
||||||
#define ASSET_ALPHA_IMAGE_HEIGHT_MAX 256
|
|
||||||
#define ASSET_ALPHA_IMAGE_SIZE_MAX ( \
|
|
||||||
ASSET_ALPHA_IMAGE_WIDTH_MAX * ASSET_ALPHA_IMAGE_HEIGHT_MAX \
|
|
||||||
)
|
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
|
||||||
typedef struct {
|
|
||||||
uint32_t width;
|
|
||||||
uint32_t height;
|
|
||||||
uint8_t pixels[ASSET_ALPHA_IMAGE_SIZE_MAX];
|
|
||||||
} assetalphaimage_t;
|
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads an alpha image asset from the given asset structure. The asset must
|
|
||||||
* be of type ASSET_TYPE_ALPHA_IMAGE and must be loaded.
|
|
||||||
*
|
|
||||||
* @param asset The asset to load the alpha image from.
|
|
||||||
* @return An error code.
|
|
||||||
*/
|
|
||||||
errorret_t assetAlphaImageLoad(void *data, void *output);
|
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "asset/asset.h"
|
|
||||||
#include "assert/assert.h"
|
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
|
||||||
typedef struct {
|
|
||||||
uint32_t tileCount;
|
|
||||||
uint8_t modelCount;
|
|
||||||
} assetchunkheader_t;
|
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
|
||||||
typedef struct {
|
|
||||||
tile_t tile;
|
|
||||||
} assetchunktiledata_t;
|
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
|
||||||
typedef struct {
|
|
||||||
uint32_t vertexCount;
|
|
||||||
} assetchunkmodelheader_t;
|
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
errorret_t assetChunkLoad(assetcustom_t custom) {
|
|
||||||
assertNotNull(custom.output, "Output pointer cannot be NULL");
|
|
||||||
assertNotNull(custom.zipFile, "Zip file pointer cannot be NULL");
|
|
||||||
|
|
||||||
chunk_t *chunk = (chunk_t *)custom.output;
|
|
||||||
printf(
|
|
||||||
"Loading chunk asset at position (%d, %d, %d)...\n",
|
|
||||||
chunk->position.x,
|
|
||||||
chunk->position.y,
|
|
||||||
chunk->position.z
|
|
||||||
);
|
|
||||||
|
|
||||||
// Read header
|
|
||||||
assetchunkheader_t header;
|
|
||||||
size_t bytesRead = zip_fread(
|
|
||||||
custom.zipFile, &header, sizeof(assetchunkheader_t)
|
|
||||||
);
|
|
||||||
if(bytesRead != sizeof(assetchunkheader_t)) {
|
|
||||||
zip_fclose(custom.zipFile);
|
|
||||||
errorThrow("Failed to read chunk asset header.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(header.tileCount != CHUNK_TILE_COUNT) {
|
|
||||||
zip_fclose(custom.zipFile);
|
|
||||||
errorThrow(
|
|
||||||
"Chunk asset has invalid tile count: %d (expected %d).",
|
|
||||||
header.tileCount,
|
|
||||||
CHUNK_TILE_COUNT
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(header.modelCount > CHUNK_MESH_COUNT_MAX) {
|
|
||||||
zip_fclose(custom.zipFile);
|
|
||||||
errorThrow(
|
|
||||||
"Chunk asset has too many models: %d (max %d).",
|
|
||||||
header.modelCount,
|
|
||||||
CHUNK_MESH_COUNT_MAX
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
chunk->meshCount = header.modelCount;
|
|
||||||
|
|
||||||
// Read tile data
|
|
||||||
bytesRead = zip_fread(
|
|
||||||
custom.zipFile,
|
|
||||||
chunk->tiles,
|
|
||||||
sizeof(assetchunktiledata_t) * header.tileCount
|
|
||||||
);
|
|
||||||
if(bytesRead != sizeof(assetchunktiledata_t) * header.tileCount) {
|
|
||||||
zip_fclose(custom.zipFile);
|
|
||||||
errorThrow("Failed to read chunk tile data.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// For each model...
|
|
||||||
uint32_t vertexIndex = 0;
|
|
||||||
for(uint8_t i = 0; i < header.modelCount; i++) {
|
|
||||||
assetchunkmodelheader_t modelHeader;
|
|
||||||
bytesRead = zip_fread(
|
|
||||||
custom.zipFile, &modelHeader, sizeof(assetchunkmodelheader_t)
|
|
||||||
);
|
|
||||||
if(bytesRead != sizeof(assetchunkmodelheader_t)) {
|
|
||||||
zip_fclose(custom.zipFile);
|
|
||||||
errorThrow("Failed to read chunk model header.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(
|
|
||||||
vertexIndex + modelHeader.vertexCount >
|
|
||||||
CHUNK_VERTEX_COUNT_MAX
|
|
||||||
) {
|
|
||||||
zip_fclose(custom.zipFile);
|
|
||||||
errorThrow("Chunk model vertex count exceeds maximum.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read vertex data.
|
|
||||||
bytesRead = zip_fread(
|
|
||||||
custom.zipFile,
|
|
||||||
&chunk->vertices[vertexIndex],
|
|
||||||
sizeof(meshvertex_t) * modelHeader.vertexCount
|
|
||||||
);
|
|
||||||
if(bytesRead != sizeof(meshvertex_t) * modelHeader.vertexCount) {
|
|
||||||
zip_fclose(custom.zipFile);
|
|
||||||
errorThrow("Failed to read chunk model vertex data.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Init the mesh
|
|
||||||
mesh_t *mesh = &chunk->meshes[i];
|
|
||||||
meshInit(
|
|
||||||
mesh,
|
|
||||||
MESH_PRIMITIVE_TRIANGLES,
|
|
||||||
modelHeader.vertexCount,
|
|
||||||
&chunk->vertices[vertexIndex]
|
|
||||||
);
|
|
||||||
|
|
||||||
vertexIndex += modelHeader.vertexCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "error/error.h"
|
|
||||||
#include "rpg/world/chunk.h"
|
|
||||||
|
|
||||||
typedef struct assetcustom_s assetcustom_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles loading of chunk data from a chunk asset file.
|
|
||||||
*
|
|
||||||
* @param custom The custom asset loading parameters.
|
|
||||||
* @return An error code.
|
|
||||||
*/
|
|
||||||
errorret_t assetChunkLoad(assetcustom_t custom);
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "asset/asset.h"
|
|
||||||
#include "assert/assert.h"
|
|
||||||
#include "locale/localemanager.h"
|
|
||||||
|
|
||||||
errorret_t assetLanguageHandler(assetcustom_t custom) {
|
|
||||||
assertNotNull(custom.zipFile, "Custom asset zip file cannot be NULL");
|
|
||||||
assertNotNull(custom.output, "Custom asset output cannot be NULL");
|
|
||||||
|
|
||||||
assetlanguage_t *lang = (assetlanguage_t *)custom.output;
|
|
||||||
errorChain(assetLanguageInit(lang, custom.zipFile));
|
|
||||||
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
errorret_t assetLanguageInit(
|
|
||||||
assetlanguage_t *lang,
|
|
||||||
zip_file_t *zipFile
|
|
||||||
) {
|
|
||||||
assertNotNull(lang, "Language asset cannot be NULL");
|
|
||||||
assertNotNull(zipFile, "Zip file cannot be NULL");
|
|
||||||
assertNull(lang->zip, "Language asset zip file must be NULL.");
|
|
||||||
// I want this but ubuntu isn't compiling with it right now.
|
|
||||||
// assertTrue(zip_file_is_seekable(zipFile), "Language file must be seekable.");
|
|
||||||
|
|
||||||
// We now own the zip file handle.
|
|
||||||
lang->zip = zipFile;
|
|
||||||
|
|
||||||
// Read in the header.
|
|
||||||
zip_int64_t bytesRead = zip_fread(
|
|
||||||
lang->zip,
|
|
||||||
&lang->header,
|
|
||||||
sizeof(assetlanguageheader_t)
|
|
||||||
);
|
|
||||||
if(bytesRead != sizeof(assetlanguageheader_t)) {
|
|
||||||
zip_fclose(lang->zip);
|
|
||||||
errorThrow("Failed to read language asset header.");
|
|
||||||
}
|
|
||||||
|
|
||||||
lang->chunksOffset = zip_ftell(lang->zip);
|
|
||||||
if(lang->chunksOffset <= 0) {
|
|
||||||
zip_fclose(lang->zip);
|
|
||||||
errorThrow("Failed to get language asset chunks offset.");
|
|
||||||
}
|
|
||||||
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
errorret_t assetLanguageRead(
|
|
||||||
assetlanguage_t *lang,
|
|
||||||
const uint32_t key,
|
|
||||||
char_t *buffer,
|
|
||||||
const uint32_t bufferSize,
|
|
||||||
uint32_t *outLength
|
|
||||||
) {
|
|
||||||
assertNotNull(lang, "Language asset cannot be NULL");
|
|
||||||
assertNotNull(lang->zip, "Language asset zip file cannot be NULL");
|
|
||||||
assertTrue(key < LANG_KEY_COUNT, "Language key out of bounds.");
|
|
||||||
|
|
||||||
// Find the string entry
|
|
||||||
assetlanguagestring_t *str = &lang->header.strings[LANG_MAP_TEST];
|
|
||||||
|
|
||||||
// If buffer is NULL, return the string length
|
|
||||||
if(buffer == NULL) {
|
|
||||||
assertNotNull(outLength, "Output length pointer cannot be NULL.");
|
|
||||||
*outLength = str->length;
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure buffer is large enough
|
|
||||||
assertTrue(
|
|
||||||
bufferSize >= str->length + 1,
|
|
||||||
"Provided buffer is too small for language string."
|
|
||||||
);
|
|
||||||
|
|
||||||
// Determine the file position
|
|
||||||
zip_int64_t seekTo = lang->chunksOffset + (
|
|
||||||
(str->chunk * ASSET_LANG_CHUNK_CHAR_COUNT) + str->offset
|
|
||||||
);
|
|
||||||
|
|
||||||
// Seek
|
|
||||||
zip_int64_t result = zip_fseek(lang->zip, seekTo, SEEK_SET);
|
|
||||||
if(result != 0) {
|
|
||||||
errorThrow("Failed to seek to language string in asset.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read
|
|
||||||
zip_int64_t readTest = zip_fread(lang->zip, buffer, str->length);
|
|
||||||
if(readTest != str->length) {
|
|
||||||
errorThrow("Failed to read test string from language asset.");
|
|
||||||
}
|
|
||||||
buffer[str->length] = '\0';
|
|
||||||
|
|
||||||
// Set str length if requested
|
|
||||||
if(outLength != NULL) *outLength = str->length;
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
void assetLanguageDispose(assetlanguage_t *lang) {
|
|
||||||
assertNotNull(lang, "Language asset cannot be NULL");
|
|
||||||
|
|
||||||
if(lang->zip) {
|
|
||||||
zip_fclose(lang->zip);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "locale/language/keys.h"
|
|
||||||
#include "error/error.h"
|
|
||||||
#include <zip.h>
|
|
||||||
|
|
||||||
#define ASSET_LANG_CHUNK_CHAR_COUNT 6 * 1024 // 6 KB per chunk
|
|
||||||
#define ASSET_LANG_CHUNK_CACHE 4 // Number of chunks to cache in memory
|
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
|
||||||
typedef char assetlanguagechunk_t[ASSET_LANG_CHUNK_CHAR_COUNT];
|
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
|
||||||
typedef struct {
|
|
||||||
uint32_t chunk;
|
|
||||||
uint32_t offset;
|
|
||||||
uint32_t length;
|
|
||||||
} assetlanguagestring_t;
|
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
|
||||||
typedef struct {
|
|
||||||
assetlanguagestring_t strings[LANG_KEY_COUNT];
|
|
||||||
} assetlanguageheader_t;
|
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
zip_file_t *zip;
|
|
||||||
assetlanguageheader_t header;
|
|
||||||
zip_int64_t chunksOffset;
|
|
||||||
|
|
||||||
// Chunk cache
|
|
||||||
assetlanguagechunk_t chunks[ASSET_LANG_CHUNK_CACHE];
|
|
||||||
uint32_t chunkIndices[ASSET_LANG_CHUNK_CACHE];
|
|
||||||
} assetlanguage_t;
|
|
||||||
|
|
||||||
typedef struct assetcustom_s assetcustom_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Receiving function from the asset manager to handle language assets.
|
|
||||||
*
|
|
||||||
* @param custom Custom asset loading data.
|
|
||||||
* @return Error code.
|
|
||||||
*/
|
|
||||||
errorret_t assetLanguageHandler(assetcustom_t custom);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes a language asset and loads the header data into memory.
|
|
||||||
*
|
|
||||||
* @param lang Language asset to initialize.
|
|
||||||
* @param zipFile Zip file handle for the language asset.
|
|
||||||
* @return Error code.
|
|
||||||
*/
|
|
||||||
errorret_t assetLanguageInit(assetlanguage_t *lang, zip_file_t *zipFile);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads a string from the language asset into the provided buffer.
|
|
||||||
*
|
|
||||||
* @param lang Language asset to read from.
|
|
||||||
* @param key Language key to read.
|
|
||||||
* @param buffer Buffer to read the string into.
|
|
||||||
* @param bufferSize Size of the provided buffer.
|
|
||||||
* @param outLength Pointer to store the length of the string read.
|
|
||||||
* @return Error code.
|
|
||||||
*/
|
|
||||||
errorret_t assetLanguageRead(
|
|
||||||
assetlanguage_t *lang,
|
|
||||||
const uint32_t key,
|
|
||||||
char_t *buffer,
|
|
||||||
const uint32_t bufferSize,
|
|
||||||
uint32_t *outLength
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disposes of language asset resources.
|
|
||||||
*
|
|
||||||
* @param custom Custom asset loading data.
|
|
||||||
* @return Error code.
|
|
||||||
*/
|
|
||||||
void assetLanguageDispose(assetlanguage_t *lang);
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "asset/asset.h"
|
|
||||||
#include "assert/assert.h"
|
|
||||||
#include "util/memory.h"
|
|
||||||
|
|
||||||
errorret_t assetMapLoad(void *data, void *output) {
|
|
||||||
assertNotNull(data, "Data cannot be NULL");
|
|
||||||
assertNotNull(output, "Output cannot be NULL");
|
|
||||||
|
|
||||||
assertUnreachable("map not finished");
|
|
||||||
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "error/error.h"
|
|
||||||
#include "rpg/world/map.h"
|
|
||||||
#include "display/mesh/mesh.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads a map asset from the given data pointer into the output map structure.
|
|
||||||
*
|
|
||||||
* @param data Pointer to the raw assetmap_t data.
|
|
||||||
* @param output Pointer to the map_t to load the map into.
|
|
||||||
* @return An error code.
|
|
||||||
*/
|
|
||||||
errorret_t assetMapLoad(void *data, void *output);
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "assetpaletteimage.h"
|
|
||||||
#include "assert/assert.h"
|
|
||||||
#include "display/texture.h"
|
|
||||||
|
|
||||||
errorret_t assetPaletteImageLoad(void *data, void *output) {
|
|
||||||
assertNotNull(data, "Data pointer cannot be NULL.");
|
|
||||||
assertNotNull(output, "Output pointer cannot be NULL.");
|
|
||||||
|
|
||||||
assetpaletteimage_t *assetData = (assetpaletteimage_t *)data;
|
|
||||||
texture_t *texture = (texture_t *)output;
|
|
||||||
|
|
||||||
textureInit(
|
|
||||||
texture,
|
|
||||||
assetData->width,
|
|
||||||
assetData->height,
|
|
||||||
TEXTURE_FORMAT_PALETTE,
|
|
||||||
(texturedata_t){
|
|
||||||
.palette = {
|
|
||||||
.palette = assetData->paletteIndex,
|
|
||||||
.data = assetData->palette
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "error/error.h"
|
|
||||||
|
|
||||||
#define ASSET_PALETTE_IMAGE_WIDTH_MAX 128
|
|
||||||
#define ASSET_PALETTE_IMAGE_HEIGHT_MAX 128
|
|
||||||
#define ASSET_PALETTE_IMAGE_SIZE_MAX ( \
|
|
||||||
ASSET_PALETTE_IMAGE_WIDTH_MAX * ASSET_PALETTE_IMAGE_HEIGHT_MAX \
|
|
||||||
)
|
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
|
||||||
typedef struct {
|
|
||||||
uint32_t width;
|
|
||||||
uint32_t height;
|
|
||||||
uint8_t paletteIndex;
|
|
||||||
uint8_t palette[ASSET_PALETTE_IMAGE_SIZE_MAX];
|
|
||||||
} assetpaletteimage_t;
|
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads a palette image asset from the given data pointer into the output
|
|
||||||
* texture.
|
|
||||||
*
|
|
||||||
* @param data Pointer to the raw assetpaletteimage_t data.
|
|
||||||
* @param output Pointer to the texture_t to load the image into.
|
|
||||||
* @return An error code.
|
|
||||||
*/
|
|
||||||
errorret_t assetPaletteImageLoad(void *data, void *output);
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "debug.h"
|
|
||||||
|
|
||||||
void debugPrint(const char_t *message, ...) {
|
|
||||||
va_list args;
|
|
||||||
va_start(args, message);
|
|
||||||
vprintf(message, args);
|
|
||||||
va_end(args);
|
|
||||||
|
|
||||||
// For the time being just use standard printing functions.
|
|
||||||
printf(message, args);
|
|
||||||
|
|
||||||
#if PSP
|
|
||||||
FILE *file = fopen("ms0:/PSP/GAME/Dusk/debug.log", "a");
|
|
||||||
if(file) {
|
|
||||||
va_start(args, message);
|
|
||||||
vfprintf(file, message, args);
|
|
||||||
va_end(args);
|
|
||||||
fclose(file);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "dusk.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prints a debug message to the debug console.
|
|
||||||
*
|
|
||||||
* @param message The message format string.
|
|
||||||
* @param ... Additional arguments for the format string.
|
|
||||||
*/
|
|
||||||
void debugPrint(const char_t *message, ...);
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
# Copyright (c) 2025 Dominic Masters
|
|
||||||
#
|
|
||||||
# This software is released under the MIT License.
|
|
||||||
# https://opensource.org/licenses/MIT
|
|
||||||
|
|
||||||
# Sources
|
|
||||||
target_sources(${DUSK_TARGET_NAME}
|
|
||||||
PRIVATE
|
|
||||||
display.c
|
|
||||||
framebuffer.c
|
|
||||||
camera.c
|
|
||||||
screen.c
|
|
||||||
texture.c
|
|
||||||
spritebatch.c
|
|
||||||
)
|
|
||||||
|
|
||||||
# Subdirectories
|
|
||||||
add_subdirectory(mesh)
|
|
||||||
add_subdirectory(palette)
|
|
||||||
add_subdirectory(tileset)
|
|
||||||
|
|
||||||
if(DUSK_TARGET_SYSTEM STREQUAL "linux")
|
|
||||||
target_compile_definitions(${DUSK_TARGET_NAME}
|
|
||||||
PRIVATE
|
|
||||||
DISPLAY_SDL2=1
|
|
||||||
DISPLAY_WINDOW_WIDTH_DEFAULT=1080
|
|
||||||
DISPLAY_WINDOW_HEIGHT_DEFAULT=810
|
|
||||||
DISPLAY_SCREEN_HEIGHT_DEFAULT=270
|
|
||||||
)
|
|
||||||
elseif(DUSK_TARGET_SYSTEM STREQUAL "psp")
|
|
||||||
target_compile_definitions(${DUSK_TARGET_NAME}
|
|
||||||
PRIVATE
|
|
||||||
DISPLAY_SDL2=1
|
|
||||||
DISPLAY_WINDOW_WIDTH_DEFAULT=480
|
|
||||||
DISPLAY_WINDOW_HEIGHT_DEFAULT=272
|
|
||||||
DISPLAY_WIDTH=480
|
|
||||||
DISPLAY_HEIGHT=272
|
|
||||||
DISPLAY_SIZE_DYNAMIC=0
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
@@ -1,172 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "camera.h"
|
|
||||||
#include "display/display.h"
|
|
||||||
#include "assert/assert.h"
|
|
||||||
#include "display/framebuffer.h"
|
|
||||||
|
|
||||||
void cameraInit(camera_t *camera) {
|
|
||||||
cameraInitPerspective(camera);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cameraInitPerspective(camera_t *camera) {
|
|
||||||
assertNotNull(camera, "Not a camera component");
|
|
||||||
|
|
||||||
camera->projType = CAMERA_PROJECTION_TYPE_PERSPECTIVE;
|
|
||||||
camera->perspective.fov = glm_rad(45.0f);
|
|
||||||
camera->nearClip = 0.1f;
|
|
||||||
camera->farClip = 10000.0f;
|
|
||||||
|
|
||||||
camera->viewType = CAMERA_VIEW_TYPE_LOOKAT;
|
|
||||||
glm_vec3_copy((vec3){ 5.0f, 5.0f, 5.0f }, camera->lookat.position);
|
|
||||||
glm_vec3_copy((vec3){ 0.0f, 1.0f, 0.0f }, camera->lookat.up);
|
|
||||||
glm_vec3_copy((vec3){ 0.0f, 0.0f, 0.0f }, camera->lookat.target);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cameraInitOrthographic(camera_t *camera) {
|
|
||||||
assertNotNull(camera, "Not a camera component");
|
|
||||||
|
|
||||||
camera->projType = CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC;
|
|
||||||
camera->orthographic.left = 0.0f;
|
|
||||||
camera->orthographic.right = (float_t)frameBufferGetWidth(FRAMEBUFFER_BOUND);
|
|
||||||
camera->orthographic.bottom = 0.0f;
|
|
||||||
camera->orthographic.top = (float_t)frameBufferGetHeight(FRAMEBUFFER_BOUND);
|
|
||||||
camera->nearClip = -1.0f;
|
|
||||||
camera->farClip = 1.0f;
|
|
||||||
|
|
||||||
camera->viewType = CAMERA_VIEW_TYPE_2D;
|
|
||||||
glm_vec2_copy((vec2){ 0.0f, 0.0f }, camera->_2d.position);
|
|
||||||
camera->_2d.zoom = 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cameraPushMatrix(camera_t *camera) {
|
|
||||||
assertNotNull(camera, "Not a camera component");
|
|
||||||
|
|
||||||
mat4 projection;
|
|
||||||
mat4 view;
|
|
||||||
|
|
||||||
switch(camera->projType) {
|
|
||||||
case CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC: {
|
|
||||||
assertTrue(
|
|
||||||
camera->orthographic.right != camera->orthographic.left &&
|
|
||||||
camera->orthographic.top != camera->orthographic.bottom,
|
|
||||||
"Invalid orthographic projection parameters"
|
|
||||||
);
|
|
||||||
glm_ortho(
|
|
||||||
camera->orthographic.left,
|
|
||||||
camera->orthographic.right,
|
|
||||||
camera->orthographic.bottom,
|
|
||||||
camera->orthographic.top,
|
|
||||||
camera->nearClip,
|
|
||||||
camera->farClip,
|
|
||||||
projection
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED:
|
|
||||||
case CAMERA_PROJECTION_TYPE_PERSPECTIVE: {
|
|
||||||
const float_t aspect = (
|
|
||||||
(float_t)frameBufferGetWidth(FRAMEBUFFER_BOUND) /
|
|
||||||
(float_t)frameBufferGetHeight(FRAMEBUFFER_BOUND)
|
|
||||||
);
|
|
||||||
glm_perspective(
|
|
||||||
camera->perspective.fov,
|
|
||||||
aspect,
|
|
||||||
camera->nearClip,
|
|
||||||
camera->farClip,
|
|
||||||
projection
|
|
||||||
);
|
|
||||||
|
|
||||||
if(camera->projType == CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED) {
|
|
||||||
// Flip Y axis
|
|
||||||
projection[1][1] *= -1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(camera->viewType) {
|
|
||||||
case CAMERA_VIEW_TYPE_MATRIX:
|
|
||||||
glm_mat4_copy(camera->view, view);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CAMERA_VIEW_TYPE_LOOKAT:
|
|
||||||
glm_lookat(
|
|
||||||
camera->lookat.position,
|
|
||||||
camera->lookat.target,
|
|
||||||
camera->lookat.up,
|
|
||||||
view
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CAMERA_VIEW_TYPE_LOOKAT_PIXEL_PERFECT:
|
|
||||||
assertTrue(
|
|
||||||
camera->projType == CAMERA_PROJECTION_TYPE_PERSPECTIVE ||
|
|
||||||
camera->projType == CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED,
|
|
||||||
"Pixel perfect camera view requires perspective projection"
|
|
||||||
);
|
|
||||||
|
|
||||||
const float_t viewportHeight = (
|
|
||||||
(float_t)frameBufferGetHeight(FRAMEBUFFER_BOUND)
|
|
||||||
);
|
|
||||||
const float_t z = (viewportHeight / 2.0f) / (
|
|
||||||
camera->lookatPixelPerfect.pixelsPerUnit *
|
|
||||||
tanf(camera->perspective.fov / 2.0f)
|
|
||||||
);
|
|
||||||
|
|
||||||
vec3 position;
|
|
||||||
glm_vec3_copy(camera->lookatPixelPerfect.target, position);
|
|
||||||
glm_vec3_add(position, camera->lookatPixelPerfect.offset, position);
|
|
||||||
position[2] += z;
|
|
||||||
glm_lookat(
|
|
||||||
position,
|
|
||||||
camera->lookatPixelPerfect.target,
|
|
||||||
camera->lookatPixelPerfect.up,
|
|
||||||
view
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CAMERA_VIEW_TYPE_2D:
|
|
||||||
glm_mat4_identity(view);
|
|
||||||
glm_translate(view, (vec3){
|
|
||||||
-camera->_2d.position[0],
|
|
||||||
-camera->_2d.position[1],
|
|
||||||
0.0f
|
|
||||||
});
|
|
||||||
glm_scale(view, (vec3){
|
|
||||||
camera->_2d.zoom,
|
|
||||||
camera->_2d.zoom,
|
|
||||||
1.0f
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
assertUnreachable("Invalid camera view type");
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
// mat4 pv;
|
|
||||||
// glm_mat4_mul(projection, camera->transform, pv);
|
|
||||||
|
|
||||||
glPushMatrix();
|
|
||||||
glMatrixMode(GL_PROJECTION);
|
|
||||||
glLoadIdentity();
|
|
||||||
glLoadMatrixf((const GLfloat*)projection);
|
|
||||||
|
|
||||||
glMatrixMode(GL_MODELVIEW);
|
|
||||||
glLoadIdentity();
|
|
||||||
glLoadMatrixf((const GLfloat*)view);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void cameraPopMatrix(void) {
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
glPopMatrix();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "dusk.h"
|
|
||||||
#include "display/color.h"
|
|
||||||
|
|
||||||
#define CAMERA_COUNT_MAX 4
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
CAMERA_PROJECTION_TYPE_PERSPECTIVE,
|
|
||||||
CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED,
|
|
||||||
CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC
|
|
||||||
} cameraprojectiontype_t;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
CAMERA_VIEW_TYPE_MATRIX,
|
|
||||||
CAMERA_VIEW_TYPE_LOOKAT,
|
|
||||||
CAMERA_VIEW_TYPE_2D,
|
|
||||||
CAMERA_VIEW_TYPE_LOOKAT_PIXEL_PERFECT
|
|
||||||
} cameraviewtype_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
cameraprojectiontype_t projType;
|
|
||||||
cameraviewtype_t viewType;
|
|
||||||
|
|
||||||
union {
|
|
||||||
mat4 view;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
float_t position[3];
|
|
||||||
float_t target[3];
|
|
||||||
float_t up[3];
|
|
||||||
} lookat;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
float_t offset[3];
|
|
||||||
float_t target[3];
|
|
||||||
float_t up[3];
|
|
||||||
float_t pixelsPerUnit;
|
|
||||||
} lookatPixelPerfect;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
float_t position[2];
|
|
||||||
float_t zoom;
|
|
||||||
} _2d;
|
|
||||||
};
|
|
||||||
|
|
||||||
union {
|
|
||||||
struct {
|
|
||||||
float_t fov;
|
|
||||||
} perspective;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
float_t left;
|
|
||||||
float_t right;
|
|
||||||
float_t top;
|
|
||||||
float_t bottom;
|
|
||||||
} orthographic;
|
|
||||||
};
|
|
||||||
|
|
||||||
float_t nearClip;
|
|
||||||
float_t farClip;
|
|
||||||
} camera_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes a camera to default values. This calls cameraInitPerspective.
|
|
||||||
*/
|
|
||||||
void cameraInit(camera_t *camera);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes a camera for perspective projection.
|
|
||||||
*/
|
|
||||||
void cameraInitPerspective(camera_t *camera);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes a camera for orthographic projection.
|
|
||||||
*/
|
|
||||||
void cameraInitOrthographic(camera_t *camera);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pushes the camera's view matrix onto the matrix stack.
|
|
||||||
*
|
|
||||||
* @param id The ID of the camera entity to use.
|
|
||||||
*/
|
|
||||||
void cameraPushMatrix(camera_t* camera);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pops the camera's view matrix off the matrix stack.
|
|
||||||
*/
|
|
||||||
void cameraPopMatrix(void);
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "dusk.h"
|
|
||||||
|
|
||||||
typedef float_t colorchannelf_t;
|
|
||||||
typedef uint8_t colorchannelb_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
colorchannelf_t r;
|
|
||||||
colorchannelf_t g;
|
|
||||||
colorchannelf_t b;
|
|
||||||
} color3f_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
colorchannelf_t r;
|
|
||||||
colorchannelf_t g;
|
|
||||||
colorchannelf_t b;
|
|
||||||
colorchannelf_t a;
|
|
||||||
} color4f_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
colorchannelb_t r;
|
|
||||||
colorchannelb_t g;
|
|
||||||
colorchannelb_t b;
|
|
||||||
} color3b_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
colorchannelb_t r;
|
|
||||||
colorchannelb_t g;
|
|
||||||
colorchannelb_t b;
|
|
||||||
colorchannelb_t a;
|
|
||||||
} color4b_t;
|
|
||||||
|
|
||||||
typedef color4b_t color_t;
|
|
||||||
|
|
||||||
#define color3f(r, g, b) ((color3f_t){r, g, b})
|
|
||||||
#define color4f(r, g, b, a) ((color4f_t){r, g, b, a})
|
|
||||||
#define color3b(r, g, b) ((color3b_t){r, g, b})
|
|
||||||
#define color4b(r, g, b, a) ((color4b_t){r, g, b, a})
|
|
||||||
#define color(r, g, b, a) ((color_t){r, g, b, a})
|
|
||||||
|
|
||||||
#define color_hex(hex) color( \
|
|
||||||
((hex >> 24) & 0xFF), \
|
|
||||||
((hex >> 16) & 0xFF), \
|
|
||||||
((hex >> 8) & 0xFF), \
|
|
||||||
(hex & 0xFF) \
|
|
||||||
)
|
|
||||||
|
|
||||||
#define COLOR_WHITE_3F color3f(1.0f, 1.0f, 1.0f)
|
|
||||||
#define COLOR_WHITE_4F color4f(1.0f, 1.0f, 1.0f, 1.0f)
|
|
||||||
#define COLOR_WHITE_3B color3b(255, 255, 255)
|
|
||||||
#define COLOR_WHITE_4B color4b(255, 255, 255, 255)
|
|
||||||
#define COLOR_WHITE color(255, 255, 255, 255)
|
|
||||||
|
|
||||||
#define COLOR_BLACK_3F color3f(0.0f, 0.0f, 0.0f)
|
|
||||||
#define COLOR_BLACK_4F color4f(0.0f, 0.0f, 0.0f, 1.0f)
|
|
||||||
#define COLOR_BLACK_3B color3b(0, 0, 0)
|
|
||||||
#define COLOR_BLACK_4B color4b(0, 0, 0, 255)
|
|
||||||
#define COLOR_BLACK color(0, 0, 0, 255)
|
|
||||||
|
|
||||||
#define COLOR_RED_3F color3f(1.0f, 0.0f, 0.0f)
|
|
||||||
#define COLOR_RED_4F color4f(1.0f, 0.0f, 0.0f, 1.0f)
|
|
||||||
#define COLOR_RED_3B color3b(255, 0, 0)
|
|
||||||
#define COLOR_RED_4B color4b(255, 0, 0, 255)
|
|
||||||
#define COLOR_RED color(255, 0, 0, 255)
|
|
||||||
|
|
||||||
#define COLOR_GREEN_3F color3f(0.0f, 1.0f, 0.0f)
|
|
||||||
#define COLOR_GREEN_4F color4f(0.0f, 1.0f, 0.0f, 1.0f)
|
|
||||||
#define COLOR_GREEN_3B color3b(0, 255, 0)
|
|
||||||
#define COLOR_GREEN_4B color4b(0, 255, 0, 255)
|
|
||||||
#define COLOR_GREEN color(0, 255, 0, 255)
|
|
||||||
|
|
||||||
#define COLOR_BLUE_3F color3f(0.0f, 0.0f, 1.0f)
|
|
||||||
#define COLOR_BLUE_4F color4f(0.0f, 0.0f, 1.0f, 1.0f)
|
|
||||||
#define COLOR_BLUE_3B color3b(0, 0, 255)
|
|
||||||
#define COLOR_BLUE_4B color4b(0, 0, 255, 255)
|
|
||||||
#define COLOR_BLUE color(0, 0, 255, 255)
|
|
||||||
|
|
||||||
#define COLOR_YELLOW_3F color3f(1.0f, 1.0f, 0.0f)
|
|
||||||
#define COLOR_YELLOW_4F color4f(1.0f, 1.0f, 0.0f, 1.0f)
|
|
||||||
#define COLOR_YELLOW_3B color3b(255, 255, 0)
|
|
||||||
#define COLOR_YELLOW_4B color4b(255, 255, 0, 255)
|
|
||||||
#define COLOR_YELLOW color(255, 255, 0, 255)
|
|
||||||
|
|
||||||
#define COLOR_CYAN_3F color3f(0.0f, 1.0f, 1.0f)
|
|
||||||
#define COLOR_CYAN_4F color4f(0.0f, 1.0f, 1.0f, 1.0f)
|
|
||||||
#define COLOR_CYAN_3B color3b(0, 255, 255)
|
|
||||||
#define COLOR_CYAN_4B color4b(0, 255, 255, 255)
|
|
||||||
#define COLOR_CYAN color(0, 255, 255, 255)
|
|
||||||
|
|
||||||
#define COLOR_MAGENTA_3F color3f(1.0f, 0.0f, 1.0f)
|
|
||||||
#define COLOR_MAGENTA_4F color4f(1.0f, 0.0f, 1.0f, 1.0f)
|
|
||||||
#define COLOR_MAGENTA_3B color3b(255, 0, 255)
|
|
||||||
#define COLOR_MAGENTA_4B color4b(255, 0, 255, 255)
|
|
||||||
#define COLOR_MAGENTA color(255, 0, 255, 255)
|
|
||||||
|
|
||||||
#define COLOR_TRANSPARENT_3F color3f(0.0f, 0.0f, 0.0f)
|
|
||||||
#define COLOR_TRANSPARENT_4F color4f(0.0f, 0.0f, 0.0f, 0.0f)
|
|
||||||
#define COLOR_TRANSPARENT_3B color3b(0, 0, 0)
|
|
||||||
#define COLOR_TRANSPARENT_4B color4b(0, 0, 0, 0)
|
|
||||||
#define COLOR_TRANSPARENT color(0, 0, 0, 0)
|
|
||||||
|
|
||||||
#define COLOR_CORNFLOWER_BLUE_3F color3f(0.39f, 0.58f, 0.93f)
|
|
||||||
#define COLOR_CORNFLOWER_BLUE_4F color4f(0.39f, 0.58f, 0.93f, 1.0f)
|
|
||||||
#define COLOR_CORNFLOWER_BLUE_3B color3b(100, 149, 237)
|
|
||||||
#define COLOR_CORNFLOWER_BLUE_4B color4b(100, 149, 237, 255)
|
|
||||||
#define COLOR_CORNFLOWER_BLUE color(100, 149, 237, 255)
|
|
||||||
@@ -1,157 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "display/display.h"
|
|
||||||
#include "engine/engine.h"
|
|
||||||
#include "display/framebuffer.h"
|
|
||||||
#include "scene/scenemanager.h"
|
|
||||||
#include "display/spritebatch.h"
|
|
||||||
#include "display/mesh/quad.h"
|
|
||||||
#include "display/screen.h"
|
|
||||||
#include "ui/ui.h"
|
|
||||||
#include "debug/debug.h"
|
|
||||||
|
|
||||||
display_t DISPLAY;
|
|
||||||
|
|
||||||
errorret_t displayInit(void) {
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
uint32_t flags = SDL_INIT_VIDEO;
|
|
||||||
#if INPUT_GAMEPAD == 1
|
|
||||||
flags |= SDL_INIT_GAMECONTROLLER | SDL_INIT_JOYSTICK;
|
|
||||||
#endif
|
|
||||||
if(SDL_Init(flags) != 0) {
|
|
||||||
errorThrow("SDL Failed to Initialize: %s", SDL_GetError());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set OpenGL attributes (Needs to be done now or later?)
|
|
||||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
|
||||||
|
|
||||||
// Create window with OpenGL flag.
|
|
||||||
DISPLAY.window = SDL_CreateWindow(
|
|
||||||
"Dusk",
|
|
||||||
SDL_WINDOWPOS_UNDEFINED,
|
|
||||||
SDL_WINDOWPOS_UNDEFINED,
|
|
||||||
DISPLAY_WINDOW_WIDTH_DEFAULT,
|
|
||||||
DISPLAY_WINDOW_HEIGHT_DEFAULT,
|
|
||||||
SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI |
|
|
||||||
SDL_WINDOW_OPENGL
|
|
||||||
);
|
|
||||||
if(!DISPLAY.window) {
|
|
||||||
errorThrow("SDL_CreateWindow failed: %s", SDL_GetError());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create OpenGL context
|
|
||||||
DISPLAY.glContext = SDL_GL_CreateContext(DISPLAY.window);
|
|
||||||
if(!DISPLAY.glContext) {
|
|
||||||
errorThrow("SDL_GL_CreateContext failed: %s", SDL_GetError());
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_GL_SetSwapInterval(1);
|
|
||||||
glDisable(GL_DEPTH_TEST);
|
|
||||||
glDisable(GL_CULL_FACE);
|
|
||||||
glDisable(GL_LIGHTING);// PSP defaults this on?
|
|
||||||
glShadeModel(GL_SMOOTH); // Fixes color on PSP?
|
|
||||||
glEnable(GL_BLEND);
|
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
||||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
|
||||||
|
|
||||||
glEnableClientState(GL_COLOR_ARRAY);// To confirm: every frame on PSP?
|
|
||||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
||||||
glEnableClientState(GL_VERTEX_ARRAY);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
quadInit();
|
|
||||||
frameBufferInitBackbuffer();
|
|
||||||
spriteBatchInit();
|
|
||||||
screenInit();
|
|
||||||
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
errorret_t displayUpdate(void) {
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
SDL_Event event;
|
|
||||||
while(SDL_PollEvent(&event)) {
|
|
||||||
switch(event.type) {
|
|
||||||
case SDL_QUIT: {
|
|
||||||
ENGINE.running = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case SDL_WINDOWEVENT: {
|
|
||||||
switch(event.window.event) {
|
|
||||||
case SDL_WINDOWEVENT_CLOSE: {
|
|
||||||
ENGINE.running = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default: {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
default: {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_GL_MakeCurrent(DISPLAY.window, DISPLAY.glContext);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Reset state
|
|
||||||
spriteBatchClear();
|
|
||||||
frameBufferBind(NULL);
|
|
||||||
|
|
||||||
// Bind screen and render scene
|
|
||||||
screenBind();
|
|
||||||
frameBufferClear(
|
|
||||||
FRAMEBUFFER_CLEAR_COLOR | FRAMEBUFFER_CLEAR_DEPTH,
|
|
||||||
COLOR_CORNFLOWER_BLUE
|
|
||||||
);
|
|
||||||
sceneManagerRender();
|
|
||||||
uiRender();
|
|
||||||
|
|
||||||
// Finish up
|
|
||||||
spriteBatchFlush();
|
|
||||||
screenUnbind();
|
|
||||||
screenRender();
|
|
||||||
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
SDL_GL_SwapWindow(DISPLAY.window);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
GLenum err;
|
|
||||||
while((err = glGetError()) != GL_NO_ERROR) {
|
|
||||||
debugPrint("GL Error: %d\n", err);
|
|
||||||
}
|
|
||||||
|
|
||||||
// For now, we just return an OK error.
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
errorret_t displayDispose(void) {
|
|
||||||
spriteBatchDispose();
|
|
||||||
screenDispose();
|
|
||||||
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
if(DISPLAY.glContext) {
|
|
||||||
SDL_GL_DeleteContext(DISPLAY.glContext);
|
|
||||||
DISPLAY.glContext = NULL;
|
|
||||||
}
|
|
||||||
if(DISPLAY.window) {
|
|
||||||
SDL_DestroyWindow(DISPLAY.window);
|
|
||||||
DISPLAY.window = NULL;
|
|
||||||
}
|
|
||||||
SDL_Quit();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// For now, we just return an OK error.
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "displaydefs.h"
|
|
||||||
#include "error/error.h"
|
|
||||||
#include "display/camera.h"
|
|
||||||
#include "display/framebuffer.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
SDL_Window *window;
|
|
||||||
SDL_GLContext glContext;
|
|
||||||
#endif
|
|
||||||
} display_t;
|
|
||||||
|
|
||||||
extern display_t DISPLAY;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the display system.
|
|
||||||
*/
|
|
||||||
errorret_t displayInit(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tells the display system to actually draw the frame.
|
|
||||||
*/
|
|
||||||
errorret_t displayUpdate(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disposes of the display system.
|
|
||||||
*/
|
|
||||||
errorret_t displayDispose(void);
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
#include <SDL2/SDL.h>
|
|
||||||
|
|
||||||
#define GL_GLEXT_PROTOTYPES
|
|
||||||
#include <GL/gl.h>
|
|
||||||
#include <GL/glext.h>
|
|
||||||
|
|
||||||
#ifndef DISPLAY_SIZE_DYNAMIC
|
|
||||||
#define DISPLAY_SIZE_DYNAMIC 1
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
#error "Need to specify display backend."
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if DISPLAY_SIZE_DYNAMIC == 0
|
|
||||||
#ifndef DISPLAY_WIDTH
|
|
||||||
#error "DISPLAY_WIDTH must be defined when DISPLAY_SIZE_DYNAMIC is 0."
|
|
||||||
#endif
|
|
||||||
#ifndef DISPLAY_HEIGHT
|
|
||||||
#error "DISPLAY_HEIGHT must be defined when DISPLAY_SIZE_DYNAMIC is 0."
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef DISPLAY_WINDOW_WIDTH_DEFAULT
|
|
||||||
#error "DISPLAY_WINDOW_WIDTH_DEFAULT must be defined."
|
|
||||||
#endif
|
|
||||||
#ifndef DISPLAY_WINDOW_HEIGHT_DEFAULT
|
|
||||||
#define DISPLAY_WINDOW_HEIGHT_DEFAULT DISPLAY_HEIGHT
|
|
||||||
#endif
|
|
||||||
@@ -1,162 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "framebuffer.h"
|
|
||||||
#include "display/display.h"
|
|
||||||
#include "assert/assert.h"
|
|
||||||
#include "util/memory.h"
|
|
||||||
|
|
||||||
framebuffer_t FRAMEBUFFER_BACKBUFFER = {0};
|
|
||||||
const framebuffer_t *FRAMEBUFFER_BOUND = &FRAMEBUFFER_BACKBUFFER;
|
|
||||||
|
|
||||||
void frameBufferInitBackbuffer() {
|
|
||||||
memoryZero(&FRAMEBUFFER_BACKBUFFER, sizeof(framebuffer_t));
|
|
||||||
|
|
||||||
FRAMEBUFFER_BACKBUFFER.id = -1;
|
|
||||||
FRAMEBUFFER_BOUND = &FRAMEBUFFER_BACKBUFFER;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DISPLAY_SIZE_DYNAMIC == 1
|
|
||||||
void frameBufferInit(
|
|
||||||
framebuffer_t *framebuffer,
|
|
||||||
const uint32_t width,
|
|
||||||
const uint32_t height
|
|
||||||
) {
|
|
||||||
#if DISPLAY_SDL2 == 1
|
|
||||||
assertNotNull(framebuffer, "Framebuffer cannot be NULL");
|
|
||||||
assertTrue(width > 0 && height > 0, "W/H must be greater than 0");
|
|
||||||
|
|
||||||
memoryZero(framebuffer, sizeof(framebuffer_t));
|
|
||||||
textureInit(&framebuffer->texture, width, height, GL_RGBA,(texturedata_t){
|
|
||||||
.rgba = { .colors = NULL }
|
|
||||||
});
|
|
||||||
|
|
||||||
glGenFramebuffersEXT(1, &framebuffer->id);
|
|
||||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer->id);
|
|
||||||
|
|
||||||
glFramebufferTexture2DEXT(
|
|
||||||
GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
|
|
||||||
GL_TEXTURE_2D, framebuffer->texture.id, 0
|
|
||||||
);
|
|
||||||
|
|
||||||
if(
|
|
||||||
glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) !=
|
|
||||||
GL_FRAMEBUFFER_COMPLETE_EXT
|
|
||||||
) {
|
|
||||||
assertUnreachable("Framebuffer is not complete");
|
|
||||||
}
|
|
||||||
|
|
||||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int32_t frameBufferGetWidth(const framebuffer_t *framebuffer) {
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
if(framebuffer == &FRAMEBUFFER_BACKBUFFER) {
|
|
||||||
#if DISPLAY_SIZE_DYNAMIC == 0
|
|
||||||
return DISPLAY_WIDTH;
|
|
||||||
#else
|
|
||||||
int32_t windowWidth, windowHeight;
|
|
||||||
SDL_GetWindowSize(DISPLAY.window, &windowWidth, &windowHeight);
|
|
||||||
return windowWidth;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
return framebuffer->texture.width;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t frameBufferGetHeight(const framebuffer_t *framebuffer) {
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
if(framebuffer == &FRAMEBUFFER_BACKBUFFER) {
|
|
||||||
#if DISPLAY_SIZE_DYNAMIC == 0
|
|
||||||
return DISPLAY_HEIGHT;
|
|
||||||
#else
|
|
||||||
int32_t windowWidth, windowHeight;
|
|
||||||
SDL_GetWindowSize(DISPLAY.window, &windowWidth, &windowHeight);
|
|
||||||
return windowHeight;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
return framebuffer->texture.height;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void frameBufferBind(const framebuffer_t *framebuffer) {
|
|
||||||
if(framebuffer == NULL) {
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
frameBufferBind(&FRAMEBUFFER_BACKBUFFER);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
FRAMEBUFFER_BOUND = &FRAMEBUFFER_BACKBUFFER;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bind the framebuffer for rendering
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
if(framebuffer == &FRAMEBUFFER_BACKBUFFER) {
|
|
||||||
#if PSP
|
|
||||||
|
|
||||||
#else
|
|
||||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
#if PSP
|
|
||||||
assertUnreachable("Framebuffers not supported on PSP");
|
|
||||||
#else
|
|
||||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer->id);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
glViewport(
|
|
||||||
0, 0,
|
|
||||||
frameBufferGetWidth(framebuffer), frameBufferGetHeight(framebuffer)
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
FRAMEBUFFER_BOUND = framebuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
void frameBufferClear(uint8_t flags, color_t color) {
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
GLbitfield glFlags = 0;
|
|
||||||
|
|
||||||
if(flags & FRAMEBUFFER_CLEAR_COLOR) {
|
|
||||||
glFlags |= GL_COLOR_BUFFER_BIT;
|
|
||||||
glClearColor(
|
|
||||||
color.r / 255.0f,
|
|
||||||
color.g / 255.0f,
|
|
||||||
color.b / 255.0f,
|
|
||||||
color.a / 255.0f
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(flags & FRAMEBUFFER_CLEAR_DEPTH) {
|
|
||||||
glFlags |= GL_DEPTH_BUFFER_BIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
glClear(glFlags);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void frameBufferDispose(framebuffer_t *framebuffer) {
|
|
||||||
assertNotNull(framebuffer, "Framebuffer cannot be NULL");
|
|
||||||
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
if(framebuffer == &FRAMEBUFFER_BACKBUFFER) {
|
|
||||||
assertUnreachable("Cannot dispose of backbuffer");
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DISPLAY_SIZE_DYNAMIC == 0
|
|
||||||
assertUnreachable("Dynamic size framebuffers not supported");
|
|
||||||
#else
|
|
||||||
textureDispose(&framebuffer->texture);
|
|
||||||
glDeleteFramebuffersEXT(1, &framebuffer->id);
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "display/texture.h"
|
|
||||||
|
|
||||||
#define FRAMEBUFFER_CLEAR_COLOR (1 << 0)
|
|
||||||
#define FRAMEBUFFER_CLEAR_DEPTH (1 << 1)
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
#if DISPLAY_SDL2 == 1
|
|
||||||
// OpenGL Framebuffer Object ID
|
|
||||||
GLuint id;
|
|
||||||
texture_t texture;
|
|
||||||
#else
|
|
||||||
#error "Framebuffers not implemented on this platform."
|
|
||||||
#endif
|
|
||||||
} framebuffer_t;
|
|
||||||
|
|
||||||
extern framebuffer_t FRAMEBUFFER_BACKBUFFER;
|
|
||||||
extern const framebuffer_t *FRAMEBUFFER_BOUND;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the backbuffer framebuffer.
|
|
||||||
*/
|
|
||||||
void frameBufferInitBackbuffer(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes a framebuffer.
|
|
||||||
*
|
|
||||||
* @param framebuffer The framebuffer to initialize.
|
|
||||||
* @param width The width of the framebuffer.
|
|
||||||
* @param height The height of the framebuffer.
|
|
||||||
*/
|
|
||||||
#if DISPLAY_SIZE_DYNAMIC == 1
|
|
||||||
void frameBufferInit(
|
|
||||||
framebuffer_t *framebuffer,
|
|
||||||
const uint32_t width,
|
|
||||||
const uint32_t height
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the width of the framebuffer.
|
|
||||||
*
|
|
||||||
* @param framebuffer The framebuffer to get the width of.
|
|
||||||
* @return The width of the framebuffer, or 0 if the framebuffer is NULL.
|
|
||||||
*/
|
|
||||||
int32_t frameBufferGetWidth(const framebuffer_t *framebuffer);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the height of the framebuffer.
|
|
||||||
*
|
|
||||||
* @param framebuffer The framebuffer to get the height of.
|
|
||||||
* @return The height of the framebuffer, or 0 if the framebuffer is NULL.
|
|
||||||
*/
|
|
||||||
int32_t frameBufferGetHeight(const framebuffer_t *framebuffer);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Binds the framebuffer for rendering, or the backbuffer if the framebuffer
|
|
||||||
* provided is NULL.
|
|
||||||
*
|
|
||||||
* @param framebuffer The framebuffer to bind, or NULL to bind the backbuffer.
|
|
||||||
*/
|
|
||||||
void frameBufferBind(const framebuffer_t *framebuffer);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears the currently bound framebuffer.
|
|
||||||
*
|
|
||||||
* @param flags The clear flags.
|
|
||||||
* @param color The color to clear the color buffer to (if clearing color).
|
|
||||||
*/
|
|
||||||
void frameBufferClear(uint8_t flags, color_t color);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disposes of the framebuffer using EXT methods.
|
|
||||||
*
|
|
||||||
* @param framebuffer The framebuffer to dispose of.
|
|
||||||
*/
|
|
||||||
void frameBufferDispose(framebuffer_t *framebuffer);
|
|
||||||
|
|
||||||
// #if RENDER_USE_FRAMEBUFFER
|
|
||||||
// typedef struct {
|
|
||||||
// GLuint id;
|
|
||||||
// texture_t texture;
|
|
||||||
// } framebuffer_t;
|
|
||||||
|
|
||||||
// /**
|
|
||||||
// * Initializes a framebuffer using EXT methods.
|
|
||||||
// *
|
|
||||||
// * @param framebuffer The framebuffer to initialize.
|
|
||||||
// * @param width The width of the framebuffer.
|
|
||||||
// * @param height The height of the framebuffer.
|
|
||||||
// * @return An error code indicating success or failure.
|
|
||||||
// */
|
|
||||||
// void frameBufferInit(
|
|
||||||
// framebuffer_t *framebuffer,
|
|
||||||
// const uint32_t width,
|
|
||||||
// const uint32_t height
|
|
||||||
// );
|
|
||||||
|
|
||||||
// #endif
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "mesh.h"
|
|
||||||
#include "util/memory.h"
|
|
||||||
#include "assert/assert.h"
|
|
||||||
|
|
||||||
void meshInit(
|
|
||||||
mesh_t *mesh,
|
|
||||||
const meshprimitivetype_t primitiveType,
|
|
||||||
const int32_t vertexCount,
|
|
||||||
const meshvertex_t *vertices
|
|
||||||
) {
|
|
||||||
assertNotNull(mesh, "Mesh cannot be NULL");
|
|
||||||
assertNotNull(vertices, "Vertices cannot be NULL");
|
|
||||||
assertTrue(vertexCount > 0, "Vertex count must be greater than 0");
|
|
||||||
|
|
||||||
memoryZero(mesh, sizeof(mesh_t));
|
|
||||||
|
|
||||||
mesh->primitiveType = primitiveType;
|
|
||||||
mesh->vertexCount = vertexCount;
|
|
||||||
mesh->vertices = vertices;
|
|
||||||
}
|
|
||||||
|
|
||||||
void meshDraw(
|
|
||||||
const mesh_t *mesh,
|
|
||||||
const int32_t vertexOffset,
|
|
||||||
const int32_t vertexCount
|
|
||||||
) {
|
|
||||||
const int32_t offset = vertexOffset == -1 ? 0 : vertexOffset;
|
|
||||||
const int32_t count = vertexCount == -1 ? mesh->vertexCount : vertexCount;
|
|
||||||
|
|
||||||
assertNotNull(mesh, "Mesh cannot be NULL");
|
|
||||||
assertTrue(offset >= 0, "Vertex offset must be non-negative");
|
|
||||||
assertTrue(count >= 0, "Vertex count must be non-negative");
|
|
||||||
assertTrue(offset + count <= mesh->vertexCount,
|
|
||||||
"Vertex offset + count must not exceed vertex count"
|
|
||||||
);
|
|
||||||
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
// PSP style pointer legacy OpenGL
|
|
||||||
const GLsizei stride = sizeof(meshvertex_t);
|
|
||||||
|
|
||||||
glColorPointer(
|
|
||||||
sizeof(color4b_t),
|
|
||||||
GL_UNSIGNED_BYTE,
|
|
||||||
stride,
|
|
||||||
(const GLvoid*)&mesh->vertices[offset].color
|
|
||||||
);
|
|
||||||
glTexCoordPointer(
|
|
||||||
MESH_VERTEX_UV_SIZE,
|
|
||||||
GL_FLOAT,
|
|
||||||
stride,
|
|
||||||
(const GLvoid*)&mesh->vertices[offset].uv[0]
|
|
||||||
);
|
|
||||||
glVertexPointer(
|
|
||||||
MESH_VERTEX_POS_SIZE,
|
|
||||||
GL_FLOAT,
|
|
||||||
stride,
|
|
||||||
(const GLvoid*)&mesh->vertices[offset].pos[0]
|
|
||||||
);
|
|
||||||
|
|
||||||
glDrawArrays(
|
|
||||||
mesh->primitiveType,
|
|
||||||
0,
|
|
||||||
count
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void meshDispose(mesh_t *mesh) {
|
|
||||||
assertNotNull(mesh, "Mesh cannot be NULL");
|
|
||||||
memoryZero(mesh, sizeof(mesh_t));
|
|
||||||
}
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
// Copyright (c) 2025 Dominic Masters
|
|
||||||
//
|
|
||||||
// This software is released under the MIT License.
|
|
||||||
// https://opensource.org/licenses/MIT
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "display/display.h"
|
|
||||||
#include "display/color.h"
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
MESH_PRIMITIVE_TRIANGLES = GL_TRIANGLES,
|
|
||||||
MESH_PRIMITIVE_LINES = GL_LINES,
|
|
||||||
MESH_PRIMITIVE_POINTS = GL_POINTS,
|
|
||||||
#endif
|
|
||||||
} meshprimitivetype_t;
|
|
||||||
|
|
||||||
#define MESH_VERTEX_UV_SIZE 2
|
|
||||||
#define MESH_VERTEX_POS_SIZE 3
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
color4b_t color;
|
|
||||||
GLfloat uv[MESH_VERTEX_UV_SIZE];
|
|
||||||
GLfloat pos[MESH_VERTEX_POS_SIZE];
|
|
||||||
#endif
|
|
||||||
} meshvertex_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
const meshvertex_t *vertices;
|
|
||||||
int32_t vertexCount;
|
|
||||||
meshprimitivetype_t primitiveType;
|
|
||||||
} mesh_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes a mesh.
|
|
||||||
*
|
|
||||||
* @param mesh The mesh to initialize.
|
|
||||||
* @param primitiveType The OpenGL primitive type (e.g., GL_TRIANGLES).
|
|
||||||
* @param vertexCount The number of vertices in the mesh.
|
|
||||||
* @param vertices The vertex data for the mesh.
|
|
||||||
*/
|
|
||||||
void meshInit(
|
|
||||||
mesh_t *mesh,
|
|
||||||
const meshprimitivetype_t primitiveType,
|
|
||||||
const int32_t vertexCount,
|
|
||||||
const meshvertex_t *vertices
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Draws a mesh.
|
|
||||||
*
|
|
||||||
* @param mesh The mesh to draw.
|
|
||||||
* @param vertexOffset The offset in the vertex array to start drawing from.
|
|
||||||
* @param vertexCount The number of vertices to draw. If -1, draws all vertices.
|
|
||||||
*/
|
|
||||||
void meshDraw(
|
|
||||||
const mesh_t *mesh,
|
|
||||||
const int32_t vertexOffset,
|
|
||||||
const int32_t vertexCount
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disposes a mesh.
|
|
||||||
*
|
|
||||||
* @param mesh The mesh to dispose.
|
|
||||||
*/
|
|
||||||
void meshDispose(mesh_t *mesh);
|
|
||||||
@@ -1,128 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "quad.h"
|
|
||||||
#include "assert/assert.h"
|
|
||||||
|
|
||||||
mesh_t QUAD_MESH_SIMPLE;
|
|
||||||
meshvertex_t QUAD_MESH_SIMPLE_VERTICES[QUAD_VERTEX_COUNT] = {
|
|
||||||
{ COLOR_WHITE_4B, { 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } },
|
|
||||||
{ COLOR_WHITE_4B, { 1.0f, 0.0f }, { 1.0f, 0.0f, 0.0f } },
|
|
||||||
{ COLOR_WHITE_4B, { 1.0f, 1.0f }, { 1.0f, 1.0f, 0.0f } },
|
|
||||||
|
|
||||||
{ COLOR_WHITE_4B, { 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } },
|
|
||||||
{ COLOR_WHITE_4B, { 1.0f, 1.0f }, { 1.0f, 1.0f, 0.0f } },
|
|
||||||
{ COLOR_WHITE_4B, { 0.0f, 1.0f }, { 0.0f, 1.0f, 0.0f } }
|
|
||||||
};
|
|
||||||
|
|
||||||
void quadInit() {
|
|
||||||
meshInit(
|
|
||||||
&QUAD_MESH_SIMPLE,
|
|
||||||
QUAD_PRIMITIVE_TYPE,
|
|
||||||
QUAD_VERTEX_COUNT,
|
|
||||||
QUAD_MESH_SIMPLE_VERTICES
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void quadBuffer(
|
|
||||||
meshvertex_t *vertices,
|
|
||||||
const float_t minX,
|
|
||||||
const float_t minY,
|
|
||||||
const float_t maxX,
|
|
||||||
const float_t maxY,
|
|
||||||
const color_t color,
|
|
||||||
const float_t u0,
|
|
||||||
const float_t v0,
|
|
||||||
const float_t u1,
|
|
||||||
const float_t v1
|
|
||||||
) {
|
|
||||||
const float_t z = 0.0f; // Z coordinate for 2D rendering
|
|
||||||
assertNotNull(vertices, "Vertices cannot be NULL");
|
|
||||||
|
|
||||||
// First triangle
|
|
||||||
vertices[0] = (meshvertex_t) {
|
|
||||||
{ color.r, color.g, color.b, color.a }, // Color
|
|
||||||
{ u0, v0 }, // UV
|
|
||||||
{ minX, minY, z } // Position
|
|
||||||
};
|
|
||||||
vertices[1] = (meshvertex_t) {
|
|
||||||
{ color.r, color.g, color.b, color.a }, // Color
|
|
||||||
{ u1, v0 }, // UV
|
|
||||||
{ maxX, minY, z } // Position
|
|
||||||
};
|
|
||||||
vertices[2] = (meshvertex_t) {
|
|
||||||
{ color.r, color.g, color.b, color.a }, // Color
|
|
||||||
{ u1, v1 }, // UV
|
|
||||||
{ maxX, maxY, z } // Position
|
|
||||||
};
|
|
||||||
|
|
||||||
// Second triangle
|
|
||||||
vertices[3] = (meshvertex_t) {
|
|
||||||
{ color.r, color.g, color.b, color.a }, // Color
|
|
||||||
{ u0, v0 }, // UV
|
|
||||||
{ minX, minY, z } // Position
|
|
||||||
};
|
|
||||||
vertices[4] = (meshvertex_t) {
|
|
||||||
{ color.r, color.g, color.b, color.a }, // Color
|
|
||||||
{ u1, v1 }, // UV
|
|
||||||
{ maxX, maxY, z } // Position
|
|
||||||
};
|
|
||||||
vertices[5] = (meshvertex_t) {
|
|
||||||
{ color.r, color.g, color.b, color.a }, // Color
|
|
||||||
{ u0, v1 }, // UV
|
|
||||||
{ minX, maxY, z } // Position
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void quadBuffer3D(
|
|
||||||
meshvertex_t *vertices,
|
|
||||||
const vec3 min,
|
|
||||||
const vec3 max,
|
|
||||||
const color_t color,
|
|
||||||
const vec2 uvMin,
|
|
||||||
const vec2 uvMax
|
|
||||||
) {
|
|
||||||
assertNotNull(vertices, "Vertices cannot be NULL");
|
|
||||||
assertNotNull(min, "Min vector cannot be NULL");
|
|
||||||
assertNotNull(max, "Max vector cannot be NULL");
|
|
||||||
assertNotNull(uvMin, "UV Min vector cannot be NULL");
|
|
||||||
assertNotNull(uvMax, "UV Max vector cannot be NULL");
|
|
||||||
|
|
||||||
// First triangle
|
|
||||||
vertices[0] = (meshvertex_t) {
|
|
||||||
{ color.r, color.g, color.b, color.a }, // Color
|
|
||||||
{ uvMin[0], uvMin[1] }, // UV
|
|
||||||
{ min[0], min[1], min[2] } // Position
|
|
||||||
};
|
|
||||||
vertices[1] = (meshvertex_t) {
|
|
||||||
{ color.r, color.g, color.b, color.a }, // Color
|
|
||||||
{ uvMax[0], uvMin[1] }, // UV
|
|
||||||
{ max[0], min[1], min[2] } // Position
|
|
||||||
};
|
|
||||||
vertices[2] = (meshvertex_t) {
|
|
||||||
{ color.r, color.g, color.b, color.a }, // Color
|
|
||||||
{ uvMax[0], uvMax[1] }, // UV
|
|
||||||
{ max[0], max[1], min[2] } // Position
|
|
||||||
};
|
|
||||||
|
|
||||||
// Second triangle
|
|
||||||
vertices[3] = (meshvertex_t) {
|
|
||||||
{ color.r, color.g, color.b, color.a }, // Color
|
|
||||||
{ uvMin[0], uvMin[1] }, // UV
|
|
||||||
{ min[0], min[1], min[2] } // Position
|
|
||||||
};
|
|
||||||
vertices[4] = (meshvertex_t) {
|
|
||||||
{ color.r, color.g, color.b, color.a }, // Color
|
|
||||||
{ uvMax[0], uvMax[1] }, // UV
|
|
||||||
{ max[0], max[1], min[2] } // Position
|
|
||||||
};
|
|
||||||
vertices[5] = (meshvertex_t) {
|
|
||||||
{ color.r, color.g, color.b, color.a }, // Color
|
|
||||||
{ uvMin[0], uvMax[1] }, // UV
|
|
||||||
{ min[0], max[1], min[2] } // Position
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "display/color.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
const uint8_t colorCount;
|
|
||||||
const color_t *colors;
|
|
||||||
} palette_t;
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "dusk.h"
|
|
||||||
#include "display/framebuffer.h"
|
|
||||||
#include "display/camera.h"
|
|
||||||
#include "display/mesh/quad.h"
|
|
||||||
|
|
||||||
#if DISPLAY_SIZE_DYNAMIC == 1
|
|
||||||
#ifndef DISPLAY_SCREEN_HEIGHT_DEFAULT
|
|
||||||
#error "DISPLAY_SCREEN_HEIGHT_DEFAULT must be defined when DISPLAY_SIZE_DYNAMIC is enabled."
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
SCREEN_MODE_BACKBUFFER,
|
|
||||||
|
|
||||||
#if DISPLAY_SIZE_DYNAMIC == 1
|
|
||||||
SCREEN_MODE_FIXED_SIZE,
|
|
||||||
SCREEN_MODE_ASPECT_RATIO,// Maintains aspect at all cost
|
|
||||||
SCREEN_MODE_FIXED_HEIGHT, // Fixed height, width expands/contracts as needed
|
|
||||||
SCREEN_MODE_FIXED_WIDTH, // Fixed width, height expands/contracts as needed
|
|
||||||
#endif
|
|
||||||
} screenmode_t;
|
|
||||||
|
|
||||||
// typedef enum {
|
|
||||||
// SCREEN_SCALE_MODE_FILL,
|
|
||||||
// SCREEN_SCALE_MODE_INTEGER,
|
|
||||||
// SCREEN_SCALE_MODE_INEGER_OVERFLOW
|
|
||||||
// } screenscalemode_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
screenmode_t mode;
|
|
||||||
// screenscalemode_t scaleMode;
|
|
||||||
|
|
||||||
// Calculated dimensions of the viewport, to be used by the camera
|
|
||||||
int32_t width;
|
|
||||||
int32_t height;
|
|
||||||
float_t aspect;
|
|
||||||
|
|
||||||
#if DISPLAY_SIZE_DYNAMIC == 1
|
|
||||||
framebuffer_t framebuffer;
|
|
||||||
bool_t framebufferReady;
|
|
||||||
camera_t framebufferCamera;
|
|
||||||
mesh_t frameBufferMesh;
|
|
||||||
meshvertex_t frameBufferMeshVertices[QUAD_VERTEX_COUNT];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
union {
|
|
||||||
struct {
|
|
||||||
int32_t width;
|
|
||||||
int32_t height;
|
|
||||||
} fixedSize;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
float_t ratio;
|
|
||||||
} aspectRatio;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
int32_t height;
|
|
||||||
} fixedHeight;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
int32_t width;
|
|
||||||
} fixedWidth;
|
|
||||||
};
|
|
||||||
} screen_t;
|
|
||||||
|
|
||||||
extern screen_t SCREEN;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the screen system.
|
|
||||||
*/
|
|
||||||
void screenInit();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Binds the screen, this is done before rendering game content.
|
|
||||||
*/
|
|
||||||
void screenBind();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unbinds the screen, does nothing for now.
|
|
||||||
*/
|
|
||||||
void screenUnbind();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Renders the screen to the current framebuffer.
|
|
||||||
*/
|
|
||||||
void screenRender();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disposes the screen system.
|
|
||||||
*/
|
|
||||||
void screenDispose();
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "spritebatch.h"
|
|
||||||
#include "assert/assert.h"
|
|
||||||
#include "util/memory.h"
|
|
||||||
|
|
||||||
spritebatch_t SPRITEBATCH;
|
|
||||||
|
|
||||||
void spriteBatchInit() {
|
|
||||||
SPRITEBATCH.spriteCount = 0;
|
|
||||||
SPRITEBATCH.currentTexture = NULL;
|
|
||||||
|
|
||||||
meshInit(
|
|
||||||
&SPRITEBATCH.mesh,
|
|
||||||
MESH_PRIMITIVE_TRIANGLES,
|
|
||||||
SPRITEBATCH_VERTEX_COUNT,
|
|
||||||
&SPRITEBATCH.vertices[0]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void spriteBatchPush(
|
|
||||||
texture_t *texture,
|
|
||||||
const float_t minX,
|
|
||||||
const float_t minY,
|
|
||||||
const float_t maxX,
|
|
||||||
const float_t maxY,
|
|
||||||
const color_t color,
|
|
||||||
const float_t u0,
|
|
||||||
const float_t v0,
|
|
||||||
const float_t u1,
|
|
||||||
const float_t v1
|
|
||||||
) {
|
|
||||||
// Need to flush?
|
|
||||||
if(
|
|
||||||
SPRITEBATCH.currentTexture != texture ||
|
|
||||||
SPRITEBATCH.spriteCount >= SPRITEBATCH_SPRITES_MAX
|
|
||||||
) {
|
|
||||||
spriteBatchFlush();
|
|
||||||
SPRITEBATCH.currentTexture = texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
quadBuffer(
|
|
||||||
&SPRITEBATCH.vertices[SPRITEBATCH.spriteCount * QUAD_VERTEX_COUNT],
|
|
||||||
minX, minY, maxX, maxY,
|
|
||||||
color,
|
|
||||||
u0, v0, u1, v1
|
|
||||||
);
|
|
||||||
|
|
||||||
SPRITEBATCH.spriteCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void spriteBatchPush3D(
|
|
||||||
texture_t *texture,
|
|
||||||
const vec3 min,
|
|
||||||
const vec3 max,
|
|
||||||
const color_t color,
|
|
||||||
const vec2 uv0,
|
|
||||||
const vec2 uv1
|
|
||||||
) {
|
|
||||||
// Need to flush?
|
|
||||||
if(
|
|
||||||
SPRITEBATCH.currentTexture != texture ||
|
|
||||||
SPRITEBATCH.spriteCount >= SPRITEBATCH_SPRITES_MAX
|
|
||||||
) {
|
|
||||||
spriteBatchFlush();
|
|
||||||
SPRITEBATCH.currentTexture = texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
quadBuffer3D(
|
|
||||||
&SPRITEBATCH.vertices[SPRITEBATCH.spriteCount * QUAD_VERTEX_COUNT],
|
|
||||||
min, max, color, uv0, uv1
|
|
||||||
);
|
|
||||||
|
|
||||||
SPRITEBATCH.spriteCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void spriteBatchClear() {
|
|
||||||
SPRITEBATCH.spriteCount = 0;
|
|
||||||
SPRITEBATCH.currentTexture = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void spriteBatchFlush() {
|
|
||||||
if(SPRITEBATCH.spriteCount == 0) return;
|
|
||||||
textureBind(SPRITEBATCH.currentTexture);
|
|
||||||
meshDraw(&SPRITEBATCH.mesh, 0, QUAD_VERTEX_COUNT * SPRITEBATCH.spriteCount);
|
|
||||||
spriteBatchClear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void spriteBatchDispose() {
|
|
||||||
meshDispose(&SPRITEBATCH.mesh);
|
|
||||||
}
|
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "display/mesh/quad.h"
|
|
||||||
#include "display/texture.h"
|
|
||||||
|
|
||||||
#define SPRITEBATCH_SPRITES_MAX 1
|
|
||||||
#define SPRITEBATCH_VERTEX_COUNT (SPRITEBATCH_SPRITES_MAX * QUAD_VERTEX_COUNT)
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
mesh_t mesh;
|
|
||||||
int32_t spriteCount;
|
|
||||||
texture_t *currentTexture;
|
|
||||||
meshvertex_t vertices[SPRITEBATCH_VERTEX_COUNT];
|
|
||||||
} spritebatch_t;
|
|
||||||
|
|
||||||
extern spritebatch_t SPRITEBATCH;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes a sprite batch.
|
|
||||||
*
|
|
||||||
* @param spriteBatch The sprite batch to initialize.
|
|
||||||
*/
|
|
||||||
void spriteBatchInit();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pushes a sprite to the batch. This basically "queues" it to render (well
|
|
||||||
* technically it is buffering the vertices to the mesh at the moment, but
|
|
||||||
* that is likely to change when we switch to VAOs or VBOs or even Shader UBOs).
|
|
||||||
*
|
|
||||||
* Currently changing texture pointer will cause the buffer to flush but this is
|
|
||||||
* also likely to change in the future.
|
|
||||||
*
|
|
||||||
* @param texture The texture to use for the sprite.
|
|
||||||
* @param minX The minimum x coordinate of the sprite.
|
|
||||||
* @param minY The minimum y coordinate of the sprite.
|
|
||||||
* @param maxX The maximum x coordinate of the sprite.
|
|
||||||
* @param maxY The maximum y coordinate of the sprite.
|
|
||||||
* @param color The color to tint the sprite with.
|
|
||||||
* @param u0 The texture coordinate for the top-left corner of the sprite.
|
|
||||||
* @param v0 The texture coordinate for the top-left corner of the sprite.
|
|
||||||
* @param u1 The texture coordinate for the bottom-right corner of the sprite.
|
|
||||||
* @param v1 The texture coordinate for the bottom-right corner of the sprite.
|
|
||||||
*/
|
|
||||||
void spriteBatchPush(
|
|
||||||
texture_t *texture,
|
|
||||||
const float_t minX,
|
|
||||||
const float_t minY,
|
|
||||||
const float_t maxX,
|
|
||||||
const float_t maxY,
|
|
||||||
const color_t color,
|
|
||||||
const float_t u0,
|
|
||||||
const float_t v0,
|
|
||||||
const float_t u1,
|
|
||||||
const float_t v1
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pushes a 3D sprite to the batch. This is like spriteBatchPush but takes
|
|
||||||
* 3D coordinates instead of 2D.
|
|
||||||
*
|
|
||||||
* @param texture The texture to use for the sprite.
|
|
||||||
* @param min The minimum (x,y,z) coordinate of the sprite.
|
|
||||||
* @param max The maximum (x,y,z) coordinate of the sprite.
|
|
||||||
* @param color The color to tint the sprite with.
|
|
||||||
* @param uvMin The texture coordinate for the top-left corner of the sprite.
|
|
||||||
* @param uvMax The texture coordinate for the bottom-right corner of the sprite.
|
|
||||||
*/
|
|
||||||
void spriteBatchPush3D(
|
|
||||||
texture_t *texture,
|
|
||||||
const vec3 min,
|
|
||||||
const vec3 max,
|
|
||||||
const color_t color,
|
|
||||||
const vec2 uvMin,
|
|
||||||
const vec2 uvMax
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears the sprite batch. This will mean calling flush renders nothing.
|
|
||||||
*/
|
|
||||||
void spriteBatchClear();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Flushes the sprite batch, rendering all queued sprites.
|
|
||||||
*/
|
|
||||||
void spriteBatchFlush();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disposes of the sprite batch, freeing any allocated resources.
|
|
||||||
*/
|
|
||||||
void spriteBatchDispose();
|
|
||||||
@@ -1,185 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "texture.h"
|
|
||||||
#include "assert/assert.h"
|
|
||||||
#include "util/memory.h"
|
|
||||||
#include "util/math.h"
|
|
||||||
#include "display/palette/palettelist.h"
|
|
||||||
|
|
||||||
const texture_t *TEXTURE_BOUND = NULL;
|
|
||||||
|
|
||||||
void textureInit(
|
|
||||||
texture_t *texture,
|
|
||||||
const int32_t width,
|
|
||||||
const int32_t height,
|
|
||||||
const textureformat_t format,
|
|
||||||
const texturedata_t data
|
|
||||||
) {
|
|
||||||
assertNotNull(texture, "Texture cannot be NULL");
|
|
||||||
assertTrue(width > 0 && height > 0, "width/height must be greater than 0");
|
|
||||||
|
|
||||||
memoryZero(texture, sizeof(texture_t));
|
|
||||||
texture->width = width;
|
|
||||||
texture->height = height;
|
|
||||||
|
|
||||||
#if PSP
|
|
||||||
assertTrue(
|
|
||||||
width == mathNextPowTwo(width),
|
|
||||||
"Width must be powers of 2 for PSP"
|
|
||||||
);
|
|
||||||
assertTrue(
|
|
||||||
height == mathNextPowTwo(height),
|
|
||||||
"Height must be powers of 2 for PSP"
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
glGenTextures(1, &texture->id);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, texture->id);
|
|
||||||
|
|
||||||
switch(format) {
|
|
||||||
case TEXTURE_FORMAT_RGBA:
|
|
||||||
glTexImage2D(
|
|
||||||
GL_TEXTURE_2D, 0, format, width, height, 0,
|
|
||||||
format, GL_UNSIGNED_BYTE, (void*)data.rgba.colors
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TEXTURE_FORMAT_ALPHA:
|
|
||||||
glTexImage2D(
|
|
||||||
GL_TEXTURE_2D, 0, format, width, height, 0,
|
|
||||||
format, GL_UNSIGNED_BYTE, (void*)data.alpha.data
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TEXTURE_FORMAT_PALETTE:
|
|
||||||
assertNotNull(data.palette.data, "Palette texture data cannot be NULL");
|
|
||||||
assertTrue(
|
|
||||||
data.palette.palette < PALETTE_LIST_COUNT,
|
|
||||||
"Palette index out of range"
|
|
||||||
);
|
|
||||||
|
|
||||||
// Get and validate the palette.
|
|
||||||
const palette_t *pal = PALETTE_LIST[data.palette.palette];
|
|
||||||
assertNotNull(pal, "Palette cannot be NULL");
|
|
||||||
GLenum err = glGetError();
|
|
||||||
if(err != GL_NO_ERROR) {
|
|
||||||
assertUnreachable("GL Error before setting color table");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do we support paletted textures?
|
|
||||||
bool_t havePalTex = false;
|
|
||||||
|
|
||||||
#if PSP
|
|
||||||
havePalTex = true;
|
|
||||||
#else
|
|
||||||
GLint mask = 0;
|
|
||||||
glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask);
|
|
||||||
if(mask & GL_CONTEXT_CORE_PROFILE_BIT) {
|
|
||||||
GLint n=0; glGetIntegerv(GL_NUM_EXTENSIONS, &n);
|
|
||||||
for(GLint i=0; i<n; ++i) {
|
|
||||||
const char* e = (const char*)glGetStringi(GL_EXTENSIONS, i);
|
|
||||||
if(e && strcmp(e, "GL_EXT_paletted_texture")==0) { havePalTex = true; break; }
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const char* ext = (const char*)glGetString(GL_EXTENSIONS);
|
|
||||||
havePalTex = ext && strstr(ext, "GL_EXT_paletted_texture");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if(!havePalTex) {
|
|
||||||
// Not supported, convert to RGBA using lookup
|
|
||||||
color_t formatted[width * height];
|
|
||||||
for(int32_t i = 0; i < width * height; i++) {
|
|
||||||
uint8_t index = data.palette.data[i];
|
|
||||||
assertTrue(
|
|
||||||
index < pal->colorCount,
|
|
||||||
"Palette index out of range"
|
|
||||||
);
|
|
||||||
formatted[i] = pal->colors[index];
|
|
||||||
}
|
|
||||||
glTexImage2D(
|
|
||||||
GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
|
|
||||||
GL_RGBA, GL_UNSIGNED_BYTE, (void*)formatted
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// Supported.
|
|
||||||
#if PSP
|
|
||||||
// PSP requires the color table itself to be a power of two
|
|
||||||
assertTrue(
|
|
||||||
pal->colorCount == mathNextPowTwo(pal->colorCount),
|
|
||||||
"Palette color count must be a power of 2 for PSP"
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
glTexImage2D(
|
|
||||||
GL_TEXTURE_2D,
|
|
||||||
0, GL_COLOR_INDEX8_EXT,
|
|
||||||
width, height,
|
|
||||||
0, GL_COLOR_INDEX8_EXT,
|
|
||||||
GL_UNSIGNED_BYTE, (void*)data.palette.data
|
|
||||||
);
|
|
||||||
|
|
||||||
glColorTableEXT(
|
|
||||||
GL_TEXTURE_2D, GL_RGBA, pal->colorCount, GL_RGBA,
|
|
||||||
GL_UNSIGNED_BYTE, (const void*)pal->colors
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
assertUnreachable("Unknown texture format");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void textureBind(const texture_t *texture) {
|
|
||||||
if(TEXTURE_BOUND == texture) return;
|
|
||||||
|
|
||||||
if(texture == NULL) {
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
glDisable(GL_TEXTURE_2D);
|
|
||||||
#endif
|
|
||||||
TEXTURE_BOUND = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
assertTrue(
|
|
||||||
texture->id != 0,
|
|
||||||
"Texture ID must not be 0"
|
|
||||||
);
|
|
||||||
assertTrue(
|
|
||||||
texture->width > 0 && texture->height > 0,
|
|
||||||
"Texture width and height must be greater than 0"
|
|
||||||
);
|
|
||||||
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
glEnable(GL_TEXTURE_2D);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, texture->id);
|
|
||||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
||||||
#endif
|
|
||||||
TEXTURE_BOUND = texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
void textureDispose(texture_t *texture) {
|
|
||||||
assertNotNull(texture, "Texture cannot be NULL");
|
|
||||||
assertTrue(texture->id != 0, "Texture ID must not be 0");
|
|
||||||
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
glDeleteTextures(1, &texture->id);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "display/color.h"
|
|
||||||
#include "display/displaydefs.h"
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
TEXTURE_FORMAT_RGBA = GL_RGBA,
|
|
||||||
TEXTURE_FORMAT_ALPHA = GL_ALPHA,
|
|
||||||
TEXTURE_FORMAT_PALETTE = GL_COLOR_INDEX8_EXT,
|
|
||||||
#endif
|
|
||||||
} textureformat_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
#if DISPLAY_SDL2
|
|
||||||
GLuint id;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int32_t width;
|
|
||||||
int32_t height;
|
|
||||||
} texture_t;
|
|
||||||
|
|
||||||
typedef union {
|
|
||||||
struct {
|
|
||||||
color_t *colors;
|
|
||||||
} rgba;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
uint8_t palette;
|
|
||||||
uint8_t *data;
|
|
||||||
} palette;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
uint8_t *data;
|
|
||||||
} alpha;
|
|
||||||
} texturedata_t;
|
|
||||||
|
|
||||||
extern const texture_t *TEXTURE_BOUND;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes a texture.
|
|
||||||
*
|
|
||||||
* @param texture The texture to initialize.
|
|
||||||
* @param width The width of the texture.
|
|
||||||
* @param height The height of the texture.
|
|
||||||
* @param format The format of the texture (e.g., GL_RGBA, GL_ALPHA).
|
|
||||||
* @param data The data for the texture, the format changes per format.
|
|
||||||
*/
|
|
||||||
void textureInit(
|
|
||||||
texture_t *texture,
|
|
||||||
const int32_t width,
|
|
||||||
const int32_t height,
|
|
||||||
const textureformat_t format,
|
|
||||||
const texturedata_t data
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Binds a texture for rendering. Providing NULL will unbind any texture.
|
|
||||||
*
|
|
||||||
* @param texture The texture to bind.
|
|
||||||
*/
|
|
||||||
void textureBind(const texture_t *texture);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disposes a texture.
|
|
||||||
*
|
|
||||||
* @param texture The texture to dispose.
|
|
||||||
*/
|
|
||||||
void textureDispose(texture_t *texture);
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user