Skip to content

Commit

Permalink
Use 4x4 matrices for transforms
Browse files Browse the repository at this point in the history
  • Loading branch information
wtholliday committed Oct 11, 2023
1 parent 715c140 commit 17d5078
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 22 deletions.
12 changes: 5 additions & 7 deletions Sources/vger/vger.metal
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ kernel void vger_prune(uint gid [[thread_position_in_grid]],
vertex VertexOut vger_vertex(uint vid [[vertex_id]],
uint iid [[instance_id]],
const device vgerPrim* prims,
const device float3x3* xforms,
const device float4x4* xforms,
constant float2& viewSize) {

device auto& prim = prims[iid];
Expand All @@ -67,13 +67,11 @@ vertex VertexOut vger_vertex(uint vid [[vertex_id]],
out.primIndex = iid;
out.t = float2(prim.texBounds[vid & 1].x, prim.texBounds[vid >> 1].y);

auto q = xforms[prim.xform] * float3(float2(prim.quadBounds[vid & 1].x,
prim.quadBounds[vid >> 1].y),
1.0);
out.position = xforms[prim.xform] * float4(prim.quadBounds[vid & 1].x,
prim.quadBounds[vid >> 1].y,
0.0,
1.0);

auto p = float2{q.x/q.z, q.y/q.z};
out.position = float4(2.0 * p / viewSize - 1.0, 0, 1);

return out;
}

Expand Down
40 changes: 28 additions & 12 deletions Sources/vger/vger.mm
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,14 @@
scene.cvs = GPUVec<float2>(device);
scene.cvs.buffer.label = [NSString stringWithFormat:@"cv buffer scene %d", i];

scene.xforms = GPUVec<float3x3>(device);
scene.xforms = GPUVec<float4x4>(device);
scene.xforms.buffer.label = [NSString stringWithFormat:@"xform buffer scene %d", i];

scene.paints = GPUVec<vgerPaint>(device);
scene.paints.buffer.label = [NSString stringWithFormat:@"paints buffer scene %d", i];

scenes[i] = scene;
}
txStack.push_back(matrix_identity_float3x3);

auto desc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm width:1 height:1 mipmapped:NO];
nullTexture = [device newTextureWithDescriptor:desc];
Expand Down Expand Up @@ -80,6 +79,15 @@ void vgerDelete(vgerContext vg) {
this->devicePxRatio = devicePxRatio;
computedGlyphBounds = false;

// Add view transform to matrix stack.
txStack.clear();
auto M = matrix_identity_float4x4;
M.columns[0].x = 2.0 / windowWidth;
M.columns[1].y = 2.0 / windowHeight;
M.columns[3].x = -1;
M.columns[3].y = -1;
txStack.push_back(M);

// Prune the text cache.
for(auto it = std::begin(textCache); it != std::end(textCache);) {
if (it->second.lastFrame != currentFrame) {
Expand Down Expand Up @@ -319,9 +327,9 @@ size_t vgerPrimCount(vgerContext vg) {
return vg->primCount();
}

static float averageScale(const float3x3& M)
static float averageScale(const float4x4& M, float2 windowSize)
{
return 0.5f * (length(M.columns[0].xy) + length(M.columns[1].xy));
return 0.5f * (length(M.columns[0].xy) * windowSize.x/2 + length(M.columns[1].xy) * windowSize.y/2);
}

static float2 alignOffset(CTLineRef line, int align) {
Expand Down Expand Up @@ -501,7 +509,7 @@ void vgerText(vgerContext vg, const char* str, float4 color, int align) {

} else {

auto scale = averageScale(txStack.back()) * devicePxRatio;
auto scale = averageScale(txStack.back(), windowSize) * devicePxRatio;
auto key = TextLayoutKey{std::string(str), scale, align};

if(renderCachedText(key, paint, xform)) {
Expand Down Expand Up @@ -592,7 +600,7 @@ void vgerTextBox(vgerContext vg, const char* str, float breakRowWidth, float4 co
}

auto paint = vgerColorPaint(this, color);
auto scale = averageScale(txStack.back()) * devicePxRatio;
auto scale = averageScale(txStack.back(), windowSize) * devicePxRatio;
auto key = TextLayoutKey{std::string(str), scale, align, breakRowWidth};
auto xform = addxform(txStack.back());

Expand Down Expand Up @@ -840,13 +848,20 @@ static bool isValid(matrix_float3x3 M) {
isValid(M.columns[2]);
}

static bool isValid(matrix_float4x4 M) {
return isValid(M.columns[0]) &&
isValid(M.columns[1]) &&
isValid(M.columns[2]) &&
isValid(M.columns[3]);
}

void vgerTranslate(vgerContext vg, float2 t) {
if(!isValid(t)) {
fprintf(stderr, "vgerTranslate: bad translation: (%f, %f)\n", t.x, t.y);
return;
}
auto M = matrix_identity_float3x3;
M.columns[2] = vector3(t, 1);
auto M = matrix_identity_float4x4;
M.columns[3] = float4{t.x, t.y, 0, 1};

assert(!vg->txStack.empty());
auto A = vg->txStack.back();
Expand All @@ -865,7 +880,7 @@ void vgerScale(vgerContext vg, float2 s) {
fprintf(stderr, "vgerScale: bad scale: (%f, %f)\n", s.x, s.y);
return;
}
auto M = matrix_identity_float3x3;
auto M = matrix_identity_float4x4;
M.columns[0].x = s.x;
M.columns[1].y = s.y;

Expand All @@ -881,7 +896,7 @@ void vgerScale(vgerContext vg, float2 s) {
}

void vgerRotate(vgerContext vg, float theta) {
auto M = matrix_identity_float3x3;
auto M = matrix_identity_float4x4;
M.columns[0].x = cosf(theta);
M.columns[0].y = sinf(theta);
M.columns[1].x = - M.columns[0].y;
Expand All @@ -894,8 +909,9 @@ void vgerRotate(vgerContext vg, float theta) {
/// Transforms a point according to the current transformation.
float2 vgerTransform(vgerContext vg, float2 p) {
auto& M = vg->txStack.back();
auto q = matrix_multiply(M, float3{p.x,p.y,1.0});
return {q.x/q.z, q.y/q.z};
auto q = matrix_multiply(M, float4{p.x,p.y,0.0,1.0});
return { (q.x/q.w + 1) * vg->windowSize.x / 2,
(q.y/q.w + 1) * vg->windowSize.y / 2};
}

simd_float3x2 vgerCurrentTransform(vgerContext vg) {
Expand Down
2 changes: 1 addition & 1 deletion Sources/vger/vgerScene.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ struct GPUVec {
struct vgerScene {
GPUVec<vgerPrim> prims[VGER_MAX_LAYERS];
GPUVec<float2> cvs;
GPUVec<float3x3> xforms;
GPUVec<float4x4> xforms;
GPUVec<vgerPaint> paints;

void clear() {
Expand Down
4 changes: 2 additions & 2 deletions Sources/vger/vger_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ struct vger {
vgerRenderer* glowRenderer;

/// Transform matrix stack.
std::vector<float3x3> txStack;
std::vector<float4x4> txStack;

/// Number of buffers.
int maxBuffers = 1;
Expand Down Expand Up @@ -138,7 +138,7 @@ struct vger {
scenes[currentScene].cvs.append(p);
}

uint32_t addxform(const matrix_float3x3& M) {
uint32_t addxform(const matrix_float4x4& M) {
uint32_t idx = (uint32_t) scenes[currentScene].xforms.count;
scenes[currentScene].xforms.append(M);
return idx;
Expand Down

0 comments on commit 17d5078

Please sign in to comment.