|
|
1.1 ! root 1: ! 2: #import <math.h> ! 3: #import <libc.h> ! 4: #import <c.h> ! 5: #import <defaults/defaults.h> ! 6: #import <sys/file.h> ! 7: #import <appkit/appkit.h> ! 8: #import "WorldSpaceView.h" ! 9: #import "SpaceView.h" ! 10: #import "Thinker.h" ! 11: ! 12: @implementation WorldSpaceView ! 13: ! 14: // x & y periods in milliseconds ! 15: #define X_PERIOD 20000.0 ! 16: #define Y_PERIOD 19000.0 ! 17: #define DEFAULT_FPS 20 ! 18: ! 19: #define PI 3.1415926535 ! 20: ! 21: // #define MAX_IMAGE_WIDTH 200 ! 22: // #define MAX_IMAGE_HEIGHT 150 ! 23: #define MAX_IMAGE_WIDTH 256 ! 24: #define MAX_IMAGE_HEIGHT 256 ! 25: ! 26: #define MAX_X_SPEED (26) ! 27: #define MAX_Y_SPEED (26) ! 28: ! 29: #define BUFFER_WIDTH (MAX_IMAGE_WIDTH + MAX_X_SPEED + 1) ! 30: #define BUFFER_HEIGHT (MAX_IMAGE_HEIGHT + MAX_Y_SPEED + 1) ! 31: ! 32: ! 33: ! 34: // move the world to its new position ! 35: - oneStep ! 36: { ! 37: NXRect black = {0,0,0,0}; ! 38: NXRect ballRect; ! 39: BRECT new; ! 40: ! 41: then = now; ! 42: now = currentTimeInMs(); ! 43: // now += 30; ! 44: ! 45: // calculate new ball x & y position ! 46: xpos = ((1 + sin(((float)now) / X_PERIOD * 2. * PI))/2.0) ! 47: * maxCoord.x; ! 48: ypos = ((1 + sin(((float)now) / Y_PERIOD * 2. * PI))/2.0) ! 49: * maxCoord.y; ! 50: ! 51: ! 52: if (xpos < (old.l - MAX_X_SPEED)) xpos = old.l - MAX_X_SPEED; ! 53: else if (xpos > (old.l + MAX_X_SPEED)) xpos = old.l + MAX_X_SPEED; ! 54: ! 55: if (ypos < (old.b - MAX_Y_SPEED)) ypos = old.b - MAX_Y_SPEED; ! 56: else if (ypos > (old.b + MAX_Y_SPEED)) ypos = old.b + MAX_Y_SPEED; ! 57: ! 58: ! 59: /* animate by selecting a new image to blit */ ! 60: ! 61: [self incrementImageNumber]; ! 62: ! 63: new.l = floor(xpos); ! 64: new.b = floor(ypos); ! 65: new.r = new.l + imageSize.width; ! 66: new.t = new.b + imageSize.height; ! 67: ! 68: ballRect.origin.x = 0; ! 69: ballRect.origin.y = 0; ! 70: ballRect.size.width = imageSize.width; ! 71: ballRect.size.height = imageSize.height; ! 72: ! 73: redrawTo.x = MIN(new.l, old.l); ! 74: redrawTo.y = MIN(new.b, old.b); ! 75: ! 76: redraw.origin.x = 0; ! 77: redraw.origin.y = 0; ! 78: redraw.size.width = (MAX(new.r, old.r)) - redrawTo.x + 1; ! 79: redraw.size.height = (MAX(new.t, old.t)) - redrawTo.y + 1; ! 80: ! 81: black.size= redraw.size; ! 82: ! 83: [buffer lockFocus]; ! 84: PSsetgray(0); ! 85: NXRectFill(&black); ! 86: ! 87: ballTo.x = new.l - redrawTo.x; ! 88: ballTo.y = new.b - redrawTo.y; ! 89: ! 90: [currentImage composite:NX_SOVER fromRect:&ballRect toPoint:&ballTo]; ! 91: [buffer unlockFocus]; ! 92: ! 93: ! 94: // Now bring it onto the screen ! 95: ! 96: [buffer composite:NX_COPY fromRect:&redraw toPoint:&redrawTo]; ! 97: ! 98: old = new; ! 99: ! 100: // now put in the stars... ! 101: ! 102: avoid.origin = redrawTo; ! 103: [mySpaceView setVoidRect:&avoid]; ! 104: [mySpaceView oneStep]; ! 105: ! 106: return self; ! 107: } ! 108: ! 109: ! 110: ! 111: static char *basename(char *path, const char *suffix) ! 112: { ! 113: char *begin, *end, *name; ! 114: int len; ! 115: ! 116: if (strlen(path) < strlen(suffix)) { ! 117: end = begin = path; ! 118: } ! 119: else { ! 120: begin = rindex(path, '/'); ! 121: if (begin) begin++; ! 122: else begin = path; ! 123: ! 124: end = path+strlen(path)-strlen(suffix); ! 125: if (0 != strcmp(end, suffix)) ! 126: end = path+strlen(path); ! 127: ! 128: if (end < begin) end = begin; ! 129: } ! 130: len = end-begin; ! 131: name = malloc(len+1); ! 132: strncpy(name, begin, len); ! 133: name[len] = '\0'; ! 134: return name; ! 135: } ! 136: ! 137: ! 138: static BOOL noAnimFile = FALSE; ! 139: ! 140: - initFrame:(const NXRect *)frameRect ! 141: { ! 142: char moduleDirectory[1024]; ! 143: const char *animSpeed, *animFile, *animName; ! 144: char animFrame[1024]; ! 145: int i, f; ! 146: id local_image; ! 147: ! 148: NXRect black = {0, 0, BUFFER_WIDTH, BUFFER_HEIGHT }; ! 149: ! 150: [super initFrame:frameRect]; ! 151: [self allocateGState]; // For faster lock/unlockFocus ! 152: [self setClipping:NO]; // even faster... ! 153: ! 154: //in this case, I only need one buffer for several Views ! 155: if (!(buffer = [NXImage findImageNamed:"worldBuffer"])) ! 156: { ! 157: buffer = [[NXImage alloc] initSize:&black.size]; ! 158: [buffer setName:"worldBuffer"]; ! 159: } ! 160: ! 161: if ([buffer lockFocus]) ! 162: { ! 163: PSsetgray(0); ! 164: NXRectFill(&black); ! 165: [buffer unlockFocus]; ! 166: } ! 167: ! 168: ! 169: animSpeed = NXGetDefaultValue([NXApp appName], "animSpeed"); ! 170: if (animSpeed == NULL) framesPerSecond = DEFAULT_FPS; ! 171: else framesPerSecond = atoi(animSpeed); ! 172: ! 173: animFile = NXGetDefaultValue([NXApp appName], "animFile"); ! 174: if (animFile == NULL) ! 175: { ! 176: sprintf(moduleDirectory,"%s/Globe.anim", ! 177: [(BSThinker()) moduleDirectory:"WorldSpace"]); ! 178: animFile = moduleDirectory; ! 179: } ! 180: animName = basename((char *)animFile, ".anim"); ! 181: ! 182: imageList = [[List alloc] init]; ! 183: ! 184: /* construct the image list */ ! 185: for (i=0; ; i++) ! 186: { ! 187: sprintf(animFrame, "%s/%s.%d.tiff", animFile, animName, i+1); ! 188: if (!(local_image = [NXImage findImageNamed:animFrame])) ! 189: { ! 190: if ((f=open(animFrame, O_RDONLY)) < 0) break; ! 191: close(f); ! 192: ! 193: local_image = [[NXImage alloc] initFromFile:animFrame]; ! 194: if (local_image == NULL) break; // never null, even if no file ! 195: [local_image setName:animFrame]; ! 196: } ! 197: ! 198: [imageList addObject:local_image]; ! 199: if (i == 0) [local_image getSize: &imageSize]; ! 200: } ! 201: numberOfFrames = i; ! 202: currentFrame = 0; ! 203: ! 204: if (numberOfFrames == 0) ! 205: { ! 206: if (!noAnimFile) ! 207: NXRunAlertPanel([NXApp appName], "Could not open %s", ! 208: NULL, NULL, NULL, animFile); ! 209: noAnimFile = TRUE; ! 210: return nil; ! 211: } ! 212: ! 213: nextRotationTime = 0; ! 214: ! 215: [self newViewSize]; ! 216: ! 217: mySpaceView = [[SpaceView alloc] initFrame:frameRect]; ! 218: avoid.size = imageSize; ! 219: ! 220: return self; ! 221: } ! 222: ! 223: - sizeTo:(NXCoord)width :(NXCoord)height ! 224: { ! 225: [super sizeTo:width :height]; ! 226: [mySpaceView sizeTo:width :height]; ! 227: [self newViewSize]; ! 228: return self; ! 229: } ! 230: ! 231: - drawSelf:(const NXRect *)rects :(int)rectCount ! 232: { ! 233: // if (!rects || !rectCount) return self; ! 234: ! 235: //PSsetgray(0); ! 236: //NXRectFill(rects); ! 237: ! 238: //NXRectClip(rects); ! 239: ! 240: return self; ! 241: } ! 242: ! 243: - newViewSize ! 244: { ! 245: //this is called every time View size changes ! 246: NXRect black = {0, 0, BUFFER_WIDTH, BUFFER_HEIGHT }; ! 247: ! 248: then = now = currentTimeInMs(); ! 249: ! 250: if (oldSize.width == bounds.size.width && ! 251: oldSize.height == bounds.size.height) ! 252: return self; ! 253: else ! 254: { ! 255: oldSize.width = bounds.size.width; ! 256: oldSize.height = bounds.size.height; ! 257: } ! 258: ! 259: maxCoord.x = bounds.size.width - imageSize.width; ! 260: maxCoord.y = bounds.size.height - imageSize.height; ! 261: if (maxCoord.x < 0) maxCoord.x = 0; ! 262: if (maxCoord.y < 0) maxCoord.y = 0; ! 263: ! 264: ! 265: old.l = old.r = maxCoord.x/2; ! 266: old.b = old.t = maxCoord.y/2; ! 267: ballTo.x = ballTo.y = 0; ! 268: ! 269: if ([buffer lockFocus]) ! 270: { ! 271: PSsetgray(0); ! 272: NXRectFill(&black); ! 273: [buffer unlockFocus]; ! 274: } ! 275: ! 276: return self; ! 277: } ! 278: ! 279: - incrementImageNumber ! 280: { ! 281: if (now > nextRotationTime) ! 282: { ! 283: if (++currentFrame >= numberOfFrames) currentFrame = 0; ! 284: currentImage = [imageList objectAt:currentFrame]; ! 285: nextRotationTime = now + 1000/framesPerSecond; ! 286: } ! 287: ! 288: return self; ! 289: } ! 290: ! 291: - (const char *)windowTitle ! 292: { ! 293: return "World in Space"; ! 294: } ! 295: ! 296: - didLockFocus ! 297: { ! 298: [mySpaceView didLockFocus]; ! 299: return self; ! 300: } ! 301: ! 302: - inspector:sender ! 303: { ! 304: char buf[MAXPATHLEN]; ! 305: ! 306: if (!sharedInspectorPanel) ! 307: { ! 308: [NXBundle getPath:buf forResource:"WorldSpace" ofType:"nib" inDirectory:[sender moduleDirectory:"WorldSpace"] withVersion:0]; ! 309: [NXApp loadNibFile:buf owner:self withNames:NO]; ! 310: } ! 311: return sharedInspectorPanel; ! 312: } ! 313: ! 314: @end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.