diff --git a/include/display/common.h b/include/display/common.h new file mode 100644 index 0000000..a1ec4b2 --- /dev/null +++ b/include/display/common.h @@ -0,0 +1,60 @@ +//--- +// display:common - Internal definitions for common display functions +//--- + +#ifndef DISPLAY_COMMON +#define DISPLAY_COMMON + +#include + +/* dhline() - optimized drawing of a horizontal line + @x1 @x2 @y Coordinates of endpoints of line (both included) + @color Any color suitable for dline() */ +void dhline(int x1, int x2, int y, color_t color); + +/* dvline() - optimized drawing of a vertical line + @y1 @y2 @x Coordinates of endpoints of line (both included) + @color Any color suitable for dline() */ +void dvline(int y1, int y2, int x, color_t color); + +//--- +// Font rendering (topti) +//--- + +/* Current font */ +extern font_t const * topti_font; +/* Default font */ +extern font_t const * gint_default_font; + +/* enum topti_charset: Available character set decoders + Each charset is associated with a reduced character table. */ +enum topti_charset +{ + charset_numeric = 0, /* 10 elements: 0..9 */ + charset_upper = 1, /* 26 elements: A..Z */ + charset_alpha = 2, /* 52 elements: A..Z, a..z */ + charset_alnum = 3, /* 62 elements: A..Z, a..z, 0..9 */ + charset_print = 4, /* 95 elements: 0x20..0x7e */ + charset_ascii = 5, /* 128 elements: 0x00..0x7f */ +}; + +/* charset_size(): Number of elements in each character set + @set Character set ID + Returns the expected number of glyphs, -1 if charset ID is invalid. */ +int charset_size(enum topti_charset set); + +/* charset_decode(): Translate ASCII into reduced character sets + Returns the position of [c] in the character table of the given charset, or + -1 if [c] is not part of that set. + @set Any character set + @c Character to decode */ +int charset_decode(enum topti_charset set, uint c); + +/* topti_offset(): Use a font index to find the location of a glyph + @f Font object + @glyph Glyph number obtained by charset_decode(), must be nonnegative. + Returns the offset the this glyph's data in the font's data array. When + using a proportional font, the size array is not heeded for. */ +int topti_offset(font_t const *f, uint glyph); + +#endif /* DISPLAY_COMMON */ diff --git a/include/display/fx.h b/include/display/fx.h index 289b964..761a3ef 100644 --- a/include/display/fx.h +++ b/include/display/fx.h @@ -24,9 +24,6 @@ @masks Stores the result of the function (four uint32_t values) */ void masks(int x1, int x2, uint32_t *masks); -/* Font currently configured for text rendering */ -extern font_t const * topti_font; - /* bopti_render_clip() - render a bopti image with clipping @x @y Location of the top-left corner @img Image encoded by [fxconv] diff --git a/include/gint/display-cg.h b/include/gint/display-cg.h index 01292c2..de0919e 100644 --- a/include/gint/display-cg.h +++ b/include/gint/display-cg.h @@ -22,11 +22,19 @@ In this module, colors are in the 16-bit R5G6B5 format, as it is the format used by the display controller. */ - #ifdef GINT_NEED_VRAM extern uint16_t *vram; #endif +/* Provide a platform-agnostic definition of color_t. + Some functions also support transparency, in which case they take an [int] + as argument and recognize negative values as transparent. */ +typedef uint16_t color_t; + +enum { + color_none = -1, +}; + //--- // Video RAM management //--- @@ -62,73 +70,6 @@ extern uint16_t *vram; @secondary Additional VRAM area, enables triple buffering if non-NULL */ void dvram(uint16_t *main, uint16_t *secondary); -/* dupdate() - push the video RAM to the display driver - This function makes the contents of the VRAM visible on the screen. It is - the direct equivalent of Bdisp_PutDisp_DD(). - - If triple buffering is enabled (this is the default, and disabled only if - dvram() is used to setup double buffering instead), it also swaps buffers. - Also waits for the previous dupdate() call to finish before executing. */ -void dupdate(void); - -//--- -// Area rendering functions -//--- - -/* dclear() - fill the screen with a single color - This function clears the screen by painting all the pixels in a single, - opaque color. - - @color Any R5G6B5 color */ -void dclear(uint16_t color); - -/* drect() - fill a rectangle of the screen - This functions paints a rectangle in an opaque color. The endpoints (x1 y1) - and (x2 y2) are included in the rectangle. - - @x1 @y1 @x2 @y2 Bounding rectangle (drawn area). - @color Any R5G6B5 color */ -void drect(int x1, int y1, int x2, int y2, uint16_t color); - -//--- -// Point drawing functions -//--- - -/* dpixel() - change a pixel's color - Paints the selected pixel with an opaque color. Setting pixels individually - is a slow method for rendering. Other functions that draw lines, rectangles, - images or text will take advantage of possible optimizations to make the - rendering faster: check them out first. - - @x @y Coordinates of the pixel to repaint - @color Any R5G6B5 color */ -void dpixel(int x, int y, uint16_t color); - -/* dline() - render a straight line - This function draws a line using a Bresenham-style algorithm. Please note - that the affected pixels may not be exactly the same when using dline() and - Bdisp algorithms. - - dline() has optimization facilities for horizontal and vertical lines. The - first kind is about twice as fast, while the second avoids some computation - (the optimization gain is not as significant as on fx9860g). dline() is not - able to clip the line without calculating all the pixels, so drawing a line - from (-1e6,0) to (1e6,395) will work, but will be veeery slow. - - @x1 @y1 @x2 @y2 End points of the line (both included). - @color Any R5G6B5 color */ -void dline(int x1, int y1, int x2, int y2, uint16_t color); - -//--- -// Image rendering (bopti) -//--- - -//--- -// Text rendering (topti) -//--- - -typedef void font_t; - #endif /* FXCG50 */ #endif /* GINT_DISPLAY_CG */ diff --git a/include/gint/display-fx.h b/include/gint/display-fx.h index e7e0426..8e01377 100644 --- a/include/gint/display-fx.h +++ b/include/gint/display-fx.h @@ -31,7 +31,7 @@ extern uint32_t *vram; OPERATORS (combine with existing pixels) none - leaves unchanged - reverse - inverts white <-> black, light <-> dark + invert - inverts white <-> black, light <-> dark lighten - shifts black -> dark -> light -> white -> white darken - shifts white -> light -> dark -> black -> black @@ -47,7 +47,7 @@ typedef enum /* Monochrome operators */ color_none = 4, - color_reverse = 5, + color_invert = 5, /* Gray operators */ color_lighten = 6, @@ -55,59 +55,6 @@ typedef enum } color_t; -//--- -// Area drawing functions -//--- - -/* dupdate() - push the video RAM to the display driver - This function makes the contents of the VRAM visible on the screen. It is - the direct equivalent of Bdisp_PutDisp_DD(). */ -void dupdate(void); - -/* dclear() - fill the screen with a single color - This function clears the screen by replacing all the pixels with a single - color. This function is optimized for opaque drawing. If you wish to apply - operators, use drect(). - - @color Allowed colors: white, black */ -void dclear(color_t color); - -/* drect() - fill a rectangle of the screen - This functions applies a color or an operator to a rectangle defined by two - points (x1 y1) and (x2 y2). Both are included in the rectangle. - - @x1 @y1 @x2 @y2 Bounding rectangle (drawn area). - @color Allowed colors: white, black, none, reverse */ -void drect(int x1, int y1, int x2, int y2, color_t color); - -//--- -// Point drawing functions -//--- - -/* dpixel() - change a pixel's color - If the requested color is an operator, the result will depend on the current - color of the pixel. Setting single pixels is the slowest method to produce a - graphical result: all other functions for rendering lines, rectangles, - images or text use highly-optimized methods, so check them out first if you - care about performance. - - @x @y Coordinates of the pixel to repaint - @color Allowed colors: white, black, none, reverse */ -void dpixel(int x, int y, color_t color); - -/* dline() - render a straight line - This function draws a line using a Bresenham-style algorithm. Please note - that the affected pixels may not be exactly the same when using dline() and - Bdisp_DrawLineVRAM(). - - dline() has optimization facilities for horizontal and vertical lines, but - it does not detect if your line doesn't fit in the screen. So drawing from - (-1e6,0) to (1e6,63) will work, but will be veeery slow. - - @x1 @y1 @x2 @y2 End points of the line (both included). - @color Allowed colors: white, black, none, reverse */ -void dline(int x1, int y1, int x2, int y2, color_t color); - //--- // Image rendering (bopti) //--- @@ -161,99 +108,6 @@ enum { void dimage_opt(int x, int y, image_t const *image, int left, int top, int width, int height, int flags); -//--- -// Text rendering (topti) -//--- - -/* font_t - font data encoded for topti */ -typedef struct -{ - /* Length of font name (not NUL-terminated) */ - uint title :5; - /* Font shape flags */ - uint bold :1; - uint italic :1; - uint serif :1; - uint mono :1; - /* Whether data is variable-length (proportional font) */ - uint prop :1; - /* Reserved for future use */ - uint :2; - /* Implemented charcter set */ - uint charset :4; - /* Line height */ - uint8_t line_height; - /* Storage height */ - uint8_t data_height; - - /* The rest of the data depends on whether the font is proportional */ - union { - /* For monospaced fonts */ - struct { - /* Width of glyphs */ - uint16_t width; - /* Storage size, in longwords, of each glyph */ - uint16_t storage_size; - /* Raw glyph data */ - uint32_t data[]; - }; - /* For proportional fonts */ - struct { - /* Storage index to find glyphs quickly */ - uint16_t index[16]; - /* Size array (padded to 4 bytes), 1 byte per entry, - followed by glyph data */ - uint8_t sized_data[]; - }; - }; - - /* The font name is stored after the data. The size is the length set - in the [title] field, padded to 4 bytes with NULs. There might not - be a NUL at the end. */ - -} GPACKED(4) font_t; - -/* dfont() - set the default font for text rendering - This font will be used by dtext() and sister functions. If font=NULL, gint's - default 5*6 font is used. - - @font Font to use for subsequent text rendering calls */ -void dfont(font_t const * font); - -/* dsize() - get the width and height of rendered text - This function computes the size that the given string would take up if - rendered with a certain font. If you specify a NULL font, the currently - configured font will be used; this differs from dfont() which uses gint's - default font when NULL is passed. - - Note that the height of each glyph is not stored in the font, only the - maximum. Usually this is what you want because vertically-centered strings - must have the same baseline regardless of their contents. So the height - returned by dsize() is the same for all strings, only depends on the font. - - The height is computed in constant time, and the width in linear time. - - @str String whose size must be evaluated - @font Font to use; if NULL, defaults to the current font - @w @h Set to the width and height of the rendered text, may be NULL */ -void dsize(const char *str, font_t const * font, int *w, int *h); - -/* dtext() - display a string of text - - Draws some text in the video RAM using the font set with dfont() (or gint's - default if no such font was set). - - Due to the particular design of topti, this function takes advantage of the - line structure of the VRAM to rendeer several characters at once. This is - not a printf()-family function so [str] cannot contain formats like "%d" - (they will be rendered directly) and cannot receive additional arguments. - - @x @y Coordinates of top-left corner of the rendered string - @str String to display - @fg Text color - @bg Background color, pass [color_none] to disable */ -void dtext(int x, int y, const char *str, color_t fg, color_t bg); - #endif /* FX9860G */ #endif /* GINT_DISPLAY_FX */ diff --git a/include/gint/display.h b/include/gint/display.h index 3e832e5..76d29f1 100644 --- a/include/gint/display.h +++ b/include/gint/display.h @@ -1,5 +1,9 @@ //--- // gint:display - Drawing functions +// +// This module covers the drawing functions that are common to fx9860g and +// fxcg50. Platform-specific definitions are found in +// and . //--- #ifndef GINT_DISPLAY @@ -7,8 +11,8 @@ #include -/* As you would expect, display on fx9860g and display on fxcg50 are completely - different worlds. As a consequence, so are the rendering functions ^^ */ +/* Platform-specific functions include VRAM management and the definition of + the color_t type. */ #ifdef FX9860G #include @@ -18,26 +22,180 @@ #include #endif -#if 0 -/* dinfo_t - summary of information provided by this module */ +/* TODO: dinfo() or similar */ + +//--- +// Video RAM management +//--- + +/* dupdate() - push the video RAM to the display driver + This function makes the contents of the VRAM visible on the screen. It is + the direct equivalent of Bdisp_PutDisp_DD(). + + On fxcg50, if triple buffering is enabled (which is the default and disabled + only by calling dvram()), it also swaps buffers. Due to the DMA being used, + always waits for the previous call to dupdate() call() to finish. */ +void dupdate(void); + +//--- +// Area rendering functions +//--- + +/* dclear() - fill the screen with a single color + This function clears the screen by painting all the pixels in a single + color. It is optimized for opaque colors. + + On fx9860g, use drect() if you need complex operators such as invert. + + @color fx9860g: white, black + fxcg50: Any R5G6B5 color */ +void dclear(color_t color); + +/* drect() - fill a rectangle of the screen + This functions applies a color or an operator to a rectangle defined by two + points (x1 y1) and (x2 y2). Both are included in the rectangle. + + @x1 @y1 @x2 @y2 Bounding rectangle (drawn area). + @color fx9860g: white, black, none, invert + fxcg50: Any R5G6B5 color */ +void drect(int x1, int y1, int x2, int y2, color_t color); + +//--- +// Point drawing functions +//--- + +/* dpixel() - change a pixel's color + Paints the selected pixel with an opaque color. Setting pixels individually + is a slow method for rendering. Other functions that draw lines, rectangles, + images or text will take advantage of possible optimizations to make the + rendering faster: check them out first. + + On fx9860g, if an operator such as invert is used, the result will depend + on the current color of the pixel. + + @x @y Coordinates of the pixel to repaint + @color fx9860g: white, black, none, invert + fxcg50: Any R5G6B5 color */ +void dpixel(int x, int y, color_t color); + +/* dline() - render a straight line + This function draws a line using a Bresenham-style algorithm. Please note + that dline() may not render lines exactly like Bdisp_DrawLineVRAM(). + + dline() has optimization facilities for horizontal and vertical lines. The + speedup for horizontal lines is about x2 on fxcg50 and probably about x30 + on fx9860g. Vertical lines have a smaller speedup. + + dline() is currently not able to clip arbitrary lines without calculating + all the pixels, so drawing a line from (-1e6,0) to (1e6,395) will work but + will be veeery slow. + + @x1 @y1 @x2 @y2 End points of the line (both included). + @color fx9860g: white, black, none, invert + fxcg50: Any R5G6B5 color */ +void dline(int x1, int y1, int x2, int y2, color_t color); + +//--- +// Text rendering (topti) +//--- + +/* font_t - font data encoded for topti */ typedef struct { - /* Screen width, in pixels */ - int width; - /* Screen height, in pixels */ - int height; - /* Color depth (is 1 on fx9860g regardless of the gray engine) */ - int bpp; - /* Current rendering font */ - font_t const * font; + /* Length of font name (not necessarily NUL-terminated!) */ + uint title :5; + /* Font shape flags */ + uint bold :1; + uint italic :1; + uint serif :1; + uint mono :1; + /* Whether data is variable-length (proportional font) */ + uint prop :1; + /* Reserved for future use */ + uint :2; + /* Implemented charcter set */ + uint charset :4; + /* Line height */ + uint8_t line_height; + /* Storage height */ + uint8_t data_height; -} dinfo_t; + /* The rest of the data depends on whether the font is proportional */ + union { + /* For monospaced fonts */ + struct { + /* Width of glyphs */ + uint16_t width; + /* Storage size, in longwords, of each glyph */ + uint16_t storage_size; + /* Raw glyph data */ + uint32_t data[]; + }; + /* For proportional fonts */ + struct { + /* Storage index to find glyphs quickly */ + uint16_t index[16]; + /* Size array (padded to 4 bytes), 1 byte per entry, + followed by glyph data */ + uint8_t sized_data[]; + }; + }; -/* dinfo() - retrieve information from the display module - This function returns the value of most parameters of the display module. + /* The font name is stored after the data. The size is the length set + in the [title] field, padded to 4 bytes with NULs. There might not + be a NUL at the end. */ - @info Pointer to allocated dinfo_t structure, will be filled. */ -void dinfo(dinfo_t *info); -#endif +} GPACKED(4) font_t; + +/* dfont() - set the default font for text rendering + This font will be used by dtext() and sister functions. If [font = NULL], + gint's default font is used. + + On fx9860g, the default font is a 5x7 font very close to the system's. + On fxcg50, the default font is an original 10x12 font. + + @font Font to use for subsequent text rendering calls */ +void dfont(font_t const * font); + +/* dsize() - get the width and height of rendered text + This function computes the size that the given string would take up if + rendered with a certain font. If you specify a NULL font, the currently + configured font will be used; this is different from dfont(), which uses + gint's default font when NULL is passed. + + Note that the height of each glyph is not stored in the font, only the + maximum. Usually this is what you want because vertically-centered strings + must have the same baseline regardless of their contents. So the height + returned by dsize() is the same for all strings, only depends on the font. + + The height is computed in constant time, and the width in linear time. If + [w = NULL], this function returns in constant time. + + @str String whose size must be evaluated + @font Font to use; if NULL, defaults to the current font + @w @h Set to the width and height of the rendered text, may be NULL */ +void dsize(const char *str, font_t const * font, int *w, int *h); + +/* dtext() - display a string of text + + Draws some text in the video RAM using the font set with dfont() (or gint's + default if no such font was set). + + On fx9860g, due to the particular design of topti, this function performs + drastic rendering optimizations using the line structure of the VRAM and is + able to render several characters at once. + + This is not a printf()-family function so [str] cannot contain formats like + "%d" and you cannot pass aditional arguments. + + @x @y Coordinates of top-left corner of the rendered string + @str String to display + @fg Text color + fx9860g: white, black, none, invert + fxcg50: Any R5G6B6 color, or [color_none] + @bg Background color + fx9860g: white, black, none, invert + fxcg50: Any R5G6B5 color, or [color_none] */ +void dtext(int x, int y, const char *str, int fg, int bg); #endif /* GINT_DISPLAY */ diff --git a/include/gint/syscalls.h b/include/gint/syscalls.h index 993e433..247297b 100644 --- a/include/gint/syscalls.h +++ b/include/gint/syscalls.h @@ -1,11 +1,11 @@ //--- -// gint:core:syscalls - calls to CASIOWIN +// gint:syscalls - calls to CASIOWIN //--- -#ifndef GINT_CORE_SYSCALLS -#define GINT_CORE_SYSCALLS +#ifndef GINT_SYSCALLS +#define GINT_SYSCALLS /* __os_version(): Get OS version on the form MM.mm.iiii (10 bytes) */ void __os_version(char *version); -#endif /* GINT_CORE_SYSCALLS */ +#endif /* GINT_SYSCALLS */ diff --git a/make/Makefile b/make/Makefile index 22aec68..0e1affb 100755 --- a/make/Makefile +++ b/make/Makefile @@ -53,8 +53,9 @@ src := $(shell find ../src \ src_obj := $(foreach s,$(src),$(call src2obj,$s)) # Files with special handling -spe := ../src/font5x7.png -spe_obj := version.o $(foreach s,$(spe),$(call src2obj,$s)) +spe-fx := ../src/font5x7.png +spe-cg := ../src/font10x12.png +spe_obj := version.o $(foreach s,$(spe-$(CONFIG.TARGET)),$(call src2obj,$s)) # All object files obj := $(src_obj) $(spe_obj) @@ -107,14 +108,18 @@ $(call src2obj,../src/font5x7.png): ../src/font5x7.png @ mkdir -p $(dir $@) $(call cmd_m,fxconv,font5x7.png)$(conv) -f $< -o $@ name:gint_font5x7 \ charset:ascii grid.size:5x7 grid.padding:1 grid.border:0 +$(call src2obj,../src/font10x12.png): ../src/font10x12.png + @ mkdir -p $(dir $@) + $(call cmd_m,fxconv,font10x12.png)$(conv) -f $< -o $@ name:gint_font10x12 \ + charset:print grid.size:10x12 grid.padding:0 grid.border:3 # Version symbol. ld generates a .stack section for unknown reasons; I remove # it in the linker script. -version.o: +version.o: ../.git/HEAD @ mkdir -p $(dir $@) @ echo "_GINT_VERSION = $(version_hash);" > $@.txt $(call cmd_b,ld,$@) $(ld) -r -R $@.txt -o $@ -.PHONY: version.o + # # Cleaning # diff --git a/src/font10x12.png b/src/font10x12.png new file mode 100644 index 0000000..cb99fb0 Binary files /dev/null and b/src/font10x12.png differ diff --git a/src/font5x7.png b/src/font5x7.png index 4400501..69d2059 100644 Binary files a/src/font5x7.png and b/src/font5x7.png differ diff --git a/src/render-cg/dline.c b/src/render-cg/dline.c index 25a6fd5..ec01ba3 100644 --- a/src/render-cg/dline.c +++ b/src/render-cg/dline.c @@ -1,11 +1,9 @@ #define GINT_NEED_VRAM -#include #include +#include -/* dhline() - optimized drawing of a horizontal line - @x1 @x2 @y Coordinates of endpoints of line (both included) - @color Any R5G6B5 color */ -static void dhline(int x1, int x2, int y, uint16_t color) +/* dhline() - optimized drawing of a horizontal line */ +void dhline(int x1, int x2, int y, uint16_t color) { /* Order and bounds */ if((uint)y >= 224) return; @@ -32,10 +30,8 @@ static void dhline(int x1, int x2, int y, uint16_t color) while(end > start) *--end = op; } -/* dvline() - optimized drawing of a vertical line - @y1 @y2 @x Coordinates of endpoints of line (both included) - @color Any R5G6B5 color */ -static void dvline(int y1, int y2, int x, uint16_t color) +/* dvline() - optimized drawing of a vertical line */ +void dvline(int y1, int y2, int x, uint16_t color) { /* Order and bounds */ if((uint)x >= 395) return; @@ -49,59 +45,3 @@ static void dvline(int y1, int y2, int x, uint16_t color) while(height--) *v = color, v += 396; } -/* dline() - Bresenham line drawing algorithm - Remotely adapted from MonochromeLib code by Pierre "PerriotLL" Le Gall. - Relies on dhline() and dvline() for optimized situations. - @x1 @y1 @x2 @y2 Coordinates of endpoints of line (included) - @color Any R5G6B5 color */ -void dline(int x1, int y1, int x2, int y2, uint16_t color) -{ - /* Possible optimizations */ - if(y1 == y2) - { - dhline(x1, x2, y1, color); - return; - } - if(x1 == x2) - { - dvline(y1, y2, x1, color); - return; - } - - /* Brensenham line drawing algorithm */ - - int i, x = x1, y = y1, cumul; - int dx = x2 - x1, dy = y2 - y1; - int sx = sgn(dx), sy = sgn(dy); - - dx = abs(dx), dy = abs(dy); - - dpixel(x1, y1, color); - - if(dx >= dy) - { - /* Start with a non-zero cumul to even the overdue between the - two ends of the line (for more regularity) */ - cumul = dx >> 1; - for(i = 1; i < dx; i++) - { - x += sx; - cumul += dy; - if(cumul > dx) cumul -= dx, y += sy; - dpixel(x, y, color); - } - } - else - { - cumul = dy >> 1; - for(i = 1; i < dy; i++) - { - y += sy; - cumul += dx; - if(cumul > dy) cumul -= dy, x += sx; - dpixel(x, y, color); - } - } - - dpixel(x2, y2, color); -} diff --git a/src/render-cg/drect.c b/src/render-cg/drect.c index 510d0ee..6384e97 100644 --- a/src/render-cg/drect.c +++ b/src/render-cg/drect.c @@ -21,39 +21,21 @@ void drect(int x1, int y1, int x2, int y2, uint16_t color) uint16_t *base = vram + 396 * y1; int height = y2 - y1 + 1; - /* Do borders first if there are at an odd position */ - - if(x1 & 1) - { - uint16_t *v = base; - for(int h = height; h; h--) - { - v[x1] = color; - v += 396; - } - x1++; - } - - if(x2 & 1) x2++; - else - { - uint16_t *v = base; - for(int h = height; h; h--) - { - v[x2] = color; - v += 396; - } - } - /* Now copy everything that's left as longwords */ - uint32_t *v = (void *)(base + x1); + int ax1 = x1 + (x1 & 1); + int ax2 = (x2 + 1) & ~1; + + uint32_t *v = (void *)(base + ax1); uint32_t op = (color << 16) | color; - int width = (x2 - x1) >> 1; + int width = (ax2 - ax1) >> 1; for(int h = height; h; h--) { + base[x1] = color; + base[x2] = color; for(int w = 0; w < width; w++) v[w] = op; v += 198; + base += 396; } } diff --git a/src/render-cg/topti-asm.h b/src/render-cg/topti-asm.h new file mode 100644 index 0000000..d5d4e1a --- /dev/null +++ b/src/render-cg/topti-asm.h @@ -0,0 +1,29 @@ +//--- +// gint:render-cg:topti-asm - Assembler drawing routines for topti +//--- + +#ifndef GINT_RENDERCG_TOPTIASM +#define GINT_RENDERCG_TOPTIASM + +/* Text rendering functions + + @vram Pointer to VRAM, offset for subglyph position + @data Glyph data, offset for subglyph position + @color topti_glyph_fg: Foreground color + topti_glyph_bg: Background color + topti_glyph_fg_bg: (fg << 16) | bg + @height Subglyph height + @width Sublgyph width + @stride Storage width of subglyph - width + @index Starting index in data, ie. top * storage width + left */ +typedef void asm_text_t(uint16_t *vram, uint32_t const * data, uint32_t color, + int height, int width, int stride, int index); + +/* Opaque foreground, transparent background */ +extern asm_text_t topti_glyph_fg; +/* Transparent foreground, opaque background */ +extern asm_text_t topti_glyph_bg; +/* Opaque foreground, opaque background */ +extern asm_text_t topti_glyph_fg_bg; + +#endif /* GINT_RENDERFX_TOPTIASM */ diff --git a/src/render-cg/topti-asm.s b/src/render-cg/topti-asm.s new file mode 100644 index 0000000..ac3247e --- /dev/null +++ b/src/render-cg/topti-asm.s @@ -0,0 +1,202 @@ +.global _topti_glyph_fg_bg +.global _topti_glyph_fg +.global _topti_glyph_bg +.section .pretext + +# Glyph rendering functions. +# These are pretty naive, using only word accesses to index the VRAM and +# absolute positions to index the glyph data, instead of shiting a single +# longword to real all bits in order. This is because we only render a subglyph +# (for clipping) so there'a non-zero stride in glyph data. + +# Parameters: +# r4: vram +# r5: data +# r6: color (either fg, bg, or (fg << 16) | bg) +# r7: height +# @(4,r15): width +# @(8,r15): dataw - width (stride) +# @(12,r15): starting index in data +# Stack: +# @(0,r15): r8 save + +# Register allocation: +# r0: (temporary) +# r1: (temporary) +# r2: x counter +# r3: glyph data index +# r4: vram pointer +# r5: glyph pointer +# r6: color +# r7: y counter +# Callee-saved registers: +# r8: vram stride + +# Opaque foreground, opaque background + +_topti_glyph_fg_bg: + + # Compute VRAM stride 2 * (396-width) + mov.l r8, @-r15 + mov.l 1f, r8 + mov.l @(4, r15), r3 + shll r3 + sub r3, r8 + + # Load the starting index + mov.l @(12, r15), r3 + +.fg_bg_y: + # Initialize width counter + mov.l @(4, r15), r2 + +.fg_bg_x: + # Load one bit of data in T + mov r3, r0 + mov #-5, r1 + shld r1, r0 + shll2 r0 + mov.l @(r0, r5), r1 + + mov r3, r0 + and #31, r0 + + shld r0, r1 + shll r1 + + # Select the correct 16 bits or r6 + bf/s .fg_bg_zero + mov r6, r1 + swap.w r6, r1 + +.fg_bg_zero: + # Write color to VRAM + mov.w r1, @r4 + add #2, r4 + + # Leave the x-loop if x counter reaches 0 + dt r2 + bf/s .fg_bg_x + add #1, r3 + + # Move to next row, leave the y-loop if height reaches 0 + dt r7 + mov.l @(8, r15), r0 + add r0, r3 + bf/s .fg_bg_y + add r8, r4 + + rts + mov.l @r15+, r8 + +# Opaque foreground, transparent background + +_topti_glyph_fg: + + # Compute VRAM stride 2 * (396-width) + mov.l r8, @-r15 + mov.l 1f, r8 + mov.l @(4, r15), r3 + shll r3 + sub r3, r8 + + # Load the starting index + mov.l @(12, r15), r3 + +.fg_y: + # Initialize width counter + mov.l @(4, r15), r2 + +.fg_x: + # Load one bit of data in T + mov r3, r0 + mov #-5, r1 + shld r1, r0 + shll2 r0 + mov.l @(r0, r5), r1 + + mov r3, r0 + and #31, r0 + + shld r0, r1 + shll r1 + + # Write color to VRAM only if it's a 1 bit + bf .fg_next + mov.w r6, @r4 + +.fg_next: + # Leave the x-loop if x counter reaches 0 + add #2, r4 + dt r2 + bf/s .fg_x + add #1, r3 + + # Move to next row, leave the y-loop if height reaches 0 + dt r7 + mov.l @(8, r15), r0 + add r0, r3 + bf/s .fg_y + add r8, r4 + + rts + mov.l @r15+, r8 + +# Transparent foreground, opaque background + +_topti_glyph_bg: + + # Compute VRAM stride 2 * (396-width) + mov.l r8, @-r15 + mov.l 1f, r8 + mov.l @(4, r15), r3 + shll r3 + sub r3, r8 + + # Load the starting index + mov.l @(12, r15), r3 + +.bg_y: + # Initialize width counter + mov.l @(4, r15), r2 + +.bg_x: + # Load one bit of data in T + mov r3, r0 + mov #-5, r1 + shld r1, r0 + shll2 r0 + mov.l @(r0, r5), r1 + + mov r3, r0 + and #31, r0 + + shld r0, r1 + shll r1 + + # Write color to VRAM only if it's a 0 bit + bt .bg_next + mov.w r6, @r4 + +.bg_next: + # Leave the x-loop if x counter reaches 0 + add #2, r4 + dt r2 + bf/s .bg_x + add #1, r3 + + # Move to next row, leave the y-loop if height reaches 0 + dt r7 + mov.l @(8, r15), r0 + add r0, r3 + bf/s .bg_y + add r8, r4 + + rts + mov.l @r15+, r8 + +# Data + +.align 4 + +1: .long 396*2 diff --git a/src/render-cg/topti.c b/src/render-cg/topti.c new file mode 100644 index 0000000..538b16c --- /dev/null +++ b/src/render-cg/topti.c @@ -0,0 +1,96 @@ +#define GINT_NEED_VRAM +#include +#include +#include +#include +#include "topti-asm.h" + +/* Default font */ +extern font_t gint_font10x12; +font_t const * gint_default_font = &gint_font10x12; +font_t const * topti_font = &gint_font10x12; + +/* topti_glyph(): Render a glyph on the VRAM + Prints a glyph naively using word accesses, because for most fonts with a + small size (including gint's 10x12 font) this will be more efficient than + the complex logic for longword accesses. + + This function assumes that at least one of [fg] and [bg] is not transparent. + + @vram Target position on VRAM, adjusted to [top], not adjusted to [left] + @data Glyph data + @left Left-position of subglyph + @top Top-Position of subglyph + @width Subglyph width + @height Subglyph height + @dataw Glyph width + @fg @bg Foreground and background colors */ +GSECTION(".pretext") +void topti_glyph(uint16_t *vram, uint32_t const * data, int left, int top, + int width, int height, int dataw, int fg, int bg) +{ + int index = top * dataw + left; + + /* Most common situation: opaque text on transparent background */ + if(bg < 0) topti_glyph_fg(vram + left, data, fg, height, width, + dataw - width, index); + /* Full text on opaque background */ + else if(fg >= 0) topti_glyph_fg_bg(vram + left, data, (fg << 16) | bg, + height, width, dataw - width, index); + /* Draw background but not text */ + else topti_glyph_bg(vram + left, data, bg, height, width, + dataw - width, index); +} + +GSECTION(".pretext") +void topti_render(int x, int y, const char *str, size_t size, font_t const *f, + int fg, int bg) +{ + /* Raw glyph data */ + uint32_t const * data = f->prop + ? (void *)(f->sized_data + charset_size(f->charset)) + : f->data; + + /* Storage height, top position within glyph */ + int height = f->data_height, top = 0; + + /* Vertical clipping */ + if(x > 395 || y > 223 || y + height <= 0) return; + if(y + height > 224) height = 224 - y; + if(y < 0) top = -y, height += y, y = 0; + + /* Move to top row */ + uint16_t *target = vram + 396 * y; + + /* Character spacing */ + int space = 2; + + /* Read each character from the input string */ + while(size--) + { + int glyph = charset_decode(f->charset, *str++); + if(glyph < 0) continue; + + int index = topti_offset(f, glyph); + + /* Compute horizontal intersection between glyph and screen */ + + int dataw = f->prop ? f->sized_data[glyph] : f->width; + int width = dataw, left = 0; + + if(x + dataw <= 0) + { + x += dataw + space; + continue; + } + if(x < 0) left = -x, width += x; + if(x + width > 396) width = 396 - x; + + /* Render glyph */ + + topti_glyph(target + x, data + index, left, top, width, height, + dataw, fg, bg); + + x += dataw + space; + } +} diff --git a/src/render-fx/dline.c b/src/render-fx/dline.c index 93d23a9..8eff80b 100644 --- a/src/render-fx/dline.c +++ b/src/render-fx/dline.c @@ -1,11 +1,9 @@ #define GINT_NEED_VRAM -#include #include +#include #include -/* dhline() - optimized drawing of a horizontal line using a rectangle mask - @x1 @x2 @y Coordinates of endpoints of line (both included) - @color Allowed colors: white, black, none, reverse */ +/* dhline() - optimized drawing of a horizontal line using a rectangle mask */ void dhline(int x1, int x2, int y, color_t color) { if((uint)y >= 64) return; @@ -31,7 +29,7 @@ void dhline(int x1, int x2, int y, color_t color) data[2] |= m[2]; data[3] |= m[3]; } - else if(color == color_reverse) + else if(color == color_invert) { data[0] ^= m[0]; data[1] ^= m[1]; @@ -40,92 +38,26 @@ void dhline(int x1, int x2, int y, color_t color) } } -/* dvline() - optimized drawing of a vertical line - This variant is less powerful than dhline() because the line-based structure - of the vram cannot be used here. - @y1 @y2 @x Coordinates of endpoints of line (both included) - @color Allowed colors: black, white, none, reverse */ -void dvline(int y1, int y2, int x, color_t operator) +/* dvline() - optimized drawing of a vertical line */ +void dvline(int y1, int y2, int x, color_t color) { if((uint)x >= 128) return; if(y1 > y2) swap(y1, y2); uint32_t *base = vram + (y1 << 2) + (x >> 5); - uint32_t *lword = base + ((y2 - y1 + 1) << 4); + uint32_t *lword = base + ((y2 - y1 + 1) << 2); uint32_t mask = 1 << (~x & 31); - switch(operator) + if(color == color_white) { - case color_white: while(lword > base) lword -= 4, *lword &= ~mask; - break; - - case color_black: + } + else if(color == color_black) + { while(lword > base) lword -= 4, *lword |= mask; - break; - - case color_reverse: + } + else if(color == color_invert) + { while(lword > base) lword -= 4, *lword ^= mask; - break; - - default: - break; } } - -/* dline() - Bresenham line drawing algorithm - Remotely adapted from MonochromeLib code by Pierre "PerriotLL" Le Gall. - Relies on dhline() and dvline() for optimized situations. - @x1 @y1 @x2 @y2 Coordinates of endpoints of line (included) - @color Allowed colors: black, white, none, reverse */ -void dline(int x1, int y1, int x2, int y2, color_t color) -{ - /* Possible optimizations */ - if(y1 == y2) - { - dhline(x1, x2, y1, color); - return; - } - if(x1 == x2) - { - dvline(y1, y2, x1, color); - return; - } - - /* Brensenham line drawing algorithm */ - - int i, x = x1, y = y1, cumul; - int dx = x2 - x1, dy = y2 - y1; - int sx = sgn(dx), sy = sgn(dy); - - dx = abs(dx), dy = abs(dy); - - dpixel(x1, y1, color); - - if(dx >= dy) - { - /* Start with a non-zero cumul to even the overdue between the - two ends of the line (for more regularity) */ - cumul = dx >> 1; - for(i = 1; i < dx; i++) - { - x += sx; - cumul += dy; - if(cumul > dx) cumul -= dx, y += sy; - dpixel(x, y, color); - } - } - else - { - cumul = dy >> 1; - for(i = 1; i < dy; i++) - { - y += sy; - cumul += dx; - if(cumul > dy) cumul -= dy, x += sx; - dpixel(x, y, color); - } - } - - dpixel(x2, y2, color); -} diff --git a/src/render-fx/dpixel.c b/src/render-fx/dpixel.c index 51d3c96..abfa8df 100644 --- a/src/render-fx/dpixel.c +++ b/src/render-fx/dpixel.c @@ -11,18 +11,16 @@ void dpixel(int x, int y, color_t color) uint32_t *lword = vram + (y << 2) + (x >> 5); uint32_t mask = 1 << (~x & 31); - switch(color) + if(color == color_white) { - case color_white: *lword &= ~mask; - break; - case color_black: + } + else if(color == color_black) + { *lword |= mask; - break; - case color_reverse: + } + else if(color == color_invert) + { *lword ^= mask; - break; - default: - return; } } diff --git a/src/render-fx/drect.c b/src/render-fx/drect.c index 6d4ce82..e33eac5 100644 --- a/src/render-fx/drect.c +++ b/src/render-fx/drect.c @@ -37,7 +37,7 @@ void drect(int x1, int y1, int x2, int y2, color_t color) *--lword |= m[1]; *--lword |= m[0]; } - else if(color == color_reverse) while(lword > base) + else if(color == color_invert) while(lword > base) { *--lword ^= m[3]; *--lword ^= m[2]; diff --git a/src/render-fx/topti-asm.s b/src/render-fx/topti-asm.s index a2fae15..11bac42 100644 --- a/src/render-fx/topti-asm.s +++ b/src/render-fx/topti-asm.s @@ -94,7 +94,7 @@ _topti_asm_none: nop .align 4 -_topti_asm_reverse: +_topti_asm_invert: 1: mov.l @r6+, r0 dt r7 mov.l @r4, r1 @@ -165,7 +165,7 @@ _topti_asm_text: .long _topti_asm_dark .long _topti_asm_black .long _topti_asm_none - .long _topti_asm_reverse + .long _topti_asm_invert .long _topti_asm_lighten .long _topti_asm_darken diff --git a/src/render-fx/topti.c b/src/render-fx/topti.c index 16b73b3..cea4803 100644 --- a/src/render-fx/topti.c +++ b/src/render-fx/topti.c @@ -2,104 +2,14 @@ #include #include #include +#include #include "topti-asm.h" /* Default font */ extern font_t gint_font5x7; +font_t const * gint_default_font = &gint_font5x7; font_t const * topti_font = &gint_font5x7; -/* dfont() - set the default font for text rendering */ -GSECTION(".pretext") -void dfont(font_t const * font) -{ - topti_font = font ? font : &gint_font5x7; -} - -/* enum charset: Available character set decoders - Each charset is associated with a reduced character table. */ -enum charset -{ - charset_numeric = 0, /* 10 elements: 0..9 */ - charset_upper = 1, /* 26 elements: A..Z */ - charset_alpha = 2, /* 52 elements: A..Z, a..z */ - charset_alnum = 3, /* 62 elements: A..Z, a..z, 0..9 */ - charset_print = 4, /* 95 elements: 0x20..0x7e */ - charset_ascii = 5, /* 128 elements: 0x00..0x7f */ -}; - -/* charset_size(): Number of elements in each character set - @set Character set ID - Returns the expected number of glyphs, -1 if charset ID is invalid. */ -GSECTION(".pretext") -int charset_size(enum charset set) -{ - int size[] = { 10, 26, 52, 62, 95, 128 }; - return (uint)set < 6 ? size[set] : -1; -} - -/* charset_decode(): Translate ASCII into reduced character sets - Returns the position of [c] in the character table of the given charset, or - -1 if [c] is not part of that set. - @set Any character set - @c Character to decode */ -GSECTION(".pretext") -int charset_decode(enum charset set, uint c) -{ - int x, y; - - switch(set) - { - case charset_numeric: - x = c - '0'; - return (x < 10) ? x : -1; - case charset_upper: - x = (c - 'A') & ~0x20; - return (x < 26) ? x : -1; - case charset_alnum: - x = c - '0'; - if(x < 10) return x; - /* Intentional fallthrough */ - case charset_alpha: - y = c & 0x20; - x = (c ^ y) - 'A'; - /* Turn 32 into 26 and leave 0 as 0 */ - y = y - (y >> 3) - (y >> 4); - return (x < 26) ? (x + y) : -1; - case charset_print: - x = c - 0x20; - return (x < 0x5f) ? x : -1; - case charset_ascii: - return c; - } - - return -1; -} - -/* topti_offset(): Use a font index to find the location of a glyph - @f Font object - @glyph Glyph number obtained by charset_decode(), must be nonnegative. - Returns the offset the this glyph's data in the font's data array. When - using a proportional font, the size array is not heeded for. */ -GSECTION(".pretext") -int topti_offset(font_t const *f, uint glyph) -{ - /* Non-proportional fonts don't need an index */ - if(!f->prop) return glyph * f->storage_size; - - uint8_t const *width = f->sized_data; - - /* The index gives us the position of all glyphs whose IDs are mutiples - of 8. Start with a close one and iterate from there. */ - uint g = glyph & ~0x7; - int offset = f->index[g >> 3]; - - /* Traverse the width array (which is in bits) while converting to - longword size */ - while(g < glyph) offset += (width[g++] * f->data_height + 31) >> 5; - - return offset; -} - /* topti_split(): Split glyph data into lines This function splits the data from [glyph] inyo lines and writes a bit of each line in [operators]. This operation is meant to be used multiple times @@ -299,7 +209,7 @@ void dsize(const char *str, font_t const * f, int *w, int *h) /* dtext() - display a string of text */ GSECTION(".pretext") -void dtext(int x, int y, const char *str, color_t fg, color_t bg) +void dtext(int x, int y, const char *str, int fg, int bg) { if((uint)fg >= 8 || (uint)bg >= 8) return; topti_render(x, y, str, topti_font, topti_asm_text[fg], diff --git a/src/render/dline.c b/src/render/dline.c new file mode 100644 index 0000000..2a2c016 --- /dev/null +++ b/src/render/dline.c @@ -0,0 +1,60 @@ +#include +#include +#include + +/* dline() - Bresenham line drawing algorithm + Remotely adapted from MonochromeLib code by Pierre "PerriotLL" Le Gall. + Relies on platform-dependent dhline() and dvline() for optimized situations. + @x1 @y1 @x2 @y2 Coordinates of endpoints of line (included) + @color Any R5G6B5 color */ +void dline(int x1, int y1, int x2, int y2, color_t color) +{ + /* Possible optimizations */ + if(y1 == y2) + { + dhline(x1, x2, y1, color); + return; + } + if(x1 == x2) + { + dvline(y1, y2, x1, color); + return; + } + + /* Brensenham line drawing algorithm */ + + int i, x = x1, y = y1, cumul; + int dx = x2 - x1, dy = y2 - y1; + int sx = sgn(dx), sy = sgn(dy); + + dx = abs(dx), dy = abs(dy); + + dpixel(x1, y1, color); + + if(dx >= dy) + { + /* Start with a non-zero cumul to even the overdue between the + two ends of the line (for more regularity) */ + cumul = dx >> 1; + for(i = 1; i < dx; i++) + { + x += sx; + cumul += dy; + if(cumul > dx) cumul -= dx, y += sy; + dpixel(x, y, color); + } + } + else + { + cumul = dy >> 1; + for(i = 1; i < dy; i++) + { + y += sy; + cumul += dx; + if(cumul > dy) cumul -= dy, x += sx; + dpixel(x, y, color); + } + } + + dpixel(x2, y2, color); +} diff --git a/src/render/topti.c b/src/render/topti.c new file mode 100644 index 0000000..037097c --- /dev/null +++ b/src/render/topti.c @@ -0,0 +1,73 @@ +#include +#include +#include + +/* dfont(): Set the default font for text rendering */ +GSECTION(".pretext") +void dfont(font_t const * font) +{ + topti_font = font ? font : gint_default_font; +} + +/* charset_size(): Number of elements in each character set */ +GSECTION(".pretext") +int charset_size(enum topti_charset set) +{ + int size[] = { 10, 26, 52, 62, 95, 128 }; + return (uint)set < 6 ? size[set] : -1; +} + +/* charset_decode(): Translate ASCII into reduced character sets */ +GSECTION(".pretext") +int charset_decode(enum topti_charset set, uint c) +{ + int x, y; + + switch(set) + { + case charset_numeric: + x = c - '0'; + return (x < 10) ? x : -1; + case charset_upper: + x = (c - 'A') & ~0x20; + return (x < 26) ? x : -1; + case charset_alnum: + x = c - '0'; + if(x < 10) return x; + /* Intentional fallthrough */ + case charset_alpha: + y = c & 0x20; + x = (c ^ y) - 'A'; + /* Turn 32 into 26 and leave 0 as 0 */ + y = y - (y >> 3) - (y >> 4); + return (x < 26) ? (x + y) : -1; + case charset_print: + x = c - 0x20; + return (x < 0x5f) ? x : -1; + case charset_ascii: + return c; + } + + return -1; +} + +/* topti_offset(): Use a font index to find the location of a glyph */ +GSECTION(".pretext") +int topti_offset(font_t const *f, uint glyph) +{ + /* Non-proportional fonts don't need an index */ + if(!f->prop) return glyph * f->storage_size; + + uint8_t const *width = f->sized_data; + + /* The index gives us the position of all glyphs whose IDs are mutiples + of 8. Start with a close one and iterate from there. */ + uint g = glyph & ~0x7; + int offset = f->index[g >> 3]; + + /* Traverse the width array (which is in bits) while converting to + longword size */ + while(g < glyph) offset += (width[g++] * f->data_height + 31) >> 5; + + return offset; +}