m3g/m3gcore11/src/m3g_rendercontext.c
changeset 0 5d03bc08d59c
child 11 fed1595b188e
equal deleted inserted replaced
-1:000000000000 0:5d03bc08d59c
       
     1 /*
       
     2 * Copyright (c) 2003 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of the License "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description: Rendering context function implementations
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 /*!
       
    20  * \internal
       
    21  * \file
       
    22  * \brief Rendering context function implementations
       
    23  */
       
    24 
       
    25 #ifndef M3G_CORE_INCLUDE
       
    26 #   error included by m3g_core.c; do not compile separately.
       
    27 #endif
       
    28 
       
    29 #include "m3g_rendercontext.h"
       
    30 #include "m3g_object.h"
       
    31 
       
    32 #include "m3g_gl.h"
       
    33 #include "m3g_memory.h"
       
    34 #include "m3g_appearance.h"
       
    35 #include "m3g_indexbuffer.h"
       
    36 #include "m3g_lightmanager.h"
       
    37 #include "m3g_vertexbuffer.h"
       
    38 #include "m3g_world.h"
       
    39 
       
    40 /*----------------------------------------------------------------------
       
    41  * Private data types
       
    42  *--------------------------------------------------------------------*/
       
    43 
       
    44 #if defined(M3G_NGL_CONTEXT_API)
       
    45 /*!
       
    46  * \internal
       
    47  * \brief Depth buffer data
       
    48  */
       
    49 typedef struct
       
    50 {
       
    51     M3GMemObject handle;
       
    52     M3Gsizei size;
       
    53 } DepthBuffer;
       
    54 #endif /*M3G_NGL_CONTEXT_API*/
       
    55 
       
    56 #if !defined(M3G_NGL_CONTEXT_API)
       
    57 /*! \internal \brief OpenGL rendering context record */
       
    58 typedef struct {
       
    59     EGLContext handle;
       
    60     M3GPixelFormat format;
       
    61     M3Gbitmask bufferBits;
       
    62     M3Gbitmask surfaceTypeBits;
       
    63     M3Gbitmask modeBits;
       
    64     M3Guint lastUseTime;
       
    65 } GLContextRecord;
       
    66 
       
    67 /*! \internal \brief OpenGL surface record */
       
    68 typedef struct {
       
    69     EGLSurface handle;
       
    70     M3Gbitmask bufferBits;
       
    71     M3Gbitmask type;
       
    72     M3Guint targetHandle;
       
    73     M3Guint lastUseTime;
       
    74 } GLSurfaceRecord;
       
    75 #endif /*!M3G_NGL_CONTEXT_API*/
       
    76 
       
    77 /*!
       
    78  * \internal \brief Rendering target data
       
    79  */
       
    80 typedef struct 
       
    81 {
       
    82     M3Gbitmask type;
       
    83     M3GPixelFormat format;
       
    84     M3Gint width, height;
       
    85 #   if defined(M3G_NGL_CONTEXT_API)
       
    86     M3Guint stride;
       
    87     /*@shared@*/ void *pixels, *lockedPixels;
       
    88 #   else
       
    89     EGLSurface surface;
       
    90 #   endif
       
    91     M3Guint handle;
       
    92     M3Guint userData;
       
    93     
       
    94     /*!
       
    95      * \internal
       
    96      * \brief Flag set to indicate back buffer rendering
       
    97      *
       
    98      * The final target is only written to, via a format
       
    99      * conversion, when releasing the target.
       
   100      */
       
   101     M3Gbool buffered;
       
   102 } RenderTarget;
       
   103 
       
   104 /*!
       
   105  * \internal
       
   106  * \brief Back color buffer data
       
   107  */
       
   108 typedef struct {
       
   109 #   if defined(M3G_NGL_CONTEXT_API)
       
   110     M3GMemObject handle;
       
   111     M3Gsizei size;
       
   112 #   else
       
   113     M3Gint width, height;
       
   114     EGLSurface glSurface;
       
   115 #   endif /* M3G_NGL_CONTEXT_API */
       
   116     M3Gbool contentsValid;
       
   117 } BackBuffer;
       
   118 
       
   119 /*!
       
   120  * \internal
       
   121  * \brief Rendering context data structure
       
   122  *
       
   123  * This includes data related to a specific rendering context,
       
   124  * including e.g.  viewport settings, and active lights and
       
   125  * camera. This is equivalent to the Graphics3D class in the Java API.
       
   126  */
       
   127 struct M3GRenderContextImpl
       
   128 {
       
   129     Object object;
       
   130     
       
   131     RenderTarget target;
       
   132     BackBuffer backBuffer;
       
   133 #   if defined(M3G_NGL_CONTEXT_API)
       
   134     DepthBuffer depthBuffer;
       
   135 #   endif
       
   136 
       
   137 #   if !defined(M3G_NGL_CONTEXT_API)
       
   138     
       
   139     /* OpenGL context and surface caches */
       
   140     
       
   141     GLContextRecord glContext[M3G_MAX_GL_CONTEXTS];
       
   142     GLSurfaceRecord glSurface[M3G_MAX_GL_SURFACES];
       
   143     M3Guint cacheTimeStamp;
       
   144     
       
   145 #   endif /* M3G_NGL_CONTEXT_API */
       
   146 
       
   147     /*! \internal \brief Current/last rendering mode */
       
   148     M3Genum renderMode;
       
   149     
       
   150     /*! \internal \brief OpenGL viewing transformation */
       
   151     GLfloat viewTransform[16];
       
   152 
       
   153     /*! \internal \brief Current camera */
       
   154     const Camera *camera;
       
   155 
       
   156     /*! \internal \brief Light manager component */
       
   157     LightManager lightManager;
       
   158 
       
   159     /*! \internal \brief Last used scope, to speed up light selection */
       
   160     M3Gint lastScope;
       
   161 
       
   162 	M3Gfloat depthNear;
       
   163 	M3Gfloat depthFar;
       
   164     
       
   165     /*! \internal \brief Clipping rectangle parameters */
       
   166     struct { M3Gint x0, y0, x1, y1; } clip;
       
   167 
       
   168     /*! \internal \brief Scissor and viewport rectangles */
       
   169     struct { GLint x, y, width, height; } scissor, viewport;
       
   170 
       
   171     /*! \internal \brief Physical display size */
       
   172     struct { M3Gint width, height; } display;
       
   173     
       
   174     M3Gbitmask bufferBits;      /*!< \brief Rendering buffer bits */
       
   175     M3Gbitmask modeBits;        /*!< \brief Rendering mode bits */
       
   176 
       
   177     /*! \internal \brief OpenGL subsystem initialization flag */
       
   178     M3Gbool glInitialized;
       
   179 
       
   180     /*! \internal \brief HW acceleration status flag */
       
   181     M3Gbool accelerated;
       
   182     
       
   183     /*! \internal \brief Render queue for this context */
       
   184 	RenderQueue *renderQueue;
       
   185 
       
   186     M3Gbool currentColorWrite;
       
   187     M3Gbool currentAlphaWrite;
       
   188     M3Gbool inSplitDraw;
       
   189     M3Gbool alphaWrite;
       
   190 };
       
   191 
       
   192 /*
       
   193  * Rendering target types; note that the values here MUST match the
       
   194  * respective EGL bit values
       
   195  */
       
   196 enum SurfaceType {
       
   197     SURFACE_NONE = 0,
       
   198     SURFACE_IMAGE = 0x01,       /* EGL_PBUFFER_BIT */
       
   199     SURFACE_BITMAP = 0x02,      /* EGL_PIXMAP_BIT */
       
   200     SURFACE_WINDOW = 0x04,      /* EGL_WINDOW_BIT */
       
   201     SURFACE_MEMORY = SURFACE_IMAGE | SURFACE_BITMAP | SURFACE_WINDOW,
       
   202     SURFACE_EGL = 0x80
       
   203 };
       
   204 
       
   205 enum RenderMode {
       
   206     RENDER_IMMEDIATE,
       
   207     RENDER_NODES,
       
   208     RENDER_WORLD
       
   209 };
       
   210 
       
   211 /*----------------------------------------------------------------------
       
   212  * Platform specific code
       
   213  *--------------------------------------------------------------------*/
       
   214 
       
   215 static M3Gbool m3gBindRenderTarget(RenderContext *ctx,
       
   216                                    M3Genum targetType,
       
   217                                    M3Gint width, M3Gint height,
       
   218                                    M3GPixelFormat format,
       
   219                                    M3Guint handle);
       
   220 static void m3gResetRectangles(RenderContext *ctx);
       
   221 static void m3gSetGLDefaults(void);
       
   222 static void m3gUpdateScissor(RenderContext *ctx);
       
   223 static void m3gValidateBuffers(RenderContext *ctx);
       
   224 static M3Gbool m3gValidTargetFormat(M3GPixelFormat format);
       
   225 
       
   226 #include "m3g_rendercontext.inl"
       
   227 
       
   228 /*----------------------------------------------------------------------
       
   229  * Internal functions
       
   230  *--------------------------------------------------------------------*/
       
   231 
       
   232 /*!
       
   233  * \internal
       
   234  * \brief Rendering context destructor
       
   235  *
       
   236  */
       
   237 static void m3gDestroyContext(/*@only@*/ Object *obj)
       
   238 {
       
   239     RenderContext *ctx = (RenderContext *) obj;
       
   240     M3G_VALIDATE_OBJECT(ctx);
       
   241 
       
   242     M3G_ASSIGN_REF(ctx->camera, NULL);
       
   243     
       
   244 #   if defined(M3G_NGL_CONTEXT_API)
       
   245     if (ctx->target.type == SURFACE_MEMORY && ctx->target.pixels == NULL) {
       
   246         m3gSignalTargetRelease(M3G_INTERFACE(ctx), ctx->target.handle);
       
   247     }
       
   248 
       
   249     m3gFreeObject(M3G_INTERFACE(ctx), ctx->depthBuffer.handle);
       
   250     m3gFreeObject(M3G_INTERFACE(ctx), ctx->backBuffer.handle);
       
   251     
       
   252 #   else /* !M3G_NGL_CONTEXT_API */
       
   253     
       
   254     {
       
   255         int i;
       
   256         for (i = 0; i < M3G_MAX_GL_CONTEXTS; ++i) {
       
   257             if (ctx->glContext[i].handle != 0) {
       
   258                 m3gDeleteGLContext(ctx->glContext[i].handle);
       
   259             }
       
   260         }
       
   261         for (i = 0; i < M3G_MAX_GL_SURFACES; ++i) {
       
   262             if (ctx->glSurface[i].handle != 0) {
       
   263                 m3gDeleteGLSurface(ctx->glSurface[i].handle);
       
   264             }
       
   265         }
       
   266     }
       
   267 
       
   268 #   endif /* M3G_NGL_CONTEXT_API */
       
   269     
       
   270     if (ctx->glInitialized) {
       
   271         m3gShutdownGL(M3G_INTERFACE(ctx));
       
   272     }
       
   273 
       
   274     m3gDestroyLightManager(&ctx->lightManager, M3G_INTERFACE(ctx));
       
   275     m3gDestroyRenderQueue(M3G_INTERFACE(ctx), ctx->renderQueue);
       
   276     m3gDestroyObject(obj);
       
   277 }
       
   278 
       
   279 /*!
       
   280  * \internal
       
   281  * \brief Resets the clipping and viewport rectangles to defaults
       
   282  *
       
   283  * This is called after binding a new target.
       
   284  */
       
   285 static void m3gResetRectangles(RenderContext *ctx)
       
   286 {
       
   287     int w = ctx->display.width;
       
   288     int h = ctx->display.height;
       
   289     
       
   290     ctx->clip.x0 = 0;
       
   291     ctx->clip.y0 = ctx->target.height - ctx->display.height;
       
   292     ctx->clip.x1 = w;
       
   293     ctx->clip.y1 = ctx->clip.y0 + h;
       
   294 
       
   295     ctx->viewport.x = 0;
       
   296     ctx->viewport.y = 0;
       
   297     ctx->viewport.width = M3G_MIN(w, M3G_MAX_VIEWPORT_DIMENSION);
       
   298     ctx->viewport.height = M3G_MIN(h, M3G_MAX_VIEWPORT_DIMENSION);
       
   299 }
       
   300 
       
   301 /*!
       
   302  * \internal
       
   303  * \brief Constrains the clip rectangle to the rendering target.
       
   304  */
       
   305 static void m3gValidateClipRect(RenderContext *ctx)
       
   306 {
       
   307     int xMin = 0;
       
   308     int xMax = ctx->display.width;
       
   309     int yMin = ctx->target.height - ctx->display.height;
       
   310     int yMax = yMin + ctx->display.height;
       
   311     
       
   312     ctx->clip.x0 = m3gClampInt(ctx->clip.x0, xMin, xMax);
       
   313     ctx->clip.y0 = m3gClampInt(ctx->clip.y0, yMin, yMax);
       
   314     ctx->clip.x1 = m3gClampInt(ctx->clip.x1, xMin, xMax);
       
   315     ctx->clip.y1 = m3gClampInt(ctx->clip.y1, yMin, yMax);
       
   316 }
       
   317 
       
   318 /*!
       
   319  * \internal
       
   320  * \brief Computes the GL scissor rectangle
       
   321  *
       
   322  * The scissor rectangle is the intersection of the viewport and the
       
   323  * clipping rectangle.
       
   324  */
       
   325 static void m3gUpdateScissor(RenderContext *ctx)
       
   326 {
       
   327     int sx0 = ctx->viewport.x;
       
   328     int sy0 = ctx->viewport.y;
       
   329     int sx1 = sx0 + ctx->viewport.width;
       
   330     int sy1 = sy0 + ctx->viewport.height;
       
   331 
       
   332     sx0 = M3G_MAX(sx0, ctx->clip.x0);
       
   333     sy0 = M3G_MAX(sy0, ctx->clip.y0);
       
   334     sx1 = M3G_MIN(sx1, ctx->clip.x1);
       
   335     sy1 = M3G_MIN(sy1, ctx->clip.y1);
       
   336 
       
   337     ctx->scissor.x = sx0;
       
   338     ctx->scissor.y = sy0;
       
   339     
       
   340     if (sx0 < sx1 && sy0 < sy1) {
       
   341         ctx->scissor.width = sx1 - sx0;
       
   342         ctx->scissor.height = sy1 - sy0;
       
   343     }
       
   344     else {
       
   345         ctx->scissor.width = ctx->scissor.height = 0;
       
   346     }
       
   347 }
       
   348 
       
   349 /*!
       
   350  * \internal
       
   351  * \brief Checks whether we can render in a given format
       
   352  */
       
   353 static M3Gbool m3gValidTargetFormat(M3GPixelFormat format)
       
   354 {
       
   355     return m3gInRange(format, M3G_RGB8, M3G_RGBA4);
       
   356 }
       
   357 
       
   358 /*!
       
   359  * \internal
       
   360  * \brief Checks whether a given format has alpha
       
   361  */
       
   362 static M3Gbool m3gFormatHasAlpha(M3GPixelFormat format)
       
   363 {
       
   364     switch (format) {
       
   365     case M3G_A8:
       
   366     case M3G_LA8:
       
   367     case M3G_LA4:
       
   368     case M3G_RGBA8:
       
   369     case M3G_BGRA8:
       
   370     case M3G_RGBA4:
       
   371     case M3G_RGB5A1:
       
   372     case M3G_PALETTE8_RGBA8:
       
   373         return M3G_TRUE;
       
   374     default:
       
   375         return M3G_FALSE;
       
   376     }
       
   377 }
       
   378 
       
   379 /*!
       
   380  * \internal
       
   381  * \brief Sets the global alpha write enable flag. 
       
   382  *
       
   383  *	Used for disabling the alpha channel writes when the rendering 
       
   384  *  target is a Java MIDP Image that has an alpha channel.
       
   385  *
       
   386  * \param ctx        the rendering context
       
   387  * \param enable     alpha write enable flag
       
   388  */
       
   389 M3G_API void m3gSetAlphaWrite(M3GRenderContext ctx, M3Gbool enable)
       
   390 {
       
   391 	ctx->alphaWrite = enable;
       
   392 }
       
   393 
       
   394 /*!
       
   395  * \internal
       
   396  * \brief Reads the global alpha write enable flag. 
       
   397  *
       
   398  * \param ctx        the rendering context
       
   399  */
       
   400 M3G_API M3Gbool m3gGetAlphaWrite(M3GRenderContext ctx)
       
   401 {
       
   402 	return ctx->alphaWrite;
       
   403 }
       
   404 
       
   405 
       
   406 /*!
       
   407  * \internal
       
   408  * \brief Sets up a new rendering target
       
   409  *
       
   410  * \param ctx        the rendering context
       
   411  * \param targetType rendering target type
       
   412  * \param width      width of the target
       
   413  * \param height     height of the target
       
   414  * \param format     target pixel format
       
   415  * \param handle     user object handle
       
   416  */
       
   417 static M3Gbool m3gBindRenderTarget(RenderContext *ctx,
       
   418                                    M3Genum targetType,
       
   419                                    M3Gint width, M3Gint height,
       
   420                                    M3GPixelFormat format,
       
   421                                    M3Guint handle)
       
   422 {
       
   423     /* Check for generic errors */
       
   424     
       
   425     if (ctx->target.type != SURFACE_NONE) {
       
   426         m3gRaiseError(M3G_INTERFACE(ctx), M3G_INVALID_OPERATION);
       
   427         return M3G_FALSE;
       
   428     }
       
   429     if (!m3gValidTargetFormat(format)) {
       
   430         m3gRaiseError(M3G_INTERFACE(ctx), M3G_INVALID_ENUM);
       
   431         return M3G_FALSE;
       
   432     }
       
   433 
       
   434     /* If target width or height exceeds maximum viewport width or height
       
   435        an exception is thrown. */
       
   436     
       
   437     if (width > M3G_MAX_VIEWPORT_WIDTH ||
       
   438         height > M3G_MAX_VIEWPORT_HEIGHT) {
       
   439         m3gRaiseError(M3G_INTERFACE(ctx), M3G_INVALID_ENUM);
       
   440         return M3G_FALSE;
       
   441     }
       
   442 
       
   443     /* Everything checks out; set up the target parameters */
       
   444     
       
   445     ctx->target.type = targetType;
       
   446     ctx->target.width = width;
       
   447     ctx->target.height = height;
       
   448     ctx->display.width = width;
       
   449     ctx->display.height = height;
       
   450     ctx->target.format = format;
       
   451     ctx->target.handle = handle;
       
   452     m3gResetRectangles(ctx);
       
   453     m3gUpdateScissor(ctx);
       
   454     m3gValidateBuffers(ctx);
       
   455     
       
   456     /* Invalidate lights in case we're using a different OpenGL
       
   457      * rendering context this time around */
       
   458     
       
   459     ctx->lastScope = 0;
       
   460     
       
   461     return M3G_TRUE;
       
   462 }
       
   463 
       
   464 /*!
       
   465  * \internal
       
   466  * \brief Initializes the current GL context to default settings.
       
   467  */
       
   468 static void m3gSetGLDefaults(void)
       
   469 {
       
   470 	static const GLfloat black[] = {0.f, 0.f, 0.f, 0.f};
       
   471     glEnable(GL_NORMALIZE);
       
   472     glEnable(GL_SCISSOR_TEST);
       
   473 	glLightModelfv(GL_LIGHT_MODEL_AMBIENT, black);
       
   474     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
       
   475 }
       
   476 
       
   477 /*!
       
   478  * \internal
       
   479  * \brief Validates the buffers required for a rendering context
       
   480  *
       
   481  * Allocates or reallocates buffers as necessary, according to the
       
   482  * currently set flags of the context.
       
   483  */
       
   484 static void m3gValidateBuffers(RenderContext *ctx)
       
   485 {
       
   486     M3G_VALIDATE_OBJECT(ctx);
       
   487 
       
   488     /* Initialize OpenGL if not already done */
       
   489     
       
   490     if (!ctx->glInitialized) {
       
   491         m3gInitializeGL(M3G_INTERFACE(ctx));
       
   492         ctx->glInitialized = M3G_TRUE;
       
   493     }
       
   494 
       
   495     /* Check whether we can render directly to the target or need to
       
   496      * use a back buffer */
       
   497     
       
   498     ctx->target.buffered = !m3gCanDirectRender(ctx);
       
   499 #   if defined(M3G_FORCE_BUFFERED_RENDERING)
       
   500     ctx->target.buffered = M3G_TRUE;
       
   501 #   endif
       
   502     
       
   503     /* If direct rendering wasn't possible, check that the back buffer
       
   504      * for buffered rendering exists. */
       
   505     
       
   506     if (ctx->target.buffered) {
       
   507         if (!m3gValidateBackBuffer(ctx)) {
       
   508             return; /* out of memory */
       
   509         }
       
   510     }
       
   511 
       
   512     /* With the legacy NGL API, we also manage the depth buffer */
       
   513     
       
   514 #   if defined(M3G_NGL_CONTEXT_API)
       
   515     if (!m3gValidateDepthBuffer(ctx)) {
       
   516         return; /* out of memory */
       
   517     }
       
   518 #   endif
       
   519 
       
   520     /* Delay blitting from the front buffer until we know it's
       
   521      * necessary; let's raise a flag to check that later on */
       
   522     
       
   523     if (ctx->target.buffered) {
       
   524         if (ctx->modeBits & M3G_OVERWRITE_BIT) {
       
   525             ctx->backBuffer.contentsValid = M3G_TRUE;
       
   526         }
       
   527         else {
       
   528             ctx->backBuffer.contentsValid = M3G_FALSE;
       
   529         }
       
   530     }
       
   531 }
       
   532 
       
   533 /*!
       
   534  * \internal
       
   535  * \brief Makes a GL context current to this thread and the currently
       
   536  * set rendering target buffer
       
   537  */
       
   538 static void m3gMakeCurrent(RenderContext *ctx)
       
   539 {
       
   540     m3gMakeGLCurrent(ctx);
       
   541 
       
   542     /* Note that the depth buffer may in some cases exist even if not
       
   543      * explicitly requested, so we need to disable the depth test just
       
   544      * in case */
       
   545     
       
   546     if ((ctx->bufferBits & M3G_DEPTH_BUFFER_BIT) == 0) {
       
   547         glDisable(GL_DEPTH_TEST);
       
   548     }
       
   549     else {
       
   550         glEnable(GL_DEPTH_TEST);
       
   551     }
       
   552 
       
   553     /* Enable multisampling if required */
       
   554 
       
   555     if (ctx->modeBits & M3G_ANTIALIAS_BIT) {
       
   556         glEnable(GL_MULTISAMPLE);
       
   557     }
       
   558     else {
       
   559         glDisable(GL_MULTISAMPLE);
       
   560     }
       
   561     
       
   562     M3G_ASSERT_GL;
       
   563 }
       
   564 
       
   565 /*!
       
   566  * \internal
       
   567  * \brief Returns the HW acceleration status of the current context
       
   568  */
       
   569 static M3Gbool m3gIsAccelerated(const RenderContext *ctx)
       
   570 {
       
   571     return ctx->accelerated;
       
   572 }
       
   573 
       
   574 /*!
       
   575  * \internal
       
   576  * \brief Sets the currently enabled lights to the GL state
       
   577  *
       
   578  * \note the correct viewing matrix *must* be set prior to calling
       
   579  * this for the lights to be transformed into eye space correctly
       
   580  */
       
   581 static M3G_INLINE void m3gApplyLights(RenderContext *ctx, M3Gint scope)
       
   582 {
       
   583     if (ctx->lastScope != scope) {
       
   584 
       
   585         /* If coming from RenderNode, we have the geometry in camera
       
   586          * space but the lights in world space, so we need to apply
       
   587          * the viewing matrix to the lights only */
       
   588         
       
   589         if (ctx->renderMode == RENDER_NODES) {
       
   590             glPushMatrix();
       
   591             glLoadMatrixf(ctx->viewTransform);
       
   592         }
       
   593         
       
   594         m3gSelectGLLights(&ctx->lightManager, 8, scope, 0, 0, 0);
       
   595         ctx->lastScope = scope;
       
   596         
       
   597         if (ctx->renderMode == RENDER_NODES) {
       
   598             glPopMatrix();
       
   599         }
       
   600     }
       
   601 	M3G_ASSERT_GL;
       
   602 }
       
   603 
       
   604 /*!
       
   605  * \internal
       
   606  * \brief Gets the current camera
       
   607  */
       
   608 static const Camera *m3gGetCurrentCamera(const RenderContext *ctx) {
       
   609 	return ctx->camera;	
       
   610 }
       
   611 
       
   612 /*!
       
   613  * \internal
       
   614  * \brief Sets up some rendering parameters that
       
   615  * do not change during scene renders.
       
   616  */
       
   617 static void m3gInitRender(M3GRenderContext context, M3Genum renderMode)
       
   618 {
       
   619     RenderContext *ctx = (RenderContext *) context;
       
   620     M3G_VALIDATE_OBJECT(ctx);
       
   621 
       
   622     m3gIncrementRenderTimeStamp(ctx);
       
   623     m3gMakeCurrent(ctx);
       
   624     m3gCollectGLObjects(M3G_INTERFACE(ctx));
       
   625     
       
   626     /* If buffered rendering, blit the image to the back buffer at
       
   627      * this point */
       
   628     
       
   629     if (ctx->target.buffered && !ctx->backBuffer.contentsValid) {
       
   630         m3gUpdateBackBuffer(ctx);
       
   631     }
       
   632     
       
   633     /* Set up viewport and scissoring */
       
   634     
       
   635     glViewport(ctx->viewport.x, ctx->viewport.y,
       
   636                ctx->viewport.width, ctx->viewport.height);
       
   637 	glDepthRangef(ctx->depthNear, ctx->depthFar);
       
   638     glScissor(ctx->scissor.x, ctx->scissor.y,
       
   639               ctx->scissor.width, ctx->scissor.height);
       
   640     M3G_ASSERT_GL;
       
   641     
       
   642     /* Set up the projection and viewing transformations (static
       
   643      * during rendering) */
       
   644 
       
   645 	m3gApplyProjection(ctx->camera);
       
   646     if (renderMode == RENDER_NODES) {
       
   647         glLoadIdentity();
       
   648     }
       
   649     else {
       
   650         glLoadMatrixf(ctx->viewTransform);
       
   651     }
       
   652     M3G_ASSERT_GL;
       
   653 
       
   654     /* Invalidate any already set GL lights if rendering mode changed */
       
   655     
       
   656     if (renderMode != ctx->renderMode) {
       
   657         ctx->lastScope = 0;
       
   658     }
       
   659     ctx->renderMode = renderMode;
       
   660 }
       
   661 
       
   662 /*!
       
   663  * \internal
       
   664  * \brief A workaround for a broken implementation of glColorMask
       
   665  *
       
   666  * Saves the framebuffer in the OpenGL default texture each time the
       
   667  * color mask changes, for restoring later.  Not very pretty, but
       
   668  * works as long as the default texture is not touched in between --
       
   669  * currently, we only touch that when copying to and from the back
       
   670  * buffer.
       
   671  *
       
   672  * \param newColorWrite the color mask state we're about to change to
       
   673  * \param newAlphaWrite the alpha write state we're about to change to
       
   674  */
       
   675 static void m3gUpdateColorMaskStatus(RenderContext *ctx,
       
   676                                      M3Gbool newColorWrite,
       
   677                                      M3Gbool newAlphaWrite)
       
   678 {
       
   679     GLint pow2Width, pow2Height;
       
   680 
       
   681 	/* Get the global alpha write value */
       
   682 	newAlphaWrite &= m3gGetAlphaWrite(ctx);
       
   683 
       
   684     /* Check that the ColorMask state is actually about to change */
       
   685     
       
   686     if (ctx->currentColorWrite == newColorWrite
       
   687         && (ctx->currentAlphaWrite == newAlphaWrite || !m3gFormatHasAlpha(ctx->target.format))) {
       
   688         return; /* no change, quick exit */
       
   689     }
       
   690     
       
   691     pow2Width = m3gNextPowerOfTwo(ctx->clip.x1 - ctx->clip.x0);
       
   692     pow2Height = m3gNextPowerOfTwo(ctx->clip.y1 - ctx->clip.y0);
       
   693     
       
   694     /* If we previously had stored something, restore it now */
       
   695 
       
   696     if (ctx->currentColorWrite != ctx->currentAlphaWrite) {
       
   697         
       
   698         /* Disable any stray state we don't want */
       
   699 
       
   700         glDisable(GL_CULL_FACE);
       
   701         glDisable(GL_ALPHA_TEST);
       
   702         glDisableClientState(GL_NORMAL_ARRAY);
       
   703         glDisableClientState(GL_COLOR_ARRAY);
       
   704         glDisable(GL_LIGHTING);
       
   705         glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
       
   706         glDepthMask(GL_FALSE);
       
   707         glDepthFunc(GL_ALWAYS);
       
   708         m3gDisableTextures();
       
   709         M3G_ASSERT_GL;
       
   710     
       
   711         /* Bind the default texture and set up screen space rendering */
       
   712         
       
   713         glActiveTexture(GL_TEXTURE0);
       
   714         glBindTexture(GL_TEXTURE_2D, 0);
       
   715         glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
       
   716         glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
       
   717         M3G_ASSERT_GL;
       
   718 
       
   719         glScissor(ctx->clip.x0, ctx->clip.y0,
       
   720                   ctx->clip.x1 - ctx->clip.x0, ctx->clip.y1 - ctx->clip.y0);
       
   721         m3gPushScreenSpace(ctx, M3G_FALSE);
       
   722         glViewport(0, 0, ctx->target.width, ctx->target.height);
       
   723         glMatrixMode(GL_PROJECTION);
       
   724         glOrthox(0, ctx->target.width << 16,
       
   725                  0, ctx->target.height << 16,
       
   726                  -1 << 16, 1 << 16);
       
   727         glMatrixMode(GL_MODELVIEW);
       
   728             
       
   729         /* Set up texture and vertex coordinate arrays */
       
   730 
       
   731         glClientActiveTexture(GL_TEXTURE0);
       
   732         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
       
   733         glEnableClientState(GL_VERTEX_ARRAY);
       
   734         glMatrixMode(GL_TEXTURE);
       
   735         glLoadIdentity();
       
   736         glMatrixMode(GL_MODELVIEW);
       
   737         M3G_ASSERT_GL;
       
   738 
       
   739         /* Blend the texture with the frame buffer */
       
   740         {
       
   741             static const M3Gbyte tc[8] = { 0, 0, 0, 1, 1, 0, 1, 1 };
       
   742             GLshort pos[8];
       
   743             
       
   744             GLfixed cm = (GLfixed)(ctx->currentColorWrite ? 0 : 1 << 16);
       
   745             GLfixed am = (GLfixed)(ctx->currentAlphaWrite ? 0 : 1 << 16);
       
   746 
       
   747             glVertexPointer(2, GL_SHORT, 0, pos);
       
   748             glTexCoordPointer(2, GL_BYTE, 0, tc);
       
   749                 
       
   750             pos[0] = (GLshort) ctx->clip.x0;
       
   751             pos[1] = (GLshort) ctx->clip.y0;
       
   752             pos[2] = pos[0];
       
   753             pos[3] = (GLshort) (pos[1] + pow2Height);
       
   754             pos[4] = (GLshort) (pos[0] + pow2Width);
       
   755             pos[5] = pos[1];
       
   756             pos[6] = pos[4];
       
   757             pos[7] = pos[3];
       
   758             
       
   759             glEnable(GL_BLEND);
       
   760             glColor4x(cm, cm, cm, am);
       
   761 
       
   762             /* Zero the masked channels */
       
   763             
       
   764             glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
       
   765             glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
       
   766 
       
   767             /* Add the masked channels from the stored texture */
       
   768             
       
   769             glEnable(GL_TEXTURE_2D);
       
   770             glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
       
   771             glBlendFunc(GL_ONE, GL_ONE);
       
   772             glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
       
   773         }
       
   774             
       
   775         /* Restore the mandatory state */
       
   776             
       
   777         glScissor(ctx->scissor.x, ctx->scissor.y,
       
   778                   ctx->scissor.width, ctx->scissor.height);
       
   779         glViewport(ctx->viewport.x, ctx->viewport.y,
       
   780                    ctx->viewport.width, ctx->viewport.height);
       
   781         m3gPopSpace(ctx);
       
   782     }
       
   783     
       
   784     /* Copy the current clip rectangle into the default texture if
       
   785      * we're going to be rendering with unsupported masks in effect */
       
   786     
       
   787     if (newColorWrite != newAlphaWrite) {
       
   788         GLenum err;
       
   789             
       
   790         glBindTexture(GL_TEXTURE_2D, 0);
       
   791         M3G_ASSERT_GL;
       
   792             
       
   793         glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
       
   794                          ctx->clip.x0, ctx->clip.y0,
       
   795                          pow2Width, pow2Height,
       
   796                          0);
       
   797         err = glGetError();
       
   798         if (err == GL_INVALID_OPERATION) {
       
   799             /* Incompatible FB format -- must be GL_RGB then */
       
   800             glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
       
   801                              ctx->clip.x0, ctx->clip.y0,
       
   802                              pow2Width, pow2Height,
       
   803                              0);
       
   804             err = glGetError();
       
   805         }
       
   806         if (err == GL_OUT_OF_MEMORY) {
       
   807             m3gRaiseError(M3G_INTERFACE(ctx), M3G_OUT_OF_MEMORY);
       
   808         }
       
   809         M3G_ASSERT(!err);
       
   810     }
       
   811     else {
       
   812         
       
   813         /* Texture not needed for now, so allow GL to free some
       
   814          * resources */
       
   815         
       
   816         glTexImage2D(GL_TEXTURE_2D, 0,
       
   817                      GL_RGBA,
       
   818                      1, 1,
       
   819                      0,
       
   820                      GL_RGBA, GL_UNSIGNED_BYTE, NULL);
       
   821     }
       
   822     
       
   823     ctx->currentColorWrite = newColorWrite;
       
   824     ctx->currentAlphaWrite = newAlphaWrite;
       
   825 }
       
   826 
       
   827 /*!
       
   828  * \internal
       
   829  * \brief Sets the GL to input screen space coordinates
       
   830  *
       
   831  * This pushes the current modelview and projection matrices into the
       
   832  * matrix stack, then sets up an orthogonal projection and an identity
       
   833  * modelview matrix.
       
   834  * 
       
   835  * \param ctx the rendering context
       
   836  * \param realPixels M3G_TRUE to use actual pixel coordinates,
       
   837  * M3G_FALSE to use normalized device coordinates
       
   838  */
       
   839 static void m3gPushScreenSpace(RenderContext *ctx, M3Gbool realPixels)
       
   840 {
       
   841     M3G_VALIDATE_OBJECT(ctx);
       
   842     
       
   843     glMatrixMode(GL_PROJECTION);
       
   844     glPushMatrix();
       
   845     glLoadIdentity();
       
   846     if (realPixels) {
       
   847         int w = ctx->viewport.width;
       
   848         int h = ctx->viewport.height;
       
   849         glOrthox(0, w << 16, 0, h << 16, -1 << 16, 1 << 16);
       
   850     }
       
   851     glMatrixMode(GL_MODELVIEW);
       
   852     glPushMatrix();
       
   853     glLoadIdentity();
       
   854 }
       
   855 
       
   856 /*!
       
   857  * \internal
       
   858  * \brief Restores the projection and modelview matrix modified by
       
   859  * m3gPushScreenSpace
       
   860  */
       
   861 static void m3gPopSpace(RenderContext *ctx)
       
   862 {
       
   863     M3G_VALIDATE_OBJECT(ctx);
       
   864     
       
   865     M3G_UNREF(ctx);
       
   866     glMatrixMode(GL_PROJECTION);
       
   867     glPopMatrix();
       
   868     glMatrixMode(GL_MODELVIEW);
       
   869     glPopMatrix();
       
   870 }
       
   871 
       
   872 /*!
       
   873  * \internal
       
   874  * \brief Clears the current buffer(s)
       
   875  */
       
   876 static void m3gClearInternal(RenderContext *ctx, Background *bg)
       
   877 {
       
   878     m3gMakeCurrent(ctx);
       
   879     
       
   880     /* If buffered rendering, copy data to the back buffer at this
       
   881      * point if we're not clearing the whole clip rectangle */
       
   882     
       
   883     if (ctx->target.buffered && !ctx->backBuffer.contentsValid) {
       
   884         if (ctx->scissor.x > ctx->clip.x0 || ctx->scissor.y > ctx->clip.y0 ||
       
   885             ctx->scissor.x + ctx->scissor.width < ctx->clip.x1 ||
       
   886             ctx->scissor.y + ctx->scissor.height < ctx->clip.y1) {
       
   887             m3gUpdateBackBuffer(ctx);
       
   888         }
       
   889     }
       
   890 
       
   891     if (m3gGetColorMaskWorkaround(M3G_INTERFACE(ctx))) {
       
   892         m3gUpdateColorMaskStatus(ctx, M3G_TRUE, M3G_TRUE);
       
   893     }
       
   894 
       
   895     glDepthMask(GL_TRUE);
       
   896     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, m3gGetAlphaWrite(ctx));
       
   897     glDepthRangef(ctx->depthNear, ctx->depthFar);
       
   898     glViewport(ctx->viewport.x, ctx->viewport.y,
       
   899                ctx->viewport.width, ctx->viewport.height);
       
   900     glScissor(ctx->scissor.x, ctx->scissor.y,
       
   901               ctx->scissor.width, ctx->scissor.height);
       
   902 
       
   903     /* Touch the background image to make sure it's created prior to
       
   904      * locking memory for rendering */
       
   905     
       
   906     if (bg != NULL && bg->image != NULL) {
       
   907         if (!m3gGetPowerOfTwoImage(bg->image)) {
       
   908             return; /* out of memory */
       
   909         }
       
   910     }
       
   911 
       
   912     /* All clear for clearing... */
       
   913     
       
   914     m3gLockFrameBuffer(ctx);
       
   915     
       
   916     if (bg != NULL) {
       
   917         m3gApplyBackground(ctx, bg);
       
   918         if (ctx->target.buffered && bg->colorClearEnable) {
       
   919             ctx->backBuffer.contentsValid = M3G_TRUE;
       
   920         }
       
   921     }
       
   922     else {
       
   923         glClearColorx(0, 0, 0, 0);
       
   924         glClearDepthx(1 << 16);
       
   925         glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
       
   926         if (ctx->target.buffered) {
       
   927             ctx->backBuffer.contentsValid = M3G_TRUE;
       
   928         }
       
   929     }
       
   930         
       
   931     m3gReleaseFrameBuffer(ctx);
       
   932 }
       
   933 
       
   934 /*!
       
   935  * \internal
       
   936  * \brief Draws a batch of primitives
       
   937  *
       
   938  * This is the place most rendering commands are eventually routed to;
       
   939  * sprites and backgrounds are the only exception to this. We assume
       
   940  * that all eror checking has been performed at this point.
       
   941  */
       
   942 static void m3gDrawMesh(RenderContext *ctx,
       
   943                         const VertexBuffer *vb,
       
   944                         const IndexBuffer *ib,
       
   945                         const Appearance *app,
       
   946                         const M3GMatrix *modelTransform,
       
   947                         M3Gint alphaFactor,
       
   948                         M3Gint scope)
       
   949 {
       
   950     M3G_VALIDATE_OBJECT(ctx);
       
   951     M3G_VALIDATE_OBJECT(vb);
       
   952     M3G_VALIDATE_OBJECT(ib);
       
   953     M3G_VALIDATE_OBJECT(app);
       
   954 
       
   955     /* Check whether we need to use alternate rendering to get
       
   956      * two-sided lighting */
       
   957     if (m3gGetTwoSidedLightingWorkaround(M3G_INTERFACE(ctx))) {
       
   958         if (m3gSplitDrawMesh(ctx, vb, ib, app, modelTransform, alphaFactor, scope)) {
       
   959             return;
       
   960         }
       
   961     }
       
   962 
       
   963     M3G_ASSERT(m3gInRange(alphaFactor, 0, 0x10000));
       
   964     
       
   965     if (m3gGetColorMaskWorkaround(M3G_INTERFACE(ctx))) {
       
   966 		m3gUpdateColorMaskStatus(ctx, m3gColorMask(app), m3gAlphaMask(app));
       
   967     }
       
   968     
       
   969     /* Load lights */
       
   970     
       
   971     m3gApplyLights(ctx, scope);
       
   972     
       
   973     /* Apply the extra modeling transformation if present */
       
   974     
       
   975     if (modelTransform != NULL) {
       
   976 		float transform[16];
       
   977 		m3gGetMatrixColumns(modelTransform, transform);
       
   978         
       
   979         glPushMatrix();
       
   980         glMultMatrixf(transform);
       
   981     }
       
   982 
       
   983     /* Check whether we need to create an alpha-factored color cache
       
   984      * for the vertex buffer; this requires unlocking the frame buffer
       
   985      * for a while, and we may even run out of memory in the process,
       
   986      * but we still need to exit with the frame buffer lock and the
       
   987      * matrix stack in the expected state */
       
   988 
       
   989     if (alphaFactor < 0x10000 && !m3gValidateAlphaCache(vb)) {
       
   990         M3Gbool ok;
       
   991         m3gReleaseFrameBuffer(ctx);
       
   992         ok = m3gCreateAlphaColorCache(vb->colors);
       
   993         m3gLockFrameBuffer(ctx);
       
   994         if (!ok) {
       
   995             goto RestoreModelview; /* let's just skip the drawing part */
       
   996         }
       
   997     }
       
   998 
       
   999 #   if defined(M3G_NGL_TEXTURE_API)
       
  1000     /* Similarly to the alpha cache above, also check whether any
       
  1001      * textures may need to allocate mipmaps at this point */
       
  1002     {
       
  1003         M3Gint i;
       
  1004         for (i = 0; i < M3G_NUM_TEXTURE_UNITS; ++i) {
       
  1005             Texture *tex = app->texture[i];
       
  1006             if (tex && !m3gValidateTextureMipmapping(tex)) {
       
  1007                 M3Gbool ok;
       
  1008                 m3gReleaseFrameBuffer(ctx);
       
  1009                 ok = m3gValidateMipmapMemory(m3gGetTextureImage(tex));
       
  1010                 m3gLockFrameBuffer(ctx);
       
  1011                 if (!ok) {
       
  1012                     goto RestoreModelview;
       
  1013                 }
       
  1014             }
       
  1015         }
       
  1016     }
       
  1017 #   endif
       
  1018     
       
  1019     /* Load up the rest of the stuff we need for rendering; note that
       
  1020      * the vertex buffer scale and bias apply to the texture matrix
       
  1021      * from the appearance object, so they need to be applied last */
       
  1022     
       
  1023     m3gApplyAppearance(app, ctx, alphaFactor);
       
  1024     m3gLockVertexBuffer(vb, alphaFactor);
       
  1025     m3gApplyScaleAndBias(vb);
       
  1026     
       
  1027     /* All ready, render and then release the stuff we bound above */
       
  1028     
       
  1029     m3gSendIndexBuffer(ib);
       
  1030     m3gReleaseVertexBuffer(vb);
       
  1031     m3gReleaseTextures(app);
       
  1032 
       
  1033     /* Restore viewing-only modelview if changed */
       
  1034 
       
  1035 RestoreModelview:
       
  1036     if (modelTransform != NULL) {
       
  1037         glPopMatrix();
       
  1038     }
       
  1039 }
       
  1040 
       
  1041 /*!
       
  1042  * \internal
       
  1043  * \brief Validates background format against current target
       
  1044  *
       
  1045  * \retval M3G_TRUE valid format
       
  1046  * \retval M3G_FALSE invalid format
       
  1047  */
       
  1048 static M3Gbool m3gValidateBackground(RenderContext *ctx, Background *bg)
       
  1049 {
       
  1050     /* Check that source image and target formats match */
       
  1051     if (bg != NULL && bg->image != NULL) {
       
  1052         M3GPixelFormat boundFormat =
       
  1053             (ctx->target.type == SURFACE_IMAGE)
       
  1054             ? m3gPixelFormat(((const Image *)ctx->target.handle)->format)
       
  1055             : ctx->target.format;
       
  1056         if (ctx->target.type == SURFACE_IMAGE && boundFormat == M3G_RGBA8) {
       
  1057             return (m3gGetFormat(bg->image) == M3G_RGBA);
       
  1058         }
       
  1059         else {
       
  1060             return (m3gGetFormat(bg->image) == M3G_RGB);
       
  1061         }
       
  1062     }
       
  1063 
       
  1064     return M3G_TRUE;
       
  1065 }
       
  1066 
       
  1067 /*----------------------------------------------------------------------
       
  1068  * Virtual function table
       
  1069  *--------------------------------------------------------------------*/
       
  1070 
       
  1071 static const ObjectVFTable m3gvf_RenderContext = {
       
  1072     NULL, /* ApplyAnimation */
       
  1073     NULL, /* IsCompatible */
       
  1074     NULL, /* UpdateProperty */
       
  1075     NULL, /* GetReference */
       
  1076     NULL, /* find */
       
  1077     NULL, /* CreateClone */
       
  1078     m3gDestroyContext
       
  1079 };
       
  1080 
       
  1081 
       
  1082 /*----------------------------------------------------------------------
       
  1083  * Public API
       
  1084  *--------------------------------------------------------------------*/
       
  1085 
       
  1086 /*!
       
  1087  * \brief Creates and initializes a new rendering context
       
  1088  *
       
  1089  * \param bufferBits buffer bitmask
       
  1090  * \param width maximum width of context
       
  1091  * \param height maximum height of context
       
  1092  * \param modeBits hint bitmask
       
  1093  * \param mem pointer to memory block to allocate from
       
  1094  */
       
  1095 /*@access M3GInterface@*/
       
  1096 /*@access M3GRenderContext@*/
       
  1097 /*@only@*/
       
  1098 M3G_API M3GRenderContext m3gCreateContext(M3GInterface interface)/*@*/
       
  1099 {
       
  1100     Interface *m3g = (Interface*) interface;
       
  1101     M3G_VALIDATE_INTERFACE(m3g);
       
  1102         
       
  1103     {
       
  1104         RenderContext *ctx =
       
  1105             (RenderContext*) m3gAllocZ(m3g, (int) sizeof(RenderContext));
       
  1106         if (ctx == NULL) {
       
  1107             return NULL; /* m3gAlloc automatically raises out-of-mem */
       
  1108         }
       
  1109 
       
  1110 		ctx->renderQueue = m3gCreateRenderQueue(m3g);
       
  1111         if (ctx->renderQueue == NULL) {
       
  1112             m3gFree(m3g, ctx);
       
  1113             return NULL;
       
  1114         }
       
  1115         ctx->bufferBits = M3G_COLOR_BUFFER_BIT|M3G_DEPTH_BUFFER_BIT;
       
  1116         ctx->depthNear = 0.0f;
       
  1117         ctx->depthFar = 1.0f;
       
  1118 
       
  1119         m3gInitObject(&ctx->object, m3g, M3G_CLASS_RENDER_CONTEXT);
       
  1120 
       
  1121 		m3gSetAlphaWrite(ctx, M3G_TRUE);
       
  1122 
       
  1123         if (m3gGetColorMaskWorkaround(M3G_INTERFACE(ctx))) {
       
  1124             ctx->currentColorWrite = M3G_TRUE;
       
  1125             ctx->currentAlphaWrite = m3gGetAlphaWrite(ctx);
       
  1126         }
       
  1127         
       
  1128 		return (M3GRenderContext)ctx;
       
  1129     }
       
  1130 }
       
  1131 
       
  1132 /*!
       
  1133  * \brief Sets the buffers to use for subsequent rendering
       
  1134  */
       
  1135 M3G_API M3Gbool m3gSetRenderBuffers(M3GRenderContext hCtx,
       
  1136                                     M3Gbitmask bufferBits)
       
  1137 {
       
  1138     RenderContext *ctx = (RenderContext *) hCtx;
       
  1139     M3G_VALIDATE_OBJECT(ctx);
       
  1140 
       
  1141     if ((bufferBits & ~(M3G_COLOR_BUFFER_BIT|M3G_DEPTH_BUFFER_BIT|M3G_STENCIL_BUFFER_BIT|M3G_MULTISAMPLE_BUFFER_BIT)) != 0) {
       
  1142         m3gRaiseError(M3G_INTERFACE(ctx), M3G_INVALID_VALUE);
       
  1143         return M3G_FALSE;
       
  1144     }
       
  1145     ctx->bufferBits = bufferBits;
       
  1146     return M3G_TRUE;
       
  1147 }
       
  1148 
       
  1149 /*!
       
  1150  * \brief Sets the rendering quality hints to use for subsequent
       
  1151  * rendering
       
  1152  *
       
  1153  * \note This may not take effect before the target is released and
       
  1154  * rebound
       
  1155  */
       
  1156 M3G_API M3Gbool m3gSetRenderHints(M3GRenderContext hCtx, M3Gbitmask modeBits)
       
  1157 {
       
  1158     RenderContext *ctx = (RenderContext *) hCtx;
       
  1159     M3G_VALIDATE_OBJECT(ctx);
       
  1160 
       
  1161     if ((modeBits & ~(M3G_OVERWRITE_BIT|M3G_ANTIALIAS_BIT|M3G_DITHER_BIT|M3G_TRUECOLOR_BIT)) != 0) {
       
  1162         m3gRaiseError(M3G_INTERFACE(ctx), M3G_INVALID_VALUE);
       
  1163         return M3G_FALSE;
       
  1164     }
       
  1165     
       
  1166     /* Disable features not supported in the current configuration */
       
  1167 
       
  1168     if (M3G_SUPPORT_ANTIALIASING == M3G_FALSE ||
       
  1169         !m3gIsAntialiasingSupported(M3G_INTERFACE(ctx))) {
       
  1170         modeBits &= ~M3G_ANTIALIAS_BIT;
       
  1171     }
       
  1172     if (M3G_SUPPORT_DITHERING == M3G_FALSE) {
       
  1173         modeBits &= ~M3G_DITHER_BIT;
       
  1174     }
       
  1175     if (M3G_SUPPORT_TRUE_COLOR == M3G_FALSE) {
       
  1176         modeBits &= ~M3G_TRUECOLOR_BIT;
       
  1177     }
       
  1178 
       
  1179     ctx->modeBits = modeBits;
       
  1180     return M3G_TRUE;
       
  1181 }
       
  1182 
       
  1183 M3G_API void m3gBindImageTarget(M3GRenderContext hCtx, M3GImage hImage)
       
  1184 {
       
  1185     RenderContext *ctx = (RenderContext *) hCtx;
       
  1186     Image *img = (Image *) hImage;
       
  1187     M3G_VALIDATE_OBJECT(ctx);
       
  1188     M3G_VALIDATE_OBJECT(img);
       
  1189 
       
  1190     M3G_LOG1(M3G_LOG_RENDERING, "Binding image target 0x%08X\n",
       
  1191              (unsigned) img);
       
  1192 
       
  1193     /* Check for image-specific errors */
       
  1194     
       
  1195     if ((img->flags & M3G_DYNAMIC) == 0
       
  1196         || !m3gValidTargetFormat(img->internalFormat)) {
       
  1197         
       
  1198         m3gRaiseError(M3G_INTERFACE(ctx), M3G_INVALID_ENUM);
       
  1199         return;
       
  1200     }
       
  1201 
       
  1202     /* Do the generic checking and set-up */
       
  1203     
       
  1204     if (!m3gBindRenderTarget(ctx,
       
  1205                              SURFACE_IMAGE,
       
  1206                              img->width, img->height,
       
  1207                              img->internalFormat,
       
  1208                              (M3Guint) hImage)) {
       
  1209         return; /* appropriate error raised automatically */
       
  1210     }
       
  1211 
       
  1212     /* Set up image-specific parameters */
       
  1213     
       
  1214 #   if defined(M3G_NGL_CONTEXT_API)
       
  1215     ctx->target.stride = m3gGetImageStride(img);
       
  1216     ctx->target.pixels = NULL;
       
  1217 #   endif
       
  1218     
       
  1219     m3gAddRef((Object*) img);
       
  1220 }
       
  1221 
       
  1222 /*!
       
  1223  */
       
  1224 M3G_API M3Guint m3gGetUserHandle(M3GRenderContext hCtx)
       
  1225 {
       
  1226     RenderContext *ctx = (RenderContext *) hCtx;
       
  1227     M3G_VALIDATE_OBJECT(ctx);
       
  1228 
       
  1229     if (ctx->target.type == SURFACE_MEMORY) {
       
  1230         return ctx->target.handle;
       
  1231     }
       
  1232     return 0;
       
  1233 }
       
  1234 
       
  1235 /*!
       
  1236  */
       
  1237 M3G_API void m3gSetUserData(M3GRenderContext hCtx, M3Guint hData)
       
  1238 {
       
  1239     RenderContext *ctx = (RenderContext *) hCtx;
       
  1240     M3G_VALIDATE_OBJECT(ctx);
       
  1241     ctx->target.userData = hData;
       
  1242 }
       
  1243 
       
  1244 /*!
       
  1245  */
       
  1246 M3G_API M3Guint m3gGetUserData(M3GRenderContext hCtx)
       
  1247 {
       
  1248     RenderContext *ctx = (RenderContext *) hCtx;
       
  1249     M3G_VALIDATE_OBJECT(ctx);
       
  1250     return ctx->target.userData;
       
  1251 }
       
  1252 
       
  1253 /*!
       
  1254  * \brief Clears the current buffer(s)
       
  1255  */
       
  1256 M3G_API void m3gClear(M3GRenderContext context, M3GBackground hBackground)
       
  1257 {
       
  1258     RenderContext *ctx = (RenderContext*) context;
       
  1259     Background *bg = (Background *) hBackground;
       
  1260     M3G_VALIDATE_OBJECT(ctx);
       
  1261 
       
  1262     M3G_LOG(M3G_LOG_STAGES, "Clearing frame buffer\n");
       
  1263     
       
  1264     /* Check errors */
       
  1265     
       
  1266     if (ctx->target.type == SURFACE_NONE) {
       
  1267         m3gRaiseError(M3G_INTERFACE(context), M3G_INVALID_OPERATION);
       
  1268         return;
       
  1269     }
       
  1270 
       
  1271     if(m3gValidateBackground(ctx, bg)) {
       
  1272         m3gClearInternal(ctx, bg);
       
  1273     }
       
  1274     else {
       
  1275         m3gRaiseError(M3G_INTERFACE(bg), M3G_INVALID_VALUE);
       
  1276     }
       
  1277 }
       
  1278 
       
  1279 /*!
       
  1280  * \brief Release the currently bound color buffer
       
  1281  *
       
  1282  * Flushes all rendering and commits the final result to the currently
       
  1283  * bound target color buffer. Any changes to the target buffer since
       
  1284  * it was bound may be overwritten.
       
  1285  */
       
  1286 M3G_API void m3gReleaseTarget(M3GRenderContext context)
       
  1287 {
       
  1288     RenderContext *ctx = (RenderContext*) context;
       
  1289     M3G_VALIDATE_OBJECT(ctx);
       
  1290 
       
  1291     M3G_LOG(M3G_LOG_RENDERING, "Releasing target\n");
       
  1292     
       
  1293     if (ctx->target.type == SURFACE_NONE) {
       
  1294         return;
       
  1295     }
       
  1296     
       
  1297     m3gMakeCurrent(ctx);
       
  1298 
       
  1299     if (m3gGetColorMaskWorkaround(M3G_INTERFACE(ctx))) {
       
  1300         m3gUpdateColorMaskStatus(ctx, M3G_TRUE, M3G_TRUE);
       
  1301     }
       
  1302 
       
  1303     glFinish();
       
  1304 
       
  1305     /* Update the real target if we rendered into the back buffer */
       
  1306     
       
  1307     if (ctx->target.buffered) {
       
  1308         m3gUpdateTargetBuffer(ctx);
       
  1309     }
       
  1310 
       
  1311     /* Invalidate Image targets so that mipmap levels and/or OpenGL
       
  1312      * texture objects are updated accordingly */
       
  1313     
       
  1314     if (ctx->target.type == SURFACE_IMAGE) {
       
  1315         Image *img = (Image *) ctx->target.handle;
       
  1316         M3G_VALIDATE_OBJECT(img);
       
  1317         m3gInvalidateImage(img);
       
  1318         m3gDeleteRef((Object*) img);
       
  1319     }
       
  1320 
       
  1321     /* Swap in case we rendered onto a double-buffered surface,
       
  1322      * release any GL resources that might have been release since the
       
  1323      * last time we rendered, then release the GL context so we don't
       
  1324      * hog resources */
       
  1325 #   if !defined(M3G_NGL_CONTEXT_API)
       
  1326     if (ctx->target.type != SURFACE_EGL) {
       
  1327     m3gSwapBuffers(ctx->target.surface);
       
  1328     }
       
  1329 #   endif
       
  1330     m3gCollectGLObjects(M3G_INTERFACE(ctx));
       
  1331 #   if !defined(M3G_NGL_CONTEXT_API)
       
  1332     m3gMakeGLCurrent(NULL);
       
  1333     ctx->target.surface = NULL;
       
  1334 #   else
       
  1335     if (ctx->target.type == SURFACE_MEMORY && ctx->target.pixels == NULL) {
       
  1336         m3gSignalTargetRelease(M3G_INTERFACE(ctx), ctx->target.handle);
       
  1337     }
       
  1338 #   endif
       
  1339 
       
  1340     ctx->target.type = SURFACE_NONE;
       
  1341     ctx->renderQueue->root = NULL;
       
  1342 
       
  1343 #   if (M3G_PROFILE_LOG_INTERVAL > 0)
       
  1344     m3gLogProfileCounters(M3G_INTERFACE(ctx));
       
  1345 #   endif
       
  1346 }
       
  1347 
       
  1348 /*!
       
  1349  * \brief Sets a camera for this context
       
  1350  */
       
  1351 M3G_API void m3gSetCamera(M3GRenderContext context,
       
  1352                           M3GCamera hCamera,
       
  1353                           M3GMatrix *transform)
       
  1354 {
       
  1355 	Matrix m;
       
  1356     RenderContext *ctx = (RenderContext*) context;
       
  1357 	const Camera *camera = (Camera *)hCamera;
       
  1358 
       
  1359     M3G_VALIDATE_OBJECT(ctx);
       
  1360 
       
  1361     M3G_ASSIGN_REF(ctx->camera, camera);
       
  1362 
       
  1363 	if (transform != NULL) {
       
  1364 		if (!m3gMatrixInverse(&m, transform)) {
       
  1365             m3gRaiseError(M3G_INTERFACE(ctx), M3G_ARITHMETIC_ERROR);
       
  1366             return;
       
  1367         }
       
  1368 	}
       
  1369 	else {
       
  1370 		m3gIdentityMatrix(&m);
       
  1371 	}
       
  1372 
       
  1373 	m3gGetMatrixColumns(&m, ctx->viewTransform);
       
  1374 
       
  1375     ctx->lastScope = 0;
       
  1376 }
       
  1377 
       
  1378 /*!
       
  1379  * \brief Adds a light to the light array for this context
       
  1380  */
       
  1381 M3G_API M3Gint m3gAddLight(M3GRenderContext hCtx,
       
  1382                            M3GLight hLight,
       
  1383                            const M3GMatrix *transform)
       
  1384 {
       
  1385     RenderContext *ctx = (RenderContext *)hCtx;
       
  1386     Light *light = (Light *)hLight;
       
  1387     M3G_VALIDATE_OBJECT(ctx);
       
  1388 
       
  1389     if (light == NULL) {
       
  1390         m3gRaiseError(M3G_INTERFACE(ctx), M3G_INVALID_VALUE);
       
  1391         return -1;
       
  1392     }
       
  1393     else {
       
  1394         LightManager *mgr = &ctx->lightManager;
       
  1395         M3G_VALIDATE_OBJECT(light);
       
  1396         ctx->lastScope = 0;
       
  1397         return m3gInsertLight(mgr, light, transform, M3G_INTERFACE(ctx));
       
  1398     }
       
  1399 }
       
  1400 
       
  1401 /**
       
  1402  * \brief Sets a light for this context
       
  1403  */
       
  1404 M3G_API void m3gSetLight(M3GRenderContext context,
       
  1405                          M3Gint lightIndex,
       
  1406                          M3GLight hLight,
       
  1407                          const M3GMatrix *transform)
       
  1408 {
       
  1409     RenderContext *ctx = (RenderContext*) context;
       
  1410 	Light *light = (Light *)hLight;
       
  1411     M3G_VALIDATE_OBJECT(ctx);
       
  1412 
       
  1413 	/* Check for invalid arguments */
       
  1414 	if (lightIndex < 0 || lightIndex >= m3gLightArraySize(&ctx->lightManager)) {
       
  1415 		m3gRaiseError(M3G_INTERFACE(ctx), M3G_INVALID_INDEX);
       
  1416         return;
       
  1417 	}
       
  1418 
       
  1419     ctx->lastScope = 0;
       
  1420     m3gReplaceLight(&ctx->lightManager, lightIndex, light, transform);
       
  1421 }
       
  1422 
       
  1423 /*!
       
  1424  * \brief Removes all lights from this context
       
  1425  */
       
  1426 M3G_API void m3gClearLights(M3GRenderContext context)
       
  1427 {
       
  1428     RenderContext *ctx = (RenderContext *)context;
       
  1429     M3G_VALIDATE_OBJECT(ctx);
       
  1430     ctx->lastScope = 0;
       
  1431     m3gClearLights2(&ctx->lightManager);
       
  1432 }
       
  1433 
       
  1434 /*!
       
  1435  * \brief Sets the viewport
       
  1436  *
       
  1437  */
       
  1438 M3G_API void m3gSetViewport(M3GRenderContext hCtx,
       
  1439                             M3Gint x, M3Gint y,
       
  1440                             M3Gint width, M3Gint height)
       
  1441 {
       
  1442     RenderContext *ctx = (RenderContext *)hCtx;
       
  1443     M3G_VALIDATE_OBJECT(ctx);
       
  1444 
       
  1445     /* Note that the error checking here differs from that specified
       
  1446      * for the Java API; this is to avoid complications when setting
       
  1447      * from BindTarget where the clip rectangle may be zero.
       
  1448      * Additional checks are performed in the Java glue code. */
       
  1449     
       
  1450     if (width < 0 || height < 0) {
       
  1451         m3gRaiseError(M3G_INTERFACE(ctx), M3G_INVALID_VALUE);
       
  1452         return;
       
  1453     }
       
  1454     
       
  1455     width = M3G_MIN(width, M3G_MAX_VIEWPORT_DIMENSION);
       
  1456     height = M3G_MIN(height, M3G_MAX_VIEWPORT_DIMENSION);
       
  1457     
       
  1458     ctx->viewport.x = x;
       
  1459     ctx->viewport.y = ctx->target.height - (y + height);
       
  1460     ctx->viewport.width = width;
       
  1461     ctx->viewport.height = height;
       
  1462     m3gUpdateScissor(ctx);
       
  1463 }
       
  1464 
       
  1465 
       
  1466 /*!
       
  1467  * \brief Gets the viewport
       
  1468  */
       
  1469 M3G_API void m3gGetViewport(M3GRenderContext hCtx,
       
  1470                             M3Gint *x, M3Gint *y,
       
  1471                             M3Gint *width, M3Gint *height)
       
  1472 {
       
  1473     RenderContext *ctx = (RenderContext *)hCtx;
       
  1474     M3G_VALIDATE_OBJECT(ctx);
       
  1475 
       
  1476     *x = ctx->viewport.x;
       
  1477     *y = ctx->target.height - (ctx->viewport.y + ctx->viewport.height);
       
  1478     *width = ctx->viewport.width;
       
  1479     *height = ctx->viewport.height;
       
  1480 }
       
  1481 
       
  1482 /*!
       
  1483  * \brief Sets the scissor rectangle
       
  1484  */
       
  1485 M3G_API void m3gSetClipRect(M3GRenderContext hCtx,
       
  1486                             M3Gint x, M3Gint y,
       
  1487                             M3Gint width, M3Gint height)
       
  1488 {
       
  1489     RenderContext *ctx = (RenderContext *)hCtx;
       
  1490     M3G_VALIDATE_OBJECT(ctx);
       
  1491 
       
  1492     if (width < 0 || height < 0) {
       
  1493         m3gRaiseError(M3G_INTERFACE(ctx), M3G_INVALID_VALUE);
       
  1494         return;
       
  1495     }
       
  1496     ctx->clip.x0 = x;
       
  1497     ctx->clip.y0 = ctx->target.height - (y + height);
       
  1498     ctx->clip.x1 = x + width;
       
  1499     ctx->clip.y1 = ctx->clip.y0 + height;
       
  1500     m3gValidateClipRect(ctx);
       
  1501     m3gUpdateScissor(ctx);
       
  1502 }
       
  1503 
       
  1504 /*!
       
  1505  * \brief Sets the physical display area
       
  1506  *
       
  1507  * The display are is normally set to the full rendering targte size
       
  1508  * in m3gBindTarget, but this function allows overriding the default
       
  1509  * setting.
       
  1510  *
       
  1511  * Any pixels outside of the display area can be discarded for
       
  1512  * performance.  The origin is assumed to be in the top-left corner of
       
  1513  * the rendering target.
       
  1514  */
       
  1515 M3G_API void m3gSetDisplayArea(M3GRenderContext hCtx,
       
  1516                                M3Gint width, M3Gint height)
       
  1517 {
       
  1518     RenderContext *ctx = (RenderContext*) hCtx;
       
  1519     M3G_VALIDATE_OBJECT(ctx);
       
  1520     
       
  1521     ctx->display.width = M3G_MIN(width, ctx->target.width);
       
  1522     ctx->display.height = M3G_MIN(height, ctx->target.height);
       
  1523 }
       
  1524 
       
  1525 /*!
       
  1526  * \brief Sets depth range
       
  1527  * 
       
  1528  */
       
  1529 M3G_API void m3gSetDepthRange(M3GRenderContext hCtx,
       
  1530                               M3Gfloat depthNear, M3Gfloat depthFar)
       
  1531 {
       
  1532     RenderContext *ctx = (RenderContext *)hCtx;
       
  1533     M3G_VALIDATE_OBJECT(ctx);
       
  1534 	
       
  1535 	if (depthNear < 0 || depthNear > 1.0f || depthFar < 0 || depthFar > 1.0f) {
       
  1536 		m3gRaiseError(M3G_INTERFACE(ctx), M3G_INVALID_VALUE);
       
  1537         return;
       
  1538     }
       
  1539 
       
  1540 	ctx->depthNear = depthNear;
       
  1541 	ctx->depthFar = depthFar;
       
  1542 }
       
  1543 
       
  1544 /*!
       
  1545  * \brief Gets depth range
       
  1546  * 
       
  1547  */
       
  1548 M3G_API void m3gGetDepthRange(M3GRenderContext hCtx,
       
  1549                               M3Gfloat *depthNear, M3Gfloat *depthFar)
       
  1550 {
       
  1551     RenderContext *ctx = (RenderContext *)hCtx;
       
  1552     M3G_VALIDATE_OBJECT(ctx);
       
  1553 	
       
  1554 	*depthNear = ctx->depthNear;
       
  1555 	*depthFar= ctx->depthFar;
       
  1556 }
       
  1557 
       
  1558 /*!
       
  1559  * \brief Gets current view transform
       
  1560  * 
       
  1561  */
       
  1562 
       
  1563 M3G_API void m3gGetViewTransform(M3GRenderContext hCtx,
       
  1564                                  M3GMatrix *transform)
       
  1565 {
       
  1566     RenderContext *ctx = (RenderContext *)hCtx;
       
  1567     M3G_VALIDATE_OBJECT(ctx);
       
  1568     m3gSetMatrixColumns(transform, ctx->viewTransform);
       
  1569     m3gInvertMatrix(transform); /*lint !e534 always invertible */
       
  1570 }
       
  1571 
       
  1572 /*!
       
  1573  * \brief Gets current Camera
       
  1574  * 
       
  1575  */
       
  1576 
       
  1577 M3G_API M3GCamera m3gGetCamera(M3GRenderContext hCtx)
       
  1578 {
       
  1579     RenderContext *ctx = (RenderContext *)hCtx;
       
  1580     M3G_VALIDATE_OBJECT(ctx);
       
  1581     return (M3GCamera) ctx->camera;
       
  1582 }
       
  1583 
       
  1584 /*!
       
  1585  * \brief Gets light transform of given light
       
  1586  * 
       
  1587  */
       
  1588 
       
  1589 M3G_API M3GLight m3gGetLightTransform (M3GRenderContext hCtx,
       
  1590                                        M3Gint lightIndex, M3GMatrix *transform)
       
  1591 {
       
  1592     RenderContext *ctx = (RenderContext *)hCtx;
       
  1593     M3G_VALIDATE_OBJECT(ctx);
       
  1594     return m3gGetLightTransformInternal(&ctx->lightManager, lightIndex, transform);
       
  1595 }
       
  1596 
       
  1597 /*!
       
  1598  * \brief Gets light count
       
  1599  * 
       
  1600  */
       
  1601 
       
  1602 M3G_API M3Gsizei m3gGetLightCount (M3GRenderContext hCtx)
       
  1603 {
       
  1604     RenderContext *ctx = (RenderContext *)hCtx;
       
  1605     M3G_VALIDATE_OBJECT(ctx);
       
  1606     return m3gLightArraySize(&ctx->lightManager);
       
  1607 }
       
  1608 
       
  1609 /*!
       
  1610  * \brief Renders a world
       
  1611  *
       
  1612  */
       
  1613 M3G_API void m3gRenderWorld(M3GRenderContext context, M3GWorld hWorld)
       
  1614 {
       
  1615 	Camera *camera;
       
  1616     RenderContext *ctx = (RenderContext*) context;
       
  1617 	World *world = (World *) hWorld;
       
  1618 
       
  1619     M3G_LOG1(M3G_LOG_STAGES, "Rendering World 0x%08X\n", (unsigned) world);
       
  1620     
       
  1621     M3G_VALIDATE_OBJECT(ctx);
       
  1622     M3G_VALIDATE_OBJECT(world);
       
  1623 
       
  1624 	camera = m3gGetActiveCamera(world);
       
  1625 
       
  1626     /* Check for errors */
       
  1627     
       
  1628     if (ctx->target.type == SURFACE_NONE) {
       
  1629         m3gRaiseError(M3G_INTERFACE(ctx), M3G_INVALID_OPERATION);
       
  1630         return;
       
  1631     }
       
  1632     
       
  1633 	if (camera == NULL ||
       
  1634         !m3gIsChildOf((Node *)world, (Node *)camera)) {
       
  1635 		m3gRaiseError(M3G_INTERFACE(ctx), M3G_INVALID_OPERATION);
       
  1636         return;
       
  1637 	}
       
  1638 
       
  1639     /* Exit if the camera will show nothing (zero view volume) */
       
  1640     
       
  1641     if (!m3gValidProjection(camera)) {
       
  1642         return;
       
  1643     }
       
  1644 
       
  1645     /* Override the currently set viewing transformation with identity
       
  1646      * (will fix this before we return) */
       
  1647     
       
  1648 	m3gSetCamera(ctx, camera, NULL);
       
  1649 
       
  1650     if (m3gValidateBackground(ctx, world->background)) {
       
  1651     	m3gClearInternal(ctx, world->background);
       
  1652     }
       
  1653     else {
       
  1654         m3gRaiseError(M3G_INTERFACE(world), M3G_INVALID_OPERATION);
       
  1655         return;
       
  1656     }
       
  1657 
       
  1658     /* All clear for rendering */
       
  1659     
       
  1660     M3G_LOG(M3G_LOG_RENDERING, "Rendering: start\n");    
       
  1661     M3G_ASSERT(ctx->renderQueue->root == NULL);
       
  1662     M3G_BEGIN_PROFILE(M3G_INTERFACE(ctx), M3G_PROFILE_VALIDATE);
       
  1663     
       
  1664     if (m3gValidateNode((Node*) world, NODE_RENDER_BIT, camera->node.scope)) {
       
  1665         M3Gbool setup;
       
  1666         SetupRenderState s;
       
  1667         M3G_END_PROFILE(M3G_INTERFACE(ctx), M3G_PROFILE_VALIDATE);
       
  1668 
       
  1669         /* We start the traversal from the camera, so set the initial
       
  1670          * camera-space transformation to identity */
       
  1671         
       
  1672         m3gIdentityMatrix(&s.toCamera);
       
  1673         s.cullMask = CULLMASK_ALL;
       
  1674         
       
  1675         m3gClearLights2(&ctx->lightManager);
       
  1676         
       
  1677         ctx->renderQueue->root = (Node *)world;
       
  1678         ctx->renderQueue->scope = camera->node.scope;
       
  1679         ctx->renderQueue->lightManager = &ctx->lightManager;
       
  1680         ctx->renderQueue->camera = camera;
       
  1681 
       
  1682         M3G_BEGIN_PROFILE(M3G_INTERFACE(ctx), M3G_PROFILE_SETUP);
       
  1683         
       
  1684         setup = M3G_VFUNC(Node, camera, setupRender)((Node *) camera,
       
  1685                                                      NULL,
       
  1686                                                      &s,
       
  1687                                                      ctx->renderQueue);
       
  1688         M3G_END_PROFILE(M3G_INTERFACE(ctx), M3G_PROFILE_SETUP);
       
  1689         M3G_LOG(M3G_LOG_RENDERING, "Rendering: commit\n");
       
  1690         M3G_BEGIN_PROFILE(M3G_INTERFACE(ctx), M3G_PROFILE_COMMIT);
       
  1691 
       
  1692         if (setup) {
       
  1693             m3gInitRender(ctx, RENDER_WORLD);
       
  1694             m3gLockFrameBuffer(ctx);
       
  1695             m3gCommit(ctx->renderQueue, ctx);
       
  1696             m3gReleaseFrameBuffer(ctx);
       
  1697         }
       
  1698         
       
  1699         M3G_END_PROFILE(M3G_INTERFACE(ctx), M3G_PROFILE_COMMIT);
       
  1700 
       
  1701         /* Fix light and camera transformations to be relative to world
       
  1702          * space on exit */
       
  1703     
       
  1704         if (setup) {
       
  1705             Matrix m;
       
  1706             if (m3gGetTransformTo((Node*) world, (Node*) camera, &m)) {
       
  1707                 m3gGetMatrixColumns(&m, ctx->viewTransform);
       
  1708                 if (m3gInvertMatrix(&m)) {
       
  1709                     m3gTransformLights(&ctx->lightManager, &m);
       
  1710                 }
       
  1711                 else {
       
  1712                     M3G_ASSERT(M3G_FALSE);
       
  1713                 }
       
  1714             }
       
  1715             else {
       
  1716                 M3G_ASSERT(M3G_FALSE);
       
  1717             }
       
  1718         }
       
  1719     }
       
  1720     
       
  1721 	m3gClearRenderQueue(ctx->renderQueue);
       
  1722     M3G_LOG(M3G_LOG_RENDERING, "Rendering: end\n");
       
  1723 }
       
  1724 
       
  1725 /*!
       
  1726  * \brief Renders a node or subtree
       
  1727  */
       
  1728 M3G_API void m3gRenderNode(M3GRenderContext context,
       
  1729                            M3GNode hNode,
       
  1730                            const M3GMatrix *transform)
       
  1731 {
       
  1732     RenderContext *ctx = (RenderContext*) context;
       
  1733     Node *node = (Node *) hNode;
       
  1734 
       
  1735     M3G_LOG1(M3G_LOG_STAGES, "Rendering Node 0x%08X\n", (unsigned) node);
       
  1736     
       
  1737     M3G_VALIDATE_OBJECT(ctx);
       
  1738     M3G_VALIDATE_OBJECT(node);
       
  1739 
       
  1740     /* Check for errors */
       
  1741     
       
  1742     if (node == NULL) {
       
  1743         m3gRaiseError(M3G_INTERFACE(ctx), M3G_NULL_POINTER);
       
  1744         return;
       
  1745     }
       
  1746 
       
  1747     if (ctx->target.type == SURFACE_NONE || ctx->camera == NULL) {
       
  1748         m3gRaiseError(M3G_INTERFACE(ctx), M3G_INVALID_OPERATION);
       
  1749         return;
       
  1750     }
       
  1751 
       
  1752     /* Exit if the camera will show nothing (zero view volume) */
       
  1753     
       
  1754     if (!m3gValidProjection(ctx->camera)) {
       
  1755         return;
       
  1756     }
       
  1757 
       
  1758     /* All clear, draw away */
       
  1759 
       
  1760     M3G_LOG(M3G_LOG_RENDERING, "Rendering: start\n");
       
  1761 	M3G_ASSERT(ctx->renderQueue->root == NULL);
       
  1762     M3G_BEGIN_PROFILE(M3G_INTERFACE(ctx), M3G_PROFILE_VALIDATE);
       
  1763     
       
  1764     if (m3gValidateNode(node, NODE_RENDER_BIT, ctx->camera->node.scope)) {
       
  1765         M3Gbool setup;
       
  1766         SetupRenderState s;
       
  1767         M3G_END_PROFILE(M3G_INTERFACE(ctx), M3G_PROFILE_VALIDATE);
       
  1768         
       
  1769         s.cullMask = CULLMASK_ALL;
       
  1770 
       
  1771         /* We start the traversal from world space, so preload the
       
  1772          * current camera-space transformation to get camera-space
       
  1773          * meshes and correct view frustum culling */
       
  1774         
       
  1775         m3gSetMatrixColumns(&s.toCamera, ctx->viewTransform);
       
  1776         if (transform) {
       
  1777             m3gMulMatrix(&s.toCamera, transform);
       
  1778         }
       
  1779         ctx->renderQueue->root = (Node *) node;
       
  1780         ctx->renderQueue->scope = ctx->camera->node.scope;
       
  1781         ctx->renderQueue->lightManager = NULL;
       
  1782         ctx->renderQueue->camera = ctx->camera;
       
  1783         
       
  1784         M3G_BEGIN_PROFILE(M3G_INTERFACE(ctx), M3G_PROFILE_SETUP);
       
  1785         
       
  1786         setup = M3G_VFUNC(Node, node, setupRender)(node,
       
  1787                                                    NULL,
       
  1788                                                    &s,
       
  1789                                                    ctx->renderQueue);
       
  1790         M3G_END_PROFILE(M3G_INTERFACE(ctx), M3G_PROFILE_SETUP);
       
  1791         M3G_LOG(M3G_LOG_RENDERING, "Rendering: commit\n");
       
  1792         M3G_BEGIN_PROFILE(M3G_INTERFACE(ctx), M3G_PROFILE_COMMIT);
       
  1793         
       
  1794         if (setup) {
       
  1795             m3gInitRender(ctx, RENDER_NODES);
       
  1796             m3gLockFrameBuffer(ctx);
       
  1797     		m3gCommit(ctx->renderQueue, ctx);
       
  1798             m3gReleaseFrameBuffer(ctx);
       
  1799         }
       
  1800         
       
  1801         M3G_END_PROFILE(M3G_INTERFACE(ctx), M3G_PROFILE_COMMIT);
       
  1802 	}
       
  1803 
       
  1804 	m3gClearRenderQueue(ctx->renderQueue);
       
  1805     
       
  1806     M3G_LOG(M3G_LOG_RENDERING, "Rendering: end\n");
       
  1807 }
       
  1808 
       
  1809 /*!
       
  1810  * \brief Render a set of primitives
       
  1811  * 
       
  1812  */
       
  1813 M3G_API void m3gRender(M3GRenderContext context,
       
  1814                        M3GVertexBuffer hVertices,
       
  1815                        M3GIndexBuffer hIndices,
       
  1816                        M3GAppearance hAppearance,
       
  1817                        const M3GMatrix *transformMatrix,
       
  1818                        M3Gfloat alphaFactor,
       
  1819                        M3Gint scope)
       
  1820 {
       
  1821     RenderContext *ctx = (RenderContext *) context;
       
  1822     const VertexBuffer *vb = (const VertexBuffer *) hVertices;
       
  1823     const IndexBuffer *ib = (const IndexBuffer *) hIndices;
       
  1824     const Appearance *app = (const Appearance *) hAppearance;
       
  1825     M3G_VALIDATE_OBJECT(ctx);
       
  1826 
       
  1827     M3G_LOG1(M3G_LOG_STAGES, "Rendering vertex buffer 0x%08X\n",
       
  1828              (unsigned) vb);
       
  1829     
       
  1830     /* Check validity of input */
       
  1831     
       
  1832     if (ctx->target.type == SURFACE_NONE || ctx->camera == NULL) {
       
  1833         m3gRaiseError(M3G_INTERFACE(ctx), M3G_INVALID_OPERATION);
       
  1834         return;
       
  1835     }
       
  1836     
       
  1837     /* Quick exit if out of scope or zero view volume */
       
  1838 
       
  1839     if ((scope & ctx->camera->node.scope) == 0
       
  1840         || !m3gValidProjection(ctx->camera)) {
       
  1841         return;
       
  1842     }
       
  1843 
       
  1844     if (vb == NULL || ib == NULL || app == NULL) {
       
  1845         m3gRaiseError(M3G_INTERFACE(ctx), M3G_INVALID_OBJECT);
       
  1846         return;
       
  1847     }
       
  1848 
       
  1849     if (!m3gValidateVertexBuffer(vb, app, m3gGetMaxIndex(ib))) {
       
  1850         m3gRaiseError(M3G_INTERFACE(ctx), M3G_INVALID_OPERATION);
       
  1851         return;
       
  1852     }
       
  1853 
       
  1854     /* Everything checks out, so draw */
       
  1855 
       
  1856     M3G_LOG(M3G_LOG_RENDERING, "Rendering: start immediate\n");
       
  1857     
       
  1858     m3gInitRender(ctx, RENDER_IMMEDIATE);
       
  1859     m3gLockFrameBuffer(ctx);
       
  1860     m3gDrawMesh(ctx,
       
  1861                 vb, ib, app,
       
  1862                 transformMatrix,
       
  1863                 m3gRoundToInt(
       
  1864                     m3gMul(alphaFactor,
       
  1865                            (M3Gfloat)(1 << NODE_ALPHA_FACTOR_BITS))),
       
  1866                 scope);
       
  1867     m3gReleaseFrameBuffer(ctx);
       
  1868     
       
  1869     M3G_LOG(M3G_LOG_RENDERING, "Rendering: end immediate\n");
       
  1870 }
       
  1871