mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 22:36:57 +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 <PacketHeaders.h>
|
||||||
|
|
||||||
|
#include <MetavoxelMessages.h>
|
||||||
#include <MetavoxelUtil.h>
|
#include <MetavoxelUtil.h>
|
||||||
|
|
||||||
#include "MetavoxelServer.h"
|
#include "MetavoxelServer.h"
|
||||||
|
@ -88,7 +89,9 @@ void MetavoxelSession::sendData(const QByteArray& data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetavoxelSession::readPacket(Bitstream& in) {
|
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();
|
Bitstream& out = _sequencer.startPacket();
|
||||||
_sequencer.endPacket();
|
_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 <SharedUtil.h>
|
||||||
|
|
||||||
|
#include <MetavoxelMessages.h>
|
||||||
#include <MetavoxelUtil.h>
|
#include <MetavoxelUtil.h>
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
|
@ -193,6 +194,8 @@ MetavoxelClient::MetavoxelClient(const HifiSockAddr& address) :
|
||||||
|
|
||||||
void MetavoxelClient::simulate(float deltaTime) {
|
void MetavoxelClient::simulate(float deltaTime) {
|
||||||
Bitstream& out = _sequencer.startPacket();
|
Bitstream& out = _sequencer.startPacket();
|
||||||
|
ClientPositionMessage msg = { 55 };
|
||||||
|
out << QVariant::fromValue(msg);
|
||||||
_sequencer.endPacket();
|
_sequencer.endPacket();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,9 @@ find_package(Qt5Widgets REQUIRED)
|
||||||
include(${MACRO_DIR}/SetupHifiLibrary.cmake)
|
include(${MACRO_DIR}/SetupHifiLibrary.cmake)
|
||||||
setup_hifi_library(${TARGET_NAME})
|
setup_hifi_library(${TARGET_NAME})
|
||||||
|
|
||||||
|
include(${MACRO_DIR}/AutoMTC.cmake)
|
||||||
|
auto_mtc(${TARGET_NAME} ${ROOT_DIR})
|
||||||
|
|
||||||
qt5_use_modules(${TARGET_NAME} Widgets Script)
|
qt5_use_modules(${TARGET_NAME} Widgets Script)
|
||||||
|
|
||||||
include(${MACRO_DIR}/IncludeGLM.cmake)
|
include(${MACRO_DIR}/IncludeGLM.cmake)
|
||||||
|
|
|
@ -40,6 +40,7 @@ IDStreamer& IDStreamer::operator<<(int value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
IDStreamer& IDStreamer::operator>>(int& value) {
|
IDStreamer& IDStreamer::operator>>(int& value) {
|
||||||
|
value = 0;
|
||||||
_stream.read(&value, _bits);
|
_stream.read(&value, _bits);
|
||||||
if (value == (1 << _bits) - 1) {
|
if (value == (1 << _bits) - 1) {
|
||||||
_bits++;
|
_bits++;
|
||||||
|
@ -93,7 +94,8 @@ Bitstream& Bitstream::read(void* data, int bits, int offset) {
|
||||||
_underlying >> _byte;
|
_underlying >> _byte;
|
||||||
}
|
}
|
||||||
int bitsToRead = qMin(BITS_IN_BYTE - _position, qMin(BITS_IN_BYTE - offset, bits));
|
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;
|
_position = (_position + bitsToRead) & LAST_BIT_POSITION;
|
||||||
if ((offset += bitsToRead) == BITS_IN_BYTE) {
|
if ((offset += bitsToRead) == BITS_IN_BYTE) {
|
||||||
dest++;
|
dest++;
|
||||||
|
@ -166,7 +168,7 @@ Bitstream& Bitstream::operator<<(int value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Bitstream& Bitstream::operator>>(int& value) {
|
Bitstream& Bitstream::operator>>(int& value) {
|
||||||
qint32 sizedValue;
|
qint32 sizedValue = 0;
|
||||||
read(&sizedValue, 32);
|
read(&sizedValue, 32);
|
||||||
value = sizedValue;
|
value = sizedValue;
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -180,6 +182,7 @@ Bitstream& Bitstream::operator<<(const QByteArray& string) {
|
||||||
Bitstream& Bitstream::operator>>(QByteArray& string) {
|
Bitstream& Bitstream::operator>>(QByteArray& string) {
|
||||||
int size;
|
int size;
|
||||||
*this >> size;
|
*this >> size;
|
||||||
|
string.resize(size);
|
||||||
return read(string.data(), size * BITS_IN_BYTE);
|
return read(string.data(), size * BITS_IN_BYTE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,6 +194,7 @@ Bitstream& Bitstream::operator<<(const QString& string) {
|
||||||
Bitstream& Bitstream::operator>>(QString& string) {
|
Bitstream& Bitstream::operator>>(QString& string) {
|
||||||
int size;
|
int size;
|
||||||
*this >> size;
|
*this >> size;
|
||||||
|
string.resize(size);
|
||||||
return read(string.data(), size * sizeof(QChar) * BITS_IN_BYTE);
|
return read(string.data(), size * sizeof(QChar) * BITS_IN_BYTE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <QMetaType>
|
#include <QMetaType>
|
||||||
#include <QSharedPointer>
|
#include <QSharedPointer>
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
|
#include <QtDebug>
|
||||||
|
|
||||||
class QByteArray;
|
class QByteArray;
|
||||||
class QDataStream;
|
class QDataStream;
|
||||||
|
@ -278,10 +279,12 @@ public:
|
||||||
#define REGISTER_SIMPLE_TYPE_STREAMER(x) static int x##Streamer = \
|
#define REGISTER_SIMPLE_TYPE_STREAMER(x) static int x##Streamer = \
|
||||||
Bitstream::registerTypeStreamer(QMetaType::type(#x), new SimpleTypeStreamer<x>());
|
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) \
|
#define DECLARE_STREAMABLE_METATYPE(X) Q_DECLARE_METATYPE(X) \
|
||||||
Bitstream& operator<<(Bitstream& out, const X& obj); \
|
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.
|
/// Registers a streamable type and its streamer.
|
||||||
template<class T> int registerStreamableMetaType() {
|
template<class T> int registerStreamableMetaType() {
|
||||||
|
@ -290,4 +293,10 @@ template<class T> int registerStreamableMetaType() {
|
||||||
return type;
|
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__) */
|
#endif /* defined(__interface__Bitstream__) */
|
||||||
|
|
|
@ -13,9 +13,11 @@
|
||||||
|
|
||||||
/// A message containing the position of a client.
|
/// A message containing the position of a client.
|
||||||
class ClientPositionMessage {
|
class ClientPositionMessage {
|
||||||
|
STREAMABLE
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
int test;
|
STREAM int test;
|
||||||
};
|
};
|
||||||
|
|
||||||
DECLARE_STREAMABLE_METATYPE(ClientPositionMessage)
|
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