📄 sprite.c
字号:
/*---------------------------------------------------------------------- File : sprite.c Contents: sprite management, single color (X11 version) Author : Christian Borgelt History : 30.10.1997 file created 31.10.1997 first version completed 01.11.1997 event processing in function spr_move added 02.11.1997 NOFLICKER version hardcoded 04.11.1997 move function changed to timeout procedure 06.11.1997 callback function added to function spr_move 16.06.1998 switching to new sprite image improved----------------------------------------------------------------------*/#include <stdio.h>#include <stdlib.h>#include <time.h>#include "sprite.h"#include <X11/Xutil.h>/*---------------------------------------------------------------------- Auxiliary Functions----------------------------------------------------------------------*/static void move (XtPointer data, XtIntervalId *iid){ /* --- move sprite one step */ SPRITE *spr = data; /* sprite to be moved */ if (spr->cnt <= 0) return; /* if stopped, abort function */ XSetClipOrigin(spr->display, spr->gc, /* duplicate */ spr->xext -spr->xoff, -spr->yoff); /* background */ XCopyArea(spr->display, spr->buffer, spr->buffer, spr->gc, 0, 0, spr->xext, spr->yext, spr->xext, 0); spr->xnew += spr->di *spr->xext; /* get offset for new image */ XSetClipOrigin(spr->display, spr->gc, /* draw new image */ spr->dx -spr->xnew, spr->dy -spr->ynew); /* into buffer */ XFillRectangle(spr->display, spr->buffer, spr->gc, spr->dx, spr->dy, spr->xext, spr->yext); XSetClipOrigin(spr->display, spr->gc, /* undraw sprite */ spr->xpos -spr->xoff, spr->ypos -spr->yoff); XCopyArea(spr->display, spr->buffer, spr->window, spr->gc, 0, 0, spr->xext, spr->yext, spr->xpos, spr->ypos); spr->xpos += spr->dx; /* move sprite to */ spr->ypos += spr->dy; /* new position */ XSetClipOrigin(spr->display, spr->gc, /* copy background */ -spr->xnew, -spr->ynew); /* into buffer */ XCopyArea(spr->display, spr->window, spr->buffer, spr->gc, spr->xpos, spr->ypos, spr->xext, spr->yext, 0, 0); XSetClipOrigin(spr->display, spr->gc, /* complete background */ -spr->dx -spr->xoff, -spr->dy -spr->yoff);/* from duplicate */ XCopyArea(spr->display, spr->buffer, spr->buffer, spr->gc, spr->xext, 0, spr->xext, spr->yext, -spr->dx, -spr->dy); /* It is necessary to complete the background with the */ /* background data from the duplicate in the second buffer, */ /* since we drew the new sprite image into the background */ /* buffer and copied this modified background to the screen. */ /* Hence, if the new and the old sprite image overlap, */ /* we cannot get the complete background from the screen, */ /* but only the part that is not obscured by the overlap. */ /* The obscured part we get from the buffered duplicate. */ XSetClipOrigin(spr->display, spr->gc, /* draw sprite */ spr->xpos -spr->xnew, spr->ypos -spr->ynew); XFillRectangle(spr->display, spr->window, spr->gc, spr->xpos, spr->ypos, spr->xext, spr->yext); XFlush(spr->display); /* flush buffered drawing commands */ spr->xoff = spr->xnew; /* transfer offsets for new image */ spr->yoff = spr->ynew; /* to offsets for current image */ if (--spr->cnt > 0) /* if not done, reregister function */ spr->iid = XtAppAddTimeOut(spr->appctx, spr->delay, move, spr); else if (spr->cback) /* otherwise call callback function */ spr->cback(spr->widget, spr->data, (XtPointer)spr);} /* move() *//*---------------------------------------------------------------------- Main Functions----------------------------------------------------------------------*/SPRITE* spr_create (Widget widget, int xext, int yext, Pixmap bitmap, unsigned long color){ /* --- create a sprite */ SPRITE *spr; /* created sprite */ int depth; /* color depth of display */ spr = (SPRITE*)malloc(sizeof(SPRITE)); if (!spr) return NULL; /* allocate sprite body */ spr->xext = xext; /* and initialize fields */ spr->yext = yext; /* note sprite extensions */ spr->xoff = spr->yoff = 0; /* select first image of first series */ spr->xnew = spr->ynew = 0; /* for the current and the new image */ spr->xpos = spr->ypos = 0; /* initialize position */ spr->drawn = spr->cnt = 0; /* sprite is not drawn and not moving */ spr->appctx = XtWidgetToApplicationContext(widget); spr->widget = widget; /* note app. context and widget */ spr->display = XtDisplay(widget); /* get display and */ spr->window = XtWindow(widget); /* window of widget */ /* --- create window graphic context --- */ spr->gc = XCreateGC(spr->display, spr->window, 0, NULL); if (!spr->gc) { free(spr); return NULL; } XSetForeground(spr->display, spr->gc, color); /* set color */ XSetClipMask (spr->display, spr->gc, bitmap); /* and bitmap */ /* --- create background buffer --- */ depth = XDefaultDepth(spr->display, XDefaultScreen(spr->display)); spr->buffer = XCreatePixmap(spr->display, spr->window, 2 *xext, yext, depth); if (spr->buffer == None) { spr_delete(spr); return NULL; } /* The reason why the background buffer is allocated with */ /* double sprite width can be seen in the function spr_move. */ return spr; /* return created sprite */} /* spr_create() *//*--------------------------------------------------------------------*/void spr_delete (SPRITE *spr){ /* --- delete a sprite */ if (spr->drawn) spr_undraw(spr); if (spr->buffer != None) XFreePixmap(spr->display, spr->buffer); if (spr->gc) XFreeGC(spr->display, spr->gc); free(spr); /* delete buffer, gcs and sprite body */} /* spr_delete() *//*--------------------------------------------------------------------*/void spr_select (SPRITE *spr, int series, int index){ /* --- select a sprite image */ spr->xnew = (index > 0) ? index *spr->xext : 0; spr->ynew = (series > 0) ? series *spr->yext : 0;} /* spr_select() *//*--------------------------------------------------------------------*/int spr_draw (SPRITE *spr, int x, int y){ /* --- draw a sprite */ if (spr->drawn) { /* if sprite is drawn */ if (((x == INT_MIN) || (x == spr->xpos)) && ((y == INT_MIN) || (y == spr->ypos)) && (spr->xoff == spr->xnew) && (spr->yoff == spr->ynew)) return 0; /* if sprite is already drawn at the */ spr_undraw(spr); /* correct position, abort function, */ spr->xoff = spr->xnew; /* otherwise undraw sprite */ spr->yoff = spr->ynew; /* and get the offsets for */ } /* the new sprite image */ if (x > INT_MIN) spr->xpos = x; /* if new coordinates given, */ if (y > INT_MIN) spr->ypos = y; /* use coordinates */ XSetClipOrigin(spr->display, spr->gc, -spr->xoff, -spr->yoff); /* save background in buffer */ XCopyArea(spr->display, spr->window, spr->buffer, spr->gc, spr->xpos, spr->ypos, spr->xext, spr->yext, 0, 0); XSetClipOrigin(spr->display, spr->gc, spr->xpos -spr->xoff, spr->ypos -spr->yoff); XFillRectangle(spr->display, spr->window, spr->gc, spr->xpos, spr->ypos, spr->xext, spr->yext); XFlush(spr->display); /* draw sprite */ spr->drawn = 1; /* note that sprite is drawn */ return 0; /* return 'ok' */} /* spr_draw() *//*--------------------------------------------------------------------*/int spr_undraw (SPRITE *spr){ /* --- undraw a sprite */ if (!spr->drawn) return -1; /* if sprite is not drawn, abort */ XCopyArea(spr->display, spr->buffer, spr->window, spr->gc, 0, 0, spr->xext, spr->yext, spr->xpos, spr->ypos); XFlush(spr->display); /* copy background back to window */ spr->drawn = 0; /* note that sprite is not drawn */ return 0; /* return 'ok' */} /* spr_undraw() *//*--------------------------------------------------------------------*/int spr_move (SPRITE *spr, int dx, int dy, int di, int cnt, float delay, XtCallbackProc callback, XtPointer data){ /* --- animate a sprite */ if (spr->cnt > 0) return -1; /* if sprite is (still) moving, abort */ if (!spr->drawn) /* if sprite is not drawn, */ spr_draw(spr, INT_MIN, INT_MIN); /* draw it */ if (cnt <= 0) return 0; /* if not to move, abort function */ spr->dx = dx; spr->dy = dy; spr->di = di; spr->cnt = cnt; /* note parameters */ spr->delay = (unsigned int)(delay *1000); spr->cback = callback; /* note callback function */ spr->data = data; /* and client data */ spr->iid = XtAppAddTimeOut(spr->appctx, spr->delay, move, spr); return 0; /* register function and return 'ok' */} /* spr_move() *//*--------------------------------------------------------------------*/void spr_stop (SPRITE *spr){ /* --- stop moving sprite */ if (spr->cnt <= 0) return; /* if sprite is not moving, abort */ XtRemoveTimeOut(spr->iid); /* remove timer procedure */ spr->cnt = 0; /* and clear number of steps */} /* spr_stop() */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -