From a780d11c48d0901a9e019687ce127a1d4f4672fb Mon Sep 17 00:00:00 2001
From: Kyle K <kylek389@gmail.com>
Date: Mon, 18 Jul 2011 11:03:31 -0500
Subject: sdl: implement loading config file using Lua

---
 sdl/Makefile   |  13 +++--
 sdl/config.lua |  14 +++++
 sdl/luatools.c | 163 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 sdl/luatools.h |  28 ++++++++++
 sdl/mingw32    |   4 +-
 sdl/platform.c | 112 +++++++++++++++++++++++++++++++++++++--
 sdl/platform.h |  35 +++++++++++++
 sdl/pyramid.c  |  91 +++++---------------------------
 sdl/sdltools.c |   6 ++-
 sdl/sdltools.h |   2 -
 sdl/window.c   |   2 +-
 11 files changed, 376 insertions(+), 94 deletions(-)
 create mode 100644 sdl/config.lua
 create mode 100644 sdl/luatools.c
 create mode 100644 sdl/luatools.h

diff --git a/sdl/Makefile b/sdl/Makefile
index 269c69e..d6df1f7 100644
--- a/sdl/Makefile
+++ b/sdl/Makefile
@@ -1,6 +1,6 @@
 BIN = pyramid
 SRC = pyramid.c math3d.c gltools.c glframe.c shader.c platform.c window.c \
-      gldraw.c sdltools.c
+      gldraw.c sdltools.c luatools.c
 CC = gcc
 CFLAGS = -Wall -std=gnu99
 DBGFLAGS = -g -O0
@@ -9,7 +9,7 @@ ifdef DEBUG
 else
     CFLAGS += -O2 -march=native -mtune=native
 endif
-LDFLAGS = -lGLEW -lGL -lGLU -lm -lglut
+LDFLAGS = -lGLEW -lGL -lGLU -lm -lglut -llua
 SDL_CFLAGS := $(shell sdl-config --cflags)
 SDL_LDFLAGS := $(shell sdl-config --libs)
 SDL_image_CFLAGS := $(shell pkg-config --cflags SDL_image)
@@ -21,7 +21,7 @@ OBJ_FILES = $(addprefix $(OBJ_DIR)/, $(addsuffix .o, $(subst .c,,$(SRC))))
 $(BIN): $(OBJ_DIR) $(OBJ_FILES)
 	$(CC) $(LDFLAGS) $(SDL_LDFLAGS) $(SDL_image_LDFLAGS) $(OBJ_FILES) -o $@
 
-$(OBJ_DIR)/pyramid.o: $(OBJ_DIR)/%.o: %.c math3d.h gltools.h glframe.h platform.h sdltools.h
+$(OBJ_DIR)/pyramid.o: $(OBJ_DIR)/%.o: %.c gldraw.h glframe.h gltools.h luatools.h math3d.h platform.h sdltools.h window.h
 	$(CC) -c $(CFLAGS) $(SDL_CFLAGS) $(SDL_image_CFLAGS) $< -o $@
 
 $(OBJ_DIR)/math3d.o: $(OBJ_DIR)/%.o: %.c %.h
@@ -30,7 +30,7 @@ $(OBJ_DIR)/math3d.o: $(OBJ_DIR)/%.o: %.c %.h
 $(OBJ_DIR)/gltools.o: $(OBJ_DIR)/%.o: %.c %.h
 	$(CC) -c $(CFLAGS) $< -o $@
 
-$(OBJ_DIR)/glframe.o: $(OBJ_DIR)/%.o: %.c %.h math3d.h
+$(OBJ_DIR)/glframe.o: $(OBJ_DIR)/%.o: %.c %.h math3d.h glframe.h luatools.h gldraw.h gltools.h luatools.h sdltools.h
 	$(CC) -c $(CFLAGS) $< -o $@
 
 $(OBJ_DIR)/shader.o: $(OBJ_DIR)/%.o: %.c %.h
@@ -45,7 +45,10 @@ $(OBJ_DIR)/window.o: $(OBJ_DIR)/%.o: %.c %.h
 $(OBJ_DIR)/gldraw.o: $(OBJ_DIR)/%.o: %.c %.h math3d.h
 	$(CC) -c $(CFLAGS) $< -o $@
 
-$(OBJ_DIR)/sdltools.o: $(OBJ_DIR)/%.o: %.c %.h math3d.h
+$(OBJ_DIR)/sdltools.o: $(OBJ_DIR)/%.o: %.c %.h math3d.h glframe.h
+	$(CC) -c $(CFLAGS) $< -o $@
+
+$(OBJ_DIR)/luatools.o: $(OBJ_DIR)/%.o: %.c %.h math3d.h
 	$(CC) -c $(CFLAGS) $< -o $@
 
 $(OBJ_DIR):
diff --git a/sdl/config.lua b/sdl/config.lua
new file mode 100644
index 0000000..34a7920
--- /dev/null
+++ b/sdl/config.lua
@@ -0,0 +1,14 @@
+platform =
+{
+    name   = "Textured Pyramid",
+    icon   = "tux.png",
+    xres   = 640,
+    yres   = 480,
+    bpp    = 32,
+    af     = 8,
+    fovy   = 40.0,
+    znear  = 1.0,
+    zfar   = 40.0,
+    maxfps = 60
+}
+
diff --git a/sdl/luatools.c b/sdl/luatools.c
new file mode 100644
index 0000000..5116df1
--- /dev/null
+++ b/sdl/luatools.c
@@ -0,0 +1,163 @@
+/* luatools.c
+ *
+ * Lua Tools
+ *
+ *
+ */
+
+#include <lauxlib.h>
+#include <lualib.h>
+#include <stdio.h>
+#include <string.h>
+#include "luatools.h"
+
+const char *luaGetFieldString(lua_State *L, const char *key)
+{
+    if (!L || !key)
+        return NULL;
+
+    const char *ret = NULL;
+
+    /* push the key string onto stack */
+    lua_pushstring(L, key);
+
+    lua_gettable(L, -2);
+    if (!lua_isstring(L, -1))
+    {
+        fprintf(stderr, "Lua: \"%s\" field within the table is not a string\n", key);
+        lua_pop(L, 1);
+
+        return ret;
+    }
+
+    ret = lua_tostring(L, -1);
+    lua_pop(L, 1);
+
+    return ret;
+}
+
+double luaGetFieldNumber(lua_State *L, const char *key)
+{
+    if (!L || !key)
+        return -1.0;
+
+    double ret = -1.0;
+
+    /* push the key string onto stack */
+    lua_pushstring(L, key);
+
+    /* remember, -1 points to top of the stack, our table should a second
+     * item from the top, this call effectively accesses t[key] and
+     * pushes that value on the stack */
+    lua_gettable(L, -2);
+    if (!lua_isnumber(L, -1))
+    {
+        fprintf(stderr, "Lua: \"%s\" field within the table is NaN\n", key);
+        lua_pop(L, 1);
+
+        return ret;
+    }
+
+    /* finally retrieve our value */
+    ret = lua_tonumber(L, -1);
+
+    /* value is no longer needed, pop it */
+    lua_pop(L, 1);
+
+    return ret;
+}
+
+int luaLoadConfig(lua_State *L, const char *fname)
+{
+    if (!L || !fname)
+        return -1;
+
+    int status;
+
+    /* load the file containing the config */
+    /* call a function, what function? dry run the script? */
+    status = (luaL_loadfile(L, fname) || lua_pcall(L, 0, 0, 0));
+    if (status)
+    {
+        fprintf(stderr, "Lua: %s\n", lua_tostring(L, -1));
+        return -1;
+    }
+
+    return 0;
+}
+
+int luaFillTablePlatform(lua_State *L, struct luat_table_platform *p)
+{
+    if (!L || !p)
+        return -1;
+
+    double ret;
+    const char *ret_str = NULL;
+
+    /* pushes the table on the stack */
+    lua_getglobal(L, "platform");
+
+    if (!lua_istable(L, -1))
+    {
+        fprintf(stderr, "Lua: failed to parse \"platform\" table\n");
+        lua_pop(L, 1);
+        return -1;
+    }
+
+    if ((ret_str = luaGetFieldString(L, "name")) != NULL)
+        p->name  = ret_str;
+
+    if ((ret_str = luaGetFieldString(L, "icon")) != NULL)
+        p->icon  = ret_str;
+
+    if ((ret = luaGetFieldNumber(L, "xres")) != -1.0)
+        p->xres  = (unsigned int) ret;
+
+    if ((ret = luaGetFieldNumber(L, "yres")) != -1.0)
+        p->yres  = (unsigned int) ret;
+
+    if ((ret = luaGetFieldNumber(L, "bpp")) != -1.0)
+        p->bpp   = (unsigned int) ret;
+
+    if ((ret = luaGetFieldNumber(L, "af")) != -1.0)
+        p->af   = (unsigned int) ret;
+
+    if ((ret = luaGetFieldNumber(L, "fovy")) != -1.0)
+        p->fovy  = (float) ret;
+
+    if ((ret = luaGetFieldNumber(L, "znear")) != -1.0)
+        p->znear = (float) ret;
+
+    if ((ret = luaGetFieldNumber(L, "zfar")) != -1.0)
+        p->zfar  = (float) ret;
+
+    if ((ret = luaGetFieldNumber(L, "maxfps")) != -1.0)
+        p->maxfps   = (unsigned int) ret;
+
+    /* pop the table */
+    lua_pop(L, 1);
+
+    return 0;
+}
+
+void luaPrintTablePlatform(struct luat_table_platform *p)
+{
+    if (!p)
+        return;
+
+    printf("-- Lua platform config file --\n"
+           "  name  : %s\n"
+           "  icon  : %s\n"
+           "  xres  : %u\n"
+           "  yres  : %u\n"
+           "  bpp   : %u\n"
+           "  af    : %u\n"
+           "  fovy  : %f\n"
+           "  znear : %f\n"
+           "  zfar  : %f\n"
+           "  maxfps: %u\n",
+           p->name, p->icon, p->xres, p->yres, p->bpp, p->af,
+           p->fovy, p->znear, p->zfar, p->maxfps);
+    puts("");
+}
+
diff --git a/sdl/luatools.h b/sdl/luatools.h
new file mode 100644
index 0000000..e05cb6b
--- /dev/null
+++ b/sdl/luatools.h
@@ -0,0 +1,28 @@
+#ifndef _LUATOOLS_H_
+#define _LUATOOLS_H_
+
+#include <lua.h>
+
+/* lua table to c struct converter would be very useful */
+struct luat_table_platform
+{
+    const char *name;
+    const char *icon;
+    unsigned int xres;
+    unsigned int yres;
+    unsigned int bpp;
+    unsigned int af;
+    float fovy;
+    float znear;
+    float zfar;
+    unsigned int maxfps;
+};
+
+const char *luaGetFieldString(lua_State *L, const char *);
+double luaGetFieldNumber(lua_State *, const char *);
+int luaLoadConfig(lua_State *, const char *);
+int luaFillTablePlatform(lua_State *, struct luat_table_platform *);
+void luaPrintTablePlatform(struct luat_table_platform *);
+
+#endif
+
diff --git a/sdl/mingw32 b/sdl/mingw32
index 591f975..1607875 100644
--- a/sdl/mingw32
+++ b/sdl/mingw32
@@ -1,6 +1,6 @@
 BIN = pyramid
 SRC = pyramid.c math3d.c gltools.c glframe.c shader.c platform.c window.c \
-      gldraw.c sdltools.c
+      gldraw.c sdltools.c luatools.c
 CC = gcc
 CFLAGS = -Wall -std=c99 -MD
 DBGFLAGS = -g -O0
@@ -9,7 +9,7 @@ ifdef DEBUG
 else
     CFLAGS += -O2 -march=native -mtune=native
 endif
-LDFLAGS = -lglew32 -lopengl32 -lglu32 -lm -lfreeglut -lmingw32 -lsdlmain -lsdl -lsdl_image -mwindows
+LDFLAGS = -lglew32 -lopengl32 -lglu32 -lm -lfreeglut -lmingw32 -lsdlmain -lsdl -lsdl_image -mwindows -llua
 
 OBJ_DIR = obj
 DEPS_DIR = obj
diff --git a/sdl/platform.c b/sdl/platform.c
index aba5789..a44bfd4 100644
--- a/sdl/platform.c
+++ b/sdl/platform.c
@@ -6,11 +6,17 @@
  *
  */
 
+#include <lauxlib.h>
+#include <lualib.h>
 #include <SDL/SDL.h>
 #include <SDL/SDL_image.h>
 #include <GL/glew.h>
+#include <string.h>
+#include "gldraw.h"
 #include "gltools.h"
+#include "luatools.h"
 #include "platform.h"
+#include "sdltools.h"
 
 /* few light arrays */
 const GLfloat fNoLight[]     = { 0.0f, 0.0f, 0.0f, 1.0f    };
@@ -23,13 +29,109 @@ const GLfloat fBrightLight[] = { 1.0f, 1.0f, 1.0f, 1.0f    };
 const GLfloat lightPos[]    = { -10.f, 5.0f, 5.0f, 1.0f   };
 
 /* variables that should be already defined and declared for us by main program */
-extern const unsigned int xres_w;
-extern const unsigned int yres_w;
-extern const unsigned int bpp_w;
-extern const unsigned int af_w;
-extern const unsigned int sdl_video_flags;
+extern unsigned int xres_w;
+extern unsigned int yres_w;
+extern unsigned int bpp_w;
+extern unsigned int af_w;
 extern const char *window_caption;
 extern const char *window_icon_path;
+extern const unsigned int sdl_video_flags;
+extern unsigned int maxfps_w;
+
+void platform_init(struct platform *p)
+{
+    memset(p, 0, sizeof(struct platform));
+
+    /* Lua */
+    /* create new lua state */
+    p->L = luaL_newstate();
+
+    /* load lua libraries */
+    luaL_openlibs(p->L);
+
+    /* ToDo: how would you make platform more generic? */
+    /* note, this should be already zero'ed out */
+    memset(&p->config_table, 0, sizeof(p->config_table));
+
+    /* initialize SDL, GLEW, and OpenGL */
+    load_config(p);
+    p->screen = setup_sdl();
+    setup_glew();
+    setup_opengl();
+
+    /* set the camera to <0,0,0> */
+    glframe_reset(&p->camera);
+    p->textures[0] = gltLoadTGATexture("stone.tga");
+    p->textures[1] = gltLoadTGATexture("grass.tga");
+
+    /* display list, precompile commands */
+    p->ground_list   = glGenLists(2);
+    p->triangle_list = p->ground_list + 1;
+
+    /* a triangle with a texture */
+    glNewList(p->triangle_list, GL_COMPILE);
+       glBindTexture(GL_TEXTURE_2D, p->textures[0]);
+       /* glBindTexture(GL_TEXTURE_2D, p->textures[1]); */
+       glColor3f(1.0f, 1.0f, 1.0f);
+       glDrawTriangle();
+    glEndList();
+
+    /* a ground drawn using magneta lines */
+    glNewList(p->ground_list, GL_COMPILE);
+       glColor3ub(255, 0, 255);
+       glDrawGround();
+    glEndList();
+
+    /* add a simple timer / callback function */
+    p->timer_id = SDL_AddTimer(5000, sdlTimerCallback, &(p->camera));
+
+    /* apply a custom cursor */
+    p->my_cursor = sdlInitCursor(arrow);
+    SDL_SetCursor(p->my_cursor);
+}
+
+void platform_destroy(struct platform *p)
+{
+    glDeleteTextures(2, p->textures);
+    glDeleteLists(p->ground_list, 2);
+
+    SDL_FreeSurface(p->screen);
+
+    lua_close(p->L);
+}
+
+/* load Lua config file from the disk */
+void load_config(struct platform *p)
+{
+    if (luaLoadConfig(p->L, "config.lua") ||
+        luaFillTablePlatform(p->L, &p->config_table) != -1)
+    {
+        /* print was was loaded from config.lua to stdout */
+        luaPrintTablePlatform(&p->config_table);
+
+        /* override any globals that config.lua redefines */
+        if (p->config_table.xres)
+            xres_w = p->config_table.xres;
+
+        if (p->config_table.yres)
+            yres_w = p->config_table.yres;
+
+        if (p->config_table.bpp)
+            bpp_w = p->config_table.bpp;
+
+        if (p->config_table.af)
+            af_w = p->config_table.af;
+
+        if (p->config_table.name)
+            window_caption = p->config_table.name;
+
+        if (p->config_table.icon)
+            window_icon_path = p->config_table.icon;
+
+        if (p->config_table.maxfps)
+            maxfps_w = p->config_table.maxfps;
+    }
+}
 
 void setup_opengl(void)
 {
diff --git a/sdl/platform.h b/sdl/platform.h
index 09028d1..dc34788 100644
--- a/sdl/platform.h
+++ b/sdl/platform.h
@@ -1,6 +1,38 @@
 #ifndef _PLATFORM_H_
 #define _PLATFORM_H_
 
+#include <SDL/SDL.h>
+#include <SDL/SDL_image.h>
+#include <GL/glew.h>
+#include "glframe.h"
+#include "luatools.h"
+
+/* platform struct */
+struct platform
+{
+    GLFrame camera;
+
+    /* display lists identifiers */
+    GLuint ground_list;
+    GLuint triangle_list;
+
+    /* pyramid texture handle */
+    GLuint textures[2];
+
+    GLfloat xrot;
+    GLfloat yrot;
+
+    /* SDL surface, our screen */
+    SDL_Surface *screen;
+
+    SDL_TimerID timer_id;
+    SDL_Cursor *my_cursor;
+
+    /* Lua */
+    lua_State *L;
+    struct luat_table_platform config_table;
+};
+
 extern const GLfloat fNoLight[];
 extern const GLfloat fLowLight[];
 extern const GLfloat fShinyLight[];
@@ -8,6 +40,9 @@ extern const GLfloat fBrightLight[];
 extern const GLfloat lightPos[];
 
 /* function prototypes */
+void platform_init(struct platform *);
+void platform_destroy(struct platform *);
+void load_config(struct platform *);
 void setup_opengl(void);
 SDL_Surface *setup_sdl_video(int, int, int, unsigned int);
 SDL_Surface *setup_sdl(void);
diff --git a/sdl/pyramid.c b/sdl/pyramid.c
index bc0fd7a..1260dff 100644
--- a/sdl/pyramid.c
+++ b/sdl/pyramid.c
@@ -14,6 +14,8 @@
  *
  * it might be time to split the code, and make a shader version...
  *
+ * ToDo: on linux, update the makefile dependencies, and check out lua-config
+ *
  */
 
 #include <SDL/SDL.h>
@@ -32,41 +34,21 @@
 /* function prototypes */
 static void keys(SDL_keysym *, const unsigned int *, const int);
 static void process_events(void);
-static void platform_init(void);
-static void platform_destroy(void);
 static void render(void);
 
-/* global */
+/* globals */
+struct platform p;
+
+/* sane defaults, these can be overwritten by config.lua */
 int program_running = 1;
-const unsigned int xres_w = 640;
-const unsigned int yres_w = 480;
-const unsigned int bpp_w  = 32;
-const unsigned int af_w   = 8;
+unsigned int xres_w = 640;
+unsigned int yres_w = 480;
+unsigned int bpp_w  = 32;
+unsigned int af_w   = 8;
 const char *window_caption   = "Textured Pyramid";
 const char *window_icon_path = "tux.png";
 const unsigned int sdl_video_flags = SDL_OPENGL | SDL_RESIZABLE;
-
-/* platform struct */
-static struct
-{
-    GLFrame camera;
-
-    /* display lists identifiers */
-    GLuint ground_list;
-    GLuint triangle_list;
-
-    /* pyramid texture handle */
-    GLuint textures[2];
-
-    GLfloat xrot;
-    GLfloat yrot;
-
-    /* SDL surface, our screen */
-    SDL_Surface *screen;
-
-    SDL_TimerID timer_id;
-    SDL_Cursor *my_cursor;
-} p;
+unsigned int maxfps_w  = 60;
 
 static void keys(SDL_keysym *keysym, const unsigned int *keys_held, const int flag)
 {
@@ -163,49 +145,6 @@ static void process_events(void)
         flag = !flag;
 }
 
-static void platform_init(void)
-{
-    memset(&p, 0, sizeof(p));
-
-    /* set the camera to <0,0,0> */
-    glframe_reset(&p.camera);
-    p.textures[0] = gltLoadTGATexture("stone.tga");
-    p.textures[1] = gltLoadTGATexture("grass.tga");
-
-    /* display list, precompile commands */
-    p.ground_list = glGenLists(2);
-    p.triangle_list = p.ground_list + 1;
-
-    /* a triangle with a texture */
-    glNewList(p.triangle_list, GL_COMPILE);
-       glBindTexture(GL_TEXTURE_2D, p.textures[0]);
-       /* glBindTexture(GL_TEXTURE_2D, p.textures[1]); */
-       glColor3f(1.0f, 1.0f, 1.0f);
-       glDrawTriangle();
-    glEndList();
-
-    /* a ground drawn using magneta lines */
-    glNewList(p.ground_list, GL_COMPILE);
-       glColor3ub(255, 0, 255);
-       glDrawGround();
-    glEndList();
-
-    /* add a simple timer / callback function */
-    p.timer_id = SDL_AddTimer(5000, sdlTimerCallback, &(p.camera));
-
-    /* apply a custom cursor */
-    p.my_cursor = sdlInitCursor(arrow);
-    SDL_SetCursor(p.my_cursor);
-}
-
-static void platform_destroy(void)
-{
-    glDeleteTextures(2, p.textures);
-    glDeleteLists(p.ground_list, 2);
-
-    SDL_FreeSurface(p.screen);
-}
-
 static void render(void)
 {
     /* clear the window with current clearing color */
@@ -243,10 +182,8 @@ static void render(void)
 
 int main(int argc, char **argv)
 {
-    p.screen = setup_sdl();
-    setup_glew();
-    setup_opengl();
-    platform_init();
+    platform_init(&p);
+
     gltErrorCheck();
     gltOpenGLInfo();
 
@@ -261,7 +198,7 @@ int main(int argc, char **argv)
         sdlFrameControl(startclock);
     }
 
-    platform_destroy();
+    platform_destroy(&p);
     puts("bye!");
 
     return 0;
diff --git a/sdl/sdltools.c b/sdl/sdltools.c
index c98a968..aea91bb 100644
--- a/sdl/sdltools.c
+++ b/sdl/sdltools.c
@@ -12,6 +12,8 @@
 #include "math3d.h"
 #include "glframe.h"
 
+extern unsigned int maxfps_w;
+
 /* creates a new mouse cursor from an XPM */
 const char *arrow[] = {
   /* width height num_colors chars_per_pixel */
@@ -59,8 +61,8 @@ const char *arrow[] = {
 inline void sdlFrameControl(const unsigned int startclock)
 {
     unsigned int deltaclock = SDL_GetTicks() - startclock;
-    if (deltaclock < 1000 / FRAMES_PER_SECOND)
-        SDL_Delay((1000 / FRAMES_PER_SECOND) - deltaclock);
+    if (deltaclock < 1000 / maxfps_w)
+        SDL_Delay((1000 / maxfps_w) - deltaclock);
 
 #ifdef STAT_FPS
     char buffer[30] = { 0 };
diff --git a/sdl/sdltools.h b/sdl/sdltools.h
index 63478ec..852096f 100644
--- a/sdl/sdltools.h
+++ b/sdl/sdltools.h
@@ -1,8 +1,6 @@
 #ifndef _SDL_TOOLS_
 #define _SDL_TOOLS_
 
-#define FRAMES_PER_SECOND 60
-
 extern const char *arrow[];
 
 /* function prototypes */
diff --git a/sdl/window.c b/sdl/window.c
index a96eef6..50bc72d 100644
--- a/sdl/window.c
+++ b/sdl/window.c
@@ -10,7 +10,7 @@
 #include <GL/glew.h>
 #include "window.h"
 
-extern const unsigned int bpp_w;
+extern unsigned int bpp_w;
 extern const unsigned int sdl_video_flags;
 
 void window_resize(int w, int h)
-- 
cgit v1.2.3