//
// Created by trotfunky on 24/09/2019.
//

#include "Texture.h"


Texture::Texture() : width(0), height(0), color_bits(0), image_data(nullptr), opengl_id{(uint32_t)-1}
{}

Texture::~Texture()
{
    if (opengl_id[0] != (uint32_t)-1)
    {
        delete(image_data);
        glDeleteTextures(1,opengl_id);
    }
}

bool Texture::load_tga(const std::string& filename, uint8_t*& data_array)
{
    std::fstream file_stream(filename,std::ios_base::in|std::ios_base::binary);
    if (file_stream.fail())
    {
        std::cerr << "Error while opening " <<  filename << std::endl;
        return false;
    }

    // Length of the image ID
    uint8_t id_length = 0;
    file_stream >> id_length;

    file_stream.seekg(1,std::ios_base::cur);
    uint8_t tga_data_type = 0;
    file_stream >> tga_data_type;

    // Only supported type : Raw RGB data
    if (tga_data_type != 2)
    {
        std::cerr << "Error loading file " << filename << ": Unsupported format " << tga_data_type << std::endl;
        file_stream.close();
        return false;
    }

    // Place the cursor to the position of the width header data
    file_stream.seekg(12,std::ios_base::beg);
    file_stream.read((char*)&width,2);
    file_stream.read((char*)&height,2);
    file_stream >> color_bits;

    if (color_bits != 24)
    {
        std::cerr << "Error loading file " << filename << ": Unsupported " << color_bits << " bits colors" << std::endl;
        file_stream.close();
        return false;
    }

    // Move cursor to the end to get file size
    file_stream.seekg(0,std::ios_base::end);
    // Size of the file minus header length minus ID length
    int data_length = width*height*(color_bits/8);

    // Move cursor to the start of the data.
    file_stream.seekg(18+id_length,std::ios_base::beg);

    data_array = new uint8_t[data_length];
    file_stream.read((char*)data_array,data_length);

    return true;
}

bool Texture::load_rgb_tga(const std::string& rgb_filename)
{
    bool return_value = load_tga(rgb_filename,image_data);
    invert_channels(0,2);
    return return_value;
}

bool Texture::load_rgba_tga(const std::string& rgb_filename, const std::string& mask_filename)
{
    uint8_t* rgb_data = nullptr;
    uint8_t* mask_data = nullptr;

    bool load_successful = true;
    // Load rgb and alpha data before merging them
    load_successful &= load_tga(rgb_filename, rgb_data);
    uint16_t temp_width = width;
    uint16_t temp_height = height;

    load_successful &= load_tga(mask_filename, mask_data);

    if (!load_successful)
    {
        std::cerr << "Error while loading RGBA image" << std::endl;
        return false;
    }
    if (temp_width != width || temp_height != height)
    {
        std::cerr << "Error while loading RGBA image : image and mask dimensions do no match : " << std::endl;
        std::cerr << temp_width << "x" << temp_height << " versus " << width << "x" << height << std::endl;
        return false;
    }


    image_data = new uint8_t[width*height*4];

    // Merge the two images
    for(int i = 0;i<height*width;i++)
    {
        for(int j = 0;j<3;j++)
        {
            image_data[i*4+j] = rgb_data[i*3+j];
        }
        image_data[i*4+3] = mask_data[i*3];
    }

    // Now we have an RGBA image, update color_bits
    color_bits = 32;

    return true;
}

void Texture::invert_channels(uint8_t first_channel, uint8_t second_channel)
{
    uint8_t increment = color_bits/8;
    for (int i = 0;i<width*height;i++)
    {
        uint8_t temp = image_data[i*increment+first_channel];
        image_data[i*increment+first_channel] = image_data[i*increment+second_channel];
        image_data[i*increment+second_channel] = temp;
    }
}
