12#include "physfsrwops.h"
18#include "distance_field.h"
34typedef struct glTexList_ {
46static SDL_threadID tex_mainthread;
47static SDL_mutex* tex_lock = NULL;
53static uint8_t
SDL_GetAlpha( SDL_Surface* s,
int x,
int y );
54static int SDL_IsTrans( SDL_Surface* s,
int x,
int y );
55static uint8_t*
SDL_MapAlpha( SDL_Surface* s,
int w,
int h,
int tight );
56static size_t gl_transSize(
const int w,
const int h );
59static GLuint
gl_loadSurface( SDL_Surface* surface,
unsigned int flags,
int freesur,
double *vmax );
65static int tex_cmp(
const void *p1,
const void *p2 );
67static void tex_ctxSet (
void)
69 if (SDL_ThreadID() != tex_mainthread)
73static void tex_ctxUnset (
void)
75 if (SDL_ThreadID() != tex_mainthread)
79void gl_contextSet (
void)
81 SDL_mutexP( tex_lock );
85void gl_contextUnset (
void)
88 SDL_mutexV( tex_lock );
91static int tex_cmp(
const void *p1,
const void *p2 )
95 int ret = strcmp( t1->
path, t2->
path );
98 ret = t1->
sx - t2->
sx;
101 return t1->
sy - t2->
sy;
114 size_t bytes_per_pixel = s->format->BytesPerPixel;
120 p = (Uint8 *)s->pixels + y * s->pitch + x * bytes_per_pixel;
121#if SDL_BYTEORDER == SDL_BIG_ENDIAN
122 SDL_memcpy(((Uint8 *) &pixel) + (
sizeof(pixel) - bytes_per_pixel), p, bytes_per_pixel);
124 SDL_memcpy(&pixel, p, bytes_per_pixel);
126 SDL_GetRGBA(pixel, s->format, &r, &g, &b, &a);
127 SDL_UnlockSurface(s);
171 size_t size = gl_transSize(w, h);
174 WARN(_(
"Out of Memory"));
180 for (
int i=0; i<h; i++)
181 for (
int j=0; j<w; j++)
182 t[(i*w+j)/8] |= (
SDL_IsTrans(s,j,i)) ? 0 : (1<<((i*w+j)%8));
187 for (
int i=0; i<h; i++)
188 for (
int j=0; j<w; j++)
202static size_t gl_transSize(
const int w,
const int h )
205 return w*h/8 + ((w*h%8)?1:0);
216 glGenTextures( 1, &texture );
217 glBindTexture( GL_TEXTURE_2D, texture );
222 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
223 if (flags & OPENGL_TEX_MIPMAPS)
224 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
226 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
229 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
230 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
234 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
235 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
252int gl_fboCreate( GLuint *fbo, GLuint *tex, GLsizei width, GLsizei height )
256 SDL_mutexP( tex_lock );
260 glGenTextures(1, tex);
261 glBindTexture(GL_TEXTURE_2D, *tex);
262 glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB_ALPHA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
263 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
264 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
265 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
266 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
267 glBindTexture(GL_TEXTURE_2D, 0);
270 glGenFramebuffers( 1, fbo );
271 glBindFramebuffer(GL_FRAMEBUFFER, *fbo);
274 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, *tex, 0);
277 status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
278 if (status != GL_FRAMEBUFFER_COMPLETE)
279 WARN(_(
"Error setting up framebuffer!"));
285 SDL_mutexV( tex_lock );
289 return (status==GL_FRAMEBUFFER_COMPLETE);
292glTexture* gl_loadImageData(
float *data,
int w,
int h,
int sx,
int sy,
const char* name )
294 SDL_mutexP( tex_lock );
300 texture->w = (double) w;
301 texture->h = (double) h;
302 texture->sx = (double) sx;
303 texture->sy = (double) sy;
309 glTexImage2D( GL_TEXTURE_2D, 0, GL_SRGB_ALPHA, w, h, 0, GL_RGBA, GL_FLOAT, data );
310 glBindTexture( GL_TEXTURE_2D, 0 );
316 texture->sw = texture->w / texture->sx;
317 texture->sh = texture->h / texture->sy;
318 texture->srw = texture->sw / texture->w;
319 texture->srh = texture->sh / texture->h;
323 texture->name = strdup(name);
328 SDL_mutexV( tex_lock );
342static GLuint
gl_loadSurface( SDL_Surface* surface,
unsigned int flags,
int freesur,
double *vmax )
346 SDL_PixelFormatEnum fmt = SDL_PIXELFORMAT_ABGR8888;
348 SDL_mutexP( tex_lock );
356 if (surface->format->format != fmt)
357 rgba = SDL_ConvertSurfaceFormat( surface, fmt, 0 );
361 SDL_LockSurface(rgba);
362 if (flags & OPENGL_TEX_SDF) {
363 float border[] = { 0., 0., 0., 0. };
364 uint8_t *trans =
SDL_MapAlpha( rgba, rgba->w, rgba->h, 0 );
367 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border);
368 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
369 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
370 glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
371 glTexImage2D( GL_TEXTURE_2D, 0, GL_RED, rgba->w, rgba->h, 0, GL_RED, GL_FLOAT, dataf );
372 glPixelStorei( GL_UNPACK_ALIGNMENT, 4 );
377 glPixelStorei( GL_UNPACK_ALIGNMENT,
MIN( rgba->pitch&-rgba->pitch, 8 ) );
378 glTexImage2D( GL_TEXTURE_2D, 0, GL_SRGB_ALPHA,
379 rgba->w, rgba->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgba->pixels );
380 glPixelStorei( GL_UNPACK_ALIGNMENT, 4 );
382 SDL_UnlockSurface(rgba);
384 SDL_FreeSurface(rgba);
387 if (flags & OPENGL_TEX_MIPMAPS) {
389 if (GLAD_GL_ARB_texture_filter_anisotropic) {
391 glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY, ¶m);
392 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY, param);
396 glGenerateMipmap(GL_TEXTURE_2D);
400 glBindTexture(GL_TEXTURE_2D, 0);
404 SDL_FreeSurface( surface );
408 SDL_mutexV( tex_lock );
428 unsigned int flags,
int w,
int h,
int sx,
int sy,
int freesur )
431 size_t filesize, cachesize;
436 SDL_mutexP( tex_lock );
438 if ((name != NULL) && !(flags & OPENGL_TEX_SKIPCACHE)) {
440 if ((texture != NULL) && (texture->trans != NULL)) {
442 SDL_FreeSurface( surface );
443 SDL_mutexV( tex_lock );
448 if (flags & OPENGL_TEX_MAPTRANS)
449 flags ^= OPENGL_TEX_MAPTRANS;
452 cachesize = gl_transSize(w, h);
461 md5_byte_t *md5val = malloc(16);
464 pngsize = SDL_RWseek( rw, 0, SEEK_END );
465 SDL_RWseek( rw, 0, SEEK_SET );
467 data = malloc(pngsize);
469 WARN(_(
"Out of Memory"));
471 SDL_RWread( rw, data, pngsize, 1 );
472 md5_append( &md5, (md5_byte_t*)data, pngsize );
475 md5_finish( &md5, md5val );
477 for (
int i=0; i<16; i++)
478 snprintf( &digest[i * 2], 3,
"%02x", md5val[i] );
481 SDL_asprintf( &cachefile,
"%scollisions/%s",
489 if (trans != NULL && cachesize != (
unsigned int)filesize) {
503 WARN(_(
"Texture '%s' has no RWops"), name);
507 SDL_LockSurface(surface);
509 SDL_UnlockSurface(surface);
511 if (cachefile != NULL) {
514 snprintf( dirpath,
sizeof(dirpath),
"%s/%s",
nfile_cachePath(),
"collisions/" );
522 texture =
gl_loadImagePad( name, surface, flags, w, h, sx, sy, freesur );
524 SDL_FreeSurface( surface );
525 texture->trans = trans;
526 SDL_mutexV( tex_lock );
544 unsigned int flags,
int w,
int h,
int sx,
int sy,
int freesur )
547 SDL_mutexP( tex_lock );
550 if ((name != NULL) && !(flags & OPENGL_TEX_SKIPCACHE)) {
552 if (texture != NULL) {
553 SDL_mutexV( tex_lock );
558 if (flags & OPENGL_TEX_MAPTRANS) {
561 SDL_mutexV( tex_lock );
566 texture = calloc( 1,
sizeof(
glTexture) );
568 texture->w = (double) w;
569 texture->h = (double) h;
570 texture->sx = (double) sx;
571 texture->sy = (double) sy;
573 texture->texture =
gl_loadSurface( surface, flags, freesur, &texture->vmax );
575 texture->sw = texture->w / texture->sx;
576 texture->sh = texture->h / texture->sy;
577 texture->srw = texture->sw / texture->w;
578 texture->srh = texture->sh / texture->h;
579 texture->flags = flags;
582 texture->name = strdup(name);
586 texture->name = NULL;
588 SDL_mutexV( tex_lock );
601 return gl_loadImagePad( NULL, surface, flags, surface->w, surface->h, 1, 1, 1 );
620 SDL_mutexP( tex_lock );
624 SDL_mutexV( tex_lock );
629 const glTexList q = { .path=path, .sx=sx, .sy=sy };
632 SDL_mutexV( tex_lock );
638 SDL_mutexV( tex_lock );
659 new->path = tex->
name;
678 if (!(flags & OPENGL_TEX_SKIPCACHE)) {
703 if (!(flags & OPENGL_TEX_SKIPCACHE)) {
726 WARN(_(
"Trying to load image from NULL path."));
731 rw = PHYSFSRWOPS_openRead( path );
733 WARN(_(
"Failed to load surface '%s' from ndata."), path);
753 SDL_Surface *surface;
760 surface = IMG_Load_RW( rw, 0 );
762 flags |= OPENGL_TEX_VFLIP;
763 if (surface == NULL) {
764 WARN(_(
"Unable to load image '%s'."), path );
768 if (surface == NULL) {
769 WARN(_(
"'%s' could not be opened"), path );
773 SDL_mutexP( tex_lock );
774 if (flags & OPENGL_TEX_MAPTRANS)
777 tex =
gl_loadImagePad( path, surface, flags, surface->w, surface->h, 1, 1, 1 );
778 SDL_mutexV( tex_lock );
792 const unsigned int flags )
797 if (!(flags & OPENGL_TEX_SKIPCACHE)) {
804 texture =
gl_newImage( path, flags | OPENGL_TEX_SKIPCACHE );
810 texture->sx = (double) sx;
811 texture->sy = (double) sy;
812 texture->sw = texture->w / texture->sx;
813 texture->sh = texture->h / texture->sy;
814 texture->srw = texture->sw / texture->w;
815 texture->srh = texture->sh / texture->h;
830 const int sx,
const int sy,
const unsigned int flags )
835 if (!(flags & OPENGL_TEX_SKIPCACHE)) {
848 texture->sx = (double) sx;
849 texture->sy = (double) sy;
850 texture->sw = texture->w / texture->sx;
851 texture->sh = texture->h / texture->sy;
852 texture->srw = texture->sw / texture->w;
853 texture->srh = texture->sh / texture->h;
867 SDL_mutexP( tex_lock );
873 if (cur->
tex!=texture)
878 if (cur->
used <= 0) {
880 glDeleteTextures( 1, &texture->texture );
881 free(texture->trans);
888 SDL_mutexV( tex_lock );
893 if (texture->name != NULL)
894 WARN(_(
"Attempting to free texture '%s' not found in stack!"), texture->name);
900 glDeleteTextures( 1, &texture->texture );
901 free(texture->trans);
908 SDL_mutexV( tex_lock );
924 SDL_mutexP( tex_lock );
927 if (texture == cur->
tex) {
929 SDL_mutexV( tex_lock );
933 SDL_mutexV( tex_lock );
936 WARN(_(
"Unable to duplicate texture '%s'."), texture->name);
951 int i = y*(int)(t->
w) + x ;
953 return !(t->
trans[ i/8 ] & (1 << (i%8)));
973 if ((dir > 2.*M_PI) || (dir < 0.)) {
974 WARN(_(
"Angle not between 0 and 2.*M_PI [%f]."), dir);
981 shard = 2.*M_PI / (t->
sy*t->
sx);
984 rdir = dir + shard/2.;
987 s = (int)(rdir / shard);
1006 tex_lock = SDL_CreateMutex();
1007 tex_mainthread = SDL_ThreadID();
1023 DEBUG(_(
"Texture leak detected!"));
1026 DEBUG( n_(
" '%s' opened %d time",
" '%s' opened %d times", cur->
used ), cur->
tex->
name, cur->
used );
1032 SDL_DestroyMutex( tex_lock );
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
#define array_create_size(basic_type, capacity)
Creates a new dynamic array of ‘basic_type’ with an initial capacity.
#define array_erase(ptr_array, first, last)
Erases elements in interval [first, last).
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
#define array_grow(ptr_array)
Increases the number of elements by one and returns the last element.
#define array_push_back(ptr_array, element)
Adds a new element at the end of the array.
#define array_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
float * make_distance_mapbf(unsigned char *img, unsigned int width, unsigned int height, double *vmax)
Perform a Euclidean Distance Transform on the input and normalize to [0,1], with a value of 0....
Header file with generic functions and naev-specifics.
int nfile_writeFile(const char *data, size_t len, const char *path)
Tries to write a file.
char * nfile_readFile(size_t *filesize, const char *path)
Tries to read a file.
int nfile_dirMakeExist(const char *path)
Creates a directory if it doesn't exist.
const char * nfile_cachePath(void)
Gets Naev's cache path (for cached data such as generated textures)
int nfile_fileExists(const char *path)
Checks to see if a file exists.
glTexture * gl_dupTexture(const glTexture *texture)
Duplicates a texture.
glTexture * gl_newSprite(const char *path, const int sx, const int sy, const unsigned int flags)
Loads the texture immediately, but also sets it as a sprite.
void gl_exitTextures(void)
Cleans up the opengl texture subsystem.
static uint8_t * SDL_MapAlpha(SDL_Surface *s, int w, int h, int tight)
Maps the surface transparency.
glTexture * gl_newImageRWops(const char *path, SDL_RWops *rw, const unsigned int flags)
Loads an image as a texture.
int gl_fboCreate(GLuint *fbo, GLuint *tex, GLsizei width, GLsizei height)
Creates a framebuffer and its associated texture.
static glTexture * gl_texExists(const char *path, int sx, int sy)
Check to see if a texture matching a path already exists.
glTexture * gl_loadImage(SDL_Surface *surface, unsigned int flags)
Loads the SDL_Surface to a glTexture.
glTexture * gl_newSpriteRWops(const char *path, SDL_RWops *rw, const int sx, const int sy, const unsigned int flags)
Loads the texture immediately, but also sets it as a sprite.
static GLuint gl_loadSurface(SDL_Surface *surface, unsigned int flags, int freesur, double *vmax)
Loads a surface into an opengl texture.
glTexture ** gl_addTexArray(glTexture **tex, glTexture *t)
Adds an element to a texture array.
int gl_isTrans(const glTexture *t, const int x, const int y)
Checks to see if a pixel is transparent in a texture.
static glTexture * gl_loadNewImage(const char *path, unsigned int flags)
Only loads the image, does not add to stack unlike gl_newImage.
static int SDL_IsTrans(SDL_Surface *s, int x, int y)
Checks to see if a position of the surface is transparent.
glTexture ** gl_copyTexArray(glTexture **tex)
Copy a texture array.
static int gl_texAdd(glTexture *tex, int sx, int sy)
Adds a texture to the list under the name of path.
glTexture * gl_loadImagePad(const char *name, SDL_Surface *surface, unsigned int flags, int w, int h, int sx, int sy, int freesur)
Loads the already padded SDL_Surface to a glTexture.
glTexture * gl_loadImagePadTrans(const char *name, SDL_Surface *surface, SDL_RWops *rw, unsigned int flags, int w, int h, int sx, int sy, int freesur)
Wrapper for gl_loadImagePad that includes transparency mapping.
glTexture * gl_newImage(const char *path, const unsigned int flags)
Loads an image as a texture.
static uint8_t SDL_GetAlpha(SDL_Surface *s, int x, int y)
Gets the alpha value of a pixel.
void gl_getSpriteFromDir(int *x, int *y, const glTexture *t, const double dir)
Sets x and y to be the appropriate sprite for glTexture using dir.
static glTexture * gl_loadNewImageRWops(const char *path, SDL_RWops *rw, unsigned int flags)
Only loads the image, does not add to stack unlike gl_newImage.
static GLuint gl_texParameters(unsigned int flags)
Sets default texture parameters.
static glTexList * texture_list
void gl_freeTexture(glTexture *texture)
Frees a texture.
int gl_initTextures(void)
Initializes the opengl texture subsystem.
Represents a node in the texture list.
Abstraction for rendering sprite sheets.
Define the state of the MD5 Algorithm.