mirror of
https://git.planet-casio.com/Lephenixnoir/gint.git
synced 2024-12-28 04:23: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:
|
||||
* bopti: remove the deprecated image_t definition
|
||||
* project: remove the compat branch
|
||||
* project: remove the gray aliases
|
||||
|
||||
Issues:
|
||||
* #10 support fx-CG 20
|
||||
|
||||
Extensions on existing code:
|
||||
* build: move the private headers to the src/ folder
|
||||
* tmu: make interrupt handlers more elegant
|
||||
* 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
|
||||
* dma: fx9860g support (need to switch it on and update the Makefile)
|
||||
* core: try to leave add-in without reset in case of panic
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#include <gint/defs/types.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
|
||||
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) */
|
||||
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
|
||||
@img Image encoded by [fxconv]
|
||||
@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,
|
||||
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(),
|
||||
eliminating two types of coordinate checks:
|
||||
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,
|
||||
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 */
|
||||
|
|
|
@ -29,12 +29,33 @@
|
|||
//---
|
||||
|
||||
/* dupdate(): Push the video RAM to the display driver
|
||||
This function makes the contents of the VRAM visible on the screen. It is
|
||||
the direct equivalent of Bdisp_PutDisp_DD().
|
||||
|
||||
On fxcg50, if triple buffering is enabled (which is the default and disabled
|
||||
only by calling dvram()), it also swaps buffers. Due to the DMA being used,
|
||||
always waits for the previous call to dupdate() call() to finish. */
|
||||
This function makes the contents of the VRAM visible on the screen. It is
|
||||
the equivalent of Bdisp_PutDisp_DD() in most situations.
|
||||
|
||||
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);
|
||||
|
||||
//---
|
||||
|
@ -42,88 +63,108 @@ void dupdate(void);
|
|||
//---
|
||||
|
||||
/* dclear(): Fill the screen with a single color
|
||||
|
||||
This function clears the screen by painting all the pixels in a single
|
||||
color. It is optimized for opaque colors.
|
||||
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
|
||||
fxcg50: Any R5G6B5 color */
|
||||
On fx9860g, use drect() if you need operators that modify existing pixels
|
||||
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);
|
||||
|
||||
/* drect(): Fill a rectangle of the screen
|
||||
This functions applies a color or an operator to a rectangle defined by two
|
||||
points (x1 y1) and (x2 y2). Both are included in the rectangle.
|
||||
|
||||
@x1 @y1 @x2 @y2 Bounding rectangle (drawn area).
|
||||
@color fx9860g: white, black, none, invert
|
||||
fxcg50: Any R5G6B5 color */
|
||||
void drect(int x1, int y1, int x2, int y2, color_t color);
|
||||
@x1 @y1 Top-left rectangle corner (included)
|
||||
@x2 @y2 Bottom-right rectangle corner (included)
|
||||
@color fx-9860G: white light* dark* black none invert lighten* darken*
|
||||
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
|
||||
This function draws a rectangle with an inner border. The border width must
|
||||
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);
|
||||
be smaller than half the width and half the height.
|
||||
|
||||
@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
|
||||
//---
|
||||
|
||||
/* 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.
|
||||
|
||||
@x @y Coordinates of the pixel to repaint
|
||||
@color fx9860g: white, black, none, invert
|
||||
fxcg50: Any R5G6B5 color */
|
||||
void dpixel(int x, int y, color_t color);
|
||||
@color fx-9860G: white light* dark* black none invert lighten* darken*
|
||||
fx-CG 50: Any R5G6B5 color or C_NONE
|
||||
|
||||
*: When the gray engine is on, see dgray(). */
|
||||
void dpixel(int x, int y, int color);
|
||||
|
||||
/* dline(): Render a straight line
|
||||
|
||||
This function draws a line using a Bresenham-style algorithm. Please note
|
||||
that dline() may not render lines exactly like Bdisp_DrawLineVRAM().
|
||||
|
||||
dline() has optimization facilities for horizontal and vertical lines. The
|
||||
speedup for horizontal lines is about x2 on fxcg50 and probably about x30
|
||||
on fx9860g. Vertical lines have a smaller speedup.
|
||||
dline() has optimizations for horizontal and vertical lines. The speedup for
|
||||
horizontal lines is about x2 on fx-CG 50 and probably about x30 on fx-9860G.
|
||||
Vertical lines have a smaller speedup.
|
||||
|
||||
dline() is currently not able to clip arbitrary lines without calculating
|
||||
all the pixels, so drawing a line from (-1e6,0) to (1e6,395) will work but
|
||||
will be veeery slow.
|
||||
will be very slow.
|
||||
|
||||
@x1 @y1 @x2 @y2 End points of the line (both included).
|
||||
@color fx9860g: white, black, none, invert
|
||||
fxcg50: Any R5G6B5 color */
|
||||
void dline(int x1, int y1, int x2, int y2, color_t color);
|
||||
@x1 @y1 @x2 @y2 Endpoints of the line (both included).
|
||||
@color Line color (same values as dpixel() are allowed) */
|
||||
void dline(int x1, int y1, int x2, int y2, int color);
|
||||
|
||||
/* dhline(): Full-width horizontal line
|
||||
This function draws a horizontal line from the left end of the screen to the
|
||||
right end, much like the Basic command "Horizontal".
|
||||
|
||||
@y Line number
|
||||
@color fx9860g: white, black, none, invert
|
||||
fxcg50: Any R5G6B5 color */
|
||||
void dhline(int y, color_t color);
|
||||
@color Line color (same values as dline() are allowed) */
|
||||
void dhline(int y, int color);
|
||||
|
||||
/* dvline(): Full-height vertical line
|
||||
This function draws a vertical line from the top end of the screen to the
|
||||
bottom end, much like the Basic command "Vertical".
|
||||
|
||||
@x Column number
|
||||
@color fx9860g: white, black, none, invert
|
||||
fxcg50: Any R5G6B5 color */
|
||||
void dvline(int x, color_t color);
|
||||
@color Line color (same values as dline() are allowed) */
|
||||
void dvline(int x, int color);
|
||||
|
||||
//---
|
||||
// Text rendering (topti)
|
||||
//---
|
||||
|
||||
/* font_t - font data encoded for topti */
|
||||
/* font_t: Font data encoded for topti */
|
||||
typedef struct
|
||||
{
|
||||
/* Length of font name (not necessarily NUL-terminated!) */
|
||||
|
@ -172,17 +213,28 @@ typedef struct
|
|||
} GPACKED(4) font_t;
|
||||
|
||||
/* dfont(): Set the default font for text rendering
|
||||
This font will be used by dtext() and sister functions. If [font = NULL],
|
||||
gint's default font is used.
|
||||
|
||||
On fx9860g, the default font is a 5x7 font very close to the system's.
|
||||
On fxcg50, the default font is an original 8x9 font.
|
||||
This function changes the default font for text rendering; this affects
|
||||
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
|
||||
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
|
||||
|
||||
This function computes the size that the given string would take up if
|
||||
rendered with a certain font. If you specify a NULL font, the currently
|
||||
configured font will be used; this is different from dfont(), which uses
|
||||
|
@ -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
|
||||
maximum. Usually this is what you want because vertically-centered strings
|
||||
must have the same baseline regardless of their contents. So the height
|
||||
returned by dsize() is the same for all strings, only depends on the font.
|
||||
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
|
||||
[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
|
||||
@font Font to use; if NULL, defaults to the current font
|
||||
@w @h Set to the width and height of the rendered text, may be NULL */
|
||||
void dsize(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
|
||||
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,
|
||||
see dtext() for a simpler version.
|
||||
|
||||
On fx9860g, due to the particular design of topti, this function performs
|
||||
drastic rendering optimizations using the line structure of the VRAM and is
|
||||
able to render several characters at once.
|
||||
The alignment options specify where (x y) should be relative to the rendered
|
||||
string. The default is halign=DTEXT_LEFT and valign=DTEXT_TOP, which means
|
||||
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()
|
||||
for that.
|
||||
|
||||
@x @y Coordinates of top-left corner of the rendered string
|
||||
@fg Text color
|
||||
fx9860g: white, black, none, invert
|
||||
fxcg50: Any R5G6B6 color, or C_NONE
|
||||
@bg Background color
|
||||
fx9860g: white, black, none, invert
|
||||
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)
|
||||
@x @y Coordinates of the anchor of the rendered string
|
||||
@fg @bg Text color and background color
|
||||
fx-9860G: white light* dark* black none invert lighten* darken*
|
||||
fx-CG 50: Any R5G6B6 color, or C_NONE
|
||||
@halign Where x should be relative to the rendered string
|
||||
@valign Where y should be relative to the rendered string
|
||||
@str String to display */
|
||||
void dtext_opt(int x, int y, int fg, int bg, int halign, int valign,
|
||||
char const *str);
|
||||
|
||||
/* dtext(): Simple version of dtext_opt() with defaults
|
||||
This is exactly dtext_opt() with bg=C_NONE, halign=DTEXT_LEFT and
|
||||
valign=DTEXT_TOP. */
|
||||
Calls dtext_opt() with bg=C_NONE, halign=DTEXT_LEFT and valign=DTEXT_TOP. */
|
||||
void dtext(int x, int y, int fg, char const *str);
|
||||
|
||||
/* 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,
|
||||
char const *format, ...);
|
||||
|
||||
/* 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, ...);
|
||||
|
||||
//---
|
||||
// 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
|
||||
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.
|
||||
|
||||
@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);
|
||||
|
||||
/* Option values for dsubimage() */
|
||||
enum {
|
||||
/* No option */
|
||||
DIMAGE_NONE = 0x00,
|
||||
|
||||
/* Disable clipping, ie. adjustments to the specified subrectangle and
|
||||
screen location such that any part that overflows from the image or
|
||||
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.
|
||||
|
||||
@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]
|
||||
@image Pointer to image encoded with fxconv for bopti
|
||||
@left @top Top-left coordinates of the subrectangle within the image
|
||||
@width @height Subrectangle dimensions
|
||||
@flags OR-combination of DIMAGE_* flags */
|
||||
void dsubimage(int x, int y, bopti_image_t const *image, int left, int top,
|
||||
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 */
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//---
|
||||
// gint:gray - Gray engine and rendering functions
|
||||
// gint:gray - Gray engine control
|
||||
//---
|
||||
|
||||
#ifndef GINT_GRAY
|
||||
|
@ -8,34 +8,71 @@
|
|||
#include <gint/defs/types.h>
|
||||
#include <gint/display.h>
|
||||
|
||||
//---
|
||||
// Engine control
|
||||
//---
|
||||
/* Commands for the gray engine */
|
||||
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
|
||||
dupdate() after this function, only gupdate().
|
||||
This function configures the display module to work with or without the gray
|
||||
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
|
||||
the timer is unavailable, this function will fail. Otherwise, the gray
|
||||
engine is started and any attempt to use timer 0 while it is running will be
|
||||
denied by the timer module. */
|
||||
void gray_start(void);
|
||||
Similarly, when the mode is DGRAY_OFF, all rendering functions are replaced
|
||||
to use monochrome rendering, and the next frame sent with dupdate() will
|
||||
stop the gray engine on the display. To transition back to monochrome
|
||||
rendering, call dgray(DGRAY_OFF), draw your first monochrome frame from
|
||||
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
|
||||
control of the screen and dupdate() is safe to use again.
|
||||
When functions that use the gray engine call functions that don't and vice-
|
||||
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
|
||||
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);
|
||||
This function returns non-zero if the engine has failed to initialize at
|
||||
startup (because it failed to obtain either GRAY_TIMER or some of its VRAM
|
||||
memory). Because changes to the gray engine only apply after a call to
|
||||
dupdate(), you can check if the engine is successfully initialized with:
|
||||
|
||||
/* 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
|
||||
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 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:
|
||||
Here are values from the old fx-9860G-like family, which is every monochrome
|
||||
calculator but the Graph 35+E II:
|
||||
|
||||
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
|
||||
898 1350 none common good
|
||||
1075 1444 low common too close
|
||||
609 884 medium terrible variable
|
||||
937 1333 low common decent
|
||||
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
|
||||
--------------------------------------------------
|
||||
680 1078
|
||||
762 1311 low some too light [default]
|
||||
869 1097 medium some excellent
|
||||
680 1078 low common good
|
||||
762 1311 low some good [default]
|
||||
869 1097 medium some too close
|
||||
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
|
||||
@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
|
||||
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);
|
||||
|
||||
/* 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);
|
||||
@dark Set to the current dark delay setting */
|
||||
void dgray_getdelays(uint32_t *light, uint32_t *dark);
|
||||
|
||||
//---
|
||||
// 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
|
||||
displayed on the screen at the next refresh, while the VRAMs that were
|
||||
previously being displayed are now available for drawing.
|
||||
//---
|
||||
// Aliases for older programs
|
||||
//---
|
||||
|
||||
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);
|
||||
/* Functions for the gray engine used to be called g*() to mirror the d*()
|
||||
functions of the display module. They are now bundled together, so these
|
||||
aliases are for older programs that still use the g*() naming scheme */
|
||||
|
||||
#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.
|
||||
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.
|
||||
#define gupdate dupdate
|
||||
#define gray_delays dgray_setdelays
|
||||
#define gray_config dgray_getdelays
|
||||
#define gvram dgray_getvram
|
||||
|
||||
@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_ALIASES */
|
||||
|
||||
#endif /* GINT_GRAY */
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#include <gint/display.h>
|
||||
#include <gint/timer.h>
|
||||
|
||||
#include <display/fx.h>
|
||||
|
||||
/* Three additional video RAMS, allocated statically if --static-gray was set
|
||||
at configure time, or with malloc() otherwise. */
|
||||
#ifdef GINT_STATIC_GRAY
|
||||
|
@ -17,27 +19,63 @@ GBSS static uint32_t gvrams[3][256];
|
|||
#endif
|
||||
|
||||
/* 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
|
||||
VRAMs 0 and 1) or 2 (draws to VRAMs 2 and 3). */
|
||||
static volatile int st = 0;
|
||||
|
||||
/* Whether the engine is running. Delays of light and dark frames. */
|
||||
static int volatile st = 0;
|
||||
/* Timer ID, always equal to GRAY_TIMER except if initialization fails */
|
||||
static int timer = -1;
|
||||
/* Whether the engine is scheduled to run at the next frame */
|
||||
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];
|
||||
|
||||
/* Underlying timer */
|
||||
#define GRAY_TIMER 0
|
||||
/* The alternate rendering mode structure used to override d*() */
|
||||
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)
|
||||
{
|
||||
/* Here [gint_vram] refers to the standard, monochrome VRAM */
|
||||
/* We need four VRAMs. First use the standard monochrome one */
|
||||
vrams[0] = gint_vram;
|
||||
|
||||
#ifdef GINT_STATIC_GRAY
|
||||
|
@ -61,16 +99,74 @@ GCONSTRUCTOR static void gray_init(void)
|
|||
delays[0] = 923;
|
||||
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)
|
||||
{
|
||||
#ifndef GINT_STATIC_GRAY
|
||||
free(vrams[1]);
|
||||
free(vrams[2]);
|
||||
free(vrams[3]);
|
||||
if(vrams[1]) free(vrams[1]);
|
||||
if(vrams[2]) free(vrams[2]);
|
||||
if(vrams[3]) free(vrams[3]);
|
||||
|
||||
vrams[1] = NULL;
|
||||
vrams[2] = NULL;
|
||||
vrams[3] = NULL;
|
||||
#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 */
|
||||
|
@ -83,69 +179,57 @@ int gray_int(void)
|
|||
return TIMER_CONTINUE;
|
||||
}
|
||||
|
||||
/* gray_start(): Start the gray engine */
|
||||
void gray_start(void)
|
||||
/* gupdate(): Push the current VRAMs to the screen */
|
||||
int gupdate(void)
|
||||
{
|
||||
#ifndef GINT_STATIC_GRAY
|
||||
if(!vrams[1] || !vrams[2] || !vrams[3]) return;
|
||||
#endif
|
||||
/* At the first gupdate(), start the engine */
|
||||
if(dmode == &gray_mode && !runs)
|
||||
{
|
||||
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;
|
||||
|
||||
int timer = timer_setup(GRAY_TIMER|TIMER_Pphi_64, delays[0], gray_int);
|
||||
if(timer != GRAY_TIMER) return;
|
||||
|
||||
timer_start(GRAY_TIMER);
|
||||
st = 0;
|
||||
runs = 1;
|
||||
/* When the engine is running, swap frames */
|
||||
st ^= 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
runs = 0;
|
||||
return (dmode == &gray_mode);
|
||||
}
|
||||
|
||||
/* gray_delays(): Set the gray engine delays */
|
||||
void gray_delays(uint32_t light, uint32_t dark)
|
||||
/* dgray_setdelays(): Set the gray engine delays */
|
||||
void dgray_setdelays(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)
|
||||
/* dgray_getdelays(): Get the gray engine delays */
|
||||
void dgray_getdelays(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)
|
||||
/* dgray_getvram(): Get the current VRAM pointers */
|
||||
void dgray_getvram(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];
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
void gclear(color_t color)
|
||||
{
|
||||
uint32_t *light, *dark;
|
||||
gvram(&light, &dark);
|
||||
dgray_getvram(&light, &dark);
|
||||
|
||||
uint32_t l = -(color == C_LIGHT || 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 */
|
||||
void gpixel(int x, int y, color_t color)
|
||||
{
|
||||
if((uint)x >= 128 || (uint)y >= 64) return;
|
||||
|
||||
uint32_t *light, *dark;
|
||||
gvram(&light, &dark);
|
||||
dgray_getvram(&light, &dark);
|
||||
|
||||
int offset = (y << 2) + (x >> 5);
|
||||
uint32_t mask = 1 << (~x & 31), tmp;
|
||||
|
|
|
@ -5,22 +5,12 @@
|
|||
/* 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);
|
||||
dgray_getvram(&light, &dark);
|
||||
|
||||
light += (y1 << 2);
|
||||
dark += (y1 << 2);
|
||||
|
|
|
@ -10,22 +10,12 @@ static void *bopti_asm[] = {
|
|||
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 */
|
||||
void gsubimage(int x, int y, bopti_image_t const *img, int left, int top,
|
||||
int width, int height, int flags)
|
||||
{
|
||||
uint32_t *light, *dark;
|
||||
gvram(&light, &dark);
|
||||
dgray_getvram(&light, &dark);
|
||||
|
||||
if(flags & DIMAGE_NOCLIP)
|
||||
{
|
|
@ -2,13 +2,23 @@
|
|||
#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)
|
||||
/* gtext_opt(): Display a string of text */
|
||||
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;
|
||||
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_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>
|
||||
|
||||
/* 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 */
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -2,8 +2,10 @@
|
|||
#include <gint/display.h>
|
||||
|
||||
/* 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(y1 > y2) swap(y1, y2);
|
||||
|
||||
|
|
|
@ -1,13 +1,7 @@
|
|||
#include <gint/display.h>
|
||||
#include "bopti-asm.h"
|
||||
|
||||
/* dimage() - render a full 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 */
|
||||
/* dsubimage(): Render a section of an image */
|
||||
void dsubimage(int x, int y, bopti_image_t const *img, int left, int top,
|
||||
int width, int height, int flags)
|
||||
{
|
|
@ -11,9 +11,3 @@ void dupdate(void)
|
|||
overwriting the data which is about to be sent. */
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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 <display/fx.h>
|
||||
|
||||
/* dclear() - fill the screen with a single color */
|
||||
void dclear(color_t color)
|
||||
{
|
||||
DMODE_OVERRIDE(dclear, color);
|
||||
|
||||
/* SuperH only supports a single write-move addressing mode, which is
|
||||
pre-decrement write; the other similar mode is post-increment
|
||||
read. So we'll use pre-decrement writes to improve performance. */
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
#include <gint/display.h>
|
||||
#include <gint/defs/types.h>
|
||||
#include <display/fx.h>
|
||||
|
||||
/* 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 */
|
||||
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 mask = 1 << (~x & 31);
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include <display/fx.h>
|
||||
|
||||
/* 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(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(y2 >= 64) y2 = 63;
|
||||
|
||||
DMODE_OVERRIDE(drect, x1, y1, x2, y2, color);
|
||||
|
||||
/* Use masks to get the work done fast! */
|
||||
uint32_t m[4];
|
||||
masks(x1, x2, m);
|
||||
|
|
|
@ -8,18 +8,12 @@ static void *bopti_asm[] = {
|
|||
bopti_asm_mono_alpha,
|
||||
};
|
||||
|
||||
/* dimage() - render a full 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 */
|
||||
/* dsubimage(): Render a section of an image */
|
||||
void dsubimage(int x, int y, bopti_image_t const *img, int left, int top,
|
||||
int width, int height, int flags)
|
||||
{
|
||||
DMODE_OVERRIDE(dsubimage, x, y, img, left, top, width, height, flags);
|
||||
|
||||
if(img->gray) return;
|
||||
|
||||
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/drivers/t6k11.h>
|
||||
#include <display/fx.h>
|
||||
|
||||
/* Standard video RAM for fx9860g is 1 bit per pixel */
|
||||
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> */
|
||||
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 */
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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>
|
||||
|
||||
/* 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(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 */
|
||||
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(y1 > y2) swap(y1, y2);
|
|
@ -2,6 +2,7 @@
|
|||
#include <gint/defs/attributes.h>
|
||||
#include <gint/display.h>
|
||||
#include <display/common.h>
|
||||
#include <display/fx.h>
|
||||
#include "topti-asm.h"
|
||||
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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>
|
||||
|
||||
/* 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 <display/common.h>
|
||||
|
||||
#ifdef FX9860G
|
||||
#include <display/fx.h>
|
||||
#endif
|
||||
|
||||
/* dline(): Bresenham line drawing algorithm
|
||||
Remotely adapted from MonochromeLib code by Pierre "PerriotLL" Le Gall.
|
||||
Relies on platform-dependent dhline() and dvline() for optimized situations.
|
||||
@x1 @y1 @x2 @y2 Coordinates of endpoints of line (included)
|
||||
@color Any 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 */
|
||||
if(y1 == y2)
|
||||
{
|
||||
#ifdef FX9860G
|
||||
DMODE_OVERRIDE(gint_dhline, x1, x2, y1, color);
|
||||
#endif
|
||||
|
||||
gint_dhline(x1, x2, y1, color);
|
||||
return;
|
||||
}
|
||||
if(x1 == x2)
|
||||
{
|
||||
#ifdef FX9860G
|
||||
DMODE_OVERRIDE(gint_dvline, y1, y2, x1, color);
|
||||
#endif
|
||||
|
||||
gint_dvline(y1, y2, x1, color);
|
||||
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>
|
||||
|
||||
/* 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