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