uniform mat3 dirmatrix;
#define DIST_THRES 1e-3
-#define MAX_ITER 250
-#define MAX_STEP 1.0
+#define MAX_ITER 128
+#define MAX_STEP 0.5
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);
float boxdist(in vec3 p, in vec3 b);
float sphdist(in vec3 p, in vec3 sp, in float srad);
+float fbm(vec3 v, int noct);
+float snoise(vec3 v);
+
+float eval_sdf_gen(in vec3 p);
+
+
void main()
{
vec2 uv = gl_TexCoord[0].st;
return vec3(0.1, 0.1, 0.1);
}
+float eval_sdf(in vec3 p)
+{
+ return eval_sdf_gen(p) + fbm(p, 4) * 0.05;
+}
+
#define DELTA 1e-4
vec3 eval_grad(in vec3 p, float dist)
{
{
return length(p - sp) - srad;
}
+
+#ifdef TEST_SDF
+float eval_sdf_gen(in vec3 p)
+{
+ return boxdist(p - vec3(14.000000, 0.0, 14.000000), vec3(0.550000, 1.0, 4.550000));
+}
+#endif
+
+float fbm(vec3 v, int noct)
+{
+ float val = 0.0;
+ float f = 1.0;
+ for(int i=0; i<noct; i++) {
+ val += snoise(v * f) / f;
+ f *= 2.0;
+ }
+ return val;
+}
+
+// Description : Array and textureless GLSL 2D/3D/4D simplex
+// noise functions.
+// Author : Ian McEwan, Ashima Arts.
+// Maintainer : stegu
+// Lastmod : 20201014 (stegu)
+// License : Copyright (C) 2011 Ashima Arts. All rights reserved.
+// Distributed under the MIT License. See LICENSE file.
+// https://github.com/ashima/webgl-noise
+// https://github.com/stegu/webgl-noise
+//
+
+vec3 mod289(vec3 x) {
+ return x - floor(x * (1.0 / 289.0)) * 289.0;
+}
+
+vec4 mod289(vec4 x) {
+ return x - floor(x * (1.0 / 289.0)) * 289.0;
+}
+
+vec4 permute(vec4 x) {
+ return mod289(((x*34.0)+10.0)*x);
+}
+
+vec4 taylorInvSqrt(vec4 r)
+{
+ return 1.79284291400159 - 0.85373472095314 * r;
+}
+
+float snoise(vec3 v)
+{
+ const vec2 C = vec2(1.0/6.0, 1.0/3.0) ;
+ const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);
+
+ // First corner
+ vec3 i = floor(v + dot(v, C.yyy) );
+ vec3 x0 = v - i + dot(i, C.xxx) ;
+
+ // Other corners
+ vec3 g = step(x0.yzx, x0.xyz);
+ vec3 l = 1.0 - g;
+ vec3 i1 = min( g.xyz, l.zxy );
+ vec3 i2 = max( g.xyz, l.zxy );
+
+ // x0 = x0 - 0.0 + 0.0 * C.xxx;
+ // x1 = x0 - i1 + 1.0 * C.xxx;
+ // x2 = x0 - i2 + 2.0 * C.xxx;
+ // x3 = x0 - 1.0 + 3.0 * C.xxx;
+ vec3 x1 = x0 - i1 + C.xxx;
+ vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y
+ vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y
+
+ // Permutations
+ i = mod289(i);
+ vec4 p = permute( permute( permute(
+ i.z + vec4(0.0, i1.z, i2.z, 1.0 ))
+ + i.y + vec4(0.0, i1.y, i2.y, 1.0 ))
+ + i.x + vec4(0.0, i1.x, i2.x, 1.0 ));
+
+ // Gradients: 7x7 points over a square, mapped onto an octahedron.
+ // The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294)
+ float n_ = 0.142857142857; // 1.0/7.0
+ vec3 ns = n_ * D.wyz - D.xzx;
+
+ vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7)
+
+ vec4 x_ = floor(j * ns.z);
+ vec4 y_ = floor(j - 7.0 * x_ ); // mod(j,N)
+
+ vec4 x = x_ *ns.x + ns.yyyy;
+ vec4 y = y_ *ns.x + ns.yyyy;
+ vec4 h = 1.0 - abs(x) - abs(y);
+
+ vec4 b0 = vec4( x.xy, y.xy );
+ vec4 b1 = vec4( x.zw, y.zw );
+
+ //vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0;
+ //vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0;
+ vec4 s0 = floor(b0)*2.0 + 1.0;
+ vec4 s1 = floor(b1)*2.0 + 1.0;
+ vec4 sh = -step(h, vec4(0.0));
+
+ vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ;
+ vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ;
+
+ vec3 p0 = vec3(a0.xy,h.x);
+ vec3 p1 = vec3(a0.zw,h.y);
+ vec3 p2 = vec3(a1.xy,h.z);
+ vec3 p3 = vec3(a1.zw,h.w);
+
+ //Normalise gradients
+ vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3)));
+ p0 *= norm.x;
+ p1 *= norm.y;
+ p2 *= norm.z;
+ p3 *= norm.w;
+
+ // Mix final noise value
+ vec4 m = max(0.5 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);
+ m = m * m;
+ return 105.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1),
+ dot(p2,x2), dot(p3,x3) ) );
+}
/* try expanding horizontally first */
cell = orgcell + 1;
x = ra.x + 1;
- while(x < lvl->xsz && cell->type != CELL_SOLID) {
+ while(x++ < lvl->xsz && cell->type == CELL_SOLID) {
ra.w++;
cell++;
}
while(y++ < lvl->ysz) {
int rowsz = 0;
x = ra.x;
- while(x++ < lvl->xsz && cell->type != CELL_SOLID) {
+ while(x++ < lvl->xsz && cell->type == CELL_SOLID) {
rowsz++;
cell++;
}
/* then try the same thing, but vertical first */
cell = orgcell + lvl->xsz;
y = rb.y + 1;
- while(y++ < lvl->ysz && cell->type != CELL_SOLID) {
+ while(y++ < lvl->ysz && cell->type == CELL_SOLID) {
rb.h++;
cell += lvl->xsz;
}
int colsz = 0;
y = rb.y;
cell = lvl->cells + y * lvl->xsz + x;
- while(y++ < lvl->ysz && cell->type != CELL_SOLID) {
+ while(y++ < lvl->ysz && cell->type == CELL_SOLID) {
colsz++;
cell += lvl->xsz;
}
cell = lvl->cells;
for(i=0; i<lvl->ysz; i++) {
for(j=0; j<lvl->xsz; j++) {
- if(cell->type != CELL_SOLID && !cell->visited) {
+ if(cell->type == CELL_SOLID && !cell->visited) {
rect.x = j;
rect.y = i;
rect.w = rect.h = 1;
fprintf(fp, "SDRSTART\n");
- fprintf(fp, "float eval_sdf(in vec3 p)\n");
+ fprintf(fp, "float eval_sdf_gen(in vec3 p)\n");
fprintf(fp, "{\n");
rect = lvl->rects;
for(i=0; i<num; i++) {
int main(int argc, char **argv)
{
glutInit(&argc, argv);
- glutInitWindowSize(1280, 800);
+ glutInitWindowSize(1280, 720);
glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
glutCreateWindow("raydungeon");
#include "treestor.h"
#define DEF_XRES 1280
-#define DEF_YRES 800
+#define DEF_YRES 720
#define DEF_VSYNC 1
#define DEF_VOL 255
#define DEF_MUS 1
#define DEF_INVMOUSEY 0
#define DEF_MOUSE_SPEED 50
+#define DEF_GFX_RENDRES 1
struct options opt = {
DEF_XRES, DEF_YRES,
DEF_MUS,
DEF_INVMOUSEY,
DEF_MOUSE_SPEED,
+
+ { DEF_GFX_RENDRES }
};
int parse_options(int argc, char **argv)
opt.inv_mouse_y = ts_lookup_int(cfg, "options.controls.invmousey", DEF_INVMOUSEY);
opt.mouse_speed = ts_lookup_int(cfg, "options.controls.mousespeed", DEF_MOUSE_SPEED);
+ opt.gfx.render_res = ts_lookup_num(cfg, "options.gfx.render_res", DEF_GFX_RENDRES);
+
ts_free_tree(cfg);
return 0;
}
#define WROPT(lvl, fmt, val, defval) \
do { \
int i; \
+ if((val) == (defval)) fputc('#', fp); \
for(i=0; i<lvl; i++) fputc('\t', fp); \
- if((val) == (defval)) { \
- fprintf(fp, fmt "\t# default\n", val); \
- } else { \
- fprintf(fp, fmt "\n", val); \
- } \
+ fprintf(fp, fmt "\n", val); \
} while(0)
int save_options(const char *fname)
{
FILE *fp;
+ static const char *hdr = "# Game options\n# ------------\n"
+ "# Lines starting with '#' are comments. Options set to their default value are\n"
+ "# automatically commented when this file is written. If you want to change some\n"
+ "# option, make sure to remove the '#' from the beginning of the line, or your\n"
+ "# change will have no effect.\n";
+
printf("writing config: %s\n", fname);
if(!(fp = fopen(fname, "wb"))) {
fprintf(stderr, "failed to save options (%s): %s\n", fname, strerror(errno));
}
+ fprintf(fp, "%s\n", hdr);
fprintf(fp, "options {\n");
fprintf(fp, "\tvideo {\n");
WROPT(2, "xres = %d", opt.xres, DEF_XRES);
WROPT(2, "fullscreen = %d", opt.fullscreen, DEF_FULLSCR);
fprintf(fp, "\t}\n");
+ fprintf(fp, "\tgfx {\n");
+ WROPT(2, "render_res = %f", opt.gfx.render_res, DEF_GFX_RENDRES);
+ fprintf(fp, "\t}\n");
+
fprintf(fp, "\taudio {\n");
WROPT(2, "volmaster = %d", opt.vol_master, DEF_VOL);
WROPT(2, "volmusic = %d", opt.vol_mus, DEF_VOL);
#define OPTIONS_H_
struct gfxoptions {
- int foo;
+ float render_res; /* 0.5 means render at half-res and scale by 2 */
};
struct options {
#include "sdr.h"
#include "level.h"
#include "util.h"
+#include "options.h"
static int ginit(void);
static void gdestroy(void);
static float proj_mat[16], view_mat[16];
-static float cam_theta, cam_phi = 20, cam_dist = 10;
+static float cam_theta, cam_phi, cam_dist;
static cgm_vec3 cam_pan;
static unsigned int sdr;
+static int rbuf_width, rbuf_height;
+static unsigned int fbo, rbuf_col, rbuf_zbuf;
+
+
static int ginit(void)
{
return 0;
static void gdestroy(void)
{
+ glDeleteRenderbuffers(1, &rbuf_col);
+ glDeleteRenderbuffers(1, &rbuf_zbuf);
+ glDeleteFramebuffers(1, &fbo);
}
static int gstart(void)
if(load_level(lvl, "data/test.lvl") == -1) {
return -1;
}
- cam_pan.x = -(lvl->xsz / 2.0f) * lvl->scale;
+ cam_pan.x = -lvl->sx * lvl->scale;
cam_pan.y = 0;
- cam_pan.z = -(lvl->ysz / 2.0f) * lvl->scale;
+ cam_pan.z = -lvl->sy * 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");
+ add_shader_header(GL_FRAGMENT_SHADER, "#define TEST_SDF\n");
}
if(!(sdr = create_program_load("sdr/raydungeon.v.glsl", "sdr/raydungeon.p.glsl"))) {
return -1;
float x, y;
struct level_cell *cell;
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+ glViewport(0, 0, rbuf_width, rbuf_height);
+
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
cgm_mtranslation(view_mat, 0, 0, -cam_dist);
for(j=0; j<lvl->xsz; j++) {
x = (float)j * lvl->scale;
if(cell->type) {
- glVertex3f(x - 0.48, -1, y - 0.48);
- glVertex3f(x + 0.48, -1, y - 0.48);
- glVertex3f(x + 0.48, -1, y + 0.48);
- glVertex3f(x - 0.48, -1, y + 0.48);
+ glVertex3f(x - 0.48 * lvl->scale, -1, y - 0.48 * lvl->scale);
+ glVertex3f(x + 0.48 * lvl->scale, -1, y - 0.48 * lvl->scale);
+ glVertex3f(x + 0.48 * lvl->scale, -1, y + 0.48 * lvl->scale);
+ glVertex3f(x - 0.48 * lvl->scale, -1, y + 0.48 * lvl->scale);
}
cell++;
}
}
glEnd();
+
+ glViewport(0, 0, win_width, win_height);
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ glBlitFramebuffer(0, 0, rbuf_width, rbuf_height, 0, 0, win_width, win_height,
+ GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
static void greshape(int x, int y)
{
- cgm_mperspective(proj_mat, cgm_deg_to_rad(60), win_aspect, 0.5, 40.0);
+ cgm_mperspective(proj_mat, cgm_deg_to_rad(60), win_aspect, 0.5, 200.0);
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(proj_mat);
+
+ rbuf_width = ((int)(x * opt.gfx.render_res) + 3) & 0xfffffc;
+ rbuf_height = ((int)(y * opt.gfx.render_res) + 3) & 0xfffffc;
+ printf("render buffer %dx%d\n", rbuf_width, rbuf_height);
+
+ if(!fbo) {
+ glGenFramebuffers(1, &fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+
+ glGenRenderbuffers(1, &rbuf_col);
+ glBindRenderbuffer(GL_RENDERBUFFER, rbuf_col);
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB, rbuf_width, rbuf_height);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbuf_col);
+
+ glGenRenderbuffers(1, &rbuf_zbuf);
+ glBindRenderbuffer(GL_RENDERBUFFER, rbuf_zbuf);
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, rbuf_width, rbuf_height);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbuf_zbuf);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ } else {
+ glBindRenderbuffer(GL_RENDERBUFFER, rbuf_col);
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB, rbuf_width, rbuf_height);
+
+ glBindRenderbuffer(GL_RENDERBUFFER, rbuf_zbuf);
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, rbuf_width, rbuf_height);
+ }
}
static void gkeyb(int key, int press)
{
float proj_mat[16];
- cgm_mperspective(proj_mat, cgm_deg_to_rad(60), win_aspect, 0.5, 40.0);
+ cgm_mperspective(proj_mat, cgm_deg_to_rad(60), win_aspect, 0.5, 500.0);
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(proj_mat);
}