1 /*
2
3 Copyright (C) 2015-2018 Night Dive Studios, LLC.
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 */
19 /*
20 * $Source: r:/prj/lib/src/star/RCS/star.c $
21 * $Revision: 1.2 $
22 * $Author: buzzard $
23 * $Date: 1994/11/11 19:51:04 $
24 *
25 * Main star library source
26 *
27 * $Log: star.c $
28 * Revision 1.2 1994/11/11 19:51:04 buzzard
29 * Anti/aliasing stars in high resolutions.
30 * Ugly hacked for system shock rather than changing interface.
31 *
32 * Revision 1.1 1994/10/24 23:27:31 jaemz
33 * Initial revision
34 *
35 * Revision 1.2 1994/10/21 16:45:47 jaemz
36 * *** empty log message ***
37 *
38 * Revision 1.1 1994/09/07 17:41:29 jaemz
39 * Initial revision
40 *
41 */
42
43 #include <stdlib.h>
44 #include "star.h"
45
46 #include "OpenGL.h"
47
48 //#define STAR_SPEW
49 #define STARS_ANTI_ALIAS
50
51 #ifdef STEREO_ON
52 extern uchar g3d_stereo;
53 extern fix g3d_eyesep_raw;
54 extern uchar *g3d_rt_canv_bits;
55 extern uchar *g3d_lt_canv_bits;
56 #endif
57
58 // globals for state
59 sts_vec *std_vec;
60 uchar *std_col;
61 int std_num;
62
63 fix std_min_z = 0x7fffffff;
64 fix std_max_rad = 0;
65
66 int std_size = 1;
67
68 #ifdef STARS_ANTI_ALIAS
69 // The canvas must be more than <std_alias_size> pixels wide
70 // for us to anti-alias the stars (which makes them bigger,
71 // hence the size restriction)
72 int std_alias_size = 640;
73 // This size is chosen so anti-aliasing starts happening
74 // in full screen 640x400 modes. Won't happen in demo mode
75 // if demo mode uses a subcanvas
76
77 // We must record the meaning of the colors of stars so
78 // we can anti-alias them
79 int std_color_base, std_color_range;
80
81 // gamma-correct star colors
82 uchar std_alias_color_table[256];
83 #endif
84
85 extern g3s_vector _matrix_scale;
86 extern g3s_phandle _vbuf2;
87 extern int _n_verts;
88
89 // prototypes
90 fix mag2_point(g3s_phandle p);
91 void do_aa_star_pixel(int x, int y, int fx, int fy, int c);
92 void do_aa_star(fix fx, fix fy, int c);
93 void star_init_alias_table(void);
94
95 // sets global pointers in the star library
96 // to the number of stars, their positions, their colors
star_set(int n,sts_vec * vlist,uchar * clist)97 void star_set(int n, sts_vec *vlist, uchar *clist) {
98 std_num = n;
99 std_vec = vlist;
100 std_col = clist;
101 }
102
103 // allocates the necessary space for stars using alloc
star_alloc(int n)104 int star_alloc(int n) {
105 std_vec = (sts_vec *)malloc(n * sizeof(sts_vec) + n);
106 if (std_vec == NULL)
107 return -1;
108 std_col = (uchar *)(std_vec + n);
109 std_num = n;
110 return n;
111 }
112
113 // frees star space using free, only if you've used
114 // alloc to allocate it
star_free(void)115 void star_free(void) { free(std_vec); }
116
117 // renders star field in the polygon defined by the vertex list
118 // uses your 3d context, so make sure that's been set
119 // what we do is render a zero polygon, which is black,
120 // then render stars on that field. Beware of CLUT modes or
121 // other FILL modes. In general, will hurt this and we'll
122 // have to code around it.
123 // Then we rotate star field around viewer and draw them
124 // wherever there is black. Not dissimilar to Kevins
125 // per tmap hack
126
127 extern g3s_vector view_position;
128
129 #ifdef STAR_SPEW
130 extern int star_num_behind;
131 extern int star_num_projected;
132 #endif
133
134 // for the love of god, I hate 3d scaling.
mag2_point(g3s_phandle p)135 fix mag2_point(g3s_phandle p) {
136 fix a, f;
137
138 a = fix_div(p->gX, _matrix_scale.gX);
139 f = fix_mul(a, a);
140
141 a = fix_div(p->gY, _matrix_scale.gY);
142 f += fix_mul(a, a);
143
144 a = fix_div(p->gZ, _matrix_scale.gZ);
145 f += fix_mul(a, a);
146
147 return f;
148 }
149
150 // in stereo mode, we can leave this normal
151 // and it should work, assuming the two
152 // polygons are similar enough
star_poly(int n,g3s_phandle * vp)153 void star_poly(int n, g3s_phandle *vp) {
154 if(use_opengl()) {
155 // Stencil out this area where we want stars to draw
156 opengl_set_stencil(0xFF);
157 opengl_draw_poly(0x00, n, vp, 0);
158 opengl_set_stencil(0x00);
159 }
160 else {
161 // draw star poly in color zero (note that 255 is hacked black). This part very
162 // important, if not zero, won't work.
163 g3_draw_poly(0xff, n, vp);
164 }
165
166 star_empty(n, vp); //fix disappearing stars; std_min_z was not being set below its max value,
167 //which caused star_render() to abort
168 }
169
star_empty(int n,g3s_phandle * vp)170 void star_empty(int n, g3s_phandle *vp) {
171 int i;
172 fix m;
173 int n1;
174 g3s_phandle dest[10]; // assume max clip 10
175
176 // clip it just like you would when you render
177 // then run through it
178 // set max out the maximum it could be, which would be eyesep raw
179 n1 = g3_clip_polygon(n, vp, dest);
180 for (i = 0; i < n1; ++i) {
181 if (dest[i]->gZ < std_min_z)
182 std_min_z = dest[i]->gZ;
183 m = mag2_point(dest[i]);
184 if (m > std_max_rad)
185 std_max_rad = m;
186 }
187 }
188
189 // render stars to a sky-like thing,
190 // no viewports, clips to half sphere
star_sky(void)191 void star_sky(void) {
192 std_min_z = 0;
193 std_max_rad = FIX_UNIT;
194 }
195
196 #ifdef STARS_ANTI_ALIAS
197 // render a single pixel of an anti-aliased star
do_aa_star_pixel(int x,int y,int fx,int fy,int c)198 void do_aa_star_pixel(int x, int y, int fx, int fy, int c) {
199 int q;
200
201 if (gr_get_pixel(x, y) == 0xff) {
202 q = fx * fy * c;
203
204 // fx is % 0..256; fy is % 0..256; c is % 0..255.
205
206 q = q >> 16;
207
208 // q is now 0..255, which we rescale back into color range
209
210 gr_set_pixel(std_alias_color_table[q], x, y);
211 }
212 }
213
214 // render an anti-aliased star.
215 // this is a prime candidate for being made table driven
do_aa_star(fix fx,fix fy,int c)216 void do_aa_star(fix fx, fix fy, int c) {
217 // isolate the fractions and the integers
218 int x_frac = fix_frac(fx) >> 8;
219 int y_frac = fix_frac(fy) >> 8;
220 int x = fix_int(fx);
221 int y = fix_int(fy);
222
223 int color = (std_color_base + std_color_range - 1 - c);
224
225 // rescale the color so that it's 0..255, 0 = dark, 255 = light
226 color = (255 * color) / (std_color_range + 1);
227
228 // ok, now compute the weightings for each pixel
229
230 do_aa_star_pixel(x, y, 256 - x_frac, 256 - y_frac, color);
231 do_aa_star_pixel(x + 1, y, x_frac, 256 - y_frac, color);
232 do_aa_star_pixel(x, y + 1, 256 - x_frac, y_frac, color);
233 do_aa_star_pixel(x + 1, y + 1, x_frac, y_frac, color);
234 }
235
star_init_alias_table(void)236 void star_init_alias_table(void) {
237 // init gamma corrected table
238 int i, a;
239 fix b, gamma;
240
241 gamma = fix_make(0, 30000);
242
243 a = std_color_base + std_color_range - 1;
244 b = fix_make(-(std_color_range - 1), 0);
245
246 for (i = 0; i < 256; ++i)
247 std_alias_color_table[i] = a + fix_int(fix_mul(b, fix_pow(fix_make(i, 0) / 255, gamma)));
248 }
249
250 #endif
251
star_render(void)252 void star_render(void) {
253 int i;
254 g3s_phandle s;
255 int x, y;
256 int x1, y1;
257 g3s_vector v;
258 #ifdef STEREO_ON
259 uchar old_stereo;
260 #endif
261 #ifdef STARS_ANTI_ALIAS
262 int anti_alias = grd_bm.w >= std_alias_size;
263 #endif
264
265 #ifdef STAR_SPEW
266 star_num_behind = 0;
267 star_num_projected = 0;
268 #endif
269
270 #if defined(STARS_ANTI_ALIAS) && defined(STEREO_ON)
271 if (g3d_stereo)
272 anti_alias = 0;
273 #endif
274
275 // exit if no one every drew a star field anywhere visible
276 if (std_min_z == 0x7fffffff) {
277 #ifdef STAR_SPEW
278 mprintf("ignored\n");
279 #endif
280 return;
281 }
282
283 if(use_opengl()) {
284 opengl_begin_stars();
285 }
286
287 #ifdef STAR_SPEW
288 mprintf("max_rad = %x min_z = %x\n", fix_sqrt(star_max_rad), star_min_z);
289 #endif
290 if (std_min_z < 0)
291 std_min_z = 0;
292
293 // scale by max radius
294 #ifndef STEREO_ON
295 g3_scale_object(fix_sqrt(std_max_rad));
296 #else
297 // add in eyesep raw cause that's as much bigger it could be
298 g3_scale_object(fix_sqrt(std_max_rad) + (g3d_stereo ? g3d_eyesep_raw : 0));
299 #endif
300
301 #ifdef STEREO_ON
302 old_stereo = g3d_stereo;
303 g3d_stereo = 0;
304 #endif
305
306 for (i = 0; i < std_num; ++i) {
307 // in theory if codes aren't set it's on the screen
308
309 // unpack star vec to a normal vec
310 v.gX = ((fix)std_vec[i].x) << 1;
311 v.gY = ((fix)std_vec[i].y) << 1;
312 v.gZ = ((fix)std_vec[i].z) << 1;
313
314 s = star_transform_point(&v);
315
316 if (s->codes == 0) {
317 x = fix_rint(s->sx);
318 y = fix_rint(s->sy);
319
320 if(use_opengl()) {
321 opengl_draw_star(s->sx, s->sy, std_col[i], anti_alias);
322 continue;
323 }
324
325 if (std_size <= 1) {
326 #ifdef STARS_ANTI_ALIAS
327 if (anti_alias) {
328 do_aa_star(s->sx, s->sy, std_col[i]);
329 } else
330 #endif
331 if (gr_get_pixel(x, y) == 0xff)
332 gr_set_pixel(std_col[i], x, y);
333 } else {
334 for (x1 = x; x1 < x + std_size; ++x1) {
335 for (y1 = y; y1 < y + std_size; ++y1) {
336 if (gr_get_pixel(x1, y1) == 0xff)
337 gr_set_pixel(std_col[i], x1, y1);
338 }
339 }
340 }
341
342 #ifdef STEREO_ON
343 if (old_stereo) {
344 // switch canvases quickly
345 grd_bm.bits = g3d_rt_canv_bits;
346 if (std_size <= 1) {
347 if (gr_get_pixel(x, y) == 0xff)
348 gr_set_pixel(std_col[i], x, y);
349 } else {
350 for (x1 = x; x1 < x + std_size; ++x1) {
351 for (y1 = y; y1 < y + std_size; ++y1) {
352 if (gr_get_pixel(x1, y1) == 0xff)
353 gr_set_pixel(std_col[i], x1, y1);
354 }
355 }
356 }
357 // switch back
358 grd_bm.bits = g3d_lt_canv_bits;
359 }
360 #endif
361 }
362
363 g3_free_point(s);
364 }
365
366 if(use_opengl()) {
367 opengl_end_stars();
368 }
369
370 #ifdef STEREO_ON
371 g3d_stereo = old_stereo;
372 #endif
373
374 #ifdef STAR_SPEW
375 mprintf("stars = %d behind = %d proj = %d\n", st_num, star_num_behind, star_num_projected);
376 #endif
377
378 // reset min z and max rad
379 std_min_z = 0x7fffffff;
380 std_max_rad = 0;
381 }
382
383 // stuffs random vectors and colors into the set areas
384 // randomly assigning a color range to them
385 // feel free to seed
star_rand(uchar col,uchar range)386 void star_rand(uchar col, uchar range) {
387 int i;
388 g3s_vector v;
389 sts_vec *s;
390 fix m;
391
392 #ifdef STARS_ANTI_ALIAS
393 // SYSTEM SHOCK HACK!
394 std_color_base = 208; // col;
395 std_color_range = 16; // range;
396
397 star_init_alias_table();
398 #endif
399
400 for (i = 0; i < std_num; ++i) {
401 s = &std_vec[i];
402
403 v.gX = ((rand() % 4000) - 2000) << 8;
404 v.gY = ((rand() % 4000) - 2000) << 8;
405 v.gZ = ((rand() % 4000) - 2000) << 8;
406
407 m = fix_mul(v.gX, v.gX) + fix_mul(v.gY, v.gY) + fix_mul(v.gZ, v.gZ);
408
409 if (m < FIX_UNIT / 100) {
410 i = i - 1;
411 continue;
412 }
413
414 m = fix_sqrt(m);
415
416 // normalize for fun hack
417 v.gX = fix_div(v.gX, m);
418 v.gY = fix_div(v.gY, m);
419 v.gZ = fix_div(v.gZ, m);
420
421 // put into star vec
422 s->x = (v.gX >> 1);
423 s->y = (v.gY >> 1);
424 s->z = (v.gZ >> 1);
425
426 // assign color
427 std_col[i] = rand() % range + col;
428 }
429 }
430
431 extern g3s_point *first_free;
432 extern g3s_matrix view_matrix;
433 extern int code_point(g3s_point *pt);
434
435 // matrix rotate and code a star point. Project if clip codes
436 // are not set, rotate fully if in front of viewer
437 // (or smaller than a boundary
438 // takes pointer to vector
439 // returns point
star_transform_point(g3s_vector * v)440 g3s_phandle star_transform_point(g3s_vector *v) {
441 g3s_point *point;
442 int64_t r;
443 fix temp;
444
445 getpnt(point);
446 point->p3_flags = 0;
447
448 // third column (z)
449 r = fix64_mul(v->gX, vm3) + fix64_mul(v->gY, vm6) + fix64_mul(v->gZ, vm9);
450 temp = fix64_to_fix(r);
451
452 // check out z, see if behind
453 if (temp < std_min_z) {
454 point->codes = CC_BEHIND;
455 return (point);
456 }
457
458 point->gZ = temp; // save z
459
460 // first column (x)
461 r = fix64_mul(v->gX, vm1) + fix64_mul(v->gY, vm4) + fix64_mul(v->gZ, vm7);
462 point->gX = fix64_to_fix(r);
463
464 // second column (y)
465 r = fix64_mul(v->gX, vm2) + fix64_mul(v->gY, vm5) + fix64_mul(v->gZ, vm8);
466 point->gY = fix64_to_fix(r);
467
468 // call clip codes
469 if (code_point(point))
470 return (point);
471
472 // transform if not clipped
473 g3_project_point(point);
474 return (point);
475 }
476