1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: r_sky.c 1560 2020-11-25 12:34:46Z wesleyjohnson $
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 // Portions Copyright (C) 1998-2000 by DooM Legacy Team.
8 //
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License
11 // as published by the Free Software Foundation; either version 2
12 // of the License, or (at your option) any later version.
13 //
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
18 //
19 //
20 // $Log: r_sky.c,v $
21 // Revision 1.8 2001/08/06 23:57:09 stroggonmeth
22 // Removed portal code, improved 3D floors in hardware mode.
23 //
24 // Revision 1.7 2001/04/02 18:54:32 bpereira
25 //
26 // Revision 1.6 2001/03/21 18:24:39 stroggonmeth
27 // Misc changes and fixes. Code cleanup
28 //
29 // Revision 1.5 2001/03/13 22:14:20 stroggonmeth
30 // Long time no commit. 3D floors, FraggleScript, portals, ect.
31 //
32 // Revision 1.4 2001/01/25 22:15:44 bpereira
33 // added heretic support
34 //
35 // Revision 1.3 2000/09/21 16:45:08 bpereira
36 // Revision 1.2 2000/02/27 00:42:10 hurdler
37 // Revision 1.1.1.1 2000/02/22 20:32:32 hurdler
38 // Initial import into CVS (v1.29 pr3)
39 //
40 //
41 // DESCRIPTION:
42 // Sky rendering. The DOOM sky is a texture map like any
43 // wall, wrapping around. A 1024 columns equal 360 degrees.
44 // The default sky map is 256 columns and repeats 4 times
45 // on a 320 screen?
46 //
47 //
48 //-----------------------------------------------------------------------------
49
50 #include "doomincl.h"
51 #include "r_local.h"
52 #include "w_wad.h"
53 #include "z_zone.h"
54
55 #include "p_maputl.h"
56 // P_PointOnLineSide
57 #include "m_swap.h"
58 #include "r_sky.h"
59
60 #include "m_random.h"
61 #include "v_video.h"
62
63
64 // SoM: I know I should be moving portals out of r_sky.c and as soon
65 // as I have time and a I will... But for now, they are mostly used
66 // for sky boxes anyway so they have a mostly appropriate home here.
67
68 void sky_gen_OnChange( void );
69
70 CV_PossibleValue_t skygen_cons_t[] = {
71 {0, "auto"}, {1,"subst"}, {10, "bg_stars" }, {11,"extend_stars"}, {12,"extend_bg"}, {13,"extend_fill"},
72 {248,"vanilla"}, {250,"stretch"}, {0,NULL} };
73 consvar_t cv_sky_gen = {"skygen", "auto", CV_SAVE|CV_CALL, skygen_cons_t, sky_gen_OnChange };
74
sky_gen_OnChange(void)75 void sky_gen_OnChange( void )
76 {
77 if( sky_texture )
78 {
79 R_Setup_SkyDraw();
80 R_Set_Sky_Scale();
81 }
82 }
83
84 //
85 // sky mapping
86 //
87 int sky_texture = 0;
88
89 // sky drawing
90 int sky_flatnum; // to detect sectors with sky
91 byte * sky_pict = NULL; // ZMalloc, PU_STATIC
92 // TM_picture format, columofs, column image
93 int sky_texturemid;
94 fixed_t sky_scale;
95 uint32_t sky_widthmask = 0;
96 int sky_height=128;
97 int sky_yh_max_oc, sky_yl_min_oc; // sky limits
98 byte sky_240=0; // 0=std 128 sky, 1=240 high sky
99
100 byte skytop_flat[SKY_FLAT_WIDTH][SKY_FLAT_HEIGHT]; // above sky
101 byte ground_flat[SKY_FLAT_WIDTH][SKY_FLAT_HEIGHT]; // below sky
102
103
104 // Sample the sky, setup the skytop_flat or ground_flat.
set_sky_flat(byte * sflat,byte * srcp,byte sample_y,int sample_width,int sample_height)105 void set_sky_flat( byte * sflat, byte * srcp, byte sample_y, int sample_width, int sample_height )
106 {
107 #if 0
108 // A pattern just looks like vertical wall.
109 // Sample the sky
110 int i;
111 for( i=0; i<(SKY_FLAT_WIDTH*SKY_FLAT_HEIGHT); i++ )
112 {
113 int rx = E_Random() % sample_width;
114 int ry = sample_y + (E_Random() % sample_height );
115 sflat[i] = srcp[ (rx * sky_height) + ry ];
116 }
117 #endif
118 #if 1
119 // Make a solid average color.
120 int r = 0, g = 0, b = 0;
121 int i;
122 for( i=0; i<32; i++ )
123 {
124 int rx = E_Random() % sample_width;
125 int ry = sample_y + (E_Random() % sample_height );
126 byte c1 = srcp[ (rx * sky_height) + ry ];
127 RGBA_t p = pLocalPalette[c1];
128 r += p.s.red;
129 g += p.s.green;
130 b += p.s.blue;
131 }
132 byte solid_color = NearestColor( r/32, g/32, b/32 );
133 memset( sflat, solid_color, (SKY_FLAT_WIDTH*SKY_FLAT_HEIGHT) );
134 #endif
135 #if 0
136 // Pick the most used color.
137 int hist[256];
138 int max_hist = 0;
139 int i;
140 byte solid_color;
141 memset( hist, 0, 256 );
142 for( i=0; i<256; i++ )
143 {
144 int rx = E_Random() % sample_width;
145 int ry = sample_y + (E_Random() % sample_height );
146 byte c1 = srcp[ (rx * sky_height) + ry ];
147 hist[c1]++;
148 if( hist[c1] > max_hist )
149 {
150 max_hist = hist[c1];
151 solid_color = c1;
152 }
153 }
154 memset( sflat, solid_color, (SKY_FLAT_WIDTH*SKY_FLAT_HEIGHT) );
155 #endif
156 }
157
158
159 #define SKY_WIDTH 1024
160 #define SKY_HEIGHT 240
161 #define SKY_HORIZON_OFFSET 12
162
163 typedef struct{
164 uint32_t colofs[ SKY_WIDTH ];
165 } pic_header_t;
166
167 static
dark_pixel(byte c)168 byte dark_pixel( byte c )
169 {
170 RGBA_t rc = pLocalPalette[ c ];
171 return( rc.s.red < 2 && rc.s.green < 2 && rc.s.blue < 2 );
172 }
173
174 static
sample_sky(int r1,int dr,int tw,int twm,byte buf[SKY_WIDTH][SKY_HEIGHT],byte background_color,byte stargen)175 void sample_sky( int r1, int dr, int tw, int twm, byte buf[SKY_WIDTH][SKY_HEIGHT], byte background_color, byte stargen )
176 {
177 int c;
178 byte pix;
179 for( c=0; c < tw; c++ )
180 {
181 if( buf[c][r1] != background_color ) continue;
182
183 int c3 = (c + E_SignedRandom( 21 )) & twm;
184 int r3 = r1 + 1 + ((E_Random() * dr) >> 16);
185 pix = buf[c3][r3];
186 if( stargen && ! dark_pixel(pix) )
187 {
188 byte cn = 15;
189 while( cn-- )
190 {
191 // Find a star, surrounded by dark.
192 if( ( dark_pixel( buf[(c3-1)&twm][r3] )
193 + dark_pixel( buf[(c3+1)&twm][r3] )
194 + dark_pixel( buf[(c3)&twm][r3-1] )
195 + dark_pixel( buf[(c3)&twm][r3+1] ) ) > 2 ) break;
196 c3 += 27;
197 pix = buf[c3&twm][r3];
198 }
199 }
200 buf[c][r1] = pix;
201 }
202 }
203
204
205 // r : percentage of op1 to op2
206 static
proportion(float op1,float op2,float r)207 float proportion( float op1, float op2, float r )
208 {
209 return (op1 * r) + (op2 * (1.0f - r));
210 }
211
212 //#define DEBUG_SLOPE
213 // pixel : the solid pixel
214 // c1, r1 : where
215 // edgeinc : -1 left edge of solid, +1 for right edge
216 // rinc : +1 for top, -1 for bottom
217 // twm : mask for c
218 // buf : the draw buffer
219 // reg_slope : regular slope, as a guide
220 // max_slope : maximum
221 // pinch_inc : which way and how strongly to pinch slopes together
222 // solid_width : width of the solid area
223 static
edge_by_slope(byte pixel,int c1,int r1,int edgeinc,int rinc,unsigned int twm,byte buf[SKY_WIDTH][SKY_HEIGHT],float reg_slope,float max_slope,float pinch_inc,int solid_width)224 int edge_by_slope( byte pixel, int c1, int r1, int edgeinc, int rinc, unsigned int twm, byte buf[SKY_WIDTH][SKY_HEIGHT], float reg_slope, float max_slope, float pinch_inc, int solid_width )
225 {
226 float accum_slope = 0.0;
227 float slope = 0;
228 int accum_cnt = 0;
229 int c, r4, c4;
230 int cinc = edgeinc; // left has outside to the -1 direction
231 byte inside = 0; // do outside first
232 byte max_inside_depth = 0;
233 byte dep;
234
235 // Assert pixel == buf[c1][r1]
236
237 // Bidirectional loop
238 for( c = c1+cinc; ; c += cinc )
239 {
240 c4 = c & twm;
241 r4 = r1; // first pixel
242
243 if( inside == 0 )
244 {
245 // Assert buf[c4][r1] != pixel
246 for( dep = 1; dep < 17; dep++ )
247 {
248 r4 -= rinc; // previous rows
249 if( buf[c4][r4] == pixel ) break;
250 }
251 if( dep >= 16 ) c = 0x7FFF; // end of pixel solid
252 }
253 else
254 {
255 // inside
256 if( buf[c4][r1] != pixel ) break; // end of pixel solid
257 // find depth of last matching pixel
258 for( dep = 0; dep < 16; dep++ )
259 {
260 r4 -= rinc; // previous rows
261 if( buf[c4][r4] != pixel ) break;
262 }
263 // Need the max_inside_depth for pinch calc,
264 // but should avoid including the opposite edge of the solid.
265 if( dep > max_inside_depth ) // dep should be increasing
266 max_inside_depth = dep;
267 else
268 dep = 0; // probably the opposite edge
269 }
270
271 if( (dep > 0) && (dep < 16) )
272 {
273 // avg the slopes, weighted by their dep
274 accum_slope += (float)(c - c1); // ((c-c1) / dep) * dep
275 accum_cnt += dep;
276 }
277
278 if(( c <= c1-16 ) || ( c >= c1+16 ))
279 {
280 if( inside ) break;
281 // switch to the inside, and the other direction
282 inside = 1;
283 cinc = -cinc;
284 c = c1;
285 }
286 }
287
288 // column per row, slope = 0 is straight up, neg towards neg c.
289 if( accum_cnt )
290 {
291 slope = (accum_slope / accum_cnt);
292 }
293 else
294 {
295 // choose a random slope; there is no slope sign
296 slope = E_SignedRandom(2048) * (2.0f/2048) * reg_slope; // 0 to 2*reg_slope
297 }
298
299 // Use E_Random because it does not repeat within buf size.
300 int er = E_Random();
301 float signed_reg_slope = (slope < 0)? -reg_slope : reg_slope;
302
303 if( fabs(slope) < 0.4f )
304 {
305 // random slope, near 0 to signed_reg_slope/2
306 slope = (er + 0x3000) * (0.45f/0xFFFF) * signed_reg_slope;
307 }
308 else if( er > 0xCC13 )
309 {
310 slope = proportion( signed_reg_slope, slope, 0.150f );
311 }
312
313 slope += E_SignedRandom(1024) * (1.27f/1024);
314
315 // Pinch as function of depth inside.
316 if( solid_width < 1 ) solid_width = 1;
317 float pinch_strength = pinch_inc * 0.058f / solid_width;
318 slope += pinch_strength * max_inside_depth; // pinch inwards
319
320 if( fabs(slope) > max_slope )
321 {
322 er = E_Random();
323
324 if( ((edgeinc * slope) > 0) && ( er < 0x2BFF ))
325 {
326 // Flip slope direction
327 slope = -slope * 0.980f;
328 }
329
330 // Apply some reg_slope.
331 slope = proportion( reg_slope, slope, ((er * (0.8f/0xFFFF)) + 0.1f) );
332
333 if( slope > max_slope ) slope = max_slope - (er * (2.0f/0xFFFF));
334 else if( slope < -max_slope ) slope = -max_slope + (er * (2.0f/0xFFFF));
335 }
336
337 return (int)(c1 + slope + 0.5f);
338 }
339
340
341
342 typedef enum {
343 BE_none,
344 BE_greater,
345 BE_less,
346 BE_adhere
347 } blob_edge_e;
348
349 typedef struct {
350 int c1, c2; // first and last columns
351 byte solid_color;
352 byte speck;
353 byte importance;
354 int16_t sb_left, sb_right; // index sbp
355 int16_t sb_enclosure; // enclosing sky_blob
356 byte has_enclosed;
357 byte left_adj, right_adj;
358 } sky_blob_t;
359
360 static
init_sky_blob(sky_blob_t * sbp)361 void init_sky_blob( sky_blob_t * sbp )
362 {
363 sbp->c1 = 0;
364 sbp->c2 = 0;
365 sbp->speck = 0;
366 sbp->left_adj = BE_none;
367 sbp->right_adj = BE_none;
368 sbp->sb_left = -1;
369 sbp->sb_right = -1;
370 sbp->has_enclosed = 0;
371 sbp->sb_enclosure = -1;
372 sbp->importance = 1;
373 }
374
375
376 // Generate large sky.
377 // [WDJ] Must do this into a temp texture, or else it recursively modifies the sky with each level.
R_Generate_Sky(int texnum)378 byte * R_Generate_Sky( int texnum )
379 {
380 texture_t * texture = textures[texnum]; // texture info from wad
381 byte buf[SKY_WIDTH][SKY_HEIGHT]; // buf of composite sky, column oriented
382
383 #define HIST_DEPTH 8
384 unsigned int sky_hist[256], gnd_hist[256];
385 unsigned int hist_total;
386 unsigned int sky_dark_cnt = 0, gnd_dark_cnt = 0;
387 int th, tw;
388 unsigned int twm; // width mask
389 int sky_top_align, sky_bottom_align, sky_horizon, sl_horizon;
390 // int pixel_cnt;
391 int r, c;
392 int c1, c2, c3, c4, r1, r2, r3;
393 byte background_color = 0;
394 byte sky_color = 0;
395 byte ground_color = 0;
396 byte en_background_transparent;
397 byte night_stars_upper = 0;
398 byte night_stars_lower = 0;
399
400 // Blob building
401 #define MAX_SKY_BLOB SKY_WIDTH
402 sky_blob_t sky_blob[ MAX_SKY_BLOB ];
403 sky_blob_t * sbp, * sbp2, * sbp3, * sbp4;
404 sky_blob_t * last_sbp;
405
406 int rinc;
407 int row1, row2;
408 // int num_rows;
409 int speck_per;
410
411 float reg_slope, max_slope, per;
412 byte c_pixel, solid_pixel, write_pixel;
413 byte db;
414
415
416 // This puts ptr in texren->cache
417 pic_header_t * sky_pic = (pic_header_t*) R_GenerateTexture2( texnum, & texture_render[texnum], TM_picture );
418
419 th = texture->height; // should be 128
420 tw = texture->width; // 256, 512, or 1024
421 // Requiem has SKY1 width 1024.
422 if( tw > SKY_WIDTH ) tw = SKY_WIDTH;
423
424 // tw must be a power of 2.
425 twm = tw-1;
426
427 sky_top_align = SKY_HEIGHT - SKY_HORIZON_OFFSET - th;
428 if( sky_top_align < 0 ) sky_top_align = 0;
429 sky_bottom_align = sky_top_align + th;
430 if( sky_bottom_align > SKY_HEIGHT ) sky_bottom_align = SKY_HEIGHT;
431 sky_horizon = sky_bottom_align - SKY_HORIZON_OFFSET;
432
433 // Histogram of the sky top 16 rows.
434 memset( sky_hist, 0, 256 * sizeof(int) );
435 memset( gnd_hist, 0, 256 * sizeof(int) );
436
437 // Note: The sky is displayed reversed left to right,
438 // so increasing c is to the left.
439 // Find background and ground color
440 int bs = 0, bg = 0;
441 for( c=0; c<tw; c++ )
442 {
443 // R_GenerateTexture gives it TM_picture format.
444 byte * p = (byte*)sky_pic + sky_pic->colofs[ c ];
445 memcpy( &buf[c][sky_top_align], p, th ); // copy sky to buf
446
447 // Detect night sky upper,lower, and histogram.
448 for( r=0; r<HIST_DEPTH; r++ )
449 {
450 byte pix = buf[c][sky_top_align+r];
451 int hc = ++sky_hist[pix]; // count pixel colors
452 if( hc > bs ) // largest hist
453 {
454 bs = hc;
455 sky_color = pix;
456 }
457 if( dark_pixel(pix) ) sky_dark_cnt++;
458
459 pix = buf[c][sky_bottom_align-1-r];
460 hc = ++gnd_hist[pix]; // count pixel colors
461 if( hc > bg ) // largest hist
462 {
463 bg = hc;
464 ground_color = pix;
465 }
466 if( dark_pixel(pix) ) gnd_dark_cnt++;
467 }
468 }
469 hist_total = tw * HIST_DEPTH;
470
471 if( sky_dark_cnt > (hist_total * 4 / 7) )
472 {
473 night_stars_upper = 1;
474 }
475
476 if( gnd_dark_cnt > (hist_total * 4 / 7) )
477 {
478 night_stars_lower = 1;
479 }
480
481 sl_horizon = sky_top_align / 2;
482
483 if(cv_sky_gen.EV == 10) // bg_stars
484 {
485 en_background_transparent = 1;
486 sl_horizon = sky_horizon;
487 }
488 else if(cv_sky_gen.EV == 11) // extend_stars
489 {
490 // en_background_transparent = 1;
491 sl_horizon = sky_top_align * 4 / 5;
492 // sky_color = ci_black;
493 }
494 else if(cv_sky_gen.EV == 12) // extend_bg
495 {
496 en_background_transparent = 1;
497 sl_horizon = sky_top_align / 2;
498 }
499
500 #if 0
501 if( night_stars_upper || (cv_sky_gen.EV == 11))
502 {
503 // This color is detected as transparent.
504 sky_color = ci_black;
505 }
506
507 if( night_stars_lower )
508 {
509 ground_color = ci_black;
510 }
511 #endif
512
513 for( c1=0; c1 < tw; c1++ )
514 {
515 // set to solid background color
516 memset( &buf[c1][0], sky_color, sky_top_align );
517 memset( &buf[c1][sky_bottom_align], ground_color, SKY_HEIGHT - sky_bottom_align );
518 }
519
520 if( night_stars_upper && night_stars_lower ) goto generate_backgrounds;
521
522 // Note: buf is circular. Do previous row setup first.
523 // Upper sky values.
524 background_color = sky_color;
525 row1 = sky_top_align;
526 row2 = 0;
527 // num_rows = sky_top_align;
528 rinc = -1;
529
530 for(;;)
531 {
532 // Blob building
533 sbp = & sky_blob[0];
534 init_sky_blob( sbp );
535 solid_pixel = buf[0][row1];
536 sbp->c1 = 0;
537 sbp->solid_color = solid_pixel;
538
539 // Initial scan of row1.
540 // Positive c is to the right, but display is reversed.
541 for( c1 = 1; c1<tw; c1++ )
542 {
543 // Find trailing edge of each solid
544 c_pixel = buf[c1][row1];
545 if( c_pixel == solid_pixel ) continue;
546
547 if( buf[(c1+1)&twm][row1] == solid_pixel )
548 {
549 sbp->speck++;
550 continue;
551 }
552
553 // Record blob info.
554 sbp->c2 = c1-1;
555 sbp->importance = 1;
556
557 // Do not cross background blobs.
558 if( solid_pixel == background_color ) goto next_blob;
559
560 // check for blob in blob
561 c4 = c1 - (tw/4);
562 for( sbp2 = & sbp[-1]; sbp2 >= &sky_blob[0]; sbp2-- )
563 {
564 if( sbp2->solid_color == background_color ) break;
565 if( sbp2->importance < 1 ) break;
566 if( sbp2->c1 < c4 ) break; // too large a structure
567
568 // This does produce overlapping enclosures,
569 // but those make for an interesting sky feature.
570 if( sbp2->solid_color == solid_pixel )
571 {
572 int sb2id = sbp2 - &sky_blob[0];
573 // part of larger blob, enclosing a smaller blob
574 sbp2->c2 = c1-1;
575 sbp2->importance++;
576
577 // linking
578 sbp3 = NULL; // default, sb2 has no enclosures
579 // traverse interior blobs
580 for( sbp4 = sbp2+1; sbp4 < sbp; sbp4++ )
581 {
582 if( sbp4->sb_enclosure == sb2id )
583 {
584 sbp3 = sbp4;
585 }
586 else if( sbp4->sb_enclosure < 0 ) // an unlinked blob
587 {
588 // enclose it in sbp2
589 sbp4->sb_enclosure = sb2id; // enclosed by sbp2
590 if( sbp3 )
591 {
592 int sb3id = sbp3 - &sky_blob[0];
593 sbp4->sb_left = sb3id;
594 }
595 else
596 {
597 sbp4->sb_left = -1; // first
598 }
599 sbp2->has_enclosed = 1;
600 sbp3 = sbp4;
601 }
602 } // traverse interior blobs
603 sbp--; // was merged
604 break;
605 } // solid_color == solid_pixel
606 } // for sbp2, blob in blob
607
608 next_blob:
609 // next blob
610 sbp++;
611 init_sky_blob( sbp );
612 solid_pixel = c_pixel;
613 sbp->solid_color = c_pixel;
614 sbp->c1 = c1;
615 int sbid = sbp - &sky_blob[0];
616 sbp->sb_left = sbid - 1;
617 }
618 sbp->c2 = tw-1;
619 sbp->importance = 1;
620
621 // Wrap the sky
622 if((sbp > &sky_blob[0]) && (sbp->solid_color == sky_blob[0].solid_color) )
623 {
624 // sky wraps, merge first and last
625 sky_blob[0].c1 = sbp->c1 - tw;
626 sky_blob[0].sb_left = sbp->sb_left;
627 sbp--;
628 }
629 last_sbp = sbp;
630
631 // fix right associations
632 for( sbp = &sky_blob[0]; ; sbp++ )
633 {
634 if( sbp->sb_left >= 0 )
635 sky_blob[ sbp->sb_left ].sb_right = sbp - &sky_blob[0];
636
637 if( sbp >= last_sbp ) break;
638 }
639
640 // Draw
641 for( r1 = row1 + rinc; ; r1+=rinc )
642 {
643 r3 = r1 - rinc; // prev row
644 if( rinc < 0 )
645 { // upper
646 if( r1 < row2 ) break;
647 per = (float)r1 / sky_horizon;
648 }
649 else
650 { // lower
651 if( r1 > row2 ) break;
652 per = (float)(SKY_HEIGHT - r1) / (SKY_HEIGHT - sky_horizon);
653 }
654 // per goes to 0 as nears viewer
655 reg_slope = proportion( 6.0f, 1.95f, per );
656 max_slope = proportion( 13.0f, 4.00f, per );
657
658 for( sbp = & sky_blob[0]; sbp <= last_sbp; sbp++ )
659 {
660 if( sbp->importance < 1 ) continue;
661
662 solid_pixel = sbp->solid_color;
663 if( (solid_pixel == background_color) && en_background_transparent )
664 {
665 // background has already been filled in and there is no overwrite needed
666 continue;
667 }
668
669 c1 = sbp->c1;
670 c2 = sbp->c2;
671
672 if(( c1 > c2 ) && (c1 > (3*SKY_WIDTH/4)) && (c2 < (SKY_WIDTH/4)) )
673 c1 -= SKY_WIDTH; // wrap
674
675 if( sbp->sb_enclosure >= 0 )
676 {
677 sbp2 = & sky_blob[ sbp->sb_enclosure ];
678
679 int c5 = sbp2->c1;
680 int c6 = sbp2->c2;
681
682 if( c5 > c2 && (c5 > (3*SKY_WIDTH/4)) )
683 {
684 c5 -= SKY_WIDTH;
685 c6 -= SKY_WIDTH;
686 }
687 else if( c6 < c1 && (c6 < (SKY_WIDTH/4)) )
688 {
689 c5 += SKY_WIDTH;
690 c6 += SKY_WIDTH;
691 }
692
693 if( c1 <= c5 )
694 {
695 c1 = c5 + 1;
696 }
697 if( c2 >= c6 )
698 {
699 c2 = c6 - 1;
700 }
701 }
702
703 // negative pinch when above sl_horizon
704 int width = c2 - c1 + 1;
705 if( width < 1 )
706 {
707 sbp->importance = 0;
708 continue;
709 }
710
711 c3 = edge_by_slope( solid_pixel, c1, r1, 1, rinc, twm, buf, reg_slope, max_slope, (r1 - sl_horizon), (c2 - c1 + 1) );
712 c4 = edge_by_slope( solid_pixel, c2, r1, -1, rinc, twm, buf, reg_slope, max_slope, (sl_horizon - r1), (c2 - c1 + 1) );
713
714 if(( c3 > c4 ) && (c3 > (3*SKY_WIDTH/4)) && (c4 < (SKY_WIDTH/4)) )
715 c3 -= SKY_WIDTH; // wrap
716
717 sbp->c1 = c3;
718 sbp->c2 = c4;
719
720 if( c3 >= c4 )
721 {
722 sbp->importance = 0;
723 continue;
724 }
725
726 speck_per = sbp->speck / (c4 - c3);
727 if( speck_per > 250 ) speck_per = 250;
728
729 db = (buf[c3&twm][r3] != solid_pixel) ? 2 : 0;
730
731 // stripe write
732 for( c = c3; c <= c4; c++ )
733 {
734 byte rn = E_Random();
735
736 write_pixel = solid_pixel;
737 if( (c < c4) && (buf[(c+1)&twm][r3] != solid_pixel) ) db |= 4;
738
739 if( db )
740 {
741 db >>= 1;
742 if( rn < 97 )
743 {
744 int cs = c + (E_Random() & 0x07) - 3;
745 int rs = r1 - (((E_Random() & 0x07) + 1) * rinc);
746 write_pixel = buf[cs&twm][rs];
747 }
748 }
749 else if( speck_per && (speck_per > rn) )
750 {
751 // with specks
752 int cs = c + (E_Random() & 0x0F) - 7;
753 int rs = row1 - ((E_Random() & 0x0F) * rinc);
754 write_pixel = buf[cs&twm][rs];
755 }
756 buf[c&twm][r1] = write_pixel;
757 }
758 }
759 }
760
761 // lower ground
762 if( row2 > SKY_HEIGHT - 2 ) break;
763 row1 = sky_bottom_align - 1;
764 row2 = SKY_HEIGHT - 1;
765 // num_rows = row2 - row1;
766 rinc = 1;
767 background_color = ground_color;
768 sl_horizon = 0;
769 }
770
771
772
773
774
775
776 generate_backgrounds:
777 // Generate background above sky texture.
778 // Copy stars has precedence because it matches better.
779 if( night_stars_upper || ( cv_sky_gen.EV == 13 )) // or fill random
780 {
781 for( r1 = sky_top_align-1; r1 >= 0; r1-- ) // must be row first
782 {
783 int dr = ((sky_top_align - r1) >> 1) + 2;
784 sample_sky( r1, dr, tw, twm, buf, sky_color, night_stars_upper );
785 }
786 }
787 else if((cv_sky_gen.EV == 10) || (cv_sky_gen.EV == 11)) // generate upper stars
788 {
789 int rst[SKY_WIDTH]; // r position for this c
790 byte ci_star1 = NearestColor( 80, 80, 80 );
791 byte ci_star2 = NearestColor( 135, 135, 135 );
792
793 memset( rst, 0, sizeof(rst) );
794 r2 = (cv_sky_gen.EV == 10)? sky_bottom_align : sky_top_align;
795 for( c1=0; c1 < tw; c1++ )
796 {
797 for( r1 = rst[c1]; r1 < r2; r1++ )
798 {
799 if( buf[c1][r1] != sky_color )
800 {
801 if((cv_sky_gen.EV == 10) && (r1 > sky_top_align) && ((c1==0) || (r1 > rst[c1-1]))) break;
802 continue;
803 }
804
805 rst[c1] = r1;
806 if((cv_sky_gen.EV == 10) && (c1>0) && (buf[c1-1][r1] == sky_color))
807 {
808 c1--; // background to the left, follow it
809 }
810
811 // Generate a new star sky
812 c4 = 0x35C + (((r1 ^ c1)>>4) & 0x3f);
813 buf[c1][r1] = ((E_Random() & 0x3FF) < c4)? ci_black
814 : (E_RandomPercent( 0.13f ))? ci_star2
815 : (E_RandomPercent( 1.28f ))? ci_star1
816 : ci_grey;
817 }
818 }
819 }
820
821 // Generate background below sky texture.
822 if( night_stars_lower || ( cv_sky_gen.EV == 13 )) // or fill random
823 {
824 for( r1 = sky_bottom_align; r1 < SKY_HEIGHT; r1++ )
825 {
826 int dr = ((r1 - sky_bottom_align) >> 1) + 2;
827 sample_sky( r1, dr, tw, twm, buf, ground_color, night_stars_lower );
828 }
829 }
830
831 goto make_patch;
832
833 make_patch:
834 {
835 // Source is column oriented, pixels are a byte no offset, no blank pixel.
836 // Create a TM_picture, with colofs array, no blank trim.
837 byte * sky_pict1 = R_Create_Patch( tw, SKY_HEIGHT,
838 /*SRC*/ TM_column_image, &buf[0][0], 1, 0, 299,
839 /*DEST*/ TM_picture, 0, NULL );
840 return sky_pict1;
841 }
842 }
843
844
845 //
846 // R_Init_SkyMap called at startup, once.
847 //
R_Init_SkyMap(void)848 void R_Init_SkyMap (void)
849 {
850 // set at P_LoadSectors
851 //sky_flatnum = R_FlatNumForName ( SKYFLATNAME );
852 }
853
854
855 // Setup sky draw for old or new skies (new skies = freelook 256x240)
856 //
857 // Call at loadlevel after sky_texture is set
858 //
859 // NOTE: skycolfunc should be set at R_ExecuteSetViewSize ()
860 // I dont bother because we don't use low detail no more
861 //
R_Setup_SkyDraw(void)862 void R_Setup_SkyDraw (void)
863 {
864 texpatch_t* texpatch;
865 patch_t wpatch;
866 int count;
867 int max_height;
868 int i;
869
870 if( sky_texture == 0 ) return;
871
872 // parse the patches composing sky texture for the tallest one
873 // patches are usually RSKY1,RSKY2... and unique
874
875 // note: the TEXTURES lump doesn't have the taller size of Legacy
876 // skies, but the patches it use will give the right size
877
878 count = textures[sky_texture]->patchcount;
879 texpatch = &textures[sky_texture]->patches[0];
880 max_height = 0;
881 for (i=0;i<count;i++)
882 {
883 W_ReadLumpHeader( texpatch->lumpnum, &wpatch, sizeof(patch_t) );
884 // [WDJ] Do endian fix as this is read.
885 wpatch.height = (uint16_t)( LE_SWAP16(wpatch.height) );
886 if( wpatch.height > max_height )
887 max_height = wpatch.height;
888 texpatch++;
889 }
890
891 // Doom: sky texture height=128, sky patch height=128
892 // Heretic: sky texture height=128, sky patch height=200, leftoffset=127, topoffset=195
893 // Legacy wad RSKY: sky patch height = 240
894
895 if( sky_pict )
896 {
897 Z_Free( sky_pict );
898 sky_pict = NULL;
899 }
900
901 texture_render[sky_texture].texture_model = TM_none; // to not affect R_GenerateTexture
902
903 // the horizon line in a 256x128 sky texture
904 sky_texturemid = 100<<FRACBITS; // Boom
905 sky_height = 128; // vanilla, Boom, default
906
907 if(max_height > 128)
908 {
909 // Need to convince R_GenerateTexture2 of new height.
910 if( max_height > textures[sky_texture]->height )
911 textures[sky_texture]->height = max_height;
912 sky_height = max_height;
913 sky_pict = R_GenerateTexture2( sky_texture, & texture_render[sky_texture], TM_picture );
914 sky_240 = 1;
915 // horizon line on 256x240 freelook textures of Legacy or heretic
916 sky_texturemid = 200<<FRACBITS;
917 }
918 else
919 {
920 if( cv_sky_gen.value == 0 ) // Auto
921 {
922 // If have subst sky, then use that
923 // otherwise extend the sky.
924 cv_sky_gen.EV = 12; // extend_bg
925 }
926
927 if( cv_sky_gen.EV >= 10 && cv_sky_gen.EV < 99 )
928 {
929 // Extend sky
930 sky_pict = R_Generate_Sky( sky_texture );
931 sky_240 = 1;
932 sky_height = SKY_HEIGHT;
933 sky_texturemid = 200<<FRACBITS;
934 }
935 else
936 {
937 // Vanilla or Stretch sky
938 sky_pict = R_GenerateTexture2( sky_texture, & texture_render[sky_texture], TM_picture );
939 sky_240 = 0;
940 if( max_height > 128 )
941 sky_height = max_height;
942 }
943 }
944 Z_ChangeTag( sky_pict, PU_STATIC );
945
946 // Sky has dedicated texture.
947
948 // determine width power of 2
949 // Sky is 128, 256, 512, or 1024 wide.
950 int tw = textures[sky_texture]->width;
951 sky_widthmask = tw - 1;
952 if( tw & sky_widthmask )
953 {
954 // The hard way, power of 2
955 i = 1;
956 while( (i<<1) < tw ) i = i<<1;
957 sky_widthmask = i - 1;
958 }
959
960 #if 0
961 if( cv_sky_gen.EV == 248 ) // vanilla
962 {
963 // Vanilla always has solid flats.
964 memset( skytop_flat, *(sky_pict + ((uint32_t*)sky_pict)[0]), SKY_FLAT_WIDTH*SKY_FLAT_HEIGHT );
965 memset( ground_flat, *(sky_pict + ((uint32_t*)sky_pict)[0] + sky_height-1), SKY_FLAT_WIDTH*SKY_FLAT_HEIGHT );
966 }
967 else
968 #endif
969 {
970 byte * sip = sky_pict + (((uint32_t*) sky_pict)[0]); // sky image
971 set_sky_flat( &skytop_flat[0][0], sip, 0, tw, 8 ); // sample upper sky
972 set_sky_flat( &ground_flat[0][0], sip, sky_height-8, tw, 8 ); // sample lower sky, for ground
973 }
974
975 // Get the right drawer. It was set by screen.c, depending on the
976 // current video mode bytes per pixel (quick fix)
977 skycolfunc = skydrawerfunc[sky_240];
978
979 R_Set_Sky_Scale ();
980 }
981
982
983 // set the correct scale for the sky at setviewsize
R_Set_Sky_Scale(void)984 void R_Set_Sky_Scale (void)
985 {
986 // Altered by screensize, splitscreen
987 // rdraw_viewheight, centery
988 // Boom
989 // SCREENHEIGHT=200, SCREENWIDTH=320
990 // centery = viewheight/2;
991 // pspriteyscale = (((SCREENHEIGHT*viewwidth)/SCREENWIDTH)<<FRACBITS)/200;
992 // projectiony = (((SCREENHEIGHT*centerx*320)/200)/SCREENWIDTH)*FRACUNIT;
993 // sky iscale = FRACUNIT*200/viewheight;
994 // Legacy
995 // BASEVIDHEIGHT=200, BASEVIDWIDTH=320
996 // centery = rdraw_viewheight/2;
997 // pspriteyscale = (((vid.height*rdraw_viewwidth)/vid.width)<<FRACBITS)/BASEVIDHEIGHT;
998 // projectiony = (((vid.height*centerx*BASEVIDWIDTH)/BASEVIDHEIGHT)/vid.width)<<FRACBITS;
999 // sky dc_iscale = FixedDiv (FRACUNIT, pspriteyscale);
1000
1001 // normal aspect ratio corrected scale
1002 // sky_scale = (FRACUNIT*200)/rdraw_viewheight; // Boom
1003 sky_scale = FixedDiv (FRACUNIT, pspriteyscale); // Legacy
1004
1005 if( cv_sky_gen.EV == 250 ) // Stretch
1006 {
1007 // double the texture vertically, bleeergh!!
1008 sky_scale >>= 1;
1009 }
1010
1011 // Sky draw limits
1012 // fixed_t frac = dc_texturemid + (dc_yl - centery) * fracstep;
1013 // limit frac to (0..sky_height-1) << 16
1014 // centery varies according to view
1015 // (dc_yl - centery) = ((frac - dc_texturemid) / fracstep);
1016 sky_yl_min_oc = ( 0 - sky_texturemid ) / sky_scale; // frac = 0
1017 sky_yh_max_oc = ( ((sky_height-1)<<16) - sky_texturemid ) / sky_scale; // frac = sky_height-1
1018 }
1019
1020
1021
1022
1023