main.cpp
retracer.cpp
settingsdialog.cpp
+ vertexdatainterpreter.cpp
)
qt4_automoc(${qapitrace_SRCS})
return QString::number(variant.toFloat());
}
if (variant.userType() == QVariant::ByteArray) {
- float kb = variant.toByteArray().size()/1024.;
- return QObject::tr("[binary data, size = %1kb]").arg(kb);
+ if (variant.toByteArray().size() < 1024) {
+ int bytes = variant.toByteArray().size();
+ return QObject::tr("[binary data, size = %1 bytes]").arg(bytes);
+ } else {
+ float kb = variant.toByteArray().size()/1024.;
+ return QObject::tr("[binary data, size = %1 kb]").arg(kb);
+ }
}
if (variant.userType() < QVariant::UserType) {
for (int i = 0; i < argNames.count(); ++i) {
m_filterText += argNames[i];
m_filterText += QString::fromLatin1(" = ");
+
+ if (argValues[i].type() == QVariant::ByteArray) {
+ m_hasBinaryData = true;
+ m_binaryDataIndex = i;
+ }
m_filterText += apiVariantToString(argValues[i]);
if (i < argNames.count() - 1)
m_filterText += QString::fromLatin1(", ");
}
ApiTraceCall::ApiTraceCall()
- : ApiTraceEvent(ApiTraceEvent::Call)
+ : ApiTraceEvent(ApiTraceEvent::Call),
+ m_hasBinaryData(false),
+ m_binaryDataIndex(0)
{
}
{
m_state = state;
}
+
+bool ApiTraceCall::hasBinaryData() const
+{
+ return m_hasBinaryData;
+}
+
+int ApiTraceCall::binaryDataIndex() const
+{
+ return m_binaryDataIndex;
+}
QString filterText() const;
QStaticText staticText() const;
int numChildren() const;
+ bool hasBinaryData() const;
+ int binaryDataIndex() const;
private:
mutable QString m_richText;
mutable QString m_filterText;
mutable QStaticText m_staticText;
+ mutable bool m_hasBinaryData;
+ mutable int m_binaryDataIndex;
};
Q_DECLARE_METATYPE(ApiTraceCall*);
#include "apitracefilter.h"
#include "retracer.h"
#include "settingsdialog.h"
+#include "vertexdatainterpreter.h"
#include <qjson/parser.h>
connect(m_retracer, SIGNAL(error(const QString&)),
this, SLOT(replayError(const QString&)));
+ m_vdataInterpreter = new VertexDataInterpreter(this);
+ m_vdataInterpreter->setListWidget(m_ui.vertexDataListWidget);
+ m_vdataInterpreter->setStride(
+ m_ui.vertexStrideSB->value());
+ m_vdataInterpreter->setComponents(
+ m_ui.vertexComponentsSB->value());
+ m_vdataInterpreter->setTypeFromString(
+ m_ui.vertexTypeCB->currentText());
+
+ connect(m_ui.vertexInterpretButton, SIGNAL(clicked()),
+ m_vdataInterpreter, SLOT(interpretData()));
+ connect(m_ui.vertexTypeCB, SIGNAL(activated(const QString&)),
+ m_vdataInterpreter, SLOT(setTypeFromString(const QString&)));
+ connect(m_ui.vertexStrideSB, SIGNAL(valueChanged(int)),
+ m_vdataInterpreter, SLOT(setStride(int)));
+ connect(m_ui.vertexComponentsSB, SIGNAL(valueChanged(int)),
+ m_vdataInterpreter, SLOT(setComponents(int)));
+
m_model = new ApiTraceModel();
m_model->setApiTrace(m_trace);
m_proxyModel = new ApiTraceFilter();
m_progressBar->hide();
m_ui.detailsDock->hide();
+ m_ui.vertexDataDock->hide();
m_ui.stateDock->hide();
+ setDockOptions(dockOptions() | QMainWindow::ForceTabbedDocks);
+
+ tabifyDockWidget(m_ui.stateDock, m_ui.vertexDataDock);
connect(m_ui.actionOpen, SIGNAL(triggered()),
this, SLOT(openTrace()));
ApiTraceCall *call = static_cast<ApiTraceCall*>(event);
m_ui.detailsWebView->setHtml(call->toHtml());
m_ui.detailsDock->show();
+ if (call->hasBinaryData()) {
+ QByteArray data =
+ call->argValues[call->binaryDataIndex()].toByteArray();
+ m_vdataInterpreter->setData(data);
+
+ for (int i = 0; i < call->argNames.count(); ++i) {
+ QString name = call->argNames[i];
+ if (name == QLatin1String("stride")) {
+ int stride = call->argValues[i].toInt();
+ m_ui.vertexStrideSB->setValue(stride);
+ } else if (name == QLatin1String("size")) {
+ int components = call->argValues[i].toInt();
+ m_ui.vertexComponentsSB->setValue(components);
+ } else if (name == QLatin1String("type")) {
+ QString val = call->argValues[i].toString();
+ int textIndex = m_ui.vertexTypeCB->findText(val);
+ if (textIndex >= 0)
+ m_ui.vertexTypeCB->setCurrentIndex(textIndex);
+ }
+ }
+ }
+ m_ui.vertexDataDock->setVisible(call->hasBinaryData());
m_selectedEvent = call;
} else {
if (event && event->type() == ApiTraceEvent::Frame) {
} else
m_selectedEvent = 0;
m_ui.detailsDock->hide();
+ m_ui.vertexDataDock->hide();
}
if (m_selectedEvent && !m_selectedEvent->state().isEmpty()) {
fillStateForFrame();
class QModelIndex;
class QProgressBar;
class Retracer;
+class VertexDataInterpreter;
namespace QJson {
class Parser;
QJson::Parser *m_jsonParser;
Retracer *m_retracer;
+
+ VertexDataInterpreter *m_vdataInterpreter;
};
<rect>
<x>0</x>
<y>0</y>
- <width>760</width>
- <height>422</height>
+ <width>787</width>
+ <height>758</height>
</rect>
</property>
<property name="windowTitle">
<string>ApiTrace</string>
</property>
+ <property name="documentMode">
+ <bool>false</bool>
+ </property>
+ <property name="dockNestingEnabled">
+ <bool>false</bool>
+ </property>
+ <property name="dockOptions">
+ <set>QMainWindow::AnimatedDocks|QMainWindow::ForceTabbedDocks</set>
+ </property>
<widget class="QWidget" name="centralwidget">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<rect>
<x>0</x>
<y>0</y>
- <width>760</width>
+ <width>787</width>
<height>21</height>
</rect>
</property>
</widget>
</widget>
<widget class="QDockWidget" name="stateDock">
+ <property name="features">
+ <set>QDockWidget::AllDockWidgetFeatures</set>
+ </property>
<property name="windowTitle">
<string>Current State</string>
</property>
</layout>
</widget>
</widget>
+ <widget class="QDockWidget" name="vertexDataDock">
+ <property name="allowedAreas">
+ <set>Qt::AllDockWidgetAreas</set>
+ </property>
+ <property name="windowTitle">
+ <string>Vertex Data</string>
+ </property>
+ <attribute name="dockWidgetArea">
+ <number>2</number>
+ </attribute>
+ <widget class="QWidget" name="dockWidgetContents_3">
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <layout class="QFormLayout" name="formLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Type</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QComboBox" name="vertexTypeCB">
+ <property name="currentIndex">
+ <number>6</number>
+ </property>
+ <item>
+ <property name="text">
+ <string>GL_BYTE</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>GL_UNSIGNED_BYTE</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>GL_SHORT</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>GL_UNSIGNED_SHORT</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>GL_INT</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>GL_UNSIGNED_INT</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>GL_FLOAT</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Stride</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QSpinBox" name="vertexStrideSB">
+ <property name="maximum">
+ <number>1000</number>
+ </property>
+ <property name="value">
+ <number>8</number>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>Components</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QSpinBox" name="vertexComponentsSB">
+ <property name="maximum">
+ <number>256</number>
+ </property>
+ <property name="value">
+ <number>4</number>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" colspan="2">
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="vertexInterpretButton">
+ <property name="text">
+ <string>Interpret</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QListWidget" name="vertexDataListWidget"/>
+ </item>
+ </layout>
+ </widget>
+ </widget>
<action name="actionExit">
<property name="text">
<string>Exit</string>
<string>Options</string>
</property>
</action>
+ <zorder>stateDock</zorder>
+ <zorder>vertexDataDock</zorder>
</widget>
<customwidgets>
<customwidget>
--- /dev/null
+#include "vertexdatainterpreter.h"
+
+#include <QListWidget>
+#include <QStringList>
+
+#include <QDebug>
+
+#include <GL/gl.h>
+
+static int
+sizeForType(int glType)
+{
+ switch(glType) {
+ case GL_FLOAT:
+ return sizeof(GLfloat);
+ case GL_UNSIGNED_BYTE:
+ return sizeof(GLubyte);
+ case GL_BYTE:
+ return sizeof(GLbyte);
+ case GL_SHORT:
+ return sizeof(GLshort);
+ case GL_UNSIGNED_SHORT:
+ return sizeof(GLushort);
+ case GL_INT:
+ return sizeof(GLint);
+ case GL_UNSIGNED_INT:
+ return sizeof(GLuint);
+ default:
+ return sizeof(GLint);
+ }
+}
+
+template <typename T>
+static QStringList
+convertData(const QByteArray &dataArray,
+ int type,
+ int stride,
+ int numComponents)
+{
+ QStringList strings;
+
+ const char *data = dataArray.constData();
+ int typeSize = sizeForType(type);
+ int sizePerAttribute = typeSize;
+
+ if (stride)
+ sizePerAttribute = stride;
+
+ int numElements = dataArray.size() / sizePerAttribute;
+
+#if 0
+ qDebug() << "numElements = "<<numElements;
+ qDebug() << "sizePerAttribute = "<<sizePerAttribute;
+ qDebug() << "stride = "<<stride;
+ qDebug() << "numComponents = "<<numComponents;
+#endif
+
+ if (numElements * sizePerAttribute > dataArray.size()) {
+ qDebug()<<"Vertex data too large for the given binary data";
+ return strings;
+ }
+ if ((numElements % numComponents) != 0) {
+ qDebug()<<"Bad stride for the given vertex data";
+ return strings;
+ }
+
+ for (int i = 0; i < numElements; i += numComponents) {
+ QString vectorString = QString::fromLatin1("%1) [").arg(i / numComponents);
+ for (int j = 0; j < numComponents; ++j) {
+ int idx = i + j;
+ const T *elementPtr =
+ (const T*)(data + idx * sizePerAttribute);
+ T elem = *elementPtr;
+ vectorString += QString::number(elem);
+ if ((j + 1) < numComponents)
+ vectorString += QLatin1String(", ");
+ }
+ vectorString += "]";
+ strings += vectorString;
+ }
+
+ return strings;
+}
+
+
+VertexDataInterpreter::VertexDataInterpreter(QObject *parent)
+ : QObject(parent),
+ m_listWidget(0),
+ m_type(GL_FLOAT),
+ m_stride(16),
+ m_components(4)
+{
+}
+
+void VertexDataInterpreter::setData(const QByteArray &data)
+{
+ m_data = data;
+ if (m_listWidget)
+ m_listWidget->clear();
+}
+
+QByteArray VertexDataInterpreter::data() const
+{
+ return m_data;
+}
+
+void VertexDataInterpreter::setType(int type)
+{
+ m_type = type;
+}
+
+int VertexDataInterpreter::type() const
+{
+ return m_type;
+}
+
+void VertexDataInterpreter::setStride(int stride)
+{
+ m_stride = stride;
+}
+
+int VertexDataInterpreter::stride() const
+{
+ return m_stride;
+}
+
+void VertexDataInterpreter::setComponents(int num)
+{
+ m_components = num;
+}
+
+int VertexDataInterpreter::components() const
+{
+ return m_components;
+}
+
+void VertexDataInterpreter::setListWidget(QListWidget *listWidget)
+{
+ m_listWidget = listWidget;
+}
+
+void VertexDataInterpreter::interpretData()
+{
+ if (!m_listWidget)
+ return;
+
+ m_listWidget->clear();
+
+ if (m_data.isEmpty() || !m_components)
+ return;
+
+ QStringList lst;
+ switch(m_type) {
+ case GL_FLOAT:
+ lst = convertData<float>(m_data, m_type, m_stride, m_components);
+ break;
+ case GL_UNSIGNED_BYTE:
+ lst = convertData<quint8>(m_data, m_type, m_stride, m_components);
+ break;
+ case GL_BYTE:
+ lst = convertData<qint8>(m_data, m_type, m_stride, m_components);
+ break;
+ case GL_SHORT:
+ lst = convertData<qint16>(m_data, m_type, m_stride, m_components);
+ break;
+ case GL_UNSIGNED_SHORT:
+ lst = convertData<quint16>(m_data, m_type, m_stride, m_components);
+ break;
+ case GL_INT:
+ lst = convertData<unsigned int>(m_data, m_type, m_stride, m_components);
+ break;
+ case GL_UNSIGNED_INT:
+ lst = convertData<int>(m_data, m_type, m_stride, m_components);
+ break;
+ default:
+ qDebug()<<"unkown gltype = "<<m_type;
+ }
+ //qDebug()<<"list is "<<lst;
+ m_listWidget->addItems(lst);
+}
+
+
+void VertexDataInterpreter::setTypeFromString(const QString &str)
+{
+ if (str == QLatin1String("GL_FLOAT")) {
+ setType(GL_FLOAT);
+ } else if (str == QLatin1String("GL_INT")) {
+ setType(GL_INT);
+ } else if (str == QLatin1String("GL_UNSIGNED_INT")) {
+ setType(GL_UNSIGNED_INT);
+ } else if (str == QLatin1String("GL_SHORT")) {
+ setType(GL_SHORT);
+ } else if (str == QLatin1String("GL_UNSIGNED_SHORT")) {
+ setType(GL_UNSIGNED_SHORT);
+ } else if (str == QLatin1String("GL_BYTE")) {
+ setType(GL_BYTE);
+ } else if (str == QLatin1String("GL_UNSIGNED_BYTE")) {
+ setType(GL_UNSIGNED_BYTE);
+ } else {
+ qDebug()<<"unknown vertex data type";
+ }
+}
+
+#include "vertexdatainterpreter.moc"
--- /dev/null
+#ifndef VERTEXDATAINTERPRETER_H
+#define VERTEXDATAINTERPRETER_H
+
+#include <QObject>
+
+class QListWidget;
+
+class VertexDataInterpreter : public QObject
+{
+ Q_OBJECT
+public:
+ VertexDataInterpreter(QObject *parent=0);
+
+ QByteArray data() const;
+
+ int type() const;
+ int stride() const;
+ int components() const;
+
+ void setListWidget(QListWidget *listWidget);
+
+public slots:
+ void interpretData();
+
+ void setData(const QByteArray &data);
+ void setTypeFromString(const QString &str);
+ void setStride(int stride);
+ void setComponents(int num);
+ void setType(int type);
+
+private:
+ QListWidget *m_listWidget;
+ QByteArray m_data;
+ int m_type;
+ int m_stride;
+ int m_components;
+};
+
+#endif