Drop in SDL
[theoddone33/hhexen.git] / opengl / ogl_sky.c
1
2 //**************************************************************************
3 //**
4 //** OGL_SKY.C
5 //**
6 //**************************************************************************
7
8 // HEADER FILES ------------------------------------------------------------
9
10 #ifdef __WIN32
11 #define WIN32_LEAN_AND_MEAN
12 #include <windows.h>
13 #endif
14
15 #include <GL/gl.h>
16 #include "h2def.h"
17 #include "r_local.h"
18 #include "ogl_def.h"
19 #include "ogl_rl.h"
20 #include <math.h>
21
22 // MACROS ------------------------------------------------------------------
23
24 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
25
26 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
27
28 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
29
30 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
31
32 extern float            texw, texh;
33
34 extern float            vx, vy, vz;
35
36 extern boolean          special200;                     // Should sky2 be used?
37 extern int                      Sky1Texture, Sky2Texture;
38 extern fixed_t          Sky1ColumnOffset, Sky2ColumnOffset;
39 extern boolean          DoubleSky;
40 extern byte                     topLineRGB[3];
41 int                     skyDetail = 1;
42
43 // PUBLIC DATA DEFINITIONS -------------------------------------------------
44
45 int                     skyhemispheres;
46 fadeout_t       fadeOut[2];             // For both skies.
47
48 // PRIVATE DATA DEFINITIONS ------------------------------------------------
49
50 // CODE --------------------------------------------------------------------
51
52 // The texture offset to be applied to the texture coordinates in SkyVertex().
53 static float            maxSideAngle = (float) PI/3;
54 static float            texoff;
55 static int                      rows, columns;  
56 static float            scale = 32;     // Fogging affects, thus close-by.
57 static boolean          yflip;
58 static fadeout_t        *currentFO;
59
60 // Calculate the vertex and texture coordinates.
61 static void SkyVertex(int r, int c)
62 {
63         // The direction must be clockwise.
64         float topAngle = c/(float)columns * 2*PI;
65         float sideAngle = maxSideAngle * (rows-r)/(float)rows;
66         float height = sin(sideAngle);
67         float realRadius = scale*cos(sideAngle);
68         float x = vx + realRadius*cos(topAngle), 
69                         z = vz + realRadius*sin(topAngle),
70                         y = vy + ((!yflip)? scale*height : -scale*height);      
71
72         // And the texture coordinates.
73         if(!yflip)      // Flipped Y is for the lower hemisphere.
74                 glTexCoord2f(4*c/(float)columns + texoff/texw, r/(float)rows*200.0/256.0);
75         else
76                 glTexCoord2f(4*c/(float)columns + texoff/texw, (rows-r)/(float)rows*200.0/256.0);
77         // Also the color.
78         if(currentFO->use)
79         {
80                 if(r==0) glColor4f(1,1,1,0); else glColor3f(1,1,1);
81         }
82         else
83         {
84                 if(r==0) glColor3f(0,0,0); else glColor3f(1,1,1);
85         }
86         // And finally the vertex.
87         glVertex3f(x, y, z);    
88 }
89
90 static void CapSideVertex(int r, int c)
91 {
92         // The direction must be clockwise.
93         float topAngle = c/(float)columns * 2*PI;
94         float sideAngle = maxSideAngle * (rows-r)/(float)rows;
95         float height = sin(sideAngle);
96         float realRadius = scale*cos(sideAngle);
97
98         glVertex3f(vx + realRadius*cos(topAngle),
99                 vy + ((!yflip)? scale*height : -scale*height), 
100                 vz + realRadius*sin(topAngle)); 
101 }
102
103 // Hemi is Upper or Lower. Zero is not acceptable.
104 // The current texture is used. SKYHEMI_NO_TOPCAP can be used.
105 void OGL_RenderSkyHemisphere(int hemi)
106 {
107         int             r, c;
108
109         if(hemi & SKYHEMI_LOWER) yflip = true; else yflip = false;
110
111         // The top row (row 0) is the one that's faded out.
112         // There must be at least 4 columns. The preferable number
113         // is 4n, where n is 1, 2, 3... There should be at least
114         // two rows because the first one is always faded.
115         rows = 3;
116         columns = 4*skyDetail;  // 4n
117         if(hemi & SKYHEMI_JUST_CAP)
118         {
119                 //glBindTexture(GL_TEXTURE_2D, 0);
120                 glDisable( GL_TEXTURE_2D );
121
122                 // Use the appropriate color.
123                 if(currentFO->use)
124                         glColor3fv(currentFO->rgb);
125                 else
126                         glColor3f(0,0,0);
127                 glBegin(GL_TRIANGLE_FAN);
128                 for(c=0; c<columns; c++) CapSideVertex(0, c);
129                 glEnd();
130
131                 // If we are doing a colored fadeout...
132                 if(currentFO->use)
133                 {
134                         // We must fill the background for the top row since it'll
135                         // be partially translucent.
136                         glBegin(GL_TRIANGLE_STRIP);
137                         CapSideVertex(0, 0);
138                         for(c=0; c<columns; c++)
139                         {
140                                 CapSideVertex(1, c);    // One step down.
141                                 CapSideVertex(0, c+1);  // And one step right.
142                         }
143                         CapSideVertex(1, c);
144                         glEnd();
145                 }
146
147                 glEnable( GL_TEXTURE_2D );
148                 return;
149         }
150
151         // The total number of triangles per hemisphere can be calculated
152         // as follows: rows * columns * 2 + 2 (for the top cap).
153         for(r=0; r<rows; r++)
154         {
155                 glBegin(GL_TRIANGLE_STRIP);
156                 // Add the start vertex.
157                 SkyVertex(r, 0);
158                 for(c=0; c<columns; c++)
159                 {
160                         SkyVertex(r+1, c);      // One step down.
161                         SkyVertex(r, c+1);      // And one step right.
162                 }
163                 // Add the end vertex for this row. This vertex is also
164                 // the start vertex for the next row.
165                 SkyVertex(r+1, c);
166                 glEnd();
167                 /*glBegin(GL_QUADS);
168                 for(c=0; c<columns; c++)
169                 {
170                         SkyVertex(r, c);
171                         SkyVertex(r+1, c);
172                         SkyVertex(r+1, c+1);
173                         SkyVertex(r, c+1);
174                 }
175                 glEnd();*/
176         }
177 }
178
179 void OGL_HandleColoredFadeOut(int skynum)
180 {
181         int                     i;
182
183         currentFO = fadeOut + skynum-1;
184         // We have to remember the top line average RGB.
185         if(!currentFO->set)
186         {
187                 currentFO->set = 1;     // Now it is.
188                 for(i=0; i<3; i++) currentFO->rgb[i] = topLineRGB[i]/255.0;
189                 // Determine if it should be used.
190                 for(currentFO->use=false, i=0; i<3; i++)
191                         if(currentFO->rgb[i] > .3)
192                         {
193                                 // Colored fadeout is needed.
194                                 currentFO->use = true;
195                                 break;
196                         }
197         }
198 }
199
200 static void OGL_DrawSkyhemi(int whichHemi)
201 {
202         GLuint skyname;
203
204         // A double sky?
205         if(DoubleSky)
206         {
207                 skyname = OGL_PrepareSky(Sky2Texture, false);
208                 OGL_HandleColoredFadeOut(2);
209                 // First the top cap.
210                 OGL_RenderSkyHemisphere(whichHemi | SKYHEMI_JUST_CAP);
211
212                 glBindTexture(GL_TEXTURE_2D, skyname);
213                 texoff = FIX2FLT(Sky2ColumnOffset);
214                 OGL_RenderSkyHemisphere(whichHemi);
215                 
216                 // Then the masked sky1.
217                 glBindTexture(GL_TEXTURE_2D, OGL_PrepareSky(Sky1Texture, true));
218                 texoff = FIX2FLT(Sky1ColumnOffset);
219         }
220         else // Single-layer sky.
221         {
222                 if(special200)  // Use sky2?
223                 {
224                         skyname = OGL_PrepareSky(Sky2Texture, false);
225                         texoff = FIX2FLT(Sky2ColumnOffset);
226                         OGL_HandleColoredFadeOut(2);
227                 }
228                 else // Sky1, then. This is the normal case.
229                 {
230                         skyname = OGL_PrepareSky(Sky1Texture, false);
231                         texoff = FIX2FLT(Sky1ColumnOffset);
232                         OGL_HandleColoredFadeOut((Sky1Texture==P_GetMapSky1Texture(gamemap))?1:2);
233                 }
234                 // First the top cap.
235                 OGL_RenderSkyHemisphere(whichHemi | SKYHEMI_JUST_CAP);
236                 glBindTexture(GL_TEXTURE_2D, skyname);
237         }
238         // Render the front sky (sky1).
239         OGL_RenderSkyHemisphere(whichHemi);
240 }
241
242 void R_RenderSkyHemispheres(int hemis)
243 {
244         // IS there a sky to be rendered?
245         if(!hemis) return;
246
247         // We don't want anything written in the depth buffer, not yet.
248         glDepthMask(GL_FALSE);
249         glPushAttrib(GL_ENABLE_BIT);
250         // Disable culling, all triangles face the viewer.
251         glDisable(GL_CULL_FACE);
252         glDisable(GL_FOG);
253         // Draw the possibly visible hemispheres.
254         if(hemis & SKYHEMI_UPPER) OGL_DrawSkyhemi(SKYHEMI_UPPER);
255         if(hemis & SKYHEMI_LOWER) OGL_DrawSkyhemi(SKYHEMI_LOWER);
256         // Enable the disabled things.
257         glPopAttrib();
258         glDepthMask(GL_TRUE);
259 }
260