TMesh


Croquet-Teapot

Comment:

das 10/7/2002 11:49

TMesh
Almost all simple arrays are 0 based when indexed by other arrays. Not the materialList.

materialList - this is an OrderedCollection of materials that are used in the mesh. This is what the first element of the faceGroups refers to. This must always be a list.
alias - you can ignore this for now. It is important when we start doing mesh based transforms, because it tells you where the aliased vertices are.
vertices - 0 index based list of 3D vertices.
vtxNormals - the normal 3D vector for the given vertex.
alpha - checks the materials referenced by the facegroups for alpha values. Calculated for you based upon the materialList.
opaque  - same as alpha, but inverted.
textureUV - the 2D u,v coordinates of the texture at the associated vertex.
faceGroups - an array of materialList index (indexing starting at 1), and vertex face index arrays (index starting at 0). These are simply interleaved. 
boundsChanged - calculated for you at construction time. 
boundSphere - calculated for you.
boundsDepth - part of construction and used to determine the depth of the hierarchy.
boundMaterial - only used if you need to see the bound spheres or bound cubes.

These are the analogs to the equivalent TPrimitives. There are two sets because a TMesh may have some materials that have alpha components and some that don't. These are rendered at different times, so they need separate display lists.
glListID 
glListAlphaID 
glListValid 
glListAlphaValid 
glListEnabled

Hierarchy:

ProtoObject
Object
TObject
TFrame
TMesh

Summary:

instance variables:

alias alpha boundMaterial boundSphere boundsChanged boundsDepth cachingAlphaEnabled cachingEnabled faceGroups glInstance glListAlphaID glListAlphaValid glListEnabled glListID glListValid materialList opaque textureUV vertices vtxNormals

Pool:

OpenGLConstants

methods:

instance class
accessing collision copying fileIn/Out initialize properties render testing instance creation

Detail:

instance variables:

alias
alpha
boundMaterial
boundSphere
boundsChanged
boundsDepth
cachingAlphaEnabled
cachingEnabled
faceGroups
glInstance
glListAlphaID
glListAlphaValid
glListEnabled
glListID
glListValid
materialList
opaque
textureUV
vertices
vtxNormals

instance methods:

accessing
boundsChanged

	boundsChanged _ true.
boundsDepth


	^ boundsDepth.
boundsDepth: depth


	boundsDepth _ depth.
	frameChildren ifNotNil:[ frameChildren do:[ :fc | fc boundsDepth: depth].].
	self boundsChanged.
collapse


"Forces all frames to identity transform while retaining translation, and pushes the previous transform to the frame children. This is used primarily for meshes and their supporting groups."
	| orient|

	orient _ self orientation.
	1 to: vertices size do:[ :index |
		vertices at: index put:(orient localPointToGlobal: (vertices at: index)).].
	1 to: vtxNormals size do:[ :index |
		vtxNormals at: index put:(orient localPointToGlobal:( vtxNormals at: index)).].
	super collapse.
colorize: col


	self materialList do:[ :ml |
		ml ambientColor: col.
		ml diffuseColor: col.
		ml textureMode: GLModulate.
		].
	self resetCaching.
	self checkAlpha.
	frameChildren ifNotNil:[frameChildren do:[ :fc | fc colorize: col].].
faceGroupsDo: aBlock

	1 to: faceGroups size by: 2 do:[ :i | aBlock value: (faceGroups at: i+1)].
forceGlobalToLocal


"This is used by TMesh where we assume that the imported vertices are pre-transformed and we want to put them back into their untransformed state. Only TMesh will probably need this, but TMeshes can have TGroups which don't know what to do."
	| invMat invOrient |

	frameChildren ifNotNil:[ frameChildren do:[ :fc | fc forceGlobalToLocal.]].
	invMat _ self localTransform orthoNormInverse.
	invOrient _ self orientation orthoNormInverse.
	1 to: vertices size do:[ :index | 
		vertices at: index put:(invMat localPointToGlobal: (vertices at: index)).].
	1 to: vtxNormals size do:[ :index |
		vtxNormals at: index put:(invOrient localPointToGlobal: (vtxNormals at: index)).].
	frameParent ifNotNil:[
		self localTransform: (
			frameParent localTransform orthoNormInverse composeWith: self localTransform).
		].
frameBox

	"Answer the local bounding box of this frame"
	boundsChanged ifTrue:[self initBounds].
	boundSphere ifNil:[^super frameBox].
	^boundSphere box ifNil:[super frameBox]
fullBright: bool


	super fullBright: bool.
	materialList ifNotNil:[ materialList do:[ :ml | ml fullBright: bool]].
hasAlpha: bool


	alpha _ bool.
inertiaTensor


	| it |

	it _ TTensor initialize.
	1 to: faceGroups size by: 2 do:[:i |
		it addFaces: (faceGroups at: i+1) vertices: vertices.].
	^ it.
	
isSolid

	^ solid
material

	^materialList first
material: aMaterial

	materialList at: 1 put: aMaterial
materialList


	^ materialList.
materialList: ml


	materialList _ ml.
	self checkAlpha.
normals

	^vtxNormals
normals: normals

	vtxNormals := normals
opaque


	^ opaque.
opaque: bool


	opaque _ bool.
pick: pointer


" We are here because we already picked the top level boundSphere, so we know that is true. Now what we need to test against the hierarchy, which will return a list of faces if true - otherwise, it will return nil."

	^ boundSphere pickChildren: pointer.
scale: scale

	vertices *= scale.
	super scale: scale.
	self scaleBounds: scale.
	"self boundsChanged."
scaleBounds: scale


	boundSphere ifNil: [self boundsChanged. ^ self].
	boundSphere scale: scale.
transparency: trans


	self materialList do:[ :ml |
		ml transparency: trans.
		].
	self checkAlpha.
	frameChildren ifNotNil:[frameChildren do:[ :fc | fc transparency: trans].].
vertices

	^vertices
vertices: verts

	vertices _ verts.

collision
collideFloor: floor


	(self boundSphere globalPosition y)-floor > boundSphere radius ifTrue:[ ^ nil ].

	^ boundSphere collideFloor: floor transform: self globalTransform.
collidePlane: normal offset: offset


	| tNormal tOffset |

" Simple test in world coordinates:"
	(boundSphere globalPosition dot: normal)-offset > boundSphere radius ifTrue:[ ^ nil ].

"Put the global coordinates of the plane into the local coordinate frame."
	tNormal _ self globalOrientation orthoNormInverse localPointToGlobal: normal.
	tOffset _ (tNormal dot: (self globalTransform orthoNormInverse localPointToGlobal: (normal*offset))).

	^ boundSphere collidePlane: tNormal offset: tOffset.

copying
postCopy


	super postCopy.
	materialList ifNotNil:[
		materialList _ materialList collect:[:mat| mat copy].
	].
	self vertices: vertices copy.
	self boundsChanged.
	glListID _ nil.
	glListAlphaID _ nil.
	self enableCaching.
	^ self.

fileIn/Out
postImportFrom: importer

	super postImportFrom: importer.
	glListID _ nil.
	glListAlphaID _ nil.
	self enableCaching.
prepareToExportOn: exporter

	super prepareToExportOn: exporter.


initialize
checkAlpha


	opaque _ false.
	alpha _ false.
	1 to: faceGroups size by: 2 do:[:i |
		((materialList at:(faceGroups at: i)) hasAlpha) ifTrue: [ self hasAlpha: true. ] ifFalse:[ self opaque: true.].
		].
	boundMaterial ifNotNil:[self hasAlpha: true].
initBounds


	boundsDepth = 0 ifTrue:[
		boundSphere _ TBoundSphere mtfBall: vertices. ]
	ifFalse:[
		faceGroups size = 2 ifTrue:[	
			boundSphere _ 
			TBoundSphere calcTree: vertices faces: (faceGroups at: 2) depth: boundsDepth. ] 
		ifFalse:[
			boundSphere _ TBoundSphere mtfBall: vertices.
			1 to: faceGroups size by: 2 do:[ :i || child |
				child _ 
				TBoundSphere calcTree: vertices faces: (faceGroups at: i+1) depth: boundsDepth-1.
				boundSphere addChild: child.].
			].].
	boundSphere frame: self.
	boundsChanged _ false.
initializeWithVertices: v alias: a norms: n textureUV: tuv faceGroups: fg material: ml
 

	| mat |
	super initialize.
	vertices _ v.
	alias _ a.
	vtxNormals _ n.
	textureUV _ tuv.
	faceGroups _ fg.
	alpha_ false.
	opaque _ false.
	mat _ ml.
	mat ifNil:[ 
		mat _ TMaterial new.
		mat ambientColor: #(1.0 0.2 0.2 0.5) asFloatArray.
		 ].
	mat subMaterialList ifNotNil:[ materialList _ mat subMaterialList. ]
	ifNil:[
		materialList _ OrderedCollection new.
		materialList add: mat.
		1 to: faceGroups size by: 2 do:[ :i |
			faceGroups at: i put: 1. ].].

	1 to: faceGroups size by: 2 do:[:i |
		faceGroups at: i put: 1+(((faceGroups at: i)-1)\\materialList size).
		((materialList at:(faceGroups at: i)) hasAlpha) ifTrue: [ self hasAlpha: true.] ifFalse:[ self opaque: true].
		].
	self optimizeFaceGroups.

	boundsDepth _ 2. "must always be a mimimum of 1 - the top sphere, and at least one recursion."
	self boundsChanged.
	glListID _ nil.
	glListAlphaID _ nil.
	self enableCaching.

"	This code is used to test the bounds sphere."
"	boundMaterial _ TMaterial new.
	boundMaterial ambientColor: #(0.7  0.2 0.1 0.3)asFloatArray.
	boundMaterial diffuseColor: #(0.7  0.2 0.1 0.3)asFloatArray.
	alpha _ true."
	^self
optimizeFaceGroups

	"Optimize the face groups to minimize state changes"
	| matList faces index |
	matList := IdentityDictionary new.
	1 to: faceGroups size by: 2 do:[:i|
		index := faceGroups at: i.
		faces := faceGroups at: i+1.
		matList at: index put: ((matList at: index ifAbsent:[#()]) copyWith: faces).
	].
	index := 0.
	matList keysAndValuesDo:[:mIndex :fList|
		fList do:[:fGroup|
			faceGroups at: (index := index+1) put: mIndex.
			faceGroups at: (index := index+1) put: fGroup.
		].
	].
validateFaceGroups

	"Check to see if all face groups are valid. For debugging only."
	| vtxSize face |
	vtxSize := vertices size.
	vtxNormals ifNotNil:[
		vtxNormals size = vertices size ifFalse:[self error:'normal size mismatch'].
	].
	textureUV ifNotNil:[
		textureUV size = vertices size ifFalse:[self error:'texture size mismatch'].
	].
	self faceGroupsDo:[:fg|
		fg basicSize \\ 3 = 0 ifFalse:[self error:'Face group not divisable by 3'].
		1 to: fg basicSize do:[:i|
			face := fg basicAt: i.
			(face >= 0 and:[face < vtxSize]) ifFalse:[self error:'Vertex out of range'].
		].
	].

properties
getAlpha

	^materialList first getAlpha
getColor

	^materialList first getColor
getSpecularColor

	^materialList first getSpecularColor
setAlpha: newAlpha

	super setAlpha: newAlpha.
	materialList do:[ :each | each setAlpha: newAlpha].
	alpha := newAlpha < 1.0.
setColor: aColor

	self frameChildrenDo:[:child| child setColor: aColor].
	materialList first setColor: aColor
setSpecularColor: aColor

	self frameChildrenDo:[:child| child setColor: aColor].
	materialList first setSpecularColor: aColor

render
boundSphere


	boundsChanged ifTrue:[
		self initBounds. 
		boundsChanged _ false.
		].
	^ boundSphere.
disableCaching

	cachingEnabled _ false.
	cachingAlphaEnabled _ false.
enableCaching

	cachingEnabled _ true.
	cachingAlphaEnabled _ true.
hasAlpha


	^ alpha.
oldRender: ogl


	self opaque ifTrue:[
		(cachingEnabled = true) ifFalse:[
			(glListID notNil and:[ glInstance = ogl instance]) ifTrue:[
				ogl glDeleteLists: glListID with: 1.
				ogl unregisterList: self.
				].
			glListID _ nil.
			cachingEnabled = #reset ifTrue:[ cachingEnabled _ true.].
			^self renderPrimitive: ogl alpha: false.
		].
		"if there is a cached list and ogl has not changed, call it"
		(glListID notNil and: [glInstance = ogl instance]) ifTrue:[
			ogl glCallList: glListID.
		] ifFalse:[
			glListID _ ogl glGenLists: 1.
			ogl registerList: glListID range: 1 owner: self.
			glInstance _ nil.
			ogl glNewList: glListID with: GLCompileAndExecute.
			self renderPrimitive: ogl alpha: false.
			"See if current display list completed correctly.
			If any other has been constructed in the mean time
			defer this lists creation until the next rendering loop."
			(ogl glGetInteger: GLListIndex) = glListID ifTrue:[glInstance _ ogl instance].
			ogl glEndList.
		].
	].
oldRenderAlpha: ogl


	(cachingAlphaEnabled = true) ifFalse:[
		(glListAlphaID notNil and:[ glInstance = ogl instance]) ifTrue:[
			ogl glDeleteLists: glListAlphaID with: 1.
			ogl unregisterList: self.
			].
		glListAlphaID _ nil.
		cachingAlphaEnabled = #reset ifTrue:[ cachingAlphaEnabled _ true.].
		^self renderPrimitive: ogl alpha: true.
	].
	"if there is a cached list and ogl has not changed, call it"
	(glListAlphaID notNil and: [glInstance = ogl instance]) ifTrue:[
		ogl glCallList: glListAlphaID.
	] ifFalse:[
		glListAlphaID _ ogl glGenLists: 1.
		ogl registerList: glListAlphaID range: 1 owner: self.
		glInstance _ nil.
		ogl glNewList: glListAlphaID with: GLCompileAndExecute.
		self renderPrimitive: ogl alpha: true.
		"See if current display list completed correctly.
		If any other has been constructed in the mean time
		defer this lists creation until the next rendering loop."
		(ogl glGetInteger: GLListIndex) = glListAlphaID ifTrue:[glInstance _ ogl instance].
		ogl glEndList.
	].
render: ogl


	^self renderPrimitive: ogl alpha: false.
renderAlpha: ogl


	^self renderPrimitive: ogl alpha: true.
renderPrimitive: ogl alpha: alphaPass

	| lastMat nextMat |
	lastMat := nil.
	1 to: faceGroups size by: 2 do:[ :i |
		nextMat _ materialList at: (faceGroups at: i).
		nextMat hasAlpha = alphaPass ifTrue:[
			nextMat == lastMat ifFalse:[
				lastMat ifNotNil:[lastMat disable: ogl].
				nextMat enable: ogl.
				lastMat := nextMat.
			].
			ogl drawIndexedTriangles: (faceGroups at: i+1) 
				vertices: vertices 
				normals: vtxNormals 
				colors: nil texCoords: textureUV.
		].
	].
	lastMat ifNotNil:[lastMat disable: ogl].

"	boundSphere renderBox: self."
resetCaching

	cachingEnabled _ #reset.
	cachingAlphaEnabled _ #reset.

testing
isMesh


	^ true.

class methods:

^top


- made by Dandelion -