/* * Copyright (C) 2021 Christopher J. Howard * * This file is part of Antkeeper source code. * * Antkeeper source code is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Antkeeper source code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Antkeeper source code. If not, see . */ #include "renderer/material.hpp" #include "resource-loader.hpp" #include "resource-manager.hpp" #include "gl/shader-variable-type.hpp" #include "gl/texture-wrapping.hpp" #include "gl/texture-filter.hpp" #include "gl/texture-2d.hpp" #include "utility/fundamental-types.hpp" #include "string-table.hpp" #include #include #include static bool load_bool_property(material* material, const string_table_row& row, int vector_size, int array_size) { if (row.size() - 4 != vector_size * array_size || vector_size < 1 || vector_size > 4) { return false; } std::size_t size = array_size * vector_size; bool* values = new bool[size]; for (std::size_t i = 0; i < size; ++i) { values[i] = (std::stoi(row[4 + i]) != 0); } if (vector_size == 1) { material_property* property = material->add_property(row[1], array_size); property->set_values(0, values, array_size); } else if (vector_size == 2) { material_property* property = material->add_property(row[1], array_size); property->set_values(0, reinterpret_cast(values), array_size); } else if (vector_size == 3) { material_property* property = material->add_property(row[1], array_size); property->set_values(0, reinterpret_cast(values), array_size); } else if (vector_size == 4) { material_property* property = material->add_property(row[1], array_size); property->set_values(0, reinterpret_cast(values), array_size); } delete[] values; return true; } static bool load_int_property(material* material, const string_table_row& row, int vector_size, int array_size) { if (row.size() - 4 != vector_size * array_size || vector_size < 1 || vector_size > 4) { return false; } std::size_t size = array_size * vector_size; int* values = new int[size]; for (std::size_t i = 0; i < size; ++i) { values[i] = std::stoi(row[4 + i]); } if (vector_size == 1) { material_property* property = material->add_property(row[1], array_size); property->set_values(0, values, array_size); } else if (vector_size == 2) { material_property* property = material->add_property(row[1], array_size); property->set_values(0, reinterpret_cast(values), array_size); } else if (vector_size == 3) { material_property* property = material->add_property(row[1], array_size); property->set_values(0, reinterpret_cast(values), array_size); } else if (vector_size == 4) { material_property* property = material->add_property(row[1], array_size); property->set_values(0, reinterpret_cast(values), array_size); } delete[] values; return true; } static bool load_uint_property(material* material, const string_table_row& row, int vector_size, int array_size) { if (row.size() - 4 != vector_size * array_size || vector_size < 1 || vector_size > 4) { return false; } std::size_t size = array_size * vector_size; unsigned int* values = new unsigned int[size]; for (std::size_t i = 0; i < size; ++i) { values[i] = static_cast(std::stoul(row[4 + i])); } if (vector_size == 1) { material_property* property = material->add_property(row[1], array_size); property->set_values(0, values, array_size); } else if (vector_size == 2) { material_property* property = material->add_property(row[1], array_size); property->set_values(0, reinterpret_cast(values), array_size); } else if (vector_size == 3) { material_property* property = material->add_property(row[1], array_size); property->set_values(0, reinterpret_cast(values), array_size); } else if (vector_size == 4) { material_property* property = material->add_property(row[1], array_size); property->set_values(0, reinterpret_cast(values), array_size); } delete[] values; return true; } static bool load_float_property(material* material, const string_table_row& row, int vector_size, int array_size) { if (row.size() - 4 != vector_size * array_size || vector_size < 1 || vector_size > 4) { return false; } std::size_t size = array_size * vector_size; float* values = new float[size]; for (std::size_t i = 0; i < size; ++i) { values[i] = static_cast(std::stod(row[4 + i])); } if (vector_size == 1) { material_property* property = material->add_property(row[1], array_size); property->set_values(0, values, array_size); } else if (vector_size == 2) { material_property* property = material->add_property(row[1], array_size); property->set_values(0, reinterpret_cast(values), array_size); } else if (vector_size == 3) { material_property* property = material->add_property(row[1], array_size); property->set_values(0, reinterpret_cast(values), array_size); } else if (vector_size == 4) { material_property* property = material->add_property(row[1], array_size); property->set_values(0, reinterpret_cast(values), array_size); } delete[] values; return true; } static bool load_float_matrix_property(material* material, const string_table_row& row, int matrix_columns, int matrix_rows, int array_size) { int matrix_size = matrix_columns * matrix_rows; if (row.size() - 4 != matrix_size * array_size) { return false; } std::size_t size = array_size * matrix_size; float* values = new float[size]; for (std::size_t i = 0; i < size; ++i) { values[i] = static_cast(std::stod(row[4 + i])); } if (matrix_size == 2*2) { material_property* property = material->add_property(row[1], array_size); property->set_values(0, reinterpret_cast(values), array_size); } else if (matrix_size == 3*3) { material_property* property = material->add_property(row[1], array_size); property->set_values(0, reinterpret_cast(values), array_size); } else if (matrix_size == 4*4) { material_property* property = material->add_property(row[1], array_size); property->set_values(0, reinterpret_cast(values), array_size); } delete[] values; return true; } static bool load_texture_2d_property(material* material, const string_table_row& row, resource_manager* resource_manager, int array_size) { if (row.size() - 4 != array_size * 1) { return false; } const gl::texture_2d** values = new const gl::texture_2d*[array_size]; for (std::size_t i = 0; i < array_size; ++i) { values[i] = resource_manager->load(row[4 + i]); } material_property* property = material->add_property(row[1], array_size); property->set_values(0, values, array_size); delete[] values; return true; } static bool load_texture_cube_property(material* material, const string_table_row& row, resource_manager* resource_manager, int array_size) { return false; } static bool load_material_property(material* material, const string_table_row& row, resource_manager* resource_manager) { // Ensure row has at least five columns if (row.size() < 5) { return false; } const std::string& name = row[1]; if (name.empty()) { return false; } const std::string& type = row[2]; if (type.empty()) { return false; } int vector_size = 1; if (std::isdigit(type.back())) { vector_size = std::stoi(type.substr(type.size() - 1, 1)); } int matrix_columns = 0; int matrix_rows = 0; if (type[type.size() - 2] == 'x' && std::isdigit(type[type.size() - 3]) && std::isdigit(type.back())) { matrix_columns = std::stoi(type.substr(type.size() - 3, 1)); matrix_rows = std::stoi(type.substr(type.size() - 1, 1)); } int array_size = std::stoi(row[3]); if (array_size <= 0) { return false; } if (type == "bool" || type == "bool2" || type == "bool3" || type == "bool4") { return load_bool_property(material, row, vector_size, array_size); } else if (type == "int" || type == "int2" || type == "int3" || type == "int4") { return load_int_property(material, row, vector_size, array_size); } else if (type == "uint" || type == "uint2" || type == "uint3" || type == "uint4") { return load_uint_property(material, row, vector_size, array_size); } else if (type == "float" || type == "float2" || type == "float3" || type == "float4") { return load_float_property(material, row, vector_size, array_size); } else if (type == "float2x2" || type == "float3x3" || type == "float4x4") { return load_float_matrix_property(material, row, matrix_columns, matrix_rows, array_size); } else if (type == "texture_2d") { return load_texture_2d_property(material, row, resource_manager, array_size); } else if (type == "texture_cube") { return load_texture_cube_property(material, row, resource_manager, array_size); } return false; } template <> material* resource_loader::load(resource_manager* resource_manager, PHYSFS_File* file) { // Load string table from input stream string_table* table = resource_loader::load(resource_manager, file); // Ensure table is not empty. if (!table || table->empty()) { delete table; return nullptr; } // Allocate material ::material* material = new ::material(); // Parse table rows for (const string_table_row& row: *table) { // Skip empty rows and comments if (row.empty() || row[0].empty() || row[0][0] == '#') { continue; } if (row[0] == "shader" && row.size() == 2) { gl::shader_program* program = resource_manager->load(row[1]); material->set_shader_program(program); } else if (row[0] == "flags" && row.size() == 2) { std::uint32_t flags = std::stoi(row[1]); material->set_flags(flags); } else if (row[0] == "property") { load_material_property(material, row, resource_manager); } } return material; }