/**************************************************************************** * This is the boinclet, a small main program for testing BOINC graphics * * * Fullscreen (Screensaver mode) modeled after Nate Robins's starfield * demo. * * Eric Myers - 9 July 2004 * Department of Physics and Astronomy, Vassar College, Poughkeepsie, New York *****************************************************************************/ static volatile const char CVSfileVersion[]= "@(#) $Id: boinclet.C,v 3.09 2006/12/20 18:53:40 myers Exp $ "; /*********************************************************************** * Copyright (C) 2004 David Hammer, Eric Myers, Bruce Allen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ************************************************************************/ #include "boinclet.h" // Graphics state: double last_render_called=0.0; // to keep track of frame rate double boinc_max_fps = 30.; // frame rate double boinc_max_gfx_cpu_frac = 0.5; // this is ignored in boinclet //EAM// Additions for monitoring frame rate: double boinc_fps = 0.0; // measured value double boinc_gfx_cpu_frac = 0.0; // measured value double boinc_fps_sample_min = 1.0; // sample start interval double boinc_fps_sample_max = 60.0; // sample reset interval /* * GLUT -> BOINC API callbacks and state: */ void graphics_render(); void mouse_click(int button, int state, int x, int y); void mouse_move(int x, int y); void any_mouse_move(int x, int y); void any_keyboard_event(unsigned char key, int x, int y); void key_press_event(unsigned char key, int x, int y); void key_release_event(unsigned char key, int x, int y); void window_reshape(int width, int height); void boinclet_idle(); void throttled_frame_rate(); void all_done(int rc); /******************************************************************* * MAIN PROGRAM: the boinclet */ main(int argc, char** argv) { int i; bool is_fullscreen=false; FILE* f; double frac_done; i=1; while(i < argc) { if (!strcmp(argv[i], "-root")) { is_fullscreen=true; } i++; } frac_done= 0.3715; glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH); glutInitWindowSize(640,480); glutCreateWindow("BOINC Graphics API test stand"); if(is_fullscreen){ //f=freopen("/dev/null", "w", stderr); glutSetCursor(GLUT_CURSOR_NONE); glutFullScreen(); // enable the line following to make it exit on any keyboard event. //glutKeyboardFunc(any_keyboard_event); glutMotionFunc(any_mouse_move); glutMouseFunc(mouse_click); glutPassiveMotionFunc(any_mouse_move); } else { printf("BOINC Graphics API test stand -- press ESC to exit.\n"); glutMotionFunc(mouse_move); glutKeyboardFunc(key_press_event); glutKeyboardUpFunc(key_release_event); glutMouseFunc(mouse_click); } // Register GLUT API callbacks: glutDisplayFunc(graphics_render); glutReshapeFunc(window_reshape); glutIdleFunc( boinclet_idle ); // Main loop (never ends until exit): glutMainLoop(); return 47; } /* Windows entry point WinMain() */ #ifdef _WIN32 /******************************************************* * Windows: Unix applications begin with main() while Windows applications * begin with WinMain, so this just makes WinMain() process the command line * and then invoke main() */ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR Args, int WinMode) { LPSTR command_line; char* argv[100]; int argc; command_line = GetCommandLine(); argc = parse_command_line( command_line, argv ); return main(argc, argv); } #endif //**************************************************************** // TRANSLATIONS FROM GLUT TO BOINC GRAPHICS API: // BOINC internal state (used as argments to callbacks): int boinc_x_size, boinc_y_size; double boinc_time_of_day; bool mouse_state[3] = { false, false, false }; static bool is_inited=false; // Callback functions translated: void graphics_render(){ // BOINC only calls app_graphics_init() *after* window is up and resized if ( !is_inited ) { app_graphics_init(); is_inited=true; } boinc_time_of_day = dtime(); // dtime() from util.h last_render_called = boinc_time_of_day; // note last time app_graphics_render(boinc_x_size, boinc_y_size, boinc_time_of_day); glutSwapBuffers(); } /************************ * Idle function (could call worker function in future) */ void boinclet_idle() { // if callback is given, then call it back... // if ( _worker_function ) _worker_function(); // draw the picture, if it's time throttled_frame_rate(); } /*********************** * This implements frame rate throttling in the same way as BOINC. * It only calls glutPostRedisplay() if it's time to show next frame. */ void throttled_frame_rate() { double dt, period; dt = dtime() - last_render_called; period = 1.0/boinc_max_fps; if( dt > period ) glutPostRedisplay(); } /************************* * Mouse click or motion, keyboard events: */ void mouse_click(int button, int state, int x, int y) { bool is_down; if(state==GLUT_DOWN) { is_down = true; mouse_state[button] = true; } else { is_down = false; mouse_state[button] = false; } boinc_app_mouse_button(x, y, button, is_down); } void mouse_move(int x, int y) { boinc_app_mouse_move(x, y, mouse_state[0], mouse_state[1], mouse_state[2]); } /* GLUT calls passive motion callback once at startup, so ignore that */ void any_mouse_move(int x, int y) { static int ncall=0; if(ncall>1) all_done(0); ncall++; } /*************************************** * Keyboard */ void any_keyboard_event(unsigned char key, int x, int y){ all_done(0); } void key_press_event(unsigned char key, int x, int y){ int key_code; char key_char; key_code = (int) key; key_char = key; if ( key_code < 32 ) { key_char = '?';} fprintf(stderr,"keyboard_event: key '%c' (code %d) pressed at (%d,%d).\n", key_char, key_code, x, y); switch(key) { case 27: /* ESC key = exit */ all_done(0); case '?': /* ? or h = help */ case 'h': printf(" Press ESC to exit.\n"); break; default: boinc_app_key_press(key, key); break; } glutPostRedisplay(); /* force redisplay */ } void key_release_event(unsigned char key, int x, int y){ int key_code; char key_char; key_code = (int) key; key_char = key; if ( key_code < 32 ) { key_char = '?';} fprintf(stderr,"keyboard_event: key '%c' (code %d) released at (%d,%d).\n", key_char, key_code, x, y); boinc_app_key_release(key, key); glutPostRedisplay(); /* force redisplay */ } /***************************** * Window resize/remap event */ void window_reshape(int width, int height){ boinc_x_size = width; boinc_y_size = height; app_graphics_resize(width, height); } void all_done(int rc) { glFinish(); fprintf(stderr, "\nboinclet: all done.\n"); exit(rc); } void boinc_quit() { all_done(0); } /*********************************** * User, host, and team data: fake it! */ int boinc_get_init_data(APP_INIT_DATA &app_init_data) { APP_INIT_DATA user_data; safe_strcpy(user_data.user_name, "(Unknown)\0"); user_data.user_total_credit = 137.0; user_data.user_expavg_credit = 3.14159; user_data.host_total_credit = 47.0; user_data.host_expavg_credit = 2.7183; safe_strcpy(user_data.team_name, "Red Sox\0"); app_init_data = user_data; return 0; } /*********************************** * Other useful odds and ends */ #ifdef NOT_USING_BOINC_LIB // Use this instead of strncpy(). // Result will always be null-terminated, and it's faster. // see http://www.gratisoft.us/todd/papers/strlcpy.html // #if !defined(HAVE_STRLCPY) size_t strlcpy(char *dst, const char *src, size_t size) { size_t ret = strlen(src); if (size) { size_t len = (ret >= size) ? size-1 : ret; memcpy(dst, src, len); dst[len] = '\0'; } return ret; } #endif #endif #ifdef _WIN32 struct timezone { int tz_minuteswest; /* minutes W of Greenwich */ int tz_dsttime; /* type of dst correction */ }; int gettimeofday(timeval *tv, struct timezone *tz){ FILETIME ft; SYSTEMTIME st; GetSystemTimeAsFileTime(&ft); if(!FileTimeToSystemTime(&ft, &st)) return -1; tv->tv_sec=st.wSecond; tv->tv_usec=st.wMilliseconds; return 0; } #endif #ifdef NOT_USING_BOINC_LIB double dtime(){ struct timeval tv; gettimeofday(&tv, 0); return tv.tv_sec + (tv.tv_usec/1.e6); } #endif //EOF