{"action":"created","issue":{"url":"https://api.github.com/repos/ephtracy/voxel-model/issues/1","repository_url":"https://api.github.com/repos/ephtracy/voxel-model","labels_url":"https://api.github.com/repos/ephtracy/voxel-model/issues/1/labels{/name}","comments_url":"https://api.github.com/repos/ephtracy/voxel-model/issues/1/comments","events_url":"https://api.github.com/repos/ephtracy/voxel-model/issues/1/events","html_url":"https://github.com/ephtracy/voxel-model/issues/1","id":185032398,"number":1,"title":"A few questions about the vox format","user":{"login":"mgerhardy","id":577713,"avatar_url":"https://avatars.githubusercontent.com/u/577713?v=3","gravatar_id":"","url":"https://api.github.com/users/mgerhardy","html_url":"https://github.com/mgerhardy","followers_url":"https://api.github.com/users/mgerhardy/followers","following_url":"https://api.github.com/users/mgerhardy/following{/other_user}","gists_url":"https://api.github.com/users/mgerhardy/gists{/gist_id}","starred_url":"https://api.github.com/users/mgerhardy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mgerhardy/subscriptions","organizations_url":"https://api.github.com/users/mgerhardy/orgs","repos_url":"https://api.github.com/users/mgerhardy/repos","events_url":"https://api.github.com/users/mgerhardy/events{/privacy}","received_events_url":"https://api.github.com/users/mgerhardy/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":5,"created_at":"2016-10-25T06:48:30Z","updated_at":"2016-10-25T10:34:29Z","closed_at":null,"body":"Everything is tied to be little endian, right?\r\n\r\n\"4 x N | int | (x, y, z, colorIndex) : 1 byte for each component\"\r\nIf x, y and z coordinates of a voxel can only be a byte, how do you create big models? Maybe this is a typo and should be int, too? Because the size of the whole volume is int, too - imo that wouldn't make sense if the max coordinates can only be in 0-255 range.\r\n\r\nthe main chunk always has a 0 for \"num bytes of chunk content\"?\r\n\r\n\"4 * N | float | normalized property value : (0.0 - 1.0]\" The N here is it the chunk content bytes?"},"comment":{"url":"https://api.github.com/repos/ephtracy/voxel-model/issues/comments/255999114","html_url":"https://github.com/ephtracy/voxel-model/issues/1#issuecomment-255999114","issue_url":"https://api.github.com/repos/ephtracy/voxel-model/issues/1","id":255999114,"user":{"login":"mgerhardy","id":577713,"avatar_url":"https://avatars.githubusercontent.com/u/577713?v=3","gravatar_id":"","url":"https://api.github.com/users/mgerhardy","html_url":"https://github.com/mgerhardy","followers_url":"https://api.github.com/users/mgerhardy/followers","following_url":"https://api.github.com/users/mgerhardy/following{/other_user}","gists_url":"https://api.github.com/users/mgerhardy/gists{/gist_id}","starred_url":"https://api.github.com/users/mgerhardy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mgerhardy/subscriptions","organizations_url":"https://api.github.com/users/mgerhardy/orgs","repos_url":"https://api.github.com/users/mgerhardy/repos","events_url":"https://api.github.com/users/mgerhardy/events{/privacy}","received_events_url":"https://api.github.com/users/mgerhardy/received_events","type":"User","site_admin":false},"created_at":"2016-10-25T10:34:29Z","updated_at":"2016-10-25T10:34:29Z","body":"```\r\n#include \"VoxLoader.h\"\r\n#include \"io/FileStream.h\"\r\n#include \"core/Common.h\"\r\n\r\nnamespace voxel {\r\n\r\n#define wrap(read) \\\r\n\tif (read != 0) { \\\r\n\t\tLog::error(\"Could not load vox file: Not enough data in stream\"); \\\r\n\t\treturn nullptr; \\\r\n\t}\r\n\r\nRawVolume* VoxLoader::load(const io::FilePtr& file) {\r\n\tif (!(bool)file || !file->exists()) {\r\n\t\tLog::error(\"Could not load vox file: File doesn't exist\");\r\n\t\treturn nullptr;\r\n\t}\r\n\tio::FileStream stream(file.get());\r\n\r\n\t// 1. File Structure : RIFF style\r\n\t// -------------------------------------------------------------------------------\r\n\t// # Bytes  | Type       | Value\r\n\t// -------------------------------------------------------------------------------\r\n\t// 1x4      | char       | id 'VOX ' : 'V' 'O' 'X' 'space', 'V' is first\r\n\t// 4        | int        | version number : 150\r\n\t//\r\n\t// Chunk 'MAIN'\r\n\t// {\r\n\t//     // pack of models\r\n\t//     Chunk 'PACK'    : optional\r\n\t//\r\n\t//     // models\r\n\t//     Chunk 'SIZE'\r\n\t//     Chunk 'XYZI'\r\n\t//\r\n\t//     Chunk 'SIZE'\r\n\t//     Chunk 'XYZI'\r\n\t//\r\n\t//     ...\r\n\t//\r\n\t//     Chunk 'SIZE'\r\n\t//     Chunk 'XYZI'\r\n\t//\r\n\t//     // palette\r\n\t//     Chunk 'RGBA'    : optional\r\n\t//\r\n\t//     // materials\r\n\t//     Chunk 'MATT'    : optional\r\n\t//     Chunk 'MATT'\r\n\t//     ...\r\n\t//     Chunk 'MATT'\r\n\t// }\r\n\t// -------------------------------------------------------------------------------\r\n\r\n\tuint32_t header;\r\n\twrap(stream.readInt(header))\r\n\tconstexpr uint32_t headerMagic = FourCC('V','O','X',' ');\r\n\tif (header != headerMagic) {\r\n\t\tLog::error(\"Could not load vox file: Invalid magic found (%u vs %u)\", header, headerMagic);\r\n\t\treturn nullptr;\r\n\t}\r\n\r\n\tuint32_t version;\r\n\twrap(stream.readInt(version))\r\n\r\n\tif (version != 150) {\r\n\t\tLog::warn(\"Vox file loading is only tested for version 150 - but we've found %i\", version);\r\n\t}\r\n\r\n\t// 2. Chunk Structure\r\n\t// -------------------------------------------------------------------------------\r\n\t// # Bytes  | Type       | Value\r\n\t// -------------------------------------------------------------------------------\r\n\t// 1x4      | char       | chunk id\r\n\t// 4        | int        | num bytes of chunk content (N)\r\n\t// 4        | int        | num bytes of children chunks (M)\r\n\t// N        |            | chunk content\r\n\t// M        |            | children chunks\r\n\t// -------------------------------------------------------------------------------\r\n\r\n\tuint32_t mainChunk;\r\n\twrap(stream.readInt(mainChunk))\r\n\t// 3. Chunk id 'MAIN' : the root chunk and parent chunk of all the other chunks\r\n\tif (mainChunk != FourCC('M','A','I','N')) {\r\n\t\tLog::error(\"Could not load vox file: Invalid magic for main chunk found\");\r\n\t\treturn nullptr;\r\n\t}\r\n\r\n\tuint32_t numBytesMainChunk;\r\n\twrap(stream.readInt(numBytesMainChunk))\r\n\tuint32_t numBytesMainChildrenChunks;\r\n\twrap(stream.readInt(numBytesMainChildrenChunks))\r\n\r\n\tif (stream.remaining() < numBytesMainChildrenChunks) {\r\n\t\tLog::error(\"Could not load vox file: Incomplete file\");\r\n\t\treturn nullptr;\r\n\t}\r\n\r\n\tRawVolume *volume = nullptr;\r\n\tuint32_t numModels = 1;\r\n\r\n\t// 8. Default Palette : if chunk 'RGBA' is absent\r\n\t// -------------------------------------------------------------------------------\r\n\tuint32_t palette[256] = {\r\n\t\t0x00000000, 0xffffffff, 0xffccffff, 0xff99ffff, 0xff66ffff, 0xff33ffff, 0xff00ffff, 0xffffccff, 0xffccccff, 0xff99ccff, 0xff66ccff, 0xff33ccff, 0xff00ccff, 0xffff99ff, 0xffcc99ff, 0xff9999ff,\r\n\t\t0xff6699ff, 0xff3399ff, 0xff0099ff, 0xffff66ff, 0xffcc66ff, 0xff9966ff, 0xff6666ff, 0xff3366ff, 0xff0066ff, 0xffff33ff, 0xffcc33ff, 0xff9933ff, 0xff6633ff, 0xff3333ff, 0xff0033ff, 0xffff00ff,\r\n\t\t0xffcc00ff, 0xff9900ff, 0xff6600ff, 0xff3300ff, 0xff0000ff, 0xffffffcc, 0xffccffcc, 0xff99ffcc, 0xff66ffcc, 0xff33ffcc, 0xff00ffcc, 0xffffcccc, 0xffcccccc, 0xff99cccc, 0xff66cccc, 0xff33cccc,\r\n\t\t0xff00cccc, 0xffff99cc, 0xffcc99cc, 0xff9999cc, 0xff6699cc, 0xff3399cc, 0xff0099cc, 0xffff66cc, 0xffcc66cc, 0xff9966cc, 0xff6666cc, 0xff3366cc, 0xff0066cc, 0xffff33cc, 0xffcc33cc, 0xff9933cc,\r\n\t\t0xff6633cc, 0xff3333cc, 0xff0033cc, 0xffff00cc, 0xffcc00cc, 0xff9900cc, 0xff6600cc, 0xff3300cc, 0xff0000cc, 0xffffff99, 0xffccff99, 0xff99ff99, 0xff66ff99, 0xff33ff99, 0xff00ff99, 0xffffcc99,\r\n\t\t0xffcccc99, 0xff99cc99, 0xff66cc99, 0xff33cc99, 0xff00cc99, 0xffff9999, 0xffcc9999, 0xff999999, 0xff669999, 0xff339999, 0xff009999, 0xffff6699, 0xffcc6699, 0xff996699, 0xff666699, 0xff336699,\r\n\t\t0xff006699, 0xffff3399, 0xffcc3399, 0xff993399, 0xff663399, 0xff333399, 0xff003399, 0xffff0099, 0xffcc0099, 0xff990099, 0xff660099, 0xff330099, 0xff000099, 0xffffff66, 0xffccff66, 0xff99ff66,\r\n\t\t0xff66ff66, 0xff33ff66, 0xff00ff66, 0xffffcc66, 0xffcccc66, 0xff99cc66, 0xff66cc66, 0xff33cc66, 0xff00cc66, 0xffff9966, 0xffcc9966, 0xff999966, 0xff669966, 0xff339966, 0xff009966, 0xffff6666,\r\n\t\t0xffcc6666, 0xff996666, 0xff666666, 0xff336666, 0xff006666, 0xffff3366, 0xffcc3366, 0xff993366, 0xff663366, 0xff333366, 0xff003366, 0xffff0066, 0xffcc0066, 0xff990066, 0xff660066, 0xff330066,\r\n\t\t0xff000066, 0xffffff33, 0xffccff33, 0xff99ff33, 0xff66ff33, 0xff33ff33, 0xff00ff33, 0xffffcc33, 0xffcccc33, 0xff99cc33, 0xff66cc33, 0xff33cc33, 0xff00cc33, 0xffff9933, 0xffcc9933, 0xff999933,\r\n\t\t0xff669933, 0xff339933, 0xff009933, 0xffff6633, 0xffcc6633, 0xff996633, 0xff666633, 0xff336633, 0xff006633, 0xffff3333, 0xffcc3333, 0xff993333, 0xff663333, 0xff333333, 0xff003333, 0xffff0033,\r\n\t\t0xffcc0033, 0xff990033, 0xff660033, 0xff330033, 0xff000033, 0xffffff00, 0xffccff00, 0xff99ff00, 0xff66ff00, 0xff33ff00, 0xff00ff00, 0xffffcc00, 0xffcccc00, 0xff99cc00, 0xff66cc00, 0xff33cc00,\r\n\t\t0xff00cc00, 0xffff9900, 0xffcc9900, 0xff999900, 0xff669900, 0xff339900, 0xff009900, 0xffff6600, 0xffcc6600, 0xff996600, 0xff666600, 0xff336600, 0xff006600, 0xffff3300, 0xffcc3300, 0xff993300,\r\n\t\t0xff663300, 0xff333300, 0xff003300, 0xffff0000, 0xffcc0000, 0xff990000, 0xff660000, 0xff330000, 0xff0000ee, 0xff0000dd, 0xff0000bb, 0xff0000aa, 0xff000088, 0xff000077, 0xff000055, 0xff000044,\r\n\t\t0xff000022, 0xff000011, 0xff00ee00, 0xff00dd00, 0xff00bb00, 0xff00aa00, 0xff008800, 0xff007700, 0xff005500, 0xff004400, 0xff002200, 0xff001100, 0xffee0000, 0xffdd0000, 0xffbb0000, 0xffaa0000,\r\n\t\t0xff880000, 0xff770000, 0xff550000, 0xff440000, 0xff220000, 0xff110000, 0xffeeeeee, 0xffdddddd, 0xffbbbbbb, 0xffaaaaaa, 0xff888888, 0xff777777, 0xff555555, 0xff444444, 0xff222222, 0xff111111\r\n\t};\r\n\r\n\tdo {\r\n\t\tuint32_t chunkId;\r\n\t\twrap(stream.readInt(chunkId))\r\n\t\tuint32_t numBytesChunk;\r\n\t\twrap(stream.readInt(numBytesChunk))\r\n\t\tuint32_t numBytesChildrenChunks;\r\n\t\twrap(stream.readInt(numBytesChildrenChunks))\r\n\t\tconst int64_t currentChunkPos = stream.pos();\r\n\t\tconst int64_t nextChunkPos = currentChunkPos + numBytesChunk + numBytesChildrenChunks;\r\n\r\n\t\tif (chunkId == FourCC('P','A','C','K')) {\r\n\t\t\tLog::debug(\"Found pack chunk with %u bytes\", numBytesChunk);\r\n\t\t\t// 4. Chunk id 'PACK' : if it is absent, only one model in the file\r\n\t\t\t// -------------------------------------------------------------------------------\r\n\t\t\t// # Bytes  | Type       | Value\r\n\t\t\t// -------------------------------------------------------------------------------\r\n\t\t\t// 4        | int        | numModels : num of SIZE and XYZI chunks\r\n\t\t\t// -------------------------------------------------------------------------------\r\n\t\t\twrap(stream.readInt(numModels))\r\n\t\t\tif (numModels > 1) {\r\n\t\t\t\tLog::warn(\"We are right now only loading the first model of a vox file\");\r\n\t\t\t}\r\n\t\t} else if (chunkId == FourCC('S','I','Z','E')) {\r\n\t\t\tLog::debug(\"Found size chunk with %u bytes\", numBytesChunk);\r\n\t\t\t// 5. Chunk id 'SIZE' : model size\r\n\t\t\t// -------------------------------------------------------------------------------\r\n\t\t\t// # Bytes  | Type       | Value\r\n\t\t\t// -------------------------------------------------------------------------------\r\n\t\t\t// 4        | int        | size x\r\n\t\t\t// 4        | int        | size y\r\n\t\t\t// 4        | int        | size z : gravity direction\r\n\t\t\t// -------------------------------------------------------------------------------\r\n\t\t\t// we have to flip the axis here\r\n\t\t\tuint32_t x, y, z;\r\n\t\t\twrap(stream.readInt(x))\r\n\t\t\twrap(stream.readInt(z))\r\n\t\t\twrap(stream.readInt(y))\r\n\t\t\tglm::ivec3 maxs(x, y, z);\r\n\t\t\tLog::debug(\"Found size chunk: (%u:%u:%u)\", x, y, z);\r\n\t\t\tRegion region(glm::ivec3(0), maxs);\r\n\t\t\tif (volume != nullptr) {\r\n\t\t\t\tdelete volume;\r\n\t\t\t}\r\n\t\t\tvolume = new RawVolume(region);\r\n\t\t} else if (chunkId == FourCC('X','Y','Z','I')) {\r\n\t\t\tLog::debug(\"Found voxel chunk with %u bytes\", numBytesChunk);\r\n\t\t\t// 6. Chunk id 'XYZI' : model voxels\r\n\t\t\t// -------------------------------------------------------------------------------\r\n\t\t\t// # Bytes  | Type       | Value\r\n\t\t\t// -------------------------------------------------------------------------------\r\n\t\t\t// 4        | int        | numVoxels (N)\r\n\t\t\t// 4 x N    | int        | (x, y, z, colorIndex) : 1 byte for each component\r\n\t\t\t// -------------------------------------------------------------------------------\r\n\t\t\tuint32_t numVoxels;\r\n\t\t\twrap(stream.readInt(numVoxels))\r\n\t\t\tif (volume == nullptr) {\r\n\t\t\t\tLog::error(\"Could not load vox file: Wrong order of chunks\");\r\n\t\t\t\treturn nullptr;\r\n\t\t\t}\r\n\t\t\tLog::debug(\"Found voxel chunk with %u voxels\", numVoxels);\r\n\t\t\tfor (uint32_t i = 0; i < numVoxels; ++i) {\r\n\t\t\t\t// we have to flip the axis here\r\n\t\t\t\tuint8_t x, y, z, colorIndex;\r\n\t\t\t\twrap(stream.readByte(x))\r\n\t\t\t\twrap(stream.readByte(z))\r\n\t\t\t\twrap(stream.readByte(y))\r\n\t\t\t\twrap(stream.readByte(colorIndex))\r\n\t\t\t\t// TODO: palette support\r\n\t\t\t\tvolume->setVoxel(x, y, z, createVoxel(Grass1));\r\n\t\t\t}\r\n\t\t} else if (chunkId == FourCC('R','G','B','A')) {\r\n\t\t\tLog::debug(\"Found palette chunk with %u bytes\", numBytesChunk);\r\n\t\t\t// 7. Chunk id 'RGBA' : palette\r\n\t\t\t// -------------------------------------------------------------------------------\r\n\t\t\t// # Bytes  | Type       | Value\r\n\t\t\t// -------------------------------------------------------------------------------\r\n\t\t\t// 4 x 256  | int        | (R, G, B, A) : 1 byte for each component\r\n\t\t\t//                       | * <NOTICE>\r\n\t\t\t//                       | * color [0-254] are mapped to palette index [1-255], e.g :\r\n\t\t\t//                       |\r\n\t\t\t//                       | for ( int i = 0; i <= 254; i++ ) {\r\n\t\t\t//                       |     palette[i + 1] = ReadRGBA();\r\n\t\t\t//                       | }\r\n\t\t\t// -------------------------------------------------------------------------------\r\n\t\t\tfor (int i = 0; i <= 254; i++) {\r\n\t\t\t\tuint32_t rgba;\r\n\t\t\t\twrap(stream.readInt(rgba))\r\n\t\t\t\tpalette[i + 1] = rgba;\r\n\t\t\t}\r\n\t\t} else if (chunkId == FourCC('M','A','T','T')) {\r\n\t\t\tLog::debug(\"Found material chunk with %u bytes\", numBytesChunk);\r\n\t\t\t// 9. Chunk id 'MATT' : material, if it is absent, it is diffuse material\r\n\t\t\t// -------------------------------------------------------------------------------\r\n\t\t\t// # Bytes  | Type       | Value\r\n\t\t\t// -------------------------------------------------------------------------------\r\n\t\t\t// 4        | int        | id [1-255]\r\n\t\t\t//\r\n\t\t\t// 4        | int        | material type\r\n\t\t\t//                       | 0 : diffuse\r\n\t\t\t//                       | 1 : metal\r\n\t\t\t//                       | 2 : glass\r\n\t\t\t//                       | 3 : emissive\r\n\t\t\t//\r\n\t\t\t// 4        | float      | material weight\r\n\t\t\t//                       | diffuse  : 1.0\r\n\t\t\t//                       | metal    : (0.0 - 1.0] : blend between metal and diffuse material\r\n\t\t\t//                       | glass    : (0.0 - 1.0] : blend between glass and diffuse material\r\n\t\t\t//                       | emissive : (0.0 - 1.0] : self-illuminated material\r\n\t\t\t//\r\n\t\t\t// 4        | int        | property bits : set if value is saved in next section\r\n\t\t\t//                       | bit(0) : Plastic\r\n\t\t\t//                       | bit(1) : Roughness\r\n\t\t\t//                       | bit(2) : Specular\r\n\t\t\t//                       | bit(3) : IOR\r\n\t\t\t//                       | bit(4) : Attenuation\r\n\t\t\t//                       | bit(5) : Power\r\n\t\t\t//                       | bit(6) : Glow\r\n\t\t\t//                       | bit(7) : isTotalPower (*no value)\r\n\t\t\t//\r\n\t\t\t// 4 * N    | float      | normalized property value : (0.0 - 1.0]\r\n\t\t\t//                       | * need to map to real range\r\n\t\t\t//                       | * Plastic material only accepts {0.0, 1.0} for this version\r\n\t\t\t// -------------------------------------------------------------------------------\r\n\t\t\t// TODO:\r\n\t\t\tuint32_t materialId;\r\n\t\t\twrap(stream.readInt(materialId))\r\n\t\t\tuint32_t materialType;\r\n\t\t\twrap(stream.readInt(materialType))\r\n\t\t\tfloat materialWeight;\r\n\t\t\twrap(stream.readFloat(materialWeight))\r\n\t\t\tuint32_t materialProperties;\r\n\t\t\twrap(stream.readInt(materialProperties))\r\n\t\t\tfor (uint32_t i = 0; i < numBytesChunk; ++i) {\r\n\t\t\t\tfloat materialPropertyValue;\r\n\t\t\t\twrap(stream.readFloat(materialPropertyValue))\r\n\t\t\t}\r\n\t\t}\r\n\t\tstream.seek(nextChunkPos);\r\n\t} while (stream.remaining() > 0);\r\n\r\n\treturn volume;\r\n}\r\n\r\n}\r\n\r\n```\r\n\r\nPosting some code here. Is this how it should be to be future proof (ignore the TODOs, it's just about the offsetting and so on).\r\n\r\nThanks for your help."}}
{"actor":{"display_login":"mgerhardy"}}