some optimizations

This commit is contained in:
RandomityGuy 2024-07-16 18:47:39 +05:30
parent ef6612bcb8
commit 13c9c8d99e
6 changed files with 180 additions and 328 deletions

View file

@ -1,5 +1,6 @@
package src;
import h3d.prim.DynamicPrimitive;
import h3d.scene.MultiMaterial;
import shaders.EnvMap;
import h3d.shader.CubeMap;
@ -52,13 +53,6 @@ var dtsMaterials = [
"pball-round-bottm" => {friction: 0.5, restitution: 0.0, force: 15.0}
];
typedef GraphNode = {
var index:Int;
var node:Node;
var children:Array<GraphNode>;
var parent:GraphNode;
}
typedef MaterialGeometry = {
var vertices:Array<Vector>;
var normals:Array<Vector>;
@ -66,12 +60,15 @@ typedef MaterialGeometry = {
var indices:Array<Int>;
}
typedef SkinMeshData = {
@:structInit
@:publicFields
class SkinMeshData {
var meshIndex:Int;
var vertices:Array<Vector>;
var normals:Array<Vector>;
var vertices:Array<Float>; // Turn THIS into a FloatBuffer
var normals:Array<Float>; // SAME HERE
var indices:Array<Int>;
var geometry:Object;
var primitives:Array<DynamicPolygon>;
}
@:publicFields
@ -88,7 +85,7 @@ class DtsObject extends GameObject {
var matNameOverride:Map<String, String> = new Map();
var sequenceKeyframeOverride:Map<Sequence, Float> = new Map();
var lastSequenceKeyframes:Map<Sequence, Float> = new Map();
var lastSequenceKeyframes:Array<Float> = [];
var graphNodes:Array<Object> = [];
var dirtyTransforms:Array<Bool> = [];
@ -272,22 +269,39 @@ class DtsObject extends GameObject {
var vertices = mesh.vertices.map(v -> new Vector(-v.x, v.y, v.z));
var vertexNormals = mesh.normals.map(v -> new Vector(-v.x, v.y, v.z));
var geometry = this.generateMaterialGeometry(mesh, vertices, vertexNormals);
var prims = [];
for (k in 0...geometry.length) {
if (geometry[k].vertices.length == 0)
continue;
var poly = new DynamicPolygon(geometry[k].vertices.map(x -> x.toPoint()));
poly.normals = geometry[k].normals.map(x -> x.toPoint());
poly.uvs = geometry[k].uvs;
var poly = new DynamicPolygon();
poly.addPoints(geometry[k].vertices.map(x -> x.toPoint()));
poly.addNormals(geometry[k].normals.map(x -> x.toPoint()));
poly.addUVs(geometry[k].uvs);
var obj = new MultiMaterial(poly, [materials[k]], skinObj);
prims.push(poly);
}
var flatVerts = [];
var flatNormals = [];
for (v in vertices) {
flatVerts.push(v.x);
flatVerts.push(v.y);
flatVerts.push(v.z);
}
for (n in vertexNormals) {
flatNormals.push(n.x);
flatNormals.push(n.y);
flatNormals.push(n.z);
}
skinMeshData = {
meshIndex: i,
vertices: vertices,
normals: vertexNormals,
vertices: flatVerts,
normals: flatNormals,
indices: [],
geometry: skinObj
geometry: skinObj,
primitives: prims
};
var idx = geometry.map(x -> x.indices);
for (indexes in idx) {
@ -310,12 +324,17 @@ class DtsObject extends GameObject {
vertices: [],
normals: [],
indices: [],
geometry: skinObj
geometry: skinObj,
primitives: []
};
}
}
}
for (seq in this.dts.sequences) {
lastSequenceKeyframes.push(0);
}
if (!this.isInstanced) {
for (i in 0...this.materials.length) {
var info = this.materialInfos.get(this.materials[i]);
@ -807,7 +826,8 @@ class DtsObject extends GameObject {
if (this.currentOpacity == 0)
return;
for (sequence in this.dts.sequences) {
for (i in 0...this.dts.sequences.length) {
var sequence = this.dts.sequences[i];
if (!this.showSequences)
break;
if (!this.hasNonVisualSequences)
@ -824,9 +844,9 @@ class DtsObject extends GameObject {
var scales:Array<Vector> = null;
var actualKeyframe = this.sequenceKeyframeOverride.exists(sequence) ? this.sequenceKeyframeOverride.get(sequence) : ((completion * sequence.numKeyFrames) % sequence.numKeyFrames);
if (this.lastSequenceKeyframes.get(sequence) == actualKeyframe)
if (lastSequenceKeyframes[i] == actualKeyframe)
continue;
lastSequenceKeyframes.set(sequence, actualKeyframe);
lastSequenceKeyframes[i] = actualKeyframe;
var keyframeLow = Math.floor(actualKeyframe);
var keyframeHigh = Math.ceil(actualKeyframe) % sequence.numKeyFrames;
@ -931,8 +951,8 @@ class DtsObject extends GameObject {
var mesh = this.dts.meshes[info.meshIndex];
for (i in 0...info.vertices.length) {
info.vertices[i].set(0, 0, 0);
info.normals[i].set(0, 0, 0);
info.vertices[i] = 0;
info.normals[i] = 0;
}
var boneTransformations = [];
@ -966,34 +986,42 @@ class DtsObject extends GameObject {
Util.m_matF_x_vectorF(mat, vec2);
vec2.load(vec2.multiply(mesh.weights[i]));
info.vertices[vIndex].load(info.vertices[vIndex].add(vec));
info.normals[vIndex].load(info.normals[vIndex].add(vec2));
info.vertices[3 * vIndex] = info.vertices[3 * vIndex] + vec.x;
info.vertices[3 * vIndex + 1] = info.vertices[3 * vIndex + 1] + vec.y;
info.vertices[3 * vIndex + 2] = info.vertices[3 * vIndex + 2] + vec.z;
info.normals[3 * vIndex] = info.normals[3 * vIndex] + vec2.x;
info.normals[3 * vIndex + 1] = info.normals[3 * vIndex + 1] + vec2.y;
info.normals[3 * vIndex + 2] = info.normals[3 * vIndex + 2] + vec2.z;
}
for (i in 0...info.normals.length) {
var norm = info.normals[i];
for (i in 0...Std.int(info.normals.length / 3)) {
var norm = new Vector(info.normals[3 * i], info.normals[3 * i + 1], info.normals[3 * i + 2]);
var len2 = norm.dot(norm);
if (len2 > 0.01)
if (len2 > 0.01) {
norm.normalize();
info.normals[3 * i] = norm.x;
info.normals[3 * i + 1] = norm.y;
info.normals[3 * i + 2] = norm.z;
}
}
var meshIndex = 0;
var mesh:Mesh = cast info.geometry.children[meshIndex];
var prim:DynamicPolygon = cast mesh.primitive;
var prim = info.primitives[meshIndex];
var pos = 0;
for (i in info.indices) {
if (pos >= prim.points.length) {
if (pos >= Std.int(prim.points.length / 3)) {
meshIndex++;
mesh.primitive = prim;
mesh = cast info.geometry.children[meshIndex];
prim = cast mesh.primitive;
prim = info.primitives[meshIndex];
pos = 0;
}
var vertex = info.vertices[i];
var normal = info.normals[i];
prim.points[pos].load(vertex.toPoint());
prim.normals[pos].load(normal.toPoint()); // .normalized();
prim.points[3 * pos] = info.vertices[3 * i];
prim.points[3 * pos + 1] = info.vertices[3 * i + 1];
prim.points[3 * pos + 2] = info.vertices[3 * i + 2];
prim.normals[3 * pos] = info.normals[3 * i];
prim.normals[3 * pos + 1] = info.normals[3 * i + 1];
prim.normals[3 * pos + 2] = info.normals[3 * i + 2];
if (prim.buffer != null) {
prim.dirtyFlags[pos] = true;
}

View file

@ -12,37 +12,62 @@ import h3d.col.Point;
To update points/normals/uvs, just change the points/normals/uvs array and set dirtyFlags[i] to true for all index of changed points/normals/uvs where i is index of point and call flush();
*/
class DynamicPolygon extends MeshPrimitive {
public var points:Array<Point>;
public var normals:Array<Point>;
public var uvs:Array<UV>;
public var idx:hxd.IndexBuffer;
public var points:Array<Float>;
public var normals:Array<Float>;
public var uvs:Array<Float>;
// A list of bools having the same length as points/normals/uv and each bool corresponds to point/normal/uv having the same index as the bool
// Basically this is just used to tell apart vertices that changed so it will be flushed, it will be created after alloc has been called
public var dirtyFlags:Array<Bool>;
var vbuf:FloatBuffer;
var buf:FloatBuffer;
@:s var scaled = 1.;
@:s var translatedX = 0.;
@:s var translatedY = 0.;
@:s var translatedZ = 0.;
var bounds:h3d.col.Bounds;
public function new(points, ?idx) {
this.points = points;
this.idx = idx;
public function new() {}
public function addPoints(points:Array<h3d.col.Point>) {
this.points = [];
for (p in points) {
this.points.push(p.x);
this.points.push(p.y);
this.points.push(p.z);
}
}
public function addUVs(uvs:Array<h3d.prim.UV>) {
this.uvs = [];
for (uv in uvs) {
this.uvs.push(uv.u);
this.uvs.push(uv.v);
}
}
public function addNormals(normals:Array<h3d.col.Point>) {
this.normals = [];
for (n in normals) {
this.normals.push(n.x);
this.normals.push(n.y);
this.normals.push(n.z);
}
}
override function getBounds() {
if (bounds == null) {
var b = new h3d.col.Bounds();
for (p in points)
b.addPoint(p);
return b;
var i = 0;
while (i < points.length) {
b.addPoint(new h3d.col.Point(points[i], points[i + 1], points[i + 2]));
i += 3;
}
bounds = b;
}
return bounds;
}
public function flush() {
var alloc = hxd.impl.Allocator.get();
var vsize = points.length;
var vsize = Std.int(points.length / 3);
if (vsize == 0) {
if (buffer != null) {
alloc.disposeBuffer(buffer);
@ -64,22 +89,19 @@ class DynamicPolygon extends MeshPrimitive {
buffer = alloc.allocBuffer(hxd.Math.imax(0, vsize), 8, Dynamic);
var off = 0;
for (k in 0...points.length) {
for (k in 0...Std.int(points.length / 3)) {
if (dirtyFlags[k]) {
var p = points[k];
vbuf[off++] = p.x;
vbuf[off++] = p.y;
vbuf[off++] = p.z;
buf[off++] = points[k * 3];
buf[off++] = points[k * 3 + 1];
buf[off++] = points[k * 3 + 2];
if (normals != null) {
var n = normals[k];
vbuf[off++] = n.x;
vbuf[off++] = n.y;
vbuf[off++] = n.z;
buf[off++] = normals[k * 3];
buf[off++] = normals[k * 3 + 1];
buf[off++] = normals[k * 3 + 2];
}
if (uvs != null) {
var uv = uvs[k];
vbuf[off++] = uv.u;
vbuf[off++] = uv.v;
buf[off++] = uvs[k * 2];
buf[off++] = uvs[k * 2 + 1];
}
dirtyFlags[k] = false;
} else {
@ -91,9 +113,7 @@ class DynamicPolygon extends MeshPrimitive {
}
}
buffer.uploadVector(vbuf, 0, vsize);
if (idx != null)
indexes = h3d.Indexes.alloc(idx);
buffer.uploadVector(buf, 0, vsize);
}
override function alloc(engine:h3d.Engine) {
@ -117,146 +137,41 @@ class DynamicPolygon extends MeshPrimitive {
size += 2;
}
vbuf = new hxd.FloatBuffer();
for (k in 0...points.length) {
var p = points[k];
vbuf.push(p.x);
vbuf.push(p.y);
vbuf.push(p.z);
buf = new hxd.FloatBuffer();
for (k in 0...Std.int(points.length / 3)) {
buf.push(points[k * 3]);
buf.push(points[k * 3 + 1]);
buf.push(points[k * 3 + 2]);
if (normals != null) {
var n = normals[k];
vbuf.push(n.x);
vbuf.push(n.y);
vbuf.push(n.z);
buf.push(normals[k * 3]);
buf.push(normals[k * 3 + 1]);
buf.push(normals[k * 3 + 2]);
}
if (uvs != null) {
var t = uvs[k];
vbuf.push(t.u);
vbuf.push(t.v);
buf.push(uvs[k * 2]);
buf.push(uvs[k * 2 + 1]);
}
dirtyFlags.push(false);
}
var flags:Array<h3d.Buffer.BufferFlag> = [];
if (idx == null)
flags.push(Triangles);
if (normals == null)
flags.push(RawFormat);
flags.push(Dynamic);
buffer = allocator.allocBuffer(hxd.Math.imax(0, vertexCount()), 8, Dynamic); // h3d.Buffer.ofFloats(buf, size, flags);
buffer.uploadVector(vbuf, 0, points.length);
buffer.uploadVector(buf, 0, Std.int(points.length / 3));
for (i in 0...names.length)
addBuffer(names[i], buffer, positions[i]);
if (idx != null)
indexes = h3d.Indexes.alloc(idx);
}
public function getDrawBuffer(vertices:Int) {
if (vbuf == null)
vbuf = hxd.impl.Allocator.get().allocFloats(vertices * 8)
else
vbuf.grow(vertices * 8);
return vbuf;
}
public function unindex() {
if (idx != null && points.length != idx.length) {
var p = [];
var used = [];
for (i in 0...idx.length)
p.push(points[idx[i]].clone());
if (normals != null) {
var n = [];
for (i in 0...idx.length)
n.push(normals[idx[i]].clone());
normals = n;
}
if (uvs != null) {
var t = [];
for (i in 0...idx.length)
t.push(uvs[idx[i]].clone());
uvs = t;
}
points = p;
idx = null;
}
}
public function translate(dx, dy, dz) {
translatedX += dx;
translatedY += dy;
translatedZ += dz;
for (p in points) {
p.x += dx;
p.y += dy;
p.z += dz;
}
}
public function scale(s:Float) {
scaled *= s;
for (p in points) {
p.x *= s;
p.y *= s;
p.z *= s;
}
}
public function addNormals() {
// make per-point normal
normals = new Array();
for (i in 0...points.length)
normals[i] = new Point();
var pos = 0;
for (i in 0...triCount()) {
var i0, i1, i2;
if (idx == null) {
i0 = pos++;
i1 = pos++;
i2 = pos++;
} else {
i0 = idx[pos++];
i1 = idx[pos++];
i2 = idx[pos++];
}
var p0 = points[i0];
var p1 = points[i1];
var p2 = points[i2];
// this is the per-face normal
var n = p1.sub(p0).cross(p2.sub(p0));
// add it to each point
normals[i0].x += n.x;
normals[i0].y += n.y;
normals[i0].z += n.z;
normals[i1].x += n.x;
normals[i1].y += n.y;
normals[i1].z += n.z;
normals[i2].x += n.x;
normals[i2].y += n.y;
normals[i2].z += n.z;
}
// normalize all normals
for (n in normals)
n.normalize();
}
public function addUVs() {
uvs = [];
for (i in 0...points.length)
uvs[i] = new UV(points[i].x, points[i].y);
}
public function uvScale(su:Float, sv:Float) {
if (uvs == null)
throw "Missing UVs";
var m = new Map<UV, Bool>();
for (t in uvs) {
if (m.exists(t))
continue;
m.set(t, true);
t.u *= su;
t.v *= sv;
if (indexes == null && Std.int(points.length / 3) > 65535) {
var indices = new haxe.io.BytesOutput();
for (i in 0...Std.int(points.length / 3))
indices.writeInt32(i);
indexes = new h3d.Indexes(indices.length >> 2, true);
indexes.uploadBytes(indices.getBytes(), 0, indices.length >> 2);
}
}
@ -264,27 +179,11 @@ class DynamicPolygon extends MeshPrimitive {
var n = super.triCount();
if (n != 0)
return n;
return Std.int((idx == null ? points.length : idx.length) / 3);
return Std.int(points.length / 3);
}
override function vertexCount() {
return points.length;
}
override function getCollider():h3d.col.Collider {
var vertexes = new haxe.ds.Vector<hxd.impl.Float32>(points.length * 3);
var indexes = new haxe.ds.Vector<Int>(idx.length);
var vid = 0;
for (p in points) {
vertexes[vid++] = p.x;
vertexes[vid++] = p.y;
vertexes[vid++] = p.z;
}
for (i in 0...idx.length)
indexes[i] = idx[i];
var poly = new h3d.col.Polygon();
poly.addBuffers(vertexes, indexes);
return poly;
return Std.int(points.length / 3);
}
override function render(engine:h3d.Engine) {
@ -298,94 +197,4 @@ class DynamicPolygon extends MeshPrimitive {
else
engine.renderMultiBuffers(bufs, engine.mem.triIndexes, 0, triCount());
}
#if hxbit
override function customSerialize(ctx:hxbit.Serializer) {
ctx.addInt(points.length);
for (p in points) {
ctx.addDouble(p.x);
ctx.addDouble(p.y);
ctx.addDouble(p.z);
}
if (normals == null)
ctx.addInt(0);
else {
ctx.addInt(normals.length);
for (p in normals) {
ctx.addDouble(p.x);
ctx.addDouble(p.y);
ctx.addDouble(p.z);
}
}
if (tangents == null)
ctx.addInt(0);
else {
ctx.addInt(tangents.length);
for (p in tangents) {
ctx.addDouble(p.x);
ctx.addDouble(p.y);
ctx.addDouble(p.z);
}
}
if (uvs == null)
ctx.addInt(0);
else {
ctx.addInt(uvs.length);
for (uv in uvs) {
ctx.addDouble(uv.u);
ctx.addDouble(uv.v);
}
}
if (idx == null)
ctx.addInt(0);
else {
ctx.addInt(idx.length);
for (i in idx)
ctx.addInt(i);
}
if (colors == null)
ctx.addInt(0);
else {
ctx.addInt(colors.length);
for (c in colors) {
ctx.addDouble(c.x);
ctx.addDouble(c.y);
ctx.addDouble(c.z);
}
}
}
override function customUnserialize(ctx:hxbit.Serializer) {
points = [
for (i in 0...ctx.getInt())
new h3d.col.Point(ctx.getDouble(), ctx.getDouble(), ctx.getDouble())
];
normals = [
for (i in 0...ctx.getInt())
new h3d.col.Point(ctx.getDouble(), ctx.getDouble(), ctx.getDouble())
];
tangents = [
for (i in 0...ctx.getInt())
new h3d.col.Point(ctx.getDouble(), ctx.getDouble(), ctx.getDouble())
];
uvs = [for (i in 0...ctx.getInt()) new UV(ctx.getDouble(), ctx.getDouble())];
if (normals.length == 0)
normals = null;
if (uvs.length == 0)
uvs = null;
var nindex = ctx.getInt();
if (nindex > 0) {
idx = new hxd.IndexBuffer();
idx.grow(nindex);
for (i in 0...nindex)
idx[i] = ctx.getInt();
}
colors = [
for (i in 0...ctx.getInt())
new h3d.col.Point(ctx.getDouble(), ctx.getDouble(), ctx.getDouble())
];
if (colors.length == 0)
colors = null;
}
#end
}

View file

@ -38,6 +38,7 @@ class MeshBatchInfo {
class MeshInstance {
var emptyObj:Object;
var gameObject:GameObject;
var visibleTicks:Int = 10;
public function new(eo, go) {
this.emptyObj = eo;
@ -127,6 +128,7 @@ class InstanceManager {
// for (frustum in renderFrustums) {
// if (frustum.hasBounds(objBounds)) {
if (inst.visibleTicks == 0) {
tmpBounds.load(minfo.baseBounds);
tmpBounds.transform(inst.emptyObj.getAbsPos());
@ -145,6 +147,11 @@ class InstanceManager {
continue;
}
inst.visibleTicks = 10;
} else {
inst.visibleTicks = inst.visibleTicks - 1;
}
if (inst.gameObject.currentOpacity == 1)
opaqueinstances.push(inst);
else if (inst.gameObject.currentOpacity != 0)

View file

@ -370,15 +370,12 @@ class Util {
return str;
}
public static function m_matF_x_vectorF(matrix:Matrix, v:Vector) {
var m = matrix.clone();
m.transpose();
public static inline function m_matF_x_vectorF(m:Matrix, v:Vector) {
var v0 = v.x, v1 = v.y, v2 = v.z;
var vresult_0 = m._11 * v0 + m._12 * v1 + m._13 * v2;
var vresult_1 = m._21 * v0 + m._22 * v1 + m._23 * v2;
var vresult_2 = m._31 * v0 + m._23 * v1 + m._33 * v2;
var vresult_0 = m._11 * v0 + m._21 * v1 + m._31 * v2;
var vresult_1 = m._12 * v0 + m._22 * v1 + m._32 * v2;
var vresult_2 = m._13 * v0 + m._23 * v1 + m._33 * v2;
v.set(vresult_0, vresult_1, vresult_2);
}

View file

@ -30,6 +30,7 @@ class Sequence {
var priority:Int;
var flags:Int;
var dirtyFlags:Int;
var lastSequenceKeyframe:Float;
public function new() {}

View file

@ -80,6 +80,11 @@ class PlayGui {
var powerupImageSceneTargetBitmap:Bitmap;
var powerupImageObject:DtsObject;
var blastBarTile:h2d.Tile;
var blastBarGreenTile:h2d.Tile;
var blastBarGrayTile:h2d.Tile;
var blastBarChargedTile:h2d.Tile;
var RSGOCenterText:Anim;
var helpTextForeground:GuiText;
@ -609,6 +614,11 @@ class PlayGui {
blastFrame.position = new Vector(0, 0);
blastFrame.extent = new Vector(120, 28);
blastBar.addChild(blastFrame);
blastBarTile = ResourceLoader.getResource("data/ui/game/blastbar.png", ResourceLoader.getImage, this.imageResources).toTile();
blastBarGreenTile = ResourceLoader.getResource("data/ui/game/blastbar_bargreen.png", ResourceLoader.getImage, this.imageResources).toTile();
blastBarGrayTile = ResourceLoader.getResource("data/ui/game/blastbar_bargray.png", ResourceLoader.getImage, this.imageResources).toTile();
blastBarChargedTile = ResourceLoader.getResource("data/ui/game/blastbar_charged.png", ResourceLoader.getImage, this.imageResources).toTile();
}
public function setBlastValue(value:Float) {
@ -618,21 +628,21 @@ class PlayGui {
}
if (value <= 1) {
if (blastFill.extent.y == 16) { // Was previously charged
blastFrame.bmp.tile = ResourceLoader.getResource("data/ui/game/blastbar.png", ResourceLoader.getImage, this.imageResources).toTile();
blastFrame.bmp.tile = blastBarTile;
}
var oldVal = blastFill.extent.x;
blastFill.extent = new Vector(Util.lerp(0, 110, value), 17);
if (oldVal < 22 && blastFill.extent.x >= 22) {
blastFill.bmp.tile = ResourceLoader.getResource("data/ui/game/blastbar_bargreen.png", ResourceLoader.getImage, this.imageResources).toTile();
blastFill.bmp.tile = blastBarGreenTile;
MarbleGame.instance.touchInput.blastbutton.setEnabled(true);
}
if (oldVal >= 22 && blastFill.extent.x < 22) {
blastFill.bmp.tile = ResourceLoader.getResource("data/ui/game/blastbar_bargray.png", ResourceLoader.getImage, this.imageResources).toTile();
blastFill.bmp.tile = blastBarGrayTile;
MarbleGame.instance.touchInput.blastbutton.setEnabled(false);
}
} else {
blastFill.extent = new Vector(0, 16); // WE will just use this extra number to store whether it was previously charged or not
blastFrame.bmp.tile = ResourceLoader.getResource("data/ui/game/blastbar_charged.png", ResourceLoader.getImage, this.imageResources).toTile();
blastFrame.bmp.tile = blastBarChargedTile;
MarbleGame.instance.touchInput.blastbutton.setEnabled(true);
}
this.blastBar.render(scene2d);