cleaned all trailing white space from source files.
[sdk] / ecere / src / gfx / Surface.ec
1 namespace gfx;
2
3 import "Display"
4
5 #include <stdarg.h>
6
7 public struct ColorKey
8 {
9    ColorAlpha color;
10    float percent;
11 };
12
13 public enum GradientDirection { vertical, horizontal };
14
15 public void PaletteGradient(ColorAlpha * palette, int numColors, ColorKey * keys, int numKeys, float smoothness)
16 {
17    ColorKey * key = keys, * nextKey = keys;
18    int keyNum = 0, nextKeyNum = 0;
19    float inc = 1.0f/(numColors-1);
20    float percent = 0;
21    int start;
22    ColorAlpha color;
23    int c;
24
25    for(c = start = 0; c<numColors; c++)
26    {
27       ColorAlpha newColor = 0;
28
29       while(nextKey && percent > nextKey->percent)
30       {
31          key = nextKey; keyNum = nextKeyNum;
32
33          if(keyNum < numKeys - 1)
34          {
35             nextKey = key + 1;
36             nextKeyNum = keyNum + 1;
37          }
38          else
39             break;
40       }
41
42       if(nextKey && nextKey->percent != key->percent)
43       {
44          float scale = ease((percent - key->percent) / (nextKey->percent - key->percent),
45             smoothness, smoothness);
46          int cr = key->color.color.r;
47          int cg = key->color.color.g;
48          int cb = key->color.color.b;
49          int nr = nextKey->color.color.r;
50          int ng = nextKey->color.color.g;
51          int nb = nextKey->color.color.b;
52          int r = (int)(cr + (nr - cr) * scale);
53          int g = (int)(cg + (ng - cg) * scale);
54          int b = (int)(cb + (nb - cb) * scale);
55
56          r = Max(Min(r, 255),0);
57          g = Max(Min(g, 255),0);
58          b = Max(Min(b, 255),0);
59
60          newColor = Color { (byte)r, (byte)g, (byte)b };
61       }
62       else if(key)
63          newColor = key ? key->color : 0;
64
65       if(c == 0 || newColor != color)
66       {
67          if(c != 0)
68          {
69             int i;
70             for(i = start; i<c; i++)
71                palette[i] = color;
72
73             start = c;
74          }
75          color = newColor;
76       }
77       percent += inc;
78    }
79
80    {
81       int i;
82       for(i = start; i<c; i++)
83          palette[i] = color;
84    }
85 }
86
87 float ease(float t, float a, float b)
88 {
89    float k;
90    float s = a + b;
91
92    if (s == 0.0f) return t;
93    if (s > 1.0f)
94    {
95       a /= s;
96       b /= s;
97    }
98    k = 1.0f/(2.0f-a-b);
99    if (t < a) return (k/a)*t*t;
100    if (t < 1.0f - b) return k*(2.0f * t - a);
101    t = 1.0f - t;
102    return 1.0f - (k/b)*t*t;
103 }
104
105 public enum AlphaWriteMode
106 {
107    dontWrite,
108    write,
109    blend
110 };
111
112 public class Surface
113 {
114 public:
115    int width, height;
116    Point offset;
117    Box box, unclippedBox;
118    void * driverData;
119
120 private:
121    subclass(DisplayDriver) driver;
122    DisplaySystem displaySystem;
123    Display display;
124
125
126    // States
127    Font font;
128    ColorAlpha foreground, background;
129    bool textOpacity;
130    AlphaWriteMode alphaWrite;
131    bool blend;
132    bool writeColor;
133    ColorAlpha blitTint;
134
135    blitTint = white;
136
137    blend = true;
138    writeColor = true;
139    alphaWrite = blend;
140
141    ~Surface()
142    {
143       if(driver)
144          driver.ReleaseSurface(display, this);
145    }
146
147 public:
148    property AlphaWriteMode alphaWrite
149    {
150       set { alphaWrite = value; }
151       get { return alphaWrite; }
152    }
153    property bool blend
154    {
155       set { blend = value; }
156       get { return blend; }
157    }
158    property Bitmap bitmap
159    {
160       get
161       {
162          return ((LFBSurface)driverData).bitmap;
163       }
164    }
165
166    ColorAlpha GetPixel(int x, int y)
167    {
168       return driver.GetPixel(display, this, x,y);
169    }
170
171    void PutPixel(int x, int y)
172    {
173       driver.PutPixel(display, this, x,y);
174    }
175
176    void DrawLine(int x1, int y1, int x2, int y2)
177    {
178       driver.DrawLine(display, this, x1,y1,x2,y2);
179    }
180
181    void VLine(int y1, int y2, int x)
182    {
183       driver.DrawLine(display, this, x,y1,x,y2);
184    }
185
186    void HLine(int x1, int x2, int y)
187    {
188       driver.DrawLine(display, this, x1,y,x2,y);
189    }
190
191    void Rectangle(int x1, int y1, int x2, int y2)
192    {
193       driver.Rectangle(display, this, x1,y1,x2,y2);
194    }
195
196    void Area(int x1, int y1, int x2, int y2)
197    {
198       driver.Area(display, this, x1,y1,x2,y2);
199    }
200
201    void Clear(ClearType type)
202    {
203       driver.Clear(display, this, type);
204    }
205
206    void Blit(Bitmap src, int dx, int dy, int sx, int sy, int w, int h)
207    {
208       if(src.driver == driver)
209          driver.Blit(display, this, src, dx,dy, sx, sy,w,h);
210       else if(!src.driver || src.driver == class(LFBDisplayDriver))
211          driver.BlitDI(display, this, src, dx,dy, sx, sy,w,h);
212    }
213
214    void Stretch(Bitmap src, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh)
215    {
216       if(src.driver == driver)
217          driver.Stretch(display, this, src, dx,dy, sx,sy, w,h, sw, sh);
218       else if(!src.driver || src.driver == class(LFBDisplayDriver))
219          driver.StretchDI(display, this, src, dx,dy, sx,sy, w,h, sw, sh);
220    }
221
222    void Filter(Bitmap src, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh)
223    {
224       if(src.driver == driver)
225          driver.Filter(display, this, src, dx,dy, sx,sy, w,h, sw, sh);
226       else if(!src.driver || src.driver == class(LFBDisplayDriver))
227          driver.FilterDI(display, this, src, dx,dy, sx,sy, w,h, sw, sh);
228    }
229
230    void Tile(Bitmap src, int dx, int dy, int w, int h)
231    {
232       if(src && src.width && src.height)
233       {
234          int x,y,sx,sy;
235          for(x = 0,sx = dx; x < w; x += src.width, sx += src.width)
236             for(y = 0, sy = dy; y < h; y += src.height,sy += src.height)
237                Blit(src, sx, sy, 0,0, Min(src.width, w - x), Min(src.height, h - y));
238       }
239    }
240
241    void HTile(Bitmap src, int dx, int dy, int w, int h)
242    {
243       if(src && src.width && src.height)
244       {
245          int x,sx;
246          for(x = 0, sx = dx; x < w; x += src.width, sx += src.width)
247             Stretch(src, sx, dy, 0, 0, Min(src.width, w - x), h, Min(src.width, w - x), src.height);
248       }
249    }
250
251    void VTile(Bitmap src, int dx, int dy, int w, int h)
252    {
253       if(src && src.width && src.height)
254       {
255          int y,sy;
256          for(y = 0, sy = dy; y < h; y += src.height, sy += src.height)
257             Stretch(src, dx, sy, 0,0, w, Min(src.height, h - y), src.width, Min(src.height, h - y));
258       }
259    }
260
261    void FilterHTile(Bitmap src, int dx, int dy, int w, int h)
262    {
263       if(src && src.width && src.height)
264       {
265          int x,sx;
266          for(x = 0, sx = dx; x < w; x += src.width, sx += src.width)
267             Filter(src, sx, dy, 0, 0, Min(src.width, w - x), h, Min(src.width, w - x), src.height);
268       }
269    }
270
271    void FilterVTile(Bitmap src, int dx, int dy, int w, int h)
272    {
273       if(src && src.width && src.height)
274       {
275          int y,sy;
276          for(y = 0, sy = dy; y < h; y += src.height, sy += src.height)
277             Filter(src, dx, sy, 0,0, w, Min(src.height, h - y), src.width, Min(src.height, h - y));
278       }
279    }
280
281    void WriteText(int x, int y, char * text, int len)
282    {
283       if(text)
284          driver.WriteText(display, this, x,y, text, len);
285    }
286
287    void TextExtent(char * text, int len, int * width, int * height)
288    {
289       driver.TextExtent(display, this, text, len, width, height);
290    }
291
292    void WriteTextf(int x, int y, char * format, ...)
293    {
294       if(format)
295       {
296          char text[MAX_F_STRING];
297          va_list args;
298          va_start(args, format);
299          vsnprintf(text, sizeof(text), format, args);
300          text[sizeof(text)-1] = 0;
301          driver.WriteText(display, this, x,y, text, strlen(text));
302          va_end(args);
303       }
304    }
305
306    void CenterTextf(int x, int y, char * format, ...)
307    {
308       if(format)
309       {
310          char text[MAX_F_STRING];
311          va_list args;
312          int len;
313          int w, h;
314          va_start(args, format);
315          vsnprintf(text, sizeof(text), format, args);
316          text[sizeof(text)-1] = 0;
317          len = strlen(text);
318
319          driver.TextExtent(display, this, text, len, &w, &h);
320          driver.WriteText(display, this, x - w/2, y, text, len);
321          va_end(args);
322       }
323    }
324
325    void WriteTextDots(Alignment alignment, int x, int y, int width, char * text, int len)
326    {
327       int w, h;
328
329       TextExtent(text, len, &w, &h);
330       if(w < width)
331       {
332          if(alignment == right)
333             x += width - w - 1;
334          else if(alignment == center)
335             x += (width - w) / 2;
336          WriteText(x, y, text, len);
337       }
338       else
339       {
340          int c;
341          int dw, dh;
342          int current;
343          int totalW = 0;
344          int nb;
345          char ch;
346
347          TextExtent(".", 1, &dw, &dh);
348          current = 3 * dw;
349          #define UTF8_NUM_BYTES(x)  (__extension__({ byte b = x; (b & 0x80 && b & 0x40) ? ((b & 0x20) ? ((b & 0x10) ? 4 : 3) : 2) : 1; }))
350          for(c = 0; (ch = text[c]); c += nb)
351          {
352             nb = UTF8_NUM_BYTES(ch);
353             TextExtent(text+c, nb, &w, &h);
354             current += w;
355             if(current > width)
356                break;
357             totalW += w;
358          }
359          WriteText(x, y, text, c);
360          //TextExtent(text, c, &totalW, &h);
361          x += totalW;
362          WriteText(x, y, "...", 3);
363       }
364    }
365
366    void WriteTextDotsf(Alignment alignment, int x, int y, int width, char * format, ...)
367    {
368       if(format)
369       {
370          char text[MAX_F_STRING];
371          va_list args;
372          va_start(args, format);
373          vsnprintf(text, sizeof(text), format, args);
374          text[sizeof(text)-1] = 0;
375          WriteTextDots(alignment, x,y, width, text, strlen(text));
376          va_end(args);
377       }
378    }
379
380    void Bevel(bool inner, int x, int y, int w, int h)
381    {
382       ColorAlpha foreground = this.foreground;
383
384       SetForeground(inner ? Color { 128,128,128 } : formColor);
385       HLine(x,   x+w - 2, y);
386       VLine(y+1, y+h - 2, x);
387
388       SetForeground(inner ? Color { 64,64,64 } : white);
389       HLine(x+1, x+w-3, y+1);
390       VLine(y+2, y+h-3, x+1);
391
392       SetForeground(inner ? formColor : Color { 128,128,128 } );
393       HLine(x+1, x+w-2, y + h -2);
394       VLine(y+1, y+h-3, x + w - 2);
395
396       SetForeground(inner ? white : Color { 64,64,64 });
397       HLine(x, x+w-1, y + h - 1);
398       VLine(y, y+h-2, x + w - 1);
399
400       SetForeground(foreground);
401    }
402
403    void ThinBevel(bool inner, int x, int y, int w, int h)
404    {
405       SetForeground(inner ? Color { 128,128,128 } : white);
406       HLine(x,   x+w - 2, y);
407       VLine(y+1, y+h - 2, x);
408       SetForeground(inner ? white : Color { 128,128,128 });
409       HLine(x, x+w-1, y + h - 1);
410       VLine(y, y+h-2, x + w - 1);
411    }
412
413    void Gradient(ColorKey * keys, int numKeys, float smoothness, GradientDirection direction, int x1, int y1, int x2, int y2)
414    {
415       if(x2 >= box.left && x1 <= box.right && y2 >= box.top && y1 <= box.bottom)
416       {
417          ColorKey * key = keys, * nextKey = keys;
418          int keyNum = 0, nextKeyNum = 0;
419          int height = (direction == horizontal) ? ((x2 - x1) + 1) : ((y2 - y1) + 1);
420          float inc = 1.0f/(height-1);
421          float percent = 0;
422          int start;
423          ColorAlpha color = 0;
424          int firstPixel = (direction == horizontal) ? x1 : y1;
425          int lastPixel = (direction == horizontal) ? x2 : y2;
426          int boxLeft = (direction == horizontal) ? box.left : box.top;
427          int boxRight = (direction == horizontal) ? box.right : box.bottom;
428          int c;
429
430          // Clip it
431          if(boxLeft > firstPixel)
432          {
433             percent = (boxLeft - firstPixel) * inc;
434             firstPixel = boxLeft;
435          }
436          if(boxRight < lastPixel)
437             lastPixel = boxRight;
438
439          for(c = start = firstPixel; c<=lastPixel; c++)
440          {
441             ColorAlpha newColor;
442
443             while(nextKey && percent > nextKey->percent)
444             {
445                key = nextKey; keyNum = nextKeyNum;
446
447                if(keyNum < numKeys - 1)
448                {
449                   nextKey = key + 1;
450                   nextKeyNum = keyNum + 1;
451                }
452                else
453                   break;
454             }
455
456             if(nextKey && nextKey->percent != key->percent)
457             {
458                float scale = ease((percent - key->percent) / (nextKey->percent - key->percent),
459                   smoothness, smoothness);
460                int cr = key->color.color.r;
461                int cg = key->color.color.g;
462                int cb = key->color.color.b;
463                int nr = nextKey->color.color.r;
464                int ng = nextKey->color.color.g;
465                int nb = nextKey->color.color.b;
466                int r = (int)(cr + (nr - cr) * scale);
467                int g = (int)(cg + (ng - cg) * scale);
468                int b = (int)(cb + (nb - cb) * scale);
469
470                r = Max(Min(r, 255),0);
471                g = Max(Min(g, 255),0);
472                b = Max(Min(b, 255),0);
473
474                newColor = Color { (byte)r, (byte)g, (byte)b };
475             }
476             else
477                newColor = key ? key->color : 0;
478
479             if(c == firstPixel || newColor != color)
480             {
481                if(c != firstPixel)
482                {
483                   SetBackground(color);
484
485                   if(direction == horizontal)
486                      Area(start,y1,c-1,y2);
487                   else
488                      Area(x1, start,x2, c-1);
489                   start = c;
490                }
491                color = newColor;
492             }
493             percent += inc;
494          }
495
496          SetBackground(color);
497          if(direction == horizontal)
498             Area(start,y1,c-1,y2);
499          else
500             Area(x1, start,x2, c-1);
501       }
502    }
503
504    // Properties
505    property ColorAlpha foreground
506    {
507       set
508       {
509          foreground = value;
510          driver.SetForeground(display, this, value);
511       }
512       get { return foreground; }
513    }
514
515    property ColorAlpha background
516    {
517       set
518       {
519          background = value;
520          driver.SetBackground(display, this, value);
521       }
522       get { return background; }
523    }
524
525    property ColorAlpha blitTint
526    {
527       set
528       {
529          blitTint = value;
530          driver.SetBlitTint(display, this, value);
531       }
532       get { return blitTint; }
533    }
534
535    property uint lineStipple
536    {
537       set
538       {
539          driver.LineStipple(display, this, value);
540       }
541    }
542
543    property Size size
544    {
545       get { value = { width, height }; }
546    }
547
548    /*property Box box
549    {
550       get
551       {
552          value = box;
553          if(display && display.flags.text)
554          {
555             value.left *= textCellW;
556             value.top *= textCellH;
557             value.right *= textCellW;
558             value.bottom *= textCellH;
559          }
560       }
561    }*/
562
563    property Display display
564    {
565       get { return display; }
566    }
567
568    property Font font
569    {
570       set
571       {
572          if(value && font != value)
573          {
574             driver.TextFont(display, this, value);
575             font = value;
576          }
577       }
578
579       get { return font; }
580    }
581
582    property bool textOpacity
583    {
584       set
585       {
586          textOpacity = value;
587          driver.TextOpacity(display, this, value);
588       }
589
590       get { return textOpacity; }
591    }
592
593    property byte drawingChar
594    {
595       set { driver.DrawingChar(display, this, value); }
596    }
597
598    property Box clipping
599    {
600       set { driver.Clip(display, this, value); }
601    }
602
603    // TODO: Make these functions obsolete
604    void SetForeground(ColorAlpha value)
605    {
606       foreground = value;
607       driver.SetForeground(display, this, value);
608    }
609
610    void SetBackground(ColorAlpha value)
611    {
612       background = value;
613       driver.SetBackground(display, this, value);
614    }
615
616    Color GetForeground(void)
617    {
618       return foreground;
619    }
620
621    Color GetBackground(void)
622    {
623       return background;
624    }
625
626    void LineStipple(uint value)
627    {
628       driver.LineStipple(display, this, value);
629    }
630
631    void GetSize(int * w, int * h)
632    {
633       if(w) *w = width;
634       if(h) *h = height;
635    }
636
637    void GetBox(Box value)
638    {
639       value = box;
640       if(display.flags.text)
641       {
642          box.left *= textCellW;
643          box.top *= textCellH;
644          box.right *= textCellW;
645          box.bottom *= textCellH;
646       }
647    }
648
649    Display GetDisplay(void)
650    {
651       return display;
652    }
653
654    void TextFont(Font value)
655    {
656       if(value && font != value)
657       {
658          driver.TextFont(display, this, value);
659          font = value;
660       }
661    }
662
663    Font GetFont(void)
664    {
665       return font;
666    }
667
668    bool GetTextOpacity(void)
669    {
670       return textOpacity;
671    }
672
673    void TextOpacity(bool value)
674    {
675       textOpacity = value;
676       driver.TextOpacity(display, this, value);
677    }
678
679    void DrawingChar(unsigned char value)
680    {
681       driver.DrawingChar(display, this, value);
682    }
683
684    void Clip(Box box)
685    {
686       driver.Clip(display, this, box);
687    }
688 };