initial commit

This commit is contained in:
Lephenixnoir 2024-03-10 00:28:30 +01:00
commit 84fea18624
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
10 changed files with 316 additions and 0 deletions

14
.gitignore vendored Normal file
View File

@ -0,0 +1,14 @@
# Build files
/build-fx
/build-cg
/build-cg-push
/*.g1a
/*.g3a
# Python bytecode
__pycache__/
# Common IDE files
*.sublime-project
*.sublime-workspace
.vscode

37
CMakeLists.txt Normal file
View File

@ -0,0 +1,37 @@
# Configure with [fxsdk build-fx] or [fxsdk build-cg], which provide the
# toolchain file and module path of the fxSDK
cmake_minimum_required(VERSION 3.15)
project(MyAddin LANGUAGES C CXX)
include(GenerateG1A)
include(GenerateG3A)
include(Fxconv)
find_package(Gint 2.9 REQUIRED)
find_package(Azur 0.1 REQUIRED)
set(CMAKE_CXX_STANDARD 20)
set(SOURCES
src/main.cc)
set(ASSETS
assets/map1.txt)
set(ASSETS_fx
)
set(ASSETS_cg
)
fxconv_declare_converters(converters.py)
fxconv_declare_assets(${ASSETS} ${ASSETS_fx} ${ASSETS_cg} WITH_METADATA)
add_executable(myaddin ${SOURCES} ${ASSETS} ${ASSETS_${FXSDK_PLATFORM}})
target_compile_options(myaddin PRIVATE -Wall -Wextra -Os)
target_link_libraries(myaddin Azur::Azur -lnum Gint::Gint -lstdc++)
if("${FXSDK_PLATFORM_LONG}" STREQUAL fx9860G)
generate_g1a(TARGET myaddin OUTPUT "Azuray.g1a"
NAME "Azuray" ICON assets-fx/icon.png)
elseif("${FXSDK_PLATFORM_LONG}" STREQUAL fxCG50)
generate_g3a(TARGET myaddin OUTPUT "Azuray.g3a"
NAME "Azuray" ICONS assets-cg/icon-uns.png assets-cg/icon-sel.png)
endif()

BIN
assets-cg/icon-cg.xcf Normal file

Binary file not shown.

BIN
assets-cg/icon-sel.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

BIN
assets-cg/icon-uns.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
assets-fx/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

View File

@ -0,0 +1,3 @@
map*.txt:
custom-type: map
name_regex: map(.*)\.txt map_\1

7
assets/map1.txt Normal file
View File

@ -0,0 +1,7 @@
#########
# # #
###
#
# #
## ##
#########

36
converters.py Normal file
View File

@ -0,0 +1,36 @@
import fxconv
def convert(input, output, params, target):
recognized = True
if params["custom-type"] == "map":
o = convert_map(input, params)
if recognized:
fxconv.elf(o, output, "_" + params["name"], **target)
return 0
return 1
def convert_map(input, params):
with open(input, "r") as fp:
lines = fp.read().strip().splitlines()
w = max(len(line) for line in lines)
h = len(lines)
def at(line, x):
if x >= len(line):
return 0
return 1 if line[x] == "#" else 0
cells = bytes()
for y in range(h):
for x in range(w):
cells += bytes([ at(lines[y], x) ])
s = fxconv.Structure()
s += fxconv.u16(w)
s += fxconv.u16(h)
s += fxconv.ptr(cells)
return s

219
src/main.cc Normal file
View File

@ -0,0 +1,219 @@
#define __BSD_VISIBLE 1
#include <gint/display.h>
#include <gint/keyboard.h>
#include <gint/defs/util.h>
#include <gint/gint.h>
#include <num/num.h>
#include <num/vec.h>
#include <math.h>
using namespace libnum;
using ivec2 = vec<int,2>;
/*** Raycasting tools ***/
typedef uint8_t map_cell_t;
typedef struct
{
/* Dimensions, columns are 0 to width-1, rows are 0 to height-1 */
uint16_t width, height;
/* Tileset base (first layer), tileset decor (second layer) */
// tileset_t *tileset;
/* All cells */
map_cell_t *cells;
} map_t;
map_cell_t *map_cell(map_t const *m, int x, int y)
{
if((unsigned)x >= m->width || (unsigned)y >= m->height)
return NULL;
return &m->cells[y * m->width + x];
}
static int num_ifloor_along(num x, num dir)
{
x.v -= (dir < 0);
return x.ifloor();
}
static num num_frac_roundup(num x)
{
x.v--;
x = x.frac();
x.v++;
return x;
}
static num num_max_epsilon(num x)
{
x.v += (x.v == 0);
return x;
}
bool raycast_clear(map_t const *map, vec2 start, vec2 end, vec2 *collision,
ivec2 *collision_cell)
{
vec2 u = { end.x - start.x, end.y - start.y };
if(u.x == 0 && u.y == 0) return true;
num inv_ux = (u.x != 0) ? num(1) / u.x : 0;
num inv_uy = (u.y != 0) ? num(1) / u.y : 0;
/* Current point is [start + t*u]; when t = 1, we've reached [end] */
num t = num(0);
while(t < num(1)) {
num x = start.x + t * u.x;
num y = start.y + t * u.y;
/* Re-check current cell to avoid diagonal clips, where we change tiles
diagonally in a single step (which happens quite often when snapping
to points with integer or half-integer coordinates as things align
perfectly) */
int current_x = num_ifloor_along(x, u.x);
int current_y = num_ifloor_along(y, u.y);
map_cell_t *cell = map_cell(map, current_x, current_y);
if(!cell)
return true;
if(*cell) {
*collision = (vec2){ x, y };
*collision_cell = (ivec2){ current_x, current_y };
return false;
}
/* Distance to the next horizontal, and vertical line */
num dist_y = (u.y >= 0) ? num(1) - y.frac() : -num_frac_roundup(y);
num dist_x = (u.x >= 0) ? num(1) - x.frac() : -num_frac_roundup(x);
/* Increase in t that would make us hit a horizontal line */
num dty = dist_y * inv_uy;
num dtx = dist_x * inv_ux;
int next_x = current_x;
int next_y = current_y;
/* Move to the next point */
if(u.x == 0 || (u.y != 0 && dty <= dtx)) {
/* Make sure we don't get stuck, at all costs */
t += num_max_epsilon(dty);
next_y += (u.y >= 0 ? 1 : -1);
}
else {
t += num_max_epsilon(dtx);
next_x += (u.x >= 0 ? 1 : -1);
}
if(t > num(1)) break;
cell = map_cell(map, next_x, next_y);
if(!cell)
return true;
if(*cell) {
num x = start.x + t * u.x;
num y = start.y + t * u.y;
*collision = (vec2){ x, y };
*collision_cell = (ivec2){ next_x, next_y };
return false;
}
}
return true;
}
//---
extern map_t const map_1;
static int cell_x(int x)
{
return 16 * x + 32;
}
static int cell_y(int y)
{
return 16 * y + 32;
}
static ivec2 map_coord_to_pixel_coord(vec2 pos)
{
ivec2 result;
result.x = (16 * pos.x).ifloor() + 32;
result.y = (16 * pos.y).ifloor() + 32;
return result;
}
static int cell_color(int cellx, int celly)
{
int r = (7 * cellx + 31 * celly) % 24;
int g = (4 * cellx - 9 * celly) % 24;
int b = (17 * cellx + celly / 2) % 24;
return C_RGB(r & 0x1f, g & 0x1f, b & 0x1f);
}
void draw_map(map_t const *M, vec2 camera)
{
for(int y = 0; y < M->height; y++)
for(int x = 0; x < M->width; x++) {
int px = cell_x(x);
int py = cell_y(y);
map_cell_t *cell = map_cell(M, x, y);
if(!cell || !*cell)
continue;
drect(px, py, px+15, py+15, cell_color(x, y));
}
for(int i = 0; i < 32; i++) {
/* Bunch of angles */
float s, c, alpha = i * (2 * M_PI) / 32;
sincosf(alpha, &s, &c);
vec2 end;
end.x = camera.x + num(c) * 20;
end.y = camera.y + num(s) * 20;
vec2 collision;
ivec2 collision_cell;
if(raycast_clear(M, camera, end, &collision, &collision_cell))
continue;
ivec2 s1 = map_coord_to_pixel_coord(camera);
ivec2 s2 = map_coord_to_pixel_coord(collision);
int color = cell_color(collision_cell.x, collision_cell.y);
dline(s1.x, s1.y, s2.x, s2.y, color);
}
dupdate();
}
int main(void)
{
map_t const *M = &map_1;
vec2 camera;
camera.x = num(4.5);
camera.y = num(3.5);
while(1) {
dclear(C_WHITE);
draw_map(M, camera);
dupdate();
cleareventflips();
clearevents();
if(keydown(KEY_RIGHT))
camera.x = min(camera.x + num(0.2), num(M->width));
if(keydown(KEY_LEFT))
camera.x = max(camera.x - num(0.2), num(0));
if(keydown(KEY_DOWN))
camera.y = min(camera.y + num(0.2), num(M->height));
if(keydown(KEY_UP))
camera.y = max(camera.y - num(0.2), num(0));
if(keypressed(KEY_MENU))
gint_osmenu();
if(keypressed(KEY_EXIT))
break;
}
return 0;
}