static void camOrbit(int dx, int dy) { const double radius = 200; double dist; Vec3 v = cam_position; Quaternion o = cam_orientation; Quaternion q, q2; /* We invert the transformation because we are transforming the camera * and not the scene. */ q = quat_conjugate(quat_trackball(dx, dy, radius)); /* The quaternion q gives us an intrinsic transformation, close to unity. * To make it extrinsic, we compute q2 = o * q * ~o */ q2 = quat_multiply(o, quat_multiply(q, quat_conjugate(o))); q2 = quat_normalize(q2); /* As round-off errors accumulate, the distance between the camera and the * target would normally fluctuate. We take steps to prevent that here. */ dist = vec3_length(v); v = quat_transform(q2, v); v = vec3_normalize(v); v = vec3_scale(v, dist); cam_position = v; cam_orientation = quat_multiply(q2, cam_orientation); }
static void camDolly(int dz) { Vec3 v = cam_position; v = vec3_scale(v, exp(-0.1*dz)); cam_position = v; }
int collision_test_sphere(t_ray_result *r, t_sphere *sphere) { t_real a; t_real b; t_real c; t_real det; a = collision_test_sphere_a(&r->ray.direction); b = collision_test_sphere_b(&r->ray, &sphere->position); c = collision_test_sphere_c(&r->ray, sphere); det = ft_pow(b, 2) - (4 * a * c); if (!det) r->distance = -(b / 2 * a); else if (det > 0) r->distance = FT_MIN((-b - sqrt(det)) / (2 * a), (-b + sqrt(det)) / (2 * a)); else return (0); r->hit = OT_SPHERE; r->contact.point = vec3_add(r->ray.origin, vec3_scale(r->ray.direction, r->distance)); return (1); }
void generate_debug_geometry(vector_buffer *vertices, vector_buffer *normals, geometry* out) { float temp[3]; vector_buffer debug; vector_init(&debug); for(int i = 0; i < out->vertex_count; ++i) { vec3_scale(vector_get(normals, i), 0.05f, temp); vec3_add(vector_get(vertices, i), temp, temp); vector_append(&debug, vector_get(vertices, i)); vector_append(&debug, temp); } out->debug_geometry.attributes.position = 3; make_buffer(out->debug_geometry.attributes.position, &out->debug_geometry.vertex_buffer, debug.data , (GLsizei) (out->vertex_count * 3 * 2 * sizeof(float))); out->debug_geometry.vertex_shader = make_shader(GL_VERTEX_SHADER, "shaders/debug_shader.v.glsl"); out->debug_geometry.fragment_shader = make_shader(GL_FRAGMENT_SHADER, "shaders/debug_shader.f.glsl"); out->debug_geometry.program = make_program(out->debug_geometry.vertex_shader, out->debug_geometry.fragment_shader); glBindAttribLocation(out->debug_geometry.program, out->debug_geometry.attributes.position, "position"); glLinkProgram(out->debug_geometry.program); out->debug_geometry.uniform.mvp_matrix = glGetUniformLocation(out->program, "mvp_matrix"); }
/** * Component of the support function for a cylinder collider. **/ static void object_support_component_cylinder(object_t *object, float direction[3], float out[3]) { float top[3] = { 0, object->h / 2, 0 }; float bottom[3] = { 0, -object->h / 2, 0 }; float axis[3]; float dir_perp[3]; float trans[16]; float dot_top; object_get_transform_mat(object, trans); /* Top and bottom are set to points in the middle of the top and the * bottom faces of the cylinder respectively. We transform them to * their worldspace positions. */ matrix_vec3_mul(trans, top, 1.0, top); matrix_vec3_mul(trans, bottom, 1.0, bottom); /* We get an axis vector that runs down the middle of the cylinder. */ vec3_subtract(top, bottom, axis); /* Part of another process, but useful now for a reason... */ vec3_cross(axis, direction, dir_perp); /* If the cross product is zero, our direction is aligned with the * cylinder and top and bottom are our two final candidates. */ if (vec3_magnitude(dir_perp) > 0) { /* This completes what we started with the last cross product. * dir_perp is now a vector perpendicular to the cylinder's * axis, but as close to our selected direction as possible. */ vec3_cross(dir_perp, axis, dir_perp); /* Scale dir_perp to be the radius of our cylinder. */ vec3_normalize(dir_perp, dir_perp); vec3_scale(dir_perp, dir_perp, object->r); /* Finally, move top and bottom to the edges of our cylinder in * the appropriate direction. We now have our two final * candidates. */ vec3_add(dir_perp, top, top); vec3_add(dir_perp, bottom, bottom); } /* We now have two candidates, top and bottom. We can just use largest * dot product to determine which is furthest. */ dot_top = vec3_dot(top, direction); if (dot_top > vec3_dot(bottom, direction)) memcpy(out, top, 3 * sizeof(float)); else memcpy(out, bottom, 3 * sizeof(float)); }
CollisionResult collision_ray_scene_invert(const Ray* ray, const Scene* scene) { CollisionResult r = collision_ray_scene(ray, (const Scene*)scene->data); if (r.type == None) { return r; } else if (r.type == Enter) { r.type = Exit; r.normal = vec3_scale(&r.normal, (FPType)-1); return r; } else if (r.type == Exit) { r.type = Enter; r.normal = vec3_scale(&r.normal, (FPType)-1); return r; } else { assert(!"unexpected line reached"); return r; } }
void quat_mult(quat_t *r, const quat_t *a, const quat_t *b) { quat_t ret; vec3_t t; ret.w = a->w * b->w - vec3_dot(&a->v, &b->v); vec3_cross(&ret.v, &a->v, &b->v); t = a->v; vec3_scale(&t, b->w); vec3_add(&ret.v, &ret.v, &t); t = b->v; vec3_scale(&t, a->w); vec3_add(&ret.v, &ret.v, &t); *r = ret; }
static int ray_mesh_intersect(Ray ray, const Mesh *mesh, float *t, Vec3 *normal) { struct TriangleHit tri_hit; if (ray_kd_tree_intersect(ray, mesh->vertex, mesh->kd_tree, &tri_hit)) { Triangle tri = tri_hit.triangle; *t = tri_hit.t; *normal = vec3_add(vec3_add( vec3_scale(tri_hit.a, mesh->normal[tri.normal_index[0]]), vec3_scale(tri_hit.b, mesh->normal[tri.normal_index[1]])), vec3_scale(tri_hit.c, mesh->normal[tri.normal_index[2]])); return 1; } return 0; }
void quat_normalize(quat_t *q) { float m = q->w * q->w + vec3_dot(&q->v, &q->v); m = 1.f / m; q->w *= m; vec3_scale(&q->v, m); }
void quat_axis_angle(quat_t *q, const vec3_t *v, float angle) { float s, c; sincosf(angle/2, &s, &c); q->w = c; q->v = *v; vec3_normalize(&q->v); vec3_scale(&q->v, s); }
void marching_cubes(float threshold, scan_data *data, int debug, geometry* out) { float temp[3]; vector_buffer vertices; vector_buffer normals; vector_init(&vertices); vector_init(&normals); for (size_t x = 0; x < data->length; x++) for (size_t y = 0; y < data->width; y++) for (size_t z = 0; z < data->height; z++) { march_cube(x, y, z, step_size, threshold, data, &vertices, &normals); } out->vertex_count = (GLuint) vertices.size; out->attributes.position = 0; out->attributes.normal = 1; make_buffer(out->attributes.position, &out->vertex_buffer, vertices.data , (GLsizei) (out->vertex_count * 3 * sizeof(float))); make_buffer(out->attributes.normal, &out->vertex_buffer, normals.data , (GLsizei) (out->vertex_count * 3 * sizeof(float))); out->vertex_shader = make_shader(GL_VERTEX_SHADER, "shaders/diffuse_shader.v.glsl"); out->fragment_shader = make_shader(GL_FRAGMENT_SHADER, "shaders/diffuse_shader.f.glsl"); out->program = make_program(out->vertex_shader, out->fragment_shader); glBindAttribLocation(out->program, out->attributes.position, "position"); glBindAttribLocation(out->program, out->attributes.normal, "normal"); glLinkProgram(out->program); out->uniform.mvp_matrix = glGetUniformLocation(out->program, "mvp_matrix"); out->uniform.normal_matrix = glGetUniformLocation(out->program, "normal_matrix"); out->center[0] = 0.0f; out->center[1] = 0.0f; out->center[2] = 0.0f; for(size_t i = 0; i < out->vertex_count; ++i) { vec3_scale(vertices.data[i], -1.0f / out->vertex_count, temp); vec3_add(out->center, temp, out->center); } if(debug) { generate_debug_geometry(&vertices, &normals, out); } vector_free(&vertices); vector_free(&normals); }
static inline void _move_camera(game *g, direction d) { vec3 temp; switch (d) { case (UP): vec3_scale(temp, g->d.view_u, g->d.trans); break; case(DOWN): vec3_scale(temp, g->d.view_u, -g->d.trans); break; case(LEFT): vec3_scale(temp, g->d.view_r, -g->d.trans); break; case(RIGHT): vec3_scale(temp, g->d.view_r, g->d.trans); break; } vec3_add(g->d.eye, g->d.eye, temp); vec3_add(g->d.eye_zoom, g->d.eye_zoom, temp); vec3_add(g->d.center, g->d.center, temp); }
/** * GJK collision support function. **/ static void object_support(object_t *a, object_t *b, float direction[3], float out[3]) { float pa[3]; float pb[3]; object_support_component(a, direction, pa); vec3_scale(direction, direction, -1); object_support_component(b, direction, pb); vec3_subtract(pa, pb, out); }
void vec3_normalize(vec3_t *v) { float len = vec3_magnitude(v); if (len < 1.e-5) return; len = 1.f / len; vec3_scale(v, len); }
int bullet_updatePosition(bullet* B, unsigned int frameTime) { B->distanceTraveled += frameTime * B->frameDistance; vec3 velocity; vec3_scale(velocity, B->direction, frameTime * B->specs->speed); B->position[0] += velocity[0]; B->position[1] += velocity[1]; B->position[2] += velocity[2]; mesh_translate_from_origin(B->model, B->position[0], B->position[1], B->position[2]); if (B->distanceTraveled < B->specs->maximumTravelDistance) return 1; else return 0; }
bool sphere::intersect(const ray& ray, const range& r, surface_hit* hit) { float t = sphere_intersect(center, radius, ray, r); if(t == NO_t) return false; if(t > hit->t) return false; if(keep_stats) sphere_shadings++; vec3 point = vec3_add(ray.o, vec3_scale(ray.d, t)); // snap to sphere surface vec3 to_surface = vec3_subtract(point, center); float distance = sqrtf(vec3_dot(to_surface, to_surface)); hit->point = vec3_add(center, vec3_scale(to_surface, radius / distance)); hit->normal = vec3_divide(to_surface, radius); hit->color = color; hit->t = t; return true; }
void matrix_project(const matrix_t *m, const vec3_t *in, vec3_t *out) { vec3_t t; float w; t.x = m->m[0] * in->x + m->m[4] * in->y + m->m[ 8] * in->z + m->m[12]; t.y = m->m[1] * in->x + m->m[5] * in->y + m->m[ 9] * in->z + m->m[13]; t.z = m->m[2] * in->x + m->m[6] * in->y + m->m[10] * in->z + m->m[14]; w = m->m[3] * in->x + m->m[7] * in->y + m->m[11] * in->z + m->m[15]; if (w != 0.f) vec3_scale(&t, 1.f/w); *out = t; }
static inline void _calc_zoom(game *g, int dir) { g->d.zoom_level += dir; g->d.zoom = pow(g->d.zoom_amount, g->d.zoom_level - (g->d.ortho ? 0 : 6)); _update_translations(g); float zoom = 1 / g->d.zoom; if (g->d.ortho) { mat4x4_ortho(g->d.proj, -g->aspect * zoom, g->aspect * zoom, -1 * zoom, 1 * zoom, 1, 1000); } else { vec3 temp; memcpy(&g->d.eye_zoom, &g->d.eye, sizeof(g->d.eye_zoom)); vec3_scale(temp, g->d.view_f, zoom); vec3_sub(g->d.eye_zoom, g->d.center, temp); } }
float fBm(const vec3 p) { float amplitude = 1.0f; float frequency = 1.0f; float fBm = 0.0f; vec3 p_freq; for(int i = 0; i < lattice_noise.num_octaves; i++) { vec3_scale(p_freq, p, frequency); fBm += amplitude * noiseFunc(p_freq); amplitude *= lattice_noise.gain; frequency *= lattice_noise.lacunarity; } return (fBm - lattice_noise.fs_min) / (lattice_noise.fs_max - lattice_noise.fs_min); }
float turbulenceNoise(const vec3 p) { float amplitude = 1.0f; float frequency = 1.0f; float turbulence = 0.0f; vec3 p_freq; for(int i = 0; i < lattice_noise.num_octaves; i++) { vec3_scale(p_freq, p, frequency); turbulence += amplitude * fabs(noiseFunc(p_freq)); amplitude *= 0.5f; frequency *= 2.0f; } return turbulence /= lattice_noise.fs_max; }
/** * Component of the support function for a sphere collider. **/ static void object_support_component_sphere(object_t *object, float direction[3], float out[3]) { float trans[16]; vec3_normalize(direction, direction); vec3_scale(direction, direction, object->r); object_get_transform_mat(object, trans); out[0] = trans[3]; out[1] = trans[7]; out[2] = trans[11]; vec3_add(direction, out, out); }
int collision_test_plane(t_ray_result *result, t_plane *plane) { t_vec3 opp; t_real dv; opp = vec3_sub(result->ray.origin, plane->point); dv = vec3_dot(plane->normal, result->ray.direction); if (!dv) return (0); result->distance = -vec3_dot(plane->normal, opp) / dv; if (result->distance < 0) return (0); result->hit = OT_PLANE; result->contact.point = vec3_add(result->ray.origin, vec3_scale(result->ray.direction, result->distance)); return (1); }
void Camera_update(Camera* const camera, Input* const input) { Camera_offset_orientation( camera, toRadians((-input->mouse_dx * input->mouse_sensitivity)), toRadians((-input->mouse_dy * input->mouse_sensitivity)) ); // TODO: Delta time vec3 dir = {0.0f, 0.0f, 0.0f}; float vel = 0.2f; vec3 forward, backward, left, right; Camera_relative_directions(camera, forward, backward, left, right); if (input->forward_key) { vec3 f = {forward[0], 0.0f, forward[2]}; vec3_norm(f, f); vec3_add(dir, dir, f); } if (input->back_key) { vec3 b = {backward[0], 0.0f, backward[2]}; vec3_norm(b, b); vec3_add(dir, dir, b); } if (input->left_key) { vec3_add(dir, dir, left); } if (input->right_key) { vec3_add(dir, dir, right); } if (vec3_len(dir) > 0.0f) { vec3_norm(dir, dir); } vec3 movement; vec3_scale(movement, dir, vel); vec3_add(camera->transform.position, camera->transform.position, movement); }
void test_vec3() { // Vec4 /* struct vec4 v1 = { 1, 2, 3, 4 }; struct vec4 v2 = { 2, 2, 2, 2 }; assert(vec4_dot(&v1, &v2) == 2); struct vec4 v3 = vec4_sub(&v1, &v2); assert(v3.x == -1); assert(v3.y == 0); assert(v3.z == 1); assert(v3.w == 2); struct vec4 v3 = v1 + v2; assert(v3.x == 3); assert(v3.y == 4); assert(v3.z == 5); assert(v3.w == 6); struct vec4 v3 = 2 * v1; assert(v3.x == 2); assert(v3.y == 4); assert(v3.z == 6); assert(v3.w == 8); */ // Vec3 struct vec3 v1 = {1, 2, 3}; struct vec3 v2 = {2, 2, 2}; assert(vec3_dot(&v1, &v2) == 12); struct vec3 v3 = vec3_sub(&v1, &v2); assert(v3.x == -1); assert(v3.y == 0); assert(v3.z == 1); struct vec3 v4 = vec3_add(&v1, &v2); assert(v4.x == 3); assert(v4.y == 4); assert(v4.z == 5); struct vec3 v5 = vec3_scale(&v1, 2); assert(v5.x == 2); assert(v5.y == 4); assert(v5.z == 6); struct vec3 vx = {1, 0, 0}; struct vec3 vy = {0, 1, 0}; struct vec3 vz = {0, 0, 1}; struct vec3 v6; v6 = vec3_cross(&vx, &vy); assert(v6.x == 0 && v6.y == 0 && v6.z == 1); v6 = vec3_cross(&vz, &vx); assert(v6.x == 0 && v6.y == 1 && v6.z == 0); v6 = vec3_cross(&vy, &vz); assert(v6.x == 1 && v6.y == 0 && v6.z == 0); /* // Vec2 local v1 = vec.Vec2(1, 2) local v2 = vec.Vec2(2, 2) assert(v1:dot(v2) == 6) local v3 = v1 - v2 assert(v3.x == -1) assert(v3.y == 0) local v3 = v1 + v2 assert(v3.x == 3) assert(v3.y == 4) local v3 = 2 * v1 assert(v3.x == 2) assert(v3.y == 4) assert(v3:data()[0] == 2) assert(v3:data()[1] == 4) assert(ffi.sizeof(v3) == ffi.sizeof('vec_Scalar')*2) assert(v3 == vec.Vec2(2, 4)) */ }
void render(msg_block_t *msg, rt_context_t *rtx, uint32_t *frame_buffer) { uint32_t *pixel; float sy = rtx->sheight * 0.5f - rtx->ayc; unsigned int y; for (y = 0; y < rtx->height; y++) { uint32_t *src = frame_buffer + (y * SCALE + rtx->yoff) * msg->fbinfo.line_length / sizeof(uint32_t) + rtx->xoff; pixel = src; float sx = rtx->swidth * -0.5f; unsigned int x; for (x = 0; x < rtx->width; x++) { rtx->ray.pos = rtx->eye; rtx->ray.dir = normalize(vec3_sub(vec3_set(sx, sy, 0.0f), rtx->eye)); vec3_t col = vec3_set(0.0f, 0.0f, 0.0f); unsigned int j; for (j = 0; j < MAXREF; j++) { trace_ray(rtx); if (rtx->hit != NOHIT) { vec3_t p, n; ray_t next; p = vec3_add(rtx->ray.pos, vec3_scale(rtx->ray.dir, rtx->dist)); switch (rtx->obj[rtx->hit].type) { case SPHERE: n = normalize(vec3_sub(p, rtx->obj[rtx->hit].pos)); break; case PLANE: n = rtx->obj[rtx->hit].norm; break; default: break; } next.pos = vec3_add(p, vec3_scale(n, EPSILON)); vec3_t lv = vec3_sub(rtx->light.pos, p); vec3_t l = normalize(lv); next.dir = rtx->ray.dir; int prev_hit_index = rtx->hit; vec3_t hit_obj_col = rtx->obj[rtx->hit].col; float diffuse = dot(n, l); float specular = dot(rtx->ray.dir, vec3_sub(l, vec3_scale(n, 2.0f * diffuse))); diffuse = max(diffuse, 0.0f); specular = max(specular, 0.0f); specular = power_spec(specular); float s1 = 1.0f; float s2 = 1.0f; if (rtx->obj[rtx->hit].flag_shadow) { rtx->ray.dir = l; rtx->ray.pos = next.pos; trace_ray(rtx); int shadow = (rtx->dist < norm(lv)); s1 = shadow ? 0.5f : s1; s2 = shadow ? 0.0f : s2; } col = vec3_add(col, vec3_add(vec3_scale(rtx->light.col, specular * s2), vec3_scale(hit_obj_col, diffuse * s1))); if (!rtx->obj[prev_hit_index].flag_refrect) { break; } rtx->ray.dir = vec3_sub(next.dir, vec3_scale(n, dot(next.dir, n) * 2.0f)); rtx->ray.pos = next.pos; } else { break; } } col = vec3_min(vec3_max(col, 0.0f), 1.0f); uint32_t col2 = 0xff000000 + ((unsigned int)(col.x * 255.0f) << 16) + ((unsigned int)(col.y * 255.0f) << 8) + (unsigned int)(col.z * 255.0f); *pixel = col2; #if SCALE > 1 *(pixel + 1) = col2; #endif #if SCALE > 3 *(pixel + 2) = col2; *(pixel + 3) = col2; #endif pixel += SCALE; sx += rtx->ax; } uint32_t size = rtx->width * SCALE; unsigned int i; for (i = 1; i < SCALE; i++) { uint32_t *dst = src + i * msg->fbinfo.line_length / sizeof(uint32_t); unsigned int j; for (j = 0; j < size; j++) { dst[j] = src[j]; } } sy -= rtx->ay; } }
static bool ray_surface_intersect(Ray ray, const Surface *surf, Hit *hit) { float ts[2] = {-HUGE_VAL, -HUGE_VAL}, t; Vec3 tnormals[2] = {{0,0,0},{0,0,0}}, tnormal; Ray tray; Mat4 normal_matrix; Shape *shape = surf->shape; int hits; mat4_copy(normal_matrix, surf->world_to_model); mat4_transpose(normal_matrix); tray.origin = mat4_transform3_homo(surf->world_to_model, ray.origin); tray.direction = mat4_transform3_hetero(surf->world_to_model, ray.direction); tray.near = ray.near; tray.far = ray.far; switch(shape->type) { case SHAPE_PLANE: hits = ray_plane_intersect(tray, shape->u.plane, ts, tnormals); break; case SHAPE_DISK: hits = ray_disk_intersect(tray, shape->u.disk, ts, tnormals); break; case SHAPE_SPHERE: hits = ray_sphere_intersect(tray, shape->u.sphere, ts, tnormals); break; case SHAPE_CYLINDER: hits = ray_cylinder_intersect(tray, shape->u.cylinder, ts, tnormals); break; case SHAPE_CONE: hits = ray_cone_intersect(tray, shape->u.cone, ts, tnormals); break; case SHAPE_MESH: hits = ray_mesh_intersect(tray, shape->u.mesh, ts, tnormals); break; default: printf("Unknown shape\n"); return false; break; } /* We're looking for the smallest hit that is between the near and far * planes of the ray. */ if (hits == 0) return false; if (hits == 1) { if (ts[0] < ray.near || ts[0] > ray.far) return false; t = ts[0]; tnormal = tnormals[0]; } else if (hits == 2) { bool t0_ok = ts[0] >= ray.near && ts[0] <= ray.far; bool t1_ok = ts[1] >= ray.near && ts[1] <= ray.far; if (!t0_ok && !t1_ok) { return false; } else if (t0_ok && !t1_ok) { t = ts[0]; tnormal = tnormals[0]; } else if (!t0_ok && t1_ok) { t = ts[1]; tnormal = tnormals[1]; } else { if (ts[0] < ts[1]) { t = ts[0]; tnormal = tnormals[0]; } else { t = ts[1]; tnormal = tnormals[1]; } } } else { printf("General t finding code unimplemented\n"); return false; } hit->t = t; hit->position = vec3_add(ray.origin, vec3_scale(t, ray.direction)); hit->normal = vec3_normalize(mat4_transform3_hetero(normal_matrix, tnormal)); return true; }
X42_EXPORT affine_t* X42_CALL x42_GetAnimBoneMatrices( void *out_buffer, const x42data_t *x42, const x42animLerp_t *lerp, x42opts_t *opts ) { uint i; affine_t * RESTRICT ret; const vec3_t * RESTRICT pv; const vec3_t * RESTRICT sv; const quat_t * RESTRICT rv; REF_PARAM( opts ); #ifndef LIBX42_NO_PARAM_VALIDATION demand_rn( out_buffer != NULL, X42_ERR_BADPTR, "out_buffer is NULL" ); demand_rn( lerp != NULL, X42_ERR_BADPTR, "lerp is NULL" ); demand_rn( x42 != NULL, X42_ERR_BADPTR, "x42 is NULL" ); demand_rn( x42_ValidateHeader( &x42->header ), X42_ERR_BADDATA, "invalid x42 header data" ); #endif pv = lerp->p; sv = lerp->s; rv = lerp->r; ret = (affine_t*)out_buffer; for( i = 0; i < x42->header.numBones; i++ ) { affine_t * RESTRICT o = ret + i; const x42bone_t * RESTRICT b = x42->bones + i; if( b->parentIdx != X42_MODEL_BONE && (b->flags & X42_BF_USE_INV_PARENT_SCALE) ) { vec3_t ips; affine_t rs; quat_to_affine( &rs, rv[i] ); vec3_scale( rs.c[0], rs.c[0], sv[i][0] ); vec3_scale( rs.c[1], rs.c[1], sv[i][1] ); vec3_scale( rs.c[2], rs.c[2], sv[i][2] ); ips[0] = 1.0F / sv[b->parentIdx][0]; ips[1] = 1.0F / sv[b->parentIdx][1]; ips[2] = 1.0F / sv[b->parentIdx][2]; vec3_mul( o->c[0], rs.c[0], ips ); vec3_mul( o->c[1], rs.c[1], ips ); vec3_mul( o->c[2], rs.c[2], ips ); } else { quat_to_affine( o, rv[i] ); vec3_scale( o->c[0], o->c[0], sv[i][0] ); vec3_scale( o->c[1], o->c[1], sv[i][1] ); vec3_scale( o->c[2], o->c[2], sv[i][2] ); } vec3_cpy( o->c[3], pv[i] ); } for( i = 0; i < x42->header.numBones; i++ ) { const x42bone_t * RESTRICT b = x42->bones + i; if( b->parentIdx != X42_MODEL_BONE ) affine_mul( ret + i, ret + b->parentIdx, ret + i ); else if( x42->header.runFlags & X42_RF_ROOT_MATRIX ) affine_mul( ret + i, &x42->rootMatrix, ret + i ); } return ret; }
group* make_tree(sphere* spheres, int start, unsigned int count, int level = 0) { if(level == 0) { previous = time(NULL); if(getenv("DEBUG_BVH") != NULL) { bvh_spheres_debug_output = fopen("bvh.r9", "w"); } } if(time(NULL) > previous) { fprintf(stderr, "total treed = %d\n", total_treed); previous = time(NULL); } if((level >= bvh_max_depth) || count <= bvh_leaf_max) { total_treed += count; group* g = new group(spheres, start, count); if(bvh_spheres_debug_output != NULL) { // fprintf(bvh_spheres_debug_output, "sphere 7 %f %f %f %f 1 1 1 # %d\n", g->radius, g->center.x, g->center.y, g->center.z, level ); if(level == 0) { fclose(bvh_spheres_debug_output); bvh_spheres_debug_output = NULL; } } bvh_leaf_size_counts[std::min(63U, count)]++; bvh_leaf_count++; bvh_level_counts[level]++; bvh_node_count++; return g; } vec3 split_pivot; vec3 split_plane_normal; // find bounding box vec3 boxmin, boxmax; box_init(boxmin, boxmax); for(unsigned int i = 0; i < count; i++) { sphere &s = spheres[start + i]; vec3 spheremin = vec3_subtract(s.center, vec3(s.radius)); vec3 spheremax = vec3_add(s.center, vec3(s.radius)); box_extend(boxmin, boxmax, spheremin, spheremax); } split_pivot = vec3_scale(vec3_add(boxmin, boxmax), .5); vec3 boxdim = vec3_subtract(boxmax, boxmin); if(boxdim.x > boxdim.y && boxdim.x > boxdim.z) { split_plane_normal = vec3(1, 0, 0); } else if(boxdim.y > boxdim.z) { split_plane_normal = vec3(0, 1, 0); } else { split_plane_normal = vec3(0, 0, 1); } // XXX output split plane to BVH debug file int startA; int countA; int startB; int countB; if(!bvh_split_median) { int s1 = start - 1; int s2 = start + count; do { // from start to s1, not including s1, is negative // from s2 to start + count - 1 is positive do { s1 += 1; } while((s1 < s2) && vec3_dot(vec3_subtract(spheres[s1].center, split_pivot), split_plane_normal) < 0); // If there wasn't a positive sphere before s2, done. if(s1 >= s2) break; // s1 is now location of lowest positive sphere do { s2 -= 1; } while((s1 < s2) && vec3_dot(vec3_subtract(spheres[s2].center, split_pivot), split_plane_normal) >= 0); // If there wasn't a negative sphere between s1 and s2, done if(s1 >= s2) break; // s2 is now location of highest negative sphere std::swap(spheres[s1], spheres[s2]); } while(true); // s1 is the first of the positive spheres startA = start; countA = s1 - startA; startB = s1; countB = start + count - s1; } else { sphere_sorter sorter(split_plane_normal); std::sort(spheres + start, spheres + start + count - 1, sorter); startA = start; countA = count / 2; startB = startA + countA; countB = count - countA; } group *g; if(countA > 0 && countB > 0) { // get a tighter bound around children than hierarchical bounds vec3 boxmin, boxmax; box_init(boxmin, boxmax); for(unsigned int i = 0; i < count; i++) { add_sphere(&boxmin, &boxmax, spheres[start + i].center, spheres[start + i].radius); } // construct children group *g1 = make_tree(spheres, startA, countA, level + 1); g = new group(spheres, g1, NULL, split_plane_normal, boxmin, boxmax); group *g2 = make_tree(spheres, startB, countB, level + 1); g->positive = g2; bvh_level_counts[level]++; bvh_node_count++; } else { total_treed += count; fprintf(stderr, "Leaf node at %d, %u spheres, total %d\n", level, count, total_treed); g = new group(spheres, start, count); bvh_leaf_size_counts[std::min(63U, count)]++; bvh_leaf_count++; bvh_level_counts[level]++; bvh_node_count++; } if(bvh_spheres_debug_output != NULL) { // fprintf(bvh_spheres_debug_output, "sphere 7 %f %f %f %f 1 1 1 # %d\n", g->radius, g->center.x, g->center.y, g->center.z, level ); if(level == 0) { fclose(bvh_spheres_debug_output); bvh_spheres_debug_output = NULL; } } return g; }
int main(int argc, char** argv) { Settings settings; ConstructSettings(&settings); LoadSettingsFile(&settings, "settings.ini"); if(Init(&settings) < 0) return -1; GLuint program; if(SetupProgram(&program) < 0) return -2; GLuint grid_vbuf = CreateGridVertexBuffer(settings.graphics.viewdistance); int grid_icount; GLuint grid_ibuf = CreateGridIndexBuffer(&grid_icount, settings.graphics.viewdistance); glUseProgram(program); GLint grid_pos_loc = glGetAttribLocation(program, "grid_pos"); GLint grid_world_mat_loc = glGetUniformLocation(program, "world_mat"); GLint grid_view_mat_loc = glGetUniformLocation(program, "view_mat"); GLint grid_proj_mat_loc = glGetUniformLocation(program, "proj_mat"); GLint grid_color_loc = glGetUniformLocation(program, "color"); GLint grid_viewdistance_loc = glGetUniformLocation(program, "viewdistance"); glUniform3f(grid_color_loc, 0.f, 0.6f, 0.f); glUniform1f(grid_viewdistance_loc, settings.graphics.viewdistance); GLuint grid_vao; glGenVertexArrays(1, &grid_vao); glBindVertexArray(grid_vao); glBindBuffer(GL_ARRAY_BUFFER, grid_vbuf); glEnableVertexAttribArray(grid_pos_loc); glVertexAttribPointer(grid_pos_loc, 2, GL_FLOAT, GL_FALSE, 0, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, grid_ibuf); glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); glClearColor(0.5f, 0.5f, 0.5f, 1.f); glViewport(0, 0, settings.video.width, settings.video.height); Node grid_node; ConstructNode(&grid_node); Camera camera; ConstructCamera(&camera); mat4x4 projection_matrix; mat4x4_perspective(projection_matrix, settings.video.pfov, settings.video.width/(float)settings.video.height, settings.video.pnear, settings.video.pfar); glUniformMatrix4fv(grid_proj_mat_loc, 1, GL_FALSE, (const float*)projection_matrix); float speed = 10.f; Uint32 ticks = SDL_GetTicks(); State state = STATE_RUNNING | (settings.video.fullscreen ? STATE_FULLSCREEN : 0); while(state & STATE_RUNNING) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glUseProgram(program); glUniformMatrix4fv(grid_world_mat_loc, 1, GL_FALSE, (const float*)grid_node.world_matrix); glUniformMatrix4fv(grid_view_mat_loc, 1, GL_FALSE, (const float*)camera.view_matrix); glBindVertexArray(grid_vao); glDrawElements(GL_TRIANGLE_STRIP, grid_icount, GL_UNSIGNED_INT, NULL); SDL_GL_SwapWindow(window); SDL_Event event; while(SDL_PollEvent(&event)) { switch(event.type) { case SDL_QUIT: state &= ~STATE_RUNNING; break; case SDL_KEYUP: switch(event.key.keysym.scancode) { case SDL_SCANCODE_F11: state ^= STATE_FULLSCREEN; SDL_SetWindowFullscreen ( window, state & STATE_FULLSCREEN ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0 ); break; case SDL_SCANCODE_ESCAPE: state ^= STATE_MOUSE_GRABBED; SDL_SetRelativeMouseMode(state & STATE_MOUSE_GRABBED); break; case SDL_SCANCODE_LSHIFT: speed = settings.controls.speed1; break; default: break; } break; case SDL_KEYDOWN: switch(event.key.keysym.scancode) { case SDL_SCANCODE_LSHIFT: speed = settings.controls.speed2; break; default: break; } break; case SDL_WINDOWEVENT: if(event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) { int w = event.window.data1; int h = event.window.data2; glViewport(0, 0, w, h); mat4x4_perspective(projection_matrix, settings.video.pfov, w/(float)h, settings.video.pnear, settings.video.pfar); glUniformMatrix4fv(grid_proj_mat_loc, 1, GL_FALSE, (const float*)projection_matrix); } break; case SDL_MOUSEMOTION: if(state & STATE_MOUSE_GRABBED) { camera.yaw -= settings.controls.xsensitivity * event.motion.xrel; camera.pitch -= settings.controls.xsensitivity * event.motion.yrel; } break; default: break; } } Uint32 nticks = SDL_GetTicks(); float delta = (nticks - ticks)/1000.f; ticks = nticks; const Uint8* keys = SDL_GetKeyboardState(NULL); vec3 movement; int i; for(i = 0; i < 3; i++) movement[i] = 0.f; SDL_bool moved = SDL_FALSE; if(keys[SDL_SCANCODE_W] && !keys[SDL_SCANCODE_S]) { vec3_add(movement, movement, camera.direction); moved = SDL_TRUE; } else if(keys[SDL_SCANCODE_S] && !keys[SDL_SCANCODE_W]) { vec3_sub(movement, movement, camera.direction); moved = SDL_TRUE; } if(keys[SDL_SCANCODE_A] && !keys[SDL_SCANCODE_D]) { vec3_sub(movement, movement, camera.right); moved = SDL_TRUE; } else if(keys[SDL_SCANCODE_D] && !keys[SDL_SCANCODE_A]) { vec3_add(movement, movement, camera.right); moved = SDL_TRUE; } if(keys[SDL_SCANCODE_Q] && !keys[SDL_SCANCODE_E]) { vec3_sub(movement, movement, camera.up); moved = SDL_TRUE; } else if(keys[SDL_SCANCODE_E] && !keys[SDL_SCANCODE_Q]) { vec3_add(movement, movement, camera.up); moved = SDL_TRUE; } if(moved) { vec3_norm(movement, movement); vec3_scale(movement, movement, delta * speed); vec3_add(camera.node.translation, camera.node.translation, movement); } UpdateCamera(&camera); if(moved) { vec2 tmp1; tmp1[0] = camera.node.position[0]; tmp1[1] = camera.node.position[2]; vec2 tmp2; tmp2[0] = grid_node.position[0]; tmp2[1] = grid_node.position[2]; vec2_sub(tmp1, tmp1, tmp2); tmp1[0] = floor(tmp1[0]); tmp1[1] = floor(tmp1[1]); grid_node.translation[0] += tmp1[0]; grid_node.translation[2] += tmp1[1]; UpdateNode(&grid_node); } } glDeleteVertexArrays(1, &grid_vao); glDeleteBuffers(1, &grid_vbuf); glDeleteBuffers(1, &grid_ibuf); glDeleteProgram(program); return 0; }
/** * Check for collision between objects. **/ int object_check_collision(object_t *a, object_t *b) { float direction[3] = { 0, 1, 0 }; float simplex[4][3]; size_t simplex_pos = 5; size_t last; float middle[3]; float to_last[3]; if (! (object_is_collider(a) && object_is_collider(b))) return 0; object_support(a, b, direction, simplex[0]); direction[2] = -1; object_support(a, b, direction, simplex[1]); if (vec3_dot(simplex[1], direction) <= 0) return 0; vec3_subtract(simplex[1], simplex[0], to_last); vec3_cross(simplex[1], to_last, direction); vec3_cross(direction, to_last, direction); object_support(a, b, direction, simplex[2]); if (vec3_dot(simplex[2], direction) <= 0) return 0; while (vec3_dot(simplex[simplex_pos], direction)) { if (simplex_pos == 5) { simplex_pos = 3; last = 2; } else { last = simplex_pos; simplex_pos = object_simplex_detect_region(simplex, simplex_pos); } if (simplex_pos == 4) return 1; middle[0] = middle[1] = middle[2] = 0; if (simplex_pos != 3) vec3_add(simplex[3], middle, middle); if (simplex_pos != 2) vec3_add(simplex[2], middle, middle); if (simplex_pos != 1) vec3_add(simplex[1], middle, middle); if (simplex_pos != 0) vec3_add(simplex[0], middle, middle); vec3_scale(middle, middle, 1.0/3.0); vec3_subtract(middle, simplex[last], to_last); vec3_cross(middle, to_last, direction); vec3_cross(direction, to_last, direction); object_support(a, b, direction, simplex[simplex_pos]); } return 0; }