rev |
line source |
nuclear@14
|
1 #include <math.h>
|
nuclear@1
|
2 #include "object.h"
|
nuclear@1
|
3 #include "vmath.h"
|
nuclear@1
|
4 #include "min3d.h"
|
nuclear@9
|
5 #include "logger.h"
|
nuclear@1
|
6
|
nuclear@1
|
7 Object::Object()
|
nuclear@1
|
8 {
|
nuclear@12
|
9 type = NODE_OBJECT;
|
nuclear@1
|
10 }
|
nuclear@1
|
11
|
nuclear@1
|
12 Object::~Object()
|
nuclear@1
|
13 {
|
nuclear@1
|
14 }
|
nuclear@1
|
15
|
nuclear@17
|
16 Vector3 Object::hit_normal(const RayHit &hit) const
|
nuclear@17
|
17 {
|
nuclear@17
|
18 return Vector3(0, 0, 0);
|
nuclear@17
|
19 }
|
nuclear@17
|
20
|
nuclear@1
|
21 // ---- sphere ----
|
nuclear@1
|
22 Sphere::Sphere()
|
nuclear@1
|
23 {
|
nuclear@1
|
24 }
|
nuclear@1
|
25
|
nuclear@1
|
26 Sphere::~Sphere()
|
nuclear@1
|
27 {
|
nuclear@1
|
28 }
|
nuclear@1
|
29
|
nuclear@9
|
30 #define USUB 12
|
nuclear@9
|
31 #define VSUB 6
|
nuclear@1
|
32
|
nuclear@14
|
33 void Sphere::draw(bool emph) const
|
nuclear@1
|
34 {
|
nuclear@1
|
35 static Vector3 *varr;
|
nuclear@9
|
36 static unsigned int *iarr;
|
nuclear@9
|
37 static int num_verts, num_indices;
|
nuclear@1
|
38 if(!varr) {
|
nuclear@9
|
39 int i, j;
|
nuclear@1
|
40 int uverts = USUB;
|
nuclear@1
|
41 int vverts = VSUB + 1;
|
nuclear@9
|
42
|
nuclear@1
|
43 num_verts = uverts * vverts;
|
nuclear@1
|
44 varr = new Vector3[num_verts];
|
nuclear@1
|
45
|
nuclear@1
|
46 Vector3 *vptr = varr;
|
nuclear@9
|
47 for(i=0; i<vverts; i++) {
|
nuclear@9
|
48 float v = (float)i / (float)VSUB;
|
nuclear@9
|
49 float phi = v * M_PI;
|
nuclear@9
|
50 for(j=0; j<uverts; j++) {
|
nuclear@9
|
51 float u = (float)j / (float)uverts;
|
nuclear@9
|
52 float theta = u * M_PI * 2.0;
|
nuclear@1
|
53
|
nuclear@9
|
54 float x = sin(theta) * sin(phi);
|
nuclear@12
|
55 float y = -cos(phi);
|
nuclear@9
|
56 float z = cos(theta) * sin(phi);
|
nuclear@1
|
57
|
nuclear@1
|
58 *vptr++ = Vector3(x, y, z);
|
nuclear@1
|
59 }
|
nuclear@1
|
60 }
|
nuclear@9
|
61
|
nuclear@9
|
62 num_indices = USUB * VSUB * 4;
|
nuclear@9
|
63 iarr = new unsigned int[num_indices];
|
nuclear@9
|
64
|
nuclear@9
|
65 unsigned int *iptr = iarr;
|
nuclear@9
|
66 for(i=0; i<VSUB; i++) {
|
nuclear@9
|
67 for(j=0; j<USUB; j++) {
|
nuclear@9
|
68 iptr[0] = i * uverts + j;
|
nuclear@9
|
69 iptr[1] = i * uverts + ((j + 1) % uverts);
|
nuclear@9
|
70 iptr[2] = iptr[1] + uverts;
|
nuclear@9
|
71 iptr[3] = iptr[0] + uverts;
|
nuclear@9
|
72 iptr += 4;
|
nuclear@9
|
73 }
|
nuclear@9
|
74 }
|
nuclear@9
|
75
|
nuclear@9
|
76 printlog("created sphere mesh\n");
|
nuclear@9
|
77 printlog(" vertices: %d (%d slices, %d stacks)\n", num_verts, uverts, vverts);
|
nuclear@9
|
78 printlog(" quads: %d (%d indices, %d usub, %d vsub)\n", USUB * VSUB, num_indices, USUB, VSUB);
|
nuclear@1
|
79 }
|
nuclear@1
|
80
|
nuclear@12
|
81 pre_draw();
|
nuclear@14
|
82 SceneNode::draw(emph);
|
nuclear@9
|
83
|
nuclear@5
|
84 m3d_vertex_array(&varr->x);
|
nuclear@9
|
85 m3d_draw_indexed(M3D_QUADS, iarr, num_indices);
|
nuclear@5
|
86 m3d_vertex_array(0);
|
nuclear@12
|
87
|
nuclear@12
|
88 post_draw();
|
nuclear@1
|
89 }
|
nuclear@12
|
90
|
nuclear@17
|
91 bool Sphere::intersect(const Ray &wray, RayHit *hit) const
|
nuclear@12
|
92 {
|
nuclear@14
|
93 Ray ray = transform(get_inv_matrix(), wray);
|
nuclear@14
|
94
|
nuclear@14
|
95 // assumes center is 0,0,0, and radius is 1
|
nuclear@14
|
96 float a = dot(ray.dir, ray.dir);
|
nuclear@14
|
97 float b = 2.0 * ray.dir.x * ray.origin.x +
|
nuclear@14
|
98 2.0 * ray.dir.y * ray.origin.y +
|
nuclear@14
|
99 2.0 * ray.dir.z * ray.origin.z;
|
nuclear@14
|
100 float c = dot(ray.origin, ray.origin) - 1.0;
|
nuclear@14
|
101
|
nuclear@14
|
102 float discr = b * b - 4.0 * a * c;
|
nuclear@14
|
103 if(discr < 1e-4)
|
nuclear@14
|
104 return false;
|
nuclear@14
|
105
|
nuclear@14
|
106 float sqrt_discr = sqrt(discr);
|
nuclear@14
|
107 float t0 = (-b + sqrt_discr) / (2.0 * a);
|
nuclear@14
|
108 float t1 = (-b - sqrt_discr) / (2.0 * a);
|
nuclear@14
|
109
|
nuclear@14
|
110 if(t0 < 1e-4)
|
nuclear@14
|
111 t0 = t1;
|
nuclear@14
|
112 if(t1 < 1e-4)
|
nuclear@14
|
113 t1 = t0;
|
nuclear@14
|
114
|
nuclear@14
|
115 float t = t0 < t1 ? t0 : t1;
|
nuclear@14
|
116 if(t < 1e-4)
|
nuclear@14
|
117 return false;
|
nuclear@14
|
118
|
nuclear@17
|
119 if(hit) {
|
nuclear@17
|
120 hit->ray = wray;
|
nuclear@17
|
121 hit->lray = ray;
|
nuclear@17
|
122 hit->dist = t;
|
nuclear@17
|
123 hit->obj = this;
|
nuclear@17
|
124 hit->subobj = 0;
|
nuclear@17
|
125 }
|
nuclear@14
|
126 return true;
|
nuclear@12
|
127 }
|
nuclear@12
|
128
|
nuclear@17
|
129 Vector3 Sphere::hit_normal(const RayHit &hit) const
|
nuclear@17
|
130 {
|
nuclear@17
|
131 return hit.lray.origin + hit.lray.dir * hit.dist;
|
nuclear@17
|
132 }
|
nuclear@17
|
133
|
nuclear@12
|
134 // ---- box ----
|
nuclear@12
|
135
|
nuclear@12
|
136 Box::Box()
|
nuclear@12
|
137 {
|
nuclear@12
|
138 }
|
nuclear@12
|
139
|
nuclear@12
|
140 Box::~Box()
|
nuclear@12
|
141 {
|
nuclear@12
|
142 }
|
nuclear@12
|
143
|
nuclear@12
|
144 /*
|
nuclear@12
|
145 3--------2
|
nuclear@12
|
146 /. .\
|
nuclear@12
|
147 0------------1
|
nuclear@12
|
148 | 7--------6 |
|
nuclear@12
|
149 |/ \|
|
nuclear@12
|
150 4------------5
|
nuclear@12
|
151
|
nuclear@12
|
152 */
|
nuclear@14
|
153 void Box::draw(bool emph) const
|
nuclear@12
|
154 {
|
nuclear@12
|
155 static const float verts[] = {
|
nuclear@12
|
156 -1, 1, 1,
|
nuclear@12
|
157 1, 1, 1,
|
nuclear@12
|
158 1, 1, -1,
|
nuclear@12
|
159 -1, 1, -1,
|
nuclear@12
|
160 -1, -1, 1,
|
nuclear@12
|
161 1, -1, 1,
|
nuclear@12
|
162 1, -1, -1,
|
nuclear@12
|
163 -1, -1, -1
|
nuclear@12
|
164 };
|
nuclear@12
|
165 static const unsigned int indices[] = {
|
nuclear@12
|
166 0, 1, 2, 3, // top
|
nuclear@12
|
167 4, 7, 6, 5, // bottom
|
nuclear@12
|
168 0, 4, 5, 1, // front
|
nuclear@12
|
169 5, 6, 2, 1, // right
|
nuclear@12
|
170 6, 7, 3, 2, // back
|
nuclear@12
|
171 7, 4, 0, 3 // left
|
nuclear@12
|
172 };
|
nuclear@12
|
173
|
nuclear@12
|
174 pre_draw();
|
nuclear@14
|
175 SceneNode::draw(emph);
|
nuclear@12
|
176
|
nuclear@12
|
177 m3d_vertex_array(verts);
|
nuclear@12
|
178 m3d_draw_indexed(M3D_QUADS, indices, sizeof indices / sizeof *indices);
|
nuclear@12
|
179 m3d_vertex_array(0);
|
nuclear@12
|
180
|
nuclear@12
|
181 post_draw();
|
nuclear@12
|
182 }
|
nuclear@12
|
183
|
nuclear@17
|
184 bool Box::intersect(const Ray &wray, RayHit *hit) const
|
nuclear@12
|
185 {
|
nuclear@17
|
186 Ray ray = transform(get_inv_matrix(), wray);
|
nuclear@17
|
187
|
nuclear@17
|
188 Vector3 param[2] = { Vector3(-1, -1, -1), Vector3(1, 1, 1) };
|
nuclear@17
|
189 Vector3 inv_dir(1.0 / ray.dir.x, 1.0 / ray.dir.y, 1.0 / ray.dir.z);
|
nuclear@17
|
190 int sign[3] = {inv_dir.x < 0, inv_dir.y < 0, inv_dir.z < 0};
|
nuclear@17
|
191
|
nuclear@17
|
192 float tmin = (param[sign[0]].x - ray.origin.x) * inv_dir.x;
|
nuclear@17
|
193 float tmax = (param[1 - sign[0]].x - ray.origin.x) * inv_dir.x;
|
nuclear@17
|
194 float tymin = (param[sign[1]].y - ray.origin.y) * inv_dir.y;
|
nuclear@17
|
195 float tymax = (param[1 - sign[1]].y - ray.origin.y) * inv_dir.y;
|
nuclear@17
|
196
|
nuclear@17
|
197 if(tmin > tymax || tymin > tmax) {
|
nuclear@17
|
198 return false;
|
nuclear@17
|
199 }
|
nuclear@17
|
200 if(tymin > tmin) tmin = tymin;
|
nuclear@17
|
201 if(tymax < tmax) tmax = tymax;
|
nuclear@17
|
202
|
nuclear@17
|
203 float tzmin = (param[sign[2]].z - ray.origin.z) * inv_dir.z;
|
nuclear@17
|
204 float tzmax = (param[1 - sign[2]].z - ray.origin.z) * inv_dir.z;
|
nuclear@17
|
205
|
nuclear@17
|
206 if(tmin > tzmax || tzmin > tmax) {
|
nuclear@17
|
207 return false;
|
nuclear@17
|
208 }
|
nuclear@17
|
209 if(tzmin > tmin) tmin = tzmin;
|
nuclear@17
|
210 if(tzmax < tmax) tmax = tzmax;
|
nuclear@17
|
211
|
nuclear@17
|
212 float t = tmin < 1e-4 ? tmax : tmin;
|
nuclear@17
|
213 if(t >= 1e-4) {
|
nuclear@17
|
214 if(hit) {
|
nuclear@17
|
215 hit->dist = t;
|
nuclear@17
|
216 hit->ray = wray;
|
nuclear@17
|
217 hit->lray = ray;
|
nuclear@17
|
218 hit->obj = this;
|
nuclear@17
|
219 hit->subobj = 0;
|
nuclear@17
|
220 }
|
nuclear@17
|
221 return true;
|
nuclear@17
|
222 }
|
nuclear@17
|
223 return false;
|
nuclear@12
|
224 }
|
nuclear@17
|
225
|
nuclear@17
|
226 Vector3 Box::hit_normal(const RayHit &hit) const
|
nuclear@17
|
227 {
|
nuclear@17
|
228 Vector3 lpt = hit.lray.origin + hit.lray.dir * hit.dist;
|
nuclear@17
|
229
|
nuclear@17
|
230 if(fabs(lpt.x) > fabs(lpt.y) && fabs(lpt.x) > fabs(lpt.z)) {
|
nuclear@17
|
231 return Vector3(lpt.x, 0, 0);
|
nuclear@17
|
232 }
|
nuclear@17
|
233 if(fabs(lpt.y) > fabs(lpt.z)) {
|
nuclear@17
|
234 return Vector3(0, lpt.y, 0);
|
nuclear@17
|
235 }
|
nuclear@17
|
236 return Vector3(0, 0, lpt.z);
|
nuclear@17
|
237 }
|