40ce53f3f9ee6f72ecac9d20dddf8f45cddd5e01
[dosdemo] / src / hairball.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include "demo.h"
5 #include "3dgfx.h"
6 #include "vmath.h"
7 #include "screen.h"
8 #include "util.h"
9
10 #define NSPAWNPOS       128
11 #define SPAWN_RATE      16.0f
12 #define GRAV            (-6.0f)
13 #define HAIR_LENGTH 32
14
15 struct particle {
16         vec3_t pos;
17         vec3_t vel;
18         float r, g, b, a;
19         int life;
20
21         struct particle *next;
22 };
23
24 struct hairball {
25         vec3_t pos;
26         quat_t rot;
27         float xform[16];
28
29         struct particle *plist[NSPAWNPOS];
30 };
31
32 static int init(void);
33 static void destroy(void);
34 static void start(long trans_time);
35 static void draw(void);
36 static void update_hairball(struct hairball *hb, float dt);
37 static void draw_hairball(struct hairball *hb);
38
39 static struct particle *palloc(void);
40 void pfree(struct particle *p);
41
42
43 static struct screen scr = {
44         "hairball",
45         init,
46         destroy,
47         start, 0,
48         draw
49 };
50
51 static long start_time;
52
53 static vec3_t *spawnpos, *spawndir;
54
55 static struct hairball hball;
56
57 struct screen *hairball_screen(void)
58 {
59         return &scr;
60 }
61
62 static int init(void)
63 {
64         int i;
65
66         hball.xform[0] = hball.xform[5] = hball.xform[10] = hball.xform[15] = 1.0f;
67         hball.rot.w = 1.0f;
68
69         if(!(spawnpos = malloc(NSPAWNPOS * sizeof *spawnpos)) ||
70                         !(spawndir = malloc(NSPAWNPOS * sizeof *spawndir))) {
71                 fprintf(stderr, "failed to allocate spawnpos/dir array\n");
72                 return -1;
73         }
74
75         for(i=0; i<NSPAWNPOS; i++) {
76                 spawnpos[i] = spawndir[i] = sphrand(1.0f);
77         }
78
79         return 0;
80 }
81
82 static void destroy(void)
83 {
84 }
85
86 static void start(long trans_time)
87 {
88         g3d_matrix_mode(G3D_PROJECTION);
89         g3d_load_identity();
90         g3d_perspective(50.0, 1.33333, 0.5, 100.0);
91
92         start_time = time_msec;
93 }
94
95 static void update(void)
96 {
97         static float prev_mx, prev_my;
98         static long prev_msec;
99         int mouse_dx, mouse_dy;
100         long msec = time_msec - start_time;
101         float dt = (msec - prev_msec) / 1000.0f;
102         prev_msec = msec;
103
104         mouse_dx = mouse_x - prev_mx;
105         mouse_dy = mouse_y - prev_my;
106         prev_mx = mouse_x;
107         prev_my = mouse_y;
108
109         if(mouse_bmask) {
110                 hball.pos.x += mouse_dx * 0.05;
111                 hball.pos.y -= mouse_dy * 0.05;
112         }
113
114         hball.rot = quat_rotate(hball.rot, dt * 2.0f, 0, 1, 0);
115
116         quat_to_mat(hball.xform, hball.rot);
117         hball.xform[12] = hball.pos.x;
118         hball.xform[13] = hball.pos.y;
119         hball.xform[14] = hball.pos.z;
120
121         update_hairball(&hball, dt);
122 }
123
124 static void draw(void)
125 {
126         update();
127
128         memset(fb_pixels, 0, fb_width * fb_height * 2);
129
130         g3d_matrix_mode(G3D_MODELVIEW);
131         g3d_load_identity();
132         g3d_translate(0, 0, -8);
133
134         draw_hairball(&hball);
135
136         swap_buffers(fb_pixels);
137 }
138
139 static void update_hairball(struct hairball *hb, float dt)
140 {
141         int i, j, spawn_count;
142         struct particle pdummy, *prev, *p;
143         static float spawn_acc;
144
145         /* update particles */
146         for(i=0; i<NSPAWNPOS; i++) {
147                 pdummy.next = hb->plist[i];
148                 prev = &pdummy;
149                 while(prev && prev->next) {
150                         p = prev->next;
151                         if(--p->life <= 0) {
152                                 prev->next = p->next;
153                                 pfree(p);
154                                 prev = prev->next;
155                                 continue;
156                         }
157
158                         p->pos.x += p->vel.x * dt;
159                         p->pos.y += p->vel.y * dt;
160                         p->pos.z += p->vel.z * dt;
161                         p->vel.y += GRAV * dt;
162                         prev = p;
163                 }
164
165                 hb->plist[i] = pdummy.next;
166         }
167
168         /* spawn new particles */
169         spawn_acc += dt;
170         if(spawn_acc >= (1.0f / SPAWN_RATE)) {
171                 for(i=0; i<NSPAWNPOS; i++) {
172                         struct particle *p = palloc();
173                         float *mat = hb->xform;
174                         vec3_t pos = spawnpos[i];
175
176                         p->pos.x = mat[0] * pos.x + mat[4] * pos.y + mat[8] * pos.z + mat[12];
177                         p->pos.y = mat[1] * pos.x + mat[5] * pos.y + mat[9] * pos.z + mat[13];
178                         p->pos.z = mat[2] * pos.x + mat[6] * pos.y + mat[10] * pos.z + mat[14];
179
180                         p->vel = spawndir[i];
181                         p->life = HAIR_LENGTH;
182                         /* TODO color */
183
184                         p->next = hb->plist[i];
185                         hb->plist[i] = p;
186                 }
187                 spawn_acc -= 1.0f / SPAWN_RATE;
188         }
189 }
190
191 static void draw_hairball(struct hairball *hb)
192 {
193         int i, j, col;
194         struct particle *p;
195         vec3_t prevpos;
196
197         g3d_begin(G3D_LINES);
198         for(i=0; i<NSPAWNPOS; i++) {
199                 p = hb->plist[i];
200                 prevpos.x = hb->xform[0] * spawnpos[i].x + hb->xform[4] * spawnpos[i].y + hb->xform[8] * spawnpos[i].z + hb->xform[12];
201                 prevpos.y = hb->xform[1] * spawnpos[i].x + hb->xform[5] * spawnpos[i].y + hb->xform[9] * spawnpos[i].z + hb->xform[13];
202                 prevpos.z = hb->xform[2] * spawnpos[i].x + hb->xform[6] * spawnpos[i].y + hb->xform[10] * spawnpos[i].z + hb->xform[14];
203
204                 j = 0;
205                 while(p) {
206                         col = 255 - j++ * (HAIR_LENGTH - 1);
207                         g3d_color3b(col, col, col);
208                         g3d_vertex(prevpos.x, prevpos.y, prevpos.z);
209                         g3d_vertex(p->pos.x, p->pos.y, p->pos.z);
210                         prevpos = p->pos;
211                         p = p->next;
212                 }
213         }
214         g3d_end();
215 }
216
217
218 static struct particle *palloc(void)
219 {
220         return malloc(sizeof(struct particle));
221 }
222
223 void pfree(struct particle *p)
224 {
225         free(p);
226 }