/* model/material.cc This file is part of the Osirion project and is distributed under the terms of the GNU General Public License version 2 */ #include #include "auxiliary/functions.h" #include "filesystem/filestream.h" #include "math/functions.h" #include "model/material.h" #include "sys/sys.h" namespace model { Material::LoaderFuncPtr Material::material_loaderfunc = 0; Material::Registry Material::material_registry; Material::Material(const std::string &name) : material_name(name), material_color(1.0f) , material_specular(1.0f) , material_size(64.0f, 64.0f) { aux::to_lowercase(material_name); material_flags = 0; material_colortype = ColorMaterial; material_texture_id = 0; } Material::~Material() { } void Material::print() { con_print << name() << std::endl; con_print << " material color: " << material_color.r << " " << material_color.g << " " << material_color.b << " " << material_color.a << std::endl; switch (colortype()) { case ColorMaterial: break; case ColorPrimary: con_print << " color type " << "entity primary" << std::endl; break; case ColorSecondary: con_print << " color type " << "entity secondary" << std::endl; break; case ColorTertiary: con_print << " color type " << "entity tertiary" << std::endl; break; case ColorEngine: con_print << " color type " << "entity engine" << std::endl; break; } con_print << " flags: " << flags() << " "; if (flags() == FlagNone) { con_print << "none"; } else { if (flags() & FlagBright) { con_print << "bright "; } if (flags() & FlagEnvironment) { con_print << "environment "; } if (flags() & FlagTexture) { con_print << "texture "; } if (flags() & FlagIgnore) { con_print << "ignore "; } if (flags() & FlagClip) { con_print << "clip "; } if (flags() & FlagOrigin) { con_print << "origin "; } if (flags() & FlagDecal) { con_print << "decal "; } if (flags() & FlagBounds) { con_print << "bounds "; } } con_print << std::endl; if (material_texture.size()) { con_print << " texture: " << material_texture << std::endl; } } void Material::set_color(const math::Color &color) { material_color.assign(color); //material_color.a = 1.0f; } void Material::set_specular(const math::Color &color) { material_specular.assign(color); } void Material::set_texture(const std::string &texture) { if (texture.size()) { set_flags(FlagTexture); material_texture.assign(texture); if (material_loaderfunc) { material_loaderfunc(this); } } else { unset_flags(FlagTexture); material_texture.clear(); material_texture_id = 0; } } void Material::set_texture_id(const size_t texture_id) { material_texture_id = texture_id; } void Material::set_size(const float width, const float height) { material_size.assign(width, height); } void Material::set_size(const math::Vector2f &size) { material_size.assign(size); } void Material::set_colortype(ColorType colortype) { material_colortype = colortype; } /* ---- static ----------------------------------------------------- */ void Material::init() { con_print << "^BInitializing materials..." << std::endl; filesystem::IFileStream shaderlistfile("materials/shaderlist.txt"); if (!shaderlistfile.is_open()) { con_warn << "Could not open " << shaderlistfile.name() << std::endl; return; } con_debug << " " << shaderlistfile.name() << std::endl; char line[1024]; while (shaderlistfile.getline(line, 1023)) { if ((line[0] == 0) || (line[0] == '#') || (line[0] == ';')) { continue; if ((line[0] == '/') && (line[1] == '/')) continue; } else { std::string s(line); aux::trim(s); load_shaderfile(s); } } shaderlistfile.close(); } void Material::clear() { con_print << "^BClearing materials..." << std::endl; for (Registry::iterator i = material_registry.begin(); i != material_registry.end(); ++i) { delete(*i).second; } material_registry.clear(); } void Material::shutdown() { clear(); } void Material::add(Material *material) { if (!find(material->name())) { material_registry[material->name()] = material; } } void Material::load_shaderfile(const std::string &shadername) { std::string shaderfilename("materials/"); shaderfilename.append(shadername); shaderfilename.append(".shader"); filesystem::IFileStream shaderfile(shaderfilename); if (!shaderfile.is_open()) { con_warn << "Could not open " << shaderfile.name() << std::endl; return; } int parselevel = 0; unsigned int linenumber = 0; char line[1024]; unsigned int count = 0; float r, g, b, a; Material *material = 0; while (shaderfile.getline(line, 1023)) { linenumber++; // read materials std::string s(line); aux::trim(s); // skip empty lines if (!s.size()) continue; // skip comments if ((s[0] == '#') || (s[0] == ';') || ((s[0] == '/') && (s[1] == '/'))) continue; std::istringstream linestream(s); std::string firstword; if (linestream >> firstword) { if (firstword.compare("//") == 0) { continue; } else if (firstword.compare("}") == 0) { parselevel--; } else if (firstword.compare("{") == 0) { parselevel++; } else if ((firstword.size()) && (parselevel == 0)) { material = find(firstword); if (material) { con_warn << "Duplicate material '" << firstword << "'" << std::endl; } else { material = new Material(firstword); add(material); count++; //con_debug << " " << firstword << std::endl; } } else if ((parselevel == 1) && (material)) { aux::to_lowercase(firstword); if (firstword.compare("color") == 0) { if (linestream >> r >> g >> b) { if (math::max(r, math::max(g, b)) > 1.0f) { r /= 255.0f; g /= 255.0f; b /= 255.0f; } if (!(linestream >> a)) { a = 1.0f; } material->set_color(math::Color(r, g, b, a)); // set specular too, preserving the old behavior material->set_specular(math::Color(r, g, b, a)); } } else if (firstword.compare("specular") == 0) { if (linestream >> r >> g >> b) { if (math::max(r, math::max(g, b)) > 1.0f) { r /= 255.0f; g /= 255.0f; b /= 255.0f; } if (!(linestream >> a)) { a = 1.0f; } material->set_specular(math::Color(r, g, b, a)); } } else if (firstword.compare("engine") == 0) { material->set_colortype(ColorEngine); } else if (firstword.compare("entity") == 0) { material->set_colortype(ColorPrimary); } else if (firstword.compare("entitysecond") == 0) { material->set_colortype(ColorSecondary); } else if (firstword.compare("entitythird") == 0) { material->set_colortype(ColorTertiary); } else if (firstword.compare("bright") == 0) { material->set_flags(FlagBright); } else if (firstword.compare("environment") == 0) { material->set_flags(FlagEnvironment); } else if (firstword.compare("ignore") == 0) { material->set_flags(FlagIgnore); } else if (firstword.compare("clip") == 0) { material->set_flags(FlagClip); } else if (firstword.compare("origin") == 0) { material->set_flags(FlagOrigin); } else if (firstword.compare("decal") == 0) { material->set_flags(FlagDecal); } else if (firstword.compare("bounds") == 0) { material->set_flags(FlagBounds); } else if (firstword.compare("qer_editorimage") == 0) { // keyword qer_editorimage is ignored continue; } else if (firstword.compare("qer_trans") == 0) { // keyword qer_trans is ignored continue; } else if (firstword.compare("surfaceparm") == 0) { // keyword surfaceparm is ignored continue; } else if (firstword.compare("texture") == 0) { // texture name should not contain spaces if (linestream >> firstword) { // remove extension if (firstword[firstword.size()-4] == '.') { firstword.erase(firstword.size() - 4); } material->set_texture(firstword); } else { con_warn << shaderfile.name() << " texture key without filename at line " << linenumber << std::endl; } } else { con_warn << shaderfile.name() << " unknown key '" << firstword << "' at line " << linenumber << std::endl; } } } } con_debug << " " << shaderfile.name() << " " << count << " materials " << std::endl; shaderfile.close(); } void Material::list() { for (Registry::iterator i = material_registry.begin(); i != material_registry.end(); ++i) { con_print << " " << (*i).second->name() << std::endl; } con_print << material_registry.size() << " registered materials" << std::endl; } Material *Material::find(const std::string &name) { for (Registry::iterator i = material_registry.begin(); i != material_registry.end(); ++i) { if ((*i).first.compare(name) == 0) return (*i).second; } return 0; } void Material::set_loader_func(LoaderFuncPtr func) { material_loaderfunc = func; } }