11#include "physfsrwops.h"
19#include "distance_field.h"
31typedef struct glTexList_ {
44static SDL_threadID tex_mainthread;
52static uint8_t
SDL_GetAlpha( SDL_Surface *s,
int x,
int y );
53static int SDL_IsTrans( SDL_Surface *s,
int x,
int y );
54static USE_RESULT uint8_t *
SDL_MapAlpha( SDL_Surface *s,
int tight );
55static size_t gl_transSize(
const int w,
const int h );
59 unsigned int flags,
int freesur,
64 SDL_RWops *rw,
int sx,
int sy,
70static int tex_cmp(
const void *p1,
const void *p2 );
72static void tex_ctxSet(
void )
74 if ( SDL_ThreadID() != tex_mainthread )
78static void tex_ctxUnset(
void )
80 if ( SDL_ThreadID() != tex_mainthread )
81 SDL_GL_MakeCurrent(
gl_screen.window, NULL );
84void gl_contextSet(
void )
90void gl_contextUnset(
void )
96static int tex_cmp(
const void *p1,
const void *p2 )
100 const unsigned int testflags = OPENGL_TEX_SDF | OPENGL_TEX_VFLIP |
101 OPENGL_TEX_MAPTRANS | OPENGL_TEX_NOTSRGB;
102 int ret = strcmp( t1->
path, t2->
path );
105 ret = t1->
sx - t2->
sx;
108 ret = t1->
sy - t2->
sy;
111 return ( t1->
flags & testflags ) - ( t2->
flags & testflags );
124 size_t bytes_per_pixel = s->format->BytesPerPixel;
129 SDL_LockSurface( s );
130 p = (Uint8 *)s->pixels + y * s->pitch + x * bytes_per_pixel;
131#if SDL_BYTEORDER == SDL_BIG_ENDIAN
132 SDL_memcpy( ( (Uint8 *)&pixel ) + (
sizeof( pixel ) - bytes_per_pixel ), p,
135 SDL_memcpy( &pixel, p, bytes_per_pixel );
137 SDL_GetRGBA( pixel, s->format, &r, &g, &b, &a );
138 SDL_UnlockSurface( s );
177 size_t size = gl_transSize( w, h );
180 WARN( _(
"Out of Memory" ) );
183 memset( t, 0, size );
186 for (
int i = 0; i < h; i++ )
187 for (
int j = 0; j < w;
189 t[( i * w + j ) / 8] |=
190 (
SDL_IsTrans( s, j, i ) ) ? 0 : ( 1 << ( ( i * w + j ) % 8 ) );
194 for (
int i = 0; i < h; i++ )
195 for (
int j = 0; j < w;
211static size_t gl_transSize(
const int w,
const int h )
214 return w * h / 8 + ( ( w * h % 8 ) ? 1 : 0 );
225 glGenTextures( 1, &texture );
226 glBindTexture( GL_TEXTURE_2D, texture );
230 if ( (
gl_screen.scale != 1. ) || ( flags & OPENGL_TEX_MIPMAPS ) ) {
231 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
232 if ( flags & OPENGL_TEX_MIPMAPS )
233 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
234 GL_LINEAR_MIPMAP_LINEAR );
236 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
238 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
239 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
243 if ( flags & OPENGL_TEX_CLAMP_ALPHA ) {
244 const float border[] = { 0., 0., 0., 0. };
245 glTexParameterfv( GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border );
246 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER );
247 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER );
249 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
250 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
268int gl_fboCreate( GLuint *fbo, GLuint *tex, GLsizei width, GLsizei height )
276 glGenTextures( 1, tex );
277 glBindTexture( GL_TEXTURE_2D, *tex );
278 glTexImage2D( GL_TEXTURE_2D, 0, GL_SRGB_ALPHA, width, height, 0, GL_RGBA,
279 GL_UNSIGNED_BYTE, NULL );
280 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
281 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
282 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER );
283 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER );
286 glGenFramebuffers( 1, fbo );
287 glBindFramebuffer( GL_FRAMEBUFFER, *fbo );
290 glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
294 status = glCheckFramebufferStatus( GL_FRAMEBUFFER );
295 if ( status != GL_FRAMEBUFFER_COMPLETE )
296 WARN( _(
"Error setting up framebuffer!" ) );
299 glBindTexture( GL_TEXTURE_2D, 0 );
300 glBindFramebuffer( GL_FRAMEBUFFER,
gl_screen.current_fbo );
307 return ( status == GL_FRAMEBUFFER_COMPLETE );
321 glGenTextures( 1, tex );
322 glBindTexture( GL_TEXTURE_2D, *tex );
323 glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width, height, 0,
324 GL_DEPTH_COMPONENT, GL_FLOAT, NULL );
325 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
326 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
327 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER );
328 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER );
331 glBindFramebuffer( GL_FRAMEBUFFER, fbo );
332 glFramebufferTexture2D( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
336 status = glCheckFramebufferStatus( GL_FRAMEBUFFER );
337 if ( status != GL_FRAMEBUFFER_COMPLETE )
338 WARN( _(
"Error attaching depth to framebuffer!" ) );
341 glBindTexture( GL_TEXTURE_2D, 0 );
342 glBindFramebuffer( GL_FRAMEBUFFER,
gl_screen.current_fbo );
349 return ( status == GL_FRAMEBUFFER_COMPLETE );
352glTexture *gl_loadImageData(
float *data,
int w,
int h,
int sx,
int sy,
358 texture->w = (double)w;
359 texture->h = (double)h;
360 texture->sx = (double)sx;
361 texture->sy = (double)sy;
368 glTexImage2D( GL_TEXTURE_2D, 0, GL_SRGB_ALPHA, w, h, 0, GL_RGBA, GL_FLOAT,
370 glBindTexture( GL_TEXTURE_2D, 0 );
377 texture->sw = texture->w / texture->sx;
378 texture->sh = texture->h / texture->sy;
379 texture->srw = texture->sw / texture->w;
380 texture->srh = texture->sh / texture->h;
383 if ( name != NULL ) {
384 texture->name = strdup( name );
386 gl_texAdd( texture, sx, sy, OPENGL_TEX_SKIPCACHE );
403 int freesur,
double *vmax )
405 const SDL_PixelFormatEnum fmt = SDL_PIXELFORMAT_ABGR8888;
408 int has_alpha = surface->format->Amask;
417 if ( surface->format->format != fmt )
418 rgba = SDL_ConvertSurfaceFormat( surface, fmt, 0 );
422 SDL_LockSurface( rgba );
423 if ( flags & OPENGL_TEX_SDF ) {
424 const float border[] = { 0., 0., 0., 0. };
428 glTexParameterfv( GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border );
429 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER );
430 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER );
431 glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
432 glTexImage2D( GL_TEXTURE_2D, 0, GL_RED, rgba->w, rgba->h, 0, GL_RED,
434 glPixelStorei( GL_UNPACK_ALIGNMENT, 4 );
437 GLint internalformat;
438 if ( flags & OPENGL_TEX_NOTSRGB )
439 internalformat = has_alpha ? GL_RGBA : GL_RGB;
441 internalformat = has_alpha ? GL_SRGB_ALPHA : GL_SRGB;
444 glPixelStorei( GL_UNPACK_ALIGNMENT,
445 MIN( rgba->pitch & -rgba->pitch, 8 ) );
446 glTexImage2D( GL_TEXTURE_2D, 0, internalformat, rgba->w, rgba->h, 0,
447 GL_RGBA, GL_UNSIGNED_BYTE, rgba->pixels );
448 glPixelStorei( GL_UNPACK_ALIGNMENT, 4 );
450 SDL_UnlockSurface( rgba );
451 if ( rgba != surface )
452 SDL_FreeSurface( rgba );
455 if ( flags & OPENGL_TEX_MIPMAPS ) {
457 if ( GLAD_GL_ARB_texture_filter_anisotropic ) {
459 glGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY, ¶m );
460 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY, param );
464 glGenerateMipmap( GL_TEXTURE_2D );
468 glBindTexture( GL_TEXTURE_2D, 0 );
472 SDL_FreeSurface( surface );
487 tex->
name = strdup( path );
488 tex->
sx = (double)sx;
489 tex->
sy = (double)sy;
509 unsigned int flags,
int sx,
int sy,
516 if ( ( path == NULL ) || ( flags & OPENGL_TEX_SKIPCACHE ) ) {
522 realdir = PHYSFS_getRealDir( path );
523 snprintf( buf,
sizeof( buf ),
"%s/%s", realdir ? realdir :
"[NULL]", path );
535 const glTexList q = { .path = buf, .sx = sx, .sy = sy, .flags = flags };
570 new->path = tex->
name;
612 const unsigned int flags )
639 if ( path == NULL ) {
640 WARN( _(
"Trying to load image from NULL path." ) );
645 rw = PHYSFSRWOPS_openRead( path );
647 WARN( _(
"Failed to load surface '%s' from ndata." ), path );
669 SDL_RWops *rw,
int sx,
int sy,
672 SDL_Surface *surface;
675 if ( path == NULL ) {
676 path = _(
"unknown" );
677 flags |= OPENGL_TEX_SKIPCACHE;
680 surface = IMG_Load_RW( rw, 0 );
682 flags |= OPENGL_TEX_VFLIP;
683 if ( surface == NULL ) {
684 WARN( _(
"'%s' could not be opened" ), path );
689 if ( flags & OPENGL_TEX_MAPTRANS ) {
690 size_t pngsize, filesize, cachesize;
693 char *cachefile = NULL;
694 uint8_t *trans = NULL;
695 md5_byte_t *md5val = malloc( 16 );
700 cachesize = gl_transSize( surface->w, surface->h );
703 pngsize = SDL_RWseek( rw, 0, SEEK_END );
704 SDL_RWseek( rw, 0, SEEK_SET );
706 data = malloc( pngsize );
708 WARN( _(
"Out of Memory" ) );
710 SDL_RWread( rw, data, pngsize, 1 );
711 md5_append( &md5, (md5_byte_t *)data, pngsize );
714 md5_finish( &md5, md5val );
716 for (
int i = 0; i < 16; i++ )
717 snprintf( &digest[i * 2], 3,
"%02x", md5val[i] );
720 SDL_asprintf( &cachefile,
"%scollisions/%s",
nfile_cachePath(), digest );
727 if ( trans != NULL && cachesize != (
unsigned int)filesize ) {
738 if ( trans == NULL ) {
739 SDL_LockSurface( surface );
741 SDL_UnlockSurface( surface );
743 if ( cachefile != NULL ) {
758 tex->
w = (double)surface->w;
759 tex->
h = (double)surface->h;
760 tex->
sx = (double)sx;
761 tex->
sy = (double)sy;
765 tex->
sw = tex->
w / tex->
sx;
766 tex->
sh = tex->
h / tex->
sy;
767 tex->
srw = tex->
sw / tex->
w;
768 tex->
srh = tex->
sh / tex->
h;
772 SDL_FreeSurface( surface );
786 const unsigned int flags )
809 const int sy,
const unsigned int flags )
823 t->
sw = t->
w / t->
sx;
824 t->
sh = t->
h / t->
sy;
837 if ( texture == NULL )
846 if ( cur->
tex != texture )
851 if ( cur->
used <= 0 ) {
853 glDeleteTextures( 1, &texture->texture );
854 free( texture->trans );
855 free( texture->name );
866 if ( texture->name != NULL )
867 WARN( _(
"Attempting to free texture '%s' not found in stack!" ),
874 glDeleteTextures( 1, &texture->texture );
875 free( texture->trans );
876 free( texture->name );
894 if ( texture == NULL )
901 if ( texture == cur->
tex ) {
910 WARN( _(
"Unable to duplicate texture '%s'." ), texture->name );
923 texture = calloc( 1,
sizeof(
glTexture ) );
925 texture->w = (double)w;
926 texture->h = (double)h;
927 texture->sx = (double)1.;
928 texture->sy = (double)1.;
930 texture->texture = texid;
932 texture->sw = texture->w / texture->sx;
933 texture->sh = texture->h / texture->sy;
934 texture->srw = texture->sw / texture->w;
935 texture->srh = texture->sh / texture->h;
938 if ( name != NULL ) {
939 texture->name = strdup( name );
941 gl_texAdd( texture, 1, 1, OPENGL_TEX_SKIPCACHE );
944 texture->name = NULL;
960 int i = y * (int)( t->
w ) + x;
962 return !( t->
trans[i / 8] & ( 1 << ( i % 8 ) ) );
983 if ( ( dir > 2. * M_PI ) || ( dir < 0. ) ) {
984 WARN( _(
"Angle not between 0 and 2.*M_PI [%f]." ), dir );
991 shard = 2. * M_PI / ( sy * sx );
994 rdir = dir + shard / 2.;
997 s = (int)( rdir / shard );
1000 if ( s > ( sy * sx - 1 ) )
1001 s = s % ( sy * sx );
1016 tex_mainthread = SDL_ThreadID();
1035 DEBUG( _(
"Texture leak detected!" ) );
1039 n_(
" '%s' opened %d time",
" '%s' opened %d times", cur->
used ),
1059 for (
int i = 0; i <
array_size( tex ); i++ )
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.
static int gl_loadNewImageRWops(glTexture *tex, const char *path, SDL_RWops *rw, int sx, int sy, unsigned int flags)
The heavy loading image backend image function. It loads images and does transparency mapping if nece...
glTexture * gl_dupTexture(const glTexture *texture)
Duplicates a texture.
USE_RESULT glTexture * gl_texExistsOrCreate(const char *path, unsigned int flags, int sx, int sy, int *created)
Check to see if a texture matching a path already exists.
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.
static int gl_loadNewImage(glTexture *tex, const char *path, int sx, int sy, unsigned int flags)
Only loads the image, does not add to stack unlike gl_newImage.
void gl_exitTextures(void)
Cleans up the opengl texture subsystem.
glTexture * gl_newImageRWops(const char *path, SDL_RWops *rw, const unsigned int flags)
Loads an image as a texture.
USE_RESULT glTexture * gl_rawTexture(const char *name, GLuint texid, double w, double h)
Creates a texture from a raw opengl index.
int gl_fboCreate(GLuint *fbo, GLuint *tex, GLsizei width, GLsizei height)
Creates a framebuffer and its associated texture.
static int gl_texAdd(glTexture *tex, int sx, int sy, unsigned int flags)
Adds a texture to the list under the name of path.
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 glTexture * gl_texCreate(const char *path, int sx, int sy, unsigned int flags)
Creates a new texture.
static USE_RESULT 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 int SDL_IsTrans(SDL_Surface *s, int x, int y)
Checks to see if a position of the surface is transparent.
static USE_RESULT uint8_t * SDL_MapAlpha(SDL_Surface *s, int tight)
Maps the surface transparency.
glTexture ** gl_copyTexArray(glTexture **tex)
Copy a texture array.
glTexture * gl_newImage(const char *path, const unsigned int flags)
Loads an image as a texture.
int gl_fboAddDepth(GLuint fbo, GLuint *tex, GLsizei width, GLsizei height)
Adds a depth attachment to an FBO.
static SDL_mutex * gl_lock
static uint8_t SDL_GetAlpha(SDL_Surface *s, int x, int y)
Gets the alpha value of a pixel.
static SDL_mutex * tex_lock
static USE_RESULT GLuint gl_texParameters(unsigned int flags)
Sets default texture parameters.
void gl_getSpriteFromDir(int *x, int *y, int sx, int sy, double dir)
Sets x and y to be the appropriate sprite for glTexture using dir.
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.