summaryrefslogtreecommitdiffstats
path: root/src/hgl/GLView.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/hgl/GLView.cpp')
-rw-r--r--src/hgl/GLView.cpp643
1 files changed, 643 insertions, 0 deletions
diff --git a/src/hgl/GLView.cpp b/src/hgl/GLView.cpp
new file mode 100644
index 00000000000..9ae5b5c83ac
--- /dev/null
+++ b/src/hgl/GLView.cpp
@@ -0,0 +1,643 @@
+/*
+ * Copyright 2006-2012, Haiku. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ * Jérôme Duval, [email protected]
+ * Philippe Houdoin, [email protected]
+ * Stefano Ceccherini, [email protected]
+ */
+
+#include <kernel/image.h>
+
+#include <GLView.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <DirectWindow.h>
+#include <GLRenderer.h>
+
+#include "interface/DirectWindowPrivate.h"
+#include "GLDispatcher.h"
+#include "GLRendererRoster.h"
+
+
+struct glview_direct_info {
+ direct_buffer_info* direct_info;
+ bool direct_connected;
+ bool enable_direct_mode;
+
+ glview_direct_info();
+ ~glview_direct_info();
+};
+
+
+BGLView::BGLView(BRect rect, const char* name, ulong resizingMode, ulong mode,
+ ulong options)
+ :
+ BView(rect, name, B_FOLLOW_ALL_SIDES, mode | B_WILL_DRAW | B_FRAME_EVENTS),
+ // | B_FULL_UPDATE_ON_RESIZE)
+ fGc(NULL),
+ fOptions(options),
+ fDitherCount(0),
+ fDrawLock("BGLView draw lock"),
+ fDisplayLock("BGLView display lock"),
+ fClipInfo(NULL),
+ fRenderer(NULL),
+ fRoster(NULL),
+ fDitherMap(NULL)
+{
+ fRoster = new GLRendererRoster(this, options);
+}
+
+
+BGLView::~BGLView()
+{
+ delete fClipInfo;
+ if (fRenderer)
+ fRenderer->Release();
+}
+
+
+void
+BGLView::LockGL()
+{
+ // TODO: acquire the OpenGL API lock it on this glview
+
+ fDisplayLock.Lock();
+ if (fRenderer)
+ fRenderer->LockGL();
+}
+
+
+void
+BGLView::UnlockGL()
+{
+ if (fRenderer)
+ fRenderer->UnlockGL();
+ fDisplayLock.Unlock();
+
+ // TODO: release the GL API lock to others glviews
+}
+
+
+void
+BGLView::SwapBuffers()
+{
+ SwapBuffers(false);
+}
+
+
+void
+BGLView::SwapBuffers(bool vSync)
+{
+ if (fRenderer) {
+ _LockDraw();
+ fRenderer->SwapBuffers(vSync);
+ _UnlockDraw();
+ }
+}
+
+
+BView*
+BGLView::EmbeddedView()
+{
+ return NULL;
+}
+
+
+void*
+BGLView::GetGLProcAddress(const char* procName)
+{
+ BGLDispatcher* glDispatcher = NULL;
+
+ if (fRenderer)
+ glDispatcher = fRenderer->GLDispatcher();
+
+ if (glDispatcher)
+ return (void*)glDispatcher->AddressOf(procName);
+
+ return NULL;
+}
+
+
+status_t
+BGLView::CopyPixelsOut(BPoint source, BBitmap* dest)
+{
+ if (!fRenderer)
+ return B_ERROR;
+
+ if (!dest || !dest->Bounds().IsValid())
+ return B_BAD_VALUE;
+
+ return fRenderer->CopyPixelsOut(source, dest);
+}
+
+
+status_t
+BGLView::CopyPixelsIn(BBitmap* source, BPoint dest)
+{
+ if (!fRenderer)
+ return B_ERROR;
+
+ if (!source || !source->Bounds().IsValid())
+ return B_BAD_VALUE;
+
+ return fRenderer->CopyPixelsIn(source, dest);
+}
+
+
+/*! Mesa's GLenum is not ulong but uint, so we can't use GLenum
+ without breaking this method signature.
+ Instead, we have to use the effective BeOS's SGI OpenGL GLenum type:
+ unsigned long.
+ */
+void
+BGLView::ErrorCallback(unsigned long errorCode)
+{
+ char msg[32];
+ sprintf(msg, "GL: Error code $%04lx.", errorCode);
+ // TODO: under BeOS R5, it call debugger(msg);
+ fprintf(stderr, "%s\n", msg);
+}
+
+
+void
+BGLView::Draw(BRect updateRect)
+{
+ if (fRenderer) {
+ _LockDraw();
+ fRenderer->Draw(updateRect);
+ _UnlockDraw();
+ return;
+ }
+ // TODO: auto-size and center the string
+ MovePenTo(8, 32);
+ DrawString("No OpenGL renderer available!");
+}
+
+
+void
+BGLView::AttachedToWindow()
+{
+ BView::AttachedToWindow();
+
+ fBounds = Bounds();
+ for (BView* view = this; view != NULL; view = view->Parent())
+ view->ConvertToParent(&fBounds);
+
+ fRenderer = fRoster->GetRenderer();
+ if (fRenderer != NULL) {
+ // Jackburton: The following code was commented because it doesn't look
+ // good in "direct" mode:
+ // when the window is moved, the app_server doesn't paint the view's
+ // background, and the stuff behind the window itself shows up.
+ // Setting the view color to black, instead, looks a bit more elegant.
+#if 0
+ // Don't paint white window background when resized
+ SetViewColor(B_TRANSPARENT_32_BIT);
+#else
+ SetViewColor(0, 0, 0);
+#endif
+
+ // Set default OpenGL viewport:
+ LockGL();
+ glViewport(0, 0, Bounds().IntegerWidth(), Bounds().IntegerHeight());
+ UnlockGL();
+ fRenderer->FrameResized(Bounds().IntegerWidth(),
+ Bounds().IntegerHeight());
+
+ if (fClipInfo) {
+ fRenderer->DirectConnected(fClipInfo->direct_info);
+ fRenderer->EnableDirectMode(fClipInfo->enable_direct_mode);
+ }
+
+ return;
+ }
+
+ fprintf(stderr, "no renderer found! \n");
+
+ // No Renderer, no rendering. Setup a minimal "No Renderer" string drawing
+ // context
+ SetFont(be_bold_font);
+ // SetFontSize(16);
+}
+
+
+void
+BGLView::AllAttached()
+{
+ BView::AllAttached();
+}
+
+
+void
+BGLView::DetachedFromWindow()
+{
+ if (fRenderer)
+ fRenderer->Release();
+ fRenderer = NULL;
+
+ BView::DetachedFromWindow();
+}
+
+
+void
+BGLView::AllDetached()
+{
+ BView::AllDetached();
+}
+
+
+void
+BGLView::FrameResized(float width, float height)
+{
+ fBounds = Bounds();
+ for (BView* v = this; v; v = v->Parent())
+ v->ConvertToParent(&fBounds);
+
+ if (fRenderer) {
+ LockGL();
+ _LockDraw();
+ _CallDirectConnected();
+ fRenderer->FrameResized(width, height);
+ _UnlockDraw();
+ UnlockGL();
+ }
+
+ BView::FrameResized(width, height);
+}
+
+
+status_t
+BGLView::Perform(perform_code d, void* arg)
+{
+ return BView::Perform(d, arg);
+}
+
+
+status_t
+BGLView::Archive(BMessage* data, bool deep) const
+{
+ return BView::Archive(data, deep);
+}
+
+
+void
+BGLView::MessageReceived(BMessage* msg)
+{
+ BView::MessageReceived(msg);
+}
+
+
+void
+BGLView::SetResizingMode(uint32 mode)
+{
+ BView::SetResizingMode(mode);
+}
+
+
+void
+BGLView::GetPreferredSize(float* _width, float* _height)
+{
+ if (_width)
+ *_width = 0;
+ if (_height)
+ *_height = 0;
+}
+
+
+void
+BGLView::Show()
+{
+ BView::Show();
+}
+
+
+void
+BGLView::Hide()
+{
+ BView::Hide();
+}
+
+
+BHandler*
+BGLView::ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier,
+ int32 form, const char* property)
+{
+ return BView::ResolveSpecifier(msg, index, specifier, form, property);
+}
+
+
+status_t
+BGLView::GetSupportedSuites(BMessage* data)
+{
+ return BView::GetSupportedSuites(data);
+}
+
+
+void
+BGLView::DirectConnected(direct_buffer_info* info)
+{
+ if (fClipInfo == NULL) {
+ fClipInfo = new (std::nothrow) glview_direct_info();
+ if (fClipInfo == NULL)
+ return;
+ }
+
+ direct_buffer_info* localInfo = fClipInfo->direct_info;
+
+ switch (info->buffer_state & B_DIRECT_MODE_MASK) {
+ case B_DIRECT_START:
+ fClipInfo->direct_connected = true;
+ memcpy(localInfo, info, DIRECT_BUFFER_INFO_AREA_SIZE);
+ _UnlockDraw();
+ break;
+
+ case B_DIRECT_MODIFY:
+ _LockDraw();
+ memcpy(localInfo, info, DIRECT_BUFFER_INFO_AREA_SIZE);
+ _UnlockDraw();
+ break;
+
+ case B_DIRECT_STOP:
+ fClipInfo->direct_connected = false;
+ _LockDraw();
+ break;
+ }
+
+ if (fRenderer)
+ _CallDirectConnected();
+}
+
+
+void
+BGLView::EnableDirectMode(bool enabled)
+{
+ if (fRenderer)
+ fRenderer->EnableDirectMode(enabled);
+ if (fClipInfo == NULL) {
+ fClipInfo = new (std::nothrow) glview_direct_info();
+ if (fClipInfo == NULL)
+ return;
+ }
+
+ fClipInfo->enable_direct_mode = enabled;
+}
+
+
+void
+BGLView::_LockDraw()
+{
+ if (!fClipInfo || !fClipInfo->enable_direct_mode)
+ return;
+
+ fDrawLock.Lock();
+}
+
+
+void
+BGLView::_UnlockDraw()
+{
+ if (!fClipInfo || !fClipInfo->enable_direct_mode)
+ return;
+
+ fDrawLock.Unlock();
+}
+
+
+void
+BGLView::_CallDirectConnected()
+{
+ if (!fClipInfo)
+ return;
+
+ direct_buffer_info* localInfo = fClipInfo->direct_info;
+ direct_buffer_info* info = (direct_buffer_info*)malloc(
+ DIRECT_BUFFER_INFO_AREA_SIZE);
+ if (info == NULL)
+ return;
+
+ memcpy(info, localInfo, DIRECT_BUFFER_INFO_AREA_SIZE);
+
+ // Collect the rects into a BRegion, then clip to the view's bounds
+ BRegion region;
+ for (uint32 c = 0; c < localInfo->clip_list_count; c++)
+ region.Include(localInfo->clip_list[c]);
+ BRegion boundsRegion = fBounds.OffsetByCopy(localInfo->window_bounds.left,
+ localInfo->window_bounds.top);
+ info->window_bounds = boundsRegion.RectAtInt(0);
+ // window_bounds are now view bounds
+ region.IntersectWith(&boundsRegion);
+
+ info->clip_list_count = region.CountRects();
+ info->clip_bounds = region.FrameInt();
+
+ for (uint32 c = 0; c < info->clip_list_count; c++)
+ info->clip_list[c] = region.RectAtInt(c);
+ fRenderer->DirectConnected(info);
+ free(info);
+}
+
+
+//---- virtual reserved methods ----------
+
+
+void BGLView::_ReservedGLView1() {}
+void BGLView::_ReservedGLView2() {}
+void BGLView::_ReservedGLView3() {}
+void BGLView::_ReservedGLView4() {}
+void BGLView::_ReservedGLView5() {}
+void BGLView::_ReservedGLView6() {}
+void BGLView::_ReservedGLView7() {}
+void BGLView::_ReservedGLView8() {}
+
+
+// #pragma mark -
+
+
+// BeOS compatibility: contrary to others BView's contructors,
+// BGLView one wants a non-const name argument.
+BGLView::BGLView(BRect rect, char* name, ulong resizingMode, ulong mode,
+ ulong options)
+ :
+ BView(rect, name, B_FOLLOW_ALL_SIDES, mode | B_WILL_DRAW | B_FRAME_EVENTS),
+ fGc(NULL),
+ fOptions(options),
+ fDitherCount(0),
+ fDrawLock("BGLView draw lock"),
+ fDisplayLock("BGLView display lock"),
+ fClipInfo(NULL),
+ fRenderer(NULL),
+ fRoster(NULL),
+ fDitherMap(NULL)
+{
+ fRoster = new GLRendererRoster(this, options);
+}
+
+
+#if 0
+// TODO: implement BGLScreen class...
+
+
+BGLScreen::BGLScreen(char* name, ulong screenMode, ulong options,
+ status_t* error, bool debug)
+ :
+ BWindowScreen(name, screenMode, error, debug)
+{
+}
+
+
+BGLScreen::~BGLScreen()
+{
+}
+
+
+void
+BGLScreen::LockGL()
+{
+}
+
+
+void
+BGLScreen::UnlockGL()
+{
+}
+
+
+void
+BGLScreen::SwapBuffers()
+{
+}
+
+
+void
+BGLScreen::ErrorCallback(unsigned long errorCode)
+{
+ // Mesa's GLenum is not ulong but uint!
+ char msg[32];
+ sprintf(msg, "GL: Error code $%04lx.", errorCode);
+ // debugger(msg);
+ fprintf(stderr, "%s\n", msg);
+ return;
+}
+
+
+void
+BGLScreen::ScreenConnected(bool enabled)
+{
+}
+
+
+void
+BGLScreen::FrameResized(float width, float height)
+{
+ return BWindowScreen::FrameResized(width, height);
+}
+
+
+status_t
+BGLScreen::Perform(perform_code d, void* arg)
+{
+ return BWindowScreen::Perform(d, arg);
+}
+
+
+status_t
+BGLScreen::Archive(BMessage* data, bool deep) const
+{
+ return BWindowScreen::Archive(data, deep);
+}
+
+
+void
+BGLScreen::MessageReceived(BMessage* msg)
+{
+ BWindowScreen::MessageReceived(msg);
+}
+
+
+void
+BGLScreen::Show()
+{
+ BWindowScreen::Show();
+}
+
+
+void
+BGLScreen::Hide()
+{
+ BWindowScreen::Hide();
+}
+
+
+BHandler*
+BGLScreen::ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier,
+ int32 form, const char* property)
+{
+ return BWindowScreen::ResolveSpecifier(msg, index, specifier,
+ form, property);
+}
+
+
+status_t
+BGLScreen::GetSupportedSuites(BMessage* data)
+{
+ return BWindowScreen::GetSupportedSuites(data);
+}
+
+
+//---- virtual reserved methods ----------
+
+void BGLScreen::_ReservedGLScreen1() {}
+void BGLScreen::_ReservedGLScreen2() {}
+void BGLScreen::_ReservedGLScreen3() {}
+void BGLScreen::_ReservedGLScreen4() {}
+void BGLScreen::_ReservedGLScreen5() {}
+void BGLScreen::_ReservedGLScreen6() {}
+void BGLScreen::_ReservedGLScreen7() {}
+void BGLScreen::_ReservedGLScreen8() {}
+#endif
+
+
+const char* color_space_name(color_space space)
+{
+#define C2N(a) case a: return #a
+
+ switch (space) {
+ C2N(B_RGB24);
+ C2N(B_RGB32);
+ C2N(B_RGBA32);
+ C2N(B_RGB32_BIG);
+ C2N(B_RGBA32_BIG);
+ C2N(B_GRAY8);
+ C2N(B_GRAY1);
+ C2N(B_RGB16);
+ C2N(B_RGB15);
+ C2N(B_RGBA15);
+ C2N(B_CMAP8);
+ default:
+ return "Unknown!";
+ };
+
+#undef C2N
+};
+
+
+glview_direct_info::glview_direct_info()
+{
+ // TODO: See direct_window_data() in app_server's ServerWindow.cpp
+ direct_info = (direct_buffer_info*)calloc(1, DIRECT_BUFFER_INFO_AREA_SIZE);
+ direct_connected = false;
+ enable_direct_mode = false;
+}
+
+
+glview_direct_info::~glview_direct_info()
+{
+ free(direct_info);
+}
+