#include "ofApp.h"
#include "generator-config.h"
#include "ofFileUtils.h"
#include "ofGraphics.h"
#include "ofUtils.h"
#include "save-bmp.h"

//--------------------------------------------------------------
void ofApp::setup(){
    string fontName = "RobotoFlex.ttf";
    fontPath = "data/fonts/" + fontName;

    int dimension = 64;
    int width = dimension;
    int height = dimension;

    FreetypeHandle * ft = initializeFreetype();
    if(ft){
        const char * fontPath_c_str = fontPath.c_str();
        FontHandle * font = loadFont(ft, fontPath_c_str);
        if(font){
            Shape shape;
            if(loadGlyph(shape, font, 'a')){
                shape.normalize();
                Shape::Bounds bounds = shape.getBounds();

                double pxRange = 2;
                Vector2 translate;
                Vector2 scale = 1;
                double range = 1;
                double avgScale = .5 * (scale.x + scale.y);

                // Auto-frame
                double l = bounds.l, b = bounds.b, r = bounds.r, t = bounds.t;
                Vector2 frame(width, height);
                double m = .5 + (double)0;
                frame -= 2 * m * pxRange;
                if(l >= r || b >= t){
                    l = 0, b = 0, r = 1, t = 1;
                }
                if(frame.x <= 0 || frame.y <= 0){
                    ofLogError("Cannot fit the specified pixel range.");
                }
                Vector2 dims(r - l, t - b);
                if(dims.x * frame.y < dims.y * frame.x){
                    translate.set(.5 * (frame.x / frame.y * dims.y - dims.x) - l, -b);
                    scale = avgScale = frame.y / dims.y;
                }else{
                    translate.set(-l, .5 * (frame.y / frame.x * dims.x - dims.y) - b);
                    scale = avgScale = frame.x / dims.x;
                }
                translate += m * pxRange / scale;
                range = pxRange / std::min(scale.x, scale.y);

                //                      max. angle
                edgeColoringSimple(shape, 3.0);
                //           image width, height
                Bitmap <float, 3> msdf(dimension, dimension);
                msdfgen::Projection projection(scale, translate);
                msdfgen::MSDFGeneratorConfig generatorConfig;
                generateMSDF(msdf, shape, projection, range, generatorConfig);

                ofxMsdfgen::toOfImage(msdf, image);

                msdfgen::saveBmp(msdf, "data/outpurt.bmp");

            }
            destroyFont(font);
        }
        deinitializeFreetype(ft);
    }

    #ifdef TARGET_EMSCRIPTEN
        shader.load("ofxMsdfgen/shaders/simple/ES3/shader");
    #else
        shader.load("ofxMsdfgen/shaders/simple/GL3/shader");
    #endif
}

//--------------------------------------------------------------
void ofApp::update(){

}

//--------------------------------------------------------------
void ofApp::draw(){
    ofBackground(ofColor::lightGreen);

    shader.begin();
    float pxRange = ofMap(sin(ofGetElapsedTimeMillis() * 0.001),
                          -1, 1,
                          1, 100);
    shader.setUniform1f("pxRange", pxRange);
    shader.setUniformTexture("msdf", image.getTexture(), 0);
    shader.setUniform4f("fontColor", ofFloatColor::white);

    image.draw(0, 0, ofGetHeight(), ofGetHeight());

    shader.end();
    ofPushStyle();
    ofSetColor(ofColor::purple);
    ofDrawBitmapString("pxRange: " + ofToString(pxRange), 20, 20);
    ofPopStyle();

    image.draw(0, 0, 64 * 4, 64 * 4);
}

//--------------------------------------------------------------
void ofApp::keyPressed(int key){
    if(key == 's'){
        ofSaveImage(image, "output.png");
        ofSaveImage(image, "output.jpg");
        image.save("outerput.png");
    }
}

//--------------------------------------------------------------
void ofApp::keyReleased(int key){

}

//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y){

}

//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mouseEntered(int x, int y){

}

//--------------------------------------------------------------
void ofApp::mouseExited(int x, int y){

}

//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){

}

//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){

}

//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){

}
