diff --git a/src/animation.c b/src/animation.c index d54bb79..b789864 100644 --- a/src/animation.c +++ b/src/animation.c @@ -12,6 +12,7 @@ static Animation first, last; typedef struct _HeliTexture { const char *key; unsigned int id; + int own; int refcount; } HeliTexture; @@ -104,6 +105,37 @@ int imageLoad(const char *path, int *outWidth, int *outHeight, unsigned char **o } +int imageSave(const char *path, int width, int height, const void *pixels) { + #if SDL_BYTEORDER == SDL_BIG_ENDIAN + Uint32 rm = 0xff000000, + gm = 0x00ff0000, + bm = 0x0000ff00, + am = 0x000000ff; + #else + Uint32 rm = 0x000000ff, + gm = 0x0000ff00, + bm = 0x00ff0000, + am = 0xff000000; + #endif + + SDL_Surface *surface = SDL_CreateRGBSurfaceFrom(SDL_const_cast(void*, pixels), width, height, 32, width*4, rm, gm, bm, am); + + if (!surface) { + fprintf(stderr, "helianthus: cannot create SDL surface to save image: %s\n", SDL_GetError()); + return FALSE; + } + + if (IMG_SavePNG(surface, path) != 0) { + fprintf(stderr, "helianthus: cannot save image to file: %s, : %s\n", path, SDL_GetError()); + SDL_FreeSurface(surface); + return FALSE; + } + + SDL_FreeSurface(surface); + return TRUE; +} + + unsigned int imageToGLTexture(int width, int height, const void *pixels, int wrap) { return imageToGLTextureEx(width, height, pixels, wrap, wrap, TRUE, TRUE); } @@ -177,7 +209,8 @@ unsigned int imageToGLTextureEx(int width, int height, const void *pixels, int h while(h > maxSize) mipy(buffer, &w, &h); // create OpenGL texture - unsigned int texid = 0; + unsigned int texid = 0, prevtex = 0; + glGetIntegerv(GL_TEXTURE_BINDING_2D, (int*)&prevtex); glGenTextures(1, &texid); glBindTexture(GL_TEXTURE_2D, texid); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, smooth ? GL_LINEAR : GL_NEAREST); @@ -217,21 +250,47 @@ unsigned int imageToGLTextureEx(int width, int height, const void *pixels, int h // done free(ibuffer); free(buffer); - glBindTexture(GL_TEXTURE_2D, 0); + glBindTexture(GL_TEXTURE_2D, prevtex); return texid; } +int imageFromGLTexture(unsigned int texid, int *outWidth, int *outHeight, unsigned char **outPixels) { + *outWidth = *outHeight = 0; *outPixels = NULL; + + int w = 0, h = 0; + unsigned int prevtex = 0; + glGetIntegerv(GL_TEXTURE_BINDING_2D, (int*)&prevtex); + glBindTexture(GL_TEXTURE_2D, texid); + glGetTextureLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w); + glGetTextureLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &h); + if (w > 0 && h > 0) { + *outWidth = w; + *outHeight = h; + *outPixels = malloc(sizeof(**outPixels)*w*h*4); + glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, *outPixels); + } + glBindTexture(GL_TEXTURE_2D, prevtex); + + return outPixels != NULL; +} + static void unloadTexture(HeliTexture *texture) { assert(!texture->refcount); - glDeleteTextures(1, &texture->id); + if (texture->own && texture->id) { + unsigned int prevtex = 0; + glGetIntegerv(GL_TEXTURE_BINDING_2D, (int*)&prevtex); + if (prevtex == texture->id) glBindTexture(GL_TEXTURE_2D, 0); + glDeleteTextures(1, &texture->id); + } } static HeliTexture* loadTexture(const char *key) { HeliTexture *texture = calloc(1, sizeof(*texture)); texture->key = heliStringCopy(key); + texture->own = TRUE; if (key[0] == 'T') { texture->id = (unsigned int)atoll(key + 3); } else { @@ -318,6 +377,16 @@ Animation createAnimationFromGLTexId(unsigned int texid) { return animation; } +void animationGLTexIdSetOwnership(unsigned int texid, int own) { + char key[256] = "TTT"; + sprintf(key+3, "%d", texid); + HeliPair *item = heliStringmapGet(&cache, key); + if (item) { + HeliTexture *texture = (HeliTexture*)item->value; + texture->own = own != 0; + } +} + Animation createAnimation(const char *path) { return createAnimationEx(path, TRUE, FALSE, FALSE); } @@ -401,7 +470,6 @@ double animationGetFps(Animation animation) void animationSetFps(Animation animation, double fps) { animation->fps = !(fps > HELI_MIN_FPS) ? HELI_MIN_FPS : !(fps > HELI_MAX_FPS) ? HELI_MAX_FPS : fps; - } int animationIsPlaying(Animation animation) diff --git a/src/animation.h b/src/animation.h index 7280fec..c68f635 100644 --- a/src/animation.h +++ b/src/animation.h @@ -8,11 +8,10 @@ typedef struct _Animation *Animation; int imageLoad(const char *path, int *outWidth, int *outHeight, unsigned char **outPixels); -//int imageSave(const char *path, int width, int *height, const void *pixels); +int imageSave(const char *path, int width, int height, const void *pixels); unsigned int imageToGLTexture(int width, int height, const void *pixels, int wrap); unsigned int imageToGLTextureEx(int width, int height, const void *pixels, int horWrap, int vertWrap, int smooth, int mipMap); -//int imageFromGLTexture(unsigned int texid, int *outWidth, int *outHeight, unsigned char **outPixels); - +int imageFromGLTexture(unsigned int texid, int *outWidth, int *outHeight, unsigned char **outPixels); Animation createAnimation(const char *path); Animation createAnimationEx(const char *path, int smooth, int horWrap, int vertWrap); @@ -26,7 +25,7 @@ Animation animationClone(Animation animation); Animation animationCloneEx(Animation animation, int start, int count); unsigned int animationGetGLTexId(Animation animation); -//void animationGLTexIdSetOwnership(unsigned int texid, int own); +void animationGLTexIdSetOwnership(unsigned int texid, int own); int animationGetFramesCount(Animation animation); void animationInsert(Animation animation, int index, Animation other); diff --git a/src/font.c b/src/font.c index 369e755..40e3c68 100644 --- a/src/font.c +++ b/src/font.c @@ -94,6 +94,8 @@ static HeliFontMap* createFontMap() { for(int i = 0; i < FONT_MAP_FULLCNT; ++i) map->glyphs[i].map = map; + unsigned int prevtex = 0; + glGetIntegerv(GL_TEXTURE_BINDING_2D, (int*)&prevtex); glGenTextures(1, &map->texid); glBindTexture(GL_TEXTURE_2D, map->texid); @@ -113,7 +115,7 @@ static HeliFontMap* createFontMap() { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, maxLevel - 1); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, maxLevel - 1); - glBindTexture(GL_TEXTURE_2D, 0); + glBindTexture(GL_TEXTURE_2D, prevtex); return map; }