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