kick
/Users/morten/Programmering/cpp/kick/src/kick/2d/label.cpp
00001 //
00002 // Created by morten on 30/06/14.
00003 //
00004 
00005 #include "label.h"
00006 #include <iostream>
00007 #include "kick/mesh/mesh.h"
00008 #include "glm/gtx/string_cast.hpp"
00009 
00010 using namespace std;
00011 using namespace glm;
00012 
00013 namespace kick {
00014 
00015     Label::Label(GameObject *gameObject, std::shared_ptr<Canvas> canvas)
00016             : Component2D(gameObject, canvas),
00017               mBounds{vec2{0,0},vec2{0,0}} {
00018         mMesh = new Mesh();
00019         mMeshData = make_shared<MeshData>();
00020         mMaterial = new Material();
00021         mMesh->setMeshData(mMeshData);
00022     }
00023 
00024     std::string const &Label::text() const {
00025         return mText;
00026     }
00027 
00028     void Label::setText(std::string const &text) {
00029         Label::mText = text;
00030         updateVertexBuffer();
00031     }
00032 
00033     void Label::render(EngineUniforms *engineUniforms) {
00034         if (!mFont) return;
00035         auto shader = mMaterial->shader();
00036         assert(shader);
00037         mMesh->bind(shader.get());
00038         shader->bind_uniforms(mMaterial, engineUniforms, transform().get());
00039         mMesh->render(0);
00040     }
00041 
00042     void Label::setFont(std::shared_ptr<Font>& font) {
00043         if (!font->initialized()){
00044             font->loadFntFile();
00045         }
00046         Label::mFont = font;
00047         auto setupFont = [&](Font* f){
00048             mMaterial->setShader(f->getShader());
00049             mMaterial->setUniform("mainTexture", f->texture());
00050         };
00051         setupFont(font.get());
00052         mEventListener = font->fontListener.createListener(setupFont);
00053         updateVertexBuffer();
00054     }
00055 
00056     std::shared_ptr<Font> Label::font() const {
00057         return mFont;
00058     }
00059 
00060     void Label::updateVertexBuffer() {
00061         if (!mFont || mText.length() ==0) {
00062             mMeshData->setSubmesh(0, {}, MeshType::Triangles);
00063             mMesh->setMeshData(mMeshData);
00064             return;
00065         }
00066         vector<vec3> position;
00067         vector<vec2> textureCoords;
00068         vector<GLushort> indices;
00069         vec2 caret{-mFont->width(mText) * mAnchor.x, -mFont->height() * mAnchor.y};
00070 
00071         if (mText.length()>0){ // if first char is x-offset, then undo offset to fix horizontal alignment
00072             const FontChar fc = mFont->getChar(mText[0]);
00073             caret.x -= fc.xoffset;
00074         }
00075 
00076         mBounds.max = vec2{-FLT_MAX};
00077         mBounds.min = vec2{FLT_MAX};
00078         GLushort vertexCount = 0;
00079         int lastChar = -1;
00080         for (unsigned short i=0;i< mText.length();i++){
00081             const FontChar fc = mFont->getChar(mText[i]);
00082 
00083             caret.x += mFont->getKerning(lastChar, mText[i]);
00084             bool visibleCharacter = fc.width  > 0;
00085             if (visibleCharacter) {
00086                 vec2 basePoint = caret + vec2{fc.xoffset, mFont->height()-fc.height-fc.yoffset};
00087                 position.push_back(vec3{basePoint,0});
00088                 position.push_back(vec3{basePoint+vec2{fc.width,0},0});
00089                 position.push_back(vec3{basePoint+vec2{fc.width,fc.height},0});
00090                 position.push_back(vec3{basePoint+vec2{0       ,fc.height},0});
00091 
00092                 mBounds.min = glm::min(mBounds.min, basePoint);
00093                 mBounds.max = glm::max(mBounds.max, (vec2)position[position.size()-2]);
00094 
00095                 vec2 scale{1.0f / mFont->scaleW(), 1.0f / mFont->scaleH()};
00096 
00097                 textureCoords.push_back(vec2{fc.x         , mFont->scaleH()-fc.y-fc.height}*scale);
00098                 textureCoords.push_back(vec2{fc.x+fc.width, mFont->scaleH()-fc.y-fc.height}*scale);
00099                 textureCoords.push_back(vec2{fc.x+fc.width, mFont->scaleH()-fc.y}*scale);
00100                 textureCoords.push_back(vec2{fc.x         , mFont->scaleH()-fc.y}*scale);
00101 
00102                 // push two triangles
00103                 indices.push_back(vertexCount);
00104                 indices.push_back(vertexCount + (GLushort)1);
00105                 indices.push_back(vertexCount + (GLushort)2);
00106                 indices.push_back(vertexCount + (GLushort)2);
00107                 indices.push_back(vertexCount + (GLushort)3);
00108                 indices.push_back(vertexCount);
00109 
00110                 vertexCount += 4;
00111             }
00112             caret.x += fc.xadvance;
00113             lastChar = mText[i];
00114         }
00115 
00116         mMeshData->setPosition(position);
00117         mMeshData->setTexCoord0(textureCoords);
00118         mMeshData->setSubmesh(0,indices, MeshType::Triangles);
00119         mMesh->setMeshData(mMeshData);
00120     }
00121 
00122     Bounds2 Label::bounds() const {
00123         return mBounds;
00124     }
00125 
00126     Material *Label::material() const {
00127         return mMaterial;
00128     }
00129 
00130     void Label::setMaterial(Material *material) {
00131         assert(material);
00132         Label::mMaterial = material;
00133         material->setShader(mFont->getShader());
00134         material->setUniform("mainTexture", mFont->texture());
00135     }
00136 
00137     int Label::renderOrder() {
00138         return mMaterial->renderOrder();
00139     }
00140 
00141     void Label::setAnchor(glm::vec2 anchor) {
00142         if (anchor != Label::mAnchor){
00143             Label::mAnchor = anchor;
00144             updateVertexBuffer();
00145         }
00146     }
00147 
00148     glm::vec2 Label::anchor() const {
00149         return mAnchor;
00150     }
00151 
00152     Shader *Label::shader() const {
00153         if (mMaterial){
00154             return mMaterial->shader().get();
00155         }
00156         return nullptr;
00157     }
00158 
00159     void Label::setBounds(Bounds2 bounds) {
00160         cout << "Implement" << endl;
00161     }
00162 }
 All Classes Functions Variables