JsonObject* Fonts = Json.CreateObject(adam_task); #define C2D_MAGIC 0xDEDEDEDEDEDEDEDE class @context2d { I64 width; I64 height; U32* fb; I64 opacity; }; class @callable_context2d : @context2d { @callable_context2d* (*blot)(I64 x, I64 y, @callable_context2d* src); @callable_context2d* (*blur)(I64 radius); @callable_context2d* (*copy_rect)(I64 x, I64 y, @callable_context2d* rect); @callable_context2d* (*fill)(U32 color = 0); @callable_context2d* (*fill_rect)(I64 x, I64 y, I64 w, I64 h, U32 color); U32 (*peek)(I64 x, I64 y); @callable_context2d* (*plot)(I64 x, I64 y, U32 color); @callable_context2d* (*line)(I64 x1, I64 y1, I64 x2, I64 y2, U32 color); @callable_context2d* (*text)(U64 font, I64 x, I64 y, I64 size, U32 color, U8* text); @callable_context2d* (*clipped)(); @callable_context2d* (*rotated)(F64 angle); @callable_context2d* (*scaled)(F64 scale_x, F64 scale_y); }; extern @callable_context2d* @create_callable_context2d(@context2d* ctx); #define Context2D @callable_context2d class Bounds2D { I64 x1; I64 y1; I64 x2; I64 y2; }; U32 Color(I64 r, I64 g, I64 b, I64 a = 255) { U32 c; c.u8[0] = b; c.u8[1] = g; c.u8[2] = r; c.u8[3] = a; return c; } U32 ColorHSVToRGB(I64 hue, I64 saturation, I64 value) { if (!(0 <= hue < 360)) hue = 0; if (!(0 <= saturation <= 100)) saturation = 100; if (!(0 <= value <= 100)) value = 100; F64 s = saturation / 100.0; F64 v = value / 100.0; F64 c = v * s; F64 x = c * (1 - Abs(((hue / 60.0) % 2) - 1)); F64 m = v - c; F64 r, g, b; switch (hue) { case 0...59: r = c; g = x; b = 0; break; case 60...119: r = x; g = c; b = 0; break; case 120...179: r = 0; g = c; b = x; break; case 180...239: r = 0; g = x; b = c; break; case 240...299: r = x; g = 0; b = c; break; case 300...359: r = c; g = 0; b = x; break; } return Color(ToI64((r + m) * 255), ToI64((g + m) * 255), ToI64((b + m) * 255)); } U0 ColorRGBToHSV(U32 color, I64* hue, I64* saturation, I64* value) { if (!hue || !saturation || !value) return; F64 r = color.u8[2] / 255.0; F64 g = color.u8[1] / 255.0; F64 b = color.u8[0] / 255.0; F64 cMax = Max(r, Max(g, b)); F64 cMin = Min(r, Min(g, b)); F64 delta = cMax - cMin; if (delta == 0) *hue = 0; else if (cMax == r) *hue = 60 * (((g - b) / delta) % 6); else if (cMax == g) *hue = 60 * (((b - r) / delta) + 2); else *hue = 60 * (((r - g) / delta) + 4); if (cMax != 0) *saturation = (delta / cMax) * 100; else *saturation = 0; *value = cMax * 100; } /* * ISO Latin-1 Font * * Copyright (c) 2000 * Ka-Ping Yee * * This font may be freely used for any purpose. */ /* * adjusted 'A' 'V' to improve their dense appearance (ie. lightened) * adjusted 'i' 'l' to improve their flow within a word (ie. widened) * adjusted 'E' 'F' '#' */ U8 console_font[256 * 16] = { /* 0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 2 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 3 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 4 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 6 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 7 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 9 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 11 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 12 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 13 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 14 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 15 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 16 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 17 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 18 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 19 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 21 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 22 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 23 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 24 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 25 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 26 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 27 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 28 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 29 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 31 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 32 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 33 */ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, /* 34 */ 0x00, 0x00, 0x6c, 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 35 */ 0x00, 0x00, 0x00, 0x36, 0x36, 0x7f, 0x36, 0x36, 0x7f, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, /* 36 */ 0x00, 0x08, 0x08, 0x3e, 0x6b, 0x0b, 0x0b, 0x3e, 0x68, 0x68, 0x6b, 0x3e, 0x08, 0x08, 0x00, 0x00, /* 37 */ 0x00, 0x00, 0x00, 0x33, 0x13, 0x18, 0x08, 0x0c, 0x04, 0x06, 0x32, 0x33, 0x00, 0x00, 0x00, 0x00, /* 38 */ 0x00, 0x00, 0x1c, 0x36, 0x36, 0x1c, 0x6c, 0x3e, 0x33, 0x33, 0x7b, 0xce, 0x00, 0x00, 0x00, 0x00, /* 39 */ 0x00, 0x00, 0x18, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 40 */ 0x00, 0x00, 0x30, 0x18, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, /* 41 */ 0x00, 0x00, 0x0c, 0x18, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x18, 0x0c, 0x00, 0x00, 0x00, /* 42 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x1c, 0x7f, 0x1c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 43 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 44 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x0c, 0x00, 0x00, 0x00, /* 45 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 46 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, /* 47 */ 0x00, 0x00, 0x60, 0x20, 0x30, 0x10, 0x18, 0x08, 0x0c, 0x04, 0x06, 0x02, 0x03, 0x00, 0x00, 0x00, /* 48 */ 0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x6b, 0x6b, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 49 */ 0x00, 0x00, 0x18, 0x1e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, /* 50 */ 0x00, 0x00, 0x3e, 0x63, 0x60, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x7f, 0x00, 0x00, 0x00, 0x00, /* 51 */ 0x00, 0x00, 0x3e, 0x63, 0x60, 0x60, 0x3c, 0x60, 0x60, 0x60, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 52 */ 0x00, 0x00, 0x30, 0x38, 0x3c, 0x36, 0x33, 0x7f, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, /* 53 */ 0x00, 0x00, 0x7f, 0x03, 0x03, 0x3f, 0x60, 0x60, 0x60, 0x60, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 54 */ 0x00, 0x00, 0x3c, 0x06, 0x03, 0x03, 0x3f, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 55 */ 0x00, 0x00, 0x7f, 0x60, 0x30, 0x30, 0x18, 0x18, 0x18, 0x0c, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, /* 56 */ 0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 57 */ 0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x7e, 0x60, 0x60, 0x60, 0x30, 0x1e, 0x00, 0x00, 0x00, 0x00, /* 58 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, /* 59 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x0c, 0x00, 0x00, 0x00, /* 60 */ 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, /* 61 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 62 */ 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00, /* 63 */ 0x00, 0x00, 0x3e, 0x63, 0x60, 0x30, 0x30, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, /* 64 */ 0x00, 0x00, 0x3c, 0x66, 0x73, 0x7b, 0x6b, 0x6b, 0x7b, 0x33, 0x06, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 65 */ 0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, /* 66 */ 0x00, 0x00, 0x3f, 0x63, 0x63, 0x63, 0x3f, 0x63, 0x63, 0x63, 0x63, 0x3f, 0x00, 0x00, 0x00, 0x00, /* 67 */ 0x00, 0x00, 0x3c, 0x66, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 68 */ 0x00, 0x00, 0x1f, 0x33, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x33, 0x1f, 0x00, 0x00, 0x00, 0x00, /* 69 */ 0x00, 0x00, 0x7f, 0x03, 0x03, 0x03, 0x3f, 0x03, 0x03, 0x03, 0x03, 0x7f, 0x00, 0x00, 0x00, 0x00, /* 70 */ 0x00, 0x00, 0x7f, 0x03, 0x03, 0x03, 0x3f, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, /* 71 */ 0x00, 0x00, 0x3c, 0x66, 0x03, 0x03, 0x03, 0x73, 0x63, 0x63, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, /* 72 */ 0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, /* 73 */ 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 74 */ 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x33, 0x1e, 0x00, 0x00, 0x00, 0x00, /* 75 */ 0x00, 0x00, 0x63, 0x33, 0x1b, 0x0f, 0x07, 0x07, 0x0f, 0x1b, 0x33, 0x63, 0x00, 0x00, 0x00, 0x00, /* 76 */ 0x00, 0x00, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x7f, 0x00, 0x00, 0x00, 0x00, /* 77 */ 0x00, 0x00, 0x63, 0x63, 0x77, 0x7f, 0x7f, 0x6b, 0x6b, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, /* 78 */ 0x00, 0x00, 0x63, 0x63, 0x67, 0x6f, 0x6f, 0x7b, 0x7b, 0x73, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, /* 79 */ 0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 80 */ 0x00, 0x00, 0x3f, 0x63, 0x63, 0x63, 0x63, 0x3f, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, /* 81 */ 0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x6f, 0x7b, 0x3e, 0x30, 0x60, 0x00, 0x00, /* 82 */ 0x00, 0x00, 0x3f, 0x63, 0x63, 0x63, 0x63, 0x3f, 0x1b, 0x33, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, /* 83 */ 0x00, 0x00, 0x3e, 0x63, 0x03, 0x03, 0x0e, 0x38, 0x60, 0x60, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 84 */ 0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, /* 85 */ 0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 86 */ 0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x36, 0x36, 0x1c, 0x1c, 0x08, 0x00, 0x00, 0x00, 0x00, /* 87 */ 0x00, 0x00, 0x63, 0x63, 0x6b, 0x6b, 0x6b, 0x6b, 0x7f, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, /* 88 */ 0x00, 0x00, 0x63, 0x63, 0x36, 0x36, 0x1c, 0x1c, 0x36, 0x36, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, /* 89 */ 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x66, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, /* 90 */ 0x00, 0x00, 0x7f, 0x30, 0x30, 0x18, 0x18, 0x0c, 0x0c, 0x06, 0x06, 0x7f, 0x00, 0x00, 0x00, 0x00, /* 91 */ 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 92 */ 0x00, 0x00, 0x03, 0x02, 0x06, 0x04, 0x0c, 0x08, 0x18, 0x10, 0x30, 0x20, 0x60, 0x00, 0x00, 0x00, /* 93 */ 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 94 */ 0x00, 0x08, 0x1c, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 95 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, /* 96 */ 0x00, 0x00, 0x0c, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 97 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x60, 0x7e, 0x63, 0x63, 0x73, 0x6e, 0x00, 0x00, 0x00, 0x00, /* 98 */ 0x00, 0x00, 0x03, 0x03, 0x03, 0x3b, 0x67, 0x63, 0x63, 0x63, 0x67, 0x3b, 0x00, 0x00, 0x00, 0x00, /* 99 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63, 0x03, 0x03, 0x03, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 100 */ 0x00, 0x00, 0x60, 0x60, 0x60, 0x6e, 0x73, 0x63, 0x63, 0x63, 0x73, 0x6e, 0x00, 0x00, 0x00, 0x00, /* 101 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63, 0x63, 0x7f, 0x03, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 102 */ 0x00, 0x00, 0x3c, 0x66, 0x06, 0x1f, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, /* 103 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x73, 0x63, 0x63, 0x63, 0x73, 0x6e, 0x60, 0x63, 0x3e, 0x00, /* 104 */ 0x00, 0x00, 0x03, 0x03, 0x03, 0x3b, 0x67, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, /* 105 */ 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x38, 0x00, 0x00, 0x00, 0x00, /* 106 */ 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x33, 0x1e, 0x00, /* 107 */ 0x00, 0x00, 0x03, 0x03, 0x03, 0x63, 0x33, 0x1b, 0x0f, 0x1f, 0x33, 0x63, 0x00, 0x00, 0x00, 0x00, /* 108 */ 0x00, 0x00, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x38, 0x00, 0x00, 0x00, 0x00, /* 109 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x35, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x00, 0x00, 0x00, 0x00, /* 110 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x67, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, /* 111 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 112 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x67, 0x63, 0x63, 0x63, 0x67, 0x3b, 0x03, 0x03, 0x03, 0x00, /* 113 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x73, 0x63, 0x63, 0x63, 0x73, 0x6e, 0x60, 0xe0, 0x60, 0x00, /* 114 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x67, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, /* 115 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63, 0x0e, 0x38, 0x60, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 116 */ 0x00, 0x00, 0x00, 0x0c, 0x0c, 0x3e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x38, 0x00, 0x00, 0x00, 0x00, /* 117 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x73, 0x6e, 0x00, 0x00, 0x00, 0x00, /* 118 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x36, 0x36, 0x1c, 0x1c, 0x08, 0x00, 0x00, 0x00, 0x00, /* 119 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x6b, 0x6b, 0x6b, 0x3e, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, /* 120 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x36, 0x1c, 0x1c, 0x1c, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00, /* 121 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x36, 0x36, 0x1c, 0x1c, 0x0c, 0x0c, 0x06, 0x03, 0x00, /* 122 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x7f, 0x00, 0x00, 0x00, 0x00, /* 123 */ 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, /* 124 */ 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, /* 125 */ 0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00, /* 126 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 127 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 128 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 129 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 130 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 131 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 132 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 133 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 134 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 135 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 136 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 137 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 138 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 139 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 140 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 141 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 142 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 143 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 144 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 145 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 146 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 147 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 148 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 149 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 150 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 151 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 152 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 153 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 154 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 155 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 156 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 157 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 158 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 159 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 160 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 161 */ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, /* 162 */ 0x00, 0x00, 0x00, 0x08, 0x08, 0x3e, 0x6b, 0x0b, 0x0b, 0x0b, 0x6b, 0x3e, 0x08, 0x08, 0x00, 0x00, /* 163 */ 0x00, 0x00, 0x1c, 0x36, 0x06, 0x06, 0x1f, 0x06, 0x06, 0x07, 0x6f, 0x3b, 0x00, 0x00, 0x00, 0x00, /* 164 */ 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, /* 165 */ 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x66, 0x3c, 0x7e, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, /* 166 */ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, /* 167 */ 0x00, 0x3c, 0x66, 0x0c, 0x1e, 0x33, 0x63, 0x66, 0x3c, 0x18, 0x33, 0x1e, 0x00, 0x00, 0x00, 0x00, /* 168 */ 0x00, 0x00, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 169 */ 0x00, 0x00, 0x3c, 0x42, 0x99, 0xa5, 0x85, 0xa5, 0x99, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, /* 170 */ 0x00, 0x1e, 0x30, 0x3e, 0x33, 0x3b, 0x36, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 171 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x36, 0x1b, 0x1b, 0x36, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, /* 172 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x60, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 173 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 174 */ 0x00, 0x00, 0x3c, 0x42, 0x9d, 0xa5, 0x9d, 0xa5, 0xa5, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, /* 175 */ 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 176 */ 0x00, 0x00, 0x1c, 0x36, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 177 */ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, /* 178 */ 0x00, 0x1e, 0x33, 0x18, 0x0c, 0x06, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 179 */ 0x00, 0x1e, 0x33, 0x18, 0x30, 0x33, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 180 */ 0x00, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 181 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x76, 0x6e, 0x06, 0x06, 0x03, 0x00, /* 182 */ 0x00, 0x00, 0x7e, 0x2f, 0x2f, 0x2f, 0x2e, 0x28, 0x28, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, /* 183 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 184 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x1e, 0x00, /* 185 */ 0x00, 0x0c, 0x0e, 0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 186 */ 0x00, 0x1e, 0x33, 0x33, 0x33, 0x33, 0x1e, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 187 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x36, 0x6c, 0x6c, 0x36, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, /* 188 */ 0x00, 0x10, 0x1c, 0x18, 0x18, 0x18, 0x00, 0x7f, 0x00, 0x18, 0x1c, 0x1a, 0x3e, 0x18, 0x00, 0x00, /* 189 */ 0x00, 0x10, 0x1c, 0x18, 0x18, 0x18, 0x00, 0x7f, 0x00, 0x1c, 0x36, 0x18, 0x0c, 0x3e, 0x00, 0x00, /* 190 */ 0x00, 0x1c, 0x36, 0x18, 0x36, 0x1c, 0x00, 0x7f, 0x00, 0x18, 0x1c, 0x1a, 0x3e, 0x18, 0x00, 0x00, /* 191 */ 0x00, 0x00, 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x0c, 0x0c, 0x06, 0x06, 0x03, 0x63, 0x3e, 0x00, 0x00, /* 192 */ 0x0c, 0x18, 0x3e, 0x63, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, /* 193 */ 0x18, 0x0c, 0x3e, 0x63, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, /* 194 */ 0x08, 0x14, 0x3e, 0x63, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, /* 195 */ 0x6e, 0x3b, 0x3e, 0x63, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, /* 196 */ 0x36, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, /* 197 */ 0x1c, 0x36, 0x3e, 0x63, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, /* 198 */ 0x00, 0x00, 0xfe, 0x33, 0x33, 0x33, 0xff, 0x33, 0x33, 0x33, 0x33, 0xf3, 0x00, 0x00, 0x00, 0x00, /* 199 */ 0x00, 0x00, 0x3c, 0x66, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x66, 0x3c, 0x18, 0x30, 0x1e, 0x00, /* 200 */ 0x0c, 0x18, 0x7f, 0x03, 0x03, 0x03, 0x3f, 0x03, 0x03, 0x03, 0x03, 0x7f, 0x00, 0x00, 0x00, 0x00, /* 201 */ 0x18, 0x0c, 0x7f, 0x03, 0x03, 0x03, 0x3f, 0x03, 0x03, 0x03, 0x03, 0x7f, 0x00, 0x00, 0x00, 0x00, /* 202 */ 0x08, 0x14, 0x7f, 0x03, 0x03, 0x03, 0x3f, 0x03, 0x03, 0x03, 0x03, 0x7f, 0x00, 0x00, 0x00, 0x00, /* 203 */ 0x36, 0x00, 0x7f, 0x03, 0x03, 0x03, 0x3f, 0x03, 0x03, 0x03, 0x03, 0x7f, 0x00, 0x00, 0x00, 0x00, /* 204 */ 0x0c, 0x18, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 205 */ 0x30, 0x18, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 206 */ 0x18, 0x24, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 207 */ 0x66, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 208 */ 0x00, 0x00, 0x1e, 0x36, 0x66, 0x66, 0x6f, 0x66, 0x66, 0x66, 0x36, 0x1e, 0x00, 0x00, 0x00, 0x00, /* 209 */ 0x6e, 0x3b, 0x63, 0x63, 0x67, 0x6f, 0x6f, 0x7b, 0x7b, 0x73, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, /* 210 */ 0x06, 0x0c, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 211 */ 0x30, 0x18, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 212 */ 0x08, 0x14, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 213 */ 0x6e, 0x3b, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 214 */ 0x36, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 215 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 216 */ 0x00, 0x20, 0x3e, 0x73, 0x73, 0x6b, 0x6b, 0x6b, 0x6b, 0x67, 0x67, 0x3e, 0x02, 0x00, 0x00, 0x00, /* 217 */ 0x0c, 0x18, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 218 */ 0x18, 0x0c, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 219 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 220 */ 0x36, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 221 */ 0x30, 0x18, 0xc3, 0xc3, 0x66, 0x66, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, /* 222 */ 0x00, 0x00, 0x0f, 0x06, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3e, 0x06, 0x0f, 0x00, 0x00, 0x00, 0x00, /* 223 */ 0x00, 0x00, 0x1e, 0x33, 0x33, 0x1b, 0x33, 0x63, 0x63, 0x63, 0x63, 0x3b, 0x00, 0x00, 0x00, 0x00, /* 224 */ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x3e, 0x60, 0x7e, 0x63, 0x63, 0x73, 0x6e, 0x00, 0x00, 0x00, 0x00, /* 225 */ 0x00, 0x30, 0x18, 0x0c, 0x00, 0x3e, 0x60, 0x7e, 0x63, 0x63, 0x73, 0x6e, 0x00, 0x00, 0x00, 0x00, /* 226 */ 0x00, 0x08, 0x1c, 0x36, 0x00, 0x3e, 0x60, 0x7e, 0x63, 0x63, 0x73, 0x6e, 0x00, 0x00, 0x00, 0x00, /* 227 */ 0x00, 0x00, 0x6e, 0x3b, 0x00, 0x3e, 0x60, 0x7e, 0x63, 0x63, 0x73, 0x6e, 0x00, 0x00, 0x00, 0x00, /* 228 */ 0x00, 0x00, 0x36, 0x36, 0x00, 0x3e, 0x60, 0x7e, 0x63, 0x63, 0x73, 0x6e, 0x00, 0x00, 0x00, 0x00, /* 229 */ 0x00, 0x1c, 0x36, 0x1c, 0x00, 0x3e, 0x60, 0x7e, 0x63, 0x63, 0x73, 0x6e, 0x00, 0x00, 0x00, 0x00, /* 230 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0xdb, 0xd8, 0xfe, 0x1b, 0xdb, 0x76, 0x00, 0x00, 0x00, 0x00, /* 231 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63, 0x03, 0x03, 0x03, 0x63, 0x3e, 0x18, 0x30, 0x1e, 0x00, /* 232 */ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x3e, 0x63, 0x63, 0x7f, 0x03, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 233 */ 0x00, 0x30, 0x18, 0x0c, 0x00, 0x3e, 0x63, 0x63, 0x7f, 0x03, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 234 */ 0x00, 0x08, 0x1c, 0x36, 0x00, 0x3e, 0x63, 0x63, 0x7f, 0x03, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 235 */ 0x00, 0x00, 0x36, 0x36, 0x00, 0x3e, 0x63, 0x63, 0x7f, 0x03, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 236 */ 0x00, 0x06, 0x0c, 0x18, 0x00, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x38, 0x00, 0x00, 0x00, 0x00, /* 237 */ 0x00, 0x18, 0x0c, 0x06, 0x00, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x38, 0x00, 0x00, 0x00, 0x00, /* 238 */ 0x00, 0x08, 0x1c, 0x36, 0x00, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x38, 0x00, 0x00, 0x00, 0x00, /* 239 */ 0x00, 0x00, 0x36, 0x36, 0x00, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x38, 0x00, 0x00, 0x00, 0x00, /* 240 */ 0x00, 0x00, 0x2c, 0x18, 0x34, 0x60, 0x7c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, /* 241 */ 0x00, 0x00, 0x6e, 0x3b, 0x00, 0x3b, 0x67, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, /* 242 */ 0x00, 0x06, 0x0c, 0x18, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 243 */ 0x00, 0x30, 0x18, 0x0c, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 244 */ 0x00, 0x08, 0x1c, 0x36, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 245 */ 0x00, 0x00, 0x6e, 0x3b, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 246 */ 0x00, 0x00, 0x36, 0x36, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, /* 247 */ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, /* 248 */ 0x00, 0x00, 0x00, 0x00, 0x20, 0x3e, 0x73, 0x6b, 0x6b, 0x6b, 0x67, 0x3e, 0x02, 0x00, 0x00, 0x00, /* 249 */ 0x00, 0x06, 0x0c, 0x18, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x73, 0x6e, 0x00, 0x00, 0x00, 0x00, /* 250 */ 0x00, 0x30, 0x18, 0x0c, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x73, 0x6e, 0x00, 0x00, 0x00, 0x00, /* 251 */ 0x00, 0x08, 0x1c, 0x36, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x73, 0x6e, 0x00, 0x00, 0x00, 0x00, /* 252 */ 0x00, 0x00, 0x36, 0x36, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x73, 0x6e, 0x00, 0x00, 0x00, 0x00, /* 253 */ 0x00, 0x30, 0x18, 0x0c, 0x00, 0x63, 0x63, 0x36, 0x36, 0x1c, 0x1c, 0x0c, 0x0c, 0x06, 0x03, 0x00, /* 254 */ 0x00, 0x00, 0x0f, 0x06, 0x06, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3e, 0x06, 0x06, 0x0f, 0x00, /* 255 */ 0x00, 0x00, 0x36, 0x36, 0x00, 0x63, 0x63, 0x36, 0x36, 0x1c, 0x1c, 0x0c, 0x0c, 0x06, 0x03, 0x00 }; Context2D* NewContext2D(I64 width, I64 height, I64 bpp = 32) { // Create new Context2D. switch (bpp) { case 32: break; default: return NULL; break; } Context2D* ctx = CAlloc(sizeof(Context2D)); ctx->width = width; ctx->height = height; ctx->fb = CAlloc((width * height) * bpp / 8); ctx->opacity = -1; return @create_callable_context2d(ctx); } U0 DelContext2D(Context2D* ctx) { if (!ctx) { return; } Free(ctx->fb); Free(ctx->scaled); Free(ctx->rotated); Free(ctx->clipped); Free(ctx->line); Free(ctx->plot); Free(ctx->peek); Free(ctx->fill_rect); Free(ctx->fill); Free(ctx->copy_rect); Free(ctx->blur); Free(ctx->blot); Free(ctx); } U0 Fill2D(Context2D* ctx, U32 color = 0) { // Fill a Context2D with color. MemSetU32(ctx->fb, color, ctx->width * ctx->height); return; } U32 Peek2D(Context2D* ctx, I64 x, I64 y) { // Return RGBA value for pixel. if (x < 0 || x > ctx->width - 1 || y < 0 || y > ctx->height - 1) return Color(255, 255, 255); return ctx->fb[(ctx->width * y) + x]; } U0 Plot2D(Context2D* ctx, I64 x, I64 y, U32 color) { // Plot a pixel with clipping. if (x < 0 || x > ctx->width - 1 || y < 0 || y > ctx->height - 1) return; ctx->fb[(ctx->width * y) + x] = color; } U0 VLine2D(Context2D* ctx, I64 x, I64 y, I64 y2, U32 color) { // Draw a vertical line. if (x > ctx->width || y > ctx->height) return; if (y2 < y) return; while (y < y2 + 1) { Plot2D(ctx, x, y, color); y++; } } U0 HLine2D(Context2D* ctx, I64 x, I64 y, I64 x2, U32 color) { // Draw a horizontal line. if (x2 < x) return; I64 width = x2 - x; MemSetU32(ctx->fb + (y * ctx->width) + x, color, T(x + width > ctx->width, ctx->width - x, width)); } U0 Line2D(Context2D* ctx, I64 x1, I64 y1, I64 x2, I64 y2, U32 color) { // Draw an arbitrary line using Bresenham's algorithm. x1 = Max(0, x1); y1 = Max(0, y1); x2 = Min(ctx->width, x2); y2 = Min(ctx->height, y2); if (x1 == x2) { VLine2D(ctx, x1, y1, y2, color); return; } if (y1 == y2) { HLine2D(ctx, x1, y1, x2, color); return; } I64 dx, sx, dy, sy; I64 err, e2; dx = Abs(x2 - x1); sx = T(x1 < x2, 1, -1); dy = -Abs(y2 - y1); sy = T(y1 < y2, 1, -1); err = dx + dy; while (1) { Plot2D(ctx, x1, y1, color); if (x2 == x1 && y2 == y1) break; e2 = 2 * err; if (e2 >= dy) { err += dy; x1 += sx; } if (e2 <= dx) { err += dx; y1 += sy; } } } Context2D* MirroredHorz2D(Context2D* src) { if (!src) return NULL; Context2D* dst = NewContext2D(src->width, src->height); I64 x, y; for (y = 0; y < src->height; y++) for (x = src->width - 1; x > -1; x--) Plot2D(dst, (src->width - 1) - x, y, Peek2D(src, x, y)); return dst; } Context2D* MirroredVert2D(Context2D* src) { if (!src) return NULL; Context2D* dst = NewContext2D(src->width, src->height); I64 x, y; for (x = 0; x < src->width; x++) for (y = src->height - 1; y > -1; y--) Plot2D(dst, x, (src->height - 1) - y, Peek2D(src, x, y)); return dst; } I64 Blend2D(F64 alpha, F64 value1, F64 value2) { return ToI64((1 - alpha) * value1 + alpha * value2); } U0 Blot2D(Context2D* dst, I64 x, I64 y, Context2D* src) { if (!src || !dst) return; I64 xx, yy; I64 src_col, dst_col; F64 alpha; I64 plot_col; for (yy = 0; yy < src->height; yy++) { for (xx = 0; xx < src->width; xx++) { src_col = Peek2D(src, xx, yy); dst_col = Peek2D(dst, x + xx, y + yy); alpha = src_col.u8[3] / 128; // FIXME: Alpha blending not working correctly. plot_col = Blend2D(alpha, dst_col, src_col); if (src->opacity > -1) { plot_col.u8[3] = src->opacity; } Plot2D(dst, x + xx, y + yy, plot_col); } } } U0 @patch_blend_rect_2d(U64 addr_start, I64 size, U64 jmp_offset, U64 table_offset) { U8* patch_ptr = addr_start; I64 i; for (i = 0; (addr_start + table_offset - i) % 16; i++) { patch_ptr[jmp_offset]--; } if (i) MemCpy(addr_start + table_offset - i, addr_start + table_offset, size - table_offset); } U0 BlendRect2D(Context2D* rect, Context2D* ctx) { U64 reg R10 d = ctx->fb; U64 reg R11 s1 = rect->fb; U64 reg R14 s2 = ctx->fb; I64 reg RSI w = ctx->width; I64 reg RDI h = ctx->height; no_warn d, s1, s2, w, h; asm { MOV RAX, R10 MOV RDX, R11 MOV RCX, R14 DU8 0x0f, 0xaf, 0xf7, 0xc1, 0xfe, 0x02, 0xeb, 0x7f, 0x66, 0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x1f, 0x40, 0x00, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x03, 0x80, 0x03, 0x80, 0x07, 0x80, 0x07, 0x80, 0x0b, 0x80, 0x0b, 0x80, 0x0f, 0x80, 0x0f, 0x80, 0x00, 0x80, 0x02, 0x80, 0x04, 0x80, 0x06, 0x80, 0x08, 0x80, 0x0a, 0x80, 0x0c, 0x80, 0x0e, 0x80, 0x01, 0x80, 0x03, 0x80, 0x05, 0x80, 0x07, 0x80, 0x09, 0x80, 0x0b, 0x80, 0x0d, 0x80, 0x0f, 0x80, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x10, 0x0a, 0x0f, 0x10, 0x11, 0x66, 0x0f, 0x6f, 0xd9, 0x66, 0x0f, 0x38, 0x00, 0x1d, 0x8d, 0xff, 0xff, 0xff, 0x66, 0x0f, 0x6f, 0xe3, 0x66, 0x0f, 0xef, 0x25, 0xb1, 0xff, 0xff, 0xff, 0x66, 0x0f, 0x6f, 0xe9, 0x66, 0x0f, 0x6f, 0xf2, 0x66, 0x0f, 0x38, 0x00, 0x0d, 0x80, 0xff, 0xff, 0xff, 0x66, 0x0f, 0xd5, 0xcb, 0x66, 0x0f, 0x38, 0x00, 0x15, 0x73, 0xff, 0xff, 0xff, 0x66, 0x0f, 0xd5, 0xd4, 0x66, 0x0f, 0x38, 0x00, 0x2d, 0x76, 0xff, 0xff, 0xff, 0x66, 0x0f, 0xd5, 0xeb, 0x66, 0x0f, 0xfd, 0xd1, 0x66, 0x0f, 0xe4, 0x15, 0x86, 0xff, 0xff, 0xff, 0x66, 0x0f, 0x38, 0x00, 0x35, 0x5d, 0xff, 0xff, 0xff, 0x66, 0x0f, 0xd5, 0xf4, 0x66, 0x0f, 0xfd, 0xf5, 0x66, 0x0f, 0xe4, 0x35, 0x6d, 0xff, 0xff, 0xff, 0x66, 0x0f, 0x71, 0xf6, 0x08, 0x66, 0x0f, 0xeb, 0xd6, 0x66, 0x0f, 0xeb, 0x15, 0x6c, 0xff, 0xff, 0xff, 0x0f, 0x11, 0x10, 0x48, 0x83, 0xc2, 0x10, 0x48, 0x83, 0xc1, 0x10, 0x48, 0x83, 0xc0, 0x10, 0xff, 0xce, 0x0f, 0x85, 0x65, 0xff, 0xff, 0xff, 0x90; } } @patch_blend_rect_2d(&BlendRect2D, sizeof(BlendRect2D), 0x3D, 0x5D); U0 CopyRect2D(Context2D* ctx, I64 x, I64 y, Context2D* rect) { // Copy rect with clipping. if (x > ctx->width - 1 || y > ctx->height - 1) return; U8* ctx_pos = ctx->fb; U8* rect_pos = rect->fb; I64 rect_row = 0; I64 rect_y_ofs = 0; I64 rect_x_ofs = 0; I64 clip_y = 0; U8* rect_line; I64 bpp = 32 / 8; // Handle horizontal clipping left while (x < 0) { rect_x_ofs++; x++; } // Handle vertical clipping top while (y < 0) { rect_pos += (rect->width) * bpp; rect_y_ofs++; y++; } // default, clip line to copy as width-left off screen rect_line = rect->width - rect_x_ofs; if (-rect_x_ofs + x + rect->width >= ctx->width) { rect_line -= ((-rect_x_ofs + x + rect->width) - ctx->width); } rect_pos += (rect_x_ofs)*bpp; clip_y = y; while (rect_row < (rect->height - rect_y_ofs) && clip_y < ctx->height) { MemCpyU32(ctx_pos + (y * ((ctx->width) * bpp)) + (x * bpp), rect_pos, (rect_line)); ctx_pos += (ctx->width) * bpp; rect_pos += (rect->width) * bpp; clip_y++; rect_row++; } } U0 @graphics2d_get_gradient_steps(U32 start, U32 end, U32* gradient) { I64 a2 = start.u8[3]; I64 r2 = start.u8[2]; I64 g2 = start.u8[1]; I64 b2 = start.u8[0]; I64 a1 = end.u8[3]; I64 r1 = end.u8[2]; I64 g1 = end.u8[1]; I64 b1 = end.u8[0]; I64 i; F64 c = 1.0; for (i = 0; i < 256; i++) { gradient[i] = Color(r1 / 255.0 * c + r2 / 255.0 * (255 - c), g1 / 255.0 * c + g2 / 255.0 * (255 - c), b1 / 255.0 * c + b2 / 255.0 * (255 - c), a1 / 255.0 * c + a2 / 255.0 * (255 - c)); c += 1.0; } } U0 HGradientRect2D(Context2D* ctx, I64 x, I64 y, I64 w, I64 h, U32 from, U32 to) { U32 gradient[256]; F64 gradient_index; I64 xx; @graphics2d_get_gradient_steps(from, to, &gradient); for (xx = 0; xx < w; xx++) { gradient_index = ToF64(256.0 / ToF64(w)) * ToF64(xx); Line2D(ctx, x + xx, y, x + xx, y + h - 1, gradient[ToI64(gradient_index)]); } } U0 Rect2D(Context2D* ctx, I64 x, I64 y, I64 w, I64 h, U32 color) { // Draw a rectangle fill. Context2D* tmpctx = NewContext2D(Max(4, w), Max(4, h)); Fill2D(tmpctx, color); CopyRect2D(ctx, x, y, tmpctx); DelContext2D(tmpctx); } U0 ConsolePrint2D(Context2D* ctx, I64 x, I64 y, U32 color = Color(255, 255, 255), U32 colorbg = 0, U8* fmt, ...) { // Print formatted string using console font. Bool skip; U8* buf = StrPrintJoin(NULL, fmt, argc, argv); U8* str = buf; I64 orig_x = x; I64 xx, yy; U64* chr = console_font; while (*str) { skip = FALSE; if (*str == '\n') { skip = TRUE; y += 16; x = orig_x - 8; } for (yy = 0; yy < 16; yy++) { for (xx = 0; xx < 8; xx++) { if (chr[(*str) * 2].u8[yy] & 1 << xx == 1 << xx && !skip) Plot2D(ctx, x + xx, y + yy, color); else Plot2D(ctx, x + xx, y + yy, colorbg); } } x += 8; str++; } Free(buf); } U0 PutChar2D(Context2D* ctx, BitmapFont* font, I64 x, I64 y, U32 color = Color(0, 0, 0), I64 char) { if (!ctx) return; I64 xx; I64 yy; I64 char_index = 0; while (char != font->char_map[char_index]) char_index++; for (yy = 0; yy < 16; yy++) { for (xx = 0; xx < 16; xx++) { if (font->bitmap[(char_index * 16) + yy] & 0x8000 >> xx == 0x8000 >> xx && char != ' ') { Plot2D(ctx, x + xx, y + yy, color); } } } } I64 PutS2D(Context2D* ctx, BitmapFont* font, I64 x, I64 y, U32 color = Color(0, 0, 0), I64 max_width = -1, U8* buf) { U8* str = buf; I64 origin_x; I64 origin_y; I64 xx, yy; Bool char_space; I64 char_index; I64 insert_space; I64 pass; origin_x = x; origin_y = y; if (max_width > -1) max_width = Min(ctx->width, max_width); for (pass = 0; pass < 2; pass++) { x = origin_x; y = origin_y; str = buf; while (*str) { char_space = FALSE; switch (*str) { case '\n': x = origin_x; if (font->line_height) y += Min(16, font->line_height); else y += 16; goto @print2d_next_char; break; case ' ': char_space = TRUE; break; default: break; } char_index = 0; while (*str != font->char_map[char_index]) char_index++; insert_space = 0; for (yy = 0; yy < 16; yy++) { for (xx = 0; xx < 16; xx++) { if (font->bitmap[(char_index * 16) + yy] & 0x8000 >> xx == 0x8000 >> xx && !char_space) { insert_space = Max(xx, insert_space); if (pass && ctx) Plot2D(ctx, x + xx, y + yy, color); } } } if (char_space) insert_space = 4; @print2d_next_char : str++; if (str > buf && str[-1] != '\n') { if (*str) { x += insert_space + 2; } else { x += insert_space; } } if (max_width == -1) { } else if (x > max_width) { StrCpy(&str[-4], "..."); break; } } } return x; } I64 Print2D(Context2D* ctx, BitmapFont* font, I64 x, I64 y, U32 color = Color(0, 0, 0), I64 max_width = -1, U8* fmt, ...) { // Print formatted string using BitmapFont. U8* buf; if (argc) buf = StrPrintJoin(NULL, fmt, argc, argv); else buf = StrNew(fmt); I64 retval = PutS2D(ctx, font, x, y, color, max_width, buf); Free(buf); return retval; } I64 X1Pos(CDC* src) { I64 x = 0; I64 y = 0; I64 color; while (x < src->width) { y = 0; while (y < src->height) { color = GrPeek(src, x, y); if (color) return x; y++; } x++; } return -1; } I64 X2Pos(CDC* src) { I64 x = src->width - 1; I64 y = src->height - 1; I64 color; while (x > -1) { y = src->height - 1; while (y > -1) { color = GrPeek(src, x, y); if (color) return x; y--; } x--; } return -1; } I64 Y2Pos(CDC* src) { I64 x = src->width - 1; I64 y = src->height - 1; I64 color; while (y > -1) { x = src->width - 1; while (x > -1) { color = GrPeek(src, x, y); if (color) return y; x--; } y--; } return -1; } I64 @get_truetype_text_width(U8* font_name, I64 size, I32* text, I32* advance = NULL) { I64 line_height = ToI64(size * 1.2); stbtt_fontinfo* font = Fonts->@(font_name); if (!font || !line_height || !text) { return 0; } return @stbtt_GetTextWidth(font, line_height, text, advance); } I64 @get_truetype_baseline(U8* font_name, I64 size) { stbtt_fontinfo* font = Fonts->@(font_name); if (!font) { return 0; } I64 res = 0; CDC* dc = DCNew(Display.Width() / 2, (size * 2)); Free(dc->body); I32 i32char[16]; MemSet(&i32char, NULL, 16); i32char[0] = 'o'; dc->body = @stbtt_RenderText(font, dc->width_internal, dc->height, ToI64(size * 1.2), &i32char); dc->width -= 16; dc->height -= size / 4; res = Y2Pos(dc); Free(dc); return res; } U0 Text2D(Context2D* ctx, U8* font_name, I64 x, I64 y, I64 size, U32 color, U8* text) { stbtt_fontinfo* font = Fonts->@(font_name); if (!ctx || !ctx->width || !ctx->height || !font || !size || !text || !StrLen(text)) { return; } Context2D* text_ctx = NewContext2D(ctx->width, ctx->height); CDC* dc = DCNew(ctx->width, ctx->height); Free(dc->body); dc->body = @stbtt_RenderText(font, dc->width_internal, dc->height, ToI64(size * 1.2), text); I64 text_x, text_y, text_c; for (text_y = 0; text_y < dc->height; text_y++) { for (text_x = 0; text_x < dc->width; text_x++) { text_c = GrPeek(dc, text_x, text_y); if (text_c) { color.u8[3] = text_c; text_ctx->plot(x + text_x, y + text_y, color); } } } BlendRect2D(text_ctx, ctx); DelContext2D(text_ctx); Free(dc); } Context2D* FastBoxBlur2D(Context2D* img, I64 radius) { /* Algorithm by Wojciech Jarosz, Implementation by Ferris Ateniese http://elynxsdk.free.fr/ext-docs/Blur/Fast_box_blur.pdf https://gist.github.com/LionRoar/12d625bee5882abb339dc7102ad6fe32#file-fastboxblur-cs */ I64 kSize = radius; I64 c, i, j, x, y; I64 bpp = 32; no_warn bpp; U32 tmpColor, tmp_nColor, tmp_pColor, plot_color; F64 hSum[4]; F64 tSum[4]; F64 iAvg[4]; if (kSize % 2 == 0) kSize++; Context2D* Hblur = NewContext2D(img->width, img->height); MemCpyU32(Hblur->fb, img->fb, img->width * img->height); F64 Avg = 1.0 / kSize; for (j = 0; j < img->height; j++) { for (c = 0; c < 4; c++) { hSum[c] = 0.0; iAvg[c] = 0.0; } for (x = 0; x < kSize; x++) { tmpColor = Peek2D(img, x, j); hSum[3] += tmpColor.u8[3]; hSum[2] += tmpColor.u8[2]; hSum[1] += tmpColor.u8[1]; hSum[0] += tmpColor.u8[0]; } iAvg[3] = hSum[3] * Avg; iAvg[2] = hSum[2] * Avg; iAvg[1] = hSum[1] * Avg; iAvg[0] = hSum[0] * Avg; for (i = 0; i < img->width; i++) { if (i - kSize / 2 >= 0 && i + 1 + kSize / 2 < img->width) { tmp_pColor = Peek2D(img, i - kSize / 2, j); hSum[3] -= tmp_pColor.u8[3]; hSum[2] -= tmp_pColor.u8[2]; hSum[1] -= tmp_pColor.u8[1]; hSum[0] -= tmp_pColor.u8[0]; tmp_nColor = Peek2D(img, i + 1 + kSize / 2, j); hSum[3] += tmp_nColor.u8[3]; hSum[2] += tmp_nColor.u8[2]; hSum[1] += tmp_nColor.u8[1]; hSum[0] += tmp_nColor.u8[0]; iAvg[3] = hSum[3] * Avg; iAvg[2] = hSum[2] * Avg; iAvg[1] = hSum[1] * Avg; iAvg[0] = hSum[0] * Avg; } plot_color.u8[3] = ToI64(iAvg[3]); plot_color.u8[2] = ToI64(iAvg[2]); plot_color.u8[1] = ToI64(iAvg[1]); plot_color.u8[0] = ToI64(iAvg[0]); Plot2D(Hblur, i, j, plot_color); } } Context2D* total = NewContext2D(Hblur->width, Hblur->height); MemCpyU32(total->fb, Hblur->fb, Hblur->width * Hblur->height); for (i = 0; i < Hblur->width; i++) { for (c = 0; c < 4; c++) { tSum[c] = 0.0; iAvg[c] = 0.0; } for (y = 0; y < kSize; y++) { tmpColor = Peek2D(Hblur, i, y); tSum[3] += tmpColor.u8[3]; tSum[2] += tmpColor.u8[2]; tSum[1] += tmpColor.u8[1]; tSum[0] += tmpColor.u8[0]; } iAvg[3] = tSum[3] * Avg; iAvg[2] = tSum[2] * Avg; iAvg[1] = tSum[1] * Avg; iAvg[0] = tSum[0] * Avg; for (j = 0; j < Hblur->height; j++) { if (j - kSize / 2 >= 0 && j + 1 + kSize / 2 < Hblur->height) { tmp_pColor = Peek2D(Hblur, i, j - kSize / 2); tSum[3] -= tmp_pColor.u8[3]; tSum[2] -= tmp_pColor.u8[2]; tSum[1] -= tmp_pColor.u8[1]; tSum[0] -= tmp_pColor.u8[0]; tmp_nColor = Peek2D(Hblur, i, j + 1 + kSize / 2); tSum[3] += tmp_nColor.u8[3]; tSum[2] += tmp_nColor.u8[2]; tSum[1] += tmp_nColor.u8[1]; tSum[0] += tmp_nColor.u8[0]; iAvg[3] = tSum[3] * Avg; iAvg[2] = tSum[2] * Avg; iAvg[1] = tSum[1] * Avg; iAvg[0] = tSum[0] * Avg; } plot_color.u8[3] = ToI64(iAvg[3]); plot_color.u8[2] = ToI64(iAvg[2]); plot_color.u8[1] = ToI64(iAvg[1]); plot_color.u8[0] = ToI64(iAvg[0]); Plot2D(total, i, j, plot_color); } } DelContext2D(Hblur); return total; } U0 BlurInPlace(Context2D* img, I64 radius) { Context2D* blurred = FastBoxBlur2D(img, radius); CopyRect2D(img, 0, 0, blurred); DelContext2D(blurred); } U8 @scale2d_get_byte(I64 value, I64 n) { return (value >> (n * 8) & 0xFF); } U32 @scale2d_get_pixel(Context2D* img, I64 x, I64 y) { return img->fb[(y * img->width) + x]; } F64 @scale2d_lerp(F64 s, F64 e, F64 t) { return s + (e - s) * t; } F64 @scale2d_blerp(F64 c00, F64 c10, F64 c01, F64 c11, F64 tx, F64 ty) { return @scale2d_lerp(@scale2d_lerp(c00, c10, tx), @scale2d_lerp(c01, c11, tx), ty); } U0 @scale2d_put_pixel(Context2D* img, I64 x, I64 y, U32 color) { img->fb[(y * img->width) + x] = color; } I64 X1Pos2D(Context2D* src) { I64 x = 0; I64 y = 0; U32 color; while (x < src->width) { y = 0; while (y < src->height) { color = Peek2D(src, x, y); if (color.u8[3]) return x; y++; } x++; } return -1; } I64 Y1Pos2D(Context2D* src) { I64 x = 0; I64 y = 0; U32 color; while (y < src->height) { x = 0; while (x < src->width) { color = Peek2D(src, x, y); if (color.u8[3]) return y; x++; } y++; } return -1; } I64 X2Pos2D(Context2D* src) { I64 x = src->width - 1; I64 y = src->height - 1; U32 color; while (x > -1) { y = src->height - 1; while (y > -1) { color = Peek2D(src, x, y); if (color.u8[3]) return x; y--; } x--; } return -1; } I64 Y2Pos2D(Context2D* src) { I64 x = src->width - 1; I64 y = src->height - 1; U32 color; while (y > -1) { x = src->width - 1; while (x > -1) { color = Peek2D(src, x, y); if (color.u8[3]) return y; x--; } y--; } return -1; } Context2D* ClipToRect2D(Context2D* src) { I64 x1, y1, x2, y2; x1 = X1Pos2D(src); y1 = Y1Pos2D(src); x2 = X2Pos2D(src); y2 = Y2Pos2D(src); Context2D* dst = NewContext2D(x2 - x1, y2 - y1); CopyRect2D(dst, -x1, -y1, src); return dst; } Context2D* Scale2D(Context2D* src, F64 scale_x, F64 scale_y) { I64 newWidth = ToI64(src->width * scale_x); I64 newHeight = ToI64(src->height * scale_y); Context2D* dst = NewContext2D(newWidth, newHeight); I64 x, y; F64 fw, fh; F64 gx; F64 gy; I64 gxi; I64 gyi; U32 result; U32 c00; U32 c10; U32 c01; U32 c11; U64 i; fw = ToF64(newWidth); fh = ToF64(newHeight); for (x = 0, y = 0; y < newHeight; x++) { if (x > newWidth) { x = 0; y++; } gx = x / fw * (src->width - 1); gy = y / fh * (src->height - 1); gxi = ToI64(gx); gyi = ToI64(gy); result = 0; c00 = @scale2d_get_pixel(src, gxi, gyi); c10 = @scale2d_get_pixel(src, gxi + 1, gyi); c01 = @scale2d_get_pixel(src, gxi, gyi + 1); c11 = @scale2d_get_pixel(src, gxi + 1, gyi + 1); for (i = 0; i < 4; i++) { result.u8[i] = ToI64( @scale2d_blerp(@scale2d_get_byte(c00, i), @scale2d_get_byte(c10, i), @scale2d_get_byte(c01, i), @scale2d_get_byte(c11, i), gx - gxi, gy - gyi) << (8 * i)); } @scale2d_put_pixel(dst, x, y, result); } return dst; } Context2D* Rotate2D(Context2D* src, F64 angle) { // FIXME: This is just awful... Context2D* dst = NewContext2D(src->width * 4, src->height * 4); Fill2D(dst, 0); CDC* dc[4]; CSprite* s[4]; I64 i, x, y; U32 color; for (i = 0; i < 4; i++) { dc[i] = DCNew(src->width * 4, src->height * 4); } for (y = 0; y < src->height; y++) { for (x = 0; x < src->width; x++) { color = Peek2D(src, x, y); for (i = 0; i < 4; i++) { dc[i]->color = Min(color.u8[i], 254); GrPlot(dc[i], x, y); } } } for (i = 0; i < 4; i++) { s[i] = DC2Sprite(dc[i]); DCFill(dc[i], 0); Sprite3ZB(dc[i], src->width * 2, src->height * 2, 0, s[i], angle * 0.017499999999); } for (y = 0; y < src->height * 4; y++) { for (x = 0; x < src->width * 4; x++) { for (i = 0; i < 4; i++) { color.u8[i] = GrPeek(dc[i], x, y); } Plot2D(dst, x, y, color); } } for (i = 0; i < 4; i++) { DCDel(dc[i]); Free(s[i]); } Context2D* dst2 = ClipToRect2D(dst); DelContext2D(dst); return dst2; } class @graphics2d { Context2D* fb; Context2D* (*FrameBufferContext2D)(); U0 (*Init)(); U0 (*Flip)(Context2D* ctx); I64 qwords; }; @graphics2d Graphics2D; U0 @graphics2d_init() { Graphics2D.fb = CAlloc(sizeof(Context2D)); Graphics2D.fb->width = Display.width; Graphics2D.fb->height = Display.height; Graphics2D.fb->fb = Display.fb; Graphics2D.fb->opacity = -1; Graphics2D.qwords = (Display.width * Display.height) / 2; Fill2D(Graphics2D.fb, 0x0); } U0 @graphics2d_flip(Context2D* ctx) { MemCpyU64(Graphics2D.fb->fb, ctx->fb, Graphics2D.qwords); } Context2D @graphics2d_get_framebuffer_context2d() { return Graphics2D.fb; } Graphics2D.FrameBufferContext2D = &@graphics2d_get_framebuffer_context2d; Graphics2D.Init = &@graphics2d_init; Graphics2D.Flip = &@graphics2d_flip; @callable_context2d* @c2d_blot_wrapper_function(I64 x, I64 y, @callable_context2d* src) { Context2D* dst = C2D_MAGIC; Blot2D(dst, x, y, src); return dst; } @callable_context2d* @c2d_blur_wrapper_function(I64 radius) { Context2D* img = C2D_MAGIC; BlurInPlace(img, radius); return img; } @callable_context2d* @c2d_copy_rect_wrapper_function(I64 x, I64 y, @callable_context2d* rect) { Context2D* ctx = C2D_MAGIC; CopyRect2D(ctx, x, y, rect); return ctx; } @callable_context2d* @c2d_fill_wrapper_function(U32 color = 0) { Context2D* ctx = C2D_MAGIC; Fill2D(ctx, color); return ctx; } @callable_context2d* @c2d_fill_rect_wrapper_function(I64 x, I64 y, I64 w, I64 h, U32 color) { Context2D* ctx = C2D_MAGIC; Rect2D(ctx, x, y, w, h, color); return ctx; } U32 @c2d_peek_wrapper_function(I64 x, I64 y) { Context2D* ctx = C2D_MAGIC; return Peek2D(ctx, x, y); } @callable_context2d* @c2d_plot_wrapper_function(I64 x, I64 y, U32 color) { Context2D* ctx = C2D_MAGIC; Plot2D(ctx, x, y, color); return ctx; } @callable_context2d* @c2d_line_wrapper_function(I64 x1, I64 y1, I64 x2, I64 y2, U32 color) { Context2D* ctx = C2D_MAGIC; Line2D(ctx, x1, y1, x2, y2, color); return ctx; } @callable_context2d* @c2d_text_wrapper_function(U64 font, I64 x, I64 y, I64 size, U32 color, U8* text) { Context2D* ctx = C2D_MAGIC; Text2D(ctx, font, x, y, size, color, text); return ctx; } @callable_context2d* @c2d_clipped_wrapper_function() { Context2D* ctx = C2D_MAGIC; return ClipToRect2D(ctx); } @callable_context2d* @c2d_rotated_wrapper_function(F64 angle) { Context2D* src = C2D_MAGIC; return Rotate2D(src, angle); } @callable_context2d* @c2d_scaled_wrapper_function(F64 scale_x, F64 scale_y) { Context2D* src = C2D_MAGIC; return Scale2D(src, scale_x, scale_y); } @callable_context2d* @create_callable_context2d(@context2d* ctx) { @callable_context2d* res = CAlloc(sizeof(@callable_context2d)); MemCpy(res, ctx, sizeof(@context2d)); Free(ctx); U64 a; I64 code_size; // blot code_size = MSize(&@c2d_blot_wrapper_function); res->blot = CAlloc(code_size, adam_task->code_heap); MemCpy(res->blot, &@c2d_blot_wrapper_function, code_size); a = res->blot; a += 0x1c; MemSetI64(a, res, 1); a = res->blot; a += 0x2a; @patch_call_rel32(a, &Blot2D); // blur code_size = MSize(&@c2d_blur_wrapper_function); res->blur = CAlloc(code_size, adam_task->code_heap); MemCpy(res->blur, &@c2d_blur_wrapper_function, code_size); a = res->blur; a += 0x10; MemSetI64(a, res, 1); a = res->blur; a += 0x1a; @patch_call_rel32(a, &BlurInPlace); // copy_rect code_size = MSize(&@c2d_copy_rect_wrapper_function); res->copy_rect = CAlloc(code_size, adam_task->code_heap); MemCpy(res->copy_rect, &@c2d_copy_rect_wrapper_function, code_size); a = res->copy_rect; a += 0x1c; MemSetI64(a, res, 1); a = res->copy_rect; a += 0x2a; @patch_call_rel32(a, &CopyRect2D); // fill code_size = MSize(&@c2d_fill_wrapper_function); res->fill = CAlloc(code_size, adam_task->code_heap); MemCpy(res->fill, &@c2d_fill_wrapper_function, code_size); a = res->fill; a += 0x0f; MemSetI64(a, res, 1); a = res->fill; a += 0x19; @patch_call_rel32(a, &Fill2D); // fill_rect code_size = MSize(&@c2d_fill_rect_wrapper_function); res->fill_rect = CAlloc(code_size, adam_task->code_heap); MemCpy(res->fill_rect, &@c2d_fill_rect_wrapper_function, code_size); a = res->fill_rect; a += 0x28; MemSetI64(a, res, 1); a = res->fill_rect; a += 0x3a; @patch_call_rel32(a, &Rect2D); // peek code_size = MSize(&@c2d_peek_wrapper_function); res->peek = CAlloc(code_size, adam_task->code_heap); MemCpy(res->peek, &@c2d_peek_wrapper_function, code_size); a = res->peek; a += 0x16; MemSetI64(a, res, 1); a = res->peek; a += 0x22; @patch_call_rel32(a, &Peek2D); // plot code_size = MSize(&@c2d_plot_wrapper_function); res->plot = CAlloc(code_size, adam_task->code_heap); MemCpy(res->plot, &@c2d_plot_wrapper_function, code_size); a = res->plot; a += 0x1b; MemSetI64(a, res, 1); a = res->plot; a += 0x29; @patch_call_rel32(a, &Plot2D); // line code_size = MSize(&@c2d_line_wrapper_function); res->line = CAlloc(code_size, adam_task->code_heap); MemCpy(res->line, &@c2d_line_wrapper_function, code_size); a = res->line; a += 0x28; MemSetI64(a, res, 1); a = res->line; a += 0x3a; @patch_call_rel32(a, &Line2D); // text code_size = MSize(&@c2d_text_wrapper_function); res->text = CAlloc(code_size, adam_task->code_heap); MemCpy(res->text, &@c2d_text_wrapper_function, code_size); a = res->text; a += 0x2e; MemSetI64(a, res, 1); a = res->text; a += 0x42; @patch_call_rel32(a, &Text2D); // clipped code_size = MSize(&@c2d_clipped_wrapper_function); res->clipped = CAlloc(code_size, adam_task->code_heap); MemCpy(res->clipped, &@c2d_clipped_wrapper_function, code_size); a = res->clipped; a += 0x0b; MemSetI64(a, res, 1); a = res->clipped; a += 0x14; @patch_call_rel32(a, &ClipToRect2D); // rotated code_size = MSize(&@c2d_rotated_wrapper_function); res->rotated = CAlloc(code_size, adam_task->code_heap); MemCpy(res->rotated, &@c2d_rotated_wrapper_function, code_size); a = res->rotated; a += 0x0b; MemSetI64(a, res, 1); a = res->rotated; a += 0x18; @patch_call_rel32(a, &Rotate2D); // scaled code_size = MSize(&@c2d_scaled_wrapper_function); res->scaled = CAlloc(code_size, adam_task->code_heap); MemCpy(res->scaled, &@c2d_scaled_wrapper_function, code_size); a = res->scaled; a += 0x0b; MemSetI64(a, res, 1); a = res->scaled; a += 0x1c; @patch_call_rel32(a, &Scale2D); return res; } "graphics2d ";