netgen/ng/Togl2.1/toglNSOpenGL.c
2016-02-22 09:21:47 +01:00

207 lines
7.0 KiB
C

/* $Id: toglNSOpenGL.c,v 1.7 2009/10/22 00:06:41 gregcouch Exp $ */
/* vi:set sw=4 expandtab: */
/*
* Togl - a Tk OpenGL widget
*
* Copyright (C) 1996-2002 Brian Paul and Ben Bederson
* Copyright (C) 2005-2009 Greg Couch
* See the LICENSE file for copyright details.
*/
static NSOpenGLPixelFormat *
togl_pixelFormat(Togl *togl)
{
NSOpenGLPixelFormatAttribute attribs[32];
int na = 0;
NSOpenGLPixelFormat *pix;
#if 0
if (togl->MultisampleFlag && !hasMultisampling) {
Tcl_SetResult(togl->Interp,
TCL_STUPID "multisampling not supported", TCL_STATIC);
return NULL;
}
#endif
if (togl->PbufferFlag && !togl->RgbaFlag) {
Tcl_SetResult(togl->Interp,
TCL_STUPID "puffer must be RGB[A]", TCL_STATIC);
return NULL;
}
attribs[na++] = NSOpenGLPFAMinimumPolicy;
/* ask for hardware-accelerated onscreen */
attribs[na++] = NSOpenGLPFAAccelerated;
attribs[na++] = NSOpenGLPFANoRecovery;
if (togl->RgbaFlag) {
/* RGB[A] mode */
attribs[na++] = NSOpenGLPFAColorSize;
attribs[na++] = togl->RgbaRed + togl->RgbaGreen + togl->RgbaBlue;
/* NSOpenGL does not take separate red,green,blue sizes. */
if (togl->AlphaFlag) {
attribs[na++] = NSOpenGLPFAAlphaSize;
attribs[na++] = togl->AlphaSize;
}
} else {
/* Color index mode */
Tcl_SetResult(togl->Interp,
TCL_STUPID "Color index mode not supported", TCL_STATIC);
return NULL;
}
if (togl->DepthFlag) {
attribs[na++] = NSOpenGLPFADepthSize;
attribs[na++] = togl->DepthSize;
}
if (togl->DoubleFlag) {
attribs[na++] = NSOpenGLPFADoubleBuffer;
}
if (togl->StencilFlag) {
attribs[na++] = NSOpenGLPFAStencilSize;
attribs[na++] = togl->StencilSize;
}
if (togl->AccumFlag) {
attribs[na++] = NSOpenGLPFAAccumSize;
attribs[na++] = togl->AccumRed + togl->AccumGreen + togl->AccumBlue + (togl->AlphaFlag ? togl->AccumAlpha : 0);
}
if (togl->MultisampleFlag) {
attribs[na++] = NSOpenGLPFAMultisample;
attribs[na++] = NSOpenGLPFASampleBuffers;
attribs[na++] = 1;
attribs[na++] = NSOpenGLPFASamples;
attribs[na++] = 2;
}
if (togl->AuxNumber != 0) {
attribs[na++] = NSOpenGLPFAAuxBuffers;
attribs[na++] = togl->AuxNumber;
}
if (togl->Stereo == TOGL_STEREO_NATIVE) {
attribs[na++] = NSOpenGLPFAStereo;
}
if (togl->FullscreenFlag) {
attribs[na++] = NSOpenGLPFAFullScreen;
}
attribs[na++] = 0; /* End of attributes. */
pix = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
if (pix == nil) {
Tcl_SetResult(togl->Interp, TCL_STUPID "couldn't choose pixel format",
TCL_STATIC);
return NULL;
}
return pix;
}
static int
togl_describePixelFormat(Togl *togl)
{
NSOpenGLPixelFormat *pfmt = togl->PixelFormat;
/* fill in RgbaFlag, DoubleFlag, and Stereo */
GLint has_rgba, has_doublebuf, has_depth, has_accum, has_alpha,
has_stencil, has_stereo, has_multisample;
GLint vscr = 0;
[pfmt getValues:&has_rgba forAttribute:NSOpenGLPFAColorSize forVirtualScreen:vscr];
[pfmt getValues:&has_doublebuf forAttribute:NSOpenGLPFADoubleBuffer forVirtualScreen:vscr];
[pfmt getValues:&has_depth forAttribute:NSOpenGLPFADepthSize forVirtualScreen:vscr];
[pfmt getValues:&has_accum forAttribute:NSOpenGLPFAAccumSize forVirtualScreen:vscr];
[pfmt getValues:&has_alpha forAttribute:NSOpenGLPFAAlphaSize forVirtualScreen:vscr];
[pfmt getValues:&has_stencil forAttribute:NSOpenGLPFAStencilSize forVirtualScreen:vscr];
[pfmt getValues:&has_stereo forAttribute:NSOpenGLPFAStereo forVirtualScreen:vscr];
[pfmt getValues:&has_multisample forAttribute:NSOpenGLPFASampleBuffers forVirtualScreen:vscr];
togl->RgbaFlag = (has_rgba != 0);
togl->DoubleFlag = (has_doublebuf != 0);
togl->DepthFlag = (has_depth != 0);
togl->AccumFlag = (has_accum != 0);
togl->AlphaFlag = (has_alpha != 0);
togl->StencilFlag = (has_stencil != 0);
togl->Stereo = (has_stereo ? TOGL_STEREO_NATIVE : TOGL_STEREO_NONE);
togl->MultisampleFlag = (has_multisample != 0);
return True;
}
#define isPow2(x) (((x) & ((x) - 1)) == 0)
static NSOpenGLPixelBuffer *
togl_createPbuffer(Togl *togl)
{
GLint min_size[2], max_size[2];
Bool hasPbuffer;
const char *extensions;
GLint target;
GLint virtualScreen;
NSOpenGLPixelBuffer *pbuf;
extensions = (const char *) glGetString(GL_EXTENSIONS);
hasPbuffer = (strstr(extensions, "GL_APPLE_pixel_buffer") != NULL);
if (!hasPbuffer) {
Tcl_SetResult(togl->Interp,
TCL_STUPID "pbuffers are not supported", TCL_STATIC);
return NULL;
}
glGetIntegerv(GL_MIN_PBUFFER_VIEWPORT_DIMS_APPLE, min_size);
glGetIntegerv(GL_MAX_VIEWPORT_DIMS, max_size);
virtualScreen = [togl->Ctx currentVirtualScreen];
for (;;) {
/* make sure we don't exceed the maximum size because if we do,
* NSOpenGLPixelBuffer allocationmay succeed and later uses of
* the pbuffer fail
*/
if (togl->Width < min_size[0])
togl->Width = min_size[0];
else if (togl->Width > max_size[0]) {
if (togl->LargestPbufferFlag)
togl->Width = max_size[0];
else {
Tcl_SetResult(togl->Interp,
TCL_STUPID "pbuffer too large", TCL_STATIC);
return NULL;
}
}
if (togl->Height < min_size[1])
togl->Height = min_size[1];
else if (togl->Height > max_size[1]) {
if (togl->LargestPbufferFlag)
togl->Height = max_size[1];
else {
Tcl_SetResult(togl->Interp,
TCL_STUPID "pbuffer too large", TCL_STATIC);
return NULL;
}
}
if (isPow2(togl->Width) && isPow2(togl->Height))
target = GL_TEXTURE_2D;
else
target = GL_TEXTURE_RECTANGLE_ARB;
pbuf = [[NSOpenGLPixelBuffer alloc] initWithTextureTarget:target
textureInternalFormat:(togl->AlphaFlag ? GL_RGBA : GL_RGB)
textureMaxMipMapLevel:0
pixelsWide:togl->Width pixelsHigh:togl->Height];
if (pbuf != nil) {
/* setPixelBuffer allocates the framebuffer space */
[togl->Ctx setPixelBuffer:pbuf cubeMapFace:0 mipMapLevel:0
currentVirtualScreen:virtualScreen];
return pbuf;
}
if (!togl->LargestPbufferFlag
|| togl->Width == min_size[0] || togl->Height == min_size[1]) {
Tcl_SetResult(togl->Interp,
TCL_STUPID "unable to create pbuffer", TCL_STATIC);
return NULL;
}
/* largest unavailable, try something smaller */
togl->Width = togl->Width / 2 + togl->Width % 2;
togl->Height = togl->Width / 2 + togl->Height % 2;
}
}
static void
togl_destroyPbuffer(Togl *togl)
{
[togl->pbuf release];
}