[dasher: 3/28] iPhone+Mac: cache label sizes at one font size, scale proportionately (faster!)



commit b9b25c1bf7882776ac8b61d342d575a1aec55a30
Author: Alan Lawrence <acl33 inf phy cam ac uk>
Date:   Tue Sep 13 18:08:41 2011 +0100

    iPhone+Mac: cache label sizes at one font size, scale proportionately (faster!)
    
    as opposed to asking OS for exact dimensions at every font size.
    (This was taking ~50% CPU time on iPhone; fix improves framerate ~18 -> ~28)

 Src/Common/OpenGLScreen.h      |    9 +++++----
 Src/Common/OpenGLScreen.mm     |   31 +++++++++++++++++--------------
 Src/MacOSX/DasherViewOpenGL.mm |   30 ++++++++++++------------------
 Src/iPhone/Classes/EAGLView.h  |    2 +-
 Src/iPhone/Classes/EAGLView.mm |    9 +++++----
 5 files changed, 40 insertions(+), 41 deletions(-)
---
diff --git a/Src/Common/OpenGLScreen.h b/Src/Common/OpenGLScreen.h
index ecb753e..59878e2 100755
--- a/Src/Common/OpenGLScreen.h
+++ b/Src/Common/OpenGLScreen.h
@@ -23,6 +23,7 @@ namespace Dasher {
       NSString *str;
       GLuint texture;
       GLfloat texcoords[8];
+      CGSize sz; //at base font size, or wrapped size if appropriate
       AlphabetLetter(OpenGLScreen *pScreen, const std::string &strText, unsigned int iWrapSize);
       ~AlphabetLetter();
       void PrepareTexture();
@@ -48,10 +49,10 @@ namespace Dasher {
     void resize(screenint iWidth, screenint iHeight, GLshort backingWidth, GLshort backingHeight, GLfloat tc_x, GLfloat tc_y);
     void RegenerateLabels();
     ///Render a string onto a CoreGraphics context, using the context's current colour etc.
-    /// \param iFontSize if 0, render on a single line, in 36pt font; any other value,
-    /// render in that size, but constrained to the screen width, wrapping across multiple
-    /// lines if necessary
-    virtual void RenderStringOntoCGContext(NSString *string, CGContextRef context, unsigned int iFontSize)=0;
+    /// \param iFontSize font size to use
+    /// \param bWrap if true, constrain to screen width and wrap across multiple lines (if necessary);
+    /// if false, render on a single line.
+    virtual void RenderStringOntoCGContext(NSString *string, CGContextRef context, unsigned int iFontSize, bool bWrap)=0;
     /// Get the pixel dimensions of a string when rendered in a specified font size
     /// \param bWrap if true, string should be wrapped to the screen width, possibly
     /// over multiple lines (=> returned height will reflect this); if false,
diff --git a/Src/Common/OpenGLScreen.mm b/Src/Common/OpenGLScreen.mm
index e4c18f2..a29aa31 100644
--- a/Src/Common/OpenGLScreen.mm
+++ b/Src/Common/OpenGLScreen.mm
@@ -13,6 +13,8 @@
 using namespace Dasher;
 using namespace std;
 
+#define BASE_SIZE 32
+
 OpenGLScreen::OpenGLScreen(screenint iWidth, screenint iHeight, GLshort backingWidth, GLshort backingHeight, GLfloat tc_x, GLfloat tc_y, GLuint *_textures)
 : CLabelListScreen(iWidth,iHeight), colourTable(NULL), circ_rad(-1.0f), circ_coords(NULL), circPoints(0), textures(_textures) {
   resize(iWidth,iHeight,backingWidth,backingHeight,tc_x,tc_y);
@@ -205,22 +207,23 @@ OpenGLScreen::AlphabetLetter::AlphabetLetter(OpenGLScreen *pScreen, const string
 }
 
 void OpenGLScreen::AlphabetLetter::PrepareTexture() {
+  
+  sz = static_cast<OpenGLScreen *>(m_pScreen)->TextSize(str,m_iWrapSize ? m_iWrapSize : BASE_SIZE,m_iWrapSize);
+  
   int width=1, height=1;
   GLfloat texw,texh;
-  {
-    CGSize sz = static_cast<OpenGLScreen *>(m_pScreen)->TextSize(str,m_iWrapSize ? m_iWrapSize : 36,m_iWrapSize);
-    while (width<sz.width) width<<=1;
-    while (height<sz.height) height<<=1;
-    texw = sz.width/(float)width;
-    texh = sz.height/(float)height;
-  }
+  
+  while (width<sz.width) width<<=1;
+  while (height<sz.height) height<<=1;
+  texw = sz.width/(float)width;
+  texh = sz.height/(float)height;
 
   char *data = new char[width*height*4];
   CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
   CGContextRef context = CGBitmapContextCreate(data, width, height, 8, width*4, colorSpace, kCGImageAlphaPremultipliedLast);
   CGContextClearRect(context, CGRectMake(0.0, 0.0, width, height));
 
-  static_cast<OpenGLScreen *>(m_pScreen)->RenderStringOntoCGContext(str,context,m_iWrapSize);
+  static_cast<OpenGLScreen *>(m_pScreen)->RenderStringOntoCGContext(str,context,m_iWrapSize ? m_iWrapSize : BASE_SIZE,m_iWrapSize);
 
   glBindTexture(GL_TEXTURE_2D, texture);
   //...but tell the GL _not_ to interpolate between texels, as that results in a _big_
@@ -267,12 +270,12 @@ void OpenGLScreen::DrawString(CDasherScreen::Label *label, screenint x, screenin
   // by the currently selected GL foreground colour
 	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
 	glColor4f(colourTable[iColour].r, colourTable[iColour].g, colourTable[iColour].b, 1.0); //so we select the colour we want the text to appear in
-	CGSize sz = TextSize(l->str, iFontSize, l->m_iWrapSize);
+	pair<screenint,screenint> rect = TextSize(label, iFontSize);
 	GLshort coords[8];
 	coords[0] = x; coords[1]=y;
-	coords[2] = x+sz.width; coords[3] = y;
-	coords[4] = x; coords[5] = y+sz.height;
-	coords[6] = x+sz.width; coords[7]=y+sz.height;
+	coords[2] = x+rect.first; coords[3] = y;
+	coords[4] = x; coords[5] = y+rect.second;
+	coords[6] = x+rect.first; coords[7]=y+rect.second;
   glEnableClientState(GL_VERTEX_ARRAY);
 	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 	glVertexPointer(2, GL_SHORT, 0, coords);
@@ -285,8 +288,8 @@ void OpenGLScreen::DrawString(CDasherScreen::Label *label, screenint x, screenin
 
 pair<screenint,screenint> OpenGLScreen::TextSize(CDasherScreen::Label *label, unsigned int iFontSize) {
   const AlphabetLetter *l(static_cast<AlphabetLetter *> (label));
-  CGSize sz = TextSize(l->str, iFontSize, l->m_iWrapSize);
+  const int baseSize(l->m_iWrapSize ? l->m_iWrapSize : BASE_SIZE);
   //apply "ceil" to floating-point width/height ?
-  return pair<screenint,screenint>(sz.width, sz.height);
+  return pair<screenint,screenint>((l->sz.width*iFontSize)/baseSize, (l->sz.height*iFontSize)/baseSize);
 }
 
diff --git a/Src/MacOSX/DasherViewOpenGL.mm b/Src/MacOSX/DasherViewOpenGL.mm
index 4bf73b6..58cd8b6 100755
--- a/Src/MacOSX/DasherViewOpenGL.mm
+++ b/Src/MacOSX/DasherViewOpenGL.mm
@@ -26,17 +26,12 @@
 
 class COSXDasherScreen : public OpenGLScreen {
   DasherViewOpenGL *dasherView;
-  NSDictionary *fontAttrs;
 public:
   COSXDasherScreen(DasherViewOpenGL *_dasherView,screenint iWidth, screenint iHeight, GLfloat tc_x, GLfloat tc_y, GLuint *textures)
-  : OpenGLScreen(iWidth, iHeight, iWidth, iHeight,tc_x,tc_y,textures), dasherView(_dasherView), fontAttrs(nil) {
+  : OpenGLScreen(iWidth, iHeight, iWidth, iHeight,tc_x,tc_y,textures), dasherView(_dasherView) {
     RegenerateLabels(); //no actual labels, so just initialize fontAttrs
   }
-  
-  ~COSXDasherScreen() {
-    [fontAttrs release];
-  }
-  
+    
   void SendMarker(int iMarker) {
     [dasherView sendMarker:iMarker];    
   }
@@ -50,26 +45,25 @@ public:
     OpenGLScreen::resize(w,h, w,h, tc_x,tc_y);
   }
   
+  ///Override just to make callable from DasherViewOpenGL
   void RegenerateLabels() {
-    [fontAttrs release];
-    //white text on (default) transparent background means that when we texture
-    //a surface using a colour, the text appears in that colour...
-    fontAttrs = [NSDictionary dictionaryWithObjectsAndKeys:[NSFont fontWithName:dasherView.cachedFontName size:36.0],NSFontAttributeName,[NSColor whiteColor],NSForegroundColorAttributeName,nil];
-    //dictionaryWith...: does an autorelease - only "alloc" methods do not.
-    // But we want to keep the fontAttrs indefinitely...
-    [fontAttrs retain];
     OpenGLScreen::RegenerateLabels();
   }
   
 protected:
-  void RenderStringOntoCGContext(NSString *string, CGContextRef context, unsigned int iWrapSize) {
+  void RenderStringOntoCGContext(NSString *string, CGContextRef context, unsigned int iFontSize, bool bWrap) {
     NSGraphicsContext *old = [NSGraphicsContext currentContext];
     [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:context flipped:YES]];
 
-    if (iWrapSize)
-      [string drawWithRect:NSMakeRect(0.0, 0.0, GetWidth(), CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:[NSDictionary dictionaryWithObjectsAndKeys:[NSFont fontWithName:dasherView.cachedFontName size:iWrapSize],NSFontAttributeName,[NSColor whiteColor],NSForegroundColorAttributeName,nil]];
+    //white text on (default) transparent background means that when we texture
+    //a surface using a colour, the text appears in that colour...
+    NSDictionary *attrs = [NSDictionary dictionaryWithObjectsAndKeys:[NSFont fontWithName:dasherView.cachedFontName size:iFontSize], NSFontAttributeName, [NSColor whiteColor], NSForegroundColorAttributeName, nil];
+    //dictionaryWith...: does an autorelease - only "alloc" methods do not.
+    
+    if (bWrap)
+      [string drawWithRect:NSMakeRect(0.0, 0.0, GetWidth(), CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:attrs];
     else
-      [string drawAtPoint:NSMakePoint(0.0, 0.0) withAttributes:fontAttrs];
+      [string drawAtPoint:NSMakePoint(0.0, 0.0) withAttributes:attrs];
     [NSGraphicsContext setCurrentContext:old];  
   }
   
diff --git a/Src/iPhone/Classes/EAGLView.h b/Src/iPhone/Classes/EAGLView.h
index 71f7f4a..e457768 100644
--- a/Src/iPhone/Classes/EAGLView.h
+++ b/Src/iPhone/Classes/EAGLView.h
@@ -27,7 +27,7 @@ public:
   void SendMarker(int iMarker);
   
 protected:
-  void RenderStringOntoCGContext(NSString *str, CGContextRef context, unsigned int iWrapFontSize);
+  void RenderStringOntoCGContext(NSString *str, CGContextRef context, unsigned int iFontSize, bool bWrap);
   CGSize TextSize(NSString *str, unsigned int iFontSize, bool bWrap);
 };
 
diff --git a/Src/iPhone/Classes/EAGLView.mm b/Src/iPhone/Classes/EAGLView.mm
index 4e4bf98..fa08f73 100644
--- a/Src/iPhone/Classes/EAGLView.mm
+++ b/Src/iPhone/Classes/EAGLView.mm
@@ -42,17 +42,18 @@ void CDasherScreenBridge::SendMarker(int iMarker) {
   [view sendMarker:iMarker];
 }
 
-void CDasherScreenBridge::RenderStringOntoCGContext(NSString *str, CGContextRef context, unsigned int iFontWrapSize) {
+void CDasherScreenBridge::RenderStringOntoCGContext(NSString *str, CGContextRef context, unsigned int iFontSize, bool bWrap) {
   UIGraphicsPushContext(context);
   //white text on transparent background means that when we texture
   //a surface using a colour, the text appears in that colour...
   const CGFloat whiteComps[] = {1.0, 1.0, 1.0, 1.0};
   CGColorRef white = CGColorCreate(CGBitmapContextGetColorSpace(context), whiteComps);
   CGContextSetFillColorWithColor(context, white);
-  if (iFontWrapSize)
-    [str drawInRect:CGRectMake(0.0, 0.0, GetWidth(), CGFLOAT_MAX) withFont:[UIFont systemFontOfSize:iFontWrapSize]];
+  UIFont *font = [UIFont systemFontOfSize:iFontSize];
+  if (bWrap)
+    [str drawInRect:CGRectMake(0.0, 0.0, GetWidth(), CGFLOAT_MAX) withFont:font];
   else
-    [str drawAtPoint:CGPointMake(0.0, 0.0) withFont:[UIFont systemFontOfSize:36]];
+    [str drawAtPoint:CGPointMake(0.0, 0.0) withFont:font];
   CGColorRelease(white);
   UIGraphicsPopContext();  
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]