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 //
CardBlt(HDC hdc,int x,int y,int nCardNum)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 //
DrawHorzCardStrip(HDC hdc,int x,int y,int nCardNum,int height,BOOL fDrawTips)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 //
DrawVertCardStrip(HDC hdc,int x,int y,int nCardNum,int width,BOOL fDrawTips)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 //
DrawCardCorner(HDC hdc,int x,int y,int cardval,int xdir,int ydir)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 //
DrawCard(HDC hdc,int x,int y,HDC hdcDragCard,int width,int height)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 //
ClipCard(HDC hdc,int x,int y,int width,int height)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
Clip(HDC hdc)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
Render(HDC hdc)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
calc_offset(int offset,int numcards,int numtodrag,int realvisible)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
PrepareDragBitmaps(int numtodrag)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
PrepareDragBitmapsThreed(int numtodrag)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
ReleaseDragBitmaps(void)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
Redraw()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