History

Basic "meta type compiler" for streaming, streaming fixes and test.

Andrzej Kapolka committed 12 years ago

Commit effd00a1 parent f9043c39 files · +241 −6Browse files

Unified · Split

9 files
  1. assignment-client/src/metavoxels/MetavoxelServer.cpp +4 −1
  2. cmake/macros/AutoMTC.cmake +20 −0
  3. interface/src/MetavoxelSystem.cpp +3 −0
  4. libraries/metavoxels/CMakeLists.txt +3 −0
  5. libraries/metavoxels/src/Bitstream.cpp +6 −2
  6. libraries/metavoxels/src/Bitstream.h +11 −2
  7. libraries/metavoxels/src/MetavoxelMessages.h +3 −1
  8. tools/mtc/CMakeLists.txt +11 −0
  9. tools/mtc/src/main.cpp +180 −0
assignment-client/src/metavoxels/MetavoxelServer.cpp+4−1
@@ -8,6 +8,7 @@ · 7 unmodified lines
88
99 #include <PacketHeaders.h>
1010
11+#include <MetavoxelMessages.h>
1112 #include <MetavoxelUtil.h>
1213
1314 #include "MetavoxelServer.h"
@@ -88,7 +89,9 @@ void MetavoxelSession::sendData(const QByteArray& data) { · 74 unmodified lines
8889 }
8990
9091 void MetavoxelSession::readPacket(Bitstream& in) {
91− qDebug("got packet from client!\n");
92+ QVariant msg;
93+ in >> msg;
94+ qDebug() << msg.value<ClientPositionMessage>().test << "\n";
9295
9396 Bitstream& out = _sequencer.startPacket();
9497 _sequencer.endPacket();
cmake/macros/AutoMTC.cmake+20−0
@@ -0,0 +1,20 @@
1+macro(AUTO_MTC TARGET ROOT_DIR)
2+ if (NOT TARGET mtc)
3+ add_subdirectory(${ROOT_DIR}/tools/mtc ${ROOT_DIR}/tools/mtc)
4+ endif (NOT TARGET mtc)
5+
6+ file(GLOB INCLUDE_FILES src/*.h)
7+
8+ add_custom_command(OUTPUT ${TARGET}_automtc.cpp COMMAND mtc -o ${TARGET}_automtc.cpp ${INCLUDE_FILES} DEPENDS mtc)
9+
10+ find_package(Qt5Core REQUIRED)
11+
12+ add_library(${TARGET}_automtc STATIC ${TARGET}_automtc.cpp)
13+
14+ qt5_use_modules(${TARGET}_automtc Core)
15+
16+ target_link_libraries(${TARGET} ${TARGET}_automtc)
17+
18+endmacro()
19+
20+
interface/src/MetavoxelSystem.cpp+3−0
@@ -12,6 +12,7 @@ · 11 unmodified lines
1212
1313 #include <SharedUtil.h>
1414
15+#include <MetavoxelMessages.h>
1516 #include <MetavoxelUtil.h>
1617
1718 #include "Application.h"
@@ -193,6 +194,8 @@ MetavoxelClient::MetavoxelClient(const HifiSockAddr& address) : · 175 unmodified lines
193194
194195 void MetavoxelClient::simulate(float deltaTime) {
195196 Bitstream& out = _sequencer.startPacket();
197+ ClientPositionMessage msg = { 55 };
198+ out << QVariant::fromValue(msg);
196199 _sequencer.endPacket();
197200 }
198201
libraries/metavoxels/CMakeLists.txt+3−0
@@ -13,6 +13,9 @@ find_package(Qt5Widgets REQUIRED) · 12 unmodified lines
1313 include(${MACRO_DIR}/SetupHifiLibrary.cmake)
1414 setup_hifi_library(${TARGET_NAME})
1515
16+include(${MACRO_DIR}/AutoMTC.cmake)
17+auto_mtc(${TARGET_NAME} ${ROOT_DIR})
18+
1619 qt5_use_modules(${TARGET_NAME} Widgets Script)
1720
1821 include(${MACRO_DIR}/IncludeGLM.cmake)
libraries/metavoxels/src/Bitstream.cpp+6−2
@@ -40,6 +40,7 @@ IDStreamer& IDStreamer::operator<<(int value) { · 39 unmodified lines
4040 }
4141
4242 IDStreamer& IDStreamer::operator>>(int& value) {
43+ value = 0;
4344 _stream.read(&value, _bits);
4445 if (value == (1 << _bits) - 1) {
4546 _bits++;
@@ -93,7 +94,8 @@ Bitstream& Bitstream::read(void* data, int bits, int offset) { · 47 unmodified lines
9394 _underlying >> _byte;
9495 }
9596 int bitsToRead = qMin(BITS_IN_BYTE - _position, qMin(BITS_IN_BYTE - offset, bits));
96− *dest |= ((_byte >> _position) & ((1 << bitsToRead) - 1)) << offset;
97+ int mask = ((1 << bitsToRead) - 1) << offset;
98+ *dest = (*dest & ~mask) | (((_byte >> _position) << offset) & mask);
9799 _position = (_position + bitsToRead) & LAST_BIT_POSITION;
98100 if ((offset += bitsToRead) == BITS_IN_BYTE) {
99101 dest++;
@@ -166,7 +168,7 @@ Bitstream& Bitstream::operator<<(int value) { · 66 unmodified lines
166168 }
167169
168170 Bitstream& Bitstream::operator>>(int& value) {
169− qint32 sizedValue;
171+ qint32 sizedValue = 0;
170172 read(&sizedValue, 32);
171173 value = sizedValue;
172174 return *this;
@@ -180,6 +182,7 @@ Bitstream& Bitstream::operator<<(const QByteArray& string) { · 7 unmodified lines
180182 Bitstream& Bitstream::operator>>(QByteArray& string) {
181183 int size;
182184 *this >> size;
185+ string.resize(size);
183186 return read(string.data(), size * BITS_IN_BYTE);
184187 }
185188
@@ -191,6 +194,7 @@ Bitstream& Bitstream::operator<<(const QString& string) { · 5 unmodified lines
191194 Bitstream& Bitstream::operator>>(QString& string) {
192195 int size;
193196 *this >> size;
197+ string.resize(size);
194198 return read(string.data(), size * sizeof(QChar) * BITS_IN_BYTE);
195199 }
196200
libraries/metavoxels/src/Bitstream.h+11−2
@@ -13,6 +13,7 @@ · 12 unmodified lines
1313 #include <QMetaType>
1414 #include <QSharedPointer>
1515 #include <QVariant>
16+#include <QtDebug>
1617
1718 class QByteArray;
1819 class QDataStream;
@@ -278,10 +279,12 @@ public: · 259 unmodified lines
278279 #define REGISTER_SIMPLE_TYPE_STREAMER(x) static int x##Streamer = \
279280 Bitstream::registerTypeStreamer(QMetaType::type(#x), new SimpleTypeStreamer<x>());
280281
281−/// Declares the metatype and the streaming operators.
282+/// Declares the metatype and the streaming operators. The last line
283+/// ensures that the generated file will be included in the link phase.
282284 #define DECLARE_STREAMABLE_METATYPE(X) Q_DECLARE_METATYPE(X) \
283285 Bitstream& operator<<(Bitstream& out, const X& obj); \
284− Bitstream& operator>>(Bitstream& in, X& obj);
286+ Bitstream& operator>>(Bitstream& in, X& obj); \
287+ static const int* _TypePtr##X = &X::Type;
285288
286289 /// Registers a streamable type and its streamer.
287290 template<class T> int registerStreamableMetaType() {
@@ -290,4 +293,10 @@ template<class T> int registerStreamableMetaType() { · 2 unmodified lines
290293 return type;
291294 }
292295
296+/// Flags a class as streamable (use as you would Q_OBJECT).
297+#define STREAMABLE public: static const int Type; private:
298+
299+/// Flags a field or base class as streaming.
300+#define STREAM
301+
293302 #endif /* defined(__interface__Bitstream__) */
libraries/metavoxels/src/MetavoxelMessages.h+3−1
@@ -13,9 +13,11 @@ · 12 unmodified lines
1313
1414 /// A message containing the position of a client.
1515 class ClientPositionMessage {
16+ STREAMABLE
17+
1618 public:
1719
18− int test;
20+ STREAM int test;
1921 };
2022
2123 DECLARE_STREAMABLE_METATYPE(ClientPositionMessage)
tools/mtc/CMakeLists.txt+11−0
@@ -0,0 +1,11 @@
1+cmake_minimum_required(VERSION 2.8)
2+
3+set(TARGET_NAME mtc)
4+
5+set(ROOT_DIR ../..)
6+set(MACRO_DIR ${ROOT_DIR}/cmake/macros)
7+
8+include(${MACRO_DIR}/SetupHifiProject.cmake)
9+setup_hifi_project(${TARGET_NAME} TRUE)
10+
11+
tools/mtc/src/main.cpp+180−0
@@ -0,0 +1,180 @@
1+//
2+// main.cpp
3+// mtc
4+//
5+// Created by Andrzej Kapolka on 12/31/13.
6+// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
7+//
8+
9+#include <iostream>
10+
11+#include <QFile>
12+#include <QList>
13+#include <QRegExp>
14+#include <QString>
15+#include <QStringList>
16+#include <QTextStream>
17+#include <QtDebug>
18+
19+using namespace std;
20+
21+class Class {
22+public:
23+ QString name;
24+ QStringList bases;
25+};
26+
27+class Streamable {
28+public:
29+ Class clazz;
30+ QStringList fields;
31+};
32+
33+void processInput(QTextStream& in, QList<Streamable>* streamables) {
34+ Class clazz;
35+ Streamable currentStreamable;
36+
37+ QRegExp exp(
38+ "(/\\*.*\\*/)|" // multi-line comments
39+ "(//.*\n)|" // single-line comments
40+ "(\\s*#.*\n)|" // preprocessor definitions
41+ "(\\s*STREAMABLE\\s+)|" // STREAMABLE tag for classes
42+ "(\\s*STREAM\\s+.*;)|" // STREAM tag for fields
43+ "(\\s*class\\s+[^;]+\\{)" // class definition
44+ );
45+ exp.setMinimal(true);
46+
47+ QRegExp classExp("class (\\w+) ?:?([^:]*)\\{");
48+
49+ // read in the entire input and look for matches with our expression
50+ QString all = in.readAll();
51+ for (int off = 0; (off = exp.indexIn(all, off)) != -1; off += exp.matchedLength()) {
52+ QString match = exp.cap().simplified();
53+ if (match.startsWith("/*") || match.startsWith("//") || match.startsWith('#')) {
54+ continue; // comment, preprocessor definition
55+ }
56+ if (match.startsWith("STREAMABLE")) {
57+ if (clazz.name.isEmpty()) {
58+ cerr << "Found STREAMABLE marker before class definition." << endl;
59+ continue;
60+ }
61+ if (!currentStreamable.clazz.name.isEmpty()) {
62+ streamables->append(currentStreamable);
63+ }
64+ currentStreamable.clazz = clazz;
65+ currentStreamable.fields.clear();
66+
67+ } else if (match.startsWith("STREAM")) {
68+ match.chop(1); // get rid of the semicolon
69+ match = match.trimmed(); // and any space before it
70+ currentStreamable.fields.append(match.mid(match.lastIndexOf(' ') + 1));
71+
72+ } else { // match.startsWith("class")
73+ classExp.exactMatch(match);
74+ clazz.name = classExp.cap(1);
75+ clazz.bases.clear();
76+ foreach (const QString& bstr, classExp.cap(2).split(',')) {
77+ QString base = bstr.trimmed();
78+ if (!base.isEmpty() && base.startsWith("STREAM")) {
79+ clazz.bases.append(base.mid(base.lastIndexOf(' ') + 1));
80+ }
81+ }
82+ }
83+ }
84+ if (!currentStreamable.clazz.name.isEmpty()) {
85+ streamables->append(currentStreamable);
86+ }
87+}
88+
89+void generateOutput (QTextStream& out, const QList<Streamable>& streamables) {
90+ foreach (const Streamable& str, streamables) {
91+ const QString& name = str.clazz.name;
92+
93+ out << "Bitstream& operator<< (Bitstream& out, const " << name << "& obj) {\n";
94+ foreach (const QString& base, str.clazz.bases) {
95+ out << " out << static_cast<const " << base << "&>(obj);\n";
96+ }
97+ foreach (const QString& field, str.fields) {
98+ out << " out << obj." << field << ";\n";
99+ }
100+ out << " return out;\n";
101+ out << "}\n";
102+
103+ out << "Bitstream& operator>> (Bitstream& in, " << name << "& obj) {\n";
104+ foreach (const QString& base, str.clazz.bases) {
105+ out << " in >> static_cast<" << base << "&>(obj);\n";
106+ }
107+ foreach (const QString& field, str.fields) {
108+ out << " in >> obj." << field << ";\n";
109+ }
110+ out << " return in;\n";
111+ out << "}\n";
112+
113+ out << "const int " << name << "::Type = registerStreamableMetaType<" << name << ">();\n\n";
114+ }
115+}
116+
117+int main (int argc, char** argv) {
118+ // process the command line arguments
119+ QStringList inputs;
120+ QString output;
121+ for (int ii = 1; ii < argc; ii++) {
122+ QString arg(argv[ii]);
123+ if (!arg.startsWith('-')) {
124+ inputs.append(arg);
125+ continue;
126+ }
127+ QStringRef name = arg.midRef(1);
128+ if (name == "o") {
129+ if (++ii == argc) {
130+ cerr << "Missing file name argument for -o" << endl;
131+ return 1;
132+ }
133+ output = argv[ii];
134+
135+ } else {
136+ cerr << "Unknown option " << arg.toStdString() << endl;
137+ return 1;
138+ }
139+ }
140+ if (inputs.isEmpty()) {
141+ cerr << "Usage: mtc [OPTION]... input files" << endl;
142+ cerr << "Where options include:" << endl;
143+ cerr << " -o filename: Send output to filename rather than standard output." << endl;
144+ return 0;
145+ }
146+
147+ QList<Streamable> streamables;
148+ foreach (const QString& input, inputs) {
149+ QFile ifile(input);
150+ if (!ifile.open(QIODevice::ReadOnly | QIODevice::Text)) {
151+ cerr << ("Couldn't open " + input + ": " + ifile.errorString()).toStdString() << endl;
152+ continue;
153+ }
154+ QTextStream istream(&ifile);
155+ int oldSize = streamables.size();
156+ processInput(istream, &streamables);
157+ if (streamables.size() == oldSize) {
158+ // no streamables; remove from list
159+ inputs.removeOne(input);
160+ }
161+ }
162+
163+ QFile ofile(output);
164+ if (output.isNull()) {
165+ ofile.open(stdout, QIODevice::WriteOnly | QIODevice::Text);
166+
167+ } else if (!ofile.open(QIODevice::WriteOnly | QIODevice::Text)) {
168+ cerr << ("Couldn't open " + output + ": " + ofile.errorString()).toStdString() << endl;
169+ return 1;
170+ }
171+
172+ QTextStream ostream(&ofile);
173+ ostream << "// generated by mtc\n";
174+ foreach (const QString& input, inputs) {
175+ ostream << "#include \"" << input << "\"\n";
176+ }
177+ generateOutput(ostream, streamables);
178+
179+ return 0;
180+}