Subversion Repositories group.electronics

Rev

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