godot/servers/visual/rasterizer.cpp
Rémi Verschelde d8223ffa75 Welcome in 2017, dear changelog reader!
That year should bring the long-awaited OpenGL ES 3.0 compatible renderer
with state-of-the-art rendering techniques tuned to work as low as middle
end handheld devices - without compromising with the possibilities given
for higher end desktop games of course. Great times ahead for the Godot
community and the gamers that will play our games!

(cherry picked from commit c7bc44d5ad)
2017-01-12 19:15:30 +01:00

642 lines
20 KiB
C++

/*************************************************************************/
/* 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<FixedMaterialShaderKey,FixedMaterialShader>::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<VS::FIXED_MATERIAL_PARAM_MAX;i++) {
if (p_key.texture_mask&(1<<i))
texcoords_used|=(1<<((p_key.texcoord_mask>>(i*2))&0x3));
}
if (texcoords_used&(1<<VS::FIXED_MATERIAL_TEXCOORD_UV_TRANSFORM)) {
code+="uniform mat4 fmp_uv_xform;\n";
code+="vec2 uv_xform = (fmp_uv_xform * vec4(UV,0,1)).xy;\n";
}
/* HANDLE NORMAL MAPPING */
if (p_key.texture_mask&(1<<VS::FIXED_MATERIAL_PARAM_NORMAL)) {
String scode;
scode+="uniform float fmp_normal;\n";
scode+="uniform texture fmp_normal_tex;\n";
String uv_str;
if (((p_key.texcoord_mask>>(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<<VS::FIXED_MATERIAL_TEXCOORD_SPHERE)) {
String tcode;
tcode="vec3 eye_normal = normalize(VERTEX);\n";
tcode+="vec3 ref = (eye_normal - 2.0*dot(NORMAL, eye_normal)*NORMAL);\n";
tcode+="ref.z+=1.0;\n";
tcode+="vec2 uv_sphere = ref.xy*vec2(0.5,0.0-0.5)+vec2(0.5,0.0-0.5);\n";
code+=tcode;
}
/* HANDLE DIFFUSE LIGHTING */
code+="uniform color fmp_diffuse;\n";
code+="color diffuse=fmp_diffuse;\n";
if (p_key.use_color_array)
code+="diffuse*=COLOR;\n";
if (p_key.texture_mask&(1<<VS::FIXED_MATERIAL_PARAM_DIFFUSE)) {
code+="uniform texture fmp_diffuse_tex;\n";
code+="diffuse*=tex( fmp_diffuse_tex,"+_TEXUVSTR(VS::FIXED_MATERIAL_PARAM_DIFFUSE)+");\n";
}
if (p_key.texture_mask&(1<<VS::FIXED_MATERIAL_PARAM_DETAIL)) {
String dcode;
dcode+="uniform texture fmp_detail_tex;\n";
dcode+="uniform float fmp_detail;\n";
dcode+="color detail=tex( fmp_detail_tex,"+_TEXUVSTR(VS::FIXED_MATERIAL_PARAM_DETAIL)+");\n";
//aways mix
dcode+="diffuse=vec4(mix(diffuse.rgb,detail.rgb,detail.a*fmp_detail),diffuse.a);\n";
code+=dcode;
}
if (p_key.use_alpha) {
code+="DIFFUSE_ALPHA=diffuse;\n";
if (p_key.discard_alpha) {
code+="DISCARD=diffuse.a<0.5;\n";
}
} else {
code+="DIFFUSE=diffuse.rgb;\n";
}
/* HANDLE SPECULAR LIGHTING */
code+="uniform color fmp_specular;\n";
code+="color specular=fmp_specular;\n";
if (p_key.texture_mask&(1<<VS::FIXED_MATERIAL_PARAM_SPECULAR)) {
String scode;
scode+="uniform texture fmp_specular_tex;\n";
scode+="specular*=tex( fmp_specular_tex,"+_TEXUVSTR(VS::FIXED_MATERIAL_PARAM_SPECULAR)+");\n";
code+=scode;
}
code+="SPECULAR=specular.rgb;\n";
code+="uniform float fmp_specular_exp;\n";
code+="float specular_exp=fmp_specular_exp;\n";
if (p_key.texture_mask&(1<<VS::FIXED_MATERIAL_PARAM_SPECULAR_EXP)) {
String scode;
scode+="uniform texture fmp_specular_exp_tex;\n";
scode+="specular_exp*=tex( fmp_specular_exp_tex,"+_TEXUVSTR(VS::FIXED_MATERIAL_PARAM_SPECULAR_EXP)+").r;\n";
code+=scode;
}
code+="SPEC_EXP=specular_exp;\n";
/* HANDLE EMISSION LIGHTING */
code+="uniform color fmp_emission;\n";
code+="color emission=fmp_emission;\n";
if (p_key.texture_mask&(1<<VS::FIXED_MATERIAL_PARAM_EMISSION)) {
String scode;
scode+="uniform texture fmp_emission_tex;\n";
scode+="emission*=tex( fmp_emission_tex,"+_TEXUVSTR(VS::FIXED_MATERIAL_PARAM_EMISSION)+");\n";
code+=scode;
}
code+="EMISSION=emission.rgb;\n";
/* HANDLE GLOW */
code+="uniform float fmp_glow;\n";
code+="float glow=fmp_glow;\n";
if (p_key.texture_mask&(1<<VS::FIXED_MATERIAL_PARAM_GLOW)) {
String scode;
scode+="uniform texture fmp_glow_tex;\n";
scode+="glow*=tex( fmp_glow_tex,"+_TEXUVSTR(VS::FIXED_MATERIAL_PARAM_GLOW)+").r;\n";
code+=scode;
}
code+="GLOW=glow;\n";
if (p_key.texture_mask&(1<<VS::FIXED_MATERIAL_PARAM_SHADE_PARAM)) {
String scode;
scode+="uniform texture fmp_shade_param_tex;\n";
scode+="SHADE_PARAM=tex( fmp_shade_param_tex,"+_TEXUVSTR(VS::FIXED_MATERIAL_PARAM_SHADE_PARAM)+").r;\n";
code+=scode;
} else {
String scode;
scode+="uniform float fmp_shade_param;\n";
scode+="SHADE_PARAM=fmp_shade_param;\n";
code+=scode;
}
//print_line("**FRAGMENT SHADER GENERATED code: \n"+code);
String vcode;
vcode="uniform float "+_fixed_material_param_names[VS::FIXED_MATERIAL_PARAM_SPECULAR_EXP]+";\n";
vcode+="SPEC_EXP="+_fixed_material_param_names[VS::FIXED_MATERIAL_PARAM_SPECULAR_EXP]+";\n";
if (p_key.use_pointsize) {
vcode+="uniform float "+_fixed_material_point_size_name+";\n";
vcode+="POINT_SIZE="+_fixed_material_point_size_name+";\n";
// vcode+="POINT_SIZE=10.0;\n";
}
String lcode;
switch(p_key.light_shader) {
case VS::FIXED_MATERIAL_LIGHT_SHADER_LAMBERT: {
//do nothing
} break;
case VS::FIXED_MATERIAL_LIGHT_SHADER_WRAP: {
lcode+="float NdotL = max(0.0,((dot( NORMAL, LIGHT_DIR )+SHADE_PARAM)/(1.0+SHADE_PARAM)));";
lcode+="vec3 half_vec = normalize(LIGHT_DIR + EYE_VEC);";
lcode+="float eye_light = max(dot(NORMAL, half_vec),0.0);";
lcode+="LIGHT = LIGHT_DIFFUSE * DIFFUSE * NdotL;";
lcode+="if (NdotL > 0.0) {";
lcode+="\tLIGHT+=LIGHT_SPECULAR * SPECULAR * pow( eye_light, SPECULAR_EXP );";
lcode+="};";
} break;
case VS::FIXED_MATERIAL_LIGHT_SHADER_VELVET: {
lcode+="float NdotL = max(0.0,dot( NORMAL, LIGHT_DIR ));";
lcode+="vec3 half_vec = normalize(LIGHT_DIR + EYE_VEC);";
lcode+="float eye_light = max(dot(NORMAL, half_vec),0.0);";
lcode+="LIGHT = LIGHT_DIFFUSE * DIFFUSE * NdotL;";
lcode+="float rim = (1.0-abs(dot(NORMAL,vec3(0,0,1))))*SHADE_PARAM;";
lcode+="LIGHT += LIGHT_DIFFUSE * DIFFUSE * rim;";
lcode+="if (NdotL > 0.0) {";
lcode+="\tLIGHT+=LIGHT_SPECULAR * SPECULAR * pow( eye_light, SPECULAR_EXP );";
lcode+="};";
} break;
case VS::FIXED_MATERIAL_LIGHT_SHADER_TOON: {
lcode+="float NdotL = dot( NORMAL, LIGHT_DIR );";
lcode+="vec3 light_ref = reflect( LIGHT_DIR, NORMAL );";
lcode+="float eye_light = clamp( dot( light_ref, vec3(0,0,0)-EYE_VEC), 0.0, 1.0 );";
lcode+="float NdotL_diffuse = smoothstep( max( SHADE_PARAM-0.05, 0.0-1.0), min( SHADE_PARAM+0.05, 1.0), NdotL );";
lcode+="float spec_radius=clamp((1.0-(SPECULAR_EXP/64.0)),0.0,1.0);";
lcode+="float NdotL_specular = smoothstep( max( spec_radius-0.05, 0.0), min( spec_radius+0.05, 1.0), eye_light )*max(NdotL,0);";
lcode+="LIGHT = NdotL_diffuse * LIGHT_DIFFUSE*DIFFUSE + NdotL_specular * LIGHT_SPECULAR*SPECULAR;";
} break;
}
//print_line("**VERTEX SHADER GENERATED code: \n"+vcode);
double tf = (OS::get_singleton()->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<FixedMaterialShaderKey,FixedMaterialShader>::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<RID,FixedMaterial*>::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<RID,FixedMaterial*>::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<VS::FIXED_MATERIAL_PARAM_MAX;i++) {
material_set_param(mat,_fixed_material_param_names[i],fm.param[i]); //must be there
}
fixed_material_dirty_list.add(&fm.dirty_list);
//print_line("FMC: "+itos(mat.get_id()));
return mat;
}
void Rasterizer::fixed_material_set_parameter(RID p_material, VS::FixedMaterialParam p_parameter, const Variant& p_value){
Map<RID,FixedMaterial*>::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<RID,FixedMaterial*>::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<RID,FixedMaterial*>::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<RID,FixedMaterial*>::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<RID,FixedMaterial*>::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<RID,FixedMaterial*>::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<RID,FixedMaterial*>::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<RID,FixedMaterial*>::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<RID,FixedMaterial*>::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<RID,FixedMaterial*>::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<RID,FixedMaterial*>::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<RID,FixedMaterial*>::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<RID,FixedMaterial*>::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<VS::FIXED_MATERIAL_PARAM_MAX;i++) {
_fixed_material_param_names[i]=String("fmp_")+fm_names[i];
_fixed_material_tex_names[i]=String("fmp_")+fm_names[i]+"_tex";
}
_fixed_material_uv_xform_name="fmp_uv_xform";
_fixed_material_point_size_name="fmp_point_size";
draw_viewport_func=NULL;
ERR_FAIL_COND( sizeof(FixedMaterialShaderKey)!=4);
}
RID Rasterizer::create_overdraw_debug_material() {
RID mat = fixed_material_create();
fixed_material_set_parameter( mat,VisualServer::FIXED_MATERIAL_PARAM_SPECULAR,Color(0,0,0) );
fixed_material_set_parameter( mat,VisualServer::FIXED_MATERIAL_PARAM_DIFFUSE,Color(0.1,0.1,0.2) );
fixed_material_set_parameter( mat,VisualServer::FIXED_MATERIAL_PARAM_EMISSION,Color(0,0,0) );
fixed_material_set_flag( mat, VS::FIXED_MATERIAL_FLAG_USE_ALPHA, true);
material_set_flag( mat, VisualServer::MATERIAL_FLAG_UNSHADED, true );
material_set_blend_mode( mat,VisualServer::MATERIAL_BLEND_MODE_ADD );
return mat;
}