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
8 8
9#include <PacketHeaders.h>9#include <PacketHeaders.h>
10 10
11#include <MetavoxelMessages.h>
11#include <MetavoxelUtil.h>12#include <MetavoxelUtil.h>
12 13
13#include "MetavoxelServer.h"14#include "MetavoxelServer.h"
@@ -88,7 +89,9 @@ void MetavoxelSession::sendData(const QByteArray& data) { · 74 unmodified lines
88}89}
89 90
90void MetavoxelSession::readPacket(Bitstream& in) {91void MetavoxelSession::readPacket(Bitstream& in) {
91 qDebug("got packet from client!\n");92 QVariant msg;
93 in >> msg;
94 qDebug() << msg.value<ClientPositionMessage>().test << "\n";
92 95
93 Bitstream& out = _sequencer.startPacket();96 Bitstream& out = _sequencer.startPacket();
94 _sequencer.endPacket();97 _sequencer.endPacket();
cmake/macros/AutoMTC.cmake+20−0
@@ -0,0 +1,20 @@
1macro(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
18endmacro()
19
20
interface/src/MetavoxelSystem.cpp+3−0
@@ -12,6 +12,7 @@ · 11 unmodified lines
12 12
13#include <SharedUtil.h>13#include <SharedUtil.h>
14 14
15#include <MetavoxelMessages.h>
15#include <MetavoxelUtil.h>16#include <MetavoxelUtil.h>
16 17
17#include "Application.h"18#include "Application.h"
@@ -193,6 +194,8 @@ MetavoxelClient::MetavoxelClient(const HifiSockAddr& address) : · 175 unmodified lines
193 194
194void MetavoxelClient::simulate(float deltaTime) {195void MetavoxelClient::simulate(float deltaTime) {
195 Bitstream& out = _sequencer.startPacket();196 Bitstream& out = _sequencer.startPacket();
197 ClientPositionMessage msg = { 55 };
198 out << QVariant::fromValue(msg);
196 _sequencer.endPacket();199 _sequencer.endPacket();
197}200}
198 201
libraries/metavoxels/CMakeLists.txt+3−0
@@ -13,6 +13,9 @@ find_package(Qt5Widgets REQUIRED) · 12 unmodified lines
13include(${MACRO_DIR}/SetupHifiLibrary.cmake)13include(${MACRO_DIR}/SetupHifiLibrary.cmake)
14setup_hifi_library(${TARGET_NAME})14setup_hifi_library(${TARGET_NAME})
15 15
16include(${MACRO_DIR}/AutoMTC.cmake)
17auto_mtc(${TARGET_NAME} ${ROOT_DIR})
18
16qt5_use_modules(${TARGET_NAME} Widgets Script)19qt5_use_modules(${TARGET_NAME} Widgets Script)
17 20
18include(${MACRO_DIR}/IncludeGLM.cmake)21include(${MACRO_DIR}/IncludeGLM.cmake)
libraries/metavoxels/src/Bitstream.cpp+6−2
@@ -40,6 +40,7 @@ IDStreamer& IDStreamer::operator<<(int value) { · 39 unmodified lines
40}40}
41 41
42IDStreamer& IDStreamer::operator>>(int& value) {42IDStreamer& IDStreamer::operator>>(int& value) {
43 value = 0;
43 _stream.read(&value, _bits);44 _stream.read(&value, _bits);
44 if (value == (1 << _bits) - 1) {45 if (value == (1 << _bits) - 1) {
45 _bits++;46 _bits++;
@@ -93,7 +94,8 @@ Bitstream& Bitstream::read(void* data, int bits, int offset) { · 47 unmodified lines
93 _underlying >> _byte;94 _underlying >> _byte;
94 }95 }
95 int bitsToRead = qMin(BITS_IN_BYTE - _position, qMin(BITS_IN_BYTE - offset, bits));96 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);
97 _position = (_position + bitsToRead) & LAST_BIT_POSITION;99 _position = (_position + bitsToRead) & LAST_BIT_POSITION;
98 if ((offset += bitsToRead) == BITS_IN_BYTE) {100 if ((offset += bitsToRead) == BITS_IN_BYTE) {
99 dest++;101 dest++;
@@ -166,7 +168,7 @@ Bitstream& Bitstream::operator<<(int value) { · 66 unmodified lines
166}168}
167 169
168Bitstream& Bitstream::operator>>(int& value) {170Bitstream& Bitstream::operator>>(int& value) {
169 qint32 sizedValue;171 qint32 sizedValue = 0;
170 read(&sizedValue, 32);172 read(&sizedValue, 32);
171 value = sizedValue;173 value = sizedValue;
172 return *this;174 return *this;
@@ -180,6 +182,7 @@ Bitstream& Bitstream::operator<<(const QByteArray& string) { · 7 unmodified lines
180Bitstream& Bitstream::operator>>(QByteArray& string) {182Bitstream& Bitstream::operator>>(QByteArray& string) {
181 int size;183 int size;
182 *this >> size;184 *this >> size;
185 string.resize(size);
183 return read(string.data(), size * BITS_IN_BYTE);186 return read(string.data(), size * BITS_IN_BYTE);
184}187}
185 188
@@ -191,6 +194,7 @@ Bitstream& Bitstream::operator<<(const QString& string) { · 5 unmodified lines
191Bitstream& Bitstream::operator>>(QString& string) {194Bitstream& Bitstream::operator>>(QString& string) {
192 int size;195 int size;
193 *this >> size;196 *this >> size;
197 string.resize(size);
194 return read(string.data(), size * sizeof(QChar) * BITS_IN_BYTE);198 return read(string.data(), size * sizeof(QChar) * BITS_IN_BYTE);
195}199}
196 200
libraries/metavoxels/src/Bitstream.h+11−2
@@ -13,6 +13,7 @@ · 12 unmodified lines
13#include <QMetaType>13#include <QMetaType>
14#include <QSharedPointer>14#include <QSharedPointer>
15#include <QVariant>15#include <QVariant>
16#include <QtDebug>
16 17
17class QByteArray;18class QByteArray;
18class QDataStream;19class QDataStream;
@@ -278,10 +279,12 @@ public: · 259 unmodified lines
278#define REGISTER_SIMPLE_TYPE_STREAMER(x) static int x##Streamer = \279#define REGISTER_SIMPLE_TYPE_STREAMER(x) static int x##Streamer = \
279 Bitstream::registerTypeStreamer(QMetaType::type(#x), new SimpleTypeStreamer<x>());280 Bitstream::registerTypeStreamer(QMetaType::type(#x), new SimpleTypeStreamer<x>());
280 281
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.
282#define DECLARE_STREAMABLE_METATYPE(X) Q_DECLARE_METATYPE(X) \284#define DECLARE_STREAMABLE_METATYPE(X) Q_DECLARE_METATYPE(X) \
283 Bitstream& operator<<(Bitstream& out, const X& obj); \285 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;
285 288
286/// Registers a streamable type and its streamer.289/// Registers a streamable type and its streamer.
287template<class T> int registerStreamableMetaType() {290template<class T> int registerStreamableMetaType() {
@@ -290,4 +293,10 @@ template<class T> int registerStreamableMetaType() { · 2 unmodified lines
290 return type;293 return type;
291}294}
292 295
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
293#endif /* defined(__interface__Bitstream__) */302#endif /* defined(__interface__Bitstream__) */
libraries/metavoxels/src/MetavoxelMessages.h+3−1
@@ -13,9 +13,11 @@ · 12 unmodified lines
13 13
14/// A message containing the position of a client.14/// A message containing the position of a client.
15class ClientPositionMessage {15class ClientPositionMessage {
16 STREAMABLE
17
16public:18public:
17 19
18 int test;20 STREAM int test;
19};21};
20 22
21DECLARE_STREAMABLE_METATYPE(ClientPositionMessage)23DECLARE_STREAMABLE_METATYPE(ClientPositionMessage)
tools/mtc/CMakeLists.txt+11−0
@@ -0,0 +1,11 @@
1cmake_minimum_required(VERSION 2.8)
2
3set(TARGET_NAME mtc)
4
5set(ROOT_DIR ../..)
6set(MACRO_DIR ${ROOT_DIR}/cmake/macros)
7
8include(${MACRO_DIR}/SetupHifiProject.cmake)
9setup_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
19using namespace std;
20
21class Class {
22public:
23 QString name;
24 QStringList bases;
25};
26
27class Streamable {
28public:
29 Class clazz;
30 QStringList fields;
31};
32
33void 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
89void 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
117int 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}