# HG changeset patch # User John Tsiombikas # Date 1430444210 -10800 # Node ID 45b91185b29839367e537bb64246ca693c5837d2 # Parent e3b9707504df8e257126bcd05145f2473bca2c8c android port diff -r e3b9707504df -r 45b91185b298 Makefile --- a/Makefile Mon Apr 27 05:37:17 2015 +0300 +++ b/Makefile Fri May 01 04:36:50 2015 +0300 @@ -1,14 +1,15 @@ -src = $(wildcard src/*.c) +include proj.mk +src += src/glut/main.c + obj = $(src:.c=.o) -bin = lab sys = $(shell uname -s) -libgl_Linux = -lGL -lGLU -lglut -libgl_Darwin = -framework OpenGL -framework GLUT +libgl_Linux = -lGL -lGLU -lglut -lGLEW +libgl_Darwin = -framework OpenGL -framework GLUT -lGLEW -CFLAGS = -pedantic -Wall -g -LDFLAGS = $(libgl_$(sys)) -lm +CFLAGS = -pedantic -Wall -g $(incpaths) +LDFLAGS = $(libpaths) $(libgl_$(sys)) -lm $(bin): $(obj) $(CC) -o $@ $(obj) $(LDFLAGS) diff -r e3b9707504df -r 45b91185b298 android/AndroidManifest.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/android/AndroidManifest.xml Fri May 01 04:36:50 2015 +0300 @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + diff -r e3b9707504df -r 45b91185b298 android/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/android/Makefile Fri May 01 04:36:50 2015 +0300 @@ -0,0 +1,78 @@ +root = .. +include $(root)/proj.mk + +# --- android settings --- +android_platform = android-22 +name = $(bin) +pkgprefix = com.mutantstargoat +# ------------------------ +native_app_glue_dir = $(NDK)/sources/android/native_app_glue + +src += $(wildcard $(root)/src/android/*.c) \ + $(wildcard $(root)/src/gles/*.c) \ + $(native_app_glue_dir)/android_native_app_glue.c + +obj = $(src:.c=.o) $(ccsrc:.cc=.o) +lib = libs/armeabi/lib$(name).so +apk-release = bin/$(name).apk +apk-debug = bin/$(name)-debug.apk + +pkg = $(pkgprefix).$(name) +act = android.app.NativeActivity + +CC = arm-linux-androideabi-gcc +CXX = arm-linux-androideabi-g++ + +android_usr = $(NDK)/platforms/$(android_platform)/arch-arm/usr +android_inc = -I$(android_usr)/include -I$(native_app_glue_dir) +android_libs = -L$(android_usr)/lib -llog -landroid -lEGL -lGLESv1_CM + +CFLAGS = -std=c99 -Wall -g -DAPP_NAME=\"$(name)\" \ + $(android_inc) -I$(root)/src/android -I$(root)/src/gles $(incpaths) +LDFLAGS = -Wl,--fix-cortex-a8 $(android_libs) $(libpaths) + +.PHONY: debug +debug: $(apk-debug) + +.PHONY: release +release: $(apk-release) + +$(apk-debug): $(lib) AndroidManifest.xml + ant debug + +$(apk-release): $(lib) AndroidManifest.xml + ant release + +.PHONY: lib +lib: $(lib) + +$(lib): $(obj) + @mkdir -p libs/armeabi + $(CC) -o $@ -shared $(obj) $(LDFLAGS) + +.PHONY: clean +clean: + rm -f $(obj) $(lib) $(apk-release) $(apk-debug) + +.PHONY: install +install: install-debug + +.PHONY: install-debug +install-debug: + adb install -r $(apk-debug) + +.PHONY: install-release +install-release: + adb install -r $(apk-release) + +.PHONY: run +run: + adb shell am start -n $(pkg)/$(act) + +.PHONY: stop +stop: + adb shell am force-stop $(pkg) + +.PHONY: update-project +update-project: build.xml + android update project --path . --target $(android_platform) diff -r e3b9707504df -r 45b91185b298 proj.mk --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/proj.mk Fri May 01 04:36:50 2015 +0300 @@ -0,0 +1,7 @@ +root ?= $(shell pwd) + +src = $(wildcard $(root)/src/*.c) +bin = labyrinth + +incpaths = -I$(root)/src +libpaths = diff -r e3b9707504df -r 45b91185b298 src/android/amain.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/android/amain.c Fri May 01 04:36:50 2015 +0300 @@ -0,0 +1,251 @@ +#include +#include +#include +#include +#include "logger.h" +#include "game.h" +#include "timer.h" + + +static void handle_command(struct android_app *app, int32_t cmd); +static int handle_input(struct android_app *app, AInputEvent *ev); +static int handle_touch_input(struct android_app *app, AInputEvent *ev); +static int init_gl(void); +static void destroy_gl(void); + +static EGLDisplay dpy; +static EGLSurface surf; +static EGLContext ctx; + +static struct android_app *app; +static int win_width, win_height; + +void android_main(struct android_app *app_ptr) +{ + app_dummy(); + app = app_ptr; + + app->onAppCmd = handle_command; + app->onInputEvent = handle_input; + + start_logger(); + + for(;;) { + int num_events; + struct android_poll_source *pollsrc; + + while(ALooper_pollAll(0, 0, &num_events, (void**)&pollsrc) >= 0) { + if(pollsrc) { + pollsrc->process(app, pollsrc); + } + } + + if(app->destroyRequested) { + return; + } + + game_display(get_time_msec()); + } +} + +void set_mouse_pos(int x, int y) +{ +} + +void set_mouse_cursor(int enable) +{ +} + +static void handle_command(struct android_app *app, int32_t cmd) +{ + switch(cmd) { + case APP_CMD_SAVE_STATE: + /* save the application state to be reloaded on restart if needed */ + break; + + case APP_CMD_INIT_WINDOW: + if(init_gl() == -1) { + exit(1); + } + /* initialize the application */ + if(game_init() == -1) { + exit(1); /* initialization failed, quit */ + } + break; + + case APP_CMD_TERM_WINDOW: + /* cleanup */ + game_shutdown(); + destroy_gl(); + break; + + case APP_CMD_GAINED_FOCUS: + /* app focused */ + break; + + case APP_CMD_LOST_FOCUS: + /* app lost focus */ + break; + + case APP_CMD_WINDOW_RESIZED: + case APP_CMD_CONFIG_CHANGED: + { + int nx = ANativeWindow_getWidth(app->window); + int ny = ANativeWindow_getHeight(app->window); + if(nx != win_width || ny != win_height) { + game_reshape(nx, ny); + win_width = nx; + win_height = ny; + } + } + break; + + default: + break; + } +} + +static int handle_input(struct android_app *app, AInputEvent *ev) +{ + int evtype = AInputEvent_getType(ev); + + switch(evtype) { + case AINPUT_EVENT_TYPE_MOTION: + return handle_touch_input(app, ev); + + default: + break; + } + return 0; +} + +#define MAX_TOUCH_IDS 32 + +static int handle_touch_input(struct android_app *app, AInputEvent *ev) +{ + int x, y, idx, touch_id; + unsigned int action; + static int prev_pos[MAX_TOUCH_IDS][2]; + + action = AMotionEvent_getAction(ev); + + idx = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> + AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; + touch_id = AMotionEvent_getPointerId(ev, idx); + + x = AMotionEvent_getX(ev, idx); + y = AMotionEvent_getY(ev, idx); + + switch(action & AMOTION_EVENT_ACTION_MASK) { + case AMOTION_EVENT_ACTION_DOWN: + case AMOTION_EVENT_ACTION_POINTER_DOWN: + game_mouse_button(touch_id, 0, 1, x, y); + if(touch_id < MAX_TOUCH_IDS) { + prev_pos[touch_id][0] = x; + prev_pos[touch_id][1] = y; + } + break; + + case AMOTION_EVENT_ACTION_UP: + case AMOTION_EVENT_ACTION_POINTER_UP: + game_mouse_button(touch_id, 0, 0, x, y); + if(touch_id < MAX_TOUCH_IDS) { + prev_pos[touch_id][0] = x; + prev_pos[touch_id][1] = y; + } + break; + + case AMOTION_EVENT_ACTION_MOVE: + { + int i, pcount = AMotionEvent_getPointerCount(ev); + for(i=0; iwindow, 0, 0, vis); + + if(!(surf = eglCreateWindowSurface(dpy, eglcfg, app->window, 0))) { + fprintf(stderr, "failed to create window\n"); + destroy_gl(); + return -1; + } + + if(!(ctx = eglCreateContext(dpy, eglcfg, EGL_NO_CONTEXT, ctxattr))) { + fprintf(stderr, "failed to create OpenGL ES context\n"); + destroy_gl(); + return -1; + } + eglMakeCurrent(dpy, surf, surf, ctx); + + eglQuerySurface(dpy, surf, EGL_WIDTH, &win_width); + eglQuerySurface(dpy, surf, EGL_HEIGHT, &win_height); + game_reshape(win_width, win_height); + + return 0; +} + +static void destroy_gl(void) +{ + if(!dpy) return; + + eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + + if(ctx) { + eglDestroyContext(dpy, ctx); + ctx = 0; + } + if(surf) { + eglDestroySurface(dpy, surf); + surf = 0; + } + + eglTerminate(dpy); + dpy = 0; +} + diff -r e3b9707504df -r 45b91185b298 src/android/logger.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/android/logger.c Fri May 01 04:36:50 2015 +0300 @@ -0,0 +1,60 @@ +#include +#include +#include +#include +#include +#include "logger.h" + +static void *thread_func(void *arg); + +static int pfd[2]; +static pthread_t thr; +static int initialized; + +int start_logger(void) +{ + if(initialized) { + return 1; + } + + /* set stdout to line-buffered, and stderr to unbuffered */ + setvbuf(stdout, 0, _IOLBF, 0); + setvbuf(stderr, 0, _IONBF, 0); + + if(pipe(pfd) == -1) { + perror("failed to create logging pipe"); + return -1; + } + assert(pfd[0] > 2 && pfd[1] > 2); + + /* redirect stdout & stderr to the write-end of the pipe */ + dup2(pfd[1], 1); + dup2(pfd[1], 2); + + /* start the logging thread */ + if(pthread_create(&thr, 0, thread_func, 0) == -1) { + perror("failed to spawn logging thread"); + return -1; + } + pthread_detach(thr); + return 0; +} + +static void *thread_func(void *arg) +{ + ssize_t rdsz; + char buf[257]; + + __android_log_print(ANDROID_LOG_DEBUG, APP_NAME, "logger starting up..."); + + while((rdsz = read(pfd[0], buf, sizeof buf - 1)) > 0) { + if(buf[rdsz - 1] == '\n') { + --rdsz; + } + buf[rdsz] = 0; + __android_log_write(ANDROID_LOG_DEBUG, APP_NAME, buf); + } + + __android_log_print(ANDROID_LOG_DEBUG, APP_NAME, "logger shutting down..."); + return 0; +} diff -r e3b9707504df -r 45b91185b298 src/android/logger.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/android/logger.h Fri May 01 04:36:50 2015 +0300 @@ -0,0 +1,6 @@ +#ifndef LOGGER_H_ +#define LOGGER_H_ + +int start_logger(void); + +#endif /* LOGGER_H_ */ diff -r e3b9707504df -r 45b91185b298 src/game.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/game.c Fri May 01 04:36:50 2015 +0300 @@ -0,0 +1,356 @@ +#include +#include +#include +#include "opengl.h" +#include "game.h" +#include "player.h" +#include "level.h" +#include "noise.h" +#include "texture.h" +#include "mesh.h" + +#define PLAYER_EYE_HEIGHT 1.65 + +static void draw_scene(unsigned long msec); + +static int win_width, win_height; +static struct level level; +static struct player player; +static int mouselook, freelook = 1; +static char keystate[256]; + +static struct mesh *monkey_mesh; +static unsigned int envmap; +static unsigned int win_tex; + +static int game_won; + +static float dbg_cam_dist = 0.0; + + +int game_init(void) +{ + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); + glEnable(GL_LIGHTING); + glEnable(GL_NORMALIZE); + + glEnable(GL_LIGHT0); + glEnable(GL_LIGHT1); + + /* set a slightly bluish cold ambient light */ + { + float ambient[] = {0.08, 0.1, 0.3, 1.0}; + glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient); + } + + level_init(&level); + if(level_load(&level, "data/0.level") == -1) { + fprintf(stderr, "level loading failed\n"); + return -1; + } + + if(!(level.wall_tex = load_texture("data/wall.ppm"))) { + return -1; + } + if(!(level.floor_tex = load_texture("data/floor.ppm"))) { + return -1; + } + level.floor_tex_scale = 1.0; + if(!(level.ceil_tex = load_texture("data/ceil.ppm"))) { + return -1; + } + level.ceil_tex_scale = 2.0; + + + if(!(monkey_mesh = load_mesh("data/monkey.obj"))) { + return -1; + } + if(!(envmap = load_texture("data/refmap.ppm"))) { + return -1; + } + + if(!(win_tex = load_texture("data/done.ppm"))) { + return -1; + } + + player_init(&player, &level); + return 0; +} + +void game_shutdown(void) +{ +} + +static void update(unsigned long msec) +{ + static unsigned long prev_upd; + float dfwd = 0.0f; + float dright = 0.0f; + float walk_speed = 8.0; + + float dt = (float)(msec - prev_upd) / 1000.0f; + prev_upd = msec; + + if(game_won) return; + + if(freelook) { + if(keystate['w'] || keystate['W']) { + dfwd += walk_speed * dt; + } + if(keystate['s'] || keystate['S']) { + dfwd -= walk_speed * dt; + } + if(keystate['d'] || keystate['D']) { + dright += walk_speed * dt * 0.6; + } + if(keystate['a'] || keystate['A']) { + dright -= walk_speed * dt * 0.6; + } + + player_move(&player, dfwd, dright); + } + + if(level_cell_at(&level, player.x, player.y) == 'x') { + game_won = 1; + } +} + +void game_display(unsigned long msec) +{ + float flicker = 1.0f; + + update(msec); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(0, 0, -dbg_cam_dist); + /* set view matrix according to player pos/rot */ + player_setup_view_matrix(&player); + glTranslatef(0, -PLAYER_EYE_HEIGHT, 0); + + /* setup lights */ + flicker = fbm1((float)msec / 500.0f, 2) * 0.4 + 0.6; + set_light_position(0, player.x, PLAYER_EYE_HEIGHT + 0.2, player.y); + set_light_color(0, 1.0 * flicker, 0.6 * flicker, 0.3 * flicker); + set_light_attenuation(0, 0.5, 0, 0.04); + + set_light_position(1, level.goal_pos[0], 0.8, level.goal_pos[1]); + set_light_color(1, 0.955, 0.75, 0.06); + set_light_attenuation(1, 0.9, 0, 0.05); + + /* draw the scene */ + draw_scene(msec); +} + +void game_reshape(int x, int y) +{ + win_width = x; + win_height = y; + glViewport(0, 0, x, y); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(55.0, (float)x / (float)y, 0.5, 500.0); +} + + +static void draw_scene(unsigned long msec) +{ + float x, y; + float tsec = (float)msec / 1000.0f; + + level_draw(&level); + + /* draw the golden monkey */ + if(level_obj_pos(&level, 'x', &x, &y)) { + /* TODO: GLES doesn't have tex-gen... recalc manually */ +#ifndef GL_MOBILE + glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); + glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); + glEnable(GL_TEXTURE_GEN_S); + glEnable(GL_TEXTURE_GEN_T); + + glBindTexture(GL_TEXTURE_2D, envmap); + glEnable(GL_TEXTURE_2D); +#endif + + set_mtl_diffuse(0.1, 0.1, 0.1, 1); + set_mtl_specular(0.955, 0.75, 0.06); + set_mtl_shininess(80.0); + set_mtl_emission(0.955, 0.75 * 0.7, 0.06 * 0.1); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glTranslatef(x, 0.8 + sin(tsec * 2.0) * 0.1, y); + glRotatef(tsec * 100.0, 0, 1, 0); + glRotatef(sin(tsec * 3.0) * 10.0, 1, 0, 0); + glScalef(0.3, 0.3, 0.3); + + render_mesh(monkey_mesh); + + glPopMatrix(); + + set_mtl_emission(0, 0, 0); + +#ifndef GL_MOBILE + glDisable(GL_TEXTURE_2D); + + glDisable(GL_TEXTURE_GEN_S); + glDisable(GL_TEXTURE_GEN_T); +#endif + } + + /* draw the win text */ + if(game_won) { + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glScalef((float)win_height / (float)win_width, 1, 1); + + glBindTexture(GL_TEXTURE_2D, win_tex); + glEnable(GL_TEXTURE_2D); + + glEnable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE); + glDisable(GL_LIGHTING); + + glBegin(GL_QUADS); + glTexCoord2f(0, 1); glVertex2f(-1, -1); + glTexCoord2f(1, 1); glVertex2f(1, -1); + glTexCoord2f(1, 0); glVertex2f(1, 1); + glTexCoord2f(0, 0); glVertex2f(-1, 1); + glEnd(); + + glDisable(GL_BLEND); + glDisable(GL_TEXTURE_2D); + glEnable(GL_LIGHTING); + + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + } +} + +static int warping_mouse; + +void game_keyboard(int key, int pressed) +{ + keystate[key] = pressed; + + if(!pressed) return; + + switch(key) { + case 27: + exit(0); + + case 'a': + if(!freelook && !game_won) { + player_turn(&player, -90, 0); + } + break; + + case 'd': + if(!freelook && !game_won) { + player_turn(&player, 90, 0); + } + break; + + case 'w': + case 's': + if(!freelook && !game_won) { + float prev_x = player.x; + float prev_y = player.y; + float sign = key == 'w' ? 1.0 : -1.0; + + if(!player_move(&player, level.cell_size * sign, 0)) { + player.x = prev_x; + player.y = prev_y; + } + } + break; + + case '`': + case '~': + mouselook = !mouselook; + if(mouselook) { + warping_mouse = 1; + set_mouse_pos(win_width / 2, win_height / 2); + set_mouse_cursor(0); + } else { + set_mouse_cursor(1); + } + break; + + case 'b': + case 'B': + freelook = !freelook; + break; + + case 'r': + case 'R': + game_won = 0; + player_init(&player, &level); + break; + + default: + break; + } +} + +#define MAX_TOUCH_IDS 16 +static struct { + int bnstate[8]; + int prev_x, prev_y; +} mstate[MAX_TOUCH_IDS]; + +void game_mouse_button(int id, int bn, int pressed, int x, int y) +{ + if(id >= MAX_TOUCH_IDS) return; + + mstate[id].prev_x = x; + mstate[id].prev_y = y; + mstate[id].bnstate[bn] = pressed; +} + +void game_mouse_motion(int id, int x, int y) +{ + int dx, dy, cx, cy; + + if(id >= MAX_TOUCH_IDS) return; + + cx = win_width / 2; + cy = win_height / 2; + + if(warping_mouse) { + warping_mouse = 0; + return; + } + + dx = x - (mouselook ? cx : mstate[id].prev_x); + dy = y - (mouselook ? cy : mstate[id].prev_y); + mstate[id].prev_x = x; + mstate[id].prev_y = y; + + if(!dx && !dy) return; + + if(mouselook || mstate[id].bnstate[0]) { + player_turn(&player, dx * 0.5, dy * 0.5); + } + if(mstate[id].bnstate[2]) { + dbg_cam_dist += 0.1 * dy; + if(dbg_cam_dist < 0.0) dbg_cam_dist = 0.0; + } + + if(mouselook) { + warping_mouse = 1; + set_mouse_pos(cx, cy); + mstate[id].prev_x = cx; + mstate[id].prev_y = cy; + } +} + diff -r e3b9707504df -r 45b91185b298 src/game.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/game.h Fri May 01 04:36:50 2015 +0300 @@ -0,0 +1,19 @@ +#ifndef GAME_H_ +#define GAME_H_ + +int game_init(void); +void game_shutdown(void); + +void game_display(unsigned long msec); +void game_reshape(int x, int y); + +void game_keyboard(int key, int press); +void game_mouse_button(int id, int bn, int press, int x, int y); +void game_mouse_motion(int id, int x, int y); + +/* provided by the system frontend */ +void set_mouse_pos(int x, int y); +void set_mouse_cursor(int enable); + +#endif /* GAME_H_ */ + diff -r e3b9707504df -r 45b91185b298 src/gles/sanegl.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gles/sanegl.c Fri May 01 04:36:50 2015 +0300 @@ -0,0 +1,185 @@ +/* +SaneGL - a small library to bring back sanity to OpenGL ES 2.x +Copyright (C) 2011-2013 John Tsiombikas + +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 . +*/ + +#include +#include +#include +#include +#include +#include "sanegl.h" + +#define MAX_VERTS 512 + +static void gl_draw_immediate(void); + +typedef struct { float x, y; } vec2_t; +typedef struct { float x, y, z; } vec3_t; +typedef struct { float x, y, z, w; } vec4_t; + +static int prim = -1; + +static vec3_t cur_normal; +static vec4_t cur_color; +static vec2_t cur_texcoord; + +static vec4_t *vert_arr, *col_arr; +static vec3_t *norm_arr; +static vec2_t *texc_arr; + +static int num_verts, vert_calls; + +/* immediate mode rendering */ +void gl_begin(int p) +{ + if(!vert_arr) { + vert_arr = malloc(MAX_VERTS * sizeof *vert_arr); + norm_arr = malloc(MAX_VERTS * sizeof *norm_arr); + texc_arr = malloc(MAX_VERTS * sizeof *texc_arr); + col_arr = malloc(MAX_VERTS * sizeof *col_arr); + assert(vert_arr && norm_arr && texc_arr && col_arr); + } + + prim = p; + num_verts = vert_calls = 0; +} + +void gl_end(void) +{ + if(num_verts > 0) { + gl_draw_immediate(); + } +} + +static void gl_draw_immediate(void) +{ + int glprim; + + glprim = prim == GL_QUADS ? GL_TRIANGLES : prim; + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_NORMAL_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + glVertexPointer(4, GL_FLOAT, 0, vert_arr); + glNormalPointer(GL_FLOAT, 0, norm_arr); + glColorPointer(4, GL_FLOAT, 0, col_arr); + glTexCoordPointer(2, GL_FLOAT, 0, texc_arr); + + glDrawArrays(glprim, 0, num_verts); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); +} + +void gl_vertex2f(float x, float y) +{ + gl_vertex4f(x, y, 0.0f, 1.0f); +} + +void gl_vertex3f(float x, float y, float z) +{ + gl_vertex4f(x, y, z, 1.0f); +} + +void gl_vertex4f(float x, float y, float z, float w) +{ + int i, buffer_full; + + if(prim == GL_QUADS && vert_calls % 4 == 3) { + for(i=0; i<2; i++) { + col_arr[num_verts] = col_arr[num_verts - 3 + i]; + texc_arr[num_verts] = texc_arr[num_verts - 3 + i]; + norm_arr[num_verts] = norm_arr[num_verts - 3 + i]; + vert_arr[num_verts] = vert_arr[num_verts - 3 + i]; + num_verts++; + } + } + + vert_arr[num_verts].x = x; + vert_arr[num_verts].y = y; + vert_arr[num_verts].z = z; + vert_arr[num_verts].w = w; + + col_arr[num_verts] = cur_color; + norm_arr[num_verts] = cur_normal; + texc_arr[num_verts] = cur_texcoord; + + vert_calls++; + num_verts++; + + if(prim == GL_QUADS) { + /* leave space for 6 more worst-case and don't allow flushes mid-quad */ + buffer_full = num_verts >= MAX_VERTS - 6 && vert_calls % 4 == 0; + } else { + buffer_full = num_verts >= MAX_VERTS - prim; + } + + if(buffer_full) { + gl_draw_immediate(); + gl_begin(prim); /* reset everything */ + } +} + + +void gl_normal3f(float x, float y, float z) +{ + cur_normal.x = x; + cur_normal.y = y; + cur_normal.z = z; +} + + +void gl_color3f(float r, float g, float b) +{ + cur_color.x = r; + cur_color.y = g; + cur_color.z = b; + cur_color.w = 1.0f; +} + +void gl_color4f(float r, float g, float b, float a) +{ + cur_color.x = r; + cur_color.y = g; + cur_color.z = b; + cur_color.w = a; +} + + +void gl_texcoord1f(float s) +{ + cur_texcoord.x = s; + cur_texcoord.y = 0.0f; +} + +void gl_texcoord2f(float s, float t) +{ + cur_texcoord.x = s; + cur_texcoord.y = t; +} + +void glu_perspective(float fov, float aspect, float nearz, float farz) +{ + float fovrad = M_PI * fov / 180.0; + float halfsz = tan(fovrad) * nearz; + + glFrustumf(-halfsz * aspect, halfsz * aspect, -halfsz, halfsz, nearz, farz); +} diff -r e3b9707504df -r 45b91185b298 src/gles/sanegl.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gles/sanegl.h Fri May 01 04:36:50 2015 +0300 @@ -0,0 +1,96 @@ +/* +SaneGL - a small library to bring back sanity to OpenGL ES 2.x +Copyright (C) 2011-2013 John Tsiombikas + +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 . +*/ + +#ifndef SANEGL_H_ +#define SANEGL_H_ + +#include "opengl.h" + +#ifndef GL_POINTS +#define GL_POINTS 0 +#endif +#ifndef GL_LINES +#define GL_LINES 1 +#endif +#ifndef GL_TRIANGLES +#define GL_TRIANGLES 4 +#endif +#ifndef GL_QUADS +#define GL_QUADS 7 +#endif + +/* glGet stuff */ +#ifndef GL_VIEWPORT +#define GL_VIEWPORT 0x0BA2 +#endif +#ifndef GL_MODELVIEW_MATRIX +#define GL_MODELVIEW_MATRIX 0x0BA6 +#endif +#ifndef GL_PROJECTION_MATRIX +#define GL_PROJECTION_MATRIX 0x0BA7 +#endif + +#ifdef GLDEF + +#define glBegin gl_begin +#define glEnd gl_end +#define glVertex2f gl_vertex2f +#define glVertex3f gl_vertex3f +#define glVertex4f gl_vertex4f +#define glNormal3f gl_normal3f +#define glColor3f gl_color3f +#define glColor4f gl_color4f +#define glTexCoord1f gl_texcoord1f +#define glTexCoord2f gl_texcoord2f +#define glVertexAttrib2f gl_vertex_attrib2f +#define glVertexAttrib3f gl_vertex_attrib3f +#define glVertexAttrib4f gl_vertex_attrib4f + +#define gluPerspective glu_perspective + +#endif /* GLDEF */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* immediate mode rendering */ +void gl_begin(int prim); +void gl_end(void); + +void gl_vertex2f(float x, float y); +void gl_vertex3f(float x, float y, float z); +void gl_vertex4f(float x, float y, float z, float w); + +void gl_normal3f(float x, float y, float z); + +void gl_color3f(float r, float g, float b); +void gl_color4f(float r, float g, float b, float a); + +void gl_texcoord1f(float s); +void gl_texcoord2f(float s, float t); + +/* GLU */ + +void glu_perspective(float fov, float aspect, float nearz, float farz); + +#ifdef __cplusplus +} +#endif + +#endif /* SANEGL_H_ */ diff -r e3b9707504df -r 45b91185b298 src/glut/main.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/glut/main.c Fri May 01 04:36:50 2015 +0300 @@ -0,0 +1,94 @@ +#include +#include +#include +#include +#include "opengl.h" + +#ifdef __APPLE__ +#include +#else +#include +#endif + +#include "game.h" + +static void display(void); +static void idle(void); +static void reshape(int x, int y); +static void key_down(unsigned char key, int x, int y); +static void key_up(unsigned char key, int x, int y); +static void mouse(int bn, int state, int x, int y); +static void motion(int x, int y); + +int main(int argc, char **argv) +{ + glutInit(&argc, argv); + glutInitWindowSize(1280, 800); + glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE); + glutCreateWindow("labyrinth game example"); + + glutDisplayFunc(display); + glutIdleFunc(idle); + glutReshapeFunc(reshape); + glutKeyboardFunc(key_down); + glutKeyboardUpFunc(key_up); + glutMouseFunc(mouse); + glutMotionFunc(motion); + glutPassiveMotionFunc(motion); + + glewInit(); + + if(game_init() == -1) { + return 1; + } + glutMainLoop(); + return 0; +} + +void set_mouse_pos(int x, int y) +{ + glutWarpPointer(x, y); +} + +void set_mouse_cursor(int enable) +{ + glutSetCursor(enable ? GLUT_CURSOR_INHERIT : GLUT_CURSOR_NONE); +} + +static void display(void) +{ + game_display(glutGet(GLUT_ELAPSED_TIME)); + + glutSwapBuffers(); + assert(glGetError() == GL_NO_ERROR); +} + +static void idle(void) +{ + glutPostRedisplay(); +} + +static void reshape(int x, int y) +{ + game_reshape(x, y); +} + +static void key_down(unsigned char key, int x, int y) +{ + game_keyboard(key, 1); +} + +static void key_up(unsigned char key, int x, int y) +{ + game_keyboard(key, 0); +} + +static void mouse(int bn, int state, int x, int y) +{ + game_mouse_button(0, bn - GLUT_LEFT_BUTTON, state == GLUT_DOWN ? 1 : 0, x, y); +} + +static void motion(int x, int y) +{ + game_mouse_motion(0, x, y); +} diff -r e3b9707504df -r 45b91185b298 src/main.c --- a/src/main.c Mon Apr 27 05:37:17 2015 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,382 +0,0 @@ -#include -#include -#include -#include -#include "opengl.h" -#include "player.h" -#include "level.h" -#include "noise.h" -#include "texture.h" -#include "mesh.h" - -#define PLAYER_EYE_HEIGHT 1.65 - -static int init(void); -static void update(unsigned int msec); -static void display(void); -static void draw_scene(unsigned int msec); -static void idle(void); -static void reshape(int x, int y); -static void key_down(unsigned char key, int x, int y); -static void key_up(unsigned char key, int x, int y); -static void mouse(int bn, int state, int x, int y); -static void motion(int x, int y); - -static int win_width, win_height; -static struct level level; -static struct player player; -static int mouselook, freelook = 1; -static char keystate[256]; - -static struct mesh *monkey_mesh; -static unsigned int envmap; -static unsigned int win_tex; - -static int game_won; - -static float dbg_cam_dist = 0.0; - -int main(int argc, char **argv) -{ - glutInit(&argc, argv); - glutInitWindowSize(1280, 800); - glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE); - glutCreateWindow("labyrinth game example"); - - glutDisplayFunc(display); - glutIdleFunc(idle); - glutReshapeFunc(reshape); - glutKeyboardFunc(key_down); - glutKeyboardUpFunc(key_up); - glutMouseFunc(mouse); - glutMotionFunc(motion); - - if(init() == -1) { - return 1; - } - glutMainLoop(); - return 0; -} - - -static int init(void) -{ - glEnable(GL_DEPTH_TEST); - glEnable(GL_CULL_FACE); - glEnable(GL_LIGHTING); - glEnable(GL_NORMALIZE); - - glEnable(GL_LIGHT0); - glEnable(GL_LIGHT1); - - /* set a slightly bluish cold ambient light */ - { - float ambient[] = {0.08, 0.1, 0.3, 1.0}; - glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient); - } - - level_init(&level); - if(level_load(&level, "data/0.level") == -1) { - fprintf(stderr, "level loading failed\n"); - return -1; - } - - if(!(level.wall_tex = load_texture("data/wall.ppm"))) { - return -1; - } - if(!(level.floor_tex = load_texture("data/floor.ppm"))) { - return -1; - } - level.floor_tex_scale = 1.0; - if(!(level.ceil_tex = load_texture("data/ceil.ppm"))) { - return -1; - } - level.ceil_tex_scale = 2.0; - - - if(!(monkey_mesh = load_mesh("data/monkey.obj"))) { - return -1; - } - if(!(envmap = load_texture("data/refmap.ppm"))) { - return -1; - } - - if(!(win_tex = load_texture("data/done.ppm"))) { - return -1; - } - - player_init(&player, &level); - return 0; -} - -static void update(unsigned int msec) -{ - static unsigned int prev_upd; - float dfwd = 0.0f; - float dright = 0.0f; - float walk_speed = 8.0; - - float dt = (float)(msec - prev_upd) / 1000.0f; - prev_upd = msec; - - if(game_won) return; - - if(freelook) { - if(keystate['w'] || keystate['W']) { - dfwd += walk_speed * dt; - } - if(keystate['s'] || keystate['S']) { - dfwd -= walk_speed * dt; - } - if(keystate['d'] || keystate['D']) { - dright += walk_speed * dt * 0.6; - } - if(keystate['a'] || keystate['A']) { - dright -= walk_speed * dt * 0.6; - } - - player_move(&player, dfwd, dright); - } - - if(level_cell_at(&level, player.x, player.y) == 'x') { - game_won = 1; - } -} - -static void display(void) -{ - float flicker = 1.0f; - unsigned int msec = glutGet(GLUT_ELAPSED_TIME); - - update(msec); - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glTranslatef(0, 0, -dbg_cam_dist); - /* set view matrix according to player pos/rot */ - player_setup_view_matrix(&player); - glTranslatef(0, -PLAYER_EYE_HEIGHT, 0); - - /* setup lights */ - flicker = fbm1((float)msec / 500.0f, 2) * 0.4 + 0.6; - set_light_position(0, player.x, PLAYER_EYE_HEIGHT + 0.2, player.y); - set_light_color(0, 1.0 * flicker, 0.6 * flicker, 0.3 * flicker); - set_light_attenuation(0, 0.5, 0, 0.04); - - set_light_position(1, level.goal_pos[0], 0.8, level.goal_pos[1]); - set_light_color(1, 0.955, 0.75, 0.06); - set_light_attenuation(1, 0.9, 0, 0.05); - - /* draw the scene */ - draw_scene(msec); - - glutSwapBuffers(); - assert(glGetError() == GL_NO_ERROR); -} - -static void draw_scene(unsigned int msec) -{ - float x, y; - float tsec = (float)msec / 1000.0f; - - level_draw(&level); - - /* draw the golden monkey */ - if(level_obj_pos(&level, 'x', &x, &y)) { - glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); - glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); - glEnable(GL_TEXTURE_GEN_S); - glEnable(GL_TEXTURE_GEN_T); - - glBindTexture(GL_TEXTURE_2D, envmap); - glEnable(GL_TEXTURE_2D); - - set_mtl_diffuse(0.1, 0.1, 0.1, 1); - set_mtl_specular(0.955, 0.75, 0.06); - set_mtl_shininess(80.0); - set_mtl_emission(0.955, 0.75 * 0.7, 0.06 * 0.1); - - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glTranslatef(x, 0.8 + sin(tsec * 2.0) * 0.1, y); - glRotatef(tsec * 100.0, 0, 1, 0); - glRotatef(sin(tsec * 3.0) * 10.0, 1, 0, 0); - glScalef(0.3, 0.3, 0.3); - - render_mesh(monkey_mesh); - - glPopMatrix(); - - set_mtl_emission(0, 0, 0); - - glDisable(GL_TEXTURE_2D); - - glDisable(GL_TEXTURE_GEN_S); - glDisable(GL_TEXTURE_GEN_T); - } - - /* draw the win text */ - if(game_won) { - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glScalef((float)win_height / (float)win_width, 1, 1); - - glBindTexture(GL_TEXTURE_2D, win_tex); - glEnable(GL_TEXTURE_2D); - - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE); - glDisable(GL_LIGHTING); - - glBegin(GL_QUADS); - glTexCoord2f(0, 1); glVertex2f(-1, -1); - glTexCoord2f(1, 1); glVertex2f(1, -1); - glTexCoord2f(1, 0); glVertex2f(1, 1); - glTexCoord2f(0, 0); glVertex2f(-1, 1); - glEnd(); - - glDisable(GL_BLEND); - glDisable(GL_TEXTURE_2D); - glEnable(GL_LIGHTING); - - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - } -} - -static void idle(void) -{ - glutPostRedisplay(); -} - -static void reshape(int x, int y) -{ - win_width = x; - win_height = y; - glViewport(0, 0, x, y); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - gluPerspective(55.0, (float)x / (float)y, 0.5, 500.0); -} - -static int warping_mouse; - -static void key_down(unsigned char key, int x, int y) -{ - keystate[key] = 1; - - switch(key) { - case 27: - exit(0); - - case 'a': - if(!freelook && !game_won) { - player_turn(&player, -90, 0); - } - break; - - case 'd': - if(!freelook && !game_won) { - player_turn(&player, 90, 0); - } - break; - - case 'w': - case 's': - if(!freelook && !game_won) { - float prev_x = player.x; - float prev_y = player.y; - float sign = key == 'w' ? 1.0 : -1.0; - - if(!player_move(&player, level.cell_size * sign, 0)) { - player.x = prev_x; - player.y = prev_y; - } - } - break; - - case '`': - case '~': - mouselook = !mouselook; - if(mouselook) { - warping_mouse = 1; - glutWarpPointer(win_width / 2, win_height / 2); - glutPassiveMotionFunc(motion); - glutSetCursor(GLUT_CURSOR_NONE); - } else { - glutPassiveMotionFunc(0); - glutSetCursor(GLUT_CURSOR_INHERIT); - } - break; - - case 'b': - case 'B': - freelook = !freelook; - break; - - case 'r': - case 'R': - game_won = 0; - player_init(&player, &level); - break; - - default: - break; - } -} - -static void key_up(unsigned char key, int x, int y) -{ - keystate[key] = 0; -} - -static int bnstate[16]; -static int prev_x, prev_y; - -static void mouse(int bn, int state, int x, int y) -{ - prev_x = x; - prev_y = y; - bnstate[bn - GLUT_LEFT_BUTTON] = state == GLUT_DOWN ? 1 : 0; -} - -static void motion(int x, int y) -{ - int dx, dy; - int cx = win_width / 2; - int cy = win_height / 2; - - if(warping_mouse) { - warping_mouse = 0; - return; - } - - dx = x - (mouselook ? cx : prev_x); - dy = y - (mouselook ? cy : prev_y); - prev_x = x; - prev_y = y; - - if(!dx && !dy) return; - - if(mouselook || bnstate[0]) { - player_turn(&player, dx * 0.5, dy * 0.5); - } - if(bnstate[2]) { - dbg_cam_dist += 0.1 * dy; - if(dbg_cam_dist < 0.0) dbg_cam_dist = 0.0; - } - - if(mouselook) { - warping_mouse = 1; - glutWarpPointer(cx, cy); - prev_x = cx; - prev_y = cy; - } -} diff -r e3b9707504df -r 45b91185b298 src/mesh.c --- a/src/mesh.c Mon Apr 27 05:37:17 2015 +0300 +++ b/src/mesh.c Fri May 01 04:36:50 2015 +0300 @@ -1,11 +1,5 @@ -#ifdef __APPLE__ -#include -#elif defined(WIN32) -#include -#else -#include -#endif - +#include +#include "opengl.h" #include "mesh.h" #include "objfile.h" diff -r e3b9707504df -r 45b91185b298 src/opengl.h --- a/src/opengl.h Mon Apr 27 05:37:17 2015 +0300 +++ b/src/opengl.h Fri May 01 04:36:50 2015 +0300 @@ -1,11 +1,20 @@ #ifndef OPENGL_H_ #define OPENGL_H_ -#ifdef __APPLE__ -#include +#ifdef __ANDROID__ +#include +#include +#include + +#define GL_MOBILE + #else -#include -#endif + +#include + +#define GL_DESKTOP + +#endif /* not __ANDROID__ */ /* some helpers */ @@ -18,4 +27,9 @@ void set_mtl_shininess(float shin); void set_mtl_emission(float r, float g, float b); +#ifdef GL_MOBILE +#define GLDEF +#include "sanegl.h" +#endif + #endif /* OPENGL_H_ */ diff -r e3b9707504df -r 45b91185b298 src/timer.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/timer.c Fri May 01 04:36:50 2015 +0300 @@ -0,0 +1,71 @@ +#include "timer.h" + +#if defined(__APPLE__) && !defined(__unix__) +#define __unix__ +#endif + +#ifdef __unix__ +#include +#include +#include + +#ifdef CLOCK_MONOTONIC +unsigned long get_time_msec(void) +{ + struct timespec ts; + static struct timespec ts0; + + clock_gettime(CLOCK_MONOTONIC, &ts); + if(ts0.tv_sec == 0 && ts0.tv_nsec == 0) { + ts0 = ts; + return 0; + } + return (ts.tv_sec - ts0.tv_sec) * 1000 + (ts.tv_nsec - ts0.tv_nsec) / 1000000; +} +#else /* no fancy POSIX clocks, fallback to good'ol gettimeofday */ +unsigned long get_time_msec(void) +{ + struct timeval tv; + static struct timeval tv0; + + gettimeofday(&tv, 0); + if(tv0.tv_sec == 0 && tv0.tv_usec == 0) { + tv0 = tv; + return 0; + } + return (tv.tv_sec - tv0.tv_sec) * 1000 + (tv.tv_usec - tv0.tv_usec) / 1000; +} +#endif /* !posix clock */ + +void sleep_msec(unsigned long msec) +{ + usleep(msec * 1000); +} +#endif + +#ifdef WIN32 +#include +#pragma comment(lib, "winmm.lib") + +unsigned long get_time_msec(void) +{ + return timeGetTime(); +} + +void sleep_msec(unsigned long msec) +{ + Sleep(msec); +} +#endif + +double get_time_sec(void) +{ + return get_time_msec() / 1000.0f; +} + +void sleep_sec(double sec) +{ + if(sec > 0.0f) { + sleep_msec(sec * 1000.0f); + } +} diff -r e3b9707504df -r 45b91185b298 src/timer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/timer.h Fri May 01 04:36:50 2015 +0300 @@ -0,0 +1,10 @@ +#ifndef TIMER_H_ +#define TIMER_H_ + +unsigned long get_time_msec(void); +void sleep_msec(unsigned long msec); + +double get_time_sec(void); +void sleep_sec(double sec); + +#endif // TIMER_H_