diff options
Diffstat (limited to 'src/hgl/GLView.cpp')
-rw-r--r-- | src/hgl/GLView.cpp | 643 |
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); +} + |