home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 January / macformat-020.iso / Shareware City / Developers / apps.to.go / Kibitz / Offscreen.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-01  |  11.9 KB  |  389 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** File:        offscreen.c
  5. ** Written by:  Eric Soldan
  6. **
  7. ** Copyright © 1991-1992 Apple Computer, Inc.
  8. ** All rights reserved. */
  9.  
  10.  
  11.  
  12. /*****************************************************************************/
  13.  
  14.  
  15.  
  16. #include "Kibitz.h"                /* Get the Kibitz includes/typedefs, etc.    */
  17. #include "KibitzCommon.h"        /* Get the stuff in common with rez.        */
  18. #include "Kibitz.protos"        /* Get the prototypes for Kibitz.            */
  19.  
  20. #ifndef __ERRORS__
  21. #include "Errors.h"
  22. #endif
  23.  
  24. #ifndef __GWLAYERS__
  25. #include <GWLayers.h>
  26. #endif
  27.  
  28. #ifndef __RESOURCES__
  29. #include <Resources.h>
  30. #endif
  31.  
  32. #ifndef __UTILITIES__
  33. #include <Utilities.h>
  34. #endif
  35.  
  36.  
  37.  
  38. static short        gDepth, gPiece;
  39. static CTabHandle    gCtab;
  40. static Rect            gPieceRect;
  41. static RgnHandle    gColorRgn, gTestRgn;
  42.  
  43.  
  44.  
  45. /*****************************************************************************/
  46.  
  47.  
  48.  
  49. LayerObj            gBoardLayer;
  50. short                gClearSquare;
  51. extern CIconHandle    gPieceCIcon[26];
  52.  
  53. static OSErr    PieceLayerProc(LayerObj theLayer, short message);
  54. static OSErr    BoardLayerProc(LayerObj theLayer, short message);
  55. static void        PlotWithShadow(short x, short y);
  56.  
  57.  
  58.  
  59. /*****************************************************************************/
  60.  
  61.  
  62.  
  63. #pragma segment Config
  64. OSErr    InitOffscreen(void)
  65. {
  66.     RgnHandle    colorRgn;
  67.     short        depth;
  68.     OSErr        err;
  69.  
  70.     gClearSquare = 0;        /* Regular board imaging as default. */
  71.  
  72.     colorRgn = ScreenDepthRegion(8);
  73.     depth = (EmptyRgn(colorRgn)) ? 1 : 8;
  74.     DisposeRgn(colorRgn);
  75.  
  76.     err = NewLayer(&gBoardLayer, nil, BoardLayerProc, nil, depth, 0);
  77.         /* We create boardLayer at initialization time.  This layer will be
  78.         ** used to image the board off-screen.  Note that the layer has its own
  79.         ** layerProc.  The kLayerInit action doesn't call the default layerInit.
  80.         ** This custom layerProc uses just the size of the above GWorld to
  81.         ** determine the size of the bitmap it creates, so this layer isn't
  82.         ** necessarily the same depth as the above layer.  If there is no above
  83.         ** layer, then this custom layerProc needs to return paramErr for the
  84.         ** kLayerInit message, just as the default LayerProc does. */
  85.  
  86.     return(err);
  87. }
  88.  
  89.  
  90.  
  91. /*****************************************************************************/
  92.  
  93.  
  94.  
  95. #pragma segment Config
  96. void    MoveThePiece(FileRecHndl frHndl, short fromSq, Rect fromRect, Point fromLoc, Point *toLoc)
  97. {
  98.     WindowPtr        window, keepPort;
  99.     LayerObj        windowLayer, pieceLayer;
  100.     short            dx, dy, adx, ady, ticksForMove, tickDiff, update;
  101.     unsigned long    startTick;
  102.     Point            lastLoc, mouseLoc, pt;
  103.  
  104.     lastLoc.h = lastLoc.v = 0x4000;
  105.         /* Make sure that the first position gets updated.  We want a last mouse
  106.         ** location that is different than whatever the user would have clicked. */
  107.  
  108.     keepPort = SetFilePort(frHndl);
  109.     GetPort(&window);
  110.  
  111.     ImageDocument(frHndl, true);
  112.  
  113.     NewLayer(&windowLayer, nil, nil, window, 8, 0);
  114.         /* Create the layer object related to the window.  If NewLayer fails,
  115.         ** windowLayer is set to nil. */
  116.     (*windowLayer)->dstRect = BoardRect();
  117.         /* pieceLayer isn't the same size as the window's portRect.  By setting
  118.         ** windowLayer's dstRect, we change the area that the two layers map
  119.         ** to.  dstRect is set nil by NewLayer, and if it is left nil, then
  120.         ** the portRect is used for mapping.  Since we only want to map into
  121.         ** the window for the board, we set dstRect to just that portion of
  122.         ** the window. */
  123.     gClearSquare = fromSq;
  124.     gPiece       = (*frHndl)->doc.theBoard[fromSq];
  125.     if (gPiece < WK) gPiece += KSIDEPIECE;
  126.     if (gPiece > BK) gPiece -= KSIDEPIECE;
  127.     ImageDocument(frHndl, true);
  128.     gClearSquare = 0;
  129.  
  130.     gTestRgn  = NewRgn();
  131.     gColorRgn = ScreenDepthRegion(8);        /* Screen of 8-bit or greater get color icon. */
  132.     pt.h = pt.v = 0;
  133.     GlobalToLocal(&pt);
  134.     OffsetRgn(gColorRgn, pt.h, pt.v);        /* Localize the area that gets color icons. */
  135.  
  136.     NewLayer(&pieceLayer, windowLayer, PieceLayerProc, nil, 8, 0);
  137.         /* pieceLayer is created, and it maps to the board area of windowLayer.
  138.         ** Note that windowLayer is a parameter for pieceLayer.  If windowLayer
  139.         ** failed to get created, then this call will return a paramErr.  This
  140.         ** is because if you don't state a port, pixmap, or bitmap, the default
  141.         ** layerProc (which PieceLayerProc calls) uses the above layer to
  142.         ** determine the size and depth of an off-screen GWorld it automatically
  143.         ** creates.  If there is also no above layer, then there is nothing that
  144.         ** can be used as a basis for the GWorld, and that results in a paramErr. */
  145.  
  146.     InsertLayer(gBoardLayer, windowLayer, 2);
  147.         /* Connect board layer in as the background layer. */
  148.     InvalLayer(windowLayer, fromRect, false);
  149.         /* On first update, redraw square where piece was picked up. */
  150.  
  151.     if (toLoc->h != 0x4000) {        /* If we have a start and end point, slide the piece. */
  152.         startTick = TickCount();
  153.         dx = adx = toLoc->h - fromLoc.h;
  154.         if (adx < 0) adx = -adx;
  155.         dy = ady = toLoc->v - fromLoc.v;
  156.         if (ady < 0) ady = -ady;
  157.         ticksForMove = (adx + ady) / 3;
  158. #ifdef powerc
  159.         if (ticksForMove > 6)  ticksForMove = 6;    /* The piece slide will take at most half a second. */
  160. #else
  161.         if (ticksForMove > 30) ticksForMove = 30;    /* The piece slide will take at most half a second. */
  162. #endif
  163.     }
  164.  
  165.     for (;;) {
  166.         if (toLoc->h == 0x4000) {        /* If user grabbed the piece, get where the mouse is now. */
  167.             GetMouse(&mouseLoc);
  168.             update = UpdateTime(frHndl, true);
  169.             if (update) DrawTime(frHndl);
  170.             if (update == 2) {
  171.                 if ((*frHndl)->doc.twoPlayer) SendGame(frHndl, kIsMove, nil);
  172.                 AlertIfGameOver(frHndl);
  173.                 lastLoc.h = lastLoc.v = 0x4000;
  174.                 break;
  175.             }
  176.         }
  177.         else {
  178.             tickDiff = TickCount() - startTick;
  179.             if (tickDiff > ticksForMove) tickDiff = ticksForMove;
  180.             mouseLoc.h = fromLoc.h + dx * tickDiff / ticksForMove;
  181.             mouseLoc.v = fromLoc.v + dy * tickDiff / ticksForMove;
  182.                 /* If sliding piece, calculate the new position, based on time. */
  183.         }
  184.         if ((lastLoc.h != mouseLoc.h) || (lastLoc.v != mouseLoc.v)) {
  185.                 /* If new piece position is different than last... */
  186.             lastLoc = mouseLoc;
  187.             gPieceRect = fromRect;
  188.             gPieceRect.right  += 5;            /* Make space for the piece's shadow. */
  189.             gPieceRect.bottom += 5;
  190.             OffsetRect(&gPieceRect, mouseLoc.h - fromLoc.h - 2, mouseLoc.v - fromLoc.v - 2);
  191.                 /* Position the update rect at the new mouse location but offset 2
  192.                 ** up and 2 left.  This offset is so the piece looks like it is
  193.                 ** lifted from the board for the first update. */
  194.             InvalLayer(windowLayer, gPieceRect, true);    /* Mark the area to be updated. */
  195.             UpdateLayer(windowLayer);                    /* DO IT. */
  196.         }
  197.         if (toLoc->h == 0x4000) {        /* If under user control... */
  198.             if (!StillDown()) break;    /* Break if mouse is released. */
  199.         }
  200.         else if (tickDiff == ticksForMove) break;
  201.             /* If piece being slid, break when it gets there. */
  202.     }
  203.  
  204.     DetachLayer(gBoardLayer);
  205.         /* Keep this permanent layer from being disposed of. */
  206.     DisposeThisAndBelowLayers(windowLayer);
  207.         /* Dispose of the layers and associated data. */
  208.     DisposeRgn(gColorRgn);
  209.     DisposeRgn(gTestRgn);
  210.  
  211.     SetPort(keepPort);
  212.     *toLoc = lastLoc;        /* Return where the piece was dropped. */
  213. }
  214.  
  215.  
  216.  
  217. /*****************************************************************************/
  218.  
  219.  
  220.  
  221. #pragma segment Config
  222. static OSErr    PieceLayerProc(LayerObj theLayer, short message)
  223. {
  224.     OSErr    err;
  225.     GrafPtr    thisPort;
  226.  
  227.     err = noErr;
  228.     switch (message) {
  229.         case kLayerInit:
  230.             gCtab = nil;
  231.                 /* We will need a color table if the depth is greater than 1, and
  232.                 ** we succeed in creating the pixMap for the layer.  Assume that
  233.                 ** these conditions won't be met, and initialize the color table
  234.                 ** reference to nil. */
  235.             err = DefaultLayerProc(theLayer, kLayerInit);
  236.             if (!err) {
  237.                 thisPort = (*theLayer)->layerPort;
  238.                 gDepth = 1;
  239.                 if (thisPort->portBits.rowBytes & 0x8000)
  240.                     gDepth = (*(((CGrafPtr)thisPort)->portPixMap))->pixelSize;
  241.                 if (gDepth != 1) gCtab = GetCTable(64 + 8);
  242.                     /* We need a color table for the shadow if depth is greater than 1. */
  243.             }
  244.             break;
  245.         case kLayerDispose:
  246.             err = DefaultLayerProc(theLayer, kLayerDispose);
  247.                 /* Do the standard dispose behavior. */
  248.             if (gCtab) DisposeCTable(gCtab);
  249.                 /* Dispose of the color table for the piece shadow, if we have one. */
  250.             break;
  251.         case kLayerUpdate:
  252.             DefaultLayerProc(theLayer, kLayerUpdate);
  253.             SetLayerWorld(theLayer);
  254.             PlotWithShadow(gPieceRect.left, gPieceRect.top);
  255.                 /* Draw the piece and shadow into the piece layer in the new position. */
  256.             ResetLayerWorld(theLayer);
  257.             break;
  258.         default:
  259.             err = DefaultLayerProc(theLayer, message);
  260.                 /* For future messages, use the default behavior. */
  261.             break;
  262.     }
  263.  
  264.     return(err);
  265. }
  266.  
  267.  
  268.  
  269. /*****************************************************************************/
  270.  
  271.  
  272.  
  273. #pragma segment Config
  274. static OSErr    BoardLayerProc(LayerObj theLayer, short message)
  275. {
  276.     OSErr        err;
  277.     Rect        boardRect;
  278.     GWorldPtr    layerWorld;
  279.     CGrafPtr    keepPort;
  280.     GDHandle    keepGDevice;
  281.  
  282.     switch (message) {
  283.         case kLayerInit:
  284.             boardRect = BoardRect();
  285.             err = NewGWorld(&layerWorld, (*theLayer)->layerDepth, &boardRect, nil, nil, 0);
  286.             if (!err) {        /* If we succeeded at creating the GWorld... */
  287.                 (*theLayer)->layerOwnsPort = true;
  288.                 GetGWorld(&keepPort, &keepGDevice);        /* To get the GDevice. */
  289.                 (*theLayer)->layerPort    = (GrafPtr)layerWorld;
  290.                 (*theLayer)->layerGDevice = keepGDevice;
  291.                 SetLayerWorld(theLayer);
  292.                 SetOrigin(boardRect.left, boardRect.top);
  293.                 EraseRect(&boardRect);
  294.                     /* Pre-clear the bitmap before imaging into it. */
  295.                 ImageBoardLines(1, kBoardHOffset, kBoardVOffset);
  296.                     /* Pre-image the lines dividing the squares. */
  297.                 ResetLayerWorld(theLayer);
  298.             }
  299.             break;
  300.         default:
  301.             err = DefaultLayerProc(theLayer, message);
  302.                 /* Default behavior for everything else. */
  303.             break;
  304.     }
  305.  
  306.     return(err);
  307. }
  308.  
  309.  
  310.  
  311. /*****************************************************************************/
  312.  
  313.  
  314.  
  315. #pragma segment Config
  316. void    PlotWithShadow(short x, short y)
  317. {
  318.     GrafPtr        curPort;
  319.     Handle        shadowHndl;
  320.     short        pieceShadow;
  321.     ResType        iconType;
  322.     Rect        iconRect, destRect;
  323.     char        hstate;
  324.     PixMap        shadowPixMap;
  325.  
  326.     iconType = (gDepth == 1) ? 'ICON' : 'icl8';
  327.     if ((pieceShadow = gPiece) < 0) pieceShadow = -pieceShadow;
  328.     shadowHndl = GetResource(iconType, 400 + pieceShadow);
  329.     hstate = LockHandleHigh(shadowHndl);
  330.  
  331.     SetRect(&iconRect, 0, 0, 32, 32);
  332.     shadowPixMap.baseAddr   = *shadowHndl;
  333.     shadowPixMap.rowBytes   = (iconType == 'ICON') ? 4 : 0x8020;
  334.     shadowPixMap.bounds     = iconRect;
  335.     shadowPixMap.pmVersion  = 0;
  336.     shadowPixMap.packType   = 0;
  337.     shadowPixMap.packSize   = 0;
  338.     shadowPixMap.hRes       = 0x00480000;
  339.     shadowPixMap.vRes       = 0x00480000;
  340.     shadowPixMap.pixelType  = 0;
  341.     shadowPixMap.pixelSize  = 8;
  342.     shadowPixMap.cmpCount   = 1;
  343.     shadowPixMap.cmpSize    = 8;
  344.     shadowPixMap.planeBytes = 0;
  345.     shadowPixMap.pmTable    = gCtab;
  346.     shadowPixMap.pmReserved = 0;
  347.  
  348.     destRect.bottom = (destRect.top  = y + 5) + 32;
  349.     destRect.right  = (destRect.left = x + 5) + 32;
  350.         /* Add 5 to offset the shadow. */
  351.  
  352.     GetPort(&curPort);
  353.     CopyBits((BitMapPtr)&shadowPixMap, &(curPort->portBits), &iconRect, &destRect, srcOr, nil);
  354.     HSetState(shadowHndl, hstate);
  355.  
  356.     if (!gPieceCIcon[gPiece + KING])
  357.         gPieceCIcon[gPiece + KING] = ReadCIcon(gPiece + KING + 257);
  358.     if (!gPieceCIcon[gPiece + KING + 13])
  359.         gPieceCIcon[gPiece + KING + 13] = ReadCIcon(gPiece + KING + 13 + 257);
  360.  
  361.     OffsetRect(&destRect, -5, -5);
  362.         /* 5 was added for the shadow.  This undoes that. */
  363.  
  364.     if (!RectInRgn(&destRect, gColorRgn))        /* If 1-bit, draw b/w icon. */
  365.         DrawCIconByDepth(gPieceCIcon[gPiece + KING], destRect, 1, true);
  366.  
  367.     else {                                    /* Draw some combo of color and b/w icon. */
  368.         RectRgn(gTestRgn, &destRect);
  369.         SectRgn(gColorRgn, gTestRgn, gTestRgn);
  370.         if ((*gTestRgn)->rgnSize == 10) {
  371.             if (EqualRect(&((*gTestRgn)->rgnBBox), &destRect)) {        /* All color. */
  372.                 DrawCIconByDepth(gPieceCIcon[gPiece + KING + 13], destRect, 8, true);
  373.                 return;
  374.             }
  375.         }
  376.         SetClip(gTestRgn);
  377.         DrawCIconByDepth(gPieceCIcon[gPiece + KING + 13], destRect, 8, true);    /* Color part. */
  378.         RectRgn(gTestRgn, &destRect);
  379.         XorRgn(gColorRgn, gTestRgn, gTestRgn);
  380.         SetClip(gTestRgn);
  381.         DrawCIconByDepth(gPieceCIcon[gPiece + KING], destRect, 1, true);        /* b/w part. */
  382.         SetRectRgn(gTestRgn, -32000, -32000, 32000, 32000);
  383.         SetClip(gTestRgn);
  384.     }
  385. }
  386.  
  387.  
  388.  
  389.