Compare commits
5 Commits
main
...
feature/ph
| Author | SHA1 | Date | |
|---|---|---|---|
|
462fb12bd5
|
|||
|
cb878cfaa5
|
|||
|
71de95822c
|
|||
|
f4728bf19d
|
|||
|
42453c2eb6
|
@@ -75,6 +75,7 @@ add_library(akgl SHARED
|
||||
src/staticstring.c
|
||||
src/tilemap.c
|
||||
src/util.c
|
||||
src/stage.c
|
||||
${GAMECONTROLLERDB_H}
|
||||
)
|
||||
|
||||
|
||||
271
README.md
271
README.md
@@ -1,271 +0,0 @@
|
||||
## How do I initialize a game
|
||||
|
||||
Initialize the global game object with info about your game
|
||||
|
||||
```c
|
||||
strncpy((char *)&game.name, "sdl3-gametest", 256);
|
||||
strncpy((char *)&game.version, "0.0.1", 32);
|
||||
strncpy((char *)&game.uri, "net.aklabs.games.sdl3-gametest", 256);
|
||||
```
|
||||
|
||||
Call the game initialization routines and lock the game state for further initialization
|
||||
|
||||
```c
|
||||
PASS(e, akgl_game_init());
|
||||
PASS(e, akgl_game_state_lock());
|
||||
```
|
||||
|
||||
If you have a registry properties file, load it. If you don't have a properties file, use `akgl_set_property("prop_name", "prop_value")` to populate the required game properties.
|
||||
|
||||
```c
|
||||
PASS(e, akgl_registry_load_properties(YOUR_REGISTR_FILEPATH));
|
||||
```
|
||||
|
||||
Initialize your physics engine and renderer of choice
|
||||
|
||||
```c
|
||||
PASS(e, akgl_render_init2d(renderer));
|
||||
PASS(e, akgl_physics_init_arcade(physics));
|
||||
```
|
||||
|
||||
Unlock the game state
|
||||
|
||||
```c
|
||||
PASS(e, akgl_game_state_unlock());
|
||||
```
|
||||
|
||||
## What is in a properties file (or, What properties must I set if I don't have one?)
|
||||
|
||||
```json
|
||||
{
|
||||
"properties": {
|
||||
"game.screenwidth": "640",
|
||||
"game.screenheight": "480",
|
||||
"physics.gravity.y": "1024.0",
|
||||
"physics.drag.y": "1.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Physics properties (gravity and drag along X, Y and Z) are optional and default to `0`.
|
||||
|
||||
## How do I update and render the game world in my main loop
|
||||
|
||||
In your game loop (or in your `SDL_AppIterate` method), lock the game state, call the game update function, and then unlock the game state
|
||||
|
||||
```c
|
||||
PASS(e, akgl_game_state_lock());
|
||||
PASS(e, renderer->frame_start(renderer));
|
||||
SDL_RenderClear(renderer->sdl_renderer);
|
||||
PASS(e, akgl_game_update(NULL));
|
||||
PASS(e, renderer->frame_end(renderer));
|
||||
PASS(e, akgl_game_state_unlock());
|
||||
```
|
||||
|
||||
## How do I get an actor on screen
|
||||
|
||||
Load a sprite for a character. Sprites are JSON documents describing 2D sprites, frames, and looping. Sprites are named, and sprite names must be unique.
|
||||
|
||||
```c
|
||||
PASS(e, akgl_sprite_load_json(SOME_FILENAME))
|
||||
```
|
||||
|
||||
Load a character from a JSON file. Characters map sprites to actor states and define physics characteristics like movement speed. Each character is named, and character names must be unique.
|
||||
|
||||
```c
|
||||
PASS(e, akgl_character_load_json(SOME_FILENAME))
|
||||
```
|
||||
|
||||
You don't strictly have to load sprites and characters from json files, you can initialize them yourself, it's just tedious work. Here's an example of initializing a 32x32 sprite from a spritesheet that uses the first 4 frames in a looping animation.
|
||||
|
||||
```c
|
||||
akgl_SpriteSheet *sheet;
|
||||
akgl_Sprite *sprite;
|
||||
akgl_Character *character;
|
||||
PASS(e, akgl_heap_next_spritesheet(&sheet);
|
||||
PASS(e, akgl_spritesheet_initialize(sheet, 32, 32, IMAGE_FILENAME));
|
||||
PASS(e, akgl_heap_next_sprite(&sprite));
|
||||
PASS(e, akgl_sprite_initialize(sprite, SPRITE_NAME, &sheet);
|
||||
sprite->frames = 4;
|
||||
sprite->frameids = [0, 1, 2, 3];
|
||||
sprite->width = 32;
|
||||
sprite->height = 32;
|
||||
sprite->speed = 1000;
|
||||
sprite->loop = true;
|
||||
strncpy((char *)&sprite->name, "SPRITE NAME", AKGL_SPRITE_MAX_NAME_LENGTH);
|
||||
PASS(e, akgl_heap_next_character(&character));
|
||||
PASS(e, akgl_character_initialize(&character, "CHAR NAME"));
|
||||
PASS(e, akgl_character_sprite_add(&character, &sprite, STATE_MASK));
|
||||
// Set the character acceleration and scale if desired
|
||||
character->ax = 64.0;
|
||||
character->ay = 64.0;
|
||||
character->sx = 2.0;
|
||||
character->sy = 2.0;
|
||||
```
|
||||
|
||||
Initialize an actor. Actors are named ("player", "Quest NPC", whatever) and names must be unique.
|
||||
|
||||
```c
|
||||
akgl_Actor *myactor = NULL;
|
||||
PASS(e, akgl_heap_next_actor(&myactor);
|
||||
PASS(e, akgl_actor_initialize(&myactor, "ACTOR_NAME"));
|
||||
```
|
||||
|
||||
Assign a character to the actor by looking up the `akgl_Character` from the AKGL registry and assign it.
|
||||
|
||||
```c
|
||||
myactor->basechar = SDL_GetPointerProperty(
|
||||
AKGL_REGISTRY_CHARACTER,
|
||||
"CHARACTER_NAME",
|
||||
NULL);
|
||||
FAIL_ZERO_BREAK(e, myactor->basechar, AKERR_REGISTRY, "Character missing");
|
||||
```
|
||||
|
||||
Give the actor a position and a state, and turn it visible.
|
||||
|
||||
```c
|
||||
myactor->state = 9AKGL_ACTOR_STATE_ALIVE | AKGL_ACTOR_STATE_FACE_LEFT);
|
||||
myactor->x = 320;
|
||||
myactor->y = 240;
|
||||
myactor->visible = true;
|
||||
```
|
||||
|
||||
## What are in Sprite and Character files
|
||||
|
||||
Sprite files:
|
||||
|
||||
```json
|
||||
{
|
||||
"spritesheet": {
|
||||
"filename": "RELATIVE_IMAGE_FILE_REFERENCE",
|
||||
"frame_width": int,
|
||||
"frame_height": int
|
||||
},
|
||||
"name": "UNIQUE_SPRITE_NAME",
|
||||
"width": int,
|
||||
"height": int,
|
||||
"speed": int,
|
||||
"loop": boolean,
|
||||
"loopReverse": boolean,
|
||||
"frames": [
|
||||
int
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
* `frames` references the frame indexes in the spritesheet that should be used for this animation. Spritesheets are counted from the top left corner going to the right according to the spritesheet `frame_width` and `frame_height`.
|
||||
* `loop` says whether or not we should loop the animation
|
||||
* `loopReverse` says whether or not we should "bounce" the animation (when we reach the end of the frames, start counting back to the beginning, then count to the end, etc). Otherwise the frames are displayed from 0..n and then cycles back to 0.
|
||||
* `speed` is the number of milliseconds each frame in the animation should appear on the screen
|
||||
|
||||
Character files:
|
||||
|
||||
```c
|
||||
{
|
||||
"name": "UNIQUE_CHARACTER_NAME",
|
||||
"speedtime": 8,
|
||||
"speed_x": 0,
|
||||
"speed_y": 0,
|
||||
"acceleration_x": 0,
|
||||
"acceleration_y": 0,
|
||||
"sprite_mappings": [
|
||||
{
|
||||
"state": [
|
||||
"AKGL_ACTOR_STATE_ALIVE",
|
||||
"AKGL_ACTOR_STATE_FACE_UP",
|
||||
"AKGL_ACTOR_STATE_MOVING_UP"
|
||||
],
|
||||
"sprite": "menupointer"
|
||||
}[, ...]
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
* `speedtime` appears to be legacy and unused.
|
||||
* `speed_[xy]` and `acceleration_[xy]` are physics parameters that specify the top speed and acceleration rate (in pixels per nanosecond) of the character in physics simulations. The effect of acceleration depends on the physics simulation being used at the time (which may or may not account for gravity, drag, etc).
|
||||
* `sprite_mappings` map a set of actor state flag bitmasks (assume everything in `state` is `OR`ed together) to a sprite name. The game engine uses this to automatically pick the correct sprite (by name) for a given set of state flags. You need one of these for every possible state the character may be used in.
|
||||
|
||||
## How do I load a tilemap from the filesystem and display it on screen with my actors
|
||||
|
||||
The engine ONLY supports TilED TMJ tilemaps with tileset external references. Load a tilemap into the global `akgl_Tilemap *gamemap` object.
|
||||
|
||||
```c
|
||||
PASS(e, akgl_tilemap_load(PATHSTRING, gamemap));
|
||||
```
|
||||
|
||||
Actors will be automatically populated from objects in the tilemap object layers. Actor state flags here must be expressed as an integer, you can't (yet) use the same array of strings that is used in character json files.
|
||||
|
||||
```json
|
||||
"objects":[
|
||||
{
|
||||
"gid":147,
|
||||
"height":16,
|
||||
"id":1,
|
||||
"name":"player",
|
||||
"properties":[
|
||||
{
|
||||
"name":"character",
|
||||
"type":"string",
|
||||
"value":"little guy"
|
||||
},
|
||||
{
|
||||
"name":"state",
|
||||
"type":"int",
|
||||
"value":24
|
||||
}],
|
||||
"rotation":0,
|
||||
"type":"actor",
|
||||
"visible":true,
|
||||
"width":16,
|
||||
"x":440.510088317656,
|
||||
"y":140.347239175702
|
||||
}[, ... ]
|
||||
```
|
||||
|
||||
Check if the tilemap wants to use its own physics, and if you want to allow that, override the global physics simulation
|
||||
|
||||
```c
|
||||
if ( gamemap->use_own_physics == true ) {
|
||||
physics = &gamemap->physics;
|
||||
}
|
||||
```
|
||||
|
||||
Tilemap physics specification follows. A map can specify its own physics properties (drag, gravity) without specifying a custom model.
|
||||
|
||||
```json
|
||||
"properties":[
|
||||
{
|
||||
"name":"physics.drag.y",
|
||||
"type":"float",
|
||||
"value":0
|
||||
},
|
||||
{
|
||||
"name":"physics.gravity.y",
|
||||
"type":"float",
|
||||
"value":0
|
||||
},
|
||||
{
|
||||
"name":"physics.model",
|
||||
"type":"string",
|
||||
"value":"arcade"
|
||||
}],
|
||||
```
|
||||
|
||||
The global `gamemap` object is automatically displayed if it is populated. Actors are drawn at the appropriate map layer depending on the actor's `layer` property (warning: this may be replaced with a `z` property soon.)
|
||||
|
||||
## How do I get the screen width and height
|
||||
|
||||
The most direct is to call `SDL_GetCurrentDisplayMode` to get the parameters from the returned `SDL_DisplayMode` structure (`->w` and `->h`).
|
||||
|
||||
The simplest way is to check the global `camera` object's `camera->w` and `camera->h` object. You may have more than one camera on a scene, and it's theoretically possible that the global camera object has been overriden and no longer represents the full screen.
|
||||
|
||||
The most reliable engine-centric way is to use `akgl_get_property` to get the property from the engine. Properties are read and stored as strings, so if you need to do these kinds of things a lot, cache the integer value somewhere.
|
||||
|
||||
```c
|
||||
akgl_String *width = NULL;
|
||||
int screenwidth = NULL;
|
||||
PASS(e, akgl_get_property("game.screenwidth", &width, "0"));
|
||||
PASS(e, aksl_atoi(width->data, &screenwidth));
|
||||
PASS(e, akgl_heap_release_string(width));
|
||||
```
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#ifndef _SDL_GAMECONTROLLERDB_H_
|
||||
#define _SDL_GAMECONTROLLERDB_H_
|
||||
|
||||
// Taken from https://raw.githubusercontent.com/mdqinc/SDL_GameControllerDB/refs/heads/master/gamecontrollerdb.txt on Tue Jun 2 04:45:53 PM EDT 2026
|
||||
// Taken from https://raw.githubusercontent.com/mdqinc/SDL_GameControllerDB/refs/heads/master/gamecontrollerdb.txt on Sat Jun 27 08:22:48 AM EDT 2026
|
||||
|
||||
#define AKGL_SDL_GAMECONTROLLER_DB_LEN 2229
|
||||
#define AKGL_SDL_GAMECONTROLLER_DB_LEN 2243
|
||||
|
||||
const char *SDL_GAMECONTROLLER_DB[] = {
|
||||
"03000000300f00000a01000000000000,3 In 1 Conversion Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b8,x:b3,y:b0,platform:Windows",
|
||||
@@ -687,7 +687,7 @@ const char *SDL_GAMECONTROLLER_DB[] = {
|
||||
"03000000a306000020f6000000000000,Saitek PS2700 PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows",
|
||||
"03000000300f00001101000000000000,Saitek Rumble,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows",
|
||||
"03000000e804000000a0000000000000,Samsung EIGP20,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows",
|
||||
"03000000bd12000010d1000000000000,Sanwa 4Button,a:b0,b:b1,x:b2,y:b3,dpup:-a1,dpdown:+a1,dpleft:-a0,dpright:+a0,platform:Windows",
|
||||
"03000000bd12000010d1000000000000,Sanwa 4Button,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,x:b2,y:b3,platform:Windows",
|
||||
"03000000c01100000252000000000000,Sanwa Easy Grip,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows",
|
||||
"03000000c01100004350000000000000,Sanwa Micro Grip P3,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,x:b3,y:b2,platform:Windows",
|
||||
"03000000411200004550000000000000,Sanwa Micro Grip Pro,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a1,righty:a2,start:b9,x:b1,y:b3,platform:Windows",
|
||||
@@ -701,14 +701,14 @@ const char *SDL_GAMECONTROLLER_DB[] = {
|
||||
"030000004f04000028b3000000000000,Score A,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows",
|
||||
"03000000952e00002577000000000000,Scuf PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows",
|
||||
"03000000a30c00002500000000000000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Windows",
|
||||
"03000000a30c00002400000000000000,Sega Mega Drive Mini 6B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,leftshoulder:b6,lefttrigger:b7,back:b8,start:b9,x:b3,y:b0,platform:Windows",
|
||||
"03000000a30c00002400000000000000,Sega Mega Drive Mini 6B Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows",
|
||||
"03000000d804000086e6000000000000,Sega Multi Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:a2,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows",
|
||||
"0300000000050000289b000000000000,Sega Saturn Adapter,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows",
|
||||
"0300000000f000000800000000000000,Sega Saturn Controller,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,righttrigger:b3,start:b0,x:b5,y:b6,platform:Windows",
|
||||
"03000000730700000601000000000000,Sega Saturn Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows",
|
||||
"03000000b40400000a01000000000000,Sega Saturn Controller,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows",
|
||||
"030000003b07000004a1000000000000,SFX,a:b0,b:b2,back:b7,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b5,start:b8,x:b1,y:b3,platform:Windows",
|
||||
"03000000632500002705000000000000,ShanWan Gamepad,a:b0,b:b1,x:b3,y:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,-lefty:-a1,+lefty:+a2,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,righttrigger:b9,start:b11,leftstick:b13,rightstick:b14,platform:Windows",
|
||||
"03000000632500002705000000000000,ShanWan Gamepad,+lefty:+a2,-lefty:-a1,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,rightshoulder:b7,rightstick:b14,righttrigger:b9,start:b11,x:b3,y:b4,platform:Windows",
|
||||
"03000000f82100001900000000000000,Shogun Bros Chameleon X1,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows",
|
||||
"03000000120c00001c1e000000000000,SnakeByte 4S PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows",
|
||||
"03000000140300000918000000000000,SNES Controller,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows",
|
||||
@@ -737,6 +737,7 @@ const char *SDL_GAMECONTROLLER_DB[] = {
|
||||
"03000000120c0000160e000000000000,Steel Play Metaltech PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows",
|
||||
"03000000110100001914000000000000,SteelSeries,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows",
|
||||
"03000000381000001214000000000000,SteelSeries Free,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows",
|
||||
"03000000381000004114000000000000,SteelSeries Nimbus Cloud,a:b0,b:b1,x:b3,y:b4,back:b10,guide:b15,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,paddle1:b5,paddle2:b2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b8,righttrigger:b9,platform:Windows",
|
||||
"03000000110100003114000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows",
|
||||
"03000000381000003014000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows",
|
||||
"03000000381000003114000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows",
|
||||
@@ -780,7 +781,7 @@ const char *SDL_GAMECONTROLLER_DB[] = {
|
||||
"030000005f140000c501000000000000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows",
|
||||
"03000000b80500000210000000000000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows",
|
||||
"030000005f1400002a01000000000000,Trust Predator GM1200,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,x:b3,y:b4,platform:Windows",
|
||||
"03000000580400000a10000000000000,Trust Sight Fighter,a:b0,b:b1,x:b3,y:b4,back:b5,start:b2,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,lefttrigger:b8,righttrigger:b9,platform:Windows",
|
||||
"03000000580400000a10000000000000,Trust Sight Fighter,a:b0,b:b1,back:b5,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,start:b2,x:b3,y:b4,platform:Windows",
|
||||
"030000004f04000087b6000000000000,TWCS Throttle,dpdown:b8,dpleft:b9,dpright:b7,dpup:b6,leftstick:b5,lefttrigger:-a5,leftx:a0,lefty:a1,righttrigger:+a5,platform:Windows",
|
||||
"03000000411200000450000000000000,Twin Shock,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a4,start:b11,x:b3,y:b0,platform:Windows",
|
||||
"03000000d90400000200000000000000,TwinShock PS2 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows",
|
||||
@@ -942,6 +943,7 @@ const char *SDL_GAMECONTROLLER_DB[] = {
|
||||
"03000000503200000110000045010000,Atari VCS Classic,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b3,start:b2,platform:Mac OS X",
|
||||
"03000000503200000110000047010000,Atari VCS Classic Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b3,start:b2,platform:Mac OS X",
|
||||
"03000000503200000210000047010000,Atari VCS Modern Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a2,righty:a3,start:b8,x:b2,y:b3,platform:Mac OS X",
|
||||
"03000000e30500008106000000010000,Austgame GameCube Adapter,a:b0,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:+a4,leftx:a0,lefty:a1,misc3:b5,misc4:b6,rightshoulder:b4,righttrigger:-a4,rightx:a2,righty:a3,start:b7,x:b1,y:b3,platform:Mac OS X",
|
||||
"030000008a3500000102000000010000,Backbone One,a:b0,b:b1,back:b16,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b17,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b15,x:b2,y:b3,platform:Mac OS X",
|
||||
"030000008a3500000201000000010000,Backbone One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X",
|
||||
"030000008a3500000202000000010000,Backbone One,a:b0,b:b1,back:b16,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b17,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b15,x:b2,y:b3,platform:Mac OS X",
|
||||
@@ -1119,6 +1121,7 @@ const char *SDL_GAMECONTROLLER_DB[] = {
|
||||
"03000000110100002014000000000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X",
|
||||
"03000000110100002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X",
|
||||
"03000000381000002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X",
|
||||
"03000000381000004114000000010000,SteelSeries Nimbus Cloud,a:b0,b:b1,x:b3,y:b4,back:b10,guide:b15,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,paddle1:b5,paddle2:b2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,platform:Mac OS X",
|
||||
"05000000484944204465766963650000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b15,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b14,x:b2,y:b3,platform:Mac OS X",
|
||||
"050000004e696d6275732b0000000000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b15,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b14,x:b2,y:b3,platform:Mac OS X",
|
||||
"03000000381000003014000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X",
|
||||
@@ -1250,12 +1253,16 @@ const char *SDL_GAMECONTROLLER_DB[] = {
|
||||
"03000000c82d00001230000011010000,8BitDo Ultimate,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux",
|
||||
"03000000c82d00001330000011010000,8BitDo Ultimate,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux",
|
||||
"05000000c82d00001230000000010000,8BitDo Ultimate,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux",
|
||||
"03000000c82d00001260000011010000,8BitDo Ultimate 2,a:b0,b:b1,x:b3,y:b4,back:b10,guide:b12,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,paddle1:b17,paddle2:b16,paddle3:b2,paddle4:b5,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,platform:Linux",
|
||||
"03000000c82d00000b31000014010000,8BitDo Ultimate 2,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,start:b7,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux",
|
||||
"05000000c82d00001260000001000000,8BitDo Ultimate 2,a:b0,b:b1,x:b3,y:b4,back:b10,guide:b12,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,paddle1:b17,paddle2:b16,paddle3:b2,paddle4:b5,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,platform:Linux",
|
||||
"03000000c82d00000a31000014010000,8BitDo Ultimate 2C,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux",
|
||||
"03000000c82d00001d30000011010000,8BitDo Ultimate 2C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b5,paddle2:b2,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux",
|
||||
"05000000c82d00001b30000001000000,8BitDo Ultimate 2C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b5,paddle2:b2,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux",
|
||||
"03000000c82d00001530000011010000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux",
|
||||
"03000000c82d00001630000011010000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux",
|
||||
"03000000c82d00001730000011010000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux",
|
||||
"06000000c82d00000320000007010000,8BitDo Ultimate Wired Controller for Xbox,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,start:b7,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux",
|
||||
"03000000c82d00000121000011010000,8BitDo Xbox One SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux",
|
||||
"05000000c82d00000121000000010000,8BitDo Xbox One SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux",
|
||||
"05000000a00500003232000001000000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux",
|
||||
@@ -1277,6 +1284,7 @@ const char *SDL_GAMECONTROLLER_DB[] = {
|
||||
"03000000020500000913000010010000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux",
|
||||
"03000000373500000710000010010000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux",
|
||||
"05000000373500004610000001000000,Anbernic RG P01,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux",
|
||||
"19000000010000000100000000010000,Anbernic RG28XX Controller,a:b4,b:b3,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b7,misc1:b1,rightshoulder:b8,leftstick:b12,rightstick:b13,start:b10,x:b5,y:b6,platform:Linux",
|
||||
"03000000190e00000110000010010000,Aquaplus Piece,a:b1,b:b0,back:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b2,platform:Linux",
|
||||
"03000000790000003018000011010000,Arcade Fightstick F300,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux",
|
||||
"03000000a30c00002700000011010000,Astro City Mini,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux",
|
||||
@@ -1349,6 +1357,7 @@ const char *SDL_GAMECONTROLLER_DB[] = {
|
||||
"05000000ac0500002d0200001b010000,GameSir G4s,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b33,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux",
|
||||
"03000000ac0500007a05000011010000,GameSir G5,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b16,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux",
|
||||
"03000000373500009710000001020000,GameSir Kaleid Flux,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux",
|
||||
"03000000373500005810000001020000,GameSir K1,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux",
|
||||
"03000000ac0500001a06000011010000,GameSir T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux",
|
||||
"03000000373500000410000044010000,GameSir T4 Kaleid,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux",
|
||||
"03000000bc2000005656000011010000,GameSir T4w,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux",
|
||||
@@ -1447,6 +1456,7 @@ const char *SDL_GAMECONTROLLER_DB[] = {
|
||||
"03000000242f00008a00000011010000,JYS Adapter,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Linux",
|
||||
"03000000314100001935000000010000,LeadJoy Xeno Plus,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:+a5,rightx:a4,righty:a4,start:b7,x:b2,y:b3,platform:Linux",
|
||||
"030000006f0e00000103000000020000,Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux",
|
||||
"030000006f0e000001f5000010010000,Logic3 Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux",
|
||||
"030000006d040000d1ca000000000000,Logitech Chillstream,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux",
|
||||
"030000006d040000d1ca000011010000,Logitech Chillstream,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux",
|
||||
"030000006d04000016c2000010010000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux",
|
||||
@@ -1537,10 +1547,10 @@ const char *SDL_GAMECONTROLLER_DB[] = {
|
||||
"03000000853200000706000012010000,Nacon GC100,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux",
|
||||
"030000006b140000010c000010010000,Nacon GC400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux",
|
||||
"05000000853200000503000000010000,Nacon MGX Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux",
|
||||
"0300000085320000170d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux",
|
||||
"0300000085320000190d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux",
|
||||
"0300000085320000180d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux",
|
||||
"0300000085320000160d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux",
|
||||
"0300000085320000170d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux",
|
||||
"0300000085320000180d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux",
|
||||
"0300000085320000190d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux",
|
||||
"030000000d0f00000900000010010000,Natec Genesis P44,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux",
|
||||
"030000004f1f00000800000011010000,NeoGeo PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux",
|
||||
"0300000092120000474e000000010000,NeoGeo X Arcade Stick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b3,y:b2,platform:Linux",
|
||||
@@ -1619,6 +1629,7 @@ const char *SDL_GAMECONTROLLER_DB[] = {
|
||||
"03000000d62000000520000050010000,PowerA Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux",
|
||||
"03000000d62000000b20000001010000,PowerA Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux",
|
||||
"03000000d62000000f20000001010000,PowerA Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b7,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux",
|
||||
"03000000d62000006520000002010000,PowerA Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux",
|
||||
"030000006d040000d2ca000011010000,Precision Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux",
|
||||
"03000000250900000017000010010000,PS SS N64 Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b5,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2~,righty:a3,start:b8,platform:Linux",
|
||||
"03000000ff1100004133000010010000,PS2 Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux",
|
||||
@@ -1752,7 +1763,8 @@ const char *SDL_GAMECONTROLLER_DB[] = {
|
||||
"030000005e0400008e02000073050000,Speedlink Torid,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux",
|
||||
"030000005e0400008e02000020200000,SpeedLink Xeox Pro Analog,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux",
|
||||
"03000000de280000ff11000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux",
|
||||
"05000000381000001214000001000000,SteelSeries Free,a:b0,b:b1,x:b3,y:b4,back:b10,guide:b12,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a2,righttrigger:a3,platform:Linux",
|
||||
"05000000381000001214000001000000,SteelSeries Free,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a3,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux",
|
||||
"05000000381000004114000000010000,SteelSeries Nimbus Cloud,a:b0,b:b1,x:b3,y:b4,back:b10,guide:b15,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,paddle1:b5,paddle2:b2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,platform:Linux",
|
||||
"050000004e696d6275732b0000000000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b10,guide:b11,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b12,x:b2,y:b3,platform:Linux",
|
||||
"03000000381000003014000075010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux",
|
||||
"03000000381000003114000075010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux",
|
||||
@@ -1798,9 +1810,10 @@ const char *SDL_GAMECONTROLLER_DB[] = {
|
||||
"03000000e00d00000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,platform:Linux",
|
||||
"03000000f00600000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,platform:Linux",
|
||||
"030000005f140000c501000010010000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux",
|
||||
"03000000f51000001370000000000000,Turtle Beach ReactR,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux",
|
||||
"03000000f51000001370000000010000,Turtle Beach ReactR,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux",
|
||||
"06000000f51000000870000003010000,Turtle Beach Recon,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux",
|
||||
"03000000f51000001370000000010000,Turtle Beach ReactR,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,start:b7,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux",
|
||||
"03000000f51000001370000000000000,Turtle Beach ReactR,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,start:b7,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux",
|
||||
"05000000f51000008f01000001000000,Turtle Beach Rematch Nintendo Switch Controller,a:b0,b:b1,x:b2,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Linux",
|
||||
"03000000100800000100000010010000,Twin PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux",
|
||||
"03000000c0160000e105000010010000,Ultimate Atari Fight Stick,a:b1,b:b2,back:b9,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b4,righttrigger:b5,start:b8,x:b0,y:b3,platform:Linux",
|
||||
"03000000151900005678000010010000,Uniplay U6,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux",
|
||||
@@ -2014,6 +2027,7 @@ const char *SDL_GAMECONTROLLER_DB[] = {
|
||||
"5553422c322d6178697320382d627574,iBuffalo Super Famicom Controller,a:b1,b:b0,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b17,rightshoulder:b18,start:b10,x:b3,y:b2,platform:Android",
|
||||
"64306137363261396266353433303531,InterAct GoPad,a:b24,b:b25,leftshoulder:b23,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,x:b21,y:b22,platform:Android",
|
||||
"532e542e442e20496e74657261637420,InterAct HammerHead FX,a:b23,b:b24,back:b30,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b26,leftstick:b22,lefttrigger:b28,leftx:a0,lefty:a1,rightshoulder:b27,rightstick:b25,righttrigger:b29,rightx:a2,righty:a3,start:b31,x:b20,y:b21,platform:Android",
|
||||
"05000000300f00001201000000780f00,Jess Tech Dual Analog Pad,a:b22,b:b23,back:b28,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b24,leftstick:b30,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b26,rightstick:b31,righttrigger:b27,rightx:a3,righty:a2,start:b29,x:b20,y:b21,platform:Android",
|
||||
"65346535636333663931613264643164,Joy-Con,a:b21,b:b22,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b23,y:b24,platform:Android",
|
||||
"33346566643039343630376565326335,Joy-Con (L),a:b0,b:b1,back:b7,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b17,x:b19,y:b2,platform:Android",
|
||||
"35313531613435623366313835326238,Joy-Con (L),a:b0,b:b1,back:b7,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b17,x:b19,y:b2,platform:Android",
|
||||
|
||||
@@ -2,8 +2,11 @@
|
||||
#define _AKGL_ACTOR_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "types.h"
|
||||
#include "character.h"
|
||||
|
||||
#include <akstdlib.h>
|
||||
|
||||
#include <akgl/types.h>
|
||||
#include <akgl/character.h>
|
||||
|
||||
// ---- LOW WORD STATUSES ----
|
||||
|
||||
@@ -59,6 +62,7 @@ extern char *AKGL_ACTOR_STATE_STRING_NAMES[AKGL_ACTOR_MAX_STATES+1];
|
||||
#define AKGL_MAX_HEAP_ACTOR 64
|
||||
|
||||
typedef struct akgl_Actor {
|
||||
uint8_t type;
|
||||
uint8_t refcount;
|
||||
char name[AKGL_ACTOR_MAX_NAME_LENGTH];
|
||||
akgl_Character *basechar;
|
||||
@@ -70,7 +74,10 @@ typedef struct akgl_Actor {
|
||||
bool movement_controls_face;
|
||||
void *actorData;
|
||||
bool visible;
|
||||
bool simulating;
|
||||
SDL_Time movetimer;
|
||||
// Bounding box accounting for the actor's current real position plus physics delta
|
||||
SDL_FRect bbox;
|
||||
// Velocity. Combined effect of all forces acting on the actor resulting
|
||||
// in energy along an axis.
|
||||
float32_t vx;
|
||||
@@ -100,13 +107,24 @@ typedef struct akgl_Actor {
|
||||
float32_t y;
|
||||
float32_t z;
|
||||
float32_t scale;
|
||||
// Reference to the BSP Node currently containing this actor
|
||||
aksl_TreeNode *bsphome;
|
||||
// Reference to the BSP linked list node currently holding this actor
|
||||
aksl_ListNode *bsplistnode;
|
||||
struct akgl_Actor *children[AKGL_ACTOR_MAX_CHILDREN];
|
||||
struct akgl_Actor *parent;
|
||||
|
||||
// method that controls logic update functions
|
||||
akerr_ErrorContext AKERR_NOIGNORE *(*updatefunc)(struct akgl_Actor *obj);
|
||||
// method that renders the actor to the currently active renderer
|
||||
akerr_ErrorContext AKERR_NOIGNORE *(*renderfunc)(struct akgl_Actor *obj);
|
||||
// method that changes the actor's face flags based on other state
|
||||
akerr_ErrorContext AKERR_NOIGNORE *(*facefunc)(struct akgl_Actor *obj);
|
||||
// method that performs movement logic on the actor based on state flags
|
||||
akerr_ErrorContext AKERR_NOIGNORE *(*movementlogicfunc)(struct akgl_Actor *obj, float32_t dt);
|
||||
// method that calculates the correct sprite frame for the actor's current state
|
||||
akerr_ErrorContext AKERR_NOIGNORE *(*changeframefunc)(struct akgl_Actor *obj, akgl_Sprite *curSprite, SDL_Time curtimems);
|
||||
// method to add a child to this actor
|
||||
akerr_ErrorContext AKERR_NOIGNORE *(*addchild)(struct akgl_Actor *obj, struct akgl_Actor *child);
|
||||
} akgl_Actor;
|
||||
|
||||
|
||||
@@ -12,7 +12,9 @@
|
||||
#define RESTORE_GCC_WARNINGS \
|
||||
_Pragma("GCC diagnostic pop")
|
||||
|
||||
#define AKGL_ERR_SDL AKERR_LAST_ERRNO_VALUE + 1
|
||||
#define AKGL_ERR_LOGICINTERRUPT AKERR_LAST_ERRNO_VALUE + 2
|
||||
#define AKGL_ERR_SDL AKERR_LAST_ERRNO_VALUE + 1 /** Error in the SDL library. See SDL_GetError() for more detail. */
|
||||
#define AKGL_ERR_LOGICINTERRUPT AKERR_LAST_ERRNO_VALUE + 2 /** Raised by an actor to tell the physics simulator not to process this node */
|
||||
#define AKGL_ERR_REGISTRY AKERR_LAST_ERRNO_VALUE + 3 /** The AKGL Registry was not able to fulfill the operation */
|
||||
#define AKGL_ERR_OOHEAP AKERR_LAST_ERRNO_VALUE + 4 /** The AKGL Heap in this context has been exhausted */
|
||||
|
||||
#endif // _ERROR_H_
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <SDL3_mixer/SDL_mixer.h>
|
||||
#include "types.h"
|
||||
#include "tilemap.h"
|
||||
#include "renderer.h"
|
||||
#include "physics.h"
|
||||
#include <akgl/types.h>
|
||||
#include <akgl/tilemap.h>
|
||||
#include <akgl/renderer.h>
|
||||
#include <akgl/physics.h>
|
||||
#include <akgl/stage.h>
|
||||
|
||||
#define AKGL_VERSION "0.1.0"
|
||||
|
||||
@@ -49,10 +50,12 @@ extern MIX_Mixer *akgl_mixer;
|
||||
extern MIX_Track *akgl_tracks[AKGL_GAME_AUDIO_MAX_TRACKS];
|
||||
extern SDL_FRect _akgl_camera;
|
||||
extern akgl_Game game;
|
||||
extern akgl_Stage _stage;
|
||||
extern akgl_RenderBackend _akgl_renderer;
|
||||
extern akgl_PhysicsBackend _akgl_physics;
|
||||
extern akgl_Tilemap _akgl_gamemap;
|
||||
|
||||
extern akgl_Stage *stage;
|
||||
extern akgl_Tilemap *gamemap;
|
||||
extern akgl_RenderBackend *renderer;
|
||||
extern akgl_PhysicsBackend *physics;
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
#ifndef _AKGL_HEAP_H_
|
||||
#define _AKGL_HEAP_H_
|
||||
|
||||
#include "sprite.h"
|
||||
#include "actor.h"
|
||||
#include "character.h"
|
||||
#include "staticstring.h"
|
||||
#include <akgl/sprite.h>
|
||||
#include <akgl/actor.h>
|
||||
#include <akgl/character.h>
|
||||
#include <akgl/staticstring.h>
|
||||
#include <akgl/stage.h>
|
||||
#include <akerror.h>
|
||||
#include <akstdlib.h>
|
||||
|
||||
#ifndef AKGL_MAX_HEAP_ACTOR
|
||||
#define AKGL_MAX_HEAP_ACTOR 64
|
||||
@@ -22,25 +24,43 @@
|
||||
#ifndef AKGL_MAX_HEAP_STRING
|
||||
#define AKGL_MAX_HEAP_STRING 256
|
||||
#endif
|
||||
#ifndef AKGL_MAX_HEAP_LIST
|
||||
#define AKGL_MAX_HEAP_LIST (AKGL_MAX_HEAP_ACTOR * 2) + 256
|
||||
#endif
|
||||
#ifndef AKGL_MAX_HEAP_TREE
|
||||
#define AKGL_MAX_HEAP_TREE 32
|
||||
#endif
|
||||
|
||||
extern akgl_Actor HEAP_ACTOR[AKGL_MAX_HEAP_ACTOR];
|
||||
extern akgl_Sprite HEAP_SPRITE[AKGL_MAX_HEAP_SPRITE];
|
||||
extern akgl_SpriteSheet HEAP_SPRITESHEET[AKGL_MAX_HEAP_SPRITESHEET];
|
||||
extern akgl_Character HEAP_CHARACTER[AKGL_MAX_HEAP_CHARACTER];
|
||||
extern akgl_String HEAP_STRING[AKGL_MAX_HEAP_STRING];
|
||||
extern aksl_ListNode HEAP_LIST[AKGL_MAX_HEAP_LIST];
|
||||
extern aksl_TreeNode HEAP_TREE[AKGL_MAX_HEAP_TREE];
|
||||
extern akgl_BSPLeaf HEAP_TREE_LEAVES[AKGL_MAX_HEAP_TREE];
|
||||
extern void *AKGL_LIST_SENTINEL;
|
||||
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_heap_init();
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_heap_init_list();
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_heap_init_tree();
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_heap_init_actor();
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_heap_next_actor(akgl_Actor **dest);
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_heap_next_sprite(akgl_Sprite **dest);
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_heap_next_spritesheet(akgl_SpriteSheet **dest);
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_heap_next_character(akgl_Character **dest);
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_heap_next_string(akgl_String **dest);
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_heap_next_list(aksl_ListNode **dest);
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_heap_next_tree(aksl_TreeNode **dest);
|
||||
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_heap_release_actor(akgl_Actor *ptr);
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_heap_release_sprite(akgl_Sprite *ptr);
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_heap_release_spritesheet(akgl_SpriteSheet *ptr);
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_heap_release_character(akgl_Character *ptr);
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_heap_release_string(akgl_String *ptr);
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_heap_release_list(aksl_ListNode *ptr);
|
||||
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_heap_iter_list_release(aksl_ListNode *ptr, void *data);
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_heap_iter_tree_release(aksl_TreeNode *ptr, void *data);
|
||||
|
||||
#endif //_AKGL_HEAP_H_
|
||||
|
||||
45
include/akgl/stage.h
Normal file
45
include/akgl/stage.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#ifndef _STAGE_H_
|
||||
#define _STAGE_H_
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <akstdlib.h>
|
||||
|
||||
#include <akgl/actor.h>
|
||||
|
||||
#define AKGL_STAGE_PARTITION_HORIZONTAL 0
|
||||
#define AKGL_STAGE_PARTITION_VERTICAL 1
|
||||
#define AKGL_STAGE_PARTITION_MAXDEPTH 4
|
||||
|
||||
typedef struct akgl_BSPContext {
|
||||
aksl_TreeNode *left;
|
||||
aksl_TreeNode *right;
|
||||
aksl_TreeNode *parent;
|
||||
} akgl_BSPContext;
|
||||
|
||||
typedef struct akgl_BSPLeaf {
|
||||
SDL_FRect extent;
|
||||
aksl_ListNode *actors;
|
||||
} akgl_BSPLeaf;
|
||||
|
||||
// Stages are collections of lights and cameras in a 2D or 3D space wherein actors
|
||||
// and backgrounds are placed and directed for action.
|
||||
typedef struct akgl_Stage {
|
||||
aksl_TreeNode bsp;
|
||||
akgl_BSPLeaf _rootleaf;
|
||||
akerr_ErrorContext AKERR_NOIGNORE *(*partition)(struct akgl_Stage *self);
|
||||
akerr_ErrorContext AKERR_NOIGNORE *(*partition_actor)(struct akgl_Stage *self, akgl_Actor *actor);
|
||||
} akgl_Stage;
|
||||
|
||||
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_stage_2d(akgl_Stage *self);
|
||||
|
||||
// A function to divide the stage into a binary space partition tree with lists of actors in each partition
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_stage_2d_partition(akgl_Stage *self);
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_stage_2d_partition_switchdirection(uint8_t direction, uint8_t *dest);
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_stage_2d_bsp_actoriter(aksl_ListNode *node, void *data);
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_stage_2d_bsp(aksl_TreeNode *root, aksl_ListNode *actors, SDL_FRect extents, uint8_t direction, uint8_t depth, uint8_t maxdepth);
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_stage_2d_bspfree(akgl_Stage *self);
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_stage_2d_partition(akgl_Stage *self);
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_stage_2d_bsp_move(akgl_Stage *self, akgl_Actor *actor);
|
||||
|
||||
#endif // _STAGE_H_
|
||||
@@ -10,9 +10,9 @@
|
||||
typedef struct
|
||||
{
|
||||
int refcount;
|
||||
int length;
|
||||
char data[AKGL_MAX_STRING_LENGTH];
|
||||
} akgl_String;
|
||||
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_string_initialize(akgl_String *obj, char *init);
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_string_copy(akgl_String *src, akgl_String *dst, int count);
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_string_initialize(akgl_String *obj, char *init);akerr_ErrorContext AKERR_NOIGNORE *akgl_string_copy(akgl_String *src, akgl_String *dst, int count);
|
||||
#endif //_STRING_H_
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#include <SDL3/SDL.h>
|
||||
#include <SDL3_image/SDL_image.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <akerror.h>
|
||||
#include <akstdlib.h>
|
||||
|
||||
#include <akgl/physics.h>
|
||||
#include <akgl/game.h>
|
||||
|
||||
@@ -277,7 +277,7 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_controller_default(int controlmapid, cha
|
||||
controlmap->jsid = jsid;
|
||||
|
||||
controlmap->target = SDL_GetPointerProperty(AKGL_REGISTRY_ACTOR, actorname, NULL);
|
||||
FAIL_ZERO_BREAK(errctx, controlmap->target, AKERR_REGISTRY, "Actor %s not found in registry", actorname);
|
||||
FAIL_ZERO_BREAK(errctx, controlmap->target, AKGL_ERR_REGISTRY, "Actor %s not found in registry", actorname);
|
||||
|
||||
// ---- KEYBOARD CONTROLS ----
|
||||
|
||||
|
||||
12
src/game.c
12
src/game.c
@@ -25,12 +25,14 @@ akgl_RenderBackend *renderer;
|
||||
akgl_PhysicsBackend *physics;
|
||||
SDL_FRect *camera;
|
||||
akgl_Tilemap *gamemap;
|
||||
akgl_Stage *stage;
|
||||
|
||||
// Default objects
|
||||
akgl_RenderBackend _akgl_renderer;
|
||||
akgl_PhysicsBackend _akgl_physics;
|
||||
SDL_FRect _akgl_camera;
|
||||
akgl_Tilemap _akgl_gamemap;
|
||||
akgl_Stage _akgl_stage;
|
||||
|
||||
MIX_Audio *bgm = NULL;
|
||||
MIX_Mixer *akgl_mixer = NULL;
|
||||
@@ -50,6 +52,12 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_game_init()
|
||||
|
||||
int i = 0;
|
||||
PREPARE_ERROR(e);
|
||||
|
||||
akerr_name_for_status(AKGL_ERR_SDL, "SDL Error");
|
||||
akerr_name_for_status(AKGL_ERR_LOGICINTERRUPT, "AKGL Logic Interrupt");
|
||||
akerr_name_for_status(AKGL_ERR_REGISTRY, "AKGL Registry Error");
|
||||
akerr_name_for_status(AKGL_ERR_OOHEAP, "AKGL Heap Capacity");
|
||||
|
||||
strncpy((char *)&game.libversion, AKGL_VERSION, 32);
|
||||
game.gameStartTime = SDL_GetTicksNS();
|
||||
game.lastIterTime = game.gameStartTime;
|
||||
@@ -118,6 +126,7 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_game_init()
|
||||
renderer = &_akgl_renderer;
|
||||
physics = &_akgl_physics;
|
||||
gamemap = &_akgl_gamemap;
|
||||
stage = &_akgl_stage;
|
||||
|
||||
PASS(e, akgl_game_state_unlock());
|
||||
SUCCEED_RETURN(e);
|
||||
@@ -445,7 +454,8 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_game_update(akgl_Iterator *opflags)
|
||||
PASS(e, actor->updatefunc(actor));
|
||||
}
|
||||
}
|
||||
PASS(e, physics->simulate(physics, NULL));
|
||||
|
||||
PASS(e, physics->simulate(physics, NULL));
|
||||
PASS(e, renderer->draw_world(renderer, NULL));
|
||||
PASS(e, akgl_game_state_unlock());
|
||||
SUCCEED_RETURN(e);
|
||||
|
||||
261
src/heap.c
261
src/heap.c
@@ -1,3 +1,5 @@
|
||||
/** @file */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <akerror.h>
|
||||
|
||||
@@ -8,12 +10,18 @@
|
||||
#include <akgl/staticstring.h>
|
||||
#include <akgl/iterator.h>
|
||||
#include <akgl/error.h>
|
||||
#include <akgl/stage.h>
|
||||
|
||||
akgl_Actor HEAP_ACTOR[AKGL_MAX_HEAP_ACTOR];
|
||||
akgl_Sprite HEAP_SPRITE[AKGL_MAX_HEAP_SPRITE];
|
||||
akgl_SpriteSheet HEAP_SPRITESHEET[AKGL_MAX_HEAP_SPRITESHEET];
|
||||
akgl_Character HEAP_CHARACTER[AKGL_MAX_HEAP_CHARACTER];
|
||||
akgl_String HEAP_STRING[AKGL_MAX_HEAP_STRING];
|
||||
aksl_ListNode HEAP_LIST[AKGL_MAX_HEAP_LIST];
|
||||
aksl_TreeNode HEAP_TREE[AKGL_MAX_HEAP_TREE];
|
||||
akgl_BSPLeaf HEAP_TREE_LEAVES[AKGL_MAX_HEAP_TREE];
|
||||
|
||||
void *AKGL_LIST_SENTINEL = (void *)1; /** Sentinel value used for aksl_ListNode objects to determine if they are available */
|
||||
|
||||
akerr_ErrorContext *akgl_heap_init()
|
||||
{
|
||||
@@ -21,6 +29,8 @@ akerr_ErrorContext *akgl_heap_init()
|
||||
int i = 0;
|
||||
akerr_name_for_status(AKGL_ERR_SDL, "SDL Error");
|
||||
PASS(errctx, akgl_heap_init_actor());
|
||||
PASS(errctx, akgl_heap_init_list());
|
||||
PASS(errctx, akgl_heap_init_tree());
|
||||
for ( i = 0; i < AKGL_MAX_HEAP_SPRITE; i++) {
|
||||
memset(&HEAP_SPRITE[i], 0x00, sizeof(akgl_Sprite));
|
||||
}
|
||||
@@ -36,6 +46,27 @@ akerr_ErrorContext *akgl_heap_init()
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
akerr_ErrorContext *akgl_heap_init_list(void)
|
||||
{
|
||||
PREPARE_ERROR(e);
|
||||
for ( int i = 0; i < AKGL_MAX_HEAP_LIST; i++) {
|
||||
memset(&HEAP_LIST[i], 0x00, sizeof(aksl_ListNode));
|
||||
HEAP_LIST[i].data = AKGL_LIST_SENTINEL;
|
||||
}
|
||||
SUCCEED_RETURN(e);
|
||||
}
|
||||
|
||||
akerr_ErrorContext *akgl_heap_init_tree(void)
|
||||
{
|
||||
PREPARE_ERROR(e);
|
||||
for ( int i = 0; i < AKGL_MAX_HEAP_TREE; i++) {
|
||||
memset(&HEAP_TREE[i], 0x00, sizeof(aksl_TreeNode));
|
||||
HEAP_TREE[i].leaf = AKGL_LIST_SENTINEL;
|
||||
memset(&HEAP_TREE_LEAVES[i], 0x00, sizeof(akgl_BSPLeaf));
|
||||
}
|
||||
SUCCEED_RETURN(e);
|
||||
}
|
||||
|
||||
akerr_ErrorContext *akgl_heap_init_actor(void)
|
||||
{
|
||||
PREPARE_ERROR(e);
|
||||
@@ -45,6 +76,143 @@ akerr_ErrorContext *akgl_heap_init_actor(void)
|
||||
SUCCEED_RETURN(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the next aksl_ListNode from the heap
|
||||
*
|
||||
* @param[out] dest The pointer that will hold the procured aksl_ListNode
|
||||
*
|
||||
* @throws AKGL_ERR_OOHEAP There are no available nodes in HEAP_LIST
|
||||
* @return akerr_ErrorContext*
|
||||
*/
|
||||
|
||||
akerr_ErrorContext *akgl_heap_next_list(aksl_ListNode **dest)
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
for (int i = 0; i < AKGL_MAX_HEAP_LIST; i++ ) {
|
||||
if ( HEAP_LIST[i].data != AKGL_LIST_SENTINEL ) {
|
||||
continue;
|
||||
}
|
||||
*dest = &HEAP_LIST[i];
|
||||
HEAP_LIST[i].data = NULL;
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
FAIL_RETURN(errctx, AKGL_ERR_OOHEAP, "Unable to find unused list on the heap");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the next aksl_TreeNode from the heap
|
||||
*
|
||||
* @param[out] dest The pointer that will hold the procured tree node
|
||||
*
|
||||
* @throws AKGL_ERR_OOHEAP There are no available nodes in HEAP_TREE
|
||||
* @return akerr_ErrorContext*
|
||||
*/
|
||||
|
||||
akerr_ErrorContext *akgl_heap_next_tree(aksl_TreeNode **dest)
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
for (int i = 0; i < AKGL_MAX_HEAP_TREE; i++ ) {
|
||||
if ( HEAP_TREE[i].leaf != AKGL_LIST_SENTINEL ) {
|
||||
continue;
|
||||
}
|
||||
*dest = &HEAP_TREE[i];
|
||||
HEAP_TREE[i].leaf = &HEAP_TREE_LEAVES[i];
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
FAIL_RETURN(errctx, AKGL_ERR_OOHEAP, "Unable to find unused tree on the heap");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Release an aksl_ListNode that came from HEAP_TREE to make it available again
|
||||
*
|
||||
* @param[in] tree The aksl_ListNode to release.
|
||||
*
|
||||
* @return akerr_ErrorContext*
|
||||
*/
|
||||
|
||||
akerr_ErrorContext *akgl_heap_release_list(aksl_ListNode *list)
|
||||
{
|
||||
PREPARE_ERROR(e);
|
||||
FAIL_ZERO_RETURN(e, list, AKERR_NULLPOINTER, "list");
|
||||
list->next = NULL;
|
||||
list->prev = NULL;
|
||||
list->data = (void *)AKGL_LIST_SENTINEL;
|
||||
SUCCEED_RETURN(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Release an aksl_TreeNode that came from HEAP_TREE to make it available again
|
||||
*
|
||||
* @param[in] tree The aksl_TreeNode to release. Ensure the leaf on this node has been released and the leaf is set to NULL.
|
||||
*
|
||||
* @throws AKERR_VALUE The aksl_TreeNode contains a leaf that has not been released.
|
||||
* @return akerr_ErrorContext*
|
||||
*/
|
||||
|
||||
akerr_ErrorContext *akgl_heap_release_tree(aksl_TreeNode *tree)
|
||||
{
|
||||
PREPARE_ERROR(e);
|
||||
FAIL_ZERO_RETURN(e, tree, AKERR_NULLPOINTER, "tree");
|
||||
akgl_BSPLeaf *leaf = NULL;
|
||||
tree->left = NULL;
|
||||
tree->right = NULL;
|
||||
tree->parent = NULL;
|
||||
leaf = (akgl_BSPLeaf *)tree->leaf;
|
||||
if ( tree->leaf != NULL && leaf->actors != NULL ) {
|
||||
FAIL_RETURN(e, AKERR_VALUE, "Can't release tree node %p until its leaf actors %p is released and leaf->actors == NULL", tree, leaf->actors);
|
||||
} else if ( tree->leaf != NULL ) {
|
||||
memset((void *)tree->leaf, 0x00, sizeof(akgl_BSPLeaf));
|
||||
}
|
||||
tree->leaf = AKGL_LIST_SENTINEL;
|
||||
SUCCEED_RETURN(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Iterator callback which releases a given list item back to the heap
|
||||
*
|
||||
* @param[in] ptr The aksl_ListNode to free
|
||||
* @param[in] data Context data that was passed to aksl_list_iterate
|
||||
*
|
||||
* @throws AKERR_VALUE The aksl_TreeNode contains a leaf that has not been released.
|
||||
* @return akerr_ErrorContext*
|
||||
*/
|
||||
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_heap_iter_list_release(aksl_ListNode *ptr, void *data)
|
||||
{
|
||||
PREPARE_ERROR(e);
|
||||
FAIL_ZERO_RETURN(e, ptr, AKERR_NULLPOINTER, "ptr)");
|
||||
PASS(e, akgl_heap_release_list(ptr));
|
||||
SUCCEED_RETURN(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Iterator callback which releases a given tree node back to the heap. Calls akgl_heap_release_list on the tree leaf as well.
|
||||
*
|
||||
* @param[in] ptr The aksl_TreeNode to free
|
||||
* @param[in] data Context data that was passed to aksl_tree_iterate
|
||||
*
|
||||
* @return akerr_ErrorContext*
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_heap_iter_tree_release(aksl_TreeNode *ptr, void *data)
|
||||
{
|
||||
PREPARE_ERROR(e);
|
||||
FAIL_ZERO_RETURN(e, ptr, AKERR_NULLPOINTER, "ptr");
|
||||
if ( ptr->leaf != AKGL_LIST_SENTINEL && ptr->leaf != NULL ) {
|
||||
PASS(e, akgl_heap_release_list(ptr->leaf));
|
||||
//ptr->leaf = NULL;
|
||||
}
|
||||
PASS(e, akgl_heap_release_tree(ptr));
|
||||
SUCCEED_RETURN(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the next actor from the heap
|
||||
*
|
||||
* @param[out] dest The pointer that will hold the procured actor
|
||||
*
|
||||
* @throws AKGL_ERR_OOHEAP There are no available actors in HEAP_ACTOR
|
||||
* @return akerr_ErrorContext*
|
||||
*/
|
||||
akerr_ErrorContext *akgl_heap_next_actor(akgl_Actor **dest)
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
@@ -55,9 +223,18 @@ akerr_ErrorContext *akgl_heap_next_actor(akgl_Actor **dest)
|
||||
*dest = &HEAP_ACTOR[i];
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
FAIL_RETURN(errctx, AKERR_HEAP, "Unable to find unused actor on the heap");
|
||||
FAIL_RETURN(errctx, AKGL_ERR_OOHEAP, "Unable to find unused actor on the heap");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the next akgl_Sprite from the heap
|
||||
*
|
||||
* @param[out] dest The pointer that will hold the procured sprite
|
||||
*
|
||||
* @throws AKGL_ERR_OOHEAP There are no available actors in HEAP_SPRITE
|
||||
* @return akerr_ErrorContext*
|
||||
*/
|
||||
|
||||
akerr_ErrorContext *akgl_heap_next_sprite(akgl_Sprite **dest)
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
@@ -68,9 +245,17 @@ akerr_ErrorContext *akgl_heap_next_sprite(akgl_Sprite **dest)
|
||||
*dest = &HEAP_SPRITE[i];
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
FAIL_RETURN(errctx, AKERR_HEAP, "Unable to find unused sprite on the heap");
|
||||
FAIL_RETURN(errctx, AKGL_ERR_OOHEAP, "Unable to find unused sprite on the heap");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the next akgl_SpriteSheet from the heap
|
||||
*
|
||||
* @param[out] dest The pointer that will hold the procured spritesheet
|
||||
*
|
||||
* @throws AKGL_ERR_OOHEAP There are no available elements in HEAP_SPRITESHEET
|
||||
* @return akerr_ErrorContext*
|
||||
*/
|
||||
akerr_ErrorContext *akgl_heap_next_spritesheet(akgl_SpriteSheet **dest)
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
@@ -81,9 +266,18 @@ akerr_ErrorContext *akgl_heap_next_spritesheet(akgl_SpriteSheet **dest)
|
||||
*dest = &HEAP_SPRITESHEET[i];
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
FAIL_RETURN(errctx, AKERR_HEAP, "Unable to find unused spritesheet on the heap");
|
||||
FAIL_RETURN(errctx, AKGL_ERR_OOHEAP, "Unable to find unused spritesheet on the heap");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the next akgl_Character from the heap
|
||||
*
|
||||
* @param[out] dest The pointer that will hold the procured character
|
||||
*
|
||||
* @throws AKGL_ERR_OOHEAP There are no available elements in HEAP_CHARACTER
|
||||
* @return akerr_ErrorContext*
|
||||
*/
|
||||
|
||||
akerr_ErrorContext *akgl_heap_next_character(akgl_Character **dest)
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
@@ -94,9 +288,17 @@ akerr_ErrorContext *akgl_heap_next_character(akgl_Character **dest)
|
||||
*dest = &HEAP_CHARACTER[i];
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
FAIL_RETURN(errctx, AKERR_HEAP, "Unable to find unused character on the heap");
|
||||
FAIL_RETURN(errctx, AKGL_ERR_OOHEAP, "Unable to find unused character on the heap");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the next akgl_String from the heap
|
||||
*
|
||||
* @param[out] dest The pointer that will hold the procured string
|
||||
*
|
||||
* @throws AKGL_ERR_OOHEAP There are no available elements in HEAP_STRING
|
||||
* @return akerr_ErrorContext*
|
||||
*/
|
||||
akerr_ErrorContext *akgl_heap_next_string(akgl_String **dest)
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
@@ -108,9 +310,16 @@ akerr_ErrorContext *akgl_heap_next_string(akgl_String **dest)
|
||||
HEAP_STRING[i].refcount += 1;
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
FAIL_RETURN(errctx, AKERR_HEAP, "Unable to find unused string on the heap");
|
||||
FAIL_RETURN(errctx, AKGL_ERR_OOHEAP, "Unable to find unused string on the heap");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Release an akgl_Actor from the heap to be used again
|
||||
*
|
||||
* @param[in] ptr The object that will be released
|
||||
*
|
||||
* @return akerr_ErrorContext*
|
||||
*/
|
||||
akerr_ErrorContext *akgl_heap_release_actor(akgl_Actor *ptr)
|
||||
{
|
||||
int i = 0;
|
||||
@@ -131,23 +340,37 @@ akerr_ErrorContext *akgl_heap_release_actor(akgl_Actor *ptr)
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
akerr_ErrorContext *akgl_heap_release_character(akgl_Character *basechar)
|
||||
/**
|
||||
* @brief Release an akgl_Character from the heap to be used again
|
||||
*
|
||||
* @param[in] ptr The object that will be released
|
||||
*
|
||||
* @return akerr_ErrorContext*
|
||||
*/
|
||||
akerr_ErrorContext *akgl_heap_release_character(akgl_Character *ptr)
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
akgl_Iterator opflags;
|
||||
FAIL_ZERO_RETURN(errctx, basechar, AKERR_NULLPOINTER, "NULL character reference");
|
||||
FAIL_ZERO_RETURN(errctx, ptr, AKERR_NULLPOINTER, "NULL character reference");
|
||||
AKGL_BITMASK_CLEAR(opflags.flags);
|
||||
|
||||
if ( basechar->refcount > 0 ) {
|
||||
basechar->refcount -= 1;
|
||||
if ( ptr->refcount > 0 ) {
|
||||
ptr->refcount -= 1;
|
||||
}
|
||||
if ( basechar->refcount == 0 ) {
|
||||
SDL_ClearProperty(AKGL_REGISTRY_CHARACTER, (char *)&basechar->name);
|
||||
memset(basechar, 0x00, sizeof(akgl_Character));
|
||||
if ( ptr->refcount == 0 ) {
|
||||
SDL_ClearProperty(AKGL_REGISTRY_CHARACTER, (char *)&ptr->name);
|
||||
memset(ptr, 0x00, sizeof(akgl_Character));
|
||||
}
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Release an akgl_Sprite from the heap to be used again
|
||||
*
|
||||
* @param[in] ptr The object that will be released
|
||||
*
|
||||
* @return akerr_ErrorContext*
|
||||
*/
|
||||
akerr_ErrorContext *akgl_heap_release_sprite(akgl_Sprite *ptr)
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
@@ -162,6 +385,13 @@ akerr_ErrorContext *akgl_heap_release_sprite(akgl_Sprite *ptr)
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Release an akgl_SpriteSheet from the heap to be used again
|
||||
*
|
||||
* @param[in] ptr The object that will be released
|
||||
*
|
||||
* @return akerr_ErrorContext*
|
||||
*/
|
||||
akerr_ErrorContext *akgl_heap_release_spritesheet(akgl_SpriteSheet *ptr)
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
@@ -180,6 +410,13 @@ akerr_ErrorContext *akgl_heap_release_spritesheet(akgl_SpriteSheet *ptr)
|
||||
SUCCEED_RETURN(errctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Release an akgl_String from the heap to be used again
|
||||
*
|
||||
* @param[in] ptr The object that will be released
|
||||
*
|
||||
* @return akerr_ErrorContext*
|
||||
*/
|
||||
akerr_ErrorContext *akgl_heap_release_string(akgl_String *ptr)
|
||||
{
|
||||
PREPARE_ERROR(errctx);
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <akgl/error.h>
|
||||
#include <akgl/heap.h>
|
||||
#include <akgl/registry.h>
|
||||
#include <akgl/stage.h>
|
||||
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_physics_null_gravity(akgl_PhysicsBackend *self, akgl_Actor *actor, float32_t dt)
|
||||
{
|
||||
@@ -64,10 +65,24 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_physics_arcade_gravity(akgl_PhysicsBacke
|
||||
SUCCEED_RETURN(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test two actors for collision
|
||||
*
|
||||
* @param[in] self The physics simulation to use
|
||||
* @param[in] a1 actor 1
|
||||
* @param[in] a2 actor 2
|
||||
*
|
||||
* @throws AKERR_NULLPOINTER on null pointer input
|
||||
*
|
||||
* @return akerr_ErrorContext*
|
||||
*/
|
||||
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_physics_arcade_collide(akgl_PhysicsBackend *self, akgl_Actor *a1, akgl_Actor *a2)
|
||||
{
|
||||
PREPARE_ERROR(e);
|
||||
FAIL_ZERO_RETURN(e, self, AKERR_NULLPOINTER, "self");
|
||||
FAIL_ZERO_RETURN(e, a1, AKERR_NULLPOINTER, "a1");
|
||||
FAIL_ZERO_RETURN(e, a2, AKERR_NULLPOINTER, "a2");
|
||||
FAIL_RETURN(e, AKERR_API, "Not implemented");
|
||||
SUCCEED_RETURN(e);
|
||||
}
|
||||
@@ -77,9 +92,17 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_physics_arcade_move(struct akgl_PhysicsB
|
||||
PREPARE_ERROR(e);
|
||||
FAIL_ZERO_RETURN(e, self, AKERR_NULLPOINTER, "self");
|
||||
FAIL_ZERO_RETURN(e, actor, AKERR_NULLPOINTER, "actor");
|
||||
akgl_Sprite *curspr = NULL;
|
||||
actor->x += actor->vx * dt;
|
||||
actor->y += actor->vy * dt;
|
||||
actor->z += actor->vz * dt;
|
||||
actor->z += actor->vz * dt;
|
||||
// Set the actor's bounding box for physics
|
||||
if ( actor->basechar != NULL ) {
|
||||
PASS(e, actor->basechar->sprite_get(actor->basechar, actor->state, &curspr));
|
||||
actor->bbox = (SDL_FRect){actor->x, actor->y, curspr->width, curspr->height};
|
||||
} else {
|
||||
actor->bbox = (SDL_FRect){actor->x, actor->y, 0, 0};
|
||||
}
|
||||
SUCCEED_RETURN(e);
|
||||
}
|
||||
|
||||
@@ -116,6 +139,17 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_physics_init_arcade(akgl_PhysicsBackend
|
||||
SUCCEED_RETURN(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Perform arcade physics simulation on all alive actors
|
||||
*
|
||||
* @param[in] self Physics simulator object
|
||||
* @param[in] opflags Iteration operation flags (or NULL)
|
||||
*
|
||||
* @throws AKERR_NULLPOINTER on null pointer input
|
||||
*
|
||||
* @return akerr_ErrorContext*
|
||||
*/
|
||||
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_physics_simulate(akgl_PhysicsBackend *self, akgl_Iterator *opflags)
|
||||
{
|
||||
PREPARE_ERROR(e);
|
||||
@@ -189,34 +223,47 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_physics_simulate(akgl_PhysicsBackend *se
|
||||
}
|
||||
ATTEMPT {
|
||||
CATCH(e, actor->movementlogicfunc(actor, dt));
|
||||
PASS(e, self->gravity(self, actor, dt));
|
||||
|
||||
// Counteract velocity with atmospheric drag
|
||||
if ( self->drag_x != 0 ) {
|
||||
actor->ex -= actor->ex * self->drag_x * dt;
|
||||
}
|
||||
if ( self->drag_y != 0 ) {
|
||||
actor->ey -= actor->ey * self->drag_y * dt;
|
||||
}
|
||||
if ( self->drag_z != 0 ) {
|
||||
actor->ez -= actor->ez * self->drag_z * dt;
|
||||
}
|
||||
|
||||
actor->vx = actor->ex + actor->tx;
|
||||
actor->vy = actor->ey + actor->ty;
|
||||
actor->vz = actor->ez + actor->tz;
|
||||
|
||||
PASS(e, self->move(self, actor, dt));
|
||||
} CLEANUP {
|
||||
} PROCESS(e) {
|
||||
} HANDLE(e, AKGL_ERR_LOGICINTERRUPT) {
|
||||
// noop
|
||||
} FINISH(e, true);
|
||||
|
||||
PASS(e, self->gravity(self, actor, dt));
|
||||
|
||||
// Counteract velocity with atmospheric drag
|
||||
if ( self->drag_x != 0 ) {
|
||||
actor->ex -= actor->ex * self->drag_x * dt;
|
||||
}
|
||||
if ( self->drag_y != 0 ) {
|
||||
actor->ey -= actor->ey * self->drag_y * dt;
|
||||
}
|
||||
if ( self->drag_z != 0 ) {
|
||||
actor->ez -= actor->ez * self->drag_z * dt;
|
||||
}
|
||||
|
||||
actor->vx = actor->ex + actor->tx;
|
||||
actor->vy = actor->ey + actor->ty;
|
||||
actor->vz = actor->ez + actor->tz;
|
||||
|
||||
PASS(e, self->move(self, actor, dt));
|
||||
PASS(e, stage->partition_actor(stage, actor));
|
||||
}
|
||||
self->gravity_time = curtime;
|
||||
SUCCEED_RETURN(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize a physics backend according to a string type
|
||||
*
|
||||
* @param[out] self The physics backend to initialize
|
||||
* @param[in] type The type to initialize
|
||||
*
|
||||
* @throws AKERR_NULLPOINTER on null pointer input
|
||||
* @throws AKERR_KEY on invalid type
|
||||
*
|
||||
* @return akerr_ErrorContext*
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_physics_factory(akgl_PhysicsBackend *self, akgl_String *type)
|
||||
{
|
||||
uint32_t hashval;
|
||||
|
||||
373
src/stage.c
Normal file
373
src/stage.c
Normal file
@@ -0,0 +1,373 @@
|
||||
#include <SDL3/SDL.h>
|
||||
#include <akstdlib.h>
|
||||
#include <akgl/stage.h>
|
||||
#include <akgl/actor.h>
|
||||
#include <akgl/heap.h>
|
||||
#include <akgl/game.h>
|
||||
|
||||
/**
|
||||
* @brief Initialize a 2D stage
|
||||
*
|
||||
* @param[in] self akgl_Stage * to initialize
|
||||
*
|
||||
* @throw AKERR_NULLPOINTER on null input pointers
|
||||
* @return akerr_ErrorContext
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_stage_2d(akgl_Stage *self)
|
||||
{
|
||||
PREPARE_ERROR(e);
|
||||
FAIL_ZERO_RETURN(e, self, AKERR_NULLPOINTER, "self");
|
||||
memset((void *)self, 0x00, sizeof(akgl_Stage));
|
||||
self->partition = akgl_stage_2d_partition;
|
||||
self->partition_actor = akgl_stage_2d_bsp_move;
|
||||
memset((void *)&self->bsp, 0x00, sizeof(aksl_TreeNode));
|
||||
self->bsp.leaf = &self->_rootleaf;
|
||||
memset((void *)&self->_rootleaf, 0x00, sizeof(akgl_BSPLeaf));
|
||||
SUCCEED_RETURN(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Flip the current partitioning direction
|
||||
*
|
||||
* @param[in] One of AKGL_STAGE_PARTITION_HORIZONTAL or AKGL_STAGE_PARTITION_VERTICAL
|
||||
* @param[out] dest Location to place the modified direction
|
||||
*
|
||||
* @throws AKERR_NULLPOINTER on null pointer inputs
|
||||
* @throws AKERR_VALUE on invalid direction
|
||||
* @return akerr_ErrorContext*
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_stage_2d_partition_switchdirection(uint8_t direction, uint8_t *dest)
|
||||
{
|
||||
PREPARE_ERROR(e);
|
||||
FAIL_ZERO_RETURN(e, dest, AKERR_NULLPOINTER, "dest");
|
||||
if ( direction == AKGL_STAGE_PARTITION_HORIZONTAL ) {
|
||||
*dest = AKGL_STAGE_PARTITION_VERTICAL;
|
||||
} else if ( direction == AKGL_STAGE_PARTITION_VERTICAL ) {
|
||||
*dest = AKGL_STAGE_PARTITION_HORIZONTAL;
|
||||
} else {
|
||||
FAIL_RETURN(e, AKERR_VALUE, "Unknown partition direction %d", direction);
|
||||
}
|
||||
SUCCEED_RETURN(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Iterator function that sorts an actor into one of three lists based on colliding rectangles
|
||||
*
|
||||
* This function tests which of two rectangles ("left" and "right") in the context collide with the actor.
|
||||
* The actor is sorted into the appropriate linked list for each given rectangle.
|
||||
* If the actor collides with neither rectangle, it is pushed onto the parent list.
|
||||
* Note that the existing node is not pushed - a new node is taken from the heap and pushed.
|
||||
* Otherwise we would have to pop the actor out of whatever list it was in, which would
|
||||
* modify the list during iteration.
|
||||
*
|
||||
* @param[in] node A list node containing an akgl_Actor in ->data
|
||||
* @param[in] data A pointer to akgl_BSPContext containing left, right, and parent SDL_FRect structures
|
||||
*
|
||||
* @throws AKERR_NULLPOINTER on null pointer inputs
|
||||
* @return akerr_ErrorContext*
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_stage_2d_bsp_actoriter(aksl_ListNode *node, void *data)
|
||||
{
|
||||
bool e1intersect;
|
||||
bool e2intersect;
|
||||
akgl_BSPContext *context = NULL;
|
||||
akgl_Actor *actor = NULL;
|
||||
aksl_TreeNode *dest = NULL;
|
||||
aksl_ListNode *newnode = NULL;
|
||||
akgl_BSPLeaf *leaf = NULL;
|
||||
|
||||
PREPARE_ERROR(e);
|
||||
FAIL_ZERO_RETURN(e, node, AKERR_NULLPOINTER, "node");
|
||||
FAIL_ZERO_RETURN(e, data, AKERR_NULLPOINTER, "data");
|
||||
FAIL_ZERO_RETURN(e, node->data, AKERR_NULLPOINTER, "node->data");
|
||||
context = (akgl_BSPContext *)data;
|
||||
actor = (akgl_Actor *)node->data;
|
||||
|
||||
FAIL_ZERO_RETURN(e, context->left, AKERR_NULLPOINTER, "left");
|
||||
FAIL_ZERO_RETURN(e, context->right, AKERR_NULLPOINTER, "right");
|
||||
FAIL_ZERO_RETURN(e, context->parent, AKERR_NULLPOINTER, "parent");
|
||||
FAIL_ZERO_RETURN(e, ((akgl_BSPLeaf *)context->left->leaf)->actors, AKERR_NULLPOINTER, "left->leaf");
|
||||
FAIL_ZERO_RETURN(e, ((akgl_BSPLeaf *)context->right->leaf)->actors, AKERR_NULLPOINTER, "right->leaf");
|
||||
FAIL_ZERO_RETURN(e, ((akgl_BSPLeaf *)context->parent->leaf)->actors, AKERR_NULLPOINTER, "parent->leaf");
|
||||
|
||||
|
||||
leaf = (akgl_BSPLeaf *)context->left->leaf;
|
||||
e1intersect = SDL_HasRectIntersectionFloat(&leaf->extent, &actor->bbox);
|
||||
leaf = (akgl_BSPLeaf *)context->right->leaf;
|
||||
e2intersect = SDL_HasRectIntersectionFloat(&leaf->extent, &actor->bbox);
|
||||
|
||||
if ( e1intersect && e2intersect ) {
|
||||
// Actors who cross left/right boundaries get left in the context of their parent, so both
|
||||
// child spaces test them for collision
|
||||
dest = context->parent;
|
||||
} else if ( e1intersect ) {
|
||||
dest = context->left;
|
||||
} else if ( e2intersect ) {
|
||||
dest = context->right;
|
||||
}
|
||||
|
||||
if ( dest != NULL ) {
|
||||
PASS(e, akgl_heap_next_list(&newnode));
|
||||
newnode->data = node->data;
|
||||
leaf = (akgl_BSPLeaf *)dest->leaf;
|
||||
PASS(e, aksl_list_push(leaf->actors, newnode));
|
||||
actor->bsphome = dest;
|
||||
actor->bsplistnode = newnode;
|
||||
}
|
||||
|
||||
SUCCEED_RETURN(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Recursive function used to divide the stage into a BSP tree of actor near neighbors
|
||||
*
|
||||
* This is a recursive function that builds a balanced tree until the tree is maxdepth levels deep.
|
||||
* It creates a list of all actors which fit within the extents of the root node,
|
||||
* then successively divides that actor list down into the extents of the child nodes of the balanced tree,
|
||||
* until the maximum recursion depth has been achieved.
|
||||
*
|
||||
* @param[in] root The root node of the current level of the tree
|
||||
* @param[in] actors The list of all actors that are within the root node's extents
|
||||
* @param[in] extents The {x, y, w, h} extents of this level of the tree
|
||||
* @param[in] direction The AKL_STAGE_PARTITION_* direction in which the extent is being divided
|
||||
* @param[in] depth The depth of the current root node. Callers should provide 1 here.
|
||||
* @param[in] maxdepth The maximum depth to which we should recurse
|
||||
*
|
||||
* @throws AKERR_VALUE Invalid direction provided
|
||||
*
|
||||
* @return akerr_ErrorContext*
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_stage_2d_bsp(aksl_TreeNode *root, aksl_ListNode *actors, SDL_FRect extents, uint8_t direction, uint8_t depth, uint8_t maxdepth)
|
||||
{
|
||||
akgl_BSPContext context = {0, 0, 0};
|
||||
akgl_BSPLeaf *leaf = NULL;
|
||||
|
||||
// Until we have reached maxdepth levels of depth
|
||||
PREPARE_ERROR(e);
|
||||
if ( depth > maxdepth ) {
|
||||
SUCCEED_RETURN(e);
|
||||
}
|
||||
|
||||
// - Get a pointer to the left and right nodes of the tree representing the halves
|
||||
// - Divide the current working space into two equal halves
|
||||
// - Construct a SDL_FRect representing the two equal halves
|
||||
// (the top half of a vertical division is "left", bottom half is "right")
|
||||
if ( root->left == NULL ) {
|
||||
PASS(e, akgl_heap_next_tree((aksl_TreeNode **)&root->left));
|
||||
PASS(e, akgl_heap_next_list((aksl_ListNode **)&((akgl_BSPLeaf *)root->left->leaf)->actors));
|
||||
root->left->parent = root;
|
||||
leaf = root->left->leaf;
|
||||
if ( direction == AKGL_STAGE_PARTITION_HORIZONTAL ) {
|
||||
leaf->extent.x = extents.x;
|
||||
leaf->extent.y = extents.y;
|
||||
leaf->extent.w = extents.w;
|
||||
leaf->extent.h = (extents.h / 2);
|
||||
} else if ( direction == AKGL_STAGE_PARTITION_VERTICAL ) {
|
||||
leaf->extent.x = extents.x;
|
||||
leaf->extent.y = extents.y;
|
||||
leaf->extent.w = (extents.w / 2);
|
||||
leaf->extent.h = extents.h;
|
||||
} else {
|
||||
FAIL_RETURN(e, AKERR_VALUE, "Invalid partition direction %d", direction);
|
||||
}
|
||||
}
|
||||
if ( root->right == NULL ) {
|
||||
PASS(e, akgl_heap_next_tree((aksl_TreeNode **)&root->right));
|
||||
PASS(e, akgl_heap_next_list((aksl_ListNode **)&((akgl_BSPLeaf *)root->right->leaf)->actors));
|
||||
root->right->parent = root;
|
||||
leaf = root->right->leaf;
|
||||
if ( direction == AKGL_STAGE_PARTITION_HORIZONTAL ) {
|
||||
leaf->extent.x = extents.x;
|
||||
leaf->extent.y = extents.y + (extents.h / 2);
|
||||
leaf->extent.w = extents.w;
|
||||
leaf->extent.h = (extents.h / 2);
|
||||
} else if ( direction == AKGL_STAGE_PARTITION_VERTICAL ) {
|
||||
leaf->extent.x = extents.x + (extents.w / 2);
|
||||
leaf->extent.y = extents.y;
|
||||
leaf->extent.w = (extents.w / 2);
|
||||
leaf->extent.h = extents.h;
|
||||
} else {
|
||||
FAIL_RETURN(e, AKERR_VALUE, "Invalid partition direction %d", direction);
|
||||
}
|
||||
}
|
||||
if ( ((akgl_BSPLeaf *)root->leaf)->actors == NULL ) {
|
||||
PASS(e, akgl_heap_next_list((aksl_ListNode **)&((akgl_BSPLeaf *)root->leaf)->actors));
|
||||
}
|
||||
context.left = root->left;
|
||||
context.right = root->right;
|
||||
context.parent = root;
|
||||
|
||||
// - Test (SDL_HasIntersection) all actor objects in the current working space
|
||||
// against the SDL_Frects for both halves. If they intersect, push the actors
|
||||
// down into the leaf linked lists for each half
|
||||
ATTEMPT {
|
||||
CATCH(e, aksl_list_iterate(actors, &akgl_stage_2d_bsp_actoriter, &context));
|
||||
} CLEANUP {
|
||||
} PROCESS(e) {
|
||||
} HANDLE(e, AKERR_NULLPOINTER) {
|
||||
SDL_Log("Empty actor list");
|
||||
} FINISH(e, true);
|
||||
|
||||
PASS(e, akgl_stage_2d_partition_switchdirection(direction, &direction));
|
||||
// - Recurse down into the left BSP node, changing our partitioning
|
||||
// (vertical->horizontal, horizontal->vertical etc)
|
||||
PASS(e, akgl_stage_2d_bsp(root->left, ((akgl_BSPLeaf *)root->left->leaf)->actors, ((akgl_BSPLeaf *)context.left->leaf)->extent, direction, depth + 1, maxdepth));
|
||||
// - Recurse down into the right BSP node
|
||||
// (vertical->horizontal, horizontal->vertical etc)
|
||||
PASS(e, akgl_stage_2d_bsp(root->right, ((akgl_BSPLeaf *)root->right->leaf)->actors, ((akgl_BSPLeaf *)context.right->leaf)->extent, direction, depth + 1, maxdepth));
|
||||
|
||||
SUCCEED_RETURN(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Release the stage's curent BSP tree
|
||||
*
|
||||
* This recursive function traverses down all nodes of the stage's BSP tree and release all the tree and list nodes
|
||||
*
|
||||
* @param[in] self The stage whose BSP tree should be freed
|
||||
*
|
||||
* @throws AKERR_NULLPOINTER on NULL pointer inputs
|
||||
*
|
||||
* @return akerr_ErrorContext*
|
||||
*/
|
||||
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_stage_2d_bspfree(akgl_Stage *self)
|
||||
{
|
||||
PREPARE_ERROR(e);
|
||||
FAIL_ZERO_RETURN(e, self, AKERR_NULLPOINTER, "self");
|
||||
PASS(e, aksl_tree_iterate(&self->bsp, &akgl_heap_iter_tree_release, NULL, NULL, AKSL_TREE_SEARCH_DFS, NULL, NULL));
|
||||
SUCCEED_RETURN(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Partition the stage into a BSP tree, grouping near neighbor actors together
|
||||
*
|
||||
* @param[in] self The stage to partition
|
||||
*
|
||||
* @return akerr_ErrorContext*
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_stage_2d_partition(akgl_Stage *self)
|
||||
{
|
||||
aksl_ListNode *actors = NULL;
|
||||
aksl_ListNode *curnode = NULL;
|
||||
PREPARE_ERROR(e);
|
||||
FAIL_ZERO_RETURN(e, self, AKERR_NULLPOINTER, "self");
|
||||
|
||||
PASS(e, akgl_stage_2d_bspfree(self));
|
||||
|
||||
self->bsp.leaf = &self->_rootleaf;
|
||||
memset((void *)&self->_rootleaf, 0x00, sizeof(akgl_BSPLeaf));
|
||||
|
||||
// Build a linked list of all actors currently initialized
|
||||
PASS(e, akgl_heap_next_list(&actors));
|
||||
curnode = actors;
|
||||
for ( int i = 0; i < AKGL_MAX_HEAP_ACTOR; i++ ) {
|
||||
if ( HEAP_ACTOR[i].refcount != 0 ) {
|
||||
curnode->data = (void *)&HEAP_ACTOR[i];
|
||||
PASS(e, akgl_heap_next_list(&curnode->next));
|
||||
curnode = curnode->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* This could be better.
|
||||
* Right now we divide the extents into 16 equal rectangles and sort actors
|
||||
* into them by their bbox coordinates. This doesn't help when lots of actors are
|
||||
* stacked up unequally on one area of the screen. A better solution might be to
|
||||
* continue subdividing a given extent until it is small enough that only
|
||||
* N number of actors fit inside of it. All of this is overkill for something like
|
||||
* a simple Mario style sidescroller or even a JRPG, but for something like
|
||||
* a bullet hell, it will be essential.
|
||||
*/
|
||||
((akgl_BSPLeaf *)self->bsp.leaf)->extent = (SDL_FRect){0, 0, camera->w, camera->h};
|
||||
ATTEMPT {
|
||||
CATCH(e, akgl_stage_2d_bsp(
|
||||
&self->bsp,
|
||||
actors,
|
||||
// Define the current working space as the boundaries of the entire stage
|
||||
// (from the origin to the extents of the largest and/or furthest object)
|
||||
// .... let's see what we get if we just cheat and use the camera extents.
|
||||
// (Do we *really* want off-screen objects in the collision detection?)
|
||||
(SDL_FRect){0.0, 0.0, camera->w, camera->h},
|
||||
// Define if we are partitioning horizontally or vertically
|
||||
AKGL_STAGE_PARTITION_VERTICAL,
|
||||
// Begin depth counter at 1
|
||||
1,
|
||||
// Maximum recursion depth
|
||||
AKGL_STAGE_PARTITION_MAXDEPTH)
|
||||
);
|
||||
} CLEANUP {
|
||||
PREPARE_ERROR(e2);
|
||||
PASS(e2, aksl_list_iterate(actors, &akgl_heap_iter_list_release, NULL));
|
||||
} PROCESS(e) {
|
||||
} FINISH(e, true);
|
||||
|
||||
SUCCEED_RETURN(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Move this actor to the correct part of the BSP tree
|
||||
*
|
||||
* @param[in] self akgl_Stage *
|
||||
* @param[in] actor akgl_Actor *
|
||||
*
|
||||
* @throws AKERR_NULLPOINTER on null pointer inputs
|
||||
* @return akerr_ErrorContext
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_stage_2d_bsp_move(akgl_Stage *self, akgl_Actor *actor)
|
||||
{
|
||||
aksl_ListNode *tmp = NULL;
|
||||
aksl_TreeNode *curnode = NULL;
|
||||
akgl_BSPContext context;
|
||||
PREPARE_ERROR(e);
|
||||
FAIL_ZERO_RETURN(e, self, AKERR_NULLPOINTER, "self");
|
||||
FAIL_ZERO_RETURN(e, actor, AKERR_NULLPOINTER, "actor");
|
||||
if ( actor->bsphome == NULL ) {
|
||||
// New actor that is not currently part of the BSP tree. Push it down.
|
||||
PASS(e, akgl_heap_next_list(&tmp));
|
||||
tmp->data = actor;
|
||||
ATTEMPT {
|
||||
PASS(e, akgl_stage_2d_bsp(
|
||||
&self->bsp,
|
||||
tmp,
|
||||
(SDL_FRect){0.0, 0.0, camera->w, camera->h},
|
||||
AKGL_STAGE_PARTITION_VERTICAL,
|
||||
1,
|
||||
AKGL_STAGE_PARTITION_MAXDEPTH)
|
||||
);
|
||||
} CLEANUP {
|
||||
PREPARE_ERROR(e2);
|
||||
PASS(e2, akgl_heap_release_list(tmp));
|
||||
} PROCESS(e) {
|
||||
} FINISH(e, true);
|
||||
} else {
|
||||
// Actor already exists somewhere in the BSP tree
|
||||
// 1. Is it still in the extents for its bsphome? If so, do nothing.
|
||||
if ( SDL_HasRectIntersectionFloat(&((akgl_BSPLeaf *)actor->bsphome->leaf)->extent, &actor->bbox) ) {
|
||||
SUCCEED_RETURN(e);
|
||||
}
|
||||
// 2. If not, pop the actor out of its current BSP actor list, and start walking up.
|
||||
PASS(e, aksl_list_pop(actor->bsplistnode));
|
||||
curnode = actor->bsphome->parent;
|
||||
tmp = actor->bsplistnode;
|
||||
while ( curnode != NULL ) {
|
||||
// 3. Is it within the current BSP node's extents? If not, walk up and repeat.
|
||||
if ( SDL_HasRectIntersectionFloat(&((akgl_BSPLeaf *)curnode->leaf)->extent, &actor->bbox) ) {
|
||||
// 4. Find which extent it matches.
|
||||
// FIXME : akgl_BSPContext should be replaced with aksl_TreeNode at this point, it's fully redundant
|
||||
context.left = curnode->left;
|
||||
context.right = curnode->right;
|
||||
context.parent = curnode->parent;
|
||||
PASS(e, akgl_stage_2d_bsp_actoriter(actor->bsplistnode, &context));
|
||||
}
|
||||
curnode = curnode->parent;
|
||||
}
|
||||
// Release the old actor node, it will have been moved to a new one by now
|
||||
if ( tmp == actor->bsplistnode ) {
|
||||
// Odd ...
|
||||
SDL_Log("Expected actor %p to be moved to a different BSP node after moving, but it still has the same list node...\n", actor);
|
||||
} else {
|
||||
PASS(e, akgl_heap_release_list(tmp));
|
||||
}
|
||||
}
|
||||
SUCCEED_RETURN(e);
|
||||
}
|
||||
Reference in New Issue
Block a user