blob: 9ae5b5c83ac9cef6db555b5e9e45509954d3d052 [file] [log] [blame]
Alexander von Gluck IVc9f12172013-10-01 21:03:48 +00001/*
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