-src = $(wildcard src/*.c)
+src = $(wildcard src/*.c) libs/glew/glew.c
obj = $(src:.c=.o)
dep = $(src:.c=.d)
bin = game
warn = -pedantic -Wall
dbg = -g
-def = -DMINIGLUT_USE_LIBC
+def = -DMINIGLUT_USE_LIBC -DGLEW_STATIC
-inc = -Ilibs -Ilibs/assfile -Ilibs/treestor/include
+inc = -Ilibs -Ilibs/assfile -Ilibs/treestor/include -Ilibs/glew
libs = -lassfile -ldrawtext -lgoat3d -limago -ltreestor
CFLAGS = $(warn) $(opt) $(dbg) $(inc) $(def) -MMD
libdir = -Llibs/w32
else
- libgl = -lGL -lGLU -lX11
+ libgl = -lGL -lX11
libdir = -Llibs/unix
endif
+uniform float aspect;
+uniform mat4 matrix;
+uniform mat3 dirmatrix;
+
+#define DIST_THRES 1e-3
+#define MAX_ITER 250
+#define MAX_STEP 1.0
+
+vec3 raymarch(inout vec3 p, in vec3 dir, out float depth);
+vec3 shade(in vec3 p, in vec3 dir, in float dist, in float total_dist);
+vec3 backdrop(in vec3 dir);
+float eval_sdf(in vec3 p);
+vec3 eval_grad(in vec3 p, float dist);
+vec3 primray(in vec2 uv, out vec3 org);
+
+float boxdist(in vec3 p, in vec3 b);
+float sphdist(in vec3 p, in vec3 sp, in float srad);
+
void main()
{
- vec3 col = vec3(gl_TexCoord[0].st, 1.0);
- gl_FragColor = vec4(col, 1.0);
+ vec2 uv = gl_TexCoord[0].st;
+ vec3 rorg;
+ vec3 rdir = primray(uv, rorg);
+ float depth;
+
+ gl_FragColor.rgb = raymarch(rorg, rdir, depth);
+ gl_FragColor.a = 1.0;
+
+ vec4 projp = gl_ProjectionMatrix * vec4(0.0, 0.0, -depth, 1.0);
+ float zval = projp.z / projp.w;
+
+ gl_FragDepth = zval;
+}
+
+vec3 raymarch(inout vec3 p, in vec3 dir, out float depth)
+{
+ float d, total_d = 0.0;
+
+ for(int i=0; i<MAX_ITER; i++) {
+ if((d = eval_sdf(p)) <= DIST_THRES) {
+ depth = total_d;
+ return shade(p, dir, d, total_d);
+ }
+
+ d = min(d, MAX_STEP);
+
+ p = p + dir * d;
+ total_d += d;
+ }
+
+ depth = -gl_DepthRange.far;
+ return backdrop(dir);
+}
+
+vec3 shade(in vec3 p, in vec3 dir, in float dist, in float total_dist)
+{
+ const vec3 kd = vec3(1.0, 0.3, 0.1);
+ const vec3 ks = vec3(0.7, 0.7, 0.7);
+ const vec3 ldir = normalize(vec3(-1.0, 1.0, -1.5));
+ const vec3 vdir = vec3(0.0, 0.0, -1.0);
+
+ vec3 diffuse = vec3(0.0, 0.0, 0.0);
+ vec3 specular = vec3(0.0, 0.0, 0.0);
+
+ vec3 n = eval_grad(p, dist);
+ return n * 0.5 + 0.5;
+ vec3 hdir = normalize(ldir + vdir);
+
+ float ndotl = max(dot(n, ldir), 0.0);
+ float ndoth = max(dot(n, hdir), 0.0);
+
+ diffuse += kd * ndotl;
+ specular += ks * pow(ndoth, 50.0);
+
+ float fog = clamp(300.0 / (total_dist * total_dist), 0.0, 1.0);
+
+ return mix(backdrop(dir), diffuse + specular, fog);
+}
+
+vec3 backdrop(in vec3 dir)
+{
+ return vec3(0.1, 0.1, 0.1);
+}
+
+#define DELTA 1e-4
+vec3 eval_grad(in vec3 p, float dist)
+{
+ float dfdx = eval_sdf(p + vec3(DELTA, 0.0, 0.0)) - dist;
+ float dfdy = eval_sdf(p + vec3(0.0, DELTA, 0.0)) - dist;
+ float dfdz = eval_sdf(p + vec3(0.0, 0.0, DELTA)) - dist;
+ return normalize(vec3(dfdx, dfdy, dfdz));
+}
+
+vec3 primray(in vec2 uv, out vec3 org)
+{
+ vec3 origin = (gl_ModelViewMatrixInverse * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
+ org = origin;
+
+ vec2 nuv = uv * 2.0 - 1.0;
+ vec4 cp_near = vec4(nuv, -1.0, 1.0);
+
+ vec4 vdir = gl_ProjectionMatrixInverse * cp_near;
+ vec4 wdir = gl_ModelViewMatrixInverse * vec4(vdir.xyz, 0.0);
+
+ return normalize(wdir.xyz);
+}
+
+float boxdist(in vec3 p, in vec3 b)
+{
+ vec3 q = abs(p) - b;
+ return length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0);
+}
+
+float sphdist(in vec3 p, in vec3 sp, in float srad)
+{
+ return length(p - sp) - srad;
}
#define darr_strpush(da, c) \
do { \
char cnull = 0, ch = (char)(c); \
- (da) = dynarr_pop_impl(da); \
- (da) = dynarr_push_impl((da), &ch); \
- (da) = dynarr_push_impl((da), &cnull); \
+ (da) = darr_pop_impl(da); \
+ (da) = darr_push_impl((da), &ch); \
+ (da) = darr_push_impl((da), &cnull); \
} while(0)
#define darr_strpop(da) \
do { \
char cnull = 0; \
- (da) = dynarr_pop_impl(da); \
- (da) = dynarr_pop_impl(da); \
- (da) = dynarr_push_impl((da), &cnull); \
+ (da) = darr_pop_impl(da); \
+ (da) = darr_pop_impl(da); \
+ (da) = darr_push_impl((da), &cnull); \
} while(0)
long time_msec;
struct game_screen *cur_scr;
+char *start_scr_name;
/* available screens */
extern struct game_screen scr_menu, scr_game, scr_map, scr_lvled;
int game_init(int argc, char **argv)
{
int i;
- char *start_scr_name;
+ char *env;
load_options(GAME_CFG_FILE);
if(parse_options(argc, argv) == -1) {
screens[num_screens++] = &scr_map;
screens[num_screens++] = &scr_lvled;
- start_scr_name = getenv("START_SCREEN");
+ if((env = getenv("START_SCREEN"))) {
+ start_scr_name = env;
+ }
for(i=0; i<num_screens; i++) {
if(screens[i]->init() == -1) {
extern long time_msec;
extern struct game_screen *cur_scr;
+extern char *start_scr_name;
int game_init(int argc, char **argv);
rect++;
}
fprintf(fp, "RECTEND\n\n");
+
+
+ fprintf(fp, "SDRSTART\n");
+ fprintf(fp, "float eval_sdf(in vec3 p)\n");
+ fprintf(fp, "{\n");
+ rect = lvl->rects;
+ for(i=0; i<num; i++) {
+ float cx = (rect->x - 0.5f + rect->w * 0.5f) * lvl->scale;
+ float cy = (rect->y - 0.5f + rect->h * 0.5f) * lvl->scale;
+ float rx = (rect->w + 0.1f) * lvl->scale * 0.5f;
+ float ry = (rect->h + 0.1f) * lvl->scale * 0.5f;
+
+ if(i == 0) {
+ fprintf(fp, "\tfloat d = boxdist(p - vec3(%f, 0.0, %f), vec3(%f, 1.0, %f));\n",
+ cx, cy, rx, ry);
+ } else {
+ fprintf(fp, "\td = min(d, boxdist(p - vec3(%f, 0.0, %f), vec3(%f, 1.0, %f)));\n",
+ cx, cy, rx, ry);
+ }
+ rect++;
+ }
+ fprintf(fp, "\treturn d;\n}\n");
+ fprintf(fp, "SDREND\n\n");
}
fclose(fp);
return *s ? s : 0;
}
+enum {
+ ST_HEADER,
+ ST_ASSIGN,
+ ST_MAP,
+ ST_SDR
+};
+
int load_level(struct level *lvl, const char *fname)
{
ass_file *fp;
int state = 0;
int i, nrow;
struct level_rect rect;
+ char *sdr = 0;
if(!(fp = ass_fopen(fname, "rb"))) {
fprintf(stderr, "load_level: failed to open: %s\n", fname);
while(ass_fgets(buf, sizeof buf, fp)) {
switch(state) {
- case 0:
+ case ST_HEADER:
if(memcmp(buf, "RDLEVEL", 7) != 0) {
fprintf(stderr, "load_level: invalid level file: %s\n", fname);
ass_fclose(fp);
return -1;
}
- state++;
+ state = ST_ASSIGN;
break;
- case 1:
+ case ST_ASSIGN:
if(!(line = clean_line(buf)) || *line == '#') {
continue;
}
lvl->cells = calloc_nf(lvl->xsz * lvl->ysz, sizeof *lvl->cells);
nrow = 0;
- state++;
+ state = ST_MAP;
+
+ } else if(strcmp(line, "SDRSTART") == 0) {
+ if(sdr) {
+ darr_clear(sdr);
+ } else {
+ sdr = darr_alloc(0, 1);
+ }
+ state = ST_SDR;
} else if(sscanf(line, "rect %d %d %d %d", &rect.x, &rect.y, &rect.w, &rect.h) == 4) {
rect.dbgcol[0] = (rand() & 0x7f) + 0x7f;
}
break;
- case 2:
+ case ST_MAP:
if(memcmp(buf, "MAPEND", 6) == 0) {
- state = 1;
+ state = ST_ASSIGN;
break;
}
for(i=0; i<lvl->xsz; i++) {
parse_cell(lvl, i, nrow, buf[i]);
}
if(++nrow >= lvl->ysz) {
- state = 1;
+ state = ST_ASSIGN;
break;
}
break;
+
+ case ST_SDR:
+ if(memcmp(buf, "SDREND", 6) == 0) {
+ state = ST_ASSIGN;
+ break;
+ }
+ for(i=0; buf[i]; i++) {
+ darr_strpush(sdr, buf[i]);
+ }
+ break;
}
}
+ if(sdr) {
+ lvl->sdf_src = darr_finalize(sdr);
+ }
+
ass_fclose(fp);
return 0;
}
int sx, sy;
struct level_rect *rects; /* darr, empty spaces */
+
+ char *sdf_src;
};
void init_level(struct level *lvl);
#include <string.h>
#include <errno.h>
#include "options.h"
+#include "game.h"
#include "treestor.h"
#define DEF_XRES 1280
fprintf(stderr, "%s must be followed by a screen name\n", argv[i - 1]);
return -1;
}
+ start_scr_name = argv[i];
+
} else if(strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "-help") == 0) {
printf(usage_fmt, argv[0]);
exit(0);
static unsigned int sdr;
-
static int ginit(void)
{
- if(!(sdr = create_program_load("sdr/raydungeon.v.glsl", "sdr/raydungeon.p.glsl"))) {
- return -1;
- }
return 0;
}
static void gdestroy(void)
{
- free_program(sdr);
}
static int gstart(void)
cam_pan.x = -(lvl->xsz / 2.0f) * lvl->scale;
cam_pan.y = 0;
cam_pan.z = -(lvl->ysz / 2.0f) * lvl->scale;
+
+ glEnable(GL_DEPTH_TEST);
+
+ if(lvl->sdf_src) {
+ add_shader_footer(GL_FRAGMENT_SHADER, lvl->sdf_src);
+ } else {
+ add_shader_footer(GL_FRAGMENT_SHADER, "float eval_sdf(in vec3 p) { return 10000.0; }\n");
+ }
+ if(!(sdr = create_program_load("sdr/raydungeon.v.glsl", "sdr/raydungeon.p.glsl"))) {
+ return -1;
+ }
+ clear_shader_footer(GL_FRAGMENT_SHADER);
+ glUseProgram(sdr);
return 0;
}
{
destroy_level(lvl);
free(lvl);
+
+ free_program(sdr);
}
static void gdisplay(void)
glUseProgram(sdr);
- glDepthMask(0);
glBegin(GL_TRIANGLES);
glTexCoord2f(0, 0); glVertex2f(-1, -1);
- glTexCoord2f(2, 0); glVertex2f(4, -1);
- glTexCoord2f(0, 2); glVertex2f(-1, 4);
+ glTexCoord2f(2, 0); glVertex2f(3, -1);
+ glTexCoord2f(0, 2); glVertex2f(-1, 3);
glEnd();
- glDepthMask(1);
glUseProgram(0);
static void greshape(int x, int y)
{
- cgm_mperspective(proj_mat, cgm_deg_to_rad(60), win_aspect, 0.5, 500.0);
+ cgm_mperspective(proj_mat, cgm_deg_to_rad(60), win_aspect, 0.5, 40.0);
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(proj_mat);
}
#include <stdlib.h>
#include <math.h>
#include <GL/gl.h>
+#include "cgmath/cgmath.h"
#include "game.h"
#include "level.h"
#include "util.h"
struct level_cell *cell;
struct level_rect *rect;
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0, 0, -cam_dist);
static void reshape(int x, int y)
{
+ float proj_mat[16];
+
+ cgm_mperspective(proj_mat, cgm_deg_to_rad(60), win_aspect, 0.5, 40.0);
+ glMatrixMode(GL_PROJECTION);
+ glLoadMatrixf(proj_mat);
}
static void keyb(int key, int press)