diff --git a/Makefile b/Makefile index e358b80..0607f44 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/TODO b/TODO index e2f2ba8..f830f93 100644 --- a/TODO +++ b/TODO @@ -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) diff --git a/demo/gintdemo.c b/demo/gintdemo.c index 4f14e51..19f097b 100644 --- a/demo/gintdemo.c +++ b/demo/gintdemo.c @@ -1,17 +1,11 @@ -#include -#include +#include "gintdemo.h" #include #include #include #include -#include #include -#include -#include -#include <7305.h> - #include @@ -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; } } diff --git a/demo/gintdemo.h b/demo/gintdemo.h new file mode 100644 index 0000000..a7805a3 --- /dev/null +++ b/demo/gintdemo.h @@ -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 diff --git a/demo/resources/bitmap_opt.bmp b/demo/resources/bitmap_opt.bmp deleted file mode 100644 index dd8d123..0000000 Binary files a/demo/resources/bitmap_opt.bmp and /dev/null differ diff --git a/demo/resources/bopti_thumbs.bmp b/demo/resources/bopti_thumbs.bmp new file mode 100644 index 0000000..923b77e Binary files /dev/null and b/demo/resources/bopti_thumbs.bmp differ diff --git a/demo/resources/font_modern.bmp b/demo/resources/font_modern.bmp index 5c1c91b..0340f76 100644 Binary files a/demo/resources/font_modern.bmp and b/demo/resources/font_modern.bmp differ diff --git a/demo/resources/isometric.bmp b/demo/resources/isometric.bmp new file mode 100644 index 0000000..5241b60 Binary files /dev/null and b/demo/resources/isometric.bmp differ diff --git a/demo/resources/items.bmp b/demo/resources/items.bmp index ec6a419..c57f934 100644 Binary files a/demo/resources/items.bmp and b/demo/resources/items.bmp differ diff --git a/demo/resources/opt_bitmap.bmp b/demo/resources/opt_bitmap.bmp new file mode 100644 index 0000000..c776021 Binary files /dev/null and b/demo/resources/opt_bitmap.bmp differ diff --git a/demo/resources/opt_tales.bmp b/demo/resources/opt_tales.bmp new file mode 100644 index 0000000..8f34e47 Binary files /dev/null and b/demo/resources/opt_tales.bmp differ diff --git a/demo/resources/symbol.bmp b/demo/resources/symbol.bmp deleted file mode 100644 index 74772f7..0000000 Binary files a/demo/resources/symbol.bmp and /dev/null differ diff --git a/demo/resources/symbol2.bmp b/demo/resources/symbol2.bmp deleted file mode 100644 index be7ac38..0000000 Binary files a/demo/resources/symbol2.bmp and /dev/null differ diff --git a/demo/resources/zelda.bmp b/demo/resources/zelda.bmp new file mode 100644 index 0000000..03440dd Binary files /dev/null and b/demo/resources/zelda.bmp differ diff --git a/demo/test_bopti.c b/demo/test_bopti.c new file mode 100644 index 0000000..3b9ee45 --- /dev/null +++ b/demo/test_bopti.c @@ -0,0 +1,222 @@ +#include "gintdemo.h" +#include +#include +#include + +#include + +#include + +/* + 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; +} diff --git a/demo/test_gray.c b/demo/test_gray.c new file mode 100644 index 0000000..55c23ef --- /dev/null +++ b/demo/test_gray.c @@ -0,0 +1,93 @@ +#include "gintdemo.h" +#include +#include +#include + +/* + 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(); +} diff --git a/demo/test_keyboard.c b/demo/test_keyboard.c new file mode 100644 index 0000000..a10a78d --- /dev/null +++ b/demo/test_keyboard.c @@ -0,0 +1,82 @@ +#include "gintdemo.h" +#include +#include +#include + +/* + 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(); + } +} diff --git a/demo/test_tales.c b/demo/test_tales.c new file mode 100644 index 0000000..5a94190 --- /dev/null +++ b/demo/test_tales.c @@ -0,0 +1,158 @@ +#include "gintdemo.h" +#include +#include +#include + +#include + +/* + 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); + } +} diff --git a/doc/bopti.md b/doc/bopti.md index 4cb6b2b..b460253 100644 --- a/doc/bopti.md +++ b/doc/bopti.md @@ -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 diff --git a/gintdemo.g1a b/gintdemo.g1a index 10aa989..6c2964e 100644 Binary files a/gintdemo.g1a and b/gintdemo.g1a differ diff --git a/include/display.h b/include/display.h index 2b53a14..a7167a4 100644 --- a/include/display.h +++ b/include/display.h @@ -14,8 +14,6 @@ // Heading declarations. //--- -#include - enum Color { Color_White = 0, @@ -26,6 +24,9 @@ enum Color Color_Invert = 5, }; +// This header needs enum Color to be defined. +#include + /* 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 diff --git a/include/gint.h b/include/gint.h index 8e7fa35..098f9da 100644 --- a/include/gint.h +++ b/include/gint.h @@ -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); //--- diff --git a/include/gray.h b/include/gray.h index de14fba..c77cf83 100644 --- a/include/gray.h +++ b/include/gray.h @@ -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); diff --git a/include/internals/bopti.h b/include/internals/bopti.h index 3ed11cb..7e0009c 100644 --- a/include/internals/bopti.h +++ b/include/internals/bopti.h @@ -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, }; /* diff --git a/include/internals/tales.h b/include/internals/tales.h index 5e101cd..7f5dd26 100644 --- a/include/internals/tales.h +++ b/include/internals/tales.h @@ -13,7 +13,16 @@ #include #include +#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 diff --git a/include/keyboard.h b/include/keyboard.h index b622a6e..7b57390 100644 --- a/include/keyboard.h +++ b/include/keyboard.h @@ -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); diff --git a/include/stdlib.h b/include/stdlib.h index 0eb5591..e77a140 100644 --- a/include/stdlib.h +++ b/include/stdlib.h @@ -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 diff --git a/include/tales.h b/include/tales.h index 5d5c25f..e1304c3 100644 --- a/include/tales.h +++ b/include/tales.h @@ -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() diff --git a/libc.a b/libc.a index ddbff9e..c7e02ab 100644 Binary files a/libc.a and b/libc.a differ diff --git a/libgint.a b/libgint.a index 895e9b7..a2df03c 100644 Binary files a/libgint.a and b/libgint.a differ diff --git a/src/bopti/bopti_internals.c b/src/bopti/bopti_internals.c index bb48bdb..b8c08ce 100644 --- a/src/bopti/bopti_internals.c +++ b/src/bopti/bopti_internals.c @@ -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; } } diff --git a/src/bopti/dimage.c b/src/bopti/dimage.c index d4d300f..9f28532 100644 --- a/src/bopti/dimage.c +++ b/src/bopti/dimage.c @@ -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; diff --git a/src/bopti/dimage_part.c b/src/bopti/dimage_part.c new file mode 100644 index 0000000..d4ce26d --- /dev/null +++ b/src/bopti/dimage_part.c @@ -0,0 +1,65 @@ +#include +#include + +/* + 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++; + } +} diff --git a/src/bopti/gimage.c b/src/bopti/gimage.c index 27df32b..e7499f4 100644 --- a/src/bopti/gimage.c +++ b/src/bopti/gimage.c @@ -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); diff --git a/src/bopti/gimage_part.c b/src/bopti/gimage_part.c new file mode 100644 index 0000000..391c43b --- /dev/null +++ b/src/bopti/gimage_part.c @@ -0,0 +1,85 @@ +#include +#include +#include + +/* +#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++; + } +} diff --git a/src/core/gint.c b/src/core/gint.c index ec5f526..ec3a2cb 100644 --- a/src/core/gint.c +++ b/src/core/gint.c @@ -110,7 +110,7 @@ void gint_quit(void) //--- #include -#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(); } diff --git a/src/core/syscalls.s b/src/core/syscalls.s index ca5397f..621a84a 100644 --- a/src/core/syscalls.s +++ b/src/core/syscalls.s @@ -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 diff --git a/src/display/font_system.bmp b/src/display/font_system.bmp index 0f49d5b..5e7a0a7 100644 Binary files a/src/display/font_system.bmp and b/src/display/font_system.bmp differ diff --git a/src/gray/gline.c b/src/gray/gline.c index bd7cadd..9b31480 100644 --- a/src/gray/gline.c +++ b/src/gray/gline.c @@ -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); diff --git a/src/keyboard/keyboard_sh7305.c b/src/keyboard/keyboard_sh7305.c index 2df0ec6..09ef109 100644 --- a/src/keyboard/keyboard_sh7305.c +++ b/src/keyboard/keyboard_sh7305.c @@ -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); } diff --git a/src/keyboard/keyboard_sh7705.c b/src/keyboard/keyboard_sh7705.c index 4f3b27a..7f0c75c 100644 --- a/src/keyboard/keyboard_sh7705.c +++ b/src/keyboard/keyboard_sh7705.c @@ -30,8 +30,6 @@ static void kdelay(void) __asm__ ( r4("nop\n\t") - r4("nop\n\t") - r4("nop\n\t") ); #undef r4 diff --git a/src/mpu/gint_sh7305.c b/src/mpu/gint_sh7305.c index 03570b3..5a27924 100644 --- a/src/mpu/gint_sh7305.c +++ b/src/mpu/gint_sh7305.c @@ -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); diff --git a/src/stdio/stdio_format.c b/src/stdio/stdio_format.c index 392ddc7..d1f10c7 100644 --- a/src/stdio/stdio_format.c +++ b/src/stdio/stdio_format.c @@ -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; diff --git a/src/stdlib/abs.c b/src/stdlib/abs.c new file mode 100644 index 0000000..3a10e8f --- /dev/null +++ b/src/stdlib/abs.c @@ -0,0 +1,7 @@ +#include +#undef abs + +int abs(int x) +{ + return (x < 0) ? (-x) : (x); +} diff --git a/src/stdlib/calloc.c b/src/stdlib/calloc.c new file mode 100644 index 0000000..9c8421a --- /dev/null +++ b/src/stdlib/calloc.c @@ -0,0 +1,12 @@ +#include + +/* + 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; +} diff --git a/src/string/strchr.c b/src/string/strchr.c index c90725d..7954fcf 100644 --- a/src/string/strchr.c +++ b/src/string/strchr.c @@ -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; } diff --git a/src/tales/dtext.c b/src/tales/dtext.c deleted file mode 100644 index 6d44e2b..0000000 --- a/src/tales/dtext.c +++ /dev/null @@ -1,92 +0,0 @@ -#include -#include - -#include -#include -#include - -/* - 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); -} diff --git a/src/tales/gprint.c b/src/tales/gprint.c index 37e6862..f67f3c1 100644 --- a/src/tales/gprint.c +++ b/src/tales/gprint.c @@ -2,17 +2,3 @@ #include #include -/* - 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); -} diff --git a/src/tales/gtext.c b/src/tales/gtext.c deleted file mode 100644 index b12d483..0000000 --- a/src/tales/gtext.c +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include - -/* - 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); -} diff --git a/src/tales/tales_configuration.c b/src/tales/tales_configuration.c index 394dd0f..916b761 100644 --- a/src/tales/tales_configuration.c +++ b/src/tales/tales_configuration.c @@ -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; } diff --git a/src/tales/tales_internals.c b/src/tales/tales_internals.c index 7e29d3f..a92ccac 100644 --- a/src/tales/tales_internals.c +++ b/src/tales/tales_internals.c @@ -1,7 +1,20 @@ #include +#include +#include #include +#include 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); +} diff --git a/src/tales/dprint.c b/src/tales/tales_print.c similarity index 51% rename from src/tales/dprint.c rename to src/tales/tales_print.c index 5547c52..be3d107 100644 --- a/src/tales/dprint.c +++ b/src/tales/tales_print.c @@ -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); } diff --git a/src/tales/tales_text.c b/src/tales/tales_text.c new file mode 100644 index 0000000..8b7977c --- /dev/null +++ b/src/tales/tales_text.c @@ -0,0 +1,23 @@ +#include +#include + +#include +#include + +/* + 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); +}