static int debug = 0;

#define FPS 30

#define SHOW_FPS 1 // if enabled in fbgl

//#define USE_FB_320X480 1  // Now passing this in on the cc command line with cc -DUSE_FB_320X480
#ifdef USE_FB_320X480
#define USE_FB 1
#endif

#ifdef USE_FB
#define FBGL_IMPLEMENTATION 1
#include "fbgl.h"
fbgl_psf1_font_t *font;
#else
#ifdef __linux
#warning No graphics code defined.
#endif
#endif

#ifdef USE_FB
static fbgl_t fb;
static uint32_t fbcolor = 0xFFFFFF;

void fbDrawColor(uint8_t r, uint8_t g, uint8_t b, uint32_t c) {
  fbcolor = (c<<16) | (c<<8) | c;
}

void fbDrawPoint(int32_t x0, int32_t y0) {
  if (debug) fprintf(stdout, "fbDrawPoint(%d,%d);\r\n", x0, y0);
  int sx = (x0*fb.width/128)+fb.width/2;
  int sy = (y0*fb.width/128)+fb.height/2;
  if (debug) fprintf(stdout, "fbgl_put_pixel(%d,%d, %06x, %p;\r\n", sx, sy,  fbcolor, &fb);
  fbgl_put_pixel(sx, (fb.height-1)-sy, fbcolor, &fb);
}

void fbDrawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1) {
  if (debug) fprintf(stdout, "fbDrawLine(%d,%d, %d,%d);\r\n", x0, y0,  x1, y1);
  int sx0 = (x0*fb.width/128)+fb.width/2;
  int sy0 = (y0*fb.width/128)+fb.height/2;
  int sx1 = (x1*fb.width/128)+fb.width/2;
  int sy1 = (y1*fb.width/128)+fb.height/2;
  if (debug) fprintf(stdout, "fbgl_draw_line(%d,%d, %d,%d, %06x, %p);\r\n", sx0, sy0,  sx1, sy1,  fbcolor, &fb);
  fbgl_draw_line((fbgl_point_t){.x=sx0,.y=(fb.height-1)-sy0},
                 (fbgl_point_t){.x=sx1,.y=(fb.height-1)-sy1},
                 fbcolor, &fb);
}
#endif // USE_FB

static int8_t vscale = 127;
static int8_t vbright = 0x7F;
static int8_t vx = 0;
static int8_t vy = 0;

static int fromx = 0, fromy = 0;
static void G_MoveAbs(int8_t x, int8_t y, uint8_t scale) {
  if (debug) fprintf(stdout, "G_MoveAbs(%d,%d, scale=%u);\r\n", x, y, scale);
  fromx = (x * scale) / 256; fromy = (y * scale) / 256;
  if (debug) fprintf(stdout, "fromx = %d; fromy = %d;\r\n", fromx, fromy);
}
static void G_MoveRel(int8_t x, int8_t y, uint8_t scale) {
  if (debug) fprintf(stdout, "G_MoveRel(%d,%d, scale=%u);\r\n", x, y, scale);
  fromx += (x * scale) / 256; fromy += (y * scale) / 256;
  if (debug) fprintf(stdout, "fromx = %d; fromy = %d;\r\n", fromx, fromy);
}
static void G_LineRel(int8_t x, int8_t y, uint8_t intensity, uint8_t scale) {
  if (debug) fprintf(stdout, "G_LineRel(%d,%d, intensity=%d, scale=%d);\r\n", x, y, intensity, scale);
  int tox, toy;
  tox = (x * scale) / 256; toy = (y * scale) / 256;
  // draw [from,fromy] to [tox,toy]
#ifdef USE_FB
  fbDrawColor(intensity, intensity, intensity, intensity);
  fbDrawLine(fromx, fromy, fromx+tox, fromy+toy);
#endif
  fromx += tox; fromy += toy;
}
static void Clear(void) {
  // clear screen
  if (debug) fprintf(stdout, "clear();\r\n");
#ifdef USE_FB
  fbgl_clear(&fb);
#endif
}
static int InitGraphics(char *FRAMEBUFFER_DEV) {
#ifdef USE_FB
  if (debug) fprintf(stderr, "InitGraphics();\r\n");
  // Load PSF1 font
  font = fbgl_load_psf1_font("font-16.psf");
  if (!font) {
    fprintf(stderr, "Failed to load PSF1 font-16.psf\r\n");
    return 1;
  }

  if (fbgl_init(FRAMEBUFFER_DEV, &fb) == -1) {
    fprintf(stdout, "Error: could not open framebuffer device\r\n");
    return -1;
  }
  // Initialize keyboard
  if (fbgl_keyboard_init() != 0) {
    fprintf(stderr, "Failed to initialize keyboard\r\n");
    fbgl_destroy(&fb);
    return 1;
  }
  fbgl_set_fps(FPS);
#endif // USE_FB
  return 0;
}
static void set_scale(uint8_t scale) {
  vscale = scale;
}
static void Wait_Recal(void) {
  if (debug) fprintf(stdout, "Wait_Recal();\r\n");
  usleep(1000000/FPS);
  Clear();
}
static void Intensity_7F(void) {
  vbright = 0x7F;
}
static void Intensity_a(uint8_t i) {
  vbright = i;
}
static void Reset0Ref(void) {
  if (debug) fprintf(stdout, "Reset0Ref();\r\n");
  G_MoveAbs(vx = 0, vy = 0, vscale);
}
static void Moveto_d(int8_t y, int8_t x) {
  if (debug) fprintf(stdout, "Moveto_d(y=%d, x=%d);\r\n", y, x);
  G_MoveRel(vx = x, vy = y, vscale);
}
static void Draw_Line_d(int8_t y, int8_t x) {
  if (debug) fprintf(stdout, "Draw_Line_d(y=%d, x=%d);\r\n", y, x);
  G_LineRel(x, y, vbright, vscale);
}
