mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-16 17:46:46 +02:00
Added JavaScript Baking
This commit is contained in:
parent
921ebc221e
commit
cda5e94b33
4 changed files with 438 additions and 7 deletions
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include <ClientServerUtils.h>
|
||||
#include <FBXBaker.h>
|
||||
#include <JSBaker.h>
|
||||
#include <NodeType.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <PathUtils.h>
|
||||
|
@ -49,10 +50,11 @@ static const int INTERFACE_RUNNING_CHECK_FREQUENCY_MS = 1000;
|
|||
|
||||
const QString ASSET_SERVER_LOGGING_TARGET_NAME = "asset-server";
|
||||
|
||||
static const QStringList BAKEABLE_MODEL_EXTENSIONS = { "fbx" };
|
||||
static const QStringList BAKEABLE_MODEL_EXTENSIONS = { "fbx" , "js" };
|
||||
static QStringList BAKEABLE_TEXTURE_EXTENSIONS;
|
||||
static const QString BAKED_MODEL_SIMPLE_NAME = "asset.fbx";
|
||||
static const QString BAKED_TEXTURE_SIMPLE_NAME = "texture.ktx";
|
||||
static const QString BAKED_SCRIPT_SIMPLE_NAME = "script.js";
|
||||
|
||||
void AssetServer::bakeAsset(const AssetHash& assetHash, const AssetPath& assetPath, const QString& filePath) {
|
||||
qDebug() << "Starting bake for: " << assetPath << assetHash;
|
||||
|
@ -96,7 +98,11 @@ std::pair<BakingStatus, QString> AssetServer::getAssetStatus(const AssetPath& pa
|
|||
QString bakedFilename;
|
||||
|
||||
if (BAKEABLE_MODEL_EXTENSIONS.contains(extension)) {
|
||||
bakedFilename = BAKED_MODEL_SIMPLE_NAME;
|
||||
if (extension == "js") {
|
||||
bakedFilename = BAKED_SCRIPT_SIMPLE_NAME;
|
||||
} else {
|
||||
bakedFilename = BAKED_MODEL_SIMPLE_NAME;
|
||||
}
|
||||
} else if (BAKEABLE_TEXTURE_EXTENSIONS.contains(extension.toLocal8Bit()) && hasMetaFile(hash)) {
|
||||
bakedFilename = BAKED_TEXTURE_SIMPLE_NAME;
|
||||
} else {
|
||||
|
@ -183,7 +189,11 @@ bool AssetServer::needsToBeBaked(const AssetPath& path, const AssetHash& assetHa
|
|||
}
|
||||
|
||||
if (BAKEABLE_MODEL_EXTENSIONS.contains(extension)) {
|
||||
bakedFilename = BAKED_MODEL_SIMPLE_NAME;
|
||||
if (extension == "js") {
|
||||
bakedFilename = BAKED_SCRIPT_SIMPLE_NAME;
|
||||
} else {
|
||||
bakedFilename = BAKED_MODEL_SIMPLE_NAME;
|
||||
}
|
||||
} else if (loaded && BAKEABLE_TEXTURE_EXTENSIONS.contains(extension.toLocal8Bit())) {
|
||||
bakedFilename = BAKED_TEXTURE_SIMPLE_NAME;
|
||||
} else {
|
||||
|
@ -485,7 +495,11 @@ void AssetServer::handleGetMappingOperation(ReceivedMessage& message, SharedNode
|
|||
QString bakedRootFile;
|
||||
|
||||
if (BAKEABLE_MODEL_EXTENSIONS.contains(assetPathExtension)) {
|
||||
bakedRootFile = BAKED_MODEL_SIMPLE_NAME;
|
||||
if (assetPathExtension == "js") {
|
||||
bakedRootFile = BAKED_SCRIPT_SIMPLE_NAME;
|
||||
} else {
|
||||
bakedRootFile = BAKED_MODEL_SIMPLE_NAME;
|
||||
}
|
||||
} else if (BAKEABLE_TEXTURE_EXTENSIONS.contains(assetPathExtension.toLocal8Bit())) {
|
||||
bakedRootFile = BAKED_TEXTURE_SIMPLE_NAME;
|
||||
}
|
||||
|
@ -1141,6 +1155,7 @@ bool AssetServer::renameMapping(AssetPath oldPath, AssetPath newPath) {
|
|||
|
||||
static const QString BAKED_ASSET_SIMPLE_FBX_NAME = "asset.fbx";
|
||||
static const QString BAKED_ASSET_SIMPLE_TEXTURE_NAME = "texture.ktx";
|
||||
static const QString BAKED_ASSET_SIMPLE_JS_NAME = "script.js";
|
||||
|
||||
QString getBakeMapping(const AssetHash& hash, const QString& relativeFilePath) {
|
||||
return HIDDEN_BAKED_CONTENT_FOLDER + hash + "/" + relativeFilePath;
|
||||
|
@ -1203,8 +1218,9 @@ void AssetServer::handleCompletedBake(QString originalAssetHash, QString origina
|
|||
// setup the mapping for this bake file
|
||||
auto relativeFilePath = QUrl(filePath).fileName();
|
||||
qDebug() << "Relative file path is: " << relativeFilePath;
|
||||
|
||||
if (relativeFilePath.endsWith(".fbx", Qt::CaseInsensitive)) {
|
||||
if (relativeFilePath.endsWith(".js", Qt::CaseInsensitive)) {
|
||||
relativeFilePath = BAKED_ASSET_SIMPLE_JS_NAME;
|
||||
} else if (relativeFilePath.endsWith(".fbx", Qt::CaseInsensitive)) {
|
||||
// for an FBX file, we replace the filename with the simple name
|
||||
// (to handle the case where two mapped assets have the same hash but different names)
|
||||
relativeFilePath = BAKED_ASSET_SIMPLE_FBX_NAME;
|
||||
|
@ -1350,7 +1366,11 @@ bool AssetServer::setBakingEnabled(const AssetPathList& paths, bool enabled) {
|
|||
QString bakedFilename;
|
||||
|
||||
if (BAKEABLE_MODEL_EXTENSIONS.contains(extension)) {
|
||||
bakedFilename = BAKED_MODEL_SIMPLE_NAME;
|
||||
if (extension == "js") {
|
||||
bakedFilename = BAKED_SCRIPT_SIMPLE_NAME;
|
||||
} else {
|
||||
bakedFilename = BAKED_MODEL_SIMPLE_NAME;
|
||||
}
|
||||
} else if (BAKEABLE_TEXTURE_EXTENSIONS.contains(extension.toLocal8Bit()) && hasMetaFile(hash)) {
|
||||
bakedFilename = BAKED_TEXTURE_SIMPLE_NAME;
|
||||
} else {
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include <FBXBaker.h>
|
||||
#include <PathUtils.h>
|
||||
#include <JSBaker.h>
|
||||
|
||||
BakeAssetTask::BakeAssetTask(const AssetHash& assetHash, const AssetPath& assetPath, const QString& filePath) :
|
||||
_assetHash(assetHash),
|
||||
|
@ -34,6 +35,10 @@ void BakeAssetTask::run() {
|
|||
_baker = std::unique_ptr<FBXBaker> {
|
||||
new FBXBaker(QUrl("file:///" + _filePath), fn, PathUtils::generateTemporaryDir())
|
||||
};
|
||||
} else if (_assetPath.endsWith(".js", Qt::CaseInsensitive)) {
|
||||
_baker = std::unique_ptr<JSBaker>{
|
||||
new JSBaker(QUrl("file:///" + _filePath), PathUtils::generateTemporaryDir())
|
||||
};
|
||||
} else {
|
||||
_baker = std::unique_ptr<TextureBaker> {
|
||||
new TextureBaker(QUrl("file:///" + _filePath), image::TextureUsage::CUBE_TEXTURE,
|
||||
|
|
349
libraries/baking/src/JSBaker.cpp
Normal file
349
libraries/baking/src/JSBaker.cpp
Normal file
|
@ -0,0 +1,349 @@
|
|||
#include <QtConcurrent>
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QEventLoop>
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QtCore/QThread>
|
||||
#include <PathUtils.h>
|
||||
|
||||
#include "JSBaker.h"
|
||||
#include "Baker.h"
|
||||
|
||||
JSBaker::JSBaker(const QUrl& jsURL, const QString& bakedOutputDir) :
|
||||
_jsURL(jsURL),
|
||||
_bakedOutputDir(bakedOutputDir)
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
void JSBaker::bake() {
|
||||
|
||||
auto tempDir = PathUtils::generateTemporaryDir();
|
||||
|
||||
if (tempDir.isEmpty()) {
|
||||
handleError("Failed to create a temporary directory.");
|
||||
return;
|
||||
}
|
||||
|
||||
_tempDir = tempDir;
|
||||
|
||||
_originalJSFilePath = _tempDir.filePath(_jsURL.fileName());
|
||||
qDebug() << "Made temporary dir " << _tempDir;
|
||||
qDebug() << "Origin file path: " << _originalJSFilePath;
|
||||
|
||||
connect(this, &JSBaker::sourceCopyReadyToLoad, this, &JSBaker::bakeSourceCopy);
|
||||
|
||||
loadSourceJS();
|
||||
}
|
||||
|
||||
void JSBaker::loadSourceJS() {
|
||||
|
||||
// load the local file
|
||||
QFile localJS{ _jsURL.toLocalFile() };
|
||||
|
||||
if (!localJS.exists()) {
|
||||
|
||||
handleError("Could not find " + _jsURL.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
// copy to original file
|
||||
qDebug() << "Local file url: " << _jsURL << _jsURL.toString() << _jsURL.toLocalFile() << ", copying to: " << _originalJSFilePath;
|
||||
localJS.copy(_originalJSFilePath);
|
||||
|
||||
// emit signal to indicate script is ready to import
|
||||
emit sourceCopyReadyToLoad();
|
||||
}
|
||||
|
||||
void JSBaker::bakeSourceCopy() {
|
||||
|
||||
importScript();
|
||||
|
||||
if (hasErrors()) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*bakeScript();
|
||||
if (hasErrors()) {
|
||||
return;
|
||||
}*/
|
||||
|
||||
/*exportScript();
|
||||
|
||||
if (hasErrors()) {
|
||||
return;
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
void JSBaker::importScript() {
|
||||
|
||||
//qDebug() << "file path: " << _originalJSFilePath.toLocal8Bit().data() << QDir(_originalJSFilePath).exists();
|
||||
|
||||
// Import the file to be processed
|
||||
QFile jsFile(_originalJSFilePath);
|
||||
if (!jsFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
handleError("Error opening " + _originalJSFilePath + " for reading");
|
||||
return;
|
||||
}
|
||||
|
||||
// Call Bake Script with the opened file
|
||||
bakeScript(&jsFile);
|
||||
}
|
||||
|
||||
void JSBaker::bakeScript(QFile* inFile) {
|
||||
|
||||
QFile outFile;
|
||||
outFile.open(QIODevice::WriteOnly | QIODevice::Text);
|
||||
QTextStream in(inFile);
|
||||
QTextStream out(&outFile);
|
||||
|
||||
QChar currentChar;
|
||||
QChar prevChar;
|
||||
QChar nextChar;
|
||||
|
||||
// Initialize prevChar with new line
|
||||
prevChar = '\n';
|
||||
in >> currentChar;
|
||||
|
||||
while (!in.atEnd()) {
|
||||
|
||||
// Reading per character
|
||||
in >> nextChar;
|
||||
|
||||
if (currentChar == '\r') {
|
||||
out << '\n';
|
||||
//currentChar = '\n';
|
||||
|
||||
} else if (currentChar == '/') {
|
||||
|
||||
if (nextChar == '/') {
|
||||
|
||||
handleSingleLineComments(&in);
|
||||
//out << '\n';
|
||||
|
||||
//Start fresh after handling comments
|
||||
prevChar = '\n';
|
||||
in >> currentChar;
|
||||
continue;
|
||||
|
||||
} else if (nextChar == '*') {
|
||||
|
||||
handleMultiLineComments(&in);
|
||||
//out << ' ';
|
||||
|
||||
//Start fresh after handling comments
|
||||
prevChar = '\n';
|
||||
in >> currentChar;
|
||||
//currentChar = ' ';
|
||||
continue;
|
||||
} else {
|
||||
out << currentChar;
|
||||
}
|
||||
} else if (currentChar == ' ' || (int) currentChar.toLatin1() == 9) {
|
||||
|
||||
// Handle multiple spaces
|
||||
if (nextChar == ' ' || (int)currentChar.toLatin1() == 9) {
|
||||
while (nextChar == ' ' || (int)nextChar.toLatin1() == 9 ) {
|
||||
|
||||
in >> nextChar;
|
||||
if (nextChar == '\n')
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!omitSpace(prevChar,nextChar)) {
|
||||
|
||||
out << ' ';
|
||||
}
|
||||
|
||||
} else if (currentChar == '\n') {
|
||||
qDebug() << "prevChar2" << prevChar;
|
||||
qDebug() << "currentChar2" << currentChar;
|
||||
qDebug() << "nextChar2" << nextChar;
|
||||
//Handle multiple new lines
|
||||
//Hnadle new line followed by space or tab
|
||||
if (nextChar == '\n' || nextChar == ' ' || (int)nextChar.toLatin1() == 9) {
|
||||
while (nextChar == '\n' || nextChar == ' ' || (int)nextChar.toLatin1() == 9) {
|
||||
in >> nextChar;
|
||||
}
|
||||
}
|
||||
|
||||
if (!omitNewLine(prevChar, nextChar)) {
|
||||
out << '\n';
|
||||
}
|
||||
|
||||
} else if (currentChar == '"' ) {
|
||||
//Don't modify quoted strings
|
||||
out << currentChar;
|
||||
out << nextChar;
|
||||
while (nextChar != '"') {
|
||||
in >> nextChar;
|
||||
out << nextChar;
|
||||
}
|
||||
|
||||
|
||||
//Start fresh after handling quoted strings
|
||||
//prevChar = '"';
|
||||
prevChar = nextChar;
|
||||
//currentChar = nextChar;
|
||||
in >> currentChar;
|
||||
continue;
|
||||
} else if (currentChar == "'") {
|
||||
//Don't modify quoted strings
|
||||
out << currentChar;
|
||||
out << nextChar;
|
||||
while (nextChar != "'") {
|
||||
in >> nextChar;
|
||||
out << nextChar;
|
||||
}
|
||||
|
||||
qDebug() << "prevChar" << prevChar;
|
||||
qDebug() << "currentChar" << currentChar;
|
||||
qDebug() << "nextChar" << nextChar;
|
||||
|
||||
//out << nextChar;
|
||||
//Start fresh after handling quoted strings
|
||||
//prevChar = '\'';
|
||||
prevChar = nextChar;
|
||||
//currentChar = nextChar;
|
||||
in >> currentChar;
|
||||
qDebug() << "prevChar1" << prevChar;
|
||||
qDebug() << "currentChar1" << currentChar;
|
||||
qDebug() << "nextChar1" << nextChar;
|
||||
continue;
|
||||
} else {
|
||||
out << currentChar;
|
||||
|
||||
}
|
||||
|
||||
prevChar = currentChar;
|
||||
currentChar = nextChar;
|
||||
}
|
||||
|
||||
//Output current character when next character reaches EOF
|
||||
if (currentChar != '\n') {
|
||||
|
||||
out << currentChar;
|
||||
}
|
||||
|
||||
|
||||
inFile->close();
|
||||
exportScript(&outFile);
|
||||
}
|
||||
|
||||
void JSBaker::handleSingleLineComments(QTextStream * in) {
|
||||
QChar ch;
|
||||
|
||||
while (!in->atEnd()) {
|
||||
*in >> ch;
|
||||
if (ch <= '\n')
|
||||
break;
|
||||
}
|
||||
|
||||
//*out << '\n';
|
||||
}
|
||||
|
||||
void JSBaker::handleMultiLineComments(QTextStream * in) {
|
||||
QChar ch;
|
||||
|
||||
while (!in->atEnd()) {
|
||||
*in >> ch;
|
||||
if (ch == '*') {
|
||||
if (in->read(1) == '/') {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handleError("Eror unterminated multi line comment");
|
||||
|
||||
}
|
||||
|
||||
bool JSBaker::isAlphanum(QChar c) {
|
||||
return ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
|
||||
(c >= 'A' && c <= 'Z') || c == '_' || c == '$' || c == '\\' ||
|
||||
c > 126);
|
||||
}
|
||||
|
||||
bool JSBaker::omitSpace(QChar prevChar, QChar nextChar) {
|
||||
|
||||
if ((isAlphanum(prevChar) || isNonAscii(prevChar) || isSpecialChar(prevChar)) &&
|
||||
(isAlphanum(nextChar) || isNonAscii(nextChar) || isSpecialChar(nextChar))
|
||||
) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool JSBaker::isNonAscii(QChar c) {
|
||||
return ((int)c.toLatin1() > 127);
|
||||
}
|
||||
|
||||
bool JSBaker::isSpecialChar(QChar c) {
|
||||
|
||||
if (c == '\'' || c == '$' || c == '_')
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool JSBaker::isSpecialCharPre(QChar c) {
|
||||
|
||||
if (c == '\'' || c == '$' || c == '_' || c == '}' || c == ']' || c == ')' || c == '+' || c == '-'
|
||||
|| c == '"' || c == "'")
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool JSBaker::isSpecialCharPost(QChar c) {
|
||||
|
||||
if (c == '\'' || c == '$' || c == '_' || c == '{' || c == '[' || c == '(' || c == '+' || c == '-' || c == '/')
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool JSBaker::omitNewLine(QChar prevChar, QChar nextChar) {
|
||||
|
||||
if ((isAlphanum(prevChar) || isNonAscii(prevChar) || isSpecialCharPre(prevChar)) &&
|
||||
(isAlphanum(nextChar) || isNonAscii(nextChar) || isSpecialCharPost(nextChar))
|
||||
) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
void JSBaker::exportScript(QFile* bakedFile) {
|
||||
// save the relative path to this FBX inside our passed output folder
|
||||
auto fileName = _jsURL.fileName();
|
||||
auto baseName = fileName.left(fileName.lastIndexOf('.'));
|
||||
auto bakedFilename = baseName + BAKED_JS_EXTENSION;
|
||||
|
||||
_bakedJSFilePath = _bakedOutputDir + "/" + bakedFilename;
|
||||
|
||||
bakedFile->setFileName(_bakedJSFilePath);
|
||||
|
||||
//QFile bakedFile(_bakedJSFilePath);
|
||||
|
||||
if (!bakedFile->open(QIODevice::WriteOnly)) {
|
||||
handleError("Error opening " + _bakedJSFilePath + " for writing");
|
||||
return;
|
||||
}
|
||||
|
||||
/*QByteArray x(5, 'a');
|
||||
bakedFile.copy();*/
|
||||
|
||||
_outputFiles.push_back(_bakedJSFilePath);
|
||||
|
||||
qCDebug(model_baking) << "Exported" << _jsURL << "with re-written paths to" << _bakedJSFilePath;
|
||||
bakedFile->close();
|
||||
emit finished();
|
||||
}
|
57
libraries/baking/src/JSBaker.h
Normal file
57
libraries/baking/src/JSBaker.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
#ifndef hifi_JSBaker_h
|
||||
#define hifi_JSBaker_h
|
||||
|
||||
#include <QtCore/QFutureSynchronizer>
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QUrl>
|
||||
|
||||
#include "Baker.h"
|
||||
#include "TextureBaker.h"
|
||||
#include "ModelBakingLoggingCategory.h"
|
||||
|
||||
static const QString BAKED_JS_EXTENSION = ".baked.js";
|
||||
|
||||
class JSBaker : public Baker {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
JSBaker(const QUrl& jsURL, const QString& bakedOutputDir);
|
||||
|
||||
public slots:
|
||||
virtual void bake() override;
|
||||
|
||||
signals:
|
||||
void sourceCopyReadyToLoad();
|
||||
|
||||
private slots:
|
||||
void bakeSourceCopy();
|
||||
|
||||
|
||||
private :
|
||||
|
||||
QUrl _jsURL;
|
||||
QString _bakedOutputDir;
|
||||
QDir _tempDir;
|
||||
QString _originalJSFilePath;
|
||||
QString _bakedJSFilePath;
|
||||
QByteArray _buffer;
|
||||
|
||||
void loadSourceJS();
|
||||
void importScript();
|
||||
|
||||
void exportScript(QFile*);
|
||||
void bakeScript(QFile*);
|
||||
void handleSingleLineComments(QTextStream*);
|
||||
void handleMultiLineComments(QTextStream*);
|
||||
|
||||
bool isAlphanum(QChar);
|
||||
bool omitSpace(QChar, QChar);
|
||||
bool isNonAscii(QChar c);
|
||||
bool isSpecialChar(QChar c);
|
||||
bool isSpecialCharPre(QChar c);
|
||||
bool isSpecialCharPost(QChar c);
|
||||
bool omitNewLine(QChar, QChar);
|
||||
|
||||
};
|
||||
|
||||
#endif // !hifi_JSBaker_h
|
Loading…
Reference in a new issue