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