Work on offline generation of data arrays for new planets.

git-svn-id: http://svn.berlios.de/svnroot/repos/oolite-linux/trunk@2767 127b21dd-08f5-0310-b4b7-95ae10353056
This commit is contained in:
Jens Ayton 2009-11-20 14:49:24 +00:00
parent ba30324d99
commit c8445aeb9e
14 changed files with 1406 additions and 0 deletions

View File

@ -0,0 +1,27 @@
#import "icosmesh.h"
@class JAVertexSet, JAIcosTriangle;
@interface JAIcosMesh: NSObject
{
@private
JAVertexSet *_vertexSet;
NSMutableArray *_indices;
NSUInteger _maxIndex;
}
// Vertex set may optionally be specified, so one can be shared between multiple meshes.
+ (id) meshWithVertexSet:(JAVertexSet *)vertexSet;
- (id) initWithVertexSet:(JAVertexSet *)vertexSet;
@property (readonly) JAVertexSet *vertexSet;
@property (readonly) NSUInteger faceCount;
@property (readonly) NSUInteger maxIndex;
- (void) addTriangle:(JAIcosTriangle *)triangle;
- (void) addTriangles:(NSArray *)triangles;
- (NSArray *) indexArray; // NSArray of faceCount * 3 NSNumbers, being indices into vertexSet.
@end

113
tools/icosmesh/JAIcosMesh.m Normal file
View File

@ -0,0 +1,113 @@
//
// JAIcosMesh.m
// icosmesh
//
// Created by Jens Ayton on 2009-11-18.
// Copyright 2009 Jens Ayton. All rights reserved.
//
#import "JAIcosMesh.h"
#import "JAVertexSet.h"
#import "JAIcosTriangle.h"
@interface JAIcosMesh ()
- (void) addOneVertex:(Vertex)v;
@end
@implementation JAIcosMesh
- (id) init
{
return [self initWithVertexSet:nil];
}
+ (id) meshWithVertexSet:(JAVertexSet *)vertexSet
{
return [[[self alloc] initWithVertexSet:vertexSet] autorelease];
}
- (id) initWithVertexSet:(JAVertexSet *)vertexSet
{
if ((self = [super init]))
{
if (vertexSet == nil) vertexSet = [[[JAVertexSet alloc] init] autorelease];
_vertexSet = [vertexSet retain];
_indices = [[NSMutableArray alloc] init];
if (_vertexSet == nil || _indices == nil)
{
[self release];
return nil;
}
}
return self;
}
- (void) dealloc
{
[_vertexSet release];
[_indices release];
[super dealloc];
}
- (JAVertexSet *)vertexSet
{
return _vertexSet;
}
- (NSUInteger) faceCount
{
return _indices.count / 3;
}
- (NSUInteger) maxIndex
{
return _maxIndex;
}
- (void) addTriangle:(JAIcosTriangle *)triangle
{
if (triangle == nil) return;
[self addOneVertex:triangle.vertexA];
[self addOneVertex:triangle.vertexB];
[self addOneVertex:triangle.vertexC];
}
- (void) addTriangles:(NSArray *)triangles
{
for (JAIcosTriangle *triangle in triangles)
{
[self addTriangle:triangle];
}
}
- (NSArray *) indexArray
{
return [[_indices copy] autorelease];
}
- (void) addOneVertex:(Vertex)v
{
NSUInteger index = [_vertexSet indexForVertex:v];
[_indices addObject:[NSNumber numberWithUnsignedInteger:index]];
if (_maxIndex < index) _maxIndex = index;
}
@end

View File

@ -0,0 +1,28 @@
//
// JAIcosTriangle.h
// icosmesh
//
// Created by Jens Ayton on 2009-11-18.
// Copyright 2009 Jens Ayton. All rights reserved.
//
#import "icosmesh.h"
@interface JAIcosTriangle: NSObject
{
@private
Vertex _vertices[3];
}
// Note: order is not guaranteed to be maintained.
+ (id) triangleWithVectorA:(Vector)a b:(Vector)b c:(Vector)c;
- (id) initWithVectorA:(Vector)a b:(Vector)b c:(Vector)c;
- (NSArray *) subdivide; // A list of four JAIcosTriangles.
@property (readonly) Vertex vertexA;
@property (readonly) Vertex vertexB;
@property (readonly) Vertex vertexC;
@end

View File

@ -0,0 +1,183 @@
//
// JAIcosTriangle.m
// icosmesh
//
// Created by Jens Ayton on 2009-11-18.
// Copyright 2009 Jens Ayton. All rights reserved.
//
#import "JAIcosTriangle.h"
static inline BOOL IsPolarVector(Vector v)
{
return v.x == 0.0 && v.z == 0.0;
}
@interface JAIcosTriangle ()
- (void) rotate; // a = b, b = c, c = a
- (void) generateTextureCoordinates; // Requires that any polar coordinate is in [0].
@end
static NSComparisonResult CompareVertices(Vertex *a, Vertex *b)
{
return NSOrderedSame;
}
static NSString *VertexDescription(Vertex v)
{
return [NSString stringWithFormat:@"{ %g, %g, %g} (%g, %g)", v.v.x, v.v.y, v.v.z, v.s, v.t];
}
@implementation JAIcosTriangle
+ (id) triangleWithVectorA:(Vector)a b:(Vector)b c:(Vector)c
{
return [[[self alloc] initWithVectorA:a b:b c:c] autorelease];
}
- (id) initWithVectorA:(Vector)a b:(Vector)b c:(Vector)c
{
if ((self = [super init]))
{
_vertices[0].v = VectorNormal(a);
_vertices[1].v = VectorNormal(b);
_vertices[2].v = VectorNormal(c);
// If one of our vertices is a pole, make it the first.
if (IsPolarVector(_vertices[2].v)) [self rotate];
if (IsPolarVector(_vertices[1].v)) [self rotate];
[self generateTextureCoordinates];
}
return self;
}
- (NSString *) description
{
return [NSString stringWithFormat:@"{%@, %@, %@}", VertexDescription(_vertices[0]), VertexDescription(_vertices[1]), VertexDescription(_vertices[2])];
}
- (Vertex) vertexA
{
return _vertices[0];
}
- (Vertex) vertexB
{
return _vertices[1];
}
- (Vertex) vertexC
{
return _vertices[2];
}
- (void) rotate
{
Vertex temp = _vertices[0];
_vertices[0] = _vertices[1];
_vertices[1] = _vertices[2];
_vertices[2] = temp;
}
- (void) generateTextureCoordinates
{
VectorToCoords0_1(_vertices[1].v, &_vertices[1].t, &_vertices[1].s);
VectorToCoords0_1(_vertices[2].v, &_vertices[2].t, &_vertices[2].s);
if (!IsPolarVector(_vertices[0].v)) VectorToCoords0_1(_vertices[0].v, &_vertices[0].t, &_vertices[0].s);
else
{
// Use longitude of average of v1 and v2.
VectorToCoords0_1(VectorAdd(_vertices[1].v, _vertices[2].v), NULL, &_vertices[0].s);
_vertices[0].t = (_vertices[0].v.y < 0) ? 1.0 : 0.0;
}
/* Texture seam handling
At the back of the mesh, at the longitude = 180°/-180° meridian, the
texture wraps around. However, there isn't a convenient matching seam
in the geometry - there are no great circles on a subdivided
icosahedron - so we need to adjust texture coordinates and use the
GL_REPEAT texture wrapping mode to cover it over.
The technique is to establish whether we have at least one vertex in
each of the (x, -z) and (-x, -z) quadrants, and if so, add 1 to the
texture coordinates for the vertices in (-x, -z) -- corresponding to
the east Pacific.
NOTE: this technique is suboptimal because the selection of wrapped
vertices changes at each subdivision level. Interpolating texture
coordinates during subidivision, then finding the "nearest" option
for "correct" calculated s for interpolated vertices could fix this.
*/
bool haveNXNZ = false;
bool havePXNZ = false;
unsigned i;
for (i = 0; i < 3; i++)
{
if (_vertices[i].v.z < 0)
{
if (_vertices[i].v.x <= 0)
{
haveNXNZ = true;
}
else
{
havePXNZ = true;
}
}
}
if (haveNXNZ && havePXNZ)
{
for (i = 0; i < 3; i++)
{
if (_vertices[i].v.z < 0 && _vertices[i].v.x >= 0)
{
printf("Remapping %g -> %g\n", _vertices[i].s, _vertices[i].s + 1.0);
_vertices[i].s += 1.0;
}
}
}
}
- (NSArray *) subdivide
{
Vector a = _vertices[0].v;
Vector b = _vertices[1].v;
Vector c = _vertices[2].v;
Vector ab = VectorNormal(VectorAdd(a, b));
Vector bc = VectorNormal(VectorAdd(b, c));
Vector ca = VectorNormal(VectorAdd(c, a));
/* Note: vertex orders preserve winding. Triangle order is intended to be
somewhat cache-friendly, but not as good as actually optimizing the
data.
*/
JAIcosTriangle *subTris[4];
subTris[0] = [JAIcosTriangle triangleWithVectorA:a b:ab c:ca];
subTris[3] = [JAIcosTriangle triangleWithVectorA:ab b:bc c:ca];
subTris[1] = [JAIcosTriangle triangleWithVectorA:ab b:b c:bc];
subTris[2] = [JAIcosTriangle triangleWithVectorA:ca b:bc c:c];
return [NSArray arrayWithObjects:subTris count:4];
}
@end

View File

@ -0,0 +1,19 @@
#import "icosmesh.h"
@interface JAVertexSet: NSObject
{
@private
NSMutableDictionary *_indices;
NSMutableArray *_vertices;
}
- (NSUInteger) indexForVertex:(Vertex)vertex;
- (Vertex) vertexAtIndex:(NSUInteger)index;
@property (readonly) NSUInteger count;
- (NSArray *) positionArray; // Array of 3 * count numbers representing vertex positions
- (NSArray *) texCoordArray; // Array of 2 * count numbers representing texture coordinates
@end

View File

@ -0,0 +1,95 @@
#import "JAVertexSet.h"
@implementation JAVertexSet
- (id) init
{
if ((self = [super init]))
{
_indices = [[NSMutableDictionary alloc] init];
_vertices = [[NSMutableArray alloc] init];
if (_indices == NULL || _vertices == NULL)
{
[self release];
return nil;
}
}
return self;
}
- (void) dealloc
{
[_indices release];
[_vertices release];
[super dealloc];
}
- (NSUInteger) indexForVertex:(Vertex)vertex
{
NSValue *value = [NSValue value:&vertex withObjCType:@encode(Vertex)];
NSNumber *number = [_indices objectForKey:value];
if (number == nil)
{
number = [NSNumber numberWithUnsignedInteger:self.count];
[_indices setObject:number forKey:value];
[_vertices addObject:value];
}
return [number unsignedIntegerValue];
}
- (Vertex) vertexAtIndex:(NSUInteger)index
{
if (index >= self.count)
{
[NSException raise:NSRangeException format:@"%s: attempt to access element %u of %u", __FUNCTION__, index, self.count];
}
Vertex result;
[[_vertices objectAtIndex:index] getValue:&result];
return result;
}
- (NSUInteger) count
{
return _vertices.count;
}
- (NSArray *) positionArray
{
unsigned i, count = self.count;
NSMutableArray *result = [NSMutableArray arrayWithCapacity:count * 3];
for (i = 0; i < count; i++)
{
Vertex v = [self vertexAtIndex:i];
[result addObject:[NSNumber numberWithDouble:v.v.x]];
[result addObject:[NSNumber numberWithDouble:v.v.y]];
[result addObject:[NSNumber numberWithDouble:v.v.z]];
}
return result;
}
- (NSArray *) texCoordArray
{
unsigned i, count = self.count;
NSMutableArray *result = [NSMutableArray arrayWithCapacity:count * 2];
for (i = 0; i < count; i++)
{
Vertex v = [self vertexAtIndex:i];
[result addObject:[NSNumber numberWithDouble:v.s]];
[result addObject:[NSNumber numberWithDouble:v.t]];
}
return result;
}
@end

View File

@ -0,0 +1,2 @@
typedef float GLfloat;
typedef unsigned GLuint;

View File

@ -0,0 +1,111 @@
/*
OOPlanetData.c
For Oolite
This file was automatically generated by tools/icosmesh. Do not modify.
This data may be used freely.
*/
#include "OOPlanetData.h"
static const GLfloat kLevel0Vertices[60] =
{
+0.00000000f, +1.00000000f, +0.00000000f /* Magnitude: 1 */,
+0.89442718f, +0.44721359f, +0.00000000f /* Magnitude: 1 */,
+0.27639320f, +0.44721359f, +0.85065079f /* Magnitude: 1 */,
-0.72360682f, +0.44721359f, +0.52573115f /* Magnitude: 1 */,
-0.72360682f, +0.44721359f, -0.52573115f /* Magnitude: 1 */,
+0.27639320f, +0.44721359f, -0.85065079f /* Magnitude: 1 */,
+0.72360682f, -0.44721359f, +0.52573115f /* Magnitude: 1 */,
-0.27639320f, -0.44721359f, +0.85065079f /* Magnitude: 1 */,
-0.89442718f, -0.44721359f, +0.00000000f /* Magnitude: 1 */,
-0.27639320f, -0.44721359f, -0.85065079f /* Magnitude: 1 */,
+0.72360682f, -0.44721359f, -0.52573115f /* Magnitude: 1 */,
+0.00000000f, -1.00000000f, +0.00000000f /* Magnitude: 1 */,
+0.00000000f, +1.00000000f, +0.00000000f /* Magnitude: 1 */,
+0.00000000f, +1.00000000f, +0.00000000f /* Magnitude: 1 */,
+0.00000000f, +1.00000000f, +0.00000000f /* Magnitude: 1 */,
+0.00000000f, +1.00000000f, +0.00000000f /* Magnitude: 1 */,
+0.00000000f, -1.00000000f, +0.00000000f /* Magnitude: 1 */,
+0.00000000f, -1.00000000f, +0.00000000f /* Magnitude: 1 */,
+0.00000000f, -1.00000000f, +0.00000000f /* Magnitude: 1 */,
+0.00000000f, -1.00000000f, +0.00000000f /* Magnitude: 1 */
};
static const GLfloat kLevel0TexCoords[40] =
{
+0.25000000f, +0.00000000f,
+0.25000000f, +0.35241637f,
+0.05000000f, +0.35241637f,
+0.84999996f, +0.35241640f,
+0.65000004f, +0.35241640f,
+0.44999999f, +0.35241637f,
+0.15000001f, +0.64758360f,
+0.94999999f, +0.64758360f,
+0.75000000f, +0.64758360f,
+0.55000001f, +0.64758360f,
+0.34999999f, +0.64758360f,
+0.50000000f, +1.00000000f,
+0.25000000f, +0.00000000f,
+0.25000000f, +0.00000000f,
+0.25000000f, +0.00000000f,
+0.25000000f, +0.00000000f,
+0.50000000f, +1.00000000f,
+0.50000000f, +1.00000000f,
+0.50000000f, +1.00000000f,
+0.50000000f, +1.00000000f
};
static const GLuint kLevel0Indices[60] =
{
0, 1, 2,
12, 2, 3,
13, 3, 4,
14, 4, 5,
15, 5, 1,
11, 6, 7,
16, 7, 8,
17, 8, 9,
18, 9, 10,
19, 10, 6,
1, 2, 6,
2, 3, 7,
3, 4, 8,
4, 5, 9,
5, 1, 10,
6, 7, 2,
7, 8, 3,
8, 9, 4,
9, 10, 5,
10, 6, 1
};
#define kLevel1Vertices 0
#define kLevel1TexCoords 0
#define kLevel1Indices 0
#define kLevel2Vertices 0
#define kLevel2TexCoords 0
#define kLevel2Indices 0
#define kLevel3Vertices 0
#define kLevel3TexCoords 0
#define kLevel3Indices 0
#define kLevel4Vertices 0
#define kLevel4TexCoords 0
#define kLevel4Indices 0
#define kLevel5Vertices 0
#define kLevel5TexCoords 0
#define kLevel5Indices 0
const OOPlanetDataLevel kPlanetData[kOOPlanetDataLevels] =
{
{ 20, 20, kLevel0Vertices, kLevel0Indices, kLevel0TexCoords },
{ 20, 20, kLevel1Vertices, kLevel1Indices, kLevel1TexCoords },
{ 20, 20, kLevel2Vertices, kLevel2Indices, kLevel2TexCoords },
{ 20, 20, kLevel3Vertices, kLevel3Indices, kLevel3TexCoords },
{ 20, 20, kLevel4Vertices, kLevel4Indices, kLevel4TexCoords },
{ 20, 20, kLevel5Vertices, kLevel5Indices, kLevel5TexCoords }
};

View File

@ -0,0 +1,26 @@
/*
OOPlanetData.h
For Oolite
This file was automatically generated by tools/icosmesh. Do not modify.
This data may be used freely.
*/
#import "OOOpenGL.h"
#define kOOPlanetDataLevels 6
typedef struct
{
unsigned vertexCount;
unsigned faceCount;
const GLfloat *vertices; // vertexCount * 3
const GLuint *indices; // faceCount * 3
const GLfloat *texCoords; // vertexCount * 2
} OOPlanetDataLevel;
extern const OOPlanetDataLevel kPlanetData[kOOPlanetDataLevels];

View File

@ -0,0 +1,74 @@
#import "OOPlanetData.h"
#import "OOMaths.h"
#import <stdio.h>
#import <assert.h>
#define kScale 500
static Vector GetVector(GLuint idx)
{
return make_vector(kOOPlanetVertices[idx * 3], kOOPlanetVertices[idx * 3 + 1], kOOPlanetVertices[idx * 3 + 2]);
}
static void WriteDAT(unsigned i);
int main (int argc, const char * argv[])
{
unsigned i;
for (i = 0; i < kOOPlanetDataLevels; i++)
{
WriteDAT(i);
}
return EXIT_SUCCESS;
}
static void WriteDAT(unsigned level)
{
const OOPlanetDataLevel *data = &kPlanetData[level];
char name[20];
snprintf(name, 20, "level_%u.dat", level);
FILE *file = fopen(name, "w");
fprintf(file, "NVERTS %u\nNFACES %u\n\nVERTEX\n", data->vertexCount, data->faceCount);
unsigned i;
for (i = 0; i < data->vertexCount; i++)
{
fprintf(file, "%g, %g, %g\n", kOOPlanetVertices[i * 3] * kScale, kOOPlanetVertices[i * 3 + 1] * kScale, kOOPlanetVertices[i * 3 + 2] * kScale);
}
fprintf(file, "\nFACES\n");
for (i = 0; i < data->faceCount; i++)
{
GLuint a = data->indices[i * 3];
GLuint b = data->indices[i * 3 + 1];
GLuint c = data->indices[i * 3 + 2];
Vector va = GetVector(a);
Vector vb = GetVector(b);
Vector vc = GetVector(c);
Vector n = vector_normal(vector_add(va, vector_add(vb, vc)));
fprintf(file, "1,0,0, %g,%g,%g, 3, %u,%u,%u\n", n.x, n.y, n.z, a, b, c);
}
fprintf(file, "\nTEXTURES\n");
for (i = 0; i < data->faceCount; i++)
{
GLuint a = data->indices[i * 3];
GLuint b = data->indices[i * 3 + 1];
GLuint c = data->indices[i * 3 + 2];
fprintf(file, "world.png 1 1 %g %g %g %g %g %g\n", kOOPlanetTexCoords[a * 2], kOOPlanetTexCoords[a * 2 + 1], kOOPlanetTexCoords[b * 2], kOOPlanetTexCoords[b * 2 + 1], kOOPlanetTexCoords[c * 2], kOOPlanetTexCoords[c * 2 + 1]);
}
fprintf(file, "\nEND\n");
fclose(file);
}

63
tools/icosmesh/icosmesh.h Normal file
View File

@ -0,0 +1,63 @@
#import <Foundation/Foundation.h>
#import <math.h>
typedef struct
{
double x, y, z;
} Vector;
typedef struct
{
Vector v;
double s, t; // Lat/long texture coordinates
} Vertex;
// Convert vector to latitude and longitude (or θ and φ).
void VectorToCoordsRad(Vector vc, double *latitude, double *longitude);
void VectorToCoords0_1(Vector vc, double *latitude, double *longitude);
static inline Vector VectorAdd(Vector u, Vector v)
{
return (Vector){ u.x + v.x, u.y + v.y, u.z + v.z };
}
static inline Vector VectorSubtract(Vector u, Vector v)
{
return (Vector){ u.x - v.x, u.y - v.y, u.z - v.z };
}
static inline double VectorDot(Vector u, Vector v)
{
return u.x * v.x + u.y * v.y + u.z * v.z;
}
static inline double VectorMagnitude(Vector v)
{
return sqrt(VectorDot(v, v));
}
static inline Vector VectorScale(Vector v, double s)
{
return (Vector){ v.x * s, v.y * s, v.z * s };
}
static inline Vector VectorScaleReciprocal(Vector v, double s)
{
return (Vector){ v.x / s, v.y / s, v.z / s };
}
static inline Vector VectorNormal(Vector v)
{
return VectorScaleReciprocal(v, VectorMagnitude(v));
}

View File

@ -0,0 +1,376 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 45;
objects = {
/* Begin PBXBuildFile section */
1A675E6D10B4528F00786F5F /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A675E6C10B4528F00786F5F /* Foundation.framework */; };
1A675ED710B456F200786F5F /* OOFastArithmetic.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A675ED010B456EB00786F5F /* OOFastArithmetic.m */; };
1A675ED810B456F300786F5F /* OOMatrix.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A675ED210B456EB00786F5F /* OOMatrix.m */; };
1A675ED910B456F300786F5F /* OOQuaternion.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A675ED410B456EB00786F5F /* OOQuaternion.m */; };
1A675EDA10B456F300786F5F /* OOVector.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A675ED610B456EB00786F5F /* OOVector.m */; };
1A675F6210B466AF00786F5F /* generatemesh.c in Sources */ = {isa = PBXBuildFile; fileRef = 1A675F6110B466AF00786F5F /* generatemesh.c */; };
1A675F6810B466CE00786F5F /* OOPlanetData.c in Sources */ = {isa = PBXBuildFile; fileRef = 1A675F6610B466CE00786F5F /* OOPlanetData.c */; };
1A675FC710B4710E00786F5F /* OOFastArithmetic.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A675ED010B456EB00786F5F /* OOFastArithmetic.m */; };
1A675FC810B4710F00786F5F /* OOMatrix.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A675ED210B456EB00786F5F /* OOMatrix.m */; };
1A675FC910B4710F00786F5F /* OOQuaternion.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A675ED410B456EB00786F5F /* OOQuaternion.m */; };
1A675FCA10B4711000786F5F /* OOVector.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A675ED610B456EB00786F5F /* OOVector.m */; };
1A67607310B486EE00786F5F /* JAIcosTriangle.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A67605510B479D200786F5F /* JAIcosTriangle.m */; };
1A6760A710B48EC000786F5F /* JAIcosMesh.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A67609610B48C6600786F5F /* JAIcosMesh.m */; };
1A6760A810B48EC200786F5F /* JAVertexSet.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A67608F10B4897B00786F5F /* JAVertexSet.m */; };
8DD76F770486A8DE00D96B5E /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* main.m */; settings = {ATTRIBUTES = (); }; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
1A675F6A10B466F700786F5F /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 8DD76F740486A8DE00D96B5E;
remoteInfo = icosmesh;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
8DD76F7B0486A8DE00D96B5E /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 8;
dstPath = /usr/share/man/man1/;
dstSubfolderSpec = 0;
files = (
);
runOnlyForDeploymentPostprocessing = 1;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
08FB7796FE84155DC02AAC07 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = "<absolute>"; };
1A675E6C10B4528F00786F5F /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
1A675ECD10B456EB00786F5F /* OOMaths.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OOMaths.h; sourceTree = "<group>"; };
1A675ECE10B456EB00786F5F /* OOFunctionAttributes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OOFunctionAttributes.h; sourceTree = "<group>"; };
1A675ECF10B456EB00786F5F /* OOFastArithmetic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OOFastArithmetic.h; sourceTree = "<group>"; };
1A675ED010B456EB00786F5F /* OOFastArithmetic.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OOFastArithmetic.m; sourceTree = "<group>"; };
1A675ED110B456EB00786F5F /* OOMatrix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OOMatrix.h; sourceTree = "<group>"; };
1A675ED210B456EB00786F5F /* OOMatrix.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OOMatrix.m; sourceTree = "<group>"; };
1A675ED310B456EB00786F5F /* OOQuaternion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OOQuaternion.h; sourceTree = "<group>"; };
1A675ED410B456EB00786F5F /* OOQuaternion.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OOQuaternion.m; sourceTree = "<group>"; };
1A675ED510B456EB00786F5F /* OOVector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OOVector.h; sourceTree = "<group>"; };
1A675ED610B456EB00786F5F /* OOVector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OOVector.m; sourceTree = "<group>"; };
1A675F5D10B466A000786F5F /* generatemesh */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = generatemesh; sourceTree = BUILT_PRODUCTS_DIR; };
1A675F6110B466AF00786F5F /* generatemesh.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = generatemesh.c; sourceTree = "<group>"; };
1A675F6610B466CE00786F5F /* OOPlanetData.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = OOPlanetData.c; path = build/Debug/OOPlanetData.c; sourceTree = "<group>"; };
1A675F6710B466CE00786F5F /* OOPlanetData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OOPlanetData.h; path = build/Debug/OOPlanetData.h; sourceTree = "<group>"; };
1A675F7610B4684900786F5F /* OOOpenGL.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OOOpenGL.h; sourceTree = "<group>"; };
1A67605410B479D200786F5F /* JAIcosTriangle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JAIcosTriangle.h; sourceTree = "<group>"; };
1A67605510B479D200786F5F /* JAIcosTriangle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JAIcosTriangle.m; sourceTree = "<group>"; };
1A67605710B479EA00786F5F /* icosmesh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = icosmesh.h; sourceTree = "<group>"; };
1A67608E10B4897B00786F5F /* JAVertexSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JAVertexSet.h; sourceTree = "<group>"; };
1A67608F10B4897B00786F5F /* JAVertexSet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JAVertexSet.m; sourceTree = "<group>"; };
1A67609510B48C6600786F5F /* JAIcosMesh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JAIcosMesh.h; sourceTree = "<group>"; };
1A67609610B48C6600786F5F /* JAIcosMesh.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JAIcosMesh.m; sourceTree = "<group>"; };
8DD76F7E0486A8DE00D96B5E /* icosmesh */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = icosmesh; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
1A675F5B10B466A000786F5F /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
8DD76F780486A8DE00D96B5E /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
1A675E6D10B4528F00786F5F /* Foundation.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
08FB7794FE84155DC02AAC07 /* icosmesh */ = {
isa = PBXGroup;
children = (
08FB7795FE84155DC02AAC07 /* Source */,
1A675ECC10B456EB00786F5F /* OOMaths */,
1A675F6110B466AF00786F5F /* generatemesh.c */,
1A2A9BB010B6CBEB0039208A /* New Group */,
1A675F6410B466BB00786F5F /* Generated files */,
08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */,
19C28FBDFE9D53C911CA2CBB /* Products */,
1A675E6C10B4528F00786F5F /* Foundation.framework */,
);
name = icosmesh;
sourceTree = "<group>";
};
08FB7795FE84155DC02AAC07 /* Source */ = {
isa = PBXGroup;
children = (
08FB7796FE84155DC02AAC07 /* main.m */,
1A67605710B479EA00786F5F /* icosmesh.h */,
1A675F7610B4684900786F5F /* OOOpenGL.h */,
1A67605410B479D200786F5F /* JAIcosTriangle.h */,
1A67605510B479D200786F5F /* JAIcosTriangle.m */,
1A67608E10B4897B00786F5F /* JAVertexSet.h */,
1A67608F10B4897B00786F5F /* JAVertexSet.m */,
1A67609510B48C6600786F5F /* JAIcosMesh.h */,
1A67609610B48C6600786F5F /* JAIcosMesh.m */,
);
name = Source;
sourceTree = "<group>";
};
08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */ = {
isa = PBXGroup;
children = (
09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */,
);
name = "External Frameworks and Libraries";
sourceTree = "<group>";
};
19C28FBDFE9D53C911CA2CBB /* Products */ = {
isa = PBXGroup;
children = (
8DD76F7E0486A8DE00D96B5E /* icosmesh */,
1A675F5D10B466A000786F5F /* generatemesh */,
);
name = Products;
sourceTree = "<group>";
};
1A2A9BB010B6CBEB0039208A /* New Group */ = {
isa = PBXGroup;
children = (
);
name = "New Group";
sourceTree = "<group>";
};
1A675ECC10B456EB00786F5F /* OOMaths */ = {
isa = PBXGroup;
children = (
1A675ECD10B456EB00786F5F /* OOMaths.h */,
1A675ECE10B456EB00786F5F /* OOFunctionAttributes.h */,
1A675ECF10B456EB00786F5F /* OOFastArithmetic.h */,
1A675ED010B456EB00786F5F /* OOFastArithmetic.m */,
1A675ED110B456EB00786F5F /* OOMatrix.h */,
1A675ED210B456EB00786F5F /* OOMatrix.m */,
1A675ED310B456EB00786F5F /* OOQuaternion.h */,
1A675ED410B456EB00786F5F /* OOQuaternion.m */,
1A675ED510B456EB00786F5F /* OOVector.h */,
1A675ED610B456EB00786F5F /* OOVector.m */,
);
name = OOMaths;
path = ../../src/Core;
sourceTree = SOURCE_ROOT;
};
1A675F6410B466BB00786F5F /* Generated files */ = {
isa = PBXGroup;
children = (
1A675F6710B466CE00786F5F /* OOPlanetData.h */,
1A675F6610B466CE00786F5F /* OOPlanetData.c */,
);
name = "Generated files";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
1A675F5C10B466A000786F5F /* generatemesh */ = {
isa = PBXNativeTarget;
buildConfigurationList = 1A675F6310B466B000786F5F /* Build configuration list for PBXNativeTarget "generatemesh" */;
buildPhases = (
1A675F6E10B466FF00786F5F /* ShellScript */,
1A675F5A10B466A000786F5F /* Sources */,
1A675F5B10B466A000786F5F /* Frameworks */,
);
buildRules = (
);
dependencies = (
1A675F6B10B466F700786F5F /* PBXTargetDependency */,
);
name = generatemesh;
productName = generatemesh;
productReference = 1A675F5D10B466A000786F5F /* generatemesh */;
productType = "com.apple.product-type.tool";
};
8DD76F740486A8DE00D96B5E /* icosmesh */ = {
isa = PBXNativeTarget;
buildConfigurationList = 1DEB924708733DCA0010E9CD /* Build configuration list for PBXNativeTarget "icosmesh" */;
buildPhases = (
8DD76F760486A8DE00D96B5E /* Sources */,
8DD76F780486A8DE00D96B5E /* Frameworks */,
8DD76F7B0486A8DE00D96B5E /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = icosmesh;
productInstallPath = "$(HOME)/bin";
productName = icosmesh;
productReference = 8DD76F7E0486A8DE00D96B5E /* icosmesh */;
productType = "com.apple.product-type.tool";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
08FB7793FE84155DC02AAC07 /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
};
buildConfigurationList = 1DEB924B08733DCA0010E9CD /* Build configuration list for PBXProject "icosmesh" */;
compatibilityVersion = "Xcode 3.1";
hasScannedForEncodings = 1;
mainGroup = 08FB7794FE84155DC02AAC07 /* icosmesh */;
projectDirPath = "";
projectRoot = "";
targets = (
8DD76F740486A8DE00D96B5E /* icosmesh */,
1A675F5C10B466A000786F5F /* generatemesh */,
);
};
/* End PBXProject section */
/* Begin PBXShellScriptBuildPhase section */
1A675F6E10B466FF00786F5F /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "cd \"$BUILT_PRODUCTS_DIR\"\n\"$BUILT_PRODUCTS_DIR/icosmesh\"\n\n";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
1A675F5A10B466A000786F5F /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
1A675F6210B466AF00786F5F /* generatemesh.c in Sources */,
1A675F6810B466CE00786F5F /* OOPlanetData.c in Sources */,
1A675FC710B4710E00786F5F /* OOFastArithmetic.m in Sources */,
1A675FC810B4710F00786F5F /* OOMatrix.m in Sources */,
1A675FC910B4710F00786F5F /* OOQuaternion.m in Sources */,
1A675FCA10B4711000786F5F /* OOVector.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
8DD76F760486A8DE00D96B5E /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
8DD76F770486A8DE00D96B5E /* main.m in Sources */,
1A675ED710B456F200786F5F /* OOFastArithmetic.m in Sources */,
1A675ED810B456F300786F5F /* OOMatrix.m in Sources */,
1A675ED910B456F300786F5F /* OOQuaternion.m in Sources */,
1A675EDA10B456F300786F5F /* OOVector.m in Sources */,
1A67607310B486EE00786F5F /* JAIcosTriangle.m in Sources */,
1A6760A710B48EC000786F5F /* JAIcosMesh.m in Sources */,
1A6760A810B48EC200786F5F /* JAVertexSet.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
1A675F6B10B466F700786F5F /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 8DD76F740486A8DE00D96B5E /* icosmesh */;
targetProxy = 1A675F6A10B466F700786F5F /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
1A675F5F10B466A100786F5F /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
COPY_PHASE_STRIP = NO;
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_FIX_AND_CONTINUE = YES;
GCC_MODEL_TUNING = G5;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS_NOT_USED_IN_PRECOMPS = "OOMATHS_STANDALONE=1";
INSTALL_PATH = /usr/local/bin;
OTHER_LDFLAGS = (
"-framework",
Foundation,
"-framework",
AppKit,
);
PREBINDING = NO;
PRODUCT_NAME = generatemesh;
};
name = Debug;
};
1DEB924808733DCA0010E9CD /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
COPY_PHASE_STRIP = NO;
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_FIX_AND_CONTINUE = YES;
GCC_MODEL_TUNING = G5;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS_NOT_USED_IN_PRECOMPS = "OOMATHS_STANDALONE=1";
INSTALL_PATH = /usr/local/bin;
PRODUCT_NAME = icosmesh;
};
name = Debug;
};
1DEB924C08733DCA0010E9CD /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
ONLY_ACTIVE_ARCH = YES;
PREBINDING = NO;
SDKROOT = macosx10.6;
};
name = Debug;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
1A675F6310B466B000786F5F /* Build configuration list for PBXNativeTarget "generatemesh" */ = {
isa = XCConfigurationList;
buildConfigurations = (
1A675F5F10B466A100786F5F /* Debug */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Debug;
};
1DEB924708733DCA0010E9CD /* Build configuration list for PBXNativeTarget "icosmesh" */ = {
isa = XCConfigurationList;
buildConfigurations = (
1DEB924808733DCA0010E9CD /* Debug */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Debug;
};
1DEB924B08733DCA0010E9CD /* Build configuration list for PBXProject "icosmesh" */ = {
isa = XCConfigurationList;
buildConfigurations = (
1DEB924C08733DCA0010E9CD /* Debug */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Debug;
};
/* End XCConfigurationList section */
};
rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
}

289
tools/icosmesh/main.m Normal file
View File

@ -0,0 +1,289 @@
/* icosmesh
Tool to generate subdivided icosahedron mesh data.
*/
#import <stdio.h>
#import "icosmesh.h"
#import "JAIcosTriangle.h"
#import "JAVertexSet.h"
#import "JAIcosMesh.h"
#define kFileName "OOPlanetData"
#define kLevels 6
/* Coordinates of icosahedron with poles on the Y axis.
Based on http://www.csee.umbc.edu/~squire/reference/polyhedra.shtml#icosahedron
*/
static const Vector kBaseVertices[12] =
{
{ +0.000000000000, +1.000000000000, +0.000000000000 },
{ +0.894427200187, +0.447213577125, +0.000000000000 },
{ +0.276393205089, +0.447213577125, +0.850650817090 },
{ -0.723606805183, +0.447213577125, +0.525731117519 },
{ -0.723606805183, +0.447213577125, -0.525731117519 },
{ +0.276393205089, +0.447213577125, -0.850650817090 },
{ +0.723606805183, -0.447213577125, +0.525731117519 },
{ -0.276393205089, -0.447213577125, +0.850650817090 },
{ -0.894427200187, -0.447213577125, +0.000000000000 },
{ -0.276393205089, -0.447213577125, -0.850650817090 },
{ +0.723606805183, -0.447213577125, -0.525731117519 },
{ +0.000000000000, -1.000000000000, +0.000000000000 }
};
#define kBaseFaceCount 20
static const struct { unsigned a, b, c; } kBaseTriangles[kBaseFaceCount] =
{
{ 0, 1, 2 },
{ 0, 2, 3 },
{ 0, 3, 4 },
{ 0, 4, 5 },
{ 0, 5, 1 },
{ 11, 6, 7 },
{ 11, 7, 8 },
{ 11, 8, 9 },
{ 11, 9, 10 },
{ 11, 10, 6 },
{ 1, 2, 6 },
{ 2, 3, 7 },
{ 3, 4, 8 },
{ 4, 5, 9 },
{ 5, 1, 10 },
{ 6, 7, 2 },
{ 7, 8, 3 },
{ 8, 9, 4 },
{ 9, 10, 5 },
{ 10, 6, 1 }
};
static NSArray *SubdivideMesh(NSArray *triangles);
static void WritePrelude(FILE *header, FILE *source);
static void WriteVertices(FILE *header, FILE *source, JAVertexSet *vertices);
static void WriteMeshForTriangles(FILE *source, unsigned level, NSArray *triangles, JAVertexSet *vertices, unsigned *faceCount, unsigned *maxVertex);
static void WriteMesh(FILE *source, unsigned level, JAIcosMesh *mesh);
int main (int argc, const char * argv[])
{
NSAutoreleasePool *pool = [NSAutoreleasePool new];
FILE *header = fopen(kFileName ".h", "w");
FILE *source = fopen(kFileName ".c", "w");
if (header == NULL || source == NULL)
{
fprintf(stderr, "Failed to open output files.\n");
return EXIT_FAILURE;
}
WritePrelude(header, source);
// Load up the base triangles.
unsigned i;
NSMutableArray *baseTriangles = [NSMutableArray arrayWithCapacity:kBaseFaceCount];
for (i = 0; i < kBaseFaceCount; i++)
{
Vector a = kBaseVertices[kBaseTriangles[i].a];
Vector b = kBaseVertices[kBaseTriangles[i].b];
Vector c = kBaseVertices[kBaseTriangles[i].c];
// printf("%g %g %g %g %g %g %g %g %g\n", a.x, a.y, a.z, b.x, b.y, b.z, c.x, c.y, c.z);
JAIcosTriangle *tri = [JAIcosTriangle triangleWithVectorA:a b:b c:c];
[baseTriangles addObject:tri];
}
unsigned faceCount[kLevels];
unsigned maxIndex[kLevels];
JAVertexSet *vertices = [[[JAVertexSet alloc] init] autorelease];
WriteMeshForTriangles(source, 0, baseTriangles, vertices, &faceCount[0], &maxIndex[0]);
NSArray *triangles = baseTriangles;
for (i = 1; i < kLevels; i++)
{
triangles = (NSMutableArray *)SubdivideMesh(triangles);
WriteMeshForTriangles(source, i, triangles, vertices, &faceCount[i], &maxIndex[i]);
}
WriteVertices(header, source, vertices);
fprintf(source, "\n\nconst OOPlanetDataLevel kPlanetData[kOOPlanetDataLevels] =\n{\n");
for (i = 0; i < kLevels; i++)
{
if (i != 0) fprintf(source, ",\n");
fprintf(source, "\t%u, %u, kFaceIndicesLevel%u", maxIndex[i], faceCount[i], i);
}
fprintf(source, "\n};\n");
fclose(header);
fclose(source);
[pool release];
return EXIT_SUCCESS;
}
static NSArray *SubdivideMesh(NSArray *triangles)
{
NSMutableArray *result = [NSMutableArray arrayWithCapacity:triangles.count * 4];
for (JAIcosTriangle *triangle in triangles)
{
[result addObjectsFromArray:[triangle subdivide]];
}
return result;
}
static void WritePrelude(FILE *header, FILE *source)
{
fprintf(header,
"/*\n"
"\t%s.h\n"
"\tFor Oolite\n"
"\t\n"
"\tThis file was automatically generated by tools/icosmesh. Do not modify.\n"
"\t\n"
"\tThis data may be used freely.\n"
"*/\n"
"\n"
"#import \"OOOpenGL.h\"\n"
"\n"
"\n"
"#define kOOPlanetDataLevels %u\n"
"\n"
"\n"
"typedef struct\n"
"{\n"
"\tunsigned vertexCount;\n"
"\tunsigned faceCount;\n"
"\tconst GLuint *indices; // faceCount * 3\n"
"} OOPlanetDataLevel;\n"
"\n"
"\n"
"extern const OOPlanetDataLevel kPlanetData[kOOPlanetDataLevels];\n", kFileName, kLevels);
fprintf(source,
"/*\n"
"\t%s.c\n"
"\tFor Oolite\n"
"\t\n"
"\tThis file was automatically generated by tools/icosmesh. Do not modify.\n"
"\t\n"
"\tThis data may be used freely.\n"
"*/\n"
"\n"
"#include \"OOPlanetData.h\"\n", kFileName);
}
static void WriteVertices(FILE *header, FILE *source, JAVertexSet *vertices)
{
unsigned i, count = vertices.count;
fprintf(header, "\n\nextern const GLfloat kOOPlanetVertices[%u];\n", count * 3);
fprintf(header, "\nextern const GLfloat kOOPlanetTexCoords[%u];\n", count * 2);
fprintf(source, "\n\n/* Shared vertex array\n %u vertices\n*/\nconst GLfloat kOOPlanetVertices[%u] =\n{\n", count, count * 3);
NSArray *data = [vertices positionArray];
for (i = 0; i < count; i++)
{
if (i != 0) fprintf(source, ",\n");
fprintf(source, "\t%+.8ff, %+.8ff, %+.8ff", [[data objectAtIndex:i * 3] doubleValue], [[data objectAtIndex:i * 3 + 1] doubleValue], [[data objectAtIndex:i * 3 + 2] doubleValue]);
}
fprintf(source, "\n};\n\n/* Shared texture coordinate array\n %u pairs\n*/\nconst GLfloat kOOPlanetTexCoords[%u] =\n{\n", count, count * 2);
data = [vertices texCoordArray];
for (i = 0; i < count; i++)
{
if (i != 0) fprintf(source, ",\n");
fprintf(source, "\t%+.8ff, %+.8ff", [[data objectAtIndex:i * 2] doubleValue], [[data objectAtIndex:i * 2 + 1] doubleValue]);
}
fprintf(source, "\n};\n");
}
static void WriteMeshForTriangles(FILE *source, unsigned level, NSArray *triangles, JAVertexSet *vertices, unsigned *faceCount, unsigned *maxVertex)
{
JAIcosMesh *mesh = [JAIcosMesh meshWithVertexSet:vertices];
[mesh addTriangles:triangles];
WriteMesh(source, level, mesh);
*faceCount = mesh.faceCount;
*maxVertex = mesh.maxIndex + 1;
}
static void WriteMesh(FILE *source, unsigned level, JAIcosMesh *mesh)
{
unsigned i, count = mesh.faceCount;
NSArray *indices = [mesh indexArray];
fprintf(source, "\n\n/* Level %u index array\n %u faces\n*/\nstatic const GLuint kFaceIndicesLevel%u[%u] =\n{\n", level, count, level, count * 3);
for (i = 0; i < count; i++)
{
if (i != 0) fprintf(source, ",\n");
fprintf(source, "\t%5u, %5u, %5u", [[indices objectAtIndex:i * 3] unsignedIntValue], [[indices objectAtIndex:i * 3 + 1] unsignedIntValue], [[indices objectAtIndex:i * 3 + 2] unsignedIntValue]);
}
fprintf(source, "\n};\n");
}
// Convert vector to latitude and longitude (or θ and φ).
void VectorToCoordsRad(Vector v, double *latitude, double *longitude)
{
v = VectorNormal(v);
double las = v.y;
if (las != 1.0f)
{
double lat = asin(las);
double rlac = 1.0 / sqrt(1.0 - las * las); // Equivalent to abs(1/cos(lat))
if (latitude != NULL) *latitude = lat;
if (longitude != NULL)
{
double los = v.x * rlac;
double lon = asin(fmin(1.0, fmax(-1.0, los)));
// Quadrant rectification.
if (v.z < 0.0f)
{
// We're beyond 90 degrees of longitude in some direction.
if (v.x < 0.0f)
{
// ...specifically, west.
lon = -M_PI - lon;
}
else
{
// ...specifically, east.
lon = M_PI - lon;
}
}
*longitude = lon;
}
}
else
{
// Straight up, avoid divide-by-zero
if (latitude != NULL) *latitude = M_PI / 2.0f;
if (longitude != NULL) *longitude = 0.0f; // arbitrary
}
}
void VectorToCoords0_1(Vector v, double *latitude, double *longitude)
{
VectorToCoordsRad(v, latitude, longitude);
if (latitude != NULL) *latitude = 1.0 - (*latitude / M_PI + 0.5);
if (longitude != NULL) *longitude = 1.0 - (*longitude / (M_PI * 2.0) + 0.5);
}

BIN
tools/icosmesh/world.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 MiB