Calling SUFaceGetVertices() correctly


#1

Almost certainly a silly error on my part, but I’m not seeing it. Given the following:

        size_t vertexCount;
        SUFaceGetNumVertices(face, &vertexCount);
        SUVertexRef* vertices;
        size_t vertexActualCount;
        if (SU_ERROR_NONE != SUFaceGetVertices(face, vertexCount, vertices, &vertexActualCount)) {
            std::cerr << "problem getting vertices\n";
            break;
        }

So the function returns successfully, and if I passed in a vertexCount of 4, my vertexActualCount comes back 4, but vertices is NULL.

What am I missing here?


#2

I think the following would be better:

SUVertexRef vertices; // No *
SUFaceGetVertices(…, &vertices, …);


#3

It isn’t clear from your snippet whether vertices has been initialized somewhere, but my guess is not, hence it is NULL. The function will populate the array that vertices points to, but it can not modify the pointer itself!


#4

Yes, that makes sense. But how do I iterate over the vertices, then? This idiom of passing in the array by reference with void* types is not a way I write stuff, so sorry if I’m confused here…

I’d like to just do a vertices[i] to get each of the SUVertexRefs, but that’s not the right thing.


#5

Actually, coming to think of it I was all wrong and was about to lead you to horrible crashes. You need to first check how many vertices there are, then allocate a buffer of SUVertexRef large enough for all of them and pass that buffer to the function!


#6

Doh! That totally makes sense.


#7

Okay, so here’s the final solution for the archives. There are two ways one might imagine doing it; one is a traditional C approach, the other is more C++.

So here’s the old skool malloc/free way:

        size_t vertexCount, vertexActualCount;
        SUFaceGetNumVertices(face, &vertexCount);
        size_t memSize = vertexCount * sizeof(SUVertexRef*);
        SUVertexRef* vertices = (SUVertexRef*)malloc(memSize);
        std::cerr << "allocating " << memSize << " bytes yielded pointer " << vertices << "\n";
         if (!vertices || (SU_ERROR_NONE != SUFaceGetVertices(face, vertexCount, vertices, &vertexActualCount))) {
            std::cerr << "problem getting vertices\n";
            break;
        }
        if (vertexCount != vertexActualCount) {
            std::cerr << "expected " << vertexCount << " vertices, but got " << vertexActualCount << "\n";
            break;
        }
        for (size_t v = 0; v < vertexActualCount; v++) {
            SUPoint3D position;
            SUVertexRef vertex = vertices[v];
            if (SU_ERROR_NONE != SUVertexGetPosition(vertex, &position)) {
                std::cerr << "problem getting vertex\n";
                break;
            }
            std::cerr << "vertex #" << v << " = (" << position.x << ", " << position.y << ", " << position.z << ")\n";
        }
        free(vertices);

and here’s the more C++ way to do it with a std::vector<> - this is clearly preferred, except for the weird syntax of handing in the parameter:

        std::vector<SUVertexRef> vertexRefs(vertexCount);
        if (SU_ERROR_NONE != SUFaceGetVertices(face, vertexCount, &vertexRefs[0], &vertexActualCount)) {
            std::cerr << "problem getting vertices : ";
            break;
        }
        for (size_t v = 0; v < vertexActualCount; v++) {
            SUPoint3D position;
            SUVertexRef vertex = vertexRefs[v];
            if (SU_ERROR_NONE != SUVertexGetPosition(vertex, &position)) {
                std::cerr << "problem getting vertex\n";
                break;
            }
            std::cerr << "vertex #" << v << " = (" << position.x << ", " << position.y << ", " << position.z << ")\n";
        }