Blob Blame Raw

#include <stdio.h>
#include <helianthus.h>


#define CW 4
#define CH 5

#define MAXW 1024
#define MAXH 1024
#define BORDER 1

#define ROWS   8
#define COLS  12

#define WIDTH  (COLS*(CW + BORDER) + BORDER)
#define HEIGHT (ROWS*(CH + BORDER) + BORDER)
#define CS ((MAXW/WIDTH) < (MAXH/HEIGHT) ? (MAXW/WIDTH) : (MAXH/HEIGHT))

#define IW 512
#define IH 512
#define IB 16

#define BCOLOR COLOR_BLACK
#define FCOLOR COLOR_WHITE
#define SCOLOR COLOR_YELLOW

#define QUOTES2(x) #x
#define QUOTES(x) QUOTES2(x)

#define PREFIX  "data/output/pixelfont" QUOTES(CW) QUOTES(CH)
#define MAPFILE PREFIX ".map"
#define IMGFILE PREFIX ".png"
#define CFILE   PREFIX ".c"


int map[HEIGHT][WIDTH];
unsigned int img[IH][IW];
Animation imgAnim;
int k = 1;

const char demoText[] =
  "THE QUICK BROWN FOX JUMPS OVER A LAZY DOG.\n"
  "the quick brown fox jumps over a lazy dog.\n"
  "\n"
  "`~!@#$%^&*()-_+=\\|[]{};:'\",.<>/?\n"
  "\n"
  "\"Free software\" means software that respects users' freedom and community.\n"
  "Roughly, it means that the users have the freedom to run, copy, distribute,\n"
  "study, change and improve the software. Thus, \"free software\" is a matter\n"
  "of liberty, not price. To understand the concept, you should think of \"free\"\n"
  "as in \"free speech\", not as in \"free beer\". We sometimes call it \"libre\n"
  "software,\" borrowing the French or Spanish word for \"free\" as in freedom,\n"
  "to show we do not mean the software is gratis.\n"
  "\n"
  "12+(34-56)*67/890\n"
  "\n"
  "2^3=8\n"
  "3/100=3%\n"
  "\n"
  "e-mail of Richard Stallman: rms@gnu.org\n"
  "\n"
  "`reverse apostrophe`, ~tilda, array[12], {scope}\n"
  "price is $100\n"
  "\n"
  "#include <stdio.h>\n"
  "int x = IB, y = IB;\n"
  "for(const char *c = demoText; *c; ++c) {\n"
  "  if (*c == '\\n') { x = IB, y += CH+BORDER; continue; }\n"
  "  if (*c >= 32 && *c < 128) {\n"
  "    int mx = ((int)*c - 32)%COLS*(CW + BORDER) + BORDER;\n"
  "    int my = ((int)*c - 32)/COLS*(CH + BORDER) + BORDER;\n"
  "    for(int yy = 0; yy < CH; ++yy)\n"
  "    for(int xx = 0; xx < CW; ++xx)\n"
  "      if (map[my + yy][mx + xx])\n"
  "        img[y + yy][x + xx] = FCOLOR;\n"
  "  }\n"
  "  x += CW+BORDER;\n"
  "}\n";


void buildDemoImage() {
  for(int y = 0; y < IH; ++y)
  for(int x = 0; x < IW; ++x)
    imageSetPixel(IW, IH, img, x, y, BCOLOR);

  int x = IB, y = IB;
  for(const char *c = demoText; *c; ++c) {
    if (*c == '\n') { x = IB, y += CH+BORDER; continue; }
    if (*c >= 32 && *c < 128) {
      int mx = ((int)*c - 32)%COLS*(CW + BORDER) + BORDER;
      int my = ((int)*c - 32)/COLS*(CH + BORDER) + BORDER;
      for(int yy = 0; yy < CH; ++yy)
      for(int xx = 0; xx < CW; ++xx)
        if (map[my + yy][mx + xx])
          imageSetPixel(IW, IH, img, x + xx, y + yy, FCOLOR);
    }
    x += CW+BORDER;
  }

  if (imgAnim) animationDestroy(imgAnim);
  imgAnim = createAnimationFromImageEx(IW, IH, img, FALSE, FALSE, FALSE, FALSE);
}


void save() {
  FILE *f = fopen(MAPFILE, "w");
  if (!f)
    { printf("cannot write to file: %s\n", MAPFILE); return; }
  for(int y = 0; y < HEIGHT; ++y) {
    for(int x = 0; x < WIDTH; ++x)
      fputc(map[y][x] ? '#' : ' ', f);
    fputc('\n', f);
  }
  fclose(f);

  imageSave(IMGFILE, IW, IH, img);

  f = fopen(CFILE, "w");
  if (!f)
    { printf("cannot write to file: %s\n", CFILE); return; }

  int bits = CW*CH;
  char format[] = " 0x%00llx,";
  format[5] = '0' + (bits-1)/4 + 1;
  unsigned long long bit = 1ull << (bits-1);
  const char *itype = bits <=  8 ? "char"
                    : bits <= 16 ? "short"
                    : bits <= 32 ? "int"
                    : "long long";

  fprintf(f, "unsigned %s font%dx%d_data[] = {\n", itype, CW, CH);
  for(int r = 0; r < COLS; ++r) {
    fprintf(f, " ");
    for(int c = 0; c < ROWS; ++c) {
      int i = r*ROWS + c;
      int x = i%COLS*(CW+BORDER) + BORDER;
      int y = i/COLS*(CH+BORDER) + BORDER;
      unsigned long long d = 0;
      for(int yy = 0; yy < CH; ++yy)
      for(int xx = 0; xx < CW; ++xx)
        d = (d >> 1) | (map[y + yy][x + xx] ? bit : 0);
      fprintf(f, format, d);
    }
    fprintf(f, "\n");
  }
  fprintf(f, "};\n");
  fclose(f);
}


void load() {
  for(int y = 0; y < HEIGHT; ++y)
  for(int x = 0; x < WIDTH; ++x)
    map[y][x] = 0;

  FILE *f = fopen(MAPFILE, "r");
  if (!f)
    { printf("cannot read from file: %s\n", MAPFILE); return; }
  int x = 0, y = 0;
  while(!feof(f)) {
    int c = fgetc(f);
    if (c == '\n') { x = 0; ++y; continue; }
    if (c == '#' && x < WIDTH && y < HEIGHT)
      map[y][x] = 1;
    ++x;
  }
}


void init() {
  background(BCOLOR);
  load();
  buildDemoImage();
}


void draw() {
  saveState();

  int imx = (int)(mouseX()/CS);
  int imy = (int)(mouseY()/CS);

  double o = CS/2.0;
  stroke(colorWithAlpha(FCOLOR, 0.25));
  strokeWidth(1);
  for(int r = 0; r <= ROWS; ++r)
    line(o, o + r*(CH+BORDER)*CS, CS*WIDTH - o, o + r*(CH+BORDER)*CS);
  for(int c = 0; c <= COLS; ++c)
    line(o + c*(CW+BORDER)*CS, o, o + c*(CW+BORDER)*CS, CS*HEIGHT - o);

  noFill();
  textAlign(HALIGN_CENTER, VALIGN_CENTER);
  textSize(CH*CS*0.5);
  for(int i = 0; i < 96; ++i) {
    double x = ((i%COLS + 0.5)*(CW+BORDER) + BORDER)*CS;
    double y = ((i/COLS + 0.5)*(CH+BORDER) + BORDER)*CS;
    char t[2] = { i+32, 0 };
    text(x, y, t);
  }

  fill(COLOR_WHITE);
  rectTextured(imgAnim, WIDTH*CS + o, o, IW*k, IH*k);

  noStroke();
  fill(FCOLOR);
  for(int y = 0; y < HEIGHT; ++y)
  for(int x = 0; x < WIDTH; ++x)
    if (map[y][x]) rect(x*CS, y*CS, CS, CS);

  if ( imx >= BORDER && imx < WIDTH
    && imy >= BORDER && imy < HEIGHT
    && (imx-BORDER)%(CW+BORDER) < CW
    && (imy-BORDER)%(CH+BORDER) < CH )
  {
    fill(colorWithAlpha(SCOLOR, 0.25));
    rect(imx*CS, imy*CS, CS, CS);
    if (mouseDown("left"))  { map[imy][imx] = 1; buildDemoImage(); }
    if (mouseDown("right")) { map[imy][imx] = 0; buildDemoImage(); }
  }

  if (keyWentDown("s")) {
    printf("saving\n");
    save();
  }

  if (keyWentDown("any +")) {
    k = k == 1 ? 2 : 1;
  }

  restoreState();
}


int main() {
  windowSetResizable(TRUE);
  windowSetVariableFrameRate();
  windowSetInit(&init);
  windowSetDraw(&draw);
  windowRun();
  return 0;
}