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