iv.sdpy: line drawing fixes
[iv.d.git] / sdpy / bgichr.d
blob617324c14c2dfc07ff44c6c96f7701da8ed1514f
1 /*
2 * Pixel Graphics Library
3 * coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
4 * Understanding is not required. Only obedience.
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, version 3 of the License ONLY.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 module iv.sdpy.bgichr /*is aliced*/;
20 import iv.alice;
21 import iv.sdpy.color;
22 import iv.sdpy.gfxbuf;
24 import iv.vfs;
27 // ////////////////////////////////////////////////////////////////////////// //
28 final class BgiChr {
29 private:
30 enum {
31 OpEnd,
32 OpScan,
33 OpMove,
34 OpDraw,
37 static struct Stroke {
38 ubyte opcode;
39 byte x, y;
42 char[4] name;
43 char[4] type;
44 int ffirstChar;
45 int flastChar;
46 int fascent;
47 int fbase;
48 int fdescent;
49 int[256] wdt;
50 int[256] ffirstStroke;
51 Stroke[] stk;
52 ushort fver, dver; // font and driver versions
54 public:
55 this (const(char)[] fname) {
56 import std.stdio : File;
57 load(File(fname.idup)); // fixme
60 this(ST) (auto ref ST st) if (isReadableStream!ST) {
61 load(st);
64 @property const pure nothrow @safe @nogc {
65 int height () { return fascent-fdescent; }
66 int ascent () { return fascent; }
67 int descent () { return fdescent; }
68 int baseline () { return fbase; }
71 const pure nothrow @safe @nogc {
72 int charWidth (char ch, in float scale=1.0f) { return cast(int)(scale*wdt[cast(ubyte)ch]); }
73 int textWidth (const(char)[] str, in float scale=1.0f) {
74 float w = 0.0f;
75 foreach (immutable ch; str) w += scale*wdt[cast(ubyte)ch];
76 return cast(int)w;
80 int drawChar() (auto ref GfxBuf gb, int x, int y, char ch, VColor clr, in float scale=1.0f) {
81 int sn = ffirstStroke[cast(ubyte)ch];
82 if (sn < 0) return 0;
83 float ox = 0.0f, oy = 0.0f;
84 for (; sn < stk.length && stk[sn].opcode != OpEnd; ++sn) {
85 immutable float nx = scale*stk[sn].x;
86 immutable float ny = scale*stk[sn].y;
87 if (stk[sn].opcode == OpDraw) {
88 immutable bool lastPoint = (sn+1 >= stk.length || stk[sn+1].opcode != OpDraw);
89 gb.line(cast(int)(x+ox), cast(int)(y-oy), cast(int)(x+nx), cast(int)(y-ny), clr, lastPoint);
91 ox = nx;
92 oy = ny;
94 return cast(int)(scale*wdt[ch]);
97 int drawText() (auto ref GfxBuf gb, int x, int y, const(char)[] str, VColor clr, in float scale=1.0f) {
98 int w = 0;
99 foreach (immutable ch; str) {
100 int d = drawChar(gb, x, y, ch, clr, scale);
101 w += d;
102 x += d;
104 return w;
107 private:
108 void load(ST) (auto ref ST st) if (isReadableStream!ST) {
109 char[4] sign;
110 int dataSize, charCount, stkOfs, dataOfs;
111 int snum, btcount;
112 // signature
113 st.rawReadExact(sign[0..4]);
114 if (sign != "PK\x08\x08") throw new Exception("invalid CHR signature");
115 // font type ("BGI ", "LCD ")
116 st.rawReadExact(type[0..4]);
117 // skip description
118 btcount = 8; // temp counter
119 for (;;) {
120 ubyte b = st.readNum!ubyte();
121 ++btcount;
122 if (b == 26) break;
123 if (btcount > 65535) throw new Exception("CHR description too long");
125 // header size
126 dataOfs = st.readNum!ushort();
127 btcount += 2;
128 // internal name
129 st.rawReadExact(name[0..4]);
130 btcount += 4;
131 // data size
132 dataSize = st.readNum!ushort();
133 btcount += 2;
134 if (dataSize < 2) throw new Exception("invalid CHR data size");
135 // versions
136 fver = cast(ushort)(st.readNum!ubyte()<<8);
137 fver |= st.readNum!ubyte();
138 dver = cast(ushort)(st.readNum!ubyte()<<8);
139 dver |= st.readNum!ubyte();
140 btcount += 4;
141 // skip other header bytes
142 if (dataOfs < btcount) throw new Exception("invalid CHR data offset");
143 while (btcount < dataOfs) { st.readNum!ubyte(); ++btcount; }
144 btcount = 0;
145 // signature
146 //debug { import std.stdio; writefln("ofs=0x%08x", st.tell); }
147 if (st.readNum!ubyte() != '+') throw new Exception("invalid CHR data signature");
148 ++btcount;
149 // number of chars
150 charCount = st.readNum!ushort();
151 btcount += 2;
152 if (charCount < 1 || charCount > 255) throw new Exception("invalid CHR character count");
153 // meaningless byte
154 st.readNum!ubyte();
155 ++btcount;
156 // first char
157 ffirstChar = st.readNum!ubyte();
158 ++btcount;
159 // offset to stroke data (from the start of this header)
160 stkOfs = st.readNum!ushort();
161 btcount += 2;
162 // scanable flag
163 st.readNum!ubyte();
164 ++btcount;
165 // capitals height
166 fascent = st.readNum!byte();
167 ++btcount;
168 // baseline
169 fbase = st.readNum!byte();
170 ++btcount;
171 // decender height
172 fdescent = st.readNum!byte();
173 ++btcount;
174 // internal font name
175 st.rawReadExact(sign[0..4]);
176 btcount += 4;
177 // unused byte
178 st.readNum!byte();
179 ++btcount;
180 // stroke offsets in stroke data
181 ffirstStroke[] = -1;
182 wdt[] = 0;
183 //debug { import std.stdio; writefln("stofs=0x%08x", st.tell); }
184 foreach (int cn; ffirstChar..ffirstChar+charCount) {
185 auto fs = st.readNum!ushort();
186 btcount += 2;
187 if (fs < 0 || fs%2) throw new Exception("invalid CHR stroke offset");
188 if (cn < 256) ffirstStroke[cn] = fs/2;
190 //debug { import std.stdio; writefln("wdtofs=0x%08x", st.tell); }
191 // char width table
192 foreach (int cn; ffirstChar..ffirstChar+charCount) {
193 auto w = st.readNum!ubyte();
194 ++btcount;
195 if (cn < 256) wdt[cn] = w;
197 // move to stroke data
198 if (btcount > stkOfs) throw new Exception("invalid CHR stroke data offset");
199 while (btcount < stkOfs) { st.readNum!ubyte(); ++btcount; }
200 // read stroke data
201 //debug { import std.stdio; writefln("sdofs=0x%08x", st.tell); }
202 if ((dataSize -= btcount) < 2) throw new Exception("invalid CHR no stroke data");
203 stk.length = dataSize/2;
204 foreach (ref s; stk) {
205 int x, y, op;
206 if (dataSize == 1) {
207 st.readNum!ubyte();
208 break;
210 x = st.readNum!ubyte();
211 y = st.readNum!ubyte();
212 dataSize -= 2;
213 op = (x>>7)|((y>>6)&0x02);
214 if ((x &= 0x7f) > 63) x -= 128;
215 if ((y &= 0x7f) > 63) y -= 128;
216 s.opcode = cast(ubyte)op;
217 s.x = cast(byte)x;
218 s.y = cast(byte)y;
220 flastChar = ffirstChar+charCount-1;
221 if (flastChar > 255) flastChar = 255;