/* \brief initialize */ GLHCKAPI glhckContext* glhckContextCreate(int argc, char **argv) { glhckContext *ctx, *oldCtx; #ifndef _GLHCK_TLS_FOUND fprintf(stderr, "-!- Thread-local storage support in compiler was not detected.\n"); fprintf(stderr, "-!- Using multiple glhck contextes in different threads may cause unexpected behaviour.\n"); fprintf(stderr, "-!- If your compiler supports TLS, file a bug report!\n"); #endif /* allocate glhck context */ if (!(ctx = calloc(1, sizeof(glhckContext)))) return NULL; /* swap current context until init done */ oldCtx = glhckContextGet(); glhckContextSet(ctx); /* enable color by default */ glhckLogColor(1); /* FIXME: change the signal calls in these functions to sigaction's */ #ifndef NDEBUG /* set FPE handler */ _glhckSetupFPE(); /* setup backtrace handler * make this optional.. */ _glhckSetBacktrace(); #endif #if !GLHCK_DISABLE_TRACE /* init trace system */ _glhckTraceInit(argc, (const char**)argv); #endif /* setup internal vertex/index types */ _glhckGeometryInit(); /* set default global precision for glhck to use with geometry * NOTE: _NONE means that glhck and importers choose the best precision. */ glhckSetGlobalPrecision(GLHCK_IDX_AUTO, GLHCK_IDX_AUTO); /* pre-allocate render queues */ GLHCKRD()->objects.queue = _glhckMalloc(GLHCK_QUEUE_ALLOC_STEP * sizeof(_glhckObject*)); GLHCKRD()->objects.allocated += GLHCK_QUEUE_ALLOC_STEP; GLHCKRD()->textures.queue = _glhckMalloc(GLHCK_QUEUE_ALLOC_STEP * sizeof(_glhckTexture*)); GLHCKRD()->textures.allocated += GLHCK_QUEUE_ALLOC_STEP; /* switch back to old context, if there was one */ if (oldCtx) glhckContextSet(oldCtx); return ctx; }
/* \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 push current render state to stack */ GLHCKAPI void glhckRenderStatePush(void) { __GLHCKrenderState *state; GLHCK_INITIALIZED(); TRACE(2); if (!(state = _glhckMalloc(sizeof(__GLHCKrenderState)))) return; memcpy(&state->pass, &GLHCKR()->pass, sizeof(__GLHCKrenderPass)); memcpy(&state->view, &GLHCKRD()->view, sizeof(__GLHCKrenderView)); state->width = GLHCKR()->width; state->height = GLHCKR()->height; state->next = GLHCKR()->stack; GLHCKR()->stack = state; }
/* \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; }
/* \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 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; }
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; }