zoomedit: Added Pixmap to drawing; added "point in polygon" checker; rooms are now selectable

This commit is contained in:
neoraider 2007-06-25 16:55:01 +00:00
parent a686a31dae
commit b8549034be
12 changed files with 315 additions and 42 deletions

View file

@ -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@

View file

@ -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 \

143
draw.c
View file

@ -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);
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_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);
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;
}

7
draw.h
View file

@ -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_*/

22
edit.c Normal file
View file

@ -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;
}

15
edit.h Normal file
View file

@ -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_*/

View file

@ -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;

View file

@ -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);

11
level.c
View file

@ -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));

View file

@ -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);

View file

@ -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);

View file

@ -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();