2007-06-21 19:52:03 +00:00
|
|
|
#include "draw.h"
|
2007-06-25 16:55:01 +00:00
|
|
|
#include "edit.h"
|
2007-06-21 19:52:03 +00:00
|
|
|
#include "level.h"
|
2007-06-23 19:00:05 +00:00
|
|
|
#include "geometry.h"
|
2007-06-24 00:35:04 +00:00
|
|
|
#include <math.h>
|
2007-06-21 19:52:03 +00:00
|
|
|
#include <gtk/gtk.h>
|
|
|
|
#include <cairo/cairo.h>
|
2007-09-16 12:52:01 +00:00
|
|
|
#include <stdlib.h>
|
2007-06-21 19:52:03 +00:00
|
|
|
|
|
|
|
|
|
|
|
static double scale = 100.0;
|
|
|
|
static double xTranslate = 0.0, yTranslate = 0.0;
|
2007-06-25 16:55:01 +00:00
|
|
|
static gboolean repaint = FALSE;
|
2007-06-21 19:52:03 +00:00
|
|
|
|
2007-06-23 19:00:05 +00:00
|
|
|
|
2007-06-24 00:35:04 +00:00
|
|
|
static void drawGrid(cairo_t *cr, const RECTANGLE *rect) {
|
|
|
|
double depth = log10(scale)-0.75;
|
|
|
|
double depth2 = floor(depth);
|
|
|
|
double step = pow(0.1, depth2);
|
2007-06-24 17:33:00 +00:00
|
|
|
double d;
|
2007-06-24 00:35:04 +00:00
|
|
|
int i;
|
2007-08-29 19:54:05 +00:00
|
|
|
gchar *string;
|
2007-06-24 00:35:04 +00:00
|
|
|
|
|
|
|
|
2007-06-24 17:33:00 +00:00
|
|
|
cairo_set_font_size(cr, 10.0/scale);
|
|
|
|
|
2007-06-25 16:55:01 +00:00
|
|
|
for(i = 0; 0.4*(depth-depth2+i-1) < 0.5; i++) {
|
|
|
|
d = MIN(0.4*(depth-depth2+i), 0.5);
|
2007-06-24 17:33:00 +00:00
|
|
|
cairo_set_source_rgb(cr, d, d, d);
|
|
|
|
|
|
|
|
for(d = rect->x - fmod(rect->x, step) - step; d <= rect->x+rect->width; d+=step) {
|
|
|
|
cairo_move_to(cr, d, rect->y);
|
|
|
|
cairo_line_to(cr, d, rect->y+rect->height);
|
2007-06-24 00:35:04 +00:00
|
|
|
|
2007-09-15 17:54:02 +00:00
|
|
|
if(step > 0.005) {
|
|
|
|
if(step > 0.5)
|
2007-09-15 21:22:05 +00:00
|
|
|
string = g_strdup_printf("%i", (int)rint(d));
|
2007-09-15 17:54:02 +00:00
|
|
|
else
|
|
|
|
string = g_strdup_printf("%.*f", -(int)floor(log10(step*1.1)), d+step/10);
|
|
|
|
|
|
|
|
cairo_move_to(cr, d+1/scale, rect->y+11/scale);
|
|
|
|
cairo_show_text(cr, string);
|
|
|
|
|
|
|
|
g_free(string);
|
|
|
|
}
|
2007-06-24 00:35:04 +00:00
|
|
|
}
|
|
|
|
|
2007-06-24 17:33:00 +00:00
|
|
|
for(d = rect->y - fmod(rect->y, step) - step; d <= rect->y+rect->height; d+=step) {
|
|
|
|
cairo_move_to(cr, rect->x, d);
|
|
|
|
cairo_line_to(cr, rect->x+rect->width, d);
|
2007-06-24 00:35:04 +00:00
|
|
|
|
2007-09-15 17:54:02 +00:00
|
|
|
if(step > 0.005) {
|
|
|
|
if(step > 0.5)
|
2007-09-15 21:22:05 +00:00
|
|
|
string = g_strdup_printf("%i", (int)rint(d));
|
2007-09-15 17:54:02 +00:00
|
|
|
else
|
|
|
|
string = g_strdup_printf("%.*f", -(int)floor(log10(step*1.1)), d+step/10);
|
|
|
|
|
|
|
|
cairo_move_to(cr, rect->x+3/scale, d+11/scale);
|
|
|
|
cairo_show_text(cr, string);
|
|
|
|
|
|
|
|
g_free(string);
|
|
|
|
}
|
2007-06-24 00:35:04 +00:00
|
|
|
}
|
|
|
|
|
2007-06-26 21:20:01 +00:00
|
|
|
cairo_stroke(cr);
|
|
|
|
|
2007-06-24 00:35:04 +00:00
|
|
|
step *= 10;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-09-16 19:06:02 +00:00
|
|
|
static void polygon2path(cairo_t *cr, const Polygon *polygon, const RECTANGLE *rect, gboolean close) {
|
|
|
|
Polygon polygon2;
|
2007-06-21 19:52:03 +00:00
|
|
|
|
2007-06-23 19:00:05 +00:00
|
|
|
// no vertices
|
2007-09-16 19:06:02 +00:00
|
|
|
if(polygon->empty()) return;
|
2007-06-21 19:52:03 +00:00
|
|
|
|
2007-06-23 19:00:05 +00:00
|
|
|
if(rect)
|
2007-08-29 19:54:05 +00:00
|
|
|
simplifyPolygon(polygon, rect, &polygon2);
|
2007-06-23 19:00:05 +00:00
|
|
|
else
|
2007-08-29 19:54:05 +00:00
|
|
|
polygon2 = *polygon;
|
2007-06-23 19:00:05 +00:00
|
|
|
|
2007-09-16 19:06:02 +00:00
|
|
|
if(polygon2.empty()) return;
|
2007-06-21 19:52:03 +00:00
|
|
|
|
2007-06-23 19:00:05 +00:00
|
|
|
cairo_new_sub_path(cr);
|
|
|
|
|
2007-09-16 19:06:02 +00:00
|
|
|
for(Polygon::iterator it = polygon2.begin(); it != polygon2.end(); it++) {
|
|
|
|
cairo_line_to(cr, it->getX(), it->getY());
|
2007-06-23 19:00:05 +00:00
|
|
|
}
|
2007-06-21 19:52:03 +00:00
|
|
|
|
2007-09-15 17:54:02 +00:00
|
|
|
if(close)
|
|
|
|
cairo_close_path(cr);
|
2007-06-21 19:52:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
gboolean drawTopView(GtkWidget *widget, GdkEventExpose *event, gpointer data) {
|
|
|
|
cairo_t *cr;
|
2007-09-16 14:07:03 +00:00
|
|
|
Vertex v1(-1, -1), v2(widget->allocation.width+1, widget->allocation.height+1);
|
2007-06-26 21:20:01 +00:00
|
|
|
RECTANGLE rect;
|
2007-09-15 17:54:02 +00:00
|
|
|
gboolean vertexOk;
|
2007-06-25 16:55:01 +00:00
|
|
|
static GdkPixmap *pixmap = NULL;
|
|
|
|
static double lastImageWidth = 0.0, lastImageHeight = 0.0;
|
|
|
|
static gint lastWidth = 0.0, lastHeight = 0.0;
|
2007-09-15 17:54:02 +00:00
|
|
|
static int lastEditMode = 0;
|
2007-06-21 19:52:03 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
|
2007-06-26 19:30:01 +00:00
|
|
|
if(getLevel() == NULL) return FALSE;
|
2007-06-21 19:52:03 +00:00
|
|
|
|
2007-06-26 21:20:01 +00:00
|
|
|
viewToImage(&v1);
|
|
|
|
viewToImage(&v2);
|
|
|
|
|
2007-09-16 14:07:03 +00:00
|
|
|
rect.x = v1.getX();
|
|
|
|
rect.y = v1.getY();
|
|
|
|
rect.width = v2.getX()-v1.getX();
|
|
|
|
rect.height = v2.getY()-v1.getY();
|
2007-06-26 21:20:01 +00:00
|
|
|
|
2007-09-15 17:54:02 +00:00
|
|
|
if(pixmap == NULL || fabs(lastImageWidth - getImageWidth()) >= 0.000001 || fabs(lastImageHeight - getImageHeight()) >= 0.000001 ||
|
|
|
|
lastWidth != widget->allocation.width || lastHeight != widget->allocation.height || lastEditMode != getEditMode() || repaint)
|
2007-06-25 16:55:01 +00:00
|
|
|
{
|
|
|
|
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;
|
2007-09-15 17:54:02 +00:00
|
|
|
lastEditMode = getEditMode();
|
2007-06-25 16:55:01 +00:00
|
|
|
repaint = FALSE;
|
|
|
|
|
2007-09-15 17:54:02 +00:00
|
|
|
|
2007-06-25 16:55:01 +00:00
|
|
|
cr = gdk_cairo_create(GDK_DRAWABLE(pixmap));
|
|
|
|
|
|
|
|
cairo_translate(cr, getImageWidth()/2-xTranslate, getImageHeight()/2-yTranslate);
|
|
|
|
cairo_scale(cr, scale, scale);
|
|
|
|
|
|
|
|
cairo_set_line_width(cr, 1.0/scale);
|
2007-09-15 17:54:02 +00:00
|
|
|
cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND);
|
2007-06-25 16:55:01 +00:00
|
|
|
|
2007-06-26 21:20:01 +00:00
|
|
|
cairo_set_source_rgb(cr, 0, 0, 0);
|
|
|
|
cairo_paint(cr);
|
|
|
|
|
2007-06-25 16:55:01 +00:00
|
|
|
drawGrid(cr, &rect);
|
|
|
|
|
|
|
|
for(i = 0; i < getLevel()->nRooms; i++) {
|
2007-09-15 21:22:05 +00:00
|
|
|
if(&getLevel()->rooms[i] != getActiveRoom()) {
|
2007-09-15 17:54:02 +00:00
|
|
|
polygon2path(cr, &getLevel()->rooms[i].polygon, &rect, TRUE);
|
2007-09-15 21:22:05 +00:00
|
|
|
}
|
2007-06-25 16:55:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
2007-09-15 17:54:02 +00:00
|
|
|
polygon2path(cr, &getActiveRoom()->polygon, &rect, TRUE);
|
2007-06-25 16:55:01 +00:00
|
|
|
|
|
|
|
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);
|
2007-06-26 19:30:01 +00:00
|
|
|
cairo_set_line_width(cr, 2.0/scale);
|
2007-09-15 17:54:02 +00:00
|
|
|
cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND);
|
2007-06-25 16:55:01 +00:00
|
|
|
cairo_stroke(cr);
|
|
|
|
}
|
|
|
|
|
|
|
|
cairo_destroy (cr);
|
|
|
|
}
|
2007-06-21 19:52:03 +00:00
|
|
|
|
2007-06-25 16:55:01 +00:00
|
|
|
gdk_draw_drawable(GDK_DRAWABLE(widget->window), widget->style->fg_gc[GTK_WIDGET_STATE(widget)], GDK_DRAWABLE(pixmap), 0, 0, 0, 0, -1, -1);
|
2007-06-21 19:52:03 +00:00
|
|
|
|
2007-09-15 17:54:02 +00:00
|
|
|
cr = gdk_cairo_create(GDK_DRAWABLE(widget->window));
|
|
|
|
|
|
|
|
cairo_translate(cr, getImageWidth()/2-xTranslate, getImageHeight()/2-yTranslate);
|
|
|
|
cairo_scale(cr, scale, scale);
|
|
|
|
|
|
|
|
cairo_set_line_width(cr, 2.0/scale);
|
|
|
|
cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER);
|
|
|
|
|
2007-06-26 21:20:01 +00:00
|
|
|
if(getHoveredRoom() != NULL && getHoveredRoom() != getActiveRoom() &&
|
|
|
|
(getEditMode() == EDIT_MODE_VIEW || getEditMode() == EDIT_MODE_SELECTED))
|
|
|
|
{
|
2007-09-15 17:54:02 +00:00
|
|
|
polygon2path(cr, &getHoveredRoom()->polygon, &rect, TRUE);
|
2007-06-26 19:30:01 +00:00
|
|
|
|
2007-09-15 17:54:02 +00:00
|
|
|
cairo_set_source_rgba(cr, 0.0, 0.7, 1.0, 0.7);
|
|
|
|
cairo_stroke(cr);
|
|
|
|
}
|
|
|
|
else if(getEditMode() == EDIT_MODE_ADD) {
|
|
|
|
polygon2path(cr, &getActiveRoom()->polygon, NULL, FALSE);
|
2007-06-26 19:30:01 +00:00
|
|
|
|
2007-09-15 17:54:02 +00:00
|
|
|
if(isPolygonOk(&getActiveRoom()->polygon))
|
|
|
|
cairo_set_source_rgba(cr, 0.0, 0.7, 1.0, 0.2);
|
|
|
|
else
|
|
|
|
cairo_set_source_rgba(cr, 1.0, 0.3, 0.3, 0.2);
|
|
|
|
cairo_fill_preserve(cr);
|
2007-06-26 19:30:01 +00:00
|
|
|
|
|
|
|
|
2007-09-16 19:06:02 +00:00
|
|
|
if(!getActiveRoom()->polygon.empty() && getHoveredVertex()) {
|
2007-09-15 17:54:02 +00:00
|
|
|
vertexOk = isVertexOk(getHoveredVertex());
|
|
|
|
|
|
|
|
if(vertexOk)
|
2007-09-16 14:07:03 +00:00
|
|
|
cairo_line_to(cr, getHoveredVertex()->getX(), getHoveredVertex()->getY());
|
2007-09-15 17:54:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
cairo_set_line_width(cr, 2.0/scale);
|
|
|
|
cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND);
|
|
|
|
cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
|
2007-06-26 19:30:01 +00:00
|
|
|
cairo_set_source_rgba(cr, 0.0, 0.7, 1.0, 0.7);
|
|
|
|
cairo_stroke(cr);
|
|
|
|
|
2007-09-16 19:06:02 +00:00
|
|
|
if(!getActiveRoom()->polygon.empty() && getHoveredVertex() && !vertexOk) {
|
2007-09-15 17:54:02 +00:00
|
|
|
cairo_set_source_rgba(cr, 1.0, 0.3, 0.3, 0.7);
|
|
|
|
|
2007-09-16 19:06:02 +00:00
|
|
|
cairo_move_to(cr, getActiveRoom()->polygon.back().getX(), getActiveRoom()->polygon.back().getY());
|
2007-09-16 14:07:03 +00:00
|
|
|
cairo_line_to(cr, getHoveredVertex()->getX(), getHoveredVertex()->getY());
|
2007-09-15 17:54:02 +00:00
|
|
|
|
|
|
|
cairo_stroke(cr);
|
|
|
|
}
|
2007-06-26 19:30:01 +00:00
|
|
|
}
|
|
|
|
|
2007-09-15 17:54:02 +00:00
|
|
|
cairo_destroy (cr);
|
|
|
|
|
2007-06-21 19:52:03 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2007-06-25 16:55:01 +00:00
|
|
|
|
2007-06-21 19:52:03 +00:00
|
|
|
double getScale() {
|
|
|
|
return scale;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setScale(double s) {
|
2007-09-15 17:54:02 +00:00
|
|
|
scale = MAX(0.005, MIN(s, 10000));
|
2007-06-25 16:55:01 +00:00
|
|
|
repaint = TRUE;
|
|
|
|
}
|
|
|
|
|
2007-09-16 14:07:03 +00:00
|
|
|
void imageToView(Vertex *v) {
|
|
|
|
v->setX(v->getX()*scale+getImageWidth()/2-xTranslate);
|
|
|
|
v->setY(v->getY()*scale+getImageHeight()/2-yTranslate);
|
2007-06-25 16:55:01 +00:00
|
|
|
}
|
|
|
|
|
2007-09-16 14:07:03 +00:00
|
|
|
void viewToImage(Vertex *v) {
|
|
|
|
v->setX((v->getX()-getImageWidth()/2+xTranslate)/scale);
|
|
|
|
v->setY((v->getY()-getImageHeight()/2+yTranslate)/scale);
|
2007-06-21 19:52:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
double getImageWidth() {
|
2007-06-25 16:55:01 +00:00
|
|
|
const LEVEL *level = getLevel();
|
|
|
|
double min = 0.0, max = 0.0;
|
2007-09-16 19:06:02 +00:00
|
|
|
int i;
|
|
|
|
|
2007-06-25 16:55:01 +00:00
|
|
|
|
|
|
|
if(level) {
|
|
|
|
for(i = 0; i < level->nRooms; i++) {
|
2007-09-16 19:06:02 +00:00
|
|
|
for(Polygon::iterator it = level->rooms[i].polygon.begin(); it != level->rooms[i].polygon.end(); it++) {
|
|
|
|
min = MIN(min, it->getX());
|
|
|
|
max = MAX(max, it->getX());
|
2007-06-25 16:55:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (max-min+10)*scale;
|
2007-06-21 19:52:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
double getImageHeight() {
|
2007-06-25 16:55:01 +00:00
|
|
|
const LEVEL *level = getLevel();
|
|
|
|
double min = 0.0, max = 0.0;
|
2007-09-16 19:06:02 +00:00
|
|
|
int i;
|
2007-06-25 16:55:01 +00:00
|
|
|
|
|
|
|
if(level) {
|
|
|
|
for(i = 0; i < level->nRooms; i++) {
|
2007-09-16 19:06:02 +00:00
|
|
|
for(Polygon::iterator it = level->rooms[i].polygon.begin(); it != level->rooms[i].polygon.end(); it++) {
|
|
|
|
min = MIN(min, it->getY());
|
|
|
|
max = MAX(max, it->getY());
|
2007-06-25 16:55:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (max-min+10)*scale;
|
2007-06-21 19:52:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
double getXTranslate() {
|
|
|
|
return xTranslate;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setXTranslate(double x) {
|
|
|
|
xTranslate = x;
|
2007-06-25 16:55:01 +00:00
|
|
|
repaint = TRUE;
|
2007-06-21 19:52:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
double getYTranslate() {
|
|
|
|
return yTranslate;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setYTranslate(double y) {
|
|
|
|
yTranslate = y;
|
2007-06-25 16:55:01 +00:00
|
|
|
repaint = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void redraw() {
|
|
|
|
repaint = TRUE;
|
2007-06-21 19:52:03 +00:00
|
|
|
}
|