mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2025-02-17 01:22:18 +00:00
Visual mode: regular walls are now clipped by solid 3d floors (this should eliminate z-fighting).
Fixed, WavefrontExporter: floor and ceiling textures were not exported when using "classic" game configurations (ones with disabled "MixTexturesAndFlats" option). This should also fix incorrect flats on exported model when there are flats and textures with the same name. Fixed, WavefrontExporter: 3d floors geometry and wall geometry around them was created incorrectly. Fixed, WavefrontExporter: floor and ceiling textures of non-Vavoom 3d floors were swapped on exported geometry.
This commit is contained in:
parent
698f57b2f1
commit
0d90d9b297
8 changed files with 392 additions and 188 deletions
|
@ -151,15 +151,17 @@ namespace CodeImp.DoomBuilder.VisualModes
|
|||
protected void SetVertices(ICollection<WorldVertex> verts)
|
||||
{
|
||||
// Copy vertices
|
||||
if (verts != null) { //mxd
|
||||
if(verts != null) //mxd
|
||||
{
|
||||
vertices = new WorldVertex[verts.Count];
|
||||
verts.CopyTo(vertices, 0);
|
||||
triangles = vertices.Length / 3;
|
||||
|
||||
//mxd
|
||||
CalculateNormals();
|
||||
} else {
|
||||
vertices = new WorldVertex[1];
|
||||
CalculateNormals(); //mxd
|
||||
}
|
||||
else
|
||||
{
|
||||
vertices = null;
|
||||
triangles = 0;
|
||||
}
|
||||
|
||||
|
@ -167,46 +169,50 @@ namespace CodeImp.DoomBuilder.VisualModes
|
|||
}
|
||||
|
||||
//mxd. Normals calculation algorithm taken from OpenGl wiki
|
||||
protected void CalculateNormals() {
|
||||
if (triangles > 0) {
|
||||
int startIndex;
|
||||
Vector3 U, V;
|
||||
protected void CalculateNormals()
|
||||
{
|
||||
if (triangles == 0) return;
|
||||
|
||||
int startIndex;
|
||||
Vector3 U, V;
|
||||
|
||||
BoundingBoxSizes bbs = new BoundingBoxSizes(vertices[0]);
|
||||
BoundingBoxSizes bbs = new BoundingBoxSizes(vertices[0]);
|
||||
|
||||
for (int i = 0; i < triangles; i++) {
|
||||
startIndex = i * 3;
|
||||
WorldVertex p1 = vertices[startIndex];
|
||||
WorldVertex p2 = vertices[startIndex + 1];
|
||||
WorldVertex p3 = vertices[startIndex + 2];
|
||||
for(int i = 0; i < triangles; i++)
|
||||
{
|
||||
startIndex = i * 3;
|
||||
WorldVertex p1 = vertices[startIndex];
|
||||
WorldVertex p2 = vertices[startIndex + 1];
|
||||
WorldVertex p3 = vertices[startIndex + 2];
|
||||
|
||||
U = new Vector3(p2.x - p1.x, p2.y - p1.y, p2.z - p1.z);
|
||||
V = new Vector3(p3.x - p1.x, p3.y - p1.y, p3.z - p1.z);
|
||||
U = new Vector3(p2.x - p1.x, p2.y - p1.y, p2.z - p1.z);
|
||||
V = new Vector3(p3.x - p1.x, p3.y - p1.y, p3.z - p1.z);
|
||||
|
||||
p1.nx = p2.nx = p3.nx = -(U.Y * V.Z - U.Z * V.Y);
|
||||
p1.ny = p2.ny = p3.ny = -(U.Z * V.X - U.X * V.Z);
|
||||
p1.nz = p2.nz = p3.nz = -(U.X * V.Y - U.Y * V.X);
|
||||
p1.nx = p2.nx = p3.nx = -(U.Y * V.Z - U.Z * V.Y);
|
||||
p1.ny = p2.ny = p3.ny = -(U.Z * V.X - U.X * V.Z);
|
||||
p1.nz = p2.nz = p3.nz = -(U.X * V.Y - U.Y * V.X);
|
||||
|
||||
vertices[startIndex] = p1;
|
||||
vertices[startIndex + 1] = p2;
|
||||
vertices[startIndex + 2] = p3;
|
||||
vertices[startIndex] = p1;
|
||||
vertices[startIndex + 1] = p2;
|
||||
vertices[startIndex + 2] = p3;
|
||||
|
||||
BoundingBoxTools.UpdateBoundingBoxSizes(ref bbs, p1);
|
||||
BoundingBoxTools.UpdateBoundingBoxSizes(ref bbs, p2);
|
||||
BoundingBoxTools.UpdateBoundingBoxSizes(ref bbs, p3);
|
||||
}
|
||||
|
||||
boundingBox = BoundingBoxTools.CalculateBoundingPlane(bbs);
|
||||
BoundingBoxTools.UpdateBoundingBoxSizes(ref bbs, p1);
|
||||
BoundingBoxTools.UpdateBoundingBoxSizes(ref bbs, p2);
|
||||
BoundingBoxTools.UpdateBoundingBoxSizes(ref bbs, p3);
|
||||
}
|
||||
|
||||
boundingBox = BoundingBoxTools.CalculateBoundingPlane(bbs);
|
||||
}
|
||||
|
||||
//mxd. Used to get proper sector from 3d-floors
|
||||
public virtual Sector GetControlSector() {
|
||||
public virtual Sector GetControlSector()
|
||||
{
|
||||
return sector.Sector;
|
||||
}
|
||||
|
||||
//mxd. Used to get proper linedef from 3d-floors
|
||||
public virtual Linedef GetControlLinedef() {
|
||||
public virtual Linedef GetControlLinedef()
|
||||
{
|
||||
return sidedef.Line;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,13 +17,14 @@ namespace CodeImp.DoomBuilder.BuilderModes.IO
|
|||
internal struct WavefrontExportSettings
|
||||
{
|
||||
public string Obj;
|
||||
public string ObjName;
|
||||
public string ObjPath;
|
||||
public float Scale;
|
||||
public bool FixScale;
|
||||
public bool ExportTextures;
|
||||
public readonly string ObjName;
|
||||
public readonly string ObjPath;
|
||||
public readonly float Scale;
|
||||
public readonly bool FixScale;
|
||||
public readonly bool ExportTextures;
|
||||
public bool Valid;
|
||||
public string[] Textures;
|
||||
public string[] Flats;
|
||||
|
||||
public WavefrontExportSettings(string name, string path, float scale, bool fixScale, bool exportTextures) {
|
||||
ObjName = name;
|
||||
|
@ -35,6 +36,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.IO
|
|||
Valid = false;
|
||||
Obj = string.Empty;
|
||||
Textures = null;
|
||||
Flats = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,8 +71,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.IO
|
|||
continue;
|
||||
}
|
||||
|
||||
if(!id.IsImageLoaded)
|
||||
id.LoadImage();
|
||||
if(!id.IsImageLoaded) id.LoadImage();
|
||||
Bitmap bmp = id.GetBitmap();
|
||||
bmp.Save(Path.Combine(settings.ObjPath, s + ".PNG"), ImageFormat.Png);
|
||||
} else {
|
||||
|
@ -78,6 +79,33 @@ namespace CodeImp.DoomBuilder.BuilderModes.IO
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (settings.Flats != null) {
|
||||
foreach(string s in settings.Flats) {
|
||||
if(s == DEFAULT) continue;
|
||||
if(General.Map.Data.GetFlatExists(s)) {
|
||||
ImageData id = General.Map.Data.GetFlatImage(s);
|
||||
if(id.Width == 0 || id.Height == 0) {
|
||||
General.ErrorLogger.Add(ErrorType.Warning, "OBJ Exporter: flat '" + s + "' has invalid size (" + id.Width + "x" + id.Height + ")!");
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!id.IsImageLoaded) id.LoadImage();
|
||||
Bitmap bmp = id.GetBitmap();
|
||||
|
||||
// Handle duplicate names
|
||||
string flatname = s;
|
||||
if(settings.Textures != null && Array.IndexOf(settings.Textures, s) != -1) {
|
||||
flatname += "_FLAT";
|
||||
}
|
||||
|
||||
bmp.Save(Path.Combine(settings.ObjPath, flatname + ".PNG"), ImageFormat.Png);
|
||||
|
||||
} else {
|
||||
General.ErrorLogger.Add(ErrorType.Warning, "OBJ Exporter: flat '" + s + "' does not exist!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//write obj
|
||||
|
@ -90,12 +118,32 @@ namespace CodeImp.DoomBuilder.BuilderModes.IO
|
|||
mtl.Append("# MTL for " + General.Map.FileTitle + ", map " + General.Map.Options.LevelName + Environment.NewLine);
|
||||
mtl.Append("# Created by GZDoom Builder " + Application.ProductVersion + Environment.NewLine + Environment.NewLine);
|
||||
|
||||
foreach(string s in settings.Textures) {
|
||||
if(s == DEFAULT) continue;
|
||||
mtl.Append("newmtl " + s.ToUpperInvariant() + Environment.NewLine);
|
||||
mtl.Append("Kd 1.0 1.0 1.0" + Environment.NewLine);
|
||||
if(settings.ExportTextures) mtl.Append("map_Kd " + Path.Combine(settings.ObjPath, s.ToUpperInvariant() + ".PNG") + Environment.NewLine);
|
||||
mtl.Append(Environment.NewLine);
|
||||
if (settings.Textures != null) {
|
||||
foreach (string s in settings.Textures) {
|
||||
if (s == DEFAULT) continue;
|
||||
mtl.Append("newmtl " + s.ToUpperInvariant() + Environment.NewLine);
|
||||
mtl.Append("Kd 1.0 1.0 1.0" + Environment.NewLine);
|
||||
if (settings.ExportTextures) mtl.Append("map_Kd " + Path.Combine(settings.ObjPath, s.ToUpperInvariant() + ".PNG") + Environment.NewLine);
|
||||
mtl.Append(Environment.NewLine);
|
||||
}
|
||||
}
|
||||
|
||||
if(settings.Flats != null) {
|
||||
foreach (string s in settings.Flats) {
|
||||
if (s == DEFAULT) continue;
|
||||
mtl.Append("newmtl " + s.ToUpperInvariant() + Environment.NewLine);
|
||||
mtl.Append("Kd 1.0 1.0 1.0" + Environment.NewLine);
|
||||
if (settings.ExportTextures) {
|
||||
// Handle duplicate names
|
||||
string flatname = s;
|
||||
if(settings.Textures != null && Array.IndexOf(settings.Textures, s) != -1) {
|
||||
flatname += "_FLAT";
|
||||
}
|
||||
|
||||
mtl.Append("map_Kd " + Path.Combine(settings.ObjPath, flatname.ToUpperInvariant() + ".PNG") + Environment.NewLine);
|
||||
}
|
||||
mtl.Append(Environment.NewLine);
|
||||
}
|
||||
}
|
||||
|
||||
//write mtl
|
||||
|
@ -131,14 +179,13 @@ namespace CodeImp.DoomBuilder.BuilderModes.IO
|
|||
}
|
||||
|
||||
//sort geometry
|
||||
Dictionary<string, List<WorldVertex[]>> geometryByTexture = sortGeometry(visualSectors);
|
||||
List<Dictionary<string, List<WorldVertex[]>>> geometryByTexture = sortGeometry(visualSectors);
|
||||
|
||||
//restore vm settings
|
||||
if(renderingEffectsDisabled)
|
||||
mode.ToggleGZDoomRenderingEffects();
|
||||
|
||||
mode.Dispose();
|
||||
mode = null;
|
||||
|
||||
//create obj
|
||||
StringBuilder obj = createObjGeometry(geometryByTexture, data);
|
||||
|
@ -154,32 +201,39 @@ namespace CodeImp.DoomBuilder.BuilderModes.IO
|
|||
obj.Insert(0, "# " + General.Map.FileTitle + ", map " + General.Map.Options.LevelName + Environment.NewLine);
|
||||
data.Obj = obj.ToString();
|
||||
|
||||
string[] textures = new string[geometryByTexture.Keys.Count];
|
||||
geometryByTexture.Keys.CopyTo(textures, 0);
|
||||
string[] textures = new string[geometryByTexture[0].Keys.Count];
|
||||
geometryByTexture[0].Keys.CopyTo(textures, 0);
|
||||
Array.Sort(textures);
|
||||
data.Textures = textures;
|
||||
|
||||
string[] flats = new string[geometryByTexture[1].Keys.Count];
|
||||
geometryByTexture[1].Keys.CopyTo(flats, 0);
|
||||
Array.Sort(flats);
|
||||
data.Flats = flats;
|
||||
|
||||
data.Valid = true;
|
||||
}
|
||||
|
||||
private Dictionary<string, List<WorldVertex[]>> sortGeometry(List<BaseVisualSector> visualSectors) {
|
||||
var geo = new Dictionary<string, List<WorldVertex[]>>(StringComparer.Ordinal);
|
||||
geo.Add(DEFAULT, new List<WorldVertex[]>());
|
||||
private List<Dictionary<string, List<WorldVertex[]>>> sortGeometry(List<BaseVisualSector> visualSectors) {
|
||||
var texturegeo = new Dictionary<string, List<WorldVertex[]>>(StringComparer.Ordinal);
|
||||
texturegeo.Add(DEFAULT, new List<WorldVertex[]>());
|
||||
var flatgeo = new Dictionary<string, List<WorldVertex[]>>(StringComparer.Ordinal);
|
||||
flatgeo.Add(DEFAULT, new List<WorldVertex[]>());
|
||||
string texture;
|
||||
|
||||
foreach(BaseVisualSector vs in visualSectors) {
|
||||
//floor
|
||||
if(vs.Floor != null) {
|
||||
texture = vs.Sector.FloorTexture;
|
||||
checkTextureName(ref geo, ref texture);
|
||||
geo[texture].AddRange(optimizeSector(vs.Floor.Vertices, vs.Floor.GeometryType));
|
||||
checkTextureName(ref flatgeo, ref texture);
|
||||
flatgeo[texture].AddRange(OptimizeGeometry(vs.Floor.Vertices, vs.Floor.GeometryType, vs.Floor.Sector.Sector.Labels.Count > 1));
|
||||
}
|
||||
|
||||
//ceiling
|
||||
if(vs.Ceiling != null) {
|
||||
texture = vs.Sector.CeilTexture;
|
||||
checkTextureName(ref geo, ref texture);
|
||||
geo[texture].AddRange(optimizeSector(vs.Ceiling.Vertices, vs.Ceiling.GeometryType));
|
||||
checkTextureName(ref flatgeo, ref texture);
|
||||
flatgeo[texture].AddRange(OptimizeGeometry(vs.Ceiling.Vertices, vs.Ceiling.GeometryType, vs.Ceiling.Sector.Sector.Labels.Count > 1));
|
||||
}
|
||||
|
||||
//walls
|
||||
|
@ -188,31 +242,31 @@ namespace CodeImp.DoomBuilder.BuilderModes.IO
|
|||
//upper
|
||||
if(part.upper != null && part.upper.Vertices != null) {
|
||||
texture = part.upper.Sidedef.HighTexture;
|
||||
checkTextureName(ref geo, ref texture);
|
||||
geo[texture].Add(optimizeWall(part.upper.Vertices));
|
||||
checkTextureName(ref texturegeo, ref texture);
|
||||
texturegeo[texture].AddRange(OptimizeGeometry(part.upper.Vertices, part.upper.GeometryType));
|
||||
}
|
||||
|
||||
//middle single
|
||||
if(part.middlesingle != null && part.middlesingle.Vertices != null) {
|
||||
texture = part.middlesingle.Sidedef.MiddleTexture;
|
||||
checkTextureName(ref geo, ref texture);
|
||||
geo[texture].Add(optimizeWall(part.middlesingle.Vertices));
|
||||
checkTextureName(ref texturegeo, ref texture);
|
||||
texturegeo[texture].AddRange(OptimizeGeometry(part.middlesingle.Vertices, part.middlesingle.GeometryType));
|
||||
}
|
||||
|
||||
//middle double
|
||||
if(part.middledouble != null && part.middledouble.Vertices != null) {
|
||||
texture = part.middledouble.Sidedef.MiddleTexture;
|
||||
checkTextureName(ref geo, ref texture);
|
||||
geo[texture].Add(optimizeWall(part.middledouble.Vertices));
|
||||
checkTextureName(ref texturegeo, ref texture);
|
||||
texturegeo[texture].AddRange(OptimizeGeometry(part.middledouble.Vertices, part.middledouble.GeometryType));
|
||||
}
|
||||
|
||||
//middle3d
|
||||
if(part.middle3d != null && part.middle3d.Count > 0) {
|
||||
foreach(VisualMiddle3D m3d in part.middle3d) {
|
||||
if(m3d.Vertices == null) continue;
|
||||
texture = m3d.Sidedef.MiddleTexture;
|
||||
checkTextureName(ref geo, ref texture);
|
||||
geo[texture].Add(optimizeWall(m3d.Vertices));
|
||||
texture = m3d.GetControlLinedef().Front.MiddleTexture;
|
||||
checkTextureName(ref texturegeo, ref texture);
|
||||
texturegeo[texture].AddRange(OptimizeGeometry(m3d.Vertices, m3d.GeometryType));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -221,30 +275,30 @@ namespace CodeImp.DoomBuilder.BuilderModes.IO
|
|||
//lower
|
||||
if(part.lower != null && part.lower.Vertices != null) {
|
||||
texture = part.lower.Sidedef.LowTexture;
|
||||
checkTextureName(ref geo, ref texture);
|
||||
geo[texture].Add(optimizeWall(part.lower.Vertices));
|
||||
checkTextureName(ref texturegeo, ref texture);
|
||||
texturegeo[texture].AddRange(OptimizeGeometry(part.lower.Vertices, part.lower.GeometryType));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//3d ceilings
|
||||
foreach(VisualCeiling vc in vs.ExtraCeilings) {
|
||||
texture = vc.GetControlSector().FloorTexture;
|
||||
checkTextureName(ref geo, ref texture);
|
||||
geo[texture].AddRange(optimizeSector(vc.Vertices, vc.GeometryType));
|
||||
texture = vc.GetControlSector().CeilTexture;
|
||||
checkTextureName(ref flatgeo, ref texture);
|
||||
flatgeo[texture].AddRange(OptimizeGeometry(vc.Vertices, (vc.ExtraFloor.VavoomType ? vc.GeometryType : VisualModes.VisualGeometryType.FLOOR)));
|
||||
}
|
||||
|
||||
//3d floors
|
||||
foreach(VisualFloor vf in vs.ExtraFloors) {
|
||||
texture = vf.GetControlSector().FloorTexture;
|
||||
checkTextureName(ref geo, ref texture);
|
||||
geo[texture].AddRange(optimizeSector(vf.Vertices, vf.GeometryType));
|
||||
checkTextureName(ref flatgeo, ref texture);
|
||||
flatgeo[texture].AddRange(OptimizeGeometry(vf.Vertices, (vf.ExtraFloor.VavoomType ? vf.GeometryType : VisualModes.VisualGeometryType.CEILING)));
|
||||
}
|
||||
|
||||
//backsides(?)
|
||||
}
|
||||
|
||||
return geo;
|
||||
return new List<Dictionary<string, List<WorldVertex[]>>> { texturegeo, flatgeo };
|
||||
}
|
||||
|
||||
private static void checkTextureName(ref Dictionary<string, List<WorldVertex[]>> geo, ref string texture) {
|
||||
|
@ -257,24 +311,19 @@ namespace CodeImp.DoomBuilder.BuilderModes.IO
|
|||
}
|
||||
|
||||
//SURFACE OPTIMIZATION
|
||||
//it's either quad, or triangle
|
||||
private static WorldVertex[] optimizeWall(WorldVertex[] verts) {
|
||||
if (verts.Length == 6) {
|
||||
return new[] { verts[5], verts[2], verts[1], verts[0] };
|
||||
}
|
||||
|
||||
Array.Reverse(verts);
|
||||
return verts;
|
||||
private static List<WorldVertex[]> OptimizeGeometry(WorldVertex[] verts, VisualModes.VisualGeometryType geotype)
|
||||
{
|
||||
return OptimizeGeometry(verts, geotype, false);
|
||||
}
|
||||
|
||||
private static List<WorldVertex[]> optimizeSector(WorldVertex[] verts, VisualModes.VisualGeometryType visualGeometryType) {
|
||||
private static List<WorldVertex[]> OptimizeGeometry(WorldVertex[] verts, VisualModes.VisualGeometryType geotype, bool skiprectoptimization) {
|
||||
List<WorldVertex[]> groups = new List<WorldVertex[]>();
|
||||
|
||||
if(verts.Length == 6) { //rectangle surface
|
||||
if (visualGeometryType == VisualModes.VisualGeometryType.FLOOR) {
|
||||
verts = new[] { verts[5], verts[2], verts[1], verts[0] };
|
||||
} else {
|
||||
if(!skiprectoptimization && verts.Length == 6) { //rectangular surface
|
||||
if(geotype == VisualModes.VisualGeometryType.CEILING) {
|
||||
verts = new[] { verts[2], verts[5], verts[1], verts[0] };
|
||||
} else {
|
||||
verts = new[] { verts[5], verts[2], verts[1], verts[0] };
|
||||
}
|
||||
groups.Add(verts);
|
||||
} else {
|
||||
|
@ -287,7 +336,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.IO
|
|||
}
|
||||
|
||||
//OBJ Creation
|
||||
private static StringBuilder createObjGeometry(Dictionary<string, List<WorldVertex[]>> geometryByTexture, WavefrontExportSettings data) {
|
||||
private static StringBuilder createObjGeometry(List<Dictionary<string, List<WorldVertex[]>>> geometryByTexture, WavefrontExportSettings data) {
|
||||
StringBuilder obj = new StringBuilder();
|
||||
const string vertexFormatter = "{0} {2} {1}\n";
|
||||
|
||||
|
@ -302,46 +351,56 @@ namespace CodeImp.DoomBuilder.BuilderModes.IO
|
|||
int uvc = 0;
|
||||
|
||||
//optimize geometry
|
||||
foreach(KeyValuePair<string, List<WorldVertex[]>> group in geometryByTexture) {
|
||||
Dictionary<WorldVertex, VertexIndices> vertsData = new Dictionary<WorldVertex, VertexIndices>();
|
||||
foreach(WorldVertex[] verts in group.Value) {
|
||||
//vertex normals
|
||||
Vector3D n = new Vector3D(verts[0].nx, verts[0].ny, verts[0].nz).GetNormal();
|
||||
if(uniqueNormals.ContainsKey(n)) {
|
||||
ni = uniqueNormals[n];
|
||||
} else {
|
||||
uniqueNormals.Add(n, ++nc);
|
||||
ni = nc;
|
||||
}
|
||||
|
||||
foreach(WorldVertex v in verts){
|
||||
if(vertsData.ContainsKey(v)) continue;
|
||||
VertexIndices indices = new VertexIndices();
|
||||
indices.NormalIndex = ni;
|
||||
|
||||
//vertex coords
|
||||
Vector3D vc = new Vector3D(v.x, v.y, v.z);
|
||||
if(uniqueVerts.ContainsKey(vc)) {
|
||||
indices.PositionIndex = uniqueVerts[vc];
|
||||
foreach(Dictionary<string, List<WorldVertex[]>> dictionary in geometryByTexture) {
|
||||
foreach(KeyValuePair<string, List<WorldVertex[]>> group in dictionary) {
|
||||
Dictionary<WorldVertex, VertexIndices> vertsData = new Dictionary<WorldVertex, VertexIndices>();
|
||||
foreach(WorldVertex[] verts in group.Value) {
|
||||
//vertex normals
|
||||
Vector3D n = new Vector3D(verts[0].nx, verts[0].ny, verts[0].nz).GetNormal();
|
||||
if (uniqueNormals.ContainsKey(n)) {
|
||||
ni = uniqueNormals[n];
|
||||
} else {
|
||||
uniqueVerts.Add(vc, ++pc);
|
||||
indices.PositionIndex = pc;
|
||||
uniqueNormals.Add(n, ++nc);
|
||||
ni = nc;
|
||||
}
|
||||
|
||||
//uv
|
||||
PointF uv = new PointF(v.u, v.v);
|
||||
if(uniqueUVs.ContainsKey(uv)) {
|
||||
indices.UVIndex = uniqueUVs[uv];
|
||||
}else{
|
||||
uniqueUVs.Add(uv, ++uvc);
|
||||
indices.UVIndex = uvc;
|
||||
}
|
||||
foreach(WorldVertex v in verts) {
|
||||
if (vertsData.ContainsKey(v)) continue;
|
||||
VertexIndices indices = new VertexIndices();
|
||||
indices.NormalIndex = ni;
|
||||
|
||||
vertsData.Add(v, indices);
|
||||
//vertex coords
|
||||
Vector3D vc = new Vector3D(v.x, v.y, v.z);
|
||||
if (uniqueVerts.ContainsKey(vc)) {
|
||||
indices.PositionIndex = uniqueVerts[vc];
|
||||
} else {
|
||||
uniqueVerts.Add(vc, ++pc);
|
||||
indices.PositionIndex = pc;
|
||||
}
|
||||
|
||||
//uv
|
||||
PointF uv = new PointF(v.u, v.v);
|
||||
if (uniqueUVs.ContainsKey(uv)) {
|
||||
indices.UVIndex = uniqueUVs[uv];
|
||||
} else {
|
||||
uniqueUVs.Add(uv, ++uvc);
|
||||
indices.UVIndex = uvc;
|
||||
}
|
||||
|
||||
vertsData.Add(v, indices);
|
||||
}
|
||||
}
|
||||
|
||||
if(vertsData.Count > 0) {
|
||||
if(vertexDataByTexture.ContainsKey(group.Key)) {
|
||||
foreach(KeyValuePair<WorldVertex, VertexIndices> g in vertsData) {
|
||||
vertexDataByTexture[group.Key].Add(g.Key, g.Value);
|
||||
}
|
||||
} else {
|
||||
vertexDataByTexture.Add(group.Key, vertsData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vertexDataByTexture.Add(group.Key, vertsData);
|
||||
}
|
||||
|
||||
//write geometry
|
||||
|
@ -366,18 +425,20 @@ namespace CodeImp.DoomBuilder.BuilderModes.IO
|
|||
obj.Append("mtllib ").Append(data.ObjName + ".mtl").Append("\n");
|
||||
|
||||
//write materials and surface indices
|
||||
foreach(KeyValuePair<string, List<WorldVertex[]>> group in geometryByTexture) {
|
||||
//material
|
||||
obj.Append("usemtl ").Append(group.Key).Append("\n");
|
||||
|
||||
foreach(WorldVertex[] verts in group.Value) {
|
||||
//surface indices
|
||||
obj.Append("f");
|
||||
foreach(WorldVertex v in verts) {
|
||||
VertexIndices vi = vertexDataByTexture[group.Key][v];
|
||||
obj.Append(" " + vi.PositionIndex + "/" + vi.UVIndex + "/" + vi.NormalIndex);
|
||||
foreach(Dictionary<string, List<WorldVertex[]>> dictionary in geometryByTexture) {
|
||||
foreach(KeyValuePair<string, List<WorldVertex[]>> group in dictionary) {
|
||||
//material
|
||||
obj.Append("usemtl ").Append(group.Key).Append("\n");
|
||||
|
||||
foreach(WorldVertex[] verts in group.Value) {
|
||||
//surface indices
|
||||
obj.Append("f");
|
||||
foreach(WorldVertex v in verts) {
|
||||
VertexIndices vi = vertexDataByTexture[group.Key][v];
|
||||
obj.Append(" " + vi.PositionIndex + "/" + vi.UVIndex + "/" + vi.NormalIndex);
|
||||
}
|
||||
obj.Append("\n");
|
||||
}
|
||||
obj.Append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -178,22 +178,53 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
// Cut off the part above the other floor
|
||||
CropPoly(ref poly, osd.Floor.plane, false);
|
||||
CropPoly(ref poly, osd.Ceiling.plane, true);
|
||||
|
||||
if(poly.Count > 2)
|
||||
|
||||
// Cut out pieces that overlap 3D floors in this sector
|
||||
List<WallPolygon> polygons = new List<WallPolygon>(1);
|
||||
polygons.Add(poly);
|
||||
foreach(Effect3DFloor ef in sd.ExtraFloors) {
|
||||
//mxd. Walls should be clipped by solid 3D floors
|
||||
if(!ef.RenderInside && ef.Alpha == 255) {
|
||||
int num = polygons.Count;
|
||||
for(int pi = 0; pi < num; pi++) {
|
||||
// Split by floor plane of 3D floor
|
||||
WallPolygon p = polygons[pi];
|
||||
WallPolygon np = SplitPoly(ref p, ef.Ceiling.plane, true);
|
||||
|
||||
if(np.Count > 0) {
|
||||
// Split part below floor by the ceiling plane of 3D floor
|
||||
// and keep only the part below the ceiling (front)
|
||||
SplitPoly(ref np, ef.Floor.plane, true);
|
||||
|
||||
if(p.Count == 0) {
|
||||
polygons[pi] = np;
|
||||
} else {
|
||||
polygons[pi] = p;
|
||||
polygons.Add(np);
|
||||
}
|
||||
} else {
|
||||
polygons[pi] = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(polygons.Count > 0)
|
||||
{
|
||||
// Keep top and bottom planes for intersection testing
|
||||
top = osd.Floor.plane;
|
||||
bottom = sd.Floor.plane;
|
||||
|
||||
// Process the polygon and create vertices
|
||||
List<WorldVertex> verts = CreatePolygonVertices(poly, tp, sd, lightvalue, lightabsolute);
|
||||
if(verts.Count > 0)
|
||||
List<WorldVertex> verts = CreatePolygonVertices(polygons, tp, sd, lightvalue, lightabsolute);
|
||||
if(verts.Count > 2)
|
||||
{
|
||||
base.SetVertices(verts);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
base.SetVertices(null); //mxd
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -255,37 +255,41 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
}
|
||||
|
||||
// Process the polygon and create vertices
|
||||
List<WorldVertex> verts = CreatePolygonVertices(polygons, tp, sd, lightvalue, lightabsolute);
|
||||
if(verts.Count > 0)
|
||||
if (polygons.Count > 0)
|
||||
{
|
||||
if ((extrafloor.Linedef.Args[2] & (int)Effect3DFloor.Flags.RenderAdditive) != 0)//mxd
|
||||
this.RenderPass = RenderPass.Additive;
|
||||
else if (extrafloor.Alpha < 255)
|
||||
this.RenderPass = RenderPass.Alpha;
|
||||
else
|
||||
this.RenderPass = RenderPass.Mask;
|
||||
|
||||
if(extrafloor.Alpha < 255)
|
||||
List<WorldVertex> verts = CreatePolygonVertices(polygons, tp, sd, lightvalue, lightabsolute);
|
||||
if (verts.Count > 2)
|
||||
{
|
||||
// Apply alpha to vertices
|
||||
byte alpha = (byte)General.Clamp(extrafloor.Alpha, 0, 255);
|
||||
if(alpha < 255)
|
||||
if ((extrafloor.Linedef.Args[2] & (int) Effect3DFloor.Flags.RenderAdditive) != 0) //mxd
|
||||
this.RenderPass = RenderPass.Additive;
|
||||
else if (extrafloor.Alpha < 255)
|
||||
this.RenderPass = RenderPass.Alpha;
|
||||
else
|
||||
this.RenderPass = RenderPass.Mask;
|
||||
|
||||
if (extrafloor.Alpha < 255)
|
||||
{
|
||||
for(int i = 0; i < verts.Count; i++)
|
||||
// Apply alpha to vertices
|
||||
byte alpha = (byte) General.Clamp(extrafloor.Alpha, 0, 255);
|
||||
if (alpha < 255)
|
||||
{
|
||||
WorldVertex v = verts[i];
|
||||
PixelColor c = PixelColor.FromInt(v.c);
|
||||
v.c = c.WithAlpha(alpha).ToInt();
|
||||
verts[i] = v;
|
||||
for (int i = 0; i < verts.Count; i++)
|
||||
{
|
||||
WorldVertex v = verts[i];
|
||||
PixelColor c = PixelColor.FromInt(v.c);
|
||||
v.c = c.WithAlpha(alpha).ToInt();
|
||||
verts[i] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
base.SetVertices(verts);
|
||||
return true;
|
||||
}
|
||||
|
||||
base.SetVertices(verts);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
base.SetVertices(null); //mxd
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -219,34 +219,41 @@ namespace CodeImp.DoomBuilder.BuilderModes {
|
|||
}
|
||||
|
||||
// Process the polygon and create vertices
|
||||
List<WorldVertex> verts = CreatePolygonVertices(polygons, tp, sd, lightvalue, lightabsolute);
|
||||
if(verts.Count > 0)
|
||||
if (polygons.Count > 0)
|
||||
{
|
||||
if ((extrafloor.Linedef.Args[2] & (int)Effect3DFloor.Flags.RenderAdditive) != 0)//mxd
|
||||
this.RenderPass = RenderPass.Additive;
|
||||
else if (extrafloor.Alpha < 255)
|
||||
this.RenderPass = RenderPass.Alpha;
|
||||
else
|
||||
this.RenderPass = RenderPass.Mask;
|
||||
List<WorldVertex> verts = CreatePolygonVertices(polygons, tp, sd, lightvalue, lightabsolute);
|
||||
if (verts.Count > 2)
|
||||
{
|
||||
if ((extrafloor.Linedef.Args[2] & (int) Effect3DFloor.Flags.RenderAdditive) != 0) //mxd
|
||||
this.RenderPass = RenderPass.Additive;
|
||||
else if (extrafloor.Alpha < 255)
|
||||
this.RenderPass = RenderPass.Alpha;
|
||||
else
|
||||
this.RenderPass = RenderPass.Mask;
|
||||
|
||||
if (extrafloor.Alpha < 255) {
|
||||
// Apply alpha to vertices
|
||||
byte alpha = (byte)General.Clamp(extrafloor.Alpha, 0, 255);
|
||||
if (alpha < 255) {
|
||||
for (int i = 0; i < verts.Count; i++) {
|
||||
WorldVertex v = verts[i];
|
||||
PixelColor c = PixelColor.FromInt(v.c);
|
||||
v.c = c.WithAlpha(alpha).ToInt();
|
||||
verts[i] = v;
|
||||
if (extrafloor.Alpha < 255)
|
||||
{
|
||||
// Apply alpha to vertices
|
||||
byte alpha = (byte) General.Clamp(extrafloor.Alpha, 0, 255);
|
||||
if (alpha < 255)
|
||||
{
|
||||
for (int i = 0; i < verts.Count; i++)
|
||||
{
|
||||
WorldVertex v = verts[i];
|
||||
PixelColor c = PixelColor.FromInt(v.c);
|
||||
v.c = c.WithAlpha(alpha).ToInt();
|
||||
verts[i] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
base.SetVertices(verts);
|
||||
return true;
|
||||
}
|
||||
|
||||
base.SetVertices(verts);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
base.SetVertices(null); //mxd
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -206,14 +206,44 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
CropPoly(ref poly, bottomclipplane, true);
|
||||
}
|
||||
|
||||
if(poly.Count > 2) {
|
||||
// Cut out pieces that overlap 3D floors in this sector
|
||||
List<WallPolygon> polygons = new List<WallPolygon>(1);
|
||||
polygons.Add(poly);
|
||||
foreach(Effect3DFloor ef in sd.ExtraFloors) {
|
||||
//mxd. Walls should be clipped by solid 3D floors
|
||||
if(!ef.RenderInside && ef.Alpha == 255) {
|
||||
int num = polygons.Count;
|
||||
for(int pi = 0; pi < num; pi++) {
|
||||
// Split by floor plane of 3D floor
|
||||
WallPolygon p = polygons[pi];
|
||||
WallPolygon np = SplitPoly(ref p, ef.Ceiling.plane, true);
|
||||
|
||||
if(np.Count > 0) {
|
||||
// Split part below floor by the ceiling plane of 3D floor
|
||||
// and keep only the part below the ceiling (front)
|
||||
SplitPoly(ref np, ef.Floor.plane, true);
|
||||
|
||||
if(p.Count == 0) {
|
||||
polygons[pi] = np;
|
||||
} else {
|
||||
polygons[pi] = p;
|
||||
polygons.Add(np);
|
||||
}
|
||||
} else {
|
||||
polygons[pi] = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(polygons.Count > 0) {
|
||||
// Keep top and bottom planes for intersection testing
|
||||
top = osd.Ceiling.plane;
|
||||
bottom = osd.Floor.plane;
|
||||
|
||||
// Process the polygon and create vertices
|
||||
List<WorldVertex> verts = CreatePolygonVertices(poly, tp, sd, lightvalue, lightabsolute);
|
||||
if(verts.Count > 0) {
|
||||
List<WorldVertex> verts = CreatePolygonVertices(polygons, tp, sd, lightvalue, lightabsolute);
|
||||
if(verts.Count > 2) {
|
||||
// Apply alpha to vertices
|
||||
byte alpha = SetLinedefRenderstyle(true);
|
||||
if(alpha < 255) {
|
||||
|
|
|
@ -180,16 +180,50 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel, Sidedef));
|
||||
PixelColor wallcolor = PixelColor.Modulate(sd.Ceiling.colorbelow, wallbrightness);
|
||||
poly.color = wallcolor.WithAlpha(255).ToInt();
|
||||
|
||||
// Process the polygon and create vertices
|
||||
List<WorldVertex> verts = CreatePolygonVertices(poly, tp, sd, lightvalue, lightabsolute);
|
||||
if(verts.Count > 0)
|
||||
|
||||
// Cut out pieces that overlap 3D floors in this sector
|
||||
List<WallPolygon> polygons = new List<WallPolygon>(1);
|
||||
polygons.Add(poly);
|
||||
foreach(Effect3DFloor ef in sd.ExtraFloors) {
|
||||
//mxd. Walls should be clipped by solid 3D floors
|
||||
if(!ef.RenderInside && ef.Alpha == 255) {
|
||||
int num = polygons.Count;
|
||||
for(int pi = 0; pi < num; pi++) {
|
||||
// Split by floor plane of 3D floor
|
||||
WallPolygon p = polygons[pi];
|
||||
WallPolygon np = SplitPoly(ref p, ef.Ceiling.plane, true);
|
||||
|
||||
if(np.Count > 0) {
|
||||
// Split part below floor by the ceiling plane of 3D floor
|
||||
// and keep only the part below the ceiling (front)
|
||||
SplitPoly(ref np, ef.Floor.plane, true);
|
||||
|
||||
if(p.Count == 0) {
|
||||
polygons[pi] = np;
|
||||
} else {
|
||||
polygons[pi] = p;
|
||||
polygons.Add(np);
|
||||
}
|
||||
} else {
|
||||
polygons[pi] = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (polygons.Count > 0)
|
||||
{
|
||||
base.SetVertices(verts);
|
||||
return true;
|
||||
// Process the polygon and create vertices
|
||||
List<WorldVertex> verts = CreatePolygonVertices(polygons, tp, sd, lightvalue, lightabsolute);
|
||||
if (verts.Count > 2)
|
||||
{
|
||||
base.SetVertices(verts);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
base.SetVertices(null); //mxd
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -173,21 +173,52 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
// Cut off the part below the other ceiling
|
||||
CropPoly(ref poly, osd.Ceiling.plane, false);
|
||||
|
||||
if(poly.Count > 2)
|
||||
// Cut out pieces that overlap 3D floors in this sector
|
||||
List<WallPolygon> polygons = new List<WallPolygon>(1);
|
||||
polygons.Add(poly);
|
||||
foreach(Effect3DFloor ef in sd.ExtraFloors) {
|
||||
//mxd. Walls should be clipped by solid 3D floors
|
||||
if(!ef.RenderInside && ef.Alpha == 255) {
|
||||
int num = polygons.Count;
|
||||
for(int pi = 0; pi < num; pi++) {
|
||||
// Split by floor plane of 3D floor
|
||||
WallPolygon p = polygons[pi];
|
||||
WallPolygon np = SplitPoly(ref p, ef.Ceiling.plane, true);
|
||||
|
||||
if(np.Count > 0) {
|
||||
// Split part below floor by the ceiling plane of 3D floor
|
||||
// and keep only the part below the ceiling (front)
|
||||
SplitPoly(ref np, ef.Floor.plane, true);
|
||||
|
||||
if(p.Count == 0) {
|
||||
polygons[pi] = np;
|
||||
} else {
|
||||
polygons[pi] = p;
|
||||
polygons.Add(np);
|
||||
}
|
||||
} else {
|
||||
polygons[pi] = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(polygons.Count > 0)
|
||||
{
|
||||
// Keep top and bottom planes for intersection testing
|
||||
top = sd.Ceiling.plane;
|
||||
bottom = osd.Ceiling.plane;
|
||||
|
||||
// Process the polygon and create vertices
|
||||
List<WorldVertex> verts = CreatePolygonVertices(poly, tp, sd, lightvalue, lightabsolute);
|
||||
if(verts.Count > 0)
|
||||
List<WorldVertex> verts = CreatePolygonVertices(polygons, tp, sd, lightvalue, lightabsolute);
|
||||
if(verts.Count > 2)
|
||||
{
|
||||
base.SetVertices(verts);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
base.SetVertices(null); //mxd
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue