Blame onefile/message3d.c

2ed0d1
2ed0d1
#include <ctype.h></ctype.h>
2ed0d1
#include <math.h></math.h>
2ed0d1
#include <string.h></string.h>
2ed0d1
#include <stdio.h></stdio.h>
2ed0d1
#include <stdlib.h></stdlib.h>
2ed0d1
2ed0d1
#include <helianthus.h></helianthus.h>
2ed0d1
2ed0d1
2ed0d1
#define SPLITPOINTS 17
2ed0d1
double pointsArc[SPLITPOINTS][3];
2ed0d1
double pointsQua[SPLITPOINTS][3];
2ed0d1
double pointsCub[SPLITPOINTS][4];
2ed0d1
2ed0d1
double ax =  0;
2ed0d1
double ay = 10;
2ed0d1
double mx, my;
2ed0d1
2ed0d1
int randomAngle = 1;
2ed0d1
int rnd = 0;
2ed0d1
2ed0d1
typedef struct {
2ed0d1
  double mat[9];
2ed0d1
  double ox, oy;
2ed0d1
  double curr[3];
2ed0d1
} Painter;
2ed0d1
2ed0d1
2ed0d1
const char *letters[][2] = {
2ed0d1
  { "box", "L000-800-880-080-000-008-808-888-088-008 800-808 880-888 080-088"
2ed0d1
           " 004-804-884-084z 040-840-848-048z 400-480-488-408z" },
2ed0d1
  { "star", "L440-533-844-535-448-335-044-333-440-553-844-555-448-355-044-353z"
2ed0d1
            " 333-404-535 335-404-533 353-484-555 355-484-553" },
2ed0d1
  //{ "cube", "L000-800-880-080-000-008-808-888-088-008 800-808 880-888 080-088" },
2ed0d1
  //{ "cub", "L000-800-880-080-000-008-808-888-088-008 800-808 880-888 080-088" },
2ed0d1
  { "a", "L000-448-800 080-448-880 224-624-664-264z" },
2ed0d1
  { "b", "L000-008-608-A808-806-804-604-L004-064-A084-086-088-068-L008 A806-886-086 608-668-068 604-664-064 600-660-060 802-882-082 604-804-802-800-600-L000-060-A080-082-084-064-L004" },
2ed0d1
  { "c", "L800-400-A000-004-008-408-L808-848-A888-884-880-840-L800 A004-084-884 400-440-840 408-448-848" },
2ed0d1
  { "d", "L008-000-400-A800-804-808-408-L008-048-A088-084-080-040-L000 A804-884-084 400-440-040 408-448-048" },
2ed0d1
  { "e", "L000-800-880-080-000-008-808-888-088-008 004-804-884-084z" },
2ed0d1
  { "f", "L000-008-808-888-088-008 004-804-884-084z" },
2ed0d1
  { "g", "L800-804-404-A444-844-L804-A800-400-000-004-008-408-L808-848-A888-884-880-840-800-804 A004-084-884 400-440-840 408-448-848" },
2ed0d1
  { "h", "L004-804-884-084z 000-008 800-808 880-888 080-088" },
2ed0d1
  { "i", "L440-448 220-260-660-620z 228-268-668-628z" },
2ed0d1
  { "j", "A848-888-488-088-048-008-408-808-848-L844-A840-440-040-044-004-404-804-844-884-484-084-044 404-400-440-480-484" },
2ed0d1
  { "k", "L000-008 800-004-808 080-004-088 880-004-888" },
2ed0d1
  { "l", "L008-000-800-880-080-000" },
2ed0d1
  { "m", "L000-228-400-628-800 080-268-480-668-880 040-268-440-668-840-628-440-228z" },
2ed0d1
  { "n", "L000-008-800-808 008-080-088 008-880-888" },
2ed0d1
  { "o", "A044-040-440-840-844-848-448-048-044-004-404-804-844-884-484-084-044 404-400-440-480-484-488-448-408-404" },
2ed0d1
  { "p", "L000-008-608-A808-806-804-604-L004-064-A084-086-088-068-L008 A806-886-086 608-668-068 604-664-064" },
2ed0d1
  { "q", "A044-040-440-840-844-848-448-048-044-004-404-804-844-884-484-084-044 404-400-440-480-484-488-448-408-404 L444-840-A880-480z" },
2ed0d1
  { "r", "L000-008-608-A808-806-804-604-L004-064-A084-086-088-068-L008 A806-886-086 608-668-068 604-664-064 604-804-802-L800-A880-080-L082-A084-064 802-882-082" },
2ed0d1
  { "s", "A424-404-204-004-006-008-208-L808-868-A888-886-884-864-844-644 L208-248-A268-468-L868 006-046-A086-486-L886 A248-048-046-044-244 468-488-486-484-464"
2ed0d1
         " 464-484-684-884-882-880-680-L080-020-A000-002-004-024-L044-244 680-640-A620-420-L020 882-842-A802-402-L002 A640-840-842-844-644 420-400-402-404-424"
2ed0d1
         " 244-224-424-624-644-664-464-264-244" },
2ed0d1
  { "t", "L008-808-888-088z 440-448" },
2ed0d1
  { "u", "A848-888-488-088-048-008-408-808-848-L844-A840-440-040-044-L048 408-404-A400-440-480-484-L488 A044-004-404-804-844-884-484-084-044" },
2ed0d1
  { "v", "L008-440-808 088-440-888" },
2ed0d1
  { "w", "L008-220-408-620-808 088-260-488-660-888 048-260-448-660-848-620-448-220z" },
2ed0d1
  { "x", "L000-888 800-088 880-008 080-808" },
2ed0d1
  { "y", "L000-888 444-088 444-008 444-808" },
2ed0d1
  { "z", "L000-800-880-080-000-888-088-008-808-888" },
2ed0d1
2ed0d1
  { "0", "A044-040-440-840-844-848-448-048-044-004-404-804-844-884-484-084-044 404-400-440-480-484-488-448-408-404 L040-848" },
2ed0d1
  { "1", "L440-448-226 220-260-660-620z" },
2ed0d1
  { "2", "L000-002-A004-204-404-604-804-806-808-608-L008-068-A088-086-084-064-044-024-004-002-L000-800-880-080-000"
2ed0d1
         " 608-648-A668-468-L068 604-644-A664-464-L064 806-846-A886-486-L086 "
2ed0d1
         " A648-848-846-844-644 468-488-486-484-464 " },
2ed0d1
  { "3", "L008-608-A808-806-804-604-L004-064-A084-086-088-068-L008 A806-886-086 608-668-068 604-664-064 600-660-060 802-882-082 604-804-802-800-600-L000-060-A080-082-084-064-L004" },
2ed0d1
  { "4", "L004-804-884-084z 004-008 800-808 884-888 084-088" },
2ed0d1
  { "5", "L008-006-A004-204-404-604-804-802-800-600-L000-060-A080-082-084-064-044-024-004-006-L008-808-888-088-008"
2ed0d1
         " 600-640-A660-460-L060 604-644-A664-464-L064 802-842-A882-482-L082 "
2ed0d1
         " A640-840-842-844-644 460-480-482-484-464 " },
2ed0d1
  { "6", "L042-044-C048-088-488-A888-848-808-408-C008-048-044-048-048-448-L848 408-488"
2ed0d1
         " A042-040-240-L640-A840-842-844-644-L244-A044-042-002-402-802-842-882-482-082-042"
2ed0d1
         "  402-400-420-L460-A480-482-484-464-L424-A404-402 244-224-424-624-644-664-464-264-244 240-220-420-620-640-660-460-260-240 "},
2ed0d1
  { "7", "L000-888-088-008-808-888 224-264-664-624z" },
2ed0d1
  { "8", "A244-044-042-040-240-L640-A840-842-844-644-L244-A044-046-048-248-L648-A848-846-844-644"
2ed0d1
         " 424-404-402-400-420-L460-A480-482-484-464-L424-A404-406-408-428-L468-A488-486-484-464"
2ed0d1
         " 042-002-402-802-842-882-482-082-042 046-006-406-806-846-886-486-086-046"
2ed0d1
         " 240-220-420-620-640-660-460-260-240 244-224-424-624-644-664-464-264-244 248-228-428-628-648-668-468-268-248" },
2ed0d1
  { "9", "L846-844-C840-880-480-A080-040-000-400-C800-840-844-840-840-440-L040 400-480"
2ed0d1
         " A046-048-248-L648-A848-846-844-644-L244-A044-046-006-406-806-846-886-486-086-046"
2ed0d1
         "  406-408-428-L468-A488-486-484-464-L424-A404-406 244-224-424-624-644-664-464-264-244 248-228-428-628-648-668-468-268-248 "},
2ed0d1
2ed0d1
  { ",", "P442 L442-220" },
2ed0d1
  { "...", "P002 402 802 042 442 842 882 482 082" },
2ed0d1
  { "..", "P222 622 662 262" },
2ed0d1
  { ".", "L331-531-551-351-331-333-533-553-353-333 531-533 551-553 351-353 " },
2ed0d1
  //{ ".", "P442" },
2ed0d1
  { "?", "A442-444-424-404-604-804-806-808-608-L008-068-A088-086-084-064-044-244-444-442"
2ed0d1
         " L608-648-A668-468-L068 806-846-A886-486-L086"
2ed0d1
         " A648-848-846-844-644-444-442 468-488-486-484-464-444-442 424-624-644-664-464-264-244 P440" },
2ed0d1
  { "!", "A442-244-246-248-448-648-646-644-442 A442-424-426-428-448-468-466-464-442 246-226-426-626-646-666-466-266-246 P440" },
2ed0d1
  { ":", "P222 622 662 262 226 626 666 266" },
2ed0d1
  { ";", "P222 622 662 262 226 626 666 266 L222-240 L622-420 L662-640 L262-460" },
2ed0d1
  { "\"","P226 626 666 266 L226-244 L626-424 L666-644 L266-464" },
2ed0d1
  { "\'","P446 L446-224" },
2ed0d1
  { "`", "P446 L446-664" },
2ed0d1
  { "<", "L800-044-880 808-044-888" },
2ed0d1
  { ">", "L000-844-080 008-844-088" },
2ed0d1
  { "=", "L222-262-662-622z 226-266-666-626z" },
2ed0d1
  { "-", "L224-264-664-624z" },
2ed0d1
  { "+", "L244-644 424-464 442-446" },
2ed0d1
  { "*", "L244-644 424-464 442-446 222-666 622-266 662-226 262-626" },
2ed0d1
  { "/", "L000-888" },
2ed0d1
  { "\\","L800-088" },
2ed0d1
  { "^", "L226-448-666 626-448-266" },
2ed0d1
  { "(", "A640-680-684-688-648-608-604-600-640-240-244-248-648 604-204-244-284-684" },
2ed0d1
  { ")", "A240-280-284-288-248-208-204-200-240-640-644-648-248 204-604-644-684-284" },
2ed0d1
  { "[", "L640-680-684-688-648-608-604-600-640-240-244-248-648 604-204-244-284-684" },
2ed0d1
  { "]", "L240-280-284-288-248-208-204-200-240-640-644-648-248 204-604-644-684-284" },
2ed0d1
  { "{", "A640-440-442-444-244-444-446-448-648 604-404-424-444-244-444-464-484-684"
2ed0d1
         " 464-466-446-426-424-422-442-462-464 L684-688-648-608-604-600-640-680-684 " },
2ed0d1
  { "}", "A240-440-442-444-644-444-446-448-248 204-404-424-444-644-444-464-484-284"
2ed0d1
         " 464-466-446-426-424-422-442-462-464 L284-288-248-208-204-200-240-280-284 " },
2ed0d1
  { "_", "L000-800-880-080z" },
2ed0d1
  { "||","L220-228 620-628 660-668 260-268" },
2ed0d1
  { "|", "L440-448" },
2ed0d1
  { "#", "L220-228 620-628 660-668 260-268 202-282 206-286 606-686 602-682 022-822 062-862 066-866 026-826" },
2ed0d1
  { "@", "A244-242-442-642-644-646-446-246-244-224-424-624-644-664-464-264-244 424-422-442-462-464-466-446-426-424"
2ed0d1
         " 440-480-484-084-044-040-440-L840-800-400-440"
2ed0d1
         " C[8.00][4.00][0.00]-[8.00][6.31][0.00]-[4.52][8.33][1.78]-[4.00][8.00][4.00]"
2ed0d1
                             "-[3.83][7.89][4.73]-[3.89][7.53][5.53]-[4.12][7.03][6.06]"
2ed0d1
                             "-[4.36][6.53][6.59]-[4.78][5.83][6.91]-[5.18][5.18][6.89]"
2ed0d1
                             "-[5.57][4.55][6.86]-[5.98][3.88][6.51]-[6.20][3.43][5.96]"
2ed0d1
                             "-[6.41][3.00][5.44]-[6.47][2.71][4.68]-[6.31][2.67][4.00]"
2ed0d1
                             "-[6.17][2.62][3.38]-[5.82][2.78][2.73]-[5.37][3.06][2.36]"
2ed0d1
                             "-[4.98][3.30][2.04]-[4.45][3.68][1.88]-[4.00][4.00][2.00]"
2ed0d1
                             "-[4.32][3.55][1.88]-[4.70][3.02][2.04]-[4.94][2.63][2.36]"
2ed0d1
                             "-[5.22][2.18][2.73]-[5.38][1.83][3.38]-[5.33][1.69][4.00]"
2ed0d1
                             "-[5.29][1.53][4.68]-[5.00][1.59][5.44]-[4.57][1.80][5.96]"
2ed0d1
                             "-[4.12][2.02][6.51]-[3.45][2.43][6.86]-[2.82][2.82][6.89]"
2ed0d1
                             "-[2.17][3.22][6.91]-[1.47][3.64][6.59]-[0.97][3.88][6.06]"
2ed0d1
                             "-[0.47][4.11][5.53]-[0.11][4.17][4.73]-[0.00][4.00][4.00]"
2ed0d1
                             "-[-0.33][3.48][1.78]-[1.69][0.00][0.00]-[4.00][0.00][0.00]"
2ed0d1
          " [5.18][5.18][6.89]-[4.50][4.50][7.44]-[3.50][3.50][7.44]-[2.82][2.82][6.89]" },
2ed0d1
  { "&", " A046-048-248-L648-A848-846-844-644-L244-A044-046-006-406-806-846-886-486-086-046"
2ed0d1
          " 406-408-428-L468-A488-486-484-464-L424-A404-406 244-224-424-624-644-664-464-264-244 248-228-428-628-648-668-468-268-248"
2ed0d1
         " A424-404-204-004-002-000-200-L800-860-A880-882-884-864-844-644"
2ed0d1
         " L200-240-A260-460-L860 002-042-A082-482-L882 A240-040-042-044-244 460-480-482-484-464" },
2ed0d1
  { "%", "A066-064-264-464-466-468-268-068-066-046-246-446-466-486-286-086-066 246-244-264-284-286-288-268-248-246"
2ed0d1
         " 422-420-620-820-822-824-624-424-422-402-602-802-822-842-642-442-422 602-600-620-640-642-644-624-604-602"
2ed0d1
         " L000-888" },
2ed0d1
  { "~", "C244-254-255-355-A455-444-433-533-C633-634-644 A244-224-424-624-644-664-464-264-244" },
2ed0d1
  { "$", "A424-404-204-004-006-008-208-L808-868-A888-886-884-864-844-644 L208-248-A268-468-L868 006-046-A086-486-L886 A248-048-046-044-244 468-488-486-484-464"
2ed0d1
         " 464-484-684-884-882-880-680-L080-020-A000-002-004-024-L044-244 680-640-A620-420-L020 882-842-A802-402-L002 A640-840-842-844-644 420-400-402-404-424"
2ed0d1
         " 244-224-424-624-644-664-464-264-244 L24[-2]-24[10] L64[-2]-64[10] L42[-2]-42[10] L46[-2]-46[10] " },
2ed0d1
};
2ed0d1
int lettersCount = sizeof(letters)/sizeof(letters[0]);
2ed0d1
2ed0d1
const char *textToDraw = NULL;
2ed0d1
double boxStep = 64;
2ed0d1
double boxSize = 0.5;
2ed0d1
int renderToFiles = 0;
2ed0d1
2ed0d1
2ed0d1
void vec3set(double *v, double x, double y, double z)
2ed0d1
  { v[0] = x, v[1] = y, v[2] = z; }
2ed0d1
void vec3cpy(double *v, const double *vv)
2ed0d1
  { memcpy(v, vv, sizeof(*v)*3); }
2ed0d1
void vec3add(double *v, const double *vv)
2ed0d1
  { v[0] += vv[0]; v[1] += vv[1]; v[2] += vv[2]; }
2ed0d1
void vec3trans(double *v, const double *m) {
2ed0d1
  vec3set(v, v[0]*m[0] + v[1]*m[3] + v[2]*m[6],
2ed0d1
             v[0]*m[1] + v[1]*m[4] + v[2]*m[7],
2ed0d1
             v[0]*m[2] + v[1]*m[5] + v[2]*m[8] );
2ed0d1
}
2ed0d1
2ed0d1
void mat3cpy(double *m, double *mm)
2ed0d1
  { memcpy(m, mm, sizeof(*m)*9); }
2ed0d1
void mat3one(double *m) {
2ed0d1
  m[1] = m[2] = m[3] = m[5] = m[6] = m[7] = 0;
2ed0d1
  m[0] = m[4] = m[8] = 1;
2ed0d1
}
2ed0d1
void mat3trans(double *m, const double *mm) {
2ed0d1
  vec3trans(m+0, mm);
2ed0d1
  vec3trans(m+3, mm);
2ed0d1
  vec3trans(m+6, mm);
2ed0d1
}
2ed0d1
void mat3rotX(double *m, double a) {
2ed0d1
  rotateVector(&m[1], &m[2], a);
2ed0d1
  rotateVector(&m[4], &m[5], a);
2ed0d1
  rotateVector(&m[7], &m[8], a);
2ed0d1
}
2ed0d1
void mat3rotY(double *m, double a) {
2ed0d1
  rotateVector(&m[2], &m[0], a);
2ed0d1
  rotateVector(&m[5], &m[3], a);
2ed0d1
  rotateVector(&m[8], &m[6], a);
2ed0d1
}
2ed0d1
void mat3rotZ(double *m, double a) {
2ed0d1
  rotateVector(&m[0], &m[1], a);
2ed0d1
  rotateVector(&m[3], &m[4], a);
2ed0d1
  rotateVector(&m[6], &m[7], a);
2ed0d1
}
2ed0d1
2ed0d1
2ed0d1
void painterInternalMoveTo(Painter *p, double x, double y, double z) {
2ed0d1
  double xx = p->mat[0]*x + p->mat[3]*y + p->mat[6]*z + p->ox;
2ed0d1
  double yy = p->mat[1]*x + p->mat[4]*y + p->mat[7]*z + p->oy;
2ed0d1
  moveTo(xx, yy);
2ed0d1
}
2ed0d1
2ed0d1
void painterInternalLineTo(Painter *p, double x, double y, double z) {
2ed0d1
  double xx = p->mat[0]*x + p->mat[3]*y + p->mat[6]*z + p->ox;
2ed0d1
  double yy = p->mat[1]*x + p->mat[4]*y + p->mat[7]*z + p->oy;
2ed0d1
  lineTo(xx, yy);
2ed0d1
}
2ed0d1
2ed0d1
void painterInternalPointTo(Painter *p, double x, double y, double z) {
2ed0d1
  double xx = p->mat[0]*x + p->mat[3]*y + p->mat[6]*z + p->ox;
2ed0d1
  double yy = p->mat[1]*x + p->mat[4]*y + p->mat[7]*z + p->oy;
2ed0d1
  saveState();
2ed0d1
  translate(xx, yy);
2ed0d1
  zoom(3);
2ed0d1
  point(0, 0);
2ed0d1
  restoreState();
2ed0d1
}
2ed0d1
2ed0d1
void painterFinish(Painter *p)
2ed0d1
  { strokePath(); }
2ed0d1
2ed0d1
void painterMoveTo(Painter *p, double *pos) {
2ed0d1
  painterFinish(p);
2ed0d1
  painterInternalMoveTo(p, pos[0], pos[1], pos[2]);
2ed0d1
  vec3cpy(p->curr, pos);
2ed0d1
}
2ed0d1
2ed0d1
void painterLineTo(Painter *p, double *pos) {
2ed0d1
  painterInternalLineTo(p, pos[0], pos[1], pos[2]);
2ed0d1
  vec3cpy(p->curr, pos);
2ed0d1
}
2ed0d1
2ed0d1
void painterPointTo(Painter *p, double *pos) {
2ed0d1
  painterFinish(p);
2ed0d1
  painterInternalPointTo(p, pos[0], pos[1], pos[2]);
2ed0d1
  vec3cpy(p->curr, pos);
2ed0d1
}
2ed0d1
2ed0d1
void painterArcTo(Painter *p, double *pos1, double *pos2) {
2ed0d1
  double *pos0 = p->curr;
2ed0d1
  for(int i = 1; i < SPLITPOINTS; ++i)
2ed0d1
    painterInternalLineTo( p,
2ed0d1
      pointsArc[i][0]*pos0[0] + pointsArc[i][1]*pos1[0] + pointsArc[i][2]*pos2[0],
2ed0d1
      pointsArc[i][0]*pos0[1] + pointsArc[i][1]*pos1[1] + pointsArc[i][2]*pos2[1],
2ed0d1
      pointsArc[i][0]*pos0[2] + pointsArc[i][1]*pos1[2] + pointsArc[i][2]*pos2[2] );
2ed0d1
  vec3cpy(p->curr, pos2);
2ed0d1
}
2ed0d1
2ed0d1
void painterQuadraticTo(Painter *p, double *pos1, double *pos2) {
2ed0d1
  double *pos0 = p->curr;
2ed0d1
  for(int i = 1; i < SPLITPOINTS; ++i)
2ed0d1
    painterInternalLineTo( p,
2ed0d1
      pointsQua[i][0]*pos0[0] + pointsQua[i][1]*pos1[0] + pointsQua[i][2]*pos2[0],
2ed0d1
      pointsQua[i][0]*pos0[1] + pointsQua[i][1]*pos1[1] + pointsQua[i][2]*pos2[1],
2ed0d1
      pointsQua[i][0]*pos0[2] + pointsQua[i][1]*pos1[2] + pointsQua[i][2]*pos2[2] );
2ed0d1
  vec3cpy(p->curr, pos2);
2ed0d1
}
2ed0d1
2ed0d1
void painterCubicTo(Painter *p, double *pos1, double *pos2, double *pos3) {
2ed0d1
  double *pos0 = p->curr;
2ed0d1
  for(int i = 1; i < SPLITPOINTS; ++i)
2ed0d1
    painterInternalLineTo( p,
2ed0d1
      pointsCub[i][0]*pos0[0] + pointsCub[i][1]*pos1[0] + pointsCub[i][2]*pos2[0] + pointsCub[i][3]*pos3[0],
2ed0d1
      pointsCub[i][0]*pos0[1] + pointsCub[i][1]*pos1[1] + pointsCub[i][2]*pos2[1] + pointsCub[i][3]*pos3[1],
2ed0d1
      pointsCub[i][0]*pos0[2] + pointsCub[i][1]*pos1[2] + pointsCub[i][2]*pos2[2] + pointsCub[i][3]*pos3[2] );
2ed0d1
  vec3cpy(p->curr, pos3);
2ed0d1
}
2ed0d1
2ed0d1
void painterClose(Painter *p)
2ed0d1
  { closePath(); }
2ed0d1
2ed0d1
2ed0d1
void drawLetter(Painter *p, const char *cmd) {
2ed0d1
  saveState();
2ed0d1
  noFill();
2ed0d1
  double mat[11];
2ed0d1
  mat3cpy(mat, p->mat);
2ed0d1
  mat[9] = p->ox; mat[10] = p->oy;
2ed0d1
  if (randomAngle) {
2ed0d1
    double m[9], v[3];
2ed0d1
    vec3set(v, -4, -4, -4);
2ed0d1
    vec3trans(v, p->mat);
2ed0d1
2ed0d1
    mat3one(m);
2ed0d1
    mat3rotZ(m, randomFloat()*360);
2ed0d1
    mat3trans(m, p->mat);
2ed0d1
    mat3cpy(p->mat, m);
2ed0d1
2ed0d1
    vec3set(m, -4, -4, -4);
2ed0d1
    vec3trans(m, p->mat);
2ed0d1
    p->ox += m[0] - v[0], p->oy += m[1] - v[1];
2ed0d1
  }
2ed0d1
2ed0d1
  char mode = 'L';
2ed0d1
2ed0d1
  int begin = 1;
2ed0d1
  int relative = 0;
2ed0d1
  int cnt = 0;
2ed0d1
  double coords[3][3] = {};
2ed0d1
2ed0d1
  for(const char *c = cmd; 1; ++c) {
2ed0d1
    switch(*c) {
2ed0d1
    case 'L':
2ed0d1
    case 'A':
2ed0d1
    case 'Q':
2ed0d1
    case 'C':
2ed0d1
    case 'P':
2ed0d1
      mode = *c;
2ed0d1
      relative = 0;
2ed0d1
      cnt = 0;
2ed0d1
      break;
2ed0d1
    case 'l':
2ed0d1
    case 'a':
2ed0d1
    case 'q':
2ed0d1
    case 'c':
2ed0d1
    case 'p':
2ed0d1
      mode = toupper(*c);
2ed0d1
      relative = 1;
2ed0d1
      cnt = 0;
2ed0d1
      break;
2ed0d1
    case '0':
2ed0d1
    case '1':
2ed0d1
    case '2':
2ed0d1
    case '3':
2ed0d1
    case '4':
2ed0d1
    case '5':
2ed0d1
    case '6':
2ed0d1
    case '7':
2ed0d1
    case '8':
2ed0d1
    case '9':
2ed0d1
      coords[0][0] = coords[0][1];
2ed0d1
      coords[0][1] = coords[0][2];
2ed0d1
      coords[0][2] = *c - '0';
2ed0d1
      break;
2ed0d1
    case '[':
2ed0d1
      coords[0][0] = coords[0][1];
2ed0d1
      coords[0][1] = coords[0][2];
2ed0d1
      coords[0][2] = atof(c+1);
2ed0d1
      while(*c != ']' && c[1]) ++c;
2ed0d1
      break;
2ed0d1
    case '-':
2ed0d1
    case ' ':
2ed0d1
    case 'z':
2ed0d1
    case 'Z':
2ed0d1
    case 0:
2ed0d1
      if (relative) vec3add(coords[0], coords[cnt+1]);
2ed0d1
2ed0d1
      if (mode == 'P') {
2ed0d1
        painterPointTo(p, coords[0]);
2ed0d1
        begin = 1; cnt = 0;
2ed0d1
      } else
2ed0d1
      if (begin) {
2ed0d1
        painterMoveTo(p, coords[0]);
2ed0d1
        begin = 0;
2ed0d1
      } else
2ed0d1
      if (mode == 'L') {
2ed0d1
        painterLineTo(p, coords[0]);
2ed0d1
      } else
2ed0d1
      if (mode == 'A') {
2ed0d1
        if (cnt) { painterArcTo(p, coords[1], coords[0]); cnt = 0; }
2ed0d1
            else { vec3cpy(coords[1], coords[0]); ++cnt; }
2ed0d1
      } else
2ed0d1
      if (mode == 'Q') {
2ed0d1
        if (cnt) { painterQuadraticTo(p, coords[1], coords[0]); cnt = 0; }
2ed0d1
            else { vec3cpy(coords[1], coords[0]); ++cnt; }
2ed0d1
      } else
2ed0d1
      if (mode == 'C') {
2ed0d1
        if (cnt > 1) { painterCubicTo(p, coords[2], coords[1], coords[0]); cnt = 0; }
2ed0d1
                else { vec3cpy(coords[2], coords[1]); vec3cpy(coords[1], coords[0]); ++cnt; }
2ed0d1
      }
2ed0d1
2ed0d1
      if (*c == ' ' || *c == 0) {
2ed0d1
        painterFinish(p);
2ed0d1
        begin = 1; cnt = 0;
2ed0d1
      } else
2ed0d1
      if (*c == 'z' || *c == 'Z') {
2ed0d1
        painterClose(p);
2ed0d1
        begin = 1; cnt = 0;
2ed0d1
      }
2ed0d1
      break;
2ed0d1
    }
2ed0d1
    if (!*c) break;
2ed0d1
  }
2ed0d1
2ed0d1
  mat3cpy(p->mat, mat);
2ed0d1
  p->ox = mat[9]; p->oy = mat[10];
2ed0d1
  restoreState();
2ed0d1
}
2ed0d1
2ed0d1
2ed0d1
void drawStr(
2ed0d1
  Painter *p, double dx, double dy,
2ed0d1
  const char *str, char stopChar,
2ed0d1
  int *rows, int *cols )
2ed0d1
{
2ed0d1
  if (randomAngle) srand(rnd);
2ed0d1
  double ox, oy;
2ed0d1
  if (p) { ox = p->ox; oy = p->oy; }
2ed0d1
2ed0d1
  int row = 0, col = 0, maxRow = -1, maxCol = -1;
2ed0d1
  for(const char *c = str; *c && *c != stopChar; ++c) {
2ed0d1
    if (*c == '\n')
2ed0d1
      { ++row; col = 0; continue; }
2ed0d1
2ed0d1
    for(int i = 0; i < lettersCount; ++i) {
2ed0d1
      int equals = 0;
2ed0d1
      for(const char *ca = c, *cb = letters[i][0]; 1; ++ca, ++cb) {
2ed0d1
        if (!*cb) { equals = 1; c += cb-letters[i][0]-1; break; }
2ed0d1
        if (!*ca || *ca == stopChar || tolower(*ca) != tolower(*cb)) break;
2ed0d1
      }
2ed0d1
      if (equals) {
2ed0d1
        if (maxCol < col) maxCol = col;
2ed0d1
        if (maxRow < row) maxRow = row;
2ed0d1
        if (p) {
2ed0d1
          p->ox = ox + col*dx;
2ed0d1
          p->oy = oy + row*dy;
2ed0d1
          drawLetter(p, letters[i][1]);
2ed0d1
        }
2ed0d1
        break;
2ed0d1
      }
2ed0d1
    }
2ed0d1
    ++col;
2ed0d1
  }
2ed0d1
  if (p) { p->ox = ox; p->oy = oy; }
2ed0d1
  if (rows) *rows = maxRow + 1;
2ed0d1
  if (cols) *cols = maxCol + 1;
2ed0d1
}
2ed0d1
2ed0d1
2ed0d1
void drawAllLetters(Painter *p) {
2ed0d1
  if (randomAngle) srand(rnd);
2ed0d1
  double ox = p->ox, oy = p->oy;
2ed0d1
  int lcnt = (int)ceil(sqrt(lettersCount) - 1e-6);
2ed0d1
  for(int i = 0; i < lettersCount; ++i) {
2ed0d1
    int r = i/lcnt, c = i%lcnt;
2ed0d1
    p->ox = (c - 0.5*(lcnt - 1))*boxStep + ox;
2ed0d1
    p->oy = (r - 0.5*(lcnt - 1))*boxStep + oy;
2ed0d1
    drawLetter(p, letters[i][1]);
2ed0d1
  }
2ed0d1
  p->ox = ox; p->oy = oy;
2ed0d1
}
2ed0d1
2ed0d1
2ed0d1
void initCurvePoints() {
2ed0d1
  for(int i = 0; i < SPLITPOINTS; ++i) {
2ed0d1
    double l = i/(SPLITPOINTS-1.0), k = 1-l;
2ed0d1
    double a = l*PI/2, s = sin(a), c = cos(a);
2ed0d1
2ed0d1
    pointsQua[i][0] = k*k;
2ed0d1
    pointsQua[i][1] = 2*k*l;
2ed0d1
    pointsQua[i][2] = l*l;
2ed0d1
2ed0d1
    pointsCub[i][0] = k*k*k;
2ed0d1
    pointsCub[i][1] = 3*k*k*l;
2ed0d1
    pointsCub[i][2] = 3*l*l*k;
2ed0d1
    pointsCub[i][3] = l*l*l;
2ed0d1
2ed0d1
    pointsArc[i][0] = 1-s;
2ed0d1
    pointsArc[i][1] = s+c-1;
2ed0d1
    pointsArc[i][2] = 1-c;
2ed0d1
  }
2ed0d1
}
2ed0d1
2ed0d1
2ed0d1
2ed0d1
2ed0d1
void render(int framesCount) {
2ed0d1
  saveState();
2ed0d1
2ed0d1
  int rows, cols;
2ed0d1
  drawStr(NULL, 0, 0, textToDraw, 0, &rows, &cols);
2ed0d1
  int w = (int)ceil(cols*boxStep - 1e-5);
2ed0d1
  int h = (int)ceil(rows*boxStep - 1e-5);
2ed0d1
  Framebuffer fb = createFramebuffer(w, h);
2ed0d1
  target(fb);
2ed0d1
2ed0d1
  for(int i = 0; i < framesCount; ++i) {
2ed0d1
    clear();
2ed0d1
    double step = boxStep*boxSize/8.0;
2ed0d1
    double mat[9] = {step, 0, 0, 0, 0, step, 0, -step, 0};
2ed0d1
    mat3rotY(mat, 360.0*i/framesCount);
2ed0d1
    mat3rotX(mat, 10);
2ed0d1
    double vec[3] = {-4, -4, -4};
2ed0d1
    vec3trans(vec, mat);
2ed0d1
2ed0d1
    Painter p = {};
2ed0d1
    mat3cpy(p.mat, mat);
2ed0d1
    p.ox = vec[0] + boxStep/2; p.oy = vec[1] + boxStep/2;
2ed0d1
    drawStr(&p, boxStep, boxStep, textToDraw, 0, &rows, &cols);
2ed0d1
2ed0d1
    char buf[1024] = {};
2ed0d1
    sprintf(buf, "data/output/message3d/msg%04d.png", i);
2ed0d1
    printf("save file: %s\n", buf);
2ed0d1
    viewportSave(buf);
2ed0d1
  }
2ed0d1
2ed0d1
  noTarget();
2ed0d1
  framebufferDestroy(fb);
2ed0d1
  restoreState();
2ed0d1
}
2ed0d1
2ed0d1
2ed0d1
void init() {
2ed0d1
  rnd = rand();
2ed0d1
  if (renderToFiles)
2ed0d1
      render(64);
2ed0d1
}
2ed0d1
2ed0d1
2ed0d1
void draw() {
2ed0d1
  double pmx = mx, pmy = my;
2ed0d1
  mx = mouseX(), my = mouseY();
2ed0d1
2ed0d1
  double w = windowGetWidth();
2ed0d1
  double h = windowGetHeight();
2ed0d1
  saveState();
2ed0d1
  translate(w/2, h/2);
2ed0d1
2ed0d1
  int ml = mouseDown("left");
2ed0d1
  int mr = mouseDown("right");
2ed0d1
2ed0d1
  ax += ml ? pmx - mx : windowGetFrameTime()*360/2;
2ed0d1
  if (ml || mr) ay += my - pmy;
2ed0d1
  ax = fmod(ax, 360);
2ed0d1
  ay = fmod(ay, 360);
2ed0d1
2ed0d1
  double step = boxStep*boxSize/8.0;
2ed0d1
  double mat[9] = {step, 0, 0, 0, 0, step, 0, -step, 0};
2ed0d1
  mat3rotY(mat, ax);
2ed0d1
  mat3rotX(mat, ay);
2ed0d1
  double vec[3] = {-4, -4, -4};
2ed0d1
  vec3trans(vec, mat);
2ed0d1
2ed0d1
  Painter p = {};
2ed0d1
  mat3cpy(p.mat, mat);
2ed0d1
  p.ox = vec[0]; p.oy = vec[1];
2ed0d1
2ed0d1
  if (textToDraw) {
2ed0d1
    int rows, cols;
2ed0d1
    drawStr(NULL, 0, 0, textToDraw, 0, &rows, &cols);
2ed0d1
    p.ox -= (cols - 1)*boxStep/2;
2ed0d1
    p.oy -= (rows - 1)*boxStep/2;
2ed0d1
    drawStr(&p, boxStep, boxStep, textToDraw, 0, &rows, &cols);
2ed0d1
  } else {
2ed0d1
    drawAllLetters(&p);
2ed0d1
  }
2ed0d1
2ed0d1
  restoreState();
2ed0d1
}
2ed0d1
2ed0d1
2ed0d1
int main(int argc, char **argv) {
2ed0d1
  initCurvePoints();
2ed0d1
2ed0d1
  windowSetSize(768, 768);
2ed0d1
2ed0d1
  if (argc > 1) {
2ed0d1
    textToDraw = argv[1];
2ed0d1
    if (argc > 2 && strcmp(argv[2], "render") == 0) renderToFiles = 1;
2ed0d1
2ed0d1
    int rows, cols;
2ed0d1
    drawStr(NULL, 0, 0, textToDraw, 0, &rows, &cols);
2ed0d1
    double w = boxStep*cols;
2ed0d1
    if (w > 1024) boxStep *= 1024/w;
2ed0d1
    double h = boxStep*rows;
2ed0d1
    if (h > 768) boxStep *= 768/h;
2ed0d1
    windowSetSize( (int)ceil(boxStep*cols - 1e-5), (int)ceil(boxStep*rows - 1e-5) );
2ed0d1
  } else {
2ed0d1
    printf(
2ed0d1
      "Usage: message3d <message> [render]\n"</message>
2ed0d1
      " - render path is hardcoded to data/output/message3d/msgXXXX.png\n" );
2ed0d1
  }
2ed0d1
2ed0d1
  windowSetVariableFrameRate();
2ed0d1
  windowSetResizable(TRUE);
2ed0d1
  windowSetInit(&init);
2ed0d1
  windowSetDraw(&draw);
2ed0d1
  windowRun();
2ed0d1
}
2ed0d1
2ed0d1
2ed0d1