summaryrefslogtreecommitdiff
path: root/meme
diff options
context:
space:
mode:
authorWerner Almesberger <werner@almesberger.net>2014-09-12 02:55:24 -0300
committerWerner Almesberger <werner@almesberger.net>2014-09-12 02:55:24 -0300
commit173e5325d1968ff88a0788c8d1248841dd381f15 (patch)
tree7e10579891a6291637dac3680d7fcb5563c62486 /meme
parente067eb87674ba8a3cc6cea7127bb6094eee6ba93 (diff)
downloadmisc-173e5325d1968ff88a0788c8d1248841dd381f15.tar.gz
misc-173e5325d1968ff88a0788c8d1248841dd381f15.tar.bz2
misc-173e5325d1968ff88a0788c8d1248841dd381f15.zip
meme/gui.c: add cursor (and nearest vertex lookup, SDL backing store)
Diffstat (limited to 'meme')
-rw-r--r--meme/gui.c188
1 files changed, 186 insertions, 2 deletions
diff --git a/meme/gui.c b/meme/gui.c
index d648dfa..2dd247b 100644
--- a/meme/gui.c
+++ b/meme/gui.c
@@ -18,16 +18,22 @@
#include "SDL.h"
#include "SDL_gfxPrimitives.h"
+#include "util.h"
#include "mesh.h"
-#define XRES 1280
-#define YRES 1024
+#define XRES 1280
+#define YRES 1024
+
+#define CURSOR_R 5
+#define CURSOR_RGBA 0xff202080
+
static int x_orig, y_orig;
static int x_min, x_max, y_min, y_max, z_min, z_max;
static int zoom;
static bool show_grid = 1;
+static const struct vertex *cursor;
/* ----- Coordinate transform ---------------------------------------------- */
@@ -135,9 +141,178 @@ static void draw(SDL_Surface *s)
}
+/* ----- Backing store ----------------------------------------------------- */
+
+
+static struct change {
+ SDL_Surface *s;
+ SDL_Rect r;
+ struct change *next;
+} *changes;
+
+
+static void change(SDL_Surface *s, int x, int y, int w, int h)
+{
+ struct change *c;
+ SDL_Surface *tmp;
+
+ if (x < 0) {
+ w += x;
+ x = 0;
+ }
+ if (y < 0) {
+ h += y;
+ y = 0;
+ }
+ if (x+w >= XRES)
+ w = XRES-x-1;
+ if (y+h >= XRES)
+ h = XRES-y-1;
+
+ /*
+ * @@@ this seems weird. do we really have no direct way to create
+ * a surface that's compatible with the display ?
+ */
+ c = alloc_type(struct change);
+ tmp = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 0, 0, 0, 0, 0);
+ if (!tmp) {
+ fprintf(stderr, "SDL_CreateRGBSurface failed\n");
+ exit(1);
+ }
+ c->s = SDL_DisplayFormat(tmp);
+ if (!c->s) {
+ fprintf(stderr, "SDL_DisplayFormat failed\n");
+ exit(1);
+ }
+ SDL_FreeSurface(tmp);
+
+ c->r.x = x;
+ c->r.y = y;
+ c->r.w = w;
+ c->r.h = h;
+ if (SDL_BlitSurface(s, &c->r, c->s, NULL)) {
+ fprintf(stderr, "SDL_BlitSurface failed\n");
+ exit(1);
+ }
+ c->next = changes;
+ changes = c;
+}
+
+
+static void apply_changes(SDL_Surface *s)
+{
+ const struct change *c;
+
+ for (c = changes; c; c = c->next)
+ SDL_UpdateRect(s, c->r.x, c->r.y, c->r.w, c->r.h);
+}
+
+
+static void rollback_changes(SDL_Surface *s)
+{
+ struct change *next;
+
+ while (changes) {
+ next = changes->next;
+ if (SDL_BlitSurface(changes->s, NULL, s, &changes->r)) {
+ fprintf(stderr, "SDL_BlitSurface failed\n");
+ exit(1);
+ }
+ SDL_FreeSurface(changes->s);
+ SDL_UpdateRect(s,
+ changes->r.x, changes->r.y, changes->r.w, changes->r.h);
+ free(changes);
+ changes = next;
+ }
+}
+
+
+static void discard_changes(void)
+{
+ struct change *next;
+
+ while (changes) {
+ next = changes->next;
+ SDL_FreeSurface(changes->s);
+ free(changes);
+ changes = next;
+ }
+}
+
+
+/* ----- Cursor handling --------------------------------------------------- */
+
+
+static void hide_cursor(SDL_Surface *s)
+{
+ rollback_changes(s);
+}
+
+
+static void show_cursor(SDL_Surface *s, const struct vertex *v)
+{
+ int x = x_model2screen(v->x);
+ int y = y_model2screen(v->y);
+
+ change(s, x-CURSOR_R, y-CURSOR_R, 2*CURSOR_R+1, 2*CURSOR_R+1);
+ SDL_LockSurface(s);
+ filledCircleColor(s, x, y, CURSOR_R, CURSOR_RGBA);
+ SDL_UnlockSurface(s);
+}
+
+
+/* ----- Find nearest vertex ----------------------------------------------- */
+
+
+struct proximity {
+ int x, y;
+ const struct vertex *best;
+ double best_d;
+};
+
+
+static bool proximity_fn(const struct vertex *v, void *user)
+{
+ struct proximity *p = user;
+ double d = hypot(v->x - p->x, v->y - p->y);
+
+ if (!p->best || d < p->best_d) {
+ p->best_d = d;
+ p->best = v;
+ }
+ return 0;
+}
+
+
+static const struct vertex *find_nearest(int x, int y)
+{
+ struct proximity p = {
+ .x = x,
+ .y = y,
+ .best = NULL,
+ };
+
+ vertex_foreach_const(proximity_fn, &p);
+ return p.best;
+}
+
+
/* ----- Event handling ---------------------------------------------------- */
+static void motion_event(SDL_Surface *s, SDL_MouseMotionEvent *motion)
+{
+ int x = x_screen2model(motion->x);
+ int y = y_screen2model(motion->y);
+
+ if (cursor)
+ hide_cursor(s);
+ cursor = find_nearest(x, y);
+ show_cursor(s, cursor);
+ apply_changes(s);
+}
+
+
static void button_event(SDL_MouseButtonEvent *button)
{
int x = x_screen2model(button->x);
@@ -228,14 +403,23 @@ void gui(void)
while (1) {
bool redraw;
+ discard_changes();
SDL_LockSurface(surf);
draw(surf);
SDL_UnlockSurface(surf);
SDL_UpdateRect(surf, 0, 0, 0, 0);
+ if (cursor) {
+ show_cursor(surf, cursor);
+ apply_changes(surf);
+ }
+
redraw = 0;
while (SDL_WaitEvent(&event) && !redraw) {
switch (event.type) {
+ case SDL_MOUSEMOTION:
+ motion_event(surf, &event.motion);
+ break;
case SDL_MOUSEBUTTONDOWN:
button_event(&event.button);
redraw = 1;