home *** CD-ROM | disk | FTP | other *** search
/ The CDPD Public Domain Collection for CDTV 3 / CDPDIII.bin / bbs / ff887.lha / NBuff / NBuff.c next >
C/C++ Source or Header  |  1993-07-16  |  16KB  |  385 lines

  1. /*==========================================================================
  2. NBUFF.C
  3. Three helpful routines to allow double-buffering of views, using an
  4. Intuition window as one of the buffers.  Triple-buffering, N-buffering
  5. (subject to memory limitations), is also supported.  Compiler defines can be
  6. used to make use of the layers library and also to bypass the "Intuition-
  7. friendly" method of switching displays. 
  8.  
  9. Version:          2.2
  10.  
  11. Author:           Alex Matulich
  12. Copyright 1992 by Unicorn Research Corporation
  13.                   4621 N. Landmark Drive
  14.                   Orlando, FL, 32817-1235
  15.                   (407) 657-4974
  16. Email:            Internet: alex@bilver.oau.org
  17.                             alex%bilver@peora.sdc.ccur.com
  18.                   UUCP:     alex@bilver.uucp
  19.                   Fido:     1:363/140 username "Alex Matulich"
  20.  
  21. ============================================================================
  22.  
  23. This program is not in the public domain, but it may be freely copied
  24. and distributed for no charge providing this header is included.
  25. Legal disclaimer:  Use this code at your own risk!
  26.  
  27. NBuff.c compiles with no warnings nor errors using SAS Amiga C 5.10b, or
  28. SAS Amiga C 6.2.
  29.  
  30. You may pass the following optional definitions to the compiler:
  31.  
  32.    FASTNBUFF -    Directly manipulate copper to switch views.  This is very
  33.                fast, but Intuition doesn't like it.  If the user presses
  34.                left-Amiga-M or -N during FASTNBUFF buffering, the computer
  35.                can crash; otherwise this mode causes absolutely no problems.
  36.                   If FASTNBUFF is not defined, the Intuition-friendlier
  37.                RethinkDisplay() will be used to switch views.
  38.  
  39.    NOLAYERS  -    Disable the layers library, use the basic RastPorts.  No
  40.                clipping will be done in your views, and you have to be sure
  41.                that anything you render will stay within the RastPort
  42.                bounds, or the computer WILL crash.
  43.                   If NOLAYERS is *not* defined, then each view buffer is
  44.                associated with a simple-refresh backdrop layer.  This will
  45.                provide your RastPorts with automatic clipping (and prevent
  46.                crashes) when you draw outside the bitmap boundaries.  You
  47.                must open layers.library as LayersBase before calling
  48.                InitNBuff(), if you don't define NOLAYERS.
  49.  
  50. ACKNOWLEGEMENTS:  This code is a completely rewritten version of DBuff.c
  51. by Andrew C. R. Martin of SciTech Software in Europe.  The separate Demo
  52. program is only slightly modified from Mr. Martin's original version.
  53. DBuff had some problems which prompted me to write this (see the revision
  54. history below).
  55.  
  56. ============================================================================
  57.  
  58. Description:
  59. ------------
  60.    These routines set up, manipulate, and tidy up for N-buffered
  61.    animation using an Intuition Screen and Window
  62.  
  63. Usage:
  64. ------
  65.    3 simple routines are supplied:
  66.  
  67. >  RastPort = (struct RastPort *)InitNBuff(Screen,depth,Window,n)
  68.    --------------------------------------------------------------
  69.    Given the Screen and Window, this routine returns a pointer to RastPort n.
  70.    n=0 indicates the window's RastPort, and the Intuition copper lists will
  71.    be initialized, but no rastport will be allocated.  A pointer to the
  72.    Window RastPort is returned.  The first time this function is called
  73.    (after screen and window are created), n should be zero.  For n>0, a new
  74.    RastPort and BitMaps (or Layers), and copper lists will be allocated and
  75.    initialized, and a pointer to the new RastPort returned.  GfxBase must
  76.    be initialized before calling this function.
  77.  
  78. >  ShowView(n)
  79.    -----------
  80.    Sets the required view ready for drawing. ShowView(0) shows the Intuition
  81.    view, ShowView(n) sets alternate view n.  N-buffering is accomplished by
  82.    drawing to one of your background RastPorts and then displaying it with
  83.    ShowView().
  84.  
  85. >  FreeNBuff(screen,depth,rastport,n)
  86.    ----------------------------------
  87.    Frees up all memory associated with buffer n.  Iif n==0, only the
  88.    intermediate copperlists are freed, and nothing else.  The 0 buffer
  89.    buffer belongs to Intuition, and Intuition will free it with
  90.    CloseWindow() and CloseScreen().
  91.  
  92. Two additional internal functions are supplied which you may find useful:
  93.  
  94. >  getBitMap(width,height,depth,clear)
  95.    -----------------------------------
  96.    Allocates a bitmap, optionally clears it, and returns a pointer to it,
  97.    or NULL if the allocation failed.
  98.  
  99. >  freeBitMap(BitMap)
  100.    ------------
  101.    Frees a bitmap.  A NULL pointer may be passed.
  102.  
  103. Notes:
  104. ------
  105.    1. Assumes both graphics and intuition libraries are already open.
  106.    2. Assumes the layers library is open if NOLAYERS was not defined
  107.       at compile time.
  108.    3. Preferably, the window should be BORDERLESS and have a null title.
  109.    4. Link with NBuffDemo to see the demonstration.  You can do this with
  110.       SAS Amiga C 5.10b with the following command:
  111.       lc -L NBuffDemo NBuff
  112.       or with SAS Amiga C 6.2:
  113.       sc link NBuffDemo NBuff
  114.  
  115. ============================================================================
  116.  
  117. Revision history:
  118. -----------------
  119.    1.0 - DBuff - Original inspiration from Andrew C. R. Martin of SciTech
  120.          Software.  It did not actually switch views unless you used the
  121.          debugger (easy to check by clearing one RastPort to another color
  122.          in the Demo and watching what happens).  Compiled w/many warnings
  123.          using SAS Amiga C 5.10b, MrgCop() was being used improperly, only
  124.          one set of copper lists were being initialized although 3 were
  125.          declared, intermediate copperlists were not being freed, etc.
  126.          This program was a great teacher for me.
  127.    2.0 - Separated demo-related things from the actual buffer handling.
  128.          Completely re-wrote DBuff handling functions (reduced necessary
  129.          functions to 3).
  130.    2.1 - Modified software to handle any number of buffers (I needed to do
  131.          quadruple buffering in an application).  Renamed to NBuff.
  132.    2.11- Fixed bug that ate up a few hundred bytes more memory each time
  133.          the program terminated (only the hardware copper lists were being
  134.          freed, and not the intermediate ones).
  135.    2.12- Improved on, but not fixed, a bug that resulted in a corrupt
  136.          memory list lockup if the user used left-Amiga-M or left-Amiga-N
  137.          to toggle the Workbench screen in and out while the program runs.
  138.    2.13- Fixed the bug above by using the Intuition-friendly-but-slow
  139.          RethinkDisplay() to switch views.  Introduced the FASTNBUFF
  140.          compiler definition to retain the old faster method of 2.12.
  141.    2.2 - Added layers library support so that anything rendered to the
  142.          video buffers will be clipped automatically, preventing potential
  143.          catastrophic crashes.  Introduced the NOLAYERS compiler definition
  144.          to do things the old way, which conserves some memory.
  145.  
  146. ===========================================================================*/
  147.  
  148. #define NBUFF_C
  149. #include "NBuff.h"
  150.  
  151.  
  152. //==========================================================================
  153. // Global Amiga system variables
  154. // Note: The constant NBUFS is typically 2, for double buffering.
  155. //       This constant is set in NBuff.h.  Hardly any extra memory is
  156. //       needed if NBUFS is larger than 2 - memory is only used according
  157. //       to the number of times you call InitNBuff().
  158. //==========================================================================
  159.  
  160. #ifdef FASTNBUFF
  161. struct cprlist    *NB_LOF[NBUFS],         // copperlist ptrs in View struct
  162.                   *NB_SHF[NBUFS];
  163. #endif
  164.  
  165. struct Screen     *NB_screen;
  166. struct RasInfo    *NB_rinfo = NULL;       // Intuition supplied rasinfo
  167. struct BitMap     *NB_bmap[NBUFS];        // Bitmaps (0 is Intuition-supplied)
  168. struct View       *NB_view = NULL;        // Intuition View
  169. struct ViewPort   *NB_vp = NULL;          // Intuition ViewPort
  170.  
  171. #ifndef NOLAYERS
  172. struct Layer_Info *NB_layerinfo[NBUFS];   // Layer description
  173. struct Layer      *NB_layer[NBUFS];       // layer array
  174. #endif
  175.  
  176. extern struct GfxBase *GfxBase;
  177.  
  178.  
  179. //==========================================================================
  180. // INITNBUFF
  181. // Initialize a new buffer, and return a pointer to the new RastPort.
  182. // n may range from 0 to NBUFS-1.  Call this function for each buffer you
  183. // have, including your Intuition window.  This function assumes that a
  184. // screen of DEPTH bitplanes is already opened, and a window is on it.
  185. // n should be 0 the first time you call this function.
  186. //==========================================================================
  187. struct RastPort *InitNBuff(struct Screen *screen,
  188.           short depth, struct Window *window, short n)
  189. {
  190. struct RastPort *rport = NULL;  // RastPort pointer to return
  191. short err = 0;
  192.  
  193. if (!n) {  // If Intuition buffer data is not yet initialized...
  194.    rport = window->RPort;
  195.    NB_bmap[0] = rport->BitMap;
  196.    NB_screen = screen;
  197.    NB_view = GfxBase->ActiView;
  198.    NB_vp = &screen->ViewPort;
  199.    NB_rinfo = NB_vp->RasInfo;
  200.    // --> the line above also makes NB_rinfo->BitMap == rport->Bitmap <--
  201.    MakeScreen(screen);   // Intuition-integrated MakeVPort() for copperlists
  202.    RethinkDisplay();
  203. #ifdef FASTNBUFF
  204.    NB_LOF[0] = NB_view->LOFCprList;  // save Intuition lo-res copper list
  205.    NB_SHF[0] = NB_view->SHFCprList;  // save Intuition hi-res copper list
  206. #endif
  207.    return rport;
  208.    }
  209.  
  210. // ...otherwise, allocate another bitmap & memory for bitplanes
  211.  
  212. #ifndef NOLAYERS
  213. if (!(NB_layerinfo[n] = NewLayerInfo())) return NULL;
  214. #endif
  215.  
  216. if (!(NB_bmap[n] = getBitMap(screen->Width, screen->Height, depth, 1)))
  217.    goto NBInit_done;
  218.  
  219. // Create a rastport or layer for this bitmap to simplify drawing
  220.  
  221. #ifdef NOLAYERS
  222. if (!(rport = (struct RastPort *)
  223.          AllocMem(sizeof(struct RastPort), MEMF_PUBLIC))) {
  224.    err = 3;
  225.    goto NBInit_done;
  226.    }
  227. InitRastPort(rport);
  228. rport->BitMap = NB_bmap[n];
  229.  
  230. #else   // if we're using the Layers library...
  231.  
  232. if (!(NB_layer[n] = CreateBehindLayer(NB_layerinfo[n], NB_bmap[n],
  233.                       0L, 0L, screen->Width-1, screen->Height-1,
  234.                       LAYERSIMPLE | LAYERBACKDROP, NULL))) {
  235.    err = 4;
  236.    goto NBInit_done;
  237.    }
  238. rport = NB_layer[n]->rp;
  239. #endif
  240.  
  241. SetRast(rport, 0);   // clear this view
  242.  
  243. // set up for N-buffering (initialize copperlists) - FASTNBUFF only
  244.  
  245. #ifdef FASTNBUFF  // the rest is needed if we're Intuition-UNfriendly...
  246. NB_LOF[n] = NB_view->LOFCprList = NULL;  // reset view copperlists to NULL
  247. NB_SHF[n] = NB_view->SHFCprList = NULL;
  248.  
  249. NB_rinfo->BitMap = NB_bmap[n];           // set new bitmap to display
  250. MakeVPort(NB_view, NB_vp);               // build intermediate copper lists
  251. MrgCop(NB_view);                         // build final copper lists
  252. LoadView(NB_view);                       // execute the coppper instructions
  253.                                          // at next VBeam blank inerval
  254. NB_LOF[n] = NB_view->LOFCprList;   // now save new copper lists for new view
  255. NB_SHF[n] = NB_view->SHFCprList;
  256.  
  257. // ...and that's it!  We now have all we need to switch views: a set of
  258. // copper lists NB_LOF[] and NB_SHF[], and a bitmap pointer NB_rinfo->BitMap!
  259.  
  260. NB_rinfo->BitMap = NB_bmap[0];  // restore Intuition BitMap
  261. ShowView(0);                    // show the Intuition RastPort
  262. #endif
  263.  
  264. NBInit_done:
  265. if (err) FreeNBuff(screen, depth, rport, n);
  266. return rport;
  267. }
  268.  
  269.  
  270. //=========================================================================
  271. // GETBITMAP
  272. // Allocate a bitmap according to the dimensions provided, clear it if
  273. // clear is nonzero, and return a pointer to the bitmap.  NULL is returned
  274. // if the bitmap couldn't be created.
  275. //=========================================================================
  276. struct BitMap *getBitMap(int wide, int high, int deep, short clear)
  277. {
  278. register short i;
  279. struct BitMap *bitmap;
  280. if (!(bitmap = (struct BitMap *)
  281.                AllocMem(sizeof(struct BitMap), MEMF_PUBLIC|MEMF_CLEAR)))
  282.    goto bitmaperr;
  283. InitBitMap(bitmap, deep, wide, high);
  284. for (i = 0; i < deep; i++) {
  285.    if (!(bitmap->Planes[i] = (PLANEPTR)AllocRaster(wide, high)))
  286.       goto bitmaperr;
  287.    if (clear) BltClear(bitmap->Planes[i], RASSIZE(wide, high), 0);
  288.    }
  289. return bitmap;
  290.  
  291. bitmaperr:
  292. freeBitMap(bitmap);
  293. return NULL;
  294. }
  295.  
  296.  
  297. //==========================================================================
  298. // FREEBITMAP
  299. // Deallocate a bitmap structure, with all its bitplanes.
  300. //==========================================================================
  301. void freeBitMap(struct BitMap *bm)
  302. {
  303. short j;
  304. if (bm) {
  305.    for (j = 0; j < bm->Depth; j++)
  306.       if (bm->Planes[j])
  307.          FreeRaster(bm->Planes[j], bm->BytesPerRow << 3, bm->Rows);
  308.    FreeMem(bm, sizeof(struct BitMap));
  309.    }
  310. }
  311.  
  312.  
  313. //==========================================================================
  314. // ShowView
  315. // Program the copper with the appropriate lists, set the bitmap pointer to
  316. // buffer n, and display the new view.  The new view will be displayed
  317. // during the next CRT vertical blanking interval.
  318. // NOTE:  When debugging, the view will switch when the new bitmap is set,
  319. // and not when LoadView() is called.  Don't be fooled into thinking that
  320. // this means you don't need LoadView()!  If you remove the LoadView() call,
  321. // the view will NOT switch when run without the debugger.
  322. //==========================================================================
  323. void ShowView(register short n)
  324. {
  325. #ifdef FASTNBUFF
  326.  
  327. NB_view->LOFCprList = NB_LOF[n];  // set lo-res copper list
  328. NB_view->SHFCprList = NB_SHF[n];  // set hi-res copper list
  329. // you may want to call to WaitTOF() here to sync with the CRT vblank.
  330. LoadView(NB_view);                // cause copper to show new view
  331.  
  332. #else   // if not using FASTNBUFF, then be slow but Intuition-friendly
  333.  
  334. NB_screen->RastPort.BitMap = NB_rinfo->BitMap = NB_bmap[n];
  335. MakeScreen(NB_screen);
  336. RethinkDisplay();  // automatically calls WaitTOF()
  337.  
  338. #endif
  339. }
  340.  
  341.  
  342. //==========================================================================
  343. // FREENBUFF
  344. // Free everything associated with a display buffer.
  345. // This function will ignore a call to free buffer 0, because buffer 0 and
  346. // its associated structures all belong to Intuition, which will take care
  347. // of everything when the screen and window are finally closed.  You SHOULD
  348. // call this routine to free buffer 0 so that the intermediate copperlists
  349. // will be freed, escpecially if you defined FASTNBUFF!
  350. // The value n MUST be associated with the correct RastPort rp!!
  351. //==========================================================================
  352. void FreeNBuff(struct Screen *screen, short depth, struct RastPort *rp, short n)
  353. {
  354. if (!n) {
  355.    // Deallocate all intermediate copper lists for this viewport.
  356.    // This may not be necessary if FASTNBUFF was not specified, but it
  357.    // doesn't hurt to do it anyway.
  358.    // NOT calling FreeVPortCopLists() may result in a few hundred bytes of
  359.    // memory loss each time your program is run.
  360.    FreeVPortCopLists(NB_vp);
  361.    return;
  362.    }
  363.  
  364. // Ensure we're on the Intuition-supplied bitmap before exiting
  365. ShowView(0);
  366. WaitTOF();
  367.  
  368. // Free up the nth rastport or layer
  369. #ifdef NOLAYERS
  370. if (rp) FreeMem(rp, sizeof(struct RastPort));
  371. #else
  372. if (NB_layer[n]) DeleteLayer(0L, NB_layer[n]);
  373. if (NB_layerinfo[n]) DisposeLayerInfo(NB_layerinfo[n]);
  374. #endif
  375.  
  376. freeBitMap(NB_bmap[n]);  // Free up the nth bitmap
  377.  
  378. // Free up the copper lists - FASTNBUFF only
  379.  
  380. #ifdef FASTNBUFF
  381. FreeCprList(NB_LOF[n]);
  382. FreeCprList(NB_SHF[n]);
  383. #endif
  384. }
  385.