1521 lines
51 KiB
C#

//********************************************************************************************************************************************
//*********************************** Whirld - by Aubrey Falconer ****************************************************************************
//**** http://AubreyFalconer.com **** http://web.archive.org/web/20120519040400/http://www.unifycommunity.com/wiki/index.php?title=Whirld ****
//********************************************************************************************************************************************
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Runtime.CompilerServices;
//using Ionic.Zlib;
using System.IO.Compression;
using UnityEngine;
[Serializable]
public enum WhirldInStatus
{
Idle,
Working,
Success,
WWWError,
SyntaxError
}
[Serializable]
public class WhirldIn : System.Object
{
public WhirldInStatus status = WhirldInStatus.Idle;
public string statusTxt = "";
public float progress = 0.00f;
public string info = "";
public string url = "";
public string data;
public GameObject world;
public GameObject whirldBuffer;
public string worldName = "World";
public string urlPath;
public Hashtable worldParams = new Hashtable();
public Hashtable threads = new Hashtable();
public int threadAssetBundles = 0;
public int threadTextures = 0;
public int maxThreads = 5;
public List<AssetBundle> loadedAssetBundles = new List<AssetBundle>();
public Hashtable objects = new Hashtable();
public Hashtable textures = new Hashtable();
public Hashtable meshMaterials = new Hashtable();
public Hashtable meshMatLibs = new Hashtable();
public MonoBehaviour monoBehaviour; //Needed for attaching Coroutines too
public int readChr = 0;
public void Load()
{
whirldBuffer = new GameObject("WhirldBuffer");
monoBehaviour = (MonoBehaviour)whirldBuffer.AddComponent(typeof(MonoBehaviourScript));
monoBehaviour.StartCoroutine(Generate());
}
public void Cleanup()
{
//We are still loading the world
if ((bool)whirldBuffer && (bool)monoBehaviour)
{
monoBehaviour.StopAllCoroutines();
GameObject.Destroy(whirldBuffer);
}
//Unload AssetBundles
if (loadedAssetBundles.Count > 0)
{
foreach (AssetBundle ab in loadedAssetBundles)
{
ab.Unload(true);
}
loadedAssetBundles.Clear();
}
}
public IEnumerator Generate()
{
status = WhirldInStatus.Working;
if (url != "")
{
//Download Whirld File
statusTxt = "Downloading World Definition";
info = "";
urlPath = url.Substring(0, url.LastIndexOf("/") + 1);
WWW www = new WWW(url);
while (!www.isDone)
{
progress = www.progress;
yield return new WaitForSeconds(0.1f);
}
progress = 1f;
//Verify Successful Download
if (www.error != null)
{
info =
"Failed to download Whirld definition file: " +
url +
" (" +
www.error +
")\n";
status = WhirldInStatus.WWWError;
yield break;
}
data = www.data;
}
//Init
readChr = 0;
world = GameObject.Find("World");
if (world) GameObject.Destroy(world);
world = new GameObject("World");
statusTxt = "Parsing World Definition";
//Sanity Check
if (
data == null ||
data.Length < 10 ||
(data[0] != '[' && data[0] != '{'))
{
status = WhirldInStatus.SyntaxError;
yield break;
}
//Read Whirld Headers
String n = null;
String v = null;
while (true)
{
//Read next char
char s = data[readChr];
readChr++;
//Incorrectly nested header []s
if (readChr >= data.Length)
{
status = WhirldInStatus.SyntaxError;
yield break;
}
//Ignore Newlines and Tabs
else if (s == '\n' || s == '\t') continue;
else if (s == '{') break; //Finished reading headers
else if (s == '[') //Beginning new header
{
n = "";
v = "";
}
//Header name read, read value
else if (s == ':' && n == "")
{
n = v;
v = "";
}
//Header ended
else if (s == ']')
{
//[name] header
if (n == "")
{
n = v;
v = "";
}
//AssetBundle
if (n == "ab") monoBehaviour.StartCoroutine_Auto(LoadAssetBundle(v));
//StreamedScene
if (n == "ss") monoBehaviour.StartCoroutine_Auto(LoadStreamedScene(v));
//Skybox
else if (n == "rndSkybox") monoBehaviour.StartCoroutine_Auto(LoadSkybox(v));
//Texture
else if (n == "txt") monoBehaviour.StartCoroutine_Auto(LoadTexture(v));
//Mesh
else if (n == "msh") monoBehaviour.StartCoroutine_Auto(LoadMesh(v));
//Terrain
else if (n == "trn") monoBehaviour.StartCoroutine_Auto(LoadTerrain(v));
//Rendering Settings
else if (
n == "rndFogColor" ||
n == "rndFogDensity" ||
n == "rndAmbientLight" ||
n == "rndHaloStrength" ||
n == "rndFlareStrength")
{
String[] vS = v.Split(","[0]);
if (n == "rndFogColor")
{
RenderSettings.fogColor = new Color(
float.Parse(vS[0]),
float.Parse(vS[1]),
float.Parse(vS[2]),
1);
}
else if (n == "rndFogDensity")
{
RenderSettings.fogDensity = float.Parse(v);
}
else if (n == "rndAmbientLight")
{
RenderSettings.ambientLight = new Color(
float.Parse(vS[0]),
float.Parse(vS[1]),
float.Parse(vS[2]),
float.Parse(vS[3]));
}
else if (n == "rndHaloStrength")
{
RenderSettings.haloStrength = float.Parse(v);
}
else if (n == "rndFlareStrength")
{
RenderSettings.flareStrength = float.Parse(v);
}
}
//Arbitrary Data
else worldParams.Add(n, v);
}
//Header char read
else v += s;
}
statusTxt = "Downloading World Assets";
//Wait for all "threads" to finish working
while (threads.Count > 0)
{
yield return null;
}
//Generate World
statusTxt = "Initializing World";
ReadObject(world.transform);
//Add TerrainControllers to Terrain objects
foreach (Terrain trn in GameObject.FindObjectsOfType(typeof(Terrain)))
{
((TerrainController)trn.gameObject.AddComponent(typeof(TerrainController))).trnDat = trn.terrainData;
}
//Cleanup
GameObject.Destroy(whirldBuffer);
//Send Scene Generation Notice to each object
foreach (GameObject go in GameObject.FindObjectsOfType(typeof(GameObject)))
{
go.SendMessage(
"OnSceneGenerated",
SendMessageOptions.DontRequireReceiver);
}
//Success!
status = WhirldInStatus.Success;
statusTxt = "World Loaded Successfully";
if (info != "")
{
Debug.Log("Whirld Loading Info: " + info);
}
}
public IEnumerator LoadAssetBundle(string p)
{
threadAssetBundles++;
while (threads.Count >= maxThreads) yield return null; //Don't overwhelm the computer by doing too many things @ once
//Presets
String thread = System.IO.Path.GetFileNameWithoutExtension(p);
threads.Add(thread, "");
String url = p;
//Download StreamedScene
url = GetURL(url);
WWW www = new WWW(url);
while (!www.isDone)
{
threads[thread] = www.progress;
yield return null;
}
if (www.error != null || !www.assetBundle)
{
if (!www.assetBundle) info +=
"Referenced file is not an AssetBundle: " +
url +
"\n";
else info +=
"Failed to download asset file: " +
url +
" (" +
www.error +
")\n";
threads.Remove(thread);
threadAssetBundles--;
yield break;
}
//Load AssetBundle
threads[thread] = "Initializing Bundle";
loadedAssetBundles.Add(www.assetBundle);
//Success
threads.Remove(thread);
threadAssetBundles--;
}
public IEnumerator LoadStreamedScene(string p)
{
while (threads.Count >= maxThreads) yield return null; //Don't overwhelm the computer by doing too many things @ once
//Presets
String thread = "SceneData";
threads.Add(thread, "");
String nme = "World";
String url = "Whirld.unity3d";
//Object Parameters
if (p != "") //[ss:sceneName,url]
{
String[] pS = p.Split(","[0]);
if (pS[0] != null) nme = pS[0];
if (pS[1] != null) url = pS[1];
}
//Download StreamedScene
url = GetURL(url);
WWW www = new WWW(url);
while (!www.isDone)
{
threads[thread] = www.progress;
yield return null;
}
if (www.error != null || !www.assetBundle)
{
if (!www.assetBundle) info +=
"StreamedScene file contains no scenes: " +
url +
"\n";
else info +=
"Failed to download asset file: " +
url +
" (" +
www.error +
")\n";
threads.Remove(thread);
yield break;
}
//Wait for all AssetBundles to load
threads[thread] = "Loading Asset Dependencies";
while (threadAssetBundles > 0) yield return null;
threads.Remove(thread);
thread = "SceneInit";
threads.Add(thread, "...");
//Load StreamedScene
AssetBundle blah = www.assetBundle;
AsyncOperation async = Application.LoadLevelAdditiveAsync(nme);
float tme = Time.time;
while (!async.isDone)
{
threads[thread] = (Time.time - tme) + "...";
yield return null;
}
//Success
loadedAssetBundles.Add(www.assetBundle);
threads.Remove(thread);
}
public IEnumerator LoadTexture(string p) //[txt:name,url,wrapMode,anisoLevel]
{
threadTextures++;
//Don't overwhelm the computer by doing too many things @ once
while (threads.Count >= maxThreads) yield return null;
String[] vS = p.Split(","[0]);
String thread = "Txt" +
threadTextures +
" - " +
vS[0];
threads.Add(thread, "");
String url = GetURL(vS[1]);
WWW www = new WWW(url);
while (!www.isDone)
{
threads[thread] = www.progress;
yield return null;
}
if (www.error != null)
{
info +=
"Failed to download texture: " +
url +
" (" +
www.error +
")\n";
threads.Remove(thread);
threadTextures--;
yield break;
}
threads[thread] = "Initializing";
//Texture2D txt = www.texture;
Texture2D txt = new Texture2D(
4,
4,
TextureFormat.DXT1,
true);
www.LoadImageIntoTexture(txt);
txt.wrapMode = (
(vS[2] == null || float.Parse(vS[2]) == 0f) ?
TextureWrapMode.Clamp :
TextureWrapMode.Repeat);
txt.anisoLevel = (vS[3] != null ? int.Parse(vS[3]) : 1);
txt.Apply(true);
txt.Compress(true);
textures.Add(vS[0], txt);
threads.Remove(thread);
threadTextures--;
}
public IEnumerator LoadMeshTexture(string url, string materialName)
{
threadTextures++;
//Don't overwhelm the computer by doing too many things @ once
while (threads.Count >= maxThreads) yield return null;
String thread = "MshTxt" +
threadTextures +
" - " +
materialName;
threads.Add(thread, "");
url = GetURL(url);
WWW www = new WWW(url);
while (!www.isDone)
{
threads[thread] = www.progress;
yield return null;
}
if (www.error != null)
{
info +=
"Failed to download mesh texture: " +
url +
" (" +
www.error +
")\n";
threads.Remove(thread);
threadTextures--;
yield break;
}
threads[thread] = "Initializing";
Texture2D mshTxt = new Texture2D(
4,
4,
TextureFormat.DXT1,
true);
www.LoadImageIntoTexture(mshTxt);
mshTxt.wrapMode = TextureWrapMode.Repeat;
mshTxt.Apply(true);
mshTxt.Compress(true);
((Material)meshMaterials[materialName]).mainTexture = mshTxt;
threads.Remove(thread);
threadTextures--;
}
public IEnumerator LoadMesh(string v) //[msh:name,url]
{
Mesh msh = new Mesh();
List<Vector3> verts = new List<Vector3>();
List<Vector3> norms = new List<Vector3>();
List<Vector2> uvs = new List<Vector2>();
List<int> tris = new List<int>();
List<List<int>> triangles = new List<List<int>>();
List<Material> mats = new List<Material>();
//Don't overwhelm the computer by doing too many things @ once
while (threads.Count >= maxThreads) yield return null;
//Init Thread
String[] vS = v.Split(","[0]);
String thread = vS[0];
threads.Add(thread, "");
//Download Mesh Object
int hasCollider = (vS.Length > 2 ? int.Parse(vS[2]) : 0);
WWW www = new WWW(GetURL(vS[1]));
while (!www.isDone)
{
threads[thread] = www.progress;
yield return null;
}
if (www.error != null)
{
info +=
"Failed to download mesh: " +
url +
" (" +
www.error +
")\n";
threads.Remove(thread);
yield break;
}
//Download All Textures Before Generating Mesh
//threads[thread] = "Loading Textures";
//while(threadTextures > 0) yield return null;
//Uncompress as necessary...
threads[thread] = "Decompressing";
yield return null; //Rebuild GUI as we may be working for a while
int lastDot = vS[1].LastIndexOf(".");
String data;
if (vS[1].Substring(lastDot + 1) == "gz")
{
//data = GZipStream.UncompressString(www.bytes);
GZipStream gz = new GZipStream(new MemoryStream(www.bytes), CompressionMode.Decompress);
byte[] buf = new byte[www.bytes.Length];
gz.Read(buf, 0, buf.Length);
data = buf.ToString();
vS[1] = vS[1].Substring(0, lastDot);
}
else data = www.data;
threads[thread] = "Generating";
lastDot = vS[1].LastIndexOf(".");
String ext = vS[1].Substring(lastDot + 1);
//Binary UnityMesh Object
if (ext == "utm")
{
//MeshSerializer has been depricated - it's totally nonstandard, and it didn't support submeshes anyway
//Mesh msh = MeshSerializer.ReadMesh(www.bytes);
}
//.obj File
else if (ext == "obj")
{
float timer = Time.time + 0.1f;
String[] file = data.Split("\n"[0]);
foreach (String str in file)
{
if (str == "") continue;
String[] l = str.Split(" "[0]);
if (l[0] == "v")
{
verts.Add(new Vector3(
-float.Parse(l[1]),
float.Parse(l[2]),
float.Parse(l[3])));
}
else if (l[0] == "vn")
{
norms.Add(new Vector3(
float.Parse(l[1]),
float.Parse(l[2]),
float.Parse(l[3])));
}
else if (l[0] == "vt")
{
uvs.Add(new Vector2(
float.Parse(l[1]),
float.Parse(l[2])));
}
else if (l[0] == "f")
{
if (l.Length == 4)
{
tris.Add(int.Parse(l[2].Substring(
0,
l[2].IndexOf("/"))) - 1);
tris.Add(int.Parse(l[1].Substring(
0,
l[2].IndexOf("/"))) - 1);
tris.Add(int.Parse(l[3].Substring(
0,
l[2].IndexOf("/"))) - 1);
}
//Attempt to triangulate face - hardly works, could use better routine here...
else
{
int i;
for (i = 2; i < l.Length; i++)
{
tris.Add(int.Parse(l[i].Substring(
0,
l[i].IndexOf("/"))) - 1);
if (i % 2 == 0)
{
tris.Add(int.Parse(l[1].Substring(
0,
l[1].IndexOf("/"))) - 1);
}
}
while (tris.Count % 3 != 0)
{
tris.Add(int.Parse(l[i = 2].Substring(
0,
l[i - 2].IndexOf("/"))) - 1);
}
}
}
else if (l[0] == "usemtl")
{
if (meshMaterials.ContainsKey(l[1]))
{
mats.Add((Material)meshMaterials[l[1]]);
}
else
{
info +=
"Mesh Material Missing: " +
l[1] +
"\n";
mats.Add(null);
}
if (tris.Count > 0)
{
triangles.Add(tris);
tris = new List<int>();
}
}
else if (l[0] == "mtllib") //Time to load a material library!
{
if (!meshMatLibs.ContainsKey(l[1]))
{
//Only load a material library once, even if it is referenced by multiple meshes
meshMatLibs.Add(l[1], true);
www = new WWW(GetURL(l[1]));
while (!www.isDone)
{
threads[thread] =
"Downloading Material Library (" +
Mathf.RoundToInt(www.progress * 100) +
"%)";
//yield return null;
}
if (www.error != null)
{
info +=
"Mesh Material Library Undownloadable: " +
GetURL(l[1]) +
" (" +
www.error +
")\n";
}
else
{
threads[thread] = "Initializing " + vS[0] + "";
//yield return null;
String[] meshlib = www.data.Split("\n"[0]);
Material curMat = null;
int offset = -1;
while (true)
{
offset = www.data.IndexOf("map_Ka", offset + 1);
if (offset == -1) break;
}
foreach (String meshline in meshlib)
{
String[] ml = meshline.Split(" "[0]);
if (ml[0] == "newmtl") //Beginning of new material
{
if (curMat) //Save current material
{
meshMaterials.Add(curMat.name, curMat);
}
curMat = new Material(Shader.Find("VertexLit"));
curMat.name = ml[1];
}
else if (ml[0] == "#Shader") //Set shader of current material
{
String shdr = meshline.Substring(8).Replace("Diffuse", "VertexLit");
if (shdr != "VertexLit" && shdr != "VertexLit Fast")
{
curMat.shader = Shader.Find(shdr);
}
}
else if (ml[0] == "Ka") //Set color of current material
{
curMat.color = new Color(
float.Parse(ml[1]),
float.Parse(ml[2]),
float.Parse(ml[3]),
1f);
}
else if (ml[0] == "Kd")
{
curMat.SetColor("_Emission", new Color(
float.Parse(ml[1]),
float.Parse(ml[2]),
float.Parse(ml[3]),
1f));
}
else if (ml[0] == "Ks")
{
curMat.SetColor("_SpecColor", new Color(
float.Parse(ml[1]),
float.Parse(ml[2]),
float.Parse(ml[3]),
1f));
}
else if (ml[0] == "Ns")
{
curMat.SetFloat("_Shininess", float.Parse(ml[1]));
}
else if (ml[0] == "map_Ka") //Set texture of current material
{
curMat.mainTextureOffset = new Vector2(
float.Parse(ml[2]),
float.Parse(ml[3]));
curMat.mainTextureScale = new Vector2(
float.Parse(ml[5]),
float.Parse(ml[6]));
monoBehaviour.StartCoroutine_Auto(LoadMeshTexture(
ml[7],
curMat.name));
}
else if (ml[0] == "d") //Set alpha cutoff of current material
{
//curMat.shader = Shader.Find("Transparent/Cutout/VertexLit");
//curMat.SetFloat("_Cutoff", float.Parse(ml[1]));
}
}
if (curMat) //Save last material (others get saved as file is read)
{
meshMaterials.Add(curMat.name, curMat);
}
}
}
}
if (Time.time > timer) //Refresh GUI 10 times per second to keep the user entertained
{
timer = Time.time + 0.1f;
yield return null;
}
}
threads[thread] = "Initializing";
msh.vertices = verts.ToArray();
msh.normals = norms.ToArray();
msh.uv = uvs.ToArray();
if (triangles.Count > 0)
{
triangles.Add(tris);
msh.subMeshCount = triangles.Count;
for (int i = 0; i < triangles.Count; i++)
{
msh.SetTriangles(triangles[i].ToArray(), i);
}
}
else msh.triangles = tris.ToArray();
}
//Unknown File Type
else info +=
"Mesh Type Unrecognized: " +
vS[0] +
" " +
vS[1] +
" (." +
ext +
")\n";
if (hasCollider == 1) //This mesh is being created, and it has a renderer
{
GameObject mshObj = new GameObject(vS[0]);
mshObj.AddComponent(typeof(MeshFilter));
((MeshFilter)mshObj.GetComponent(typeof(MeshFilter))).mesh = msh;
mshObj.AddComponent(typeof(MeshRenderer));
((MeshRenderer)mshObj.GetComponent(typeof(MeshRenderer))).materials = mats.ToArray();
if (hasCollider != -1) //This mesh has a collider, and it is the same as it's rendered mesh
{
mshObj.AddComponent(typeof(MeshCollider));
((MeshCollider)mshObj.GetComponent(typeof(MeshCollider))).sharedMesh = msh;
}
if (msh.uv.Length < 1) TextureObject(mshObj);
objects.Add(vS[0], mshObj);
mshObj.transform.parent = whirldBuffer.transform;
}
else //This mesh has a custom collider
{
if (objects.ContainsKey(vS[0])) //This mesh already exists, add a custom collider to it
{
GameObject mshObj = new GameObject(vS[0]);
mshObj.AddComponent(typeof(MeshCollider));
((MeshCollider)mshObj.GetComponent(typeof(MeshCollider))).sharedMesh = msh;
objects.Add(vS[0], mshObj);
mshObj.transform.parent = whirldBuffer.transform;
}
}
msh.Optimize();
threads.Remove(thread);
}
//v = "name;r:width,height,length,heightmapResolution //,detailResolution,controlResolution,textureResolution;h:heightMapUrl";
public IEnumerator LoadTerrain(string v)
{
String[] vS2 = v.Split(";"[0]);
String tName = vS2[0];
String[] tRes = null;
String tHtmp = null;
String tLtmp = null;
String tSpmp = null;
String tSpmp2 = null;
String[] tTxts = null;
// /*UNUSED*/ String tDtmp = null;
for (int i2 = 1; i2 < vS2.Length; i2++)
{
String[] str = vS2[i2].Split(":"[0]);
if (str[0] == "r") tRes = str[1].Split(","[0]);
else if (str[0] == "h") tHtmp = GetURL(str[1]);
else if (str[0] == "l") tLtmp = GetURL(str[1]);
else if (str[0] == "s") tSpmp = GetURL(str[1]);
else if (str[0] == "s2") tSpmp2 = GetURL(str[1]);
else if (str[0] == "t") tTxts = str[1].Split(","[0]);
//else if (str[0] == "d") tDtmp = GetURL(str[1]);
}
String thread = tName;
threads.Add(thread, "");
WWW www = new WWW(tHtmp);
while (!www.isDone)
{
threads[thread] = www.progress;
yield return null;
}
if (www.error != null)
{
info +=
"Terrain Undownloadable: " +
tName +
" " +
tHtmp +
" (" +
www.error +
")\n";
}
else
{
threads[thread] = "Initializing";
//yield return null;
int tWidth = int.Parse(tRes[0]);
int tHeight = int.Parse(tRes[1]);
int tLength = int.Parse(tRes[2]);
int tHRes = int.Parse(tRes[3]);
TerrainData trnDat = new TerrainData();
//Heights
trnDat.heightmapResolution = tHRes;
float[,] hmap = trnDat.GetHeights(0, 0, tHRes, tHRes);
System.IO.BinaryReader br;
if (true) //Terrain RAW file is compressed
{
GZipStream gz = new GZipStream(new MemoryStream(www.bytes), CompressionMode.Decompress);
byte[] buf = new byte[www.bytes.Length];
gz.Read(buf, 0, buf.Length);
br = new System.IO.BinaryReader(new System.IO.MemoryStream(
buf));
}
//else br = new System.IO.BinaryReader(new System.IO.MemoryStream(www.bytes));
for (int x = 0; x < tHRes; x++)
{
for (int y = 0; y < tHRes; y++)
{
hmap[x, y] = br.ReadUInt16() / 65535.00000000f;
}
}
trnDat.SetHeights(0, 0, hmap);
trnDat.size = new Vector3(tWidth, tHeight, tLength);
//Textures
SplatPrototype[] splatPrototypes = null;
if (tTxts != null)
{
splatPrototypes = new SplatPrototype[tTxts.Length];
for (int i = 0; i < tTxts.Length; i++)
{
String[] splatTxt = tTxts[i].Split("="[0]);
String[] splatTxtSize = splatTxt[1].Split("x"[0]);
www = new WWW(GetURL(splatTxt[0]));
while (!www.isDone)
{
//threads[thread] = "Initializing";
//yield return new WaitForSeconds(0.1f);
}
if (www.error != null)
{
info +=
"Terrain Texture Undownloadable: #" +
(i + 1) +
" (" +
splatTxt[0] +
")\n";
}
else
{
//yield return null;
splatPrototypes[i] = new SplatPrototype();
splatPrototypes[i].texture = new Texture2D(
4,
4,
TextureFormat.DXT1,
true);
www.LoadImageIntoTexture(splatPrototypes[i].texture);
splatPrototypes[i].texture.Apply(true);
splatPrototypes[i].texture.Compress(true);
splatPrototypes[i].tileSize = new Vector2(
int.Parse(splatTxtSize[0]),
int.Parse(splatTxtSize[1]));
}
}
}
trnDat.splatPrototypes = splatPrototypes;
//Lightmap
if (tLtmp != null)
{
//whirld.statusTxt = "Downloading Terrain Lightmap (" + tName + ")";
www = new WWW(tLtmp);
while (!www.isDone)
{
//whirld.progress = www.progress;
//yield return new WaitForSeconds(0.1f);
}
if (www.error != null)
{
info +=
"Terrain Lightmap Undownloadable: " +
tName +
" " +
tLtmp +
" (" +
www.error +
")\n";
}
else
{
trnDat.lightmap = www.texture;
}
}
//Splatmap
if (tSpmp != null)
{
Color[] mapColors2 = null;
if (tSpmp2 != null)
{
//whirld.statusTxt = "Downloading Augmentative Terrain Texturemap (" + tName + ")";
www = new WWW(tSpmp2);
while (!www.isDone)
{
//whirld.progress = www.progress;
//yield return new WaitForSeconds(0.1f);
}
mapColors2 = www.texture.GetPixels();
}
//whirld.statusTxt = "Downloading Terrain Texturemap (" + tName + ")";
www = new WWW(tSpmp);
while (!www.isDone)
{
//whirld.progress = www.progress;
//yield return new WaitForSeconds(0.1f);
}
//whirld.statusTxt = "Mapping Terrain Textures...";
//yield return null;
if (www.error != null)
{
info +=
"Terrain Texturemap Undownloadable: " +
tName +
" " +
tLtmp +
" (" +
www.error +
")\n";
}
else
{
trnDat.alphamapResolution = www.texture.width;
float[, ,] splatmapData = trnDat.GetAlphamaps(
0,
0,
www.texture.width,
www.texture.width);
Color[] mapColors = www.texture.GetPixels();
int ht = www.texture.height;
int wd = www.texture.width;
for (int y = 0; y < ht; y++)
{
for (int x = 0; x < wd; x++)
{
for (int z = 0; z < trnDat.alphamapLayers; z++)
{
if (z < 4)
{
splatmapData[x, y, z] = mapColors[x * wd + y][z];
}
else splatmapData[x, y, z] = mapColors2[x * wd + y][z - 4];
}
}
}
trnDat.SetAlphamaps(0, 0, splatmapData);
}
}
//Go !
GameObject trnObj = new GameObject(tName);
trnObj.AddComponent(typeof(Terrain));
((Terrain)trnObj.GetComponent(typeof(Terrain))).terrainData = trnDat;
trnObj.AddComponent(typeof(TerrainCollider));
((TerrainCollider)trnObj.GetComponent(typeof(TerrainCollider))).terrainData = trnDat;
objects.Add(tName, trnObj);
//Delete this temporary terrain object AFTER world is fully loaded
trnObj.transform.parent = whirldBuffer.transform;
}
threads.Remove(thread);
}
public IEnumerator LoadSkyboxTexture(string url, int dest)
{
threadTextures++;
//Don't overwhelm the computer by doing too many things @ once
while (threads.Count >= maxThreads) yield return null;
//Presets
String thread = "Skybox" + dest;
threads.Add(thread, "");
//Download Skybox Image
url = GetURL(url);
WWW www = new WWW(url);
while (!www.isDone)
{
threads[thread] = www.progress;
yield return null;
}
threads.Remove(thread);
threadTextures--;
if (www.error != null)
{
info +=
"Failed to download skybox # " +
dest +
": " +
url +
" (" +
www.error +
")\n";
yield break; ;
}
Texture2D txt = new Texture2D(
4,
4,
TextureFormat.DXT1,
true);
www.LoadImageIntoTexture(txt);
txt.wrapMode = TextureWrapMode.Clamp;
txt.Apply(true);
txt.Compress(true);
//Wait for everything else to load
while (threads.Count > 0) yield return null;
//Assign Texture to Skybox!
if (dest == 0 || dest == 1)
{
RenderSettings.skybox.SetTexture("_FrontTex", txt);
}
if (dest == 0 || dest == 2)
{
RenderSettings.skybox.SetTexture("_BackTex", txt);
}
if (dest == 0 || dest == 3)
{
RenderSettings.skybox.SetTexture("_LeftTex", txt);
}
if (dest == 0 || dest == 4)
{
RenderSettings.skybox.SetTexture("_RightTex", txt);
}
if (dest == 0 || dest == 5)
{
RenderSettings.skybox.SetTexture("_UpTex", txt);
}
if (dest == 0 || dest == 6)
{
RenderSettings.skybox.SetTexture("_DownTex", txt);
}
}
public IEnumerator LoadSkybox(string v)
{
String[] vS = v.Split(","[0]);
//Multiple Image Skybox
if (vS.Length > 5)
{
//Material skyMat = RenderSettings.skybox;
//RenderSettings.skybox = new Material();
//RenderSettings.skybox.CopyPropertiesFromMaterial(skymat);
LoadSkyboxTexture(vS[0], 1);
LoadSkyboxTexture(vS[1], 2);
LoadSkyboxTexture(vS[2], 3);
LoadSkyboxTexture(vS[3], 4);
LoadSkyboxTexture(vS[4], 5);
LoadSkyboxTexture(vS[5], 6);
//Wait for everything else to load
while (threads.Count > 0) yield return null;
if (vS.Length > 6)
{
RenderSettings.skybox.SetColor("_Tint", new Color(
float.Parse(vS[6]),
float.Parse(vS[7]),
float.Parse(vS[8]),
0.5f));
}
}
//Single JPG image for all sides
else if (vS[0].Substring(vS[0].LastIndexOf(".") + 1) == "jpg")
{
LoadSkyboxTexture(vS[0], 0);
//Wait for everything else to load
while (threads.Count > 0) yield return null;
if (vS.Length > 1)
{
RenderSettings.skybox.SetColor("_Tint", new Color(
float.Parse(vS[1]),
float.Parse(vS[2]),
float.Parse(vS[3]),
0.5f));
}
}
//AssetBundle Material Skybox
else
{
//Wait for everything else to load
while (threads.Count > 0) yield return null;
RenderSettings.skybox = (Material)GetAsset(v); //, Material
if (!RenderSettings.skybox)
{
info +=
"Skybox not found: " +
v +
"\n";
}
}
}
public UnityEngine.Object GetAsset(string str)
{
if (loadedAssetBundles.Count > 0)
{
foreach (AssetBundle ab in loadedAssetBundles)
{
if (ab.Contains(str)) return ab.Load(str);
}
}
return null;
}
public void ReadObject(Transform parent)
{
// /*UNUSED*/ string c = null; //Character
int i = 0; //Index of param
string n = ""; //Param name we are reading data for
string v = ""; //Value we are building
List<String> d = new List<String>(); //Array of all values in current param data
GameObject obj = null; //Object we have created
GameObject goP = default(GameObject);
WhirldObject whirldObject = default(WhirldObject);
Light lightSource = default(Light);
while (true)
{
if (readChr >= data.Length) return;
//Get Char
char s = data[readChr];
//Ignore spaces
if (s == ' ' || s == '\n' || s == '\t') { ; }
//Name fully read, begin collecting param value(s)
else if (s == ':')
{
n = v;
v = "";
}
//Move to next section of value
else if (s == ',')
{
d.Add(v);
v = "";
}
//Move to next section of value
else if (s == '{')
{
readChr++;
ReadObject(obj.transform);
//Continue to next obj once the child "thread" we just launched has finished parsing objects at it's level
continue;
}
//Assign current value to object, Begin reading new value
else if (s == ';' || s == '}')
{
//Object name just read, create object
if (!obj)
{
if (objects.ContainsKey(v))
{
if (objects[v] != null)
{
goP = (GameObject)objects[v];
}
else
{
Debug.Log("Whirld: Objects[" + v + "] is null");
}
//else goP = gameObject.Find();
}
else
{
goP = (GameObject)Resources.Load(v);
if ((bool)goP) objects.Add(v, goP);
}
if ((bool)goP)
{
obj = (GameObject)GameObject.Instantiate(goP);
obj.name = v;
}
else
{
obj = new GameObject(v);
objects.Add(v, obj);
}
if (
obj.name != "Base" &&
obj.name != "Sea" &&
obj.name != "JumpPoint" &&
obj.name != "Light")
{
obj.transform.parent = parent;
}
whirldObject = (WhirldObject)obj.GetComponent(typeof(WhirldObject));
if ((bool)whirldObject)
{
whirldObject.parameters = new Hashtable();
}
lightSource = (Light)obj.GetComponent(typeof(Light));
}
//Object already created, assign property to object
else
{
if (
(n == "p" || (n == "" && i == 1)) &&
d.Count == 2)
{
obj.transform.localPosition = new Vector3(
float.Parse(d[0]),
float.Parse(d[1]),
float.Parse(v));
}
else if (
n == "p" ||
(n == "" && i == 1))
{
obj.transform.localPosition = Vector3.one * float.Parse(v);
}
else if (
(n == "r" || (n == string.Empty && i == 2)) &&
d.Count == 3)
{
obj.transform.rotation = new Quaternion(
float.Parse(d[0]),
float.Parse(d[1]),
float.Parse(d[2]),
float.Parse(v));
}
else if (
(n == "r" || (n == string.Empty && i == 2)) &&
d.Count == 2)
{
obj.transform.rotation = Quaternion.Euler(
float.Parse(d[0]),
float.Parse(d[1]),
float.Parse(v));
}
else if (
(n == "r" || (n == string.Empty && i == 2)) &&
d.Count == 0)
{
obj.transform.rotation = Quaternion.identity;
}
else if (
(n == "s" || (n == string.Empty && i == 3)) &&
d.Count == 0)
{
obj.transform.localScale = Vector3.one * float.Parse(v);
}
else if (
n == "s" ||
(n == "" && i == 3))
{
obj.transform.localScale = new Vector3(
float.Parse(d[0]),
float.Parse(d[1]),
float.Parse(v));
}
else if (n == "cc")
{
obj.AddComponent(typeof(CombineChildren));
worldParams["ccc"] = 1;
}
else if (n == "m")
{
//d.Add(v);
//ReadMesh(obj, d);
info += "Inline Whirld mesh generation not supported\n";
}
else if ((bool)lightSource && n == "color")
{
Color lsc = lightSource.color;
lsc.r = float.Parse(d[0]);
lsc.g = float.Parse(d[1]);
lsc.b = float.Parse(v);
lightSource.color = lsc;
}
else if ((bool)lightSource && n == "intensity")
{
lightSource.intensity = float.Parse(v);
}
else
{
if ((bool)whirldObject)
{
//Object Reference
if (v.Substring(0, 1) == "#")
{
whirldObject.parameters.Add(
n,
GetAsset(v.Substring(1)));
}
//Text
else
{
whirldObject.parameters.Add(n, v);
}
}
else if (n != "")
{
Debug.Log(
obj.name +
" Unknown Param: " +
n +
" > " +
v);
}
}
}
//Reset properties
v = "";
n = "";
if (d.Count > 0) d = new List<String>();
i++;
//Done reading this object
if (s == '}')
{
//Finish up this object
if (
obj.name == "cube" ||
obj.name == "pyramid" ||
obj.name == "cone" ||
obj.name == "mesh")
{
TextureObject(obj);
}
//Increment ReadChar
readChr++;
//Handle spaces
while (
readChr < data.Length &&
(
data[readChr] == ' ' ||
data[readChr] == '\n' ||
data[readChr] == '\t'))
{
readChr++;
}
//Read the next object
if (readChr < data.Length && data[readChr] == '{')
{
readChr++;
ReadObject(parent);
return;
}
//Done reading objects at this level of recursion
else return;
}
}
//Assign char to property we are reading
else
{
if (n != null) v += s;
else n += s;
}
readChr++;
}
}
public void TextureObject(GameObject go)
{
MeshFilter mf = (MeshFilter)go.GetComponent(typeof(MeshFilter));
if (!mf) return;
Mesh mesh = mf.mesh;
Vector2[] uvs = new Vector2[mesh.vertices.Length];
int[] tris = mesh.triangles;
for (int i = 0; i < tris.Length; i += 3)
{
Vector3 a = go.transform.TransformPoint(mesh.vertices[tris[i]]);
Vector3 b = go.transform.TransformPoint(mesh.vertices[tris[i+1]]);
Vector3 c = go.transform.TransformPoint(mesh.vertices[tris[i+2]]);
Vector3 n = Vector3.Cross(a-c, b-c).normalized;
if (
Vector3.Dot(Vector3.up, n) >= 0.5f ||
(Vector3.Dot(-Vector3.up, n) >= 0.5f))
{
uvs[tris[i]] = new Vector2(a.x, a.z);
uvs[tris[i+1]] = new Vector2(b.x, b.z);
uvs[tris[i+2]] = new Vector2(c.x, c.z);
}
else if (
Vector3.Dot(Vector3.right, n) >= 0.5f ||
(Vector3.Dot(Vector3.left, n) >= 0.5f))
{
uvs[tris[i]] = new Vector2(a.y, a.z);
uvs[tris[i+1]] = new Vector2(b.y, b.z);
uvs[tris[i+2]] = new Vector2(c.y, c.z);
}
else
{
uvs[tris[i]] = new Vector2(a.y, a.x);
uvs[tris[i + 1]] = new Vector2(b.y, b.x);
uvs[tris[i + 2]] = new Vector2(c.y, c.x);
}
}
mesh.uv = uvs;
}
public String GetURL(String url)
{
if (url.Substring(0, 4) != "http") url = urlPath + url;
return url;
}
}