📄 cimg.c
字号:
{
VIEW *view = (VIEW *)handle;
IMAGE *img = view_get_image(view);
#ifdef DISPLAY_DEBUG
gs_addmessf("display_close(0x%x, 0x%x)\n", handle, device);
#endif
img->open = FALSE;
img->opening = FALSE;
img->handle = handle;
img->device = device;
img->width = img->height = img->raster = 0;
img->format = 0;
img->image = NULL;
if (img->tile)
free(img->tile);
img->tile = NULL;
img->tile_width = 0;
img->tile_height = 0;
img->tile_dirty = 0;
img->tile_verydirty_threshold = 0;
img->tile_threshold = 0;
img->tile_columns = 0;
img->tile_rows = 0;
img->tile_time = 0;
img->tile_interval = 0;
image_unlock(img);
view_post_message(view, WM_GSDEVICE, 0);
return 0;
}
/* Device is about to be resized. */
/* Resize will only occur if this function returns 0. */
static int display_presize(void *handle, void *device, int width, int height,
int raster, unsigned int format)
{
VIEW *view = (VIEW *)handle;
IMAGE *img = view_get_image(view);
#ifdef DISPLAY_DEBUG
gs_addmessf("display_presize(0x%x, 0x%x, width=%d height=%d raster=%d\
format=%d)\n",
handle, device, width, height, raster, format);
#endif
if (!img->opening)
image_lock(img);
/* check if we understand format */
if (image_presize(img, width, height, raster, format))
return_error(DISPLAY_ERROR);
if (img->tile)
free(img->tile);
img->tile = NULL;
return 0;
}
/* Device has been resized. */
/* New pointer to raster returned in pimage */
static int display_size(void *handle, void *device, int width, int height,
int raster, unsigned int format, unsigned char *pimage)
{
VIEW *view = (VIEW *)handle;
IMAGE *img = view_get_image(view);
int len;
#ifdef DISPLAY_DEBUG
gs_addmessf("display_size(0x%x, 0x%x, width=%d height=%d raster=%d\
format=%d image=0x%x)\n",
handle, device, width, height, raster, format, pimage);
#endif
img->width = width;
img->height = height;
img->raster = raster;
img->format = format;
img->image = pimage;
if (image_size(img))
img->open = FALSE;
else {
if (img->opening)
img->open = TRUE;
img->opening = FALSE;
}
img->tile_width = 64;
img->tile_height = 64;
img->tile_dirty = 0;
img->tile_verydirty_threshold = 256;
if (img->tile) {
free(img->tile);
img->tile = NULL;
}
img->tile_columns = (img->width + img->tile_width - 1) / img->tile_width;
img->tile_rows = (img->height + img->tile_height - 1) / img->tile_height;
len = img->tile_rows * img->tile_columns * sizeof(img->tile[0]);
img->tile = (int *)malloc(len);
if (img->tile)
memset(img->tile, 0, len);
img->tile_threshold = max(4, img->tile_columns/2);
img->tile_time = 0;
img->tile_interval = 100; /* start at 100ms */
image_unlock(img);
view_post_message(view, WM_GSSIZE, 0);
return 0;
}
/* flushpage */
static int display_sync(void *handle, void *device)
{
VIEW *view = (VIEW *)handle;
IMAGE *img = view_get_image(view);
#ifdef DISPLAY_DEBUG
gs_addmessf("display_sync(0x%x, 0x%x)\n", handle, device);
#endif
if (img->ignore_sync) {
/* ignore this sync, but not the next */
img->ignore_sync = FALSE;
return 0;
}
image_sync(img);
view_post_message(view, WM_GSSYNC, 0);
return 0;
}
/* showpage */
/* If you want to pause on showpage, then don't return immediately */
static int display_page(void *handle, void *device, int copies, int flush)
{
VIEW *view = (VIEW *)handle;
IMAGE *img = view_get_image(view);
#ifdef DISPLAY_DEBUG
gs_addmessf("display_page(0x%x, 0x%x, copies=%d flush=%d)\n",
handle, device, copies, flush);
#endif
img->ignore_sync = FALSE;
image_sync(img);
view_page_callback(view);
return 0;
}
/*
* This keeps track of how much of the page is currently
* dirty by segmenting the page into tiles and keeping
* track of which tiles are dirty.
* When more than img->tile_threshold tiles are dirty,
* or a single tile has been dirtied many times,
* a refresh of those tiles is requested.
* The first part of this code must be fast because it is
* called frequently.
*
* The current code causes the redraw to occur in chunks.
* Perhaps a LRU method would be better so that it progressively
* draws those tiles which are no longer being dirtied.
*/
void
image_draw_tile(IMAGE *img, int tx1, int ty1, int tx2, int ty2)
{
int param;
tx1 = min(max(0, tx1), 255);
ty1 = min(max(0, ty1), 255);
tx2 = min(max(0, tx2), 255);
ty2 = min(max(0, ty2), 255);
param = (tx1<<24) + (ty1<<16) + (tx2<<8) + ty2;
view_post_message((VIEW *)(img->handle), WM_GSTILE, param);
}
void
image_tile_update(IMAGE *img, int ux, int uy, int uw, int uh)
{
int tx, ty;
int tx1, ty1, tx2, ty2;
int columns = img->tile_columns;
int rows = img->tile_rows;
int dirty = 0;
int very_dirty = 0;
if (!img->tile)
return;
if ((img->width==0) || (img->height ==0) ||
(img->tile_width == 0) || (img->tile_height ==0))
return;
/* Mark tiles as dirty */
tx1 = ux / img->tile_width; /* lower left */
ty1 = uy / img->tile_height;
tx2 = (ux+uw-1) / img->tile_width; /* upper right */
ty2 = (uy+uh-1) / img->tile_height;
/* Sanity check on tile index */
if ((tx2 >= img->tile_columns) || (tx1 > tx2) || (tx1 < 0) ||
(ty2 >= img->tile_rows) || (ty1 > ty2) || (ty1 < 0))
return;
/* Mark dirty tiles */
for (ty=ty1; ty<=ty2; ty++) {
for (tx=tx1; tx<=tx2; tx++) {
/* is tile newly dirtied? */
if (!img->tile[ty*columns + tx])
img->tile_dirty++; /* newly dirtied tile */
/* mark tile as dirty, and note if it is very dirty */
dirty = ++(img->tile[ty*columns + tx]);
if (dirty > img->tile_verydirty_threshold)
very_dirty = 1;
}
}
/* code above here must be fast */
if (very_dirty || (img->tile_dirty > img->tile_threshold)) {
/* Make sure we do this no more than 10 times per second */
/* to avoid swamping the window queue */
if (image_update_time(img) != 0) {
/* too soon */
return;
}
/* work out rectangle enclosing dirty tiles */
tx1 = columns;
tx2 = 0;
ty1 = rows;
ty2 = 0;
dirty = 0;
for (ty=0; ty<rows; ty++) {
for (tx=0; tx<columns; tx++) {
if (img->tile[ty * columns + tx]) {
dirty++;
if (tx < tx1)
tx1 = tx;
if (tx > tx2)
tx2 = tx;
if (ty < ty1)
ty1 = ty;
if (ty > ty2)
ty2 = ty;
}
else {
}
}
}
if (img->ignore_sync) {
img->ignore_sync = FALSE;
image_sync(img);
}
else if ((tx2 >= tx1) && (ty2 >= ty1)) {
/* redraw it */
int tx3;
if (dirty * 10 < (tx2 - tx1 + 1) * (ty2 - ty1 + 1)) {
/* draw individual tiles */
/* but merge horizontally adjacent tiles together */
for (ty=ty1; ty<=ty2; ty++) {
for (tx=tx1; tx<=tx2; tx++) {
if (img->tile[ty*columns + tx]) {
/* look for adjacent tiles */
for (tx3 = tx+1; tx3 <= tx2; tx3++) {
if (!img->tile[ty*columns + tx3])
break;
}
tx3--;
image_draw_tile(img, tx, ty, tx3, ty);
}
}
}
}
else {
image_draw_tile(img, tx1, ty1, tx2, ty2);
}
}
memset(img->tile, 0, sizeof(img->tile[0]) * rows * columns);
img->tile_dirty = 0; /* all tiles will be cleaned */
}
}
/* Poll the caller for cooperative multitasking. */
/* If this function is NULL, polling is not needed */
static int display_update(void *handle, void *device,
int x, int y, int w, int h)
{
VIEW *view = (VIEW *)handle;
IMAGE *img = view_get_image(view);
image_tile_update(img, x, y, w, h);
if (img->lock_count != 0)
return 0; /* prevent update during image resize on single thread */
return view_poll((VIEW *)handle);
}
display_callback gsdisplay = {
sizeof(display_callback),
DISPLAY_VERSION_MAJOR,
DISPLAY_VERSION_MINOR,
display_open,
display_preclose,
display_close,
display_presize,
display_size,
display_sync,
display_page,
display_update,
#ifdef OS2
display_memalloc,
display_memfree
#else
NULL, /* memalloc */
NULL /* memfree */
#endif
};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -