55#define kCosMitreLimit 0.866f
58@interface OOPolygonSprite (Private) <OOGraphicsResetClient>
60- (BOOL) loadPolygons:(NSArray *)dataArray outlineWidth:(
float)outlineWidth;
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])
124- (id) initWithDataArray:(NSArray *)dataArray outlineWidth:(GLfloat)outlineWidth name:(NSString *)name {
…}
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));
178- (void) drawWithData:(GLfloat *)data count:(
size_t)count VBO:(GLuint *)vbo {
…}
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);
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;
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;
257- (BOOL) loadPolygons:(NSArray *)dataArray outlineWidth:(
float)outlineWidth {
…}
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];
#define OOLog(class, format,...)
#define OO_ENTER_OPENGL()
#define OOVerifyOpenGLState()
BOOL OOCheckOpenGLErrors(NSString *format,...)
#define OOSetOpenGLState(STATE)
OOINLINE CGFloat PtDot(NSPoint a, NSPoint b)
OOINLINE NSPoint PtScale(NSPoint p, CGFloat scale)
OOINLINE NSPoint PtSub(NSPoint a, NSPoint b)
OOINLINE NSPoint PtRotACW(NSPoint p)
OOINLINE NSPoint PtNormal(NSPoint p)
OOINLINE CGFloat PtCross(NSPoint a, NSPoint b)
OOINLINE NSPoint PtAdd(NSPoint a, NSPoint b)
static void APIENTRY TessVertexCallback(void *vertexData, void *polygonData)
static void APIENTRY TessEndCallback(void *polygonData)
static BOOL AppendVertex(TessPolygonData *data, NSPoint vertex)
static void SVGDumpEndPrimitive(TessPolygonData *data)
static void APIENTRY TessBeginCallback(GLenum type, void *polygonData)
static void SVGDumpBeginGroup(TessPolygonData *data, NSString *name)
static void SVGDumpAppendTriangle(TessPolygonData *data, NSPoint v0, NSPoint v1, NSPoint v2)
static NSArray * DataArrayToPoints(TessPolygonData *data, NSArray *dataArray)
static void SubmitVertices(GLUtesselator *tesselator, TessPolygonData *polygonData, NSArray *contour)
static void APIENTRY ErrorCallback(GLenum error, void *polygonData)
static void SVGDumpBeginPrimitive(TessPolygonData *data)
static void APIENTRY TessCombineCallback(GLdouble coords[3], void *vertexData[4], GLfloat weight[4], void **outData, void *polygonData)
static void SVGDumpAppendBaseContour(TessPolygonData *data, NSArray *points)
static NSArray * BuildOutlineContour(NSArray *dataArray, GLfloat width, BOOL inner)
static void SVGDumpBegin(TessPolygonData *data)
static void SVGDumpEndGroup(TessPolygonData *data)
static void SVGDumpEnd(TessPolygonData *data)
static BOOL GrowTessPolygonData(TessPolygonData *data, size_t capacityHint)
void registerClient:(id< OOGraphicsResetClient > client)
void unregisterClient:(id< OOGraphicsResetClient > client)
OOGraphicsResetManager * sharedManager()
OOOpenGLExtensionManager * sharedManager()
void drawWithData:count:VBO:(GLfloat *data, [count] size_t count, [VBO] GLuint *vbo)
void resetGraphicsState()
NSString * descriptionComponents()
BOOL writeDiagnosticString:toFileNamed:(NSString *string,[toFileNamed] NSString *name)
NSMutableString * debugSVG