
/*
 * Mesa 3-D graphics library
 * Version:  6.5
 *
 * Copyright (C) 1999-2006  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.
 *
 * Authors:
 *    Keith Whitwell <keith@tungstengraphics.com>
 */

/* Helper for drivers which find themselves rendering a range of
 * indices starting somewhere above zero.  Typically the application
 * is issuing multiple DrawArrays() or DrawElements() to draw
 * successive primitives layed out linearly in the vertex arrays.
 * Unless the vertex arrays are all in a VBO, the OpenGL semantics
 * imply that we need to re-upload the vertex data on each draw call.
 * In that case, we want to avoid starting the upload at zero, as it
 * will mean every draw call uploads an increasing amount of not-used
 * vertex data.  Worse - in the software tnl module, all those
 * vertices will be transformed and lit.
 *
 * If we just upload the new data, however, the indices will be
 * incorrect as we tend to upload each set of vertex data to a new
 * region.  
 *
 * This file provides a helper to adjust the arrays, primitives and
 * indices of a draw call so that it can be re-issued with a min_index
 * of zero.
 */

#include "main/glheader.h"
#include "main/imports.h"
#include "main/mtypes.h"

#include "vbo.h"


#define REBASE(TYPE) 						\
static void *rebase_##TYPE( const void *ptr,			\
			  GLuint count, 			\
			  TYPE min_index )			\
{								\
   const TYPE *in = (TYPE *)ptr;				\
   TYPE *tmp_indices = malloc(count * sizeof(TYPE));	\
   GLuint i;							\
								\
   for (i = 0; i < count; i++)  				\
      tmp_indices[i] = in[i] - min_index;			\
								\
   return (void *)tmp_indices;					\
}


REBASE(GLuint)
REBASE(GLushort)
REBASE(GLubyte)

GLboolean vbo_all_varyings_in_vbos( const struct gl_client_array *arrays[] )
{
   GLuint i;
   
   for (i = 0; i < VERT_ATTRIB_MAX; i++)
      if (arrays[i]->StrideB &&
	  arrays[i]->BufferObj->Name == 0)
	 return GL_FALSE;

   return GL_TRUE;
}

GLboolean vbo_any_varyings_in_vbos( const struct gl_client_array *arrays[] )
{
   GLuint i;

   for (i = 0; i < VERT_ATTRIB_MAX; i++)
      if (arrays[i]->BufferObj->Name != 0)
	 return GL_TRUE;

   return GL_FALSE;
}

/* Adjust primitives, indices and vertex definitions so that min_index
 * becomes zero. There are lots of reasons for wanting to do this, eg:
 *
 * Software tnl:
 *    - any time min_index != 0, otherwise unused vertices lower than
 *      min_index will be transformed.
 *
 * Hardware tnl:
 *    - if ib != NULL and min_index != 0, otherwise vertices lower than 
 *      min_index will be uploaded.  Requires adjusting index values.
 *
 *    - if ib == NULL and min_index != 0, just for convenience so this doesn't
 *      have to be handled within the driver.
 *
 * Hardware tnl with VBO support:
 *    - as above, but only when vertices are not (all?) in VBO's.
 *    - can't save time by trying to upload half a vbo - typically it is
 *      all or nothing.
 */
void vbo_rebase_prims( struct gl_context *ctx,
		       const struct gl_client_array *arrays[],
		       const struct _mesa_prim *prim,
		       GLuint nr_prims,
		       const struct _mesa_index_buffer *ib,
		       GLuint min_index,
		       GLuint max_index,
		       vbo_draw_func draw )
{
   struct gl_client_array tmp_arrays[VERT_ATTRIB_MAX];
   const struct gl_client_array *tmp_array_pointers[VERT_ATTRIB_MAX];

   struct _mesa_index_buffer tmp_ib;
   struct _mesa_prim *tmp_prims = NULL;
   const struct gl_client_array **saved_arrays = ctx->Array._DrawArrays;
   void *tmp_indices = NULL;
   GLuint i;

   assert(min_index != 0);

   if (0)
      printf("%s %d..%d\n", __FUNCTION__, min_index, max_index);


   /* XXX this path is disabled for now.
    * There's rendering corruption in some apps when it's enabled.
    */
   if (0 && ib && ctx->Extensions.ARB_draw_elements_base_vertex) {
      /* If we can just tell the hardware or the TNL to interpret our
       * indices with a different base, do so.
       */
      tmp_prims = (struct _mesa_prim *)malloc(sizeof(*prim) * nr_prims);

      for (i = 0; i < nr_prims; i++) {
	 tmp_prims[i] = prim[i];
	 tmp_prims[i].basevertex -= min_index;
      }

      prim = tmp_prims;
   } else if (ib) {
      /* Unfortunately need to adjust each index individually.
       */
      GLboolean map_ib = ib->obj->Name && !ib->obj->Pointer;
      void *ptr;

      if (map_ib) 
	 ctx->Driver.MapBufferRange(ctx, 0, ib->obj->Size, GL_MAP_READ_BIT,
				    ib->obj);


      ptr = ADD_POINTERS(ib->obj->Pointer, ib->ptr);

      /* Some users might prefer it if we translated elements to
       * GLuints here.  Others wouldn't...
       */
      switch (ib->type) {
      case GL_UNSIGNED_INT: 
	 tmp_indices = rebase_GLuint( ptr, ib->count, min_index );
	 break;
      case GL_UNSIGNED_SHORT: 
	 tmp_indices = rebase_GLushort( ptr, ib->count, min_index );
	 break;
      case GL_UNSIGNED_BYTE: 
	 tmp_indices = rebase_GLubyte( ptr, ib->count, min_index );
	 break;
      }      

      if (map_ib) 
	 ctx->Driver.UnmapBuffer(ctx, ib->obj);

      tmp_ib.obj = ctx->Shared->NullBufferObj;
      tmp_ib.ptr = tmp_indices;
      tmp_ib.count = ib->count;
      tmp_ib.type = ib->type;

      ib = &tmp_ib;
   }
   else {
      /* Otherwise the primitives need adjustment.
       */
      tmp_prims = (struct _mesa_prim *)malloc(sizeof(*prim) * nr_prims);

      for (i = 0; i < nr_prims; i++) {
	 /* If this fails, it could indicate an application error:
	  */
	 assert(prim[i].start >= min_index);

	 tmp_prims[i] = prim[i];
	 tmp_prims[i].start -= min_index;
      }

      prim = tmp_prims;
   }

   /* Just need to adjust the pointer values on each incoming array.
    * This works for VBO and non-vbo rendering and shouldn't pesimize
    * VBO-based upload schemes.  However this may still not be a fast
    * path for hardware tnl for VBO based rendering as most machines
    * will be happier if you just specify a starting vertex value in
    * each primitive.
    *
    * For drivers with hardware tnl, you only want to do this if you
    * are forced to, eg non-VBO indexed rendering with start != 0.
    */
   for (i = 0; i < VERT_ATTRIB_MAX; i++) {
      tmp_arrays[i] = *arrays[i];
      tmp_arrays[i].Ptr += min_index * tmp_arrays[i].StrideB;
      tmp_array_pointers[i] = &tmp_arrays[i];
   }
   
   /* Re-issue the draw call.
    */
   ctx->Array._DrawArrays = tmp_array_pointers;
   ctx->NewDriverState |= ctx->DriverFlags.NewArray;

   draw( ctx, 
	 prim,
	 nr_prims, 
	 ib, 
	 GL_TRUE,
	 0, 
	 max_index - min_index,
	 NULL );

   ctx->Array._DrawArrays = saved_arrays;
   ctx->NewDriverState |= ctx->DriverFlags.NewArray;
   
   if (tmp_indices)
      free(tmp_indices);
   
   if (tmp_prims)
      free(tmp_prims);
}



