Cone Primitive w/Texture Coords and Normals

A work in progress …

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# Function name : CreateOpenShadedCone
#
# Author : Paul H. Leopard, DESE Research, Inc.
#
# Description:
#
#	Create and return a GeomNode describing an open shaded cone.
#
# Input(s):
#
#   nodeName - Name of the GeomNode
#   sliceCount - Number of slices in the cone.
#
# Output(s):
#
#	A GeomNode representing the cone
#
# Example Useage:
#
#   geomNode = CreateOpenShadedCone('ConeWith32Slices',32)
#   nodePath = NodePath(geomNode)
#   nodePath.reparentTo(render)
#
def CreateOpenShadedCone(nodeName,sliceCount):

	# Create points for a circle
	deltaAngle = 360.0/float(sliceCount-2)
	angle = 0
	points = []
	for i in range(0,sliceCount):
		angleRadians = angle*0.01745329251994
		y = math.sin(angleRadians)
		x = math.cos(angleRadians)
		point = (x,y)
		points.append(point)
		angle += deltaAngle

	# Define the vetex data format (GVF). 
	gvf = GeomVertexFormat.getV3n3c4t2()

	# Create the vetex data container (GVD) using the GVF from above to
	# describe its contents.
	gvd = GeomVertexData('GridVertices',gvf,Geom.UHStatic)

	# Create writers for the GVD, one for each type of data (column) that
	# we are going to store in it.
	gvwV = GeomVertexWriter(gvd,'vertex')
	gvwT = GeomVertexWriter(gvd,'texcoord')
	gvwC = GeomVertexWriter(gvd,'color')
	gvwN = GeomVertexWriter(gvd,'normal')

	# Use the writers to add vertex data to the GVD.
	T = (0,0,1)
	C = (1,1,1,1)
	n = len(points)

	# Upload Vertex/Normal/Tex/Color for top point
	gvwV.addData3f(T[0],T[1],T[2])
	gvwN.addData3f(0,0,1)
	gvwC.addData4f(C[0],C[1],C[2],C[3])
	gvwT.addData2f(0,0)
	tIndex = 0

	# For each point sample
	for i in range(0,n):

		# Get first point (A)
		p = points[i]
		A = (p[0],p[1],0)

		# Get next point (B)
		j = (i+1) % n
		p = points[j]
		B = (p[0],p[1],0)

		# Compute surface normal (N0) for Facet(A,B,T)
		x10 = B[0] - A[0]
		y10 = B[1] - A[1]
		z10 = B[2] - A[2]
		x12 = B[0] - T[0]
		y12 = B[1] - T[1]
		z12 = B[2] - T[2]
		cpx = (z10*y12) - (y10*z12)
		cpy = (x10*z12) - (z10*x12)
		cpz = (y10*x12) - (x10*y12)
		r = math.sqrt(cpx*cpx + cpy*cpy + cpz*cpz)
		N = (cpx/r, cpy/r, cpz/r)

		# Get Previous point (C)
		# Compute facet normal (N1) for C,A,T
		# Compute average normal N = (N0 + N1)/2
		# @TODO@ Implement these ^^^ later on

		# Compute normalized texture coordinate TX(U,V) on XY plane
		TX = (A[0],A[1])

		# Upload Vertex/Normal/Tex/Color
		gvwV.addData3f(A[0],A[1],A[2])
		gvwN.addData3f(N[0],N[1],N[2])
		gvwC.addData4f(C[0],C[1],C[2],C[3])
		gvwT.addData2f(TX[0],TX[1])

	# Create a GeomPrimitive object to use the vertices in the GVD
	# then fill it with our cone facets data.

	geom = Geom(gvd)

	for i in range(0,n):

		# Get first point (A)
		aIndex = i+1

		# Get next point (B)
		j = (aIndex+1) % n
		bIndex = j

		# Create and upload face F(A,B,T)
		tris = GeomTriangles(Geom.UHStatic)
		tris.setIndexType(Geom.NTUint32)
		tris.addVertex(aIndex)
		tris.addVertex(bIndex)
		tris.addVertex(tIndex)
		tris.closePrimitive()

		geom.addPrimitive(tris)

		str = "\tTris : %d,%d,%d" % (aIndex,bIndex,tIndex)
		print str

	geomNode = GeomNode(nodeName)
	geomNode.addGeom(geom)
	return geomNode

Version of the above in class form, derived from NodePath:

# Standard imports

import math

# Panda imports

from pandac.PandaModules import *

# PHL imports

from PHL.P3D.Shapes import CreateOpenShadedCone

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# Class name : EllipticalCone
#
# Description:
#
#	Extends NodePath to represent an elliptical cone with texture coordinates,
#   normals, and color coordinates.
#
# Author: Paul H. Leopard
#
# $Modtime: 10/19/06 8:46p $
#
# $Revision: 2 $ 
#
#-------0---------0---------0---------0---------0---------0---------0---------0
class EllipticalCone(NodePath):

	# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	#
	# Method name : __init__
	#
	# Description:
	#
	#	Create and return an instance of EllipticalCone.
	#
	# Input(s):
	#
	#   nodeName - Name of the GeomNode
	#   sliceCount - Number of slices in the cone.
	#
	# Output(s):
	#
	#	A GeomNode representing the cone
	#
	def __init__(self,nodeName,sliceCount):
		gNode = CreateOpenShadedCone(nodeName,sliceCount)
		NodePath.__init__(self,gNode)