Root/ubb-la/gui.c

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

Archive Download this file

Branches:
master



interactive