I'm using OpenGL to draw in Mac OS. When my code runs on Retina display everything works fine except text drawing. Under Retinal display the text is twice as big as it should be. It happens because the font size is in points and each point is 2 pixels under Retina, but OpenGL is pixel based.
Here is the correct text drawing under standard display:
Here is the incorrect text drawing under Retina display:
Here is how I normaly draw strings. Since OpenGL does not have text drawing functions, in order to draw text I do the following:
Get the font:
NSFontManager fontManager = [NSFontManager sharedFontManager];
NSString font_name = [NSString stringWithCString: "Helvetica" encoding: NSMacOSRomanStringEncoding];
font = [fontManager fontWithFamily: font_name traits:fontStyle weight:5 size:9];
attribs = [[NSMutableDictionary dictionaryWithCapacity: 3] retain];
[attribs setObject:font forKey:NSFontAttributeName];
Create and measure the string:
NSString* aString = [NSString stringWithCString: "blah blah" encoding: NSMacOSRomanStringEncoding];
NSSize frameSize = [aString sizeWithAttributes: m_attribs];
Allocate NSImage with the size:
NSImage* image = [[NSImage alloc] initWithSize:frameSize];
[image lockFocus];
Draw the string into the image:
[aString drawAtPoint:NSMakePoint (0, 0) withAttributes:m_attribs];
Get the bits:
NSBitmapImageRep* bitmap = [[NSBitmapImageRep alloc] initWithFocusedViewRect:NSMakeRect (0.0f, 0.0f, frameSize.width, frameSize.height)];
[image unlockFocus];
Create OpenGL texture:
GLuint texture = 0;
glGenTextures(1, &texture);
glTexImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, GL_RGBA, GLsizei(frameSize.width), GLsizei(frameSize.height), 0, GL_RGBA, [bitmap bitmapData]);
Draw the texture:
glBindTexture ….
other OpenGL drawing code
My question is how to get NSString to draw in pixel resolution not in points.
I tried the following:
OpenGLs coordinate system is in fact point based not pixel based, but you are the one who decides what those points are. A context defines the coordinate system in 2D by the glOrtho function (or you could construct an ortho matrix by hand) which sets up the min and max x,y coordinates on the screen. For example an orthographic projection could be setup so that 0 was on the left of the screen and 100 was on the right regardless of the size of the framebuffers you are rendering into.
The font texture appears to be created just fine. The problem is that you are rendering it on geometry twice as large as it needs to be. In OpenGL, texture size does not effect the size of the object rendered on your screen. The size on screen is defined by the geometry passed to glDrawArrays
or glBegin
etc not the texture.
I think the problem is that you are using the pixel size of the font texture to define the quad size used to render on screen. This would put your problem in the "other OpenGL Drawing code" section. To fix that you could apply some sort of scale factor to the drawing. In retina mode the scale factor to 0.5 and for normal screens it would be 1.0 (UIKit uses a similar idea to render UIView content)
The quad calculation could look something like this:
quad.width = texture.width * scaleFactor
quad.height = texture.height * scaleFactor
Another option would be to separate the quad rendering size completely from the texture. If you had a function or a class for drawing text it could have a font size parameter which it would use as the actual quad size instead of using the texture size.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With