/* * 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 #if __ANDROID__ #include #include #else #include #endif #include "android_logger.h" #include #include #include #include #include #include #include "glcamera.h" #include "image_pool.h" using namespace cv; 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"; 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: #if ANDROID format = GL_RGB; #else format = GL_BGR; #endif 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"); #if ANDROID // Set the filtering mode glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); #else /* Linear Filtering */ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); #endif return _textureid; } GLuint glcamera::loadShader(GLenum shaderType, const char* pSource) { GLuint shader = 0; #if __ANDROID__ 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; } } } #endif return shader; } GLuint glcamera::createProgram(const char* pVertexSource, const char* pFragmentSource) { #if __ANDROID__ 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; #else return 0; #endif } void glcamera::clear(){ nimg = Mat(); } //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); #if __ANDROID__ 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); glViewport(0, 0, w, h); #endif return true; } void glcamera::renderFrame() { #if __ANDROID__ 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, img_h, // TexCoord 1 1.0f, -1.0f, 0.0f, // Position 2 img_w, img_h, // TexCoord 2 1.0f, 1.0f, 0.0f, // Position 3 img_w, 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"); if(nimg.empty())return; 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); #endif //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.cols, nimg.rows, nimg.channels()); newimage = false; } renderFrame(); } #define NEAREST_POW2(x)( std::ceil(std::log(x)/0.69315) ) void glcamera::setTextureImage(const Mat& img) { int p = NEAREST_POW2(img.cols/2); //subsample by 2 //int sz = std::pow(2, p); // Size size(sz, sz); Size size(256, 256); img_w = 1; img_h = 1; if (nimg.cols != size.width) LOGI_STREAM( "using texture of size: (" << size.width << " , " << size.height << ") image size is: (" << img.cols << " , " << img.rows << ")"); nimg.create(size, img.type()); #if SUBREGION_NPO2 cv::Rect roi(0, 0, img.cols/2, img.rows/2); cv::Mat nimg_sub = nimg(roi); //img.copyTo(nimg_sub); img_w = (img.cols/2)/float(sz); img_h = (img.rows/2)/float(sz); cv::resize(img,nimg_sub,nimg_sub.size(),0,0,CV_INTER_NN); #else cv::resize(img, nimg, nimg.size(), 0, 0, CV_INTER_NN); #endif 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"); }