normals calculation fix
[voxconv.git] / vox_load.d
blob5d387e1ab52979abc012b8ddc06185ea31c996ba
1 module vox_load;
3 import iv.bclamp;
4 import iv.glbinds.utils;
5 import iv.cmdcongl;
6 import iv.strex;
7 import iv.vfs;
8 import iv.vfs.io;
9 import iv.vmath;
11 static import iv.timer;
13 import vox_data;
16 // ////////////////////////////////////////////////////////////////////////// //
17 public __gshared bool vox_optimize_hollow = true;
20 //==========================================================================
22 // loadKVX
24 //==========================================================================
25 private void loadKVX (ref VoxelData vox, VFile fl, uint fsize) {
26 if (fsize > int.max/8) throw new Exception("voxel data too big (kvx)");
27 version(kvx_dump) conwriteln("loading KVX...");
28 auto nextpos = fl.tell+fsize;
29 uint[] xofs;
30 ushort[][] xyofs;
31 ubyte[] data;
32 int xsiz, ysiz, zsiz;
33 int xpivot, ypivot, zpivot;
35 auto fx = wrapStreamRO(fl, fl.tell, fsize);
36 xsiz = fx.readNum!uint;
37 ysiz = fx.readNum!uint;
38 zsiz = fx.readNum!uint;
39 version(kvx_dump) conwriteln("xsiz=", xsiz, "; ysiz=", ysiz, "; zsiz=", zsiz);
40 if (xsiz < 1 || ysiz < 1 || zsiz < 1 || xsiz > 1024 || ysiz > 1024 || zsiz > 1024) throw new Exception("invalid voxel size");
41 xpivot = fx.readNum!uint;
42 ypivot = fx.readNum!uint;
43 zpivot = fx.readNum!uint;
44 version(kvx_dump) conwriteln("xpivot=", xpivot>>8, "; ypivot=", ypivot>>8, "; zpivot=", zpivot>>8);
45 uint xstart = (xsiz+1)*4+xsiz*(ysiz+1)*2;
46 xofs = new uint[](xsiz+1);
47 foreach (ref o; xofs) o = fx.readNum!uint-xstart;
48 //conwriteln(xofs);
49 xyofs = new ushort[][](xsiz, ysiz+1);
50 foreach (immutable x; 0..xsiz) {
51 foreach (immutable y; 0..ysiz+1) {
52 xyofs[x][y] = fx.readNum!ushort;
55 assert(fx.size-fx.tell == fsize-24-(xsiz+1)*4-xsiz*(ysiz+1)*2);
56 data = new ubyte[](cast(uint)(fx.size-fx.tell));
57 fx.rawReadExact(data);
59 fl.seek(nextpos);
60 // skip mipmaps
61 while (fl.size-fl.tell > 768) {
62 fsize = fl.readNum!uint; // size of this voxel (useful for mipmaps)
63 fl.seek(fsize, Seek.Cur);
64 version(kvx_dump) conwriteln(" skiped ", fsize, " bytes of mipmap");
66 ubyte[768] pal;
67 if (fl.size-fl.tell == 768) {
68 version(kvx_dump) conwriteln(" has palette!");
69 fl.rawReadExact(pal[]);
70 foreach (ref ubyte c; pal[]) {
71 if (c > 63) throw new Exception("invalid palette value");
72 c = clampToByte(255*c/64);
74 } else {
75 foreach (immutable cidx; 0..256) {
76 pal[cidx*3+0] = cidx;
77 pal[cidx*3+1] = cidx;
78 pal[cidx*3+2] = cidx;
81 immutable float px = 1.0f*xpivot/256.0f;
82 immutable float py = 1.0f*ypivot/256.0f;
83 immutable float pz = 1.0f*zpivot/256.0f;
84 // now build cubes
85 version(kvx_dump) conwriteln("building voxel data...");
86 vox.setSize(xsiz, ysiz, zsiz);
87 foreach (immutable y; 0..ysiz) {
88 foreach (immutable x; 0..xsiz) {
89 uint sofs = xofs[x]+xyofs[x][y];
90 uint eofs = xofs[x]+xyofs[x][y+1];
91 while (sofs < eofs) {
92 int ztop = data[sofs++];
93 uint zlen = data[sofs++];
94 ubyte cull = data[sofs++];
95 if (!zlen) continue;
96 //conwritefln(" x=%s; y=%s; z=%s; len=%s; cull=0x%02x", x, y, ztop, zlen, cull);
97 // colors
98 foreach (immutable cidx; 0..zlen) {
99 ubyte palcol = data[sofs++];
100 ubyte cl = cull;
101 version(none) {
102 // no need to do this, voxel optimiser will take care of it
103 if (cidx != 0) cl &= cast(ubyte)~0x10;
104 if (cidx != zlen-1) cl &= cast(ubyte)~0x20;
106 immutable ubyte r = pal[palcol*3+0];
107 immutable ubyte g = pal[palcol*3+1];
108 immutable ubyte b = pal[palcol*3+2];
109 //addCube(cl, (xsiz-x-1)-px, y-py, (zsiz-ztop-1)-pz, b|(g<<8)|(r<<16));
110 //version(kvx_dump) conwriteln(" adding voxel at (", x, ",", y, ",", ztop, ")");
111 vox.addVoxel(xsiz-x-1, y, zsiz-ztop-1, b|(g<<8)|(r<<16), cl);
112 //version(kvx_dump) conwriteln(" added.");
113 ++ztop;
116 assert(sofs == eofs);
119 vox.cx = px;
120 vox.cy = py;
121 vox.cz = pz;
125 //==========================================================================
127 // loadKV6
129 //==========================================================================
130 private void loadKV6 (ref VoxelData vox, VFile fl) {
131 version(kvx_dump) conwriteln("loading KV6...");
132 int xsiz, ysiz, zsiz;
133 float xpivot, ypivot, zpivot;
134 xsiz = fl.readNum!uint;
135 ysiz = fl.readNum!uint;
136 zsiz = fl.readNum!uint;
137 version(kvx_dump) conwriteln("xsiz=", xsiz, "; ysiz=", ysiz, "; zsiz=", zsiz);
138 if (xsiz < 1 || ysiz < 1 || zsiz < 1 || xsiz > 1024 || ysiz > 1024 || zsiz > 1024) {
139 throw new Exception("invalid voxel size (kv6)");
141 xpivot = fl.readNum!float;
142 ypivot = fl.readNum!float;
143 zpivot = fl.readNum!float;
144 version(kvx_dump) conwriteln("xpivot=", xpivot, "; ypivot=", ypivot, "; zpivot=", zpivot);
145 uint voxcount = fl.readNum!uint;
146 if (voxcount == 0 || voxcount > int.max/8) throw new Exception("invalid number of voxels");
147 static struct KVox {
148 uint rgb;
149 ubyte zlo;
150 ubyte zhi;
151 ubyte cull;
152 ubyte normidx;
154 auto kvox = new KVox[](voxcount);
155 foreach (immutable vidx; 0..voxcount) {
156 auto kv = &kvox[vidx];
157 kv.rgb = 0;
158 kv.rgb |= fl.readNum!ubyte;
159 kv.rgb |= fl.readNum!ubyte<<8;
160 kv.rgb |= fl.readNum!ubyte<<16;
161 kv.rgb |= 0xff_00_00_00U;
162 fl.readNum!ubyte; // always 128; ignore
163 kv.zlo = fl.readNum!ubyte;
164 kv.zhi = fl.readNum!ubyte;
165 if (kv.zhi) assert(0, "zhi is not zero!");
166 kv.cull = fl.readNum!ubyte;
167 kv.normidx = fl.readNum!ubyte;
169 auto xofs = new uint[](xsiz+1);
170 uint curvidx = 0;
171 foreach (ref v; xofs[0..$-1]) {
172 v = curvidx;
173 auto count = fl.readNum!uint;
174 curvidx += count;
176 xofs[$-1] = curvidx;
177 auto xyofs = new uint[][](xsiz, ysiz+1);
178 foreach (immutable xx; 0..xsiz) {
179 curvidx = 0;
180 foreach (immutable yy; 0..ysiz) {
181 xyofs[xx][yy] = curvidx;
182 auto count = fl.readNum!ushort;
183 curvidx += count;
185 xyofs[xx][$-1] = curvidx;
187 // now build cubes
188 vox.setSize(xsiz, ysiz, zsiz);
189 foreach (immutable y; 0..ysiz) {
190 foreach (immutable x; 0..xsiz) {
191 uint sofs = xofs[x]+xyofs[x][y];
192 uint eofs = xofs[x]+xyofs[x][y+1];
193 //if (sofs == eofs) continue;
194 //assert(sofs < data.length && eofs <= data.length);
195 while (sofs < eofs) {
196 auto kv = &kvox[sofs++];
197 //debug(kvx_dump) conwritefln(" x=%s; y=%s; zlo=%s; zhi=%s; cull=0x%02x", x, y, kv.zlo, kv.zhi, kv.cull);
198 int z = kv.zlo;
199 foreach (immutable cidx; 0..kv.zhi+1) {
200 z += 1;
201 vox.addVoxel(xsiz-x-1, y, zsiz-z, kv.rgb, kv.cull);
206 //conwriteln(texpos);
207 vox.cx = xpivot;
208 vox.cy = ypivot;
209 vox.cz = zpivot;
213 //==========================================================================
215 // loadVox
217 //==========================================================================
218 private void loadVox (ref VoxelData vox, VFile fl, uint xsiz) {
219 version(kvx_dump) conwriteln("loading VOX...");
220 uint ysiz = fl.readNum!uint;
221 uint zsiz = fl.readNum!uint;
222 /*debug(kvx_dump)*/ conwriteln("xsiz=", xsiz, "; ysiz=", ysiz, "; zsiz=", zsiz);
223 if (xsiz < 1 || ysiz < 1 || zsiz < 1 || xsiz > 1024 || ysiz > 1024 || zsiz > 1024) {
224 throw new Exception("invalid voxel size (vox)");
226 auto fpos = fl.tell();
227 fl.seek(fpos+xsiz*ysiz*zsiz);
228 //auto data = new ubyte[](xsiz*ysiz*zsiz);
229 //fl.rawReadExact(data);
230 ubyte[768] pal;
231 fl.rawReadExact(pal[]);
232 foreach (ref ubyte c; pal[]) {
233 if (c > 63) throw new Exception("invalid palette value");
234 c = clampToByte(255*c/64);
236 immutable float px = 1.0f*xsiz/2.0f;
237 immutable float py = 1.0f*ysiz/2.0f;
238 immutable float pz = 1.0f*zsiz/2.0f;
239 // now build cubes
240 fl.seek(fpos);
241 vox.setSize(xsiz, ysiz, zsiz);
242 foreach (immutable x; 0..xsiz) {
243 foreach (immutable y; 0..ysiz) {
244 foreach (immutable z; 0..zsiz) {
245 ubyte palcol = fl.readNum!ubyte;
246 if (palcol != 255) {
247 uint rgb = pal[palcol*3+2]|(cast(uint)pal[palcol*3+1]<<8)|(cast(uint)pal[palcol*3+0]<<16);
248 //addCube(0xff, (xsiz-x-1)-px, y-py, (zsiz-z-1)-pz, b|(g<<8)|(r<<16));
249 vox.addVoxel(xsiz-x-1, y, zsiz-z-1, rgb, 0xff);
254 vox.cx = px;
255 vox.cy = py;
256 vox.cz = pz;
260 //==========================================================================
262 // loadVxl
264 //==========================================================================
265 private void loadVxl (ref VoxelData vox, VFile fl) {
266 uint xsiz = fl.readNum!uint;
267 uint ysiz = fl.readNum!uint;
268 uint zsiz = 256;
269 /*debug(kvx_dump)*/ conwriteln("xsiz=", xsiz, "; ysiz=", ysiz, "; zsiz=", zsiz);
270 if (xsiz < 1 || ysiz < 1 || zsiz < 1 || xsiz > 1024 || ysiz > 1024 || zsiz > 1024) throw new Exception("invalid voxel size");
271 //immutable float px = 1.0f*xsiz/2.0f;
272 //immutable float py = 1.0f*ysiz/2.0f;
273 //immutable float pz = 1.0f*zsiz/2.0f;
274 float px, py, pz;
275 // camera
276 px = fl.readNum!double;
277 py = fl.readNum!double;
278 pz = fl.readNum!double;
279 pz = zsiz-1-pz;
280 // unit right
281 fl.readNum!double;
282 fl.readNum!double;
283 fl.readNum!double;
284 // unit down
285 fl.readNum!double;
286 fl.readNum!double;
287 fl.readNum!double;
288 // unit forward
289 fl.readNum!double;
290 fl.readNum!double;
291 fl.readNum!double;
293 vox.setSize(xsiz, ysiz, zsiz);
295 void vxlReset (int x, int y, int z) {
296 vox.removeVoxel(xsiz-x-1, y, zsiz-z-1);
299 void vxlPaint (int x, int y, int z, uint clr) {
300 vox.addVoxel(xsiz-x-1, y, zsiz-z-1, clr, 0x3f);
303 // now carve crap out of it
304 auto data = new ubyte[](cast(uint)(fl.size-fl.tell));
305 fl.rawReadExact(data);
306 const(ubyte)* v = data.ptr;
307 foreach (immutable y; 0..ysiz) {
308 foreach (immutable x; 0..xsiz) {
309 uint z = 0;
310 for (;;) {
311 foreach (immutable i; z..v[1]) vxlReset(x, y, i);
312 for (z = v[1]; z <= v[2]; ++z) {
313 const(uint)* cp = cast(const(uint)*)(v+(z-v[1]+1)*4);
314 vxlPaint(x, y, z, *cp);
316 if (!v[0]) break;
317 z = v[2]-v[1]-v[0]+2;
318 v += v[0]*4;
319 for (z += v[3]; z < v[3]; ++z) {
320 const(uint)* cp = cast(const(uint)*)(v+(z-v[3])*4);
321 vxlPaint(x, y, z, *cp);
324 v += (v[2]-v[1]+2)*4;
327 vox.cx = px;
328 vox.cy = py;
329 vox.cz = pz;
333 //==========================================================================
335 // loadVoxel
337 //==========================================================================
338 public void loadVoxel (ref VoxelData vox, string fname, bool asvox=false) {
339 auto fl = VFile(fname);
340 uint fsize = fl.readNum!uint; // size of this voxel (useful for mipmaps)
341 auto tm = iv.timer.Timer(true);
342 if (fsize == 0x6c78764bU) {
343 loadKV6(vox, fl);
344 } else if (fsize == 0x09072000U) {
345 loadVxl(vox, fl);
346 } else {
347 if (fname.endsWithCI(".vox")) loadVox(vox, fl, fsize);
348 else loadKVX(vox, fl, fsize);
350 tm.stop();
351 conwriteln("loaded in ", tm.toString(), "; grid size: ", vox.xsize, "x", vox.ysize, "x", vox.zsize);
352 tm.restart();
353 vox.optimise(vox_optimize_hollow);
354 tm.stop();
355 conwriteln("optimised in ", tm.toString());