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. Sprite(const Image<uint8_t> & image)36 explicit Sprite(const Image<uint8_t>& image) { LoadTexture(image, NULL); } 37 Sprite(const Image<uint8_t> & image,const BoundingBox * const area)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. ~Sprite()43 ~Sprite() { 44 glDeleteTextures(1, &texture_); 45 } 46 GetWidth()47 inline int GetWidth() const { 48 return actual_width_; 49 } 50 GetHeight()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. Draw()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: GetNextPowerOfTwo(const int number)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. LoadTexture(const Image<uint8_t> & texture_source,const BoundingBox * const area)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