nuclear@14: #include nuclear@1: #include "object.h" nuclear@1: #include "vmath.h" nuclear@1: #include "min3d.h" nuclear@9: #include "logger.h" nuclear@1: nuclear@1: Object::Object() nuclear@1: { nuclear@12: type = NODE_OBJECT; nuclear@1: } nuclear@1: nuclear@1: Object::~Object() nuclear@1: { nuclear@1: } nuclear@1: nuclear@17: Vector3 Object::hit_normal(const RayHit &hit) const nuclear@17: { nuclear@17: return Vector3(0, 0, 0); nuclear@17: } nuclear@17: nuclear@1: // ---- sphere ---- nuclear@1: Sphere::Sphere() nuclear@1: { nuclear@1: } nuclear@1: nuclear@1: Sphere::~Sphere() nuclear@1: { nuclear@1: } nuclear@1: nuclear@9: #define USUB 12 nuclear@9: #define VSUB 6 nuclear@1: nuclear@14: void Sphere::draw(bool emph) const nuclear@1: { nuclear@1: static Vector3 *varr; nuclear@9: static unsigned int *iarr; nuclear@9: static int num_verts, num_indices; nuclear@1: if(!varr) { nuclear@9: int i, j; nuclear@1: int uverts = USUB; nuclear@1: int vverts = VSUB + 1; nuclear@9: nuclear@1: num_verts = uverts * vverts; nuclear@1: varr = new Vector3[num_verts]; nuclear@1: nuclear@1: Vector3 *vptr = varr; nuclear@9: for(i=0; ix); nuclear@9: m3d_draw_indexed(M3D_QUADS, iarr, num_indices); nuclear@5: m3d_vertex_array(0); nuclear@12: nuclear@12: post_draw(); nuclear@1: } nuclear@12: nuclear@17: bool Sphere::intersect(const Ray &wray, RayHit *hit) const nuclear@12: { nuclear@14: Ray ray = transform(get_inv_matrix(), wray); nuclear@14: nuclear@14: // assumes center is 0,0,0, and radius is 1 nuclear@14: float a = dot(ray.dir, ray.dir); nuclear@14: float b = 2.0 * ray.dir.x * ray.origin.x + nuclear@14: 2.0 * ray.dir.y * ray.origin.y + nuclear@14: 2.0 * ray.dir.z * ray.origin.z; nuclear@14: float c = dot(ray.origin, ray.origin) - 1.0; nuclear@14: nuclear@14: float discr = b * b - 4.0 * a * c; nuclear@14: if(discr < 1e-4) nuclear@14: return false; nuclear@14: nuclear@14: float sqrt_discr = sqrt(discr); nuclear@14: float t0 = (-b + sqrt_discr) / (2.0 * a); nuclear@14: float t1 = (-b - sqrt_discr) / (2.0 * a); nuclear@14: nuclear@14: if(t0 < 1e-4) nuclear@14: t0 = t1; nuclear@14: if(t1 < 1e-4) nuclear@14: t1 = t0; nuclear@14: nuclear@14: float t = t0 < t1 ? t0 : t1; nuclear@14: if(t < 1e-4) nuclear@14: return false; nuclear@14: nuclear@17: if(hit) { nuclear@17: hit->ray = wray; nuclear@17: hit->lray = ray; nuclear@17: hit->dist = t; nuclear@17: hit->obj = this; nuclear@17: hit->subobj = 0; nuclear@17: } nuclear@14: return true; nuclear@12: } nuclear@12: nuclear@17: Vector3 Sphere::hit_normal(const RayHit &hit) const nuclear@17: { nuclear@17: return hit.lray.origin + hit.lray.dir * hit.dist; nuclear@17: } nuclear@17: nuclear@12: // ---- box ---- nuclear@12: nuclear@12: Box::Box() nuclear@12: { nuclear@12: } nuclear@12: nuclear@12: Box::~Box() nuclear@12: { nuclear@12: } nuclear@12: nuclear@12: /* nuclear@12: 3--------2 nuclear@12: /. .\ nuclear@12: 0------------1 nuclear@12: | 7--------6 | nuclear@12: |/ \| nuclear@12: 4------------5 nuclear@12: nuclear@12: */ nuclear@14: void Box::draw(bool emph) const nuclear@12: { nuclear@12: static const float verts[] = { nuclear@12: -1, 1, 1, nuclear@12: 1, 1, 1, nuclear@12: 1, 1, -1, nuclear@12: -1, 1, -1, nuclear@12: -1, -1, 1, nuclear@12: 1, -1, 1, nuclear@12: 1, -1, -1, nuclear@12: -1, -1, -1 nuclear@12: }; nuclear@12: static const unsigned int indices[] = { nuclear@12: 0, 1, 2, 3, // top nuclear@12: 4, 7, 6, 5, // bottom nuclear@12: 0, 4, 5, 1, // front nuclear@12: 5, 6, 2, 1, // right nuclear@12: 6, 7, 3, 2, // back nuclear@12: 7, 4, 0, 3 // left nuclear@12: }; nuclear@12: nuclear@12: pre_draw(); nuclear@14: SceneNode::draw(emph); nuclear@12: nuclear@12: m3d_vertex_array(verts); nuclear@12: m3d_draw_indexed(M3D_QUADS, indices, sizeof indices / sizeof *indices); nuclear@12: m3d_vertex_array(0); nuclear@12: nuclear@12: post_draw(); nuclear@12: } nuclear@12: nuclear@17: bool Box::intersect(const Ray &wray, RayHit *hit) const nuclear@12: { nuclear@17: Ray ray = transform(get_inv_matrix(), wray); nuclear@17: nuclear@17: Vector3 param[2] = { Vector3(-1, -1, -1), Vector3(1, 1, 1) }; nuclear@17: Vector3 inv_dir(1.0 / ray.dir.x, 1.0 / ray.dir.y, 1.0 / ray.dir.z); nuclear@17: int sign[3] = {inv_dir.x < 0, inv_dir.y < 0, inv_dir.z < 0}; nuclear@17: nuclear@17: float tmin = (param[sign[0]].x - ray.origin.x) * inv_dir.x; nuclear@17: float tmax = (param[1 - sign[0]].x - ray.origin.x) * inv_dir.x; nuclear@17: float tymin = (param[sign[1]].y - ray.origin.y) * inv_dir.y; nuclear@17: float tymax = (param[1 - sign[1]].y - ray.origin.y) * inv_dir.y; nuclear@17: nuclear@17: if(tmin > tymax || tymin > tmax) { nuclear@17: return false; nuclear@17: } nuclear@17: if(tymin > tmin) tmin = tymin; nuclear@17: if(tymax < tmax) tmax = tymax; nuclear@17: nuclear@17: float tzmin = (param[sign[2]].z - ray.origin.z) * inv_dir.z; nuclear@17: float tzmax = (param[1 - sign[2]].z - ray.origin.z) * inv_dir.z; nuclear@17: nuclear@17: if(tmin > tzmax || tzmin > tmax) { nuclear@17: return false; nuclear@17: } nuclear@17: if(tzmin > tmin) tmin = tzmin; nuclear@17: if(tzmax < tmax) tmax = tzmax; nuclear@17: nuclear@17: float t = tmin < 1e-4 ? tmax : tmin; nuclear@17: if(t >= 1e-4) { nuclear@17: if(hit) { nuclear@17: hit->dist = t; nuclear@17: hit->ray = wray; nuclear@17: hit->lray = ray; nuclear@17: hit->obj = this; nuclear@17: hit->subobj = 0; nuclear@17: } nuclear@17: return true; nuclear@17: } nuclear@17: return false; nuclear@12: } nuclear@17: nuclear@17: Vector3 Box::hit_normal(const RayHit &hit) const nuclear@17: { nuclear@17: Vector3 lpt = hit.lray.origin + hit.lray.dir * hit.dist; nuclear@17: nuclear@17: if(fabs(lpt.x) > fabs(lpt.y) && fabs(lpt.x) > fabs(lpt.z)) { nuclear@17: return Vector3(lpt.x, 0, 0); nuclear@17: } nuclear@17: if(fabs(lpt.y) > fabs(lpt.z)) { nuclear@17: return Vector3(0, lpt.y, 0); nuclear@17: } nuclear@17: return Vector3(0, 0, lpt.z); nuclear@17: }