Compare commits
63 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 64ab08973c | |||
| 94a7a38cdd | |||
| 76165e4345 | |||
| 767a1f6af8 | |||
| 20ca024100 | |||
| 3c3857c1b2 | |||
| 523342fed9 | |||
| 217ca58b1a | |||
| ec6565bf71 | |||
| cd7f06f3a1 | |||
| 8886873ed5 | |||
| a41e696b69 | |||
| 4b7cbd88bb | |||
| 789cbbc593 | |||
| 1dd87c0707 | |||
| 330044e10f | |||
| f8c5207d5c | |||
| 2caaa29124 | |||
| cdc4d07394 | |||
| 1023cde1be | |||
| a3aeed4b7c | |||
| 3b0354da54 | |||
| 622ccd22bc | |||
| 1441134aea | |||
| 0500dce7aa | |||
| 9f0dfc4e24 | |||
| aa66dd41c1 | |||
| 69fb5f3cc1 | |||
| d6b2e97777 | |||
| 98c90e6075 | |||
| f795c86a38 | |||
| c1c5774406 | |||
| 0139da4764 | |||
| ec911979fb | |||
| e51749dbc6 | |||
| 9ceb21c04f | |||
| 76a91b4736 | |||
| df744338f1 | |||
| 8803fc3806 | |||
| c26a4774a1 | |||
| 20538af4c6 | |||
| 73f222fcb7 | |||
| 67681e0f37 | |||
| 5210448ac9 | |||
| 983f42814f | |||
| 89302a2ee3 | |||
| 832f77de80 | |||
| 656144d182 | |||
| 4f926ddebf | |||
| 624039e00d | |||
| 430fcbe026 | |||
| 8e25d388fa | |||
| 3c7df0e989 | |||
| 4d0a5ca5bd | |||
| 06e9a10c98 | |||
| 836debdc0b | |||
| 1e8829ba22 | |||
| 2b1311042f | |||
| 0d69af667d | |||
| 93fed0b984 | |||
| c8838aa450 | |||
| 896a61ed0d | |||
| c7a7e604f1 |
21
.clang-format
Normal file
21
.clang-format
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
BasedOnStyle: Google
|
||||||
|
IndentWidth: 4
|
||||||
|
IndentAccessModifiers: true
|
||||||
|
ColumnLimit: 0 # Sin límite de longitud de línea
|
||||||
|
BreakBeforeBraces: Attach # Llaves en la misma línea
|
||||||
|
AllowShortIfStatementsOnASingleLine: true
|
||||||
|
AllowShortBlocksOnASingleLine: true
|
||||||
|
AllowShortFunctionsOnASingleLine: All
|
||||||
|
AlignOperands: DontAlign
|
||||||
|
AlignAfterOpenBracket: DontAlign
|
||||||
|
BinPackArguments: false
|
||||||
|
BinPackParameters: false
|
||||||
|
ContinuationIndentWidth: 4
|
||||||
|
ConstructorInitializerIndentWidth: 4
|
||||||
|
IndentWrappedFunctionNames: false
|
||||||
|
Cpp11BracedListStyle: true
|
||||||
|
BreakConstructorInitializers: BeforeColon
|
||||||
|
AllowAllConstructorInitializersOnNextLine: false
|
||||||
|
PackConstructorInitializers: Never
|
||||||
|
AllowAllArgumentsOnNextLine: false
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: false
|
||||||
102
.gitignore
vendored
Normal file
102
.gitignore
vendored
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
# IDEs and Editors
|
||||||
|
.vscode/*
|
||||||
|
.idea/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
|
||||||
|
# Build directories
|
||||||
|
build/
|
||||||
|
bin/
|
||||||
|
out/
|
||||||
|
cmake-build-*/
|
||||||
|
|
||||||
|
# Executables
|
||||||
|
orni
|
||||||
|
asteroids
|
||||||
|
*.exe
|
||||||
|
*.out
|
||||||
|
*.app
|
||||||
|
tools/pack_resources/pack_resources
|
||||||
|
tools/pack_resources/pack_resources.exe
|
||||||
|
|
||||||
|
# Releases
|
||||||
|
*.zip
|
||||||
|
*.tar.gz
|
||||||
|
*.dmg
|
||||||
|
|
||||||
|
# Generated resources
|
||||||
|
resources.pack
|
||||||
|
|
||||||
|
# Compiled Object files
|
||||||
|
*.o
|
||||||
|
*.obj
|
||||||
|
*.ko
|
||||||
|
*.elf
|
||||||
|
|
||||||
|
# Precompiled Headers
|
||||||
|
*.gch
|
||||||
|
*.pch
|
||||||
|
|
||||||
|
# Compiled Dynamic libraries
|
||||||
|
*.so
|
||||||
|
*.so.*
|
||||||
|
*.dylib
|
||||||
|
*.dll
|
||||||
|
|
||||||
|
# Compiled Static libraries
|
||||||
|
*.a
|
||||||
|
*.lib
|
||||||
|
*.la
|
||||||
|
*.lo
|
||||||
|
|
||||||
|
# CMake
|
||||||
|
CMakeCache.txt
|
||||||
|
CMakeFiles/
|
||||||
|
CMakeScripts/
|
||||||
|
cmake_install.cmake
|
||||||
|
install_manifest.txt
|
||||||
|
compile_commands.json
|
||||||
|
CTestTestfile.cmake
|
||||||
|
_deps/
|
||||||
|
|
||||||
|
# Debug files
|
||||||
|
*.dSYM/
|
||||||
|
*.su
|
||||||
|
*.idb
|
||||||
|
*.pdb
|
||||||
|
*.ilk
|
||||||
|
|
||||||
|
# Core dumps
|
||||||
|
# core
|
||||||
|
# core.*
|
||||||
|
# *.core
|
||||||
|
|
||||||
|
# macOS
|
||||||
|
.DS_Store
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
._*
|
||||||
|
|
||||||
|
# Windows
|
||||||
|
Thumbs.db
|
||||||
|
Thumbs.db:encryptable
|
||||||
|
ehthumbs.db
|
||||||
|
ehthumbs_vista.db
|
||||||
|
*.stackdump
|
||||||
|
[Dd]esktop.ini
|
||||||
|
|
||||||
|
# Linux
|
||||||
|
*~
|
||||||
|
.directory
|
||||||
|
.fuse_hidden*
|
||||||
|
.Trash-*
|
||||||
|
.nfs*
|
||||||
|
|
||||||
|
# Temporary files
|
||||||
|
*.tmp
|
||||||
|
*.temp
|
||||||
|
*.log
|
||||||
|
*.bak
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
BIN
Asteroids.ico
BIN
Asteroids.ico
Binary file not shown.
|
Before Width: | Height: | Size: 2.2 KiB |
817
CLAUDE.md
Normal file
817
CLAUDE.md
Normal file
@@ -0,0 +1,817 @@
|
|||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## Project Overview
|
||||||
|
|
||||||
|
This is **Orni Attack**, an **Asteroids-style game** originally written in **Turbo Pascal 7 for DOS** (1999), now being **migrated to modern C++20 with SDL3**. The game features a spaceship that must avoid and destroy enemies (pentagonal "ORNIs"). This is a **phased migration** preserving the original game feel.
|
||||||
|
|
||||||
|
**Language**: All code, comments, and variable names are in **Catalan/Valencian** (preserved from original).
|
||||||
|
|
||||||
|
**Current Status**: **BETA 3.0** - Modernized architecture with dynamic windows, modular code organization, viewport scaling, and auto-generated project metadata.
|
||||||
|
|
||||||
|
## Build System
|
||||||
|
|
||||||
|
Based on `/home/sergio/gitea/pollo` project structure, now with **CMake as build authority** and **automatic file discovery**.
|
||||||
|
|
||||||
|
### Basic Build Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make # Compile (delegates to CMake)
|
||||||
|
make debug # Debug build
|
||||||
|
make clean # Clean artifacts
|
||||||
|
./orni # Run
|
||||||
|
```
|
||||||
|
|
||||||
|
### Release Packaging
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make macos_release # macOS .app bundle + .dmg (Apple Silicon)
|
||||||
|
make linux_release # Linux .tar.gz
|
||||||
|
make windows_release # Windows .zip (requires MinGW on Windows)
|
||||||
|
make windows_cross # Cross-compile Windows from Linux/macOS
|
||||||
|
make rpi_release # Raspberry Pi ARM64 cross-compile
|
||||||
|
```
|
||||||
|
|
||||||
|
### Build Files
|
||||||
|
|
||||||
|
- **CMakeLists.txt** - CMake configuration (C++20, SDL3, auto-discovers .cpp files)
|
||||||
|
- **Makefile** - Wrapper for compilation + complex packaging recipes
|
||||||
|
- **source/project.h.in** - Template for auto-generated project.h
|
||||||
|
- **build/project.h** - Auto-generated (by CMake) with project constants
|
||||||
|
- **release/** - Platform-specific resources (icons, .rc, .plist, frameworks, DLLs)
|
||||||
|
|
||||||
|
### Architecture: Hybrid CMake + Makefile
|
||||||
|
|
||||||
|
**CMake handles**: Compilation (simple, standard, IDE-friendly)
|
||||||
|
- Auto-discovers all `.cpp` files in `source/core/` and `source/game/`
|
||||||
|
- Excludes `source/legacy/` automatically
|
||||||
|
- Generates `build/project.h` from template
|
||||||
|
- Links SDL3
|
||||||
|
|
||||||
|
**Makefile handles**: Packaging (complex bash scripts)
|
||||||
|
- Delegates compilation to CMake (`make` → `cmake --build build`)
|
||||||
|
- Contains 5 release packaging targets (macOS, Linux, Windows, RPI, Windows-cross)
|
||||||
|
- Includes: code signing, framework symlinks, DMG creation, cross-compilation
|
||||||
|
|
||||||
|
### Project Metadata System
|
||||||
|
|
||||||
|
**Single source of truth** in `CMakeLists.txt`:
|
||||||
|
|
||||||
|
```cmake
|
||||||
|
project(orni VERSION 0.3.0)
|
||||||
|
set(PROJECT_LONG_NAME "Orni Attack")
|
||||||
|
set(PROJECT_COPYRIGHT "© 1999 Visente i Sergi, 2025 Port")
|
||||||
|
```
|
||||||
|
|
||||||
|
**Auto-generated** `build/project.h`:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
namespace Project {
|
||||||
|
constexpr const char* NAME = "orni";
|
||||||
|
constexpr const char* LONG_NAME = "Orni Attack";
|
||||||
|
constexpr const char* VERSION = "0.3.0";
|
||||||
|
constexpr const char* COPYRIGHT = "© 1999 Visente i Sergi, 2025 Port";
|
||||||
|
constexpr const char* GIT_HASH = "abc1234"; // From git rev-parse
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Window title** (dynamic): `Orni Attack v0.3.0 (© 1999 Visente i Sergi, 2025 Port)`
|
||||||
|
|
||||||
|
### File Discovery
|
||||||
|
|
||||||
|
**Automatic** - no manual maintenance needed:
|
||||||
|
|
||||||
|
```cmake
|
||||||
|
# CMakeLists.txt automatically finds:
|
||||||
|
file(GLOB_RECURSE CORE_SOURCES "source/core/*.cpp")
|
||||||
|
file(GLOB_RECURSE GAME_SOURCES "source/game/*.cpp")
|
||||||
|
# + source/main.cpp
|
||||||
|
# - source/legacy/* (excluded)
|
||||||
|
```
|
||||||
|
|
||||||
|
**When you create a new file** like `source/game/entities/asteroide.cpp`:
|
||||||
|
1. Just create it in the appropriate directory
|
||||||
|
2. Run `make`
|
||||||
|
3. CMake automatically detects and compiles it
|
||||||
|
|
||||||
|
**No need to edit** Makefile or CMakeLists.txt!
|
||||||
|
|
||||||
|
### Cross-Platform Notes
|
||||||
|
|
||||||
|
- **macOS**: Requires `create-dmg` (auto-installed via Homebrew)
|
||||||
|
- **Windows**: Compile natively with MinGW or use `make windows_cross` on Linux/macOS
|
||||||
|
- **Windows cross**: Requires `x86_64-w64-mingw32-g++` toolchain
|
||||||
|
- **RPI cross**: Requires `aarch64-linux-gnu-g++` toolchain
|
||||||
|
- **Frameworks**: macOS release includes SDL3.xcframework with symlink recreation
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
### File Structure (BETA 3.0)
|
||||||
|
|
||||||
|
```
|
||||||
|
source/
|
||||||
|
├── core/ - Reusable engine layer
|
||||||
|
│ ├── defaults.hpp - Configuration constants (SINGLE SOURCE OF TRUTH)
|
||||||
|
│ ├── types.hpp - Data structures (IPunt, Punt, Triangle, Poligon)
|
||||||
|
│ └── rendering/
|
||||||
|
│ ├── sdl_manager.hpp/cpp - SDL3 window management + viewport scaling
|
||||||
|
│ └── primitives.hpp/cpp - Pure geometric functions
|
||||||
|
├── game/ - Asteroids-specific game logic
|
||||||
|
│ ├── constants.hpp - Legacy constant aliases
|
||||||
|
│ └── joc_asteroides.hpp/cpp - Game loop, physics, rendering
|
||||||
|
├── utils/ - Shared utilities (empty for now)
|
||||||
|
├── main.cpp - Entry point, F1/F2/F3 window controls
|
||||||
|
└── legacy/
|
||||||
|
└── asteroids.cpp - Original Pascal code (reference only)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Key architectural decisions:**
|
||||||
|
- **core/** contains reusable, game-agnostic code
|
||||||
|
- **game/** contains Asteroids-specific logic
|
||||||
|
- All constants centralized in `core/defaults.hpp`
|
||||||
|
- Backward compatibility via `game/constants.hpp` aliases
|
||||||
|
|
||||||
|
### Core Data Structures
|
||||||
|
|
||||||
|
The game uses **polar coordinates** for all geometric objects (preserved from Pascal original):
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct IPunt {
|
||||||
|
float r; // Radius
|
||||||
|
float angle; // Angle in radians
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Punt {
|
||||||
|
int x, y; // Cartesian coordinates
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Triangle { // Player's ship (nau_)
|
||||||
|
IPunt p1, p2, p3; // 3 polar points
|
||||||
|
Punt centre; // Center position
|
||||||
|
float angle; // Orientation
|
||||||
|
float velocitat; // Speed (px/s)
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Poligon { // Enemies (orni_) and bullets (bales_)
|
||||||
|
std::array<IPunt, MAX_IPUNTS> ipuntx; // Polar points
|
||||||
|
Punt centre;
|
||||||
|
float angle; // Movement direction
|
||||||
|
float velocitat; // Speed (units/frame)
|
||||||
|
uint8_t n; // Number of sides
|
||||||
|
float drotacio; // Rotation delta per frame
|
||||||
|
float rotacio; // Current rotation angle
|
||||||
|
bool esta; // Is active?
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Constants (joc_asteroides.hpp)
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
namespace Constants {
|
||||||
|
constexpr int MARGE_DALT = 20; // Top margin
|
||||||
|
constexpr int MARGE_BAIX = 460; // Bottom margin
|
||||||
|
constexpr int MARGE_ESQ = 20; // Left margin
|
||||||
|
constexpr int MARGE_DRET = 620; // Right margin
|
||||||
|
constexpr int MAX_IPUNTS = 30; // Max polygon points
|
||||||
|
constexpr int MAX_ORNIS = 15; // Max enemies
|
||||||
|
constexpr int MAX_BALES = 3; // Max bullets
|
||||||
|
constexpr int VELOCITAT = 2; // Base velocity
|
||||||
|
constexpr int VELOCITAT_MAX = 6; // Max velocity
|
||||||
|
constexpr float PI = 3.14159265359f;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Game Loop (main.cpp)
|
||||||
|
|
||||||
|
**Time-based physics** with real delta_time:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Lines 21-56
|
||||||
|
Uint64 last_time = SDL_GetTicks();
|
||||||
|
while (running) {
|
||||||
|
// Calculate real delta_time
|
||||||
|
Uint64 current_time = SDL_GetTicks();
|
||||||
|
float delta_time = (current_time - last_time) / 1000.0f; // ms → s
|
||||||
|
last_time = current_time;
|
||||||
|
|
||||||
|
// Cap at 50ms (20 FPS minimum)
|
||||||
|
if (delta_time > 0.05f) delta_time = 0.05f;
|
||||||
|
|
||||||
|
// Process events
|
||||||
|
while (SDL_PollEvent(&event)) {
|
||||||
|
joc.processar_input(event);
|
||||||
|
// Handle quit/ESC
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update + render
|
||||||
|
joc.actualitzar(delta_time);
|
||||||
|
sdl.neteja(0, 0, 0);
|
||||||
|
joc.dibuixar();
|
||||||
|
sdl.presenta();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Critical**: Delta_time is **real** and **variable**, not fixed at 0.016f. All physics must multiply by delta_time.
|
||||||
|
|
||||||
|
## SDL3 API Notes
|
||||||
|
|
||||||
|
SDL3 has breaking changes from SDL2:
|
||||||
|
|
||||||
|
- `SDL_CreateRenderer(window, nullptr)` - no flags parameter
|
||||||
|
- `event.key.key` instead of `event.key.keysym.sym`
|
||||||
|
- `SDL_EVENT_KEY_DOWN` instead of `SDL_KEYDOWN`
|
||||||
|
- `SDL_EVENT_QUIT` instead of `SDL_QUIT`
|
||||||
|
- `SDL_GetKeyboardState(nullptr)` - state-based input for continuous keys
|
||||||
|
|
||||||
|
## Physics System
|
||||||
|
|
||||||
|
### Ship Movement (joc_asteroides.cpp:67-155)
|
||||||
|
|
||||||
|
**State-based input** (not event-based) for smooth controls:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
const bool* keyboard_state = SDL_GetKeyboardState(nullptr);
|
||||||
|
|
||||||
|
if (keyboard_state[SDL_SCANCODE_RIGHT])
|
||||||
|
nau_.angle += ROTATION_SPEED * delta_time;
|
||||||
|
if (keyboard_state[SDL_SCANCODE_LEFT])
|
||||||
|
nau_.angle -= ROTATION_SPEED * delta_time;
|
||||||
|
if (keyboard_state[SDL_SCANCODE_UP])
|
||||||
|
nau_.velocitat += ACCELERATION * delta_time;
|
||||||
|
```
|
||||||
|
|
||||||
|
**Physics constants** (calibrated for ~20 FPS feel):
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
constexpr float ROTATION_SPEED = 2.5f; // rad/s (~143°/s)
|
||||||
|
constexpr float ACCELERATION = 100.0f; // px/s²
|
||||||
|
constexpr float MAX_VELOCITY = 200.0f; // px/s
|
||||||
|
constexpr float FRICTION = 6.0f; // px/s²
|
||||||
|
```
|
||||||
|
|
||||||
|
**Position calculation** (angle-PI/2 because angle=0 points up, not right):
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
float dy = (nau_.velocitat * delta_time) * std::sin(nau_.angle - PI/2.0f);
|
||||||
|
float dx = (nau_.velocitat * delta_time) * std::cos(nau_.angle - PI/2.0f);
|
||||||
|
nau_.centre.y += round(dy);
|
||||||
|
nau_.centre.x += round(dx);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Visual velocity effect**: Ship triangle grows when moving (joc_asteroides.cpp:162-164):
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Scale 200 px/s → 6 px visual effect (like original)
|
||||||
|
float velocitat_visual = nau_.velocitat / 33.33f;
|
||||||
|
rota_tri(nau_, nau_.angle, velocitat_visual, true);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Enemy Movement (joc_asteroides.cpp:367-405) - FASE 8
|
||||||
|
|
||||||
|
Autonomous movement with random direction changes:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void mou_orni(Poligon& orni, float delta_time) {
|
||||||
|
// 5% probability to change direction
|
||||||
|
if (rand() < 0.05f * RAND_MAX)
|
||||||
|
orni.angle = random() * 2*PI;
|
||||||
|
|
||||||
|
// Move (2 px/frame * 20 FPS = 40 px/s)
|
||||||
|
float velocitat_efectiva = orni.velocitat * 20.0f * delta_time;
|
||||||
|
float dy = velocitat_efectiva * sin(orni.angle - PI/2.0f);
|
||||||
|
float dx = velocitat_efectiva * cos(orni.angle - PI/2.0f);
|
||||||
|
orni.centre.y += round(dy);
|
||||||
|
orni.centre.x += round(dx);
|
||||||
|
|
||||||
|
// Bounce on walls
|
||||||
|
if (x < MARGE_ESQ || x > MARGE_DRET)
|
||||||
|
orni.angle = PI - orni.angle; // Horizontal reflection
|
||||||
|
if (y < MARGE_DALT || y > MARGE_BAIX)
|
||||||
|
orni.angle = 2*PI - orni.angle; // Vertical reflection
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Bullet Movement (joc_asteroides.cpp:444-465) - FASE 9
|
||||||
|
|
||||||
|
Straight-line movement, deactivates when leaving screen:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void mou_bales(Poligon& bala, float delta_time) {
|
||||||
|
// Fast movement (6 px/frame * 20 FPS = 120 px/s)
|
||||||
|
float velocitat_efectiva = bala.velocitat * 20.0f * delta_time;
|
||||||
|
float dy = velocitat_efectiva * sin(bala.angle - PI/2.0f);
|
||||||
|
float dx = velocitat_efectiva * cos(bala.angle - PI/2.0f);
|
||||||
|
bala.centre.y += round(dy);
|
||||||
|
bala.centre.x += round(dx);
|
||||||
|
|
||||||
|
// Deactivate if out of bounds
|
||||||
|
if (x < MARGE_ESQ || x > MARGE_DRET ||
|
||||||
|
y < MARGE_DALT || y > MARGE_BAIX)
|
||||||
|
bala.esta = false;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Rendering System
|
||||||
|
|
||||||
|
### Coordinate Conversion
|
||||||
|
|
||||||
|
**Polar → Cartesian** with rotation (used in `rota_tri` and `rota_pol`):
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// For each polar point
|
||||||
|
int x = round((r + velocitat) * cos(angle_punt + angle_object)) + centre.x;
|
||||||
|
int y = round((r + velocitat) * sin(angle_punt + angle_object)) + centre.y;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Line Drawing (joc_asteroides.cpp:230-298)
|
||||||
|
|
||||||
|
Currently uses **SDL_RenderLine** for efficiency:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
bool linea(int x1, int y1, int x2, int y2, bool dibuixar) {
|
||||||
|
if (dibuixar && renderer_) {
|
||||||
|
SDL_SetRenderDrawColor(renderer_, 255, 255, 255, 255); // White
|
||||||
|
SDL_RenderLine(renderer_, x1, y1, x2, y2);
|
||||||
|
}
|
||||||
|
return false; // Collision detection TODO (Phase 10)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note**: Original Bresenham algorithm preserved in comments for **Phase 10** (pixel-perfect collision detection).
|
||||||
|
|
||||||
|
### Ship Rendering (joc_asteroides.cpp:300-337)
|
||||||
|
|
||||||
|
Triangle with 3 lines:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void rota_tri(const Triangle& tri, float angul, float velocitat, bool dibuixar) {
|
||||||
|
// Convert 3 polar points to Cartesian
|
||||||
|
int x1 = round((tri.p1.r + velocitat) * cos(tri.p1.angle + angul)) + tri.centre.x;
|
||||||
|
int y1 = round((tri.p1.r + velocitat) * sin(tri.p1.angle + angul)) + tri.centre.y;
|
||||||
|
// ... same for p2, p3
|
||||||
|
|
||||||
|
// Draw 3 lines
|
||||||
|
linea(x1, y1, x2, y2, dibuixar);
|
||||||
|
linea(x1, y1, x3, y3, dibuixar);
|
||||||
|
linea(x3, y3, x2, y2, dibuixar);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Polygon Rendering (joc_asteroides.cpp:339-365)
|
||||||
|
|
||||||
|
Enemies and bullets:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void rota_pol(const Poligon& pol, float angul, bool dibuixar) {
|
||||||
|
// Convert all polar points to Cartesian
|
||||||
|
std::array<Punt, MAX_IPUNTS> xy;
|
||||||
|
for (int i = 0; i < pol.n; i++) {
|
||||||
|
xy[i].x = round(pol.ipuntx[i].r * cos(pol.ipuntx[i].angle + angul)) + pol.centre.x;
|
||||||
|
xy[i].y = round(pol.ipuntx[i].r * sin(pol.ipuntx[i].angle + angul)) + pol.centre.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw lines between consecutive points
|
||||||
|
for (int i = 0; i < pol.n - 1; i++)
|
||||||
|
linea(xy[i].x, xy[i].y, xy[i+1].x, xy[i+1].y, dibuixar);
|
||||||
|
|
||||||
|
// Close polygon
|
||||||
|
linea(xy[pol.n-1].x, xy[pol.n-1].y, xy[0].x, xy[0].y, dibuixar);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Input System - FASE 9
|
||||||
|
|
||||||
|
### Continuous Input (actualitzar)
|
||||||
|
|
||||||
|
Arrow keys use **state-based** polling:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
const bool* keyboard_state = SDL_GetKeyboardState(nullptr);
|
||||||
|
if (keyboard_state[SDL_SCANCODE_UP]) { /* accelerate */ }
|
||||||
|
```
|
||||||
|
|
||||||
|
### Event-Based Input (processar_input)
|
||||||
|
|
||||||
|
SPACE bar for shooting (joc_asteroides.cpp:174-212):
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void processar_input(const SDL_Event& event) {
|
||||||
|
if (event.type == SDL_EVENT_KEY_DOWN) {
|
||||||
|
if (event.key.key == SDLK_SPACE) {
|
||||||
|
// Find first inactive bullet
|
||||||
|
for (auto& bala : bales_) {
|
||||||
|
if (!bala.esta) {
|
||||||
|
bala.esta = true;
|
||||||
|
bala.centre = nau_.centre; // Spawn at ship
|
||||||
|
bala.angle = nau_.angle; // Fire in ship direction
|
||||||
|
bala.velocitat = 6.0f; // High speed
|
||||||
|
break; // Only one bullet at a time
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Initialization (joc_asteroides.cpp:15-65)
|
||||||
|
|
||||||
|
### Ship (lines 20-34)
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Triangle with 3 polar points (r=12, angles at 270°, 45°, 135°)
|
||||||
|
nau_.p1.r = 12.0f;
|
||||||
|
nau_.p1.angle = 3.0f * PI / 2.0f; // Points up
|
||||||
|
nau_.p2.r = 12.0f;
|
||||||
|
nau_.p2.angle = PI / 4.0f; // Back-right
|
||||||
|
nau_.p3.r = 12.0f;
|
||||||
|
nau_.p3.angle = 3.0f * PI / 4.0f; // Back-left
|
||||||
|
nau_.centre = {320, 240};
|
||||||
|
nau_.angle = 0.0f;
|
||||||
|
nau_.velocitat = 0.0f;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Enemies (lines 39-54) - FASE 7
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
for (int i = 0; i < MAX_ORNIS; i++) {
|
||||||
|
crear_poligon_regular(orni_[i], 5, 20.0f); // Pentagon, r=20
|
||||||
|
orni_[i].centre.x = rand(30, 610);
|
||||||
|
orni_[i].centre.y = rand(30, 450);
|
||||||
|
orni_[i].angle = rand(0, 360) * PI/180;
|
||||||
|
orni_[i].esta = true;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Bullets (lines 56-64) - FASE 9
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
for (int i = 0; i < MAX_BALES; i++) {
|
||||||
|
crear_poligon_regular(bales_[i], 5, 5.0f); // Small pentagon, r=5
|
||||||
|
bales_[i].esta = false; // Initially inactive
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Update Loop (joc_asteroides.cpp:67-155)
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void actualitzar(float delta_time) {
|
||||||
|
// 1. Ship input + physics (lines 68-125)
|
||||||
|
// - Keyboard state polling
|
||||||
|
// - Rotation, acceleration, friction
|
||||||
|
// - Position update with boundary checking
|
||||||
|
|
||||||
|
// 2. Enemy movement (lines 137-147) - FASE 8
|
||||||
|
for (auto& enemy : orni_) {
|
||||||
|
if (enemy.esta) {
|
||||||
|
mou_orni(enemy, delta_time);
|
||||||
|
enemy.rotacio += enemy.drotacio; // Visual rotation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Bullet movement (lines 149-154) - FASE 9
|
||||||
|
for (auto& bala : bales_) {
|
||||||
|
if (bala.esta)
|
||||||
|
mou_bales(bala, delta_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Phase 10: Collision detection
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Draw Loop (joc_asteroides.cpp:157-184)
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void dibuixar() {
|
||||||
|
// 1. Ship (if alive)
|
||||||
|
if (itocado_ == 0) {
|
||||||
|
float velocitat_visual = nau_.velocitat / 33.33f;
|
||||||
|
rota_tri(nau_, nau_.angle, velocitat_visual, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Enemies (FASE 7)
|
||||||
|
for (const auto& enemy : orni_) {
|
||||||
|
if (enemy.esta)
|
||||||
|
rota_pol(enemy, enemy.rotacio, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Bullets (FASE 9)
|
||||||
|
for (const auto& bala : bales_) {
|
||||||
|
if (bala.esta)
|
||||||
|
rota_pol(bala, 0.0f, true); // No visual rotation
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Phase 11: Draw borders
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Migration Progress
|
||||||
|
|
||||||
|
### ✅ Phase 0: Project Setup
|
||||||
|
- CMakeLists.txt + Makefile (based on pollo)
|
||||||
|
- Stub files created
|
||||||
|
|
||||||
|
### ✅ Phase 1: SDL Manager
|
||||||
|
- SDLManager class (sdl_manager.hpp/cpp)
|
||||||
|
- Window + renderer initialization
|
||||||
|
- Fixed SDL3 API differences
|
||||||
|
|
||||||
|
### ✅ Phase 2: Data Structures
|
||||||
|
- IPunt, Punt, Triangle, Poligon defined
|
||||||
|
- Constants namespace with constexpr
|
||||||
|
|
||||||
|
### ✅ Phase 3: Geometry Functions
|
||||||
|
- modul(), diferencia(), distancia(), angle_punt()
|
||||||
|
- crear_poligon_regular()
|
||||||
|
|
||||||
|
### ✅ Phase 4: Line Drawing
|
||||||
|
- linea() with SDL_RenderLine
|
||||||
|
- Bresenham preserved in comments for Phase 10
|
||||||
|
|
||||||
|
### ✅ Phase 5: Ship Rendering
|
||||||
|
- rota_tri() polar→Cartesian conversion
|
||||||
|
- Ship initialization
|
||||||
|
|
||||||
|
### ✅ Phase 6: Ship Movement
|
||||||
|
- **Critical fix**: Event-based → State-based input (SDL_GetKeyboardState)
|
||||||
|
- **Critical fix**: Fixed delta_time (0.016f) → Real delta_time calculation
|
||||||
|
- **Critical fix**: Visual velocity scaling (200 px/s → 6 px visual)
|
||||||
|
- Time-based physics (all values in px/s)
|
||||||
|
- Rotation, acceleration, friction, boundary checking
|
||||||
|
|
||||||
|
### ✅ Phase 7: Enemy Rendering
|
||||||
|
- rota_pol() for polygons
|
||||||
|
- 15 random pentagons initialized
|
||||||
|
- Visual rotation (enemy.rotacio)
|
||||||
|
|
||||||
|
### ✅ Phase 8: Enemy AI & Movement
|
||||||
|
- **mou_orni()** (joc_asteroides.cpp:367-405)
|
||||||
|
- 5% random direction change
|
||||||
|
- Polar movement (40 px/s)
|
||||||
|
- Boundary bounce (angle reflection)
|
||||||
|
- Integrated in actualitzar() (lines 137-147)
|
||||||
|
|
||||||
|
### ✅ Phase 9: Bullet System
|
||||||
|
- **Bullet initialization** (joc_asteroides.cpp:56-64)
|
||||||
|
- 3 bullets, initially inactive
|
||||||
|
- Small pentagons (r=5)
|
||||||
|
- **Shooting with SPACE** (joc_asteroides.cpp:174-212)
|
||||||
|
- Spawns at ship position
|
||||||
|
- Fires in ship direction
|
||||||
|
- Only one bullet at a time
|
||||||
|
- **mou_bales()** (joc_asteroides.cpp:444-465)
|
||||||
|
- Fast rectlinear movement (120 px/s)
|
||||||
|
- Deactivates when out of bounds
|
||||||
|
- **Drawing** (joc_asteroides.cpp:175-181)
|
||||||
|
- No visual rotation
|
||||||
|
|
||||||
|
### 🔲 Phase 10: Collision Detection & Death (NEXT)
|
||||||
|
- **Collision detection**:
|
||||||
|
- Restore Bresenham pixel-perfect algorithm
|
||||||
|
- Detect ship-enemy collision → tocado()
|
||||||
|
- Detect bullet-enemy collision → destroy enemy
|
||||||
|
- **Death sequence** (tocado):
|
||||||
|
- Explosion animation (itocado_ counter)
|
||||||
|
- Ship shrinking
|
||||||
|
- Debris particles (chatarra_cosmica)
|
||||||
|
- Respawn after delay
|
||||||
|
- **Important**: Original Pascal used bit-packed framebuffer (llig() function)
|
||||||
|
- Need to adapt to SDL3 rendering pipeline
|
||||||
|
- Options: render to texture, software buffer, or geometric collision
|
||||||
|
|
||||||
|
### 🔲 Phase 11: Polish & Refinements
|
||||||
|
- Draw borders (marges)
|
||||||
|
- Text rendering with SDL_ttf (TODO for later)
|
||||||
|
- Sound effects (optional)
|
||||||
|
- Score system (optional)
|
||||||
|
|
||||||
|
### 🔲 Phase 12: Cross-Platform Testing
|
||||||
|
- Test on Linux, macOS, Windows
|
||||||
|
- Create release builds
|
||||||
|
- Package with resources
|
||||||
|
|
||||||
|
## Known Issues & Tuning Needed
|
||||||
|
|
||||||
|
1. **Ship physics constants**: User mentioned "sigue sin ir fino" - may need adjustment:
|
||||||
|
- `ROTATION_SPEED` (currently 2.5 rad/s)
|
||||||
|
- `ACCELERATION` (currently 100.0 px/s²)
|
||||||
|
- `MAX_VELOCITY` (currently 200.0 px/s)
|
||||||
|
- `FRICTION` (currently 6.0 px/s²)
|
||||||
|
|
||||||
|
2. **Enemy movement**: May need speed/bounce angle tuning
|
||||||
|
- `VELOCITAT_SCALE` (currently 20.0)
|
||||||
|
- Reflection angles (PI - angle, 2*PI - angle)
|
||||||
|
|
||||||
|
3. **Bullet speed**: May need adjustment
|
||||||
|
- `velocitat = 6.0f` (120 px/s)
|
||||||
|
|
||||||
|
## Important Pascal References (Original Code)
|
||||||
|
|
||||||
|
The original Pascal game is in `source/ASTEROID.PAS` (if available). Key procedures:
|
||||||
|
|
||||||
|
- `teclapuls` - Keyboard handler (converted to SDL_GetKeyboardState)
|
||||||
|
- `mou_nau` - Ship movement (now actualitzar ship section)
|
||||||
|
- `mou_orni` - Enemy movement (joc_asteroides.cpp:367-405)
|
||||||
|
- `mou_bales` - Bullet movement (joc_asteroides.cpp:444-465)
|
||||||
|
- `rota_tri` - Ship rendering (joc_asteroides.cpp:300-337)
|
||||||
|
- `rota_pol` - Polygon rendering (joc_asteroides.cpp:339-365)
|
||||||
|
- `linea` - Bresenham line (joc_asteroides.cpp:230-298)
|
||||||
|
- `tocado` - Death sequence (TODO Phase 10)
|
||||||
|
|
||||||
|
## Controls
|
||||||
|
|
||||||
|
- **Arrow Keys** (UP/DOWN/LEFT/RIGHT): Ship movement (continuous)
|
||||||
|
- **SPACE**: Shoot (event-based)
|
||||||
|
- **ESC**: Quit
|
||||||
|
|
||||||
|
## Debug Output
|
||||||
|
|
||||||
|
Ship debug info printed every second (joc_asteroides.cpp:115-125):
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
static float time_accumulator = 0.0f;
|
||||||
|
time_accumulator += delta_time;
|
||||||
|
if (time_accumulator >= 1.0f) {
|
||||||
|
std::cout << "Nau: pos(" << nau_.centre.x << "," << nau_.centre.y
|
||||||
|
<< ") vel=" << (int)nau_.velocitat << " px/s"
|
||||||
|
<< " angle=" << (int)(nau_.angle * 180/PI) << "°"
|
||||||
|
<< " dt=" << (int)(delta_time * 1000) << "ms" << std::endl;
|
||||||
|
time_accumulator -= 1.0f;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Next Session Priorities
|
||||||
|
|
||||||
|
1. **Phase 10: Collision Detection**
|
||||||
|
- Most complex phase
|
||||||
|
- Need to decide: geometric vs pixel-perfect collision
|
||||||
|
- Implement tocado() death sequence
|
||||||
|
- Bullet-enemy collision
|
||||||
|
|
||||||
|
2. **Phase 11: Polish**
|
||||||
|
- Draw borders
|
||||||
|
- Consider text rendering (score, lives)
|
||||||
|
|
||||||
|
3. **Phase 12: Release**
|
||||||
|
- Cross-platform testing
|
||||||
|
- Final physics tuning
|
||||||
|
|
||||||
|
## IMPORTANT: Modernization Architecture (BETA 3.0)
|
||||||
|
|
||||||
|
Starting from BETA 3.0, the project has evolved into a professional modular architecture:
|
||||||
|
|
||||||
|
### Structural Changes
|
||||||
|
|
||||||
|
**Before (BETA 2.2):**
|
||||||
|
```
|
||||||
|
source/
|
||||||
|
├── main.cpp
|
||||||
|
├── sdl_manager.hpp/cpp
|
||||||
|
├── joc_asteroides.hpp/cpp
|
||||||
|
└── asteroids.cpp (Pascal)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Now (BETA 3.0):**
|
||||||
|
```
|
||||||
|
source/
|
||||||
|
├── core/ - Reusable engine
|
||||||
|
│ ├── defaults.hpp - SINGLE SOURCE OF TRUTH for constants
|
||||||
|
│ ├── types.hpp - Data structures
|
||||||
|
│ └── rendering/
|
||||||
|
│ ├── sdl_manager - Dynamic windows + viewport
|
||||||
|
│ └── primitives - Pure geometric functions
|
||||||
|
├── game/ - Asteroids-specific logic
|
||||||
|
│ ├── constants.hpp - Aliases for backward compatibility
|
||||||
|
│ └── joc_asteroides - Game loop
|
||||||
|
├── utils/ - Shared utilities
|
||||||
|
├── main.cpp - Entry point
|
||||||
|
└── legacy/
|
||||||
|
└── asteroids.cpp - Original Pascal code (reference)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Dynamic Window System
|
||||||
|
|
||||||
|
**Controls:**
|
||||||
|
- **F1**: Decrease window (-100px width/height)
|
||||||
|
- **F2**: Increase window (+100px width/height)
|
||||||
|
- **F3**: Toggle fullscreen
|
||||||
|
- **ESC**: Exit (unchanged)
|
||||||
|
|
||||||
|
**Behavior:**
|
||||||
|
- Window starts at 640x480 centered on screen
|
||||||
|
- Each resize keeps window centered on itself
|
||||||
|
- Minimum size: 320x240
|
||||||
|
- Maximum size: Calculated from display resolution (limit -100px)
|
||||||
|
|
||||||
|
**Viewport Scaling (SDL3):**
|
||||||
|
- Game ALWAYS renders in logical coordinates 640x480
|
||||||
|
- SDL3 automatically scales to any physical window size
|
||||||
|
- Aspect ratio preserved (4:3 with letterboxing)
|
||||||
|
- Vectors look SHARPER in larger windows (higher resolution)
|
||||||
|
- Game physics UNCHANGED (still px/s relative to 640x480 logical)
|
||||||
|
|
||||||
|
**Implementation:**
|
||||||
|
```cpp
|
||||||
|
SDL_SetRenderLogicalPresentation(
|
||||||
|
renderer_,
|
||||||
|
640, 480, // Fixed logical size
|
||||||
|
SDL_LOGICAL_PRESENTATION_LETTERBOX // Maintain aspect ratio
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuration System
|
||||||
|
|
||||||
|
**core/defaults.hpp** - Only place to change constants:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
namespace Defaults {
|
||||||
|
namespace Window {
|
||||||
|
constexpr int WIDTH = 640;
|
||||||
|
constexpr int HEIGHT = 480;
|
||||||
|
constexpr int SIZE_INCREMENT = 100; // F1/F2
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Game {
|
||||||
|
constexpr int WIDTH = 640; // Logical
|
||||||
|
constexpr int HEIGHT = 480;
|
||||||
|
constexpr int MARGIN_LEFT = 20; // MARGE_ESQ
|
||||||
|
constexpr int MARGIN_RIGHT = 620; // MARGE_DRET
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Physics {
|
||||||
|
constexpr float ROTATION_SPEED = 2.5f;
|
||||||
|
constexpr float ACCELERATION = 100.0f;
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**game/constants.hpp** - Backward compatibility:
|
||||||
|
```cpp
|
||||||
|
using Defaults::Game::MARGIN_LEFT; // For legacy code using MARGE_ESQ
|
||||||
|
// ...
|
||||||
|
```
|
||||||
|
|
||||||
|
### Important Reminders
|
||||||
|
|
||||||
|
**1. Logical vs Physical Coordinates**
|
||||||
|
- ALL game code uses logical coordinates (640x480)
|
||||||
|
- NO need to adjust physics or collision calculations
|
||||||
|
- SDL3 handles conversion automatically
|
||||||
|
|
||||||
|
**2. Rendering**
|
||||||
|
- `linea()`, `rota_tri()`, `rota_pol()` still use direct coords
|
||||||
|
- NO manual transformation, SDL does it internally
|
||||||
|
|
||||||
|
**3. Configuration**
|
||||||
|
- NEVER use magic numbers in new code
|
||||||
|
- Always reference `Defaults::*`
|
||||||
|
- For game values, create aliases in `game/constants.hpp` if needed
|
||||||
|
|
||||||
|
**4. Future OpenGL**
|
||||||
|
- Current system allows migrating to OpenGL without changing game code
|
||||||
|
- Would only require changing SDLManager and rendering function implementations
|
||||||
|
- Postponed until needing >50 enemies or complex effects
|
||||||
|
|
||||||
|
### Compilation
|
||||||
|
|
||||||
|
**No changes:**
|
||||||
|
```bash
|
||||||
|
make clean && make
|
||||||
|
./asteroids
|
||||||
|
```
|
||||||
|
|
||||||
|
**Files modified by CMake:**
|
||||||
|
- Updated to include subdirectories core/, game/
|
||||||
|
- Include path: `${CMAKE_SOURCE_DIR}/source` (for relative includes)
|
||||||
|
|
||||||
|
### Migration for Future Sessions
|
||||||
|
|
||||||
|
If you find code using magic numbers:
|
||||||
|
1. Add constant in `core/defaults.hpp` in the appropriate namespace
|
||||||
|
2. If it's a frequently used game value, create alias in `game/constants.hpp`
|
||||||
|
3. Replace the number with the constant
|
||||||
|
4. Compile and verify
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```cpp
|
||||||
|
// Before (bad):
|
||||||
|
if (enemy.centre.x < 20 || enemy.centre.x > 620) { ... }
|
||||||
|
|
||||||
|
// After (good):
|
||||||
|
if (enemy.centre.x < MARGIN_LEFT || enemy.centre.x > MARGIN_RIGHT) { ... }
|
||||||
|
```
|
||||||
|
|
||||||
|
## Tips for Future Claude Code Sessions
|
||||||
|
|
||||||
|
- **Always read this file first** before making changes
|
||||||
|
- **Preserve Valencian naming**: nau, orni, bales, centre, velocitat, etc.
|
||||||
|
- **Time-based physics**: All movement must multiply by delta_time
|
||||||
|
- **Polar coordinates**: Core to the game, don't change to Cartesian
|
||||||
|
- **Test compilation** after each change: `make clean && make`
|
||||||
|
- **Visual velocity scaling**: Remember to scale velocitat before passing to rota_tri
|
||||||
|
- **Angle convention**: angle=0 points UP (not right), hence `angle - PI/2` in calculations
|
||||||
|
- **One bullet at a time**: Original game limitation, preserve it
|
||||||
|
- **Simple code style**: Avoid over-engineering, keep "small DOS program" feel
|
||||||
|
- **Use defaults.hpp**: Never hardcode constants, always use Defaults namespace
|
||||||
127
CMakeLists.txt
Normal file
127
CMakeLists.txt
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
# CMakeLists.txt
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
project(orni VERSION 0.5.0)
|
||||||
|
|
||||||
|
# Info del proyecto
|
||||||
|
set(PROJECT_LONG_NAME "Orni Attack")
|
||||||
|
set(PROJECT_COPYRIGHT "© 1999 Visente i Sergi, 2025 Port")
|
||||||
|
|
||||||
|
# Establecer estándar de C++
|
||||||
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||||
|
|
||||||
|
# Exportar comandos de compilación para herramientas de análisis
|
||||||
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||||
|
|
||||||
|
# --- GENERACIÓN DE VERSIÓN AUTOMÁTICA ---
|
||||||
|
find_package(Git QUIET)
|
||||||
|
if(GIT_FOUND)
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${GIT_EXECUTABLE} rev-parse --short=7 HEAD
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||||
|
OUTPUT_VARIABLE GIT_HASH
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
ERROR_QUIET
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
set(GIT_HASH "unknown")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Configurar archivo de versión
|
||||||
|
configure_file(${CMAKE_SOURCE_DIR}/source/project.h.in ${CMAKE_BINARY_DIR}/project.h @ONLY)
|
||||||
|
|
||||||
|
# --- LISTA DE FUENTES (AUTO-DESCUBRIMIENTO) ---
|
||||||
|
# Buscar automáticamente todos los archivos .cpp en core/, game/ y main.cpp
|
||||||
|
file(GLOB_RECURSE CORE_SOURCES "${CMAKE_SOURCE_DIR}/source/core/*.cpp")
|
||||||
|
file(GLOB_RECURSE GAME_SOURCES "${CMAKE_SOURCE_DIR}/source/game/*.cpp")
|
||||||
|
set(APP_SOURCES
|
||||||
|
${CORE_SOURCES}
|
||||||
|
${GAME_SOURCES}
|
||||||
|
source/main.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
# Excluir archivos legacy (código Pascal de referencia)
|
||||||
|
list(FILTER APP_SOURCES EXCLUDE REGEX ".*/legacy/.*")
|
||||||
|
|
||||||
|
# Log de archivos encontrados (útil para debug)
|
||||||
|
list(LENGTH APP_SOURCES APP_SOURCES_COUNT)
|
||||||
|
message(STATUS "Archivos .cpp encontrados: ${APP_SOURCES_COUNT}")
|
||||||
|
|
||||||
|
# Configuración de SDL3
|
||||||
|
find_package(SDL3 REQUIRED CONFIG REQUIRED COMPONENTS SDL3)
|
||||||
|
message(STATUS "SDL3 encontrado: ${SDL3_INCLUDE_DIRS}")
|
||||||
|
|
||||||
|
# --- AÑADIR EJECUTABLE ---
|
||||||
|
add_executable(${PROJECT_NAME} ${APP_SOURCES})
|
||||||
|
|
||||||
|
# --- DIRECTORIOS DE INCLUSIÓN ---
|
||||||
|
target_include_directories(${PROJECT_NAME} PUBLIC
|
||||||
|
"${CMAKE_SOURCE_DIR}/source"
|
||||||
|
"${CMAKE_BINARY_DIR}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Enlazar las librerías SDL3
|
||||||
|
target_link_libraries(${PROJECT_NAME} PRIVATE SDL3::SDL3)
|
||||||
|
|
||||||
|
# --- CONFIGURACIÓN PLATAFORMAS Y COMPILADOR ---
|
||||||
|
# Configuración de flags de compilación
|
||||||
|
target_compile_options(${PROJECT_NAME} PRIVATE -Wall)
|
||||||
|
target_compile_options(${PROJECT_NAME} PRIVATE $<$<CONFIG:RELEASE>:-O2 -ffunction-sections -fdata-sections>)
|
||||||
|
|
||||||
|
# Definir _DEBUG en modo Debug y RELEASE_BUILD en modo Release
|
||||||
|
target_compile_definitions(${PROJECT_NAME} PRIVATE $<$<CONFIG:DEBUG>:_DEBUG>)
|
||||||
|
target_compile_definitions(${PROJECT_NAME} PRIVATE $<$<CONFIG:RELEASE>:RELEASE_BUILD>)
|
||||||
|
|
||||||
|
# Definir MACOS_BUNDLE si es un bundle de macOS
|
||||||
|
if(APPLE AND MACOSX_BUNDLE)
|
||||||
|
target_compile_definitions(${PROJECT_NAME} PRIVATE MACOS_BUNDLE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Configuración específica para cada plataforma
|
||||||
|
if(WIN32)
|
||||||
|
target_compile_definitions(${PROJECT_NAME} PRIVATE WINDOWS_BUILD)
|
||||||
|
target_link_libraries(${PROJECT_NAME} PRIVATE mingw32)
|
||||||
|
# Añadir icono en Windows (se configurará desde el Makefile con windres)
|
||||||
|
elseif(APPLE)
|
||||||
|
target_compile_definitions(${PROJECT_NAME} PRIVATE MACOS_BUILD)
|
||||||
|
target_compile_options(${PROJECT_NAME} PRIVATE -Wno-deprecated)
|
||||||
|
set(CMAKE_OSX_ARCHITECTURES "arm64")
|
||||||
|
elseif(UNIX AND NOT APPLE)
|
||||||
|
target_compile_definitions(${PROJECT_NAME} PRIVATE LINUX_BUILD)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Especificar la ubicación del ejecutable
|
||||||
|
set_target_properties(${PROJECT_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||||
|
|
||||||
|
# --- STATIC ANALYSIS TARGETS ---
|
||||||
|
# Buscar herramientas de análisis estático
|
||||||
|
find_program(CLANG_FORMAT_EXE NAMES clang-format)
|
||||||
|
|
||||||
|
# Recopilar todos los archivos fuente para formateo
|
||||||
|
file(GLOB_RECURSE ALL_SOURCE_FILES
|
||||||
|
"${CMAKE_SOURCE_DIR}/source/*.cpp"
|
||||||
|
"${CMAKE_SOURCE_DIR}/source/*.hpp"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Targets de clang-format
|
||||||
|
if(CLANG_FORMAT_EXE)
|
||||||
|
add_custom_target(format
|
||||||
|
COMMAND ${CLANG_FORMAT_EXE}
|
||||||
|
-i
|
||||||
|
${ALL_SOURCE_FILES}
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||||
|
COMMENT "Running clang-format..."
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_target(format-check
|
||||||
|
COMMAND ${CLANG_FORMAT_EXE}
|
||||||
|
--dry-run
|
||||||
|
--Werror
|
||||||
|
${ALL_SOURCE_FILES}
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||||
|
COMMENT "Checking clang-format..."
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
message(STATUS "clang-format no encontrado - targets 'format' y 'format-check' no disponibles")
|
||||||
|
endif()
|
||||||
275
KEYBOARD.PAS
275
KEYBOARD.PAS
@@ -1,275 +0,0 @@
|
|||||||
{
|
|
||||||
-----------------------------------------------------
|
|
||||||
File: Keyboard.Pas
|
|
||||||
By: Ronny Wester, ronny@rat.se
|
|
||||||
|
|
||||||
Unit to check up/down status of individual key flags.
|
|
||||||
Written from code I got off rec.games.programmer.
|
|
||||||
Sorry, I lost the name of the poster.
|
|
||||||
As most of this code is scancode-dependent some keys
|
|
||||||
may not be where they "should" on your keyboard.
|
|
||||||
-----------------------------------------------------
|
|
||||||
}
|
|
||||||
unit Keyboard;
|
|
||||||
|
|
||||||
|
|
||||||
interface
|
|
||||||
|
|
||||||
uses Dos;
|
|
||||||
|
|
||||||
|
|
||||||
const
|
|
||||||
|
|
||||||
keySysReq = $54;
|
|
||||||
keyCapsLock = $3A;
|
|
||||||
keyNumLock = $45;
|
|
||||||
keyScrollLock = $46;
|
|
||||||
keyLeftCtrl = $1D;
|
|
||||||
keyLeftAlt = $38;
|
|
||||||
keyLeftShift = $2A;
|
|
||||||
keyRightCtrl = $9D;
|
|
||||||
keyAltGr = $B8;
|
|
||||||
keyRightShift = $36;
|
|
||||||
keyEsc = $01;
|
|
||||||
keyBackspace = $0E;
|
|
||||||
keyEnter = $1C;
|
|
||||||
keySpace = $39;
|
|
||||||
keyTab = $0F;
|
|
||||||
keyF1 = $3B;
|
|
||||||
keyF2 = $3C;
|
|
||||||
keyF3 = $3D;
|
|
||||||
keyF4 = $3E;
|
|
||||||
keyF5 = $3F;
|
|
||||||
keyF6 = $40;
|
|
||||||
keyF7 = $41;
|
|
||||||
keyF8 = $42;
|
|
||||||
keyF9 = $43;
|
|
||||||
keyF10 = $44;
|
|
||||||
keyF11 = $57;
|
|
||||||
keyF12 = $58;
|
|
||||||
keyA = $1E;
|
|
||||||
keyB = $30;
|
|
||||||
keyC = $2E;
|
|
||||||
keyD = $20;
|
|
||||||
keyE = $12;
|
|
||||||
keyF = $21;
|
|
||||||
keyG = $22;
|
|
||||||
keyH = $23;
|
|
||||||
keyI = $17;
|
|
||||||
keyJ = $24;
|
|
||||||
keyK = $25;
|
|
||||||
keyL = $26;
|
|
||||||
keyM = $32;
|
|
||||||
keyN = $31;
|
|
||||||
keyO = $18;
|
|
||||||
keyP = $19;
|
|
||||||
keyQ = $10;
|
|
||||||
keyR = $13;
|
|
||||||
keyS = $1F;
|
|
||||||
keyT = $14;
|
|
||||||
keyU = $16;
|
|
||||||
keyV = $2F;
|
|
||||||
keyW = $11;
|
|
||||||
keyX = $2D;
|
|
||||||
keyY = $15;
|
|
||||||
keyZ = $2C;
|
|
||||||
key1 = $02;
|
|
||||||
key2 = $03;
|
|
||||||
key3 = $04;
|
|
||||||
key4 = $05;
|
|
||||||
key5 = $06;
|
|
||||||
key6 = $07;
|
|
||||||
key7 = $08;
|
|
||||||
key8 = $09;
|
|
||||||
key9 = $0A;
|
|
||||||
key0 = $0B;
|
|
||||||
keyMinus = $0C;
|
|
||||||
keyEqual = $0D;
|
|
||||||
keyLBracket = $1A;
|
|
||||||
keyRBracket = $1B;
|
|
||||||
keySemicolon = $27;
|
|
||||||
keyTick = $28;
|
|
||||||
keyApostrophe = $29;
|
|
||||||
keyBackslash = $2B;
|
|
||||||
keyComma = $33;
|
|
||||||
keyPeriod = $34;
|
|
||||||
keySlash = $35;
|
|
||||||
keyInsert = $D2;
|
|
||||||
keyDelete = $D3;
|
|
||||||
keyHome = $C7;
|
|
||||||
keyEnd = $CF;
|
|
||||||
keyPageUp = $C9;
|
|
||||||
keyArrowLeft = $CB;
|
|
||||||
keyArrowRight = $CD;
|
|
||||||
keyArrowUp = $C8;
|
|
||||||
keyArrowDown = $D0;
|
|
||||||
keyKeypad0 = $52;
|
|
||||||
keyKeypad1 = $4F;
|
|
||||||
keyKeypad2 = $50;
|
|
||||||
keyKeypad3 = $51;
|
|
||||||
keyKeypad4 = $4B;
|
|
||||||
keyKeypad5 = $4C;
|
|
||||||
keyKeypad6 = $4D;
|
|
||||||
keyKeypad7 = $47;
|
|
||||||
keyKeypad8 = $48;
|
|
||||||
keyKeypad9 = $49;
|
|
||||||
keyKeypadComma = $53;
|
|
||||||
keyKeypadStar = $37;
|
|
||||||
keyKeypadMinus = $4A;
|
|
||||||
keyKeypadPlus = $4E;
|
|
||||||
keyKeypadEnter = $9C;
|
|
||||||
keyCtrlPrtScr = $B7;
|
|
||||||
keyShiftPrtScr = $B7;
|
|
||||||
keyKeypadSlash = $B5;
|
|
||||||
keyNames : array [0..255] of PChar =
|
|
||||||
( { $00 } nil, 'Esc', '1', '2', '3', '4', '5', '6',
|
|
||||||
{ $08 } '7', '8', '9', '0', '+', 'Apostrophe', 'Backspace', 'Tab',
|
|
||||||
{ $10 } 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I',
|
|
||||||
{ $18 } 'O', 'P', '<27>', '?', 'Enter', 'Left Ctrl', 'A', 'S',
|
|
||||||
{ $20 } 'D', 'F', 'G', 'H', 'J', 'K', 'L', '™',
|
|
||||||
{ $28 } 'Ž', '''', 'Left shift', '<', 'Z', 'X', 'C', 'V',
|
|
||||||
{ $30 } 'B', 'N', 'M', ',', '.', '-', 'Right shift', '* (pad)',
|
|
||||||
{ $38 } 'Alt', 'Space', 'Caps Lock', 'F1', 'F2', 'F3', 'F4', 'F5',
|
|
||||||
{ $40 } 'F6', 'F7', 'F8', 'F9', 'F10', 'Num Lock', 'Scroll Lock', '7 (pad)',
|
|
||||||
{ $48 } '8 (pad)', '9 (pad)', '- (pad)', '4 (pad)', '5 (pad)', '6 (pad)', '+ (pad)', '1 (pad)',
|
|
||||||
{ $50 } '2 (pad)', '3 (pad)', '0 (pad)', ', (pad)', 'SysRq', nil, nil, 'F11', 'F12',
|
|
||||||
{ $59 } nil, nil, nil, nil, nil, nil, nil,
|
|
||||||
{ $60 } nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
|
|
||||||
{ $70 } nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
|
|
||||||
{ $80 } nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
|
|
||||||
{ $90 } nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 'Enter (pad)', 'Right Ctrl', nil, nil,
|
|
||||||
{ $A0 } nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
|
|
||||||
{ $B0 } nil, nil, nil, nil, nil, '/ (pad)', nil, 'PrtScr', 'Alt Gr', nil, nil, nil, nil, nil, nil, nil,
|
|
||||||
{ $C0 } nil, nil, nil, nil, nil, nil, nil, 'Home',
|
|
||||||
{ $C8 } 'Up arrow', 'Page Up', nil, 'Left arrow', nil, 'Right arrow', nil, 'End',
|
|
||||||
{ $D0 } 'Down arrow', nil, 'Insert', 'Delete', nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
|
|
||||||
{ $E0 } nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
|
|
||||||
{ $F0 } nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
procedure InstalarKb;
|
|
||||||
procedure DesinstalarKb;
|
|
||||||
function TeclaPuls( b : byte ) : Boolean;
|
|
||||||
function QTeclaPuls : Boolean;
|
|
||||||
function AgarrarTecla : Byte;
|
|
||||||
procedure BorrarKb;
|
|
||||||
procedure EscriuKb;
|
|
||||||
|
|
||||||
|
|
||||||
implementation
|
|
||||||
|
|
||||||
|
|
||||||
var
|
|
||||||
|
|
||||||
uOldInt9 : Pointer; { saves location of old OldInt9 vector }
|
|
||||||
uKeys : array [0..255] of Boolean; { array that holds key values }
|
|
||||||
e0Flag : Byte;
|
|
||||||
uExitProc : Pointer;
|
|
||||||
|
|
||||||
|
|
||||||
{$F+}
|
|
||||||
procedure NewInt9; interrupt; assembler;
|
|
||||||
asm
|
|
||||||
cli
|
|
||||||
in al, $60 { get scan code from keyboard port }
|
|
||||||
cmp al, $E0 { al = $E0 key ? }
|
|
||||||
jne @@SetScanCode
|
|
||||||
mov [e0Flag], 128
|
|
||||||
mov al, 20h { Send 'generic' EOI to PIC }
|
|
||||||
out 20h, al
|
|
||||||
jmp @@exit
|
|
||||||
@@SetScanCode:
|
|
||||||
mov bl, al { Save scancode in BL }
|
|
||||||
and bl, 01111111b
|
|
||||||
add bl, [e0Flag]
|
|
||||||
xor bh, bh
|
|
||||||
and al, 10000000b { keep break bit, if set }
|
|
||||||
xor al, 10000000b { flip bit, 1 means pressed, 0 no }
|
|
||||||
rol al, 1 { move breakbit to bit 0 }
|
|
||||||
mov [offset uKeys + bx], al
|
|
||||||
mov [e0Flag], 0
|
|
||||||
mov al, 20h { send EOI to PIC }
|
|
||||||
out 20h, al
|
|
||||||
@@exit:
|
|
||||||
sti
|
|
||||||
end;
|
|
||||||
{$F-}
|
|
||||||
|
|
||||||
|
|
||||||
procedure InstalarKb;
|
|
||||||
begin
|
|
||||||
GetIntVec( $09, uOldInt9); { save old location of INT 09 handler }
|
|
||||||
SetIntVec( $09, Addr( NewInt9)); { point to new routine }
|
|
||||||
FillChar( uKeys, SizeOf( uKeys), 0); { clear the keys array }
|
|
||||||
end;
|
|
||||||
|
|
||||||
|
|
||||||
procedure DesinstalarKb;
|
|
||||||
begin
|
|
||||||
SetIntVec( $09, uOldInt9); { point back to original routine }
|
|
||||||
uOldInt9 := nil;
|
|
||||||
end;
|
|
||||||
|
|
||||||
|
|
||||||
function TeclaPuls( b : byte ) : Boolean;
|
|
||||||
begin
|
|
||||||
TeclaPuls := uKeys[b];
|
|
||||||
end;
|
|
||||||
|
|
||||||
|
|
||||||
function QTeclaPuls : Boolean;
|
|
||||||
var b : Integer;
|
|
||||||
begin
|
|
||||||
QTeclaPuls := True;
|
|
||||||
for b := 0 to 255 do
|
|
||||||
if uKeys[b] and (keyNames[b] <> nil) then
|
|
||||||
Exit;
|
|
||||||
QTeclaPuls := False;
|
|
||||||
end;
|
|
||||||
|
|
||||||
|
|
||||||
function AgarrarTecla : Byte;
|
|
||||||
var b : Integer;
|
|
||||||
begin
|
|
||||||
AgarrarTecla := 0;
|
|
||||||
for b := 1 to 255 do
|
|
||||||
if uKeys[b] and (keyNames[b] <> nil) then
|
|
||||||
begin
|
|
||||||
AgarrarTecla := b;
|
|
||||||
Exit;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
|
|
||||||
procedure BorrarKb;
|
|
||||||
begin
|
|
||||||
FillChar( uKeys, SizeOf( uKeys), 0); { clear the keys array }
|
|
||||||
end;
|
|
||||||
|
|
||||||
|
|
||||||
{$F+}
|
|
||||||
procedure CleanUp;
|
|
||||||
begin
|
|
||||||
ExitProc := uExitProc;
|
|
||||||
if uOldInt9 <> nil then
|
|
||||||
DesinstalarKb;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure EscriuKb;
|
|
||||||
var b:byte;
|
|
||||||
begin
|
|
||||||
for b := 0 to 255 do
|
|
||||||
if uKeys[b] and (keyNames[b] <> nil) then
|
|
||||||
write(keyNames[b],' | ');
|
|
||||||
writeln;
|
|
||||||
end;
|
|
||||||
|
|
||||||
{$F-}
|
|
||||||
|
|
||||||
|
|
||||||
begin
|
|
||||||
uExitProc := ExitProc;
|
|
||||||
ExitProc := @CleanUp;
|
|
||||||
uOldInt9 := nil;
|
|
||||||
end.
|
|
||||||
379
Makefile
Normal file
379
Makefile
Normal file
@@ -0,0 +1,379 @@
|
|||||||
|
# ==============================================================================
|
||||||
|
# DIRECTORIES
|
||||||
|
# ==============================================================================
|
||||||
|
DIR_ROOT := $(dir $(abspath $(MAKEFILE_LIST)))
|
||||||
|
DIR_SOURCES := $(addprefix $(DIR_ROOT), source/)
|
||||||
|
DIR_BIN := $(DIR_ROOT)
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# TARGET NAMES
|
||||||
|
# ==============================================================================
|
||||||
|
ifeq ($(OS),Windows_NT)
|
||||||
|
TARGET_NAME := $(shell powershell -Command "$$line = Get-Content CMakeLists.txt | Where-Object {$$_ -match '^project'}; if ($$line -match 'project\s*\x28(\w+)') { $$matches[1] }")
|
||||||
|
LONG_NAME := $(shell powershell -Command "$$line = Get-Content CMakeLists.txt | Where-Object {$$_ -match 'PROJECT_LONG_NAME'}; if ($$line -match '\"(.+)\"') { $$matches[1] }")
|
||||||
|
else
|
||||||
|
TARGET_NAME := $(shell awk '/^project/ {gsub(/[)(]/, " "); print $$2}' CMakeLists.txt)
|
||||||
|
LONG_NAME := $(shell grep 'PROJECT_LONG_NAME' CMakeLists.txt | sed 's/.*"\(.*\)".*/\1/')
|
||||||
|
endif
|
||||||
|
|
||||||
|
TARGET_FILE := $(DIR_BIN)$(TARGET_NAME)
|
||||||
|
RELEASE_FOLDER := $(TARGET_NAME)_release
|
||||||
|
RELEASE_FILE := $(RELEASE_FOLDER)/$(TARGET_NAME)
|
||||||
|
|
||||||
|
# Release file names
|
||||||
|
RAW_VERSION := $(shell echo $(VERSION) | sed 's/^v//')
|
||||||
|
WINDOWS_RELEASE := $(TARGET_NAME)-$(VERSION)-windows-x64.zip
|
||||||
|
MACOS_ARM_RELEASE := $(TARGET_NAME)-$(VERSION)-macos-arm64.dmg
|
||||||
|
MACOS_INTEL_RELEASE := $(TARGET_NAME)-$(VERSION)-macos-x64.dmg
|
||||||
|
LINUX_RELEASE := $(TARGET_NAME)-$(VERSION)-linux-x64.tar.gz
|
||||||
|
RPI_RELEASE := $(TARGET_NAME)-$(VERSION)-rpi-arm64.tar.gz
|
||||||
|
APP_NAME := $(LONG_NAME)
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# VERSION
|
||||||
|
# ==============================================================================
|
||||||
|
ifeq ($(OS),Windows_NT)
|
||||||
|
VERSION := v$(shell powershell -Command "$$line = Get-Content CMakeLists.txt | Where-Object {$$_ -match '^project'}; if ($$line -match 'VERSION\s+([0-9.]+)') { $$matches[1] }")
|
||||||
|
else
|
||||||
|
VERSION := v$(shell grep "^project" CMakeLists.txt | tr -cd 0-9.)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# SOURCE FILES
|
||||||
|
# ==============================================================================
|
||||||
|
# Note: Source files are now auto-discovered by CMake using GLOB_RECURSE
|
||||||
|
# No need to maintain this list manually anymore!
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# PLATFORM-SPECIFIC UTILITIES
|
||||||
|
# ==============================================================================
|
||||||
|
ifeq ($(OS),Windows_NT)
|
||||||
|
RMFILE := del /Q
|
||||||
|
RMDIR := rmdir /S /Q
|
||||||
|
MKDIR := mkdir
|
||||||
|
else
|
||||||
|
RMFILE := rm -f
|
||||||
|
RMDIR := rm -rf
|
||||||
|
MKDIR := mkdir -p
|
||||||
|
UNAME_S := $(shell uname -s)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# PACKING TOOL
|
||||||
|
# ==============================================================================
|
||||||
|
PACK_TOOL := tools/pack_resources/pack_resources
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# DEFAULT GOAL
|
||||||
|
# ==============================================================================
|
||||||
|
.DEFAULT_GOAL := all
|
||||||
|
|
||||||
|
.PHONY: pack_tool resources.pack
|
||||||
|
|
||||||
|
pack_tool:
|
||||||
|
@$(MAKE) -C tools/pack_resources
|
||||||
|
|
||||||
|
resources.pack: pack_tool
|
||||||
|
@echo "Creating resources.pack..."
|
||||||
|
@./$(PACK_TOOL) data resources.pack
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# TARGETS
|
||||||
|
# ==============================================================================
|
||||||
|
.PHONY: all clean debug help backup
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# BUILD TARGETS (delegate to CMake)
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
|
# Default target: build with CMake + resources
|
||||||
|
all: resources.pack $(TARGET_FILE)
|
||||||
|
|
||||||
|
$(TARGET_FILE):
|
||||||
|
@cmake -B build -DCMAKE_BUILD_TYPE=Release
|
||||||
|
@cmake --build build
|
||||||
|
@echo "Build successful: $(TARGET_FILE)"
|
||||||
|
|
||||||
|
# Debug build
|
||||||
|
debug: resources.pack
|
||||||
|
@cmake -B build -DCMAKE_BUILD_TYPE=Debug
|
||||||
|
@cmake --build build
|
||||||
|
@echo "Debug build successful: $(TARGET_FILE)"
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# RELEASE PACKAGING TARGETS
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
|
# macOS Release (Apple Silicon)
|
||||||
|
.PHONY: macos_release
|
||||||
|
macos_release: pack_tool resources.pack
|
||||||
|
@echo "Creating macOS release - Version: $(VERSION)"
|
||||||
|
|
||||||
|
# Check/install create-dmg
|
||||||
|
@command -v create-dmg >/dev/null || (echo "Installing create-dmg..." && brew install create-dmg)
|
||||||
|
|
||||||
|
# Clean previous releases
|
||||||
|
@$(RMDIR) "$(RELEASE_FOLDER)" 2>/dev/null || true
|
||||||
|
@$(RMDIR) Frameworks 2>/dev/null || true
|
||||||
|
@$(RMFILE) "$(MACOS_ARM_RELEASE)" 2>/dev/null || true
|
||||||
|
|
||||||
|
# Create .app structure
|
||||||
|
@$(MKDIR) "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Frameworks"
|
||||||
|
@$(MKDIR) "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/MacOS"
|
||||||
|
@$(MKDIR) "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources"
|
||||||
|
@$(MKDIR) Frameworks
|
||||||
|
|
||||||
|
# Copy resources.pack to Resources
|
||||||
|
@cp resources.pack "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources/"
|
||||||
|
@ditto release/frameworks/SDL3.xcframework/macos-arm64_x86_64/SDL3.framework "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Frameworks/SDL3.framework"
|
||||||
|
@ditto release/frameworks/SDL3.xcframework/macos-arm64_x86_64/SDL3.framework Frameworks/SDL3.framework
|
||||||
|
|
||||||
|
# Recreate framework symlinks (may be broken)
|
||||||
|
@cd Frameworks/SDL3.framework && rm -f SDL3 Headers Resources && \
|
||||||
|
ln -s Versions/Current/SDL3 SDL3 && \
|
||||||
|
ln -s Versions/Current/Headers Headers && \
|
||||||
|
ln -s Versions/Current/Resources Resources
|
||||||
|
@cd Frameworks/SDL3.framework/Versions && rm -f Current && ln -s A Current
|
||||||
|
@cd "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Frameworks/SDL3.framework" && rm -f SDL3 Headers Resources && \
|
||||||
|
ln -s Versions/Current/SDL3 SDL3 && \
|
||||||
|
ln -s Versions/Current/Headers Headers && \
|
||||||
|
ln -s Versions/Current/Resources Resources
|
||||||
|
@cd "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Frameworks/SDL3.framework/Versions" && rm -f Current && ln -s A Current
|
||||||
|
|
||||||
|
@cp release/icon.icns "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources/"
|
||||||
|
@cp release/Info.plist "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/"
|
||||||
|
@cp LICENSE "$(RELEASE_FOLDER)/" 2>/dev/null || echo "Warning: LICENSE not found"
|
||||||
|
@cp README.md "$(RELEASE_FOLDER)/" 2>/dev/null || echo "Warning: README.md not found"
|
||||||
|
|
||||||
|
# Update Info.plist version
|
||||||
|
@echo "Updating Info.plist with version $(RAW_VERSION)..."
|
||||||
|
@sed -i '' '/<key>CFBundleShortVersionString<\/key>/{n;s|<string>.*</string>|<string>$(RAW_VERSION)</string>|;}' \
|
||||||
|
"$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Info.plist"
|
||||||
|
@sed -i '' '/<key>CFBundleVersion<\/key>/{n;s|<string>.*</string>|<string>$(RAW_VERSION)</string>|;}' \
|
||||||
|
"$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Info.plist"
|
||||||
|
|
||||||
|
# Compile for Apple Silicon using CMake
|
||||||
|
@cmake -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES=arm64
|
||||||
|
@cmake --build build
|
||||||
|
@cp $(TARGET_FILE) "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/MacOS/$(TARGET_NAME)"
|
||||||
|
|
||||||
|
# Code sign
|
||||||
|
@codesign --deep --force --sign - --timestamp=none "$(RELEASE_FOLDER)/$(APP_NAME).app" || echo "Warning: Code signing failed"
|
||||||
|
|
||||||
|
# Create DMG
|
||||||
|
@echo "Creating DMG for Apple Silicon..."
|
||||||
|
@create-dmg \
|
||||||
|
--volname "$(APP_NAME)" \
|
||||||
|
--window-pos 200 120 \
|
||||||
|
--window-size 720 300 \
|
||||||
|
--icon-size 96 \
|
||||||
|
--text-size 12 \
|
||||||
|
--icon "$(APP_NAME).app" 278 102 \
|
||||||
|
--icon "LICENSE" 441 102 \
|
||||||
|
--icon "README.md" 604 102 \
|
||||||
|
--app-drop-link 115 102 \
|
||||||
|
--hide-extension "$(APP_NAME).app" \
|
||||||
|
"$(MACOS_ARM_RELEASE)" \
|
||||||
|
"$(RELEASE_FOLDER)" || true
|
||||||
|
@echo "✓ macOS release created: $(MACOS_ARM_RELEASE)"
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
@$(RMDIR) Frameworks
|
||||||
|
@$(RMDIR) "$(RELEASE_FOLDER)"
|
||||||
|
|
||||||
|
# Linux Release
|
||||||
|
.PHONY: linux_release
|
||||||
|
linux_release:
|
||||||
|
@echo "Creating Linux release - Version: $(VERSION)"
|
||||||
|
|
||||||
|
# Clean previous
|
||||||
|
@$(RMDIR) "$(RELEASE_FOLDER)"
|
||||||
|
@$(RMFILE) "$(LINUX_RELEASE)"
|
||||||
|
|
||||||
|
# Create folder
|
||||||
|
@$(MKDIR) "$(RELEASE_FOLDER)"
|
||||||
|
|
||||||
|
# Copy resources
|
||||||
|
@cp -r resources "$(RELEASE_FOLDER)/"
|
||||||
|
@cp LICENSE "$(RELEASE_FOLDER)/" 2>/dev/null || echo "Warning: LICENSE not found"
|
||||||
|
@cp README.md "$(RELEASE_FOLDER)/" 2>/dev/null || echo "Warning: README.md not found"
|
||||||
|
|
||||||
|
# Compile with CMake
|
||||||
|
@cmake -B build -DCMAKE_BUILD_TYPE=Release
|
||||||
|
@cmake --build build
|
||||||
|
@cp $(TARGET_FILE) "$(RELEASE_FILE)"
|
||||||
|
@strip -s -R .comment -R .gnu.version "$(RELEASE_FILE)" --strip-unneeded || strip "$(RELEASE_FILE)"
|
||||||
|
|
||||||
|
# Package
|
||||||
|
@tar -czf "$(LINUX_RELEASE)" -C "$(RELEASE_FOLDER)" .
|
||||||
|
@echo "✓ Linux release created: $(LINUX_RELEASE)"
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
@$(RMDIR) "$(RELEASE_FOLDER)"
|
||||||
|
|
||||||
|
# Windows Release (requires MinGW on Windows or cross-compiler on Linux)
|
||||||
|
.PHONY: windows_release
|
||||||
|
windows_release:
|
||||||
|
@echo "Creating Windows release - Version: $(VERSION)"
|
||||||
|
@echo "Note: This target should be run on Windows with MinGW or use windows_cross on Linux"
|
||||||
|
|
||||||
|
# Clean previous
|
||||||
|
@$(RMDIR) "$(RELEASE_FOLDER)"
|
||||||
|
@$(RMFILE) "$(WINDOWS_RELEASE)"
|
||||||
|
|
||||||
|
# Create folder
|
||||||
|
@$(MKDIR) "$(RELEASE_FOLDER)"
|
||||||
|
|
||||||
|
# Copy resources
|
||||||
|
@cp -r resources "$(RELEASE_FOLDER)/"
|
||||||
|
@cp release/dll/*.dll "$(RELEASE_FOLDER)/" 2>/dev/null || echo "Warning: DLLs not found"
|
||||||
|
@cp LICENSE "$(RELEASE_FOLDER)/" 2>/dev/null || echo "Warning: LICENSE not found"
|
||||||
|
@cp README.md "$(RELEASE_FOLDER)/" 2>/dev/null || echo "Warning: README.md not found"
|
||||||
|
|
||||||
|
# Compile resource file
|
||||||
|
@windres release/$(TARGET_NAME).rc -O coff -o release/$(TARGET_NAME).res 2>/dev/null || echo "Warning: windres failed"
|
||||||
|
|
||||||
|
# Compile with CMake
|
||||||
|
@cmake -B build -DCMAKE_BUILD_TYPE=Release
|
||||||
|
@cmake --build build
|
||||||
|
@cp $(TARGET_FILE).exe "$(RELEASE_FILE).exe" || cp $(TARGET_FILE) "$(RELEASE_FILE).exe"
|
||||||
|
|
||||||
|
# Package
|
||||||
|
@cd "$(RELEASE_FOLDER)" && zip -r ../$(WINDOWS_RELEASE) *
|
||||||
|
@echo "✓ Windows release created: $(WINDOWS_RELEASE)"
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
@$(RMDIR) "$(RELEASE_FOLDER)"
|
||||||
|
|
||||||
|
# Raspberry Pi Release (cross-compilation from Linux/macOS)
|
||||||
|
.PHONY: rpi_release
|
||||||
|
rpi_release:
|
||||||
|
@echo "Creating Raspberry Pi ARM64 release - Version: $(VERSION)"
|
||||||
|
@echo "Note: Requires aarch64-linux-gnu-g++ cross-compiler"
|
||||||
|
|
||||||
|
# Check for cross-compiler
|
||||||
|
@command -v aarch64-linux-gnu-g++ >/dev/null || (echo "Error: aarch64-linux-gnu-g++ not found" && exit 1)
|
||||||
|
|
||||||
|
# Clean previous
|
||||||
|
@$(RMDIR) "$(RELEASE_FOLDER)"
|
||||||
|
@$(RMFILE) "$(RPI_RELEASE)"
|
||||||
|
|
||||||
|
# Create folder
|
||||||
|
@$(MKDIR) "$(RELEASE_FOLDER)"
|
||||||
|
|
||||||
|
# Copy resources
|
||||||
|
@cp -r resources "$(RELEASE_FOLDER)/"
|
||||||
|
@cp LICENSE "$(RELEASE_FOLDER)/" 2>/dev/null || echo "Warning: LICENSE not found"
|
||||||
|
@cp README.md "$(RELEASE_FOLDER)/" 2>/dev/null || echo "Warning: README.md not found"
|
||||||
|
|
||||||
|
# Note: Cross-compilation with CMake is complex, would need toolchain file
|
||||||
|
@echo "Warning: RPI cross-compilation requires manual setup with CMake toolchain file"
|
||||||
|
@echo "Falling back to direct g++ compilation..."
|
||||||
|
@aarch64-linux-gnu-g++ -std=c++20 -Wall -O2 -DLINUX_BUILD -DRPI_BUILD \
|
||||||
|
-Isource -Ibuild \
|
||||||
|
$$(find source/core source/game -name "*.cpp") source/main.cpp \
|
||||||
|
-lSDL3 -o "$(RELEASE_FILE)" || echo "Error: Compilation failed"
|
||||||
|
@aarch64-linux-gnu-strip -s -R .comment -R .gnu.version "$(RELEASE_FILE)" --strip-unneeded || true
|
||||||
|
|
||||||
|
# Package
|
||||||
|
@tar -czf "$(RPI_RELEASE)" -C "$(RELEASE_FOLDER)" .
|
||||||
|
@echo "✓ Raspberry Pi release created: $(RPI_RELEASE)"
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
@$(RMDIR) "$(RELEASE_FOLDER)"
|
||||||
|
|
||||||
|
# Windows Cross-compilation (from Linux/macOS)
|
||||||
|
.PHONY: windows_cross
|
||||||
|
windows_cross:
|
||||||
|
@echo "Cross-compiling for Windows from $(UNAME_S) - Version: $(VERSION)"
|
||||||
|
|
||||||
|
# Check for cross-compiler
|
||||||
|
@command -v x86_64-w64-mingw32-g++ >/dev/null || (echo "Error: x86_64-w64-mingw32-g++ not found" && exit 1)
|
||||||
|
|
||||||
|
# Clean previous
|
||||||
|
@$(RMDIR) "$(RELEASE_FOLDER)"
|
||||||
|
@$(RMFILE) "$(WINDOWS_RELEASE)"
|
||||||
|
|
||||||
|
# Create folder
|
||||||
|
@$(MKDIR) "$(RELEASE_FOLDER)"
|
||||||
|
|
||||||
|
# Copy resources
|
||||||
|
@cp -r resources "$(RELEASE_FOLDER)/"
|
||||||
|
@cp release/dll/*.dll "$(RELEASE_FOLDER)/" 2>/dev/null || echo "Warning: DLLs not found in release/dll/"
|
||||||
|
@cp LICENSE "$(RELEASE_FOLDER)/" 2>/dev/null || echo "Warning: LICENSE not found"
|
||||||
|
@cp README.md "$(RELEASE_FOLDER)/" 2>/dev/null || echo "Warning: README.md not found"
|
||||||
|
|
||||||
|
# Compile resource file
|
||||||
|
@x86_64-w64-mingw32-windres release/$(TARGET_NAME).rc -O coff -o release/$(TARGET_NAME).res 2>/dev/null || echo "Warning: windres failed"
|
||||||
|
|
||||||
|
# Cross-compile
|
||||||
|
@echo "Compiling with MinGW cross-compiler..."
|
||||||
|
@x86_64-w64-mingw32-g++ -std=c++20 -Wall -O2 -DWINDOWS_BUILD -DRELEASE_BUILD \
|
||||||
|
-static-libstdc++ -static-libgcc -Wl,-subsystem,windows \
|
||||||
|
-Isource -Ibuild \
|
||||||
|
$$(find source/core source/game -name "*.cpp") source/main.cpp \
|
||||||
|
release/$(TARGET_NAME).res \
|
||||||
|
-lmingw32 -lSDL3 -o "$(RELEASE_FILE).exe" || echo "Error: Compilation failed"
|
||||||
|
@x86_64-w64-mingw32-strip "$(RELEASE_FILE).exe" || true
|
||||||
|
|
||||||
|
# Package
|
||||||
|
@cd "$(RELEASE_FOLDER)" && zip -r ../$(WINDOWS_RELEASE) *
|
||||||
|
@echo "✓ Windows cross-compiled release created: $(WINDOWS_RELEASE)"
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
@$(RMDIR) "$(RELEASE_FOLDER)"
|
||||||
|
|
||||||
|
# Clean build artifacts
|
||||||
|
clean:
|
||||||
|
ifeq ($(OS),Windows_NT)
|
||||||
|
@if exist $(call FixPath,$(TARGET_FILE).exe) $(RMFILE) $(call FixPath,$(TARGET_FILE).exe)
|
||||||
|
@if exist $(call FixPath,$(TARGET_FILE)_debug.exe) $(RMFILE) $(call FixPath,$(TARGET_FILE)_debug.exe)
|
||||||
|
@if exist build $(RMDIR) build
|
||||||
|
@if exist $(RELEASE_FOLDER) $(RMDIR) $(RELEASE_FOLDER)
|
||||||
|
else
|
||||||
|
@$(RMFILE) $(TARGET_FILE) $(TARGET_FILE)_debug
|
||||||
|
@$(RMDIR) build $(RELEASE_FOLDER)
|
||||||
|
@$(RMFILE) *.dmg *.zip *.tar.gz 2>/dev/null || true
|
||||||
|
@$(RMFILE) resources.pack 2>/dev/null || true
|
||||||
|
@$(MAKE) -C tools/pack_resources clean 2>/dev/null || true
|
||||||
|
endif
|
||||||
|
@echo "Clean complete"
|
||||||
|
|
||||||
|
# Backup to remote server
|
||||||
|
backup:
|
||||||
|
@echo "Backing up project to maverick:/home/sergio/git-backup/orni..."
|
||||||
|
rsync -a --delete \
|
||||||
|
--exclude='build/' \
|
||||||
|
--exclude='*.o' \
|
||||||
|
--exclude='*.exe' \
|
||||||
|
--exclude='orni' \
|
||||||
|
--exclude='orni_debug' \
|
||||||
|
--exclude='*_release/' \
|
||||||
|
$(DIR_ROOT) maverick:/home/sergio/git-backup/orni/
|
||||||
|
@echo "Backup completed successfully"
|
||||||
|
|
||||||
|
# Help target
|
||||||
|
help:
|
||||||
|
@echo "Available targets:"
|
||||||
|
@echo ""
|
||||||
|
@echo "Build:"
|
||||||
|
@echo " all - Build the game (default, delegates to CMake)"
|
||||||
|
@echo " debug - Build with debug symbols"
|
||||||
|
@echo " clean - Remove build artifacts and release packages"
|
||||||
|
@echo ""
|
||||||
|
@echo "Release Packaging:"
|
||||||
|
@echo " macos_release - Create macOS .app bundle + .dmg (Apple Silicon)"
|
||||||
|
@echo " linux_release - Create Linux .tar.gz"
|
||||||
|
@echo " windows_release - Create Windows .zip (requires MinGW on Windows)"
|
||||||
|
@echo " windows_cross - Cross-compile Windows from Linux/macOS (requires MinGW)"
|
||||||
|
@echo " rpi_release - Cross-compile for Raspberry Pi ARM64"
|
||||||
|
@echo ""
|
||||||
|
@echo "Other:"
|
||||||
|
@echo " backup - Backup project to remote server"
|
||||||
|
@echo " help - Show this help message"
|
||||||
|
@echo ""
|
||||||
|
@echo "Current configuration:"
|
||||||
|
@echo " Project: $(LONG_NAME)"
|
||||||
|
@echo " Target: $(TARGET_NAME)"
|
||||||
|
@echo " Version: $(VERSION)"
|
||||||
|
@echo " Platform: $(UNAME_S)"
|
||||||
BIN
data/music/game.ogg
Normal file
BIN
data/music/game.ogg
Normal file
Binary file not shown.
BIN
data/music/title.ogg
Normal file
BIN
data/music/title.ogg
Normal file
Binary file not shown.
23
data/shapes/bullet.shp
Normal file
23
data/shapes/bullet.shp
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# bullet.shp - Projectil (petit pentàgon)
|
||||||
|
# © 1999 Visente i Sergi (versió Pascal)
|
||||||
|
# © 2025 Port a C++20 amb SDL3
|
||||||
|
|
||||||
|
name: bullet
|
||||||
|
scale: 1.0
|
||||||
|
center: 0, 0
|
||||||
|
|
||||||
|
# Cercle (octàgon regular radi=3)
|
||||||
|
# 8 punts equidistants (45° entre ells) per aproximar un cercle
|
||||||
|
# Començant a angle=-90° (amunt), rotant sentit horari
|
||||||
|
#
|
||||||
|
# Conversió polar→cartesià (radi=3, SDL: Y creix cap avall):
|
||||||
|
# angle=-90°: (0.00, -3.00)
|
||||||
|
# angle=-45°: (2.12, -2.12)
|
||||||
|
# angle=0°: (3.00, 0.00)
|
||||||
|
# angle=45°: (2.12, 2.12)
|
||||||
|
# angle=90°: (0.00, 3.00)
|
||||||
|
# angle=135°: (-2.12, 2.12)
|
||||||
|
# angle=180°: (-3.00, 0.00)
|
||||||
|
# angle=225°: (-2.12, -2.12)
|
||||||
|
|
||||||
|
polyline: 0,-3 2.12,-2.12 3,0 2.12,2.12 0,3 -2.12,2.12 -3,0 -2.12,-2.12 0,-3
|
||||||
21
data/shapes/enemy_pentagon.shp
Normal file
21
data/shapes/enemy_pentagon.shp
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# enemy_pentagon.shp - ORNI enemic (pentàgon regular)
|
||||||
|
# © 1999 Visente i Sergi (versió Pascal)
|
||||||
|
# © 2025 Port a C++20 amb SDL3
|
||||||
|
|
||||||
|
name: enemy_pentagon
|
||||||
|
scale: 1.0
|
||||||
|
center: 0, 0
|
||||||
|
|
||||||
|
# Pentàgon regular radi=20
|
||||||
|
# 5 punts equidistants al voltant d'un cercle (72° entre ells)
|
||||||
|
# Començant a angle=-90° (amunt), rotant sentit antihorari
|
||||||
|
#
|
||||||
|
# Angles: -90°, -18°, 54°, 126°, 198°
|
||||||
|
# Conversió polar→cartesià (SDL: Y creix cap avall):
|
||||||
|
# angle=-90°: (0.00, -20.00)
|
||||||
|
# angle=-18°: (19.02, -6.18)
|
||||||
|
# angle=54°: (11.76, 16.18)
|
||||||
|
# angle=126°: (-11.76, 16.18)
|
||||||
|
# angle=198°: (-19.02, -6.18)
|
||||||
|
|
||||||
|
polyline: 0,-20 19.02,-6.18 11.76,16.18 -11.76,16.18 -19.02,-6.18 0,-20
|
||||||
30
data/shapes/enemy_pinwheel.shp
Normal file
30
data/shapes/enemy_pinwheel.shp
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# enemy_pinwheel.shp - ORNI enemic (molinillo de 4 triangles)
|
||||||
|
# © 2025 Port a C++20 amb SDL3
|
||||||
|
|
||||||
|
name: enemy_pinwheel
|
||||||
|
scale: 1.0
|
||||||
|
center: 0, 0
|
||||||
|
|
||||||
|
# Molinillo: 4 triangles, un en cada quadrant
|
||||||
|
# Cada triangle comparteix el centre (0,0) i té:
|
||||||
|
# - Un vèrtex en un eix (±20, 0) o (0, ±20)
|
||||||
|
# - Un vèrtex en la diagonal del quadrant (±14.14, ±14.14)
|
||||||
|
# - El tercer vèrtex al centre (0,0)
|
||||||
|
#
|
||||||
|
# Geometria:
|
||||||
|
# Triangle 1 (quadrant superior-dret): centre → eix dret → diagonal
|
||||||
|
# Triangle 2 (quadrant superior-esq): centre → eix superior → diagonal
|
||||||
|
# Triangle 3 (quadrant inferior-esq): centre → eix esquerre → diagonal
|
||||||
|
# Triangle 4 (quadrant inferior-dret): centre → eix inferior → diagonal
|
||||||
|
|
||||||
|
# Triangle 1: quadrant superior-dret
|
||||||
|
polyline: 0,0 20,0 14.14,-14.14 0,0
|
||||||
|
|
||||||
|
# Triangle 2: quadrant superior-esquerre
|
||||||
|
polyline: 0,0 0,-20 -14.14,-14.14 0,0
|
||||||
|
|
||||||
|
# Triangle 3: quadrant inferior-esquerre
|
||||||
|
polyline: 0,0 -20,0 -14.14,14.14 0,0
|
||||||
|
|
||||||
|
# Triangle 4: quadrant inferior-dret
|
||||||
|
polyline: 0,0 0,20 14.14,14.14 0,0
|
||||||
19
data/shapes/enemy_square.shp
Normal file
19
data/shapes/enemy_square.shp
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# enemy_square.shp - ORNI enemic (quadrat regular)
|
||||||
|
# © 2025 Port a C++20 amb SDL3
|
||||||
|
|
||||||
|
name: enemy_square
|
||||||
|
scale: 1.0
|
||||||
|
center: 0, 0
|
||||||
|
|
||||||
|
# Quadrat regular radi=20 (circumscrit)
|
||||||
|
# 4 punts equidistants al voltant d'un cercle (90° entre ells)
|
||||||
|
# Començant a angle=-90° (amunt), rotant sentit horari
|
||||||
|
#
|
||||||
|
# Angles: -90°, 0°, 90°, 180°
|
||||||
|
# Conversió polar→cartesià (SDL: Y creix cap avall):
|
||||||
|
# angle=-90°: (0.00, -20.00)
|
||||||
|
# angle=0°: (20.00, 0.00)
|
||||||
|
# angle=90°: (0.00, 20.00)
|
||||||
|
# angle=180°: (-20.00, 0.00)
|
||||||
|
|
||||||
|
polyline: 0,-20 20,0 0,20 -20,0 0,-20
|
||||||
10
data/shapes/font/char_0.shp
Normal file
10
data/shapes/font/char_0.shp
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# char_0.shp - Dígito 0
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
# Rectángulo cerrado (polyline continua, NO 6 líneas separadas)
|
||||||
|
|
||||||
|
name: char_0
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Rectángulo cerrado
|
||||||
|
polyline: 2,10 18,10 18,30 2,30 2,10
|
||||||
10
data/shapes/font/char_1.shp
Normal file
10
data/shapes/font/char_1.shp
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# char_1.shp - Dígito 1
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
# Línea vertical simple centrada
|
||||||
|
|
||||||
|
name: char_1
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Línea vertical central
|
||||||
|
line: 10,10 10,30
|
||||||
10
data/shapes/font/char_2.shp
Normal file
10
data/shapes/font/char_2.shp
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# char_2.shp - Dígito 2
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
# Forma de "2" con curva simulada (polyline continua)
|
||||||
|
|
||||||
|
name: char_2
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Trazo continuo en forma de S achatada
|
||||||
|
polyline: 2,10 18,10 18,20 2,20 2,30 18,30
|
||||||
11
data/shapes/font/char_3.shp
Normal file
11
data/shapes/font/char_3.shp
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# char_3.shp - Dígito 3
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
# Forma de "3" con dos curvas (polylines)
|
||||||
|
|
||||||
|
name: char_3
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Trazo continuo (barra superior + lateral derecho + barra media + lateral derecho + barra inferior)
|
||||||
|
polyline: 2,10 18,10 18,20 14,20
|
||||||
|
polyline: 14,20 18,20 18,30 2,30
|
||||||
12
data/shapes/font/char_4.shp
Normal file
12
data/shapes/font/char_4.shp
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# char_4.shp - Dígito 4
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
# Forma de "4" con líneas continuas
|
||||||
|
|
||||||
|
name: char_4
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Trazo principal (vertical izquierda + horizontal + vertical derecha superior)
|
||||||
|
polyline: 2,10 2,20 18,20
|
||||||
|
# Vertical derecha completa (cruza la horizontal)
|
||||||
|
line: 18,10 18,30
|
||||||
10
data/shapes/font/char_5.shp
Normal file
10
data/shapes/font/char_5.shp
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# char_5.shp - Dígito 5
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
# Forma de "5" con curva (polyline continua)
|
||||||
|
|
||||||
|
name: char_5
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Trazo continuo en forma de S invertida
|
||||||
|
polyline: 18,10 2,10 2,20 18,20 18,30 2,30
|
||||||
10
data/shapes/font/char_6.shp
Normal file
10
data/shapes/font/char_6.shp
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# char_6.shp - Dígito 6
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
# Forma de "6" con espiral (polyline continua)
|
||||||
|
|
||||||
|
name: char_6
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Trazo continuo: barra superior + lateral izquierdo + barra media + lateral derecho inferior + barra inferior + cierre
|
||||||
|
polyline: 18,10 2,10 2,30 18,30 18,20 2,20
|
||||||
10
data/shapes/font/char_7.shp
Normal file
10
data/shapes/font/char_7.shp
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# char_7.shp - Dígito 7
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
# Línea horizontal superior + diagonal hacia abajo-derecha
|
||||||
|
|
||||||
|
name: char_7
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Barra superior + diagonal
|
||||||
|
polyline: 2,10 18,10 18,30
|
||||||
12
data/shapes/font/char_8.shp
Normal file
12
data/shapes/font/char_8.shp
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# char_8.shp - Dígito 8
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
# Dos rectángulos apilados (polylines continuas)
|
||||||
|
|
||||||
|
name: char_8
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Rectángulo superior
|
||||||
|
polyline: 2,10 18,10 18,20 2,20 2,10
|
||||||
|
# Rectángulo inferior (comparte borde con el superior)
|
||||||
|
polyline: 2,20 18,20 18,30 2,30 2,20
|
||||||
10
data/shapes/font/char_9.shp
Normal file
10
data/shapes/font/char_9.shp
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# char_9.shp - Dígito 9
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
# Forma de "9" con espiral (polyline continua)
|
||||||
|
|
||||||
|
name: char_9
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Trazo continuo: lateral derecho completo + barra superior + lateral izquierdo superior + barra media
|
||||||
|
polyline: 18,30 18,10 2,10 2,20 18,20
|
||||||
11
data/shapes/font/char_A.shp
Normal file
11
data/shapes/font/char_A.shp
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# char_A.shp - Letra A
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
|
||||||
|
name: char_A
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Forma triangular (dos diagonales hacia arriba)
|
||||||
|
polyline: 2,30 10,10 18,30
|
||||||
|
# Barra horizontal media
|
||||||
|
line: 5,22 15,22
|
||||||
11
data/shapes/font/char_B.shp
Normal file
11
data/shapes/font/char_B.shp
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# char_B.shp - Letra B
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
|
||||||
|
name: char_B
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Rectángulo superior
|
||||||
|
polyline: 2,10 14,10 14,20 2,20 2,10
|
||||||
|
# Rectángulo inferior (más ancho)
|
||||||
|
polyline: 2,20 16,20 16,30 2,30 2,20
|
||||||
9
data/shapes/font/char_C.shp
Normal file
9
data/shapes/font/char_C.shp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# char_C.shp - Letra C
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
|
||||||
|
name: char_C
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Curva simulada (semicírculo abierto a la derecha)
|
||||||
|
polyline: 18,12 14,10 6,10 2,14 2,26 6,30 14,30 18,28
|
||||||
9
data/shapes/font/char_D.shp
Normal file
9
data/shapes/font/char_D.shp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# char_D.shp - Letra D
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
|
||||||
|
name: char_D
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Vertical izquierda + curva derecha simulada
|
||||||
|
polyline: 2,10 14,10 18,14 18,26 14,30 2,30 2,10
|
||||||
10
data/shapes/font/char_E.shp
Normal file
10
data/shapes/font/char_E.shp
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# char_E.shp - Letra E
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
|
||||||
|
name: char_E
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Forma de E (vertical izquierda + 3 horizontales)
|
||||||
|
polyline: 18,10 2,10 2,30 18,30
|
||||||
|
line: 2,20 14,20
|
||||||
10
data/shapes/font/char_F.shp
Normal file
10
data/shapes/font/char_F.shp
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# char_F.shp - Letra F
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
|
||||||
|
name: char_F
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Vertical izquierda + barra superior + barra media
|
||||||
|
polyline: 2,30 2,10 18,10
|
||||||
|
line: 2,20 14,20
|
||||||
9
data/shapes/font/char_G.shp
Normal file
9
data/shapes/font/char_G.shp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# char_G.shp - Letra G
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
|
||||||
|
name: char_G
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Como C pero con barra horizontal hacia adentro
|
||||||
|
polyline: 18,12 14,10 6,10 2,14 2,26 6,30 14,30 18,28 18,20 12,20
|
||||||
13
data/shapes/font/char_H.shp
Normal file
13
data/shapes/font/char_H.shp
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# char_H.shp - Letra H
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
|
||||||
|
name: char_H
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Vertical izquierda
|
||||||
|
line: 2,10 2,30
|
||||||
|
# Vertical derecha
|
||||||
|
line: 18,10 18,30
|
||||||
|
# Barra media
|
||||||
|
line: 2,20 18,20
|
||||||
9
data/shapes/font/char_I.shp
Normal file
9
data/shapes/font/char_I.shp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# char_I.shp - Letra I
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
|
||||||
|
name: char_I
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Línea vertical central
|
||||||
|
line: 10,10 10,30
|
||||||
9
data/shapes/font/char_J.shp
Normal file
9
data/shapes/font/char_J.shp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# char_J.shp - Letra J
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
|
||||||
|
name: char_J
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Vertical derecha con curva abajo-izquierda
|
||||||
|
polyline: 18,10 18,26 14,30 6,30 2,26
|
||||||
13
data/shapes/font/char_K.shp
Normal file
13
data/shapes/font/char_K.shp
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# char_K.shp - Letra K
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
|
||||||
|
name: char_K
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Vertical izquierda
|
||||||
|
line: 2,10 2,30
|
||||||
|
# Diagonal superior
|
||||||
|
line: 18,10 2,20
|
||||||
|
# Diagonal inferior
|
||||||
|
line: 2,20 18,30
|
||||||
9
data/shapes/font/char_L.shp
Normal file
9
data/shapes/font/char_L.shp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# char_L.shp - Letra L
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
|
||||||
|
name: char_L
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Forma de L (vertical izquierda + horizontal abajo)
|
||||||
|
polyline: 2,10 2,30 18,30
|
||||||
9
data/shapes/font/char_M.shp
Normal file
9
data/shapes/font/char_M.shp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# char_M.shp - Letra M
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
|
||||||
|
name: char_M
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Forma de M con pico en el medio
|
||||||
|
polyline: 2,30 2,10 10,20 18,10 18,30
|
||||||
9
data/shapes/font/char_N.shp
Normal file
9
data/shapes/font/char_N.shp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# char_N.shp - Letra N
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
|
||||||
|
name: char_N
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Vertical izquierda + diagonal + vertical derecha
|
||||||
|
polyline: 2,30 2,10 18,30 18,10
|
||||||
9
data/shapes/font/char_O.shp
Normal file
9
data/shapes/font/char_O.shp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# char_O.shp - Letra O
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
|
||||||
|
name: char_O
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Rectángulo cerrado
|
||||||
|
polyline: 2,10 18,10 18,30 2,30 2,10
|
||||||
11
data/shapes/font/char_P.shp
Normal file
11
data/shapes/font/char_P.shp
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# char_P.shp - Letra P
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
|
||||||
|
name: char_P
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Vertical izquierda completa
|
||||||
|
line: 2,10 2,30
|
||||||
|
# Rectángulo superior cerrado
|
||||||
|
polyline: 2,10 14,10 14,20 2,20
|
||||||
11
data/shapes/font/char_Q.shp
Normal file
11
data/shapes/font/char_Q.shp
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# char_Q.shp - Letra Q
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
|
||||||
|
name: char_Q
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Rectángulo cerrado (como O)
|
||||||
|
polyline: 2,10 18,10 18,30 2,30 2,10
|
||||||
|
# Diagonal inferior derecha (cola de la Q)
|
||||||
|
line: 12,24 18,30
|
||||||
13
data/shapes/font/char_R.shp
Normal file
13
data/shapes/font/char_R.shp
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# char_R.shp - Letra R
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
|
||||||
|
name: char_R
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Vertical izquierda completa
|
||||||
|
line: 2,10 2,30
|
||||||
|
# Rectángulo superior cerrado
|
||||||
|
polyline: 2,10 14,10 14,20 2,20
|
||||||
|
# Diagonal inferior derecha
|
||||||
|
line: 8,20 18,30
|
||||||
9
data/shapes/font/char_S.shp
Normal file
9
data/shapes/font/char_S.shp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# char_S.shp - Letra S
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
|
||||||
|
name: char_S
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Forma de S con curvas simuladas
|
||||||
|
polyline: 18,12 14,10 6,10 2,14 2,18 6,20 14,20 18,22 18,26 14,30 6,30 2,28
|
||||||
11
data/shapes/font/char_T.shp
Normal file
11
data/shapes/font/char_T.shp
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# char_T.shp - Letra T
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
|
||||||
|
name: char_T
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Barra horizontal superior
|
||||||
|
line: 2,10 18,10
|
||||||
|
# Línea vertical central
|
||||||
|
line: 10,10 10,30
|
||||||
9
data/shapes/font/char_U.shp
Normal file
9
data/shapes/font/char_U.shp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# char_U.shp - Letra U
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
|
||||||
|
name: char_U
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Forma de U (dos verticales + curva abajo)
|
||||||
|
polyline: 2,10 2,26 6,30 14,30 18,26 18,10
|
||||||
9
data/shapes/font/char_V.shp
Normal file
9
data/shapes/font/char_V.shp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# char_V.shp - Letra V
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
|
||||||
|
name: char_V
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Forma de V (dos diagonales hacia abajo)
|
||||||
|
polyline: 2,10 10,30 18,10
|
||||||
9
data/shapes/font/char_W.shp
Normal file
9
data/shapes/font/char_W.shp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# char_W.shp - Letra W
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
|
||||||
|
name: char_W
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Forma de W (doble V)
|
||||||
|
polyline: 2,10 5,30 10,20 15,30 18,10
|
||||||
11
data/shapes/font/char_X.shp
Normal file
11
data/shapes/font/char_X.shp
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# char_X.shp - Letra X
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
|
||||||
|
name: char_X
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Diagonal \
|
||||||
|
line: 2,10 18,30
|
||||||
|
# Diagonal /
|
||||||
|
line: 18,10 2,30
|
||||||
12
data/shapes/font/char_Y.shp
Normal file
12
data/shapes/font/char_Y.shp
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# char_Y.shp - Letra Y
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
|
||||||
|
name: char_Y
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Dos diagonales superiores que se juntan
|
||||||
|
polyline: 2,10 10,20
|
||||||
|
polyline: 18,10 10,20
|
||||||
|
# Línea vertical inferior
|
||||||
|
line: 10,20 10,30
|
||||||
9
data/shapes/font/char_Z.shp
Normal file
9
data/shapes/font/char_Z.shp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# char_Z.shp - Letra Z
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
|
||||||
|
name: char_Z
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Barra superior + diagonal + barra inferior
|
||||||
|
polyline: 2,10 18,10 2,30 18,30
|
||||||
11
data/shapes/font/char_colon.shp
Normal file
11
data/shapes/font/char_colon.shp
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# char_colon.shp - Símbolo : (dos puntos)
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
|
||||||
|
name: char_colon
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Punto superior
|
||||||
|
polyline: 8,14 12,14 12,17 8,17 8,14
|
||||||
|
# Punto inferior
|
||||||
|
polyline: 8,23 12,23 12,26 8,26 8,23
|
||||||
9
data/shapes/font/char_comma.shp
Normal file
9
data/shapes/font/char_comma.shp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# char_comma.shp - Símbolo , (coma)
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
|
||||||
|
name: char_comma
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Dot + tail hacia abajo-izquierda
|
||||||
|
polyline: 10,28 10,32 8,34
|
||||||
12
data/shapes/font/char_copyright.shp
Normal file
12
data/shapes/font/char_copyright.shp
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# char_copyright.shp - Símbolo © (copyright)
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
|
||||||
|
name: char_copyright
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Círculo exterior (aproximado con 12 puntos)
|
||||||
|
polyline: 10,8 13,9 15,11 17,14 18,17 18,23 17,26 15,29 13,31 10,32 7,31 5,29 3,26 2,23 2,17 3,14 5,11 7,9 10,8
|
||||||
|
|
||||||
|
# Letra C interior
|
||||||
|
polyline: 13,16 9,14 7,16 6,20 7,24 9,26 13,24
|
||||||
9
data/shapes/font/char_dot.shp
Normal file
9
data/shapes/font/char_dot.shp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# char_dot.shp - Símbolo . (punto)
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
|
||||||
|
name: char_dot
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Cuadrado pequeño centrado abajo
|
||||||
|
polyline: 8,28 12,28 12,32 8,32 8,28
|
||||||
11
data/shapes/font/char_exclamation.shp
Normal file
11
data/shapes/font/char_exclamation.shp
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# char_exclamation.shp - Símbolo ! (exclamación)
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
|
||||||
|
name: char_exclamation
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Línea vertical superior
|
||||||
|
line: 10,10 10,24
|
||||||
|
# Dot inferior
|
||||||
|
polyline: 8,28 12,28 12,32 8,32 8,28
|
||||||
9
data/shapes/font/char_minus.shp
Normal file
9
data/shapes/font/char_minus.shp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# char_minus.shp - Símbolo - (menos/guión)
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
|
||||||
|
name: char_minus
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Línea horizontal en el centro
|
||||||
|
line: 4,20 16,20
|
||||||
11
data/shapes/font/char_question.shp
Normal file
11
data/shapes/font/char_question.shp
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# char_question.shp - Símbolo ? (interrogación)
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
|
||||||
|
name: char_question
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# Curva superior + trazo hacia abajo
|
||||||
|
polyline: 2,12 10,10 18,12 18,18 10,20 10,24
|
||||||
|
# Dot inferior
|
||||||
|
polyline: 8,28 12,28 12,32 8,32 8,28
|
||||||
9
data/shapes/font/char_space.shp
Normal file
9
data/shapes/font/char_space.shp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# char_space.shp - Espacio (vacío)
|
||||||
|
# Dimensiones: 20×40 (blocky display)
|
||||||
|
# Sin geometría (espacio vacío intencional)
|
||||||
|
|
||||||
|
name: char_space
|
||||||
|
scale: 1.0
|
||||||
|
center: 10, 20
|
||||||
|
|
||||||
|
# No hay polylines ni lines (vacío intencionado)
|
||||||
10
data/shapes/logo/letra_a.shp
Normal file
10
data/shapes/logo/letra_a.shp
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# letra_a.shp
|
||||||
|
# Generado automáticamente desde jailgames.svg
|
||||||
|
# Dimensiones: 71.43 x 100.00 px
|
||||||
|
|
||||||
|
name: letra_a
|
||||||
|
scale: 1.0
|
||||||
|
center: 35.71, 50.00
|
||||||
|
|
||||||
|
polyline: 28.57,71.43 28.57,100.00 0.00,100.00 0.00,14.29 14.29,14.29 14.29,0.00 57.14,0.00 57.14,14.29 71.43,14.29 71.43,100.00 42.86,100.00 42.86,71.43 28.57,71.43
|
||||||
|
polyline: 28.57,14.29 28.57,57.14 42.86,57.14 42.86,14.29 28.57,14.29
|
||||||
9
data/shapes/logo/letra_e.shp
Normal file
9
data/shapes/logo/letra_e.shp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# letra_e.shp
|
||||||
|
# Generado automáticamente desde jailgames.svg
|
||||||
|
# Dimensiones: 71.43 x 100.00 px
|
||||||
|
|
||||||
|
name: letra_e
|
||||||
|
scale: 1.0
|
||||||
|
center: 35.71, 50.00
|
||||||
|
|
||||||
|
polyline: 57.14,28.57 57.14,42.86 28.57,42.86 28.57,85.71 71.43,85.71 71.43,100.00 0.00,100.00 0.00,0.00 71.43,0.00 71.43,14.29 28.57,14.29 28.57,28.57 57.14,28.57
|
||||||
9
data/shapes/logo/letra_g.shp
Normal file
9
data/shapes/logo/letra_g.shp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# letra_g.shp
|
||||||
|
# Generado automáticamente desde jailgames.svg
|
||||||
|
# Dimensiones: 71.43 x 100.00 px
|
||||||
|
|
||||||
|
name: letra_g
|
||||||
|
scale: 1.0
|
||||||
|
center: 35.71, 50.00
|
||||||
|
|
||||||
|
polyline: 14.29,0.00 57.14,0.00 57.14,14.29 28.57,14.29 28.57,85.71 42.86,85.71 42.86,42.86 71.43,42.86 71.43,100.00 14.29,100.00 14.29,85.71 0.00,85.71 0.00,14.29 14.29,14.29 14.29,0.00
|
||||||
9
data/shapes/logo/letra_i.shp
Normal file
9
data/shapes/logo/letra_i.shp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# letra_i.shp
|
||||||
|
# Generado automáticamente desde jailgames.svg
|
||||||
|
# Dimensiones: 28.57 x 100.00 px
|
||||||
|
|
||||||
|
name: letra_i
|
||||||
|
scale: 1.0
|
||||||
|
center: 14.29, 50.00
|
||||||
|
|
||||||
|
polyline: 0.00,0.00 28.57,0.00 28.57,100.00 0.00,100.00 0.00,0.00
|
||||||
9
data/shapes/logo/letra_j.shp
Normal file
9
data/shapes/logo/letra_j.shp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# letra_j.shp
|
||||||
|
# Generado automáticamente desde jailgames.svg
|
||||||
|
# Dimensiones: 57.14 x 100.00 px
|
||||||
|
|
||||||
|
name: letra_j
|
||||||
|
scale: 1.0
|
||||||
|
center: 28.57, 50.00
|
||||||
|
|
||||||
|
polyline: 0.00,100.00 0.00,85.71 28.57,85.71 28.57,0.00 57.14,0.00 57.14,85.71 42.86,85.71 42.86,100.00 0.00,100.00
|
||||||
9
data/shapes/logo/letra_l.shp
Normal file
9
data/shapes/logo/letra_l.shp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# letra_l.shp
|
||||||
|
# Generado automáticamente desde jailgames.svg
|
||||||
|
# Dimensiones: 57.14 x 100.00 px
|
||||||
|
|
||||||
|
name: letra_l
|
||||||
|
scale: 1.0
|
||||||
|
center: 28.57, 50.00
|
||||||
|
|
||||||
|
polyline: 0.00,0.00 28.57,0.00 28.57,85.71 57.14,85.71 57.14,100.00 0.00,100.00 0.00,0.00
|
||||||
9
data/shapes/logo/letra_m.shp
Normal file
9
data/shapes/logo/letra_m.shp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# letra_m.shp
|
||||||
|
# Generado automáticamente desde jailgames.svg
|
||||||
|
# Dimensiones: 100.00 x 100.00 px
|
||||||
|
|
||||||
|
name: letra_m
|
||||||
|
scale: 1.0
|
||||||
|
center: 50.00, 50.00
|
||||||
|
|
||||||
|
polyline: 71.43,57.14 57.14,57.14 57.14,71.43 42.86,71.43 42.86,57.14 28.57,57.14 28.57,100.00 0.00,100.00 0.00,0.00 14.29,0.00 14.29,14.29 28.57,14.29 28.57,28.57 42.86,28.57 42.86,42.86 57.14,42.86 57.14,28.57 71.43,28.57 71.43,14.29 85.71,14.29 85.71,0.00 100.00,0.00 100.00,100.00 71.43,100.00 71.43,57.14
|
||||||
9
data/shapes/logo/letra_s.shp
Normal file
9
data/shapes/logo/letra_s.shp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# letra_s.shp
|
||||||
|
# Generado automáticamente desde jailgames.svg
|
||||||
|
# Dimensiones: 57.14 x 100.00 px
|
||||||
|
|
||||||
|
name: letra_s
|
||||||
|
scale: 1.0
|
||||||
|
center: 28.57, 50.00
|
||||||
|
|
||||||
|
polyline: 0.00,85.71 28.57,85.71 28.57,57.14 14.29,57.14 14.29,42.86 0.00,42.86 0.00,14.29 14.29,14.29 14.29,0.00 57.14,0.00 57.14,14.29 28.57,14.29 28.57,42.86 42.86,42.86 42.86,57.14 57.14,57.14 57.14,85.71 42.86,85.71 42.86,100.00 0.00,100.00 0.00,85.71
|
||||||
20
data/shapes/ship.shp
Normal file
20
data/shapes/ship.shp
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# ship.shp - Nau del jugador (triangle)
|
||||||
|
# © 1999 Visente i Sergi (versió Pascal)
|
||||||
|
# © 2025 Port a C++20 amb SDL3
|
||||||
|
|
||||||
|
name: ship
|
||||||
|
scale: 1.0
|
||||||
|
center: 0, 0
|
||||||
|
|
||||||
|
# Triangle: punta amunt, base avall
|
||||||
|
# Punts originals (polar):
|
||||||
|
# p1: r=12, angle=270° (3π/2) → punta amunt
|
||||||
|
# p2: r=12, angle=45° (π/4) → base dreta-darrere
|
||||||
|
# p3: r=12, angle=135° (3π/4) → base esquerra-darrere
|
||||||
|
#
|
||||||
|
# Conversió polar→cartesià (angle-90° perquè origen visual és amunt):
|
||||||
|
# p1: (0, -12)
|
||||||
|
# p2: (8.49, 8.49)
|
||||||
|
# p3: (-8.49, 8.49)
|
||||||
|
|
||||||
|
polyline: 0,-12 8.49,8.49 -8.49,8.49 0,-12
|
||||||
24
data/shapes/ship2.shp
Normal file
24
data/shapes/ship2.shp
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# ship2.shp - Nau del jugador (triangle amb base còncava - punta de fletxa)
|
||||||
|
# © 1999 Visente i Sergi (versió Pascal)
|
||||||
|
# © 2025 Port a C++20 amb SDL3
|
||||||
|
|
||||||
|
name: ship2
|
||||||
|
scale: 1.0
|
||||||
|
center: 0, 0
|
||||||
|
|
||||||
|
# Triangle amb base còncava tipus "punta de fletxa"
|
||||||
|
# Punts originals (polar):
|
||||||
|
# p1: r=12, angle=270° (3π/2) → punta amunt
|
||||||
|
# p2: r=12, angle=45° (π/4) → base dreta-darrere
|
||||||
|
# p3: r=12, angle=135° (3π/4) → base esquerra-darrere
|
||||||
|
#
|
||||||
|
# MODIFICACIÓ: afegit p4 al mig de la base, desplaçat cap al centre
|
||||||
|
# p4: (0, 4) → punt central de la base, cap endins
|
||||||
|
#
|
||||||
|
# Conversió polar→cartesià (angle-90° perquè origen visual és amunt):
|
||||||
|
# p1: (0, -12) → punta
|
||||||
|
# p2: (8.49, 8.49) → base dreta
|
||||||
|
# p4: (0, 4) → base centre (cap endins)
|
||||||
|
# p3: (-8.49, 8.49) → base esquerra
|
||||||
|
|
||||||
|
polyline: 0,-12 8.49,8.49 0,4 -8.49,8.49 0,-12
|
||||||
19
data/shapes/star.shp
Normal file
19
data/shapes/star.shp
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# star.shp - Estrella per a starfield
|
||||||
|
# © 2025 Orni Attack
|
||||||
|
|
||||||
|
name: star
|
||||||
|
scale: 1.0
|
||||||
|
center: 0, 0
|
||||||
|
|
||||||
|
# Estrella de 4 puntes (diamant/creu)
|
||||||
|
# Petita i simple per a l'efecte starfield
|
||||||
|
#
|
||||||
|
# Punts:
|
||||||
|
# angle=0°: (0, -3) Dalt
|
||||||
|
# angle=90°: (3, 0) Dreta
|
||||||
|
# angle=180°: (0, 3) Baix
|
||||||
|
# angle=270°: (-3, 0) Esquerra
|
||||||
|
#
|
||||||
|
# Forma de diamant amb línies de centre a puntes
|
||||||
|
|
||||||
|
polyline: 0,-3 3,0 0,3 -3,0 0,-3
|
||||||
10
data/shapes/title/letra_a.shp
Normal file
10
data/shapes/title/letra_a.shp
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# letra_a.shp
|
||||||
|
# Generado automáticamente desde jailgames.svg
|
||||||
|
# Dimensiones: 137.50 x 100.00 px
|
||||||
|
|
||||||
|
name: letra_a
|
||||||
|
scale: 1.0
|
||||||
|
center: 68.75, 50.00
|
||||||
|
|
||||||
|
polyline: 0.00,100.00 0.00,75.00 37.50,0.00 100.00,0.00 137.50,75.00 137.50,100.00 100.00,100.00 100.00,87.50 37.50,87.50 37.50,100.00 0.00,100.00
|
||||||
|
polyline: 62.50,25.00 50.00,50.00 50.00,62.50 87.50,62.50 87.50,50.00 75.00,25.00 62.50,25.00
|
||||||
9
data/shapes/title/letra_c.shp
Normal file
9
data/shapes/title/letra_c.shp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# letra_c.shp
|
||||||
|
# Generado automáticamente desde jailgames.svg
|
||||||
|
# Dimensiones: 137.50 x 100.00 px
|
||||||
|
|
||||||
|
name: letra_c
|
||||||
|
scale: 1.0
|
||||||
|
center: 68.75, 50.00
|
||||||
|
|
||||||
|
polyline: 12.50,100.00 0.00,87.50 0.00,12.50 12.50,0.00 125.00,0.00 137.50,12.50 137.50,37.50 100.00,37.50 100.00,25.00 37.50,25.00 37.50,75.00 100.00,75.00 100.00,62.50 137.50,62.50 137.50,87.50 125.00,100.00 12.50,100.00
|
||||||
10
data/shapes/title/letra_exclamacion.shp
Normal file
10
data/shapes/title/letra_exclamacion.shp
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# letra_exclamacion.shp
|
||||||
|
# Generado automáticamente desde jailgames.svg
|
||||||
|
# Dimensiones: 37.51 x 100.00 px
|
||||||
|
|
||||||
|
name: letra_exclamacion
|
||||||
|
scale: 1.0
|
||||||
|
center: 18.75, 50.00
|
||||||
|
|
||||||
|
polyline: 0.00,62.50 0.00,0.00 37.51,0.00 37.51,62.50 0.00,62.50
|
||||||
|
polyline: 0.00,100.00 0.00,75.00 37.51,75.00 37.51,100.00 0.00,100.00
|
||||||
9
data/shapes/title/letra_i.shp
Normal file
9
data/shapes/title/letra_i.shp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# letra_i.shp
|
||||||
|
# Generado automáticamente desde jailgames.svg
|
||||||
|
# Dimensiones: 37.50 x 100.00 px
|
||||||
|
|
||||||
|
name: letra_i
|
||||||
|
scale: 1.0
|
||||||
|
center: 18.75, 50.00
|
||||||
|
|
||||||
|
polyline: 0.00,0.00 37.50,0.00 37.50,100.00 0.00,100.00 0.00,0.00
|
||||||
9
data/shapes/title/letra_k.shp
Normal file
9
data/shapes/title/letra_k.shp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# letra_k.shp
|
||||||
|
# Generado automáticamente desde jailgames.svg
|
||||||
|
# Dimensiones: 137.50 x 100.00 px
|
||||||
|
|
||||||
|
name: letra_k
|
||||||
|
scale: 1.0
|
||||||
|
center: 68.75, 50.00
|
||||||
|
|
||||||
|
polyline: 0.00,100.00 0.00,0.00 37.50,0.00 37.50,37.50 50.00,37.50 100.00,0.00 137.50,0.00 137.50,25.00 87.06,50.00 137.50,75.00 137.50,100.00 100.00,100.00 50.00,62.50 37.50,62.50 37.50,100.00 0.00,100.00
|
||||||
9
data/shapes/title/letra_n.shp
Normal file
9
data/shapes/title/letra_n.shp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# letra_n.shp
|
||||||
|
# Generado automáticamente desde jailgames.svg
|
||||||
|
# Dimensiones: 137.50 x 100.00 px
|
||||||
|
|
||||||
|
name: letra_n
|
||||||
|
scale: 1.0
|
||||||
|
center: 68.75, 50.00
|
||||||
|
|
||||||
|
polyline: 0.00,100.00 0.00,0.00 50.00,0.00 100.00,50.00 100.00,0.00 137.50,0.00 137.50,100.00 87.50,100.00 37.50,50.00 37.50,100.00 0.00,100.00
|
||||||
10
data/shapes/title/letra_o.shp
Normal file
10
data/shapes/title/letra_o.shp
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# letra_o.shp
|
||||||
|
# Generado automáticamente desde jailgames.svg
|
||||||
|
# Dimensiones: 137.50 x 100.00 px
|
||||||
|
|
||||||
|
name: letra_o
|
||||||
|
scale: 1.0
|
||||||
|
center: 68.75, 50.00
|
||||||
|
|
||||||
|
polyline: 12.50,100.00 0.00,87.50 0.00,12.50 12.50,0.00 125.00,0.00 137.50,12.50 137.50,87.50 125.00,100.00 12.50,100.00
|
||||||
|
polyline: 100.00,25.00 37.50,25.00 37.50,75.00 100.00,75.00 100.00,25.00
|
||||||
10
data/shapes/title/letra_r.shp
Normal file
10
data/shapes/title/letra_r.shp
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# letra_r.shp
|
||||||
|
# Generado automáticamente desde jailgames.svg
|
||||||
|
# Dimensiones: 137.50 x 100.00 px
|
||||||
|
|
||||||
|
name: letra_r
|
||||||
|
scale: 1.0
|
||||||
|
center: 68.75, 50.00
|
||||||
|
|
||||||
|
polyline: 0.00,100.00 0.00,0.00 125.00,0.00 137.50,12.50 137.50,62.50 125.00,62.50 137.50,75.00 137.50,100.00 100.00,100.00 100.00,75.00 37.50,75.00 37.50,100.00 0.00,100.00
|
||||||
|
polyline: 37.50,50.00 100.00,50.00 100.00,25.00 37.50,25.00 37.50,50.00
|
||||||
9
data/shapes/title/letra_t.shp
Normal file
9
data/shapes/title/letra_t.shp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# letra_t.shp
|
||||||
|
# Generado automáticamente desde jailgames.svg
|
||||||
|
# Dimensiones: 137.50 x 100.00 px
|
||||||
|
|
||||||
|
name: letra_t
|
||||||
|
scale: 1.0
|
||||||
|
center: 68.75, 50.00
|
||||||
|
|
||||||
|
polyline: 0.00,25.00 0.00,0.00 137.50,0.00 137.50,25.00 87.50,25.00 87.50,100.00 50.00,100.00 50.00,25.00 0.00,25.00
|
||||||
BIN
data/sounds/explosion.wav
Normal file
BIN
data/sounds/explosion.wav
Normal file
Binary file not shown.
BIN
data/sounds/good_job_commander.wav
Normal file
BIN
data/sounds/good_job_commander.wav
Normal file
Binary file not shown.
BIN
data/sounds/laser_shoot.wav
Normal file
BIN
data/sounds/laser_shoot.wav
Normal file
Binary file not shown.
BIN
data/sounds/logo.wav
Normal file
BIN
data/sounds/logo.wav
Normal file
Binary file not shown.
168
data/stages/stages.yaml
Normal file
168
data/stages/stages.yaml
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
# stages.yaml - Configuració de les 10 etapes d'Orni Attack
|
||||||
|
# © 2025 Orni Attack
|
||||||
|
|
||||||
|
metadata:
|
||||||
|
version: "1.0"
|
||||||
|
total_stages: 10
|
||||||
|
description: "Progressive difficulty curve from novice to expert"
|
||||||
|
|
||||||
|
stages:
|
||||||
|
# STAGE 1: Tutorial - Only pentagons, slow speed
|
||||||
|
- stage_id: 1
|
||||||
|
total_enemies: 5
|
||||||
|
spawn_config:
|
||||||
|
mode: "progressive"
|
||||||
|
initial_delay: 2.0
|
||||||
|
spawn_interval: 3.0
|
||||||
|
enemy_distribution:
|
||||||
|
pentagon: 100
|
||||||
|
quadrat: 0
|
||||||
|
molinillo: 0
|
||||||
|
difficulty_multipliers:
|
||||||
|
speed_multiplier: 0.7
|
||||||
|
rotation_multiplier: 0.8
|
||||||
|
tracking_strength: 0.0
|
||||||
|
|
||||||
|
# STAGE 2: Introduction to tracking enemies
|
||||||
|
- stage_id: 2
|
||||||
|
total_enemies: 7
|
||||||
|
spawn_config:
|
||||||
|
mode: "progressive"
|
||||||
|
initial_delay: 1.5
|
||||||
|
spawn_interval: 2.5
|
||||||
|
enemy_distribution:
|
||||||
|
pentagon: 70
|
||||||
|
quadrat: 30
|
||||||
|
molinillo: 0
|
||||||
|
difficulty_multipliers:
|
||||||
|
speed_multiplier: 0.85
|
||||||
|
rotation_multiplier: 0.9
|
||||||
|
tracking_strength: 0.3
|
||||||
|
|
||||||
|
# STAGE 3: All enemy types, normal speed
|
||||||
|
- stage_id: 3
|
||||||
|
total_enemies: 10
|
||||||
|
spawn_config:
|
||||||
|
mode: "progressive"
|
||||||
|
initial_delay: 1.0
|
||||||
|
spawn_interval: 2.0
|
||||||
|
enemy_distribution:
|
||||||
|
pentagon: 50
|
||||||
|
quadrat: 30
|
||||||
|
molinillo: 20
|
||||||
|
difficulty_multipliers:
|
||||||
|
speed_multiplier: 1.0
|
||||||
|
rotation_multiplier: 1.0
|
||||||
|
tracking_strength: 0.5
|
||||||
|
|
||||||
|
# STAGE 4: Increased count, faster enemies
|
||||||
|
- stage_id: 4
|
||||||
|
total_enemies: 12
|
||||||
|
spawn_config:
|
||||||
|
mode: "progressive"
|
||||||
|
initial_delay: 0.8
|
||||||
|
spawn_interval: 1.8
|
||||||
|
enemy_distribution:
|
||||||
|
pentagon: 40
|
||||||
|
quadrat: 35
|
||||||
|
molinillo: 25
|
||||||
|
difficulty_multipliers:
|
||||||
|
speed_multiplier: 1.1
|
||||||
|
rotation_multiplier: 1.15
|
||||||
|
tracking_strength: 0.6
|
||||||
|
|
||||||
|
# STAGE 5: Maximum count reached
|
||||||
|
- stage_id: 5
|
||||||
|
total_enemies: 15
|
||||||
|
spawn_config:
|
||||||
|
mode: "progressive"
|
||||||
|
initial_delay: 0.5
|
||||||
|
spawn_interval: 1.5
|
||||||
|
enemy_distribution:
|
||||||
|
pentagon: 35
|
||||||
|
quadrat: 35
|
||||||
|
molinillo: 30
|
||||||
|
difficulty_multipliers:
|
||||||
|
speed_multiplier: 1.2
|
||||||
|
rotation_multiplier: 1.25
|
||||||
|
tracking_strength: 0.7
|
||||||
|
|
||||||
|
# STAGE 6: Molinillo becomes dominant
|
||||||
|
- stage_id: 6
|
||||||
|
total_enemies: 15
|
||||||
|
spawn_config:
|
||||||
|
mode: "progressive"
|
||||||
|
initial_delay: 0.3
|
||||||
|
spawn_interval: 1.3
|
||||||
|
enemy_distribution:
|
||||||
|
pentagon: 30
|
||||||
|
quadrat: 30
|
||||||
|
molinillo: 40
|
||||||
|
difficulty_multipliers:
|
||||||
|
speed_multiplier: 1.3
|
||||||
|
rotation_multiplier: 1.4
|
||||||
|
tracking_strength: 0.8
|
||||||
|
|
||||||
|
# STAGE 7: High intensity, fast spawns
|
||||||
|
- stage_id: 7
|
||||||
|
total_enemies: 15
|
||||||
|
spawn_config:
|
||||||
|
mode: "progressive"
|
||||||
|
initial_delay: 0.2
|
||||||
|
spawn_interval: 1.0
|
||||||
|
enemy_distribution:
|
||||||
|
pentagon: 25
|
||||||
|
quadrat: 30
|
||||||
|
molinillo: 45
|
||||||
|
difficulty_multipliers:
|
||||||
|
speed_multiplier: 1.4
|
||||||
|
rotation_multiplier: 1.5
|
||||||
|
tracking_strength: 0.9
|
||||||
|
|
||||||
|
# STAGE 8: Expert level, 50% molinillos
|
||||||
|
- stage_id: 8
|
||||||
|
total_enemies: 15
|
||||||
|
spawn_config:
|
||||||
|
mode: "progressive"
|
||||||
|
initial_delay: 0.1
|
||||||
|
spawn_interval: 0.8
|
||||||
|
enemy_distribution:
|
||||||
|
pentagon: 20
|
||||||
|
quadrat: 30
|
||||||
|
molinillo: 50
|
||||||
|
difficulty_multipliers:
|
||||||
|
speed_multiplier: 1.5
|
||||||
|
rotation_multiplier: 1.6
|
||||||
|
tracking_strength: 1.0
|
||||||
|
|
||||||
|
# STAGE 9: Near-maximum difficulty
|
||||||
|
- stage_id: 9
|
||||||
|
total_enemies: 15
|
||||||
|
spawn_config:
|
||||||
|
mode: "progressive"
|
||||||
|
initial_delay: 0.0
|
||||||
|
spawn_interval: 0.6
|
||||||
|
enemy_distribution:
|
||||||
|
pentagon: 15
|
||||||
|
quadrat: 25
|
||||||
|
molinillo: 60
|
||||||
|
difficulty_multipliers:
|
||||||
|
speed_multiplier: 1.6
|
||||||
|
rotation_multiplier: 1.7
|
||||||
|
tracking_strength: 1.1
|
||||||
|
|
||||||
|
# STAGE 10: Final challenge, 70% molinillos
|
||||||
|
- stage_id: 10
|
||||||
|
total_enemies: 15
|
||||||
|
spawn_config:
|
||||||
|
mode: "progressive"
|
||||||
|
initial_delay: 0.0
|
||||||
|
spawn_interval: 0.5
|
||||||
|
enemy_distribution:
|
||||||
|
pentagon: 10
|
||||||
|
quadrat: 20
|
||||||
|
molinillo: 70
|
||||||
|
difficulty_multipliers:
|
||||||
|
speed_multiplier: 1.8
|
||||||
|
rotation_multiplier: 2.0
|
||||||
|
tracking_strength: 1.2
|
||||||
BIN
data/voices/good_job_commander.wav
Normal file
BIN
data/voices/good_job_commander.wav
Normal file
Binary file not shown.
42
release/Info.plist
Normal file
42
release/Info.plist
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>en</string>
|
||||||
|
<key>CFBundleDisplayName</key>
|
||||||
|
<string>Orni Attack</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>orni</string>
|
||||||
|
<key>CFBundleIconFile</key>
|
||||||
|
<string>icon</string>
|
||||||
|
<key>CFBundleIconName</key>
|
||||||
|
<string>icon</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>org.jailgames.orni</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>Orni Attack</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>APPL</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>0.1</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>????</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>0.1</string>
|
||||||
|
<key>CSResourcesFileMapped</key>
|
||||||
|
<true/>
|
||||||
|
<key>LSMinimumSystemVersion</key>
|
||||||
|
<string>10.15</string>
|
||||||
|
<key>NSHighResolutionCapable</key>
|
||||||
|
<true/>
|
||||||
|
<key>NSHumanReadableCopyright</key>
|
||||||
|
<string>© 1999 Visente i Sergi, 2025 Port</string>
|
||||||
|
<key>NSPrincipalClass</key>
|
||||||
|
<string>NSApplication</string>
|
||||||
|
<key>SUPublicDSAKeyFile</key>
|
||||||
|
<string>dsa_pub.pem</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
BIN
release/dll/SDL3.dll
Normal file
BIN
release/dll/SDL3.dll
Normal file
Binary file not shown.
BIN
release/dll/libwinpthread-1.dll
Normal file
BIN
release/dll/libwinpthread-1.dll
Normal file
Binary file not shown.
100
release/frameworks/SDL3.xcframework/Info.plist
Normal file
100
release/frameworks/SDL3.xcframework/Info.plist
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>AvailableLibraries</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>BinaryPath</key>
|
||||||
|
<string>SDL3.framework/Versions/A/SDL3</string>
|
||||||
|
<key>DebugSymbolsPath</key>
|
||||||
|
<string>dSYMs</string>
|
||||||
|
<key>LibraryIdentifier</key>
|
||||||
|
<string>macos-arm64_x86_64</string>
|
||||||
|
<key>LibraryPath</key>
|
||||||
|
<string>SDL3.framework</string>
|
||||||
|
<key>SupportedArchitectures</key>
|
||||||
|
<array>
|
||||||
|
<string>arm64</string>
|
||||||
|
<string>x86_64</string>
|
||||||
|
</array>
|
||||||
|
<key>SupportedPlatform</key>
|
||||||
|
<string>macos</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>BinaryPath</key>
|
||||||
|
<string>SDL3.framework/SDL3</string>
|
||||||
|
<key>DebugSymbolsPath</key>
|
||||||
|
<string>dSYMs</string>
|
||||||
|
<key>LibraryIdentifier</key>
|
||||||
|
<string>tvos-arm64_x86_64-simulator</string>
|
||||||
|
<key>LibraryPath</key>
|
||||||
|
<string>SDL3.framework</string>
|
||||||
|
<key>SupportedArchitectures</key>
|
||||||
|
<array>
|
||||||
|
<string>arm64</string>
|
||||||
|
<string>x86_64</string>
|
||||||
|
</array>
|
||||||
|
<key>SupportedPlatform</key>
|
||||||
|
<string>tvos</string>
|
||||||
|
<key>SupportedPlatformVariant</key>
|
||||||
|
<string>simulator</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>BinaryPath</key>
|
||||||
|
<string>SDL3.framework/SDL3</string>
|
||||||
|
<key>DebugSymbolsPath</key>
|
||||||
|
<string>dSYMs</string>
|
||||||
|
<key>LibraryIdentifier</key>
|
||||||
|
<string>tvos-arm64</string>
|
||||||
|
<key>LibraryPath</key>
|
||||||
|
<string>SDL3.framework</string>
|
||||||
|
<key>SupportedArchitectures</key>
|
||||||
|
<array>
|
||||||
|
<string>arm64</string>
|
||||||
|
</array>
|
||||||
|
<key>SupportedPlatform</key>
|
||||||
|
<string>tvos</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>BinaryPath</key>
|
||||||
|
<string>SDL3.framework/SDL3</string>
|
||||||
|
<key>DebugSymbolsPath</key>
|
||||||
|
<string>dSYMs</string>
|
||||||
|
<key>LibraryIdentifier</key>
|
||||||
|
<string>ios-arm64</string>
|
||||||
|
<key>LibraryPath</key>
|
||||||
|
<string>SDL3.framework</string>
|
||||||
|
<key>SupportedArchitectures</key>
|
||||||
|
<array>
|
||||||
|
<string>arm64</string>
|
||||||
|
</array>
|
||||||
|
<key>SupportedPlatform</key>
|
||||||
|
<string>ios</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>BinaryPath</key>
|
||||||
|
<string>SDL3.framework/SDL3</string>
|
||||||
|
<key>DebugSymbolsPath</key>
|
||||||
|
<string>dSYMs</string>
|
||||||
|
<key>LibraryIdentifier</key>
|
||||||
|
<string>ios-arm64_x86_64-simulator</string>
|
||||||
|
<key>LibraryPath</key>
|
||||||
|
<string>SDL3.framework</string>
|
||||||
|
<key>SupportedArchitectures</key>
|
||||||
|
<array>
|
||||||
|
<string>arm64</string>
|
||||||
|
<string>x86_64</string>
|
||||||
|
</array>
|
||||||
|
<key>SupportedPlatform</key>
|
||||||
|
<string>ios</string>
|
||||||
|
<key>SupportedPlatformVariant</key>
|
||||||
|
<string>simulator</string>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>XFWK</string>
|
||||||
|
<key>XCFrameworkFormatVersion</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
# SDL3 CMake configuration file:
|
||||||
|
# This file is meant to be placed in Resources/CMake of a SDL3 framework
|
||||||
|
|
||||||
|
# INTERFACE_LINK_OPTIONS needs CMake 3.12
|
||||||
|
cmake_minimum_required(VERSION 3.12)
|
||||||
|
|
||||||
|
include(FeatureSummary)
|
||||||
|
set_package_properties(SDL3 PROPERTIES
|
||||||
|
URL "https://www.libsdl.org/"
|
||||||
|
DESCRIPTION "low level access to audio, keyboard, mouse, joystick, and graphics hardware"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Copied from `configure_package_config_file`
|
||||||
|
macro(set_and_check _var _file)
|
||||||
|
set(${_var} "${_file}")
|
||||||
|
if(NOT EXISTS "${_file}")
|
||||||
|
message(FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist !")
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# Copied from `configure_package_config_file`
|
||||||
|
macro(check_required_components _NAME)
|
||||||
|
foreach(comp ${${_NAME}_FIND_COMPONENTS})
|
||||||
|
if(NOT ${_NAME}_${comp}_FOUND)
|
||||||
|
if(${_NAME}_FIND_REQUIRED_${comp})
|
||||||
|
set(${_NAME}_FOUND FALSE)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
set(SDL3_FOUND TRUE)
|
||||||
|
|
||||||
|
# Compute the installation prefix relative to this file.
|
||||||
|
set(_sdl3_framework_path "${CMAKE_CURRENT_LIST_DIR}") # > /SDL3.framework/Resources/CMake/
|
||||||
|
get_filename_component(_sdl3_framework_path "${_sdl3_framework_path}" REALPATH) # > /SDL3.framework/Versions/Current/Resources/CMake
|
||||||
|
get_filename_component(_sdl3_framework_path "${_sdl3_framework_path}" REALPATH) # > /SDL3.framework/Versions/A/Resources/CMake/
|
||||||
|
get_filename_component(_sdl3_framework_path "${_sdl3_framework_path}" PATH) # > /SDL3.framework/Versions/A/Resources/
|
||||||
|
get_filename_component(_sdl3_framework_path "${_sdl3_framework_path}" PATH) # > /SDL3.framework/Versions/A/
|
||||||
|
get_filename_component(_sdl3_framework_path "${_sdl3_framework_path}" PATH) # > /SDL3.framework/Versions/
|
||||||
|
get_filename_component(_sdl3_framework_path "${_sdl3_framework_path}" PATH) # > /SDL3.framework/
|
||||||
|
get_filename_component(_sdl3_framework_parent_path "${_sdl3_framework_path}" PATH) # > /
|
||||||
|
|
||||||
|
|
||||||
|
# All targets are created, even when some might not be requested though COMPONENTS.
|
||||||
|
# This is done for compatibility with CMake generated SDL3-target.cmake files.
|
||||||
|
|
||||||
|
if(NOT TARGET SDL3::Headers)
|
||||||
|
add_library(SDL3::Headers INTERFACE IMPORTED)
|
||||||
|
set_target_properties(SDL3::Headers
|
||||||
|
PROPERTIES
|
||||||
|
INTERFACE_COMPILE_OPTIONS "SHELL:-F \"${_sdl3_framework_parent_path}\""
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
set(SDL3_Headers_FOUND TRUE)
|
||||||
|
|
||||||
|
if(NOT TARGET SDL3::SDL3-shared)
|
||||||
|
add_library(SDL3::SDL3-shared SHARED IMPORTED)
|
||||||
|
set_target_properties(SDL3::SDL3-shared
|
||||||
|
PROPERTIES
|
||||||
|
FRAMEWORK "TRUE"
|
||||||
|
IMPORTED_LOCATION "${_sdl3_framework_path}/SDL3"
|
||||||
|
INTERFACE_LINK_LIBRARIES "SDL3::Headers"
|
||||||
|
COMPATIBLE_INTERFACE_BOOL "SDL3_SHARED"
|
||||||
|
INTERFACE_SDL3_SHARED "ON"
|
||||||
|
COMPATIBLE_INTERFACE_STRING "SDL_VERSION"
|
||||||
|
INTERFACE_SDL_VERSION "SDL3"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
set(SDL3_SDL3-shared_FOUND TRUE)
|
||||||
|
|
||||||
|
set(SDL3_SDL3-static FALSE)
|
||||||
|
|
||||||
|
set(SDL3_SDL3_test FALSE)
|
||||||
|
|
||||||
|
unset(_sdl3_framework_parent_path)
|
||||||
|
unset(_sdl3_framework_path)
|
||||||
|
|
||||||
|
if(SDL3_SDL3-shared_FOUND)
|
||||||
|
set(SDL3_SDL3_FOUND TRUE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
function(_sdl_create_target_alias_compat NEW_TARGET TARGET)
|
||||||
|
if(CMAKE_VERSION VERSION_LESS "3.18")
|
||||||
|
# Aliasing local targets is not supported on CMake < 3.18, so make it global.
|
||||||
|
add_library(${NEW_TARGET} INTERFACE IMPORTED)
|
||||||
|
set_target_properties(${NEW_TARGET} PROPERTIES INTERFACE_LINK_LIBRARIES "${TARGET}")
|
||||||
|
else()
|
||||||
|
add_library(${NEW_TARGET} ALIAS ${TARGET})
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# Make sure SDL3::SDL3 always exists
|
||||||
|
if(NOT TARGET SDL3::SDL3)
|
||||||
|
if(TARGET SDL3::SDL3-shared)
|
||||||
|
_sdl_create_target_alias_compat(SDL3::SDL3 SDL3::SDL3-shared)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
check_required_components(SDL3)
|
||||||
|
|
||||||
|
set(SDL3_LIBRARIES SDL3::SDL3)
|
||||||
|
set(SDL3_STATIC_LIBRARIES SDL3::SDL3-static)
|
||||||
|
set(SDL3_STATIC_PRIVATE_LIBS)
|
||||||
|
|
||||||
|
set(SDL3TEST_LIBRARY SDL3::SDL3_test)
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
# based on the files generated by CMake's write_basic_package_version_file
|
||||||
|
|
||||||
|
# SDL CMake version configuration file:
|
||||||
|
# This file is meant to be placed in Resources/CMake of a SDL3 framework
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.12)
|
||||||
|
|
||||||
|
if(NOT EXISTS "${CMAKE_CURRENT_LIST_DIR}/../../Headers/SDL_version.h")
|
||||||
|
message(AUTHOR_WARNING "Could not find SDL_version.h. This script is meant to be placed in the Resources/CMake directory of SDL2.framework")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
file(READ "${CMAKE_CURRENT_LIST_DIR}/../../Headers/SDL_version.h" _sdl_version_h)
|
||||||
|
string(REGEX MATCH "#define[ \t]+SDL_MAJOR_VERSION[ \t]+([0-9]+)" _sdl_major_re "${_sdl_version_h}")
|
||||||
|
set(_sdl_major "${CMAKE_MATCH_1}")
|
||||||
|
string(REGEX MATCH "#define[ \t]+SDL_MINOR_VERSION[ \t]+([0-9]+)" _sdl_minor_re "${_sdl_version_h}")
|
||||||
|
set(_sdl_minor "${CMAKE_MATCH_1}")
|
||||||
|
string(REGEX MATCH "#define[ \t]+SDL_MICRO_VERSION[ \t]+([0-9]+)" _sdl_micro_re "${_sdl_version_h}")
|
||||||
|
set(_sdl_micro "${CMAKE_MATCH_1}")
|
||||||
|
if(_sdl_major_re AND _sdl_minor_re AND _sdl_micro_re)
|
||||||
|
set(PACKAGE_VERSION "${_sdl_major}.${_sdl_minor}.${_sdl_micro}")
|
||||||
|
else()
|
||||||
|
message(AUTHOR_WARNING "Could not extract version from SDL_version.h.")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
unset(_sdl_major_re)
|
||||||
|
unset(_sdl_major)
|
||||||
|
unset(_sdl_minor_re)
|
||||||
|
unset(_sdl_minor)
|
||||||
|
unset(_sdl_micro_re)
|
||||||
|
unset(_sdl_micro)
|
||||||
|
|
||||||
|
if(PACKAGE_FIND_VERSION_RANGE)
|
||||||
|
# Package version must be in the requested version range
|
||||||
|
if ((PACKAGE_FIND_VERSION_RANGE_MIN STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION_MIN)
|
||||||
|
OR ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_GREATER PACKAGE_FIND_VERSION_MAX)
|
||||||
|
OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND PACKAGE_VERSION VERSION_GREATER_EQUAL PACKAGE_FIND_VERSION_MAX)))
|
||||||
|
set(PACKAGE_VERSION_COMPATIBLE FALSE)
|
||||||
|
else()
|
||||||
|
set(PACKAGE_VERSION_COMPATIBLE TRUE)
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
|
||||||
|
set(PACKAGE_VERSION_COMPATIBLE FALSE)
|
||||||
|
else()
|
||||||
|
set(PACKAGE_VERSION_COMPATIBLE TRUE)
|
||||||
|
if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
|
||||||
|
set(PACKAGE_VERSION_EXACT TRUE)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# The SDL3.xcframework only contains 64-bit archives
|
||||||
|
if(NOT "${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
|
||||||
|
set(PACKAGE_VERSION_UNSUITABLE TRUE)
|
||||||
|
endif()
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
Simple DirectMedia Layer
|
||||||
|
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main include header for the SDL library, version 3.2.26
|
||||||
|
*
|
||||||
|
* It is almost always best to include just this one header instead of
|
||||||
|
* picking out individual headers included here. There are exceptions to
|
||||||
|
* this rule--SDL_main.h is special and not included here--but usually
|
||||||
|
* letting SDL.h include the kitchen sink for you is the correct approach.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SDL_h_
|
||||||
|
#define SDL_h_
|
||||||
|
|
||||||
|
#include <SDL3/SDL_stdinc.h>
|
||||||
|
#include <SDL3/SDL_assert.h>
|
||||||
|
#include <SDL3/SDL_asyncio.h>
|
||||||
|
#include <SDL3/SDL_atomic.h>
|
||||||
|
#include <SDL3/SDL_audio.h>
|
||||||
|
#include <SDL3/SDL_bits.h>
|
||||||
|
#include <SDL3/SDL_blendmode.h>
|
||||||
|
#include <SDL3/SDL_camera.h>
|
||||||
|
#include <SDL3/SDL_clipboard.h>
|
||||||
|
#include <SDL3/SDL_cpuinfo.h>
|
||||||
|
#include <SDL3/SDL_dialog.h>
|
||||||
|
#include <SDL3/SDL_endian.h>
|
||||||
|
#include <SDL3/SDL_error.h>
|
||||||
|
#include <SDL3/SDL_events.h>
|
||||||
|
#include <SDL3/SDL_filesystem.h>
|
||||||
|
#include <SDL3/SDL_gamepad.h>
|
||||||
|
#include <SDL3/SDL_gpu.h>
|
||||||
|
#include <SDL3/SDL_guid.h>
|
||||||
|
#include <SDL3/SDL_haptic.h>
|
||||||
|
#include <SDL3/SDL_hidapi.h>
|
||||||
|
#include <SDL3/SDL_hints.h>
|
||||||
|
#include <SDL3/SDL_init.h>
|
||||||
|
#include <SDL3/SDL_iostream.h>
|
||||||
|
#include <SDL3/SDL_joystick.h>
|
||||||
|
#include <SDL3/SDL_keyboard.h>
|
||||||
|
#include <SDL3/SDL_keycode.h>
|
||||||
|
#include <SDL3/SDL_loadso.h>
|
||||||
|
#include <SDL3/SDL_locale.h>
|
||||||
|
#include <SDL3/SDL_log.h>
|
||||||
|
#include <SDL3/SDL_messagebox.h>
|
||||||
|
#include <SDL3/SDL_metal.h>
|
||||||
|
#include <SDL3/SDL_misc.h>
|
||||||
|
#include <SDL3/SDL_mouse.h>
|
||||||
|
#include <SDL3/SDL_mutex.h>
|
||||||
|
#include <SDL3/SDL_pen.h>
|
||||||
|
#include <SDL3/SDL_pixels.h>
|
||||||
|
#include <SDL3/SDL_platform.h>
|
||||||
|
#include <SDL3/SDL_power.h>
|
||||||
|
#include <SDL3/SDL_process.h>
|
||||||
|
#include <SDL3/SDL_properties.h>
|
||||||
|
#include <SDL3/SDL_rect.h>
|
||||||
|
#include <SDL3/SDL_render.h>
|
||||||
|
#include <SDL3/SDL_scancode.h>
|
||||||
|
#include <SDL3/SDL_sensor.h>
|
||||||
|
#include <SDL3/SDL_storage.h>
|
||||||
|
#include <SDL3/SDL_surface.h>
|
||||||
|
#include <SDL3/SDL_system.h>
|
||||||
|
#include <SDL3/SDL_thread.h>
|
||||||
|
#include <SDL3/SDL_time.h>
|
||||||
|
#include <SDL3/SDL_timer.h>
|
||||||
|
#include <SDL3/SDL_tray.h>
|
||||||
|
#include <SDL3/SDL_touch.h>
|
||||||
|
#include <SDL3/SDL_version.h>
|
||||||
|
#include <SDL3/SDL_video.h>
|
||||||
|
#include <SDL3/SDL_oldnames.h>
|
||||||
|
|
||||||
|
#endif /* SDL_h_ */
|
||||||
@@ -0,0 +1,662 @@
|
|||||||
|
/*
|
||||||
|
Simple DirectMedia Layer
|
||||||
|
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* # CategoryAssert
|
||||||
|
*
|
||||||
|
* A helpful assertion macro!
|
||||||
|
*
|
||||||
|
* SDL assertions operate like your usual `assert` macro, but with some added
|
||||||
|
* features:
|
||||||
|
*
|
||||||
|
* - It uses a trick with the `sizeof` operator, so disabled assertions
|
||||||
|
* vaporize out of the compiled code, but variables only referenced in the
|
||||||
|
* assertion won't trigger compiler warnings about being unused.
|
||||||
|
* - It is safe to use with a dangling-else: `if (x) SDL_assert(y); else
|
||||||
|
* do_something();`
|
||||||
|
* - It works the same everywhere, instead of counting on various platforms'
|
||||||
|
* compiler and C runtime to behave.
|
||||||
|
* - It provides multiple levels of assertion (SDL_assert, SDL_assert_release,
|
||||||
|
* SDL_assert_paranoid) instead of a single all-or-nothing option.
|
||||||
|
* - It offers a variety of responses when an assertion fails (retry, trigger
|
||||||
|
* the debugger, abort the program, ignore the failure once, ignore it for
|
||||||
|
* the rest of the program's run).
|
||||||
|
* - It tries to show the user a dialog by default, if possible, but the app
|
||||||
|
* can provide a callback to handle assertion failures however they like.
|
||||||
|
* - It lets failed assertions be retried. Perhaps you had a network failure
|
||||||
|
* and just want to retry the test after plugging your network cable back
|
||||||
|
* in? You can.
|
||||||
|
* - It lets the user ignore an assertion failure, if there's a harmless
|
||||||
|
* problem that one can continue past.
|
||||||
|
* - It lets the user mark an assertion as ignored for the rest of the
|
||||||
|
* program's run; if there's a harmless problem that keeps popping up.
|
||||||
|
* - It provides statistics and data on all failed assertions to the app.
|
||||||
|
* - It allows the default assertion handler to be controlled with environment
|
||||||
|
* variables, in case an automated script needs to control it.
|
||||||
|
* - It can be used as an aid to Clang's static analysis; it will treat SDL
|
||||||
|
* assertions as universally true (under the assumption that you are serious
|
||||||
|
* about the asserted claims and that your debug builds will detect when
|
||||||
|
* these claims were wrong). This can help the analyzer avoid false
|
||||||
|
* positives.
|
||||||
|
*
|
||||||
|
* To use it: compile a debug build and just sprinkle around tests to check
|
||||||
|
* your code!
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SDL_assert_h_
|
||||||
|
#define SDL_assert_h_
|
||||||
|
|
||||||
|
#include <SDL3/SDL_stdinc.h>
|
||||||
|
|
||||||
|
#include <SDL3/SDL_begin_code.h>
|
||||||
|
/* Set up for C function definitions, even when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SDL_WIKI_DOCUMENTATION_SECTION
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The level of assertion aggressiveness.
|
||||||
|
*
|
||||||
|
* This value changes depending on compiler options and other preprocessor
|
||||||
|
* defines.
|
||||||
|
*
|
||||||
|
* It is currently one of the following values, but future SDL releases might
|
||||||
|
* add more:
|
||||||
|
*
|
||||||
|
* - 0: All SDL assertion macros are disabled.
|
||||||
|
* - 1: Release settings: SDL_assert disabled, SDL_assert_release enabled.
|
||||||
|
* - 2: Debug settings: SDL_assert and SDL_assert_release enabled.
|
||||||
|
* - 3: Paranoid settings: All SDL assertion macros enabled, including
|
||||||
|
* SDL_assert_paranoid.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_ASSERT_LEVEL SomeNumberBasedOnVariousFactors
|
||||||
|
|
||||||
|
#elif !defined(SDL_ASSERT_LEVEL)
|
||||||
|
#ifdef SDL_DEFAULT_ASSERT_LEVEL
|
||||||
|
#define SDL_ASSERT_LEVEL SDL_DEFAULT_ASSERT_LEVEL
|
||||||
|
#elif defined(_DEBUG) || defined(DEBUG) || \
|
||||||
|
(defined(__GNUC__) && !defined(__OPTIMIZE__))
|
||||||
|
#define SDL_ASSERT_LEVEL 2
|
||||||
|
#else
|
||||||
|
#define SDL_ASSERT_LEVEL 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SDL_WIKI_DOCUMENTATION_SECTION
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to tell an attached debugger to pause.
|
||||||
|
*
|
||||||
|
* This allows an app to programmatically halt ("break") the debugger as if it
|
||||||
|
* had hit a breakpoint, allowing the developer to examine program state, etc.
|
||||||
|
*
|
||||||
|
* This is a macro--not a function--so that the debugger breaks on the source
|
||||||
|
* code line that used SDL_TriggerBreakpoint and not in some random guts of
|
||||||
|
* SDL. SDL_assert uses this macro for the same reason.
|
||||||
|
*
|
||||||
|
* If the program is not running under a debugger, SDL_TriggerBreakpoint will
|
||||||
|
* likely terminate the app, possibly without warning. If the current platform
|
||||||
|
* isn't supported, this macro is left undefined.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this macro from any thread.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_TriggerBreakpoint() TriggerABreakpointInAPlatformSpecificManner
|
||||||
|
|
||||||
|
#elif defined(__MINGW32__) || (defined(_MSC_VER) && _MSC_VER >= 1310)
|
||||||
|
/* Don't include intrin.h here because it contains C++ code */
|
||||||
|
extern void __cdecl __debugbreak(void);
|
||||||
|
#define SDL_TriggerBreakpoint() __debugbreak()
|
||||||
|
#elif defined(_MSC_VER) && defined(_M_IX86)
|
||||||
|
#define SDL_TriggerBreakpoint() { _asm { int 0x03 } }
|
||||||
|
#elif defined(ANDROID)
|
||||||
|
#include <assert.h>
|
||||||
|
#define SDL_TriggerBreakpoint() assert(0)
|
||||||
|
#elif SDL_HAS_BUILTIN(__builtin_debugtrap)
|
||||||
|
#define SDL_TriggerBreakpoint() __builtin_debugtrap()
|
||||||
|
#elif SDL_HAS_BUILTIN(__builtin_trap)
|
||||||
|
#define SDL_TriggerBreakpoint() __builtin_trap()
|
||||||
|
#elif (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__))
|
||||||
|
#define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "int $3\n\t" )
|
||||||
|
#elif (defined(__GNUC__) || defined(__clang__)) && defined(__riscv)
|
||||||
|
#define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "ebreak\n\t" )
|
||||||
|
#elif ( defined(SDL_PLATFORM_APPLE) && (defined(__arm64__) || defined(__aarch64__)) ) /* this might work on other ARM targets, but this is a known quantity... */
|
||||||
|
#define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "brk #22\n\t" )
|
||||||
|
#elif defined(SDL_PLATFORM_APPLE) && defined(__arm__)
|
||||||
|
#define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "bkpt #22\n\t" )
|
||||||
|
#elif defined(_WIN32) && ((defined(__GNUC__) || defined(__clang__)) && (defined(__arm64__) || defined(__aarch64__)) )
|
||||||
|
#define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "brk #0xF000\n\t" )
|
||||||
|
#elif defined(__GNUC__) || defined(__clang__)
|
||||||
|
#define SDL_TriggerBreakpoint() __builtin_trap() /* older gcc may not support SDL_HAS_BUILTIN(__builtin_trap) above */
|
||||||
|
#elif defined(__386__) && defined(__WATCOMC__)
|
||||||
|
#define SDL_TriggerBreakpoint() { _asm { int 0x03 } }
|
||||||
|
#elif defined(HAVE_SIGNAL_H) && !defined(__WATCOMC__)
|
||||||
|
#include <signal.h>
|
||||||
|
#define SDL_TriggerBreakpoint() raise(SIGTRAP)
|
||||||
|
#else
|
||||||
|
/* SDL_TriggerBreakpoint is intentionally left undefined on unknown platforms. */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SDL_WIKI_DOCUMENTATION_SECTION
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A macro that reports the current function being compiled.
|
||||||
|
*
|
||||||
|
* If SDL can't figure how the compiler reports this, it will use "???".
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_FUNCTION __FUNCTION__
|
||||||
|
|
||||||
|
#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 supports __func__ as a standard. */
|
||||||
|
# define SDL_FUNCTION __func__
|
||||||
|
#elif ((defined(__GNUC__) && (__GNUC__ >= 2)) || defined(_MSC_VER) || defined (__WATCOMC__))
|
||||||
|
# define SDL_FUNCTION __FUNCTION__
|
||||||
|
#else
|
||||||
|
# define SDL_FUNCTION "???"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A macro that reports the current file being compiled.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_FILE __FILE__
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A macro that reports the current line number of the file being compiled.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_LINE __LINE__
|
||||||
|
|
||||||
|
/*
|
||||||
|
sizeof (x) makes the compiler still parse the expression even without
|
||||||
|
assertions enabled, so the code is always checked at compile time, but
|
||||||
|
doesn't actually generate code for it, so there are no side effects or
|
||||||
|
expensive checks at run time, just the constant size of what x WOULD be,
|
||||||
|
which presumably gets optimized out as unused.
|
||||||
|
This also solves the problem of...
|
||||||
|
|
||||||
|
int somevalue = blah();
|
||||||
|
SDL_assert(somevalue == 1);
|
||||||
|
|
||||||
|
...which would cause compiles to complain that somevalue is unused if we
|
||||||
|
disable assertions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef SDL_WIKI_DOCUMENTATION_SECTION
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A macro for wrapping code in `do {} while (0);` without compiler warnings.
|
||||||
|
*
|
||||||
|
* Visual Studio with really aggressive warnings enabled needs this to avoid
|
||||||
|
* compiler complaints.
|
||||||
|
*
|
||||||
|
* the `do {} while (0);` trick is useful for wrapping code in a macro that
|
||||||
|
* may or may not be a single statement, to avoid various C language
|
||||||
|
* accidents.
|
||||||
|
*
|
||||||
|
* To use:
|
||||||
|
*
|
||||||
|
* ```c
|
||||||
|
* do { SomethingOnce(); } while (SDL_NULL_WHILE_LOOP_CONDITION (0));
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_NULL_WHILE_LOOP_CONDITION (0)
|
||||||
|
|
||||||
|
#elif defined(_MSC_VER) /* Avoid /W4 warnings. */
|
||||||
|
/* "while (0,0)" fools Microsoft's compiler's /W4 warning level into thinking
|
||||||
|
this condition isn't constant. And looks like an owl's face! */
|
||||||
|
#define SDL_NULL_WHILE_LOOP_CONDITION (0,0)
|
||||||
|
#else
|
||||||
|
#define SDL_NULL_WHILE_LOOP_CONDITION (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The macro used when an assertion is disabled.
|
||||||
|
*
|
||||||
|
* This isn't for direct use by apps, but this is the code that is inserted
|
||||||
|
* when an SDL_assert is disabled (perhaps in a release build).
|
||||||
|
*
|
||||||
|
* The code does nothing, but wraps `condition` in a sizeof operator, which
|
||||||
|
* generates no code and has no side effects, but avoid compiler warnings
|
||||||
|
* about unused variables.
|
||||||
|
*
|
||||||
|
* \param condition the condition to assert (but not actually run here).
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_disabled_assert(condition) \
|
||||||
|
do { (void) sizeof ((condition)); } while (SDL_NULL_WHILE_LOOP_CONDITION)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Possible outcomes from a triggered assertion.
|
||||||
|
*
|
||||||
|
* When an enabled assertion triggers, it may call the assertion handler
|
||||||
|
* (possibly one provided by the app via SDL_SetAssertionHandler), which will
|
||||||
|
* return one of these values, possibly after asking the user.
|
||||||
|
*
|
||||||
|
* Then SDL will respond based on this outcome (loop around to retry the
|
||||||
|
* condition, try to break in a debugger, kill the program, or ignore the
|
||||||
|
* problem).
|
||||||
|
*
|
||||||
|
* \since This enum is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
typedef enum SDL_AssertState
|
||||||
|
{
|
||||||
|
SDL_ASSERTION_RETRY, /**< Retry the assert immediately. */
|
||||||
|
SDL_ASSERTION_BREAK, /**< Make the debugger trigger a breakpoint. */
|
||||||
|
SDL_ASSERTION_ABORT, /**< Terminate the program. */
|
||||||
|
SDL_ASSERTION_IGNORE, /**< Ignore the assert. */
|
||||||
|
SDL_ASSERTION_ALWAYS_IGNORE /**< Ignore the assert from now on. */
|
||||||
|
} SDL_AssertState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about an assertion failure.
|
||||||
|
*
|
||||||
|
* This structure is filled in with information about a triggered assertion,
|
||||||
|
* used by the assertion handler, then added to the assertion report. This is
|
||||||
|
* returned as a linked list from SDL_GetAssertionReport().
|
||||||
|
*
|
||||||
|
* \since This struct is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
typedef struct SDL_AssertData
|
||||||
|
{
|
||||||
|
bool always_ignore; /**< true if app should always continue when assertion is triggered. */
|
||||||
|
unsigned int trigger_count; /**< Number of times this assertion has been triggered. */
|
||||||
|
const char *condition; /**< A string of this assert's test code. */
|
||||||
|
const char *filename; /**< The source file where this assert lives. */
|
||||||
|
int linenum; /**< The line in `filename` where this assert lives. */
|
||||||
|
const char *function; /**< The name of the function where this assert lives. */
|
||||||
|
const struct SDL_AssertData *next; /**< next item in the linked list. */
|
||||||
|
} SDL_AssertData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Never call this directly.
|
||||||
|
*
|
||||||
|
* Use the SDL_assert macros instead.
|
||||||
|
*
|
||||||
|
* \param data assert data structure.
|
||||||
|
* \param func function name.
|
||||||
|
* \param file file name.
|
||||||
|
* \param line line number.
|
||||||
|
* \returns assert state.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC SDL_AssertState SDLCALL SDL_ReportAssertion(SDL_AssertData *data,
|
||||||
|
const char *func,
|
||||||
|
const char *file, int line) SDL_ANALYZER_NORETURN;
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef SDL_WIKI_DOCUMENTATION_SECTION
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The macro used when an assertion triggers a breakpoint.
|
||||||
|
*
|
||||||
|
* This isn't for direct use by apps; use SDL_assert or SDL_TriggerBreakpoint
|
||||||
|
* instead.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_AssertBreakpoint() SDL_TriggerBreakpoint()
|
||||||
|
|
||||||
|
#elif !defined(SDL_AssertBreakpoint)
|
||||||
|
# if defined(ANDROID) && defined(assert)
|
||||||
|
/* Define this as empty in case assert() is defined as SDL_assert */
|
||||||
|
# define SDL_AssertBreakpoint()
|
||||||
|
# else
|
||||||
|
# define SDL_AssertBreakpoint() SDL_TriggerBreakpoint()
|
||||||
|
# endif
|
||||||
|
#endif /* !SDL_AssertBreakpoint */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The macro used when an assertion is enabled.
|
||||||
|
*
|
||||||
|
* This isn't for direct use by apps, but this is the code that is inserted
|
||||||
|
* when an SDL_assert is enabled.
|
||||||
|
*
|
||||||
|
* The `do {} while(0)` avoids dangling else problems:
|
||||||
|
*
|
||||||
|
* ```c
|
||||||
|
* if (x) SDL_assert(y); else blah();
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* ... without the do/while, the "else" could attach to this macro's "if". We
|
||||||
|
* try to handle just the minimum we need here in a macro...the loop, the
|
||||||
|
* static vars, and break points. The heavy lifting is handled in
|
||||||
|
* SDL_ReportAssertion().
|
||||||
|
*
|
||||||
|
* \param condition the condition to assert.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_enabled_assert(condition) \
|
||||||
|
do { \
|
||||||
|
while ( !(condition) ) { \
|
||||||
|
static struct SDL_AssertData sdl_assert_data = { false, 0, #condition, NULL, 0, NULL, NULL }; \
|
||||||
|
const SDL_AssertState sdl_assert_state = SDL_ReportAssertion(&sdl_assert_data, SDL_FUNCTION, SDL_FILE, SDL_LINE); \
|
||||||
|
if (sdl_assert_state == SDL_ASSERTION_RETRY) { \
|
||||||
|
continue; /* go again. */ \
|
||||||
|
} else if (sdl_assert_state == SDL_ASSERTION_BREAK) { \
|
||||||
|
SDL_AssertBreakpoint(); \
|
||||||
|
} \
|
||||||
|
break; /* not retrying. */ \
|
||||||
|
} \
|
||||||
|
} while (SDL_NULL_WHILE_LOOP_CONDITION)
|
||||||
|
|
||||||
|
#ifdef SDL_WIKI_DOCUMENTATION_SECTION
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An assertion test that is normally performed only in debug builds.
|
||||||
|
*
|
||||||
|
* This macro is enabled when the SDL_ASSERT_LEVEL is >= 2, otherwise it is
|
||||||
|
* disabled. This is meant to only do these tests in debug builds, so they can
|
||||||
|
* tend to be more expensive, and they are meant to bring everything to a halt
|
||||||
|
* when they fail, with the programmer there to assess the problem.
|
||||||
|
*
|
||||||
|
* In short: you can sprinkle these around liberally and assume they will
|
||||||
|
* evaporate out of the build when building for end-users.
|
||||||
|
*
|
||||||
|
* When assertions are disabled, this wraps `condition` in a `sizeof`
|
||||||
|
* operator, which means any function calls and side effects will not run, but
|
||||||
|
* the compiler will not complain about any otherwise-unused variables that
|
||||||
|
* are only referenced in the assertion.
|
||||||
|
*
|
||||||
|
* One can set the environment variable "SDL_ASSERT" to one of several strings
|
||||||
|
* ("abort", "break", "retry", "ignore", "always_ignore") to force a default
|
||||||
|
* behavior, which may be desirable for automation purposes. If your platform
|
||||||
|
* requires GUI interfaces to happen on the main thread but you're debugging
|
||||||
|
* an assertion in a background thread, it might be desirable to set this to
|
||||||
|
* "break" so that your debugger takes control as soon as assert is triggered,
|
||||||
|
* instead of risking a bad UI interaction (deadlock, etc) in the application.
|
||||||
|
*
|
||||||
|
* \param condition boolean value to test.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this macro from any thread.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_assert(condition) if (assertion_enabled && (condition)) { trigger_assertion; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An assertion test that is performed even in release builds.
|
||||||
|
*
|
||||||
|
* This macro is enabled when the SDL_ASSERT_LEVEL is >= 1, otherwise it is
|
||||||
|
* disabled. This is meant to be for tests that are cheap to make and
|
||||||
|
* extremely unlikely to fail; generally it is frowned upon to have an
|
||||||
|
* assertion failure in a release build, so these assertions generally need to
|
||||||
|
* be of more than life-and-death importance if there's a chance they might
|
||||||
|
* trigger. You should almost always consider handling these cases more
|
||||||
|
* gracefully than an assert allows.
|
||||||
|
*
|
||||||
|
* When assertions are disabled, this wraps `condition` in a `sizeof`
|
||||||
|
* operator, which means any function calls and side effects will not run, but
|
||||||
|
* the compiler will not complain about any otherwise-unused variables that
|
||||||
|
* are only referenced in the assertion.
|
||||||
|
*
|
||||||
|
* One can set the environment variable "SDL_ASSERT" to one of several strings
|
||||||
|
* ("abort", "break", "retry", "ignore", "always_ignore") to force a default
|
||||||
|
* behavior, which may be desirable for automation purposes. If your platform
|
||||||
|
* requires GUI interfaces to happen on the main thread but you're debugging
|
||||||
|
* an assertion in a background thread, it might be desirable to set this to
|
||||||
|
* "break" so that your debugger takes control as soon as assert is triggered,
|
||||||
|
* instead of risking a bad UI interaction (deadlock, etc) in the application.
|
||||||
|
* *
|
||||||
|
*
|
||||||
|
* \param condition boolean value to test.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this macro from any thread.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_assert_release(condition) SDL_disabled_assert(condition)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An assertion test that is performed only when built with paranoid settings.
|
||||||
|
*
|
||||||
|
* This macro is enabled when the SDL_ASSERT_LEVEL is >= 3, otherwise it is
|
||||||
|
* disabled. This is a higher level than both release and debug, so these
|
||||||
|
* tests are meant to be expensive and only run when specifically looking for
|
||||||
|
* extremely unexpected failure cases in a special build.
|
||||||
|
*
|
||||||
|
* When assertions are disabled, this wraps `condition` in a `sizeof`
|
||||||
|
* operator, which means any function calls and side effects will not run, but
|
||||||
|
* the compiler will not complain about any otherwise-unused variables that
|
||||||
|
* are only referenced in the assertion.
|
||||||
|
*
|
||||||
|
* One can set the environment variable "SDL_ASSERT" to one of several strings
|
||||||
|
* ("abort", "break", "retry", "ignore", "always_ignore") to force a default
|
||||||
|
* behavior, which may be desirable for automation purposes. If your platform
|
||||||
|
* requires GUI interfaces to happen on the main thread but you're debugging
|
||||||
|
* an assertion in a background thread, it might be desirable to set this to
|
||||||
|
* "break" so that your debugger takes control as soon as assert is triggered,
|
||||||
|
* instead of risking a bad UI interaction (deadlock, etc) in the application.
|
||||||
|
*
|
||||||
|
* \param condition boolean value to test.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this macro from any thread.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_assert_paranoid(condition) SDL_disabled_assert(condition)
|
||||||
|
|
||||||
|
/* Enable various levels of assertions. */
|
||||||
|
#elif SDL_ASSERT_LEVEL == 0 /* assertions disabled */
|
||||||
|
# define SDL_assert(condition) SDL_disabled_assert(condition)
|
||||||
|
# define SDL_assert_release(condition) SDL_disabled_assert(condition)
|
||||||
|
# define SDL_assert_paranoid(condition) SDL_disabled_assert(condition)
|
||||||
|
#elif SDL_ASSERT_LEVEL == 1 /* release settings. */
|
||||||
|
# define SDL_assert(condition) SDL_disabled_assert(condition)
|
||||||
|
# define SDL_assert_release(condition) SDL_enabled_assert(condition)
|
||||||
|
# define SDL_assert_paranoid(condition) SDL_disabled_assert(condition)
|
||||||
|
#elif SDL_ASSERT_LEVEL == 2 /* debug settings. */
|
||||||
|
# define SDL_assert(condition) SDL_enabled_assert(condition)
|
||||||
|
# define SDL_assert_release(condition) SDL_enabled_assert(condition)
|
||||||
|
# define SDL_assert_paranoid(condition) SDL_disabled_assert(condition)
|
||||||
|
#elif SDL_ASSERT_LEVEL == 3 /* paranoid settings. */
|
||||||
|
# define SDL_assert(condition) SDL_enabled_assert(condition)
|
||||||
|
# define SDL_assert_release(condition) SDL_enabled_assert(condition)
|
||||||
|
# define SDL_assert_paranoid(condition) SDL_enabled_assert(condition)
|
||||||
|
#else
|
||||||
|
# error Unknown assertion level.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An assertion test that is always performed.
|
||||||
|
*
|
||||||
|
* This macro is always enabled no matter what SDL_ASSERT_LEVEL is set to. You
|
||||||
|
* almost never want to use this, as it could trigger on an end-user's system,
|
||||||
|
* crashing your program.
|
||||||
|
*
|
||||||
|
* One can set the environment variable "SDL_ASSERT" to one of several strings
|
||||||
|
* ("abort", "break", "retry", "ignore", "always_ignore") to force a default
|
||||||
|
* behavior, which may be desirable for automation purposes. If your platform
|
||||||
|
* requires GUI interfaces to happen on the main thread but you're debugging
|
||||||
|
* an assertion in a background thread, it might be desirable to set this to
|
||||||
|
* "break" so that your debugger takes control as soon as assert is triggered,
|
||||||
|
* instead of risking a bad UI interaction (deadlock, etc) in the application.
|
||||||
|
*
|
||||||
|
* \param condition boolean value to test.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this macro from any thread.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_assert_always(condition) SDL_enabled_assert(condition)
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A callback that fires when an SDL assertion fails.
|
||||||
|
*
|
||||||
|
* \param data a pointer to the SDL_AssertData structure corresponding to the
|
||||||
|
* current assertion.
|
||||||
|
* \param userdata what was passed as `userdata` to SDL_SetAssertionHandler().
|
||||||
|
* \returns an SDL_AssertState value indicating how to handle the failure.
|
||||||
|
*
|
||||||
|
* \threadsafety This callback may be called from any thread that triggers an
|
||||||
|
* assert at any time.
|
||||||
|
*
|
||||||
|
* \since This datatype is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
typedef SDL_AssertState (SDLCALL *SDL_AssertionHandler)(
|
||||||
|
const SDL_AssertData *data, void *userdata);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set an application-defined assertion handler.
|
||||||
|
*
|
||||||
|
* This function allows an application to show its own assertion UI and/or
|
||||||
|
* force the response to an assertion failure. If the application doesn't
|
||||||
|
* provide this, SDL will try to do the right thing, popping up a
|
||||||
|
* system-specific GUI dialog, and probably minimizing any fullscreen windows.
|
||||||
|
*
|
||||||
|
* This callback may fire from any thread, but it runs wrapped in a mutex, so
|
||||||
|
* it will only fire from one thread at a time.
|
||||||
|
*
|
||||||
|
* This callback is NOT reset to SDL's internal handler upon SDL_Quit()!
|
||||||
|
*
|
||||||
|
* \param handler the SDL_AssertionHandler function to call when an assertion
|
||||||
|
* fails or NULL for the default handler.
|
||||||
|
* \param userdata a pointer that is passed to `handler`.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetAssertionHandler
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC void SDLCALL SDL_SetAssertionHandler(
|
||||||
|
SDL_AssertionHandler handler,
|
||||||
|
void *userdata);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the default assertion handler.
|
||||||
|
*
|
||||||
|
* This returns the function pointer that is called by default when an
|
||||||
|
* assertion is triggered. This is an internal function provided by SDL, that
|
||||||
|
* is used for assertions when SDL_SetAssertionHandler() hasn't been used to
|
||||||
|
* provide a different function.
|
||||||
|
*
|
||||||
|
* \returns the default SDL_AssertionHandler that is called when an assert
|
||||||
|
* triggers.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetAssertionHandler
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC SDL_AssertionHandler SDLCALL SDL_GetDefaultAssertionHandler(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current assertion handler.
|
||||||
|
*
|
||||||
|
* This returns the function pointer that is called when an assertion is
|
||||||
|
* triggered. This is either the value last passed to
|
||||||
|
* SDL_SetAssertionHandler(), or if no application-specified function is set,
|
||||||
|
* is equivalent to calling SDL_GetDefaultAssertionHandler().
|
||||||
|
*
|
||||||
|
* The parameter `puserdata` is a pointer to a void*, which will store the
|
||||||
|
* "userdata" pointer that was passed to SDL_SetAssertionHandler(). This value
|
||||||
|
* will always be NULL for the default handler. If you don't care about this
|
||||||
|
* data, it is safe to pass a NULL pointer to this function to ignore it.
|
||||||
|
*
|
||||||
|
* \param puserdata pointer which is filled with the "userdata" pointer that
|
||||||
|
* was passed to SDL_SetAssertionHandler().
|
||||||
|
* \returns the SDL_AssertionHandler that is called when an assert triggers.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_SetAssertionHandler
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC SDL_AssertionHandler SDLCALL SDL_GetAssertionHandler(void **puserdata);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a list of all assertion failures.
|
||||||
|
*
|
||||||
|
* This function gets all assertions triggered since the last call to
|
||||||
|
* SDL_ResetAssertionReport(), or the start of the program.
|
||||||
|
*
|
||||||
|
* The proper way to examine this data looks something like this:
|
||||||
|
*
|
||||||
|
* ```c
|
||||||
|
* const SDL_AssertData *item = SDL_GetAssertionReport();
|
||||||
|
* while (item) {
|
||||||
|
* printf("'%s', %s (%s:%d), triggered %u times, always ignore: %s.\\n",
|
||||||
|
* item->condition, item->function, item->filename,
|
||||||
|
* item->linenum, item->trigger_count,
|
||||||
|
* item->always_ignore ? "yes" : "no");
|
||||||
|
* item = item->next;
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* \returns a list of all failed assertions or NULL if the list is empty. This
|
||||||
|
* memory should not be modified or freed by the application. This
|
||||||
|
* pointer remains valid until the next call to SDL_Quit() or
|
||||||
|
* SDL_ResetAssertionReport().
|
||||||
|
*
|
||||||
|
* \threadsafety This function is not thread safe. Other threads calling
|
||||||
|
* SDL_ResetAssertionReport() simultaneously, may render the
|
||||||
|
* returned pointer invalid.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_ResetAssertionReport
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC const SDL_AssertData * SDLCALL SDL_GetAssertionReport(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the list of all assertion failures.
|
||||||
|
*
|
||||||
|
* This function will clear the list of all assertions triggered up to that
|
||||||
|
* point. Immediately following this call, SDL_GetAssertionReport will return
|
||||||
|
* no items. In addition, any previously-triggered assertions will be reset to
|
||||||
|
* a trigger_count of zero, and their always_ignore state will be false.
|
||||||
|
*
|
||||||
|
* \threadsafety This function is not thread safe. Other threads triggering an
|
||||||
|
* assertion, or simultaneously calling this function may cause
|
||||||
|
* memory leaks or crashes.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetAssertionReport
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC void SDLCALL SDL_ResetAssertionReport(void);
|
||||||
|
|
||||||
|
/* Ends C function definitions when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#include <SDL3/SDL_close_code.h>
|
||||||
|
|
||||||
|
#endif /* SDL_assert_h_ */
|
||||||
@@ -0,0 +1,546 @@
|
|||||||
|
/*
|
||||||
|
Simple DirectMedia Layer
|
||||||
|
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* WIKI CATEGORY: AsyncIO */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* # CategoryAsyncIO
|
||||||
|
*
|
||||||
|
* SDL offers a way to perform I/O asynchronously. This allows an app to read
|
||||||
|
* or write files without waiting for data to actually transfer; the functions
|
||||||
|
* that request I/O never block while the request is fulfilled.
|
||||||
|
*
|
||||||
|
* Instead, the data moves in the background and the app can check for results
|
||||||
|
* at their leisure.
|
||||||
|
*
|
||||||
|
* This is more complicated than just reading and writing files in a
|
||||||
|
* synchronous way, but it can allow for more efficiency, and never having
|
||||||
|
* framerate drops as the hard drive catches up, etc.
|
||||||
|
*
|
||||||
|
* The general usage pattern for async I/O is:
|
||||||
|
*
|
||||||
|
* - Create one or more SDL_AsyncIOQueue objects.
|
||||||
|
* - Open files with SDL_AsyncIOFromFile.
|
||||||
|
* - Start I/O tasks to the files with SDL_ReadAsyncIO or SDL_WriteAsyncIO,
|
||||||
|
* putting those tasks into one of the queues.
|
||||||
|
* - Later on, use SDL_GetAsyncIOResult on a queue to see if any task is
|
||||||
|
* finished without blocking. Tasks might finish in any order with success
|
||||||
|
* or failure.
|
||||||
|
* - When all your tasks are done, close the file with SDL_CloseAsyncIO. This
|
||||||
|
* also generates a task, since it might flush data to disk!
|
||||||
|
*
|
||||||
|
* This all works, without blocking, in a single thread, but one can also wait
|
||||||
|
* on a queue in a background thread, sleeping until new results have arrived:
|
||||||
|
*
|
||||||
|
* - Call SDL_WaitAsyncIOResult from one or more threads to efficiently block
|
||||||
|
* until new tasks complete.
|
||||||
|
* - When shutting down, call SDL_SignalAsyncIOQueue to unblock any sleeping
|
||||||
|
* threads despite there being no new tasks completed.
|
||||||
|
*
|
||||||
|
* And, of course, to match the synchronous SDL_LoadFile, we offer
|
||||||
|
* SDL_LoadFileAsync as a convenience function. This will handle allocating a
|
||||||
|
* buffer, slurping in the file data, and null-terminating it; you still check
|
||||||
|
* for results later.
|
||||||
|
*
|
||||||
|
* Behind the scenes, SDL will use newer, efficient APIs on platforms that
|
||||||
|
* support them: Linux's io_uring and Windows 11's IoRing, for example. If
|
||||||
|
* those technologies aren't available, SDL will offload the work to a thread
|
||||||
|
* pool that will manage otherwise-synchronous loads without blocking the app.
|
||||||
|
*
|
||||||
|
* ## Best Practices
|
||||||
|
*
|
||||||
|
* Simple non-blocking I/O--for an app that just wants to pick up data
|
||||||
|
* whenever it's ready without losing framerate waiting on disks to spin--can
|
||||||
|
* use whatever pattern works well for the program. In this case, simply call
|
||||||
|
* SDL_ReadAsyncIO, or maybe SDL_LoadFileAsync, as needed. Once a frame, call
|
||||||
|
* SDL_GetAsyncIOResult to check for any completed tasks and deal with the
|
||||||
|
* data as it arrives.
|
||||||
|
*
|
||||||
|
* If two separate pieces of the same program need their own I/O, it is legal
|
||||||
|
* for each to create their own queue. This will prevent either piece from
|
||||||
|
* accidentally consuming the other's completed tasks. Each queue does require
|
||||||
|
* some amount of resources, but it is not an overwhelming cost. Do not make a
|
||||||
|
* queue for each task, however. It is better to put many tasks into a single
|
||||||
|
* queue. They will be reported in order of completion, not in the order they
|
||||||
|
* were submitted, so it doesn't generally matter what order tasks are
|
||||||
|
* started.
|
||||||
|
*
|
||||||
|
* One async I/O queue can be shared by multiple threads, or one thread can
|
||||||
|
* have more than one queue, but the most efficient way--if ruthless
|
||||||
|
* efficiency is the goal--is to have one queue per thread, with multiple
|
||||||
|
* threads working in parallel, and attempt to keep each queue loaded with
|
||||||
|
* tasks that are both started by and consumed by the same thread. On modern
|
||||||
|
* platforms that can use newer interfaces, this can keep data flowing as
|
||||||
|
* efficiently as possible all the way from storage hardware to the app, with
|
||||||
|
* no contention between threads for access to the same queue.
|
||||||
|
*
|
||||||
|
* Written data is not guaranteed to make it to physical media by the time a
|
||||||
|
* closing task is completed, unless SDL_CloseAsyncIO is called with its
|
||||||
|
* `flush` parameter set to true, which is to say that a successful result
|
||||||
|
* here can still result in lost data during an unfortunately-timed power
|
||||||
|
* outage if not flushed. However, flushing will take longer and may be
|
||||||
|
* unnecessary, depending on the app's needs.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SDL_asyncio_h_
|
||||||
|
#define SDL_asyncio_h_
|
||||||
|
|
||||||
|
#include <SDL3/SDL_stdinc.h>
|
||||||
|
|
||||||
|
#include <SDL3/SDL_begin_code.h>
|
||||||
|
/* Set up for C function definitions, even when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The asynchronous I/O operation structure.
|
||||||
|
*
|
||||||
|
* This operates as an opaque handle. One can then request read or write
|
||||||
|
* operations on it.
|
||||||
|
*
|
||||||
|
* \since This struct is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_AsyncIOFromFile
|
||||||
|
*/
|
||||||
|
typedef struct SDL_AsyncIO SDL_AsyncIO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Types of asynchronous I/O tasks.
|
||||||
|
*
|
||||||
|
* \since This enum is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
typedef enum SDL_AsyncIOTaskType
|
||||||
|
{
|
||||||
|
SDL_ASYNCIO_TASK_READ, /**< A read operation. */
|
||||||
|
SDL_ASYNCIO_TASK_WRITE, /**< A write operation. */
|
||||||
|
SDL_ASYNCIO_TASK_CLOSE /**< A close operation. */
|
||||||
|
} SDL_AsyncIOTaskType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Possible outcomes of an asynchronous I/O task.
|
||||||
|
*
|
||||||
|
* \since This enum is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
typedef enum SDL_AsyncIOResult
|
||||||
|
{
|
||||||
|
SDL_ASYNCIO_COMPLETE, /**< request was completed without error */
|
||||||
|
SDL_ASYNCIO_FAILURE, /**< request failed for some reason; check SDL_GetError()! */
|
||||||
|
SDL_ASYNCIO_CANCELED /**< request was canceled before completing. */
|
||||||
|
} SDL_AsyncIOResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about a completed asynchronous I/O request.
|
||||||
|
*
|
||||||
|
* \since This struct is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
typedef struct SDL_AsyncIOOutcome
|
||||||
|
{
|
||||||
|
SDL_AsyncIO *asyncio; /**< what generated this task. This pointer will be invalid if it was closed! */
|
||||||
|
SDL_AsyncIOTaskType type; /**< What sort of task was this? Read, write, etc? */
|
||||||
|
SDL_AsyncIOResult result; /**< the result of the work (success, failure, cancellation). */
|
||||||
|
void *buffer; /**< buffer where data was read/written. */
|
||||||
|
Uint64 offset; /**< offset in the SDL_AsyncIO where data was read/written. */
|
||||||
|
Uint64 bytes_requested; /**< number of bytes the task was to read/write. */
|
||||||
|
Uint64 bytes_transferred; /**< actual number of bytes that were read/written. */
|
||||||
|
void *userdata; /**< pointer provided by the app when starting the task */
|
||||||
|
} SDL_AsyncIOOutcome;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A queue of completed asynchronous I/O tasks.
|
||||||
|
*
|
||||||
|
* When starting an asynchronous operation, you specify a queue for the new
|
||||||
|
* task. A queue can be asked later if any tasks in it have completed,
|
||||||
|
* allowing an app to manage multiple pending tasks in one place, in whatever
|
||||||
|
* order they complete.
|
||||||
|
*
|
||||||
|
* \since This struct is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_CreateAsyncIOQueue
|
||||||
|
* \sa SDL_ReadAsyncIO
|
||||||
|
* \sa SDL_WriteAsyncIO
|
||||||
|
* \sa SDL_GetAsyncIOResult
|
||||||
|
* \sa SDL_WaitAsyncIOResult
|
||||||
|
*/
|
||||||
|
typedef struct SDL_AsyncIOQueue SDL_AsyncIOQueue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this function to create a new SDL_AsyncIO object for reading from
|
||||||
|
* and/or writing to a named file.
|
||||||
|
*
|
||||||
|
* The `mode` string understands the following values:
|
||||||
|
*
|
||||||
|
* - "r": Open a file for reading only. It must exist.
|
||||||
|
* - "w": Open a file for writing only. It will create missing files or
|
||||||
|
* truncate existing ones.
|
||||||
|
* - "r+": Open a file for update both reading and writing. The file must
|
||||||
|
* exist.
|
||||||
|
* - "w+": Create an empty file for both reading and writing. If a file with
|
||||||
|
* the same name already exists its content is erased and the file is
|
||||||
|
* treated as a new empty file.
|
||||||
|
*
|
||||||
|
* There is no "b" mode, as there is only "binary" style I/O, and no "a" mode
|
||||||
|
* for appending, since you specify the position when starting a task.
|
||||||
|
*
|
||||||
|
* This function supports Unicode filenames, but they must be encoded in UTF-8
|
||||||
|
* format, regardless of the underlying operating system.
|
||||||
|
*
|
||||||
|
* This call is _not_ asynchronous; it will open the file before returning,
|
||||||
|
* under the assumption that doing so is generally a fast operation. Future
|
||||||
|
* reads and writes to the opened file will be async, however.
|
||||||
|
*
|
||||||
|
* \param file a UTF-8 string representing the filename to open.
|
||||||
|
* \param mode an ASCII string representing the mode to be used for opening
|
||||||
|
* the file.
|
||||||
|
* \returns a pointer to the SDL_AsyncIO structure that is created or NULL on
|
||||||
|
* failure; call SDL_GetError() for more information.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_CloseAsyncIO
|
||||||
|
* \sa SDL_ReadAsyncIO
|
||||||
|
* \sa SDL_WriteAsyncIO
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC SDL_AsyncIO * SDLCALL SDL_AsyncIOFromFile(const char *file, const char *mode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this function to get the size of the data stream in an SDL_AsyncIO.
|
||||||
|
*
|
||||||
|
* This call is _not_ asynchronous; it assumes that obtaining this info is a
|
||||||
|
* non-blocking operation in most reasonable cases.
|
||||||
|
*
|
||||||
|
* \param asyncio the SDL_AsyncIO to get the size of the data stream from.
|
||||||
|
* \returns the size of the data stream in the SDL_IOStream on success or a
|
||||||
|
* negative error code on failure; call SDL_GetError() for more
|
||||||
|
* information.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC Sint64 SDLCALL SDL_GetAsyncIOSize(SDL_AsyncIO *asyncio);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start an async read.
|
||||||
|
*
|
||||||
|
* This function reads up to `size` bytes from `offset` position in the data
|
||||||
|
* source to the area pointed at by `ptr`. This function may read less bytes
|
||||||
|
* than requested.
|
||||||
|
*
|
||||||
|
* This function returns as quickly as possible; it does not wait for the read
|
||||||
|
* to complete. On a successful return, this work will continue in the
|
||||||
|
* background. If the work begins, even failure is asynchronous: a failing
|
||||||
|
* return value from this function only means the work couldn't start at all.
|
||||||
|
*
|
||||||
|
* `ptr` must remain available until the work is done, and may be accessed by
|
||||||
|
* the system at any time until then. Do not allocate it on the stack, as this
|
||||||
|
* might take longer than the life of the calling function to complete!
|
||||||
|
*
|
||||||
|
* An SDL_AsyncIOQueue must be specified. The newly-created task will be added
|
||||||
|
* to it when it completes its work.
|
||||||
|
*
|
||||||
|
* \param asyncio a pointer to an SDL_AsyncIO structure.
|
||||||
|
* \param ptr a pointer to a buffer to read data into.
|
||||||
|
* \param offset the position to start reading in the data source.
|
||||||
|
* \param size the number of bytes to read from the data source.
|
||||||
|
* \param queue a queue to add the new SDL_AsyncIO to.
|
||||||
|
* \param userdata an app-defined pointer that will be provided with the task
|
||||||
|
* results.
|
||||||
|
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||||
|
* information.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_WriteAsyncIO
|
||||||
|
* \sa SDL_CreateAsyncIOQueue
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_ReadAsyncIO(SDL_AsyncIO *asyncio, void *ptr, Uint64 offset, Uint64 size, SDL_AsyncIOQueue *queue, void *userdata);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start an async write.
|
||||||
|
*
|
||||||
|
* This function writes `size` bytes from `offset` position in the data source
|
||||||
|
* to the area pointed at by `ptr`.
|
||||||
|
*
|
||||||
|
* This function returns as quickly as possible; it does not wait for the
|
||||||
|
* write to complete. On a successful return, this work will continue in the
|
||||||
|
* background. If the work begins, even failure is asynchronous: a failing
|
||||||
|
* return value from this function only means the work couldn't start at all.
|
||||||
|
*
|
||||||
|
* `ptr` must remain available until the work is done, and may be accessed by
|
||||||
|
* the system at any time until then. Do not allocate it on the stack, as this
|
||||||
|
* might take longer than the life of the calling function to complete!
|
||||||
|
*
|
||||||
|
* An SDL_AsyncIOQueue must be specified. The newly-created task will be added
|
||||||
|
* to it when it completes its work.
|
||||||
|
*
|
||||||
|
* \param asyncio a pointer to an SDL_AsyncIO structure.
|
||||||
|
* \param ptr a pointer to a buffer to write data from.
|
||||||
|
* \param offset the position to start writing to the data source.
|
||||||
|
* \param size the number of bytes to write to the data source.
|
||||||
|
* \param queue a queue to add the new SDL_AsyncIO to.
|
||||||
|
* \param userdata an app-defined pointer that will be provided with the task
|
||||||
|
* results.
|
||||||
|
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||||
|
* information.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_ReadAsyncIO
|
||||||
|
* \sa SDL_CreateAsyncIOQueue
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_WriteAsyncIO(SDL_AsyncIO *asyncio, void *ptr, Uint64 offset, Uint64 size, SDL_AsyncIOQueue *queue, void *userdata);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close and free any allocated resources for an async I/O object.
|
||||||
|
*
|
||||||
|
* Closing a file is _also_ an asynchronous task! If a write failure were to
|
||||||
|
* happen during the closing process, for example, the task results will
|
||||||
|
* report it as usual.
|
||||||
|
*
|
||||||
|
* Closing a file that has been written to does not guarantee the data has
|
||||||
|
* made it to physical media; it may remain in the operating system's file
|
||||||
|
* cache, for later writing to disk. This means that a successfully-closed
|
||||||
|
* file can be lost if the system crashes or loses power in this small window.
|
||||||
|
* To prevent this, call this function with the `flush` parameter set to true.
|
||||||
|
* This will make the operation take longer, and perhaps increase system load
|
||||||
|
* in general, but a successful result guarantees that the data has made it to
|
||||||
|
* physical storage. Don't use this for temporary files, caches, and
|
||||||
|
* unimportant data, and definitely use it for crucial irreplaceable files,
|
||||||
|
* like game saves.
|
||||||
|
*
|
||||||
|
* This function guarantees that the close will happen after any other pending
|
||||||
|
* tasks to `asyncio`, so it's safe to open a file, start several operations,
|
||||||
|
* close the file immediately, then check for all results later. This function
|
||||||
|
* will not block until the tasks have completed.
|
||||||
|
*
|
||||||
|
* Once this function returns true, `asyncio` is no longer valid, regardless
|
||||||
|
* of any future outcomes. Any completed tasks might still contain this
|
||||||
|
* pointer in their SDL_AsyncIOOutcome data, in case the app was using this
|
||||||
|
* value to track information, but it should not be used again.
|
||||||
|
*
|
||||||
|
* If this function returns false, the close wasn't started at all, and it's
|
||||||
|
* safe to attempt to close again later.
|
||||||
|
*
|
||||||
|
* An SDL_AsyncIOQueue must be specified. The newly-created task will be added
|
||||||
|
* to it when it completes its work.
|
||||||
|
*
|
||||||
|
* \param asyncio a pointer to an SDL_AsyncIO structure to close.
|
||||||
|
* \param flush true if data should sync to disk before the task completes.
|
||||||
|
* \param queue a queue to add the new SDL_AsyncIO to.
|
||||||
|
* \param userdata an app-defined pointer that will be provided with the task
|
||||||
|
* results.
|
||||||
|
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||||
|
* information.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread, but two
|
||||||
|
* threads should not attempt to close the same object.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_CloseAsyncIO(SDL_AsyncIO *asyncio, bool flush, SDL_AsyncIOQueue *queue, void *userdata);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a task queue for tracking multiple I/O operations.
|
||||||
|
*
|
||||||
|
* Async I/O operations are assigned to a queue when started. The queue can be
|
||||||
|
* checked for completed tasks thereafter.
|
||||||
|
*
|
||||||
|
* \returns a new task queue object or NULL if there was an error; call
|
||||||
|
* SDL_GetError() for more information.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_DestroyAsyncIOQueue
|
||||||
|
* \sa SDL_GetAsyncIOResult
|
||||||
|
* \sa SDL_WaitAsyncIOResult
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC SDL_AsyncIOQueue * SDLCALL SDL_CreateAsyncIOQueue(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy a previously-created async I/O task queue.
|
||||||
|
*
|
||||||
|
* If there are still tasks pending for this queue, this call will block until
|
||||||
|
* those tasks are finished. All those tasks will be deallocated. Their
|
||||||
|
* results will be lost to the app.
|
||||||
|
*
|
||||||
|
* Any pending reads from SDL_LoadFileAsync() that are still in this queue
|
||||||
|
* will have their buffers deallocated by this function, to prevent a memory
|
||||||
|
* leak.
|
||||||
|
*
|
||||||
|
* Once this function is called, the queue is no longer valid and should not
|
||||||
|
* be used, including by other threads that might access it while destruction
|
||||||
|
* is blocking on pending tasks.
|
||||||
|
*
|
||||||
|
* Do not destroy a queue that still has threads waiting on it through
|
||||||
|
* SDL_WaitAsyncIOResult(). You can call SDL_SignalAsyncIOQueue() first to
|
||||||
|
* unblock those threads, and take measures (such as SDL_WaitThread()) to make
|
||||||
|
* sure they have finished their wait and won't wait on the queue again.
|
||||||
|
*
|
||||||
|
* \param queue the task queue to destroy.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread, so long as
|
||||||
|
* no other thread is waiting on the queue with
|
||||||
|
* SDL_WaitAsyncIOResult.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC void SDLCALL SDL_DestroyAsyncIOQueue(SDL_AsyncIOQueue *queue);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query an async I/O task queue for completed tasks.
|
||||||
|
*
|
||||||
|
* If a task assigned to this queue has finished, this will return true and
|
||||||
|
* fill in `outcome` with the details of the task. If no task in the queue has
|
||||||
|
* finished, this function will return false. This function does not block.
|
||||||
|
*
|
||||||
|
* If a task has completed, this function will free its resources and the task
|
||||||
|
* pointer will no longer be valid. The task will be removed from the queue.
|
||||||
|
*
|
||||||
|
* It is safe for multiple threads to call this function on the same queue at
|
||||||
|
* once; a completed task will only go to one of the threads.
|
||||||
|
*
|
||||||
|
* \param queue the async I/O task queue to query.
|
||||||
|
* \param outcome details of a finished task will be written here. May not be
|
||||||
|
* NULL.
|
||||||
|
* \returns true if a task has completed, false otherwise.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_WaitAsyncIOResult
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_GetAsyncIOResult(SDL_AsyncIOQueue *queue, SDL_AsyncIOOutcome *outcome);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Block until an async I/O task queue has a completed task.
|
||||||
|
*
|
||||||
|
* This function puts the calling thread to sleep until there a task assigned
|
||||||
|
* to the queue that has finished.
|
||||||
|
*
|
||||||
|
* If a task assigned to the queue has finished, this will return true and
|
||||||
|
* fill in `outcome` with the details of the task. If no task in the queue has
|
||||||
|
* finished, this function will return false.
|
||||||
|
*
|
||||||
|
* If a task has completed, this function will free its resources and the task
|
||||||
|
* pointer will no longer be valid. The task will be removed from the queue.
|
||||||
|
*
|
||||||
|
* It is safe for multiple threads to call this function on the same queue at
|
||||||
|
* once; a completed task will only go to one of the threads.
|
||||||
|
*
|
||||||
|
* Note that by the nature of various platforms, more than one waiting thread
|
||||||
|
* may wake to handle a single task, but only one will obtain it, so
|
||||||
|
* `timeoutMS` is a _maximum_ wait time, and this function may return false
|
||||||
|
* sooner.
|
||||||
|
*
|
||||||
|
* This function may return false if there was a system error, the OS
|
||||||
|
* inadvertently awoke multiple threads, or if SDL_SignalAsyncIOQueue() was
|
||||||
|
* called to wake up all waiting threads without a finished task.
|
||||||
|
*
|
||||||
|
* A timeout can be used to specify a maximum wait time, but rather than
|
||||||
|
* polling, it is possible to have a timeout of -1 to wait forever, and use
|
||||||
|
* SDL_SignalAsyncIOQueue() to wake up the waiting threads later.
|
||||||
|
*
|
||||||
|
* \param queue the async I/O task queue to wait on.
|
||||||
|
* \param outcome details of a finished task will be written here. May not be
|
||||||
|
* NULL.
|
||||||
|
* \param timeoutMS the maximum time to wait, in milliseconds, or -1 to wait
|
||||||
|
* indefinitely.
|
||||||
|
* \returns true if task has completed, false otherwise.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_SignalAsyncIOQueue
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_WaitAsyncIOResult(SDL_AsyncIOQueue *queue, SDL_AsyncIOOutcome *outcome, Sint32 timeoutMS);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wake up any threads that are blocking in SDL_WaitAsyncIOResult().
|
||||||
|
*
|
||||||
|
* This will unblock any threads that are sleeping in a call to
|
||||||
|
* SDL_WaitAsyncIOResult for the specified queue, and cause them to return
|
||||||
|
* from that function.
|
||||||
|
*
|
||||||
|
* This can be useful when destroying a queue to make sure nothing is touching
|
||||||
|
* it indefinitely. In this case, once this call completes, the caller should
|
||||||
|
* take measures to make sure any previously-blocked threads have returned
|
||||||
|
* from their wait and will not touch the queue again (perhaps by setting a
|
||||||
|
* flag to tell the threads to terminate and then using SDL_WaitThread() to
|
||||||
|
* make sure they've done so).
|
||||||
|
*
|
||||||
|
* \param queue the async I/O task queue to signal.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_WaitAsyncIOResult
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC void SDLCALL SDL_SignalAsyncIOQueue(SDL_AsyncIOQueue *queue);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load all the data from a file path, asynchronously.
|
||||||
|
*
|
||||||
|
* This function returns as quickly as possible; it does not wait for the read
|
||||||
|
* to complete. On a successful return, this work will continue in the
|
||||||
|
* background. If the work begins, even failure is asynchronous: a failing
|
||||||
|
* return value from this function only means the work couldn't start at all.
|
||||||
|
*
|
||||||
|
* The data is allocated with a zero byte at the end (null terminated) for
|
||||||
|
* convenience. This extra byte is not included in SDL_AsyncIOOutcome's
|
||||||
|
* bytes_transferred value.
|
||||||
|
*
|
||||||
|
* This function will allocate the buffer to contain the file. It must be
|
||||||
|
* deallocated by calling SDL_free() on SDL_AsyncIOOutcome's buffer field
|
||||||
|
* after completion.
|
||||||
|
*
|
||||||
|
* An SDL_AsyncIOQueue must be specified. The newly-created task will be added
|
||||||
|
* to it when it completes its work.
|
||||||
|
*
|
||||||
|
* \param file the path to read all available data from.
|
||||||
|
* \param queue a queue to add the new SDL_AsyncIO to.
|
||||||
|
* \param userdata an app-defined pointer that will be provided with the task
|
||||||
|
* results.
|
||||||
|
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||||
|
* information.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_LoadFile_IO
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_LoadFileAsync(const char *file, SDL_AsyncIOQueue *queue, void *userdata);
|
||||||
|
|
||||||
|
/* Ends C function definitions when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#include <SDL3/SDL_close_code.h>
|
||||||
|
|
||||||
|
#endif /* SDL_asyncio_h_ */
|
||||||
@@ -0,0 +1,664 @@
|
|||||||
|
/*
|
||||||
|
Simple DirectMedia Layer
|
||||||
|
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* # CategoryAtomic
|
||||||
|
*
|
||||||
|
* Atomic operations.
|
||||||
|
*
|
||||||
|
* IMPORTANT: If you are not an expert in concurrent lockless programming, you
|
||||||
|
* should not be using any functions in this file. You should be protecting
|
||||||
|
* your data structures with full mutexes instead.
|
||||||
|
*
|
||||||
|
* ***Seriously, here be dragons!***
|
||||||
|
*
|
||||||
|
* You can find out a little more about lockless programming and the subtle
|
||||||
|
* issues that can arise here:
|
||||||
|
* https://learn.microsoft.com/en-us/windows/win32/dxtecharts/lockless-programming
|
||||||
|
*
|
||||||
|
* There's also lots of good information here:
|
||||||
|
*
|
||||||
|
* - https://www.1024cores.net/home/lock-free-algorithms
|
||||||
|
* - https://preshing.com/
|
||||||
|
*
|
||||||
|
* These operations may or may not actually be implemented using processor
|
||||||
|
* specific atomic operations. When possible they are implemented as true
|
||||||
|
* processor specific atomic operations. When that is not possible the are
|
||||||
|
* implemented using locks that *do* use the available atomic operations.
|
||||||
|
*
|
||||||
|
* All of the atomic operations that modify memory are full memory barriers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SDL_atomic_h_
|
||||||
|
#define SDL_atomic_h_
|
||||||
|
|
||||||
|
#include <SDL3/SDL_stdinc.h>
|
||||||
|
#include <SDL3/SDL_platform_defines.h>
|
||||||
|
|
||||||
|
#include <SDL3/SDL_begin_code.h>
|
||||||
|
|
||||||
|
/* Set up for C function definitions, even when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An atomic spinlock.
|
||||||
|
*
|
||||||
|
* The atomic locks are efficient spinlocks using CPU instructions, but are
|
||||||
|
* vulnerable to starvation and can spin forever if a thread holding a lock
|
||||||
|
* has been terminated. For this reason you should minimize the code executed
|
||||||
|
* inside an atomic lock and never do expensive things like API or system
|
||||||
|
* calls while holding them.
|
||||||
|
*
|
||||||
|
* They are also vulnerable to starvation if the thread holding the lock is
|
||||||
|
* lower priority than other threads and doesn't get scheduled. In general you
|
||||||
|
* should use mutexes instead, since they have better performance and
|
||||||
|
* contention behavior.
|
||||||
|
*
|
||||||
|
* The atomic locks are not safe to lock recursively.
|
||||||
|
*
|
||||||
|
* Porting Note: The spin lock functions and type are required and can not be
|
||||||
|
* emulated because they are used in the atomic emulation code.
|
||||||
|
*/
|
||||||
|
typedef int SDL_SpinLock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to lock a spin lock by setting it to a non-zero value.
|
||||||
|
*
|
||||||
|
* ***Please note that spinlocks are dangerous if you don't know what you're
|
||||||
|
* doing. Please be careful using any sort of spinlock!***
|
||||||
|
*
|
||||||
|
* \param lock a pointer to a lock variable.
|
||||||
|
* \returns true if the lock succeeded, false if the lock is already held.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_LockSpinlock
|
||||||
|
* \sa SDL_UnlockSpinlock
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_TryLockSpinlock(SDL_SpinLock *lock);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lock a spin lock by setting it to a non-zero value.
|
||||||
|
*
|
||||||
|
* ***Please note that spinlocks are dangerous if you don't know what you're
|
||||||
|
* doing. Please be careful using any sort of spinlock!***
|
||||||
|
*
|
||||||
|
* \param lock a pointer to a lock variable.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_TryLockSpinlock
|
||||||
|
* \sa SDL_UnlockSpinlock
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC void SDLCALL SDL_LockSpinlock(SDL_SpinLock *lock);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unlock a spin lock by setting it to 0.
|
||||||
|
*
|
||||||
|
* Always returns immediately.
|
||||||
|
*
|
||||||
|
* ***Please note that spinlocks are dangerous if you don't know what you're
|
||||||
|
* doing. Please be careful using any sort of spinlock!***
|
||||||
|
*
|
||||||
|
* \param lock a pointer to a lock variable.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_LockSpinlock
|
||||||
|
* \sa SDL_TryLockSpinlock
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC void SDLCALL SDL_UnlockSpinlock(SDL_SpinLock *lock);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef SDL_WIKI_DOCUMENTATION_SECTION
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark a compiler barrier.
|
||||||
|
*
|
||||||
|
* A compiler barrier prevents the compiler from reordering reads and writes
|
||||||
|
* to globally visible variables across the call.
|
||||||
|
*
|
||||||
|
* This macro only prevents the compiler from reordering reads and writes, it
|
||||||
|
* does not prevent the CPU from reordering reads and writes. However, all of
|
||||||
|
* the atomic operations that modify memory are full memory barriers.
|
||||||
|
*
|
||||||
|
* \threadsafety Obviously this macro is safe to use from any thread at any
|
||||||
|
* time, but if you find yourself needing this, you are probably
|
||||||
|
* dealing with some very sensitive code; be careful!
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_CompilerBarrier() DoCompilerSpecificReadWriteBarrier()
|
||||||
|
|
||||||
|
#elif defined(_MSC_VER) && (_MSC_VER > 1200) && !defined(__clang__)
|
||||||
|
void _ReadWriteBarrier(void);
|
||||||
|
#pragma intrinsic(_ReadWriteBarrier)
|
||||||
|
#define SDL_CompilerBarrier() _ReadWriteBarrier()
|
||||||
|
#elif (defined(__GNUC__) && !defined(SDL_PLATFORM_EMSCRIPTEN)) || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x5120))
|
||||||
|
/* This is correct for all CPUs when using GCC or Solaris Studio 12.1+. */
|
||||||
|
#define SDL_CompilerBarrier() __asm__ __volatile__ ("" : : : "memory")
|
||||||
|
#elif defined(__WATCOMC__)
|
||||||
|
extern __inline void SDL_CompilerBarrier(void);
|
||||||
|
#pragma aux SDL_CompilerBarrier = "" parm [] modify exact [];
|
||||||
|
#else
|
||||||
|
#define SDL_CompilerBarrier() \
|
||||||
|
{ SDL_SpinLock _tmp = 0; SDL_LockSpinlock(&_tmp); SDL_UnlockSpinlock(&_tmp); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert a memory release barrier (function version).
|
||||||
|
*
|
||||||
|
* Please refer to SDL_MemoryBarrierRelease for details. This is a function
|
||||||
|
* version, which might be useful if you need to use this functionality from a
|
||||||
|
* scripting language, etc. Also, some of the macro versions call this
|
||||||
|
* function behind the scenes, where more heavy lifting can happen inside of
|
||||||
|
* SDL. Generally, though, an app written in C/C++/etc should use the macro
|
||||||
|
* version, as it will be more efficient.
|
||||||
|
*
|
||||||
|
* \threadsafety Obviously this function is safe to use from any thread at any
|
||||||
|
* time, but if you find yourself needing this, you are probably
|
||||||
|
* dealing with some very sensitive code; be careful!
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_MemoryBarrierRelease
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC void SDLCALL SDL_MemoryBarrierReleaseFunction(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert a memory acquire barrier (function version).
|
||||||
|
*
|
||||||
|
* Please refer to SDL_MemoryBarrierRelease for details. This is a function
|
||||||
|
* version, which might be useful if you need to use this functionality from a
|
||||||
|
* scripting language, etc. Also, some of the macro versions call this
|
||||||
|
* function behind the scenes, where more heavy lifting can happen inside of
|
||||||
|
* SDL. Generally, though, an app written in C/C++/etc should use the macro
|
||||||
|
* version, as it will be more efficient.
|
||||||
|
*
|
||||||
|
* \threadsafety Obviously this function is safe to use from any thread at any
|
||||||
|
* time, but if you find yourself needing this, you are probably
|
||||||
|
* dealing with some very sensitive code; be careful!
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_MemoryBarrierAcquire
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC void SDLCALL SDL_MemoryBarrierAcquireFunction(void);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef SDL_WIKI_DOCUMENTATION_SECTION
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert a memory release barrier (macro version).
|
||||||
|
*
|
||||||
|
* Memory barriers are designed to prevent reads and writes from being
|
||||||
|
* reordered by the compiler and being seen out of order on multi-core CPUs.
|
||||||
|
*
|
||||||
|
* A typical pattern would be for thread A to write some data and a flag, and
|
||||||
|
* for thread B to read the flag and get the data. In this case you would
|
||||||
|
* insert a release barrier between writing the data and the flag,
|
||||||
|
* guaranteeing that the data write completes no later than the flag is
|
||||||
|
* written, and you would insert an acquire barrier between reading the flag
|
||||||
|
* and reading the data, to ensure that all the reads associated with the flag
|
||||||
|
* have completed.
|
||||||
|
*
|
||||||
|
* In this pattern you should always see a release barrier paired with an
|
||||||
|
* acquire barrier and you should gate the data reads/writes with a single
|
||||||
|
* flag variable.
|
||||||
|
*
|
||||||
|
* For more information on these semantics, take a look at the blog post:
|
||||||
|
* http://preshing.com/20120913/acquire-and-release-semantics
|
||||||
|
*
|
||||||
|
* This is the macro version of this functionality; if possible, SDL will use
|
||||||
|
* compiler intrinsics or inline assembly, but some platforms might need to
|
||||||
|
* call the function version of this, SDL_MemoryBarrierReleaseFunction to do
|
||||||
|
* the heavy lifting. Apps that can use the macro should favor it over the
|
||||||
|
* function.
|
||||||
|
*
|
||||||
|
* \threadsafety Obviously this macro is safe to use from any thread at any
|
||||||
|
* time, but if you find yourself needing this, you are probably
|
||||||
|
* dealing with some very sensitive code; be careful!
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_MemoryBarrierAcquire
|
||||||
|
* \sa SDL_MemoryBarrierReleaseFunction
|
||||||
|
*/
|
||||||
|
#define SDL_MemoryBarrierRelease() SDL_MemoryBarrierReleaseFunction()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert a memory acquire barrier (macro version).
|
||||||
|
*
|
||||||
|
* Please see SDL_MemoryBarrierRelease for the details on what memory barriers
|
||||||
|
* are and when to use them.
|
||||||
|
*
|
||||||
|
* This is the macro version of this functionality; if possible, SDL will use
|
||||||
|
* compiler intrinsics or inline assembly, but some platforms might need to
|
||||||
|
* call the function version of this, SDL_MemoryBarrierAcquireFunction, to do
|
||||||
|
* the heavy lifting. Apps that can use the macro should favor it over the
|
||||||
|
* function.
|
||||||
|
*
|
||||||
|
* \threadsafety Obviously this macro is safe to use from any thread at any
|
||||||
|
* time, but if you find yourself needing this, you are probably
|
||||||
|
* dealing with some very sensitive code; be careful!
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_MemoryBarrierRelease
|
||||||
|
* \sa SDL_MemoryBarrierAcquireFunction
|
||||||
|
*/
|
||||||
|
#define SDL_MemoryBarrierAcquire() SDL_MemoryBarrierAcquireFunction()
|
||||||
|
|
||||||
|
#elif defined(__GNUC__) && (defined(__powerpc__) || defined(__ppc__))
|
||||||
|
#define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("lwsync" : : : "memory")
|
||||||
|
#define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("lwsync" : : : "memory")
|
||||||
|
#elif defined(__GNUC__) && defined(__aarch64__)
|
||||||
|
#define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("dmb ish" : : : "memory")
|
||||||
|
#define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("dmb ish" : : : "memory")
|
||||||
|
#elif defined(__GNUC__) && defined(__arm__)
|
||||||
|
#if 0 /* defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_ANDROID) */
|
||||||
|
/* Information from:
|
||||||
|
https://chromium.googlesource.com/chromium/chromium/+/trunk/base/atomicops_internals_arm_gcc.h#19
|
||||||
|
|
||||||
|
The Linux kernel provides a helper function which provides the right code for a memory barrier,
|
||||||
|
hard-coded at address 0xffff0fa0
|
||||||
|
*/
|
||||||
|
typedef void (*SDL_KernelMemoryBarrierFunc)();
|
||||||
|
#define SDL_MemoryBarrierRelease() ((SDL_KernelMemoryBarrierFunc)0xffff0fa0)()
|
||||||
|
#define SDL_MemoryBarrierAcquire() ((SDL_KernelMemoryBarrierFunc)0xffff0fa0)()
|
||||||
|
#else
|
||||||
|
#if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) || defined(__ARM_ARCH_8A__)
|
||||||
|
#define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("dmb ish" : : : "memory")
|
||||||
|
#define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("dmb ish" : : : "memory")
|
||||||
|
#elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__)
|
||||||
|
#ifdef __thumb__
|
||||||
|
/* The mcr instruction isn't available in thumb mode, use real functions */
|
||||||
|
#define SDL_MEMORY_BARRIER_USES_FUNCTION
|
||||||
|
#define SDL_MemoryBarrierRelease() SDL_MemoryBarrierReleaseFunction()
|
||||||
|
#define SDL_MemoryBarrierAcquire() SDL_MemoryBarrierAcquireFunction()
|
||||||
|
#else
|
||||||
|
#define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" : : "r"(0) : "memory")
|
||||||
|
#define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" : : "r"(0) : "memory")
|
||||||
|
#endif /* __thumb__ */
|
||||||
|
#else
|
||||||
|
#define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("" : : : "memory")
|
||||||
|
#define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("" : : : "memory")
|
||||||
|
#endif /* SDL_PLATFORM_LINUX || SDL_PLATFORM_ANDROID */
|
||||||
|
#endif /* __GNUC__ && __arm__ */
|
||||||
|
#else
|
||||||
|
#if (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x5120))
|
||||||
|
/* This is correct for all CPUs on Solaris when using Solaris Studio 12.1+. */
|
||||||
|
#include <mbarrier.h>
|
||||||
|
#define SDL_MemoryBarrierRelease() __machine_rel_barrier()
|
||||||
|
#define SDL_MemoryBarrierAcquire() __machine_acq_barrier()
|
||||||
|
#else
|
||||||
|
/* This is correct for the x86 and x64 CPUs, and we'll expand this over time. */
|
||||||
|
#define SDL_MemoryBarrierRelease() SDL_CompilerBarrier()
|
||||||
|
#define SDL_MemoryBarrierAcquire() SDL_CompilerBarrier()
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* "REP NOP" is PAUSE, coded for tools that don't know it by that name. */
|
||||||
|
#ifdef SDL_WIKI_DOCUMENTATION_SECTION
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A macro to insert a CPU-specific "pause" instruction into the program.
|
||||||
|
*
|
||||||
|
* This can be useful in busy-wait loops, as it serves as a hint to the CPU as
|
||||||
|
* to the program's intent; some CPUs can use this to do more efficient
|
||||||
|
* processing. On some platforms, this doesn't do anything, so using this
|
||||||
|
* macro might just be a harmless no-op.
|
||||||
|
*
|
||||||
|
* Note that if you are busy-waiting, there are often more-efficient
|
||||||
|
* approaches with other synchronization primitives: mutexes, semaphores,
|
||||||
|
* condition variables, etc.
|
||||||
|
*
|
||||||
|
* \threadsafety This macro is safe to use from any thread.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_CPUPauseInstruction() DoACPUPauseInACompilerAndArchitectureSpecificWay
|
||||||
|
|
||||||
|
#elif (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__))
|
||||||
|
#define SDL_CPUPauseInstruction() __asm__ __volatile__("pause\n") /* Some assemblers can't do REP NOP, so go with PAUSE. */
|
||||||
|
#elif (defined(__arm__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7) || defined(__aarch64__)
|
||||||
|
#define SDL_CPUPauseInstruction() __asm__ __volatile__("yield" ::: "memory")
|
||||||
|
#elif (defined(__powerpc__) || defined(__powerpc64__))
|
||||||
|
#define SDL_CPUPauseInstruction() __asm__ __volatile__("or 27,27,27");
|
||||||
|
#elif (defined(__riscv) && __riscv_xlen == 64)
|
||||||
|
#define SDL_CPUPauseInstruction() __asm__ __volatile__(".insn i 0x0F, 0, x0, x0, 0x010");
|
||||||
|
#elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
|
||||||
|
#define SDL_CPUPauseInstruction() _mm_pause() /* this is actually "rep nop" and not a SIMD instruction. No inline asm in MSVC x86-64! */
|
||||||
|
#elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64))
|
||||||
|
#define SDL_CPUPauseInstruction() __yield()
|
||||||
|
#elif defined(__WATCOMC__) && defined(__386__)
|
||||||
|
extern __inline void SDL_CPUPauseInstruction(void);
|
||||||
|
#pragma aux SDL_CPUPauseInstruction = ".686p" ".xmm2" "pause"
|
||||||
|
#else
|
||||||
|
#define SDL_CPUPauseInstruction()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A type representing an atomic integer value.
|
||||||
|
*
|
||||||
|
* This can be used to manage a value that is synchronized across multiple
|
||||||
|
* CPUs without a race condition; when an app sets a value with
|
||||||
|
* SDL_SetAtomicInt all other threads, regardless of the CPU it is running on,
|
||||||
|
* will see that value when retrieved with SDL_GetAtomicInt, regardless of CPU
|
||||||
|
* caches, etc.
|
||||||
|
*
|
||||||
|
* This is also useful for atomic compare-and-swap operations: a thread can
|
||||||
|
* change the value as long as its current value matches expectations. When
|
||||||
|
* done in a loop, one can guarantee data consistency across threads without a
|
||||||
|
* lock (but the usual warnings apply: if you don't know what you're doing, or
|
||||||
|
* you don't do it carefully, you can confidently cause any number of
|
||||||
|
* disasters with this, so in most cases, you _should_ use a mutex instead of
|
||||||
|
* this!).
|
||||||
|
*
|
||||||
|
* This is a struct so people don't accidentally use numeric operations on it
|
||||||
|
* directly. You have to use SDL atomic functions.
|
||||||
|
*
|
||||||
|
* \since This struct is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_CompareAndSwapAtomicInt
|
||||||
|
* \sa SDL_GetAtomicInt
|
||||||
|
* \sa SDL_SetAtomicInt
|
||||||
|
* \sa SDL_AddAtomicInt
|
||||||
|
*/
|
||||||
|
typedef struct SDL_AtomicInt { int value; } SDL_AtomicInt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set an atomic variable to a new value if it is currently an old value.
|
||||||
|
*
|
||||||
|
* ***Note: If you don't know what this function is for, you shouldn't use
|
||||||
|
* it!***
|
||||||
|
*
|
||||||
|
* \param a a pointer to an SDL_AtomicInt variable to be modified.
|
||||||
|
* \param oldval the old value.
|
||||||
|
* \param newval the new value.
|
||||||
|
* \returns true if the atomic variable was set, false otherwise.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetAtomicInt
|
||||||
|
* \sa SDL_SetAtomicInt
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_CompareAndSwapAtomicInt(SDL_AtomicInt *a, int oldval, int newval);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set an atomic variable to a value.
|
||||||
|
*
|
||||||
|
* This function also acts as a full memory barrier.
|
||||||
|
*
|
||||||
|
* ***Note: If you don't know what this function is for, you shouldn't use
|
||||||
|
* it!***
|
||||||
|
*
|
||||||
|
* \param a a pointer to an SDL_AtomicInt variable to be modified.
|
||||||
|
* \param v the desired value.
|
||||||
|
* \returns the previous value of the atomic variable.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetAtomicInt
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC int SDLCALL SDL_SetAtomicInt(SDL_AtomicInt *a, int v);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value of an atomic variable.
|
||||||
|
*
|
||||||
|
* ***Note: If you don't know what this function is for, you shouldn't use
|
||||||
|
* it!***
|
||||||
|
*
|
||||||
|
* \param a a pointer to an SDL_AtomicInt variable.
|
||||||
|
* \returns the current value of an atomic variable.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_SetAtomicInt
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC int SDLCALL SDL_GetAtomicInt(SDL_AtomicInt *a);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add to an atomic variable.
|
||||||
|
*
|
||||||
|
* This function also acts as a full memory barrier.
|
||||||
|
*
|
||||||
|
* ***Note: If you don't know what this function is for, you shouldn't use
|
||||||
|
* it!***
|
||||||
|
*
|
||||||
|
* \param a a pointer to an SDL_AtomicInt variable to be modified.
|
||||||
|
* \param v the desired value to add.
|
||||||
|
* \returns the previous value of the atomic variable.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_AtomicDecRef
|
||||||
|
* \sa SDL_AtomicIncRef
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC int SDLCALL SDL_AddAtomicInt(SDL_AtomicInt *a, int v);
|
||||||
|
|
||||||
|
#ifndef SDL_AtomicIncRef
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increment an atomic variable used as a reference count.
|
||||||
|
*
|
||||||
|
* ***Note: If you don't know what this macro is for, you shouldn't use it!***
|
||||||
|
*
|
||||||
|
* \param a a pointer to an SDL_AtomicInt to increment.
|
||||||
|
* \returns the previous value of the atomic variable.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this macro from any thread.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_AtomicDecRef
|
||||||
|
*/
|
||||||
|
#define SDL_AtomicIncRef(a) SDL_AddAtomicInt(a, 1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SDL_AtomicDecRef
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrement an atomic variable used as a reference count.
|
||||||
|
*
|
||||||
|
* ***Note: If you don't know what this macro is for, you shouldn't use it!***
|
||||||
|
*
|
||||||
|
* \param a a pointer to an SDL_AtomicInt to decrement.
|
||||||
|
* \returns true if the variable reached zero after decrementing, false
|
||||||
|
* otherwise.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this macro from any thread.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_AtomicIncRef
|
||||||
|
*/
|
||||||
|
#define SDL_AtomicDecRef(a) (SDL_AddAtomicInt(a, -1) == 1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A type representing an atomic unsigned 32-bit value.
|
||||||
|
*
|
||||||
|
* This can be used to manage a value that is synchronized across multiple
|
||||||
|
* CPUs without a race condition; when an app sets a value with
|
||||||
|
* SDL_SetAtomicU32 all other threads, regardless of the CPU it is running on,
|
||||||
|
* will see that value when retrieved with SDL_GetAtomicU32, regardless of CPU
|
||||||
|
* caches, etc.
|
||||||
|
*
|
||||||
|
* This is also useful for atomic compare-and-swap operations: a thread can
|
||||||
|
* change the value as long as its current value matches expectations. When
|
||||||
|
* done in a loop, one can guarantee data consistency across threads without a
|
||||||
|
* lock (but the usual warnings apply: if you don't know what you're doing, or
|
||||||
|
* you don't do it carefully, you can confidently cause any number of
|
||||||
|
* disasters with this, so in most cases, you _should_ use a mutex instead of
|
||||||
|
* this!).
|
||||||
|
*
|
||||||
|
* This is a struct so people don't accidentally use numeric operations on it
|
||||||
|
* directly. You have to use SDL atomic functions.
|
||||||
|
*
|
||||||
|
* \since This struct is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_CompareAndSwapAtomicU32
|
||||||
|
* \sa SDL_GetAtomicU32
|
||||||
|
* \sa SDL_SetAtomicU32
|
||||||
|
*/
|
||||||
|
typedef struct SDL_AtomicU32 { Uint32 value; } SDL_AtomicU32;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set an atomic variable to a new value if it is currently an old value.
|
||||||
|
*
|
||||||
|
* ***Note: If you don't know what this function is for, you shouldn't use
|
||||||
|
* it!***
|
||||||
|
*
|
||||||
|
* \param a a pointer to an SDL_AtomicU32 variable to be modified.
|
||||||
|
* \param oldval the old value.
|
||||||
|
* \param newval the new value.
|
||||||
|
* \returns true if the atomic variable was set, false otherwise.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetAtomicU32
|
||||||
|
* \sa SDL_SetAtomicU32
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_CompareAndSwapAtomicU32(SDL_AtomicU32 *a, Uint32 oldval, Uint32 newval);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set an atomic variable to a value.
|
||||||
|
*
|
||||||
|
* This function also acts as a full memory barrier.
|
||||||
|
*
|
||||||
|
* ***Note: If you don't know what this function is for, you shouldn't use
|
||||||
|
* it!***
|
||||||
|
*
|
||||||
|
* \param a a pointer to an SDL_AtomicU32 variable to be modified.
|
||||||
|
* \param v the desired value.
|
||||||
|
* \returns the previous value of the atomic variable.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetAtomicU32
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC Uint32 SDLCALL SDL_SetAtomicU32(SDL_AtomicU32 *a, Uint32 v);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value of an atomic variable.
|
||||||
|
*
|
||||||
|
* ***Note: If you don't know what this function is for, you shouldn't use
|
||||||
|
* it!***
|
||||||
|
*
|
||||||
|
* \param a a pointer to an SDL_AtomicU32 variable.
|
||||||
|
* \returns the current value of an atomic variable.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_SetAtomicU32
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC Uint32 SDLCALL SDL_GetAtomicU32(SDL_AtomicU32 *a);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a pointer to a new value if it is currently an old value.
|
||||||
|
*
|
||||||
|
* ***Note: If you don't know what this function is for, you shouldn't use
|
||||||
|
* it!***
|
||||||
|
*
|
||||||
|
* \param a a pointer to a pointer.
|
||||||
|
* \param oldval the old pointer value.
|
||||||
|
* \param newval the new pointer value.
|
||||||
|
* \returns true if the pointer was set, false otherwise.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_CompareAndSwapAtomicInt
|
||||||
|
* \sa SDL_GetAtomicPointer
|
||||||
|
* \sa SDL_SetAtomicPointer
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_CompareAndSwapAtomicPointer(void **a, void *oldval, void *newval);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a pointer to a value atomically.
|
||||||
|
*
|
||||||
|
* ***Note: If you don't know what this function is for, you shouldn't use
|
||||||
|
* it!***
|
||||||
|
*
|
||||||
|
* \param a a pointer to a pointer.
|
||||||
|
* \param v the desired pointer value.
|
||||||
|
* \returns the previous value of the pointer.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_CompareAndSwapAtomicPointer
|
||||||
|
* \sa SDL_GetAtomicPointer
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC void * SDLCALL SDL_SetAtomicPointer(void **a, void *v);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value of a pointer atomically.
|
||||||
|
*
|
||||||
|
* ***Note: If you don't know what this function is for, you shouldn't use
|
||||||
|
* it!***
|
||||||
|
*
|
||||||
|
* \param a a pointer to a pointer.
|
||||||
|
* \returns the current value of a pointer.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_CompareAndSwapAtomicPointer
|
||||||
|
* \sa SDL_SetAtomicPointer
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC void * SDLCALL SDL_GetAtomicPointer(void **a);
|
||||||
|
|
||||||
|
/* Ends C function definitions when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <SDL3/SDL_close_code.h>
|
||||||
|
|
||||||
|
#endif /* SDL_atomic_h_ */
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,486 @@
|
|||||||
|
/*
|
||||||
|
Simple DirectMedia Layer
|
||||||
|
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* WIKI CATEGORY: BeginCode */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* # CategoryBeginCode
|
||||||
|
*
|
||||||
|
* `SDL_begin_code.h` sets things up for C dynamic library function
|
||||||
|
* definitions, static inlined functions, and structures aligned at 4-byte
|
||||||
|
* alignment. If you don't like ugly C preprocessor code, don't look at this
|
||||||
|
* file. :)
|
||||||
|
*
|
||||||
|
* SDL's headers use this; applications generally should not include this
|
||||||
|
* header directly.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* This shouldn't be nested -- included it around code only. */
|
||||||
|
#ifdef SDL_begin_code_h
|
||||||
|
#error Nested inclusion of SDL_begin_code.h
|
||||||
|
#endif
|
||||||
|
#define SDL_begin_code_h
|
||||||
|
|
||||||
|
#ifdef SDL_WIKI_DOCUMENTATION_SECTION
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A macro to tag a symbol as deprecated.
|
||||||
|
*
|
||||||
|
* A function is marked deprecated by adding this macro to its declaration:
|
||||||
|
*
|
||||||
|
* ```c
|
||||||
|
* extern SDL_DEPRECATED int ThisFunctionWasABadIdea(void);
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Compilers with deprecation support can give a warning when a deprecated
|
||||||
|
* function is used. This symbol may be used in SDL's headers, but apps are
|
||||||
|
* welcome to use it for their own interfaces as well.
|
||||||
|
*
|
||||||
|
* SDL, on occasion, might deprecate a function for various reasons. However,
|
||||||
|
* SDL never removes symbols before major versions, so deprecated interfaces
|
||||||
|
* in SDL3 will remain available until SDL4, where it would be expected an app
|
||||||
|
* would have to take steps to migrate anyhow.
|
||||||
|
*
|
||||||
|
* On compilers without a deprecation mechanism, this is defined to nothing,
|
||||||
|
* and using a deprecated function will not generate a warning.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_DEPRECATED __attribute__((deprecated))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A macro to tag a symbol as a public API.
|
||||||
|
*
|
||||||
|
* SDL uses this macro for all its public functions. On some targets, it is
|
||||||
|
* used to signal to the compiler that this function needs to be exported from
|
||||||
|
* a shared library, but it might have other side effects.
|
||||||
|
*
|
||||||
|
* This symbol is used in SDL's headers, but apps and other libraries are
|
||||||
|
* welcome to use it for their own interfaces as well.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_DECLSPEC __attribute__ ((visibility("default")))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A macro to set a function's calling conventions.
|
||||||
|
*
|
||||||
|
* SDL uses this macro for all its public functions, and any callbacks it
|
||||||
|
* defines. This macro guarantees that calling conventions match between SDL
|
||||||
|
* and the app, even if the two were built with different compilers or
|
||||||
|
* optimization settings.
|
||||||
|
*
|
||||||
|
* When writing a callback function, it is very important for it to be
|
||||||
|
* correctly tagged with SDLCALL, as mismatched calling conventions can cause
|
||||||
|
* strange behaviors and can be difficult to diagnose. Plus, on many
|
||||||
|
* platforms, SDLCALL is defined to nothing, so compilers won't be able to
|
||||||
|
* warn that the tag is missing.
|
||||||
|
*
|
||||||
|
* This symbol is used in SDL's headers, but apps and other libraries are
|
||||||
|
* welcome to use it for their own interfaces as well.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDLCALL __cdecl
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A macro to request a function be inlined.
|
||||||
|
*
|
||||||
|
* This is a hint to the compiler to inline a function. The compiler is free
|
||||||
|
* to ignore this request. On compilers without inline support, this is
|
||||||
|
* defined to nothing.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_INLINE __inline
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A macro to demand a function be inlined.
|
||||||
|
*
|
||||||
|
* This is a command to the compiler to inline a function. SDL uses this macro
|
||||||
|
* in its public headers for a handful of simple functions. On compilers
|
||||||
|
* without forceinline support, this is defined to `static SDL_INLINE`, which
|
||||||
|
* is often good enough.
|
||||||
|
*
|
||||||
|
* This symbol is used in SDL's headers, but apps and other libraries are
|
||||||
|
* welcome to use it for their own interfaces as well.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_FORCE_INLINE __forceinline
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A macro to tag a function as never-returning.
|
||||||
|
*
|
||||||
|
* This is a hint to the compiler that a function does not return. An example
|
||||||
|
* of a function like this is the C runtime's exit() function.
|
||||||
|
*
|
||||||
|
* This hint can lead to code optimizations, and help analyzers understand
|
||||||
|
* code flow better. On compilers without noreturn support, this is defined to
|
||||||
|
* nothing.
|
||||||
|
*
|
||||||
|
* This symbol is used in SDL's headers, but apps and other libraries are
|
||||||
|
* welcome to use it for their own interfaces as well.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_NORETURN __attribute__((noreturn))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A macro to tag a function as never-returning (for analysis purposes).
|
||||||
|
*
|
||||||
|
* This is almost identical to SDL_NORETURN, except functions marked with this
|
||||||
|
* _can_ actually return. The difference is that this isn't used for code
|
||||||
|
* generation, but rather static analyzers use this information to assume
|
||||||
|
* truths about program state and available code paths. Specifically, this tag
|
||||||
|
* is useful for writing an assertion mechanism. Indeed, SDL_assert uses this
|
||||||
|
* tag behind the scenes. Generally, apps that don't understand the specific
|
||||||
|
* use-case for this tag should avoid using it directly.
|
||||||
|
*
|
||||||
|
* On compilers without analyzer_noreturn support, this is defined to nothing.
|
||||||
|
*
|
||||||
|
* This symbol is used in SDL's headers, but apps and other libraries are
|
||||||
|
* welcome to use it for their own interfaces as well.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_ANALYZER_NORETURN __attribute__((analyzer_noreturn))
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A macro to signal that a case statement without a `break` is intentional.
|
||||||
|
*
|
||||||
|
* C compilers have gotten more aggressive about warning when a switch's
|
||||||
|
* `case` block does not end with a `break` or other flow control statement,
|
||||||
|
* flowing into the next case's code, as this is a common accident that leads
|
||||||
|
* to strange bugs. But sometimes falling through to the next case is the
|
||||||
|
* correct and desired behavior. This symbol lets an app communicate this
|
||||||
|
* intention to the compiler, so it doesn't generate a warning.
|
||||||
|
*
|
||||||
|
* It is used like this:
|
||||||
|
*
|
||||||
|
* ```c
|
||||||
|
* switch (x) {
|
||||||
|
* case 1:
|
||||||
|
* DoSomethingOnlyForOne();
|
||||||
|
* SDL_FALLTHROUGH; // tell the compiler this was intentional.
|
||||||
|
* case 2:
|
||||||
|
* DoSomethingForOneAndTwo();
|
||||||
|
* break;
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_FALLTHROUGH [[fallthrough]]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A macro to tag a function's return value as critical.
|
||||||
|
*
|
||||||
|
* This is a hint to the compiler that a function's return value should not be
|
||||||
|
* ignored.
|
||||||
|
*
|
||||||
|
* If an NODISCARD function's return value is thrown away (the function is
|
||||||
|
* called as if it returns `void`), the compiler will issue a warning.
|
||||||
|
*
|
||||||
|
* While it's generally good practice to check return values for errors, often
|
||||||
|
* times legitimate programs do not for good reasons. Be careful about what
|
||||||
|
* functions are tagged as NODISCARD. It operates best when used on a function
|
||||||
|
* that's failure is surprising and catastrophic; a good example would be a
|
||||||
|
* program that checks the return values of all its file write function calls
|
||||||
|
* but not the call to close the file, which it assumes incorrectly never
|
||||||
|
* fails.
|
||||||
|
*
|
||||||
|
* Function callers that want to throw away a NODISCARD return value can call
|
||||||
|
* the function with a `(void)` cast, which informs the compiler the act is
|
||||||
|
* intentional.
|
||||||
|
*
|
||||||
|
* On compilers without nodiscard support, this is defined to nothing.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_NODISCARD [[nodiscard]]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A macro to tag a function as an allocator.
|
||||||
|
*
|
||||||
|
* This is a hint to the compiler that a function is an allocator, like
|
||||||
|
* malloc(), with certain rules. A description of how GCC treats this hint is
|
||||||
|
* here:
|
||||||
|
*
|
||||||
|
* https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-malloc-function-attribute
|
||||||
|
*
|
||||||
|
* On compilers without allocator tag support, this is defined to nothing.
|
||||||
|
*
|
||||||
|
* Most apps don't need to, and should not, use this directly.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_MALLOC __declspec(allocator) __desclspec(restrict)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A macro to tag a function as returning a certain allocation.
|
||||||
|
*
|
||||||
|
* This is a hint to the compiler that a function allocates and returns a
|
||||||
|
* specific amount of memory based on one of its arguments. For example, the C
|
||||||
|
* runtime's malloc() function could use this macro with an argument of 1
|
||||||
|
* (first argument to malloc is the size of the allocation).
|
||||||
|
*
|
||||||
|
* On compilers without alloc_size support, this is defined to nothing.
|
||||||
|
*
|
||||||
|
* Most apps don't need to, and should not, use this directly.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_ALLOC_SIZE(p) __attribute__((alloc_size(p)))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A macro to tag a pointer variable, to help with pointer aliasing.
|
||||||
|
*
|
||||||
|
* A good explanation of the restrict keyword is here:
|
||||||
|
*
|
||||||
|
* https://en.wikipedia.org/wiki/Restrict
|
||||||
|
*
|
||||||
|
* On compilers without restrict support, this is defined to nothing.
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_RESTRICT __restrict__
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the compiler supports a given builtin functionality.
|
||||||
|
*
|
||||||
|
* This allows preprocessor checks for things that otherwise might fail to
|
||||||
|
* compile.
|
||||||
|
*
|
||||||
|
* Supported by virtually all clang versions and more-recent GCCs. Use this
|
||||||
|
* instead of checking the clang version if possible.
|
||||||
|
*
|
||||||
|
* On compilers without has_builtin support, this is defined to 0 (always
|
||||||
|
* false).
|
||||||
|
*
|
||||||
|
* \since This macro is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
#define SDL_HAS_BUILTIN(x) __has_builtin(x)
|
||||||
|
|
||||||
|
/* end of wiki documentation section. */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SDL_HAS_BUILTIN
|
||||||
|
#ifdef __has_builtin
|
||||||
|
#define SDL_HAS_BUILTIN(x) __has_builtin(x)
|
||||||
|
#else
|
||||||
|
#define SDL_HAS_BUILTIN(x) 0
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SDL_DEPRECATED
|
||||||
|
# if defined(__GNUC__) && (__GNUC__ >= 4) /* technically, this arrived in gcc 3.1, but oh well. */
|
||||||
|
# define SDL_DEPRECATED __attribute__((deprecated))
|
||||||
|
# elif defined(_MSC_VER)
|
||||||
|
# define SDL_DEPRECATED __declspec(deprecated)
|
||||||
|
# else
|
||||||
|
# define SDL_DEPRECATED
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SDL_UNUSED
|
||||||
|
# ifdef __GNUC__
|
||||||
|
# define SDL_UNUSED __attribute__((unused))
|
||||||
|
# else
|
||||||
|
# define SDL_UNUSED
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Some compilers use a special export keyword */
|
||||||
|
#ifndef SDL_DECLSPEC
|
||||||
|
# if defined(SDL_PLATFORM_WINDOWS)
|
||||||
|
# ifdef DLL_EXPORT
|
||||||
|
# define SDL_DECLSPEC __declspec(dllexport)
|
||||||
|
# else
|
||||||
|
# define SDL_DECLSPEC
|
||||||
|
# endif
|
||||||
|
# else
|
||||||
|
# if defined(__GNUC__) && __GNUC__ >= 4
|
||||||
|
# define SDL_DECLSPEC __attribute__ ((visibility("default")))
|
||||||
|
# else
|
||||||
|
# define SDL_DECLSPEC
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* By default SDL uses the C calling convention */
|
||||||
|
#ifndef SDLCALL
|
||||||
|
#if defined(SDL_PLATFORM_WINDOWS) && !defined(__GNUC__)
|
||||||
|
#define SDLCALL __cdecl
|
||||||
|
#else
|
||||||
|
#define SDLCALL
|
||||||
|
#endif
|
||||||
|
#endif /* SDLCALL */
|
||||||
|
|
||||||
|
/* Force structure packing at 4 byte alignment.
|
||||||
|
This is necessary if the header is included in code which has structure
|
||||||
|
packing set to an alternate value, say for loading structures from disk.
|
||||||
|
The packing is reset to the previous value in SDL_close_code.h
|
||||||
|
*/
|
||||||
|
#if defined(_MSC_VER) || defined(__MWERKS__) || defined(__BORLANDC__)
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(disable: 4103)
|
||||||
|
#endif
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic ignored "-Wpragma-pack"
|
||||||
|
#endif
|
||||||
|
#ifdef __BORLANDC__
|
||||||
|
#pragma nopackwarning
|
||||||
|
#endif
|
||||||
|
#ifdef _WIN64
|
||||||
|
/* Use 8-byte alignment on 64-bit architectures, so pointers are aligned */
|
||||||
|
#pragma pack(push,8)
|
||||||
|
#else
|
||||||
|
#pragma pack(push,4)
|
||||||
|
#endif
|
||||||
|
#endif /* Compiler needs structure packing set */
|
||||||
|
|
||||||
|
#ifndef SDL_INLINE
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define SDL_INLINE __inline__
|
||||||
|
#elif defined(_MSC_VER) || defined(__BORLANDC__) || \
|
||||||
|
defined(__DMC__) || defined(__SC__) || \
|
||||||
|
defined(__WATCOMC__) || defined(__LCC__) || \
|
||||||
|
defined(__DECC) || defined(__CC_ARM)
|
||||||
|
#define SDL_INLINE __inline
|
||||||
|
#ifndef __inline__
|
||||||
|
#define __inline__ __inline
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define SDL_INLINE inline
|
||||||
|
#ifndef __inline__
|
||||||
|
#define __inline__ inline
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif /* SDL_INLINE not defined */
|
||||||
|
|
||||||
|
#ifndef SDL_FORCE_INLINE
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define SDL_FORCE_INLINE __forceinline
|
||||||
|
#elif ( (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__) )
|
||||||
|
#define SDL_FORCE_INLINE __attribute__((always_inline)) static __inline__
|
||||||
|
#else
|
||||||
|
#define SDL_FORCE_INLINE static SDL_INLINE
|
||||||
|
#endif
|
||||||
|
#endif /* SDL_FORCE_INLINE not defined */
|
||||||
|
|
||||||
|
#ifndef SDL_NORETURN
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define SDL_NORETURN __attribute__((noreturn))
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#define SDL_NORETURN __declspec(noreturn)
|
||||||
|
#else
|
||||||
|
#define SDL_NORETURN
|
||||||
|
#endif
|
||||||
|
#endif /* SDL_NORETURN not defined */
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
#if __has_feature(attribute_analyzer_noreturn)
|
||||||
|
#define SDL_ANALYZER_NORETURN __attribute__((analyzer_noreturn))
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SDL_ANALYZER_NORETURN
|
||||||
|
#define SDL_ANALYZER_NORETURN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Apparently this is needed by several Windows compilers */
|
||||||
|
#ifndef __MACH__
|
||||||
|
#ifndef NULL
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#define NULL 0
|
||||||
|
#else
|
||||||
|
#define NULL ((void *)0)
|
||||||
|
#endif
|
||||||
|
#endif /* NULL */
|
||||||
|
#endif /* ! macOS - breaks precompiled headers */
|
||||||
|
|
||||||
|
#ifndef SDL_FALLTHROUGH
|
||||||
|
#if (defined(__cplusplus) && __cplusplus >= 201703L) || \
|
||||||
|
(defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000L)
|
||||||
|
#define SDL_FALLTHROUGH [[fallthrough]]
|
||||||
|
#else
|
||||||
|
#if defined(__has_attribute) && !defined(__SUNPRO_C) && !defined(__SUNPRO_CC)
|
||||||
|
#define SDL_HAS_FALLTHROUGH __has_attribute(__fallthrough__)
|
||||||
|
#else
|
||||||
|
#define SDL_HAS_FALLTHROUGH 0
|
||||||
|
#endif /* __has_attribute */
|
||||||
|
#if SDL_HAS_FALLTHROUGH && \
|
||||||
|
((defined(__GNUC__) && __GNUC__ >= 7) || \
|
||||||
|
(defined(__clang_major__) && __clang_major__ >= 10))
|
||||||
|
#define SDL_FALLTHROUGH __attribute__((__fallthrough__))
|
||||||
|
#else
|
||||||
|
#define SDL_FALLTHROUGH do {} while (0) /* fallthrough */
|
||||||
|
#endif /* SDL_HAS_FALLTHROUGH */
|
||||||
|
#undef SDL_HAS_FALLTHROUGH
|
||||||
|
#endif /* C++17 or C2x */
|
||||||
|
#endif /* SDL_FALLTHROUGH not defined */
|
||||||
|
|
||||||
|
#ifndef SDL_NODISCARD
|
||||||
|
#if (defined(__cplusplus) && __cplusplus >= 201703L) || \
|
||||||
|
(defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L)
|
||||||
|
#define SDL_NODISCARD [[nodiscard]]
|
||||||
|
#elif ( (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__) )
|
||||||
|
#define SDL_NODISCARD __attribute__((warn_unused_result))
|
||||||
|
#elif defined(_MSC_VER) && (_MSC_VER >= 1700)
|
||||||
|
#define SDL_NODISCARD _Check_return_
|
||||||
|
#else
|
||||||
|
#define SDL_NODISCARD
|
||||||
|
#endif /* C++17 or C23 */
|
||||||
|
#endif /* SDL_NODISCARD not defined */
|
||||||
|
|
||||||
|
#ifndef SDL_MALLOC
|
||||||
|
#if defined(__GNUC__) && (__GNUC__ >= 3)
|
||||||
|
#define SDL_MALLOC __attribute__((malloc))
|
||||||
|
/** FIXME
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#define SDL_MALLOC __declspec(allocator) __desclspec(restrict)
|
||||||
|
**/
|
||||||
|
#else
|
||||||
|
#define SDL_MALLOC
|
||||||
|
#endif
|
||||||
|
#endif /* SDL_MALLOC not defined */
|
||||||
|
|
||||||
|
#ifndef SDL_ALLOC_SIZE
|
||||||
|
#if (defined(__clang__) && __clang_major__ >= 4) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)))
|
||||||
|
#define SDL_ALLOC_SIZE(p) __attribute__((alloc_size(p)))
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#define SDL_ALLOC_SIZE(p)
|
||||||
|
#else
|
||||||
|
#define SDL_ALLOC_SIZE(p)
|
||||||
|
#endif
|
||||||
|
#endif /* SDL_ALLOC_SIZE not defined */
|
||||||
|
|
||||||
|
#ifndef SDL_ALLOC_SIZE2
|
||||||
|
#if (defined(__clang__) && __clang_major__ >= 4) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)))
|
||||||
|
#define SDL_ALLOC_SIZE2(p1, p2) __attribute__((alloc_size(p1, p2)))
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#define SDL_ALLOC_SIZE2(p1, p2)
|
||||||
|
#else
|
||||||
|
#define SDL_ALLOC_SIZE2(p1, p2)
|
||||||
|
#endif
|
||||||
|
#endif /* SDL_ALLOC_SIZE2 not defined */
|
||||||
@@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
Simple DirectMedia Layer
|
||||||
|
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* # CategoryBits
|
||||||
|
*
|
||||||
|
* Functions for fiddling with bits and bitmasks.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SDL_bits_h_
|
||||||
|
#define SDL_bits_h_
|
||||||
|
|
||||||
|
#include <SDL3/SDL_stdinc.h>
|
||||||
|
|
||||||
|
#include <SDL3/SDL_begin_code.h>
|
||||||
|
/* Set up for C function definitions, even when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__WATCOMC__) && defined(__386__)
|
||||||
|
extern __inline int _SDL_bsr_watcom(Uint32);
|
||||||
|
#pragma aux _SDL_bsr_watcom = \
|
||||||
|
"bsr eax, eax" \
|
||||||
|
parm [eax] nomemory \
|
||||||
|
value [eax] \
|
||||||
|
modify exact [eax] nomemory;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the index of the most significant (set) bit in a 32-bit number.
|
||||||
|
*
|
||||||
|
* Result is undefined when called with 0. This operation can also be stated
|
||||||
|
* as "count leading zeroes" and "log base 2".
|
||||||
|
*
|
||||||
|
* Note that this is a forced-inline function in a header, and not a public
|
||||||
|
* API function available in the SDL library (which is to say, the code is
|
||||||
|
* embedded in the calling program and the linker and dynamic loader will not
|
||||||
|
* be able to find this function inside SDL itself).
|
||||||
|
*
|
||||||
|
* \param x the 32-bit value to examine.
|
||||||
|
* \returns the index of the most significant bit, or -1 if the value is 0.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
SDL_FORCE_INLINE int SDL_MostSignificantBitIndex32(Uint32 x)
|
||||||
|
{
|
||||||
|
#if defined(__GNUC__) && (__GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
|
||||||
|
/* Count Leading Zeroes builtin in GCC.
|
||||||
|
* http://gcc.gnu.org/onlinedocs/gcc-4.3.4/gcc/Other-Builtins.html
|
||||||
|
*/
|
||||||
|
if (x == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 31 - __builtin_clz(x);
|
||||||
|
#elif defined(__WATCOMC__) && defined(__386__)
|
||||||
|
if (x == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return _SDL_bsr_watcom(x);
|
||||||
|
#elif defined(_MSC_VER) && _MSC_VER >= 1400
|
||||||
|
unsigned long index;
|
||||||
|
if (_BitScanReverse(&index, x)) {
|
||||||
|
return (int)index;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
#else
|
||||||
|
/* Based off of Bit Twiddling Hacks by Sean Eron Anderson
|
||||||
|
* <seander@cs.stanford.edu>, released in the public domain.
|
||||||
|
* http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog
|
||||||
|
*/
|
||||||
|
const Uint32 b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000};
|
||||||
|
const int S[] = {1, 2, 4, 8, 16};
|
||||||
|
|
||||||
|
int msbIndex = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (x == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 4; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if (x & b[i])
|
||||||
|
{
|
||||||
|
x >>= S[i];
|
||||||
|
msbIndex |= S[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return msbIndex;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if a unsigned 32-bit value has exactly one bit set.
|
||||||
|
*
|
||||||
|
* If there are no bits set (`x` is zero), or more than one bit set, this
|
||||||
|
* returns false. If any one bit is exclusively set, this returns true.
|
||||||
|
*
|
||||||
|
* Note that this is a forced-inline function in a header, and not a public
|
||||||
|
* API function available in the SDL library (which is to say, the code is
|
||||||
|
* embedded in the calling program and the linker and dynamic loader will not
|
||||||
|
* be able to find this function inside SDL itself).
|
||||||
|
*
|
||||||
|
* \param x the 32-bit value to examine.
|
||||||
|
* \returns true if exactly one bit is set in `x`, false otherwise.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
SDL_FORCE_INLINE bool SDL_HasExactlyOneBitSet32(Uint32 x)
|
||||||
|
{
|
||||||
|
if (x && !(x & (x - 1))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ends C function definitions when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#include <SDL3/SDL_close_code.h>
|
||||||
|
|
||||||
|
#endif /* SDL_bits_h_ */
|
||||||
@@ -0,0 +1,202 @@
|
|||||||
|
/*
|
||||||
|
Simple DirectMedia Layer
|
||||||
|
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* # CategoryBlendmode
|
||||||
|
*
|
||||||
|
* Blend modes decide how two colors will mix together. There are both
|
||||||
|
* standard modes for basic needs and a means to create custom modes,
|
||||||
|
* dictating what sort of math to do on what color components.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SDL_blendmode_h_
|
||||||
|
#define SDL_blendmode_h_
|
||||||
|
|
||||||
|
#include <SDL3/SDL_stdinc.h>
|
||||||
|
|
||||||
|
#include <SDL3/SDL_begin_code.h>
|
||||||
|
/* Set up for C function definitions, even when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A set of blend modes used in drawing operations.
|
||||||
|
*
|
||||||
|
* These predefined blend modes are supported everywhere.
|
||||||
|
*
|
||||||
|
* Additional values may be obtained from SDL_ComposeCustomBlendMode.
|
||||||
|
*
|
||||||
|
* \since This datatype is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_ComposeCustomBlendMode
|
||||||
|
*/
|
||||||
|
typedef Uint32 SDL_BlendMode;
|
||||||
|
|
||||||
|
#define SDL_BLENDMODE_NONE 0x00000000u /**< no blending: dstRGBA = srcRGBA */
|
||||||
|
#define SDL_BLENDMODE_BLEND 0x00000001u /**< alpha blending: dstRGB = (srcRGB * srcA) + (dstRGB * (1-srcA)), dstA = srcA + (dstA * (1-srcA)) */
|
||||||
|
#define SDL_BLENDMODE_BLEND_PREMULTIPLIED 0x00000010u /**< pre-multiplied alpha blending: dstRGBA = srcRGBA + (dstRGBA * (1-srcA)) */
|
||||||
|
#define SDL_BLENDMODE_ADD 0x00000002u /**< additive blending: dstRGB = (srcRGB * srcA) + dstRGB, dstA = dstA */
|
||||||
|
#define SDL_BLENDMODE_ADD_PREMULTIPLIED 0x00000020u /**< pre-multiplied additive blending: dstRGB = srcRGB + dstRGB, dstA = dstA */
|
||||||
|
#define SDL_BLENDMODE_MOD 0x00000004u /**< color modulate: dstRGB = srcRGB * dstRGB, dstA = dstA */
|
||||||
|
#define SDL_BLENDMODE_MUL 0x00000008u /**< color multiply: dstRGB = (srcRGB * dstRGB) + (dstRGB * (1-srcA)), dstA = dstA */
|
||||||
|
#define SDL_BLENDMODE_INVALID 0x7FFFFFFFu
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The blend operation used when combining source and destination pixel
|
||||||
|
* components.
|
||||||
|
*
|
||||||
|
* \since This enum is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
typedef enum SDL_BlendOperation
|
||||||
|
{
|
||||||
|
SDL_BLENDOPERATION_ADD = 0x1, /**< dst + src: supported by all renderers */
|
||||||
|
SDL_BLENDOPERATION_SUBTRACT = 0x2, /**< src - dst : supported by D3D, OpenGL, OpenGLES, and Vulkan */
|
||||||
|
SDL_BLENDOPERATION_REV_SUBTRACT = 0x3, /**< dst - src : supported by D3D, OpenGL, OpenGLES, and Vulkan */
|
||||||
|
SDL_BLENDOPERATION_MINIMUM = 0x4, /**< min(dst, src) : supported by D3D, OpenGL, OpenGLES, and Vulkan */
|
||||||
|
SDL_BLENDOPERATION_MAXIMUM = 0x5 /**< max(dst, src) : supported by D3D, OpenGL, OpenGLES, and Vulkan */
|
||||||
|
} SDL_BlendOperation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The normalized factor used to multiply pixel components.
|
||||||
|
*
|
||||||
|
* The blend factors are multiplied with the pixels from a drawing operation
|
||||||
|
* (src) and the pixels from the render target (dst) before the blend
|
||||||
|
* operation. The comma-separated factors listed above are always applied in
|
||||||
|
* the component order red, green, blue, and alpha.
|
||||||
|
*
|
||||||
|
* \since This enum is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
typedef enum SDL_BlendFactor
|
||||||
|
{
|
||||||
|
SDL_BLENDFACTOR_ZERO = 0x1, /**< 0, 0, 0, 0 */
|
||||||
|
SDL_BLENDFACTOR_ONE = 0x2, /**< 1, 1, 1, 1 */
|
||||||
|
SDL_BLENDFACTOR_SRC_COLOR = 0x3, /**< srcR, srcG, srcB, srcA */
|
||||||
|
SDL_BLENDFACTOR_ONE_MINUS_SRC_COLOR = 0x4, /**< 1-srcR, 1-srcG, 1-srcB, 1-srcA */
|
||||||
|
SDL_BLENDFACTOR_SRC_ALPHA = 0x5, /**< srcA, srcA, srcA, srcA */
|
||||||
|
SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA = 0x6, /**< 1-srcA, 1-srcA, 1-srcA, 1-srcA */
|
||||||
|
SDL_BLENDFACTOR_DST_COLOR = 0x7, /**< dstR, dstG, dstB, dstA */
|
||||||
|
SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR = 0x8, /**< 1-dstR, 1-dstG, 1-dstB, 1-dstA */
|
||||||
|
SDL_BLENDFACTOR_DST_ALPHA = 0x9, /**< dstA, dstA, dstA, dstA */
|
||||||
|
SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA = 0xA /**< 1-dstA, 1-dstA, 1-dstA, 1-dstA */
|
||||||
|
} SDL_BlendFactor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compose a custom blend mode for renderers.
|
||||||
|
*
|
||||||
|
* The functions SDL_SetRenderDrawBlendMode and SDL_SetTextureBlendMode accept
|
||||||
|
* the SDL_BlendMode returned by this function if the renderer supports it.
|
||||||
|
*
|
||||||
|
* A blend mode controls how the pixels from a drawing operation (source) get
|
||||||
|
* combined with the pixels from the render target (destination). First, the
|
||||||
|
* components of the source and destination pixels get multiplied with their
|
||||||
|
* blend factors. Then, the blend operation takes the two products and
|
||||||
|
* calculates the result that will get stored in the render target.
|
||||||
|
*
|
||||||
|
* Expressed in pseudocode, it would look like this:
|
||||||
|
*
|
||||||
|
* ```c
|
||||||
|
* dstRGB = colorOperation(srcRGB * srcColorFactor, dstRGB * dstColorFactor);
|
||||||
|
* dstA = alphaOperation(srcA * srcAlphaFactor, dstA * dstAlphaFactor);
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Where the functions `colorOperation(src, dst)` and `alphaOperation(src,
|
||||||
|
* dst)` can return one of the following:
|
||||||
|
*
|
||||||
|
* - `src + dst`
|
||||||
|
* - `src - dst`
|
||||||
|
* - `dst - src`
|
||||||
|
* - `min(src, dst)`
|
||||||
|
* - `max(src, dst)`
|
||||||
|
*
|
||||||
|
* The red, green, and blue components are always multiplied with the first,
|
||||||
|
* second, and third components of the SDL_BlendFactor, respectively. The
|
||||||
|
* fourth component is not used.
|
||||||
|
*
|
||||||
|
* The alpha component is always multiplied with the fourth component of the
|
||||||
|
* SDL_BlendFactor. The other components are not used in the alpha
|
||||||
|
* calculation.
|
||||||
|
*
|
||||||
|
* Support for these blend modes varies for each renderer. To check if a
|
||||||
|
* specific SDL_BlendMode is supported, create a renderer and pass it to
|
||||||
|
* either SDL_SetRenderDrawBlendMode or SDL_SetTextureBlendMode. They will
|
||||||
|
* return with an error if the blend mode is not supported.
|
||||||
|
*
|
||||||
|
* This list describes the support of custom blend modes for each renderer.
|
||||||
|
* All renderers support the four blend modes listed in the SDL_BlendMode
|
||||||
|
* enumeration.
|
||||||
|
*
|
||||||
|
* - **direct3d**: Supports all operations with all factors. However, some
|
||||||
|
* factors produce unexpected results with `SDL_BLENDOPERATION_MINIMUM` and
|
||||||
|
* `SDL_BLENDOPERATION_MAXIMUM`.
|
||||||
|
* - **direct3d11**: Same as Direct3D 9.
|
||||||
|
* - **opengl**: Supports the `SDL_BLENDOPERATION_ADD` operation with all
|
||||||
|
* factors. OpenGL versions 1.1, 1.2, and 1.3 do not work correctly here.
|
||||||
|
* - **opengles2**: Supports the `SDL_BLENDOPERATION_ADD`,
|
||||||
|
* `SDL_BLENDOPERATION_SUBTRACT`, `SDL_BLENDOPERATION_REV_SUBTRACT`
|
||||||
|
* operations with all factors.
|
||||||
|
* - **psp**: No custom blend mode support.
|
||||||
|
* - **software**: No custom blend mode support.
|
||||||
|
*
|
||||||
|
* Some renderers do not provide an alpha component for the default render
|
||||||
|
* target. The `SDL_BLENDFACTOR_DST_ALPHA` and
|
||||||
|
* `SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA` factors do not have an effect in this
|
||||||
|
* case.
|
||||||
|
*
|
||||||
|
* \param srcColorFactor the SDL_BlendFactor applied to the red, green, and
|
||||||
|
* blue components of the source pixels.
|
||||||
|
* \param dstColorFactor the SDL_BlendFactor applied to the red, green, and
|
||||||
|
* blue components of the destination pixels.
|
||||||
|
* \param colorOperation the SDL_BlendOperation used to combine the red,
|
||||||
|
* green, and blue components of the source and
|
||||||
|
* destination pixels.
|
||||||
|
* \param srcAlphaFactor the SDL_BlendFactor applied to the alpha component of
|
||||||
|
* the source pixels.
|
||||||
|
* \param dstAlphaFactor the SDL_BlendFactor applied to the alpha component of
|
||||||
|
* the destination pixels.
|
||||||
|
* \param alphaOperation the SDL_BlendOperation used to combine the alpha
|
||||||
|
* component of the source and destination pixels.
|
||||||
|
* \returns an SDL_BlendMode that represents the chosen factors and
|
||||||
|
* operations.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_SetRenderDrawBlendMode
|
||||||
|
* \sa SDL_GetRenderDrawBlendMode
|
||||||
|
* \sa SDL_SetTextureBlendMode
|
||||||
|
* \sa SDL_GetTextureBlendMode
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC SDL_BlendMode SDLCALL SDL_ComposeCustomBlendMode(SDL_BlendFactor srcColorFactor,
|
||||||
|
SDL_BlendFactor dstColorFactor,
|
||||||
|
SDL_BlendOperation colorOperation,
|
||||||
|
SDL_BlendFactor srcAlphaFactor,
|
||||||
|
SDL_BlendFactor dstAlphaFactor,
|
||||||
|
SDL_BlendOperation alphaOperation);
|
||||||
|
|
||||||
|
/* Ends C function definitions when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#include <SDL3/SDL_close_code.h>
|
||||||
|
|
||||||
|
#endif /* SDL_blendmode_h_ */
|
||||||
@@ -0,0 +1,519 @@
|
|||||||
|
/*
|
||||||
|
Simple DirectMedia Layer
|
||||||
|
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* # CategoryCamera
|
||||||
|
*
|
||||||
|
* Video capture for the SDL library.
|
||||||
|
*
|
||||||
|
* This API lets apps read input from video sources, like webcams. Camera
|
||||||
|
* devices can be enumerated, queried, and opened. Once opened, it will
|
||||||
|
* provide SDL_Surface objects as new frames of video come in. These surfaces
|
||||||
|
* can be uploaded to an SDL_Texture or processed as pixels in memory.
|
||||||
|
*
|
||||||
|
* Several platforms will alert the user if an app tries to access a camera,
|
||||||
|
* and some will present a UI asking the user if your application should be
|
||||||
|
* allowed to obtain images at all, which they can deny. A successfully opened
|
||||||
|
* camera will not provide images until permission is granted. Applications,
|
||||||
|
* after opening a camera device, can see if they were granted access by
|
||||||
|
* either polling with the SDL_GetCameraPermissionState() function, or waiting
|
||||||
|
* for an SDL_EVENT_CAMERA_DEVICE_APPROVED or SDL_EVENT_CAMERA_DEVICE_DENIED
|
||||||
|
* event. Platforms that don't have any user approval process will report
|
||||||
|
* approval immediately.
|
||||||
|
*
|
||||||
|
* Note that SDL cameras only provide video as individual frames; they will
|
||||||
|
* not provide full-motion video encoded in a movie file format, although an
|
||||||
|
* app is free to encode the acquired frames into any format it likes. It also
|
||||||
|
* does not provide audio from the camera hardware through this API; not only
|
||||||
|
* do many webcams not have microphones at all, many people--from streamers to
|
||||||
|
* people on Zoom calls--will want to use a separate microphone regardless of
|
||||||
|
* the camera. In any case, recorded audio will be available through SDL's
|
||||||
|
* audio API no matter what hardware provides the microphone.
|
||||||
|
*
|
||||||
|
* ## Camera gotchas
|
||||||
|
*
|
||||||
|
* Consumer-level camera hardware tends to take a little while to warm up,
|
||||||
|
* once the device has been opened. Generally most camera apps have some sort
|
||||||
|
* of UI to take a picture (a button to snap a pic while a preview is showing,
|
||||||
|
* some sort of multi-second countdown for the user to pose, like a photo
|
||||||
|
* booth), which puts control in the users' hands, or they are intended to
|
||||||
|
* stay on for long times (Pokemon Go, etc).
|
||||||
|
*
|
||||||
|
* It's not uncommon that a newly-opened camera will provide a couple of
|
||||||
|
* completely black frames, maybe followed by some under-exposed images. If
|
||||||
|
* taking a single frame automatically, or recording video from a camera's
|
||||||
|
* input without the user initiating it from a preview, it could be wise to
|
||||||
|
* drop the first several frames (if not the first several _seconds_ worth of
|
||||||
|
* frames!) before using images from a camera.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SDL_camera_h_
|
||||||
|
#define SDL_camera_h_
|
||||||
|
|
||||||
|
#include <SDL3/SDL_stdinc.h>
|
||||||
|
#include <SDL3/SDL_error.h>
|
||||||
|
#include <SDL3/SDL_pixels.h>
|
||||||
|
#include <SDL3/SDL_properties.h>
|
||||||
|
#include <SDL3/SDL_surface.h>
|
||||||
|
|
||||||
|
#include <SDL3/SDL_begin_code.h>
|
||||||
|
/* Set up for C function definitions, even when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a unique ID for a camera device for the time it is connected to the
|
||||||
|
* system, and is never reused for the lifetime of the application.
|
||||||
|
*
|
||||||
|
* If the device is disconnected and reconnected, it will get a new ID.
|
||||||
|
*
|
||||||
|
* The value 0 is an invalid ID.
|
||||||
|
*
|
||||||
|
* \since This datatype is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetCameras
|
||||||
|
*/
|
||||||
|
typedef Uint32 SDL_CameraID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The opaque structure used to identify an opened SDL camera.
|
||||||
|
*
|
||||||
|
* \since This struct is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
typedef struct SDL_Camera SDL_Camera;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The details of an output format for a camera device.
|
||||||
|
*
|
||||||
|
* Cameras often support multiple formats; each one will be encapsulated in
|
||||||
|
* this struct.
|
||||||
|
*
|
||||||
|
* \since This struct is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetCameraSupportedFormats
|
||||||
|
* \sa SDL_GetCameraFormat
|
||||||
|
*/
|
||||||
|
typedef struct SDL_CameraSpec
|
||||||
|
{
|
||||||
|
SDL_PixelFormat format; /**< Frame format */
|
||||||
|
SDL_Colorspace colorspace; /**< Frame colorspace */
|
||||||
|
int width; /**< Frame width */
|
||||||
|
int height; /**< Frame height */
|
||||||
|
int framerate_numerator; /**< Frame rate numerator ((num / denom) == FPS, (denom / num) == duration in seconds) */
|
||||||
|
int framerate_denominator; /**< Frame rate denominator ((num / denom) == FPS, (denom / num) == duration in seconds) */
|
||||||
|
} SDL_CameraSpec;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The position of camera in relation to system device.
|
||||||
|
*
|
||||||
|
* \since This enum is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetCameraPosition
|
||||||
|
*/
|
||||||
|
typedef enum SDL_CameraPosition
|
||||||
|
{
|
||||||
|
SDL_CAMERA_POSITION_UNKNOWN,
|
||||||
|
SDL_CAMERA_POSITION_FRONT_FACING,
|
||||||
|
SDL_CAMERA_POSITION_BACK_FACING
|
||||||
|
} SDL_CameraPosition;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this function to get the number of built-in camera drivers.
|
||||||
|
*
|
||||||
|
* This function returns a hardcoded number. This never returns a negative
|
||||||
|
* value; if there are no drivers compiled into this build of SDL, this
|
||||||
|
* function returns zero. The presence of a driver in this list does not mean
|
||||||
|
* it will function, it just means SDL is capable of interacting with that
|
||||||
|
* interface. For example, a build of SDL might have v4l2 support, but if
|
||||||
|
* there's no kernel support available, SDL's v4l2 driver would fail if used.
|
||||||
|
*
|
||||||
|
* By default, SDL tries all drivers, in its preferred order, until one is
|
||||||
|
* found to be usable.
|
||||||
|
*
|
||||||
|
* \returns the number of built-in camera drivers.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetCameraDriver
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC int SDLCALL SDL_GetNumCameraDrivers(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this function to get the name of a built in camera driver.
|
||||||
|
*
|
||||||
|
* The list of camera drivers is given in the order that they are normally
|
||||||
|
* initialized by default; the drivers that seem more reasonable to choose
|
||||||
|
* first (as far as the SDL developers believe) are earlier in the list.
|
||||||
|
*
|
||||||
|
* The names of drivers are all simple, low-ASCII identifiers, like "v4l2",
|
||||||
|
* "coremedia" or "android". These never have Unicode characters, and are not
|
||||||
|
* meant to be proper names.
|
||||||
|
*
|
||||||
|
* \param index the index of the camera driver; the value ranges from 0 to
|
||||||
|
* SDL_GetNumCameraDrivers() - 1.
|
||||||
|
* \returns the name of the camera driver at the requested index, or NULL if
|
||||||
|
* an invalid index was specified.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetNumCameraDrivers
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC const char * SDLCALL SDL_GetCameraDriver(int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the name of the current camera driver.
|
||||||
|
*
|
||||||
|
* The names of drivers are all simple, low-ASCII identifiers, like "v4l2",
|
||||||
|
* "coremedia" or "android". These never have Unicode characters, and are not
|
||||||
|
* meant to be proper names.
|
||||||
|
*
|
||||||
|
* \returns the name of the current camera driver or NULL if no driver has
|
||||||
|
* been initialized.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC const char * SDLCALL SDL_GetCurrentCameraDriver(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a list of currently connected camera devices.
|
||||||
|
*
|
||||||
|
* \param count a pointer filled in with the number of cameras returned, may
|
||||||
|
* be NULL.
|
||||||
|
* \returns a 0 terminated array of camera instance IDs or NULL on failure;
|
||||||
|
* call SDL_GetError() for more information. This should be freed
|
||||||
|
* with SDL_free() when it is no longer needed.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_OpenCamera
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC SDL_CameraID * SDLCALL SDL_GetCameras(int *count);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the list of native formats/sizes a camera supports.
|
||||||
|
*
|
||||||
|
* This returns a list of all formats and frame sizes that a specific camera
|
||||||
|
* can offer. This is useful if your app can accept a variety of image formats
|
||||||
|
* and sizes and so want to find the optimal spec that doesn't require
|
||||||
|
* conversion.
|
||||||
|
*
|
||||||
|
* This function isn't strictly required; if you call SDL_OpenCamera with a
|
||||||
|
* NULL spec, SDL will choose a native format for you, and if you instead
|
||||||
|
* specify a desired format, it will transparently convert to the requested
|
||||||
|
* format on your behalf.
|
||||||
|
*
|
||||||
|
* If `count` is not NULL, it will be filled with the number of elements in
|
||||||
|
* the returned array.
|
||||||
|
*
|
||||||
|
* Note that it's legal for a camera to supply an empty list. This is what
|
||||||
|
* will happen on Emscripten builds, since that platform won't tell _anything_
|
||||||
|
* about available cameras until you've opened one, and won't even tell if
|
||||||
|
* there _is_ a camera until the user has given you permission to check
|
||||||
|
* through a scary warning popup.
|
||||||
|
*
|
||||||
|
* \param instance_id the camera device instance ID.
|
||||||
|
* \param count a pointer filled in with the number of elements in the list,
|
||||||
|
* may be NULL.
|
||||||
|
* \returns a NULL terminated array of pointers to SDL_CameraSpec or NULL on
|
||||||
|
* failure; call SDL_GetError() for more information. This is a
|
||||||
|
* single allocation that should be freed with SDL_free() when it is
|
||||||
|
* no longer needed.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetCameras
|
||||||
|
* \sa SDL_OpenCamera
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC SDL_CameraSpec ** SDLCALL SDL_GetCameraSupportedFormats(SDL_CameraID instance_id, int *count);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the human-readable device name for a camera.
|
||||||
|
*
|
||||||
|
* \param instance_id the camera device instance ID.
|
||||||
|
* \returns a human-readable device name or NULL on failure; call
|
||||||
|
* SDL_GetError() for more information.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetCameras
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC const char * SDLCALL SDL_GetCameraName(SDL_CameraID instance_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the position of the camera in relation to the system.
|
||||||
|
*
|
||||||
|
* Most platforms will report UNKNOWN, but mobile devices, like phones, can
|
||||||
|
* often make a distinction between cameras on the front of the device (that
|
||||||
|
* points towards the user, for taking "selfies") and cameras on the back (for
|
||||||
|
* filming in the direction the user is facing).
|
||||||
|
*
|
||||||
|
* \param instance_id the camera device instance ID.
|
||||||
|
* \returns the position of the camera on the system hardware.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetCameras
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC SDL_CameraPosition SDLCALL SDL_GetCameraPosition(SDL_CameraID instance_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a video recording device (a "camera").
|
||||||
|
*
|
||||||
|
* You can open the device with any reasonable spec, and if the hardware can't
|
||||||
|
* directly support it, it will convert data seamlessly to the requested
|
||||||
|
* format. This might incur overhead, including scaling of image data.
|
||||||
|
*
|
||||||
|
* If you would rather accept whatever format the device offers, you can pass
|
||||||
|
* a NULL spec here and it will choose one for you (and you can use
|
||||||
|
* SDL_Surface's conversion/scaling functions directly if necessary).
|
||||||
|
*
|
||||||
|
* You can call SDL_GetCameraFormat() to get the actual data format if passing
|
||||||
|
* a NULL spec here. You can see the exact specs a device can support without
|
||||||
|
* conversion with SDL_GetCameraSupportedFormats().
|
||||||
|
*
|
||||||
|
* SDL will not attempt to emulate framerate; it will try to set the hardware
|
||||||
|
* to the rate closest to the requested speed, but it won't attempt to limit
|
||||||
|
* or duplicate frames artificially; call SDL_GetCameraFormat() to see the
|
||||||
|
* actual framerate of the opened the device, and check your timestamps if
|
||||||
|
* this is crucial to your app!
|
||||||
|
*
|
||||||
|
* Note that the camera is not usable until the user approves its use! On some
|
||||||
|
* platforms, the operating system will prompt the user to permit access to
|
||||||
|
* the camera, and they can choose Yes or No at that point. Until they do, the
|
||||||
|
* camera will not be usable. The app should either wait for an
|
||||||
|
* SDL_EVENT_CAMERA_DEVICE_APPROVED (or SDL_EVENT_CAMERA_DEVICE_DENIED) event,
|
||||||
|
* or poll SDL_GetCameraPermissionState() occasionally until it returns
|
||||||
|
* non-zero. On platforms that don't require explicit user approval (and
|
||||||
|
* perhaps in places where the user previously permitted access), the approval
|
||||||
|
* event might come immediately, but it might come seconds, minutes, or hours
|
||||||
|
* later!
|
||||||
|
*
|
||||||
|
* \param instance_id the camera device instance ID.
|
||||||
|
* \param spec the desired format for data the device will provide. Can be
|
||||||
|
* NULL.
|
||||||
|
* \returns an SDL_Camera object or NULL on failure; call SDL_GetError() for
|
||||||
|
* more information.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetCameras
|
||||||
|
* \sa SDL_GetCameraFormat
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC SDL_Camera * SDLCALL SDL_OpenCamera(SDL_CameraID instance_id, const SDL_CameraSpec *spec);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query if camera access has been approved by the user.
|
||||||
|
*
|
||||||
|
* Cameras will not function between when the device is opened by the app and
|
||||||
|
* when the user permits access to the hardware. On some platforms, this
|
||||||
|
* presents as a popup dialog where the user has to explicitly approve access;
|
||||||
|
* on others the approval might be implicit and not alert the user at all.
|
||||||
|
*
|
||||||
|
* This function can be used to check the status of that approval. It will
|
||||||
|
* return 0 if still waiting for user response, 1 if the camera is approved
|
||||||
|
* for use, and -1 if the user denied access.
|
||||||
|
*
|
||||||
|
* Instead of polling with this function, you can wait for a
|
||||||
|
* SDL_EVENT_CAMERA_DEVICE_APPROVED (or SDL_EVENT_CAMERA_DEVICE_DENIED) event
|
||||||
|
* in the standard SDL event loop, which is guaranteed to be sent once when
|
||||||
|
* permission to use the camera is decided.
|
||||||
|
*
|
||||||
|
* If a camera is declined, there's nothing to be done but call
|
||||||
|
* SDL_CloseCamera() to dispose of it.
|
||||||
|
*
|
||||||
|
* \param camera the opened camera device to query.
|
||||||
|
* \returns -1 if user denied access to the camera, 1 if user approved access,
|
||||||
|
* 0 if no decision has been made yet.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_OpenCamera
|
||||||
|
* \sa SDL_CloseCamera
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC int SDLCALL SDL_GetCameraPermissionState(SDL_Camera *camera);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the instance ID of an opened camera.
|
||||||
|
*
|
||||||
|
* \param camera an SDL_Camera to query.
|
||||||
|
* \returns the instance ID of the specified camera on success or 0 on
|
||||||
|
* failure; call SDL_GetError() for more information.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_OpenCamera
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC SDL_CameraID SDLCALL SDL_GetCameraID(SDL_Camera *camera);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the properties associated with an opened camera.
|
||||||
|
*
|
||||||
|
* \param camera the SDL_Camera obtained from SDL_OpenCamera().
|
||||||
|
* \returns a valid property ID on success or 0 on failure; call
|
||||||
|
* SDL_GetError() for more information.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetCameraProperties(SDL_Camera *camera);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the spec that a camera is using when generating images.
|
||||||
|
*
|
||||||
|
* Note that this might not be the native format of the hardware, as SDL might
|
||||||
|
* be converting to this format behind the scenes.
|
||||||
|
*
|
||||||
|
* If the system is waiting for the user to approve access to the camera, as
|
||||||
|
* some platforms require, this will return false, but this isn't necessarily
|
||||||
|
* a fatal error; you should either wait for an
|
||||||
|
* SDL_EVENT_CAMERA_DEVICE_APPROVED (or SDL_EVENT_CAMERA_DEVICE_DENIED) event,
|
||||||
|
* or poll SDL_GetCameraPermissionState() occasionally until it returns
|
||||||
|
* non-zero.
|
||||||
|
*
|
||||||
|
* \param camera opened camera device.
|
||||||
|
* \param spec the SDL_CameraSpec to be initialized by this function.
|
||||||
|
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||||
|
* information.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_OpenCamera
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_GetCameraFormat(SDL_Camera *camera, SDL_CameraSpec *spec);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Acquire a frame.
|
||||||
|
*
|
||||||
|
* The frame is a memory pointer to the image data, whose size and format are
|
||||||
|
* given by the spec requested when opening the device.
|
||||||
|
*
|
||||||
|
* This is a non blocking API. If there is a frame available, a non-NULL
|
||||||
|
* surface is returned, and timestampNS will be filled with a non-zero value.
|
||||||
|
*
|
||||||
|
* Note that an error case can also return NULL, but a NULL by itself is
|
||||||
|
* normal and just signifies that a new frame is not yet available. Note that
|
||||||
|
* even if a camera device fails outright (a USB camera is unplugged while in
|
||||||
|
* use, etc), SDL will send an event separately to notify the app, but
|
||||||
|
* continue to provide blank frames at ongoing intervals until
|
||||||
|
* SDL_CloseCamera() is called, so real failure here is almost always an out
|
||||||
|
* of memory condition.
|
||||||
|
*
|
||||||
|
* After use, the frame should be released with SDL_ReleaseCameraFrame(). If
|
||||||
|
* you don't do this, the system may stop providing more video!
|
||||||
|
*
|
||||||
|
* Do not call SDL_DestroySurface() on the returned surface! It must be given
|
||||||
|
* back to the camera subsystem with SDL_ReleaseCameraFrame!
|
||||||
|
*
|
||||||
|
* If the system is waiting for the user to approve access to the camera, as
|
||||||
|
* some platforms require, this will return NULL (no frames available); you
|
||||||
|
* should either wait for an SDL_EVENT_CAMERA_DEVICE_APPROVED (or
|
||||||
|
* SDL_EVENT_CAMERA_DEVICE_DENIED) event, or poll
|
||||||
|
* SDL_GetCameraPermissionState() occasionally until it returns non-zero.
|
||||||
|
*
|
||||||
|
* \param camera opened camera device.
|
||||||
|
* \param timestampNS a pointer filled in with the frame's timestamp, or 0 on
|
||||||
|
* error. Can be NULL.
|
||||||
|
* \returns a new frame of video on success, NULL if none is currently
|
||||||
|
* available.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_ReleaseCameraFrame
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_AcquireCameraFrame(SDL_Camera *camera, Uint64 *timestampNS);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Release a frame of video acquired from a camera.
|
||||||
|
*
|
||||||
|
* Let the back-end re-use the internal buffer for camera.
|
||||||
|
*
|
||||||
|
* This function _must_ be called only on surface objects returned by
|
||||||
|
* SDL_AcquireCameraFrame(). This function should be called as quickly as
|
||||||
|
* possible after acquisition, as SDL keeps a small FIFO queue of surfaces for
|
||||||
|
* video frames; if surfaces aren't released in a timely manner, SDL may drop
|
||||||
|
* upcoming video frames from the camera.
|
||||||
|
*
|
||||||
|
* If the app needs to keep the surface for a significant time, they should
|
||||||
|
* make a copy of it and release the original.
|
||||||
|
*
|
||||||
|
* The app should not use the surface again after calling this function;
|
||||||
|
* assume the surface is freed and the pointer is invalid.
|
||||||
|
*
|
||||||
|
* \param camera opened camera device.
|
||||||
|
* \param frame the video frame surface to release.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_AcquireCameraFrame
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC void SDLCALL SDL_ReleaseCameraFrame(SDL_Camera *camera, SDL_Surface *frame);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this function to shut down camera processing and close the camera
|
||||||
|
* device.
|
||||||
|
*
|
||||||
|
* \param camera opened camera device.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread, but no
|
||||||
|
* thread may reference `device` once this function is called.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_OpenCamera
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC void SDLCALL SDL_CloseCamera(SDL_Camera *camera);
|
||||||
|
|
||||||
|
/* Ends C function definitions when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#include <SDL3/SDL_close_code.h>
|
||||||
|
|
||||||
|
#endif /* SDL_camera_h_ */
|
||||||
@@ -0,0 +1,330 @@
|
|||||||
|
/*
|
||||||
|
Simple DirectMedia Layer
|
||||||
|
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* # CategoryClipboard
|
||||||
|
*
|
||||||
|
* SDL provides access to the system clipboard, both for reading information
|
||||||
|
* from other processes and publishing information of its own.
|
||||||
|
*
|
||||||
|
* This is not just text! SDL apps can access and publish data by mimetype.
|
||||||
|
*
|
||||||
|
* ## Basic use (text)
|
||||||
|
*
|
||||||
|
* Obtaining and publishing simple text to the system clipboard is as easy as
|
||||||
|
* calling SDL_GetClipboardText() and SDL_SetClipboardText(), respectively.
|
||||||
|
* These deal with C strings in UTF-8 encoding. Data transmission and encoding
|
||||||
|
* conversion is completely managed by SDL.
|
||||||
|
*
|
||||||
|
* ## Clipboard callbacks (data other than text)
|
||||||
|
*
|
||||||
|
* Things get more complicated when the clipboard contains something other
|
||||||
|
* than text. Not only can the system clipboard contain data of any type, in
|
||||||
|
* some cases it can contain the same data in different formats! For example,
|
||||||
|
* an image painting app might let the user copy a graphic to the clipboard,
|
||||||
|
* and offers it in .BMP, .JPG, or .PNG format for other apps to consume.
|
||||||
|
*
|
||||||
|
* Obtaining clipboard data ("pasting") like this is a matter of calling
|
||||||
|
* SDL_GetClipboardData() and telling it the mimetype of the data you want.
|
||||||
|
* But how does one know if that format is available? SDL_HasClipboardData()
|
||||||
|
* can report if a specific mimetype is offered, and
|
||||||
|
* SDL_GetClipboardMimeTypes() can provide the entire list of mimetypes
|
||||||
|
* available, so the app can decide what to do with the data and what formats
|
||||||
|
* it can support.
|
||||||
|
*
|
||||||
|
* Setting the clipboard ("copying") to arbitrary data is done with
|
||||||
|
* SDL_SetClipboardData. The app does not provide the data in this call, but
|
||||||
|
* rather the mimetypes it is willing to provide and a callback function.
|
||||||
|
* During the callback, the app will generate the data. This allows massive
|
||||||
|
* data sets to be provided to the clipboard, without any data being copied
|
||||||
|
* before it is explicitly requested. More specifically, it allows an app to
|
||||||
|
* offer data in multiple formats without providing a copy of all of them
|
||||||
|
* upfront. If the app has an image that it could provide in PNG or JPG
|
||||||
|
* format, it doesn't have to encode it to either of those unless and until
|
||||||
|
* something tries to paste it.
|
||||||
|
*
|
||||||
|
* ## Primary Selection
|
||||||
|
*
|
||||||
|
* The X11 and Wayland video targets have a concept of the "primary selection"
|
||||||
|
* in addition to the usual clipboard. This is generally highlighted (but not
|
||||||
|
* explicitly copied) text from various apps. SDL offers APIs for this through
|
||||||
|
* SDL_GetPrimarySelectionText() and SDL_SetPrimarySelectionText(). SDL offers
|
||||||
|
* these APIs on platforms without this concept, too, but only so far that it
|
||||||
|
* will keep a copy of a string that the app sets for later retrieval; the
|
||||||
|
* operating system will not ever attempt to change the string externally if
|
||||||
|
* it doesn't support a primary selection.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SDL_clipboard_h_
|
||||||
|
#define SDL_clipboard_h_
|
||||||
|
|
||||||
|
#include <SDL3/SDL_stdinc.h>
|
||||||
|
#include <SDL3/SDL_error.h>
|
||||||
|
|
||||||
|
#include <SDL3/SDL_begin_code.h>
|
||||||
|
/* Set up for C function definitions, even when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Function prototypes */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Put UTF-8 text into the clipboard.
|
||||||
|
*
|
||||||
|
* \param text the text to store in the clipboard.
|
||||||
|
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||||
|
* information.
|
||||||
|
*
|
||||||
|
* \threadsafety This function should only be called on the main thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetClipboardText
|
||||||
|
* \sa SDL_HasClipboardText
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_SetClipboardText(const char *text);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get UTF-8 text from the clipboard.
|
||||||
|
*
|
||||||
|
* This function returns an empty string if there is not enough memory left
|
||||||
|
* for a copy of the clipboard's content.
|
||||||
|
*
|
||||||
|
* \returns the clipboard text on success or an empty string on failure; call
|
||||||
|
* SDL_GetError() for more information. This should be freed with
|
||||||
|
* SDL_free() when it is no longer needed.
|
||||||
|
*
|
||||||
|
* \threadsafety This function should only be called on the main thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_HasClipboardText
|
||||||
|
* \sa SDL_SetClipboardText
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC char * SDLCALL SDL_GetClipboardText(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query whether the clipboard exists and contains a non-empty text string.
|
||||||
|
*
|
||||||
|
* \returns true if the clipboard has text, or false if it does not.
|
||||||
|
*
|
||||||
|
* \threadsafety This function should only be called on the main thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetClipboardText
|
||||||
|
* \sa SDL_SetClipboardText
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_HasClipboardText(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Put UTF-8 text into the primary selection.
|
||||||
|
*
|
||||||
|
* \param text the text to store in the primary selection.
|
||||||
|
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||||
|
* information.
|
||||||
|
*
|
||||||
|
* \threadsafety This function should only be called on the main thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetPrimarySelectionText
|
||||||
|
* \sa SDL_HasPrimarySelectionText
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_SetPrimarySelectionText(const char *text);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get UTF-8 text from the primary selection.
|
||||||
|
*
|
||||||
|
* This function returns an empty string if there is not enough memory left
|
||||||
|
* for a copy of the primary selection's content.
|
||||||
|
*
|
||||||
|
* \returns the primary selection text on success or an empty string on
|
||||||
|
* failure; call SDL_GetError() for more information. This should be
|
||||||
|
* freed with SDL_free() when it is no longer needed.
|
||||||
|
*
|
||||||
|
* \threadsafety This function should only be called on the main thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_HasPrimarySelectionText
|
||||||
|
* \sa SDL_SetPrimarySelectionText
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC char * SDLCALL SDL_GetPrimarySelectionText(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query whether the primary selection exists and contains a non-empty text
|
||||||
|
* string.
|
||||||
|
*
|
||||||
|
* \returns true if the primary selection has text, or false if it does not.
|
||||||
|
*
|
||||||
|
* \threadsafety This function should only be called on the main thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetPrimarySelectionText
|
||||||
|
* \sa SDL_SetPrimarySelectionText
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_HasPrimarySelectionText(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback function that will be called when data for the specified mime-type
|
||||||
|
* is requested by the OS.
|
||||||
|
*
|
||||||
|
* The callback function is called with NULL as the mime_type when the
|
||||||
|
* clipboard is cleared or new data is set. The clipboard is automatically
|
||||||
|
* cleared in SDL_Quit().
|
||||||
|
*
|
||||||
|
* \param userdata a pointer to the provided user data.
|
||||||
|
* \param mime_type the requested mime-type.
|
||||||
|
* \param size a pointer filled in with the length of the returned data.
|
||||||
|
* \returns a pointer to the data for the provided mime-type. Returning NULL
|
||||||
|
* or setting the length to 0 will cause zero length data to be sent
|
||||||
|
* to the "receiver", which should be able to handle this. The
|
||||||
|
* returned data will not be freed, so it needs to be retained and
|
||||||
|
* dealt with internally.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_SetClipboardData
|
||||||
|
*/
|
||||||
|
typedef const void *(SDLCALL *SDL_ClipboardDataCallback)(void *userdata, const char *mime_type, size_t *size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback function that will be called when the clipboard is cleared, or when new
|
||||||
|
* data is set.
|
||||||
|
*
|
||||||
|
* \param userdata a pointer to the provided user data.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_SetClipboardData
|
||||||
|
*/
|
||||||
|
typedef void (SDLCALL *SDL_ClipboardCleanupCallback)(void *userdata);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offer clipboard data to the OS.
|
||||||
|
*
|
||||||
|
* Tell the operating system that the application is offering clipboard data
|
||||||
|
* for each of the provided mime-types. Once another application requests the
|
||||||
|
* data the callback function will be called, allowing it to generate and
|
||||||
|
* respond with the data for the requested mime-type.
|
||||||
|
*
|
||||||
|
* The size of text data does not include any terminator, and the text does
|
||||||
|
* not need to be null-terminated (e.g., you can directly copy a portion of a
|
||||||
|
* document).
|
||||||
|
*
|
||||||
|
* \param callback a function pointer to the function that provides the
|
||||||
|
* clipboard data.
|
||||||
|
* \param cleanup a function pointer to the function that cleans up the
|
||||||
|
* clipboard data.
|
||||||
|
* \param userdata an opaque pointer that will be forwarded to the callbacks.
|
||||||
|
* \param mime_types a list of mime-types that are being offered. SDL copies the given list.
|
||||||
|
* \param num_mime_types the number of mime-types in the mime_types list.
|
||||||
|
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||||
|
* information.
|
||||||
|
*
|
||||||
|
* \threadsafety This function should only be called on the main thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_ClearClipboardData
|
||||||
|
* \sa SDL_GetClipboardData
|
||||||
|
* \sa SDL_HasClipboardData
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_SetClipboardData(SDL_ClipboardDataCallback callback, SDL_ClipboardCleanupCallback cleanup, void *userdata, const char **mime_types, size_t num_mime_types);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the clipboard data.
|
||||||
|
*
|
||||||
|
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||||
|
* information.
|
||||||
|
*
|
||||||
|
* \threadsafety This function should only be called on the main thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_SetClipboardData
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_ClearClipboardData(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the data from the clipboard for a given mime type.
|
||||||
|
*
|
||||||
|
* The size of text data does not include the terminator, but the text is
|
||||||
|
* guaranteed to be null-terminated.
|
||||||
|
*
|
||||||
|
* \param mime_type the mime type to read from the clipboard.
|
||||||
|
* \param size a pointer filled in with the length of the returned data.
|
||||||
|
* \returns the retrieved data buffer or NULL on failure; call SDL_GetError()
|
||||||
|
* for more information. This should be freed with SDL_free() when it
|
||||||
|
* is no longer needed.
|
||||||
|
*
|
||||||
|
* \threadsafety This function should only be called on the main thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_HasClipboardData
|
||||||
|
* \sa SDL_SetClipboardData
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC void * SDLCALL SDL_GetClipboardData(const char *mime_type, size_t *size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query whether there is data in the clipboard for the provided mime type.
|
||||||
|
*
|
||||||
|
* \param mime_type the mime type to check for data.
|
||||||
|
* \returns true if data exists in the clipboard for the provided mime type,
|
||||||
|
* false if it does not.
|
||||||
|
*
|
||||||
|
* \threadsafety This function should only be called on the main thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_SetClipboardData
|
||||||
|
* \sa SDL_GetClipboardData
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC bool SDLCALL SDL_HasClipboardData(const char *mime_type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the list of mime types available in the clipboard.
|
||||||
|
*
|
||||||
|
* \param num_mime_types a pointer filled with the number of mime types, may
|
||||||
|
* be NULL.
|
||||||
|
* \returns a null-terminated array of strings with mime types, or NULL on
|
||||||
|
* failure; call SDL_GetError() for more information. This should be
|
||||||
|
* freed with SDL_free() when it is no longer needed.
|
||||||
|
*
|
||||||
|
* \threadsafety This function should only be called on the main thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.2.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_SetClipboardData
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC char ** SDLCALL SDL_GetClipboardMimeTypes(size_t *num_mime_types);
|
||||||
|
|
||||||
|
/* Ends C function definitions when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#include <SDL3/SDL_close_code.h>
|
||||||
|
|
||||||
|
#endif /* SDL_clipboard_h_ */
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
Simple DirectMedia Layer
|
||||||
|
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file reverses the effects of SDL_begin_code.h and should be included
|
||||||
|
* after you finish any function and structure declarations in your headers.
|
||||||
|
*
|
||||||
|
* SDL's headers use this; applications generally should not include this
|
||||||
|
* header directly.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SDL_begin_code_h
|
||||||
|
#error SDL_close_code.h included without matching SDL_begin_code.h
|
||||||
|
#endif
|
||||||
|
#undef SDL_begin_code_h
|
||||||
|
|
||||||
|
/* Reset structure packing at previous byte alignment */
|
||||||
|
#if defined(_MSC_VER) || defined(__MWERKS__) || defined(__BORLANDC__)
|
||||||
|
#ifdef __BORLANDC__
|
||||||
|
#pragma nopackwarning
|
||||||
|
#endif
|
||||||
|
#pragma pack(pop)
|
||||||
|
#endif /* Compiler needs structure packing set */
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user