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

Last change on this file since 206 was 206, checked in by sam, 10 years ago

Activate depth buffer when the GL context is created.

  • Property svn:keywords set to Id
File size: 8.0 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#include <gdk/gdkkeysyms.h>
13
14#include "core.h"
15#include "glmapview.h"
16
17static float const FPS = 30.0f;
18
19GlMapView::GlMapView(GtkBuilder *builder)
20  : hadj(GTK_ADJUSTMENT(gtk_builder_get_object(builder, "gl_hadj"))),
21    vadj(GTK_ADJUSTMENT(gtk_builder_get_object(builder, "gl_vadj"))),
22    ticking(FALSE), panning(FALSE),
23    mapviewer(0),
24    xpan(0.0), ypan(0.0)
25{
26    /* Create new OpenGL widget */
27    int attrlist[] =
28    {
29        GDK_GL_RGBA,
30        GDK_GL_RED_SIZE, 1,
31        GDK_GL_GREEN_SIZE, 1,
32        GDK_GL_BLUE_SIZE, 1,
33        GDK_GL_DEPTH_SIZE, 16,
34        GDK_GL_DOUBLEBUFFER,
35        GDK_GL_NONE
36    };
37
38    glarea = gtk_gl_area_new(attrlist);
39    gtk_widget_set_usize(glarea, 400, 300);
40    gtk_widget_set_events(glarea, GDK_EXPOSURE_MASK |
41                                  GDK_POINTER_MOTION_MASK |
42                                  GDK_BUTTON_PRESS_MASK |
43                                  GDK_BUTTON_RELEASE_MASK);
44    gtk_widget_set_can_focus(glarea, TRUE);
45
46    GtkContainer *cont = GTK_CONTAINER(gtk_builder_get_object(builder,
47                                                              "gl_container"));
48    gtk_container_add(cont, glarea);
49
50    /* We tick from the idle function instead of a timeout to avoid
51     * stealing time from the GTK loop when the callback time exceeds
52     * the timeout value. */
53    g_idle_add((GSourceFunc)IdleTickSignal, this);
54
55    /* We must divert gtk_main_quit() to release our resources when the
56     * GL widget is still realised. We'll call gtk_main_quit() when we
57     * are sure that everything has been cleaned. */
58    gtk_quit_add(0, (GtkFunction)ShutdownSignal, this);
59
60    gtk_signal_connect(GTK_OBJECT(glarea), "realize",
61                       GTK_SIGNAL_FUNC(SetupSignal), this);
62    gtk_signal_connect(GTK_OBJECT(glarea), "expose_event",
63                       GTK_SIGNAL_FUNC(DrawSignal), this);
64    gtk_signal_connect(GTK_OBJECT(glarea), "configure_event",
65                       GTK_SIGNAL_FUNC(ReshapeSignal), this);
66
67    gtk_signal_connect(GTK_OBJECT(glarea), "button_press_event",
68                       GTK_SIGNAL_FUNC(MouseButtonSignal), this);
69    gtk_signal_connect(GTK_OBJECT(glarea), "button_release_event",
70                       GTK_SIGNAL_FUNC(MouseButtonSignal), this);
71    gtk_signal_connect(GTK_OBJECT(glarea), "motion_notify_event",
72                       GTK_SIGNAL_FUNC(MouseMotionSignal), this);
73
74    gtk_signal_connect(GTK_OBJECT(glarea), "key_press_event",
75                       GTK_SIGNAL_FUNC(KeyPressSignal), this);
76}
77
78void GlMapView::LoadMap(char const *path)
79{
80    // FIXME: detect when the map viewer is killed
81    mapviewer = new MapViewer(path);
82    Ticker::Ref(mapviewer);
83
84    UpdateAdjustments();
85}
86
87void GlMapView::CloseMap()
88{
89    if (mapviewer)
90        Ticker::Unref(mapviewer);
91    mapviewer = NULL;
92
93    UpdateAdjustments();
94}
95
96gboolean GlMapView::IdleTick()
97{
98    if (Ticker::Finished())
99    {
100        gtk_main_quit();
101        return FALSE;
102    }
103
104    ticking = TRUE;
105
106    if (mapviewer)
107        mapviewer->SetPOV(gtk_adjustment_get_value(hadj),
108                          mapviewer->GetHeight() - glarea->allocation.height
109                           - gtk_adjustment_get_value(vadj));
110
111    /* Tick the game */
112    Ticker::TickGame();
113
114    gtk_widget_draw(GTK_WIDGET(glarea), NULL);
115
116    return TRUE;
117}
118
119gboolean GlMapView::Setup()
120{
121    /* Set up display */
122    gtk_widget_grab_focus(glarea);
123    if (gtk_gl_area_make_current(GTK_GL_AREA(glarea)))
124        Video::Setup(glarea->allocation.width, glarea->allocation.height);
125
126    UpdateAdjustments();
127
128    return TRUE;
129}
130
131gboolean GlMapView::Shutdown()
132{
133    CloseMap();
134    Ticker::Shutdown();
135    /* Hijack the exit process by adding another level of gtk_main */
136    gtk_widget_set_sensitive(gtk_widget_get_toplevel(glarea), FALSE);
137    gtk_main();
138    return TRUE;
139}
140
141gboolean GlMapView::Draw(GdkEventExpose *e)
142{
143    if (e->count > 0)
144        return TRUE;
145
146    /* OpenGL functions can be called only if make_current returns true */
147    if (ticking && gtk_gl_area_make_current(GTK_GL_AREA(glarea)))
148    {
149        ticking = FALSE;
150
151        /* Clear the screen, tick the renderer, show the frame and
152         * clamp to desired framerate */
153        Video::Clear();
154        Ticker::TickDraw();
155        gtk_gl_area_swapbuffers(GTK_GL_AREA(glarea));
156        while (g_main_context_iteration(NULL, FALSE))
157            ;
158
159        // FIXME: do some GTK stuff in here
160        Ticker::ClampFps(1000.0f / FPS);
161    }
162
163    return TRUE;
164}
165
166void GlMapView::Scroll(double dx, double dy)
167{
168    gtk_adjustment_set_value(hadj, gtk_adjustment_get_value(hadj) + dx);
169    gtk_adjustment_set_value(vadj, gtk_adjustment_get_value(vadj) + dy);
170
171    UpdateAdjustments();
172}
173
174void GlMapView::UpdateAdjustments()
175{
176    float w = mapviewer ? mapviewer->GetWidth() : glarea->allocation.width;
177    float h = mapviewer ? mapviewer->GetHeight() : glarea->allocation.height;
178
179    /* Manage adjustments */
180    struct { GtkAdjustment *adj; float map_size, sw_size; } s[2] =
181    {
182        { hadj, w, glarea->allocation.width },
183        { vadj, h, glarea->allocation.height },
184    };
185
186    for (int i = 0; i < 2; i++)
187    {
188        gtk_adjustment_set_lower(s[i].adj, 0);
189        gtk_adjustment_set_upper(s[i].adj, s[i].map_size);
190        gtk_adjustment_set_step_increment(s[i].adj, 1);
191        gtk_adjustment_set_page_increment(s[i].adj, s[i].sw_size);
192        gtk_adjustment_set_page_size(s[i].adj, s[i].sw_size);
193
194        float val = gtk_adjustment_get_value(s[i].adj);
195        if (val + s[i].sw_size > s[i].map_size)
196        {
197            gtk_adjustment_set_value(s[i].adj,
198                                     s[i].map_size - s[i].sw_size);
199            gtk_adjustment_value_changed(s[i].adj);
200        }
201    }
202}
203
204gboolean GlMapView::MouseButton(GdkEventButton *e)
205{
206    if (e->type == GDK_BUTTON_PRESS && e->button == 2)
207    {
208        panning = TRUE;
209        xpan = e->x;
210        ypan = e->y;
211        GdkCursor *cursor = gdk_cursor_new(GDK_HAND1);
212        gdk_window_set_cursor(glarea->window, cursor);
213        gdk_cursor_unref(cursor);
214        return FALSE;
215    }
216    else if (e->type == GDK_BUTTON_RELEASE && e->button == 2)
217    {
218        panning = FALSE;
219        gdk_window_set_cursor(glarea->window, NULL);
220        return FALSE;
221    }
222
223    return TRUE;
224}
225
226gboolean GlMapView::MouseMotion(GdkEventMotion *e)
227{
228    if (panning)
229    {
230        Scroll(xpan - e->x, ypan - e->y);
231        xpan = e->x;
232        ypan = e->y;
233        return TRUE;
234    }
235
236    return FALSE;
237}
238
239gboolean GlMapView::KeyPress(GdkEventKey *e)
240{
241    switch (e->keyval)
242    {
243    case GDK_Up:    Scroll(  0.0, -10.0); return TRUE;
244    case GDK_Down:  Scroll(  0.0,  10.0); return TRUE;
245    case GDK_Left:  Scroll(-10.0,   0.0); return TRUE;
246    case GDK_Right: Scroll( 10.0,   0.0); return TRUE;
247    }
248
249    return FALSE;
250}
251
252/* Private signal slots */
253gboolean GlMapView::IdleTickSignal(GlMapView *that)
254{
255    return that->IdleTick();
256}
257
258gboolean GlMapView::SetupSignal(GtkWidget *w, GlMapView *that)
259{
260    (void)w;
261    return that->Setup();
262}
263
264gboolean GlMapView::ShutdownSignal(GlMapView *that)
265{
266    return that->Shutdown();
267}
268
269gboolean GlMapView::DrawSignal(GtkWidget *w, GdkEventExpose *e,
270                               GlMapView *that)
271{
272    (void)w;
273    return that->Draw(e);
274}
275
276gboolean GlMapView::ReshapeSignal(GtkWidget *w, GdkEventConfigure *e,
277                                  GlMapView *that)
278{
279    (void)w;
280    (void)e;
281    return that->Setup();
282}
283
284gboolean GlMapView::MouseButtonSignal(GtkWidget *w, GdkEventButton *e,
285                                      GlMapView *that)
286{
287    (void)w;
288    return that->MouseButton(e);
289}
290
291gboolean GlMapView::MouseMotionSignal(GtkWidget *w, GdkEventMotion *e,
292                                      GlMapView *that)
293{
294    (void)w;
295    return that->MouseMotion(e);
296}
297
298gboolean GlMapView::KeyPressSignal(GtkWidget *w, GdkEventKey *e,
299                                   GlMapView *that)
300{
301    (void)w;
302    return that->KeyPress(e);
303}
304
Note: See TracBrowser for help on using the repository browser.