Improve zoom window in Viewer

Made a more general mechanism for getting a canvas callback during GUI
rendering, clipped to a region. Use that to implement the zoom window.
The new version has better zoom control (I think), avoids bugs with
clamped image drawing stretching off-canvas, adds a highlight of the
pixel under the cursor, and also prints the RGBA values of that pixel.

Bug: skia:
Change-Id: I2c4da581648e7923c2a6fb28846dfdb52bdd3029
Reviewed-on: https://skia-review.googlesource.com/70723
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
This commit is contained in:
Brian Osman 2017-11-13 15:36:36 -05:00 committed by Skia Commit-Bot
parent e92b1b16f7
commit ead517d822

View File

@ -1114,6 +1114,15 @@ static void ImGui_Primaries(SkColorSpacePrimaries* primaries, SkPaint* gamutPain
ImGui::SetCursorPos(endPos);
}
typedef std::function<void(SkCanvas*)> CustomGuiPainter;
static SkTArray<CustomGuiPainter> gCustomGuiPainters;
static void ImGui_Skia_Callback(const ImVec2& size, CustomGuiPainter painter) {
intptr_t painterIndex = gCustomGuiPainters.count();
gCustomGuiPainters.push_back(painter);
ImGui::Image((ImTextureID)painterIndex, size);
}
void Viewer::drawImGui(SkCanvas* canvas) {
// Support drawing the ImGui demo window. Superfluous, but gives a good idea of what's possible
if (fShowImGuiTestWindow) {
@ -1294,24 +1303,40 @@ void Viewer::drawImGui(SkCanvas* canvas) {
ImGui::End();
}
SkPaint zoomImagePaint;
if (fShowZoomWindow && fLastImage) {
if (ImGui::Begin("Zoom", &fShowZoomWindow, ImVec2(200, 200))) {
static int zoomFactor = 4;
ImGui::SliderInt("Scale", &zoomFactor, 1, 16);
static int zoomFactor = 8;
if (ImGui::Button("<<")) {
zoomFactor = SkTMax(zoomFactor / 2, 4);
}
ImGui::SameLine(); ImGui::Text("%2d", zoomFactor); ImGui::SameLine();
if (ImGui::Button(">>")) {
zoomFactor = SkTMin(zoomFactor * 2, 32);
}
zoomImagePaint.setShader(fLastImage->makeShader());
zoomImagePaint.setColor(SK_ColorWHITE);
// Zoom by shrinking the corner UVs towards the mouse cursor
ImVec2 mousePos = ImGui::GetMousePos();
ImVec2 avail = ImGui::GetContentRegionAvail();
ImVec2 zoomHalfExtents = ImVec2((avail.x * 0.5f) / zoomFactor,
(avail.y * 0.5f) / zoomFactor);
ImGui::Image(&zoomImagePaint, avail,
ImVec2(mousePos.x - zoomHalfExtents.x, mousePos.y - zoomHalfExtents.y),
ImVec2(mousePos.x + zoomHalfExtents.x, mousePos.y + zoomHalfExtents.y));
uint32_t pixel = 0;
SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
if (fLastImage->readPixels(info, &pixel, info.minRowBytes(), mousePos.x, mousePos.y)) {
ImGui::SameLine();
ImGui::Text("RGBA: %x %x %x %x", SkGetPackedR32(pixel), SkGetPackedG32(pixel),
SkGetPackedB32(pixel), SkGetPackedA32(pixel));
}
ImGui_Skia_Callback(avail, [=](SkCanvas* c) {
// Translate so the region of the image that's under the mouse cursor is centered
// in the zoom canvas:
c->scale(zoomFactor, zoomFactor);
c->translate(avail.x * 0.5f / zoomFactor - mousePos.x - 0.5f,
avail.y * 0.5f / zoomFactor - mousePos.y - 0.5f);
c->drawImage(this->fLastImage, 0, 0);
SkPaint outline;
outline.setStyle(SkPaint::kStroke_Style);
c->drawRect(SkRect::MakeXYWH(mousePos.x, mousePos.y, 1, 1), outline);
});
}
ImGui::End();
@ -1347,27 +1372,42 @@ void Viewer::drawImGui(SkCanvas* canvas) {
for (int j = 0; j < drawList->CmdBuffer.size(); ++j) {
const ImDrawCmd* drawCmd = &drawList->CmdBuffer[j];
SkAutoCanvasRestore acr(canvas, true);
// TODO: Find min/max index for each draw, so we know how many vertices (sigh)
if (drawCmd->UserCallback) {
drawCmd->UserCallback(drawList, drawCmd);
} else {
intptr_t idIndex = (intptr_t)drawCmd->TextureId;
if (idIndex < gCustomGuiPainters.count()) {
// Small image IDs are actually indices into a list of callbacks. We directly
// examing the vertex data to deduce the image rectangle, then reconfigure the
// canvas to be clipped and translated so that the callback code gets to use
// Skia to render a widget in the middle of an ImGui panel.
ImDrawIdx rectIndex = drawList->IdxBuffer[indexOffset];
SkPoint tl = pos[rectIndex], br = pos[rectIndex + 2];
canvas->clipRect(SkRect::MakeLTRB(tl.fX, tl.fY, br.fX, br.fY));
canvas->translate(tl.fX, tl.fY);
gCustomGuiPainters[idIndex](canvas);
} else {
SkPaint* paint = static_cast<SkPaint*>(drawCmd->TextureId);
SkASSERT(paint);
canvas->save();
canvas->clipRect(SkRect::MakeLTRB(drawCmd->ClipRect.x, drawCmd->ClipRect.y,
drawCmd->ClipRect.z, drawCmd->ClipRect.w));
canvas->drawVertices(SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode,
drawList->VtxBuffer.size(), pos.begin(),
uv.begin(), color.begin(),
auto vertices = SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode,
drawList->VtxBuffer.size(),
pos.begin(), uv.begin(), color.begin(),
drawCmd->ElemCount,
drawList->IdxBuffer.begin() + indexOffset),
SkBlendMode::kModulate, *paint);
drawList->IdxBuffer.begin() + indexOffset);
canvas->drawVertices(vertices, SkBlendMode::kModulate, *paint);
indexOffset += drawCmd->ElemCount;
canvas->restore();
}
}
}
}
gCustomGuiPainters.reset();
}
void Viewer::onIdle() {