From 6c7372ed907656639af46e66041c97c73fdcd48a Mon Sep 17 00:00:00 2001 From: "Charles J. Cliffe" Date: Mon, 8 Dec 2014 02:16:06 -0500 Subject: [PATCH] Font loader experiment --- src/CubicSDR.h | 2 +- src/util/GLFont.cpp | 376 ++++++++++++++++++++++++++++++++ src/util/GLFont.h | 79 +++++++ src/visual/PrimaryGLContext.cpp | 10 + src/visual/PrimaryGLContext.h | 4 + src/visual/SpectrumContext.cpp | 3 + 6 files changed, 473 insertions(+), 1 deletion(-) create mode 100644 src/util/GLFont.cpp create mode 100644 src/util/GLFont.h diff --git a/src/CubicSDR.h b/src/CubicSDR.h index 29a2026..12f6b54 100644 --- a/src/CubicSDR.h +++ b/src/CubicSDR.h @@ -15,7 +15,7 @@ #include "AudioThread.h" #include "DemodulatorMgr.h" -#define NUM_DEMODULATORS 3 +#define NUM_DEMODULATORS 1 class CubicSDR: public wxApp { public: diff --git a/src/util/GLFont.cpp b/src/util/GLFont.cpp new file mode 100644 index 0000000..0a3cb15 --- /dev/null +++ b/src/util/GLFont.cpp @@ -0,0 +1,376 @@ +#include "GLFont.h" + +#include +#include +#include + +GLFontChar::GLFontChar() : + id(0), x(0), y(0), width(0), height(0), xadvance(0), xoffset(0), yoffset(0), index(0) { + +} + +GLFontChar::~GLFontChar() { + +} + +void GLFontChar::setId(int idval) { + id = idval; +} + +int GLFontChar::getId() { + return id; +} + +void GLFontChar::setXOffset(int xofs) { + xoffset = xofs; +} + +int GLFontChar::getXOffset() { + return xoffset; +} + +void GLFontChar::setYOffset(int yofs) { + yoffset = yofs; +} + +int GLFontChar::getYOffset() { + return yoffset; +} + +void GLFontChar::setX(int xpos) { + x = xpos; +} + +int GLFontChar::getX() { + return x; +} + +void GLFontChar::setY(int ypos) { + y = ypos; +} + +int GLFontChar::getY() { + return y; +} + +void GLFontChar::setWidth(int w) { + width = w; + if (width && height) { + aspect = (float) width / (float) height; + } +} + +int GLFontChar::getWidth() { + return width; +} + +void GLFontChar::setHeight(int h) { + height = h; + if (width && height) { + aspect = (float) width / (float) height; + } +} + +int GLFontChar::getHeight() { + return height; +} + +void GLFontChar::setXAdvance(int xadv) { + xadvance = xadv; +} + +int GLFontChar::getXAdvance() { + return xadvance; +} + +float GLFontChar::getAspect() { + return aspect; +} + +void GLFontChar::setIndex(unsigned int idx) { + index = idx; +} + +int GLFontChar::getIndex() { + return index; +} + +GLFont::GLFont() : + numCharacters(0), imageHeight(0), imageWidth(0), base(0), lineHeight(0), texId(0) { + +} + +GLFont::~GLFont() { + +} + +std::string GLFont::nextParam(std::istringstream &str) { + std::string param_str; + + str >> param_str; + + if (param_str.find('"') != std::string::npos) { + std::string rest; + while (!str.eof() && (std::count(param_str.begin(), param_str.end(), '"') % 2)) { + str >> rest; + param_str.append(" " + rest); + } + } + + return param_str; +} + +std::string GLFont::getParamKey(std::string param_str) { + std::string keyName; + + int eqpos = param_str.find("="); + + if (eqpos != std::string::npos) { + keyName = param_str.substr(0, eqpos); + } + + return keyName; +} + +std::string GLFont::getParamValue(std::string param_str) { + std::string value; + + int eqpos = param_str.find("="); + + if (eqpos != std::string::npos) { + value = param_str.substr(eqpos + 1); + } + + if (value[0] == '"' && value[value.length() - 1] == '"') { + value = value.substr(1, value.length() - 2); + } + + return value; +} + +void GLFont::loadFont(std::string fontFile) { + fontFileSource = fontFile; + + std::ifstream input; + input.open(fontFileSource.c_str(), std::ios::in); + + std::string op; + + while (!input.eof()) { + input >> op; + + if (op == "info") { + std::string info_param_str; + getline(input, info_param_str); + std::istringstream info_param(info_param_str); + + while (!info_param.eof()) { + std::string param = nextParam(info_param); + + std::string paramKey = getParamKey(param); + std::string paramValue = getParamValue(param); + + if (paramKey == "face") { + fontName = paramValue; + } + +// std::cout << "[" << paramKey << "] = '" << paramValue << "'" << std::endl; + } + } else if (op == "common") { + std::string common_param_str; + getline(input, common_param_str); + std::istringstream common_param(common_param_str); + + while (!common_param.eof()) { + std::string param = nextParam(common_param); + + std::string paramKey = getParamKey(param); + std::istringstream paramValue(getParamValue(param)); + + if (paramKey == "lineHeight") { + paramValue >> lineHeight; + } else if (paramKey == "base") { + paramValue >> base; + } else if (paramKey == "scaleW") { + paramValue >> imageWidth; + } else if (paramKey == "scaleH") { + paramValue >> imageHeight; + } +// std::cout << "[" << paramKey << "] = '" << getParamValue(param) << "'" << std::endl; + } + } else if (op == "page") { + std::string page_param_str; + getline(input, page_param_str); + std::istringstream page_param(page_param_str); + + while (!page_param.eof()) { + std::string param = nextParam(page_param); + + std::string paramKey = getParamKey(param); + std::string paramValue = getParamValue(param); + + if (paramKey == "file") { + imageFile = paramValue; + } +// std::cout << "[" << paramKey << "] = '" << paramValue << "'" << std::endl; + } + + } else if (op == "char") { + std::string char_param_str; + getline(input, char_param_str); + std::istringstream char_param(char_param_str); + + GLFontChar *newChar = new GLFontChar; + + while (!char_param.eof()) { + std::string param = nextParam(char_param); + + std::string paramKey = getParamKey(param); + std::istringstream paramValue(getParamValue(param)); + + int val; + + if (paramKey == "id") { + paramValue >> val; + newChar->setId(val); + } else if (paramKey == "x") { + paramValue >> val; + newChar->setX(val); + } else if (paramKey == "y") { + paramValue >> val; + newChar->setY(val); + } else if (paramKey == "width") { + paramValue >> val; + newChar->setWidth(val); + } else if (paramKey == "height") { + paramValue >> val; + newChar->setHeight(val); + } else if (paramKey == "xoffset") { + paramValue >> val; + newChar->setXOffset(val); + } else if (paramKey == "yoffset") { + paramValue >> val; + newChar->setYOffset(val); + } else if (paramKey == "xadvance") { + paramValue >> val; + newChar->setXAdvance(val); + } + +// std::cout << "[" << paramKey << "] = '" << getParamValue(param) << "'" << std::endl; + } + + characters[newChar->getId()] = newChar; + + } else { + std::string dummy; + getline(input, dummy); + } + } + + if (imageFile != "" && imageWidth && imageHeight && characters.size()) { + + // Load file and decode image. + std::vector image; + unsigned int imgWidth = imageWidth, imgHeight = imageHeight; + unsigned error = lodepng::decode(image, imgWidth, imgHeight, imageFile); + + glGenTextures(1, &texId); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, texId); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, 4, imageWidth, imageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, &image[0]); + glDisable(GL_TEXTURE_2D); + + std::map::iterator char_i; + + gl_vertices.resize(characters.size() * 8); // one quad per char + gl_uv.resize(characters.size() * 8); + + unsigned int ofs = 0; + for (char_i = characters.begin(); char_i != characters.end(); char_i++) { + int charId = (*char_i).first; + GLFontChar *fchar = (*char_i).second; + + float faspect = fchar->getAspect()/8.0; + + float uv_xpos = (float) fchar->getX() / (float) imageWidth; + float uv_ypos = ((float) fchar->getY() / (float) imageHeight); + float uv_xofs = (float) fchar->getWidth() / (float) imageWidth; + float uv_yofs = ((float) fchar->getHeight() / (float) imageHeight); + + gl_vertices[ofs] = 0; + gl_vertices[ofs + 1] = 0; + gl_uv[ofs] = uv_xpos; + gl_uv[ofs + 1] = uv_ypos + uv_yofs; +// gl_uv[ofs] = 0; +// gl_uv[ofs + 1] = 1; + + gl_vertices[ofs + 2] = faspect; + gl_vertices[ofs + 3] = 0; + gl_uv[ofs + 2] = uv_xpos + uv_xofs; + gl_uv[ofs + 3] = uv_ypos + uv_yofs; +// gl_uv[ofs + 2] = 1; +// gl_uv[ofs + 3] = 1; + + gl_vertices[ofs + 4] = faspect; + gl_vertices[ofs + 5] = 1; + gl_uv[ofs + 4] = uv_xpos + uv_xofs; + gl_uv[ofs + 5] = uv_ypos; +// gl_uv[ofs + 4] = 1; +// gl_uv[ofs + 5] = 0; + + gl_vertices[ofs + 6] = 0; + gl_vertices[ofs + 7] = 1; + gl_uv[ofs + 6] = uv_xpos; + gl_uv[ofs + 7] = uv_ypos; +// gl_uv[ofs + 6] = 0; +// gl_uv[ofs + 7] = 0; + + fchar->setIndex(ofs); + + ofs += 8; + } + + std::cout << "Loaded font '" << fontName << "' from '" << fontFileSource << "', parsed " << characters.size() << " characters." << std::endl; + } else { + std::cout << "Error loading font file " << fontFileSource << std::endl; + } + + input.close(); +} + +void GLFont::drawString(std::string str, float xpos, float ypos, float size) { + + glPushMatrix(); + glTranslatef(xpos, ypos, 0.0f); + glScalef(size, size, 1.0f); + glPushMatrix(); + + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, texId); + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glVertexPointer(2, GL_FLOAT, 0, &gl_vertices[0]); + glTexCoordPointer(2, GL_FLOAT, 0, &gl_uv[0]); + + for (int i = 0, iMax = str.length(); i < iMax; i++) { + int charId = str.at(i); + + if (characters.find(charId) == characters.end()) { + continue; + } + + GLFontChar *fchar = characters[charId]; + + glDrawArrays(GL_QUADS, fchar->getIndex()/2, 4); + glTranslatef(fchar->getAspect()/8.0,0.0,0.0); + } + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glPopMatrix(); + glPopMatrix(); +} + diff --git a/src/util/GLFont.h b/src/util/GLFont.h new file mode 100644 index 0000000..7a648a3 --- /dev/null +++ b/src/util/GLFont.h @@ -0,0 +1,79 @@ +#pragma once + +#include +#include +#include +#include "lodepng.h" +#include "wx/glcanvas.h" + + +class GLFontChar { +public: + GLFontChar(); + ~GLFontChar(); + + void setId(int idval); + int getId(); + + void setXOffset(int xofs); + int getXOffset(); + + void setYOffset(int yofs); + int getYOffset(); + + void setX(int xpos); + int getX(); + + void setY(int ypos); + int getY(); + + void setWidth(int w); + int getWidth(); + + void setHeight(int h); + int getHeight(); + + void setXAdvance(int xadv); + int getXAdvance(); + + float getAspect(); + + void setIndex(unsigned int idx); + int getIndex(); + +private: + int id; + int x, y, width, height; + int xoffset, yoffset; + int xadvance; + float aspect; + int index; +}; + +class GLFont { +public: + GLFont(); + ~GLFont(); + void loadFont(std::string fontFile); + void drawString(std::string str, float xpos, float ypos, float height); + +private: + std::string nextParam(std::istringstream &str); + std::string getParamKey(std::string param_str); + std::string getParamValue(std::string param_str); + + int numCharacters; + int lineHeight; + int base; + int imageWidth, imageHeight; + + std::map characters; + + std::vector gl_vertices; + std::vector gl_uv; + + std::string fontName; + std::string imageFile; + std::string fontFileSource; + GLuint texId; +}; diff --git a/src/visual/PrimaryGLContext.cpp b/src/visual/PrimaryGLContext.cpp index 6cde9a7..151dce0 100644 --- a/src/visual/PrimaryGLContext.cpp +++ b/src/visual/PrimaryGLContext.cpp @@ -15,6 +15,8 @@ #include "AppFrame.h" #include +GLFont *PrimaryGLContext::font = NULL; + wxString PrimaryGLContext::glGetwxString(GLenum name) { const GLubyte *v = glGetString(name); if (v == 0) { @@ -56,3 +58,11 @@ PrimaryGLContext::PrimaryGLContext(wxGLCanvas *canvas, wxGLContext *sharedContex CheckGLError(); } +GLFont *PrimaryGLContext::getFont() { + if (font == NULL) { + font = new GLFont(); + font->loadFont("vera_sans_mono.fnt"); + } + + return font; +} diff --git a/src/visual/PrimaryGLContext.h b/src/visual/PrimaryGLContext.h index 5a92605..c9a0f91 100644 --- a/src/visual/PrimaryGLContext.h +++ b/src/visual/PrimaryGLContext.h @@ -7,6 +7,7 @@ #include #include "CubicSDRDefs.h" +#include "GLFont.h" class PrimaryGLContext: public wxGLContext { public: @@ -15,5 +16,8 @@ public: static wxString glGetwxString(GLenum name); static void CheckGLError(); + static GLFont *getFont(); + private: + static GLFont *font; }; diff --git a/src/visual/SpectrumContext.cpp b/src/visual/SpectrumContext.cpp index 22f243c..d3c1990 100644 --- a/src/visual/SpectrumContext.cpp +++ b/src/visual/SpectrumContext.cpp @@ -32,5 +32,8 @@ void SpectrumContext::Draw(std::vector &points) { glDisableClientState(GL_VERTEX_ARRAY); glPopMatrix(); } + + getFont()->drawString("Testing",0.0,0.0,0.7); + CheckGLError(); }