Pārlūkot izejas kodu

support texture rotation; better interaction of mouse centering & VC6 debugger; fix in-place conversion when mca blocks are written in different order

Sean Barrett 10 gadi atpakaļ
vecāks
revīzija
efcd76c9ab

+ 70 - 31
stb_voxel_render.h

@@ -1,6 +1,5 @@
 // @TODO
 //
-//   - extend 2 bits below normal/texgen to support texture rotation
 //   - compute full set of texture normals
 //   - handle output buffer being full
 //   - gather vertex lighting from slopes correctly
@@ -516,6 +515,13 @@ struct stbvox_mesh_maker
    typedef unsigned int   stbvox_uint32;
 #endif
 
+#ifdef _MSC_VER
+   #define STBVOX_NOTUSED(v)  (void)(v)
+#else
+   #define STBVOX_NOTUSED(v)  (void)sizeof(v)
+#endif
+
+
 // 20-byte quad format:
 //
 // per vertex:
@@ -536,10 +542,22 @@ struct stbvox_mesh_maker
 
 // Default uniform values
 
-static float stbvox_default_texgen[2][16][3] =
+static float stbvox_default_texgen[2][32][3] =
 {
-   { { 0,1,0 }, { 1,0,0 }, { 0,-1,0 }, { -1,0,0 }, { 1,0,0 }, { -1,0,0 } },
-   { { 0,0,-1 }, { 0,0,-1 }, { 0,0,-1 }, { 0,0,-1 }, { 0,-1,0 }, { 0,1,0 } },
+   { {  0, 1,0 }, { 0, 0, 1 }, {  0,-1,0 }, { 0, 0,-1 },
+     {  1, 0,0 }, { 0, 0, 1 }, { -1, 0,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 }, { 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 },
+   },
+   { { 0, 0,-1 }, {  0, 1,0 }, { 0, 0, 1 }, {  0,-1,0 },
+     { 0, 0,-1 }, {  1, 0,0 }, { 0, 0, 1 }, { -1, 0,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 },
+     { 0,-1, 0 }, {  1, 0,0 }, { 0, 1, 0 }, { -1, 0,0 },
+     { 0, 1, 0 }, { -1, 0,0 }, { 0,-1, 0 }, {  1, 0,0 },
+   },
 };
 
 static float stbvox_default_normals[32][3] =
@@ -684,7 +702,7 @@ stbvox_tagged_string stbvox_vertex_program[] =
             "   amb_occ  = float( (attr_vertex >> 23u) &  63u ) / 63.0;\n"      // a[23..28]
             "   texlerp  = float( (attr_vertex >> 29u)        ) /  7.0;\n"      // a[29..31]
 
-            "   vnormal = normal_table[facedata.w & 31u];\n"
+            "   vnormal = normal_table[(facedata.w>>2) & 31u];\n"
             "   objectspace_pos = offset * transform[0];\n"  // object-to-world scale
             "   vec3 position  = objectspace_pos + transform[1];\n"  // object-to-world translate
    },
@@ -745,8 +763,8 @@ stbvox_tagged_string stbvox_fragment_program[] =
 #if 0
 
             "uniform vec4 color_table[64];\n"
-            "uniform vec2 texscale[128];\n"
-            "uniform vec3 texgen[32];\n"
+            "uniform vec2 texscale[64];\n" // instead of 128, to avoid running out of uniforms
+            "uniform vec3 texgen[64];\n"
 #else
             "uniform samplerBuffer color_table;\n"
             "uniform samplerBuffer texscale;\n"
@@ -771,20 +789,20 @@ stbvox_tagged_string stbvox_fragment_program[] =
             // unpack the values
             "   uint tex1_id = facedata.x;\n"
             "   uint tex2_id = facedata.y;\n"
-            "   uint texprojid = facedata.w & 15u;\n"
+            "   uint texprojid = facedata.w & 31u;\n"
             "   uint color_id  = facedata.z;\n"
             "   bool texblend_mode = ((facedata.w & 128u) != 0u);\n"
 
 #if 0
             // load from uniforms / texture buffers 
             "   vec3 texgen_s = texgen[texprojid];\n"
-            "   vec3 texgen_t = texgen[texprojid+16u];\n"
-            "   float tex1_scale = texscale[tex1_id & 127u].x;\n"
-            "   float tex2_scale = texscale[tex2_id & 127u].y;\n"
+            "   vec3 texgen_t = texgen[texprojid+32u];\n"
+            "   float tex1_scale = texscale[tex1_id & 63u].x;\n"
+            "   float tex2_scale = texscale[tex2_id & 63u].y;\n"
             "   vec4 color = color_table[color_id & 63u];\n"
 #else
             "   vec3 texgen_s = texelFetch(texgen, int(texprojid)).xyz;\n"
-            "   vec3 texgen_t = texelFetch(texgen, int(texprojid+16u)).xyz;\n"
+            "   vec3 texgen_t = texelFetch(texgen, int(texprojid+32u)).xyz;\n"
             "   float tex1_scale = texelFetch(texscale, int(tex1_id & 127u)).x;\n"
             "   float tex2_scale = texelFetch(texscale, int(tex2_id & 127u)).y;\n"
             "   vec4 color = texelFetch(color_table, int(color_id & 63u));\n"
@@ -794,7 +812,7 @@ stbvox_tagged_string stbvox_fragment_program[] =
             "   texcoord.s = dot(texturespace_pos, texgen_s);\n"
             "   texcoord.t = dot(texturespace_pos, texgen_t);\n"
 
-            // @TODO: use 2 bits of facedata.w to enable animation of facedata.x & y   
+            // @TODO: use 2 bits of facedata.w to enable animation of facedata.x & y?
    
             "   vec4 tex1 = texture(tex_array[0], vec3(tex1_scale * texcoord, float(tex1_id)));\n"
             "   vec4 tex2 = texture(tex_array[1], vec3(tex2_scale * texcoord, float(tex2_id)));\n"
@@ -925,7 +943,7 @@ stbvox_uniform_info stbvox_uniforms[] =
    { STBVOX_UNIFORM_TYPE_vec4     , 16,  64, "color_table"  , stbvox_default_palette[0]   , STBVOX_TAG_textured },
 
    { STBVOX_UNIFORM_TYPE_vec3     , 12,  32, "normal_table" , stbvox_default_normals[0]   , STBVOX_TAG_all },
-   { STBVOX_UNIFORM_TYPE_vec3     , 12,  32, "texgen"       , stbvox_default_texgen[0][0] , STBVOX_TAG_textured },
+   { STBVOX_UNIFORM_TYPE_vec3     , 12,  64, "texgen"       , stbvox_default_texgen[0][0] , STBVOX_TAG_textured },
 
    { STBVOX_UNIFORM_TYPE_vec3     , 12,   4, "ambient"      , 0                           , STBVOX_TAG_all },
    { STBVOX_UNIFORM_TYPE_vec3     , 12,   1, "camera_pos"   , stbvox_dummy_transform[0]   , STBVOX_TAG_all },
@@ -960,8 +978,9 @@ typedef struct
 {
    unsigned char block;
    unsigned char overlay;
+   unsigned char facerot:4;
+   unsigned char ecolor:4;
    unsigned char tex2;
-   unsigned char ecolor;
 } stbvox_rotate;
 
 typedef struct
@@ -983,7 +1002,7 @@ static unsigned char stbvox_rotate_face[6][4] =
 
 static unsigned char face_info_for_side[6] =
 {
-   0,1,2,3,4,5
+   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)
@@ -1058,7 +1077,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];
+   face_data.face_info = face_info_for_side[face] + rot.facerot;
    return face_data;
 }
 
@@ -1374,7 +1393,7 @@ void stbvox_make_mesh_for_block(stbvox_mesh_maker *mm, stbvox_pos pos, int v_off
    unsigned char *blockptr = &mm->input.blocktype[v_off];
    stbvox_mesh_vertex basevert = stbvox_vertex_p(pos.x, pos.y, pos.z<<mm->precision_z , 0,0);
 
-   stbvox_rotate rot = { 0,0,0,0 };
+   stbvox_rotate rot = { 0,0,0,0,0 };
    unsigned char simple_rot = 0;
 
    unsigned char mesh = mm->default_mesh;
@@ -1392,10 +1411,14 @@ void stbvox_make_mesh_for_block(stbvox_mesh_maker *mm, stbvox_pos pos, int v_off
    simple_rot = mm->input.lighting[v_off] & 3;
    #endif
 
-   if (blockptr[ 1]==0)
+   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);
-   if (blockptr[-1]==0)
+   }
+   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);
+   }
 
    if (mm->input.rotate) {
       unsigned char val = mm->input.rotate[v_off];
@@ -1403,9 +1426,10 @@ void stbvox_make_mesh_for_block(stbvox_mesh_maker *mm, stbvox_pos pos, int v_off
       rot.overlay = (val >> 2) & 3;
       rot.tex2    = (val >> 4) & 3;
       rot.ecolor  = (val >> 6) & 3;
-   } else if (mm->input.selector) {
+   } else {
       rot.block = rot.overlay = rot.tex2 = rot.ecolor = simple_rot;
    }
+   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);
@@ -1580,12 +1604,15 @@ void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_pos pos,
       ngeo[4] = mm->input.geometry[v_off +      1];
       ngeo[5] = mm->input.geometry[v_off -      1];
 
+      #ifndef STBVOX_ROTATION_IN_LIGHTING
       rot = (geo >> 4) & 3;
       geo &= 15;
       for (i=0; i < 6; ++i) {
          nrot[i] = (ngeo[i] >> 4) & 3;
          ngeo[i] &= 15;
       }
+      #endif
+      STBVOX_NOTUSED(i);
    } else {
       int i;
       assert(mm->input.block_geometry);
@@ -1593,6 +1620,7 @@ void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_pos pos,
       for (i=0; i < 6; ++i)
          ngeo[i] = mm->input.block_geometry[nbt[i]];
       if (mm->input.selector) {
+         #ifndef STBVOX_ROTATION_IN_LIGHTING
          rot     = (mm->input.selector[v_off         ] >> 4) & 3;
          nrot[0] = (mm->input.selector[v_off + ew_off] >> 4) & 3;
          nrot[1] = (mm->input.selector[v_off + ns_off] >> 4) & 3;
@@ -1600,13 +1628,16 @@ void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_pos pos,
          nrot[3] = (mm->input.selector[v_off - ns_off] >> 4) & 3;
          nrot[4] = (mm->input.selector[v_off +      1] >> 4) & 3;
          nrot[5] = (mm->input.selector[v_off -      1] >> 4) & 3;
+         #endif
       } else {
+         #ifndef STBVOX_ROTATION_IN_LIGHTING
          rot = (geo>>4)&3;
          geo &= 15;
          for (i=0; i < 6; ++i) {
             nrot[i] = (ngeo[i]>>4)&3;
             ngeo[i] &= 15;
          }
+         #endif
       }
    }
 
@@ -1618,7 +1649,9 @@ void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_pos pos,
    nrot[3] = (mm->input.lighting[v_off - ns_off]) & 3;
    nrot[4] = (mm->input.lighting[v_off +      1]) & 3;
    nrot[5] = (mm->input.lighting[v_off -      1]) & 3;
-   #endif   
+   #endif
+
+   //rot = 2;
 
    if (geo == STBVOX_GEOM_transp) {
       // transparency has a special rule: if the blocktype is the same,
@@ -1694,7 +1727,7 @@ void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_pos pos,
       // this is the simple case, we can just use regular block gen with special vmesh calculated with vheight
       stbvox_mesh_vertex basevert;
       stbvox_mesh_vertex vmesh[6][4];
-      stbvox_rotate rotate = { 0,0,0,0 };
+      stbvox_rotate rotate = { 0,0,0,0,0 };
       unsigned char simple_rot = rot;
       int i;
       // we only need to do this for the displayed faces, but it's easier
@@ -1718,10 +1751,14 @@ void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_pos pos,
          return;
       }
 
-      if (visible_faces & (1 << STBVOX_FACE_up))
+      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))
+      }
+      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 (mm->input.rotate) {
          unsigned char val = mm->input.rotate[v_off];
@@ -1729,10 +1766,12 @@ void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_pos pos,
          rotate.overlay = (val >> 2) & 3;
          rotate.tex2    = (val >> 4) & 3;
          rotate.ecolor  = (val >> 6) & 3;
-      } else if (mm->input.selector) {
+      } else {
          rotate.block = rotate.overlay = rotate.tex2 = rotate.ecolor = simple_rot;
       }
 
+      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);
       if (visible_faces & (1 << STBVOX_FACE_south))
@@ -1750,7 +1789,7 @@ void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_pos pos,
       stbvox_mesh_vertex vmesh[6][4];
       stbvox_mesh_vertex cube[8];
       stbvox_mesh_vertex basevert;
-      stbvox_rotate rotate = { 0,0,0,0 };
+      stbvox_rotate rotate = { 0,0,0,0,0 };
       unsigned char simple_rot = rot;
       unsigned char ht[4];
       int extreme;
@@ -1775,7 +1814,7 @@ void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_pos pos,
          for (i=0; i < 4; ++i)
             ht[i] = raw[stbvox_rotate_vertex[i][rot]];
       } else {
-         assert(mm->input.geometry);
+         assert(0);
       }
 
       // flag whether any sides go off the top of the block, which means
@@ -1872,9 +1911,8 @@ void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_pos pos,
    if (geo == STBVOX_GEOM_crossed_pair) {
       // this can be generated with a special vmesh
       stbvox_mesh_vertex basevert = stbvox_vertex_p(pos.x, pos.y, pos.z<<mm->precision_z , 0,0);
-      stbvox_rotate rot = { 0,0,0,0 };
-      unsigned char simple_rot;
-
+      unsigned char simple_rot=0;
+      stbvox_rotate rot = { 0,0,0,0,0 };
       unsigned char mesh = mm->default_mesh;
       if (mm->input.selector) {
          mesh = mm->input.selector[v_off];
@@ -1897,6 +1935,7 @@ void stbvox_make_mesh_for_block_with_geo(stbvox_mesh_maker *mm, stbvox_pos pos,
       } else if (mm->input.selector) {
          rot.block = rot.overlay = rot.tex2 = rot.ecolor = simple_rot;
       }
+      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);

+ 9 - 6
tests/caveview/README.md

@@ -11,11 +11,13 @@ Not very. Many Minecraft blocks are not handled correctly:
 *         Only one wood type
 *         Colored glass becomes regular glass
 *         Glass panes become glass blocks
+*         Water is opaque
 *         Water level is incorrect
 *         No biome coloration
 *         Cactus is not shrunk, shows holes
 *         Chests are not shrunk
-*         Chests, pumpkins, etc. are not rotated properly
+*         Double-chests draw as two chests
+*         Pumpkins etc. are not rotated properly
 *         Torches are drawn hackily, do not attach to walls
 *         Incorrect textures for blocks that postdate terrain.png
 *         Transparent textures have black fringes due to non-premultiplied-alpha
@@ -47,9 +49,11 @@ things that way wouldn't be so bad.
 
 Rails, ladders, and redstone lines could be implemented by
 using tex2 to overlay those effects, but you can't rotate
-tex1 and tex2 independently, so you'd have to have a
-separate texture for each orientation of rail, etc, and
-you'd need special rendering for rail up/down sections.
+tex1 and tex2 independently, so there may be cases where
+the underlying texture needs a different rotation from the
+overlaid texture, which would require separate rendering.
+Handling redstone's brightness being different from underlying
+block's brightness would require separate rendering.
 
 You can use the face-color effect to do biome coloration,
 but the change won't be smooth the way it is in Minecraft.
@@ -60,8 +64,7 @@ but the change won't be smooth the way it is in Minecraft.
 Partly because converting from minecraft data is expensive.
 
 Here is the approximate breakdown of an older version
-of this executable and lib that did the building single-threaded,
-and was a bit slower at building mesh data.
+of this executable and lib that did the building single-threaded.
 
 *       25%   loading & parsing minecraft files (4/5ths of this is my zlib)
 *       18%   converting from minecraft blockids & lighting to stb blockids & lighting

+ 6 - 2
tests/caveview/cave_main.c

@@ -66,7 +66,7 @@ static void print(char *text, ...)
    pos_y += 10;
 }
 
-float camang[3], camloc[3] = { 0,0,75 };
+float camang[3], camloc[3] = { 60,22,77 };
 float player_zoom = 1.0;
 float rotate_view = 0.0;
 
@@ -551,8 +551,12 @@ int SDL_main(int argc, char **argv)
 
    SDL_GL_MakeCurrent(window, context); // is this true by default?
 
-   // if (!IsDebuggerPresent())   
    SDL_SetRelativeMouseMode(SDL_TRUE);
+   #if defined(_MSC_VER) && _MSC_VER < 1300
+   // work around broken behavior in VC6 debugging
+   if (IsDebuggerPresent())
+      SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, "1");
+   #endif
 
    stbgl_initExtensions();
 

+ 72 - 23
tests/caveview/cave_mesher.c

@@ -121,7 +121,7 @@ unsigned char minecraft_info[256][7] =
    { C_empty }, // fire
    { C_trans, 65,65,65,65,65,65 },
    { C_stair, 4,4,4,4,4,4 },
-   { C_solid, 27,26,26,26,25,25 },
+   { C_solid, 26,26,26,27,25,25 },
    { C_empty }, // redstone
 
    // 56
@@ -237,7 +237,7 @@ unsigned char minecraft_info[256][7] =
    // 144
    { C_empty }, // mob head
    { C_empty }, // anvil
-   { C_solid, 27,26,26,26,25,25 }, // trapped chest
+   { C_solid, 26,26,26,27,25,25 }, // trapped chest
    { C_empty }, // weighted pressure plate light
    { C_empty }, // weighted pressure plat eheavy
    { C_empty }, // comparator inactive
@@ -315,11 +315,13 @@ void convert_fastchunk_inplace(fast_chunk *fc)
 {
    int i;
    int num_blocks=0, step=0;
-   unsigned char rot[4096] = { 0 };
+   unsigned char rot[4096];
    #ifndef IN_PLACE
    unsigned char *storage;
    #endif
 
+   memset(rot, 0, 4096);
+
    for (i=0; i < 16; ++i)
       num_blocks += fc->blockdata[i] != NULL;
 
@@ -340,15 +342,12 @@ void convert_fastchunk_inplace(fast_chunk *fc)
          sky = fc->skylight[i];
 
          #ifdef IN_PLACE
-         assert(dd < sky && sky < lt && lt < bd);
          out = bd;
-         outb = dd;
          #else
          out = storage + 16*16*16*2*step;
-         outb = out + 16*16*16;
-         ++step;
          #endif
 
+         // bd is written in place, but also reads from dd
          for (o=0; o < 16*16*16/2; o += 1) {
             unsigned char v1,v2;
             unsigned char d = dd[o];
@@ -359,7 +358,7 @@ void convert_fastchunk_inplace(fast_chunk *fc)
             {
                //unsigned char d = bd[o] & 15;
                v1 = remap_data[remap[v1]][d&15];
-               rot[o] = rotate_data[d&3];
+               rot[o*2+0] = rotate_data[d&3];
             } else
                v1 = effective_blocktype[v1];
 
@@ -367,7 +366,7 @@ void convert_fastchunk_inplace(fast_chunk *fc)
             {
                //unsigned char d = bd[o] >> 4;
                v2 = remap_data[remap[v2]][d>>4];
-               rot[o+1] = rotate_data[(d>>4)&3];
+               rot[o*2+1] = rotate_data[(d>>4)&3];
             } else
                v2 = effective_blocktype[v2];
 
@@ -375,18 +374,54 @@ void convert_fastchunk_inplace(fast_chunk *fc)
             out[o*2+1] = v2;
          }
 
-         // because this stores to data[], can't run at same time as above loop
-         for (o=0; o < 16*16*16/2; ++o) {
-            int bright;
-            bright = (lt[o]&15)*12 + 15 + (sky[o]&15)*16;
-            if (bright > 255) bright = 255;
-            if (bright <  32) bright =  32;
-            outb[o*2+0] = STBVOX_MAKE_LIGHTING((unsigned char) bright, rot[o]);
-
-            bright = (lt[o]>>4)*12 + 15 + (sky[o]>>4)*16;
-            if (bright > 255) bright = 255;
-            if (bright <  32) bright =  32;
-            outb[o*2+1] = STBVOX_MAKE_LIGHTING((unsigned char) bright, rot[o+1]);
+         // this reads from lt & sky
+         #ifndef IN_PLACE
+         outb = out + 16*16*16;
+         ++step;
+         #endif
+
+         // MC used to write in this order and it makes it possible to compute in-place
+         if (dd < sky && sky < lt) {
+            // @TODO go this path always if !IN_PLACE
+            #ifdef IN_PLACE
+            outb = dd;
+            #endif
+
+            for (o=0; o < 16*16*16/2; ++o) {
+               int bright;
+               bright = (lt[o]&15)*12 + 15 + (sky[o]&15)*16;
+               if (bright > 255) bright = 255;
+               if (bright <  32) bright =  32;
+               outb[o*2+0] = STBVOX_MAKE_LIGHTING((unsigned char) bright, (rot[o*2+0]&3));
+
+               bright = (lt[o]>>4)*12 + 15 + (sky[o]>>4)*16;
+               if (bright > 255) bright = 255;
+               if (bright <  32) bright =  32;
+               outb[o*2+1] = STBVOX_MAKE_LIGHTING((unsigned char) bright, (rot[o*2+1]&3));
+            }
+         } else {
+            // @TODO: if blocktype is in between others, this breaks; need to find which side has two pointers, and use that
+            // overwrite rot[] array, then copy out
+            #ifdef IN_PLACE
+            outb = (dd < sky) ? dd : sky;
+            if (lt < outb) lt = outb;
+            #endif
+
+            for (o=0; o < 16*16*16/2; ++o) {
+               int bright;
+               bright = (lt[o]&15)*12 + 15 + (sky[o]&15)*16;
+               if (bright > 255) bright = 255;
+               if (bright <  32) bright =  32;
+               rot[o*2+0] = STBVOX_MAKE_LIGHTING((unsigned char) bright, (rot[o*2+0]&3));
+
+               bright = (lt[o]>>4)*12 + 15 + (sky[o]>>4)*16;
+               if (bright > 255) bright = 255;
+               if (bright <  32) bright =  32;
+               rot[o*2+1] = STBVOX_MAKE_LIGHTING((unsigned char) bright, (rot[o*2+1]&3));
+            }
+
+            memcpy(outb, rot, 4096);
+            fc->data[i] = outb;
          }
 
          #ifndef IN_PLACE
@@ -653,10 +688,11 @@ void build_stair_rotations(int blocktype, unsigned char *map)
    int i,j,k;
    for (j=0; j < 2; ++j) {
       int geom = j ? STBVOX_GEOM_ceil_slope_north_is_bottom : STBVOX_GEOM_floor_slope_north_is_top;
+      //int geom = STBVOX_GEOM_solid;
       for (i=0; i < 4; ++i) {
          if (i == 0 && j == 0) {
             map[j*4+i+8] = map[j*4+i] = blocktype;
-            minecraft_geom_for_blocktype[blocktype] = (unsigned char) STBVOX_MAKE_GEOMETRY(geom, mc_rot[i], 0);
+            minecraft_geom_for_blocktype[blocktype] = (unsigned char) STBVOX_MAKE_GEOMETRY(geom, 0, 0);
          } else {
             map[j*4+i+8] = map[j*4+i] = next_blocktype;
 
@@ -664,7 +700,7 @@ void build_stair_rotations(int blocktype, unsigned char *map)
                minecraft_color_for_blocktype[next_blocktype][k] = minecraft_color_for_blocktype[blocktype][k];
                minecraft_tex1_for_blocktype [next_blocktype][k] = minecraft_tex1_for_blocktype [blocktype][k];
             }
-            minecraft_geom_for_blocktype[next_blocktype] = (unsigned char) STBVOX_MAKE_GEOMETRY(geom, mc_rot[i], 0);
+            minecraft_geom_for_blocktype[next_blocktype] = (unsigned char) STBVOX_MAKE_GEOMETRY(geom, 0, 0);
             --next_blocktype;
          }
       }
@@ -690,6 +726,15 @@ void build_wool_variations(int bt, unsigned char *map)
    }
 }
 
+void remap_in_place(int bt, int rm)
+{
+   int i;
+   remap[bt] = rm;
+   for (i=0; i < 16; ++i)
+      remap_data[rm][i] = bt;
+}
+
+
 void mesh_init(void)
 {
    int i;
@@ -750,6 +795,10 @@ void mesh_init(void)
    remap[35]  = 8;
    build_wool_variations(35, remap_data[remap[35]]);
 
+   // set the remap flags for these so they write the rotation values
+   remap_in_place(54, 9);
+   remap_in_place(146, 10);
+
    for (i=0; i < 256; ++i) {
       if (remap[i])
          effective_block_add[i] = 0;

+ 4 - 0
tests/caveview/caveview.dsp

@@ -123,6 +123,10 @@ SOURCE=.\glext_list.h
 # End Source File
 # Begin Source File
 
+SOURCE=.\README.md
+# End Source File
+# Begin Source File
+
 SOURCE=.\win32\SDL_windows_main.c
 # End Source File
 # Begin Source File