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, &GTKWindow::on_delete_event));
127 	ogre->signal_expose_event().connect(SigC::slot(*this, &GTKWindow::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