Esempio n. 1
0
/* \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;
}
Esempio n. 2
0
static void _pndman_device_memory_free(pndman_device *device)
{
   IFDO(free, device->mount);
   IFDO(free, device->device);
   IFDO(free, device->appdata);
   free(device);
}
Esempio n. 3
0
/* \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;
}
Esempio n. 4
0
/* \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;
}
Esempio n. 5
0
/* \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;
}
Esempio n. 6
0
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;
}
Esempio n. 7
0
/* \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;
}
Esempio n. 8
0
/* \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;
}
Esempio n. 9
0
/* \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;
}
Esempio n. 10
0
/* \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;
}
Esempio n. 11
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;
}
Esempio n. 12
0
/* \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;
}
Esempio n. 13
0
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);
   }
}
Esempio n. 14
0
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);
   }
}
Esempio n. 15
0
/* 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;
}
Esempio n. 16
0
/* \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;
}
Esempio n. 17
0
/* \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;
}
Esempio n. 18
0
/* \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);
}
Esempio n. 19
0
/* \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;
}
Esempio n. 20
0
/* \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);
}
Esempio n. 21
0
/* \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;
}
Esempio n. 22
0
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;
}
Esempio n. 23
0
/* \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
}
Esempio n. 24
0
/* \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;
}
Esempio n. 25
0
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;
}
Esempio n. 26
0
/* \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;
}
Esempio n. 27
0
static void _pndman_device_set_appdata(pndman_device *device, const char *appdata)
{
   assert(device);
   IFDO(free, device->appdata);
   if (appdata) device->appdata = strdup(appdata);
}
Esempio n. 28
0
/* \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;
}