/* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // OpenGL ES 2.0 code #include #include #include #include #include #include #include #include #include #include #include "glcamera.h" #include "image_pool.h" using namespace cv; #define LOG_TAG "libandroid-opencv" #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) static void printGLString(const char *name, GLenum s) { const char *v = (const char *)glGetString(s); LOGI("GL %s = %s\n", name, v); } static void checkGlError(const char* op) { for (GLint error = glGetError(); error; error = glGetError()) { LOGI("after %s() glError (0x%x)\n", op, error); } } static const char gVertexShader[] = "attribute vec4 a_position; \n" "attribute vec2 a_texCoord; \n" "varying vec2 v_texCoord; \n" "void main() \n" "{ \n" " gl_Position = a_position; \n" " v_texCoord = a_texCoord; \n" "} \n"; static const char gFragmentShader[] = "precision mediump float; \n" "varying vec2 v_texCoord; \n" "uniform sampler2D s_texture; \n" "void main() \n" "{ \n" " gl_FragColor = texture2D( s_texture, v_texCoord );\n" "} \n"; const GLfloat gTriangleVertices[] = {0.0f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f}; GLubyte testpixels[4 * 3] = {255, 0, 0, // Red 0, 255, 0, // Green 0, 0, 255, // Blue 255, 255, 0 // Yellow }; GLuint glcamera::createSimpleTexture2D(GLuint _textureid, GLubyte* pixels, int width, int height, int channels) { // Bind the texture glActiveTexture( GL_TEXTURE0); checkGlError("glActiveTexture"); // Bind the texture object glBindTexture(GL_TEXTURE_2D, _textureid); checkGlError("glBindTexture"); GLenum format; switch (channels) { case 3: format = GL_RGB; break; case 1: format = GL_LUMINANCE; break; case 4: format = GL_RGBA; break; } // Load the texture glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, pixels); checkGlError("glTexImage2D"); // Set the filtering mode glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); return _textureid; } GLuint glcamera::loadShader(GLenum shaderType, const char* pSource) { GLuint shader = glCreateShader(shaderType); if (shader) { glShaderSource(shader, 1, &pSource, NULL); glCompileShader(shader); GLint compiled = 0; glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); if (!compiled) { GLint infoLen = 0; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); if (infoLen) { char* buf = (char*)malloc(infoLen); if (buf) { glGetShaderInfoLog(shader, infoLen, NULL, buf); LOGE("Could not compile shader %d:\n%s\n", shaderType, buf); free(buf); } glDeleteShader(shader); shader = 0; } } } return shader; } GLuint glcamera::createProgram(const char* pVertexSource, const char* pFragmentSource) { GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource); if (!vertexShader) { return 0; } GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource); if (!pixelShader) { return 0; } GLuint program = glCreateProgram(); if (program) { glAttachShader(program, vertexShader); checkGlError("glAttachShader"); glAttachShader(program, pixelShader); checkGlError("glAttachShader"); glLinkProgram(program); GLint linkStatus = GL_FALSE; glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); if (linkStatus != GL_TRUE) { GLint bufLength = 0; glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength); if (bufLength) { char* buf = (char*)malloc(bufLength); if (buf) { glGetProgramInfoLog(program, bufLength, NULL, buf); LOGE("Could not link program:\n%s\n", buf); free(buf); } } glDeleteProgram(program); program = 0; } } return program; } //GLuint textureID; bool glcamera::setupGraphics(int w, int h) { printGLString("Version", GL_VERSION); printGLString("Vendor", GL_VENDOR); printGLString("Renderer", GL_RENDERER); printGLString("Extensions", GL_EXTENSIONS); LOGI("setupGraphics(%d, %d)", w, h); gProgram = createProgram(gVertexShader, gFragmentShader); if (!gProgram) { LOGE("Could not create program."); return false; } gvPositionHandle = glGetAttribLocation(gProgram, "a_position"); gvTexCoordHandle = glGetAttribLocation(gProgram, "a_texCoord"); gvSamplerHandle = glGetAttribLocation(gProgram, "s_texture"); // Use tightly packed data glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // Generate a texture object glGenTextures(1, &textureID); textureID = createSimpleTexture2D(textureID, testpixels, 2, 2, 3); checkGlError("glGetAttribLocation"); LOGI("glGetAttribLocation(\"vPosition\") = %d\n", gvPositionHandle); glViewport(0, 0, w, h); checkGlError("glViewport"); return true; } void glcamera::renderFrame() { GLfloat vVertices[] = {-1.0f, 1.0f, 0.0f, // Position 0 0.0f, 0.0f, // TexCoord 0 -1.0f, -1.0f, 0.0f, // Position 1 0.0f, 1.0f, // TexCoord 1 1.0f, -1.0f, 0.0f, // Position 2 1.0f, 1.0f, // TexCoord 2 1.0f, 1.0f, 0.0f, // Position 3 1.0f, 0.0f // TexCoord 3 }; GLushort indices[] = {0, 1, 2, 0, 2, 3}; GLsizei stride = 5 * sizeof(GLfloat); // 3 for position, 2 for texture glClearColor(0.0f, 0.0f, 0.0f, 0.0f); checkGlError("glClearColor"); glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); checkGlError("glClear"); glUseProgram(gProgram); checkGlError("glUseProgram"); // Load the vertex position glVertexAttribPointer(gvPositionHandle, 3, GL_FLOAT, GL_FALSE, stride, vVertices); // Load the texture coordinate glVertexAttribPointer(gvTexCoordHandle, 2, GL_FLOAT, GL_FALSE, stride, &vVertices[3]); glEnableVertexAttribArray(gvPositionHandle); glEnableVertexAttribArray(gvTexCoordHandle); // Bind the texture glActiveTexture( GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textureID); // Set the sampler texture unit to 0 glUniform1i(gvSamplerHandle, 0); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices); //checkGlError("glVertexAttribPointer"); //glEnableVertexAttribArray(gvPositionHandle); //checkGlError("glEnableVertexAttribArray"); //glDrawArrays(GL_TRIANGLES, 0, 3); //checkGlError("glDrawArrays"); } void glcamera::init(int width, int height) { newimage = false; nimg = Mat(); setupGraphics(width, height); } void glcamera::step() { if (newimage && !nimg.empty()) { textureID = createSimpleTexture2D(textureID, nimg.ptr (0), nimg.rows, nimg.cols, nimg.channels()); newimage = false; } renderFrame(); } #define NEAREST_POW2(x)((int)(0.5 + std::log(x)/0.69315) ) void glcamera::setTextureImage(const Mat& img) { Size size(256, 256); resize(img, nimg, size, cv::INTER_NEAREST); newimage = true; } void glcamera::drawMatToGL(int idx, image_pool* pool) { Mat img = pool->getImage(idx); if (img.empty()) return; //no image at input_idx! setTextureImage(img); } glcamera::glcamera() : newimage(false) { LOGI("glcamera constructor"); } glcamera::~glcamera() { LOGI("glcamera destructor"); }