예제 #1
0
void GX_Project(f32 mx, f32 my, f32 mz, Mtx mv, const f32 *projection,
					const f32 *viewport, f32 *sx, f32 *sy, f32 *sz)
{
	float x, y, z, w;

	guVector vec = (guVector) { mx, my, mz };
	guVector vecRes;
	guVecMultiply(mv, &vec, &vecRes);

	if(projection[0] == GX_PERSPECTIVE)
	{
		x = (vecRes.x * projection[1]) + (vecRes.z * projection[2]);
		y = (vecRes.y * projection[3]) + (vecRes.z * projection[4]);
		z = (vecRes.z * projection[5]) + projection[6];
		w = -1.0f / vecRes.z;
	}
	else
	{
		x = (vecRes.x * projection[1]) + projection[2];
		y = (vecRes.y * projection[3]) + projection[4];
		z = (vecRes.z * projection[5]) + projection[6];
		w = 1.0f;
	}

	*sx = viewport[0] + (w * x * viewport[2] + viewport[2]) * 0.5f;
	*sy = viewport[1] - (w * y * viewport[3] - viewport[3]) * 0.5f;
	*sz = viewport[5] + (w * z * (viewport[5] - viewport[4]));
}
예제 #2
0
파일: gl.c 프로젝트: machinamentum/gl2gx
void glLightfv( GLenum light, GLenum pname, const GLfloat *params ){
	int lightNum = 0;
	switch(light)
	{
		case GL_LIGHT0: lightNum = 0; break;
		case GL_LIGHT1: lightNum = 1; break;
		case GL_LIGHT2: lightNum = 2; break;
		case GL_LIGHT3: lightNum = 3; break;
		case GL_LIGHT4: lightNum = 4; break;
		case GL_LIGHT5: lightNum = 5; break;
		case GL_LIGHT6: lightNum = 6; break;
		case GL_LIGHT7: lightNum = 7; break;						
	};

	guVector lightPos={0.0F,0.0F,0.0F}; //TODO: make it opengl default light position
	GXColor defcolor={0xFF,0xFF,0xFF,0xFF};
	switch(pname)
	{
		case GL_POSITION: 
			lightPos.x = params[0];
			lightPos.y = params[1];
			lightPos.z = params[2];
			guVecMultiply(model,&lightPos,&lightPos); //update light position by current model matrix
			gxlightpos[lightNum].x = lightPos.x;
			gxlightpos[lightNum].y = lightPos.y;
			gxlightpos[lightNum].z = lightPos.z;
			gxlightpos[lightNum].w = params[3]; //leave W param untouched
			gxcurlight = lightNum;
			break;
		case GL_DIFFUSE:
			gxlightdiffusecolor[lightNum].r = params[0];
			gxlightdiffusecolor[lightNum].g = params[1];
			gxlightdiffusecolor[lightNum].b = params[2];
			gxlightdiffusecolor[lightNum].a = params[3];
			break;
		case GL_AMBIENT:
			gxlightambientcolor[lightNum].r = params[0];
			gxlightambientcolor[lightNum].g = params[1];
			gxlightambientcolor[lightNum].b = params[2];
			gxlightambientcolor[lightNum].a = params[3];
			break;
		case GL_SPECULAR:
			gxlightspecularcolor[lightNum].r = params[0];
			gxlightspecularcolor[lightNum].g = params[1];
			gxlightspecularcolor[lightNum].b = params[2];
			gxlightspecularcolor[lightNum].a = params[3];
			break;
		case GL_SPOT_DIRECTION:
             gxspotdirection[lightNum].x = params[0];
             gxspotdirection[lightNum].y = params[1];
             gxspotdirection[lightNum].z = params[2];
             gxspotdirection[lightNum].w = params[3];
             break;
	};
};
예제 #3
0
void orderQueue(CAMERA * cam)
{
	TRACKER * tz = transQueue;//Temporal storage Queue;
	TRACKER * aux, *t;
	transQueue = NULL;
	Vector v;
	aux = tz;
	while(aux)
	{
		tz = aux->next;
		aux->next = NULL;
		//
		v = aux->target->getPos();
		guVecMultiply(view, &v, &v);
		aux->z = v.z;
		//
		t = transQueue;
		if(t)
		{
			while(t->next)
			{
				if(aux->z > t->next->z)
					t = t->next;
				else break;
			}
			if(aux->z > t->z)
			{
				aux->next = t->next;
				t->next = aux;
			}
			else
			{
				aux->next = transQueue;
				transQueue = aux;
			}
		}
		else
		{
			transQueue = aux;
			aux->next = NULL;
		}
		aux = tz;
	}
}
예제 #4
0
void render(NODE * node, Vector camPos)
{
	Mtx tmp;
	if(!node->isRenderable()) return;//Skip non-renderable nodes such as empty nodes, regions or lights
	if(node->flags & F_Visible)//Is it visible?
	{
		//Set matrices
		Mtx aux, inv;
		GX_ClearVtxDesc();
		node->absMtx(modelM);
		char msg[64];

		guMtxConcat(view, modelM, modelview);
		GX_LoadPosMtxImm(modelview, GX_PNMTX0);//Load model view matrix
		guMtxInverse(modelview, tmp);
		guMtxTranspose(tmp,inv);
		GX_LoadNrmMtxImm(inv, GX_PNMTX0);//Load normal matrix

		//TODO: Better lighting (multiple lights)
		std::vector<LIGHT*>::iterator light = mainRoot->getLights().begin();
		//if(light == mainRoot->getLights().end())
		//	REVConsole->write("LIGHT");
		GXLightObj lObj[8];
		u8 lightMask = 0, tmpLight = GX_LIGHT0;
		for(u8 i = 0;light != mainRoot->getLights().end(); ++light, ++i)
		{
			Vector lpos = (*light)->getPos();
			guVecMultiply(view, &lpos, &lpos);
			
			GX_InitLightPos(&lObj[i],lpos.x,lpos.y,lpos.z);
			GX_InitLightAttn(&lObj[i], 1.0f,0.0f,0.0f,1.0f,0.0f,0.0f);
			GX_InitLightSpot(&lObj[i],0.0f,GX_SP_OFF);
			GX_InitLightColor(&lObj[i],(*light)->clr);
			GX_LoadLightObj(&lObj[i],tmpLight);
			lightMask |= tmpLight;
			tmpLight *= 2;
		}
		//Render the node
		node->render(lightMask);
	}
}
예제 #5
0
void SetLight(Mtx view)
{
	guVector lpos;
	GXLightObj lobj;

	lpos.x = 0;
	lpos.y = 0;
	lpos.z = 2.0f;

	guVecMultiply(view,&lpos,&lpos);

	GX_InitLightPos(&lobj,lpos.x,lpos.y,lpos.z);
	GX_InitLightColor(&lobj,lightColor[0]);
	GX_LoadLightObj(&lobj,GX_LIGHT0);
	
	// set number of rasterized color channels
	GX_SetNumChans(1);
    GX_SetChanCtrl(GX_COLOR0A0,GX_ENABLE,GX_SRC_VTX,GX_SRC_VTX,GX_LIGHT0,GX_DF_CLAMP,GX_AF_NONE);
    GX_SetChanAmbColor(GX_COLOR0A0,lightColor[1]);
    GX_SetChanMatColor(GX_COLOR0A0,lightColor[2]);
}
예제 #6
0
파일: gl.c 프로젝트: machinamentum/gl2gx
void glEnd(void) {
     
     GX_SetCullMode(GX_CULL_FRONT);

	Mtx mvi;
	Mtx mv;
	
//	Mtx inversemodelview;

	// load the modelview matrix into matrix memory
	guMtxConcat(view,model,modelview);
	GX_LoadPosMtxImm(modelview, GX_PNMTX0);

	//for normals first calculate normal matrix (thanks shagkur)
    guMtxInverse(modelview,mvi); 
    guMtxTranspose(mvi,modelview); 
    GX_LoadNrmMtxImm(modelview,GX_PNMTX0); //experimtal leave out (hmm works good?)


	//use global ambient light together with current material ambient and add emissive material color
	GXColor constcolor;
	constcolor.r = (gxcurrentmaterialambientcolor.r*gxglobalambientlightcolor.r) * 0xFF;
	constcolor.g = (gxcurrentmaterialambientcolor.g*gxglobalambientlightcolor.g) * 0xFF;
	constcolor.b = (gxcurrentmaterialambientcolor.b*gxglobalambientlightcolor.b) * 0xFF;
	constcolor.a = (gxcurrentmaterialambientcolor.a*gxglobalambientlightcolor.a) * 0xFF;
	GX_SetTevColor(GX_TEVREG0, constcolor);
	
	GXColor emiscolor;
	emiscolor.r = gxcurrentmaterialemissivecolor.r * 0xFF;
	emiscolor.g = gxcurrentmaterialemissivecolor.g * 0xFF;
	emiscolor.b = gxcurrentmaterialemissivecolor.b * 0xFF;
	emiscolor.a = gxcurrentmaterialemissivecolor.a * 0xFF;
	GX_SetTevColor(GX_TEVREG1, emiscolor);

	//first check if a lightdirtyflag is set (thanks ector) so we do not have to set up light every run
	//also usefull on matrices etc.

	//now set each light
	GXColor gxchanambient;
	gxchanambient.r = gxcurrentmaterialambientcolor.r;
	gxchanambient.g = gxcurrentmaterialambientcolor.g;
	gxchanambient.b = gxcurrentmaterialambientcolor.b;
	gxchanambient.a = gxcurrentmaterialambientcolor.a;
	
	GXColor gxchanspecular;
	gxchanspecular.r = gxcurrentmaterialspecularcolor.r;
	gxchanspecular.g = gxcurrentmaterialspecularcolor.g;
	gxchanspecular.b = gxcurrentmaterialspecularcolor.b;
	gxchanspecular.a = gxcurrentmaterialspecularcolor.a;	
	
	int lightcounter = 0;
	for (lightcounter =0; lightcounter < 4; lightcounter++){

		if(gxlightenabled[lightcounter]){ //when light is enabled

            //somewhere here an error happens?

            //Setup mat/light ambient color 
			gxchanambient.r = ((gxchanambient.r * gxlightambientcolor[lightcounter].r) * 0xFF);
			gxchanambient.g = ((gxchanambient.g * gxlightambientcolor[lightcounter].g) * 0xFF);
			gxchanambient.b = ((gxchanambient.b * gxlightambientcolor[lightcounter].b) * 0xFF);
			gxchanambient.a = ((gxchanambient.a * gxlightambientcolor[lightcounter].a) * 0xFF);
			GX_SetChanAmbColor(GX_COLOR0A0, gxchanambient ); 
			
			//Setup diffuse material color
			GXColor mdc;
			mdc.r = (gxcurrentmaterialdiffusecolor.r * 0xFF);
			mdc.g = (gxcurrentmaterialdiffusecolor.g * 0xFF);
			mdc.b = (gxcurrentmaterialdiffusecolor.b * 0xFF);
			mdc.a = (gxcurrentmaterialdiffusecolor.a * 0xFF);
			GX_SetChanMatColor(GX_COLOR0A0, mdc ); 
			
			//Setup specular material color
//			gxcurrentmaterialshininess *
			gxchanspecular.r = (gxchanspecular.r * gxlightspecularcolor[lightcounter].r) * 0xFF;
			gxchanspecular.g = (gxchanspecular.g * gxlightspecularcolor[lightcounter].g) * 0xFF;
			gxchanspecular.b = (gxchanspecular.b * gxlightspecularcolor[lightcounter].b) * 0xFF;
			gxchanspecular.a = (gxchanspecular.a * gxlightspecularcolor[lightcounter].a) * 0xFF;
			GX_SetChanMatColor(GX_COLOR1A1, gxchanspecular); // use red as test color

            //Setup light diffuse color
            GXColor ldc;
			ldc.r = gxlightdiffusecolor[lightcounter].r * 0xFF;
			ldc.g = gxlightdiffusecolor[lightcounter].g * 0xFF;
			ldc.b = gxlightdiffusecolor[lightcounter].b * 0xFF;
			ldc.a = gxlightdiffusecolor[lightcounter].a * 0xFF;
			GX_InitLightColor(&gxlight[lightcounter], ldc ); //move call to glend or init?;
            GX_InitLightColor(&gxlight[lightcounter+4], ldc ); //move call to glend or init?;

			//Setup light postion
			
			//check on w component when 1. light is positional
			//                     when 0. light is directional at infinite pos
			
			guVector lpos;
			guVector wpos;
            lpos.x = gxlightpos[lightcounter].x;
            lpos.y = gxlightpos[lightcounter].y;
            lpos.z = gxlightpos[lightcounter].z;
               
               
            if (gxlightpos[lightcounter].w == 0){
                guVecNormalize(&lpos);
                lpos.x *= BIG_NUMBER;
                lpos.y *= BIG_NUMBER;
                lpos.z *= BIG_NUMBER;
            }
            
			guVecMultiply(view,&lpos,&wpos);	   //light position should be transformed by world-to-view matrix (thanks h0lyRS)
			GX_InitLightPosv(&gxlight[lightcounter], &wpos); //feed corrected coord to light pos
			GX_InitLightPosv(&gxlight[lightcounter+4], &wpos); //feed corrected coord to light pos
		


            //Setup light direction (when w is 1 dan dir = 0,0,0
            guVector ldir;
            if (gxlightpos[lightcounter].w==0){ 
               //lpos.x = gxlightpos[lightcounter].x;
			   //lpos.y = gxlightpos[lightcounter].y;
               //lpos.z = gxlightpos[lightcounter].z;
                                                
               ldir.x = gxlightpos[lightcounter].x;
               ldir.y = gxlightpos[lightcounter].y;
               ldir.z = gxlightpos[lightcounter].z;
            }
            else
            {
                if (gxspotcutoff[lightcounter] != 180){ //if we have a spot light direction is needed
                   ldir.x = gxspotdirection[lightcounter].x;
                   ldir.y = gxspotdirection[lightcounter].y;
                   ldir.z = gxspotdirection[lightcounter].z;
                }
                else { 
                     ldir.x = 0;
                     ldir.y = 0;
                     ldir.z = -1;
               }
            }
            
            //guVecNormalize(&ldir);
            //ldir.x *= BIG_NUMBER;
            //ldir.y *= BIG_NUMBER;
            //ldir.z *= BIG_NUMBER;
            
            guMtxInverse(view,mvi);
            guMtxTranspose(mvi,view);
            
            guVecMultiply(view,&ldir,&ldir); //and direction should be transformed by inv-transposed of world-to-view (thanks h0lyRS)
            
            GX_InitLightDir(&gxlight[lightcounter], ldir.x, ldir.y, ldir.z); //feed corrected coord to light dir
            GX_InitLightDir(&gxlight[lightcounter+4], ldir.x, ldir.y, ldir.z); //feed corrected coord to light dir
           
            
			if (gxspotcutoff[lightcounter] != 180){
               //Setup specular light (only for spotlight when GL_SPOT_CUTOFF <> 180)
			   //make this line optional? If on it disturbs diffuse light?
               guVector sdir;
               sdir.x = gxspotdirection[lightcounter].x;
               sdir.y = gxspotdirection[lightcounter].y;
               sdir.z = gxspotdirection[lightcounter].z;
               //guVecNormalize(&sdir);
                     
               //sdir.x *= BIG_NUMBER;
               //sdir.y *= BIG_NUMBER;
               //sdir.z *= BIG_NUMBER;       
                              
			   guVecMultiply(view,&sdir,&sdir);
			   
			   guVector light_dir;
			   guVecSub(&sdir, &lpos, &light_dir);
			   
			   GX_TestInitSpecularDir(&gxlight[lightcounter], light_dir.x, light_dir.y, light_dir.z); //needed to enable specular light
               GX_TestInitSpecularDir(&gxlight[lightcounter+4], light_dir.x, light_dir.y, light_dir.z); //needed to enable specular light
               
            };
            
            
            //this calls:
            // #define GX_InitLightShininess(lobj, shininess) (GX_InitLightAttn(lobj, 0.0F, 0.0F, 1.0F, (shininess)/2.0F, 0.0F, 1.0F-(shininess)/2.0F ))

            //Setup distance attinuation (opengl vs gx differences?)
			//GX_InitLightDistAttn(&gxlight[lightcounter], 100.0f, gxspotexponent[lightcounter], GX_DA_GENTLE); //gxspotexponent was 0.5f
                                                     //ref_dist, bright, dist func  
            //k0 = 1.0;                   
            //k1 = 0.5f*(1.0f-ref_brite)/(ref_brite*ref_dist);
 			//k2 = 0.5f*(1.0f-ref_brite)/(ref_brite*ref_dist*ref_dist); or 0.0f;                  
                    
                    
                     
            //Attenuation factor = 1 / (kc + kl*d + kq*d2) 
            //kc = constant attenuation factor (default = 1.0) 
            //kl = linear attenuation factor (default = 0.0) 
            //kq = quadratic attenuation factor (default = 0.0) 
         
            float distance = BIG_NUMBER; //either distance of light or falloff factor
            float factor = 1 / (gxconstantattanuation[lightcounter] + gxlinearattanuation[lightcounter]*distance + gxquadraticattanuation[lightcounter]*distance*distance);                   
             
            //float factor = 5.0; 
             
            //k0 - 0;                            
       		//k1 = 0.5f*(1.0f-ref_brite)/(ref_brite*ref_dist);
 			//k2 = 0.5f*(1.0f-ref_brite)/(ref_brite*ref_dist*ref_dist);                            

/*                           
            GX_InitLightAttn(&gxlight[lightcounter], 
                                                     1.0, //filled by initlightspot
                                                     0.0, //filled by initlightspot
                                                     0.0, //filled by initlightspot
                                                     gxconstantattanuation[lightcounter], 
                                                     gxlinearattanuation[lightcounter]*distance, 
                                                     gxquadraticattanuation[lightcounter]*distance*distance
                                                     
                                                     ) ;
                                                   //  k0              k1   , k2                    
*/                           
                                                     
            //GX_InitLightAttnK(&gxlight[lightcounter],  (gxcurrentmaterialshininess)/2.0F , 0.0F ,1.0F-(gxcurrentmaterialshininess)/2.0F);
            
             
                     
            
            GX_InitLightDistAttn(&gxlight[lightcounter], factor ,1.0, GX_DA_STEEP); //gxspotexponent[lightcounter] GX_DA_GENTLE
            GX_InitLightDistAttn(&gxlight[lightcounter+4], factor ,1.0, GX_DA_STEEP); //gxspotexponent[lightcounter] GX_DA_GENTLE

            
                                                         //ref_dist //ref_brite
            //                                           factor / strenght
//1.0 is //    glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, 10.0f); ??
                                                     
                                                           
            //Setup light type (normal/spotlight)
            //0-90 / 255-0
            
            
                                                //cut_off, spot func
            //GX_InitLightSpot(&gxlight[lightcounter], 0.0f, GX_SP_OFF); //not this is not a spot light
            
            //GX_InitLightShininess(&gxlight[lightcounter], gxcurrentmaterialshininess); // /180?
            
            //float testspot = 90 - ((gxcurrentmaterialshininess * 90) / 128); //thanks ector 90 - (x * 90 / 255) 
            //if (gxcurrentmaterialshininess == 0){
            //   testspot = 90;
            //}
            //zid 255-gxcurrentmaterialshininess/(255/90);
            
            //setup specular highlight
            //GX_InitLightSpot(&gxlight[lightcounter], testspot, GX_SP_COS); //not this is not a spot light (gxspotcutoff[lightcounter])
            
            //setup normal spotlight
            GX_InitLightSpot(&gxlight[lightcounter], gxspotcutoff[lightcounter], GX_SP_RING1); //not this is not a spot light ()
            GX_InitLightSpot(&gxlight[1], gxspotcutoff[lightcounter], GX_SP_RING1); //not this is not a spot light ()
            
            if ( gxcurrentmaterialshininess != 0 ) {
                 //if (gxspotcutoff[lightcounter] != 180) {
                    GX_TestInitLightShininess(&gxlight[lightcounter+4], gxcurrentmaterialshininess);
                 //}
            };

			//Load the light up
			switch (lightcounter){
				case 0: 
                     GX_LoadLightObj(&gxlight[lightcounter], GX_LIGHT0);
                     GX_LoadLightObj(&gxlight[lightcounter+4], GX_LIGHT4);  
                     break;
				case 1: 
                     GX_LoadLightObj(&gxlight[lightcounter], GX_LIGHT1);
                     GX_LoadLightObj(&gxlight[lightcounter+4], GX_LIGHT5); 
                     break;
				case 2: 
                     GX_LoadLightObj(&gxlight[lightcounter], GX_LIGHT2); 
                     GX_LoadLightObj(&gxlight[lightcounter+4], GX_LIGHT6);
                     break;
				case 3: 
                     GX_LoadLightObj(&gxlight[lightcounter], GX_LIGHT3); 
                     GX_LoadLightObj(&gxlight[lightcounter+4], GX_LIGHT7);
                     break;
//				case 4: GX_LoadLightObj(&gxlight[lightcounter], GX_LIGHT4); break;
//				case 5: GX_LoadLightObj(&gxlight[lightcounter], GX_LIGHT5); break;
//				case 6: GX_LoadLightObj(&gxlight[lightcounter], GX_LIGHT6); break;
//				case 7: GX_LoadLightObj(&gxlight[lightcounter], GX_LIGHT7); break;
			}
			
			//GX_LoadLightObj(&gxlight[lightcounter], GX_LIGHT0);
			//GX_LoadLightObj(&gxlight[1], GX_LIGHT1);

		}
	}


	//set the curtexture if tex2denabled
	if (tex2denabled){
	GX_LoadTexObj(&gxtextures[curtexture], GX_TEXMAP0); //TODO: make GX_TEXMAP0 dynamic for multitexturing
	};

	//now we can draw the gx way (experiment try render in reverse ivm normals pointing the wrong way)
	
	int countelements = _numelements*2;
	if (gxcullfaceanabled==true){
       countelements = _numelements;
    }
	
	GX_Begin(_type, GX_VTXFMT0, countelements); //dependend on culling setting
	int i =0;
                                //default
//order dependend on glFrontFace(GL_CCW); 
//or GL_CW //	for( i=0; i<_numelements; i++)

//GX_TRIANGLESTRIP   GL_TRIANGLE_STRIP
//0 1 2			     0 1 2
//1 3 2			     2 1 3
//2 3 4			     2 3 4
//better think of a clever swapping routine
//maybe then no need to invert normal for trianglestrip anymore

//also GX_TRIANLES need to be drawn in reverse?
//but GX_QUAD does not

//so GX = CW by default while opengl is CCW by default?

//bushing say cannot i be possibel that opengl reorders vertexes

//u32 reverse = 0;
//int pos = 0;
//int temp = 0;

//GL_POLYGON: http://www.gamedev.net/reference/articles/article425.asp

bool cw = true;
bool ccw = true;

if(gxcullfaceanabled==true){
   cw = false;
   ccw = false;                            
   switch(gxwinding){
      case GL_CW: cw = true; break;
      case GL_CCW: ccw = true; break;
   }                         
}

    if (cw==true){ 
       //CW     
       for( i=_numelements-1; i>=0; i--)
       {
            UploadVertex(i);    	
       }
    }
    
    if (ccw==true){
       //CCW
       for( i=0; i<_numelements; i++)
       {
            UploadVertex(i);    	
       }
    }


	GX_End();

	//clean up just to be sure
	i =0;
	for( i=0; i<_numelements; i++)
	{
		_vertexelements[i].x = 0.0F;
		_vertexelements[i].y = 0.0F;
		_vertexelements[i].z = 0.0F;

		_normalelements[i].x = 0.0F;
		_normalelements[i].y = 0.0F;
		_normalelements[i].z = 0.0F;

		_colorelements[i].r = 0.0F;
		_colorelements[i].g = 0.0F;
		_colorelements[i].b = 0.0F;
		_colorelements[i].a = 0.0F;

		_texcoordelements[i].s = 0.0F;
		_texcoordelements[i].t = 0.0F;

	}
	_numelements =0;
}
예제 #7
0
파일: raycast.c 프로젝트: Hamcha/hovercraft
BOOL Raycast(object_t* object, guVector* raydir, guVector* rayorigin, f32* distanceOut, guVector* normalOut) {
	/* Init data */
	model_t * const mesh = object->mesh;
	u16 *baseindices = mesh->modelIndices;
	guVector *vertices = (guVector*) mesh->modelPositions;
	guVector *normals = (guVector*) mesh->modelNormals;
	Mtx InverseObjMtx;
	guVector rayO, rayD;

	OBJECT_flush(object);

	/* Get the raycast into object space */
	guMtxInverse(object->transform.matrix, InverseObjMtx);

	guVecMultiply(InverseObjMtx, rayorigin, &rayO);
	guVecMultiplySR(InverseObjMtx, raydir, &rayD);
	f32 rayScale = sqrtf(guVecDotProduct(&rayD, &rayD));
	guVecNormalize(&rayD);

	/* Temporary variables */
	guVector e1, e2;
	guVector P, Q, T;
	float inv_det, u, v;
	float t;

	BOOL hit = FALSE;
	f32 sdist = 0;

	guVector *normal = 0;

	/* Iterate over every triangle */
	u32 f = 0;
	for (; f < mesh->modelFaceCount; ++f) {
		u16 *indices = baseindices + (f * 3);

		/* Get data */
		guVector *point0 = &vertices[indices[0]],
				 *point1 = &vertices[indices[1]],
				 *point2 = &vertices[indices[2]];

		guVecSub(point1, point0, &e1);
		guVecSub(point2, point0, &e2);

		guVecCross(&rayD, &e2, &P);

		float det = guVecDotProduct(&e1, &P);

		/* NOT CULLING */
		if (det > -EPSILON && det < EPSILON) {
			continue;
		}
		inv_det = 1.f / det;

		/* Calculate distance from V1 to ray origin */
		guVecSub(&rayO, point0, &T);

		/* Calculate u parameter and test bound */
		u = guVecDotProduct(&T, &P) * inv_det;
		/* The intersection lies outside of the triangle */
		if (u < 0.f || u > 1.f) {
			continue;
		}

		/* Prepare to test v parameter */
		guVecCross(&T, &e1, &Q);

		/* Calculate V parameter and test bound */
		v = guVecDotProduct(&rayD, &Q) * inv_det;
		/* The intersection lies outside of the triangle */
		if (v < 0.f || u + v  > 1.f) {
			continue;
		}

		t = guVecDotProduct(&e2, &Q) * inv_det;

		if (t > EPSILON) { /* Got a ray intersection! */
			if (t < sdist || hit == 0) {
				sdist = t;
				normal = &normals[indices[0]]; //TODO Interpolate 3 normals to get the positional one?
				hit = TRUE;
			}
		}
	}

	if (hit == TRUE) {
		*distanceOut = sdist / rayScale;
		if (normalOut != NULL) {
			*normalOut = *normal;
		}
	}

	return hit;
}