Root/ubb-la/gui.c

Source at commit 159a128d2894792efa08f706c1e24173a283c6b8 created 6 years 10 months ago.
By Werner Almesberger, ubb-la.c/gui.c: show units in light blue to better separate them from numbers
1/*
2 * gui.c - Graphical output for ubb-la
3 *
4 * Written 2013 by Werner Almesberger
5 * Copyright 2013 Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <stdarg.h>
14#include <stdint.h>
15#include <stdlib.h>
16#include <alloca.h>
17
18#include "SDL.h"
19#include "SDL_gfxPrimitives.h"
20#include "SDL_gfxPrimitives_font.h"
21
22#include "gui.h"
23
24
25#if 0
26#define DEBUG(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__)
27#else
28#define DEBUG(fmt, ...)
29#endif
30
31
32#define XRES 320 /* canvas width */
33#define YRES 240 /* canvas height */
34
35#define TEXT_RGBA 0xffffffff /* general text */
36#define UNIT_RGBA 0xb0e0ffff /* units */
37#define MAP_BUF_RGBA 0x808080ff /* buffer in the map */
38#define MAP_VIEW_RGBA 0xffffffff /* current view in the map */
39#define LEVEL_RGBA 0xffff00ff /* constant level or single change */
40#define BOUNCE_RGBA 0xff8080ff /* bouncing signal */
41#define LABEL_RGBA 0xffffffff /* channel label */
42#define DIV_RGBA 0x808080ff /* divisions */
43
44#define XCENTER ((XRES+CH_XOFF)/2)
45#define XWIDTH (XRES-CH_XOFF)
46
47#define MAP_BUF_Y0 2
48#define MAP_BUF_Y1 8
49#define MAP_VIEW_Y0 0
50#define MAP_VIEW_Y1 10
51
52#define CH_XOFF 30
53#define CH_YOFF 30
54#define CH_SKIP 16
55#define CH_HEIGHT 8
56
57#define DIV_X 32
58#define DIV_Y 6
59
60#define MAX_ZOOM 3
61
62#define FREQ_X 0
63#define FREQ_Y 220
64#define INTERVAL_X 0
65#define INTERVAL_Y 230
66#define DIV_SAMP_X (80-8)
67#define DIV_SAMP_Y FREQ_Y
68#define DIV_INT_X 80
69#define DIV_INT_Y INTERVAL_Y
70
71#define REPEAT_DELAY_MS 300
72#define REPEAT_INTERVAL_MS 30
73
74static SDL_Surface *surf;
75
76
77/* ----- SDL initialization and screen-wide functions ---------------------- */
78
79
80void gui_init(void)
81{
82    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
83        fprintf(stderr, "SDL_init: %s\n", SDL_GetError());
84        exit(1);
85    }
86    atexit(SDL_Quit);
87
88    surf = SDL_SetVideoMode(XRES, YRES, 0, SDL_SWSURFACE);
89    if (!surf) {
90        fprintf(stderr, "SDL_SetVideoMode: %s\n", SDL_GetError());
91        exit(1);
92    }
93
94    SDL_EnableKeyRepeat(REPEAT_DELAY_MS, REPEAT_INTERVAL_MS);
95}
96
97
98static void clear(void)
99{
100    SDL_LockSurface(surf);
101    SDL_FillRect(surf, NULL, SDL_MapRGB(surf->format, 0, 0, 0));
102}
103
104
105static void update(void)
106{
107    SDL_UnlockSurface(surf);
108    SDL_UpdateRect(surf, 0, 0, 0, 0);
109}
110
111
112/* ----- Text output ------------------------------------------------------- */
113
114
115/*
116 * stringColor from SDL_gfx fails for some reason. SDL_ttf is just too much
117 * compatibility trouble. So we do our own.
118 */
119
120static void textf(int x, int y, uint32_t color, const char *fmt, ...)
121{
122    va_list ap;
123    char *tmp, *s;
124    uint8_t *p;
125    int n, ix, iy;
126
127    va_start(ap, fmt);
128    n = vsnprintf(NULL, 0, fmt, ap);
129    va_end(ap);
130    tmp = alloca(n+1);
131    va_start(ap, fmt);
132    vsnprintf(tmp, n+1, fmt, ap);
133    va_end(ap);
134
135    for (s = tmp; *s; s++) {
136        p = gfxPrimitivesFontdata+(*s << 3);
137        for (iy = 0; iy != 8; iy++) {
138            for (ix = 0; ix != 8; ix++)
139                if ((*p << ix) & 0x80)
140                    pixelColor(surf, x+ix, y+iy, color);
141            p++;
142        }
143        x += 8;
144    }
145}
146
147
148/* ----- Map of buffer and view -------------------------------------------- */
149
150
151static void show_map(int skip, int nibbles, int s0, int s1)
152{
153    int w = nibbles-skip;
154    int m = (nibbles+skip) >> 1;
155    int scale = 0;
156
157    while (w >= XWIDTH/2) {
158        w >>= 1;
159        scale++;
160    }
161    boxColor(surf, XCENTER-(w >> 1), MAP_BUF_Y0,
162        XCENTER+(w >> 1), MAP_BUF_Y1, MAP_BUF_RGBA);
163    rectangleColor(surf, (s0-m+(XCENTER << scale)) >> scale, MAP_VIEW_Y0,
164        (s1-m+(XCENTER << scale)) >> scale, MAP_VIEW_Y1, MAP_VIEW_RGBA);
165}
166
167
168/* ----- Waveform elements ------------------------------------------------- */
169
170
171static inline int ch_y(int ch, int v)
172{
173    return CH_YOFF+CH_SKIP*ch+(v ? 0 : CH_HEIGHT);
174}
175
176
177static void bounce(int x, int ch)
178{
179    vlineColor(surf, x, ch_y(ch, 0), ch_y(ch, 1), BOUNCE_RGBA);
180}
181
182
183static void change(int x, int ch)
184{
185    vlineColor(surf, x, ch_y(ch, 0), ch_y(ch, 1), LEVEL_RGBA);
186}
187
188
189static void level(int x0, int x1, int ch, int v)
190{
191    if (x0 == x1)
192        pixelColor(surf, x0, ch_y(ch, v), LEVEL_RGBA);
193    else
194        hlineColor(surf, x0, x1, ch_y(ch, v), LEVEL_RGBA);
195}
196
197
198/* ----- Show (part of) a buffer ------------------------------------------- */
199
200
201static void show_buffer_zoom_in(const uint8_t *buf, int skip, int nibbles,
202    int x0, int x1)
203{
204    int f = (x1-x0)/(nibbles-skip);
205    int x, i, j;
206    int last[4] = { -1, -1, -1, -1};
207    uint8_t v, bit;
208
209    DEBUG("in: %d-%d (%d) Sa %d-%d (%d) pix %d f (%d)\n",
210        skip, nibbles, nibbles-skip, x0, x1, x1-x0, f, f*(nibbles-skip));
211    x = x0;
212    for (i = skip; i != nibbles; i++) {
213        v = (buf[i >> 1] >> 4*(~i & 1)) & 0xf;
214        for (j = 0; j != 4; j++) {
215            bit = (v >> j) & 1;
216            if (bit == last[j] || last[j] == -1) {
217                level(x, x+f-1, j, bit);
218            } else {
219                change(x, j);
220                level(x+1, x+f-1, j, bit);
221            }
222            last[j] = bit;
223        }
224        x += f;
225    }
226}
227
228
229static void show_buffer_zoom_out(const uint8_t *buf, int skip, int nibbles,
230    int x0, int x1)
231{
232    int f = (nibbles-skip)/(x1-x0);
233    int x;
234    int i = skip, n, j;
235    int changes[4], last[4] = { -1, -1, -1, -1}, next[4];
236    uint8_t v, bit;
237
238    DEBUG("out: %d-%d (%d) Sa %d-%d (%d) pix %d f (%d)\n",
239        skip, nibbles, nibbles-skip, x0, x1, x1-x0, f, f*(x1-x0));
240    for (x = x0; x != x1; x++) {
241        n = i+f;
242        for (j = 0; j != 4; j++) {
243            next[j] = last[j];
244            changes[j] = 0;
245        }
246        while (i != n) {
247            v = (buf[i >> 1] >> 4*(~i & 1)) & 0xf;
248            for (j = 0; j != 4; j++) {
249                bit = (v >> j) & 1;
250                if (bit != next[j]) {
251                    changes[j]++;
252                    next[j] = bit;
253                }
254            }
255            i++;
256        }
257        for (j = 0; j != 4; j++) {
258            if (changes[j] > 1)
259                bounce(x, j);
260            else if (!changes[j] || last[j] == -1)
261                level(x, x, j, next[j]);
262            else
263                change(x, j);
264            last[j] = next[j];
265        }
266    }
267}
268
269
270static void show_buffer(const uint8_t *buf, int skip, int nibbles,
271    int x0, int x1, int zoom, int pos)
272{
273    int xm, w, s, p0, p1;
274    int d, dp;
275
276    xm = (x0+x1) >> 1;
277    dp = pos-((nibbles+skip) >> 1);
278    if (zoom < 0) {
279        s = (x1-x0) << -zoom;
280        show_map(skip, nibbles, pos-s/2, pos+s/2);
281        w = (nibbles-skip) >> -zoom;
282        p0 = xm-(w >> 1)-(dp >> -zoom);
283        p1 = xm+((w+1) >> 1)-(dp >> -zoom);
284        if (p0 < x0) {
285            skip += (x0-p0) << -zoom;
286            p0 = x0;
287        }
288        if (p1 > x1) {
289            nibbles -= (p1-x1) << -zoom;
290            p1 = x1;
291        }
292        show_buffer_zoom_out(buf, skip, nibbles, p0, p1);
293    } else {
294        s = (x1-x0) >> zoom;
295        show_map(skip, nibbles, pos-s/2, pos+s/2);
296        w = (nibbles-skip) << zoom;
297        p0 = xm-(w >> 1)-(dp << zoom);
298        p1 = xm+((w+1) >> 1)-(dp << zoom);
299        if (p0 < x0) {
300            d = ((x0-p0)+(1 << zoom)-1) >> zoom;
301            skip += d;
302            p0 += d << zoom;
303        }
304        if (p1 > x1) {
305            d = ((p1-x1)+(1 << zoom)-1) >> zoom;
306            nibbles -= d;
307            p1 -= d << zoom;
308        }
309        show_buffer_zoom_in(buf, skip, nibbles, p0, p1);
310    }
311}
312
313
314/* ----- Display the sample frequency -------------------------------------- */
315
316
317static void si_text(int x, int y, double v, const char *unit)
318{
319    const char *pfx;
320
321    if (v >= 1e6) {
322        v /= 1e6;
323        pfx = "M";
324    } else if (v >= 1e3) {
325        v /= 1e3;
326        pfx = "k";
327    } else if (v >= 1) {
328        pfx = " ";
329    } else if (v >= 1e-3) {
330        v *= 1e3;
331        pfx = "m";
332    } else if (v >= 1e-6) {
333        v *= 1e6;
334        pfx = "u";
335    } else {
336        v *= 1e9;
337        pfx = "n";
338    }
339    if (v >= 10)
340        textf(x, y, TEXT_RGBA, "%3d", (int) (v+0.5));
341    else
342        textf(x, y, TEXT_RGBA, "%3.1f", v);
343    textf(x+3*8, y, UNIT_RGBA, "%s%s", pfx, unit);
344}
345
346
347static void show_freq(double freq, int zoom)
348{
349    int div;
350
351    si_text(FREQ_X, FREQ_Y, freq, "Sa/s");
352    si_text(INTERVAL_X, INTERVAL_Y, 1/freq, "s/Sa");
353    div = (DIV_X >> MAX_ZOOM) << (MAX_ZOOM-zoom);
354    textf(DIV_SAMP_X, DIV_SAMP_Y, TEXT_RGBA, "%4d", div);
355    textf(DIV_SAMP_X+4*8, DIV_SAMP_Y, UNIT_RGBA, "Sa/div", div);
356    si_text(DIV_INT_X, DIV_INT_Y, div/freq, "s/div");
357}
358
359
360/* ----- Show a divisions -------------------------------------------------- */
361
362
363static void show_divisions(void)
364{
365    int n = XWIDTH/2/DIV_X;
366    int i;
367
368    for (i = -n; i <= n; i++)
369        vlineColor(surf, XCENTER+i*DIV_X,
370            ch_y(0, 1)-DIV_Y, ch_y(3, 0)+DIV_Y, DIV_RGBA);
371}
372
373
374/* ----- Main event loop --------------------------------------------------- */
375
376
377static int pos_step(int zoom)
378{
379    return 1 << (MAX_ZOOM-zoom+1);
380}
381
382
383void gui(const uint8_t *buf, int skip, int nibbles, double freq)
384{
385    SDL_Event event;
386    int pos = (skip+nibbles) >> 1;
387    int zoom; /* < 0: zoom out; 0: 1 pixel = 1 sample; > 1: zoom in */
388    int min_zoom = 0;
389    int i;
390
391    while (XWIDTH < (nibbles-skip) >> -min_zoom)
392        min_zoom--;
393    zoom = min_zoom;
394    while (1) {
395        clear();
396        for (i = 0; i != 4; i++)
397            textf(0, ch_y(i, 1), LABEL_RGBA, "CH%d", i);
398        show_divisions();
399        show_buffer(buf, skip, nibbles, CH_XOFF, XRES, zoom, pos);
400        show_freq(freq, zoom);
401        update();
402
403        while (1) {
404            SDL_WaitEvent(&event);
405            switch (event.type) {
406            case SDL_KEYDOWN:
407                switch (event.key.keysym.sym) {
408                case SDLK_UP:
409                    if (zoom < MAX_ZOOM)
410                        zoom++;
411                    break;
412                case SDLK_DOWN:
413                    if (zoom > min_zoom)
414                        zoom--;
415                    break;
416                case SDLK_LEFT:
417                    pos -= pos_step(zoom);
418                    if (pos < 0)
419                        pos = 0;
420                    break;
421                case SDLK_RIGHT:
422                    pos += pos_step(zoom);
423                    if (pos > nibbles-1)
424                        pos = nibbles-1;
425                    break;
426                case SDLK_RETURN:
427                case SDLK_q:
428                    return;
429                default:
430                    printf("%x\n", event.key.keysym.sym);
431                    continue;
432                }
433                break;
434            case SDL_QUIT:
435                return;
436            default:
437                continue;
438            }
439            break;
440        }
441    }
442}
443

Archive Download this file

Branches:
master



interactive