void guLookAt(Mtx mt,Vector *camPos,Vector *camUp,Vector *target) { Vector vLook,vRight,vUp; vLook.x = camPos->x - target->x; vLook.y = camPos->y - target->y; vLook.z = camPos->z - target->z; guVecNormalize(&vLook); guVecCross(camUp,&vLook,&vRight); guVecNormalize(&vRight); guVecCross(&vLook,&vRight,&vUp); mt[0][0] = vRight.x; mt[0][1] = vRight.y; mt[0][2] = vRight.z; mt[0][3] = -( camPos->x * vRight.x + camPos->y * vRight.y + camPos->z * vRight.z ); mt[1][0] = vUp.x; mt[1][1] = vUp.y; mt[1][2] = vUp.z; mt[1][3] = -( camPos->x * vUp.x + camPos->y * vUp.y + camPos->z * vUp.z ); mt[2][0] = vLook.x; mt[2][1] = vLook.y; mt[2][2] = vLook.z; mt[2][3] = -( camPos->x * vLook.x + camPos->y * vLook.y + camPos->z * vLook.z ); }
static void face_to_sphere (guVector *out, int face, float a, float b) { guVector sphere; guVector eye = { 0, 0, -1 }; switch (face) { case 0: /* left */ sphere.x = -1.0; sphere.y = -b; sphere.z = -a; break; case 1: /* front */ sphere.x = -a; sphere.y = -b; sphere.z = 1.0; break; case 2: /* right */ sphere.x = 1.0; sphere.y = -b; sphere.z = a; break; case 3: /* back */ sphere.x = a; sphere.y = -b; sphere.z = -1; break; case 4: /* top */ sphere.x = -a; sphere.y = 1.0; sphere.z = b; break; case 5: /* bottom */ sphere.x = -a; sphere.y = -1.0; sphere.z = -b; break; } /* We just need to add the "sphere" & eye vectors, then normalize. */ guVecNormalize (&sphere); guVecAdd (&sphere, &eye, out); if (out->x == 0 && out->y == 0 && out->z == 0) out->z += 0.0001; guVecNormalize (out); }
void guVecHalfAngle(Vector *a,Vector *b,Vector *half) { Vector tmp1,tmp2,tmp3; tmp1.x = -a->x; tmp1.y = -a->y; tmp1.z = -a->z; tmp2.x = -b->x; tmp2.y = -b->y; tmp2.z = -b->z; guVecNormalize(&tmp1); guVecNormalize(&tmp2); guVecAdd(&tmp1,&tmp2,&tmp3); if(guVecDotProduct(&tmp3,&tmp3)>0.0f) guVecNormalize(&tmp3); *half = tmp3; }
static void glass_postpass (void *dummy) { GXLightObj lo0; guVector ldir; #include "glass-postpass.inc" GX_SetChanAmbColor (GX_ALPHA0, (GXColor) { 0, 0, 0, 0 }); GX_SetChanMatColor (GX_ALPHA0, (GXColor) { 0, 0, 0, 255 }); GX_SetChanCtrl (GX_ALPHA0, GX_ENABLE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT0, GX_DF_NONE, GX_AF_SPEC); /* Light 0: use for both specular and diffuse lighting. */ guVecSub (&light0.tpos, &light0.tlookat, &ldir); guVecNormalize (&ldir); GX_InitSpecularDir (&lo0, -ldir.x, -ldir.y, -ldir.z); GX_InitLightShininess (&lo0, 128); GX_InitLightColor (&lo0, (GXColor) { 192, 192, 192, 255 }); GX_LoadLightObj (&lo0, GX_LIGHT0); }
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; }
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; }