1 /*
2 -----------------------------------------------------------------------------
3 This source file is part of OGRE
4 (Object-oriented Graphics Rendering Engine)
5 For the latest info, see http://www.ogre3d.org
6
7 Copyright (c) 2000-2013 Torus Knot Software Ltd
8
9 Permission is hereby granted, free of charge, to any person obtaining a copy
10 of this software and associated documentation files (the "Software"), to deal
11 in the Software without restriction, including without limitation the rights
12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom the Software is
14 furnished to do so, subject to the following conditions:
15
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
18
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 THE SOFTWARE.
26 -----------------------------------------------------------------------------
27 */
28
29 #include "OgreGTKWindow.h"
30 #include "OgreGTKGLSupport.h"
31 #include "OgreRenderSystem.h"
32 #include "OgreRoot.h"
33 #include "OgreLogManager.h"
34
35 using namespace Ogre;
36
OGREWidget(bool useDepthBuffer)37 OGREWidget::OGREWidget(bool useDepthBuffer) :
38 Gtk::GL::DrawingArea()
39 {
40 Glib::RefPtr<Gdk::GL::Config> glconfig;
41
42 Gdk::GL::ConfigMode mode = Gdk::GL::MODE_RGBA | Gdk::GL::MODE_DOUBLE;
43 if (useDepthBuffer)
44 mode |= Gdk::GL::MODE_DEPTH;
45
46 glconfig = Gdk::GL::Config::create(mode);
47 if (glconfig.is_null())
48 {
49 LogManager::getSingleton().logMessage("[gtk] GLCONFIG BLOWUP");
50 }
51
52 // Inherit GL context from Ogre main context
53 set_gl_capability(glconfig, GTKGLSupport::getSingleton().getMainContext());
54
55 add_events(Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK);
56 }
57
58 // OGREWidget TODO:
59 // - resize events et al
60 // - Change aspect ratio
61
GTKWindow()62 GTKWindow::GTKWindow():
63 mGtkWindow(0)
64 {
65 //kit = Gtk::Main::instance();
66
67 // Should this move to GTKGLSupport?
68 // Gtk::GL::init(0, NULL);
69 // Already done in GTKGLSupport
70
71 mWidth = 0;
72 mHeight = 0;
73 }
74
~GTKWindow()75 GTKWindow::~GTKWindow()
76 {
77 }
pump_events()78 bool GTKWindow::pump_events()
79 {
80 Gtk::Main *kit = Gtk::Main::instance();
81 if (kit->events_pending())
82 {
83 kit->iteration(false);
84 return true;
85 }
86 return false;
87 }
88
get_ogre_widget()89 OGREWidget* GTKWindow::get_ogre_widget()
90 {
91 return ogre;
92 }
93
create(const String & name,unsigned int width,unsigned int height,unsigned int colourDepth,bool fullScreen,int left,int top,bool depthBuffer,void * miscParam,...)94 void GTKWindow::create(const String& name, unsigned int width, unsigned int height, unsigned int colourDepth,
95 bool fullScreen, int left, int top, bool depthBuffer,
96 void* miscParam, ...)
97 {
98 mName = name;
99 mWidth = width;
100 mHeight = height;
101
102 if(!miscParam) {
103 mGtkWindow = new Gtk::Window();
104 mGtkWindow->set_title(mName);
105
106 if (fullScreen)
107 {
108 mIsFullScreen = true;
109 mGtkWindow->set_decorated(false);
110 mGtkWindow->fullscreen();
111 }
112 else
113 {
114 mIsFullScreen = false;
115 mGtkWindow->set_default_size(mWidth, mHeight);
116 mGtkWindow->move(left, top);
117 }
118 } else {
119 // If miscParam is not 0, a parent widget has been passed in,
120 // we will handle this later on after the widget has been created.
121 }
122
123 ogre = Gtk::manage(new OGREWidget(depthBuffer));
124 ogre->set_size_request(width, height);
125
126 ogre->signal_delete_event().connect(SigC::slot(*this, >KWindow::on_delete_event));
127 ogre->signal_expose_event().connect(SigC::slot(*this, >KWindow::on_expose_event));
128
129 if(mGtkWindow) {
130 mGtkWindow->add(*ogre);
131 mGtkWindow->show_all();
132 }
133 if(miscParam) {
134 // Attach it!
135 // Note that the parent widget *must* be visible already at this point,
136 // or the widget won't get realized in time for the GLinit that follows
137 // this call. This is usually the case for Glade generated windows, anyway.
138 reinterpret_cast<Gtk::Container*>(miscParam)->add(*ogre);
139 ogre->show();
140 }
141 //ogre->realize();
142 }
143
destroy()144 void GTKWindow::destroy()
145 {
146 Root::getSingleton().getRenderSystem()->detachRenderTarget( this->getName() );
147 // We could detach the widget from its parent and destroy it here too,
148 // but then again, it is managed so we rely on GTK to destroy it.
149 delete mGtkWindow;
150 mGtkWindow = 0;
151
152 }
153
setFullscreen(bool fullScreen,unsigned int width,unsigned int height)154 void GTKWindow::setFullscreen(bool fullScreen, unsigned int width, unsigned int height)
155 {
156
157 if((fullScreen) && (!mIsFullScreen))
158 {
159 mIsFullScreen = true;
160 mGtkWindow->fullscreen();
161 ogre->set_size_request(width, height);
162 }
163 else if((!fullScreen) && (mIsFullScreen))
164 {
165 mIsFullScreen = false;
166 mGtkWindow->unfullscreen();
167 ogre->set_size_request(width, height);
168 }
169 }
170
isActive() const171 bool GTKWindow::isActive() const
172 {
173 return ogre->is_realized();
174 }
175
isClosed() const176 bool GTKWindow::isClosed() const
177 {
178 return ogre->is_visible();
179 }
180
reposition(int left,int top)181 void GTKWindow::reposition(int left, int top)
182 {
183 if(mGtkWindow)
184 mGtkWindow->move(left, top);
185 }
186
resize(unsigned int width,unsigned int height)187 void GTKWindow::resize(unsigned int width, unsigned int height)
188 {
189 if(mGtkWindow)
190 mGtkWindow->resize(width, height);
191 }
192
swapBuffers()193 void GTKWindow::swapBuffers()
194 {
195 Glib::RefPtr<Gdk::GL::Window> glwindow = ogre->get_gl_window();
196 glwindow->swap_buffers();
197 }
198
copyContentsToMemory(const PixelBox & dst,FrameBuffer buffer)199 void GTKWindow::copyContentsToMemory(const PixelBox &dst, FrameBuffer buffer)
200 {
201 if ((dst.left < 0) || (dst.right > mWidth) ||
202 (dst.top < 0) || (dst.bottom > mHeight) ||
203 (dst.front != 0) || (dst.back != 1))
204 {
205 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
206 "Invalid box.",
207 "GTKWindow::copyContentsToMemory" );
208 }
209
210 if (buffer == FB_AUTO)
211 {
212 buffer = mIsFullScreen? FB_FRONT : FB_BACK;
213 }
214
215 GLenum format = Ogre::GLPixelUtil::getGLOriginFormat(dst.format);
216 GLenum type = Ogre::GLPixelUtil::getGLOriginDataType(dst.format);
217
218 if ((format == GL_NONE) || (type == 0))
219 {
220 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
221 "Unsupported format.",
222 "GTKWindow::copyContentsToMemory" );
223 }
224
225 // Switch context if different from current one
226 RenderSystem* rsys = Root::getSingleton().getRenderSystem();
227 rsys->_setViewport(this->getViewport(0));
228
229 if(dst.getWidth() != dst.rowPitch)
230 glPixelStorei(GL_PACK_ROW_LENGTH, dst.rowPitch);
231 // Must change the packing to ensure no overruns!
232 glPixelStorei(GL_PACK_ALIGNMENT, 1);
233
234 glReadBuffer((buffer == FB_FRONT)? GL_FRONT : GL_BACK);
235 glReadPixels((GLint)0, (GLint)(mHeight - dst.getHeight()),
236 (GLsizei)dst.getWidth(), (GLsizei)dst.getHeight(),
237 format, type, dst.getTopLeftFrontPixelPtr());
238
239 // restore default alignment
240 glPixelStorei(GL_PACK_ALIGNMENT, 4);
241 glPixelStorei(GL_PACK_ROW_LENGTH, 0);
242
243 PixelUtil::bulkPixelVerticalFlip(dst);
244 }
245
getCustomAttribute(const String & name,void * pData)246 void GTKWindow::getCustomAttribute( const String& name, void* pData )
247 {
248 if( name == "GTKMMWINDOW" )
249 {
250 Gtk::Window **win = static_cast<Gtk::Window **>(pData);
251 // Oh, the burdens of multiple inheritance
252 *win = mGtkWindow;
253 return;
254 }
255 else if( name == "GTKGLMMWIDGET" )
256 {
257 Gtk::GL::DrawingArea **widget = static_cast<Gtk::GL::DrawingArea **>(pData);
258 *widget = ogre;
259 return;
260 }
261 else if( name == "isTexture" )
262 {
263 bool *b = reinterpret_cast< bool * >( pData );
264 *b = false;
265 return;
266 }
267 RenderWindow::getCustomAttribute(name, pData);
268 }
269
270
on_delete_event(GdkEventAny * event)271 bool GTKWindow::on_delete_event(GdkEventAny* event)
272 {
273 Root::getSingleton().getRenderSystem()->detachRenderTarget( this->getName() );
274 return false;
275 }
276
on_expose_event(GdkEventExpose * event)277 bool GTKWindow::on_expose_event(GdkEventExpose* event)
278 {
279 // Window exposed, update interior
280 //std::cout << "Window exposed, update interior" << std::endl;
281 // TODO: time between events, as expose events can be sent crazily fast
282 update();
283 return false;
284 }
285