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 |