15 #include "dos/gfx.h" /* for wait_vsync assembly macro */
17 void wait_vsync(void);
21 #define SPAWN_RATE 16.0f
22 /*#define GRAV (-6.0f)*/
24 #define HAIR_LENGTH 20
32 struct particle *next;
40 struct particle *plist[NSPAWNPOS];
43 static int init(void);
44 static void destroy(void);
45 static void start(long trans_time);
46 static void draw(void);
47 static void update_hairball(struct hairball *hb, float dt);
48 static void draw_hairball(struct hairball *hb);
50 static struct particle *palloc(void);
51 void pfree(struct particle *p);
54 static struct screen scr = {
62 static long start_time;
64 static float cam_theta, cam_phi = 15;
65 static float cam_dist = 8;
67 static vec3_t *spawnpos, *spawndir;
68 static struct hairball hball;
69 static struct g3d_mesh sphmesh;
71 struct screen *hairball_screen(void)
80 gen_sphere_mesh(&sphmesh, 1.0f, 12, 6);
82 hball.xform[0] = hball.xform[5] = hball.xform[10] = hball.xform[15] = 1.0f;
85 if(!(spawnpos = malloc(NSPAWNPOS * sizeof *spawnpos)) ||
86 !(spawndir = malloc(NSPAWNPOS * sizeof *spawndir))) {
87 fprintf(stderr, "failed to allocate spawnpos/dir array\n");
91 while(numpt < NSPAWNPOS) {
92 float best_dist = -1.0f;
93 for(i=0; i<100; i++) {
94 vec3_t pos = sphrand(1.0f);
96 float mindist = FLT_MAX;
97 for(j=0; j<numpt; j++) {
98 float dx = pos.x - spawnpos[j].x;
99 float dy = pos.y - spawnpos[j].y;
100 float dz = pos.z - spawnpos[j].z;
101 float dsq = dx * dx + dy * dy + dz * dz;
107 if(mindist > best_dist) {
108 spawnpos[numpt] = pos;
113 spawndir[numpt] = spawnpos[numpt];
120 static void destroy(void)
124 static void start(long trans_time)
126 g3d_matrix_mode(G3D_PROJECTION);
128 g3d_perspective(50.0, 1.33333, 0.5, 100.0);
130 start_time = time_msec;
133 static void update(void)
135 static float prev_mx, prev_my;
136 static long prev_msec;
137 int mouse_dx, mouse_dy;
138 long msec = time_msec - start_time;
139 float dt = (msec - prev_msec) / 1000.0f;
142 mouse_dx = mouse_x - prev_mx;
143 mouse_dy = mouse_y - prev_my;
149 memcpy(hball.xform, sball_matrix, 16 * sizeof(float));
151 hball.pos.x = hball.xform[12];
152 hball.pos.y = hball.xform[13];
153 hball.pos.z = hball.xform[14];
155 if(mouse_bmask & MOUSE_BN_MIDDLE) {
156 hball.pos.x += mouse_dx * 0.05;
157 hball.pos.y -= mouse_dy * 0.05;
160 quat_to_mat(hball.xform, hball.rot);
161 hball.xform[12] = hball.pos.x;
162 hball.xform[13] = hball.pos.y;
163 hball.xform[14] = hball.pos.z;
166 update_hairball(&hball, dt);
168 mouse_orbit_update(&cam_theta, &cam_phi, &cam_dist);
171 static void draw(void)
174 static unsigned long last_swap;
178 memset(fb_pixels, 0, FB_WIDTH * FB_HEIGHT * 2);
180 g3d_matrix_mode(G3D_MODELVIEW);
182 g3d_translate(0, 0, -cam_dist);
183 g3d_rotate(cam_phi, 1, 0, 0);
184 g3d_rotate(cam_theta, 0, 1, 0);
186 draw_hairball(&hball);
189 if(msec - last_swap < 16) {
195 swap_buffers(fb_pixels);
196 last_swap = get_msec();
199 static void update_hairball(struct hairball *hb, float dt)
201 int i, j, spawn_count;
202 struct particle pdummy, *prev, *p;
203 static float spawn_acc;
205 /* update particles */
206 for(i=0; i<NSPAWNPOS; i++) {
207 pdummy.next = hb->plist[i];
209 while(prev && prev->next) {
212 prev->next = p->next;
218 p->pos.x += p->vel.x * dt;
219 p->pos.y += p->vel.y * dt;
220 p->pos.z += p->vel.z * dt;
221 p->vel.y += GRAV * dt;
223 p->r = p->g = p->b = (p->life << 8) / HAIR_LENGTH - 1;
228 hb->plist[i] = pdummy.next;
231 /* spawn new particles */
233 if(spawn_acc >= (1.0f / SPAWN_RATE)) {
234 for(i=0; i<NSPAWNPOS; i++) {
235 struct particle *p = palloc();
236 float *mat = hb->xform;
237 vec3_t pos = spawnpos[i];
238 vec3_t dir = spawndir[i];
240 p->pos.x = mat[0] * pos.x + mat[4] * pos.y + mat[8] * pos.z + mat[12];
241 p->pos.y = mat[1] * pos.x + mat[5] * pos.y + mat[9] * pos.z + mat[13];
242 p->pos.z = mat[2] * pos.x + mat[6] * pos.y + mat[10] * pos.z + mat[14];
244 p->vel.x = mat[0] * dir.x + mat[4] * dir.y + mat[8] * dir.z;
245 p->vel.y = mat[1] * dir.x + mat[5] * dir.y + mat[9] * dir.z;
246 p->vel.z = mat[2] * dir.x + mat[6] * dir.y + mat[10] * dir.z;
247 p->life = HAIR_LENGTH;
249 p->next = hb->plist[i];
252 spawn_acc -= 1.0f / SPAWN_RATE;
256 static void draw_hairball(struct hairball *hb)
261 vec3_t start[NSPAWNPOS];
263 for(i=0; i<NSPAWNPOS; i++) {
264 start[i].x = hb->xform[0] * spawnpos[i].x + hb->xform[4] * spawnpos[i].y + hb->xform[8] * spawnpos[i].z + hb->xform[12];
265 start[i].y = hb->xform[1] * spawnpos[i].x + hb->xform[5] * spawnpos[i].y + hb->xform[9] * spawnpos[i].z + hb->xform[13];
266 start[i].z = hb->xform[2] * spawnpos[i].x + hb->xform[6] * spawnpos[i].y + hb->xform[10] * spawnpos[i].z + hb->xform[14];
269 g3d_begin(G3D_LINES);
270 for(i=0; i<NSPAWNPOS; i++) {
271 if(start[i].z >= hb->pos.z) continue;
275 g3d_color3b(p->r, p->g, p->b);
276 g3d_vertex(prevpos.x, prevpos.y, prevpos.z);
277 g3d_vertex(p->pos.x, p->pos.y, p->pos.z);
286 g3d_mult_matrix(hb->xform);
287 zsort_mesh(&sphmesh);
291 g3d_begin(G3D_LINES);
292 for(i=0; i<NSPAWNPOS; i++) {
293 if(start[i].z < hb->pos.z) continue;
297 g3d_color3b(p->r, p->g, p->b);
298 g3d_vertex(prevpos.x, prevpos.y, prevpos.z);
299 g3d_vertex(p->pos.x, p->pos.y, p->pos.z);
309 static struct particle *palloc(void)
311 return malloc(sizeof(struct particle));
314 void pfree(struct particle *p)