Home | History | Annotate | Download | only in object_tracking
      1 /* Copyright 2016 The TensorFlow Authors. All Rights Reserved.
      2 
      3 Licensed under the Apache License, Version 2.0 (the "License");
      4 you may not use this file except in compliance with the License.
      5 You may obtain a copy of the License at
      6 
      7     http://www.apache.org/licenses/LICENSE-2.0
      8 
      9 Unless required by applicable law or agreed to in writing, software
     10 distributed under the License is distributed on an "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 See the License for the specific language governing permissions and
     13 limitations under the License.
     14 ==============================================================================*/
     15 
     16 #ifndef TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_SPRITE_H_
     17 #define TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_SPRITE_H_
     18 
     19 #include <GLES/gl.h>
     20 #include <GLES/glext.h>
     21 
     22 #include "tensorflow/examples/android/jni/object_tracking/image-inl.h"
     23 #include "tensorflow/examples/android/jni/object_tracking/image.h"
     24 
     25 #ifndef __RENDER_OPENGL__
     26 #error sprite.h should not included if OpenGL is not enabled by platform.h
     27 #endif
     28 
     29 namespace tf_tracking {
     30 
     31 // This class encapsulates the logic necessary to load an render image data
     32 // at the same aspect ratio as the original source.
     33 class Sprite {
     34  public:
     35   // Only create Sprites when you have an OpenGl context.
     36   explicit Sprite(const Image<uint8_t>& image) { LoadTexture(image, NULL); }
     37 
     38   Sprite(const Image<uint8_t>& image, const BoundingBox* const area) {
     39     LoadTexture(image, area);
     40   }
     41 
     42   // Also, try to only delete a Sprite when holding an OpenGl context.
     43   ~Sprite() {
     44     glDeleteTextures(1, &texture_);
     45   }
     46 
     47   inline int GetWidth() const {
     48     return actual_width_;
     49   }
     50 
     51   inline int GetHeight() const {
     52     return actual_height_;
     53   }
     54 
     55   // Draw the sprite at 0,0 - original width/height in the current reference
     56   // frame. Any transformations desired must be applied before calling this
     57   // function.
     58   void Draw() const {
     59     const float float_width = static_cast<float>(actual_width_);
     60     const float float_height = static_cast<float>(actual_height_);
     61 
     62     // Where it gets rendered to.
     63     const float vertices[] = { 0.0f, 0.0f, 0.0f,
     64                                0.0f, float_height, 0.0f,
     65                                float_width, 0.0f, 0.0f,
     66                                float_width, float_height, 0.0f,
     67                                };
     68 
     69     // The coordinates the texture gets drawn from.
     70     const float max_x = float_width / texture_width_;
     71     const float max_y = float_height / texture_height_;
     72     const float textureVertices[] = {
     73         0, 0,
     74         0, max_y,
     75         max_x, 0,
     76         max_x, max_y,
     77     };
     78 
     79     glEnable(GL_TEXTURE_2D);
     80     glBindTexture(GL_TEXTURE_2D, texture_);
     81 
     82     glEnableClientState(GL_VERTEX_ARRAY);
     83     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
     84 
     85     glVertexPointer(3, GL_FLOAT, 0, vertices);
     86     glTexCoordPointer(2, GL_FLOAT, 0, textureVertices);
     87 
     88     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
     89 
     90     glDisableClientState(GL_VERTEX_ARRAY);
     91     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
     92   }
     93 
     94  private:
     95   inline int GetNextPowerOfTwo(const int number) const {
     96     int power_of_two = 1;
     97     while (power_of_two < number) {
     98       power_of_two *= 2;
     99     }
    100     return power_of_two;
    101   }
    102 
    103   // TODO(andrewharp): Allow sprites to have their textures reloaded.
    104   void LoadTexture(const Image<uint8_t>& texture_source,
    105                    const BoundingBox* const area) {
    106     glEnable(GL_TEXTURE_2D);
    107 
    108     glGenTextures(1, &texture_);
    109 
    110     glBindTexture(GL_TEXTURE_2D, texture_);
    111 
    112     int left = 0;
    113     int top = 0;
    114 
    115     if (area != NULL) {
    116       // If a sub-region was provided to pull the texture from, use that.
    117       left = area->left_;
    118       top = area->top_;
    119       actual_width_ = area->GetWidth();
    120       actual_height_ = area->GetHeight();
    121     } else {
    122       actual_width_ = texture_source.GetWidth();
    123       actual_height_ = texture_source.GetHeight();
    124     }
    125 
    126     // The textures must be a power of two, so find the sizes that are large
    127     // enough to contain the image data.
    128     texture_width_ = GetNextPowerOfTwo(actual_width_);
    129     texture_height_ = GetNextPowerOfTwo(actual_height_);
    130 
    131     bool allocated_data = false;
    132     uint8_t* texture_data;
    133 
    134     // Except in the lucky case where we're not using a sub-region of the
    135     // original image AND the source data has dimensions that are power of two,
    136     // care must be taken to copy data at the appropriate source and destination
    137     // strides so that the final block can be copied directly into texture
    138     // memory.
    139     // TODO(andrewharp): Figure out if data can be pulled directly from the
    140     // source image with some alignment modifications.
    141     if (left != 0 || top != 0 ||
    142         actual_width_ != texture_source.GetWidth() ||
    143         actual_height_ != texture_source.GetHeight()) {
    144       texture_data = new uint8_t[actual_width_ * actual_height_];
    145 
    146       for (int y = 0; y < actual_height_; ++y) {
    147         memcpy(texture_data + actual_width_ * y, texture_source[top + y] + left,
    148                actual_width_ * sizeof(uint8_t));
    149       }
    150       allocated_data = true;
    151     } else {
    152       // Cast away const-ness because for some reason glTexSubImage2D wants
    153       // a non-const data pointer.
    154       texture_data = const_cast<uint8_t*>(texture_source.data());
    155     }
    156 
    157     glTexImage2D(GL_TEXTURE_2D,
    158                  0,
    159                  GL_LUMINANCE,
    160                  texture_width_,
    161                  texture_height_,
    162                  0,
    163                  GL_LUMINANCE,
    164                  GL_UNSIGNED_BYTE,
    165                  NULL);
    166 
    167     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    168     glTexSubImage2D(GL_TEXTURE_2D,
    169                     0,
    170                     0,
    171                     0,
    172                     actual_width_,
    173                     actual_height_,
    174                     GL_LUMINANCE,
    175                     GL_UNSIGNED_BYTE,
    176                     texture_data);
    177 
    178     if (allocated_data) {
    179       delete(texture_data);
    180     }
    181 
    182     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    183   }
    184 
    185   // The id for the texture on the GPU.
    186   GLuint texture_;
    187 
    188   // The width and height to be used for display purposes, referring to the
    189   // dimensions of the original texture.
    190   int actual_width_;
    191   int actual_height_;
    192 
    193   // The allocated dimensions of the texture data, which must be powers of 2.
    194   int texture_width_;
    195   int texture_height_;
    196 
    197   TF_DISALLOW_COPY_AND_ASSIGN(Sprite);
    198 };
    199 
    200 }  // namespace tf_tracking
    201 
    202 #endif  // TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_SPRITE_H_
    203