Add markCTM to canvaskit API, use in 3D cube example

Change-Id: Id0eafdf0fd69f080e26e2bee5c7b38eb55b6a5c0
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/287897
Commit-Queue: Nathaniel Nifong <nifong@google.com>
Reviewed-by: Kevin Lubick <kjlubick@google.com>
This commit is contained in:
Nathaniel Nifong 2020-05-06 16:22:33 -04:00 committed by Skia Commit-Bot
parent 00ee8f58aa
commit 00de91c591
5 changed files with 69 additions and 17 deletions

View File

@ -616,9 +616,9 @@ const curves = {
in fragmentProcessor color_map;
in fragmentProcessor normal_map;
uniform float4x4 localToWorld;
uniform float4x4 localToWorldAdjInv;
uniform float3 lightPos;
layout (marker=local_to_world) uniform float4x4 localToWorld;
layout (marker=normals(local_to_world)) uniform float4x4 localToWorldAdjInv;
float3 convert_normal_sample(half4 c) {
float3 n = 2 * c.rgb - 1;
@ -628,7 +628,7 @@ const curves = {
void main(float2 p, inout half4 color) {
float3 norm = convert_normal_sample(sample(normal_map, p));
float3 plane_norm = normalize(localToWorld * float4(norm, 0)).xyz;
float3 plane_norm = normalize(localToWorldAdjInv * float4(norm, 0)).xyz;
float3 plane_pos = (localToWorld * float4(p, 0, 1)).xyz;
float3 light_dir = normalize(lightPos - plane_pos);
@ -640,6 +640,7 @@ const curves = {
color = sample(color_map, p) * half4(float4(scale, scale, scale, 1));
}
`;
const fact = CanvasKit.SkRuntimeEffect.Make(prog);
// properties of light
@ -723,7 +724,8 @@ const curves = {
// as part of our "camera".
canvas.concat(CanvasKit.SkM44.multiply(viewport, perspective));
canvas.concat(CanvasKit.SkM44.multiply(camera, mustInvert(viewport)));
// canvas.markCTM(...);
// Mark the matrix to make it available to the shader by this name.
canvas.markCTM('local_to_world');
}
function setClickToWorld(canvas, matrix) {
@ -739,9 +741,9 @@ const curves = {
if (znormal < 0) {
return; // skip faces facing backwards
}
const ltw = canvas.getLocalToWorld();
// shader expects the 4x4 matrices in column major order.
const uniforms = [...CanvasKit.SkM44.transpose(ltw), ...mustInvert(ltw), ...lightWorldPos];
// Pad with space for two 4x4 matrices. Even though the shader uses a layout()
// statement to populate them, we still have to reserve space for them.
const uniforms = [...lightWorldPos, ...Array(32).fill(0)];
const paint = new CanvasKit.SkPaint();
paint.setAntiAlias(true);
const shader = fact.makeShaderWithChildren(uniforms, true /*=opaque*/, children);

View File

@ -985,6 +985,21 @@ EMSCRIPTEN_BINDINGS(Skia) {
.function("makeSurface", optional_override([](SkCanvas& self, SimpleImageInfo sii)->sk_sp<SkSurface> {
return self.makeSurface(toSkImageInfo(sii), nullptr);
}), allow_raw_pointers())
.function("markCTM", optional_override([](SkCanvas& self, std::string marker) {
self.markCTM(marker.c_str());
}))
.function("_findMarkedCTM", optional_override([](SkCanvas& self, std::string marker, uintptr_t /* SkScalar* */ mPtr) -> bool {
SkScalar* sixteenMatrixValues = reinterpret_cast<SkScalar*>(mPtr);
if (!sixteenMatrixValues) {
return false; // matrix cannot be null
}
SkM44 m;
if (self.findMarkedCTM(marker.c_str(), &m)) {
m.getRowMajor(sixteenMatrixValues);
return true;
}
return false;
}))
.function("_readPixels", optional_override([](SkCanvas& self, SimpleImageInfo di,
uintptr_t /* uint8_t* */ pPtr,
size_t dstRowBytes, int srcX, int srcY) {

View File

@ -200,6 +200,8 @@ var CanvasKit = {
flush: function() {},
getSaveCount: function() {},
makeSurface: function() {},
markCTM: function() {},
findMarkedCTM: function() {},
restore: function() {},
restoreToCount: function() {},
rotate: function() {},
@ -227,6 +229,7 @@ var CanvasKit = {
_getLocalToDevice: function() {},
_getLocalToWorld: function() {},
_getTotalMatrix: function() {},
_findMarkedCTM: function() {},
_readPixels: function() {},
_writePixels: function() {},
delete: function() {},

View File

@ -978,6 +978,18 @@ CanvasKit.onRuntimeInitialized = function() {
return copy4x4MatrixFromWasm(matrPtr);
}
// findMarkedCTM returns a 4x4 matrix, or null if a matrix was not found at
// the provided marker.
CanvasKit.SkCanvas.prototype.findMarkedCTM = function(marker) {
var matrPtr = CanvasKit._malloc(16 * 4); // allocate space for the matrix
// _getLocalToDevice will copy the values into the pointer.
var found = this._findMarkedCTM(marker, matrPtr);
if (!found) {
return null;
}
return copy4x4MatrixFromWasm(matrPtr);
}
// getTotalMatrix returns the current matrix as a 3x3 matrix.
CanvasKit.SkCanvas.prototype.getTotalMatrix = function() {
var matrPtr = CanvasKit._malloc(9 * 4); // allocate space for the matrix

View File

@ -579,6 +579,26 @@ describe('Canvas Behavior', () => {
}
};
it('can mark a CTM and retrieve it', () => {
const canvas = new CanvasKit.SkCanvas();
canvas.concat(CanvasKit.SkM44.rotated([0, 1, 0], Math.PI/4));
canvas.concat(CanvasKit.SkM44.rotated([1, 0, 1], Math.PI/8));
canvas.markCTM('krispykreme');
const expected = CanvasKit.SkM44.multiply(
CanvasKit.SkM44.rotated([0, 1, 0], Math.PI/4),
CanvasKit.SkM44.rotated([1, 0, 1], Math.PI/8),
);
expect4x4MatricesToMatch(expected, canvas.findMarkedCTM('krispykreme'));
});
it('returns null for an invalid CTM marker', () => {
const canvas = new CanvasKit.SkCanvas();
expect(canvas.findMarkedCTM('dunkindonuts')).toBeNull();
});
it('can change the 4x4 matrix on the canvas and read it back', () => {
const canvas = new CanvasKit.SkCanvas();