1 /*
2  * Copyright 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "TextureAsset.h"
17 
18 #include <android/imagedecoder.h>
19 
20 #include "AndroidOut.h"
21 #include "Utility.h"
22 
loadAsset(AAssetManager * assetManager,const std::string & assetPath)23 std::shared_ptr<TextureAsset> TextureAsset::loadAsset(AAssetManager *assetManager,
24                                                       const std::string &assetPath) {
25     // Get the image from asset manager
26     auto pAndroidRobotPng = AAssetManager_open(assetManager, assetPath.c_str(), AASSET_MODE_BUFFER);
27 
28     // Make a decoder to turn it into a texture
29     AImageDecoder *pAndroidDecoder = nullptr;
30     auto result = AImageDecoder_createFromAAsset(pAndroidRobotPng, &pAndroidDecoder);
31     assert(result == ANDROID_IMAGE_DECODER_SUCCESS);
32 
33     // make sure we get 8 bits per channel out. RGBA order.
34     AImageDecoder_setAndroidBitmapFormat(pAndroidDecoder, ANDROID_BITMAP_FORMAT_RGBA_8888);
35 
36     // Get the image header, to help set everything up
37     const AImageDecoderHeaderInfo *pAndroidHeader = nullptr;
38     pAndroidHeader = AImageDecoder_getHeaderInfo(pAndroidDecoder);
39 
40     // important metrics for sending to GL
41     auto width = AImageDecoderHeaderInfo_getWidth(pAndroidHeader);
42     auto height = AImageDecoderHeaderInfo_getHeight(pAndroidHeader);
43     auto stride = AImageDecoder_getMinimumStride(pAndroidDecoder);
44 
45     // Get the bitmap data of the image
46     auto upAndroidImageData = std::make_unique<std::vector<uint8_t>>(height * stride);
47     auto decodeResult = AImageDecoder_decodeImage(pAndroidDecoder, upAndroidImageData->data(),
48                                                   stride, upAndroidImageData->size());
49     assert(decodeResult == ANDROID_IMAGE_DECODER_SUCCESS);
50 
51     // Get an opengl texture
52     GLuint textureId;
53     glGenTextures(1, &textureId);
54     glBindTexture(GL_TEXTURE_2D, textureId);
55 
56     // Clamp to the edge, you'll get odd results alpha blending if you don't
57     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
58     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
59 
60     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
61     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
62 
63     // Load the texture into VRAM
64     glTexImage2D(GL_TEXTURE_2D,             // target
65                  0,                         // mip level
66                  GL_RGBA,                   // internal format, often advisable to use BGR
67                  width,                     // width of the texture
68                  height,                    // height of the texture
69                  0,                         // border (always 0)
70                  GL_RGBA,                   // format
71                  GL_UNSIGNED_BYTE,          // type
72                  upAndroidImageData->data() // Data to upload
73     );
74 
75     // generate mip levels. Not really needed for 2D, but good to do
76     glGenerateMipmap(GL_TEXTURE_2D);
77 
78     // cleanup helpers
79     AImageDecoder_delete(pAndroidDecoder);
80     AAsset_close(pAndroidRobotPng);
81 
82     // Create a shared pointer so it can be cleaned up easily/automatically
83     return std::shared_ptr<TextureAsset>(new TextureAsset(textureId));
84 }
85 
~TextureAsset()86 TextureAsset::~TextureAsset() {
87     // return texture resources
88     glDeleteTextures(1, &textureID_);
89     textureID_ = 0;
90 }