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