void Polyhedron<Real>::transform(const matrix4<Real>& matrix)
	{
		for (uint i = 0; i < planes.size(); ++i)
			planes[i] = matrix.transformPlane(planes[i]);

		for (uint i = 0; i < vertices.size(); ++i)
			vertices[i] = matrix.transformVertex(vertices[i]);

	}
Example #2
0
static bool transformPlane(const vector3df & point, const vector3df & normal,
						   const matrix4 & matrix, const plane3df & expected)
{
	plane3df plane(point, vector3df(normal).normalize());

	logTestString("\n     Pre: (%.3ff,%.3ff,%.3ff), %.3ff\n",
		plane.Normal.X, plane.Normal.Y, plane.Normal.Z, plane.D);

	matrix.transformPlane(plane);

	logTestString("    Post: (%.3ff,%.3ff,%.3ff), %.3ff\n",
		plane.Normal.X, plane.Normal.Y, plane.Normal.Z, plane.D);

	logTestString("Expected: (%.3ff,%.3ff,%.3ff), %.3ff\n",
		expected.Normal.X, expected.Normal.Y, expected.Normal.Z, expected.D);

	if(!sloppyComparePlanes(plane, expected))
	{
		logTestString("Unexpected result\n");
		assert_log(false);
		return false;
	}

	return true;
}
Example #3
0
void matrix4::ToInverse( const matrix4& in )
{

	// first transpose the rotation matrix
	_11 = in._11;
	_12 = in._21;
	_13 = in._31;
	_21 = in._12;
	_22 = in._22;
	_23 = in._32;
	_31 = in._13;
	_32 = in._23;
	_33 = in._33;

	// fix right column
	_14 = 0;
	_24 = 0;
	_34 = 0;
	_44 = 1;

	// now get the new translation vector
	point3 temp = in.GetLoc();

	_41 = -(temp.x * in._11 + temp.y * in._12 + temp.z * in._13);
	_42 = -(temp.x * in._21 + temp.y * in._22 + temp.z * in._23);
	_43 = -(temp.x * in._31 + temp.y * in._32 + temp.z * in._33);

}
Example #4
0
void matrix4::multiply(matrix4 m) {
    matrix4 product;
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            product.set_at(i, j,
                           matrix[i][0] * m.get_at(0, j)
                           + matrix[i][1] * m.get_at(1, j)
                           + matrix[i][2] * m.get_at(2, j)
                           + matrix[i][3] * m.get_at(3, j));
        }
    }
    float* data = product.get_data();

    for (int i_2 = 0; i_2 < 4; i_2++) {
        for (int j_2 = 0; j_2 < 4; j_2++) {
            int index = putils::get_index_2d(i_2, j_2, 4);
            matrix[i_2][j_2] = data[index];
        }
    }

    delete data;
}
/*********************************************************************************
* Draw 'beethovan' object.
**********************************************************************************/
void drawBet()
{  

	glPushMatrix();
	glMultMatrixd(bet2wld.GLmatrix());
	drawFrame(8);
	float frontColor[] = {0.8, 0.3, 0.1, 1.0};
	glEnable(GL_LIGHTING);
	glMaterialfv(GL_FRONT, GL_AMBIENT, frontColor);
	glMaterialfv(GL_FRONT, GL_DIFFUSE, frontColor);
	glCallList(betID);
	glPopMatrix();
}
Plane makePlane(vector3 const& a, vector3 const& b, vector3 const& n)
{
	vector3 v=a;
	for(int i=0; i<3; i++)
	{
		if(n[i]==1.0)
			v[i]=b[i];
		else if(n[i]==-1.0)
			v[i]=a[i];
		else
			assert(n[i]==0.0);
	}
	//std::cout<<n<<v<<std::endl;
		
	return Plane(cow2wld.rotate(n),cow2wld*v);
}
Example #7
0
void quater::setRotation(const matrix4& m)
{
#ifdef USE_D3DFUNC
	D3DXMATRIX dxmat;
	m.toDXmat(dxmat);
	D3DXQuaternionRotationMatrix(*this,&dxmat);	
#else
	
	// jehee lee implementation
	quater &q=*this;

    double tr, s;
    int    i, j, k;
    static int next[3] = { 1, 2, 0 };

    tr = m.m[0][0] + m.m[1][1] + m.m[2][2];
    if ( tr > 0.0 )
    {
        s = sqrt( tr + 1.0 );
        q[0] = ( s * 0.5 );
        s = 0.5 / s;
        q.x = ( m.m[2][1] - m.m[1][2] ) * s;
        q.y = ( m.m[0][2] - m.m[2][0] ) * s;
        q.z = ( m.m[1][0] - m.m[0][1] ) * s;
    }
    else
    {
        i = 0;
        if ( m.m[1][1] > m.m[0][0] ) i = 1;
        if ( m.m[2][2] > m.m[i][i] ) i = 2;

        j = next[i];
        k = next[j];

        s = sqrt( (m.m[i][i]
					- (m.m[j][j] + m.m[k][k])) + 1.0 );
        q[i+1] = s * 0.5;
        s = 0.5 / s;
        q.w   = ( m.m[k][j] - m.m[j][k] ) * s;
        q[j+1] = ( m.m[j][i] + m.m[i][j] ) * s;
        q[k+1] = ( m.m[k][i] + m.m[i][k] ) * s;
    }


#endif
}
Example #8
0
 void setTransform(const matrix4<Type>& m)
 {
     m_matrix = m;
     m_invertedMatrix = m.inverse();
 }
void onMouseDrag( GLFWwindow* window, double fx, double fy)
{
	int x=fx;
	int y=fy;
#else
void onMouseDrag( int x, int y)
{
#endif
	if (isDrag) 
	{
		printf( "in drag mode %d\n", isDrag);
		if (isDrag==V_DRAG && cowFlag)
		{
			// vertical dragging
			// TODO:
			// create a dragging plane perpendicular to the ray direction, 
			// and test intersection with the screen ray.
      // When dragged just change Y position
			Ray ray;
			screenCoordToRay(clickX, y, ray);
			PickInfo &pp=pickInfo;
			std::pair<bool, double> c=ray.intersects(dragPlane);

			vector3 currentPos=ray.getPoint(c.second);	

      matrix4 T;
      T.setTranslation(currentPos - pp.cowPickPosition, false);
      cow2wld.mult(T, pp.cowPickConfiguration);
		}
		else
		{ 
			// horizontal dragging
			// Hint: read carefully the following block to implement vertical dragging.
			if(cursorOnCowBoundingBox)
			{
				Ray ray;
				screenCoordToRay(x, y, ray);
				PickInfo &pp=pickInfo;
				Plane p(vector3(0,1,0), pp.cowPickPosition);
				std::pair<bool, double> c=ray.intersects(p);

				vector3 currentPos=ray.getPoint(c.second);	

				matrix4 T;
				T.setTranslation(currentPos-pp.cowPickPosition, false);
				cow2wld.mult(T, pp.cowPickConfiguration);
			}
		}
	}
	else
	{
		Ray ray;
		screenCoordToRay(x, y, ray);

		std::vector<Plane> planes;
		vector3 bbmin(cow->bbmin.x, cow->bbmin.y, cow->bbmin.z);
		vector3 bbmax(cow->bbmax.x, cow->bbmax.y, cow->bbmax.z);

		planes.push_back(makePlane(bbmin, bbmax, vector3(0,1,0)));
		planes.push_back(makePlane(bbmin, bbmax, vector3(0,-1,0)));
		planes.push_back(makePlane(bbmin, bbmax, vector3(1,0,0)));
		planes.push_back(makePlane(bbmin, bbmax, vector3(-1,0,0)));
		planes.push_back(makePlane(bbmin, bbmax, vector3(0,0,1)));
		planes.push_back(makePlane(bbmin, bbmax, vector3(0,0,-1)));


		std::pair<bool,double> o=ray.intersects(planes);
		cursorOnCowBoundingBox=o.first;
		PickInfo &pp=pickInfo;
		pp.cursorRayT=o.second;
		pp.cowPickPosition=ray.getPoint(pp.cursorRayT);
		pp.cowPickConfiguration=cow2wld;
		matrix4 invWorld;
		invWorld.inverse(cow2wld);
		// the local position (relative to the cow frame) of the pick position.
		pp.cowPickPositionLocal=invWorld*pp.cowPickPosition;
	}

}

/*********************************************************************************
* Call this part whenever user types keyboard. 
**********************************************************************************/
#if GLFW_VERSION_MAJOR==3
void onKeyPress(GLFWwindow *__win, int key, int __scancode, int action, int __mods)
#else
void onKeyPress( int key, int action)
#endif
{
	if (action==GLFW_RELEASE)
		return 	; // do nothing
	// If 'c' or space bar are pressed, alter the camera.
	// If a number is pressed, alter the camera corresponding the number.
	if ((key == ' ') || (key == 'c'))
	{    
		printf( "Toggle camera %d\n", cameraIndex );
		cameraIndex += 1;
	}      
	else if ((key >= '0') && (key <= '9'))
		cameraIndex = key - '0';

	if (cameraIndex >= (int)wld2cam.size() )
		cameraIndex = 0;
}
void screenCoordToRay(int x, int y, Ray& ray)
{
	int height , width;
#if GLFW_VERSION_MAJOR==3
	glfwGetWindowSize(g_window, &width, &height);
#else
	glfwGetWindowSize(&width, &height);
#endif

	matrix4 matProjection;
	matProjection.getCurrentOpenGLmatrix(GL_PROJECTION_MATRIX);
	matProjection*=wld2cam[cameraIndex];
	matrix4 invMatProjection;
	invMatProjection.inverse(matProjection);

	vector3 vecAfterProjection, vecAfterProjection2;
	// -1<=v.x<1 when 0<=x<width
	// -1<=v.y<1 when 0<=y<height
	vecAfterProjection.x = ((double)(x - 0)/(double)width)*2.0-1.0;
	vecAfterProjection.y = ((double)(y - 0)/(double)height)*2.0-1.0;
	vecAfterProjection.y*=-1;
	vecAfterProjection.z = -10;

	//std::cout<<"cowPosition in clip coordinate (NDC)"<<matProjection*cow2wld.getTranslation()<<std::endl;
	
	vector3 vecBeforeProjection=invMatProjection*vecAfterProjection;

	// camera position
	ray.origin()=cam2wld[cameraIndex].getTranslation();
	ray.direction()=vecBeforeProjection-ray.origin();
	ray.direction().normalize();

	//std::cout<<"dir" <<ray.direction()<<std::endl;

}
//------------------------------------------------------------------------------
void initialize()
{
	cursorOnCowBoundingBox=false;
	// Set up OpenGL state
	glShadeModel(GL_SMOOTH);         // Set Smooth Shading
	glEnable(GL_DEPTH_TEST);         // Enables Depth Testing
	glDepthFunc(GL_LEQUAL);          // The Type Of Depth Test To Do
	// Use perspective correct interpolation if available
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
	// Initialize the matrix stacks
	reshape(width, height);
	// Define lighting for the scene
	float lightDirection[]   = {1.0, 1.0, 1.0, 0};
	float ambientIntensity[] = {0.1, 0.1, 0.1, 1.0};
	float lightIntensity[]   = {0.9, 0.9, 0.9, 1.0};
	glLightfv(GL_LIGHT0, GL_AMBIENT, ambientIntensity);
	glLightfv(GL_LIGHT0, GL_DIFFUSE, lightIntensity);
	glLightfv(GL_LIGHT0, GL_POSITION, lightDirection);
	glEnable(GL_LIGHT0);

	// initialize floor
	{
		// After making checker-patterned texture, use this repetitively.

		// Insert color into checker[] according to checker pattern.
		const int size = 8;
		unsigned char checker[size*size*3];
		for( int i=0; i < size*size; i++ )
		{
			if (((i/size) ^ i) & 1)
			{
				checker[3*i+0] = 200;
				checker[3*i+1] = 32;
				checker[3*i+2] = 32;
			}
			else
			{
				checker[3*i+0] = 200;
				checker[3*i+1] = 200;
				checker[3*i+2] = 32;
			}
		}

		// Make texture which is accessible through floorTexID. 
		glGenTextures( 1, &floorTexID );				
		glBindTexture(GL_TEXTURE_2D, floorTexID);		
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
		glTexImage2D(GL_TEXTURE_2D, 0, 3, size, size, 0, GL_RGB, GL_UNSIGNED_BYTE, checker);
	}
	// initialize cow
	{

		// Read information from cow.obj.
		cow = new WaveFrontOBJ( "cow.obj" );

		// Make display list. After this, you can draw cow using 'cowID'.
		cowID = glGenLists(1);				// Create display lists
		glNewList(cowID, GL_COMPILE);		// Begin compiling the display list using cowID
		cow->Draw();						// Draw the cow on display list.
		glEndList();						// Terminate compiling the display list. Now, you can draw cow using 'cowID'.
		glPushMatrix();						// Push the current matrix of GL into stack.
		glLoadIdentity();					// Set the GL matrix Identity matrix.
		glTranslated(0,-cow->bbmin.y,-8);	// Set the location of cow.
		glRotated(-90, 0, 1, 0);			// Set the direction of cow. These information are stored in the matrix of GL.
		// Read the modelview matrix about location and direction set above, and store it in cow2wld matrix.
		cow2wld.getCurrentOpenGLmatrix(	GL_MODELVIEW_MATRIX);

		glPopMatrix();						// Pop the matrix on stack to GL.
	}
	// initialize bethoben
	{

		// Read information from beethovan.obj.
		bet = new WaveFrontOBJ( "beethovan.obj" );

		// Make display list. After this, you can draw beethovan using 'betID'.
		betID = glGenLists(1);
		glNewList(betID, GL_COMPILE);
		bet->Draw();
		glEndList();
		glPushMatrix();
		glLoadIdentity();
		glTranslated(0,-bet->bbmin.y,8);
		glRotated(180, 0, 1, 0);
		// bet2wld will become T * R
		bet2wld.getCurrentOpenGLmatrix(GL_MODELVIEW_MATRIX);
		glPopMatrix();
	}
	// intialize camera model.
	{
		cam = new WaveFrontOBJ("camera.obj");	// Read information of camera from camera.obj.
		camID = glGenLists(1);					// Create display list of the camera.
		glNewList(camID, GL_COMPILE);			// Begin compiling the display list using camID.
		cam->Draw();							// Draw the camera. you can do this job again through camID..
		glEndList();							// Terminate compiling the display list.

		// initialize camera frame transforms.
		for (int i=0; i < cameraCount; i++ )
		{
			double* c = cameras[i];											// 'c' points the coordinate of i-th camera.
			wld2cam.push_back(matrix4());								// Insert {0} matrix to wld2cam vector.
			glPushMatrix();													// Push the current matrix of GL into stack.
			glLoadIdentity();												// Set the GL matrix Identity matrix.
			gluLookAt(c[0],c[1],c[2], c[3],c[4],c[5], c[6],c[7],c[8]);		// Setting the coordinate of camera.
			wld2cam[i].getCurrentOpenGLmatrix(GL_MODELVIEW_MATRIX);
			glPopMatrix();													// Transfer the matrix that was pushed the stack to GL.
			matrix4 invmat;
			invmat.inverse(wld2cam[i]);
			cam2wld.push_back(invmat);
		}
		cameraIndex = 0;
	}
}
/*********************************************************************************
* Draw 'cow' object.
**********************************************************************************/
void drawCow(matrix4 const& _cow2wld, bool drawBB)
{  

	glPushMatrix();		// Push the current matrix of GL into stack. This is because the matrix of GL will be change while drawing cow.

	// The information about location of cow to be drawn is stored in cow2wld matrix.
	// (Project2 hint) If you change the value of the cow2wld matrix or the current matrix, cow would rotate or move.
	glMultMatrixd(_cow2wld.GLmatrix());

	drawFrame(5);										// Draw x, y, and z axis.
	float frontColor[] = {0.8, 0.2, 0.9, 1.0};
	glEnable(GL_LIGHTING);
	glMaterialfv(GL_FRONT, GL_AMBIENT, frontColor);		// Set ambient property frontColor.
	glMaterialfv(GL_FRONT, GL_DIFFUSE, frontColor);		// Set diffuse property frontColor.
	glCallList(cowID);		// Draw cow. 
	glDisable(GL_LIGHTING);
	if(drawBB){
		glBegin(GL_LINES);
		glColor3d(1,1,1);
		glVertex3d( cow->bbmin.x, cow->bbmin.y, cow->bbmin.z);
		glVertex3d( cow->bbmax.x, cow->bbmin.y, cow->bbmin.z);
		glVertex3d( cow->bbmin.x, cow->bbmax.y, cow->bbmin.z);
		glVertex3d( cow->bbmax.x, cow->bbmax.y, cow->bbmin.z);
		glVertex3d( cow->bbmin.x, cow->bbmin.y, cow->bbmax.z);
		glVertex3d( cow->bbmax.x, cow->bbmin.y, cow->bbmax.z);
		glVertex3d( cow->bbmin.x, cow->bbmax.y, cow->bbmax.z);
		glVertex3d( cow->bbmax.x, cow->bbmax.y, cow->bbmax.z);

		glColor3d(1,1,1);
		glVertex3d( cow->bbmin.x, cow->bbmin.y, cow->bbmin.z);
		glVertex3d( cow->bbmin.x, cow->bbmax.y, cow->bbmin.z);
		glVertex3d( cow->bbmax.x, cow->bbmin.y, cow->bbmin.z);
		glVertex3d( cow->bbmax.x, cow->bbmax.y, cow->bbmin.z);
		glVertex3d( cow->bbmin.x, cow->bbmin.y, cow->bbmax.z);
		glVertex3d( cow->bbmin.x, cow->bbmax.y, cow->bbmax.z);
		glVertex3d( cow->bbmax.x, cow->bbmin.y, cow->bbmax.z);
		glVertex3d( cow->bbmax.x, cow->bbmax.y, cow->bbmax.z);

		glColor3d(1,1,1);
		glVertex3d( cow->bbmin.x, cow->bbmin.y, cow->bbmin.z);
		glVertex3d( cow->bbmin.x, cow->bbmin.y, cow->bbmax.z);
		glVertex3d( cow->bbmax.x, cow->bbmin.y, cow->bbmin.z);
		glVertex3d( cow->bbmax.x, cow->bbmin.y, cow->bbmax.z);
		glVertex3d( cow->bbmin.x, cow->bbmax.y, cow->bbmin.z);
		glVertex3d( cow->bbmin.x, cow->bbmax.y, cow->bbmax.z);
		glVertex3d( cow->bbmax.x, cow->bbmax.y, cow->bbmin.z);
		glVertex3d( cow->bbmax.x, cow->bbmax.y, cow->bbmax.z);


		glColor3d(1,1,1);
		glVertex3d( cow->bbmin.x, cow->bbmin.y, cow->bbmin.z);
		glVertex3d( cow->bbmin.x, cow->bbmax.y, cow->bbmin.z);
		glVertex3d( cow->bbmax.x, cow->bbmin.y, cow->bbmin.z);
		glVertex3d( cow->bbmax.x, cow->bbmax.y, cow->bbmin.z);
		glVertex3d( cow->bbmin.x, cow->bbmin.y, cow->bbmax.z);
		glVertex3d( cow->bbmin.x, cow->bbmax.y, cow->bbmax.z);
		glVertex3d( cow->bbmax.x, cow->bbmin.y, cow->bbmax.z);
		glVertex3d( cow->bbmax.x, cow->bbmax.y, cow->bbmax.z);

		glColor3d(1,1,1);
		glVertex3d( cow->bbmin.x, cow->bbmin.y, cow->bbmin.z);
		glVertex3d( cow->bbmin.x, cow->bbmin.y, cow->bbmax.z);
		glVertex3d( cow->bbmax.x, cow->bbmin.y, cow->bbmin.z);
		glVertex3d( cow->bbmax.x, cow->bbmin.y, cow->bbmax.z);
		glVertex3d( cow->bbmin.x, cow->bbmax.y, cow->bbmin.z);
		glVertex3d( cow->bbmin.x, cow->bbmax.y, cow->bbmax.z);
		glVertex3d( cow->bbmax.x, cow->bbmax.y, cow->bbmin.z);
		glVertex3d( cow->bbmax.x, cow->bbmax.y, cow->bbmax.z);
		glEnd();
	}
	glPopMatrix();			// Pop the matrix in stack to GL. Change it the matrix before drawing cow.
}
void Water::_drawQuad()
{
#if 0
	static float radius = 0.5f;
	static float strength = 1.0f;

	glViewport(0,0,m_frameBufferA->GetWidth(),m_frameBufferA->GetHeight());
	m_frameBufferA->Begin();
	m_shader_drop->bind();
	kmVec2 vec2;
	vec2.x = 0.5f;
	vec2.y = 0.5f;
	m_shader_drop->uniform(RTHASH("center"), vec2);
	m_shader_drop->uniform(RTHASH("radius"), radius);
	m_shader_drop->uniform(RTHASH("strength"), strength);
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D,m_frameBufferB->GetColorTexture());
	glBindTexture(GL_TEXTURE_2D,m_textureObject);
	_renderMesh(m_screenRect,m_shader_drop);
	m_shader_drop->unbind();
	m_frameBufferA->End();
#endif

#if 0
	glViewport(0,0,m_screenWidth,m_screenHeight);
	m_quadShader->bind();
	glActiveTexture(GL_TEXTURE0);
	//glBindTexture(GL_TEXTURE_2D, m_frameBufferB->GetColorTexture());
	glBindTexture(GL_TEXTURE_2D, m_textureObject);
	m_quadShader->uniform(RTHASH("s_texture"), 0);
	_renderMesh(m_screenRect,m_quadShader);
	m_quadShader->unbind();
	glGetError();

	//
#else

	//vector4df transformedVertexs[3];
	//vector4df originalVertex[] = 
	//{
	//	vector4df(0.0f, 0.0f, 0.5f, 1.0f),
	//	vector4df(1.0f, 0.0f, 0.5f, 1.0f),
	//	vector4df(0.0f, 0.0f, -1.0f, 1.0f)
	//};

	//for (int i=0; i<3; ++i)
	//{
	//	g_viewProjectMatrix.transformVect(transformedVertexs[i],originalVertex[i]);
	//}

	matrix4 transposedMatrix = g_viewProjectMatrix.getTransposed();
	vector2df screenSize((float)m_screenWidth, (float)m_screenHeight);
	//vector2df screenSize(10.0f, 10.0f);

	//
	static const float inverseWidth = 1.0f/m_fbWrite->GetWidth();
	static const float inverseHeight = 1.0f/m_fbWrite->GetHeight();
	//

	glViewport(0, 0, m_screenWidth, m_screenHeight); 
	m_shader_water->bind();
	glActiveTexture(GL_TEXTURE0);
#if 1
	glBindTexture(GL_TEXTURE_2D, m_fbRead->GetColorTexture());
#else
	glBindTexture(GL_TEXTURE_2D, m_frameBufferCaustic->GetColorTexture());
#endif
	m_shader_water->uniform(RTHASH("water"),0);

#if 0
	glActiveTexture(GL_TEXTURE1);
	glBindTexture(GL_TEXTURE_2D, m_textureObject);
	m_shader_water->uniform(RTHASH("base"),1);
#endif

	m_shader_water->uniform(RTHASH("screenSize"), screenSize);

#if 1
	m_shader_water->uniform(RTHASH("WVPMatrix"), g_viewProjectMatrixOrc);
#else
	m_shader_water->uniform(RTHASH("WVPMatrix"), g_viewProjectMatrix);
#endif
	vector2df delta(inverseWidth, inverseHeight);
	m_shader_water->uniform(RTHASH("delta"), delta);

	_renderMesh(m_screenRect,m_shader_water);
	m_shader_water->unbind();
	glGetError();
#endif

}
Example #13
0
    //-----------------------------------------------------------------------
    //                          T M e s h S h a p e
    //-----------------------------------------------------------------------
    TMeshShape::TMeshShape(IMesh* mesh, const matrix4& transform, bool isConvex) : TCollisionShape(),        
        m_baseCount(0),
        m_hullCount(0)
    {
        TApplication* app = getApplication();
        app->logMessage(LOG_INFO, "TMeshShape isConvex: %d", isConvex);

        u32 vcount=0, tcount=0;
        for(u32 i=0; i<mesh->getMeshBufferCount(); i++)
        {
            tcount += mesh->getMeshBuffer(i)->getIndexCount() / 3;
            vcount += mesh->getMeshBuffer(i)->getVertexCount();
        }
        app->logMessage(LOG_INFO, "   org vert count: %d", vcount);
        app->logMessage(LOG_INFO, "   org  tri count: %d", tcount);

        btQuaternion q(TMath::HALF_PI,0.f,0.f);
        m_localTransform = transform;
        m_localScale = transform.getScale();

        m_triMesh = extractTriangles(mesh, true);        
        app->logMessage(LOG_INFO, "   ext  tri count: %d", m_triMesh->getNumTriangles());

        if(isConvex)
        {
            if(1)
            {   // using Bullet's btShapeHull class - faster, typically produces less verts/tris
                btConvexShape* tmpConvexShape = new btConvexTriangleMeshShape(m_triMesh);
                m_shape = tmpConvexShape;
                btShapeHull* hull = new btShapeHull(tmpConvexShape);
                btScalar margin = tmpConvexShape->getMargin();
                hull->buildHull(margin);
                tmpConvexShape->setUserPointer(hull);

                app->logMessage(LOG_INFO, "  hull vert count: %d", hull->numVertices());
                app->logMessage(LOG_INFO, "  hull  tri count: %d", hull->numTriangles());

                //btConvexHullShape* chShape = new btConvexHullShape((const btScalar *)hull->getVertexPointer(),hull->numVertices());
                btConvexHullShape* chShape = new btConvexHullShape();
                
                const btVector3* vp = hull->getVertexPointer();
                const unsigned int* ip = hull->getIndexPointer();
                for (int i=0;i<hull->numTriangles();i++)
                {
                    chShape->addPoint(vp[ip[i*3]]);     
                    chShape->addPoint(vp[ip[i*3+1]]);     
                    chShape->addPoint(vp[ip[i*3+2]]);     
                }
                
                m_shape = chShape;
                delete hull;
                delete tmpConvexShape;
            }
            else
            {   // using Bullet's hull library directly
                HullResult  result;
                HullLibrary hl;
                HullDesc    desc;

                desc.mMaxFaces = 256;
                desc.mMaxVertices = 256;
                desc.SetHullFlag(QF_TRIANGLES);
                PHY_ScalarType type, indicestype;
                const unsigned char* indexbase;
                int istride,numfaces;

                m_triMesh->getLockedReadOnlyVertexIndexBase((const unsigned char**)&desc.mVertices, (int&)desc.mVcount, type, 
                    (int&)desc.mVertexStride, &indexbase, istride, numfaces, indicestype);

                HullError ret = hl.CreateConvexHull(desc,result);
                if(ret == QE_OK)
                {
                    app->logMessage(LOG_INFO, "  hull vert count: %d", result.mNumOutputVertices);
                    app->logMessage(LOG_INFO, "  hull  tri count: %d", result.mNumFaces);
                    btConvexHullShape* chShape = new btConvexHullShape();

                    for (unsigned int i=0;i<result.mNumFaces;i++)
                    {             
                        chShape->addPoint(result.m_OutputVertices[result.m_Indices[i*3]]);
                        chShape->addPoint(result.m_OutputVertices[result.m_Indices[i*3+1]]);
                        chShape->addPoint(result.m_OutputVertices[result.m_Indices[i*3+2]]);
                    }

                    m_shape = chShape;
                }
                else
                {
                    m_shape = new btBvhTriangleMeshShape(m_triMesh,true,true);                
                }
                hl.ReleaseResult(result);
            }
        }
        else 
        {
            //m_shape = _decomposeTriMesh();
            m_shape = new btBvhTriangleMeshShape(m_triMesh,true,true);
        }
        btVector3 scale(m_localScale.X, m_localScale.Y, m_localScale.Z);
        m_shape->setLocalScaling(scale);
    }