Unified · Split
| @@ -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 | ||
| 90 | void MetavoxelSession::readPacket(Bitstream& in) { | 91 | 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"; | ||
| 92 | 95 | ||
| 93 | Bitstream& out = _sequencer.startPacket(); | 96 | Bitstream& out = _sequencer.startPacket(); |
| 94 | _sequencer.endPacket(); | 97 | _sequencer.endPacket(); |
| @@ -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 | |||
| @@ -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 | ||
| 194 | void MetavoxelClient::simulate(float deltaTime) { | 195 | void 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 | ||
| @@ -13,6 +13,9 @@ find_package(Qt5Widgets REQUIRED) · 12 unmodified lines | |||
| 13 | include(${MACRO_DIR}/SetupHifiLibrary.cmake) | 13 | include(${MACRO_DIR}/SetupHifiLibrary.cmake) |
| 14 | setup_hifi_library(${TARGET_NAME}) | 14 | setup_hifi_library(${TARGET_NAME}) |
| 15 | 15 | ||
| 16 | include(${MACRO_DIR}/AutoMTC.cmake) | ||
| 17 | auto_mtc(${TARGET_NAME} ${ROOT_DIR}) | ||
| 18 | |||
| 16 | qt5_use_modules(${TARGET_NAME} Widgets Script) | 19 | qt5_use_modules(${TARGET_NAME} Widgets Script) |
| 17 | 20 | ||
| 18 | include(${MACRO_DIR}/IncludeGLM.cmake) | 21 | include(${MACRO_DIR}/IncludeGLM.cmake) |
| @@ -40,6 +40,7 @@ IDStreamer& IDStreamer::operator<<(int value) { · 39 unmodified lines | |||
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | IDStreamer& IDStreamer::operator>>(int& value) { | 42 | IDStreamer& 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 | ||
| 168 | Bitstream& Bitstream::operator>>(int& value) { | 170 | Bitstream& 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 | |||
| 180 | Bitstream& Bitstream::operator>>(QByteArray& string) { | 182 | Bitstream& 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 | |||
| 191 | Bitstream& Bitstream::operator>>(QString& string) { | 194 | Bitstream& 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 | ||
| @@ -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 | ||
| 17 | class QByteArray; | 18 | class QByteArray; |
| 18 | class QDataStream; | 19 | class 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. |
| 287 | template<class T> int registerStreamableMetaType() { | 290 | template<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__) */ |
| @@ -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. |
| 15 | class ClientPositionMessage { | 15 | class ClientPositionMessage { |
| 16 | STREAMABLE | ||
| 17 | |||
| 16 | public: | 18 | public: |
| 17 | 19 | ||
| 18 | int test; | 20 | STREAM int test; |
| 19 | }; | 21 | }; |
| 20 | 22 | ||
| 21 | DECLARE_STREAMABLE_METATYPE(ClientPositionMessage) | 23 | DECLARE_STREAMABLE_METATYPE(ClientPositionMessage) |
| @@ -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 | |||
| @@ -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 | } | ||