/* \brief check if file is a MikuMikuDance PMD file */ int _glhckFormatPMD(const char *file) { FILE *f; mmd_data *mmd = NULL; CALL(0, "%s", file); if (!(f = fopen(file, "rb"))) goto read_fail; if (!(mmd = mmd_new(f))) goto fail; if (mmd_read_header(mmd) != 0) goto fail; /* close file */ NULLDO(mmd_free, mmd); NULLDO(fclose, f); return RETURN_OK; read_fail: DEBUG(GLHCK_DBG_ERROR, "Failed to open: %s", file); fail: IFDO(mmd_free, mmd); IFDO(fclose, f); return RETURN_FAIL; }
static void _pndman_device_memory_free(pndman_device *device) { IFDO(free, device->mount); IFDO(free, device->device); IFDO(free, device->appdata); free(device); }
/* \brief import image file */ int _glhckImportImage(glhckTexture *texture, const char *file, const glhckImportImageParameters *params) { _glhckImageImporter *importer; _glhckImportImageStruct import; CALL(0, "%p, %s, %p", texture, file, params); DEBUG(GLHCK_DBG_CRAP, "Image: %s", file); memset(&import, 0, sizeof(_glhckImportImageStruct)); /* figure out the image format */ if (!(importer = _glhckGetImageImporter(file))) { RET(0, "%d", RETURN_FAIL); return RETURN_FAIL; } /* import */ if (importer->importFunc(file, &import) != RETURN_OK) goto fail; /* post process */ if (_glhckImagePostProcess(texture, params, &import) != RETURN_OK) goto fail; IFDO(_glhckFree, import.data); RET(0, "%d", RETURN_OK); return RETURN_OK; fail: IFDO(_glhckFree, import.data); RET(0, "%d", RETURN_FAIL); return RETURN_FAIL; }
/* \brief check if file is TGA */ int _glhckFormatTGA(const char *file) { FILE *f; void *data = NULL; char isTga = 0; size_t size; tga_header *header; tga_footer *footer; CALL(0, "%s", file); if (!(f = fopen(file, "rb"))) goto read_fail; fseek(f, 0L, SEEK_END); if ((size = ftell(f)) < sizeof(tga_header) + sizeof(tga_footer)) goto fail; if (!(data = _glhckMalloc(size))) goto out_of_memory; fseek(f, 0L, SEEK_SET); if (fread(data, 1, size, f) != size) goto fail; /* we don't need the file anymore */ NULLDO(fclose, f); header = (tga_header*)data; footer = (tga_footer*)((char*)data+size-sizeof(tga_footer)); /* is TGA v2.0? (stop storing the headers at EOF please) */ if (!memcmp(footer->signature, TGA_SIGNATURE, sizeof(footer->signature))) isTga = 1; else if ((header->bpp == 32) || (header->bpp == 24) || (header->bpp == 8)) isTga = 1; NULLDO(_glhckFree, data); RET(0, "%d", isTga?RETURN_OK:RETURN_FAIL); return isTga?RETURN_OK:RETURN_FAIL; read_fail: DEBUG(GLHCK_DBG_ERROR, "Failed to open: %s", file); goto fail; out_of_memory: DEBUG(GLHCK_DBG_ERROR, "Out of memory, won't load file: %s", file); fail: IFDO(fclose, f); IFDO(_glhckFree, data); return RETURN_FAIL; }
/* \brief import Assimp file */ int _glhckImportAssimp(glhckObject *object, const char *file, const glhckImportModelParameters *params, glhckGeometryIndexType itype, glhckGeometryVertexType vtype) { const struct aiScene *scene; glhckObject *first = NULL; unsigned int aflags; CALL(0, "%p, %s, %p", object, file, params); /* import the model using assimp * TODO: make import hints tunable? * Needs changes to import protocol! */ aflags = aiProcessPreset_TargetRealtime_Fast | aiProcess_OptimizeGraph; if (!params->animated && params->flatten) aflags |= aiProcess_PreTransformVertices; scene = aiImportFile(file, aflags); if (!scene) goto assimp_fail; /* mark ourself as special root object. * this makes most functions called on root object echo to children */ object->flags |= GLHCK_OBJECT_ROOT; /* this is going to be the first object in mesh, * the object returned by this importer is just invisible root object. */ if (!(first = glhckObjectNew())) goto fail; glhckObjectAddChild(object, first); glhckObjectFree(first); /* process the model */ if (processModel(file, object, first, scene, scene->mRootNode, itype, vtype, params) != RETURN_OK) goto fail; /* process the animated model part */ if (params->animated && processBonesAndAnimations(object, scene) != RETURN_OK) goto fail; /* close file */ NULLDO(aiReleaseImport, scene); RET(0, "%d", RETURN_OK); return RETURN_OK; assimp_fail: DEBUG(GLHCK_DBG_ERROR, aiGetErrorString()); fail: IFDO(aiReleaseImport, scene); IFDO(glhckObjectFree, first); RET(0, "%d", RETURN_FAIL); return RETURN_FAIL; }
static int buildModel(glhckObject *object, unsigned int numIndices, unsigned int numVertices, const glhckImportIndexData *indices, const glhckImportVertexData *vertexData, glhckGeometryIndexType itype, glhckGeometryVertexType vtype) { unsigned int geometryType = GLHCK_TRIANGLE_STRIP; unsigned int numStrippedIndices = 0; glhckImportIndexData *stripIndices = NULL; if (!numVertices) return RETURN_OK; /* triangle strip geometry */ if (!(stripIndices = _glhckTriStrip(indices, numIndices, &numStrippedIndices))) { /* failed, use non stripped geometry */ geometryType = GLHCK_TRIANGLES; numStrippedIndices = numIndices; } /* set geometry */ glhckObjectInsertIndices(object, itype, (stripIndices?stripIndices:indices), numStrippedIndices); glhckObjectInsertVertices(object, vtype, vertexData, numVertices); object->geometry->type = geometryType; IFDO(_glhckFree, stripIndices); return RETURN_OK; }
/* \brief allocate new camera */ GLHCKAPI glhckCamera* glhckCameraNew(void) { glhckCamera *object; /* allocate camera */ if (!(object = _glhckCalloc(1, sizeof(glhckCamera)))) goto fail; /* increase reference */ object->refCounter++; /* initialize camera's object */ if (!(object->object = glhckObjectNew())) goto fail; /* defaults */ object->view.projectionType = GLHCK_PROJECTION_PERSPECTIVE; object->view.near = 1.0f; object->view.far = 100.0f; object->view.fov = 35.0f; /* reset */ glhckCameraReset(object); /* insert to world */ _glhckWorldInsert(camera, object, glhckCamera*); RET(0, "%p", object); return object; fail: IFDO(_glhckFree, object); RET(0, "%p", NULL); return NULL; }
/* \brief save texture to file in TGA format */ GLHCKAPI int glhckTextureSave(glhckTexture *object, const char *path) { FILE *f = NULL; CALL(0, "%p, %s", object, path); assert(object); DEBUG(GLHCK_DBG_CRAP, "\2Save \3%d\5x\3%d\5 [\4%s\5]", object->width, object->height, path); /* TODO: Render to FBO to get the image * Or use glGetTexImage if it's available (not in GLES) */ #if 0 /* open for read */ if (!(f = fopen(path, "wb"))) goto fail; /* dump raw data */ fwrite(object->data, 1, object->size, f); NULLDO(fclose, f); #endif RET(0, "%d", RETURN_OK); return RETURN_OK; //fail: IFDO(fclose, f); RET(0, "%d", RETURN_FAIL); return RETURN_FAIL; }
/* \brief new texture object from file */ GLHCKAPI glhckTexture* glhckTextureNewFromFile(const char *file, const glhckImportImageParameters *importParams, const glhckTextureParameters *params) { glhckTexture *object; CALL(0, "%s, %p, %p", file, importParams, params); assert(file); /* check if texture is in cache */ if ((object = _glhckTextureCacheCheck(file))) goto success; if (!(object = glhckTextureNew())) goto fail; /* copy filename */ if (!(object->file = _glhckStrdup(file))) goto fail; /* import image */ if (_glhckImportImage(object, file, importParams) != RETURN_OK) goto fail; /* apply texture parameters */ glhckTextureParameter(object, params); success: RET(0, "%p", object); return object; fail: IFDO(glhckTextureFree, object); RET(0, "%p", NULL); return NULL; }
/* \brief free texture */ GLHCKAPI unsigned int glhckTextureFree(glhckTexture *object) { unsigned int i; if (!glhckInitialized()) return 0; CALL(FREE_CALL_PRIO(object), "%p", object); assert(object); /* there is still references to this object alive */ if (--object->refCounter != 0) goto success; DEBUG(GLHCK_DBG_CRAP, "FREE(%p) %dx%dx%d", object, object->internalWidth, object->internalHeight, object->internalDepth); /* unbind from active slot */ for (i = 0; i != GLHCK_MAX_ACTIVE_TEXTURE; ++i) { if (GLHCKRD()->texture[i][object->target] == object) glhckTextureUnbind(object->target); } /* delete texture if there is one */ if (object->object) GLHCKRA()->textureDelete(1, &object->object); /* free */ IFDO(_glhckFree, object->file); /* remove from world */ _glhckWorldRemove(texture, object, glhckTexture*); /* free */ NULLDO(_glhckFree, object); success: RET(FREE_RET_PRIO(object), "%u", object?object->refCounter:0); return object?object->refCounter:0; }
/* \brief allocate new texture object */ GLHCKAPI glhckTexture* glhckTextureNew(void) { glhckTexture *object; /* allocate texture */ if (!(object = _glhckCalloc(1, sizeof(glhckTexture)))) goto fail; /* increase reference */ object->refCounter++; /* default target type */ object->target = GLHCK_TEXTURE_2D; /* insert to world */ _glhckWorldInsert(texture, object, glhckTexture*); RET(0, "%p", object); return object; fail: IFDO(glhckTextureFree, object); RET(0, "%p", NULL); return NULL; }
/* \brief use browser to load images, may support more formats than glhck */ int _glhckImportEmscripten(const char *file, _glhckImportImageStruct *import) { unsigned int i, i2; unsigned char *importData = NULL, hasa = 0; SDL_Surface* surface = NULL; glhckTextureFormat format; CALL(0, "%s, %p", file, import); if (!(surface = IMG_Load(file))) goto fail; if (surface->format->BytesPerPixel == 4) { hasa = 1; if (surface->format->Rmask == 0x000000ff) format = GLHCK_RGBA; else format = GLHCK_BGRA; } else if (surface->format->BytesPerPixel == 3) { if (surface->format->Rmask == 0x000000ff) format = GLHCK_RGB; else format = GLHCK_BGR; } else { goto not_truecolor; } if (!(importData = _glhckMalloc(surface->w * surface->h * 4))) goto fail; memcpy(importData, surface->pixels, surface->w * surface->h * 4); _glhckInvertPixels(importData, surface->w, surface->h, surface->format->BytesPerPixel); import->width = surface->w; import->height = surface->h; import->data = importData; import->format = format; import->type = GLHCK_UNSIGNED_BYTE; import->flags |= (hasa?GLHCK_TEXTURE_IMPORT_ALPHA:0); SDL_FreeSurface(surface); RET(0, "%d", RETURN_OK); return RETURN_OK; not_truecolor: DEBUG(GLHCK_DBG_ERROR, "SDL_Surface not truecolor, will bail out!"); fail: IFDO(SDL_FreeSurface, surface); IFDO(_glhckFree, importData); RET(0, "%d", RETURN_FAIL); return RETURN_FAIL; }
static void _pndman_device_set_mount(pndman_device *device, const char *mount) { assert(device); IFDO(free, device->mount); if (mount) { device->mount = strdup(mount); if (strcmp(mount, "/")) _strip_slash(device->mount); } }
static void _pndman_device_set_device(pndman_device *device, const char *cdevice) { assert(device); IFDO(free, device->device); if (cdevice) { device->device = strdup(cdevice); if (strcmp(cdevice, "/")) _strip_slash(device->device); } }
/* post-processing of image data */ int _glhckImagePostProcess(glhckTexture *texture, const glhckImportImageParameters *params, const _glhckImportImageStruct *import) { int size = 0; void *data = NULL, *compressed = NULL; glhckTextureFormat format; glhckDataType type; CALL(0, "%p, %p, %p", texture, params, import); assert(texture); assert(import); /* use default parameters */ if (!params) params = glhckImportDefaultImageParameters(); /* try to compress the data if requested */ if (params->compression != GLHCK_COMPRESSION_NONE) { compressed = glhckTextureCompress(params->compression, import->width, import->height, import->format, import->type, import->data, &size, &format, &type); } /* compression not done/failed */ if (!(data = compressed)) { data = import->data; format = import->format; type = import->type; } /* pass the import flags */ texture->importFlags = import->flags; /* upload texture */ if (glhckTextureCreate(texture, GLHCK_TEXTURE_2D, 0, import->width, import->height, 0, 0, format, type, size, data) != RETURN_OK) goto fail; IFDO(_glhckFree, compressed); RET(0, "%d", RETURN_OK); return RETURN_OK; fail: IFDO(_glhckFree, compressed); RET(0, "%d", RETURN_FAIL); return RETURN_FAIL; }
/* \brief compress image data, this is public function which return data you must free! */ GLHCKAPI void* glhckTextureCompress(glhckTextureCompression compression, int width, int height, glhckTextureFormat format, glhckDataType type, const void *data, int *size, glhckTextureFormat *outFormat, glhckDataType *outType) { void *compressed = NULL; CALL(0, "%d, %d, %d, %d, %d, %p, %p, %p", compression, width, height, format, type, data, size, outFormat); assert(type == GLHCK_UNSIGNED_BYTE && "Only GLHCK_UNSIGNED_BYTE is supported atm"); if (size) *size = 0; if (outFormat) *outFormat = 0; /* NULL data, just return */ if (!data) goto fail; /* check if already compressed */ if (_glhckIsCompressedFormat(format)) goto already_compressed; /* DXT compression requested */ if (compression == GLHCK_COMPRESSION_DXT) { if ((_glhckNumChannels(format) & 1) == 1) { /* RGB */ if (!(compressed = malloc(texhckSizeForDXT1(width, height)))) goto out_of_memory; texhckConvertToDXT1(compressed, data, width, height, _glhckNumChannels(format)); if (size) *size = texhckSizeForDXT1(width, height); if (outFormat) *outFormat = GLHCK_COMPRESSED_RGB_DXT1; if (outType) *outType = GLHCK_UNSIGNED_BYTE; DEBUG(GLHCK_DBG_CRAP, "Image data converted to DXT1"); } else { /* RGBA */ if (!(compressed = malloc(texhckSizeForDXT5(width, height)))) goto out_of_memory; texhckConvertToDXT5(compressed, data, width, height, _glhckNumChannels(format)); if (size) *size = texhckSizeForDXT5(width, height); if (outFormat) *outFormat = GLHCK_COMPRESSED_RGBA_DXT5; if (outType) *outType = GLHCK_UNSIGNED_BYTE; DEBUG(GLHCK_DBG_CRAP, "Image data converted to DXT5"); } } else { DEBUG(GLHCK_DBG_WARNING, "Compression type not implemented or supported for the texture format/datatype combination."); } RET(0, "%p", compressed); return compressed; already_compressed: DEBUG(GLHCK_DBG_WARNING, "Image data is already compressed"); goto fail; out_of_memory: DEBUG(GLHCK_DBG_ERROR, "Out of memory"); fail: IFDO(_glhckFree, compressed); RET(0, "%p", NULL); return NULL; }
/* \brief add new pnd to repository */ pndman_package* _pndman_repository_new_pnd(pndman_repository *repo) { pndman_package *p; assert(repo); if (repo->pnd) { for (p = repo->pnd; p->next; p = p->next); p = p->next = _pndman_new_pnd(); } else p = repo->pnd = _pndman_new_pnd(); IFDO(free, p->repository); if (repo->url) p->repository = strdup(repo->url); p->repositoryptr = repo; return p; }
/* \brief remove temp files in appdata (don't create tree) */ static void _pndman_remove_tmp_files(pndman_device *device) { char *tmp = NULL; #ifndef _WIN32 DIR *dp; struct dirent *ep; #else WIN32_FIND_DATA dp; HANDLE hFind = NULL; #endif assert(device && device->mount); if (!(tmp = _pndman_device_get_appdata_no_create(device))) goto fail; #ifndef _WIN32 dp = opendir(tmp); if (!dp) return; while ((ep = readdir(dp))) { if (strstr(ep->d_name, ".tmp")) { char *tmp2; int size2 = snprintf(NULL, 0, "%s/%s", tmp, ep->d_name)+1; if (!(tmp2 = malloc(size2))) continue; sprintf(tmp2, "%s/%s", tmp, ep->d_name); remove(tmp2); free(tmp2); } } closedir(dp); #else if ((hFind = FindFirstFile(tmp, &dp)) == INVALID_HANDLE_VALUE) return; do { char *tmp2; int size2 = snprintf(NULL, 0, "%s/%s", tmp, dp.cFileName)+1; if (!(tmp2 = malloc(size2))) continue; sprintf(tmp2, "%s/%s", tmp, dp.cFileName); remove(tmp2); free(tmp2); } while (FindNextFile(hFind, &dp)); FindClose(hFind); #endif fail: IFDO(free, tmp); }
/* \brief set weights to skin bone */ GLHCKAPI int glhckSkinBoneInsertWeights(glhckSkinBone *object, const glhckVertexWeight *weights, unsigned int memb) { glhckVertexWeight *weightsCopy = NULL; CALL(0, "%p, %p, %u", object, weights, memb); assert(object); /* copy weights, if they exist */ if (weights && !(weightsCopy = _glhckCopy(weights, memb * sizeof(glhckVertexWeight)))) goto fail; IFDO(_glhckFree, object->weights); object->weights = weightsCopy; object->numWeights = (weightsCopy?memb:0); return RETURN_OK; fail: return RETURN_FAIL; }
/* \brief check duplicate pnd on repo, return that pnd if found, else return new */ pndman_package* _pndman_repository_new_pnd_check(pndman_package *in_pnd, const char *path, const char *mount, pndman_repository *repo) { pndman_package *pnd, *pni, *pr; pr = NULL; for (pnd = repo->pnd; pnd; pnd = pnd->next) { if (in_pnd->id && pnd->id && !strcmp(in_pnd->id, pnd->id)) { /* if local repository, create instance */ if (!repo->prev) { /* create instance here, path differs! */ if (!repo->prev && path && pnd->path && strcmp(path, pnd->path) && pnd->mount && mount && strcmp(pnd->mount, mount)) { /* only local repo can have next installed */ if (!_pndman_vercmp(&pnd->version, &in_pnd->version)) { /* new pnd is older, assing it to end */ for (pni = pnd; pni && pni->next_installed; pni = pni->next_installed) if (path && pni->path && !strcmp(path, pni->path)) return pni; /* it's next installed */ if (!(pni = pni->next_installed = _pndman_new_pnd())) return NULL; pni->next = pnd->next; /* assign parent's next to next */ DEBUG(PNDMAN_LEVEL_CRAP, "Older : %s", path); } else { /* new pnd is newer, assign it to first */ if (!(pni = _pndman_new_pnd())) return NULL; pr->next = pni; pni->next_installed = pnd; /* assign nexts */ pni->next = pnd->next; DEBUG(PNDMAN_LEVEL_CRAP, "Newer : %s", path); } IFDO(free, pni->repository); if (repo->url) pni->repository = strdup(repo->url); pni->repositoryptr = repo; return pni; } else return pnd; /* this is the same pnd as installed locally */ } else return pnd; /* remote repository can't have instances :) */ } pr = pnd; } /* create new pnd */ return _pndman_repository_new_pnd(repo); }
/* \brief pop render state from stack */ GLHCKAPI void glhckRenderStatePop(void) { __GLHCKrenderState *state, *newState; if (!(state = GLHCKR()->stack)) return; glhckRenderResize(state->width, state->height); memcpy(&GLHCKR()->pass, &state->pass, sizeof(__GLHCKrenderPass)); glhckRenderClearColor(&state->pass.clearColor); glhckRenderViewport(&state->pass.viewport); glhckRenderProjection(&state->view.projection); glhckRenderView(&state->view.view); GLHCKRA()->setOrthographic(&state->view.orthographic); memcpy(&GLHCKRD()->view.orthographic, &state->view.orthographic, sizeof(kmMat4)); glhckRenderFlip(state->view.flippedProjection); newState = (state?state->next:NULL); IFDO(_glhckFree, state); GLHCKR()->stack = newState; }
static glhckBone* processBones(const struct aiNode *boneNd, const struct aiNode *nd, const struct aiMesh *mesh, glhckBone **bones, glhckSkinBone **skinBones, unsigned int *numBones) { kmMat4 matrix, transposed; glhckBone *bone = NULL, *child; glhckSkinBone *skinBone = NULL; const struct aiBone *assimpBone; unsigned int i; assert(boneNd && nd); assert(mesh); assert(numBones); /* something went wrong */ if (!numBones || *numBones >= ASSIMP_BONES_MAX) goto fail; /* don't allow duplicates */ for (i = 0; i != *numBones; ++i) if (!strcmp(glhckBoneGetName(bones[i]), boneNd->mName.data)) goto fail; /* create new bone */ if (!(bone = glhckBoneNew()) || !(skinBone = glhckSkinBoneNew())) goto fail; /* set bone to list */ bones[*numBones] = bone; skinBones[*numBones] = skinBone; *numBones = *numBones+1; /* store bone name */ glhckBoneName(bone, boneNd->mName.data); glhckSkinBoneBone(skinBone, bone); /* skip this part by creating dummy bone, if this information is not found */ if ((assimpBone = findBone(mesh, bone->name))) { /* get offset matrix */ matrix.mat[0] = assimpBone->mOffsetMatrix.a1; matrix.mat[1] = assimpBone->mOffsetMatrix.a2; matrix.mat[2] = assimpBone->mOffsetMatrix.a3; matrix.mat[3] = assimpBone->mOffsetMatrix.a4; matrix.mat[4] = assimpBone->mOffsetMatrix.b1; matrix.mat[5] = assimpBone->mOffsetMatrix.b2; matrix.mat[6] = assimpBone->mOffsetMatrix.b3; matrix.mat[7] = assimpBone->mOffsetMatrix.b4; matrix.mat[8] = assimpBone->mOffsetMatrix.c1; matrix.mat[9] = assimpBone->mOffsetMatrix.c2; matrix.mat[10] = assimpBone->mOffsetMatrix.c3; matrix.mat[11] = assimpBone->mOffsetMatrix.c4; matrix.mat[12] = assimpBone->mOffsetMatrix.d1; matrix.mat[13] = assimpBone->mOffsetMatrix.d2; matrix.mat[14] = assimpBone->mOffsetMatrix.d3; matrix.mat[15] = assimpBone->mOffsetMatrix.d4; /* get weights */ glhckVertexWeight weights[assimpBone->mNumWeights]; memset(weights, 0, sizeof(weights)); for (i = 0; i != assimpBone->mNumWeights; ++i) { weights[i].vertexIndex = assimpBone->mWeights[i].mVertexId; weights[i].weight = assimpBone->mWeights[i].mWeight; } /* assimp is row-major, kazmath is column-major */ kmMat4Transpose(&transposed, &matrix); glhckSkinBoneOffsetMatrix(skinBone, &transposed); glhckSkinBoneInsertWeights(skinBone, weights, assimpBone->mNumWeights); } /* get transformation matrix */ matrix.mat[0] = boneNd->mTransformation.a1; matrix.mat[1] = boneNd->mTransformation.a2; matrix.mat[2] = boneNd->mTransformation.a3; matrix.mat[3] = boneNd->mTransformation.a4; matrix.mat[4] = boneNd->mTransformation.b1; matrix.mat[5] = boneNd->mTransformation.b2; matrix.mat[6] = boneNd->mTransformation.b3; matrix.mat[7] = boneNd->mTransformation.b4; matrix.mat[8] = boneNd->mTransformation.c1; matrix.mat[9] = boneNd->mTransformation.c2; matrix.mat[10] = boneNd->mTransformation.c3; matrix.mat[11] = boneNd->mTransformation.c4; matrix.mat[12] = boneNd->mTransformation.d1; matrix.mat[13] = boneNd->mTransformation.d2; matrix.mat[14] = boneNd->mTransformation.d3; matrix.mat[15] = boneNd->mTransformation.d4; /* assimp is row-major, kazmath is column-major */ kmMat4Transpose(&transposed, &matrix); glhckBoneTransformationMatrix(bone, &transposed); /* process children bones */ for (i = 0; i != boneNd->mNumChildren; ++i) { child = processBones(findNode(nd, boneNd->mChildren[i]->mName.data), nd, mesh, bones, skinBones, numBones); if (child) glhckBoneParentBone(child, bone); } return bone; fail: IFDO(glhckBoneFree, bone); IFDO(glhckSkinBoneFree, skinBone); return RETURN_FAIL; }
/* \brief return tristripped indecies for triangle index data */ glhckImportIndexData* _glhckTriStrip(const glhckImportIndexData *indices, unsigned int memb, unsigned int *outMemb) { #if !GLHCK_TRISTRIP (void)indices; (void)memb; (void)outMemb; /* stripping is disabled. * importers should fallback to GLHCK_TRIANGLES */ return NULL; #else int prim; glhckImportIndexData v1, v2, v3; glhckImportIndexData *outIndices = NULL, *newIndices = NULL; unsigned int i, primCount, tmp; ACTCData *tc = NULL; CALL(0, "%p, %u, %p", indices, memb, outMemb); /* check if the triangles we got are valid */ if (memb % 3 != 0) goto not_valid; if (!(outIndices = _glhckMalloc(memb * sizeof(glhckImportIndexData)))) goto out_of_memory; if (!(tc = actcNew())) goto actc_fail; /* parameters */ ACTC_CALL(actcParami(tc, ACTC_OUT_MIN_FAN_VERTS, INT_MAX)); ACTC_CALL(actcParami(tc, ACTC_OUT_HONOR_WINDING, ACTC_FALSE)); /* input data */ ACTC_CALL(actcBeginInput(tc)); for (i = 0; i != memb; i+=3) { ACTC_CALL(actcAddTriangle(tc, indices[i+0], indices[i+1], indices[i+2])); } ACTC_CALL(actcEndInput(tc)); /* FIXME: fix the winding of generated stiched strips */ /* output data */ tmp = memb, i = 0, primCount = 0; unsigned int flipStart = 0, length = 0; ACTC_CALL(actcBeginOutput(tc)); while ((prim = actcStartNextPrim(tc, &v1, &v2)) != ACTC_DATABASE_EMPTY) { assert(prim == ACTC_PRIM_STRIP); if (i + (primCount?5:3) > memb) goto no_profit; /* degenerate to next strip */ if (primCount && v1 != v3) { if (length & 1) { _glhckTriStripReverse(&outIndices[flipStart], i-flipStart); if (flipStart) outIndices[flipStart-1] = outIndices[flipStart]; } v3 = outIndices[i-1]; if (v1 != v3) { outIndices[i++] = v3; outIndices[i++] = v1; } flipStart = i; } length = 0; outIndices[i++] = v1; outIndices[i++] = v2; while (actcGetNextVert(tc, &v3) != ACTC_PRIM_COMPLETE) { if (i + 1 > memb) goto no_profit; outIndices[i++] = v3; ++length; } primCount++; } ACTC_CALL(actcEndOutput(tc)); puts(""); printf("%u alloc\n", memb); if (outMemb) *outMemb = i; memb = tmp; // for (i = *outMemb-12; i != *outMemb; ++i) // outIndices[i] = 0; #if 0 puts("- INDICES:"); for (i = 0; i != *outMemb; ++i) printf("%u%s", outIndices[i], (!((i+1) % 3)?"\n":", ")); puts(""); #endif if (!(newIndices = _glhckRealloc(outIndices, memb, i, sizeof(glhckImportIndexData)))) goto out_of_memory; outIndices = newIndices; printf("%u indices\n", memb); printf("%u out indicies\n", i); printf("%u tristrips\n", primCount); printf("%u profit\n", memb - i); actcDelete(tc); RET(0, "%p", outIndices); return outIndices; not_valid: DEBUG(GLHCK_DBG_ERROR, "Tristripper: not valid triangle indices"); goto fail; out_of_memory: DEBUG(GLHCK_DBG_ERROR, "Tristripper: out of memory"); goto fail; actc_fail: DEBUG(GLHCK_DBG_ERROR, "Tristripper: init failed"); goto fail; no_profit: DEBUG(GLHCK_DBG_CRAP, "Tripstripper: no profit from stripping, fallback to triangles"); fail: IFDO(actcDelete, tc); IFDO(_glhckFree, outIndices); RET(0, "%p", NULL); return NULL; #endif }
/* \brief check the pnd tree before writing to ->appdata */ static int _pndman_device_check_pnd_tree(pndman_device *device) { char *tmp = NULL; char *tmp2 = NULL; assert(device && device->mount); /* <device>/pandora */ int size = snprintf(NULL, 0, "%s/pandora", device->mount)+1; if (!(tmp = malloc(size))) goto fail; sprintf(tmp, "%s/pandora", device->mount); if (_check_create_tree_dir(tmp) == -1) goto fail; /* <device>/apps */ int size2 = snprintf(NULL, 0, "%s/apps", tmp)+1; if (!(tmp2 = malloc(size2))) goto fail; sprintf(tmp2, "%s/apps", tmp); if (_check_create_tree_dir(tmp2) == -1) goto fail; free(tmp2); /* <device>/menu */ size2 = snprintf(NULL, 0, "%s/menu", tmp)+1; if (!(tmp2 = malloc(size2))) goto fail; sprintf(tmp2, "%s/menu", tmp); if (_check_create_tree_dir(tmp2) == -1) goto fail; free(tmp2); /* <device>/desktop */ size2 = snprintf(NULL, 0, "%s/desktop", tmp)+1; if (!(tmp2 = malloc(size2))) goto fail; sprintf(tmp2, "%s/desktop", tmp); if (_check_create_tree_dir(tmp2) == -1) goto fail; free(tmp2); /* <device>/appdata */ size2 = snprintf(NULL, 0, "%s/appdata", tmp)+1; if (!(tmp2 = malloc(size2))) goto fail; sprintf(tmp2, "%s/appdata", tmp); if (_check_create_tree_dir(tmp2) == -1) goto fail; free(tmp2); /* <device>/appdata/<LIBPNDMAN_APPDATA_FOLDER> */ size2 = snprintf(NULL, 0, "%s/appdata/%s", tmp, PNDMAN_APPDATA)+1; if (!(tmp2 = malloc(size2))) goto fail; sprintf(tmp2, "%s/appdata/%s", tmp, PNDMAN_APPDATA); if (_check_create_tree_dir(tmp2) == -1) goto fail; _pndman_device_set_appdata(device, tmp2); free(tmp2); free(tmp); return RETURN_OK; fail: IFDO(free, tmp); IFDO(free, tmp2); return RETURN_FAIL; }
static int processModel(const char *file, glhckObject *object, glhckObject *current, const struct aiScene *sc, const struct aiNode *nd, glhckGeometryIndexType itype, glhckGeometryVertexType vtype, const glhckImportModelParameters *params) { unsigned int m, f; unsigned int numVertices = 0, numIndices = 0; unsigned int ioffset, voffset; glhckImportIndexData *indices = NULL; glhckImportVertexData *vertexData = NULL; glhckMaterial *material = NULL; glhckTexture **textureList = NULL, *texture = NULL; glhckAtlas *atlas = NULL; const struct aiMesh *mesh; const struct aiFace *face; int canFreeCurrent = 0; int hasTexture = 0; assert(file); assert(object && current); assert(sc && nd); /* combine && atlas loading path */ if (params->flatten) { /* prepare atlas for texture combining */ if (!(atlas = glhckAtlasNew())) goto assimp_no_memory; /* texturelist for offseting coordinates */ if (!(textureList = _glhckCalloc(nd->mNumMeshes, sizeof(_glhckTexture*)))) goto assimp_no_memory; /* gather statistics */ for (m = 0; m != nd->mNumMeshes; ++m) { mesh = sc->mMeshes[nd->mMeshes[m]]; if (!mesh->mVertices) continue; for (f = 0; f != mesh->mNumFaces; ++f) { face = &mesh->mFaces[f]; if (!face) goto fail; numIndices += face->mNumIndices; } numVertices += mesh->mNumVertices; if ((texture = textureFromMaterial(file, sc->mMaterials[mesh->mMaterialIndex]))) { glhckAtlasInsertTexture(atlas, texture); glhckTextureFree(texture); textureList[m] = texture; hasTexture = 1; } } /* allocate vertices */ if (!(vertexData = _glhckCalloc(numVertices, sizeof(glhckImportVertexData)))) goto assimp_no_memory; /* allocate indices */ if (!(indices = _glhckMalloc(numIndices * sizeof(glhckImportIndexData)))) goto assimp_no_memory; /* pack combined textures */ if (hasTexture) { if (glhckAtlasPack(atlas, GLHCK_RGBA, 1, 0, glhckTextureDefaultParameters()) != RETURN_OK) goto fail; } else { NULLDO(glhckAtlasFree, atlas); NULLDO(_glhckFree, textureList); } /* join vertex data */ for (m = 0, ioffset = 0, voffset = 0; m != nd->mNumMeshes; ++m) { mesh = sc->mMeshes[nd->mMeshes[m]]; if (!mesh->mVertices) continue; if (textureList) texture = textureList[m]; else texture = NULL; joinMesh(mesh, voffset, indices+ioffset, vertexData+voffset, atlas, texture); for (f = 0; f != mesh->mNumFaces; ++f) { face = &mesh->mFaces[f]; if (!face) goto fail; ioffset += face->mNumIndices; } voffset += mesh->mNumVertices; } /* create material */ if (hasTexture && !(material = glhckMaterialNew(texture))) goto assimp_no_memory; /* finally build the model */ if (buildModel(current, numIndices, numVertices, indices, vertexData, itype, vtype) == RETURN_OK) { _glhckObjectFile(current, nd->mName.data); if (material) glhckObjectMaterial(current, material); if (!(current = glhckObjectNew())) goto fail; glhckObjectAddChild(object, current); glhckObjectFree(current); canFreeCurrent = 1; } /* free stuff */ IFDO(glhckAtlasFree, atlas); IFDO(glhckMaterialFree, material); IFDO(_glhckFree, textureList); NULLDO(_glhckFree, vertexData); NULLDO(_glhckFree, indices); } else { /* default loading path */ for (m = 0, ioffset = 0, voffset = 0; m != nd->mNumMeshes; ++m) { mesh = sc->mMeshes[nd->mMeshes[m]]; if (!mesh->mVertices) continue; /* gather statistics */ numIndices = 0; for (f = 0; f != mesh->mNumFaces; ++f) { face = &mesh->mFaces[f]; if (!face) goto fail; numIndices += face->mNumIndices; } numVertices = mesh->mNumVertices; // FIXME: create materialFromAssimpMaterial // that returns glhckMaterial with correct stuff /* get texture */ hasTexture = 0; if ((texture = textureFromMaterial(file, sc->mMaterials[mesh->mMaterialIndex]))) hasTexture = 1; /* create material */ if (hasTexture && !(material = glhckMaterialNew(texture))) goto assimp_no_memory; /* allocate vertices */ if (!(vertexData = _glhckCalloc(numVertices, sizeof(glhckImportVertexData)))) goto assimp_no_memory; /* allocate indices */ if (!(indices = _glhckMalloc(numIndices * sizeof(glhckImportIndexData)))) goto assimp_no_memory; /* fill arrays */ joinMesh(mesh, 0, indices, vertexData, NULL, NULL); /* build model */ if (buildModel(current, numIndices, numVertices, indices, vertexData, itype, vtype) == RETURN_OK) { /* FIXME: UGLY */ char pointer[16]; snprintf(pointer, sizeof(pointer), "%p", mesh); _glhckObjectFile(current, pointer); if (material) glhckObjectMaterial(current, material); if (!(current = glhckObjectNew())) goto fail; glhckObjectAddChild(object, current); glhckObjectFree(current); canFreeCurrent = 1; } /* free stuff */ NULLDO(_glhckFree, vertexData); NULLDO(_glhckFree, indices); IFDO(glhckTextureFree, texture); IFDO(glhckMaterialFree, material); } } /* process childrens */ for (m = 0; m != nd->mNumChildren; ++m) { if (processModel(file, object, current, sc, nd->mChildren[m], itype, vtype, params) == RETURN_OK) { if (!(current = glhckObjectNew())) goto fail; glhckObjectAddChild(object, current); glhckObjectFree(current); canFreeCurrent = 1; } } /* we din't do anything to the next * allocated object, so free it */ if (canFreeCurrent) glhckObjectRemoveFromParent(current); return RETURN_OK; assimp_no_memory: DEBUG(GLHCK_DBG_ERROR, "Assimp not enough memory."); fail: IFDO(_glhckFree, vertexData); IFDO(_glhckFree, indices); IFDO(_glhckFree, textureList); IFDO(glhckTextureFree, texture); IFDO(glhckMaterialFree, material); IFDO(glhckAtlasFree, atlas); if (canFreeCurrent) glhckObjectRemoveFromParent(current); return RETURN_FAIL; }
/* \brief import TGA images */ int _glhckImportTGA(const char *file, _glhckImportImageStruct *import) { FILE *f; void *seg = NULL, *data; int bpp, vinverted = 0; int rle = 0, footer_present = 0; size_t datasize, size; unsigned short i, w, h; tga_header *header; tga_footer *footer; unsigned char *bufptr, *bufend, *importData = NULL; CALL(0, "%s, %p", file, import); if (!(f = fopen(file, "rb"))) goto read_fail; fseek(f, 0L, SEEK_END); if ((size = ftell(f)) < sizeof(tga_header) + sizeof(tga_footer)) goto not_possible; if (!(seg = _glhckMalloc(size))) goto out_of_memory; fseek(f, 0L, SEEK_SET); if (fread(seg, 1, size, f) != size) goto fail; /* we don't need the file anymore */ NULLDO(fclose, f); data = seg; header = (tga_header*)data; footer = (tga_footer*)((char*)data+size-sizeof(tga_footer)); /* is TGA v2.0? (stop storing the headers at EOF please) */ if (!memcmp(footer->signature, TGA_SIGNATURE, sizeof(footer->signature))) footer_present = 1; /* skip over header */ data = (char*)data+sizeof(tga_header); /* skip over ID filed */ if (header->idLength) data = (char*)data+header->idLength; /* inverted TGA? */ vinverted = !(header->descriptor & TGA_DESC_VERTICAL); switch (header->imageType) { case TGA_TYPE_COLOR_RLE: case TGA_TYPE_GRAY_RLE: rle = 1; break; case TGA_TYPE_COLOR: case TGA_TYPE_GRAY: rle = 0; break; default: goto unknown_type; } bpp = header->bpp; if (!((bpp == 32) || (bpp == 24) || (bpp == 8))) goto invalid_bpp; /* endian safe for 16-bit dimensions */ w = (header->widthHi << 8) | header->widthLo; h = (header->heightHi << 8) | header->heightLo; if (!IMAGE_DIMENSIONS_OK(w, h)) goto bad_dimensions; /* allocate destination buffer */ if (!(importData = _glhckMalloc(w*h*4))) goto out_of_memory; /* find out how much data to be read from file * (this is NOT simply width*height*4, due to compression) */ datasize = size - sizeof(tga_header) - header->idLength - (footer_present ? sizeof(tga_footer) : 0); /* bufptr is the next byte to be read from the buffer */ bufptr = data; bufend = data + datasize; /* non RLE compressed data */ if (!rle) { for (i = 0; i < h*w && bufptr+bpp/8 <= bufend; ++i) { switch (bpp) { /* 32-bit BGRA */ case 32: importData[i*4+0] = bufptr[2]; importData[i*4+1] = bufptr[1]; importData[i*4+2] = bufptr[0]; importData[i*4+3] = bufptr[3]; bufptr += 4; break; /* 24-bit BGR */ case 24: importData[i*4+0] = bufptr[2]; importData[i*4+1] = bufptr[1]; importData[i*4+2] = bufptr[0]; importData[i*4+3] = 255; bufptr += 3; break; /* 8-bit grayscale */ case 8: importData[i*4+0] = bufptr[0]; importData[i*4+1] = bufptr[0]; importData[i*4+2] = bufptr[0]; importData[i*4+3] = 255; bufptr += 1; break; } } } /* RLE compressed data */ if (rle) { DEBUG(GLHCK_DBG_ERROR, "RLE compressed import not yet implemented."); goto fail; } /* some TGA's are upside-down */ if (vinverted) _glhckInvertPixels(importData, w, h, 4); /* free */ NULLDO(_glhckFree, seg); /* fill import struct */ import->width = w; import->height = h; import->data = importData; import->format = GLHCK_RGBA; import->type = GLHCK_UNSIGNED_BYTE; import->flags |= (bpp==32?GLHCK_TEXTURE_IMPORT_ALPHA:0); RET(0, "%d", RETURN_OK); return RETURN_OK; read_fail: DEBUG(GLHCK_DBG_ERROR, "Failed to open: %s", file); goto fail; not_possible: DEBUG(GLHCK_DBG_ERROR, "Assumed TGA file '%s' has too small filesize", file); goto fail; out_of_memory: DEBUG(GLHCK_DBG_ERROR, "Out of memory, won't load file: %s", file); goto fail; unknown_type: DEBUG(GLHCK_DBG_ERROR, "Unknown TGA image type"); goto fail; invalid_bpp: DEBUG(GLHCK_DBG_ERROR, "TGA image is not either 32, 24 or 8 bpp"); goto fail; bad_dimensions: DEBUG(GLHCK_DBG_ERROR, "TGA image has invalid dimension %dx%d", w, h); fail: IFDO(fclose, f); IFDO(_glhckFree, importData); IFDO(_glhckFree, seg); RET(0, "%d", RETURN_FAIL); return RETURN_FAIL; }
static void _pndman_device_set_appdata(pndman_device *device, const char *appdata) { assert(device); IFDO(free, device->appdata); if (appdata) device->appdata = strdup(appdata); }
/* \brief import MikuMikuDance PMD file */ int _glhckImportPMD(_glhckObject *object, const char *file, const glhckImportModelParameters *params, glhckGeometryIndexType itype, glhckGeometryVertexType vtype) { FILE *f; char *texturePath; mmd_data *mmd = NULL; glhckAtlas *atlas = NULL; glhckMaterial *material = NULL; glhckTexture *texture = NULL, **textureList = NULL; glhckImportVertexData *vertexData = NULL; glhckImportIndexData *indices = NULL, *stripIndices = NULL; unsigned int geometryType = GLHCK_TRIANGLE_STRIP; unsigned int i, i2, ix, start, numFaces, numIndices = 0; CALL(0, "%p, %s, %p", object, file, params); if (!(f = fopen(file, "rb"))) goto read_fail; if (!(mmd = mmd_new(f))) goto mmd_no_memory; if (mmd_read_header(mmd) != 0) goto mmd_import_fail; if (mmd_read_vertex_data(mmd) != 0) goto mmd_import_fail; if (mmd_read_index_data(mmd) != 0) goto mmd_import_fail; if (mmd_read_material_data(mmd) != 0) goto mmd_import_fail; /* close file */ NULLDO(fclose, f); if (mmd->header.name) { DEBUG(GLHCK_DBG_CRAP, "%s\n", mmd->header.name); } if (mmd->header.comment) printf("%s\n\n", mmd->header.comment); if (!(vertexData = _glhckCalloc(mmd->num_vertices, sizeof(glhckImportVertexData)))) goto mmd_no_memory; if (!(indices = _glhckMalloc(mmd->num_indices * sizeof(unsigned int)))) goto mmd_no_memory; if (!(textureList = _glhckCalloc(mmd->num_materials, sizeof(_glhckTexture*)))) goto mmd_no_memory; if (!(atlas = glhckAtlasNew())) goto mmd_no_memory; /* add all textures to atlas packer */ for (i = 0; i < mmd->num_materials; ++i) { if (!mmd->materials[i].texture) continue; if (!(texturePath = _glhckImportTexturePath(mmd->materials[i].texture, file))) continue; if ((texture = glhckTextureNewFromFile(texturePath, NULL, NULL))) { glhckAtlasInsertTexture(atlas, texture); glhckTextureFree(texture); textureList[i] = texture; } _glhckFree(texturePath); } for (i = 0; i < mmd->num_materials && !textureList[i]; ++i); if (i >= mmd->num_materials) { /* no textures found */ NULLDO(glhckAtlasFree, atlas); NULLDO(_glhckFree, textureList); } else { /* pack textures */ if (glhckAtlasPack(atlas, GLHCK_RGBA, 1, 0, glhckTextureDefaultParameters()) != RETURN_OK) goto fail; } /* assign data */ for (i = 0, start = 0; i < mmd->num_materials; ++i, start += numFaces) { numFaces = mmd->materials[i].face; for (i2 = start; i2 < start + numFaces; ++i2) { ix = mmd->indices[i2]; /* vertices */ vertexData[ix].vertex.x = mmd->vertices[ix*3+0]; vertexData[ix].vertex.y = mmd->vertices[ix*3+1]; vertexData[ix].vertex.z = mmd->vertices[ix*3+2]; /* normals */ vertexData[ix].normal.x = mmd->normals[ix*3+0]; vertexData[ix].normal.y = mmd->normals[ix*3+1]; vertexData[ix].normal.z = mmd->normals[ix*3+2]; /* texture coords */ vertexData[ix].coord.x = mmd->coords[ix*2+0]; vertexData[ix].coord.y = mmd->coords[ix*2+1] * -1; /* fix coords */ if (vertexData[ix].coord.x < 0.0f) vertexData[ix].coord.x += 1.0f; if (vertexData[ix].coord.y < 0.0f) vertexData[ix].coord.y += 1.0f; /* if there is packed texture */ if (atlas && textureList[i]) { kmVec2 coord; coord.x = vertexData[ix].coord.x; coord.y = vertexData[ix].coord.y; glhckAtlasTransformCoordinates(atlas, textureList[i], &coord, &coord); vertexData[ix].coord.x = coord.x; vertexData[ix].coord.y = coord.y; } indices[i2] = ix; } } if (atlas) { if (!(material = glhckMaterialNew(glhckAtlasGetTexture(atlas)))) goto mmd_no_memory; glhckObjectMaterial(object, material); NULLDO(glhckMaterialFree, material); NULLDO(glhckAtlasFree, atlas); NULLDO(_glhckFree, textureList); } /* triangle strip geometry */ if (!(stripIndices = _glhckTriStrip(indices, mmd->num_indices, &numIndices))) { /* failed, use non stripped geometry */ geometryType = GLHCK_TRIANGLES; numIndices = mmd->num_indices; stripIndices = indices; } else NULLDO(_glhckFree, indices); /* set geometry */ glhckObjectInsertIndices(object, itype, stripIndices, numIndices); glhckObjectInsertVertices(object, vtype, vertexData, mmd->num_vertices); object->geometry->type = geometryType; /* finish */ NULLDO(_glhckFree, vertexData); NULLDO(_glhckFree, stripIndices); NULLDO(mmd_free, mmd); RET(0, "%d", RETURN_OK); return RETURN_OK; read_fail: DEBUG(GLHCK_DBG_ERROR, "Failed to open: %s", file); goto fail; mmd_import_fail: DEBUG(GLHCK_DBG_ERROR, "MMD importing failed."); goto fail; mmd_no_memory: DEBUG(GLHCK_DBG_ERROR, "MMD not enough memory."); fail: IFDO(fclose, f); IFDO(glhckAtlasFree, atlas); IFDO(mmd_free, mmd); IFDO(_glhckFree, textureList); IFDO(_glhckFree, vertexData); IFDO(_glhckFree, indices); IFDO(_glhckFree, stripIndices); RET(0, "%d", RETURN_FAIL); return RETURN_FAIL; }