SkHitBox added.

SkHitBox is a class that determines which draw command is associated with the pixel located at x,y. By calculating a single point instead of the entire bitmap at once there is no visible performance slowdown.

Review URL: https://codereview.appspot.com/6350098

git-svn-id: http://skia.googlecode.com/svn/trunk@4565 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
chudy@google.com 2012-07-12 14:31:25 +00:00
parent e565de4fad
commit e606d6e210
12 changed files with 234 additions and 20 deletions

View File

@ -11,7 +11,6 @@
#include "SkStream.h" #include "SkStream.h"
#include "SkCanvasWidget.h" #include "SkCanvasWidget.h"
#include "SkColor.h" #include "SkColor.h"
#include <iostream>
SkCanvasWidget::SkCanvasWidget(QWidget *parent) : SkCanvasWidget::SkCanvasWidget(QWidget *parent) :
QWidget(parent) { QWidget(parent) {
@ -56,7 +55,7 @@ void SkCanvasWidget::resizeEvent(QResizeEvent* event) {
fDevice = new SkDevice(fBitmap); fDevice = new SkDevice(fBitmap);
fCanvas = new SkCanvas(fDevice); fCanvas = new SkCanvas(fDevice);
fDebugCanvas->setBounds(event->size().width(), event->size().height()); fDebugCanvas->setBounds(event->size().width(), event->size().height());
fDebugCanvas->drawTo(fCanvas, fIndex); fDebugCanvas->drawTo(fCanvas, fIndex+1, &fBitmap);
this->update(); this->update();
} }
@ -72,7 +71,7 @@ void SkCanvasWidget::drawTo(int fIndex) {
} }
emit commandChanged(fIndex); emit commandChanged(fIndex);
fDebugCanvas->drawTo(fCanvas, fIndex+1); fDebugCanvas->drawTo(fCanvas, fIndex+1, &fBitmap);
this->update(); this->update();
this->fIndex = fIndex; this->fIndex = fIndex;
} }
@ -128,6 +127,11 @@ void SkCanvasWidget::mouseMoveEvent(QMouseEvent* event) {
void SkCanvasWidget::mousePressEvent(QMouseEvent* event) { void SkCanvasWidget::mousePressEvent(QMouseEvent* event) {
fPreviousPoint.set(event->globalX(), event->globalY()); fPreviousPoint.set(event->globalX(), event->globalY());
fDebugCanvas->getBoxClass()->setHitPoint(event->x(), event->y());
fDebugCanvas->isCalculatingHits(true);
drawTo(fIndex);
emit hitChanged(fDebugCanvas->getHitBoxPoint());
fDebugCanvas->isCalculatingHits(false);
} }
void SkCanvasWidget::mouseDoubleClickEvent(QMouseEvent* event) { void SkCanvasWidget::mouseDoubleClickEvent(QMouseEvent* event) {

View File

@ -132,6 +132,7 @@ public:
signals: signals:
void scaleFactorChanged(float newScaleFactor); void scaleFactorChanged(float newScaleFactor);
void commandChanged(int newCommand); void commandChanged(int newCommand);
void hitChanged(int hit);
protected: protected:
/** /**

View File

@ -71,10 +71,12 @@ SkDebuggerGUI::SkDebuggerGUI(QWidget *parent) :
SLOT(actionCommandFilter())); SLOT(actionCommandFilter()));
connect(&fCanvasWidget, SIGNAL(scaleFactorChanged(float)), this, connect(&fCanvasWidget, SIGNAL(scaleFactorChanged(float)), this,
SLOT(actionScale(float))); SLOT(actionScale(float)));
connect(fSettingsWidget.getCommandCheckBox(), SIGNAL(stateChanged(int)), connect(fSettingsWidget.getCommandCheckBox(), SIGNAL(toggled(bool)),
this, SLOT(pauseDrawing(bool))); this, SLOT(pauseDrawing(bool)));
connect(&fCanvasWidget, SIGNAL(commandChanged(int)), &fSettingsWidget, connect(&fCanvasWidget, SIGNAL(commandChanged(int)), &fSettingsWidget,
SLOT(updateCommand(int))); SLOT(updateCommand(int)));
connect(&fCanvasWidget, SIGNAL(hitChanged(int)), &fSettingsWidget,
SLOT(updateHit(int)));
} }
SkDebuggerGUI::~SkDebuggerGUI() { SkDebuggerGUI::~SkDebuggerGUI() {
@ -478,6 +480,7 @@ void SkDebuggerGUI::loadPicture(QString fileName) {
fSettingsWidget.getVisibilityButton()->isChecked()); fSettingsWidget.getVisibilityButton()->isChecked());
setupListWidget(cv); setupListWidget(cv);
setupComboBox(cv); setupComboBox(cv);
fSettingsWidget.setDisabled(false);
} }
void SkDebuggerGUI::setupListWidget(std::vector<std::string>* cv) { void SkDebuggerGUI::setupListWidget(std::vector<std::string>* cv) {

View File

@ -19,6 +19,7 @@ SkSettingsWidget::SkSettingsWidget(QWidget *parent) : QWidget(parent)
, fVisibleOff(&fVisibleFrame) , fVisibleOff(&fVisibleFrame)
, fCommandLayout(&fCommandFrame) , fCommandLayout(&fCommandFrame)
, fCurrentCommandBox(&fCommandFrame) , fCurrentCommandBox(&fCommandFrame)
, fCommandHitBox(&fCommandFrame)
, fCommandCheckBox(&fCommandFrame) , fCommandCheckBox(&fCommandFrame)
, fZoomBox(&fZoomFrame) , fZoomBox(&fZoomFrame)
, fZoomLayout(&fZoomFrame) , fZoomLayout(&fZoomFrame)
@ -65,10 +66,24 @@ SkSettingsWidget::SkSettingsWidget(QWidget *parent) : QWidget(parent)
fCurrentCommandLayout.addWidget(&fCurrentCommandLabel); fCurrentCommandLayout.addWidget(&fCurrentCommandLabel);
fCurrentCommandLayout.addWidget(&fCurrentCommandBox); fCurrentCommandLayout.addWidget(&fCurrentCommandBox);
fCommandHitLabel.setText("Command HitBox: ");
fCommandHitLabel.setMinimumWidth(178);
fCommandHitLabel.setMaximumWidth(178);
fCommandHitBox.setText("0");
fCommandHitBox.setMinimumSize(QSize(50,25));
fCommandHitBox.setMaximumSize(QSize(50,25));
fCommandHitBox.setAlignment(Qt::AlignRight);
fCommandHitLayout.setSpacing(0);
fCommandHitLayout.setContentsMargins(0,0,0,0);
fCommandHitLayout.setAlignment(Qt::AlignLeft);
fCommandHitLayout.addWidget(&fCommandHitLabel);
fCommandHitLayout.addWidget(&fCommandHitBox);
fCommandCheckBox.setText("Pause"); fCommandCheckBox.setText("Pause");
fCommandLayout.setSpacing(6); fCommandLayout.setSpacing(6);
fCommandLayout.setContentsMargins(11,11,11,11); fCommandLayout.setContentsMargins(11,11,11,11);
fCommandLayout.addLayout(&fCurrentCommandLayout); fCommandLayout.addLayout(&fCurrentCommandLayout);
fCommandLayout.addLayout(&fCommandHitLayout);
fCommandLayout.addWidget(&fCommandCheckBox); fCommandLayout.addWidget(&fCommandCheckBox);
// Zoom Info // Zoom Info
@ -93,7 +108,7 @@ SkSettingsWidget::SkSettingsWidget(QWidget *parent) : QWidget(parent)
fVerticalLayout.addWidget(&fCommandFrame); fVerticalLayout.addWidget(&fCommandFrame);
fVerticalLayout.addWidget(&fZoomFrame); fVerticalLayout.addWidget(&fZoomFrame);
//this->setDisabled(true); this->setDisabled(true);
} }
SkSettingsWidget::~SkSettingsWidget() {} SkSettingsWidget::~SkSettingsWidget() {}
@ -103,6 +118,10 @@ void SkSettingsWidget::updateCommand(int newCommand) {
fCurrentCommandBox.setText(QString::number(newCommand)); fCurrentCommandBox.setText(QString::number(newCommand));
} }
void SkSettingsWidget::updateHit(int newHit) {
fCommandHitBox.setText(QString::number(newHit));
}
QCheckBox* SkSettingsWidget::getCommandCheckBox() { QCheckBox* SkSettingsWidget::getCommandCheckBox() {
return &fCommandCheckBox; return &fCommandCheckBox;
} }

View File

@ -43,6 +43,7 @@ public:
private slots: private slots:
void updateCommand(int newCommand); void updateCommand(int newCommand);
void updateHit(int newHit);
signals: signals:
void scrollingPreferences(bool isStickyActivate); void scrollingPreferences(bool isStickyActivate);
@ -64,10 +65,14 @@ private:
QFrame fCommandFrame; QFrame fCommandFrame;
QVBoxLayout fCommandLayout; QVBoxLayout fCommandLayout;
QLineEdit fCurrentCommandBox;
QLabel fCurrentCommandLabel; QLabel fCurrentCommandLabel;
QLineEdit fCurrentCommandBox;
QHBoxLayout fCurrentCommandLayout; QHBoxLayout fCurrentCommandLayout;
QLabel fCommandHitLabel;
QLineEdit fCommandHitBox;
QHBoxLayout fCommandHitLayout;
QCheckBox fCommandCheckBox; QCheckBox fCommandCheckBox;
QLabel fZoomSetting; QLabel fZoomSetting;

View File

@ -1,7 +1,7 @@
/**************************************************************************** /****************************************************************************
** Meta object code from reading C++ file 'SkCanvasWidget.h' ** Meta object code from reading C++ file 'SkCanvasWidget.h'
** **
** Created: Mon Jul 9 13:45:07 2012 ** Created: Wed Jul 11 15:15:07 2012
** by: The Qt Meta Object Compiler version 62 (Qt 4.6.2) ** by: The Qt Meta Object Compiler version 62 (Qt 4.6.2)
** **
** WARNING! All changes made in this file will be lost! ** WARNING! All changes made in this file will be lost!
@ -23,16 +23,17 @@ static const uint qt_meta_data_SkCanvasWidget[] = {
4, // revision 4, // revision
0, // classname 0, // classname
0, 0, // classinfo 0, 0, // classinfo
2, 14, // methods 3, 14, // methods
0, 0, // properties 0, 0, // properties
0, 0, // enums/sets 0, 0, // enums/sets
0, 0, // constructors 0, 0, // constructors
0, // flags 0, // flags
2, // signalCount 3, // signalCount
// signals: signature, parameters, type, tag, flags // signals: signature, parameters, type, tag, flags
31, 16, 15, 15, 0x05, 31, 16, 15, 15, 0x05,
68, 57, 15, 15, 0x05, 68, 57, 15, 15, 0x05,
92, 88, 15, 15, 0x05,
0 // eod 0 // eod
}; };
@ -40,7 +41,7 @@ static const uint qt_meta_data_SkCanvasWidget[] = {
static const char qt_meta_stringdata_SkCanvasWidget[] = { static const char qt_meta_stringdata_SkCanvasWidget[] = {
"SkCanvasWidget\0\0newScaleFactor\0" "SkCanvasWidget\0\0newScaleFactor\0"
"scaleFactorChanged(float)\0newCommand\0" "scaleFactorChanged(float)\0newCommand\0"
"commandChanged(int)\0" "commandChanged(int)\0hit\0hitChanged(int)\0"
}; };
const QMetaObject SkCanvasWidget::staticMetaObject = { const QMetaObject SkCanvasWidget::staticMetaObject = {
@ -74,9 +75,10 @@ int SkCanvasWidget::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
switch (_id) { switch (_id) {
case 0: scaleFactorChanged((*reinterpret_cast< float(*)>(_a[1]))); break; case 0: scaleFactorChanged((*reinterpret_cast< float(*)>(_a[1]))); break;
case 1: commandChanged((*reinterpret_cast< int(*)>(_a[1]))); break; case 1: commandChanged((*reinterpret_cast< int(*)>(_a[1]))); break;
case 2: hitChanged((*reinterpret_cast< int(*)>(_a[1]))); break;
default: ; default: ;
} }
_id -= 2; _id -= 3;
} }
return _id; return _id;
} }
@ -94,4 +96,11 @@ void SkCanvasWidget::commandChanged(int _t1)
void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) }; void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
QMetaObject::activate(this, &staticMetaObject, 1, _a); QMetaObject::activate(this, &staticMetaObject, 1, _a);
} }
// SIGNAL 2
void SkCanvasWidget::hitChanged(int _t1)
{
void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
QMetaObject::activate(this, &staticMetaObject, 2, _a);
}
QT_END_MOC_NAMESPACE QT_END_MOC_NAMESPACE

View File

@ -1,7 +1,7 @@
/**************************************************************************** /****************************************************************************
** Meta object code from reading C++ file 'SkSettingsWidget.h' ** Meta object code from reading C++ file 'SkSettingsWidget.h'
** **
** Created: Mon Jul 9 13:45:07 2012 ** Created: Wed Jul 11 15:20:23 2012
** by: The Qt Meta Object Compiler version 62 (Qt 4.6.2) ** by: The Qt Meta Object Compiler version 62 (Qt 4.6.2)
** **
** WARNING! All changes made in this file will be lost! ** WARNING! All changes made in this file will be lost!
@ -23,7 +23,7 @@ static const uint qt_meta_data_SkSettingsWidget[] = {
4, // revision 4, // revision
0, // classname 0, // classname
0, 0, // classinfo 0, 0, // classinfo
4, 14, // methods 5, 14, // methods
0, 0, // properties 0, 0, // properties
0, 0, // enums/sets 0, 0, // enums/sets
0, 0, // constructors 0, 0, // constructors
@ -37,6 +37,7 @@ static const uint qt_meta_data_SkSettingsWidget[] = {
// slots: signature, parameters, type, tag, flags // slots: signature, parameters, type, tag, flags
138, 127, 17, 17, 0x08, 138, 127, 17, 17, 0x08,
164, 157, 17, 17, 0x08,
0 // eod 0 // eod
}; };
@ -46,7 +47,7 @@ static const char qt_meta_stringdata_SkSettingsWidget[] = {
"scrollingPreferences(bool)\0isSingleCommand\0" "scrollingPreferences(bool)\0isSingleCommand\0"
"showStyle(bool)\0isEnabled\0" "showStyle(bool)\0isEnabled\0"
"visibilityFilter(bool)\0newCommand\0" "visibilityFilter(bool)\0newCommand\0"
"updateCommand(int)\0" "updateCommand(int)\0newHit\0updateHit(int)\0"
}; };
const QMetaObject SkSettingsWidget::staticMetaObject = { const QMetaObject SkSettingsWidget::staticMetaObject = {
@ -82,9 +83,10 @@ int SkSettingsWidget::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
case 1: showStyle((*reinterpret_cast< bool(*)>(_a[1]))); break; case 1: showStyle((*reinterpret_cast< bool(*)>(_a[1]))); break;
case 2: visibilityFilter((*reinterpret_cast< bool(*)>(_a[1]))); break; case 2: visibilityFilter((*reinterpret_cast< bool(*)>(_a[1]))); break;
case 3: updateCommand((*reinterpret_cast< int(*)>(_a[1]))); break; case 3: updateCommand((*reinterpret_cast< int(*)>(_a[1]))); break;
case 4: updateHit((*reinterpret_cast< int(*)>(_a[1]))); break;
default: ; default: ;
} }
_id -= 4; _id -= 5;
} }
return _id; return _id;
} }

View File

@ -34,12 +34,11 @@ void SkDebugCanvas::draw(SkCanvas* canvas) {
} }
} }
void SkDebugCanvas::drawTo(SkCanvas* canvas, int index, SkBitmap* bitmap) {
void SkDebugCanvas::drawTo(SkCanvas* canvas, int index) {
int counter = 0; int counter = 0;
if(!commandVector.empty()) { if(!commandVector.empty()) {
for(it = commandVector.begin(); it != commandVector.end(); ++it) { for(it = commandVector.begin(); it != commandVector.end(); ++it) {
if (counter != (index-1)) { if (counter != (index-1)) {
if ((*it)->getVisibility()) { if ((*it)->getVisibility()) {
(*it)->execute(canvas); (*it)->execute(canvas);
} }
@ -56,11 +55,13 @@ void SkDebugCanvas::drawTo(SkCanvas* canvas, int index) {
canvas->drawRectCoords(SkIntToScalar(0),SkIntToScalar(0),SkIntToScalar(fWidth),SkIntToScalar(fHeight), *p); canvas->drawRectCoords(SkIntToScalar(0),SkIntToScalar(0),SkIntToScalar(fWidth),SkIntToScalar(fHeight), *p);
canvas->restore(); canvas->restore();
} }
if ((*it)->getVisibility()) { if ((*it)->getVisibility()) {
(*it)->execute(canvas); (*it)->execute(canvas);
} }
} }
if (fCalculateHits == true) {
fHitBox.updateHitPoint(bitmap, counter);
}
/* TODO(chudy): Implement a bitmap wide function that will take /* TODO(chudy): Implement a bitmap wide function that will take
* ~50 out of each R,G,B. This will make everything but the last * ~50 out of each R,G,B. This will make everything but the last

View File

@ -14,6 +14,7 @@
#include "SkCanvas.h" #include "SkCanvas.h"
#include "SkDrawCommand.h" #include "SkDrawCommand.h"
#include "SkPicture.h" #include "SkPicture.h"
#include "SkHitBox.h"
#include <vector> #include <vector>
class SkDebugCanvas : public SkCanvas { class SkDebugCanvas : public SkCanvas {
@ -45,7 +46,7 @@ public:
@param canvas The canvas being drawn to @param canvas The canvas being drawn to
@param index The index of the final command being executed @param index The index of the final command being executed
*/ */
void drawTo(SkCanvas* canvas, int index); void drawTo(SkCanvas* canvas, int index, SkBitmap* bitmap);
/** /**
Returns the draw command at the given index. Returns the draw command at the given index.
@ -69,6 +70,21 @@ public:
*/ */
std::vector<std::string>* getDrawCommandsAsStrings(); 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. Returns length of draw command vector.
*/ */
@ -76,6 +92,9 @@ public:
return commandVector.size(); return commandVector.size();
} }
void isCalculatingHits(bool isEnabled) {
fCalculateHits = isEnabled;
}
/** /**
Toggles the execution of the draw command at index i. Toggles the execution of the draw command at index i.
*/ */
@ -176,6 +195,8 @@ private:
int fHeight; int fHeight;
int fWidth; int fWidth;
SkBitmap fBm; SkBitmap fBm;
SkHitBox fHitBox;
bool fCalculateHits;
/** /**
Adds the command to the classes vector of commands. Adds the command to the classes vector of commands.

66
debugger/SkHitBox.cpp Normal file
View File

@ -0,0 +1,66 @@
/*
* 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);
}

81
debugger/SkHitBox.h Normal file
View File

@ -0,0 +1,81 @@
/*
* 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_ */

View File

@ -30,6 +30,8 @@
'../debugger/SkObjectParser.cpp', '../debugger/SkObjectParser.cpp',
'../debugger/QT/SkSettingsWidget.h', '../debugger/QT/SkSettingsWidget.h',
'../debugger/QT/SkSettingsWidget.cpp', '../debugger/QT/SkSettingsWidget.cpp',
'../debugger/SkHitBox.h',
'../debugger/SkHitBox.cpp',
# To update this file edit SkIcons.qrc and rerun rcc to generate cpp # To update this file edit SkIcons.qrc and rerun rcc to generate cpp
'../debugger/QT/qrc_SkIcons.cpp', '../debugger/QT/qrc_SkIcons.cpp',