mirror of
				https://github.com/zenorogue/hyperrogue.git
				synced 2025-10-30 13:32:59 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			730 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			730 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "hyper.h"
 | |
| 
 | |
| namespace hr {
 | |
| 
 | |
| EX bool context_fog = true;
 | |
| 
 | |
| EX ld camera_level;
 | |
| EX bool camera_sign;
 | |
| 
 | |
| #if HDR
 | |
| enum eSkyMode { skyNone, skyAutomatic, skySkybox, skyAlways };
 | |
| #endif
 | |
| 
 | |
| EX eSkyMode draw_sky;
 | |
| 
 | |
| EX bool auto_remove_roofs;
 | |
| EX bool simple_sky;
 | |
| 
 | |
| EX bool camera_over(ld x) {
 | |
|   if(!auto_remove_roofs) return false;
 | |
|   if(camera_sign) return camera_level <= x;
 | |
|   return camera_level >= x;
 | |
|   }
 | |
| 
 | |
| #if MAXMDIM >= 4 && CAP_GL
 | |
| 
 | |
| EX int get_skybrightness(int mul IS(1)) {
 | |
|   if(simple_sky) return 255;
 | |
|   ld s = 1 - mul * (camera_level - cgi.WALL) / -2;
 | |
|   if(s > 1) return 255;
 | |
|   if(s < 0) return 0;
 | |
|   return int(s * 255);
 | |
|   }
 | |
| 
 | |
| struct sky_item {
 | |
|   cell *c;
 | |
|   shiftmatrix T;
 | |
|   color_t 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 {
 | |
|   vector<sky_item> sky;
 | |
|   void draw() override;
 | |
|   color_t outline_group() override { return 3; }
 | |
|   // singleton
 | |
|   explicit dqi_sky() { hr::sky = this; }
 | |
|   ~dqi_sky() override { hr::sky = NULL; }
 | |
|   };
 | |
|   
 | |
| EX struct dqi_sky *sky;
 | |
| 
 | |
| EX bool do_draw_skybox() {
 | |
|   if(no_wall_rendering) return false;
 | |
|   if(!euclid) return false;
 | |
|   if(draw_sky == skySkybox) return true;
 | |
|   if(!embedded_plane) return false;
 | |
|   if(draw_sky == skyAutomatic) return !cgi.emb->is_sph_in_low() && !cgi.emb->is_cylinder();
 | |
|   return false;
 | |
|   }
 | |
| 
 | |
| EX void prepare_sky() {
 | |
|   sky = NULL;
 | |
|   if(do_draw_skybox()) {
 | |
|     shiftmatrix T = ggmatrix(currentmap->gamestart());
 | |
|     T.T = gpushxto0(tC0(T.T)) * T.T;
 | |
|     queuepoly(T, cgi.shEuclideanSky, 0x0044e4FF);
 | |
|     queuepolyat(T * zpush(cgi.STAR * 0.7) * xpush(cgi.STAR * 0.7), cgi.shSkyboxSun, 0xFFFF00FF, PPR::SKY);
 | |
|     }
 | |
|   else {
 | |
|     sky = &queuea<dqi_sky> (euclid ? PPR::EUCLIDEAN_SKY : PPR::MISSILE);
 | |
|     }
 | |
|   }
 | |
| 
 | |
| EX vector<glhr::colored_vertex> skyvertices;
 | |
| EX cell *sky_centerover;
 | |
| EX shiftmatrix sky_cview;
 | |
| 
 | |
| EX void delete_sky() {
 | |
|   sky_centerover = nullptr;
 | |
|   skyvertices.clear();
 | |
|   }
 | |
| 
 | |
| EX bool do_draw_sky() {
 | |
|   if(!embedded_plane) return false;
 | |
|   if(draw_sky == skyAlways) return true;
 | |
|   if(draw_sky != skyAutomatic) return false;
 | |
| 
 | |
|   if(vid.wall_height < 0 && cgi.emb->is_euc_in_hyp()) return false; /* just looks bad, hollow horospheres should not have sky */
 | |
|   if(vid.wall_height < 0 && meuclid && geom3::ggclass() == gcNIH) return false; /* same */
 | |
|   if(among(geom3::ggclass(), gcSol, gcSolN)) return false;  /* errors */
 | |
|   if(among(geom3::ggclass(), gcNil)) return false;  /* errors sometimes too */
 | |
|   if(cgi.emb->is_hyp_in_solnih()) return false;
 | |
|   if(cgi.emb->is_euc_in_product()) return false;
 | |
|   if(cgi.emb->is_euc_in_sl2()) return false;
 | |
|   if(cgi.emb->is_cylinder()) return false;
 | |
| 
 | |
|   return true;
 | |
|   }
 | |
| 
 | |
| EX bool do_draw_stars(bool rev) {
 | |
|   if(!do_draw_sky()) return false;
 | |
|   if(cgi.emb->is_sph_in_low()) {
 | |
|     if(cgi.SKY < 0) return false;
 | |
|     }
 | |
|   if(cgi.emb->is_euc_in_hyp() && (rev ? cgi.SKY > 0 : cgi.SKY < 0)) return false;
 | |
|   return true;
 | |
|   }
 | |
| 
 | |
| void compute_skyvertices(const vector<sky_item>& sky) {
 | |
|   skyvertices.clear();
 | |
|   if(!do_draw_sky()) return;
 | |
| 
 | |
|   int sk = get_skybrightness();
 | |
|   
 | |
|   std::map<cell*, pair<color_t, color_t>> colors;
 | |
|   for(const 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 + cgi.emb->center_z());
 | |
|   hyperpoint hellpoint = cpush0(2, cgi.HELL + cgi.emb->center_z());
 | |
|   
 | |
|   vector<glhr::colored_vertex> this_poly;
 | |
| 
 | |
|   for(const sky_item& si: sky) {
 | |
|     auto c = si.c;
 | |
|     
 | |
|     if(c->land == laMirrorWall) continue;
 | |
|     bool inmir = false;
 | |
|     forCellEx(c1, c) if(c1->land == laMirrorWall) inmir = true;
 | |
|     if(inmir) continue;
 | |
| 
 | |
|     if(cgflags & qIDEAL) {
 | |
|       for(int i=0; i<c->type; i++) {
 | |
|         int j = (i+1) % c->type;
 | |
|         transmatrix T1 = unshift(si.T);
 | |
|         hyperpoint ci = kleinize(get_corner_position(c, i, 3));
 | |
|         hyperpoint cj = kleinize(get_corner_position(c, j, 3));
 | |
|         static constexpr int prec = 8;
 | |
|         ci = (ci - C0)/prec;
 | |
|         cj = (cj - C0)/prec;
 | |
|         glhr::colored_vertex vs[prec+1][prec+1], vh[prec+1][prec+1];
 | |
|         
 | |
|         auto& co = colors[c];
 | |
|         
 | |
|         for(int x=0; x<=prec; x++)
 | |
|         for(int y=0; y<=prec-x; y++) {
 | |
|           transmatrix h = T1 * rgpushxto0(normalize(C0+ci*min<ld>(x, prec - .01)+cj*min<ld>(y, prec-.01)));
 | |
|           vs[y][x] = glhr::colored_vertex(h * skypoint, co.first);
 | |
|           vh[y][x] = glhr::colored_vertex(h * hellpoint, co.second);
 | |
|           }
 | |
|                 
 | |
|         for(int x=0; x<prec; x++)
 | |
|         for(int y=0; y<prec; y++) {
 | |
|           if(x+y < prec) {
 | |
|             skyvertices.emplace_back(vs[y][x]);
 | |
|             skyvertices.emplace_back(vs[y+1][x]);
 | |
|             skyvertices.emplace_back(vs[y][x+1]);
 | |
|             if(x < prec-1 && y < prec-1) {
 | |
|               skyvertices.emplace_back(vh[y][x]);
 | |
|               skyvertices.emplace_back(vh[y+1][x]);
 | |
|               skyvertices.emplace_back(vh[y][x+1]);
 | |
|               }
 | |
|             }
 | |
|           if(x && y && x+y <= prec) {
 | |
|             skyvertices.emplace_back(vs[y][x]);
 | |
|             skyvertices.emplace_back(vs[y][x-1]);
 | |
|             skyvertices.emplace_back(vs[y-1][x]);
 | |
|             if(x < prec-1 && y < prec-1) {
 | |
|               skyvertices.emplace_back(vh[y][x]);
 | |
|               skyvertices.emplace_back(vh[y][x-1]);
 | |
|               skyvertices.emplace_back(vh[y-1][x]);
 | |
|               }
 | |
|             }
 | |
|           }
 | |
|         
 | |
|         if(!colors.count(c->move(i))) {
 | |
|           for(int i=0; i<prec; i++) {
 | |
|             int j = i+1;
 | |
|             skyvertices.emplace_back(vs[i][prec-i]);
 | |
|             skyvertices.emplace_back(vs[j][prec-j]);
 | |
|             skyvertices.emplace_back(vh[i][prec-i]);
 | |
|             skyvertices.emplace_back(vh[i][prec-i]);
 | |
|             skyvertices.emplace_back(vs[j][prec-j]);
 | |
|             skyvertices.emplace_back(vh[j][prec-j]);
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       continue;
 | |
|       }
 | |
|     
 | |
|     for(int i=0; i<c->type; i++) {
 | |
|       
 | |
|       static constexpr int prec = 2; 
 | |
| 
 | |
|       if(1) {
 | |
|         cellwalker cw0(c, i);
 | |
|         cellwalker cw2 = cw0;
 | |
|         cw2--; cw2 += wstep;
 | |
|         if(!colors.count(cw2.at)) {
 | |
|           this_poly.clear();
 | |
|           transmatrix T1 = Id;
 | |
|           transmatrix T2 = unshift(si.T);
 | |
|           auto cw = cw0;
 | |
|           auto co = at_or_null(colors, cw.at);
 | |
|           while(co) {
 | |
|             this_poly.emplace_back(T2 * T1 * skypoint, co->first);
 | |
|             this_poly.emplace_back(T2 * T1 * hellpoint, co->second);
 | |
|             auto cw1 = cw;
 | |
|             cw += wstep; cw++;
 | |
|             auto co1 = at_or_null(colors, cw.at);
 | |
|             if(!co1) break;
 | |
|             transmatrix A = currentmap->adj(cw1.at, cw1.spin);
 | |
|             hyperpoint a = tC0(A);
 | |
|             for(int i=1; i<prec; i++) {
 | |
|               hyperpoint h = T1 * normalize(C0 * (prec-i) + a * i);
 | |
|               this_poly.emplace_back(T2 * orthogonal_move(h, cgi.SKY), gradient(co->first, co1->first, 0, i, prec));
 | |
|               this_poly.emplace_back(T2 * orthogonal_move(h, -cgi.SKY), gradient(co->second, co1->second, 0, i, prec));
 | |
|               }
 | |
|             T1 = T1 * A;
 | |
|             co = co1;
 | |
|             }
 | |
| 
 | |
|           int k = isize(this_poly);
 | |
|           for(int j=2; j<k; j+=2) {
 | |
|             skyvertices.push_back(this_poly[j-2]);
 | |
|             skyvertices.push_back(this_poly[j-1]);
 | |
|             skyvertices.push_back(this_poly[j]);
 | |
|             skyvertices.push_back(this_poly[j-1]);
 | |
|             skyvertices.push_back(this_poly[j]);
 | |
|             skyvertices.push_back(this_poly[j+1]);
 | |
|             }
 | |
|           goto next;
 | |
|           }        
 | |
|         }
 | |
| 
 | |
|       if(true) {
 | |
|         hyperpoint tctr = tile_center();
 | |
|         cellwalker cw0(c, i);
 | |
|         cellwalker cw = cw0;
 | |
|         do {
 | |
|           cw += wstep; cw++;
 | |
|           if(cw.at < c || !colors.count(cw.at)) goto next;
 | |
|           }
 | |
|         while(cw != cw0);
 | |
|           
 | |
|         vector<hyperpoint> vertices;
 | |
|         vector<color_t> vcolors;
 | |
|   
 | |
|         transmatrix T1 = Id;
 | |
|         do {
 | |
|           vertices.push_back(T1 * tctr);
 | |
|           vcolors.push_back(colors[cw.at].first);
 | |
|           T1 = T1 * currentmap->adj(cw.at, cw.spin);
 | |
|           cw += wstep; cw++;
 | |
|           }
 | |
|         while(cw != cw0);
 | |
|         
 | |
|         int k = isize(vertices);
 | |
|   
 | |
|         color_t ccolor;
 | |
|         for(int i=0; i<k; i++) ccolor = gradient(ccolor, vcolors[i], 0, 1, i+1);
 | |
|         
 | |
|         hyperpoint ctr = Hypc;
 | |
|         for(auto& p: vertices) p = cgi.emb->normalize_flat(p);
 | |
|         for(auto& p: vertices) ctr = ctr + p;
 | |
|         ctr = cgi.emb->normalize_flat(ctr);
 | |
| 
 | |
|         for(int j=0; j<k; j++) {
 | |
|           int j1 = (j+1) % k;
 | |
|           glhr::colored_vertex cv[prec+1][prec+1];
 | |
|           for(int x=0; x<=prec; x++) for(int y=0; y<=prec; y++) if(x+y <= prec) {
 | |
|             hyperpoint h = ctr * (prec-x-y) + vertices[j] * x + vertices[j1] * y;
 | |
|             h = cgi.emb->normalize_flat(h);
 | |
|             color_t co = gradient(ccolor, gradient(vcolors[j], vcolors[j1], 0, y, x+y), 0, x+y, prec);
 | |
|             // co = (hrand(0x1000000)  << 8) | 0xFF;
 | |
|             // co = minecolors[(x+2*y) % 7] << 8 | 0xFF;
 | |
|             h = unshift(si.T) * orthogonal_move(h, cgi.SKY);
 | |
|             cv[y][x] = {h, co};
 | |
|             }
 | |
|   
 | |
|           for(int x=0; x<=prec; x++)
 | |
|           for(int y=0; y<=prec; y++) if(x+y < prec) {
 | |
|             skyvertices.emplace_back(cv[y][x]);
 | |
|             skyvertices.emplace_back(cv[y+1][x]);
 | |
|             skyvertices.emplace_back(cv[y][x+1]);
 | |
|             if(true) if(x+y < prec-1) {
 | |
|               skyvertices.emplace_back(cv[y+1][x+1]);
 | |
|               skyvertices.emplace_back(cv[y][x+1]);
 | |
|               skyvertices.emplace_back(cv[y+1][x]);
 | |
|               }
 | |
|             }
 | |
|           }
 | |
|         }
 | |
| 
 | |
|       next: ;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|   if(!simple_sky) for(auto& v: skyvertices) for(int i=0; i<3; i++) v.color[i] *= 2;
 | |
|   }
 | |
| 
 | |
| void dqi_sky::draw() {
 | |
|   if(!vid.usingGL || sky.empty() || skyvertices.empty()) return;
 | |
|   if(!do_draw_sky()) { delete_sky(); return; }
 | |
| 
 | |
|   #if CAP_VR
 | |
|   transmatrix s = (vrhr::rendering() ? vrhr::master_cview : cview()).T * inverse(sky_cview.T);
 | |
|   #else
 | |
|   transmatrix s = cview().T * inverse(sky_cview.T);
 | |
|   #endif
 | |
|     
 | |
|   be_euclidean_infinity(s);
 | |
| 
 | |
|   for(int ed = current_display->separate_eyes() ? -1 : 0; ed<2; ed+=2) {
 | |
|     if(global_projection && global_projection != ed) continue;
 | |
|     current_display->next_shader_flags = GF_VARCOLOR;
 | |
|     current_display->set_all(ed, 0);
 | |
|     if(global_projection) {
 | |
|       glhr::projection_multiply(glhr::tmtogl(xpush(-vid.ipd * global_projection/2)));
 | |
|       glapplymatrix(xpush(vid.ipd * global_projection/2) * s);
 | |
|       }
 | |
|     else {
 | |
|       glapplymatrix(s);
 | |
|       }
 | |
|     glhr::prepare(skyvertices);
 | |
|     glhr::color2(0xFFFFFFFF);
 | |
|     if(simple_sky) {
 | |
|       glhr::set_fogbase(1);
 | |
|       glhr::set_depthtest(true);
 | |
|       glhr::set_depthwrite(true);
 | |
|       }
 | |
|     else {
 | |
|       glhr::set_fogbase(1.0 + abs(cgi.SKY - cgi.LOWSKY) / sightranges[geometry]);
 | |
|       glhr::set_depthtest(model_needs_depth() && prio < PPR::SUPERLINE);
 | |
|       glhr::set_depthwrite(model_needs_depth() && prio != PPR::TRANSPARENT_SHADOW && prio != PPR::EUCLIDEAN_SKY);
 | |
|       }
 | |
| 
 | |
|     glDrawArrays(GL_TRIANGLES, 0, isize(skyvertices));
 | |
|     }
 | |
|   }
 | |
| 
 | |
| color_t skycolor(cell *c) {
 | |
|   int cd = (euclid || stdhyperbolic) ? getCdata(c, 1) : 0;
 | |
|   int z = (cd * 5) & 127;
 | |
|   if(z >= 64) z = 127 - z;
 | |
|   return gradient(0x4040FF, 0xFFFFFF, 0, z, 63);
 | |
|   }
 | |
| 
 | |
| EX bool use_euclidean_infinity = true;
 | |
| 
 | |
| /** move an Euclidean matrix to V(C0) == C0 */
 | |
| EX void be_euclidean_infinity(transmatrix& V) {
 | |
|   if(euclid && msphere && use_euclidean_infinity)
 | |
|     for(int i=0; i<3; i++) V[i][3] = 0;
 | |
|   }
 | |
| 
 | |
| EX void draw_star(const shiftmatrix& V, const hpcshape& sh, color_t col, ld rev IS(false)) {
 | |
|   if(!do_draw_stars(rev)) return;
 | |
| 
 | |
|   ld val = cgi.STAR;
 | |
|   if(rev) val = cgi.FLOOR * 2 - val;
 | |
|   val += cgi.emb->center_z();
 | |
| 
 | |
|   auto V1 = V; be_euclidean_infinity(V1.T);
 | |
|   queuepolyat(V1 * lzpush(val), sh, col, PPR::SKY);
 | |
|   }
 | |
| 
 | |
| EX ld star_prob = 0.33;
 | |
| 
 | |
| /* the first star is supposed to appear as long as probability > 0 */
 | |
| EX vector<ld> stars = {1e-20};
 | |
| 
 | |
| EX bool star_for(int i) {
 | |
|   i = i & ((1<<16)-1);
 | |
|   while(isize(stars) <= i) stars.push_back(randd());
 | |
|   return stars[i] < star_prob;
 | |
|   }
 | |
| 
 | |
| EX hookset<bool(celldrawer *cd)> hooks_ceiling;
 | |
| 
 | |
| EX void g_add_to_sky(cell *c, shiftmatrix& V, color_t col, color_t col2) {
 | |
|   if(sky) sky->sky.emplace_back(c, V, col, col2);
 | |
|   }
 | |
| 
 | |
| void celldrawer::draw_ceiling() {
 | |
| 
 | |
|   if(!models::is_perspective(pmodel)) return;
 | |
|   
 | |
|   if(callhandlers(false, hooks_ceiling, this)) return;
 | |
| 
 | |
|   auto add_to_sky = [this] (color_t col, color_t col2) {
 | |
|     if(sky) sky->sky.emplace_back(c, V, col, col2);
 | |
|     };
 | |
| 
 | |
|   switch(ceiling_category(c)) {
 | |
|     /* ceilingless levels */
 | |
|     case 1: {
 | |
|       if(star_for(fieldpattern::fieldval_uniq(c)))
 | |
|         draw_star(V, cgi.shNightStar, 0xFFFFFFFF);
 | |
|       add_to_sky(0x00000F, 0x00000F);
 | |
|       if(c->land == laAsteroids) {
 | |
|         if(star_for(fieldpattern::fieldval_uniq(c) ^ 0x5555))
 | |
|           draw_star(V, cgi.shNightStar, 0xFFFFFFFF, true);
 | |
|         int sk = get_skybrightness(-1);
 | |
|         auto sky = draw_shapevec(c, V * MirrorZ, cgi.shFullFloor.levels[SIDE::SKY], 0x000000FF + 0x100 * (sk/17), PPR::SKY);
 | |
|         if(sky) sky->tinf = NULL, sky->flags |= POLY_INTENSE;
 | |
|         }
 | |
|       return;
 | |
|       }
 | |
|     
 | |
|     case 2: {
 | |
|       color_t col;
 | |
|       color_t skycol;
 | |
|       
 | |
|       switch(c->land) {
 | |
|         case laWineyard:
 | |
|           col = 0x4040FF;
 | |
|           skycol = 0x8080FF;
 | |
|           if(emeraldval(c) / 4 == 11) draw_star(V, cgi.shSun, 0xFFFF00FF);
 | |
|           break;
 | |
| 
 | |
|         case laDesert:
 | |
|           col = 0x2020C0;
 | |
|           skycol = 0x8080FF;
 | |
|           if(emeraldval(c) / 4 == 11) draw_star(V, cgi.shSun, 0xFFFF00FF);
 | |
|           break;
 | |
| 
 | |
|         case laFrog:
 | |
|           col = 0x4040FF;
 | |
|           skycol = 0x8080FF;
 | |
|           if(zebra40(c) / 4 == 1) draw_star(V, cgi.shSun, 0xFFFF00FF);
 | |
|           break;
 | |
| 
 | |
|         case laPower:
 | |
|           skycol = col = c->landparam ? 0xFF2010 : 0x000020;
 | |
|           break;
 | |
|         
 | |
|         /* case laDesert:
 | |
|           col = 0x4040FF;
 | |
|           skycol = (0xCDA98F & 0xFEFEFE) / 2;
 | |
|           break; */
 | |
|         
 | |
|         case laAlchemist:
 | |
|           skycol = col = fcol;
 | |
|           break;
 | |
|         
 | |
|         case laVariant: {
 | |
|           #if CAP_COMPLEX2
 | |
|           int b = getBits(c);
 | |
|           col = 0x404040;
 | |
|           for(int a=0; a<21; a++)
 | |
|             if((b >> a) & 1)
 | |
|               col += variant::features[a].color_change;
 | |
|           col = col & 0x00FF00;
 | |
|           skycol = col;
 | |
|           #endif
 | |
|           break;
 | |
|           }
 | |
|         
 | |
|         case laDragon:
 | |
|           col = c->wall == waChasm ? 0xFFFFFF : 0x4040FF;
 | |
|           skycol = 0;
 | |
|           break;
 | |
|         
 | |
|         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, skycol);
 | |
|       return;
 | |
|       }
 | |
|     
 | |
|     case 3: {
 | |
|       add_to_sky(0, 0);
 | |
|       if(camera_over(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);
 | |
|       forCellIdEx(c2, i, c) 
 | |
|         if(ceiling_category(c2) != 3) {
 | |
|           color_t wcol2 = gradient(0, wcol, 0, .8, 1);
 | |
|           placeSidewall(c, i, SIDE::HIGH, V, darkena(wcol2, fd, 0xFF));
 | |
|           placeSidewall(c, i, SIDE::HIGH2, V, darkena(wcol2, fd, 0xFF));
 | |
|           placeSidewall(c, i, SIDE::SKY, V, darkena(wcol2, fd, 0xFF));
 | |
|           }
 | |
|       return;
 | |
|       }
 | |
|     
 | |
|     case 4: {
 | |
|       add_to_sky(0x00000F, 0x00000F);
 | |
|       if(camera_over(cgi.HIGH)) return;
 | |
|       auto ispal = [&] (cell *c0) { return c0->land == laPalace && among(c0->wall, waPalace, waClosedGate, waOpenGate); };
 | |
|       color_t wcol2 = 0xFFD500;
 | |
|       if(ispal(c)) {
 | |
|         forCellIdEx(c2, i, c) if(!ispal(c2))
 | |
|           placeSidewall(c, i, SIDE::HIGH, V, darkena(wcol2, fd, 0xFF));
 | |
|         }
 | |
|       else {
 | |
|         bool window = false;
 | |
|         forCellIdEx(c2, i, c) if(c2->wall == waPalace && ispal(c->cmodmove(i+1)) && ispal(c->cmodmove(i-1))) window = true;        
 | |
|         if(qfi.fshape && !window) draw_shapevec(c, V, qfi.fshape->levels[SIDE::HIGH], darkena(fcol, fd, 0xFF), PPR::WALL);
 | |
|         if(window) 
 | |
|           forCellIdEx(c2, i, c) 
 | |
|             placeSidewall(c, i, SIDE::HIGH2, V, darkena(wcol2, fd, 0xFF));
 | |
|         }
 | |
|       if(among(c->wall, waClosedGate, waOpenGate) && qfi.fshape) draw_shapevec(c, V, qfi.fshape->levels[SIDE::WALL], 0x202020FF, PPR::WALL);
 | |
| 
 | |
|       draw_star(V, cgi.shNightStar, 0xFFFFFFFF);
 | |
|       break;
 | |
|       }
 | |
|     
 | |
|     case 6: {
 | |
|       add_to_sky(skycolor(c), 0x4040C0);
 | |
|       if(camera_over(cgi.HIGH2)) return;
 | |
|       color_t wcol2 = winf[waRuinWall].color;
 | |
|       if(c->landparam == 1)
 | |
|         forCellIdEx(c2, i, c) if(c2->landparam != 1)
 | |
|           placeSidewall(c, i, SIDE::HIGH, V, darkena(wcol2, fd, 0xFF));
 | |
|       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 == 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, 0x00000F);
 | |
|       if(fieldpattern::fieldval_uniq(c) % 5 < 2)
 | |
|         draw_star(V, cgi.shNightStar, 0xFFFFFFFF);
 | |
|       if(camera_over(cgi.HIGH2)) return;
 | |
|       color_t wcol2 = winf[waColumn].color;
 | |
|       if(c->landparam == 1)
 | |
|         forCellIdEx(c2, i, c) if(c2->landparam != 1)
 | |
|           placeSidewall(c, i, SIDE::HIGH, V, darkena(wcol2, fd, 0xFF));
 | |
|       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 == 1)
 | |
|         if(qfi.fshape) draw_shapevec(c, V, qfi.fshape->levels[SIDE::WALL], darkena(wcol2, fd, 0xFF), PPR::WALL);
 | |
|       break;
 | |
|       }
 | |
|     
 | |
|     case 5: {
 | |
|       add_to_sky(0x00000F, 0x00000F);
 | |
|       if(camera_over(cgi.WALL)) return;
 | |
|     
 | |
|       if(pseudohept(c)) {
 | |
|         forCellIdEx(c2, i, c) 
 | |
|           placeSidewall(c, i, SIDE::HIGH, V, darkena(fcol, fd, 0xFF));
 | |
|         }
 | |
|       else if(qfi.fshape)
 | |
|         draw_shapevec(c, V, qfi.fshape->levels[SIDE::WALL], darkena(fcol, fd, 0xFF), PPR::WALL);
 | |
| 
 | |
|       draw_star(V, cgi.shNightStar, 0xFFFFFFFF);
 | |
|       break;
 | |
|       }
 | |
| 
 | |
|     default:
 | |
|       add_to_sky(0, 0);
 | |
|     }
 | |
|   }
 | |
| 
 | |
| EX struct renderbuffer *airbuf;
 | |
| 
 | |
| EX void swap_if_missing(bool missing) {
 | |
|   if(!missing) return;
 | |
|   arb::swap_vertices();
 | |
|   #if CAP_IRR
 | |
|   irr::swap_vertices();
 | |
|   #endif
 | |
|   }
 | |
| 
 | |
| EX void make_air() {
 | |
|   if(!sky) return;
 | |
|   if(!embedded_plane) return;
 | |
| 
 | |
|   if(centerover != sky_centerover) {
 | |
|     sky_centerover = centerover;
 | |
|     sky_cview = cview();
 | |
|     compute_skyvertices(sky->sky);
 | |
|     }
 | |
|   
 | |
|   if(!context_fog) return;
 | |
|   if(vrhr::rendering()) 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 CAP_VR
 | |
|   dynamicval<int> i(vrhr::state, 0);
 | |
|   #endif
 | |
| 
 | |
|   bool missing = false;
 | |
| 
 | |
|   auto cgi1 = &cgi;
 | |
| 
 | |
|   if(1) {
 | |
|     //shot::take("airtest.png", drawqueue); 
 | |
|     dynamicval<videopar> v(vid, vid);    
 | |
|     dynamicval<bool> vi(inHighQual, true);
 | |
| 
 | |
|     vid.xres = AIR_TEXTURE;
 | |
|     vid.yres = AIR_TEXTURE;
 | |
|     dynamicval<ld> g1(current_display->xmin, 0);
 | |
|     dynamicval<ld> g2(current_display->ymin, 0);
 | |
|     dynamicval<ld> g3(current_display->xmax, 1);
 | |
|     dynamicval<ld> g4(current_display->ymax, 1);
 | |
|     calcparam();
 | |
|     models::configure();
 | |
|   
 | |
|     resetbuffer rb;
 | |
|     airbuf->enable();
 | |
|     current_display->set_viewport(0);
 | |
|   
 | |
|     airbuf->clear(0xFFFF00FF);
 | |
| 
 | |
|     pconf.alpha = 1;
 | |
|     pconf.scale = 1;
 | |
|     dynamicval<transmatrix> vm(pconf.cam(), Id);
 | |
|     pconf.stretch = 1;
 | |
|     pmodel = mdDisk;
 | |
| 
 | |
|     vid.always3 = false;
 | |
|     geom3::apply_always3();
 | |
|     check_cgi();
 | |
|     missing = !(cgi.state & 2);
 | |
|     cgi.require_basics();
 | |
|     geom3::swap_direction = -1;
 | |
|     if(missing) {
 | |
|       swap(cgi.emb, cgi1->emb);
 | |
|       swap_if_missing(missing);
 | |
|       swap(cgi.emb, cgi1->emb);
 | |
|       }
 | |
| 
 | |
|     cgi.require_shapes();
 | |
|     
 | |
|     eGeometry orig = geometry;
 | |
| 
 | |
|     #if !ISIOS
 | |
|     glDisable(GL_LINE_SMOOTH);
 | |
|     #endif
 | |
|     
 | |
|     for(auto& g: sky->sky) {
 | |
|       transmatrix S;
 | |
|       if(1) {
 | |
|         geometry = gSpace534;
 | |
|         S = g.T.T;
 | |
|         S = current_display->radar_transform * S;
 | |
|         geometry = orig;
 | |
|         S = cgi1->emb->actual_to_base(S);
 | |
|         }
 | |
|       
 | |
|       int id = shvid(g.c);
 | |
|       ensure_floorshape_generated(id, g.c);
 | |
|       auto& h = cgi.shFullFloor.b[id];
 | |
| 
 | |
|       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 !ISIOS
 | |
|     if(vid.antialias & AA_LINES)
 | |
|       glEnable(GL_LINE_SMOOTH);
 | |
|     #endif
 | |
| 
 | |
| #if CAP_SDL
 | |
|     // if(anyshiftclick) IMAGESAVE(airbuf->render(), "air.png");
 | |
| #endif
 | |
|     rb.reset();
 | |
|     }
 | |
| 
 | |
|   GLERR("after draw");
 | |
|   geom3::apply_always3();
 | |
|   geom3::swap_direction = +1;
 | |
|   if(missing) {
 | |
|     swap(cgi.emb, cgi1->emb);
 | |
|     swap_if_missing(missing);
 | |
|     swap(cgi.emb, cgi1->emb);
 | |
|     }
 | |
|   check_cgi();
 | |
|   calcparam();
 | |
|   cgi.require_basics();
 | |
|   GLERR("after make_air");
 | |
|   current_display->set_viewport(0);
 | |
|   current_display->set_all(0,0);
 | |
|   }
 | |
| 
 | |
| #endif
 | |
| }
 | 
