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);
124- (id) initWithDataArray:(NSArray *)dataArray outlineWidth:(GLfloat)outlineWidth name:(NSString *)name
126 if ((
self = [super init]))
132 if ([dataArray
count] == 0)
139 if (![[dataArray objectAtIndex:0] isKindOfClass:[NSArray
class]])
141 dataArray = [NSArray arrayWithObject:dataArray];
143 if (![
self loadPolygons:dataArray outlineWidth:outlineWidth])
171- (NSString *) descriptionComponents
178- (void) drawWithData:(GLfloat *)data count:(
size_t)count VBO:(GLuint *)vbo
180 if (
count == 0)
return;
181 NSParameterAssert(vbo != NULL && data != NULL);
193 OOGL(glGenBuffersARB(1, vbo));
196 OOGL(glBindBufferARB(GL_ARRAY_BUFFER, *vbo));
197 OOGL(glBufferDataARB(GL_ARRAY_BUFFER,
sizeof (GLfloat) *
count * 2, data, GL_STATIC_DRAW));
202 OOGL(glBindBufferARB(GL_ARRAY_BUFFER, *vbo));
204 if (*vbo != 0) data = NULL;
208 OOGL(glEnableClientState(GL_VERTEX_ARRAY));
209 OOGL(glVertexPointer(2, GL_FLOAT, 0, data));
210 OOGL(glDrawArrays(GL_TRIANGLES, 0,
count));
211 OOGL(glDisableClientState(GL_VERTEX_ARRAY));
214 if (useVBO)
OOGL(glBindBufferARB(GL_ARRAY_BUFFER, 0));
228 [
self drawWithData:_solidData count:_solidCount VBO:&_solidVBO];
238 [
self drawWithData:_outlineData count:_outlineCount VBO:&_outlineVBO];
247 if (_solidVBO != 0) glDeleteBuffersARB(1, &_solidVBO);
248 if (_outlineVBO != 0) glDeleteBuffersARB(1, &_outlineVBO);
257- (BOOL) loadPolygons:(NSArray *)dataArray outlineWidth:(
float)outlineWidth
259 NSParameterAssert(dataArray !=
nil);
261 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
262 GLUtesselator *tesselator = NULL;
265 memset(&polygonData, 0,
sizeof polygonData);
266 polygonData.
OK = YES;
268 polygonData.
name = _name;
269 if ([[NSUserDefaults standardUserDefaults] boolForKey:
@"polygon-sprite-dump-svg"])
SVGDumpBegin(&polygonData);
279 tesselator = gluNewTess();
280 if (tesselator == NULL)
295 gluTessBeginPolygon(tesselator, &polygonData);
298 NSUInteger contourCount = [dataArray count], contourIndex;
299 for (contourIndex = 0; contourIndex < contourCount && polygonData.
OK; contourIndex++)
301 NSArray *contour = [dataArray oo_arrayAtIndex:contourIndex];
311 gluTessEndPolygon(tesselator);
316 _solidCount = polygonData.
count;
318 if (_solidCount != 0)
320 _solidData = realloc(polygonData.
data, polygonData.
count * sizeof (GLfloat) * 2);
321 if (_solidData != NULL) polygonData.
data = NULL;
325 _solidData = polygonData.
data;
326 if (_solidData == NULL) polygonData.
OK = NO;
335 if (!polygonData.
OK)
goto END;
338 gluDeleteTess(tesselator);
339 tesselator = gluNewTess();
340 if (tesselator == NULL)
346 polygonData.
count = 0;
362 gluTessProperty(tesselator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE);
364 gluTessBeginPolygon(tesselator, &polygonData);
367 outlineWidth *= 0.5f;
368 contourCount = [dataArray count];
369 for (contourIndex = 0; contourIndex < contourCount && polygonData.
OK; contourIndex++)
371 NSArray *contour = [dataArray oo_arrayAtIndex:contourIndex];
382 gluTessEndPolygon(tesselator);
387 if (polygonData.
count != 0)
389 _outlineCount = polygonData.
count;
390 _outlineData = realloc(polygonData.
data, polygonData.
count * sizeof (GLfloat) * 2);
391 if (_outlineData != NULL) polygonData.
data = NULL;
395 _outlineData = polygonData.
data;
396 if (_outlineData == NULL) polygonData.
OK = NO;
409 free(polygonData.
data);
410 gluDeleteTess(tesselator);
415 return polygonData.
OK;
423 NSUInteger vertexCount = [contour count], vertexIndex;
426 gluTessBeginContour(tesselator);
428 for (vertexIndex = 0; vertexIndex < vertexCount && polygonData->
OK; vertexIndex++)
430 NSValue *pointValue = [contour objectAtIndex:vertexIndex];
431 NSPoint p = [pointValue pointValue];
432 GLdouble vert[3] = { p.x, p.y, 0.0 };
434 gluTessVertex(tesselator, vert, pointValue);
437 gluTessEndContour(tesselator);
457 NSUInteger polyIter, polyCount = [dataArray count];
458 NSArray *subArrays[polyCount];
460 for (polyIter = 0; polyIter < polyCount; polyIter++)
462 NSArray *polyDef = [dataArray objectAtIndex:polyIter];
463 NSUInteger vertIter, vertCount = [polyDef count] / 2;
464 NSMutableArray *newPolyDef = [NSMutableArray arrayWithCapacity:vertCount];
467 CGFloat oldX = [polyDef oo_doubleAtIndex:(vertCount -1) * 2];
468 CGFloat oldY = [polyDef oo_doubleAtIndex:(vertCount -1) * 2 + 1];
470 for (vertIter = 0; vertIter < vertCount; vertIter++)
472 CGFloat
x = [polyDef oo_doubleAtIndex:vertIter * 2];
473 CGFloat
y = [polyDef oo_doubleAtIndex:vertIter * 2 + 1];
476 if (
x == oldX &&
y == oldY)
continue;
477 if (isnan(
x) || isnan(
y))
continue;
478 if (!isfinite(
x) || !isfinite(
y))
continue;
480 area +=
x * oldY - oldX *
y;
485 [newPolyDef addObject:[NSValue valueWithPoint:NSMakePoint(x, y)]];
489 while ([newPolyDef
count] > 1 && [[newPolyDef objectAtIndex:0] isEqual:[newPolyDef lastObject]])
491 [newPolyDef removeLastObject];
496 subArrays[polyIter] = newPolyDef;
500 subArrays[polyIter] = [[newPolyDef reverseObjectEnumerator] allObjects];
507 return [NSArray arrayWithObjects:subArrays count:polyCount];
513 NSUInteger i,
count = [dataArray count];
514 if (
count < 2)
return dataArray;
550 NSPoint prev, current, next;
553 prev = [[dataArray objectAtIndex:0] pointValue];
554 current = [[dataArray objectAtIndex:count -1] pointValue];
555 next = [[dataArray objectAtIndex:count - 2] pointValue];
559 prev = [[dataArray objectAtIndex:count - 1] pointValue];
560 current = [[dataArray objectAtIndex:0] pointValue];
561 next = [[dataArray objectAtIndex:1] pointValue];
564 NSMutableArray *result = [NSMutableArray arrayWithCapacity:count];
566 for (i = 0; i <
count; i++)
571 CGFloat dot =
PtDot(a, b);
572 BOOL clockwise =
PtCross(a, b) < 0.0f;
580 if (!isnan(v.x) && !isnan(v.y))
582 [result addObject:[NSValue valueWithPoint:PtAdd(v, current)]];
591 if (!isnan(v1.x) && !isnan(v1.y))
593 [result addObject:[NSValue valueWithPoint:PtAdd(v1, current)]];
595 if (!isnan(v2.x) && !isnan(v2.y))
597 [result addObject:[NSValue valueWithPoint:PtAdd(v2, current)]];
606 next = [[dataArray objectAtIndex:(count * 2 - 3 - i) % count] pointValue];
610 next = [[dataArray objectAtIndex:(i + 2) % count] pointValue];
620 NSCParameterAssert(data != NULL);
622 size_t minCapacity = data->
capacity + 1;
623 size_t desiredCapacity =
MAX(capacityHint, minCapacity);
624 size_t newCapacity = 0;
625 GLfloat *newData = realloc(data->
data, desiredCapacity * sizeof (GLfloat) * 2);
628 newCapacity = desiredCapacity;
632 desiredCapacity = minCapacity;
633 newData = realloc(data->
data, desiredCapacity * sizeof (GLfloat) * 2);
634 if (newData != NULL) newCapacity = desiredCapacity;
637 if (newData == NULL)
return NO;
639 NSCAssert(newCapacity > data->
capacity,
@"Buffer regrow logic error");
641 data->
data = newData;
649 NSCParameterAssert(data != NULL);
653 data->
data[data->count * 2] = vertex.x;
654 data->
data[data->count * 2 + 1] = vertex.y;
663 NSCParameterAssert(data != NULL);
675 NSValue *vertValue = vertexData;
676 NSCParameterAssert(vertValue != NULL && data != NULL);
677 if (!data->
OK)
return;
679 NSPoint p = [vertValue pointValue];
680 NSPoint vertex = { p.x, p.y };
681 size_t vCount = data->
vCount++;
704 case GL_TRIANGLE_FAN:
705 if (vCount == 0) data->
pending0 = vertex;
706 else if (vCount == 1) data->
pending1 = vertex;
717 case GL_TRIANGLE_STRIP:
718 if (vCount == 0) data->
pending0 = vertex;
719 else if (vCount == 1) data->
pending1 = vertex;
749 if ((vCount % 2) == 0) data->
pending0 = vertex;
755 OOLog(
@"polygonSprite.tesselate.error",
@"Unexpected tesselator primitive mode %u.", data->
mode);
763 NSPoint point = { coords[0], coords[1] };
764 *outData = [NSValue valueWithPoint:point];
771 NSCParameterAssert(data != NULL);
783 NSCParameterAssert(data != NULL);
785 NSString *name =
@"";
787 name = [NSString stringWithFormat:@" \"%@\"", data->name];
790 char *errStr = (
char *)gluErrorString(error);
792 OOLog(
@"polygonSprite.tesselate.error",
@"Error %s (%u) while tesselating polygon%@.", errStr, error, name);
803 data->
debugSVG = [[NSMutableString alloc] initWithString:
804 @"<?xml version=\"1.0\" standalone=\"no\"?>\n"
805 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n"
806 "<svg viewBox=\"-5 -5 10 10\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n"
807 "\t<desc>Oolite polygon sprite debug dump.</desc>\n"
817 [data->debugSVG appendString:@"</svg>\n"];
827 [data->debugSVG appendFormat:@"\t<g id=\"%@ %u\">\n", name, data->svgID++];
834 [data->debugSVG appendString:@"\t</g>\n"];
842 NSString *groupName = [NSString stringWithFormat:@"contour %u", data->svgID++];
843 [data->debugSVG appendFormat:@"\t\t<g id=\"%@\" stroke=\"#BBB\" fill=\"none\">\n\t\t<path stroke-width=\"0.05\" d=\"", groupName];
845 NSUInteger i,
count = [points count];
846 for (i = 0; i <
count; i++)
848 NSPoint p = [[points objectAtIndex:i] pointValue];
849 [data->debugSVG appendFormat:@"%c %f %f ", (i == 0) ? 'M' : 'L', p.x, -p.y];
853 NSPoint p = [[points objectAtIndex:0] pointValue];
854 [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];
862 NSString *groupName =
@"Unknown primitive";
866 groupName =
@"Triangle soup";
869 case GL_TRIANGLE_FAN:
870 groupName =
@"Triangle fan";
873 case GL_TRIANGLE_STRIP:
874 groupName =
@"Triangle strip";
877 groupName = [groupName stringByAppendingFormat:@" %u", data->svgID++];
880 uint8_t red = (
Ranrot() & 0x3F) + 0x20;
881 uint8_t green = (
Ranrot() & 0x3F) + 0x20;
882 uint8_t blue = (
Ranrot() & 0x3F) + 0x20;
890 [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"];
897 [data->debugSVG appendString:@"\t\t</g>\n"];
904 [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];