blob: 005466f03b10ebf29c77b0cf611831a48adf0504 [file] [log] [blame]
/**
* projectM -- Milkdrop-esque visualisation SDK
* Copyright (C)2003-2007 projectM Team
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* See 'LICENSE.txt' included within this release
*
*/
/**
* $Id: iprojectM.c,v 1.10 2004/11/07 17:29:04 cvs Exp $
*
* iTunes Plugin Wrapper for projectM
*/
#include <string.h>
#ifdef WIN32
#include <windows.h>
#endif
#include <libprojectM/carbontoprojectM.hpp>
#include <libprojectM/Common.hpp>
#include <libprojectM/Renderer/BeatDetect.hpp>
#include <libprojectM/Renderer/PCM.hpp>
#include <libprojectM/projectM.hpp>
#ifdef WIN32
#include "win32/iTunesVisualAPI.h"
#else
#ifdef MACOS
#include "macos/iTunesVisualAPI.h"
#include <agl.h>
#endif /** MACOS */
#endif /** WIN32 */
#ifdef WIN32
// window information
HWND windowHandle;
HDC windowDC;
HGLRC windowRC;
#endif /** WIN32 */
#ifdef MACOS
CGrafPtr port = NULL;
AGLContext context = NULL;
int frameCount = 0;
CFDictionaryRef desktopMode = NULL;
CFDictionaryRef fullscreenMode = NULL;
int inFullScreenMode = 0;
int displayCaptured = 0;
boolean_t exactMatch;
int fullscreenWidth, fullscreenHeight;
#endif /** MACOS */
#ifdef MACOS
#define kTVisualPluginName "\pprojectM"
#define kTVisualPluginCreator 'hook'
#define kTVisualPluginMajorVersion 1
#define kTVisualPluginMinorVersion 0
#define kTVisualPluginReleaseStage finalStage
#define kTVisualPluginNonFinalRelease 0
#endif /** MACOS */
/** Port dimensions */
int windowWidth;
int windowHeight;
/** projectM info */
projectM *globalPM = NULL;
#ifdef DEBUG
FILE *debugFile = NULL;
#endif
// iTunes information
RenderVisualData renderData;
int playing;
void *appCookie;
ITAppProcPtr appProc;
#ifdef WIN32
ITTrackInfoV1 trackInfo;
ITStreamInfoV1 streamInfo;
#else
#ifdef MACOS
ITTrackInfo trackInfo;
ITStreamInfo streamInfo;
FSSpec pluginSpec;
#endif /** MACOS */
#endif /** WIN32 */
#ifdef MACOS
void CleanupGL();
#endif
#ifdef MACOS
/** fss2path takes the FSSpec of the plugin and returns the filename */
void fss2path( FSSpec *fss, char *path ) {
int l;
for ( l = 0 ; l < (fss->name[0]) ; l++ ) {
path[l] = fss->name[l + 1];
}
path[l] = '\0';
DWRITE( "fss2path: '%s'\n", path );
if ( fss->parID != fsRtParID) {
int i, len;
CInfoPBRec pb;
pb.dirInfo.ioNamePtr = fss->name;
pb.dirInfo.ioVRefNum = fss->vRefNum;
pb.dirInfo.ioDrParID = fss->parID;
do {
pb.dirInfo.ioFDirIndex = -1;
pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID;
if ( PBGetCatInfoSync( &pb ) != noErr ) {
break;
}
len = fss->name[0] + 1;
for ( i = l ; i >= 0 ; i-- ) path[i + len] = path[i];
for ( i = 1 ; i < len ; i++ ) path[i - 1] = fss->name[i];
path[i - 1] = '/';
l += len;
} while ( pb.dirInfo.ioDrDirID != fsRtDirID );
len = 9;
for ( i = l ; i >= 0 ; i-- ) path[i + len] = path[i];
path[0] = '/';
path[1] = 'V';
path[2] = 'o';
path[3] = 'l';
path[4] = 'u';
path[5] = 'm';
path[6] = 'e';
path[7] = 's';
path[8] = '/';
}
}
#endif
// create OpenGL rendering context for the specified window
#ifdef WIN32
void InitializeGL(HWND hwnd)
{
int pixelFormat;
PIXELFORMATDESCRIPTOR pfd = {
sizeof (PIXELFORMATDESCRIPTOR), /* struct size */
1, /* Version number */
PFD_DRAW_TO_WINDOW /* Flags, draw to a window, */
| PFD_DOUBLEBUFFER /* Requires Doublebuffer hw */
| PFD_SUPPORT_OPENGL, /* use OpenGL */
PFD_TYPE_RGBA, /* RGBA pixel values */
32, /* 24-bit color */
0, 0, 0, /* RGB bits & shift sizes. */
0, 0, 0, /* Don't care about them */
0, 0, /* No alpha buffer info */
0, 0, 0, 0, 0, /* No accumulation buffer */
16, /* depth buffer */
1, /* stencil buffer */
0, /* No auxiliary buffers */
PFD_MAIN_PLANE, /* Layer type */
0, /* Reserved (must be 0) */
0, /* No layer mask */
0, /* No visible mask */
0 /* No damage mask */
};
windowHandle = hwnd;
windowDC = GetDC(windowHandle);
// memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
pixelFormat = ChoosePixelFormat(windowDC, &pfd);
if (pixelFormat == 0)
return;
if (SetPixelFormat(windowDC, pixelFormat, &pfd) == 0)
return;
windowRC = wglCreateContext(windowDC);
if (windowRC == NULL)
return;
if (!wglMakeCurrent(windowDC, windowRC))
return;
#ifdef PANTS
// enable v-sync if WGL_EXT_swap_control is supported
PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL;
wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
if (wglSwapIntervalEXT != NULL)
wglSwapIntervalEXT(1);
#endif
/** Initialise projectM */
#ifdef DEBUG
debugFile = fopen( "c:\\iprojectM.txt", "wb" );
#endif
globalPM = (projectM_t *)malloc( sizeof( projectM_t ) );
projectM_reset( globalPM );
globalPM->fullscreen = 0;
globalPM->usePbuffers = 1;
globalPM->renderTarget->texsize = 1024;
globalPM->showfps = 1;
/** Initialise font and preset paths */
globalPM->fontURL = (char *)malloc( sizeof( char ) * 1024 );
strcpy( globalPM->fontURL, "c:\\Program Files\\iTunes\\Plug-ins\\projectM\\fonts" );
globalPM->presetURL = (char *)malloc( sizeof( char ) * 1024 );
strcpy( globalPM->presetURL, "c:\\Program Files\\iTunes\\Plug-ins\\projectM\\presets" );
projectM_init( globalPM );
}
#else
#ifdef MACOS
void InitializeGL( CGrafPtr destPort, int isFullScreen ) {
AGLPixelFormat pixelFormat;
GLint attrib[64];
DWRITE( "InitializeGL(): in: %d\n", isFullScreen );
/** Stash the target port */
port = destPort;
#ifdef PANTS
if ( isFullScreen ) {
CGCaptureAllDisplays();
displayCaptured = 1;
if ( fullscreenMode != NULL ) {
if ( CGDisplaySwitchToMode( kCGDirectMainDisplay, fullscreenMode ) != CGDisplayNoErr ) {
DWRITE( "%s\n", "failed to switch display to fullscreen" );
} else {
DWRITE( "%s\n", "display switch to fullscreen ok\n" );
}
}
} else {
/** Switch back to the previous desktop mode */
if ( desktopMode != NULL ) {
if ( CGDisplaySwitchToMode( kCGDirectMainDisplay, desktopMode ) != CGDisplayNoErr ) {
DWRITE( "%s\n", "failed to switch display" );
} else {
DWRITE( "%s\n", "display switch OK" );
}
}
}
#endif
/** Chuck out the old context if one exists */
if ( context != NULL ) {
aglDestroyContext( context );
context = NULL;
}
/** Choose the OpenGL pixel format */
#ifdef PANTS
if ( isFullScreen ) {
attrib[0] = AGL_RGBA;
attrib[1] = AGL_DOUBLEBUFFER;
attrib[2] = AGL_PIXEL_SIZE;
attrib[3] = 32;
attrib[4] = AGL_FULLSCREEN;
attrib[5] = AGL_NO_RECOVERY;
attrib[6] = AGL_SINGLE_RENDERER;
attrib[6] = AGL_NONE;
} else {
#endif
attrib[0] = AGL_RGBA;
attrib[1] = AGL_DOUBLEBUFFER;
attrib[2] = AGL_ACCELERATED;
attrib[3] = AGL_PIXEL_SIZE;
attrib[4] = 32;
attrib[5] = AGL_NO_RECOVERY;
attrib[6] = AGL_SINGLE_RENDERER;
attrib[5] = AGL_NONE;
// }
GDHandle mainDevice = GetMainDevice();
pixelFormat = aglChoosePixelFormat( &mainDevice, 1, attrib );
if ( pixelFormat == 0 ) {
DWRITE( "failed to select pixel format\n" );
exit( 1 );
CleanupGL();
isFullScreen = 0;
return;
} else {
DWRITE( "selected pixel format OK\n" );
}
context = aglCreateContext( pixelFormat, NULL );
if ( context == NULL ) {
DWRITE( "failed to create context\n" );
} else {
DWRITE( "created context OK\n" );
}
// if ( !isFullScreen ) {
if ( !aglSetDrawable( context, destPort ) ) {
DWRITE( "failed to set drawable\n" );
} else {
DWRITE( "set drawable OK\n" );
}
// } else {
// aglSetDrawable( context, NULL );
// }
if ( !aglSetCurrentContext( context ) ) {
DWRITE( "failed to make context current\n" );
} else {
DWRITE( "set current context OK\n" );
}
// if ( !isFullScreen ) {
if ( !aglUpdateContext( context ) ) {
DWRITE( "failed to update context\n" );
} else {
DWRITE( "updated context OK\n" );
}
if ( globalPM != NULL ) {
globalPM->fullscreen = 0;
}
#ifdef PANTS
} else {
aglSetFullScreen( context, 800, 600, 0, 0 );
if ( globalPM != NULL ) {
globalPM->fullscreen = 1;
}
GLint displayCaps[3];
aglGetInteger( context, AGL_FULLSCREEN, displayCaps );
DWRITE( "dcaps: %d\t%d\t%d\n",
displayCaps[0], displayCaps[1], displayCaps[2] );
fullscreenWidth = displayCaps[0];
fullscreenHeight = displayCaps[1];
}
#endif
#ifdef WIN32
// enable v-sync if WGL_EXT_swap_control is supported
PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL;
wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
if (wglSwapIntervalEXT != NULL)
wglSwapIntervalEXT(1);
#endif
#ifdef MACOS
/** Setup VSYNC */
GLint sync = 1;
aglSetInteger ( context, AGL_SWAP_INTERVAL, &sync );
#endif
/** Initialise projectM */
globalPM->projectM_init();
}
#endif /** MACOS */
#endif /** WIN32 */
// render visualization data
void RenderGL()
{
#ifdef WIN32
if (windowDC == NULL || globalPM == NULL ) return;
#else
#ifdef MACOS
if ( port == NULL || context == NULL ) {
return;
}
#endif /** MACOS */
#endif /** WIN32 */
/** Stuff the PCM data into projectM */
globalPM->beatDetect->pcm->addPCM8( renderData.waveformData );
/** Render a frame via projectM */
globalPM->renderFrame();
#if defined(DEBUG2) && defined(MACOS)
fprintf( debugFile, "port: %X\tcontext: %X\n", port, context );
fflush( debugFile );
#endif
#ifdef WIN32
/** Buffer swap to display the results */
SwapBuffers( windowDC );
#else
#ifdef MACOS
aglSwapBuffers( context );
#endif /** MACOS */
#endif /** WIN32 */
}
// resize rendering viewport
void ResizeGL( CGrafPtr destPort, Rect windowRect, int isFullScreen ) {
#ifdef MACOS
GLint bufferRect[4];
#endif
DWRITE( "ResizeGL(): in: %d\n", isFullScreen );
#ifdef PANTS
if ( isFullScreen ) {
#ifdef MACOS
aglDisable( context, AGL_BUFFER_RECT );
#endif /** MACOS */
/** Reset projectM */
if ( globalPM != NULL ) {
globalPM->projectM_resetGL( fullscreenWidth, fullscreenHeight );
}
} else {
#endif
windowWidth = windowRect.right - windowRect.left;
windowHeight = windowRect.bottom - windowRect.top;
if (windowHeight == 0) windowHeight = 1;
/** Re-initialise OpenGL */
if ( globalPM != NULL ) {
#ifdef MACOS
/**
* Grab the dimensions of the main window itself. This is required
* to accurately locate the port since OpenGL is "upside-down" from
* Carbon window coordinates...
*/
WindowRef itWindowRef;
Rect mwindowRect;
itWindowRef = GetWindowFromPort(port);
GetWindowPortBounds(itWindowRef, &mwindowRect);
DWRITE( "rect: (%d, %d) -> (%d, %d)\n",
windowRect.left, windowRect.top,
windowRect.right, windowRect.bottom );
DWRITE( "window-rect: (%d, %d) -> (%d, %d)\n",
mwindowRect.left, mwindowRect.top,
mwindowRect.right, mwindowRect.bottom );
/** Update the buffer rect */
bufferRect[0] = windowRect.left;
bufferRect[1] = mwindowRect.bottom - windowRect.bottom;
bufferRect[2] = windowWidth;
bufferRect[3] = windowHeight;
aglSetInteger( context, AGL_BUFFER_RECT, bufferRect );
aglEnable( context, AGL_BUFFER_RECT );
if ( !aglUpdateContext( context ) ) {
DWRITE( "failed to update context\n" );
} else {
DWRITE( "updated context OK\n" );
}
#endif
globalPM->projectM_resetGL( windowWidth, windowHeight );
}
// }
}
// cleanup OpenGL rendering context
void CleanupGL()
{
#ifdef WIN32
wglMakeCurrent(NULL, NULL);
if (windowRC != NULL)
{
wglDeleteContext(windowRC);
windowRC = NULL;
}
if (windowDC)
{
ReleaseDC(windowHandle, windowDC);
windowDC = NULL;
}
#else
#ifdef MACOS
/** Release the held main display */
#ifdef PANTS
if ( displayCaptured ) {
DWRITE( "%s\n", "switching to non-fullscreen" );
CGDisplaySwitchToMode( kCGDirectMainDisplay, desktopMode );
DWRITE( "%s\n", "releasing displays" );
CGReleaseAllDisplays();
}
#endif
DWRITE( "pre-context destroy\n" );
if ( context != NULL ) {
aglSetCurrentContext( NULL );
aglDestroyContext( context );
context = NULL;
}
#endif /** MACOS */
#endif /** WIN32 */
}
// handle messages sent by iTunes
OSStatus pluginMessageHandler( OSType message,
VisualPluginMessageInfo *messageInfo,
void *refCon) {
OSStatus status = noErr;
switch (message) {
// sent when the plugin is loaded/unloaded
case kVisualPluginInitMessage: {
DWRITE( "*** %s\n", "kVisualPluginInitMessage" );
break;
}
case kVisualPluginCleanupMessage: {
DWRITE( "*** %s\n", "kVisualPluginCleanupMessage" );
// CleanupGL();
break;
}
// sent when plugin is enabled/disabled, plugin should handle these messages and do nothing
case kVisualPluginEnableMessage: {
DWRITE( "*** %s\n", "kVisualPluginEnableMessage" );
break;
}
case kVisualPluginDisableMessage: {
DWRITE( "*** %s\n", "kVisualPluginDisableMessage" );
break;
}
// redraw the screne while idle
case kVisualPluginIdleMessage: {
DWRITE( "*** %s\n", "kVisualPluginIdleMessage" );
if (playing == false) {
RenderGL();
}
break;
}
// sent when the visualizer is shown
case kVisualPluginShowWindowMessage: {
DWRITE( "*** kVisualPluginShowWindowMessage( %d )\n",
messageInfo->u.showWindowMessage.options );
#ifdef WIN32
InitializeGL(messageInfo->u.showWindowMessage.window,
messageInfo->u.showWindowMessage.options );
#else
#ifdef MACOS
InitializeGL( messageInfo->u.showWindowMessage.port,
/* messageInfo->u.showWindowMessage.options */ 0 );
#endif /** MACOS */
#endif /** WIN32 */
ResizeGL( messageInfo->u.showWindowMessage.port,
messageInfo->u.setWindowMessage.drawRect,
/* messageInfo->u.setWindowMessage.options */ 0 );
RenderGL();
break;
}
// sent when the visualizer is hidden
case kVisualPluginHideWindowMessage: {
DWRITE( "*** %s\n", "kVisualPluginHideWindowMessage" );
CleanupGL();
break;
}
#ifdef PANTS
// sent when visualizer viewport size is changed
case kVisualPluginSetWindowMessage: {
DWRITE( "*** kVisualPluginSetWindowMessage( %d )\n",
messageInfo->u.setWindowMessage.options );
ResizeGL(messageInfo->u.setWindowMessage.port,
messageInfo->u.setWindowMessage.drawRect,
messageInfo->u.setWindowMessage.options);
RenderGL();
break;
}
#endif
// sent when visualizer should render a frame
case kVisualPluginRenderMessage: {
DWRITE( "*** %s\n", "kVisualPluginRenderMessage" );
renderData = *messageInfo->u.renderMessage.renderData;
RenderGL();
break;
}
// sent when visualizer should update itself
case kVisualPluginUpdateMessage: {
DWRITE( "*** %s\n", "kVisualPluginUpdateMessage" );
RenderGL();
break;
}
// sent when player is stopped or paused
case kVisualPluginStopMessage: {
DWRITE( "*** %s\n", "kVisualPluginStopMessage" );
break;
}
case kVisualPluginPauseMessage: {
DWRITE( "*** %s\n", "kVisualPluginPauseMessage" );
playing = false;
break;
}
// sent when player is started or unpaused
case kVisualPluginPlayMessage: {
DWRITE( "*** %s\n", "kVisualPluginPlayMessage" );
break;
}
case kVisualPluginUnpauseMessage: {
DWRITE( "*** %s\n", "kVisualPluginPauseMessage" );
/** Grab the track or stream title from iTunes */
if (messageInfo->u.changeTrackMessage.trackInfo != nil) {
trackInfo = *messageInfo->u.changeTrackMessage.trackInfo;
} else {
memset( &trackInfo, sizeof( trackInfo ) * sizeof( char ), 0 );
}
if (messageInfo->u.changeTrackMessage.streamInfo != nil) {
streamInfo = *messageInfo->u.changeTrackMessage.streamInfo;
} else {
memset( &streamInfo, sizeof( streamInfo ) * sizeof( char ), 0 );
}
/** Pass this info into projectM */
if ( globalPM != NULL ) {
globalPM->drawtitle = 1;
if ( strlen( (const char *)trackInfo.name ) > 0 ) {
globalPM->projectM_setTitle( (char *)trackInfo.name );
} else {
if ( strlen( (const char *)streamInfo.streamTitle ) > 0 ) {
globalPM->projectM_setTitle( (char *)streamInfo.streamTitle );
}
}
}
playing = true;
break;
}
/** Sent when the track changes */
case kVisualPluginChangeTrackMessage: {
DWRITE( "*** %s\n", "kVisualPluginChangeTrackMessage" );
/** Grab the track or stream title from iTunes */
if (messageInfo->u.changeTrackMessage.trackInfo != nil) {
trackInfo = *messageInfo->u.changeTrackMessage.trackInfo;
} else {
memset( &trackInfo, sizeof( trackInfo ) * sizeof( char ), 0 );
}
if (messageInfo->u.changeTrackMessage.streamInfo != nil) {
streamInfo = *messageInfo->u.changeTrackMessage.streamInfo;
} else {
memset( &streamInfo, sizeof( streamInfo ) * sizeof( char ), 0 );
}
/** Pass this info into projectM */
globalPM->drawtitle = 1;
if ( strlen( (const char *)trackInfo.name ) > 0 ) {
globalPM->projectM_setTitle( (char *)trackInfo.name );
} else {
if ( strlen( (const char *)streamInfo.streamTitle ) > 0 ) {
globalPM->projectM_setTitle( (char *)streamInfo.streamTitle );
}
}
RenderGL();
break;
}
case kVisualPluginEventMessage: {
projectMEvent event;
projectMKeycode keycode;
projectMModifier mod;
DWRITE( "*** %s\n", "kVisualPluginEventMessage" );
#ifdef MACOS
event = carbon2pmEvent( messageInfo->u.eventMessage.event );
keycode = carbon2pmKeycode( messageInfo->u.eventMessage.event );
#else
#ifdef WIN32
#endif /** WIN32 */
#endif /** MACOS */
DWRITE( "keycode: %d\n", keycode );
if ( keycode == ' ' ) {
status = unimpErr;
}
globalPM->key_handler( event, keycode, mod );
break;
}
default: {
status = unimpErr;
break;
}
}
return status;
}
// register plugin with iTunes
OSStatus registerPlugin(PluginMessageInfo *messageInfo) {
OSStatus status;
// plugin constants
#ifdef WIN32
const char *pluginTitle = "projectM";
const UInt32 pluginCreator = '\?\?\?\?';
#else
#ifdef MACOS
const char *pluginTitle = "projectM";
const UInt32 pluginCreator = 'hook';
#endif /** MACOS */
#endif /** WIN32 */
const UInt8 pluginMajorVersion = 10;
const UInt8 pluginMinorVersion = 9;
PlayerMessageInfo playerMessageInfo;
memset( &playerMessageInfo.u.registerVisualPluginMessage,
0, sizeof(playerMessageInfo.u.registerVisualPluginMessage));
// copy in name length byte first
playerMessageInfo.u.registerVisualPluginMessage.name[0] =
(UInt8)strlen( pluginTitle );
// now copy in actual name
memcpy( &playerMessageInfo.u.registerVisualPluginMessage.name[1],
pluginTitle, strlen( pluginTitle ));
SetNumVersion( &playerMessageInfo.u.registerVisualPluginMessage.pluginVersion,
pluginMajorVersion, pluginMinorVersion, 0x80, 0);
playerMessageInfo.u.registerVisualPluginMessage.options =
kVisualWantsIdleMessages;
#ifdef WIN32
playerMessageInfo.u.registerVisualPluginMessage.handler =
pluginMessageHandler;
#else
playerMessageInfo.u.registerVisualPluginMessage.handler =
(VisualPluginProcPtr)pluginMessageHandler;
#endif
playerMessageInfo.u.registerVisualPluginMessage.registerRefCon = 0;
playerMessageInfo.u.registerVisualPluginMessage.creator = pluginCreator;
playerMessageInfo.u.registerVisualPluginMessage.timeBetweenDataInMS = 0xFFFFFFFF; // 16 milliseconds = 1 Tick, 0xFFFFFFFF = Often as possible.
playerMessageInfo.u.registerVisualPluginMessage.numWaveformChannels = 2;
playerMessageInfo.u.registerVisualPluginMessage.numSpectrumChannels = 2;
playerMessageInfo.u.registerVisualPluginMessage.minWidth = 64;
playerMessageInfo.u.registerVisualPluginMessage.minHeight = 64;
playerMessageInfo.u.registerVisualPluginMessage.maxWidth = 32767;
playerMessageInfo.u.registerVisualPluginMessage.maxHeight = 32767;
playerMessageInfo.u.registerVisualPluginMessage.minFullScreenBitDepth = 0;
playerMessageInfo.u.registerVisualPluginMessage.maxFullScreenBitDepth = 0;
playerMessageInfo.u.registerVisualPluginMessage.windowAlignmentInBytes = 0;
status = PlayerRegisterVisualPlugin(messageInfo->u.initMessage.appCookie,
messageInfo->u.initMessage.appProc,
&playerMessageInfo);
appCookie = messageInfo->u.initMessage.appCookie;
appProc = messageInfo->u.initMessage.appProc;
return status;
}
#ifdef WIN32
#define IMPEXP __declspec(dllexport)
#define MAIN iTunesPluginMain
#else
#ifdef MACOS
#define IMPEXP
#define MAIN iTunesPluginMainMachO
#endif /** MACOS */
#endif /** WIN32 */
#ifdef MACOS
extern "C"
#endif
IMPEXP OSStatus MAIN (OSType message, PluginMessageInfo *messageInfo, void *refCon)
{
OSStatus status = noErr;
char fname[1024];
char fontURL[1024];
char presetURL[1024];
switch (message) {
case kPluginInitMessage: {
#ifdef DEBUG
#ifdef MACOS
debugFile = fopen( "/Users/descarte/iprojectM.txt", "wb" );
fprintf( debugFile, "registerPlugin: %d\n", status );
fflush( debugFile );
#endif /** MACOS */
#endif /** DEBUG */
DWRITE( "%s: %d\t%d\n",
"kPluginInitMessage",
messageInfo->u.initMessage.majorVersion,
messageInfo->u.initMessage.minorVersion );
status = registerPlugin(messageInfo);
if ( status == noErr ) {
#ifdef MACOS
desktopMode = CGDisplayCurrentMode( kCGDirectMainDisplay );
fullscreenMode =
CGDisplayBestModeForParameters( kCGDirectMainDisplay,
32, 800, 600, NULL );
#ifdef DEBUG
if ( debugFile != NULL ) {
long dwidth = 0, dheight = 0;
/** Get the desktop mode */
/* Get the height, width, bpp, and refresh rate of this display mode. Print them out. */
CFNumberRef number ;
number = (CFNumberRef)CFDictionaryGetValue( desktopMode, kCGDisplayWidth ) ;
CFNumberGetValue( number, kCFNumberLongType, &dwidth ) ;
number = (CFNumberRef)CFDictionaryGetValue( desktopMode, kCGDisplayHeight ) ;
CFNumberGetValue( number, kCFNumberLongType, &dheight ) ;
DWRITE( "stashing desktop mode: %d x %d -> %d\n",
dwidth, dheight, exactMatch );
}
#endif
#endif
/** Initialise projectM */
if (globalPM != 0)
delete(globalPM);
globalPM = new projectM();
globalPM->projectM_reset();
/** Set basic rendering options */
globalPM->renderTarget->usePbuffers = 1;
globalPM->fullscreen = 0;
globalPM->renderTarget->texsize = 1024;
globalPM->showfps = 1;
/** Get the font and preset locations */
PlayerGetPluginFileSpec( appCookie, appProc, &pluginSpec );
fss2path( &pluginSpec, fname );
DWRITE( "fsspace name: %s\n", fname );
sprintf( fontURL, "%s/Contents/Resources/fonts", fname );
globalPM->fontURL = (char *)malloc( sizeof( char ) * 1024 );
strncpy( globalPM->fontURL, fontURL, strlen( fontURL ) + 1 );
DWRITE( "fontURL: %s\n", globalPM->fontURL );
sprintf( presetURL, "%s/Contents/Resources/presets", fname );
globalPM->presetURL = (char *)malloc( sizeof( char ) * 1024 );
strncpy( globalPM->presetURL, presetURL, strlen( presetURL ) + 1 );
DWRITE( "presetURL: %s\n", globalPM->presetURL );
}
break;
}
case kPluginCleanupMessage: {
DWRITE( "%s\n", "kPluginCleanupMessage" );
#ifdef DEBUG
if ( debugFile != NULL ) {
fclose( debugFile );
}
#endif
status = noErr;
break;
}
default: {
status = unimpErr;
break;
}
}
DWRITE( "status: %d\n", status );
return status;
}