Home | History | Annotate | Download | only in hgl
      1 /*
      2  * Copyright 2006-2012, Haiku. All rights reserved.
      3  * Distributed under the terms of the MIT License.
      4  *
      5  * Authors:
      6  *		Jrme Duval, korli (at) users.berlios.de
      7  *		Philippe Houdoin, philippe.houdoin (at) free.fr
      8  *		Stefano Ceccherini, burton666 (at) 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 
     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 }
     55 
     56 
     57 BGLView::~BGLView()
     58 {
     59 	delete fClipInfo;
     60 	if (fRenderer)
     61 		fRenderer->Release();
     62 }
     63 
     64 
     65 void
     66 BGLView::LockGL()
     67 {
     68 	// TODO: acquire the OpenGL API lock it on this glview
     69 
     70 	fDisplayLock.Lock();
     71 	if (fRenderer)
     72 		fRenderer->LockGL();
     73 }
     74 
     75 
     76 void
     77 BGLView::UnlockGL()
     78 {
     79 	if (fRenderer)
     80 		fRenderer->UnlockGL();
     81 	fDisplayLock.Unlock();
     82 
     83 	// TODO: release the GL API lock to others glviews
     84 }
     85 
     86 
     87 void
     88 BGLView::SwapBuffers()
     89 {
     90 	SwapBuffers(false);
     91 }
     92 
     93 
     94 void
     95 BGLView::SwapBuffers(bool vSync)
     96 {
     97 	if (fRenderer) {
     98 		_LockDraw();
     99 		fRenderer->SwapBuffers(vSync);
    100 		_UnlockDraw();
    101 	}
    102 }
    103 
    104 
    105 BView*
    106 BGLView::EmbeddedView()
    107 {
    108 	return NULL;
    109 }
    110 
    111 
    112 void*
    113 BGLView::GetGLProcAddress(const char* procName)
    114 {
    115 	BGLDispatcher* glDispatcher = NULL;
    116 
    117 	if (fRenderer)
    118 		glDispatcher = fRenderer->GLDispatcher();
    119 
    120 	if (glDispatcher)
    121 		return (void*)glDispatcher->AddressOf(procName);
    122 
    123 	return NULL;
    124 }
    125 
    126 
    127 status_t
    128 BGLView::CopyPixelsOut(BPoint source, BBitmap* dest)
    129 {
    130 	if (!fRenderer)
    131 		return B_ERROR;
    132 
    133 	if (!dest || !dest->Bounds().IsValid())
    134 		return B_BAD_VALUE;
    135 
    136 	return fRenderer->CopyPixelsOut(source, dest);
    137 }
    138 
    139 
    140 status_t
    141 BGLView::CopyPixelsIn(BBitmap* source, BPoint dest)
    142 {
    143 	if (!fRenderer)
    144 		return B_ERROR;
    145 
    146 	if (!source || !source->Bounds().IsValid())
    147 		return B_BAD_VALUE;
    148 
    149 	return fRenderer->CopyPixelsIn(source, dest);
    150 }
    151 
    152 
    153 /*!	Mesa's GLenum is not ulong but uint, so we can't use GLenum
    154 	without breaking this method signature.
    155 	Instead, we have to use the effective BeOS's SGI OpenGL GLenum type:
    156 	unsigned long.
    157  */
    158 void
    159 BGLView::ErrorCallback(unsigned long errorCode)
    160 {
    161 	char msg[32];
    162 	sprintf(msg, "GL: Error code $%04lx.", errorCode);
    163 	// TODO: under BeOS R5, it call debugger(msg);
    164 	fprintf(stderr, "%s\n", msg);
    165 }
    166 
    167 
    168 void
    169 BGLView::Draw(BRect updateRect)
    170 {
    171 	if (fRenderer) {
    172 		_LockDraw();
    173 		fRenderer->Draw(updateRect);
    174 		_UnlockDraw();
    175 		return;
    176 	}
    177 	// TODO: auto-size and center the string
    178 	MovePenTo(8, 32);
    179 	DrawString("No OpenGL renderer available!");
    180 }
    181 
    182 
    183 void
    184 BGLView::AttachedToWindow()
    185 {
    186 	BView::AttachedToWindow();
    187 
    188 	fBounds = Bounds();
    189 	for (BView* view = this; view != NULL; view = view->Parent())
    190 		view->ConvertToParent(&fBounds);
    191 
    192 	fRenderer = fRoster->GetRenderer();
    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
    231 BGLView::AllAttached()
    232 {
    233 	BView::AllAttached();
    234 }
    235 
    236 
    237 void
    238 BGLView::DetachedFromWindow()
    239 {
    240 	if (fRenderer)
    241 		fRenderer->Release();
    242 	fRenderer = NULL;
    243 
    244 	BView::DetachedFromWindow();
    245 }
    246 
    247 
    248 void
    249 BGLView::AllDetached()
    250 {
    251 	BView::AllDetached();
    252 }
    253 
    254 
    255 void
    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
    276 BGLView::Perform(perform_code d, void* arg)
    277 {
    278 	return BView::Perform(d, arg);
    279 }
    280 
    281 
    282 status_t
    283 BGLView::Archive(BMessage* data, bool deep) const
    284 {
    285 	return BView::Archive(data, deep);
    286 }
    287 
    288 
    289 void
    290 BGLView::MessageReceived(BMessage* msg)
    291 {
    292 	BView::MessageReceived(msg);
    293 }
    294 
    295 
    296 void
    297 BGLView::SetResizingMode(uint32 mode)
    298 {
    299 	BView::SetResizingMode(mode);
    300 }
    301 
    302 
    303 void
    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
    314 BGLView::Show()
    315 {
    316 	BView::Show();
    317 }
    318 
    319 
    320 void
    321 BGLView::Hide()
    322 {
    323 	BView::Hide();
    324 }
    325 
    326 
    327 BHandler*
    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
    336 BGLView::GetSupportedSuites(BMessage* data)
    337 {
    338 	return BView::GetSupportedSuites(data);
    339 }
    340 
    341 
    342 void
    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
    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
    393 BGLView::_LockDraw()
    394 {
    395 	if (!fClipInfo || !fClipInfo->enable_direct_mode)
    396 		return;
    397 
    398 	fDrawLock.Lock();
    399 }
    400 
    401 
    402 void
    403 BGLView::_UnlockDraw()
    404 {
    405 	if (!fClipInfo || !fClipInfo->enable_direct_mode)
    406 		return;
    407 
    408 	fDrawLock.Unlock();
    409 }
    410 
    411 
    412 void
    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 
    449 void BGLView::_ReservedGLView1() {}
    450 void BGLView::_ReservedGLView2() {}
    451 void BGLView::_ReservedGLView3() {}
    452 void BGLView::_ReservedGLView4() {}
    453 void BGLView::_ReservedGLView5() {}
    454 void BGLView::_ReservedGLView6() {}
    455 void BGLView::_ReservedGLView7() {}
    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.
    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 
    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 
    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 
    639 glview_direct_info::~glview_direct_info()
    640 {
    641 	free(direct_info);
    642 }
    643 
    644