• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2006-2012, Haiku. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Jérôme Duval, korli@users.berlios.de
7  *		Philippe Houdoin, philippe.houdoin@free.fr
8  *		Stefano Ceccherini, burton666@libero.it
9  */
10 
11 #include <kernel/image.h>
12 
13 #include <GLView.h>
14 
15 #include <assert.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 
20 #include <DirectWindow.h>
21 #include <GLRenderer.h>
22 
23 #include "interface/DirectWindowPrivate.h"
24 #include "GLDispatcher.h"
25 #include "GLRendererRoster.h"
26 
27 
28 struct glview_direct_info {
29 	direct_buffer_info* direct_info;
30 	bool direct_connected;
31 	bool enable_direct_mode;
32 
33 	glview_direct_info();
34 	~glview_direct_info();
35 };
36 
37 
BGLView(BRect rect,const char * name,ulong resizingMode,ulong mode,ulong options)38 BGLView::BGLView(BRect rect, const char* name, ulong resizingMode, ulong mode,
39 	ulong options)
40 	:
41 	BView(rect, name, B_FOLLOW_ALL_SIDES, mode | B_WILL_DRAW | B_FRAME_EVENTS),
42 		//  | B_FULL_UPDATE_ON_RESIZE)
43 	fGc(NULL),
44 	fOptions(options),
45 	fDitherCount(0),
46 	fDrawLock("BGLView draw lock"),
47 	fDisplayLock("BGLView display lock"),
48 	fClipInfo(NULL),
49 	fRenderer(NULL),
50 	fRoster(NULL),
51 	fDitherMap(NULL)
52 {
53 	fRoster = new GLRendererRoster(this, options);
54 	fRenderer = fRoster->GetRenderer();
55 }
56 
57 
~BGLView()58 BGLView::~BGLView()
59 {
60 	delete fClipInfo;
61 	if (fRenderer)
62 		fRenderer->Release();
63 }
64 
65 
66 void
LockGL()67 BGLView::LockGL()
68 {
69 	// TODO: acquire the OpenGL API lock it on this glview
70 
71 	fDisplayLock.Lock();
72 	if (fRenderer != NULL && fDisplayLock.CountLocks() == 1)
73 		fRenderer->LockGL();
74 }
75 
76 
77 void
UnlockGL()78 BGLView::UnlockGL()
79 {
80 	if (fRenderer != NULL && fDisplayLock.CountLocks() == 1)
81 		fRenderer->UnlockGL();
82 	fDisplayLock.Unlock();
83 
84 	// TODO: release the GL API lock to others glviews
85 }
86 
87 
88 void
SwapBuffers()89 BGLView::SwapBuffers()
90 {
91 	SwapBuffers(false);
92 }
93 
94 
95 void
SwapBuffers(bool vSync)96 BGLView::SwapBuffers(bool vSync)
97 {
98 	if (fRenderer) {
99 		_LockDraw();
100 		fRenderer->SwapBuffers(vSync);
101 		_UnlockDraw();
102 	}
103 }
104 
105 
106 BView*
EmbeddedView()107 BGLView::EmbeddedView()
108 {
109 	return NULL;
110 }
111 
112 
113 void*
GetGLProcAddress(const char * procName)114 BGLView::GetGLProcAddress(const char* procName)
115 {
116 	BGLDispatcher* glDispatcher = NULL;
117 
118 	if (fRenderer)
119 		glDispatcher = fRenderer->GLDispatcher();
120 
121 	if (glDispatcher)
122 		return (void*)glDispatcher->AddressOf(procName);
123 
124 	return NULL;
125 }
126 
127 
128 status_t
CopyPixelsOut(BPoint source,BBitmap * dest)129 BGLView::CopyPixelsOut(BPoint source, BBitmap* dest)
130 {
131 	if (!fRenderer)
132 		return B_ERROR;
133 
134 	if (!dest || !dest->Bounds().IsValid())
135 		return B_BAD_VALUE;
136 
137 	return fRenderer->CopyPixelsOut(source, dest);
138 }
139 
140 
141 status_t
CopyPixelsIn(BBitmap * source,BPoint dest)142 BGLView::CopyPixelsIn(BBitmap* source, BPoint dest)
143 {
144 	if (!fRenderer)
145 		return B_ERROR;
146 
147 	if (!source || !source->Bounds().IsValid())
148 		return B_BAD_VALUE;
149 
150 	return fRenderer->CopyPixelsIn(source, dest);
151 }
152 
153 
154 /*!	Mesa's GLenum is not ulong but uint, so we can't use GLenum
155 	without breaking this method signature.
156 	Instead, we have to use the effective BeOS's SGI OpenGL GLenum type:
157 	unsigned long.
158  */
159 void
ErrorCallback(unsigned long errorCode)160 BGLView::ErrorCallback(unsigned long errorCode)
161 {
162 	char msg[32];
163 	sprintf(msg, "GL: Error code $%04lx.", errorCode);
164 	// TODO: under BeOS R5, it call debugger(msg);
165 	fprintf(stderr, "%s\n", msg);
166 }
167 
168 
169 void
Draw(BRect updateRect)170 BGLView::Draw(BRect updateRect)
171 {
172 	if (fRenderer) {
173 		_LockDraw();
174 		fRenderer->Draw(updateRect);
175 		_UnlockDraw();
176 		return;
177 	}
178 	// TODO: auto-size and center the string
179 	MovePenTo(8, 32);
180 	DrawString("No OpenGL renderer available!");
181 }
182 
183 
184 void
AttachedToWindow()185 BGLView::AttachedToWindow()
186 {
187 	BView::AttachedToWindow();
188 
189 	fBounds = Bounds();
190 	for (BView* view = this; view != NULL; view = view->Parent())
191 		view->ConvertToParent(&fBounds);
192 
193 	if (fRenderer != NULL) {
194 		// Jackburton: The following code was commented because it doesn't look
195 		// good in "direct" mode:
196 		// when the window is moved, the app_server doesn't paint the view's
197 		// background, and the stuff behind the window itself shows up.
198 		// Setting the view color to black, instead, looks a bit more elegant.
199 #if 0
200 		// Don't paint white window background when resized
201 		SetViewColor(B_TRANSPARENT_32_BIT);
202 #else
203 		SetViewColor(0, 0, 0);
204 #endif
205 
206 		// Set default OpenGL viewport:
207 		LockGL();
208 		glViewport(0, 0, Bounds().IntegerWidth(), Bounds().IntegerHeight());
209 		UnlockGL();
210 		fRenderer->FrameResized(Bounds().IntegerWidth(),
211 			Bounds().IntegerHeight());
212 
213 		if (fClipInfo) {
214 			fRenderer->DirectConnected(fClipInfo->direct_info);
215 			fRenderer->EnableDirectMode(fClipInfo->enable_direct_mode);
216 		}
217 
218 		return;
219 	}
220 
221 	fprintf(stderr, "no renderer found! \n");
222 
223 	// No Renderer, no rendering. Setup a minimal "No Renderer" string drawing
224 	// context
225 	SetFont(be_bold_font);
226 	// SetFontSize(16);
227 }
228 
229 
230 void
AllAttached()231 BGLView::AllAttached()
232 {
233 	BView::AllAttached();
234 }
235 
236 
237 void
DetachedFromWindow()238 BGLView::DetachedFromWindow()
239 {
240 	if (fRenderer)
241 		fRenderer->Release();
242 	fRenderer = NULL;
243 
244 	BView::DetachedFromWindow();
245 }
246 
247 
248 void
AllDetached()249 BGLView::AllDetached()
250 {
251 	BView::AllDetached();
252 }
253 
254 
255 void
FrameResized(float width,float height)256 BGLView::FrameResized(float width, float height)
257 {
258 	fBounds = Bounds();
259 	for (BView* v = this; v; v = v->Parent())
260 		v->ConvertToParent(&fBounds);
261 
262 	if (fRenderer) {
263 		LockGL();
264 		_LockDraw();
265 		_CallDirectConnected();
266 		fRenderer->FrameResized(width, height);
267 		_UnlockDraw();
268 		UnlockGL();
269 	}
270 
271 	BView::FrameResized(width, height);
272 }
273 
274 
275 status_t
Perform(perform_code d,void * arg)276 BGLView::Perform(perform_code d, void* arg)
277 {
278 	return BView::Perform(d, arg);
279 }
280 
281 
282 status_t
Archive(BMessage * data,bool deep) const283 BGLView::Archive(BMessage* data, bool deep) const
284 {
285 	return BView::Archive(data, deep);
286 }
287 
288 
289 void
MessageReceived(BMessage * msg)290 BGLView::MessageReceived(BMessage* msg)
291 {
292 	BView::MessageReceived(msg);
293 }
294 
295 
296 void
SetResizingMode(uint32 mode)297 BGLView::SetResizingMode(uint32 mode)
298 {
299 	BView::SetResizingMode(mode);
300 }
301 
302 
303 void
GetPreferredSize(float * _width,float * _height)304 BGLView::GetPreferredSize(float* _width, float* _height)
305 {
306 	if (_width)
307 		*_width = 0;
308 	if (_height)
309 		*_height = 0;
310 }
311 
312 
313 void
Show()314 BGLView::Show()
315 {
316 	BView::Show();
317 }
318 
319 
320 void
Hide()321 BGLView::Hide()
322 {
323 	BView::Hide();
324 }
325 
326 
327 BHandler*
ResolveSpecifier(BMessage * msg,int32 index,BMessage * specifier,int32 form,const char * property)328 BGLView::ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier,
329 	int32 form, const char* property)
330 {
331 	return BView::ResolveSpecifier(msg, index, specifier, form, property);
332 }
333 
334 
335 status_t
GetSupportedSuites(BMessage * data)336 BGLView::GetSupportedSuites(BMessage* data)
337 {
338 	return BView::GetSupportedSuites(data);
339 }
340 
341 
342 void
DirectConnected(direct_buffer_info * info)343 BGLView::DirectConnected(direct_buffer_info* info)
344 {
345 	if (fClipInfo == NULL) {
346 		fClipInfo = new (std::nothrow) glview_direct_info();
347 		if (fClipInfo == NULL)
348 			return;
349 	}
350 
351 	direct_buffer_info* localInfo = fClipInfo->direct_info;
352 
353 	switch (info->buffer_state & B_DIRECT_MODE_MASK) {
354 		case B_DIRECT_START:
355 			fClipInfo->direct_connected = true;
356 			memcpy(localInfo, info, DIRECT_BUFFER_INFO_AREA_SIZE);
357 			_UnlockDraw();
358 			break;
359 
360 		case B_DIRECT_MODIFY:
361 			_LockDraw();
362 			memcpy(localInfo, info, DIRECT_BUFFER_INFO_AREA_SIZE);
363 			_UnlockDraw();
364 			break;
365 
366 		case B_DIRECT_STOP:
367 			fClipInfo->direct_connected = false;
368 			_LockDraw();
369 			break;
370 	}
371 
372 	if (fRenderer)
373 		_CallDirectConnected();
374 }
375 
376 
377 void
EnableDirectMode(bool enabled)378 BGLView::EnableDirectMode(bool enabled)
379 {
380 	if (fRenderer)
381 		fRenderer->EnableDirectMode(enabled);
382 	if (fClipInfo == NULL) {
383 		fClipInfo = new (std::nothrow) glview_direct_info();
384 		if (fClipInfo == NULL)
385 			return;
386 	}
387 
388 	fClipInfo->enable_direct_mode = enabled;
389 }
390 
391 
392 void
_LockDraw()393 BGLView::_LockDraw()
394 {
395 	if (!fClipInfo || !fClipInfo->enable_direct_mode)
396 		return;
397 
398 	fDrawLock.Lock();
399 }
400 
401 
402 void
_UnlockDraw()403 BGLView::_UnlockDraw()
404 {
405 	if (!fClipInfo || !fClipInfo->enable_direct_mode)
406 		return;
407 
408 	fDrawLock.Unlock();
409 }
410 
411 
412 void
_CallDirectConnected()413 BGLView::_CallDirectConnected()
414 {
415 	if (!fClipInfo)
416 		return;
417 
418 	direct_buffer_info* localInfo = fClipInfo->direct_info;
419 	direct_buffer_info* info = (direct_buffer_info*)malloc(
420 		DIRECT_BUFFER_INFO_AREA_SIZE);
421 	if (info == NULL)
422 		return;
423 
424 	memcpy(info, localInfo, DIRECT_BUFFER_INFO_AREA_SIZE);
425 
426 	// Collect the rects into a BRegion, then clip to the view's bounds
427 	BRegion region;
428 	for (uint32 c = 0; c < localInfo->clip_list_count; c++)
429 		region.Include(localInfo->clip_list[c]);
430 	BRegion boundsRegion = fBounds.OffsetByCopy(localInfo->window_bounds.left,
431 		localInfo->window_bounds.top);
432 	info->window_bounds = boundsRegion.RectAtInt(0);
433 		// window_bounds are now view bounds
434 	region.IntersectWith(&boundsRegion);
435 
436 	info->clip_list_count = region.CountRects();
437 	info->clip_bounds = region.FrameInt();
438 
439 	for (uint32 c = 0; c < info->clip_list_count; c++)
440 		info->clip_list[c] = region.RectAtInt(c);
441 	fRenderer->DirectConnected(info);
442 	free(info);
443 }
444 
445 
446 //---- virtual reserved methods ----------
447 
448 
_ReservedGLView1()449 void BGLView::_ReservedGLView1() {}
_ReservedGLView2()450 void BGLView::_ReservedGLView2() {}
_ReservedGLView3()451 void BGLView::_ReservedGLView3() {}
_ReservedGLView4()452 void BGLView::_ReservedGLView4() {}
_ReservedGLView5()453 void BGLView::_ReservedGLView5() {}
_ReservedGLView6()454 void BGLView::_ReservedGLView6() {}
_ReservedGLView7()455 void BGLView::_ReservedGLView7() {}
_ReservedGLView8()456 void BGLView::_ReservedGLView8() {}
457 
458 
459 // #pragma mark -
460 
461 
462 // BeOS compatibility: contrary to others BView's contructors,
463 // BGLView one wants a non-const name argument.
BGLView(BRect rect,char * name,ulong resizingMode,ulong mode,ulong options)464 BGLView::BGLView(BRect rect, char* name, ulong resizingMode, ulong mode,
465 	ulong options)
466 	:
467 	BView(rect, name, B_FOLLOW_ALL_SIDES, mode | B_WILL_DRAW | B_FRAME_EVENTS),
468 	fGc(NULL),
469 	fOptions(options),
470 	fDitherCount(0),
471 	fDrawLock("BGLView draw lock"),
472 	fDisplayLock("BGLView display lock"),
473 	fClipInfo(NULL),
474 	fRenderer(NULL),
475 	fRoster(NULL),
476 	fDitherMap(NULL)
477 {
478 	fRoster = new GLRendererRoster(this, options);
479 }
480 
481 
482 #if 0
483 // TODO: implement BGLScreen class...
484 
485 
486 BGLScreen::BGLScreen(char* name, ulong screenMode, ulong options,
487 		status_t* error, bool debug)
488 	:
489 	BWindowScreen(name, screenMode, error, debug)
490 {
491 }
492 
493 
494 BGLScreen::~BGLScreen()
495 {
496 }
497 
498 
499 void
500 BGLScreen::LockGL()
501 {
502 }
503 
504 
505 void
506 BGLScreen::UnlockGL()
507 {
508 }
509 
510 
511 void
512 BGLScreen::SwapBuffers()
513 {
514 }
515 
516 
517 void
518 BGLScreen::ErrorCallback(unsigned long errorCode)
519 {
520 	// Mesa's GLenum is not ulong but uint!
521 	char msg[32];
522 	sprintf(msg, "GL: Error code $%04lx.", errorCode);
523 	// debugger(msg);
524 	fprintf(stderr, "%s\n", msg);
525 	return;
526 }
527 
528 
529 void
530 BGLScreen::ScreenConnected(bool enabled)
531 {
532 }
533 
534 
535 void
536 BGLScreen::FrameResized(float width, float height)
537 {
538 	return BWindowScreen::FrameResized(width, height);
539 }
540 
541 
542 status_t
543 BGLScreen::Perform(perform_code d, void* arg)
544 {
545 	return BWindowScreen::Perform(d, arg);
546 }
547 
548 
549 status_t
550 BGLScreen::Archive(BMessage* data, bool deep) const
551 {
552 	return BWindowScreen::Archive(data, deep);
553 }
554 
555 
556 void
557 BGLScreen::MessageReceived(BMessage* msg)
558 {
559 	BWindowScreen::MessageReceived(msg);
560 }
561 
562 
563 void
564 BGLScreen::Show()
565 {
566 	BWindowScreen::Show();
567 }
568 
569 
570 void
571 BGLScreen::Hide()
572 {
573 	BWindowScreen::Hide();
574 }
575 
576 
577 BHandler*
578 BGLScreen::ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier,
579 	int32 form, const char* property)
580 {
581 	return BWindowScreen::ResolveSpecifier(msg, index, specifier,
582 		form, property);
583 }
584 
585 
586 status_t
587 BGLScreen::GetSupportedSuites(BMessage* data)
588 {
589 	return BWindowScreen::GetSupportedSuites(data);
590 }
591 
592 
593 //---- virtual reserved methods ----------
594 
595 void BGLScreen::_ReservedGLScreen1() {}
596 void BGLScreen::_ReservedGLScreen2() {}
597 void BGLScreen::_ReservedGLScreen3() {}
598 void BGLScreen::_ReservedGLScreen4() {}
599 void BGLScreen::_ReservedGLScreen5() {}
600 void BGLScreen::_ReservedGLScreen6() {}
601 void BGLScreen::_ReservedGLScreen7() {}
602 void BGLScreen::_ReservedGLScreen8() {}
603 #endif
604 
605 
color_space_name(color_space space)606 const char* color_space_name(color_space space)
607 {
608 #define C2N(a)	case a:	return #a
609 
610 	switch (space) {
611 	C2N(B_RGB24);
612 	C2N(B_RGB32);
613 	C2N(B_RGBA32);
614 	C2N(B_RGB32_BIG);
615 	C2N(B_RGBA32_BIG);
616 	C2N(B_GRAY8);
617 	C2N(B_GRAY1);
618 	C2N(B_RGB16);
619 	C2N(B_RGB15);
620 	C2N(B_RGBA15);
621 	C2N(B_CMAP8);
622 	default:
623 		return "Unknown!";
624 	};
625 
626 #undef C2N
627 };
628 
629 
glview_direct_info()630 glview_direct_info::glview_direct_info()
631 {
632 	// TODO: See direct_window_data() in app_server's ServerWindow.cpp
633 	direct_info = (direct_buffer_info*)calloc(1, DIRECT_BUFFER_INFO_AREA_SIZE);
634 	direct_connected = false;
635 	enable_direct_mode = false;
636 }
637 
638 
~glview_direct_info()639 glview_direct_info::~glview_direct_info()
640 {
641 	free(direct_info);
642 }
643 
644