level 1-1 but no death

This commit is contained in:
Lephenixnoir 2023-04-23 13:49:12 +02:00
parent 39310e7e2e
commit b9067833bc
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
9 changed files with 273 additions and 17 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
__pycache__
/build-*/
*.g3a
*.mp4

View File

@ -15,8 +15,9 @@ set(ASSETS)
if(AZUR_PLATFORM STREQUAL gint)
list(APPEND SOURCES
src/backend/gint/shader.cc)
# list(APPEND ASSETS
# ...)
list(APPEND ASSETS
assets/font.png
assets/1_1.txt)
endif()
if(AZUR_PLATFORM STREQUAL linux)
@ -40,6 +41,7 @@ if(AZUR_PLATFORM STREQUAL gint)
find_package(Gint 2.10 REQUIRED)
find_package(LibProf 2.4 REQUIRED)
include(Fxconv)
fxconv_declare_converters(converters.py)
fxconv_declare_assets(${ASSETS} WITH_METADATA)
target_link_libraries(chaos-drop Azur::Azur LibProf::LibProf Gint::Gint -lm)

21
assets/1_1.txt Normal file
View File

@ -0,0 +1,21 @@
name: 1-1
finish: 66
1-3: text "Welcome to the drop!\n"
4-8: text "I know you have\nmany questions.\n\nDon't ask them. We're busy."
9-13: text "Use the arrow keys to move."
20-24: text "Red bad.\nDon't touch the red stuff."
26: plane DAMAGE 0b10001'10001'10001'10001'10001
30: plane DAMAGE 0b11111'10001'10001'10001'11111
34: plane DAMAGE 0b11100'11100'11100'00000'00000
38: plane DAMAGE 0b11100'11000'10001'00011'00111
42-44: text "Be careful!"
46: plane DAMAGE 0b11100'11100'11100'11100'11100
48: plane DAMAGE 0b00000'00000'11111'11111'11111
50: plane DAMAGE 0b00111'00111'00111'00111'00111
52: plane DAMAGE 0b11111'11111'11111'00000'00000
56-60: text "Nice job.\n\nDon't worry, I'll teach you\nfrom the ground up."
62-64: text "Get it? The ground. Haha."

BIN
assets/font.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@ -0,0 +1,8 @@
*.png:
name_regex: (.*)\.png img_\1
type: bopti-image
profile: p8_rgb565a
*.txt:
name_regex: (.*)\.txt level_\1
custom-type: level

121
converters.py Normal file
View File

@ -0,0 +1,121 @@
import fxconv
import re
def convert(input, output, params, target):
recognized = True
if params["custom-type"] == "level":
o = convert_level(input, params)
else:
recognized = False
if recognized:
fxconv.elf(o, output, "_" + params["name"], **target)
return 0
return 1
def num(value):
return fxconv.u32(value * 65536)
def convert_level(input, params):
RE_VALUES = {
"name": re.compile(r'.*'),
"finish": re.compile(r'\d+')
}
RE_ELEMENTS = {
"mirror": (True, re.compile(r'')),
"plane": (False, re.compile(r'([A-Z]+)\s+(\S+)')),
"text": (True, re.compile(r'\"([^"]+)\"')),
}
RE_POSITION = re.compile(r'(\d+)(?:-(\d+))?')
header = dict()
elements = []
with open(input, "r") as fp:
lines = [l for l in fp.read().splitlines() if l
and not l.startswith("#")]
for i, l in enumerate(lines):
if ":" not in l:
raise fxconv.FxconvError(f"invalid line '{l}': no ':'")
key, value = [x.strip() for x in l.split(":", 1)]
m_pos = RE_POSITION.fullmatch(key)
if m_pos:
start = int(m_pos[1])
end = int(m_pos[2]) if m_pos[2] else None
things = [x.strip() for x in value.strip().split(" ", 1)]
if len(things) == 1:
key, value = things[0], ""
else:
key, value = things
if key not in RE_ELEMENTS:
raise fxconv.FxconvError(f"unknown element '{key}'")
if RE_ELEMENTS[key][0] and end is None:
raise fxconv.FxconvError(f"'{key}' needs an end position")
if not RE_ELEMENTS[key][0] and end is not None:
raise fxconv.FxconvError(f"'{key}' needs no end position")
m = RE_ELEMENTS[key][1].fullmatch(value)
if not m:
raise fxconv.FxconvError(
f"invalid value for '{key}': '{value}")
elements.append((key, start, end, m))
else:
if key not in RE_VALUES:
raise fxconv.FxconvError(f"unknown key '{key}'")
if not RE_VALUES[key].fullmatch(value):
raise fxconv.FxconvError(
f"invalid value for '{key}': '{value}'")
header[key] = value
mirrors = fxconv.ObjectData()
planes = fxconv.ObjectData()
texts = fxconv.ObjectData()
mirror_count = 0
plane_count = 0
text_count = 0
for (key, start, end, m) in elements:
if key == "mirror":
mirrors += num(start * 32)
mirrors += num(end * 32)
mirror_count += 1
elif key == "plane":
kind = m[1]
shape = m[2]
assert shape.startswith("0b")
shape = "".join(c for c in shape[2:] if c != "'")
assert(len(shape) == 25)
kinds = {
"DAMAGE": 0,
"ARROW": 1,
}
assert kind in kinds
planes += num(start * 32)
planes += fxconv.u32(int(shape, 2))
planes += fxconv.u16(kinds[kind])
planes += fxconv.u16(0) # TODO: Arrow directions
plane_count += 1
elif key == "text":
string = m[1].replace("\\n", "\n").replace("\\\\", "\\")
texts += num(start * 32)
texts += num(end * 32)
texts += fxconv.string(string)
text_count += 1
o = fxconv.ObjectData()
o += fxconv.string(header.get("name", "<Untitled>"))
o += num(int(header["finish"]) * 32)
o += fxconv.u32(mirror_count)
o += fxconv.ptr(mirrors)
o += fxconv.u32(plane_count)
o += fxconv.ptr(planes)
o += fxconv.u32(text_count)
o += fxconv.ptr(texts)
return o

View File

@ -68,6 +68,9 @@ struct element_text {
};
struct level {
char const *name;
num finish;
int mirror_count;
struct element_mirror *mirrors;

View File

@ -1,5 +1,6 @@
#define __BSD_VISIBLE 1
#include <azur/azur.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "chaos-drop.h"
@ -90,6 +91,17 @@ static void platform_render(void)
SDL_GL_SwapWindow(window);
}
static void draw_text(int x, int y, char const *str, int size)
{
// TODO: SDL: Text rendering
}
static int text_size(char const *str, int length)
{
// TODO: SDL: Text rendering
return 0;
}
#elif defined(AZUR_TOOLKIT_GINT)
#include <azur/gint/render.h>
@ -135,6 +147,7 @@ static void init(void)
prof_init();
azrp_config_scale(2);
cd_raytrace_configure();
azrp_shader_image_p8_configure();
}
static void quit(void)
@ -142,6 +155,46 @@ static void quit(void)
prof_quit();
}
static uint8_t const font_glyph_width[96] = {
3,1,3,5,5,4,5,2,2,2,3,5,2,5,2,3,
4,4,4,4,4,4,4,4,4,4,2,2,3,4,3,4,
5,4,4,4,4,4,4,4,4,1,4,4,4,5,4,4,
4,4,4,4,5,4,5,5,5,5,4,2,3,2,5,4,
2,4,4,4,4,4,4,4,4,1,2,4,3,5,4,4,
4,4,4,4,4,4,5,5,5,4,4,3,1,3,5,4,
};
/* Very bad text renderer */
static void draw_text(int x, int y, char const *str, int size)
{
extern bopti_image_t img_font;
for(int i = 0; str[i] && i < size; i++) {
if(str[i] < 32 || str[i] >= 0x7f)
continue;
int row = (str[i] - 32) >> 4;
int col = (str[i] - 32) & 15;
int gw = font_glyph_width[str[i] - 32];
azrp_subimage(x, y, &img_font, 7 * col + 1, 9 * row + 1, gw, 8,
DIMAGE_NONE);
x += gw + 1;
}
}
static int text_size(char const *str, int length)
{
int total = 0;
for(int i = 0; str[i] && i < length; i++) {
if(str[i] < 32 || str[i] >= 0x7f)
continue;
total += font_glyph_width[str[i] - 32] + 1;
}
return total - (total > 0);
}
#endif
mat3 operator *(mat3 const &A, mat3 const &B)
@ -174,6 +227,40 @@ vec3 operator * (mat3 const &M, vec3 const &u)
return v;
}
#if 0
static void print_text(int x, int y, char const *fmt, ...)
{
static char str[128];
va_list args;
va_start(args, fmt);
vsnprintf(str, sizeof str, fmt, args);
va_end(args);
draw_text(x, y, str, strlen(str));
}
#endif
void render_centered_text(char const *str)
{
/* Count lines */
int lines = 1;
for(int i = 0; str[i]; i++)
lines += str[i] == '\n';
static int const line_height = 10;
int y = (VHEIGHT - line_height * lines) / 2;
/* Draw each line centered */
char const *line = str;
char const *endline;
while(*line) {
endline = strchrnul(line, '\n');
int w = text_size(line, endline - line);
draw_text((VWIDTH - w) / 2, y, line, endline - line);
line = endline + (*endline != 0);
y += line_height;
}
}
static struct camera *camera = NULL;
static struct world *world = NULL;
static struct level *level = NULL;
@ -184,6 +271,8 @@ void render(void)
#ifdef AZUR_TOOLKIT_GINT
azrp_perf_clear();
cd_raytrace(camera, world);
if(world->text)
render_centered_text(world->text->str);
platform_render();
if(debug) {
@ -262,7 +351,7 @@ int update(void)
if(w->mirror && w->depth > w->mirror->end)
w->mirror = NULL;
if(w->plane && w->depth > w->plane->y) {
if(w->plane && w->depth > w->plane->y - num(4)) {
// TODO: Check collision
w->plane = NULL;
}
@ -284,24 +373,34 @@ int update(void)
w->text = &level->texts[w->text_index++];
}
// End of level
if(!w->mirror && !w->plane && !w->text && w->depth >= level->finish) {
gint_osmenu();
}
return 0;
}
/* Basic basic level */
struct level lv1 = {
.name = "<Test>",
.finish = num(1024),
.mirror_count = 1,
.mirrors = (struct element_mirror[]){
{ .begin = 256, .end = 512 },
{ .begin = 256, .end = 768 },
},
.plane_count = 2,
.planes = (struct element_plane[]){
{ .y = 64, .shape = 0b01010'10101'01010'10101'01010,
{ .y = 384, .shape = 0b01010'10101'01010'10101'01010,
.type = ELEMENT_PLANE_DAMAGE, .data = 0 },
{ .y = 128, .shape = 0b11111'10001'10001'10001'11111,
{ .y = 384+64, .shape = 0b11111'10001'10001'10001'11111,
.type = ELEMENT_PLANE_DAMAGE, .data = 0 },
},
.text_count = 0,
.text_count = 1,
.texts = (struct element_text[]){
{ .begin = 32, .end = 256,
.str = "Red stuff bad!\nDon't touch the red stuff!", },
},
};
@ -316,7 +415,8 @@ int main(void)
camera_set_fov(camera, 80.0);
camera_update_angles(camera);
level = &lv1;
extern struct level level_1_1;
level = &level_1_1;
struct world w = {};
w.neon_position = 0;

View File

@ -144,21 +144,22 @@ static int cast_ray(struct world const *world, svec3 const &origin,
{
snum tx_rx_rz, tz_rx_rz;
int hitx = 0, hitz = 0;
static snum const epsilon = 0.1;
if(rayDir.x > 0) {
if(rayDir.x > epsilon) {
tx_rx_rz = (snum(WORLD_SIZE / 2) - origin.x) * rayDir.z;
hitx = RIGHT;
}
else if(__builtin_expect(rayDir.x < 0, 1)) {
else if(__builtin_expect(rayDir.x < -epsilon, 1)) {
tx_rx_rz = (snum(-WORLD_SIZE / 2) - origin.x) * rayDir.z;
hitx = LEFT;
}
if(rayDir.z > 0) {
if(rayDir.z > epsilon) {
tz_rx_rz = (snum(WORLD_SIZE / 2) - origin.z) * rayDir.x;
hitz = TOP;
}
else if(__builtin_expect(rayDir.z < 0, 1)) {
else if(__builtin_expect(rayDir.z < -epsilon, 1)) {
tz_rx_rz = (snum(-WORLD_SIZE / 2) - origin.z) * rayDir.x;
hitz = BOTTOM;
}
@ -184,11 +185,10 @@ static int cast_ray(struct world const *world, svec3 const &origin,
-rayDir.x);
hit = hitx;
}
else return 0;
*collision_y = hit ? num(origin.y) + num(*t) * num(rayDir.y) : num(192);
/* Compute intersection with object plane */
*collision_y = num(origin.y) + num(*t) * num(rayDir.y);
if(__builtin_expect(world->plane &&
(*collision_y > world->plane->y - world->depth), 0)) {
snum plane_y = snum(world->plane->y - world->depth);
@ -202,7 +202,7 @@ static int cast_ray(struct world const *world, svec3 const &origin,
int cell_z = plane_z.ifloor();
if((unsigned)cell_x < 5 && (unsigned)cell_z < 5) {
if((world->plane->shape >> (5*cell_z + cell_x)) & 1) {
if((world->plane->shape >> (5*cell_z + 4-cell_x)) & 1) {
*t = plane_t;
*collision_y = world->plane->y - world->depth;
return OBJECT_PLANE;
@ -287,7 +287,7 @@ void render_fragment(struct camera const *camera, struct world const *world,
if(coll_y > 20)
neon_size += ((snum(coll_y)-snum(20)) * snum(1.0/4));
if(neon <= neon_size)
color = 0xffff;
color = world->text ? RGB(15,15,15) : 0xffff;
}
else if(__builtin_expect(coll_y >= 64, 0)) {
if(coll_y > 128)