level 1-1 but no death
This commit is contained in:
parent
39310e7e2e
commit
b9067833bc
|
@ -1,3 +1,4 @@
|
|||
__pycache__
|
||||
/build-*/
|
||||
*.g3a
|
||||
*.mp4
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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."
|
Binary file not shown.
After Width: | Height: | Size: 21 KiB |
|
@ -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
|
|
@ -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
|
|
@ -68,6 +68,9 @@ struct element_text {
|
|||
};
|
||||
|
||||
struct level {
|
||||
char const *name;
|
||||
num finish;
|
||||
|
||||
int mirror_count;
|
||||
struct element_mirror *mirrors;
|
||||
|
||||
|
|
112
src/main.cc
112
src/main.cc
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue