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

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

Add an about dialogue and fix an initialisation bug in the map viewer
scrollbar handling.

  • Property svn:keywords set to Id
File size: 7.3 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    UpdateAdjustments();
74}
75
76gboolean GlMapView::IdleTick()
77{
78    // FIXME: do not do anything if the previous tick was too recent?
79    ticking = TRUE;
80
81    if (mapviewer)
82        mapviewer->SetPOV(gtk_adjustment_get_value(hadj),
83                          gtk_adjustment_get_value(vadj));
84
85    /* Tick the game */
86    Ticker::TickGame();
87
88    gtk_widget_draw(GTK_WIDGET(glarea), NULL);
89
90    return TRUE;
91}
92
93gboolean GlMapView::Setup()
94{
95    /* Set up display */
96    if (gtk_gl_area_make_current(GTK_GL_AREA(glarea)))
97        Video::Setup(glarea->allocation.width, glarea->allocation.height);
98
99    UpdateAdjustments();
100
101    return TRUE;
102}
103
104gboolean GlMapView::Destroy()
105{
106    g_idle_remove_by_data(this);
107    return TRUE;
108}
109
110gboolean GlMapView::Draw(GdkEventExpose *event)
111{
112    if (event->count > 0)
113        return TRUE;
114
115    /* OpenGL functions can be called only if make_current returns true */
116    if (ticking && gtk_gl_area_make_current(GTK_GL_AREA(glarea)))
117    {
118        ticking = FALSE;
119
120        /* Clear the screen, tick the renderer, show the frame and
121         * clamp to desired framerate */
122        Video::Clear();
123        Ticker::TickDraw();
124        gtk_gl_area_swapbuffers(GTK_GL_AREA(glarea));
125        while (g_main_context_iteration(NULL, FALSE))
126            ;
127        Ticker::ClampFps(1000.0f / FPS);
128    }
129
130    return TRUE;
131}
132
133gboolean GlMapView::UpdateAdjustments()
134{
135    float w = mapviewer ? mapviewer->GetWidth() : glarea->allocation.width;
136    float h = mapviewer ? mapviewer->GetHeight() : glarea->allocation.height;
137
138    /* Manage adjustments */
139    struct { GtkAdjustment *adj; float map_size, sw_size; } s[2] =
140    {
141        { hadj, w, glarea->allocation.width },
142        { vadj, h, glarea->allocation.height },
143    };
144
145    for (int i = 0; i < 2; i++)
146    {
147        gtk_adjustment_set_lower(s[i].adj, 0);
148        gtk_adjustment_set_upper(s[i].adj, s[i].map_size);
149        gtk_adjustment_set_step_increment(s[i].adj, 1);
150        gtk_adjustment_set_page_increment(s[i].adj, s[i].sw_size);
151        gtk_adjustment_set_page_size(s[i].adj, s[i].sw_size);
152
153        float val = gtk_adjustment_get_value(s[i].adj);
154        if (val + s[i].sw_size > s[i].map_size)
155        {
156            gtk_adjustment_set_value(s[i].adj,
157                                     s[i].map_size - s[i].sw_size);
158            gtk_adjustment_value_changed(s[i].adj);
159        }
160    }
161
162    return TRUE;
163}
164
165gboolean GlMapView::MouseButton(GdkEventButton *event)
166{
167    if (event->type == GDK_BUTTON_PRESS && event->button == 2)
168    {
169        panning = TRUE;
170        xpan = event->x;
171        ypan = event->y;
172        GdkCursor *cursor = gdk_cursor_new(GDK_HAND1);
173        gdk_window_set_cursor(glarea->window, cursor);
174        gdk_cursor_unref(cursor);
175        return FALSE;
176    }
177    else if (event->type == GDK_BUTTON_RELEASE && event->button == 2)
178    {
179        panning = FALSE;
180        gdk_window_set_cursor(glarea->window, NULL);
181        return FALSE;
182    }
183
184    return TRUE;
185}
186
187gboolean GlMapView::MouseMotion(GdkEventMotion *event)
188{
189    if (panning)
190    {
191        if (event->x != xpan)
192        {
193            double val = gtk_adjustment_get_value(hadj);
194            int map_width = mapviewer->GetWidth();
195            val += xpan - event->x;
196            xpan = event->x;
197            if (val + glarea->allocation.width > map_width)
198                val = map_width - glarea->allocation.width;
199            gtk_adjustment_set_value(hadj, val);
200            gtk_adjustment_value_changed(hadj);
201        }
202
203        if (event->y != ypan)
204        {
205            double val = gtk_adjustment_get_value(vadj);
206            int map_height = mapviewer->GetHeight();
207            val += ypan - event->y;
208            ypan = event->y;
209            if (val + glarea->allocation.height > map_height)
210                val = map_height - glarea->allocation.height;
211            gtk_adjustment_set_value(vadj, val);
212            gtk_adjustment_value_changed(vadj);
213        }
214    }
215
216    return TRUE;
217}
218
219/* Private signal slots */
220gboolean GlMapView::IdleTickSignal(GlMapView *that)
221{
222    return that->IdleTick();
223}
224
225gboolean GlMapView::SetupSignal(GtkWidget *w, GlMapView *that)
226{
227    (void)w;
228    return that->Setup();
229}
230
231gboolean GlMapView::DestroySignal(GtkWidget *w, GlMapView *that)
232{
233    (void)w;
234    return that->Destroy();
235}
236
237gboolean GlMapView::DrawSignal(GtkWidget *w, GdkEventExpose *event,
238                               GlMapView *that)
239{
240    (void)w;
241    return that->Draw(event);
242}
243
244gboolean GlMapView::ReshapeSignal(GtkWidget *w, GdkEventConfigure *event,
245                                  GlMapView *that)
246{
247    (void)w;
248    (void)event;
249    return that->Setup();
250}
251
252gboolean GlMapView::MouseButtonSignal(GtkWidget *w, GdkEventButton *event,
253                                      GlMapView *that)
254{
255    (void)w;
256    return that->MouseButton(event);
257}
258
259gboolean GlMapView::MouseMotionSignal(GtkWidget *w, GdkEventMotion *event,
260                                      GlMapView *that)
261{
262    (void)w;
263    return that->MouseMotion(event);
264}
265
Note: See TracBrowser for help on using the repository browser.