This repository has been archived on 2025-03-02. You can view files and clone it, but cannot push or open issues or pull requests.
neofx-zoomedit/Drawer.cpp

262 lines
8.4 KiB
C++
Raw Normal View History

#include "Drawer.h"
#include "Window.h"
#include <GL/gl.h>
#include <math.h>
void Drawer::realize(GtkWidget *widget, Drawer *drawer) {
GdkGLContext *context = gtk_widget_get_gl_context(widget);
GdkGLDrawable *drawable = gtk_widget_get_gl_drawable(widget);
if(!gdk_gl_drawable_gl_begin(drawable, context))
return;
glClearColor(0, 0, 0, 1);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glEnable(GL_LINE_SMOOTH);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gdk_gl_drawable_gl_end(drawable);
}
gboolean Drawer::eventHandler(GtkWidget *widget, GdkEvent *event, Drawer *drawer) {
switch(event->type) {
case GDK_CONFIGURE:
drawer->updateViewport();
drawer->updateScrollbars();
return TRUE;
case GDK_EXPOSE:
drawer->render();
return TRUE;
case GDK_MOTION_NOTIFY:
drawer->updateHoveredPoint(event->motion.x, event->motion.y);
return TRUE;
case GDK_ENTER_NOTIFY:
drawer->updateHoveredPoint(event->crossing.x, event->crossing.y);
return TRUE;
case GDK_LEAVE_NOTIFY:
drawer->window->getEditManager().setHoveredVertex(NULL);
return TRUE;
case GDK_BUTTON_PRESS:
drawer->window->getEditManager().buttonPress(event->button.button);
return TRUE;
case GDK_SCROLL:
switch(event->scroll.direction) {
case GDK_SCROLL_UP:
drawer->zoom(1, event->scroll.x/widget->allocation.width, event->scroll.y/widget->allocation.height);
break;
case GDK_SCROLL_DOWN:
drawer->zoom(-1, event->scroll.x/widget->allocation.width, event->scroll.y/widget->allocation.height);
break;
default:
return FALSE;
}
return TRUE;
default:
return FALSE;
}
}
void Drawer::valueChanged(GtkAdjustment *adjustment, Drawer *drawer) {
drawer->updateScrolling();
}
void Drawer::updateViewport() {
GdkGLContext *context = gtk_widget_get_gl_context(drawingArea);
GdkGLDrawable *drawable = gtk_widget_get_gl_drawable(drawingArea);
if(!gdk_gl_drawable_gl_begin(drawable, context))
return;
glViewport(0, 0, getWidth(), getHeight());
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if(getWidth() != 0 && getHeight() != 0) {
glTranslatef(-1, 1, 0);
glScalef(2.0f/getWidth(), -2.0f/getHeight(), 1);
}
gdk_gl_drawable_gl_end(drawable);
}
void Drawer::updateScrolling() {
if(getImageWidth() < getWidth())
xTranslate = (getImageWidth()-getWidth())/2;
else
xTranslate = gtk_adjustment_get_value(hAdjustment);
if(getImageHeight() < getHeight())
yTranslate = (getImageHeight()-getHeight())/2;
else
yTranslate = gtk_adjustment_get_value(vAdjustment);
update();
}
void Drawer::updateScrollbars(float x, float y) {
const gdouble imageWidth = getImageWidth(), imageHeight = getImageHeight();
const gdouble width = getWidth(), height = getHeight();
gdouble upper, pageSize, value;
gdk_window_freeze_updates(drawingArea->window);
g_object_get(G_OBJECT(hAdjustment), "upper", &upper, "page_size", &pageSize, NULL);
g_object_set(G_OBJECT(hAdjustment), "upper", imageWidth, "page_size", width, NULL);
gtk_adjustment_changed(hAdjustment);
if((pageSize > upper && width < imageWidth) || upper == 0)
value = (imageWidth-width)/2;
else
value = (gtk_adjustment_get_value(hAdjustment)+pageSize*x)/upper*imageWidth-width*x;
gtk_adjustment_set_value(hAdjustment, MAX(MIN(value, imageWidth-width), 0));
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;
else
value = (gtk_adjustment_get_value(vAdjustment)+pageSize*y)/upper*imageHeight-height*y;
gtk_adjustment_set_value(vAdjustment, MAX(MIN(value, imageHeight-height), 0));
gdk_window_thaw_updates(drawingArea->window);
updateScrolling();
}
void Drawer::updateHoveredPoint(float x, float y) {
Vertex v(x, y);
viewToImage(&v);
window->getEditManager().setHoveredVertex(&v);
}
void Drawer::render() {
GdkGLContext *context = gtk_widget_get_gl_context(drawingArea);
GdkGLDrawable *drawable = gtk_widget_get_gl_drawable(drawingArea);
Rectangle rect(0, 0, drawingArea->allocation.width, drawingArea->allocation.height);
viewToImage(&rect.getVertex1());
viewToImage(&rect.getVertex2());
if(!gdk_gl_drawable_gl_begin(drawable, context))
return;
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glTranslatef(getImageWidth()/2-xTranslate, getImageHeight()/2-yTranslate, 0);
glScalef(scale, scale, 1);
renderer.render(window->getLevel(), rect, scale);
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
gdk_gl_drawable_swap_buffers(drawable);
gdk_gl_drawable_gl_end(drawable);
}
Drawer::Drawer(Window *window, GdkGLConfig *glconfig)
: renderer(&window->getEditManager())
{
this->window = window;
zoomExp = 0;
scale = 100;
xTranslate = 0;
yTranslate = 0;
drawer = gtk_table_new(2, 2, FALSE);
g_object_ref_sink(G_OBJECT(drawer));
drawingArea = gtk_drawing_area_new();
gtk_widget_set_gl_capability(drawingArea, glconfig, NULL, TRUE, GDK_GL_RGBA_TYPE);
g_signal_connect(G_OBJECT(drawingArea), "realize", G_CALLBACK(realize), this);
g_signal_connect(G_OBJECT(drawingArea), "configure-event", G_CALLBACK(eventHandler), this);
g_signal_connect(G_OBJECT(drawingArea), "expose-event", G_CALLBACK(eventHandler), this);
g_signal_connect(G_OBJECT(drawingArea), "button-press-event", G_CALLBACK(eventHandler), this);
//g_signal_connect(G_OBJECT(drawingArea), "button-release-event", G_CALLBACK(eventHandler), this);
g_signal_connect(G_OBJECT(drawingArea), "enter-notify-event", G_CALLBACK(eventHandler), this);
g_signal_connect(G_OBJECT(drawingArea), "leave-notify-event", G_CALLBACK(eventHandler), this);
g_signal_connect(G_OBJECT(drawingArea), "motion-notify-event", G_CALLBACK(eventHandler), this);
g_signal_connect(G_OBJECT(drawingArea), "scroll-event", G_CALLBACK(eventHandler), this);
gtk_widget_add_events(drawingArea, GDK_SCROLL_MASK | GDK_POINTER_MOTION_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
gtk_table_attach(GTK_TABLE(drawer), drawingArea, 0, 1, 0, 1, (GtkAttachOptions)(GTK_FILL|GTK_EXPAND|GTK_SHRINK), (GtkAttachOptions)(GTK_FILL|GTK_EXPAND|GTK_SHRINK), 0, 0);
hAdjustment = GTK_ADJUSTMENT(gtk_adjustment_new(0, 0, 0, 10, 100, 100));
GtkWidget *hScroll = gtk_hscrollbar_new(hAdjustment);
g_signal_connect(G_OBJECT(hScroll), "value-changed", G_CALLBACK(valueChanged), this);
gtk_table_attach(GTK_TABLE(drawer), hScroll, 0, 1, 1, 2, (GtkAttachOptions)(GTK_FILL|GTK_EXPAND|GTK_SHRINK), (GtkAttachOptions)0, 0, 0);
vAdjustment = GTK_ADJUSTMENT(gtk_adjustment_new(0, 0, 0, 10, 100, 100));
GtkWidget *vScroll = gtk_vscrollbar_new(vAdjustment);
g_signal_connect(G_OBJECT(vScroll), "value-changed", G_CALLBACK(valueChanged), this);
gtk_table_attach(GTK_TABLE(drawer), vScroll, 1, 2, 0, 1, (GtkAttachOptions)0, (GtkAttachOptions)(GTK_FILL|GTK_EXPAND|GTK_SHRINK), 0, 0);
gtk_widget_show_all(drawer);
}
Drawer::~Drawer() {
g_object_unref(G_OBJECT(drawer));
}
void Drawer::zoom(int zoom, float x, float y) {
zoomExp = MAX(MIN(zoomExp + zoom, 50), -100);
scale = 100*powf(1.1f, zoomExp);
updateScrollbars(x, y);
}
void Drawer::imageToView(Vertex *v) const {
v->setX(v->getX()*scale+getImageWidth()/2-xTranslate);
v->setY(v->getY()*scale+getImageHeight()/2-yTranslate);
}
void Drawer::viewToImage(Vertex *v) const {
v->setX((v->getX()-getImageWidth()/2+xTranslate)/scale);
v->setY((v->getY()-getImageHeight()/2+yTranslate)/scale);
}
float Drawer::getImageWidth() const {
float min = 0, max = 0;
for(Level::iterator room = window->getLevel().begin(); room != window->getLevel().end(); room++) {
for(Room::iterator v = room->begin(); v != room->end(); v++) {
min = fminf(min, v->getX());
max = fmaxf(max, v->getX());
}
}
return (max-min+10)*scale;
}
float Drawer::getImageHeight() const {
float min = 0, max = 0;
for(Level::iterator room = window->getLevel().begin(); room != window->getLevel().end(); room++) {
for(Room::iterator v = room->begin(); v != room->end(); v++) {
min = fminf(min, v->getY());
max = fmaxf(max, v->getY());
}
}
return (max-min+10)*scale;
}