"C-Period" to find my messages; "C-Insert" to copy post URL to clipboard
[knntp.git] / egfx.d
blobbc6f3246ec3c8c1b79b82bc8cc79c76ef8f6c440
1 /* DigitalMars NNTP reader
2 * coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
3 * Understanding is not required. Only obedience.
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
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 egfx is aliced;
19 private:
21 import core.atomic;
22 import std.concurrency;
24 import arsd.simpledisplay;
26 import iv.bclamp;
27 import iv.cmdcon;
28 import iv.utfutil;
29 import iv.vfs;
31 //version = cp866;
32 enum FontHeight = 9;
35 // ////////////////////////////////////////////////////////////////////////// //
36 public char uni2local (dchar dch) nothrow @trusted @nogc {
37 if (!Utf8DecoderFast.isValidDC(dch)) {
38 version(cp866) return '\xb0'; else return '\x97';
40 switch (cast(uint)dch) {
41 case 0: return ' ';
42 case 0x00F6: return 'o';
43 case 0x00F8: return 'o';
44 case 0x00FC: return 'u';
45 case 0x0308: return 'C';
46 case 0x032A: return 's';
47 case 0x033B: return 'o';
48 case 0x00E1: return 'a';
49 case 0x00ED: return 'i';
50 default:
51 version(cp866) return uni2cp866!'\xb0'(dch); else return uni2koi!'\x97'(dch);
56 public @property string triangleUpStr () nothrow @safe @nogc { version(cp866) return "\x1f"; else return "\x8d"; }
57 public @property string triangleDownStr () nothrow @safe @nogc { version(cp866) return "\x1e"; else return "\x8e"; }
59 public @property string arrowLeftStr () nothrow @safe @nogc { version(cp866) return "\x1b"; else return "\x90"; }
60 public @property string arrowRightStr () nothrow @safe @nogc { version(cp866) return "\x1a"; else return "\x8f"; }
63 // ////////////////////////////////////////////////////////////////////////// //
64 public void utfByLocal (const(char)[] s, scope void delegate (char ch) nothrow @trusted @nogc dg) nothrow @trusted @nogc {
65 if (dg is null) return;
66 Utf8DecoderFast dc;
67 foreach (char ch; s) {
68 if (dc.decode(cast(ubyte)ch)) dg(uni2local(dc.codepoint));
73 // ////////////////////////////////////////////////////////////////////////// //
74 //mixin(import("egfxfont.d"));
75 // font: (hi nibble: lshift; lo nibble: width); 8 data bytes
76 version(cp866) {
77 static immutable ubyte[] font6x8p = cast(immutable(ubyte)[])import("databin/zxpfont866.fnt");
78 } else {
79 static immutable ubyte[] font6x8p = cast(immutable(ubyte)[])import("databin/zxpfontkoi.fnt");
83 // ////////////////////////////////////////////////////////////////////////// //
84 //public enum GLTexType = GL_RGBA;
85 public enum GLTexType = GL_BGRA;
87 public __gshared int VBufWidth = 640;
88 public __gshared int VBufHeight = 480;
89 public __gshared ubyte VBufScale = 2; // new window scale
90 public __gshared ubyte vbufEffScale = 2; // effective (current) window scale
92 public __gshared uint[] zxtexbuf; // OpenGL texture buffer
93 public __gshared uint vArrowTextureId = 0;
95 shared static this () {
96 zxtexbuf.length = VBufWidth*VBufHeight+4;
100 public @property int winWidth () nothrow @trusted @nogc { pragma(inline, true); return VBufWidth; }
101 public @property int winHeight () nothrow @trusted @nogc { pragma(inline, true); return VBufHeight; }
103 public @property int winWidthScaled () nothrow @trusted @nogc { pragma(inline, true); return VBufWidth*vbufEffScale; }
104 public @property int winHeightScaled () nothrow @trusted @nogc { pragma(inline, true); return VBufHeight*vbufEffScale; }
107 // ////////////////////////////////////////////////////////////////////////// //
108 public void createArrowTexture () {
109 import iv.glbinds;
111 enum wrapOpt = GL_REPEAT;
112 enum filterOpt = GL_NEAREST; //GL_LINEAR;
113 enum ttype = GL_UNSIGNED_BYTE;
115 if (vArrowTextureId) glDeleteTextures(1, &vArrowTextureId);
116 vArrowTextureId = 0;
117 glGenTextures(1, &vArrowTextureId);
118 if (vArrowTextureId == 0) assert(0, "can't create arrow texture");
120 //GLint gltextbinding;
121 //glGetIntegerv(GL_TEXTURE_BINDING_2D, &gltextbinding);
122 //scope(exit) glBindTexture(GL_TEXTURE_2D, gltextbinding);
124 glBindTexture(GL_TEXTURE_2D, vArrowTextureId);
125 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapOpt);
126 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapOpt);
127 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filterOpt);
128 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filterOpt);
129 //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
130 //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
132 GLfloat[4] bclr = 0.0;
133 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, bclr.ptr);
135 uint[16*8] pmap = 0x00_000000U;
136 // sprite,sprite,mask,mask
137 static immutable ushort[$] spx = [
138 0b11111111_10000000, 0b00000000_01111111,
139 0b01000000_10000000, 0b10000000_01111111,
140 0b00100000_10000000, 0b11000000_01111111,
141 0b00010000_01100000, 0b11100000_00011111,
142 0b00001001_10011000, 0b11110000_00000111,
143 0b00000110_01100110, 0b11111001_10000001,
144 0b00000000_00011001, 0b11111111_11100000,
145 0b00000000_00000110, 0b11111111_11111001,
148 foreach (immutable dy; 0..8) {
149 ushort spr = spx[dy*2+0];
150 ushort msk = spx[dy*2+1];
151 foreach (immutable dx; 0..16) {
152 if ((msk&0x8000) == 0) {
153 pmap[dy*16+dx] = (spr&0x8000 ? 0xff_ffffffU : 0xff_000000U);
155 msk <<= 1;
156 spr <<= 1;
159 //pmap = 0xff_ff0000U;
160 //pmap[0] = 0;
162 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 8, 0, GLTexType, GL_UNSIGNED_BYTE, pmap.ptr);
165 // ////////////////////////////////////////////////////////////////////////// //
166 // mix dc with ARGB (or ABGR) col; dc A is ignored (removed)
167 public uint gxColMix (uint dc, uint col) pure nothrow @trusted @nogc {
168 pragma(inline, true);
169 immutable uint a = 256-(col>>24); // to not loose bits
170 //immutable uint dc = (da)&0xffffff;
171 dc &= 0xffffff;
172 immutable uint srb = (col&0xff00ff);
173 immutable uint sg = (col&0x00ff00);
174 immutable uint drb = (dc&0xff00ff);
175 immutable uint dg = (dc&0x00ff00);
176 immutable uint orb = (drb+(((srb-drb)*a+0x800080)>>8))&0xff00ff;
177 immutable uint og = (dg+(((sg-dg)*a+0x008000)>>8))&0x00ff00;
178 return orb|og;
182 // ////////////////////////////////////////////////////////////////////////// //
183 private template isGoodRGBInt(T) {
184 import std.traits : Unqual;
185 alias TT = Unqual!T;
186 enum isGoodRGBInt =
187 is(TT == ubyte) ||
188 is(TT == short) || is(TT == ushort) ||
189 is(TT == int) || is(TT == uint) ||
190 is(TT == long) || is(TT == ulong);
194 // ////////////////////////////////////////////////////////////////////////// //
195 public uint ztrgb(T0, T1, T2) (T0 r, T1 g, T2 b) pure nothrow @trusted @nogc if (isGoodRGBInt!T0 && isGoodRGBInt!T1 && isGoodRGBInt!T2) {
196 pragma(inline, true);
197 return (clampToByte(r)<<16)|(clampToByte(g)<<8)|clampToByte(b);
201 public template gxRGB(int r, int g, int b) {
202 enum gxRGB = (clampToByte(r)<<16)|(clampToByte(g)<<8)|clampToByte(b);
205 public template gxRGBA(int r, int g, int b, int a) {
206 enum gxRGBA = (clampToByte(a)<<24)|(clampToByte(r)<<16)|(clampToByte(g)<<8)|clampToByte(b);
210 // ////////////////////////////////////////////////////////////////////////// //
211 public __gshared int clipX0 = 0, clipY0 = 0;
212 public __gshared int clipX1 = 65535, clipY1 = 65535;
215 public void clipReset () nothrow @trusted @nogc {
216 clipX0 = clipY0 = 0;
217 clipX1 = clipY1 = 65535;
221 public int clipWidth () nothrow @trusted @nogc { return (clipX0 <= clipX1 ? clipX1-clipX0+1 : 0); }
222 public int clipHeight () nothrow @trusted @nogc { return (clipY0 <= clipY1 ? clipY1-clipY0+1 : 0); }
224 public void clipShrink (int dx, int dy) nothrow @trusted @nogc {
225 clipX0 += dx;
226 clipY0 += dy;
227 clipX1 -= dx;
228 clipY1 -= dy;
231 public void clipGrow (int dx, int dy) nothrow @trusted @nogc {
232 clipX0 -= dx;
233 clipY0 -= dy;
234 clipX1 += dx;
235 clipY1 += dy;
239 // ////////////////////////////////////////////////////////////////////////// //
240 public void gxPutPixel (int x, int y, uint c) nothrow @trusted @nogc {
241 pragma(inline, true);
242 if (x >= 0 && y >= 0 && x < VBufWidth && y < VBufHeight && (c&0xff000000) != 0xff000000) {
243 if (x >= clipX0 && y >= clipY0 && x <= clipX1 && y <= clipY1) {
245 ubyte* dp = cast(ubyte*)zxtexbuf.ptr;
246 dp += y*(VBufWidth*4)+x*4;
247 *dp++ = (c>>16)&0xff; //R
248 *dp++ = (c>>8)&0xff; //G
249 *dp++ = c&0xff; //B
250 *dp = 0;
252 uint* dp = cast(uint*)(cast(ubyte*)zxtexbuf.ptr)+y*VBufWidth+x;
253 *dp = gxColMix(*dp, c);
259 // ////////////////////////////////////////////////////////////////////////// //
260 public void gxDrawCharM (int x, int y, char ch, uint fg, uint bg=0xff000000) nothrow @trusted @nogc {
261 if (FontHeight > 8) y += 1;
262 foreach (immutable dy; 1..9) {
263 ubyte b = font6x8p.ptr[cast(uint)ch*9+dy];
264 if (b) {
265 foreach (immutable dx; 0..6) {
266 gxPutPixel(x+dx, y, (b&0x80 ? fg : bg));
267 b <<= 1;
270 ++y;
275 // return char width
276 public int gxDrawCharP (int x, int y, char ch, uint fg, uint bg=0xff000000) nothrow @trusted @nogc {
277 if (FontHeight > 8) y += 1;
278 ubyte wdt = font6x8p.ptr[cast(uint)ch*9];
279 ubyte shift = wdt>>4;
280 wdt &= 0x0f;
281 foreach (immutable dy; 1..9) {
282 ubyte b = cast(ubyte)(font6x8p.ptr[cast(uint)ch*9+dy]<<shift);
283 if (b) {
284 foreach (immutable dx; 0..wdt) {
285 gxPutPixel(x+dx, y, (b&0x80 ? fg : bg));
286 b <<= 1;
289 ++y;
291 return wdt;
295 public int gxCharWidthP (char ch) nothrow @trusted @nogc { return font6x8p.ptr[cast(uint)ch*9]; }
298 public int gxCharWidthScaledP (int scale, char ch) nothrow @trusted @nogc { return (scale < 1 ? 0 : font6x8p.ptr[cast(uint)ch*9]*scale); }
301 // return char width
302 public int gxDrawCharScaledP (int scale, int x, int y, char ch, uint fg, uint bg=0xff000000) nothrow @trusted @nogc {
303 if (scale < 1) return 0;
304 if (FontHeight > 8) y += scale;
305 ubyte wdt = font6x8p.ptr[cast(uint)ch*9];
306 ubyte shift = wdt>>4;
307 wdt &= 0x0f;
308 foreach (immutable dy; 1..9) {
309 ubyte b = cast(ubyte)(font6x8p.ptr[cast(uint)ch*9+dy]<<shift);
310 if (b) {
311 foreach (immutable dx; 0..wdt) {
312 foreach (immutable scx; 0..scale) {
313 foreach (immutable scy; 0..scale) {
314 gxPutPixel(x+dx*scale+scx, y+scy, (b&0x80 ? fg : bg));
317 b <<= 1;
320 y += scale;
322 return wdt*scale;
326 // ////////////////////////////////////////////////////////////////////////// //
327 public int gxTextWidthM (const(char)[] s) nothrow @trusted @nogc { return cast(int)s.length*6; }
328 public int gxTextHeightM () nothrow @trusted @nogc { return FontHeight; }
331 public int gxTextWidthP (const(char)[] s) nothrow @trusted @nogc {
332 int res = 0;
333 foreach (char ch; s) {
334 if (res) ++res;
335 res += font6x8p.ptr[cast(uint)ch*9];
337 return res;
339 public int gxTextHeightP () nothrow @trusted @nogc { return FontHeight; }
342 public int gxTextWidthScaledP (int scale, const(char)[] s) nothrow @trusted @nogc {
343 if (scale < 1) return 0;
344 int res = 0;
345 foreach (char ch; s) {
346 res += (font6x8p.ptr[cast(uint)ch*9]+1)*scale;
348 if (res) res -= scale;
349 return res;
351 public int gxTextHeightScaledP (int scale) nothrow @trusted @nogc { return (scale < 1 ? 0 : FontHeight*scale); }
354 // ////////////////////////////////////////////////////////////////////////// //
355 public void gxDrawTextM (int x, int y, const(char)[] s, uint fg, uint bg=0xff000000) nothrow @trusted @nogc {
356 foreach (char ch; s) {
357 gxDrawCharM(x, y, ch, fg, bg);
358 x += 6;
363 // return text width
364 public int gxDrawTextP (int x, int y, const(char)[] s, uint fg, uint bg=0xff000000) nothrow @trusted @nogc {
365 int res = 0;
366 foreach (char ch; s) {
367 auto w = gxDrawCharP(x, y, ch, fg, bg);
368 if (res) ++res;
369 res += w;
370 x += w+1;
372 return res;
376 // return text width
377 public int gxDrawTextScaledP (int scale, int x, int y, const(char)[] s, uint fg, uint bg=0xff000000) nothrow @trusted @nogc {
378 if (scale < 1) return 0;
379 int res = 0;
380 foreach (char ch; s) {
381 auto w = gxDrawCharScaledP(scale, x, y, ch, fg, bg)+scale;
382 res += w;
383 x += w;
385 if (res) res -= scale;
386 return res;
390 // ////////////////////////////////////////////////////////////////////////// //
391 public void gxDrawTextOutM (int x, int y, const(char)[] s, uint fg, uint ot) nothrow @trusted @nogc {
392 foreach (immutable dy; -1..2) {
393 foreach (immutable dx; -1..2) {
394 if (dx == 0 && dy == 0) continue;
395 gxDrawTextM(x+dx, y+dy, s, ot);
398 gxDrawTextM(x, y, s, fg);
402 // return text width
403 public int gxDrawTextOutP (int x, int y, const(char)[] s, uint fg, uint ot) nothrow @trusted @nogc {
404 foreach (immutable dy; -1..2) {
405 foreach (immutable dx; -1..2) {
406 if (dx == 0 && dy == 0) continue;
407 gxDrawTextP(x+dx, y+dy, s, ot);
410 return gxDrawTextP(x, y, s, fg);
414 // ////////////////////////////////////////////////////////////////////////// //
415 public int gxTextHeightUtf () nothrow @trusted @nogc { return FontHeight; }
417 public int gxTextWidthUtf (const(char)[] s) nothrow @trusted @nogc {
418 int res = 0;
419 s.utfByLocal(delegate (char ch) @trusted { res += gxCharWidthP(ch)+1; });
420 if (res) --res;
421 return res;
424 public int gxTextHeightScaledUtf (int scale) nothrow @trusted @nogc { return gxTextHeightScaledP(scale); }
426 public int gxTextWidthScaledUtf (int scale, const(char)[] s) nothrow @trusted @nogc {
427 if (scale < 1) return 0;
428 int res = 0;
429 s.utfByLocal(delegate (char ch) { res += gxCharWidthScaledP(scale, ch)+scale; });
430 if (res) res -= scale;
431 return res;
434 public int gxDrawTextUtf (int x, int y, const(char)[] s, uint clr) nothrow @trusted @nogc {
435 int res = 0;
436 s.utfByLocal(delegate (char ch) { int rc = gxDrawCharP(x, y, ch, clr)+1; res += rc; x += rc; });
437 if (res) --res;
438 return res;
442 public int gxDrawTextScaledUtf (int scale, int x, int y, const(char)[] s, uint clr) nothrow @trusted @nogc {
443 if (scale < 1) return 0;
444 int res = 0;
445 s.utfByLocal(delegate (char ch) { int rc = gxDrawCharScaledP(scale, x, y, ch, clr)+scale; res += rc; x += rc; });
446 if (res) res -= scale;
447 return res;
451 // ////////////////////////////////////////////////////////////////////////// //
452 public void gxHLine (int x, int y, int w, uint clr) nothrow @trusted @nogc {
453 if (w < 1 || y < 0 || y >= VBufHeight || x >= VBufWidth) return;
454 if (x < 0) {
455 if (x+w <= 0) return;
456 w += x;
457 x = 0;
458 assert(w > 0);
460 if (x+w > VBufWidth) {
461 w = VBufWidth-x;
462 assert(w > 0);
464 while (w-- > 0) gxPutPixel(x++, y, clr);
468 public void gxVLine (int x, int y, int h, uint clr) nothrow @trusted @nogc {
469 if (h < 1 || x < 0 || x >= VBufWidth || y >= VBufHeight) return;
470 if (y < 0) {
471 if (y+h <= 0) return;
472 h += y;
473 y = 0;
474 assert(h > 0);
476 if (y+h > VBufHeight) {
477 h = VBufHeight-y;
478 assert(h > 0);
480 while (h-- > 0) gxPutPixel(x, y++, clr);
484 public void gxFillRect (int x, int y, int w, int h, uint clr) nothrow @trusted @nogc {
485 if (w < 1 || h < 1 || x >= VBufWidth || y >= VBufHeight) return;
486 while (h-- > 0) gxHLine(x, y++, w, clr);
490 public void gxDrawRect (int x, int y, int w, int h, uint clr) nothrow @trusted @nogc {
491 if (w < 1 || h < 1 || x >= VBufWidth || y >= VBufHeight) return;
492 gxHLine(x, y, w, clr);
493 gxHLine(x, y+h-1, w, clr);
494 gxVLine(x, y+1, h-2, clr);
495 gxVLine(x+w-1, y+1, h-2, clr);
499 // ////////////////////////////////////////////////////////////////////////// //
500 // use clip region as boundaries
501 public void gxDrawShadow () nothrow @trusted @nogc {
502 clipX1 += 8;
503 clipY1 += 8;
504 gxFillRect(clipX1-7, clipY0+8, 8, clipHeight-8*2, gxRGBA!(0, 0, 0, 127));
505 gxFillRect(clipX0+8, clipY1-7, clipWidth-8, 8, gxRGBA!(0, 0, 0, 127));
506 clipX1 -= 8;
507 clipY1 -= 8;
511 // shrink cliprect from "whole window" to "client"
512 public void gxClipClient () nothrow @trusted @nogc {
513 clipX0 += 1;
514 clipY0 += 10;
515 clipX1 -= 1;
516 clipY1 -= 1;
520 public void gxDrawWindow (const(char)[] title, uint framecolor, uint titlecolor, uint windowcolor) nothrow @trusted @nogc {
521 gxDrawShadow();
523 gxFillRect(clipX0, clipY0, clipWidth, clipHeight, windowcolor);
524 gxDrawRect(clipX0, clipY0, clipWidth, clipHeight, framecolor);
526 if (title !is null) {
527 gxFillRect(clipX0, clipY0, clipWidth, 10, framecolor);
528 gxDrawTextUtf(clipX0+(clipWidth-gxTextWidthUtf(title))/2, clipY0+1, title, titlecolor);