# Copyright (c) 2001, Stanford University
# All rights reserved.
#
# See the file LICENSE.txt for information on redistributing this software.

# This script generates the packer_bbox.c file from gl_header.parsed

import sys
import cPickle
import string

import apiutil


apiutil.CopyrightC()

print """
/* DO NOT EDIT - THIS FILE GENERATED BY THE packer_bbox.py SCRIPT */

/* These functions pack glVertex functions and also update the bounding box
 * if the cr_packer_globals.updateBBOX variable is non-zero.
 */

#include "packer.h"
#include "cr_opcodes.h"
#include "pack_bbox.h"

#include <float.h>

/**
 * Reset packer bounding box to empty state.
 */
void crPackResetBoundingBox( CRPackContext *pc )
{
	pc->bounds_min.x =  FLT_MAX;
	pc->bounds_min.y =  FLT_MAX;
	pc->bounds_min.z =  FLT_MAX;
	pc->bounds_max.x = -FLT_MAX;
	pc->bounds_max.y = -FLT_MAX;
	pc->bounds_max.z = -FLT_MAX;
	pc->updateBBOX = 1;
}

/**
 * Query current bounding box.
 * \return GL_TRUE if non-empty box, GL_FALSE if empty box.
 */
GLboolean crPackGetBoundingBox( CRPackContext *pc,
                                GLfloat *xmin, GLfloat *ymin, GLfloat *zmin,
                                GLfloat *xmax, GLfloat *ymax, GLfloat *zmax)
{
	if (pc->bounds_min.x != FLT_MAX) {
		*xmin = pc->bounds_min.x;
		*ymin = pc->bounds_min.y;
		*zmin = pc->bounds_min.z;
		*xmax = pc->bounds_max.x;
		*ymax = pc->bounds_max.y;
		*zmax = pc->bounds_max.z;
		return GL_TRUE;
	}
	else {
		return GL_FALSE;
	}
}

"""

def WriteData( offset, arg_type, arg_name, is_swapped ):
	if string.find( arg_type, '*' ) != -1:
		retval = "\tWRITE_NETWORK_POINTER( %d, (void *) %s );" % (offset, arg_name )
	else:	
		if is_swapped:
			if arg_type == "GLfloat" or arg_type == "GLclampf":
				retval = "\tWRITE_DATA( %d, GLuint, SWAPFLOAT(%s) );" % (offset, arg_name)
			elif arg_type == "GLdouble" or arg_type == "GLclampd":
				retval = "\tWRITE_SWAPPED_DOUBLE( %d, %s );" % (offset, arg_name)
			elif apiutil.sizeof(arg_type) == 1:
				retval = "\tWRITE_DATA( %d, %s, %s );" % (offset, arg_type, arg_name)
			elif apiutil.sizeof(arg_type) == 2:
				retval = "\tWRITE_DATA( %d, %s, SWAP16(%s) );" % (offset, arg_type, arg_name)
			elif apiutil.sizeof(arg_type) == 4:
				retval = "\tWRITE_DATA( %d, %s, SWAP32(%s) );" % (offset, arg_type, arg_name)
		else:
			if arg_type == "GLdouble" or arg_type == "GLclampd":
				retval = "\tWRITE_DOUBLE( %d, %s );" % (offset, arg_name)
			else:
				retval = "\tWRITE_DATA( %d, %s, %s );" % (offset, arg_type, arg_name)
	return retval


def PrintFunction( func_name, extSuffix, num_coords, argtype,
				   do_swapped, do_count, do_vector ):
	"""
	Generate all the functions named crPackVertex[234][dfis][v]BBOX() and
	crPackVertex[234][dfis][v]BBOX_COUNT().
	We also handle glVertexAttrib*ARB.
	Note: func_name should not have an ARB suffix.
	"""

	if do_count:
		countSuffix = "_COUNT"
	else:
		countSuffix = ""

	if do_swapped:
		swapSuffix = "SWAP"
	else:
		swapSuffix = ""

	if func_name[0:12] == "VertexAttrib":
		isVertexAttrib = 1
	else:
		isVertexAttrib = 0

	if argtype[0] == "N":
		normalized = 1
	else:
		normalized = 0;

	if argtype == "b" or argtype == "Nb":
		vector_type = "GLbyte"
	elif argtype == "ub" or argtype == "Nub":
		vector_type = "GLubyte"
	elif argtype == "s" or argtype == "Ns":
		vector_type = "GLshort"
	elif argtype == "us" or argtype == "Nus":
		vector_type = "GLushort"
	elif argtype == "i" or argtype == "Ni":
		vector_type = "GLint"
	elif argtype == "ui" or argtype == "Nui":
		vector_type = "GLuint"
	elif argtype == "f":
		vector_type = "GLfloat"
	elif argtype == "d":
		vector_type = "GLdouble"
	else:
		print "type is %s" % argtype
		abort()

	if do_vector:
		if isVertexAttrib:
			func_name = 'VertexAttrib%d%sv' % (num_coords, argtype)
		else:
			func_name = 'Vertex%d%sv' % (num_coords,argtype)

	params = apiutil.Parameters(func_name + extSuffix)

	print 'void PACK_APIENTRY crPack%sBBOX%s%s( %s )' % (func_name + extSuffix, countSuffix,
			 swapSuffix, apiutil.MakeDeclarationString(params))
	print '{'

	if do_vector:
		# vector version
		packet_length = num_coords * apiutil.sizeof(vector_type)
		if isVertexAttrib:
			packet_length += 4  # for index
		if packet_length % 4 != 0:
			packet_length += 2

	else:
		# non-vector
		packet_length = apiutil.PacketLength( params )
		if isVertexAttrib:
			packet_length += 0  # for index
		if packet_length % 4 != 0:
			packet_length += 2


	print "\tCR_GET_PACKER_CONTEXT(pc);"
	print "\tunsigned char *data_ptr;"

	if normalized:
		if argtype == "Nb":
			t = "B"
		elif argtype == "Ni":
			t = "I"
		elif argtype == "Nui":
			t = "UI"
		elif argtype == "Nub":
			t = "UB"
		elif argtype == "Ns":
			t = "S"
		elif argtype == "Nus":
			t = "US"
		else:
			abort()
		if do_vector:
			print "\tCREATE_%dD_VFLOATS_%s_NORMALIZED();" % (num_coords, t)
		else:
			print "\tCREATE_%dD_FLOATS_%s_NORMALIZED();" % (num_coords, t)
	else:
		if do_vector:
			print "\tCREATE_%dD_VFLOATS();" % num_coords
		else:
			print "\tCREATE_%dD_FLOATS();" % num_coords

	print "\tCR_GET_BUFFERED%s_POINTER( pc, %d );" % (countSuffix, packet_length)

	# Bounding box code
	if isVertexAttrib:
		print "\tif (pc->updateBBOX && index == 0)"
	else:
		print "\tif (pc->updateBBOX)"
	print "\t{"
	if num_coords < 4:
		print "\t\tUPDATE_%dD_BBOX();" % num_coords
	else:
		print "\t\tUPDATE_3D_BBOX();"
	print "\t}"

	if isVertexAttrib:
		print "\tif (index > 0) {"
		t = argtype
		print "\t\tpc->current.c.vertexAttrib.%s%d[index] = data_ptr + 4;" % (t, num_coords)
		print "\t\tpc->current.attribsUsedMask |= (1 << index);"
		if do_count:
			print "\t\tpc->current.vtx_count--;"

		print "\t}"

		fname = func_name + extSuffix
		if do_vector:
			# use non-vector opcode
			opcode = apiutil.OpcodeName( func_name[:-1] + extSuffix )
		else:
			opcode = apiutil.OpcodeName( func_name + extSuffix )
	counter = 0

	if do_vector:
		if isVertexAttrib:
			if do_swapped:
				print "\tWRITE_DATA( 0, GLuint, SWAP32(index) );"
			else:
				print "\tWRITE_DATA( 0, GLuint, index );"
			counter += 4
			argname = params[1][0]  # skip 'index' parameter
		else:
			argname = params[0][0]

		for index in range(num_coords):
			print WriteData( counter, vector_type, "%s[%d]" % (argname, index), do_swapped )
			counter += apiutil.sizeof(vector_type)

		if isVertexAttrib:
			if do_vector == 2:
				# this is a bit of a hack
				print "\tWRITE_OPCODE( pc, %s );" % apiutil.OpcodeName( func_name + "ARB" )
			else:
				print "\tWRITE_OPCODE( pc, %s );" % apiutil.OpcodeName( func_name[:-1] + "ARB" )
		else:
			print "\tWRITE_OPCODE( pc, %s );" % apiutil.OpcodeName( func_name[:-1] )
	else:
		for index in range(0,len(params)):
			(name, type, vecSize) = params[index]
			print WriteData( counter, type, name, do_swapped )
			counter += apiutil.sizeof(type)

		if isVertexAttrib:
			print "\tWRITE_OPCODE( pc, %s );" % apiutil.OpcodeName( func_name + "ARB" )
		else:
			print "\tWRITE_OPCODE( pc, %s );" % apiutil.OpcodeName( func_name )

	print "\tCR_UNLOCK_PACKER_CONTEXT(pc);"


	print '}\n'

#end PrintFunction()


for num_coords in [2,3,4]:
	for argtype in ['d', 'f', 'i', 's']:
		func_name = 'Vertex%d%s' % (num_coords, argtype)
		for swap in range(0, 2):
			for count in range(0, 2):
				for vec in range(0, 2):
					PrintFunction( func_name, "", num_coords, argtype, swap,
								   count, vec )

for num_coords in [1,2,3,4]:
	for argtype in ['d', 'f', 's']:
		func_name = 'VertexAttrib%d%s' % (num_coords, argtype)
		for swap in range(0, 2):
			for count in range(0, 2):
				for vec in range(0, 2):
					PrintFunction( func_name, "ARB", num_coords, argtype, swap,
								   count, vec )

# Special vector functions
moreFuncs = [ [ "VertexAttrib4ubv", "ub" ],
			  [ "VertexAttrib4usv", "us" ],
			  [ "VertexAttrib4uiv", "ui" ],
			  [ "VertexAttrib4bv", "b" ],
			  [ "VertexAttrib4iv", "i" ],
			  [ "VertexAttrib4Nbv", "Nb" ],
			  [ "VertexAttrib4Nsv", "Ns" ],
			  [ "VertexAttrib4Niv", "Ni" ],
			  [ "VertexAttrib4Nubv", "Nub" ],
			  [ "VertexAttrib4Nusv", "Nus" ],
			  [ "VertexAttrib4Nuiv", "Nui" ]
			]
for (func_name, argtype) in moreFuncs:
	vec = 2  # special, hacked value
	num_coords = 4
	for swap in range(0, 2):
		for count in range(0, 2):
			PrintFunction( func_name, "ARB", num_coords, argtype, swap, count, vec )

# Special non-vector functions
moreFuncs = [ [ "VertexAttrib4Nub", "Nub" ] ]
for (func_name, argtype) in moreFuncs:
	vec = 0
	num_coords = 4
	for swap in range(0, 2):
		for count in range(0, 2):
			PrintFunction( func_name, "ARB", num_coords, argtype, swap, count, vec )
