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 }