• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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