Unified · Split
| @@ -8,6 +8,7 @@ · 7 unmodified lines | ||
| 8 | 8 | |
| 9 | 9 | #include <PacketHeaders.h> |
| 10 | 10 | |
| 11 | +#include <MetavoxelMessages.h> | |
| 11 | 12 | #include <MetavoxelUtil.h> |
| 12 | 13 | |
| 13 | 14 | #include "MetavoxelServer.h" |
| @@ -88,7 +89,9 @@ void MetavoxelSession::sendData(const QByteArray& data) { · 74 unmodified lines | ||
| 88 | 89 | } |
| 89 | 90 | |
| 90 | 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 | 96 | Bitstream& out = _sequencer.startPacket(); |
| 94 | 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 | 13 | #include <SharedUtil.h> |
| 14 | 14 | |
| 15 | +#include <MetavoxelMessages.h> | |
| 15 | 16 | #include <MetavoxelUtil.h> |
| 16 | 17 | |
| 17 | 18 | #include "Application.h" |
| @@ -193,6 +194,8 @@ MetavoxelClient::MetavoxelClient(const HifiSockAddr& address) : · 175 unmodified lines | ||
| 193 | 194 | |
| 194 | 195 | void MetavoxelClient::simulate(float deltaTime) { |
| 195 | 196 | Bitstream& out = _sequencer.startPacket(); |
| 197 | + ClientPositionMessage msg = { 55 }; | |
| 198 | + out << QVariant::fromValue(msg); | |
| 196 | 199 | _sequencer.endPacket(); |
| 197 | 200 | } |
| 198 | 201 | |
| @@ -13,6 +13,9 @@ find_package(Qt5Widgets REQUIRED) · 12 unmodified lines | ||
| 13 | 13 | include(${MACRO_DIR}/SetupHifiLibrary.cmake) |
| 14 | 14 | setup_hifi_library(${TARGET_NAME}) |
| 15 | 15 | |
| 16 | +include(${MACRO_DIR}/AutoMTC.cmake) | |
| 17 | +auto_mtc(${TARGET_NAME} ${ROOT_DIR}) | |
| 18 | + | |
| 16 | 19 | qt5_use_modules(${TARGET_NAME} Widgets Script) |
| 17 | 20 | |
| 18 | 21 | include(${MACRO_DIR}/IncludeGLM.cmake) |
| @@ -40,6 +40,7 @@ IDStreamer& IDStreamer::operator<<(int value) { · 39 unmodified lines | ||
| 40 | 40 | } |
| 41 | 41 | |
| 42 | 42 | IDStreamer& IDStreamer::operator>>(int& value) { |
| 43 | + value = 0; | |
| 43 | 44 | _stream.read(&value, _bits); |
| 44 | 45 | if (value == (1 << _bits) - 1) { |
| 45 | 46 | _bits++; |
| @@ -93,7 +94,8 @@ Bitstream& Bitstream::read(void* data, int bits, int offset) { · 47 unmodified lines | ||
| 93 | 94 | _underlying >> _byte; |
| 94 | 95 | } |
| 95 | 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 | 99 | _position = (_position + bitsToRead) & LAST_BIT_POSITION; |
| 98 | 100 | if ((offset += bitsToRead) == BITS_IN_BYTE) { |
| 99 | 101 | dest++; |
| @@ -166,7 +168,7 @@ Bitstream& Bitstream::operator<<(int value) { · 66 unmodified lines | ||
| 166 | 168 | } |
| 167 | 169 | |
| 168 | 170 | Bitstream& Bitstream::operator>>(int& value) { |
| 169 | − qint32 sizedValue; | |
| 171 | + qint32 sizedValue = 0; | |
| 170 | 172 | read(&sizedValue, 32); |
| 171 | 173 | value = sizedValue; |
| 172 | 174 | return *this; |
| @@ -180,6 +182,7 @@ Bitstream& Bitstream::operator<<(const QByteArray& string) { · 7 unmodified lines | ||
| 180 | 182 | Bitstream& Bitstream::operator>>(QByteArray& string) { |
| 181 | 183 | int size; |
| 182 | 184 | *this >> size; |
| 185 | + string.resize(size); | |
| 183 | 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 | 194 | Bitstream& Bitstream::operator>>(QString& string) { |
| 192 | 195 | int size; |
| 193 | 196 | *this >> size; |
| 197 | + string.resize(size); | |
| 194 | 198 | return read(string.data(), size * sizeof(QChar) * BITS_IN_BYTE); |
| 195 | 199 | } |
| 196 | 200 | |
| @@ -13,6 +13,7 @@ · 12 unmodified lines | ||
| 13 | 13 | #include <QMetaType> |
| 14 | 14 | #include <QSharedPointer> |
| 15 | 15 | #include <QVariant> |
| 16 | +#include <QtDebug> | |
| 16 | 17 | |
| 17 | 18 | class QByteArray; |
| 18 | 19 | class QDataStream; |
| @@ -278,10 +279,12 @@ public: · 259 unmodified lines | ||
| 278 | 279 | #define REGISTER_SIMPLE_TYPE_STREAMER(x) static int x##Streamer = \ |
| 279 | 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 | 284 | #define DECLARE_STREAMABLE_METATYPE(X) Q_DECLARE_METATYPE(X) \ |
| 283 | 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 | 289 | /// Registers a streamable type and its streamer. |
| 287 | 290 | template<class T> int registerStreamableMetaType() { |
| @@ -290,4 +293,10 @@ template<class T> int registerStreamableMetaType() { · 2 unmodified lines | ||
| 290 | 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 | 302 | #endif /* defined(__interface__Bitstream__) */ |
| @@ -13,9 +13,11 @@ · 12 unmodified lines | ||
| 13 | 13 | |
| 14 | 14 | /// A message containing the position of a client. |
| 15 | 15 | class ClientPositionMessage { |
| 16 | + STREAMABLE | |
| 17 | + | |
| 16 | 18 | public: |
| 17 | 19 | |
| 18 | − int test; | |
| 20 | + STREAM int test; | |
| 19 | 21 | }; |
| 20 | 22 | |
| 21 | 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 | +} | |