Subversion Repositories group.electronics

Rev

Rev 183 | Rev 185 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
182 pfowler 1
using System;
2
using System.Collections;
3
using System.Collections.Generic;
4
using System.Drawing;
5
using System.IO;
6
using System.Linq;
7
using System.Text;
8
using System.Threading.Tasks;
9
 
10
namespace nitdcscore {
11
    public class Oled {
12
        public const int LCD_WIDTH = 128;
13
        public const int LCD_HEIGHT = 64;
14
 
15
        public const int EXTERNALVCC = 0x01;
16
        public const int SWITCHCAPVCC = 0x02;
17
        public const int SETLOWCOLUMN = 0x00;
18
        public const int SETHIGHCOLUMN = 0x10;
19
        public const int MEMORYMODE = 0x20;
20
        public const int COLUMNADDR = 0x21;
21
        public const int PAGEADDR = 0x22;
22
        public const int DEACTIVATESCROLL = 0x2E;
23
        public const int SETSTARTLINE = 0x40;
24
 
25
        public const int SETCONTRAST = 0x81;
26
        public const int CHARGEPUMP = 0x8D;
27
 
28
        public const int SEGREMAP = 0xA0;
29
        public const int DISPLAYALLON_RESUME = 0xA4;
30
        public const int DISPLAYALLON = 0xA5;
31
        public const int NORMALDISPLAY = 0xA6;
32
        public const int INVERTDISPLAY = 0xA7;
33
        public const int SETMULTIPLEX = 0xA8;
34
        public const int DISPLAYOFF = 0xAE;
35
        public const int DISPLAYON = 0xAF;
36
 
37
        public const int COMSCANINC = 0xC0;
38
        public const int COMSCANDEC = 0xC8;
39
 
40
        public const int SETDISPLAYOFFSET = 0xD3;
41
        public const int SETCOMPINS = 0xDA;
42
        public const int SETVCOMDETECT = 0xDB;
43
        public const int SETDISPLAYCLOCKDIV = 0xD5;
44
        public const int SETPRECHARGE = 0xD9;
45
 
184 pfowler 46
        public byte[] buffer = new byte[Oled.LCD_WIDTH / 8 * Oled.LCD_HEIGHT];
182 pfowler 47
 
48
        public int vccstate { get; set; }
184 pfowler 49
        public byte i2caddr { get; set; }
182 pfowler 50
 
51
        public i2cmaster i2c { get; set; }
52
 
184 pfowler 53
        public Oled(int vccstate, byte i2caddr, i2cmaster i2c) {
182 pfowler 54
            this.vccstate = vccstate;
55
            this.i2caddr = i2caddr;
56
            this.i2c = i2c;
184 pfowler 57
 
58
 
59
            for (int i = 0; i < (LCD_WIDTH * LCD_HEIGHT / 8); i++) {
60
                buffer[i] = new byte();
61
                buffer[i] = 0x00;
62
            }
183 pfowler 63
        }
182 pfowler 64
 
183 pfowler 65
        public void init() {
182 pfowler 66
            // Init sequence
184 pfowler 67
 
182 pfowler 68
            oled_command(DISPLAYOFF);
69
            oled_command(SETDISPLAYCLOCKDIV);
70
            oled_command(0x80); // Suggested ratio
71
 
72
            oled_command(SETMULTIPLEX);
73
            oled_command(LCD_HEIGHT - 1);
74
 
75
            oled_command(SETDISPLAYOFFSET);
76
            oled_command(0x00); // No offset
77
            oled_command(SETSTARTLINE | 0x00); // Start line 0
78
            oled_command(CHARGEPUMP);
79
            if (this.vccstate == EXTERNALVCC)
80
                oled_command(0x10);
81
            else
82
                oled_command(0x14);
83
 
84
            oled_command(MEMORYMODE);
85
            oled_command(0x00);
86
            oled_command(SEGREMAP | 0x01);
87
            oled_command(COMSCANDEC);
88
 
89
            // 128-64 specific
90
            oled_command(SETCOMPINS);
91
            oled_command(0x12);
92
            oled_command(SETCONTRAST);
93
            if (this.vccstate == EXTERNALVCC)
94
                oled_command(0x9F);
95
            else
96
                oled_command(0xCF);
97
 
98
            oled_command(SETPRECHARGE);
99
            if (this.vccstate == EXTERNALVCC)
100
                oled_command(0x22);
101
            else
102
                oled_command(0xF1);
103
 
104
            oled_command(SETVCOMDETECT);
105
            oled_command(0x40);
106
            oled_command(DISPLAYALLON_RESUME);
107
            oled_command(NORMALDISPLAY);
108
            oled_command(DEACTIVATESCROLL);
109
 
110
            oled_command(DISPLAYON);
111
 
112
        }
113
 
114
        public void display() {
115
            oled_command(COLUMNADDR);
116
            oled_command(0x00);         // Column start address
117
            oled_command(LCD_WIDTH - 1);  // Column end address
118
 
119
            oled_command(PAGEADDR);
120
            oled_command(0x00); // Page start address
121
            oled_command(7);    // Page end address (7 for 64 pixels)
122
 
123
            for (int i = 0; i < (LCD_WIDTH * LCD_HEIGHT / 8); i++) {
124
                byte[] data = new byte[16];
125
                for (int j = 0; j < 16; j++) {
126
                    data[j] = buffer[i];
127
                    i++;
128
                }
129
                i--;
184 pfowler 130
                i2c.WriteI2cData(i2cUtils.addressToWrite(this.i2caddr), data, 16);
182 pfowler 131
            }
132
        }
133
 
134
        public int oled_command(byte c) {
184 pfowler 135
            byte[] data = { 0x00, c };            
136
            i2c.WriteI2cData(i2cUtils.addressToWrite(this.i2caddr), data, 2); ;
137
            //data[0] = c;
138
            //i2c.WriteI2cData((byte)this.i2caddr, data, 1);
182 pfowler 139
            return 0;
140
        }
141
    }
142
 
143
    public class BmpImage {
144
        public string filename;     // The image filename
145
        public int filesize;        // Total size of the 
146
        public int datastart;       // Location of the start of image data
147
        public int imagesize;       // The size of actual image data
148
        public int width;           // Width of the image
149
        public int height;          // Height of the image
150
        public int bpp;             // Bits per pixel of the image
151
        public int bytepad;         // Bytes padded to align image row
152
        public byte[] data;         // The bmp image data
153
        public BitArray[] bitdata;  // Data in bitarray format
154
 
155
        public BmpImage(string filename) {
156
            this.filename = filename;
157
            filesize = 0;
158
            datastart = 0xffffff;
159
            imagesize = 0;
160
            width = 0;
161
            height = 0;
162
            bpp = 0;
163
            bytepad = 0;
164
            data = new byte[8192];
165
            bitdata = new BitArray[1];
166
 
167
            this.load();
168
        }
169
 
170
        public int load() {
171
            using (BinaryReader b = new BinaryReader(File.Open(this.filename, FileMode.Open))) {
172
                int pos = 0;
173
 
174
                int readLen = (int)b.BaseStream.Length;
175
                while (pos < readLen) {
176
                    // Read the image data from the file
177
                    if (pos >= this.datastart) {
178
 
179
                        // BMP format stored in 'data'
180
                        int imgptr = 0;
181
                        while (imgptr < this.imagesize) {
182
                            this.data[imgptr++] = b.ReadByte();
183
                        }
184
                        //Console.WriteLine("Read " + imgptr.ToString() + " bytes");
185
 
186
                        // Raw decoded data stored in 'bitdata'
187
                        this.bitdata = new BitArray[this.height];
188
                        int x = 0;      // Cursor X position
189
                        int y = 0;      // Cursor Y position
190
                        int i = 0;    // Current byte position
191
                        //Console.WriteLine("W:{0} H:{1}", img.width.ToString(), img.height.ToString());
192
 
193
                        for (y = this.height - 1; y >= 0; y--) {
194
 
195
                            this.bitdata[y] = new BitArray(this.width);
196
                            x = 0;
197
                            while (x < this.width) {
198
                                if (x >= this.width)
199
                                    break;
200
                                // Reverse the bit cause its stored back to front in bmp format
201
                                byte br;
202
                                br = this.data[i];
203
                                br = (byte)((br * 0x0202020202 & 0x010884422010) % 1023);
204
 
205
                                for (int bitidx = 0; bitidx < 8; bitidx++) {
206
                                    int bitpos = x + bitidx;
207
                                    if (bitpos >= this.width)
208
                                        break;
209
                                    int val = br >> bitidx & 0x01;
210
                                    //Console.WriteLine("X:{0} Y:{1}", x.ToString(), y.ToString());
211
                                    this.bitdata[y].Set(bitpos, Convert.ToBoolean(val));
212
                                }
213
                                x += 8;
214
                                i++;
215
                            }
216
                            i += this.bytepad; // Account for the padding
217
                        }
218
                        break;
219
                    }
220
 
221
                    // Read the header data from the file
222
                    switch (pos) {
223
                        // Magic number header ("BM")
224
                        case 0x00: {
225
                                byte t1 = b.ReadByte();
226
                                byte t2 = b.ReadByte();
227
                                pos += 2;
228
                                string text = ((char)t1).ToString();
229
                                text += ((char)t2).ToString();
230
                            }
231
                            break;
232
                        // The size of the image file
233
                        case 0x02: {
234
                                this.filesize = (int)b.ReadUInt32();
235
                                pos += 4;
236
                                if (this.filesize != b.BaseStream.Length)
237
                                    Console.WriteLine("Size mismatch: " + this.filesize.ToString() + ":" + b.BaseStream.Length.ToString());
238
                                else
239
                                    Console.WriteLine("Size: " + this.filesize.ToString());
240
                            }
241
                            break;
242
                        // The start of image data location
243
                        case 0x0a: {
244
                                this.datastart = (int)b.ReadUInt32();
245
                                pos += 4;
246
                            }
247
                            break;
248
                        // The DIB header file size
249
                        case 0x0e: {
250
                                //UInt32 dibhs = b.ReadUInt32();
251
                                b.ReadUInt32();
252
                                pos += 4;
253
                            }
254
                            break;
255
                        // Bitmap width in pixels
256
                        case 0x12: {
257
                                this.width = (int)b.ReadInt32();
258
                                pos += 4;
259
 
260
                                // Rows aligned to a DWORD
261
                                int bitsOver = this.width % 32;
262
                                if (bitsOver > 0) {
263
                                    this.bytepad = (32 - bitsOver) / 8;
264
                                }
265
                            }
266
                            break;
267
                        // Bitmap height in pixels
268
                        case 0x16: {
269
                                this.height = (int)b.ReadInt32();
270
                                pos += 4;
271
                            }
272
                            break;
273
                        // Bitmap bytes per pixel
274
                        case 0x1c: {
275
                                this.bpp = (int)b.ReadUInt16();
276
                                pos += 2;
277
                            }
278
                            break;
279
                        // Bitmap size
280
                        case 0x22: {
281
                                this.imagesize = (int)b.ReadUInt32();
282
                                pos += 4;
283
                            }
284
                            break;
285
 
286
                        // Not an important piece of data; dump it
287
                        default:
288
                            b.ReadByte();
289
                            pos++;
290
                            break;
291
                    }
292
                }
293
            }
294
            return 0;
295
        }
296
 
297
    }
298
 
299
    public class BitImage {
300
 
301
        public BitArray[] bitdata;
302
        public int width;
303
        public int height;
304
 
305
        public BitImage(int width, int height) {
306
            this.width = width;
307
            this.height = height;
308
            this.bitdata = new BitArray[this.height];
309
 
310
            for (int i = 0; i < this.height; i++) {
311
                this.bitdata[i] = new BitArray(this.width);
312
            }
313
        }
314
 
315
        public BitImage(BitArray[] matrix) {
316
            this.width = matrix[0].Length;
317
            this.height = matrix.Length;
318
            this.bitdata = BitImage.copy(matrix);
319
        }
320
 
321
        public BitImage(BmpImage bmp) {
322
            this.width = bmp.width;
323
            this.height = bmp.height;
324
            this.bitdata = BitImage.copy(bmp.bitdata);
325
        }
326
 
327
        public BitImage(BitImage bit) {
328
            this.width = bit.width;
329
            this.height = bit.height;
330
            this.bitdata = BitImage.copy(bit.bitdata);
331
        }
332
 
333
        public BitImage(Bitmap bmp) {
334
            //Bitmap bmp = new Bitmap(nitdcscore.Properties.Resources.flap_bg);
335
            //BitImage bi = new BitImage(new Bitmap(Resources.flap_needle));
336
            this.width = bmp.Width;
337
            this.height = bmp.Height;
338
            this.bitdata = new BitArray[this.height];
339
 
340
            for (int y = 0; y < this.height; y++) {
341
                this.bitdata[y] = new BitArray(this.width);
342
                for (int x = 0; x < this.height; x++) {
343
                    Color c = bmp.GetPixel(x, y);
344
 
345
                    if (c.GetBrightness() == 0)
346
                        this.bitdata[y].Set(x, false);
347
                    else
348
                        this.bitdata[y].Set(x, true);
349
                }
350
            }
351
        }
352
 
353
 
354
 
355
        public void fillAll(bool color) {
356
            for (int i = 0; i < this.height; i++) {
357
                this.bitdata[i].SetAll(color);
358
            }
359
        }
360
 
361
        public void drawPixel(int x, int y, bool color) {
362
            if (x < 0 || y < 0 || x >= this.width || y >= this.height)
363
                return;
364
            this.bitdata[y].Set(x, color);
365
        }
366
 
367
        public void drawVLine(int x, int y, int h, bool color) {
368
 
369
            if (x < 0 || x >= this.width)
370
                return;
371
 
372
            if (y < 0) {
373
                h += y;
374
                y = 0;
375
            }
376
 
377
            if ((y + h) > this.height)
378
                h = this.height - y;
379
 
380
            if (h <= 0)
381
                return;
382
 
383
            for (int i = y; i < y + h; i++) {
384
                this.bitdata[i].Set(x, color);
385
            }
386
        }
387
 
388
        public void drawHLine(int x, int y, int w, bool color) {
389
            if (y < 0 || y >= this.height)
390
                return;
391
            if (x < 0) {
392
                w += x;
393
                x = 0;
394
            }
395
 
396
            if ((x + w) > this.width)
397
                w = this.width - x;
398
 
399
            if (w <= 0)
400
                return;
401
 
402
            for (int i = x; i < x + height; i++) {
403
                this.bitdata[y].Set(i, color);
404
            }
405
        }
406
 
407
 
408
        public void drawLine(int x0, int y0, int x1, int y1, bool color) {
409
            bool steep = Math.Abs(y1 - y0) > Math.Abs(x1 - x0);
410
            if (steep) {
411
                swap(ref x0, ref y0);
412
                swap(ref x1, ref y1);
413
            }
414
 
415
            if (x0 > x1) {
416
                swap(ref x0, ref x1);
417
                swap(ref y0, ref y1);
418
            }
419
 
420
            int dx, dy;
421
            dx = x1 - x0;
422
            dy = Math.Abs(y1 - y0);
423
 
424
            int err = dx / 2;
425
            int ystep;
426
 
427
            if (y0 < y1)
428
                ystep = 1;
429
            else
430
                ystep = -1;
431
 
432
            for (; x0 <= x1; x0++) {
433
                if (steep)
434
                    drawPixel(y0, x0, color);
435
                else
436
                    drawPixel(x0, y0, color);
437
 
438
                err -= dy;
439
                if (err < 0) {
440
                    y0 += ystep;
441
                    err += dx;
442
                }
443
            }
444
        }
445
 
446
        public void drawRect(int x, int y, int w, int h, bool color) {
447
            drawHLine(x, y, w, color);
448
            drawHLine(x, y + h - 1, w, color);
449
            drawVLine(x, y, h, color);
450
            drawVLine(x + w - 1, y, h, color);
451
        }
452
 
453
        public void fillRect(int x, int y, int w, int h, bool color) {
454
            for (int i = x; i < x + w; i++) {
455
                drawVLine(i, y, h, color);
456
            }
457
        }
458
 
459
 
460
        public void drawCircle(int x0, int y0, int r, bool color) {
461
            int f = 1 - r;
462
            int ddF_x = 1;
463
            int ddF_y = -2 * r;
464
            int x = 0;
465
            int y = r;
466
 
467
            drawPixel(x0, y0 + r, color);
468
            drawPixel(x0, y0 - r, color);
469
            drawPixel(x0 + r, y0, color);
470
            drawPixel(x0 - r, y0, color);
471
 
472
            while (x < y) {
473
                if (f >= 0) {
474
                    y--;
475
                    ddF_y += 2;
476
                    f += ddF_y;
477
                }
478
                x++;
479
                ddF_x += 2;
480
                f += ddF_x;
481
 
482
                drawPixel(x0 + x, y0 + y, color);
483
                drawPixel(x0 - x, y0 + y, color);
484
                drawPixel(x0 + x, y0 - y, color);
485
                drawPixel(x0 - x, y0 - y, color);
486
                drawPixel(x0 + y, y0 + x, color);
487
                drawPixel(x0 - y, y0 + x, color);
488
                drawPixel(x0 + y, y0 - x, color);
489
                drawPixel(x0 - y, y0 - x, color);
490
            }
491
        }
492
 
493
        public void fillCircle(int x0, int y0, int r, bool color) {
494
            drawVLine(x0, y0 - r, 2 * r + 1, color);
495
            fillCircleHelper(x0, y0, r, 3, 0, color);
496
        }
497
 
498
        public void fillCircleHelper(int x0, int y0, int r, int corner, int delta, bool color) {
499
            int f = 1 - r;
500
            int ddF_x = 1;
501
            int ddF_y = -2 * r;
502
            int x = 0;
503
            int y = r;
504
 
505
            while (x < y) {
506
                if (f >= 0) {
507
                    y--;
508
                    ddF_y += 2;
509
                    f += ddF_y;
510
                }
511
                x++;
512
                ddF_x += 2;
513
                f += ddF_x;
514
 
515
                if ((corner & 0x01) > 0) {
516
                    drawVLine(x0 + x, y0 - y, 2 * y + 1 + delta, color);
517
                    drawVLine(x0 + y, y0 - x, 2 * x + 1 + delta, color);
518
                }
519
 
520
                if ((corner & 0x02) > 0) {
521
                    drawVLine(x0 - x, y0 - y, 2 * y + 1 + delta, color);
522
                    drawVLine(x0 - y, y0 - x, 2 * x + 1 + delta, color);
523
                }
524
            }
525
        }
526
 
527
        public void drawTriangle(int x0, int y0, int x1, int y1, int x2, int y2, bool color) {
528
            drawLine(x0, y0, x1, y1, color);
529
            drawLine(x1, y1, x2, y2, color);
530
            drawLine(x2, y2, x0, y0, color);
531
        }
532
 
533
        public void drawPoly(Point[] points, bool color) {
534
            int idx = 1;
535
            int c = points.Length;
536
            while (idx < c) {
537
                drawLine(points[idx - 1].X, points[idx - 1].Y, points[idx].X, points[idx].Y, color);
538
                idx++;
539
            }
540
            drawLine(points[c - 1].X, points[c - 1].Y, points[0].X, points[0].Y, color);
541
        }
542
 
543
        public void drawChar(int x, int y, byte c, bool color, int size) {
544
            for (int i = 0; i < 6; i++) {
545
                byte line;
546
                if (i < 5)
547
                    line = Font.classic[c * 5 + i];
548
                else
549
                    line = 0x00;
550
                for (int j = 0; j < 8; j++, line >>= 1) {
551
                    if ((line & 0x01) > 0) {
552
                        if (size == 1)
553
                            drawPixel(x + i, y + j, color);
554
                        else
555
                            fillRect(x + (i * size), y + (j * size), size, size, color);
556
                    }
557
                    /*
558
                    } else {
559
                        if (size == 1)
560
                            drawPixel(x + i, y + j, !color);
561
                        else
562
                            fillRect(x+i*size, y+j*size, size, size, !color);
563
                    }
564
                    */
565
                }
566
 
567
            }
568
        }
569
 
570
        public void write(string text, int x, int y, bool color, int size) {
571
            Point cur = new Point(x, y);
572
            foreach (byte c in text) {
573
                if (c == '\n') {
574
                    cur.Y += size * 8;
575
                    cur.X = x;
576
                } else if (c == '\r') {
577
 
578
                } else if (c == ' ') {
579
                    // Quicker then calling drawChar function
580
                    cur.X += size * 6;
581
                } else {
582
                    drawChar(cur.X, cur.Y, c, color, size);
583
                    cur.X += size * 6;
584
                }
585
            }
586
        }
587
 
588
        public static void swap(ref int i, ref int j) {
589
            int t = i; i = j; j = t;
590
        }
591
 
592
 
593
        /// <summary>
594
        /// Copies the provided image onto the objects image, at position specified
595
        /// by the ox and oy parms. Only copies lit bits (not dark)
596
        /// </summary>
597
        /// <param name="bit">The bit image to paste onto this image</param>
598
        /// <param name="ox">The X origin</param>
599
        /// <param name="oy">The Y origin</param>
600
        public void blit(BitImage bit, int ox, int oy) {
601
            int x = 0;
602
            int y = 0;
603
 
604
            for (y = 0; y < bit.height; y++) {
605
                for (x = 0; x < bit.width; x++) {
606
                    if (bit.bitdata[y].Get(x)) {
607
                        this.bitdata[oy + y].Set(ox + x, true);
608
                    }
609
                }
610
            }
611
        }
612
 
613
        /// <summary>
614
        /// Rotate the image by the specified degrees.
615
        /// </summary>
616
        /// <param name="degrees">Degrees to rotate</param>
617
        public void rotate(int degrees) {
618
            this.bitdata = (BitArray[])BitImage.rotateMatrix(this.bitdata, degrees).bitdata;
619
            this.width = this.bitdata[0].Length;
620
            this.height = this.bitdata.Length;
621
        }
622
 
623
        public byte[] toByteArray() {
624
            return BitImage.toByteArray(this.bitdata);
625
        }
626
 
627
        public static BitArray[] copy(BitArray[] ba) {
628
            int width = ba[0].Length;
629
            int height = ba.Length;
630
 
631
            BitArray[] newba = new BitArray[height];
632
 
633
            for (int y = 0; y < height; y++) {
634
                newba[y] = new BitArray(width);
635
                for (int x = 0; x < width; x++) {
636
                    if (ba[y].Get(x)) {
637
                        newba[y].Set(x, true);
638
                    }
639
                }
640
            }
641
            return newba;
642
        }
643
 
644
        public static byte[] toByteArray(BitArray[] ba) {
645
            int width = ba[0].Length;
646
            int height = ba.Length;
647
 
648
            int size = width * height / 8;
649
            byte[] buffer = new byte[size];
650
            if (size % 8 != 0) {
651
                Console.WriteLine("toByteArray only supports mod 8 array (size: {0}, misalinged by {1})", size, size % 8);
652
                return null;
653
            }
654
 
655
            for (int y = 0; y < ba.Length; y++) {
656
                byte[] bytes = new byte[ba[0].Length / 8];
657
                ba[y].CopyTo(bytes, 0);
658
                for (int i = 0; i < bytes.Length; i++) {
659
                    buffer[y * bytes.Length + i] = bytes[i];
660
                }
661
            }
662
 
663
            return buffer;
664
        }
665
 
666
        /// <summary>
667
        /// Rotates a matrix by provided degrees. Note that the size of the
668
        ///  image may change with this process
669
        /// </summary>
670
        /// <returns>A matrix with the rotated elements</returns>
671
        /// <param name="matrix">The BitArray matrix to be rotated</param>
672
        /// <param name="degrees">The degress to rotate the matrix by</param>
673
        public static BitImage rotateMatrix(BitArray[] matrix, int degrees) {
674
            // Widths of the matrix
675
            int oldwidth = matrix[0].Length;
676
            int oldheight = matrix.Length;
677
 
678
            // If no rotation nessecary, just return a new BitImage
679
            if (degrees == 0 || degrees == 360) {
680
                BitImage bit = new BitImage(oldwidth, oldheight);
681
                bit.bitdata = (BitArray[])matrix;
682
                return bit;
683
            }
684
 
685
            // Calc the new image meta data
686
            double rads = degrees * Math.PI / 180;
687
            double tcos = Math.Cos(rads);
688
            double tsin = Math.Sin(rads);
689
 
690
            Point p1 = new Point((int)(-oldheight * tsin), (int)(oldheight * tcos));
691
            Point p2 = new Point((int)(oldwidth * tcos - oldheight * tsin),
692
                (int)(oldheight * tcos + oldwidth * tsin));
693
            Point p3 = new Point((int)(oldwidth * tcos), (int)(oldwidth * tsin));
694
            Point min = new Point(Math.Min(0, Math.Min(p1.X, Math.Min(p2.X, p3.X))),
695
                Math.Min(0, Math.Min(p1.Y, Math.Min(p2.Y, p3.Y))));
696
            Point max = new Point(Math.Max(p1.X, Math.Max(p2.X, p3.X)),
697
                Math.Max(p1.Y, Math.Max(p2.Y, p3.Y)));
698
            Point size = new Point(max.X - min.X, max.Y - min.Y);
699
 
700
            // Prepopulate the bitarray
701
            BitArray[] bitmatrix = new BitArray[size.Y];
702
            for (int y = 0; y < size.Y; y++) {
703
                bitmatrix[y] = new BitArray(size.X);
704
            }
705
 
706
            // Transform pixel by pixel
707
            for (int y = 0; y < size.Y - 1; y++) {
708
                for (int x = 0; x < size.X - 1; x++) {
709
                    int sourcex = (int)((x + min.X) * tcos + (y + min.Y) * tsin);
710
                    int sourcey = (int)((y + min.Y) * tcos - (x + min.X) * tsin);
711
 
712
                    if (sourcex < 0 || sourcex > oldwidth - 1 || sourcey < 0 || sourcey > oldheight - 1)
713
                        continue;
714
                    if (x < 0 || x > size.X - 1 || y < 0 || y > size.Y - 1)
715
                        continue;
716
 
717
                    bitmatrix[y].Set(x, matrix[sourcey].Get(sourcex));
718
                }
719
            }
720
 
721
            BitImage bi = new BitImage(bitmatrix[0].Length, bitmatrix.Length);
722
            bi.bitdata = (BitArray[])bitmatrix;
723
            return bi;
724
        }
725
 
726
    }
727
 
728
    public struct Point {
729
        private int x;
730
        private int y;
731
 
732
        public int X {
733
            get {
734
                return this.x;
735
            }
736
            set {
737
                this.x = value;
738
            }
739
        }
740
 
741
        public int Y {
742
            get {
743
                return this.y;
744
            }
745
            set {
746
                this.y = value;
747
            }
748
        }
749
 
750
        public Point(int x, int y) {
751
            this.x = x;
752
            this.y = y;
753
        }
754
    }
755
 
756
    public class Font {
757
        public Font() {
758
        }
759
 
760
        public static byte[] classic = new byte[] {
761
            0x00, 0x00, 0x00, 0x00, 0x00,
762
            0x3E, 0x5B, 0x4F, 0x5B, 0x3E,
763
            0x3E, 0x6B, 0x4F, 0x6B, 0x3E,
764
            0x1C, 0x3E, 0x7C, 0x3E, 0x1C,
765
            0x18, 0x3C, 0x7E, 0x3C, 0x18,
766
            0x1C, 0x57, 0x7D, 0x57, 0x1C,
767
            0x1C, 0x5E, 0x7F, 0x5E, 0x1C,
768
            0x00, 0x18, 0x3C, 0x18, 0x00,
769
            0xFF, 0xE7, 0xC3, 0xE7, 0xFF,
770
            0x00, 0x18, 0x24, 0x18, 0x00,
771
            0xFF, 0xE7, 0xDB, 0xE7, 0xFF,
772
            0x30, 0x48, 0x3A, 0x06, 0x0E,
773
            0x26, 0x29, 0x79, 0x29, 0x26,
774
            0x40, 0x7F, 0x05, 0x05, 0x07,
775
            0x40, 0x7F, 0x05, 0x25, 0x3F,
776
            0x5A, 0x3C, 0xE7, 0x3C, 0x5A,
777
            0x7F, 0x3E, 0x1C, 0x1C, 0x08,
778
            0x08, 0x1C, 0x1C, 0x3E, 0x7F,
779
            0x14, 0x22, 0x7F, 0x22, 0x14,
780
            0x5F, 0x5F, 0x00, 0x5F, 0x5F,
781
            0x06, 0x09, 0x7F, 0x01, 0x7F,
782
            0x00, 0x66, 0x89, 0x95, 0x6A,
783
            0x60, 0x60, 0x60, 0x60, 0x60,
784
            0x94, 0xA2, 0xFF, 0xA2, 0x94,
785
            0x08, 0x04, 0x7E, 0x04, 0x08,
786
            0x10, 0x20, 0x7E, 0x20, 0x10,
787
            0x08, 0x08, 0x2A, 0x1C, 0x08,
788
            0x08, 0x1C, 0x2A, 0x08, 0x08,
789
            0x1E, 0x10, 0x10, 0x10, 0x10,
790
            0x0C, 0x1E, 0x0C, 0x1E, 0x0C,
791
            0x30, 0x38, 0x3E, 0x38, 0x30,
792
            0x06, 0x0E, 0x3E, 0x0E, 0x06,
793
            0x00, 0x00, 0x00, 0x00, 0x00,
794
            0x00, 0x00, 0x5F, 0x00, 0x00,
795
            0x00, 0x07, 0x00, 0x07, 0x00,
796
            0x14, 0x7F, 0x14, 0x7F, 0x14,
797
            0x24, 0x2A, 0x7F, 0x2A, 0x12,
798
            0x23, 0x13, 0x08, 0x64, 0x62,
799
            0x36, 0x49, 0x56, 0x20, 0x50,
800
            0x00, 0x08, 0x07, 0x03, 0x00,
801
            0x00, 0x1C, 0x22, 0x41, 0x00,
802
            0x00, 0x41, 0x22, 0x1C, 0x00,
803
            0x2A, 0x1C, 0x7F, 0x1C, 0x2A,
804
            0x08, 0x08, 0x3E, 0x08, 0x08,
805
            0x00, 0x80, 0x70, 0x30, 0x00,
806
            0x08, 0x08, 0x08, 0x08, 0x08,
807
            0x00, 0x00, 0x60, 0x60, 0x00,
808
            0x20, 0x10, 0x08, 0x04, 0x02,
809
            0x3E, 0x51, 0x49, 0x45, 0x3E,
810
            0x00, 0x42, 0x7F, 0x40, 0x00,
811
            0x72, 0x49, 0x49, 0x49, 0x46,
812
            0x21, 0x41, 0x49, 0x4D, 0x33,
813
            0x18, 0x14, 0x12, 0x7F, 0x10,
814
            0x27, 0x45, 0x45, 0x45, 0x39,
815
            0x3C, 0x4A, 0x49, 0x49, 0x31,
816
            0x41, 0x21, 0x11, 0x09, 0x07,
817
            0x36, 0x49, 0x49, 0x49, 0x36,
818
            0x46, 0x49, 0x49, 0x29, 0x1E,
819
            0x00, 0x00, 0x14, 0x00, 0x00,
820
            0x00, 0x40, 0x34, 0x00, 0x00,
821
            0x00, 0x08, 0x14, 0x22, 0x41,
822
            0x14, 0x14, 0x14, 0x14, 0x14,
823
            0x00, 0x41, 0x22, 0x14, 0x08,
824
            0x02, 0x01, 0x59, 0x09, 0x06,
825
            0x3E, 0x41, 0x5D, 0x59, 0x4E,
826
            0x7C, 0x12, 0x11, 0x12, 0x7C,
827
            0x7F, 0x49, 0x49, 0x49, 0x36,
828
            0x3E, 0x41, 0x41, 0x41, 0x22,
829
            0x7F, 0x41, 0x41, 0x41, 0x3E,
830
            0x7F, 0x49, 0x49, 0x49, 0x41,
831
            0x7F, 0x09, 0x09, 0x09, 0x01,
832
            0x3E, 0x41, 0x41, 0x51, 0x73,
833
            0x7F, 0x08, 0x08, 0x08, 0x7F,
834
            0x00, 0x41, 0x7F, 0x41, 0x00,
835
            0x20, 0x40, 0x41, 0x3F, 0x01,
836
            0x7F, 0x08, 0x14, 0x22, 0x41,
837
            0x7F, 0x40, 0x40, 0x40, 0x40,
838
            0x7F, 0x02, 0x1C, 0x02, 0x7F,
839
            0x7F, 0x04, 0x08, 0x10, 0x7F,
840
            0x3E, 0x41, 0x41, 0x41, 0x3E,
841
            0x7F, 0x09, 0x09, 0x09, 0x06,
842
            0x3E, 0x41, 0x51, 0x21, 0x5E,
843
            0x7F, 0x09, 0x19, 0x29, 0x46,
844
            0x26, 0x49, 0x49, 0x49, 0x32,
845
            0x03, 0x01, 0x7F, 0x01, 0x03,
846
            0x3F, 0x40, 0x40, 0x40, 0x3F,
847
            0x1F, 0x20, 0x40, 0x20, 0x1F,
848
            0x3F, 0x40, 0x38, 0x40, 0x3F,
849
            0x63, 0x14, 0x08, 0x14, 0x63,
850
            0x03, 0x04, 0x78, 0x04, 0x03,
851
            0x61, 0x59, 0x49, 0x4D, 0x43,
852
            0x00, 0x7F, 0x41, 0x41, 0x41,
853
            0x02, 0x04, 0x08, 0x10, 0x20,
854
            0x00, 0x41, 0x41, 0x41, 0x7F,
855
            0x04, 0x02, 0x01, 0x02, 0x04,
856
            0x40, 0x40, 0x40, 0x40, 0x40,
857
            0x00, 0x03, 0x07, 0x08, 0x00,
858
            0x20, 0x54, 0x54, 0x78, 0x40,
859
            0x7F, 0x28, 0x44, 0x44, 0x38,
860
            0x38, 0x44, 0x44, 0x44, 0x28,
861
            0x38, 0x44, 0x44, 0x28, 0x7F,
862
            0x38, 0x54, 0x54, 0x54, 0x18,
863
            0x00, 0x08, 0x7E, 0x09, 0x02,
864
            0x18, 0xA4, 0xA4, 0x9C, 0x78,
865
            0x7F, 0x08, 0x04, 0x04, 0x78,
866
            0x00, 0x44, 0x7D, 0x40, 0x00,
867
            0x20, 0x40, 0x40, 0x3D, 0x00,
868
            0x7F, 0x10, 0x28, 0x44, 0x00,
869
            0x00, 0x41, 0x7F, 0x40, 0x00,
870
            0x7C, 0x04, 0x78, 0x04, 0x78,
871
            0x7C, 0x08, 0x04, 0x04, 0x78,
872
            0x38, 0x44, 0x44, 0x44, 0x38,
873
            0xFC, 0x18, 0x24, 0x24, 0x18,
874
            0x18, 0x24, 0x24, 0x18, 0xFC,
875
            0x7C, 0x08, 0x04, 0x04, 0x08,
876
            0x48, 0x54, 0x54, 0x54, 0x24,
877
            0x04, 0x04, 0x3F, 0x44, 0x24,
878
            0x3C, 0x40, 0x40, 0x20, 0x7C,
879
            0x1C, 0x20, 0x40, 0x20, 0x1C,
880
            0x3C, 0x40, 0x30, 0x40, 0x3C,
881
            0x44, 0x28, 0x10, 0x28, 0x44,
882
            0x4C, 0x90, 0x90, 0x90, 0x7C,
883
            0x44, 0x64, 0x54, 0x4C, 0x44,
884
            0x00, 0x08, 0x36, 0x41, 0x00,
885
            0x00, 0x00, 0x77, 0x00, 0x00,
886
            0x00, 0x41, 0x36, 0x08, 0x00,
887
            0x02, 0x01, 0x02, 0x04, 0x02,
888
            0x3C, 0x26, 0x23, 0x26, 0x3C,
889
            0x1E, 0xA1, 0xA1, 0x61, 0x12,
890
            0x3A, 0x40, 0x40, 0x20, 0x7A,
891
            0x38, 0x54, 0x54, 0x55, 0x59,
892
            0x21, 0x55, 0x55, 0x79, 0x41,
893
            0x22, 0x54, 0x54, 0x78, 0x42, // a-umlaut
894
            0x21, 0x55, 0x54, 0x78, 0x40,
895
            0x20, 0x54, 0x55, 0x79, 0x40,
896
            0x0C, 0x1E, 0x52, 0x72, 0x12,
897
            0x39, 0x55, 0x55, 0x55, 0x59,
898
            0x39, 0x54, 0x54, 0x54, 0x59,
899
            0x39, 0x55, 0x54, 0x54, 0x58,
900
            0x00, 0x00, 0x45, 0x7C, 0x41,
901
            0x00, 0x02, 0x45, 0x7D, 0x42,
902
            0x00, 0x01, 0x45, 0x7C, 0x40,
903
            0x7D, 0x12, 0x11, 0x12, 0x7D, // A-umlaut
904
            0xF0, 0x28, 0x25, 0x28, 0xF0,
905
            0x7C, 0x54, 0x55, 0x45, 0x00,
906
            0x20, 0x54, 0x54, 0x7C, 0x54,
907
            0x7C, 0x0A, 0x09, 0x7F, 0x49,
908
            0x32, 0x49, 0x49, 0x49, 0x32,
909
            0x3A, 0x44, 0x44, 0x44, 0x3A, // o-umlaut
910
            0x32, 0x4A, 0x48, 0x48, 0x30,
911
            0x3A, 0x41, 0x41, 0x21, 0x7A,
912
            0x3A, 0x42, 0x40, 0x20, 0x78,
913
            0x00, 0x9D, 0xA0, 0xA0, 0x7D,
914
            0x3D, 0x42, 0x42, 0x42, 0x3D, // O-umlaut
915
            0x3D, 0x40, 0x40, 0x40, 0x3D,
916
            0x3C, 0x24, 0xFF, 0x24, 0x24,
917
            0x48, 0x7E, 0x49, 0x43, 0x66,
918
            0x2B, 0x2F, 0xFC, 0x2F, 0x2B,
919
            0xFF, 0x09, 0x29, 0xF6, 0x20,
920
            0xC0, 0x88, 0x7E, 0x09, 0x03,
921
            0x20, 0x54, 0x54, 0x79, 0x41,
922
            0x00, 0x00, 0x44, 0x7D, 0x41,
923
            0x30, 0x48, 0x48, 0x4A, 0x32,
924
            0x38, 0x40, 0x40, 0x22, 0x7A,
925
            0x00, 0x7A, 0x0A, 0x0A, 0x72,
926
            0x7D, 0x0D, 0x19, 0x31, 0x7D,
927
            0x26, 0x29, 0x29, 0x2F, 0x28,
928
            0x26, 0x29, 0x29, 0x29, 0x26,
929
            0x30, 0x48, 0x4D, 0x40, 0x20,
930
            0x38, 0x08, 0x08, 0x08, 0x08,
931
            0x08, 0x08, 0x08, 0x08, 0x38,
932
            0x2F, 0x10, 0xC8, 0xAC, 0xBA,
933
            0x2F, 0x10, 0x28, 0x34, 0xFA,
934
            0x00, 0x00, 0x7B, 0x00, 0x00,
935
            0x08, 0x14, 0x2A, 0x14, 0x22,
936
            0x22, 0x14, 0x2A, 0x14, 0x08,
937
            0x55, 0x00, 0x55, 0x00, 0x55, // #176 (25% block) missing in old code
938
            0xAA, 0x55, 0xAA, 0x55, 0xAA, // 50% block
939
            0xFF, 0x55, 0xFF, 0x55, 0xFF, // 75% block
940
            0x00, 0x00, 0x00, 0xFF, 0x00,
941
            0x10, 0x10, 0x10, 0xFF, 0x00,
942
            0x14, 0x14, 0x14, 0xFF, 0x00,
943
            0x10, 0x10, 0xFF, 0x00, 0xFF,
944
            0x10, 0x10, 0xF0, 0x10, 0xF0,
945
            0x14, 0x14, 0x14, 0xFC, 0x00,
946
            0x14, 0x14, 0xF7, 0x00, 0xFF,
947
            0x00, 0x00, 0xFF, 0x00, 0xFF,
948
            0x14, 0x14, 0xF4, 0x04, 0xFC,
949
            0x14, 0x14, 0x17, 0x10, 0x1F,
950
            0x10, 0x10, 0x1F, 0x10, 0x1F,
951
            0x14, 0x14, 0x14, 0x1F, 0x00,
952
            0x10, 0x10, 0x10, 0xF0, 0x00,
953
            0x00, 0x00, 0x00, 0x1F, 0x10,
954
            0x10, 0x10, 0x10, 0x1F, 0x10,
955
            0x10, 0x10, 0x10, 0xF0, 0x10,
956
            0x00, 0x00, 0x00, 0xFF, 0x10,
957
            0x10, 0x10, 0x10, 0x10, 0x10,
958
            0x10, 0x10, 0x10, 0xFF, 0x10,
959
            0x00, 0x00, 0x00, 0xFF, 0x14,
960
            0x00, 0x00, 0xFF, 0x00, 0xFF,
961
            0x00, 0x00, 0x1F, 0x10, 0x17,
962
            0x00, 0x00, 0xFC, 0x04, 0xF4,
963
            0x14, 0x14, 0x17, 0x10, 0x17,
964
            0x14, 0x14, 0xF4, 0x04, 0xF4,
965
            0x00, 0x00, 0xFF, 0x00, 0xF7,
966
            0x14, 0x14, 0x14, 0x14, 0x14,
967
            0x14, 0x14, 0xF7, 0x00, 0xF7,
968
            0x14, 0x14, 0x14, 0x17, 0x14,
969
            0x10, 0x10, 0x1F, 0x10, 0x1F,
970
            0x14, 0x14, 0x14, 0xF4, 0x14,
971
            0x10, 0x10, 0xF0, 0x10, 0xF0,
972
            0x00, 0x00, 0x1F, 0x10, 0x1F,
973
            0x00, 0x00, 0x00, 0x1F, 0x14,
974
            0x00, 0x00, 0x00, 0xFC, 0x14,
975
            0x00, 0x00, 0xF0, 0x10, 0xF0,
976
            0x10, 0x10, 0xFF, 0x10, 0xFF,
977
            0x14, 0x14, 0x14, 0xFF, 0x14,
978
            0x10, 0x10, 0x10, 0x1F, 0x00,
979
            0x00, 0x00, 0x00, 0xF0, 0x10,
980
            0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
981
            0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
982
            0xFF, 0xFF, 0xFF, 0x00, 0x00,
983
            0x00, 0x00, 0x00, 0xFF, 0xFF,
984
            0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
985
            0x38, 0x44, 0x44, 0x38, 0x44,
986
            0xFC, 0x4A, 0x4A, 0x4A, 0x34, // sharp-s or beta
987
            0x7E, 0x02, 0x02, 0x06, 0x06,
988
            0x02, 0x7E, 0x02, 0x7E, 0x02,
989
            0x63, 0x55, 0x49, 0x41, 0x63,
990
            0x38, 0x44, 0x44, 0x3C, 0x04,
991
            0x40, 0x7E, 0x20, 0x1E, 0x20,
992
            0x06, 0x02, 0x7E, 0x02, 0x02,
993
            0x99, 0xA5, 0xE7, 0xA5, 0x99,
994
            0x1C, 0x2A, 0x49, 0x2A, 0x1C,
995
            0x4C, 0x72, 0x01, 0x72, 0x4C,
996
            0x30, 0x4A, 0x4D, 0x4D, 0x30,
997
            0x30, 0x48, 0x78, 0x48, 0x30,
998
            0xBC, 0x62, 0x5A, 0x46, 0x3D,
999
            0x3E, 0x49, 0x49, 0x49, 0x00,
1000
            0x7E, 0x01, 0x01, 0x01, 0x7E,
1001
            0x2A, 0x2A, 0x2A, 0x2A, 0x2A,
1002
            0x44, 0x44, 0x5F, 0x44, 0x44,
1003
            0x40, 0x51, 0x4A, 0x44, 0x40,
1004
            0x40, 0x44, 0x4A, 0x51, 0x40,
1005
            0x00, 0x00, 0xFF, 0x01, 0x03,
1006
            0xE0, 0x80, 0xFF, 0x00, 0x00,
1007
            0x08, 0x08, 0x6B, 0x6B, 0x08,
1008
            0x36, 0x12, 0x36, 0x24, 0x36,
1009
            0x06, 0x0F, 0x09, 0x0F, 0x06,
1010
            0x00, 0x00, 0x18, 0x18, 0x00,
1011
            0x00, 0x00, 0x10, 0x10, 0x00,
1012
            0x30, 0x40, 0xFF, 0x01, 0x01,
1013
            0x00, 0x1F, 0x01, 0x01, 0x1E,
1014
            0x00, 0x19, 0x1D, 0x17, 0x12,
1015
            0x00, 0x3C, 0x3C, 0x3C, 0x3C,
1016
            0x00, 0x00, 0x00, 0x00, 0x00  // #255 NBSP
1017
        };
1018
    }
1019
}