0

我对以下代码有疑问。它应该是一个简单的.obj加载器,将数据存储在三个不同的数组中。数组被传递到函数中,但它们没有被修改。每次我使用该函数时,该行*out_vertices[index] = gl_vector3_make(0.0, 0.0, 0.0);也会抛出一个EXC_BAD_ACCESS,即使我预先分配了传入的数组并删除了函数本身中的所有相关分配代码。

对象IO.h

#ifndef ObjectIO_h
#define ObjectIO_h

union _vector2 {
    struct {float x, y;};
    struct {float s, t;};
    float v[2];
};
typedef union _vector2 gl_vector2;

extern inline gl_vector2 gl_vector2_make(float x, float y);

union _vector3 {
    struct {float x, y, z;};
    struct {float s, t, p;};
    struct {float r, g, b;};
    float v[3];
};
typedef union _vector3 gl_vector3;

extern inline gl_vector3 gl_vector3_make(float x, float y, float z);

union _vector4 {
    struct {float x, y, z, w;};
    struct {float s, t, p, q;};
    struct {float r, g, b, a;};
    float v[4];
};
typedef union _vector4 gl_vector4;

extern inline gl_vector4 gl_vector4_make(float x, float y, float z, float w);

extern inline int loadOBJ(const char *path, gl_vector3 **out_vertices, gl_vector2 **out_uvs, gl_vector3 **out_normals);

#endif

对象IO.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "ObjectIO.h"

extern inline gl_vector2 gl_vector2_make(float x, float y) {
    gl_vector2 vector;

    vector.x = x;
    vector.y = y;

    return vector;
}

extern inline gl_vector3 gl_vector3_make(float x, float y, float z) {
    gl_vector3 vector;

    vector.x = x;
    vector.y = y;
    vector.z = z;

    return vector;
}

extern inline gl_vector4 gl_vector4_make(float x, float y, float z, float w) {
    gl_vector4 vector;

    vector.x = x;
    vector.y = y;
    vector.z = z;
    vector.w = w;

    return vector;
}

extern inline char** splitstring(char *inputstring, char *separator, size_t *lines) {
    char **res = NULL;
    char * p = strtok(inputstring, separator);
    int n_spaces = 0, i;

    while (p) {
        n_spaces ++;
        res = realloc(res, sizeof(char*) * n_spaces);
        if (res == NULL)
            exit (-1); /* memory allocation failed */

        res[n_spaces - 1] = p;

        p = strtok (NULL, separator);
    }

    res = realloc (res, sizeof (char*) * (n_spaces + 1));
    res[n_spaces] = '\0';

    /* print the result */

    for (i = 0; i < (n_spaces); i ++) printf ("res[%d] = %s\n", i, res[i]);

    /* free the memory allocated */

    *lines = (n_spaces - 1);
    free(res);

    return res;
}

extern inline int loadOBJ(const char *path, gl_vector3 **out_vertices, gl_vector2 **out_uvs, gl_vector3 **out_normals) {
    printf("Loading OBJ file %s...\n", path);
    long filesize;
    char *file_c;
    char *linesep;
    char **filecontents;
    size_t filecontentsize, result, lines, index, faces;
    float *normals = malloc(sizeof(float) * 3);
    float *uvs = malloc(sizeof(float) * 2);
    float *vertices = malloc(sizeof(float) * 3);
    FILE* file = fopen(path, "r");

    if (file == NULL) {
        printf("File %s cannot be opened.\n", path);
        fclose(file);
        return 0;
    }

    fseek(file, 0, SEEK_END);
    filesize = ftell(file);
    fseek(file, 0, SEEK_SET);
    filecontentsize = sizeof(char) * filesize;
    file_c = malloc(filecontentsize);
    result = fread(file_c, 1, filesize, file);

    linesep = malloc(sizeof(char) * 2);
    linesep[0] = '\n';
    lines = 0;
    index = 0;
    faces = 0;
    filecontents = splitstring(file_c, linesep, &lines);

    fseek(file, 0, SEEK_SET);
    while (index < lines) {
        if (filecontents[index][0] == 'v') {
            if (filecontents[index][1] == 'n') {
                normals = realloc(normals, (sizeof(float) * 3));

                fscanf(file, "vn %f %f %f\n", &normals[(index * 3) + 0], &normals[(index * 3) + 1], &normals[(index * 3) + 2]);
            }
            else {
                if (filecontents[index][1] == 't') {
                    uvs = realloc(uvs, (sizeof(float) * 2));
                    fscanf(file, "vt %f %f\n", &uvs[(index * 3) + 0], &uvs[(index * 3) + 1]);
                }
                else {
                    vertices = realloc(vertices, (sizeof(float) * 3));
                    fscanf(file, "v %f %f %f\n", &vertices[(index * 3) + 0], &vertices[(index * 3) + 1], &vertices[(index * 3) + 2]);
                }
            }
        }
        if (filecontents[index][0] == 'f') {
            faces ++;
        }

        index ++;
    }

    *out_vertices = malloc(sizeof(gl_vector3) * faces * 3);
    *out_uvs = malloc(sizeof(gl_vector2) * faces * 2);
    *out_normals = malloc(sizeof(gl_vector3) * faces * 3);

    index = 0;
    while (index <= lines) {
        *out_normals[index] = gl_vector3_make(0.0, 0.0, 0.0);
        *out_uvs[index] = gl_vector2_make(0.0, 0.0);
        *out_vertices[index] = gl_vector3_make(0.0, 0.0, 0.0);
        printf("%lu\n", index);
        index ++;
    }
    fclose(file);

    return 1;
}

该函数在这里调用:

gl_vector3 *normals;
gl_vector2 *uvs;
gl_vector3 *vertices;

loadOBJ("/Users/justin/Downloads/OpenGL-tutorial_v0010_21/tutorial16_shadowmaps/room.obj", &vertices, &uvs, &normals);
printf("%f, %f, %f\n", vertices[0].x, vertices[0].y, vertices[0].z);
4

1 回答 1

0

您正在创建一个由 2、3 或 4 个相同匿名结构组成的联合,这很奇怪,但可以,当然可以。你的函数 gl_vector2_make、gl_vector3_make 和 gl_vector4_make 不是,因为我第一次读错了,返回指针,所以也没关系。您使用 realloc() 的方式效率非常低,但可以肯定的是,请继续。但是,您的函数splitstring()分配存储空间,将点填充到要处理的字符串数据中,然后在返回指向它的指针之前释放分配的存储空间。这是一个严重的错误。在您的函数loadOBJ()中,您的名为normals,uvs和的变量vertices都分配给固定大小,但即使您realloc()反复使用它们,您也永远不会增长任何一位。您总是分配相同的大小。然后根据您要分配的大小对它们进行索引,这又是一个主要错误。此外,在 中loadOBJ(),您将整个文件读入分配的内存,将其传递给它,将splitstring()其分解为一个近乎的字符串数组,逐行,然后不是实际使用它,而是倒回文件并用于fscanf()读取整个文件再次,一次一行。为什么不对sscanf()返回的每个字符串数组使用splitstring()

于 2013-04-23T03:01:23.267 回答