public SculptMesh SculptMeshFromFile(string fileName, SculptType sculptType, int lod, bool viewerMode) { Bitmap bitmap = (Bitmap) Image.FromFile(fileName); SculptMesh sculptMesh = new SculptMesh(bitmap, sculptType, lod, viewerMode); bitmap.Dispose(); return sculptMesh; }
public SculptMesh SculptMeshFromFile(string fileName, SculptType sculptType, int lod, bool viewerMode) { Bitmap bitmap = (Bitmap)Bitmap.FromFile(fileName); SculptMesh sculptMesh = new SculptMesh(bitmap, sculptType, lod, viewerMode); bitmap.Dispose(); return(sculptMesh); }
private void calcVertexNormals(SculptType sculptType, int xSize, int ySize) { // compute vertex normals by summing all the surface normals of all the triangles sharing // each vertex and then normalizing var numFaces = faces.Count; for (var i = 0; i < numFaces; i++) { var face = faces[i]; var surfaceNormal = face.SurfaceNormal(coords); normals[face.n1] += surfaceNormal; normals[face.n2] += surfaceNormal; normals[face.n3] += surfaceNormal; } var numNormals = normals.Count; for (var i = 0; i < numNormals; i++) { normals[i] = normals[i].Normalize(); } if (sculptType != SculptType.plane) { for (var y = 0; y < ySize; y++) { var rowOffset = y * xSize; normals[rowOffset] = normals[rowOffset + xSize - 1] = (normals[rowOffset] + normals[rowOffset + xSize - 1]).Normalize(); } } foreach (var face in faces) { var vf = new ViewerFace(0); vf.v1 = coords[face.v1]; vf.v2 = coords[face.v2]; vf.v3 = coords[face.v3]; vf.coordIndex1 = face.v1; vf.coordIndex2 = face.v2; vf.coordIndex3 = face.v3; vf.n1 = normals[face.n1]; vf.n2 = normals[face.n2]; vf.n3 = normals[face.n3]; vf.uv1 = uvs[face.uv1]; vf.uv2 = uvs[face.uv2]; vf.uv3 = uvs[face.uv3]; viewerFaces.Add(vf); } }
private void calcVertexNormals(SculptType sculptType, int xSize, int ySize) { // compute vertex normals by summing all the surface normals of all the triangles sharing // each vertex and then normalizing int numFaces = this.faces.Count; for (int i = 0; i < numFaces; i++) { Face face = this.faces[i]; Coord surfaceNormal = face.SurfaceNormal(this.coords); this.normals[face.n1] += surfaceNormal; this.normals[face.n2] += surfaceNormal; this.normals[face.n3] += surfaceNormal; } int numNormals = this.normals.Count; for (int i = 0; i < numNormals; i++) { this.normals[i] = this.normals[i].Normalize(); } if (sculptType != SculptType.plane) { // blend the vertex normals at the cylinder seam for (int y = 0; y < ySize; y++) { int rowOffset = y * xSize; this.normals[rowOffset] = this.normals[rowOffset + xSize - 1] = (this.normals[rowOffset] + this.normals[rowOffset + xSize - 1]).Normalize(); } } foreach (ViewerFace vf in this.faces.Select(face => new ViewerFace(0) { v1 = this.coords[face.v1], v2 = this.coords[face.v2], v3 = this.coords[face.v3], coordIndex1 = face.v1, coordIndex2 = face.v2, coordIndex3 = face.v3, n1 = this.normals[face.n1], n2 = this.normals[face.n2], n3 = this.normals[face.n3], uv1 = this.uvs[face.uv1], uv2 = this.uvs[face.uv2], uv3 = this.uvs[face.uv3] })) { this.viewerFaces.Add(vf); } }
public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool mirror, bool invert) { if (mirror) invert = !invert; SculptMap smap = new SculptMap(sculptBitmap, lod); List<List<Coord>> rows = smap.ToRows(mirror); _SculptMesh(rows, sculptType, invert); }
public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool mirror, bool invert) { if (mirror) { invert = !invert; } SculptMap smap = new SculptMap(sculptBitmap, lod); List <List <Coord> > rows = smap.ToRows(mirror); _SculptMesh(rows, sculptType, invert); }
public SculptData(byte[] data, int pos) { if (data.Length >= 17) { SculptTexture = new LLUUID(data, pos); Type = (SculptType)data[pos + 16]; } else { SculptTexture = LLUUID.Zero; Type = SculptType.None; } }
private void calcVertexNormals(SculptType sculptType, int xSize, int ySize) { // compute vertex normals by summing all the surface normals of all the triangles sharing // each vertex and then normalizing int numFaces = this.faces.Count; for (int i = 0; i < numFaces; i++) { Face face = this.faces[i]; Coord surfaceNormal = face.SurfaceNormal(this.coords); this.normals[face.v1] += surfaceNormal; this.normals[face.v2] += surfaceNormal; this.normals[face.v3] += surfaceNormal; } int numNormals = this.normals.Count; for (int i = 0; i < numNormals; i++) { this.normals[i] = this.normals[i].Normalize(); } if (sculptType != SculptType.plane) { // blend the vertex normals at the cylinder seam int pixelsAcross = xSize + 1; for (int y = 0; y < ySize; y++) { int rowOffset = y * pixelsAcross; this.normals[rowOffset] = this.normals[rowOffset + xSize - 1] = (this.normals[rowOffset] + this.normals[rowOffset + xSize - 1]).Normalize(); } } foreach (Face face in this.faces) { ViewerFace vf = new ViewerFace(0); vf.v1 = this.coords[face.v1]; vf.v2 = this.coords[face.v2]; vf.v3 = this.coords[face.v3]; vf.n1 = this.normals[face.n1]; vf.n2 = this.normals[face.n2]; vf.n3 = this.normals[face.n3]; vf.uv1 = this.uvs[face.uv1]; vf.uv2 = this.uvs[face.uv2]; vf.uv3 = this.uvs[face.uv3]; this.viewerFaces.Add(vf); } }
private void _SculptMesh(List <List <Coord> > rows, SculptType sculptType, bool viewerMode, bool mirror, bool invert) { coords = new List <Coord>(); faces = new List <Face>(); normals = new List <Coord>(); uvs = new List <UVCoord>(); sculptType = (SculptType)((int)sculptType & 0x07); if (mirror) { invert = !invert; } viewerFaces = new List <ViewerFace>(); var width = rows[0].Count; int p1, p2, p3, p4; int imageX, imageY; if (sculptType != SculptType.plane) { if (rows.Count % 2 == 0) { foreach (List <Coord> row in rows) { row.Add(row[0]); } } else { var lastIndex = rows[0].Count - 1; foreach (List <Coord> row in rows) { row[0] = row[lastIndex]; } } } var topPole = rows[0][width / 2]; var bottomPole = rows[rows.Count - 1][width / 2]; if (sculptType == SculptType.sphere) { if (rows.Count % 2 == 0) { var count = rows[0].Count; var topPoleRow = new List <Coord>(count); var bottomPoleRow = new List <Coord>(count); for (var i = 0; i < count; i++) { topPoleRow.Add(topPole); bottomPoleRow.Add(bottomPole); } rows.Insert(0, topPoleRow); rows.Add(bottomPoleRow); } else { var count = rows[0].Count; var topPoleRow = rows[0]; var bottomPoleRow = rows[rows.Count - 1]; for (var i = 0; i < count; i++) { topPoleRow[i] = topPole; bottomPoleRow[i] = bottomPole; } } } if (sculptType == SculptType.torus) { rows.Add(rows[0]); } var coordsDown = rows.Count; var coordsAcross = rows[0].Count; var lastColumn = coordsAcross - 1; var widthUnit = 1.0f / (coordsAcross - 1); var heightUnit = 1.0f / (coordsDown - 1); for (imageY = 0; imageY < coordsDown; imageY++) { var rowOffset = imageY * coordsAcross; for (imageX = 0; imageX < coordsAcross; imageX++) { /* * p1-----p2 * | \ f2 | * | \ | * | f1 \| * p3-----p4 */ p4 = rowOffset + imageX; p3 = p4 - 1; p2 = p4 - coordsAcross; p1 = p3 - coordsAcross; coords.Add(rows[imageY][imageX]); if (viewerMode) { normals.Add(new Coord()); uvs.Add(new UVCoord(widthUnit * imageX, heightUnit * imageY)); } if (imageY > 0 && imageX > 0) { Face f1, f2; if (viewerMode) { if (invert) { f1 = new Face(p1, p4, p3, p1, p4, p3) { uv1 = p1, uv2 = p4, uv3 = p3 }; f2 = new Face(p1, p2, p4, p1, p2, p4) { uv1 = p1, uv2 = p2, uv3 = p4 }; } else { f1 = new Face(p1, p3, p4, p1, p3, p4) { uv1 = p1, uv2 = p3, uv3 = p4 }; f2 = new Face(p1, p4, p2, p1, p4, p2) { uv1 = p1, uv2 = p4, uv3 = p2 }; } } else { if (invert) { f1 = new Face(p1, p4, p3); f2 = new Face(p1, p2, p4); } else { f1 = new Face(p1, p3, p4); f2 = new Face(p1, p4, p2); } } faces.Add(f1); faces.Add(f2); } } } if (viewerMode) { calcVertexNormals(sculptType, coordsAcross, coordsDown); } }
public SculptData(byte[] data, int pos) { if (data.Length >= 17) { SculptTexture = new LLUUID(data, pos); Type = (SculptType)data[pos + 16]; } else { SculptTexture = LLUUID.Zero; Type = SculptType.None; } }
public Mesh GetSculptMesh(UUID assetid, TextureExtended sculpttex, SculptType stype, Primitive prim) { Mesh result = null; lock (StoredMesh) { if (StoredMesh.ContainsKey(assetid.ToString())) { result = StoredMesh[assetid.ToString()]; return result; } } if (result == null) { System.Drawing.Bitmap bm = sculpttex.DOTNETImage; result = PrimMesherG.SculptIrrMesh(bm, stype); if (!killed.Contains(sculpttex.Raw)) { try { killed.Add(sculpttex.Raw); device.VideoDriver.RemoveTexture(sculpttex); } catch (AccessViolationException) { VUtil.LogConsole(this.ToString() + "[ACCESSVIOLATION]", "MeshFactory::GetSculptMesh"); System.Console.WriteLine("Unable to remove a sculpt texture from the video driver!"); } } bm.Dispose(); if (result != null) { lock (StoredMesh) { if (!StoredMesh.ContainsKey(assetid.ToString())) { StoredMesh.Add(assetid.ToString(), result); } } } } if (result != null) { return result; } return null; }
public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert) { _SculptMesh(sculptBitmap, sculptType, lod, viewerMode, mirror, invert); }
private void _SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert) { _SculptMesh(new SculptMap(sculptBitmap, lod).ToRows(mirror), sculptType, viewerMode, mirror, invert); }
public void Deserialize(OSDMap map) { GroupID = map["group-id"].AsUUID(); Material = (Material)map["material"].AsInteger(); Name = map["name"].AsString(); Position = map["pos"].AsVector3(); Rotation = map["rotation"].AsQuaternion(); Scale = map["scale"].AsVector3(); // Extra params OSDArray extraParams = map["extra_parameters"] as OSDArray; if (extraParams != null) { ExtraParams = new ExtraParam[extraParams.Count]; for (int i = 0; i < extraParams.Count; i++) { ExtraParam extraParam = new ExtraParam(); extraParam.Deserialize(extraParams[i] as OSDMap); ExtraParams[i] = extraParam; } } else { ExtraParams = new ExtraParam[0]; } // Faces OSDArray faces = map["facelist"] as OSDArray; if (faces != null) { Faces = new Face[faces.Count]; for (int i = 0; i < faces.Count; i++) { Face face = new Face(); face.Deserialize(faces[i] as OSDMap); Faces[i] = face; } } else { Faces = new Face[0]; } // Shape OSDMap shape = map["shape"] as OSDMap; OSDMap path = shape["path"] as OSDMap; PathBegin = (float)path["begin"].AsReal(); PathCurve = path["curve"].AsInteger(); PathEnd = (float)path["end"].AsReal(); RadiusOffset = (float)path["radius_offset"].AsReal(); Revolutions = (float)path["revolutions"].AsReal(); ScaleX = (float)path["scale_x"].AsReal(); ScaleY = (float)path["scale_y"].AsReal(); ShearX = (float)path["shear_x"].AsReal(); ShearY = (float)path["shear_y"].AsReal(); Skew = (float)path["skew"].AsReal(); TaperX = (float)path["taper_x"].AsReal(); TaperY = (float)path["taper_y"].AsReal(); Twist = (float)path["twist"].AsReal(); TwistBegin = (float)path["twist_begin"].AsReal(); OSDMap profile = shape["profile"] as OSDMap; ProfileBegin = (float)profile["begin"].AsReal(); ProfileCurve = profile["curve"].AsInteger(); ProfileEnd = (float)profile["end"].AsReal(); ProfileHollow = (float)profile["hollow"].AsReal(); OSDMap sculpt = shape["sculpt"] as OSDMap; if (sculpt != null) { SculptID = sculpt["id"].AsUUID(); SculptType = (SculptType)sculpt["type"].AsInteger(); } else { SculptID = UUID.Zero; SculptType = 0; } }
public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode) { _SculptMesh(sculptBitmap, sculptType, lod, viewerMode, false, false); }
public SculptMesh(List <List <Coord> > rows, SculptType sculptType, bool viewerMode, bool mirror, bool invert) { _SculptMesh(rows, sculptType, viewerMode, mirror, invert); }
void _SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert) { coords = new List<Coord>(); faces = new List<Face>(); normals = new List<Coord>(); uvs = new List<UVCoord>(); sculptType = (SculptType)(((int)sculptType) & 0x07); if (mirror) if (sculptType == SculptType.plane) invert = !invert; float sourceScaleFactor = (float)(lod) / (float)Math.Sqrt(sculptBitmap.Width * sculptBitmap.Height); int scale = (int)(1.0f / sourceScaleFactor); if (scale < 1) scale = 1; List<List<Coord>> rows = bitmap2Coords(sculptBitmap, scale, mirror); viewerFaces = new List<ViewerFace>(); int width = sculptBitmap.Width / scale; // int height = sculptBitmap.Height / scale; int p1, p2, p3, p4; int imageX, imageY; if (sculptType != SculptType.plane) { for (int rowNdx = 0; rowNdx < rows.Count; rowNdx++) rows[rowNdx].Add(rows[rowNdx][0]); } Coord topPole = rows[0][width / 2]; Coord bottomPole = rows[rows.Count - 1][width / 2]; if (sculptType == SculptType.sphere) { int count = rows[0].Count; List<Coord> topPoleRow = new List<Coord>(count); List<Coord> bottomPoleRow = new List<Coord>(count); for (int i = 0; i < count; i++) { topPoleRow.Add(topPole); bottomPoleRow.Add(bottomPole); } rows.Insert(0, topPoleRow); rows.Add(bottomPoleRow); } else if (sculptType == SculptType.torus) rows.Add(rows[0]); int coordsDown = rows.Count; int coordsAcross = rows[0].Count; float widthUnit = 1.0f / (coordsAcross - 1); float heightUnit = 1.0f / (coordsDown - 1); for (imageY = 0; imageY < coordsDown; imageY++) { int rowOffset = imageY * coordsAcross; for (imageX = 0; imageX < coordsAcross; imageX++) { /* * p1-----p2 * | \ f2 | * | \ | * | f1 \| * p3-----p4 */ p4 = rowOffset + imageX; p3 = p4 - 1; p2 = p4 - coordsAcross; p1 = p3 - coordsAcross; this.coords.Add(rows[imageY][imageX]); if (viewerMode) { this.normals.Add(new Coord()); this.uvs.Add(new UVCoord(widthUnit * imageX, heightUnit * imageY)); } if (imageY > 0 && imageX > 0) { Face f1, f2; if (viewerMode) { if (invert) { f1 = new Face(p1, p4, p3, p1, p4, p3); f1.uv1 = p1; f1.uv2 = p4; f1.uv3 = p3; f2 = new Face(p1, p2, p4, p1, p2, p4); f2.uv1 = p1; f2.uv2 = p2; f2.uv3 = p4; } else { f1 = new Face(p1, p3, p4, p1, p3, p4); f1.uv1 = p1; f1.uv2 = p3; f1.uv3 = p4; f2 = new Face(p1, p4, p2, p1, p4, p2); f2.uv1 = p1; f2.uv2 = p4; f2.uv3 = p2; } } else { if (invert) { f1 = new Face(p1, p4, p3); f2 = new Face(p1, p2, p4); } else { f1 = new Face(p1, p3, p4); f2 = new Face(p1, p4, p2); } } this.faces.Add(f1); this.faces.Add(f2); } } } if (viewerMode) calcVertexNormals(sculptType, coordsAcross, coordsDown); }
void calcVertexNormals(SculptType sculptType, int xSize, int ySize) { // compute vertex normals by summing all the surface normals of all the triangles sharing // each vertex and then normalizing int numFaces = faces.Count; for (int i = 0; i < numFaces; i++) { Face face = faces[i]; Coord surfaceNormal = face.SurfaceNormal(this.coords); normals[face.n1] += surfaceNormal; normals[face.n2] += surfaceNormal; normals[face.n3] += surfaceNormal; } int numNormals = normals.Count; for (int i = 0; i < numNormals; i++) normals[i] = normals[i].Normalize(); if (sculptType != SculptType.plane) { // blend the vertex normals at the cylinder seam for (int y = 0; y < ySize; y++) { int rowOffset = y * xSize; normals[rowOffset] = normals[rowOffset + xSize - 1] = (normals[rowOffset] + normals[rowOffset + xSize - 1]).Normalize(); } } foreach (Face face in faces) { ViewerFace vf = new ViewerFace(0); vf.v1 = coords[face.v1]; vf.v2 = coords[face.v2]; vf.v3 = coords[face.v3]; vf.coordIndex1 = face.v1; vf.coordIndex2 = face.v2; vf.coordIndex3 = face.v3; vf.n1 = normals[face.n1]; vf.n2 = normals[face.n2]; vf.n3 = normals[face.n3]; vf.uv1 = uvs[face.uv1]; vf.uv2 = uvs[face.uv2]; vf.uv3 = uvs[face.uv3]; viewerFaces.Add(vf); } }
protected bool CreateSide(Volume volume, bool partialBuild) { bool flat = TypeMask.HasFlag(VolumeFaceMask.Flat); SculptType sculptStitching = volume.Parameters.SculptType; SculptFlags sculptFlags = volume.Parameters.SculptFlags; bool sculptInvert = sculptFlags.HasFlag(SculptFlags.Invert); bool sculptMirror = sculptFlags.HasFlag(SculptFlags.Mirror); bool sculptReverseHorizontal = (sculptInvert ? !sculptMirror : sculptMirror); // XOR int numVertices, numIndices; List <Vector3> mesh = volume.Points; List <Vector3> profile = volume.Profile.Points; List <Path.PathPoint> pathData = volume.Path.Points; int maxS = volume.Profile.PointCount; int s, t, i; float ss, tt; numVertices = NumS * NumT; numIndices = (NumS - 1) * (NumT - 1) * 6; // TODO: How does partial builds work? //partial_build = (num_vertices > NumVertices || num_indices > NumIndices) ? false : partial_build; //if (!partial_build) //{ // resizeVertices(num_vertices); // resizeIndices(num_indices); // if (!volume->isMeshAssetLoaded()) // { // mEdge.resize(num_indices); // } //} Positions.Clear(); Normals.Clear(); Indices.Clear(); Edge.Clear(); float beginStex = Mathf.Floor(profile[BeginS][2]); bool test = TypeMask.HasFlag(VolumeFaceMask.Inner | VolumeFaceMask.Flat) && NumS > 2; int numS = test ? NumS / 2 : NumS; int curVertex = 0; int endT = BeginT + NumT; // Copy the vertices into the array for (t = BeginT; t < endT; t++) { tt = pathData[t].ExtrusionT; for (s = 0; s < numS; s++) { if (TypeMask.HasFlag(VolumeFaceMask.End)) { ss = s > 0 ? 1f : 0f; } else { // Get s value for tex-coord. if (!flat) { ss = profile[BeginS + s][2]; } else { ss = profile[BeginS + s][2] - beginStex; } } if (sculptReverseHorizontal) { ss = 1f - ss; } // Check to see if this triangle wraps around the array. if (BeginS + s >= maxS) { // We're wrapping i = BeginS + s + maxS * (t - 1); } else { i = BeginS + s + maxS * t; } Positions.Add(mesh[i]); Normals.Add(Vector3.zero); // This will be calculated later TexCoords.Add(new Vector2(ss, tt)); curVertex++; if (test && s > 0) { Positions.Add(mesh[i]); Normals.Add(Vector3.zero); // This will be calculated later TexCoords.Add(new Vector2(ss, tt)); curVertex++; } } if (test) { s = TypeMask.HasFlag(VolumeFaceMask.Open) ? numS - 1 : 0; i = BeginS + s + maxS * t; ss = profile[BeginS + s][2] - beginStex; Positions.Add(mesh[i]); Normals.Add(Vector3.zero); // This will be calculated later TexCoords.Add(new Vector2(ss, tt)); curVertex++; } } Centre = Vector3.zero; int curPos = 0; int endPos = Positions.Count; //get bounding box for this side Vector3 faceMin; Vector3 faceMax; faceMin = faceMax = Positions[curPos++]; while (curPos < endPos) { UpdateMinMax(ref faceMin, ref faceMax, Positions[curPos++]); } // VFExtents change ExtentsMin = faceMin; ExtentsMax = faceMax; int tcCount = NumVertices; if (tcCount % 2 == 1) { //odd number of texture coordinates, duplicate last entry to padded end of array tcCount++; TexCoords.Add(TexCoords[NumVertices - 1]); } int curTc = 0; int endTc = TexCoords.Count; Vector3 tcMin; Vector3 tcMax; tcMin = tcMax = TexCoords[curTc++]; while (curTc < endTc) { UpdateMinMax(ref tcMin, ref tcMax, TexCoords[curTc++]); } //TODO: TexCoordExtents are weird this assumes Vector4 //TexCoordExtentsMin.x = llmin(minp[0], minp[2]); //TexCoordExtentsMin.y = llmin(minp[1], minp[3]); //TexCoordExtentsMax.x = llmax(maxp[0], maxp[2]); //TexCoordExtentsMax.y = llmax(maxp[1], maxp[3]); Centre = (faceMin + faceMax) * 0.5f; bool flatFace = TypeMask.HasFlag(VolumeFaceMask.Flat); //(TypeMask & VolumeFaceMask.Flat) != 0; if (!partialBuild) { // Now we generate the indices. for (t = 0; t < (NumT - 1); t++) { for (s = 0; s < (NumS - 1); s++) { Indices.Add(s + NumS * t); //bottom left Indices.Add(s + 1 + NumS * (t + 1)); //top right Indices.Add(s + NumS * (t + 1)); //top left Indices.Add(s + NumS * t); //bottom left Indices.Add(s + 1 + NumS * t); //bottom right Indices.Add(s + 1 + NumS * (t + 1)); //top right Edge.Add((NumS - 1) * 2 * t + s * 2 + 1); //bottom left/top right neighbor face if (t < NumT - 2) { //top right/top left neighbor face Edge.Add((NumS - 1) * 2 * (t + 1) + s * 2 + 1); } else if (NumT <= 3 || volume.Path.IsOpen == true) { //no neighbor Edge.Add(-1); } else { //wrap on T Edge.Add(s * 2 + 1); } if (s > 0) { //top left/bottom left neighbor face Edge.Add((NumS - 1) * 2 * t + s * 2 - 1); } else if (flatFace || volume.Profile.IsOpen == true) { //no neighbor Edge.Add(-1); } else { //wrap on S Edge.Add((NumS - 1) * 2 * t + (NumS - 2) * 2 + 1); } if (t > 0) { //bottom left/bottom right neighbor face Edge.Add((NumS - 1) * 2 * (t - 1) + s * 2); } else if (NumT <= 3 || volume.Path.IsOpen == true) { //no neighbor Edge.Add(-1); } else { //wrap on T Edge.Add((NumS - 1) * 2 * (NumT - 2) + s * 2); } if (s < NumS - 2) { //bottom right/top right neighbor face Edge.Add((NumS - 1) * 2 * t + (s + 1) * 2); } else if (flatFace || volume.Profile.IsOpen == true) { //no neighbor Edge.Add(-1); } else { //wrap on S Edge.Add((NumS - 1) * 2 * t); } Edge.Add((NumS - 1) * 2 * t + s * 2); //top right/bottom left neighbor face } } } // //clear normals //int dst = Normals.Count; //int end = dst + NumVertices; //Vector3 zero = Vector3.zero; //while (dst < end) // { // Normals.Add(zero); // dst++; //} //generate normals // Compute triangle normals: int count = Indices.Count / 3; List <Vector3> triangleNormals = new List <Vector3>(); int idx = 0; for (int triangleIndex = 0; triangleIndex < count; triangleIndex++) { Vector3 p0 = Positions[Indices[idx + 0]]; Vector3 p1 = Positions[Indices[idx + 1]]; Vector3 p2 = Positions[Indices[idx + 2]]; //calculate triangle normal Vector3 a = p1 - p0; Vector3 b = p2 - p0; Vector3 normal = Vector3.Cross(a, b); if (Vector3.Dot(normal, normal) > 0.00001f) { normal.Normalize(); } else { //degenerate, make up a value normal = normal.z >= 0 ? new Vector3(0f, 0f, 1f) : new Vector3(0f, 0f, -1f); } // This is probably an optimised way to calculate this: //LLQuad & vector1 = *((LLQuad*)&v1); //LLQuad & vector2 = *((LLQuad*)&v2); //LLQuad & amQ = *((LLQuad*)&a); //LLQuad & bmQ = *((LLQuad*)&b); // Vectors are stored in memory in w, z, y, x order from high to low // Set vector1 = { a[W], a[X], a[Z], a[Y] } //vector1 = _mm_shuffle_ps(amQ, amQ, _MM_SHUFFLE(3, 0, 2, 1)); // Set vector2 = { b[W], b[Y], b[X], b[Z] } //vector2 = _mm_shuffle_ps(bmQ, bmQ, _MM_SHUFFLE(3, 1, 0, 2)); // mQ = { a[W]*b[W], a[X]*b[Y], a[Z]*b[X], a[Y]*b[Z] } //vector2 = _mm_mul_ps(vector1, vector2); // vector3 = { a[W], a[Y], a[X], a[Z] } //amQ = _mm_shuffle_ps(amQ, amQ, _MM_SHUFFLE(3, 1, 0, 2)); // vector4 = { b[W], b[X], b[Z], b[Y] } //bmQ = _mm_shuffle_ps(bmQ, bmQ, _MM_SHUFFLE(3, 0, 2, 1)); // mQ = { 0, a[X]*b[Y] - a[Y]*b[X], a[Z]*b[X] - a[X]*b[Z], a[Y]*b[Z] - a[Z]*b[Y] } //vector1 = _mm_sub_ps(vector2, _mm_mul_ps(amQ, bmQ)); //llassert(v1.isFinite3()); triangleNormals.Add(normal); idx += 3; } // Add triangle normal contributions from each triangle to the vertex normals: idx = 0; for (int triangleIndex = 0; triangleIndex < count; triangleIndex++) //for each triangle { Vector3 c = triangleNormals[triangleIndex]; Vector3 n0 = Normals[Indices[idx + 0]]; Vector3 n1 = Normals[Indices[idx + 1]]; Vector3 n2 = Normals[Indices[idx + 2]]; n0 += c; n1 += c; n2 += c; //llassert(c.isFinite3()); //even out quad contributions switch (triangleIndex % 2 + 1) { case 0: n0 += c; break; case 1: n1 += c; break; case 2: n2 += c; break; } ; Normals[Indices[idx + 0]] = n0; Normals[Indices[idx + 1]] = n1; Normals[Indices[idx + 2]] = n2; idx += 3; } // adjust normals based on wrapping and stitching Vector3 top = (Positions[0] - Positions[NumS * (NumT - 2)]); bool s_bottom_converges = Vector3.Dot(top, top) < 0.000001f; top = Positions[NumS - 1] - Positions[NumS * (NumT - 2) + NumS - 1]; bool s_top_converges = Vector3.Dot(top, top) < 0.000001f; if (sculptStitching == SculptType.None) // logic for non-sculpt volumes { if (volume.Path.IsOpen == false) { //wrap normals on T for (int j = 0; j < NumS; j++) { Vector3 n = Normals[j] + Normals[NumS * (NumT - 1) + j]; Normals[j] = n; Normals[NumS * (NumT - 1) + j] = n; } } if ((volume.Profile.IsOpen == false) && !(s_bottom_converges)) { //wrap normals on S for (int j = 0; j < NumT; j++) { Vector3 n = Normals[NumS * j] + Normals[NumS * j + NumS - 1]; Normals[NumS * j] = n; Normals[NumS * j + NumS - 1] = n; } } if (volume.Parameters.PathParameters.PathType == PathType.Circle && volume.Parameters.ProfileParameters.ProfileType == ProfileType.CircleHalf) { if (s_bottom_converges) { //all lower S have same normal for (int j = 0; j < NumT; j++) { Normals[NumS * j] = new Vector3(1f, 0f, 0f); } } if (s_top_converges) { //all upper S have same normal for (int j = 0; j < NumT; j++) { Normals[NumS * j + NumS - 1] = new Vector3(-1f, 0f, 0f); } } } } //else // logic for sculpt volumes //{ //BOOL average_poles = FALSE; //BOOL wrap_s = FALSE; //BOOL wrap_t = FALSE; //if (sculpt_stitching == LL_SCULPT_TYPE_SPHERE) // average_poles = TRUE; //if ((sculpt_stitching == LL_SCULPT_TYPE_SPHERE) || // (sculpt_stitching == LL_SCULPT_TYPE_TORUS) || // (sculpt_stitching == LL_SCULPT_TYPE_CYLINDER)) // wrap_s = TRUE; //if (sculpt_stitching == LL_SCULPT_TYPE_TORUS) // wrap_t = TRUE; //if (average_poles) //{ // // average normals for north pole // LLVector4a average; // average.clear(); // for (S32 i = 0; i < mNumS; i++) // { // average.add(norm[i]); // } // // set average // for (S32 i = 0; i < mNumS; i++) // { // norm[i] = average; // } // // average normals for south pole // average.clear(); // for (S32 i = 0; i < mNumS; i++) // { // average.add(norm[i + mNumS * (mNumT - 1)]); // } // // set average // for (S32 i = 0; i < mNumS; i++) // { // norm[i + mNumS * (mNumT - 1)] = average; // } // } //if (wrap_s) //{ // for (S32 i = 0; i < mNumT; i++) // { // LLVector4a n; // n.setAdd(norm[mNumS * i], norm[mNumS * i + mNumS - 1]); // norm[mNumS * i] = n; // norm[mNumS * i + mNumS - 1] = n; // } //} //if (wrap_t) //{ // for (S32 i = 0; i < mNumS; i++) // { // LLVector4a n; // n.setAdd(norm[i], norm[mNumS * (mNumT - 1) + i]); // norm[i] = n; // norm[mNumS * (mNumT - 1) + i] = n; // } //} //} // Normalise normals: for (int normalIndex = 0; normalIndex < Normals.Count; normalIndex++) { Normals[normalIndex] = Normals[normalIndex].normalized; } return(true); }
private void SetPrimType(IScriptInstance script, object[] rules, ref int i) { LLPrimitive prim = script.Host as LLPrimitive; if (prim == null) { return; } int code = llList2Integer(script, rules, i++); switch (code) { case LSLConstants.PRIM_TYPE_BOX: { int holeShape = llList2Integer(script, rules, i++); Vector3 cut = llList2Vector(script, rules, i++); float hollow = llList2Float(script, rules, i++); Vector3 twist = llList2Vector(script, rules, i++); Vector3 topSize = llList2Vector(script, rules, i++); Vector3 topShear = llList2Vector(script, rules, i++); Primitive.ConstructionData primData = ObjectManager.BuildBasicShape(PrimType.Box); primData.Material = prim.Prim.PrimData.Material; primData.State = prim.Prim.PrimData.State; prim.Prim.PrimData = primData; prim.Prim.Sculpt = null; SetPrimShapeParams(prim, holeShape, cut, hollow, twist, topSize, topShear); break; } case LSLConstants.PRIM_TYPE_CYLINDER: { int holeShape = llList2Integer(script, rules, i++); Vector3 cut = llList2Vector(script, rules, i++); float hollow = llList2Float(script, rules, i++); Vector3 twist = llList2Vector(script, rules, i++); Vector3 topSize = llList2Vector(script, rules, i++); Vector3 topShear = llList2Vector(script, rules, i++); Primitive.ConstructionData primData = ObjectManager.BuildBasicShape(PrimType.Cylinder); primData.Material = prim.Prim.PrimData.Material; primData.State = prim.Prim.PrimData.State; prim.Prim.PrimData = primData; prim.Prim.Sculpt = null; SetPrimShapeParams(prim, holeShape, cut, hollow, twist, topSize, topShear); break; } case LSLConstants.PRIM_TYPE_PRISM: { int holeShape = llList2Integer(script, rules, i++); Vector3 cut = llList2Vector(script, rules, i++); float hollow = llList2Float(script, rules, i++); Vector3 twist = llList2Vector(script, rules, i++); Vector3 topSize = llList2Vector(script, rules, i++); Vector3 topShear = llList2Vector(script, rules, i++); Primitive.ConstructionData primData = ObjectManager.BuildBasicShape(PrimType.Prism); primData.Material = prim.Prim.PrimData.Material; primData.State = prim.Prim.PrimData.State; prim.Prim.PrimData = primData; prim.Prim.Sculpt = null; SetPrimShapeParams(prim, holeShape, cut, hollow, twist, topSize, topShear); break; } case LSLConstants.PRIM_TYPE_SPHERE: { int holeShape = llList2Integer(script, rules, i++); Vector3 cut = llList2Vector(script, rules, i++); float hollow = llList2Float(script, rules, i++); Vector3 twist = llList2Vector(script, rules, i++); Vector3 dimple = llList2Vector(script, rules, i++); Primitive.ConstructionData primData = ObjectManager.BuildBasicShape(PrimType.Sphere); primData.Material = prim.Prim.PrimData.Material; primData.State = prim.Prim.PrimData.State; prim.Prim.PrimData = primData; prim.Prim.Sculpt = null; SetPrimShapeParams(prim, holeShape, cut, hollow, twist, dimple); break; } case LSLConstants.PRIM_TYPE_TORUS: { int holeShape = llList2Integer(script, rules, i++); Vector3 cut = llList2Vector(script, rules, i++); float hollow = llList2Float(script, rules, i++); Vector3 twist = llList2Vector(script, rules, i++); Vector3 topSize = llList2Vector(script, rules, i++); Vector3 topShear = llList2Vector(script, rules, i++); Vector3 advCut = llList2Vector(script, rules, i++); Vector3 taper = llList2Vector(script, rules, i++); float revolutions = llList2Float(script, rules, i++); float radiusOffset = llList2Float(script, rules, i++); float skew = llList2Float(script, rules, i++); Primitive.ConstructionData primData = ObjectManager.BuildBasicShape(PrimType.Torus); primData.Material = prim.Prim.PrimData.Material; primData.State = prim.Prim.PrimData.State; prim.Prim.PrimData = primData; prim.Prim.Sculpt = null; SetPrimShapeParams(prim, holeShape, cut, hollow, twist, topSize, topShear, advCut, taper, revolutions, radiusOffset, skew); break; } case LSLConstants.PRIM_TYPE_TUBE: { int holeShape = llList2Integer(script, rules, i++); Vector3 cut = llList2Vector(script, rules, i++); float hollow = llList2Float(script, rules, i++); Vector3 twist = llList2Vector(script, rules, i++); Vector3 topSize = llList2Vector(script, rules, i++); Vector3 topShear = llList2Vector(script, rules, i++); Vector3 advCut = llList2Vector(script, rules, i++); Vector3 taper = llList2Vector(script, rules, i++); float revolutions = llList2Float(script, rules, i++); float radiusOffset = llList2Float(script, rules, i++); float skew = llList2Float(script, rules, i++); Primitive.ConstructionData primData = ObjectManager.BuildBasicShape(PrimType.Tube); primData.Material = prim.Prim.PrimData.Material; primData.State = prim.Prim.PrimData.State; prim.Prim.PrimData = primData; prim.Prim.Sculpt = null; SetPrimShapeParams(prim, holeShape, cut, hollow, twist, topSize, topShear, advCut, taper, revolutions, radiusOffset, skew); break; } case LSLConstants.PRIM_TYPE_RING: { int holeShape = llList2Integer(script, rules, i++); Vector3 cut = llList2Vector(script, rules, i++); float hollow = llList2Float(script, rules, i++); Vector3 twist = llList2Vector(script, rules, i++); Vector3 topSize = llList2Vector(script, rules, i++); Vector3 topShear = llList2Vector(script, rules, i++); Vector3 advCut = llList2Vector(script, rules, i++); Vector3 taper = llList2Vector(script, rules, i++); float revolutions = llList2Float(script, rules, i++); float radiusOffset = llList2Float(script, rules, i++); float skew = llList2Float(script, rules, i++); Primitive.ConstructionData primData = ObjectManager.BuildBasicShape(PrimType.Ring); primData.Material = prim.Prim.PrimData.Material; primData.State = prim.Prim.PrimData.State; prim.Prim.PrimData = primData; prim.Prim.Sculpt = null; SetPrimShapeParams(prim, holeShape, cut, hollow, twist, topSize, topShear, advCut, taper, revolutions, radiusOffset, skew); break; } case LSLConstants.PRIM_TYPE_SCULPT: { string sculptMap = llList2String(script, rules, i++); SculptType type = (SculptType)llList2Integer(script, rules, i++); UUID textureID = InventoryKey(script, sculptMap, AssetType.Texture); if (textureID == UUID.Zero) { return; } Primitive.ConstructionData primData = ObjectManager.BuildBasicShape(PrimType.Sculpt); primData.Material = prim.Prim.PrimData.Material; primData.State = prim.Prim.PrimData.State; Primitive.SculptData sculpt = new Primitive.SculptData(); sculpt.Type = type; sculpt.SculptTexture = textureID; prim.Prim.PrimData = primData; prim.Prim.Sculpt = sculpt; break; } } }
private void _SculptMesh(List<List<Coord>> rows, SculptType sculptType, bool invert) { coords = new List<Coord>(); faces = new List<Face>(); sculptType = (SculptType)(((int)sculptType) & 0x07); int width = rows[0].Count; int p1, p2, p3, p4; int imageX, imageY; if (sculptType != SculptType.plane) { if (rows.Count % 2 == 0) { for (int rowNdx = 0; rowNdx < rows.Count; rowNdx++) rows[rowNdx].Add(rows[rowNdx][0]); } else { int lastIndex = rows[0].Count - 1; for (int i = 0; i < rows.Count; i++) rows[i][0] = rows[i][lastIndex]; } } Coord topPole = rows[0][width / 2]; Coord bottomPole = rows[rows.Count - 1][width / 2]; if (sculptType == SculptType.sphere) { if (rows.Count % 2 == 0) { int count = rows[0].Count; List<Coord> topPoleRow = new List<Coord>(count); List<Coord> bottomPoleRow = new List<Coord>(count); for (int i = 0; i < count; i++) { topPoleRow.Add(topPole); bottomPoleRow.Add(bottomPole); } rows.Insert(0, topPoleRow); rows.Add(bottomPoleRow); } else { int count = rows[0].Count; List<Coord> topPoleRow = rows[0]; List<Coord> bottomPoleRow = rows[rows.Count - 1]; for (int i = 0; i < count; i++) { topPoleRow[i] = topPole; bottomPoleRow[i] = bottomPole; } } } if (sculptType == SculptType.torus) rows.Add(rows[0]); int coordsDown = rows.Count; int coordsAcross = rows[0].Count; float widthUnit = 1.0f / (coordsAcross - 1); float heightUnit = 1.0f / (coordsDown - 1); for (imageY = 0; imageY < coordsDown; imageY++) { int rowOffset = imageY * coordsAcross; for (imageX = 0; imageX < coordsAcross; imageX++) { /* * p1-----p2 * | \ f2 | * | \ | * | f1 \| * p3-----p4 */ p4 = rowOffset + imageX; p3 = p4 - 1; p2 = p4 - coordsAcross; p1 = p3 - coordsAcross; this.coords.Add(rows[imageY][imageX]); if (imageY > 0 && imageX > 0) { Face f1, f2; if (invert) { f1 = new Face(p1, p4, p3); f2 = new Face(p1, p2, p4); } else { f1 = new Face(p1, p3, p4); f2 = new Face(p1, p4, p2); } this.faces.Add(f1); this.faces.Add(f2); } } } }
public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert) { _SculptMesh(sculptBitmap, sculptType, lod, viewerMode, mirror, invert); }
private static List<Vertex> GenerateSculptMesh(int sculptWidth, int sculptHeight, int sizeS, int sizeT, SculptType sculptType, bool invert, bool mirror, Bitmap sculptTexture) { bool reverseHorizontal = (invert) ? !mirror : mirror; List<Vertex> mesh = new List<Vertex>(sizeS * sizeT); Rectangle rect = new Rectangle(0, 0, sculptWidth, sculptHeight); BitmapData bmpData = sculptTexture.LockBits(rect, ImageLockMode.ReadOnly, sculptTexture.PixelFormat); int components = (sculptTexture.PixelFormat == (sculptTexture.PixelFormat | PixelFormat.Alpha)) ? 4 : 3; //int offset = bmpData.Stride - sculptWidth * components; for (int s = sizeS - 1; s >= 0; s--) { // Run along the profile for (int t = 0; t < sizeT; t++) { int reversedT = t; if (reverseHorizontal) reversedT = sizeT - t - 1; int x = (int)((float)reversedT / (sizeT - 1) * (float)sculptWidth); int y = (int)((float)s / (sizeS - 1) * (float)sculptHeight); if (y == 0) // Top row stitching { // Pinch? if (sculptType == SculptType.Sphere) x = sculptWidth / 2; } if (y == sculptHeight) // Bottom row stitching { // Wrap? if (sculptType == SculptType.Torus) y = 0; else y = sculptHeight - 1; // Pinch? if (sculptType == SculptType.Sphere) x = sculptWidth / 2; } if (x == sculptWidth) // Side stitching { // Wrap? if (sculptType == SculptType.Sphere || sculptType == SculptType.Torus || sculptType == SculptType.Cylinder) x = 0; else x = sculptWidth - 1; } Vector3 pos; unsafe { byte* ptr = (byte*)bmpData.Scan0 + (y * bmpData.Stride) + (x * components); pos = SculptRGBToVector(*(ptr + 2), *(ptr + 1), *(ptr + 0)); } if (mirror) pos.X *= -1f; // The rest of the vertex parameters will be set later mesh.Add(new Vertex { Position = pos }); } } sculptTexture.UnlockBits(bmpData); return mesh; }
void _SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert) { coords = new List<Coord>(); faces = new List<Face>(); normals = new List<Coord>(); uvs = new List<UVCoord>(); sculptType = (SculptType)(((int)sculptType) & 0x07); if (mirror) if (sculptType == SculptType.plane) invert = !invert; float sculptBitmapLod = (float)Math.Sqrt(sculptBitmap.Width * sculptBitmap.Height); float sourceScaleFactor = (float)(lod) / sculptBitmapLod; float fScale = 1.0f / sourceScaleFactor; int iScale = (int)fScale; if (iScale < 1) iScale = 1; if (iScale > 2 && iScale % 2 == 0) _SculptMesh(bitmap2Coords(ScaleImage(sculptBitmap, 64.0f / sculptBitmapLod, true), 64 / lod, mirror), sculptType, viewerMode, mirror, invert); else _SculptMesh(bitmap2Coords(sculptBitmap, iScale, mirror), sculptType, viewerMode, mirror, invert); }
private void _SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert) { _SculptMesh(new SculptMap(sculptBitmap, lod).ToRows(mirror), sculptType, viewerMode, mirror, invert); }
private void _SculptMesh(List <List <Coord> > rows, SculptType sculptType, bool viewerMode, bool mirror, bool invert) { coords = new List <Coord>(); faces = new List <Face>(); normals = new List <Coord>(); uvs = new List <UVCoord>(); sculptType = (SculptType)(((int)sculptType) & 0x07); if (mirror) { invert = !invert; } viewerFaces = new List <ViewerFace>(); int width = rows[0].Count; int p1, p2, p3, p4; int imageX, imageY; if (sculptType != SculptType.plane) { if (rows.Count % 2 == 0) { for (int rowNdx = 0; rowNdx < rows.Count; rowNdx++) { rows[rowNdx].Add(rows[rowNdx][0]); } } else { int lastIndex = rows[0].Count - 1; for (int i = 0; i < rows.Count; i++) { rows[i][0] = rows[i][lastIndex]; } } } Coord topPole = rows[0][width / 2]; Coord bottomPole = rows[rows.Count - 1][width / 2]; if (sculptType == SculptType.sphere) { if (rows.Count % 2 == 0) { int count = rows[0].Count; List <Coord> topPoleRow = new List <Coord>(count); List <Coord> bottomPoleRow = new List <Coord>(count); for (int i = 0; i < count; i++) { topPoleRow.Add(topPole); bottomPoleRow.Add(bottomPole); } rows.Insert(0, topPoleRow); rows.Add(bottomPoleRow); } else { int count = rows[0].Count; List <Coord> topPoleRow = rows[0]; List <Coord> bottomPoleRow = rows[rows.Count - 1]; for (int i = 0; i < count; i++) { topPoleRow[i] = topPole; bottomPoleRow[i] = bottomPole; } } } if (sculptType == SculptType.torus) { rows.Add(rows[0]); } int coordsDown = rows.Count; int coordsAcross = rows[0].Count; // int lastColumn = coordsAcross - 1; float widthUnit = 1.0f / (coordsAcross - 1); float heightUnit = 1.0f / (coordsDown - 1); for (imageY = 0; imageY < coordsDown; imageY++) { int rowOffset = imageY * coordsAcross; for (imageX = 0; imageX < coordsAcross; imageX++) { /* * p1-----p2 * | \ f2 | * | \ | * | f1 \| * p3-----p4 */ p4 = rowOffset + imageX; p3 = p4 - 1; p2 = p4 - coordsAcross; p1 = p3 - coordsAcross; this.coords.Add(rows[imageY][imageX]); if (viewerMode) { this.normals.Add(new Coord()); this.uvs.Add(new UVCoord(widthUnit * imageX, heightUnit * imageY)); } if (imageY > 0 && imageX > 0) { Face f1, f2; if (viewerMode) { if (invert) { f1 = new Face(p1, p4, p3, p1, p4, p3); f1.uv1 = p1; f1.uv2 = p4; f1.uv3 = p3; f2 = new Face(p1, p2, p4, p1, p2, p4); f2.uv1 = p1; f2.uv2 = p2; f2.uv3 = p4; } else { f1 = new Face(p1, p3, p4, p1, p3, p4); f1.uv1 = p1; f1.uv2 = p3; f1.uv3 = p4; f2 = new Face(p1, p4, p2, p1, p4, p2); f2.uv1 = p1; f2.uv2 = p4; f2.uv3 = p2; } } else { if (invert) { f1 = new Face(p1, p4, p3); f2 = new Face(p1, p2, p4); } else { f1 = new Face(p1, p3, p4); f2 = new Face(p1, p4, p2); } } this.faces.Add(f1); this.faces.Add(f2); } } } if (viewerMode) { calcVertexNormals(sculptType, coordsAcross, coordsDown); } }
private void calcVertexNormals(SculptType sculptType, int xSize, int ySize) { // compute vertex normals by summing all the surface normals of all the triangles sharing // each vertex and then normalizing int numFaces = this.faces.Count; for (int i = 0; i < numFaces; i++) { Face face = this.faces[i]; Coord surfaceNormal = face.SurfaceNormal(this.coords); this.normals[face.n1] += surfaceNormal; this.normals[face.n2] += surfaceNormal; this.normals[face.n3] += surfaceNormal; } int numNormals = this.normals.Count; for (int i = 0; i < numNormals; i++) this.normals[i] = this.normals[i].Normalize(); if (sculptType != SculptType.plane) { // blend the vertex normals at the cylinder seam for (int y = 0; y < ySize; y++) { int rowOffset = y*xSize; this.normals[rowOffset] = this.normals[rowOffset + xSize - 1] = (this.normals[rowOffset] + this.normals[rowOffset + xSize - 1]).Normalize(); } } #if (!ISWIN) foreach(Face face in this.faces) { ViewerFace vf = new ViewerFace(0) { v1 = this.coords[face.v1], v2 = this.coords[face.v2], v3 = this.coords[face.v3], coordIndex1 = face.v1, coordIndex2 = face.v2, coordIndex3 = face.v3, n1 = this.normals[face.n1], n2 = this.normals[face.n2], n3 = this.normals[face.n3], uv1 = this.uvs[face.uv1], uv2 = this.uvs[face.uv2], uv3 = this.uvs[face.uv3] }; this.viewerFaces.Add(vf); } #else foreach (ViewerFace vf in this.faces.Select(face => new ViewerFace(0) { v1 = this.coords[face.v1], v2 = this.coords[face.v2], v3 = this.coords[face.v3], coordIndex1 = face.v1, coordIndex2 = face.v2, coordIndex3 = face.v3, n1 = this.normals[face.n1], n2 = this.normals[face.n2], n3 = this.normals[face.n3], uv1 = this.uvs[face.uv1], uv2 = this.uvs[face.uv2], uv3 = this.uvs[face.uv3] })) { this.viewerFaces.Add(vf); } #endif }
public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode) { _SculptMesh(sculptBitmap, sculptType, lod, viewerMode, false, false); }
public SculptMesh(List <List <Vector3> > rows, SculptType sculptType, bool viewerMode, int lod) { uint vertsWanted = 1024; switch ((LevelDetail)lod) { case LevelDetail.Highest: vertsWanted = 1024; break; case LevelDetail.High: vertsWanted = 1024; break; case LevelDetail.Low: vertsWanted = 256; break; default: vertsWanted = 32; break; } // It is defined that the sculpt texture shall be no smaller than 64 pixels // and that the behavior with a 32 x 32 texture is uint height = (uint)rows.Count(); if (height < 2) { return; } uint width = (uint)rows[0].Count(); if (width < 2) { return; } // Sculpt textures must be powers of two. if (!((height & (~height + 1)) == height) || !((width & (~width + 1)) == width)) { return; } // Sculpties are limited to 1024 vertices. If the count is exceeded, the texture // sample rate will be reduced until the vertex count fits. ushort step = 1; uint verts = width * height; while (verts > vertsWanted) { step <<= 1; // In the below cases, this LOD has no geometry (doesn't show) if (step >= width) { return; } if (step >= height) { return; } verts >>= 2; } sculptType = (SculptType)(((int)sculptType) & 0x07); ushort horizontalDivisions = (ushort)(width / step); ushort verticalDivisions = (ushort)(height / step); ushort matrixWidth = (ushort)(horizontalDivisions + 1); ushort matrixHeight = (ushort)(verticalDivisions + 1); float divisionU = 1.0f / (float)horizontalDivisions; float divisionV = 1.0f / (float)verticalDivisions; // Reduce the input texture to our coordinate matrix. This greatly simplifies // what is to come. Vector3[,] matrix = new Vector3[matrixHeight, matrixWidth]; int v, vv; int h, hh; int oneMinushalfStep = -step / 2; oneMinushalfStep += step; for (v = 0, vv = 0; v < (int)height; ++vv, v += step) { for (h = 0, hh = 0; h < (int)width; ++hh, h += step) { matrix[vv, hh] = rows[v][h]; } if (step > 1) { if (step > 2) { matrix[vv, hh] = rows[v][h - oneMinushalfStep]; } else { matrix[vv, hh] = rows[v][h - 1]; } } else { // This WILL cause texture mapping errors but we have no // closer approximation to the data needed here. matrix[vv, hh] = matrix[vv, hh - 1]; } } for (h = 0, hh = 0; h < (int)width; ++hh, h += step) { if (step > 1) { if (step > 2) { matrix[vv, hh] = rows[v - oneMinushalfStep][h]; } else { matrix[vv, hh] = rows[v - 1][h]; } } else { matrix[vv, hh] = matrix[vv - 1, hh]; } } if (hh == matrixWidth - 1 && h == width && step > 1) { if (step > 2) { matrix[vv, hh] = rows[v - oneMinushalfStep][h - 1]; } else { matrix[vv, hh] = rows[v - 1][h - 1]; } } if (sculptType == SculptType.sphere) { // Find the poles for spherical sitching // The south pole is taken from the "extra" row (33) data // unless the source texture is 32 pixels tall. In that case // it is taken from the center of the last valid row. The // results may be undefined. Vector3 northPole = matrix[0, matrixWidth / 2]; Vector3 southPole = matrix[matrixHeight - 1, matrixWidth / 2]; // Spherical sculpts get all vertices in the 1st and 33rd // row stitched to a common "pole" taken from the center // of the top and the last valid input row. // The coordinates in the top row get overwritten by this // operation. for (int h1 = 0; h1 < matrixWidth; ++h1) { matrix[0, h1] = northPole; matrix[matrixHeight - 1, h1] = southPole; } } // For these two, stitch sides left to right if (sculptType == SculptType.sphere || sculptType == SculptType.cylinder || sculptType == SculptType.torus) { for (int v1 = 0; v1 < matrixHeight; ++v1) { matrix[v1, matrixWidth - 1] = matrix[v1, 0]; } } // For this one, stitch top to bottom as well if (sculptType == SculptType.torus) { for (int h1 = 0; h1 < matrixWidth; ++h1) { matrix[matrixHeight - 1, h1] = matrix[0, h1]; } } coords.Clear(); normals.Clear(); faces.Clear(); int p1, p2, p3, p4; for (int imageY = 0; imageY < matrixHeight; imageY++) { int rowOffset = imageY * matrixWidth; for (int imageX = 0; imageX < matrixWidth; imageX++) { //* //* p1-----p2 //* | \ f2 | //* | \ | //* | f1 \| //* p3-----p4 //* p4 = rowOffset + imageX; p3 = p4 - 1; p2 = p4 - matrixWidth; p1 = p3 - matrixWidth; coords.Add(matrix[imageY, imageX]); if (viewerMode) { normals.Add(new Vector3()); uvs.Add(new Vector2(divisionU * imageX, divisionV * imageY)); } if (imageY > 0 && imageX > 0) { Face f; f = new Face(p1, p3, p4); faces.Add(f); f = new Face(p1, p4, p2); faces.Add(f); } } } if (viewerMode) { calcVertexNormals(sculptType, matrixWidth, matrixHeight); } }
public SculptMesh(List<List<Coord>> rows, SculptType sculptType, bool viewerMode, bool mirror, bool invert) { _SculptMesh(rows, sculptType, viewerMode, mirror, invert); }
void _SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert) { coords = new List <Coord>(); faces = new List <Face>(); normals = new List <Coord>(); uvs = new List <UVCoord>(); if (mirror) { if (sculptType == SculptType.plane) { invert = !invert; } } float sourceScaleFactor = (float)(lod) / (float)Math.Sqrt(sculptBitmap.Width * sculptBitmap.Height); bool scaleSourceImage = sourceScaleFactor < 1.0f ? true : false; Bitmap bitmap; if (scaleSourceImage) { bitmap = ScaleImage(sculptBitmap, sourceScaleFactor); } else { bitmap = sculptBitmap; } viewerFaces = new List <ViewerFace>(); int width = bitmap.Width; int height = bitmap.Height; float widthUnit = 1.0f / width; float heightUnit = 1.0f / (height - 1); int p1, p2, p3, p4; Color color; float x, y, z; int imageX, imageY; if (sculptType == SculptType.sphere) { int lastRow = height - 1; // poles of sphere mesh are the center pixels of the top and bottom rows Color newC1 = bitmap.GetPixel(width / 2, 0); Color newC2 = bitmap.GetPixel(width / 2, lastRow); for (imageX = 0; imageX < width; imageX++) { bitmap.SetPixel(imageX, 0, newC1); bitmap.SetPixel(imageX, lastRow, newC2); } } int pixelsDown = sculptType == SculptType.plane ? height : height + 1; int pixelsAcross = sculptType == SculptType.plane ? width : width + 1; for (imageY = 0; imageY < pixelsDown; imageY++) { int rowOffset = imageY * width; for (imageX = 0; imageX < pixelsAcross; imageX++) { /* * p1-----p2 * | \ f2 | * | \ | * | f1 \| * p3-----p4 */ if (imageX < width) { p4 = rowOffset + imageX; p3 = p4 - 1; } else { p4 = rowOffset; // wrap around to beginning p3 = rowOffset + imageX - 1; } p2 = p4 - width; p1 = p3 - width; color = bitmap.GetPixel(imageX == width ? 0 : imageX, imageY == height ? height - 1 : imageY); x = (color.R - 128) * pixScale; if (mirror) { x = -x; } y = (color.G - 128) * pixScale; z = (color.B - 128) * pixScale; Coord c = new Coord(x, y, z); this.coords.Add(c); if (viewerMode) { this.normals.Add(new Coord()); this.uvs.Add(new UVCoord(widthUnit * imageX, heightUnit * imageY)); } if (imageY > 0 && imageX > 0) { Face f1, f2; if (viewerMode) { if (invert) { f1 = new Face(p1, p4, p3, p1, p4, p3); f1.uv1 = p1; f1.uv2 = p4; f1.uv3 = p3; f2 = new Face(p1, p2, p4, p1, p2, p4); f2.uv1 = p1; f2.uv2 = p2; f2.uv3 = p4; } else { f1 = new Face(p1, p3, p4, p1, p3, p4); f1.uv1 = p1; f1.uv2 = p3; f1.uv3 = p4; f2 = new Face(p1, p4, p2, p1, p4, p2); f2.uv1 = p1; f2.uv2 = p4; f2.uv3 = p2; } } else { if (invert) { f1 = new Face(p1, p4, p3); f2 = new Face(p1, p2, p4); } else { f1 = new Face(p1, p3, p4); f2 = new Face(p1, p4, p2); } } this.faces.Add(f1); this.faces.Add(f2); } } } if (scaleSourceImage) { bitmap.Dispose(); } if (viewerMode) { calcVertexNormals(sculptType, width, height); } }
private void _SculptMesh(List<List<Coord>> rows, SculptType sculptType, bool viewerMode, bool mirror, bool invert) { coords = new List<Coord>(); faces = new List<Face>(); normals = new List<Coord>(); uvs = new List<UVCoord>(); sculptType = (SculptType) (((int) sculptType) & 0x07); if (mirror) invert = !invert; viewerFaces = new List<ViewerFace>(); int width = rows[0].Count; int p1, p2, p3, p4; int imageX, imageY; if (sculptType != SculptType.plane) { if (rows.Count%2 == 0) { foreach (List<Coord> t in rows) t.Add(t[0]); } else { int lastIndex = rows[0].Count - 1; foreach (List<Coord> t in rows) t[0] = t[lastIndex]; } } Coord topPole = rows[0][width/2]; Coord bottomPole = rows[rows.Count - 1][width/2]; if (sculptType == SculptType.sphere) { if (rows.Count%2 == 0) { int count = rows[0].Count; List<Coord> topPoleRow = new List<Coord>(count); List<Coord> bottomPoleRow = new List<Coord>(count); for (int i = 0; i < count; i++) { topPoleRow.Add(topPole); bottomPoleRow.Add(bottomPole); } rows.Insert(0, topPoleRow); rows.Add(bottomPoleRow); } else { int count = rows[0].Count; List<Coord> topPoleRow = rows[0]; List<Coord> bottomPoleRow = rows[rows.Count - 1]; for (int i = 0; i < count; i++) { topPoleRow[i] = topPole; bottomPoleRow[i] = bottomPole; } } } if (sculptType == SculptType.torus) rows.Add(rows[0]); int coordsDown = rows.Count; int coordsAcross = rows[0].Count; float widthUnit = 1.0f/(coordsAcross - 1); float heightUnit = 1.0f/(coordsDown - 1); for (imageY = 0; imageY < coordsDown; imageY++) { int rowOffset = imageY*coordsAcross; for (imageX = 0; imageX < coordsAcross; imageX++) { /* * p1-----p2 * | \ f2 | * | \ | * | f1 \| * p3-----p4 */ p4 = rowOffset + imageX; p3 = p4 - 1; p2 = p4 - coordsAcross; p1 = p3 - coordsAcross; this.coords.Add(rows[imageY][imageX]); if (viewerMode) { this.normals.Add(new Coord()); this.uvs.Add(new UVCoord(widthUnit*imageX, heightUnit*imageY)); } if (imageY > 0 && imageX > 0) { Face f1, f2; if (viewerMode) { if (invert) { f1 = new Face(p1, p4, p3, p1, p4, p3) {uv1 = p1, uv2 = p4, uv3 = p3}; f2 = new Face(p1, p2, p4, p1, p2, p4) {uv1 = p1, uv2 = p2, uv3 = p4}; } else { f1 = new Face(p1, p3, p4, p1, p3, p4) {uv1 = p1, uv2 = p3, uv3 = p4}; f2 = new Face(p1, p4, p2, p1, p4, p2) {uv1 = p1, uv2 = p4, uv3 = p2}; } } else { if (invert) { f1 = new Face(p1, p4, p3); f2 = new Face(p1, p2, p4); } else { f1 = new Face(p1, p3, p4); f2 = new Face(p1, p4, p2); } } this.faces.Add(f1); this.faces.Add(f2); } } } if (viewerMode) calcVertexNormals(sculptType, coordsAcross, coordsDown); }
void _SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert) { coords = new List <Coord>(); faces = new List <Face>(); normals = new List <Coord>(); uvs = new List <UVCoord>(); sculptType = (SculptType)(((int)sculptType) & 0x07); if (mirror) { if (sculptType == SculptType.plane) { invert = !invert; } } float sourceScaleFactor = (float)(lod) / (float)Math.Sqrt(sculptBitmap.Width * sculptBitmap.Height); int scale = (int)(1.0f / sourceScaleFactor); if (scale < 1) { scale = 1; } List <List <Coord> > rows = bitmap2Coords(sculptBitmap, scale, mirror); viewerFaces = new List <ViewerFace>(); int width = sculptBitmap.Width / scale; // int height = sculptBitmap.Height / scale; int p1, p2, p3, p4; int imageX, imageY; if (sculptType != SculptType.plane) { for (int rowNdx = 0; rowNdx < rows.Count; rowNdx++) { rows[rowNdx].Add(rows[rowNdx][0]); } } Coord topPole = rows[0][width / 2]; Coord bottomPole = rows[rows.Count - 1][width / 2]; if (sculptType == SculptType.sphere) { int count = rows[0].Count; List <Coord> topPoleRow = new List <Coord>(count); List <Coord> bottomPoleRow = new List <Coord>(count); for (int i = 0; i < count; i++) { topPoleRow.Add(topPole); bottomPoleRow.Add(bottomPole); } rows.Insert(0, topPoleRow); rows.Add(bottomPoleRow); } else if (sculptType == SculptType.torus) { rows.Add(rows[0]); } int coordsDown = rows.Count; int coordsAcross = rows[0].Count; float widthUnit = 1.0f / (coordsAcross - 1); float heightUnit = 1.0f / (coordsDown - 1); for (imageY = 0; imageY < coordsDown; imageY++) { int rowOffset = imageY * coordsAcross; for (imageX = 0; imageX < coordsAcross; imageX++) { /* * p1-----p2 * | \ f2 | * | \ | * | f1 \| * p3-----p4 */ p4 = rowOffset + imageX; p3 = p4 - 1; p2 = p4 - coordsAcross; p1 = p3 - coordsAcross; this.coords.Add(rows[imageY][imageX]); if (viewerMode) { this.normals.Add(new Coord()); this.uvs.Add(new UVCoord(widthUnit * imageX, heightUnit * imageY)); } if (imageY > 0 && imageX > 0) { Face f1, f2; if (viewerMode) { if (invert) { f1 = new Face(p1, p4, p3, p1, p4, p3); f1.uv1 = p1; f1.uv2 = p4; f1.uv3 = p3; f2 = new Face(p1, p2, p4, p1, p2, p4); f2.uv1 = p1; f2.uv2 = p2; f2.uv3 = p4; } else { f1 = new Face(p1, p3, p4, p1, p3, p4); f1.uv1 = p1; f1.uv2 = p3; f1.uv3 = p4; f2 = new Face(p1, p4, p2, p1, p4, p2); f2.uv1 = p1; f2.uv2 = p4; f2.uv3 = p2; } } else { if (invert) { f1 = new Face(p1, p4, p3); f2 = new Face(p1, p2, p4); } else { f1 = new Face(p1, p3, p4); f2 = new Face(p1, p4, p2); } } this.faces.Add(f1); this.faces.Add(f2); } } } if (viewerMode) { calcVertexNormals(sculptType, coordsAcross, coordsDown); } }
void _SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert) { coords = new List<Coord>(); faces = new List<Face>(); normals = new List<Coord>(); uvs = new List<UVCoord>(); sculptType = (SculptType)(((int)sculptType) & 0x07); if (mirror) if (sculptType == SculptType.plane) invert = !invert; float sourceScaleFactor = (float)(lod) / (float)Math.Sqrt(sculptBitmap.Width * sculptBitmap.Height); int scale = (int)(1.0f / sourceScaleFactor); if (scale < 1) scale = 1; _SculptMesh(bitmap2Coords(sculptBitmap, scale, mirror), sculptType, viewerMode, mirror, invert); }
private void calcVertexNormals(SculptType sculptType, int xSize, int ySize) { normals.Clear(); for (int i = 0; i < coords.Count(); i++) { normals[i] = new Vector3(); } int numFaces = faces.Count(); for (int i = 0; i < numFaces; i++) { Face face = faces[i]; Vector3 surfaceNormal = face.SurfaceNormal(coords); normals[face.v1] += surfaceNormal; normals[face.v2] += surfaceNormal; normals[face.v3] += surfaceNormal; } if (sculptType == SculptType.sphere) { Vector3 avg = new Vector3(0, 0, 0); for (int i = 0; i < xSize; i++) { avg += normals[i]; } for (int i = 0; i < xSize; i++) { normals[i] = avg; } avg.X = 0; avg.Y = 0; avg.Z = 0; int lastrow = xSize * (ySize - 1); for (int i = lastrow; i < lastrow + xSize; i++) { avg += normals[i]; } for (int i = lastrow; i < lastrow + xSize; i++) { normals[i] = avg; } } if (sculptType == SculptType.sphere || sculptType == SculptType.cylinder || sculptType == SculptType.torus) { // blend the vertex normals at the cylinder seam int xminusOne = xSize - 1; for (int y = 0; y < ySize; y++) { int rowOffset = y * xSize; normals[rowOffset] = normals[rowOffset + xminusOne] = (normals[rowOffset] + normals[rowOffset + xminusOne]); } } if (sculptType == SculptType.torus) { int lastrow = xSize * (ySize - 1); for (int x = 0; x < xSize; x++) { normals[x] = normals[lastrow + x] = (normals[x] + normals[lastrow + x]); } } int numNormals = normals.Count(); for (int i = 0; i < numNormals; i++) { normals[i] = Vector3.Normalize(normals[i]); } }