mirror of
https://github.com/overte-org/overte.git
synced 2025-04-19 16:23:39 +02:00
Basic "meta type compiler" for streaming, streaming fixes and test.
This commit is contained in:
parent
f9043c3cb9
commit
effd00a405
9 changed files with 241 additions and 6 deletions
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <PacketHeaders.h>
|
||||
|
||||
#include <MetavoxelMessages.h>
|
||||
#include <MetavoxelUtil.h>
|
||||
|
||||
#include "MetavoxelServer.h"
|
||||
|
@ -88,7 +89,9 @@ void MetavoxelSession::sendData(const QByteArray& data) {
|
|||
}
|
||||
|
||||
void MetavoxelSession::readPacket(Bitstream& in) {
|
||||
qDebug("got packet from client!\n");
|
||||
QVariant msg;
|
||||
in >> msg;
|
||||
qDebug() << msg.value<ClientPositionMessage>().test << "\n";
|
||||
|
||||
Bitstream& out = _sequencer.startPacket();
|
||||
_sequencer.endPacket();
|
||||
|
|
20
cmake/macros/AutoMTC.cmake
Normal file
20
cmake/macros/AutoMTC.cmake
Normal file
|
@ -0,0 +1,20 @@
|
|||
macro(AUTO_MTC TARGET ROOT_DIR)
|
||||
if (NOT TARGET mtc)
|
||||
add_subdirectory(${ROOT_DIR}/tools/mtc ${ROOT_DIR}/tools/mtc)
|
||||
endif (NOT TARGET mtc)
|
||||
|
||||
file(GLOB INCLUDE_FILES src/*.h)
|
||||
|
||||
add_custom_command(OUTPUT ${TARGET}_automtc.cpp COMMAND mtc -o ${TARGET}_automtc.cpp ${INCLUDE_FILES} DEPENDS mtc)
|
||||
|
||||
find_package(Qt5Core REQUIRED)
|
||||
|
||||
add_library(${TARGET}_automtc STATIC ${TARGET}_automtc.cpp)
|
||||
|
||||
qt5_use_modules(${TARGET}_automtc Core)
|
||||
|
||||
target_link_libraries(${TARGET} ${TARGET}_automtc)
|
||||
|
||||
endmacro()
|
||||
|
||||
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include <MetavoxelMessages.h>
|
||||
#include <MetavoxelUtil.h>
|
||||
|
||||
#include "Application.h"
|
||||
|
@ -193,6 +194,8 @@ MetavoxelClient::MetavoxelClient(const HifiSockAddr& address) :
|
|||
|
||||
void MetavoxelClient::simulate(float deltaTime) {
|
||||
Bitstream& out = _sequencer.startPacket();
|
||||
ClientPositionMessage msg = { 55 };
|
||||
out << QVariant::fromValue(msg);
|
||||
_sequencer.endPacket();
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,9 @@ find_package(Qt5Widgets REQUIRED)
|
|||
include(${MACRO_DIR}/SetupHifiLibrary.cmake)
|
||||
setup_hifi_library(${TARGET_NAME})
|
||||
|
||||
include(${MACRO_DIR}/AutoMTC.cmake)
|
||||
auto_mtc(${TARGET_NAME} ${ROOT_DIR})
|
||||
|
||||
qt5_use_modules(${TARGET_NAME} Widgets Script)
|
||||
|
||||
include(${MACRO_DIR}/IncludeGLM.cmake)
|
||||
|
|
|
@ -40,6 +40,7 @@ IDStreamer& IDStreamer::operator<<(int value) {
|
|||
}
|
||||
|
||||
IDStreamer& IDStreamer::operator>>(int& value) {
|
||||
value = 0;
|
||||
_stream.read(&value, _bits);
|
||||
if (value == (1 << _bits) - 1) {
|
||||
_bits++;
|
||||
|
@ -93,7 +94,8 @@ Bitstream& Bitstream::read(void* data, int bits, int offset) {
|
|||
_underlying >> _byte;
|
||||
}
|
||||
int bitsToRead = qMin(BITS_IN_BYTE - _position, qMin(BITS_IN_BYTE - offset, bits));
|
||||
*dest |= ((_byte >> _position) & ((1 << bitsToRead) - 1)) << offset;
|
||||
int mask = ((1 << bitsToRead) - 1) << offset;
|
||||
*dest = (*dest & ~mask) | (((_byte >> _position) << offset) & mask);
|
||||
_position = (_position + bitsToRead) & LAST_BIT_POSITION;
|
||||
if ((offset += bitsToRead) == BITS_IN_BYTE) {
|
||||
dest++;
|
||||
|
@ -166,7 +168,7 @@ Bitstream& Bitstream::operator<<(int value) {
|
|||
}
|
||||
|
||||
Bitstream& Bitstream::operator>>(int& value) {
|
||||
qint32 sizedValue;
|
||||
qint32 sizedValue = 0;
|
||||
read(&sizedValue, 32);
|
||||
value = sizedValue;
|
||||
return *this;
|
||||
|
@ -180,6 +182,7 @@ Bitstream& Bitstream::operator<<(const QByteArray& string) {
|
|||
Bitstream& Bitstream::operator>>(QByteArray& string) {
|
||||
int size;
|
||||
*this >> size;
|
||||
string.resize(size);
|
||||
return read(string.data(), size * BITS_IN_BYTE);
|
||||
}
|
||||
|
||||
|
@ -191,6 +194,7 @@ Bitstream& Bitstream::operator<<(const QString& string) {
|
|||
Bitstream& Bitstream::operator>>(QString& string) {
|
||||
int size;
|
||||
*this >> size;
|
||||
string.resize(size);
|
||||
return read(string.data(), size * sizeof(QChar) * BITS_IN_BYTE);
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <QMetaType>
|
||||
#include <QSharedPointer>
|
||||
#include <QVariant>
|
||||
#include <QtDebug>
|
||||
|
||||
class QByteArray;
|
||||
class QDataStream;
|
||||
|
@ -278,10 +279,12 @@ public:
|
|||
#define REGISTER_SIMPLE_TYPE_STREAMER(x) static int x##Streamer = \
|
||||
Bitstream::registerTypeStreamer(QMetaType::type(#x), new SimpleTypeStreamer<x>());
|
||||
|
||||
/// Declares the metatype and the streaming operators.
|
||||
/// Declares the metatype and the streaming operators. The last line
|
||||
/// ensures that the generated file will be included in the link phase.
|
||||
#define DECLARE_STREAMABLE_METATYPE(X) Q_DECLARE_METATYPE(X) \
|
||||
Bitstream& operator<<(Bitstream& out, const X& obj); \
|
||||
Bitstream& operator>>(Bitstream& in, X& obj);
|
||||
Bitstream& operator>>(Bitstream& in, X& obj); \
|
||||
static const int* _TypePtr##X = &X::Type;
|
||||
|
||||
/// Registers a streamable type and its streamer.
|
||||
template<class T> int registerStreamableMetaType() {
|
||||
|
@ -290,4 +293,10 @@ template<class T> int registerStreamableMetaType() {
|
|||
return type;
|
||||
}
|
||||
|
||||
/// Flags a class as streamable (use as you would Q_OBJECT).
|
||||
#define STREAMABLE public: static const int Type; private:
|
||||
|
||||
/// Flags a field or base class as streaming.
|
||||
#define STREAM
|
||||
|
||||
#endif /* defined(__interface__Bitstream__) */
|
||||
|
|
|
@ -13,9 +13,11 @@
|
|||
|
||||
/// A message containing the position of a client.
|
||||
class ClientPositionMessage {
|
||||
STREAMABLE
|
||||
|
||||
public:
|
||||
|
||||
int test;
|
||||
STREAM int test;
|
||||
};
|
||||
|
||||
DECLARE_STREAMABLE_METATYPE(ClientPositionMessage)
|
||||
|
|
11
tools/mtc/CMakeLists.txt
Normal file
11
tools/mtc/CMakeLists.txt
Normal file
|
@ -0,0 +1,11 @@
|
|||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
set(TARGET_NAME mtc)
|
||||
|
||||
set(ROOT_DIR ../..)
|
||||
set(MACRO_DIR ${ROOT_DIR}/cmake/macros)
|
||||
|
||||
include(${MACRO_DIR}/SetupHifiProject.cmake)
|
||||
setup_hifi_project(${TARGET_NAME} TRUE)
|
||||
|
||||
|
180
tools/mtc/src/main.cpp
Normal file
180
tools/mtc/src/main.cpp
Normal file
|
@ -0,0 +1,180 @@
|
|||
//
|
||||
// main.cpp
|
||||
// mtc
|
||||
//
|
||||
// Created by Andrzej Kapolka on 12/31/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <QFile>
|
||||
#include <QList>
|
||||
#include <QRegExp>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QTextStream>
|
||||
#include <QtDebug>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class Class {
|
||||
public:
|
||||
QString name;
|
||||
QStringList bases;
|
||||
};
|
||||
|
||||
class Streamable {
|
||||
public:
|
||||
Class clazz;
|
||||
QStringList fields;
|
||||
};
|
||||
|
||||
void processInput(QTextStream& in, QList<Streamable>* streamables) {
|
||||
Class clazz;
|
||||
Streamable currentStreamable;
|
||||
|
||||
QRegExp exp(
|
||||
"(/\\*.*\\*/)|" // multi-line comments
|
||||
"(//.*\n)|" // single-line comments
|
||||
"(\\s*#.*\n)|" // preprocessor definitions
|
||||
"(\\s*STREAMABLE\\s+)|" // STREAMABLE tag for classes
|
||||
"(\\s*STREAM\\s+.*;)|" // STREAM tag for fields
|
||||
"(\\s*class\\s+[^;]+\\{)" // class definition
|
||||
);
|
||||
exp.setMinimal(true);
|
||||
|
||||
QRegExp classExp("class (\\w+) ?:?([^:]*)\\{");
|
||||
|
||||
// read in the entire input and look for matches with our expression
|
||||
QString all = in.readAll();
|
||||
for (int off = 0; (off = exp.indexIn(all, off)) != -1; off += exp.matchedLength()) {
|
||||
QString match = exp.cap().simplified();
|
||||
if (match.startsWith("/*") || match.startsWith("//") || match.startsWith('#')) {
|
||||
continue; // comment, preprocessor definition
|
||||
}
|
||||
if (match.startsWith("STREAMABLE")) {
|
||||
if (clazz.name.isEmpty()) {
|
||||
cerr << "Found STREAMABLE marker before class definition." << endl;
|
||||
continue;
|
||||
}
|
||||
if (!currentStreamable.clazz.name.isEmpty()) {
|
||||
streamables->append(currentStreamable);
|
||||
}
|
||||
currentStreamable.clazz = clazz;
|
||||
currentStreamable.fields.clear();
|
||||
|
||||
} else if (match.startsWith("STREAM")) {
|
||||
match.chop(1); // get rid of the semicolon
|
||||
match = match.trimmed(); // and any space before it
|
||||
currentStreamable.fields.append(match.mid(match.lastIndexOf(' ') + 1));
|
||||
|
||||
} else { // match.startsWith("class")
|
||||
classExp.exactMatch(match);
|
||||
clazz.name = classExp.cap(1);
|
||||
clazz.bases.clear();
|
||||
foreach (const QString& bstr, classExp.cap(2).split(',')) {
|
||||
QString base = bstr.trimmed();
|
||||
if (!base.isEmpty() && base.startsWith("STREAM")) {
|
||||
clazz.bases.append(base.mid(base.lastIndexOf(' ') + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!currentStreamable.clazz.name.isEmpty()) {
|
||||
streamables->append(currentStreamable);
|
||||
}
|
||||
}
|
||||
|
||||
void generateOutput (QTextStream& out, const QList<Streamable>& streamables) {
|
||||
foreach (const Streamable& str, streamables) {
|
||||
const QString& name = str.clazz.name;
|
||||
|
||||
out << "Bitstream& operator<< (Bitstream& out, const " << name << "& obj) {\n";
|
||||
foreach (const QString& base, str.clazz.bases) {
|
||||
out << " out << static_cast<const " << base << "&>(obj);\n";
|
||||
}
|
||||
foreach (const QString& field, str.fields) {
|
||||
out << " out << obj." << field << ";\n";
|
||||
}
|
||||
out << " return out;\n";
|
||||
out << "}\n";
|
||||
|
||||
out << "Bitstream& operator>> (Bitstream& in, " << name << "& obj) {\n";
|
||||
foreach (const QString& base, str.clazz.bases) {
|
||||
out << " in >> static_cast<" << base << "&>(obj);\n";
|
||||
}
|
||||
foreach (const QString& field, str.fields) {
|
||||
out << " in >> obj." << field << ";\n";
|
||||
}
|
||||
out << " return in;\n";
|
||||
out << "}\n";
|
||||
|
||||
out << "const int " << name << "::Type = registerStreamableMetaType<" << name << ">();\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
int main (int argc, char** argv) {
|
||||
// process the command line arguments
|
||||
QStringList inputs;
|
||||
QString output;
|
||||
for (int ii = 1; ii < argc; ii++) {
|
||||
QString arg(argv[ii]);
|
||||
if (!arg.startsWith('-')) {
|
||||
inputs.append(arg);
|
||||
continue;
|
||||
}
|
||||
QStringRef name = arg.midRef(1);
|
||||
if (name == "o") {
|
||||
if (++ii == argc) {
|
||||
cerr << "Missing file name argument for -o" << endl;
|
||||
return 1;
|
||||
}
|
||||
output = argv[ii];
|
||||
|
||||
} else {
|
||||
cerr << "Unknown option " << arg.toStdString() << endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (inputs.isEmpty()) {
|
||||
cerr << "Usage: mtc [OPTION]... input files" << endl;
|
||||
cerr << "Where options include:" << endl;
|
||||
cerr << " -o filename: Send output to filename rather than standard output." << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
QList<Streamable> streamables;
|
||||
foreach (const QString& input, inputs) {
|
||||
QFile ifile(input);
|
||||
if (!ifile.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
cerr << ("Couldn't open " + input + ": " + ifile.errorString()).toStdString() << endl;
|
||||
continue;
|
||||
}
|
||||
QTextStream istream(&ifile);
|
||||
int oldSize = streamables.size();
|
||||
processInput(istream, &streamables);
|
||||
if (streamables.size() == oldSize) {
|
||||
// no streamables; remove from list
|
||||
inputs.removeOne(input);
|
||||
}
|
||||
}
|
||||
|
||||
QFile ofile(output);
|
||||
if (output.isNull()) {
|
||||
ofile.open(stdout, QIODevice::WriteOnly | QIODevice::Text);
|
||||
|
||||
} else if (!ofile.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
cerr << ("Couldn't open " + output + ": " + ofile.errorString()).toStdString() << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
QTextStream ostream(&ofile);
|
||||
ostream << "// generated by mtc\n";
|
||||
foreach (const QString& input, inputs) {
|
||||
ostream << "#include \"" << input << "\"\n";
|
||||
}
|
||||
generateOutput(ostream, streamables);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue