Optimized hit testing feature, refactored into seperate function from canvas draw calls
Review URL: https://codereview.appspot.com/6443068 git-svn-id: http://skia.googlecode.com/svn/trunk@4867 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
622a17091b
commit
0b5bbb0f82
@ -33,9 +33,7 @@ SkCanvasWidget::SkCanvasWidget() : QWidget()
|
||||
}
|
||||
|
||||
SkCanvasWidget::~SkCanvasWidget() {
|
||||
if (fDebugCanvas) {
|
||||
delete fDebugCanvas;
|
||||
}
|
||||
delete fDebugCanvas;
|
||||
}
|
||||
|
||||
void SkCanvasWidget::drawTo(int index) {
|
||||
@ -78,13 +76,8 @@ void SkCanvasWidget::mouseMoveEvent(QMouseEvent* event) {
|
||||
|
||||
void SkCanvasWidget::mousePressEvent(QMouseEvent* event) {
|
||||
fPreviousPoint.set(event->globalX(), event->globalY());
|
||||
if (fDebugCanvas) {
|
||||
fDebugCanvas->getBoxClass()->setHitPoint(event->x(), event->y());
|
||||
fDebugCanvas->isCalculatingHits(true);
|
||||
drawTo(fIndex);
|
||||
emit hitChanged(fDebugCanvas->getHitBoxPoint());
|
||||
fDebugCanvas->isCalculatingHits(false);
|
||||
}
|
||||
emit hitChanged(fDebugCanvas->getLayerAtPoint(event->x(), event->y(),
|
||||
fIndex, fTransform, fScaleFactor));
|
||||
}
|
||||
|
||||
void SkCanvasWidget::mouseDoubleClickEvent(QMouseEvent* event) {
|
||||
|
@ -54,8 +54,7 @@ void SkGLWidget::paintGL() {
|
||||
} else if (fScaleFactor > 0) {
|
||||
canvas.scale(fScaleFactor, fScaleFactor);
|
||||
}
|
||||
// TODO(chudy): Remove bitmap arguement.
|
||||
fDebugCanvas->drawTo(&canvas, fIndex+1, NULL);
|
||||
fDebugCanvas->drawTo(&canvas, fIndex);
|
||||
canvas.flush();
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ public:
|
||||
|
||||
void setDebugCanvas(SkDebugCanvas* debugCanvas) {
|
||||
fDebugCanvas = debugCanvas;
|
||||
fIndex = debugCanvas->getSize();
|
||||
fIndex = debugCanvas->getSize() - 1;
|
||||
this->updateGL();
|
||||
}
|
||||
|
||||
|
@ -28,12 +28,8 @@ SkRasterWidget::~SkRasterWidget() {
|
||||
void SkRasterWidget::resizeEvent(QResizeEvent* event) {
|
||||
fBitmap.setConfig(SkBitmap::kARGB_8888_Config, event->size().width(), event->size().height());
|
||||
fBitmap.allocPixels();
|
||||
if (fDevice) {
|
||||
delete fDevice;
|
||||
}
|
||||
fDevice = new SkDevice(fBitmap);
|
||||
|
||||
|
||||
delete fDevice;
|
||||
fDevice = new SkDevice(fBitmap);
|
||||
this->update();
|
||||
}
|
||||
|
||||
@ -50,7 +46,7 @@ void SkRasterWidget::paintEvent(QPaintEvent* event) {
|
||||
|
||||
fMatrix = canvas.getTotalMatrix();
|
||||
fClip = canvas.getTotalClip().getBounds();
|
||||
fDebugCanvas->drawTo(&canvas, fIndex+1, &fBitmap);
|
||||
fDebugCanvas->drawTo(&canvas, fIndex);
|
||||
|
||||
QPainter painter(this);
|
||||
QStyleOption opt;
|
||||
|
@ -31,7 +31,7 @@ public:
|
||||
|
||||
void setDebugCanvas(SkDebugCanvas* debugCanvas) {
|
||||
fDebugCanvas = debugCanvas;
|
||||
fIndex = debugCanvas->getSize();
|
||||
fIndex = debugCanvas->getSize() - 1;
|
||||
this->update();
|
||||
}
|
||||
|
||||
|
@ -29,47 +29,62 @@ void SkDebugCanvas::addDrawCommand(SkDrawCommand* command) {
|
||||
void SkDebugCanvas::draw(SkCanvas* canvas) {
|
||||
if(!commandVector.empty()) {
|
||||
for(it = commandVector.begin(); it != commandVector.end(); ++it) {
|
||||
if ((*it)->getVisibility()) {
|
||||
if ((*it)->isVisible()) {
|
||||
(*it)->execute(canvas);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SkDebugCanvas::drawTo(SkCanvas* canvas, int index, SkBitmap* bitmap) {
|
||||
int counter = 0;
|
||||
if(!commandVector.empty()) {
|
||||
for(it = commandVector.begin(); it != commandVector.end(); ++it) {
|
||||
if (counter != (index-1)) {
|
||||
if ((*it)->getVisibility()) {
|
||||
(*it)->execute(canvas);
|
||||
}
|
||||
} else {
|
||||
if (fFilter) {
|
||||
SkPaint* p = new SkPaint();
|
||||
p->setColor(0xAAFFFFFF);
|
||||
canvas->save();
|
||||
canvas->resetMatrix();
|
||||
SkRect dump;
|
||||
// TODO(chudy): Replace with a call to QtWidget to get dimensions.
|
||||
dump.set(SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(fWidth), SkIntToScalar(fHeight));
|
||||
canvas->clipRect(dump, SkRegion::kReplace_Op, false );
|
||||
canvas->drawRectCoords(SkIntToScalar(0),SkIntToScalar(0),SkIntToScalar(fWidth),SkIntToScalar(fHeight), *p);
|
||||
canvas->restore();
|
||||
}
|
||||
if ((*it)->getVisibility()) {
|
||||
(*it)->execute(canvas);
|
||||
}
|
||||
}
|
||||
if (fCalculateHits == true && bitmap != NULL) {
|
||||
fHitBox.updateHitPoint(bitmap, counter);
|
||||
}
|
||||
int SkDebugCanvas::getCommandAtPoint(int x, int y, int index,
|
||||
SkIPoint transform, float scale) {
|
||||
SkBitmap bitmap;
|
||||
bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
|
||||
bitmap.allocPixels();
|
||||
|
||||
/* TODO(chudy): Implement a bitmap wide function that will take
|
||||
* ~50 out of each R,G,B. This will make everything but the last
|
||||
* command brighter.
|
||||
*/
|
||||
if (++counter == index) return;
|
||||
SkCanvas canvas(bitmap);
|
||||
canvas.translate(transform.fX - x, transform.fY - y);
|
||||
if (scale < 0) {
|
||||
canvas.scale((1.0 / -scale), (1.0 / -scale));
|
||||
} else if (scale > 0) {
|
||||
canvas.scale(scale, scale);
|
||||
}
|
||||
|
||||
int layer = 0;
|
||||
int prev = bitmap.getColor(0,0);
|
||||
for (int i = 0; i < index; i++) {
|
||||
if (commandVector[i]->isVisible()) {
|
||||
commandVector[i]->execute(&canvas);
|
||||
}
|
||||
if (prev != bitmap.getColor(0,0)) {
|
||||
layer = i;
|
||||
}
|
||||
prev = bitmap.getColor(0,0);
|
||||
}
|
||||
return layer;
|
||||
}
|
||||
|
||||
void SkDebugCanvas::drawTo(SkCanvas* canvas, int index) {
|
||||
int counter = 0;
|
||||
SkASSERT(!commandVector.empty());
|
||||
SkASSERT(index < commandVector.size());
|
||||
for (int i = 0; i <= index; i++) {
|
||||
if (i == index && fFilter) {
|
||||
SkPaint p;
|
||||
p.setColor(0xAAFFFFFF);
|
||||
canvas->save();
|
||||
canvas->resetMatrix();
|
||||
SkRect mask;
|
||||
mask.set(SkIntToScalar(0), SkIntToScalar(0),
|
||||
SkIntToScalar(fWidth), SkIntToScalar(fHeight));
|
||||
canvas->clipRect(mask, SkRegion::kReplace_Op, false);
|
||||
canvas->drawRectCoords(SkIntToScalar(0), SkIntToScalar(0),
|
||||
SkIntToScalar(fWidth), SkIntToScalar(fHeight), p);
|
||||
canvas->restore();
|
||||
}
|
||||
|
||||
if (commandVector[i]->isVisible()) {
|
||||
commandVector[i]->execute(canvas);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -86,7 +101,7 @@ std::vector<std::string>* SkDebugCanvas::getCommandInfoAt(int index) {
|
||||
|
||||
bool SkDebugCanvas::getDrawCommandVisibilityAt(int index) {
|
||||
SkASSERT(index < commandVector.size());
|
||||
return commandVector[index]->getVisibility();
|
||||
return commandVector[index]->isVisible();
|
||||
}
|
||||
|
||||
std::vector<SkDrawCommand*> SkDebugCanvas::getDrawCommands() {
|
||||
@ -252,5 +267,5 @@ bool SkDebugCanvas::translate(SkScalar dx, SkScalar dy) {
|
||||
|
||||
void SkDebugCanvas::toggleCommand(int index, bool toggle) {
|
||||
SkASSERT(index < commandVector.size());
|
||||
commandVector[index]->setVisibility(toggle);
|
||||
commandVector[index]->setVisible(toggle);
|
||||
}
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include "SkCanvas.h"
|
||||
#include "SkDrawCommand.h"
|
||||
#include "SkPicture.h"
|
||||
#include "SkHitBox.h"
|
||||
#include <vector>
|
||||
|
||||
class SkDebugCanvas : public SkCanvas {
|
||||
@ -43,7 +42,13 @@ public:
|
||||
@param canvas The canvas being drawn to
|
||||
@param index The index of the final command being executed
|
||||
*/
|
||||
void drawTo(SkCanvas* canvas, int index, SkBitmap* bitmap);
|
||||
void drawTo(SkCanvas* canvas, int index);
|
||||
|
||||
/**
|
||||
Returns the index of the last draw command to write to the pixel at (x,y)
|
||||
*/
|
||||
int getCommandAtPoint(int x, int y, int index,
|
||||
SkIPoint transform, float scale);
|
||||
|
||||
/**
|
||||
Returns the draw command at the given index.
|
||||
@ -73,21 +78,6 @@ public:
|
||||
*/
|
||||
std::vector<std::string>* getDrawCommandsAsStrings();
|
||||
|
||||
/**
|
||||
Returns the mapping of all pixels to a layer value.
|
||||
*/
|
||||
int* getHitBox() {
|
||||
return fHitBox.getHitBox();
|
||||
}
|
||||
|
||||
SkHitBox* getBoxClass() {
|
||||
return &fHitBox;
|
||||
}
|
||||
|
||||
int getHitBoxPoint() {
|
||||
return fHitBox.getPoint();
|
||||
}
|
||||
|
||||
/**
|
||||
Returns length of draw command vector.
|
||||
*/
|
||||
@ -95,10 +85,6 @@ public:
|
||||
return commandVector.size();
|
||||
}
|
||||
|
||||
void isCalculatingHits(bool isEnabled) {
|
||||
fCalculateHits = isEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
Toggles the visibility / execution of the draw command at index i with
|
||||
the value of toggle.
|
||||
@ -194,8 +180,6 @@ private:
|
||||
int fHeight;
|
||||
int fWidth;
|
||||
SkBitmap fBm;
|
||||
SkHitBox fHitBox;
|
||||
bool fCalculateHits;
|
||||
bool fFilter;
|
||||
|
||||
/**
|
||||
|
@ -28,8 +28,13 @@ public:
|
||||
return GetCommandString(fDrawType);
|
||||
}
|
||||
|
||||
bool getVisibility() const { return fVisible; }
|
||||
void setVisibility(bool toggle) {fVisible = toggle; }
|
||||
bool isVisible() const {
|
||||
return fVisible;
|
||||
}
|
||||
|
||||
void setVisible(bool toggle) {
|
||||
fVisible = toggle;
|
||||
}
|
||||
|
||||
std::vector<std::string>* Info() {return &fInfo; };
|
||||
virtual void execute(SkCanvas* canvas)=0;
|
||||
|
@ -1,66 +0,0 @@
|
||||
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
#include "SkHitBox.h"
|
||||
|
||||
SkHitBox::SkHitBox() {
|
||||
fHitBox = NULL;
|
||||
fX = -1;
|
||||
fY = -1;
|
||||
fLayer = -1;
|
||||
}
|
||||
|
||||
SkHitBox::~SkHitBox() {}
|
||||
|
||||
void SkHitBox::alloc(int width, int height) {
|
||||
free(fHitBox);
|
||||
int length = width * height;
|
||||
fHitBox = (int*) malloc(length * sizeof(int));
|
||||
for (int i = 0; i < length; i++) {
|
||||
fHitBox[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void SkHitBox::updateHitBox(SkBitmap* newBitmap, int layer) {
|
||||
int length = fPrev.width() * fPrev.height();
|
||||
int* prevBase = (int*)fPrev.getPixels();
|
||||
int* currBase = (int*)newBitmap->getPixels();
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (SkUnPreMultiply::PMColorToColor(prevBase[i]) !=
|
||||
SkUnPreMultiply::PMColorToColor(currBase[i])) {
|
||||
fHitBox[i] = layer;
|
||||
}
|
||||
}
|
||||
if (fPrev.empty()) {
|
||||
alloc(newBitmap->width(), newBitmap->height());
|
||||
fPrev.setConfig(SkBitmap::kARGB_8888_Config, newBitmap->width(), newBitmap->height());
|
||||
fPrev.allocPixels();
|
||||
}
|
||||
newBitmap->deepCopyTo(&fPrev, SkBitmap::kARGB_8888_Config);
|
||||
}
|
||||
|
||||
void SkHitBox::updateHitPoint(SkBitmap* newBitmap, int layer) {
|
||||
int* prevBase = (int*)fPrev.getPixels();
|
||||
int* currBase = (int*)newBitmap->getPixels();
|
||||
int pixel = fY * fPrev.width() + fX;
|
||||
|
||||
if (pointIsSet() && !fPrev.empty()) {
|
||||
if (SkUnPreMultiply::PMColorToColor(prevBase[pixel]) !=
|
||||
SkUnPreMultiply::PMColorToColor(currBase[pixel])) {
|
||||
fLayer = layer;
|
||||
}
|
||||
}
|
||||
if (fPrev.empty()) {
|
||||
alloc(newBitmap->width(), newBitmap->height());
|
||||
fPrev.setConfig(SkBitmap::kARGB_8888_Config, newBitmap->width(), newBitmap->height());
|
||||
fPrev.allocPixels();
|
||||
}
|
||||
newBitmap->deepCopyTo(&fPrev, SkBitmap::kARGB_8888_Config);
|
||||
}
|
@ -1,81 +0,0 @@
|
||||
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SKHITBOX_H_
|
||||
#define SKHITBOX_H_
|
||||
|
||||
#include "SkBitmap.h"
|
||||
#include "SkUnPreMultiply.h"
|
||||
|
||||
/* NOTE(chudy): It's possible that this class can be entirely static similar to
|
||||
* SkObjectParser. We will have to pass in the fHitBox void * every call.
|
||||
*/
|
||||
class SkHitBox {
|
||||
public:
|
||||
SkHitBox();
|
||||
~SkHitBox();
|
||||
|
||||
/**
|
||||
Allocates enough space in memory for our hitbox pointer to contain
|
||||
a layer value for every pixel. Initializes every value to 0.
|
||||
*/
|
||||
void alloc(int width, int height);
|
||||
|
||||
/**
|
||||
Compares the new SkBitmap compared to the SkBitmap from the last
|
||||
call. Updates our hitbox with the draw command number if different.
|
||||
*/
|
||||
void updateHitBox(SkBitmap* newBitmap, int layer);
|
||||
|
||||
/**
|
||||
Compares point x,y in the new bitmap compared to the saved previous
|
||||
one. Updates hitpoint with the draw command number if different.
|
||||
*/
|
||||
void updateHitPoint(SkBitmap* newBitmap, int layer);
|
||||
|
||||
/**
|
||||
Sets the target hitpoint we are attempting to find the layer of.
|
||||
*/
|
||||
void setHitPoint(int x, int y) {
|
||||
fX = x;
|
||||
fY = y;
|
||||
fLayer = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns a pointer to the start of the hitbox.
|
||||
*/
|
||||
int* getHitBox() {
|
||||
return fHitBox;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the layer numbr corresponding to the point (fX, fY) in this class.
|
||||
*/
|
||||
int getPoint() {
|
||||
return fLayer;
|
||||
}
|
||||
|
||||
/**
|
||||
Checks to see if a mouse click has been passed in.
|
||||
*/
|
||||
bool pointIsSet() {
|
||||
return !(fX == -1 && fY == -1);
|
||||
}
|
||||
|
||||
private:
|
||||
SkBitmap fPrev;
|
||||
int* fHitBox;
|
||||
int fX;
|
||||
int fY;
|
||||
int fLayer;
|
||||
};
|
||||
|
||||
|
||||
#endif /* SKHITBOX_H_ */
|
@ -32,8 +32,6 @@
|
||||
'../debugger/SkObjectParser.cpp',
|
||||
'../debugger/QT/SkSettingsWidget.h',
|
||||
'../debugger/QT/SkSettingsWidget.cpp',
|
||||
'../debugger/SkHitBox.h',
|
||||
'../debugger/SkHitBox.cpp',
|
||||
'../debugger/QT/SkGLWidget.h',
|
||||
'../debugger/QT/SkGLWidget.cpp',
|
||||
'../debugger/QT/SkRasterWidget.h',
|
||||
|
Loading…
Reference in New Issue
Block a user