1 // 2 // CardLib - CardRegion drawing support 3 // 4 // Freeware 5 // Copyright J Brown 2001 6 // 7 8 #include "cardlib.h" 9 10 HPALETTE UseNicePalette(HDC hdc, HPALETTE hPalette); 11 void PaintRect(HDC hdc, RECT *rect, COLORREF colour); 12 void CardBlt(HDC hdc, int x, int y, int nCardNum); 13 void DrawCard(HDC hdc, int x, int y, HDC hdcSource, int width, int height); 14 15 // 16 // Draw specified card at position x, y 17 // xoff - source offset from left of card 18 // yoff - source offset from top of card 19 // width - width to draw 20 // height - height to draw 21 // 22 void CardBlt(HDC hdc, int x, int y, int nCardNum)//, int xoff, int yoff, int width, int height) 23 { 24 int sx = nCardNum * __cardwidth; 25 int sy = 0; 26 int width = __cardwidth; 27 int height = __cardheight; 28 29 //draw main center band 30 BitBlt(hdc, x+2, y, width - 4, height, __hdcCardBitmaps, sx+2, sy+0, SRCCOPY); 31 32 //draw the two bits to the left 33 BitBlt(hdc, x, y+2, 1, height - 4, __hdcCardBitmaps, sx+0, sy+2, SRCCOPY); 34 BitBlt(hdc, x+1, y+1, 1, height - 2, __hdcCardBitmaps, sx+1, sy+1, SRCCOPY); 35 36 //draw the two bits to the right 37 BitBlt(hdc, x+width-2, y+1, 1, height - 2, __hdcCardBitmaps, sx+width-2, sy+1, SRCCOPY); 38 BitBlt(hdc, x+width-1, y+2, 1, height - 4, __hdcCardBitmaps, sx+width-1, sy+2, SRCCOPY); 39 } 40 41 // 42 // Draw a shape this this: 43 // 44 // ++++++++++++ 45 // ++++++++++++++ 46 // ++ ++ 47 // 48 void DrawHorzCardStrip(HDC hdc, int x, int y, int nCardNum, int height, BOOL fDrawTips) 49 { 50 int sx = nCardNum * __cardwidth; 51 int sy = 0; 52 int one = 1; 53 int two = 2; 54 BOOL tips = fDrawTips ? FALSE : TRUE; 55 56 if(height == 0) return; 57 58 if(height < 0) 59 { 60 sy = sy + __cardheight; 61 y -= height; 62 one = -one; 63 two = -two; 64 } 65 66 // draw the main vertical band 67 // 68 BitBlt(hdc, x + 2, y, __cardwidth - 4, height, __hdcCardBitmaps, sx+2, sy, SRCCOPY); 69 70 //if(height <= 1) return; 71 72 // draw the "lips" at the left and right 73 BitBlt(hdc, x+1, y+one, 1, height-one*tips, __hdcCardBitmaps, sx+1, sy+one, SRCCOPY); 74 BitBlt(hdc, x+__cardwidth-2, y+one, 1, height-one*tips, __hdcCardBitmaps, sx+__cardwidth-2, sy+one, SRCCOPY); 75 76 //if(height <= 2) return; 77 78 // draw the outer-most lips 79 BitBlt(hdc, x, y+two, 1, height-two*tips, __hdcCardBitmaps, sx, sy+two, SRCCOPY); 80 BitBlt(hdc, x+__cardwidth-1, y+two, 1, height-two*tips, __hdcCardBitmaps, sx+__cardwidth-1, sy+two, SRCCOPY); 81 } 82 83 // 84 // Draw a shape like this: 85 // 86 // +++ 87 // +++ 88 // +++ 89 // +++ 90 // +++ 91 // +++ 92 // +++ 93 // +++ 94 // +++ 95 // +++ 96 // 97 // 98 void DrawVertCardStrip(HDC hdc, int x, int y, int nCardNum, int width, BOOL fDrawTips) 99 { 100 int sx = nCardNum * __cardwidth; 101 int sy = 0; 102 int one = 1; 103 int two = 2; 104 BOOL tips = fDrawTips ? FALSE : TRUE; 105 106 if(width == 0) return; 107 108 109 if(width < 0) 110 { 111 sx = sx + __cardwidth; 112 x -= width; 113 one = -1; 114 two = -2; 115 } 116 117 // draw the main vertical band 118 // 119 BitBlt(hdc, x, y + 2, width, __cardheight - 4, __hdcCardBitmaps, sx, sy+2, SRCCOPY); 120 121 //if(width <= 1) return; 122 123 // draw the "lips" at the top and bottom 124 BitBlt(hdc, x+one, y+1, width-one*tips, 1, __hdcCardBitmaps, sx+one, sy + 1, SRCCOPY); 125 BitBlt(hdc, x+one, y+__cardheight-2, width-one*tips, 1, __hdcCardBitmaps, sx+one, sy + __cardheight-2, SRCCOPY); 126 127 //if(width <= 2) return; 128 129 // draw the outer-most lips 130 BitBlt(hdc, x+two, y, width-two*tips, 1, __hdcCardBitmaps, sx+two, sy, SRCCOPY); 131 BitBlt(hdc, x+two, y+__cardheight-1, width-two*tips, 1, __hdcCardBitmaps, sx+two, sy + __cardheight-1, SRCCOPY); 132 } 133 134 // 135 // xdir - <0 or >0 136 // ydir - <0 or >0 137 // 138 void DrawCardCorner(HDC hdc, int x, int y, int cardval, int xdir, int ydir) 139 { 140 int sx = cardval * __cardwidth; 141 int sy = 0; 142 143 HDC hdcSource = __hdcCardBitmaps; 144 145 if(xdir < 0) 146 { 147 x += __cardwidth + xdir - 1; 148 sx += __cardwidth + xdir - 1; 149 } 150 else 151 { 152 x += xdir; 153 sx += xdir; 154 } 155 156 if(ydir < 0) 157 { 158 y += __cardheight + ydir - 1; 159 sy += __cardheight + ydir - 1; 160 } 161 else 162 { 163 y += ydir; 164 sy += ydir; 165 } 166 167 //convert x,y directions to -1, +1 168 xdir = xdir < 0 ? -1 : 1; 169 ydir = ydir < 0 ? -1 : 1; 170 171 SetPixel(hdc, x+xdir, y , GetPixel(hdcSource, sx+xdir, sy)); 172 SetPixel(hdc, x, y, GetPixel(hdcSource, sx, sy)); 173 SetPixel(hdc, x, y+ydir, GetPixel(hdcSource, sx, sy+ydir)); 174 175 } 176 177 // 178 // Draw a card (i.e. miss out the corners) 179 // 180 void DrawCard(HDC hdc, int x, int y, HDC hdcDragCard, int width, int height) 181 { 182 //draw main center band 183 BitBlt(hdc, x+2, y, width - 4, height, hdcDragCard, 2, 0, SRCCOPY); 184 185 //draw the two bits to the left 186 BitBlt(hdc, x, y+2, 1, height - 4, hdcDragCard, 0, 2, SRCCOPY); 187 BitBlt(hdc, x+1, y+1, 1, height - 2, hdcDragCard, 1, 1, SRCCOPY); 188 189 //draw the two bits to the right 190 BitBlt(hdc, x+width-2, y+1, 1, height - 2, hdcDragCard, width-2, 1, SRCCOPY); 191 BitBlt(hdc, x+width-1, y+2, 1, height - 4, hdcDragCard, width-1, 2, SRCCOPY); 192 } 193 194 // 195 // Clip a card SHAPE - basically any rectangle 196 // with rounded corners 197 // 198 int ClipCard(HDC hdc, int x, int y, int width, int height) 199 { 200 ExcludeClipRect(hdc, x+2, y, x+2+width-4, y+ height); 201 ExcludeClipRect(hdc, x, y+2, x+1, y+2+height-4); 202 ExcludeClipRect(hdc, x+1, y+1, x+2, y+1+height-2); 203 ExcludeClipRect(hdc, x+width-2, y+1, x+width-2+1, y+1+height-2); 204 ExcludeClipRect(hdc, x+width-1, y+2, x+width-1+1, y+2+height-4); 205 return 0; 206 } 207 208 void CardRegion::Clip(HDC hdc) 209 { 210 int numtoclip; 211 212 if(fVisible == false) 213 return; 214 215 Update(); //Update this stack's size+card count 216 numtoclip = nNumApparentCards; 217 218 //if we are making this stack flash on/off, then only 219 //clip the stack for drawing if the flash is in its ON state 220 if(nFlashCount != 0) 221 { 222 if(fFlashVisible == FALSE) 223 numtoclip = 0; 224 } 225 226 //if offset along a diagonal 227 if(xoffset != 0 && yoffset != 0 && cardstack.NumCards() != 0) 228 { 229 for(int j = 0; j < numtoclip; j ++) 230 { 231 ClipCard(hdc, xpos + xoffset * j, ypos + yoffset * j, __cardwidth, __cardheight); 232 } 233 } 234 //otherwise if just offset along a horizontal/vertical axis 235 else 236 { 237 if(yoffset < 0 && numtoclip > 0) 238 { 239 ClipCard(hdc, xpos, ypos-((numtoclip-1)*-yoffset), width, height); 240 } 241 else if(xoffset < 0 && numtoclip > 0) 242 { 243 ClipCard(hdc, xpos-((numtoclip-1)*-xoffset), ypos, width, height); 244 } 245 else 246 { 247 ClipCard(hdc, xpos, ypos, width, height); 248 } 249 } 250 251 } 252 253 void CardRegion::Render(HDC hdc) 254 { 255 int cardnum = 0; 256 int numtodraw; 257 BOOL fDrawTips; 258 259 Update(); //Update this stack's card count + size 260 261 numtodraw = nNumApparentCards; 262 263 if(nFlashCount != 0) 264 { 265 if(fFlashVisible == false) 266 numtodraw = 0; 267 } 268 269 if(fVisible == 0) return; 270 271 cardnum = cardstack.NumCards() - numtodraw; 272 int counter; 273 274 for(counter = 0; counter < numtodraw; counter++) 275 { 276 int cardval; 277 278 int x = xoffset * counter + xpos; 279 int y = yoffset * counter + ypos; 280 281 //if about to draw last card, then actually draw the top card 282 if(counter == numtodraw - 1) cardnum = cardstack.NumCards() - 1; 283 284 Card card = cardstack.cardlist[cardnum]; 285 cardval = card.Idx(); 286 287 if(card.FaceDown()) 288 cardval = nBackCardIdx; //card-back 289 290 //only draw the visible part of the card 291 if(counter < numtodraw - 1) 292 { 293 if(yoffset != 0 && xoffset != 0) 294 fDrawTips = FALSE; 295 else 296 fDrawTips = TRUE; 297 298 if((yoffset != 0 && abs(xoffset) == 1) || (xoffset != 0 && abs(yoffset) == 1)) 299 fDrawTips = TRUE; 300 301 //draw horizontal strips 302 if(yoffset > 0) 303 { 304 DrawHorzCardStrip(hdc, x, y, cardval, yoffset, fDrawTips); 305 } 306 else if(yoffset < 0) 307 { 308 DrawHorzCardStrip(hdc, x, y+__cardheight+yoffset, cardval, yoffset, fDrawTips); 309 } 310 311 //draw some vertical bars 312 if(xoffset > 0) 313 { 314 DrawVertCardStrip(hdc, x, y, cardval, xoffset, fDrawTips); 315 } 316 else if(xoffset < 0) 317 { 318 DrawVertCardStrip(hdc, x+__cardwidth+xoffset, y, cardval, xoffset, fDrawTips); 319 } 320 321 if(yoffset != 0 && xoffset != 0)//fDrawTips == FALSE) 322 { 323 //if we didn't draw any tips, then this is a 2-dim stack 324 //(i.e, it goes at a diagonal). 325 //in this case, we need to fill in the small triangle in 326 //each corner! 327 DrawCardCorner(hdc, x, y, cardval, xoffset, yoffset); 328 } 329 } 330 //if the top card, draw the whole thing 331 else 332 { 333 CardBlt(hdc, x, y, cardval); 334 } 335 336 cardnum ++; 337 338 } //end of index 339 340 if(counter == 0) //if the cardstack is empty, then draw it that way 341 { 342 int x = xpos; 343 int y = ypos; 344 345 switch(uEmptyImage) 346 { 347 default: 348 case CS_EI_NONE: 349 //this wipes the RECT variable, so watch out! 350 //SetRect(&rect, x, y, x+__cardwidth, y+__cardheight); 351 //PaintRect(hdc, &rect, MAKE_PALETTERGB(crBackgnd)); 352 parentWnd.PaintCardRgn(hdc, x, y, __cardwidth, __cardheight, x, y); 353 break; 354 355 case CS_EI_SUNK: 356 DrawCard(hdc, x, y, __hdcPlaceHolder, __cardwidth, __cardheight); 357 break; 358 359 case CS_EI_CIRC: 360 case CS_EI_X: 361 CardBlt(hdc, x, y, uEmptyImage); 362 break; 363 } 364 365 } 366 367 return; 368 } 369 370 int calc_offset(int offset, int numcards, int numtodrag, int realvisible) 371 { 372 if(offset >= 0) 373 return -offset * numcards; 374 else 375 return -offset * (numtodrag) + 376 -offset * (realvisible - 1); 377 } 378 379 void CardRegion::PrepareDragBitmaps(int numtodrag) 380 { 381 RECT rect; 382 HDC hdc; 383 int icard; 384 int numcards = cardstack.NumCards(); 385 int xoff, yoff; 386 387 if(nThreedCount > 1) 388 { 389 PrepareDragBitmapsThreed(numtodrag); 390 return; 391 } 392 393 //work out how big the bitmaps need to be 394 nDragCardWidth = (numtodrag - 1) * abs(xoffset) + __cardwidth; 395 nDragCardHeight = (numtodrag - 1) * abs(yoffset) + __cardheight; 396 397 //Create bitmap for the back-buffer 398 hdc = GetDC(NULL); 399 hdcBackGnd = CreateCompatibleDC(hdc); 400 hbmBackGnd = CreateCompatibleBitmap(hdc, nDragCardWidth, nDragCardHeight); 401 SelectObject(hdcBackGnd, hbmBackGnd); 402 403 //Create bitmap for the drag-image 404 hdcDragCard = CreateCompatibleDC(hdc); 405 hbmDragCard = CreateCompatibleBitmap(hdc, nDragCardWidth, nDragCardHeight); 406 SelectObject(hdcDragCard, hbmDragCard); 407 ReleaseDC(NULL, hdc); 408 409 UseNicePalette(hdcBackGnd, __hPalette); 410 UseNicePalette(hdcDragCard, __hPalette); 411 412 int realvisible = numcards / nThreedCount; 413 414 //if(numcards > 0 && realvisible == 0) realvisible = 1; 415 int iwhichcard = numcards - 1; 416 if(nThreedCount == 1) iwhichcard = 0; 417 418 //grab the first bit of background so we can prep the back buffer; do this by 419 //rendering the card stack (minus the card we are dragging) to the temporary 420 //background buffer, so it appears if we have lifted the card from the stack 421 //PaintRect(hdcBackGnd, &rect, crBackgnd); 422 SetRect(&rect, 0, 0, nDragCardWidth, nDragCardHeight); 423 424 xoff = calc_offset(xoffset, numcards, numtodrag, realvisible); 425 yoff = calc_offset(yoffset, numcards, numtodrag, realvisible); 426 427 parentWnd.PaintCardRgn(hdcBackGnd, 0, 0, nDragCardWidth, nDragCardHeight, xpos - xoff, ypos - yoff); 428 429 // 430 // Render the cardstack into the back-buffer. The stack 431 // has already had the dragcards removed, so just draw 432 // what is left 433 // 434 for(icard = 0; icard < realvisible; icard++) 435 { 436 Card card = cardstack.cardlist[iwhichcard]; 437 int nCardVal; 438 439 nCardVal = card.FaceUp() ? card.Idx() : nBackCardIdx; 440 441 xoff = xoffset * icard + calc_offset(xoffset, numcards, numtodrag, realvisible);//- xoffset * ((numcards+numtodrag) / nThreedCount - numtodrag); 442 yoff = yoffset * icard + calc_offset(yoffset, numcards, numtodrag, realvisible);//- yoffset * ((numcards+numtodrag) / nThreedCount - numtodrag); 443 444 CardBlt(hdcBackGnd, xoff, yoff, nCardVal); 445 iwhichcard++; 446 } 447 448 // 449 // If there are no cards under this one, just draw the place holder 450 // 451 if(numcards == 0) 452 { 453 int xoff = 0, yoff = 0; 454 455 if(xoffset < 0) xoff = nDragCardWidth - __cardwidth; 456 if(yoffset < 0) yoff = nDragCardHeight - __cardheight; 457 458 switch(uEmptyImage) 459 { 460 case CS_EI_NONE: 461 //No need to draw anything: We already cleared the 462 //back-buffer before the main loop.. 463 464 //SetRect(&rc, xoff, yoff, xoff+ __cardwidth, yoff + __cardheight); 465 //PaintRect(hdcBackGnd, &rc, MAKE_PALETTERGB(crBackgnd)); 466 //parentWnd.PaintCardRgn(hdcBackGnd, xoff, yoff, __cardwidth, __cardheight, xpos, ypos);// + xoff, ypos + yoff); 467 break; 468 469 case CS_EI_SUNK: 470 DrawCard(hdcBackGnd, xoff, yoff, __hdcPlaceHolder, __cardwidth, __cardheight); 471 break; 472 473 case CS_EI_CIRC: 474 case CS_EI_X: 475 CardBlt(hdc, xoff, yoff, uEmptyImage); 476 break; 477 } 478 } 479 480 // 481 // now render the drag-cards into the dragcard image 482 // 483 PaintRect(hdcDragCard, &rect, crBackgnd); 484 485 for(icard = 0; icard < numtodrag; icard++) 486 { 487 int nCardVal; 488 489 if(xoffset >= 0) xoff = xoffset * icard; 490 else xoff = -xoffset * (numtodrag - icard - 1); 491 492 if(yoffset >= 0) yoff = yoffset * icard; 493 else yoff = -yoffset * (numtodrag - icard - 1); 494 495 Card card = dragstack.cardlist[icard]; 496 497 nCardVal = card.FaceUp() ? card.Idx() : nBackCardIdx; 498 499 CardBlt(hdcDragCard, xoff, yoff, nCardVal); 500 } 501 } 502 503 void CardRegion::PrepareDragBitmapsThreed(int numtodrag) 504 { 505 RECT rect; 506 HDC hdc; 507 int icard; 508 int numunder = 0; 509 int iwhichcard; 510 511 int numcards = cardstack.NumCards(); 512 513 //work out how big the bitmaps need to be 514 nDragCardWidth = (numtodrag - 1) * abs(xoffset) + __cardwidth; 515 nDragCardHeight = (numtodrag - 1) * abs(yoffset) + __cardheight; 516 517 //Create bitmap for the back-buffer 518 hdc = GetDC(NULL); 519 hdcBackGnd = CreateCompatibleDC(hdc); 520 hbmBackGnd = CreateCompatibleBitmap(hdc, nDragCardWidth, nDragCardHeight); 521 SelectObject(hdcBackGnd, hbmBackGnd); 522 523 //create bitmap for the drag-image 524 hdcDragCard = CreateCompatibleDC(hdc); 525 hbmDragCard = CreateCompatibleBitmap(hdc, nDragCardWidth, nDragCardHeight); 526 SelectObject(hdcDragCard, hbmDragCard); 527 ReleaseDC(NULL, hdc); 528 529 UseNicePalette(hdcBackGnd, __hPalette); 530 UseNicePalette(hdcDragCard, __hPalette); 531 532 //grab the first bit of background so we can prep the back buffer; do this by 533 //rendering the card stack (minus the card we are dragging) to the temporary 534 //background buffer, so it appears if we have lifted the card from the stack 535 //--SetRect(&rect, 0, 0, nDragCardWidth, nDragCardHeight); 536 //--PaintRect(hdcBackGnd, &rect, crBackgnd); 537 538 int threedadjust = numcards % nThreedCount == 0; 539 540 numunder = CalcApparentCards(numcards); 541 iwhichcard = (numcards+numtodrag) - numunder - 1; 542 if(nThreedCount == 1) iwhichcard = 0; 543 544 int xoff = calc_offset(xoffset, numunder, numtodrag, numunder); 545 int yoff = calc_offset(yoffset, numunder, numtodrag, numunder); 546 547 parentWnd.PaintCardRgn(hdcBackGnd, 0,0, nDragCardWidth,nDragCardHeight, xpos - xoff,ypos - yoff); 548 549 // 550 // Render the cardstack into the back-buffer. The stack 551 // has already had the dragcards removed, so just draw 552 // what is left 553 // 554 for(icard = 0; icard < numunder; icard++) 555 { 556 Card card = cardstack.cardlist[iwhichcard]; 557 int nCardVal = card.FaceUp() ? card.Idx() : nBackCardIdx; 558 559 CardBlt(hdcBackGnd, 560 xoffset * icard - xoffset*(numunder-numtodrag+threedadjust), 561 yoffset * icard - yoffset*(numunder-numtodrag+threedadjust), 562 nCardVal); 563 564 iwhichcard++; 565 } 566 567 // 568 // If there are no cards under this one, just draw the place holder 569 // 570 if(numcards == 0) 571 { 572 switch(uEmptyImage) 573 { 574 case CS_EI_NONE: 575 //no need! we've already cleared the whole 576 //back-buffer before the main loop! 577 //SetRect(&rect, 0, 0, __cardwidth, __cardheight); 578 //PaintRect(hdcBackGnd, &rect, MAKE_PALETTERGB(crBackgnd)); 579 break; 580 581 case CS_EI_SUNK: 582 DrawCard(hdcBackGnd, 0, 0, __hdcPlaceHolder, __cardwidth, __cardheight); 583 break; 584 585 case CS_EI_CIRC: 586 case CS_EI_X: 587 CardBlt(hdc, 0, 0, uEmptyImage); 588 break; 589 } 590 } 591 592 // 593 // now render the drag-cards into the dragcard image 594 // 595 PaintRect(hdcDragCard, &rect, crBackgnd); 596 597 for(icard = 0; icard < numtodrag; icard++) 598 { 599 Card card = dragstack.cardlist[icard]; 600 int nCardVal = card.FaceUp() ? card.Idx() : nBackCardIdx; 601 602 CardBlt(hdcDragCard, xoffset * icard, yoffset * icard, nCardVal); 603 } 604 } 605 606 void CardRegion::ReleaseDragBitmaps(void) 607 { 608 //SelectObject(hdcBackGnd, hOld1); 609 DeleteObject(hbmBackGnd); 610 DeleteDC(hdcBackGnd); 611 612 //SelectObject(hdcDragCard, hOld2); 613 DeleteObject(hbmDragCard); 614 DeleteDC(hdcDragCard); 615 } 616 617 618 void CardRegion::Redraw() 619 { 620 HDC hdc = GetDC((HWND)parentWnd); 621 622 Update(); 623 Render(hdc); 624 625 ReleaseDC((HWND)parentWnd, hdc); 626 } 627