Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
Bitmap.cpp
Go to the documentation of this file.
1 /* Project nGenEx
2  Destroyer Studios LLC
3  Copyright © 1997-2004. All Rights Reserved.
4 
5  SUBSYSTEM: nGenEx.lib
6  FILE: Bitmap.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12  Bitmap Resource class
13 */
14 
15 #include "MemDebug.h"
16 #include "Bitmap.h"
17 #include "Video.h"
18 #include "Color.h"
19 #include "Game.h"
20 
21 // +--------------------------------------------------------------------+
22 
23 DWORD GetRealTime();
24 
25 static inline void swap(int& a, int& b) { int tmp=a; a=b; b=tmp; }
26 static inline void sort(int& a, int& b) { if (a>b) swap(a,b); }
27 static inline void swap(double& a, double& b) { double tmp=a; a=b; b=tmp; }
28 static inline void sort(double& a, double& b) { if (a>b) swap(a,b); }
29 static void draw_strip(BYTE* dst, int pitch, int pixsize, int x, int y, int len, Color color);
30 static void draw_vline(BYTE* dst, int pitch, int pixsize, int x, int y, int len, Color color);
31 
32 class WinPlot
33 {
34 public:
35  WinPlot(Bitmap* bmp);
36  void plot(int x, int y, DWORD val, int exch=0);
37 
38 private:
39  BYTE* s;
40  int pitch, pixsize;
41 };
42 
44 {
45  s = bmp->GetSurface();
46  pitch = bmp->Pitch();
47  pixsize = bmp->PixSize();
48 }
49 
50 void WinPlot::plot(int x, int y, DWORD val, int exch)
51 {
52  if (exch) swap(x,y);
53  BYTE* dst = s + y*pitch + x*pixsize;
54 
55  switch (pixsize) {
56  case 1: *dst = (BYTE) val; break;
57  case 2: { LPWORD dst2 = (LPWORD) dst; *dst2 = (WORD) val; } break;
58  case 4: { LPDWORD dst4 = (LPDWORD) dst; *dst4 = (DWORD) val; } break;
59  }
60 }
61 
62 // +--------------------------------------------------------------------+
63 
65 : type(BMP_SOLID), width(0), height(0),
66 ownpix(false), alpha_loaded(false), texture(false),
67 pix(0), hipix(0), mapsize(0),
68 last_modified(0)
69 {
70  strcpy_s(filename, "Bitmap()");
71 }
72 
73 Bitmap::Bitmap(int w, int h, ColorIndex* p, int t)
74 : type(t), width(w), height(h),
75 ownpix(false), alpha_loaded(false), texture(false),
76 pix(p), hipix(0), mapsize(w*h),
77 last_modified(GetRealTime())
78 {
79  sprintf_s(filename, "Bitmap(%d, %d, index, type=%d)", w, h, (int) t);
80 }
81 
82 Bitmap::Bitmap(int w, int h, Color* p, int t)
83 : type(t), width(w), height(h),
84 ownpix(false), alpha_loaded(false), texture(false),
85 pix(0), hipix(p), mapsize(w*h),
86 last_modified(GetRealTime())
87 {
88  sprintf_s(filename, "Bitmap(%d, %d, hicolor, type=%d)", w, h, (int) t);
89 }
90 
91 // +--------------------------------------------------------------------+
92 
94 {
95  if (ownpix) {
96  delete [] pix;
97  delete [] hipix;
98  }
99 }
100 
101 // +--------------------------------------------------------------------+
102 
103 int
105 {
106  return mapsize * PixSize();
107 }
108 
109 int
111 {
112  return width;
113 }
114 
115 int
117 {
118  return width * PixSize();
119 }
120 
121 int
123 {
124  if (hipix)
125  return sizeof(Color);
126 
127  else if (pix)
128  return sizeof(ColorIndex);
129 
130  return 0;
131 }
132 
133 BYTE*
135 {
136  if (ownpix) {
137  if (hipix)
138  return (BYTE*) hipix;
139 
140  return (BYTE*) pix;
141  }
142 
143  return 0;
144 }
145 
146 // +--------------------------------------------------------------------+
147 
148 void
149 Bitmap::BitBlt(int x, int y, const Bitmap& srcBmp, int sx, int sy, int w, int h, bool blend)
150 {
151  if (!ownpix || x < 0 || y < 0 || x >= width || y >= height)
152  return;
153 
154  if (sx < 0 || sy < 0 || sx >= srcBmp.Width() || sy >= srcBmp.Height())
155  return;
156 
157  if (hipix) {
158  if (srcBmp.HiPixels()) {
159  int dpitch = width;
160  int spitch = srcBmp.Width();
161  int rowlen = w * sizeof(Color);
162  Color* dst = hipix + (y*dpitch) + x;
163  Color* src = srcBmp.HiPixels() + (sy*spitch) + sx;
164 
165  if (!blend) {
166  for (int i = 0; i < h; i++) {
167  memcpy(dst, src, rowlen);
168  dst += dpitch;
169  src += spitch;
170  }
171  }
172  else {
173  for (int i = 0; i < h; i++) {
174  Color* ps = src;
175  Color* pd = dst;
176 
177  for (int n = 0; n < w; n++) {
178  if (ps->Value())
179  pd->Set(Color::FormattedBlend(ps->Value(), pd->Value()));
180  ps++;
181  pd++;
182  }
183 
184  dst += dpitch;
185  src += spitch;
186  }
187  }
188  }
189 
190  else {
191  int dpitch = width;
192  int spitch = srcBmp.Width();
193  Color* dst = hipix + (y*dpitch) + x;
194  ColorIndex* src = srcBmp.Pixels() + (sy*spitch) + sx;
195 
196  if (!blend) {
197  for (int j = 0; j < h; j++) {
198  for (int i = 0; i < w; i++) {
199  dst[i].Set(src[i].Formatted());
200  }
201 
202  dst += dpitch;
203  src += spitch;
204  }
205  }
206  else {
207  for (int i = 0; i < h; i++) {
208  ColorIndex* ps = src;
209  Color* pd = dst;
210 
211  for (int n = 0; n < w; n++) {
212  if (ps->Index())
213  pd->Set(Color::FormattedBlend(ps->Formatted(), pd->Value()));
214  ps++;
215  pd++;
216  }
217  }
218 
219  dst += dpitch;
220  src += spitch;
221  }
222  }
223  }
224 
225  else if (pix) {
226  if (srcBmp.Pixels()) {
227  int dpitch = width;
228  int spitch = srcBmp.Width();
229  int rowlen = w;
230  Color* dst = hipix + (y*dpitch) + x;
231  Color* src = srcBmp.HiPixels() + (sy*spitch) + sx;
232 
233  for (int i = 0; i < h; i++) {
234 #pragma warning(suppress: 28183)
235  memcpy(dst, src, rowlen);
236  dst += dpitch;
237  src += spitch;
238  }
239  }
240  }
241 
242  alpha_loaded = srcBmp.alpha_loaded;
244 }
245 
246 // +--------------------------------------------------------------------+
247 
248 void
250 {
251  if (ownpix) {
252  delete [] pix;
253  delete [] hipix;
254  pix = 0;
255  hipix = 0;
256  }
257 
258  type = rhs.type;
259  width = rhs.width;
260  height = rhs.height;
262  texture = rhs.texture;
263  ownpix = true;
264 
265  mapsize = width * height;
266 
267  if (rhs.pix) {
268  pix = new(__FILE__,__LINE__) ColorIndex[mapsize];
269 
270  if (!pix) {
271  width = 0;
272  height = 0;
273  mapsize = 0;
274  }
275 
276  else {
277  memcpy(pix, rhs.pix, mapsize*sizeof(ColorIndex));
278  }
279  }
280 
281  if (rhs.hipix) {
282  hipix = new(__FILE__,__LINE__) Color[mapsize];
283 
284  if (!hipix && !pix) {
285  width = 0;
286  height = 0;
287  mapsize = 0;
288  }
289 
290  else {
291  memcpy(hipix, rhs.hipix, mapsize*sizeof(Color));
292  }
293  }
294 
296 }
297 
298 // +--------------------------------------------------------------------+
299 
300 void
302 {
303  if (ownpix) {
304  delete [] pix;
305  delete [] hipix;
306  pix = 0;
307  hipix = 0;
308  }
309 
310  type = BMP_SOLID;
311  width = 0;
312  height = 0;
313  mapsize = 0;
314  ownpix = false;
315  texture = false;
316 
318 }
319 
320 // +--------------------------------------------------------------------+
321 
322 void
323 Bitmap::CopyImage(int w, int h, BYTE* p, int t)
324 {
325  if (ownpix) {
326  delete [] pix;
327  pix = 0;
328  }
329  else {
330  hipix = 0;
331  }
332 
333  type = t;
334  width = w;
335  height = h;
336  ownpix = true;
337  texture = false;
338  mapsize = w * h;
339 
340  pix = new(__FILE__,__LINE__) ColorIndex[mapsize];
341 
342  if (!pix) {
343  width = 0;
344  height = 0;
345  mapsize = 0;
346  }
347 
348  else {
349  memcpy(pix, p, mapsize);
350  }
351 
353 }
354 
355 // +--------------------------------------------------------------------+
356 
357 void
358 Bitmap::CopyHighColorImage(int w, int h, DWORD* p, int t)
359 {
360  if (ownpix) {
361  delete [] hipix;
362  hipix = 0;
363  }
364  else {
365  pix = 0;
366  }
367 
368  type = t;
369  width = w;
370  height = h;
371  ownpix = true;
372  texture = false;
373  mapsize = w * h;
374 
375  hipix = new(__FILE__,__LINE__) Color[mapsize];
376 
377  if (!hipix) {
378  width = 0;
379  height = 0;
380  mapsize = 0;
381  }
382 
383  else {
384  memcpy(hipix, p, mapsize*sizeof(DWORD));
385  }
386 
388 }
389 
390 // +--------------------------------------------------------------------+
391 
392 void
393 Bitmap::CopyAlphaImage(int w, int h, BYTE* a)
394 {
395  if (!hipix || width != w || height != h)
396  return;
397 
399  alpha_loaded = true;
400 
401  Color* p = hipix;
402 
403  for (int i = 0; i < mapsize; i++) {
404  p->SetAlpha(*a);
405  p++;
406  a++;
407  }
408 
410 }
411 
412 void
413 Bitmap::CopyAlphaRedChannel(int w, int h, DWORD* a)
414 {
415  if (!hipix || width != w || height != h)
416  return;
417 
419  alpha_loaded = true;
420 
421  Color* p = hipix;
422 
423  for (int i = 0; i < mapsize; i++) {
424  p->SetAlpha((BYTE) ((*a & Color::RMask) >> Color::RShift));
425  p++;
426  a++;
427  }
428 
430 }
431 
432 // +--------------------------------------------------------------------+
433 
434 void
435 Bitmap::AutoMask(DWORD mask)
436 {
437  if (!hipix || !mapsize || alpha_loaded)
438  return;
439 
441  alpha_loaded = true;
442 
443  Color* p = hipix;
444  DWORD m = mask & Color::RGBMask;
445 
446  for (int i = 0; i < mapsize; i++) {
447  if ((p->Value() & Color::RGBMask) == m)
448  p->SetAlpha(0);
449  else
450  p->SetAlpha(255);
451 
452  p++;
453  }
454 
456 }
457 
458 // +--------------------------------------------------------------------+
459 
460 void
462 {
463  if (!width || !height)
464  return;
465 
466  if (pix) {
467  ColorIndex* p = pix;
468  BYTE index = c.Index();
469 
470  for (int i = 0; i < mapsize; i++)
471  *p++ = index;
472  }
473 
474  if (hipix) {
475  Color* p = hipix;
476  DWORD value = c.Value();
477 
478  for (int i = 0; i < mapsize; i++) {
479  p->Set(value);
480  p++;
481  }
482  }
483 
485 }
486 
487 // +--------------------------------------------------------------------+
488 
489 void
490 Bitmap::ScaleTo(int w, int h)
491 {
492  if (w < 1 || h < 1)
493  return;
494 
495  double dx = (double) width / (double) w;
496  double dy = (double) height / (double) h;
497 
498  bool mem_ok = true;
499 
500  if (hipix) {
501  Color* src = hipix;
502  Color* buf = new(__FILE__,__LINE__) Color[w*h];
503  Color* dst = buf;
504 
505  if (!buf) {
506  mem_ok = false;
507  }
508 
509  else {
510  for (int y = 0; y < h; y++) {
511  int y_offset = (int) (y * dy);
512  for (int x = 0; x < w; x++) {
513  int x_offset = (int) (x * dx);
514  src = hipix + (y_offset * width) + x_offset;
515  *dst++ = *src;
516  }
517  }
518 
519  if (ownpix)
520  delete [] hipix;
521 
522  hipix = buf;
523  ownpix = true;
524  }
525  }
526 
527  if (pix) {
528  ColorIndex* src = pix;
529  ColorIndex* buf = new(__FILE__,__LINE__) ColorIndex[w*h];
530  ColorIndex* dst = buf;
531 
532  if (!buf) {
533  mem_ok = false;
534  }
535 
536  else {
537  for (int y = 0; y < h; y++) {
538  int y_offset = (int) (y * dy);
539  for (int x = 0; x < w; x++) {
540  int x_offset = (int) (x * dx);
541  src = pix + (y_offset * width) + x_offset;
542  *dst++ = *src;
543  }
544  }
545 
546  if (ownpix)
547  delete [] pix;
548 
549  pix = buf;
550  ownpix = true;
551  }
552  }
553 
554  if (mem_ok) {
555  width = w;
556  height = h;
557  mapsize = width * height;
558  }
559 }
560 
561 // +--------------------------------------------------------------------+
562 
563 void
565 {
566  if (hipix) {
567  if (pix && ownpix)
568  delete [] pix;
569  pix = new(__FILE__,__LINE__) ColorIndex[mapsize];
570 
571  if (pix) {
572  Color* src = hipix;
573  ColorIndex* dst = pix;
574 
575  for (int y = 0; y < height; y++) {
576  for (int x = 0; x < width; x++) {
577  *dst++ = src->Index();
578  src++;
579  }
580  }
581 
582  if (!ownpix)
583  hipix = 0;
584 
585  ownpix = true;
586  }
587  }
588 }
589 
590 // +--------------------------------------------------------------------+
591 
592 void
594 {
595  if (pix) {
596  if (hipix && ownpix)
597  delete [] hipix;
598 
599  hipix = new(__FILE__,__LINE__) Color[mapsize];
600 
601  if (hipix) {
602  ColorIndex* src = pix;
603  Color* dst = hipix;
604 
605  for (int y = 0; y < height; y++) {
606  for (int x = 0; x < width; x++) {
607  *dst++ = src->Index();
608  src++;
609  }
610  }
611 
612  if (!ownpix)
613  pix = 0;
614 
615  ownpix = true;
616  }
617  }
618 }
619 
620 // +--------------------------------------------------------------------+
621 
622 static int FindBestTexSize(int n, int max_size)
623 {
624  int delta = 100000;
625  int best = 1;
626 
627  for (int i = 0; i < 12; i++) {
628  int size = 1 << i;
629 
630  if (size > max_size)
631  break;
632 
633  int dx = abs(n-size);
634 
635  if (size < n)
636  dx *= 4;
637 
638  if (dx < delta) {
639  delta = dx;
640  best = size;
641  }
642  }
643 
644  return best;
645 }
646 
647 void
649 {
650  if (width < 1 || height < 1 || (!pix && !hipix)) {
651  if (ownpix) {
652  delete [] pix;
653  delete [] hipix;
654  }
655 
656  width = 0;
657  height = 0;
658  pix = 0;
659  hipix = 0;
660  texture = false;
661  return;
662  }
663 
664  // texture surface format is 32-bit RGBA:
665  if (pix && !hipix) {
666  MakeHighColor();
667  }
668 
669  // check size and aspect ratio:
670  int max_tex_size = Game::MaxTexSize();
671  int max_tex_aspect = Game::MaxTexAspect();
672 
673  int best_width = FindBestTexSize(width, max_tex_size);
674  int best_height = FindBestTexSize(height, max_tex_size);
675  int aspect = 1;
676 
677  // correct sizes for aspect if necessary:
678  if (best_width > best_height) {
679  aspect = best_width / best_height;
680 
681  if (aspect > max_tex_aspect)
682  best_height = best_width / max_tex_aspect;
683  }
684 
685  else {
686  aspect = best_height / best_width;
687 
688  if (aspect > max_tex_aspect)
689  best_width = best_height / max_tex_aspect;
690  }
691 
692  // rescale if necessary:
693  if (width != best_width || height != best_height)
694  ScaleTo(best_width, best_width);
695 
696  texture = true;
697 }
698 
699 // +--------------------------------------------------------------------+
700 
702 Bitmap::GetIndex(int x, int y) const
703 {
704  ColorIndex result(0);
705 
706  if (x < 0 || y < 0 || x > width-1 || y > height-1)
707  return result;
708 
709  if (pix) {
710  result = *(pix + y*width + x);
711  }
712  else if (hipix) {
713  result = (hipix + y*width + x)->Index();
714  }
715 
716  return result;
717 }
718 
719 // +--------------------------------------------------------------------+
720 
721 Color
722 Bitmap::GetColor(int x, int y) const
723 {
724  Color result = Color::Black;
725 
726  if (x < 0 || y < 0 || x > width-1 || y > height-1)
727  return result;
728 
729  if (pix) {
730  result = (pix + y*width + x)->Index();
731  }
732  else if (hipix) {
733  result = *(hipix + y*width + x);
734  }
735 
736  return result;
737 }
738 
739 // +--------------------------------------------------------------------+
740 
741 void
742 Bitmap::SetIndex(int x, int y, ColorIndex c)
743 {
744  if (x < 0 || y < 0 || x > width || y > height)
745  return;
746 
747  if (pix) {
748  *(pix + y*width + x) = c;
749  }
750  else if (hipix) {
751  *(hipix + y*width + x) = c.Index();
752  }
753 
755 }
756 
757 // +--------------------------------------------------------------------+
758 
759 void
760 Bitmap::SetColor(int x, int y, Color c)
761 {
762  if (x < 0 || y < 0 || x > width || y > height)
763  return;
764 
765  if (pix) {
766  *(pix + y*width + x) = c.Index();
767  }
768  else if (hipix) {
769  *(hipix + y*width + x) = c;
770  }
771 
773 }
774 
775 // +--------------------------------------------------------------------+
776 
777 void
778 Bitmap::SetFilename(const char* s)
779 {
780  if (s) {
781  int n = strlen(s);
782 
783  if (n >= 60) {
784  ZeroMemory(filename, sizeof(filename));
785  strcpy_s(filename, "...");
786  strcat_s(filename, s + n - 59);
787  filename[63] = 0;
788  }
789 
790  else {
791  strcpy_s(filename, s);
792  }
793  }
794 }
795 
796 // +--------------------------------------------------------------------+
797 
798 Bitmap*
800 {
801  static Bitmap def;
802 
803  if (!def.width) {
804  def.width = def.height = 64;
805  def.mapsize = 64*64;
806  def.ownpix = true;
807  def.pix = new(__FILE__,__LINE__) ColorIndex[def.mapsize];
808 
809  // 8 bit palette mode
810  if (def.pix) {
811  ColorIndex* p = def.pix;
812 
813  for (int y = 0; y < 64; y++) {
814  for (int x = 0; x < 64; x++) {
815  double distance = sqrt((x-32.0)*(x-32.0) + (y-32.0)*(y-32.0));
816  if (distance > 31.0) distance = 31.0;
817  BYTE color = 24 + (BYTE) distance;
818 
819  if (x == 0 || y == 0) color = 255;
820  else if (x == 32 || y == 32) color = 251;
821 
822  *p++ = color;
823  }
824  }
825  }
826  }
827 
828  return &def;
829 }
830 
831 // +--------------------------------------------------------------------+
832 
833 static List<Bitmap> bitmap_cache;
834 
835 Bitmap*
836 Bitmap::GetBitmapByID(HANDLE bmp_id)
837 {
838  for (int i = 0; i < bitmap_cache.size(); i++) {
839  if (bitmap_cache[i]->Handle() == bmp_id) {
840  return bitmap_cache[i];
841  }
842  }
843 
844  return 0;
845 }
846 
847 Bitmap*
848 Bitmap::CheckCache(const char* filename)
849 {
850  for (int i = 0; i < bitmap_cache.size(); i++) {
851  if (!_stricmp(bitmap_cache[i]->GetFilename(), filename)) {
852  return bitmap_cache[i];
853  }
854  }
855 
856  return 0;
857 }
858 
859 void
861 {
862  bitmap_cache.append(bmp);
863 }
864 
865 void
867 {
868  for (int i = 0; i < bitmap_cache.size(); i++) {
869  Bitmap* bmp = bitmap_cache[i];
870 
871  if (bmp->IsTexture())
872  bmp->MakeTexture();
873  }
874 }
875 
876 void
878 {
879  bitmap_cache.destroy();
880 }
881 
882 DWORD
884 {
885  DWORD result = sizeof(bitmap_cache);
886  result += bitmap_cache.size() * sizeof(Bitmap*);
887 
888  for (int i = 0; i < bitmap_cache.size(); i++) {
889  Bitmap* bmp = bitmap_cache[i];
890 
891  if (bmp->pix)
892  result += bmp->mapsize * sizeof(ColorIndex);
893 
894  if (bmp->hipix)
895  result += bmp->mapsize * sizeof(Color);
896  }
897 
898  return result;
899 }
900 
901 // +--------------------------------------------------------------------+
902 
903 bool
904 Bitmap::ClipLine(int& x1, int& y1, int& x2, int& y2)
905 {
906  // vertical lines:
907  if (x1==x2) {
908  clip_vertical:
909  sort(y1,y2);
910  if (x1 < 0 || x1 >= width) return false;
911  if (y1 < 0) y1 = 0;
912  if (y2 >= height) y2 = height;
913  return true;
914  }
915 
916  // horizontal lines:
917  if (y1==y2) {
918  clip_horizontal:
919  sort(x1,x2);
920  if (y1 < 0 || y1 >= height) return false;
921  if (x1 < 0) x1 = 0;
922  if (x2 > width) x2 = width;
923  return true;
924  }
925 
926  // general lines:
927 
928  // sort left to right:
929  if (x1 > x2) {
930  swap(x1,x2);
931  swap(y1,y2);
932  }
933 
934  double m = (double)(y2-y1) / (double)(x2-x1);
935  double b = (double) y1 - (m * x1);
936 
937  // clip:
938  if (x1 < 0) { x1 = 0; y1 = (int) b; }
939  if (x1 >= width) return false;
940  if (x2 < 0) return false;
941  if (x2 > width-1) { x2 = width-1; y2 = (int) (m * x2 + b); }
942 
943  if (y1 < 0 && y2 < 0) return false;
944  if (y1 >= height && y2 >= height) return false;
945 
946  if (y1 < 0) { y1 = 0; x1 = (int) (-b/m); }
947  if (y1 >= height) { y1 = height-1; x1 = (int) ((y1-b)/m); }
948  if (y2 < 0) { y2 = 0; x2 = (int) (-b/m); }
949  if (y2 >= height) { y2 = height-1; x2 = (int) ((y2-b)/m); }
950 
951  if (x1 == x2)
952  goto clip_vertical;
953 
954  if (y1 == y2)
955  goto clip_horizontal;
956 
957  return true;
958 }
959 
960 // +--------------------------------------------------------------------+
961 
962 bool
963 Bitmap::ClipLine(double& x1, double& y1, double& x2, double& y2)
964 {
965  // vertical lines:
966  if (x1==x2) {
967  clip_vertical:
968  sort(y1,y2);
969  if (x1 < 0 || x1 >= width) return false;
970  if (y1 < 0) y1 = 0;
971  if (y2 >= height) y2 = height;
972  return true;
973  }
974 
975  // horizontal lines:
976  if (y1==y2) {
977  clip_horizontal:
978  sort(x1,x2);
979  if (y1 < 0 || y1 >= height) return false;
980  if (x1 < 0) x1 = 0;
981  if (x2 > width) x2 = width;
982  return true;
983  }
984 
985  // general lines:
986 
987  // sort left to right:
988  if (x1 > x2) {
989  swap(x1,x2);
990  swap(y1,y2);
991  }
992 
993  double m = (double)(y2-y1) / (double)(x2-x1);
994  double b = (double) y1 - (m * x1);
995 
996  // clip:
997  if (x1 < 0) { x1 = 0; y1 = b; }
998  if (x1 >= width) return false;
999  if (x2 < 0) return false;
1000  if (x2 > width-1) { x2 = width-1; y2 = (m * x2 + b); }
1001 
1002  if (y1 < 0 && y2 < 0) return false;
1003  if (y1 >= height && y2 >= height) return false;
1004 
1005  if (y1 < 0) { y1 = 0; x1 = (-b/m); }
1006  if (y1 >= height) { y1 = height-1; x1 = ((y1-b)/m); }
1007  if (y2 < 0) { y2 = 0; x2 = (-b/m); }
1008  if (y2 >= height) { y2 = height-1; x2 = ((y2-b)/m); }
1009 
1010  if (x1 == x2)
1011  goto clip_vertical;
1012 
1013  if (y1 == y2)
1014  goto clip_horizontal;
1015 
1016  return true;
1017 }
1018 
1019 // +--------------------------------------------------------------------+
1020 
1021 void
1022 Bitmap::DrawLine(int x1, int y1, int x2, int y2, Color color)
1023 {
1024  BYTE* s = GetSurface();
1025 
1026  if (!s) return;
1027 
1029 
1030  // vertical lines:
1031  if (x1==x2) {
1032  draw_vertical:
1033  sort(y1,y2);
1034  int fh = y2-y1;
1035  if (x1 < 0 || x1 >= width) return;
1036  if (y1 < 0) y1 = 0;
1037  if (y2 >= height) y2 = height;
1038  fh = y2-y1;
1039  draw_vline(s, Pitch(), PixSize(), x1, y1, fh, color);
1040  return;
1041  }
1042 
1043  // horizontal lines:
1044  if (y1==y2) {
1045  draw_horizontal:
1046  sort(x1,x2);
1047  int fw = x2-x1;
1048  if (y1 < 0 || y1 >= height) return;
1049  if (x1 < 0) x1 = 0;
1050  if (x2 > width) x2 = width;
1051  fw = x2-x1;
1052  draw_strip(s, Pitch(), PixSize(), x1, y1, fw, color);
1053  return;
1054  }
1055 
1056  // general lines:
1057 
1058  // sort left to right:
1059  if (x1 > x2) {
1060  swap(x1,x2);
1061  swap(y1,y2);
1062  }
1063 
1064  double m = (double)(y2-y1) / (double)(x2-x1);
1065  double b = (double) y1 - (m * x1);
1066 
1067  // clip:
1068  if (x1 < 0) { x1 = 0; y1 = (int) b; }
1069  if (x1 >= width) return;
1070  if (x2 < 0) return;
1071  if (x2 > width-1) { x2 = width-1; y2 = (int) (m * x2 + b); }
1072 
1073  if (y1 < 0 && y2 < 0) return;
1074  if (y1 >= height && y2 >= height) return;
1075 
1076  if (y1 < 0) { y1 = 0; x1 = (int) (-b/m); }
1077  if (y1 >= height) { y1 = height-1; x1 = (int) ((y1-b)/m); }
1078  if (y2 < 0) { y2 = 0; x2 = (int) (-b/m); }
1079  if (y2 >= height) { y2 = height-1; x2 = (int) ((y2-b)/m); }
1080 
1081  if (x1 > x2)
1082  return;
1083 
1084  if (x1 == x2)
1085  goto draw_vertical;
1086 
1087  if (y1 == y2)
1088  goto draw_horizontal;
1089 
1090  // plot the line using
1091  /*
1092  Symmetric Double Step Line Algorithm
1093  by Brian Wyvill
1094  from "Graphics Gems", Academic Press, 1990
1095 */
1096 
1097  WinPlot plotter(this);
1098 
1099  DWORD pix = color.Value();
1100  int sign_x=1, sign_y=1, step, reflect;
1101  int i, inc1, inc2, c, D, x_end, pixleft;
1102  int dx = x2 - x1;
1103  int dy = y2 - y1;
1104 
1105  if (dx < 0) {
1106  sign_x = -1;
1107  dx *= -1;
1108  }
1109  if (dy < 0) {
1110  sign_y = -1;
1111  dy *= -1;
1112  }
1113 
1114  // decide increment sign by the slope sign
1115  if (sign_x == sign_y)
1116  step = 1;
1117  else
1118  step = -1;
1119 
1120  if (dy > dx) { // chooses axis of greatest movement (make * dx)
1121  swap(x1, y1);
1122  swap(x2, y2);
1123  swap(dx, dy);
1124  reflect = 1;
1125  } else
1126  reflect = 0;
1127 
1128  if (x1 > x2) { // start from the smaller coordinate
1129  swap(x1,x2);
1130  swap(y1,y2);
1131  }
1132 
1133  /* Note dx=n implies 0 - n or (dx+1) pixels to be set */
1134  /* Go round loop dx/4 times then plot last 0,1,2 or 3 pixels */
1135  /* In fact (dx-1)/4 as 2 pixels are already plottted */
1136  x_end = (dx - 1) / 4;
1137  pixleft = (dx - 1) % 4; /* number of pixels left over at the end */
1138 
1139  plotter.plot(x1, y1, pix, reflect);
1140  plotter.plot(x2, y2, pix, reflect); /* plot first two points */
1141 
1142  inc2 = 4 * dy - 2 * dx;
1143  if (inc2 < 0) { /* slope less than 1/2 */
1144  c = 2 * dy;
1145  inc1 = 2 * c;
1146  D = inc1 - dx;
1147 
1148  for (i = 0; i < x_end; i++) { /* plotting loop */
1149  ++x1;
1150  --x2;
1151  if (D < 0) {
1152  /* pattern 1 forwards */
1153  plotter.plot(x1, y1, pix, reflect);
1154  plotter.plot(++x1, y1, pix, reflect);
1155  /* pattern 1 backwards */
1156  plotter.plot(x2, y2, pix, reflect);
1157  plotter.plot(--x2, y2, pix, reflect);
1158  D += inc1;
1159  }
1160  else {
1161  if (D < c) {
1162  /* pattern 2 forwards */
1163  plotter.plot(x1, y1, pix, reflect);
1164  plotter.plot(++x1, y1 += step, pix, reflect);
1165  /* pattern 2 backwards */
1166  plotter.plot(x2, y2, pix, reflect);
1167  plotter.plot(--x2, y2 -= step, pix, reflect);
1168  }
1169  else {
1170  /* pattern 3 forwards */
1171  plotter.plot(x1, y1 += step, pix, reflect);
1172  plotter.plot(++x1, y1, pix, reflect);
1173  /* pattern 3 backwards */
1174  plotter.plot(x2, y2 -= step, pix, reflect);
1175  plotter.plot(--x2, y2, pix, reflect);
1176  }
1177  D += inc2;
1178  }
1179  } /* end for */
1180 
1181  /* plot last pattern */
1182  if (pixleft) {
1183  if (D < 0) {
1184  plotter.plot(++x1, y1, pix, reflect); /* pattern 1 */
1185  if (pixleft > 1)
1186  plotter.plot(++x1, y1, pix, reflect);
1187  if (pixleft > 2)
1188  plotter.plot(--x2, y2, pix, reflect);
1189  }
1190  else {
1191  if (D < c) {
1192  plotter.plot(++x1, y1, pix, reflect); /* pattern 2 */
1193  if (pixleft > 1)
1194  plotter.plot(++x1, y1 += step, pix, reflect);
1195  if (pixleft > 2)
1196  plotter.plot(--x2, y2, pix, reflect);
1197  }
1198  else {
1199  /* pattern 3 */
1200  plotter.plot(++x1, y1 += step, pix, reflect);
1201  if (pixleft > 1)
1202  plotter.plot(++x1, y1, pix, reflect);
1203  if (pixleft > 2)
1204  plotter.plot(--x2, y2 -= step, pix, reflect);
1205  }
1206  }
1207  } /* end if pixleft */
1208  }
1209  /* end slope < 1/2 */
1210  else { /* slope greater than 1/2 */
1211  c = 2 * (dy - dx);
1212  inc1 = 2 * c;
1213  D = inc1 + dx;
1214  for (i = 0; i < x_end; i++) {
1215  ++x1;
1216  --x2;
1217  if (D > 0) {
1218  /* pattern 4 forwards */
1219  plotter.plot(x1, y1 += step, pix, reflect);
1220  plotter.plot(++x1, y1 += step, pix, reflect);
1221  /* pattern 4 backwards */
1222  plotter.plot(x2, y2 -= step, pix, reflect);
1223  plotter.plot(--x2, y2 -= step, pix, reflect);
1224  D += inc1;
1225  } else {
1226  if (D < c) {
1227  /* pattern 2 forwards */
1228  plotter.plot(x1, y1, pix, reflect);
1229  plotter.plot(++x1, y1 += step, pix, reflect);
1230 
1231  /* pattern 2 backwards */
1232  plotter.plot(x2, y2, pix, reflect);
1233  plotter.plot(--x2, y2 -= step, pix, reflect);
1234  } else {
1235  /* pattern 3 forwards */
1236  plotter.plot(x1, y1 += step, pix, reflect);
1237  plotter.plot(++x1, y1, pix, reflect);
1238  /* pattern 3 backwards */
1239  plotter.plot(x2, y2 -= step, pix, reflect);
1240  plotter.plot(--x2, y2, pix, reflect);
1241  }
1242  D += inc2;
1243  }
1244  } /* end for */
1245  /* plot last pattern */
1246  if (pixleft) {
1247  if (D > 0) {
1248  plotter.plot(++x1, y1 += step, pix, reflect); /* pattern 4 */
1249  if (pixleft > 1)
1250  plotter.plot(++x1, y1 += step, pix, reflect);
1251  if (pixleft > 2)
1252  plotter.plot(--x2, y2 -= step, pix, reflect);
1253  } else {
1254  if (D < c) {
1255  plotter.plot(++x1, y1, pix, reflect); /* pattern 2 */
1256  if (pixleft > 1)
1257  plotter.plot(++x1, y1 += step, pix, reflect);
1258  if (pixleft > 2)
1259  plotter.plot(--x2, y2, pix, reflect);
1260  } else {
1261  /* pattern 3 */
1262  plotter.plot(++x1, y1 += step, pix, reflect);
1263  if (pixleft > 1)
1264  plotter.plot(++x1, y1, pix, reflect);
1265  if (pixleft > 2) {
1266  if (D > c) /* step 3 */
1267  plotter.plot(--x2, y2 -= step, pix, reflect);
1268  else /* step 2 */
1269  plotter.plot(--x2, y2, pix, reflect);
1270  }
1271  }
1272  }
1273  }
1274  }
1275 }
1276 
1277 // +--------------------------------------------------------------------+
1278 
1279 void
1280 Bitmap::DrawRect(int x1, int y1, int x2, int y2, Color color)
1281 {
1282  sort(x1,x2);
1283  sort(y1,y2);
1284 
1285  int fw = x2-x1;
1286  int fh = y2-y1;
1287 
1288  if (fw == 0 || fh == 0) return;
1289 
1290  // perform clip
1291  int left = (x1 >= 0);
1292  int right = (x2 <= width);
1293  int top = (y1 >= 0);
1294  int bottom = (y2 <= height);
1295 
1296  BYTE* s = GetSurface();
1297  if (!s) return;
1298  int pitch = Pitch();
1299  int pixsize = PixSize();
1300 
1301  if (left) draw_vline(s, pitch, pixsize, x1, y1, fh, color);
1302  if (right) draw_vline(s, pitch, pixsize, x2, y1, fh, color);
1303  if (top) draw_strip(s, pitch, pixsize, x1, y1, fw, color);
1304  if (bottom) draw_strip(s, pitch, pixsize, x1, y2, fw, color);
1305 
1307 }
1308 
1309 // +--------------------------------------------------------------------+
1310 
1311 void
1312 Bitmap::DrawRect(const Rect& r, Color color)
1313 {
1314  if (r.w == 0 || r.h == 0) return;
1315 
1316  int x1 = r.x;
1317  int y1 = r.y;
1318  int x2 = r.x + r.w;
1319  int y2 = r.y + r.h;
1320 
1321  // perform clip
1322  int left = (x1 >= 0);
1323  int right = (x2 <= width);
1324  int top = (y1 >= 0);
1325  int bottom = (y2 <= height);
1326 
1327  BYTE* s = GetSurface();
1328  if (!s) return;
1329  int pitch = Pitch();
1330  int pixsize = PixSize();
1331 
1332  if (left) draw_vline(s, pitch, pixsize, x1, y1, r.h, color);
1333  if (right) draw_vline(s, pitch, pixsize, x2, y1, r.h, color);
1334  if (top) draw_strip(s, pitch, pixsize, x1, y1, r.w, color);
1335  if (bottom) draw_strip(s, pitch, pixsize, x1, y2, r.w, color);
1336 
1338 }
1339 
1340 // +--------------------------------------------------------------------+
1341 
1342 void
1343 Bitmap::FillRect(int x1, int y1, int x2, int y2, Color color)
1344 {
1345  // perform clip
1346  if (x1 < 0) x1 = 0;
1347  if (x2 > width-1) x2 = width-1;
1348  if (y1 < 0) y1 = 0;
1349  if (y2 > height) y2 = height;
1350 
1351  int fw = x2-x1;
1352  int fh = y2-y1;
1353 
1354  if (fw == 0 || fh == 0) return;
1355 
1356  BYTE* s = GetSurface();
1357  if (!s) return;
1358  int pitch = Pitch();
1359  int pixsize = PixSize();
1360 
1361  for (int i = 0; i < fh; i++)
1362  draw_strip(s, pitch, pixsize, x1, y1+i, fw, color);
1363 
1365 }
1366 
1367 // +--------------------------------------------------------------------+
1368 
1369 void
1370 Bitmap::FillRect(const Rect& r, Color color)
1371 {
1372  int x1 = r.x;
1373  int y1 = r.y;
1374  int x2 = r.x + r.w;
1375  int y2 = r.y + r.h;
1376 
1377  // perform clip
1378  if (x1 < 0) x1 = 0;
1379  if (x2 > width-1) x2 = width-1;
1380  if (y1 < 0) y1 = 0;
1381  if (y2 > height) y2 = height;
1382 
1383  int fw = x2-x1;
1384  int fh = y2-y1;
1385 
1386  if (fw == 0 || fh == 0) return;
1387 
1388  BYTE* s = GetSurface();
1389  if (!s) return;
1390  int pitch = Pitch();
1391  int pixsize = PixSize();
1392 
1393  for (int i = 0; i < fh; i++)
1394  draw_strip(s, pitch, pixsize, x1, y1+i, fw, color);
1395 
1397 }
1398 
1399 // +--------------------------------------------------------------------+
1400 
1401 void
1402 Bitmap::DrawEllipse(int x1, int y1, int x2, int y2, Color color, BYTE quad)
1403 {
1404  BYTE* orig = GetSurface();
1405  BYTE* s = orig;
1406 
1407  if (!s) return;
1408 
1409  sort(x1,x2);
1410  sort(y1,y2);
1411 
1412  int fw = x2-x1;
1413  int fh = y2-y1;
1414 
1415  if (fw < 1 || fh < 1) return;
1416 
1417  // clip:
1418  if (x1 >= width || x2 < 0) return;
1419  if (y1 >= height || y2 < 0) return;
1420 
1421  double a = fw / 2.0;
1422  double b = fh / 2.0;
1423  double a2 = a*a;
1424  double b2 = b*b;
1425 
1426  int x = 0;
1427  int y = (int) b;
1428  int x0 = (x1+x2)/2;
1429  int y0 = (y1+y2)/2;
1430 
1431  // clip super-giant ellipses:
1432  if (x1 < 0 && y1 < 0 && x2 > width && y2 > height) {
1433  double r2 = (a2<b2) ? a2 : b2;
1434 
1435  if (r2 > 32 * height)
1436  return;
1437 
1438  double ul = (x1-x0)*(x1-x0) + (y1-y0)*(y1-y0);
1439  double ur = (x2-x0)*(x2-x0) + (y1-y0)*(y1-y0);
1440  double ll = (x1-x0)*(x1-x0) + (y2-y0)*(y2-y0);
1441  double lr = (x2-x0)*(x2-x0) + (y2-y0)*(y2-y0);
1442 
1443  if (ul > r2 && ur > r2 && ll > r2 && lr > r2)
1444  return;
1445  }
1446 
1447  DrawEllipsePoints(x0,y0,x,y,color,quad);
1448 
1449  // region 1
1450  double d1 = (b2)-(a2*b)+(0.25*a2);
1451  while ((a2)*(y-0.5) > (b2)*(x+1)) {
1452  if (d1 < 0)
1453  d1 += b2*(2*x+3);
1454  else {
1455  d1 += b2*(2*x+3) + a2*(-2*y+2);
1456  y--;
1457  }
1458  x++;
1459 
1460  DrawEllipsePoints(x0,y0,x,y,color,quad);
1461  }
1462 
1463  // region 2
1464  double d2 = b2*(x+0.5)*(x+0.5) + a2*(y-1)*(y-1) - a2*b2;
1465  while (y > 0) {
1466  if (d2 < 0) {
1467  d2 += b2*(2*x+2) + a2*(-2*y+3);
1468  x++;
1469  }
1470  else
1471  d2 += a2*(-2*y+3);
1472  y--;
1473 
1474  DrawEllipsePoints(x0,y0,x,y,color,quad);
1475  }
1476 
1478 }
1479 
1480 void
1481 Bitmap::DrawEllipsePoints(int x0, int y0, int x, int y, Color c, BYTE quad)
1482 {
1483  BYTE* s = GetSurface();
1484 
1485  if (!s) return;
1486 
1487  int pitch = Pitch();
1488  int pixsize = PixSize();
1489 
1490  int left = x0-x;
1491  int right = x0+x+1;
1492  int top = y0-y;
1493  int bottom = y0+y+1;
1494 
1495  // clip:
1496  if (left >= width || right < 0) return;
1497  if (top >= height || bottom < 0) return;
1498 
1499  BYTE* dst = 0;
1500  DWORD cf = c.Value();
1501 
1502  if (left >= 0 && top >= 0 && quad&1) {
1503  dst = s + top*pitch + left*pixsize;
1504 
1505  switch (pixsize) {
1506  case 1: *dst = (BYTE) cf; break;
1507  case 2: { LPWORD sw = (LPWORD) dst; *sw = (WORD) cf; } break;
1508  case 4: { LPDWORD sd = (LPDWORD) dst; *sd = (DWORD) cf; } break;
1509  }
1510  }
1511 
1512  if (right < width && top >= 0 && quad&2) {
1513  dst = s + top*pitch + right*pixsize;
1514 
1515  switch (pixsize) {
1516  case 1: *dst = (BYTE) cf; break;
1517  case 2: { LPWORD sw = (LPWORD) dst; *sw = (WORD) cf; } break;
1518  case 4: { LPDWORD sd = (LPDWORD) dst; *sd = (DWORD) cf; } break;
1519  }
1520  }
1521 
1522  if (left >= 0 && bottom < height && quad&4) {
1523  dst = s + bottom*pitch + left*pixsize;
1524 
1525  switch (pixsize) {
1526  case 1: *dst = (BYTE) cf; break;
1527  case 2: { LPWORD sw = (LPWORD) dst; *sw = (WORD) cf; } break;
1528  case 4: { LPDWORD sd = (LPDWORD) dst; *sd = (DWORD) cf; } break;
1529  }
1530  }
1531 
1532  if (right < width && bottom < height && quad&4) {
1533  dst = s + bottom*pitch + right*pixsize;
1534 
1535  switch (pixsize) {
1536  case 1: *dst = (BYTE) cf; break;
1537  case 2: { LPWORD sw = (LPWORD) dst; *sw = (WORD) cf; } break;
1538  case 4: { LPDWORD sd = (LPDWORD) dst; *sd = (DWORD) cf; } break;
1539  }
1540  }
1541 }
1542 
1543 // +--------------------------------------------------------------------+
1544 
1545 static void draw_strip(BYTE* s, int pitch, int pixsize, int x, int y, int len, Color color)
1546 {
1547  if (!s) return;
1548  s += y*pitch + x*pixsize;
1549 
1550  DWORD value = color.Formatted();
1551 
1552  switch (pixsize) {
1553  case 1: {
1554  if (len > 1)
1555  memset(s, (BYTE) value, len);
1556  }
1557  break;
1558 
1559  case 2: {
1560  LPWORD sw = (LPWORD) s;
1561  for (int x = 0; x < len; x++) {
1562  *sw++ = (WORD) value;
1563  }
1564  }
1565  break;
1566 
1567  case 4: {
1568  Color* sd = (Color*) s;
1569  for (int x = 0; x < len; x++) {
1570  *sd++ = color;
1571  }
1572  }
1573  break;
1574  }
1575 }
1576 
1577 // +--------------------------------------------------------------------+
1578 
1579 static void draw_vline(BYTE* s, int pitch, int pixsize, int x, int y, int len, Color color)
1580 {
1581  if (!s) return;
1582  s += (y)*pitch + (x)*pixsize;
1583 
1584  DWORD value = color.Formatted();
1585 
1586  switch (pixsize) {
1587  case 1: {
1588  for (int y = 0; y < len; y++) {
1589  *s = (BYTE) value;
1590  s += pitch;
1591  }
1592  }
1593  break;
1594 
1595  case 2: {
1596  LPWORD sw = (LPWORD) s;
1597  pitch /= 2;
1598 
1599  for (int y = 0; y < len; y++) {
1600  *sw = (WORD) value;
1601  sw += pitch;
1602  }
1603  }
1604  break;
1605 
1606  case 4: {
1607  Color* sd = (Color*) s;
1608  pitch /= 4;
1609 
1610  for (int y = 0; y < len; y++) {
1611  *sd = color;
1612  sd += pitch;
1613  }
1614  }
1615  break;
1616  }
1617 }
1618 
1619