void drawCube(float *viewProjectionMatrix, float size, float x, float y, float z) { // Colour cube data. int i; const GLfloat cube_vertices [8][3] = { /* +z */ {0.5f, 0.5f, 0.5f}, {0.5f, -0.5f, 0.5f}, {-0.5f, -0.5f, 0.5f}, {-0.5f, 0.5f, 0.5f}, /* -z */ {0.5f, 0.5f, -0.5f}, {0.5f, -0.5f, -0.5f}, {-0.5f, -0.5f, -0.5f}, {-0.5f, 0.5f, -0.5f} }; const GLubyte cube_vertex_colors [8][4] = { {255, 255, 255, 255}, {255, 255, 0, 255}, {0, 255, 0, 255}, {0, 255, 255, 255}, {255, 0, 255, 255}, {255, 0, 0, 255}, {0, 0, 0, 255}, {0, 0, 255, 255} }; const GLubyte cube_vertex_colors_black [8][4] = { {0, 0, 0, 255}, {0, 0, 0, 255}, {0, 0, 0, 255}, {0, 0, 0, 255}, {0, 0, 0, 255}, {0, 0, 0, 255}, {0, 0, 0, 255}, {0, 0, 0, 255} }; const GLushort cube_faces [6][4] = { /* ccw-winding */ /* +z */ {3, 2, 1, 0}, /* -y */ {2, 3, 7, 6}, /* +y */ {0, 1, 5, 4}, /* -x */ {3, 0, 4, 7}, /* +x */ {1, 2, 6, 5}, /* -z */ {4, 5, 6, 7} }; float modelViewProjection[16]; mtxLoadMatrixf(modelViewProjection, viewProjectionMatrix); mtxTranslatef(modelViewProjection, x, y, z); // Rotate about z axis. mtxScalef(modelViewProjection, size, size, size); glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEW_PROJECTION_MATRIX], 1, GL_FALSE, modelViewProjection); glVertexAttribPointer(ATTRIBUTE_VERTEX, 3, GL_FLOAT, GL_FALSE, 0, cube_vertices); glEnableVertexAttribArray(ATTRIBUTE_VERTEX); glVertexAttribPointer(ATTRIBUTE_COLOUR, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, cube_vertex_colors); glEnableVertexAttribArray(ATTRIBUTE_COLOUR); #ifdef DEBUG if (!arglGLValidateProgram(program)) { ARLOGe("Error: shader program %d validation failed.\n", program); return; } #endif for (i = 0; i < 6; i++) { glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, &(cube_faces[i][0])); } glVertexAttribPointer(ATTRIBUTE_COLOUR, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, cube_vertex_colors_black); glEnableVertexAttribArray(ATTRIBUTE_COLOUR); for (i = 0; i < 6; i++) { glDrawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_SHORT, &(cube_faces[i][0])); } }
JNIEXPORT void JNICALL JNIFUNCTION_NATIVE(nativeDrawFrame(JNIEnv* env, jobject obj)) { float width, height; float viewProjection[16]; if (!videoInited) { #ifdef DEBUG LOGI("nativeDrawFrame !VIDEO\n"); #endif return; // No point in trying to draw until video is inited. } #ifdef DEBUG LOGI("nativeDrawFrame\n"); #endif if (!gARViewInited) { if (!initARView()) return; } if (gARViewLayoutRequired) layoutARView(); // Upload new video frame if required. if (videoFrameNeedsPixelBufferDataUpload) { arglPixelBufferDataUploadBiPlanar(gArglSettings, gVideoFrame, gVideoFrame + videoWidth*videoHeight); videoFrameNeedsPixelBufferDataUpload = false; } glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear the buffers for new frame. // Display the current frame arglDispImage(gArglSettings); if (!program) { GLuint vertShader = 0, fragShader = 0; // A simple shader pair which accepts just a vertex position and colour, no lighting. const char vertShaderString[] = "attribute vec4 position;\n" "attribute vec4 colour;\n" "uniform mat4 modelViewProjectionMatrix;\n" "varying vec4 colourVarying;\n" "void main()\n" "{\n" "gl_Position = modelViewProjectionMatrix * position;\n" "colourVarying = colour;\n" "}\n"; const char fragShaderString[] = "#ifdef GL_ES\n" "precision mediump float;\n" "#endif\n" "varying vec4 colourVarying;\n" "void main()\n" "{\n" "gl_FragColor = colourVarying;\n" "}\n"; if (program) arglGLDestroyShaders(0, 0, program); program = glCreateProgram(); if (!program) { ARLOGe("drawCube: Error creating shader program.\n"); arglGLDestroyShaders(vertShader, fragShader, program); return; } if (!arglGLCompileShaderFromString(&vertShader, GL_VERTEX_SHADER, vertShaderString)) { ARLOGe("drawCube: Error compiling vertex shader.\n"); arglGLDestroyShaders(vertShader, fragShader, program); return; } if (!arglGLCompileShaderFromString(&fragShader, GL_FRAGMENT_SHADER, fragShaderString)) { ARLOGe("drawCube: Error compiling fragment shader.\n"); arglGLDestroyShaders(vertShader, fragShader, program); return; } glAttachShader(program, vertShader); glAttachShader(program, fragShader); glBindAttribLocation(program, ATTRIBUTE_VERTEX, "position"); glBindAttribLocation(program, ATTRIBUTE_COLOUR, "colour"); if (!arglGLLinkProgram(program)) { ARLOGe("drawCube: Error linking shader program.\n"); arglGLDestroyShaders(vertShader, fragShader, program); return; } arglGLDestroyShaders(vertShader, fragShader, 0); // After linking, shader objects can be deleted. // Retrieve linked uniform locations. uniforms[UNIFORM_MODELVIEW_PROJECTION_MATRIX] = glGetUniformLocation(program, "modelViewProjectionMatrix"); } glUseProgram(program); // Set up 3D mode. mtxLoadIdentityf(viewProjection); mtxMultMatrixf(viewProjection, cameraLens); glStateCacheEnableDepthTest(); // Set any initial per-frame GL state you require here. // ---> // Lighting and geometry that moves with the camera should be added here. // (I.e. should be specified before camera pose transform.) // ---> // Draw an object on all valid markers. for (int i = 0; i < markersSquareCount; i++) { if (markersSquare[i].valid) { float viewProjection2[16]; mtxLoadMatrixf(viewProjection2, viewProjection); mtxMultMatrixf(viewProjection2, markersSquare[i].pose.T); drawCube(viewProjection2, 40.0f, 0.0f, 0.0f, 20.0f); } } if (cameraPoseValid) { mtxMultMatrixf(viewProjection, cameraPose); // All lighting and geometry to be drawn in world coordinates goes here. // ---> } // If you added external OpenGL code above, and that code doesn't use the glStateCache routines, // then uncomment the line below. //glStateCacheFlush(); // Set up 2D mode. mtxLoadIdentityf(viewProjection); width = (float)viewPort[viewPortIndexWidth]; height = (float)viewPort[viewPortIndexHeight]; mtxOrthof(viewProjection, 0.0f, width, 0.0f, height, -1.0f, 1.0f); glStateCacheDisableDepthTest(); // Add your own 2D overlays here. // ---> // If you added external OpenGL code above, and that code doesn't use the glStateCache routines, // then uncomment the line below. //glStateCacheFlush(); #ifdef DEBUG // Example of 2D drawing. It just draws a white border line. Change the 0 to 1 to enable. const GLfloat square_vertices [4][3] = { {0.5f, 0.5f, 0.0f}, {0.5f, height - 0.5f, 0.0f}, {width - 0.5f, height - 0.5f, 0.0f}, {width - 0.5f, 0.5f, 0.0f} }; const GLubyte square_vertex_colors_white [4][4] = { {255, 255, 255, 255}, {255, 255, 255, 255}, {255, 255, 255, 255}, {255, 255, 255, 255}}; glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEW_PROJECTION_MATRIX], 1, GL_FALSE, viewProjection); glVertexAttribPointer(ATTRIBUTE_VERTEX, 3, GL_FLOAT, GL_FALSE, 0, square_vertices); glEnableVertexAttribArray(ATTRIBUTE_VERTEX); glVertexAttribPointer(ATTRIBUTE_COLOUR, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, square_vertex_colors_white); glEnableVertexAttribArray(ATTRIBUTE_COLOUR); if (!arglGLValidateProgram(program)) { ARLOGe("Error: shader program %d validation failed.\n", program); return; } glDrawArrays(GL_LINE_LOOP, 0, 4); #endif #ifdef DEBUG CHECK_GL_ERROR(); #endif }
static void mainLoop(void) { static int ms_prev; int ms; float s_elapsed; ARUint8 *image; ARMarkerInfo* markerInfo; int markerNum; ARdouble err; ARPose opticalPose; int i, j, k; // Calculate time delta. ms = glutGet(GLUT_ELAPSED_TIME); s_elapsed = (float)(ms - ms_prev) * 0.001f; ms_prev = ms; // Grab a video frame. if ((image = arVideoGetImage()) != NULL) { gARTImage = image; // Save the fetched image. gCallCountMarkerDetect++; // Increment ARToolKit FPS counter. // Detect the markers in the video frame. if (arDetectMarker(gARHandle, gARTImage) < 0) { exit(-1); } // Get detected markers markerInfo = arGetMarker(gARHandle); markerNum = arGetMarkerNum(gARHandle); // Update markers. for (i = 0; i < markersSquareCount; i++) { markersSquare[i].validPrev = markersSquare[i].valid; // Check through the marker_info array for highest confidence // visible marker matching our preferred pattern. k = -1; if (markersSquare[i].patt_type == AR_PATTERN_TYPE_TEMPLATE) { for (j = 0; j < markerNum; j++) { if (markersSquare[i].patt_id == markerInfo[j].idPatt) { if (k == -1) { if (markerInfo[j].cfPatt >= markersSquare[i].matchingThreshold) k = j; // First marker detected. } else if (markerInfo[j].cfPatt > markerInfo[k].cfPatt) k = j; // Higher confidence marker detected. } } if (k != -1) { markerInfo[k].id = markerInfo[k].idPatt; markerInfo[k].cf = markerInfo[k].cfPatt; markerInfo[k].dir = markerInfo[k].dirPatt; } } else { for (j = 0; j < markerNum; j++) { if (markersSquare[i].patt_id == markerInfo[j].idMatrix) { if (k == -1) { if (markerInfo[j].cfMatrix >= markersSquare[i].matchingThreshold) k = j; // First marker detected. } else if (markerInfo[j].cfMatrix > markerInfo[k].cfMatrix) k = j; // Higher confidence marker detected. } } if (k != -1) { markerInfo[k].id = markerInfo[k].idMatrix; markerInfo[k].cf = markerInfo[k].cfMatrix; markerInfo[k].dir = markerInfo[k].dirMatrix; } } if (k != -1) { markersSquare[i].valid = TRUE; ARLOGd("Marker %d matched pattern %d.\n", i, markerInfo[k].id); // Get the transformation between the marker and the real camera into trans. if (markersSquare[i].validPrev && useContPoseEstimation) { err = arGetTransMatSquareCont(gAR3DHandle, &(markerInfo[k]), markersSquare[i].trans, markersSquare[i].marker_width, markersSquare[i].trans); } else { err = arGetTransMatSquare(gAR3DHandle, &(markerInfo[k]), markersSquare[i].marker_width, markersSquare[i].trans); } } else { markersSquare[i].valid = FALSE; } if (markersSquare[i].valid) { // Filter the pose estimate. if (markersSquare[i].ftmi) { if (arFilterTransMat(markersSquare[i].ftmi, markersSquare[i].trans, !markersSquare[i].validPrev) < 0) { ARLOGe("arFilterTransMat error with marker %d.\n", i); } } if (!markersSquare[i].validPrev) { // Marker has become visible, tell any dependent objects. VirtualEnvironmentHandleARMarkerAppeared(i); } // We have a new pose, so set that. arglCameraViewRH(markersSquare[i].trans, markersSquare[i].pose.T, 1.0f /*VIEW_SCALEFACTOR*/); // Tell any dependent objects about the update. // Work out the correct optical position relative to the eye. // We first apply the transform from the eye of the viewer to the camera, // then the usual view relative to the camera. // Remember, mtxMultMatrix(A, B) post-multiplies A by B, i.e. A' = A.B, // so opticalPose.T = eye.m . markersSquare[i].pose.T. #ifdef ARDOUBLE_IS_FLOAT mtxLoadMatrixf(opticalPose.T, eye.m); mtxMultMatrixf(opticalPose.T, markersSquare[i].pose.T); #else mtxLoadMatrixd(opticalPose.T, eye.m); mtxMultMatrixd(opticalPose.T, markersSquare[i].pose.T); #endif VirtualEnvironmentHandleARMarkerWasUpdated(i, opticalPose); } else { if (markersSquare[i].validPrev) { // Marker has ceased to be visible, tell any dependent objects. VirtualEnvironmentHandleARMarkerDisappeared(i); } } } // Tell GLUT the display has changed. glutPostRedisplay(); } else { arUtilSleep(2); } }