NSView in OS 10.11 El Capitan Throwing Errors - opengl
I have an OpenGL application I'm running in Xcode 7.0.1 on a 2011 MacBookPro.
I recently upgraded from OS 10.10 to 10.11 El Capitan, and now windows with NSViews are throwing this error (Deployment Target 10.11, 10.10 or 10.9):
invalid context 0x0. If you want to see the backtrace, please set
CG_CONTEXT_SHOW_BACKTRACE environmental variable.
In the NSView drawRect method, I get the CGContext with the following statement:
CGContextRef context = [[NSGraphicsContext currentContext] CGContext];
Also, my GLSL 4.1 shaders don't write anything to the OpenGL window anymore.
This code was not giving me any problems before I upgraded to El Capitan, and the (almost) exact same code runs fine without errors on a 2012 MacBookPro, OS 10.10, Xcode 6.4, Deployment Target 10.9 or 10.10. The only code difference is that the graphics context in the NSView drawRect method is obtained with:
CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
I think my problem might be that the computer that has problems is a 2011 MacBookPro, and Metal requires 2012 or later. I'm not using Metal, but I still think this might be a factor.
Is the computer vintage the problem that generates the error, or is there some other syntax I should be using to get the graphics context?
I have no idea why the GLSL shaders don't work anymore. Any ideas there?
The application main window is an OpenGL view, but I use many NSViews in pop up user interface windows, custom buttons and various other uses. Below is the complete code for one of the simplest of those windows. Again, this all ran fine before I upgraded to EC and Xcode 7.0.1.
#implementation StatusView
// **************************** Init **********************************
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
}
return self;
}
// ************************** Draw Rect ********************************
- (void)drawRect:(NSRect)dirtyRect
{
if(windowManager)
{
CGContextRef context = [[NSGraphicsContext currentContext] CGContext];
// Define a color space variable
CGColorSpaceRef rgbColorspace = CGColorSpaceCreateDeviceRGB();
// Get the bounds
NSRect nsBounds = [self bounds];
// Set the graphics bounds
CGRect cgBounds = NSRectToCGRect(nsBounds);
// ****** Draw the Background in Transparent Black
CGContextSetRGBFillColor(context, 0.0f, 0.0f, 0.0f, 0.0f);
CGContextFillRect(context, cgBounds);
// Set the text matrix.
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
// Create a color that will be added as an attribute to the attrString for normal text.
CGFloat textColorComponents[] = { 1.0, 1.0, 1.0, 1.0 };
CGColorRef whiteColor = CGColorCreate(rgbColorspace, textColorComponents);
// Create a color that will be added as an attribute to the attrString for invisible text.
CGFloat invisibleTextColorComponents[] = { 0.0, 0.0, 0.0, 0.0 };
CGColorRef invisibleColor = CGColorCreate(rgbColorspace, invisibleTextColorComponents);
// Create a font for normal text.
CFStringRef stringFontName = CFSTR("AppleCasual");
CTFontRef stringFont = CTFontCreateWithName(stringFontName, 18.0, NULL);
CGContextSetRGBFillColor(context, 0.0f, 0.0f, 0.0f, 0.0f);
CGContextFillRect(context, cgBounds);
// ************* Box the Window in Gray ***************************
CGContextMoveToPoint(context, 0.0,1.0);
CGContextAddLineToPoint(context,0.0, cgBounds.size.height - 1.0);
CGContextAddLineToPoint(context,cgBounds.size.width - 2.0, cgBounds.size.height - 1.0);
CGContextAddLineToPoint(context,cgBounds.size.width - 2.0, 1.0);
CGContextAddLineToPoint(context,0.0, 1.0);
CGContextSetLineWidth(context, 2.0);
CGContextSetRGBStrokeColor(context, 0.7, 0.7, 0.7, 1.0);
CGContextStrokePath(context);
// *********** Draw String1
CGPoint endingTextPoint;
if(windowManager->statusTextBox1String)
{
// Create a mutable attributed string with a max length of 0 for normal text.
CFMutableAttributedStringRef attrString = CFAttributedStringCreateMutable(kCFAllocatorDefault, 0);
// Create a path which will bound the area where you will be drawing text.
CGMutablePathRef invisibleTextPath = CGPathCreateMutable();
// Create a path which will bound the area where you will be drawing text.
CGMutablePathRef string1TextPath = CGPathCreateMutable();
// Initialize a string.
CFStringRef textString = (__bridge CFStringRef)windowManager->statusTextBox1String;
CFIndex textStringLength = CFStringGetLength (textString);
// Measure the string length
CGRect invisibleTextBounds = CGRectMake(0.0, 0.0, cgBounds.size.width, 30.0);
CGPathAddRect(invisibleTextPath, NULL, invisibleTextBounds);
// Copy the textString into attrString
CFAttributedStringReplaceString (attrString, CFRangeMake(0, 0), textString);
// Set the color and font.
CFAttributedStringSetAttribute(attrString, CFRangeMake(0, textStringLength), kCTForegroundColorAttributeName, invisibleColor);
CFAttributedStringSetAttribute(attrString, CFRangeMake(0, textStringLength), kCTFontAttributeName, stringFont);
// Create the framesetter with the attributed string.
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(attrString);
CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), invisibleTextPath, NULL);
// Draw the specified frame in the given context.
CTFrameDraw(frame, context);
endingTextPoint = CGContextGetTextPosition(context);
// Draw the Text
// Set a rectangular path.
CGRect textBounds = CGRectMake((cgBounds.size.width / 2.0) - (endingTextPoint.x / 2.0), 140.0, cgBounds.size.width, 30.0);
CGPathAddRect(string1TextPath, NULL, textBounds);
// Copy the textString into attrString
CFAttributedStringReplaceString (attrString, CFRangeMake(0, textStringLength), textString);
// Set the color and fontof the first chars.
CFAttributedStringSetAttribute(attrString, CFRangeMake(0, textStringLength), kCTForegroundColorAttributeName, whiteColor);
CFAttributedStringSetAttribute(attrString, CFRangeMake(0, textStringLength), kCTFontAttributeName, stringFont);
// Create the framesetter with the attributed string.
framesetter = CTFramesetterCreateWithAttributedString(attrString);
// Create a frame.
frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), string1TextPath, NULL);
// Draw the specified frame in the given context.
CTFrameDraw(frame, context);
CFRelease(string1TextPath);
CFRelease(invisibleTextPath);
CFRelease(frame);
CFRelease(framesetter);
CFRelease(attrString);
}
// ****************** Draw String 2
if(windowManager->statusTextBox2String)
{
CGContextSetRGBFillColor(context, 0.0f, 0.0f, 0.0f, 0.0f);
CGContextFillRect(context, cgBounds);
// ********** Box the Window in Gray ***********************
CGContextMoveToPoint(context, 0.0,1.0);
CGContextAddLineToPoint(context,0.0, cgBounds.size.height - 1.0);
CGContextAddLineToPoint(context,cgBounds.size.width - 2.0, cgBounds.size.height - 1.0);
CGContextAddLineToPoint(context,cgBounds.size.width - 2.0, 1.0);
CGContextAddLineToPoint(context,0.0, 1.0);
CGContextSetLineWidth(context, 2.0);
CGContextSetRGBStrokeColor(context, 0.7, 0.7, 0.7, 1.0);
CGContextStrokePath(context);
// Create a mutable attributed string with a max length of 0 for normal text.
CFMutableAttributedStringRef attrString = CFAttributedStringCreateMutable(kCFAllocatorDefault, 0);
// Create a path which will bound the area where you will be drawing text.
CGMutablePathRef invisibleTextPath = CGPathCreateMutable();
// Create a path which will bound the area where you will be drawing text.
CGMutablePathRef string2TextPath = CGPathCreateMutable();
// Initialize a string.
CFStringRef textString = (__bridge CFStringRef)windowManager->statusTextBox2String;
CFIndex textStringLength = CFStringGetLength (textString);
// Measure the string length
CGRect invisibleTextBounds = CGRectMake(0.0, 0.0, cgBounds.size.width, 130.0);
CGPathAddRect(invisibleTextPath, NULL, invisibleTextBounds);
// Copy the textString into attrString
CFAttributedStringReplaceString (attrString, CFRangeMake(0, 0), textString);
// Set the color and font
CFAttributedStringSetAttribute(attrString, CFRangeMake(0, textStringLength), kCTForegroundColorAttributeName, invisibleColor);
CFAttributedStringSetAttribute(attrString, CFRangeMake(0, textStringLength), kCTFontAttributeName, stringFont);
// Create the framesetter with the attributed string.
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(attrString);
CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), invisibleTextPath, NULL);
// Draw the specified frame in the given context.
CTFrameDraw(frame, context);
endingTextPoint = CGContextGetTextPosition(context);
// Draw the Text
// Set a rectangular path.
CGRect textBounds = CGRectMake((cgBounds.size.width / 2.0) - (endingTextPoint.x / 2.0), 100.0, cgBounds.size.width, 30.0);
CGPathAddRect(string2TextPath, NULL, textBounds);
// Copy the textString into attrString
CFAttributedStringReplaceString (attrString, CFRangeMake(0, textStringLength), textString);
// Set the color and fontof the first chars.
CFAttributedStringSetAttribute(attrString, CFRangeMake(0, textStringLength), kCTForegroundColorAttributeName, whiteColor);
CFAttributedStringSetAttribute(attrString, CFRangeMake(0, textStringLength), kCTFontAttributeName, stringFont);
// Create the framesetter with the attributed string.
framesetter = CTFramesetterCreateWithAttributedString(attrString);
// Create a frame.
frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), string2TextPath, NULL);
// Draw the specified frame in the given context.
CTFrameDraw(frame, context);
CFRelease(string2TextPath);
CFRelease(invisibleTextPath);
CFRelease(frame);
CFRelease(framesetter);
CFRelease(attrString);
}
CFRelease(stringFont);
CFRelease(whiteColor);
CFRelease(invisibleColor);
CGContextFlush(context);
}
return;
}
#end
This is an image of what this particular window looks like:
The behavior is not consistent. For example, this status window should come up for each of several steps in the calculation process, but it looks like only every other window is displayed (e.g. steps 2, 4 and 6, but not 1, 3 or 5).
There are LOTS of errors being generated, but this is a sample backtrace from one of the errors:
Oct 9 10:23:30 WispFractals3D[746] <Error>: CGContextRestoreGState: invalid context 0x0. Backtrace:
<-[StatusWindowController updateStatusProgress:]+228>
<-[AppController updateStatusProgress:]+64>
<-[AppController runTheFractal:]+804>
<_os_activity_initiate+75>
<-[NSApplication sendAction:to:from:]+460>
<-[NSMenuItem _corePerformAction]+336>
<-[NSCarbonMenuImpl performActionWithHighlightingForItemAtIndex:]+114>
<_os_activity_initiate+75>
<-[NSMenu performActionForItemAtIndex:]+131>
<-[NSMenu _internalPerformActionForItemAtIndex:]+35>
<-[NSCarbonMenuImpl _carbonCommandProcessEvent:handlerCallRef:]+107>
<NSSLMMenuEventHandler+708>
<_ZL23DispatchEventToHandlersP14EventTargetRecP14OpaqueEventRefP14HandlerCallRec+1231>
<_ZL30SendEventToEventTargetInternalP14OpaqueEventRefP20OpaqueEventTargetRefP14HandlerCallRec+404>
<SendEventToEventTarget+40>
<_ZL18SendHICommandEventjPK9HICommandjjhPKvP20OpaqueEventTargetRefS5_PP14OpaqueEventRef+411>
<SendMenuCommandWithContextAndModifiers+59>
<SendMenuItemSelectedEvent+188>
<_ZL19FinishMenuSelectionP13SelectionDataP10MenuResultS2_+96>
<_ZL14MenuSelectCoreP8MenuData5PointdjPP13OpaqueMenuRefPt+711>
<_HandleMenuSelection2+460>
<_NSHandleCarbonMenuEvent+277>
<_DPSNextEvent+1906>
<-[NSApplication _nextEventMatchingEventMask:untilDate:inMode:dequeue:]+454>
<-[NSApplication run]+682>
<NSApplicationMain+1176>
<main+34>
The .xib file looks like this:
There's a custom progress indicator in this window (bounded by the two white squares) that's invisible, but it's there.
Sample code to display this window looks like:
[self showStatusWindowWithString1:#"Calculation Complete" String2:timeMessage ButtonOn:YES AbortOn:NO ProgressOn:NO ProgressMax:100.0 Title:#"Fractal Run Time"];
and the code for the showStatusWindow method is:
- (void)showStatusWindowWithString1:(NSString *)string1 String2:(NSString *)string2 ButtonOn:(BOOL)buttonon AbortOn:(BOOL)aborton ProgressOn:(BOOL)progresson ProgressMax:(double)progressmax Title:(NSString *)title
{
statusWindowTitle = title;
statusTextBox1String = string1;
statusTextBox2String = string2;
statusButtonOn = buttonon;
abortOn = aborton;
statusProgressOn = progresson;
statusProgressMax = progressmax;
if (!statusWindowController)
{
statusWindowController = [[StatusWindowController alloc] initWithWindowNibName:#"StatusWindow" Manager:self];
}
[[statusWindowController window] setTitle:statusWindowTitle];
[statusWindowController showWindow:self];
[fileStatusWindow makeKeyAndOrderFront:self];
appDelegate->fileStatusWindowOpenFlag = YES;
[appDelegate checkFlags];
return;
}
Ken Thomases diagnosed that the backtrace indicated that invalid context errors were being generated in [StatusWindowController updateStatusProgress:] (this updates a custom progress indicator).
I changed this method from:
- (void) updateStatusProgress:(double)statusprogress
{
[statusProgressIndicator setDoubleValue:statusprogress];
[statusProgressIndicator drawRect:[statusProgressIndicator bounds]];
}
To:
- (void) updateStatusProgress:(double)statusprogress
{
[statusProgressIndicator setDoubleValue:statusprogress];
[statusProgressIndicator setNeedsDisplay:YES];
}
It looked to me like the error messages were being generated in multiple places, but this one change stopped all error messages.
My next problem, was that the status window (image above) was not displaying every time it should, only sometimes. Again, this all worked fine in Yosemite, Xcode 6.4.
I've now found that when the status window does not display, I can get it to display by running it modally. Strange.
The last problem I'm working through is that the GLSL shaders are not writing to the OpenGL view as they should. I've tested that the shaders are loading and running by adding a line at the end of the fragment shader: fragColor = vec4(1.0, 0.0, 0.0, 1.0);, which turned the view totally red as it should.
The fragment shader actually should be sampling from a texture, so I loaded this texture with all (255, 0, 0, 255) to test the sampling by putting a simple sampling statement at the end of the fragment shader:
fragColor = texture(Texture, texCoord).rgba;
but nothing gets written, so there must be a problem with loading the texture into the shader. I'm working on that now.
The problem causing the "invalid context 0x0" messages was that you were directly calling -drawRect:. This has never been valid. -drawRect: is called by the framework after it has set up the appropriate graphics context and things like the coordinate transform to put the drawing in the right place in the window and clipping to the bounds of the view. If you call it at other times, then no context has been set up and nothing good can come of it.
If you must redraw immediately, you could call one of the -display... methods.
However, it's usually best to do as you've now done: simply mark the view as needing display and let Cocoa redraw it in due course.
You should probably post separate questions for the other issues.
I just did a quick build of one of my apps which hadn't been rebuilt under EC before. It all worked fine.
Perhaps you can post a bit more detail. The code and crash point?
Related
OGLFT draws text when GLStipple is used
I have an interesting bug that has been "bugging" me for a few days now. I am currently using OpenGL to draw text on a screen. I am utilizing the OGLFT library to assist the drawing. This library actually uses the freetype2 library. I am actually not doing anything special with the text. I am only looking for monochromatic text. Anyways, after implementing the library, I noticed that the text is only drawn correct when I have glStipple enabled. I believe that there is some interference issue between the OGLFT library and what I am enabling. I was wondering if there is anyone out there with some experience on using the OGLFT library. I am posting a minimalist example of my code to demonstrate what is going on: (Please note that there are some variables that are used to st the zoom factor of my glCanvas and the position of the camera and that this is only for 2D) double _zoomX = 1.0; double _zoomY = 1.0; double _cameraX = 0; double _cameraY = 0; /* This function gets called everytime a draw routine is needed */ void modelDefinition::onPaintCanvas(wxPaintEvent &event) { wxGLCanvas::SetCurrent(*_geometryContext);// This will make sure the the openGL commands are routed to the wxGLCanvas object wxPaintDC dc(this);// This is required for drawing glMatrixMode(GL_MODELVIEW); glClear(GL_COLOR_BUFFER_BIT); updateProjection(); OGLFT::Monochrome *testface = new OGLFT::Monochrome( "/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf", 8); testface->draw(0, 0, "test"); glEnable(GL_LINE_STIPPLE);// WHen I comment out this line, the text is unable to be drawn glLineStipple(1, 0b0001100011000110); glBegin(GL_LINES); glVertex2d(_startPoint.x, _startPoint.y); glVertex2d(_endPoint.x, _endPoint.y); glEnd(); glDisable(GL_LINE_STIPPLE); SwapBuffers(); } void modelDefinition::updateProjection() { // First, load the projection matrix and reset the view to a default view glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-_zoomX, _zoomX, -_zoomY, _zoomY, -1.0, 1.0); //Reset to modelview matrix glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glViewport(0, 0, (double)this->GetSize().GetWidth(), (double)this->GetSize().GetHeight()); /* This section will handle the translation (panning) and scaled (zooming). * Needs to be called each time a draw occurs in order to update the placement of all the components */ if(_zoomX < 1e-9 || _zoomY < 1e-9) { _zoomX = 1e-9; _zoomY = _zoomX; } if(_zoomX > 1e6 || _zoomY > 1e6) { _zoomX = 1e6; _zoomY = _zoomX; } glTranslated(-_cameraX, -_cameraY, 0.0); } Also one thing to note is that the code below the glEnable(GL_LINE_STIPPLE); is required. It is as if the glStipple needs to be drawn correctly for the text to be displayed correctly.
Looking through your code, I believe that your intention is to render it as a greyscale? If so, then you can simply use the OGLFT::Grayscale *testface = new OGLFT::Grayscale( "/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf", 8); This will get what you need without having to worry about the issue that you posted. In fact, I recommend doing it this way too.
Cairo Fill with Transparency
I'm new to Cairo, trying to create text with transparent color and stroke. stroke color's transparency works but text fill color transparency transparency_value doesn't work. If i reduce transparency_value , text color just gets darker(black) and increasing transparency_value makes text color brighter (green in my case) cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 640, 480); cairo_t* cairo = cairo_create(surface); cairo_set_font_face(cairo, myfont_face); cairo_set_font_size(cairo, 25); cairo_text_extents_t extents; cairo_text_extents(cairo, "Hello World", &extents); cairo_move_to(cairo, 200, 200); cairo_text_path(cairo, "Hello World"); double transparency_value = 0.5; cairo_set_source_rgba(cairo, 0,1,0,transparency_value ); //transparency doesn't work //cairo_fill(cairo); //this didn't make a difference cairo_fill_preserve(cairo); cairo_set_source_rgba(cairo, 0.56, 0.76, 0.96, 0.5); //transparency works cairo_set_line_width(cairo, 1.5); cairo_stroke(cairo);
Could it be that you are drawing your text outside of the surface? In the following example I added a call to cairo_move_to(cr, 200, 200) and now I get the following result. (This is written in Lua and uses https://github.com/pavouk/lgi to call into cairo; comments indicate things that I changed compared to your version) local cairo = require("lgi").cairo local surface = cairo.ImageSurface.create(cairo.Format.ARGB32, 640, 480) local cr = cairo.Context(surface) local myfont_face = cr:get_font_face() -- I have to get this from somewhere cr:move_to(200, 200) -- I added this line to make something appear cr:set_font_face(myfont_face) cr:set_font_size(25) cr:text_path("Hello World") local transparency_value = 0.5 cr:set_source_rgba(0, 1, 0, transparency_value) -- cr:fill() cr:fill_preserve() cr:set_source_rgba(0.65, 0.76, 0.96, 0.5) cr:set_line_width(5) -- changed from 1.5 to 5 to make it more prominent cr:stroke() surface:write_to_png("/tmp/out.png") Edit: And this is the result when I change transparency_value to 0.1. Clearly, the result is different and transparency works correctly (when zooming in, you still see some faint green in the middle).
JOGL GL_SELECT picking fails
I am using the GL_SELECT method to achieve mouse selection in OpenGL using JOGL Java Library. I know the method is deprecated and such, but it is a simple school assignment and this should do it. However I am having some trouble: even though something is rendered in GL_SELECT mode, glRenderMode(GL_RENDER) returns zero hits. The problem is deterministic, but I don't see a kind of pattern; for example, if I have a sphere in the center, it works if I click on its upper part, but not on its lower part. For a cube, it only won't work on one specific face. For a rectangle it works alright. I have tested commenting out the glRenderMode(GL_SELECT) to check if something was indeed being rendered and yes, I could see the shape, but even so glRenderMode(GL_RENDER) gave me zero. EDIT: I have also tested removing the call to gluPickMatrix() and the glRenderMode(GL_SELECT), which gave me exactly the same as the normal (non-picking) render, so the projection and model view matrixes are set up correctly I think. So, I don't think I am rendering incorrectly in select mode. What can be going on? EDIT: maybe this could be a hardware problem, as the method is deprecated. Is that possible? Thanks in advance. // Get required information point.y = getHeight() - point.y; gl.glGetIntegerv(GL2.GL_VIEWPORT, view, 0); // Setup OpenGL for selection gl.glSelectBuffer(64, buffer); gl.glRenderMode(GL2.GL_SELECT); gl.glInitNames(); // Setup projection matrix gl.glMatrixMode(GL2.GL_PROJECTION); gl.glPushMatrix(); gl.glLoadIdentity(); Util.glu.gluPickMatrix( point.x, point.y, 5.0, 5.0, view, 0 ); Util.glu.gluPerspective(camera.getFieldOfView(), getWidth() * 1.0 / getHeight(), camera.getCloseDistance(), camera.getFarDistance() ); // Setup model view matrix for rendering gl.glMatrixMode(GL2.GL_MODELVIEW); camera.setView(gl); // Set to model view and use glLookAt gl.glClear( GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT ); // Render objects for(int i = 0; i < shapeList.size(); i++) { gl.glPushName(i); // Execute transformations for translation/rotation/scale and render shape shapeList.get(i).display(gl, false); gl.glPopName(); } // Process hits hits = gl.glRenderMode(GL2.GL_RENDER); System.out.println("Hits = " + hits); // ... Process hits here ... // Reset matrixes gl.glMatrixMode(GL2.GL_PROJECTION); gl.glPopMatrix(); gl.glMatrixMode(GL2.GL_MODELVIEW); gl.glLoadIdentity(); camera.setView function: public void setView( GL2 gl ) { gl.glMatrixMode(GL2.GL_MODELVIEW); gl.glLoadIdentity(); Util.glu.gluLookAt( eye[Axis.X], eye[Axis.Y], eye[Axis.Z], target[Axis.X], target[Axis.Y], target[Axis.Z], up[Axis.X], up[Axis.Y], up[Axis.Z] ); }
text in 3d space - how to carriage return? (openGL, C++, OSX)
Here is my if statement that detects a bomb threat (just a game I'm making)... if (exodus2_bomb == 1) { float exodus2_theta_math = (exodus2_theta)/10.0*M_PI; float exodus2_phi_math = (exodus2_phi)/10.0*2*M_PI; r_exodus2_x = radius_exodus_pos * sin(exodus2_theta_math) * cos(exodus2_phi_math); r_exodus2_y = radius_exodus_pos * sin(exodus2_theta_math) * sin(exodus2_phi_math); r_exodus2_z = radius_exodus_pos * cos(exodus2_theta_math); glPushMatrix(); glTranslatef(r_exodus2_x,r_exodus2_y,r_exodus2_z); glColor3f (1.0, 0.0, 0.0); glRasterPos3i(exodus2_x/10,exodus2_y/10,exodus2_z/10); string exodus2 = "BOMB!!"; void * fontexodus2 = GLUT_BITMAP_HELVETICA_10; for (string::iterator i = exodus2.begin(); i != exodus2.end(); ++i) { char c = *i; glutBitmapCharacter(fontexodus2, c); } glEnd(); glPopMatrix(); glPushMatrix(); glTranslatef(r_exodus2_x,r_exodus2_y,r_exodus2_z); glColor3f (1.0, 0.0, 0.0); glRasterPos3i(exodus2_x/10,exodus2_y/10,exodus2_z/10); string exodus2b = "\n THREAT LEVEL 1"; void * fontexodus2b = GLUT_BITMAP_HELVETICA_10; for (string::iterator i = exodus2b.begin(); i != exodus2b.end(); ++i) { char c = *i; glutBitmapCharacter(fontexodus2b, c); } glEnd(); glPopMatrix(); } What I would like to have is a carriage return between "string exodus2" and "string exodus2b". However, it is always on one line. And I don't have the real estate onscreen for that. Is it possible to add a carriage return somewhere in my string iterator? Unfortunately, screwing around with "glTranslatef" and "glRasterPos3i" only results in the distance between the two lines of text NOT being consistent as I move the camera.
You need to render each string separately, and modify the raster position appropriate to reset the string's position. If you use glutBitmapHeight, you can determine how far you need to move the raster position "down" to emulate a new line. If you want the strings to be positioned in 3D, but then to "act" like they're restricted to the same plane in 2D, you can use the glBitmap command to modify the raster position in screen space. int lineHeight = glutBitmapHeight( font ); // number of pixels between "lines" int stringLength = glutBitmapLength( font, s1 ); // returns length of string 1 in pixels glutBitmap( 0, 0, 0, 0, -stringLength, lineHeight, NULL ); // move raster position glutBitmapString( font, s2 ); the fifth and sixth parameters of glBitmap control how far the raster position is moved. Alternatively, if you want these strings to be anchored in a position relative to the window, as compared to a point in your 3D space, check out glWindowPos. By the way, all of these functions are deprecated with OpenGL 3.0, removed in OpenGL 3.1, unless you use a compatibility context in verisons of OpenGL greater than 3.2.
Java3d - Bad Normals using GeometryInfo
I'm working with Java3d under eclipse Indigo in windows. After finally modifying the StlLoader example and ObjLoad classes to get my STL files to load up, I get a result that looks like the below (I think from other questions these are definitely bad vector normals). Does anybody know why I might be having this problem? I am using SolidWorks to save the STL as an ASCII file and using a modification of the code for loading STL files given on java3d.org. Although I have only changed some appearance properties and fixed broken imports etc. I have confirmed that the facet normals put into "normList" below definitely match those from the file. Example of Result: Snippet of StlFile.java from http://www.java3d.org : private SceneBase makeScene() { // Create Scene to pass back SceneBase scene = new SceneBase(); BranchGroup group = new BranchGroup(); scene.setSceneGroup(group); // Store the scene info on a GeometryInfo GeometryInfo gi = new GeometryInfo(GeometryInfo.TRIANGLE_STRIP_ARRAY); // Convert ArrayLists to arrays: only needed if file was not binary if(this.Ascii) { coordArray = objectToPoint3Array(coordList); normArray = objectToVectorArray(normList); } gi.setCoordinates(coordArray); gi.setNormals(normArray); gi.setStripCounts(stripCounts); // Setting the Material Appearance Appearance app = new Appearance(); // Coloring Attributes ColoringAttributes catt = new ColoringAttributes(); catt.setShadeModel( ColoringAttributes.NICEST ); app.setColoringAttributes(catt); Material mat = new Material(new Color3f(0.6f, 0.6f, 0.6f), // ambient new Color3f(0, 0, 0), // emissive new Color3f(0.6f, 0.6f, 0.6f), // diffuse new Color3f(0.6f, 0.6f, 0.6f), // specular 10); // shininess app.setMaterial(mat); // Put geometry into Shape3d Shape3D shape = new Shape3D(gi.getGeometryArray(), app); group.addChild(shape); scene.addNamedObject(objectName, shape); return scene; } // end of makeScene
If some areas on the surface are really black (0x000000), I would guess some of the normals are actually pointing inwards the model rather than to the outside. You may check if vertices v1,v2,v3 for all the triangles are defined in right-hand order (just test if det(v1,v2,v3) > 0 ) and reorder points accordingly. Alternatively, detect the "opposite" normals and multiply them by -1