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

          Line data    Source code
       1           0 : /*
       2             : 
       3             : OOPlanetEntity.m
       4             : 
       5             : Oolite
       6             : Copyright (C) 2004-2013 Giles C Williams and contributors
       7             : 
       8             : This program is free software; you can redistribute it and/or
       9             : modify it under the terms of the GNU General Public License
      10             : as published by the Free Software Foundation; either version 2
      11             : of the License, or (at your option) any later version.
      12             : 
      13             : This program is distributed in the hope that it will be useful,
      14             : but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             : GNU General Public License for more details.
      17             : 
      18             : You should have received a copy of the GNU General Public License
      19             : along with this program; if not, write to the Free Software
      20             : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
      21             : MA 02110-1301, USA.
      22             : 
      23             : */
      24             : 
      25             : #import "OOPlanetEntity.h"
      26             : 
      27             : #if NEW_PLANETS
      28             : 
      29             : #define NEW_ATMOSPHERE 1
      30             : 
      31             : #import "OOPlanetDrawable.h"
      32             : 
      33             : #import "AI.h"
      34             : #import "Universe.h"
      35             : #import "ShipEntity.h"
      36             : #import "PlayerEntity.h"
      37             : #import "ShipEntityAI.h"
      38             : #import "OOCharacter.h"
      39             : 
      40             : #import "OOMaths.h"
      41             : #import "ResourceManager.h"
      42             : #import "OOStringParsing.h"
      43             : #import "OOCollectionExtractors.h"
      44             : #import "OOSystemDescriptionManager.h"
      45             : 
      46             : #import "OOPlanetTextureGenerator.h"
      47             : #import "OOStandaloneAtmosphereGenerator.h"
      48             : #import "OOSingleTextureMaterial.h"
      49             : #import "OOShaderMaterial.h"
      50             : #import "OOEntityFilterPredicate.h"
      51             : #import "OOGraphicsResetManager.h"
      52             : #import "OOStringExpander.h"
      53             : #import "OOOpenGLMatrixManager.h"
      54             : 
      55             : 
      56             : #define OO_TERMINATOR_THRESHOLD_VECTOR_DEFAULT  (make_vector(0.105, 0.18, 0.28))        // used to be (0.1, 0.105, 0.12);
      57             : 
      58             : 
      59             : @interface OOPlanetEntity (Private) <OOGraphicsResetClient>
      60             : 
      61             : - (void) setUpTerrainParametersWithSourceInfo:(NSDictionary *)sourceInfo targetInfo:(NSMutableDictionary *)targetInfo;
      62             : - (void) setUpLandParametersWithSourceInfo:(NSDictionary *)sourceInfo targetInfo:(NSMutableDictionary *)targetInfo;
      63             : - (void) setUpAtmosphereParametersWithSourceInfo:(NSDictionary *)sourceInfo targetInfo:(NSMutableDictionary *)targetInfo;
      64             : - (void) setUpColorParametersWithSourceInfo:(NSDictionary *)sourceInfo targetInfo:(NSMutableDictionary *)targetInfo isAtmosphere:(BOOL)isAtmosphere;
      65             : - (void) setUpTypeParametersWithSourceInfo:(NSDictionary *)sourceInfo targetInfo:(NSMutableDictionary *)targetInfo;
      66             : 
      67             : @end
      68             : 
      69             : 
      70             : @implementation OOPlanetEntity
      71             : 
      72             : // this is exclusively called to initialise the main planet.
      73             : - (id) initAsMainPlanetForSystem:(OOSystemID)s
      74             : {
      75             :         NSMutableDictionary *planetInfo = [[UNIVERSE generateSystemData:s] mutableCopy];
      76             :         [planetInfo autorelease];
      77             :         
      78             :         [planetInfo oo_setBool:YES forKey:@"mainForLocalSystem"];
      79             :         if (s != [PLAYER systemID])
      80             :         {
      81             :                 [planetInfo oo_setBool:YES forKey:@"isMiniature"];
      82             :         }
      83             :         return [self initFromDictionary:planetInfo withAtmosphere:[planetInfo oo_boolForKey:@"has_atmosphere" defaultValue:YES] andSeed:[[UNIVERSE systemManager] getRandomSeedForSystem:s inGalaxy:[PLAYER galaxyNumber]] forSystem:s];
      84             : }
      85             : 
      86             : 
      87             : static const double kMesosphere = 10.0 * ATMOSPHERE_DEPTH;      // atmosphere effect starts at 10x the height of the clouds
      88             : 
      89             : 
      90             : - (id) initFromDictionary:(NSDictionary *)dict withAtmosphere:(BOOL)atmosphere andSeed:(Random_Seed)seed forSystem:(OOSystemID)systemID
      91             : {
      92             :         if (dict == nil)  dict = [NSDictionary dictionary];
      93             :         RANROTSeed savedRanrotSeed = RANROTGetFullSeed();
      94             :         
      95             :         self = [self init];
      96             :         if (self == nil)  return nil;
      97             :         
      98             :         scanClass = CLASS_NO_DRAW;
      99             :         
     100             :         NSMutableDictionary *planetInfo = [[UNIVERSE generateSystemData:systemID] mutableCopy];
     101             :         [planetInfo autorelease];
     102             : 
     103             :         [self setUpTypeParametersWithSourceInfo:dict targetInfo:planetInfo];
     104             : 
     105             :         [self setUpTerrainParametersWithSourceInfo:dict targetInfo:planetInfo];
     106             : 
     107             : 
     108             :         // Load random seed override.
     109             :         NSString *seedStr = [dict oo_stringForKey:@"seed"];
     110             :         if (seedStr != nil)
     111             :         {
     112             :                 Random_Seed overrideSeed = RandomSeedFromString(seedStr);
     113             :                 if (!is_nil_seed(overrideSeed))  seed = overrideSeed;
     114             :                 else  OOLogERR(@"planet.fromDict", @"could not interpret \"%@\" as planet seed, using default.", seedStr);
     115             :         }
     116             :         
     117             :         // Generate various planet info.
     118             :         seed_for_planet_description(seed);
     119             : 
     120             :         _name = nil;
     121             :         [self setName:OOExpand([dict oo_stringForKey:KEY_PLANETNAME defaultValue:[planetInfo oo_stringForKey:KEY_PLANETNAME defaultValue:@"%H"]])];
     122             :         
     123             :         int radius_km = [dict oo_intForKey:KEY_RADIUS defaultValue:[planetInfo oo_intForKey:KEY_RADIUS]];
     124             :         collision_radius = radius_km * 10.0;    // Scale down by a factor of 100
     125             :         OOTechLevelID techLevel = [dict oo_intForKey:KEY_TECHLEVEL defaultValue:[planetInfo oo_intForKey:KEY_TECHLEVEL]];
     126             :         
     127             :         if (techLevel > 14)  techLevel = 14;
     128             :         _shuttlesOnGround = 1 + techLevel / 2;
     129             :         _shuttleLaunchInterval = 3600.0 / (double)_shuttlesOnGround;    // All are launched in one hour.
     130             :         _lastLaunchTime = [UNIVERSE getTime] + 30.0 - _shuttleLaunchInterval;   // launch 30s after player enters universe.
     131             :                                                                                                                                                         // make delay > 0 to allow scripts adding a station nearby.
     132             :         
     133             :         int percent_land = [planetInfo oo_intForKey:@"percent_land" defaultValue:24 + (gen_rnd_number() % 48)];
     134             :         [planetInfo setObject:[NSNumber numberWithFloat:0.01 * percent_land] forKey:@"land_fraction"];
     135             : 
     136             :         int percent_ice = [planetInfo oo_intForKey:@"percent_ice" defaultValue:5];
     137             :         [planetInfo setObject:[NSNumber numberWithFloat:0.01 * percent_ice] forKey:@"polar_fraction"];
     138             : 
     139             :         
     140             :         RNG_Seed savedRndSeed = currentRandomSeed();
     141             :         
     142             :         _planetDrawable = [[OOPlanetDrawable alloc] init];
     143             :         
     144             :         _terminatorThresholdVector = [planetInfo oo_vectorForKey:@"terminator_threshold_vector" defaultValue:OO_TERMINATOR_THRESHOLD_VECTOR_DEFAULT];
     145             :         
     146             :         // Load material parameters, including atmosphere.
     147             :         RANROTSeed planetNoiseSeed = RANROTGetFullSeed();
     148             :         [planetInfo setObject:[NSValue valueWithBytes:&planetNoiseSeed objCType:@encode(RANROTSeed)] forKey:@"noise_map_seed"];
     149             :         [self setUpLandParametersWithSourceInfo:dict targetInfo:planetInfo];
     150             :         
     151             :         _airColor = nil;        // default to no air
     152             :         _airColorMixRatio = 0.5f;
     153             :         _airDensity = 0.75f;
     154             :         
     155             :         _illuminationColor = [[planetInfo objectForKey:@"illumination_color"] retain];
     156             :         
     157             : #if NEW_ATMOSPHERE
     158             :         if (atmosphere)
     159             :         {
     160             :                 // shader atmosphere always has a radius of collision_radius + ATMOSPHERE_DEPTH. For texture atmosphere, we need to check
     161             :                 // if a shader atmosphere is also used. If yes, set its radius to just cover the planet so that it doesn't conflict with 
     162             :                 // the shader atmosphere at the planet edges. If no shader atmosphere is used, then set it to the standard radius
     163             :                 double atmosphereRadius = [UNIVERSE detailLevel] >= DETAIL_LEVEL_SHADERS ? collision_radius : collision_radius + ATMOSPHERE_DEPTH;
     164             :                 _atmosphereDrawable = [[OOPlanetDrawable atmosphereWithRadius:atmosphereRadius] retain];
     165             :                 _atmosphereShaderDrawable = [[OOPlanetDrawable atmosphereWithRadius:collision_radius + ATMOSPHERE_DEPTH] retain];
     166             :                 
     167             :                 // convert the atmosphere settings to generic 'material parameters'
     168             :                 percent_land = 100 - [dict oo_intForKey:@"percent_cloud" defaultValue:100 - (3 + (gen_rnd_number() & 31)+(gen_rnd_number() & 31))];
     169             :                 [planetInfo setObject:[NSNumber numberWithFloat:0.01 * percent_land] forKey:@"cloud_fraction"];
     170             :                 [self setUpAtmosphereParametersWithSourceInfo:dict targetInfo:planetInfo];
     171             :                 // planetInfo now contains a valid air_color
     172             :                 _airColor = [[planetInfo objectForKey:@"air_color"] retain];
     173             :                 _airColorMixRatio = [planetInfo oo_floatForKey:@"air_color_mix_ratio"];
     174             :                 
     175             :                 _airDensity = OOClamp_0_1_f([planetInfo oo_floatForKey:@"air_density"]);
     176             :                 // OOLog (@"planet.debug",@" translated air colour:%@ cloud colour:%@ polar cloud color:%@", [_airColor rgbaDescription],[(OOColor *)[planetInfo objectForKey:@"cloud_color"] rgbaDescription],[(OOColor *)[planetInfo objectForKey:@"polar_cloud_color"] rgbaDescription]);
     177             : 
     178             :                 _materialParameters = [planetInfo dictionaryWithValuesForKeys:[NSArray arrayWithObjects:@"cloud_fraction", @"air_color", @"air_color_mix_ratio", @"air_density", @"cloud_color", @"polar_cloud_color", @"cloud_alpha", @"land_fraction", @"land_color", @"sea_color", @"polar_land_color", @"polar_sea_color", @"noise_map_seed", @"economy", @"polar_fraction", @"isMiniature", @"perlin_3d", @"terminator_threshold_vector", nil]];
     179             :         }
     180             :         else
     181             : #else
     182             :         // NEW_ATMOSPHERE is 0? still differentiate between normal planets and moons.
     183             :         if (atmosphere)
     184             :         {
     185             :                 _atmosphereDrawable = [[OOPlanetDrawable atmosphereWithRadius:collision_radius + ATMOSPHERE_DEPTH] retain];
     186             :                 _airColor = [[OOColor colorWithRed:0.8f green:0.8f blue:0.9f alpha:1.0f] retain];
     187             :         }
     188             :         if (YES) // create _materialParameters when NEW_ATMOSPHERE is set to 0
     189             : #endif
     190             :         {
     191             :                 _materialParameters = [planetInfo dictionaryWithValuesForKeys:[NSArray arrayWithObjects:@"land_fraction", @"land_color", @"sea_color", @"polar_land_color", @"polar_sea_color", @"noise_map_seed", @"economy", @"polar_fraction",  @"isMiniature", @"perlin_3d", @"terminator_threshold_vector", @"illumination_color", nil]];
     192             :         }
     193             :         [_materialParameters retain];
     194             :         
     195             :         _mesopause2 = (atmosphere) ? (kMesosphere + collision_radius) * (kMesosphere + collision_radius) : 0.0;
     196             :         
     197             :         _normSpecMapName = [[dict oo_stringForKey:@"texture_normspec"] retain]; // must be set up before _textureName
     198             :         
     199             :         _textureName = [[dict oo_stringForKey:@"texture"] retain];
     200             :         [self setUpPlanetFromTexture:_textureName];
     201             :         [_planetDrawable setRadius:collision_radius];
     202             :                 
     203             :         // Orientation should be handled by the code that calls this planetEntity. Starting with a default value anyway.
     204             :         orientation = (Quaternion){ M_SQRT1_2, M_SQRT1_2, 0, 0 };
     205             :         _atmosphereOrientation = kIdentityQuaternion;
     206             :         _rotationAxis = vector_up_from_quaternion(orientation);
     207             :         
     208             :         // set speed of rotation.
     209             :         if ([dict objectForKey:@"rotational_velocity"])
     210             :         {
     211             :                 _rotationalVelocity = [dict oo_floatForKey:@"rotational_velocity" defaultValue:0.01f * randf()];      // 0.0 .. 0.01 avr 0.005
     212             :         }
     213             :         else
     214             :         {
     215             :                 _rotationalVelocity = [planetInfo oo_floatForKey:@"rotation_speed" defaultValue:0.005f * randf()]; // 0.0 .. 0.005 avr 0.0025
     216             :                 _rotationalVelocity *= [planetInfo oo_floatForKey:@"rotation_speed_factor" defaultValue:1.0f];
     217             :         }
     218             : 
     219             :         _atmosphereRotationalVelocity = [dict oo_floatForKey:@"atmosphere_rotational_velocity" defaultValue:0.01f * randf()];
     220             : 
     221             :         // set energy
     222             :         energy = collision_radius * 1000.0f;
     223             :         
     224             :         setRandomSeed(savedRndSeed);
     225             :         RANROTSetFullSeed(savedRanrotSeed);
     226             :         
     227             :         // rotate planet based on current time, needs to be done here - backported from PlanetEntity.
     228             :         int             deltaT = floor(fmod([PLAYER clockTimeAdjusted], 86400));
     229             :         quaternion_rotate_about_axis(&orientation, _rotationAxis, _rotationalVelocity * deltaT);
     230             :         quaternion_rotate_about_axis(&_atmosphereOrientation, kBasisYVector, _atmosphereRotationalVelocity * deltaT);
     231             :         
     232             :         
     233             : #ifdef OO_DUMP_PLANETINFO
     234             : #define CPROP(PROP)     OOLog(@"planetinfo.record",@#PROP " = %@;",[(OOColor *)[planetInfo objectForKey:@#PROP] descriptionComponents]);
     235             : #define FPROP(PROP)     OOLog(@"planetinfo.record",@#PROP " = %f;",[planetInfo oo_floatForKey:@"" #PROP]);
     236             :         CPROP(air_color);
     237             :         CPROP(illumination_color);
     238             :         FPROP(air_color_mix_ratio);
     239             :         FPROP(cloud_alpha);
     240             :         CPROP(cloud_color);
     241             :         FPROP(cloud_fraction);
     242             :         CPROP(land_color);
     243             :         FPROP(land_fraction);
     244             :         CPROP(polar_cloud_color);
     245             :         CPROP(polar_land_color);
     246             :         CPROP(polar_sea_color);
     247             :         CPROP(sea_color);
     248             :         OOLog(@"planetinfo.record",@"rotation_speed = %f",_rotationalVelocity);
     249             : #endif
     250             : 
     251             :         [self setStatus:STATUS_ACTIVE];
     252             :         
     253             :         [[OOGraphicsResetManager sharedManager] registerClient:self];
     254             : 
     255             :         return self;
     256             : }
     257             : 
     258             : 
     259             : static Vector RandomHSBColor(void)
     260             : {
     261             :         return (Vector)
     262             :         {
     263             :                 gen_rnd_number() / 256.0,
     264             :                 gen_rnd_number() / 256.0,
     265             :                 0.5 + gen_rnd_number() / 512.0
     266             :         };
     267             : }
     268             : 
     269             : 
     270             : static Vector LighterHSBColor(Vector c)
     271             : {
     272             :         return (Vector)
     273             :         {
     274             :                 c.x,
     275             :                 c.y * 0.25f,
     276             :                 1.0f - (c.z * 0.1f)
     277             :         };
     278             : }
     279             : 
     280             : 
     281             : static Vector HSBColorWithColor(OOColor *color)
     282             : {
     283             :         OOHSBAComponents c = [color hsbaComponents];
     284             :         return (Vector){ c.h/360, c.s, c.b };
     285             : }
     286             : 
     287             : 
     288             : static OOColor *ColorWithHSBColor(Vector c)
     289             : {
     290             :         return [OOColor colorWithHue:c.x saturation:c.y brightness:c.z alpha:1.0];
     291             : }
     292             : 
     293             : 
     294             : - (void) setUpTypeParametersWithSourceInfo:(NSDictionary *)sourceInfo targetInfo:(NSMutableDictionary *)targetInfo
     295             : {
     296             :         [targetInfo oo_setBool:[sourceInfo oo_boolForKey:@"mainForLocalSystem"] forKey:@"mainForLocalSystem"];
     297             :         [targetInfo oo_setBool:[sourceInfo oo_boolForKey:@"isMiniature"] forKey:@"isMiniature"];
     298             : 
     299             : }
     300             : 
     301             : 
     302             : - (void) setUpTerrainParametersWithSourceInfo:(NSDictionary *)sourceInfo targetInfo:(NSMutableDictionary *)targetInfo
     303             : {
     304             :         NSArray *keys = [NSArray arrayWithObjects:@"atmosphere_rotational_velocity",@"rotational_velocity",@"cloud_alpha",@"has_atmosphere",@"percent_cloud",@"percent_ice",@"percent_land",@"radius",@"seed",nil];
     305             :         NSString *key = nil;
     306             :         foreach (key, keys) {
     307             :                 id sval = [sourceInfo objectForKey:key];
     308             :                 if (sval != nil) {
     309             :                         [targetInfo setObject:sval forKey:key];
     310             :                 }
     311             :         }
     312             : 
     313             : }
     314             : 
     315             : 
     316             : - (void) setUpLandParametersWithSourceInfo:(NSDictionary *)sourceInfo targetInfo:(NSMutableDictionary *)targetInfo
     317             : {
     318             :         [self setUpColorParametersWithSourceInfo:sourceInfo targetInfo:targetInfo isAtmosphere:NO];
     319             : }
     320             : 
     321             : 
     322             : - (void) setUpAtmosphereParametersWithSourceInfo:(NSDictionary *)sourceInfo targetInfo:(NSMutableDictionary *)targetInfo
     323             : {
     324             :         [self setUpColorParametersWithSourceInfo:sourceInfo targetInfo:targetInfo isAtmosphere:YES];
     325             : }
     326             : 
     327             : 
     328             : - (void) setUpColorParametersWithSourceInfo:(NSDictionary *)sourceInfo targetInfo:(NSMutableDictionary *)targetInfo isAtmosphere:(BOOL)isAtmosphere
     329             : {
     330             :         // Stir the PRNG fourteen times for backwards compatibility.
     331             :         unsigned i;
     332             :         for (i = 0; i < 14; i++)
     333             :         {
     334             :                 gen_rnd_number();
     335             :         }
     336             :         
     337             :         Vector  landHSB, seaHSB, landPolarHSB, seaPolarHSB, illumHSB;
     338             :         Vector  terminatorThreshold;
     339             :         OOColor *color;
     340             :         
     341             :         landHSB = RandomHSBColor();
     342             :         
     343             :         if (!isAtmosphere)
     344             :         {
     345             :                 do
     346             :                 {
     347             :                         seaHSB = RandomHSBColor();
     348             :                 }
     349             :                 while (dot_product(landHSB, seaHSB) > .80f); // make sure land and sea colors differ significantly
     350             :                 
     351             :                 // saturation bias - avoids really grey oceans
     352             :                 if (seaHSB.y < 0.22f) seaHSB.y = seaHSB.y * 0.3f + 0.2f;
     353             :                 // brightness bias - avoids really bright landmasses
     354             :                 if (landHSB.z > 0.66f) landHSB.z = 0.66f;
     355             :                 
     356             :                 // planetinfo.plist overrides
     357             :                 color = [OOColor colorWithDescription:[sourceInfo objectForKey:@"land_color"]];
     358             :                 if (color != nil) landHSB = HSBColorWithColor(color);
     359             :                 else ScanVectorFromString([sourceInfo oo_stringForKey:@"land_hsb_color"], &landHSB);
     360             :                 
     361             :                 color = [OOColor colorWithDescription:[sourceInfo objectForKey:@"sea_color"]];
     362             :                 if (color != nil) seaHSB = HSBColorWithColor(color);
     363             :                 else ScanVectorFromString([sourceInfo oo_stringForKey:@"sea_hsb_color"], &seaHSB);
     364             :                 
     365             :                 color = [OOColor colorWithDescription:[sourceInfo objectForKey:@"illumination_color"]];
     366             :                 if (color != nil) illumHSB = HSBColorWithColor(color);
     367             :                 else
     368             :                 {
     369             :                         NSString *illumHSBColorString = [sourceInfo oo_stringForKey:@"illumination_hsb_color"];
     370             :                         if (illumHSBColorString)  ScanVectorFromString(illumHSBColorString, &illumHSB);
     371             :                         else illumHSB = HSBColorWithColor([OOColor colorWithRed:0.8f green:0.8f blue:0.4f alpha:1.0f]); 
     372             :                 }
     373             :                 
     374             :                 // polar areas are brighter but have less colour (closer to white)
     375             :                 color = [OOColor colorWithDescription:[sourceInfo objectForKey:@"polar_land_color"]];
     376             :                 if (color != nil)
     377             :                 {
     378             :                         landPolarHSB = HSBColorWithColor(color);
     379             :                 }
     380             :                 else 
     381             :                 {
     382             :                         landPolarHSB = LighterHSBColor(landHSB);
     383             :                 }
     384             : 
     385             :                 color = [OOColor colorWithDescription:[sourceInfo objectForKey:@"polar_sea_color"]];
     386             :                 if (color != nil)
     387             :                 {
     388             :                         seaPolarHSB = HSBColorWithColor(color);
     389             :                 }
     390             :                 else
     391             :                 {
     392             :                         seaPolarHSB = LighterHSBColor(seaHSB);
     393             :                 }
     394             :                 
     395             :                 [targetInfo setObject:ColorWithHSBColor(landHSB) forKey:@"land_color"];
     396             :                 [targetInfo setObject:ColorWithHSBColor(seaHSB) forKey:@"sea_color"];
     397             :                 [targetInfo setObject:ColorWithHSBColor(landPolarHSB) forKey:@"polar_land_color"];
     398             :                 [targetInfo setObject:ColorWithHSBColor(seaPolarHSB) forKey:@"polar_sea_color"];
     399             :                 [targetInfo setObject:ColorWithHSBColor(illumHSB) forKey:@"illumination_color"];
     400             :         }
     401             :         else
     402             :         {
     403             :                 landHSB = RandomHSBColor();     // NB: randomcolor is called twice to make the cloud colour similar to the old one.
     404             : 
     405             :                 // add a cloud_color tinge to sky blue({0.66, 0.3, 1}).
     406             :                 seaHSB = vector_add(landHSB,((Vector){1.333, 0.6, 2})); // 1 part cloud, 2 parts sky blue
     407             :                 scale_vector(&seaHSB, 0.333);
     408             :                                 
     409             :                 float cloudAlpha = OOClamp_0_1_f([sourceInfo oo_floatForKey:@"cloud_alpha" defaultValue:1.0f]);
     410             :                 [targetInfo setObject:[NSNumber numberWithFloat:cloudAlpha] forKey:@"cloud_alpha"];
     411             :                 
     412             :                 // planetinfo overrides
     413             :                 color = [OOColor colorWithDescription:[sourceInfo objectForKey:@"air_color"]];
     414             :                 if (color != nil) seaHSB = HSBColorWithColor(color);
     415             :                 
     416             :                 color = [OOColor colorWithDescription:[sourceInfo objectForKey:@"cloud_color"]];
     417             :                 if (color != nil) landHSB = HSBColorWithColor(color);
     418             :                 
     419             :                 // polar areas: brighter, less saturation
     420             :                 landPolarHSB = vector_add(landHSB,LighterHSBColor(landHSB));
     421             :                 scale_vector(&landPolarHSB, 0.5);
     422             :                 
     423             :                 color = [OOColor colorWithDescription:[sourceInfo objectForKey:@"polar_cloud_color"]];
     424             :                 if (color != nil) landPolarHSB = HSBColorWithColor(color);
     425             :                 
     426             :                 [targetInfo setObject:ColorWithHSBColor(seaHSB) forKey:@"air_color"];
     427             :                 [targetInfo setObject:ColorWithHSBColor(landHSB) forKey:@"cloud_color"];
     428             :                 [targetInfo setObject:ColorWithHSBColor(landPolarHSB) forKey:@"polar_cloud_color"];
     429             :                 [targetInfo setObject:[NSNumber numberWithFloat:[sourceInfo oo_floatForKey:@"air_color_mix_ratio"]] forKey:@"air_color_mix_ratio"];
     430             :         }
     431             :         terminatorThreshold = [sourceInfo oo_vectorForKey:@"terminator_threshold_vector" defaultValue:OO_TERMINATOR_THRESHOLD_VECTOR_DEFAULT];
     432             :         [targetInfo setObject:[NSString stringWithFormat:@"%f %f %f", terminatorThreshold.x, terminatorThreshold.y, terminatorThreshold.z] forKey:@"terminator_threshold_vector"];
     433             : }
     434             : 
     435             : 
     436             : - (id) initAsMiniatureVersionOfPlanet:(OOPlanetEntity *)planet
     437             : {
     438             :         // Nasty, nasty. I'd really prefer to have a separate entity class for this.
     439             :         if (planet == nil)
     440             :         {
     441             :                 [self release];
     442             :                 return nil;
     443             :         }
     444             :         
     445             :         self = [self init];
     446             :         if (self == nil)  return nil;
     447             :         
     448             :         scanClass = CLASS_NO_DRAW;
     449             :         [self setStatus:STATUS_COCKPIT_DISPLAY];
     450             :         
     451             :         collision_radius = planet->collision_radius * PLANET_MINIATURE_FACTOR;
     452             :         orientation = planet->orientation;
     453             :         _rotationAxis = planet->_rotationAxis;
     454             :         _atmosphereOrientation = planet->_atmosphereOrientation;
     455             :         _rotationalVelocity = 0.04;
     456             :         
     457             :         _terminatorThresholdVector = planet->_terminatorThresholdVector;
     458             :         
     459             :         _miniature = YES;
     460             :         
     461             :         _planetDrawable = [planet->_planetDrawable copy];
     462             :         [_planetDrawable setRadius:collision_radius];
     463             :         
     464             :         // FIXME: in old planet code, atmosphere (if textured) is set to 0.6 alpha.
     465             :         _atmosphereDrawable = [planet->_atmosphereDrawable copy];
     466             :         _atmosphereShaderDrawable = [planet->_atmosphereShaderDrawable copy];
     467             :         [_atmosphereDrawable setRadius:collision_radius + ATMOSPHERE_DEPTH * PLANET_MINIATURE_FACTOR * 2.0]; //not to scale: invisible otherwise
     468             :         if (_atmosphereShaderDrawable)  [_atmosphereShaderDrawable setRadius:collision_radius + ATMOSPHERE_DEPTH * PLANET_MINIATURE_FACTOR * 2.0];
     469             :         
     470             :         [_planetDrawable setLevelOfDetail:0.8f];
     471             :         [_atmosphereDrawable setLevelOfDetail:0.8f];
     472             :         if (_atmosphereShaderDrawable)  [_atmosphereShaderDrawable setLevelOfDetail:0.8f];
     473             :         
     474             :         return self;
     475             : }
     476             : 
     477             : 
     478             : - (void) dealloc
     479             : {
     480             :         DESTROY(_name);
     481             :         DESTROY(_planetDrawable);
     482             :         DESTROY(_atmosphereDrawable);
     483             :         DESTROY(_atmosphereShaderDrawable);
     484             :         DESTROY(_airColor);
     485             :         DESTROY(_illuminationColor);
     486             :         DESTROY(_materialParameters);
     487             :         DESTROY(_textureName);
     488             :         DESTROY(_normSpecMapName);
     489             :         
     490             :         [[OOGraphicsResetManager sharedManager] unregisterClient:self];
     491             : 
     492             :         [super dealloc];
     493             : }
     494             : 
     495             : 
     496             : - (NSString*) descriptionComponents
     497             : {
     498             :         return [NSString stringWithFormat:@"position: %@ radius: %g m", HPVectorDescription([self position]), [self radius]];
     499             : }
     500             : 
     501             : 
     502             : - (void) setOrientation:(Quaternion) quat
     503             : {
     504             :         [super setOrientation: quat];
     505             :         _rotationAxis = vector_up_from_quaternion(quat);
     506             : }
     507             : 
     508             : 
     509             : - (double) radius
     510             : {
     511             :         return collision_radius;
     512             : }
     513             : 
     514             : 
     515             : - (OOStellarBodyType) planetType
     516             : {
     517             :         if (_miniature)  return STELLAR_TYPE_MINIATURE;
     518             :         if (_atmosphereDrawable != nil)  return STELLAR_TYPE_NORMAL_PLANET;
     519             :         return STELLAR_TYPE_MOON;
     520             : }
     521             : 
     522             : 
     523             : - (instancetype) miniatureVersion
     524             : {
     525             :         return [[[[self class] alloc] initAsMiniatureVersionOfPlanet:self] autorelease];
     526             : }
     527             : 
     528             : 
     529             : - (void) update:(OOTimeDelta) delta_t
     530             : {
     531             :         [super update:delta_t];
     532             :         
     533             :         if (EXPECT(!_miniature))
     534             :         {
     535             :                 BOOL canDrawShaderAtmosphere = _atmosphereShaderDrawable && [UNIVERSE detailLevel] >= DETAIL_LEVEL_SHADERS;
     536             :                 if (EXPECT_NOT(_atmosphereDrawable && cam_zero_distance < _mesopause2))
     537             :                 {
     538             :                         NSAssert(_airColor != nil, @"Expected a non-nil air colour for normal planet. Exiting.");
     539             :                         double          alt = (sqrt(cam_zero_distance) - collision_radius) / kMesosphere; // the viewpoint altitude
     540             :                         double          trueAlt = (sqrt(zero_distance) - collision_radius) / kMesosphere; // the actual ship altitude
     541             :                         // if at long distance external view, rotating the camera could potentially end up with it being
     542             :                         // at negative altitude. Since we know we are already inside the atmosphere at this point, just make sure
     543             :                         // that altitude is kept to a minimum positive value to avoid sudden black skies
     544             :                         if (alt <= 0.0)  alt = 1e-4;
     545             :                         if (EXPECT_NOT(alt > 0 && alt <= 1.0))    // ensure aleph is clamped between 0 and 1
     546             :                         {
     547             :                                 double  aleph = 1.0 - alt;
     548             :                                 double  aleph2 = aleph * aleph;
     549             :                                 
     550             :                                 // night sky, reddish flash on entering the atmosphere, low light pollution otherwhise
     551             :                                 OOColor *mixColor = [OOColor colorWithRed:(EXPECT_NOT(alt > 0.98) ? 30.0f : 0.1f)
     552             :                                                                                                         green:0.1f
     553             :                                                                                                          blue:0.1f
     554             :                                                                                                         alpha:aleph];
     555             :                                                                                                                           
     556             :                                 // occlusion rate: .9 is 18 degrees after the terminus, where twilight ends.
     557             :                                 // 1 is the terminus, 1.033 is 6 degrees before the terminus, where the sky begins to redden
     558             :                                 double rate = ([PLAYER occlusionLevel] - 0.97)/0.06; // from 0.97 to 1.03
     559             : 
     560             :                                 if (EXPECT(rate <= 1.0 && rate > 0.0))
     561             :                                 {
     562             :                                         mixColor = [mixColor blendedColorWithFraction:rate ofColor:_airColor];
     563             :                                         // TODO: properly calculated pink sky - needs to depend on sun's angular size,
     564             :                                         // and its angular height on the horizon.
     565             :                                         /*
     566             :                                         rate -= 0.7;
     567             :                                         if (rate >= 0.0) // pink sky!
     568             :                                         {
     569             :                                                 rate = 0.5 - (fabs(rate - 0.15) / 0.3); // at most a 50% blend!
     570             :                                                 mixColor = [mixColor blendedColorWithFraction:rate ofColor:[OOColor colorWithRed:0.6
     571             :                                                                                                                                                                                                    green:0.1
     572             :                                                                                                                                                                                                         blue:0.0
     573             :                                                                                                                                                                                                    alpha:aleph]];
     574             :                                         }
     575             :                                         */
     576             :                                 }
     577             :                                 else
     578             :                                 {
     579             :                                         if (PLAYER->isSunlit && _airColor != nil) mixColor = _airColor;
     580             :                                 }
     581             :                                 [UNIVERSE setSkyColorRed:[mixColor redComponent] * aleph2
     582             :                                                                    green:[mixColor greenComponent] * aleph2
     583             :                                                                         blue:[mixColor blueComponent] * aleph
     584             :                                                                    alpha:aleph];
     585             :                                 double atmosphereRadius = canDrawShaderAtmosphere ? collision_radius : collision_radius + (ATMOSPHERE_DEPTH * alt);
     586             :                                 [_atmosphereDrawable setRadius:atmosphereRadius];
     587             :                                 if (_atmosphereShaderDrawable)  [_atmosphereShaderDrawable setRadius:collision_radius + (ATMOSPHERE_DEPTH * alt)];
     588             :                                 // apply air resistance for the ship, not the camera. Although setSkyColorRed
     589             :                                 // has already set the air resistance to aleph, override it immediately
     590             :                                 [UNIVERSE setAirResistanceFactor:OOClamp_0_1_f(1.0 - trueAlt)];
     591             :                         }
     592             :                 }
     593             :                 else
     594             :                 {
     595             :                         if (EXPECT_NOT([_atmosphereDrawable radius] < collision_radius + ATMOSPHERE_DEPTH))
     596             :                         {
     597             :                                 [_atmosphereDrawable setRadius:collision_radius + ATMOSPHERE_DEPTH];
     598             :                                 if (_atmosphereShaderDrawable)  [_atmosphereShaderDrawable setRadius:collision_radius + ATMOSPHERE_DEPTH];
     599             :                         }
     600             :                         if (canDrawShaderAtmosphere && [_atmosphereDrawable radius] != collision_radius)
     601             :                         {
     602             :                                 // if shader atmo is in use, force texture atmo radius to just collision_radius for cosmetic purposes
     603             :                                 [_atmosphereDrawable setRadius:collision_radius];
     604             :                         }
     605             :                         if ([PLAYER findNearestPlanet] == self) // ensure no problems in case of more than one planets
     606             :                         {
     607             :                                 [UNIVERSE setAirResistanceFactor:0.0f]; // out of atmosphere - no air friction
     608             :                         }
     609             :                 }
     610             :                 
     611             :                 double time = [UNIVERSE getTime];
     612             :                 
     613             :                 if (_shuttlesOnGround > 0 && time > _lastLaunchTime + _shuttleLaunchInterval)  [self launchShuttle];
     614             :         }
     615             :         
     616             :         quaternion_rotate_about_axis(&orientation, _rotationAxis, _rotationalVelocity * delta_t);
     617             :         // atmosphere orientation is relative to the orientation of the planet
     618             :         quaternion_rotate_about_axis(&_atmosphereOrientation, kBasisYVector, _atmosphereRotationalVelocity * delta_t);
     619             : 
     620             :         [self orientationChanged];
     621             :         
     622             :         // FIXME: update atmosphere rotation
     623             : }
     624             : 
     625             : 
     626             : - (BOOL) isFinishedLoading
     627             : {
     628             :         OOMaterial *material = [self material];
     629             :         if (material != nil && ![material isFinishedLoading])  return NO;
     630             :         material = [self atmosphereMaterial];
     631             :         if (material != nil && ![material isFinishedLoading])  return NO;
     632             :         material = [self atmosphereShaderMaterial];
     633             :         if (material != nil && ![material isFinishedLoading])  return NO;
     634             :         return YES;
     635             : }
     636             : 
     637             : 
     638             : - (void) drawImmediate:(bool)immediate translucent:(bool)translucent
     639             : {
     640             :         BOOL canDrawShaderAtmosphere = _atmosphereShaderDrawable && [UNIVERSE detailLevel] >= DETAIL_LEVEL_SHADERS;
     641             :         
     642             :         if ([UNIVERSE breakPatternHide])   return; // DON'T DRAW
     643             :         if (_miniature && ![self isFinishedLoading])  return; // For responsiveness, don't block to draw as miniature.
     644             : 
     645             :         // too far away to be drawn
     646             :         if (magnitude(cameraRelativePosition) > [self radius]*3000) {
     647             :                 return;
     648             :         }
     649             :         if (![UNIVERSE viewFrustumIntersectsSphereAt:cameraRelativePosition withRadius:([self radius] + ATMOSPHERE_DEPTH)])
     650             :         {
     651             :                 // Don't draw
     652             :                 return;
     653             :         }
     654             :         
     655             :         if ([UNIVERSE wireframeGraphics])  OOGLWireframeModeOn();
     656             :         
     657             :         if (!_miniature)
     658             :         {
     659             :                 [_planetDrawable calculateLevelOfDetailForViewDistance:cam_zero_distance];
     660             :                 [_atmosphereDrawable setLevelOfDetail:[_planetDrawable levelOfDetail]];
     661             :                 if (canDrawShaderAtmosphere)  [_atmosphereShaderDrawable setLevelOfDetail:[_planetDrawable levelOfDetail]];
     662             :         }
     663             : 
     664             :         // 500km squared
     665             :     //  if (magnitude2(cameraRelativePosition) > 250000000000.0) 
     666             :         /* Temporarily for 1.82 make this branch unconditional. There's an
     667             :          * odd change in appearance when crossing this boundary, which can
     668             :          * be quite noticeable. There don't appear to be close-range
     669             :          * problems with doing it this way all the time, though it's not
     670             :          * ideal. - CIM */
     671             :         {
     672             :                 /* at this distance the atmosphere is too close to the planet
     673             :                  * for a 24-bit depth buffer to reliably distinguish the two,
     674             :                  * so cheat and draw the atmosphere on the opaque pass: it's
     675             :                  * far enough away that painter's algorithm should do fine */
     676             :                 [_planetDrawable renderOpaqueParts];
     677             :                 if (_atmosphereDrawable != nil)
     678             :                 {
     679             :                         OOGLPushModelView();
     680             :                         OOGLMultModelView(OOMatrixForQuaternionRotation(_atmosphereOrientation));
     681             :                         [_atmosphereDrawable renderTranslucentPartsOnOpaquePass];
     682             :                         if (canDrawShaderAtmosphere)  [_atmosphereShaderDrawable renderTranslucentPartsOnOpaquePass];
     683             :                         OOGLPopModelView();
     684             :                 }
     685             :         }
     686             : #if OOLITE_HAVE_FIXED_THE_ABOVE_DESCRIBED_BUG_WHICH_WE_HAVENT
     687             :         else 
     688             :         {
     689             :                 /* At close range we can do this properly and draw the
     690             :                  * atmosphere on the transparent pass */
     691             :                 if (translucent)
     692             :                 {
     693             :                         if (_atmosphereDrawable != nil)
     694             :                         {
     695             :                                 OOGLPushModelView();
     696             :                                 OOGLMultModelView(OOMatrixForQuaternionRotation(_atmosphereOrientation));
     697             :                                 [_atmosphereDrawable renderTranslucentParts];
     698             :                                 if (canDrawShaderAtmosphere)  [_atmosphereShaderDrawable renderTranslucentParts];
     699             :                                 OOGLPopModelView();
     700             :                         }
     701             :                 }
     702             :                 else
     703             :                 {
     704             :                         [_planetDrawable renderOpaqueParts];
     705             :                 }
     706             :         }
     707             : #endif
     708             :         
     709             :         if ([UNIVERSE wireframeGraphics])  OOGLWireframeModeOff();
     710             : }
     711             : 
     712             : 
     713             : - (BOOL) checkCloseCollisionWith:(Entity *)other
     714             : {
     715             :         if (!other)
     716             :                 return NO;
     717             :         if (other->isShip)
     718             :         {
     719             :                 ShipEntity *ship = (ShipEntity *)other;
     720             :                 if ([ship behaviour] == BEHAVIOUR_LAND_ON_PLANET)
     721             :                 {
     722             :                         return NO;
     723             :                 }
     724             :         }
     725             :         
     726             :         return YES;
     727             : }
     728             : 
     729             : 
     730             : - (BOOL) planetHasStation
     731             : {
     732             :         // find the nearest station...
     733             :         ShipEntity      *station =  nil;
     734             :         station = [UNIVERSE nearestShipMatchingPredicate:IsStationPredicate
     735             :                                                                                    parameter:nil
     736             :                                                                         relativeToEntity:self];
     737             :         
     738             :         if (station && HPdistance([station position], position) < 4 * collision_radius) // there is a station in range.
     739             :         {
     740             :                 return YES;
     741             :         }
     742             :         return NO;
     743             : }
     744             : 
     745             : 
     746             : - (void) launchShuttle
     747             : {
     748             :         if (_shuttlesOnGround == 0)  
     749             :         {
     750             :                 return;
     751             :         }
     752             :         if ([PLAYER status] == STATUS_START_GAME)
     753             :         {
     754             :                 // don't launch if game not started
     755             :                 return;
     756             :         }
     757             :         if (self != [UNIVERSE planet] && ![self planetHasStation])
     758             :         {
     759             :                 // don't launch shuttles when no station is nearby.
     760             :                 _shuttlesOnGround = 0;
     761             :                 return;
     762             :         }
     763             :         
     764             :         Quaternion  q1;
     765             :         quaternion_set_random(&q1);
     766             :         float start_distance = collision_radius + 125.0f;
     767             :         HPVector launch_pos = HPvector_add(position, vectorToHPVector(vector_multiply_scalar(vector_forward_from_quaternion(q1), start_distance)));
     768             :         
     769             :         ShipEntity *shuttle_ship = [UNIVERSE newShipWithRole:@"shuttle"];   // retain count = 1
     770             :         if (shuttle_ship)
     771             :         {
     772             :                 if ([[shuttle_ship crew] count] == 0)
     773             :                 {
     774             :                         [shuttle_ship setSingleCrewWithRole:@"trader"];
     775             :                 }
     776             :                 
     777             :                 [shuttle_ship setPosition:launch_pos];
     778             :                 [shuttle_ship setOrientation:q1];
     779             :                 
     780             :                 [shuttle_ship setScanClass: CLASS_NEUTRAL];
     781             :                 [shuttle_ship setCargoFlag:CARGO_FLAG_FULL_PLENTIFUL];
     782             :                 [shuttle_ship switchAITo:@"oolite-shuttleAI.js"];
     783             :                 [UNIVERSE addEntity:shuttle_ship];      // STATUS_IN_FLIGHT, AI state GLOBAL
     784             :                 _shuttlesOnGround--;
     785             :                 _lastLaunchTime = [UNIVERSE getTime];
     786             :                 
     787             :                 [shuttle_ship release];
     788             :         }
     789             : }
     790             : 
     791             : 
     792             : - (void) welcomeShuttle:(ShipEntity *)shuttle
     793             : {
     794             :         _shuttlesOnGround++;
     795             : }
     796             : 
     797             : 
     798             : - (BOOL) isPlanet
     799             : {
     800             :         return YES;
     801             : }
     802             : 
     803             : 
     804             : - (BOOL) isVisible
     805             : {
     806             :         return YES;
     807             : }
     808             : 
     809             : 
     810             : - (double) rotationalVelocity
     811             : {
     812             :         return _rotationalVelocity;
     813             : }
     814             : 
     815             : 
     816             : - (void) setRotationalVelocity:(double) v
     817             : {
     818             :         if ([self hasAtmosphere])
     819             :         {
     820             :                 // FIXME: change atmosphere rotation speed proportionally
     821             :         }
     822             :         _rotationalVelocity = v;
     823             : }
     824             : 
     825             : 
     826             : // this method is visible to shader bindings, hence it returns vector
     827             : - (Vector) airColorAsVector
     828             : {
     829             :         float r, g, b, a;
     830             :         [_airColor getRed:&r green:&g blue:&b alpha:&a];
     831             :         return make_vector(r, g, b); // don't care about a
     832             : }
     833             : 
     834             : 
     835             : - (OOColor *) airColor
     836             : {
     837             :         return _airColor;
     838             : }
     839             : 
     840             : 
     841             : - (void) setAirColor:(OOColor *) newColor
     842             : {
     843             :         if (newColor)
     844             :         {
     845             :                 [_airColor release];
     846             :                 _airColor = [newColor retain];
     847             :         }
     848             : }
     849             : 
     850             : 
     851             : // this method is visible to shader bindings, hence it returns vector
     852             : - (Vector) illuminationColorAsVector
     853             : {
     854             :         float r, g, b, a;
     855             :         [_illuminationColor getRed:&r green:&g blue:&b alpha:&a];
     856             :         return make_vector(r, g, b); // don't care about a
     857             : }
     858             : 
     859             : 
     860             : - (OOColor *) illuminationColor
     861             : {
     862             :         return _illuminationColor;
     863             : }
     864             : 
     865             : 
     866             : - (void) setIlluminationColor:(OOColor *) newColor
     867             : {
     868             :         if (newColor)
     869             :         {
     870             :                 [_illuminationColor release];
     871             :                 _illuminationColor = [newColor retain];
     872             :         }
     873             : }
     874             : 
     875             : 
     876             : // visible to shader bindings
     877             : - (float) airColorMixRatio
     878             : {
     879             :         return _airColorMixRatio;
     880             : }
     881             : 
     882             : 
     883             : - (void) setAirColorMixRatio:(float) newRatio
     884             : {
     885             :         _airColorMixRatio = OOClamp_0_1_f(newRatio);
     886             : }
     887             : 
     888             : 
     889             : // visible to shader bindings
     890             : - (float) airDensity
     891             : {
     892             :         return _airDensity;
     893             : }
     894             : 
     895             : 
     896             : - (void) setAirDensity: (float)newDensity
     897             : {
     898             :         _airDensity = OOClamp_0_1_f(newDensity);
     899             : }
     900             : 
     901             : 
     902             : - (void) setTerminatorThresholdVector:(Vector) newTerminatorThresholdVector
     903             : {
     904             :         _terminatorThresholdVector.x = newTerminatorThresholdVector.x;
     905             :         _terminatorThresholdVector.y = newTerminatorThresholdVector.y;
     906             :         _terminatorThresholdVector.z = newTerminatorThresholdVector.z;
     907             : }
     908             : 
     909             : 
     910             : - (Vector) terminatorThresholdVector
     911             : {
     912             :         return _terminatorThresholdVector;
     913             : }
     914             : 
     915             : 
     916             : - (BOOL) hasAtmosphere
     917             : {
     918             :         return _atmosphereDrawable != nil;
     919             : }
     920             : 
     921             : 
     922             : // FIXME: need material model.
     923             : - (NSString *) textureFileName
     924             : {
     925             :         return [_planetDrawable textureName];
     926             : }
     927             : 
     928             : 
     929             : - (void)resetGraphicsState
     930             : {
     931             :         // reset the texture if graphics mode changes
     932             :         [self setUpPlanetFromTexture:_textureName];
     933             : }
     934             : 
     935             : 
     936             : - (void) setTextureFileName:(NSString *)textureName
     937             : {
     938             :         BOOL isMoon = _atmosphereDrawable == nil;
     939             :         
     940             :         OOTexture *diffuseMap = nil;
     941             :         OOTexture *normalMap = nil;
     942             :         NSDictionary *macros = nil;
     943             :         NSDictionary *materialDefaults = [ResourceManager materialDefaults];
     944             :         
     945             : #if OO_SHADERS
     946             :         OOGraphicsDetail detailLevel = [UNIVERSE detailLevel];
     947             :         BOOL shadersOn = detailLevel >= DETAIL_LEVEL_SHADERS;
     948             : #else
     949             :         const BOOL shadersOn = NO;
     950             : #endif
     951             :         
     952             :         if (textureName != nil)
     953             :         {
     954             :                 NSDictionary *spec = [NSDictionary dictionaryWithObjectsAndKeys:textureName, @"name", @"yes", @"repeat_s", @"linear", @"min_filter", @"yes", @"cube_map", nil];
     955             :                 diffuseMap = [OOTexture textureWithConfiguration:spec];
     956             :                 if (diffuseMap == nil)  return;         // OOTexture will have logged a file-not-found warning.
     957             :                 if (shadersOn)  
     958             :                 {
     959             :                         [diffuseMap ensureFinishedLoading]; // only know if it is a cube map if it's loaded
     960             :                         if ([diffuseMap isCubeMap])
     961             :                         {
     962             :                                 macros = [materialDefaults oo_dictionaryForKey:isMoon ? @"moon-customized-cubemap-macros" : @"planet-customized-cubemap-macros"];
     963             :                         }
     964             :                         else
     965             :                         {
     966             :                                 macros = [materialDefaults oo_dictionaryForKey:isMoon ? @"moon-customized-macros" : @"planet-customized-macros"];
     967             :                         }
     968             :                 }
     969             :                 else textureName = @"dynamic";
     970             :                 
     971             :                  // let's try giving some love to normalMap too
     972             :                 if (_normSpecMapName)
     973             :                 {
     974             :                         NSDictionary *nspec = [NSDictionary dictionaryWithObjectsAndKeys:_normSpecMapName, @"name", @"yes", @"repeat_s", @"linear", @"min_filter", @"yes", @"cube_map", nil];
     975             :                         normalMap = [OOTexture textureWithConfiguration:nspec];
     976             :                         if (normalMap != nil) // OOTexture will have logged a file-not-found warning.
     977             :                         {
     978             :                                 if (shadersOn)  
     979             :                                 {
     980             :                                         [normalMap ensureFinishedLoading]; // only know if it is a cube map if it's loaded
     981             :                                         if ([normalMap isCubeMap])
     982             :                                         {
     983             :                                                 macros = [materialDefaults oo_dictionaryForKey:isMoon ? @"moon-customized-cubemap-normspec-macros" : @"planet-customized-cubemap-normspec-macros"];
     984             :                                         }
     985             :                                         else
     986             :                                         {
     987             :                                                 macros = [materialDefaults oo_dictionaryForKey:isMoon ? @"moon-customized-normspec-macros" : @"planet-customized-normspec-macros"];
     988             :                                         }
     989             :                                 }
     990             :                         }
     991             :                 }
     992             :         }
     993             :         else
     994             :         {
     995             :                 [OOPlanetTextureGenerator generatePlanetTexture:&diffuseMap
     996             :                                                                            secondaryTexture:(detailLevel >= DETAIL_LEVEL_SHADERS) ? &normalMap : NULL
     997             :                                                                                            withInfo:_materialParameters];
     998             : 
     999             :                 if (shadersOn)
    1000             :                 {
    1001             :                         macros = [materialDefaults oo_dictionaryForKey:isMoon ? @"moon-dynamic-macros" : @"planet-dynamic-macros"];
    1002             :                 }
    1003             :                 textureName = @"dynamic";
    1004             :         }
    1005             : 
    1006             :         /* Generate atmosphere texture */
    1007             :         if (!isMoon)
    1008             :         {
    1009             :                 if (shadersOn)
    1010             :                 {
    1011             :                         NSMutableDictionary *aConfig = [[[materialDefaults oo_dictionaryForKey:@"atmosphere-material"] mutableCopy] autorelease];
    1012             :                         [aConfig setObject:[NSArray arrayWithObjects:diffuseMap, normalMap, nil] forKey:@"_oo_texture_objects"];
    1013             :                         
    1014             :                         NSDictionary *amacros = [materialDefaults oo_dictionaryForKey:@"atmosphere-dynamic-macros"];
    1015             :                         
    1016             :                         OOMaterial *dynamicShaderMaterial = [OOShaderMaterial shaderMaterialWithName:@"dynamic"
    1017             :                                                                                                                                         configuration:aConfig
    1018             :                                                                                                                                         macros:amacros
    1019             :                                                                                                                                         bindingTarget:self];
    1020             :                                                                                                                                         
    1021             :                         if (dynamicShaderMaterial == nil)
    1022             :                         {
    1023             :                                 DESTROY(_atmosphereShaderDrawable);
    1024             :                         }
    1025             :                         else
    1026             :                         {
    1027             :                                 [_atmosphereShaderDrawable setMaterial:dynamicShaderMaterial];
    1028             :                         }
    1029             :                 }
    1030             :                 
    1031             :                 OOLog(@"texture.planet.generate",@"Preparing atmosphere for planet %@",self);
    1032             :                 /* Generate a standalone atmosphere texture */
    1033             :                 OOTexture *atmosphere = nil;
    1034             :                 [OOStandaloneAtmosphereGenerator generateAtmosphereTexture:&atmosphere
    1035             :                                                                                                                 withInfo:_materialParameters];
    1036             :                 
    1037             :                 OOLog(@"texture.planet.generate",@"Planet %@ has atmosphere %@",self,atmosphere);
    1038             :                 
    1039             :                 OOSingleTextureMaterial *dynamicMaterial = [[OOSingleTextureMaterial alloc] initWithName:@"dynamic" texture:atmosphere configuration:nil];
    1040             :                 [_atmosphereDrawable setMaterial:dynamicMaterial];
    1041             :                 [dynamicMaterial release];
    1042             :         }
    1043             : 
    1044             :         OOMaterial *material = nil;
    1045             :         
    1046             : #if OO_SHADERS
    1047             :         if (shadersOn)
    1048             :         {
    1049             :                 NSMutableDictionary *config = [[[materialDefaults oo_dictionaryForKey:@"planet-material"] mutableCopy] autorelease];
    1050             :                 [config setObject:[NSArray arrayWithObjects:diffuseMap, normalMap, nil] forKey:@"_oo_texture_objects"];
    1051             :                 
    1052             :                 material = [OOShaderMaterial shaderMaterialWithName:textureName
    1053             :                                                                                           configuration:config
    1054             :                                                                                                          macros:macros
    1055             :                                                                                           bindingTarget:self];
    1056             :         }
    1057             : #endif
    1058             :         if (material == nil)
    1059             :         {
    1060             :                 material = [[OOSingleTextureMaterial alloc] initWithName:textureName texture:diffuseMap configuration:nil];
    1061             :                 [material autorelease];
    1062             :         }
    1063             :         [_planetDrawable setMaterial:material];
    1064             : }
    1065             : 
    1066             : 
    1067             : - (BOOL) setUpPlanetFromTexture:(NSString *)textureName
    1068             : {
    1069             :         [self setTextureFileName:textureName];
    1070             :         return YES;
    1071             : }
    1072             : 
    1073             : 
    1074             : - (OOMaterial *) material
    1075             : {
    1076             :         return [_planetDrawable material];
    1077             : }
    1078             : 
    1079             : 
    1080             : - (OOMaterial *) atmosphereMaterial
    1081             : {
    1082             :         return [_atmosphereDrawable material];
    1083             : }
    1084             : 
    1085             : 
    1086             : - (OOMaterial *) atmosphereShaderMaterial
    1087             : {
    1088             :         if(!_atmosphereShaderDrawable)  return nil;
    1089             :         return [_atmosphereShaderDrawable material];
    1090             : }
    1091             : 
    1092             : 
    1093             : - (NSString *) name
    1094             : {
    1095             :         return _name;
    1096             : }
    1097             : 
    1098             : 
    1099             : - (void) setName:(NSString *)name
    1100             : {
    1101             :         [_name release];
    1102             :         _name = [name retain];
    1103             : }
    1104             : 
    1105             : @end
    1106             : 
    1107             : #endif  // NEW_PLANETS

Generated by: LCOV version 1.14