/* * Mesa 3-D graphics library * Version: 3.3 * * Copyright (C) 1999 Brian Paul All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * This is a sample template for writing new Mesa device drivers. * You'll have to rewrite much of the code below. * * Let's say you're interfacing Mesa to a window/operating system * called FOO. Replace all occurances of FOOMesa with the real name * you select for your interface (i.e. XMesa, WMesa, AmigaMesa). * * You'll have to design an API for clients to use, defined in a * header called Mesa/include/GL/FooMesa.h Use the sample as an * example. The API should at least have functions for creating * rendering contexts, binding rendering contexts to windows/frame * buffers, etc. * * Next, you'll have to write implementations for the device driver * functions described in dd.h * * Note that you'll usually have to flip Y coordinates since Mesa's * window coordinates start at the bottom and increase upward. Most * window system's Y-axis increases downward * * Functions marked OPTIONAL may be completely omitted by your driver. * * Your Makefile should compile this module along with the rest of * the core Mesa library. */ /* * XXX XXX * THIS FILE IS VERY OUT OF DATE! LOOK AT OSmesa/osmesa.c FOR A BETTER * EXAMPLE DRIVER! */ #ifdef PC_HEADER #include "all.h" #else #include "glheader.h" #include "GL/FooMesa.h" #include "context.h" #include "matrix.h" #include "types.h" #include "vb.h" #endif /* * In C++ terms, this class derives from the GLvisual class. * Add system-specific fields to it. */ struct foo_mesa_visual { GLvisual *gl_visual; GLboolean db_flag; /* double buffered? */ GLboolean rgb_flag; /* RGB mode? */ GLuint depth; /* bits per pixel (1, 8, 24, etc) */ }; /* * In C++ terms, this class derives from the GLframebuffer class. * Add system-specific fields to it. */ struct foo_mesa_buffer { GLframebuffer *gl_buffer; /* The depth, stencil, accum, etc buffers */ void *the_window; /* your window handle, etc */ int Width, Height; }; /* * In C++ terms, this class derives from the GLcontext class. * Add system-specific fields to it. */ struct foo_mesa_context { GLcontext *gl_ctx; /* the core library context */ FooMesaVisual visual; FooMesaBuffer Buffer; GLuint ClearIndex; GLubyte ClearColor[4]; GLuint CurrentIndex; GLubyte CurrentColor[4]; /* etc... */ }; static FooMesaContext CurrentContext = 0; static FooMesaBuffer CurrentBuffer = 0; static void setup_DD_pointers( GLcontext *ctx ); /**********************************************************************/ /***** Miscellaneous device driver funcs *****/ /**********************************************************************/ static void finish( GLcontext *ctx ) { struct foo_mesa_context *foo = (struct foo_mesa_context *) ctx->DriverCtx; /* OPTIONAL FUNCTION: implements glFinish if possible */ } static void flush( GLcontext *ctx ) { struct foo_mesa_context *foo = (struct foo_mesa_context *) ctx->DriverCtx; /* OPTIONAL FUNCTION: implements glFlush if possible */ } static void clear_index( GLcontext *ctx, GLuint index ) { struct foo_mesa_context *foo = (struct foo_mesa_context *) ctx->DriverCtx; foo->ClearIndex = index; } static void clear_color( GLcontext *ctx, GLubyte r, GLubyte g, GLubyte b, GLubyte a ) { struct foo_mesa_context *foo = (struct foo_mesa_context *) ctx->DriverCtx; foo->ClearColor[0] = r; foo->ClearColor[1] = g; foo->ClearColor[2] = b; foo->ClearColor[3] = a; } static GLbitfield clear( GLcontext *ctx, GLbitfield mask, GLboolean all, GLint x, GLint y, GLint width, GLint height ) { struct foo_mesa_context *foo = (struct foo_mesa_context *) ctx->DriverCtx; /* * Clear the specified region of the buffers indicated by 'mask' * using the clear color or index as specified by one of the two * functions above. * If all==GL_TRUE, clear whole buffer, else just clear region defined * by x,y,width,height */ return mask; /* return mask of buffers remaining to be cleared */ } static void set_index( GLcontext *ctx, GLuint index ) { struct foo_mesa_context *foo = (struct foo_mesa_context *) ctx->DriverCtx; foo->CurrentIndex = index; } static void set_color( GLcontext *ctx, GLubyte r, GLubyte g, GLubyte b, GLubyte a ) { struct foo_mesa_context *foo = (struct foo_mesa_context *) ctx->DriverCtx; foo->CurrentColor[0] = r; foo->CurrentColor[1] = g; foo->CurrentColor[2] = b; foo->CurrentColor[3] = a; } /* * OPTIONAL FUNCTION: implement glIndexMask if possible, else * return GL_FALSE */ static GLboolean index_mask( GLcontext *ctx, GLuint mask ) { struct foo_mesa_context *foo = (struct foo_mesa_context *) ctx->DriverCtx; return GL_FALSE; } /* * OPTIONAL FUNCTION: implement glColorMask if possible, else * return GL_FALSE */ static GLboolean color_mask( GLcontext *ctx, GLboolean rmask, GLboolean gmask, GLboolean bmask, GLboolean amask) { struct foo_mesa_context *foo = (struct foo_mesa_context *) ctx->DriverCtx; return GL_FALSE; } /* * OPTIONAL FUNCTION: * Implements glLogicOp if possible. Return GL_TRUE if the device driver * can perform the operation, otherwise return GL_FALSE. If GL_FALSE * is returned, the logic op will be done in software by Mesa. */ static GLboolean logicop( GLcontext *ctx, GLenum op ) { struct foo_mesa_context *foo = (struct foo_mesa_context *) ctx->DriverCtx; return GL_FALSE; } /* * OPTIONAL FUNCTION: enable/disable dithering if applicable */ static void dither( GLcontext *ctx, GLboolean enable ) { struct foo_mesa_context *foo = (struct foo_mesa_context *) ctx->DriverCtx; } /* * Set the current reading buffer. */ static void set_read_buffer( GLcontext *ctx, GLframebuffer *bufer, GLenum mode ) { struct foo_mesa_context *foo = (struct foo_mesa_context *) ctx->DriverCtx; setup_DD_pointers( ctx ); } /* * Set the destination/draw buffer. */ static GLboolean set_draw_buffer( GLcontext *ctx, GLenum mode ) { struct foo_mesa_context *foo = (struct foo_mesa_context *) ctx->DriverCtx; setup_DD_pointers( ctx ); return GL_TRUE; } /* * Return the width and height of the current buffer. * If anything special has to been done when the buffer/window is * resized, do it now. */ static void get_buffer_size( GLcontext *ctx, GLuint *width, GLuint *height ) { struct foo_mesa_context *foo = (struct foo_mesa_context *) ctx->DriverCtx; *width = foo->Buffer->Width = 12345; /* XXX fix these */ *height = foo->Buffer->Height = 12345; } /**********************************************************************/ /***** Dummy functions *****/ /**********************************************************************/ static void WriteCIPixel( GLint x, GLint y, GLuint index ) { } static void WriteRGBAPixel( GLint x, GLint y, const GLubyte color[4] ) { } static void WriteRGBPixel( GLint x, GLint y, const GLubyte color[3] ) { } static GLuint ReadCIPixel( GLint x, GLint y ) { return 0; } static void ReadRGBAPixel( GLint x, GLint y, GLubyte color[4] ) { } #define FLIP(y) foo->Buffer->Height - (y) - 1; /**********************************************************************/ /***** Accelerated point, line, triangle rendering *****/ /**********************************************************************/ /* There may several functions like this, for different screen modes, etc */ static void fast_points_function( GLcontext *ctx, GLuint first, GLuint last ) { struct foo_mesa_context *foo = (struct foo_mesa_context *) ctx->DriverCtx; struct vertex_buffer *VB = ctx->VB; GLint i; for (i=first;i<=last;i++) { if (VB->ClipMask[i]==0) { int x, y; x = (GLint) VB->Win.data[i][0]; y = FLIP( (GLint) VB->Win.data[i][1] ); WriteRGBAPixel( x, y, VB->ColorPtr->data[i] ); } } } /* There may several functions like this, for different screen modes, etc */ static void fast_line_function( GLcontext *ctx, GLuint v0, GLuint v1, GLuint pv ) { /* Render a line by some hardware/OS accerated method */ struct foo_mesa_context *foo = (struct foo_mesa_context *) ctx->DriverCtx; struct vertex_buffer *VB = ctx->VB; int x0, y0, x1, y1; GLubyte *pixel; pixel = VB->ColorPtr->data[pv]; x0 = (int) VB->Win.data[v0][0]; y0 = FLIP( (int) VB->Win.data[v0][1] ); x1 = (int) VB->Win.data[v1][0]; y1 = FLIP( (int) VB->Win.data[v1][1] ); /* Draw line from (x0,y0) to (x1,y1) with current pixel color/index */ } /* There may several functions like this, for different screen modes, etc */ static void fast_triangle_function( GLcontext *ctx, GLuint v0, GLuint v1, GLuint v2, GLuint pv ) { /* Render a triangle by some hardware/OS accerated method */ struct foo_mesa_context *foo = (struct foo_mesa_context *) ctx->DriverCtx; struct vertex_buffer *VB = ctx->VB; GLubyte *pixel; pixel = VB->ColorPtr->data[pv]; /* Draw triangle with current pixel color/index */ } /**********************************************************************/ /***** Write spans of pixels *****/ /**********************************************************************/ static void write_index8_span( const GLcontext *ctx, GLuint n, GLint x, GLint y, const GLubyte index[], const GLubyte mask[] ) { GLint i; for (i=0;iDriverCtx; GLuint i; for (i=0;iCurrentIndex); } } } static void write_rgba_span( const GLcontext *ctx, GLuint n, GLint x, GLint y, const GLubyte rgba[][4], const GLubyte mask[] ) { struct foo_mesa_context *foo = (struct foo_mesa_context *) ctx->DriverCtx; GLuint i; y = FLIP(y); if (mask) { /* draw some pixels */ for (i=0; iCurrentColor ); } } } else { /* draw all pixels */ for (i=0; iCurrentColor ); } } } static void write_rgb_span( const GLcontext *ctx, GLuint n, GLint x, GLint y, const GLubyte rgb[][3], const GLubyte mask[] ) { struct foo_mesa_context *foo = (struct foo_mesa_context *) ctx->DriverCtx; GLuint i; y = FLIP(y); if (mask) { /* draw some pixels */ for (i=0; iDriverCtx; GLint i; y = FLIP(y); for (i=0; iCurrentColor ); } } } /**********************************************************************/ /***** Read spans of pixels *****/ /**********************************************************************/ static void read_index_span( const GLcontext *ctx, GLuint n, GLint x, GLint y, GLuint index[]) { GLint i; for (i=0; iDriverCtx; GLint i; for (i=0; iCurrentIndex ); } } } static void write_rgba_pixels( const GLcontext *ctx, GLuint n, const GLint x[], const GLint y[], const GLubyte rgba[][4], const GLubyte mask[] ) { GLint i; for (i=0; iDriverCtx; GLint i; for (i=0; iCurrentColor ); } } } /**********************************************************************/ /***** Read arrays of pixels *****/ /**********************************************************************/ /* Read an array of color index pixels. */ static void read_index_pixels( const GLcontext *ctx, GLuint n, const GLint x[], const GLint y[], GLuint index[], const GLubyte mask[] ) { GLint i; for (i=0; iDriver.UpdateState = setup_DD_pointers; ctx->Driver.ClearIndex = clear_index; ctx->Driver.ClearColor = clear_color; ctx->Driver.Clear = clear; ctx->Driver.Index = set_index; ctx->Driver.Color = set_color; ctx->Driver.SetDrawBuffer = set_draw_buffer; ctx->Driver.SetReadBuffer = set_read_buffer; ctx->Driver.GetBufferSize = get_buffer_size; ctx->Driver.PointsFunc = fast_points_function; ctx->Driver.LineFunc = fast_line_function; ctx->Driver.TriangleFunc = fast_triangle_function; /* Pixel/span writing functions: */ ctx->Driver.WriteRGBASpan = write_rgba_span; ctx->Driver.WriteRGBSpan = write_rgb_span; ctx->Driver.WriteMonoRGBASpan = write_mono_rgba_span; ctx->Driver.WriteRGBAPixels = write_rgba_pixels; ctx->Driver.WriteMonoRGBAPixels = write_mono_rgba_pixels; ctx->Driver.WriteCI32Span = write_index32_span; ctx->Driver.WriteCI8Span = write_index8_span; ctx->Driver.WriteMonoCISpan = write_mono_index_span; ctx->Driver.WriteCI32Pixels = write_index_pixels; ctx->Driver.WriteMonoCIPixels = write_mono_index_pixels; /* Pixel/span reading functions: */ ctx->Driver.ReadCI32Span = read_index_span; ctx->Driver.ReadRGBASpan = read_rgba_span; ctx->Driver.ReadCI32Pixels = read_index_pixels; ctx->Driver.ReadRGBAPixels = read_rgba_pixels; /* * OPTIONAL FUNCTIONS: these may be left uninitialized if the device * driver can't/needn't implement them. */ ctx->Driver.Finish = finish; ctx->Driver.Flush = flush; ctx->Driver.IndexMask = index_mask; ctx->Driver.ColorMask = color_mask; ctx->Driver.LogicOp = logicop; ctx->Driver.Dither = dither; } /**********************************************************************/ /***** FOO/Mesa Public API Functions *****/ /**********************************************************************/ /* * The exact arguments to this function will depend on your window system */ FooMesaVisual FooMesaCreateVisual( GLboolean rgb_mode, GLboolean dbFlag, GLint depthSize, GLint stencilSize, GLint accumSize ) { FooMesaVisual v; GLint redBits, greenBits, blueBits, alphaBits, indexBits; GLboolean alphaFlag = GL_FALSE; v = (FooMesaVisual) calloc( 1, sizeof(struct foo_mesa_visual) ); if (!v) { return NULL; } if (rgb_mode) { /* RGB(A) mode */ redBits = 8; /* XXX 8 is just an example */ greenBits = 8; blueBits = 8; alphaBits = 8; indexBits = 0; } else { /* color index mode */ redBits = 0; greenBits = 0; blueBits = 0; alphaBits = 0; indexBits = 8; /* XXX 8 is just an example */ } /* Create core visual */ v->gl_visual = gl_create_visual( rgb_mode, alphaFlag, dbFlag, GL_FALSE, /* stereo */ depthSize, stencilSize, accumSize, indexBits, redBits, greenBits, blueBits, alphaBits ); return v; } void FooMesaDestroyVisual( FooMesaVisual v ) { gl_destroy_visual( v->gl_visual ); free( v ); } FooMesaBuffer FooMesaCreateBuffer( FooMesaVisual visual, void *your_window_id ) { FooMesaBuffer b; b = (FooMesaBuffer) calloc( 1, sizeof(struct foo_mesa_buffer) ); if (!b) { return NULL; } b->gl_buffer = gl_create_framebuffer( visual->gl_visual, visual->gl_visual->DepthBits > 0, visual->gl_visual->StencilBits > 0, visual->gl_visual->AccumBits > 0, visual->gl_visual->AlphaBits > 0 ); b->the_window = your_window_id; /* other stuff */ return b; } void FooMesaDestroyBuffer( FooMesaBuffer b ) { gl_destroy_framebuffer( b->gl_buffer ); free( b ); } FooMesaContext FooMesaCreateContext( FooMesaVisual visual, FooMesaContext share ) { FooMesaContext c; GLboolean direct = GL_FALSE; c = (FooMesaContext) calloc( 1, sizeof(struct foo_mesa_context) ); if (!c) { return NULL; } c->gl_ctx = gl_create_context( visual->gl_visual, share ? share->gl_ctx : NULL, (void *) c, direct ); /* you probably have to do a bunch of other initializations here. */ /* and then, finally let the context examine your initializations */ _mesa_initialize_context( c->gl_ctx ); return c; } void FooMesaDestroyContext( FooMesaContext c ) { gl_destroy_context( c->gl_ctx ); free( c ); } /* * Make the specified context and buffer the current one. */ void FooMesaMakeCurrent( FooMesaContext c, FooMesaBuffer b ) { if (c && b) { gl_make_current( c->gl_ctx, b->gl_buffer ); CurrentContext = c; CurrentBuffer = b; if (c->gl_ctx->Viewport.Width==0) { /* initialize viewport to window size */ gl_Viewport( c->gl_ctx, 0, 0, c->Buffer->Width, c->Buffer->Height ); } } else { /* Detach */ gl_make_current( NULL, NULL ); CurrentContext = 0; CurrentBuffer = 0; } } void FooMesaSwapBuffers( FooMesaBuffer b ) { /* copy/swap back buffer to front if applicable */ } /* you may need to add other FOO/Mesa functions too... */