add vertical text with start of duet font

This commit is contained in:
Lephenixnoir 2021-08-21 19:10:29 +02:00
parent 562debd926
commit dcaaec7fb1
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
8 changed files with 166 additions and 21 deletions

View File

@ -13,8 +13,10 @@ set(SOURCES
src/main.c
src/render.c
src/physics.c
src/text.c
)
set(ASSETS
assets-cg/font.png
assets-cg/level/level1.txt
assets-cg/level/level2.txt
assets-cg/level/level3.txt
@ -28,7 +30,7 @@ fxconv_declare_converters(converters.py)
fxconv_declare_assets(${ASSETS} WITH_METADATA)
add_executable(addin ${SOURCES} ${ASSETS})
target_compile_options(addin PRIVATE -Wall -Wextra -Os)
target_compile_options(addin PRIVATE -Wall -Wextra -Os -ffast-math)
target_link_libraries(addin Gint::Gint)
generate_g3a(TARGET addin OUTPUT "Duet.g3a"

BIN
assets-cg/font.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 925 B

View File

@ -1,3 +1,9 @@
example.png:
type: bopti-image
name: img_example
font.png:
type: font
name: font_duet
charset: print
grid.size: 9x13
grid.padding: 1
grid.border: 0
proportional: true
height: 10

View File

@ -96,6 +96,14 @@ void drectoid(rect_t const *r, int color);
void render_player(float angle);
//---
// Duet Text
//---
/* (x,y) is screen as usual, but align is relative to rotated text */
void duet_text_opt(int x, int y, int fg, int bg, int halign, int valign,
char const *str, int size);
//---
// Physics
//---

View File

@ -35,20 +35,16 @@ level_t level0 = {
int main(void)
{
volatile int need_frame = 1;
game_t game;
float dt = 0;
int timer;
__printf_enable_fp();
game_t game;
memset(&game, 0x00, sizeof game);
game.level = &level4;
game.current = game.level->blocks;
game.time = -5.0;
timer = timer_configure(TIMER_ANY, 33000, GINT_CALL_SET(&need_frame));
volatile int need_frame = 1;
int timer = timer_configure(TIMER_ANY, 33000, GINT_CALL_SET(&need_frame));
timer_start(timer);
while (1) {
@ -57,7 +53,7 @@ int main(void)
while (need_frame == 0) sleep();
need_frame = 0;
dt = (1.0 / 30) * game.level->tempo * 2.7;
float dt = (1.0 / 30) * game.level->tempo * 2.7;
game.time += dt;
/* Input analysis */
@ -78,15 +74,15 @@ int main(void)
/* Level generation */
// Remove rectangles that have passed their lifetime by 2 seconds
// Remove rectangles that have passed their lifetime by 4 tempo
for(int i = 0; i < game.cursor;) {
if(game.time > game.table[i].meta->time + 2)
if(game.time > game.table[i].meta->time + 4)
game.table[i] = game.table[--game.cursor];
else
i++;
}
// Find rectangles that need to be loaded
// Find rectangles that need to be loaded, 10 tempo in advance
rectmeta_t const *meta = game.current;
while(meta < game.level->blocks + game.level->block_count) {
if(meta - game.current > RECT_TABLE_SIZE - game.cursor)
@ -103,6 +99,11 @@ int main(void)
rect_load(r, r->meta);
}
// End of level
if(game.current >= game.level->blocks + game.level->block_count
&& game.cursor == 0)
break;
/* Physics */
// if(player_collision(&game))
@ -120,12 +121,14 @@ int main(void)
/* Rendering */
dclear(player_collision(&game) ? C_RED : C_BLACK);
dprint(0, 0, C_WHITE, "game time: %.2fs", game.time);
dprint(0, 11, C_WHITE, "rectangles loaded: %d", game.cursor);
if(game.time < -2)
duet_text_opt(DWIDTH*3/4, DHEIGHT/2, C_WHITE, C_NONE, DTEXT_CENTER,
DTEXT_MIDDLE, "Change is inevitable.", -1);
render_player(game.player_rota);
for(int i = 0; i < game.cursor; i++)
drectoid(&game.table[i], C_WHITE);
render_player(game.player_rota);
dupdate();
}

View File

@ -95,10 +95,16 @@ void rect_load(rect_t *r, rectmeta_t const *meta)
switch(meta->position) {
case Position_Left:
r->y = DHEIGHT/2 - CORRIDOR_SIZE/2 + r->h/2;
if(meta->shape == Shape_Square)
r->y = DHEIGHT/2 - 0.22*CORRIDOR_SIZE;
else
r->y = DHEIGHT/2 - CORRIDOR_SIZE/2 + r->h/2;
break;
case Position_Right:
r->y = DHEIGHT/2 + CORRIDOR_SIZE/2 - r->h/2;
if(meta->shape == Shape_Square)
r->y = DHEIGHT/2 + 0.22*CORRIDOR_SIZE;
else
r->y = DHEIGHT/2 + CORRIDOR_SIZE/2 - r->h/2;
break;
case Position_Middle:
r->y = DHEIGHT/2;

View File

@ -101,7 +101,7 @@ void drectoid(rect_t const *r, int color)
void render_player(float angle)
{
int x=PLAYER_X, y=DHEIGHT/2;
dcircle(x, y, PLAYER_R, C_WHITE, false);
dcircle(x, y, PLAYER_R, C_RGB(10, 10, 10), false);
float x1, y1, x2, y2;
player_position(angle, &x1, &y1, &x2, &y2);

120
src/text.c Normal file
View File

@ -0,0 +1,120 @@
#include "duet.h"
extern font_t font_duet;
/* topti functions exposed to each implementation */
int topti_glyph_index(font_t const *f, uint32_t code_point);
int topti_offset(font_t const *f, uint glyph);
uint32_t topti_utf8_next(uint8_t const **str_pointer);
/* topti_glyph(): Render a glyph on the VRAM
Prints a glyph naively using word accesses, because for most fonts with a
small size (including gint's 8x9 font) this will be more efficient than the
complex logic for longword accesses.
This function assumes that at least one of [fg] and [bg] is not transparent.
@vram Target position on VRAM, adjusted to [top] and [left]
@data Glyph data
@left Left-position of subglyph
@top Top-Position of subglyph
@width Subglyph width
@height Subglyph height
@dataw Glyph width
@datah Total font height
@fg @bg Foreground and background colors */
static void topti_glyph(uint16_t *vram, uint32_t const * data, int left,
int top, int width, int height, int dataw, int datah, int fg, int bg)
{
/* A C version of what is usually done in assembler */
for(int y = 0; y < height; y++) {
for(int x = 0; x < width; x++) {
int bit_number = (top + y) * dataw + (left + x);
int bit = (data[bit_number >> 5] >> (31 - (bit_number & 31))) & 1;
/* Swithing x -> datah-y-1 and y -> x here gives vertical glyphs */
if((bit ? fg : bg) != C_NONE)
vram[DWIDTH*x + (datah-y-1)] = bit ? fg : bg;
}
}
}
static void topti_render(int x, int y, char const *str_char, font_t const *f,
int fg, int bg, int size)
{
uint8_t const *str = (void *)str_char;
uint8_t const *str0 = str;
/* Raw glyph data */
uint32_t const *data = f->data;
/* Storage height, top position within glyph */
int height = f->data_height, top = 0;
/* Vertical clipping */
if(x > 395 || y > 223 || y + height <= 0) return;
if(y + height > 224) height = 224 - y;
if(y < 0) top = -y, height += y, y = 0;
/* Character spacing waiting to be drawn, in pixels */
int space = 0;
/* Read each character from the input string */
while(1)
{
uint32_t code_point = topti_utf8_next(&str);
if(!code_point || (size >= 0 && str - str0 > size)) break;
int glyph = topti_glyph_index(f, code_point);
if(glyph < 0) continue;
int dataw = f->prop ? f->glyph_width[glyph] : f->width;
/* Draw character spacing if background is opaque */
if(space && bg >= 0) drect(x, y, x+height-1, y+space-1, bg);
y += space;
if(y >= DHEIGHT) break;
int index = topti_offset(f, glyph);
/* Compute horizontal intersection between glyph and screen */
int width = dataw, left = 0;
if(y + dataw <= 0)
{
y += dataw;
space = f->char_spacing;
continue;
}
if(y < 0) left = -y, width += y;
if(y + width > DHEIGHT) width = DHEIGHT - y;
/* Render glyph */
topti_glyph(gint_vram + 396 * y + x, data + index, left, top, width,
height, dataw, f->data_height, fg, bg);
/* Switching x -> y here (and some other places, but mostly here) gives
vertical text */
y += dataw;
space = f->char_spacing;
}
}
void duet_text_opt(int x, int y, int fg, int bg, int halign, int valign,
char const *str, int size)
{
if(halign != DTEXT_LEFT || valign != DTEXT_TOP)
{
int w, h;
dnsize(str, size, &font_duet, &w, &h);
if(halign == DTEXT_RIGHT) x -= h - 1;
if(halign == DTEXT_CENTER) x -= (h >> 1);
if(valign == DTEXT_BOTTOM) y -= w - 1;
if(valign == DTEXT_MIDDLE) y -= (w >> 1);
}
topti_render(x, y, str, &font_duet, fg, bg, size);
}