2 Copyright (C) 2011 Paul Davis
3 Copyright (C) 2012 David Robillard <http://drobilla.net>
4 Copyright (C) 2017 Robin Gareus <robin@gareus.org>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 /* include order matter due to apple defines */
23 #include <gtkmm/window.h>
25 #include "gtkmm2ext/cairo_canvas.h"
26 #include "gtkmm2ext/nsglview.h"
27 #include "gtkmm2ext/rgb_macros.h"
29 #include <gdk/gdkquartz.h>
31 #include <OpenGL/gl.h>
32 #import <Cocoa/Cocoa.h>
34 #ifndef ARDOUR_CANVAS_NSVIEW_TAG
35 #define ARDOUR_CANVAS_NSVIEW_TAG 0xa2d0c2c4
38 __attribute__ ((visibility ("hidden")))
39 @interface ArdourCanvasOpenGLView : NSOpenGLView
42 unsigned int _texture_id;
45 Cairo::RefPtr<Cairo::ImageSurface> surf;
46 Gtkmm2ext::CairoCanvas *cairo_canvas;
49 @property (readwrite) NSInteger tag;
51 - (id) initWithFrame:(NSRect)frame;
53 - (void) setCairoCanvas:(Gtkmm2ext::CairoCanvas*)c;
55 - (void) drawRect:(NSRect)rect;
56 - (BOOL) canBecomeKeyWindow:(id)sender;
57 - (BOOL) acceptsFirstResponder:(id)sender;
61 @implementation ArdourCanvasOpenGLView
63 @synthesize tag = _tag;
65 - (id) initWithFrame:(NSRect)frame
67 NSOpenGLPixelFormatAttribute pixelAttribs[16] = {
68 NSOpenGLPFADoubleBuffer,
69 NSOpenGLPFAAccelerated,
70 NSOpenGLPFAColorSize, 32,
71 NSOpenGLPFADepthSize, 32,
72 NSOpenGLPFAMultisample,
73 NSOpenGLPFASampleBuffers, 1,
74 NSOpenGLPFASamples, 4,
78 NSOpenGLPixelFormat* pixelFormat =
79 [[NSOpenGLPixelFormat alloc] initWithAttributes:pixelAttribs];
82 self = [super initWithFrame:frame pixelFormat:pixelFormat];
83 [pixelFormat release];
85 self = [super initWithFrame:frame];
93 self.tag = ARDOUR_CANVAS_NSVIEW_TAG;
94 [[self openGLContext] makeCurrentContext];
95 glClearColor (0.0f, 0.0f, 0.0f, 0.0f);
96 glDisable (GL_DEPTH_TEST);
98 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
99 glEnable (GL_TEXTURE_RECTANGLE_ARB);
100 [NSOpenGLContext clearCurrentContext];
109 [[self openGLContext] makeCurrentContext];
110 glDeleteTextures (1, &_texture_id);
111 [NSOpenGLContext clearCurrentContext];
116 - (void) setCairoCanvas:(Gtkmm2ext::CairoCanvas*)c
121 - (BOOL) canBecomeKeyWindow:(id)sender{
125 - (BOOL) acceptsFirstResponder:(id)sender{
131 [[self openGLContext] update];
133 NSRect bounds = [self bounds];
134 int width = bounds.size.width;
135 int height = bounds.size.height;
137 if (_width == width && _height == height) {
141 [[self openGLContext] makeCurrentContext];
143 glViewport (0, 0, width, height);
144 glMatrixMode (GL_PROJECTION);
146 glOrtho (-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f);
148 glClear (GL_COLOR_BUFFER_BIT);
150 glDeleteTextures (1, &_texture_id);
151 glGenTextures (1, &_texture_id);
152 glBindTexture (GL_TEXTURE_RECTANGLE_ARB, _texture_id);
153 glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8,
155 GL_BGRA, GL_UNSIGNED_BYTE, NULL);
156 glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
158 glMatrixMode(GL_MODELVIEW);
161 [NSOpenGLContext clearCurrentContext];
167 - (void) drawRect:(NSRect)rect
169 [[self openGLContext] makeCurrentContext];
171 glMatrixMode(GL_MODELVIEW);
173 glClear(GL_COLOR_BUFFER_BIT);
175 /* call back into CairoCanvas */
176 cairo_rectangle_t cairo_rect;
178 cairo_rect.x = rect.origin.x;
179 cairo_rect.y = rect.origin.y;
180 cairo_rect.width = rect.size.width;
181 cairo_rect.height = rect.size.height;
183 if (!surf || surf->get_width () != _width || surf->get_height() != _height) {
184 surf = Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, _width, _height);
188 cairo_rect.width = _width;
189 cairo_rect.height = _height;
192 Cairo::RefPtr<Cairo::Context> ctx = Cairo::Context::create (surf);
194 // TODO: check retina screen, scaling factor.
195 // cairo_surface_get_device_scale () or explicit scale
197 ctx->rectangle (cairo_rect.x, cairo_rect.y, cairo_rect.width, cairo_rect.height);
198 ctx->clip_preserve ();
200 /* draw background color */
201 uint32_t col = cairo_canvas->background_color ();
203 UINT_TO_RGBA (col, &r, &g, &b, &a);
204 ctx->set_source_rgba (r/255.0, g/255.0, b/255.0, a/255.0);
208 cairo_canvas->render (ctx, &cairo_rect);
211 uint8_t* imgdata = surf->get_data ();
213 /* NOTE for big-endian (PPC), we'd need to flip byte-order
214 * RGBA <> RGBA for the texture.
215 * GtkCanvas does not use this nsview for PPC builds, yet
218 /* continue OpenGL */
221 glEnable(GL_TEXTURE_2D);
222 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, _texture_id);
223 glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8,
224 _width, _height, /*border*/ 0,
225 GL_BGRA, GL_UNSIGNED_BYTE, imgdata);
228 glTexCoord2f( 0.0f, (GLfloat) _height);
229 glVertex2f(-1.0f, -1.0f);
231 glTexCoord2f((GLfloat) _width, (GLfloat) _height);
232 glVertex2f( 1.0f, -1.0f);
234 glTexCoord2f((GLfloat) _width, 0.0f);
235 glVertex2f( 1.0f, 1.0f);
237 glTexCoord2f( 0.0f, 0.0f);
238 glVertex2f(-1.0f, 1.0f);
241 glDisable(GL_TEXTURE_2D);
248 [NSOpenGLContext clearCurrentContext];
254 Gtkmm2ext::nsglview_create (Gtkmm2ext::CairoCanvas* canvas)
256 ArdourCanvasOpenGLView* gl_view = [ArdourCanvasOpenGLView new];
260 [gl_view setCairoCanvas:canvas];
261 [gl_view setHidden:YES];
266 Gtkmm2ext::nsglview_overlay (void* glv, GdkWindow* window)
268 ArdourCanvasOpenGLView* gl_view = (ArdourCanvasOpenGLView*) glv;
269 NSView* view = gdk_quartz_window_get_nsview (window);
270 [view addSubview:gl_view];
274 Gtkmm2ext::nsglview_resize (void* glv, int x, int y, int w, int h)
276 ArdourCanvasOpenGLView* gl_view = (ArdourCanvasOpenGLView*) glv;
277 [gl_view setFrame:NSMakeRect(x, y, w, h)];
281 Gtkmm2ext::nsglview_queue_draw (void* glv, int x, int y, int w, int h)
283 ArdourCanvasOpenGLView* gl_view = (ArdourCanvasOpenGLView*) glv;
284 [gl_view setNeedsDisplayInRect:NSMakeRect(x, y, w, h)];
288 Gtkmm2ext::nsglview_set_visible (void* glv, bool vis)
290 ArdourCanvasOpenGLView* gl_view = (ArdourCanvasOpenGLView*) glv;
292 [gl_view setHidden:NO];
294 [gl_view setHidden:YES];