protected override SolidMeshVertex GetVertex(BinaryReader reader, SolidObjectMaterial material, int stride) { SolidMeshVertex vertex; switch (stride) { case 60: vertex = new SolidMeshVertex { Position = BinaryUtil.ReadVector3(reader), Normal = BinaryUtil.ReadVector3(reader), Color = reader.ReadUInt32(), TexCoords = BinaryUtil.ReadVector2(reader), BlendWeight = BinaryUtil.ReadVector3(reader), BlendIndices = BinaryUtil.ReadVector3(reader), }; break; // position (12 bytes) + normal (12 bytes) + color (4 bytes) + tex coords (8 bytes) case 36: vertex = new SolidMeshVertex { Position = BinaryUtil.ReadVector3(reader), Normal = BinaryUtil.ReadVector3(reader), Color = reader.ReadUInt32(), TexCoords = BinaryUtil.ReadVector2(reader) }; break; // position (12 bytes) + color (4 bytes) + tex coords (8 bytes) case 24: vertex = new SolidMeshVertex { Position = BinaryUtil.ReadVector3(reader), Color = reader.ReadUInt32(), TexCoords = BinaryUtil.ReadVector2(reader) }; break; default: throw new Exception($"Cannot handle vertex size: {stride}"); } return(vertex); }
protected override SolidMeshVertex GetVertex(BinaryReader reader, SolidObjectMaterial material, int stride) { MostWantedMaterial mwm = (MostWantedMaterial)material; SolidMeshVertex vertex = new SolidMeshVertex(); InternalEffectID id = (InternalEffectID)mwm.EffectId; switch (id) { case InternalEffectID.WorldNormalMap: case InternalEffectID.WorldReflectShader: vertex.Position = BinaryUtil.ReadVector3(reader); vertex.Normal = BinaryUtil.ReadVector3(reader); vertex.Color = reader.ReadUInt32(); vertex.TexCoords = BinaryUtil.ReadVector2(reader); reader.BaseStream.Position += 8; // TODO: What's this additional D3DDECLUSAGE_TEXCOORD element? vertex.Tangent = BinaryUtil.ReadVector3(reader); reader.BaseStream.Position += 4; // skip W component of tangent vector break; case InternalEffectID.skyshader: vertex.Position = BinaryUtil.ReadVector3(reader); vertex.Normal = BinaryUtil.ReadVector3(reader); vertex.Color = reader.ReadUInt32(); vertex.TexCoords = BinaryUtil.ReadVector2(reader); reader.BaseStream.Position += 8; // TODO: What's this additional D3DDECLUSAGE_TEXCOORD element? break; case InternalEffectID.WorldShader: case InternalEffectID.GlossyWindow: case InternalEffectID.billboardshader: case InternalEffectID.CarShader: vertex.Position = BinaryUtil.ReadVector3(reader); vertex.Normal = BinaryUtil.ReadVector3(reader); vertex.Color = reader.ReadUInt32(); vertex.TexCoords = BinaryUtil.ReadVector2(reader); break; default: throw new Exception($"Unsupported effect in object {Name}: {id}"); } return(vertex); }
/// <summary> /// Read a vertex for a material from a binary stream. /// </summary> /// <param name="reader"></param> /// <param name="material"></param> /// <param name="stride"></param> /// <returns></returns> protected abstract SolidMeshVertex GetVertex(BinaryReader reader, SolidObjectMaterial material, int stride);
protected override SolidMeshVertex GetVertex(BinaryReader reader, SolidObjectMaterial material, int stride) { World15Material wm = (World15Material)material; SolidMeshVertex vertex = new SolidMeshVertex(); InternalEffectID id = (InternalEffectID)wm.EffectId; switch (id) { case InternalEffectID.WorldShader: case InternalEffectID.GLASS_REFLECT: case InternalEffectID.WorldZBiasShader: case InternalEffectID.Tree: case InternalEffectID.WATER: vertex.Position = BinaryUtil.ReadVector3(reader); vertex.Normal = BinaryUtil.ReadNormal(reader, true); vertex.TexCoords = BinaryUtil.ReadVector2(reader); vertex.Color = reader.ReadUInt32(); // daytime color reader.ReadUInt32(); // nighttime color break; case InternalEffectID.WorldPrelitShader: vertex.Position = BinaryUtil.ReadVector3(reader); vertex.Color = reader.ReadUInt32(); // daytime color reader.ReadUInt32(); // nighttime color vertex.TexCoords = BinaryUtil.ReadVector2(reader); break; case InternalEffectID.WorldZBiasPrelitShader: vertex.Position = BinaryUtil.ReadVector3(reader); vertex.Normal = BinaryUtil.ReadNormal(reader, true); vertex.Color = reader.ReadUInt32(); // daytime color reader.ReadUInt32(); // nighttime color vertex.TexCoords = BinaryUtil.ReadVector2(reader); break; case InternalEffectID.WorldNormalMap: case InternalEffectID.GLASS_REFLECTNM: case InternalEffectID.WorldRoadShader: case InternalEffectID.WorldFEShader: vertex.Position = BinaryUtil.ReadVector3(reader); vertex.Normal = BinaryUtil.ReadNormal(reader, true); vertex.TexCoords = BinaryUtil.ReadVector2(reader); vertex.Color = reader.ReadUInt32(); // daytime color reader.ReadUInt32(); // nighttime color vertex.Tangent = BinaryUtil.ReadNormal(reader, true); break; case InternalEffectID.CarShader: case InternalEffectID.CARNORMALMAP: vertex.Position = BinaryUtil.ReadNormal(reader, true) * 8; vertex.TexCoords = new Vector2(reader.ReadInt16() / 4096f, reader.ReadInt16() / 4096f - 1); vertex.Color = reader.ReadUInt32(); vertex.Normal = BinaryUtil.ReadNormal(reader, true); vertex.Tangent = BinaryUtil.ReadNormal(reader, true); break; default: throw new Exception($"Unsupported effect in object {Name}: {id}"); } return(vertex); }
/// <inheritdoc /> /// <summary> /// This thing is responsible for somehow deriving proper vertex data from /// a NFS:Undercover vertex buffer. Getting the coordinates is easy, but /// the hard part is getting the texture coordinates. Can it be done? Who knnows? /// </summary> /// <remarks>And I didn't even mention the fact that there are wayyyy too many edge cases...</remarks> /// <remarks>I hate this game. Worse than E.T.</remarks> /// <param name="reader"></param> /// <param name="material"></param> /// <param name="stride"></param> /// <returns></returns> protected override SolidMeshVertex GetVertex(BinaryReader reader, SolidObjectMaterial material, int stride) { var effectId = ((UndercoverMaterial)material).EffectId; SolidMeshVertex vertex = new SolidMeshVertex(); switch (effectId) { case EffectID.mw2_constant: case EffectID.mw2_constant_alpha_bias: case EffectID.mw2_illuminated: case EffectID.mw2_pano: vertex.Position = BinaryUtil.ReadVector3(reader); reader.ReadSingle(); vertex.TexCoords = BinaryUtil.ReadShort2N(reader) * 32; break; case EffectID.mw2_matte: case EffectID.mw2_diffuse_spec: case EffectID.mw2_branches: case EffectID.mw2_glass_no_n: case EffectID.mw2_diffuse_spec_illum: case EffectID.diffuse_spec_2sided: case EffectID.mw2_combo_refl: case EffectID.mw2_dirt: case EffectID.mw2_grass: case EffectID.mw2_tunnel_illum: case EffectID.mw2_diffuse_spec_alpha: case EffectID.mw2_trunk: vertex.Position = BinaryUtil.ReadVector3(reader); reader.ReadSingle(); vertex.Color = reader.ReadUInt32(); vertex.TexCoords = BinaryUtil.ReadShort2N(reader) * 32; vertex.Normal = BinaryUtil.ReadNormal(reader, true); break; case EffectID.mw2_normalmap: case EffectID.mw2_normalmap_bias: case EffectID.mw2_glass_refl: case EffectID.normalmap2sided: case EffectID.mw2_road_overlay: case EffectID.mw2_road_refl_overlay: case EffectID.mw2_rock: vertex.Position = BinaryUtil.ReadVector3(reader); reader.ReadSingle(); vertex.Color = reader.ReadUInt32(); vertex.TexCoords = BinaryUtil.ReadShort2N(reader) * 32; vertex.Normal = BinaryUtil.ReadNormal(reader, true); // todo: read packed tangent vector reader.BaseStream.Position += 0x8; break; case EffectID.mw2_grass_rock: case EffectID.mw2_road_refl: case EffectID.mw2_road_refl_tile: case EffectID.mw2_road_tile: case EffectID.mw2_dirt_rock: vertex.Position = BinaryUtil.ReadVector3(reader); reader.ReadSingle(); vertex.Color = reader.ReadUInt32(); vertex.TexCoords = BinaryUtil.ReadShort2N(reader) * 32; // TODO: TEXCOORD1??? what do we do with this? reader.ReadInt16(); reader.ReadInt16(); vertex.Normal = BinaryUtil.ReadNormal(reader, true); // todo: read packed tangent vector reader.BaseStream.Position += 0x8; break; case EffectID.mw2_tunnel_road: vertex.Position = BinaryUtil.ReadVector3(reader); reader.ReadSingle(); vertex.Color = reader.ReadUInt32(); vertex.TexCoords = BinaryUtil.ReadShort2N(reader) * 32; // TODO: TEXCOORD1??? what do we do with this? reader.ReadInt16(); reader.ReadInt16(); // TODO: TEXCOORD2??? what do we do with this? reader.ReadInt16(); reader.ReadInt16(); vertex.Normal = BinaryUtil.ReadNormal(reader, true); // todo: read packed tangent vector reader.BaseStream.Position += 0x8; break; case EffectID.mw2_road_refl_lite: case EffectID.mw2_road_lite: case EffectID.mw2_grass_dirt: vertex.Position = BinaryUtil.ReadVector3(reader); reader.ReadSingle(); vertex.Color = reader.ReadUInt32(); vertex.TexCoords = BinaryUtil.ReadShort2N(reader) * 32; // TODO: TEXCOORD1??? what do we do with this? reader.ReadInt16(); reader.ReadInt16(); vertex.Normal = BinaryUtil.ReadNormal(reader, true); break; case EffectID.mw2_tunnel_wall: vertex.Position = BinaryUtil.ReadVector3(reader); reader.ReadSingle(); vertex.Color = reader.ReadUInt32(); vertex.TexCoords = BinaryUtil.ReadShort2N(reader) * 32; // TODO: TEXCOORD1??? what do we do with this? reader.ReadInt16(); reader.ReadInt16(); break; case EffectID.mw2_matte_alpha: case EffectID.mw2_dif_spec_a_bias: case EffectID.mw2_dirt_overlay: vertex.Position = BinaryUtil.ReadVector3(reader); reader.ReadSingle(); vertex.Color = reader.ReadUInt32(); vertex.TexCoords = BinaryUtil.ReadShort2N(reader) * 32; vertex.Normal = BinaryUtil.ReadNormal(reader, true); break; case EffectID.mw2_foliage: case EffectID.mw2_foliage_lod: case EffectID.mw2_scrub: case EffectID.mw2_scrub_lod: case EffectID.mw2_ocean: vertex.Position = BinaryUtil.ReadVector3(reader); reader.ReadSingle(); vertex.Color = reader.ReadUInt32(); vertex.TexCoords = BinaryUtil.ReadShort2N(reader) * 32; break; case EffectID.mw2_sky: vertex.Position = BinaryUtil.ReadVector3(reader); reader.ReadSingle(); vertex.TexCoords = BinaryUtil.ReadVector2(reader); break; case EffectID.mw2_texture_scroll: case EffectID.mw2_car_heaven_default: vertex.Position = BinaryUtil.ReadVector3(reader); reader.ReadSingle(); // TODO: COLOR0 is a float4. how do we deal with that? reader.BaseStream.Position += 0x10; vertex.TexCoords = BinaryUtil.ReadVector2(reader); break; case EffectID.mw2_car_heaven: vertex.Position = BinaryUtil.ReadVector3(reader); reader.ReadSingle(); // TODO: COLOR0 is a float4. how do we deal with that? reader.BaseStream.Position += 0x10; vertex.TexCoords = BinaryUtil.ReadVector2(reader); vertex.Normal = BinaryUtil.ReadNormal(reader, true); break; case EffectID.mw2_carhvn_floor: case EffectID.mw2_road: vertex.Position = BinaryUtil.ReadVector3(reader); reader.ReadSingle(); vertex.Color = reader.ReadUInt32(); vertex.TexCoords = BinaryUtil.ReadShort2N(reader) * 32; // TODO: TEXCOORD1??? what do we do with this? reader.ReadInt16(); reader.ReadInt16(); vertex.Normal = BinaryUtil.ReadNormal(reader, true); // todo: read packed tangent vector reader.BaseStream.Position += 0x8; break; case EffectID.car: case EffectID.car_a: case EffectID.car_a_nzw: case EffectID.car_nm: case EffectID.car_nm_a: case EffectID.car_nm_v_s: case EffectID.car_nm_v_s_a: case EffectID.car_si: case EffectID.car_si_a: case EffectID.car_t: case EffectID.car_t_a: case EffectID.car_t_nm: case EffectID.car_v: vertex.Position = BinaryUtil.ReadNormal(reader, true) * 10; vertex.TexCoords = BinaryUtil.ReadShort2N(reader) * 32; vertex.Color = reader.ReadUInt32(); vertex.Normal = BinaryUtil.ReadNormal(reader, true); vertex.Tangent = BinaryUtil.ReadNormal(reader, true); break; default: throw new Exception($"Unsupported effect: {effectId}"); } return(vertex); }
protected override SolidMeshVertex GetVertex(BinaryReader reader, SolidObjectMaterial material, int stride) { ProStreetMaterial psm = (ProStreetMaterial)material; SolidMeshVertex vertex = new SolidMeshVertex(); switch ((EffectID)psm.EffectId) { case EffectID.WORLDBAKEDLIGHTING: vertex.Position = BinaryUtil.ReadVector3(reader); vertex.Color = reader.ReadUInt32(); vertex.TexCoords = BinaryUtil.ReadVector2(reader); reader.BaseStream.Position += 16; vertex.Normal = BinaryUtil.ReadNormal(reader, true); break; case EffectID.WORLD: case EffectID.SKY: vertex.Position = BinaryUtil.ReadVector3(reader); vertex.Normal = BinaryUtil.ReadNormal(reader); vertex.Color = reader.ReadUInt32(); vertex.TexCoords = BinaryUtil.ReadVector2(reader); reader.BaseStream.Position += 8; // TODO: what is this second D3DDECLUSAGE_TEXCOORD element? break; case EffectID.WORLDNORMALMAP: vertex.Position = BinaryUtil.ReadVector3(reader); vertex.Normal = BinaryUtil.ReadNormal(reader); vertex.Color = reader.ReadUInt32(); vertex.TexCoords = BinaryUtil.ReadVector2(reader); reader.BaseStream.Position += 8; // TODO: what is this second D3DDECLUSAGE_TEXCOORD element? // TODO: read tangent reader.BaseStream.Position += 16; reader.BaseStream.Position += 8; // TODO: what are these other D3DDECLUSAGE_TEXCOORD elements? (2x D3DDECLTYPE_UBYTE4) break; case EffectID.WorldDepthShader: vertex.Position = BinaryUtil.ReadVector3(reader); vertex.Normal = BinaryUtil.ReadNormal(reader); vertex.Color = reader.ReadUInt32(); vertex.TexCoords = BinaryUtil.ReadVector2(reader); break; case EffectID.TREELEAVES: vertex.Position = BinaryUtil.ReadVector3(reader); vertex.Color = reader.ReadUInt32(); vertex.Normal = BinaryUtil.ReadNormal(reader); // TODO: COLLADA supports tangent vectors, so we should eventually read them //> elements[3]: type=D3DDECLTYPE_FLOAT4 usage=D3DDECLUSAGE_TANGENT size=16 offset=0x1c reader.BaseStream.Position += 0x10; vertex.TexCoords = BinaryUtil.ReadVector2(reader); break; case EffectID.WORLDCONSTANT: vertex.Position = BinaryUtil.ReadVector3(reader); vertex.TexCoords = BinaryUtil.ReadVector2(reader); vertex.Color = reader.ReadUInt32(); break; case EffectID.ROAD: vertex.Position = BinaryUtil.ReadVector3(reader); vertex.TexCoords = BinaryUtil.ReadVector2(reader); reader.BaseStream.Position += 28; vertex.Color = reader.ReadUInt32(); break; case EffectID.TERRAIN: vertex.Position = BinaryUtil.ReadVector3(reader); vertex.TexCoords = BinaryUtil.ReadVector2(reader); reader.BaseStream.Position += 16; vertex.Normal = BinaryUtil.ReadNormal(reader, true); // TODO: read packed tangent vector (4 short-components) reader.BaseStream.Position += 8; vertex.Color = reader.ReadUInt32(); reader.BaseStream.Position += 8; // TODO: what are these other D3DDECLUSAGE_TEXCOORD elements? (2x D3DDECLTYPE_UBYTE4) break; case EffectID.GRASSTERRAIN: vertex.Position = BinaryUtil.ReadVector3(reader); vertex.TexCoords = BinaryUtil.ReadVector2(reader); reader.BaseStream.Position += 20; vertex.Normal = BinaryUtil.ReadNormal(reader, true); // TODO: read packed tangent vector (4 short-components) reader.BaseStream.Position += 8; vertex.Color = reader.ReadUInt32(); break; case EffectID.FLAG: vertex.Position = BinaryUtil.ReadVector3(reader); vertex.Color = reader.ReadUInt32(); vertex.Normal = BinaryUtil.ReadNormal(reader, true); vertex.TexCoords = BinaryUtil.ReadVector2(reader); reader.BaseStream.Position += 8; // TODO: what is this second D3DDECLUSAGE_TEXCOORD element? break; case EffectID.GRASSCARD: vertex.Position = BinaryUtil.ReadVector3(reader); vertex.Color = reader.ReadUInt32(); vertex.Normal = BinaryUtil.ReadNormal(reader, true); // TODO: read packed tangent vector (4 short-components) reader.BaseStream.Position += 8; vertex.TexCoords = BinaryUtil.ReadVector2(reader); reader.BaseStream.Position += 8; // TODO: what is this second D3DDECLUSAGE_TEXCOORD element? break; case EffectID.CAR: case EffectID.CARNORMALMAP: case EffectID.CARVINYL: vertex.Position = BinaryUtil.ReadNormal(reader, true); vertex.TexCoords = BinaryUtil.ReadShort2N(reader); vertex.Color = reader.ReadUInt32(); vertex.Normal = BinaryUtil.ReadNormal(reader, true); vertex.Tangent = BinaryUtil.ReadNormal(reader, true); break; case EffectID.ALWAYSFACING: vertex.Position = BinaryUtil.ReadVector3(reader); vertex.Color = reader.ReadUInt32(); vertex.Normal = BinaryUtil.ReadNormal(reader, true); // TODO: read packed tangent vector (4 short-components) reader.BaseStream.Position += 8; vertex.TexCoords = BinaryUtil.ReadVector2(reader); break; case EffectID.STANDARD: vertex.Position = BinaryUtil.ReadVector3(reader); vertex.Color = reader.ReadUInt32(); vertex.TexCoords = BinaryUtil.ReadVector2(reader); reader.BaseStream.Position += 8; // todo: what's this? break; case EffectID.TUNNEL: vertex.Position = BinaryUtil.ReadVector3(reader); vertex.TexCoords = BinaryUtil.ReadVector2(reader); reader.BaseStream.Position += 8; // todo: what's this? reader.BaseStream.Position += 4; // todo: what's this? reader.BaseStream.Position += 4; // todo: what's this? vertex.Color = reader.ReadUInt32(); vertex.Normal = BinaryUtil.ReadNormal(reader, true); break; case EffectID.ROADLIGHTMAP: vertex.Position = BinaryUtil.ReadVector3(reader); vertex.TexCoords = BinaryUtil.ReadVector2(reader); reader.BaseStream.Position += 8; // todo: what's this? reader.BaseStream.Position += 8; // todo: what's this? reader.BaseStream.Position += 4; // todo: what's this? vertex.Normal = BinaryUtil.ReadNormal(reader, true); vertex.Color = reader.ReadUInt32(); break; case EffectID.WATER: vertex.Position = BinaryUtil.ReadVector3(reader); vertex.Color = reader.ReadUInt32(); vertex.TexCoords = BinaryUtil.ReadVector2(reader); break; case EffectID.WORLDBONE: vertex.Position = BinaryUtil.ReadVector3(reader); vertex.Normal = BinaryUtil.ReadNormal(reader); vertex.Color = reader.ReadUInt32(); vertex.TexCoords = BinaryUtil.ReadVector2(reader); vertex.BlendWeight = BinaryUtil.ReadVector3(reader); vertex.BlendIndices = BinaryUtil.ReadVector3(reader); vertex.Tangent = BinaryUtil.ReadVector3(reader); break; default: throw new Exception($"Unsupported effect in object {Name}: {psm.EffectId}"); } return(vertex); }