Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 204 | chris | 1 | /* |
| 2 | * twoView.c |
||
| 3 | * |
||
| 4 | * Some code to demonstrate grabbing from two video sources. |
||
| 5 | * Press '?' while running for help. |
||
| 6 | * |
||
| 7 | * Copyright (c) 2004-2006 Philip Lamb (PRL) phil@eden.net.nz. All rights reserved. |
||
| 8 | * |
||
| 9 | * Rev Date Who Changes |
||
| 10 | * 1.0.0 2004-10-27 PRL Initial version. |
||
| 11 | * |
||
| 12 | */ |
||
| 13 | /* |
||
| 14 | * |
||
| 15 | * This file is part of ARToolKit. |
||
| 16 | * |
||
| 17 | * ARToolKit is free software; you can redistribute it and/or modify |
||
| 18 | * it under the terms of the GNU General Public License as published by |
||
| 19 | * the Free Software Foundation; either version 2 of the License, or |
||
| 20 | * (at your option) any later version. |
||
| 21 | * |
||
| 22 | * ARToolKit is distributed in the hope that it will be useful, |
||
| 23 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
| 24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
| 25 | * GNU General Public License for more details. |
||
| 26 | * |
||
| 27 | * You should have received a copy of the GNU General Public License |
||
| 28 | * along with ARToolKit; if not, write to the Free Software |
||
| 29 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||
| 30 | * |
||
| 31 | */ |
||
| 32 | |||
| 33 | |||
| 34 | // ============================================================================ |
||
| 35 | // Includes |
||
| 36 | // ============================================================================ |
||
| 37 | |||
| 38 | #include <stdio.h> // fprintf(), stderr |
||
| 39 | #include <stdlib.h> // malloc(), free(), atexit() |
||
| 40 | #ifndef __APPLE__ |
||
| 41 | # include <GL/glut.h> |
||
| 42 | # ifdef GL_VERSION_1_2 |
||
| 43 | # include <GL/glext.h> |
||
| 44 | # endif |
||
| 45 | #else |
||
| 46 | # include <GLUT/glut.h> |
||
| 47 | # include <OpenGL/glext.h> |
||
| 48 | #endif |
||
| 49 | #include <AR/config.h> |
||
| 50 | #include <AR/video.h> |
||
| 51 | #include <AR/param.h> // arParamDisp() |
||
| 52 | #include <AR/ar.h> |
||
| 53 | #include <AR/gsub_lite.h> |
||
| 54 | |||
| 55 | // ============================================================================ |
||
| 56 | // Constants and types. |
||
| 57 | // ============================================================================ |
||
| 58 | |||
| 59 | #define VIEW_SCALEFACTOR 0.025 // 1.0 ARToolKit unit becomes 0.025 of my OpenGL units. |
||
| 60 | #define VIEW_DISTANCE_MIN 0.1 // Objects closer to the camera than this will not be displayed. |
||
| 61 | #define VIEW_DISTANCE_MAX 100.0 // Objects further away from the camera than this will not be displayed. |
||
| 62 | |||
| 63 | // For cases in which we have multiple OpenGL contexts, never more than this many. |
||
| 64 | #define CONTEXTSACTIVECOUNT 2 |
||
| 65 | #define CONTEXTSACTIVECOUNTMAX CONTEXTSACTIVECOUNT |
||
| 66 | |||
| 67 | // Structure to keep track of per-camera variables. |
||
| 68 | typedef struct { |
||
| 69 | int apiContextIndex; // API-specific index into an array of display contexts. |
||
| 70 | ARParam ARTCparam; // Camera parameter. |
||
| 71 | AR2VideoParamT *ARTVideo; // Video parameters |
||
| 72 | ARUint8 *ARTImage; // Most recent image. |
||
| 73 | int ARTThreshhold; // Threshold for marker detection. |
||
| 74 | long callCountMarkerDetect; // Frames received. |
||
| 75 | double patt_trans[3][4]; // Marker transformation. |
||
| 76 | int patt_found; // Whether marker transformation is valid. |
||
| 77 | ARGL_CONTEXT_SETTINGS_REF arglSettings; // Settings from ARGL. |
||
| 78 | } CONTEXT_INFO; |
||
| 79 | |||
| 80 | // ============================================================================ |
||
| 81 | // Global variables. |
||
| 82 | // ============================================================================ |
||
| 83 | |||
| 84 | static GLuint *gDrawListBox = NULL; |
||
| 85 | |||
| 86 | CONTEXT_INFO *gContextsActive; |
||
| 87 | int gContextsActiveCount = 0; |
||
| 88 | |||
| 89 | // ARToolKit globals. |
||
| 90 | static long gCallCountGetImage = 0; |
||
| 91 | static int gPatt_id; |
||
| 92 | static double gPatt_width = 80.0; |
||
| 93 | static double gPatt_centre[2] = {0.0, 0.0}; |
||
| 94 | |||
| 95 | // Other globals. |
||
| 96 | static int gDrawRotate = FALSE; |
||
| 97 | static float gDrawRotateAngle = 0; // For use in drawing. |
||
| 98 | |||
| 99 | // ============================================================================ |
||
| 100 | // Functions |
||
| 101 | // ============================================================================ |
||
| 102 | |||
| 103 | static int DrawCubeInit(int contextsActiveCountMax) |
||
| 104 | { |
||
| 105 | // Allocate room for display lists for all contexts. |
||
| 106 | if (gDrawListBox) return (FALSE); // Sanity check. |
||
| 107 | if ((gDrawListBox = (GLuint *)calloc(contextsActiveCountMax, sizeof(GLuint))) == NULL) { |
||
| 108 | return (FALSE); |
||
| 109 | } |
||
| 110 | return (TRUE); |
||
| 111 | |||
| 112 | } |
||
| 113 | |||
| 114 | static int DrawCubeSetup(int contextIndex) |
||
| 115 | { |
||
| 116 | // Colour cube data. |
||
| 117 | float fSize = 0.5f; |
||
| 118 | long f, i; |
||
| 119 | const GLfloat cube_vertices [8][3] = { |
||
| 120 | {1.0, 1.0, 1.0}, {1.0, -1.0, 1.0}, {-1.0, -1.0, 1.0}, {-1.0, 1.0, 1.0}, |
||
| 121 | {1.0, 1.0, -1.0}, {1.0, -1.0, -1.0}, {-1.0, -1.0, -1.0}, {-1.0, 1.0, -1.0} }; |
||
| 122 | const GLfloat cube_vertex_colors [8][3] = { |
||
| 123 | {1.0, 1.0, 1.0}, {1.0, 1.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 1.0, 1.0}, |
||
| 124 | {1.0, 0.0, 1.0}, {1.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 1.0} }; |
||
| 125 | GLint cube_num_faces = 6; |
||
| 126 | const short cube_faces [6][4] = { {3, 2, 1, 0}, {2, 3, 7, 6}, {0, 1, 5, 4}, {3, 0, 4, 7}, {1, 2, 6, 5}, {4, 5, 6, 7} }; |
||
| 127 | |||
| 128 | if (!gDrawListBox[contextIndex]) { |
||
| 129 | gDrawListBox[contextIndex] = glGenLists (1); |
||
| 130 | glNewList(gDrawListBox[contextIndex], GL_COMPILE); |
||
| 131 | glBegin (GL_QUADS); |
||
| 132 | for (f = 0; f < cube_num_faces; f++) |
||
| 133 | for (i = 0; i < 4; i++) { |
||
| 134 | glColor3f (cube_vertex_colors[cube_faces[f][i]][0], cube_vertex_colors[cube_faces[f][i]][1], cube_vertex_colors[cube_faces[f][i]][2]); |
||
| 135 | glVertex3f(cube_vertices[cube_faces[f][i]][0] * fSize, cube_vertices[cube_faces[f][i]][1] * fSize, cube_vertices[cube_faces[f][i]][2] * fSize); |
||
| 136 | } |
||
| 137 | glEnd (); |
||
| 138 | glColor3f (0.0, 0.0, 0.0); |
||
| 139 | for (f = 0; f < cube_num_faces; f++) { |
||
| 140 | glBegin (GL_LINE_LOOP); |
||
| 141 | for (i = 0; i < 4; i++) |
||
| 142 | glVertex3f(cube_vertices[cube_faces[f][i]][0] * fSize, cube_vertices[cube_faces[f][i]][1] * fSize, cube_vertices[cube_faces[f][i]][2] * fSize); |
||
| 143 | glEnd (); |
||
| 144 | } |
||
| 145 | glEndList (); |
||
| 146 | } |
||
| 147 | |||
| 148 | return (TRUE); |
||
| 149 | } |
||
| 150 | |||
| 151 | // Something to look at, draw a rotating colour cube. |
||
| 152 | static void DrawCube(int contextIndex) |
||
| 153 | { |
||
| 154 | // Draw the colour cube. |
||
| 155 | glPushMatrix(); // Save world coordinate system. |
||
| 156 | glTranslatef(0.0, 0.0, 0.5); // Place base of cube on marker surface. |
||
| 157 | glRotatef(gDrawRotateAngle, 0.0, 0.0, 1.0); // Rotate about z axis. |
||
| 158 | glDisable(GL_LIGHTING); // Just use colours. |
||
| 159 | glCallList(gDrawListBox[contextIndex]); // Draw the cube. |
||
| 160 | glPopMatrix(); // Restore world coordinate system. |
||
| 161 | } |
||
| 162 | |||
| 163 | static void DrawCubeUpdate(float timeDelta) |
||
| 164 | { |
||
| 165 | if (gDrawRotate) { |
||
| 166 | gDrawRotateAngle += timeDelta * 45.0f; // Rotate cube at 45 degrees per second. |
||
| 167 | if (gDrawRotateAngle > 360.0f) gDrawRotateAngle -= 360.0f; |
||
| 168 | } |
||
| 169 | } |
||
| 170 | |||
| 171 | static int DrawCubeCleanup(int contextIndex) |
||
| 172 | { |
||
| 173 | if (contextIndex >= gContextsActiveCount) return (FALSE); // Sanity check. |
||
| 174 | |||
| 175 | // Destroy display lists... |
||
| 176 | if (gDrawListBox[contextIndex]) { |
||
| 177 | glDeleteLists(gDrawListBox[contextIndex], 1); |
||
| 178 | gDrawListBox[contextIndex] = 0; |
||
| 179 | } |
||
| 180 | |||
| 181 | return (TRUE); |
||
| 182 | } |
||
| 183 | |||
| 184 | static int DrawCubeFinal(void) |
||
| 185 | { |
||
| 186 | if (gDrawListBox) { |
||
| 187 | free(gDrawListBox); |
||
| 188 | gDrawListBox = NULL; |
||
| 189 | } |
||
| 190 | return (TRUE); |
||
| 191 | } |
||
| 192 | |||
| 193 | // Sets up fields ARTVideo, ARTCparam of gContextsActive[0] through gContextsActive[cameraCount - 1]. |
||
| 194 | static int setupCameras(const int cameraCount, const char *cparam_names[], char *vconfs[]) |
||
| 195 | { |
||
| 196 | int i; |
||
| 197 | ARParam wparam; |
||
| 198 | int xsize, ysize; |
||
| 199 | |||
| 200 | for (i = 0; i < cameraCount; i++) { |
||
| 201 | |||
| 202 | // Open the video path. |
||
| 203 | if ((gContextsActive[i].ARTVideo = ar2VideoOpen(vconfs[i])) == NULL) { |
||
| 204 | fprintf(stderr, "setupCameras(): Unable to open connection to camera %d.\n", i + 1); |
||
| 205 | return (FALSE); |
||
| 206 | } |
||
| 207 | |||
| 208 | // Find the size of the window. |
||
| 209 | if (ar2VideoInqSize(gContextsActive[i].ARTVideo, &xsize, &ysize) < 0) return (FALSE); |
||
| 210 | fprintf(stderr, "setupCameras(): Camera %d image size (x,y) = (%d,%d)\n", i + 1, xsize, ysize); |
||
| 211 | |||
| 212 | // Load the camera parameters, resize for the window and init. |
||
| 213 | if (arParamLoad(cparam_names[i], 1, &wparam) < 0) { |
||
| 214 | fprintf(stderr, "setupCameras(): Error loading parameter file %s for camera %d.\n", cparam_names[i], i + 1); |
||
| 215 | return (FALSE); |
||
| 216 | } |
||
| 217 | arParamChangeSize(&wparam, xsize, ysize, &(gContextsActive[i].ARTCparam)); |
||
| 218 | arInitCparam(&(gContextsActive[i].ARTCparam)); |
||
| 219 | fprintf(stderr, "*** Camera %d parameter ***\n", i + 1); |
||
| 220 | arParamDisp(&(gContextsActive[i].ARTCparam)); |
||
| 221 | gContextsActive[i].ARTThreshhold = 100; |
||
| 222 | |||
| 223 | // Start the video capture for this camera. |
||
| 224 | if (ar2VideoCapStart(gContextsActive[i].ARTVideo) != 0) { |
||
| 225 | fprintf(stderr, "setupCameras(): Unable to begin camera data capture for camera %d.\n", i + 1); |
||
| 226 | return (FALSE); |
||
| 227 | } |
||
| 228 | |||
| 229 | } |
||
| 230 | return (TRUE); |
||
| 231 | } |
||
| 232 | |||
| 233 | static int setupMarker(const char *patt_name, int *patt_id) |
||
| 234 | { |
||
| 235 | |||
| 236 | if((*patt_id = arLoadPatt(patt_name)) < 0) { |
||
| 237 | fprintf(stderr, "setupMarker(): pattern load error !!\n"); |
||
| 238 | return (FALSE); |
||
| 239 | } |
||
| 240 | |||
| 241 | return (TRUE); |
||
| 242 | } |
||
| 243 | |||
| 244 | // Report state of ARToolKit global variables arFittingMode, |
||
| 245 | // arImageProcMode, arglDrawMode, arTemplateMatchingMode, arMatchingPCAMode. |
||
| 246 | static void debugReportMode(ARGL_CONTEXT_SETTINGS_REF arglSettings) |
||
| 247 | { |
||
| 248 | if (arFittingMode == AR_FITTING_TO_INPUT) { |
||
| 249 | fprintf(stderr, "FittingMode (Z): INPUT IMAGE\n"); |
||
| 250 | } else { |
||
| 251 | fprintf(stderr, "FittingMode (Z): COMPENSATED IMAGE\n"); |
||
| 252 | } |
||
| 253 | |||
| 254 | if (arImageProcMode == AR_IMAGE_PROC_IN_FULL) { |
||
| 255 | fprintf(stderr, "ProcMode (X) : FULL IMAGE\n"); |
||
| 256 | } else { |
||
| 257 | fprintf(stderr, "ProcMode (X) : HALF IMAGE\n"); |
||
| 258 | } |
||
| 259 | |||
| 260 | if (arglDrawModeGet(arglSettings) == AR_DRAW_BY_GL_DRAW_PIXELS) { |
||
| 261 | fprintf(stderr, "DrawMode (C) : GL_DRAW_PIXELS\n"); |
||
| 262 | } else if (arglTexmapModeGet(arglSettings) == AR_DRAW_TEXTURE_FULL_IMAGE) { |
||
| 263 | fprintf(stderr, "DrawMode (C) : TEXTURE MAPPING (FULL RESOLUTION)\n"); |
||
| 264 | } else { |
||
| 265 | fprintf(stderr, "DrawMode (C) : TEXTURE MAPPING (HALF RESOLUTION)\n"); |
||
| 266 | } |
||
| 267 | |||
| 268 | if (arTemplateMatchingMode == AR_TEMPLATE_MATCHING_COLOR) { |
||
| 269 | fprintf(stderr, "TemplateMatchingMode (M) : Color Template\n"); |
||
| 270 | } else { |
||
| 271 | fprintf(stderr, "TemplateMatchingMode (M) : BW Template\n"); |
||
| 272 | } |
||
| 273 | |||
| 274 | if (arMatchingPCAMode == AR_MATCHING_WITHOUT_PCA) { |
||
| 275 | fprintf(stderr, "MatchingPCAMode (P) : Without PCA\n"); |
||
| 276 | } else { |
||
| 277 | fprintf(stderr, "MatchingPCAMode (P) : With PCA\n"); |
||
| 278 | } |
||
| 279 | #ifdef APPLE_TEXTURE_FAST_TRANSFER |
||
| 280 | # ifdef GL_APPLE_client_storage |
||
| 281 | fprintf(stderr, "arglAppleClientStorage is %d.\n", arglAppleClientStorage); |
||
| 282 | # endif // GL_APPLE_client_storage |
||
| 283 | # ifdef GL_APPLE_texture_range |
||
| 284 | fprintf(stderr, "arglAppleTextureRange is %d.\n", arglAppleTextureRange); |
||
| 285 | fprintf(stderr, "arglAppleTextureRangeStorageHint is "); |
||
| 286 | switch (arglAppleTextureRangeStorageHint) { |
||
| 287 | case GL_STORAGE_SHARED_APPLE: |
||
| 288 | fprintf(stderr, "GL_STORAGE_SHARED_APPLE.\n"); |
||
| 289 | break; |
||
| 290 | case GL_STORAGE_CACHED_APPLE: |
||
| 291 | fprintf(stderr, "GL_STORAGE_CACHED_APPLE.\n"); |
||
| 292 | break; |
||
| 293 | default: |
||
| 294 | case GL_STORAGE_PRIVATE_APPLE: |
||
| 295 | fprintf(stderr, "GL_STORAGE_PRIVATE_APPLE.\n"); |
||
| 296 | break; |
||
| 297 | } |
||
| 298 | # endif // GL_APPLE_texture_range |
||
| 299 | #endif // APPLE_TEXTURE_FAST_TRANSFER |
||
| 300 | } |
||
| 301 | |||
| 302 | // Function to clean up and then exit. Will be |
||
| 303 | // installed by atexit() and called when program exit()s. |
||
| 304 | static void Quit(void) |
||
| 305 | { |
||
| 306 | int i; |
||
| 307 | |||
| 308 | fprintf(stdout, "Quitting...\n"); |
||
| 309 | |||
| 310 | // OpenGL per-context cleanup. |
||
| 311 | for (i = 0; i < gContextsActiveCount; i++) { |
||
| 312 | if (gContextsActive[i].apiContextIndex) { |
||
| 313 | glutSetWindow(gContextsActive[i].apiContextIndex); |
||
| 314 | arglCleanup(gContextsActive[i].arglSettings); |
||
| 315 | DrawCubeCleanup(i); |
||
| 316 | glutDestroyWindow(gContextsActive[i].apiContextIndex); |
||
| 317 | gContextsActive[i].apiContextIndex = 0; |
||
| 318 | } |
||
| 319 | ar2VideoCapStop(gContextsActive[i].ARTVideo); |
||
| 320 | ar2VideoClose(gContextsActive[i].ARTVideo); |
||
| 321 | } |
||
| 322 | gContextsActiveCount = 0; |
||
| 323 | |||
| 324 | // Library finals (in reverse order to inits.) |
||
| 325 | DrawCubeFinal(); |
||
| 326 | } |
||
| 327 | |||
| 328 | static void Keyboard(unsigned char key, int x, int y) |
||
| 329 | { |
||
| 330 | int i; |
||
| 331 | int mode; |
||
| 332 | |||
| 333 | switch (key) { |
||
| 334 | case 0x1B: // Quit. |
||
| 335 | case 'Q': |
||
| 336 | case 'q': |
||
| 337 | exit(0); |
||
| 338 | break; |
||
| 339 | case ' ': |
||
| 340 | gDrawRotate = !gDrawRotate; |
||
| 341 | break; |
||
| 342 | case 'C': |
||
| 343 | case 'c': |
||
| 344 | for (i = 0; i < gContextsActiveCount; i++) { |
||
| 345 | mode = arglDrawModeGet(gContextsActive[i].arglSettings); |
||
| 346 | if (mode == AR_DRAW_BY_GL_DRAW_PIXELS) { |
||
| 347 | arglDrawModeSet(gContextsActive[i].arglSettings, AR_DRAW_BY_TEXTURE_MAPPING); |
||
| 348 | arglTexmapModeSet(gContextsActive[i].arglSettings, AR_DRAW_TEXTURE_FULL_IMAGE); |
||
| 349 | } else { |
||
| 350 | mode = arglTexmapModeGet(gContextsActive[i].arglSettings); |
||
| 351 | if (mode == AR_DRAW_TEXTURE_FULL_IMAGE) arglTexmapModeSet(gContextsActive[i].arglSettings, AR_DRAW_TEXTURE_HALF_IMAGE); |
||
| 352 | else arglDrawModeSet(gContextsActive[i].arglSettings, AR_DRAW_BY_GL_DRAW_PIXELS); |
||
| 353 | } |
||
| 354 | fprintf(stderr, "*** Camera %2d - %f (frame/sec)\n", i + 1, (double)(gContextsActive[i].callCountMarkerDetect)/arUtilTimer()); |
||
| 355 | gContextsActive[i].callCountMarkerDetect = 0; |
||
| 356 | debugReportMode(gContextsActive[i].arglSettings); |
||
| 357 | } |
||
| 358 | arUtilTimerReset(); |
||
| 359 | gCallCountGetImage = 0; |
||
| 360 | break; |
||
| 361 | case 'D': |
||
| 362 | case 'd': |
||
| 363 | arDebug = !arDebug; |
||
| 364 | break; |
||
| 365 | case '?': |
||
| 366 | case '/': |
||
| 367 | printf("Keys:\n"); |
||
| 368 | printf(" q or [esc] Quit demo.\n"); |
||
| 369 | printf(" c Change arglDrawMode and arglTexmapMode.\n"); |
||
| 370 | printf(" d Activate / deactivate debug mode.\n"); |
||
| 371 | printf(" ? or / Show this help.\n"); |
||
| 372 | printf("\nAdditionally, the ARVideo library supplied the following help text:\n"); |
||
| 373 | arVideoDispOption(); |
||
| 374 | break; |
||
| 375 | default: |
||
| 376 | break; |
||
| 377 | } |
||
| 378 | } |
||
| 379 | |||
| 380 | static void Idle(void) |
||
| 381 | { |
||
| 382 | int i; |
||
| 383 | static int ms_prev; |
||
| 384 | int ms; |
||
| 385 | float s_elapsed; |
||
| 386 | ARUint8 *image; |
||
| 387 | |||
| 388 | ARMarkerInfo *marker_info; // Pointer to array holding the details of detected markers. |
||
| 389 | int marker_num; // Count of number of markers detected. |
||
| 390 | int j, k; |
||
| 391 | |||
| 392 | // Find out how long since Idle() last ran. |
||
| 393 | ms = glutGet(GLUT_ELAPSED_TIME); |
||
| 394 | s_elapsed = (float)(ms - ms_prev) * 0.001; |
||
| 395 | if (s_elapsed < 0.01f) return; // Don't update more often than 100 Hz. |
||
| 396 | ms_prev = ms; |
||
| 397 | |||
| 398 | // Update drawing. |
||
| 399 | DrawCubeUpdate(s_elapsed); |
||
| 400 | |||
| 401 | gCallCountGetImage++; // Increment Idle() counter. |
||
| 402 | |||
| 403 | for (i = 0; i < gContextsActiveCount; i++) { |
||
| 404 | |||
| 405 | // Grab a video frame. |
||
| 406 | if ((image = ar2VideoGetImage(gContextsActive[i].ARTVideo)) != NULL) { |
||
| 407 | gContextsActive[i].ARTImage = image; // Save the fetched image. |
||
| 408 | gContextsActive[i].patt_found = FALSE; // Invalidate any previous detected markers. |
||
| 409 | |||
| 410 | gContextsActive[i].callCountMarkerDetect++; // Increment ARToolKit FPS counter. |
||
| 411 | //fprintf(stderr, "Idle(): Got image #%ld from cam %d on attempt #%ld.\n", gContextsActive[i].callCountMarkerDetect, i + 1, gCallCountGetImage); |
||
| 412 | |||
| 413 | // Detect the markers in the video frame. |
||
| 414 | if (arDetectMarkerLite(gContextsActive[i].ARTImage, gContextsActive[i].ARTThreshhold, &marker_info, &marker_num) < 0) { |
||
| 415 | exit(-1); |
||
| 416 | } |
||
| 417 | |||
| 418 | // Check through the marker_info array for highest confidence |
||
| 419 | // visible marker matching our preferred pattern. |
||
| 420 | k = -1; |
||
| 421 | for (j = 0; j < marker_num; j++) { |
||
| 422 | if (marker_info[j].id == gPatt_id) { |
||
| 423 | if (k == -1) k = j; // First marker detected. |
||
| 424 | else if(marker_info[j].cf > marker_info[k].cf) k = j; // Higher confidence marker detected. |
||
| 425 | } |
||
| 426 | } |
||
| 427 | |||
| 428 | if(k != -1) { |
||
| 429 | // Get the transformation between the marker and the real camera into gPatt_trans1. |
||
| 430 | arGetTransMat(&(marker_info[k]), gPatt_centre, gPatt_width, gContextsActive[i].patt_trans); |
||
| 431 | gContextsActive[i].patt_found = TRUE; |
||
| 432 | } |
||
| 433 | |||
| 434 | glutPostWindowRedisplay(gContextsActive[i].apiContextIndex); |
||
| 435 | } |
||
| 436 | |||
| 437 | } |
||
| 438 | } |
||
| 439 | |||
| 440 | // |
||
| 441 | // The function is called on events when the visibility of a |
||
| 442 | // GLUT window changes (including when it first becomes visible). |
||
| 443 | // |
||
| 444 | static void Visibility(int visible) |
||
| 445 | { |
||
| 446 | if (visible == GLUT_VISIBLE) { |
||
| 447 | glutIdleFunc(Idle); |
||
| 448 | } else { |
||
| 449 | glutIdleFunc(NULL); |
||
| 450 | } |
||
| 451 | } |
||
| 452 | |||
| 453 | // |
||
| 454 | // This function is called when the |
||
| 455 | // GLUT window is resized. |
||
| 456 | // |
||
| 457 | static void Reshape(int w, int h) |
||
| 458 | { |
||
| 459 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
||
| 460 | glViewport(0, 0, (GLsizei) w, (GLsizei) h); |
||
| 461 | |||
| 462 | glMatrixMode(GL_PROJECTION); |
||
| 463 | glLoadIdentity(); |
||
| 464 | glMatrixMode(GL_MODELVIEW); |
||
| 465 | glLoadIdentity(); |
||
| 466 | |||
| 467 | // Call through to anyone else who needs to know about window sizing here. |
||
| 468 | } |
||
| 469 | |||
| 470 | // |
||
| 471 | // This function is called when a window needs redrawing. |
||
| 472 | // |
||
| 473 | static void DisplayPerContext(const int drawContextIndex) |
||
| 474 | { |
||
| 475 | GLdouble p[16]; |
||
| 476 | GLdouble m[16]; |
||
| 477 | |||
| 478 | // Select correct buffer for this context. |
||
| 479 | glDrawBuffer(GL_BACK); |
||
| 480 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear the buffers for new frame. |
||
| 481 | |||
| 482 | arglDispImage(gContextsActive[drawContextIndex].ARTImage, |
||
| 483 | &(gContextsActive[drawContextIndex].ARTCparam), |
||
| 484 | 1.0, |
||
| 485 | gContextsActive[drawContextIndex].arglSettings); // zoom = 1.0. |
||
| 486 | ar2VideoCapNext(gContextsActive[drawContextIndex].ARTVideo); |
||
| 487 | gContextsActive[drawContextIndex].ARTImage = NULL; // Image data is no longer valid after calling ar2VideoCapNext(). |
||
| 488 | |||
| 489 | if (gContextsActive[drawContextIndex].patt_found) { |
||
| 490 | |||
| 491 | // Projection transformation. |
||
| 492 | arglCameraFrustumRH(&(gContextsActive[drawContextIndex].ARTCparam), VIEW_DISTANCE_MIN, VIEW_DISTANCE_MAX, p); |
||
| 493 | glMatrixMode(GL_PROJECTION); |
||
| 494 | glLoadMatrixd(p); |
||
| 495 | glMatrixMode(GL_MODELVIEW); |
||
| 496 | |||
| 497 | // Viewing transformation. |
||
| 498 | glLoadIdentity(); |
||
| 499 | // Lighting and geometry that moves with the camera should go here. |
||
| 500 | // (I.e. must be specified before viewing transformations.) |
||
| 501 | //none |
||
| 502 | |||
| 503 | // ARToolKit supplied distance in millimetres, but I want OpenGL to work in my units. |
||
| 504 | arglCameraViewRH(gContextsActive[drawContextIndex].patt_trans, m, VIEW_SCALEFACTOR); |
||
| 505 | glLoadMatrixd(m); |
||
| 506 | |||
| 507 | // All other lighting and geometry goes here. |
||
| 508 | DrawCube(drawContextIndex); |
||
| 509 | } // patt_found |
||
| 510 | |||
| 511 | // Any 2D overlays go here. |
||
| 512 | //none |
||
| 513 | |||
| 514 | // Drawing for this context complete. |
||
| 515 | } |
||
| 516 | |||
| 517 | // Linear search through all active contexts to find context index for the current glut window. |
||
| 518 | int getContextIndexForCurrentGLUTWindow(void) |
||
| 519 | { |
||
| 520 | int i, window; |
||
| 521 | |||
| 522 | if ((window = glutGetWindow()) != 0) { |
||
| 523 | for (i = 0; i < gContextsActiveCount; i++) { |
||
| 524 | if (gContextsActive[i].apiContextIndex == window) return (i); |
||
| 525 | } |
||
| 526 | } |
||
| 527 | return (-1); |
||
| 528 | } |
||
| 529 | |||
| 530 | static void Display(void) |
||
| 531 | { |
||
| 532 | int contextIndex; |
||
| 533 | |||
| 534 | if ((contextIndex = getContextIndexForCurrentGLUTWindow()) != -1) { |
||
| 535 | DisplayPerContext(contextIndex); |
||
| 536 | glutSwapBuffers(); |
||
| 537 | } |
||
| 538 | } |
||
| 539 | |||
| 540 | int main(int argc, char** argv) |
||
| 541 | { |
||
| 542 | int i; |
||
| 543 | char windowTitle[32] = {0}; |
||
| 544 | const char *cparam_names[] = { // Camera parameter names. |
||
| 545 | "Data/camera_para.dat", |
||
| 546 | "Data/camera_para.dat", |
||
| 547 | }; |
||
| 548 | char *vconfs[] = { // Camera configuration. |
||
| 549 | #if defined(_WIN32) |
||
| 550 | "Data\\WDM_camera_flipV.xml", |
||
| 551 | "Data\\WDM_camera_flipV.xml", |
||
| 552 | #elif defined(__APPLE__) |
||
| 553 | "", |
||
| 554 | "", |
||
| 555 | #else |
||
| 556 | "-dev=/dev/video0 -channel=0 -palette=YUV420P -width=320 -height=240", |
||
| 557 | "-dev=/dev/video1 -channel=0 -palette=YUV420P -width=320 -height=240", |
||
| 558 | #endif |
||
| 559 | }; |
||
| 560 | const char *patt_name = "Data/patt.hiro"; |
||
| 561 | |||
| 562 | // ---------------------------------------------------------------------------- |
||
| 563 | // Library inits. |
||
| 564 | // |
||
| 565 | |||
| 566 | glutInit(&argc, argv); |
||
| 567 | |||
| 568 | // Register a cleanup function to be called upon exit(). |
||
| 569 | if (atexit(Quit) < 0) { |
||
| 570 | fprintf(stderr, "main(): Unable to register exit function.\n"); |
||
| 571 | exit(-1); // Bail out if we can't even register our exit function. |
||
| 572 | } |
||
| 573 | |||
| 574 | // Initialise drawing libraries. |
||
| 575 | if (!DrawCubeInit(CONTEXTSACTIVECOUNTMAX)) { |
||
| 576 | fprintf(stderr, "main(): DrawCubeInit returned error.\n"); |
||
| 577 | exit(-1); |
||
| 578 | } |
||
| 579 | |||
| 580 | |||
| 581 | // ---------------------------------------------------------------------------- |
||
| 582 | // Hardware setup. |
||
| 583 | // |
||
| 584 | |||
| 585 | if ((gContextsActive = (CONTEXT_INFO *)calloc(CONTEXTSACTIVECOUNTMAX, sizeof(CONTEXT_INFO))) == NULL) exit(-1); |
||
| 586 | if (!setupCameras(CONTEXTSACTIVECOUNT, cparam_names, vconfs)) { |
||
| 587 | fprintf(stderr, "main(): Unable to set up %d AR cameras.\n", CONTEXTSACTIVECOUNT); |
||
| 588 | exit(-1); |
||
| 589 | } |
||
| 590 | gContextsActiveCount = CONTEXTSACTIVECOUNT; |
||
| 591 | for (i = 0; i < gContextsActiveCount; i++) if (!setupMarker(patt_name, &gPatt_id)) { |
||
| 592 | fprintf(stderr, "main(): Unable to set up AR marker.\n"); |
||
| 593 | exit(-1); |
||
| 594 | } |
||
| 595 | |||
| 596 | // ---------------------------------------------------------------------------- |
||
| 597 | // Library setup. |
||
| 598 | // |
||
| 599 | |||
| 600 | // Per- GL context setup. |
||
| 601 | for (i = 0; i < gContextsActiveCount; i++ ) { |
||
| 602 | |||
| 603 | // Set up GL context(s) for OpenGL to draw into. |
||
| 604 | glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); |
||
| 605 | glutInitWindowSize(gContextsActive[i].ARTCparam.xsize, gContextsActive[i].ARTCparam.ysize); |
||
| 606 | glutInitWindowPosition(10 + 10*i, 20 + 10*i); // First window at 20,10, subsequent windows staggered. |
||
| 607 | sprintf(windowTitle, "Video source %i", i); |
||
| 608 | if ((gContextsActive[i].apiContextIndex = glutCreateWindow(windowTitle)) < 1) { |
||
| 609 | fprintf(stderr, "main(): Unable to create window.\n"); |
||
| 610 | exit(-1); |
||
| 611 | } |
||
| 612 | glutDisplayFunc(Display); |
||
| 613 | glutReshapeFunc(Reshape); |
||
| 614 | glutVisibilityFunc(Visibility); |
||
| 615 | glutKeyboardFunc(Keyboard); |
||
| 616 | |||
| 617 | DrawCubeSetup(i); |
||
| 618 | |||
| 619 | if ((gContextsActive[i].arglSettings = arglSetupForCurrentContext()) == NULL) { |
||
| 620 | fprintf(stderr, "main(): arglSetupForCurrentContext() returned error.\n"); |
||
| 621 | exit(-1); |
||
| 622 | } |
||
| 623 | debugReportMode(gContextsActive[i].arglSettings); |
||
| 624 | glEnable(GL_DEPTH_TEST); |
||
| 625 | } |
||
| 626 | arUtilTimerReset(); |
||
| 627 | |||
| 628 | // Register GLUT event-handling callbacks. |
||
| 629 | // NB: Idle() is registered by Visibility. |
||
| 630 | glutMainLoop(); |
||
| 631 | |||
| 632 | return (0); |
||
| 633 | } |