diff --git a/solidify/Makefile b/solidify/Makefile new file mode 100644 index 0000000..4e021b9 --- /dev/null +++ b/solidify/Makefile @@ -0,0 +1,13 @@ +CFLAGS=-Wall -g `pkg-config --cflags gtk+-2.0` +LDFLAGS=-lm `pkg-config --libs gtk+-2.0` + +OBJS=array.o face.o level.o solidify.o + +.PHONY: all clean + +all: solidify + +solidify: $(OBJS) + +clean: + rm -f $(OBJS) diff --git a/solidify/array.c b/solidify/array.c new file mode 100644 index 0000000..12e4242 --- /dev/null +++ b/solidify/array.c @@ -0,0 +1,72 @@ +#include + +#include "util.h" +#include "array.h" + + +static void resize(struct array *a, + int nx0, int nx1, int ny0, int ny1) +{ + int ox, oy, nx, ny; + int n, x, y; + int *tmp; + + ox = a->max_x-a->min_x; + oy = a->max_y-a->min_y; + nx = nx1-nx0; + ny = ny1-ny0; + if (ox == nx && oy == ny) + return; + n = (nx+1)*(ny+1); + tmp = alloc_size(n*sizeof(int)); + for (x = 0; x != n; x++) + tmp[x] = UNDEF; + for (x = a->min_x; x <= a->max_x; x++) + for (y = a->min_y; y <= a->max_y; y++) + tmp[x-nx0+(nx+1)*(y-ny0)] = + a->data[x-a->min_x+(ox+1)*(y-a->min_y)]; + free(a->data); + a->data = tmp; + a->min_x = nx0; + a->max_x = nx1; + a->min_y = ny0; + a->max_y = ny1; +} + + +struct array *new_array(void) +{ + struct array *a; + + a = alloc_type(struct array); + a->data = NULL; + return a; +} + + +void free_array(struct array *a) +{ + free(a->data); + free(a); +} + + +void set(struct array *a, int x, int y, int z) +{ + if (!a->data) { + a->min_x = a->max_x = x; + a->min_y = a->max_y = y; + a->min_z = a->max_z = z; + a->data = alloc_type(int); + *a->data = z; + } else { + resize(a, + x < a->min_x ? x : a->min_x, x > a->max_x ? x : a->max_x, + y < a->min_y ? y : a->min_y, y > a->max_y ? y : a->max_y); + if (z < a->min_z) + a->min_z = z; + if (z > a->max_z) + a->max_z = z; + a->data[x-a->min_x+(a->max_x-a->min_x+1)*(y-a->min_y)] = z; + } +} diff --git a/solidify/array.h b/solidify/array.h new file mode 100644 index 0000000..2687ada --- /dev/null +++ b/solidify/array.h @@ -0,0 +1,29 @@ +#ifndef ARRAY_H +#define ARRAY_H + +#include + + +#define UNDEF INT_MAX + + +struct array { + int min_x, max_x; + int min_y, max_y; + int min_z, max_z; + int *data; /* NULL if there are no points */ +}; + + +struct array *new_array(void); +void free_array(struct array *a); + +void set(struct array *a, int x, int y, int z); + + +static inline int get(const struct array *a, int x, int y) +{ + return a->data[(x)-a->min_x+(a->max_x-a->min_x+1)*((y)-a->min_y)]; +} + +#endif /* ARRAY_H */ diff --git a/solidify/face.c b/solidify/face.c new file mode 100644 index 0000000..2f52f89 --- /dev/null +++ b/solidify/face.c @@ -0,0 +1,45 @@ +#include +#include +#include +#include + +#include "util.h" +#include "array.h" +#include "face.h" + + +struct face *read_face(const char *name) +{ + FILE *file; + struct face *f; + float x, y, z; + int xi, yi, zi; + + file = strcmp(name, "-") ? fopen(name, "r") : stdin; + if (!file) { + perror(name); + exit(1); + } + f = alloc_type(struct face); + f->a = new_array(); + + while (fscanf(file, "%f,%f,%f\r\n", &x, &y, &z) == 3) { + /* @@@ hack - should auto-scale */ + xi = round(x*10.0); + yi = round(y*10.0); + zi = round(z*40.0); + set(f->a, xi, yi, zi); + } + (void) fclose(file); + + f->sx = f->a->max_x-f->a->min_x+1; + f->sy = f->a->max_y-f->a->min_y+1; + f->z_ref = (f->a->min_z+f->a->max_z)/2; + fprintf(stderr, "%d-%d / %d-%d / %d-%d\n", + f->a->min_x, f->a->max_x, f->a->min_y, f->a->max_y, + f->a->min_z, f->a->max_z); + + return f; +} + + diff --git a/solidify/face.h b/solidify/face.h new file mode 100644 index 0000000..1ed5273 --- /dev/null +++ b/solidify/face.h @@ -0,0 +1,16 @@ +#ifndef FACE_H +#define FACE_H + +#include "array.h" + + +struct face { + struct array *a; + int sx, sy; + int z_ref; +}; + + +struct face *read_face(const char *name); + +#endif /* FACE_H */ diff --git a/solidify/level.c b/solidify/level.c new file mode 100644 index 0000000..abfa40a --- /dev/null +++ b/solidify/level.c @@ -0,0 +1,139 @@ +#include +#include +#include + +#include "array.h" +#include "face.h" +#include "level.h" + + +static void draw_map(GtkWidget *widget, struct face *f) +{ + int x, y, z; + guchar *rgbbuf, *p; + + rgbbuf = p = calloc(f->sx*f->sy, 3); + if (!rgbbuf) { + perror("calloc"); + exit(1); + } + for (y = f->sy-1; y >= 0; y--) + for (x = 0; x != f->sx ; x++) { + z = get(f->a, x+f->a->min_x, y+f->a->min_y); + if (z == UNDEF) { + p += 3; + continue; + } + if (z == f->z_ref) { + *p++ = 0; + *p++ = 0; + *p++ = 255; + continue; + } + if (z < f->z_ref) { + z = 255.0*(z-f->z_ref)/(f->z_ref-f->a->min_z); + *p++ = 255; + *p++ = z; + *p++ = z; + } else { + z = 255.0*(f->z_ref-z)/(f->a->max_z-f->z_ref); + *p++ = z; + *p++ = 255; + *p++ = z; + } + } + gdk_draw_rgb_image(widget->window, + widget->style->fg_gc[GTK_STATE_NORMAL], + 0, 0, f->sx, f->sy, GDK_RGB_DITHER_MAX, rgbbuf, f->sx*3); + free(rgbbuf); +} + + +static void draw_image(GtkWidget *da, struct face *f) +{ + fprintf(stderr, "%d\n", f->z_ref); + draw_map(da, f); +} + + +static gboolean scroll_event(GtkWidget *widget, GdkEventScroll *event, + gpointer data) +{ + GtkWidget *da = gtk_bin_get_child(GTK_BIN(widget)); + struct face *f = data; + + switch (event->direction) { + case GDK_SCROLL_UP: + if (f->z_ref > f->a->min_z) { + f->z_ref--; + draw_image(da, f); + } + break; + case GDK_SCROLL_DOWN: + if (f->z_ref < f->a->max_z) { + f->z_ref++; + draw_image(da, f); + } + break; + default: + /* ignore */; + } + return TRUE; +} + + +static gboolean expose_event(GtkWidget *widget, GdkEventExpose *event, + gpointer user_data) +{ + draw_image(widget, user_data); + return TRUE; +} + + +static gboolean key_press_event(GtkWidget *widget, GdkEventKey *event, + gpointer data) +{ + if (event->keyval == 'q') + gtk_main_quit(); + return TRUE; +} + + +static void make_screen(GtkWidget *root, struct face *f) +{ + GtkWidget *evbox, *da; + + da = gtk_drawing_area_new(); + gtk_widget_set_size_request(da, f->sx, f->sy); + evbox = gtk_event_box_new(); + gtk_container_add(GTK_CONTAINER(evbox), da); + gtk_container_add(GTK_CONTAINER(root), evbox); + gtk_widget_show_all(root); + draw_map(da, f); + + g_signal_connect(G_OBJECT(evbox), "scroll-event", + G_CALLBACK(scroll_event), f); + g_signal_connect(G_OBJECT(da), "expose-event", + G_CALLBACK(expose_event), f); + g_signal_connect(G_OBJECT(root), "key-press-event", + G_CALLBACK(key_press_event), NULL); +} + + +void level(struct face *f) +{ + GtkWidget *root; + + root = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_position(GTK_WINDOW(root), GTK_WIN_POS_CENTER); + +#if 0 + /* get root->window */ + gtk_widget_show_all(root); +#endif + + g_signal_connect(G_OBJECT(root), "destroy", + G_CALLBACK(gtk_main_quit), NULL); + make_screen(root, f); + gtk_main(); +} diff --git a/solidify/level.h b/solidify/level.h new file mode 100644 index 0000000..9fbdcf4 --- /dev/null +++ b/solidify/level.h @@ -0,0 +1,9 @@ +#ifndef LEVEL_H +#define LEVEL_H + +#include "face.h" + + +void level(struct face *f); + +#endif /* LEVEL_H */ diff --git a/solidify/solidify.c b/solidify/solidify.c new file mode 100644 index 0000000..8725163 --- /dev/null +++ b/solidify/solidify.c @@ -0,0 +1,33 @@ +#include +#include +#include +#include + +#include "face.h" +#include "level.h" + + +static void usage(const char *name) +{ + fprintf(stderr, "usage: %s top XXXbottomXXX\n", name); + exit(1); +} + + +int main(int argc, char **argv) +{ + struct face *top; + + gtk_init(&argc, &argv); + switch (argc) { + case 2: + break; + default: + usage(*argv); + } + setlocale(LC_ALL, "C"); /* damage control */ + top = read_face(argv[1]); + level(top); + + return 0; +} diff --git a/solidify/util.h b/solidify/util.h new file mode 100644 index 0000000..a4859b1 --- /dev/null +++ b/solidify/util.h @@ -0,0 +1,15 @@ +#ifndef UTIL_H +#define UTIL_H + +#include + + +#define alloc_size(s) \ + ({ void *alloc_size_tmp = malloc(s); \ + if (!alloc_size_tmp) \ + abort(); \ + alloc_size_tmp; }) + +#define alloc_type(t) ((t *) alloc_size(sizeof(t))) + +#endif /* UTIL_H */