void ShaderComponentTexture::configureUniforms(vox::MatrixStack* _matrixStack, RenderOptions* _renderOption, NodeRenderable* _nodeRenderable){
	MeshInterface * mesh = dynamic_cast<MeshInterface *>(_nodeRenderable);
	int numTextures = 0;
	if(mesh != nullptr){
		numTextures = mesh->textureCount();
		glUniform1i(glGetUniformLocation(_renderOption->shader->getProgramId(), GL_UNIFORM_ID_NUM_TEXTURES.c_str()), numTextures);
		// Bind each texture to the texture sampler array in the frag _shader
		for(unsigned long int i = 0; i < mesh->textureCount(); i++){
			glActiveTexture(GL_TEXTURE0 + i);
			glBindTexture(GL_TEXTURE_2D, mesh->getTexture(i)->textureId);
			glUniform1i(glGetUniformLocation(_renderOption->shader->getProgramId(), GL_UNIFORM_ID_TEXTURE_SAMPLER.c_str()), i);
		}
	}else{
		glUniform1i(glGetUniformLocation(_renderOption->shader->getProgramId(), GL_UNIFORM_ID_NUM_TEXTURES.c_str()), numTextures);
	}

	SpriteMesh * spriteMesh = dynamic_cast<SpriteMesh *>(_nodeRenderable);
	//Setup the texture for the current animation
	if(spriteMesh != nullptr){	
		if(spriteMesh->animatedTexture != nullptr){
			glActiveTexture(GL_TEXTURE0 + 1 + numTextures);
			glBindTexture(GL_TEXTURE_2D, spriteMesh->animatedTexture->textureId);
			glUniform1i(glGetUniformLocation(_renderOption->shader->getProgramId(), GL_UNIFORM_ID_TEXTURE_SAMPLER.c_str()), numTextures + 1);
			glUniform1i(glGetUniformLocation(_renderOption->shader->getProgramId(), GL_UNIFORM_ID_NUM_TEXTURES.c_str()), numTextures + 1);
		}
	}
}
Пример #2
0
MY_Scene::MY_Scene(Game * _game) :
	Scene(_game),
	screenSurfaceShader(new Shader("assets/RenderSurface", false, true)),
	screenSurface(new RenderSurface(screenSurfaceShader)),
	screenFBO(new StandardFrameBuffer(true)),
	baseShader(new ComponentShaderBase(true)),
	textShader(new ComponentShaderText(true)),
	uiLayer(0,0,0,0),
	bounds(10),
	bulletWorld(new BulletWorld()),
	score(0),
	accuracy(3.f)
{
	baseShader->addComponent(new ShaderComponentMVP(baseShader));
	//baseShader->addComponent(new ShaderComponentDiffuse(baseShader));
	baseShader->addComponent(new ShaderComponentTexture(baseShader));
	baseShader->compileShader();

	textShader->textComponent->setColor(glm::vec3(0.0f, 64.f/255.f, 165.f/255.f));
	
	screenSurface->setScaleMode(GL_NEAREST);

	// remove initial camera
	childTransform->removeChild(cameras.at(0)->parents.at(0));
	delete cameras.at(0)->parents.at(0);
	cameras.pop_back();
	

	// reference counting for member variables
	++baseShader->referenceCount;
	++textShader->referenceCount;

	++screenSurface->referenceCount;
	++screenSurfaceShader->referenceCount;
	++screenFBO->referenceCount;

	float floorL = 1000, floorW = 1000;

	// create floor/ceiling as static bullet planes
	bulletFloor = new BulletMeshEntity(bulletWorld, MeshFactory::getPlaneMesh(), baseShader);
	bulletFloor->setColliderAsStaticPlane(0, 1, 0, 0);
	bulletFloor->createRigidBody(0);
	bulletFloor->body->setFriction(0);
	childTransform->addChild(bulletFloor);
	bulletFloor->meshTransform->scale(-floorL, floorW, 1.f);
	bulletFloor->meshTransform->rotate(-90, 1, 0, 0, kOBJECT);
	bulletFloor->body->getWorldTransform().setRotation(btQuaternion(btVector3(0, 1, 0), glm::radians(180.f)));
	//bulletFloor->mesh->setScaleMode(GL_NEAREST);
	bulletFloor->mesh->scaleModeMag = GL_NEAREST;
	bulletFloor->mesh->scaleModeMin = GL_LINEAR;
	bulletFloor->mesh->pushTexture2D(MY_ResourceManager::scenario->getTexture("CLOUDS")->texture);
	// adjust UVs so that the texture tiles in squares
	for(Vertex & v : bulletFloor->mesh->vertices){
		v.u *= 30.f;
		v.v *= 30.f;
	}



	// car
	TriMesh * shipMesh = MY_ResourceManager::scenario->getMesh("SHIP")->meshes.at(0);
	ship = new BulletMeshEntity(bulletWorld, shipMesh, baseShader);
	childTransform->addChild(ship);
	ship->mesh->setScaleMode(GL_NEAREST);
	ship->mesh->pushTexture2D(MY_ResourceManager::scenario->getTexture("SHIP")->texture);

	ship->setColliderAsBoundingBox();
	ship->createRigidBody(10);
	
	ship->body->setLinearFactor(btVector3(1, 1, 0));
	ship->body->setAngularFactor(btVector3(0, 0, 0));

	ship->maxVelocity = btVector3(10, 10, 0);

	ship->body->setActivationState(4); // always active
	ship->translatePhysical(glm::vec3(0, 10, 0));
	
	//Set up player camera
	zoom = 3.f;
	playerCam = new PerspectiveCamera();
	cameras.push_back(playerCam);
	ship->meshTransform->addChild(playerCam);
	playerCam->nearClip = 0.01f;
	playerCam->farClip = 1000.f;
	playerCam->childTransform->rotate(90, 0, 1, 0, kWORLD);
	playerCam->firstParent()->translate(0, 1.5f, zoom, false);
	playerCam->yaw = 90.0f;
	playerCam->pitch = -10.0f;
	activeCamera = playerCam;

	shipAngle = 0;

	MeshInterface * sphereMesh = MY_ResourceManager::scenario->getMesh("SPHERE")->meshes.at(0);
	sphereMesh->setScaleMode(GL_NEAREST);
	sphereMesh->pushTexture2D(MY_ResourceManager::scenario->getTexture("TRAIL")->texture);

	MeshInterface * ringMesh = MY_ResourceManager::scenario->getMesh("RING")->meshes.at(0);
	ringMesh->setScaleMode(GL_NEAREST);
	ringMesh->pushTexture2D(MY_ResourceManager::scenario->getTexture("RING")->texture);

	trailTimeout = new Timeout(0.05f, [this, sphereMesh](sweet::Event * _event){
		// add player trail
		BulletMeshEntity * t = new BulletMeshEntity(bulletWorld, sphereMesh, baseShader);
		t->setColliderAsBoundingSphere();
		t->createRigidBody(1, 0, 0);
		childTransform->addChild(t);
		trail.push_back(t);
		t->translatePhysical(ship->meshTransform->getWorldPos(), false);
		t->childTransform->scale(sweet::NumberUtils::randomFloat(1,3));
		t->meshTransform->rotate(sweet::NumberUtils::randomFloat(0, 360), 0, 0, 1, kOBJECT);
		t->body->applyCentralImpulse(btVector3(sweet::NumberUtils::randomFloat(-3,3), sweet::NumberUtils::randomFloat(-3,3), sweet::NumberUtils::randomFloat(-3,3) + 10));
		trailTimeout->restart();
	});
	trailTimeout->start();
	//childTransform->addChild(trailTimeout);

	
	obstacleTimeout = new Timeout(0.5f, [this, ringMesh](sweet::Event * _event){
		// add player trail
		BulletMeshEntity * t = new BulletMeshEntity(bulletWorld, ringMesh, baseShader);
		t->setColliderAsBoundingSphere();
		t->createRigidBody(0, 0, 0);
		childTransform->addChild(t);
		obstacles.push_back(t);
		t->translatePhysical(glm::vec3(sweet::NumberUtils::randomFloat(-bounds,bounds)*0.5, sweet::NumberUtils::randomFloat(bounds*0.2,bounds*0.8), -300), false);
		t->meshTransform->rotate(sweet::NumberUtils::randomFloat(0, 360), 0, 0, 1, kOBJECT);
		t->body->setActivationState(4); // always active
		obstacleTimeout->restart();
	});
	obstacleTimeout->start();
	//childTransform->addChild(obstacleTimeout);

	VerticalLinearLayout * vl = new VerticalLinearLayout(uiLayer.world);
	vl->setRationalHeight(1.0f);
	vl->setRationalWidth(1.f);
	vl->setMarginTop(0.1f);
	vl->setRenderMode(kTEXTURE);
	vl->verticalAlignment = kTOP;


	scoreIndicator = new TextLabel(uiLayer.world, MY_ResourceManager::scenario->getFont("FONT")->font, textShader, 1.f);
	scoreIndicator->horizontalAlignment = kCENTER;
	scoreIndicator->setText("SCORE: 0");
	scoreIndicator->invalidateLayout();

	vl->addChild(scoreIndicator);
	uiLayer.addChild(vl);



	MY_ResourceManager::scenario->getAudio("BGM")->sound->play(true);
}
MY_Scene_Main::MY_Scene_Main(Game * _game) :
	MY_Scene_Base(_game),
	bulletWorld(new BulletWorld(glm::vec3(0, -9.8, 0.1))),
	bulletDebugDrawer(new BulletDebugDrawer(bulletWorld->world)),
	indicatorShader(new ComponentShaderBase(true)),
	maskComponentIndicator(nullptr),
	mirrorShader(new ComponentShaderBase(true)),
	vrCam(new StereoCamera()),


	currentTrack(nullptr),
	currentTrackId(-1),

	screenSurfaceShader(new Shader("assets/engine basics/DefaultRenderSurface", false, true)),
	screenSurface(new RenderSurface(screenSurfaceShader, true)),
	screenFBO(new StandardFrameBuffer(true)),
	
	paletteDefIdx(-1),
	
	waitingForInput(false),
	currentHoverTarget(nullptr),
	hoverTime(0),
	targetHoverTime(1.f),

	eventManager(new sweet::EventManager()),
	done(false)
{

	indicatorShader->addComponent(new ShaderComponentMVP(indicatorShader));	
	indicatorShader->addComponent(new ShaderComponentTexture(indicatorShader, 0.1f));
	maskComponentIndicator = new ShaderComponentCircularMask(indicatorShader, 0.1);
	indicatorShader->addComponent(maskComponentIndicator);
	indicatorShader->compileShader();
	indicatorShader->incrementReferenceCount();

	mirrorShader->addComponent(new ShaderComponentMVP(mirrorShader));
	mirrorShader->addComponent(new ShaderComponentTexture(mirrorShader, 0.1f));
	mirrorShader->addComponent(mirrorBlur = new ShaderComponentBlur(mirrorShader));
	mirrorShader->compileShader();
	mirrorShader->incrementReferenceCount();

	// Setup the debug drawer and add it to the scene
	bulletWorld->world->setDebugDrawer(bulletDebugDrawer);
	childTransform->addChild(bulletDebugDrawer, false);
	bulletDebugDrawer->setDebugMode(btIDebugDraw::DBG_NoDebug);


	MeshInterface * chairMesh = MY_ResourceManager::globalAssets->getMesh("chair")->meshes.at(0);
	chairMesh->pushTexture2D(MY_ResourceManager::globalAssets->getTexture("chair")->texture);
	chairMesh->setScaleMode(GL_NEAREST);

	for(signed long int i = -1; i <= 1; ++i){
		MeshEntity * chair = new MeshEntity(chairMesh, baseShader);
		childTransform->addChild(chair)->translate(glm::vec3(i * 3, 0, 0));
	}
	
	
	std::vector<TriMesh *> environmentMeshes = MY_ResourceManager::globalAssets->getMesh("salon-environment")->meshes;
	std::vector<TriMesh *> propMeshes = MY_ResourceManager::globalAssets->getMesh("salon-props")->meshes;
	std::vector<std::string> environmentMeshOrder;
	environmentMeshOrder.push_back("floor");
	environmentMeshOrder.push_back("walls");
	environmentMeshOrder.push_back("ceiling");
	environmentMeshOrder.push_back("storefront");
	environmentMeshOrder.push_back("door");
	environmentMeshOrder.push_back("windows");
	environmentMeshOrder.push_back("road");
	environmentMeshOrder.push_back("buildings");
	environmentMeshOrder.push_back("sidewalk");

	std::vector<glm::vec3> propMeshOrder;
	propMeshOrder.push_back(glm::vec3(1, 0.96, 0));
	propMeshOrder.push_back(glm::vec3(0.8, 0.45, 0.45));
	propMeshOrder.push_back(glm::vec3(0.5, 0.05, 0.2));
	propMeshOrder.push_back(glm::vec3(1,1,1));
	propMeshOrder.push_back(glm::vec3(0.02, 0.6, 0));
	propMeshOrder.push_back(glm::vec3(0.4, 0.9, 0.9));
	
	for(unsigned long int i = 0; i < environmentMeshes.size(); ++i){
		MeshEntity * c = new MeshEntity(environmentMeshes.at(i), baseShader);
		c->mesh->pushTexture2D(MY_ResourceManager::globalAssets->getTexture("salon-" + environmentMeshOrder.at(i))->texture);
		c->mesh->setScaleMode(GL_NEAREST);
		childTransform->addChild(c, false);
	}
	for(unsigned long int i = 0; i < propMeshes.size(); ++i){
		MeshEntity * c = new MeshEntity(propMeshes.at(i), baseShader);
		for(auto & v : c->mesh->vertices){
			v.red = propMeshOrder.at(i).r;
			v.green = propMeshOrder.at(i).g;
			v.blue = propMeshOrder.at(i).b;
		}
		c->mesh->setScaleMode(GL_NEAREST);
		childTransform->addChild(c, false);
	}


	activeCamera = vrCam;
	cameras.push_back(vrCam);
	vrCam->yaw = -90;
	vrCam->nearClip = 0.001f;
	vrCam->fieldOfView = 110;

	avatar = new MY_Avatar(baseShader, vrCam);
	childTransform->addChild(avatar);
	avatar->head->childTransform->addChild(vrCam)->translate(0, 0.5f, 0);

	/*MeshEntity * test = new MeshEntity(Resource::loadMeshFromObj("assets/meshes/buttman.obj", true).at(0), baseShader);
	Texture * tex = new Texture("assets/textures/buttman.png", false, true, true);
	tex->load();
	test->mesh->pushTexture2D(tex);
	childTransform->addChild(test)->translate(0, 3, 2)->rotate(90, 0, 1, 0, kOBJECT);*/
	

	
	/*MY_SelectionTarget * palette = new MY_SelectionTarget(bulletWorld, MY_ResourceManager::globalAssets->getMesh("palette")->meshes.at(0), baseShader);
	palette->mesh->pushTexture2D(MY_ResourceManager::globalAssets->getTexture("palette")->texture);
	childTransform->addChild(palette);
	palette->setColliderAsBoundingBox();
	//palette->setColliderAsSphere(5);
	palette->createRigidBody(0);
	palette->translatePhysical(glm::vec3(0, 3, 2));
	palette->name = "test";*/
	//palette->rotatePhysical(90, 0, 1, 0, kOBJECT);
	
	CameraController * c = new CameraController(vrCam);
	c->movementSpeed = 0.05f;
	vrCam->childTransform->addChild(c, false);

	std::vector<glm::vec2> points;
	std::string json = sweet::FileUtils::readFile("assets/path.json");
	Json::Reader reader;
	Json::Value path;
	bool parsingSuccessful = reader.parse( json, path);
	if(!parsingSuccessful){
		Log::error("JSON parse failed: " + reader.getFormattedErrorMessages());
	}else{		
		glm::vec2 ratio = glm::vec2(ROOM_WIDTH/path["windowSize"][0].asFloat(), ROOM_DEPTH/path["windowSize"][1].asFloat());
		for(auto point : path["points"]) {
			// Reverse co-ordinates because player is facing down z axis
			float x = /*ratio.y * */point[0].asFloat();
			float z = /*ratio.x * */point[1].asFloat() / glm::length(ratio);
			points.push_back(glm::vec2(x, z));	
		}
	}

	// setup the artist
	artist = new MY_MakeupArtist(baseShader, points);
	childTransform->addChild(artist);//->scale(0.9);

	palette = new MY_Palette(bulletWorld, baseShader);
	childTransform->addChild(palette);
	palette->translateComponents(glm::vec3(0, 3, 2));

	

	// parse palettes
	{
		Json::Reader reader;
		Json::Value json;
		bool parsingSuccessful;
	
		parsingSuccessful = reader.parse(sweet::FileUtils::readFile("assets/palettes.json"), json);

		assert(parsingSuccessful);

		for(Json::Value::ArrayIndex i = 0; i < json["palettes"].size(); ++i){
			paletteDefs.push_back(new MY_Palette_Definition(json["palettes"][i].get("name", "NO_NAME").asString(), MY_ResourceManager::globalAssets->getTexture(json["palettes"][i].get("texture", "DEFAULT").asString())->texture));
		}
	}

	Sprite * sprite = new Sprite(MY_ResourceManager::globalAssets->getTexture("indicator")->texture, indicatorShader);

	auto sd = sweet::getWindowDimensions();
	uiLayer->resize(0, sd.x, 0, sd.y);

	VerticalLinearLayout * crosshairLayout = new VerticalLinearLayout(uiLayer->world);
	crosshairLayout->setRationalWidth(1.0f, uiLayer);
	crosshairLayout->setRationalHeight(1.0f, uiLayer);
	crosshairLayout->horizontalAlignment = kCENTER;
	crosshairLayout->verticalAlignment = kMIDDLE;

	NodeUI * crossHair = new NodeUI(uiLayer->world);
	crossHair->setWidth(15);
	crossHair->setHeight(15);
	crossHair->background->mesh->pushTexture2D(MY_ResourceManager::globalAssets->getTexture("crosshair")->texture);
	crossHair->background->mesh->setScaleMode(GL_NEAREST);

	crosshairLayout->addChild(crossHair);

	crossHair->childTransform->addChild(sprite)->scale(100)->translate(7.5f, 7.5f, 0.f);

	uiLayer->addChild(crosshairLayout);

	
	// setup mirror
	mirrorCamera = new PerspectiveCamera();
	childTransform->addChild(mirrorCamera);
	cameras.push_back(mirrorCamera);
	mirrorCamera->firstParent()->translate(-0.5f, 3.25f, 4, false);

	mirrorFBO = new StandardFrameBuffer(true);
	mirrorTex = new FBOTexture(mirrorFBO, true, 0, false);
	mirrorTex->load();
	mirrorSurface = new MeshEntity(MY_ResourceManager::globalAssets->getMesh("salon-mirror")->meshes.at(0), mirrorShader);
	mirrorSurface->mesh->setScaleMode(GL_LINEAR);
	mirrorSurface->mesh->uvEdgeMode = GL_CLAMP_TO_EDGE;
	mirrorSurface->mesh->pushTexture2D(mirrorTex);
	childTransform->addChild(mirrorSurface);
	mirrorFBO->incrementReferenceCount();


	// memory management
	screenSurface->incrementReferenceCount();
	screenSurfaceShader->incrementReferenceCount();
	screenFBO->incrementReferenceCount();



	// load the tracks
	tracks = new Tracks();

	// start the experience
	getNextTrack();
	loadNextPalette();



	fade = new NodeUI(uiLayer->world);
	uiLayer->addChild(fade);
	fade->setRationalHeight(1.f, uiLayer);
	fade->setRationalWidth(1.f, uiLayer);
	fade->setBackgroundColour(0,0,0,1);

	Timeout * fadeIn = new Timeout(1.f, [this](sweet::Event * _event){
		fade->setVisible(false);
	});
	fadeIn->eventManager->addEventListener("progress", [this](sweet::Event * _event){
		float p = _event->getFloatData("progress");
		fade->setBackgroundColour(0,0,0,1.f-p);
	});
	fadeIn->start();
	childTransform->addChild(fadeIn, false);


	// recenter HMD
	ovr_RecenterPose(*sweet::hmd);

	startTime = glfwGetTime();
}
Пример #4
0
void mexFunction( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
	
  if (nrhs < 1 || !(mxIsChar(prhs[0]))) {
	mexErrMsgTxt("Bad input.");
  }
	
  int cmdlen = (mxGetM(prhs[0]) * mxGetN(prhs[0])) + 1;
  char *cmd = (char*)mxCalloc(cmdlen, sizeof(char));
  mxGetString(prhs[0], cmd, cmdlen);
	
  float nan = sqrtf(-1.0f);
  float inf = MAX_FLOAT; //1.0f/0.0f;
	
  if (strcmp(cmd, "create") == 0) {
		
	int ix_v = 1; int ix_f = 2;

	if (nrhs < 3
		|| mxGetNumberOfDimensions(prhs[ix_v]) != 2
		|| mxGetNumberOfDimensions(prhs[ix_f]) != 2
		|| mxGetM(prhs[ix_v]) != 3
		|| mxGetM(prhs[ix_f]) != 3)
	  mexErrMsgTxt("Requires vertices (3 x n_v) and faces (3 x n_f).");
		
	int n_v = (int) mxGetN(prhs[ix_v]);
	int n_f = (int) mxGetN(prhs[ix_f]);

	Mesh *fv = new Mesh;
	mxArray *fmat; mxArray *vmat;
	mexCallMATLAB(1, &fmat, 1,(mxArray **)prhs+ix_f, "int32");	
	mexCallMATLAB(1, &vmat, 1,(mxArray **)prhs+ix_v, "single");	
	convertfv(fmat,vmat,fv);

	// Create the tree
	Model *opcode = new Model;
	MeshInterface *cMesh = new MeshInterface;
	cMesh->SetInterfaceType(MESH_TRIANGLE);
	cMesh->SetNbTriangles(n_f);
	cMesh->SetNbVertices(n_v);
	//cMesh->SetCallback(trivertsCallback,(void*)fv);
	cMesh->SetPointers(fv->cIndices,fv->cVertices);
	OPCODECREATE OPCC;
	OPCC.mIMesh = cMesh;
	BuildSettings cBS;
    cBS.mRules = SPLIT_SPLATTER_POINTS | SPLIT_GEOM_CENTER;
	OPCC.mSettings = cBS;
	OPCC.mNoLeaf = true;
	OPCC.mQuantized = false;
	OPCC.mKeepOriginal = false; // For debug
	bool status = opcode->Build(OPCC);

	if (!status) {
	  mexErrMsgTxt("Error when making tree.");
	}

	plhs[0] = convertPtr2Mat<Model>(opcode);
	//plhs[1] = convertPtr2Mat<MeshInterface>(cMesh);
	//plhs[1] = convertPtr2Mat<IceMaths::IndexedTriangle>(fv->cIndices);
	//plhs[2] = convertPtr2Mat<IceMaths::Point>(fv->cVertices);
  }
  else if (strcmp(cmd, "intersect") == 0) {
		
	int ix_t = 1; int ix_c1 = 2; int ix_c2 = 3;
		
	if (nrhs < 4
	    || mxGetNumberOfDimensions(prhs[ix_c1]) != 2
		|| mxGetNumberOfDimensions(prhs[ix_c2]) != 2
		|| mxGetM(prhs[ix_c1]) != 3
		|| mxGetM(prhs[ix_c2]) != 3
		|| mxGetN(prhs[ix_c1]) != mxGetN(prhs[ix_c2]))
	  mexErrMsgTxt("Req. aabb tree handle, ray start (3 x n_c) and ray dir. (3 x n_c).");			
		
	Model *opcode = convertMat2Ptr<Model>(prhs[ix_t]);
	//MeshInterface *cMesh = convertMat2Ptr<MeshInterface>(prhs[ix_tf]);
	//opcode->SetMeshInterface(cMesh);
	//IceMaths::IndexedTriangle *fvf = convertMat2Ptr<IceMaths::IndexedTriangle>(prhs[ix_tf]);
	//IceMaths::Point *fvv = convertMat2Ptr<IceMaths::Point>(prhs[ix_tv]);
	RayCollider RC;
	RC.SetFirstContact(false);
	RC.SetClosestHit(true);
	RC.SetCulling(false);
	RC.SetMaxDist(inf);
	CollisionFaces CF;
	RC.SetDestination(&CF);

	int n_c = (int) mxGetN(prhs[ix_c1]);
	int ix_hit=0,ix_dist=1,ix_tridx=2,ix_bary=3;

	mxArray *rayorig;
	mxArray *raydir;	
	mexCallMATLAB(1, &rayorig, 1,(mxArray **)prhs+ix_c1, "single");	
	mexCallMATLAB(1, &raydir, 1,(mxArray **)prhs+ix_c2, "single");	
		
	// Create an output array of indices
	unsigned char *hitptr = 0;
	plhs[ix_hit] = mxCreateNumericMatrix(n_c,1,mxLOGICAL_CLASS,mxREAL);
	hitptr = (unsigned char*) mxGetData(plhs[ix_hit]);
		
	float *distptr = 0;
	if (nlhs > ix_dist) {
	  plhs[ix_dist] = mxCreateNumericMatrix(n_c, 1, mxSINGLE_CLASS, mxREAL);
	  distptr = (float*) mxGetData(plhs[ix_dist]);
	}
		
	int*tridxptr = 0;
	if (nlhs > ix_tridx) {
	  plhs[ix_tridx] = mxCreateNumericMatrix(n_c, 1, mxINT32_CLASS, mxREAL);
	  tridxptr = (int *) mxGetData(plhs[ix_tridx]);
	}

	float *baryptr = 0;
	if (nlhs > ix_bary) {
	  plhs[ix_bary] = mxCreateNumericMatrix(2, n_c, mxSINGLE_CLASS, mxREAL);
	  baryptr = (float *) mxGetData(plhs[ix_bary]);
	}

	float *rayo = (float*)mxGetData(rayorig);
	float *rayd = (float*)mxGetData(raydir);
	bool hit,status;
	int i;
	IceMaths::Point cStart, cDir;
	IceMaths::Ray cRay;
	
	for (i=0; i<n_c; i++) {
	  IceMaths::Point cStart = IceMaths::Point(rayo[3*i],rayo[3*i+1],rayo[3*i+2]);
	  IceMaths::Point cDir = IceMaths::Point(rayd[3*i],rayd[3*i+1],rayd[3*i+2]);
	  //cDir.Normalize();
	  IceMaths::Ray cRay = IceMaths::Ray(cStart,cDir);
	  static udword Cache;
	  status = RC.Collide(cRay, *opcode, NULL, &Cache);
	  if (!status) mexErrMsgTxt("Error when hitting.");
	  hit = RC.GetContactStatus();
	  
	  hitptr[i] = (unsigned char)hit;
	  //	printf("hit %d hitd %f\n",hit,hitDistance);

	  const CollisionFace* colFaces;
	  if (nlhs > ix_dist) {
		colFaces = CF.GetFaces();
		//	  printf("hitD: %f\n", hitDistance);
		distptr[i] = hit ? colFaces[0].mDistance : nan;
	  }
	  if (nlhs > ix_tridx) {
		tridxptr[i] = hit ? (colFaces[0].mFaceID+1) : 0; // 1-based
	  }
	  if (nlhs > ix_bary) {
		baryptr[2*i] = hit ? colFaces[0].mU : nan;
		baryptr[2*i+1] = hit ? colFaces[0].mV : nan;
		//printf("hitL: %f %f %f\n",
		//hitLocation[0],hitLocation[1],hitLocation[2]);
	  }
	}
  }
  else if (strcmp(cmd, "update") == 0) {
		
	int ix_t = 1; int ix_v = 2;
		
	if (nrhs < 3 || mxGetM(prhs[ix_v]) != 3)
	  mexErrMsgTxt("Req. aabb tree handle, vertices (3 x n_v).");			
		
	Model *opcode = convertMat2Ptr<Model>(prhs[ix_t]);

	int n_v = (int) mxGetN(prhs[ix_v]);
	if (n_v != opcode->GetMeshInterface()->GetNbVertices()) {
		mexErrMsgTxt("Input vertices need to match current mesh.");
	}

	mxArray *vertices;
	mexCallMATLAB(1, &vertices, 1,(mxArray **)prhs+ix_v, "single");
	float *v = (float*)mxGetData(vertices);
	IceMaths::Point* vc = (IceMaths::Point*)opcode->GetMeshInterface()->GetVerts();
	for (int ki=0; ki<n_v; ki++) {
		vc[ki] = IceMaths::Point(v[ki*3],v[ki*3+1],v[ki*3+2]);
	}
	opcode->Refit();
  }
  else if (strcmp(cmd, "delete") == 0) {
	int ix_t = 1;
	if (nrhs < 2) mexErrMsgTxt("Requires aabb tree.");
	destroyObject<Model>(prhs[ix_t]);
  }
  else {
	mexErrMsgTxt("Command not recognized.");
  }
}