From 4df3d69d8cdb49edc508af8f36dafc14bdf66947 Mon Sep 17 00:00:00 2001 From: Lephe Date: Wed, 16 Nov 2022 18:00:12 +0100 Subject: [PATCH] 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... --- CMakeLists.txt | 1 + include/gint/display.h | 27 ++++++++++++++-- include/gint/image.h | 16 +++++---- src/image/image_sub.c | 4 ++- src/render-cg/dclear.c | 15 +++++++-- src/render-cg/dpixel.c | 9 +++--- src/render-cg/drect.c | 25 +++++++------- src/render-cg/dvram.c | 2 +- src/render-cg/gint_dline.c | 22 ++++++------- src/render-cg/image/image.c | 36 ++++++++++++++------- src/render-cg/image/image_p4.c | 8 ++--- src/render-cg/image/image_p4_clearbg_alt.c | 4 +-- src/render-cg/image/image_p4_dye.c | 4 +-- src/render-cg/image/image_p4_swapcolor.c | 8 ++--- src/render-cg/image/image_p8.c | 8 ++--- src/render-cg/image/image_p8_dye.c | 4 +-- src/render-cg/image/image_p8_swapcolor.c | 8 ++--- src/render-cg/image/image_rgb16.c | 8 ++--- src/render-cg/image/image_rgb16_dye.c | 4 +-- src/render-cg/image/image_rgb16_swapcolor.c | 8 ++--- src/render-cg/topti.c | 27 +++++++++++----- src/render-fx/bopti.c | 24 ++++++++++---- src/render-fx/dclear.c | 11 +++++-- src/render-fx/dgetpixel.c | 3 +- src/render-fx/dpixel.c | 4 +-- src/render-fx/drect.c | 15 +++++---- src/render-fx/gint_dline.c | 12 +++---- src/render-fx/masks.c | 12 +++---- src/render-fx/topti.c | 29 ++++++++++++++--- src/render/dhline.c | 2 +- src/render/drect_border.c | 3 +- src/render/dvline.c | 2 +- src/render/dwindow.c | 21 ++++++++++++ 33 files changed, 253 insertions(+), 133 deletions(-) create mode 100644 src/render/dwindow.c diff --git a/CMakeLists.txt b/CMakeLists.txt index e83f1c5..8b91ef0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/include/gint/display.h b/include/gint/display.h index d5bb39e..9f5a93b 100644 --- a/include/gint/display.h +++ b/include/gint/display.h @@ -27,8 +27,6 @@ extern "C" { #include #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 //--- diff --git a/include/gint/image.h b/include/gint/image.h index 23d8df1..a27cec2 100644 --- a/include/gint/image.h +++ b/include/gint/image.h @@ -41,6 +41,8 @@ extern "C" { #include #include +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 diff --git a/src/image/image_sub.c b/src/image/image_sub.c index 0cf4cb4..ccc4c33 100644 --- a/src/image/image_sub.c +++ b/src/image/image_sub.c @@ -1,4 +1,5 @@ #include +#include #include #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; } diff --git a/src/render-cg/dclear.c b/src/render-cg/dclear.c index 3f8fabd..4373bb7 100644 --- a/src/render-cg/dclear.c +++ b/src/render-cg/dclear.c @@ -1,9 +1,18 @@ #include #include -/* 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); + } } diff --git a/src/render-cg/dpixel.c b/src/render-cg/dpixel.c index ca34af8..44e8d56 100644 --- a/src/render-cg/dpixel.c +++ b/src/render-cg/dpixel.c @@ -1,11 +1,12 @@ #include -/* 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; diff --git a/src/render-cg/drect.c b/src/render-cg/drect.c index 6782fcb..24bdba7 100644 --- a/src/render-cg/drect.c +++ b/src/render-cg/drect.c @@ -1,7 +1,6 @@ #include #include -/* 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; } } diff --git a/src/render-cg/dvram.c b/src/render-cg/dvram.c index 46a2c91..96c7c18 100644 --- a/src/render-cg/dvram.c +++ b/src/render-cg/dvram.c @@ -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) diff --git a/src/render-cg/gint_dline.c b/src/render-cg/gint_dline.c index 51002a1..5b27559 100644 --- a/src/render-cg/gint_dline.c +++ b/src/render-cg/gint_dline.c @@ -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; } diff --git a/src/render-cg/image/image.c b/src/render-cg/image/image.c index 994e0e1..a70e923 100644 --- a/src/render-cg/image/image.c +++ b/src/render-cg/image/image.c @@ -1,8 +1,9 @@ #include #include +#include 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; diff --git a/src/render-cg/image/image_p4.c b/src/render-cg/image/image_p4.c index d29fe4f..cf87f0a 100644 --- a/src/render-cg/image/image_p4.c +++ b/src/render-cg/image/image_p4.c @@ -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); diff --git a/src/render-cg/image/image_p4_clearbg_alt.c b/src/render-cg/image/image_p4_clearbg_alt.c index 3dec9b8..3d05f99 100644 --- a/src/render-cg/image/image_p4_clearbg_alt.c +++ b/src/render-cg/image/image_p4_clearbg_alt.c @@ -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); diff --git a/src/render-cg/image/image_p4_dye.c b/src/render-cg/image/image_p4_dye.c index d0393a5..7a9e46b 100644 --- a/src/render-cg/image/image_p4_dye.c +++ b/src/render-cg/image/image_p4_dye.c @@ -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; diff --git a/src/render-cg/image/image_p4_swapcolor.c b/src/render-cg/image/image_p4_swapcolor.c index 9010afa..b1a3753 100644 --- a/src/render-cg/image/image_p4_swapcolor.c +++ b/src/render-cg/image/image_p4_swapcolor.c @@ -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; diff --git a/src/render-cg/image/image_p8.c b/src/render-cg/image/image_p8.c index 89c6bc3..f0005e4 100644 --- a/src/render-cg/image/image_p8.c +++ b/src/render-cg/image/image_p8.c @@ -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); diff --git a/src/render-cg/image/image_p8_dye.c b/src/render-cg/image/image_p8_dye.c index 3fc9e68..5047613 100644 --- a/src/render-cg/image/image_p8_dye.c +++ b/src/render-cg/image/image_p8_dye.c @@ -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; diff --git a/src/render-cg/image/image_p8_swapcolor.c b/src/render-cg/image/image_p8_swapcolor.c index fddb7c9..6cc45ad 100644 --- a/src/render-cg/image/image_p8_swapcolor.c +++ b/src/render-cg/image/image_p8_swapcolor.c @@ -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; diff --git a/src/render-cg/image/image_rgb16.c b/src/render-cg/image/image_rgb16.c index 83550f6..32f3784 100644 --- a/src/render-cg/image/image_rgb16.c +++ b/src/render-cg/image/image_rgb16.c @@ -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); diff --git a/src/render-cg/image/image_rgb16_dye.c b/src/render-cg/image/image_rgb16_dye.c index bfc884c..ed70b8a 100644 --- a/src/render-cg/image/image_rgb16_dye.c +++ b/src/render-cg/image/image_rgb16_dye.c @@ -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; diff --git a/src/render-cg/image/image_rgb16_swapcolor.c b/src/render-cg/image/image_rgb16_swapcolor.c index 71e71a5..6843827 100644 --- a/src/render-cg/image/image_rgb16_swapcolor.c +++ b/src/render-cg/image/image_rgb16_swapcolor.c @@ -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; diff --git a/src/render-cg/topti.c b/src/render-cg/topti.c index 87bb873..eedb3b6 100644 --- a/src/render-cg/topti.c +++ b/src/render-cg/topti.c @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -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 */ diff --git a/src/render-fx/bopti.c b/src/render-fx/bopti.c index 8457aa0..460e88c 100644 --- a/src/render-fx/bopti.c +++ b/src/render-fx/bopti.c @@ -1,4 +1,5 @@ #include +#include #include #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; diff --git a/src/render-fx/dclear.c b/src/render-fx/dclear.c index 7d5fcc1..bf68a60 100644 --- a/src/render-fx/dclear.c +++ b/src/render-fx/dclear.c @@ -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; diff --git a/src/render-fx/dgetpixel.c b/src/render-fx/dgetpixel.c index d394db6..0b10c1f 100644 --- a/src/render-fx/dgetpixel.c +++ b/src/render-fx/dgetpixel.c @@ -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); diff --git a/src/render-fx/dpixel.c b/src/render-fx/dpixel.c index 106709f..375d9f9 100644 --- a/src/render-fx/dpixel.c +++ b/src/render-fx/dpixel.c @@ -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); diff --git a/src/render-fx/drect.c b/src/render-fx/drect.c index 0eed920..cc07f7c 100644 --- a/src/render-fx/drect.c +++ b/src/render-fx/drect.c @@ -2,18 +2,19 @@ #include #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); diff --git a/src/render-fx/gint_dline.c b/src/render-fx/gint_dline.c index 148b353..b087ebe 100644 --- a/src/render-fx/gint_dline.c +++ b/src/render-fx/gint_dline.c @@ -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); diff --git a/src/render-fx/masks.c b/src/render-fx/masks.c index ca87e64..864f8c4 100644 --- a/src/render-fx/masks.c +++ b/src/render-fx/masks.c @@ -1,28 +1,24 @@ +#include #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); } diff --git a/src/render-fx/topti.c b/src/render-fx/topti.c index ddbff00..6eb30a0 100644 --- a/src/render-fx/topti.c +++ b/src/render-fx/topti.c @@ -1,5 +1,6 @@ #include #include +#include #include #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); } diff --git a/src/render/dhline.c b/src/render/dhline.c index f01dc65..13fca71 100644 --- a/src/render/dhline.c +++ b/src/render/dhline.c @@ -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); } diff --git a/src/render/drect_border.c b/src/render/drect_border.c index 88adbe4..853784f 100644 --- a/src/render/drect_border.c +++ b/src/render/drect_border.c @@ -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); diff --git a/src/render/dvline.c b/src/render/dvline.c index 55b4da3..1ad30ee 100644 --- a/src/render/dvline.c +++ b/src/render/dvline.c @@ -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); } diff --git a/src/render/dwindow.c b/src/render/dwindow.c new file mode 100644 index 0000000..afe78aa --- /dev/null +++ b/src/render/dwindow.c @@ -0,0 +1,21 @@ +#include +#include + +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; +}