public static Clip ReadClip(ChunkReader reader) { // index var index = reader.ReadUInt32(); // first subchunk header var type = reader.ReadID<ClipType>(); var subchunk_size = reader.ReadUInt16(); subchunk_size += (ushort)(subchunk_size & 1); Clip clip = null; using (var subChunkReader = reader.GetSubChunk(subchunk_size)) { switch (type) { case ClipType.ID_STIL: { var tmp_clip = new ClipStill(index); tmp_clip.Name = subChunkReader.ReadString(); clip = tmp_clip; break; } case ClipType.ID_ISEQ: { var tmp_clip = new ClipSequence(index); tmp_clip.Digits = subChunkReader.ReadUInt8(); tmp_clip.Flags = subChunkReader.ReadUInt8(); tmp_clip.Offset = subChunkReader.ReadSInt16(); subChunkReader.ReadUInt16(); // Legacy Cruft: Nothing to see here tmp_clip.Start = subChunkReader.ReadSInt16(); tmp_clip.End = subChunkReader.ReadSInt16(); tmp_clip.Prefix = subChunkReader.ReadString(); tmp_clip.Suffix = subChunkReader.ReadString(); clip = tmp_clip; break; } case ClipType.ID_ANIM: { var tmp_clip = new ClipAnim(index); tmp_clip.Name = subChunkReader.ReadString(); tmp_clip.Server = subChunkReader.ReadString(); tmp_clip.Data = subChunkReader.ReadBytes((uint)subChunkReader.BytesLeft); clip = tmp_clip; break; } case ClipType.ID_XREF: { var tmp_clip = new ClipCloned(index); tmp_clip.clip_reference_index = subChunkReader.ReadUInt32(); tmp_clip.Name = subChunkReader.ReadString(); clip = tmp_clip; break; } case ClipType.ID_STCC: { var tmp_clip = new ClipColorCycle(index); tmp_clip.lo = subChunkReader.ReadSInt16(); tmp_clip.hi = subChunkReader.ReadSInt16(); tmp_clip.Name = subChunkReader.ReadString(); clip = tmp_clip; break; } default: throw new Exception("Unknown Clip type"); // TODO: create proper exception class for this ... } } while (reader.BytesLeft > 0) { // process subchunks as they're encountered var id = reader.ReadID<ClipDataType>(); subchunk_size = reader.ReadUInt16(); subchunk_size += (ushort)(subchunk_size & 1); using (var subChunkReader = reader.GetSubChunk(subchunk_size)) { switch (id) { //case ClipDataType.ID_CLRS: // Color Space RGB - CLRS { flags[U2], colorspace[U2], filename[FNAM0] } //case ClipDataType.ID_CLRA: // Color Space Alpha - CLRA { flags[U2], colorspace[U2], filename[FNAM0] } //case ClipDataType.ID_FILT: // Image Filtering - FILT { flags[U2] } //case ClipDataType.ID_DITH: // Image Dithering - DITH { flags[U2] } // Contrast - CONT { contrast-delta[FP4], envelope[VX] } case ClipDataType.ID_CONT: { clip.Contrast.value = subChunkReader.ReadSingle(); clip.Contrast.envelope_index = subChunkReader.ReadVariableLengthIndex(); break; } // Brightness - BRIT { brightness-delta[FP4], envelope[VX] } case ClipDataType.ID_BRIT: { clip.Brightness.value = subChunkReader.ReadSingle(); clip.Brightness.envelope_index = subChunkReader.ReadVariableLengthIndex(); break; } // Saturation - SATR { saturation-delta[FP4], envelope[VX] } case ClipDataType.ID_SATR: { clip.Saturation.value = subChunkReader.ReadSingle(); clip.Saturation.envelope_index = subChunkReader.ReadVariableLengthIndex(); break; } // Hue - HUE { hue-rotation[FP4], envelope[VX] } case ClipDataType.ID_HUE: { clip.Hue.value = subChunkReader.ReadSingle(); clip.Hue.envelope_index = subChunkReader.ReadVariableLengthIndex(); break; } // Gamma Correction - GAMM { gamma[F4], envelope[VX] } case ClipDataType.ID_GAMM: { clip.Gamma.value = subChunkReader.ReadSingle(); clip.Gamma.envelope_index = subChunkReader.ReadVariableLengthIndex(); break; } // Negative - NEGA { enable[U2] } case ClipDataType.ID_NEGA: { clip.Negative = subChunkReader.ReadUInt16() != 0; break; } // Time - TIME { start-time[FP4], duration[FP4], frame-rate[FP4] } case ClipDataType.ID_TIME: { clip.StartTime = subChunkReader.ReadSingle(); clip.Duration = subChunkReader.ReadSingle(); clip.FrameRate = subChunkReader.ReadSingle(); break; } // Plug-in Image Filters - IFLT { server-name[S0], flags[U2], data[...] } case ClipDataType.ID_IFLT: // Plug-in Pixel Filters - PFLT { server-name[S0], flags[U2], data[...] } case ClipDataType.ID_PFLT: { var filt = new LightwavePlugin(); filt.name = subChunkReader.ReadString(); filt.flags = subChunkReader.ReadUInt16(); filt.data = subChunkReader.ReadBytes((uint)subChunkReader.BytesLeft); if (id == ClipDataType.ID_IFLT) clip.ImageFilters.Add(filt); else clip.PixelFilters.Add(filt); break; } case ClipDataType.ID_FLAG: // not mentioned in documentation ... var flags = subChunkReader.ReadUInt16(); // unknown what they mean ... break; default: Console.WriteLine("Unknown clip type " + reader.GetIDString((uint)id)); break; } } } return clip; }
public static Envelope ReadEnvelope(ChunkReader reader) { var env = new Envelope(); // allocate the Envelope structure env.Index = reader.ReadVariableLengthIndex(); // index EnvelopeKey lastKey = null; while (reader.BytesLeft > 0) { // process subchunks as they're encountered var id = reader.ReadID<EnvelopeType>(); var sz = reader.ReadUInt16(); sz += (ushort)(sz & 1); using (var subChunkReader = reader.GetSubChunk(sz)) { switch (id) { case EnvelopeType.ID_TYPE: { env.Type = subChunkReader.ReadUInt16(); break; } case EnvelopeType.ID_NAME: { env.Name = subChunkReader.ReadString(); break; } case EnvelopeType.ID_PRE: { env.PreBehavior = (EvalType)subChunkReader.ReadUInt16(); break; } case EnvelopeType.ID_POST: { env.PostBehavior = (EvalType)subChunkReader.ReadUInt16(); break; } case EnvelopeType.ID_KEY: { lastKey = new EnvelopeKey( subChunkReader.ReadSingle(), // time subChunkReader.ReadSingle() // value ); env.Keys.Add(lastKey); //TODO: not sort all the time env.Keys.Sort((Comparison<EnvelopeKey>)delegate(EnvelopeKey k1, EnvelopeKey k2) { return k1.Time > k2.Time ? 1 : k1.Time < k2.Time ? -1 : 0; }); break; } case EnvelopeType.ID_SPAN: { if (lastKey == null) // We should've encountered an ID_KEY before an ID_SPAN throw new Exception("Key not defined"); //TODO: make proper exception class lastKey.Shape = subChunkReader.ReadID<KeyShape>(); switch (lastKey.Shape) { case KeyShape.ID_TCB: { lastKey.Tension = subChunkReader.ReadSingle(); lastKey.Continuity = subChunkReader.ReadSingle(); lastKey.Bias = subChunkReader.ReadSingle(); break; } case KeyShape.ID_BEZI: case KeyShape.ID_HERM: case KeyShape.ID_BEZ2: { Array.Clear(lastKey.param, 0, lastKey.param.Length); int i = 0; while (i < 4 && subChunkReader.BytesLeft > 0) { lastKey.param[i] = subChunkReader.ReadSingle(); i++; } break; } case KeyShape.ID_LINE: break; default: Console.WriteLine("Unknown envelope span shape type " + reader.GetIDString((uint)lastKey.Shape)); break; } break; } case EnvelopeType.ID_CHAN: { var plug = new LightwavePlugin(); plug.name = subChunkReader.ReadString(); plug.flags = subChunkReader.ReadUInt16(); plug.data = subChunkReader.ReadBytes((uint)reader.BytesLeft); env.ChannelFilters.Add(plug); break; } default: Console.WriteLine("Unknown envelope type " + reader.GetIDString((uint)id)); break; } } } return env; }
public static TextureMap ReadTextureMap(ChunkReader reader) { var tmap = new TextureMap(); while (reader.BytesLeft > 0) { var id = reader.ReadID<TextureCoordinates>(); var sz = reader.ReadUInt16(); sz += (ushort)(sz & 1); using (var subChunkReader = reader.GetSubChunk(sz)) { switch (id) { case TextureCoordinates.ID_SIZE: tmap.Size.values[0] = subChunkReader.ReadSingle(); tmap.Size.values[1] = subChunkReader.ReadSingle(); tmap.Size.values[2] = subChunkReader.ReadSingle(); tmap.Size.envelope_index = subChunkReader.ReadVariableLengthIndex(); break; case TextureCoordinates.ID_CNTR: tmap.Size.values[0] = subChunkReader.ReadSingle(); tmap.Size.values[1] = subChunkReader.ReadSingle(); tmap.Size.values[2] = subChunkReader.ReadSingle(); tmap.Center.envelope_index = subChunkReader.ReadVariableLengthIndex(); break; case TextureCoordinates.ID_ROTA: tmap.Size.values[0] = subChunkReader.ReadSingle(); tmap.Size.values[1] = subChunkReader.ReadSingle(); tmap.Size.values[2] = subChunkReader.ReadSingle(); tmap.Rotate.envelope_index = subChunkReader.ReadVariableLengthIndex(); break; case TextureCoordinates.ID_FALL: tmap.FallType = subChunkReader.ReadUInt16(); tmap.Size.values[0] = subChunkReader.ReadSingle(); tmap.Size.values[1] = subChunkReader.ReadSingle(); tmap.Size.values[2] = subChunkReader.ReadSingle(); tmap.FallOff.envelope_index = subChunkReader.ReadVariableLengthIndex(); break; case TextureCoordinates.ID_OREF: tmap.ReferenceObject = subChunkReader.ReadString(); break; case TextureCoordinates.ID_CSYS: tmap.CoordinateSystem = subChunkReader.ReadUInt16(); break; default: Console.WriteLine("Unknown texture map type " + reader.GetIDString((uint)id)); break; } } } return tmap; }
public static VertexMap ReadVertexMap(ChunkReader reader, bool perpoly) { var type = reader.ReadID<VertexMapType>(); var dimensions = reader.ReadUInt16(); var name = reader.ReadString(); var vertex_map = new VertexMap(type, name, perpoly); var vertex_indices = new List<uint>(); var polygon_indices = new List<uint>(); var values = new List<float[]>(); // fill in the vertex-map values while (reader.BytesLeft > 0) { vertex_indices.Add(reader.ReadVariableLengthIndex()); if (perpoly) polygon_indices.Add(reader.ReadVariableLengthIndex()); var pointValues = new float[dimensions]; for (var j = 0; j < dimensions; j++) pointValues[j] = reader.ReadSingle(); values.Add(pointValues); } vertex_map.Values = values.ToArray(); vertex_map.vertex_index = vertex_indices.ToArray(); if (perpoly) vertex_map.polygon_index = polygon_indices.ToArray(); return vertex_map; }
bool ReadImageMap(ChunkReader reader) { while (reader.BytesLeft > 0) { // get the next subchunk header var id = reader.ReadID<ImageMapType>(); var sz = reader.ReadUInt16(); sz += (ushort)(sz & 1); using (var subChunkReader = reader.GetSubChunk(sz)) { switch (id) { case ImageMapType.ID_TMAP: { tmap = TextureMap.ReadTextureMap(subChunkReader); break; } case ImageMapType.ID_PROJ: imap.projection = (ProjectionType)subChunkReader.ReadUInt16(); break; case ImageMapType.ID_VMAP: imap.vertex_map_name = subChunkReader.ReadString(); break; case ImageMapType.ID_AXIS: imap.axis = subChunkReader.ReadUInt16(); break; case ImageMapType.ID_IMAG: imap.clip_index = subChunkReader.ReadVariableLengthIndex(); break; case ImageMapType.ID_PIXB: imap.pblend = subChunkReader.ReadUInt16(); break; case ImageMapType.ID_WRAP: imap.wrapw_type = (WrapType)subChunkReader.ReadUInt16(); imap.wraph_type = (WrapType)subChunkReader.ReadUInt16(); break; case ImageMapType.ID_WRPW: imap.wrapw.value = subChunkReader.ReadSingle(); imap.wrapw.envelope_index = subChunkReader.ReadVariableLengthIndex(); break; case ImageMapType.ID_WRPH: imap.wraph.value = subChunkReader.ReadSingle(); imap.wraph.envelope_index = subChunkReader.ReadVariableLengthIndex(); break; case ImageMapType.ID_AAST: imap.aas_flags = subChunkReader.ReadUInt16(); imap.aa_strength = subChunkReader.ReadSingle(); break; case ImageMapType.ID_STCK: imap.stck.value = subChunkReader.ReadSingle(); imap.stck.envelope_index = subChunkReader.ReadVariableLengthIndex(); break; case ImageMapType.ID_TAMP: imap.amplitude.value = subChunkReader.ReadSingle(); imap.amplitude.envelope_index = subChunkReader.ReadVariableLengthIndex(); break; default: Console.WriteLine("Unknown image map type " + reader.GetIDString((uint)id)); break; } } } return true; }
bool ReadProcedural(ChunkReader reader) { while (reader.BytesLeft > 0) { var id = reader.ReadID<ProceduralType>(); var sz = reader.ReadUInt16(); sz += (ushort)(sz & 1); using (var subChunkReader = reader.GetSubChunk(sz)) { switch (id) { case ProceduralType.ID_TMAP: { tmap = TextureMap.ReadTextureMap(subChunkReader); break; } case ProceduralType.ID_AXIS: { proc.axis = subChunkReader.ReadUInt16(); break; } case ProceduralType.ID_VALU: { proc.value_0 = subChunkReader.ReadSingle(); if (sz >= 8) proc.value_1 = subChunkReader.ReadSingle(); if (sz >= 12) proc.value_2 = subChunkReader.ReadSingle(); break; } case ProceduralType.ID_FUNC: { proc.name = subChunkReader.ReadString(); proc.data = subChunkReader.ReadBytes((uint)subChunkReader.BytesLeft); break; } default: Console.WriteLine("Unknown procedural map type " + reader.GetIDString((uint)id)); break; } } } return true; }
// 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; }
bool ReadGradient(ChunkReader reader) { while (reader.BytesLeft > 0) { var id = reader.ReadID<GradientType>(); var sz = reader.ReadUInt16(); sz += (ushort)(sz & 1); using (var subChunkReader = reader.GetSubChunk(sz)) { switch (id) { case GradientType.ID_TMAP: { tmap = TextureMap.ReadTextureMap(subChunkReader); break; } case GradientType.ID_PNAM: { grad.paramname = subChunkReader.ReadString(); break; } case GradientType.ID_INAM: { grad.itemname = subChunkReader.ReadString(); break; } case GradientType.ID_GRST: { grad.start = subChunkReader.ReadSingle(); break; } case GradientType.ID_GREN: { grad.end = subChunkReader.ReadSingle(); break; } case GradientType.ID_GRPT: { grad.repeat = subChunkReader.ReadUInt16(); break; } case GradientType.ID_FKEY: { var keys = new List<GradientKey>(); while (subChunkReader.BytesLeft > 0) { var key = new GradientKey(); key.value = subChunkReader.ReadSingle(); key.rgba_0 = subChunkReader.ReadSingle(); key.rgba_1 = subChunkReader.ReadSingle(); key.rgba_2 = subChunkReader.ReadSingle(); key.rgba_3 = subChunkReader.ReadSingle(); keys.Add(key); } grad.Keys = keys.ToArray(); break; } case GradientType.ID_IKEY: { var ikeys = new List<ushort>(); while (subChunkReader.BytesLeft > 0) ikeys.Add(subChunkReader.ReadUInt16()); grad.ikey = ikeys.ToArray(); break; } case GradientType.ID_GVER: // unknown, not mentioned in lightwave sdk documentation break; default: Console.WriteLine("Unknown gradient type " + reader.GetIDString((uint)id)); break; } } } return true; }
public static LightwavePlugin ReadShader(ChunkReader reader) { var shader = new LightwavePlugin(); var hsz = reader.ReadUInt16(); // Q: example code does this, but can't find this in documentation? shader.ord = reader.ReadString(); using (var headerReader = reader.GetSubChunk(hsz)) { while (headerReader.BytesLeft > 0) { var id = headerReader.ReadID<PluginType>(); var sz = headerReader.ReadUInt16(); sz += (ushort)(sz & 1); hsz -= sz; if (id == PluginType.ID_ENAB) { shader.flags = headerReader.ReadUInt16(); break; } } } while (reader.BytesLeft > 0) { var id = reader.ReadID<PluginType>(); var sz = reader.ReadUInt16(); sz += (ushort)(sz & 1); using (var subChunkReader = reader.GetSubChunk(sz)) { switch (id) { case PluginType.ID_FUNC: { shader.name = subChunkReader.ReadString(); shader.data = subChunkReader.ReadBytes((uint)subChunkReader.BytesLeft); break; } default: //Console.WriteLine("Unknown shader type " + reader.GetIDString((uint)id)); break; } } } return shader; }
public static Surface ReadSurface(ChunkReader reader) { // allocate the Surface structure var surf = new Surface(); // names surf.name = reader.ReadString(); surf.srcname = reader.ReadString(); // 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) { // Vertex Color Map - VCOL { intensity[FP4], envelope[VX], vmap-type[ID4], name[S0] } // The vertex color map subchunk identifies an RGB or RGBA VMAP that will be used to color the surface case SurfaceParameter.ID_VCOL: { var intensity = subChunkReader.ReadSingle(); var envelope_index = subChunkReader.ReadVariableLengthIndex(); var vmap_type = subChunkReader.ReadUInt32(); var name = subChunkReader.ReadString(); break; } case SurfaceParameter.ID_CMNT: // Not mentioned in LWO documentation, maybe means 'comment'? { break; } case SurfaceParameter.ID_VERS: // Not mentioned in LWO documentation, maybe means 'version'? { break; } case SurfaceParameter.ID_NODS: // Not mentioned in LWO documentation, maybe means 'nodes'? { break; } case SurfaceParameter.ID_COLR: { surf.color.Red = subChunkReader.ReadSingle(); surf.color.Green = subChunkReader.ReadSingle(); surf.color.Blue = subChunkReader.ReadSingle(); surf.color.envelope_index = subChunkReader.ReadVariableLengthIndex(); break; } case SurfaceParameter.ID_LUMI: surf.luminosity.Value = subChunkReader.ReadSingle(); surf.luminosity.envelope_index = subChunkReader.ReadVariableLengthIndex(); break; case SurfaceParameter.ID_DIFF: surf.diffuse.Value = subChunkReader.ReadSingle(); surf.diffuse.envelope_index = subChunkReader.ReadVariableLengthIndex(); break; case SurfaceParameter.ID_SPEC: surf.specularity.Value = subChunkReader.ReadSingle(); surf.specularity.envelope_index = subChunkReader.ReadVariableLengthIndex(); break; case SurfaceParameter.ID_GLOS: surf.glossiness.Value = subChunkReader.ReadSingle(); surf.glossiness.envelope_index = subChunkReader.ReadVariableLengthIndex(); break; case SurfaceParameter.ID_REFL: surf.reflection.values.Value = subChunkReader.ReadSingle(); surf.reflection.values.envelope_index = subChunkReader.ReadVariableLengthIndex(); break; case SurfaceParameter.ID_RFOP: surf.reflection.options = subChunkReader.ReadUInt16(); break; case SurfaceParameter.ID_RIMG: surf.reflection.clip_index = subChunkReader.ReadVariableLengthIndex(); break; // Reflection Blurring - RBLR { blur-percentage[FP4], envelope[VX] } // The amount of blurring of reflections. The default is zero. case SurfaceParameter.ID_RBLR: break; case SurfaceParameter.ID_RSAN: surf.reflection.seam_angle = subChunkReader.ReadSingle(); break; case SurfaceParameter.ID_TRAN: surf.transparency.values.Value = subChunkReader.ReadSingle(); surf.transparency.values.envelope_index = subChunkReader.ReadVariableLengthIndex(); break; case SurfaceParameter.ID_TROP: surf.transparency.options = subChunkReader.ReadUInt16(); break; case SurfaceParameter.ID_TIMG: surf.transparency.clip_index = subChunkReader.ReadVariableLengthIndex(); break; case SurfaceParameter.ID_RIND: surf.eta.Value = subChunkReader.ReadSingle(); surf.eta.envelope_index = subChunkReader.ReadVariableLengthIndex(); break; case SurfaceParameter.ID_TRNL: surf.translucency.Value = subChunkReader.ReadSingle(); surf.translucency.envelope_index = subChunkReader.ReadVariableLengthIndex(); break; case SurfaceParameter.ID_BUMP: surf.bump.Value = subChunkReader.ReadSingle(); surf.bump.envelope_index = subChunkReader.ReadVariableLengthIndex(); break; case SurfaceParameter.ID_SMAN: surf.smooth = subChunkReader.ReadSingle(); break; case SurfaceParameter.ID_SIDE: surf.sideflags = subChunkReader.ReadUInt16(); break; case SurfaceParameter.ID_CLRH: surf.color_hilite.value = subChunkReader.ReadSingle(); surf.color_hilite.envelope_index = subChunkReader.ReadVariableLengthIndex(); break; case SurfaceParameter.ID_CLRF: surf.color_filter.value = subChunkReader.ReadSingle(); surf.color_filter.envelope_index = subChunkReader.ReadVariableLengthIndex(); break; case SurfaceParameter.ID_ADTR: surf.add_trans.value = subChunkReader.ReadSingle(); surf.add_trans.envelope_index = subChunkReader.ReadVariableLengthIndex(); break; case SurfaceParameter.ID_SHRP: surf.dif_sharp.value = subChunkReader.ReadSingle(); surf.dif_sharp.envelope_index = subChunkReader.ReadVariableLengthIndex(); break; case SurfaceParameter.ID_GVAL: surf.glow.value = subChunkReader.ReadSingle(); surf.glow.envelope_index = subChunkReader.ReadVariableLengthIndex(); break; // Render Outlines - LINE { flags[U2], ( size[F4], size-envelope[VX], ( color[COL12], color-envelope[VX] )? )? } case SurfaceParameter.ID_LINE: surf.line.enabled = 1; if (sz >= 2) surf.line.flags = subChunkReader.ReadUInt16(); if (sz >= 6) surf.line.size.value = subChunkReader.ReadSingle(); if (sz >= 8) surf.line.size.envelope_index = subChunkReader.ReadVariableLengthIndex(); break; case SurfaceParameter.ID_ALPH: surf.alpha_mode = subChunkReader.ReadUInt16(); surf.alpha = subChunkReader.ReadSingle(); break; case SurfaceParameter.ID_AVAL: surf.alpha = subChunkReader.ReadSingle(); break; case SurfaceParameter.ID_BLOK: { var type = subChunkReader.ReadID<TextureType>(); switch (type) { case TextureType.ID_IMAP: case TextureType.ID_PROC: case TextureType.ID_GRAD: { using (var blockReader = subChunkReader.GetSubChunk((uint)subChunkReader.BytesLeft)) { var tex = Texture.ReadTexture(blockReader, type); switch ( tex.Channel ) { case TextureChannel.ID_COLR: surf.color .textures.Add(tex); break; case TextureChannel.ID_LUMI: surf.luminosity .textures.Add(tex); break; case TextureChannel.ID_DIFF: surf.diffuse .textures.Add(tex); break; case TextureChannel.ID_SPEC: surf.specularity .textures.Add(tex); break; case TextureChannel.ID_GLOS: surf.glossiness .textures.Add(tex); break; case TextureChannel.ID_REFL: surf.reflection .values .textures.Add(tex); break; case TextureChannel.ID_TRAN: surf.transparency .values .textures.Add(tex); break; case TextureChannel.ID_RIND: surf.eta .textures.Add(tex); break; case TextureChannel.ID_TRNL: surf.translucency .textures.Add(tex); break; case TextureChannel.ID_BUMP: surf.bump .textures.Add(tex); break; default: throw new Exception("Unknown texture channel"); // TODO: create proper exception calass for this } } break; } case TextureType.ID_SHDR: { using (var blockReader = subChunkReader.GetSubChunk((uint)subChunkReader.BytesLeft)) { surf.shader.Add( LightwavePlugin.ReadShader(blockReader) ); } break; } default: Console.WriteLine("Unknown blok type " + reader.GetIDString((uint)type)); break; } break; } default: Console.WriteLine("Unknown surface parameter type " + reader.GetIDString((uint)id)); break; } } } return surf; }
static void ReadPolygonTags(ChunkReader reader, List<Polygon> polygons, uint polygon_offset, uint tag_offset) { var type = reader.ReadID<PolygonTags>(); if (type != PolygonTags.ID_SURF && type != PolygonTags.ID_PART && type != PolygonTags.ID_SMGP) { if (type != PolygonTags.ID_COLR && // 'Sketch Color Name'? type != PolygonTags.ID_LXGN) // unknown Console.WriteLine("Unknown polygon tag type " + reader.GetIDString((uint)type)); return; } while (reader.BytesLeft > 0) { var polygonIndex = (int)(reader.ReadVariableLengthIndex() + polygon_offset); var tagIndex = (int)(reader.ReadVariableLengthIndex() + tag_offset); switch (type) { case PolygonTags.ID_SURF: polygons[polygonIndex].surf_index = (uint)tagIndex; break; case PolygonTags.ID_PART: polygons[polygonIndex].part_index = (uint)tagIndex; break; case PolygonTags.ID_SMGP: polygons[polygonIndex].SmoothingGroup = (int)tagIndex; break; default: Console.WriteLine("Unknown polygon tag type " + reader.GetIDString((uint)type)); break; } } }
static IEnumerable<Polygon> ReadPolygons(ChunkReader reader, uint vertex_offset) { var type = reader.ReadID<PolygonType>(); // fill in the new polygons while (reader.BytesLeft > 0) { var vertex_count = reader.ReadUInt16(); var flags = vertex_count & 0xFC00; vertex_count &= 0x03FF; var newPolygon = new Polygon(type, flags); for (var j = 0; j < vertex_count; j++) newPolygon.Vertices.Add( new PolygonVertex(reader.ReadVariableLengthIndex() + vertex_offset) ); yield return newPolygon; } }
// 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; }
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; }
public static LightwaveObject LoadObject(string filename) { // open the file var contents = File.ReadAllBytes(filename); using (var reader = new ChunkReader(contents)) { // read the first 12 bytes var id = reader.ReadID<HeaderID>(); var formsize = reader.ReadUInt32(); var type = reader.ReadID<ObjectType>(); if (id != HeaderID.ID_FORM) // is this a LW object? return null; using (var formReader = reader.GetSubChunk(formsize)) { switch (type) { case ObjectType.ID_LWO2: return ReadObject2(formReader); case ObjectType.ID_LWOB: return ReadObject5(formReader); default: Console.WriteLine("Unknown object type " + reader.GetIDString((uint)type)); return null; } } } }