/******************************************************************************\ Adjusts globe vertices to show the tile's height. Updates the globe with data from the [r_tiles] array. \******************************************************************************/ void R_configure_globe(void) { c_vec2_t tile; float left, right, top, bottom, tmp; int i, tx, ty, terrain; C_debug("Configuring globe"); C_var_unlatch(&r_globe_transitions); /* UV dimensions of tile boundary box */ tile.x = 2.f * (r_terrain_tex->surface->w / R_TILE_SHEET_W) / r_terrain_tex->surface->w; tile.y = 2.f * (int)(C_SIN_60 * r_terrain_tex->surface->h / R_TILE_SHEET_H / 2) / r_terrain_tex->surface->h; for (i = 0; i < r_tiles_max; i++) { set_tile_height(i, r_tiles[i].height); /* Tile terrain texture */ terrain = tile_terrain(i); ty = terrain / R_TILE_SHEET_W; tx = terrain - ty * R_TILE_SHEET_W; left = tx / 2 * tile.x + C_SIN_60 * R_TILE_BORDER; right = (tx / 2 + 1) * tile.x - C_SIN_60 * R_TILE_BORDER; if (tx & 1) { bottom = ty * tile.y + C_SIN_30 * R_TILE_BORDER; top = (ty + 1.f) * tile.y - C_SIN_60 * R_TILE_BORDER; left += tile.x / 2.f; right += tile.x / 2.f; } else { top = ty * tile.y + R_TILE_BORDER; bottom = (ty + 1.f) * tile.y - C_SIN_30 * R_TILE_BORDER; } /* Flip tiles are mirrored over the middle */ if (i < flip_limit) { tmp = left; left = right; right = tmp; } r_globe_verts[3 * i].v.uv = C_vec2((left + right) / 2.f, top); r_globe_verts[3 * i + 1].v.uv = C_vec2(left, bottom); r_globe_verts[3 * i + 2].v.uv = C_vec2(right, bottom); } for (i = 0; i < r_tiles_max; i++) compute_tile_vectors(i); smooth_normals(); /* We can update normals dynamically from now on */ r_globe_smooth.edit = C_VE_FUNCTION; r_globe_smooth.update = globe_smooth_update; /* If Vertex Buffer Objects are supported, upload the vertices now */ R_vbo_cleanup(&r_globe_vbo); R_vbo_init(&r_globe_vbo, &r_globe_verts[0].v, 3 * r_tiles_max, sizeof (*r_globe_verts), R_VERTEX3_FORMAT, NULL, 0); }
/******************************************************************************\ Called when [r_globe_smooth] changes. \******************************************************************************/ static int globe_smooth_update(c_var_t *var, c_var_value_t value) { int i; if (value.f > 0.f) { r_globe_smooth.value.f = value.f; smooth_normals(); } else for (i = 0; i < r_tiles_max * 3; i++) r_globe_verts[i].v.no = r_tiles[i / 3].normal; R_vbo_update(&r_globe_vbo); return TRUE; }
// particle simulation void simulate(Scene* scene) { //put_your_code_here("Implement simulation"); // for each mesh for(auto m : scene->meshes){ // skip if no simulation if(!m->simulation){continue;} // compute time per step float timeperstep = scene->animation->dt/scene->animation->simsteps; // foreach simulation steps for(int step = 0; step < scene->animation->simsteps; step++){ // foreach particle, compute external forces for(int particle: range(0, m->simulation->force.size())){ // initialize particle forces to zero3f m->simulation->force[particle] = zero3f; // compute force of gravity auto g = scene->animation->gravity; // compute force of wind //EXTRA CREDIT DON"T DO WIND // accumulate sum of forces on particle m->simulation->force[particle] += g; } //SPRING EXTRA CREDIT // for each spring, compute spring force on points // compute spring distance and length // compute static force // accumulate static force on points // compute dynamic force // accumulate dynamic force on points // foreach particle, integrate using newton laws for(int particle: range(0, m->simulation->force.size())){ // if pinned, skip if(m->simulation->pinned[particle]){continue;} // compute acceleration auto acceleration = m->simulation->force[particle]/m->simulation->mass[particle]; // update velocity and positions using Euler's method m->simulation->vel[particle] = m->simulation->vel[particle] + acceleration*timeperstep ; m->pos[particle] = m->pos[particle] + m->simulation->vel[particle]*timeperstep + acceleration*timeperstep*timeperstep*.5; // for each surface, check for collision bool inside; for(auto surface : scene->surfaces){ inside = false; // compute local position auto L_pos = transform_point_to_local(surface->frame, m->pos[particle]); auto R = surface->radius; // if quad vec3f col_pos; vec3f col_norm; if(surface->isquad){ // perform inside test if(L_pos.x < R && L_pos.x > -R && L_pos.z < 0 && L_pos.y < R && L_pos.y > -R){ inside = true; // vec3f col_pos = m->pos[particle]; col_norm = surface->frame.z; col_pos = transform_point_from_local(surface->frame, vec3f(L_pos.x, L_pos.y, 0)); } } // if sphere if(!surface->isquad){ // inside test if(dist(zero3f, L_pos) < R){ // // if inside, compute a collision position and normal inside = true; // vec3f col_pos = m->pos[particle]; vec3f C = surface->frame.o; //sphere center vec3f E = surface->frame.o; //camera origin float a = lengthSqr(C - m->pos[particle]); float b = dot(2*(C - m->pos[particle]), C-E); float c = lengthSqr(C - m->pos[particle])-sqr(R); float det = sqr(b) - 4*a*c; //if(det < 0){continue;} //calculate t1 and t2 float t1 = (-b + sqrt(det))/(2*a); float t2 = (-b - sqrt(det))/(2*a); // just grab only the first hit float t = fminf(t1, t2); //check if computed param is within ray.tmin and ray.tmax col_pos = m->pos[particle] + t*(C - m->pos[particle]); //find intersection point with quad col_norm = normalize(col_pos - C); } } // if inside if(inside == true){ m->pos[particle]=col_pos; // update velocity (particle bounces), taking into account loss of kinetic energy vec3f ref = reflect(m->simulation->vel[particle], col_norm); auto v1 = ref - dot(ref, col_norm)*col_norm; auto v2 = dot(ref, col_norm)*col_norm; m->simulation->vel[particle] = (1 - scene->animation->bounce_dump.x)*v1 +(1 - scene->animation->bounce_dump.y)*v2; } } } } // smooth normals if it has triangles or quads if(m->quad.size() != 0 || m->triangle.size() != 0){ smooth_normals(m); } } }