mirror of
https://git.planet-casio.com/Lephenixnoir/gint.git
synced 2025-07-06 20:46:36 +02:00
gray: add engine, basic drawing and text
This revision includes the base gray engine with sensible starting defaults, gclear() and grect(), as well as gtext().
This commit is contained in:
parent
705854da39
commit
ae4f7af172
14 changed files with 558 additions and 38 deletions
3
TODO
3
TODO
|
@ -24,8 +24,10 @@ Complementary elements on existing code.
|
||||||
* core: use cmp/str for memchr()
|
* core: use cmp/str for memchr()
|
||||||
* timer: try putting addresses in <gint/mpu/tmu.h>
|
* timer: try putting addresses in <gint/mpu/tmu.h>
|
||||||
* r61524: brightness control and clean the file
|
* r61524: brightness control and clean the file
|
||||||
|
* t6k11: check if dupdate() can be done by the DMA
|
||||||
|
|
||||||
Keep in mind.
|
Keep in mind.
|
||||||
|
* core: run destructors when a task-switch results in leaving the app
|
||||||
* prizm: don't hardcode stack address in fxcg50.ld
|
* prizm: don't hardcode stack address in fxcg50.ld
|
||||||
* prizm: detect P1 static RAM (stack) in TLB
|
* prizm: detect P1 static RAM (stack) in TLB
|
||||||
* core: prove and use qdiv10() instead of __sdivsi3
|
* core: prove and use qdiv10() instead of __sdivsi3
|
||||||
|
@ -33,6 +35,7 @@ Keep in mind.
|
||||||
* core: free heap when a task-switch results in leaving the app
|
* core: free heap when a task-switch results in leaving the app
|
||||||
* core: save and restore interrupt masks
|
* core: save and restore interrupt masks
|
||||||
* timer: make sure ETMU interrupts are disabled in ctx_restore()
|
* timer: make sure ETMU interrupts are disabled in ctx_restore()
|
||||||
|
* timer: look for ways to improve the code again
|
||||||
* core: document the SH7305 PFC in <gint/mpu/pfc.h>
|
* core: document the SH7305 PFC in <gint/mpu/pfc.h>
|
||||||
|
|
||||||
Future directions.
|
Future directions.
|
||||||
|
|
|
@ -43,5 +43,4 @@ void bopti_render_clip(int x, int y, image_t const *img, int left, int top,
|
||||||
void bopti_render_noclip(int x, int y, image_t const *img, int left, int top,
|
void bopti_render_noclip(int x, int y, image_t const *img, int left, int top,
|
||||||
int w, int h);
|
int w, int h);
|
||||||
|
|
||||||
|
|
||||||
#endif /* DISPLAY_FX */
|
#endif /* DISPLAY_FX */
|
||||||
|
|
|
@ -30,4 +30,8 @@
|
||||||
/* Weak symbols */
|
/* Weak symbols */
|
||||||
#define GWEAK __attribute__((weak))
|
#define GWEAK __attribute__((weak))
|
||||||
|
|
||||||
|
/* Constructors */
|
||||||
|
#define GCONSTRUCTOR __attribute__((constructor))
|
||||||
|
#define GDESTRUCTOR __attribute__((destructor))
|
||||||
|
|
||||||
#endif /* GINT_DEFS_ATTRIBUTES */
|
#endif /* GINT_DEFS_ATTRIBUTES */
|
||||||
|
|
|
@ -59,16 +59,15 @@ enum {
|
||||||
|
|
||||||
Since gint transfers data to the screen using the DMA, it is possible to run
|
Since gint transfers data to the screen using the DMA, it is possible to run
|
||||||
the application while the finished frame is being transferred. However,
|
the application while the finished frame is being transferred. However,
|
||||||
writing to the VRAM during this period it is still begin read by the DMA.
|
writing to the VRAM during this period will cause display artifacts since
|
||||||
Changing the contents of the VRAM too soon would alter the frame being sent.
|
the VRAM it is still being read by the DMA.
|
||||||
|
|
||||||
The solution to this is to use triple-buffering with the display and two
|
The solution to this is to use triple-buffering with the display and two
|
||||||
VRAMs that are alternately begin written to while the other is being
|
VRAMs that are alternately being written to while the other is being
|
||||||
transferred. The VRAM switching is handled by dupdate() and is activated
|
transferred. The VRAM switching is handled by dupdate() and is activated
|
||||||
whenever two VRAMs are configured.
|
whenever two VRAMs are configured.
|
||||||
|
|
||||||
By default gint uses triple buffering with one VRAM in the user stack and
|
By default gint uses triple buffering with two VRAMs in the system stack.
|
||||||
a second one in the system stack.
|
|
||||||
|
|
||||||
VRAMs must be contiguous, 32-aligned, (2*396*224)-byte buffers.
|
VRAMs must be contiguous, 32-aligned, (2*396*224)-byte buffers.
|
||||||
|
|
||||||
|
|
180
include/gint/gray.h
Normal file
180
include/gint/gray.h
Normal file
|
@ -0,0 +1,180 @@
|
||||||
|
//---
|
||||||
|
// gint:gray - Gray engine and rendering functions
|
||||||
|
//---
|
||||||
|
|
||||||
|
#ifndef GINT_GRAY
|
||||||
|
#define GINT_GRAY
|
||||||
|
|
||||||
|
#include <gint/defs/types.h>
|
||||||
|
#include <gint/display.h>
|
||||||
|
|
||||||
|
//---
|
||||||
|
// Engine control
|
||||||
|
//---
|
||||||
|
|
||||||
|
/* gray_start(): Start the gray engine
|
||||||
|
The control of the screen is transferred to the engine; you should not use
|
||||||
|
dupdate() after this function, only gupdate(). */
|
||||||
|
void gray_start(void);
|
||||||
|
|
||||||
|
/* gray_stop(): Stop the gray engine
|
||||||
|
|
||||||
|
Safe to call if the engine was not running. The gray engine returns the
|
||||||
|
control of the screen and dupdate() is safe to use again.
|
||||||
|
|
||||||
|
This function will leave the screen in whatever state it is, which is most
|
||||||
|
probably one of the gray buffers being displayed. You should dupdate()
|
||||||
|
quickly after this call to avoid visual artifacts. If the next monochrome
|
||||||
|
frame is slow to render, consider rendering it before stopping the gray
|
||||||
|
engine, and calling dupdate() immediately after. */
|
||||||
|
void gray_stop(void);
|
||||||
|
|
||||||
|
/* gray_delays(): Set the gray engine delays
|
||||||
|
|
||||||
|
The gray engine works by swapping two images at a fast pace. Pixels that are
|
||||||
|
white on both or black or both will appear as such, but pixels that are
|
||||||
|
black on only one of the images will look gray.
|
||||||
|
|
||||||
|
If both images stay on-screen for the same amount on time, there will be
|
||||||
|
only one shade of gray. But if one stays longer, then pixels that are only
|
||||||
|
black here will look darker than their counterparts, making two shades of
|
||||||
|
gray. This is the default.
|
||||||
|
|
||||||
|
Since the gray engine has its default settings, you don't need to set the
|
||||||
|
delays before using gray drawing functions. But you can do it to customize
|
||||||
|
the appearance of the gray to your application. Be aware that most values
|
||||||
|
will just produce visual artifacts and will not look good. There are three
|
||||||
|
characteristics that you'll want to control:
|
||||||
|
|
||||||
|
* The stability of the shades; depending on the frequency gray areas can
|
||||||
|
appear to blink.
|
||||||
|
* Stripes. If the refresh timing coincides with the screen's display
|
||||||
|
duration, stripes will appear. They can be of various sizes, visibility
|
||||||
|
and speed; but overall they're the *one* thing you want to avoid.
|
||||||
|
* And the color of the shades themselves.
|
||||||
|
|
||||||
|
Here are values from an older version of gint, which may not look good now
|
||||||
|
but provide bases to search for good settings:
|
||||||
|
|
||||||
|
LIGHT DARK BLINKING STRIPES COLORS
|
||||||
|
--------------------------------------------------
|
||||||
|
860 1298 none terrible decent
|
||||||
|
912 1343 heavy none good
|
||||||
|
993 1609 medium light decent
|
||||||
|
1325 1607 heavy light excellent
|
||||||
|
--------------------------------------------------
|
||||||
|
|
||||||
|
Here are values for this version of gint;
|
||||||
|
|
||||||
|
LIGHT DARK BLINKING STRIPES COLORS
|
||||||
|
--------------------------------------------------
|
||||||
|
869 1311 medium none good [default]
|
||||||
|
937 1425 medium none good
|
||||||
|
--------------------------------------------------
|
||||||
|
|
||||||
|
@light New light delay
|
||||||
|
@dark New dark delay */
|
||||||
|
void gray_delays(uint32_t light, uint32_t dark);
|
||||||
|
|
||||||
|
/* gray_config(): Get the current configuration of the engine
|
||||||
|
|
||||||
|
Provides the value of the current light and dark delays, measured in timer
|
||||||
|
ticks of prescaler P_phi/64. See <gint/clock.h> on how to obtain this value.
|
||||||
|
Both pointers may be NULL.
|
||||||
|
|
||||||
|
@light Set to the current light delay setting
|
||||||
|
@dark Set to the current dark delay setting
|
||||||
|
Returns non-zero if the engine is currently running, 0 otherwise. */
|
||||||
|
int gray_config(uint32_t *light, uint32_t *dark);
|
||||||
|
|
||||||
|
//---
|
||||||
|
// Area rendering functions
|
||||||
|
//---
|
||||||
|
|
||||||
|
/* gclear(): Fill the screen with a single color
|
||||||
|
Clears the VRAM and paints all the pixels in the same color. Optimized for
|
||||||
|
opaque colors; use grect() for other colors.
|
||||||
|
|
||||||
|
@color white, light, dark, black */
|
||||||
|
void gclear(color_t color);
|
||||||
|
|
||||||
|
/* grect(): Fill a rectangle on the screen
|
||||||
|
Applies a color or an operator to the rectangle enclosed by (x1 y1) and
|
||||||
|
(x2 y2), both included.
|
||||||
|
|
||||||
|
@x1 @x2 @y1 @y2 Bounding rectangle
|
||||||
|
@color white, light, dark, black, none, invert, lighten, darken */
|
||||||
|
void grect(int x1, int y1, int x2, int y2, color_t color);
|
||||||
|
|
||||||
|
//---
|
||||||
|
// Point drawing functions
|
||||||
|
//---
|
||||||
|
|
||||||
|
/* gpixel(): Change a pixel's color
|
||||||
|
Paints the specified pixel. Use lines or area rendering when possible
|
||||||
|
because painting pixels individually is slow.
|
||||||
|
|
||||||
|
@x @y Coordinates of the pixel to paint
|
||||||
|
@color white, light, dark, black, none, invert, lighten, darken */
|
||||||
|
void gpixel(int x, int y, color_t color);
|
||||||
|
|
||||||
|
/* gline(): Render a straight line
|
||||||
|
Draws a line without anti-aliasing, using a Bresenham-style algorithm. Much
|
||||||
|
like dline(), has optimizations for vertical and horizontal lines but is not
|
||||||
|
able to handle clipping.
|
||||||
|
|
||||||
|
@x1 @y1 @x2 @y2 End points of the line (both included)
|
||||||
|
@color white, light, dark, black, none, invert, lighten, darken */
|
||||||
|
void gline(int x1, int y1, int x2, int y2, color_t color);
|
||||||
|
|
||||||
|
//---
|
||||||
|
// Text rendering
|
||||||
|
//---
|
||||||
|
|
||||||
|
/* dfont() and dsize() still work with the gray engine. */
|
||||||
|
|
||||||
|
/* gtext(): Display a string of text
|
||||||
|
Exactly like dtext(), except that the rendering is done on the two gray
|
||||||
|
VRAMs and all colors are supported.
|
||||||
|
|
||||||
|
@x @y Coordinates of top-left corner of the rendered string
|
||||||
|
@str String to display
|
||||||
|
@fg Foreground: white, light, dark, black, none, invert, lighten, darken
|
||||||
|
@bg Background, same colors as fg */
|
||||||
|
void gtext(int x, int y, const char *str, int fg, int bg);
|
||||||
|
|
||||||
|
//---
|
||||||
|
// VRAM management
|
||||||
|
//---
|
||||||
|
|
||||||
|
/* gupdate(): Push the current VRAMs to the screen
|
||||||
|
|
||||||
|
This function swaps pairs of VRAM buffers in the gray engine so that the
|
||||||
|
gray and light VRAMs that were being drawn to are now available to be
|
||||||
|
displayed on the screen at the next refresh, while the VRAMs that were
|
||||||
|
previously being displayed are now available for drawing.
|
||||||
|
|
||||||
|
Unlike dupdate(), gupdate() does not interact with the screen as this
|
||||||
|
interaction is done very frequently by the engine itself. It performs an
|
||||||
|
atomic operation to swap buffers, but nothing on the screen will change
|
||||||
|
until the engine's timer actually fires. */
|
||||||
|
void gupdate(void);
|
||||||
|
|
||||||
|
|
||||||
|
/* gvram(): Get the current VRAM pointers
|
||||||
|
|
||||||
|
This function stores the current VRAM pointers to the specified locations.
|
||||||
|
This operation needs to be done atomically because the engine might kick in
|
||||||
|
and sway buffers at any time; calling gvraml() then gvramd() is unsafe.
|
||||||
|
|
||||||
|
@light Set to the current light VRAM pointer
|
||||||
|
@dark Set to the current dark VRAM pointer */
|
||||||
|
void gvram(uint32_t **light, uint32_t **dark);
|
||||||
|
|
||||||
|
/* gvraml(): Shorthand to retrieve the current light VRAM pointer */
|
||||||
|
uint32_t *gvraml(void);
|
||||||
|
|
||||||
|
/* gvramd(): Shorthand to retrieve the current dark VRAM pointer */
|
||||||
|
uint32_t *gvramd(void);
|
||||||
|
|
||||||
|
#endif /* GINT_GRAY */
|
|
@ -45,10 +45,10 @@ src2obj = $(1:../src/%=src/%).o
|
||||||
src2dep = $(1:../src/%=src/%).d
|
src2dep = $(1:../src/%=src/%).d
|
||||||
|
|
||||||
# Source files
|
# Source files
|
||||||
prune-fx := "render-cg"
|
prune-fx := -name render-cg -prune
|
||||||
prune-cg := "render-fx"
|
prune-cg := -name render-fx -prune -o -name gray -prune
|
||||||
src := $(shell find ../src \
|
src := $(shell find ../src \
|
||||||
-name $(prune-$(CONFIG.TARGET)) -prune \
|
$(prune-$(CONFIG.TARGET)) \
|
||||||
-o -name '*.[csS]' -print)
|
-o -name '*.[csS]' -print)
|
||||||
src_obj := $(foreach s,$(src),$(call src2obj,$s))
|
src_obj := $(foreach s,$(src),$(call src2obj,$s))
|
||||||
|
|
||||||
|
|
142
src/gray/engine.c
Normal file
142
src/gray/engine.c
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
//---
|
||||||
|
// gint:gray:engine - Core gray engine
|
||||||
|
//---
|
||||||
|
|
||||||
|
#define GINT_NEED_VRAM
|
||||||
|
|
||||||
|
#include <gint/defs/types.h>
|
||||||
|
#include <gint/std/stdlib.h>
|
||||||
|
|
||||||
|
#include <gint/drivers/t6k11.h>
|
||||||
|
#include <gint/gray.h>
|
||||||
|
#include <gint/display.h>
|
||||||
|
#include <gint/timer.h>
|
||||||
|
|
||||||
|
/* Three additional video RAMS, allocated statically if --static-gray was set
|
||||||
|
at configure time, or with malloc() otherwise. */
|
||||||
|
#ifdef GINT_STATIC_GRAY
|
||||||
|
GBSS static uint32_t gvrams[3][256];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Four VRAMs: two to draw and two to display */
|
||||||
|
GBSS static uint32_t *vrams[4];
|
||||||
|
|
||||||
|
/* Current VRAM pair used for drawing; the value can either be 0 (draws to
|
||||||
|
VRAMs 0 and 1) or 2 (draws to VRAMs 2 and 3). */
|
||||||
|
GDATA static volatile int st = 0;
|
||||||
|
|
||||||
|
/* Whether the engine is running. Delays of light and dark frames. */
|
||||||
|
GDATA static int runs = 0;
|
||||||
|
GDATA static int delays[2] = { 869, 1311 };
|
||||||
|
|
||||||
|
/* Underlying timer */
|
||||||
|
#define GRAY_TIMER 0
|
||||||
|
|
||||||
|
//---
|
||||||
|
// Engine control
|
||||||
|
//---
|
||||||
|
|
||||||
|
/* gray_init(): Engine setup */
|
||||||
|
GCONSTRUCTOR static void gray_init(void)
|
||||||
|
{
|
||||||
|
/* Here [vram] refers to the standard, monochrome VRAM */
|
||||||
|
vrams[0] = vram;
|
||||||
|
|
||||||
|
#ifdef GINT_STATIC_GRAY
|
||||||
|
vrams[1] = gvrams[0];
|
||||||
|
vrams[2] = gvrams[1];
|
||||||
|
vrams[3] = gvrams[2];
|
||||||
|
#else
|
||||||
|
vrams[1] = malloc(1024);
|
||||||
|
vrams[2] = malloc(1024);
|
||||||
|
vrams[3] = malloc(1024);
|
||||||
|
#endif /* GINT_STATIC_GRAY */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* gray_quit(): Engine deinitialization() */
|
||||||
|
GDESTRUCTOR static void gray_quit(void)
|
||||||
|
{
|
||||||
|
#ifndef GINT_STATIC_GRAY
|
||||||
|
free(vrams[1]);
|
||||||
|
free(vrams[2]);
|
||||||
|
free(vrams[3]);
|
||||||
|
#endif /* GINT_STATIC_GRAY */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* gray_int(): Interrupt handler */
|
||||||
|
int gray_int(GUNUSED volatile void *arg)
|
||||||
|
{
|
||||||
|
t6k11_display(vrams[st ^ 2], 0, 64, 16);
|
||||||
|
timer_reload(GRAY_TIMER, delays[(st ^ 3) & 1]);
|
||||||
|
st ^= 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* gray_start(): Start the gray engine */
|
||||||
|
void gray_start(void)
|
||||||
|
{
|
||||||
|
#ifndef GINT_STATIC_GRAY
|
||||||
|
if(!vrams[1] || !vrams[2] || !vrams[3]) return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(runs) return;
|
||||||
|
|
||||||
|
int free = timer_setup(GRAY_TIMER, delays[0], timer_Po_64, gray_int,
|
||||||
|
NULL);
|
||||||
|
if(free != GRAY_TIMER) return;
|
||||||
|
|
||||||
|
timer_start(GRAY_TIMER);
|
||||||
|
st = 0;
|
||||||
|
runs = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* gray_stop(): Stop the gray engine */
|
||||||
|
void gray_stop(void)
|
||||||
|
{
|
||||||
|
timer_stop(GRAY_TIMER);
|
||||||
|
runs = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* gray_delays(): Set the gray engine delays */
|
||||||
|
void gray_delays(uint32_t light, uint32_t dark)
|
||||||
|
{
|
||||||
|
delays[0] = light;
|
||||||
|
delays[1] = dark;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* gray_config(): Get the current configuration of the engine */
|
||||||
|
int gray_config(uint32_t *light, uint32_t *dark)
|
||||||
|
{
|
||||||
|
if(light) *light = delays[0];
|
||||||
|
if(dark) *dark = delays[1];
|
||||||
|
|
||||||
|
return runs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* gupdate(): Push the current VRAMs to the screen */
|
||||||
|
void gupdate(void)
|
||||||
|
{
|
||||||
|
st ^= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* gvram(): Get the current VRAM pointers */
|
||||||
|
void gvram(uint32_t **light, uint32_t **dark)
|
||||||
|
{
|
||||||
|
int base = st;
|
||||||
|
|
||||||
|
if(light) *light = vrams[base & 2];
|
||||||
|
if(dark) *dark = vrams[base | 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* gvraml(): Shorthand to retrieve the current light VRAM pointer */
|
||||||
|
uint32_t *gvraml(void)
|
||||||
|
{
|
||||||
|
return vrams[st & 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* gvramd(): Shorthand to retrieve the current dark VRAM pointer */
|
||||||
|
uint32_t *gvramd(void)
|
||||||
|
{
|
||||||
|
return vrams[st | 1];
|
||||||
|
}
|
37
src/gray/gclear.c
Normal file
37
src/gray/gclear.c
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
#include <gint/gray.h>
|
||||||
|
|
||||||
|
/* gclear(): Fill the screen with a single color */
|
||||||
|
void gclear(color_t color)
|
||||||
|
{
|
||||||
|
uint32_t *light, *dark;
|
||||||
|
gvram(&light, &dark);
|
||||||
|
|
||||||
|
uint32_t l = -(color == C_LIGHT || color == C_BLACK);
|
||||||
|
uint32_t d = -(color == C_DARK || color == C_BLACK);
|
||||||
|
|
||||||
|
for(int i = 0; i < 32; i++)
|
||||||
|
{
|
||||||
|
light[0] = l;
|
||||||
|
light[1] = l;
|
||||||
|
light[2] = l;
|
||||||
|
light[3] = l;
|
||||||
|
|
||||||
|
light[4] = l;
|
||||||
|
light[5] = l;
|
||||||
|
light[6] = l;
|
||||||
|
light[7] = l;
|
||||||
|
|
||||||
|
dark[0] = d;
|
||||||
|
dark[1] = d;
|
||||||
|
dark[2] = d;
|
||||||
|
dark[3] = d;
|
||||||
|
|
||||||
|
dark[4] = d;
|
||||||
|
dark[5] = d;
|
||||||
|
dark[6] = d;
|
||||||
|
dark[7] = d;
|
||||||
|
|
||||||
|
light += 8;
|
||||||
|
dark += 8;
|
||||||
|
}
|
||||||
|
}
|
124
src/gray/grect.c
Normal file
124
src/gray/grect.c
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
#include <gint/defs/util.h>
|
||||||
|
#include <gint/gray.h>
|
||||||
|
#include <display/fx.h>
|
||||||
|
|
||||||
|
/* grect(): Fill a rectangle on the screen */
|
||||||
|
void grect(int x1, int y1, int x2, int y2, color_t color)
|
||||||
|
{
|
||||||
|
if(x1 > x2) swap(x1, x2);
|
||||||
|
if(y1 > y2) swap(y1, y2);
|
||||||
|
|
||||||
|
/* Argument checking */
|
||||||
|
if(x1 >= 128 || x2 < 0 || y1 >= 64 || y2 < 0) return;
|
||||||
|
if(x1 < 0) x1 = 0;
|
||||||
|
if(x2 >= 128) x2 = 127;
|
||||||
|
if(y1 < 0) y1 = 0;
|
||||||
|
if(y2 >= 64) y2 = 63;
|
||||||
|
|
||||||
|
/* Use masks to get the work done fast! */
|
||||||
|
uint32_t m[4];
|
||||||
|
masks(x1, x2, m);
|
||||||
|
|
||||||
|
uint32_t *light, *dark;
|
||||||
|
gvram(&light, &dark);
|
||||||
|
|
||||||
|
light += (y1 << 2);
|
||||||
|
dark += (y1 << 2);
|
||||||
|
int h = y2 - y1 + 1;
|
||||||
|
|
||||||
|
if(color == C_WHITE) while(h--)
|
||||||
|
{
|
||||||
|
light[0] &= ~m[0];
|
||||||
|
light[1] &= ~m[1];
|
||||||
|
light[2] &= ~m[2];
|
||||||
|
light[3] &= ~m[3];
|
||||||
|
|
||||||
|
dark[0] &= ~m[0];
|
||||||
|
dark[1] &= ~m[1];
|
||||||
|
dark[2] &= ~m[2];
|
||||||
|
dark[3] &= ~m[3];
|
||||||
|
|
||||||
|
light += 4;
|
||||||
|
dark += 4;
|
||||||
|
}
|
||||||
|
else if(color == C_LIGHT) while(h--)
|
||||||
|
{
|
||||||
|
light[0] |= m[0];
|
||||||
|
light[1] |= m[1];
|
||||||
|
light[2] |= m[2];
|
||||||
|
light[3] |= m[3];
|
||||||
|
|
||||||
|
dark[0] &= ~m[0];
|
||||||
|
dark[1] &= ~m[1];
|
||||||
|
dark[2] &= ~m[2];
|
||||||
|
dark[3] &= ~m[3];
|
||||||
|
|
||||||
|
light += 4;
|
||||||
|
dark += 4;
|
||||||
|
}
|
||||||
|
else if(color == C_DARK) while(h--)
|
||||||
|
{
|
||||||
|
light[0] &= ~m[0];
|
||||||
|
light[1] &= ~m[1];
|
||||||
|
light[2] &= ~m[2];
|
||||||
|
light[3] &= ~m[3];
|
||||||
|
|
||||||
|
dark[0] |= m[0];
|
||||||
|
dark[1] |= m[1];
|
||||||
|
dark[2] |= m[2];
|
||||||
|
dark[3] |= m[3];
|
||||||
|
|
||||||
|
light += 4;
|
||||||
|
dark += 4;
|
||||||
|
}
|
||||||
|
else if(color == C_BLACK) while(h--)
|
||||||
|
{
|
||||||
|
light[0] |= m[0];
|
||||||
|
light[1] |= m[1];
|
||||||
|
light[2] |= m[2];
|
||||||
|
light[3] |= m[3];
|
||||||
|
|
||||||
|
dark[0] |= m[0];
|
||||||
|
dark[1] |= m[1];
|
||||||
|
dark[2] |= m[2];
|
||||||
|
dark[3] |= m[3];
|
||||||
|
|
||||||
|
light += 4;
|
||||||
|
dark += 4;
|
||||||
|
}
|
||||||
|
else if(color == C_INVERT) while(h--)
|
||||||
|
{
|
||||||
|
light[0] ^= m[0];
|
||||||
|
light[1] ^= m[1];
|
||||||
|
light[2] ^= m[2];
|
||||||
|
light[3] ^= m[3];
|
||||||
|
|
||||||
|
dark[0] ^= m[0];
|
||||||
|
dark[1] ^= m[1];
|
||||||
|
dark[2] ^= m[2];
|
||||||
|
dark[3] ^= m[3];
|
||||||
|
|
||||||
|
light += 4;
|
||||||
|
dark += 4;
|
||||||
|
}
|
||||||
|
else if(color == C_LIGHTEN) for(int i = 0; i < (h << 2); i++)
|
||||||
|
{
|
||||||
|
int j = i & 3;
|
||||||
|
uint32_t tmp = *dark, x = m[j];
|
||||||
|
|
||||||
|
*dark &= *light | ~x;
|
||||||
|
*light = (*light ^ x) & (tmp | ~x);
|
||||||
|
|
||||||
|
light++, dark++;
|
||||||
|
}
|
||||||
|
else if(color == C_DARKEN) for(int i = 0; i < (h << 2); i++)
|
||||||
|
{
|
||||||
|
int j = i & 3;
|
||||||
|
uint32_t tmp = *dark, x = m[j];
|
||||||
|
|
||||||
|
*dark |= *light & x;
|
||||||
|
*light = (*light ^ x) | (tmp & x);
|
||||||
|
|
||||||
|
light++, dark++;
|
||||||
|
}
|
||||||
|
}
|
15
src/gray/gtext.c
Normal file
15
src/gray/gtext.c
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#include <gint/gray.h>
|
||||||
|
#include <display/common.h>
|
||||||
|
#include "../render-fx/topti-asm.h"
|
||||||
|
|
||||||
|
/* gtext(): Display a string of text */
|
||||||
|
void gtext(int x, int y, const char *str, int fg, int bg)
|
||||||
|
{
|
||||||
|
if((uint)fg >= 8 || (uint)bg >= 8) return;
|
||||||
|
|
||||||
|
uint32_t *light, *dark;
|
||||||
|
gvram(&light, &dark);
|
||||||
|
|
||||||
|
topti_render(x, y, str, topti_font, topti_asm_text[fg],
|
||||||
|
topti_asm_text[bg], light, dark);
|
||||||
|
}
|
13
src/render-fx/dtext.c
Normal file
13
src/render-fx/dtext.c
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#define GINT_NEED_VRAM
|
||||||
|
#include <gint/display.h>
|
||||||
|
#include <display/common.h>
|
||||||
|
#include "topti-asm.h"
|
||||||
|
|
||||||
|
/* dtext() - display a string of text */
|
||||||
|
GSECTION(".pretext")
|
||||||
|
void dtext(int x, int y, char const *str, int fg, int bg)
|
||||||
|
{
|
||||||
|
if((uint)fg >= 8 || (uint)bg >= 8) return;
|
||||||
|
topti_render(x, y, str, topti_font, topti_asm_text[fg],
|
||||||
|
topti_asm_text[bg], vram, vram);
|
||||||
|
}
|
|
@ -12,4 +12,18 @@ typedef void asm_text_t(uint32_t *v1, uint32_t *v2, uint32_t *op, int height);
|
||||||
/* One rendering function per color */
|
/* One rendering function per color */
|
||||||
extern asm_text_t *topti_asm_text[8];
|
extern asm_text_t *topti_asm_text[8];
|
||||||
|
|
||||||
|
/* topti_render(): Render a string on the VRAM
|
||||||
|
Combines glyph data onto VRAM operands and blits them efficiently onto the
|
||||||
|
VRAM. To write a single character, use a 2-byte string with a NUL.
|
||||||
|
|
||||||
|
@x @y Target position on VRAM
|
||||||
|
@str Text source
|
||||||
|
@f Font
|
||||||
|
@asm_fg Assembler function for text rendering
|
||||||
|
@asm_bg Assembler function for background rendering
|
||||||
|
@v1 Monochrome VRAM or light gray VRAM
|
||||||
|
@v2 Monochrome or dark gray VRAM */
|
||||||
|
void topti_render(int x, int y, char const *str, font_t const *f,
|
||||||
|
asm_text_t *asm_fg, asm_text_t *asm_bg, uint32_t *v1, uint32_t *v2);
|
||||||
|
|
||||||
#endif /* GINT_RENDERFX_TOPTIASM */
|
#endif /* GINT_RENDERFX_TOPTIASM */
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
# r2: dark (except lighten/darken: swapped at some point with light)
|
# r2: dark (except lighten/darken: swapped at some point with light)
|
||||||
# r3: (tmp)
|
# r3: (tmp)
|
||||||
# r4: vram (mono or light)
|
# r4: vram (mono or light)
|
||||||
# r5: vram (nothing or dark)
|
# r5: vram (mono or dark)
|
||||||
# r6: operators
|
# r6: operators
|
||||||
# r7: number of rows (r7>0, otherwise the font is clearly ill-formed)
|
# r7: number of rows (r7>0, otherwise the font is clearly ill-formed)
|
||||||
|
|
||||||
|
@ -24,16 +24,20 @@
|
||||||
.align 4
|
.align 4
|
||||||
_topti_asm_white:
|
_topti_asm_white:
|
||||||
add #-16, r4
|
add #-16, r4
|
||||||
nop
|
add #-16, r5
|
||||||
|
|
||||||
1: mov.l @r6+, r0
|
1: mov.l @r6+, r0
|
||||||
add #16, r4
|
add #16, r4
|
||||||
mov.l @r4, r1
|
mov.l @r4, r1
|
||||||
dt r7
|
dt r7
|
||||||
|
mov.l @r5, r2
|
||||||
not r0, r0
|
not r0, r0
|
||||||
and r0, r1
|
and r0, r1
|
||||||
bf.s 1b
|
and r0, r2
|
||||||
mov.l r1, @r4
|
mov.l r1, @r4
|
||||||
|
add #16, r5
|
||||||
|
bf.s 1b
|
||||||
|
mov.l r2, @r5
|
||||||
|
|
||||||
rts
|
rts
|
||||||
nop
|
nop
|
||||||
|
@ -81,10 +85,14 @@ _topti_asm_black:
|
||||||
dt r7
|
dt r7
|
||||||
mov.l @r4, r1
|
mov.l @r4, r1
|
||||||
/* (bubble) */
|
/* (bubble) */
|
||||||
or r1, r0
|
or r0, r1
|
||||||
mov.l r0, @r4
|
mov.l @r5, r2
|
||||||
bf.s 1b
|
or r0, r2
|
||||||
|
mov.l r1, @r4
|
||||||
add #16, r4
|
add #16, r4
|
||||||
|
mov.l r2, @r5
|
||||||
|
bf.s 1b
|
||||||
|
add #16, r5
|
||||||
|
|
||||||
rts
|
rts
|
||||||
nop
|
nop
|
||||||
|
@ -169,4 +177,3 @@ _topti_asm_text:
|
||||||
.long _topti_asm_invert
|
.long _topti_asm_invert
|
||||||
.long _topti_asm_lighten
|
.long _topti_asm_lighten
|
||||||
.long _topti_asm_darken
|
.long _topti_asm_darken
|
||||||
|
|
||||||
|
|
|
@ -81,18 +81,10 @@ static int topti_split(uint32_t const * glyph, int width, int height, int free,
|
||||||
return free - width;
|
return free - width;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* topti_render(): Render a string on the VRAM
|
/* topti_render(): Render a string on the VRAM */
|
||||||
Combines glyph data onto VRAM operands and blits them efficiently onto the
|
|
||||||
VRAM. To write a single character, use a 2-byte string with a NUL.
|
|
||||||
|
|
||||||
@x @y Target position on VRAM
|
|
||||||
@str Text source
|
|
||||||
@f Font
|
|
||||||
@asm_fg Assembler function for text rendering
|
|
||||||
@asm_bg Assembler function for background rendering */
|
|
||||||
GSECTION(".pretext")
|
GSECTION(".pretext")
|
||||||
void topti_render(int x, int y, char const *str, font_t const *f,
|
void topti_render(int x, int y, char const *str, font_t const *f,
|
||||||
asm_text_t *asm_fg, asm_text_t *asm_bg)
|
asm_text_t *asm_fg, asm_text_t *asm_bg, uint32_t *v1, uint32_t *v2)
|
||||||
{
|
{
|
||||||
/* Storage height and number of free bits in operators[] */
|
/* Storage height and number of free bits in operators[] */
|
||||||
int height = f->data_height, free;
|
int height = f->data_height, free;
|
||||||
|
@ -127,10 +119,10 @@ void topti_render(int x, int y, char const *str, font_t const *f,
|
||||||
/* Put an initial offset to the operators to honor the x coordinate */
|
/* Put an initial offset to the operators to honor the x coordinate */
|
||||||
free = 32 - (x & 31);
|
free = 32 - (x & 31);
|
||||||
x >>= 5;
|
x >>= 5;
|
||||||
|
|
||||||
/* VRAM pointers */
|
/* VRAM pointers */
|
||||||
/* TODO: topti: Support gray vrams */
|
v1 += (y << 2) + x;
|
||||||
uint32_t *v1 = vram + (y << 2) + x;
|
v2 += (y << 2) + x;
|
||||||
uint32_t *v2 = vram + (y << 2) + x;
|
|
||||||
|
|
||||||
/* Pull each character into the operator buffer */
|
/* Pull each character into the operator buffer */
|
||||||
while(*str)
|
while(*str)
|
||||||
|
@ -184,12 +176,3 @@ void topti_render(int x, int y, char const *str, font_t const *f,
|
||||||
asm_fg(v1, v2, operators + vdisp, height - vdisp);
|
asm_fg(v1, v2, operators + vdisp, height - vdisp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* dtext() - display a string of text */
|
|
||||||
GSECTION(".pretext")
|
|
||||||
void dtext(int x, int y, char const *str, int fg, int bg)
|
|
||||||
{
|
|
||||||
if((uint)fg >= 8 || (uint)bg >= 8) return;
|
|
||||||
topti_render(x, y, str, topti_font, topti_asm_text[fg],
|
|
||||||
topti_asm_text[bg]);
|
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue