#include #include #include #include #include #include #include OSErr CPSEnableForegroundOperation(ProcessSerialNumber *psn); OSErr CPSSetFrontProcess(ProcessSerialNumber *psn); #define BUFWIDTH 1024 #define BUFHEIGHT 1024 #define TARGET GL_TEXTURE_RECTANGLE_EXT //#define TARGET GL_TEXTURE_2D //#define NO_THREADS #define SCALE #if defined(NO_THREADS) || !defined(SCALE) #error probably broken #endif static void funcFailed(char *func,int r); static void checkStatus(OSStatus r, char *func) { if(r != noErr) funcFailed(func,r); } static void foreground(); static void createwindow(); static void createbuffer(); static void setupGL(); static void renderX(); static void reshapeX(); static void blitX(int x, int y, int x2, int y2); #define glDebugStr() glDebugStr_(__LINE__) static GLenum glDebugStr_ (int line); static pascal OSStatus eventHandler(EventHandlerCallRef handler, EventRef e, void *userData); static EventHandlerUPP eventHandlerUPP = NULL; static AGLPixelFormat fmt; static AGLContext wctx; static WindowRef window; int ww,wh; static AGLContext bctx; static WindowRef buffer; static GLint surfacetexname = -1; int abortRender = 0; int blitReq = 0; int reshapeReq = 0; int renderReq = 0; int pendingResize = 0; #ifdef NO_THREADS #define GLLOCK() #define GLUNLOCK() #endif #ifndef NO_THREADS #include static pthread_mutex_t lock; #define LOCK() do { if(pthread_mutex_lock(&lock)!=0) exit(2); } while(0) #define UNLOCK() do { if(pthread_mutex_unlock(&lock)!=0) exit(2); } while(0) #define WAIT() do { if(pthread_cond_wait(&cond,&lock)!=0) exit(2); } while(0) #define SIGNAL() do { if(pthread_cond_signal(&cond)!=0) exit(2); } while(0) static pthread_cond_t cond; void *secondThread(void *junk) { int doRender; int doBlit; int doReshape; Rect r; fprintf(stderr,"Second thread started\n"); for(;;) { LOCK(); while(!blitReq && !renderReq) WAIT(); doRender = renderReq; doBlit = blitReq; doReshape = reshapeReq; abortRender = 0; UNLOCK(); #ifdef SCALE if(doRender) renderX(); #else if(doRender) usleep(1000000); fprintf(stderr,"Done\n"); #endif if(doBlit) { LOCK(); while(pendingResize) WAIT(); if(doReshape) reshapeX(); if(doBlit) blitX(0,0,ww,wh); UNLOCK(); } LOCK(); if(doBlit) blitReq-=doBlit; if(doRender) renderReq-=doRender; if(doReshape) reshapeReq-=doReshape; if(renderReq < 0 || blitReq < 0 || reshapeReq < 0) exit(3); UNLOCK(); } return NULL; } #endif int main (int argc, const char * argv[]) { pthread_t t; OSStatus r; eventHandlerUPP = NewEventHandlerUPP(eventHandler); #ifndef NO_THREADS pthread_mutex_init(&lock,NULL); pthread_cond_init(&cond,NULL); pthread_create(&t,NULL,secondThread,NULL); #endif foreground(); createwindow(); createbuffer(); setupGL(); reshapeX(); renderX(); ShowWindow(window); //ShowWindow(buffer); SelectWindow(window); RunApplicationEventLoop(); return 0; } static const EventTypeSpec specs[] = { { kEventClassWindow, kEventWindowUpdate }, { kEventClassWindow, kEventWindowBoundsChanged }, { kEventClassWindow, kEventWindowBoundsChanging }, { kEventClassWindow, kEventWindowClosed }, { kEventClassMouse, kEventMouseUp }, { kEventClassMouse, kEventMouseDown } }; static void blitX(int x, int y, int x2, int y2) { int w = x2-x; int h = y2-y; Rect rectPort; aglSetCurrentContext (wctx); glDebugStr(); glEnable(TARGET); glBindTexture(TARGET, surfacetexname); glDebugStr(); glBegin(GL_QUADS); #if TARGET == GL_TEXTURE_2D #error broken float tx2 = w/BUFWIDTH; float ty2 = h/BUFHEIGHT; glTexCoord2f( 0.0f, 0.0f ); glVertex3f(x,y,0.0f ); glTexCoord2f( tx2, 0.0f ); glVertex3f( x+w, y,0.0f ); glTexCoord2f( tx2, ty2); glVertex3f( x+w, y+h,0.0f ); glTexCoord2f( 0.0f,ty2 ); glVertex3f( x,y+h,0.0f ); #else glTexCoord2i(x,y); glVertex3i(x,y,0); glTexCoord2i(x2,y); glVertex3i(x2,y,0); glTexCoord2i(x2,y2); glVertex3i(x2,y2,0); glTexCoord2i(x,y2); glVertex3i(x,y2,0); #endif glEnd(); glDebugStr(); glDisable(TARGET); glFlush(); } static pascal OSStatus eventHandler(EventHandlerCallRef handler, EventRef e, void *userData) { UInt32 eKind = GetEventKind(e); UInt32 eClass = GetEventClass(e); if(eClass == kEventClassWindow) { if(eKind == kEventWindowUpdate) { fprintf(stderr,"should not be here: %s:%d\n",__FILE__,__LINE__); exit(1); return noErr; } else if(eKind == kEventWindowBoundsChanged) { Rect rect; OSStatus r; r = GetEventParameter(e,kEventParamCurrentBounds,typeQDRectangle,NULL,sizeof(rect),NULL,&rect); checkStatus(r,"GetEventParameter"); #ifndef NO_THREADS LOCK(); #endif ww = rect.right - rect.left; wh = rect.bottom - rect.top; #ifdef NO_THREADS renderX(); reshapeX(); InvalWindowRect(window,&rect); #else renderReq++; blitReq++; reshapeReq++; if(pendingResize) { pendingResize = 0; UNLOCK(); SIGNAL(); } else { UNLOCK(); } #endif return noErr; } else if(eKind == kEventWindowBoundsChanging) { #ifndef NO_THREADS LOCK(); pendingResize = 1; UNLOCK(); abortRender = 1; #endif return noErr; } else if(eKind == kEventWindowClosed) { ExitToShell(); return noErr; } } else if(eClass == kEventClassMouse) { OSStatus r; r = CallNextEventHandler(handler, e); if(r != eventNotHandledErr) return r; if(eKind == kEventMouseDown) { return noErr; } } return eventNotHandledErr; } void setupGL() { GLboolean b; GLint attr[] = { AGL_NO_RECOVERY, AGL_RGBA, AGL_DEPTH_SIZE, 32, AGL_RED_SIZE, 8, AGL_GREEN_SIZE, 8, AGL_RED_SIZE, 8, AGL_ALPHA_SIZE, 8, AGL_NONE }; fmt = aglChoosePixelFormat(NULL,0,attr); if(fmt == NULL) funcFailed("aglChosePixelFormat",0); wctx = aglCreateContext(fmt,NULL /* for now.. need to create dummy context for shared texures */); if(wctx == NULL) funcFailed("aglCreateContext",0); bctx = aglCreateContext(fmt,NULL /* for now.. need to create dummy context for shared texures */); if(bctx == NULL) funcFailed("aglCreateContext",0); b = aglSetDrawable(wctx,GetWindowPort(window)); if(!b) funcFailed("aglSetDrawable",0); b = aglSetDrawable(bctx,GetWindowPort(buffer)); if(!b) funcFailed("aglSetDrawable",0); aglDestroyPixelFormat(fmt); aglSetCurrentContext (wctx); glClearColor (1.0f, 1.0f, 1.0f, 1.0f); glClearDepth( 0.0f ); aglSetCurrentContext (bctx); aglUpdateContext(bctx); glClearColor (1.0f, 1.0f, 1.0f, 1.0f); glClearDepth( 0.0f ); glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST ); glShadeModel( GL_SMOOTH ); glEnable (GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glViewport( 0, 0, BUFWIDTH, BUFHEIGHT ); glMatrixMode( GL_PROJECTION ); glLoadIdentity(); glOrtho(0,BUFWIDTH,BUFHEIGHT,0,-1,1); glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); glTranslatef (0.375, 0.375, 0.); aglSetCurrentContext (wctx); glEnable(TARGET); glDebugStr(); glGenTextures(1,&surfacetexname); glDebugStr(); glBindTexture(TARGET,surfacetexname); glDebugStr(); aglSurfaceTexture (wctx, TARGET, GL_RGBA, bctx); glDebugStr(); glDisable(TARGET); } void reshapeX() { int w,h; if(!ww || !wh) return; w = ww; h = wh; aglSetCurrentContext (wctx); aglUpdateContext(wctx); glViewport(0,0,w,h); glMatrixMode( GL_PROJECTION ); glLoadIdentity(); glOrtho(0,w,h,0,-1,1); glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); glTranslatef (0.375, 0.375, 0.); } static void createbuffer() { Rect rect; OSStatus r; rect.left = 50; rect.top = 50; rect.right=rect.left+BUFWIDTH; rect.bottom = rect.top+BUFHEIGHT; r = CreateNewWindow(kPlainWindowClass,0,&rect,&buffer); checkStatus(r,"CreateNewWindow"); } static OSStatus paintProc ( GDHandle device, GrafPtr qdContext, WindowRef window, RgnHandle inClientPaintRgn, RgnHandle outSystemPaintRgn, void * refCon ) { #ifdef NO_THREADS blitX(0,0,ww,wh); #else LOCK(); blitReq++; UNLOCK(); SIGNAL(); #endif return noErr; } static void createwindow() { Rect rect; OSStatus r; WindowClass wc = kDocumentWindowClass; HISize min,max; WindowAttributes attr = kWindowStandardHandlerAttribute|kWindowInWindowMenuAttribute|\ kWindowStandardDocumentAttributes|kWindowLiveResizeAttribute; rect.top = 400; rect.left = 400; rect.bottom = 900; rect.right=900; ww = 500; wh = 500; r = CreateNewWindow(wc,attr,&rect,&window); checkStatus(r,"CreateNewWindow"); r = InstallWindowEventHandler(window,eventHandlerUPP,sizeof(specs)/sizeof(EventTypeSpec),specs,NULL,NULL); checkStatus(r,"InstallWindowEventHandler"); r = InstallWindowContentPaintProc(window,paintProc/*FIXME: UPP*/,kWindowPaintProcOptionsNone,NULL); checkStatus(r,"InstallWindowContentPaintProc"); min.width = 80; min.height = 20; max.width = BUFWIDTH; max.height = BUFHEIGHT; SetWindowResizeLimits(window,&min,&max); } static void setcolor(int argb) { float alpha = ((argb >> 24) & 0xff) / 255.0; float red = ((argb >> 16) & 0xff) / 255.0; float green = ((argb >> 8) & 0xff) / 255.0; float blue = ((argb >> 0) & 0xff) / 255.0; glColor4f(red,green,blue,alpha); } static void fillRect(int x1, int y1, int x2, int y2, int color) { setcolor(color); glBegin(GL_QUADS); glVertex3f(x1,y2,0.0f ); // bottom left glVertex3f(x2,y2,0.0f ); // bottom right glVertex3f(x2,y1,0.0f ); // top right glVertex3f(x1,y1,0.0f ); // top left glEnd(); } #define SIZE 5 void renderX() { int i,j; int colors[] = { 0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0x00ffff, 0xff00ff, 0x000000, 0xffffff }; int sw,sh,w,h; static int firstTime = 1; sw = ww; sh = wh; w = sw/SIZE; h = sh/SIZE; aglSetCurrentContext (bctx); if(firstTime) { fillRect(0,0,BUFWIDTH,BUFHEIGHT,0xff808080); firstTime = 0; } for(i=0;i