naev 0.11.5
opengl_tex.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
10#include <stdio.h>
11#include <stdlib.h>
12#include "physfsrwops.h"
13#include "SDL_image.h"
14
15#include "naev.h"
18#include "distance_field.h"
19#include "array.h"
20#include "conf.h"
21#include "gui.h"
22#include "log.h"
23#include "md5.h"
24#include "nfile.h"
25#include "nstring.h"
26#include "opengl.h"
27
28/*
29 * graphic list
30 */
34typedef struct glTexList_ {
36 const char *path;
37 int used;
38 /* TODO We currently treat images with different number of sprites as
39 * different images, i.e., they get reloaded and use more memory. However,
40 * it should be possible to do something fancier and share the texture to
41 * avoid this increase of memory (without sharing other parameters). */
42 int sx;
43 int sy;
44} glTexList;
45static glTexList* texture_list = NULL;
46static SDL_threadID tex_mainthread;
47static SDL_mutex* tex_lock = NULL;
48
49/*
50 * prototypes
51 */
52/* misc */
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 );
57/* glTexture */
58static GLuint gl_texParameters( unsigned int flags );
59static GLuint gl_loadSurface( SDL_Surface* surface, unsigned int flags, int freesur, double *vmax );
60static glTexture* gl_loadNewImage( const char* path, unsigned int flags );
61static glTexture* gl_loadNewImageRWops( const char *path, SDL_RWops *rw, unsigned int flags );
62/* List. */
63static glTexture* gl_texExists( const char* path, int sx, int sy );
64static int gl_texAdd( glTexture *tex, int sx, int sy );
65static int tex_cmp( const void *p1, const void *p2 );
66
67static void tex_ctxSet (void)
68{
69 if (SDL_ThreadID() != tex_mainthread)
70 SDL_GL_MakeCurrent( gl_screen.window, gl_screen.context );
71}
72
73static void tex_ctxUnset (void)
74{
75 if (SDL_ThreadID() != tex_mainthread)
76 SDL_GL_MakeCurrent( gl_screen.window, NULL );
77}
78
79void gl_contextSet (void)
80{
81 SDL_mutexP( tex_lock );
82 tex_ctxSet();
83}
84
85void gl_contextUnset (void)
86{
87 tex_ctxUnset();
88 SDL_mutexV( tex_lock );
89}
90
91static int tex_cmp( const void *p1, const void *p2 )
92{
93 const glTexList *t1 = (const glTexList*) p1;
94 const glTexList *t2 = (const glTexList*) p2;
95 int ret = strcmp( t1->path, t2->path );
96 if (ret != 0)
97 return ret;
98 ret = t1->sx - t2->sx;
99 if (ret != 0)
100 return ret;
101 return t1->sy - t2->sy;
102}
103
112static uint8_t SDL_GetAlpha( SDL_Surface* s, int x, int y )
113{
114 size_t bytes_per_pixel = s->format->BytesPerPixel;
115 void *p;
116 Uint32 pixel;
117 Uint8 r, g, b, a;
118
119 SDL_LockSurface(s);
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);
123#else /* SDL_BYTEORDER == SDL_BIG_ENDIAN */
124 SDL_memcpy(&pixel, p, bytes_per_pixel);
125#endif /* SDL_BYTEORDER == SDL_BIG_ENDIAN */
126 SDL_GetRGBA(pixel, s->format, &r, &g, &b, &a);
127 SDL_UnlockSurface(s);
128 return a;
129}
130
139static int SDL_IsTrans( SDL_Surface* s, int x, int y )
140{
141 uint8_t a = SDL_GetAlpha( s, x, y );
142 /* Test whether pixels colour == colour of transparent pixels for that surface */
143
144 return a > 127;
145}
146
159static uint8_t* SDL_MapAlpha( SDL_Surface* s, int w, int h, int tight )
160{
161 uint8_t *t;
162
163 /* Get limit.s */
164 if (w < 0)
165 w = s->w;
166 if (h < 0)
167 h = s->h;
168
169 if (tight) {
170 /* alloc memory for just enough bits to hold all the data we need */
171 size_t size = gl_transSize(w, h);
172 t = malloc(size);
173 if (t==NULL) {
174 WARN(_("Out of Memory"));
175 return NULL;
176 }
177 memset(t, 0, size); /* important, must be set to zero */
178
179 /* Check each pixel individually. */
180 for (int i=0; i<h; i++)
181 for (int j=0; j<w; j++) /* sets each bit to be 1 if not transparent or 0 if is */
182 t[(i*w+j)/8] |= (SDL_IsTrans(s,j,i)) ? 0 : (1<<((i*w+j)%8));
183 }
184 else {
185 t = malloc( w*h );
186 /* Check each pixel individually. */
187 for (int i=0; i<h; i++)
188 for (int j=0; j<w; j++) /* sets each bit to be 1 if not transparent or 0 if is */
189 t[i*w+j] = SDL_GetAlpha(s,j,i); /* Flipped with tight version, this is not good :/ */
190 }
191
192 return t;
193}
194
195/*
196 * @brief Gets the size needed for a transparency map.
197 *
198 * @param w Width of the image.
199 * @param h Height of the image.
200 * @return The size in bytes.
201 */
202static size_t gl_transSize( const int w, const int h )
203{
204 /* One bit per pixel, plus remainder. */
205 return w*h/8 + ((w*h%8)?1:0);
206}
207
211static GLuint gl_texParameters( unsigned int flags )
212{
213 GLuint texture;
214
215 /* opengl texture binding */
216 glGenTextures( 1, &texture ); /* Creates the texture */
217 glBindTexture( GL_TEXTURE_2D, texture ); /* Loads the texture */
218
219 /* Filtering, LINEAR is better for scaling, nearest looks nicer, LINEAR
220 * also seems to create a bit of artifacts around the edges */
221 if ((gl_screen.scale != 1.) || (flags & OPENGL_TEX_MIPMAPS)) {
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);
225 else
226 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
227 }
228 else {
229 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
230 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
231 }
232
233 /* Always wrap just in case. */
234 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
235 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
236
237 /* Check errors. */
238 gl_checkErr();
239
240 return texture;
241}
242
252int gl_fboCreate( GLuint *fbo, GLuint *tex, GLsizei width, GLsizei height )
253{
254 GLenum status;
255
256 SDL_mutexP( tex_lock );
257 //tex_ctxSet();
258
259 /* Create the render buffer. */
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);
268
269 /* Create the frame buffer. */
270 glGenFramebuffers( 1, fbo );
271 glBindFramebuffer(GL_FRAMEBUFFER, *fbo);
272
273 /* Attach the colour buffer. */
274 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, *tex, 0);
275
276 /* Check status. */
277 status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
278 if (status != GL_FRAMEBUFFER_COMPLETE)
279 WARN(_("Error setting up framebuffer!"));
280
281 /* Restore state. */
282 glBindFramebuffer(GL_FRAMEBUFFER, gl_screen.current_fbo);
283
284 //tex_ctxUnset();
285 SDL_mutexV( tex_lock );
286
287 gl_checkErr();
288
289 return (status==GL_FRAMEBUFFER_COMPLETE);
290}
291
292glTexture* gl_loadImageData( float *data, int w, int h, int sx, int sy, const char* name )
293{
294 SDL_mutexP( tex_lock );
295 tex_ctxSet();
296
297 /* Set up the texture defaults */
298 glTexture *texture = calloc( 1, sizeof(glTexture) );
299
300 texture->w = (double) w;
301 texture->h = (double) h;
302 texture->sx = (double) sx;
303 texture->sy = (double) sy;
304
305 /* Set up texture. */
306 texture->texture = gl_texParameters( 0 );
307
308 /* Copy over. */
309 glTexImage2D( GL_TEXTURE_2D, 0, GL_SRGB_ALPHA, w, h, 0, GL_RGBA, GL_FLOAT, data );
310 glBindTexture( GL_TEXTURE_2D, 0 );
311
312 /* Check errors. */
313 gl_checkErr();
314
315 /* Set up values. */
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;
320
321 /* Add to list. */
322 if (name != NULL) {
323 texture->name = strdup(name);
324 gl_texAdd( texture, sx, sy );
325 }
326
327 tex_ctxUnset();
328 SDL_mutexV( tex_lock );
329
330 return texture;
331}
332
342static GLuint gl_loadSurface( SDL_Surface* surface, unsigned int flags, int freesur, double *vmax )
343{
344 GLuint texture;
345 SDL_Surface *rgba;
346 SDL_PixelFormatEnum fmt = SDL_PIXELFORMAT_ABGR8888;
347
348 SDL_mutexP( tex_lock );
349 tex_ctxSet();
350
351 /* Get texture. */
352 texture = gl_texParameters( flags );
353
354 /* Now load the texture data up
355 * It doesn't work with indexed ones, so I guess converting is best bet. */
356 if (surface->format->format != fmt)
357 rgba = SDL_ConvertSurfaceFormat( surface, fmt, 0 );
358 else
359 rgba = surface;
360
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 );
365 GLfloat *dataf = make_distance_mapbf( trans, rgba->w, rgba->h, vmax );
366 free( trans );
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 );
373 free( dataf );
374 }
375 else {
376 *vmax = 1.;
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 );
381 }
382 SDL_UnlockSurface(rgba);
383 if (rgba != surface)
384 SDL_FreeSurface(rgba);
385
386 /* Create mipmaps. */
387 if (flags & OPENGL_TEX_MIPMAPS) {
388 /* Do fancy stuff. */
389 if (GLAD_GL_ARB_texture_filter_anisotropic) {
390 GLfloat param;
391 glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY, &param);
392 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY, param);
393 }
394
395 /* Now generate the mipmaps. */
396 glGenerateMipmap(GL_TEXTURE_2D);
397 }
398
399 /* Unbind the texture. */
400 glBindTexture(GL_TEXTURE_2D, 0);
401
402 /* cleanup */
403 if (freesur)
404 SDL_FreeSurface( surface );
405 gl_checkErr();
406
407 tex_ctxUnset();
408 SDL_mutexV( tex_lock );
409
410 return texture;
411}
412
427glTexture* gl_loadImagePadTrans( const char *name, SDL_Surface* surface, SDL_RWops *rw,
428 unsigned int flags, int w, int h, int sx, int sy, int freesur )
429{
430 glTexture *texture = NULL;
431 size_t filesize, cachesize;
432 uint8_t *trans;
433 char *cachefile;
434 char digest[33];
435
436 SDL_mutexP( tex_lock );
437
438 if ((name != NULL) && !(flags & OPENGL_TEX_SKIPCACHE)) {
439 texture = gl_texExists( name, sx, sy );
440 if ((texture != NULL) && (texture->trans != NULL)) {
441 if (freesur)
442 SDL_FreeSurface( surface );
443 SDL_mutexV( tex_lock );
444 return texture;
445 }
446 }
447
448 if (flags & OPENGL_TEX_MAPTRANS)
449 flags ^= OPENGL_TEX_MAPTRANS;
450
451 /* Appropriate size for the transparency map, see SDL_MapAlpha */
452 cachesize = gl_transSize(w, h);
453
454 cachefile = NULL;
455 trans = NULL;
456
457 if (rw != NULL) {
458 size_t pngsize;
459 md5_state_t md5;
460 char *data;
461 md5_byte_t *md5val = malloc(16);
462 md5_init(&md5);
463
464 pngsize = SDL_RWseek( rw, 0, SEEK_END );
465 SDL_RWseek( rw, 0, SEEK_SET );
466
467 data = malloc(pngsize);
468 if (data == NULL)
469 WARN(_("Out of Memory"));
470 else {
471 SDL_RWread( rw, data, pngsize, 1 );
472 md5_append( &md5, (md5_byte_t*)data, pngsize );
473 free(data);
474 }
475 md5_finish( &md5, md5val );
476
477 for (int i=0; i<16; i++)
478 snprintf( &digest[i * 2], 3, "%02x", md5val[i] );
479 free(md5val);
480
481 SDL_asprintf( &cachefile, "%scollisions/%s",
482 nfile_cachePath(), digest );
483
484 /* Attempt to find a cached transparency map. */
485 if (nfile_fileExists(cachefile)) {
486 trans = (uint8_t*)nfile_readFile( &filesize, cachefile );
487
488 /* Consider cached data invalid if the length doesn't match. */
489 if (trans != NULL && cachesize != (unsigned int)filesize) {
490 free(trans);
491 trans = NULL;
492 }
493 /* Cached data matches, no need to overwrite. */
494 else {
495 free(cachefile);
496 cachefile = NULL;
497 }
498 }
499 }
500 else {
501 /* We could hash raw pixel data here, but that's slower than just
502 * generating the map from scratch. */
503 WARN(_("Texture '%s' has no RWops"), name);
504 }
505
506 if (trans == NULL) {
507 SDL_LockSurface(surface);
508 trans = SDL_MapAlpha( surface, w, h, 1 );
509 SDL_UnlockSurface(surface);
510
511 if (cachefile != NULL) {
512 /* Cache newly-generated transparency map. */
513 char dirpath[PATH_MAX];
514 snprintf( dirpath, sizeof(dirpath), "%s/%s", nfile_cachePath(), "collisions/" );
515 nfile_dirMakeExist( dirpath );
516 nfile_writeFile( (char*)trans, cachesize, cachefile );
517 free(cachefile);
518 }
519 }
520
521 if (texture == NULL)
522 texture = gl_loadImagePad( name, surface, flags, w, h, sx, sy, freesur );
523 else if (freesur)
524 SDL_FreeSurface( surface );
525 texture->trans = trans;
526 SDL_mutexV( tex_lock );
527 return texture;
528}
529
543glTexture* gl_loadImagePad( const char *name, SDL_Surface* surface,
544 unsigned int flags, int w, int h, int sx, int sy, int freesur )
545{
546 glTexture *texture;
547 SDL_mutexP( tex_lock );
548
549 /* Make sure doesn't already exist. */
550 if ((name != NULL) && !(flags & OPENGL_TEX_SKIPCACHE)) {
551 texture = gl_texExists( name, sx, sy );
552 if (texture != NULL) {
553 SDL_mutexV( tex_lock );
554 return texture;
555 }
556 }
557
558 if (flags & OPENGL_TEX_MAPTRANS) {
559 texture = gl_loadImagePadTrans( name, surface, NULL, flags, w, h,
560 sx, sy, freesur );
561 SDL_mutexV( tex_lock );
562 return texture;
563 }
564
565 /* set up the texture defaults */
566 texture = calloc( 1, sizeof(glTexture) );
567
568 texture->w = (double) w;
569 texture->h = (double) h;
570 texture->sx = (double) sx;
571 texture->sy = (double) sy;
572
573 texture->texture = gl_loadSurface( surface, flags, freesur, &texture->vmax );
574
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;
580
581 if (name != NULL) {
582 texture->name = strdup(name);
583 gl_texAdd( texture, sx, sy );
584 }
585 else
586 texture->name = NULL;
587
588 SDL_mutexV( tex_lock );
589 return texture;
590}
591
599glTexture* gl_loadImage( SDL_Surface* surface, unsigned int flags )
600{
601 return gl_loadImagePad( NULL, surface, flags, surface->w, surface->h, 1, 1, 1 );
602}
603
614static glTexture* gl_texExists( const char* path, int sx, int sy )
615{
616 /* Null does never exist. */
617 if (path==NULL) {
618 return NULL;
619 }
620 SDL_mutexP( tex_lock );
621
622 /* Check to see if it already exists */
623 if (texture_list == NULL) {
624 SDL_mutexV( tex_lock );
625 return NULL;
626 }
627
628 /* Do some fancy binary search. */
629 const glTexList q = { .path=path, .sx=sx, .sy=sy };
630 glTexList *t = bsearch( &q, texture_list, array_size(texture_list), sizeof(glTexList), tex_cmp );
631 if (t==NULL) {
632 SDL_mutexV( tex_lock );
633 return NULL;
634 }
635
636 /* Use new texture. */
637 t->used++;
638 SDL_mutexV( tex_lock );
639 return t->tex;
640}
641
645static int gl_texAdd( glTexture *tex, int sx, int sy )
646{
647 glTexList *new;
648
649 /* Get the new list element. */
650 if (texture_list == NULL)
652
653 /* Create the new node */
654 new = &array_grow( &texture_list );
655 new->used = 1;
656 new->tex = tex;
657 new->sx = sx;
658 new->sy = sy;
659 new->path = tex->name;
660
661 /* Sort the list. */
662 qsort( texture_list, array_size(texture_list), sizeof(glTexList), tex_cmp );
663 return 0;
664}
665
675glTexture* gl_newImage( const char* path, const unsigned int flags )
676{
677 /* Check if it already exists. */
678 if (!(flags & OPENGL_TEX_SKIPCACHE)) {
679 glTexture *t = gl_texExists( path, 1, 1 );
680 if (t != NULL)
681 return t;
682 }
683
684 /* Load the image */
685 return gl_loadNewImage( path, flags );
686}
687
700glTexture* gl_newImageRWops( const char* path, SDL_RWops *rw, const unsigned int flags )
701{
702 /* Check if it already exists. */
703 if (!(flags & OPENGL_TEX_SKIPCACHE)) {
704 glTexture *t = gl_texExists( path, 1, 1 );
705 if (t != NULL)
706 return t;
707 }
708
709 /* Load the image */
710 return gl_loadNewImageRWops( path, rw, flags );
711}
712
720static glTexture* gl_loadNewImage( const char* path, const unsigned int flags )
721{
722 glTexture *texture;
723 SDL_RWops *rw;
724
725 if (path==NULL) {
726 WARN(_("Trying to load image from NULL path."));
727 return NULL;
728 }
729
730 /* Load from packfile */
731 rw = PHYSFSRWOPS_openRead( path );
732 if (rw == NULL) {
733 WARN(_("Failed to load surface '%s' from ndata."), path);
734 return NULL;
735 }
736
737 texture = gl_loadNewImageRWops( path, rw, flags );
738
739 SDL_RWclose( rw );
740 return texture;
741}
742
751static glTexture* gl_loadNewImageRWops( const char *path, SDL_RWops *rw, unsigned int flags )
752{
753 SDL_Surface *surface;
754 glTexture *tex;
755
756 /* Placeholder for warnings. */
757 if (path==NULL)
758 path = _("unknown");
759
760 surface = IMG_Load_RW( rw, 0 );
761
762 flags |= OPENGL_TEX_VFLIP;
763 if (surface == NULL) {
764 WARN(_("Unable to load image '%s'."), path );
765 return NULL;
766 }
767
768 if (surface == NULL) {
769 WARN(_("'%s' could not be opened"), path );
770 return NULL;
771 }
772
773 SDL_mutexP( tex_lock );
774 if (flags & OPENGL_TEX_MAPTRANS)
775 tex = gl_loadImagePadTrans( path, surface, rw, flags, surface->w, surface->h, 1, 1, 1 );
776 else
777 tex = gl_loadImagePad( path, surface, flags, surface->w, surface->h, 1, 1, 1 );
778 SDL_mutexV( tex_lock );
779 return tex;
780}
781
791glTexture* gl_newSprite( const char* path, const int sx, const int sy,
792 const unsigned int flags )
793{
794 glTexture* texture;
795
796 /* Check if it already exists. */
797 if (!(flags & OPENGL_TEX_SKIPCACHE)) {
798 texture = gl_texExists( path, sx, sy );
799 if (texture != NULL)
800 return texture;
801 }
802
803 /* Create new image. */
804 texture = gl_newImage( path, flags | OPENGL_TEX_SKIPCACHE );
805 if (texture == NULL)
806 return NULL;
807
808 /* will possibly overwrite an existing texture properties
809 * so we have to load same texture always the same sprites */
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;
816 return texture;
817}
818
829glTexture* gl_newSpriteRWops( const char* path, SDL_RWops *rw,
830 const int sx, const int sy, const unsigned int flags )
831{
832 glTexture* texture;
833
834 /* Check if it already exists. */
835 if (!(flags & OPENGL_TEX_SKIPCACHE)) {
836 texture = gl_texExists( path, sx, sy );
837 if (texture != NULL)
838 return texture;
839 }
840
841 /* Create new image. */
842 texture = gl_newImageRWops( path, rw, flags | OPENGL_TEX_SKIPCACHE );
843 if (texture == NULL)
844 return NULL;
845
846 /* will possibly overwrite an existing texture properties
847 * so we have to load same texture always the same sprites */
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;
854 return texture;
855}
856
862void gl_freeTexture( glTexture *texture )
863{
864 if (texture == NULL)
865 return;
866
867 SDL_mutexP( tex_lock );
868
869 /* see if we can find it in stack */
870 for (int i=0; i<array_size(texture_list); i++) {
871 glTexList *cur = &texture_list[i];
872
873 if (cur->tex!=texture)
874 continue;
875
876 /* found it */
877 cur->used--;
878 if (cur->used <= 0) { /* not used anymore */
879 /* free the texture */
880 glDeleteTextures( 1, &texture->texture );
881 free(texture->trans);
882 free(texture->name);
883 free(texture);
884
885 /* free the list node */
887 }
888 SDL_mutexV( tex_lock );
889 return; /* we already found it so we can exit */
890 }
891
892 /* Not found */
893 if (texture->name != NULL) /* Surfaces will have NULL names */
894 WARN(_("Attempting to free texture '%s' not found in stack!"), texture->name);
895
896 /* Have to set context. */
897 tex_ctxSet();
898
899 /* Free anyways */
900 glDeleteTextures( 1, &texture->texture );
901 free(texture->trans);
902 free(texture->name);
903 free(texture);
904
905 gl_checkErr();
906
907 tex_ctxUnset();
908 SDL_mutexV( tex_lock );
909}
910
918{
919 /* No segfaults kthxbye. */
920 if (texture == NULL)
921 return NULL;
922
923 /* check to see if it already exists */
924 SDL_mutexP( tex_lock );
925 for (int i=0; i<array_size(texture_list); i++) {
926 glTexList *cur = &texture_list[i];
927 if (texture == cur->tex) {
928 cur->used++;
929 SDL_mutexV( tex_lock );
930 return cur->tex;
931 }
932 }
933 SDL_mutexV( tex_lock );
934
935 /* Invalid texture. */
936 WARN(_("Unable to duplicate texture '%s'."), texture->name);
937 return NULL;
938}
939
948int gl_isTrans( const glTexture* t, const int x, const int y )
949{
950 /* Get the position in the sheet. */
951 int i = y*(int)(t->w) + x ;
952 /* Now we have to pull out the individual bit. */
953 return !(t->trans[ i/8 ] & (1 << (i%8)));
954}
955
967void gl_getSpriteFromDir( int* x, int* y, const glTexture* t, const double dir )
968{
969 int s, sx, sy;
970 double shard, rdir;
971
972#ifdef DEBUGGING
973 if ((dir > 2.*M_PI) || (dir < 0.)) {
974 WARN(_("Angle not between 0 and 2.*M_PI [%f]."), dir);
975 *x = *y = 0;
976 return;
977 }
978#endif /* DEBUGGING */
979
980 /* what each image represents in angle */
981 shard = 2.*M_PI / (t->sy*t->sx);
982
983 /* real dir is slightly moved downwards */
984 rdir = dir + shard/2.;
985
986 /* now calculate the sprite we need */
987 s = (int)(rdir / shard);
988 sx = t->sx;
989 sy = t->sy;
990
991 /* makes sure the sprite is "in range" */
992 if (s > (sy*sx-1))
993 s = s % (sy*sx);
994
995 (*x) = s % sx;
996 (*y) = s / sx;
997}
998
1005{
1006 tex_lock = SDL_CreateMutex();
1007 tex_mainthread = SDL_ThreadID();
1008 return 0;
1009}
1010
1015{
1016 if (array_size(texture_list) <= 0) {
1018 return;
1019 }
1020
1021 /* Make sure there's no texture leak */
1022#if DEBUGGING
1023 DEBUG(_("Texture leak detected!"));
1024 for (int i=0; i<array_size(texture_list); i++) {
1025 const glTexList *cur = &texture_list[i];
1026 DEBUG( n_( " '%s' opened %d time", " '%s' opened %d times", cur->used ), cur->tex->name, cur->used );
1027 }
1028#endif /* DEBUGGING */
1029
1031
1032 SDL_DestroyMutex( tex_lock );
1033}
1034
1039{
1040 glTexture **t;
1041 int n = array_size(tex);
1042
1043 if (n <= 0)
1044 return NULL;
1045
1046 t = array_create_size( glTexture*, n );
1047 for (int i=0; i<array_size(tex); i++)
1048 array_push_back( &t, gl_dupTexture( tex[i] ) );
1049 return t;
1050}
1051
1056{
1057 if (tex==NULL)
1058 tex = array_create_size( glTexture*, 1 );
1059 array_push_back( &tex, t );
1060 return tex;
1061}
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
Definition array.h:158
#define array_create_size(basic_type, capacity)
Creates a new dynamic array of ‘basic_type’ with an initial capacity.
Definition array.h:102
#define array_erase(ptr_array, first, last)
Erases elements in interval [first, last).
Definition array.h:140
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
Definition array.h:168
#define array_grow(ptr_array)
Increases the number of elements by one and returns the last element.
Definition array.h:119
#define array_push_back(ptr_array, element)
Adds a new element at the end of the array.
Definition array.h:129
#define array_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
Definition array.h:93
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.
#define MIN(x, y)
Definition naev.h:40
#define PATH_MAX
Definition naev.h:50
int nfile_writeFile(const char *data, size_t len, const char *path)
Tries to write a file.
Definition nfile.c:538
char * nfile_readFile(size_t *filesize, const char *path)
Tries to read a file.
Definition nfile.c:427
int nfile_dirMakeExist(const char *path)
Creates a directory if it doesn't exist.
Definition nfile.c:267
const char * nfile_cachePath(void)
Gets Naev's cache path (for cached data such as generated textures)
Definition nfile.c:159
int nfile_fileExists(const char *path)
Checks to see if a file exists.
Definition nfile.c:316
glInfo gl_screen
Definition opengl.c:51
glTexture * gl_dupTexture(const glTexture *texture)
Duplicates a texture.
Definition opengl_tex.c:917
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.
Definition opengl_tex.c:791
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.
Definition opengl_tex.c:159
glTexture * gl_newImageRWops(const char *path, SDL_RWops *rw, const unsigned int flags)
Loads an image as a texture.
Definition opengl_tex.c:700
int gl_fboCreate(GLuint *fbo, GLuint *tex, GLsizei width, GLsizei height)
Creates a framebuffer and its associated texture.
Definition opengl_tex.c:252
static glTexture * gl_texExists(const char *path, int sx, int sy)
Check to see if a texture matching a path already exists.
Definition opengl_tex.c:614
glTexture * gl_loadImage(SDL_Surface *surface, unsigned int flags)
Loads the SDL_Surface to a glTexture.
Definition opengl_tex.c:599
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.
Definition opengl_tex.c:829
static GLuint gl_loadSurface(SDL_Surface *surface, unsigned int flags, int freesur, double *vmax)
Loads a surface into an opengl texture.
Definition opengl_tex.c:342
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.
Definition opengl_tex.c:948
static glTexture * gl_loadNewImage(const char *path, unsigned int flags)
Only loads the image, does not add to stack unlike gl_newImage.
Definition opengl_tex.c:720
static int SDL_IsTrans(SDL_Surface *s, int x, int y)
Checks to see if a position of the surface is transparent.
Definition opengl_tex.c:139
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.
Definition opengl_tex.c:645
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.
Definition opengl_tex.c:543
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.
Definition opengl_tex.c:427
glTexture * gl_newImage(const char *path, const unsigned int flags)
Loads an image as a texture.
Definition opengl_tex.c:675
static uint8_t SDL_GetAlpha(SDL_Surface *s, int x, int y)
Gets the alpha value of a pixel.
Definition opengl_tex.c:112
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.
Definition opengl_tex.c:967
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.
Definition opengl_tex.c:751
static GLuint gl_texParameters(unsigned int flags)
Sets default texture parameters.
Definition opengl_tex.c:211
static glTexList * texture_list
Definition opengl_tex.c:45
void gl_freeTexture(glTexture *texture)
Frees a texture.
Definition opengl_tex.c:862
int gl_initTextures(void)
Initializes the opengl texture subsystem.
double scale
Definition opengl.h:52
SDL_Window * window
Definition opengl.h:68
SDL_GLContext context
Definition opengl.h:69
GLuint current_fbo
Definition opengl.h:70
Represents a node in the texture list.
Definition opengl_tex.c:34
const char * path
Definition opengl_tex.c:36
glTexture * tex
Definition opengl_tex.c:35
Abstraction for rendering sprite sheets.
Definition opengl_tex.h:36
uint8_t * trans
Definition opengl_tex.h:53
double w
Definition opengl_tex.h:40
double sx
Definition opengl_tex.h:44
char * name
Definition opengl_tex.h:37
double sy
Definition opengl_tex.h:45
Define the state of the MD5 Algorithm.
Definition md5.h:73