This is BattleView.m in view mode; [Download] [Up]
/* Copyright 1992, Stefanos Kiakas. All rights reserved. You may not delete this notice. */ #define ABS(x) ( x < 0 ? -x : x) /* macro to calculate absolute value */ #define RANDTARGET ( random() % TARGETS)/* select a random target to attack */ #define RANDLAUNCH ( ( random() % 440 ) + 20 ) /* x pos. of attack missles */ #define PLACECITY(x) ( random() % x ) /* selct position to place city */ #define NULL 0 /* define end of list marker */ #define MAXRADIUS 15.0 /* maximum radius of explosions */ #define TERRAINCOLOUR 0.20 #define TIMEINTERVAL 0.1 #define DELTA_TIME 100 #define RADINC 1.0 /* radius increment of explosion circles */ #define MAXDEFEXP 15 #define MAXDEFLAUNCH 10 /* maximum number of defensive missiles */ #define MAXATCKMSSLS 10 /* maximum number of attack missiles */ /* define launch coordinates for defensive missiles */ #define LAUNCH_X 250.0 #define LAUNCH_Y 25.0 #define DISP 3.0 #define CDX 18.0 // center of target from display coordinates #define CITYBONUS 500 // city saved bonus #define MSLBONUS 50 // missiles saved bonus #define MSLDSTRCT 100 // attack missle intercepted ( destroyed ) bonus #define BONUSMARK 7000 // give bonus city every so many points #define OLAUNCH_Y 390.0; /* Y launch position of attack missles */ #define DX 5.0 #define DY 5.0 #define H_CURSOR 330 #define W_CURSOR 460 #define Y_CURSOR 50 #define X_CURSOR 20 #define H_TRG Y_CURSOR + H_CURSOR #define W_TRG X_CURSOR + W_CURSOR #define Y_TRG Y_CURSOR #define X_TRG X_CURSOR #define MAXNDIFF 2.0 /* maximum difficulty for novice level */ #define MAXEDIFF 2.5 /* maximum difficulty for experienced level */ #define MAXPDIFF 3.0 /* maximum difficulty for pro level */ #define STARTNDIFF 0.8 /* starting difficulty for novice level */ #define STARTEDIFF 0.75 /* starting difficulty for experienced level */ #define STARTPDIFF 0.9 /* starting difficulty for por level */ #define DIFFINCN 0.1 /* increase in difficulty after each attack for novice level */ #define DIFFINCE 0.25 /* increase in difficulty after each attack for experienced level */ #define DIFFINCP 0.3 /* increase in difficulty after each attack for pro level */ #define DISPLAYDELAY 50000 #define SCOREXPOS 150 #define SCOREYPOS 250 #import "markLoc.h" #import "plotTrajectory.h" #import "scorePhaseCities.h" #import "scorePhaseMissiles.h" #include <sys/param.h> #import <libc.h> #import "BattleView.h" #import <appkit/appkit.h> #import <soundkit/Sound.h> @implementation BattleView - initFrame:(const NXRect *) frm { char appD[MAXPATHLEN]; NXPoint mySpot; [super initFrame:frm ]; [self allocateGState]; gameRunning = FALSE; gamePaused = FALSE; sprintf(appD,"%s/%s",[self appDirectory],"RedAlert.snd"); redAlertSound = [ [Sound alloc] initFromSoundfile:appD ]; cityBitmap = [NXImage findImageNamed:"city3.tiff"]; launcherBitmap = [NXImage findImageNamed:"mBase.tiff"]; cursorImage=[NXCursor newFromImage:[NXImage newFromSection:"targetD3.tiff"]]; cBounds.origin.x = X_CURSOR; cBounds.origin.y = Y_CURSOR; cBounds.size.width= W_CURSOR; cBounds.size.height = H_CURSOR; mySpot.x = 8; mySpot.y = 7; [cursorImage setHotSpot:&mySpot]; ndiffstart = STARTNDIFF; ndiffinc = DIFFINCN; ndiffmax = MAXNDIFF; return self; } /* This function was shamelessly copied from the examples provided. */ - (const char *)appDirectory { char *suffix; strcpy(appDirectory, NXArgv[0]); if (suffix = rindex(appDirectory,'/')) *suffix = '\0'; if (appDirectory) chdir(appDirectory); getwd(appDirectory); return appDirectory; } - selectExperienced:sender { ndiffinc = DIFFINCE; ndiffstart = STARTEDIFF; ndiffmax = MAXEDIFF; return self; } - selectNovice:sender { ndiffinc = DIFFINCN; ndiffstart = STARTNDIFF; ndiffmax = MAXNDIFF; return self; } - selectPro:sender { ndiffinc = DIFFINCP; ndiffstart = STARTPDIFF; ndiffmax = MAXPDIFF; return self; } - pauseGame:sender { void stepFun(); if( gameRunning ) { gameRunning = FALSE; gamePaused = TRUE; DPSRemoveTimedEntry(gameTimer); } else if( !gameRunning && gamePaused ) { gameRunning = TRUE; gamePaused = FALSE; gameTimer =DPSAddTimedEntry(TIMEINTERVAL,&stepFun,self,NX_BASETHRESHOLD); } return self; } - resetCursorRects { [self addCursorRect:&cBounds cursor:cursorImage]; return self; } - newGame:sender { int i; void stepFun(); unsigned int currentTimeInMs(); MSLE_NODE_PNTR cpdm,fpdm; MA_NODE_PNTR cpam,fpam; EXP_PNTR cpe,fpe; if( !gameRunning && !gamePaused ) { /* set up current game difficulty levels */ cdiffstart = ndiffstart; cdiffinc = ndiffinc; cdiffmax = ndiffmax; dFactor = cdiffstart; phaseOne = TRUE; defensiveMissiles.launched = 0; defensiveMissiles.next = NULL; offensiveMissiles.launched = 0; offensiveMissiles.next = NULL; defensiveExplosions.exploding = 0; defensiveExplosions.next = NULL; for( i = 0; i < CITIES; i++) if( ( i % 3 ) && ( i %4 ) ) cityStatus[i] = TRUE; else cityStatus[i] = FALSE; // reset number of missiles aTimeBefore = currentTimeInMs(); // select attack positions [self selectTargets]; missiles = 40; score = 0; lastBonusAt = 0; displayBase = TRUE; [outMissiles setIntValue:missiles]; [outScore setIntValue:score]; [window makeKeyAndOrderFront:self]; gameRunning = TRUE; gameTimer =DPSAddTimedEntry(TIMEINTERVAL,&stepFun,self,NX_BASETHRESHOLD); [self display]; } else if( gameRunning && !gamePaused ) { gameRunning = FALSE; DPSRemoveTimedEntry(gameTimer); // remove entries in linked lists cpdm = defensiveMissiles.next; while( cpdm != NULL ) { fpdm = cpdm; cpdm = cpdm->next; free(fpdm); } /* remove attack missiles from list, and free memory */ cpam = offensiveMissiles.next; while( cpdm != NULL ) { fpam = cpam; cpam = cpam->next; free(fpam); } /* remove air explosions from list and free memory */ cpe = defensiveExplosions.next; while( cpe != NULL ) { fpe = cpe; cpe = cpe->next; free(fpe); } /* remove surface explosions from list and free memory */ cpe = surfaceExplosions.next; while( cpe != NULL ) { fpe = cpe; cpe = cpe->next; free(fpe); } } return self; } unsigned currentTimeInMs() { struct timeval curTime; gettimeofday(&curTime, NULL); return ((unsigned)curTime.tv_sec)*1000+curTime.tv_usec / 1000; } - step { NXEvent dummyEvent; unsigned int timeNow,dTime; do { timeNow = currentTimeInMs(); dTime = timeNow - aTimeBefore; if( dTime > DELTA_TIME ) { aTimeBefore = timeNow; if( defensiveMissiles.launched != 0 ) [self missilePath]; if( defensiveExplosions.exploding > 0 ) [self expDraw]; if( offensiveMissiles.launched > 0) [self attackMissilesPath]; if( surfaceExplosions.exploding > 0 ) [self surfaceExplosionsDraw]; } if( defensiveMissiles.launched == 0 && defensiveExplosions.exploding == 0 && offensiveMissiles.launched == 0 && surfaceExplosions.exploding == 0 ) { if( !phaseOne ) [ self bonusPoints]; [self nextLevel]; } NXPing(); } while ([NXApp peekNextEvent:NX_ALLEVENTS into:&dummyEvent] == NULL ); return self; } - drawSelf:(const NXRect *)r :(int)c { int i; PSsetgray(1.0); NXRectFill(r); PSsetgray(NX_BLACK); NXFrameRect(r); // draw terrain PSsetgray(TERRAINCOLOUR); PSnewpath(); PSmoveto(0.0,0.0); PSrlineto(0.0,5.0); PSrlineto(50.0,0.0); PSrlineto(5.0,5.0); PSrlineto(40.0,0.0); PSrlineto(5.0,-5.0); PSrlineto(80.0,0.0); PSrlineto(5.0,5.0); PSrlineto(40.0,0.0); PSrlineto(5.0,5.0); PSrlineto(40.0,0.0); PSrlineto(5.0,-5.0); PSrlineto(40.0,0.0); PSrlineto(5.0,-5.0); PSrlineto(80.0,0.0); PSrlineto(5.0,5.0); PSrlineto(40.0,0.0); PSrlineto(5.0,-5.0); PSrlineto(50.0,0.0); PSrlineto(0.0,-5.0); PSclosepath(); PSfill(); PSflushgraphics(); if( displayBase ) /* display missles base if it has not been destroyed */ [self drawLaunchPad]; for(i=0;i<CITIES; i++) if( cityStatus[i] ) [self drawCityBM:CBarray[i].coord]; return self; } - drawCityBM:(NXPoint ) dcPt { [cityBitmap composite:NX_SOVER toPoint:&dcPt]; return self; } - drawLaunchPad { NXPoint Pt; Pt.x = 230.0; Pt.y = 15.0; [launcherBitmap composite:NX_SOVER toPoint:&Pt]; return self; } - drawMissile { id missileBitmap = [NXImage findImageNamed:"missileIcon.tiff"]; NXPoint Pt; Pt.x = 160.0; Pt.y = 190.0; [missileBitmap composite:NX_COPY toPoint:&Pt]; return self; } - mouseDown:(NXEvent *)theEvent { NXPoint sPt; int pntInRect(); MSLE_NODE_PNTR mLaunch,p; sPt = theEvent->location; [self convertPoint:&sPt fromView:nil]; if ( defensiveMissiles.launched < MAXDEFLAUNCH && missiles > 0 && pntInRect(&sPt)) { [outMissiles setIntValue:--missiles]; defensiveMissiles.launched++; [self lockFocus]; markLoc(sPt.x,sPt.y); [self unlockFocus]; mLaunch = malloc(sizeof(MSLE_NODE)); mLaunch->dPos = sPt; mLaunch->cPos.x = LAUNCH_X; mLaunch->cPos.y = LAUNCH_Y; mLaunch->next = NULL; // must check for zeros if (ABS(sPt.x - LAUNCH_X) > ABS(sPt.y - LAUNCH_Y)) { mLaunch->delta_x = DISP; mLaunch->delta_y = DISP *(sPt.y - LAUNCH_Y) /(sPt.x - LAUNCH_X); } else { mLaunch->delta_y = DISP; mLaunch->delta_x = DISP *(sPt.x - LAUNCH_X)/ (sPt.y - LAUNCH_Y); } if ( defensiveMissiles.next == NULL) defensiveMissiles.next = mLaunch; else { p = defensiveMissiles.next; while (p->next != NULL ) p = p->next; p->next = mLaunch; } } return self; } - expDraw { EXP_PNTR cp,pp; pp = cp = defensiveExplosions.next; [self lockFocus]; while (cp != NULL ) { if (cp->rad > MAXRADIUS ) { cp->maxReached = YES; cp->rad += ( cp->maxReached ) ? -RADINC: RADINC ; pp = cp; cp = cp->next; } else if ( ( cp->rad <= 0.0 ) && cp->maxReached ) { if ( defensiveExplosions.next == cp ) { pp = defensiveExplosions.next = cp->next; free(cp); cp = pp; } else { pp->next = cp->next; free(cp); cp = pp->next; } defensiveExplosions.exploding--; } else { PSsetgray((cp->maxReached) ? NX_WHITE : NX_BLACK ); PSarc(cp->cPt.x,cp->cPt.y,cp->rad,0.0,360.0); PSstroke(); PSflushgraphics(); cp->rad += (( cp->maxReached ) ? -RADINC: RADINC ) ; pp = cp; cp = cp->next; } } [self unlockFocus]; return self; } - surfaceExplosionsDraw { EXP_PNTR cp,pp; pp = cp = surfaceExplosions.next; [self lockFocus]; while (cp != NULL ) { if (cp->rad > MAXRADIUS ) { cp->maxReached = YES; cp->rad += ( cp->maxReached ) ? -RADINC: RADINC ; pp = cp; cp = cp->next; } else if ( ( cp->rad <= 0.0 ) && cp->maxReached ) { if ( surfaceExplosions.next == cp ) { pp = surfaceExplosions.next = cp->next; PSnewpath(); PSsetgray( NX_WHITE); PSmoveto(cp->cPt.x,cp->cPt.y); PSrlineto(-10,0); PSrlineto(0,20); PSrlineto(30,0); PSrlineto(0,-20); PSrlineto(-10,0); PSfill(); PSflushgraphics(); free(cp); cp = pp; } else { pp->next = cp->next; PSnewpath(); PSsetgray( NX_WHITE); PSmoveto(cp->cPt.x,cp->cPt.y); PSrlineto(-10,0); PSrlineto(0,20); PSrlineto(30,0); PSrlineto(0,-20); PSrlineto(-10,0); PSfill(); PSflushgraphics(); free(cp); cp = pp->next; } surfaceExplosions.exploding--; } else { [self lockFocus]; PSsetgray((cp->maxReached) ? NX_WHITE : NX_BLACK ); PSarc(cp->cPt.x,cp->cPt.y,cp->rad,1.0,180.0); PSstroke(); PSflushgraphics(); [self unlockFocus]; cp->rad += (( cp->maxReached ) ? -RADINC: RADINC ) ; pp = cp; cp = cp->next; } } [self unlockFocus]; return self; } - missilePath { NXPoint nPos; // new missile position MSLE_NODE_PNTR cp,pp,dp; EXP_PNTR nExp; pp = cp = defensiveMissiles.next; [self lockFocus]; while ( cp != NULL ) { if ( cp->dPos.y <= cp->cPos.y) /* missile has reached it destination */ { PSmoveto(LAUNCH_X,LAUNCH_Y); PSlineto(cp->dPos.x,cp->dPos.y); PSsetgray(NX_WHITE); PSsetlinewidth(2.0); PSstroke(); PSsetgray(NX_BLACK); PSflushgraphics(); if ( cp == defensiveMissiles.next ) { defensiveMissiles.next = cp->next; dp = cp; cp = defensiveMissiles.next; } else { pp->next = cp->next; dp = cp; cp = pp->next; } nExp = malloc(sizeof(EXP_NODE)); nExp->cPt = dp->dPos; nExp->rad = 0.0; nExp->maxReached = NO; nExp->next = NULL; free(dp); [self addToAirExplosions:nExp]; defensiveMissiles.launched--; } else /* calculate and plot next position */ { nPos.x = cp->cPos.x + cp->delta_x; if( cp->delta_x < 0 ) /* make sure that point is not past detonation point */ { if( nPos.x < cp->dPos.x) nPos.x = cp->dPos.x; } else { if( nPos.x > cp->dPos.x ) nPos.x = cp->dPos.x; } nPos.y = cp->cPos.y + cp->delta_y; if ( cp->dPos.y > cp->cPos.y ) { plotTrajectory(cp->cPos.x,cp->cPos.y,nPos.x,nPos.y); cp->cPos = nPos; } pp = cp; cp = cp->next; } } [self unlockFocus]; return self; } - nextLevel { int cities,i; cities = 0; for(i=0;i<CITIES; i++) if( cityStatus[ i ] ) cities++; if( cities == 0 ) gameRunning = FALSE; else { if( phaseOne) phaseOne = FALSE; else { phaseOne = TRUE; if( dFactor < cdiffmax ) dFactor += cdiffinc; missiles = 40; displayBase = TRUE; } // reset time aTimeBefore = currentTimeInMs(); [outMissiles setIntValue:missiles]; [outScore setIntValue:score]; [self display]; // calculate attack positions [self selectTargets]; } return self; } - bonusPoints { NXPoint cityPt; int cities,i,re; int vacantPos[ CITIES ],j; unsigned int stime,etime; cityPt.x = SCOREXPOS; cityPt.y = SCOREYPOS; cities = 0; for(i=0;i<CITIES; i++) if( cityStatus[ i ] ) cities++; [self lockFocus]; [self drawCityBM:cityPt]; [self unlockFocus]; for(i=0; i <= cities; i++ ) { [self lockFocus]; scorePhaseCities(i,i*CITYBONUS,&re); [self unlockFocus]; } etime = stime = currentTimeInMs(); while( etime - stime < 100 ) etime = currentTimeInMs(); score += cities * CITYBONUS; [outScore setIntValue:score]; [self lockFocus]; [self drawMissile]; [self unlockFocus]; for(i=0; i <= missiles; i++ ) { [self lockFocus]; scorePhaseMissiles(i,i*MSLBONUS,&re); [self unlockFocus]; etime = stime = currentTimeInMs(); while( etime - stime < 100 ) etime = currentTimeInMs(); } score += missiles * MSLBONUS; [outScore setIntValue:score]; etime = stime = currentTimeInMs(); while( etime - stime < 1000 ) etime = currentTimeInMs(); if( score - lastBonusAt > BONUSMARK ) { lastBonusAt += BONUSMARK; j = 0; for(i=0;i<CITIES ; i++) if( cityStatus[ i ] == FALSE ) vacantPos[j++] = i; ; if( j ) cityStatus[ vacantPos[PLACECITY(j)]] = TRUE; else score += CITYBONUS; } return self; } - selectTargets { float dx,dy; MA_NODE_PNTR head,cp,pp; pp = head = cp = malloc(sizeof(MA_NODE)); while (++offensiveMissiles.launched <= MAXATCKMSSLS ) /* attack missles init */ { cp->sPos.x = RANDLAUNCH; cp->sPos.y = OLAUNCH_Y; cp->targetLoc = RANDTARGET; cp->dPos.x = CBarray[cp->targetLoc].coord.x + CDX; cp->dPos.y = CBarray[cp->targetLoc].coord.y; cp->cPos = cp->sPos; dx = cp->dPos.x - cp->sPos.x ; dy = cp->dPos.y - OLAUNCH_Y; if ( ABS(dy ) > ABS(dx)) { cp->delta_y = -1.0; cp->delta_x = ( dx ) / ABS(dy ); } else { cp->delta_y = ( dy )/ABS( dx ) ; cp->delta_x = ABS(dx ) / dx ; } cp->next = malloc(sizeof(MA_NODE)); pp = cp; cp = cp->next; } offensiveMissiles.launched--; offensiveMissiles.next = head; pp->next = NULL; free(cp); [redAlertSound play]; return self; } - addToAirExplosions: (EXP_PNTR )aExp { EXP_PNTR ep; if ( defensiveExplosions.next == NULL ) defensiveExplosions.next = aExp; else { ep = defensiveExplosions.next; while (ep->next != NULL ) ep = ep->next; ep->next = aExp; } defensiveExplosions.exploding++; return self; } - addToSurfaceExplosions:(EXP_PNTR) aExp { EXP_PNTR ep; if ( surfaceExplosions.next == NULL ) surfaceExplosions.next = aExp; else { ep = surfaceExplosions.next; while (ep->next != NULL ) ep = ep->next; ep->next = aExp; } surfaceExplosions.exploding++; return self; } - attackMissilesPath { MA_NODE_PNTR head,cp,pp; EXP_PNTR nExp; NXPoint nPt; NXRect rect = {{0.0, 0.0}, {1.0, 1.0}}; id image; NXColor colorAtSomeLoc, colorAt(); float alpha,color; [self lockFocus]; head = cp = pp = offensiveMissiles.next; /* set up pointers to point at head of attack missile list */ while ( cp != NULL ) { // calculate next point in trajectory nPt.x = cp->cPos.x + dFactor * cp->delta_x; nPt.y = cp->cPos.y + dFactor * cp->delta_y; // set rect to check if missile has been hit rect.origin = nPt; image = [[NXBitmapImageRep alloc] initData:NULL fromRect:&rect]; colorAtSomeLoc = colorAt(image, 0, 0); [image free]; NXConvertColorToGrayAlpha (colorAtSomeLoc, &color, &alpha); if ( nPt.y < cp->dPos.y) /* attack missile has arrived at target */ { offensiveMissiles.launched--; if ( cp->targetLoc == ( TARGETS - 1 ) ) { missiles = 0; [outMissiles setIntValue:missiles]; displayBase = FALSE; } else cityStatus[ cp->targetLoc ] = FALSE; /* erase missile trajectory */ PSmoveto(cp->cPos.x,cp->cPos.y); PSlineto(cp->sPos.x,cp->sPos.y); PSsetgray(NX_WHITE); PSsetlinewidth(2.0); PSstroke(); PSsetlinewidth(1.0); PSflushgraphics(); /* creat an explosion node for surface explosions */ nExp = malloc(sizeof(EXP_NODE)); nExp->cPt = cp->cPos; nExp->rad = 0.0; nExp->maxReached = NO; nExp->next = NULL; [self addToSurfaceExplosions:nExp]; /* add explosion to surface exp. list */ if ( cp == head ) { offensiveMissiles.next = head = cp->next; free(cp); cp = head; } else { pp-> next = cp->next; free(cp); cp = pp->next; } } else if ( ( ABS(color - NX_BLACK) < 0.005 ) && ( cp->cPos.y > 35 )) { offensiveMissiles.launched--; // missile has been destroyed score += MSLDSTRCT; [outScore setIntValue:score]; // remove missile trajectory PSmoveto(cp->cPos.x,cp->cPos.y); PSlineto(cp->sPos.x,cp->sPos.y); PSsetgray(NX_WHITE); PSsetlinewidth(2.0); PSstroke(); PSsetlinewidth(1.0); PSflushgraphics(); nExp = malloc(sizeof(EXP_NODE)); nExp->cPt = cp->cPos; nExp->rad = 0.0; nExp->maxReached = NO; nExp->next = NULL; [self addToAirExplosions:nExp]; // remove missile from list if ( cp == head ) { offensiveMissiles.next = head = cp->next; free(cp); cp = pp = head; } else { pp-> next = cp->next; free(cp); cp = pp->next; } } else { plotTrajectory(cp->cPos.x,cp->cPos.y,nPt.x,nPt.y); cp->cPos = nPt; pp = cp; cp = cp->next; } } [self unlockFocus]; return self; } int pntInRect(pnt) NXPoint *pnt; { if( pnt->x >= X_TRG && pnt->y >= Y_TRG && pnt->x <= W_TRG && pnt->y <= H_TRG ) return(TRUE); else return(FALSE); } void stepFun (DPSTimedEntry timedE, double timeN, void *data) { [(id)data step ]; } /**************************************************************************************************/ /* all the following code has been copied from the NeXT answers code provided by NeXT */ /***************************************************************************************************/ /* Returns the color at a certain pixel location in a bitmap. */ /* This version assumes the bitmap is 1, 2, 4, or 8 bps deep */ /* and its either grayscale or RGB. */ NXColor colorAt(NXBitmapImageRep *image, int x, int y) { int sampleCnt, bps, spp, amask; unsigned char *planes[5], data[5]; NXColorSpace colorSpace; spp = [image samplesPerPixel]; bps = [image bitsPerSample]; colorSpace = [image colorSpace]; #ifdef CHECK_VALIDITY if ((bps != 1 && bps != 2 && bps != 4 && bps != 8) || (colorSpace != NX_RGBColorSpace || colorSpace != NX_OneIsBlackColorSpace || colorSpace != NX_OneIsWhiteColorSpace)) { NXLogError ("colorAt() can't deal with provided image.\n"); return NX_COLORCLEAR; } #endif #ifdef CHECK_RANGE if ((x < 0) || (y < 0) || (x >= [image pixelsWide]) || (y >= [image pixelsHigh])) { NXLogError ("Pixel out of bounds in colorAt().\n"); return NX_COLORCLEAR; } #endif [image getDataPlanes:planes]; amask = (1 << bps) - 1; /* 1, 3, 15, 255 for bps = 1, 2, 4, 8 */ /* Get the samples into the data[] array. */ if ([image isPlanar]) { int pixel = x * bps; int byteLoc = [image bytesPerRow] * y + (pixel >> 3); int bitLoc = pixel & 7; for (sampleCnt = 0; sampleCnt < spp; sampleCnt++) { data[sampleCnt] = ((*(planes[sampleCnt]+byteLoc)) >> (8 - bitLoc - bps)) & amask; } } else { unsigned char *byteLoc = planes[0] + [image bytesPerRow] * y; int bitLoc = x * bps * spp; for (sampleCnt = 0; sampleCnt < spp; sampleCnt++) { data[sampleCnt] = ((byteLoc[bitLoc >> 3]) >> (8 - (bitLoc & 7) - bps)) & amask; bitLoc += bps; } } /* If no alpha, set it to opaque and increment spp. */ /* Otherwise, compute the true color values (by un-premultipling). */ if (![image hasAlpha]) { data[spp] = amask; spp++; } else if (data[spp - 1] && data[spp - 1] != amask) { for (sampleCnt = 0; sampleCnt < spp - 1; sampleCnt++) { data[sampleCnt] = (unsigned char)(0.5 + amask * ( ((float)(data[sampleCnt])) / (data[spp - 1]) )); } } /* At this point data[] contains spp samples, right justified */ /* within the range 0..amask. We can either return those, or */ /* return them in a normalized fashion (in the range 0..255, */ /* after shifting them over to the left by multiplying them by */ /* 255/amask), or we can return an NXColor. The latter is less */ /* efficient, probably, but most abstract. */ switch (colorSpace) { case NX_RGBColorSpace: return NXConvertRGBAToColor(((float)data[0]) / amask, ((float)data[1]) / amask, ((float)data[2]) / amask, [image hasAlpha] ? ((float)data[3]) / amask : NX_NOALPHA); case NX_OneIsWhiteColorSpace: return NXConvertGrayAlphaToColor(((float)data[0]) / amask, [image hasAlpha] ? ((float)data[1]) / amask : NX_NOALPHA); case NX_OneIsBlackColorSpace: return NXConvertGrayAlphaToColor(((float)(amask - data[0])) / amask, [image hasAlpha] ? ((float)(amask - data[1])) / amask : NX_NOALPHA); } } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.