render: refactor to share functions, and basic text on fxcg50

This commit is contained in:
lephe 2019-06-15 01:04:38 -04:00
parent 81baa4c26a
commit 0055199359
21 changed files with 759 additions and 522 deletions

60
include/display/common.h Normal file
View file

@ -0,0 +1,60 @@
//---
// display:common - Internal definitions for common display functions
//---
#ifndef DISPLAY_COMMON
#define DISPLAY_COMMON
#include <gint/display.h>
/* 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 */

View file

@ -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]

View file

@ -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 */

View file

@ -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 */

View file

@ -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 <gint/display-fx.h>
// and <gint/display-cg.h>.
//---
#ifndef GINT_DISPLAY
@ -7,8 +11,8 @@
#include <gint/defs/types.h>
/* 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 <gint/display-fx.h>
@ -18,26 +22,180 @@
#include <gint/display-cg.h>
#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 */

View file

@ -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 */

View file

@ -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
#

BIN
src/font10x12.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View file

@ -1,11 +1,9 @@
#define GINT_NEED_VRAM
#include <gint/defs/util.h>
#include <gint/display.h>
#include <gint/defs/util.h>
/* 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);
}

View file

@ -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;
}
}

29
src/render-cg/topti-asm.h Normal file
View file

@ -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 */

202
src/render-cg/topti-asm.s Normal file
View file

@ -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

96
src/render-cg/topti.c Normal file
View file

@ -0,0 +1,96 @@
#define GINT_NEED_VRAM
#include <gint/defs/types.h>
#include <gint/defs/attributes.h>
#include <gint/display.h>
#include <display/common.h>
#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;
}
}

View file

@ -1,11 +1,9 @@
#define GINT_NEED_VRAM
#include <gint/defs/util.h>
#include <gint/display.h>
#include <gint/defs/util.h>
#include <display/fx.h>
/* 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);
}

View file

@ -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;
}
}

View file

@ -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];

View file

@ -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

View file

@ -2,104 +2,14 @@
#include <gint/defs/types.h>
#include <gint/defs/attributes.h>
#include <gint/display.h>
#include <display/common.h>
#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],

60
src/render/dline.c Normal file
View file

@ -0,0 +1,60 @@
#include <gint/display.h>
#include <gint/defs/util.h>
#include <display/common.h>
/* 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);
}

73
src/render/topti.c Normal file
View file

@ -0,0 +1,73 @@
#include <gint/defs/types.h>
#include <gint/display.h>
#include <display/common.h>
/* 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;
}