mirror of
https://git.planet-casio.com/Lephenixnoir/gint.git
synced 2024-12-28 20:43:36 +01:00
gray: finalize the gray engine API
* Define dgray() to replace gray_start() and gray_stop()
* Introduce a mechanism to override the d*() functions rather than using
another set of functions, namely g*(). Gray rendering should now be
done with d*() (a compatibility macro for g*() is available until v2.1).
* Gray engine now reserves TMU0 at the start of the add-in to prevent
surprises if timers are exhausted, so it nevers fails to start
* Replace other gray engine functions with dgray_*()
* More general rendering functions (in render/) to lessen the burden of
porting them to the gray engine. As a consequence, dtext_opt(),
dprint_opt() and drect_border() are now available in the gray engine,
which was an omission from 230b796
.
* Allow C_NONE in more functions, mainly on fx-CG 50
* Remove the now-unused dupdate_noint()
This commit is contained in:
parent
411bbb9568
commit
94fb300e72
35 changed files with 557 additions and 481 deletions
3
TODO
3
TODO
|
@ -1,14 +1,15 @@
|
||||||
For the 2.1.0 release:
|
For the 2.1.0 release:
|
||||||
* bopti: remove the deprecated image_t definition
|
* bopti: remove the deprecated image_t definition
|
||||||
* project: remove the compat branch
|
* project: remove the compat branch
|
||||||
|
* project: remove the gray aliases
|
||||||
|
|
||||||
Issues:
|
Issues:
|
||||||
* #10 support fx-CG 20
|
* #10 support fx-CG 20
|
||||||
|
|
||||||
Extensions on existing code:
|
Extensions on existing code:
|
||||||
|
* build: move the private headers to the src/ folder
|
||||||
* tmu: make interrupt handlers more elegant
|
* tmu: make interrupt handlers more elegant
|
||||||
* bopti: try to display fullscreen images with TLB access + DMA on fxcg50
|
* bopti: try to display fullscreen images with TLB access + DMA on fxcg50
|
||||||
* gray: double-buffer gray settings and unify d* with g*
|
|
||||||
* topti: support unicode fonts
|
* topti: support unicode fonts
|
||||||
* dma: fx9860g support (need to switch it on and update the Makefile)
|
* dma: fx9860g support (need to switch it on and update the Makefile)
|
||||||
* core: try to leave add-in without reset in case of panic
|
* core: try to leave add-in without reset in case of panic
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
#include <gint/defs/types.h>
|
#include <gint/defs/types.h>
|
||||||
#include <gint/display.h>
|
#include <gint/display.h>
|
||||||
|
|
||||||
/* masks() - compute the vram masks for a given rectangle
|
/* masks(): Compute the vram masks for a given rectangle
|
||||||
|
|
||||||
Since the VRAM is line-based with four uin32_t elements per row, we can
|
Since the VRAM is line-based with four uin32_t elements per row, we can
|
||||||
execute any operation on a rectangle by running it on each set of four
|
execute any operation on a rectangle by running it on each set of four
|
||||||
|
@ -24,7 +24,7 @@
|
||||||
@masks Stores the result of the function (four uint32_t values) */
|
@masks Stores the result of the function (four uint32_t values) */
|
||||||
void masks(int x1, int x2, uint32_t *masks);
|
void masks(int x1, int x2, uint32_t *masks);
|
||||||
|
|
||||||
/* bopti_render_clip() - render a bopti image with clipping
|
/* bopti_render_clip(): Render a bopti image with clipping
|
||||||
@x @y Location of the top-left corner
|
@x @y Location of the top-left corner
|
||||||
@img Image encoded by [fxconv]
|
@img Image encoded by [fxconv]
|
||||||
@left @top @w @h Bounding box to render
|
@left @top @w @h Bounding box to render
|
||||||
|
@ -33,7 +33,7 @@ void masks(int x1, int x2, uint32_t *masks);
|
||||||
void bopti_render_clip(int x, int y, bopti_image_t const *img, int left,
|
void bopti_render_clip(int x, int y, bopti_image_t const *img, int left,
|
||||||
int top, int w, int h, uint32_t *v1, uint32_t *v2, void *bopti_asm);
|
int top, int w, int h, uint32_t *v1, uint32_t *v2, void *bopti_asm);
|
||||||
|
|
||||||
/* bopti_render_noclip() - render a bopti image without clipping
|
/* bopti_render_noclip(): Render a bopti image without clipping
|
||||||
This function is only ever slightly faster than bopti_render_clip(),
|
This function is only ever slightly faster than bopti_render_clip(),
|
||||||
eliminating two types of coordinate checks:
|
eliminating two types of coordinate checks:
|
||||||
1. The bounding box does not overflow from the image
|
1. The bounding box does not overflow from the image
|
||||||
|
@ -47,4 +47,59 @@ void bopti_render_clip(int x, int y, bopti_image_t const *img, int left,
|
||||||
void bopti_render_noclip(int x, int y, bopti_image_t const *img, int left,
|
void bopti_render_noclip(int x, int y, bopti_image_t const *img, int left,
|
||||||
int top, int w, int h, uint32_t *v1, uint32_t *v2, void *bopti_asm);
|
int top, int w, int h, uint32_t *v1, uint32_t *v2, void *bopti_asm);
|
||||||
|
|
||||||
|
//---
|
||||||
|
// Alternate rendering modes
|
||||||
|
//---
|
||||||
|
|
||||||
|
/* The gray engine overrides the rendering functions by specifying a set of
|
||||||
|
alternate primitives that are suited to work with two VRAMs. To avoid
|
||||||
|
linking with them when the gray engine is not used, the display module
|
||||||
|
exposes a global state in the form of a struct rendering_mode and the gray
|
||||||
|
engine modifies that state when it runs. */
|
||||||
|
struct rendering_mode
|
||||||
|
{
|
||||||
|
/* Because the gray engine still has business to do after the call to
|
||||||
|
dgray(DGRAY_OFF), the original dupdate() is made to execute after
|
||||||
|
the replacement one if the replacement one returns 1. */
|
||||||
|
int (*dupdate)(void);
|
||||||
|
/* Area rendering */
|
||||||
|
void (*dclear)(color_t color);
|
||||||
|
void (*drect)(int x1, int y1, int x2, int y2, color_t color);
|
||||||
|
/* Point rendering */
|
||||||
|
void (*dpixel)(int x, int y, color_t color);
|
||||||
|
void (*gint_dhline)(int x1, int x2, int y, int color);
|
||||||
|
void (*gint_dvline)(int y1, int y2, int x, int color);
|
||||||
|
/* Text and image rendering */
|
||||||
|
void (*dtext_opt)
|
||||||
|
(int x, int y, int fg, int bg, int halign, int valign,
|
||||||
|
char const *str);
|
||||||
|
void (*dsubimage)
|
||||||
|
(int x, int y, bopti_image_t const *image, int left, int top,
|
||||||
|
int width, int height, int flags);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The alternate rendering mode pointer (initially NULL)*/
|
||||||
|
extern struct rendering_mode const *dmode;
|
||||||
|
|
||||||
|
/* These are the corresponding gray rendering functions */
|
||||||
|
int gupdate(void);
|
||||||
|
void gclear(color_t color);
|
||||||
|
void grect(int x1, int y1, int x2, int y2, color_t color);
|
||||||
|
void gpixel(int x, int y, color_t color);
|
||||||
|
void gint_ghline(int x1, int x2, int y, int color);
|
||||||
|
void gint_gvline(int y1, int y2, int x, int color);
|
||||||
|
void gtext_opt
|
||||||
|
(int x, int y, int fg, int bg, int halign, int valign,
|
||||||
|
char const *str);
|
||||||
|
void gsubimage
|
||||||
|
(int x, int y, bopti_image_t const *image, int left, int top,
|
||||||
|
int width, int height, int flags);
|
||||||
|
|
||||||
|
/* Short macro to call the alternate rendering function when available */
|
||||||
|
#define DMODE_OVERRIDE(func, ...) \
|
||||||
|
if(dmode && dmode->func) { \
|
||||||
|
dmode->func(__VA_ARGS__); \
|
||||||
|
return; \
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* DISPLAY_FX */
|
#endif /* DISPLAY_FX */
|
||||||
|
|
|
@ -29,12 +29,33 @@
|
||||||
//---
|
//---
|
||||||
|
|
||||||
/* dupdate(): Push the video RAM to the display driver
|
/* 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
|
This function makes the contents of the VRAM visible on the screen. It is
|
||||||
only by calling dvram()), it also swaps buffers. Due to the DMA being used,
|
the equivalent of Bdisp_PutDisp_DD() in most situations.
|
||||||
always waits for the previous call to dupdate() call() to finish. */
|
|
||||||
|
On fx-9860G, this function also manages the gray engine settings. When the
|
||||||
|
gray engine is stopped, it pushes the contents of the VRAM to screen, and
|
||||||
|
when it is on, it swaps buffer and lets the engine's timer push the VRAMs to
|
||||||
|
screen when suitable. To make the transition between the two modes smooth,
|
||||||
|
dgray() does not enable the gray engine immediately; instead the first call
|
||||||
|
to update() after dgray() switches the gray engine on and off.
|
||||||
|
|
||||||
|
On fx-CG 50, because rendering is slow and sending data to screen is also
|
||||||
|
slow, a special mechanism known as triple buffering is implemented. Two
|
||||||
|
VRAMs are allocated, and frames are alternately rendered on each VRAM. When
|
||||||
|
dupdate() is called to push one of the VRAMs to screen, it starts the DMA
|
||||||
|
(which performs the push in the background) and immediately returns after
|
||||||
|
switching to the other VRAM so that the user can draw during the push.
|
||||||
|
|
||||||
|
The transfer from the DMA to the screen lasts about 10 ms if memory is
|
||||||
|
available every cycle. Each access to the memory delays the transfer by a
|
||||||
|
bit, so to fully use the available time, try to run AIs, physics or other
|
||||||
|
calculation-intensive code rather than using the VRAM.
|
||||||
|
|
||||||
|
Typical running time without overclock:
|
||||||
|
fx-9860G: 1 ms (gray engine off)
|
||||||
|
fx-9860G: ~30% of CPU time (gray engine on)
|
||||||
|
fx-CG 50: 11 ms */
|
||||||
void dupdate(void);
|
void dupdate(void);
|
||||||
|
|
||||||
//---
|
//---
|
||||||
|
@ -42,88 +63,108 @@ void dupdate(void);
|
||||||
//---
|
//---
|
||||||
|
|
||||||
/* dclear(): Fill the screen with a single color
|
/* dclear(): Fill the screen with a single color
|
||||||
|
|
||||||
This function clears the screen by painting all the pixels in a single
|
This function clears the screen by painting all the pixels in a single
|
||||||
color. It is optimized for opaque colors.
|
color. It is optimized for opaque colors; on fx-CG 50, it uses dma_memset()
|
||||||
|
to fill in the VRAM.
|
||||||
|
|
||||||
On fx9860g, use drect() if you need complex operators such as invert.
|
Typical running time without overclock:
|
||||||
|
fx-9860G SH3: 70 µs
|
||||||
|
fx-9860G SH4: 15 µs
|
||||||
|
fx-CG 50: 2.5 ms (full-screen drect() is about 6 ms)
|
||||||
|
|
||||||
@color fx9860g: white, black
|
On fx9860g, use drect() if you need operators that modify existing pixels
|
||||||
fxcg50: Any R5G6B5 color */
|
instead of replacing them such as invert.
|
||||||
|
|
||||||
|
@color fx-9860G: white light* dark* black
|
||||||
|
fx-CG 50: Any R5G6B5 color
|
||||||
|
|
||||||
|
*: When the gray engine is on, see dgray(). */
|
||||||
void dclear(color_t color);
|
void dclear(color_t color);
|
||||||
|
|
||||||
/* drect(): Fill a rectangle of the screen
|
/* drect(): Fill a rectangle of the screen
|
||||||
This functions applies a color or an operator to a rectangle defined by two
|
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.
|
points (x1 y1) and (x2 y2). Both are included in the rectangle.
|
||||||
|
|
||||||
@x1 @y1 @x2 @y2 Bounding rectangle (drawn area).
|
@x1 @y1 Top-left rectangle corner (included)
|
||||||
@color fx9860g: white, black, none, invert
|
@x2 @y2 Bottom-right rectangle corner (included)
|
||||||
fxcg50: Any R5G6B5 color */
|
@color fx-9860G: white light* dark* black none invert lighten* darken*
|
||||||
void drect(int x1, int y1, int x2, int y2, color_t color);
|
fx-CG 50: Any R5G6B5 color or C_NONE
|
||||||
|
|
||||||
|
*: When the gray engine is on, see dgray(). */
|
||||||
|
void drect(int x1, int y1, int x2, int y2, int color);
|
||||||
|
|
||||||
/* drect_border(): Rectangle with border
|
/* drect_border(): Rectangle with border
|
||||||
This function draws a rectangle with an inner border. The border width must
|
This function draws a rectangle with an inner border. The border width must
|
||||||
be smaller than half the width and half the height. */
|
be smaller than half the width and half the height.
|
||||||
void drect_border(int x1, int y1, int x2, int y2, int fill_color,
|
|
||||||
int border_width, int border_color);
|
@x1 @y1 @x2 @y2 Top-left and bottom-right rectangle corners (included)
|
||||||
|
@fill_color Center color (same values as drect() are allowed)
|
||||||
|
@border_width Amount of pixels reserved for the border on each side
|
||||||
|
@border_color Border color (same values as drect() are allowed) */
|
||||||
|
void drect_border(int x1, int y1, int x2, int y2,
|
||||||
|
int fill_color, int border_width, int border_color);
|
||||||
|
|
||||||
//---
|
//---
|
||||||
// Point drawing functions
|
// Point drawing functions
|
||||||
//---
|
//---
|
||||||
|
|
||||||
/* dpixel(): Change a pixel's color
|
/* 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
|
Paints the selected pixel with an opaque color or applies an operator to a
|
||||||
|
pixel. 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, so prefer using them
|
||||||
|
when they apply.
|
||||||
|
|
||||||
|
On fx-9860G, if an operator such as invert is used, the result will depend
|
||||||
on the current color of the pixel.
|
on the current color of the pixel.
|
||||||
|
|
||||||
@x @y Coordinates of the pixel to repaint
|
@x @y Coordinates of the pixel to repaint
|
||||||
@color fx9860g: white, black, none, invert
|
@color fx-9860G: white light* dark* black none invert lighten* darken*
|
||||||
fxcg50: Any R5G6B5 color */
|
fx-CG 50: Any R5G6B5 color or C_NONE
|
||||||
void dpixel(int x, int y, color_t color);
|
|
||||||
|
*: When the gray engine is on, see dgray(). */
|
||||||
|
void dpixel(int x, int y, int color);
|
||||||
|
|
||||||
/* dline(): Render a straight line
|
/* dline(): Render a straight line
|
||||||
|
|
||||||
This function draws a line using a Bresenham-style algorithm. Please note
|
This function draws a line using a Bresenham-style algorithm. Please note
|
||||||
that dline() may not render lines exactly like Bdisp_DrawLineVRAM().
|
that dline() may not render lines exactly like Bdisp_DrawLineVRAM().
|
||||||
|
|
||||||
dline() has optimization facilities for horizontal and vertical lines. The
|
dline() has optimizations for horizontal and vertical lines. The speedup for
|
||||||
speedup for horizontal lines is about x2 on fxcg50 and probably about x30
|
horizontal lines is about x2 on fx-CG 50 and probably about x30 on fx-9860G.
|
||||||
on fx9860g. Vertical lines have a smaller speedup.
|
Vertical lines have a smaller speedup.
|
||||||
|
|
||||||
dline() is currently not able to clip arbitrary lines without calculating
|
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
|
all the pixels, so drawing a line from (-1e6,0) to (1e6,395) will work but
|
||||||
will be veeery slow.
|
will be very slow.
|
||||||
|
|
||||||
@x1 @y1 @x2 @y2 End points of the line (both included).
|
@x1 @y1 @x2 @y2 Endpoints of the line (both included).
|
||||||
@color fx9860g: white, black, none, invert
|
@color Line color (same values as dpixel() are allowed) */
|
||||||
fxcg50: Any R5G6B5 color */
|
void dline(int x1, int y1, int x2, int y2, int color);
|
||||||
void dline(int x1, int y1, int x2, int y2, color_t color);
|
|
||||||
|
|
||||||
/* dhline(): Full-width horizontal line
|
/* dhline(): Full-width horizontal line
|
||||||
This function draws a horizontal line from the left end of the screen to the
|
This function draws a horizontal line from the left end of the screen to the
|
||||||
right end, much like the Basic command "Horizontal".
|
right end, much like the Basic command "Horizontal".
|
||||||
|
|
||||||
@y Line number
|
@y Line number
|
||||||
@color fx9860g: white, black, none, invert
|
@color Line color (same values as dline() are allowed) */
|
||||||
fxcg50: Any R5G6B5 color */
|
void dhline(int y, int color);
|
||||||
void dhline(int y, color_t color);
|
|
||||||
|
|
||||||
/* dvline(): Full-height vertical line
|
/* dvline(): Full-height vertical line
|
||||||
This function draws a vertical line from the top end of the screen to the
|
This function draws a vertical line from the top end of the screen to the
|
||||||
bottom end, much like the Basic command "Vertical".
|
bottom end, much like the Basic command "Vertical".
|
||||||
|
|
||||||
@x Column number
|
@x Column number
|
||||||
@color fx9860g: white, black, none, invert
|
@color Line color (same values as dline() are allowed) */
|
||||||
fxcg50: Any R5G6B5 color */
|
void dvline(int x, int color);
|
||||||
void dvline(int x, color_t color);
|
|
||||||
|
|
||||||
//---
|
//---
|
||||||
// Text rendering (topti)
|
// Text rendering (topti)
|
||||||
//---
|
//---
|
||||||
|
|
||||||
/* font_t - font data encoded for topti */
|
/* font_t: Font data encoded for topti */
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
/* Length of font name (not necessarily NUL-terminated!) */
|
/* Length of font name (not necessarily NUL-terminated!) */
|
||||||
|
@ -172,17 +213,28 @@ typedef struct
|
||||||
} GPACKED(4) font_t;
|
} GPACKED(4) font_t;
|
||||||
|
|
||||||
/* dfont(): Set the default font for text rendering
|
/* 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.
|
This function changes the default font for text rendering; this affects
|
||||||
On fxcg50, the default font is an original 8x9 font.
|
dtext_opt(), dtext() and the related functions. If the specified font is
|
||||||
|
NULL, gint's default font is used instead.
|
||||||
|
|
||||||
|
On fx-9860G, the default font is a 5x7 font very close to the system's.
|
||||||
|
On fx-CG 50, the default font is an original, proportional 8x9 font.
|
||||||
|
|
||||||
|
This function returns the previously configured font. Normally you want to
|
||||||
|
restore it after you're done so as to not affect ambiant calls to text
|
||||||
|
rendering functions. It would look like this:
|
||||||
|
|
||||||
|
font_t const *old_font = dfont(new_font);
|
||||||
|
// Do the text rendering...
|
||||||
|
dfont(old_font);
|
||||||
|
|
||||||
@font Font to use for subsequent text rendering calls
|
@font Font to use for subsequent text rendering calls
|
||||||
Returns the previously configured font. */
|
Returns the previously configured font. */
|
||||||
font_t const *dfont(font_t const * font);
|
font_t const *dfont(font_t const *font);
|
||||||
|
|
||||||
/* dsize(): Get the width and height of rendered text
|
/* dsize(): Get the width and height of rendered text
|
||||||
|
|
||||||
This function computes the size that the given string would take up if
|
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
|
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
|
configured font will be used; this is different from dfont(), which uses
|
||||||
|
@ -191,15 +243,15 @@ font_t const *dfont(font_t const * font);
|
||||||
Note that the height of each glyph is not stored in the font, only the
|
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
|
maximum. Usually this is what you want because vertically-centered strings
|
||||||
must have the same baseline regardless of their contents. So the height
|
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.
|
set by dsize() is the same for all strings and only depends on the font.
|
||||||
|
|
||||||
The height is computed in constant time, and the width in linear time. If
|
The height is computed in constant time, and the width in linear time. If
|
||||||
[w = NULL], this function returns in constant time.
|
the third argument is NULL, this function returns in constant time.
|
||||||
|
|
||||||
@str String whose size must be evaluated
|
@str String whose size must be evaluated
|
||||||
@font Font to use; if NULL, defaults to the current font
|
@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 */
|
@w @h Set to the width and height of the rendered text, may be NULL */
|
||||||
void dsize(char const *str, font_t const * font, int *w, int *h);
|
void dsize(char const *str, font_t const *font, int *w, int *h);
|
||||||
|
|
||||||
/* Alignment settings for dtext_opt() and dprint_opt(). Combining a vertical
|
/* Alignment settings for dtext_opt() and dprint_opt(). Combining a vertical
|
||||||
and a horizontal alignment option specifies where a given point (x,y) should
|
and a horizontal alignment option specifies where a given point (x,y) should
|
||||||
|
@ -221,61 +273,66 @@ enum {
|
||||||
default if no such font was set). This function has a lot of parameters,
|
default if no such font was set). This function has a lot of parameters,
|
||||||
see dtext() for a simpler version.
|
see dtext() for a simpler version.
|
||||||
|
|
||||||
On fx9860g, due to the particular design of topti, this function performs
|
The alignment options specify where (x y) should be relative to the rendered
|
||||||
drastic rendering optimizations using the line structure of the VRAM and is
|
string. The default is halign=DTEXT_LEFT and valign=DTEXT_TOP, which means
|
||||||
able to render several characters at once.
|
that (x y) is the top-left corder of the rendered string. The different
|
||||||
|
combinations of settings provide 9 positions of (x y) to choose from.
|
||||||
|
|
||||||
This is not a printf()-family function so [str] cannot contain formats like
|
On fx-9860G, due to the particular design of topti, this function performs
|
||||||
|
drastic rendering optimizations using the line structure of the VRAM and
|
||||||
|
renders 5 or 6 characters simultaneously.
|
||||||
|
|
||||||
|
This is not a printf()-family function so str cannot contain formats like
|
||||||
"%d" and you cannot pass additional arguments. See dprint_opt() and dprint()
|
"%d" and you cannot pass additional arguments. See dprint_opt() and dprint()
|
||||||
for that.
|
for that.
|
||||||
|
|
||||||
@x @y Coordinates of top-left corner of the rendered string
|
@x @y Coordinates of the anchor of the rendered string
|
||||||
@fg Text color
|
@fg @bg Text color and background color
|
||||||
fx9860g: white, black, none, invert
|
fx-9860G: white light* dark* black none invert lighten* darken*
|
||||||
fxcg50: Any R5G6B6 color, or C_NONE
|
fx-CG 50: Any R5G6B6 color, or C_NONE
|
||||||
@bg Background color
|
@halign Where x should be relative to the rendered string
|
||||||
fx9860g: white, black, none, invert
|
@valign Where y should be relative to the rendered string
|
||||||
fxcg50: Any R5G6B5 color, or C_NONE
|
|
||||||
@halign Where x should be relative to the rendered string (see above enum)
|
|
||||||
@valign Where y should be relative to the rendered string (see above enum)
|
|
||||||
@str String to display */
|
@str String to display */
|
||||||
void dtext_opt(int x, int y, int fg, int bg, int halign, int valign,
|
void dtext_opt(int x, int y, int fg, int bg, int halign, int valign,
|
||||||
char const *str);
|
char const *str);
|
||||||
|
|
||||||
/* dtext(): Simple version of dtext_opt() with defaults
|
/* dtext(): Simple version of dtext_opt() with defaults
|
||||||
This is exactly dtext_opt() with bg=C_NONE, halign=DTEXT_LEFT and
|
Calls dtext_opt() with bg=C_NONE, halign=DTEXT_LEFT and valign=DTEXT_TOP. */
|
||||||
valign=DTEXT_TOP. */
|
|
||||||
void dtext(int x, int y, int fg, char const *str);
|
void dtext(int x, int y, int fg, char const *str);
|
||||||
|
|
||||||
/* dprint_opt(): Display a formatted string
|
/* dprint_opt(): Display a formatted string
|
||||||
Much like dtext_opt(), but accepts printf-like formats with arguments. See
|
|
||||||
<gint/std/stdio.h> for a detailed view of what this format supports. */
|
This function is exactly like dtext_opt(), but accepts printf-like formats
|
||||||
|
with arguments. See <gint/std/stdio.h> for a detailed view of what this
|
||||||
|
format supports. For example:
|
||||||
|
|
||||||
|
dprint_opt(x, y, fg, bg, halign, valign, "A=%d B=%d", A, B); */
|
||||||
void dprint_opt(int x, int y, int fg, int bg, int halign, int valign,
|
void dprint_opt(int x, int y, int fg, int bg, int halign, int valign,
|
||||||
char const *format, ...);
|
char const *format, ...);
|
||||||
|
|
||||||
/* dprint(): Simple version of dprint_op() with defaults
|
/* dprint(): Simple version of dprint_op() with defaults
|
||||||
Like dtext() with formatted printing. */
|
Calls dprint_opt() with bg=C_NONE, halign=DTEXT_LEFT and valign=DTEXT_TOP */
|
||||||
void dprint(int x, int y, int fg, char const *format, ...);
|
void dprint(int x, int y, int fg, char const *format, ...);
|
||||||
|
|
||||||
//---
|
//---
|
||||||
// Image rendering (bopti)
|
// Image rendering (bopti)
|
||||||
//---
|
//---
|
||||||
|
|
||||||
/* The bopti_image_t structure is platform-dependent. */
|
/* The bopti_image_t structure is platform-dependent, see <gint/display-fx.h>
|
||||||
|
and <gint/display-cg.h> if you're curious. */
|
||||||
|
|
||||||
/* dimage(): Render a full image
|
/* dimage(): Render a full image
|
||||||
This function blits an image on the VRAM using gint's special format. It is
|
This function blits an image on the VRAM using gint's special format. It is
|
||||||
a special case of dsubimage() where the full image is drawn with clipping.
|
a special case of dsubimage() where the full image is drawn with clipping.
|
||||||
|
|
||||||
@x @y Coordinates of the top-left corner of the image
|
@x @y Coordinates of the top-left corner of the image
|
||||||
@image Pointer to image encoded with [fxconv] */
|
@image Pointer to image encoded with fxconv for bopti */
|
||||||
void dimage(int x, int y, bopti_image_t const *image);
|
void dimage(int x, int y, bopti_image_t const *image);
|
||||||
|
|
||||||
/* Option values for dsubimage() */
|
/* Option values for dsubimage() */
|
||||||
enum {
|
enum {
|
||||||
/* No option */
|
/* No option */
|
||||||
DIMAGE_NONE = 0x00,
|
DIMAGE_NONE = 0x00,
|
||||||
|
|
||||||
/* Disable clipping, ie. adjustments to the specified subrectangle and
|
/* Disable clipping, ie. adjustments to the specified subrectangle and
|
||||||
screen location such that any part that overflows from the image or
|
screen location such that any part that overflows from the image or
|
||||||
the screen is ignored. Slightly faster. */
|
the screen is ignored. Slightly faster. */
|
||||||
|
@ -287,23 +344,11 @@ enum {
|
||||||
the VRAM. It is more general than dimage() and also provides a few options.
|
the VRAM. It is more general than dimage() and also provides a few options.
|
||||||
|
|
||||||
@x @y Coordinates on screen of the rendered subrectangle
|
@x @y Coordinates on screen of the rendered subrectangle
|
||||||
@image Pointer to image encoded with [fxconv]
|
@image Pointer to image encoded with fxconv for bopti
|
||||||
@left @top Top-left coordinates of the subrectangle within [image]
|
@left @top Top-left coordinates of the subrectangle within the image
|
||||||
@width @height Subrectangle dimensions
|
@width @height Subrectangle dimensions
|
||||||
@flags OR-combination of DIMAGE_* flags */
|
@flags OR-combination of DIMAGE_* flags */
|
||||||
void dsubimage(int x, int y, bopti_image_t const *image, int left, int top,
|
void dsubimage(int x, int y, bopti_image_t const *image, int left, int top,
|
||||||
int width, int height, int flags);
|
int width, int height, int flags);
|
||||||
|
|
||||||
//---
|
|
||||||
// Advanced functions
|
|
||||||
//---
|
|
||||||
|
|
||||||
/* dupdate_noint(): Push VRAM to the display without interrupts
|
|
||||||
This function does exactly as dupdate(), but does not use interrupts and
|
|
||||||
always returns when the transfer is finished. It actively waits for the end
|
|
||||||
of the transfer and is thus bad for any general-purpose use. In fact, it is
|
|
||||||
only needed to display panic messages in exception handlers. Don't use it
|
|
||||||
unless you know precisely why you're doing it. */
|
|
||||||
void dupdate_noint(void);
|
|
||||||
|
|
||||||
#endif /* GINT_DISPLAY */
|
#endif /* GINT_DISPLAY */
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
//---
|
//---
|
||||||
// gint:gray - Gray engine and rendering functions
|
// gint:gray - Gray engine control
|
||||||
//---
|
//---
|
||||||
|
|
||||||
#ifndef GINT_GRAY
|
#ifndef GINT_GRAY
|
||||||
|
@ -8,34 +8,71 @@
|
||||||
#include <gint/defs/types.h>
|
#include <gint/defs/types.h>
|
||||||
#include <gint/display.h>
|
#include <gint/display.h>
|
||||||
|
|
||||||
//---
|
/* Commands for the gray engine */
|
||||||
// Engine control
|
enum {
|
||||||
//---
|
/* Start or stop the engine */
|
||||||
|
DGRAY_ON,
|
||||||
|
DGRAY_OFF,
|
||||||
|
/* Start or stop the engine, but remember previous state */
|
||||||
|
DGRAY_PUSH_ON,
|
||||||
|
DGRAY_PUSH_OFF,
|
||||||
|
/* Restore previous state remembered by DGRAY_PUSH_* */
|
||||||
|
DGRAY_POP,
|
||||||
|
};
|
||||||
|
|
||||||
/* gray_start(): Start the gray engine
|
/* dgray(): Start or stop the gray engine at the next dupdate()
|
||||||
|
|
||||||
The control of the screen is transferred to the engine; you should not use
|
This function configures the display module to work with or without the gray
|
||||||
dupdate() after this function, only gupdate().
|
engine. When the mode is set to DGRAY_ON, all rendering functions are
|
||||||
|
replaced to use gray rendering, and gray frames will start being displayed
|
||||||
|
after the next dupdate(). To transition from monochrome rendering to gray
|
||||||
|
rendering, you must first call dgray(DGRAY_ON), then draw your first gray
|
||||||
|
frame from scratch, then call dupdate().
|
||||||
|
|
||||||
The engine uses timer number GRAY_TIMER (equal to 0 by default) to run. If
|
Similarly, when the mode is DGRAY_OFF, all rendering functions are replaced
|
||||||
the timer is unavailable, this function will fail. Otherwise, the gray
|
to use monochrome rendering, and the next frame sent with dupdate() will
|
||||||
engine is started and any attempt to use timer 0 while it is running will be
|
stop the gray engine on the display. To transition back to monochrome
|
||||||
denied by the timer module. */
|
rendering, call dgray(DGRAY_OFF), draw your first monochrome frame from
|
||||||
void gray_start(void);
|
scratch, then call dupdate().
|
||||||
|
|
||||||
/* gray_stop(): Stop the gray engine
|
The gray engine uses the timer id GRAY_TIMER (which is 0) to run and needs 3
|
||||||
|
additional VRAMs (totaling 4), obtained on the heap by default. Timer 0 is
|
||||||
|
chosen for its precision and high priority. If GRAY_TIMER is unavailable or
|
||||||
|
VRAMs cannot be obtained with malloc(), the gray engine will fail to start
|
||||||
|
and this function will return a non-zero error code.
|
||||||
|
|
||||||
Safe to call if the engine was not running. The gray engine returns the
|
When functions that use the gray engine call functions that don't and vice-
|
||||||
control of the screen and dupdate() is safe to use again.
|
versa, it can be tedious to know exacly when the gray engine should be
|
||||||
|
running. This function provides a stack of gray engine states to solve this
|
||||||
|
problem. When entering a function that uses/doesn't use the gray engine, you
|
||||||
|
can call dgray(DGRAY_PUSH_ON)/dgray(DGRAY_PUSH_OFF) to start/stop the
|
||||||
|
engine; then call dgray(DGRAY_POP) at the end of the function.
|
||||||
|
dgray(DGRAY_POP) will restore the state of the engine as it was before the
|
||||||
|
previous DGRAY_PUSH_*. This allows each function to set its own state
|
||||||
|
without altering the state of their callers.
|
||||||
|
|
||||||
This function will leave the screen in whatever state it is, which is most
|
This function returns non-zero if the engine has failed to initialize at
|
||||||
probably one of the gray buffers being displayed. You should dupdate()
|
startup (because it failed to obtain either GRAY_TIMER or some of its VRAM
|
||||||
quickly after this call to avoid visual artifacts. If the next monochrome
|
memory). Because changes to the gray engine only apply after a call to
|
||||||
frame is slow to render, consider rendering it before stopping the gray
|
dupdate(), you can check if the engine is successfully initialized with:
|
||||||
engine, and calling dupdate() immediately after. */
|
|
||||||
void gray_stop(void);
|
|
||||||
|
|
||||||
/* gray_delays(): Set the gray engine delays
|
int engine_successfully_initialized = dgray(DGRAY_ON);
|
||||||
|
dgray(DGRAY_OFF);
|
||||||
|
|
||||||
|
@mode DGRAY_ON or DGRAY_PUSH_ON to turn the engine on;
|
||||||
|
DGRAY_OFF or DGRAY_PUSH_OFF to turn the engine off;
|
||||||
|
DGRAY_POP to restore the state as before the last DGRAY_PUSH_*.
|
||||||
|
|
||||||
|
Returns 0 on success and non-zero if the engine has failed to initialize. */
|
||||||
|
int dgray(int mode);
|
||||||
|
|
||||||
|
/* dgray_enabled(): Check whether gray mode is enabled
|
||||||
|
Returns non-zero if gray mode is enabled, that is if the gray engine is
|
||||||
|
planning to run at the next call to dupdate(). (This is true between the
|
||||||
|
calls to dgray(DGRAY_ON) and dgray(DGRAY_OFF).) */
|
||||||
|
int dgray_enabled(void);
|
||||||
|
|
||||||
|
/* dgray_setdelays(): Set the gray engine delays
|
||||||
|
|
||||||
The gray engine works by swapping two images at a fast pace. Pixels that are
|
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
|
white on both or black or both will appear as such, but pixels that are
|
||||||
|
@ -59,164 +96,83 @@ void gray_stop(void);
|
||||||
and speed; but overall they're the *one* thing you want to avoid.
|
and speed; but overall they're the *one* thing you want to avoid.
|
||||||
* And the color of the shades themselves.
|
* And the color of the shades themselves.
|
||||||
|
|
||||||
Here are values from an older version of gint, which may not look good now
|
Here are values from the old fx-9860G-like family, which is every monochrome
|
||||||
but provide bases to search for good settings:
|
calculator but the Graph 35+E II:
|
||||||
|
|
||||||
LIGHT DARK BLINKING STRIPES COLORS
|
LIGHT DARK BLINKING STRIPES COLORS
|
||||||
--------------------------------------------------
|
--------------------------------------------------
|
||||||
860 1298 none terrible decent
|
898 1350 none common good
|
||||||
912 1343 heavy none good
|
1075 1444 low common too close
|
||||||
993 1609 medium light decent
|
609 884 medium terrible variable
|
||||||
1325 1607 heavy light excellent
|
937 1333 low common decent
|
||||||
923 1742 none scanline good [default]
|
923 1742 none scanline good [default]
|
||||||
--------------------------------------------------
|
--------------------------------------------------
|
||||||
|
|
||||||
Here are values for this version of gint (for the Graph 35+E II only):
|
Here are values for the Graph 35+E II only:
|
||||||
|
|
||||||
LIGHT DARK BLINKING STRIPES COLORS
|
LIGHT DARK BLINKING STRIPES COLORS
|
||||||
--------------------------------------------------
|
--------------------------------------------------
|
||||||
680 1078
|
680 1078 low common good
|
||||||
762 1311 low some too light [default]
|
762 1311 low some good [default]
|
||||||
869 1097 medium some excellent
|
869 1097 medium some too close
|
||||||
869 1311 medium none good
|
869 1311 medium none good
|
||||||
937 1425 medium none good
|
937 1425 none bad good
|
||||||
--------------------------------------------------
|
--------------------------------------------------
|
||||||
|
|
||||||
|
This function sets the delays of the gray engine. It is safe to call while
|
||||||
|
the engine is running, although for best visual effects it is better to call
|
||||||
|
it prior to dgray(GRAY_ON).
|
||||||
|
|
||||||
@light New light delay
|
@light New light delay
|
||||||
@dark New dark delay */
|
@dark New dark delay */
|
||||||
void gray_delays(uint32_t light, uint32_t dark);
|
void dgray_setdelays(uint32_t light, uint32_t dark);
|
||||||
|
|
||||||
/* gray_config(): Get the current configuration of the engine
|
/* dgray_getdelays(): Get the gray engine delays
|
||||||
|
|
||||||
Provides the value of the current light and dark delays, measured in timer
|
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.
|
ticks of prescaler P_phi/64. See <gint/clock.h> on how to obtain this value.
|
||||||
Both pointers may be NULL.
|
Both pointers may be NULL.
|
||||||
|
|
||||||
@light Set to the current light delay setting
|
@light Set to the current light delay setting
|
||||||
@dark Set to the current dark delay setting
|
@dark Set to the current dark delay setting */
|
||||||
Returns non-zero if the engine is currently running, 0 otherwise. */
|
void dgray_getdelays(uint32_t *light, uint32_t *dark);
|
||||||
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);
|
|
||||||
|
|
||||||
/* ghline(): Full-width horizontal line
|
|
||||||
@y Line number
|
|
||||||
@color white, light, dark, black, none, invert, lighten, darken */
|
|
||||||
void ghline(int y, color_t color);
|
|
||||||
|
|
||||||
/* gvline(): Full-height vertical line
|
|
||||||
@x Column number
|
|
||||||
@color white, light, dark, black, none, invert, lighten, darken */
|
|
||||||
void gvline(int x, 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);
|
|
||||||
|
|
||||||
//---
|
|
||||||
// Image rendering
|
|
||||||
//---
|
|
||||||
|
|
||||||
/* gimage(): Render a full image
|
|
||||||
This function is exactly like dimage(), but it draws gray image instead.
|
|
||||||
|
|
||||||
@x @y Coordinates of the top-left corner of the image
|
|
||||||
@image Pointer to gray image encoded with [fxconv] */
|
|
||||||
void gimage(int x, int y, bopti_image_t const *image);
|
|
||||||
|
|
||||||
/* gsubimage(): Render a section of an image
|
|
||||||
Like dsubimage() for gray images. Same options apply.
|
|
||||||
|
|
||||||
@x @y Coordinates on screen of the rendered subrectangle
|
|
||||||
@image Pointer to image encoded with [fxconv]
|
|
||||||
@left @top Top-left coordinates of the subrectangle within [image]
|
|
||||||
@width @height Subrectangle dimensions
|
|
||||||
@flags OR-combination of DIMAGE_* flags */
|
|
||||||
void gsubimage(int x, int y, bopti_image_t const *image, int left, int top,
|
|
||||||
int width, int height, int flags);
|
|
||||||
|
|
||||||
//---
|
//---
|
||||||
// VRAM management
|
// VRAM management
|
||||||
//---
|
//---
|
||||||
|
|
||||||
/* gupdate(): Push the current VRAMs to the screen
|
/* dgray_getvram(): Get the current VRAM pointers
|
||||||
|
These pointers can be used for custom rendering functions. */
|
||||||
|
void dgray_getvram(uint32_t **light, uint32_t **dark);
|
||||||
|
|
||||||
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
|
// Aliases for older programs
|
||||||
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
|
/* Functions for the gray engine used to be called g*() to mirror the d*()
|
||||||
interaction is done very frequently by the engine itself. It performs an
|
functions of the display module. They are now bundled together, so these
|
||||||
atomic operation to swap buffers, but nothing on the screen will change
|
aliases are for older programs that still use the g*() naming scheme */
|
||||||
until the engine's timer actually fires. */
|
|
||||||
void gupdate(void);
|
|
||||||
|
|
||||||
|
#ifdef GINT_GRAY_ALIASES
|
||||||
|
|
||||||
/* gvram(): Get the current VRAM pointers
|
#define gclear dclear
|
||||||
|
#define grect drect
|
||||||
|
#define gpixel dpixel
|
||||||
|
#define gline dline
|
||||||
|
#define ghline dhline
|
||||||
|
#define gvline dvline
|
||||||
|
#define gimage dimage
|
||||||
|
#define gsubimage dsubimage
|
||||||
|
#define gtext dtext
|
||||||
|
#define gtext_opt dtext_opt
|
||||||
|
#define gprint dprint
|
||||||
|
#define gprint_opt dprint_opt
|
||||||
|
|
||||||
This function stores the current VRAM pointers to the specified locations.
|
#define gupdate dupdate
|
||||||
This operation needs to be done atomically because the engine might kick in
|
#define gray_delays dgray_setdelays
|
||||||
and sway buffers at any time; calling gvraml() then gvramd() is unsafe.
|
#define gray_config dgray_getdelays
|
||||||
|
#define gvram dgray_getvram
|
||||||
|
|
||||||
@light Set to the current light VRAM pointer
|
#endif /* GINT_GRAY_ALIASES */
|
||||||
@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 */
|
#endif /* GINT_GRAY */
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
#include <gint/display.h>
|
#include <gint/display.h>
|
||||||
#include <gint/timer.h>
|
#include <gint/timer.h>
|
||||||
|
|
||||||
|
#include <display/fx.h>
|
||||||
|
|
||||||
/* Three additional video RAMS, allocated statically if --static-gray was set
|
/* Three additional video RAMS, allocated statically if --static-gray was set
|
||||||
at configure time, or with malloc() otherwise. */
|
at configure time, or with malloc() otherwise. */
|
||||||
#ifdef GINT_STATIC_GRAY
|
#ifdef GINT_STATIC_GRAY
|
||||||
|
@ -17,27 +19,63 @@ GBSS static uint32_t gvrams[3][256];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Four VRAMs: two to draw and two to display */
|
/* Four VRAMs: two to draw and two to display */
|
||||||
GBSS static uint32_t *vrams[4];
|
static uint32_t *vrams[4] = { NULL, NULL, NULL, NULL };
|
||||||
|
|
||||||
/* Current VRAM pair used for drawing; the value can either be 0 (draws to
|
/* 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). */
|
VRAMs 0 and 1) or 2 (draws to VRAMs 2 and 3). */
|
||||||
static volatile int st = 0;
|
static int volatile st = 0;
|
||||||
|
/* Timer ID, always equal to GRAY_TIMER except if initialization fails */
|
||||||
/* Whether the engine is running. Delays of light and dark frames. */
|
static int timer = -1;
|
||||||
|
/* Whether the engine is scheduled to run at the next frame */
|
||||||
static int runs = 0;
|
static int runs = 0;
|
||||||
|
|
||||||
|
/* Underlying timer, set to count at P_phi/64 */
|
||||||
|
#define GRAY_TIMER 0
|
||||||
|
#define GRAY_CLOCK TIMER_Pphi_64
|
||||||
|
/* Delays of the light and dark frames for the above setting */
|
||||||
GBSS static int delays[2];
|
GBSS static int delays[2];
|
||||||
|
|
||||||
/* Underlying timer */
|
/* The alternate rendering mode structure used to override d*() */
|
||||||
#define GRAY_TIMER 0
|
static struct rendering_mode const gray_mode = {
|
||||||
|
.dupdate = gupdate,
|
||||||
|
.dclear = gclear,
|
||||||
|
.drect = grect,
|
||||||
|
.dpixel = gpixel,
|
||||||
|
.gint_dhline = gint_ghline,
|
||||||
|
.gint_dvline = gint_gvline,
|
||||||
|
.dtext_opt = gtext_opt,
|
||||||
|
.dsubimage = gsubimage,
|
||||||
|
};
|
||||||
|
static struct rendering_mode const gray_exit_mode = {
|
||||||
|
.dupdate = gupdate,
|
||||||
|
.dclear = NULL,
|
||||||
|
.drect = NULL,
|
||||||
|
.dpixel = NULL,
|
||||||
|
.gint_dhline = NULL,
|
||||||
|
.gint_dvline = NULL,
|
||||||
|
.dtext_opt = NULL,
|
||||||
|
.dsubimage = NULL,
|
||||||
|
};
|
||||||
|
|
||||||
//---
|
//---
|
||||||
// Engine control
|
// Engine control (init/quit and start/stop)
|
||||||
//---
|
//---
|
||||||
|
|
||||||
/* gray_init(): Engine setup */
|
static int gray_int(void);
|
||||||
|
static void gray_quit(void);
|
||||||
|
|
||||||
|
/* gray_isinit(): Check whether the engine is initialized and ready to run */
|
||||||
|
static int gray_isinit(void)
|
||||||
|
{
|
||||||
|
return (vrams[0] && vrams[1] && vrams[2] && vrams[3] && timer >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* gray_init(): Initialize the engine
|
||||||
|
This is done at startup so that memory can be reserved very early from the
|
||||||
|
heap (because not having enough memory is unrecoverable for the engine). */
|
||||||
GCONSTRUCTOR static void gray_init(void)
|
GCONSTRUCTOR static void gray_init(void)
|
||||||
{
|
{
|
||||||
/* Here [gint_vram] refers to the standard, monochrome VRAM */
|
/* We need four VRAMs. First use the standard monochrome one */
|
||||||
vrams[0] = gint_vram;
|
vrams[0] = gint_vram;
|
||||||
|
|
||||||
#ifdef GINT_STATIC_GRAY
|
#ifdef GINT_STATIC_GRAY
|
||||||
|
@ -61,16 +99,74 @@ GCONSTRUCTOR static void gray_init(void)
|
||||||
delays[0] = 923;
|
delays[0] = 923;
|
||||||
delays[1] = 1742;
|
delays[1] = 1742;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Try to obtain the timer right away */
|
||||||
|
timer = timer_setup(GRAY_TIMER | GRAY_CLOCK, 1000, gray_int);
|
||||||
|
|
||||||
|
/* On failure, release the resources that we obtained */
|
||||||
|
if(!gray_isinit()) gray_quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* gray_quit(): Engine deinitialization() */
|
/* gray_quit(): Free engine resources */
|
||||||
GDESTRUCTOR static void gray_quit(void)
|
GDESTRUCTOR static void gray_quit(void)
|
||||||
{
|
{
|
||||||
#ifndef GINT_STATIC_GRAY
|
#ifndef GINT_STATIC_GRAY
|
||||||
free(vrams[1]);
|
if(vrams[1]) free(vrams[1]);
|
||||||
free(vrams[2]);
|
if(vrams[2]) free(vrams[2]);
|
||||||
free(vrams[3]);
|
if(vrams[3]) free(vrams[3]);
|
||||||
|
|
||||||
|
vrams[1] = NULL;
|
||||||
|
vrams[2] = NULL;
|
||||||
|
vrams[3] = NULL;
|
||||||
#endif /* GINT_STATIC_GRAY */
|
#endif /* GINT_STATIC_GRAY */
|
||||||
|
|
||||||
|
if(timer >= 0) timer_stop(timer);
|
||||||
|
timer = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* gray_start(): Start the gray engine */
|
||||||
|
static void gray_start(void)
|
||||||
|
{
|
||||||
|
st = 2;
|
||||||
|
timer_reload(GRAY_TIMER, delays[0]);
|
||||||
|
timer_start(GRAY_TIMER);
|
||||||
|
runs = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* gray_stop(): Stop the gray engine */
|
||||||
|
static void gray_stop(void)
|
||||||
|
{
|
||||||
|
timer_pause(GRAY_TIMER);
|
||||||
|
runs = 0;
|
||||||
|
st = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---
|
||||||
|
// Dynamic udpate and rendering mode
|
||||||
|
//---
|
||||||
|
|
||||||
|
/* dgray(): Start or stop the gray engine at the next dupdate() */
|
||||||
|
int dgray(int mode)
|
||||||
|
{
|
||||||
|
if(mode == DGRAY_ON)
|
||||||
|
{
|
||||||
|
if(!gray_isinit()) return 1;
|
||||||
|
|
||||||
|
/* Set the display module's alternate rendering mode to
|
||||||
|
override rendering functions to use their g*() variant */
|
||||||
|
dmode = &gray_mode;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if(mode == DGRAY_OFF)
|
||||||
|
{
|
||||||
|
/* Set the mode to a temporary one that only overrides
|
||||||
|
dupdate() so that we can stop the engine next frame */
|
||||||
|
if(dmode == &gray_mode) dmode = &gray_exit_mode;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: DGRAY_PUSH_* and DGRAY_POP */
|
||||||
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* gray_int(): Interrupt handler */
|
/* gray_int(): Interrupt handler */
|
||||||
|
@ -83,69 +179,57 @@ int gray_int(void)
|
||||||
return TIMER_CONTINUE;
|
return TIMER_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* gray_start(): Start the gray engine */
|
/* gupdate(): Push the current VRAMs to the screen */
|
||||||
void gray_start(void)
|
int gupdate(void)
|
||||||
{
|
{
|
||||||
#ifndef GINT_STATIC_GRAY
|
/* At the first gupdate(), start the engine */
|
||||||
if(!vrams[1] || !vrams[2] || !vrams[3]) return;
|
if(dmode == &gray_mode && !runs)
|
||||||
#endif
|
{
|
||||||
|
gray_start();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* At the last gupdate(), stop the engine */
|
||||||
|
if(dmode == &gray_exit_mode)
|
||||||
|
{
|
||||||
|
gray_stop();
|
||||||
|
dmode = NULL;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if(runs) return;
|
/* When the engine is running, swap frames */
|
||||||
|
st ^= 2;
|
||||||
int timer = timer_setup(GRAY_TIMER|TIMER_Pphi_64, delays[0], gray_int);
|
return 0;
|
||||||
if(timer != GRAY_TIMER) return;
|
|
||||||
|
|
||||||
timer_start(GRAY_TIMER);
|
|
||||||
st = 0;
|
|
||||||
runs = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* gray_stop(): Stop the gray engine */
|
//---
|
||||||
void gray_stop(void)
|
// Query and configuration functions
|
||||||
|
//---
|
||||||
|
|
||||||
|
/* dgray_enabled(): Check whether gray mode is enabled */
|
||||||
|
int dgray_enabled(void)
|
||||||
{
|
{
|
||||||
timer_stop(GRAY_TIMER);
|
return (dmode == &gray_mode);
|
||||||
runs = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* gray_delays(): Set the gray engine delays */
|
/* dgray_setdelays(): Set the gray engine delays */
|
||||||
void gray_delays(uint32_t light, uint32_t dark)
|
void dgray_setdelays(uint32_t light, uint32_t dark)
|
||||||
{
|
{
|
||||||
delays[0] = light;
|
delays[0] = light;
|
||||||
delays[1] = dark;
|
delays[1] = dark;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* gray_config(): Get the current configuration of the engine */
|
/* dgray_getdelays(): Get the gray engine delays */
|
||||||
int gray_config(uint32_t *light, uint32_t *dark)
|
void dgray_getdelays(uint32_t *light, uint32_t *dark)
|
||||||
{
|
{
|
||||||
if(light) *light = delays[0];
|
if(light) *light = delays[0];
|
||||||
if(dark) *dark = delays[1];
|
if(dark) *dark = delays[1];
|
||||||
|
|
||||||
return runs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* gupdate(): Push the current VRAMs to the screen */
|
/* dgray_getvram(): Get the current VRAM pointers */
|
||||||
void gupdate(void)
|
void dgray_getvram(uint32_t **light, uint32_t **dark)
|
||||||
{
|
|
||||||
st ^= 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* gvram(): Get the current VRAM pointers */
|
|
||||||
void gvram(uint32_t **light, uint32_t **dark)
|
|
||||||
{
|
{
|
||||||
int base = st;
|
int base = st;
|
||||||
|
|
||||||
if(light) *light = vrams[base & 2];
|
if(light) *light = vrams[base & 2];
|
||||||
if(dark) *dark = vrams[base | 1];
|
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];
|
|
||||||
}
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
void gclear(color_t color)
|
void gclear(color_t color)
|
||||||
{
|
{
|
||||||
uint32_t *light, *dark;
|
uint32_t *light, *dark;
|
||||||
gvram(&light, &dark);
|
dgray_getvram(&light, &dark);
|
||||||
|
|
||||||
uint32_t l = -(color == C_LIGHT || color == C_BLACK);
|
uint32_t l = -(color == C_LIGHT || color == C_BLACK);
|
||||||
uint32_t d = -(color == C_DARK || color == C_BLACK);
|
uint32_t d = -(color == C_DARK || color == C_BLACK);
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
#include <gint/gray.h>
|
|
||||||
|
|
||||||
/* ghline(): Full-width horizontal line */
|
|
||||||
void ghline(int y, color_t color)
|
|
||||||
{
|
|
||||||
gline(0, y, 127, y, color);
|
|
||||||
}
|
|
16
src/gray/gint_gline.c
Normal file
16
src/gray/gint_gline.c
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#include <gint/display.h>
|
||||||
|
#include <gint/defs/util.h>
|
||||||
|
|
||||||
|
/* gint_ghline(): Optimized horizontal line, but not actually optimized */
|
||||||
|
void gint_ghline(int x1, int x2, int y, int color)
|
||||||
|
{
|
||||||
|
if(x1 > x2) swap(x1, x2);
|
||||||
|
for(int x = x1; x <= x2; x++) dpixel(x, y, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* gint_gvline(): Optimized horizontal line, but not actually optimized */
|
||||||
|
void gint_gvline(int y1, int y2, int x, int color)
|
||||||
|
{
|
||||||
|
if(y1 > y2) swap(y1, y2);
|
||||||
|
for(int y = y1; y <= y2; y++) dpixel(x, y, color);
|
||||||
|
}
|
|
@ -1,55 +0,0 @@
|
||||||
#include <gint/gray.h>
|
|
||||||
#include <gint/defs/util.h>
|
|
||||||
#include <display/common.h>
|
|
||||||
|
|
||||||
/* gline(): Bresenham line drawing algorithm
|
|
||||||
Remotely adapted from MonochromeLib code by Pierre "PerriotLL" Le Gall.
|
|
||||||
Relies on grect() for optimized situations.
|
|
||||||
@x1 @y1 @x2 @y2 Coordinates of endpoints of line (included)
|
|
||||||
@color Any color */
|
|
||||||
void gline(int x1, int y1, int x2, int y2, color_t color)
|
|
||||||
{
|
|
||||||
/* Trivial optimizations */
|
|
||||||
if(x1 == x2 || y1 == y2)
|
|
||||||
{
|
|
||||||
grect(x1, y1, x2, y2, 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);
|
|
||||||
|
|
||||||
gpixel(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;
|
|
||||||
gpixel(x, y, color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cumul = dy >> 1;
|
|
||||||
for(i = 1; i < dy; i++)
|
|
||||||
{
|
|
||||||
y += sy;
|
|
||||||
cumul += dx;
|
|
||||||
if(cumul > dy) cumul -= dy, x += sx;
|
|
||||||
gpixel(x, y, color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
gpixel(x2, y2, color);
|
|
||||||
}
|
|
|
@ -4,10 +4,8 @@
|
||||||
/* gpixel(): Change a pixel's color */
|
/* gpixel(): Change a pixel's color */
|
||||||
void gpixel(int x, int y, color_t color)
|
void gpixel(int x, int y, color_t color)
|
||||||
{
|
{
|
||||||
if((uint)x >= 128 || (uint)y >= 64) return;
|
|
||||||
|
|
||||||
uint32_t *light, *dark;
|
uint32_t *light, *dark;
|
||||||
gvram(&light, &dark);
|
dgray_getvram(&light, &dark);
|
||||||
|
|
||||||
int offset = (y << 2) + (x >> 5);
|
int offset = (y << 2) + (x >> 5);
|
||||||
uint32_t mask = 1 << (~x & 31), tmp;
|
uint32_t mask = 1 << (~x & 31), tmp;
|
||||||
|
|
|
@ -5,22 +5,12 @@
|
||||||
/* grect(): Fill a rectangle on the screen */
|
/* grect(): Fill a rectangle on the screen */
|
||||||
void grect(int x1, int y1, int x2, int y2, color_t color)
|
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! */
|
/* Use masks to get the work done fast! */
|
||||||
uint32_t m[4];
|
uint32_t m[4];
|
||||||
masks(x1, x2, m);
|
masks(x1, x2, m);
|
||||||
|
|
||||||
uint32_t *light, *dark;
|
uint32_t *light, *dark;
|
||||||
gvram(&light, &dark);
|
dgray_getvram(&light, &dark);
|
||||||
|
|
||||||
light += (y1 << 2);
|
light += (y1 << 2);
|
||||||
dark += (y1 << 2);
|
dark += (y1 << 2);
|
||||||
|
|
|
@ -10,22 +10,12 @@ static void *bopti_asm[] = {
|
||||||
bopti_gasm_gray_alpha,
|
bopti_gasm_gray_alpha,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* gimage(): Render a full image */
|
|
||||||
void gimage(int x, int y, bopti_image_t const *img)
|
|
||||||
{
|
|
||||||
uint32_t *light, *dark;
|
|
||||||
gvram(&light, &dark);
|
|
||||||
|
|
||||||
bopti_render_clip(x, y, img, 0, 0, img->width, img->height, light,
|
|
||||||
dark, bopti_asm[img->profile]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* gsubimage(): Render a section of an image */
|
/* gsubimage(): Render a section of an image */
|
||||||
void gsubimage(int x, int y, bopti_image_t const *img, int left, int top,
|
void gsubimage(int x, int y, bopti_image_t const *img, int left, int top,
|
||||||
int width, int height, int flags)
|
int width, int height, int flags)
|
||||||
{
|
{
|
||||||
uint32_t *light, *dark;
|
uint32_t *light, *dark;
|
||||||
gvram(&light, &dark);
|
dgray_getvram(&light, &dark);
|
||||||
|
|
||||||
if(flags & DIMAGE_NOCLIP)
|
if(flags & DIMAGE_NOCLIP)
|
||||||
{
|
{
|
|
@ -2,13 +2,23 @@
|
||||||
#include <display/common.h>
|
#include <display/common.h>
|
||||||
#include "../render-fx/topti-asm.h"
|
#include "../render-fx/topti-asm.h"
|
||||||
|
|
||||||
/* gtext(): Display a string of text */
|
/* gtext_opt(): Display a string of text */
|
||||||
void gtext(int x, int y, const char *str, int fg, int bg)
|
void gtext_opt(int x, int y, int fg, int bg, int halign, int valign,
|
||||||
|
char const *str)
|
||||||
{
|
{
|
||||||
if((uint)fg >= 8 || (uint)bg >= 8) return;
|
|
||||||
|
|
||||||
uint32_t *light, *dark;
|
uint32_t *light, *dark;
|
||||||
gvram(&light, &dark);
|
dgray_getvram(&light, &dark);
|
||||||
|
|
||||||
|
if(halign != DTEXT_LEFT || valign != DTEXT_TOP)
|
||||||
|
{
|
||||||
|
int w, h;
|
||||||
|
dsize(str, topti_font, &w, &h);
|
||||||
|
|
||||||
|
if(halign == DTEXT_RIGHT) x -= w;
|
||||||
|
if(halign == DTEXT_CENTER) x -= ((w+1) >> 1);
|
||||||
|
if(valign == DTEXT_BOTTOM) y -= h;
|
||||||
|
if(valign == DTEXT_MIDDLE) y -= ((h+1) >> 1);
|
||||||
|
}
|
||||||
|
|
||||||
topti_render(x, y, str, topti_font, topti_asm_text[fg],
|
topti_render(x, y, str, topti_font, topti_asm_text[fg],
|
||||||
topti_asm_text[bg], light, dark);
|
topti_asm_text[bg], light, dark);
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
#include <gint/gray.h>
|
|
||||||
|
|
||||||
/* gvline(): Full-height vertical line */
|
|
||||||
void gvline(int x, color_t color)
|
|
||||||
{
|
|
||||||
gline(x, 0, x, 63, color);
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
#include <gint/display.h>
|
|
||||||
|
|
||||||
/* dhline(): Full-width horizontal line */
|
|
||||||
void dhline(int y, color_t color)
|
|
||||||
{
|
|
||||||
dline(0, y, 395, y, color);
|
|
||||||
}
|
|
|
@ -1,10 +1,10 @@
|
||||||
#include <gint/display.h>
|
#include <gint/display.h>
|
||||||
|
|
||||||
/* dpixel() - change a pixel's color */
|
/* dpixel() - change a pixel's color */
|
||||||
void dpixel(int x, int y, uint16_t color)
|
void dpixel(int x, int y, int color)
|
||||||
{
|
{
|
||||||
/* Coordinate checks */
|
/* Coordinate checks */
|
||||||
if((uint)x >= 396 || (uint)y >= 224) return;
|
if((uint)x >= 396 || (uint)y >= 224 || color == C_NONE) return;
|
||||||
|
|
||||||
gint_vram[396 * y + x] = color;
|
gint_vram[396 * y + x] = color;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,10 @@
|
||||||
#include <gint/display.h>
|
#include <gint/display.h>
|
||||||
|
|
||||||
/* drect() - fill a rectangle of the screen */
|
/* drect() - fill a rectangle of the screen */
|
||||||
void drect(int x1, int y1, int x2, int y2, uint16_t color)
|
void drect(int x1, int y1, int x2, int y2, int color)
|
||||||
{
|
{
|
||||||
|
if(color == C_NONE) return;
|
||||||
|
|
||||||
if(x1 > x2) swap(x1, x2);
|
if(x1 > x2) swap(x1, x2);
|
||||||
if(y1 > y2) swap(y1, y2);
|
if(y1 > y2) swap(y1, y2);
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,7 @@
|
||||||
#include <gint/display.h>
|
#include <gint/display.h>
|
||||||
#include "bopti-asm.h"
|
#include "bopti-asm.h"
|
||||||
|
|
||||||
/* dimage() - render a full image */
|
/* dsubimage(): Render a section of an image */
|
||||||
void dimage(int x, int y, bopti_image_t const *img)
|
|
||||||
{
|
|
||||||
bopti_render_clip(x, y, img, 0, 0, img->width, img->height);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* dsubimage() - render a section of an image */
|
|
||||||
void dsubimage(int x, int y, bopti_image_t const *img, int left, int top,
|
void dsubimage(int x, int y, bopti_image_t const *img, int left, int top,
|
||||||
int width, int height, int flags)
|
int width, int height, int flags)
|
||||||
{
|
{
|
|
@ -11,9 +11,3 @@ void dupdate(void)
|
||||||
overwriting the data which is about to be sent. */
|
overwriting the data which is about to be sent. */
|
||||||
dvram_switch();
|
dvram_switch();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* dupdate_noint() - Push VRAM to the display without interrupts */
|
|
||||||
void dupdate_noint(void)
|
|
||||||
{
|
|
||||||
r61524_display(gint_vram, 0, 224, R61524_DMA_WAIT);
|
|
||||||
}
|
|
||||||
|
|
|
@ -133,9 +133,3 @@ void dtext_opt(int x, int y, int fg, int bg, int halign, int valign,
|
||||||
|
|
||||||
topti_render(x, y, str, strlen(str), topti_font, fg, bg);
|
topti_render(x, y, str, strlen(str), topti_font, fg, bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* dtext(): Simple version of dtext_opt() with defaults */
|
|
||||||
void dtext(int x, int y, int fg, char const *str)
|
|
||||||
{
|
|
||||||
dtext_opt(x, y, fg, C_NONE, DTEXT_LEFT, DTEXT_TOP, str);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
#include <gint/display.h>
|
#include <gint/display.h>
|
||||||
|
#include <display/fx.h>
|
||||||
|
|
||||||
/* dclear() - fill the screen with a single color */
|
/* dclear() - fill the screen with a single color */
|
||||||
void dclear(color_t color)
|
void dclear(color_t color)
|
||||||
{
|
{
|
||||||
|
DMODE_OVERRIDE(dclear, color);
|
||||||
|
|
||||||
/* SuperH only supports a single write-move addressing mode, which is
|
/* SuperH only supports a single write-move addressing mode, which is
|
||||||
pre-decrement write; the other similar mode is post-increment
|
pre-decrement write; the other similar mode is post-increment
|
||||||
read. So we'll use pre-decrement writes to improve performance. */
|
read. So we'll use pre-decrement writes to improve performance. */
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
#include <gint/display.h>
|
#include <gint/display.h>
|
||||||
#include <gint/defs/types.h>
|
#include <gint/defs/types.h>
|
||||||
|
#include <display/fx.h>
|
||||||
|
|
||||||
/* dpixel() - change a pixel's color */
|
/* dpixel() - change a pixel's color */
|
||||||
void dpixel(int x, int y, color_t color)
|
void dpixel(int x, int y, int color)
|
||||||
{
|
{
|
||||||
/* Sanity checks */
|
/* Sanity checks */
|
||||||
if((uint)x >= 128 || (uint)y >= 64) return;
|
if((uint)x >= 128 || (uint)y >= 64) return;
|
||||||
|
|
||||||
|
DMODE_OVERRIDE(dpixel, x, y, color);
|
||||||
|
|
||||||
uint32_t *lword = gint_vram + (y << 2) + (x >> 5);
|
uint32_t *lword = gint_vram + (y << 2) + (x >> 5);
|
||||||
uint32_t mask = 1 << (~x & 31);
|
uint32_t mask = 1 << (~x & 31);
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
#include <display/fx.h>
|
#include <display/fx.h>
|
||||||
|
|
||||||
/* drect() - fill a rectangle of the screen */
|
/* drect() - fill a rectangle of the screen */
|
||||||
void drect(int x1, int y1, int x2, int y2, color_t color)
|
void drect(int x1, int y1, int x2, int y2, int color)
|
||||||
{
|
{
|
||||||
if(x1 > x2) swap(x1, x2);
|
if(x1 > x2) swap(x1, x2);
|
||||||
if(y1 > y2) swap(y1, y2);
|
if(y1 > y2) swap(y1, y2);
|
||||||
|
@ -15,6 +15,8 @@ void drect(int x1, int y1, int x2, int y2, color_t color)
|
||||||
if(y1 < 0) y1 = 0;
|
if(y1 < 0) y1 = 0;
|
||||||
if(y2 >= 64) y2 = 63;
|
if(y2 >= 64) y2 = 63;
|
||||||
|
|
||||||
|
DMODE_OVERRIDE(drect, x1, y1, x2, y2, color);
|
||||||
|
|
||||||
/* Use masks to get the work done fast! */
|
/* Use masks to get the work done fast! */
|
||||||
uint32_t m[4];
|
uint32_t m[4];
|
||||||
masks(x1, x2, m);
|
masks(x1, x2, m);
|
||||||
|
|
|
@ -8,18 +8,12 @@ static void *bopti_asm[] = {
|
||||||
bopti_asm_mono_alpha,
|
bopti_asm_mono_alpha,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* dimage() - render a full image */
|
/* dsubimage(): Render a section of an image */
|
||||||
void dimage(int x, int y, bopti_image_t const *img)
|
|
||||||
{
|
|
||||||
if(img->gray) return;
|
|
||||||
bopti_render_clip(x, y, img, 0, 0, img->width, img->height, gint_vram,
|
|
||||||
NULL, bopti_asm[img->profile]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* dsubimage() - render a section of an image */
|
|
||||||
void dsubimage(int x, int y, bopti_image_t const *img, int left, int top,
|
void dsubimage(int x, int y, bopti_image_t const *img, int left, int top,
|
||||||
int width, int height, int flags)
|
int width, int height, int flags)
|
||||||
{
|
{
|
||||||
|
DMODE_OVERRIDE(dsubimage, x, y, img, left, top, width, height, flags);
|
||||||
|
|
||||||
if(img->gray) return;
|
if(img->gray) return;
|
||||||
|
|
||||||
if(flags & DIMAGE_NOCLIP)
|
if(flags & DIMAGE_NOCLIP)
|
|
@ -1,30 +0,0 @@
|
||||||
#include <gint/display.h>
|
|
||||||
#include <display/common.h>
|
|
||||||
#include "topti-asm.h"
|
|
||||||
|
|
||||||
/* dtext_opt(): Display a string of text */
|
|
||||||
void dtext_opt(int x, int y, int fg, int bg, int halign, int valign,
|
|
||||||
char const *str)
|
|
||||||
{
|
|
||||||
if((uint)fg >= 8 || (uint)bg >= 8) return;
|
|
||||||
|
|
||||||
if(halign != DTEXT_LEFT || valign != DTEXT_TOP)
|
|
||||||
{
|
|
||||||
int w, h;
|
|
||||||
dsize(str, topti_font, &w, &h);
|
|
||||||
|
|
||||||
if(halign == DTEXT_RIGHT) x -= w;
|
|
||||||
if(halign == DTEXT_CENTER) x -= ((w+1) >> 1);
|
|
||||||
if(valign == DTEXT_BOTTOM) y -= h;
|
|
||||||
if(valign == DTEXT_MIDDLE) y -= ((h+1) >> 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
topti_render(x, y, str, topti_font, topti_asm_text[fg],
|
|
||||||
topti_asm_text[bg], gint_vram, gint_vram);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* dtext(): Simple version of dtext_opt() with defaults */
|
|
||||||
void dtext(int x, int y, int fg, char const *str)
|
|
||||||
{
|
|
||||||
dtext_opt(x, y, fg, C_NONE, DTEXT_LEFT, DTEXT_TOP, str);
|
|
||||||
}
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include <gint/display.h>
|
#include <gint/display.h>
|
||||||
#include <gint/drivers/t6k11.h>
|
#include <gint/drivers/t6k11.h>
|
||||||
|
#include <display/fx.h>
|
||||||
|
|
||||||
/* Standard video RAM for fx9860g is 1 bit per pixel */
|
/* Standard video RAM for fx9860g is 1 bit per pixel */
|
||||||
GSECTION(".bss") static uint32_t fx_vram[256];
|
GSECTION(".bss") static uint32_t fx_vram[256];
|
||||||
|
@ -7,14 +8,19 @@ GSECTION(".bss") static uint32_t fx_vram[256];
|
||||||
/* Here is the definition of the VRAM pointer, exposed in <gint/display.h> */
|
/* Here is the definition of the VRAM pointer, exposed in <gint/display.h> */
|
||||||
uint32_t *gint_vram = fx_vram;
|
uint32_t *gint_vram = fx_vram;
|
||||||
|
|
||||||
|
/* The current rendering mode */
|
||||||
|
struct rendering_mode const *dmode = NULL;
|
||||||
|
|
||||||
/* dupdate() - push the video RAM to the display driver */
|
/* dupdate() - push the video RAM to the display driver */
|
||||||
void dupdate(void)
|
void dupdate(void)
|
||||||
{
|
{
|
||||||
|
if(dmode && dmode->dupdate)
|
||||||
|
{
|
||||||
|
/* Call the overridden dupdate(), but continue if itreturns
|
||||||
|
non-zero (this is used when stopping the gray engine) */
|
||||||
|
int rc = dmode->dupdate();
|
||||||
|
if(rc == 0) return;
|
||||||
|
}
|
||||||
|
|
||||||
t6k11_display(gint_vram, 0, 64, 16);
|
t6k11_display(gint_vram, 0, 64, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* dupdate_noint() - Push VRAM to the display without interrupts */
|
|
||||||
void dupdate_noint(void)
|
|
||||||
{
|
|
||||||
dupdate();
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
#include <gint/display.h>
|
|
||||||
|
|
||||||
/* dvline(): Full-height vertical line */
|
|
||||||
void dvline(int x, color_t color)
|
|
||||||
{
|
|
||||||
dline(x, 0, x, 63, color);
|
|
||||||
}
|
|
|
@ -3,7 +3,7 @@
|
||||||
#include <display/fx.h>
|
#include <display/fx.h>
|
||||||
|
|
||||||
/* gint_dhline(): Optimized horizontal line using a rectangle mask */
|
/* gint_dhline(): Optimized horizontal line using a rectangle mask */
|
||||||
void gint_dhline(int x1, int x2, int y, color_t color)
|
void gint_dhline(int x1, int x2, int y, int color)
|
||||||
{
|
{
|
||||||
if((uint)y >= 64) return;
|
if((uint)y >= 64) return;
|
||||||
if(x1 > x2) swap(x1, x2);
|
if(x1 > x2) swap(x1, x2);
|
||||||
|
@ -39,7 +39,7 @@ void gint_dhline(int x1, int x2, int y, color_t color)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* gint_dvline(): Optimized vertical line */
|
/* gint_dvline(): Optimized vertical line */
|
||||||
void gint_dvline(int y1, int y2, int x, color_t color)
|
void gint_dvline(int y1, int y2, int x, int color)
|
||||||
{
|
{
|
||||||
if((uint)x >= 128) return;
|
if((uint)x >= 128) return;
|
||||||
if(y1 > y2) swap(y1, y2);
|
if(y1 > y2) swap(y1, y2);
|
|
@ -2,6 +2,7 @@
|
||||||
#include <gint/defs/attributes.h>
|
#include <gint/defs/attributes.h>
|
||||||
#include <gint/display.h>
|
#include <gint/display.h>
|
||||||
#include <display/common.h>
|
#include <display/common.h>
|
||||||
|
#include <display/fx.h>
|
||||||
#include "topti-asm.h"
|
#include "topti-asm.h"
|
||||||
|
|
||||||
/* Default font */
|
/* Default font */
|
||||||
|
@ -173,3 +174,26 @@ 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_opt(): Display a string of text */
|
||||||
|
void dtext_opt(int x, int y, int fg, int bg, int halign, int valign,
|
||||||
|
char const *str)
|
||||||
|
{
|
||||||
|
if((uint)fg >= 8 || (uint)bg >= 8) return;
|
||||||
|
|
||||||
|
DMODE_OVERRIDE(dtext_opt, x, y, fg, bg, halign, valign, str);
|
||||||
|
|
||||||
|
if(halign != DTEXT_LEFT || valign != DTEXT_TOP)
|
||||||
|
{
|
||||||
|
int w, h;
|
||||||
|
dsize(str, topti_font, &w, &h);
|
||||||
|
|
||||||
|
if(halign == DTEXT_RIGHT) x -= w;
|
||||||
|
if(halign == DTEXT_CENTER) x -= ((w+1) >> 1);
|
||||||
|
if(valign == DTEXT_BOTTOM) y -= h;
|
||||||
|
if(valign == DTEXT_MIDDLE) y -= ((h+1) >> 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
topti_render(x, y, str, topti_font, topti_asm_text[fg],
|
||||||
|
topti_asm_text[bg], gint_vram, gint_vram);
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include <gint/display.h>
|
#include <gint/display.h>
|
||||||
|
|
||||||
/* dhline(): Full-width horizontal line */
|
/* dhline(): Full-width horizontal line */
|
||||||
void dhline(int y, color_t color)
|
void dhline(int y, int color)
|
||||||
{
|
{
|
||||||
dline(0, y, 127, y, color);
|
dline(0, y, DWIDTH - 1, y, color);
|
||||||
}
|
}
|
7
src/render/dimage.c
Normal file
7
src/render/dimage.c
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#include <gint/display.h>
|
||||||
|
|
||||||
|
/* dimage(): Render a full image */
|
||||||
|
void dimage(int x, int y, bopti_image_t const *img)
|
||||||
|
{
|
||||||
|
dsubimage(x, y, img, 0, 0, img->width, img->height, DIMAGE_NONE);
|
||||||
|
}
|
|
@ -2,21 +2,35 @@
|
||||||
#include <gint/defs/util.h>
|
#include <gint/defs/util.h>
|
||||||
#include <display/common.h>
|
#include <display/common.h>
|
||||||
|
|
||||||
|
#ifdef FX9860G
|
||||||
|
#include <display/fx.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
/* dline(): Bresenham line drawing algorithm
|
/* dline(): Bresenham line drawing algorithm
|
||||||
Remotely adapted from MonochromeLib code by Pierre "PerriotLL" Le Gall.
|
Remotely adapted from MonochromeLib code by Pierre "PerriotLL" Le Gall.
|
||||||
Relies on platform-dependent dhline() and dvline() for optimized situations.
|
Relies on platform-dependent dhline() and dvline() for optimized situations.
|
||||||
@x1 @y1 @x2 @y2 Coordinates of endpoints of line (included)
|
@x1 @y1 @x2 @y2 Coordinates of endpoints of line (included)
|
||||||
@color Any color accepted by dpixel() on the platform */
|
@color Any color accepted by dpixel() on the platform */
|
||||||
void dline(int x1, int y1, int x2, int y2, color_t color)
|
void dline(int x1, int y1, int x2, int y2, int color)
|
||||||
{
|
{
|
||||||
|
if(color == C_NONE) return;
|
||||||
|
|
||||||
/* Possible optimizations */
|
/* Possible optimizations */
|
||||||
if(y1 == y2)
|
if(y1 == y2)
|
||||||
{
|
{
|
||||||
|
#ifdef FX9860G
|
||||||
|
DMODE_OVERRIDE(gint_dhline, x1, x2, y1, color);
|
||||||
|
#endif
|
||||||
|
|
||||||
gint_dhline(x1, x2, y1, color);
|
gint_dhline(x1, x2, y1, color);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(x1 == x2)
|
if(x1 == x2)
|
||||||
{
|
{
|
||||||
|
#ifdef FX9860G
|
||||||
|
DMODE_OVERRIDE(gint_dvline, y1, y2, x1, color);
|
||||||
|
#endif
|
||||||
|
|
||||||
gint_dvline(y1, y2, x1, color);
|
gint_dvline(y1, y2, x1, color);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
7
src/render/dtext.c
Normal file
7
src/render/dtext.c
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#include <gint/display.h>
|
||||||
|
|
||||||
|
/* dtext(): Simple version of dtext_opt() with defaults */
|
||||||
|
void dtext(int x, int y, int fg, char const *str)
|
||||||
|
{
|
||||||
|
dtext_opt(x, y, fg, C_NONE, DTEXT_LEFT, DTEXT_TOP, str);
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#include <gint/display.h>
|
#include <gint/display.h>
|
||||||
|
|
||||||
/* dvline(): Full-height vertical line */
|
/* dvline(): Full-height vertical line */
|
||||||
void dvline(int x, color_t color)
|
void dvline(int x, int color)
|
||||||
{
|
{
|
||||||
dline(x, 0, x, 223, color);
|
dline(x, 0, x, DHEIGHT - 1, color);
|
||||||
}
|
}
|
Loading…
Reference in a new issue