forked from LeenkxTeam/LNXSDK
158 lines
4.4 KiB
Haxe
158 lines
4.4 KiB
Haxe
|
package iron.data;
|
||
|
|
||
|
import haxe.ds.Vector;
|
||
|
import kha.arrays.Int16Array;
|
||
|
import kha.arrays.Uint32Array;
|
||
|
import iron.data.SceneFormat;
|
||
|
import iron.object.Object;
|
||
|
import iron.object.CameraObject;
|
||
|
import iron.object.MeshObject;
|
||
|
import iron.object.Uniforms;
|
||
|
import iron.Scene;
|
||
|
|
||
|
#if lnx_terrain
|
||
|
|
||
|
class TerrainStream {
|
||
|
|
||
|
public var sectors: Array<MeshObject> = [];
|
||
|
public var heightTextures: Array<kha.Image> = [];
|
||
|
public var ready = false;
|
||
|
public var onReady: Void->Void = null;
|
||
|
|
||
|
var raw: TTerrainData;
|
||
|
var planes: Array<MeshData> = [];
|
||
|
var materials: Vector<MaterialData>;
|
||
|
|
||
|
public function new(raw: TTerrainData) {
|
||
|
this.raw = raw;
|
||
|
|
||
|
Data.getMaterial(Scene.active.raw.name, raw.material_ref, function(mat: MaterialData) {
|
||
|
materials = Vector.fromData([mat]);
|
||
|
|
||
|
var imagesLoaded = 0;
|
||
|
var numSectors = raw.sectors_x * raw.sectors_y;
|
||
|
for (i in 0...numSectors) {
|
||
|
var j = i + 1;
|
||
|
var ext = j < 10 ? "0" + j : "" + j;
|
||
|
Data.getImage("heightmap_" + ext + ".png", function(image: kha.Image) {
|
||
|
heightTextures[i] = image;
|
||
|
imagesLoaded++;
|
||
|
if (imagesLoaded == numSectors) {
|
||
|
loaded();
|
||
|
}
|
||
|
}, true); // Readable
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
public function notifyOnReady(f: Void->Void) {
|
||
|
onReady = f;
|
||
|
if (ready) onReady();
|
||
|
}
|
||
|
|
||
|
function loaded() {
|
||
|
for (i in 0...4) {
|
||
|
makePlane(i, raw.sector_size, raw.sector_size, heightTextures[0].width, heightTextures[0].height);
|
||
|
}
|
||
|
|
||
|
for (i in 0...raw.sectors_x * raw.sectors_y) {
|
||
|
makeSector(i);
|
||
|
}
|
||
|
|
||
|
iron.App.notifyOnInit(function() {
|
||
|
Uniforms.externalTextureLinks.push(textureLink);
|
||
|
});
|
||
|
|
||
|
ready = true;
|
||
|
if (onReady != null) onReady();
|
||
|
}
|
||
|
|
||
|
function makePlane(index: Int, sizeX: Float, sizeY: Float, vertsX: Int, vertsY: Int) {
|
||
|
// Pack positions to (-1, 1) range
|
||
|
var halfX = sizeX / 2;
|
||
|
var halfY = sizeY / 2;
|
||
|
var halfZ = raw.height_scale / 2;
|
||
|
var scalePos = Math.max(halfX, Math.max(halfY, halfZ));
|
||
|
var inv = 1 / scalePos;
|
||
|
|
||
|
var posa = new Int16Array(vertsX * vertsY * 4);
|
||
|
var nora = new Int16Array(vertsX * vertsY * 2);
|
||
|
var texa = new Int16Array(vertsX * vertsY * 2);
|
||
|
var inda = new Uint32Array((vertsX - 1) * (vertsY - 1) * 6);
|
||
|
var stepX = sizeX / (vertsX - 1);
|
||
|
var stepY = sizeY / (vertsY - 1);
|
||
|
for (i in 0...vertsX * vertsY) {
|
||
|
var x = (i % vertsX) * stepX - halfX;
|
||
|
var y = Std.int(i / vertsX) * stepY - halfY;
|
||
|
posa[i * 4 ] = Std.int(x * 32767 * inv);
|
||
|
posa[i * 4 + 1] = Std.int(y * 32767 * inv);
|
||
|
posa[i * 4 + 2] = Std.int(-halfZ * 32767 * inv);
|
||
|
nora[i * 2 ] = 0;
|
||
|
nora[i * 2 + 1] = 0;
|
||
|
posa[i * 4 + 3] = 32767;
|
||
|
x = (i % vertsX) / vertsX;
|
||
|
y = (Std.int(i / vertsX)) / vertsY;
|
||
|
texa[i * 2 ] = Std.int(x * 32767);
|
||
|
texa[i * 2 + 1] = Std.int(y * 32767);
|
||
|
}
|
||
|
for (i in 0...(vertsX - 1) * (vertsY - 1)) {
|
||
|
var x = i % (vertsX - 1);
|
||
|
var y = Std.int(i / (vertsY - 1));
|
||
|
inda[i * 6 ] = y * vertsX + x;
|
||
|
inda[i * 6 + 1] = y * vertsX + x + 1;
|
||
|
inda[i * 6 + 2] = (y + 1) * vertsX + x;
|
||
|
inda[i * 6 + 3] = y * vertsX + x + 1;
|
||
|
inda[i * 6 + 4] = (y + 1) * vertsX + x + 1;
|
||
|
inda[i * 6 + 5] = (y + 1) * vertsX + x;
|
||
|
}
|
||
|
|
||
|
// Positions, normals and indices
|
||
|
var pos: TVertexArray = { attrib: "pos", values: posa, data: "short4norm" };
|
||
|
var nor: TVertexArray = { attrib: "nor", values: nora, data: "short2norm" };
|
||
|
var tex: TVertexArray = { attrib: "tex", values: texa, data: "short2norm" };
|
||
|
var ind: TIndexArray = { material: 0, values: inda };
|
||
|
|
||
|
var rawmeshData: TMeshData = {
|
||
|
name: "Terrain",
|
||
|
vertex_arrays: [pos, nor, tex],
|
||
|
index_arrays: [ind],
|
||
|
scale_pos: scalePos,
|
||
|
scale_tex: 1.0
|
||
|
};
|
||
|
|
||
|
new MeshData(rawmeshData, function(data: MeshData) {
|
||
|
planes[index] = data;
|
||
|
data.geom.calculateAABB();
|
||
|
});
|
||
|
}
|
||
|
|
||
|
function makeSector(index: Int) {
|
||
|
var object = Scene.active.addMeshObject(planes[0], materials);
|
||
|
sectors[index] = object;
|
||
|
object.uid = index;
|
||
|
object.name = "Terrain." + index;
|
||
|
object.transform.loc.x = (index % raw.sectors_x) * 2;
|
||
|
object.transform.loc.y = Std.int(index / raw.sectors_x) * 2;
|
||
|
object.transform.loc.z = 0;
|
||
|
object.transform.buildMatrix();
|
||
|
object.transform.dim.x = raw.sector_size;
|
||
|
object.transform.dim.y = raw.sector_size;
|
||
|
object.transform.dim.z = raw.height_scale;
|
||
|
}
|
||
|
|
||
|
public function remove() {}
|
||
|
|
||
|
public function update(camera: CameraObject) {
|
||
|
if (!ready) return;
|
||
|
}
|
||
|
|
||
|
function textureLink(object: Object, mat: MaterialData, link: String): kha.Image {
|
||
|
if (link == "_TerrainHeight") {
|
||
|
return heightTextures[object.uid];
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#end
|