Expose camera matrix in SkCanvas
3 new getters:
- localToWorld
- localToCamera
- localToDevice (same as total-matrix)
The current tracking minimizes overhead, by using a computed inverse to
produce the localToWorld/Camera. This can be change as needed in the
future (more precision, but more memory/overhead), but for now is
sufficient to try out the new APIs.
Change-Id: I85440318f36dca935124b782e110fe9c0152ae7a
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/264648
Commit-Queue: Mike Reed <reed@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
Reviewed-by: Florin Malita <fmalita@chromium.org>
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index c43ad4d..cc46277 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -736,10 +736,8 @@
int SkCanvas::saveCamera(const SkMatrix44& projection, const SkMatrix44& camera) {
// TODO: add a virtual for this, and update clients (e.g. chrome)
int n = this->save();
- this->concat(projection);
- // TODO: remember this point in the matrix stack, so we can communicate it to shaders
- // that want to perform lighting.
- this->concat(camera);
+ this->concat(projection * camera);
+ fCameraStack.push_back(CameraRec(fMCRec, camera));
return n;
}
@@ -1269,6 +1267,10 @@
// move this out before we do the actual restore
auto backImage = std::move(fMCRec->fBackImage);
+ if (!fCameraStack.empty() && fCameraStack.back().fMCRec == fMCRec) {
+ fCameraStack.pop_back();
+ }
+
// now do the normal restore()
fMCRec->~MCRec(); // balanced in save()
fMCStack.pop_back();
@@ -1435,7 +1437,7 @@
void SkCanvas::translate(SkScalar dx, SkScalar dy) {
if (dx || dy) {
this->checkForDeferredSave();
- fMCRec->fMatrix.preTranslate(dx,dy);
+ fMCRec->fMatrix.preTranslate(dx, dy);
// Translate shouldn't affect the is-scale-translateness of the matrix.
// However, if either is non-finite, we might still complicate the matrix type,
@@ -1494,6 +1496,7 @@
this->checkForDeferredSave();
fMCRec->fMatrix.preConcat(matrix);
+
fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
FOR_EACH_TOP_DEVICE(device->setGlobalCTM(fMCRec->fMatrix));
@@ -1504,7 +1507,7 @@
void SkCanvas::concat44(const SkScalar m[16]) {
this->checkForDeferredSave();
- fMCRec->fMatrix.preConcat44(m);
+ fMCRec->fMatrix.preConcat16(m);
fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
@@ -1786,7 +1789,7 @@
SkMatrix inverse;
// if we can't invert the CTM, we can't return local clip bounds
- if (!fMCRec->fMatrix.invert(&inverse)) {
+ if (!fMCRec->fMatrix.asM33().invert(&inverse)) {
return SkRect::MakeEmpty();
}
@@ -1803,14 +1806,44 @@
return fMCRec->fRasterClip.getBounds();
}
+///////////////////////////////////////////////////////////////////////
+
+SkCanvas::CameraRec::CameraRec(MCRec* owner, const SkM44& camera)
+ : fMCRec(owner)
+ , fCamera(camera)
+{
+ // assumes the mcrec has already been concatenated with the camera
+ if (!owner->fMatrix.invert(&fInvPostCamera)) {
+ fInvPostCamera.setIdentity();
+ }
+}
+
SkMatrix SkCanvas::getTotalMatrix() const {
return fMCRec->fMatrix;
}
-SkM44 SkCanvas::getTotalM44() const {
+SkM44 SkCanvas::getLocalToDevice() const {
return fMCRec->fMatrix;
}
+SkM44 SkCanvas::getLocalToWorld() const {
+ if (fCameraStack.empty()) {
+ return this->getLocalToDevice();
+ } else {
+ const auto& top = fCameraStack.back();
+ return top.fInvPostCamera * this->getLocalToDevice();
+ }
+}
+
+SkM44 SkCanvas::getLocalToCamera() const {
+ if (fCameraStack.empty()) {
+ return this->getLocalToDevice();
+ } else {
+ const auto& top = fCameraStack.back();
+ return top.fCamera * top.fInvPostCamera * this->getLocalToDevice();
+ }
+}
+
GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
SkBaseDevice* dev = this->getTopDevice();
return dev ? dev->accessRenderTargetContext() : nullptr;