/* * Copyright 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "TextureAsset.h" #include #include "AndroidOut.h" #include "Utility.h" std::shared_ptr TextureAsset::loadAsset(AAssetManager *assetManager, const std::string &assetPath) { // Get the image from asset manager auto pAndroidRobotPng = AAssetManager_open(assetManager, assetPath.c_str(), AASSET_MODE_BUFFER); // Make a decoder to turn it into a texture AImageDecoder *pAndroidDecoder = nullptr; auto result = AImageDecoder_createFromAAsset(pAndroidRobotPng, &pAndroidDecoder); assert(result == ANDROID_IMAGE_DECODER_SUCCESS); // make sure we get 8 bits per channel out. RGBA order. AImageDecoder_setAndroidBitmapFormat(pAndroidDecoder, ANDROID_BITMAP_FORMAT_RGBA_8888); // Get the image header, to help set everything up const AImageDecoderHeaderInfo *pAndroidHeader = nullptr; pAndroidHeader = AImageDecoder_getHeaderInfo(pAndroidDecoder); // important metrics for sending to GL auto width = AImageDecoderHeaderInfo_getWidth(pAndroidHeader); auto height = AImageDecoderHeaderInfo_getHeight(pAndroidHeader); auto stride = AImageDecoder_getMinimumStride(pAndroidDecoder); // Get the bitmap data of the image auto upAndroidImageData = std::make_unique>(height * stride); auto decodeResult = AImageDecoder_decodeImage(pAndroidDecoder, upAndroidImageData->data(), stride, upAndroidImageData->size()); assert(decodeResult == ANDROID_IMAGE_DECODER_SUCCESS); // Get an opengl texture GLuint textureId; glGenTextures(1, &textureId); glBindTexture(GL_TEXTURE_2D, textureId); // Clamp to the edge, you'll get odd results alpha blending if you don't glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // Load the texture into VRAM glTexImage2D(GL_TEXTURE_2D, // target 0, // mip level GL_RGBA, // internal format, often advisable to use BGR width, // width of the texture height, // height of the texture 0, // border (always 0) GL_RGBA, // format GL_UNSIGNED_BYTE, // type upAndroidImageData->data() // Data to upload ); // generate mip levels. Not really needed for 2D, but good to do glGenerateMipmap(GL_TEXTURE_2D); // cleanup helpers AImageDecoder_delete(pAndroidDecoder); AAsset_close(pAndroidRobotPng); // Create a shared pointer so it can be cleaned up easily/automatically return std::shared_ptr(new TextureAsset(textureId)); } TextureAsset::~TextureAsset() { // return texture resources glDeleteTextures(1, &textureID_); textureID_ = 0; }