📄 macosx_glimp.m
字号:
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#import "macosx_glimp.h"
#include "tr_local.h"
#import "macosx_local.h"
#import "macosx_display.h"
#import "macosx_timers.h"
#import <AppKit/AppKit.h>
#import <Foundation/Foundation.h>
#import <mach-o/dyld.h>
#import <mach/mach.h>
#import <mach/mach_error.h>
cvar_t *r_allowSoftwareGL; // don't abort out if the pixelformat claims software
cvar_t *r_enablerender; // Enable actual rendering
cvar_t *r_appleTransformHint; // Enable Apple transform hint
static void GLW_InitExtensions( void );
static qboolean CreateGameWindow( qboolean isSecondTry );
static unsigned long Sys_QueryVideoMemory();
static CGDisplayErr Sys_CaptureActiveDisplays(void);
glwstate_t glw_state;
qboolean Sys_IsHidden = qfalse;
#ifdef OMNI_TIMER
OTStampList glThreadStampList;
#endif
@interface NSOpenGLContext (CGLContextAccess)
- (CGLContextObj) cglContext;
@end
@implementation NSOpenGLContext (CGLContextAccess)
- (CGLContextObj) cglContext;
{
return _contextAuxiliary;
}
@end
/*
============
CheckErrors
============
*/
void CheckErrors( void )
{
GLenum err;
err = qglGetError();
if ( err != GL_NO_ERROR ) {
ri.Error( ERR_FATAL, "glGetError: %s\n", qglGetString( err ) );
}
}
#if !defined(NDEBUG) && defined(QGL_CHECK_GL_ERRORS)
unsigned int QGLBeginStarted = 0;
void QGLErrorBreak(void)
{
}
void QGLCheckError(const char *message)
{
GLenum error;
static unsigned int errorCount = 0;
error = _glGetError();
if (error != GL_NO_ERROR) {
if (errorCount == 100) {
Com_Printf("100 GL errors printed ... disabling further error reporting.\n");
} else if (errorCount < 100) {
if (errorCount == 0) {
fprintf(stderr, "BREAK ON QGLErrorBreak to stop at the GL errors\n");
}
fprintf(stderr, "OpenGL Error(%s): 0x%04x -- %s\n", message, (int)error, gluErrorString(error));
QGLErrorBreak();
}
errorCount++;
}
}
#endif
/*
** GLimp_SetMode
*/
qboolean GLimp_SetMode( qboolean isSecondTry )
{
if ( !CreateGameWindow(isSecondTry) ) {
ri.Printf( PRINT_ALL, "GLimp_Init: window could not be created!\n" );
return qfalse;
}
// draw something to show that GL is alive
if (r_enablerender->integer) {
qglClearColor( 0.5, 0.5, 0.7, 0 );
qglClear( GL_COLOR_BUFFER_BIT );
GLimp_EndFrame();
qglClearColor( 0.5, 0.5, 0.7, 0 );
qglClear( GL_COLOR_BUFFER_BIT );
GLimp_EndFrame();
}
Sys_UnfadeScreen(Sys_DisplayToUse(), NULL);
CheckErrors();
return qtrue;
}
/*
=================
GetPixelAttributes
=================
*/
#define ADD_ATTR(x) \
do { \
if (attributeIndex >= attributeSize) { \
attributeSize *= 2; \
pixelAttributes = NSZoneRealloc(NULL, pixelAttributes, sizeof(*pixelAttributes) * attributeSize); \
} \
pixelAttributes[attributeIndex] = x; \
attributeIndex++; \
if (verbose) { \
ri.Printf(PRINT_ALL, "Adding pixel attribute: %d (%s)\n", x, #x); \
} \
} while(0)
static NSOpenGLPixelFormatAttribute *GetPixelAttributes()
{
NSOpenGLPixelFormatAttribute *pixelAttributes;
unsigned int attributeIndex = 0;
unsigned int attributeSize = 128;
int verbose = 0;
unsigned int colorDepth;
verbose = r_verbose->integer;
pixelAttributes = NSZoneMalloc(NULL, sizeof(*pixelAttributes) * attributeSize);
if (r_fullscreen->integer) {
ADD_ATTR(NSOpenGLPFAFullScreen);
// Since we are fullscreen, specify the screen that we need.
ADD_ATTR(NSOpenGLPFAScreenMask);
ADD_ATTR(CGDisplayIDToOpenGLDisplayMask(Sys_DisplayToUse()));
}
// Require hardware acceleration unless otherwise directed
if (!r_allowSoftwareGL->integer) {
ADD_ATTR(NSOpenGLPFAAccelerated);
}
// Require double-buffer
ADD_ATTR(NSOpenGLPFADoubleBuffer);
// Specify the number of color bits. If we don't have a valid specified value or we are not full screen, use the current display mode's value.
ADD_ATTR(NSOpenGLPFAColorSize);
colorDepth = r_colorbits->integer;
if (colorDepth < 16)
colorDepth = 16;
else if (colorDepth > 16)
colorDepth = 32;
if (!r_fullscreen->integer)
colorDepth = [[glw_state.desktopMode objectForKey: (id)kCGDisplayBitsPerPixel] intValue];
ADD_ATTR(colorDepth);
// Specify the number of depth bits
ADD_ATTR(NSOpenGLPFADepthSize);
ADD_ATTR(r_depthbits->integer ? r_depthbits->integer : 16);
// Specify the number of stencil bits
if (r_stencilbits->integer) {
ADD_ATTR(NSOpenGLPFAStencilSize);
ADD_ATTR(r_stencilbits->integer);
}
// Terminate the list
ADD_ATTR(0);
return pixelAttributes;
}
// Needs to be visible to Q3Controller.m.
void Sys_UpdateWindowMouseInputRect(void)
{
NSRect windowRect, screenRect;
NSScreen *screen;
// It appears we need to flip the coordinate system here. This means we need
// to know the size of the screen.
screen = [glw_state.window screen];
screenRect = [screen frame];
windowRect = [glw_state.window frame];
windowRect.origin.y = screenRect.size.height - (windowRect.origin.y + windowRect.size.height);
Sys_SetMouseInputRect(CGRectMake(windowRect.origin.x, windowRect.origin.y,
windowRect.size.width, windowRect.size.height));
}
// This is needed since CGReleaseAllDisplays() restores the gamma on the displays and we want to fade it up rather than just flickering all the displays
static void ReleaseAllDisplays()
{
CGDisplayCount displayIndex;
Com_Printf("Releasing displays\n");
for (displayIndex = 0; displayIndex < glw_state.displayCount; displayIndex++) {
CGDisplayRelease(glw_state.originalDisplayGammaTables[displayIndex].display);
}
}
/*
=================
CreateGameWindow
=================
*/
static qboolean CreateGameWindow( qboolean isSecondTry )
{
const char *windowed[] = { "Windowed", "Fullscreen" };
int current_mode;
NSOpenGLPixelFormatAttribute *pixelAttributes;
NSOpenGLPixelFormat *pixelFormat;
CGDisplayErr err;
// get mode info
current_mode = r_mode->integer;
glConfig.isFullscreen = (r_fullscreen->integer != 0);
glw_state.desktopMode = (NSDictionary *)CGDisplayCurrentMode(glw_state.display);
if (!glw_state.desktopMode) {
ri.Error(ERR_FATAL, "Could not get current graphics mode for display 0x%08x\n", glw_state.display);
}
#if 0
ri.Printf( PRINT_ALL, "... desktop mode %d = %dx%d %s\n", glw_state.desktopMode,
glw_state.desktopDesc.width, glw_state.desktopDesc.height,
depthStrings[glw_state.desktopDesc.depth]);
#endif
ri.Printf( PRINT_ALL, "...setting mode %d:\n", current_mode );
if ( !R_GetModeInfo( &glConfig.vidWidth, &glConfig.vidHeight, &glConfig.windowAspect, current_mode ) ) {
ri.Printf( PRINT_ALL, " invalid mode\n" );
return qfalse;
}
ri.Printf( PRINT_ALL, " %d %d %s\n", glConfig.vidWidth, glConfig.vidHeight, windowed[glConfig.isFullscreen] );
if (glConfig.isFullscreen) {
// We'll set up the screen resolution first in case that effects the list of pixel
// formats that are available (for example, a smaller frame buffer might mean more
// bits for depth/stencil buffers). Allow stretched video modes if we are in fallback mode.
glw_state.gameMode = Sys_GetMatchingDisplayMode(isSecondTry);
if (!glw_state.gameMode) {
ri.Printf( PRINT_ALL, "Unable to find requested display mode.\n");
return qfalse;
}
// Fade all screens to black
Sys_FadeScreens();
err = Sys_CaptureActiveDisplays();
if ( err != CGDisplayNoErr ) {
CGDisplayRestoreColorSyncSettings();
ri.Printf( PRINT_ALL, " Unable to capture displays err = %d\n", err );
return qfalse;
}
err = CGDisplaySwitchToMode(glw_state.display, (CFDictionaryRef)glw_state.gameMode);
if ( err != CGDisplayNoErr ) {
CGDisplayRestoreColorSyncSettings();
ReleaseAllDisplays();
ri.Printf( PRINT_ALL, " Unable to set display mode, err = %d\n", err );
return qfalse;
}
} else {
glw_state.gameMode = glw_state.desktopMode;
}
// Get the GL pixel format
pixelAttributes = GetPixelAttributes();
pixelFormat = [[[NSOpenGLPixelFormat alloc] initWithAttributes: pixelAttributes] autorelease];
NSZoneFree(NULL, pixelAttributes);
if (!pixelFormat) {
CGDisplayRestoreColorSyncSettings();
CGDisplaySwitchToMode(glw_state.display, (CFDictionaryRef)glw_state.desktopMode);
ReleaseAllDisplays();
ri.Printf( PRINT_ALL, " No pixel format found\n");
return qfalse;
}
// Create a context with the desired pixel attributes
OSX_SetGLContext([[NSOpenGLContext alloc] initWithFormat: pixelFormat shareContext: nil]);
if (!OSX_GetNSGLContext()) {
CGDisplayRestoreColorSyncSettings();
CGDisplaySwitchToMode(glw_state.display, (CFDictionaryRef)glw_state.desktopMode);
ReleaseAllDisplays();
ri.Printf(PRINT_ALL, "... +[NSOpenGLContext createWithFormat:share:] failed.\n" );
return qfalse;
}
if (!glConfig.isFullscreen) {
cvar_t *vid_xpos;
cvar_t *vid_ypos;
NSRect windowRect;
vid_xpos = ri.Cvar_Get( "vid_xpos", "100", CVAR_ARCHIVE );
vid_ypos = ri.Cvar_Get( "vid_ypos", "100", CVAR_ARCHIVE );
// Create a window of the desired size
windowRect.origin.x = vid_xpos->integer;
windowRect.origin.y = vid_ypos->integer;
windowRect.size.width = glConfig.vidWidth;
windowRect.size.height = glConfig.vidHeight;
glw_state.window = [[NSWindow alloc] initWithContentRect:windowRect
styleMask:NSTitledWindowMask
backing:NSBackingStoreRetained
defer:NO];
[glw_state.window setTitle: @"Quake3"];
[glw_state.window orderFront: nil];
// Always get mouse moved events (if mouse support is turned off (rare)
// the event system will filter them out.
[glw_state.window setAcceptsMouseMovedEvents: YES];
// Direct the context to draw in this window
[OSX_GetNSGLContext() setView: [glw_state.window contentView]];
// Sync input rect with where the window actually is...
Sys_UpdateWindowMouseInputRect();
} else {
CGLError err;
err = CGLSetFullScreen(OSX_GetCGLContext());
if (err) {
CGDisplayRestoreColorSyncSettings();
CGDisplaySwitchToMode(glw_state.display, (CFDictionaryRef)glw_state.desktopMode);
ReleaseAllDisplays();
Com_Printf("CGLSetFullScreen -> %d (%s)\n", err, CGLErrorString(err));
return qfalse;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -