void CCharShape::AdjustOrientation (CControl *ctrl, double dtime, double dist_from_surface, TVector3 surf_nml) { TVector3 new_x, new_y, new_z; TMatrix cob_mat, inv_cob_mat; TMatrix rot_mat; TQuaternion new_orient; double time_constant; static TVector3 minus_z_vec = { 0, 0, -1}; static TVector3 y_vec = { 0, 1, 0 }; if (dist_from_surface > 0) { new_y = ScaleVector (1, ctrl->cvel); NormVector (&new_y); new_z = ProjectToPlane (new_y, MakeVector(0, -1, 0)); NormVector (&new_z); new_z = AdjustRollvector (ctrl, ctrl->cvel, new_z); } else { new_z = ScaleVector (-1, surf_nml); new_z = AdjustRollvector (ctrl, ctrl->cvel, new_z); new_y = ProjectToPlane (surf_nml, ScaleVector (1, ctrl->cvel)); NormVector(&new_y); } new_x = CrossProduct (new_y, new_z); MakeBasismatrix_Inv (cob_mat, inv_cob_mat, new_x, new_y, new_z); new_orient = MakeQuaternionFromMatrix (cob_mat); if (!ctrl->orientation_initialized) { ctrl->orientation_initialized = true; ctrl->corientation = new_orient; } time_constant = dist_from_surface > 0 ? TO_AIR_TIME : TO_TIME; ctrl->corientation = InterpolateQuaternions ( ctrl->corientation, new_orient, min (dtime / time_constant, 1.0)); ctrl->plane_nml = RotateVector (ctrl->corientation, minus_z_vec); ctrl->cdirection = RotateVector (ctrl->corientation, y_vec); MakeMatrixFromQuaternion (cob_mat, ctrl->corientation); // Trick rotations new_y = MakeVector (cob_mat[1][0], cob_mat[1][1], cob_mat[1][2]); RotateAboutVectorMatrix (rot_mat, new_y, (ctrl->roll_factor * 360)); MultiplyMatrices (cob_mat, rot_mat, cob_mat); new_x = MakeVector (cob_mat[0][0], cob_mat[0][1], cob_mat[0][2]); RotateAboutVectorMatrix (rot_mat, new_x, ctrl->flip_factor * 360); MultiplyMatrices (cob_mat, rot_mat, cob_mat); TransposeMatrix (cob_mat, inv_cob_mat); TransformNode (0, cob_mat, inv_cob_mat); }
TQuaternion MakeRotationQuaternion (TVector3 s, TVector3 t){ TQuaternion res; TVector3 u; double cos2phi, sin2phi; double cosphi, sinphi; u = CrossProduct (s, t); sin2phi = NormVector (&u); if (sin2phi < EPS) { res = MakeQuaternion (0., 0., 0., 1.); } else { cos2phi = DotProduct (s, t); sinphi = sqrt ( (1 - cos2phi) / 2.0); cosphi = sqrt ( (1 + cos2phi) / 2.0); res.x = sinphi * u.x; res.y = sinphi * u.y; res.z = sinphi * u.z; res.w = cosphi; } return res; }
TVector3 MakeNormal (const TPolygon& p, TVector3 *v) { TVector3 v1 = SubtractVectors (v[p.vertices[1]], v[p.vertices[0]]); TVector3 v2 = SubtractVectors (v[p.vertices[p.num_vertices-1]], v[p.vertices[0]]); TVector3 normal = CrossProduct (v1, v2); NormVector (normal); return normal; }
void EarClipper::RemoveCollinearPointsFromConsideration() { if (vertices.size() > 3) { VertexList::iterator first = vertices.begin(); VertexList::iterator second = first.next(); Line2D_t ray(*(first->point), NormVector(*(second->point) - *(first->point)), true); VertexList::iterator currentSafe = first; VertexList::iterator possibleCollinear = second; VertexList::iterator currentCheck = second.next(); do { if (ray.IsPointOnLine(*(currentCheck->point), COLLINEAR_TOLERANCE)) { currentSafe->collinearPoints.push_back(possibleCollinear->point); vertices.erase(possibleCollinear); } else { currentSafe = possibleCollinear; ray.P = *(currentSafe->point); ray.V = NormVector(*(currentCheck->point) - ray.P); } possibleCollinear = currentCheck; currentCheck = currentCheck.next(); } while (possibleCollinear != vertices.begin()); ray.P = *(currentSafe->point); ray.V = NormVector(*(possibleCollinear->point) - ray.P); if (ray.IsPointOnLine(*(currentCheck->point), COLLINEAR_TOLERANCE)) { currentSafe->collinearPoints.push_back(possibleCollinear->point); MigrateCollinearPoints(currentSafe, possibleCollinear); vertices.erase(possibleCollinear); } } }
bool IntersectPolygon (TPolygon p, TVector3 *v) { TRay ray; TVector3 nml, edge_nml, edge_vec; TVector3 pt; double d, s, nuDotProd, wec; double edge_len, t, distsq; int i; nml = MakeNormal (p, v); ray.pt = MakeVector (0., 0., 0.); ray.vec = nml; nuDotProd = DotProduct (nml, ray.vec); if (fabs(nuDotProd) < EPS) return false; d = - (nml.x * v[p.vertices[0]].x + nml.y * v[p.vertices[0]].y + nml.z * v[p.vertices[0]].z); if (fabs (d) > 1) return false; for (i=0; i < p.num_vertices; i++) { TVector3 *v0, *v1; v0 = &v[p.vertices[i]]; v1 = &v[p.vertices[ (i+1) % p.num_vertices ]]; edge_vec = SubtractVectors (*v1, *v0); edge_len = NormVector (&edge_vec); t = - DotProduct (*((TVector3 *) v0), edge_vec); if (t < 0) { distsq = MAG_SQD2 (*v0); } else if (t > edge_len) { distsq = MAG_SQD2 (*v1); } else { *v0 = AddVectors (*v0, ScaleVector (t, edge_vec)); distsq = MAG_SQD2 (*v0); } if (distsq <= 1) return true; } s = - (d + DotProduct (nml, MakeVector (ray.pt.x, ray.pt.y, ray.pt.z))) / nuDotProd; pt = AddVectors (ray.pt, ScaleVector (s, ray.vec)); for (i=0; i < p.num_vertices; i++) { edge_nml = CrossProduct (nml, SubtractVectors (v[p.vertices[ (i+1) % p.num_vertices ]], v[p.vertices[i]])); wec = DotProduct (SubtractVectors (pt, v[p.vertices[i]]), edge_nml); if (wec < 0) return false; } return true; }
void EarClipper::AdjustForPossibleResultingCollinearity(VertexListIteratorList& ears, VertexList::iterator& beforeEar, VertexList::iterator& afterEar) { beforeEar->collinearPoints.clear(); if (vertices.size() > 3) { FVector2 beforeToAfter = NormVector(*(afterEar->point) - *(beforeEar->point)); Line2D_t rayBefore(*(beforeEar->point), -beforeToAfter, true); Line2D_t rayAfter(*(afterEar->point), beforeToAfter, true); VertexList::iterator twiceBeforeEar = beforeEar.previous(); VertexList::iterator twiceAfterEar = afterEar.next(); bool removeBeforeEar = rayBefore.IsPointOnLine(*(twiceBeforeEar->point), COLLINEAR_TOLERANCE); bool removeAfterEar = rayAfter.IsPointOnLine(*(twiceAfterEar->point), COLLINEAR_TOLERANCE); if (removeBeforeEar && removeAfterEar) { twiceBeforeEar->collinearPoints.push_back(beforeEar->point); twiceBeforeEar->collinearPoints.push_back(afterEar->point); MigrateCollinearPoints(twiceBeforeEar, afterEar); } else if (removeBeforeEar) { twiceBeforeEar->collinearPoints.push_back(beforeEar->point); } else if (removeAfterEar) { beforeEar->collinearPoints.push_back(afterEar->point); MigrateCollinearPoints(beforeEar, afterEar); } if (removeBeforeEar) { if (beforeEar->type == VertexType::Ear) { RemoveEar(beforeEar->point, ears); } vertices.erase(beforeEar); } if (removeAfterEar) { if (afterEar->type == VertexType::Ear) { RemoveEar(afterEar->point, ears); } vertices.erase(afterEar); } } }
TVector3 MakeNormal (TPolygon p, TVector3 *v) { TVector3 normal, v1, v2; v1 = SubtractVectors (v[p.vertices[1]], v[p.vertices[0]]); v2 = SubtractVectors (v[p.vertices[p.num_vertices-1]], v[p.vertices[0]]); normal = CrossProduct (v1, v2); NormVector (&normal); return normal; }
TVector3 CCharShape::AdjustRollvector (CControl *ctrl, TVector3 vel, TVector3 zvec) { TMatrix rot_mat; vel = ProjectToPlane (zvec, vel); NormVector (&vel); if (ctrl->is_braking) { RotateAboutVectorMatrix (rot_mat, vel, ctrl->turn_fact * BRAKING_ROLL_ANGLE); } else { RotateAboutVectorMatrix (rot_mat, vel, ctrl->turn_fact * MAX_ROLL_ANGLE); } return TransformVector (rot_mat, zvec); }
TVector3 CCourse::FindCourseNormal (double x, double z) const { double *elevation = Course.elevation; int x0, x1, y0, y1; GetIndicesForPoint (x, z, &x0, &y0, &x1, &y1); TIndex2 idx0, idx1, idx2; double u, v; FindBarycentricCoords (x, z, &idx0, &idx1, &idx2, &u, &v); const TVector3& n0 = Course.nmls[ idx0.i + nx * idx0.j ]; const TVector3& n1 = Course.nmls[ idx1.i + nx * idx1.j ]; const TVector3& n2 = Course.nmls[ idx2.i + nx * idx2.j ]; TVector3 p0 = COURSE_VERTX (idx0.i, idx0.j); TVector3 p1 = COURSE_VERTX (idx1.i, idx1.j); TVector3 p2 = COURSE_VERTX (idx2.i, idx2.j); TVector3 smooth_nml = AddVectors ( ScaleVector (u, n0), AddVectors (ScaleVector (v, n1), ScaleVector (1.-u-v, n2))); TVector3 tri_nml = CrossProduct ( SubtractVectors (p1, p0), SubtractVectors (p2, p0)); NormVector (tri_nml); double min_bary = min (u, min (v, 1. - u - v)); double interp_factor = min (min_bary / NORM_INTERPOL, 1.0); TVector3 interp_nml = AddVectors ( ScaleVector (interp_factor, tri_nml), ScaleVector (1.-interp_factor, smooth_nml)); NormVector (interp_nml); return interp_nml; }
void CalcFinishControls (CControl *ctrl, double timestep, bool airborne) { TVector3 movdir = ctrl->cvel; double speed = NormVector (movdir); double dir_angle = atan (movdir.x / movdir.z) * 57.3; if (fabs (dir_angle) > 5 && speed > 5) { ctrl->turn_fact = dir_angle / 20; if (ctrl->turn_fact < -1) ctrl->turn_fact = -1; if (ctrl->turn_fact > 1) ctrl->turn_fact = 1; ctrl->turn_animation += ctrl->turn_fact * 2 * timestep; } else { ctrl->turn_fact = 0; if (timestep < ROLL_DECAY) { ctrl->turn_animation *= 1.0 - timestep / ROLL_DECAY; } else ctrl->turn_animation = 0.0; } }
TQuaternion MakeRotationQuaternion (const TVector3& s, const TVector3& t) { TVector3 u = CrossProduct (s, t); double sin2phi = NormVector (u); if (sin2phi < EPS) { return TQuaternion (0., 0., 0., 1.); } else { double cos2phi = DotProduct (s, t); double sinphi = sqrt ( (1 - cos2phi) / 2.0); double cosphi = sqrt ( (1 + cos2phi) / 2.0); return TQuaternion( sinphi * u.x, sinphi * u.y, sinphi * u.z, cosphi); } }
// ------------------------------------------------------- void DrawHud (CControl *ctrl) { TVector3 vel; double speed; if (!param.show_hud) return; vel = ctrl->cvel; speed = NormVector (&vel); SetupGuiDisplay (); draw_gauge (speed * 3.6, ctrl->jump_amt); set_gl_options (TEXFONT); glColor4f (1, 1, 1, 1); draw_time(); draw_herring_count (g_game.herring); DrawSpeed (speed * 3.6); DrawFps (); DrawCoursePosition (ctrl); if (g_game.wind_id > 0) DrawWind2 (Wind.Angle (), Wind.Speed (), ctrl); }
void Asteroid::ResolveCollision(Asteroid& otherAsteroid) { std::chrono::high_resolution_clock::time_point now = std::chrono::high_resolution_clock::now(); if (lastCollision == &otherAsteroid) { std::chrono::high_resolution_clock::duration diff = now - lastCollisionTime; if (std::chrono::duration_cast<std::chrono::milliseconds>(diff).count() < 500) { return; } } if (otherAsteroid.lastCollision == this) { std::chrono::high_resolution_clock::duration diff = now - otherAsteroid.lastCollisionTime; if (std::chrono::duration_cast<std::chrono::milliseconds>(diff).count() < 500) { return; } } Locus::Triangle3D_t intersectingTriangle1, intersectingTriangle2; if ( GetAsteroidIntersection(otherAsteroid, intersectingTriangle1, intersectingTriangle2) ) { Locus::FVector3 collisionPoint = Locus::Triangle3D_t::ComputeCentroid(intersectingTriangle1, intersectingTriangle2); Locus::FVector3 impulseDirection = NormVector(intersectingTriangle1.Normal()); Locus::ResolveCollision(1.0f, BoundingSphere(), otherAsteroid.BoundingSphere(), collisionPoint, impulseDirection, motionProperties, otherAsteroid.motionProperties); lastCollision = &otherAsteroid; otherAsteroid.lastCollision = this; now = std::chrono::high_resolution_clock::now(); lastCollisionTime = now; otherAsteroid.lastCollisionTime = now; } }
bool CCourse::LoadObjectTypes () { CSPList list (MAX_OBJECT_TYPES+10); if (!list.Load (param.obj_dir, "object_types.lst")) { Message ("could not load object types"); return false; } ObjTypes.resize(list.Count()); for (size_t i=0; i<list.Count(); i++) { const string& line = list.Line(i); ObjTypes[i].name = SPStrN (line, "name", ""); ObjTypes[i].textureFile = ObjTypes[i].name; ObjTypes[i].texture = NULL; ObjTypes[i].drawable = SPBoolN (line, "draw", true); if (ObjTypes[i].drawable) { ObjTypes[i].textureFile = SPStrN (line, "texture", ""); } ObjTypes[i].collectable = SPBoolN (line, "snap", -1) != 0; if (ObjTypes[i].collectable == 0) { ObjTypes[i].collectable = -1; } ObjTypes[i].collidable = SPBoolN (line, "coll", false); ObjTypes[i].reset_point = SPBoolN (line, "reset", false); ObjTypes[i].use_normal = SPBoolN (line, "usenorm", false); if (ObjTypes[i].use_normal) { ObjTypes[i].normal = SPVector3N (line, "norm", TVector3(0, 1, 0)); NormVector ((ObjTypes[i].normal)); } ObjTypes[i].poly = 1; } list.MakeIndex (ObjectIndex, "name"); return true; }
Model_t ModelUtility::MakeSphere(float radius, unsigned int subdivisions) { if (subdivisions > ModelUtility::MAX_SPHERE_SUBDIVISIONS) { subdivisions = ModelUtility::MAX_SPHERE_SUBDIVISIONS; } Model_t octahedron = ModelUtility::MakeOctahedron(radius); std::vector<Triangle3D_t> initialTriangles; Transformation identity; for (std::size_t faceIndex = 0, numFaces = octahedron.NumFaces(); faceIndex < numFaces; ++faceIndex) { initialTriangles.push_back(octahedron.GetFaceTriangle(faceIndex, identity)); } std::vector<Triangle3D_t> subdividedTriangles; subdividedTriangles.reserve( initialTriangles.size() * static_cast<std::size_t>(std::pow(4, subdivisions)) ); for (const Triangle3D_t& triangle : initialTriangles) { ModelUtility::SubdivideTriangle(triangle, subdividedTriangles, subdivisions); } std::vector<std::vector<ModelVertex>> trianglesOnSphere; trianglesOnSphere.reserve(subdividedTriangles.size()); for (const Triangle3D_t& triangle : subdividedTriangles) { trianglesOnSphere.emplace_back( std::vector<ModelVertex>{ {NormVector(triangle[0]) * radius}, {NormVector(triangle[1]) * radius}, {NormVector(triangle[2]) * radius} } ); } return Model_t(trianglesOnSphere); }
int GzPutAttribute(GzRender *render, int numAttributes, GzToken *nameList, GzPointer *valueList) /* void** valuelist */ { /* - set renderer attribute states (e.g.: GZ_RGB_COLOR default color) - later set shaders, interpolaters, texture maps, and lights */ if (!render || !nameList || !valueList) return GZ_FAILURE; for (int i = 0; i < numAttributes; i++) { switch (nameList[i]) { case GZ_RGB_COLOR: GzColor* color; color = (GzColor *)valueList[i]; render->flatcolor[RED] = color[i][RED]; render->flatcolor[GREEN] = color[i][GREEN]; render->flatcolor[BLUE] = color[i][BLUE]; break; case GZ_INTERPOLATE: int * interpmodept; interpmodept = (int *)valueList[i]; render->interp_mode = *interpmodept; break; case GZ_DIRECTIONAL_LIGHT: GzLight* dirlight; dirlight = (GzLight *)valueList[i]; if (render->numlights < MAX_LIGHTS) { render->lights[render->numlights] = *dirlight; NormVector(render->lights[render->numlights].direction); render->numlights += 1; } break; case GZ_AMBIENT_LIGHT: GzLight* amblight; amblight = (GzLight *)valueList[i]; render->ambientlight = *amblight; break; case GZ_AMBIENT_COEFFICIENT: float* ka; ka = (float*)valueList[i]; render->Ka[RED] = ka[RED]; render->Ka[GREEN] = ka[GREEN]; render->Ka[BLUE] = ka[BLUE]; break; case GZ_DIFFUSE_COEFFICIENT: float* kd; kd = (float*)valueList[i]; render->Kd[RED] = kd[RED]; render->Kd[GREEN] = kd[GREEN]; render->Kd[BLUE] = kd[BLUE]; break; case GZ_SPECULAR_COEFFICIENT: float* ks; ks = (float*)valueList[i]; render->Ks[RED] = ks[RED]; render->Ks[GREEN] = ks[GREEN]; render->Ks[BLUE] = ks[BLUE]; break; case GZ_DISTRIBUTION_COEFFICIENT: float* specpower; specpower = (float*)valueList[i]; render->spec = *specpower; break; case GZ_TEXTURE_MAP: GzTexture texturefun; texturefun= (GzTexture)valueList[i]; render->tex_fun = texturefun; break; case GZ_AASHIFTX: float *dx; dx = (float*)valueList[i]; render->dx = *dx; break; case GZ_AASHIFTY: float *dy; dy = (float*)valueList[i]; render->dy = *dy; break; } } return GZ_SUCCESS; }
int GzPutTriangle(GzRender *render, int numParts, GzToken *nameList, GzPointer *valueList) /* numParts : how many names and values */ { /* - pass in a triangle description with tokens and values corresponding to GZ_POSITION:3 vert positions in model space - Xform positions of verts using matrix on top of stack - Clip - just discard any triangle with any vert(s) behind view plane - optional: test for triangles with all three verts off-screen (trivial frustum cull) - invoke triangle rasterizer */ //check error if (render == NULL) { return GZ_FAILURE; } if (nameList == NULL) { return GZ_FAILURE; } if (valueList == NULL) { return GZ_FAILURE; } GzCoord* cord; GzCoord* Norms; GzTextureIndex* Textcord;//uv for (int i = 0; i < numParts; i++) { switch (nameList[i]) { case GZ_NULL_TOKEN: break; case GZ_POSITION: cord = (GzCoord*)valueList[i]; break; case GZ_NORMAL: Norms = (GzCoord *)valueList[i]; break; case GZ_TEXTURE_INDEX: Textcord = (GzTextureIndex *)valueList[i];//uv break; } } bool behind = false;//behind Visual point GzCoord* xformcord = new GzCoord[3]; GzCoord* xformNorms = new GzCoord[3]; //get triangle cord // Xform positions of verts using matrix on top of stack GzMatrix tosmatrx; memcpy(tosmatrx, render->Ximage[render->matlevel], sizeof(GzMatrix)); GzMatrix tosNmatrx; memcpy(tosNmatrx, render->Xnorm[render->matlevel], sizeof(GzMatrix)); float W; for (int j = 0; j < 3; j++) { // xform verticies xformcord[j][X] = tosmatrx[0][0] * cord[j][X] + tosmatrx[0][1] * cord[j][Y] + tosmatrx[0][2] * cord[j][Z] + tosmatrx[0][3] * (float)1.0; xformcord[j][Y] = tosmatrx[1][0] * cord[j][X] + tosmatrx[1][1] * cord[j][Y] + tosmatrx[1][2] * cord[j][Z] + tosmatrx[1][3] * (float)1.0; xformcord[j][Z] = tosmatrx[2][0] * cord[j][X] + tosmatrx[2][1] * cord[j][Y] + tosmatrx[2][2] * cord[j][Z] + tosmatrx[2][3] * (float)1.0; W = tosmatrx[3][0] * cord[j][X] + tosmatrx[3][1] * cord[j][Y] + tosmatrx[3][2] * cord[j][Z] + tosmatrx[3][3] * (float)1.0; //Clip - just discard any triangle with any vert(s) behind view plane if (xformcord[j][Z] < render->camera.position[Z]) { behind = true; break; } xformcord[j][X] /= W; xformcord[j][Y] /= W; xformcord[j][Z] /= W; } // NormVector(Norms[0]); NormVector(Norms[1]); NormVector(Norms[2]); for (int j = 0; j < 3; j++) { xformNorms[j][X] = tosNmatrx[0][0] * Norms[j][X] + tosNmatrx[0][1] * Norms[j][Y] + tosNmatrx[0][2] * Norms[j][Z]; xformNorms[j][Y] = tosNmatrx[1][0] * Norms[j][X] + tosNmatrx[1][1] * Norms[j][Y] + tosNmatrx[1][2] * Norms[j][Z]; xformNorms[j][Z] = tosNmatrx[2][0] * Norms[j][X] + tosNmatrx[2][1] * Norms[j][Y] + tosNmatrx[2][2] * Norms[j][Z]; } NormVector(xformNorms[0]); NormVector(xformNorms[1]); NormVector(xformNorms[2]); for (int i = 0; i < 3; i++) { xformcord[i][X] = xformcord[i][X] + render->dx; xformcord[i][Y] = xformcord[i][Y] + render->dy; } if (behind == true) { return GZ_SUCCESS; } if (rastlee(render, xformcord, xformNorms, Textcord)) { return GZ_SUCCESS; } return GZ_SUCCESS; }
bool rastlee(GzRender* render, GzCoord* cord, GzCoord * norms, GzTextureIndex * Textcord) { //swap and sort Y of vertex //sort Y by ascending order for (int j = 0; j < 2; j++) { for (int k = 0; k < 2 - j; k++) { if (cord[k][Y]>cord[k + 1][Y]) { float tempx = cord[k][X]; float tempy = cord[k][Y]; float tempz = cord[k][Z]; cord[k][X] = cord[k + 1][X]; cord[k][Y] = cord[k + 1][Y]; cord[k][Z] = cord[k + 1][Z]; cord[k + 1][X] = tempx; cord[k + 1][Y] = tempy; cord[k + 1][Z] = tempz; float tempNx = norms[k][X]; float tempNy = norms[k][Y]; float tempNz = norms[k][Z]; norms[k][X] = norms[k + 1][X]; norms[k][Y] = norms[k + 1][Y]; norms[k][Z] = norms[k + 1][Z]; norms[k + 1][X] = tempNx; norms[k + 1][Y] = tempNy; norms[k + 1][Z] = tempNz; float tempU = Textcord[k][U]; float tempV = Textcord[k][V]; Textcord[k][U] = Textcord[k + 1][U]; Textcord[k][V] = Textcord[k + 1][V]; Textcord[k + 1][U] = tempU; Textcord[k + 1][V] = tempV; } } } // determine L/R CW //horizontal case have two top Y if (cord[0][Y] == cord[1][Y]) { if (cord[0][X] > cord[1][X]) { float tempx = cord[0][X]; float tempy = cord[0][Y]; float tempz = cord[0][Z]; cord[0][X] = cord[1][X]; cord[0][Y] = cord[1][Y]; cord[0][Z] = cord[1][Z]; cord[1][X] = tempx; cord[1][Y] = tempy; cord[1][Z] = tempz; float tempNx = norms[0][X]; float tempNy = norms[0][Y]; float tempNz = norms[0][Z]; norms[0][X] = norms[1][X]; norms[0][Y] = norms[1][Y]; norms[0][Z] = norms[1][Z]; norms[1][X] = tempNx; norms[1][Y] = tempNy; norms[1][Z] = tempNz; float tempU = Textcord[0][U]; float tempV = Textcord[0][V]; Textcord[0][U] = Textcord[1][U]; Textcord[0][V] = Textcord[1][V]; Textcord[1][U] = tempU; Textcord[1][V] = tempV; } } //horizontal case have two bot Y else if (cord[1][Y] == cord[2][Y]) { if (cord[2][X] > cord[1][X]) { float tempx = cord[2][X]; float tempy = cord[2][Y]; float tempz = cord[2][Z]; cord[2][X] = cord[1][X]; cord[2][Y] = cord[1][Y]; cord[2][Z] = cord[1][Z]; cord[1][X] = tempx; cord[1][Y] = tempy; cord[1][Z] = tempz; float tempNx = norms[2][X]; float tempNy = norms[2][Y]; float tempNz = norms[2][Z]; norms[2][X] = norms[1][X]; norms[2][Y] = norms[1][Y]; norms[2][Z] = norms[1][Z]; norms[1][X] = tempNx; norms[1][Y] = tempNy; norms[1][Z] = tempNz; float tempU = Textcord[2][U]; float tempV = Textcord[2][V]; Textcord[2][U] = Textcord[1][U]; Textcord[2][V] = Textcord[1][V]; Textcord[1][U] = tempU; Textcord[1][V] = tempV; } } //bound box int top = (int)floor(cord[0][Y]); int bot = (int)ceil(cord[2][Y]); int left = cord[0][X]; int right = cord[2][X]; for (int i = 0; i < 3; i++) { if (cord[i][X] < left) left = (int)floor(cord[i][X]); if (cord[i][X]>right) right = (int)ceil(cord[i][X]); } //interpolate z float interpz; GzCoord vec01, vec12; vec01[X] = cord[1][X] - cord[0][X]; vec01[Y] = cord[1][Y] - cord[0][Y]; vec01[Z] = cord[1][Z] - cord[0][Z]; vec12[X] = cord[2][X] - cord[1][X]; vec12[Y] = cord[2][Y] - cord[1][Y]; vec12[Z] = cord[2][Z] - cord[1][Z]; float A = vec01[Y] * vec12[Z] - vec01[Z] * vec12[Y]; float B = vec01[Z] * vec12[X] - vec01[X] * vec12[Z]; float C = vec01[X] * vec12[Y] - vec01[Y] * vec12[X]; float D = -(A*cord[0][X] + B*cord[0][Y] + C*cord[0][Z]); //Gouraud shading GzColor goudinter; GzColor color0, color1, color2; /* ShadingEquation(render, color0, norms[0]); ShadingEquation(render, color1, norms[1]); ShadingEquation(render, color2, norms[2]);*/ if (render->interp_mode == GZ_COLOR) { if (render->tex_fun == NULL) { ShadingEquation(render, color0, norms[0]); ShadingEquation(render, color1, norms[1]); ShadingEquation(render, color2, norms[2]); } else {//use texture function render->Ka[RED] =1; render->Ka[GREEN] =1; render->Ka[BLUE] = 1; render->Kd[RED] = 1; render->Kd[GREEN] =1; render->Kd[BLUE] = 1; render->Ks[RED] = 1; render->Ks[GREEN] =1; render->Ks[BLUE] = 1; ShadingEquation(render, color0, norms[0]); ShadingEquation(render, color1, norms[1]); ShadingEquation(render, color2, norms[2]); } } GzColor gA, gB, gC, gD; gA[RED] = vec01[Y] * (color2[RED] - color1[RED]) - (color1[RED] - color0[RED]) * vec12[Y]; gB[RED] = (color1[RED] - color0[RED]) * vec12[X] - vec01[X] * (color2[RED] - color1[RED]); gC[RED] = vec01[X] * vec12[Y] - vec01[Y] * vec12[X]; gD[RED] = -(gA[RED]*cord[0][X] + gB[RED]*cord[0][Y] + gC[RED]*color0[RED]); gA[GREEN] = vec01[Y] * (color2[GREEN] - color1[GREEN]) - (color1[GREEN] - color0[GREEN]) * vec12[Y]; gB[GREEN] = (color1[GREEN] - color0[GREEN]) * vec12[X] - vec01[X] * (color2[GREEN] - color1[GREEN]); gC[GREEN] = vec01[X] * vec12[Y] - vec01[Y] * vec12[X]; gD[GREEN] = -(gA[GREEN] * cord[0][X] + gB[GREEN] * cord[0][Y] + gC[GREEN] * color0[GREEN]); gA[BLUE] = vec01[Y] * (color2[BLUE] - color1[BLUE]) - (color1[BLUE] - color0[BLUE]) * vec12[Y]; gB[BLUE] = (color1[BLUE] - color0[BLUE]) * vec12[X] - vec01[X] * (color2[BLUE] - color1[BLUE]); gC[BLUE] = vec01[X] * vec12[Y] - vec01[Y] * vec12[X]; gD[BLUE] = -(gA[BLUE] * cord[0][X] + gB[BLUE] * cord[0][Y] + gC[BLUE] * color0[BLUE]); //prepare for interp UV texture float Vzp;// Vz' GzTextureIndex* perspTextcord = new GzTextureIndex[3];//warp uv-> UV from image space to perspective space for each vertex for (int k = 0; k < 3; k++) { Vzp = cord[k][Z] / (INT_MAX - cord[k][Z]); perspTextcord[k][U] = Textcord[k][U] / (Vzp + 1); perspTextcord[k][V] = Textcord[k][V] / (Vzp + 1); } //if in bbox draw pixel for (int i = left; i < right; i++) { if (i<0 || i>render->display->xres) { continue; } for (int j = top; j < bot; j++) { if (j<0 || j>render->display->yres) { continue; } float a01 = cord[1][Y] - cord[0][Y]; float a12 = cord[2][Y] - cord[1][Y]; float a20 = cord[0][Y] - cord[2][Y]; float b01 = -(cord[1][X] - cord[0][X]); float b12 = -(cord[2][X] - cord[1][X]); float b20 = -(cord[0][X] - cord[2][X]); float c01 = -b01*cord[0][Y] - a01*cord[0][X]; float c12 = -b12*cord[1][Y] - a12*cord[1][X]; float c20 = -b20*cord[2][Y] - a20*cord[2][X]; float e01 = a01*(float)i + b01*(float)j + c01; float e12 = a12*(float)i + b12*(float)j + c12; float e20 = a20*(float)i + b20*(float)j + c20; if ((e01 == 0 || e12 == 0 || e20 == 0)||((e01 > 0) && (e12 > 0) && (e20 > 0)) || ((e01 < 0) && (e12 < 0) && (e20 < 0))) { interpz = (-(A*i) - (B*j) - D) / C; GzIntensity r, g, b, a; GzDepth z; GzGetDisplay(render->display, i, j, &r, &g, &b, &a, &z); if (interpz < z) { GzCoord pers01, pers12; pers01[U] = perspTextcord[1][U] - perspTextcord[0][U]; pers01[V] = perspTextcord[1][V] - perspTextcord[0][V]; pers12[U] = perspTextcord[2][U] - perspTextcord[1][U]; pers12[V] = perspTextcord[2][V] - perspTextcord[1][V]; // GzCoord intepcrossprod; //crossvector(pers01, pers12, intepcrossprod); GzTextureIndex tA, tB, tC, tD, textureinter, newuv; tA[U] = vec01[Y] * (pers12[U]) - (pers01[U]) * vec12[Y]; tB[U] = (pers01[U]) * vec12[X] - vec01[X] * (pers12[U]); tC[U] = vec01[X] * vec12[Y] - vec01[Y] * vec12[X]; tD[U] = -(tA[U] * cord[0][X] + tB[U] * cord[0][Y] + tC[U] * perspTextcord[0][U]); tA[V] = vec01[Y] * (pers12[V]) - (pers01[V]) * vec12[Y]; tB[V] = (pers01[V]) * vec12[X] - vec01[X] * (pers12[V]); tC[V] = vec01[X] * vec12[Y] - vec01[Y] * vec12[X]; tD[V] = -(tA[V] * cord[0][X] + tB[V] * cord[0][Y] + tC[V] * perspTextcord[0][V]); // interpolateUV to pixel /*textureinter[U] = -(tA[U] * i + tB[U] * j + tD[U]) / tC[U]; textureinter[V] = -(tA[V] * i + tB[V] * j + tD[V]) / tC[V];*/ textureinter[U] = interpolate(tA[U], tB[U], tC[U], tD[U], i, j); textureinter[V] = interpolate(tA[V], tB[V], tC[V], tD[V], i, j); //unwarping float Vzp = interpz / (INT_MAX - interpz); newuv[U] = textureinter[U] * (Vzp + 1); newuv[V] = textureinter[V] * (Vzp + 1); //texture color lookup with bilinear interpolation GzColor texColor; if (render->tex_fun != NULL) { render->tex_fun(newuv[U], newuv[V], texColor); } switch (render->interp_mode) { case GZ_FLAT: r = (GzIntensity)ctoi((float)render->flatcolor[0]); g = (GzIntensity)ctoi((float)render->flatcolor[1]); b = (GzIntensity)ctoi((float)render->flatcolor[2]); z = interpz; break; case GZ_COLOR://ground shading render->Ka[RED] = texColor[RED]; render->Ka[GREEN] = texColor[GREEN]; render->Ka[BLUE] = texColor[BLUE]; render->Kd[RED] = texColor[RED]; render->Kd[GREEN] = texColor[GREEN]; render->Kd[BLUE] = texColor[BLUE]; render->Ks[RED] = texColor[RED]; render->Ks[GREEN] = texColor[GREEN]; render->Ks[BLUE] = texColor[BLUE]; goudinter[RED] = -(gA[RED] * i + gB[RED] * j + gD[RED]) / gC[RED]; goudinter[GREEN] = -(gA[GREEN] * i + gB[GREEN] * j + gD[GREEN]) / gC[GREEN]; goudinter[BLUE] = -(gA[BLUE] * i + gB[BLUE] * j + gD[BLUE]) / gC[BLUE]; //texture color if (render->tex_fun != NULL) { goudinter[RED] *= texColor[RED] ; goudinter[GREEN] *= texColor[GREEN]; goudinter[BLUE] *= texColor[BLUE]; } if (goudinter[RED] > 1.0) goudinter[RED] = 1.0; if (goudinter[GREEN] > 1.0) goudinter[GREEN] = 1.0; if (goudinter[BLUE] > 1.0) goudinter[BLUE] = 1.0; r = (GzIntensity)ctoi(goudinter[RED]); g = (GzIntensity)ctoi(goudinter[GREEN]); b = (GzIntensity)ctoi(goudinter[BLUE]); z = interpz; break; case GZ_NORMALS: //interpolizing norms; GzColor pA, pB, pC, pD; pA[RED] = vec01[Y] * (norms[2][RED] - norms[1][RED]) - (norms[1][RED] - norms[0][RED]) * vec12[Y]; pB[RED] = (norms[1][RED] - norms[0][RED]) * vec12[X] - vec01[X] * (norms[2][RED] - norms[1][RED]); pC[RED] = vec01[X] * vec12[Y] - vec01[Y] * vec12[X]; pD[RED] = -(pA[RED] * cord [0][X] + pB[RED] * cord[0][Y] + pC[RED] * norms[0][RED]); pA[GREEN] = vec01[Y] * (norms[2][GREEN] - norms[1][GREEN]) - (norms[1][GREEN] - norms[0][GREEN]) * vec12[Y]; pB[GREEN] = (norms[1][GREEN] - norms[0][GREEN]) * vec12[X] - vec01[X] * (norms[2][GREEN] - norms[1][GREEN]); pC[GREEN] = vec01[X] * vec12[Y] - vec01[Y] * vec12[X]; pD[GREEN] = -(pA[GREEN] * cord[0][X] + pB[GREEN] * cord[0][Y] + pC[GREEN] * norms[0][GREEN]); pA[BLUE] = vec01[Y] * (norms[2][BLUE] - norms[1][BLUE]) - (norms[1][BLUE] - norms[0][BLUE]) * vec12[Y]; pB[BLUE] = (norms[1][BLUE] - norms[0][BLUE]) * vec12[X] - vec01[X] * (norms[2][BLUE] - norms[1][BLUE]); pC[BLUE] = vec01[X] * vec12[Y] - vec01[Y] * vec12[X]; pD[BLUE] = -(pA[BLUE] * cord[0][X] + pB[BLUE] * cord[0][Y] + pC[BLUE] * norms[0][BLUE]); GzColor phonginter; phonginter[0] = -(pA[0] * i + pB[0] * j + pD[0]) / pC[0]; phonginter[1] = -(pA[1] * i + pB[1] * j + pD[1]) / pC[1]; phonginter[2] = -(pA[2] * i + pB[2] * j + pD[2]) / pC[2]; NormVector(phonginter); //Then shading calculation with texture color used as Kd and Ka if (render->tex_fun != NULL) { render->Ka[RED] = render->Kd[RED] = texColor[RED]; render->Ka[GREEN] = render->Kd[GREEN] = texColor[GREEN]; render->Ka[BLUE] = render->Kd[BLUE] = texColor[BLUE]; } GzColor colorpix; ShadingEquation(render, colorpix, phonginter); r = (GzIntensity)ctoi(colorpix[RED]); g = (GzIntensity)ctoi(colorpix[GREEN]); b = (GzIntensity)ctoi(colorpix[BLUE]); z = interpz; break; } GzPutDisplay(render->display, i, j, r, g, b, a, z); } } } } return true; }
// -------------------------------------------------------------------- // add_track_mark // -------------------------------------------------------------------- void add_track_mark(const CControl *ctrl, int *id) { if (param.perf_level < 3) return; TTerrType *TerrList = &Course.TerrList[0]; *id = Course.GetTerrainIdx (ctrl->cpos.x, ctrl->cpos.z, 0.5); if (*id < 1) { break_track_marks(); return; } if (!TerrList[*id].trackmarks) { break_track_marks(); return; } TVector3 vel = ctrl->cvel; double speed = NormVector (vel); if (speed < SPEED_TO_START_TRENCH) { break_track_marks(); return; } TVector3 width_vector = CrossProduct (ctrl->cdirection, TVector3 (0, 1, 0)); double magnitude = NormVector (width_vector); if (magnitude == 0) { break_track_marks(); return; } TVector3 left_vector = ScaleVector (TRACK_WIDTH/2.0, width_vector); TVector3 right_vector = ScaleVector (-TRACK_WIDTH/2.0, width_vector); TVector3 left_wing = SubtractVectors (ctrl->cpos, left_vector); TVector3 right_wing = SubtractVectors (ctrl->cpos, right_vector); double left_y = Course.FindYCoord (left_wing.x, left_wing.z); double right_y = Course.FindYCoord (right_wing.x, right_wing.z); if (fabs(left_y-right_y) > MAX_TRACK_DEPTH) { break_track_marks(); return; } TPlane surf_plane = Course.GetLocalCoursePlane (ctrl->cpos); double dist_from_surface = DistanceToPlane (surf_plane, ctrl->cpos); // comp_depth = get_compression_depth(Snow); double comp_depth = 0.1; if (dist_from_surface >= (2 * comp_depth)) { break_track_marks(); return; } if(track_marks.quads.size() < MAX_TRACK_MARKS) track_marks.quads.push_back(track_quad_t()); list<track_quad_t>::iterator qprev = track_marks.current_mark; if(track_marks.current_mark == track_marks.quads.end()) track_marks.current_mark = track_marks.quads.begin(); else track_marks.current_mark = incrementRingIterator(track_marks.current_mark); list<track_quad_t>::iterator q = track_marks.current_mark; if (!continuing_track) { q->track_type = TRACK_HEAD; q->v1 = TVector3 (left_wing.x, left_y + TRACK_HEIGHT, left_wing.z); q->v2 = TVector3 (right_wing.x, right_y + TRACK_HEIGHT, right_wing.z); q->v3 = TVector3 (left_wing.x, left_y + TRACK_HEIGHT, left_wing.z); q->v4 = TVector3 (right_wing.x, right_y + TRACK_HEIGHT, right_wing.z); q->n1 = Course.FindCourseNormal (q->v1.x, q->v1.z); q->n2 = Course.FindCourseNormal (q->v2.x, q->v2.z); q->t1 = TVector2(0.0, 0.0); q->t2 = TVector2(1.0, 0.0); } else { q->track_type = TRACK_TAIL; if (qprev != track_marks.quads.end()) { q->v1 = qprev->v3; q->v2 = qprev->v4; q->n1 = qprev->n3; q->n2 = qprev->n4; q->t1 = qprev->t3; q->t2 = qprev->t4; if (qprev->track_type == TRACK_TAIL) qprev->track_type = TRACK_MARK; } q->v3 = TVector3 (left_wing.x, left_y + TRACK_HEIGHT, left_wing.z); q->v4 = TVector3 (right_wing.x, right_y + TRACK_HEIGHT, right_wing.z); q->n3 = Course.FindCourseNormal (q->v3.x, q->v3.z); q->n4 = Course.FindCourseNormal (q->v4.x, q->v4.z); double tex_end = speed*g_game.time_step/TRACK_WIDTH; if (q->track_type == TRACK_HEAD) { q->t3= TVector2 (0.0, 1.0); q->t4= TVector2 (1.0, 1.0); } else { q->t3 = TVector2 (0.0, q->t1.y + tex_end); q->t4 = TVector2 (1.0, q->t2.y + tex_end); } } q->alpha = min ((2*comp_depth-dist_from_surface)/(4*comp_depth), 1.0); continuing_track = true; }
void CCourse::CalcNormals () { for (int y=0; y<ny; y++) { for (int x=0; x<nx; x++) { TVector3 nml(0.0, 0.0, 0.0); TVector3 p0 (XCD(x), ELEV(x,y), ZCD(y)); if ((x + y) % 2 == 0) { if (x > 0 && y > 0) { TVector3 p1 = NMLPOINT(x, y-1); TVector3 p2 = NMLPOINT(x-1,y-1); TVector3 v1 = SubtractVectors (p1, p0); TVector3 v2 = SubtractVectors (p2, p0); TVector3 n = CrossProduct (v2, v1); NormVector (n); nml = AddVectors (nml, n); p1 = NMLPOINT (x-1, y-1); p2 = NMLPOINT (x-1, y); v1 = SubtractVectors (p1, p0); v2 = SubtractVectors (p2, p0); n = CrossProduct (v2, v1); NormVector (n); nml = AddVectors (nml, n); } if (x > 0 && y < ny-1) { TVector3 p1 = NMLPOINT(x-1,y); TVector3 p2 = NMLPOINT(x-1,y+1); TVector3 v1 = SubtractVectors (p1, p0); TVector3 v2 = SubtractVectors (p2, p0); TVector3 n = CrossProduct (v2, v1); NormVector (n); nml = AddVectors (nml, n); p1 = NMLPOINT(x-1,y+1); p2 = NMLPOINT(x ,y+1); v1 = SubtractVectors (p1, p0); v2 = SubtractVectors (p2, p0); n = CrossProduct (v2, v1); NormVector (n); nml = AddVectors (nml, n); } if (x < nx-1 && y > 0) { TVector3 p1 = NMLPOINT(x+1,y); TVector3 p2 = NMLPOINT(x+1,y-1); TVector3 v1 = SubtractVectors (p1, p0); TVector3 v2 = SubtractVectors (p2, p0); TVector3 n = CrossProduct (v2, v1); NormVector (n); nml = AddVectors (nml, n); p1 = NMLPOINT(x+1,y-1); p2 = NMLPOINT(x ,y-1); v1 = SubtractVectors (p1, p0); v2 = SubtractVectors (p2, p0); n = CrossProduct (v2, v1); NormVector (n); nml = AddVectors (nml, n); } if (x < nx-1 && y < ny-1) { TVector3 p1 = NMLPOINT(x+1,y); TVector3 p2 = NMLPOINT(x+1,y+1); TVector3 v1 = SubtractVectors (p1, p0); TVector3 v2 = SubtractVectors (p2, p0); TVector3 n = CrossProduct (v1, v2); NormVector (n); nml = AddVectors (nml, n); p1 = NMLPOINT(x+1,y+1); p2 = NMLPOINT(x ,y+1); v1 = SubtractVectors (p1, p0); v2 = SubtractVectors (p2, p0); n = CrossProduct (v1, v2); NormVector (n); nml = AddVectors (nml, n); } } else { if (x > 0 && y > 0) { TVector3 p1 = NMLPOINT(x, y-1); TVector3 p2 = NMLPOINT(x-1,y); TVector3 v1 = SubtractVectors (p1, p0); TVector3 v2 = SubtractVectors (p2, p0); TVector3 n = CrossProduct (v2, v1); NormVector (n); nml = AddVectors (nml, n); } if (x > 0 && y < ny-1) { TVector3 p1 = NMLPOINT(x-1,y); TVector3 p2 = NMLPOINT(x ,y+1); TVector3 v1 = SubtractVectors (p1, p0); TVector3 v2 = SubtractVectors (p2, p0); TVector3 n = CrossProduct (v2, v1); NormVector (n); nml = AddVectors (nml, n); } if (x < nx-1 && y > 0) { TVector3 p1 = NMLPOINT(x+1,y); TVector3 p2 = NMLPOINT(x ,y-1); TVector3 v1 = SubtractVectors (p1, p0); TVector3 v2 = SubtractVectors (p2, p0); TVector3 n = CrossProduct (v2, v1); NormVector (n); nml = AddVectors (nml, n); } if (x < nx-1 && y < ny-1) { TVector3 p1 = NMLPOINT(x+1,y); TVector3 p2 = NMLPOINT(x ,y+1); TVector3 v1 = SubtractVectors (p1, p0); TVector3 v2 = SubtractVectors (p2, p0); TVector3 n = CrossProduct (v1, v2); NormVector (n); nml = AddVectors (nml, n); } } NormVector (nml); nmls [x + nx * y] = nml; continue; } } }
std::unique_ptr<Mesh> MeshUtility::MakeSphere(float radius, unsigned int subdivisions) { if (subdivisions > ModelUtility::MAX_SPHERE_SUBDIVISIONS) { subdivisions = ModelUtility::MAX_SPHERE_SUBDIVISIONS; } std::unique_ptr<Mesh> octahedron = MeshUtility::MakeOctahedron(radius); std::vector<Triangle3D_t> initialTriangles; Transformation identity; for (std::size_t iFace = 0, numFaces = octahedron->NumFaces(); iFace < numFaces; ++iFace) { initialTriangles.push_back(octahedron->GetFaceTriangle(iFace, identity)); } std::vector<Triangle3D_t> subdividedTriangles; for (const Triangle3D_t& triangle : initialTriangles) { ModelUtility::SubdivideTriangle(triangle, subdividedTriangles, subdivisions); } std::vector<std::vector<MeshVertex>> trianglesOnSphere; trianglesOnSphere.reserve(subdividedTriangles.size()); std::vector<MeshVertex> triangleOnSphere(3, MeshVertex(Color::White(), Locus::TextureCoordinate())); Plane fixSmearPlane(Vec3D::ZeroVector(), Vec3D::NegativeZAxis()); for (const Triangle3D_t& triangle : subdividedTriangles) { for (std::size_t i = 0; i < Triangle3D_t::NumPointsOnATriangle; ++i) { triangleOnSphere[i].position = NormVector(triangle[i]) * radius; triangleOnSphere[i].textureCoordinate = MeshUtility::SphericalUVMapping(triangleOnSphere[i].position); } // //HACK: fixing smearing that occurs at the boundary where U = 0.0 or 1.0. The //spherical UV mapping algorithm always returns U = 1.0 at the boundary. Here //we find if the triangle that was just generated is at this boundary. The "real" //way to do it would be to unwrap the sphere or make a UV sphere. // Plane::IntersectionQuery intersectionQuery = fixSmearPlane.triangleIntersectionTest(triangle); if ((intersectionQuery == Plane::IntersectionQuery::None) || (intersectionQuery == Plane::IntersectionQuery::Positive)) { for (std::size_t i = 0; i < Triangle3D_t::NumPointsOnATriangle; ++i) { if (FEqual<float>(triangleOnSphere[i].textureCoordinate.x, 1.0f)) { triangleOnSphere[i].textureCoordinate.x = 0.0f; } } } trianglesOnSphere.push_back(triangleOnSphere); } return std::make_unique<Mesh>(trianglesOnSphere); }
int ShadingEquation(GzRender *render, GzColor color, GzCoord norm) { NormVector(norm);//normalize vector GzCoord E = { 0.0, 0.0, -1.0 }; GzCoord* R = new GzCoord[render->numlights]; NormVector(E); //N*L float NdotE; int* testN = new int[render->numlights]; float* NdotL = new float[render->numlights]; float* negNdotL = new float[render->numlights]; float* RdotE = new float[render->numlights]; GzCoord negN = { -norm[X], -norm[Y], -norm[Z] }; NdotE = dotvector(norm, E); //compute R for (int i = 0; i < render->numlights; i++) { NdotL[i] = dotvector(norm, render->lights[i].direction); negNdotL[i] = dotvector(negN, render->lights[i].direction); if (NdotL[i] >= 0 && NdotE >= 0) { //compute lighting model //R = 2(NdotL)N-L R[i][X] = 2 * NdotL[i]*norm[X] - render->lights[i].direction[X]; R[i][Y] = 2 * NdotL[i]*norm[Y] - render->lights[i].direction[Y]; R[i][Z] = 2 * NdotL[i]*norm[Z] - render->lights[i].direction[Z]; NormVector(R[i]); testN[i] = 0; } else if (NdotL[i] < 0 && NdotE < 0) { //flip N and compute backside R[i][X] = 2 * negNdotL[i] * (-norm[X]) - render->lights[i].direction[X]; R[i][Y] = 2 * negNdotL[i] * (-norm[Y]) - render->lights[i].direction[Y]; R[i][Z] = 2 * negNdotL[i] * (-norm[Z]) - render->lights[i].direction[Z]; NormVector(R[i]); testN[i] = 1; } else { //skip testN[i] = 2; } } //compute Spectical light part GzColor specSum = { 0, 0, 0 }; for (int i = 0; i < render->numlights; i++) { RdotE[i] = dotvector(R[i], E); if (testN[i] != 2) { assert(abs(dotvector(R[i], R[i]) - 1) < 0.00001); if (RdotE[i] < 0) RdotE[i] = 0; if (RdotE[i] > 1) RdotE[i] = 1; specSum[RED] += render->lights[i].color[RED] * pow(RdotE[i], render->spec); specSum[GREEN] += render->lights[i].color[GREEN] * pow(RdotE[i], render->spec); specSum[BLUE] += render->lights[i].color[BLUE] * pow(RdotE[i], render->spec); } } GzColor specpart; specpart[RED] = render->Ks[RED] * specSum[RED]; specpart[GREEN] = render->Ks[GREEN] * specSum[GREEN]; specpart[BLUE] = render->Ks[BLUE] * specSum[BLUE]; //compute diffusion part GzColor diffSum = { 0, 0, 0 }; for (int i = 0; i < render->numlights; i++) { if (testN[i] == 2)continue; if (testN[i] == 0) { //both positive diffSum[RED] += render->lights[i].color[RED] * NdotL[i]; diffSum[GREEN] += render->lights[i].color[GREEN] * NdotL[i]; diffSum[BLUE] += render->lights[i].color[BLUE] * NdotL[i]; } if (testN[i] == 1) { //both negative diffSum[RED] += render->lights[i].color[RED] * negNdotL[i]; diffSum[GREEN] += render->lights[i].color[GREEN] * negNdotL[i]; diffSum[BLUE] += render->lights[i].color[BLUE] * negNdotL[i]; } } GzColor diffpart; diffpart[RED] = render->Kd[RED] * diffSum[RED]; diffpart[GREEN] = render->Kd[GREEN] * diffSum[GREEN]; diffpart[BLUE] = render->Kd[BLUE] * diffSum[BLUE]; //compute ambient part GzColor ambpart; ambpart[RED] = render->Ka[RED] * render->ambientlight.color[RED]; ambpart[GREEN] = render->Ka[GREEN] * render->ambientlight.color[GREEN]; ambpart[BLUE] = render->Ka[BLUE] * render->ambientlight.color[BLUE]; //calculate c color[RED] = specpart[RED] + diffpart[RED] + ambpart[RED]; color[GREEN] = specpart[GREEN] + diffpart[GREEN] + ambpart[GREEN]; color[BLUE] = specpart[BLUE] + diffpart[BLUE] + ambpart[BLUE]; delete[] testN; delete[] NdotL; delete[] negNdotL; delete[] RdotE; delete[] R; return GZ_SUCCESS; }
// -------------------------------------------------------------------- // add_track_mark // -------------------------------------------------------------------- void add_track_mark (CControl *ctrl, int *id) { TVector3 width_vector; TVector3 left_vector; TVector3 right_vector; double magnitude; track_quad_t *q, *qprev, *qprevprev; TVector3 vel; double speed; TVector3 left_wing, right_wing; double left_y, right_y; double dist_from_surface; TPlane surf_plane; double comp_depth; double tex_end; double dist_from_last_mark; TVector3 vector_from_last_mark; TTerrType *TerrList = Course.TerrList; if (param.perf_level < 3) return; q = &track_marks.quads[track_marks.current_mark%MAX_TRACK_MARKS]; qprev = &track_marks.quads[(track_marks.current_mark-1)%MAX_TRACK_MARKS]; qprevprev = &track_marks.quads[(track_marks.current_mark-2)%MAX_TRACK_MARKS]; vector_from_last_mark = SubtractVectors (ctrl->cpos, track_marks.last_mark_pos); dist_from_last_mark = NormVector (&vector_from_last_mark); *id = Course.GetTerrainIdx (ctrl->cpos.x, ctrl->cpos.z, 0.5); if (*id < 1) { break_track_marks(); return; } if (TerrList[*id].trackmarks < 1) { break_track_marks(); return; } vel = ctrl->cvel; speed = NormVector (&vel); if (speed < SPEED_TO_START_TRENCH) { break_track_marks(); return; } width_vector = CrossProduct (ctrl->cdirection, MakeVector (0, 1, 0)); magnitude = NormVector (&width_vector); if (magnitude == 0) { break_track_marks(); return; } left_vector = ScaleVector (TRACK_WIDTH/2.0, width_vector); right_vector = ScaleVector (-TRACK_WIDTH/2.0, width_vector); left_wing = SubtractVectors (ctrl->cpos, left_vector); right_wing = SubtractVectors (ctrl->cpos, right_vector); left_y = Course.FindYCoord (left_wing.x, left_wing.z); right_y = Course.FindYCoord (right_wing.x, right_wing.z); if (fabs(left_y-right_y) > MAX_TRACK_DEPTH) { break_track_marks(); return; } surf_plane = Course.GetLocalCoursePlane (ctrl->cpos); dist_from_surface = DistanceToPlane (surf_plane, ctrl->cpos); // comp_depth = get_compression_depth(Snow); comp_depth = 0.1; if (dist_from_surface >= (2 * comp_depth)) { break_track_marks(); return; } if (!continuing_track) { break_track_marks(); q->track_type = TRACK_HEAD; q->v1 = MakeVector (left_wing.x, left_y + TRACK_HEIGHT, left_wing.z); q->v2 = MakeVector (right_wing.x, right_y + TRACK_HEIGHT, right_wing.z); q->n1 = Course.FindCourseNormal (q->v1.x, q->v1.z); q->n2 = Course.FindCourseNormal (q->v2.x, q->v2.z); q->t1 = MakeVector2(0.0, 0.0); q->t2 = MakeVector2(1.0, 0.0); track_marks.next_mark = track_marks.current_mark + 1; } else { if (track_marks.next_mark == track_marks.current_mark) { q->v1 = qprev->v3; q->v2 = qprev->v4; q->n1 = qprev->n3; q->n2 = qprev->n4; q->t1 = qprev->t3; q->t2 = qprev->t4; if (qprev->track_type != TRACK_HEAD) qprev->track_type = TRACK_MARK; q->track_type = TRACK_MARK; } q->v3 = MakeVector (left_wing.x, left_y + TRACK_HEIGHT, left_wing.z); q->v4 = MakeVector (right_wing.x, right_y + TRACK_HEIGHT, right_wing.z); q->n3 = Course.FindCourseNormal (q->v3.x, q->v3.z); q->n4 = Course.FindCourseNormal (q->v4.x, q->v4.z); tex_end = speed*g_game.time_step/TRACK_WIDTH; if (q->track_type == TRACK_HEAD) { q->t3= MakeVector2 (0.0, 1.0); q->t4= MakeVector2 (1.0, 1.0); } else { q->t3 = MakeVector2 (0.0, q->t1.y + tex_end); q->t4 = MakeVector2 (1.0, q->t2.y + tex_end); } track_marks.current_mark++; track_marks.next_mark = track_marks.current_mark; } q->alpha = min ((2*comp_depth-dist_from_surface)/(4*comp_depth), 1.0); track_marks.last_mark_time = g_game.time; continuing_track = true; }