// Returns the contents of a LWOB static LightwaveObject ReadObject5(ChunkReader reader) { // allocate an object and a default layer var newObject = new LightwaveObject(); var currentLayer = new Layer(); newObject.Layers.Add(currentLayer); uint pointOffset = 0; uint polygonOffset = 0; uint tagOffset = 0; // process chunks as they're encountered while (reader.BytesLeft > 0) { var id = reader.ReadID<ChunkType>(); var cksize = reader.ReadUInt32(); cksize += cksize & 1; using (var subchunkReader = reader.GetSubChunk(cksize)) { switch (id) { case ChunkType.ID_PNTS: { pointOffset = (uint)currentLayer.Points.Count; currentLayer.Points.AddRange( ReadPoints(subchunkReader) // throws exception on failure ); break; } case ChunkType.ID_POLS: { polygonOffset = (uint)currentLayer.Polygons.Count; currentLayer.Polygons.AddRange( ReadPolygons5(subchunkReader, pointOffset) // throws exception on failure ); break; } case ChunkType.ID_SRFS: { tagOffset = (uint)newObject.Tags.Count; newObject.Tags.AddRange( LightwaveObject.ReadTags(subchunkReader) // throws exception on failure ); break; } case ChunkType.ID_SURF: { newObject.Surfaces.Add( Surface.ReadSurface5(subchunkReader, newObject) // throws exception on failure ); break; } default: Console.WriteLine("Unknown chunk type " + reader.GetIDString((uint)id)); break; } } } if (newObject.Tags.Count == 0) throw new Exception("No tags found for this layer"); // TODO: create a proper exception class uint layer_index = 0; foreach (var layer in newObject.Layers) { layer.CalculateBoundingBox(); newObject.CalculatePolygonNormals(layer.Points, layer.Polygons); newObject.ResolvePointPolygons(layer.Points, layer.Polygons); newObject.ResolvePolygonSurfaces(layer.Polygons, newObject.Tags, newObject.Surfaces, layer_index); newObject.CalculateVertexNormals(layer.Points, layer.Polygons); layer_index++; } return newObject; }
// LWOB public static Surface ReadSurface5(ChunkReader reader, LightwaveObject obj) { var surf = new Surface(); surf.name = reader.ReadString(); Texture tex = null; LightwavePlugin shdr = null; float[] v = new float[3]; uint flags = 0; // process subchunks as they're encountered while (reader.BytesLeft > 0) { var id = reader.ReadID<SurfaceParameter>(); var sz = reader.ReadUInt16(); sz += (ushort)(sz & 1); using (var subChunkReader = reader.GetSubChunk(sz)) { switch (id) { case SurfaceParameter.ID_COLR: { surf.color.Red = subChunkReader.ReadUInt8() / 255.0f; surf.color.Green = subChunkReader.ReadUInt8() / 255.0f; surf.color.Blue = subChunkReader.ReadUInt8() / 255.0f; break; } case SurfaceParameter.ID_FLAG: { flags = subChunkReader.ReadUInt16(); if ((flags & 4) != 0) surf.smooth = 1.56207f; if ((flags & 8) != 0) surf.color_hilite.value = 1.0f; if ((flags & 16) != 0) surf.color_filter.value = 1.0f; if ((flags & 128) != 0) surf.dif_sharp.value = 0.5f; if ((flags & 256) != 0) surf.sideflags = 3; if ((flags & 512) != 0) surf.add_trans.value = 1.0f; break; } case SurfaceParameter.ID_LUMI: { surf.luminosity.Value = subChunkReader.ReadSInt16() / 256.0f; break; } case SurfaceParameter.ID_VLUM: { surf.luminosity.Value = subChunkReader.ReadSingle(); break; } case SurfaceParameter.ID_DIFF: { surf.diffuse.Value = subChunkReader.ReadSInt16() / 256.0f; break; } case SurfaceParameter.ID_VDIF: { surf.diffuse.Value = subChunkReader.ReadSingle(); break; } case SurfaceParameter.ID_SPEC: { surf.specularity.Value = subChunkReader.ReadSInt16() / 256.0f; break; } case SurfaceParameter.ID_VSPC: { surf.specularity.Value = subChunkReader.ReadSingle(); break; } case SurfaceParameter.ID_GLOS: { surf.glossiness.Value = (float)Math.Log(subChunkReader.ReadUInt16()) / 20.7944f; break; } case SurfaceParameter.ID_SMAN: { surf.smooth = subChunkReader.ReadSingle(); break; } case SurfaceParameter.ID_REFL: { surf.reflection.values.Value = subChunkReader.ReadSInt16() / 256.0f; break; } case SurfaceParameter.ID_RFLT: { surf.reflection.options = subChunkReader.ReadUInt16(); break; } case SurfaceParameter.ID_RIMG: { var s = subChunkReader.ReadString(); surf.reflection.clip_index = AddClip(s, obj.Clips); surf.reflection.options = 3; break; } case SurfaceParameter.ID_RSAN: { surf.reflection.seam_angle = subChunkReader.ReadSingle(); break; } case SurfaceParameter.ID_TRAN: { surf.transparency.values.Value = subChunkReader.ReadSInt16() / 256.0f; break; } case SurfaceParameter.ID_RIND: { surf.eta.Value = subChunkReader.ReadSingle(); break; } case SurfaceParameter.ID_BTEX: { var s = subChunkReader.ReadString(sz);//.getbytes((uint)sz); tex = ParseTexture(s); surf.bump.textures.Add(tex); break; } case SurfaceParameter.ID_CTEX: { var s = subChunkReader.ReadString(sz);//.getbytes((uint)sz); tex = ParseTexture(s); surf.color.textures.Add(tex); break; } case SurfaceParameter.ID_DTEX: { var s = subChunkReader.ReadString(sz);//.getbytes((uint)sz); tex = ParseTexture(s); surf.diffuse.textures.Add(tex); break; } case SurfaceParameter.ID_LTEX: { var s = subChunkReader.ReadString(sz);//.getbytes((uint)sz); tex = ParseTexture(s); surf.luminosity.textures.Add(tex); break; } case SurfaceParameter.ID_RTEX: { var s = subChunkReader.ReadString(sz);//.getbytes((uint)sz); tex = ParseTexture(s); surf.reflection.values.textures.Add(tex); break; } case SurfaceParameter.ID_STEX: { var s = subChunkReader.ReadString(sz);//.getbytes((uint)sz); tex = ParseTexture(s); surf.specularity.textures.Add(tex); break; } case SurfaceParameter.ID_TTEX: { var s = subChunkReader.ReadString(sz);//.getbytes((uint)sz); tex = ParseTexture(s); surf.transparency.values.textures.Add(tex); break; } case SurfaceParameter.ID_TFLG: { if (tex == null) return null; flags = subChunkReader.ReadUInt16(); int i = 0; if ((flags & 1) != 0) i = 0; if ((flags & 2) != 0) i = 1; if ((flags & 4) != 0) i = 2; tex.axis = (ushort)i; if (tex.Type == TextureType.ID_IMAP) tex.imap.axis = i; else tex.proc.axis = i; if ((flags & 8) != 0) tex.tmap.CoordinateSystem = 1; if ((flags & 16) != 0) tex.negative = 1; if ((flags & 32) != 0) tex.imap.pblend = 1; if ((flags & 64) != 0) { tex.imap.aa_strength = 1.0f; tex.imap.aas_flags = 1; } break; } case SurfaceParameter.ID_TSIZ: { tex.tmap.Size.values[0] = subChunkReader.ReadSingle(); tex.tmap.Size.values[1] = subChunkReader.ReadSingle(); tex.tmap.Size.values[2] = subChunkReader.ReadSingle(); break; } case SurfaceParameter.ID_TCTR: { tex.tmap.Center.values[0] = subChunkReader.ReadSingle(); tex.tmap.Center.values[1] = subChunkReader.ReadSingle(); tex.tmap.Center.values[2] = subChunkReader.ReadSingle(); break; } case SurfaceParameter.ID_TFAL: { tex.tmap.FallOff.values[0] = subChunkReader.ReadSingle(); tex.tmap.FallOff.values[1] = subChunkReader.ReadSingle(); tex.tmap.FallOff.values[2] = subChunkReader.ReadSingle(); break; } case SurfaceParameter.ID_TVEL: { for (var i = 0; i < 3; i++) v[i] = subChunkReader.ReadSingle(); tex.tmap.Center.envelope_index = AddTextureVelocity(tex.tmap.Center.values, v, obj.Envelopes); break; } case SurfaceParameter.ID_TCLR: { if (tex.Type == TextureType.ID_PROC) { tex.proc.value_0 = subChunkReader.ReadUInt8() / 255.0f; tex.proc.value_1 = subChunkReader.ReadUInt8() / 255.0f; tex.proc.value_2 = subChunkReader.ReadUInt8() / 255.0f; } break; } case SurfaceParameter.ID_TVAL: { tex.proc.value_0 = subChunkReader.ReadSInt16() / 256.0f; break; } case SurfaceParameter.ID_TAMP: { if (tex.Type == TextureType.ID_IMAP) tex.imap.amplitude.value = subChunkReader.ReadSingle(); break; } case SurfaceParameter.ID_TIMG: { var s = subChunkReader.ReadString(); tex.imap.clip_index = AddClip(s, obj.Clips); break; } case SurfaceParameter.ID_TAAS: { tex.imap.aa_strength = subChunkReader.ReadSingle(); tex.imap.aas_flags = 1; break; } case SurfaceParameter.ID_TREF: { tex.tmap.ReferenceObject = subChunkReader.ReadString((uint)sz);//.getbytes((uint)sz); break; } case SurfaceParameter.ID_TOPC: { tex.opacity.value = subChunkReader.ReadSingle(); break; } case SurfaceParameter.ID_TFP0: { if (tex.Type == TextureType.ID_IMAP) tex.imap.wrapw.value = subChunkReader.ReadSingle(); break; } case SurfaceParameter.ID_TFP1: { if (tex.Type == TextureType.ID_IMAP) tex.imap.wraph.value = subChunkReader.ReadSingle(); break; } case SurfaceParameter.ID_SHDR: { shdr = new LightwavePlugin(); if (shdr == null) return null; shdr.name = subChunkReader.ReadString((uint)sz); surf.shader.Add(shdr); break; } case SurfaceParameter.ID_SDAT: { if (shdr == null) return null; shdr.data = subChunkReader.ReadBytes(sz); break; } default: Console.WriteLine("Unknown surface parameter type " + reader.GetIDString((uint)id)); break; } } } return surf; }
static LightwaveObject ReadObject2(ChunkReader reader) { // allocate an object and a default layer var newObject = new LightwaveObject(); var currentLayer = new Layer(); newObject.Layers.Add(currentLayer); bool createdLayer = false; uint pointOffset = 0; uint polygonOffset = 0; uint tagOffset = 0; // process chunks as they're encountered while (reader.BytesLeft > 0) { var id = reader.ReadID<ChunkType>(); var cksize = reader.ReadUInt32(); cksize += cksize & 1; using (var subchunkReader = reader.GetSubChunk(cksize)) { switch (id) { case ChunkType.ID_LAYR: { if (createdLayer) { currentLayer = new Layer(); newObject.Layers.Add(currentLayer); } createdLayer = true; currentLayer.Index = subchunkReader.ReadUInt16(); currentLayer.Flags = subchunkReader.ReadUInt16(); currentLayer.pivot_x = subchunkReader.ReadSingle(); currentLayer.pivot_y = subchunkReader.ReadSingle(); currentLayer.pivot_z = subchunkReader.ReadSingle(); currentLayer.Name = subchunkReader.ReadString(); if (subchunkReader.BytesLeft > 2) currentLayer.Parent = subchunkReader.ReadUInt16(); break; } case ChunkType.ID_PTAG: { ReadPolygonTags(subchunkReader, currentLayer.Polygons, polygonOffset, tagOffset); break; } case ChunkType.ID_BBOX: { currentLayer.bbox_min_x = subchunkReader.ReadSingle(); currentLayer.bbox_min_y = subchunkReader.ReadSingle(); currentLayer.bbox_min_z = subchunkReader.ReadSingle(); currentLayer.bbox_max_x = subchunkReader.ReadSingle(); currentLayer.bbox_max_y = subchunkReader.ReadSingle(); currentLayer.bbox_max_z = subchunkReader.ReadSingle(); break; } case ChunkType.ID_PNTS: { pointOffset = (uint)currentLayer.Points.Count; currentLayer.Points.AddRange( ReadPoints(subchunkReader) // throws exception on failure ); break; } case ChunkType.ID_POLS: { polygonOffset = (uint)currentLayer.Polygons.Count; currentLayer.Polygons.AddRange( ReadPolygons(subchunkReader, pointOffset) // throws exception on failure ); break; } case ChunkType.ID_VMAP: { currentLayer.VertexMaps.Add( VertexMap.ReadVertexMap(subchunkReader, false) // throws exception on failure ); break; } case ChunkType.ID_VMAD: { currentLayer.VertexMaps.Add( VertexMap.ReadVertexMap(subchunkReader, true) // throws exception on failure ); break; } case ChunkType.ID_TAGS: { tagOffset = (uint)newObject.Tags.Count; newObject.Tags.AddRange( LightwaveObject.ReadTags(subchunkReader) // throws exception on failure ); break; } case ChunkType.ID_ENVL: { newObject.Envelopes.Add( Envelope.ReadEnvelope(subchunkReader) // throws exception on failure ); break; } case ChunkType.ID_CLIP: { newObject.Clips.Add( Clip.ReadClip(subchunkReader) // throws exception on failure ); break; } case ChunkType.ID_SURF: { newObject.Surfaces.Add( Surface.ReadSurface(subchunkReader) // throws exception on failure ); break; } case ChunkType.ID_DESC: // Description Line - DESC { description-line[S0] } case ChunkType.ID_TEXT: // Commentary Text - TEXT { comment[S0] } case ChunkType.ID_ICON: // Thumbnail Icon Image - ICON { encoding[U2], width[U2], data[U1] * } case ChunkType.ID_VMPA: // Vertex Map Parameter - VMPA { UV subdivision type[I4], sketch color[I4] } break; default: Console.WriteLine("Unknown chunk type " + reader.GetIDString((uint)id)); break; } } } if (newObject.Tags.Count == 0) throw new Exception("No tags found for this layer"); // TODO: create a proper exception class uint layer_index = 0; foreach (var layer in newObject.Layers) { layer.CalculateBoundingBox(); newObject.CalculatePolygonNormals(layer.Points, layer.Polygons); newObject.ResolvePointPolygons(layer.Points, layer.Polygons); newObject.ResolvePolygonSurfaces(layer.Polygons, newObject.Tags, newObject.Surfaces, layer_index); newObject.CalculateVertexNormals(layer.Points, layer.Polygons); newObject.ResolvePointVertexMaps(layer.Points, layer.VertexMaps); newObject.ResolvePolygonVertexMaps(layer.Polygons, layer.VertexMaps); layer_index++; } return newObject; }