import tango.stdc.stdio, tango.stdc.time;
struct CalVector4 {
float X, Y, Z, W=0.0;
}
struct BoneTransform {
CalVector4 RowX, RowY, RowZ;
void scale(inout BoneTransform result, float s) {
result.RowX.X = RowX.X * s;
result.RowX.Y = RowX.Y * s;
result.RowX.Z = RowX.Z * s;
result.RowX.W = RowX.W * s;
result.RowY.X = RowY.X * s;
result.RowY.Y = RowY.Y * s;
result.RowY.Z = RowY.Z * s;
result.RowY.W = RowY.W * s;
result.RowZ.X = RowZ.X * s;
result.RowZ.Y = RowZ.Y * s;
result.RowZ.Z = RowZ.Z * s;
result.RowZ.W = RowZ.W * s;
}
void addScaled(inout BoneTransform mutate, float s) {
mutate.RowX.X += RowX.X * s;
mutate.RowX.Y += RowX.Y * s;
mutate.RowX.Z += RowX.Z * s;
mutate.RowX.W += RowX.W * s;
mutate.RowY.X += RowY.X * s;
mutate.RowY.Y += RowY.Y * s;
mutate.RowY.Z += RowY.Z * s;
mutate.RowY.W += RowY.W * s;
mutate.RowZ.X += RowZ.X * s;
mutate.RowZ.Y += RowZ.Y * s;
mutate.RowZ.Z += RowZ.Z * s;
mutate.RowZ.W += RowZ.W * s;
}
void transformPoint(inout CalVector4 result, inout CalVector4 point) {
result = CalVector4(
(RowX.X * point.X) + (RowX.Y * point.Y) + (RowX.Z * point.Z) + RowX.W,
(RowY.X * point.X) + (RowY.Y * point.Y) + (RowY.Z * point.Z) + RowY.W,
(RowZ.X * point.X) + (RowZ.Y * point.Y) + (RowZ.Z * point.Z) + RowZ.W
);
}
void transformVector(inout CalVector4 result, inout CalVector4 vector) {
result = CalVector4(
(RowX.X * vector.X) + (RowX.Y * vector.Y) + (RowX.Z * vector.Z),
(RowY.X * vector.X) + (RowY.Y * vector.Y) + (RowY.Z * vector.Z),
(RowZ.X * vector.X) + (RowZ.Y * vector.Y) + (RowZ.Z * vector.Z)
);
}
}
struct Influence {
int BoneId;
float Weight;
bool LastInfluenceForThisVertex;
}
struct Vertex {
CalVector4 Position, Normal;
}
void calculateVerticesAndNormals(BoneTransform[] boneTransforms,
int vertexCount,
Vertex[] vertices,
Influence[] influences,
CalVector4[] output) {
assert(output.length == vertices.length * 2);
BoneTransform totalTransform;
for (int sourceVertex, sourceInfluence, outputVertex;
sourceVertex < vertices.length;
sourceVertex++, sourceInfluence++, outputVertex += 2) {
auto influence = influences[sourceInfluence];
boneTransforms[influence.BoneId].scale(totalTransform, influence.Weight);
while (!influence.LastInfluenceForThisVertex) {
sourceInfluence += 1;
influence = influences[sourceInfluence];
boneTransforms[influence.BoneId].addScaled(totalTransform, influence.Weight);
}
totalTransform.transformPoint(output[outputVertex], vertices[sourceVertex].Position);
totalTransform.transformVector(output[outputVertex + 1], vertices[sourceVertex].Normal);
}
}
void main() {
const int N = 10_000;
Vertex[N] vertices;
Influence[N] influences;
for (int i = 0; i < N; i++) {
vertices[i] = Vertex(CalVector4(1, 2, 3), CalVector4(0, 0, 1));
influences[i] = Influence(0, 1.0f, true);
}
auto boneTransforms = new BoneTransform[1];
auto output = new CalVector4[N * 2];
for (int i = 0; i < 100; i++) {
long verticesSkinned = 0;
clock_t start = clock();
while (clock() < start + CLOCKS_PER_SEC) {
calculateVerticesAndNormals(boneTransforms, N, vertices, influences, output);
verticesSkinned += N;
}
clock_t elapsed = clock() - start;
printf("Skinned vertices per second: %d\n",
cast(int)(verticesSkinned * CLOCKS_PER_SEC / elapsed));
}
}