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