diff --git a/src/conio/bitmap_con.c b/src/conio/bitmap_con.c index bc574a888d3435b9ddc7234d82471c557aff140d..4d868851f9adf97f0cd40007c382ee6b2ca80e25 100644 --- a/src/conio/bitmap_con.c +++ b/src/conio/bitmap_con.c @@ -102,6 +102,7 @@ static int force_cursor=0; static struct rectlist *free_rects; static pthread_mutex_t free_rect_lock; static bool throttled; +static struct vmem_cell *bitmap_drawn; static int outstanding_rects; // win32gdi requires two rects... #define MAX_OUTSTANDING 2 @@ -279,19 +280,19 @@ bitmap_vmem_puttext_locked(int sx, int sy, int ex, int ey, struct vmem_cell *fil || ey < 1 || sx > ex || sy > ey - || ex > cio_textinfo.screenwidth - || ey > cio_textinfo.screenheight - || fill==NULL) + || ex > vstat.cols + || ey > vstat.rows + || fill==NULL) { return(0); + } vmem_ptr = get_vmem(&vstat); for(y=sy-1;y<ey;y++) { for(x=sx-1;x<ex;x++) { - vc = &vmem_ptr->vmem[y*cio_textinfo.screenwidth+x]; + vc = &vmem_ptr->vmem[y*vstat.cols+x]; memcpy(vc, fi++, sizeof(*fi)); } } - bitmap_draw_vmem(sx, sy, ex, ey, fill); release_vmem(vmem_ptr); return(1); } @@ -781,6 +782,8 @@ draw_char_row_double(struct blockstate *bs, struct charstate *cs, uint32_t y) static void bitmap_draw_vmem(int sx, int sy, int ex, int ey, struct vmem_cell *fill) { + assert(sx <= ex); + assert(sy <= ey); struct charstate charstate[255]; // ciolib only supports 255 columns struct blockstate bs; size_t vwidth = ex - sx + 1; @@ -839,12 +842,19 @@ bitmap_draw_vmem(int sx, int sy, int ex, int ey, struct vmem_cell *fill) bs.pixeloffset -= bs.maxpix; } screenb.update_pixels = 1; + for (size_t vy = 0; vy < vheight; vy++) { + for (size_t vx = 0; vx < vwidth; vx++) { + memcpy(&bitmap_drawn[(sy - 1 + vy) * vstat.cols + (sx - 1 + vx)], &fill[vy * vwidth + vx], sizeof(*bitmap_drawn)); + } + } } else { for (size_t vy = 0; vy < vheight; vy++) { // Fill in charstate for this pass - for (size_t vx = 0; vx < vwidth; vx++) + for (size_t vx = 0; vx < vwidth; vx++) { + memcpy(&bitmap_drawn[(sy - 1 + vy) * vstat.cols + (sx - 1 + vx)], &fill[vy * vwidth + vx], sizeof(*bitmap_drawn)); calc_charstate(&bs, &fill[vy * vwidth + vx], &charstate[vx], sx + vx, sy + vy); + } // Draw the characters... for (uint32_t y = 0; y < vstat.charheight; y++) { for (size_t vx = 0; vx < vwidth; vx++) { @@ -939,9 +949,8 @@ static void blinker_thread(void *data) request_redraw(); } else { - if (count==0) - if (update_from_vmem(FALSE)) - request_redraw(); + if (update_from_vmem(FALSE)) + request_redraw(); } pthread_mutex_lock(&screenlock); both_screens(blink, &screen, &ncscreen); @@ -998,6 +1007,22 @@ static __inline void both_screens(int blink, struct bitmap_screen** current, str *noncurrent = noncurrent_screen_locked(blink); } +static bool +same_cell(struct vmem_cell *c1, struct vmem_cell *c2) +{ + if (c1->ch != c2->ch) + return false; + if (c1->bg != c2->bg) + return false; + if (c1->fg != c2->fg) + return false; + if (c1->font != c2->font) + return false; + if (c1->legacy_attr != c2->legacy_attr) + return false; + return true; +} + /* * Updates any changed cells... blinking, modified flags, and the cursor * Is also used (with force = TRUE) to completely redraw the screen from @@ -1009,7 +1034,6 @@ static int update_from_vmem(int force) struct vstat_vmem *vmem_ptr; int x,y,width,height; unsigned int pos; - int cols; int bright_attr_changed=0; int blink_attr_changed=0; @@ -1017,9 +1041,6 @@ static int update_from_vmem(int force) if(!bitmap_initialized) return(-1); - width=cio_textinfo.screenwidth; - height=cio_textinfo.screenheight; - pthread_mutex_lock(&vstatlock); if (vstat.vmem == NULL) { @@ -1033,12 +1054,22 @@ static int update_from_vmem(int force) } /* If we change window size, redraw everything */ - if(vs.cols!=vstat.cols || vs.rows != vstat.rows) { + if(bitmap_drawn == NULL || vs.cols!=vstat.cols || vs.rows != vstat.rows) { + struct vmem_cell *newl = realloc(bitmap_drawn, sizeof(struct vmem_cell) * vstat.cols * vstat.rows); + if (newl == NULL) { + vs.cols = 0; + vs.rows = 0; + free(bitmap_drawn); + pthread_mutex_unlock(&vstatlock); + return -1; + } + bitmap_drawn = newl; + memset(bitmap_drawn, 0x04, sizeof(struct vmem_cell) * vstat.cols * vstat.rows); /* Force a full redraw */ - width=vstat.cols; - height=vstat.rows; force=1; } + width=vstat.cols; + height=vstat.rows; /* Did the meaning of the blink bit change? */ if (vstat.bright_background != vs.bright_background || @@ -1053,7 +1084,6 @@ static int update_from_vmem(int force) /* Get vmem pointer */ vmem_ptr = get_vmem(&vstat); - cols = vstat.cols; /* * Now we go through each character seeing if it's changed (or force is set) @@ -1064,18 +1094,36 @@ static int update_from_vmem(int force) * we add it to last_rect. */ + int sx = 0; + int ex = 0; + struct vmem_cell *f; for(y=0;y<height;y++) { - pos=y*cols; + pos=y*width; for(x=0;x<width;x++) { /* Last this char been updated? */ - if(force /* Forced */ - || ((vmem_ptr->vmem[pos].legacy_attr & 0x80) && blink_attr_changed) - || ((vmem_ptr->vmem[pos].legacy_attr & 0x08) && bright_attr_changed)) /* Bright char */ + if(force || !same_cell(&bitmap_drawn[pos], &vmem_ptr->vmem[pos]) + || ((vmem_ptr->vmem[pos].legacy_attr & 0x80) + && blink_attr_changed) + || ((vmem_ptr->vmem[pos].legacy_attr & 0x08) && bright_attr_changed)) { - bitmap_draw_vmem(x + 1, y + 1, x + 1, y + 1, &vmem_ptr->vmem[pos]); + ex = x + 1; + if (sx == 0) { + sx = ex; + f = &vmem_ptr->vmem[pos]; + } + } + else { + if (sx) { + bitmap_draw_vmem(sx, y + 1, ex, y + 1, f); + sx = ex = 0; + } } pos++; } + if (sx) { + bitmap_draw_vmem(sx, y + 1, ex, y + 1, f); + sx = ex = 0; + } } release_vmem(vmem_ptr); vs = vstat; @@ -1119,10 +1167,9 @@ int bitmap_puttext(int sx, int sy, int ex, int ey, void *fill) size_t c = 0; for (y = sy - 1; y < ey; y++) { for (x = sx - 1; x < ex; x++) { - va[c++] = *set_vmem_cell(vmem_ptr, y * cio_textinfo.screenwidth + x, *(buf++), 0x00ffffff, 0x00ffffff); + va[c++] = *set_vmem_cell(vmem_ptr, y * vstat.cols + x, *(buf++), 0x00ffffff, 0x00ffffff); } } - bitmap_draw_vmem(sx, sy, ex, ey, va); release_vmem(vmem_ptr); pthread_mutex_unlock(&vstatlock); free(va); @@ -1164,7 +1211,7 @@ int bitmap_vmem_gettext(int sx, int sy, int ex, int ey, struct vmem_cell *fill) vmem_ptr = get_vmem(&vstat); for(y=sy-1;y<ey;y++) { for(x=sx-1;x<ex;x++) - memcpy(fill++, &vmem_ptr->vmem[y*cio_textinfo.screenwidth+x], sizeof(*fill)); + memcpy(fill++, &vmem_ptr->vmem[y*vstat.cols+x], sizeof(*fill)); } release_vmem(vmem_ptr); pthread_mutex_unlock(&vstatlock); @@ -1382,7 +1429,7 @@ bitmap_movetext_screen(int x, int y, int tox, int toy, int direction, int height int32_t screeny; pthread_mutex_lock(&screenlock); - if (width == cio_textinfo.screenwidth && (height > vstat.rows / 2) && toy == 1) { + if (width == vstat.cols && (height > vstat.rows / 2) && toy == 1) { screena.toprow += (y - toy) * vstat.charheight; if (screena.toprow >= screena.screenheight) screena.toprow -= screena.screenheight; @@ -1402,14 +1449,10 @@ bitmap_movetext_screen(int x, int y, int tox, int toy, int direction, int height direction = 1; else direction = -1; - height = vstat.rows - (height + (y - toy)); - // If everything was moved, there's no lines to move back - if (height <= 0) { - pthread_mutex_unlock(&screenlock); - return; - } + height = vstat.rows - height; + int moved = y - toy; toy = vstat.rows - (height - 1); - y = toy - (height); + y = toy - moved; } int maxpos = screena.screenwidth * screena.screenheight; @@ -1478,23 +1521,25 @@ int bitmap_movetext(int x, int y, int ex, int ey, int tox, int toy) pthread_mutex_lock(&vstatlock); vmem_ptr = get_vmem(&vstat); - if (width == cio_textinfo.screenwidth) { - sourcepos = (( y - 1) * cio_textinfo.screenwidth + ( x - 1)); - destoffset = ((toy - 1) * cio_textinfo.screenwidth + (tox - 1)) - sourcepos; + if (width == vstat.cols) { + sourcepos = (( y - 1) * vstat.cols + ( x - 1)); + destoffset = ((toy - 1) * vstat.cols + (tox - 1)) - sourcepos; memmove(&(vmem_ptr->vmem[sourcepos+destoffset]), &(vmem_ptr->vmem[sourcepos]), sizeof(vmem_ptr->vmem[0])*width*height); + memmove(&(bitmap_drawn[sourcepos+destoffset]), &(bitmap_drawn[sourcepos]), sizeof(vmem_ptr->vmem[0])*width*height); } else { if (direction == -1) { - sourcepos=(y+height-2)*cio_textinfo.screenwidth+(x-1); - destoffset=(((toy+height-2)*cio_textinfo.screenwidth+(tox-1))-sourcepos); + sourcepos=(y+height-2)*vstat.cols+(x-1); + destoffset=(((toy+height-2)*vstat.cols+(tox-1))-sourcepos); } else { - sourcepos=(y-1)*cio_textinfo.screenwidth+(x-1); - destoffset=(((toy-1)*cio_textinfo.screenwidth+(tox-1))-sourcepos); + sourcepos=(y-1)*vstat.cols+(x-1); + destoffset=(((toy-1)*vstat.cols+(tox-1))-sourcepos); } - step = direction * cio_textinfo.screenwidth; + step = direction * vstat.cols; for(cy=0; cy<height; cy++) { memmove(&(vmem_ptr->vmem[sourcepos+destoffset]), &(vmem_ptr->vmem[sourcepos]), sizeof(vmem_ptr->vmem[0])*width); + memmove(&(bitmap_drawn[sourcepos+destoffset]), &(bitmap_drawn[sourcepos]), sizeof(vmem_ptr->vmem[0])*width); sourcepos += step; } } @@ -1527,7 +1572,6 @@ void bitmap_clreol(void) for(x=cio_textinfo.curx+cio_textinfo.winleft-2; x<cio_textinfo.winright; x++) { va[c++] = *set_vmem_cell(vmem_ptr, pos+x, fill, ciolib_fg, ciolib_bg); } - bitmap_draw_vmem(cio_textinfo.curx + cio_textinfo.winleft - 1, row, cio_textinfo.winright, row, va); release_vmem(vmem_ptr); pthread_mutex_unlock(&vstatlock); free(va); @@ -1556,7 +1600,6 @@ void bitmap_clrscr(void) va[c++] = *set_vmem_cell(vmem_ptr, y * cio_textinfo.screenwidth + x, fill, ciolib_fg, ciolib_bg); } } - bitmap_draw_vmem(cio_textinfo.winleft, cio_textinfo.wintop, cio_textinfo.winright, cio_textinfo.winbottom, va); free(va); release_vmem(vmem_ptr); pthread_mutex_unlock(&vstatlock); @@ -1661,6 +1704,7 @@ int bitmap_attr2palette(uint8_t attr, uint32_t *fgp, uint32_t *bgp) int bitmap_setpixel(uint32_t x, uint32_t y, uint32_t colour) { + update_from_vmem(FALSE); pthread_mutex_lock(&screenlock); if (x < screena.screenwidth && y < screena.screenheight) { if (screena.rect->data[pixel_offset(&screena, x, y)] != colour) { @@ -1711,6 +1755,7 @@ int bitmap_setpixels(uint32_t sx, uint32_t sy, uint32_t ex, uint32_t ey, uint32_ return 0; } + update_from_vmem(FALSE); pthread_mutex_lock(&screenlock); if (ex > screena.screenwidth || ey > screena.screenheight) { pthread_mutex_unlock(&screenlock);