Skip to content
Snippets Groups Projects
core_lua.c 40.4 KiB
Newer Older
dg's avatar
dg committed
/*
    TE4 - T-Engine 4
    Copyright (C) 2009, 2010 Nicolas Casalini

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

    Nicolas Casalini "DarkGod"
    darkgod@te4.org
*/
dg's avatar
dg committed
#include "fov/fov.h"
dg's avatar
dg committed
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "auxiliar.h"
dg's avatar
dg committed
#include "types.h"
#include "script.h"
#include "display.h"
dg's avatar
dg committed
#include "physfs.h"
dg's avatar
dg committed
#include "SFMT.h"
dg's avatar
dg committed
#include "mzip.h"
dg's avatar
dg committed
#include "main.h"
#include "tSDL.h"
#include <math.h>
#include <time.h>
dg's avatar
dg committed

dg's avatar
dg committed
/******************************************************************
 ******************************************************************
 *                              FOV                               *
 ******************************************************************
 ******************************************************************/
dg's avatar
dg committed
struct lua_fovcache
{
	bool *cache;
	int w, h;
};

dg's avatar
dg committed
struct lua_fov
{
	fov_settings_type fov_settings;
	int apply_ref;
	int opaque_ref;
dg's avatar
dg committed
	int cache_ref;
	struct lua_fovcache *cache;
dg's avatar
dg committed
};

static void map_seen(void *m, int x, int y, int dx, int dy, int radius, void *src)
{
	struct lua_fov *fov = (struct lua_fov *)m;
	radius--;
	if (dx*dx + dy*dy <= radius*radius + 1)
dg's avatar
dg committed
	{
		// circular view - can be changed if you like
		lua_rawgeti(L, LUA_REGISTRYINDEX, fov->apply_ref);
		if (fov->cache) lua_rawgeti(L, LUA_REGISTRYINDEX, fov->cache_ref);
		else lua_pushnil(L);
		lua_pushnumber(L, x);
		lua_pushnumber(L, y);
		lua_pushnumber(L, dx);
		lua_pushnumber(L, dy);
		lua_pushnumber(L, dx*dx + dy*dy);
		lua_call(L, 6, 0);
dg's avatar
dg committed
	}
}

static bool map_opaque(void *m, int x, int y)
{
	struct lua_fov *fov = (struct lua_fov *)m;

dg's avatar
dg committed
	if (fov->cache)
	{
		return fov->cache->cache[x + y * fov->cache->w];
	}
	else
	{
		lua_rawgeti(L, LUA_REGISTRYINDEX, fov->opaque_ref);
		if (fov->cache) lua_rawgeti(L, LUA_REGISTRYINDEX, fov->cache_ref);
		else lua_pushnil(L);
		lua_pushnumber(L, x);
		lua_pushnumber(L, y);
		lua_call(L, 3, 1);
		bool res = lua_toboolean(L, -1);
		lua_pop(L, 1);
		return res;
	}
dg's avatar
dg committed
}

static int lua_new_fov(lua_State *L)
{
dg's avatar
dg committed
	struct lua_fovcache* cache;
	int cache_ref;
	if (lua_isuserdata(L, 1))
	{
		cache = (struct lua_fovcache*)auxiliar_checkclass(L, "fov{cache}", 1);
		cache_ref = luaL_ref(L, LUA_REGISTRYINDEX);
	}
	else
	{
		cache_ref = LUA_NOREF;
		cache = NULL;
	}
dg's avatar
dg committed
	int apply_ref = luaL_ref(L, LUA_REGISTRYINDEX);
	int opaque_ref = luaL_ref(L, LUA_REGISTRYINDEX);

	struct lua_fov *fov = (struct lua_fov*)lua_newuserdata(L, sizeof(struct lua_fov));
	auxiliar_setclass(L, "fov{core}", -1);
	fov->apply_ref = apply_ref;
	fov->opaque_ref = opaque_ref;
dg's avatar
dg committed
	fov->cache_ref = cache_ref;
	fov->cache = cache;
dg's avatar
dg committed
	fov_settings_init(&(fov->fov_settings));
	fov_settings_set_opacity_test_function(&(fov->fov_settings), map_opaque);
	fov_settings_set_apply_lighting_function(&(fov->fov_settings), map_seen);

	return 1;
}

static int lua_free_fov(lua_State *L)
{
	struct lua_fov *fov = (struct lua_fov*)auxiliar_checkclass(L, "fov{core}", 1);
	fov_settings_free(&(fov->fov_settings));
	luaL_unref(L, LUA_REGISTRYINDEX, fov->apply_ref);
	luaL_unref(L, LUA_REGISTRYINDEX, fov->opaque_ref);
dg's avatar
dg committed
	if (fov->cache_ref != LUA_NOREF) luaL_unref(L, LUA_REGISTRYINDEX, fov->cache_ref);
dg's avatar
dg committed
	lua_pushnumber(L, 1);
	return 1;
}

dg's avatar
dg committed
static int lua_fov(lua_State *L)
dg's avatar
dg committed
{
	struct lua_fov *fov = (struct lua_fov*)auxiliar_checkclass(L, "fov{core}", 1);
	int x = luaL_checknumber(L, 2);
	int y = luaL_checknumber(L, 3);
	int radius = luaL_checknumber(L, 4);

	fov_circle(&(fov->fov_settings), fov, NULL, x, y, radius+1);
dg's avatar
dg committed
	map_seen(fov, x, y, 0, 0, radius, NULL);
dg's avatar
dg committed
	return 0;
}

static int lua_fov_calc_circle(lua_State *L)
dg's avatar
dg committed
{
dg's avatar
dg committed
	int x = luaL_checknumber(L, 1);
	int y = luaL_checknumber(L, 2);
	int radius = luaL_checknumber(L, 3);
dg's avatar
dg committed
	struct lua_fov fov;
dg's avatar
dg committed
	if (lua_isuserdata(L, 6))
	{
		fov.cache = (struct lua_fovcache*)auxiliar_checkclass(L, "fov{cache}", 6);
		fov.cache_ref = luaL_ref(L, LUA_REGISTRYINDEX);
	}
	else
	{
		lua_pop(L, 1);
		fov.cache_ref = LUA_NOREF;
		fov.cache = NULL;
	}
dg's avatar
dg committed
	fov.apply_ref = luaL_ref(L, LUA_REGISTRYINDEX);
	fov.opaque_ref = luaL_ref(L, LUA_REGISTRYINDEX);
dg's avatar
dg committed
//	int i= SDL_GetTicks();
dg's avatar
dg committed
	fov_settings_init(&(fov.fov_settings));
dg's avatar
dg committed
	fov_settings_set_opacity_test_function(&(fov.fov_settings), map_opaque);
	fov_settings_set_apply_lighting_function(&(fov.fov_settings), map_seen);
dg's avatar
dg committed
	fov_circle(&(fov.fov_settings), &fov, NULL, x, y, radius+1);
dg's avatar
dg committed
	map_seen(&fov, x, y, 0, 0, radius, NULL);
dg's avatar
dg committed
	fov_settings_free(&(fov.fov_settings));
dg's avatar
dg committed
//	printf("map display ticks %d\n",SDL_GetTicks()-i);
dg's avatar
dg committed
	luaL_unref(L, LUA_REGISTRYINDEX, fov.apply_ref);
	luaL_unref(L, LUA_REGISTRYINDEX, fov.opaque_ref);
dg's avatar
dg committed
	if (fov.cache_ref != LUA_NOREF) luaL_unref(L, LUA_REGISTRYINDEX, fov.cache_ref);
dg's avatar
dg committed

dg's avatar
dg committed
	return 0;
}

static int lua_fov_calc_beam(lua_State *L)
{
	int x = luaL_checknumber(L, 1);
	int y = luaL_checknumber(L, 2);
	int radius = luaL_checknumber(L, 3);
	int direction = luaL_checknumber(L, 4);
	float angle = luaL_checknumber(L, 5);
dg's avatar
dg committed
	struct lua_fov fov;
dg's avatar
dg committed
	if (lua_isuserdata(L, 8))
	{
		fov.cache = (struct lua_fovcache*)auxiliar_checkclass(L, "fov{cache}", 8);
		fov.cache_ref = luaL_ref(L, LUA_REGISTRYINDEX);
	}
	else
	{
		lua_pop(L, 1);
		fov.cache_ref = LUA_NOREF;
		fov.cache = NULL;
	}
dg's avatar
dg committed
	fov.apply_ref = luaL_ref(L, LUA_REGISTRYINDEX);
	fov.opaque_ref = luaL_ref(L, LUA_REGISTRYINDEX);
dg's avatar
dg committed
	fov.cache = NULL;
dg's avatar
dg committed
	int dir = 0;

	switch (direction)
	{
	case 1: dir = FOV_SOUTHWEST; break;
	case 2: dir = FOV_SOUTH; break;
	case 3: dir = FOV_SOUTHEAST; break;
	case 4: dir = FOV_WEST; break;
	case 6: dir = FOV_EAST; break;
	case 7: dir = FOV_NORTHWEST; break;
	case 8: dir = FOV_NORTH; break;
	case 9: dir = FOV_NORTHEAST; break;
	}

	fov_settings_init(&(fov.fov_settings));
dg's avatar
dg committed
	fov_settings_set_opacity_test_function(&(fov.fov_settings), map_opaque);
	fov_settings_set_apply_lighting_function(&(fov.fov_settings), map_seen);
dg's avatar
dg committed
	fov_beam(&(fov.fov_settings), &fov, NULL, x, y, radius+1, dir, angle);
dg's avatar
dg committed
	map_seen(&fov, x, y, 0, 0, radius, NULL);
dg's avatar
dg committed
	fov_settings_free(&(fov.fov_settings));

	luaL_unref(L, LUA_REGISTRYINDEX, fov.apply_ref);
	luaL_unref(L, LUA_REGISTRYINDEX, fov.opaque_ref);
dg's avatar
dg committed
	if (fov.cache_ref != LUA_NOREF) luaL_unref(L, LUA_REGISTRYINDEX, fov.cache_ref);
dg's avatar
dg committed

	return 0;
dg's avatar
dg committed
}

dg's avatar
dg committed
static int lua_distance(lua_State *L)
{
	double x1 = luaL_checknumber(L, 1);
	double y1 = luaL_checknumber(L, 2);
	double x2 = luaL_checknumber(L, 3);
	double y2 = luaL_checknumber(L, 4);

	lua_pushnumber(L, sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2)));
	return 1;
}

dg's avatar
dg committed
static int lua_new_fovcache(lua_State *L)
{
	int x = luaL_checknumber(L, 1);
	int y = luaL_checknumber(L, 2);
	int i, j;

	struct lua_fovcache *cache = (struct lua_fovcache*)lua_newuserdata(L, sizeof(struct lua_fovcache));
	auxiliar_setclass(L, "fov{cache}", -1);
	cache->w = x;
	cache->h = y;
	cache->cache = calloc(x * y, sizeof(bool));
	for (i = 0; i < x; i++)
		for (j = 0; j < y; j++)
			cache->cache[i + j * x] = FALSE;

	return 1;
}

static int lua_fovcache_set(lua_State *L)
{
	struct lua_fovcache *cache = (struct lua_fovcache*)auxiliar_checkclass(L, "fov{cache}", 1);
	int x = luaL_checknumber(L, 2);
	int y = luaL_checknumber(L, 3);
	bool opaque = lua_toboolean(L, 4);

	cache->cache[x + y * cache->w] = opaque;

	return 0;
}

dg's avatar
dg committed
static int lua_fovcache_get(lua_State *L)
{
	struct lua_fovcache *cache = (struct lua_fovcache*)auxiliar_checkclass(L, "fov{cache}", 1);
	int x = luaL_checknumber(L, 2);
	int y = luaL_checknumber(L, 3);

	lua_pushboolean(L, cache->cache[x + y * cache->w]);
	return 1;
}

dg's avatar
dg committed
static const struct luaL_reg fovlib[] =
dg's avatar
dg committed
{
dg's avatar
dg committed
	{"new", lua_new_fov},
dg's avatar
dg committed
	{"newCache", lua_new_fovcache},
dg's avatar
dg committed
	{"distance", lua_distance},
dg's avatar
dg committed
	{"calc_circle", lua_fov_calc_circle},
	{"calc_beam", lua_fov_calc_beam},
	{NULL, NULL},
};

static const struct luaL_reg fov_reg[] =
{
	{"__gc", lua_free_fov},
	{"close", lua_free_fov},
	{"__call", lua_fov},
dg's avatar
dg committed
	{NULL, NULL},
};

dg's avatar
dg committed
static const struct luaL_reg fovcache_reg[] =
{
	{"set", lua_fovcache_set},
dg's avatar
dg committed
	{"get", lua_fovcache_get},
dg's avatar
dg committed
	{NULL, NULL},
};

dg's avatar
dg committed
/******************************************************************
 ******************************************************************
 *                             Mouse                              *
 ******************************************************************
 ******************************************************************/
static int lua_get_mouse(lua_State *L)
{
	int x = 0, y = 0;
	(void)SDL_GetMouseState(&x, &y);
dg's avatar
dg committed

	lua_pushnumber(L, x);
	lua_pushnumber(L, y);

	return 2;
}
dg's avatar
dg committed
extern int current_mousehandler;
static int lua_set_current_mousehandler(lua_State *L)
{
	if (current_mousehandler != LUA_NOREF)
		luaL_unref(L, LUA_REGISTRYINDEX, current_mousehandler);

	if (lua_isnil(L, 1))
		current_mousehandler = LUA_NOREF;
	else
		current_mousehandler = luaL_ref(L, LUA_REGISTRYINDEX);

	return 0;
}
dg's avatar
dg committed
static const struct luaL_reg mouselib[] =
{
	{"get", lua_get_mouse},
dg's avatar
dg committed
	{"set_current_handler", lua_set_current_mousehandler},
dg's avatar
dg committed
	{NULL, NULL},
};

dg's avatar
dg committed
/******************************************************************
 ******************************************************************
 *                              Keys                              *
 ******************************************************************
 ******************************************************************/
extern int current_keyhandler;
static int lua_set_current_keyhandler(lua_State *L)
{
	if (current_keyhandler != LUA_NOREF)
		luaL_unref(L, LUA_REGISTRYINDEX, current_keyhandler);

	if (lua_isnil(L, 1))
		current_keyhandler = LUA_NOREF;
	else
		current_keyhandler = luaL_ref(L, LUA_REGISTRYINDEX);

	return 0;
}
static const struct luaL_reg keylib[] =
{
	{"set_current_handler", lua_set_current_keyhandler},
	{NULL, NULL},
};

dg's avatar
dg committed
/******************************************************************
 ******************************************************************
 *                              Game                              *
 ******************************************************************
 ******************************************************************/
dg's avatar
dg committed
extern int current_game;
static int lua_set_current_game(lua_State *L)
dg's avatar
dg committed
{
dg's avatar
dg committed
	if (current_game != LUA_NOREF)
		luaL_unref(L, LUA_REGISTRYINDEX, current_game);
dg's avatar
dg committed

	if (lua_isnil(L, 1))
dg's avatar
dg committed
		current_game = LUA_NOREF;
dg's avatar
dg committed
	else
dg's avatar
dg committed
		current_game = luaL_ref(L, LUA_REGISTRYINDEX);
dg's avatar
dg committed

	return 0;
}
dg's avatar
dg committed
extern bool exit_engine;
static int lua_exit_engine(lua_State *L)
{
	exit_engine = TRUE;
	return 0;
}
dg's avatar
dg committed
static const struct luaL_reg gamelib[] =
{
dg's avatar
dg committed
	{"set_current_game", lua_set_current_game},
dg's avatar
dg committed
	{"exit_engine", lua_exit_engine},
dg's avatar
dg committed
	{NULL, NULL},
};

dg's avatar
dg committed
/******************************************************************
 ******************************************************************
 *                           Display                              *
 ******************************************************************
 ******************************************************************/
dg's avatar
dg committed

static int sdl_fullscreen(lua_State *L)
{
	SDL_WM_ToggleFullScreen(screen);
	return 0;
}

dg's avatar
dg committed
static int sdl_screen_size(lua_State *L)
{
	lua_pushnumber(L, screen->w);
	lua_pushnumber(L, screen->h);
	return 2;
}

dg's avatar
dg committed
static int sdl_new_font(lua_State *L)
{
	const char *name = luaL_checkstring(L, 1);
	int size = luaL_checknumber(L, 2);

	TTF_Font **f = (TTF_Font**)lua_newuserdata(L, sizeof(TTF_Font*));
	auxiliar_setclass(L, "sdl{font}", -1);

	*f = TTF_OpenFontRW(PHYSFSRWOPS_openRead(name), TRUE, size);
dg's avatar
dg committed
//	TTF_SetFontOutline(*f, 2);
dg's avatar
dg committed

	return 1;
}

static int sdl_free_font(lua_State *L)
{
	TTF_Font **f = (TTF_Font**)auxiliar_checkclass(L, "sdl{font}", 1);
	TTF_CloseFont(*f);
	lua_pushnumber(L, 1);
	return 1;
}

dg's avatar
dg committed
static int sdl_font_size(lua_State *L)
{
	TTF_Font **f = (TTF_Font**)auxiliar_checkclass(L, "sdl{font}", 1);
	const char *str = luaL_checkstring(L, 2);
	int w, h;

	if (!TTF_SizeUTF8(*f, str, &w, &h))
	{
		lua_pushnumber(L, w);
		lua_pushnumber(L, h);
		return 2;
	}
	return 0;
}

static int sdl_font_height(lua_State *L)
{
	TTF_Font **f = (TTF_Font**)auxiliar_checkclass(L, "sdl{font}", 1);
	lua_pushnumber(L, TTF_FontHeight(*f));
	return 1;
}

static int sdl_font_lineskip(lua_State *L)
{
	TTF_Font **f = (TTF_Font**)auxiliar_checkclass(L, "sdl{font}", 1);
	lua_pushnumber(L, TTF_FontLineSkip(*f));
	return 1;
}

dg's avatar
dg committed
static int sdl_surface_drawstring(lua_State *L)
{
	SDL_Surface **s = (SDL_Surface**)auxiliar_checkclass(L, "sdl{surface}", 1);
	TTF_Font **f = (TTF_Font**)auxiliar_checkclass(L, "sdl{font}", 2);
	const char *str = luaL_checkstring(L, 3);
	int x = luaL_checknumber(L, 4);
	int y = luaL_checknumber(L, 5);
	int r = luaL_checknumber(L, 6);
	int g = luaL_checknumber(L, 7);
	int b = luaL_checknumber(L, 8);

	SDL_Color color = {r,g,b};
	SDL_Surface *txt = TTF_RenderUTF8_Solid(*f, str, color);
dg's avatar
dg committed
	if (txt)
	{
dg's avatar
dg committed
		sdlDrawImage(*s, txt, x, y);
dg's avatar
dg committed
		SDL_FreeSurface(txt);
	}

	return 0;
}

dg's avatar
dg committed
static int sdl_surface_drawstring_newsurface(lua_State *L)
{
	TTF_Font **f = (TTF_Font**)auxiliar_checkclass(L, "sdl{font}", 1);
	const char *str = luaL_checkstring(L, 2);
	int r = luaL_checknumber(L, 3);
	int g = luaL_checknumber(L, 4);
	int b = luaL_checknumber(L, 5);

	SDL_Color color = {r,g,b};
	SDL_Surface *txt = TTF_RenderUTF8_Solid(*f, str, color);
dg's avatar
dg committed
	if (txt)
	{
		SDL_Surface **s = (SDL_Surface**)lua_newuserdata(L, sizeof(SDL_Surface*));
		auxiliar_setclass(L, "sdl{surface}", -1);
dg's avatar
dg committed
		*s = SDL_DisplayFormatAlpha(txt);
		SDL_FreeSurface(txt);
dg's avatar
dg committed
		return 1;
	}

	lua_pushnil(L);
	return 1;
}

dg's avatar
dg committed


static int sdl_new_tile(lua_State *L)
{
	int w = luaL_checknumber(L, 1);
	int h = luaL_checknumber(L, 2);
	TTF_Font **f = (TTF_Font**)auxiliar_checkclass(L, "sdl{font}", 3);
	const char *str = luaL_checkstring(L, 4);
	int x = luaL_checknumber(L, 5);
	int y = luaL_checknumber(L, 6);
	int r = luaL_checknumber(L, 7);
	int g = luaL_checknumber(L, 8);
	int b = luaL_checknumber(L, 9);
	int br = luaL_checknumber(L, 10);
	int bg = luaL_checknumber(L, 11);
	int bb = luaL_checknumber(L, 12);
	int alpha = luaL_checknumber(L, 13);

	SDL_Color color = {r,g,b};
	SDL_Surface *txt = TTF_RenderUTF8_Blended(*f, str, color);

dg's avatar
dg committed
	SDL_Surface **s = (SDL_Surface**)lua_newuserdata(L, sizeof(SDL_Surface*));
	auxiliar_setclass(L, "sdl{surface}", -1);

dg's avatar
dg committed
	Uint32 rmask, gmask, bmask, amask;
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
	rmask = 0xff000000;
	gmask = 0x00ff0000;
	bmask = 0x0000ff00;
	amask = 0x000000ff;
#else
	rmask = 0x000000ff;
	gmask = 0x0000ff00;
	bmask = 0x00ff0000;
	amask = 0xff000000;
#endif

	*s = SDL_CreateRGBSurface(
		SDL_SWSURFACE | SDL_SRCALPHA,
		w,
		h,
		32,
		rmask, gmask, bmask, amask
		);
dg's avatar
dg committed

dg's avatar
dg committed
	SDL_FillRect(*s, NULL, SDL_MapRGBA((*s)->format, br, bg, bb, alpha));
dg's avatar
dg committed

dg's avatar
dg committed
	if (txt)
	{
		if (!alpha) SDL_SetAlpha(txt, 0, 0);
dg's avatar
dg committed
		sdlDrawImage(*s, txt, x, y);
		SDL_FreeSurface(txt);
	}

	return 1;
}

dg's avatar
dg committed
static int sdl_new_surface(lua_State *L)
{
	int w = luaL_checknumber(L, 1);
	int h = luaL_checknumber(L, 2);

	SDL_Surface **s = (SDL_Surface**)lua_newuserdata(L, sizeof(SDL_Surface*));
	auxiliar_setclass(L, "sdl{surface}", -1);
dg's avatar
dg committed

	Uint32 rmask, gmask, bmask, amask;
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
	rmask = 0xff000000;
	gmask = 0x00ff0000;
	bmask = 0x0000ff00;
	amask = 0x000000ff;
#else
	rmask = 0x000000ff;
	gmask = 0x0000ff00;
	bmask = 0x00ff0000;
	amask = 0xff000000;
#endif

	*s = SDL_CreateRGBSurface(
		SDL_SWSURFACE | SDL_SRCALPHA,
		w,
		h,
		32,
		rmask, gmask, bmask, amask
		);

        if (s == NULL)
          printf("ERROR : SDL_CreateRGBSurface : %s\n",SDL_GetError());

dg's avatar
dg committed
	return 1;
}

dg's avatar
dg committed
static int sdl_load_image(lua_State *L)
{
	const char *name = luaL_checkstring(L, 1);

	SDL_Surface **s = (SDL_Surface**)lua_newuserdata(L, sizeof(SDL_Surface*));
	auxiliar_setclass(L, "sdl{surface}", -1);

	*s = IMG_Load_RW(PHYSFSRWOPS_openRead(name), TRUE);
dg's avatar
dg committed
	if (!*s) return 0;
dg's avatar
dg committed

	return 1;
}

dg's avatar
dg committed
static int sdl_free_surface(lua_State *L)
{
	SDL_Surface **s = (SDL_Surface**)auxiliar_checkclass(L, "sdl{surface}", 1);
	SDL_FreeSurface(*s);
	lua_pushnumber(L, 1);
	return 1;
}
dg's avatar
dg committed

static int lua_display_char(lua_State *L)
{
dg's avatar
dg committed
	SDL_Surface **s = (SDL_Surface**)auxiliar_checkclass(L, "sdl{surface}", 1);
	const char *c = luaL_checkstring(L, 2);
	int x = luaL_checknumber(L, 3);
	int y = luaL_checknumber(L, 4);
	int r = luaL_checknumber(L, 5);
	int g = luaL_checknumber(L, 6);
	int b = luaL_checknumber(L, 7);
dg's avatar
dg committed

dg's avatar
dg committed
	display_put_char(*s, c[0], x, y, r, g, b);
dg's avatar
dg committed

	return 0;
}

dg's avatar
dg committed
static int sdl_surface_erase(lua_State *L)
{
	SDL_Surface **s = (SDL_Surface**)auxiliar_checkclass(L, "sdl{surface}", 1);
dg's avatar
dg committed
	int r = lua_tonumber(L, 2);
	int g = lua_tonumber(L, 3);
	int b = lua_tonumber(L, 4);
dg's avatar
dg committed
	int a = lua_isnumber(L, 5) ? lua_tonumber(L, 5) : 255;
dg's avatar
dg committed
	if (lua_isnumber(L, 6))
	{
		SDL_Rect rect;
		rect.x = lua_tonumber(L, 6);
		rect.y = lua_tonumber(L, 7);
		rect.w = lua_tonumber(L, 8);
		rect.h = lua_tonumber(L, 9);
		SDL_FillRect(*s, &rect, SDL_MapRGBA((*s)->format, r, g, b, a));
	}
	else
		SDL_FillRect(*s, NULL, SDL_MapRGBA((*s)->format, r, g, b, a));
dg's avatar
dg committed
	return 0;
}

dg's avatar
dg committed
static int sdl_surface_get_size(lua_State *L)
{
	SDL_Surface **s = (SDL_Surface**)auxiliar_checkclass(L, "sdl{surface}", 1);
	lua_pushnumber(L, (*s)->w);
	lua_pushnumber(L, (*s)->h);
	return 2;
}

dg's avatar
dg committed

static void draw_textured_quad(int x, int y, int w, int h) {
	// In case we can't support NPOT textures, the tex coords will be different
	// it might be more elegant to store the actual texture width/height somewhere.
	// it's possible to ask opengl for it but I have a suspicion that is slow.
	int realw=1;
	int realh=1;

	while (realw < w) realw *= 2;
	while (realh < h) realh *= 2;
dg's avatar
dg committed

	GLfloat texw = (GLfloat)w/realw;
	GLfloat texh = (GLfloat)h/realh;

	glBegin( GL_QUADS );
	glTexCoord2f(0,0); glVertex2f(0  + x, 0  + y);
	glTexCoord2f(0,texh); glVertex2f(0  + x, h + y);
	glTexCoord2f(texw,texh); glVertex2f(w + x, h + y);
	glTexCoord2f(texw,0); glVertex2f(w + x, 0  + y);
dg's avatar
dg committed

static GLenum sdl_gl_texture_format(SDL_Surface *s) {
dg's avatar
dg committed
	// get the number of channels in the SDL surface
dg's avatar
dg committed
	GLenum texture_format;
	if (nOfColors == 4)     // contains an alpha channel
	{
dg's avatar
dg committed
			texture_format = GL_RGBA;
		else
			texture_format = GL_BGRA;
	} else if (nOfColors == 3)     // no alpha channel
	{
dg's avatar
dg committed
			texture_format = GL_RGB;
		else
			texture_format = GL_BGR;
	} else {
		printf("warning: the image is not truecolor..  this will probably break %d\n", nOfColors);
		// this error should not go unhandled
	}

// allocate memory for a texture without copying pixels in
// caller binds texture
static void make_texture_for_surface(SDL_Surface *s) {
	// Paramtrage de la texture.
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

	// get the number of channels in the SDL surface
	GLint nOfColors = s->format->BytesPerPixel;
	GLenum texture_format = sdl_gl_texture_format(s);
	// In case we can't support NPOT textures round up to nearest POT
	int realw=1;
	int realh=1;

	while (realw < s->w) realw *= 2;
	while (realh < s->h) realh *= 2;

	//printf("request size (%d,%d), producing size (%d,%d)\n",s->w,s->h,realw,realh);

	glTexImage2D(GL_TEXTURE_2D, 0, nOfColors, realw, realh, 0, texture_format, GL_UNSIGNED_BYTE, NULL);
dg's avatar
dg committed

		printf("make_texture_for_surface: glTexImage2D : %s\n",gluErrorString(err));
}

// copy pixels into previous allocated surface
static void copy_surface_to_texture(SDL_Surface *s) {
	GLenum texture_format = sdl_gl_texture_format(s);

	glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, s->w, s->h, texture_format, GL_UNSIGNED_BYTE, s->pixels);

	GLenum err = glGetError();
	if (err != GL_NO_ERROR) {
		printf("copy_surface_to_texture : glTexSubImage2D : %s\n",gluErrorString(err));
	}
}
static int sdl_surface_toscreen(lua_State *L)
{
	SDL_Surface **s = (SDL_Surface**)auxiliar_checkclass(L, "sdl{surface}", 1);
	int x = luaL_checknumber(L, 2);
	int y = luaL_checknumber(L, 3);
dg's avatar
dg committed
	if (lua_isnumber(L, 4))
	{
		float r = luaL_checknumber(L, 4);
		float g = luaL_checknumber(L, 5);
		float b = luaL_checknumber(L, 6);
		float a = luaL_checknumber(L, 7);
		glColor4f(r, g, b, a);
	}

	GLuint t;
	glGenTextures(1, &t);
	glBindTexture(GL_TEXTURE_2D, t);

	make_texture_for_surface(*s);
	copy_surface_to_texture(*s);
dg's avatar
dg committed
	draw_textured_quad(x,y,(*s)->w,(*s)->h);
dg's avatar
dg committed

	glDeleteTextures(1, &t);

dg's avatar
dg committed
	if (lua_isnumber(L, 4)) glColor4f(1, 1, 1, 1);

dg's avatar
dg committed
	return 0;
}

static int sdl_surface_toscreen_with_texture(lua_State *L)
{
	SDL_Surface **s = (SDL_Surface**)auxiliar_checkclass(L, "sdl{surface}", 1);
	GLuint *t = (GLuint*)auxiliar_checkclass(L, "gl{texture}", 2);
	int x = luaL_checknumber(L, 3);
	int y = luaL_checknumber(L, 4);
dg's avatar
dg committed
	if (lua_isnumber(L, 5))
	{
		float r = luaL_checknumber(L, 5);
		float g = luaL_checknumber(L, 6);
		float b = luaL_checknumber(L, 7);
		float a = luaL_checknumber(L, 8);
		glColor4f(r, g, b, a);
	}
	copy_surface_to_texture(*s);
dg's avatar
dg committed
	draw_textured_quad(x,y,(*s)->w,(*s)->h);
dg's avatar
dg committed
	if (lua_isnumber(L, 5)) glColor4f(1, 1, 1, 1);

dg's avatar
dg committed
static int sdl_surface_to_texture(lua_State *L)
{
	SDL_Surface **s = (SDL_Surface**)auxiliar_checkclass(L, "sdl{surface}", 1);

	GLuint *t = (GLuint*)lua_newuserdata(L, sizeof(GLuint));
	auxiliar_setclass(L, "gl{texture}", -1);

	glGenTextures(1, t);
	glBindTexture(GL_TEXTURE_2D, *t);

	make_texture_for_surface(*s);
	copy_surface_to_texture(*s);
dg's avatar
dg committed

	return 1;
}

dg's avatar
dg committed
static int sdl_surface_merge(lua_State *L)
{
	SDL_Surface **dst = (SDL_Surface**)auxiliar_checkclass(L, "sdl{surface}", 1);
	SDL_Surface **src = (SDL_Surface**)auxiliar_checkclass(L, "sdl{surface}", 2);
	int x = luaL_checknumber(L, 3);
	int y = luaL_checknumber(L, 4);
	if (dst && *dst && src && *src)
	{
dg's avatar
dg committed
		sdlDrawImage(*dst, *src, x, y);
dg's avatar
dg committed
	}
	return 0;
}

dg's avatar
dg committed
static int sdl_surface_alpha(lua_State *L)
{
	SDL_Surface **s = (SDL_Surface**)auxiliar_checkclass(L, "sdl{surface}", 1);
	int a = luaL_checknumber(L, 2);
dg's avatar
dg committed
	SDL_SetAlpha(*s, SDL_SRCALPHA | SDL_RLEACCEL, (a < 0) ? 0 : (a > 255) ? 255 : a);
dg's avatar
dg committed
	return 0;
}

dg's avatar
dg committed
static int sdl_free_texture(lua_State *L)
{
	GLuint *t = (GLuint*)auxiliar_checkclass(L, "gl{texture}", 1);
	glDeleteTextures(1, t);
	lua_pushnumber(L, 1);
	return 1;
}

static int sdl_texture_toscreen(lua_State *L)
{
	GLuint *t = (GLuint*)auxiliar_checkclass(L, "gl{texture}", 1);
	int x = luaL_checknumber(L, 2);
	int y = luaL_checknumber(L, 3);
dg's avatar
dg committed
	int w = luaL_checknumber(L, 4);
	int h = luaL_checknumber(L, 5);
dg's avatar
dg committed
	if (lua_isnumber(L, 6))
	{
		float r = luaL_checknumber(L, 6);
		float g = luaL_checknumber(L, 7);
		float b = luaL_checknumber(L, 8);
		float a = luaL_checknumber(L, 9);
		glColor4f(r, g, b, a);
	}
dg's avatar
dg committed

	glBindTexture(GL_TEXTURE_2D, *t);
	glBegin( GL_QUADS );                 /* Draw A Quad              */
	glTexCoord2f(0,0); glVertex2f(0  + x, 0  + y);
dg's avatar
dg committed
	glTexCoord2f(0,1); glVertex2f(0  + x, h + y);
	glTexCoord2f(1,1); glVertex2f(w + x, h + y);
	glTexCoord2f(1,0); glVertex2f(w + x, 0  + y);
dg's avatar
dg committed
	glEnd( );                            /* Done Drawing The Quad    */

dg's avatar
dg committed
	if (lua_isnumber(L, 6)) glColor4f(1, 1, 1, 1);
dg's avatar
dg committed
	return 0;
}

dg's avatar
dg committed
static int sdl_set_window_title(lua_State *L)
{
	const char *title = luaL_checkstring(L, 1);
	SDL_WM_SetCaption(title, NULL);
	return 0;
}

static int sdl_set_window_size(lua_State *L)
{
	int w = luaL_checknumber(L, 1);
	int h = luaL_checknumber(L, 2);
	bool fullscreen = lua_toboolean(L, 3);

dg's avatar
dg committed
	do_resize(w, h, fullscreen);
dg's avatar
dg committed

	lua_pushboolean(L, TRUE);
	return 1;
}
dg's avatar
dg committed

dg's avatar
dg committed
extern void on_redraw();
static int sdl_redraw_screen(lua_State *L)
{
	on_redraw();
	return 0;
}

dg's avatar
dg committed
static const struct luaL_reg displaylib[] =
dg's avatar
dg committed
{
dg's avatar
dg committed
	{"forceRedraw", sdl_redraw_screen},
dg's avatar
dg committed
	{"fullscreen", sdl_fullscreen},
dg's avatar
dg committed
	{"size", sdl_screen_size},
dg's avatar
dg committed
	{"newFont", sdl_new_font},
dg's avatar
dg committed
	{"newSurface", sdl_new_surface},
dg's avatar
dg committed
	{"newTile", sdl_new_tile},
dg's avatar
dg committed
	{"drawStringNewSurface", sdl_surface_drawstring_newsurface},
dg's avatar
dg committed
	{"loadImage", sdl_load_image},
dg's avatar
dg committed
	{"setWindowTitle", sdl_set_window_title},
dg's avatar
dg committed
	{"setWindowSize", sdl_set_window_size},
dg's avatar
dg committed
	{NULL, NULL},
};

static const struct luaL_reg sdl_surface_reg[] =
{
	{"__gc", sdl_free_surface},
	{"close", sdl_free_surface},
	{"erase", sdl_surface_erase},
dg's avatar
dg committed
	{"getSize", sdl_surface_get_size},
dg's avatar
dg committed
	{"merge", sdl_surface_merge},
dg's avatar
dg committed
	{"toScreen", sdl_surface_toscreen},
	{"toScreenWithTexture", sdl_surface_toscreen_with_texture},
dg's avatar
dg committed
	{"putChar", lua_display_char},
dg's avatar
dg committed
	{"drawString", sdl_surface_drawstring},
dg's avatar
dg committed
	{"alpha", sdl_surface_alpha},
dg's avatar
dg committed
	{"glTexture", sdl_surface_to_texture},
	{NULL, NULL},
};

static const struct luaL_reg sdl_texture_reg[] =
{
	{"__gc", sdl_free_texture},
	{"close", sdl_free_texture},
	{"toScreen", sdl_texture_toscreen},
dg's avatar
dg committed
	{NULL, NULL},
};

dg's avatar
dg committed
static const struct luaL_reg sdl_font_reg[] =
{
	{"__gc", sdl_free_font},
	{"close", sdl_free_font},
dg's avatar
dg committed
	{"size", sdl_font_size},
	{"height", sdl_font_height},
	{"lineSkip", sdl_font_lineskip},
dg's avatar
dg committed
	{NULL, NULL},
};
dg's avatar
dg committed

dg's avatar
dg committed
/******************************************************************
 ******************************************************************
 *                              RNG                               *
 ******************************************************************
 ******************************************************************/

static int rng_dice(lua_State *L)
{
	int x = luaL_checknumber(L, 1);
	int y = luaL_checknumber(L, 2);
	int i, res = 0;
	for (i = 0; i < x; i++)
		res += 1 + rand_div(y);
	lua_pushnumber(L, res);
	return 1;
}

static int rng_range(lua_State *L)
{
	int x = luaL_checknumber(L, 1);
	int y = luaL_checknumber(L, 2);
dg's avatar
dg committed
	int res = x + rand_div(1 + y - x);
	lua_pushnumber(L, res);
dg's avatar
dg committed
	return 1;
}

dg's avatar
dg committed
static int rng_avg(lua_State *L)
{
	int x = luaL_checknumber(L, 1);
	int y = luaL_checknumber(L, 2);
	int nb = 2;
	double res = 0;
	int i;
	if (lua_isnumber(L, 3)) nb = luaL_checknumber(L, 3);
	for (i = 0; i < nb; i++)
dg's avatar
dg committed
	{
		int r = x + rand_div(1 + y - x);
		res += r;