naev 0.12.5
nlua_tex.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
10#include "SDL_image.h"
11#include <lauxlib.h>
13
14#include "physfsrwops.h"
15
16#include "nlua_tex.h"
17
18#include "ndata.h"
19#include "nlua_data.h"
20#include "nlua_file.h"
21#include "nluadef.h"
22#include "physics.h"
23
24static int nlua_tex_counter = 0;
25
26/* Helpers. */
27static inline uint32_t get_pixel( SDL_Surface *surface, int x, int y );
28
29/* Texture metatable methods. */
30static int texL_close( lua_State *L );
31static int texL_new( lua_State *L );
32static int texL_readData( lua_State *L );
33static int texL_writeData( lua_State *L );
34static int texL_dim( lua_State *L );
35static int texL_sprites( lua_State *L );
36static int texL_spriteFromDir( lua_State *L );
37static int texL_setFilter( lua_State *L );
38static int texL_setWrap( lua_State *L );
39
40static const luaL_Reg texL_methods[] = {
41 { "__gc", texL_close },
42 { "new", texL_new },
43 { "open", texL_new },
44 { "readData", texL_readData },
45 { "writeData", texL_writeData },
46 { "dim", texL_dim },
47 { "sprites", texL_sprites },
48 { "spriteFromDir", texL_spriteFromDir },
49 { "setFilter", texL_setFilter },
50 { "setWrap", texL_setWrap },
51 { 0, 0 } };
52
59int nlua_loadTex( nlua_env env )
60{
61 nlua_register( env, TEX_METATABLE, texL_methods, 1 );
62 return 0;
63}
64
86glTexture *lua_totex( lua_State *L, int ind )
87{
88 return *( (glTexture **)lua_touserdata( L, ind ) );
89}
90
97glTexture *luaL_checktex( lua_State *L, int ind )
98{
99 if ( lua_istex( L, ind ) )
100 return lua_totex( L, ind );
101 luaL_typerror( L, ind, TEX_METATABLE );
102 return NULL;
103}
104
113glTexture *luaL_validtex( lua_State *L, int ind, const char *searchpath )
114{
115 char path[PATH_MAX];
116 if ( lua_istex( L, ind ) )
117 return gl_dupTexture( luaL_checktex( L, ind ) );
118 ndata_getPathDefault( path, sizeof( path ), searchpath,
119 luaL_checkstring( L, ind ) );
120 return gl_newImage( path, 0 );
121}
122
129glTexture **lua_pushtex( lua_State *L, glTexture *texture )
130{
131 glTexture **t = (glTexture **)lua_newuserdata( L, sizeof( glTexture * ) );
132 *t = texture;
133 luaL_getmetatable( L, TEX_METATABLE );
134 lua_setmetatable( L, -2 );
135 return t;
136}
137
144int lua_istex( lua_State *L, int ind )
145{
146 int ret;
147
148 if ( lua_getmetatable( L, ind ) == 0 )
149 return 0;
150 lua_getfield( L, LUA_REGISTRYINDEX, TEX_METATABLE );
151
152 ret = 0;
153 if ( lua_rawequal( L, -1, -2 ) ) /* does it have the correct mt? */
154 ret = 1;
155
156 lua_pop( L, 2 ); /* remove both metatables */
157 return ret;
158}
159
166static int texL_close( lua_State *L )
167{
168 gl_freeTexture( luaL_checktex( L, 1 ) );
169 if ( gl_checkErr() )
170 NLUA_ERROR( L, _( "OpenGL Error!" ) );
171 return 0;
172}
173
196static int texL_new( lua_State *L )
197{
198 const char *path;
199 glTexture *tex;
200 LuaFile_t *lf;
201 LuaData_t *ld;
202 int sx, sy;
203 SDL_RWops *rw;
204 char *name;
205
206 /* Defaults. */
207 lf = NULL;
208 ld = NULL;
209 path = NULL;
210
211 /* Get path. */
212 if ( lua_isdata( L, 1 ) ) {
213 int w, h;
214 ld = luaL_checkdata( L, 1 );
215 /* Since we don't know the size we need the width and height separately.
216 */
217 w = luaL_checkinteger( L, 2 );
218 h = luaL_checkinteger( L, 3 );
219 if ( ( w < 0 ) || ( h < 0 ) )
220 return NLUA_ERROR( L, _( "Texture dimensions must be positive" ) );
221 sx = luaL_optinteger( L, 4, 1 );
222 sy = luaL_optinteger( L, 5, 1 );
223 if ( ( sx < 0 ) || ( sy < 0 ) )
224 return NLUA_ERROR( L, _( "Spritesheet dimensions must be positive" ) );
225 if ( ld->type != LUADATA_NUMBER )
226 return NLUA_ERROR( L, _( "Data has invalid type for texture" ) );
227 if ( w * h * ld->elem * 4 != ld->size )
228 return NLUA_ERROR( L,
229 _( "Texture dimensions don't match data size!" ) );
230 SDL_asprintf( &name, "nlua_texture_%03d", ++nlua_tex_counter );
231 tex = gl_loadImageData( (void *)ld->data, w, h, sx, sy, name );
232 free( name );
233 if ( tex == NULL )
234 return 0;
235 lua_pushtex( L, tex );
236 return 1;
237 } else if ( lua_isfile( L, 1 ) )
238 lf = luaL_checkfile( L, 1 );
239 else
240 path = luaL_checkstring( L, 1 );
241
242 sx = luaL_optinteger( L, 2, 1 );
243 sy = luaL_optinteger( L, 3, 1 );
244 if ( ( sx < 0 ) || ( sy < 0 ) )
245 return NLUA_ERROR( L, _( "Spritesheet dimensions must be positive" ) );
246
247 /* Push new texture. */
248 if ( path != NULL )
249 tex = gl_newSprite( path, sx, sy, 0 );
250 else {
251 rw = PHYSFSRWOPS_openRead( lf->path );
252 if ( rw == NULL )
253 return NLUA_ERROR( L, "Unable to open '%s'", lf->path );
254 tex = gl_newSpriteRWops( lf->path, rw, sx, sy, 0 );
255 SDL_RWclose( rw );
256 }
257
258 /* Failed to load. */
259 if ( tex == NULL )
260 return 0;
261 /* Properly loaded. */
262 lua_pushtex( L, tex );
263 return 1;
264}
265
266static inline uint32_t get_pixel( SDL_Surface *surface, int x, int y )
267{
268 int bpp = surface->format->BytesPerPixel;
269 /* Here p is the address to the pixel we want to retrieve */
270 uint8_t *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
271
272 switch ( bpp ) {
273 case 1:
274 return *p;
275 break;
276
277 case 2:
278 return *(Uint16 *)p;
279 break;
280
281 case 3:
282 if ( SDL_BYTEORDER == SDL_BIG_ENDIAN )
283 return p[0] << 16 | p[1] << 8 | p[2];
284 else
285 return p[0] | p[1] << 8 | p[2] << 16;
286 break;
287
288 case 4:
289 return *(Uint32 *)p;
290 break;
291
292 default:
293 return 0; /* shouldn't happen, but avoids warnings */
294 }
295}
296
307static int texL_readData( lua_State *L )
308{
309 LuaFile_t *lf;
310 LuaData_t ld;
311 SDL_Surface *surface;
312 SDL_RWops *rw;
313 const char *s;
314 size_t size;
315 uint8_t r, g, b, a;
316 uint32_t pix;
317 float *data;
318
319 s = NULL;
320 if ( lua_isfile( L, 1 ) ) {
321 lf = luaL_checkfile( L, 1 );
322 s = lf->path;
323 } else
324 s = luaL_checkstring( L, 1 );
325 rw = PHYSFSRWOPS_openRead( s );
326 if ( rw == NULL )
327 return NLUA_ERROR( L, _( "problem opening file '%s' for reading" ), s );
328
329 /* Try to read the image. */
330 surface = IMG_Load_RW( rw, 1 );
331 if ( surface == NULL )
332 return NLUA_ERROR( L, _( "problem opening image for reading" ) );
333
334 /* Convert surface to LuaData_t */
335 SDL_LockSurface( surface );
336 size = surface->w * surface->h;
337 ld.elem = sizeof( float );
338 ld.size = ld.elem * size * 4;
339 ld.data = calloc( ld.elem * 4, size );
340 ld.type = LUADATA_NUMBER;
341 data = (float *)ld.data;
342 for ( int i = 0; i < surface->h; i++ ) {
343 for ( int j = 0; j < surface->w; j++ ) {
344 pix = get_pixel( surface, j, i );
345 SDL_GetRGBA( pix, surface->format, &r, &g, &b, &a );
346 size_t pos = 4 * ( ( surface->h - i - 1 ) * surface->w + j );
347 data[pos + 0] = ( (float)r ) / 255.;
348 data[pos + 1] = ( (float)g ) / 255.;
349 data[pos + 2] = ( (float)b ) / 255.;
350 data[pos + 3] = ( (float)a ) / 255.;
351 }
352 }
353 SDL_UnlockSurface( surface );
354
355 /* Return parameters. */
356 lua_pushdata( L, ld );
357 lua_pushinteger( L, surface->w );
358 lua_pushinteger( L, surface->h );
359
360 /* Clean up. */
361 SDL_FreeSurface( surface );
362
363 return 3;
364}
365
373static int texL_writeData( lua_State *L )
374{
375 glTexture *tex = luaL_checktex( L, 1 );
376 const char *filename = luaL_checkstring( L, 2 );
377 int w, h;
378 size_t len;
379 char *data;
380 SDL_Surface *surface;
381 SDL_RWops *rw;
382
383 w = tex->w;
384 h = tex->h;
385 len = w * h * 4 * sizeof( GLubyte );
386 data = malloc( len );
387
388 /* Read raw data. */
389 glBindTexture( GL_TEXTURE_2D, tex->texture );
390 glGetTexImage( GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, data );
391 if ( gl_checkErr() )
392 NLUA_ERROR( L, _( "OpenGL Error!" ) );
393
394 /* Convert to PNG. */
395 surface = SDL_CreateRGBSurface( 0, w, h, 32, RGBAMASK );
396 for ( int i = 0; i < h; i++ )
397 memcpy( (GLubyte *)surface->pixels + i * ( 4 * w ),
398 &data[( h - i - 1 ) * ( 4 * w )], 4 * w );
399
400 /* Free buffer. */
401 free( data );
402
403 /* Save to file. */
404 if ( !( rw = PHYSFSRWOPS_openWrite( filename ) ) )
405 return NLUA_ERROR( L, _( "Unable to open '%s' for writing!" ), filename );
406 else
407 IMG_SavePNG_RW( surface, rw, 1 );
408
409 SDL_FreeSurface( surface );
410
411 lua_pushboolean( L, 1 );
412 return 1;
413}
414
427static int texL_dim( lua_State *L )
428{
429 const glTexture *tex = luaL_checktex( L, 1 );
430 /* Get all 4 values. */
431 lua_pushnumber( L, tex->w );
432 lua_pushnumber( L, tex->h );
433 lua_pushnumber( L, tex->sw );
434 lua_pushnumber( L, tex->sh );
435 return 4;
436}
437
449static int texL_sprites( lua_State *L )
450{
451 const glTexture *tex = luaL_checktex( L, 1 );
452 /* Get sprites. */
453 lua_pushnumber( L, tex->sx * tex->sy );
454 lua_pushnumber( L, tex->sx );
455 lua_pushnumber( L, tex->sy );
456 return 3;
457}
458
470static int texL_spriteFromDir( lua_State *L )
471{
472
473 int sx, sy;
474 const glTexture *tex = luaL_checktex( L, 1 );
475 double a = luaL_checknumber( L, 2 );
476
477 /* Calculate with parameter validity.. */
478 gl_getSpriteFromDir( &sx, &sy, tex->sx, tex->sy, angle_clean( a ) );
479
480 /* Return. */
481 lua_pushinteger( L, sx + 1 );
482 lua_pushinteger( L, sy + 1 );
483 return 2;
484}
485
495static int texL_setFilter( lua_State *L )
496{
497 const glTexture *tex = luaL_checktex( L, 1 );
498 const char *smin = luaL_checkstring( L, 2 );
499 const char *smag = luaL_optstring( L, 3, smin );
500 GLint min, mag;
501
502 min = gl_stringToFilter( smin );
503 mag = gl_stringToFilter( smag );
504
505 if ( min == 0 || mag == 0 )
506 NLUA_INVALID_PARAMETER( L, 2 );
507
508 glBindTexture( GL_TEXTURE_2D, tex->texture );
509 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag );
510 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min );
511 if ( gl_checkErr() )
512 NLUA_ERROR( L, _( "OpenGL Error!" ) );
513
514 return 0;
515}
516
529static int texL_setWrap( lua_State *L )
530{
531 const glTexture *tex = luaL_checktex( L, 1 );
532 const char *shoriz = luaL_checkstring( L, 2 );
533 const char *svert = luaL_optstring( L, 3, shoriz );
534 const char *sdepth = luaL_optstring( L, 4, shoriz );
535 GLint horiz, vert, depth;
536
537 horiz = gl_stringToClamp( shoriz );
538 vert = gl_stringToClamp( svert );
539 depth = gl_stringToClamp( sdepth );
540
541 if ( horiz == 0 || vert == 0 || depth == 0 )
542 NLUA_INVALID_PARAMETER( L, 2 );
543
544 glBindTexture( GL_TEXTURE_2D, tex->texture );
545 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, horiz );
546 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, vert );
547 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, depth );
548 if ( gl_checkErr() )
549 NLUA_ERROR( L, _( "OpenGL Error!" ) );
550
551 return 0;
552}
#define PATH_MAX
Definition naev.h:57
int ndata_getPathDefault(char *path, int len, const char *default_path, const char *filename)
Tries to see if a file is in a default path before seeing if it is an absolute path.
Definition ndata.c:442
LuaData_t * luaL_checkdata(lua_State *L, int ind)
Gets data at index or raises error if there is no data at index.
Definition nlua_data.c:80
int lua_isdata(lua_State *L, int ind)
Checks to see if ind is a data.
Definition nlua_data.c:110
LuaData_t * lua_pushdata(lua_State *L, LuaData_t data)
Pushes a data on the stack.
Definition nlua_data.c:94
int lua_isfile(lua_State *L, int ind)
Checks to see if ind is a file.
Definition nlua_file.c:123
LuaFile_t * luaL_checkfile(lua_State *L, int ind)
Gets file at index or raises error if there is no file at index.
Definition nlua_file.c:94
static int texL_dim(lua_State *L)
Gets the dimensions of the texture.
Definition nlua_tex.c:427
glTexture * lua_totex(lua_State *L, int ind)
Lua bindings to interact with OpenGL textures.
Definition nlua_tex.c:86
static int texL_setWrap(lua_State *L)
Sets the texture wrapping.
Definition nlua_tex.c:529
static int texL_readData(lua_State *L)
Reads image data from a file.
Definition nlua_tex.c:307
int lua_istex(lua_State *L, int ind)
Checks to see if ind is a texture.
Definition nlua_tex.c:144
static int texL_spriteFromDir(lua_State *L)
Gets the sprite that corresponds to a direction.
Definition nlua_tex.c:470
glTexture ** lua_pushtex(lua_State *L, glTexture *texture)
Pushes a texture on the stack.
Definition nlua_tex.c:129
static int texL_new(lua_State *L)
Opens a texture.
Definition nlua_tex.c:196
glTexture * luaL_checktex(lua_State *L, int ind)
Gets texture at index or raises error if there is no texture at index.
Definition nlua_tex.c:97
static int texL_writeData(lua_State *L)
Saves texture data as a png.
Definition nlua_tex.c:373
static int texL_sprites(lua_State *L)
Gets the number of sprites in the texture.
Definition nlua_tex.c:449
glTexture * luaL_validtex(lua_State *L, int ind, const char *searchpath)
Gets texture directly or from a filename (string) at index or raises error if there is no texture at ...
Definition nlua_tex.c:113
static int texL_close(lua_State *L)
Frees the texture.
Definition nlua_tex.c:166
static const luaL_Reg texL_methods[]
Definition nlua_tex.c:40
static int texL_setFilter(lua_State *L)
Sets the texture minification and magnification filters.
Definition nlua_tex.c:495
int nlua_loadTex(nlua_env env)
Loads the texture library.
Definition nlua_tex.c:59
GLenum gl_stringToFilter(const char *s)
Gets the associated min/mag filter from a string.
Definition opengl.c:791
GLenum gl_stringToClamp(const char *s)
Gets the associated min/mag filter from a string.
Definition opengl.c:807
glTexture * gl_dupTexture(const glTexture *texture)
Duplicates a texture.
Definition opengl_tex.c:891
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:785
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:808
glTexture * gl_newImage(const char *path, const unsigned int flags)
Loads an image as a texture.
Definition opengl_tex.c:587
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.
Definition opengl_tex.c:977
void gl_freeTexture(glTexture *texture)
Frees a texture.
Definition opengl_tex.c:835
Wrapper to datas.
Definition nlua_data.h:17
LuaDataType_t type
Definition nlua_data.h:21
void * data
Definition nlua_data.h:20
size_t size
Definition nlua_data.h:18
size_t elem
Definition nlua_data.h:19
Wrapper to files.
Definition nlua_file.h:19
char path[PATH_MAX]
Definition nlua_file.h:20
Abstraction for rendering sprite sheets.
Definition opengl_tex.h:43
double sw
Definition opengl_tex.h:53
double sh
Definition opengl_tex.h:54
double w
Definition opengl_tex.h:47
double sx
Definition opengl_tex.h:51
GLuint texture
Definition opengl_tex.h:59
double sy
Definition opengl_tex.h:52
double h
Definition opengl_tex.h:48