| // | |
| // Copyright 2014 The ANGLE Project Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| // | |
| #include "tga_utils.h" | |
| #include <fstream> | |
| #include <iostream> | |
| #include <limits.h> | |
| #include <stdint.h> | |
| #include <string> | |
| TGAImage::TGAImage() | |
| : width(0), height(0), data(0) | |
| { | |
| } | |
| struct TGAHeader | |
| { | |
| uint8_t idSize; | |
| uint8_t mapType; | |
| uint8_t imageType; | |
| uint16_t paletteStart; | |
| uint16_t paletteSize; | |
| uint8_t paletteEntryDepth; | |
| uint16_t x; | |
| uint16_t y; | |
| uint16_t width; | |
| uint16_t height; | |
| uint8_t colorDepth; | |
| uint8_t descriptor; | |
| }; | |
| #define INVERTED_BIT (1 << 5) | |
| template <typename dataType> | |
| void readBinary(std::ifstream &stream, dataType &item) | |
| { | |
| stream.read(reinterpret_cast<char *>(&item), sizeof(dataType)); | |
| } | |
| template <typename dataType> | |
| void readBinary(std::ifstream &stream, std::vector<dataType> &items) | |
| { | |
| stream.read(reinterpret_cast<char *>(items.data()), sizeof(dataType) * items.size()); | |
| } | |
| bool LoadTGAImageFromFile(const std::string &path, TGAImage *image) | |
| { | |
| std::ifstream stream(path, std::ios::binary); | |
| if (!stream) | |
| { | |
| std::cerr << "error opening tga file " << path << " for reading.\n"; | |
| return false; | |
| } | |
| TGAHeader header; | |
| readBinary(stream, header.idSize); | |
| readBinary(stream, header.mapType); | |
| readBinary(stream, header.imageType); | |
| readBinary(stream, header.paletteStart); | |
| readBinary(stream, header.paletteSize); | |
| readBinary(stream, header.paletteEntryDepth); | |
| readBinary(stream, header.x); | |
| readBinary(stream, header.y); | |
| readBinary(stream, header.width); | |
| readBinary(stream, header.height); | |
| readBinary(stream, header.colorDepth); | |
| readBinary(stream, header.descriptor); | |
| image->width = header.width; | |
| image->height = header.height; | |
| size_t pixelComponentCount = header.colorDepth / CHAR_BIT; | |
| std::vector<unsigned char> buffer(header.width * header.height * pixelComponentCount); | |
| readBinary(stream, buffer); | |
| image->data.reserve(header.width * header.height); | |
| for (size_t y = 0; y < header.height; y++) | |
| { | |
| size_t rowIdx = ((header.descriptor & INVERTED_BIT) ? (header.height - 1 - y) : y) * header.width * pixelComponentCount; | |
| for (size_t x = 0; x < header.width; x++) | |
| { | |
| size_t pixelIdx = rowIdx + x * pixelComponentCount; | |
| Byte4 pixel; | |
| pixel[0] = (pixelComponentCount > 2) ? buffer[pixelIdx + 2] : 0; | |
| pixel[2] = (pixelComponentCount > 0) ? buffer[pixelIdx + 0] : 0; | |
| pixel[1] = (pixelComponentCount > 1) ? buffer[pixelIdx + 1] : 0; | |
| pixel[3] = (pixelComponentCount > 3) ? buffer[pixelIdx + 3] : 255; | |
| image->data.push_back(pixel); | |
| } | |
| } | |
| std::cout << "loaded image " << path << ".\n"; | |
| return true; | |
| } | |
| GLuint LoadTextureFromTGAImage(const TGAImage &image) | |
| { | |
| if (image.width > 0 && image.height > 0) | |
| { | |
| GLuint texture; | |
| glGenTextures(1, &texture); | |
| glBindTexture(GL_TEXTURE_2D, texture); | |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); | |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
| glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, static_cast<GLsizei>(image.width), static_cast<GLsizei>(image.height), 0, | |
| GL_RGBA, GL_UNSIGNED_BYTE, image.data.data()); | |
| glGenerateMipmap(GL_TEXTURE_2D); | |
| return texture; | |
| } | |
| else | |
| { | |
| return 0; | |
| } | |
| } |