Browse Source

correct normals for upwards slope (and dummy lighting to test it)

Sean Barrett 10 years ago
parent
commit
c10b3fefae
2 changed files with 186 additions and 44 deletions
  1. 176 44
      stb_voxel_render.h
  2. 10 0
      tests/caveview/cave_render.c

+ 176 - 44
stb_voxel_render.h

@@ -1,6 +1,9 @@
 // @TODO
 //
 //   - compute full set of texture normals
+//   - switch to #ifdef
+//   - premultiplied alpha
+//   - edge clamp
 //   - gather vertex lighting from slopes correctly
 //   - better support texture edge_clamp: explicitly mod texcoords by 1, use textureGrad to avoid
 //     mipmap articats. Need to do compute texcoords in vertex shader, offset towards
@@ -373,6 +376,8 @@ enum
    STBVOX_FACE_south,
    STBVOX_FACE_up,
    STBVOX_FACE_down,
+
+   STBVOX_FACE__count,
 };
 
 
@@ -540,7 +545,58 @@ struct stbvox_mesh_maker
 //     color:8
 
 
-// Default uniform values
+// Faces:
+//
+// Faces use the bottom bits to choose the texgen
+// mode, and all the bits to choose the normal.
+// Thus the bottom 3 bits have to be:
+//      e, n, w, s, u, d, u, d
+
+enum
+{
+   STBVOX_EFACE_east,
+   STBVOX_EFACE_north,
+   STBVOX_EFACE_west,
+   STBVOX_EFACE_south,
+   STBVOX_EFACE_up,
+   STBVOX_EFACE_down,
+   STBVOX_EFACE_east_up,
+   STBVOX_EFACE_east_down,
+
+   STBVOX_EFACE_east_up_wall,
+   STBVOX_EFACE_north_up_wall,
+   STBVOX_EFACE_west_up_wall,
+   STBVOX_EFACE_south_up_wall,
+   STBVOX_EFACE_dummy_up_2,
+   STBVOX_EFACE_dummy_down_2,
+   STBVOX_EFACE_north_up,
+   STBVOX_EFACE_north_down,
+
+   STBVOX_EFACE_ne_up,
+   STBVOX_EFACE_nw_up,
+   STBVOX_EFACE_sw_up,
+   STBVOX_EFACE_se_up,
+   STBVOX_EFACE_dummy_up_3,
+   STBVOX_EFACE_dummy_down_3,
+   STBVOX_EFACE_west_up,
+   STBVOX_EFACE_west_down,
+
+   STBVOX_EFACE_ne_down,
+   STBVOX_EFACE_nw_down,
+   STBVOX_EFACE_sw_down,
+   STBVOX_EFACE_se_down,
+   STBVOX_EFACE_dummy_up_4,
+   STBVOX_EFACE_dummy_down_4,
+   STBVOX_EFACE_south_up,
+   STBVOX_EFACE_south_down,
+
+   // @TODO either we need more than 5 bits to encode the normal to fit these, or we can replace 'dummy' above with them but need to use full-size texgen table
+   // so for now we just texture them with the wrong projection
+   STBVOX_EFACE_east_down_wall = STBVOX_EFACE_east_down,
+   STBVOX_EFACE_north_down_wall = STBVOX_EFACE_north_down,
+   STBVOX_EFACE_west_down_wall = STBVOX_EFACE_west_down,
+   STBVOX_EFACE_south_down_wall = STBVOX_EFACE_south_down,
+};
 
 static float stbvox_default_texgen[2][32][3] =
 {
@@ -550,6 +606,8 @@ static float stbvox_default_texgen[2][32][3] =
      {  1, 0,0 }, { 0, 0, 1 }, { -1, 0,0 }, { 0, 0,-1 },
      {  1, 0,0 }, { 0, 1, 0 }, { -1, 0,0 }, { 0,-1, 0 },
      { -1, 0,0 }, { 0,-1, 0 }, {  1, 0,0 }, { 0, 1, 0 },
+     {  1, 0,0 }, { 0, 1, 0 }, { -1, 0,0 }, { 0,-1, 0 },
+     { -1, 0,0 }, { 0,-1, 0 }, {  1, 0,0 }, { 0, 1, 0 },
    },
    { { 0, 0,-1 }, {  0, 1,0 }, { 0, 0, 1 }, {  0,-1,0 },
      { 0, 0,-1 }, { -1, 0,0 }, { 0, 0, 1 }, {  1, 0,0 },
@@ -557,12 +615,51 @@ static float stbvox_default_texgen[2][32][3] =
      { 0, 0,-1 }, {  1, 0,0 }, { 0, 0, 1 }, { -1, 0,0 },
      { 0,-1, 0 }, {  1, 0,0 }, { 0, 1, 0 }, { -1, 0,0 },
      { 0, 1, 0 }, { -1, 0,0 }, { 0,-1, 0 }, {  1, 0,0 },
+     { 0,-1, 0 }, {  1, 0,0 }, { 0, 1, 0 }, { -1, 0,0 },
+     { 0, 1, 0 }, { -1, 0,0 }, { 0,-1, 0 }, {  1, 0,0 },
    },
 };
 
+#define STBVOX_RSQRT2   0.7071067811865f
+#define STBVOX_RSQRT3   0.5773502691896f
+
 static float stbvox_default_normals[32][3] =
 {
-   { 1,0,0 }, { 0,1,0 }, { -1,0,0 }, { 0,-1,0 }, { 0,0,1 }, { 0,0,-1 }
+   { 1,0,0 },  // east
+   { 0,1,0 },  // north
+   { -1,0,0 }, // west
+   { 0,-1,0 }, // south
+   { 0,0,1 },  // up
+   { 0,0,-1 }, // down
+   {  STBVOX_RSQRT2,0, STBVOX_RSQRT2 }, // east & up
+   {  STBVOX_RSQRT2,0, -STBVOX_RSQRT2 }, // east & down
+
+   {  STBVOX_RSQRT2,0, STBVOX_RSQRT2 }, // east & up
+   { 0, STBVOX_RSQRT2, STBVOX_RSQRT2 }, // north & up
+   { -STBVOX_RSQRT2,0, STBVOX_RSQRT2 }, // west & up
+   { 0,-STBVOX_RSQRT2, STBVOX_RSQRT2 }, // south & up
+   { 0,0,1 },  // up
+   { 0,0,-1 }, // down
+   { 0, STBVOX_RSQRT2, STBVOX_RSQRT2 }, // north & up
+   { 0, STBVOX_RSQRT2, -STBVOX_RSQRT2 }, // north & down
+
+   {  STBVOX_RSQRT3, STBVOX_RSQRT3,STBVOX_RSQRT3 }, // NE & up
+   { -STBVOX_RSQRT3, STBVOX_RSQRT3,STBVOX_RSQRT3 }, // NW & up
+   { -STBVOX_RSQRT3,-STBVOX_RSQRT3,STBVOX_RSQRT3 }, // SW & up
+   {  STBVOX_RSQRT3,-STBVOX_RSQRT3,STBVOX_RSQRT3 }, // SE & up
+   { 0,0,1 },  // up
+   { 0,0,-1 }, // down
+   { -STBVOX_RSQRT2,0, STBVOX_RSQRT2 }, // west & up
+   { -STBVOX_RSQRT2,0, -STBVOX_RSQRT2 }, // west & down
+
+   {  STBVOX_RSQRT3, STBVOX_RSQRT3,-STBVOX_RSQRT3 }, // NE & down
+   { -STBVOX_RSQRT3, STBVOX_RSQRT3,-STBVOX_RSQRT3 }, // NW & down
+   { -STBVOX_RSQRT3,-STBVOX_RSQRT3,-STBVOX_RSQRT3 }, // SW & down
+   {  STBVOX_RSQRT3,-STBVOX_RSQRT3,-STBVOX_RSQRT3 }, // SE & down
+   { 0,0,1 },  // up
+   { 0,0,-1 }, // down
+   { 0,-STBVOX_RSQRT2, STBVOX_RSQRT2 }, // south & up
+   { 0,-STBVOX_RSQRT2, -STBVOX_RSQRT2 }, // south & down
 };
 
 static float stbvox_default_texscale[128][2] =
@@ -774,7 +871,8 @@ stbvox_tagged_string stbvox_fragment_program[] =
    { STBVOX_TAG_all,
 
             "out vec4  outcolor;\n"
-
+            "uniform vec3 light_source[2];\n"
+            "vec3 compute_lighting(vec3 pos, vec3 norm);\n"
    },
    { STBVOX_TAG_all,
 
@@ -857,8 +955,9 @@ stbvox_tagged_string stbvox_fragment_program[] =
             "   amb_color *= amb_occ;\n"
 
             "   vec3 lit_color;\n"
+            "   vec3 lighting = compute_lighting(objectspace_pos + transform[1], normal) + amb_color * 0.25;\n"
             "   if (!emissive)\n"
-            "      lit_color = amb_color * albedo;\n"
+            "      lit_color = lighting * albedo;\n"
             "   else\n"
             "      lit_color = albedo;\n"
 
@@ -881,6 +980,13 @@ stbvox_tagged_string stbvox_fragment_program[] =
             "   vec4 final_color = vec4(lit_color, fragment_alpha);\n"
             "   outcolor = final_color;\n"
             "}"
+
+"vec3 compute_lighting(vec3 pos, vec3 norm)\n"
+"{\n"
+"   vec3 light_dir = light_source[0] - pos;\n"
+"   float lambert = dot(light_dir, norm) / dot(light_dir, light_dir);\n"
+"   return light_source[1] * clamp(lambert, 0.0, 1.0);\n"
+"}\n"
    },
 };
 
@@ -1000,12 +1106,7 @@ static unsigned char stbvox_rotate_face[6][4] =
 
 #define STBVOX_ROTATE(x,r)   stbvox_rotate_face[x][r] // (((x)+(r))&3)
 
-static unsigned char face_info_for_side[6] =
-{
-   0*4,1*4,2*4,3*4,4*4,5*4
-};
-
-stbvox_mesh_face stbvox_compute_mesh_face_value(stbvox_mesh_maker *mm, stbvox_rotate rot, int face, int v_off)
+stbvox_mesh_face stbvox_compute_mesh_face_value(stbvox_mesh_maker *mm, stbvox_rotate rot, int face, int v_off, int normal)
 {
    unsigned char color_face;
    stbvox_mesh_face face_data = { 0 };
@@ -1077,7 +1178,7 @@ stbvox_mesh_face stbvox_compute_mesh_face_value(stbvox_mesh_maker *mm, stbvox_ro
       if (mm->input.color3 && (mm->input.color3_facemask[v_off] & (1 << color_face)))
          face_data.color = mm->input.color3[v_off];
    }
-   face_data.face_info = face_info_for_side[face] + rot.facerot;
+   face_data.face_info = (normal<<2) + rot.facerot;
    return face_data;
 }
 
@@ -1248,9 +1349,9 @@ void stbvox_get_quad_vertex_pointer(stbvox_mesh_maker *mm, int mesh, stbvox_mesh
    }
 }
 
-void stbvox_make_mesh_for_face(stbvox_mesh_maker *mm, stbvox_rotate rot, int face, int v_off, stbvox_pos pos, stbvox_mesh_vertex vertbase, stbvox_mesh_vertex *face_coord, unsigned char mesh)
+void stbvox_make_mesh_for_face(stbvox_mesh_maker *mm, stbvox_rotate rot, int face, int v_off, stbvox_pos pos, stbvox_mesh_vertex vertbase, stbvox_mesh_vertex *face_coord, unsigned char mesh, int normal)
 {
-   stbvox_mesh_face face_data = stbvox_compute_mesh_face_value(mm,rot,face,v_off);
+   stbvox_mesh_face face_data = stbvox_compute_mesh_face_value(mm,rot,face,v_off, normal);
 
    // still need to compute ao & texlerp for each vertex
 
@@ -1365,10 +1466,10 @@ void stbvox_make_02_split_mesh_for_face(stbvox_mesh_maker *mm, stbvox_rotate rot
    v[1] = face_coord[1];
    v[2] = face_coord[2];
    v[3] = face_coord[0];
-   stbvox_make_mesh_for_face(mm, rot, face1, v_off, pos, vertbase, v, mesh);
+   stbvox_make_mesh_for_face(mm, rot, face1, v_off, pos, vertbase, v, mesh, face1);
    v[1] = face_coord[2];
    v[2] = face_coord[3];
-   stbvox_make_mesh_for_face(mm, rot, face2, v_off, pos, vertbase, v, mesh);
+   stbvox_make_mesh_for_face(mm, rot, face2, v_off, pos, vertbase, v, mesh, face2);
 }
 
 void stbvox_make_13_split_mesh_for_face(stbvox_mesh_maker *mm, stbvox_rotate rot, int face1, int face2, int v_off, stbvox_pos pos, stbvox_mesh_vertex vertbase, stbvox_mesh_vertex *face_coord, unsigned char mesh)
@@ -1378,10 +1479,10 @@ void stbvox_make_13_split_mesh_for_face(stbvox_mesh_maker *mm, stbvox_rotate rot
    v[1] = face_coord[2];
    v[2] = face_coord[3];
    v[3] = face_coord[1];
-   stbvox_make_mesh_for_face(mm, rot, face1, v_off, pos, vertbase, v, mesh);
+   stbvox_make_mesh_for_face(mm, rot, face1, v_off, pos, vertbase, v, mesh, face1);
    v[1] = face_coord[3];
    v[2] = face_coord[0];
-   stbvox_make_mesh_for_face(mm, rot, face2, v_off, pos, vertbase, v, mesh);
+   stbvox_make_mesh_for_face(mm, rot, face2, v_off, pos, vertbase, v, mesh, face2);
 }
 
 // simple case for mesh generation: we have only solid and empty blocks
@@ -1413,11 +1514,11 @@ void stbvox_make_mesh_for_block(stbvox_mesh_maker *mm, stbvox_pos pos, int v_off
 
    if (blockptr[ 1]==0) {
       rot.facerot = simple_rot;
-      stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_up  , v_off, pos, basevert, vmesh+4*STBVOX_FACE_up, mesh);
+      stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_up  , v_off, pos, basevert, vmesh+4*STBVOX_FACE_up, mesh, STBVOX_FACE_up);
    }
    if (blockptr[-1]==0) {
       rot.facerot = (-simple_rot) & 3;
-      stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_down, v_off, pos, basevert, vmesh+4*STBVOX_FACE_down, mesh);
+      stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_down, v_off, pos, basevert, vmesh+4*STBVOX_FACE_down, mesh, STBVOX_FACE_down);
    }
 
    if (mm->input.rotate) {
@@ -1432,13 +1533,13 @@ void stbvox_make_mesh_for_block(stbvox_mesh_maker *mm, stbvox_pos pos, int v_off
    rot.facerot = 0;
 
    if (blockptr[ ns_off]==0)
-      stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_north, v_off, pos, basevert, vmesh+4*STBVOX_FACE_north, mesh);
+      stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_north, v_off, pos, basevert, vmesh+4*STBVOX_FACE_north, mesh, STBVOX_FACE_north);
    if (blockptr[-ns_off]==0)
-      stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_south, v_off, pos, basevert, vmesh+4*STBVOX_FACE_south, mesh);
+      stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_south, v_off, pos, basevert, vmesh+4*STBVOX_FACE_south, mesh, STBVOX_FACE_south);
    if (blockptr[ ew_off]==0)
-      stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_east , v_off, pos, basevert, vmesh+4*STBVOX_FACE_east, mesh);
+      stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_east , v_off, pos, basevert, vmesh+4*STBVOX_FACE_east, mesh, STBVOX_FACE_east);
    if (blockptr[-ew_off]==0)
-      stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_west , v_off, pos, basevert, vmesh+4*STBVOX_FACE_west, mesh);
+      stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_west , v_off, pos, basevert, vmesh+4*STBVOX_FACE_west, mesh, STBVOX_FACE_west);
 }
 
 
@@ -1519,6 +1620,24 @@ static unsigned char stbvox_facetype[STBVOX_GEOM_count][6] =
    { STBVOX_FT_partial,STBVOX_FT_partial,STBVOX_FT_partial,STBVOX_FT_partial, STBVOX_FT_solid, STBVOX_FT_force }, // ceil vheight, all neighbors forced
 };
 
+// This table indicates what normal to use for the "up" face of a sloped geom
+// @TODO this could be done with math given the current arrangement of the enum, but let's not require it
+static unsigned char stbvox_floor_slope_for_rot[4] =
+{
+   STBVOX_EFACE_south_up,
+   STBVOX_EFACE_west_up, // @TODO: why is this reversed from what it should be? this is a north-is-up face, so slope should be south&up
+   STBVOX_EFACE_north_up,
+   STBVOX_EFACE_east_up,
+};
+
+static unsigned char stbvox_ceil_slope_for_rot[4] =
+{
+   STBVOX_EFACE_south_down,
+   STBVOX_EFACE_east_down,
+   STBVOX_EFACE_north_down,
+   STBVOX_EFACE_west_down,
+};
+
 // this table indicates whether, for each pair of types above, a face is visible.
 // each value indicates whether a given type is visible for all neighbor types
 static unsigned short stbvox_face_visible[STBVOX_FT_count] =
@@ -1749,13 +1868,26 @@ void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_pos pos,
          return;
       }
 
-      if (visible_faces & (1 << STBVOX_FACE_up)) {
-         rotate.facerot = simple_rot;
-         stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_up  , v_off, pos, basevert, vmesh[STBVOX_FACE_up], mesh);
-      }
-      if (visible_faces & (1 << STBVOX_FACE_down)) {
-         rotate.facerot = (-rotate.facerot) & 3;
-         stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_down, v_off, pos, basevert, vmesh[STBVOX_FACE_down], mesh);
+      if (geo >= STBVOX_GEOM_floor_slope_north_is_top) {
+         if (visible_faces & (1 << STBVOX_FACE_up)) {
+            int normal = geo == STBVOX_GEOM_floor_slope_north_is_top ? stbvox_floor_slope_for_rot[simple_rot] : STBVOX_FACE_up;
+            rotate.facerot = simple_rot;
+            stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_up  , v_off, pos, basevert, vmesh[STBVOX_FACE_up], mesh, normal);
+         }
+         if (visible_faces & (1 << STBVOX_FACE_down)) {
+            int normal = geo == STBVOX_GEOM_ceil_slope_north_is_bottom ? stbvox_ceil_slope_for_rot[simple_rot] : STBVOX_FACE_down;
+            rotate.facerot = (-rotate.facerot) & 3;
+            stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_down, v_off, pos, basevert, vmesh[STBVOX_FACE_down], mesh, normal);
+         }
+      } else {
+         if (visible_faces & (1 << STBVOX_FACE_up)) {
+            rotate.facerot = simple_rot;
+            stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_up  , v_off, pos, basevert, vmesh[STBVOX_FACE_up], mesh, STBVOX_FACE_up);
+         }
+         if (visible_faces & (1 << STBVOX_FACE_down)) {
+            rotate.facerot = (-rotate.facerot) & 3;
+            stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_down, v_off, pos, basevert, vmesh[STBVOX_FACE_down], mesh, STBVOX_FACE_down);
+         }
       }
 
       if (mm->input.rotate) {
@@ -1771,13 +1903,13 @@ void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_pos pos,
       rotate.facerot = 0;
 
       if (visible_faces & (1 << STBVOX_FACE_north))
-         stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_north, v_off, pos, basevert, vmesh[STBVOX_FACE_north], mesh);
+         stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_north, v_off, pos, basevert, vmesh[STBVOX_FACE_north], mesh, STBVOX_FACE_north);
       if (visible_faces & (1 << STBVOX_FACE_south))
-         stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_south, v_off, pos, basevert, vmesh[STBVOX_FACE_south], mesh);
+         stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_south, v_off, pos, basevert, vmesh[STBVOX_FACE_south], mesh, STBVOX_FACE_south);
       if (visible_faces & (1 << STBVOX_FACE_east))
-         stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_east , v_off, pos, basevert, vmesh[STBVOX_FACE_east ], mesh);
+         stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_east , v_off, pos, basevert, vmesh[STBVOX_FACE_east ], mesh, STBVOX_FACE_east);
       if (visible_faces & (1 << STBVOX_FACE_west))
-         stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_west , v_off, pos, basevert, vmesh[STBVOX_FACE_west ], mesh);
+         stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_west , v_off, pos, basevert, vmesh[STBVOX_FACE_west ], mesh, STBVOX_FACE_west);
    }
    if (geo >= STBVOX_GEOM_floor_vheight_02) {
       // this case can also be generated with regular block gen with special vmesh,
@@ -1870,7 +2002,7 @@ void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_pos pos,
                stbvox_make_13_split_mesh_for_face(mm, rotate, STBVOX_FACE_up, STBVOX_FACE_up, v_off, pos, basevert, vmesh[STBVOX_FACE_up], mesh);
          } else
          #endif
-            stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_up  , v_off, pos, basevert, vmesh[STBVOX_FACE_up], mesh);
+            stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_up  , v_off, pos, basevert, vmesh[STBVOX_FACE_up], mesh, STBVOX_FACE_up);
       }
       if (visible_faces & (1 << STBVOX_FACE_down)) {
          #ifndef STBVOX_OPTIMIZED_VHEIGHT
@@ -1883,7 +2015,7 @@ void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_pos pos,
                stbvox_make_13_split_mesh_for_face(mm, rotate, STBVOX_FACE_down, STBVOX_FACE_down, v_off, pos, basevert, vmesh[STBVOX_FACE_down], mesh);
          } else
          #endif
-            stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_down, v_off, pos, basevert, vmesh[STBVOX_FACE_down], mesh);
+            stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_down, v_off, pos, basevert, vmesh[STBVOX_FACE_down], mesh, STBVOX_FACE_down);
       }
 
       if (mm->input.rotate) {
@@ -1897,13 +2029,13 @@ void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_pos pos,
       }
 
       if ((visible_faces & (1 << STBVOX_FACE_north)) || (extreme && (ht[2] == 3 || ht[3] == 3)))
-         stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_north, v_off, pos, basevert, vmesh[STBVOX_FACE_north], mesh);
+         stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_north, v_off, pos, basevert, vmesh[STBVOX_FACE_north], mesh, STBVOX_FACE_north);
       if ((visible_faces & (1 << STBVOX_FACE_south)) || (extreme && (ht[0] == 3 || ht[1] == 3))) 
-         stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_south, v_off, pos, basevert, vmesh[STBVOX_FACE_south], mesh);
+         stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_south, v_off, pos, basevert, vmesh[STBVOX_FACE_south], mesh, STBVOX_FACE_south);
       if ((visible_faces & (1 << STBVOX_FACE_east)) || (extreme && (ht[1] == 3 || ht[3] == 3)))
-         stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_east , v_off, pos, basevert, vmesh[STBVOX_FACE_east ], mesh);
+         stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_east , v_off, pos, basevert, vmesh[STBVOX_FACE_east ], mesh, STBVOX_FACE_east);
       if ((visible_faces & (1 << STBVOX_FACE_west)) || (extreme && (ht[0] == 3 || ht[2] == 3)))
-         stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_west , v_off, pos, basevert, vmesh[STBVOX_FACE_west ], mesh);
+         stbvox_make_mesh_for_face(mm, rotate, STBVOX_FACE_west , v_off, pos, basevert, vmesh[STBVOX_FACE_west ], mesh, STBVOX_FACE_west);
    }
 
    if (geo == STBVOX_GEOM_crossed_pair) {
@@ -1935,10 +2067,10 @@ void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_pos pos,
       }
       rot.facerot = 0;
 
-      stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_north, v_off, pos, basevert, stbvox_vmesh_crossed_pair[STBVOX_FACE_north], mesh);
-      stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_south, v_off, pos, basevert, stbvox_vmesh_crossed_pair[STBVOX_FACE_south], mesh);
-      stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_east , v_off, pos, basevert, stbvox_vmesh_crossed_pair[STBVOX_FACE_east ], mesh);
-      stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_west , v_off, pos, basevert, stbvox_vmesh_crossed_pair[STBVOX_FACE_west ], mesh);
+      stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_north, v_off, pos, basevert, stbvox_vmesh_crossed_pair[STBVOX_FACE_north], mesh, STBVOX_EFACE_ne_up);
+      stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_south, v_off, pos, basevert, stbvox_vmesh_crossed_pair[STBVOX_FACE_south], mesh, STBVOX_EFACE_sw_up);
+      stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_east , v_off, pos, basevert, stbvox_vmesh_crossed_pair[STBVOX_FACE_east ], mesh, STBVOX_EFACE_se_up);
+      stbvox_make_mesh_for_face(mm, rot, STBVOX_FACE_west , v_off, pos, basevert, stbvox_vmesh_crossed_pair[STBVOX_FACE_west ], mesh, STBVOX_EFACE_nw_up);
    }
 
 

+ 10 - 0
tests/caveview/cave_render.c

@@ -781,6 +781,16 @@ void render_caves(float campos[3])
    glActiveTextureARB(GL_TEXTURE2_ARB);
    stbglEnableVertexAttribArray(0);
 
+   {
+      float lighting[2][3] = { { campos[0],campos[1],campos[2] }, { 0.75,0.75,0.65f } };
+      float bright = 15;
+      lighting[1][0] *= bright;
+      lighting[1][1] *= bright;
+      lighting[1][2] *= bright;
+      stbglUniform3fv(stbgl_find_uniform(main_prog, "light_source"), 2, lighting[0]);
+   }
+
+
    num_meshes_uploaded = 0;
    update_meshes_from_render_thread();