| Mandelbrot.cpp | MandelbrotOGL.cpp | |||
|---|---|---|---|---|
|
456 lines 14440 bytes Last modified : Tue Jul 22 17:20:58 2008 |
318 lines 7375 bytes Last modified : Tue Jul 22 17:20:43 2008 |
|||
| 1 | // Mandelbrot sample | 1 | // To compile on Linux: | |
| 2 | // submitted by Mark Granger, NewTek | 2 | // cc -Wall MandelbrotOGL.cpp -o MandelbrotOGL -lGL -lGLU -lglut -lGLEW -lm -lX11 -L /usr/X11R6/lib | |
| 3 | // To compile on OSX: | |||
| 4 | // g++ -framework GLUT -framework OpenGL MandelbrotOGL.cpp -o MandelbrotOGL | |||
| 5 | // Mandelbrot Client | |||
| 6 | // Original CUDA program submitted by Mark Granger, NewTek | |||
| 7 | // Client was written by Abdulmajed Dakkak | |||
| 3 | 8 | |||
| 4 | #include <stdio.h> | 9 | #include <stdio.h> | |
| 5 | #include <stdlib.h> | 10 | #include <stdlib.h> | |
| 6 | #include <string.h> | 11 | #include <string.h> | |
| 7 | #include <GL/glew.h> | 12 | #ifdef __APPLE__ | |
| 8 | #include <GL/glut.h> | 13 | #include <GLUT/glut.h> | |
| 9 | #include <cuda_runtime_api.h> | 14 | #else | |
| 10 | #include <cuda_gl_interop.h> | 15 | #include <GL/glut.h> | |
| 11 | #include "cutil.h" | 16 | #endif | |
| 12 | #include "Mandelbrot_kernel.h" | 17 | #include <fcntl.h> | |
| 13 | #include "Mandelbrot_gold.h" | 18 | #include <unistd.h> | |
| 14 | 19 | #include <netinet/in.h> | ||
| 15 | // Set to 1 to run on the CPU instead of the GPU for timing comparison. | 20 | #include <sys/socket.h> | |
| 16 | #define RUN_CPU 0 | 21 | #include <arpa/inet.h> | |
| 17 | 22 | |||
| 18 | // Set to 1 to time frame generation | 23 | #define IMAGE_W 800 | |
| 19 | #define RUN_TIMING 0 | 24 | #define IMAGE_H 600 | |
| 20 | 25 | #define MAX_PASS 4 | ||
| 21 | // Random number macros | 26 | ||
| 22 | #define RANDOMSEED(seed) ((seed) = ((seed) * 1103515245 + 12345)) | 27 | #define INVALIDATE_STEP 3 | |
| 23 | #define RANDOMBITS(seed, bits) ((unsigned int)RANDOMSEED(seed) >> (32 - (bits))) | 28 | ||
| 24 | 29 | #define GETNEWFRAME 0x0 | ||
| 25 | //OpenGL PBO and texture "names" | 30 | #define ZOOMIN 0x2 | |
| 26 | GLuint gl_PBO, gl_Tex; | 31 | #define ZOOMOUT 0x3 | |
| 27 | 32 | #define MOVERIGHT 0x4 | ||
| 28 | //Source image on the host side | 33 | #define MOVEUP 0x5 | |
| 29 | uchar4 *h_Src; | 34 | #define MOVELEFT 0x6 | |
| 35 | #define MOVEDOWN 0x7 | |||
| 36 | #define TERMINATE 0x8 | |||
| 37 | #define MOUSE 0x9 | |||
| 38 | #define CLICK 0x1 | |||
| 39 | #define MOTION 0x2 | |||
| 40 | #define LEFTCLICK 0x0 | |||
| 41 | #define RIGHTCLICK 0x1 | |||
| 30 | 42 | |||
| 31 | //Original image width and height | 43 | //Original image width and height | |
| 32 | int imageW, imageH; | 44 | int imageW, imageH, max_pass; | |
| 33 | ||||
| 34 | // Starting iteration limit | |||
| 35 | int crunch = 512; | |||
| 36 | 45 | |||
| 37 | // Starting position and scale | 46 | // Starting position and scale | |
| 38 | double xOff = -0.5; | 47 | double xOff = -0.5; | |
| 39 | double yOff = 0.0; | 48 | double yOff = 0.0; | |
| 40 | double scale = 3.2; | 49 | double scale = 3.2; | |
| 41 | 50 | |||
| 42 | // Starting stationary position and scale motion | 51 | // Starting stationary position and scale motion | |
| 43 | double xdOff = 0.0; | 52 | double xdOff = 0.0; | |
| 44 | double ydOff = 0.0; | 53 | double ydOff = 0.0; | |
| 45 | double dscale = 1.0; | |||
| 46 | 54 | |||
| 47 | // Starting animation frame and anti-aliasing pass | 55 | // SOCKET ID | |
| 48 | int animationFrame = 0; | 56 | int sockfd; | |
| 49 | int animationStep = 0; | |||
| 50 | int pass = 0; | |||
| 51 | ||||
| 52 | // Starting color multipliers and random seed | |||
| 53 | int colorSeed = 0; | |||
| 54 | uchar4 colors; | |||
| 55 | ||||
| 56 | // Timer ID | |||
| 57 | unsigned int hTimer; | |||
| 58 | ||||
| 59 | // User interface variables | |||
| 60 | int lastx = 0; | |||
| 61 | int lasty = 0; | |||
| 62 | bool leftClicked = false; | |||
| 63 | bool rightClicked = false; | |||
| 64 | ||||
| 65 | #define BUFFER_DATA(i) ((char *)0 + i) | |||
| 66 | ||||
| 67 | // Get a sub-pixel sample location | |||
| 68 | void GetSample(int sampleIndex, float &x, float &y) | |||
| 69 | { | |||
| 70 | static const unsigned char pairData[128][2] = { | |||
| 71 | { 64, 64}, { 0, 0}, { 1, 63}, { 63, 1}, { 96, 32}, { 97, 95}, { 36, 96}, { 30, 31}, | |||
| 72 | { 95, 127}, { 4, 97}, { 33, 62}, { 62, 33}, { 31, 126}, { 67, 99}, { 99, 65}, { 2, 34}, | |||
| 73 | { 81, 49}, { 19, 80}, {113, 17}, {112, 112}, { 80, 16}, {115, 81}, { 46, 15}, { 82, 79}, | |||
| 74 | { 48, 78}, { 16, 14}, { 49, 113}, {114, 48}, { 45, 45}, { 18, 47}, { 20, 109}, { 79, 115}, | |||
| 75 | { 65, 82}, { 52, 94}, { 15, 124}, { 94, 111}, { 61, 18}, { 47, 30}, { 83, 100}, { 98, 50}, | |||
| 76 | {110, 2}, {117, 98}, { 50, 59}, { 77, 35}, { 3, 114}, { 5, 77}, { 17, 66}, { 32, 13}, | |||
| 77 | {127, 20}, { 34, 76}, { 35, 110}, {100, 12}, {116, 67}, { 66, 46}, { 14, 28}, { 23, 93}, | |||
| 78 | {102, 83}, { 86, 61}, { 44, 125}, { 76, 3}, {109, 36}, { 6, 51}, { 75, 89}, { 91, 21}, | |||
| 79 | { 60, 117}, { 29, 43}, {119, 29}, { 74, 70}, {126, 87}, { 93, 75}, { 71, 24}, {106, 102}, | |||
| 80 | {108, 58}, { 89, 9}, {103, 23}, { 72, 56}, {120, 8}, { 88, 40}, { 11, 88}, {104, 120}, | |||
| 81 | { 57, 105}, {118, 122}, { 53, 6}, {125, 44}, { 43, 68}, { 58, 73}, { 24, 22}, { 22, 5}, | |||
| 82 | { 40, 86}, {122, 108}, { 87, 90}, { 56, 42}, { 70, 121}, { 8, 7}, { 37, 52}, { 25, 55}, | |||
| 83 | { 69, 11}, { 10, 106}, { 12, 38}, { 26, 69}, { 27, 116}, { 38, 25}, { 59, 54}, {107, 72}, | |||
| 84 | {121, 57}, { 39, 37}, { 73, 107}, { 85, 123}, { 28, 103}, {123, 74}, { 55, 85}, {101, 41}, | |||
| 85 | { 42, 104}, { 84, 27}, {111, 91}, { 9, 19}, { 21, 39}, { 90, 53}, { 41, 60}, { 54, 26}, | |||
| 86 | { 92, 119}, { 51, 71}, {124, 101}, { 68, 92}, { 78, 10}, { 13, 118}, { 7, 84}, {105, 4} | |||
| 87 | }; | |||
| 88 | ||||
| 89 | x = (1.0f / 128.0f) * (0.5f + (float)pairData[sampleIndex][0]); | |||
| 90 | y = (1.0f / 128.0f) * (0.5f + (float)pairData[sampleIndex][1]); | |||
| 91 | } // GetSample | |||
| 92 | 57 | |||
| 93 | // OpenGL display function | 58 | // Request packet | |
| 94 | void displayFunc(void) | 59 | char request[16]; | |
| 95 | { | 60 | ||
| 96 | if ((xdOff != 0.0) || (ydOff != 0.0)) { | 61 | // D_DST Def | |
| 97 | xOff += xdOff; | 62 | char d_dst[IMAGE_H * IMAGE_W * 4]; | |
| 98 | yOff += ydOff; | 63 | ||
| 99 | pass = 0; | 64 | short invalid_frame = true; | |
| 100 | } | 65 | ||
| 101 | if (dscale != 1.0) { | 66 | /**********Network Functions************/ | |
| 102 | scale *= dscale; | 67 | void connectToServer(int port, char* IP) { | |
| 103 | pass = 0; | 68 | fprintf(stderr,"Attempting to connect to server...\n"); | |
| 104 | } | 69 | struct sockaddr_in remote_addr; | |
| 105 | if (animationStep) { | 70 | ||
| 106 | animationFrame -= animationStep; | 71 | sockfd=socket(PF_INET,SOCK_STREAM,0); | |
| 107 | pass = 0; | 72 | ||
| 73 | remote_addr.sin_family=AF_INET; | |||
| 74 | remote_addr.sin_port=htons(port); | |||
| 75 | remote_addr.sin_addr.s_addr=inet_addr(IP); | |||
| 76 | memset(remote_addr.sin_zero, '\0',sizeof remote_addr.sin_zero); | |||
| 77 | ||||
| 78 | if(connect(sockfd,(struct sockaddr*)&remote_addr,sizeof remote_addr)==-1){ | |||
| 79 | perror("connect"); | |||
| 80 | exit(1); | |||
| 81 | } | |||
| 82 | ||||
| 83 | fprintf(stderr,"Connected to server.\n"); | |||
| 84 | } | |||
| 85 | ||||
| 86 | void sendEnvironmentVariables( ) { | |||
| 87 | int env[3] = {imageW, imageH, MAX_PASS}; | |||
| 88 | send(sockfd, env, 3 * sizeof(int), 0); | |||
| 89 | } | |||
| 90 | ||||
| 91 | void getNewFrame( ) { | |||
| 92 | // fprintf(stderr,"Requesting new frame...\n"); | |||
| 93 | ||||
| 94 | request[0]= GETNEWFRAME; | |||
| 95 | send(sockfd, request, 16 * sizeof(char), 0); | |||
| 96 | ||||
| 97 | int bytesRecieved=recv(sockfd, d_dst, | |||
| 98 | imageW * imageH * 4 * sizeof(char), MSG_WAITALL); | |||
| 99 | if(bytesRecieved==-1) { perror("recv()"); exit(1); } | |||
| 100 | ||||
| 101 | // fprintf(stderr,"Received frame. (%d bytes).\n",bytesRecieved); | |||
| 102 | } | |||
| 103 | ||||
| 104 | void sendRequestToZoomIn( ) { | |||
| 105 | request[0] = ZOOMIN; | |||
| 106 | send(sockfd, request, 16 * sizeof(char), 0); | |||
| 107 | } | |||
| 108 | ||||
| 109 | void sendRequestToZoomOut( ) { | |||
| 110 | request[0] = ZOOMOUT; | |||
| 111 | send(sockfd, request, 16 * sizeof(char), 0); | |||
| 112 | } | |||
| 113 | ||||
| 114 | void sendRequestToMoveLeft( ) { | |||
| 115 | request[0] = MOVELEFT; | |||
| 116 | send(sockfd, request, 16 * sizeof(char), 0); | |||
| 117 | } | |||
| 118 | ||||
| 119 | void sendRequestToMoveUp( ) { | |||
| 120 | request[0] = MOVEUP; | |||
| 121 | send(sockfd, request, 16 * sizeof(char), 0); | |||
| 122 | } | |||
| 123 | ||||
| 124 | void sendRequestToMoveRight( ) { | |||
| 125 | request[0] = MOVERIGHT; | |||
| 126 | send(sockfd, request, 16 * sizeof(char), 0); | |||
| 127 | } | |||
| 128 | ||||
| 129 | void sendRequestToMoveDown( ) { | |||
| 130 | request[0] = MOVEDOWN; | |||
| 131 | send(sockfd, request, 16 * sizeof(char), 0); | |||
| 132 | } | |||
| 133 | ||||
| 134 | void sendRequestToTerminate( ) { | |||
| 135 | request[0] = TERMINATE; | |||
| 136 | send(sockfd, request, 16 * sizeof(char), 0); | |||
| 137 | } | |||
| 138 | ||||
| 139 | void sendClickEvent(int button_clicked, int x, int y) { | |||
| 140 | short button; | |||
| 141 | if(button_clicked == 0) { | |||
| 142 | button = LEFTCLICK; | |||
| 108 | } | 143 | } | |
| 109 | #if RUN_TIMING | 144 | else { | |
| 110 | pass = 0; | 145 | button = RIGHTCLICK; | |
| 111 | #endif | |||
| 112 | #if RUN_CPU | |||
| 113 | if (pass < 128) { | |||
| 114 | int startPass = pass; | |||
| 115 | uchar4 *d_dst = NULL; | |||
| 116 | float xs, ys; | |||
| 117 | cutResetTimer(hTimer); | |||
| 118 | CUDA_SAFE_CALL(cudaGLMapBufferObject((void**)&d_dst, gl_PBO)); | |||
| 119 | ||||
| 120 | // Get the anti-alias sub-pixel sample location | |||
| 121 | GetSample(pass & 127, xs, ys); | |||
| 122 | ||||
| 123 | // Get the pixel scale and offset | |||
| 124 | double s = scale / (double)imageW; | |||
| 125 | double x = (xs - (double)imageW * 0.5f) * s + xOff; | |||
| 126 | double y = (ys - (double)imageH * 0.5f) * s + yOff; | |||
| 127 | ||||
| 128 | // Run the mandelbrot generator | |||
| 129 | if (pass && !startPass) // Use the adaptive sampling version when animating. | |||
| 130 | RunMandelbrotDSGold1(h_Src, imageW, imageH, crunch, x, y, s, colors, pass++, animationFrame); | |||
| 131 | else | |||
| 132 | RunMandelbrotDSGold0(h_Src, imageW, imageH, crunch, x, y, s, colors, pass++, animationFrame); | |||
| 133 | CUDA_SAFE_CALL(cudaMemcpy(d_dst, h_Src, imageW * imageH * sizeof(uchar4), cudaMemcpyHostToDevice)); | |||
| 134 | CUDA_SAFE_CALL(cudaGLUnmapBufferObject(gl_PBO)); | |||
| 135 | #if RUN_TIMING | |||
| 136 | printf("CPU = %5.8f\n", 0.001f * cutGetTimerValue(hTimer)); | |||
| 137 | #endif | |||
| 138 | } | 146 | } | |
| 139 | 147 | |||
| 140 | #else | 148 | request[0] = MOUSE; | |
| 141 | if (pass < 128) { | 149 | request[1] = CLICK; | |
| 142 | float timeEstimate; | 150 | request[2] = button; | |
| 143 | int startPass = pass; | 151 | int x_y[2] = {x, y}; | |
| 144 | uchar4 *d_dst = NULL; | 152 | memcpy(&request[3], x_y, 2*sizeof(int)); | |
| 145 | cutResetTimer(hTimer); | 153 | // printf("Sent Click event %d, %d, %d\n", button, x_y[0], x_y[1]); | |
| 146 | CUDA_SAFE_CALL(cudaGLMapBufferObject((void**)&d_dst, gl_PBO)); | 154 | send(sockfd, (void*)request, 16 * sizeof(char), 0); | |
| 147 | 155 | } | ||
| 148 | // Render anti-aliasing passes until we run out time (60fps approximately) | 156 | ||
| 149 | do { | 157 | void sendMotionEvent(int x, int y) { | |
| 150 | float xs, ys; | 158 | request[0] = MOUSE; | |
| 151 | 159 | request[1] = MOTION; | ||
| 152 | // Get the anti-alias sub-pixel sample location | 160 | ||
| 153 | GetSample(pass & 127, xs, ys); | 161 | int x_y[2] = {x, y}; | |
| 154 | 162 | memcpy(&request[2], x_y, 2*sizeof(int)); | ||
| 155 | // Get the pixel scale and offset | 163 | ||
| 156 | double s = scale / (float)imageW; | 164 | send(sockfd, request, 16 * sizeof(char), 0); | |
| 157 | double x = (xs - (double)imageW * 0.5f) * s + xOff; | 165 | } | |
| 158 | double y = (ys - (double)imageH * 0.5f) * s + yOff; | |||
| 159 | ||||
| 160 | // Run the mandelbrot generator | |||
| 161 | if (pass && !startPass) // Use the adaptive sampling version when animating. | |||
| 162 | RunMandelbrot1(d_dst, imageW, imageH, crunch, x, y, s, colors, pass++, animationFrame); | |||
| 163 | else | |||
| 164 | RunMandelbrot0(d_dst, imageW, imageH, crunch, x, y, s, colors, pass++, animationFrame); | |||
| 165 | cudaThreadSynchronize(); | |||
| 166 | ||||
| 167 | // Estimate the total time of the frame if one more pass is rendered | |||
| 168 | timeEstimate = 0.001f * cutGetTimerValue(hTimer) * ((float)(pass + 1 - startPass) / (float)(pass - startPass)); | |||
| 169 | } while ((pass < 128) && (timeEstimate < 1.0f / 60.0f) && !RUN_TIMING); | |||
| 170 | CUDA_SAFE_CALL(cudaGLUnmapBufferObject(gl_PBO)); | |||
| 171 | #if RUN_TIMING | |||
| 172 | printf("GPU = %5.8f\n", 0.001f * cutGetTimerValue(hTimer)); | |||
| 173 | #endif | |||
| 174 | } | |||
| 175 | #endif | |||
| 176 | 166 | |||
| 177 | glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, imageW, imageH, GL_RGBA, GL_UNSIGNED_BYTE, BUFFER_DATA(0)); | 167 | /*****END**Network Functions**END*******/ | |
| 178 | glBegin(GL_TRIANGLES); | |||
| 179 | glTexCoord2f(0.0f, 0.0f); | |||
| 180 | glVertex2f(-1.0f, -1.0f); | |||
| 181 | glTexCoord2f(2.0f, 0.0f); | |||
| 182 | glVertex2f(3.0f, -1.0f); | |||
| 183 | glTexCoord2f(0.0f, 2.0f); | |||
| 184 | glVertex2f(-1.0f, 3.0f); | |||
| 185 | glEnd(); | |||
| 186 | 168 | |||
| 169 | // OpenGL display function | |||
| 170 | void displayFunc(void) | |||
| 171 | { | |||
| 172 | int i, j; | |||
| 173 | char r,g,b,a; | |||
| 174 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |||
| 175 | ||||
| 176 | glColor3f(0.0, 0.0, 0.0); | |||
| 177 | glBegin(GL_POINTS); | |||
| 178 | for(j = 0; j < imageH; j++) { | |||
| 179 | for(i = 0; i < imageW; i++) { | |||
| 180 | r = d_dst[j*4*imageW + i * 4]; | |||
| 181 | g = d_dst[j*4*imageW + i * 4 + 1]; | |||
| 182 | b = d_dst[j*4*imageW + i * 4 + 2]; | |||
| 183 | a = d_dst[j*4*imageW + i * 4 + 3]; | |||
| 184 | glColor4b(r, g, b, a); | |||
| 185 | glVertex2f(i, j); | |||
| 186 | } | |||
| 187 | } | |||
| 188 | glEnd( ); | |||
| 187 | glutSwapBuffers(); | 189 | glutSwapBuffers(); | |
| 188 | } // displayFunc | 190 | } // displayFunc | |
| 189 | 191 | |||
| 190 | // OpenGL keyboard function | 192 | // OpenGL keyboard function | |
| 191 | void keyboardFunc(unsigned char k, int, int) | 193 | void keyboardFunc(unsigned char k, int, int) | |
| 192 | { | 194 | { | |
| 193 | int seed; | 195 | invalid_frame = true; | |
| 194 | switch (k){ | 196 | switch (k){ | |
| 195 | case '\033': | 197 | case '\033': | |
| 196 | case 'q': | 198 | case 'q': | |
| 197 | case 'Q': | 199 | case 'Q': | |
| 198 | printf("Shutting down...\n"); | 200 | printf("Sending server terminate request...\n"); | |
| 199 | CUT_SAFE_CALL(cutStopTimer(hTimer) ); | 201 | sendRequestToTerminate( ); | |
| 200 | CUT_SAFE_CALL(cutDeleteTimer(hTimer)); | |||
| 201 | CUDA_SAFE_CALL(cudaGLUnregisterBufferObject(gl_PBO)); | |||
| 202 | glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0); | |||
| 203 | glDeleteBuffers(1, &gl_PBO); | |||
| 204 | glDeleteTextures(1, &gl_Tex); | |||
| 205 | free(h_Src); | |||
| 206 | printf("Shutdown done.\n"); | 202 | printf("Shutdown done.\n"); | |
| 207 | exit(0); | 203 | exit(0); | |
| 208 | break; | 204 | break; | |
| 209 | 205 | |||
| 210 | case '?': | 206 | case '?': | |
| 211 | printf("xOff = %5.8f\n", xOff); | 207 | printf("xOff = %5.8f\n", xOff); | |
| 212 | printf("yOff = %5.8f\n", yOff); | 208 | printf("yOff = %5.8f\n", yOff); | |
| 213 | printf("scale = %5.8f\n", scale); | 209 | printf("scale = %5.8f\n", scale); | |
| 214 | printf("detail = %d\n", crunch); | |||
| 215 | printf("color = %d\n", colorSeed); | |||
| 216 | printf("\n"); | 210 | printf("\n"); | |
| 217 | break; | 211 | break; | |
| 218 | 212 | |||
| 219 | case 'r': case 'R': | |||
| 220 | // Reset all values to their defaults | |||
| 221 | xOff = -0.5; | |||
| 222 | yOff = 0.0; | |||
| 223 | scale = 3.2; | |||
| 224 | xdOff = 0.0; | |||
| 225 | ydOff = 0.0; | |||
| 226 | dscale = 1.0; | |||
| 227 | colorSeed = 0; | |||
| 228 | colors.x = 3; | |||
| 229 | colors.y = 5; | |||
| 230 | colors.z = 7; | |||
| 231 | crunch = 512; | |||
| 232 | animationFrame = 0; | |||
| 233 | animationStep = 0; | |||
| 234 | pass = 0; | |||
| 235 | break; | |||
| 236 | ||||
| 237 | case 'c': | |||
| 238 | seed = ++colorSeed; | |||
| 239 | if (seed) { | |||
| 240 | colors.x = RANDOMBITS(seed, 4); | |||
| 241 | colors.y = RANDOMBITS(seed, 4); | |||
| 242 | colors.z = RANDOMBITS(seed, 4); | |||
| 243 | } else { | |||
| 244 | colors.x = 3; | |||
| 245 | colors.y = 5; | |||
| 246 | colors.z = 7; | |||
| 247 | } | |||
| 248 | pass = 0; | |||
| 249 | break; | |||
| 250 | ||||
| 251 | case 'C': | |||
| 252 | seed = --colorSeed; | |||
| 253 | if (seed) { | |||
| 254 | colors.x = RANDOMBITS(seed, 4); | |||
| 255 | colors.y = RANDOMBITS(seed, 4); | |||
| 256 | colors.z = RANDOMBITS(seed, 4); | |||
| 257 | } else { | |||
| 258 | colors.x = 3; | |||
| 259 | colors.y = 5; | |||
| 260 | colors.z = 7; | |||
| 261 | } | |||
| 262 | pass = 0; | |||
| 263 | break; | |||
| 264 | ||||
| 265 | case 'a': | |||
| 266 | if (animationStep < 0) | |||
| 267 | animationStep = 0; | |||
| 268 | else { | |||
| 269 | animationStep++; | |||
| 270 | if (animationStep > 8) | |||
| 271 | animationStep = 8; | |||
| 272 | } | |||
| 273 | break; | |||
| 274 | ||||
| 275 | case 'A': | |||
| 276 | if (animationStep > 0) | |||
| 277 | animationStep = 0; | |||
| 278 | else { | |||
| 279 | animationStep--; | |||
| 280 | if (animationStep < -8) | |||
| 281 | animationStep = -8; | |||
| 282 | } | |||
| 283 | break; | |||
| 284 | ||||
| 285 | case 'd': | |||
| 286 | if (crunch < 0x40000000) { | |||
| 287 | crunch *= 2; | |||
| 288 | pass = 0; | |||
| 289 | } | |||
| 290 | break; | |||
| 291 | ||||
| 292 | case 'D': | |||
| 293 | if (crunch > 2) { | |||
| 294 | crunch /= 2; | |||
| 295 | pass = 0; | |||
| 296 | } | |||
| 297 | break; | |||
| 298 | ||||
| 299 | case '4': // Left arrow key | 213 | case '4': // Left arrow key | |
| 300 | xOff -= 0.05f * scale; | 214 | xOff -= 0.05f * scale; | |
| 301 | pass = 0; | 215 | sendRequestToMoveLeft( ); | |
| 302 | break; | 216 | break; | |
| 303 | 217 | |||
| 304 | case '8': // Up arrow key | 218 | case '8': // Up arrow key | |
| 305 | yOff += 0.05f * scale; | 219 | yOff += 0.05f * scale; | |
| 306 | pass = 0; | 220 | sendRequestToMoveUp( ); | |
| 307 | break; | 221 | break; | |
| 308 | 222 | |||
| 309 | case '6': // Right arrow key | 223 | case '6': // Right arrow key | |
| 310 | xOff += 0.05f * scale; | 224 | xOff += 0.05f * scale; | |
| 311 | pass = 0; | 225 | sendRequestToMoveRight( ); | |
| 312 | break; | 226 | break; | |
| 313 | 227 | |||
| 314 | case '2': // Down arrow key | 228 | case '2': // Down arrow key | |
| 315 | yOff -= 0.05f * scale; | 229 | yOff -= 0.05f * scale; | |
| 316 | pass = 0; | 230 | sendRequestToMoveDown( ); | |
| 317 | break; | 231 | break; | |
| 318 | 232 | |||
| 319 | case '+': | 233 | case '+': | |
| 320 | scale /= 1.1f; | 234 | scale /= 1.1f; | |
| 321 | pass = 0; | 235 | sendRequestToZoomIn( ); | |
| 322 | break; | 236 | break; | |
| 323 | 237 | |||
| 324 | case '-': | 238 | case '-': | |
| 325 | scale *= 1.1f; | 239 | scale *= 1.1f; | |
| 326 | pass = 0; | 240 | sendRequestToZoomOut( ); | |
| 327 | break; | 241 | break; | |
| 328 | 242 | |||
| 329 | default: | 243 | default: | |
| 330 | break; | 244 | break; | |
| 331 | } | 245 | } | |
| 332 | } // keyboardFunc | 246 | } // keyboardFunc | |
| 333 | 247 | |||
| 334 | // OpenGL mouse click function | 248 | // OpenGL mouse click function | |
| 335 | void clickFunc(int button, int, int x, int y) | 249 | void clickFunc(int button, int, int x, int y) | |
| 336 | { | 250 | { | |
| 337 | if (button == 0) | 251 | sendClickEvent(button, x, y); | |
| 338 | leftClicked = !leftClicked; | 252 | invalid_frame = true; | |
| 339 | if (button == 2) | |||
| 340 | rightClicked = !rightClicked; | |||
| 341 | lastx = x; | |||
| 342 | lasty = y; | |||
| 343 | xdOff = 0.0; | |||
| 344 | ydOff = 0.0; | |||
| 345 | dscale = 1.0; | |||
| 346 | } // clickFunc | 253 | } // clickFunc | |
| 347 | 254 | |||
| 348 | // OpenGL mouse motion function | 255 | // OpenGL mouse motion function | |
| 349 | void motionFunc(int x, int y) | 256 | void motionFunc(int x, int y) | |
| 350 | { | 257 | { | |
| 351 | double fx = (double)((x - lastx) / 10) / (double)(imageW); | 258 | sendMotionEvent(x, y); | |
| 352 | double fy = (double)((lasty - y) / 10) / (double)(imageW); | 259 | invalid_frame = true; | |
| 353 | ||||
| 354 | if (leftClicked) { | |||
| 355 | xdOff = fx * scale; | |||
| 356 | ydOff = fy * scale; | |||
| 357 | } else { | |||
| 358 | xdOff = 0.0f; | |||
| 359 | ydOff = 0.0f; | |||
| 360 | } | |||
| 361 | ||||
| 362 | if (rightClicked) | |||
| 363 | if (fy > 0.0f) { | |||
| 364 | dscale = 1.0 - fy; | |||
| 365 | dscale = dscale < 1.05 ? dscale : 1.05; | |||
| 366 | } else { | |||
| 367 | dscale = 1.0 / (1.0 + fy); | |||
| 368 | dscale = dscale > (1.0 / 1.05) ? dscale : (1.0 / 1.05); | |||
| 369 | } | |||
| 370 | else | |||
| 371 | dscale = 1.0; | |||
| 372 | } // motionFunc | 260 | } // motionFunc | |
| 373 | 261 | |||
| 374 | void idleFunc() | 262 | void idleFunc() | |
| 375 | { | 263 | { | |
| 376 | glutPostRedisplay(); | 264 | if(invalid_frame) { | |
| 265 | getNewFrame( ); | |||
| 266 | glutPostRedisplay(); | |||
| 267 | invalid_frame++; | |||
| 268 | if(invalid_frame == INVALIDATE_STEP) { | |||
| 269 | invalid_frame = 0; | |||
| 270 | } | |||
| 271 | } | |||
| 272 | } | |||
| 273 | ||||
| 274 | ||||
| 275 | void init_gl( ) | |||
| 276 | { | |||
| 277 | glClearColor(0.0, 0.0, 0.0, 0.0); | |||
| 278 | ||||
| 279 | glMatrixMode(GL_PROJECTION); | |||
| 280 | glLoadIdentity(); | |||
| 281 | gluOrtho2D(0.0, imageW, 0.0, imageH); | |||
| 282 | ||||
| 283 | glMatrixMode(GL_MODELVIEW); | |||
| 284 | glPointSize(2); | |||
| 377 | } | 285 | } | |
| 378 | 286 | |||
| 379 | //////////////////////////////////////////////////////////////////////////////// | 287 | //////////////////////////////////////////////////////////////////////////////// | |
| 380 | // Main program | 288 | // Main program | |
| 381 | //////////////////////////////////////////////////////////////////////////////// | 289 | //////////////////////////////////////////////////////////////////////////////// | |
| 382 | int main(int argc, char **argv) | 290 | int main(int argc, char **argv) | |
| 383 | { | 291 | { | |
| 384 | CUT_DEVICE_INIT(); | 292 | if(argc!=3) { | |
| 385 | imageW = 800; | 293 | fprintf(stderr,"Usage: %s <IP address> <port>\n",argv[0]); | |
| 386 | imageH = 600; | 294 | exit(1); | |
| 387 | h_Src = (uchar4*)malloc(imageW * imageH * 4); | 295 | } | |
| 388 | colors.w = 0; | 296 | ||
| 389 | colors.x = 3; | 297 | ||
| 390 | colors.y = 5; | 298 | imageW = IMAGE_W; | |
| 391 | colors.z = 7; | 299 | imageH = IMAGE_H; | |
| 392 | printf("Data init done.\n"); | 300 | max_pass = MAX_PASS; | |
| 393 | 301 | |||
| 394 | printf("Initializing GLUT...\n"); | 302 | connectToServer(atoi(argv[2]),argv[1]); | |
| 395 | glutInit(&argc, argv); | 303 | sendEnvironmentVariables( ); | |
| 396 | glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); | 304 | ||
| 397 | glutInitWindowSize(imageW, imageH); | 305 | glutInit(&argc, argv); | |
| 398 | glutInitWindowPosition(512 - imageW / 2, 384 - imageH / 2); | 306 | glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); | |
| 399 | glutCreateWindow(argv[0]); | 307 | glutInitWindowSize(imageW, imageH); | |
| 400 | printf("Loading extensions: %s\n", glewGetErrorString(glewInit())); | 308 | glutCreateWindow(argv[0]); | |
| 401 | if(!glewIsSupported( | |||
| 402 | "GL_VERSION_2_0 " | |||
| 403 | "GL_ARB_pixel_buffer_object " | |||
| 404 | "GL_EXT_framebuffer_object " | |||
| 405 | )){ | |||
| 406 | fprintf(stderr, "ERROR: Support for necessary OpenGL extensions missing."); | |||
| 407 | fflush(stderr); | |||
| 408 | return CUTFalse; | |||
| 409 | } | |||
| 410 | printf("OpenGL window created.\n"); | |||
| 411 | 309 | |||
| 412 | printf("Creating GL texture...\n"); | 310 | init_gl( ); | |
| 413 | glEnable(GL_TEXTURE_2D); | |||
| 414 | glGenTextures(1, &gl_Tex); | |||
| 415 | glBindTexture(GL_TEXTURE_2D, gl_Tex); | |||
| 416 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); | |||
| 417 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); | |||
| 418 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |||
| 419 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |||
| 420 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, imageW, imageH, 0, GL_RGBA, GL_UNSIGNED_BYTE, h_Src); | |||
| 421 | printf("Texture created.\n"); | |||
| 422 | ||||
| 423 | printf("Creating PBO...\n"); | |||
| 424 | glGenBuffers(1, &gl_PBO); | |||
| 425 | glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, gl_PBO); | |||
| 426 | glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, imageW * imageH * 4, h_Src, GL_STREAM_COPY); | |||
| 427 | //While a PBO is registered to CUDA, it can't be used | |||
| 428 | //as the destination for OpenGL drawing calls. | |||
| 429 | //But in our particular case OpenGL is only used | |||
| 430 | //to display the content of the PBO, specified by CUDA kernels, | |||
| 431 | //so we need to register/unregister it only once. | |||
| 432 | CUDA_SAFE_CALL( cudaGLRegisterBufferObject(gl_PBO) ); | |||
| 433 | printf("PBO created.\n"); | |||
| 434 | ||||
| 435 | printf("Starting GLUT main loop...\n"); | |||
| 436 | printf("\n"); | |||
| 437 | printf("Press [?] to print location and scale\n"); | |||
| 438 | printf("Press [q] to exit\n"); | |||
| 439 | printf("Press [r] to reset\n"); | |||
| 440 | printf("Press [a] or [A] to animate the colors\n"); | |||
| 441 | printf("Press [c] or [C] to change the colors\n"); | |||
| 442 | printf("Press [d] or [D] to increase/decrease the detail\n"); | |||
| 443 | printf("Left mouse button + drag = Scroll\n"); | |||
| 444 | printf("Right mouse button + drag = Zoom\n"); | |||
| 445 | printf("\n"); | |||
| 446 | glutDisplayFunc(displayFunc); | 311 | glutDisplayFunc(displayFunc); | |
| 447 | glutIdleFunc(idleFunc); | 312 | glutIdleFunc(idleFunc); | |
| 448 | glutKeyboardFunc(keyboardFunc); | 313 | glutKeyboardFunc(keyboardFunc); | |
| 449 | glutMouseFunc(clickFunc); | 314 | glutMouseFunc(clickFunc); | |
| 450 | glutMotionFunc(motionFunc); | 315 | glutMotionFunc(motionFunc); | |
| 451 | CUT_SAFE_CALL(cutCreateTimer(&hTimer)); | |||
| 452 | CUT_SAFE_CALL(cutStartTimer(hTimer)); | |||
| 453 | glutMainLoop(); | 316 | glutMainLoop(); | |
| 454 | 317 | |||
| 455 | CUT_EXIT(argc, argv); | |||
| 456 | } // main | 318 | } // main |