78 NSMutableString *debugSVG;
101#define SVGDumpEnd(data) do {} while (0)
102#define SVGDumpBeginGroup(data, name) do {} while (0)
103#define SVGDumpEndGroup(data) do {} while (0)
104#define SVGDumpAppendBaseContour(data, points) do {} while (0)
105#define SVGDumpBeginPrimitive(data) do {} while (0)
106#define SVGDumpEndPrimitive(data) do {} while (0)
107#define SVGDumpAppendTriangle(data, v0, v1, v2) do {} while (0)
113static void APIENTRY TessCombineCallback(GLdouble coords[3],
void *vertexData[4], GLfloat weight[4],
void **outData,
void *polygonData);
121- (id) initWithDataArray:(NSArray *)dataArray outlineWidth:(GLfloat)outlineWidth name:(NSString *)name
123 if ((
self = [super init]))
129 if ([dataArray
count] == 0)
136 if (![[dataArray objectAtIndex:0] isKindOfClass:[NSArray class]])
138 dataArray = [NSArray arrayWithObject:dataArray];
140 if (![
self loadPolygons:dataArray outlineWidth:outlineWidth])
168- (NSString *) descriptionComponents
175- (void) drawWithData:(GLfloat *)data count:(
size_t)count VBO:(GLuint *)vbo
177 if (
count == 0)
return;
178 NSParameterAssert(vbo != NULL && data != NULL);
190 OOGL(glGenBuffersARB(1, vbo));
193 OOGL(glBindBufferARB(GL_ARRAY_BUFFER, *vbo));
194 OOGL(glBufferDataARB(GL_ARRAY_BUFFER,
sizeof (GLfloat) *
count * 2, data, GL_STATIC_DRAW));
199 OOGL(glBindBufferARB(GL_ARRAY_BUFFER, *vbo));
201 if (*vbo != 0) data = NULL;
205 OOGL(glEnableClientState(GL_VERTEX_ARRAY));
206 OOGL(glVertexPointer(2, GL_FLOAT, 0, data));
207 OOGL(glDrawArrays(GL_TRIANGLES, 0,
count));
208 OOGL(glDisableClientState(GL_VERTEX_ARRAY));
211 if (useVBO)
OOGL(glBindBufferARB(GL_ARRAY_BUFFER, 0));
225 [
self drawWithData:_solidData count:_solidCount VBO:&_solidVBO];
235 [
self drawWithData:_outlineData count:_outlineCount VBO:&_outlineVBO];
244 if (_solidVBO != 0) glDeleteBuffersARB(1, &_solidVBO);
245 if (_outlineVBO != 0) glDeleteBuffersARB(1, &_outlineVBO);
254- (BOOL) loadPolygons:(NSArray *)dataArray outlineWidth:(
float)outlineWidth
256 NSParameterAssert(dataArray !=
nil);
258 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
259 GLUtesselator *tesselator = NULL;
262 memset(&polygonData, 0,
sizeof polygonData);
263 polygonData.
OK = YES;
265 polygonData.
name = _name;
266 if ([[NSUserDefaults standardUserDefaults] boolForKey:
@"polygon-sprite-dump-svg"])
SVGDumpBegin(&polygonData);
276 tesselator = gluNewTess();
277 if (tesselator == NULL)
289 gluTessCallback(tesselator, GLU_TESS_ERROR_DATA,
ErrorCallback);
292 gluTessBeginPolygon(tesselator, &polygonData);
295 NSUInteger contourCount = [dataArray count], contourIndex;
296 for (contourIndex = 0; contourIndex < contourCount && polygonData.
OK; contourIndex++)
298 NSArray *contour = [dataArray oo_arrayAtIndex:contourIndex];
308 gluTessEndPolygon(tesselator);
313 _solidCount = polygonData.
count;
315 if (_solidCount != 0)
317 _solidData = realloc(polygonData.
data, polygonData.
count * sizeof (GLfloat) * 2);
318 if (_solidData != NULL) polygonData.
data = NULL;
322 _solidData = polygonData.
data;
323 if (_solidData == NULL) polygonData.
OK = NO;
332 if (!polygonData.
OK)
goto END;
335 gluDeleteTess(tesselator);
336 tesselator = gluNewTess();
337 if (tesselator == NULL)
343 polygonData.
count = 0;
357 gluTessCallback(tesselator, GLU_TESS_ERROR_DATA,
ErrorCallback);
359 gluTessProperty(tesselator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE);
361 gluTessBeginPolygon(tesselator, &polygonData);
364 outlineWidth *= 0.5f;
365 contourCount = [dataArray count];
366 for (contourIndex = 0; contourIndex < contourCount && polygonData.
OK; contourIndex++)
368 NSArray *contour = [dataArray oo_arrayAtIndex:contourIndex];
379 gluTessEndPolygon(tesselator);
384 if (polygonData.
count != 0)
386 _outlineCount = polygonData.
count;
387 _outlineData = realloc(polygonData.
data, polygonData.
count * sizeof (GLfloat) * 2);
388 if (_outlineData != NULL) polygonData.
data = NULL;
392 _outlineData = polygonData.
data;
393 if (_outlineData == NULL) polygonData.
OK = NO;
406 free(polygonData.
data);
407 gluDeleteTess(tesselator);
412 return polygonData.
OK;
420 NSUInteger vertexCount = [contour count], vertexIndex;
423 gluTessBeginContour(tesselator);
425 for (vertexIndex = 0; vertexIndex < vertexCount && polygonData->
OK; vertexIndex++)
427 NSValue *pointValue = [contour objectAtIndex:vertexIndex];
428 NSPoint p = [pointValue pointValue];
429 GLdouble vert[3] = { p.x, p.y, 0.0 };
431 gluTessVertex(tesselator, vert, pointValue);
434 gluTessEndContour(tesselator);
454 NSUInteger polyIter, polyCount = [dataArray count];
455 NSArray *subArrays[polyCount];
457 for (polyIter = 0; polyIter < polyCount; polyIter++)
459 NSArray *polyDef = [dataArray objectAtIndex:polyIter];
460 NSUInteger vertIter, vertCount = [polyDef count] / 2;
461 NSMutableArray *newPolyDef = [NSMutableArray arrayWithCapacity:vertCount];
464 CGFloat oldX = [polyDef oo_doubleAtIndex:(vertCount -1) * 2];
465 CGFloat oldY = [polyDef oo_doubleAtIndex:(vertCount -1) * 2 + 1];
467 for (vertIter = 0; vertIter < vertCount; vertIter++)
469 CGFloat
x = [polyDef oo_doubleAtIndex:vertIter * 2];
470 CGFloat
y = [polyDef oo_doubleAtIndex:vertIter * 2 + 1];
473 if (
x == oldX &&
y == oldY)
continue;
474 if (isnan(
x) || isnan(
y))
continue;
475 if (!isfinite(
x) || !isfinite(
y))
continue;
477 area +=
x * oldY - oldX *
y;
482 [newPolyDef addObject:[NSValue valueWithPoint:NSMakePoint(x, y)]];
486 while ([newPolyDef
count] > 1 && [[newPolyDef objectAtIndex:0] isEqual:[newPolyDef lastObject]])
488 [newPolyDef removeLastObject];
493 subArrays[polyIter] = newPolyDef;
497 subArrays[polyIter] = [[newPolyDef reverseObjectEnumerator] allObjects];
504 return [NSArray arrayWithObjects:subArrays count:polyCount];
510 NSUInteger i,
count = [dataArray count];
511 if (
count < 2)
return dataArray;
547 NSPoint prev, current, next;
550 prev = [[dataArray objectAtIndex:0] pointValue];
551 current = [[dataArray objectAtIndex:count -1] pointValue];
552 next = [[dataArray objectAtIndex:count - 2] pointValue];
556 prev = [[dataArray objectAtIndex:count - 1] pointValue];
557 current = [[dataArray objectAtIndex:0] pointValue];
558 next = [[dataArray objectAtIndex:1] pointValue];
561 NSMutableArray *result = [NSMutableArray arrayWithCapacity:count];
563 for (i = 0; i <
count; i++)
568 CGFloat dot =
PtDot(a, b);
569 BOOL clockwise =
PtCross(a, b) < 0.0f;
577 if (!isnan(v.x) && !isnan(v.y))
579 [result addObject:[NSValue valueWithPoint:PtAdd(v, current)]];
588 if (!isnan(v1.x) && !isnan(v1.y))
590 [result addObject:[NSValue valueWithPoint:PtAdd(v1, current)]];
592 if (!isnan(v2.x) && !isnan(v2.y))
594 [result addObject:[NSValue valueWithPoint:PtAdd(v2, current)]];
603 next = [[dataArray objectAtIndex:(count * 2 - 3 - i) % count] pointValue];
607 next = [[dataArray objectAtIndex:(i + 2) % count] pointValue];
617 NSCParameterAssert(data != NULL);
619 size_t minCapacity = data->
capacity + 1;
620 size_t desiredCapacity =
MAX(capacityHint, minCapacity);
621 size_t newCapacity = 0;
622 GLfloat *newData = realloc(data->
data, desiredCapacity * sizeof (GLfloat) * 2);
625 newCapacity = desiredCapacity;
629 desiredCapacity = minCapacity;
630 newData = realloc(data->
data, desiredCapacity * sizeof (GLfloat) * 2);
631 if (newData != NULL) newCapacity = desiredCapacity;
634 if (newData == NULL)
return NO;
636 NSCAssert(newCapacity > data->
capacity,
@"Buffer regrow logic error");
638 data->
data = newData;
646 NSCParameterAssert(data != NULL);
650 data->
data[data->count * 2] = vertex.x;
651 data->
data[data->count * 2 + 1] = vertex.y;
660 NSCParameterAssert(data != NULL);
672 NSValue *vertValue = vertexData;
673 NSCParameterAssert(vertValue != NULL && data != NULL);
674 if (!data->
OK)
return;
676 NSPoint p = [vertValue pointValue];
677 NSPoint vertex = { p.x, p.y };
678 size_t vCount = data->
vCount++;
701 case GL_TRIANGLE_FAN:
702 if (vCount == 0) data->
pending0 = vertex;
703 else if (vCount == 1) data->
pending1 = vertex;
714 case GL_TRIANGLE_STRIP:
715 if (vCount == 0) data->
pending0 = vertex;
716 else if (vCount == 1) data->
pending1 = vertex;
746 if ((vCount % 2) == 0) data->
pending0 = vertex;
752 OOLog(
@"polygonSprite.tesselate.error",
@"Unexpected tesselator primitive mode %u.", data->
mode);
760 NSPoint point = { coords[0], coords[1] };
761 *outData = [NSValue valueWithPoint:point];
768 NSCParameterAssert(data != NULL);
780 NSCParameterAssert(data != NULL);
782 NSString *name =
@"";
784 name = [NSString stringWithFormat:@" \"%@\"", data->name];
787 char *errStr = (
char *)gluErrorString(error);
789 OOLog(
@"polygonSprite.tesselate.error",
@"Error %s (%u) while tesselating polygon%@.", errStr, error, name);
800 data->
debugSVG = [[NSMutableString alloc] initWithString:
801 @"<?xml version=\"1.0\" standalone=\"no\"?>\n"
802 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n"
803 "<svg viewBox=\"-5 -5 10 10\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n"
804 "\t<desc>Oolite polygon sprite debug dump.</desc>\n"
814 [data->debugSVG appendString:@"</svg>\n"];
824 [data->debugSVG appendFormat:@"\t<g id=\"%@ %u\">\n", name, data->svgID++];
831 [data->debugSVG appendString:@"\t</g>\n"];
839 NSString *groupName = [NSString stringWithFormat:@"contour %u", data->svgID++];
840 [data->debugSVG appendFormat:@"\t\t<g id=\"%@\" stroke=\"#BBB\" fill=\"none\">\n\t\t<path stroke-width=\"0.05\" d=\"", groupName];
842 NSUInteger i,
count = [points count];
843 for (i = 0; i <
count; i++)
845 NSPoint p = [[points objectAtIndex:i] pointValue];
846 [data->debugSVG appendFormat:@"%c %f %f ", (i == 0) ? 'M' : 'L', p.x, -p.y];
850 NSPoint p = [[points objectAtIndex:0] pointValue];
851 [data->debugSVG appendFormat:@"z\"/>\n\t\t\t<circle cx=\"%f\" cy=\"%f\" r=\"0.1\" fill=\"#BBB\" stroke=\"none\"/>\n\t\t</g>\n", p.x, -p.y];
859 NSString *groupName =
@"Unknown primitive";
863 groupName =
@"Triangle soup";
866 case GL_TRIANGLE_FAN:
867 groupName =
@"Triangle fan";
870 case GL_TRIANGLE_STRIP:
871 groupName =
@"Triangle strip";
874 groupName = [groupName stringByAppendingFormat:@" %u", data->svgID++];
877 uint8_t red = (
Ranrot() & 0x3F) + 0x20;
878 uint8_t green = (
Ranrot() & 0x3F) + 0x20;
879 uint8_t blue = (
Ranrot() & 0x3F) + 0x20;
887 [data->debugSVG appendFormat:@"\t\t<g id=\"%@\" fill=\"#%2X%2X%2X\" fill-opacity=\"0.3\" stroke=\"%@\" stroke-width=\"0.01\">\n", groupName, red, green, blue, data->generatingOutline ? @"#060" : @"#008"];
894 [data->debugSVG appendString:@"\t\t</g>\n"];
901 [data->debugSVG appendFormat:@"\t\t\t<path d=\"M %f %f L %f %f L %f %f z\"/>\n", v0.x, -v0.y, v1.x, -v1.y, v2.x, -v2.y];