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