From edbbb51135f91786c399b4f0d2cf28cdc1536e61 Mon Sep 17 00:00:00 2001 From: Zeno Rogue Date: Tue, 22 Oct 2019 00:37:57 +0200 Subject: [PATCH] basic raycaster implementation --- graph.cpp | 12 +- hyper.cpp | 1 + raycaster.cpp | 346 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 357 insertions(+), 2 deletions(-) create mode 100644 raycaster.cpp diff --git a/graph.cpp b/graph.cpp index 386c9795..56c731a1 100644 --- a/graph.cpp +++ b/graph.cpp @@ -6065,6 +6065,7 @@ EX void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) { color_t dummy; int ofs = wall_offset(c); if(isWall3(c, wcol)) { + if(!use_raycasting) { color_t wcol2 = wcol; #if CAP_TEXTURE if(texture::config.tstate == texture::tsActive) wcol2 = texture::config.recolor(wcol); @@ -6115,9 +6116,9 @@ EX void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) { queuepoly(V, cgi.shPlainWall3D[ofs + a], darkena(wcol2 - d * get_darkval(c, a), 0, 0xFF)); } } - } + } } else { - for(int a=0; atype; a++) if(c->move(a)) { + if(!use_raycasting) for(int a=0; atype; a++) if(c->move(a)) { color_t t = transcolor(c, c->move(a), wcol); if(t) { t = t - get_darkval(c, a) * ((t & 0xF0F0F000) >> 4); @@ -7345,6 +7346,8 @@ EX void precise_mouseover() { EX transmatrix Viewbase; +EX bool use_raycasting; + EX void drawthemap() { check_cgi(); cgi.require_shapes(); @@ -7398,6 +7401,10 @@ EX void drawthemap() { for(int m=0; mdraw(); + if(use_raycasting) do_raycast(); drawWormSegments(); drawBlizzards(); drawArrowTraps(); diff --git a/hyper.cpp b/hyper.cpp index 378ab0dc..2346b1f1 100644 --- a/hyper.cpp +++ b/hyper.cpp @@ -25,6 +25,7 @@ #include "classes.cpp" #include "glhr.cpp" #include "shaders.cpp" +#include "raycaster.cpp" #include "hprint.cpp" #include "util.cpp" #include "hyperpoint.cpp" diff --git a/raycaster.cpp b/raycaster.cpp new file mode 100644 index 00000000..0e209271 --- /dev/null +++ b/raycaster.cpp @@ -0,0 +1,346 @@ +// Hyperbolic Rogue -- raycaster +// Copyright (C) 2011-2019 Zeno Rogue, see 'hyper.cpp' for details + +/** \file raycaster.cpp + * \brief A raycaster to draw walls. + */ + +#include "hyper.h" + +namespace hr { + +GLuint txConnections = 0, txWallcolor = 0, txMatrixid = 0, txWallTexture = 0; + +#define IN_ODS 0 + +struct raycaster : glhr::GLprogram { + GLint uStart, uStartid, uN, uM, uLength, uFovX, uFovY, uIPD; + GLint tConnections, tWallTexture, tWallcolor, tMatrixid; + + raycaster(string vsh, string fsh) : GLprogram(vsh, fsh) { + println(hlog, "assigning"); + uStart = glGetUniformLocation(_program, "uStart"); + uStartid = glGetUniformLocation(_program, "uStartid"); + uN = glGetUniformLocation(_program, "uN"); + uM = glGetUniformLocation(_program, "uM"); + uLength = glGetUniformLocation(_program, "uLength"); + uFovX = glGetUniformLocation(_program, "uFovX"); + uFovY = glGetUniformLocation(_program, "uFovY"); + uIPD = glGetUniformLocation(_program, "uIPD"); + + tConnections = glGetUniformLocation(_program, "tConnections"); + tWallTexture = glGetUniformLocation(_program, "tWallTexture"); + tWallcolor = glGetUniformLocation(_program, "tWallcolor"); + tMatrixid = glGetUniformLocation(_program, "tMatrixid"); + } + }; + +shared_ptr our_raycaster; + +void enable_raycaster() { + if(!our_raycaster) { + string vsh = + "#define PI 3.14159265358979324\n" + "attribute vec4 aPosition;\n" + "uniform float uFovX, uFovY;\n" + "varying vec4 at;\n" + "void main() { \n" + " gl_Position = aPosition; at = aPosition; \n" + #if IN_ODS + " at[0] *= PI; at[1] *= PI; \n" + #else + " at[0] *= uFovX; at[1] *= uFovY; \n" + #endif + " }\n"; + + string fsh = + "varying vec4 at;\n" + "uniform int uN;\n" + "uniform int uLength;\n" + "uniform float uIPD;\n" + "uniform mat4 uStart;\n" + "uniform mat4 uM[84];\n" + "uniform mat4 uTest;\n" + "uniform float uStartid;\n" + "uniform sampler1D tConnections;\n" + "uniform sampler1D tWallcolor;\n" + "uniform sampler2D tWallTexture;\n" + "uniform sampler1D tMatrixid;\n" + + "mat4 xpush(float x) { return mat4(" + "cosh(x), 0., 0., sinh(x),\n" + "0., 1., 0., 0.,\n" + "0., 0., 1., 0.,\n" + "sinh(x), 0., 0., cosh(x)" + ");}\n" + + "mat4 xzspin(float x) { return mat4(" + "cos(x), 0., sin(x), 0.,\n" + "0., 1., 0., 0.,\n" + "-sin(x), 0., cos(x), 0.,\n" + "0., 0., 0., 1." + ");}\n" + + "mat4 yzspin(float x) { return mat4(" + "1., 0., 0., 0.,\n" + "0., cos(x), sin(x), 0.,\n" + "0., -sin(x), cos(x), 0.,\n" + "0., 0., 0., 1." + ");}\n" + + "void main() { \n" + + #if IN_ODS + " float lambda = at[0];\n" // -PI to PI + " float phi;\n" + " float eye;\n" + " if(at.y < 0.) { phi = at.y + PI/2.; eye = uIPD / 2.; }\n" // right + " else { phi = at.y - PI/2.; eye = -uIPD / 2.; }\n" + " mat4 vw = uStart * xzspin(-lambda) * xpush(eye) * yzspin(phi);\n" + " vec4 at0 = vec4(0., 0., 1., 0.);\n" + #else + " mat4 vw = uStart;\n" + " vec4 at0 = at;" + " at0.y = -at.y;" +// " at0.z = at.y;" + " at0.w = 0.;\n" + " at0.xyz = at0.xyz / length(at0.xyz);" + #endif + " vec4 position = vw * vec4(0., 0., 0., 1.);" + " vec4 tangent = vw * at0;" + " float go = 0.;" + " float cid = uStartid;" +// " int purp = 0;" + " for(int iter=0; iter<60; iter++) {" + " float dist = 100.;" + " int which = -1;" + + " if(go == 0.) {\n" + " float best = position[3];\n" + " for(int i=0; i 1. || v < -1.) continue;\n" + " float d = atanh(v);\n" + " vec4 next_tangent = position * sinh(d) + tangent * cosh(d);\n" + " if(next_tangent[3] < (uM[i] * next_tangent)[3]) continue;\n" +// " if(d < 1e-4) continue;\n" + " if(d < dist) { dist = d; which = i; }\n" + "}" + " if(which == -1) { gl_FragColor = vec4(0., 0., 0., 1.); return; }" + // shift d units + " if(dist < 0.) { dist = 0.; }\n" + " go = go + dist;\n" + " float ch = cosh(dist); float sh = sinh(dist);\n" + " vec4 v = position * ch + tangent * sh;\n" + " tangent = tangent * ch + position * sh;\n" + " position = v;" + // apply wall color + " float u = cid + float(which) / float(uLength);\n" + " vec4 col = texture1D(tWallcolor, u);\n" + " if(col[3] > 0.0) {\n" + " vec4 inface = uM[uN+which] * position;\n" + " inface = inface / inface.w;" + " float bright = texture2D(tWallTexture, (inface.yz + vec2(1.,1.))/2.).r;\n" + " col.xyz = col.xyz * bright * max(1.-go/7., 0.5 * exp(-go/4.));\n" // exp(-go/4.);\n" + " col.w = 1.;\n" +// " if(purp == 1) { col.rgb = (col.rgb + vec3(1., 0., 1.)) / 2; }\n" + " gl_FragColor = col;\n" + " return;\n" + " }\n" + // next cell + " float rot = texture1D(tMatrixid, u).r;\n" + " int mid = int(rot * float(uLength));\n" + " position = uM[mid] * position;\n" + " tangent = uM[mid] * tangent;\n" + " cid = texture1D(tConnections, u).r;\n" + " }" + " gl_FragColor = vec4(0.,0.,0.,1.); \n" + " }"; + + our_raycaster = make_shared (vsh, fsh); + } + full_enable(our_raycaster); + } + +void bind_array(vector& v, GLuint t, GLuint& tx, int id) { + glUniform1i(t, id); + + if(tx == 0) glGenTextures(1, &tx); + + glActiveTexture(GL_TEXTURE0 + id); + glBindTexture(GL_TEXTURE_1D, tx); + + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + glTexImage1D(GL_TEXTURE_1D, 0, GL_R32F, isize(v), 0, GL_RED, GL_FLOAT, &v[0]); + GLERR("bind_array"); + } + +void bind_array(vector>& v, GLuint t, GLuint& tx, int id) { + glUniform1i(t, id); + + if(tx == 0) glGenTextures(1, &tx); + + glActiveTexture(GL_TEXTURE0 + id); + glBindTexture(GL_TEXTURE_1D, tx); + + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, isize(v), 0, GL_RGBA, GL_FLOAT, &v[0]); + GLERR("bind_array"); + } + +bool made_texture; + +void make_walltexture(GLuint t, GLuint& tx, int id) { + if(made_texture) return; + made_texture = true; + glUniform1i(our_raycaster->tWallTexture, id); + GLERR("pre walltexture"); + + if(tx == 0) glGenTextures(1, &tx); + GLERR("gentexture"); + + glActiveTexture(GL_TEXTURE0 + id); + GLERR("walltexture b"); + + glBindTexture(GL_TEXTURE_2D, tx); + GLERR("walltexture c"); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + GLERR("walltexture a"); + + constexpr int dsize = 1024; + + float data[dsize][dsize]; + + for(int y=0; y .9) maxd = (10 - 10 * maxd) * .9; + else maxd = 0.8 + 0.1 * max(sin(maxd*50), sin(atan2(h[1], h[0]) * 30 + M_PI/4)); + data[y][x] = maxd; + } + + glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, dsize, dsize, 0, GL_RED, GL_FLOAT, &data[0][0]); + GLERR("walltexture"); + } + +EX void do_raycast() { + enable_raycaster(); + + auto& o = our_raycaster; + + make_walltexture(o->tWallTexture, txWallTexture, 6); + + vector screen = { + glhr::makevertex(-1, -1, 1), + glhr::makevertex(-1, +1, 1), + glhr::makevertex(+1, -1, 1), + glhr::makevertex(-1, +1, 1), + glhr::makevertex(+1, -1, 1), + glhr::makevertex(+1, +1, 1) + }; + + auto& cd = current_display; + glUniform1f(o->uFovX, cd->tanfov); + glUniform1f(o->uFovY, cd->tanfov * cd->ysize / cd->xsize); + + celllister cl(viewctr.at->c7, 10, 3000, NULL); + + vector lst = cl.lst; + + map ids; + for(int i=0; iuLength, length); + GLERR("uniform length"); + auto enc = [&] (int i) { return float((i+.5) / length); }; + + // for(auto &m: reg3::spins) println(hlog, m); + + glUniformMatrix4fv(o->uStart, 1, 0, glhr::tmtogl_transpose(inverse(View)).as_array()); + GLERR("uniform start"); + glUniform1i(o->uN, S7); + GLERR("uniform N"); + glUniform1f(o->uStartid, enc(ids[viewctr.at->c7] * S7)); + GLERR("uniform startid"); + glUniform1f(o->uIPD, vid.ipd); + GLERR("uniform IPD"); + + vector ms; + for(int j=0; j connections(length); + vector> wallcolor(length); + vector matrixid(length); + + if(1) for(cell *c: lst) { + int id = ids[c]; + forCellIdEx(c1, i, c) { + int u = id * S7 + i; + if(!ids.count(c1)) { + wallcolor[u] = glhr::acolor(0xFF); + continue; + } + connections[u] = enc(ids[c1] * S7); + if(isWall3(c1)) { + color_t wcol; + color_t fcol; + setcolors(c1, wcol, fcol); + wcol = darkena(wcol, 0, 0xFF); + wallcolor[u] = glhr::acolor(wcol); + } + else + wallcolor[u] = glhr::acolor(0); + + transmatrix T = currentmap->relative_matrix(c->master, c1->master); + for(int k=0; k<=isize(ms); k++) { + if(k < isize(ms) && !eqmatrix(ms[k], T)) continue; + if(k == isize(ms)) ms.push_back(T); + matrixid[u] = enc(k); + break; + } + } + } + + vector gms; + for(auto& m: ms) gms.push_back(glhr::tmtogl_transpose(m)); + glUniformMatrix4fv(o->uM, isize(gms), 0, gms[0].as_array()); + + bind_array(wallcolor, o->tWallcolor, txWallcolor, 4); + bind_array(connections, o->tConnections, txConnections, 3); + bind_array(matrixid, o->tMatrixid, txMatrixid, 5); + + glVertexAttribPointer(hr::aPosition, 4, GL_FLOAT, GL_FALSE, sizeof(glvertex), &screen[0]); + glhr::set_depthtest(false); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glDrawArrays(GL_TRIANGLES, 0, 6); + GLERR("finish"); + + glActiveTexture(GL_TEXTURE0 + 0); + } + +}