From 7c3c34c3d80c19ee3e4d5007f5666fbc8a29a3bc Mon Sep 17 00:00:00 2001 From: Zeno Rogue Date: Sat, 1 Aug 2020 13:59:53 +0200 Subject: [PATCH] sky-based fog in 2.5D --- config.cpp | 2 + drawing.cpp | 2 + glhr.cpp | 6 +- shaders.cpp | 45 ++++++++++++- sky.cpp | 191 +++++++++++++++++++++++++++++++++++++++++++++------- 5 files changed, 218 insertions(+), 28 deletions(-) diff --git a/config.cpp b/config.cpp index 41b11101..bdc0df26 100644 --- a/config.cpp +++ b/config.cpp @@ -582,6 +582,8 @@ EX void initConfig() { sightranges[i] = 10; else if(ginf[i].cclass == gcSL2) sightranges[i] = 4.5; + else if(ginf[i].cclass == gcHyperbolic && ginf[i].g.gameplay_dimension == 2) + sightranges[i] = 4.5; else sightranges[i] = 5; sightranges[gArchimedean] = 10; diff --git a/drawing.cpp b/drawing.cpp index a8151217..638df46c 100644 --- a/drawing.cpp +++ b/drawing.cpp @@ -1999,6 +1999,8 @@ void dqi_line::draw_back() { EX void sort_drawqueue() { + if(WDIM == 2 && GDIM == 3 && hyperbolic) make_air(); + DEBBI(DF_GRAPH, ("sort_drawqueue")); for(int a=0; a> compiled_programs; @@ -268,7 +269,39 @@ shared_ptr write_shader(flagtype shader_flags) { if(!skip_t) { vmain += "mediump vec4 t = uMV * aPosition;\n"; vmain += coordinator; - if(distfun != "") { + if(GDIM == 3 && WDIM == 2) { + vsh += + "uniform mediump mat4 uRadarTransform;\n" + "uniform mediump sampler2D tAirMap;\n" + "uniform mediump float uFog;\n" + "uniform mediump float uFogBase;\n" + "vec4 color_at(vec4 ending, float dist) {" + " vec3 pt = ending.xyz * sinh(dist);\n" + " pt.xy /= sqrt(pt.z*pt.z+1.);\n" + " pt.xy /= 2. * (1. + sqrt(1.+pt.x*pt.x+pt.y*pt.y));\n" + " pt.xy += vec2(.5, .5);\n" + " return texture2D(tAirMap, pt.xy);\n" + " }\n"; + + vmain += + "vec4 ending = uRadarTransform * t;\n" + "float len = acosh(ending.w);\n" + "float eulen = length(ending.xyz);\n" + "ending.xyz /= eulen;\n" + "ending.y *= -1.;\n" + "vec4 fog = vec4(1e-3,0,1e-3,1e-3);\n" + "vec4 last = vec4(0,0,0,0);\n" + "for(int i=0; i<50; i++) {\n" + " vec4 px = color_at(ending, ((float(i) + .5) / 50.) * min(len, uFog));\n" + " if(px.r < .9 || px.b < .9 || px.g > .1) last = px;\n" + " fog += last;\n" + " }\n" + "mediump float fogs = (uFogBase - len / uFog);\n" + "if(fogs < 0.) fogs = 0.;\n" + "fog.xyz /= fog.w;\n" + "vColor.xyz = vColor.xyz * fogs + fog.xyz * (1.0-fogs);\n"; + } + else if(distfun != "") { vmain += "mediump float fogs = (uFogBase - " + distfun + " / uFog);\n"; vmain += "vColor.xyz = vColor.xyz * fogs + uFogColor.xyz * (1.0-fogs);\n"; vsh += @@ -357,6 +390,16 @@ void display_data::set_projection(int ed, ld shift) { } #endif + if(selected->tAirMap != -1) { + glActiveTexture(GL_TEXTURE0 + AIR_BINDING); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glBindTexture(GL_TEXTURE_2D, airbuf->renderedTexture); + glUniform1i(selected->tAirMap, AIR_BINDING); + glActiveTexture(GL_TEXTURE0 + 0); + glUniformMatrix4fv(selected->uRadarTransform, 1, 0, glhr::tmtogl_transpose3(radar_transform).as_array()); + } + if(selected->uIterations != -1) { glhr::set_index_sl(0); glhr::set_sv(stretch::not_squared()); diff --git a/sky.cpp b/sky.cpp index 28459690..c8b23ea6 100644 --- a/sky.cpp +++ b/sky.cpp @@ -16,7 +16,8 @@ struct sky_item { cell *c; shiftmatrix T; color_t color; - sky_item(cell *_c, const struct shiftmatrix _T, color_t _color) : c(_c), T(_T), color(_color) {} + color_t skycolor; + sky_item(cell *_c, const struct shiftmatrix _T, color_t _color, color_t _skycolor) : c(_c), T(_T), color(_color), skycolor(_skycolor) {} }; struct dqi_sky : drawqueueitem { @@ -41,7 +42,7 @@ EX void prepare_sky() { queuepolyat(T * zpush(cgi.SKY+0.5) * xpush(cgi.SKY+0.5), cgi.shSun, 0xFFFF00FF, PPR::SKY); } else if(!(cgflags & qIDEAL)) { - sky = &queuea (PPR::SKY); + sky = &queuea (PPR::MISSILE); } } @@ -52,13 +53,17 @@ void dqi_sky::draw() { int sk = get_skybrightness(); - unordered_map colors; + unordered_map> colors; #ifdef USE_UNORDERED_MAP colors.reserve(isize(sky)); #endif - for(sky_item& si: sky) colors[si.c] = darkena(gradient(0, si.color, 0, sk, 255), 0, 0xFF); + for(sky_item& si: sky) colors[si.c] = + make_pair(darkena(gradient(0, si.color, 0, sk, 255), 0, 0xFF), + darkena(si.skycolor, 0, 0xFF) + ); hyperpoint skypoint = cpush0(2, cgi.SKY); + hyperpoint hellpoint = cpush0(2, -cgi.SKY); vector this_poly; @@ -72,12 +77,42 @@ void dqi_sky::draw() { auto c = si.c; for(int i=0; itype; i++) { + if(1) { + cellwalker cw0(c, i); + cellwalker cw2 = cw0; + cw2--; cw2 += wstep; + if(!colors.count(cw2.at)) { + this_poly.clear(); + transmatrix T1 = unshift(si.T); + T1 = Tsh * T1; + auto cw = cw0; + while(colors.count(cw.at)) { + color_t col = colors[cw.at].second; + this_poly.emplace_back(T1 * skypoint, colors[cw.at].first); + this_poly.emplace_back(T1 * hellpoint, col); + T1 = T1 * currentmap->adj(cw.at, cw.spin); + cw += wstep; cw++; + } + + int k = isize(this_poly); + for(int j=2; jadj(cw.at, cw.spin); cw += wstep; cw++; } @@ -125,20 +160,17 @@ color_t skycolor(cell *c) { int cd = (euclid || stdhyperbolic) ? getCdata(c, 1) : 0; int z = (cd * 5) & 127; if(z >= 64) z = 127 - z; - if(c->land == laHell) - return z < 32 ? gradient(0x400000, 0xFF0000, 0, z, 32) : gradient(0xFF0000, 0xFFFF00, 32, z, 63); - else - return gradient(0x4040FF, 0xFFFFFF, 0, z, 63); + return gradient(0x4040FF, 0xFFFFFF, 0, z, 63); } void celldrawer::draw_ceiling() { if(pmodel != mdPerspective || sphere) return; - auto add_to_sky = [this] (color_t col) { + auto add_to_sky = [this] (color_t col, color_t col2) { if(cgflags & qIDEAL) draw_shapevec(c, V, qfi.fshape->levels[SIDE_HIGH], darkena(col, 0, 0xFF), PPR::WALL); - else if(sky) sky->sky.emplace_back(c, V, col); + else if(sky) sky->sky.emplace_back(c, V, col, col2); }; switch(ceiling_category(c)) { @@ -148,7 +180,7 @@ void celldrawer::draw_ceiling() { if(fieldpattern::fieldval_uniq(c) % 3 == 0) { queuepolyat(V * zpush(cgi.SKY+1), cgi.shNightStar, 0xFFFFFFFF, PPR::SKY); } - add_to_sky(0x00000F); + add_to_sky(0x00000F, 0x00000F); if(c->land == laAsteroids) { if(fieldpattern::fieldval_uniq(c) % 9 < 3) { queuepolyat(V * zpush(-1-cgi.SKY), cgi.shNightStar, 0xFFFFFFFF, PPR::SKY); @@ -163,10 +195,12 @@ void celldrawer::draw_ceiling() { case 2: { if(euclid) return; color_t col; + color_t skycol; switch(c->land) { case laWineyard: col = 0x4040FF; + skycol = 0x8080FF; if(emeraldval(c) / 4 == 11) { queuepolyat(V * zpush(cgi.SKY+1), cgi.shSun, 0xFFFF00FF, PPR::SKY); } @@ -174,22 +208,23 @@ void celldrawer::draw_ceiling() { case laFrog: col = 0x4040FF; + skycol = 0x8080FF; if(zebra40(c) / 4 == 1) { queuepolyat(V * zpush(cgi.SKY+1), cgi.shSun, 0xFFFF00FF, PPR::SKY); } break; case laPower: - col = c->landparam ? 0xFF2010 : 0x000020; + skycol = col = c->landparam ? 0xFF2010 : 0x000020; break; case laDesert: - case laRedRock: col = 0x4040FF; + skycol = (0xCDA98F & 0xFEFEFE) / 2; break; case laAlchemist: - col = fcol; + skycol = col = fcol; break; case laVariant: { @@ -199,22 +234,38 @@ void celldrawer::draw_ceiling() { if((b >> a) & 1) col += variant::features[a].color_change; col = col & 0x00FF00; + skycol = col; break; } case laDragon: col = c->wall == waChasm ? 0xFFFFFF : 0x4040FF; + skycol = 0; break; - default: + case laHell: { + int a = 0; + forCellEx(c1, c) if(among(c1->wall, waSulphur, waSulphurC)) a++; + ld z = a * 1. / c->type; + if(z < .5) + col = gradient(0x400000, 0xFF0000, 0, z, .5); + else + col = gradient(0xFF0000, 0xFFFF00, .5, z, 1); + skycol = col; + break; + } + + default: { col = skycolor(c); + skycol = 0xA0A0FF; + } } - add_to_sky(col); + add_to_sky(col, skycol); return; } case 3: { - add_to_sky(0); + add_to_sky(0, 0); if(camera_level <= cgi.WALL) return; if(c->land == laMercuryRiver) fcol = linf[laTerracotta].color, fd = 1; if(qfi.fshape) draw_shapevec(c, V, qfi.fshape->levels[SIDE_WALL], darkena(fcol, fd, 0xFF), PPR::WALL); @@ -229,7 +280,7 @@ void celldrawer::draw_ceiling() { } case 4: { - add_to_sky(0x00000F); + add_to_sky(0x00000F, 0x00000F); if(camera_level <= cgi.HIGH2) return; auto ispal = [&] (cell *c0) { return c0->land == laPalace && among(c0->wall, waPalace, waClosedGate, waOpenGate); }; color_t wcol2 = 0xFFD500; @@ -255,7 +306,7 @@ void celldrawer::draw_ceiling() { } case 6: { - add_to_sky(skycolor(c)); + add_to_sky(skycolor(c), 0x4040C0); if(camera_level <= cgi.HIGH2) return; color_t wcol2 = winf[waRuinWall].color; if(c->landparam == 1) @@ -264,15 +315,15 @@ void celldrawer::draw_ceiling() { if(c->landparam != 2) forCellIdEx(c2, i, c) if(c2->landparam == 2) placeSidewall(c, i, SIDE_HIGH2, V, darkena(wcol2, fd, 0xFF)); - if(c->landparam == 0) - if(qfi.fshape) draw_shapevec(c, V, qfi.fshape->levels[SIDE_HIGH], darkena(wcol2, fd, 0xFF), PPR::WALL); + /* if(c->landparam == 0) + if(qfi.fshape) draw_shapevec(c, V, qfi.fshape->levels[SIDE_HIGH], darkena(wcol2, fd, 0xFF), PPR::WALL); */ if(c->landparam == 1) if(qfi.fshape) draw_shapevec(c, V, qfi.fshape->levels[SIDE_WALL], darkena(wcol2, fd, 0xFF), PPR::WALL); break; } case 7: { - add_to_sky(0x00000F); + add_to_sky(0x00000F, 0x00000F); if(fieldpattern::fieldval_uniq(c) % 5 < 2) { queuepolyat(V * zpush(cgi.SKY+1), cgi.shNightStar, 0xFFFFFFFF, PPR::SKY); } @@ -292,7 +343,7 @@ void celldrawer::draw_ceiling() { } case 5: { - add_to_sky(0x00000F); + add_to_sky(0x00000F, 0x00000F); if(camera_level <= cgi.WALL) return; if(pseudohept(c)) { @@ -309,5 +360,95 @@ void celldrawer::draw_ceiling() { } } } + +EX struct renderbuffer *airbuf; + +EX void make_air() { + if(!sky) return; + const int AIR_TEXTURE = 512; + if(!airbuf) { + airbuf = new renderbuffer(AIR_TEXTURE, AIR_TEXTURE, true); + if(!airbuf->valid) { + delete airbuf; + airbuf = nullptr; + println(hlog, "unable to make airbuf"); + return; + } + } + + if(1) { + //shot::take("airtest.png", drawqueue); + dynamicval v(vid, vid); + dynamicval vi(inHighQual, true); + + vid.xres = AIR_TEXTURE; + vid.yres = AIR_TEXTURE; + calcparam(); + models::configure(); + + resetbuffer rb; + airbuf->enable(); + current_display->set_viewport(0); + + airbuf->clear(0xFFFF00FF); + + pconf.alpha = 1; + pconf.scale = 1; + pconf.camera_angle = 0; + pconf.stretch = 1; + pmodel = mdDisk; + + vid.always3 = false; + geom3::apply_always3(); + check_cgi(); + cgi.require_shapes(); + + eGeometry orig = geometry; + + glDisable(GL_LINE_SMOOTH); + + for(auto& g: sky->sky) { + transmatrix S; + if(1) { + geometry = gSpace534; + S = g.T.T; + S = radar_transform * S; + geometry = orig; + swapmatrix(S); + } + + auto& h = cgi.shFullFloor.b[shvid(g.c)]; + + dqi_poly p; + p.V = shiftless(S); + p.offset = h.s; + p.cnt = h.e - h.s; + p.tab = &cgi.ourshape; + p.color = (g.skycolor << 8) | 0xFF; + p.outline = 0; + + p.linewidth = 1; + p.flags = POLY_FORCEWIDE; + p.tinf = nullptr; + + p.draw(); + } + + if(vid.antialias & AA_LINES) + glEnable(GL_LINE_SMOOTH); + + if(anyshiftclick) IMAGESAVE(airbuf->render(), "air.png"); + rb.reset(); + } + + GLERR("after draw"); + geom3::apply_always3(); + check_cgi(); + calcparam(); + GLERR("after make_air"); + current_display->set_viewport(0); + current_display->set_all(0,0); + } + #endif }