1 /*
   2  * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #import "GlassOffscreen.h"
  27 
  28 #import "GlassFrameBufferObject.h"
  29 //#import "GlassPBuffer.h"
  30 
  31 //#define VERBOSE
  32 #ifndef VERBOSE
  33     #define LOG(MSG, ...)
  34 #else
  35     #define LOG(MSG, ...) GLASS_LOG(MSG, ## __VA_ARGS__);
  36 #endif
  37 
  38 @interface GlassOffscreen ()
  39 - (void)setContext;
  40 - (void)unsetContext;
  41 @end
  42 
  43 @implementation GlassOffscreen
  44 
  45 - (id)initWithContext:(CGLContextObj)ctx
  46 {
  47     self = [super init];
  48     if (self != nil)
  49     {
  50         self->_ctx = CGLRetainContext(ctx);
  51         
  52         self->_backgroundR = 1.0f;
  53         self->_backgroundG = 1.0f;
  54         self->_backgroundB = 1.0f;
  55         self->_backgroundA = 1.0f;
  56         
  57         [self setContext];
  58         {
  59             self->_offscreen = [[GlassFrameBufferObject alloc] init];
  60             if (self->_offscreen == nil)
  61             {
  62                 // TODO: implement PBuffer if needed
  63                 //self->_offscreen = [[GlassPBuffer alloc] init];
  64             }
  65         }
  66         [self unsetContext];
  67     }
  68     return self;
  69 }
  70 
  71 - (CGLContextObj)getContext;
  72 {
  73     return self->_ctx;
  74 }
  75 
  76 - (void)dealloc
  77 {
  78     [self setContext];
  79     {
  80         [(NSObject*)self->_offscreen release];
  81         self->_offscreen = NULL;
  82     }
  83     [self unsetContext];
  84 
  85     CGLReleaseContext(self->_ctx);
  86     self->_ctx = NULL;
  87 
  88     [super dealloc];
  89 }
  90 
  91 - (void)setBackgroundColor:(NSColor*)color
  92 {
  93     self->_backgroundR = (GLfloat)[color redComponent];
  94     self->_backgroundG = (GLfloat)[color greenComponent];
  95     self->_backgroundB = (GLfloat)[color blueComponent];
  96     self->_backgroundA = (GLfloat)[color alphaComponent];
  97 }
  98 
  99 - (GLuint)width
 100 {
 101     return [self->_offscreen width];
 102 }
 103 
 104 - (GLuint)height
 105 {
 106     return [self->_offscreen height];
 107 }
 108 
 109 - (GLuint)fbo
 110 {
 111     return [self->_offscreen fbo];
 112 }
 113 
 114 - (CAOpenGLLayer*)getLayer
 115 {
 116     return _layer;
 117 }
 118 
 119 - (void)setLayer:(CAOpenGLLayer*)new_layer
 120 {
 121     //Set a weak reference as layer owns offscreen
 122     self->_layer = new_layer;
 123 }
 124 
 125 - (void)setContext
 126 {
 127     self->_ctxToRestore = CGLGetCurrentContext();
 128     CGLLockContext(self->_ctx);
 129     CGLSetCurrentContext(self->_ctx);
 130 }
 131 
 132 - (void)unsetContext
 133 {
 134     CGLSetCurrentContext(self->_ctxToRestore);    
 135     CGLUnlockContext(self->_ctx);
 136 }
 137 
 138 - (void)bindForWidth:(GLuint)width andHeight:(GLuint)height
 139 {
 140     [self setContext];
 141     [self->_offscreen bindForWidth:width andHeight:height];
 142     [self unsetContext];
 143 }
 144 
 145 - (void)blit
 146 {
 147     [self blitForWidth:[self->_offscreen width] andHeight:[self->_offscreen height]];
 148 }
 149 
 150 - (GLuint)texture
 151 {
 152     return [self->_offscreen texture];
 153 }
 154 
 155 - (void)blitForWidth:(GLuint)width andHeight:(GLuint)height
 156 {
 157     {
 158 #if 1
 159         glClearColor(self->_backgroundR, self->_backgroundG, self->_backgroundB, self->_backgroundA);
 160         glClear(GL_COLOR_BUFFER_BIT);
 161 #else
 162         // for debugging, change clear color every 0.5 seconds
 163         static int counterFps = 0;
 164         static int counterColor = 0;
 165         counterFps++;
 166         if ((counterFps%(60/2)) == 0)
 167         {
 168             counterColor++;
 169         }
 170         switch (counterColor%3)
 171         {
 172             case 0:
 173                 glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
 174                 break;
 175             case 1:
 176                 glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
 177                 break;
 178             case 2:
 179                 glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
 180                 break;
 181         }
 182         glClear(GL_COLOR_BUFFER_BIT);
 183 #endif        
 184         [self->_offscreen blitForWidth:width andHeight:height];
 185         
 186         self->_dirty = GL_FALSE;
 187     }
 188 }
 189 
 190 - (GLboolean)isDirty
 191 {
 192     return self->_dirty;
 193 }
 194 
 195 - (void)blitFromOffscreen:(GlassOffscreen*) other_offscreen
 196 {
 197     [self setContext];
 198     {
 199         [(GlassFrameBufferObject*)self->_offscreen blitFromFBO:(GlassFrameBufferObject*)other_offscreen->_offscreen];
 200         self->_dirty = GL_TRUE;
 201     }
 202     [self unsetContext];
 203 }
 204 
 205 @end