+ // XXX no-op ???
+}
+
+/* Direct Window stuff */
+void BGLView::drawScanline( int x1, int x2, int y, void *data )
+{
+ // no-op
+}
+
+void BGLView::scanlineHandler(struct rasStateRec *state,
+ GLint x1, GLint x2)
+{
+ // no-op
+}
+
+void BGLView::lock_draw()
+{
+ // no-op
+}
+
+void BGLView::unlock_draw()
+{
+ // no-op
+}
+
+bool BGLView::validateView()
+{
+ // no-op
+ return true;
+}
+
+// #pragma mark -
+
+MesaDriver::MesaDriver()
+{
+ m_glcontext = NULL;
+ m_glvisual = NULL;
+ m_glframebuffer = NULL;
+ m_bglview = NULL;
+ m_bitmap = NULL;
+
+ m_clear_color[BE_RCOMP] = 0;
+ m_clear_color[BE_GCOMP] = 0;
+ m_clear_color[BE_BCOMP] = 0;
+ m_clear_color[BE_ACOMP] = 0;
+
+ m_clear_index = 0;
+}
+
+
+MesaDriver::~MesaDriver()
+{
+ _mesa_destroy_visual(m_glvisual);
+ _mesa_destroy_framebuffer(m_glframebuffer);
+ _mesa_destroy_context(m_glcontext);
+
+ delete m_bitmap;
+}
+
+
+void MesaDriver::Init(BGLView * bglview, GLcontext * ctx, GLvisual * visual, GLframebuffer * framebuffer)
+{
+ m_bglview = bglview;
+ m_glcontext = ctx;
+ m_glvisual = visual;
+ m_glframebuffer = framebuffer;
+
+ MesaDriver * md = (MesaDriver *) ctx->DriverCtx;
+ struct swrast_device_driver * swdd = _swrast_GetDeviceDriverReference( ctx );
+ TNLcontext * tnl = TNL_CONTEXT(ctx);
+
+ assert(md->m_glcontext == ctx );
+ assert(tnl);
+ assert(swdd);
+
+ // Use default TCL pipeline
+ tnl->Driver.RunPipeline = _tnl_run_pipeline;
+
+ swdd->SetBuffer = this->SetBuffer;
+}
+
+
+void MesaDriver::LockGL()
+{
+ m_bglview->LockLooper();
+
+ UpdateState(m_glcontext, 0);
+ _mesa_make_current(m_glcontext, m_glframebuffer);
+}
+
+
+void MesaDriver::UnlockGL()
+{
+ if (m_bglview->Looper()->IsLocked())
+ m_bglview->UnlockLooper();
+ // Could call _mesa_make_current(NULL, NULL) but it would just
+ // hinder performance
+}
+
+
+void MesaDriver::SwapBuffers() const
+{
+ _mesa_notifySwapBuffers(m_glcontext);
+
+ if (m_bitmap) {
+ m_bglview->LockLooper();
+ m_bglview->DrawBitmap(m_bitmap);
+ m_bglview->UnlockLooper();
+ };
+}
+
+
+void MesaDriver::CopySubBuffer(GLint x, GLint y, GLuint width, GLuint height) const
+{
+ if (m_bitmap) {
+ // Source bitmap and view's bitmap are same size.
+ // Source and dest rectangle are the same.
+ // Note (x,y) = (0,0) is the lower-left corner, have to flip Y
+ BRect srcAndDest;
+ srcAndDest.left = x;
+ srcAndDest.right = x + width - 1;
+ srcAndDest.bottom = m_bottom - y;
+ srcAndDest.top = srcAndDest.bottom - height + 1;
+ m_bglview->DrawBitmap(m_bitmap, srcAndDest, srcAndDest);
+ }
+}
+
+status_t MesaDriver::CopyPixelsOut(BPoint location, BBitmap *bitmap)
+{
+ color_space scs = m_bitmap->ColorSpace();
+ color_space dcs = bitmap->ColorSpace();
+
+ if (scs != dcs && (scs != B_RGBA32 || dcs != B_RGB32)) {
+ printf("CopyPixelsOut(): incompatible color space: %s != %s\n",
+ color_space_name(scs),
+ color_space_name(dcs));
+ return B_BAD_TYPE;
+ }
+
+ // debugger("CopyPixelsOut()");
+
+ BRect sr = m_bitmap->Bounds();
+ BRect dr = bitmap->Bounds();
+
+ sr = sr & dr.OffsetBySelf(location);
+ dr = sr.OffsetByCopy(-location.x, -location.y);
+
+ uint8 *ps = (uint8 *) m_bitmap->Bits();
+ uint8 *pd = (uint8 *) bitmap->Bits();
+ uint32 *s, *d;
+ uint32 y;
+ for (y = (uint32) sr.top; y <= (uint32) sr.bottom; y++) {
+ s = (uint32 *) (ps + y * m_bitmap->BytesPerRow());
+ s += (uint32) sr.left;
+
+ d = (uint32 *) (pd + (y + (uint32) (dr.top - sr.top)) * bitmap->BytesPerRow());
+ d += (uint32) dr.left;
+
+ memcpy(d, s, dr.IntegerWidth() * 4);
+ }
+ return B_OK;
+}
+
+status_t MesaDriver::CopyPixelsIn(BBitmap *bitmap, BPoint location)
+{
+ color_space scs = bitmap->ColorSpace();
+ color_space dcs = m_bitmap->ColorSpace();
+
+ if (scs != dcs && (dcs != B_RGBA32 || scs != B_RGB32)) {
+ printf("CopyPixelsIn(): incompatible color space: %s != %s\n",
+ color_space_name(scs),
+ color_space_name(dcs));
+ return B_BAD_TYPE;
+ }
+
+ // debugger("CopyPixelsIn()");
+
+ BRect sr = bitmap->Bounds();
+ BRect dr = m_bitmap->Bounds();
+
+ sr = sr & dr.OffsetBySelf(location);
+ dr = sr.OffsetByCopy(-location.x, -location.y);
+
+ uint8 *ps = (uint8 *) bitmap->Bits();
+ uint8 *pd = (uint8 *) m_bitmap->Bits();
+ uint32 *s, *d;
+ uint32 y;
+ for (y = (uint32) sr.top; y <= (uint32) sr.bottom; y++) {
+ s = (uint32 *) (ps + y * bitmap->BytesPerRow());
+ s += (uint32) sr.left;
+
+ d = (uint32 *) (pd + (y + (uint32) (dr.top - sr.top)) * m_bitmap->BytesPerRow());
+ d += (uint32) dr.left;
+
+ memcpy(d, s, dr.IntegerWidth() * 4);
+ }
+ return B_OK;
+}
+
+
+void MesaDriver::Draw(BRect updateRect) const
+{
+ if (m_bitmap)
+ m_bglview->DrawBitmap(m_bitmap, updateRect, updateRect);
+}
+
+
+void MesaDriver::Error(GLcontext *ctx)
+{
+ MesaDriver *md = (MesaDriver *) ctx->DriverCtx;
+ if (md && md->m_bglview)
+ md->m_bglview->ErrorCallback((unsigned long) ctx->ErrorValue);
+}
+
+void MesaDriver::UpdateState( GLcontext *ctx, GLuint new_state )
+{
+ struct swrast_device_driver * swdd = _swrast_GetDeviceDriverReference( ctx );
+
+ _swrast_InvalidateState( ctx, new_state );
+ _swsetup_InvalidateState( ctx, new_state );
+ _ac_InvalidateState( ctx, new_state );
+ _tnl_InvalidateState( ctx, new_state );
+
+ if (ctx->Color.DrawBuffer[0] == GL_FRONT) {
+ /* read/write front buffer */
+ swdd->WriteRGBASpan = MesaDriver::WriteRGBASpanFront;
+ swdd->WriteRGBSpan = MesaDriver::WriteRGBSpanFront;
+ swdd->WriteRGBAPixels = MesaDriver::WriteRGBAPixelsFront;
+ swdd->WriteMonoRGBASpan = MesaDriver::WriteMonoRGBASpanFront;
+ swdd->WriteMonoRGBAPixels = MesaDriver::WriteMonoRGBAPixelsFront;
+ swdd->WriteCI32Span = MesaDriver::WriteCI32SpanFront;
+ swdd->WriteCI8Span = MesaDriver::WriteCI8SpanFront;
+ swdd->WriteMonoCISpan = MesaDriver::WriteMonoCISpanFront;
+ swdd->WriteCI32Pixels = MesaDriver::WriteCI32PixelsFront;
+ swdd->WriteMonoCIPixels = MesaDriver::WriteMonoCIPixelsFront;
+ swdd->ReadRGBASpan = MesaDriver::ReadRGBASpanFront;
+ swdd->ReadRGBAPixels = MesaDriver::ReadRGBAPixelsFront;
+ swdd->ReadCI32Span = MesaDriver::ReadCI32SpanFront;
+ swdd->ReadCI32Pixels = MesaDriver::ReadCI32PixelsFront;
+ }
+ else {
+ /* read/write back buffer */
+ swdd->WriteRGBASpan = MesaDriver::WriteRGBASpanBack;
+ swdd->WriteRGBSpan = MesaDriver::WriteRGBSpanBack;
+ swdd->WriteRGBAPixels = MesaDriver::WriteRGBAPixelsBack;
+ swdd->WriteMonoRGBASpan = MesaDriver::WriteMonoRGBASpanBack;
+ swdd->WriteMonoRGBAPixels = MesaDriver::WriteMonoRGBAPixelsBack;
+ swdd->WriteCI32Span = MesaDriver::WriteCI32SpanBack;
+ swdd->WriteCI8Span = MesaDriver::WriteCI8SpanBack;
+ swdd->WriteMonoCISpan = MesaDriver::WriteMonoCISpanBack;
+ swdd->WriteCI32Pixels = MesaDriver::WriteCI32PixelsBack;
+ swdd->WriteMonoCIPixels = MesaDriver::WriteMonoCIPixelsBack;
+ swdd->ReadRGBASpan = MesaDriver::ReadRGBASpanBack;
+ swdd->ReadRGBAPixels = MesaDriver::ReadRGBAPixelsBack;
+ swdd->ReadCI32Span = MesaDriver::ReadCI32SpanBack;
+ swdd->ReadCI32Pixels = MesaDriver::ReadCI32PixelsBack;
+ }
+}
+
+
+void MesaDriver::ClearIndex(GLcontext *ctx, GLuint index)
+{
+ MesaDriver *md = (MesaDriver *) ctx->DriverCtx;
+ md->m_clear_index = index;
+}
+
+
+void MesaDriver::ClearColor(GLcontext *ctx, const GLfloat color[4])
+{
+ MesaDriver *md = (MesaDriver *) ctx->DriverCtx;
+ CLAMPED_FLOAT_TO_CHAN(md->m_clear_color[BE_RCOMP], color[0]);
+ CLAMPED_FLOAT_TO_CHAN(md->m_clear_color[BE_GCOMP], color[1]);
+ CLAMPED_FLOAT_TO_CHAN(md->m_clear_color[BE_BCOMP], color[2]);
+ CLAMPED_FLOAT_TO_CHAN(md->m_clear_color[BE_ACOMP], color[3]);
+ assert(md->m_bglview);
+}
+
+
+void MesaDriver::Clear(GLcontext *ctx, GLbitfield mask,
+ GLboolean all, GLint x, GLint y,
+ GLint width, GLint height)
+{
+ if (mask & DD_FRONT_LEFT_BIT)
+ ClearFront(ctx, all, x, y, width, height);
+ if (mask & DD_BACK_LEFT_BIT)
+ ClearBack(ctx, all, x, y, width, height);
+
+ mask &= ~(DD_FRONT_LEFT_BIT | DD_BACK_LEFT_BIT);
+ if (mask)
+ _swrast_Clear( ctx, mask, all, x, y, width, height );
+
+ return;
+}
+
+
+void MesaDriver::ClearFront(GLcontext *ctx,
+ GLboolean all, GLint x, GLint y,
+ GLint width, GLint height)
+{
+ MesaDriver *md = (MesaDriver *) ctx->DriverCtx;
+ BGLView *bglview = md->m_bglview;
+ assert(bglview);
+
+ bglview->SetHighColor(md->m_clear_color[BE_RCOMP],
+ md->m_clear_color[BE_GCOMP],
+ md->m_clear_color[BE_BCOMP],
+ md->m_clear_color[BE_ACOMP]);
+ bglview->SetLowColor(md->m_clear_color[BE_RCOMP],
+ md->m_clear_color[BE_GCOMP],
+ md->m_clear_color[BE_BCOMP],
+ md->m_clear_color[BE_ACOMP]);
+ if (all) {
+ BRect b = bglview->Bounds();
+ bglview->FillRect(b);
+ }
+ else {
+ // XXX untested
+ BRect b;
+ b.left = x;
+ b.right = x + width;
+ b.bottom = md->m_height - y - 1;
+ b.top = b.bottom - height;
+ bglview->FillRect(b);
+ }
+
+ // restore drawing color
+#if 0
+ bglview->SetHighColor(md->mColor[BE_RCOMP],
+ md->mColor[BE_GCOMP],
+ md->mColor[BE_BCOMP],
+ md->mColor[BE_ACOMP]);
+ bglview->SetLowColor(md->mColor[BE_RCOMP],
+ md->mColor[BE_GCOMP],
+ md->mColor[BE_BCOMP],
+ md->mColor[BE_ACOMP]);
+#endif
+}
+
+
+void MesaDriver::ClearBack(GLcontext *ctx,
+ GLboolean all, GLint x, GLint y,
+ GLint width, GLint height)
+{
+ MesaDriver *md = (MesaDriver *) ctx->DriverCtx;
+ BGLView *bglview = md->m_bglview;
+ assert(bglview);
+ BBitmap *bitmap = md->m_bitmap;
+ assert(bitmap);
+ GLuint *start = (GLuint *) bitmap->Bits();
+ const GLuint *clearPixelPtr = (const GLuint *) md->m_clear_color;
+ const GLuint clearPixel = B_LENDIAN_TO_HOST_INT32(*clearPixelPtr);
+
+ if (all) {
+ const int numPixels = md->m_width * md->m_height;
+ if (clearPixel == 0) {
+ memset(start, 0, numPixels * 4);
+ }
+ else {
+ for (int i = 0; i < numPixels; i++) {
+ start[i] = clearPixel;
+ }
+ }
+ }
+ else {
+ // XXX untested
+ start += y * md->m_width + x;
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ start[j] = clearPixel;
+ }
+ start += md->m_width;
+ }
+ }
+}
+
+
+void MesaDriver::SetBuffer(GLcontext *ctx, GLframebuffer *buffer,
+ GLenum mode)
+{
+ /* TODO */
+ (void) ctx;
+ (void) buffer;
+ (void) mode;
+}
+
+void MesaDriver::GetBufferSize(GLframebuffer * framebuffer, GLuint *width,
+ GLuint *height)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ if (!ctx)
+ return;
+
+ MesaDriver * md = (MesaDriver *) ctx->DriverCtx;
+ BGLView *bglview = md->m_bglview;
+ assert(bglview);
+
+ BRect b = bglview->Bounds();
+ *width = (GLuint) b.IntegerWidth() + 1; // (b.right - b.left + 1);
+ *height = (GLuint) b.IntegerHeight() + 1; // (b.bottom - b.top + 1);
+ md->m_bottom = (GLint) b.bottom;
+
+ if (ctx->Visual.doubleBufferMode) {
+ if (*width != md->m_width || *height != md->m_height) {
+ // allocate new size of back buffer bitmap
+ if (md->m_bitmap)
+ delete md->m_bitmap;
+ BRect rect(0.0, 0.0, *width - 1, *height - 1);
+ md->m_bitmap = new BBitmap(rect, B_RGBA32);
+ }
+ }
+ else
+ {
+ md->m_bitmap = NULL;
+ }
+
+ md->m_width = *width;
+ md->m_height = *height;
+}
+
+
+void MesaDriver::Viewport(GLcontext *ctx, GLint x, GLint y, GLsizei w, GLsizei h)
+{
+ /* poll for window size change and realloc software Z/stencil/etc if needed */
+ _mesa_ResizeBuffersMESA();
+}
+
+
+const GLubyte *MesaDriver::GetString(GLcontext *ctx, GLenum name)
+{
+ switch (name) {
+ case GL_RENDERER:
+ return (const GLubyte *) "Mesa " MESA_VERSION_STRING " powered BGLView (software)";
+ default:
+ // Let core library handle all other cases
+ return NULL;
+ }
+}
+
+
+// Plot a pixel. (0,0) is upper-left corner
+// This is only used when drawing to the front buffer.
+inline void Plot(BGLView *bglview, int x, int y)
+{
+ // XXX There's got to be a better way!
+ BPoint p(x, y), q(x+1, y);
+ bglview->StrokeLine(p, q);
+}
+
+
+void MesaDriver::WriteRGBASpanFront(const GLcontext *ctx, GLuint n,
+ GLint x, GLint y,
+ CONST GLubyte rgba[][4],
+ const GLubyte mask[])
+{
+ MesaDriver *md = (MesaDriver *) ctx->DriverCtx;
+ BGLView *bglview = md->m_bglview;
+ assert(bglview);
+ int flippedY = md->m_bottom - y;
+ if (mask) {
+ for (GLuint i = 0; i < n; i++) {
+ if (mask[i]) {
+ bglview->SetHighColor(rgba[i][0], rgba[i][1], rgba[i][2], rgba[i][3]);