LNXSDK/leenkx/Sources/iron/data/TerrainStream.hx

158 lines
4.4 KiB
Haxe
Raw Normal View History

2025-01-22 16:18:30 +01:00
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