source: trunk/src/gtk/glmapview.cpp @ 162

Last change on this file since 162 was 162, checked in by sam, 11 years ago

Refactor editor to get the glarea object out of the main source file.

  • Property svn:keywords set to Id
File size: 7.2 KB
Line 
1//
2// Deus Hax (working title)
3// Copyright (c) 2010 Sam Hocevar <sam@hocevar.net>
4//
5
6#if defined HAVE_CONFIG_H
7#   include "config.h"
8#endif
9
10#include <gtk/gtk.h>
11#include <gtkgl/gtkglarea.h>
12
13#include "core.h"
14#include "glmapview.h"
15
16static float const FPS = 30.0f;
17
18GlMapView::GlMapView(GtkBuilder *builder)
19  : hadj(GTK_ADJUSTMENT(gtk_builder_get_object(builder, "gl_hadj"))),
20    vadj(GTK_ADJUSTMENT(gtk_builder_get_object(builder, "gl_vadj"))),
21    ticking(FALSE), panning(FALSE),
22    mapviewer(0),
23    xpan(0.0), ypan(0.0)
24{
25    /* Create new OpenGL widget */
26    int attrlist[] =
27    {
28        GDK_GL_RGBA,
29        GDK_GL_RED_SIZE, 1,
30        GDK_GL_GREEN_SIZE, 1,
31        GDK_GL_BLUE_SIZE, 1,
32        GDK_GL_DOUBLEBUFFER,
33        GDK_GL_NONE
34    };
35
36    glarea = gtk_gl_area_new(attrlist);
37    gtk_widget_set_usize(glarea, 400, 300);
38    gtk_widget_set_events(glarea, GDK_EXPOSURE_MASK |
39                                  GDK_POINTER_MOTION_MASK |
40                                  GDK_BUTTON_PRESS_MASK |
41                                  GDK_BUTTON_RELEASE_MASK);
42    GtkContainer *cont = GTK_CONTAINER(gtk_builder_get_object(builder,
43                                                              "gl_container"));
44    gtk_container_add(cont, glarea);
45
46    /* We tick from the idle function instead of a timeout to avoid
47     * stealing time from the GTK loop when the callback time exceeds
48     * the timeout value. */
49    g_idle_add((GSourceFunc)IdleTickSignal, this);
50
51    gtk_signal_connect(GTK_OBJECT(glarea), "realize",
52                       GTK_SIGNAL_FUNC(SetupSignal), this);
53    gtk_signal_connect(GTK_OBJECT(glarea), "destroy",
54                       GTK_SIGNAL_FUNC(DestroySignal), this);
55    gtk_signal_connect(GTK_OBJECT(glarea), "expose_event",
56                       GTK_SIGNAL_FUNC(DrawSignal), this);
57    gtk_signal_connect(GTK_OBJECT(glarea), "configure_event",
58                       GTK_SIGNAL_FUNC(ReshapeSignal), this);
59
60    gtk_signal_connect(GTK_OBJECT(glarea), "button_press_event",
61                       GTK_SIGNAL_FUNC(MouseButtonSignal), this);
62    gtk_signal_connect(GTK_OBJECT(glarea), "button_release_event",
63                       GTK_SIGNAL_FUNC(MouseButtonSignal), this);
64    gtk_signal_connect(GTK_OBJECT(glarea), "motion_notify_event",
65                       GTK_SIGNAL_FUNC(MouseMotionSignal), this);
66}
67
68void GlMapView::LoadMap(char const *path)
69{
70    // FIXME: detect when the map viewer is killed
71    mapviewer = new MapViewer(path);
72}
73
74gboolean GlMapView::IdleTick()
75{
76    // FIXME: do not do anything if the previous tick was too recent?
77
78    ticking = TRUE;
79
80    if (mapviewer)
81        mapviewer->SetPOV(gtk_adjustment_get_value(hadj),
82                          gtk_adjustment_get_value(vadj));
83
84    /* Tick the game */
85    Ticker::TickGame();
86
87    gtk_widget_draw(GTK_WIDGET(glarea), NULL);
88
89    return TRUE;
90}
91
92gboolean GlMapView::Setup()
93{
94    if (mapviewer)
95    {
96        /* Manage adjustments */
97        struct { GtkAdjustment *adj; float map_size, sw_size; } s[2] =
98        {
99            { hadj, mapviewer->GetWidth(), glarea->allocation.width },
100            { vadj, mapviewer->GetHeight(), glarea->allocation.height },
101        };
102
103        for (int i = 0; i < 2; i++)
104        {
105            gtk_adjustment_set_lower(s[i].adj, 0);
106            gtk_adjustment_set_upper(s[i].adj, s[i].map_size);
107            gtk_adjustment_set_step_increment(s[i].adj, 1);
108            gtk_adjustment_set_page_increment(s[i].adj, s[i].sw_size);
109            gtk_adjustment_set_page_size(s[i].adj, s[i].sw_size);
110
111            float val = gtk_adjustment_get_value(s[i].adj);
112            if (val + s[i].sw_size > s[i].map_size)
113            {
114                gtk_adjustment_set_value(s[i].adj,
115                                         s[i].map_size - s[i].sw_size);
116                gtk_adjustment_value_changed(s[i].adj);
117            }
118        }
119    }
120
121    /* Set up display */
122    if (gtk_gl_area_make_current(GTK_GL_AREA(glarea)))
123        Video::Setup(glarea->allocation.width, glarea->allocation.height);
124
125    return TRUE;
126}
127
128gboolean GlMapView::Destroy()
129{
130    g_idle_remove_by_data(this);
131    return TRUE;
132}
133
134gboolean GlMapView::Draw(GdkEventExpose *event)
135{
136    if (event->count > 0)
137        return TRUE;
138
139    /* OpenGL functions can be called only if make_current returns true */
140    if (ticking && gtk_gl_area_make_current(GTK_GL_AREA(glarea)))
141    {
142        ticking = FALSE;
143
144        /* Clear the screen, tick the renderer, show the frame and
145         * clamp to desired framerate */
146        Video::Clear();
147        Ticker::TickDraw();
148        gtk_gl_area_swapbuffers(GTK_GL_AREA(glarea));
149        while (g_main_context_iteration(NULL, FALSE))
150            ;
151        Ticker::ClampFps(1000.0f / FPS);
152    }
153
154    return TRUE;
155}
156
157gboolean GlMapView::MouseButton(GdkEventButton *event)
158{
159    if (event->type == GDK_BUTTON_PRESS && event->button == 2)
160    {
161        panning = TRUE;
162        xpan = event->x;
163        ypan = event->y;
164        GdkCursor *cursor = gdk_cursor_new(GDK_HAND1);
165        gdk_window_set_cursor(glarea->window, cursor);
166        gdk_cursor_unref(cursor);
167        return FALSE;
168    }
169    else if (event->type == GDK_BUTTON_RELEASE && event->button == 2)
170    {
171        panning = FALSE;
172        gdk_window_set_cursor(glarea->window, NULL);
173        return FALSE;
174    }
175
176    return TRUE;
177}
178
179gboolean GlMapView::MouseMotion(GdkEventMotion *event)
180{
181    if (panning)
182    {
183        if (event->x != xpan)
184        {
185            double val = gtk_adjustment_get_value(hadj);
186            int map_width = mapviewer->GetWidth();
187            val += xpan - event->x;
188            xpan = event->x;
189            if (val + glarea->allocation.width > map_width)
190                val = map_width - glarea->allocation.width;
191            gtk_adjustment_set_value(hadj, val);
192            gtk_adjustment_value_changed(hadj);
193        }
194
195        if (event->y != ypan)
196        {
197            double val = gtk_adjustment_get_value(vadj);
198            int map_height = mapviewer->GetHeight();
199            val += ypan - event->y;
200            ypan = event->y;
201            if (val + glarea->allocation.height > map_height)
202                val = map_height - glarea->allocation.height;
203            gtk_adjustment_set_value(vadj, val);
204            gtk_adjustment_value_changed(vadj);
205        }
206    }
207
208    return TRUE;
209}
210
211/* Private signal slots */
212gboolean GlMapView::IdleTickSignal(GlMapView *that)
213{
214    return that->IdleTick();
215}
216
217gboolean GlMapView::SetupSignal(GtkWidget *w, GlMapView *that)
218{
219    (void)w;
220    return that->Setup();
221}
222
223gboolean GlMapView::DestroySignal(GtkWidget *w, GlMapView *that)
224{
225    (void)w;
226    return that->Destroy();
227}
228
229gboolean GlMapView::DrawSignal(GtkWidget *w, GdkEventExpose *event,
230                               GlMapView *that)
231{
232    (void)w;
233    return that->Draw(event);
234}
235
236gboolean GlMapView::ReshapeSignal(GtkWidget *w, GdkEventConfigure *event,
237                                  GlMapView *that)
238{
239    (void)w;
240    (void)event;
241    return that->Setup();
242}
243
244gboolean GlMapView::MouseButtonSignal(GtkWidget *w, GdkEventButton *event,
245                                      GlMapView *that)
246{
247    (void)w;
248    return that->MouseButton(event);
249}
250
251gboolean GlMapView::MouseMotionSignal(GtkWidget *w, GdkEventMotion *event,
252                                      GlMapView *that)
253{
254    (void)w;
255    return that->MouseMotion(event);
256}
257
Note: See TracBrowser for help on using the repository browser.