private BlendChunk findChunkByPtr(long ptr) { if (ptr == 0) { return(null); } BlendChunk chunk = chunks.Get(ptr); if (chunk == null) { return(null); } if (chunk.dup) { // Console.WriteLine("Duplicate:" + Long.toString(ptr, 16) + ",idx=" + chunk.dupidx); int cnt = chunk.dupidx; chunk.dupidx++; for (int a = 0; a < cnt; a++) { chunk = chunk.nextdup; } } return(chunk); }
private void readLayer(long layers, String name) { if (layers == 0) { return; } // Console.WriteLine(name + ".layers=" + Long.toString(layers, 16)); BlendChunk raw = findChunkByPtr(layers); if (raw == null) { throw new Exception("GL_BLEND:Unable to find " + name + ".layers for Mesh"); } setData(raw.raw); // Console.WriteLine("#layers=" + raw.nr); for (int a = 0; a < raw.nr; a++) { BlendCustomDataLayer layer = new BlendCustomDataLayer(this); layer.read(); String layer_name = layer.name; if (layer.data == 0) { // Console.WriteLine("layer.data == null"); continue; } BlendChunk layer_data = findChunkByPtr(layer.data); if (layer_data == null) { throw new Exception("GL_BLEND:Unable to find " + name + ".layers.data for Mesh"); } BlendContext ctx = pushData(); setData(layer_data.raw); // Console.WriteLine("layer.data=" + Long.toString(layer.data, 16) + ",type==" + layer.type + ",a=" + a); switch (layer.type) { case CD_MTEXPOLY: { //15 //NOTE:There fis a MTexPoly per face, I only read the first BlendMTexPoly tex = new BlendMTexPoly(this); tex.read(); BlendChunk imageChunk = findChunkByPtr(tex.tpage); if (imageChunk == null) { throw new Exception("GL_BLEND:No texture found for UVMap:" + a); } setData(imageChunk.raw); BlendImage image = new BlendImage(this); image.read(); OpenGLUVMap map; if (a < obj.GetUVMapCount()) { map = obj.GetUVMap(a); } else { map = obj.CreateUVMap(); } String tn = image.name; //string texture path for now int tnidx = tn.LastIndexOf('/'); if (tnidx != -1) { tn = tn.Substring(tnidx + 1); } tnidx = tn.LastIndexOf('\\'); if (tnidx != -1) { tn = tn.Substring(tnidx + 1); } int tidx = model.AddTexture(tn); map.SetTextureIndex(tidx); map.SetName(layer_name); // Console.WriteLine("texpoly=" + map.name); break; } case CD_MLOOPUV: { //16 //There fis a UV per face per vertex if (a >= obj.GetUVMapCount()) { obj.CreateUVMap(); } // Console.WriteLine("loopuv.nr=" + layer_data.nr); for (int b = 0; b < layer_data.nr; b++) { BlendMLoopUV uv = new BlendMLoopUV(this); uv.read(); uv.uv[1] = 1.0f - uv.uv[1]; //invert V(y) obj.AddUV(uv.uv, a); } break; } } popData(ctx); } }
private void readObject(BlendChunk chunk) { List <BlendVertex> vertexList = new List <BlendVertex>(); List <int> loopList = new List <int>(); setData(chunk.raw); BlendObject bObj = new BlendObject(this); bObj.read(); // Console.WriteLine("bobject.type=" + bObj.type); if (bObj.type != 1) { return; //not a mesh bobject (could be camera, light, etc.) } obj = new OpenGLObject(); model.AddObject(obj); obj.SetName(bObj.id.name.Substring(2)); // Console.WriteLine("bobject=" + obj.name); chunk = findChunkByPtr(bObj.data); if (chunk == null) { throw new Exception("GL_BLEND:Unable to find Mesh for Object"); } BlendMesh mesh = new BlendMesh(this); setData(chunk.raw); // Console.WriteLine("Mesh@" + Int32.toString(raw.fileOffset, 16)); mesh.read(); obj.GetOrigin().x = bObj.loc[0]; org[0] = bObj.loc[0]; obj.GetOrigin().y = bObj.loc[1]; org[1] = bObj.loc[1]; obj.GetOrigin().z = bObj.loc[2]; org[2] = bObj.loc[2]; //find mvert chunk = findChunkByPtr(mesh.mvert); if (chunk == null) { throw new Exception("GL_BLEND:Unable to find MVert for Mesh"); } setData(chunk.raw); for (int a = 0; a < chunk.nr; a++) { BlendMVert mvert = new BlendMVert(this); mvert.read(); // obj.AddVertex(mvert.co); BlendVertex v = new BlendVertex(); v.xyz = mvert.v; vertexList.Add(v); } //find mloop chunk = findChunkByPtr(mesh.mloop); if (chunk == null) { throw new Exception("GL_BLEND:Unable to find MLoop for Mesh"); } setData(chunk.raw); for (int a = 0; a < chunk.nr; a++) { BlendMLoop mloop = new BlendMLoop(this); mloop.read(); loopList.Add(mloop.v); } //find mloopuv /* //use the UVMaps _in the CustomData instead - this fis only the active one * raw = findChunkByPtr(mesh.mloopuv); * if (raw == null) { * throw new Exception("GL_BLEND:Unable to find MLoopUV for Mesh"); * } * setData(raw.raw); * Console.WriteLine("MLoopUV:nr=" + raw.nr); * for(int a=0;a<raw.nr;a++) { * MLoopUV mloopuv = new MLoopUV(); * mloopuv.read(); * } */ //find mpoly chunk = findChunkByPtr(mesh.mpoly); if (chunk == null) { throw new Exception("GL_BLEND:Unable to find MPoly for Mesh"); } setData(chunk.raw); //TODO : calc which vertex needed to be dup'ed for each unique uv value (Blender does this _in their 3ds export script) int type = -1; int pcnt = -1; int vidx = 0; //MPoly = faces for (int a = 0; a < chunk.nr; a++) { BlendMPoly mpoly = new BlendMPoly(this); mpoly.read(); switch (mpoly.totloop) { case 3: if (type == GL_QUADS) { throw new Exception("GL_BLEND:Mixed QUADS/TRIANGLES not supported"); } type = GL_TRIANGLES; pcnt = 3; break; case 4: if (type == GL_TRIANGLES) { throw new Exception("GL_BLEND:Mixed QUADS/TRIANGLES not supported"); } type = GL_QUADS; pcnt = 4; break; default: throw new Exception("GL_BLEND:Polygon not supported:nr=" + mpoly.totloop); } int loopidx = mpoly.loopstart; for (int p = 0; p < pcnt; p++) { int idx = loopList.Get(loopidx++); obj.AddVertex(vertexList.Get(idx).xyz); obj.AddPoly(new int[] { vidx++ }); } } obj.SetType(type); //find customdata types readLayer(mesh.vdata.layers, "vdata"); readLayer(mesh.edata.layers, "edata"); readLayer(mesh.fdata.layers, "fdata"); readLayer(mesh.pdata.layers, "pdata"); readLayer(mesh.ldata.layers, "ldata"); }
private OpenGLModel loadBlend(IOStream fis) { setData(fis.ReadAll().ToArray()); if (data.Length < 12) { throw new Exception("GL_BLEND:File too small"); } model = new OpenGLModel(); //load signature (12 bytes) "BLENDER_V100" if (!new String(data, 0, 7).Equals("BLENDER")) { throw new Exception("Not a blender file"); } switch ((char)data[7]) { case '-': x64 = true; break; case '_': x64 = false; break; default: throw new Exception("GL_BLEND:Unknown bit size"); } switch ((char)data[8]) { case 'v': le = true; break; case 'V': le = false; break; default: throw new Exception("GL_BLEND:Unknown Endianness"); } String version = new String(data, 9, 3); // Console.WriteLine("Blender file version:" + version); int ver = Int32.ValueOf(version); if (ver < 263) { throw new Exception("Error:Blender file too old, can not read."); } datapos = 12; //skip main header //first phase - read raw chunks while (!eof()) { BlendChunk chunk = new BlendChunk(this); chunk.filepos = datapos; chunk.read(); BlendChunk ochunk = chunks.Get(chunk.ptr); if (ochunk != null) { if (!haveDups) { Console.WriteLine("Warning:This file contains duplicate BHeads."); haveDups = true; } ochunk.dup = true; while (ochunk.nextdup != null) { ochunk = ochunk.nextdup; } ochunk.nextdup = chunk; } else { chunks.Set(chunk.ptr, chunk); } } int chunkCnt = chunks.Size(); BlendChunk[] chunkArray = chunks.Values(); BlendChunk raw; //2nd phase - parse DNA chunk for (int i = 0; i < chunkCnt; i++) { if (chunkArray[i].id == ID_DNA1) { raw = chunkArray[i]; setData(raw.raw); //SDNA String SDNA = readString(4); if (!SDNA.Equals("SDNA")) { throw new Exception("Bad DNA Struct:SDNA"); } //NAME String NAME = readString(4); if (!NAME.Equals("NAME")) { throw new Exception("Bad DNA Struct:NAME"); } int nr_names = readuint32(); for (int a = 0; a < nr_names; a++) { String str = readString(); // Console.WriteLine("name=" + str); names.Add(str); } //align pointer datapos += 3; datapos &= 0x7ffffffc; //TYPE String TYPE = readString(4); if (!TYPE.Equals("TYPE")) { throw new Exception("Bad DNA Struct:TYPE"); } int nr_types = readuint32(); for (int a = 0; a < nr_types; a++) { String str = readString(); // Console.WriteLine("type=" + str); types.Add(str); } //align pointer datapos += 3; datapos &= 0x7ffffffc; //TLEN String TLEN = readString(4); if (!TLEN.Equals("TLEN")) { throw new Exception("Bad DNA Struct:TLEN"); } for (int a = 0; a < nr_types; a++) { typelen.Add(readuint16()); } //align pointer datapos += 3; datapos &= 0x7ffffffc; //STRC String STRC = readString(4); if (!STRC.Equals("STRC")) { throw new Exception("Bad DNA Struct:STRC"); } int nr_structs = readuint32(); for (int a = 0; a < nr_structs; a++) { BlendStruct s = new BlendStruct(); s.typeidx = readuint16(); s.nr = readuint16(); s.name = types.Get(s.typeidx); // Console.WriteLine("Struct:" + s.name + "==" + a); for (int b = 0; b < s.nr; b++) { BlendMember m = new BlendMember(); m.typelenidx = readuint16(); m.nameidx = readuint16(); m.name = names.Get(m.nameidx); m.typelen = typelen.Get(m.typelenidx); m.size = calcMemberSize(m); // Console.WriteLine(" Member:" + m.name + "=" + m.Length); s.members.Add(m); } structs.Add(s); } break; } } //3nd phase - now look for objects and piece together chunks for (int i = 0; i < chunkCnt; i++) { if (chunkArray[i].id == ID_SC) { setData(chunkArray[i].raw); BlendScene OpenGLScene = new BlendScene(this); OpenGLScene.read(); long ptr = OpenGLScene.last; while (ptr != 0) { BlendChunk chunk = findChunkByPtr(ptr); if (chunk == null) { break; } setData(chunk.raw); BlendBase _base = new BlendBase(this); _base.read(); chunk = findChunkByPtr(_base.bobject); if (chunk.id == ID_OB) { readObject(chunk); } ptr = _base.prev; } } } return(model); }