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 }
55
56
~BGLView()57 BGLView::~BGLView()
58 {
59 delete fClipInfo;
60 if (fRenderer)
61 fRenderer->Release();
62 }
63
64
65 void
LockGL()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
UnlockGL()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
SwapBuffers()88 BGLView::SwapBuffers()
89 {
90 SwapBuffers(false);
91 }
92
93
94 void
SwapBuffers(bool vSync)95 BGLView::SwapBuffers(bool vSync)
96 {
97 if (fRenderer) {
98 _LockDraw();
99 fRenderer->SwapBuffers(vSync);
100 _UnlockDraw();
101 }
102 }
103
104
105 BView*
EmbeddedView()106 BGLView::EmbeddedView()
107 {
108 return NULL;
109 }
110
111
112 void*
GetGLProcAddress(const char * procName)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
CopyPixelsOut(BPoint source,BBitmap * dest)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
CopyPixelsIn(BBitmap * source,BPoint dest)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
ErrorCallback(unsigned long errorCode)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
Draw(BRect updateRect)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
AttachedToWindow()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
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