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

          Line data    Source code
       1           0 : /*
       2             : 
       3             : PlanetEntity.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 "PlanetEntity.h"
      26             : 
      27             : #if !NEW_PLANETS
      28             : 
      29             : #import "OOOpenGLExtensionManager.h"
      30             : 
      31             : #import "Universe.h"
      32             : #import "AI.h"
      33             : #import "TextureStore.h"
      34             : #import "OOTexture.h"
      35             : #import "OOTextureInternal.h" // For GL_TEXTURE_CUBE_MAP -- need to clean this up.
      36             : #import "OOPixMapTextureLoader.h"
      37             : #import "MyOpenGLView.h"
      38             : #import "ShipEntityAI.h"
      39             : #import "OOColor.h"
      40             : #import "OOCharacter.h"
      41             : #import "OOStringParsing.h"
      42             : #import "PlayerEntity.h"
      43             : #import "OOCollectionExtractors.h"
      44             : #import "OODebugFlags.h"
      45             : #import "OOGraphicsResetManager.h"
      46             : 
      47             : 
      48             : #if !OOLITE_MAC_OS_X
      49             : #define NSIntegerMapKeyCallBacks        NSIntMapKeyCallBacks
      50             : #define NSIntegerMapValueCallBacks      NSIntMapValueCallBacks
      51             : #endif
      52             : 
      53             : 
      54             : // straight C
      55           0 : static Vector base_vertex_array[MAX_PLANET_VERTICES];
      56           0 : static int base_terrain_array[MAX_PLANET_VERTICES];
      57           0 : static unsigned next_free_vertex;
      58           0 : static NSMapTable *sEdgeToVertex;
      59             : 
      60           0 : static int n_triangles[MAX_SUBDIVIDE];
      61           0 : static int triangle_start[MAX_SUBDIVIDE];
      62           0 : static GLuint vertex_index_array[3*(20+80+320+1280+5120+20480)];
      63             : 
      64           0 : static GLfloat  texture_uv_array[MAX_PLANET_VERTICES * 2];
      65             : 
      66             : 
      67             : @interface PlanetEntity (OOPrivate) <OOGraphicsResetClient>
      68             : 
      69           0 : - (double) sqrtZeroDistance;
      70             : 
      71           0 : - (void) drawModelWithVertexArraysAndSubdivision: (int) subdivide;
      72             : 
      73           0 : - (void) initialiseBaseVertexArray;
      74             : 
      75             : 
      76           0 : - (void) initialiseBaseTerrainArray:(int) percent_land;
      77           0 : - (void) paintVertex:(unsigned) vi :(int) seed;
      78           0 : - (void) scaleVertices;
      79             : 
      80           0 : - (id) initAsAtmosphereForPlanet:(PlanetEntity *)planet dictionary:(NSDictionary *)dict;
      81           0 : - (void) setTextureColorForPlanet:(BOOL)isMain inSystem:(BOOL)isLocal;
      82             : 
      83           0 : - (id) initMiniatureFromPlanet:(PlanetEntity*) planet withAlpha:(float) alpha;
      84             : 
      85           0 : - (void) loadTexture:(NSDictionary *)configuration;
      86           0 : - (OOTexture *) planetTextureWithInfo:(NSDictionary *)info;
      87           0 : - (OOTexture *) cloudTextureWithCloudColor:(OOColor *)cloudColor cloudImpress:(GLfloat)cloud_impress cloudBias:(GLfloat)cloud_bias;
      88             : 
      89           0 : - (void) deleteDisplayLists;
      90             : 
      91           0 : - (void) setUseTexturedModel:(BOOL)flag;
      92             : 
      93             : @end
      94             : 
      95           0 : static unsigned baseVertexIndexForEdge(GLushort va, GLushort vb, BOOL textured);
      96             : 
      97             : 
      98           0 : typedef struct
      99             : {
     100           0 :         unsigned                        v;
     101           0 :         float                           s;
     102           0 :         float                           t;
     103             : } BaseFace;
     104             : 
     105             : 
     106           0 : static const Vector kUntexturedVertices[] =
     107             : {
     108             :         { +0.000000, -0.850664, -0.525710 },
     109             :         { +0.000000, -0.850664, +0.525710 },
     110             :         { +0.000000, +0.850664, +0.525710 },
     111             :         { +0.000000, +0.850664, -0.525710 },
     112             :         { -0.525710, +0.000000, -0.850664 },
     113             :         { +0.525710, +0.000000, -0.850664 },
     114             :         { +0.525710, +0.000000, +0.850664 },
     115             :         { -0.525710, +0.000000, +0.850664 },
     116             :         { -0.850664, -0.525710, +0.000000 },
     117             :         { -0.850664, +0.525710, +0.000000 },
     118             :         { +0.850664, +0.525710, +0.000000 },
     119             :         { +0.850664, -0.525710, +0.000000 }
     120             : };
     121             : 
     122           0 : static const BaseFace kUntexturedFaces[][3] =
     123             : {
     124             :         { {  9, +0.600000, +0.666667 }, {  7, +0.800000, +0.666667 }, {  8, +0.800000, +0.333333 } },
     125             :         { {  8, +0.800000, +0.333333 }, {  4, +0.600000, +0.333333 }, {  9, +0.600000, +0.666667 } },
     126             :         { {  3, +0.400000, +0.666667 }, {  9, +0.600000, +0.666667 }, {  4, +0.600000, +0.333333 } },
     127             :         { {  8, +0.800000, +0.333333 }, {  0, +0.500000, +0.000000 }, {  4, +0.600000, +0.333333 } },
     128             :         { {  7, +0.800000, +0.666667 }, {  1, +1.000000, +0.333333 }, {  8, +0.800000, +0.333333 } },
     129             :         { {  2, +0.500000, +1.000000 }, {  7, +0.800000, +0.666667 }, {  9, +0.600000, +0.666667 } },
     130             :         { {  2, +0.500000, +1.000000 }, {  9, +0.600000, +0.666667 }, {  3, +0.400000, +0.666667 } },
     131             :         { {  1, +1.000000, +0.333333 }, {  0, +0.500000, +0.000000 }, {  8, +0.800000, +0.333333 } },
     132             :         { {  4, +0.600000, +0.333333 }, {  0, +0.500000, +0.000000 }, {  5, +0.400000, +0.333333 } },
     133             :         { {  5, +0.400000, +0.333333 }, {  3, +0.400000, +0.666667 }, {  4, +0.600000, +0.333333 } },
     134             :         { {  6, +1.000000, +0.666667 }, {  1, +1.000000, +0.333333 }, {  7, +0.800000, +0.666667 } },
     135             :         { {  7, +0.800000, +0.666667 }, {  2, +0.500000, +1.000000 }, {  6, +1.000000, +0.666667 } },
     136             :         { {  1, +0.000000, +0.333333 }, { 11, +0.200000, +0.333333 }, {  0, +0.500000, +0.000000 } },
     137             :         { {  3, +0.400000, +0.666667 }, { 10, +0.200000, +0.666667 }, {  2, +0.500000, +1.000000 } },
     138             :         { {  0, +0.500000, +0.000000 }, { 11, +0.200000, +0.333333 }, {  5, +0.400000, +0.333333 } },
     139             :         { {  5, +0.400000, +0.333333 }, { 10, +0.200000, +0.666667 }, {  3, +0.400000, +0.666667 } },
     140             :         { {  1, +0.000000, +0.333333 }, {  6, +0.000000, +0.666667 }, { 11, +0.200000, +0.333333 } },
     141             :         { {  6, +0.000000, +0.666667 }, {  2, +0.500000, +1.000000 }, { 10, +0.200000, +0.666667 } },
     142             :         { {  5, +0.400000, +0.333333 }, { 11, +0.200000, +0.333333 }, { 10, +0.200000, +0.666667 } },
     143             :         { { 11, +0.200000, +0.333333 }, {  6, +0.000000, +0.666667 }, { 10, +0.200000, +0.666667 } }
     144             : };
     145             : 
     146             : 
     147           0 : static const Vector kTexturedVertices[] =
     148             : {
     149             :         { +0.525731, +0.000000, +0.850651 },
     150             :         { -0.525731, +0.000000, +0.850651 },
     151             :         { +0.525731, +0.000000, -0.850651 },
     152             :         { -0.525731, +0.000000, -0.850651 },
     153             :         { +0.000000, +0.850651, +0.525731 },
     154             :         { +0.000000, +0.850651, -0.525731 },
     155             :         { +0.000000, -0.850651, +0.525731 },
     156             :         { +0.000000, -0.850651, -0.525731 },
     157             :         { -0.850651, +0.525731, +0.000000 },
     158             :         { +0.850651, +0.525731, +0.000000 },
     159             :         { -0.850651, -0.525731, +0.000000 },
     160             :         { +0.850651, -0.525731, +0.000000 },
     161             :         { +0.000000, +0.850651, -0.525731 },
     162             :         { +0.525731, +0.000000, -0.850651 }
     163             : };
     164             : 
     165           0 : static const BaseFace kTexturedFaces[][3] =
     166             : {
     167             :         { {  1, +0.400000, +0.666667 }, {  0, +0.600000, +0.666667 }, {  6, +0.500000, +0.333333 } },
     168             :         { {  3, +0.100000, +0.333333 }, {  2, -0.100000, +0.333333 }, {  5, +0.000000, +0.666667 } },
     169             :         { {  4, +0.500000, +1.000000 }, {  0, +0.600000, +0.666667 }, {  1, +0.400000, +0.666667 } },
     170             :         { {  4, +0.500000, +1.000000 }, {  1, +0.400000, +0.666667 }, {  8, +0.200000, +0.666667 } },
     171             :         { { 12, +1.000000, +0.666667 }, { 13, +0.900000, +0.333333 }, {  9, +0.800000, +0.666667 } },
     172             :         { {  5, +0.000000, +0.666667 }, {  4, +0.500000, +1.000000 }, {  8, +0.200000, +0.666667 } },
     173             :         { {  6, +0.500000, +0.333333 }, {  0, +0.600000, +0.666667 }, { 11, +0.700000, +0.333333 } },
     174             :         { {  7, +0.500000, +0.000000 }, {  2, -0.100000, +0.333333 }, {  3, +0.100000, +0.333333 } },
     175             :         { {  7, +0.500000, +0.000000 }, {  3, +0.100000, +0.333333 }, { 10, +0.300000, +0.333333 } },
     176             :         { {  7, +0.500000, +0.000000 }, {  6, +0.500000, +0.333333 }, { 11, +0.700000, +0.333333 } },
     177             :         { {  8, +0.200000, +0.666667 }, {  1, +0.400000, +0.666667 }, { 10, +0.300000, +0.333333 } },
     178             :         { {  8, +0.200000, +0.666667 }, {  3, +0.100000, +0.333333 }, {  5, +0.000000, +0.666667 } },
     179             :         { {  9, +0.800000, +0.666667 }, {  0, +0.600000, +0.666667 }, {  4, +0.500000, +1.000000 } },
     180             :         { {  9, +0.800000, +0.666667 }, { 13, +0.900000, +0.333333 }, { 11, +0.700000, +0.333333 } },
     181             :         { {  9, +0.800000, +0.666667 }, {  4, +0.500000, +1.000000 }, { 12, +1.000000, +0.666667 } },
     182             :         { { 10, +0.300000, +0.333333 }, {  1, +0.400000, +0.666667 }, {  6, +0.500000, +0.333333 } },
     183             :         { { 10, +0.300000, +0.333333 }, {  3, +0.100000, +0.333333 }, {  8, +0.200000, +0.666667 } },
     184             :         { { 10, +0.300000, +0.333333 }, {  6, +0.500000, +0.333333 }, {  7, +0.500000, +0.000000 } },
     185             :         { { 11, +0.700000, +0.333333 }, {  0, +0.600000, +0.666667 }, {  9, +0.800000, +0.666667 } },
     186             :         { { 11, +0.700000, +0.333333 }, { 13, +0.900000, +0.333333 }, {  7, +0.500000, +0.000000 } }
     187             : };
     188             : 
     189             : 
     190             : @implementation PlanetEntity
     191             : 
     192           0 : - (id) init
     193             : {
     194             :         [self release];
     195             :         [NSException raise:NSInternalInconsistencyException format:@"%s, believed dead, called.", __PRETTY_FUNCTION__];
     196             :         return nil;
     197             : }
     198             : 
     199             : 
     200           0 : - (id) initAsAtmosphereForPlanet:(PlanetEntity *)planet dictionary:(NSDictionary *)dict
     201             : {
     202             :         BOOL    procGen = [UNIVERSE doProcedurallyTexturedPlanets];
     203             :         
     204             :         if (dict == nil)  dict = [NSDictionary dictionary];
     205             :         
     206             :         self = [super init];
     207             :         
     208             :         int percent_land = 100 - [dict oo_intForKey:@"percent_cloud" defaultValue:100 - (3 + (gen_rnd_number() & 31)+(gen_rnd_number() & 31))];
     209             :         
     210             :         polar_color_factor = 1.0;
     211             :         
     212           0 : #define CLEAR_SKY_ALPHA                 0.05
     213           0 : #define CLOUD_ALPHA                             0.50
     214           0 : #define POLAR_CLEAR_SKY_ALPHA   0.34
     215           0 : #define POLAR_CLOUD_ALPHA               0.75
     216             :         
     217             :         amb_land[0] = gen_rnd_number() / 256.0;
     218             :         amb_land[1] = gen_rnd_number() / 256.0;
     219             :         amb_land[2] = gen_rnd_number() / 256.0;
     220             :         amb_land[3] = CLEAR_SKY_ALPHA;                          // blue sky, zero clouds
     221             :         amb_sea[0] = 0.5 + gen_rnd_number() / 512.0;
     222             :         amb_sea[1] = 0.5 + gen_rnd_number() / 512.0;
     223             :         amb_sea[2] = 0.5 + gen_rnd_number() / 512.0;
     224             :         amb_sea[3] = CLOUD_ALPHA;                                       // 50% opaque clouds
     225             :         amb_polar_land[0] = gen_rnd_number() / 256.0;
     226             :         amb_polar_land[1] = gen_rnd_number() / 256.0;
     227             :         amb_polar_land[2] = gen_rnd_number() / 256.0;
     228             :         amb_polar_land[3] = POLAR_CLEAR_SKY_ALPHA;      // 34% gray clouds
     229             :         amb_polar_sea[0] = 0.9 + gen_rnd_number() / 2560.0;
     230             :         amb_polar_sea[1] = 0.9 + gen_rnd_number() / 2560.0;
     231             :         amb_polar_sea[2] = 0.9 + gen_rnd_number() / 2560.0;
     232             :         amb_polar_sea[3] = POLAR_CLOUD_ALPHA;           // 75% clouds
     233             :         
     234             :         // Colour overrides from dictionary
     235             :         OOColor         *clearSkyColor = nil;
     236             :         OOColor         *cloudColor = nil;
     237             :         OOColor         *polarClearSkyColor = nil;
     238             :         OOColor         *polarCloudColor = nil;
     239             :         float           cloudAlpha;
     240             :         
     241             :         
     242             :         clearSkyColor = [OOColor colorWithDescription:[dict objectForKey:@"atmosphere_color"]];
     243             :         cloudColor = [OOColor colorWithDescription:[dict objectForKey:@"cloud_color"]];
     244             :         polarClearSkyColor = [OOColor colorWithDescription:[dict objectForKey:@"polar_atmosphere_color"]];
     245             :         polarCloudColor = [OOColor colorWithDescription:[dict objectForKey:@"polar_cloud_color"]];
     246             :         cloudAlpha = OOClamp_0_1_f([dict oo_floatForKey:@"cloud_alpha" defaultValue:1.0]);
     247             :         
     248             :         if (clearSkyColor != nil)
     249             :         {
     250             :                 [clearSkyColor getRed:&amb_land[0] green:&amb_land[1] blue:&amb_land[2] alpha:&amb_land[3]];
     251             :         }
     252             :         
     253             :         if (cloudColor != nil)
     254             :         {
     255             :                 [cloudColor getRed:&amb_sea[0] green:&amb_sea[1] blue:&amb_sea[2] alpha:&amb_sea[3]];
     256             :         }
     257             :         
     258             :         if (polarClearSkyColor != nil)
     259             :         {
     260             :                 [polarClearSkyColor getRed:&amb_polar_land[0] green:&amb_polar_land[1] blue:&amb_polar_land[2] alpha:&amb_polar_land[3]];
     261             :         }
     262             :         else if (clearSkyColor != nil)
     263             :         {
     264             :                 memmove(amb_polar_land, amb_land, sizeof amb_polar_land);
     265             :                 amb_polar_land[3] = OOClamp_0_1_f(amb_polar_land[3] * (POLAR_CLEAR_SKY_ALPHA / CLEAR_SKY_ALPHA));
     266             :         }
     267             :         
     268             :         if (polarCloudColor != nil)
     269             :         {
     270             :                 [polarCloudColor getRed:&amb_polar_sea[0] green:&amb_polar_sea[1] blue:&amb_polar_sea[2] alpha:&amb_polar_sea[3]];
     271             :         }
     272             :         else if (cloudColor != nil)
     273             :         {
     274             :                 memmove(amb_polar_sea, amb_sea, sizeof amb_polar_sea);
     275             :                 amb_polar_sea[3] *= (POLAR_CLOUD_ALPHA / CLOUD_ALPHA);
     276             :         }
     277             :         
     278             :         //amb_land[3] is already 0.05
     279             :         amb_sea[3] *= cloudAlpha;
     280             :         amb_polar_land[3] *= cloudAlpha;
     281             :         amb_polar_sea[3] *= cloudAlpha;
     282             :         
     283             :         amb_sea[3] = OOClamp_0_1_f(amb_sea[3]);
     284             :         amb_polar_sea[3] = OOClamp_0_1_f(amb_polar_sea[3]);
     285             :         
     286             :         atmosphere = nil;
     287             :         
     288             :         if (procGen)
     289             :         {
     290             :                 RANROTSeed ranrotSavedSeed = RANROTGetFullSeed();
     291             :                 RNG_Seed saved_seed = currentRandomSeed();
     292             :                 cloudColor = [OOColor colorWithRed: amb_sea[0] green: amb_sea[1] blue: amb_sea[2] alpha: amb_sea[3]];
     293             :                 float cloud_bias = -0.01 * (float)percent_land;
     294             :                 float cloud_impress = 1.0 - cloud_bias;
     295             :                 
     296             :                 _texture = [self cloudTextureWithCloudColor:cloudColor cloudImpress:cloud_impress cloudBias:cloud_bias];
     297             :                 [_texture retain];
     298             :                 isTextureImage = NO;
     299             :                 
     300             :                 setRandomSeed(saved_seed);
     301             :                 RANROTSetFullSeed(ranrotSavedSeed);
     302             :         }
     303             :         
     304             :         if (!planet)
     305             :         {
     306             :                 OOLogERR(@"planet.atmosphere.init.noPlanet", @"planet entity initAsAtmosphereForPlanet: no planet found.");
     307             :                 return self;
     308             :         }
     309             :         
     310             :         [self setOwner: planet];
     311             :         
     312             :         position = [planet position];
     313             :         orientation = [planet orientation];
     314             :         
     315             :         if (planet->planet_type == STELLAR_TYPE_NORMAL_PLANET)
     316             :                 collision_radius = planet->collision_radius + ATMOSPHERE_DEPTH; //  atmosphere is 500m deep only
     317             :         if (planet->planet_type == STELLAR_TYPE_MINIATURE)
     318             :                 collision_radius = planet->collision_radius + ATMOSPHERE_DEPTH * PLANET_MINIATURE_FACTOR*2.0; //not to scale: invisible otherwise
     319             :         
     320             :         shuttles_on_ground = 0;
     321             :         last_launch_time = 0.0;
     322             :         shuttle_launch_interval = 3600.0;
     323             :         
     324             :         scanClass = CLASS_NO_DRAW;
     325             :         
     326             :         // orientation.w =  M_SQRT1_2; // is already planet->orientation
     327             :         // orientation.x =  M_SQRT1_2;
     328             :         // orientation.y =  0.0;
     329             :         // orientation.z =  0.0;
     330             :         
     331             :         planet_type =   STELLAR_TYPE_ATMOSPHERE;
     332             :         
     333             :         planet_seed =   ranrot_rand();  // random set-up for vertex colours
     334             :         
     335             :         [self setUseTexturedModel:YES];
     336             :         [self initialiseBaseVertexArray];
     337             :         [self initialiseBaseTerrainArray:percent_land];
     338             :         unsigned i;
     339             :         for (i =  0; i < next_free_vertex; i++)
     340             :         {
     341             :                 [self paintVertex:i :planet_seed];
     342             :         }
     343             :         
     344             :         [self scaleVertices];
     345             : 
     346             :         // set speed of rotation
     347             :         rotational_velocity = [dict oo_floatForKey:@"atmosphere_rotational_velocity" defaultValue:[planet rotationalVelocity]*(0.9+(randf()*0.2))]; // 90-110% of planet rotation speed
     348             :         
     349             :         root_planet = planet;
     350             :         
     351             :         rotationAxis = vector_up_from_quaternion(orientation);
     352             :         
     353             :         [[OOGraphicsResetManager sharedManager] registerClient:self];
     354             :         
     355             :         return self;
     356             : }
     357             : 
     358             : 
     359             : - (void) miniaturize
     360             : {
     361             :         planet_type = STELLAR_TYPE_MINIATURE;
     362             :         shuttles_on_ground = 0;
     363             :         last_launch_time = 0.0;
     364             :         shuttle_launch_interval = 3600.0;
     365             :         [self setStatus:STATUS_COCKPIT_DISPLAY];
     366             :         collision_radius = [self collisionRadius] * PLANET_MINIATURE_FACTOR; // teeny tiny
     367             :         [self scaleVertices];
     368             :         if (atmosphere != nil)
     369             :         {
     370             :                 atmosphere->collision_radius = collision_radius + ATMOSPHERE_DEPTH * PLANET_MINIATURE_FACTOR*2.0; //not to scale: invisible otherwise
     371             :                 [atmosphere scaleVertices];
     372             :         }
     373             :         rotational_velocity = 0.04;
     374             :         rotationAxis = kBasisYVector;
     375             : }
     376             : 
     377             : 
     378             : - (id) initFromDictionary:(NSDictionary*)dict withAtmosphere:(BOOL)atmo andSeed:(Random_Seed)p_seed
     379             : {
     380             :         BOOL procGen = [UNIVERSE doProcedurallyTexturedPlanets];
     381             :         
     382             :         if (dict == nil)  dict = [NSDictionary dictionary];
     383             :         RANROTSeed ranrotSavedSeed = RANROTGetFullSeed();
     384             :         
     385             :         self = [super init];
     386             :         
     387             :         planet_type =  atmo ? STELLAR_TYPE_NORMAL_PLANET : STELLAR_TYPE_MOON;
     388             :         
     389             :         if (atmo)
     390             :                 planet_seed = p_seed.a * 13 + p_seed.c * 11 + p_seed.e * 7;     // pseudo-random set-up for vertex colours
     391             :         else
     392             :                 planet_seed = p_seed.a * 7 + p_seed.c * 11 + p_seed.e * 13;     // pseudo-random set-up for vertex colours
     393             :         
     394             :         OOTexture *texture = [dict oo_objectOfClass:[OOTexture class] forKey:@"_oo_textureObject"];
     395             :         if (texture != nil)
     396             :         {
     397             :                 _texture = [texture retain];
     398             :                 isTextureImage = [dict oo_boolForKey:@"_oo_isExplicitlyTextured"];
     399             :         }
     400             :         else
     401             :         {
     402             :                 NSDictionary *textureSpec = [dict oo_textureSpecifierForKey:@"texture" defaultName:nil];
     403             :                 if (textureSpec != nil)
     404             :                 {
     405             :                         [self loadTexture:textureSpec];
     406             :                 }
     407             : 
     408             : // CIM: nothing actually uses textureSpec after the assignment below, so skip it
     409             : /*              if (textureSpec == nil && !procGen && !atmo)
     410             :                 {
     411             :                         // Moons use metal.png by default.
     412             :                         textureSpec = OOTextureSpecFromObject(@"metal.png", nil);
     413             :                         } */
     414             :                 
     415             :                 NSString *seedStr = [dict oo_stringForKey:@"seed"];
     416             :                 if (seedStr != nil)
     417             :                 {
     418             :                         Random_Seed seed = RandomSeedFromString(seedStr);
     419             :                         if (!is_nil_seed(seed))
     420             :                         {
     421             :                                 p_seed = seed;
     422             :                         }
     423             :                         else
     424             :                         {
     425             :                                 OOLogERR(@"planet.fromDict", @"could not interpret \"%@\" as planet seed, using default.", seedStr);
     426             :                         }
     427             :                 }
     428             :         }
     429             :         
     430             :         seed_for_planet_description(p_seed);
     431             :         
     432             :         NSMutableDictionary     *planetInfo = [NSMutableDictionary dictionaryWithDictionary:[UNIVERSE generateSystemData:p_seed]];
     433             :         int     radius_km = [dict oo_intForKey:KEY_RADIUS 
     434             :                                                 defaultValue:[planetInfo oo_intForKey:KEY_RADIUS]];
     435             :         int techlevel = [dict oo_intForKey:KEY_TECHLEVEL
     436             :                                                 defaultValue:[planetInfo oo_intForKey:KEY_TECHLEVEL]];
     437             :         
     438             :         shuttles_on_ground = 1 + floor(techlevel * 0.5);
     439             :         last_launch_time = 0.0;
     440             :         shuttle_launch_interval = 3600.0 / shuttles_on_ground; // all are launched in an hour
     441             : 
     442             :         last_launch_time = [UNIVERSE getTime] + 30.0 - shuttle_launch_interval;   // debug - launch 30s after player enters universe
     443             : 
     444             :         collision_radius = radius_km * 10.0; // scale down by a factor of 100 !
     445             :         
     446             :         scanClass = CLASS_NO_DRAW;
     447             :         
     448             :         orientation.w =  M_SQRT1_2;
     449             :         orientation.x =  M_SQRT1_2;
     450             :         orientation.y =  0.0;
     451             :         orientation.z =  0.0;
     452             :         
     453             :         [self setUseTexturedModel:(procGen || _texture != nil)];
     454             :         
     455             :         int percent_land = [planetInfo oo_intForKey:@"percent_land" defaultValue:24 + (gen_rnd_number() % 48)];
     456             :         //if (isTextured)  percent_land =  atmo ? 0 :100; // moon/planet override
     457             :         
     458             :         // save the current random number generator seed
     459             :         RNG_Seed saved_seed = currentRandomSeed();
     460             :         
     461             :         // For historical reasons, stir the PRNG vertexCount times.
     462             :         unsigned i;
     463             :         for (i = 0; i < vertexCount; i++)  gen_rnd_number();
     464             :         
     465             :         [planetInfo setObject:[NSNumber numberWithFloat:0.01 * percent_land] forKey:@"land_fraction"];
     466             :         
     467             :         polar_color_factor = [dict oo_doubleForKey:@"polar_color_factor" defaultValue:0.5f];
     468             :         
     469             :         Vector land_hsb, sea_hsb, land_polar_hsb, sea_polar_hsb;
     470             :         
     471             :         if (isTextureImage)
     472             :         {
     473             :                 // standard overlay colours.
     474             :                 land_hsb.x = 0.0;       land_hsb.y = 0.0;       land_hsb.z = 1.0;       // non-saturated fully bright (white)
     475             :                 sea_hsb.x = 0.0;        sea_hsb.y = 1.0;        sea_hsb.z = 1.0;        // fully-saturated fully bright (red)   
     476             :                 // override the mainPlanet texture colour...
     477             :                 [self setTextureColorForPlanet:!![dict objectForKey:@"mainForLocalSystem"] inSystem:[dict oo_boolForKey:@"mainForLocalSystem" defaultValue:NO]];
     478             :         }
     479             :         else
     480             :         {
     481             :                 // random land & sea colours.
     482             :                 land_hsb.x = gen_rnd_number() / 256.0;  land_hsb.y = gen_rnd_number() / 256.0;  land_hsb.z = 0.5 + gen_rnd_number() / 512.0;
     483             :                 sea_hsb.x = gen_rnd_number() / 256.0;  sea_hsb.y = gen_rnd_number() / 256.0;  sea_hsb.z = 0.5 + gen_rnd_number() / 512.0;
     484             :                 while (dot_product(land_hsb,sea_hsb) > .80) // make sure land and sea colors differ significantly
     485             :                 {
     486             :                         sea_hsb.x = gen_rnd_number() / 256.0;  sea_hsb.y = gen_rnd_number() / 256.0;  sea_hsb.z = 0.5 + gen_rnd_number() / 512.0;
     487             :                 }
     488             :                 
     489             :                 // assign land_hsb and sea_hsb overrides from planetinfo.plist if they're there.
     490             :                 ScanVectorFromString([dict objectForKey:@"land_hsb_color"], &land_hsb);
     491             :                 ScanVectorFromString([dict objectForKey:@"sea_hsb_color"], &sea_hsb);
     492             :                 
     493             :                 // polar areas are brighter but have less color (closer to white)
     494             :                 land_polar_hsb.x = land_hsb.x;  land_polar_hsb.y = (land_hsb.y / 4.0);  land_polar_hsb.z = 1.0 - (land_hsb.z / 10.0);
     495             :                 sea_polar_hsb.x = sea_hsb.x;  sea_polar_hsb.y = (sea_hsb.y / 4.0);  sea_polar_hsb.z = 1.0 - (sea_hsb.z / 10.0);
     496             :                 
     497             :                 OOColor *amb_land_color = [OOColor colorWithHue:land_hsb.x saturation:land_hsb.y brightness:land_hsb.z alpha:1.0];
     498             :                 OOColor *amb_sea_color = [OOColor colorWithHue:sea_hsb.x saturation:sea_hsb.y brightness:sea_hsb.z alpha:1.0];
     499             :                 OOColor *amb_polar_land_color = [OOColor colorWithHue:land_polar_hsb.x saturation:land_polar_hsb.y brightness:land_polar_hsb.z alpha:1.0];
     500             :                 OOColor *amb_polar_sea_color = [OOColor colorWithHue:sea_polar_hsb.x saturation:sea_polar_hsb.y brightness:sea_polar_hsb.z alpha:1.0];
     501             :                 
     502             :                 amb_land[0] = [amb_land_color redComponent];
     503             :                 amb_land[1] = [amb_land_color blueComponent];
     504             :                 amb_land[2] = [amb_land_color greenComponent];
     505             :                 amb_land[3] = 1.0;
     506             :                 amb_sea[0] = [amb_sea_color redComponent];
     507             :                 amb_sea[1] = [amb_sea_color blueComponent];
     508             :                 amb_sea[2] = [amb_sea_color greenComponent];
     509             :                 amb_sea[3] = 1.0;
     510             :                 amb_polar_land[0] = [amb_polar_land_color redComponent];
     511             :                 amb_polar_land[1] = [amb_polar_land_color blueComponent];
     512             :                 amb_polar_land[2] = [amb_polar_land_color greenComponent];
     513             :                 amb_polar_land[3] = 1.0;
     514             :                 amb_polar_sea[0] = [amb_polar_sea_color redComponent];
     515             :                 amb_polar_sea[1] = [amb_polar_sea_color blueComponent];
     516             :                 amb_polar_sea[2] = [amb_polar_sea_color greenComponent];
     517             :                 amb_polar_sea[3] = 1.0;
     518             :                 
     519             :                 [planetInfo setObject:amb_land_color forKey:@"land_color"];
     520             :                 [planetInfo setObject:amb_sea_color forKey:@"sea_color"];
     521             :                 [planetInfo setObject:amb_polar_land_color forKey:@"polar_land_color"];
     522             :                 [planetInfo setObject:amb_polar_sea_color forKey:@"polar_sea_color"];
     523             :         }
     524             : 
     525             :         if (procGen && _texture == nil)
     526             :         {
     527             :                 _texture = [self planetTextureWithInfo:planetInfo];
     528             :                 isTextureImage = NO;
     529             :                 [_texture retain];
     530             :         }
     531             :         
     532             :         [self initialiseBaseVertexArray];
     533             :         [self initialiseBaseTerrainArray:percent_land];
     534             :         
     535             :         for (i = 0; i < next_free_vertex; i++)
     536             :         {
     537             :                 [self paintVertex:i :planet_seed];
     538             :         }
     539             :         
     540             :         [self scaleVertices];
     541             :         // set speed of rotation        
     542             :         if ([dict objectForKey:@"rotational_velocity"])
     543             :         {
     544             :                 rotational_velocity = [dict oo_floatForKey:@"rotational_velocity" defaultValue:0.01f * randf()];      // 0.0 .. 0.01 avr 0.005
     545             :         }
     546             :         else
     547             :         {
     548             :                 rotational_velocity = [planetInfo oo_floatForKey:@"rotation_speed" defaultValue:0.002 * (0.5+0.5*randf())]; // 0.001 .. 0.002 avr 0.0015
     549             :                 rotational_velocity *= [planetInfo oo_floatForKey:@"rotation_speed_factor" defaultValue:1.0f];
     550             :         }
     551             : 
     552             :         // do atmosphere
     553             :         NSDictionary *atmoDict = dict;
     554             :         if (_texture != nil)  atmoDict =        [NSDictionary dictionaryWithObjectsAndKeys:@"0", @"percent_cloud", [NSNumber numberWithFloat:[planetInfo oo_floatForKey:@"cloud_alpha" defaultValue:1.0]], @"cloud_alpha", nil];
     555             :         if (atmo)  atmosphere = [[PlanetEntity alloc] initAsAtmosphereForPlanet:self dictionary:atmoDict];
     556             :         
     557             :         setRandomSeed(saved_seed);
     558             :         RANROTSetFullSeed(ranrotSavedSeed);
     559             : 
     560             :         // set energy
     561             :         energy = collision_radius * 1000.0;
     562             :         
     563             :         root_planet = self;
     564             :         
     565             :         rotationAxis = vector_up_from_quaternion(orientation);
     566             : 
     567             :         /* MKW - rotate planet based on current time.
     568             :          *     - do it here so that we catch all planets (OXP-added and otherwise! */
     569             :         int             deltaT = floor(fmod([PLAYER clockTimeAdjusted], 86400));
     570             :         quaternion_rotate_about_axis(&orientation, rotationAxis, rotational_velocity * deltaT);
     571             : 
     572             :         [self setStatus:STATUS_ACTIVE];
     573             :         
     574             :         [[OOGraphicsResetManager sharedManager] registerClient:self];
     575             :         
     576             :         return self;
     577             : }
     578             : 
     579             : 
     580           0 : - (void) dealloc
     581             : {
     582             :         [self deleteDisplayLists];
     583             :         
     584             :         DESTROY(atmosphere);
     585             :         DESTROY(_texture);
     586             :         DESTROY(_textureFileName);
     587             :         
     588             :         [[OOGraphicsResetManager sharedManager] unregisterClient:self];
     589             :         
     590             :         [super dealloc];
     591             : }
     592             : 
     593             : 
     594           0 : - (NSString*) descriptionComponents
     595             : {
     596             :         NSString *typeString;
     597             :         switch (planet_type)
     598             :         {
     599             :                 case STELLAR_TYPE_MINIATURE:
     600             :                         typeString = @"STELLAR_TYPE_MINIATURE";       break;
     601             :                 case STELLAR_TYPE_NORMAL_PLANET:
     602             :                         typeString = @"STELLAR_TYPE_NORMAL_PLANET";   break;
     603             :                 case STELLAR_TYPE_ATMOSPHERE:
     604             :                         typeString = @"STELLAR_TYPE_ATMOSPHERE";      break;
     605             :                 case STELLAR_TYPE_MOON:
     606             :                         typeString = @"STELLAR_TYPE_MOON";    break;
     607             :                 
     608             :                 default:
     609             :                         typeString = @"UNKNOWN";
     610             :         }
     611             :         return [NSString stringWithFormat:@"ID: %u position: %@ type: %@ radius: %.3fkm", [self universalID], HPVectorDescription([self position]), typeString, 0.001 * [self radius]];
     612             : }
     613             : 
     614             : 
     615           0 : - (BOOL) canCollide
     616             : {
     617             :         switch (planet_type)
     618             :         {
     619             :                 case STELLAR_TYPE_MINIATURE:
     620             :                 case STELLAR_TYPE_ATMOSPHERE:
     621             :                         return NO;
     622             :                         break;
     623             :                 case STELLAR_TYPE_MOON:
     624             :                 case STELLAR_TYPE_NORMAL_PLANET:
     625             :                 case STELLAR_TYPE_SUN:
     626             :                         return YES;
     627             :                         break;
     628             :         }
     629             :         return YES;
     630             : }
     631             : 
     632             : 
     633           0 : - (BOOL) checkCloseCollisionWith:(Entity *)other
     634             : {
     635             : #ifndef NDEBUG
     636             :         if (gDebugFlags & DEBUG_COLLISIONS)
     637             :                 OOLog(@"planet.collide", @"PLANET Collision!");
     638             : #endif
     639             :         
     640             :         if (!other)
     641             :                 return NO;
     642             :         if (other->isShip)
     643             :         {
     644             :                 ShipEntity *ship = (ShipEntity *)other;
     645             :                 if ([ship behaviour] == BEHAVIOUR_LAND_ON_PLANET)
     646             :                 {
     647             :                         return NO;
     648             :                 }
     649             : #ifndef NDEBUG
     650             :                 if ([ship reportAIMessages])
     651             :                 {
     652             :                         HPVector p1 = ship->position;
     653             :                         OOLog(@"planet.collide.shipHit", @"DEBUG: %@ %d collided with planet at (%.1f,%.1f,%.1f)",[ship name], [ship universalID], p1.x,p1.y,p1.z);
     654             :                 }
     655             : #endif
     656             :         }
     657             : 
     658             :         return YES;
     659             : }
     660             : 
     661             : 
     662           0 : - (void) update:(OOTimeDelta) delta_t
     663             : {
     664             :         [super update:delta_t];
     665             :         sqrt_zero_distance = sqrt(cam_zero_distance);
     666             : 
     667             :         switch (planet_type)
     668             :         {
     669             :                 case STELLAR_TYPE_NORMAL_PLANET:
     670             :                         // we have atmosphere in any case.
     671             :                         {
     672             :                                 double alt = sqrt_zero_distance - collision_radius;
     673             :                                 double atmo = 10.0 * (atmosphere->collision_radius - collision_radius);      // effect starts at 10x the height of the clouds
     674             : 
     675             :                                 if ((alt > 0)&&(alt <= atmo))
     676             :                                 {
     677             :                                         double aleph = (atmo - alt) / atmo;
     678             :                                         if (aleph < 0.0) aleph = 0.0;
     679             :                                         if (aleph > 1.0) aleph = 1.0;
     680             :                                         
     681             :                                         [UNIVERSE setSkyColorRed:0.8 * aleph * aleph
     682             :                                                                            green:0.8 * aleph * aleph
     683             :                                                                                 blue:0.9 * aleph
     684             :                                                                            alpha:aleph];
     685             :                                 }
     686             :                                 else if (alt > 0 && alt <= atmo * 1.5)
     687             :                                 {
     688             :                                         /* Without this, if you leave the atmosphere at very low
     689             :                                          * frame rates, you might still have skyalpha > 0 when you
     690             :                                          * go sun-skimming. Since skyalpha > 0 simulates atmospheric
     691             :                                          * friction and continually pumps heat into the ship, this
     692             :                                          * is rapidly fatal - CIM */
     693             :                                         [UNIVERSE setSkyColorRed:0.0f
     694             :                                                                                                                  green:0.0f
     695             :                                                                                                                         blue:0.0f
     696             :                                                                                                                  alpha:0.0f];
     697             :                                 }
     698             :                         }
     699             :                 case STELLAR_TYPE_MOON:
     700             :                         {
     701             :                                 double ugt = [UNIVERSE getTime];
     702             : 
     703             :                                 if ((shuttles_on_ground > 0)&&(ugt > last_launch_time + shuttle_launch_interval))
     704             :                                 {
     705             :                                         [self launchShuttle];
     706             :                                         shuttles_on_ground--;
     707             :                                         last_launch_time = ugt;
     708             :                                 }
     709             :                         }
     710             :                 
     711             :                 case STELLAR_TYPE_MINIATURE:
     712             :                         // normal planetary rotation
     713             :                         if (atmosphere) [atmosphere update:delta_t];
     714             :                         quaternion_rotate_about_axis(&orientation, rotationAxis, rotational_velocity * delta_t);
     715             :                         [self orientationChanged];
     716             :                         break;
     717             : 
     718             :                 case STELLAR_TYPE_ATMOSPHERE:
     719             :                         {
     720             :                                 // atmospheric rotation
     721             :                                 quaternion_rotate_about_axis(&orientation, rotationAxis, rotational_velocity * delta_t);
     722             :                                 [self orientationChanged];
     723             :                         }
     724             :                         break;
     725             :                 
     726             :                 case STELLAR_TYPE_SUN:
     727             :                         break;
     728             :         }
     729             : }
     730             : 
     731             : 
     732           0 : - (void) setPosition:(HPVector)posn
     733             : {
     734             :         position = posn;
     735             :         [atmosphere setPosition:posn];
     736             : }
     737             : 
     738             : 
     739           0 : - (void) setOrientation:(Quaternion)inOrientation
     740             : {
     741             :         rotationAxis = vector_up_from_quaternion(inOrientation);
     742             :         [super setOrientation:inOrientation];
     743             :         if (atmosphere) [atmosphere setOrientation:inOrientation];
     744             : }
     745             : 
     746             : 
     747           0 : - (void) setUseTexturedModel:(BOOL)flag
     748             : {
     749             :         if (flag)
     750             :         {
     751             :                 useTexturedModel = YES;
     752             :                 vertexCount = sizeof kTexturedVertices / sizeof *kTexturedVertices;
     753             :         }
     754             :         else
     755             :         {
     756             :                 useTexturedModel = NO;
     757             :                 vertexCount = sizeof kUntexturedVertices / sizeof *kTexturedVertices;
     758             :         }
     759             : }
     760             : 
     761             : 
     762             : // TODO: some translucent stuff is drawn in the opaque pass, which is Naughty.
     763           0 : - (void) drawImmediate:(bool)immediate translucent:(bool)translucent
     764             : {
     765             :         if ([UNIVERSE breakPatternHide] || translucent || immediate)  return;  // DON'T DRAW
     766             :         GLfloat radWithAtmosphere = [self radius] + ATMOSPHERE_DEPTH;
     767             :         if (radWithAtmosphere * radWithAtmosphere * 1.1 < cam_zero_distance)
     768             :         {
     769             :                 // for some reason this check doesn't work when extremely close to
     770             :                 // the planet and with the horizon near the side of the frame (FP
     771             :                 // inaccuracy?)
     772             :                 if (![UNIVERSE viewFrustumIntersectsSphereAt:cameraRelativePosition withRadius:radWithAtmosphere])
     773             :                 {
     774             :                         // Don't draw
     775             :                         return;
     776             :                 }
     777             :         }
     778             : 
     779             :         [self drawUnconditionally];
     780             : }
     781             : 
     782             : 
     783             : - (void) drawUnconditionally
     784             : {
     785             :         uint8_t subdivideLevel =        2;              // 4 is probably the maximum!
     786             :         
     787             :         double  drawFactor = [[UNIVERSE gameView] viewSize].width / 100.0;
     788             :         double  drawRatio2 = drawFactor * collision_radius / sqrt_zero_distance; // equivalent to size on screen in pixels
     789             :         
     790             :         if (cam_zero_distance > 0.0)
     791             :         {
     792             :                 subdivideLevel = 2 + floor(drawRatio2);
     793             :                 if (subdivideLevel > 4)  subdivideLevel = 4;
     794             :         }
     795             :         
     796             :         if (planet_type == STELLAR_TYPE_MINIATURE)
     797             :         {
     798             :                 subdivideLevel = [UNIVERSE reducedDetail]? 3 : 4;               // max detail or less
     799             :         }
     800             :                 
     801             :         lastSubdivideLevel = subdivideLevel;    // record
     802             :         
     803             :         OOSetOpenGLState(OPENGL_STATE_OPAQUE);
     804             :         OOGL(glPushAttrib(GL_ENABLE_BIT));
     805             :         
     806             : //      OOGL(glEnable(GL_LIGHTING));
     807             : //      OOGL(glEnable(GL_LIGHT1));
     808             :         GLfloat specular[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
     809             :         OOGL(glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular));
     810             :         OOGL(glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 0));
     811             :         
     812             :         /*
     813             : 
     814             :         The depth test gets disabled in parts of this and instead
     815             :         we rely on the painters algorithm instead.
     816             : 
     817             :         The depth buffer isn't granular enough to cope with huge objects at vast
     818             :         distances.
     819             : 
     820             :         */
     821             :         
     822             :         BOOL ignoreDepthBuffer = (planet_type == STELLAR_TYPE_ATMOSPHERE);
     823             :         
     824             :         if (cam_zero_distance > collision_radius * collision_radius * 25) // is 'far away'
     825             :         {
     826             :                 ignoreDepthBuffer |= YES;
     827             :         }
     828             :         
     829             :         [_texture ensureFinishedLoading];
     830             :         
     831             :         switch (planet_type)
     832             :         {
     833             :                 case STELLAR_TYPE_ATMOSPHERE:
     834             :                         if (root_planet)
     835             :                         {
     836             :                                 subdivideLevel = root_planet->lastSubdivideLevel;    // copy it from the planet (stops jerky LOD and such)
     837             :                         }
     838             :                         OOGLMultModelVew(rotMatrix);    // rotate the clouds!
     839             :                         OOGL(glEnable(GL_BLEND));
     840             : //                      OOGL(glDisable(GL_LIGHTING));
     841             :                         // Fall through.
     842             : 
     843             :                 case STELLAR_TYPE_MOON:
     844             :                 case STELLAR_TYPE_NORMAL_PLANET:
     845             :                 case STELLAR_TYPE_MINIATURE:
     846             :                         //if ((gDebugFlags & DEBUG_WIREFRAME_GRAPHICS)
     847             :                         if ([UNIVERSE wireframeGraphics])
     848             :                         {
     849             :                                 // Drop the detail level a bit, it still looks OK in wireframe and does not penalize
     850             :                                 // the system that much.
     851             :                                 subdivideLevel = 2;
     852             :                                 OOGLWireframeModeOn();
     853             :                         }
     854             :                         
     855             :                         {
     856             :                                 GLfloat mat1[]          = { 1.0, 1.0, 1.0, 1.0 };       // opaque white
     857             :                                 
     858             :                                 if (_texture != nil)
     859             :                                 {
     860             :                                         if ([_texture isCubeMap])
     861             :                                         {
     862             : #if OO_TEXTURE_CUBE_MAP
     863             :                                                 OOGL(glDisable(GL_TEXTURE_2D));
     864             :                                                 OOGL(glEnable(GL_TEXTURE_CUBE_MAP));
     865             : #endif
     866             :                                         }
     867             :                                         else
     868             :                                         {
     869             : //                                              OOGL(glEnable(GL_TEXTURE_2D));
     870             :                                         }
     871             :                                         OOGL(glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, mat1));
     872             :                                         [_texture apply];
     873             :                                 }
     874             :                                 else
     875             :                                 {
     876             :                                         OOGL(glDisable(GL_TEXTURE_2D));
     877             :                                         [OOTexture applyNone];
     878             :                                 }
     879             : 
     880             :                                 OOGL(glShadeModel(GL_SMOOTH));
     881             :                                 
     882             :                                 // far enough away to draw flat ?
     883             :                                 if (ignoreDepthBuffer)
     884             :                                 {
     885             :                                         OOGL(glDisable(GL_DEPTH_TEST));
     886             :                                 }
     887             : 
     888             :                                 OOGL(glColor4fv(mat1));
     889             :                                 OOGL(glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mat1));
     890             :                                 
     891             :                                 OOGL(glEnableClientState(GL_COLOR_ARRAY));
     892             :                                 OOGL(glColorPointer(4, GL_FLOAT, 0, vertexdata.color_array));
     893             : //                              OOGL(glEnableClientState(GL_VERTEX_ARRAY));
     894             :                                 OOGL(glVertexPointer(3, GL_FLOAT, 0, vertexdata.vertex_array));
     895             : //                              OOGL(glEnableClientState(GL_NORMAL_ARRAY));
     896             :                                 OOGL(glNormalPointer(GL_FLOAT, 0, vertexdata.normal_array));
     897             :                                 
     898             :                                 if (_texture != nil)
     899             :                                 {
     900             :                                         OOGL(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
     901             :                                         if ([_texture isCubeMap])
     902             :                                         {
     903             :                                                 OOGL(glTexCoordPointer(3, GL_FLOAT, 0, vertexdata.vertex_array));
     904             :                                         }
     905             :                                         else
     906             :                                         {
     907             :                                                 OOGL(glTexCoordPointer(2, GL_FLOAT, 0, vertexdata.uv_array));
     908             :                                         }
     909             :                                 }
     910             :                                 else
     911             :                                 {
     912             :                                         OOGL(glDisableClientState(GL_TEXTURE_COORD_ARRAY));
     913             :                                 }
     914             :                                 
     915             :                                 if (displayListNames[subdivideLevel] != 0)
     916             :                                 {
     917             :                                         OOGL(glCallList(displayListNames[subdivideLevel]));
     918             :                                 }
     919             :                                 else
     920             :                                 {
     921             :                                         
     922             :                                         OOGL(displayListNames[subdivideLevel] = glGenLists(1));
     923             :                                         if (displayListNames[subdivideLevel] != 0)      // sanity check
     924             :                                         {
     925             :                                                 OOGL(glNewList(displayListNames[subdivideLevel], GL_COMPILE_AND_EXECUTE));
     926             :                                                 
     927             :                                                 OOGL(glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE));
     928             :                                                 OOGL(glEnable(GL_COLOR_MATERIAL));
     929             :                                                 
     930             :                                                 [self drawModelWithVertexArraysAndSubdivision:subdivideLevel];
     931             :                                                 
     932             :                                                 OOGL(glDisable(GL_COLOR_MATERIAL));
     933             :                                                 OOGL(glEndList());
     934             :                                         }
     935             :                                 }
     936             : 
     937             : #if OO_TEXTURE_CUBE_MAP
     938             :                                 if ([_texture isCubeMap])
     939             :                                 {
     940             :                                         OOGL(glDisable(GL_TEXTURE_CUBE_MAP));
     941             :                                         OOGL(glEnable(GL_TEXTURE_2D));
     942             :                                 }
     943             : #endif
     944             : 
     945             :                         OOGL(glDisableClientState(GL_COLOR_ARRAY));
     946             :                         OOGL(glDisableClientState(GL_TEXTURE_COORD_ARRAY));
     947             :                         OOGL(glEnable(GL_DEPTH_TEST));
     948             : 
     949             :                         }
     950             :                         
     951             :                         //if ((gDebugFlags & DEBUG_WIREFRAME_GRAPHICS)
     952             :                         if ([UNIVERSE wireframeGraphics])
     953             :                         {
     954             :                                 OOGLWireframeModeOff();
     955             :                         }
     956             : //                      OOGL(glDisableClientState(GL_VERTEX_ARRAY));
     957             : //                      OOGL(glDisableClientState(GL_NORMAL_ARRAY));
     958             :                         
     959             :                         break;
     960             :                         
     961             :                 case STELLAR_TYPE_SUN:
     962             :                         break;
     963             :         }
     964             : 
     965             :         if (ignoreDepthBuffer)
     966             :         {
     967             :                 OOGL(glEnable(GL_DEPTH_TEST));
     968             :         }
     969             :         OOGL(glEnable(GL_TEXTURE_2D));
     970             : //      OOGL(glEnable(GL_LIGHTING));
     971             :         OOGL(glDisable(GL_BLEND));
     972             : 
     973             : 
     974             :         OOGL(glPopAttrib());
     975             :         OOVerifyOpenGLState();
     976             :         OOCheckOpenGLErrors(@"PlanetEntity after drawing %@", self);
     977             : 
     978             :         if (atmosphere)
     979             :         {
     980             :                 OOGLPopModelView();     // get old draw matrix back
     981             :                 OOGLPushModelView();    // and store it again
     982             :                 OOGLTranslateModelView(cameraRelativePosition); // centre on the planet
     983             :                 // rotate
     984             : //              OOGLMultModelView([atmosphere rotationMatrix]);
     985             :                 // draw atmosphere entity
     986             :                 [atmosphere drawImmediate:false translucent:false];
     987             :         }
     988             : 
     989             : 
     990             : }
     991             : 
     992             : 
     993             : #ifndef NDEBUG
     994             : - (PlanetEntity *) atmosphere
     995             : {
     996             :         return atmosphere;
     997             : }
     998             : #endif
     999             : 
    1000             : 
    1001             : - (int) planet_seed
    1002             : {
    1003             :         return planet_seed;
    1004             : }
    1005             : 
    1006             : 
    1007             : - (BOOL) isTextured
    1008             : {
    1009             :         return _texture != nil;
    1010             : }
    1011             : 
    1012             : 
    1013             : - (NSString *) textureFileName
    1014             : {
    1015             :         return _textureFileName;
    1016             : }
    1017             : 
    1018             : 
    1019           0 : - (void) setTextureColorForPlanet:(BOOL)isMain inSystem:(BOOL)isLocal
    1020             : {       
    1021             :         Vector land_hsb, land_polar_hsb;
    1022             :         land_hsb.x = 0.0;       land_hsb.y = 0.0;       land_hsb.z = 1.0;       // white
    1023             :         
    1024             :         // the colour override should only apply to main planets
    1025             :         if (isMain)
    1026             :         {
    1027             :                 if (isLocal)  ScanVectorFromString([[UNIVERSE currentSystemData] objectForKey:@"texture_hsb_color"], &land_hsb);
    1028             :                 else  ScanVectorFromString([[UNIVERSE generateSystemData:[PLAYER target_system_seed]] objectForKey:@"texture_hsb_color"], &land_hsb);
    1029             :         }
    1030             :         
    1031             :         land_polar_hsb.x = land_hsb.x;  land_polar_hsb.y = (land_hsb.y / 5.0);  land_polar_hsb.z = 1.0 - (land_hsb.z / 10.0);
    1032             :         
    1033             :         amb_sea[0] = amb_land[0] = [[OOColor colorWithHue:land_hsb.x saturation:land_hsb.y brightness:land_hsb.z alpha:1.0] redComponent];
    1034             :         amb_sea[1] = amb_land[1] = [[OOColor colorWithHue:land_hsb.x saturation:land_hsb.y brightness:land_hsb.z alpha:1.0] blueComponent];
    1035             :         amb_sea[2] = amb_land[2] = [[OOColor colorWithHue:land_hsb.x saturation:land_hsb.y brightness:land_hsb.z alpha:1.0] greenComponent];
    1036             :         amb_sea[3] = amb_land[3] = 1.0;
    1037             :         amb_polar_sea[0] =amb_polar_land[0] = [[OOColor colorWithHue:land_polar_hsb.x saturation:land_polar_hsb.y brightness:land_polar_hsb.z alpha:1.0] redComponent];
    1038             :         amb_polar_sea[1] =amb_polar_land[1] = [[OOColor colorWithHue:land_polar_hsb.x saturation:land_polar_hsb.y brightness:land_polar_hsb.z alpha:1.0] blueComponent];
    1039             :         amb_polar_sea[2] = amb_polar_land[2] = [[OOColor colorWithHue:land_polar_hsb.x saturation:land_polar_hsb.y brightness:land_polar_hsb.z alpha:1.0] greenComponent];
    1040             :         amb_polar_sea[3] =amb_polar_land[3] = 1.0;
    1041             : }
    1042             : 
    1043             : 
    1044             : - (BOOL) setUpPlanetFromTexture:(NSString *)fileName
    1045             : {
    1046             :         if (fileName == nil)  return NO;
    1047             :         
    1048             :         [self loadTexture:OOTextureSpecFromObject(fileName, nil)];
    1049             :         [self deleteDisplayLists];
    1050             :         
    1051             :         unsigned i;
    1052             :         [self setUseTexturedModel:YES];
    1053             :         
    1054             :         // recolour main planet according to "texture_hsb_color"
    1055             :         // this function is only called for local systems!
    1056             :         [self setTextureColorForPlanet:([UNIVERSE planet] == self) inSystem:YES];
    1057             :         
    1058             :         [self initialiseBaseVertexArray];
    1059             :         [self initialiseBaseTerrainArray:100];
    1060             :         for (i =  0; i < next_free_vertex; i++)
    1061             :         {
    1062             :                 [self paintVertex:i :planet_seed];
    1063             :         }
    1064             :         
    1065             :         [self scaleVertices];
    1066             :         
    1067             :         GLfloat oldCloudAlpha = 0.0;
    1068             :         if (atmosphere)
    1069             :         {
    1070             :                 oldCloudAlpha = [atmosphere amb_sea][3] / CLOUD_ALPHA;
    1071             :         }
    1072             : 
    1073             :         NSDictionary *atmo_dictionary = [NSDictionary dictionaryWithObjectsAndKeys:@"0", @"percent_cloud", [NSNumber numberWithFloat:oldCloudAlpha], @"cloud_alpha", nil];
    1074             :         [atmosphere autorelease];
    1075             :         atmosphere = [self hasAtmosphere] ? [[PlanetEntity alloc] initAsAtmosphereForPlanet:self dictionary:atmo_dictionary] : nil;
    1076             :         
    1077             :         //rotationAxis = vector_up_from_quaternion(orientation);
    1078             :         
    1079             :         return [self isTextured];
    1080             : }
    1081             : 
    1082             : 
    1083             : - (double) polar_color_factor
    1084             : {
    1085             :         return polar_color_factor;
    1086             : }
    1087             : 
    1088             : 
    1089             : - (GLfloat *) amb_land
    1090             : {
    1091             :         return amb_land;
    1092             : }
    1093             : 
    1094             : 
    1095             : - (GLfloat *) amb_polar_land
    1096             : {
    1097             :         return amb_polar_land;
    1098             : }
    1099             : 
    1100             : 
    1101             : - (GLfloat *) amb_sea
    1102             : {
    1103             :         return amb_sea;
    1104             : }
    1105             : 
    1106             : 
    1107             : - (GLfloat *) amb_polar_sea
    1108             : {
    1109             :         return amb_polar_sea;
    1110             : }
    1111             : 
    1112             : 
    1113             : - (OOStellarBodyType) planetType
    1114             : {
    1115             :         return planet_type;
    1116             : }
    1117             : 
    1118             : 
    1119             : - (void) setPlanetType:(OOStellarBodyType) pt
    1120             : {
    1121             :         planet_type = pt;
    1122             : }
    1123             : 
    1124             : 
    1125             : - (double) radius
    1126             : {
    1127             :         return collision_radius;
    1128             : }
    1129             : 
    1130             : 
    1131             : - (void) setRadius:(GLfloat) rad
    1132             : {
    1133             :         collision_radius = rad;
    1134             : }
    1135             : 
    1136             : - (double) rotationalVelocity
    1137             : {
    1138             :         return rotational_velocity;
    1139             : }
    1140             : 
    1141             : - (void) setRotationalVelocity:(double) v
    1142             : {
    1143             :         if (atmosphere) // change rotation speed proportionally
    1144             :         {
    1145             :                 [atmosphere setRotationalVelocity:[atmosphere rotationalVelocity] * v / [self rotationalVelocity]];
    1146             :         }
    1147             :         rotational_velocity = v;
    1148             : }
    1149             : 
    1150             : 
    1151           0 : - (double) sqrtZeroDistance
    1152             : {
    1153             :         return sqrt_zero_distance;
    1154             : }
    1155             : 
    1156             : 
    1157             : - (BOOL) hasAtmosphere
    1158             : {
    1159             :         return atmosphere != nil;
    1160             : }
    1161             : 
    1162             : 
    1163           0 : - (void) drawModelWithVertexArraysAndSubdivision: (int) subdivide
    1164             : {
    1165             :         OOGL(glDrawElements(GL_TRIANGLES, 3 * n_triangles[subdivide], GL_UNSIGNED_INT, &vertexdata.index_array[triangle_start[subdivide]]));
    1166             : }
    1167             : 
    1168             : 
    1169             : - (void) launchShuttle
    1170             : {
    1171             :         ShipEntity  *shuttle_ship;
    1172             :         Quaternion  q1;
    1173             :         HPVector                launch_pos = position;
    1174             :         double          start_distance = collision_radius + 125.0;
    1175             : 
    1176             :         quaternion_set_random(&q1);
    1177             : 
    1178             :         Vector vf = vector_forward_from_quaternion(q1);
    1179             : 
    1180             :         launch_pos.x += start_distance * vf.x;
    1181             :         launch_pos.y += start_distance * vf.y;
    1182             :         launch_pos.z += start_distance * vf.z;
    1183             : 
    1184             :         shuttle_ship = [UNIVERSE newShipWithRole:@"shuttle"];   // retain count = 1
    1185             :         if (shuttle_ship)
    1186             :         {
    1187             :                 if (![shuttle_ship crew])
    1188             :                 {
    1189             :                         [shuttle_ship setSingleCrewWithRole:@"trader"];
    1190             :                 }
    1191             :                                 
    1192             :                 [shuttle_ship setPosition:launch_pos];
    1193             :                 [shuttle_ship setOrientation:q1];
    1194             : 
    1195             :                 [shuttle_ship setScanClass: CLASS_NEUTRAL];
    1196             :                 [shuttle_ship setCargoFlag:CARGO_FLAG_FULL_PLENTIFUL];
    1197             :                 [shuttle_ship switchAITo:@"oolite-shuttleAI.js"];
    1198             :                 [UNIVERSE addEntity:shuttle_ship];
    1199             : 
    1200             :                 [shuttle_ship release];
    1201             :         }
    1202             : }
    1203             : 
    1204             : 
    1205             : - (void) welcomeShuttle:(ShipEntity *) shuttle
    1206             : {
    1207             :         shuttles_on_ground++;
    1208             : }
    1209             : 
    1210             : 
    1211           0 : - (void) initialiseBaseVertexArray
    1212             : {
    1213             :         BOOL isTextured = [self isTextured];
    1214             :         static BOOL lastOneWasTextured;
    1215             :         
    1216             :         if (lastOneWasTextured != isTextured)
    1217             :         {
    1218             :                 if (sEdgeToVertex != NULL)
    1219             :                 {
    1220             :                         NSFreeMapTable(sEdgeToVertex);
    1221             :                         sEdgeToVertex = NULL;
    1222             :                 }
    1223             :                 lastOneWasTextured = isTextured;
    1224             :         }
    1225             :         
    1226             :         if (sEdgeToVertex == NULL)
    1227             :         {
    1228             :                 sEdgeToVertex = NSCreateMapTable(NSIntegerMapKeyCallBacks, NSIntegerMapValueCallBacks, 7680);   // make a new one
    1229             :                 next_free_vertex = 0;
    1230             :                 
    1231             :                 const Vector *vertices = NULL;
    1232             :                 const BaseFace (*faces)[3] = NULL;
    1233             :                 GLuint faceCount = 0;
    1234             :                 if (useTexturedModel)
    1235             :                 {
    1236             :                         vertices = kTexturedVertices;
    1237             :                         faces = kTexturedFaces;
    1238             :                         faceCount = sizeof kTexturedFaces / sizeof *kTexturedFaces;
    1239             :                 }
    1240             :                 else
    1241             :                 {
    1242             :                         vertices = kUntexturedVertices;
    1243             :                         faces = kUntexturedFaces;
    1244             :                         faceCount = sizeof kUntexturedFaces / sizeof *kUntexturedFaces;
    1245             :                 }
    1246             :                 
    1247             :                 // set first 12 or 14 vertices
    1248             :                 GLuint vi;
    1249             :                 for (vi = 0; vi < vertexCount; vi++)
    1250             :                 {
    1251             :                         base_vertex_array[next_free_vertex++] =  vertices[vi];
    1252             :                 }
    1253             :                 
    1254             :                 // set first 20 triangles
    1255             :                 triangle_start[0] = 0;
    1256             :                 n_triangles[0] = faceCount;
    1257             :                 GLuint fi;
    1258             :                 for (fi = 0; fi < faceCount; fi++)
    1259             :                 {
    1260             :                         unsigned j;
    1261             :                         for (j = 0; j < 3; j++)
    1262             :                         {
    1263             :                                 vertex_index_array[fi * 3 + j] = faces[fi][j].v;
    1264             :                                 texture_uv_array[faces[fi][j].v * 2 + 0] = faces[fi][j].s;
    1265             :                                 texture_uv_array[faces[fi][j].v * 2 + 1] = faces[fi][j].t;
    1266             :                         }
    1267             :                 }
    1268             :                 
    1269             :                 // for the next levels of subdivision simply build up from the level below!...
    1270             :                 unsigned sublevel;
    1271             :                 for (sublevel = 0; sublevel < MAX_SUBDIVIDE - 1; sublevel++)
    1272             :                 {
    1273             :                         int newlevel = sublevel + 1;
    1274             :                         triangle_start[newlevel] = triangle_start[sublevel] + n_triangles[sublevel] * 3;
    1275             :                         n_triangles[newlevel] = n_triangles[sublevel] * 4;
    1276             : 
    1277             :                         int tri;
    1278             :                         for (tri = 0; tri < n_triangles[sublevel]; tri++)
    1279             :                         {
    1280             :                                 // get the six vertices for this group of four triangles
    1281             :                                 int v0 = vertex_index_array[triangle_start[sublevel] + tri * 3 + 0];
    1282             :                                 int v1 = vertex_index_array[triangle_start[sublevel] + tri * 3 + 1];
    1283             :                                 int v2 = vertex_index_array[triangle_start[sublevel] + tri * 3 + 2];
    1284             :                                 int v01 = baseVertexIndexForEdge(v0, v1, isTextured);   // sets it up if required
    1285             :                                 int v12 = baseVertexIndexForEdge(v1, v2, isTextured);   // ..
    1286             :                                 int v20 = baseVertexIndexForEdge(v2, v0, isTextured);   // ..
    1287             :                                 // v0 v01 v20
    1288             :                                 vertex_index_array[triangle_start[newlevel] + tri * 12 + 0] = v0;
    1289             :                                 vertex_index_array[triangle_start[newlevel] + tri * 12 + 1] = v01;
    1290             :                                 vertex_index_array[triangle_start[newlevel] + tri * 12 + 2] = v20;
    1291             :                                 // v01 v1 v12
    1292             :                                 vertex_index_array[triangle_start[newlevel] + tri * 12 + 3] = v01;
    1293             :                                 vertex_index_array[triangle_start[newlevel] + tri * 12 + 4] = v1;
    1294             :                                 vertex_index_array[triangle_start[newlevel] + tri * 12 + 5] = v12;
    1295             :                                 // v20 v12 v2
    1296             :                                 vertex_index_array[triangle_start[newlevel] + tri * 12 + 6] = v20;
    1297             :                                 vertex_index_array[triangle_start[newlevel] + tri * 12 + 7] = v12;
    1298             :                                 vertex_index_array[triangle_start[newlevel] + tri * 12 + 8] = v2;
    1299             :                                 // v01 v12 v20
    1300             :                                 vertex_index_array[triangle_start[newlevel] + tri * 12 + 9] = v01;
    1301             :                                 vertex_index_array[triangle_start[newlevel] + tri * 12 +10] = v12;
    1302             :                                 vertex_index_array[triangle_start[newlevel] + tri * 12 +11] = v20;
    1303             : 
    1304             :                         }
    1305             :                 }
    1306             :         }
    1307             :         
    1308             :         // all done - copy the indices to the instance
    1309             :         unsigned i;
    1310             :         for (i = 0; i < MAX_TRI_INDICES; i++)
    1311             :         {
    1312             :                 vertexdata.index_array[i] = vertex_index_array[i];
    1313             :         }
    1314             : }
    1315             : 
    1316             :         
    1317           0 : static unsigned baseVertexIndexForEdge(GLushort va, GLushort vb, BOOL textured)
    1318             : {
    1319             :         if (va < vb)
    1320             :         {
    1321             :                 GLushort temp = va;
    1322             :                 va = vb;
    1323             :                 vb = temp;
    1324             :         }
    1325             :         void *key = (void *)(((uintptr_t)va << 16) | vb);
    1326             :         uintptr_t num = (uintptr_t)NSMapGet(sEdgeToVertex, key);
    1327             :         if (num != 0)
    1328             :         {
    1329             :                 // Overall cache hit rate is just over 83 %.
    1330             :                 return (unsigned)num - 1;
    1331             :         }
    1332             :         else
    1333             :         {
    1334             :                 unsigned vindex = next_free_vertex++;
    1335             :                 NSCAssert(vindex < sizeof base_vertex_array / sizeof *base_vertex_array, @"Vertex array overflow in planet setup.");
    1336             :                 
    1337             :                 // calculate position of new vertex
    1338             :                 Vector pos = vector_add(base_vertex_array[va], base_vertex_array[vb]);
    1339             :                 pos = vector_normal(pos);       // guaranteed non-zero
    1340             :                 base_vertex_array[vindex] = pos;
    1341             :                 
    1342             :                 if (textured)
    1343             :                 {
    1344             :                         //calculate new texture coordinates
    1345             :                         NSPoint uva = (NSPoint){ texture_uv_array[va * 2], texture_uv_array[va * 2 + 1] };
    1346             :                         NSPoint uvb = (NSPoint){ texture_uv_array[vb * 2], texture_uv_array[vb * 2 + 1] };
    1347             :                         
    1348             :                         // if either of these is the polar vertex treat it specially to help with polar distortion:
    1349             :                         if (uva.y == 0.0 || uva.y == 1.0)  uva.x = uvb.x;
    1350             :                         if (uvb.y == 0.0 || uvb.y == 1.0)  uvb.x = uva.x;
    1351             :                         
    1352             :                         texture_uv_array[vindex * 2] = 0.5 * (uva.x + uvb.x);
    1353             :                         texture_uv_array[vindex * 2 + 1] = 0.5 * (uva.y + uvb.y);
    1354             :                 }
    1355             :                 
    1356             :                 // add new edge to the look-up
    1357             :                 num = vindex + 1;
    1358             :                 NSMapInsertKnownAbsent(sEdgeToVertex, key, (void *)num);
    1359             :                 return vindex;
    1360             :         }
    1361             : }
    1362             : 
    1363             : 
    1364           0 : - (void) initialiseBaseTerrainArray:(int) percent_land
    1365             : {
    1366             :         RANROTSeed saved_seed = RANROTGetFullSeed();
    1367             : 
    1368             :         // set first 12 or 14 vertices
    1369             :         if (percent_land >= 0)
    1370             :         {
    1371             :                 GLuint vi;
    1372             :                 for (vi = 0; vi < vertexCount; vi++)
    1373             :                 {
    1374             :                         if (gen_rnd_number() < 256 * percent_land / 100)
    1375             :                                 base_terrain_array[vi] = 0;  // land
    1376             :                         else
    1377             :                                 base_terrain_array[vi] = 100;  // sea
    1378             : 
    1379             :                 }
    1380             :         }
    1381             :         
    1382             :         // for the next levels of subdivision simply build up from the level below!...
    1383             :         BOOL isTextured = [self isTextured];
    1384             :         
    1385             :         int sublevel;
    1386             :         for (sublevel = 0; sublevel < MAX_SUBDIVIDE - 1; sublevel++)
    1387             :         {
    1388             :                 int tri;
    1389             :                 for (tri = 0; tri < n_triangles[sublevel]; tri++)
    1390             :                 {
    1391             :                         // get the six vertices for this group of four triangles
    1392             :                         int v0 = vertex_index_array[triangle_start[sublevel] + tri * 3 + 0];
    1393             :                         int v1 = vertex_index_array[triangle_start[sublevel] + tri * 3 + 1];
    1394             :                         int v2 = vertex_index_array[triangle_start[sublevel] + tri * 3 + 2];
    1395             :                         int v01 = baseVertexIndexForEdge(v0, v1, isTextured);   // sets it up if required
    1396             :                         int v12 = baseVertexIndexForEdge(v1, v2, isTextured);   // ..
    1397             :                         int v20 = baseVertexIndexForEdge(v2, v0, isTextured);   // ..
    1398             :                         // v01
    1399             :                         if (base_terrain_array[v0] == base_terrain_array[v1])
    1400             :                                 base_terrain_array[v01] = base_terrain_array[v0];
    1401             :                         else
    1402             :                         {
    1403             :                                 uint32_t s1 = 0xffff0000 * base_vertex_array[v01].x;
    1404             :                                 uint32_t s2 = 0x00ffff00 * base_vertex_array[v01].y;
    1405             :                                 uint32_t s3 = 0x0000ffff * base_vertex_array[v01].z;
    1406             :                                 ranrot_srand(s1+s2+s3);
    1407             :                                 base_terrain_array[v01] = (ranrot_rand() & 4) *25;
    1408             :                         }
    1409             :                         // v12
    1410             :                         if (base_terrain_array[v1] == base_terrain_array[v2])
    1411             :                                 base_terrain_array[v12] = base_terrain_array[v1];
    1412             :                         else
    1413             :                         {
    1414             :                                 uint32_t s1 = 0xffff0000 * base_vertex_array[v12].x;
    1415             :                                 uint32_t s2 = 0x00ffff00 * base_vertex_array[v12].y;
    1416             :                                 uint32_t s3 = 0x0000ffff * base_vertex_array[v12].z;
    1417             :                                 ranrot_srand(s1+s2+s3);
    1418             :                                 base_terrain_array[v12] = (ranrot_rand() & 4) *25;
    1419             :                         }
    1420             :                         // v20
    1421             :                         if (base_terrain_array[v2] == base_terrain_array[v0])
    1422             :                                 base_terrain_array[v20] = base_terrain_array[v2];
    1423             :                         else
    1424             :                         {
    1425             :                                 uint32_t s1 = 0xffff0000 * base_vertex_array[v20].x;
    1426             :                                 uint32_t s2 = 0x00ffff00 * base_vertex_array[v20].y;
    1427             :                                 uint32_t s3 = 0x0000ffff * base_vertex_array[v20].z;
    1428             :                                 ranrot_srand(s1+s2+s3);
    1429             :                                 base_terrain_array[v20] = (ranrot_rand() & 4) *25;
    1430             :                         }
    1431             :                 }
    1432             :         }
    1433             : 
    1434             :         RANROTSetFullSeed(saved_seed);
    1435             : }
    1436             : 
    1437             : 
    1438           0 : - (void) paintVertex:(unsigned) vi :(int) seed
    1439             : {
    1440             :         RANROTSeed saved_seed = RANROTGetFullSeed();
    1441             :         BOOL isTextured = _texture != nil;
    1442             :         
    1443             :         GLfloat paint_land[4] = { 0.2, 0.9, 0.0, 1.0};
    1444             :         GLfloat paint_sea[4] = { 0.0, 0.2, 0.9, 1.0};
    1445             :         GLfloat paint_color[4];
    1446             :         Vector  v = base_vertex_array[vi];
    1447             :         int             r = isTextured ? 0 : base_terrain_array[vi];    // use land color (0) for textured planets
    1448             :         int i;
    1449             :         double pole_blend = v.z * v.z * polar_color_factor;
    1450             :         if (pole_blend < 0.0)        pole_blend = 0.0;
    1451             :         if (pole_blend > 1.0)        pole_blend = 1.0;
    1452             :         
    1453             :         paint_land[0] = (1.0 - pole_blend)*amb_land[0] + pole_blend*amb_polar_land[0];
    1454             :         paint_land[1] = (1.0 - pole_blend)*amb_land[1] + pole_blend*amb_polar_land[1];
    1455             :         paint_land[2] = (1.0 - pole_blend)*amb_land[2] + pole_blend*amb_polar_land[2];
    1456             :         paint_sea[0] = (1.0 - pole_blend)*amb_sea[0] + pole_blend*amb_polar_sea[0];
    1457             :         paint_sea[1] = (1.0 - pole_blend)*amb_sea[1] + pole_blend*amb_polar_sea[1];
    1458             :         paint_sea[2] = (1.0 - pole_blend)*amb_sea[2] + pole_blend*amb_polar_sea[2];
    1459             :         if (planet_type == STELLAR_TYPE_ATMOSPHERE)     // do alphas
    1460             :         {
    1461             :                 paint_land[3] = (1.0 - pole_blend)*amb_land[3] + pole_blend*amb_polar_land[3];
    1462             :                 paint_sea[3] = (1.0 - pole_blend)*amb_sea[3] + pole_blend*amb_polar_sea[3];
    1463             :         }
    1464             :         
    1465             :         ranrot_srand((uint32_t)(seed+v.x*1000+v.y*100+v.z*10));
    1466             :         
    1467             :         for (i = 0; i < 3; i++)
    1468             :         {
    1469             :                 double cv = (ranrot_rand() % 100)*0.01; //  0..1 ***** DON'T CHANGE THIS LINE, '% 100' MAY NOT BE EFFICIENT BUT THE PATTERNING IS GOOD.
    1470             :                 paint_land[i] += (cv - 0.5)*0.1;
    1471             :                 paint_sea[i] += (cv - 0.5)*0.1;
    1472             :         }
    1473             :         
    1474             :         for (i = 0; i < 4; i++)
    1475             :         {
    1476             :                 if (planet_type == STELLAR_TYPE_ATMOSPHERE && isTextured)
    1477             :                         paint_color[i] = 1.0;
    1478             :                 else
    1479             :                         paint_color[i] = (r * paint_sea[i])*0.01 + ((100 - r) * paint_land[i])*0.01;
    1480             :                 // finally initialise the color array entry
    1481             :                 vertexdata.color_array[vi*4 + i] = paint_color[i];
    1482             :         }
    1483             : 
    1484             :         RANROTSetFullSeed(saved_seed);
    1485             : }
    1486             : 
    1487             : 
    1488           0 : - (void) scaleVertices
    1489             : {
    1490             :         NSUInteger vi;
    1491             :         for (vi = 0; vi < next_free_vertex; vi++)
    1492             :         {
    1493             :                 Vector  v = base_vertex_array[vi];
    1494             :                 vertexdata.normal_array[vi] = v;
    1495             :                 vertexdata.vertex_array[vi] = make_vector(v.x * collision_radius, v.y * collision_radius, v.z * collision_radius);
    1496             :                 
    1497             :                 vertexdata.uv_array[vi * 2] = texture_uv_array[vi * 2];
    1498             :                 vertexdata.uv_array[vi * 2 + 1] = texture_uv_array[vi * 2 + 1];
    1499             :         }
    1500             : }
    1501             : 
    1502             : 
    1503           0 : - (void) deleteDisplayLists
    1504             : {
    1505             :         unsigned i;
    1506             :         for (i = 0; i < MAX_SUBDIVIDE; i++)
    1507             :         {
    1508             :                 if (displayListNames[i] != 0)
    1509             :                 {
    1510             :                         glDeleteLists(displayListNames[i], 1);
    1511             :                         displayListNames[i] = 0;
    1512             :                 }
    1513             :         }
    1514             : }
    1515             : 
    1516             : 
    1517           0 : - (void)resetGraphicsState
    1518             : {
    1519             :         [self deleteDisplayLists];
    1520             : }
    1521             : 
    1522             : 
    1523             : - (BOOL) isExplicitlyTextured
    1524             : {
    1525             :         return isTextureImage;
    1526             : }
    1527             : 
    1528             : 
    1529             : - (OOTexture *) texture
    1530             : {
    1531             :         return _texture;
    1532             : }
    1533             : 
    1534             : 
    1535           0 : - (void) loadTexture:(NSDictionary *)configuration
    1536             : {
    1537             :         [_texture release];
    1538             :         _texture = [OOTexture textureWithConfiguration:configuration extraOptions:kOOTextureAllowCubeMap | kOOTextureRepeatS];
    1539             :         [_texture retain];
    1540             :         
    1541             :         [_textureFileName release];
    1542             :         if (_texture != nil)
    1543             :         {
    1544             :                 _textureFileName = [[configuration oo_stringForKey:@"name"] copy];
    1545             :                 isTextureImage = YES;
    1546             :         }
    1547             :         else
    1548             :         {
    1549             :                 _textureFileName = nil;
    1550             :                 isTextureImage = NO;
    1551             :         }
    1552             : }
    1553             : 
    1554             : 
    1555             : /*      Ideally, these would use OOPlanetTextureGenerator. However, it isn't
    1556             :         designed to use separate invocations for diffuse and cloud generation,
    1557             :         while old-style PlanetEntity calls these from different places for
    1558             :         different objects.
    1559             :         -- Ahruman 2010-06-04
    1560             : */
    1561           0 : - (OOTexture *) planetTextureWithInfo:(NSDictionary *)info
    1562             : {
    1563             :         unsigned char *data;
    1564             :         GLuint width, height;
    1565             :         
    1566             :         fillRanNoiseBuffer();
    1567             :         if (![TextureStore getPlanetTextureNameFor:info
    1568             :                                                                           intoData:&data
    1569             :                                                                                  width:&width
    1570             :                                                                                 height:&height])
    1571             :         {
    1572             :                 return nil;
    1573             :         }
    1574             :         
    1575             :         OOPixMap pm = OOMakePixMap(data, width, height, kOOPixMapRGBA, 0, 0);
    1576             :         OOTextureGenerator *loader = [[OOPixMapTextureLoader alloc] initWithPixMap:pm
    1577             :                                                                                                                                 textureOptions:kOOTextureDefaultOptions | kOOTextureRepeatS
    1578             :                                                                                                                                   freeWhenDone:YES];
    1579             :         [loader autorelease];
    1580             :         
    1581             :         return [OOTexture textureWithGenerator:loader];
    1582             : }
    1583             : 
    1584             : 
    1585           0 : - (OOTexture *) cloudTextureWithCloudColor:(OOColor *)cloudColor cloudImpress:(GLfloat)cloud_impress cloudBias:(GLfloat)cloud_bias
    1586             : {
    1587             :         unsigned char *data;
    1588             :         GLuint width, height;
    1589             :         
    1590             :         fillRanNoiseBuffer();
    1591             :         if (![TextureStore getCloudTextureNameFor:cloudColor
    1592             :                                                                                          :cloud_impress
    1593             :                                                                                          :cloud_bias
    1594             :                                                                          intoData:&data
    1595             :                                                                                 width:&width
    1596             :                                                                            height:&height])
    1597             :         {
    1598             :                 return nil;
    1599             :         }
    1600             :         
    1601             :         OOPixMap pm = OOMakePixMap(data, width, height, kOOPixMapRGBA, 0, 0);
    1602             :         OOTextureGenerator *loader = [[OOPixMapTextureLoader alloc] initWithPixMap:pm
    1603             :                                                                                                                                 textureOptions:kOOTextureDefaultOptions | kOOTextureRepeatS
    1604             :                                                                                                                                   freeWhenDone:YES];
    1605             :         [loader autorelease];
    1606             :         
    1607             :         return [OOTexture textureWithGenerator:loader];
    1608             : }
    1609             : 
    1610             : 
    1611             : #ifndef NDEBUG
    1612           0 : - (NSSet *) allTextures
    1613             : {
    1614             :         if (_texture != nil)  return [NSSet setWithObject:_texture];
    1615             :         else  return nil;
    1616             : }
    1617             : #endif
    1618             : 
    1619             : 
    1620           0 : - (BOOL)isPlanet
    1621             : {
    1622             :         return YES;
    1623             : }
    1624             : 
    1625             : 
    1626           0 : - (BOOL) isVisible
    1627             : {
    1628             :         return YES;
    1629             : }
    1630             : 
    1631             : @end
    1632             : 
    1633             : #endif  // !NEW_PLANETS

Generated by: LCOV version 1.14