Esempio n. 1
0
void ccHObject::applyGLTransformation_recursive(ccGLMatrix* trans/*=NULL*/)
{
	ccGLMatrix* _trans = NULL;

	if (m_glTransEnabled)
	{
		if (!trans)
		{
			//if no transformation is provided (by father)
			//we initiate it with the current one
			trans = _trans = new ccGLMatrix(m_glTrans);
		}
		else
		{
			*trans *= m_glTrans;
		}
	}

	if (trans)
	{
		applyGLTransformation(*trans);
		notifyGeometryUpdate();
	}

	for (Container::iterator it = m_children.begin(); it!=m_children.end(); ++it)
		(*it)->applyGLTransformation_recursive(trans);

	if (_trans)
		delete _trans;

	if (m_glTransEnabled)
		resetGLTransformation();
}
Esempio n. 2
0
void ccHObject::applyGLTransformation_recursive(const ccGLMatrix* transInput/*=NULL*/)
{
	ccGLMatrix transTemp;
	const ccGLMatrix* transToApply = transInput;

	if (m_glTransEnabled)
	{
		if (!transInput)
		{
			//if no transformation is provided (by father)
			//we initiate it with the current one
			transToApply = &m_glTrans;
		}
		else
		{
			transTemp = *transInput * m_glTrans;
			transToApply = &transTemp;
		}
	}

	if (transToApply)
	{
		applyGLTransformation(*transToApply);
		notifyGeometryUpdate();
	}

	for (Container::iterator it = m_children.begin(); it!=m_children.end(); ++it)
		(*it)->applyGLTransformation_recursive(transToApply);

	if (m_glTransEnabled)
		resetGLTransformation();
}
//==================================================applyGLTransformation_recursive======================================//
void ccHObject::applyGLTransformation_recursive(ccGLMatrix* trans/*=NULL*/)
{
	ccGLMatrix* _trans = NULL;

	if (m_glTransEnabled){
		if (!trans)	{
			//if no transformation is provided (by father)
			//we initiate it with the current one
			trans = _trans = new ccGLMatrix(m_glTrans);
		}
		else{
			//将trans 作用到m_glTrans
			*trans *= m_glTrans;
		}
	}

	//将trans作用到该物体,并提醒相互依赖的物体进行升级
	if (trans){
		applyGLTransformation(*trans);
		notifyGeometryUpdate();
	}

	//对于每一个子物体,进行递归变换
	for (Container::iterator it = m_children.begin(); it!=m_children.end(); ++it)
		(*it)->applyGLTransformation_recursive(trans);

	if (_trans)
		delete _trans;

	//变换完成后,进行禁止变换,对于递归函数非常重要
	if (m_glTransEnabled)
		resetGLTransformation();
}
Esempio n. 4
0
void ccSubMesh::refreshBB()
{
	m_bBox.clear();
	
	for (unsigned i=0; i<size(); ++i)
	{
		CCLib::GenericTriangle* tri = _getTriangle(i);
		m_bBox.add(*tri->_getA());
		m_bBox.add(*tri->_getB());
		m_bBox.add(*tri->_getC());
	}

	notifyGeometryUpdate();
}
Esempio n. 5
0
bool ccTorus::buildUp()
{
	if (m_drawPrecision<4)
		return false;

	//invalid parameters?
	if ((m_rectSection && m_rectSectionHeight < ZERO_TOLERANCE) || m_insideRadius >= m_outsideRadius || m_angle_rad < ZERO_TOLERANCE)
		return false;

	//topology
	bool closed = (m_angle_rad >= 2.0*M_PI);

	const unsigned steps = m_drawPrecision;

	unsigned sweepSteps = 4*(closed ? steps : (unsigned)ceil(m_angle_rad*(double)steps/(2.0*M_PI)));
	unsigned sectSteps = (m_rectSection ? 4 : steps);

	//vertices
	unsigned vertCount = (sweepSteps+(closed ? 0 : 1))*sectSteps; //DGM: +1 row for non closed loops
	//faces
	unsigned facesCount = sweepSteps*sectSteps*2;
	//faces normals
	unsigned faceNormCount = (sweepSteps+(closed ? 0 : 1))*sectSteps; //DGM: +1 row for non closed loops
	if (!closed)
		facesCount += (m_rectSection ? 2 : sectSteps)*2;

	if (!init(vertCount+(closed || m_rectSection ? 0 : 2),false,facesCount,faceNormCount+(closed ? 0 : 2)))
	{
		ccLog::Error("[ccTorus::buildUp] Not enough memory");
		return false;
	}

	//2D section
	CCVector3* sectPoints = new CCVector3[sectSteps];
	if (!sectPoints)
	{
		init(0,false,0,0);
		ccLog::Error("[ccTorus::buildUp] Not enough memory");
		return false;
	}

	PointCoordinateType sectionRadius = (m_outsideRadius-m_insideRadius)/2;
	if (m_rectSection)
	{
		//rectangular section
		sectPoints[0].x = (m_outsideRadius-m_insideRadius)/2;
		sectPoints[0].z = m_rectSectionHeight/2;
		sectPoints[1].x = -sectPoints[0].x;
		sectPoints[1].z = sectPoints[0].z;
		sectPoints[2].x = sectPoints[1].x;
		sectPoints[2].z = -sectPoints[1].z;
		sectPoints[3].x = -sectPoints[2].x;
		sectPoints[3].z = sectPoints[2].z;
	}
	else
	{
		//circular section
		for (unsigned i=0;i<sectSteps;++i)
		{
			float sect_angle_rad = (float)i/(float)sectSteps*(float)(2.0*M_PI);
			sectPoints[i].x = cos(sect_angle_rad) * sectionRadius;
			sectPoints[i].z = sin(sect_angle_rad) * sectionRadius;
		}
	}

	ccPointCloud* verts = vertices();
	assert(verts);
	assert(m_triNormals);

	//main sweep
	PointCoordinateType sweepRadius = (m_insideRadius+m_outsideRadius)/(PointCoordinateType)2.0;
	double sweepStep_rad = m_angle_rad/(double)sweepSteps;
	for (unsigned t=0; t<(closed ? sweepSteps : sweepSteps+1); ++t)
	{
		//unit director vector
		CCVector3 sweepU(static_cast<PointCoordinateType>(cos(t*sweepStep_rad)),
						 static_cast<PointCoordinateType>(sin(t*sweepStep_rad)),
						 0);

		//section points
		for (unsigned i=0;i<sectSteps;++i)
		{
			CCVector3 P(sweepU.x * (sweepRadius + sectPoints[i].x),
						sweepU.y * (sweepRadius + sectPoints[i].x),
						sectPoints[i].z);
			verts->addPoint(P);
		}

		//normals
		if (m_rectSection)
		{
			m_triNormals->addElement(ccNormalVectors::GetNormIndex(CCVector3(0.0,0.0,1.0).u));
			m_triNormals->addElement(ccNormalVectors::GetNormIndex((-sweepU).u));
			m_triNormals->addElement(ccNormalVectors::GetNormIndex(CCVector3(0.0,0.0,-1.0).u));
			m_triNormals->addElement(ccNormalVectors::GetNormIndex((-sweepU).u));
		}
		else //circular section
		{
			for (unsigned i=0;i<sectSteps;++i)
			{
				float sectAngle_rad = (float)i/(float)sectSteps*(float)(2.0*M_PI);
				CCVector3 sectU(cos(sectAngle_rad),0.0,sin(sectAngle_rad));
				CCVector3 N(sweepU.x * sectU.x,
					sweepU.y * sectU.x,
					sectU.z);
				m_triNormals->addElement(ccNormalVectors::GetNormIndex(N.u));
			}
		}
	}

	if (!closed && !m_rectSection)
	{
		CCVector3 P(sweepRadius,0,0);
		verts->addPoint(P);
		CCVector3 P2(	static_cast<PointCoordinateType>(cos(m_angle_rad))*sweepRadius,
						static_cast<PointCoordinateType>(sin(m_angle_rad))*sweepRadius,
						 0);
		verts->addPoint(P2);
	}

	if (!closed)
	{
		//first section (left side)
		m_triNormals->addElement(ccNormalVectors::GetNormIndex(CCVector3(0,-1,0).u));
		//last section (right side)
		m_triNormals->addElement(ccNormalVectors::GetNormIndex(CCVector3(	static_cast<PointCoordinateType>(-sin(m_angle_rad)),
																			static_cast<PointCoordinateType>(cos(m_angle_rad)),
																			0).u));
	}

	delete[] sectPoints;
	sectPoints=0;

	//mesh faces
	{
		assert(m_triVertIndexes);

		for (unsigned t=0;t<sweepSteps;++t)
		{
			unsigned sweepStart = t*sectSteps;
			for (unsigned i=0;i<sectSteps;++i)
			{
				unsigned iNext = (i+1)%sectSteps;
				addTriangle(sweepStart+i,(sweepStart+i+sectSteps)%vertCount,(sweepStart+iNext+sectSteps)%vertCount);
				if (m_rectSection)
					addTriangleNormalIndexes(sweepStart+i,(sweepStart+i+sectSteps)%faceNormCount,(sweepStart+i+sectSteps)%faceNormCount);
				else
					addTriangleNormalIndexes(sweepStart+i,(sweepStart+i+sectSteps)%faceNormCount,(sweepStart+iNext+sectSteps)%faceNormCount);
				addTriangle(sweepStart+i,(sweepStart+iNext+sectSteps)%vertCount,sweepStart+iNext);
				if (m_rectSection)
					addTriangleNormalIndexes(sweepStart+i,(sweepStart+i+sectSteps)%faceNormCount,sweepStart+i);
				else
					addTriangleNormalIndexes(sweepStart+i,(sweepStart+iNext+sectSteps)%faceNormCount,sweepStart+iNext);
			}
		}

		if (!closed)
		{
			unsigned lastSectionShift = sweepSteps*sectSteps;
			if (m_rectSection)
			{
				//rectangular left section
				addTriangle(0,1,2);
				addTriangleNormalIndexes(faceNormCount,faceNormCount,faceNormCount);
				addTriangle(0,2,3);
				addTriangleNormalIndexes(faceNormCount,faceNormCount,faceNormCount);
				//rectangular right section
				addTriangle(lastSectionShift,lastSectionShift+2,lastSectionShift+1);
				addTriangleNormalIndexes(faceNormCount+1,faceNormCount+1,faceNormCount+1);
				addTriangle(lastSectionShift,lastSectionShift+3,lastSectionShift+2);
				addTriangleNormalIndexes(faceNormCount+1,faceNormCount+1,faceNormCount+1);
			}
			else
			{
				unsigned lastSectionCenterShift = vertCount;
				//circular 'left' section
				for (unsigned i=0;i<sectSteps;++i)
				{
					unsigned iNext = (i+1)%sectSteps;
					addTriangle(lastSectionCenterShift,i,iNext);
					addTriangleNormalIndexes(faceNormCount,faceNormCount,faceNormCount);
				}
				//circular 'right' section
				for (unsigned i=0;i<sectSteps;++i)
				{
					unsigned iNext = (i+1)%sectSteps;
					addTriangle(lastSectionCenterShift+1,lastSectionShift+iNext,lastSectionShift+i);
					addTriangleNormalIndexes(faceNormCount+1,faceNormCount+1,faceNormCount+1);
				}
			}
		}
	}

	notifyGeometryUpdate();
	showTriNorms(true);

	return true;
}
Esempio n. 6
0
bool ccDish::buildUp()
{
	if (m_drawPrecision < MIN_DRAWING_PRECISION)
		return false;

	if (m_height <= 0 || m_baseRadius <= 0 || m_secondRadius < 0) //invalid parameters
		return false;

	//section angular span
	double startAngle_rad = 0.0;
	const double endAngle_rad = M_PI/2.0;

	PointCoordinateType realRadius = m_baseRadius;
	if (m_secondRadius == 0 && m_height<m_baseRadius) //partial spherical mode
	{
		realRadius = (m_height*m_height+m_baseRadius*m_baseRadius)/(2*m_height);
		startAngle_rad = acos(m_baseRadius/realRadius);
		assert(startAngle_rad<endAngle_rad);
	}

	const unsigned steps = m_drawPrecision;
	double angleStep_rad = 2.0*M_PI/steps;
	unsigned sectionSteps = static_cast<unsigned>(ceil((endAngle_rad-startAngle_rad)*m_drawPrecision/(2.0*M_PI)));
	double sectionAngleStep_rad = (endAngle_rad-startAngle_rad)/sectionSteps;

	//vertices
	unsigned vertCount = steps*sectionSteps+1; //+1 for noth pole
	//faces
	unsigned faceCount = steps*((sectionSteps-1)*2+1);

	if (!init(vertCount,true,faceCount,0))
	{
		ccLog::Error("[ccDish::buildUp] Not enough memory");
		return false;
	}

	//vertices
	ccPointCloud* verts = vertices();
	assert(verts);

	//first point: north pole
	verts->addPoint(CCVector3(0,0,m_height));
	verts->addNorm(CCVector3(0,0,1));

	//then, angular sweep
	{
		for (unsigned j=1; j<=sectionSteps; ++j)
		{
			PointCoordinateType theta = static_cast<PointCoordinateType>(endAngle_rad - j * sectionAngleStep_rad); //we start from north pole!
			PointCoordinateType cos_theta = cos(theta);
			PointCoordinateType sin_theta = sin(theta);

			CCVector3 N0(cos_theta, 0, sin_theta);
		
			for (unsigned i=0; i<steps; ++i) //then we make a full revolution
			{
				PointCoordinateType phi = static_cast<PointCoordinateType>(i * angleStep_rad);
				PointCoordinateType cos_phi = cos(phi);
				PointCoordinateType sin_phi = sin(phi);

				CCVector3 N(N0.x * cos_phi, N0.x * sin_phi, N0.z);
				N.normalize();

				CCVector3 P = N * realRadius;

				if (m_secondRadius > 0) //half-ellipsoid mode
				{
					P.y *= (m_secondRadius / m_baseRadius);
					P.z *= (m_height / m_baseRadius);
				}
				else //spherical section mode
				{
					P.z += m_height-realRadius;
				}

				verts->addPoint(P);
				verts->addNorm(N);
			}
		}
	}

	//faces
	{
		//north pole
		{
			for (unsigned i=0; i<steps; ++i)
			{
				unsigned A = 1+i;
				unsigned B = (i+1<steps ? A+1 : 1);
				addTriangle(A,B,0);
			}
		}

		//slices
		for (unsigned j=1; j<sectionSteps; ++j)
		{
			unsigned shift = 1+(j-1)*steps;		
			for (unsigned i=0; i<steps; ++i)
			{
				unsigned A = shift+i;
				unsigned B = (i+1<steps ? A+1 : shift);
				assert(B < vertCount);
				addTriangle(A,A+steps,B);
				addTriangle(B+steps,B,A+steps);
			}
		}
	}

	notifyGeometryUpdate();
	showNormals(true);

	return true;
}
Esempio n. 7
0
bool ccCone::buildUp()
{
	if (m_drawPrecision < MIN_DRAWING_PRECISION)
		return false;

	//invalid dimensions?
	if (m_height < ZERO_TOLERANCE || m_bottomRadius + m_topRadius < ZERO_TOLERANCE)
		return false;

	//topology
	bool singlePointBottom = (m_bottomRadius < ZERO_TOLERANCE);
	bool singlePointTop = (m_topRadius < ZERO_TOLERANCE);
	assert(!singlePointBottom || !singlePointTop);

	unsigned steps = m_drawPrecision;

	//vertices
	unsigned vertCount = 2;
	if (!singlePointBottom)
		vertCount += steps;
	if (!singlePointTop)
		vertCount += steps;
	//normals
	unsigned faceNormCounts = steps+2;
	//vertices
	unsigned facesCount = steps;
	if (!singlePointBottom)
		facesCount += steps;
	if (!singlePointTop)
		facesCount += steps;
	if (!singlePointBottom && !singlePointTop)
		facesCount += steps;

	//allocate (& clear) structures
	if (!init(vertCount,false,facesCount,faceNormCounts))
	{
		ccLog::Error("[ccCone::buildUp] Not enough memory");
		return false;
	}

	ccPointCloud* verts = vertices();
	assert(verts);
	assert(m_triNormals);

	//2 first points: centers of the top & bottom surfaces
	CCVector3 bottomCenter = CCVector3(m_xOff,m_yOff,-m_height)/2;
	CCVector3 topCenter = CCVector3(-m_xOff,-m_yOff,m_height)/2;
	{
		//bottom center
		verts->addPoint(bottomCenter);
		CompressedNormType nIndex = ccNormalVectors::GetNormIndex(CCVector3(0,0,-1).u);
		m_triNormals->addElement(nIndex);
		//top center
		verts->addPoint(topCenter);
		nIndex = ccNormalVectors::GetNormIndex(CCVector3(0,0,1).u);
		m_triNormals->addElement(nIndex);
	}
	
	//then, angular sweep for top and/or bottom surfaces
	{
		PointCoordinateType angle_rad_step = static_cast<PointCoordinateType>(2.0*M_PI)/static_cast<PointCoordinateType>(steps);
		//bottom surface
		if (!singlePointBottom)
		{
			for (unsigned i=0; i<steps; ++i)
			{
				CCVector3 P(bottomCenter.x + cos(angle_rad_step*i)*m_bottomRadius,
							bottomCenter.y + sin(angle_rad_step*i)*m_bottomRadius,
							bottomCenter.z);
				verts->addPoint(P);
			}
		}
		//top surface
		if (!singlePointTop)
		{
			for (unsigned i=0; i<steps; ++i)
			{
				CCVector3 P(topCenter.x + cos(angle_rad_step*i)*m_topRadius,
							topCenter.y + sin(angle_rad_step*i)*m_topRadius,
							topCenter.z);
				verts->addPoint(P);
			}
		}
		//side normals
		{
			for (unsigned i=0; i<steps; ++i)
			{
				//slope
				CCVector3 u(-sin(angle_rad_step*i),cos(angle_rad_step*i),0);
				CCVector3 v(bottomCenter.x-topCenter.x + u.y*(m_bottomRadius-m_topRadius),
							bottomCenter.y-topCenter.y - u.x*(m_bottomRadius-m_topRadius),
							bottomCenter.z-topCenter.z);
				CCVector3 N = v.cross(u);
				N.normalize();

				CompressedNormType nIndex = ccNormalVectors::GetNormIndex(N.u);
				m_triNormals->addElement(nIndex);
			}
		}
	}
	
	//mesh faces
	{
		assert(m_triVertIndexes);

		unsigned bottomIndex = 2;
		unsigned topIndex = 2+(singlePointBottom ? 0 : steps);

		//bottom surface
		if (!singlePointBottom)
		{
			for (unsigned i=0;i<steps;++i)
			{
				addTriangle(0,bottomIndex+(i+1)%steps,bottomIndex+i);
				addTriangleNormalIndexes(0,0,0);
			}
		}
		//top surface
		if (!singlePointTop)
		{
			for (unsigned i=0;i<steps;++i)
			{
				addTriangle(1,topIndex+i,topIndex+(i+1)%steps);
				addTriangleNormalIndexes(1,1,1);
			}
		}

		if (!singlePointBottom && !singlePointTop)
		{
			for (unsigned i=0;i<steps;++i)
			{
				unsigned iNext = (i+1)%steps;
				addTriangle(bottomIndex+i,bottomIndex+iNext,topIndex+i);
				addTriangleNormalIndexes(2+i,2+iNext,2+i);
				addTriangle(topIndex+i,bottomIndex+iNext,topIndex+iNext);
				addTriangleNormalIndexes(2+i,2+iNext,2+iNext);
			}
		}
		else if (!singlePointTop)
		{
			for (unsigned i=0;i<steps;++i)
			{
				unsigned iNext = (i+1)%steps;
				addTriangle(topIndex+i,0,topIndex+iNext);
				addTriangleNormalIndexes(2+i,2+iNext,2+iNext); //TODO: middle normal should be halfbetween?!
			}
		}
		else //if (!singlePointBottom)
		{
			for (unsigned i=0;i<steps;++i)
			{
				unsigned iNext = (i+1)%steps;
				addTriangle(bottomIndex+i,bottomIndex+iNext,1);
				addTriangleNormalIndexes(2+i,2+iNext,2+i); //TODO: last normal should be halfbetween?!
			}
		}
	}

	notifyGeometryUpdate();
	showTriNorms(true);

	return true;
}
Esempio n. 8
0
ccSubMesh* ccSubMesh::createNewSubMeshFromSelection(bool removeSelectedFaces, IndexMap* indexMap/*=0*/)
{
	ccGenericPointCloud* vertices = getAssociatedCloud();
	assert(vertices && m_associatedMesh);
	if (!vertices || !m_associatedMesh)
	{
		return NULL;
	}

	ccGenericPointCloud::VisibilityTableType* verticesVisibility = vertices->getTheVisibilityArray();
	if (!verticesVisibility || !verticesVisibility->isAllocated())
	{
		ccLog::Error(QString("[Sub-mesh %1] Internal error: vertex visibility table not instantiated!").arg(getName()));
		return NULL;
	}

	//we count the number of remaining faces
	unsigned triNum = m_triIndexes->currentSize();
	unsigned visibleFaces = 0;
	{
		for (unsigned i=0; i<triNum; ++i)
		{
			const unsigned& globalIndex = m_triIndexes->getValue(i);
			const CCLib::VerticesIndexes* tsi = m_associatedMesh->getTriangleVertIndexes(globalIndex);
			//triangle is visible?
			if (   verticesVisibility->getValue(tsi->i1) == POINT_VISIBLE
				&& verticesVisibility->getValue(tsi->i2) == POINT_VISIBLE
				&& verticesVisibility->getValue(tsi->i3) == POINT_VISIBLE)
			{
				++visibleFaces;
			}
		}
	}

	//nothing to do
	if (visibleFaces == 0)
	{
		if (indexMap) //we still have to translate global indexes!
		{
			for (unsigned i=0; i<triNum; ++i)
			{
				unsigned globalIndex = m_triIndexes->getValue(i);
				globalIndex = indexMap->getValue(globalIndex);
				m_triIndexes->setValue(i,globalIndex);
			}
		}
		return 0;
	}

	ccSubMesh* newSubMesh = new ccSubMesh(m_associatedMesh);
	if (!newSubMesh->reserve(size()))
	{
		ccLog::Error("[ccSubMesh::createNewSubMeshFromSelection] Not enough memory!");
		return NULL;
	}

	//create sub-mesh
	{
		unsigned lastTri = 0;
		for (unsigned i=0; i<triNum; ++i)
		{
			unsigned globalIndex = m_triIndexes->getValue(i);
			const CCLib::VerticesIndexes* tsi = m_associatedMesh->getTriangleVertIndexes(globalIndex);

			if (indexMap) //translate global index?
				globalIndex = indexMap->getValue(globalIndex);

			//triangle is visible?
			if (   verticesVisibility->getValue(tsi->i1) == POINT_VISIBLE
				&& verticesVisibility->getValue(tsi->i2) == POINT_VISIBLE
				&& verticesVisibility->getValue(tsi->i3) == POINT_VISIBLE)
			{
				newSubMesh->addTriangleIndex(globalIndex);
			}
			else if (removeSelectedFaces) //triangle is not visible? It stays in the original mesh!
			{
				//we replace the current triangle by the 'last' valid one
				assert(lastTri <= i);
				m_triIndexes->setValue(lastTri++,globalIndex);
			}
		}

		//resize original mesh
		if (removeSelectedFaces && lastTri < triNum)
		{
			if (lastTri == 0)
				m_triIndexes->clear(true);
			else
				resize(lastTri);

			m_bBox.setValidity(false);
			notifyGeometryUpdate();
		}
	}

	if (newSubMesh->size())
	{
		newSubMesh->setName(getName()+QString(".part"));
		newSubMesh->resize(newSubMesh->size());
		newSubMesh->setDisplay(getDisplay());
		newSubMesh->showColors(colorsShown());
		newSubMesh->showNormals(normalsShown());
		newSubMesh->showMaterials(materialsShown());
		newSubMesh->showSF(sfShown());
		newSubMesh->enableStippling(stipplingEnabled());
		newSubMesh->showWired(isShownAsWire());
	}
	else
	{
		assert(false);
		delete newSubMesh;
		newSubMesh = 0;
	}

	return newSubMesh;
}
Esempio n. 9
0
bool ccSphere::buildUp()
{
	if (m_drawPrecision<4)
		return false;

	const unsigned steps = m_drawPrecision;

	//vertices
	ccPointCloud* verts = vertices();
	assert(verts);

	//vertices
	unsigned count = steps*(steps-1)+2;
	//faces
	unsigned faces = steps*((steps-2)*2+2);

	if (!init(count,true,faces,0))
	{
		ccLog::Error("[ccSphere::buildUp] Not enough memory");
		return false;
	}

	//2 first points: poles
	verts->addPoint(CCVector3(0,0,m_radius));
	verts->addNorm(CCVector3(0,0,1));

	verts->addPoint(CCVector3(0,0,-m_radius));
	verts->addNorm(CCVector3(0,0,-1));

	//then, angular sweep
	PointCoordinateType angle_rad_step = static_cast<PointCoordinateType>(M_PI)/static_cast<PointCoordinateType>(steps);
	CCVector3 N0,N,P;
	{
		for (unsigned j=1; j<steps; ++j)
		{
			PointCoordinateType theta = static_cast<PointCoordinateType>(j) * angle_rad_step;
			PointCoordinateType cos_theta = cos(theta);
			PointCoordinateType sin_theta = sin(theta);

			N0.x = sin_theta;
			N0.y = 0;
			N0.z = cos_theta;
		
			for (unsigned i=0; i<steps; ++i)
			{
				PointCoordinateType phi = static_cast<PointCoordinateType>(2*i) * angle_rad_step;
				PointCoordinateType cos_phi = cos(phi);
				PointCoordinateType sin_phi = sin(phi);

				N.x = N0.x*cos_phi;
				N.y = N0.x*sin_phi;
				N.z = N0.z;
				N.normalize();

				P = N * m_radius;

				verts->addPoint(P);
				verts->addNorm(N);
			}
		}
	}

	//faces
	{
		assert(m_triVertIndexes);

		//north pole
		{
			for (unsigned i=0; i<steps; ++i)
			{
				unsigned A = 2+i;
				unsigned B = (i+1<steps ? A+1 : 2);
				addTriangle(A,B,0);
			}
		}

		//slices
		for (unsigned j=1; j+1<steps; ++j)
		{
			unsigned shift = 2+(j-1)*steps;		
			for (unsigned i=0; i<steps; ++i)
			{
				unsigned A = shift+i;
				unsigned B = (i+1<steps ? A+1 : shift);
				assert(B<count);
				addTriangle(A,A+steps,B);
				addTriangle(B+steps,B,A+steps);
			}
		}

		//south pole
		{
			unsigned shift = 2+(steps-2)*steps;
			for (unsigned i=0; i<steps; ++i)
			{
				unsigned A = shift+i;
				unsigned B = (i+1<steps ? A+1 : shift);
				assert(B<count);
				addTriangle(A,1,B);
			}
		}
	}

	notifyGeometryUpdate();
	showNormals(true);

	return true;
}