From http://www.jwz.org/xscreensaver/xscreensaver-5.32.tar.gz
[xscreensaver] / OSX / XScreenSaverGLView.m
index f7a58c481bd4f04d2c287fde7092d5ac2e6d9ac1..da77021c89f63f489970a054f7b1d8e30d03edcb 100644 (file)
@@ -1,13 +1,13 @@
-/* xscreensaver, Copyright (c) 2006-2012 Jamie Zawinski <jwz@jwz.org>
-*
-* Permission to use, copy, modify, distribute, and sell this software and its
-* documentation for any purpose is hereby granted without fee, provided that
-* the above copyright notice appear in all copies and that both that
-* copyright notice and this permission notice appear in supporting
-* documentation.  No representations are made about the suitability of this
-* software for any purpose.  It is provided "as is" without express or 
-* implied warranty.
-*/
+/* xscreensaver, Copyright (c) 2006-2014 Jamie Zawinski <jwz@jwz.org>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation.  No representations are made about the suitability of this
+ * software for any purpose.  It is provided "as is" without express or 
+ * implied warranty.
+ */
 
 /* This is a subclass of Apple's ScreenSaverView that knows how to run
    xscreensaver programs without X11 via the dark magic of the "jwxyz"
@@ -47,6 +47,8 @@ extern void check_gl_error (const char *type);
 # ifndef USE_IPHONE
   [NSOpenGLContext clearCurrentContext];
 # endif // !USE_IPHONE
+
+  clear_gl_error();    // This hack is defunct, don't let this linger.
 }
 
 
@@ -80,6 +82,22 @@ extern void check_gl_error (const char *type);
 }
 
 
+#ifdef USE_IPHONE
+/* With GL programs, drawing at full resolution isn't a problem.
+ */
+- (CGFloat) hackedContentScaleFactor
+{
+  NSSize ssize = [[[UIScreen mainScreen] currentMode] size];
+  NSSize bsize = [self bounds].size;
+
+  // Ratio of screen size in pixels to view size in points.
+  GLfloat s = ((ssize.width > ssize.height ? ssize.width : ssize.height) /
+               (bsize.width > bsize.height ? bsize.width : bsize.height));
+  return s;
+}
+#endif // USE_IPHONE
+
+
 - (void) setOglContext: (NSOpenGLContext *) ctx
 {
   ogl_ctx = ctx;
@@ -87,9 +105,9 @@ extern void check_gl_error (const char *type);
 # ifdef USE_IPHONE
   [EAGLContext setCurrentContext: ogl_ctx];
 
-  double s = self.contentScaleFactor;
-  int w = s * [self frame].size.width;
-  int h = s * [self frame].size.height;
+  double s = [self hackedContentScaleFactor];
+  int w = s * [self bounds].size.width;
+  int h = s * [self bounds].size.height;
 
   if (gl_framebuffer)  glDeleteFramebuffersOES  (1, &gl_framebuffer);
   if (gl_renderbuffer) glDeleteRenderbuffersOES (1, &gl_renderbuffer);
@@ -171,11 +189,21 @@ extern void check_gl_error (const char *type);
     return [CAEAGLLayer class];
 }
 
+- (void) swapBuffers
+{
+  glBindRenderbufferOES (GL_RENDERBUFFER_OES, gl_renderbuffer);
+  [ogl_ctx presentRenderbuffer:GL_RENDERBUFFER_OES];
+}
+#endif // USE_IPHONE
+
+
+#ifdef USE_BACKBUFFER
+
+- (void) initLayer
+{
+  // Do nothing.
+}
 
-/* On MacOS:   drawRect does nothing, and animateOneFrame renders.
-   On iOS GL:  drawRect does nothing, and animateOneFrame renders.
-   On iOS X11: drawRect renders, and animateOneFrame marks the view dirty.
- */
 - (void)drawRect:(NSRect)rect
 {
 }
@@ -183,9 +211,15 @@ extern void check_gl_error (const char *type);
 
 - (void) animateOneFrame
 {
+# ifdef USE_IPHONE
   UIGraphicsPushContext (backbuffer);
+# endif
+
   [self render_x11];
+
+# ifdef USE_IPHONE
   UIGraphicsPopContext();
+# endif
 }
 
 
@@ -195,34 +229,31 @@ extern void check_gl_error (const char *type);
    and discarded.  That's ok, though, because mostly it's just calls to
    XClearWindow and housekeeping stuff like that.  So we make a tiny one.
  */
-- (void) createBackbuffer
+- (void) createBackbuffer:(CGSize)new_size
 {
-  // Don't resize the X11 window to match rotation. 
-  // Rotation and scaling are handled in GL.
-  //
-  NSRect f = [self frame];
-  double s = self.contentScaleFactor;
-  backbuffer_size.width  = (int) (s * f.size.width);
-  backbuffer_size.height = (int) (s * f.size.height);
+  backbuffer_size = new_size;
 
   if (! backbuffer) {
     CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB();
     int w = 8;
     int h = 8;
-    backbuffer = CGBitmapContextCreate (NULL, w, h,
+    backbuffer = CGBitmapContextCreate (NULL, w, h,   // yup, only 8px x 8px.
                                         8, w*4, cs,
                                         kCGImageAlphaPremultipliedLast);
     CGColorSpaceRelease (cs);
   }
 }
+# endif // USE_BACKBUFFER
 
 
-- (void) swapBuffers
+/* When changing the device orientation, leave the X11 Window and glViewport
+   in portrait configuration.  OpenGL hacks examine current_device_rotation()
+   within the scene as needed.
+ */
+- (BOOL)reshapeRotatedWindow
 {
-  glBindRenderbufferOES (GL_RENDERBUFFER_OES, gl_renderbuffer);
-  [ogl_ctx presentRenderbuffer:GL_RENDERBUFFER_OES];
+  return NO;
 }
-# endif // USE_IPHONE
 
 
 - (void)dealloc {
@@ -240,14 +271,19 @@ extern void check_gl_error (const char *type);
  */
 
 
-// redefine these now since they don't work when not inside an ObjC method.
+// redefine NSAssert, etc. here since they don't work when not inside
+// an ObjC method.
 
 #undef NSAssert
 #undef NSAssert1
 #undef NSAssert2
-#define NSAssert(CC,S)      do { if (!(CC)) { NSLog(S);    abort();}} while(0)
-#define NSAssert1(CC,S,A)   do { if (!(CC)) { NSLog(S,A);  abort();}} while(0)
-#define NSAssert2(CC,S,A,B) do { if (!(CC)) { NSLog(S,A,B);abort();}} while(0)
+#define NSASS(S) \
+  jwxyz_abort ("%s", [(S) cStringUsingEncoding:NSUTF8StringEncoding])
+#define NSAssert(CC,S)      do { if (!(CC)) { NSASS((S)); }} while(0)
+#define NSAssert1(CC,S,A)   do { if (!(CC)) { \
+  NSASS(([NSString stringWithFormat: S, A])); }} while(0)
+#define NSAssert2(CC,S,A,B) do { if (!(CC)) { \
+  NSASS(([NSString stringWithFormat: S, A, B])); }} while(0)
 
 
 /* Called by OpenGL savers using the XLockmore API.
@@ -308,6 +344,7 @@ init_GL (ModeInfo *mi)
 
     NSAssert (pixfmt, @"unable to create NSOpenGLPixelFormat");
 
+    // #### Analyze says: "Potential leak of an object stored into pixfmt"
     ctx = [[NSOpenGLContext alloc] 
             initWithFormat:pixfmt
               shareContext:nil];
@@ -319,9 +356,8 @@ init_GL (ModeInfo *mi)
   [ctx setValues:&r forParameter:NSOpenGLCPSwapInterval];
 //  check_gl_error ("NSOpenGLCPSwapInterval");  // SEGV sometimes. Too early?
 
-  // #### "Build and Analyze" says that ctx leaks, because it doesn't
-  //      seem to realize that makeCurrentContext retains it (right?)
-  //      Not sure what to do to make this warning go away.
+  // #### Analyze says: "Potential leak of an object stored into "ctx"
+  // But makeCurrentContext retains it (right?)
 
   [ctx makeCurrentContext];
   check_gl_error ("makeCurrentContext");
@@ -367,9 +403,12 @@ init_GL (ModeInfo *mi)
     eagl_layer.opaque = TRUE;
     eagl_layer.drawableProperties = 
       [NSDictionary dictionaryWithObjectsAndKeys:
-      kEAGLColorFormatRGBA8,             kEAGLDrawablePropertyColorFormat,
-      [NSNumber numberWithBool:!dbuf_p], kEAGLDrawablePropertyRetainedBacking,
-      nil];
+       kEAGLColorFormatRGBA8,             kEAGLDrawablePropertyColorFormat,
+       [NSNumber numberWithBool:!dbuf_p], kEAGLDrawablePropertyRetainedBacking,
+       nil];
+
+    // Without this, the GL frame buffer is half the screen resolution!
+    eagl_layer.contentsScale = [UIScreen mainScreen].scale;
 
     ogl_ctx = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
   }
@@ -377,11 +416,25 @@ init_GL (ModeInfo *mi)
   if (!ogl_ctx)
     return 0;
   [view setOglContext:ogl_ctx];
+  // #### Analyze says "Potential leak of an object stored into ogl_ctx"
 
   check_gl_error ("OES_init");
 
+  jwzgles_reset ();
+  
 # endif // USE_IPHONE
 
+  // I don't know why this is necessary, but it beats randomly having some
+  // textures be upside down.
+  //
+  glMatrixMode(GL_TEXTURE);
+  glLoadIdentity();
+  glMatrixMode(GL_PROJECTION);
+  glLoadIdentity();
+  glMatrixMode(GL_MODELVIEW);
+  glLoadIdentity();
+
+
   // Caller expects a pointer to an opaque struct...  which it dereferences.
   // Don't ask me, it's historical...
   static int blort = -1;