float sphere_intersect(vec3 center, float radius, const ray& ray, const range &r)
{
    if(keep_stats) sphere_intersections++;
    vec3 diff = vec3_subtract(ray.o, center);

    float b = 2 * vec3_dot(ray.d, diff);

    float radicand = b * b - 4 * (vec3_dot(diff, diff) - radius * radius);
    if(radicand < 0)
        return NO_t;

    float t1 = (-b + sqrtf(radicand)) / 2;

    if(t1 < r.t0)
         return NO_t;

    float t0 = (-b - sqrtf(radicand)) / 2;

    if(t0 > r.t1)
        return NO_t;

    if(t0 < r.t0)
        return t1;

    return t0;
}
Example #2
0
/**
 * 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));
}
Example #3
0
static void find_nearest_block(struct group *group, struct ray const *ray, struct nearest *nearest)
{
    struct groupdata *groupdata = group->data;

    struct ray groupspaceray;
    vec3_subtract(&groupspaceray.origin, &ray->origin, &group->position);
    groupspaceray.direction = ray->direction;

    buffer *buffer = create_buffer();
    ptrarray *blocks = groupdata->blocks;
    size_t blockcount = ptrarray_count(blocks);

    for (size_t i = 0; i < blockcount; ++i)
    {
        block *block = get_ptrarray(blocks, i);

        get_block_triangles(block, buffer);

        triangle *tris = buffer_data(buffer);
        size_t tricount = buffer_count(buffer, sizeof(struct triangle));

        for (size_t j = 0; j < tricount; ++j)
        {
            float temp;
            if (ray_intersect_triangle(&temp, &groupspaceray, &tris[j]))
            {
                /*
                 * Use <= for distance comparsion here so that when there are
                 * multiple candidates for selection the last block added will
                 * be selected. It is useful after pasting that the new blocks
                 * can be dragged to a new location.
                 */
                if (temp <= nearest->distance)
                {
                    nearest->distance = temp;
                    nearest->group    = group;
                    nearest->block    = block;
                    nearest->triangle = tris[j];
                }
            }
        }

        clear_buffer(buffer);
    }

    destroy_buffer(buffer);

    struct ptrarray *groups = groupdata->groups;
    size_t groupcount = ptrarray_count(groups);

    for (size_t i = 0; i < groupcount; ++i)
    {
        struct group *childgroup = get_ptrarray(groups, i);
        find_nearest_block(childgroup, ray, nearest);
    }
}
Example #4
0
/**
 * 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);
}
Example #5
0
void move_group_origin(struct group *group, vec3 const *position)
{
    vec3 translation;
    vec3_subtract(&translation, &group->position, position);

    foreach_block(group->data, translate_block_, &translation);
    foreach_group(group->data, translate_group_, &translation);

    group->position = *position;
    update_group_vertexarray(group);
}
Example #6
0
void keyboard(unsigned char key, int x, int y)
{
    float direction[3];
    float rotation[16];
    mat4_identity(rotation);

    switch (key) {
        case 'q':
            vec3_subtract(center, eye, direction);
            vec3_normalize(direction, direction);
            vec3_add(eye, direction, eye);
            break;
        case 'e':
            vec3_subtract(center, eye, direction);
            vec3_normalize(direction, direction);
            vec3_subtract(eye, direction, eye);
            break;
        case 'a':
            mat4_rotateY(rotation, 0.1f, rotation);
            mat4_multiply(rotation, model, model);
            break;
        case 'd':
            mat4_rotateY(rotation, -0.1f, rotation);
            mat4_multiply(rotation, model, model);
            break;
        case 'w':
            mat4_rotateX(rotation, 0.1f, rotation);
            mat4_multiply(rotation, model, model);
            break;
        case 's':
            mat4_rotateX(rotation, -0.1f, rotation);
            mat4_multiply(rotation, model, model);
            break;
        case 27:
            exit(0);
        default:
            break;
    }
}
bool sphere_possible(vec3 center, float radius, const ray& ray)
{
    if(keep_stats) sphere_tests++;
    vec3 diff = vec3_subtract(ray.o, center);

    float b = 2 * vec3_dot(ray.d, diff);

    float radicand = b * b - 4 * (vec3_dot(diff, diff) - radius * radius);
    if(radicand < 0)
        return false;

    return true;
}
Example #8
0
/* Manually apply a look-at matrix. Will reset MODELVIEW automatically. */
void cm_apply_look_at(VEC3 target, VEC3 position)
{
  VEC3 forward = vec3_normalize(vec3_subtract(target, position));
  VEC3 right = vec3_cross(forward, (VEC3){ 0, 1, 0 });
  VEC3 up = vec3_normalize(vec3_cross(forward, right));
  double ang = atan(NOT_DUMB_ABS(forward.y) / sqrt(forward.x * forward.x + forward.z * forward.z));
  if (ang >= PI_O4)
  {
    up = vec3_negate(up);
  }

  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  gluLookAt(position.x, position.y, position.z, target.x, target.y, target.z, up.x, up.y, up.z);
}
range sphere_intersect(vec3 center, float radius, const ray& ray)
{
    if(keep_stats) sphere_intersections++;
    vec3 diff = vec3_subtract(ray.o, center);

    float b = 2 * vec3_dot(ray.d, diff);

    float radicand = b * b - 4 * (vec3_dot(diff, diff) - radius * radius);
    if(radicand < 0)
        return range(std::numeric_limits<float>::max(), -std::numeric_limits<float>::max());

    float t0 = (-b - sqrtf(radicand)) / 2;
    float t1 = (-b + sqrtf(radicand)) / 2;
    return range(t0, t1);
}
Example #10
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;
}
Example #11
0
void matrix_4x4_lookat(math_matrix_4x4 *out,
      vec3_t eye,
      vec3_t center,
      vec3_t up)
{
   vec3_t zaxis;   /* the "forward" vector */
   vec3_t xaxis;   /* the "right"   vector */
   vec3_t yaxis;   /* the "up"      vector */

   vec3_copy(&zaxis[0], center);
   vec3_subtract(&zaxis[0], eye);
   vec3_normalize(&zaxis[0]);

   vec3_cross(&xaxis[0], &zaxis[0], up);
   vec3_normalize(&xaxis[0]);
   vec3_cross(&yaxis[0], &xaxis[0], zaxis);

   MAT_ELEM_4X4(*out, 0, 0) = xaxis[0];
   MAT_ELEM_4X4(*out, 0, 1) = yaxis[0];
   MAT_ELEM_4X4(*out, 0, 2) = -zaxis[0];
   MAT_ELEM_4X4(*out, 0, 3) = 0.0;

   MAT_ELEM_4X4(*out, 1, 0) = xaxis[1];
   MAT_ELEM_4X4(*out, 1, 1) = yaxis[1];
   MAT_ELEM_4X4(*out, 1, 2) = -zaxis[1];
   MAT_ELEM_4X4(*out, 1, 3) = 0.0f;

   MAT_ELEM_4X4(*out, 2, 0) = xaxis[2];
   MAT_ELEM_4X4(*out, 2, 1) = yaxis[2];
   MAT_ELEM_4X4(*out, 2, 2) = -zaxis[2];
   MAT_ELEM_4X4(*out, 2, 3) = 0.0f;

   MAT_ELEM_4X4(*out, 3, 0) = -(xaxis[0] * eye[0] + xaxis[1] * eye[1] + xaxis[2] * eye[2]);
   MAT_ELEM_4X4(*out, 3, 1) = -(yaxis[0] * eye[0] + yaxis[1] * eye[1] + yaxis[2] * eye[2]);
   MAT_ELEM_4X4(*out, 3, 2) = -(zaxis[0] * eye[0] + zaxis[1] * eye[1] + zaxis[2] * eye[2]);
   MAT_ELEM_4X4(*out, 3, 3) = 1.f;
}
Example #12
0
/* TODO/FIXME - finish */
void matrix_4x4_lookat(math_matrix_4x4 *out,
      vec3_t eye,
      vec3_t center,
      vec3_t up)
{
   vec3_t s, t, f;

   vec3_copy(&f[0], center);
   vec3_subtract(&f[0], eye);
   vec3_normalize(&f[0]);

   vec3_cross(&s[0], &f[0], up);
   vec3_normalize(&s[0]);

   vec3_cross(&t[0], &s[0], f);

   memset(out, 0, sizeof(*out));

   MAT_ELEM_4X4(*out, 0, 0) = s[0];
   MAT_ELEM_4X4(*out, 0, 1) = t[0];
   MAT_ELEM_4X4(*out, 0, 2) = -f[0];

   MAT_ELEM_4X4(*out, 1, 0) = s[1];
   MAT_ELEM_4X4(*out, 1, 1) = t[1];
   MAT_ELEM_4X4(*out, 1, 2) = -f[1];

   MAT_ELEM_4X4(*out, 2, 0) = s[2];
   MAT_ELEM_4X4(*out, 2, 1) = t[2];
   MAT_ELEM_4X4(*out, 2, 2) = -f[2];

   MAT_ELEM_4X4(*out, 3, 3) = 1.f;

#if 0
   mat4x4_translate_in_place(m, -eye[0], -eye[1], -eye[2]);
#endif

}
Example #13
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;
}
Example #14
0
world *load_world(char *fname) // Get world and return pointer.
{
    char *inpstr;
    int wkd;

    std::auto_ptr<world> w(new world);

    time_t prev = time(NULL);

    scoped_FILE fp(fopen(fname, "r"));
    if(fp == NULL) {
        fprintf(stderr, "Cannot open file %s for input.\nE#%d\n", fname, errno);
        return NULL;
    }
    if((inpstr = getstr(fp)) == NULL) {
        fprintf(stderr, "Cannot read title.\n");
        return NULL;
    }
    if(strcmp(inpstr, ".") != 0) {
        w->Title = NULL;
    } else {
        w->Title = new char[strlen(inpstr) + 1];
        strcpy(w->Title, inpstr);
    }

    // lace now ignored
    int lace;
    if(!getint(fp, &lace)) {
        fprintf(stderr, "*!LACE\n");
        return NULL;
    }

    int wdth, lnth; // now ignored
    if(!getint(fp, &wdth)) {
        fprintf(stderr, "*!WDTH\n");
        return NULL;
    }
    if(!getint(fp, &lnth)) {
        fprintf(stderr, "*!LNTH\n");
        return NULL;
    }

    int xsub, ysub; // now ignored
    if(!getint(fp, &xsub)) {
        fprintf(stderr, "*!xsub\n");
        return NULL;
    }
    if(!getint(fp, &ysub)) {
        fprintf(stderr, "*!ysub\n");
        return NULL;
    }
    w->xsub = 1;
    w->ysub = 1;
    
    int r, g, b, brt;
    if(!getint(fp, &r)) {
        fprintf(stderr, "*!backgroundr\n");
        return NULL;
    }
    if(!getint(fp, &g)) {
        fprintf(stderr, "*!backgroundg\n");
        return NULL;
    }
    if(!getint(fp, &b)) {
        fprintf(stderr, "*!backgroundb\n");
        return NULL;
    }
    if(!getint(fp, &brt)) {
        fprintf(stderr, "*!backgroundb\n");
        return NULL;
    }
    w->background.x = r / 16.0 * brt / 100.0;
    w->background.y = g / 16.0 * brt / 100.0;
    w->background.z = b / 16.0 * brt / 100.0;

    int df;
    if(!getint(fp, &df)) {
        fprintf(stderr, "*!DIFFUSION\n");
        return NULL;
    }
    if(!getint(fp, &w->sphere_count)) {
        fprintf(stderr, "*!#Sphere\n");
        return NULL;
    }

    prev = time(NULL);

    w->spheres = new sphere[w->sphere_count];
    for(int i = 0; i < w->sphere_count; i++) {
        if(time(NULL)  > prev) {
            prev = time(NULL);
            fprintf(stderr, "loaded %u spheres\n", i);
        }
        float x, y, z, radius;
        wkd = fltget(fp, &x) && fltget(fp, &y);
        wkd = (wkd && fltget(fp, &z) && fltget(fp, &radius));

        int r, g, b, brt;
        wkd = (wkd && getint(fp, &r) && getint(fp, &g));
        wkd = (wkd && getint(fp, &b) && getint(fp, &brt));

        if(!wkd) {
            fprintf(stderr, "*!Sphere #%d\n", i);
            return NULL;
        }

        vec3 color(r / 16.0 * brt / 100.0,
            g / 16.0 * brt / 100.0, b / 16.0 * brt / 100.0);

        w->spheres[i] = sphere(vec3(x, y, z), radius, color);
    }

    w->scene_center = w->spheres[0].center;
    for(int i = 1; i < w->sphere_count; i++) {
        w->scene_center = vec3_add(w->spheres[i].center, w->scene_center);
    }
    w->scene_center = vec3_divide(w->scene_center, w->sphere_count);

    w->scene_extent = 0;
    for(int i = 0; i < w->sphere_count; i++) {
        vec3 to_center = vec3_subtract(w->scene_center, w->spheres[i].center);
        float distance = sqrtf(vec3_dot(to_center, to_center)) + w->spheres[i].radius;
        w->scene_extent = std::max(w->scene_extent, distance);
    }
    w->scene_extent *= 2;

    w->root = make_tree(w->spheres, 0, w->sphere_count);
    print_tree_stats();

    wkd = fltget(fp, &w->cam.eye.x) && fltget(fp, &w->cam.eye.y);
    wkd = (wkd && fltget(fp, &w->cam.eye.z) && fltget(fp, &w->cam.yaw));
    wkd = (wkd && fltget(fp, &w->cam.pitch) && fltget(fp, &w->cam.roll));
    wkd = (wkd && fltget(fp, &w->cam.fov));
    if(!wkd) {
        fprintf(stderr, "*!Viewpoint\n");
        return NULL;
    }

    w->cam.pitch = to_radians(w->cam.pitch);
    w->cam.yaw = to_radians(w->cam.yaw);
    w->cam.roll = to_radians(w->cam.roll);
    w->cam.fov = to_radians(w->cam.fov);

    return w.release();
}
Example #15
0
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;
}
Example #16
0
 bool operator() (const sphere& s1, const sphere& s2)
 {
     vec3 diff = vec3_subtract(s2.center, s1.center);
     return vec3_dot(diff, split_plane_normal) > 0;
 }