home *** CD-ROM | disk | FTP | other *** search
/ Multimedia Jumpstart / Multimedia Microsoft Jumpstart Version 1.1a (Microsoft).BIN / develpmt / source / sprites / sprite.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-04-01  |  8.9 KB  |  425 lines

  1. /*
  2.     sprite.c
  3.  
  4.     Sprite specific routines
  5.  
  6. */
  7.  
  8. #include "global.h"
  9.  
  10. //
  11. // local data
  12. //
  13.  
  14. PSPRITE pDlgSprite;
  15.  
  16.  
  17. //
  18. // Load a sprite
  19. // If no path is given, show a dialog to allow selection of the DIB
  20. //
  21.  
  22. PSPRITE LoadSprite(LPSTR pszPath, BOOL bRedraw)
  23. {
  24.     PSPRITE pSprite;
  25.     RECT rc;
  26.  
  27.     dprintf2("LoadSprite()");
  28.  
  29.     //
  30.     // Allocate memory for the SPRITE info
  31.     //
  32.  
  33.     pSprite = (PSPRITE) ALLOCATE(sizeof(SPRITE));
  34.     if (!pSprite) {
  35.         dprintf1("No memory for sprite");
  36.         return NULL;
  37.     }
  38.  
  39.     //
  40.     // Load the DIB image
  41.     //
  42.  
  43.     pSprite->pDIB = LoadDIB(pszPath);
  44.     if (!pSprite->pDIB) {
  45.         goto $abort;
  46.     }
  47.  
  48.     pSprite->width = (int) DIB_WIDTH(pSprite->pDIB);
  49.     pSprite->height = (int) DIB_HEIGHT(pSprite->pDIB);
  50.     pSprite->x = 0;
  51.     pSprite->y = 0;
  52.     pSprite->z = 0;
  53.     pSprite->vx = 0;
  54.     pSprite->vy = 0;
  55.     pSprite->bSelectable = TRUE;
  56.     pSprite->pNext = NULL;
  57.     pSprite->pPrev = NULL;
  58.     dprintf4("Sprite is %u by %u", pSprite->width, pSprite->height);
  59.  
  60.     //
  61.     // Map the color table so that it matches the one in the
  62.     // background DIB
  63.     //
  64.  
  65.     ASSERT(pdibBkGnd);
  66.     MapDIBColorTable(pSprite->pDIB, pdibBkGnd);
  67.  
  68.     //
  69.     // get the index and color of the top left pixel
  70.     //
  71.  
  72.     pSprite->bTopLeft = GetDIBPixelValue(pSprite->pDIB, 0, 0);
  73.     pSprite->rgbTopLeft = GetDIBPixelColor(pSprite->pDIB, 0, 0);
  74.     dprintf4("Sprite top left: %2.2XH, %8.8lXH", 
  75.              pSprite->bTopLeft,
  76.              pSprite->rgbTopLeft);
  77.  
  78.     //
  79.     // Add it to the sprite list
  80.     //
  81.  
  82.     if (pSpriteList) {
  83.         pSpriteList->pPrev = pSprite;
  84.         pSprite->pNext = pSpriteList;
  85.     }
  86.     pSpriteList = pSprite;
  87.  
  88.     //
  89.     // Set the zorder somewhere in the middle
  90.     //
  91.  
  92.     SetSpriteZOrder(pSprite, 50, NO_UPDATE);
  93.  
  94.     //
  95.     // Redraw the sprite set
  96.     //
  97.  
  98.     if (bRedraw != NO_UPDATE) {
  99.         GetSpriteRect(pSprite, &rc);
  100.         Redraw(&rc, UPDATE_SCREEN);
  101.     }
  102.  
  103.     return pSprite;
  104.  
  105. $abort:
  106.     if (pSprite) FREE(pSprite);
  107.  
  108.  
  109.     return NULL;
  110. }
  111.  
  112. //
  113. // Delete a sprite
  114. //
  115.  
  116. void DeleteSprite(PSPRITE pSprite)
  117. {
  118.     PSPRITE pPrev, pNext;
  119.  
  120.     pPrev = pSprite->pPrev;
  121.     pNext = pSprite->pNext;
  122.  
  123.     DeleteDIB(pSprite->pDIB);
  124.  
  125.     if (pPrev) {
  126.         pPrev->pNext = pNext;
  127.     } else {
  128.         pSpriteList = pNext;
  129.     }
  130.     if (pNext) {
  131.         pNext->pPrev = pPrev;
  132.     }
  133.  
  134. }
  135.  
  136. //
  137. // Delete the current set of sprites
  138. //
  139.  
  140. void DeleteSpriteList()
  141. {
  142.     PSPRITE pSprite, pNext;
  143.  
  144.     pSprite = pSpriteList;
  145.     while (pSprite) {
  146.         pNext = pSprite->pNext;
  147.         DeleteSprite(pSprite);
  148.         pSprite = pNext;
  149.     }
  150.     pSpriteList = NULL;
  151. }
  152.  
  153. //
  154. // Test for a mouse hit in a non-transparent bit of a sprite.
  155. //
  156.  
  157. PSPRITE SpriteHitTest(int x, int y)
  158. {
  159.     PSPRITE pSprite;
  160.     int dx, dy;
  161.  
  162.     pSprite = pSpriteList;
  163.     while (pSprite) {
  164.  
  165.         //
  166.         // Test if the click is inside the sprite rectangle
  167.         //
  168.     
  169.         if ((x > pSprite->x) 
  170.         && (x < pSprite->x + (int) pSprite->width)
  171.         && (y > pSprite->y)
  172.         && (y < pSprite->y + (int) pSprite->height)) {
  173.     
  174.             dprintf4("Hit is in sprite rect");
  175.     
  176.             //
  177.             // See if this point is transparent by testing to
  178.             // see if the pixel value is the same as the top
  179.             // left corner value.  Note that top left of the
  180.             // image is bottom left in the DIB.
  181.             //
  182.     
  183.             dx = x - pSprite->x;
  184.             dy = y - pSprite->y;
  185.     
  186.             if (GetDIBPixelValue(pSprite->pDIB, dx, dy) 
  187.                != pSprite->bTopLeft) {
  188.                 break;
  189.             }
  190.         }
  191.  
  192.         pSprite = pSprite->pNext;
  193.     }
  194.  
  195.     return pSprite;
  196. }
  197.  
  198. //
  199. // get the enclosing rectangle for a sprite
  200. //
  201.  
  202. void GetSpriteRect(PSPRITE pSprite, LPRECT prcSprite)
  203. {
  204.     prcSprite->left = pSprite->x;
  205.     prcSprite->right = pSprite->x + pSprite->width;
  206.     prcSprite->top = pSprite->y;
  207.     prcSprite->bottom = pSprite->y + pSprite->height;
  208. }
  209.  
  210.  
  211. //
  212. // Set a new position for a sprite
  213. //
  214.  
  215. void SetSpritePosition(PSPRITE pSprite, int x, int y, BOOL bUpdate)
  216. {
  217.     RECT rcOld, rcNew, rcChange;
  218.  
  219.  
  220.     dprintf4("SetSpritePosition(%u,%u)", x, y);
  221.  
  222.     ASSERT(pSprite);
  223.  
  224.     //
  225.     // Get the current sprite position
  226.     //
  227.  
  228.     GetSpriteRect(pSprite, &rcOld);
  229.  
  230.     //
  231.     // Update the position and get the new rectangle
  232.     //
  233.  
  234.     pSprite->x = x;
  235.     pSprite->y = y;
  236.     GetSpriteRect(pSprite, &rcNew);
  237.  
  238.     //
  239.     // Update the change rectangle to include the old and the new
  240.     // positions of the sprite
  241.     //
  242.  
  243.     CopyRect(&rcChange, &rcOld);
  244.     UnionRect(&rcChange, &rcChange, &rcNew);
  245.  
  246.     //
  247.     // Redraw the changes if required
  248.     //
  249.  
  250.     if (bUpdate != NO_UPDATE) {
  251.         Redraw(&rcChange, bUpdate);
  252.     }
  253. }
  254.  
  255. //
  256. // Set a new z position for a sprite
  257. //
  258.  
  259. void SetSpriteZOrder(PSPRITE pSprite, WORD z, BOOL bUpdate)
  260. {
  261.     RECT rcChange;
  262.     PSPRITE pNew, pLast;
  263.  
  264.     dprintf4("SetSpriteZOrder(%u)", z);
  265.  
  266.     ASSERT(pSprite);
  267.     ASSERT(pSpriteList);
  268.  
  269.     pSprite->z = z;
  270.  
  271.     //
  272.     // Get the current sprite position
  273.     //
  274.  
  275.     GetSpriteRect(pSprite, &rcChange);
  276.  
  277.     //
  278.     // Unlink the sprite from the list
  279.     //
  280.  
  281.     if (pSprite->pPrev) {
  282.         pSprite->pPrev->pNext = pSprite->pNext;
  283.     } else {
  284.         pSpriteList = pSprite->pNext;
  285.     }
  286.     if (pSprite->pNext) {
  287.         pSprite->pNext->pPrev = pSprite->pPrev;
  288.     }
  289.     pSprite->pNext = pSprite->pPrev = NULL;
  290.  
  291.     //
  292.     // Walk down the list (from the top (front) until we find
  293.     // a sprite with higher z order or the end of the list
  294.     //
  295.  
  296.     pNew = pLast = pSpriteList;
  297.     while (pNew) {
  298.         if (pNew->z > pSprite->z) break;
  299.         pLast = pNew;
  300.         pNew = pNew->pNext;
  301.     }
  302.  
  303.     if (!pNew) {
  304.  
  305.         //
  306.         // There is no sprite further back than this so put
  307.         // this one on the end
  308.         //
  309.  
  310.         if (pLast) {
  311.             pLast->pNext = pSprite;
  312.         } else {
  313.             pSpriteList = pSprite;
  314.         }
  315.         pSprite->pPrev = pLast;
  316.  
  317.     } else {
  318.  
  319.         //
  320.         // pNew points the the one we want after this one
  321.         // so insert the new sprite before it
  322.         //
  323.  
  324.         if (pNew->pPrev) {
  325.             pSprite->pNext = pNew;
  326.             pSprite->pPrev = pNew->pPrev;
  327.             pNew->pPrev->pNext = pSprite;
  328.             pNew->pPrev = pSprite;
  329.         } else {
  330.             pSprite->pNext = pNew;
  331.             pSpriteList = pSprite;
  332.             pNew->pPrev = pSprite;
  333.         }
  334.  
  335.     }
  336.  
  337.     //
  338.     // Redraw the changes if required
  339.     //
  340.  
  341.     if (bUpdate != NO_UPDATE) {
  342.         Redraw(&rcChange, bUpdate);
  343.     }
  344. }
  345.  
  346. //
  347. // Sprite dialog procedure
  348. //
  349.  
  350. int CALLBACK SpriteDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
  351. {
  352.     switch (msg) {
  353.     case WM_INITDIALOG:
  354.         SetDlgItemInt(hDlg, IDDS_X, pDlgSprite->x, TRUE);
  355.         SetDlgItemInt(hDlg, IDDS_Y, pDlgSprite->y, TRUE);
  356.         SetDlgItemInt(hDlg, IDDS_W, pDlgSprite->width, TRUE);
  357.         SetDlgItemInt(hDlg, IDDS_H, pDlgSprite->height, TRUE);
  358.         SetDlgItemInt(hDlg, IDDS_VX, pDlgSprite->vx, TRUE);
  359.         SetDlgItemInt(hDlg, IDDS_VY, pDlgSprite->vy, TRUE);
  360.         SetDlgItemInt(hDlg, IDDS_Z, pDlgSprite->z, TRUE);
  361.         CheckDlgButton(hDlg, IDDS_SEL, pDlgSprite->bSelectable);
  362.         break;
  363.  
  364.     case WM_COMMAND:
  365.         switch (wParam) {
  366.         case IDOK:
  367.             SetSpritePosition(pDlgSprite,
  368.                               GetDlgItemInt(hDlg, IDDS_X, NULL, TRUE),
  369.                               GetDlgItemInt(hDlg, IDDS_Y, NULL, TRUE),
  370.                               NO_UPDATE);
  371.             pDlgSprite->vx = GetDlgItemInt(hDlg, IDDS_VX, NULL, TRUE);
  372.             pDlgSprite->vy = GetDlgItemInt(hDlg, IDDS_VY, NULL, TRUE);
  373.             SetSpriteZOrder(pDlgSprite, 
  374.                             GetDlgItemInt(hDlg, IDDS_Z, NULL, TRUE),
  375.                             NO_UPDATE);
  376.             pDlgSprite->bSelectable = IsDlgButtonChecked(hDlg, IDDS_SEL);
  377.             Redraw(NULL, UPDATE_SCREEN);
  378.             EndDialog(hDlg, TRUE);
  379.             break;
  380.  
  381.         case IDCANCEL:
  382.             EndDialog(hDlg, FALSE);
  383.             break;
  384.  
  385.         default:
  386.             break;
  387.         }
  388.         break;
  389.  
  390.     default:
  391.         return FALSE; // say we didn't handle it
  392.         break;
  393.     }
  394.  
  395.     return TRUE; // say we handled it
  396. }
  397.  
  398. //
  399. // Show the sprite dialog box
  400. //
  401.  
  402. void SpriteDialog(PSPRITE pSprite)
  403. {
  404.     FARPROC fpDlg;
  405.  
  406.     pDlgSprite = pSprite;
  407.     fpDlg = MakeProcInstance((FARPROC)SpriteDlgProc, hAppInstance);
  408.     DialogBox(hAppInstance, 
  409.               MAKEINTRESOURCE(IDD_SPRITE), 
  410.               hwndMain,
  411.               (DLGPROC)fpDlg);
  412.     FreeProcInstance(fpDlg);
  413. }
  414.  
  415. //
  416. // Test is a sprite is selectable
  417. //
  418.  
  419. BOOL IsSpriteSelectable(PSPRITE pSprite)
  420. {
  421.     return pSprite->bSelectable;
  422. }
  423.  
  424.  
  425.