/*************************************************************************/ /* rasterizer.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ /* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ /* "Software"), to deal in the Software without restriction, including */ /* without limitation the rights to use, copy, modify, merge, publish, */ /* distribute, sublicense, and/or sell copies of the Software, and to */ /* permit persons to whom the Software is furnished to do so, subject to */ /* the following conditions: */ /* */ /* The above copyright notice and this permission notice shall be */ /* included in all copies or substantial portions of the Software. */ /* */ /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "rasterizer.h" #include "print_string.h" #include "os/os.h" RID Rasterizer::create_default_material() { return material_create(); } /* Fixed MAterial SHADER API */ RID Rasterizer::_create_shader(const FixedMaterialShaderKey& p_key) { ERR_FAIL_COND_V(!p_key.valid,RID()); Map::Element *E=fixed_material_shaders.find(p_key); if (E) { E->get().refcount++; return E->get().shader; } uint64_t t = OS::get_singleton()->get_ticks_usec(); FixedMaterialShader fms; fms.refcount=1; fms.shader=shader_create(); //create shader code int texcoords_used=0; String code; static const char* _uv_str[4]={"UV","uv_xform","UV2","uv_sphere"}; #define _TEXUVSTR(m_idx) String( _uv_str[(p_key.texcoord_mask>>(m_idx*2))&0x3] ) if (p_key.use_pointsize) { code+="UV=POINT_COORD;\n"; } for(int i=0;i>(i*2))&0x3)); } if (texcoords_used&(1<>(VS::FIXED_MATERIAL_PARAM_NORMAL*2))&0x3)==VS::FIXED_MATERIAL_TEXCOORD_SPHERE) { uv_str="uv"; //sorry not supported } else { uv_str=_TEXUVSTR(VS::FIXED_MATERIAL_PARAM_NORMAL); } if (p_key.use_xy_normalmap) { scode+="vec2 ywnormal=tex( fmp_normal_tex,"+uv_str+").wy * vec2(2.0,2.0) - vec2(1.0,1.0);\n"; scode+="NORMALMAP=vec3(ywnormal,sqrt(1 - (ywnormal.x * ywnormal.x) - (ywnormal.y * ywnormal.y) ));\n"; } else { scode+="NORMALMAP=tex( fmp_normal_tex,"+uv_str+").xyz * vec3(2.0,2.0,1.0) - vec3(1.0,1.0,0.0);\n"; } scode+="NORMALMAP_DEPTH=fmp_normal;\n"; code+=scode; } //handle sphere uv if used, do it here because it needs the normal, which may be transformed by a normal map if (texcoords_used&(1<get_ticks_usec()-t)/1000.0; // print_line("generate: "+rtos(tf)); shader_set_code(fms.shader,vcode,code,lcode,0,0); fixed_material_shaders[p_key]=fms; return fms.shader; } void Rasterizer::_free_shader(const FixedMaterialShaderKey& p_key) { if (p_key.valid==0) return; //not a valid key Map::Element *E=fixed_material_shaders.find(p_key); ERR_FAIL_COND(!E); E->get().refcount--; if (E->get().refcount==0) { free(E->get().shader); fixed_material_shaders.erase(E); } } void Rasterizer::fixed_material_set_flag(RID p_material, VS::FixedMaterialFlags p_flag, bool p_enabled) { Map::Element *E = fixed_materials.find(p_material); ERR_FAIL_COND(!E); FixedMaterial &fm=*E->get(); switch(p_flag) { case VS::FIXED_MATERIAL_FLAG_USE_ALPHA: fm.use_alpha=p_enabled; break; case VS::FIXED_MATERIAL_FLAG_USE_COLOR_ARRAY: fm.use_color_array=p_enabled; break; case VS::FIXED_MATERIAL_FLAG_USE_POINT_SIZE: fm.use_pointsize=p_enabled; break; case VS::FIXED_MATERIAL_FLAG_DISCARD_ALPHA: fm.discard_alpha=p_enabled; break; case VS::FIXED_MATERIAL_FLAG_USE_XY_NORMALMAP: fm.use_xy_normalmap=p_enabled; break; } if (!fm.dirty_list.in_list()) fixed_material_dirty_list.add( &fm.dirty_list ); } bool Rasterizer::fixed_material_get_flag(RID p_material, VS::FixedMaterialFlags p_flag) const{ const Map::Element *E = fixed_materials.find(p_material); ERR_FAIL_COND_V(!E,false); const FixedMaterial &fm=*E->get(); switch(p_flag) { case VS::FIXED_MATERIAL_FLAG_USE_ALPHA: return fm.use_alpha;; break; case VS::FIXED_MATERIAL_FLAG_USE_COLOR_ARRAY: return fm.use_color_array;; break; case VS::FIXED_MATERIAL_FLAG_USE_POINT_SIZE: return fm.use_pointsize;; break; case VS::FIXED_MATERIAL_FLAG_DISCARD_ALPHA: return fm.discard_alpha;; break; case VS::FIXED_MATERIAL_FLAG_USE_XY_NORMALMAP: return fm.use_xy_normalmap;; break; } return false; } RID Rasterizer::fixed_material_create() { RID mat = material_create(); fixed_materials[mat]=memnew( FixedMaterial() ); FixedMaterial &fm=*fixed_materials[mat]; fm.self=mat; fm.get_key(); material_set_flag(mat,VS::MATERIAL_FLAG_COLOR_ARRAY_SRGB,true); for(int i=0;i::Element *E = fixed_materials.find(p_material); ERR_FAIL_COND(!E); FixedMaterial &fm=*E->get(); RID material=E->key(); ERR_FAIL_INDEX(p_parameter,VS::FIXED_MATERIAL_PARAM_MAX); if ((p_parameter==VS::FIXED_MATERIAL_PARAM_DIFFUSE || p_parameter==VS::FIXED_MATERIAL_PARAM_SPECULAR || p_parameter==VS::FIXED_MATERIAL_PARAM_EMISSION)) { if (p_value.get_type()!=Variant::COLOR) { ERR_EXPLAIN(String(_fixed_material_param_names[p_parameter])+" expects Color"); ERR_FAIL(); } } else { if (!p_value.is_num()) { ERR_EXPLAIN(String(_fixed_material_param_names[p_parameter])+" expects scalar"); ERR_FAIL(); } } fm.param[p_parameter]=p_value; VS::get_singleton()->material_set_param(material,_fixed_material_param_names[p_parameter],p_value); } Variant Rasterizer::fixed_material_get_parameter(RID p_material,VS::FixedMaterialParam p_parameter) const{ const Map::Element *E = fixed_materials.find(p_material); ERR_FAIL_COND_V(!E,Variant()); const FixedMaterial &fm=*E->get(); ERR_FAIL_INDEX_V(p_parameter,VS::FIXED_MATERIAL_PARAM_MAX,Variant()); return fm.param[p_parameter]; } void Rasterizer::fixed_material_set_texture(RID p_material,VS::FixedMaterialParam p_parameter, RID p_texture){ Map::Element *E = fixed_materials.find(p_material); if (!E) { print_line("Not found: "+itos(p_material.get_id())); } ERR_FAIL_COND(!E); FixedMaterial &fm=*E->get(); ERR_FAIL_INDEX(p_parameter,VS::FIXED_MATERIAL_PARAM_MAX); RID material=E->key(); fm.texture[p_parameter]=p_texture; VS::get_singleton()->material_set_param(material,_fixed_material_tex_names[p_parameter],p_texture); if (!fm.dirty_list.in_list()) fixed_material_dirty_list.add( &fm.dirty_list ); } RID Rasterizer::fixed_material_get_texture(RID p_material,VS::FixedMaterialParam p_parameter) const{ const Map::Element *E = fixed_materials.find(p_material); ERR_FAIL_COND_V(!E,RID()); const FixedMaterial &fm=*E->get(); ERR_FAIL_INDEX_V(p_parameter,VS::FIXED_MATERIAL_PARAM_MAX,RID()); return fm.texture[p_parameter]; } void Rasterizer::fixed_material_set_texcoord_mode(RID p_material,VS::FixedMaterialParam p_parameter, VS::FixedMaterialTexCoordMode p_mode) { Map::Element *E = fixed_materials.find(p_material); ERR_FAIL_COND(!E); FixedMaterial &fm=*E->get(); ERR_FAIL_INDEX(p_parameter,VS::FIXED_MATERIAL_PARAM_MAX); fm.get_key(); fm.texture_tc[p_parameter]=p_mode; if (!fm.dirty_list.in_list()) fixed_material_dirty_list.add( &fm.dirty_list ); } VS::FixedMaterialTexCoordMode Rasterizer::fixed_material_get_texcoord_mode(RID p_material,VS::FixedMaterialParam p_parameter) const { const Map::Element *E = fixed_materials.find(p_material); ERR_FAIL_COND_V(!E,VS::FIXED_MATERIAL_TEXCOORD_UV); const FixedMaterial &fm=*E->get(); ERR_FAIL_INDEX_V(p_parameter,VS::FIXED_MATERIAL_PARAM_MAX,VS::FIXED_MATERIAL_TEXCOORD_UV); return fm.texture_tc[p_parameter]; } void Rasterizer::fixed_material_set_uv_transform(RID p_material,const Transform& p_transform) { Map::Element *E = fixed_materials.find(p_material); ERR_FAIL_COND(!E); FixedMaterial &fm=*E->get(); RID material=E->key(); VS::get_singleton()->material_set_param(material,_fixed_material_uv_xform_name,p_transform); fm.uv_xform=p_transform; } Transform Rasterizer::fixed_material_get_uv_transform(RID p_material) const { const Map::Element *E = fixed_materials.find(p_material); ERR_FAIL_COND_V(!E,Transform()); const FixedMaterial &fm=*E->get(); return fm.uv_xform; } void Rasterizer::fixed_material_set_light_shader(RID p_material,VS::FixedMaterialLightShader p_shader) { Map::Element *E = fixed_materials.find(p_material); ERR_FAIL_COND(!E); FixedMaterial &fm=*E->get(); fm.light_shader=p_shader; if (!fm.dirty_list.in_list()) fixed_material_dirty_list.add( &fm.dirty_list ); } VS::FixedMaterialLightShader Rasterizer::fixed_material_get_light_shader(RID p_material) const { const Map::Element *E = fixed_materials.find(p_material); ERR_FAIL_COND_V(!E,VS::FIXED_MATERIAL_LIGHT_SHADER_LAMBERT); const FixedMaterial &fm=*E->get(); return fm.light_shader; } void Rasterizer::fixed_material_set_point_size(RID p_material,float p_size) { Map::Element *E = fixed_materials.find(p_material); ERR_FAIL_COND(!E); FixedMaterial &fm=*E->get(); RID material=E->key(); VS::get_singleton()->material_set_param(material,_fixed_material_point_size_name,p_size); fm.point_size=p_size; } float Rasterizer::fixed_material_get_point_size(RID p_material) const{ const Map::Element *E = fixed_materials.find(p_material); ERR_FAIL_COND_V(!E,1.0); const FixedMaterial &fm=*E->get(); return fm.point_size; } void Rasterizer::_update_fixed_materials() { while(fixed_material_dirty_list.first()) { FixedMaterial &fm=*fixed_material_dirty_list.first()->self(); FixedMaterialShaderKey new_key = fm.get_key(); if (new_key.key!=fm.current_key.key) { _free_shader(fm.current_key); RID new_rid = _create_shader(new_key); fm.current_key=new_key; material_set_shader(fm.self,new_rid); if (fm.texture[VS::FIXED_MATERIAL_PARAM_DETAIL].is_valid()) { //send these again just in case. material_set_param(fm.self,_fixed_material_param_names[VS::FIXED_MATERIAL_PARAM_DETAIL],fm.param[VS::FIXED_MATERIAL_PARAM_DETAIL]); } if (fm.texture[VS::FIXED_MATERIAL_PARAM_NORMAL].is_valid()) { //send these again just in case. material_set_param(fm.self,_fixed_material_param_names[VS::FIXED_MATERIAL_PARAM_NORMAL],fm.param[VS::FIXED_MATERIAL_PARAM_NORMAL]); } material_set_param(fm.self,_fixed_material_uv_xform_name,fm.uv_xform); if (fm.use_pointsize) { material_set_param(fm.self,_fixed_material_point_size_name,fm.point_size); } } fixed_material_dirty_list.remove(fixed_material_dirty_list.first()); } } void Rasterizer::_free_fixed_material(const RID& p_material) { Map::Element *E = fixed_materials.find(p_material); if (E) { _free_shader(E->get()->current_key); //free shader if (E->get()->dirty_list.in_list()) fixed_material_dirty_list.remove( &E->get()->dirty_list); memdelete(E->get()); fixed_materials.erase(E); //free material } } void Rasterizer::flush_frame() { //not really necesary to implement } Rasterizer::Rasterizer() { static const char* fm_names[VS::FIXED_MATERIAL_PARAM_MAX]={ "diffuse", "detail", "specular", "emission", "specular_exp", "glow", "normal", "shade_param"}; for(int i=0;i