home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / GRAPHICS / MISC / STK100.ZIP / STKSRC.COM / SPR.C < prev    next >
Encoding:
C/C++ Source or Header  |  1990-10-20  |  15.3 KB  |  464 lines

  1. /**********************************************************************
  2. * spr.c
  3. *
  4. * The sprite support system main functions
  5. **********************************************************************
  6.                     This file is part of
  7.  
  8.           STK -- The sprite toolkit -- version 1.0
  9.  
  10.               Copyright (C) Jari Karjala 1990
  11.  
  12. The sprite toolkit (STK) is a FreeWare toolkit for creating high
  13. resolution sprite graphics with PCompatible hardware. This toolkit 
  14. is provided as is without any warranty or such thing. See the file
  15. COPYING for further information.
  16.  
  17. **********************************************************************/
  18.  
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21.  
  22. #include <alloc.h>      /* farmalloc(), farfree() */
  23. #include <dos.h>        /* delay() */
  24. #include <graphics.h>   /* setactivepage(), setvisualpage(), mode defines */
  25. #include <mem.h>        /* memcpy(), movedata() */
  26. #include <time.h>       /* clock(), clock_t */
  27.  
  28. #include "sprP.h"
  29. #include "spr.h"
  30. #include "spr_low.h"
  31. #include "spr_misc.h"
  32.  
  33. /** display lists for each display page **/
  34. SPRITE spr_sprites[2] = { NULL, NULL };
  35.  
  36. /** the sprites to be destroyed after next_pass **/
  37. static SPRITE destroy_list = { NULL };
  38.  
  39. /** the current drawing page **/
  40. WORD spr_drawingpage = 0;
  41.  
  42. /**********************************************************************
  43. * The delay after setvisualpage() before removing old objects. 
  44. * Time is given in milliseconds. Hercules cards do not need this,
  45. * but many EGA/VGA cards do need some milliseconds to switch pages.
  46. **********************************************************************/
  47. int spr_pass_delay = 10;
  48.  
  49. /**********************************************************************
  50. * Called from low level funtions if not sprite system initialized, 
  51. * or if initialization fails.
  52. **********************************************************************/
  53. void static fatal_error()
  54. {
  55.     closegraph();
  56.     puts("FATAL: Sprite system initialization error.");
  57.     exit(255);
  58. }
  59.  
  60.  
  61. /** hardware dependent putter **/
  62. void static (*spr_low_putter)
  63.                     (BYTE far *shape, BYTE far *dest, BYTE far *save, 
  64.                      WORD w, WORD h) = fatal_error;
  65.                    
  66. /** hardware dependent eraser  **/
  67. void static (*spr_low_eraser)(BYTE far *dest, BYTE far *save, 
  68.                        WORD w, WORD h) = fatal_error;    
  69.  
  70. /** hardware dependent address calculator (TCC gives warning here) **/
  71. BYTE static far *(*spr_low_addr)(WORD x, WORD y, BYTE page) = fatal_error; 
  72.  
  73.  
  74. /**********************************************************************
  75. * Initialize the sprite system to the given display hardware.
  76. * Supported graphicsdrivers: EGAMONO and HERCMONO
  77. * The visual page is set to 0.
  78. * NOTE: This function must be called before any other sprite funtions
  79. *       and the graphics mode must have been set before this call.
  80. * graphicsdriver  The BGI identifier for the graphics driver used.
  81. **********************************************************************/
  82. void spr_initialize(int graphicsdriver)
  83. {
  84.     switch (graphicsdriver) {
  85.         case HERCMONO:
  86.             spr_low_putter = spr_low_herc_put;
  87.             spr_low_eraser = spr_low_herc_erase;
  88.             spr_low_addr   = spr_low_herc_addr;
  89.             spr_pass_delay = 1; /** hercules cards do not need this **/
  90.             break;
  91.             
  92.         case EGAMONO:
  93.             spr_low_putter = spr_low_ega_mono_put;
  94.             spr_low_eraser = spr_low_ega_mono_erase;
  95.             spr_low_addr   = spr_low_ega_mono_addr;
  96.             break;
  97.             
  98.         default:
  99.             fatal_error();  /**  (TCC gives warning here) **/
  100.     }
  101.  
  102.     setvisualpage(spr_drawingpage);
  103. }
  104.  
  105.  
  106.  
  107. /**********************************************************************
  108. * Create a sprite.
  109. *
  110. * w,h   Width (must be < 8*255) and height (<256) of sprite in pixels
  111. * pic   The picture bitmap for the sprite
  112. * mask  The mask bitmap for the sprite
  113. * res   The number of steps wanted per 8 bit interval in horizontal
  114. *       direction (1,2,4,8). For example, the value 8 gives one
  115. *       pixel resolution in X-direction.
  116. * ID    The user supplied ID for the sprite (not obligatory)
  117. *
  118. * Return: the newly created sprite or NULL if parameter error
  119. *           or out-of-memory
  120. **********************************************************************/
  121. SPRITE spr_create(WORD w, WORD h, 
  122.                   BITMAP shape, BITMAP mask, 
  123.                   BYTE res, WORD ID)
  124. {
  125.     SPRITE spr;
  126.     WORD size;
  127.     
  128.     if (w<8 || h<1 || w >= 8*255 || h > 255 || shape==NULL || mask==NULL)
  129.         return NULL;
  130.  
  131.     if (res!=1 && res!=2 && res!=4 && res!=8)
  132.         return NULL;
  133.     
  134.     spr = (SPRITE)malloc(sizeof(struct _sprite));
  135.     if (spr==NULL)
  136.         return NULL;
  137.  
  138.     if (w&7)
  139.         spr->w = (w>>3) + 1;    /* not exact byte boundary, round up */
  140.     else
  141.         spr->w = w>>3;
  142.  
  143.     if (res>1)      /** make space for right shifts **/
  144.         spr->w++;
  145.     
  146.     spr->wp = w;    
  147.     spr->hp = h;    
  148.     spr->res = res;
  149.     spr->flags = FLAG_NONE;
  150.     spr->id = ID;
  151.     spr->x = spr->y = (WORD)-1;     /* Place it out of screen initially */
  152.  
  153.     size = spr->w * spr->hp;         /* size of one bitmap */
  154.     spr->size = size * 2;           /* shape + mask size */
  155.     
  156.     /** malloc space for usage count, bitmaps + save buffer for old images **/
  157.     spr->data = (FARMAP)farmalloc(spr->size*(long)res + size*2L);
  158.     if (spr->data==NULL) {
  159.         free(spr);
  160.         return NULL;
  161.     }
  162.  
  163.     /** create shifted/combined shape/mask maps **/
  164.     spr_misc_create_data(spr, shape, mask);
  165.     
  166.     /** set save buffer address for both display pages **/
  167.     spr->saved[0] = spr->data + (spr->size * res);
  168.     spr->saved[1] = spr->data + (spr->size * res + size);
  169.     
  170.     spr->next[0] = spr->next[1] = NULL;
  171.     spr->addr[0] = spr->addr[1] = NULL;
  172.  
  173.     spr->share = NULL;
  174.     spr->share_index = 0;
  175.     
  176.     return spr;
  177. }
  178.  
  179. /**********************************************************************
  180. * Create a shared version of the given sprite. This allows
  181. * n spr_copies which all share the shape data thus saving
  182. * quite much memory.
  183. *
  184. * spr   The sprite to share
  185. * n     The maximum number of shared copies
  186. *
  187. * Return: New SPRITE or NULL if error (out of memory, spr==NULL, etc)
  188. **********************************************************************/
  189. SPRITE spr_share(SPRITE spr, BYTE n)
  190. {
  191.     WORD size, i;
  192.     
  193.     if (spr==NULL)
  194.         return NULL;
  195.     
  196.     size = spr->w * spr->hp;         /* size of one bitmap */
  197.     n++;
  198.     
  199.     /** Reallocate space for shapes, save space for copies and share index **/
  200.     spr->data = (FARMAP)farrealloc(spr->data,
  201.                                    spr->size*spr->res + n*size*2L + n);
  202.     
  203.     /** Reset old save buffer address for both display pages **/
  204.     /** (Realloc might move the block) **/
  205.     spr->saved[0] = spr->data + (spr->size * spr->res);
  206.     spr->saved[1] = spr->data + (spr->size * spr->res + size);
  207.     
  208.     /** Set share index pointer and reset its contents **/
  209.     spr->share = spr->data + (spr->size*spr->res + n*size*2L);
  210.     spr->share_index = 0;
  211.     spr->max_share = n-1;
  212.     spr->share[spr->share_index] = 1;
  213.     for (i=1; i<spr->max_share; i++)
  214.         spr->share[i] = 0;
  215.     
  216.     return spr;
  217. }
  218.  
  219.  
  220. /**********************************************************************
  221. * Return a copy of the given sprite.
  222. *
  223. * spr   The sprite to copy
  224. * id    The ID for the new sprite
  225. *
  226. * Return: New SPRITE of NULL if error (out of memory, spr==NULL, etc)
  227. **********************************************************************/
  228. SPRITE spr_copy(SPRITE spr_old, WORD id)
  229. {
  230.     SPRITE spr;
  231.     WORD size, i;
  232.  
  233.     if (spr_old==NULL)
  234.         return NULL;
  235.     
  236.     spr = (SPRITE)malloc(sizeof(struct _sprite));
  237.     if (spr==NULL)
  238.         return NULL;
  239.     memcpy(spr, spr_old, sizeof(struct _sprite));
  240.  
  241.     spr->id = id;
  242.     size = spr->w * spr->hp;         /* size of one bitmap */
  243.  
  244.     if (spr->share!=NULL) { /** we have a shared sprite **/
  245.         for (i=0; i<spr->max_share; i++)
  246.             if (spr->share[i]==0)
  247.                 break;
  248.         if (i==spr->max_share) {    /** no free slots **/
  249.             free(spr);
  250.             return NULL;
  251.         }
  252.         spr->saved[0] = spr->data + (spr->size * spr->res + (size*2)*i);
  253.         spr->saved[1] = spr->data + (spr->size * spr->res + (size*2)*i+size);
  254.         spr->share[i] = 1;
  255.         spr->share_index = i;
  256.     }
  257.     else {  /** not shared, must make a full copy **/
  258.         /** space for usage count, bitmaps + save buffer for old images **/
  259.         spr->data = (FARMAP)farmalloc(spr->size*spr->res + size*2L);
  260.         if (spr->data==NULL) {
  261.             free(spr);
  262.             return NULL;
  263.         }
  264.  
  265.         movedata(FP_SEG(spr_old->data), FP_OFF(spr_old->data),
  266.                  FP_SEG(spr->data), FP_OFF(spr->data),
  267.                  spr->size*spr->res);
  268.  
  269.         /** set save buffer address for both display pages **/
  270.         spr->saved[0] = spr->data + (spr->size * spr->res);
  271.         spr->saved[1] = spr->data + (spr->size * spr->res + size);
  272.     }
  273.  
  274.     return spr;
  275. }
  276.  
  277. /**********************************************************************
  278. * Put the sprite into the given position into the display list.
  279. * NOTE: the call has no effect on screen until a call to 
  280. *       spr_next_pass() is made.
  281. *
  282. * spr   The sprite to put
  283. * x     The X coordinate
  284. * y     The Y coordinate
  285. **********************************************************************/
  286. void spr_put(SPRITE spr, WORD x, WORD y)
  287. {
  288.     /** add sprite to the display list **/
  289.     spr->next[spr_drawingpage] = spr_sprites[spr_drawingpage];
  290.     spr_sprites[spr_drawingpage] = spr;
  291.     
  292.     /** save coordinates for collision checking & SHAPE_OFS macro **/
  293.     spr->x = x;
  294.     spr->y = y;
  295.     
  296.     spr->addr[spr_drawingpage] = spr_low_addr(x,y,spr_drawingpage);
  297. }
  298.  
  299. /**********************************************************************
  300. * Remove the sprite from the display list
  301. * NOTE: the call has no effect on screen until a call to 
  302. *       spr_next_pass() is made.
  303. *
  304. * spr   The sprite to hide
  305. **********************************************************************/
  306. void spr_hide(SPRITE spr)
  307. {
  308.     spr_misc_delete(spr, spr_drawingpage);
  309. }
  310.  
  311. /**********************************************************************
  312. * Delete the given sprite and release associated memory buffers.
  313. * Also delete it from the display lists. (Actually the sprite is
  314. * only hidden and moved into the deletion list, the memory is freed
  315. * after the next_pass().)
  316. *
  317. * spr   The sprite to delete
  318. **********************************************************************/
  319. void spr_delete(SPRITE spr)
  320. {
  321.     spr_hide(spr);
  322.     spr->next[spr_drawingpage] = destroy_list;
  323.     destroy_list = spr;    
  324. }
  325.  
  326. /**********************************************************************
  327. * Display all sprites in the chain in reversed order.
  328. * NOTE: this is recursive, so it needs 4-8 bytes (depending on memory
  329. * model) of stack space for each sprite.
  330. **********************************************************************/
  331. void static show_all_reversed(SPRITE s)
  332. {
  333.     if (s==NULL)
  334.         return;
  335.     
  336.     /** First descent recursively to the end of list **/
  337.     if (s->next[spr_drawingpage]!=NULL)
  338.         show_all_reversed(s->next[spr_drawingpage]);
  339.  
  340.     spr_low_putter(s->data+SHAPE_OFS(s), 
  341.                    s->addr[spr_drawingpage], s->saved[spr_drawingpage],
  342.                    s->w, s->hp);
  343. }
  344.  
  345. /**********************************************************************
  346. * This function actually shows the sprites.
  347. * The following functions are performed (the order is important):
  348. * - put all sprite images into the hidden page (in reverse order).
  349. * - set hidden page to visual page (delay a moment for EGA cards).
  350. * - delete the old sprite images from the (now hidden) page.
  351. * - now it is safe to actually free the spr_deleted sprites.
  352. *
  353. * Return: The current visual page.
  354. **********************************************************************/
  355. WORD spr_next_pass(void)
  356. {
  357.     SPRITE s;
  358.     int i;
  359.  
  360.     /** Display all sprites at once in reverse order **/
  361.     show_all_reversed(spr_sprites[spr_drawingpage]);
  362.     
  363.     setvisualpage(spr_drawingpage); /** show 'em **/
  364.     
  365.     delay(spr_pass_delay);          /** EGA/VGA cards are SLOW! **/
  366.     
  367.     /** Then delete old ones **/
  368.     spr_drawingpage ^= 1;
  369.     s = spr_sprites[spr_drawingpage];
  370.     while (s!=NULL) {
  371.         spr_low_eraser(s->addr[spr_drawingpage], s->saved[spr_drawingpage],
  372.                        s->w,s->hp);
  373.         s = s->next[spr_drawingpage];
  374.     }
  375.     spr_sprites[spr_drawingpage] = NULL;
  376.     
  377.     /** Destroy the sprites which have been spr_deleted **/
  378.     s = destroy_list;
  379.     while (s!=NULL) {
  380.         if (s->share!=NULL) { /** if shared must check for usage **/
  381.             s->share[s->share_index] = 0;
  382.             for (i=0; i<s->max_share; i++)
  383.                 if (s->share[i])
  384.                     break;
  385.             if (i==s->max_share)
  386.                 farfree(s->data);
  387.         }
  388.         else
  389.             farfree(s->data);
  390.         
  391.         free(s);
  392.         s = s->next[spr_drawingpage^1];
  393.     }
  394.     destroy_list = NULL;
  395.         
  396.     return spr_drawingpage^1;
  397. }
  398.  
  399. /**********************************************************************
  400. * This function tries to regulate the frame speed by delaying if
  401. * we are doing more frames per second than we should. The target 
  402. * speed is 1 frame per one clock tick (about 18 frames per second).
  403. * (This is about the highest reasonable rate for 15-20 32x24 pixel
  404. * sprites on a Hercules screen with a 10 MHz 286.)
  405. **********************************************************************/
  406. void spr_regulate_speed(void)
  407. {
  408.     static int d=0;
  409.     static int j=0;
  410.     static clock_t old_clock=0;
  411.     int i;
  412.     
  413.     delay(d);
  414.     if ((j++ & 7)==7) {
  415.         if ((i=(int)(clock()-old_clock)) < 8)
  416.             d += 8-i;   /** running too fast (more than frame per tick) **/
  417.         else 
  418.             if (d>0)    /** running too slow (less than frame per tick) **/
  419.                 d--;
  420.         old_clock = clock();
  421.     }    
  422. }
  423.  
  424. /**********************************************************************
  425. * Return the user supplied identifier of the sprite
  426. **********************************************************************/
  427. WORD spr_get_id(SPRITE spr)
  428. {
  429.     return spr->id;
  430. }
  431.  
  432. /**********************************************************************
  433. * Return the X coordinate of the sprite
  434. **********************************************************************/
  435. WORD spr_get_x(SPRITE spr)
  436. {
  437.     return spr->x;
  438. }
  439.  
  440. /**********************************************************************
  441. * Return the Y coordinate of the sprite
  442. **********************************************************************/
  443. WORD spr_get_y(SPRITE spr)
  444. {
  445.     return spr->y;
  446. }
  447.  
  448. /**********************************************************************
  449. * Return the width of the sprite
  450. **********************************************************************/
  451. WORD spr_get_width(SPRITE spr)
  452. {
  453.     return spr->w*8;
  454. }
  455.  
  456. /**********************************************************************
  457. * Return the height of the sprite
  458. **********************************************************************/
  459. WORD spr_get_height(SPRITE spr)
  460. {
  461.     return spr->hp;
  462. }
  463.