Added bitmap part rendering and text colors, proper gray text. Enhanced demo app (wip).

This commit is contained in:
lephe 2016-07-28 18:12:07 +02:00
parent b2151886bc
commit c63d7b812e
53 changed files with 1227 additions and 540 deletions

View File

@ -29,10 +29,12 @@ ob = sh3eb-elf-objcopy
wr = g1a-wrapper
# Flags
cflags = -m3 -mb -nostdlib -I include -ffreestanding -std=c11 -Os
cflags = -m3 -mb -nostdlib -I include -ffreestanding -std=c11 -Os \
-W -Wall -Wextra -pedantic
# Demo application (could be done better)
demo-src = $(notdir $(wildcard demo/*.[cs]))
demo-dep = $(wildcard demo/*.h)
demo-ld = demo/gintdemo.ld
demo-icon = demo/icon.bmp
demo-res = $(notdir $(wildcard demo/resources/*))
@ -83,8 +85,9 @@ hdr-dep = $(wildcard include/*.h include/internals/*.h)
# C source file template:
# $1 module name
# $2 filename
# $3 dependencies
define rule-c-source
build/$1_$2.o: src/$1/$2 $(hdr-dep)
build/$1_$2.o: src/$1/$2 $3
$(cc) -c $$< -o $$@ $(cflags) -I src/$1
endef
@ -128,7 +131,7 @@ $(target-g1a): $(target-std) $(target-lib) $(demo-obj)
$(foreach mod,$(modules), \
$(foreach source,$(mod-$(mod)-c), $(eval \
$(call rule-c-source,$(mod),$(source)))) \
$(call rule-c-source,$(mod),$(source),$(hdr-dep)))) \
$(foreach source,$(mod-$(mod)-asm), $(eval \
$(call rule-asm-source,$(mod),$(source)))) \
)
@ -145,7 +148,7 @@ build/display_font_system.bmp.o: src/display/font_system.bmp
# Demo application
build/demo_%.c.o: demo/%.c
build/demo_%.c.o: demo/%.c $(hdr-dep) $(demo-dep)
$(cc) -c $< -o $@ $(cflags)
build/demo_font_%.bmp.o: demo/resources/font_%.bmp

12
TODO
View File

@ -9,21 +9,15 @@
~ needs investigation
@ vram overflow
@ keyboard test threaded interface
@ possibility of vram overflow with text
+ bitmap blending modes
+ have timers use structures from 7705.h and 7305.h
+ full and partial transparency
+ partial transparency
+ gint vs. ML with 248x124 at (-60, -28)
+ call exit handlers
+ compute frequencies
+ gray text
+ upgraded blending modes
+ blending modes for text
+ information masks for text
+ test all font encodings
+ font clipping
+ bitmap parts
- improve exception handler debugging information (if possible)
- full rtc driver (time)

View File

@ -1,17 +1,11 @@
#include <stdlib.h>
#include <string.h>
#include "gintdemo.h"
#include <mpu.h>
#include <gint.h>
#include <keyboard.h>
#include <display.h>
#include <timer.h>
#include <gray.h>
#include <stdint.h>
#include <stdarg.h>
#include <7305.h>
#include <internals/stdio.h>
@ -21,207 +15,28 @@
// Not really beautiful... but this will do.
//---
void print(int x, int y, const char *format, ...)
void locate(int x, int y, const char *str)
{
if(x < 1 || x > 21 || y < 1 || y > 8) return;
if(gray_runs()) gtext(x * 6 - 5, y * 8 - 8, str);
else dtext(x * 6 - 5, y * 8 - 8, str);
}
void print(int x, int y, const char *format, ...)
{
va_list args;
va_start(args, format);
__printf(0, format, args);
va_end(args);
if(gray_runs()) gtext(__stdio_buffer, x * 6 - 5, y * 8 - 8);
else dtext(__stdio_buffer, x * 6 - 5, y * 8 - 8);
locate(x, y, __stdio_buffer);
}
void locate(const char *str, int x, int y)
{
if(x < 1 || x > 21 || y < 1 || y > 8) return;
if(gray_runs()) gtext(str, x * 6 - 5, y * 8 - 8);
else dtext(str, x * 6 - 5, y * 8 - 8);
}
//---
// Test applications.
//---
/*
keyboard_test_binary()
Prints a byte as binary/
*/
void keyboard_test_binary(int byte, int x, int y)
{
char str[9];
int i = 7;
str[8] = 0;
while(i >= 0)
{
str[i] = '0' + (byte & 1);
byte >>= 1;
i--;
}
locate(str, x, y);
}
/*
keyboard_test_timer()
Displays a keyboard test. The keyboard state is displayed as well, but
there is a timer artifact. The keyboard state timer uses the same
period as the (internal) keyboard analysis timer, but there is a time
gap between a keyboard analysis and an update on the screen.
*/
void keyboard_test_timer(void)
{
volatile unsigned char *state = keystate();
dclear_area(5, 10, 71, 34);
keyboard_test_binary(state[0], 1, 1);
keyboard_test_binary(state[1], 1, 2);
keyboard_test_binary(state[2], 1, 3);
keyboard_test_binary(state[3], 1, 4);
keyboard_test_binary(state[4], 1, 5);
keyboard_test_binary(state[5], 10, 1);
keyboard_test_binary(state[6], 10, 2);
keyboard_test_binary(state[7], 10, 3);
keyboard_test_binary(state[8], 10, 4);
keyboard_test_binary(state[9], 10, 5);
dupdate();
}
/*
keyboard_test()
Displays a multi-getkey test as well as the keyboard state in real
time.
*/
void keyboard_test(void)
{
int x = 0;
char str[3];
int keys[4] = { 0 };
int i;
timer_start(TIMER_USER, 1700, TIMER_Po_256, keyboard_test_timer, 0);
dclear();
locate("Keyboard state:", 0, 0);
locate("multi-getkey ^^", 50, 55);
dupdate();
while(1)
{
multigetkey(keys, 4, 0);
if(keys[0] == KEY_EXIT && keys[1] == KEY_NONE) break;
#define hexa(h) ('0' + (h) + 39 * ((h) > 9))
x = (x + 1) & 15;
str[0] = hexa(x);
str[1] = 0;
locate(str, 100, 0);
for(i = 0; i < 4; i++)
{
str[0] = hexa((keys[i] >> 4) & 0x0f);
str[1] = hexa(keys[i] & 0x0f);
str[2] = 0;
locate(str, 100, 16 + 10 * i);
}
#undef hexa
dupdate();
}
timer_stop(TIMER_USER);
}
/*
bitmap_test()
Displays various bitmaps to ensure bopti is working correctly.
*/
/*
void bitmap_test(void)
{
extern Image res_bitmap_opt_start;
extern Image res_symbol_start;
extern Image res_symbol2_start;
extern Image res_sprites_start;
extern Image res_swords_start;
extern Image res_items_start;
Image *opt = &res_bitmap_opt_start;
Image *sybl = &res_symbol_start;
Image *sybl2 = &res_symbol2_start;
Image *sprites = &res_sprites_start;
Image *swords = &res_swords_start;
Image *items = &res_items_start;
uint32_t a32 = 0xffffffff;
int black_bg = 0, gray = 0;
int key;
int x = 20, y = 10;
while(1)
{
if(gray)
{
gray_start();
gclear();
if(black_bg) greverse_area(0, 0, 127, 63);
gimage(swords, 0, 57);
gimage(items, x, y);
gupdate();
}
else
{
gray_stop();
dclear();
if(black_bg) dreverse_area(0, 0, 127, 63);
dimage(opt, 0, 57);
dimage(sybl, 30 & a32, 40);
dimage(sybl2, 62 & a32, 40);
dupdate();
}
key = getkey();
if(key == KEY_EXIT) break;
if(key == KEY_F1) gray = !gray;
if(key == KEY_F2) a32 ^= 31;
if(key == KEY_F3) black_bg = !black_bg;
if(key == KEY_UP) y--;
if(key == KEY_DOWN) y++;
if(key == KEY_LEFT) x--;
if(key == KEY_RIGHT) x++;
}
gray_stop();
return;
}
*/
/*
text_test()
Renders text.
*/
void text_test(void)
{
extern Font res_font_modern_start;
@ -242,115 +57,27 @@ void text_test(void)
while(getkey() != KEY_EXIT);
}
/*
gray_test()
Runs the gray engine.
*/
void gray_test(void)
{
extern Image res_opt_gray_start;
int *v1, *v2;
int delays[2]; // { light, dark }
int key, changed = 1, i;
int selected = 0;
gray_getDelays(delays, delays + 1);
gray_start();
while(1)
{
if(changed)
{
gray_setDelays(delays[0], delays[1]);
gclear();
v1 = gray_lightVRAM();
v2 = gray_darkVRAM();
for(i = 0; i < 63; i++)
{
v1[(i << 2)] = v1[(i << 2) + 1] =
-((i & 31) < 16);
v2[(i << 2)] = v2[(i << 2) + 1] =
-(i < 32);
}
locate("light", 15, 2);
print(15, 3, "%d", delays[0]);
locate("dark", 15, 5);
print(15, 6, "%d", delays[1]);
locate("\x02", 14, selected ? 6 : 3);
gimage(&res_opt_gray_start, 0, 56);
gupdate();
}
changed = 0;
key = getkey_opt(Getkey_RepeatArrowKeys, 1);
if(key == KEY_EXIT) break;
changed = 1;
switch(key)
{
case KEY_F1:
selected = !selected;
break;
case KEY_F2:
delays[0] = isSH3() ? 985 : 994;
delays[1] = 1609;
break;
case KEY_F3:
delays[0] = 860;
delays[1] = 1298;
break;
case KEY_UP:
delays[selected] += 10;
break;
case KEY_DOWN:
if(delays[selected] >= 110) delays[selected] -= 10;
break;
case KEY_RIGHT:
delays[selected]++;
break;
case KEY_LEFT:
if(delays[selected] >= 101) delays[selected]--;
break;
default:
changed = 0;
break;
}
}
gray_stop();
}
/*
printf_test()
Tests formatting functions.
*/
void printf_test(void)
{
dclear();
locate("Formatted printing", 1, 1);
locate(1, 1, "Formatted printing");
print(2, 3, "%%4.2d 5 :\"%4.2d\"", 5);
print(2, 4, "%%-3c '&':\"%-3c\"", '&');
print(2, 5, "%%#05x 27 :\"%#05x\"", 27);
print(2, 6, "%%1s \"tr\":\"%1s\"", "tr");
print(2, 7, "%%6p NULL :\"%7p\"", NULL);
print(2, 7, "%%6p NULL :\"%6p\"", NULL);
dupdate();
while(getkey() != KEY_EXIT);
}
*/
/*
static const unsigned char screen[1024] = {
@ -504,7 +231,7 @@ void debug(void)
tlb_debug()
Displays the TLB contents and some information. Only available for
SH7705, because the SH7305's TLB is much more complicated.
*/
void tlb_debug(void)
{
// Entry address address (pointer in the address array), entry data
@ -573,6 +300,7 @@ void tlb_debug(void)
key = getkey();
}
}
*/
/*
main_menu()
@ -615,8 +343,8 @@ void main_menu(int *category, int *app)
"View TLB (SH3 only)",
NULL
};
const char **list;
int list_len;
const char **list = NULL;
int list_len = 0;
extern unsigned int bgint, egint;
extern unsigned int romdata;
@ -630,7 +358,7 @@ void main_menu(int *category, int *app)
int i;
mpu = mpu_names[MPU_CURRENT < 5 ? MPU_CURRENT : 5];
text_configure_default();
text_configure(NULL, Color_Black);
while(1)
{
@ -644,7 +372,7 @@ void main_menu(int *category, int *app)
switch(tab)
{
case 0:
locate("Demo application", 1, 1);
locate(1, 1, "Demo application");
print(2, 3, "gint version: %5s", GINT_VERSION_STR);
print(2, 4, "handler size: %5d", gint_size);
print(2, 5, "mpu type: %7s", mpu);
@ -654,17 +382,17 @@ void main_menu(int *category, int *app)
break;
case 1:
locate("Test list", 1, 1);
locate(1, 1, "Test list");
list = list_tests;
break;
case 2:
locate("Performance", 1, 1);
locate(1, 1, "Performance");
list = list_perfs;
break;
case 3:
locate("Debug", 1, 1);
locate(1, 1, "Debug");
list = list_debug;
break;
@ -672,7 +400,7 @@ void main_menu(int *category, int *app)
print(1, 1, "Tab %d", tab);
break;
}
dimage(&res_opt_menu_start, 0, 56);
dimage(0, 56, &res_opt_menu_start);
if(list)
{
@ -680,10 +408,10 @@ void main_menu(int *category, int *app)
while(list[list_len]) list_len++;
for(i = scroll; list[i] && i < scroll + 6; i++)
locate(list[i], 2, i - scroll + 2);
locate(2, i - scroll + 2, list[i]);
if(scroll > 0) locate("\x0d", 20, 2);
if(scroll + 6 < list_len) locate("\x0e", 20, 7);
if(scroll > 0) locate(20, 2, "\x0d");
if(scroll + 6 < list_len) locate(20, 7, "\x0e");
dreverse_area(0, 8 * (index - scroll) + 8, 127,
8 * (index - scroll) + 15);
@ -794,26 +522,33 @@ int main(void)
switch((category << 8) | app)
{
case 0x0101:
keyboard_test();
test_keyboard();
break;
case 0x0102:
gray_test();
test_gray();
break;
case 0x0103:
// bitmap_test();
test_bopti();
break;
case 0x0104:
text_test();
test_tales();
break;
case 0x0105:
// rtc_test();
// test_rtc();
break;
case 0x0106:
printf_test();
// test_printf();
break;
case 0x0201:
// perf_bopti();
break;
case 0x0202:
// perf_tales();
break;
case 0x0301:
if(isSH3()) tlb_debug();
// if(isSH3()) debug_tlb();
break;
}
}

114
demo/gintdemo.h Normal file
View File

@ -0,0 +1,114 @@
//---
//
// gint demo application
//
// Displays some tests cases for many features of the library.
//
//---
#ifndef _GINTDEMO_H
#define _GINTDEMO_H
//---
// Main routines and common functions.
//---
/*
main()
No need for description.
*/
int main(void);
/*
main_menu()
Displays the main menu and returns user's choice by setting the
category and application. Category is 0 when the user leaves the
application.
*/
void main_menu(int *category, int *app);
/*
locate()
Displays text using a system-like monospaced font on a 21*8 grid.
*/
void locate(int x, int y, const char *str);
/*
print()
Locates a string using formatted printing.
*/
void print(int x, int y, const char *format, ...);
//---
// Test applications.
//---
/*
test_keyboard()
Displays a real-time multigetkey() and the keyboard state.
*/
void test_keyboard(void);
/*
test_gray()
Lets the user set the gray delays and see the results.
*/
void test_gray(void);
/*
test_bopti()
Displays and moves many kinds of bitmaps.
*/
void test_bopti(void);
/*
test_tales()
Displays some text using different modes and clipping options.
*/
void test_tales(void);
/*
test_rtc()
Just a clock.
*/
void test_rtc(void);
/*
test_printf()
Some text formatting.
*/
void test_printf(void);
//---
// Performance applications.
//---
/*
perf_bopti()
Compares bopti and MonochromeLib.
*/
void perf_bopti(void);
/*
perf_tales()
Compares tales and the system's text rendering functions.
*/
void perf_tales(void);
//---
// Debug applications.
//---
/*
debug_tlb()
On SH7705, displays the TLB contents. Does nothing on SH7305.
*/
void debug_tlb(void);
#endif // _GINTDEMO_H

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 554 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 242 B

BIN
demo/resources/zelda.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

222
demo/test_bopti.c Normal file
View File

@ -0,0 +1,222 @@
#include "gintdemo.h"
#include <display.h>
#include <gray.h>
#include <keyboard.h>
#include <internals/bopti.h>
#include <stddef.h>
/*
test_bopti()
Displays and moves many kinds of bitmaps. Here are the images used:
Name Size Color Alpha
---------------------------------------------------------
items.bmp 266 * 124 Gray -
sprites.bmp 66 * 33 Gray -
swords.bmp 88 * 16 Gray Full
---------------------------------------------------------
zelda.bmp 86 * 280 Mono -
isometric.bmp 37 * 27 Mono Full
Mono Greater
---------------------------------------------------------
*/
static void getwh(Image *img, int *width, int *height)
{
const unsigned char *data;
if(!img)
{
*width = 0;
*height = 0;
return;
}
*width = img->width;
*height = img->height;
if(*width && *height) return;
data = img->data;
*width = (data[0] << 8) | data[1];
*height = (data[2] << 8) | data[3];
}
static void getxy(Image *img, int *x, int *y)
{
int width, height;
getwh(img, &width, &height);
*x = 64 - (width >> 1);
*y = 28 - (height >> 1);
}
static Image *select(Image *current)
{
extern Image res_bopti_thumbs_start;
extern Image
res_items_start,
res_sprites_start,
res_swords_start,
res_zelda_start,
res_isometric_start;
struct {
Image *img;
const char *name;
const char *info;
} images[] = {
{ &res_items_start, "Items", "Gray" },
{ &res_sprites_start, "Sprites", "Gray" },
{ &res_swords_start, "Swords", "Gray Alpha" },
{ &res_zelda_start, "Zelda", "Mono" },
{ &res_isometric_start, "Isometric", "Mono Alpha" },
{ NULL, NULL, NULL }
};
Image *thumbs = &res_bopti_thumbs_start;
int items = 0;
static int row = 0;
int leave = 1, i;
while(images[items].img) items++;
gray_start();
while(1)
{
gclear();
locate(1, 1, "Select an image:");
for(i = 0; i < items && i < 7; i++)
{
locate(2, 2 + i + (i > row), images[i].name);
gimage_part(100, 8 + 8 * (i + (i > row)), thumbs, 0,
8 * i, 7, 7);
if(i == row)
{
int width, height;
getwh(images[i].img, &width, &height);
print(2, 2 + i + 1, "%d\x04%d", width, height);
locate(10, 2 + i + 1, images[i].info);
}
}
greverse_area(0, 8 * row + 8, 128, 8 * row + 23);
gupdate();
do
{
leave = 1;
switch(getkey())
{
case KEY_UP:
row = (row + items - 1) % items;
break;
case KEY_DOWN:
row = (row + 1) % items;
break;
case KEY_EXE:
return images[row].img;
case KEY_EXIT:
return current;
default:
leave = 0;
break;
}
}
while(!leave);
}
gray_stop();
}
void test_bopti(void)
{
extern Image res_opt_bitmap_start;
Image *img = NULL;
int leave = 1;
int black_bg = 0;
int x = 0, y = 0;
while(1)
{
if(img && (img->format & Channel_Light))
{
gray_start();
gclear();
if(black_bg) greverse_area(0, 0, 127, 63);
if(img) gimage(x, y, img);
gclear_area(0, 55, 127, 63);
gimage(0, 56, &res_opt_bitmap_start);
gupdate();
}
else if(img)
{
gray_stop();
dclear();
if(black_bg) dreverse_area(0, 0, 127, 63);
if(img) dimage(x, y, img);
dclear_area(0, 55, 127, 63);
dimage(0, 56, &res_opt_bitmap_start);
dupdate();
}
else
{
gray_stop();
dclear();
locate(3, 3, "No image selected");
dimage(0, 56, &res_opt_bitmap_start);
dupdate();
}
leave = 1;
do
{
leave = 1;
switch(getkey())
{
case KEY_EXIT:
gray_stop();
return;
case KEY_F1:
img = select(img);
getxy(img, &x, &y);
break;
case KEY_F5:
black_bg = !black_bg;
break;
case KEY_UP:
y--;
break;
case KEY_DOWN:
y++;
break;
case KEY_LEFT:
x--;
break;
case KEY_RIGHT:
x++;
break;
default:
leave = 0;
}
}
while(!leave);
}
gray_stop();
return;
}

93
demo/test_gray.c Normal file
View File

@ -0,0 +1,93 @@
#include "gintdemo.h"
#include <gray.h>
#include <keyboard.h>
#include <mpu.h>
/*
test_gray()
Lets the user set the gray delays and see the results.
*/
static void draw(int delay1, int delay2, int selected)
{
extern Image res_opt_gray_start;
int *vl = gray_lightVRAM();
int *vd = gray_darkVRAM();
gclear();
for(int i = 0; i < 63; i++)
{
int o = (i << 2) + 2;
vl[o] = vl[o + 1] = -((i & 31) < 16);
vd[o] = vd[o + 1] = -(i < 32);
}
locate(3, 2, "light");
print(3, 3, "%d", delay1);
locate(3, 5, "dark");
print(3, 6, "%d", delay2);
locate(2, selected ? 6 : 3, "\x02");
gimage(0, 56, &res_opt_gray_start);
gupdate();
}
void test_gray(void)
{
int delays[2]; // { light, dark }
int key, changed = 1;
int selected = 0;
gray_getDelays(delays, delays + 1);
gray_start();
while(1)
{
if(changed)
{
gray_setDelays(delays[0], delays[1]);
draw(delays[0], delays[1], selected);
}
changed = 0;
key = getkey_opt(Getkey_RepeatArrowKeys, 1);
if(key == KEY_EXIT) break;
changed = 1;
switch(key)
{
case KEY_F1:
selected = !selected;
break;
case KEY_F2:
delays[0] = isSH3() ? 985 : 994;
delays[1] = 1609;
break;
case KEY_F3:
delays[0] = 860;
delays[1] = 1298;
break;
case KEY_UP:
delays[selected] += 10;
break;
case KEY_DOWN:
if(delays[selected] >= 110) delays[selected] -= 10;
break;
case KEY_RIGHT:
delays[selected]++;
break;
case KEY_LEFT:
if(delays[selected] >= 101) delays[selected]--;
break;
default:
changed = 0;
break;
}
}
gray_stop();
}

82
demo/test_keyboard.c Normal file
View File

@ -0,0 +1,82 @@
#include "gintdemo.h"
#include <display.h>
#include <keyboard.h>
#include <stdlib.h>
/*
test_keyboard()
Displays a real-time multigetkey() and the keyboard state.
*/
static void draw(volatile unsigned char *state)
{
int i, j, k, l;
int x, y;
for(i = 0; i < 10; i++) for(j = 1; j < 8; j++)
{
// Eliminating keys that do not exist.
if(!i && j != 7) continue;
if(i && j == 7) continue;
if(i <= 4 && j == 6) continue;
if(i == 4 && j == 5) continue;
x = 5 * j + 1;
y = 61 - 5 * i;
// Moving the [AC/ON] key.
if(!i) x = 5 * (5) + 1, y = 61 - 5 * (4);
// Drawing a filled shape when the key is pressed.
if(state[i] & (128 >> j))
{
for(k = -2; k <= 2; k++) for(l = -2; l <= 2; l++)
if(abs(k) + abs(l) <= 2)
dpixel(x + k, y + l, Color_Black);
}
// Drawing a square border otherwise.
else
{
for(k = -1; k <= 1; k++) for(l = -1; l <= 1; l++)
if(k || l) dpixel(x + k, y + l, Color_Black);
}
}
}
void test_keyboard(void)
{
const char *key_names[] = {
"F1", "F2", "F3", "F4", "F5", "F6",
"SHIFT", "OPTN", "VARS", "MENU", "Left", "Up",
"ALPHA", "x^2", "^", "EXIT", "Down", "Right",
"X,\x1d,T", "log", "ln", "sin", "cos", "tan",
"[frac]", "F\x0f\x09" "D", "(", ")", ",", "\x09",
"7", "8", "9", "DEL", "AC/ON", NULL,
"4", "5", "6", "\x04", "\x05", NULL,
"1", "2", "3", "+", "-", NULL,
"0", ".", "\x08", "(-)", "EXE", NULL
};
volatile unsigned char *state = keystate();
int keys[4] = { 0 };
int i;
while(1)
{
multigetkey(keys, 4, 1);
if(keys[0] == KEY_EXIT && keys[1] == KEY_NONE) break;
dclear();
locate(1, 1, "Keyboard driver");
locate(8, 3, "Pressed keys:");
draw(state);
if(keys[0] == KEY_NONE) locate(9, 4, ":None");
else for(i = 0; i < 4 && keys[i] != KEY_NONE; i++)
{
locate( 9, i + 4, ":");
locate(10, i + 4, key_names[keyid(keys[i])]);
}
dupdate();
}
}

158
demo/test_tales.c Normal file
View File

@ -0,0 +1,158 @@
#include "gintdemo.h"
#include <display.h>
#include <keyboard.h>
#include <gray.h>
#include <stddef.h>
/*
test_tales()
Displays some text using different modes and clipping options.
*/
static Font *select(Font *current)
{
extern Font res_font_modern_start;
struct {
Font *font;
const char *name;
} fonts[] = {
{ NULL, "gint default" },
{ &res_font_modern_start, "Modern" },
};
int font_number = 2;
static int row = 0;
int i, leave;
while(1)
{
text_configure(NULL, Color_Black);
dclear();
locate(1, 1, "Select a font:");
for(i = 0; i < font_number && i < 6; i++)
{
if(fonts[i].font)
{
int height = fonts[i].font->line_height;
int y = (i + 2) * 8 - 8 + ((7 - height) >> 1);
text_configure(fonts[i].font, Color_Black);
dtext(7, y, fonts[i].name);
}
else
{
text_configure(NULL, Color_Black);
locate(2, i + 2, fonts[i].name);
}
}
dreverse_area(0, 8 * row + 8, 128, 8 * row + 15);
dupdate();
do
{
leave = 1;
switch(getkey())
{
case KEY_UP:
row = (row + font_number - 1) % font_number;
break;
case KEY_DOWN:
row = (row + 1) % font_number;
break;
case KEY_EXE:
return fonts[row].font;
case KEY_EXIT:
return current;
default:
leave = 0;
break;
}
}
while(!leave);
}
}
void test_tales(void)
{
enum Color colors[] = { Color_Black, Color_Dark, Color_Light,
Color_White, Color_Invert };
extern Image res_opt_tales_start;
Font *font = NULL;
int black_bg = 0;
int color = 0;
int i, x, height;
int leave;
gray_start();
while(1)
{
gclear();
if(black_bg) greverse_area(0, 0, 127, 54);
if(font)
{
text_configure(font, colors[color]);
height = font->line_height + 1;
}
else
{
text_configure(NULL, colors[color]);
height = 8;
}
for(i = 0; i < 6 && 2 + (i + 1) * height < 56; i++)
{
char str[17];
for(int j = 0; j < 16; j++) str[j] = 32 + (i << 4) + j;
str[16] = 0;
gtext(2, 2 + i * height, str);
}
gimage(0, 56, &res_opt_tales_start);
x = 45 + 8 * color;
gline(x, 57, x + 5, 57, Color_Black);
gline(x, 57, x, 62, Color_Black);
gline(x + 5, 57, x + 5, 62, Color_Black);
gline(x, 62, x + 5, 62, Color_Black);
gupdate();
do
{
leave = 1;
switch(getkey())
{
case KEY_F1:
gray_stop();
font = select(font);
gray_start();
break;
case KEY_F2:
color = (color + 1) % 5;
break;
case KEY_F5:
black_bg = !black_bg;
break;
case KEY_EXIT:
gray_stop();
text_configure(NULL, Color_Black);
return;
default:
leave = 0;
break;
}
}
while (!leave);
}
}

View File

@ -187,7 +187,7 @@ using the operation functions.
mask for the `draw` operation.
* Transparent monochrome images have two layers. The first describes the mask
for the `draw` operation, while the other is the `alpha` operation mask (which
means that it indicates which pixels are transparent).
means that it indicates which pixels are not transparent).
* Non-transparent gray images also have two layers: one for each
[gray buffer](gray-engine). Both are for the `draw` operation.
* Transparent gray images have three layers. Two of them constitute the two-bit

Binary file not shown.

View File

@ -14,8 +14,6 @@
// Heading declarations.
//---
#include <internals/tales.h>
enum Color
{
Color_White = 0,
@ -26,6 +24,9 @@ enum Color
Color_Invert = 5,
};
// This header needs enum Color to be defined.
#include <tales.h>
/*
struct Image
This structure holds information about a bitmap encoded with fxconv.
@ -146,6 +147,15 @@ void dline(int x1, int y1, int x2, int y2, enum Color color);
Displays a monochrome image in the vram. Does a real lot of
optimization.
*/
void dimage(struct Image *image, int x, int y);
void dimage(int x, int y, struct Image *image);
/*
dimage_part()
Draws a portion of an image, defined by its bounding rectangle.
Point (left, top) is included, but (left + width, top + height) is
excluded.
*/
void dimage_part(int x, int y, struct Image *img, int left, int top,
int width, int height);
#endif // _DISPLAY_H

View File

@ -122,7 +122,7 @@ void gint_stop_7305(void);
volatile void *gint_reg_7705(enum Register reg);
volatile void *gint_reg_7305(enum Register reg);
const char *gint_strerror_7705(int is_tlb);
const char *gint_strerror_7305(int is_tlb);
const char *gint_strerror_7305(void);
//---

View File

@ -127,7 +127,16 @@ void gline(int x1, int y1, int x2, int y2, enum Color color);
gimage()
Displays a gray image in the vram.
*/
void gimage(struct Image *image, int x, int y);
void gimage(int x, int y, struct Image *image);
/*
gimage_part()
Draws a portion of a gray image, defined by its bounding rectangle.
Point (left, top) is included, but (left + width, top + height) is
excluded.
*/
void gimage_part(int x, int y, struct Image *image, int left, int top,
int width, int height);

View File

@ -27,13 +27,13 @@
*/
enum Channel
{
Channel_Mono = 0x01,
Channel_Light = 0x02,
Channel_Dark = 0x04,
Channel_FullAlpha = 0x01,
Channel_LightAlpha = 0x02,
Channel_DarkAlpha = 0x04,
Channel_FullAlpha = 0x08,
Channel_LightAlpha = 0x10,
Channel_DarkAlpha = 0x20,
Channel_Mono = 0x08,
Channel_Light = 0x10,
Channel_Dark = 0x20,
};
/*

View File

@ -13,7 +13,16 @@
#include <tales.h>
#include <stdint.h>
#define OPERATE_ARGS uint32_t *operators, int height, int x, int y
extern struct Font *font;
extern enum Color color;
/*
tales_init()
Configures tales with the default font (which is part of gint).
*/
void tales_init(void) __attribute__((constructor));
/*
getCharacterIndex()
@ -29,7 +38,8 @@ int getCharacterIndex(int c);
Operates on the vram using the given operators. The x-coordinate should
be a multiple of 32. There should be `height` operators.
*/
void operate(uint32_t *operators, int height, int x, int y);
void operate_mono(OPERATE_ARGS);
void operate_gray(OPERATE_ARGS);
/*
update()
@ -44,4 +54,11 @@ void operate(uint32_t *operators, int height, int x, int y);
*/
int update(uint32_t *operators, int height, int available, uint32_t *glyph);
/*
render()
Renders text without any formatting analysis, using the given operation
function.
*/
void render(int x, int y, const char *str, void (*op)(OPERATE_ARGS));
#endif // _INTERNALS_TALES_H

View File

@ -171,38 +171,52 @@ volatile unsigned char *keystate(void);
/*
getkey()
Blocking function with auto-repeat and SHIFT modifying functionalities.
Reproduces the behavior of the system's GetKey().
@return Pressed key matrix code.
Reproduces the behavior of the system's GetKey(). Returns the matrix
code with a possible MOD_SHIFT bit.
*/
int getkey(void);
/*
getkey_opt()
Enhances getkey() with most general functionalities.
Enhances getkey() with most general functionalities. An OR-combination
of options may be given as second argument.
If max_cycles is non-zero and positive, getkey_opt() will return
KEY_NOEVENT if no event occurs during max_cycle analysis.
@arg options OR-combination of GetkeyOpt values.
@arg max_cycles
@return Pressed key matrix code.
As getkey(), returns the pressed key matrix code, possibly with
modifiers depending on the options.
*/
int getkey_opt(enum GetkeyOpt options, int max_cycles);
/*
multigetkey()
Listens the keyboard for simultaneous key hits. Uses the same options
as getkey_opt().
multigetkey() fills the 'keys' array with 'count' key codes, adding
KEY_NONE if less than 'count' keys are pressed.
Be aware that rectangle and column effects can make multigetkey() read
unpressed keys as pressed (see documentation for more information).
Setting count = 3 is generally safe.
@arg keys Key code array.
@arg count Maximum number of keys that will be read.
@arg max_cycles
Listens the keyboard for simultaneous key hits. This functions fills
array `keys` with `count` keycodes, adding KEY_NONE at the end if
more than `count` keys are pressed.
If `max_cycles` is non-zero and nothing happens after `max_cycles`
cycles, this function returns an array of KEY_NONE.
WARNING:
Because of hardware limitations, this function generally yields poor
results. Rectangle and column effects make it read unpressed keys as
pressed (see documentation for more information). The more pressed
keys, the more errors.
The results are guaranteed to be exact if two keys or less are pressed.
With three keys or more, column effects (on SH4) and rectangle effects
(on both platforms) mess up the results by making this function think
that some keys that are actually unpressed, are pressed.
This function is designed to make combinations of one or two arrow keys
with another key as viable as possible. On SH4, this works pretty well
even if combinations like Left + Down + SHIFT trigger ALPHA sometimes.
On SH3, rectangle effects are *always* present, making it impossible to
use Left + Down or Up + Right with any other key in their rows without
having this function return junk.
Any other combination of keys may quite randomly result in variably
incorrect results. Please do not expect multigetkey() to work as an
ideal multi-key analyzer.
*/
void multigetkey(int *keys, int count, int max_cycles);

View File

@ -63,4 +63,18 @@ void free(void *ptr);
//---
// Integer arithmetic.
//---
/*
abs()
Returns the absolute value of an integer.
*/
int abs(int x);
// Use a macro instead, when possible.
#define abs(x) ((x) < 0 ? -(x) : (x))
#endif // _STDLIB_H

View File

@ -77,7 +77,7 @@ struct Font
uint16_t index[16];
__attribute__((aligned(4))) const struct FontGlyph glyphs[];
__attribute__((aligned(4))) const uint32_t glyphs[];
} __attribute__((aligned(4)));
// Useful shorthand for user code.
@ -91,27 +91,22 @@ typedef struct Font Font;
/*
text_configure()
Sets the font and mode to use for the following print operations.
Sets the font and color to use for subsequent text operations. Pass
font = NULL to use the default font.
*/
void text_configure(struct Font *font);
/*
text_configure_default()
Configures tales with the default font (which is part of gint).
*/
void text_configure_default(void) __attribute__((constructor));
void text_configure(struct Font *font, enum Color color);
/*
dtext()
Prints the given string, without any analysis.
*/
void dtext(const char *str, int x, int y);
void dtext(int x, int y, const char *str);
/*
gtext()
Prints the given raw string.
*/
void gtext(const char *str, int x, int y);
void gtext(int x, int y, const char *str);
/*
dprint()

BIN
libc.a

Binary file not shown.

BIN
libgint.a

Binary file not shown.

View File

@ -18,14 +18,14 @@ void bopti_op_mono(int offset, uint32_t operator, struct Command *c)
switch(c->channel)
{
case Channel_Mono:
bopti_vram[offset] |= operator;
break;
case Channel_FullAlpha:
bopti_vram[offset] &= ~operator;
break;
case Channel_Mono:
bopti_vram[offset] |= operator;
break;
default:
break;
}
@ -36,6 +36,15 @@ void bopti_op_gray(int offset, uint32_t operator, struct Command *c)
switch(c->channel)
{
case Channel_FullAlpha:
bopti_v1[offset] &= ~operator;
bopti_v2[offset] &= ~operator;
break;
case Channel_LightAlpha:
case Channel_DarkAlpha:
break;
case Channel_Mono:
bopti_v1[offset] |= operator;
bopti_v2[offset] |= operator;
@ -48,15 +57,6 @@ void bopti_op_gray(int offset, uint32_t operator, struct Command *c)
case Channel_Dark:
bopti_v2[offset] |= operator;
break;
case Channel_FullAlpha:
bopti_v1[offset] &= ~operator;
bopti_v2[offset] &= ~operator;
break;
case Channel_LightAlpha:
case Channel_DarkAlpha:
break;
}
}

View File

@ -5,7 +5,7 @@
dimage()
Displays a monochrome image in the video ram.
*/
void dimage(struct Image *img, int x, int y)
void dimage(int x, int y, struct Image *img)
{
if(img->magic != 0xb7) return;

65
src/bopti/dimage_part.c Normal file
View File

@ -0,0 +1,65 @@
#include <internals/bopti.h>
#include <internals/display.h>
/*
dimage_part()
Draws a portion of an image, defined by its bounding rectangle.
Point (left, top) is included, but (left + width, top + height) is
excluded.
*/
void dimage_part(int x, int y, struct Image *img, int left, int top,
int width, int height)
{
if(img->magic != 0xb7) return;
struct Structure s;
struct Command command;
int actual_width;
int format = img->format, i = 0;
if(format != Format_Mono && format != Format_MonoAlpha) return;
getStructure(img, &s);
//---
// Adjusting the bounding rectangle.
//---
// This is what happens when the bounding rectangle overflows from the
// image...
if(left < 0) left = 0;
if(top < 0) top = 0;
if(left + width > s.width) width = s.width - left;
if(top + height > s.height) height = s.height - top;
if(x + left + width <= 0 || x > 127 || y + top + height <= 0 || y > 63)
return;
command.top = (y < 0) ? (top - y) : top;
command.bottom = top + ((y + height > 64) ? (64 - y) : height);
command.left = ((x < 0) ? (left - x) : left) >> 5;
actual_width = (x + width > 128) ? (128 - x) : width;
command.right = left + ((actual_width + 31) >> 5) - 1;
command.op = bopti_op_mono;
if(x >= 0) getMasks(x, x + actual_width - 1, command.masks);
else getMasks(0, actual_width + x - 1, command.masks);
bopti_vram = display_getCurrentVRAM();
while(format)
{
if(format & 1)
{
command.x = x - left;
command.y = y - top;
command.channel = (1 << i);
bopti(s.data, &s, &command);
s.data += s.layer_size;
}
format >>= 1;
i++;
}
}

View File

@ -6,7 +6,7 @@
gimage()
Displays a gray image in the video ram.
*/
void gimage(struct Image *img, int x, int y)
void gimage(int x, int y, struct Image *img)
{
if(img->magic != 0xb7) return;
@ -21,7 +21,7 @@ void gimage(struct Image *img, int x, int y)
// Adjusting image parameters.
//---
if(x + s.width < 0 || x > 127 || y + s.height < 0 || y > 63) return;
if(x + s.width <= 0 || x > 127 || y + s.height <= 0 || y > 63) return;
command.top = (y < 0) ? (-y) : (0);
command.bottom = (y + s.height > 64) ? (64 - y) : (s.height);

85
src/bopti/gimage_part.c Normal file
View File

@ -0,0 +1,85 @@
#include <internals/bopti.h>
#include <internals/display.h>
#include <gray.h>
/*
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))
struct Rect
{
int top, bottom;
int left, right;
};
struct Rect intersect(struct Rect r1, struct Rect r2)
{
struct Rect result;
result.top = max(r1.top, r2.top);
result.bottom = min(r1.bottom, r2.bottom);
result.left = max(r1.left, r2.left);
result.right = min(r1.right, r2.right);
}
*/
/*
gimage_part()
Draws a portion of a gray image, defined by its bounding rectangle.
Point (left, top) is included, but (left + width, top + height) is
excluded.
*/
void gimage_part(int x, int y, struct Image *img, int left, int top,
int width, int height)
{
if(img->magic != 0xb7) return;
struct Structure s;
struct Command command;
int actual_width;
int format = img->format, i = 0;
getStructure(img, &s);
//---
// Adjusting the bounding rectangle.
//---
// This is what happens when the bounding rectangle overflows from the
// image...
if(left < 0) left = 0;
if(top < 0) top = 0;
if(left + width > s.width) width = s.width - left;
if(top + height > s.height) height = s.height - top;
if(x + left + width <= 0 || x > 127 || y + top + height <= 0 || y > 63)
return;
command.top = (y < 0) ? (top - y) : top;
command.bottom = top + ((y + height > 64) ? (64 - y) : height);
command.left = ((x < 0) ? (left - x) : left) >> 5;
actual_width = (x + width > 128) ? (128 - x) : width;
command.right = left + ((actual_width + 31) >> 5) - 1;
command.op = bopti_op_gray;
if(x >= 0) getMasks(x, x + actual_width - 1, command.masks);
else getMasks(0, actual_width + x - 1, command.masks);
bopti_v1 = gray_lightVRAM();
bopti_v2 = gray_darkVRAM();
while(format)
{
if(format & 1)
{
command.x = x - left;
command.y = y - top;
command.channel = (1 << i);
bopti(s.data, &s, &command);
s.data += s.layer_size;
}
format >>= 1;
i++;
}
}

View File

@ -110,7 +110,7 @@ void gint_quit(void)
//---
#include <display.h>
#define print(str, x, y) dtext(str, 6 * (x) - 5, 8 * (y) - 7)
#define print(str, x, y) dtext(6 * (x) - 5, 8 * (y) - 7, str)
#define hexdigit(n) ((n) + '0' + 39 * ((n) > 9))
void hex(unsigned int x, int digits, char *str)
@ -138,7 +138,7 @@ void gint_exc(void)
unsigned int spc;
char str[11];
text_configure_default();
text_configure(NULL, Color_Black);
__asm__("\tstc spc, %0" : "=r"(spc));
@ -175,7 +175,7 @@ void gint_tlb(void)
unsigned int spc;
char str[11];
text_configure_default();
text_configure(NULL, Color_Black);
__asm__("\tstc spc, %0" : "=r"(spc));
@ -242,5 +242,5 @@ const char *gint_strerror(int is_tlb)
if(isSH3())
return gint_strerror_7705(is_tlb);
else
return gint_strerror_7305(is_tlb);
return gint_strerror_7305();
}

View File

@ -25,13 +25,6 @@ _malloc:
nop
1: .long 0xacd
_calloc:
mov.l syscall_table, r2
mov.l 1f, r0
jmp @r2
nop
1: .long 0xe6b
_free:
mov.l syscall_table, r2
mov.l 1f, r0

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

@ -11,7 +11,11 @@ void gline(int x1, int y1, int x2, int y2, enum Color color)
if(color == Color_None) return;
else if(color == Color_Invert) c1 = c2 = Color_Invert;
else c1 = color & 1, c2 = color >> 1;
else
{
c1 = 3 * (color & 1);
c2 = 3 * (color >> 1);
}
display_useVRAM(gray_lightVRAM());
dline(x1, y1, x2, y2, c1);

View File

@ -22,7 +22,7 @@
Should sleep during a few milliseconds. Well...
This delay has a great influence on key detection. Here are a few
observations of what happens with common numbers of "nop" (without
overclock). Take care of the effect of overclock !
overclock). Take care of the effect of overclock!
Column effects
May have something to do with register HIZCRB not being used here. When
@ -48,9 +48,7 @@ static void kdelay(void)
__asm__
(
r4("nop\n\t")
r4("nop\n\t")
r4("nop\n\t")
"nop\n\t"
);
#undef r4
@ -142,5 +140,10 @@ void keyboard_updateState_7305(volatile unsigned char *keyboard_state)
{
int i;
for(i = 0; i < 10; i++) keyboard_state[i] = krow(i);
keyboard_state[8] = krow(8);
for(i = 0; i < 10; i++)
{
if(i != 7 && i != 8) keyboard_state[i] = krow(i);
}
keyboard_state[7] = krow(7);
}

View File

@ -30,8 +30,6 @@ static void kdelay(void)
__asm__
(
r4("nop\n\t")
r4("nop\n\t")
r4("nop\n\t")
);
#undef r4

View File

@ -83,12 +83,8 @@ volatile void *gint_reg_7305(enum Register reg)
gint_strerror()
Returns a string that describe the error set in EXPEVT. This string is
not platform-dependent.
Some exception codes represent different errors when invoked inside the
general exception handler and the TLB error handler. Parameter 'is_tlb'
should be set to zero for general exception meanings, and anything non-
zero for TLB error meanings.
*/
const char *gint_strerror_7305(int is_tlb)
const char *gint_strerror_7305(void)
{
volatile unsigned int *expevt = gint_reg_7305(Register_EXPEVT);

View File

@ -165,7 +165,6 @@ static struct Format get_format(const char **pointer)
const char *string = *pointer, *ptr;
int c, i;
char precision[10];
// Moving the string pointer after the '%' character.
string++;
@ -601,7 +600,6 @@ static void format_u(struct Format format)
int bspaces, zeros, digits = 0, espaces;
int x = format._unsigned;
int multiplier = 1;
int c;
// Computing number of digits.
if(!x) digits = 1;

7
src/stdlib/abs.c Normal file
View File

@ -0,0 +1,7 @@
#include <stdlib.h>
#undef abs
int abs(int x)
{
return (x < 0) ? (-x) : (x);
}

12
src/stdlib/calloc.c Normal file
View File

@ -0,0 +1,12 @@
#include <stdlib.h>
/*
calloc()
Allocates 'n' elements of size 'size' and wipes the memory area.
Returns NULL on error.
*/
void *calloc(size_t n, size_t size)
{
void *ptr = malloc(n * size);
return ptr ? memset(ptr, 0, n * size) : NULL;
}

View File

@ -6,6 +6,6 @@
*/
const char *strchr(const char *str, int value)
{
while(*str && *str != value) *str++;
while(*str && *str != value) str++;
return *str ? str : NULL;
}

View File

@ -1,92 +0,0 @@
#include <internals/tales.h>
#include <tales.h>
#include <stdlib.h>
#include <string.h>
#include <alloca.h>
/*
dtext()
Prints the given string, without any analysis.
*/
void dtext(const char *str, int x, int y)
{
// Operator data, and number of available bits in the operators (which
// is the same for all operators, since they are treated equally).
uint32_t *operators;
int available;
// Raw glyph data, each glyph being represented by one or several
// longwords, and an index in this array.
uint32_t *data = (uint32_t *)font->glyphs;
int index;
// Height of each glyph. This value is constant because the storage
// format requires it: it allows greater optimization.
int height;
int i;
if(!font) return;
// Allocating data. There will be one operator for each line.
height = font->data_height;
if(x > 127 || y > 63 || y <= -height) return;
operators = alloca(height * sizeof(uint32_t));
for(i = 0; i < height; i++) operators[i] = 0;
if(!operators) return;
// Computing the initial operator offset to have 32-aligned operators.
// This allows to write directly video ram longs instead of having to
// shift operators, and do all the vram operation twice.
available = 32 - (x & 31);
x &= ~31;
// Displaying character after another.
while(*str)
{
index = getCharacterIndex(*str++);
if(index < 0) continue;
// Updating the operators.
available = update(operators, height, available, data + index);
// Continue until operators are full (this includes an
// additional bit to add a space between each character).
if(available > 1)
{
available--;
continue;
}
// When operators are full, updating the video ram and
// preparing the operators for another row.
operate(operators, height, x, y);
x += 32;
if(x > 96) break;
memset(operators, 0, height << 2);
if(available >= 0)
{
available = 31 + available;
continue;
}
// Finishing update, in case it has been only partially done,
// because there was not enough bits available to fit all the
// information. Also adding a space, assuming that characters
// aren't more than 30 bits wide.
available += 32 + (data[index] >> 24);
available = update(operators, height, available, data + index);
available--;
}
// Final operation.
if(x <= 96 && available < 32) operate(operators, height, x, y);
// free(operators);
}

View File

@ -2,17 +2,3 @@
#include <internals/stdio.h>
#include <stdarg.h>
/*
gprint()
Prints a formatted string. Works the same as printf().
*/
void gprint(int x, int y, const char *format, ...)
{
va_list args;
va_start(args, format);
__printf(0, format, args);
va_end(args);
gtext(__stdio_buffer, x, y);
}

View File

@ -1,14 +0,0 @@
#include <tales.h>
#include <gray.h>
/*
gtext()
Prints the given raw string.
*/
void gtext(const char *str, int x, int y)
{
display_useVRAM(gray_lightVRAM());
dtext(str, x, y);
display_useVRAM(gray_darkVRAM());
dtext(str, x, y);
}

View File

@ -5,17 +5,11 @@
text_configure()
Sets the font and mode to use for the following print operations.
*/
void text_configure(struct Font *next_font)
{
font = next_font;
}
/*
text_configure_default()
Configures tales with the default font (which is part of gint).
*/
void text_configure_default(void)
void text_configure(struct Font *next_font, enum Color next_color)
{
extern Font gint_font_system_start;
text_configure(&gint_font_system_start);
if(next_font) font = next_font;
else font = &gint_font_system_start;
color = next_color;
}

View File

@ -1,7 +1,20 @@
#include <internals/tales.h>
#include <alloca.h>
#include <string.h>
#include <ctype.h>
#include <gray.h>
struct Font *font;
enum Color color;
/*
tales_init()
Configures tales with the default font (which is part of gint).
*/
void tales_init(void)
{
text_configure(NULL, Color_Black);
}
/*
getCharacterIndex()
@ -78,16 +91,72 @@ int getCharacterIndex(int c)
Operates on the vram using the given operators. The x-coordinate should
be a multiple of 32. There should be `height` operators.
*/
void operate(uint32_t *operators, int height, int x, int y)
void operate_mono(OPERATE_ARGS)
{
int *vram = display_getCurrentVRAM();
int vram_offset = (x >> 5) + (y << 2);
uint32_t op;
int i;
for(i = 0; i < height; i++)
{
// TODO BLENDING MODES //
vram[vram_offset] |= operators[i];
op = operators[i];
switch(color)
{
case Color_White:
vram[vram_offset] &= ~op;
break;
case Color_Black:
vram[vram_offset] |= op;
break;
case Color_Invert:
vram[vram_offset] ^= op;
break;
default:
break;
}
vram_offset += 4;
}
}
void operate_gray(OPERATE_ARGS)
{
int *vl = gray_lightVRAM();
int *vd = gray_darkVRAM();
int vram_offset = (x >> 5) + (y << 2);
uint32_t op;
int i;
for(i = 0; i < height; i++)
{
op = operators[i];
switch(color)
{
case Color_White:
vl[vram_offset] &= ~op;
vd[vram_offset] &= ~op;
break;
case Color_Light:
vl[vram_offset] |= op;
vd[vram_offset] &= ~op;
break;
case Color_Dark:
vl[vram_offset] &= ~op;
vd[vram_offset] |= op;
break;
case Color_Black:
vl[vram_offset] |= op;
vd[vram_offset] |= op;
break;
case Color_Invert:
vl[vram_offset] ^= op;
vd[vram_offset] ^= op;
break;
default:
break;
}
vram_offset += 4;
}
@ -162,3 +231,88 @@ int update(uint32_t *operators, int height, int available,
return available - width;
}
/*
render()
Renders text without any formatting analysis, using the given operation
function.
*/
void render(int x, int y, const char *str, void (*op)(OPERATE_ARGS))
{
// Operator data, and number of available bits in the operators (which
// is the same for all operators, since they are treated equally).
uint32_t *operators;
int available;
// Raw glyph data, each glyph being represented by one or several
// longwords, and an index in this array.
uint32_t *data = (uint32_t *)font->glyphs;
int index;
// Height of each glyph. This value is constant because the storage
// format requires it: it allows greater optimization.
int height;
int i;
if(!font) return;
// Allocating data. There will be one operator for each line.
height = font->data_height;
if(x > 127 || y > 63 || y <= -height) return;
operators = alloca(height * sizeof(uint32_t));
for(i = 0; i < height; i++) operators[i] = 0;
if(!operators) return;
// Computing the initial operator offset to have 32-aligned operators.
// This allows to write directly video ram longs instead of having to
// shift operators, and do all the vram operation twice.
available = 32 - (x & 31);
x &= ~31;
// Displaying character after another.
while(*str)
{
index = getCharacterIndex(*str++);
if(index < 0) continue;
// Updating the operators.
available = update(operators, height, available, data + index);
// Continue until operators are full (this includes an
// additional bit to add a space between each character).
if(available > 1)
{
available--;
continue;
}
// When operators are full, updating the video ram and
// preparing the operators for another row.
(*op)(operators, height, x, y);
x += 32;
if(x > 96) break;
memset(operators, 0, height << 2);
if(available >= 0)
{
available = 31 + available;
continue;
}
// Finishing update, in case it has been only partially done,
// because there was not enough bits available to fit all the
// information. Also adding a space, assuming that characters
// aren't more than 30 bits wide.
available += 32 + (data[index] >> 24);
available = update(operators, height, available, data + index);
available--;
}
// Final operation.
if(x <= 96 && available < 32) (*op)(operators, height, x, y);
}

View File

@ -14,5 +14,20 @@ void dprint(int x, int y, const char *format, ...)
__printf(0, format, args);
va_end(args);
dtext(__stdio_buffer, x, y);
dtext(x, y, __stdio_buffer);
}
/*
gprint()
Prints a formatted string. Works the same as printf().
*/
void gprint(int x, int y, const char *format, ...)
{
va_list args;
va_start(args, format);
__printf(0, format, args);
va_end(args);
gtext(x, y, __stdio_buffer);
}

23
src/tales/tales_text.c Normal file
View File

@ -0,0 +1,23 @@
#include <internals/tales.h>
#include <tales.h>
#include <display.h>
#include <gray.h>
/*
dtext()
Prints the given string, without any analysis.
*/
void dtext(int x, int y, const char *str)
{
render(x, y, str, operate_mono);
}
/*
gtext()
Prints the given raw string.
*/
void gtext(int x, int y, const char *str)
{
render(x, y, str, operate_gray);
}