2023-09-24 18:39:52 +02:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "Zip.h"
|
|
|
|
#include "Atlas.h"
|
|
|
|
#include "conversion.h"
|
|
|
|
#include "Artboard.h"
|
|
|
|
#include "ofEasyCam.h"
|
|
|
|
#include "ofMain.h"
|
|
|
|
#include "ofQuaternion.h"
|
|
|
|
#include "ofTrueTypeFont.h"
|
|
|
|
#include "ofxVariableLab.h"
|
|
|
|
#include "ofxProfiler.h"
|
|
|
|
#include <unordered_map>
|
|
|
|
#ifdef TARGET_EMSCRIPTEN
|
|
|
|
#include <emscripten/em_macros.h>
|
|
|
|
#include <emscripten/bind.h>
|
|
|
|
#include <emscripten.h>
|
|
|
|
#include <emscripten-browser-file/emscripten_browser_file.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
using namespace msdfgen;
|
|
|
|
|
|
|
|
// TODO: better antialias
|
|
|
|
// possibly just draw a bigger fbo?
|
|
|
|
// or do it properly:
|
|
|
|
// https://github.com/emscripten-core/emscripten/issues/7898
|
|
|
|
//
|
|
|
|
// TODO: fix linux build
|
|
|
|
|
|
|
|
namespace VariableEditor {
|
|
|
|
|
|
|
|
struct AppSettings {
|
|
|
|
std::array <float, 4> backgroundColor = {212 / 255.0,
|
|
|
|
212 / 255.0,
|
|
|
|
212 / 255.0,
|
|
|
|
1}; // check data/appSettings.json
|
2024-02-29 16:32:49 +01:00
|
|
|
std::string tmpExportDir = "data/export";
|
|
|
|
std::string tmpImportDir = "data/import";
|
2023-09-24 18:39:52 +02:00
|
|
|
|
|
|
|
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(AppSettings,
|
|
|
|
backgroundColor,
|
|
|
|
tmpExportDir);
|
|
|
|
|
|
|
|
};
|
|
|
|
|
2024-02-29 16:32:49 +01:00
|
|
|
class ZipProjectSaver :
|
|
|
|
public ofThread {
|
2023-09-24 18:39:52 +02:00
|
|
|
public:
|
|
|
|
void setup(string projectName,
|
|
|
|
string projectJsonString){
|
|
|
|
this->projectName = projectName;
|
|
|
|
this->projectJsonString = projectJsonString;
|
|
|
|
this->userFontsPath = "/idbfs/fonts";
|
2023-10-20 13:29:15 +02:00
|
|
|
this->userAudioPath = "/idbfs/audio";
|
2023-09-24 18:39:52 +02:00
|
|
|
this->timestamp = ofGetTimestampString();
|
|
|
|
this->filename = projectName + "_project_" + timestamp + ".zip";
|
|
|
|
}
|
|
|
|
|
|
|
|
void update(){
|
|
|
|
if(freshDownload.load()){
|
|
|
|
emscripten_browser_file::download(filename.c_str(),
|
|
|
|
"application/zip",
|
|
|
|
buffer,
|
|
|
|
buffer_size);
|
|
|
|
freshDownload.store(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void threadedFunction(){
|
|
|
|
Zip zip(filename.c_str());
|
|
|
|
ofDisableDataPath();
|
|
|
|
|
|
|
|
{
|
|
|
|
char buffy[projectJsonString.length()];
|
|
|
|
projectJsonString.copy(buffy, projectJsonString.length());
|
|
|
|
zip.addBuffer("project.json", buffy, projectJsonString.length());
|
|
|
|
}
|
|
|
|
|
|
|
|
ofDirectory userFonts(userFontsPath);
|
|
|
|
userFonts.sort();
|
|
|
|
userFonts.allowExt("ttf");
|
|
|
|
userFonts.allowExt("otf");
|
|
|
|
userFonts.listDir();
|
|
|
|
for(int i = 0; i < userFonts.size(); i++){
|
|
|
|
std::string fontFilename = userFonts.getName(i);
|
|
|
|
std::string fontFilepath = userFontsPath + "/" + fontFilename;
|
|
|
|
ofFile file = userFonts.getFile(i);
|
|
|
|
ofStringReplace(fontFilepath, "/idbfs/", "idbfs/");
|
|
|
|
if(of::filesystem::exists(fontFilepath)){
|
|
|
|
//cout << "huuurrayy " << fontFilepath << " exists" << endl;
|
|
|
|
}else{
|
|
|
|
cout << "ofApp::downloadProject() trying to load " << fontFilepath << " but it does not exist." << endl;
|
|
|
|
}
|
|
|
|
file.open(fontFilepath);
|
|
|
|
ofBuffer buffy = file.readToBuffer();
|
|
|
|
zip.addBuffer(fontFilename, buffy.getData(), buffy.size());
|
|
|
|
}
|
2023-10-20 13:29:15 +02:00
|
|
|
ofDirectory userAudio(userAudioPath);
|
|
|
|
userAudio.sort();
|
|
|
|
userAudio.allowExt("mp3");
|
|
|
|
userAudio.allowExt("ogg");
|
|
|
|
userAudio.allowExt("wav");
|
|
|
|
userAudio.allowExt("webm");
|
|
|
|
userAudio.allowExt("m4a");
|
|
|
|
userAudio.listDir();
|
|
|
|
for(int i = 0; i < userAudio.size(); i++){
|
|
|
|
std::string audioFilename = userAudio.getName(i);
|
|
|
|
std::string audioFilepath = userAudioPath + "/" + audioFilename;
|
|
|
|
ofFile file = userAudio.getFile(i);
|
|
|
|
ofStringReplace(audioFilepath, "/idbfs/", "idbfs/");
|
|
|
|
if(of::filesystem::exists(audioFilepath)){
|
|
|
|
//cout << "huuurrayy " << audioFilepath << " exists" << endl;
|
|
|
|
}else{
|
|
|
|
cout << "ofApp::downloadProject() trying to load " << audioFilepath << " but it does not exist." << endl;
|
|
|
|
}
|
|
|
|
file.open(audioFilepath);
|
|
|
|
ofBuffer buffy = file.readToBuffer();
|
|
|
|
zip.addBuffer(audioFilename, buffy.getData(), buffy.size());
|
|
|
|
}
|
2023-09-24 18:39:52 +02:00
|
|
|
buffer = NULL;
|
|
|
|
buffer_size = 0;
|
|
|
|
zip.getOutputBuffer(&buffer, buffer_size);
|
|
|
|
zip.close();
|
|
|
|
ofEnableDataPath();
|
|
|
|
freshDownload.store(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void exit(){
|
|
|
|
free(buffer);
|
|
|
|
}
|
2024-02-29 16:32:49 +01:00
|
|
|
std::string projectName;
|
|
|
|
std::string projectJsonString;
|
|
|
|
std::string userFontsPath;
|
|
|
|
std::string userAudioPath;
|
|
|
|
std::string timestamp;
|
|
|
|
std::string filename;
|
2023-09-24 18:39:52 +02:00
|
|
|
char * buffer;
|
|
|
|
size_t buffer_size;
|
|
|
|
std::atomic <bool> freshDownload{false};
|
|
|
|
std::atomic <int> percent{0};
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
class ZipSaver : public ofThread {
|
|
|
|
public:
|
|
|
|
void setup(string projectName,
|
|
|
|
string framePath,
|
|
|
|
vector <string> recordedFrameNames){
|
|
|
|
this->projectName = projectName;
|
|
|
|
this->framePath = framePath;
|
|
|
|
this->recordedFrameNames = recordedFrameNames;
|
|
|
|
this->timestamp = ofGetTimestampString();
|
|
|
|
this->filename = projectName + "_frames_" + timestamp + ".zip";
|
|
|
|
}
|
|
|
|
|
|
|
|
void update(){
|
|
|
|
if(freshDownload.load()){
|
|
|
|
EM_ASM({
|
|
|
|
document.getElementById('export_progress_task').innerHTML = 'rendering';
|
|
|
|
let innerHTML = "|";
|
|
|
|
for(let i = 0; i < 100; i++){
|
|
|
|
innerHTML += "-";
|
|
|
|
}
|
|
|
|
innerHTML += "|";
|
|
|
|
let progress = document.getElementById("export_progress");
|
|
|
|
progress.innerHTML = innerHTML;
|
|
|
|
let progress_task = document.getElementById("export_progress_task");
|
|
|
|
progress_task.innerHTML = "idle";
|
|
|
|
});
|
|
|
|
emscripten_browser_file::download(filename.c_str(),
|
|
|
|
"application/zip",
|
|
|
|
buffer,
|
|
|
|
buffer_size);
|
|
|
|
freshDownload.store(false);
|
|
|
|
}else if(isThreadRunning()){
|
|
|
|
setProgress(percent.load());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void setProgress(int percent){
|
|
|
|
EM_ASM_INT({
|
|
|
|
let percent = $0;
|
|
|
|
document.getElementById('export_progress_task').innerHTML = 'rendering';
|
|
|
|
let innerHTML = "|";
|
|
|
|
const niceText = "zip ";
|
|
|
|
for(let i = 0; i < 100; i++){
|
|
|
|
if(i < percent){
|
|
|
|
innerHTML += niceText[i % niceText.length];
|
|
|
|
}else{
|
|
|
|
innerHTML += "-";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
innerHTML += "|";
|
|
|
|
let progress = document.getElementById("export_progress");
|
|
|
|
progress.innerHTML = innerHTML;
|
|
|
|
let progress_task = document.getElementById("export_progress_task");
|
|
|
|
progress_task.innerHTML = "creating zip file";
|
|
|
|
}, percent);
|
|
|
|
}
|
|
|
|
|
|
|
|
void threadedFunction(){
|
|
|
|
Zip zip(filename.c_str());
|
|
|
|
ofDisableDataPath();
|
|
|
|
int total = recordedFrameNames.size();
|
|
|
|
int i = 0;
|
|
|
|
for(const std::string & f: recordedFrameNames){
|
|
|
|
std::string filepath = framePath + "/" + f + ".png";
|
|
|
|
if(of::filesystem::exists(filepath)){
|
|
|
|
//cout << "huuurrayy " << filepath << " exists" << endl;
|
|
|
|
}else{
|
|
|
|
cout << "ofApp::downloadFramesAsZip() trying to load " << filepath << " but it does not exist." << endl;
|
|
|
|
}
|
|
|
|
ofImage image;
|
|
|
|
image.setUseTexture(false);
|
|
|
|
image.load(filepath);
|
|
|
|
ofBuffer buffer;
|
|
|
|
ofSaveImage(image.getPixels(), buffer, OF_IMAGE_FORMAT_PNG);
|
|
|
|
zip.addBuffer(f + ".png", buffer.getData(), buffer.size());
|
|
|
|
percent.store((float(i) / float(total)) * 100.0f);
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
buffer = NULL;
|
|
|
|
buffer_size = 0;
|
|
|
|
zip.getOutputBuffer(&buffer, buffer_size);
|
|
|
|
zip.close();
|
|
|
|
ofEnableDataPath();
|
|
|
|
freshDownload.store(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void exit(){
|
|
|
|
free(buffer);
|
|
|
|
}
|
|
|
|
string projectName;
|
|
|
|
string framePath;
|
|
|
|
string timestamp;
|
|
|
|
string filename;
|
|
|
|
std::vector <string> recordedFrameNames;
|
|
|
|
char * buffer;
|
|
|
|
size_t buffer_size;
|
|
|
|
std::atomic <bool> freshDownload{false};
|
|
|
|
std::atomic <int> percent{0};
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
class ZipUnpacker : public ofThread {
|
|
|
|
public:
|
|
|
|
void setup(){
|
|
|
|
this->timestamp = ofGetTimestampString();
|
|
|
|
}
|
|
|
|
|
|
|
|
void update(){
|
|
|
|
if(freshUpload.load()){
|
|
|
|
freshUpload.store(false);
|
|
|
|
}else if(isThreadRunning()){
|
|
|
|
//setProgress(percent.load());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void setProgress(int percent){
|
|
|
|
EM_ASM_INT({
|
|
|
|
let percent = $0;
|
|
|
|
document.getElementById('export_progress_task').innerHTML = 'uploading and unpacking';
|
|
|
|
let innerHTML = "|";
|
|
|
|
const niceText = "zip ";
|
|
|
|
for(let i = 0; i < 100; i++){
|
|
|
|
if(i < percent){
|
|
|
|
innerHTML += niceText[i % niceText.length];
|
|
|
|
}else{
|
|
|
|
innerHTML += "-";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
innerHTML += "|";
|
|
|
|
let progress = document.getElementById("import_progress");
|
|
|
|
progress.innerHTML = innerHTML;
|
|
|
|
let progress_task = document.getElementById("import_progress_task");
|
|
|
|
progress_task.innerHTML = "creating zip file";
|
|
|
|
}, percent);
|
|
|
|
}
|
|
|
|
|
|
|
|
void threadedFunction(){
|
|
|
|
ofDisableDataPath();
|
|
|
|
}
|
|
|
|
|
|
|
|
void exit(){
|
|
|
|
free(buffer);
|
|
|
|
}
|
|
|
|
string timestamp;
|
|
|
|
char * buffer;
|
|
|
|
size_t buffer_size;
|
|
|
|
std::atomic <bool> freshUpload{false};
|
|
|
|
std::atomic <int> percent{0};
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
class ofApp : public ofBaseApp {
|
|
|
|
public:
|
|
|
|
|
|
|
|
void setup() override;
|
|
|
|
void update() override;
|
|
|
|
void draw() override;
|
|
|
|
|
|
|
|
void drawGrid();
|
|
|
|
void setPlaying(bool playing);
|
|
|
|
|
|
|
|
void keyPressed(int key) override;
|
|
|
|
void keyReleased(int key) override;
|
|
|
|
void mouseMoved(int x, int y) override;
|
|
|
|
void mouseDragged(int x, int y, int button) override;
|
|
|
|
void mousePressed(int x, int y, int button) override;
|
|
|
|
void mouseReleased(int x, int y, int button) override;
|
|
|
|
void mouseEntered(int x, int y) override;
|
|
|
|
void mouseExited(int x, int y) override;
|
|
|
|
void mouseScrolled(ofMouseEventArgs & mouse) override;
|
|
|
|
void mouseScrolled(int x, int y, float scrollX, float scrollY) override;
|
|
|
|
void windowResized(int w, int h) override;
|
|
|
|
void dragEvent(ofDragInfo dragInfo) override;
|
|
|
|
void gotMessage(ofMessage msg) override;
|
|
|
|
void saveFrame(const string & filename,
|
|
|
|
const ofFbo & _fbo);
|
|
|
|
#ifdef TARGET_EMSCRIPTEN
|
|
|
|
void downloadFrame(const string & filename);
|
|
|
|
void downloadFramesAsZip(const string & projectName = "project");
|
|
|
|
static void downloadImage(const string & filename,
|
|
|
|
const ofImage & image);
|
|
|
|
static void downloadFboAsImage(const string & filename,
|
|
|
|
const ofFbo & _fbo);
|
|
|
|
static void downloadPixelsAsImage(const string & filename,
|
|
|
|
const ofPixels & image);
|
|
|
|
static void downloadJson(const string & filename,
|
|
|
|
const nlohmann::json & json);
|
|
|
|
void downloadProject(const string & projectName,
|
|
|
|
const string & projectJsonString);
|
|
|
|
#endif
|
|
|
|
void exit() override;
|
|
|
|
|
|
|
|
ofxVariableLab::LayerComposition layerComposition;
|
|
|
|
|
|
|
|
ofCamera cam;
|
|
|
|
ofFboSettings fboSettings;
|
|
|
|
ofFbo fbo;
|
|
|
|
ofEasyCam observer;
|
|
|
|
bool observing = false;
|
|
|
|
bool playing = true;
|
|
|
|
bool rendering = false;
|
|
|
|
bool renderNextFrame = false;
|
|
|
|
int guessedFrameCount = 30;
|
|
|
|
double timelineLength_seconds = 0;
|
|
|
|
int currentFrame = 0;
|
|
|
|
double theatrePosition = 0;
|
|
|
|
double timeScale = 1.0;
|
|
|
|
|
|
|
|
ofImage image42;
|
|
|
|
ofImage image420;
|
|
|
|
|
|
|
|
AppSettings settings;
|
|
|
|
|
|
|
|
ofTrueTypeFont ttf;
|
|
|
|
Artboard artboard;
|
|
|
|
|
|
|
|
std::set <ofKey> inputPressed;
|
|
|
|
|
|
|
|
// EXPORTER
|
|
|
|
std::vector <std::string> recordedFrameNames;
|
|
|
|
ZipSaver zipSaver;
|
|
|
|
ZipProjectSaver projectZipSaver;
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|