diff --git a/ubb-la/gui.c b/ubb-la/gui.c new file mode 100644 index 0000000..c0482aa --- /dev/null +++ b/ubb-la/gui.c @@ -0,0 +1,179 @@ +/* + * gui.c - Graphical output for ubb-la + * + * Written 2013 by Werner Almesberger + * Copyright 2013 Werner Almesberger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include + +#include "SDL.h" +#include "SDL_gfxPrimitives.h" + +#include "gui.h" + + +#define XRES 320 /* canvas width */ +#define YRES 240 /* canvas height */ + +#define LEVEL_RGBA 0xffff00ff +#define BOUNCE_RGBA 0xff8080ff + +#define CH_XOFF 30 +#define CH_YOFF 30 +#define CH_SKIP 16 +#define CH_HEIGHT 8 + +#define MAX_ZOOM 8 + + +static SDL_Surface *surf; + + +void gui_init(void) +{ + if (SDL_Init(SDL_INIT_VIDEO) < 0) { + fprintf(stderr, "SDL_init: %s\n", SDL_GetError()); + exit(1); + } + atexit(SDL_Quit); + + surf = SDL_SetVideoMode(XRES, YRES, 0, SDL_SWSURFACE); + if (!surf) { + fprintf(stderr, "SDL_SetVideoMode: %s\n", SDL_GetError()); + exit(1); + } +} + + +static void clear(void) +{ + SDL_LockSurface(surf); + SDL_FillRect(surf, NULL, SDL_MapRGB(surf->format, 0, 0, 0)); +} + + +static inline int ch_y(int ch, int v) +{ + return CH_YOFF+CH_SKIP*ch+(v ? 0 : CH_HEIGHT); +} + + +static void bounce(int x, int ch) +{ + vlineColor(surf, x, ch_y(ch, 0), ch_y(ch, 1), BOUNCE_RGBA); +} + + +static void change(int x, int ch) +{ + vlineColor(surf, x, ch_y(ch, 0), ch_y(ch, 1), LEVEL_RGBA); +} + + +static void level(int x, int ch, int v) +{ + pixelColor(surf, x, ch_y(ch, v), LEVEL_RGBA); +} + + +static void show_buffer(const uint8_t *buf, int skip, int nibbles, + int x0, int x1) +{ + double f = (nibbles-skip)/(x1-x0+1.0); + int x; + int i = skip-1, n, j; + int changes[4], last[4] = { -1, -1, -1, -1}, next[4]; + uint8_t v, bit; + + for (x = x0; x != x1+1; x++) { + n = (x-x0)*f+skip; + if (i == n) { + for (j = 0; j != 4; j++) + level(x, j, last[j]); + continue; + } + for (j = 0; j != 4; j++) { + next[j] = last[j]; + changes[j] = 0; + } + while (i != n) { + i++; + v = (buf[i >> 1] >> 4*(~i & 1)) & 0xf; + for (j = 0; j != 4; j++) { + bit = (v >> j) & 1; + if (bit != next[j]) { + changes[j]++; + next[j] = bit; + } + } + } + for (j = 0; j != 4; j++) { + if (changes[j] > 1) + bounce(x, j); + else if (!changes[j] || last[j] == -1) + level(x, j, next[j]); + else + change(x, j); + last[j] = next[j]; + } + } +} + + +static void update(void) +{ + SDL_UnlockSurface(surf); + SDL_UpdateRect(surf, 0, 0, 0, 0); +} + + +void gui(const uint8_t *buf, int skip, int nibbles) +{ + SDL_Event event; + int zoom = 0; + int m, w; + + while (1) { + m = (nibbles-skip) >> 1; + w = (nibbles-skip) >> zoom; + clear(); + show_buffer(buf, m-(w >> 1), m+(w >> 1), CH_XOFF, XRES-1); + update(); + + do { + SDL_WaitEvent(&event); + switch (event.type) { + case SDL_KEYDOWN: + switch (event.key.keysym.sym) { + case SDLK_UP: + if (zoom < MAX_ZOOM) + zoom++; + break; + case SDLK_DOWN: + if (zoom) + zoom--; + break; + case SDLK_RETURN: + case SDLK_q: + return; + default: + printf("%x\n", event.key.keysym.sym); + continue; + } + break; + case SDL_QUIT: + return; + default: + continue; + } + } + while (0); + } +} diff --git a/ubb-la/gui.h b/ubb-la/gui.h new file mode 100644 index 0000000..f3b552a --- /dev/null +++ b/ubb-la/gui.h @@ -0,0 +1,23 @@ +/* + * gui.h - Graphical output for ubb-la + * + * Written 2013 by Werner Almesberger + * Copyright 2013 Werner Almesberger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + + +#ifndef GUI_H +#define GUI_H + +#include + + +void gui_init(void); +void gui(const uint8_t *buf, int skip, int nibbles); + +#endif /* !GUI_H */