cocos2d / cocos2d-objc

Cocos2d for iOS and OS X, built using Objective-C
http://www.cocos2d-objc.org
Other
4.07k stars 1.16k forks source link

Vertices pages boundary overlap #1426

Open AlexCP11 opened 1 year ago

AlexCP11 commented 1 year ago

There is an issue related to vertices pages boundary overlap. Result is extra random triangles or missed triangles. Issue reproduced on my devices iPad Mini (iOS 15.7.1), iPhone 7+ (iOS 15.7.5) and all Simulators (iOS 13.7, 14.2, 16.4).

Simplified sample code. Triangles should fill-up all node to make glitches easy visible. 5 vertices per iteration used to guarantee pages overlap.

- (void) draw:(CCRenderer *)renderer transform:(const GLKMatrix4 *)transform
{
    int verticesCount = 65535*2+10; // to make two pages overlaps
    int trianglesDrawsCount = (verticesCount/5); 

    GLKVector4 redColor = [CCColor colorWithRed:1. green:0. blue:0. alpha:1.].glkVector4;
    CGFloat x,y,d;
    int trianlgesPerRow = 132;
    d = <triangle size to fill-up node with triangles>;

    CGFloat vertexArray[10];
    CGPoint points[5];
    for (int trianglesDraw=0; trianglesDraw<trianglesDrawsCount; trianglesDraw++) {
        x = d*(trianglesDraw%trianlgesPerRow);
        y = d*(trianglesDraw/trianlgesPerRow);

        vertexArray[0] = x;
        vertexArray[1] = y;
        vertexArray[2] = x+d;
        vertexArray[3] = y;
        vertexArray[4] = x+d;
        vertexArray[5] = y+d;

        vertexArray[6] = x;
        vertexArray[7] = y+d;
        vertexArray[8] = x+d;
        vertexArray[9] = y+d;

        CCRenderBuffer buffer = [renderer enqueueTriangles:2 andVertexes:5 withState:self.renderState globalSortOrder:0];

        for (int i=0; i<5; ++i) {
            points[i] = ccp(vertexArray[2*i], vertexArray[2*i+1]);
            CCRenderBufferSetVertex(buffer, i, CCVertexApplyTransform((CCVertex){{points[i].x, points[i].y, 0, 1}, {0, 0}, {0, 0}, redColor}, transform));
        }

        CCRenderBufferSetTriangle(buffer, 0, 0, 1, 2);
        CCRenderBufferSetTriangle(buffer, 1, 0, 3, 4);
    }
}

Result is in attachment. pagesoverlap_issue

Take a look into CCNoARC.m file. Method CCRenderer::enqueueLines:andVertexes:withState:globalSortOrder:

-(CCRenderBuffer)enqueueTriangles:(NSUInteger)triangleCount andVertexes:(NSUInteger)vertexCount withState:(CCRenderState *)renderState globalSortOrder:(NSInteger)globalSortOrder;
{
    // Need to record the first vertex or element index before pushing more vertexes.
    NSUInteger firstVertex = _buffers->_vertexBuffer->_count;
    NSUInteger firstIndex = _buffers->_indexBuffer->_count;

    // Value is 0 unless there a page boundary overlap would occur.
    NSUInteger vertexPageOffset = PageOffset(firstVertex, vertexCount);
    if (vertexPageOffset>0) {
        int stop=0; // #1 if we got here then visual bug will be
    }

    // Split vertexes into pages of 2^16 vertexes since GLES2 requires indexing with shorts.
    NSUInteger vertexPage = (firstVertex + vertexPageOffset) >> 16;
    NSUInteger vertexPageIndex = (firstVertex + vertexPageOffset) & 0xFFFF;

    // Ensure that the buffers have enough storage space.
    NSUInteger indexCount = 3*triangleCount;
    CCVertex *vertexes = CCGraphicsBufferPushElements(_buffers->_vertexBuffer, vertexCount + vertexPageOffset);
    if (vertexPageOffset>0) {
        vertexes = vertexes + vertexPageOffset; // #2 vertices will be stored from beginning of the next page
    }

You can set breakpoint in line with my first comment to easily detect error.

    if (vertexPageOffset>0) {
        int stop=0; // #1 if we got here then visual bug will be
    }

I've added last three lines to fix this issue. I don't know is it solution or just workaround, but it works now.

    if (vertexPageOffset>0) {
        vertexes = vertexes + vertexPageOffset; // #2 vertices will be stored from beginning of the next page
    }

I hope it helps somebody.