diff --git a/src/panel/SpectrumPanel.cpp b/src/panel/SpectrumPanel.cpp index 5fcf2f6..048c858 100644 --- a/src/panel/SpectrumPanel.cpp +++ b/src/panel/SpectrumPanel.cpp @@ -254,7 +254,7 @@ void SpectrumPanel::drawPanelContents() { glColor4f(ThemeMgr::mgr.currentTheme->text.r, ThemeMgr::mgr.currentTheme->text.g, ThemeMgr::mgr.currentTheme->text.b,1.0); - GLFont::getFont(fontEnumSize).drawString(label.str(), m, hPos, fontSize, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER); + GLFont::getFont(fontEnumSize).drawString(label.str(), m, hPos, fontSize, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER, 0, 0, true); label.str(std::string()); diff --git a/src/util/GLFont.cpp b/src/util/GLFont.cpp index 33cea52..0c7ebda 100644 --- a/src/util/GLFont.cpp +++ b/src/util/GLFont.cpp @@ -3,6 +3,8 @@ #include #include #include +#include "cubic_math.h" + #ifdef _MSC_VER #include @@ -27,6 +29,9 @@ static std::string getExePath(void) #define RES_FOLDER "" #endif +GLFontStringCache::GLFontStringCache() { + gc = 0; +} GLFont GLFont::fonts[GLFONT_MAX]; @@ -122,7 +127,7 @@ int GLFontChar::getIndex() { } GLFont::GLFont() : - lineHeight(0), base(0), imageWidth(0), imageHeight(0), loaded(false), texId(0) { + lineHeight(0), base(0), imageWidth(0), imageHeight(0), loaded(false), texId(0), gcCounter(0) { } @@ -423,11 +428,11 @@ float GLFont::getStringWidth(std::string str, float size, float viewAspect) { return width; } -void GLFont::drawString(std::string str, float xpos, float ypos, int pxHeight, Align hAlign, Align vAlign, int vpx, int vpy) { - - +// Draw string, immediate +void GLFont::drawString(std::string str, float xpos, float ypos, int pxHeight, Align hAlign, Align vAlign, int vpx, int vpy, bool cacheable) { + pxHeight *= 2; - + if (!vpx || !vpy) { GLint vp[4]; glGetIntegerv( GL_VIEWPORT, vp); @@ -435,6 +440,49 @@ void GLFont::drawString(std::string str, float xpos, float ypos, int pxHeight, A vpy = vp[3]; } + if (cacheable) { + gcCounter++; + + std::lock_guard lock(cache_busy); + + if (gcCounter > 200) { + doCacheGC(); + gcCounter = 0; + } + + GLFontStringCache *fc = nullptr; + + std::map > > >::iterator i1; + std::map > >::iterator i2; + std::map >::iterator i3; + std::map::iterator i4; + + i1 = stringCache.find(vpx); + if (i1 != stringCache.end()) { + i2 = i1->second.find(vpy); + if (i2 != i1->second.end()) { + i3 = i2->second.find(pxHeight); + if (i3 != i2->second.end()) { + i4 = i3->second.find(str); + if (i4 != i3->second.end()) { + fc = i4->second; + fc->gc = 0; + } + } + } + } + + if (fc == nullptr) { +// std::cout << "cache miss" << std::endl; + fc = cacheString(str, pxHeight, vpx, vpy); + stringCache[vpx][vpy][pxHeight][str] = fc; + } + + drawCacheString(fc, xpos, ypos, hAlign, vAlign); + + return; + } + float size = (float) pxHeight / (float) vpy; float viewAspect = (float) vpx / (float) vpy; float msgWidth = getStringWidth(str, size, viewAspect); @@ -499,6 +547,9 @@ void GLFont::drawString(std::string str, float xpos, float ypos, int pxHeight, A glTranslatef(fchar->getAspect() + advx, 0.0, 0.0); } + glVertexPointer(2, GL_FLOAT, 0, nullptr); + glTexCoordPointer(2, GL_FLOAT, 0, nullptr); + glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glPopMatrix(); @@ -508,6 +559,157 @@ void GLFont::drawString(std::string str, float xpos, float ypos, int pxHeight, A glDisable(GL_TEXTURE_2D); } +// Draw cached GLFontCacheString +void GLFont::drawCacheString(GLFontStringCache *fc, float xpos, float ypos, Align hAlign, Align vAlign) { + + float size = (float) fc->pxHeight / (float) fc->vpy; + + glPushMatrix(); + glTranslatef(xpos, ypos, 0.0f); + + switch (vAlign) { + case GLFONT_ALIGN_TOP: + glTranslatef(0.0, -size, 0.0); + break; + case GLFONT_ALIGN_CENTER: + glTranslatef(0.0, -size/2.0, 0.0); + break; + default: + break; + } + + switch (hAlign) { + case GLFONT_ALIGN_RIGHT: + glTranslatef(-fc->msgWidth, 0.0, 0.0); + break; + case GLFONT_ALIGN_CENTER: + glTranslatef(-fc->msgWidth / 2.0, 0.0, 0.0); + break; + default: + break; + } + + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, texId); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glVertexPointer(2, GL_FLOAT, 0, &fc->gl_vertices[0]); + glTexCoordPointer(2, GL_FLOAT, 0, &fc->gl_uv[0]); + + glDrawArrays(GL_QUADS, 0, 4 * fc->drawlen); + + glVertexPointer(2, GL_FLOAT, 0, nullptr); + glTexCoordPointer(2, GL_FLOAT, 0, nullptr); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + glPopMatrix(); + + glDisable(GL_BLEND); + glDisable(GL_TEXTURE_2D); +} + +// Compile optimized GLFontCacheString +GLFontStringCache *GLFont::cacheString(std::string str, int pxHeight, int vpx, int vpy) { + GLFontStringCache *fc = new GLFontStringCache; + + fc->pxHeight = pxHeight; + fc->vpx = vpx; + fc->vpy = vpy; + + float size = (float) pxHeight / (float) vpy; + float viewAspect = (float) vpx / (float) vpy; + + fc->msgWidth = getStringWidth(str, size, viewAspect); + + int nChar = 0; + for (int i = 0, iMax = str.length(); i < iMax; i++) { + int charId = str.at(i); + + if (characters.find(charId) == characters.end()) { + continue; + } + nChar++; + } + + fc->drawlen = nChar; + fc->gl_vertices.resize(nChar*8); + fc->gl_uv.resize(nChar*8); + + + CubicVR::mat4 trans = CubicVR::mat4::scale(size / viewAspect, size, 1.0f); + + int c = 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]; + + float ofsx = (float) fchar->getXOffset() / (float) imageWidth; + float advx = (float) fchar->getXAdvance() / (float) imageWidth; + + if (charId == 32) { + advx = characters['_']->getAspect(); + } + + // freeze transform to buffer + trans *= CubicVR::mat4::translate(ofsx, 0.0, 0.0); + int charIdx = fchar->getIndex(); + for (int j = 0; j < 8; j+=2) { + CubicVR::vec3 pt(gl_vertices[charIdx + j],gl_vertices[charIdx + j + 1], 0.0); + pt = CubicVR::mat4::multiply(trans, pt, true); + fc->gl_vertices[c * 8 + j] = pt[0]; + fc->gl_vertices[c * 8 + j + 1] = pt[1]; + fc->gl_uv[c * 8 + j] = gl_uv[charIdx + j]; + fc->gl_uv[c * 8 + j + 1] = gl_uv[charIdx + j + 1]; + } + trans *= CubicVR::mat4::translate(fchar->getAspect() + advx, 0.0, 0.0); + c++; + } + + return fc; +} + +void GLFont::doCacheGC() { + std::map > > >::iterator i1; + std::map > >::iterator i2; + std::map >::iterator i3; + std::map::iterator i4; + + std::vector::iterator> removals; + std::vector::iterator>::iterator removals_i; + + for (i1 = stringCache.begin(); i1 != stringCache.end(); i1++) { + for (i2 = i1->second.begin(); i2 != i1->second.end(); i2++) { + for (i3 = i2->second.begin(); i3 != i2->second.end(); i3++) { + for (i4 = i3->second.begin(); i4 != i3->second.end(); i4++) { + i4->second->gc--; + if (i4->second->gc < -10) { + removals.push_back(i4); + } + } + } + } + } + + if (removals.size()) { + for (removals_i = removals.begin(); removals_i != removals.end(); removals_i++) { +// std::cout << "gc'd " << (*removals_i)->first << std::endl; + GLFontStringCache *fc = (*removals_i)->second; + stringCache[fc->vpx][fc->vpy][fc->pxHeight].erase(*removals_i); + delete (*removals_i)->second; + } + } +} GLFont &GLFont::getFont(GLFontSize esize) { diff --git a/src/util/GLFont.h b/src/util/GLFont.h index 048095a..86fc1c4 100644 --- a/src/util/GLFont.h +++ b/src/util/GLFont.h @@ -8,6 +8,18 @@ #include "wx/filename.h" #include "wx/stdpaths.h" +class GLFontStringCache { +public: + GLFontStringCache(); + int drawlen; + int vpx, vpy; + int pxHeight; + float msgWidth; + int gc; + std::vector gl_vertices; + std::vector gl_uv; +}; + class GLFontChar { public: GLFontChar(); @@ -66,12 +78,18 @@ public: bool isLoaded(); float getStringWidth(std::string str, float size, float viewAspect); - void drawString(std::string str, float xpos, float ypos, int pxHeight, Align hAlign = GLFONT_ALIGN_LEFT, Align vAlign = GLFONT_ALIGN_TOP, int vpx=0, int vpy=0); + void drawString(std::string str, float xpos, float ypos, int pxHeight, Align hAlign = GLFONT_ALIGN_LEFT, Align vAlign = GLFONT_ALIGN_TOP, int vpx=0, int vpy=0, bool cacheable = false); static GLFont fonts[GLFONT_MAX]; static GLFont &getFont(GLFontSize esize); + GLFontStringCache *cacheString(std::string str, int pxHeight, int vpx, int vpy); + void drawCacheString(GLFontStringCache *fc, float xpos, float ypos, Align hAlign, Align vAlign); + + void doCacheGC(); private: + std::map > > > stringCache; + std::string nextParam(std::istringstream &str); std::string getParamKey(std::string param_str); std::string getParamValue(std::string param_str); @@ -90,4 +108,6 @@ private: std::string imageFile; std::string fontFileSource; GLuint texId; + int gcCounter; + std::mutex cache_busy; }; diff --git a/src/visual/PrimaryGLContext.cpp b/src/visual/PrimaryGLContext.cpp index cf294f0..9a62538 100644 --- a/src/visual/PrimaryGLContext.cpp +++ b/src/visual/PrimaryGLContext.cpp @@ -166,11 +166,11 @@ void PrimaryGLContext::DrawDemodInfo(DemodulatorInstance *demod, RGBA4f color, l } if (demod->getDemodulatorType() == "USB") { - GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demodLabel, uxPos, hPos, 16, GLFont::GLFONT_ALIGN_LEFT, GLFont::GLFONT_ALIGN_CENTER); + GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demodLabel, uxPos, hPos, 16, GLFont::GLFONT_ALIGN_LEFT, GLFont::GLFONT_ALIGN_CENTER, 0, 0, true); } else if (demod->getDemodulatorType() == "LSB") { - GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demodLabel, uxPos, hPos, 16, GLFont::GLFONT_ALIGN_RIGHT, GLFont::GLFONT_ALIGN_CENTER); + GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demodLabel, uxPos, hPos, 16, GLFont::GLFONT_ALIGN_RIGHT, GLFont::GLFONT_ALIGN_CENTER, 0, 0, true); } else { - GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demodLabel, uxPos, hPos, 16, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER); + GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demodLabel, uxPos, hPos, 16, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER, 0, 0, true); } glDisable(GL_BLEND); @@ -381,9 +381,9 @@ void PrimaryGLContext::DrawDemod(DemodulatorInstance *demod, RGBA4f color, long glColor3f(0, 0, 0); GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demodStr, 2.0 * (uxPos - 0.5) + xOfs, -1.0 + hPos - yOfs, 16, demodAlign, - GLFont::GLFONT_ALIGN_CENTER); + GLFont::GLFONT_ALIGN_CENTER, 0, 0, true); glColor3f(1, 1, 1); - GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demodStr, 2.0 * (uxPos - 0.5), -1.0 + hPos, 16, demodAlign, GLFont::GLFONT_ALIGN_CENTER); + GLFont::getFont(GLFont::GLFONT_SIZE16).drawString(demodStr, 2.0 * (uxPos - 0.5), -1.0 + hPos, 16, demodAlign, GLFont::GLFONT_ALIGN_CENTER, 0, 0, true); glDisable(GL_BLEND); diff --git a/src/visual/ScopeContext.cpp b/src/visual/ScopeContext.cpp index a24e4b8..75741c4 100644 --- a/src/visual/ScopeContext.cpp +++ b/src/visual/ScopeContext.cpp @@ -35,9 +35,9 @@ void ScopeContext::DrawTunerTitles(bool ppmMode) { glColor3f(0.65, 0.65, 0.65); - GLFont::getFont(GLFont::GLFONT_SIZE12).drawString(ppmMode?"Device PPM":"Frequency", -0.66, -1.0+hPos, 12, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER); - GLFont::getFont(GLFont::GLFONT_SIZE12).drawString("Bandwidth", 0.0, -1.0+hPos, 12, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER); - GLFont::getFont(GLFont::GLFONT_SIZE12).drawString("Center Frequency", 0.66, -1.0+hPos, 12, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER); + GLFont::getFont(GLFont::GLFONT_SIZE12).drawString(ppmMode?"Device PPM":"Frequency", -0.66, -1.0+hPos, 12, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER, 0, 0, true); + GLFont::getFont(GLFont::GLFONT_SIZE12).drawString("Bandwidth", 0.0, -1.0+hPos, 12, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER, 0, 0, true); + GLFont::getFont(GLFont::GLFONT_SIZE12).drawString("Center Frequency", 0.66, -1.0+hPos, 12, GLFont::GLFONT_ALIGN_CENTER, GLFont::GLFONT_ALIGN_CENTER, 0, 0, true); } void ScopeContext::DrawDeviceName(std::string deviceName) { @@ -47,7 +47,7 @@ void ScopeContext::DrawDeviceName(std::string deviceName) { float hPos = (float) (viewHeight - 20) / viewHeight; glColor3f(0.65, 0.65, 0.65); - GLFont::getFont(GLFont::GLFONT_SIZE12).drawString(deviceName.c_str(), 1.0, hPos, 12, GLFont::GLFONT_ALIGN_RIGHT, GLFont::GLFONT_ALIGN_CENTER); + GLFont::getFont(GLFont::GLFONT_SIZE12).drawString(deviceName.c_str(), 1.0, hPos, 12, GLFont::GLFONT_ALIGN_RIGHT, GLFont::GLFONT_ALIGN_CENTER, 0, 0, true); } void ScopeContext::DrawEnd() {