Fix issues with model IO;

This commit is contained in:
bjorn 2017-10-21 17:35:50 -07:00
parent 736adf03e1
commit 231056e7e0
8 changed files with 222 additions and 104 deletions

View File

@ -195,9 +195,7 @@ int l_lovrFilesystemGetSaveDirectory(lua_State* L) {
int l_lovrFilesystemGetSize(lua_State* L) {
const char* path = luaL_checkstring(L, 1);
File* file = lovrFilesystemOpen(path, OPEN_READ);
lua_pushinteger(L, lovrFilesystemGetSize(file));
lovrFilesystemClose(file);
lua_pushinteger(L, lovrFilesystemGetSize(path));
return 1;
}

View File

@ -7,6 +7,7 @@ Blob* lovrBlobCreate(void* data, size_t size, const char* name) {
blob->data = data;
blob->size = size;
blob->name = name;
blob->seek = 0;
return blob;
}

View File

@ -7,6 +7,7 @@ typedef struct {
void* data;
size_t size;
const char* name;
size_t seek;
} Blob;
Blob* lovrBlobCreate(void* data, size_t size, const char* name);

64
src/filesystem/file.c Normal file
View File

@ -0,0 +1,64 @@
#include "filesystem/file.h"
#include <physfs.h>
File* lovrFileCreate(const char* path) {
File* file = lovrAlloc(sizeof(File), lovrFileDestroy);
if (!file) return NULL;
file->path = path;
file->handle = NULL;
return file;
}
void lovrFileDestroy(const Ref* ref) {
File* file = containerof(ref, File);
if (file->handle) {
PHYSFS_close(file->handle);
}
free(file);
}
int lovrFileOpen(File* file, FileMode mode) {
lovrAssert(!file->handle, "File is already open");
file->mode = mode;
switch (mode) {
case OPEN_READ: file->handle = PHYSFS_openRead(file->path); break;
case OPEN_WRITE: file->handle = PHYSFS_openWrite(file->path); break;
case OPEN_APPEND: file->handle = PHYSFS_openAppend(file->path); break;
}
return file->handle == NULL;
}
void lovrFileClose(File* file) {
lovrAssert(file->handle, "File must be open to close it");
PHYSFS_close(file->handle);
file->handle = NULL;
}
size_t lovrFileRead(File* file, void* data, size_t size, size_t count) {
lovrAssert(file->handle && file->mode == OPEN_READ, "File must be open for reading");
return PHYSFS_read(file->handle, data, size, count);
}
size_t lovrFileWrite(File* file, void* data, size_t size, size_t count) {
lovrAssert(file->handle && (file->mode == OPEN_READ || file->mode == OPEN_WRITE), "File must be open for writing");
return PHYSFS_write(file->handle, data, size, count);
}
size_t lovrFileGetSize(File* file) {
lovrAssert(file->handle, "File must be open to get its size");
return PHYSFS_fileLength(file->handle);
}
int lovrFileSeek(File* file, size_t position) {
lovrAssert(file->handle, "File must be open to seek");
return !PHYSFS_seek(file->handle, position);
}
size_t lovrFileTell(File* file) {
lovrAssert(file->handle, "File must be open to tell");
return PHYSFS_tell(file->handle);
}

26
src/filesystem/file.h Normal file
View File

@ -0,0 +1,26 @@
#include "util.h"
#pragma once
typedef enum {
OPEN_READ,
OPEN_WRITE,
OPEN_APPEND
} FileMode;
typedef struct {
Ref ref;
const char* path;
void* handle;
FileMode mode;
} File;
File* lovrFileCreate(const char* filename);
void lovrFileDestroy(const Ref* ref);
int lovrFileOpen(File* file, FileMode mode);
void lovrFileClose(File* file);
size_t lovrFileRead(File* file, void* data, size_t size, size_t count);
size_t lovrFileWrite(File* file, void* data, size_t size, size_t count);
size_t lovrFileGetSize(File* file);
int lovrFileSeek(File* file, size_t position);
size_t lovrFileTell(File* file);

View File

@ -1,4 +1,5 @@
#include "filesystem/filesystem.h"
#include "filesystem/file.h"
#include "util.h"
#include <physfs.h>
#include <stdio.h>
@ -55,10 +56,6 @@ void lovrFilesystemDestroy() {
PHYSFS_deinit();
}
void lovrFilesystemClose(File* file) {
PHYSFS_close(file);
}
int lovrFilesystemCreateDirectory(const char* path) {
return !PHYSFS_mkdir(path);
}
@ -67,10 +64,6 @@ int lovrFilesystemExists(const char* path) {
return PHYSFS_exists(path);
}
void lovrFilesystemFileRead(File* file, void* data, size_t size, size_t count, size_t* bytesRead) {
*bytesRead = PHYSFS_read(file, data, size, count);
}
int lovrFilesystemGetAppdataDirectory(char* dest, unsigned int size) {
#ifdef __APPLE__
const char* home;
@ -144,8 +137,13 @@ const char* lovrFilesystemGetSaveDirectory() {
return state.savePathFull;
}
size_t lovrFilesystemGetSize(File* file) {
return PHYSFS_fileLength(file);
size_t lovrFilesystemGetSize(const char* path) {
File* file = lovrFileCreate(path);
lovrFileOpen(file, OPEN_READ);
size_t size = lovrFileGetSize(file);
lovrFileClose(file);
lovrRelease(&file->ref);
return size;
}
const char* lovrFilesystemGetSource() {
@ -172,25 +170,20 @@ int lovrFilesystemMount(const char* path, const char* mountpoint, int append) {
return !PHYSFS_mount(path, mountpoint, append);
}
void* lovrFilesystemOpen(const char* path, FileMode mode) {
switch (mode) {
case OPEN_READ: return PHYSFS_openRead(path);
case OPEN_WRITE: return PHYSFS_openWrite(path);
case OPEN_APPEND: return PHYSFS_openAppend(path);
}
}
void* lovrFilesystemRead(const char* path, size_t* bytesRead) {
// Open file
PHYSFS_file* file = lovrFilesystemOpen(path, OPEN_READ);
// Create file
File* file = lovrFileCreate(path);
if (!file) {
return NULL;
}
// Open it
lovrFileOpen(file, OPEN_READ);
// Get file size
int size = PHYSFS_fileLength(file);
if (size < 0) {
size_t size = lovrFileGetSize(file);
if (size == (unsigned int) -1) {
return NULL;
}
@ -201,8 +194,8 @@ void* lovrFilesystemRead(const char* path, size_t* bytesRead) {
}
// Perform read
lovrFilesystemFileRead(file, data, 1, size, bytesRead);
lovrFilesystemClose(file);
*bytesRead = lovrFileRead(file, data, 1, size);
lovrFileClose(file);
// Make sure we got everything
if (*bytesRead != (size_t) size) {
@ -217,10 +210,6 @@ int lovrFilesystemRemove(const char* path) {
return !PHYSFS_delete(path);
}
int lovrFilesystemSeek(File* file, size_t position) {
return !PHYSFS_seek(file, position);
}
int lovrFilesystemSetIdentity(const char* identity) {
state.identity = identity;
@ -251,21 +240,19 @@ int lovrFilesystemSetIdentity(const char* identity) {
return 0;
}
size_t lovrFilesystemTell(File* file) {
return PHYSFS_tell(file);
}
int lovrFilesystemUnmount(const char* path) {
return !PHYSFS_removeFromSearchPath(path);
}
int lovrFilesystemWrite(const char* path, const char* content, size_t size, int append) {
PHYSFS_file* file = lovrFilesystemOpen(path, append ? OPEN_APPEND : OPEN_WRITE);
size_t lovrFilesystemWrite(const char* path, const char* content, size_t size, int append) {
File* file = lovrFileCreate(path);
if (!file) {
return 0;
}
int bytesWritten = PHYSFS_write(file, content, 1, size);
lovrFilesystemClose(file);
lovrFileOpen(file, append ? OPEN_APPEND : OPEN_WRITE);
size_t bytesWritten = lovrFileWrite(file, (void*) content, 1, size);
lovrFileClose(file);
lovrRelease(&file->ref);
return bytesWritten;
}

View File

@ -6,14 +6,6 @@
typedef void getDirectoryItemsCallback(void* userdata, const char* dir, const char* file);
typedef enum {
OPEN_READ,
OPEN_WRITE,
OPEN_APPEND
} FileMode;
typedef void File;
typedef struct {
char* source;
const char* identity;
@ -24,10 +16,8 @@ typedef struct {
void lovrFilesystemInit(const char* arg0, const char* arg1);
void lovrFilesystemDestroy();
void lovrFilesystemClose(File* file);
int lovrFilesystemCreateDirectory(const char* path);
int lovrFilesystemExists(const char* path);
void lovrFilesystemFileRead(File* file, void* data, size_t size, size_t count, size_t* bytesRead);
int lovrFilesystemGetAppdataDirectory(char* dest, unsigned int size);
void lovrFilesystemGetDirectoryItems(const char* path, getDirectoryItemsCallback callback, void* userdata);
int lovrFilesystemGetExecutablePath(char* dest, unsigned int size);
@ -35,19 +25,16 @@ const char* lovrFilesystemGetIdentity();
long lovrFilesystemGetLastModified(const char* path);
const char* lovrFilesystemGetRealDirectory(const char* path);
const char* lovrFilesystemGetSaveDirectory();
size_t lovrFilesystemGetSize(File* file);
size_t lovrFilesystemGetSize(const char* path);
const char* lovrFilesystemGetSource();
const char* lovrFilesystemGetUserDirectory();
int lovrFilesystemIsDirectory(const char* path);
int lovrFilesystemIsFile(const char* path);
int lovrFilesystemIsFused();
int lovrFilesystemMount(const char* path, const char* mountpoint, int append);
File* lovrFilesystemOpen(const char* path, FileMode mode);
void* lovrFilesystemRead(const char* path, size_t* bytesRead);
int lovrFilesystemRemove(const char* path);
int lovrFilesystemSeek(File* file, size_t position);
int lovrFilesystemSetIdentity(const char* identity);
int lovrFilesystemSetSource(const char* source);
size_t lovrFilesystemTell(File* file);
int lovrFilesystemUnmount(const char* path);
int lovrFilesystemWrite(const char* path, const char* content, size_t size, int append);
size_t lovrFilesystemWrite(const char* path, const char* content, size_t size, int append);

View File

@ -1,8 +1,11 @@
#include "loaders/model.h"
#include "filesystem/filesystem.h"
#include "filesystem/file.h"
#include "math/math.h"
#include "math/mat4.h"
#include <libgen.h>
#include <stdlib.h>
#include <stdio.h>
#include <assimp/cfileio.h>
#include <assimp/cimport.h>
#include <assimp/config.h>
@ -12,72 +15,127 @@
#include <assimp/vector3.h>
#include <assimp/postprocess.h>
// Blob IO (to avoid reading data twice)
static unsigned long assimpBlobRead(struct aiFile* file, char* buffer, size_t size, size_t count) {
Blob* blob = (Blob*) file->UserData;
char* data = blob->data;
memcpy(buffer, data, count * size * sizeof(char));
return count * size * sizeof(char);
static void normalizePath(const char* path, char* dst, size_t size) {
if (path[0] == '/') {
strncpy(dst, path, size);
return;
}
memset(dst, 0, size);
while (*path != '\0') {
if (*path == '/') {
path++;
continue;
}
if (*path == '.') {
if (path[1] == '\0' || path[1] == '/') {
path++;
continue;
}
if (path[1] == '.' && (path[2] == '\0' || path[2] == '/')) {
path += 2;
while ((--dst)[-1] != '/');
continue;
}
}
while (*path != '\0' && *path != '/') {
*dst++ = *path++;
}
*dst++ = '/';
}
*--dst = '\0';
}
static size_t assimpBlobGetSize(struct aiFile* file) {
Blob* blob = (Blob*) file->UserData;
// Blob IO (to avoid reading data twice)
static unsigned long assimpBlobRead(struct aiFile* assimpFile, char* buffer, size_t size, size_t count) {
Blob* blob = (Blob*) assimpFile->UserData;
char* data = blob->data;
size_t bytes = MIN(count * size * sizeof(char), blob->size - blob->seek);
memcpy(buffer, data + blob->seek, bytes);
return bytes;
}
static size_t assimpBlobGetSize(struct aiFile* assimpFile) {
Blob* blob = (Blob*) assimpFile->UserData;
return blob->size;
}
static aiReturn assimpBlobSeek(struct aiFile* file, unsigned long position, enum aiOrigin origin) {
lovrThrow("Seek is not implemented for Blobs");
return aiReturn_FAILURE;
static aiReturn assimpBlobSeek(struct aiFile* assimpFile, unsigned long position, enum aiOrigin origin) {
Blob* blob = (Blob*) assimpFile->UserData;
switch (origin) {
case aiOrigin_SET: blob->seek = position; break;
case aiOrigin_CUR: blob->seek += position; break;
case aiOrigin_END: blob->seek = blob->size - position; break;
default: return aiReturn_FAILURE;
}
return blob->seek < blob->size ? aiReturn_SUCCESS : aiReturn_FAILURE;
}
static unsigned long assimpBlobTell(struct aiFile* file) {
lovrThrow("Tell is not implemented for Blobs");
return 0;
static unsigned long assimpBlobTell(struct aiFile* assimpFile) {
Blob* blob = (Blob*) assimpFile->UserData;
return blob->seek;
}
// File IO (for reading referenced materials/textures)
static unsigned long assimpFileRead(struct aiFile* file, char* buffer, size_t size, size_t count) {
size_t bytesRead;
lovrFilesystemFileRead(file->UserData, buffer, count, size, &bytesRead);
return bytesRead;
static unsigned long assimpFileRead(struct aiFile* assimpFile, char* buffer, size_t size, size_t count) {
File* file = (File*) assimpFile->UserData;
unsigned long bytes = lovrFileRead(file, buffer, size, count);
return bytes;
}
static size_t assimpFileGetSize(struct aiFile* file) {
return lovrFilesystemGetSize(file->UserData);
static size_t assimpFileGetSize(struct aiFile* assimpFile) {
File* file = (File*) assimpFile->UserData;
return lovrFileGetSize(file);
}
static aiReturn assimpFileSeek(struct aiFile* file, unsigned long position, enum aiOrigin origin) {
return lovrFilesystemSeek(file->UserData, position) ? aiReturn_FAILURE : aiReturn_SUCCESS;
static aiReturn assimpFileSeek(struct aiFile* assimpFile, unsigned long position, enum aiOrigin origin) {
File* file = (File*) assimpFile->UserData;
return lovrFileSeek(file, position) ? aiReturn_FAILURE : aiReturn_SUCCESS;
}
static unsigned long assimpFileTell(struct aiFile* file) {
return lovrFilesystemTell(file->UserData);
static unsigned long assimpFileTell(struct aiFile* assimpFile) {
File* file = (File*) assimpFile->UserData;
return lovrFileTell(file);
}
static struct aiFile* assimpFileOpen(struct aiFileIO* io, const char* path, const char* mode) {
struct aiFile* file = malloc(sizeof(struct aiFile));
struct aiFile* assimpFile = malloc(sizeof(struct aiFile));
Blob* blob = (Blob*) io->UserData;
if (!strcmp(blob->name, path)) {
file->ReadProc = assimpBlobRead;
file->FileSizeProc = assimpBlobGetSize;
file->SeekProc = assimpBlobSeek;
file->TellProc = assimpBlobTell;
file->UserData = (void*) blob;
assimpFile->ReadProc = assimpBlobRead;
assimpFile->FileSizeProc = assimpBlobGetSize;
assimpFile->SeekProc = assimpBlobSeek;
assimpFile->TellProc = assimpBlobTell;
assimpFile->UserData = (void*) blob;
} else {
file->ReadProc = assimpFileRead;
file->FileSizeProc = assimpFileGetSize;
file->SeekProc = assimpFileSeek;
file->TellProc = assimpFileTell;
file->UserData = lovrFilesystemOpen(path, OPEN_READ);
char normalizedPath[LOVR_PATH_MAX];
normalizePath(path, normalizedPath, LOVR_PATH_MAX);
File* file = lovrFileCreate(path);
if (lovrFileOpen(file, OPEN_READ)) {
return NULL;
}
assimpFile->ReadProc = assimpFileRead;
assimpFile->FileSizeProc = assimpFileGetSize;
assimpFile->SeekProc = assimpFileSeek;
assimpFile->TellProc = assimpFileTell;
assimpFile->UserData = (void*) file;
}
return file;
return assimpFile;
}
static void assimpFileClose(struct aiFileIO* io, struct aiFile* file) {
static void assimpFileClose(struct aiFileIO* io, struct aiFile* assimpFile) {
void* blob = io->UserData;
if (file->UserData != blob) {
lovrFilesystemClose(file->UserData);
if (assimpFile->UserData != blob) {
File* file = (File*) assimpFile->UserData;
lovrFileClose(file);
lovrRelease(&file->ref);
}
free(assimpFile);
}
static void assimpSumChildren(struct aiNode* assimpNode, int* totalChildren) {
@ -126,6 +184,10 @@ ModelData* lovrModelDataCreate(Blob* blob) {
const struct aiScene* scene = aiImportFileExWithProperties(blob->name, flags, &assimpIO, propertyStore);
aiReleasePropertyStore(propertyStore);
if (!scene) {
lovrThrow("Unable to load model from '%s': %s\n", blob->name, aiGetErrorString());
}
modelData->nodeCount = 0;
modelData->vertexCount = 0;
modelData->indexCount = 0;
@ -216,19 +278,11 @@ ModelData* lovrModelDataCreate(Blob* blob) {
if (aiGetMaterialTexture(material, aiTextureType_DIFFUSE, 0, &str, NULL, NULL, NULL, NULL, NULL, NULL) == aiReturn_SUCCESS) {
char* path = str.data;
if (strstr(path, "./") == path) {
path += 2;
} else if (path[0] == '/') {
lovrThrow("Absolute paths are not supported");
}
char fullpath[LOVR_PATH_MAX];
char* dir = dirname((char*) blob->name);
snprintf(fullpath, LOVR_PATH_MAX, "%s/%s", dir, path);
char normalizedPath[LOVR_PATH_MAX];
normalizePath(path, normalizedPath, LOVR_PATH_MAX);
size_t size;
void* data = lovrFilesystemRead(fullpath, &size);
void* data = lovrFilesystemRead(path, &size);
if (data) {
Blob* blob = lovrBlobCreate(data, size, path);
materialData->textures[TEXTURE_DIFFUSE] = lovrTextureDataFromBlob(blob);