render: add a window setting to restrict rendering

Mono text rendering is a bad hack and probably not that fast, but meh.
We can optimize it the day it becomes a bottleneck, if ever...
This commit is contained in:
Lephe 2022-11-16 18:00:12 +01:00
parent 74438f5da5
commit 4df3d69d8c
Signed by untrusted user: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
33 changed files with 253 additions and 133 deletions

View File

@ -109,6 +109,7 @@ set(SOURCES_COMMON
src/render/dtext.c
src/render/dupdate_hook.c
src/render/dvline.c
src/render/dwindow.c
src/render/topti.c
# RTC driver
src/rtc/rtc.c

View File

@ -27,8 +27,6 @@ extern "C" {
#include <gint/display-cg.h>
#endif
/* TODO: dinfo() or similar */
//---
// Video RAM management
//---
@ -82,6 +80,31 @@ void dupdate_set_hook(gint_call_t function);
/* dupdate_get_hook(): Get a copy of the dupdate() hook */
gint_call_t dupdate_get_hook(void);
//---
// Rendering mode control
//---
/* dmode: Rendering mode settings
This structure indicates the current window settings. Rendering is limited
to the rectangle spanning from (left,top) included, to (right,bottom)
excluded. The default is from (0,0) to (DWIDTH,DHEIGHT). */
struct dwindow {
int left, top;
int right, bottom;
};
extern struct dwindow dwindow;
/* dwindow_set(): Set the rendering window
This function changes [dwindow] settings to limit rendering to a sub-surface
of the VRAM. Note that this doesn't change the coordinate system; the pixel
at (DWIDTH/2, DHEIGHT/2) is always in the middle of the screen regardless of
the window setting. However, it might be masked out by the window.
Returns the old dwindow settings (if it needs to be restored later). */
struct dwindow dwindow_set(struct dwindow new_mode);
//---
// Area rendering functions
//---

View File

@ -41,6 +41,8 @@ extern "C" {
#include <gint/defs/attributes.h>
#include <gint/defs/types.h>
struct dwindow;
//---
// Image structures
//---
@ -653,13 +655,14 @@ struct gint_image_box
};
/* Clip the provided box against the input. If, after clipping, the box no
longer intersects the output (whose size is specified as out_w/out_h),
returns false. Otherwise, returns true. */
longer intersects the output window, returns false. Otherwise, returns
true. */
bool gint_image_clip_input(image_t const *img, struct gint_image_box *box,
int out_w, int out_h);
struct dwindow const *window);
/* Clip the provided box against the output. */
void gint_image_clip_output(struct gint_image_box *b, int out_w, int out_h);
void gint_image_clip_output(struct gint_image_box *b,
struct dwindow const *window);
//---
// Internal image rendering routines
@ -745,15 +748,14 @@ struct gint_image_cmd
@left_edge Whether to force 2-alignment on the input (box->left)
@right_edge Whether to force 2-alignment on the width
@cmd Command to be filled
@out_width Output width (usually DWIDTH)
@out_height Output height (usually DHEIGHT)
@window Rendering window (usually {0, 0, DWIDTH, DHEIGHT})
Returns false if there is nothing to render because of clipping (in which
case [cmd] is unchanged), true otherwise. [*box] is also updated to reflect
the final box after clipping but not accounting for edges. */
bool gint_image_mkcmd(struct gint_image_box *box, image_t const *img,
int effects, bool left_edge, bool right_edge,
struct gint_image_cmd *cmd, int out_width, int out_height);
struct gint_image_cmd *cmd, struct dwindow const *window);
/* Entry point of the renderers. These functions can be called normally as long
as you can build the commands (eg. by using gint_image_mkcmd() then filling

View File

@ -1,4 +1,5 @@
#include <gint/image.h>
#include <gint/display.h>
#include <string.h>
#undef image_sub
@ -15,8 +16,9 @@ image_t *image_sub(image_t const *src, int left, int top, int w, int h,
h = src->height - top;
struct gint_image_box box = { 0, 0, w, h, left, top };
struct dwindow in_window = { 0, 0, w, h };
if(!image_valid(src) || IMAGE_IS_P4(src->format) ||
!gint_image_clip_input(src, &box, w, h)) {
!gint_image_clip_input(src, &box, &in_window)) {
memset(dst, 0, sizeof *dst);
return dst;
}

View File

@ -1,9 +1,18 @@
#include <gint/display.h>
#include <gint/dma.h>
/* dclear() - fill the screen with a single color */
void dclear(uint16_t color)
{
dma_memset(gint_vram, (color << 16) | color, 396 * 224 * 2);
return;
bool full_width = (dwindow.left == 0 && dwindow.right == DWIDTH);
bool dma_aligned = !(dwindow.top & 3) && !(dwindow.bottom & 3);
if(full_width && dma_aligned) {
uint16_t *vram = gint_vram + DWIDTH * dwindow.top;
int size_bytes = DWIDTH * (dwindow.bottom - dwindow.top) * 2;
dma_memset(vram, (color << 16) | color, size_bytes);
}
else {
drect(dwindow.left, dwindow.top, dwindow.right - 1,
dwindow.bottom - 1, color);
}
}

View File

@ -1,11 +1,12 @@
#include <gint/display.h>
/* dpixel() - change a pixel's color */
void dpixel(int x, int y, int color)
{
/* Coordinate checks */
if((uint)x >= 396 || (uint)y >= 224 || color == C_NONE) return;
int index = 396 * y + x;
if(x < dwindow.left || x >= dwindow.right) return;
if(y < dwindow.top || y >= dwindow.bottom) return;
if(color == C_NONE) return;
int index = DWIDTH * y + x;
if(color == C_INVERT) gint_vram[index] ^= 0xffff;
else gint_vram[index] = color;

View File

@ -1,7 +1,6 @@
#include <gint/defs/util.h>
#include <gint/display.h>
/* drect() - fill a rectangle of the screen */
void drect(int x1, int y1, int x2, int y2, int color)
{
if(color == C_NONE) return;
@ -9,17 +8,19 @@ void drect(int x1, int y1, int x2, int y2, int color)
if(x1 > x2) swap(x1, x2);
if(y1 > y2) swap(y1, y2);
/* Order and bounds */
if(x1 >= 396 || x2 < 0 || y1 >= 224 || y2 < 0) return;
if(x1 < 0) x1 = 0;
if(x2 >= 396) x2 = 395;
if(y1 < 0) y1 = 0;
if(y2 >= 224) y2 = 223;
/* Rectangle is completely outside the rendering window */
if(x1 >= dwindow.right || x2 < dwindow.left) return;
if(y1 >= dwindow.bottom || y2 < dwindow.top) return;
/* Clipping */
x1 = max(x1, dwindow.left);
x2 = min(x2, dwindow.right - 1);
y1 = max(y1, dwindow.top);
y2 = min(y2, dwindow.bottom - 1);
/* The method is exactly like dhline(). I first handle odd endpoints,
then write longwords for the longest section */
uint16_t *base = gint_vram + 396 * y1;
uint16_t *base = gint_vram + DWIDTH * y1;
int height = y2 - y1 + 1;
/* Now copy everything that's left as longwords */
@ -37,15 +38,15 @@ void drect(int x1, int y1, int x2, int y2, int color)
if(x1 & 1) base[x1] ^= 0xffff;
if(!(x2 & 1)) base[x2] ^= 0xffff;
for(int w = 0; w < width; w++) v[w] ^= 0xffffffff;
v += 198;
base += 396;
v += DWIDTH / 2;
base += DWIDTH;
}
else for(int h = height; h; h--)
{
base[x1] = color;
base[x2] = color;
for(int w = 0; w < width; w++) v[w] = op;
v += 198;
base += 396;
v += DWIDTH / 2;
base += DWIDTH;
}
}

View File

@ -11,7 +11,7 @@ bool dvram_init(void)
int const MARGIN = 32;
/* Leave MARGIN bytes on each side of the region; this enables some
important optimisations in the image renderer. We also add another
important optimizations in the image renderer. We also add another
32 bytes so we can manually 32-align the region */
uint32_t region = (uint32_t)malloc(DWIDTH*DHEIGHT*2 + MARGIN*2 + 32);
if(region == 0)

View File

@ -4,14 +4,13 @@
/* gint_dhline(): Optimized horizontal line */
void gint_dhline(int x1, int x2, int y, uint16_t color)
{
/* Order and bounds */
if((uint)y >= 224) return;
if(y < dwindow.top || y >= dwindow.bottom) return;
if(x1 > x2) swap(x1, x2);
if(x1 >= 396 || x2 < 0) return;
if(x1 < 0) x1 = 0;
if(x2 >= 396) x2 = 395;
if(x1 >= dwindow.right || x2 < dwindow.left) return;
x1 = max(x1, dwindow.left);
x2 = min(x2, dwindow.right - 1);
int offset = 396 * y;
int offset = DWIDTH * y;
/* Use longwords to do the copy, but first paint the endpoints to heed
for odd x1 and x2. Checking the parity may be a waste of time. */
@ -33,15 +32,14 @@ void gint_dhline(int x1, int x2, int y, uint16_t color)
/* gint_dvline(): Optimized vertical line */
void gint_dvline(int y1, int y2, int x, uint16_t color)
{
/* Order and bounds */
if((uint)x >= 396) return;
if(x < dwindow.left || x >= dwindow.right) return;
if(y1 > y2) swap(y1, y2);
if(y1 < 0) y1 = 0;
if(y2 >= 224) y2 = 223;
y1 = max(y1, dwindow.top);
y2 = min(y2, dwindow.bottom - 1);
uint16_t *v = gint_vram + 396 * y1 + x;
uint16_t *v = gint_vram + DWIDTH * y1 + x;
int height = y2 - y1 + 1;
while(height-- > 0) *v = color, v += 396;
while(height-- > 0) *v = color, v += DWIDTH;
}

View File

@ -1,8 +1,9 @@
#include <gint/image.h>
#include <gint/display.h>
#include <gint/defs/util.h>
bool gint_image_clip_input(image_t const *img, struct gint_image_box *b,
int out_w, int out_h)
struct dwindow const *window)
{
/* Adjust the bounding box of the input image */
if(b->left < 0) b->w += b->left, b->x -= b->left, b->left = 0;
@ -13,37 +14,50 @@ bool gint_image_clip_input(image_t const *img, struct gint_image_box *b,
/* Check whether the box intersects the screen */
if(b->w <= 0 || b->h <= 0)
return false;
if(b->x + b->w <= 0 || b->x >= out_w)
if(b->x + b->w <= window->left || b->x >= window->right)
return false;
if(b->y + b->h <= 0 || b->y >= out_h)
if(b->y + b->h <= window->top || b->y >= window->bottom)
return false;
return true;
}
void gint_image_clip_output(struct gint_image_box *b, int out_w, int out_h)
void gint_image_clip_output(struct gint_image_box *b,
struct dwindow const *window)
{
/* Intersect with the bounding box on-screen */
if(b->y < 0) b->top -= b->y, b->h += b->y, b->y = 0;
if(b->y + b->h > out_h) b->h = (out_h - b->y);
if(b->x < 0) b->left -= b->x, b->w += b->x, b->x = 0;
if(b->x + b->w > out_w) b->w = (out_w - b->x);
if(b->y < window->top) {
int d = window->top - b->y; /* > 0 */
b->top += d;
b->h -= d;
b->y += d;
}
b->h = min(b->h, window->bottom - b->y);
if(b->x < window->left) {
int d = window->left - b->x; /* > 0 */
b->left += d;
b->w -= d;
b->x += d;
}
b->w = min(b->w, window->right - b->x);
}
bool gint_image_mkcmd(struct gint_image_box *box, image_t const *img,
int effects, bool left_edge, bool right_edge,
struct gint_image_cmd *cmd, int out_width, int out_height)
struct gint_image_cmd *cmd, struct dwindow const *window)
{
/* Convert the old DIMAGE_NOCLIP flag */
if(effects & DIMAGE_NOCLIP)
effects |= IMAGE_NOCLIP;
if(!(effects & IMAGE_NOCLIP_INPUT)) {
if(!gint_image_clip_input(img, box, out_width, out_height))
if(!gint_image_clip_input(img, box, window))
return false;
}
if(!(effects & IMAGE_NOCLIP_OUTPUT))
gint_image_clip_output(box, out_width, out_height);
gint_image_clip_output(box, window);
cmd->effect = (effects & (IMAGE_VFLIP | IMAGE_HFLIP)) >> 8;
cmd->columns = box->w;

View File

@ -16,8 +16,8 @@ void dsubimage_p4(int x, int y, image_t const *img,
struct gint_image_box box = { x, y, w, h, left, top };
struct gint_image_cmd cmd;
if(!gint_image_mkcmd(&box, img, eff, false, false, &cmd, DWIDTH,
DHEIGHT)) return;
if(!gint_image_mkcmd(&box, img, eff, false, false, &cmd, &dwindow))
return;
cmd.loop = gint_image_p4_normal;
gint_image_p4_loop(DWIDTH, &cmd);
}
@ -33,8 +33,8 @@ void dsubimage_p4_clearbg(int x, int y, image_t const *img,
struct gint_image_box box = { x, y, w, h, left, top };
struct gint_image_cmd cmd;
if(!gint_image_mkcmd(&box, img, eff, false, false, &cmd, DWIDTH,
DHEIGHT)) return;
if(!gint_image_mkcmd(&box, img, eff, false, false, &cmd, &dwindow))
return;
cmd.color_1 = bg_color;
cmd.loop = gint_image_p4_clearbg;
gint_image_p4_loop(DWIDTH, &cmd);

View File

@ -13,8 +13,8 @@ void dsubimage_p4_clearbg_alt(int x, int y, image_t const *img,
struct gint_image_box box = { x, y, w, h, left, top };
struct gint_image_cmd cmd;
if(!gint_image_mkcmd(&box, img, eff, true, true, &cmd, DWIDTH,
DHEIGHT)) return;
if(!gint_image_mkcmd(&box, img, eff, true, true, &cmd, &dwindow))
return;
cmd.color_1 = bg_color;
cmd.loop = gint_image_p4_clearbg_alt;
gint_image_p4_loop(DWIDTH, &cmd);

View File

@ -13,8 +13,8 @@ void dsubimage_p4_dye(int x, int y, image_t const *img,
struct gint_image_box box = { x, y, w, h, left, top };
struct gint_image_cmd cmd;
if(!gint_image_mkcmd(&box, img, eff, true, true, &cmd, DWIDTH,
DHEIGHT)) return;
if(!gint_image_mkcmd(&box, img, eff, true, true, &cmd, &dwindow))
return;
cmd.color_1 = image_alpha(img->format);
cmd.color_2 = dye_color;
cmd.loop = gint_image_p4_dye;

View File

@ -14,8 +14,8 @@ void dsubimage_p4_swapcolor(int x, int y, image_t const *img,
struct gint_image_box box = { x, y, w, h, left, top };
struct gint_image_cmd cmd;
if(!gint_image_mkcmd(&box, img, eff, true, true, &cmd, DWIDTH,
DHEIGHT)) return;
if(!gint_image_mkcmd(&box, img, eff, true, true, &cmd, &dwindow))
return;
cmd.color_1 = old_index;
cmd.color_2 = new_color;
cmd.loop = gint_image_p4_swapcolor;
@ -35,8 +35,8 @@ void dsubimage_p4_addbg(int x, int y, image_t const *img,
struct gint_image_box box = { x, y, w, h, left, top };
struct gint_image_cmd cmd;
if(!gint_image_mkcmd(&box, img, eff, true, true, &cmd, DWIDTH,
DHEIGHT)) return;
if(!gint_image_mkcmd(&box, img, eff, true, true, &cmd, &dwindow))
return;
cmd.color_1 = image_alpha(img->format);
cmd.color_2 = bg_color;
cmd.loop = gint_image_p4_swapcolor;

View File

@ -16,8 +16,8 @@ void dsubimage_p8(int x, int y, image_t const *img,
struct gint_image_box box = { x, y, w, h, left, top };
struct gint_image_cmd cmd;
if(!gint_image_mkcmd(&box, img, eff, false, false, &cmd, DWIDTH,
DHEIGHT)) return;
if(!gint_image_mkcmd(&box, img, eff, false, false, &cmd, &dwindow))
return;
cmd.loop = gint_image_p8_normal;
gint_image_p8_loop(DWIDTH, &cmd);
}
@ -33,8 +33,8 @@ void dsubimage_p8_clearbg(int x, int y, image_t const *img,
struct gint_image_box box = { x, y, w, h, left, top };
struct gint_image_cmd cmd;
if(!gint_image_mkcmd(&box, img, eff, false, true, &cmd, DWIDTH,
DHEIGHT)) return;
if(!gint_image_mkcmd(&box, img, eff, false, true, &cmd, &dwindow))
return;
cmd.color_1 = bg_color;
cmd.loop = gint_image_p8_clearbg;
gint_image_p8_loop(DWIDTH, &cmd);

View File

@ -13,8 +13,8 @@ void dsubimage_p8_dye(int x, int y, image_t const *img,
struct gint_image_box box = { x, y, w, h, left, top };
struct gint_image_cmd cmd;
if(!gint_image_mkcmd(&box, img, eff, false, true, &cmd, DWIDTH,
DHEIGHT)) return;
if(!gint_image_mkcmd(&box, img, eff, false, true, &cmd, &dwindow))
return;
cmd.color_1 = image_alpha(img->format);
cmd.color_2 = dye_color;
cmd.loop = gint_image_p8_dye;

View File

@ -14,8 +14,8 @@ void dsubimage_p8_swapcolor(int x, int y, image_t const *img,
struct gint_image_box box = { x, y, w, h, left, top };
struct gint_image_cmd cmd;
if(!gint_image_mkcmd(&box, img, eff, false, false, &cmd, DWIDTH,
DHEIGHT)) return;
if(!gint_image_mkcmd(&box, img, eff, false, false, &cmd, &dwindow))
return;
cmd.color_1 = old_index;
cmd.color_2 = new_color;
cmd.loop = gint_image_p8_swapcolor;
@ -35,8 +35,8 @@ void dsubimage_p8_addbg(int x, int y, image_t const *img,
struct gint_image_box box = { x, y, w, h, left, top };
struct gint_image_cmd cmd;
if(!gint_image_mkcmd(&box, img, eff, false, false, &cmd, DWIDTH,
DHEIGHT)) return;
if(!gint_image_mkcmd(&box, img, eff, false, false, &cmd, &dwindow))
return;
cmd.color_1 = image_alpha(img->format);
cmd.color_2 = bg_color;
cmd.loop = gint_image_p8_swapcolor;

View File

@ -16,8 +16,8 @@ void dsubimage_rgb16(int x, int y, image_t const *img,
struct gint_image_box box = { x, y, w, h, left, top };
struct gint_image_cmd cmd;
if(!gint_image_mkcmd(&box, img, eff, false, false, &cmd, DWIDTH,
DHEIGHT)) return;
if(!gint_image_mkcmd(&box, img, eff, false, false, &cmd, &dwindow))
return;
cmd.loop = gint_image_rgb16_normal;
gint_image_rgb16_loop(DWIDTH, &cmd);
}
@ -34,8 +34,8 @@ void dsubimage_rgb16_clearbg(int x, int y, image_t const *img,
struct gint_image_box box = { x, y, w, h, left, top };
struct gint_image_cmd cmd;
if(!gint_image_mkcmd(&box, img, eff, false, false, &cmd, DWIDTH,
DHEIGHT)) return;
if(!gint_image_mkcmd(&box, img, eff, false, false, &cmd, &dwindow))
return;
cmd.color_1 = bg_color;
cmd.loop = gint_image_rgb16_clearbg;
gint_image_rgb16_loop(DWIDTH, &cmd);

View File

@ -13,8 +13,8 @@ void dsubimage_rgb16_dye(int x, int y, image_t const *img,
struct gint_image_box box = { x, y, w, h, left, top };
struct gint_image_cmd cmd;
if(!gint_image_mkcmd(&box, img, eff, false, false, &cmd, DWIDTH,
DHEIGHT)) return;
if(!gint_image_mkcmd(&box, img, eff, false, false, &cmd, &dwindow))
return;
cmd.color_1 = image_alpha(img->format);
cmd.color_2 = dye_color;
cmd.loop = gint_image_rgb16_dye;

View File

@ -14,8 +14,8 @@ void dsubimage_rgb16_swapcolor(int x, int y, image_t const *img,
struct gint_image_box box = { x, y, w, h, left, top };
struct gint_image_cmd cmd;
if(!gint_image_mkcmd(&box, img, eff, false, false, &cmd, DWIDTH,
DHEIGHT)) return;
if(!gint_image_mkcmd(&box, img, eff, false, false, &cmd, &dwindow))
return;
cmd.color_1 = old_color;
cmd.color_2 = new_color;
cmd.loop = gint_image_rgb16_swapcolor;
@ -35,8 +35,8 @@ void dsubimage_rgb16_addbg(int x, int y, image_t const *img,
struct gint_image_box box = { x, y, w, h, left, top };
struct gint_image_cmd cmd;
if(!gint_image_mkcmd(&box, img, eff, false, false, &cmd, DWIDTH,
DHEIGHT)) return;
if(!gint_image_mkcmd(&box, img, eff, false, false, &cmd, &dwindow))
return;
cmd.color_1 = image_alpha(img->format);
cmd.color_2 = bg_color;
cmd.loop = gint_image_rgb16_swapcolor;

View File

@ -1,5 +1,6 @@
#include <gint/defs/types.h>
#include <gint/defs/attributes.h>
#include <gint/defs/util.h>
#include <gint/display.h>
#include <string.h>
@ -56,12 +57,19 @@ static void topti_render(int x, int y, char const *str_char, font_t const *f,
int height = f->data_height, top = 0;
/* Vertical clipping */
if(x > 395 || y > 223 || y + height <= 0) return;
if(y + height > 224) height = 224 - y;
if(y < 0) top = -y, height += y, y = 0;
if(x >= dwindow.right || y >= dwindow.bottom) return;
if(y + height <= dwindow.top) return;
height = min(height, dwindow.bottom - y);
int top_overflow = y - dwindow.top;
if(top_overflow < 0) {
top = -top_overflow;
height += top_overflow;
y -= top_overflow;
}
/* Move to top row */
uint16_t *target = gint_vram + 396 * y;
uint16_t *target = gint_vram + DWIDTH * y;
/* Character spacing waiting to be drawn, in pixels */
int space = 0;
@ -80,7 +88,7 @@ static void topti_render(int x, int y, char const *str_char, font_t const *f,
/* Draw character spacing if background is opaque */
if(space && bg >= 0) drect(x, y, x+space-1, y+height-1, bg);
x += space;
if(x >= 396) break;
if(x >= dwindow.right) break;
int index = topti_offset(f, glyph);
@ -88,14 +96,17 @@ static void topti_render(int x, int y, char const *str_char, font_t const *f,
int width = dataw, left = 0;
if(x + dataw <= 0)
if(x + dataw <= dwindow.left)
{
x += dataw;
space = f->char_spacing;
continue;
}
if(x < 0) left = -x, width += x;
if(x + width > 396) width = 396 - x;
if(x < dwindow.left) {
left = dwindow.left - x;
width -= left;
}
width = min(width, dwindow.right - x);
/* Render glyph */

View File

@ -1,4 +1,5 @@
#include <gint/defs/types.h>
#include <gint/defs/util.h>
#include <gint/display.h>
#include "render-fx.h"
#include "bopti-asm.h"
@ -271,18 +272,29 @@ int bopti_clip(bopti_image_t const *img, struct rbox *r)
int x = r->visual_x, y = r->y;
int left = r->left, top = r->top;
int width = r->width, height = r->height;
int diff;
/* Adjust the bounding box of the input image */
if(left < 0) width += left, x -= left, left = 0;
if(top < 0) height += top, y -= top, top = 0;
if(left + width > img->width) width = img->width - left;
if(top + height > img->height) height = img->height - top;
width = min(width, img->width - left);
height = min(height, img->height - top);
/* Intersect with the bounding box on-screen */
if(x < 0) width += x, left -= x, x = 0;
if(y < 0) height += y, top -= y, y = 0;
if(x + width > DWIDTH) width = DWIDTH - x;
if(y + height > DHEIGHT) height = DHEIGHT - y;
if((diff = dwindow.left - x) > 0)
{
width -= diff;
left += diff;
x += diff;
}
if((diff = dwindow.top - y) > 0)
{
height -= diff;
top += diff;
y += diff;
}
width = min(width, dwindow.right - x);
height = min(height, dwindow.bottom - y);
r->visual_x = x;
r->y = y;

View File

@ -4,6 +4,12 @@
/* dclear() - fill the screen with a single color */
void dclear(color_t color)
{
if(dwindow.left != 0 || dwindow.right != DWIDTH) {
drect(dwindow.left, dwindow.top, dwindow.right - 1,
dwindow.bottom - 1, color);
return;
}
DMODE_OVERRIDE(dclear, color);
/* SuperH only supports a single write-move addressing mode, which is
@ -13,9 +19,10 @@ void dclear(color_t color)
if(color != C_WHITE && color != C_BLACK) return;
uint32_t fill = -(color >> 1);
uint32_t *index = gint_vram + 256;
uint32_t *start = gint_vram + 4 * dwindow.top;
uint32_t *index = gint_vram + 4 * dwindow.bottom;
while(index > gint_vram)
while(index > start)
{
/* Do it by batches to avoid losing cycles on loop tests */
*--index = fill;

View File

@ -4,7 +4,8 @@
int dgetpixel(int x, int y)
{
if((uint)x >= DWIDTH || (uint)y >= DHEIGHT) return -1;
if(x < dwindow.left || x >= dwindow.right) return -1;
if(y < dwindow.top || y >= dwindow.bottom) return -1;
DMODE_OVERRIDE(dgetpixel, x, y);

View File

@ -5,8 +5,8 @@
/* dpixel() - change a pixel's color */
void dpixel(int x, int y, int color)
{
/* Sanity checks */
if((uint)x >= 128 || (uint)y >= 64) return;
if(x < dwindow.left || x >= dwindow.right) return;
if(y < dwindow.top || y >= dwindow.bottom) return;
DMODE_OVERRIDE(dpixel, x, y, color);

View File

@ -2,18 +2,19 @@
#include <gint/display.h>
#include "render-fx.h"
/* drect() - fill a rectangle of the screen */
void drect(int x1, int y1, int x2, int y2, int 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;
/* Rectangle is completely outside the rendering window */
if(x1 >= dwindow.right || x2 < dwindow.left) return;
if(y1 >= dwindow.bottom || y2 < dwindow.top) return;
/* Clipping */
x1 = max(x1, dwindow.left);
x2 = min(x2, dwindow.right - 1);
y1 = max(y1, dwindow.top);
y2 = min(y2, dwindow.bottom - 1);
DMODE_OVERRIDE(drect, x1, y1, x2, y2, color);

View File

@ -5,9 +5,9 @@
/* gint_dhline(): Optimized horizontal line using a rectangle mask */
void gint_dhline(int x1, int x2, int y, int color)
{
if((uint)y >= 64) return;
if(y < dwindow.top || y >= dwindow.bottom) return;
if(x1 > x2) swap(x1, x2);
if(x1 >= 128 || x2 < 0) return;
if(x1 >= dwindow.right || x2 < dwindow.left) return;
/* Get the masks for the [x1, x2] range */
uint32_t m[4];
@ -41,11 +41,11 @@ void gint_dhline(int x1, int x2, int y, int color)
/* gint_dvline(): Optimized vertical line */
void gint_dvline(int y1, int y2, int x, int color)
{
if((uint)x >= 128) return;
if(x < dwindow.left || x >= dwindow.right) return;
if(y1 > y2) swap(y1, y2);
if(y1 >= 64 || y2 < 0) return;
if(y1 < 0) y1 = 0;
if(y2 >= 64) y2 = 63;
if(y1 >= dwindow.bottom || y2 < dwindow.top) return;
y1 = max(y1, dwindow.top);
y2 = min(y2, dwindow.bottom - 1);
uint32_t *base = gint_vram + (y1 << 2) + (x >> 5);
uint32_t *lword = base + ((y2 - y1 + 1) << 2);

View File

@ -1,28 +1,24 @@
#include <gint/defs/util.h>
#include "render-fx.h"
/* masks() - compute the vram masks for a given rectangle */
void masks(int x1, int x2, uint32_t *masks)
{
if(x1 < 0) x1 = 0;
if(x2 >= 128) x2 = 127;
x1 = max(x1, dwindow.left);
x2 = min(x2, dwindow.right - 1);
/* Indexes of the first and last non-empty longs */
size_t l1 = x1 >> 5;
size_t l2 = x2 >> 5;
size_t i = 0;
/* Base masks (0's are final, 0xffffffff will be adjusted later) */
while(i < l1) masks[i++] = 0x00000000;
while(i <= l2) masks[i++] = 0xffffffff;
while(i < 4) masks[i++] = 0x00000000;
/* Remove the index information in x1 and x2 (it's now in l1 and l2)
and keep only the offsets */
/* Remove the index information in x1 and x2; keep only the offsets */
x1 &= 31;
/* For x2 we also want the complement to 31 to invert the shift */
x2 = ~x2 & 31;
/* Now roll! */
masks[l1] &= (0xffffffffu >> x1);
masks[l2] &= (0xffffffffu << x2);
}

View File

@ -1,5 +1,6 @@
#include <gint/defs/types.h>
#include <gint/defs/attributes.h>
#include <gint/defs/util.h>
#include <gint/display.h>
#include "../render/render.h"
@ -97,12 +98,20 @@ void topti_render(int x, int y, char const *str_char, font_t const *f,
uint32_t const *data = f->data;
/* Basic clipping */
if(x > 127 || y > 63 || y + height <= 0) return;
if(y + height > 64) height = 64 - y;
if(x >= dwindow.right || y >= dwindow.bottom) return;
if(y + height <= dwindow.top) return;
height = min(height, dwindow.bottom - y);
/* How much we need to skip vertically if we render text at y < 0 */
/* How much we skip vertically if we render at y < dwindow.top */
int vdisp = 0;
if(y < 0) vdisp = -y, y = 0;
if(y < dwindow.top)
{
vdisp = dwindow.top - y;
y = dwindow.top;
}
uint32_t bg_mask[4];
masks(dwindow.left, dwindow.right, bg_mask);
/* Operator data and background */
uint32_t operators[height];
@ -146,6 +155,12 @@ void topti_render(int x, int y, char const *str_char, font_t const *f,
if(x >= 0)
{
for(int i = 0; i < height; i++)
{
operators[i] &= bg_mask[x];
bg[i] &= bg_mask[x];
}
asm_bg(v1, v2, bg + vdisp, height - vdisp);
asm_fg(v1, v2, operators + vdisp, height - vdisp);
}
@ -171,7 +186,11 @@ void topti_render(int x, int y, char const *str_char, font_t const *f,
/* Put the final longwords */
if(x >= 0 && x < 4 && free < 32)
{
for(int i = 0; i < height; i++) bg[i] &= ~((1 << free) - 1);
for(int i = 0; i < height; i++)
{
operators[i] &= bg_mask[x];
bg[i] &= bg_mask[x] & ~((1 << free) - 1);
}
asm_bg(v1, v2, bg + vdisp, height - vdisp);
asm_fg(v1, v2, operators + vdisp, height - vdisp);
}

View File

@ -3,5 +3,5 @@
/* dhline(): Full-width horizontal line */
void dhline(int y, int color)
{
dline(0, y, DWIDTH - 1, y, color);
dline(dwindow.left, y, dwindow.right - 1, y, color);
}

View File

@ -8,7 +8,8 @@ void drect_border(int x1, int y1, int x2, int y2, int fill, int width,
if(x1 > x2) swap(x1, x2);
if(y1 > y2) swap(y1, y2);
if(x1 >= DWIDTH || x2 < 0 || y1 >= DHEIGHT || y2 < 0) return;
if(x1 >= dwindow.right || x2 < dwindow.left) return;
if(y1 >= dwindow.bottom || y2 < dwindow.top) return;
drect(x1, y1, x2, y1 + (width-1), border);
drect(x1, y2 - (width-1), x2, y2, border);

View File

@ -3,5 +3,5 @@
/* dvline(): Full-height vertical line */
void dvline(int x, int color)
{
dline(x, 0, x, DHEIGHT - 1, color);
dline(x, dwindow.top, x, dwindow.bottom - 1, color);
}

21
src/render/dwindow.c Normal file
View File

@ -0,0 +1,21 @@
#include <gint/display.h>
#include <gint/defs/util.h>
struct dwindow dwindow = {
.left = 0,
.top = 0,
.right = DWIDTH,
.bottom = DHEIGHT,
};
struct dwindow dwindow_set(struct dwindow m)
{
m.left = max(m.left, 0);
m.top = max(m.top, 0);
m.right = max(m.left, min(m.right, DWIDTH));
m.bottom = max(m.top, min(m.bottom, DHEIGHT));
struct dwindow old_mode = dwindow;
dwindow = m;
return old_mode;
}