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 28struct 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 38BGLView::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 57BGLView::~BGLView() 58{ 59 delete fClipInfo; 60 if (fRenderer) 61 fRenderer->Release(); 62} 63 64 65void 66BGLView::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 76void 77BGLView::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 87void 88BGLView::SwapBuffers() 89{ 90 SwapBuffers(false); 91} 92 93 94void 95BGLView::SwapBuffers(bool vSync) 96{ 97 if (fRenderer) { 98 _LockDraw(); 99 fRenderer->SwapBuffers(vSync); 100 _UnlockDraw(); 101 } 102} 103 104 105BView* 106BGLView::EmbeddedView() 107{ 108 return NULL; 109} 110 111 112void* 113BGLView::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 127status_t 128BGLView::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 140status_t 141BGLView::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 */ 158void 159BGLView::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 168void 169BGLView::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 183void 184BGLView::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 230void 231BGLView::AllAttached() 232{ 233 BView::AllAttached(); 234} 235 236 237void 238BGLView::DetachedFromWindow() 239{ 240 if (fRenderer) 241 fRenderer->Release(); 242 fRenderer = NULL; 243 244 BView::DetachedFromWindow(); 245} 246 247 248void 249BGLView::AllDetached() 250{ 251 BView::AllDetached(); 252} 253 254 255void 256BGLView::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 275status_t 276BGLView::Perform(perform_code d, void* arg) 277{ 278 return BView::Perform(d, arg); 279} 280 281 282status_t 283BGLView::Archive(BMessage* data, bool deep) const 284{ 285 return BView::Archive(data, deep); 286} 287 288 289void 290BGLView::MessageReceived(BMessage* msg) 291{ 292 BView::MessageReceived(msg); 293} 294 295 296void 297BGLView::SetResizingMode(uint32 mode) 298{ 299 BView::SetResizingMode(mode); 300} 301 302 303void 304BGLView::GetPreferredSize(float* _width, float* _height) 305{ 306 if (_width) 307 *_width = 0; 308 if (_height) 309 *_height = 0; 310} 311 312 313void 314BGLView::Show() 315{ 316 BView::Show(); 317} 318 319 320void 321BGLView::Hide() 322{ 323 BView::Hide(); 324} 325 326 327BHandler* 328BGLView::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 335status_t 336BGLView::GetSupportedSuites(BMessage* data) 337{ 338 return BView::GetSupportedSuites(data); 339} 340 341 342void 343BGLView::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 377void 378BGLView::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 392void 393BGLView::_LockDraw() 394{ 395 if (!fClipInfo || !fClipInfo->enable_direct_mode) 396 return; 397 398 fDrawLock.Lock(); 399} 400 401 402void 403BGLView::_UnlockDraw() 404{ 405 if (!fClipInfo || !fClipInfo->enable_direct_mode) 406 return; 407 408 fDrawLock.Unlock(); 409} 410 411 412void 413BGLView::_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 449void BGLView::_ReservedGLView1() {} 450void BGLView::_ReservedGLView2() {} 451void BGLView::_ReservedGLView3() {} 452void BGLView::_ReservedGLView4() {} 453void BGLView::_ReservedGLView5() {} 454void BGLView::_ReservedGLView6() {} 455void BGLView::_ReservedGLView7() {} 456void 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. 464BGLView::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 486BGLScreen::BGLScreen(char* name, ulong screenMode, ulong options, 487 status_t* error, bool debug) 488 : 489 BWindowScreen(name, screenMode, error, debug) 490{ 491} 492 493 494BGLScreen::~BGLScreen() 495{ 496} 497 498 499void 500BGLScreen::LockGL() 501{ 502} 503 504 505void 506BGLScreen::UnlockGL() 507{ 508} 509 510 511void 512BGLScreen::SwapBuffers() 513{ 514} 515 516 517void 518BGLScreen::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 529void 530BGLScreen::ScreenConnected(bool enabled) 531{ 532} 533 534 535void 536BGLScreen::FrameResized(float width, float height) 537{ 538 return BWindowScreen::FrameResized(width, height); 539} 540 541 542status_t 543BGLScreen::Perform(perform_code d, void* arg) 544{ 545 return BWindowScreen::Perform(d, arg); 546} 547 548 549status_t 550BGLScreen::Archive(BMessage* data, bool deep) const 551{ 552 return BWindowScreen::Archive(data, deep); 553} 554 555 556void 557BGLScreen::MessageReceived(BMessage* msg) 558{ 559 BWindowScreen::MessageReceived(msg); 560} 561 562 563void 564BGLScreen::Show() 565{ 566 BWindowScreen::Show(); 567} 568 569 570void 571BGLScreen::Hide() 572{ 573 BWindowScreen::Hide(); 574} 575 576 577BHandler* 578BGLScreen::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 586status_t 587BGLScreen::GetSupportedSuites(BMessage* data) 588{ 589 return BWindowScreen::GetSupportedSuites(data); 590} 591 592 593//---- virtual reserved methods ---------- 594 595void BGLScreen::_ReservedGLScreen1() {} 596void BGLScreen::_ReservedGLScreen2() {} 597void BGLScreen::_ReservedGLScreen3() {} 598void BGLScreen::_ReservedGLScreen4() {} 599void BGLScreen::_ReservedGLScreen5() {} 600void BGLScreen::_ReservedGLScreen6() {} 601void BGLScreen::_ReservedGLScreen7() {} 602void BGLScreen::_ReservedGLScreen8() {} 603#endif 604 605 606const 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 630glview_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 639glview_direct_info::~glview_direct_info() 640{ 641 free(direct_info); 642} 643 644