xref: /aosp_15_r20/external/tensorflow/tensorflow/tools/android/test/jni/object_tracking/sprite.h (revision b6fb3261f9314811a0f4371741dbb8839866f948)
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