LCOV - code coverage report
Current view: top level - Core - OOSkyDrawable.m (source / functions) Hit Total Coverage
Test: coverxygen.info Lines: 0 42 0.0 %
Date: 2025-05-28 07:50:54 Functions: 0 0 -

          Line data    Source code
       1           0 : /*
       2             : 
       3             : OOSkyDrawable.m
       4             : 
       5             : 
       6             : Copyright (C) 2007-2013 Jens Ayton
       7             : 
       8             : Permission is hereby granted, free of charge, to any person obtaining a copy
       9             : of this software and associated documentation files (the "Software"), to deal
      10             : in the Software without restriction, including without limitation the rights
      11             : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      12             : copies of the Software, and to permit persons to whom the Software is
      13             : furnished to do so, subject to the following conditions:
      14             : 
      15             : The above copyright notice and this permission notice shall be included in all
      16             : copies or substantial portions of the Software.
      17             : 
      18             : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      19             : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      20             : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      21             : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      22             : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      23             : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      24             : SOFTWARE.
      25             : 
      26             : */
      27             : 
      28             : #import "OOSkyDrawable.h"
      29             : #import "ResourceManager.h"
      30             : #import "OOTexture.h"
      31             : #import "GameController.h"
      32             : #import "OOColor.h"
      33             : #import "OOProbabilisticTextureManager.h"
      34             : #import "OOGraphicsResetManager.h"
      35             : #import "Universe.h"
      36             : #import "OOMacroOpenGL.h"
      37             : #import "NSObjectOOExtensions.h"
      38             : #import "OOCollectionExtractors.h"
      39             : 
      40             : 
      41           0 : #define SKY_ELEMENT_SCALE_FACTOR                (BILLBOARD_DEPTH / 500.0f)
      42           0 : #define NEBULA_SHUFFLE_FACTOR                   0.005f
      43           0 : #define DEBUG_COLORS                                    0       // If set, rgb = xyz (offset to range from 0.1 to 1.0).
      44             : 
      45             : 
      46             : /*      Min and max coords are 0 and 1 normally, but the default
      47             :         sky-render-inset-coords can be used to modify them slightly as an attempted
      48             :         work-around for artefacts on buggy S3/Via renderers.
      49             : */
      50           0 : static float sMinTexCoord = 0.0f, sMaxTexCoord = 1.0f;
      51           0 : static BOOL sInited = NO;
      52             : 
      53             : 
      54             : /*      Struct used to describe quads initially. This form is optimized for
      55             :         reasoning about.
      56             : */
      57           0 : typedef struct OOSkyQuadDesc
      58             : {
      59           0 :         Vector                          corners[4];
      60           0 :         OOColor                         *color;
      61           0 :         OOTexture                       *texture;
      62           0 : } OOSkyQuadDesc;
      63             : 
      64             : 
      65           0 : enum
      66             : {
      67             :         kSkyQuadSetPositionEntriesPerVertex             = 3,
      68             :         kSkyQuadSetTexCoordEntriesPerVertex             = 2,
      69             :         kSkyQuadSetColorEntriesPerVertex                = 4
      70             : };
      71             : 
      72             : 
      73             : /*      Class containing a set of quads with the same texture. This form is
      74             :         optimized for rendering.
      75             : */
      76           0 : @interface OOSkyQuadSet: NSObject
      77             : {
      78             : @private
      79           0 :         OOTexture                               *_texture;
      80           0 :         unsigned                                _count;
      81           0 :         GLfloat                                 *_positions;    // 3 entries per vertex, 12 per quad
      82           0 :         GLfloat                                 *_texCoords;    // 2 entries per vertex, 8 per quad
      83           0 :         GLfloat                                 *_colors;               // 4 entries per vertex, 16 per quad
      84             : }
      85             : 
      86           0 : + (void)addQuads:(OOSkyQuadDesc *)quads count:(unsigned)count toArray:(NSMutableArray *)ioArray;
      87             : 
      88           0 : - (id)initWithQuadsWithTexture:(OOTexture *)texture inArray:(OOSkyQuadDesc *)array count:(unsigned)totalCount;
      89             : 
      90           0 : - (void)render;
      91             : 
      92             : #ifndef NDEBUG
      93           0 : - (size_t) totalSize;
      94           0 : - (OOTexture *) texture;
      95             : #endif
      96             : 
      97             : @end
      98             : 
      99             : 
     100             : /*      Textures are global because there is always a sky, but the sky isn't
     101             :         replaced very often, so the textures are likely to fall out of the cache.
     102             : */
     103           0 : static OOProbabilisticTextureManager    *sStarTextures;
     104           0 : static OOProbabilisticTextureManager    *sNebulaTextures;
     105             : 
     106             : 
     107             : static OOColor *SaturatedColorInRange(OOColor *color1, OOColor *color2, BOOL hueFix);
     108             : 
     109             : 
     110             : @interface OOSkyDrawable (OOPrivate) <OOGraphicsResetClient>
     111             : 
     112           0 : - (void)setUpStarsWithColor1:(OOColor *)color1 color2:(OOColor *)color2;
     113           0 : - (void)setUpNebulaeWithColor1:(OOColor *)color1
     114             :                                                 color2:(OOColor *)color2
     115             :                                  clusterFactor:(float)nebulaClusterFactor
     116             :                                   nebulaHueFix:(BOOL)nebulaHueFix
     117             :                                                  alpha:(float)nebulaAlpha
     118             :                                                  scale:(float)nebulaScale;
     119             :                                                 
     120             : 
     121           0 : - (void)loadStarTextures;
     122           0 : - (void)loadNebulaTextures;
     123             : 
     124           0 : - (void)addQuads:(OOSkyQuadDesc *)quads count:(unsigned)count;
     125             : 
     126           0 : - (void)ensureTexturesLoaded;
     127             : 
     128             : @end
     129             : 
     130             : 
     131             : @implementation OOSkyDrawable
     132             : 
     133             : - (id)initWithColor1:(OOColor *)color1
     134             :                           Color2:(OOColor *)color2
     135             :                           Color3:(OOColor *)color3
     136             :                           Color4:(OOColor *)color4
     137             :                    starCount:(unsigned)starCount
     138             :                  nebulaCount:(unsigned)nebulaCount
     139             :             nebulaHueFix:(BOOL)nebulaHueFix
     140             :            clusterFactor:(float)nebulaClusterFactor
     141             :                            alpha:(float)nebulaAlpha
     142             :                            scale:(float)nebulaScale
     143             : {
     144             :         NSAutoreleasePool               *pool = nil;
     145             :         
     146             :         if (!sInited)
     147             :         {
     148             :                 sInited = YES;
     149             :                 if ([[NSUserDefaults standardUserDefaults] boolForKey:@"sky-render-inset-coords"])
     150             :                 {
     151             :                         sMinTexCoord += 1.0f/128.0f;
     152             :                         sMaxTexCoord -= 1.0f/128.0f;
     153             :                 }
     154             :         }
     155             :         
     156             :         self = [super init];
     157             :         if (self == nil)  return nil;
     158             :         
     159             :         _starCount = starCount;
     160             :         _nebulaCount = nebulaCount;
     161             :         
     162             :         pool = [[NSAutoreleasePool alloc] init];
     163             :         [self setUpStarsWithColor1:color1 color2:color2];
     164             :         
     165             :         if (![UNIVERSE reducedDetail])
     166             :         {
     167             :                 [self setUpNebulaeWithColor1:color3
     168             :                                                           color2:color4
     169             :                                            clusterFactor:nebulaClusterFactor
     170             :                                                 nebulaHueFix:nebulaHueFix
     171             :                                                            alpha:nebulaAlpha
     172             :                                                            scale:nebulaScale];
     173             :         }
     174             :         [pool release];
     175             :         
     176             :         [[OOGraphicsResetManager sharedManager] registerClient:self];
     177             :         
     178             :         return self;
     179             : }
     180             : 
     181             : 
     182           0 : - (void)dealloc
     183             : {
     184             :         OO_ENTER_OPENGL();
     185             :         
     186             :         [_quadSets release];
     187             :         [[OOGraphicsResetManager sharedManager] unregisterClient:self];
     188             :         if (_displayListName != 0)  glDeleteLists(_displayListName, 1);
     189             :         
     190             :         [super dealloc];
     191             : }
     192             : 
     193             : 
     194           0 : - (void)renderOpaqueParts
     195             : {
     196             :         // While technically translucent, the sky doesn't need to be depth-sorted
     197             :         // since it'll be behind everything else anyway.
     198             :         
     199             :         OO_ENTER_OPENGL();
     200             :         OOSetOpenGLState(OPENGL_STATE_ADDITIVE_BLENDING);
     201             :         
     202             :         OOGL(glDisable(GL_DEPTH_TEST));  // don't read the depth buffer
     203             :         OOGL(glEnable(GL_TEXTURE_2D));
     204             :         
     205             :         // Make stars dim in atmosphere. Note: works OK on night side because sky is dark blue, not black.
     206             :         GLfloat fogColor[4] = {0.02, 0.02, 0.02, 1.0};
     207             :         OOGL(glFogfv(GL_FOG_COLOR, fogColor));
     208             :         
     209             :         if (_displayListName != 0)
     210             :         {
     211             :                 OOGL(glCallList(_displayListName));
     212             :         }
     213             :         else
     214             :         {
     215             :                 // Set up display list
     216             :                 [self ensureTexturesLoaded];
     217             :                 _displayListName = glGenLists(1);
     218             :                 
     219             :                 OOGL(glNewList(_displayListName, GL_COMPILE));
     220             :                 
     221             :                 OOGL(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
     222             :                 OOGL(glEnableClientState(GL_COLOR_ARRAY));
     223             :                 
     224             :                 [_quadSets makeObjectsPerformSelector:@selector(render)];
     225             :                 
     226             :                 OOGL(glDisableClientState(GL_TEXTURE_COORD_ARRAY));
     227             :                 OOGL(glDisableClientState(GL_COLOR_ARRAY));
     228             :                 
     229             :                 OOGL(glEndList());
     230             :         }
     231             :         
     232             :         // Restore state
     233             :         OOGL(glEnable(GL_DEPTH_TEST));
     234             :         OOGL(glDisable(GL_TEXTURE_2D));
     235             :         
     236             :         // Resetting fog is draw loop's responsibility.
     237             :         
     238             :         OOVerifyOpenGLState();
     239             :         OOCheckOpenGLErrors(@"OOSkyDrawable after rendering");
     240             : }
     241             : 
     242             : 
     243           0 : - (BOOL)hasOpaqueParts
     244             : {
     245             :         return YES;
     246             : }
     247             : 
     248             : 
     249           0 : - (GLfloat)maxDrawDistance
     250             : {
     251             :         return INFINITY;
     252             : }
     253             : 
     254             : #ifndef NDEBUG
     255           0 : - (NSSet *) allTextures
     256             : {
     257             :         NSMutableSet *result = [NSMutableSet setWithCapacity:[_quadSets count]];
     258             :         
     259             :         NSEnumerator *quadSetEnum = nil;
     260             :         OOSkyQuadSet *quadSet = nil;
     261             :         for (quadSetEnum = [_quadSets objectEnumerator]; (quadSet = [quadSetEnum nextObject]); )
     262             :         {
     263             :                 [result addObject:[quadSet texture]];
     264             :         }
     265             :         
     266             :         return result;
     267             : }
     268             : 
     269             : 
     270           0 : - (size_t) totalSize
     271             : {
     272             :         size_t result = [super totalSize];
     273             :         
     274             :         NSEnumerator *quadSetEnum = nil;
     275             :         OOSkyQuadSet *quadSet = nil;
     276             :         for (quadSetEnum = [_quadSets objectEnumerator]; (quadSet = [quadSetEnum nextObject]); )
     277             :         {
     278             :                 result += [quadSet totalSize];
     279             :         }
     280             :         
     281             :         return result;
     282             : }
     283             : #endif
     284             : 
     285             : @end
     286             : 
     287             : 
     288             : #if DEBUG_COLORS
     289             : static OOColor *DebugColor(Vector orientation)
     290             : {
     291             :         Vector color = vector_add(make_vector(0.55, 0.55, 0.55), vector_multiply_scalar(vector_normal(orientation), 0.45));
     292             :         return [OOColor colorWithCalibratedRed:color.x green:color.y blue:color.z alpha:1.0];
     293             : }
     294             : #endif
     295             : 
     296             : 
     297             : @implementation OOSkyDrawable (OOPrivate)
     298             : 
     299             : - (void)setUpStarsWithColor1:(OOColor *)color1 color2:(OOColor *)color2
     300             : {
     301             :         OOSkyQuadDesc           *quads = NULL, *currQuad = NULL;
     302             :         unsigned                        i;
     303             :         Quaternion                      q;
     304             :         Vector                          vi, vj, vk;
     305             :         float                           size;
     306             :         Vector                          middle, offset;
     307             :         
     308             :         [self loadStarTextures];
     309             :         
     310             :         quads = malloc(sizeof *quads * _starCount);
     311             :         if (quads == NULL)  return;
     312             :         
     313             :         currQuad = quads;
     314             :         for (i = 0; i != _starCount; ++i)
     315             :         {
     316             :                 // Select a direction and rotation.
     317             :                 q = OORandomQuaternion();
     318             :                 basis_vectors_from_quaternion(q, &vi, &vj, &vk);
     319             :                 
     320             :                 // Select colour and texture.
     321             : #if DEBUG_COLORS
     322             :                 currQuad->color = DebugColor(vk);
     323             : #else
     324             :                 currQuad->color = [color1 blendedColorWithFraction:randf() ofColor:color2];
     325             : #endif
     326             :                 currQuad->texture = [sStarTextures selectTexture];   // Not retained, since sStarTextures is never released.
     327             :                 
     328             :                 // Select scale; calculate centre position and offset to first corner.
     329             :                 size = (1 + (ranrot_rand() % 6)) * SKY_ELEMENT_SCALE_FACTOR;
     330             :                 middle = vector_multiply_scalar(vk, BILLBOARD_DEPTH);
     331             :                 offset = vector_multiply_scalar(vector_add(vi, vj), 0.5f * size);
     332             :                 
     333             :                 // Scale the "side" vectors.
     334             :                 Vector vj2 = vector_multiply_scalar(vj, size);
     335             :                 Vector vi2 = vector_multiply_scalar(vi, size);
     336             :                 
     337             :                 // Set up corners.
     338             :                 currQuad->corners[0] = vector_subtract(middle, offset);
     339             :                 currQuad->corners[1] = vector_add(currQuad->corners[0], vj2);
     340             :                 currQuad->corners[2] = vector_add(currQuad->corners[1], vi2);
     341             :                 currQuad->corners[3] = vector_add(currQuad->corners[0], vi2);
     342             :                 
     343             :                 ++currQuad;
     344             :         }
     345             :         
     346             :         [self addQuads:quads count:_starCount];
     347             :         free(quads);
     348             : }
     349             : 
     350             : 
     351             : - (void)setUpNebulaeWithColor1:(OOColor *)color1
     352             :                                                 color2:(OOColor *)color2
     353             :                                  clusterFactor:(float)nebulaClusterFactor
     354             :                                   nebulaHueFix:(BOOL)nebulaHueFix
     355             :                                                  alpha:(float)nebulaAlpha
     356             :                                                  scale:(float)nebulaScale
     357             : {
     358             :         OOSkyQuadDesc           *quads = NULL, *currQuad = NULL;
     359             :         unsigned                        i, actualCount = 0, clusters = 0;
     360             :         OOColor                         *color;
     361             :         Quaternion                      q;
     362             :         Vector                          vi, vj, vk;
     363             :         double                          size, r2;
     364             :         Vector                          middle, offset;
     365             :         int                                     r1;
     366             :         
     367             :         [self loadNebulaTextures];
     368             :         
     369             :         quads = malloc(sizeof *quads * _nebulaCount);
     370             :         if (quads == NULL)  return;
     371             :         
     372             :         currQuad = quads;
     373             :         for (i = 0; i < _nebulaCount; ++i)
     374             :         {
     375             :                 color = SaturatedColorInRange(color1, color2, nebulaHueFix);
     376             :                 
     377             :                 // Select a direction and rotation.
     378             :                 q = OORandomQuaternion();
     379             :                 
     380             :                 // Create a cluster of nebula quads.
     381             :                 while ((i < _nebulaCount) && (randf() < nebulaClusterFactor))
     382             :                 {
     383             :                         // Select size.
     384             :                         r1 = 1 + (ranrot_rand() & 15);
     385             :                         size = nebulaScale * r1 * SKY_ELEMENT_SCALE_FACTOR;
     386             :                         
     387             :                         // Calculate centre position and offset to first corner.
     388             :                         basis_vectors_from_quaternion(q, &vi, &vj, &vk);
     389             :                         
     390             :                         // Select colour and texture. Smaller nebula quads are dimmer.
     391             : #if DEBUG_COLORS
     392             :                         currQuad->color = DebugColor(vk);
     393             : #else
     394             :                         currQuad->color = [color colorWithBrightnessFactor:nebulaAlpha * (0.5f + (float)r1 / 32.0f)];
     395             : #endif
     396             :                         currQuad->texture = [sNebulaTextures selectTexture]; // Not retained, since sStarTextures is never released.
     397             :                         
     398             :                         middle = vector_multiply_scalar(vk, BILLBOARD_DEPTH);
     399             :                         offset = vector_multiply_scalar(vector_add(vi, vj), 0.5f * size);
     400             :                         
     401             :                         // Rotate vi and vj by a random angle
     402             :                         r2 = randf() * M_PI * 2.0;
     403             :                         quaternion_rotate_about_axis(&q, vk, r2);
     404             :                         vi = vector_right_from_quaternion(q);
     405             :                         vj = vector_up_from_quaternion(q);
     406             :                         
     407             :                         // Scale the "side" vectors.
     408             :                         vj = vector_multiply_scalar(vj, size);
     409             :                         vi = vector_multiply_scalar(vi, size);
     410             :                         
     411             :                         // Set up corners.
     412             :                         currQuad->corners[0] = vector_subtract(middle, offset);
     413             :                         currQuad->corners[1] = vector_add(currQuad->corners[0], vj);
     414             :                         currQuad->corners[2] = vector_add(currQuad->corners[1], vi);
     415             :                         currQuad->corners[3] = vector_add(currQuad->corners[0], vi);
     416             :                         
     417             :                         // Shuffle direction quat around a bit to spread the cluster out.
     418             :                         size = NEBULA_SHUFFLE_FACTOR / (nebulaScale * SKY_ELEMENT_SCALE_FACTOR);
     419             :                         q.x += size * (randf() - 0.5);
     420             :                         q.y += size * (randf() - 0.5);
     421             :                         q.z += size * (randf() - 0.5);
     422             :                         q.w += size * (randf() - 0.5);
     423             :                         quaternion_normalize(&q);
     424             :                         
     425             :                         ++i;
     426             :                         ++currQuad;
     427             :                         ++actualCount;
     428             :                 }
     429             :                 ++clusters;
     430             :         }
     431             :         
     432             :         /*      The above code generates less than _nebulaCount quads, because i is
     433             :                 incremented once in the outer loop as well as in the inner loop. To
     434             :                 keep skies looking the same, we leave the bug in and fill in the
     435             :                 actual generated count here.
     436             :         */
     437             :         _nebulaCount = actualCount;
     438             :         
     439             :         [self addQuads:quads count:_nebulaCount];
     440             :         free(quads);
     441             : }
     442             : 
     443             : 
     444             : - (void)addQuads:(OOSkyQuadDesc *)quads count:(unsigned)count
     445             : {
     446             :         if (_quadSets == nil)  _quadSets = [[NSMutableArray alloc] init];
     447             :         
     448             :         [OOSkyQuadSet addQuads:quads count:count toArray:_quadSets];
     449             : }
     450             : 
     451             : 
     452             : - (void)loadStarTextures
     453             : {
     454             :         if (sStarTextures == nil)
     455             :         {
     456             :                 sStarTextures = [[OOProbabilisticTextureManager alloc]
     457             :                                                         initWithPListName:@"startextures.plist"
     458             :                                                                           options:kOOTextureMinFilterMipMap | kOOTextureMagFilterLinear | kOOTextureAlphaMask
     459             :                                                                    anisotropy:0.0f
     460             :                                                                           lodBias:-0.0f];
     461             :                 if (sStarTextures == nil)
     462             :                 {
     463             :                         [NSException raise:OOLITE_EXCEPTION_DATA_NOT_FOUND format:@"No star textures could be loaded."];
     464             :                 }
     465             :         }
     466             :         
     467             :         [sStarTextures setSeed:RANROTGetFullSeed()];
     468             :         
     469             : }
     470             : 
     471             : 
     472             : - (void)loadNebulaTextures
     473             : {
     474             :         if (sNebulaTextures == nil)
     475             :         {
     476             :                 sNebulaTextures = [[OOProbabilisticTextureManager alloc]
     477             :                                                         initWithPListName:@"nebulatextures.plist"
     478             :                                                                           options:kOOTextureDefaultOptions | kOOTextureAlphaMask
     479             :                                                                    anisotropy:0.0f
     480             :                                                                           lodBias:0.0f];
     481             :                 if (sNebulaTextures == nil)
     482             :                 {
     483             :                         [NSException raise:OOLITE_EXCEPTION_DATA_NOT_FOUND format:@"No nebula textures could be loaded."];
     484             :                 }
     485             :         }
     486             :         
     487             :         [sNebulaTextures setSeed:RANROTGetFullSeed()];
     488             :         
     489             : }
     490             : 
     491             : 
     492             : - (void)ensureTexturesLoaded
     493             : {
     494             :         [sStarTextures ensureTexturesLoaded];
     495             :         [sNebulaTextures ensureTexturesLoaded];
     496             : }
     497             : 
     498             : 
     499           0 : - (void)resetGraphicsState
     500             : {
     501             :         OO_ENTER_OPENGL();
     502             :         
     503             :         if (_displayListName != 0)
     504             :         {
     505             :                 glDeleteLists(_displayListName, 1);
     506             :                 _displayListName = 0;
     507             :         }
     508             : }
     509             : 
     510             : @end
     511             : 
     512             : 
     513             : @implementation OOSkyQuadSet
     514             : 
     515             : + (void)addQuads:(OOSkyQuadDesc *)quads count:(unsigned)count toArray:(NSMutableArray *)ioArray
     516             : {
     517             :         NSMutableSet                    *seenTextures = nil;
     518             :         OOTexture                               *texture = nil;
     519             :         OOSkyQuadSet                    *quadSet = nil;
     520             :         unsigned                                i;
     521             :         
     522             :         // Iterate over all quads.
     523             :         seenTextures = [NSMutableSet set];
     524             :         for (i = 0; i != count; ++i)
     525             :         {
     526             :                 texture = quads[i].texture;
     527             :                 
     528             :                 // If we haven't seen this quad's texture before...
     529             :                 if (![seenTextures containsObject:texture])
     530             :                 {
     531             :                         [seenTextures addObject:texture];
     532             :                         
     533             :                         // ...create a quad set for this texture.
     534             :                         quadSet = [[self alloc] initWithQuadsWithTexture:texture
     535             :                                                                                                          inArray:quads
     536             :                                                                                                            count:count];
     537             :                         if (quadSet != nil)
     538             :                         {
     539             :                                 [ioArray addObject:quadSet];
     540             :                                 [quadSet release];
     541             :                         }
     542             :                 }
     543             :         }
     544             : }
     545             : 
     546             : 
     547             : - (id)initWithQuadsWithTexture:(OOTexture *)texture inArray:(OOSkyQuadDesc *)array count:(unsigned)totalCount
     548             : {
     549             :         BOOL                                    OK = YES;
     550             :         unsigned                                i, j, vertexCount;
     551             :         GLfloat                                 *pos;
     552             :         GLfloat                                 *tc;
     553             :         GLfloat                                 *col;
     554             :         GLfloat                                 r, g, b, x;
     555             :         size_t                                  posSize, tcSize, colSize;
     556             :         unsigned                                count = 0;
     557             :         int                                     skyColorCorrection = [[NSUserDefaults standardUserDefaults] oo_integerForKey:@"sky-color-correction" defaultValue:0];
     558             :         
     559             : // Hejl / Burgess-Dawson filmic tone mapping
     560             : // this algorithm has gamma correction already embedded 
     561           0 : #define SKYCOLOR_TONEMAP_COMPONENT(skyColorComponent) \
     562             : do { \
     563             :         x = MAX(0.0, skyColorComponent - 0.004); \
     564             :         *col++ = (x * (6.2 * x + 0.5)) / (x * (6.2 * x + 1.7) + 0.06); \
     565             : } while (0) 
     566             : 
     567             :         self = [super init];
     568             :         if (self == nil)  OK = NO;
     569             :         
     570             :         if (OK)
     571             :         {
     572             :                 // Count the quads in the array using this texture.
     573             :                 for (i = 0; i != totalCount; ++i)
     574             :                 {
     575             :                         if (array[i].texture == texture)  ++_count;
     576             :                 }
     577             :                 if (_count == 0)  OK = NO;
     578             :         }
     579             :         
     580             :         if (OK)
     581             :         {
     582             :                 // Allocate arrays.
     583             :                 vertexCount = _count * 4;
     584             :                 posSize = sizeof *_positions * vertexCount * kSkyQuadSetPositionEntriesPerVertex;
     585             :                 tcSize = sizeof *_texCoords * vertexCount * kSkyQuadSetTexCoordEntriesPerVertex;
     586             :                 colSize = sizeof *_colors * vertexCount * kSkyQuadSetColorEntriesPerVertex;
     587             :                 
     588             :                 _positions = malloc(posSize);
     589             :                 _texCoords = malloc(tcSize);
     590             :                 _colors = malloc(colSize);
     591             :                 
     592             :                 if (_positions == NULL || _texCoords == NULL || _colors == NULL)  OK = NO;
     593             :                 
     594             :                 pos = _positions;
     595             :                 tc = _texCoords;
     596             :                 col = _colors;
     597             :         }
     598             :         
     599             :         if (OK)
     600             :         {
     601             :                 // Find the matching quads again, and convert them to renderable representation.
     602             :                 for (i = 0; i != totalCount; ++i)
     603             :                 {
     604             :                         if (array[i].texture == texture)
     605             :                         {
     606             :                                 r = [array[i].color redComponent];
     607             :                                 g = [array[i].color greenComponent];
     608             :                                 b = [array[i].color blueComponent];
     609             :                                 
     610             :                                 // Loop over vertices
     611             :                                 for (j = 0; j != 4; ++j)
     612             :                                 {
     613             :                                         *pos++ = array[i].corners[j].x;
     614             :                                         *pos++ = array[i].corners[j].y;
     615             :                                         *pos++ = array[i].corners[j].z;
     616             :                                         
     617             :                                         // Colour is the same for each vertex
     618             :                                         if (skyColorCorrection == 0)            // no color correction
     619             :                                         {
     620             :                                                 *col++ = r;
     621             :                                                 *col++ = g;
     622             :                                                 *col++ = b;
     623             :                                         }
     624             :                                         else if (skyColorCorrection == 1)       // gamma correction only
     625             :                                         {
     626             :                                                 *col++ = pow(r, 1.0/2.2);
     627             :                                                 *col++ = pow(g, 1.0/2.2);
     628             :                                                 *col++ = pow(b, 1.0/2.2);
     629             :                                         }
     630             :                                         else                                    // gamma correctioin + filmic tone mapping
     631             :                                         {
     632             :                                                 SKYCOLOR_TONEMAP_COMPONENT(r);
     633             :                                                 SKYCOLOR_TONEMAP_COMPONENT(g);
     634             :                                                 SKYCOLOR_TONEMAP_COMPONENT(b);
     635             :                                         }
     636             :                                         *col++ = 1.0f;  // Alpha is unused but needs to be there
     637             :                                 }
     638             :                                 
     639             :                                 // Texture co-ordinates are the same for each quad.
     640             :                                 *tc++ = sMinTexCoord;
     641             :                                 *tc++ = sMinTexCoord;
     642             :                                 
     643             :                                 *tc++ = sMaxTexCoord;
     644             :                                 *tc++ = sMinTexCoord;
     645             :                                 
     646             :                                 *tc++ = sMaxTexCoord;
     647             :                                 *tc++ = sMaxTexCoord;
     648             :                                 
     649             :                                 *tc++ = sMinTexCoord;
     650             :                                 *tc++ = sMaxTexCoord;
     651             :                                 
     652             :                                 count++;
     653             :                         }
     654             :                 }
     655             :                 
     656             :                 _texture = [texture retain];
     657             :                 OOLog(@"sky.setup", @"Generated quadset with %u quads for texture %@", count, _texture);
     658             :         }
     659             :         
     660             :         if (!OK)
     661             :         {
     662             :                 [self release];
     663             :                 self = nil;
     664             :         }
     665             :         
     666             :         return self;
     667             : }
     668             : 
     669             : 
     670           0 : - (void)dealloc
     671             : {
     672             :         [_texture release];
     673             :         
     674             :         if (_positions != NULL)  free(_positions);
     675             :         if (_texCoords != NULL)  free(_texCoords);
     676             :         if (_colors != NULL)  free(_colors);
     677             :         
     678             :         [super dealloc];
     679             : }
     680             : 
     681             : 
     682           0 : - (NSString *)description
     683             : {
     684             :         return [NSString stringWithFormat:@"<%@ %p>{%u quads, texture: %@}", [self class], self, _count, _texture];
     685             : }
     686             : 
     687             : 
     688             : - (void)render
     689             : {
     690             :         OO_ENTER_OPENGL();
     691             :         
     692             :         [_texture apply];
     693             :         
     694             :         OOGL(glVertexPointer(kSkyQuadSetPositionEntriesPerVertex, GL_FLOAT, 0, _positions));
     695             :         OOGL(glTexCoordPointer(kSkyQuadSetTexCoordEntriesPerVertex, GL_FLOAT, 0, _texCoords));
     696             :         OOGL(glColorPointer(kSkyQuadSetColorEntriesPerVertex, GL_FLOAT, 0, _colors));
     697             :         
     698             :         OOGL(glDrawArrays(GL_QUADS, 0, 4 * _count));
     699             : }
     700             : 
     701             : 
     702             : #ifndef NDEBUG
     703             : - (size_t) totalSize
     704             : {
     705             :         return [self oo_objectSize] + _count * 4 * (sizeof *_positions + sizeof *_texCoords + sizeof *_colors);
     706             : }
     707             : 
     708             : 
     709             : - (OOTexture *) texture
     710             : {
     711             :         return _texture;
     712             : }
     713             : #endif
     714             : 
     715             : @end
     716             : 
     717             : 
     718           0 : static OOColor *SaturatedColorInRange(OOColor *color1, OOColor *color2, BOOL hueFix)
     719             : {
     720             :         OOColor                         *color = nil;
     721             :         float                           hue, saturation, brightness, alpha;
     722             :         
     723             :         color = [color1 blendedColorWithFraction:randf() ofColor:color2];
     724             :         [color getHue:&hue saturation:&saturation brightness:&brightness alpha:&alpha];
     725             :         
     726             :         saturation = 0.5 * saturation + 0.5;    // move saturation up a notch!
     727             :         
     728             :         /*      NOTE: this changes the hue, because getHue:... produces hue values
     729             :                 in [0, 360], but colorWithCalibratedHue:... takes hue values in
     730             :                 [0, 1].
     731             :         */
     732             :         if (hueFix)
     733             :         {
     734             :                 /* now nebula colours can be independently set, correct the
     735             :                  * range so they behave expectedly if they have actually been
     736             :                  * set in planetinfo */
     737             :                 hue /= 360.0;
     738             :         }
     739             :         /* else keep it how it was before so the nebula hues are clearer */
     740             :         
     741             :         return [OOColor colorWithHue:hue saturation:saturation brightness:brightness alpha:alpha];
     742             : }

Generated by: LCOV version 1.14