diff options
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | Makefile.in | 19 | ||||
-rw-r--r-- | draw.c | 143 | ||||
-rw-r--r-- | draw.h | 7 | ||||
-rw-r--r-- | edit.c | 22 | ||||
-rw-r--r-- | edit.h | 15 | ||||
-rw-r--r-- | geometry.c | 76 | ||||
-rw-r--r-- | geometry.h | 18 | ||||
-rw-r--r-- | level.c | 11 | ||||
-rw-r--r-- | level.h | 4 | ||||
-rw-r--r-- | window.c | 34 | ||||
-rw-r--r-- | zoomedit.c | 6 |
12 files changed, 315 insertions, 42 deletions
diff --git a/Makefile.am b/Makefile.am index cc6a9ee..06034df 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ bin_PROGRAMS = zoomedit -zoomedit_SOURCES = zoomedit.c window.c ui.c draw.c level.c geometry.c +zoomedit_SOURCES = zoomedit.c window.c ui.c draw.c level.c geometry.c edit.c zoomedit_CFLAGS = @GTK_CFLAGS@ zoomedit_LDADD = @GTK_LIBS@
\ No newline at end of file diff --git a/Makefile.in b/Makefile.in index b6777e9..166bcdf 100644 --- a/Makefile.in +++ b/Makefile.in @@ -51,7 +51,7 @@ PROGRAMS = $(bin_PROGRAMS) am_zoomedit_OBJECTS = zoomedit-zoomedit.$(OBJEXT) \ zoomedit-window.$(OBJEXT) zoomedit-ui.$(OBJEXT) \ zoomedit-draw.$(OBJEXT) zoomedit-level.$(OBJEXT) \ - zoomedit-geometry.$(OBJEXT) + zoomedit-geometry.$(OBJEXT) zoomedit-edit.$(OBJEXT) zoomedit_OBJECTS = $(am_zoomedit_OBJECTS) zoomedit_DEPENDENCIES = zoomedit_LINK = $(CCLD) $(zoomedit_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ @@ -166,7 +166,7 @@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -zoomedit_SOURCES = zoomedit.c window.c ui.c draw.c level.c geometry.c +zoomedit_SOURCES = zoomedit.c window.c ui.c draw.c level.c geometry.c edit.c zoomedit_CFLAGS = @GTK_CFLAGS@ zoomedit_LDADD = @GTK_LIBS@ all: config.h @@ -258,6 +258,7 @@ distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zoomedit-draw.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zoomedit-edit.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zoomedit-geometry.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zoomedit-level.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zoomedit-ui.Po@am__quote@ @@ -362,6 +363,20 @@ zoomedit-geometry.obj: geometry.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(zoomedit_CFLAGS) $(CFLAGS) -c -o zoomedit-geometry.obj `if test -f 'geometry.c'; then $(CYGPATH_W) 'geometry.c'; else $(CYGPATH_W) '$(srcdir)/geometry.c'; fi` +zoomedit-edit.o: edit.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(zoomedit_CFLAGS) $(CFLAGS) -MT zoomedit-edit.o -MD -MP -MF $(DEPDIR)/zoomedit-edit.Tpo -c -o zoomedit-edit.o `test -f 'edit.c' || echo '$(srcdir)/'`edit.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/zoomedit-edit.Tpo $(DEPDIR)/zoomedit-edit.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='edit.c' object='zoomedit-edit.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(zoomedit_CFLAGS) $(CFLAGS) -c -o zoomedit-edit.o `test -f 'edit.c' || echo '$(srcdir)/'`edit.c + +zoomedit-edit.obj: edit.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(zoomedit_CFLAGS) $(CFLAGS) -MT zoomedit-edit.obj -MD -MP -MF $(DEPDIR)/zoomedit-edit.Tpo -c -o zoomedit-edit.obj `if test -f 'edit.c'; then $(CYGPATH_W) 'edit.c'; else $(CYGPATH_W) '$(srcdir)/edit.c'; fi` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/zoomedit-edit.Tpo $(DEPDIR)/zoomedit-edit.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='edit.c' object='zoomedit-edit.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(zoomedit_CFLAGS) $(CFLAGS) -c -o zoomedit-edit.obj `if test -f 'edit.c'; then $(CYGPATH_W) 'edit.c'; else $(CYGPATH_W) '$(srcdir)/edit.c'; fi` + ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ @@ -1,4 +1,5 @@ #include "draw.h" +#include "edit.h" #include "level.h" #include "geometry.h" #include <math.h> @@ -9,6 +10,7 @@ static double scale = 100.0; static double xTranslate = 0.0, yTranslate = 0.0; +static gboolean repaint = FALSE; static void drawGrid(cairo_t *cr, const RECTANGLE *rect) { @@ -17,13 +19,13 @@ static void drawGrid(cairo_t *cr, const RECTANGLE *rect) { double step = pow(0.1, depth2); double d; int i; - gchar buffer[10]; + gchar buffer[20]; cairo_set_font_size(cr, 10.0/scale); - for(i = 0; 0.2*(depth-depth2+i-1) < 0.3; i++) { - d = MIN(0.2*(depth-depth2+i), 0.3); + for(i = 0; 0.4*(depth-depth2+i-1) < 0.5; i++) { + d = MIN(0.4*(depth-depth2+i), 0.5); cairo_set_source_rgb(cr, d, d, d); for(d = rect->x - fmod(rect->x, step) - step; d <= rect->x+rect->width; d+=step) { @@ -87,58 +89,129 @@ static void room2path(cairo_t *cr, const ROOM *room, const RECTANGLE *rect) { } gboolean drawTopView(GtkWidget *widget, GdkEventExpose *event, gpointer data) { - VERTEX vertices[4] = {{-1,-1}, {-1,1}, {1,1}, {1,-1}}; - ROOM room = {sizeof(vertices)/sizeof(vertices[0]), vertices}; - LEVEL lvl = {1, &room}; cairo_t *cr; RECTANGLE rect = {-1, -1, widget->allocation.width+2, widget->allocation.height+2}; + static GdkPixmap *pixmap = NULL; + static double lastImageWidth = 0.0, lastImageHeight = 0.0; + static gint lastWidth = 0.0, lastHeight = 0.0; int i; - cr = gdk_cairo_create(widget->window); + if(getLevel() == NULL) return; - gdk_cairo_region(cr, event->region); - cairo_clip(cr); - - cairo_translate(cr, getImageWidth()/2-xTranslate, getImageHeight()/2-yTranslate); - cairo_scale(cr, scale, scale); - - cairo_device_to_user(cr, &rect.x, &rect.y); - cairo_device_to_user_distance(cr, &rect.width, &rect.height); - - cairo_set_line_width(cr, 1.0/scale); - cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER); - - drawGrid(cr, &rect); - - for(i = 0; i < lvl.nRooms; i++) - room2path(cr, &lvl.rooms[i], &rect); - - cairo_set_source_rgba(cr, 0.0, 0.7, 1.0, 0.3); - cairo_fill_preserve(cr); - - cairo_set_source_rgba(cr, 0.0, 0.7, 1.0, 0.7); - cairo_stroke(cr); + if(pixmap == NULL || lastImageWidth != getImageWidth() || lastImageHeight != getImageHeight() || + lastWidth != widget->allocation.width || lastHeight != widget->allocation.height || repaint) + { + if(pixmap != NULL) + g_object_unref(G_OBJECT(pixmap)); + + pixmap = gdk_pixmap_new(widget->window, widget->allocation.width, widget->allocation.height, -1); + + lastImageWidth = getImageWidth(); + lastImageHeight = getImageHeight(); + lastWidth = widget->allocation.width; + lastHeight = widget->allocation.height; + repaint = FALSE; + + cr = gdk_cairo_create(GDK_DRAWABLE(pixmap)); + + cairo_set_source_rgb(cr, 0, 0, 0); + cairo_rectangle(cr, 0, 0, widget->allocation.width, widget->allocation.height); + cairo_fill(cr); + + cairo_translate(cr, getImageWidth()/2-xTranslate, getImageHeight()/2-yTranslate); + cairo_scale(cr, scale, scale); + + cairo_device_to_user(cr, &rect.x, &rect.y); + cairo_device_to_user_distance(cr, &rect.width, &rect.height); + + cairo_set_line_width(cr, 1.0/scale); + cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER); + + drawGrid(cr, &rect); + + for(i = 0; i < getLevel()->nRooms; i++) { + if(&getLevel()->rooms[i] != getActiveRoom()) + room2path(cr, &getLevel()->rooms[i], &rect); + } + + cairo_set_source_rgba(cr, 0.0, 0.7, 1.0, 0.3); + cairo_fill_preserve(cr); + + cairo_set_source_rgba(cr, 0.0, 0.7, 1.0, 0.7); + cairo_stroke(cr); + + if(getEditMode() == EDIT_MODE_SELECTED) { + room2path(cr, getActiveRoom(), &rect); + + cairo_set_source_rgba(cr, 0.0, 0.7, 1.0, 0.2); + cairo_fill_preserve(cr); + + cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.9); + cairo_set_line_width(cr, 1.5/scale); + cairo_stroke(cr); + } + + cairo_destroy (cr); + } - cairo_destroy (cr); + gdk_draw_drawable(GDK_DRAWABLE(widget->window), widget->style->fg_gc[GTK_WIDGET_STATE(widget)], GDK_DRAWABLE(pixmap), 0, 0, 0, 0, -1, -1); return FALSE; } + double getScale() { return scale; } void setScale(double s) { scale = s; + repaint = TRUE; +} + +void imageToView(VERTEX *v) { + v->x = v->x*scale+getImageWidth()/2-xTranslate; + v->y = v->y*scale+getImageHeight()/2-yTranslate; +} + +void viewToImage(VERTEX *v) { + v->x = (v->x-getImageWidth()/2+xTranslate)/scale; + v->y = (v->y-getImageHeight()/2+yTranslate)/scale; } double getImageWidth() { - return 5*scale; + const LEVEL *level = getLevel(); + double min = 0.0, max = 0.0; + int i, j; + + if(level) { + for(i = 0; i < level->nRooms; i++) { + for(j = 0; j < level->rooms[i].nVertices; j++) { + min = MIN(min, level->rooms[i].vertices[j].x); + max = MAX(max, level->rooms[i].vertices[j].x); + } + } + } + + return (max-min+10)*scale; } double getImageHeight() { - return 5*scale; + const LEVEL *level = getLevel(); + double min = 0.0, max = 0.0; + int i, j; + + if(level) { + for(i = 0; i < level->nRooms; i++) { + for(j = 0; j < level->rooms[i].nVertices; j++) { + min = MIN(min, level->rooms[i].vertices[j].y); + max = MAX(max, level->rooms[i].vertices[j].y); + } + } + } + + return (max-min+10)*scale; } double getXTranslate() { @@ -147,6 +220,7 @@ double getXTranslate() { void setXTranslate(double x) { xTranslate = x; + repaint = TRUE; } double getYTranslate() { @@ -155,4 +229,9 @@ double getYTranslate() { void setYTranslate(double y) { yTranslate = y; + repaint = TRUE; +} + +void redraw() { + repaint = TRUE; } @@ -2,12 +2,17 @@ #define DRAW_H_ #include <gtk/gtk.h> +#include "geometry.h" + gboolean drawTopView(GtkWidget *widget, GdkEventExpose *event, gpointer data); double getScale(); void setScale(double s); +void imageToView(VERTEX *v); +void viewToImage(VERTEX *v); + double getImageWidth(); double getImageHeight(); @@ -16,4 +21,6 @@ void setXTranslate(double x); double getYTranslate(); void setYTranslate(double y); +void redraw(); + #endif /*DRAW_H_*/ @@ -0,0 +1,22 @@ +#include "edit.h" + + +static int editMode = EDIT_MODE_VIEW; + +static ROOM *activeRoom = NULL; + +int getEditMode() { + return editMode; +} + + +ROOM *getActiveRoom() { + return activeRoom; +} + +void setActiveRoom(ROOM *room) { + activeRoom = room; + + if(editMode == EDIT_MODE_VIEW || editMode == EDIT_MODE_SELECTED) + editMode = (room == NULL) ? EDIT_MODE_VIEW : EDIT_MODE_SELECTED; +} @@ -0,0 +1,15 @@ +#ifndef EDIT_H_ +#define EDIT_H_ + +#include "level.h" + +#define EDIT_MODE_VIEW 0 +#define EDIT_MODE_SELECTED 1 +#define EDIT_MODE_ADD 2 + +int getEditMode(); + +ROOM *getActiveRoom(); +void setActiveRoom(ROOM *room); + +#endif /*EDIT_H_*/ @@ -57,6 +57,82 @@ int vertexInRect(const VERTEX *v, const RECTANGLE *rect) { return ret; } +static int quadrant(VERTEX *v) { + if(v->x > 0 && v->y >= 0) return 1; + if(v->x >= 0 && v->y < 0) return 2; + if(v->x < 0 && v->y <= 0) return 3; + if(v->x <= 0 && v->y > 0) return 4; + + return 0; +} + +gboolean vertexInPolygon(const VERTEX *v, const POLYGON *p) { + int d = 0, i, li; + int q, ql, q2; + LINE d1 = {{-1, -1}, {1, 1}}; + LINE d2 = {{-1, 1}, {1, -1}}; + LINE l; + VERTEX v2; + + + if(p->nVertices == 0) return FALSE; + + v2.x = p->vertices[p->nVertices-1].x - v->x; + v2.y = p->vertices[p->nVertices-1].y - v->y; + q = quadrant(&v2); + + if(q == 0) return TRUE; + + for(i = 0; i < p->nVertices; i++) { + ql = q; + + v2.x = p->vertices[i].x - v->x; + v2.y = p->vertices[i].y - v->y; + q = quadrant(&v2); + + if(q == 0) return TRUE; + + switch(q-ql) { + case 0: + break; + case 1: + case -3: + d++; + break; + case 3: + case -1: + d--; + break; + default: + l.v1.x = p->vertices[(i>0)?i-1:p->nVertices-1].x - v->x; + l.v1.y = p->vertices[(i>0)?i-1:p->nVertices-1].y - v->y; + + l.v2 = v2; + + if(q == 1 || q == 3) { + if(!(lineIntersection(&l, &d2, &v2) & INTERSECTION_LINE)) return FALSE; + + q2 = quadrant(&v2); + if(q2 == 0) return TRUE; + + if((q == 1 && q2 == 2) || (q == 3 && q2 == 4)) d -= 2; + else d += 2; + } + else { + if(!(lineIntersection(&l, &d1, &v2) & INTERSECTION_LINE)) return FALSE; + + q2 = quadrant(&v2); + if(q2 == 0) return TRUE; + + if((q == 2 && q2 == 3) || (q == 4 && q2 == 1)) d -= 2; + else d += 2; + } + } + } + + return (d == 0) ? FALSE : TRUE; +} + int lineIntersection(const LINE *la, const LINE *lb, VERTEX *v) { double xa1 = la->v1.x, ya1 = la->v1.y; double xa2 = la->v2.x, ya2 = la->v2.y; @@ -2,6 +2,8 @@ #define GEOMETRY_H_ +#include <glib.h> + #define EDGE_NONE 0 #define EDGE_LEFT (1<<0) #define EDGE_RIGHT (1<<1) @@ -9,13 +11,14 @@ #define EDGE_BOTTOM (1<<3) #define EDGE_ALL (EDGE_LEFT|EDGE_RIGHT|EDGE_TOP|EDGE_BOTTOM) -#define INTERSECTION_ERROR -1 -#define INTERSECTION_NONE 0 -#define INTERSECTION_IDENTICAL 1 -#define INTERSECTION_LINE_LINE 2 -#define INTERSECTION_LINE_SEGMENT 3 -#define INTERSECTION_SEGMENT_LINE 4 -#define INTERSECTION_SEGMENT_SEGMENT 5 +#define INTERSECTION_ERROR -1 +#define INTERSECTION_NONE 0 +#define INTERSECTION_IDENTICAL 1 +#define INTERSECTION_LINE 2 +#define INTERSECTION_LINE_LINE 2 +#define INTERSECTION_LINE_SEGMENT 3 +#define INTERSECTION_SEGMENT_LINE 6 +#define INTERSECTION_SEGMENT_SEGMENT 7 typedef struct _VERTEX { @@ -42,6 +45,7 @@ void deleteVertex(VERTEX_LIST *list, unsigned int n); int vertexInRect(const VERTEX *v, const RECTANGLE *rect); +gboolean vertexInPolygon(const VERTEX *v, const POLYGON *p); int lineIntersection(const LINE *la, const LINE *lb, VERTEX *v); int lineRectIntersection(const LINE *l, const RECTANGLE *rect, int edge, VERTEX *v); int lineRectIntersections(const LINE *line, const RECTANGLE *rect, int edge, VERTEX *v1, VERTEX *v2); @@ -2,6 +2,17 @@ #include <stdlib.h> +static LEVEL *level = NULL; + + +LEVEL *getLevel() { + return level; +} + +void setLevel(LEVEL *l) { + level = l; +} + void addRoom(LEVEL *lvl, ROOM *room) { lvl->nRooms++; lvl->rooms = realloc(lvl->rooms, lvl->nRooms*sizeof(ROOM)); @@ -10,6 +10,10 @@ typedef struct _LEVEL { ROOM *rooms; } LEVEL; + +LEVEL *getLevel(); +void setLevel(LEVEL *l); + void addRoom(LEVEL *lvl, ROOM *room); void deleteRoom(LEVEL *lvl, unsigned int n); @@ -1,6 +1,9 @@ #include "window.h" #include "ui.h" +#include "edit.h" #include "draw.h" +#include "geometry.h" +#include "level.h" #include <gtk/gtk.h> @@ -24,6 +27,34 @@ static gboolean scrollEvent(GtkWidget *widget, GdkEventScroll *event, gpointer u } } +static gboolean buttonEvent(GtkWidget *widget, GdkEventButton *event, gpointer user_data) { + VERTEX v = {event->x, event->y}; + int i; + + switch(event->type) { + case GDK_BUTTON_PRESS: + switch(event->button) { + case 1: + viewToImage(&v); + + setActiveRoom(NULL); + + for(i = 0; i < getLevel()->nRooms; i++) { + if(vertexInPolygon(&v, &getLevel()->rooms[i])) { + setActiveRoom(&getLevel()->rooms[i]); + + break; + } + } + + redraw(); + gtk_widget_queue_draw(drawingArea); + } + } + + return FALSE; +} + static void destroy(GtkWidget *widget, gpointer data) { gtk_main_quit(); } @@ -61,6 +92,7 @@ static void updateScrollbars(double x, double y) { g_object_get(G_OBJECT(vAdjustment), "upper", &upper, "page_size", &pageSize, NULL); g_object_set(G_OBJECT(vAdjustment), "upper", imageHeight, "page_size", height, NULL); + gtk_adjustment_changed(vAdjustment); if((pageSize > upper && height < imageHeight) || upper == 0) value = (imageHeight-height)/2; @@ -105,6 +137,8 @@ GtkWidget* createMainWindow() { gtk_widget_modify_bg(drawingArea, GTK_WIDGET_STATE(drawingArea), &color); g_signal_connect(G_OBJECT(drawingArea), "configure-event", G_CALLBACK(updateScrollbarsCentered), NULL); g_signal_connect(G_OBJECT(drawingArea), "expose-event", G_CALLBACK(drawTopView), NULL); + g_signal_connect(G_OBJECT(drawingArea), "button-press-event", G_CALLBACK(buttonEvent), NULL); + g_signal_connect(G_OBJECT(drawingArea), "button-release-event", G_CALLBACK(buttonEvent), NULL); g_signal_connect(G_OBJECT(drawingArea), "scroll-event", G_CALLBACK(scrollEvent), NULL); gtk_widget_add_events(drawingArea, GDK_SCROLL_MASK); gtk_table_attach(GTK_TABLE(table), drawingArea, 0, 1, 0, 1, GTK_FILL|GTK_EXPAND|GTK_SHRINK, GTK_FILL|GTK_EXPAND|GTK_SHRINK, 0, 0); @@ -1,14 +1,20 @@ #include <gtk/gtk.h> +#include "level.h" #include "window.h" int main(int argc, char *argv[]) { + VERTEX vertices[4] = {{-1.1,-1}, {-1,-1.1}, {1.1,1}, {1,1.1}}; + ROOM room = {sizeof(vertices)/sizeof(vertices[0]), vertices}; + LEVEL lvl = {1, &room}; GtkWidget *window; gtk_init(&argc, &argv); window = createMainWindow(); + setLevel(&lvl); + gtk_widget_show(window); gtk_main(); |