~ubuntu-branches/ubuntu/wily/oolite/wily-proposed

« back to all changes in this revision

Viewing changes to tools/icosmesh/JAIcosTriangle.m

  • Committer: Package Import Robot
  • Author(s): Nicolas Boulenguez
  • Date: 2011-12-22 00:22:39 UTC
  • mfrom: (1.2.2)
  • Revision ID: package-import@ubuntu.com-20111222002239-pr3upeupp4jw1psp
Tags: 1.76-1
* New upstream.
* watch: scan upstream stable releases instead of dev snapshots.
* control: use default gobjc instead of explicit 4.6.
* rules: use dpkg-dev build flags.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//
 
2
//  JAIcosTriangle.m
 
3
//  icosmesh
 
4
//
 
5
//  Created by Jens Ayton on 2009-11-18.
 
6
//  Copyright 2009 Jens Ayton. All rights reserved.
 
7
//
 
8
 
 
9
#import "JAIcosTriangle.h"
 
10
 
 
11
 
 
12
static inline BOOL IsPolarVector(Vector v)
 
13
{
 
14
        return v.x == 0.0 && v.z == 0.0;
 
15
}
 
16
 
 
17
 
 
18
@interface JAIcosTriangle ()
 
19
 
 
20
- (void) rotate;        // a = b, b = c, c = a
 
21
- (void) generateTextureCoordinatesAndBinormals;        // Requires that any polar coordinate is in [0].
 
22
- (void) fixUpWinding;
 
23
 
 
24
@end
 
25
 
 
26
 
 
27
static NSComparisonResult CompareVertices(Vertex *a, Vertex *b)
 
28
{
 
29
        return NSOrderedSame;
 
30
}
 
31
 
 
32
 
 
33
static NSString *VertexDescription(Vertex v)
 
34
{
 
35
        return [NSString stringWithFormat:@"{ %g, %g, %g} (%g, %g)", v.v.x, v.v.y, v.v.z, v.s, v.t];
 
36
}
 
37
 
 
38
 
 
39
@implementation JAIcosTriangle
 
40
 
 
41
+ (id) triangleWithVectorA:(Vector)a b:(Vector)b c:(Vector)c
 
42
{
 
43
        return [[self alloc] initWithVectorA:a b:b c:c];
 
44
}
 
45
 
 
46
 
 
47
- (id) initWithVectorA:(Vector)a b:(Vector)b c:(Vector)c
 
48
{
 
49
        if ((self = [super init]))
 
50
        {
 
51
                _vertices[0].v = VectorNormal(a);
 
52
                _vertices[1].v = VectorNormal(b);
 
53
                _vertices[2].v = VectorNormal(c);
 
54
                
 
55
                // If one of our vertices is a pole, make it the first.
 
56
                if (IsPolarVector(_vertices[2].v))  [self rotate];
 
57
                if (IsPolarVector(_vertices[1].v))  [self rotate];
 
58
                
 
59
                // Ensure winding is consistent.
 
60
                [self fixUpWinding];
 
61
                
 
62
                [self generateTextureCoordinatesAndBinormals];
 
63
        }
 
64
        
 
65
        return self;
 
66
}
 
67
 
 
68
 
 
69
- (NSString *) description
 
70
{
 
71
        return [NSString stringWithFormat:@"{%@, %@, %@}", VertexDescription(_vertices[0]), VertexDescription(_vertices[1]), VertexDescription(_vertices[2])];
 
72
}
 
73
 
 
74
 
 
75
- (Vertex) vertexA
 
76
{
 
77
        return _vertices[0];
 
78
}
 
79
 
 
80
 
 
81
- (Vertex) vertexB
 
82
{
 
83
        return _vertices[1];
 
84
}
 
85
 
 
86
 
 
87
- (Vertex) vertexC
 
88
{
 
89
        return _vertices[2];
 
90
}
 
91
 
 
92
 
 
93
- (void) rotate
 
94
{
 
95
        Vertex temp = _vertices[0];
 
96
        _vertices[0] = _vertices[1];
 
97
        _vertices[1] = _vertices[2];
 
98
        _vertices[2] = temp;
 
99
}
 
100
 
 
101
 
 
102
static inline Vector BinormalFromNormal(Vector v)
 
103
{
 
104
        return VectorNormal(VectorCross(v, (Vector){0, 1.0, 0.0}));
 
105
}
 
106
 
 
107
 
 
108
- (void) generateTextureCoordinatesAndBinormals
 
109
{
 
110
        VectorToCoords0_1(_vertices[1].v, &_vertices[1].t, &_vertices[1].s);
 
111
        VectorToCoords0_1(_vertices[2].v, &_vertices[2].t, &_vertices[2].s);
 
112
        if (!IsPolarVector(_vertices[0].v))  VectorToCoords0_1(_vertices[0].v, &_vertices[0].t, &_vertices[0].s);
 
113
        else
 
114
        {
 
115
                // Use longitude of average of v1 and v2.
 
116
                VectorToCoords0_1(VectorAdd(_vertices[1].v, _vertices[2].v), NULL, &_vertices[0].s);
 
117
                _vertices[0].t = (_vertices[0].v.y < 0) ? 1.0 : 0.0;
 
118
        }
 
119
        
 
120
        /*      Texture seam handling
 
121
                At the back of the mesh, at the longitude = 180°/-180° meridian, the
 
122
                texture wraps around. However, there isn't a convenient matching seam
 
123
                in the geometry - there are no great circles touching "poles" (source
 
124
                vertices) on a subdivided icosahedron - so we need to adjust texture
 
125
                coordinates and use the GL_REPEAT texture wrapping mode to cover it
 
126
                over.
 
127
                
 
128
                The technique is to establish whether we have at least one vertex in
 
129
                each of the (x, -z) and (-x, -z) quadrants, and if so, add 1 to the
 
130
                texture coordinates for the vertices in (-x, -z) -- corresponding to
 
131
                the east Pacific.
 
132
                
 
133
                NOTE: this technique is suboptimal because the selection of wrapped
 
134
                vertices changes at each subdivision level. Interpolating texture
 
135
                coordinates during subidivision, then finding the "nearest" option
 
136
                for "correct" calculated s for interpolated vertices could fix this.
 
137
        */
 
138
        
 
139
        bool haveNXNZ = false;
 
140
        bool havePXNZ = false;
 
141
        unsigned i;
 
142
        for (i = 0; i < 3; i++)
 
143
        {
 
144
                if (_vertices[i].v.z < 0)
 
145
                {
 
146
                        if (_vertices[i].v.x < 0)
 
147
                        {
 
148
                                haveNXNZ = true;
 
149
                        }
 
150
                        else
 
151
                        {
 
152
                                havePXNZ = true;
 
153
                        }
 
154
                }
 
155
        }
 
156
        
 
157
        if (haveNXNZ && havePXNZ)
 
158
        {
 
159
                for (i = 0; i < 3; i++)
 
160
                {
 
161
                        if (_vertices[i].v.z < 0 && _vertices[i].v.x >= 0)
 
162
                        {
 
163
        //                      printf("Remapping %g -> %g\n", _vertices[i].s, _vertices[i].s + 1.0);
 
164
                                _vertices[i].s += 1.0;
 
165
                        }
 
166
                }
 
167
                if (_vertices[0].v.y == -1.0)
 
168
                {
 
169
                        /*      Special case: also need to wrap the polar coordinate of the
 
170
                                southernmost seam triangle.
 
171
                         */
 
172
                        _vertices[0].s += 1.0;
 
173
                }
 
174
        }
 
175
        
 
176
#if OUTPUT_BINORMALS
 
177
        /*      Binormals
 
178
                For non-polar points, the binormal is the cross product of the normal
 
179
                (equal to the vertex, for a unit sphere) and the Y axis. At the poles,
 
180
                this is a singularity and we use the average of the other two binormals
 
181
                instead.
 
182
                
 
183
                Note: for non-polar vertices, it makes sense to calculate this in the
 
184
                shaders instead. It may be better to use texture coordinates to handle
 
185
                polar coordinates instead of using an attribute.
 
186
         */
 
187
        _vertices[1].binormal = BinormalFromNormal(_vertices[1].v);
 
188
        _vertices[2].binormal = BinormalFromNormal(_vertices[2].v);
 
189
        if (!IsPolarVector(_vertices[0].v))  _vertices[0].binormal = BinormalFromNormal(_vertices[0].v);
 
190
        else
 
191
        {
 
192
                _vertices[0].binormal = VectorNormal(VectorAdd(_vertices[1].binormal, _vertices[2].binormal));
 
193
        }
 
194
#endif
 
195
}
 
196
 
 
197
 
 
198
- (NSArray *) subdivide
 
199
{
 
200
        Vector a = _vertices[0].v;
 
201
        Vector b = _vertices[1].v;
 
202
        Vector c = _vertices[2].v;
 
203
        
 
204
        Vector ab = VectorNormal(VectorAdd(a, b));
 
205
        Vector bc = VectorNormal(VectorAdd(b, c));
 
206
        Vector ca = VectorNormal(VectorAdd(c, a));
 
207
        
 
208
        /*      Note: vertex orders preserve winding. Triangle order is intended to be
 
209
                somewhat cache-friendly, but not as good as actually optimizing the
 
210
                data.
 
211
        */
 
212
        JAIcosTriangle *subTris[4];
 
213
        subTris[0] = [JAIcosTriangle triangleWithVectorA:a b:ab c:ca];
 
214
        subTris[3] = [JAIcosTriangle triangleWithVectorA:ab b:bc c:ca];
 
215
        subTris[1] = [JAIcosTriangle triangleWithVectorA:ab b:b c:bc];
 
216
        subTris[2] = [JAIcosTriangle triangleWithVectorA:ca b:bc c:c];
 
217
        
 
218
        return [NSArray arrayWithObjects:subTris count:4];
 
219
}
 
220
 
 
221
 
 
222
- (void) fixUpWinding
 
223
{
 
224
        // Construct vectors from v0 to v1 and v0 to v2.
 
225
        Vector ab = VectorSubtract(_vertices[1].v, _vertices[0].v);
 
226
        Vector ac = VectorSubtract(_vertices[2].v, _vertices[0].v);
 
227
        
 
228
        // Take their cross product.
 
229
        Vector cross = VectorCross(ab, ac);
 
230
        
 
231
        // For a correctly-wound triangle, this should point inwards.
 
232
        // Since our corner vectors point generally outwards, the dot product of
 
233
        // any of these with cross should be negative.
 
234
        if (VectorDot(cross, _vertices[0].v) > 0)
 
235
        {
 
236
                // If not, we swap v1 and v2.
 
237
                Vertex temp = _vertices[1];
 
238
                _vertices[1] = _vertices[2];
 
239
                _vertices[2] = temp;
 
240
        }
 
241
}
 
242
 
 
243
@end