Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
Classes/BasicApplicationController.m
/* |
* BasicApplicationController.m |
* |
* Created by Michael Larson on Tue Mar 11 2003. |
* Copyright (c) 2003 Apple Computer. All rights reserved. |
* |
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. |
("Apple") in consideration of your agreement to the following terms, and your |
use, installation, modification or redistribution of this Apple software |
constitutes acceptance of these terms. If you do not agree with these terms, |
please do not use, install, modify or redistribute this Apple software. |
In consideration of your agreement to abide by the following terms, and subject |
to these terms, Apple grants you a personal, non-exclusive license, under Apple's |
copyrights in this original Apple software (the "Apple Software"), to use, |
reproduce, modify and redistribute the Apple Software, with or without |
modifications, in source and/or binary forms; provided that if you redistribute |
the Apple Software in its entirety and without modifications, you must retain |
this notice and the following text and disclaimers in all such redistributions of |
the Apple Software. Neither the name, trademarks, service marks or logos of |
Apple Computer, Inc. may be used to endorse or promote products derived from the |
Apple Software without specific prior written permission from Apple. Except as |
expressly stated in this notice, no other rights or licenses, express or implied, |
are granted by Apple herein, including but not limited to any patent rights that |
may be infringed by your derivative works or by other works in which the Apple |
Software may be incorporated. |
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO |
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED |
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN |
COMBINATION WITH YOUR PRODUCTS. |
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR |
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE |
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION |
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT |
(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN |
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
* |
*/ |
#import "BasicApplicationController.h" |
typedef const OSType * QTFrameTypeListPtr; |
typedef const OSTypePtr TypeListPtr; |
const OSType kApplicationSignature = FOUR_CHAR_CODE('oglv'); |
const ResType kOpenResourceType = FOUR_CHAR_CODE('open'); |
const StringPtr kApplicationName = "\pSurface Vertex Program"; |
@implementation BasicApplicationController |
- (void) awakeFromNib |
{ |
// setup the timer |
m_timer = [NSTimer scheduledTimerWithTimeInterval: 0.01 target: self |
selector:@selector(timerEventHandler) userInfo: 0 repeats: YES]; |
// Init the rotation to zero |
m_rotx = 15; |
m_roty = 30; |
m_rotz = 15; |
m_scale = 1.0; |
m_aa = m_bb = m_cc = 1.0; |
m_dd = 0.0; |
m_energy = 1.0; |
m_SndPlayer = [SoundPlayer new]; |
LissajousSurface = [self CreateLissajousSurface]; |
[LissajousSurface attachToVertexArrayRange]; |
m_AnalyzerBars = NULL; |
m_VolumeLines = NULL; |
} |
Handle CreateOpenHandle (OSType theApplicationSignature, short theNumTypes, TypeListPtr theTypeList) |
{ |
Handle myHandle = NULL; |
// see if we have an 'open' resource... |
myHandle = Get1Resource('open', 128); |
if ( myHandle != NULL && ResError() == noErr ) { |
DetachResource( myHandle ); |
return myHandle; |
} else { |
myHandle = NULL; |
} |
// nope, use the passed in types and dynamically create the NavTypeList |
if (theTypeList == NULL) |
return myHandle; |
if (theNumTypes > 0) { |
myHandle = NewHandle(sizeof(NavTypeList) + (theNumTypes * sizeof(OSType))); |
if (myHandle != NULL) { |
NavTypeListHandle myOpenResHandle = (NavTypeListHandle)myHandle; |
(*myOpenResHandle)->componentSignature = theApplicationSignature; |
(*myOpenResHandle)->osTypeCount = theNumTypes; |
BlockMoveData(theTypeList, (*myOpenResHandle)->osType, theNumTypes * sizeof(OSType)); |
} |
} |
return myHandle; |
} |
pascal void HandleNavEvent(NavEventCallbackMessage theCallBackSelector, NavCBRecPtr theCallBackParms, void *theCallBackUD) |
{ |
#pragma unused(theCallBackUD) |
if (theCallBackSelector == kNavCBEvent) { |
switch (theCallBackParms->eventData.eventDataParms.event->what) { |
case updateEvt: |
// Handle Update Event |
break; |
case nullEvent: |
// Handle Null Event |
break; |
} |
} |
} |
static OSErr GetOneFileWithPreview (short theNumTypes, TypeListPtr theTypeList, FSSpecPtr theFSSpecPtr, void *theFilterProc) |
{ |
NavReplyRecord myReply; |
NavDialogOptions myDialogOptions; |
NavTypeListHandle myOpenList = NULL; |
NavEventUPP myEventUPP = NewNavEventUPP(HandleNavEvent); |
OSErr myErr = noErr; |
if (theFSSpecPtr == NULL) |
return(paramErr); |
// specify the options for the dialog box |
NavGetDefaultDialogOptions(&myDialogOptions); |
myDialogOptions.dialogOptionFlags -= kNavNoTypePopup; |
myDialogOptions.dialogOptionFlags -= kNavAllowMultipleFiles; |
myDialogOptions.dialogOptionFlags += kNavAllowPreviews; |
// create a handle to an 'open' resource |
myOpenList = (NavTypeListHandle)CreateOpenHandle(kApplicationSignature, theNumTypes, theTypeList); |
if (myOpenList != NULL) |
HLock((Handle)myOpenList); |
// prompt the user for a file |
if (NULL == theTypeList) |
{ |
myErr = NavGetFile(NULL, &myReply, &myDialogOptions, NULL, NULL, NULL, NULL, NULL); |
} |
else |
{ |
myErr = NavGetFile(NULL, &myReply, &myDialogOptions, myEventUPP, NULL, (NavObjectFilterUPP)theFilterProc, myOpenList, NULL); |
} |
if ((myErr == noErr) && myReply.validRecord) |
{ |
AEKeyword myKeyword; |
DescType myActualType; |
Size myActualSize = 0; |
// get the FSSpec for the selected file |
if (theFSSpecPtr != NULL) |
myErr = AEGetNthPtr(&(myReply.selection), 1, typeFSS, &myKeyword, &myActualType, theFSSpecPtr, sizeof(FSSpec), &myActualSize); |
NavDisposeReply(&myReply); |
} |
if (myOpenList != NULL) |
{ |
HUnlock((Handle)myOpenList); |
DisposeHandle((Handle)myOpenList); |
} |
DisposeNavEventUPP(myEventUPP); |
return(myErr); |
} |
- (void) CloseSoundFile |
{ |
} |
- (OSErr) OpenSoundFile |
{ |
OSErr myErr = noErr; |
// elicit a new sound file from the user |
myErr = GetOneFileWithPreview(1, NULL, &m_SndFileFSSpec, NULL); |
return(myErr); |
} |
- (void) menuFileOpen: (id) sender |
{ |
if(noErr == [self OpenSoundFile]) |
{ |
[m_SndPlayer PlaySound: &m_SndFileFSSpec]; |
} |
} |
- (IBAction) sliderUpdateParams: (id) sender |
{ |
NSSlider *slider; |
GLfloat fValue; |
slider = sender; |
fValue = [slider floatValue]; |
[slider setContinuous: YES]; |
switch([slider tag]) |
{ |
case 0: m_aa = fValue; break; |
case 1: m_bb = fValue; break; |
case 2: m_cc = fValue; break; |
case 3: m_dd = fValue; break; |
} |
[self timerEventHandler]; |
} |
- (VariableFormatVertex *) CreateLissajousSurface |
{ |
VariableFormatVertex *Surface = [VariableFormatVertex new]; |
GLint nVerticesRequired; |
GLint vertexIndex; |
GLfloat u, v, ustep, vstep; |
GLfloat s, t, sstep, tstep; |
GLint rows, cols; |
GLfloat pi = 3.14159265359; |
vstep = ustep = pi / 40.0; |
sstep = tstep = 1.0 / 40.0; |
if(Surface) |
{ |
// Figure out how many vertices are required to complete the surface (uv) |
for(nVerticesRequired=0, rows=0, u=-pi;u<=pi+ustep; u+=ustep, rows++) |
{ |
for(v=-pi, cols=0;v<=pi+vstep; v+=vstep, nVerticesRequired++, cols++) |
{ |
} |
} |
[Surface initWithVertexType: kAttributeTexture0 vertexArrayOfCount: nVerticesRequired]; |
[Surface setMeshRows: rows Cols: cols]; |
// fill in the vertices |
for(vertexIndex=0, u=-pi, s=0;u<=pi+ustep; u+=ustep, s+=sstep) |
{ |
for(v=-pi, t=0;v<=pi+vstep; v+=vstep, t+=tstep, vertexIndex++) |
{ |
GLfloat *pVertex = [Surface atVertex: vertexIndex]; |
GLfloat *pST = [Surface Texture0: pVertex]; |
pVertex[0] = u; |
pVertex[1] = v; |
pVertex[2] = 0; |
pVertex[3] = 0; |
pST[0] = s; |
pST[1] = t; |
} |
} |
// Enable VertexArray Ranges |
[Surface attachToVertexArrayRange]; |
} |
return Surface; |
} |
- (void) UpdateSurface: (UInt8 *) params |
{ |
GLint i; |
GLfloat fParams[8]; |
GLfloat energy = 1; |
struct timeval tp; |
struct timezone tzp; |
if(LissajousSurface) |
{ |
if (params) |
{ |
for(i=0; i<8; i++) |
fParams[i] = (float)params[i] / 256.0; |
for(energy=0,i=0; i<8; i++) |
energy += fParams[i]; |
energy /= 8.0; |
m_energy = m_energy * 0.95 + energy * 0.1; |
gettimeofday(&tp, &tzp); |
fParams[0] = (float)tp.tv_usec / 1E6; |
fParams[1] = m_energy; |
[m_BasicOpenGLView loadEnvParameter: &fParams[0] atIndex: 1]; |
[m_BasicOpenGLView loadEnvParameter: &fParams[4] atIndex: 2]; |
for(i=0; i<8; i++) |
fParams[i] = (float)params[i] / 256.0; |
for(energy=0,i=0; i<8; i++) |
energy += fParams[i]; |
energy /= 8.0; |
m_aa = m_aa * 0.9 + ((fParams[0] + fParams[1]) / 2) * 0.1; |
m_bb = m_bb * 0.9 + ((fParams[2] + fParams[3]) / 2) * 0.1; |
m_cc = m_cc * 0.9 + ((fParams[4] + fParams[5]) / 2 + 1.0) * 0.1; |
m_dd = m_dd * 0.9 + ((fParams[6] + fParams[7]) / 2 * 2.0) * 0.1; |
} |
fParams[0] = m_aa; |
fParams[1] = m_bb; |
fParams[2] = m_cc; |
fParams[3] = m_dd; |
[m_BasicOpenGLView loadEnvParameter: fParams atIndex: 0]; |
} |
} |
- (void) timerEventHandler |
{ |
UInt8 i, soundLevels[8]; |
GLfloat fSoundLevels[8]; |
if ([m_SndPlayer IsMusicPlaying]) |
{ |
[m_SndPlayer GetSoundEqualizerBandLevels: soundLevels]; |
} |
if (m_VolumeOpenGLView) |
{ |
if (NULL == m_VolumeLines) |
{ |
GLint i; |
m_VolumeLines = [VariableFormatVertex new]; |
// Alloc enough for 100 line segments |
[m_VolumeLines initWithVertexType: kAttributeColor vertexArrayOfCount: 50]; |
for(i=0; i<50; i++) |
{ |
GLfloat *pVertex = [m_VolumeLines atVertex: i]; |
pVertex[0] = 0.0; |
pVertex[1] = 0.0; |
pVertex[2] = 1.0; |
pVertex[3] = 1.0; |
pVertex = [m_VolumeLines Color: pVertex]; |
pVertex[0] = 0.2; |
pVertex[1] = 0.0; |
pVertex[2] = 1.0; |
} |
} |
[m_VolumeOpenGLView frameBegin]; |
if ([m_SndPlayer IsMusicPlaying]) |
{ |
GLfloat energy; |
GLfloat linePos[25]; |
for(i=0; i<25; i++) |
linePos[i] = (float)i / 25.0; |
for(i=0; i<8; i++) |
fSoundLevels[i] = (float)soundLevels[i] / 256.0; |
for(energy=0, i=0; i<8; i++) |
energy += fSoundLevels[i]; |
energy /= 16.0; |
for(i=49; i >= 2; i--) |
{ |
GLfloat *pSrcVertex = [m_VolumeLines atVertex: i-2]; |
GLfloat *pDstVertex = [m_VolumeLines atVertex: i]; |
pDstVertex[0] = linePos[i / 2 + 1]; |
pDstVertex[1] = pSrcVertex[1]; |
} |
{ |
GLfloat *pVertex = [m_VolumeLines atVertex: 0]; |
pVertex[1] = 0.5 - energy; |
pVertex = [m_VolumeLines atVertex: 1]; |
pVertex[1] = 0.5 + energy; |
} |
[m_VolumeOpenGLView drawVertexArray: m_VolumeLines ofType: GL_LINES]; |
} |
[m_VolumeOpenGLView frameEnd]; |
} |
if (m_AnalyzerOpenGLView) |
{ |
if (NULL == m_AnalyzerBars) |
{ |
GLint i; |
GLfloat eightColors[][3] = {{0.5, 0.0, 0.0}, {1.0, 0.0, 0.0}, |
{1.0, 0.5, 0.0}, {0.0, 1.0, 0.0}, |
{0.0, 0.5, 0.0}, {0.0, 1.0, 0.0}, |
{0.0, 0.0, 0.5}, {0.0, 0.0, 1.0}}; |
m_AnalyzerBars = [VariableFormatVertex new]; |
// Alloc enough for 8 quads |
[m_AnalyzerBars initWithVertexType: kAttributeColor vertexArrayOfCount: 32]; |
for(i=0; i<32; i++) |
{ |
GLint barNumber = i / 4; |
GLfloat *pVertex = [m_AnalyzerBars atVertex: i]; |
pVertex[0] = 0.0; |
pVertex[1] = 0.0; |
pVertex[2] = 1.0; |
pVertex[3] = 1.0; |
pVertex = [m_AnalyzerBars Color: pVertex]; |
pVertex[0] = eightColors[barNumber][0]; |
pVertex[1] = eightColors[barNumber][1]; |
pVertex[2] = eightColors[barNumber][2]; |
} |
} |
if ([m_SndPlayer IsMusicPlaying]) |
{ |
[m_AnalyzerOpenGLView frameBegin]; |
for(i=0; i<8; i++) |
fSoundLevels[i] = (float)soundLevels[i] / 256.0; |
for(i=0; i<32; i++) |
{ |
GLint corner = i & 0x3; |
GLint barNumber = i / 4; |
GLfloat *pVertex = [m_AnalyzerBars atVertex: i]; |
switch(corner) |
{ |
case 0: |
pVertex[0] = barNumber * 0.125; |
pVertex[1] = 0; |
pVertex[2] = 0; |
break; |
case 1: |
pVertex[0] = barNumber * 0.125; |
pVertex[1] = fSoundLevels[barNumber]; |
pVertex[2] = 0; |
break; |
case 2: |
pVertex[0] = barNumber * 0.125 + 0.11; |
pVertex[1] = fSoundLevels[barNumber]; |
pVertex[2] = 0; |
break; |
case 3: |
pVertex[0] = barNumber * 0.125 + 0.11; |
pVertex[1] = 0; |
pVertex[2] = 0; |
break; |
} |
} |
[m_AnalyzerOpenGLView drawVertexArray: m_AnalyzerBars ofType: GL_QUADS]; |
[m_AnalyzerOpenGLView frameEnd]; |
} |
} |
if (m_BasicOpenGLView) |
{ |
int i; |
float scale; |
[m_BasicOpenGLView frameBegin]; |
if ([m_SndPlayer IsMusicPlaying]) |
{ |
[self UpdateSurface: soundLevels]; |
for(scale=0, i=0; i<8; i++) |
scale += soundLevels[i]; |
scale = scale / 1024; |
m_scale = m_scale * 0.9 + scale * 0.1; |
} |
else |
{ |
[self UpdateSurface: NULL]; |
} |
[m_BasicOpenGLView enableVertexPrograms]; |
if ([m_BasicOpenGLView wireframeMode]) |
[m_BasicOpenGLView drawVertexArray: LissajousSurface ofType: GL_LINE_STRIP]; |
else |
[m_BasicOpenGLView drawVertexArray: LissajousSurface ofType: GL_QUAD_STRIP]; |
[m_BasicOpenGLView disableVertexPrograms]; |
[m_BasicOpenGLView frameEnd]; |
} |
} |
@end |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-07-07