diff options
author | Paolo Bonzini <bonzini@gnu.org> | 2008-11-19 14:43:01 +0100 |
---|---|---|
committer | Nicolas Bruguier <nicolas.bruguier@supersonicimagine.fr> | 2008-11-29 14:09:31 +0100 |
commit | 49e45fb1b8dc0f2b45254a370c62a0e36ca7be91 (patch) | |
tree | cf1fc537356a2677ab55b9ccb2cdf11e489e883b /examples | |
parent | 87ea1a8b8a37a75e9859428e943fd8e0e41cdebb (diff) |
[cgl] Add glitz-cgl backend
The backend is mostly derived from the AGL backend, but allows creating
drawable on Cocoa NSView objects (*not* NSOpenGLView: the latter is
mostly a NSView + OpenGL contexts and pixel formats, which glitz manages
on its own). All the added files are Objective-C (.m).
The only changes with respect to the AGL backend were in the pixel
format queries that: 1) need to use CGL directly in order to avoid
logging messages for unavailable formats; 2) needed some tweaking in
order to find no-depth, no-stencil pbuffer formats (the new pbuffer
format discovery code actually does not need it, but it's better
to be safe; 3) have a slightly different sort order that is nicer (as
seen in the output of glitzinfo).
The renderer test's Objective-C bits in glitz_cgl.m has two parts in it.
One is the boilerplate that sets up Cocoa without using .nib files;
it can be useful only if you want to write a similar example program
for Glitz. I split the test-specific code in two (before parsing command
line/after parsing command line) to avoid showing the icon in the dock
if the program is going to exit very soon.
The second part is GlitzOpenGLView, which provides the bits of NSOpenGLView
that go beyond storing OpenGL contexts and pixel formats; see the "Custom
Cocoa OpenGL View" example from Apple. Programs using Glitz in their UI
should be able to recycle it pretty easily as it's just four methods (one
caveat: I didn't investigate how to deal with window resizes).
Diffstat (limited to 'examples')
-rw-r--r-- | examples/glitzinfo/Makefile.am | 10 | ||||
-rw-r--r-- | examples/glitzinfo/glitzinfo.c | 36 | ||||
-rw-r--r-- | examples/renderer-test/Makefile.am | 17 | ||||
-rw-r--r-- | examples/renderer-test/glitz_cgl.m | 315 |
4 files changed, 376 insertions, 2 deletions
diff --git a/examples/glitzinfo/Makefile.am b/examples/glitzinfo/Makefile.am index 22b74f7..a7b99d1 100644 --- a/examples/glitzinfo/Makefile.am +++ b/examples/glitzinfo/Makefile.am @@ -2,6 +2,16 @@ INCLUDES = $(GLITZ_INC) noinst_PROGRAMS = +if GLITZ_BUILD_CGL_BACKEND +noinst_PROGRAMS += glitzinfo-cgl + +glitzinfo_cgl_CFLAGS = $(GLITZ_CGL_CFLAGS) -DGLITZ_CGL_BACKEND + +glitzinfo_cgl_SOURCES = glitzinfo.c + +glitzinfo_cgl_LDADD = $(GLITZ_LIB) $(GLITZ_CGL_LIBS) +endif + if GLITZ_BUILD_AGL_BACKEND noinst_PROGRAMS += glitzinfo-agl diff --git a/examples/glitzinfo/glitzinfo.c b/examples/glitzinfo/glitzinfo.c index e5eb7e6..0b7719f 100644 --- a/examples/glitzinfo/glitzinfo.c +++ b/examples/glitzinfo/glitzinfo.c @@ -40,6 +40,10 @@ #include <glitz-agl.h> #endif +#ifdef GLITZ_CGL_BACKEND +#include <glitz-cgl.h> +#endif + static void print_features (unsigned long features) { @@ -245,6 +249,29 @@ main (int argc, char **argv) } #endif +#ifdef GLITZ_CGL_BACKEND + /* Cannot make a window, it's too expensive. Find a reasonably lame + window format and use it to create a pbuffer. */ + i = 0; + while ((dformat = glitz_cgl_find_window_format (0, 0, i)) != NULL + && (dformat->doublebuffer + || dformat->stencil_size + || dformat->depth_size)) + i++; + if (!dformat) + { + fprintf (stderr, "Error: couldn't find drawable format\n"); + return 1; + } + + drawable = glitz_cgl_create_pbuffer_drawable (dformat, 1, 1); + if (!drawable) + { + fprintf (stderr, "Error: couldn't create glitz pbuffer drawable\n"); + return 1; + } +#endif + print_features (glitz_drawable_get_features (drawable)); printf ("\nWindow formats:\n"); @@ -271,6 +298,11 @@ main (int argc, char **argv) i++; #endif +#ifdef GLITZ_CGL_BACKEND + while (print_format (glitz_cgl_find_window_format (0, 0, i))) + i++; +#endif + printf ("\nPbuffer formats:\n"); printf ("id\tr/g/b/a \tdepth\tstencil\tdb\tsamples\n"); printf ("-------------------------------------" @@ -343,5 +375,9 @@ main (int argc, char **argv) glitz_agl_fini (); #endif +#ifdef GLITZ_CGL_BACKEND + glitz_cgl_fini (); +#endif + return 0; } diff --git a/examples/renderer-test/Makefile.am b/examples/renderer-test/Makefile.am index ae0b624..71670a8 100644 --- a/examples/renderer-test/Makefile.am +++ b/examples/renderer-test/Makefile.am @@ -16,8 +16,7 @@ glitz_common_sources = \ glitz.c \ glitz_common.h -INCLUDES = $(GLITZ_INC) $(GLITZ_GLX_CFLAGS) $(GLITZ_EGL_CFLAGS) $(GLITZ_AGL_CFLAGS) \ - $(LIBPNG_CFLAGS) +INCLUDES = $(GLITZ_INC) $(LIBPNG_CFLAGS) if GLITZ_BUILD_GLX_BACKEND noinst_PROGRAMS += rendertest_glitz_glx @@ -26,6 +25,7 @@ rendertest_glitz_glx_SOURCES = \ $(glitz_common_sources) \ glitz_glx.c +INCLUDES += $(GLITZ_GLX_CFLAGS) rendertest_glitz_glx_LDADD = $(GLITZ_GLX_LIBS) $(LIBPNG_LIBS) -lm endif @@ -36,6 +36,7 @@ rendertest_glitz_egl_SOURCES = \ $(glitz_common_sources) \ glitz_egl.c +INCLUDES += $(GLITZ_EGL_CFLAGS) rendertest_glitz_egl_LDADD = $(GLITZ_EGL_LIBS) $(LIBPNG_LIBS) -lm endif @@ -46,7 +47,19 @@ rendertest_glitz_agl_SOURCES = \ $(glitz_common_sources) \ glitz_agl.c +INCLUDES += $(GLITZ_AGL_CFLAGS) rendertest_glitz_agl_LDADD = $(GLITZ_AGL_LIBS) $(CARBON_LIBS) $(LIBPNG_LIBS) -lm endif +if GLITZ_BUILD_CGL_BACKEND +noinst_PROGRAMS += rendertest_glitz_cgl + +rendertest_glitz_cgl_SOURCES = \ + $(glitz_common_sources) \ + glitz_cgl.m + +INCLUDES += $(GLITZ_CGL_CFLAGS) +rendertest_glitz_cgl_LDADD = $(GLITZ_CGL_LIBS) $(LIBPNG_LIBS) -lm +endif + endif diff --git a/examples/renderer-test/glitz_cgl.m b/examples/renderer-test/glitz_cgl.m new file mode 100644 index 0000000..1b4bbf3 --- /dev/null +++ b/examples/renderer-test/glitz_cgl.m @@ -0,0 +1,315 @@ +/* + * Copyright © 2004 David Reveman + * Copyright © 2008 Paolo Bonzini + * + * 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, and that the name of the + * copyright holders not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * The copyright holders make no representations about the suitability of + * this software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL DAVID REVEMAN BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: David Reveman <davidr@novell.com> + * Author: Paolo Bonzini <bonzini@gnu.org> + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdio.h> +#include <stdlib.h> + +#import <OpenGL/gl.h> +#import <OpenGL/glext.h> +#import <OpenGL/glu.h> + +#include "rendertest.h" +#include "glitz_common.h" +#include <glitz-cgl.h> +#import <Cocoa/Cocoa.h> + + +static NSAutoreleasePool *pool; +static NSObject *glitzMain; +static int rendertest_main (void); + +@interface GlitzOpenGLView : NSView +- (id)initWithFrame:(NSRect)frameRect; +- (BOOL)isOpaque; +- (void)update; +- (void) _surfaceNeedsUpdate:(NSNotification*)notification; +@end + +@interface GlitzMain : NSObject +@end + +/* The view class. A (very...) simplified version of CustomOpenGLView + from the Custom Cocoa OpenGL example. */ + +@implementation GlitzOpenGLView + +- (id)initWithFrame:(NSRect)frameRect +{ + self = [super initWithFrame:frameRect]; + [[NSNotificationCenter defaultCenter] + addObserver:self selector:@selector(_surfaceNeedsUpdate:) + name:NSViewGlobalFrameDidChangeNotification object:self]; + return self; +} + +- (BOOL)isOpaque +{ + return YES; +} + +- (void)update +{ + if ([[NSOpenGLContext currentContext] view] == self) { + [[NSOpenGLContext currentContext] update]; + } +} + +- (void) _surfaceNeedsUpdate:(NSNotification*)notification +{ + [self update]; +} + +@end + + + +/* The application delegate, which has the only purpose of firing + rendertest's main. */ + +@implementation GlitzMain + +/* Called when the internal event loop has just started running */ +- (void) applicationDidFinishLaunching: (NSNotification *) note +{ + int status = rendertest_main (); + + [glitzMain release]; + [pool release]; + exit (status); +} + +@end + +static NSView * +create_window (int width, int height) +{ + NSRect contentRect; + NSWindow *window; + NSView *view; + + contentRect = NSMakeRect (50, 50, width, height); + + /* Manually create a window, avoids having a nib file resource. We + do not care about NSMiniaturizableWindowMask and NSClosableWindowMask + because we do not handle events. NSResizableWindowMask wouldn't have + any effect for the same reason, but we explicitly do not want that. */ + window = [ [ NSWindow alloc ] + initWithContentRect: contentRect + styleMask: NSTitledWindowMask + backing: NSBackingStoreBuffered + defer: NO ]; + + if (window == nil) { + printf ("Could not create the Cocoa window\n"); + exit (1); + } + + [ window setTitle: @PACKAGE ]; + [ window setViewsNeedDisplay:NO ]; + + view = [ [ [ GlitzOpenGLView alloc ] init ] autorelease ]; + [ window setContentView: view ]; + [ window makeKeyAndOrderFront:nil ]; + return view; +} + + +static const render_backend_t _glitz_cgl_render_backend = { + _glitz_render_create_similar, + _glitz_render_destroy, + _glitz_render_composite, + _glitz_render_set_pixels, + _glitz_render_show, + _glitz_render_set_fill, + _glitz_render_set_component_alpha, + _glitz_render_set_transform, + _glitz_render_set_filter, + _glitz_render_set_clip_rectangles, + _glitz_render_set_clip_trapezoids +}; + +typedef struct cgl_options { + int samples; + int db; + int offscreen; +} cgl_options_t; + +static const render_option_t _cgl_options[] = { + { "single-buffer", 'l', NULL, 0, " use single buffered format" }, + { "samples", 'p', "SAMPLES", 0, " use this hardware multi-sample format" }, + { "offscreen", 'f', NULL, 0, " use offscreen rendering" }, + { 0 } +}; + +static int +_parse_option (int key, char *arg, render_arg_state_t *state) +{ + cgl_options_t *options = state->pointer; + + switch (key) { + case 'l': + options->db = 0; + break; + case 'p': + options->samples = atoi (arg); + break; + case 'f': + options->offscreen = 1; + break; + default: + return 1; + } + + return 0; +} + +static render_arg_state_t state; +static cgl_options_t options = { 1, 1, 0 }; + +static int +rendertest_main (void) +{ + int status; + render_surface_t surface; + glitz_drawable_format_t templ; + unsigned long mask; + glitz_drawable_format_t *dformat; + glitz_drawable_t *drawable, *offscreen = 0; + NSView *view; + + surface.backend = &_glitz_cgl_render_backend; + surface.flags = 0; + surface.width = RENDER_DEFAULT_DST_WIDTH; + surface.height = RENDER_DEFAULT_DST_HEIGHT; + + view = create_window (RENDER_DEFAULT_DST_WIDTH, RENDER_DEFAULT_DST_HEIGHT); + + templ.samples = options.samples; + mask = GLITZ_FORMAT_SAMPLES_MASK; + + if (options.db) + templ.doublebuffer = 1; + else + templ.doublebuffer = 0; + + mask |= GLITZ_FORMAT_DOUBLEBUFFER_MASK; + + dformat = glitz_cgl_find_window_format (mask, &templ, 0); + if (!dformat) { + fprintf (stderr, "Error: couldn't find window format\n"); + return 1; + } + + drawable = + glitz_cgl_create_drawable_for_view (dformat, view, + surface.width, surface.height); + if (!drawable) { + fprintf (stderr, "Error: couldn't create glitz drawable for view\n"); + return 1; + } + + if (options.offscreen) + { + dformat = glitz_find_drawable_format (drawable, 0, 0, 0); + if (!dformat) + { + fprintf (stderr, "Error: couldn't find offscreen format\n"); + return 1; + } + + offscreen = glitz_create_drawable (drawable, dformat, + surface.width, surface.height); + if (!offscreen) + { + fprintf (stderr, "Error: couldn't create offscreen drawable\n"); + return 1; + } + + surface.surface = + _glitz_create_and_attach_surface_to_drawable (drawable, + offscreen, + surface.width, + surface.height); + } + else + { + surface.surface = + _glitz_create_and_attach_surface_to_drawable (drawable, + drawable, + surface.width, + surface.height); + } + + if (!surface.surface) + return 1; + + status = render_run (&surface, &state.settings); + + glitz_surface_destroy ((glitz_surface_t *) surface.surface); + + if (offscreen) + glitz_drawable_destroy (offscreen); + + glitz_drawable_destroy (drawable); + + glitz_cgl_fini (); + + return status; +} + + +int main(int argc, char *argv[]) +{ + ProcessSerialNumber psn; + + state.pointer = &options; + if (render_parse_arguments (_parse_option, + _cgl_options, + &state, + argc, argv)) + return 1; + + /* Add the icon to the dock. */ + if (!GetCurrentProcess(&psn)) { + TransformProcessType(&psn, kProcessTransformToForegroundApplication); + SetFrontProcess(&psn); + } + + pool = [[NSAutoreleasePool alloc] init]; + [NSApplication sharedApplication]; + [NSApp finishLaunching]; + + /* Create GlitzMain and make it the app delegate */ + glitzMain = [[GlitzMain alloc] init]; + [NSApp setDelegate: glitzMain]; + [NSApp run]; + return 0; +} |