2D Shaders are working again using the new syntax, though all is buggy in general
This commit is contained in:
parent
850eaf7ed7
commit
1527cf8c0d
26 changed files with 1980 additions and 173 deletions
|
@ -49,7 +49,8 @@
|
|||
enum ErrorHandlerType {
|
||||
ERR_HANDLER_ERROR,
|
||||
ERR_HANDLER_WARNING,
|
||||
ERR_HANDLER_SCRIPT
|
||||
ERR_HANDLER_SCRIPT,
|
||||
ERR_HANDLER_SHADER,
|
||||
};
|
||||
|
||||
typedef void (*ErrorHandlerFunc)(void*,const char*,const char*,int p_line,const char *, const char *,ErrorHandlerType p_type);
|
||||
|
|
|
@ -68,6 +68,7 @@ void OS::print_error(const char* p_function,const char* p_file,int p_line,const
|
|||
case ERR_ERROR: err_type="**ERROR**"; break;
|
||||
case ERR_WARNING: err_type="**WARNING**"; break;
|
||||
case ERR_SCRIPT: err_type="**SCRIPT ERROR**"; break;
|
||||
case ERR_SHADER: err_type="**SHADER ERROR**"; break;
|
||||
}
|
||||
|
||||
if (p_rationale && *p_rationale)
|
||||
|
|
|
@ -120,7 +120,8 @@ public:
|
|||
enum ErrorType {
|
||||
ERR_ERROR,
|
||||
ERR_WARNING,
|
||||
ERR_SCRIPT
|
||||
ERR_SCRIPT,
|
||||
ERR_SHADER
|
||||
};
|
||||
|
||||
virtual void print_error(const char* p_function,const char* p_file,int p_line,const char *p_code,const char*p_rationale,ErrorType p_type=ERR_ERROR);
|
||||
|
|
|
@ -34,6 +34,9 @@ struct Pair {
|
|||
|
||||
F first;
|
||||
S second;
|
||||
|
||||
Pair() {}
|
||||
Pair( F p_first, S p_second) { first=p_first; second=p_second; }
|
||||
};
|
||||
|
||||
#endif // PAIR_H
|
||||
|
|
|
@ -138,6 +138,7 @@ void RasterizerCanvasGLES3::canvas_begin(){
|
|||
state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_DISTANCE_FIELD,false);
|
||||
|
||||
|
||||
state.canvas_shader.set_custom_shader(0);
|
||||
state.canvas_shader.bind();
|
||||
state.canvas_shader.set_uniform(CanvasShaderGLES3::FINAL_MODULATE,Color(1,1,1,1));
|
||||
state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX,Matrix32());
|
||||
|
@ -520,6 +521,8 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item,Item *curr
|
|||
//err..
|
||||
}
|
||||
|
||||
state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE,texpixel_size);
|
||||
|
||||
|
||||
glVertexAttrib4f(1,rect->rect.pos.x,rect->rect.pos.y,rect->rect.size.x,rect->rect.size.y);
|
||||
glVertexAttrib4f(2,src_rect.pos.x,src_rect.pos.y,src_rect.size.x,src_rect.size.y);
|
||||
|
@ -567,6 +570,8 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item,Item *curr
|
|||
|
||||
Size2 texpixel_size( 1.0/texture->width, 1.0/texture->height );
|
||||
|
||||
state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE,texpixel_size);
|
||||
|
||||
#define DSTRECT(m_x,m_y,m_w,m_h) glVertexAttrib4f(1,m_x,m_y,m_w,m_h)
|
||||
#define SRCRECT(m_x,m_y,m_w,m_h) glVertexAttrib4f(2,(m_x)*texpixel_size.x,(m_y)*texpixel_size.y,(m_w)*texpixel_size.x,(m_h)*texpixel_size.y)
|
||||
|
||||
|
@ -634,8 +639,13 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item,Item *curr
|
|||
|
||||
ERR_CONTINUE( primitive->points.size()<1);
|
||||
|
||||
_bind_canvas_texture(primitive->texture);
|
||||
RasterizerStorageGLES3::Texture* texture = _bind_canvas_texture(primitive->texture);
|
||||
|
||||
if (texture ) {
|
||||
Size2 texpixel_size( 1.0/texture->width, 1.0/texture->height );
|
||||
state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE,texpixel_size);
|
||||
|
||||
}
|
||||
if (primitive->colors.size()==1 && primitive->points.size()>1) {
|
||||
|
||||
Color c = primitive->colors[0];
|
||||
|
@ -652,6 +662,14 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item,Item *curr
|
|||
|
||||
Item::CommandPolygon* polygon = static_cast<Item::CommandPolygon*>(c);
|
||||
_set_texture_rect_mode(false);
|
||||
|
||||
RasterizerStorageGLES3::Texture* texture = _bind_canvas_texture(polygon->texture);
|
||||
|
||||
if (texture ) {
|
||||
Size2 texpixel_size( 1.0/texture->width, 1.0/texture->height );
|
||||
state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE,texpixel_size);
|
||||
|
||||
}
|
||||
_draw_polygon(polygon->count,polygon->indices.ptr(),polygon->points.ptr(),polygon->uvs.ptr(),polygon->colors.ptr(),polygon->texture,polygon->colors.size()==1);
|
||||
|
||||
} break;
|
||||
|
@ -800,10 +818,14 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list,int p_z,const
|
|||
glBindTexture(GL_TEXTURE_2D,storage->resources.white_tex);
|
||||
|
||||
|
||||
int last_blend_mode=-1;
|
||||
|
||||
RID canvas_last_material;
|
||||
|
||||
bool prev_distance_field=false;
|
||||
|
||||
|
||||
|
||||
while(p_item_list) {
|
||||
|
||||
Item *ci=p_item_list;
|
||||
|
@ -878,53 +900,71 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list,int p_z,const
|
|||
RID material = material_owner->material;
|
||||
|
||||
if (material!=canvas_last_material || rebind_shader) {
|
||||
#if 0
|
||||
Shader *shader = NULL;
|
||||
if (material && material->shader.is_valid()) {
|
||||
shader = shader_owner.get(material->shader);
|
||||
if (shader && !shader->valid) {
|
||||
shader=NULL;
|
||||
|
||||
RasterizerStorageGLES3::Material *material_ptr = storage->material_owner.getornull(material);
|
||||
RasterizerStorageGLES3::Shader *shader_ptr = NULL;
|
||||
|
||||
if (material_ptr) {
|
||||
|
||||
shader_ptr = material_ptr->shader;
|
||||
|
||||
if (shader_ptr && shader_ptr->mode!=VS::SHADER_CANVAS_ITEM) {
|
||||
shader_ptr=NULL; //do not use non canvasitem shader
|
||||
}
|
||||
}
|
||||
|
||||
shader_cache=shader;
|
||||
|
||||
if (shader) {
|
||||
canvas_shader.set_custom_shader(shader->custom_code_id);
|
||||
_canvas_item_setup_shader_params(material,shader);
|
||||
} else {
|
||||
shader_cache=NULL;
|
||||
canvas_shader.set_custom_shader(0);
|
||||
canvas_shader.bind();
|
||||
uses_texpixel_size=false;
|
||||
if (shader_ptr && shader_ptr!=shader_cache) {
|
||||
|
||||
state.canvas_shader.set_custom_shader(shader_ptr->custom_code_id);
|
||||
state.canvas_shader.bind();
|
||||
|
||||
if (material_ptr->ubo_id) {
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER,2,material_ptr->ubo_id);
|
||||
}
|
||||
|
||||
int tc = material_ptr->textures.size();
|
||||
RID* textures = material_ptr->textures.ptr();
|
||||
|
||||
for(int i=0;i<tc;i++) {
|
||||
|
||||
glActiveTexture(GL_TEXTURE1+i);
|
||||
|
||||
RasterizerStorageGLES3::Texture *t = storage->texture_owner.getornull( textures[i] );
|
||||
if (!t) {
|
||||
//check hints
|
||||
glBindTexture(GL_TEXTURE_2D,storage->resources.white_tex);
|
||||
continue;
|
||||
}
|
||||
|
||||
glBindTexture(t->target,t->tex_id);
|
||||
}
|
||||
|
||||
|
||||
} else if (!shader_ptr) {
|
||||
state.canvas_shader.set_custom_shader(0);
|
||||
state.canvas_shader.bind();
|
||||
|
||||
}
|
||||
|
||||
shader_cache=shader_ptr;
|
||||
|
||||
canvas_shader.set_uniform(CanvasShaderGLES3::PROJECTION_MATRIX,canvas_transform);
|
||||
if (canvas_use_modulate)
|
||||
reset_modulate=true;
|
||||
canvas_last_material=material;
|
||||
rebind_shader=false;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
if (material.is_valid() && shader_cache) {
|
||||
#if 0
|
||||
_canvas_item_setup_shader_uniforms(material,shader_cache);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool unshaded = false; //(material && material->shading_mode==VS::CANVAS_ITEM_SHADING_UNSHADED) || ci->blend_mode!=VS::MATERIAL_BLEND_MODE_MIX;
|
||||
int blend_mode = shader_cache ? shader_cache->canvas_item.blend_mode : RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_MIX;
|
||||
bool unshaded = shader_cache && (shader_cache->canvas_item.light_mode==RasterizerStorageGLES3::Shader::CanvasItem::LIGHT_MODE_UNSHADED || blend_mode!=RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_MIX);
|
||||
bool reclip=false;
|
||||
#if 0
|
||||
if (ci==p_item_list || ci->blend_mode!=canvas_blend_mode) {
|
||||
|
||||
switch(ci->blend_mode) {
|
||||
if (last_blend_mode!=blend_mode) {
|
||||
|
||||
case VS::MATERIAL_BLEND_MODE_MIX: {
|
||||
switch(blend_mode) {
|
||||
|
||||
case RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_MIX: {
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
if (current_rt && current_rt_transparent) {
|
||||
if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) {
|
||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
else {
|
||||
|
@ -932,33 +972,30 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list,int p_z,const
|
|||
}
|
||||
|
||||
} break;
|
||||
case VS::MATERIAL_BLEND_MODE_ADD: {
|
||||
case RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_ADD: {
|
||||
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFunc(GL_SRC_ALPHA,GL_ONE);
|
||||
|
||||
} break;
|
||||
case VS::MATERIAL_BLEND_MODE_SUB: {
|
||||
case RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_SUB: {
|
||||
|
||||
glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
|
||||
glBlendFunc(GL_SRC_ALPHA,GL_ONE);
|
||||
} break;
|
||||
case VS::MATERIAL_BLEND_MODE_MUL: {
|
||||
case RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_MUL: {
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFunc(GL_DST_COLOR,GL_ZERO);
|
||||
} break;
|
||||
case VS::MATERIAL_BLEND_MODE_PREMULT_ALPHA: {
|
||||
case RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_PMALPHA: {
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFunc(GL_ONE,GL_ONE_MINUS_SRC_ALPHA);
|
||||
} break;
|
||||
|
||||
}
|
||||
|
||||
canvas_blend_mode=ci->blend_mode;
|
||||
last_blend_mode=blend_mode;
|
||||
}
|
||||
#endif
|
||||
|
||||
// canvas_shader.set_uniform(CanvasShaderGLES3::CANVAS_MODULATE,unshaded ? Color(1,1,1,1) : p_modulate);
|
||||
|
||||
state.canvas_item_modulate = unshaded ? ci->final_modulate : Color(
|
||||
ci->final_modulate.r * p_modulate.r,
|
||||
|
@ -974,10 +1011,10 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list,int p_z,const
|
|||
state.canvas_shader.set_uniform(CanvasShaderGLES3::EXTRA_MATRIX,state.extra_matrix);
|
||||
|
||||
|
||||
if (unshaded || (state.canvas_item_modulate.a>0.001 && (!material.is_valid() /*|| material->shading_mode!=VS::CANVAS_ITEM_SHADING_ONLY_LIGHT*/) && !ci->light_masked ))
|
||||
if (unshaded || (state.canvas_item_modulate.a>0.001 && (!shader_cache || shader_cache->canvas_item.light_mode!=RasterizerStorageGLES3::Shader::CanvasItem::LIGHT_MODE_LIGHT_ONLY) && !ci->light_masked ))
|
||||
_canvas_item_render_commands(ci,current_clip,reclip);
|
||||
|
||||
if (/*canvas_blend_mode==VS::MATERIAL_BLEND_MODE_MIX &&*/ p_light && !unshaded) {
|
||||
if ((blend_mode==RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_MIX || RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_PMALPHA) && p_light && !unshaded) {
|
||||
|
||||
Light *light = p_light;
|
||||
bool light_used=false;
|
||||
|
@ -1046,12 +1083,7 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list,int p_z,const
|
|||
bool light_rebind = state.canvas_shader.bind();
|
||||
|
||||
if (light_rebind) {
|
||||
#if 0
|
||||
if (material && shader_cache) {
|
||||
_canvas_item_setup_shader_params(material,shader_cache);
|
||||
_canvas_item_setup_shader_uniforms(material,shader_cache);
|
||||
}
|
||||
#endif
|
||||
|
||||
state.canvas_shader.set_uniform(CanvasShaderGLES3::FINAL_MODULATE,state.canvas_item_modulate);
|
||||
state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX,state.final_transform);
|
||||
state.canvas_shader.set_uniform(CanvasShaderGLES3::EXTRA_MATRIX,Matrix32());
|
||||
|
@ -1100,15 +1132,12 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list,int p_z,const
|
|||
state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF9,false);
|
||||
state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF13,false);
|
||||
|
||||
|
||||
state.canvas_shader.bind();
|
||||
#if 0
|
||||
if (material && shader_cache) {
|
||||
_canvas_item_setup_shader_params(material,shader_cache);
|
||||
_canvas_item_setup_shader_uniforms(material,shader_cache);
|
||||
}
|
||||
#endif
|
||||
|
||||
last_blend_mode=-1;
|
||||
|
||||
/*
|
||||
//this is set again, so it should not be needed anyway?
|
||||
state.canvas_item_modulate = unshaded ? ci->final_modulate : Color(
|
||||
ci->final_modulate.r * p_modulate.r,
|
||||
ci->final_modulate.g * p_modulate.g,
|
||||
|
@ -1120,7 +1149,6 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list,int p_z,const
|
|||
state.canvas_shader.set_uniform(CanvasShaderGLES3::EXTRA_MATRIX,Matrix32());
|
||||
state.canvas_shader.set_uniform(CanvasShaderGLES3::FINAL_MODULATE,state.canvas_item_modulate);
|
||||
|
||||
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
|
||||
if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) {
|
||||
|
@ -1130,6 +1158,7 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list,int p_z,const
|
|||
}
|
||||
|
||||
//@TODO RESET canvas_blend_mode
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
@ -1380,6 +1409,9 @@ void RasterizerCanvasGLES3::reset_canvas() {
|
|||
state.vp=canvas_transform;
|
||||
|
||||
store_transform(canvas_transform,state.canvas_item_ubo_data.projection_matrix);
|
||||
for(int i=0;i<4;i++) {
|
||||
state.canvas_item_ubo_data.time[i]=storage->frame.time[i];
|
||||
}
|
||||
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, state.canvas_item_ubo);
|
||||
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(CanvasItemUBO), &state.canvas_item_ubo_data);
|
||||
|
@ -1442,6 +1474,7 @@ void RasterizerCanvasGLES3::initialize() {
|
|||
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
||||
|
||||
state.canvas_shader.init();
|
||||
state.canvas_shader.set_base_material_tex_index(1);
|
||||
state.canvas_shadow_shader.init();
|
||||
|
||||
state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_RGBA_SHADOWS,storage->config.use_rgba_2d_shadows);
|
||||
|
|
|
@ -5,12 +5,14 @@
|
|||
#include "rasterizer_storage_gles3.h"
|
||||
#include "shaders/canvas_shadow.glsl.h"
|
||||
|
||||
|
||||
class RasterizerCanvasGLES3 : public RasterizerCanvas {
|
||||
public:
|
||||
|
||||
struct CanvasItemUBO {
|
||||
|
||||
float projection_matrix[16];
|
||||
float time[4];
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -115,8 +115,17 @@ void RasterizerGLES3::initialize() {
|
|||
|
||||
void RasterizerGLES3::begin_frame(){
|
||||
|
||||
double time_total = double(OS::get_singleton()->get_ticks_usec())/1000000.0;
|
||||
|
||||
storage->frame.time[0]=time_total;
|
||||
storage->frame.time[1]=Math::fmod(time_total,3600);
|
||||
storage->frame.time[2]=Math::fmod(time_total,900);
|
||||
storage->frame.time[3]=Math::fmod(time_total,60);
|
||||
|
||||
storage->update_dirty_shaders();
|
||||
storage->update_dirty_materials();
|
||||
}
|
||||
|
||||
void RasterizerGLES3::set_current_render_target(RID p_render_target){
|
||||
|
||||
if (!p_render_target.is_valid() && storage->frame.current_rt && storage->frame.clear_request) {
|
||||
|
@ -257,6 +266,7 @@ RasterizerGLES3::RasterizerGLES3()
|
|||
storage = memnew( RasterizerStorageGLES3 );
|
||||
canvas = memnew( RasterizerCanvasGLES3 );
|
||||
canvas->storage=storage;
|
||||
storage->canvas=canvas;
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "rasterizer_storage_gles3.h"
|
||||
#include "rasterizer_canvas_gles3.h"
|
||||
#include "globals.h"
|
||||
|
||||
/* TEXTURE API */
|
||||
|
@ -1000,65 +1001,906 @@ void RasterizerStorageGLES3::texture_set_shrink_all_x2_on_set_data(bool p_enable
|
|||
|
||||
RID RasterizerStorageGLES3::shader_create(VS::ShaderMode p_mode){
|
||||
|
||||
return RID();
|
||||
Shader *shader = memnew( Shader );
|
||||
shader->mode=p_mode;
|
||||
RID rid = shader_owner.make_rid(shader);
|
||||
shader_set_mode(rid,p_mode);
|
||||
_shader_make_dirty(shader);
|
||||
shader->self=rid;
|
||||
|
||||
return rid;
|
||||
}
|
||||
|
||||
void RasterizerStorageGLES3::_shader_make_dirty(Shader* p_shader) {
|
||||
|
||||
if (p_shader->dirty_list.in_list())
|
||||
return;
|
||||
|
||||
_shader_dirty_list.add(&p_shader->dirty_list);
|
||||
}
|
||||
|
||||
void RasterizerStorageGLES3::shader_set_mode(RID p_shader,VS::ShaderMode p_mode){
|
||||
|
||||
ERR_FAIL_INDEX(p_mode,VS::SHADER_MAX);
|
||||
Shader *shader=shader_owner.get(p_shader);
|
||||
ERR_FAIL_COND(!shader);
|
||||
|
||||
if (shader->custom_code_id && p_mode==shader->mode)
|
||||
return;
|
||||
|
||||
|
||||
if (shader->custom_code_id) {
|
||||
|
||||
shader->shader->free_custom_shader(shader->custom_code_id);
|
||||
shader->custom_code_id=0;
|
||||
}
|
||||
|
||||
shader->mode=p_mode;
|
||||
|
||||
ShaderGLES3* shaders[VS::SHADER_MAX]={
|
||||
&canvas->state.canvas_shader,
|
||||
&canvas->state.canvas_shader,
|
||||
&canvas->state.canvas_shader,
|
||||
|
||||
};
|
||||
|
||||
shader->shader=shaders[p_mode];
|
||||
|
||||
shader->custom_code_id = shader->shader->create_custom_shader();
|
||||
|
||||
_shader_make_dirty(shader);
|
||||
|
||||
}
|
||||
VS::ShaderMode RasterizerStorageGLES3::shader_get_mode(RID p_shader) const {
|
||||
|
||||
return VS::SHADER_SPATIAL;
|
||||
const Shader *shader=shader_owner.get(p_shader);
|
||||
ERR_FAIL_COND_V(!shader,VS::SHADER_MAX);
|
||||
|
||||
return shader->mode;
|
||||
}
|
||||
void RasterizerStorageGLES3::shader_set_code(RID p_shader, const String& p_code){
|
||||
|
||||
Shader *shader=shader_owner.get(p_shader);
|
||||
ERR_FAIL_COND(!shader);
|
||||
|
||||
shader->code=p_code;
|
||||
_shader_make_dirty(shader);
|
||||
}
|
||||
String RasterizerStorageGLES3::shader_get_code(RID p_shader) const{
|
||||
|
||||
return String();
|
||||
const Shader *shader=shader_owner.get(p_shader);
|
||||
ERR_FAIL_COND_V(!shader,String());
|
||||
|
||||
|
||||
return shader->code;
|
||||
}
|
||||
|
||||
void RasterizerStorageGLES3::_update_shader(Shader* p_shader) const {
|
||||
|
||||
|
||||
_shader_dirty_list.remove( &p_shader->dirty_list );
|
||||
|
||||
p_shader->valid=false;
|
||||
|
||||
p_shader->uniforms.clear();
|
||||
|
||||
ShaderCompilerGLES3::GeneratedCode gen_code;
|
||||
ShaderCompilerGLES3::IdentifierActions *actions=NULL;
|
||||
|
||||
|
||||
|
||||
switch(p_shader->mode) {
|
||||
case VS::SHADER_CANVAS_ITEM: {
|
||||
|
||||
p_shader->canvas_item.light_mode=Shader::CanvasItem::LIGHT_MODE_NORMAL;
|
||||
p_shader->canvas_item.blend_mode=Shader::CanvasItem::BLEND_MODE_MIX;
|
||||
|
||||
shaders.actions_canvas.render_mode_values["blend_add"]=Pair<int*,int>(&p_shader->canvas_item.blend_mode,Shader::CanvasItem::BLEND_MODE_ADD);
|
||||
shaders.actions_canvas.render_mode_values["blend_mix"]=Pair<int*,int>(&p_shader->canvas_item.blend_mode,Shader::CanvasItem::BLEND_MODE_MIX);
|
||||
shaders.actions_canvas.render_mode_values["blend_sub"]=Pair<int*,int>(&p_shader->canvas_item.blend_mode,Shader::CanvasItem::BLEND_MODE_SUB);
|
||||
shaders.actions_canvas.render_mode_values["blend_mul"]=Pair<int*,int>(&p_shader->canvas_item.blend_mode,Shader::CanvasItem::BLEND_MODE_MUL);
|
||||
shaders.actions_canvas.render_mode_values["blend_premul_alpha"]=Pair<int*,int>(&p_shader->canvas_item.blend_mode,Shader::CanvasItem::BLEND_MODE_PMALPHA);
|
||||
|
||||
shaders.actions_canvas.render_mode_values["unshaded"]=Pair<int*,int>(&p_shader->canvas_item.light_mode,Shader::CanvasItem::LIGHT_MODE_UNSHADED);
|
||||
shaders.actions_canvas.render_mode_values["light_only"]=Pair<int*,int>(&p_shader->canvas_item.light_mode,Shader::CanvasItem::LIGHT_MODE_LIGHT_ONLY);
|
||||
|
||||
actions=&shaders.actions_canvas;
|
||||
actions->uniforms=&p_shader->uniforms;
|
||||
|
||||
} break;
|
||||
}
|
||||
|
||||
|
||||
Error err = shaders.compiler.compile(p_shader->mode,p_shader->code,actions,p_shader->path,gen_code);
|
||||
|
||||
ERR_FAIL_COND(err!=OK);
|
||||
|
||||
p_shader->shader->set_custom_shader_code(p_shader->custom_code_id,gen_code.vertex,gen_code.vertex_global,gen_code.fragment,gen_code.light,gen_code.fragment_global,gen_code.uniforms,gen_code.texture_uniforms,gen_code.defines);
|
||||
|
||||
p_shader->ubo_size=gen_code.uniform_total_size;
|
||||
p_shader->ubo_offsets=gen_code.uniform_offsets;
|
||||
p_shader->texture_count=gen_code.texture_uniforms.size();
|
||||
|
||||
//all materials using this shader will have to be invalidated, unfortunately
|
||||
|
||||
for (SelfList<Material>* E = p_shader->materials.first();E;E=E->next() ) {
|
||||
|
||||
_material_make_dirty(E->self());
|
||||
}
|
||||
|
||||
p_shader->valid=true;
|
||||
p_shader->version++;
|
||||
|
||||
}
|
||||
|
||||
void RasterizerStorageGLES3::update_dirty_shaders() {
|
||||
|
||||
while( _shader_dirty_list.first() ) {
|
||||
_update_shader(_shader_dirty_list.first()->self() );
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerStorageGLES3::shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const{
|
||||
|
||||
Shader *shader=shader_owner.get(p_shader);
|
||||
ERR_FAIL_COND(!shader);
|
||||
|
||||
|
||||
if (shader->dirty_list.in_list())
|
||||
_update_shader(shader); // ok should be not anymore dirty
|
||||
|
||||
|
||||
Map<int,StringName> order;
|
||||
|
||||
|
||||
for(Map<StringName,ShaderLanguage::ShaderNode::Uniform>::Element *E=shader->uniforms.front();E;E=E->next()) {
|
||||
|
||||
|
||||
order[E->get().order]=E->key();
|
||||
}
|
||||
|
||||
|
||||
for(Map<int,StringName>::Element *E=order.front();E;E=E->next()) {
|
||||
|
||||
PropertyInfo pi;
|
||||
ShaderLanguage::ShaderNode::Uniform &u=shader->uniforms[E->get()];
|
||||
pi.name=E->get();
|
||||
switch(u.type) {
|
||||
case ShaderLanguage::TYPE_VOID: pi.type=Variant::NIL; break;
|
||||
case ShaderLanguage::TYPE_BOOL: pi.type=Variant::BOOL; break;
|
||||
case ShaderLanguage::TYPE_BVEC2: pi.type=Variant::INT; pi.hint=PROPERTY_HINT_FLAGS; pi.hint_string="x,y"; break;
|
||||
case ShaderLanguage::TYPE_BVEC3: pi.type=Variant::INT; pi.hint=PROPERTY_HINT_FLAGS; pi.hint_string="x,y,z"; break;
|
||||
case ShaderLanguage::TYPE_BVEC4: pi.type=Variant::INT; pi.hint=PROPERTY_HINT_FLAGS; pi.hint_string="x,y,z,w"; break;
|
||||
case ShaderLanguage::TYPE_UINT:
|
||||
case ShaderLanguage::TYPE_INT: {
|
||||
pi.type=Variant::INT;
|
||||
if (u.hint==ShaderLanguage::ShaderNode::Uniform::HINT_RANGE) {
|
||||
pi.hint=PROPERTY_HINT_RANGE;
|
||||
pi.hint_string=rtos(u.hint_range[0])+","+rtos(u.hint_range[1]);
|
||||
}
|
||||
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_IVEC2:
|
||||
case ShaderLanguage::TYPE_IVEC3:
|
||||
case ShaderLanguage::TYPE_IVEC4:
|
||||
case ShaderLanguage::TYPE_UVEC2:
|
||||
case ShaderLanguage::TYPE_UVEC3:
|
||||
case ShaderLanguage::TYPE_UVEC4: {
|
||||
|
||||
pi.type=Variant::INT_ARRAY;
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_FLOAT: {
|
||||
pi.type=Variant::REAL;
|
||||
if (u.hint==ShaderLanguage::ShaderNode::Uniform::HINT_RANGE) {
|
||||
pi.hint=PROPERTY_HINT_RANGE;
|
||||
pi.hint_string=rtos(u.hint_range[0])+","+rtos(u.hint_range[1])+","+rtos(u.hint_range[2]);
|
||||
}
|
||||
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_VEC2: pi.type=Variant::VECTOR2; break;
|
||||
case ShaderLanguage::TYPE_VEC3: pi.type=Variant::VECTOR3; break;
|
||||
case ShaderLanguage::TYPE_VEC4: {
|
||||
if (u.hint==ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) {
|
||||
pi.type=Variant::COLOR;
|
||||
} else {
|
||||
pi.type=Variant::PLANE;
|
||||
}
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_MAT2: pi.type=Variant::MATRIX32; break;
|
||||
case ShaderLanguage::TYPE_MAT3: pi.type=Variant::MATRIX3; break;
|
||||
case ShaderLanguage::TYPE_MAT4: pi.type=Variant::TRANSFORM; break;
|
||||
case ShaderLanguage::TYPE_SAMPLER2D:
|
||||
case ShaderLanguage::TYPE_ISAMPLER2D:
|
||||
case ShaderLanguage::TYPE_USAMPLER2D: {
|
||||
|
||||
pi.type=Variant::OBJECT;
|
||||
pi.hint=PROPERTY_HINT_RESOURCE_TYPE;
|
||||
pi.hint_string="Texture";
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_SAMPLERCUBE: {
|
||||
|
||||
pi.type=Variant::OBJECT;
|
||||
pi.hint=PROPERTY_HINT_RESOURCE_TYPE;
|
||||
pi.hint_string="CubeMap";
|
||||
} break;
|
||||
};
|
||||
|
||||
p_param_list->push_back(pi);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerStorageGLES3::shader_set_default_texture_param(RID p_shader, const StringName& p_name, RID p_texture){
|
||||
|
||||
Shader *shader=shader_owner.get(p_shader);
|
||||
ERR_FAIL_COND(!shader);
|
||||
ERR_FAIL_COND(p_texture.is_valid() && !texture_owner.owns(p_texture));
|
||||
|
||||
if (p_texture.is_valid())
|
||||
shader->default_textures[p_name]=p_texture;
|
||||
else
|
||||
shader->default_textures.erase(p_name);
|
||||
|
||||
_shader_make_dirty(shader);
|
||||
}
|
||||
RID RasterizerStorageGLES3::shader_get_default_texture_param(RID p_shader, const StringName& p_name) const{
|
||||
|
||||
return RID();
|
||||
const Shader *shader=shader_owner.get(p_shader);
|
||||
ERR_FAIL_COND_V(!shader,RID());
|
||||
|
||||
const Map<StringName,RID>::Element *E=shader->default_textures.find(p_name);
|
||||
if (!E)
|
||||
return RID();
|
||||
return E->get();
|
||||
}
|
||||
|
||||
|
||||
/* COMMON MATERIAL API */
|
||||
|
||||
void RasterizerStorageGLES3::_material_make_dirty(Material* p_material) const {
|
||||
|
||||
if (p_material->dirty_list.in_list())
|
||||
return;
|
||||
|
||||
_material_dirty_list.add(&p_material->dirty_list);
|
||||
}
|
||||
|
||||
RID RasterizerStorageGLES3::material_create(){
|
||||
|
||||
return RID();
|
||||
Material *material = memnew( Material );
|
||||
|
||||
return material_owner.make_rid(material);
|
||||
}
|
||||
|
||||
void RasterizerStorageGLES3::material_set_shader(RID p_shader_material, RID p_shader){
|
||||
void RasterizerStorageGLES3::material_set_shader(RID p_material, RID p_shader){
|
||||
|
||||
Material *material = material_owner.get( p_material );
|
||||
ERR_FAIL_COND(!material);
|
||||
|
||||
Shader *shader=shader_owner.getornull(p_shader);
|
||||
|
||||
if (material->shader) {
|
||||
//if shader, remove from previous shader material list
|
||||
material->shader->materials.remove( &material->list );
|
||||
}
|
||||
material->shader=shader;
|
||||
|
||||
if (shader) {
|
||||
shader->materials.add(&material->list);
|
||||
}
|
||||
|
||||
_material_make_dirty(material);
|
||||
|
||||
}
|
||||
RID RasterizerStorageGLES3::material_get_shader(RID p_shader_material) const{
|
||||
|
||||
RID RasterizerStorageGLES3::material_get_shader(RID p_material) const{
|
||||
|
||||
const Material *material = material_owner.get( p_material );
|
||||
ERR_FAIL_COND_V(!material,RID());
|
||||
|
||||
if (material->shader)
|
||||
return material->shader->self;
|
||||
|
||||
return RID();
|
||||
}
|
||||
|
||||
void RasterizerStorageGLES3::material_set_param(RID p_material, const StringName& p_param, const Variant& p_value){
|
||||
|
||||
Material *material = material_owner.get( p_material );
|
||||
ERR_FAIL_COND(!material);
|
||||
|
||||
if (p_value.get_type()==Variant::NIL)
|
||||
material->params.erase(p_param);
|
||||
else
|
||||
material->params[p_param]=p_value;
|
||||
|
||||
_material_make_dirty(material);
|
||||
|
||||
}
|
||||
Variant RasterizerStorageGLES3::material_get_param(RID p_material, const StringName& p_param) const{
|
||||
|
||||
const Material *material = material_owner.get( p_material );
|
||||
ERR_FAIL_COND_V(!material,RID());
|
||||
|
||||
if (material->params.has(p_param))
|
||||
return material->params[p_param];
|
||||
|
||||
return Variant();
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataType type, const Variant& value, uint8_t *data) {
|
||||
switch(type) {
|
||||
case ShaderLanguage::TYPE_BOOL: {
|
||||
|
||||
bool v = value;
|
||||
|
||||
GLuint *gui = (GLuint*)data;
|
||||
*gui = v ? GL_TRUE : GL_FALSE;
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_BVEC2: {
|
||||
|
||||
int v = value;
|
||||
GLuint *gui = (GLuint*)data;
|
||||
gui[0]=v&1 ? GL_TRUE : GL_FALSE;
|
||||
gui[1]=v&2 ? GL_TRUE : GL_FALSE;
|
||||
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_BVEC3: {
|
||||
|
||||
int v = value;
|
||||
GLuint *gui = (GLuint*)data;
|
||||
gui[0]=v&1 ? GL_TRUE : GL_FALSE;
|
||||
gui[1]=v&2 ? GL_TRUE : GL_FALSE;
|
||||
gui[2]=v&4 ? GL_TRUE : GL_FALSE;
|
||||
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_BVEC4: {
|
||||
|
||||
int v = value;
|
||||
GLuint *gui = (GLuint*)data;
|
||||
gui[0]=v&1 ? GL_TRUE : GL_FALSE;
|
||||
gui[1]=v&2 ? GL_TRUE : GL_FALSE;
|
||||
gui[2]=v&4 ? GL_TRUE : GL_FALSE;
|
||||
gui[3]=v&8 ? GL_TRUE : GL_FALSE;
|
||||
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_INT: {
|
||||
|
||||
int v = value;
|
||||
GLint *gui = (GLint*)data;
|
||||
gui[0]=v;
|
||||
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_IVEC2: {
|
||||
|
||||
DVector<int> iv = value;
|
||||
int s = iv.size();
|
||||
GLint *gui = (GLint*)data;
|
||||
|
||||
DVector<int>::Read r = iv.read();
|
||||
|
||||
for(int i=0;i<2;i++) {
|
||||
if (i<s)
|
||||
gui[i]=r[i];
|
||||
else
|
||||
gui[i]=0;
|
||||
|
||||
}
|
||||
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_IVEC3: {
|
||||
|
||||
DVector<int> iv = value;
|
||||
int s = iv.size();
|
||||
GLint *gui = (GLint*)data;
|
||||
|
||||
DVector<int>::Read r = iv.read();
|
||||
|
||||
for(int i=0;i<3;i++) {
|
||||
if (i<s)
|
||||
gui[i]=r[i];
|
||||
else
|
||||
gui[i]=0;
|
||||
|
||||
}
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_IVEC4: {
|
||||
|
||||
|
||||
DVector<int> iv = value;
|
||||
int s = iv.size();
|
||||
GLint *gui = (GLint*)data;
|
||||
|
||||
DVector<int>::Read r = iv.read();
|
||||
|
||||
for(int i=0;i<4;i++) {
|
||||
if (i<s)
|
||||
gui[i]=r[i];
|
||||
else
|
||||
gui[i]=0;
|
||||
|
||||
}
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_UINT: {
|
||||
|
||||
int v = value;
|
||||
GLuint *gui = (GLuint*)data;
|
||||
gui[0]=v;
|
||||
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_UVEC2: {
|
||||
|
||||
DVector<int> iv = value;
|
||||
int s = iv.size();
|
||||
GLuint *gui = (GLuint*)data;
|
||||
|
||||
DVector<int>::Read r = iv.read();
|
||||
|
||||
for(int i=0;i<2;i++) {
|
||||
if (i<s)
|
||||
gui[i]=r[i];
|
||||
else
|
||||
gui[i]=0;
|
||||
|
||||
}
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_UVEC3: {
|
||||
DVector<int> iv = value;
|
||||
int s = iv.size();
|
||||
GLuint *gui = (GLuint*)data;
|
||||
|
||||
DVector<int>::Read r = iv.read();
|
||||
|
||||
for(int i=0;i<3;i++) {
|
||||
if (i<s)
|
||||
gui[i]=r[i];
|
||||
else
|
||||
gui[i]=0;
|
||||
}
|
||||
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_UVEC4: {
|
||||
DVector<int> iv = value;
|
||||
int s = iv.size();
|
||||
GLuint *gui = (GLuint*)data;
|
||||
|
||||
DVector<int>::Read r = iv.read();
|
||||
|
||||
for(int i=0;i<4;i++) {
|
||||
if (i<s)
|
||||
gui[i]=r[i];
|
||||
else
|
||||
gui[i]=0;
|
||||
}
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_FLOAT: {
|
||||
float v = value;
|
||||
GLfloat *gui = (GLfloat*)data;
|
||||
gui[0]=v;
|
||||
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_VEC2: {
|
||||
Vector2 v = value;
|
||||
GLfloat *gui = (GLfloat*)data;
|
||||
gui[0]=v.x;
|
||||
gui[1]=v.y;
|
||||
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_VEC3: {
|
||||
Vector3 v = value;
|
||||
GLfloat *gui = (GLfloat*)data;
|
||||
gui[0]=v.x;
|
||||
gui[1]=v.y;
|
||||
gui[2]=v.z;
|
||||
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_VEC4: {
|
||||
|
||||
GLfloat *gui = (GLfloat*)data;
|
||||
|
||||
if (value.get_type()==Variant::COLOR) {
|
||||
Color v=value;
|
||||
|
||||
gui[0]=v.r;
|
||||
gui[1]=v.g;
|
||||
gui[3]=v.b;
|
||||
gui[4]=v.a;
|
||||
} else if (value.get_type()==Variant::RECT2) {
|
||||
Rect2 v=value;
|
||||
|
||||
gui[0]=v.pos.x;
|
||||
gui[1]=v.pos.y;
|
||||
gui[3]=v.size.x;
|
||||
gui[4]=v.size.y;
|
||||
} else if (value.get_type()==Variant::QUAT) {
|
||||
Quat v=value;
|
||||
|
||||
gui[0]=v.x;
|
||||
gui[1]=v.y;
|
||||
gui[3]=v.z;
|
||||
gui[4]=v.w;
|
||||
} else {
|
||||
Plane v=value;
|
||||
|
||||
gui[0]=v.normal.x;
|
||||
gui[1]=v.normal.y;
|
||||
gui[3]=v.normal.x;
|
||||
gui[4]=v.d;
|
||||
|
||||
}
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_MAT2: {
|
||||
Matrix32 v = value;
|
||||
GLfloat *gui = (GLfloat*)data;
|
||||
|
||||
gui[ 0]=v.elements[0][0];
|
||||
gui[ 1]=v.elements[0][1];
|
||||
gui[ 2]=v.elements[1][0];
|
||||
gui[ 3]=v.elements[1][1];
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_MAT3: {
|
||||
|
||||
|
||||
Matrix3 v = value;
|
||||
GLfloat *gui = (GLfloat*)data;
|
||||
|
||||
gui[ 0]=v.elements[0][0];
|
||||
gui[ 1]=v.elements[1][0];
|
||||
gui[ 2]=v.elements[2][0];
|
||||
gui[ 3]=0;
|
||||
gui[ 4]=v.elements[0][1];
|
||||
gui[ 5]=v.elements[1][1];
|
||||
gui[ 6]=v.elements[2][1];
|
||||
gui[ 7]=0;
|
||||
gui[ 8]=v.elements[0][2];
|
||||
gui[ 9]=v.elements[1][2];
|
||||
gui[10]=v.elements[2][2];
|
||||
gui[11]=0;
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_MAT4: {
|
||||
|
||||
Transform v = value;
|
||||
GLfloat *gui = (GLfloat*)data;
|
||||
|
||||
gui[ 0]=v.basis.elements[0][0];
|
||||
gui[ 1]=v.basis.elements[1][0];
|
||||
gui[ 2]=v.basis.elements[2][0];
|
||||
gui[ 3]=0;
|
||||
gui[ 4]=v.basis.elements[0][1];
|
||||
gui[ 5]=v.basis.elements[1][1];
|
||||
gui[ 6]=v.basis.elements[2][1];
|
||||
gui[ 7]=0;
|
||||
gui[ 8]=v.basis.elements[0][2];
|
||||
gui[ 9]=v.basis.elements[1][2];
|
||||
gui[10]=v.basis.elements[2][2];
|
||||
gui[11]=0;
|
||||
gui[12]=v.origin.x;
|
||||
gui[13]=v.origin.y;
|
||||
gui[14]=v.origin.z;
|
||||
gui[15]=1;
|
||||
} break;
|
||||
default: {}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ static void _fill_std140_ubo_value(ShaderLanguage::DataType type, const Vector<ShaderLanguage::ConstantNode::Value>& value, uint8_t *data) {
|
||||
|
||||
switch(type) {
|
||||
case ShaderLanguage::TYPE_BOOL: {
|
||||
|
||||
GLuint *gui = (GLuint*)data;
|
||||
*gui = value[0].boolean ? GL_TRUE : GL_FALSE;
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_BVEC2: {
|
||||
|
||||
GLuint *gui = (GLuint*)data;
|
||||
gui[0]=value[0].boolean ? GL_TRUE : GL_FALSE;
|
||||
gui[1]=value[1].boolean ? GL_TRUE : GL_FALSE;
|
||||
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_BVEC3: {
|
||||
|
||||
GLuint *gui = (GLuint*)data;
|
||||
gui[0]=value[0].boolean ? GL_TRUE : GL_FALSE;
|
||||
gui[1]=value[1].boolean ? GL_TRUE : GL_FALSE;
|
||||
gui[2]=value[2].boolean ? GL_TRUE : GL_FALSE;
|
||||
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_BVEC4: {
|
||||
|
||||
GLuint *gui = (GLuint*)data;
|
||||
gui[0]=value[0].boolean ? GL_TRUE : GL_FALSE;
|
||||
gui[1]=value[1].boolean ? GL_TRUE : GL_FALSE;
|
||||
gui[2]=value[2].boolean ? GL_TRUE : GL_FALSE;
|
||||
gui[3]=value[3].boolean ? GL_TRUE : GL_FALSE;
|
||||
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_INT: {
|
||||
|
||||
GLint *gui = (GLint*)data;
|
||||
gui[0]=value[0].sint;
|
||||
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_IVEC2: {
|
||||
|
||||
GLint *gui = (GLint*)data;
|
||||
|
||||
for(int i=0;i<2;i++) {
|
||||
gui[i]=value[i].sint;
|
||||
|
||||
}
|
||||
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_IVEC3: {
|
||||
|
||||
GLint *gui = (GLint*)data;
|
||||
|
||||
for(int i=0;i<3;i++) {
|
||||
gui[i]=value[i].sint;
|
||||
|
||||
}
|
||||
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_IVEC4: {
|
||||
|
||||
GLint *gui = (GLint*)data;
|
||||
|
||||
for(int i=0;i<4;i++) {
|
||||
gui[i]=value[i].sint;
|
||||
|
||||
}
|
||||
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_UINT: {
|
||||
|
||||
|
||||
GLuint *gui = (GLuint*)data;
|
||||
gui[0]=value[0].uint;
|
||||
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_UVEC2: {
|
||||
|
||||
GLint *gui = (GLint*)data;
|
||||
|
||||
for(int i=0;i<2;i++) {
|
||||
gui[i]=value[i].uint;
|
||||
}
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_UVEC3: {
|
||||
GLint *gui = (GLint*)data;
|
||||
|
||||
for(int i=0;i<3;i++) {
|
||||
gui[i]=value[i].uint;
|
||||
}
|
||||
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_UVEC4: {
|
||||
GLint *gui = (GLint*)data;
|
||||
|
||||
for(int i=0;i<4;i++) {
|
||||
gui[i]=value[i].uint;
|
||||
}
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_FLOAT: {
|
||||
|
||||
GLfloat *gui = (GLfloat*)data;
|
||||
gui[0]=value[0].real;
|
||||
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_VEC2: {
|
||||
|
||||
GLfloat *gui = (GLfloat*)data;
|
||||
|
||||
for(int i=0;i<2;i++) {
|
||||
gui[i]=value[i].real;
|
||||
}
|
||||
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_VEC3: {
|
||||
|
||||
GLfloat *gui = (GLfloat*)data;
|
||||
|
||||
for(int i=0;i<3;i++) {
|
||||
gui[i]=value[i].real;
|
||||
}
|
||||
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_VEC4: {
|
||||
|
||||
GLfloat *gui = (GLfloat*)data;
|
||||
|
||||
for(int i=0;i<4;i++) {
|
||||
gui[i]=value[i].real;
|
||||
}
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_MAT2: {
|
||||
GLfloat *gui = (GLfloat*)data;
|
||||
|
||||
for(int i=0;i<2;i++) {
|
||||
gui[i]=value[i].real;
|
||||
}
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_MAT3: {
|
||||
|
||||
|
||||
|
||||
GLfloat *gui = (GLfloat*)data;
|
||||
|
||||
gui[ 0]=value[0].real;
|
||||
gui[ 1]=value[1].real;
|
||||
gui[ 2]=value[2].real;
|
||||
gui[ 3]=0;
|
||||
gui[ 4]=value[3].real;
|
||||
gui[ 5]=value[4].real;
|
||||
gui[ 6]=value[5].real;
|
||||
gui[ 7]=0;
|
||||
gui[ 8]=value[6].real;
|
||||
gui[ 9]=value[7].real;
|
||||
gui[10]=value[8].real;
|
||||
gui[11]=0;
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_MAT4: {
|
||||
|
||||
GLfloat *gui = (GLfloat*)data;
|
||||
|
||||
for(int i=0;i<16;i++) {
|
||||
gui[i]=value[i].real;
|
||||
}
|
||||
} break;
|
||||
default: {}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
_FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type, uint8_t *data) {
|
||||
|
||||
switch(type) {
|
||||
|
||||
case ShaderLanguage::TYPE_BOOL:
|
||||
case ShaderLanguage::TYPE_INT:
|
||||
case ShaderLanguage::TYPE_UINT:
|
||||
case ShaderLanguage::TYPE_FLOAT: {
|
||||
zeromem(data,4);
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_BVEC2:
|
||||
case ShaderLanguage::TYPE_IVEC2:
|
||||
case ShaderLanguage::TYPE_UVEC2:
|
||||
case ShaderLanguage::TYPE_VEC2: {
|
||||
zeromem(data,8);
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_BVEC3:
|
||||
case ShaderLanguage::TYPE_IVEC3:
|
||||
case ShaderLanguage::TYPE_UVEC3:
|
||||
case ShaderLanguage::TYPE_VEC3:
|
||||
case ShaderLanguage::TYPE_BVEC4:
|
||||
case ShaderLanguage::TYPE_IVEC4:
|
||||
case ShaderLanguage::TYPE_UVEC4:
|
||||
case ShaderLanguage::TYPE_VEC4:
|
||||
case ShaderLanguage::TYPE_MAT2:{
|
||||
|
||||
zeromem(data,16);
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_MAT3:{
|
||||
|
||||
zeromem(data,48);
|
||||
} break;
|
||||
case ShaderLanguage::TYPE_MAT4:{
|
||||
zeromem(data,64);
|
||||
} break;
|
||||
|
||||
default: {}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void RasterizerStorageGLES3::_update_material(Material* material) {
|
||||
|
||||
if (material->dirty_list.in_list())
|
||||
_material_dirty_list.remove( &material->dirty_list );
|
||||
|
||||
//clear ubo if it needs to be cleared
|
||||
if (material->ubo_size) {
|
||||
|
||||
if (!material->shader || material->shader->ubo_size!=material->ubo_size) {
|
||||
//by by ubo
|
||||
glDeleteBuffers(1,&material->ubo_id);
|
||||
material->ubo_id=0;
|
||||
material->ubo_size=0;
|
||||
}
|
||||
}
|
||||
|
||||
//create ubo if it needs to be created
|
||||
if (material->ubo_size==0 && material->shader && material->shader->ubo_size) {
|
||||
|
||||
glGenBuffers(1, &material->ubo_id);
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, material->ubo_id);
|
||||
glBufferData(GL_UNIFORM_BUFFER, material->shader->ubo_size, NULL, GL_DYNAMIC_DRAW);
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
||||
material->ubo_size=material->shader->ubo_size;
|
||||
}
|
||||
|
||||
//fill up the UBO if it needs to be filled
|
||||
if (material->shader && material->ubo_size) {
|
||||
uint8_t* local_ubo = (uint8_t*)alloca(material->ubo_size);
|
||||
|
||||
for(Map<StringName,ShaderLanguage::ShaderNode::Uniform>::Element *E=material->shader->uniforms.front();E;E=E->next()) {
|
||||
|
||||
if (E->get().order<0)
|
||||
continue; // texture, does not go here
|
||||
|
||||
//regular uniform
|
||||
uint8_t *data = &local_ubo[ material->shader->ubo_offsets[E->get().order] ];
|
||||
|
||||
Map<StringName,Variant>::Element *V = material->params.find(E->key());
|
||||
|
||||
if (V) {
|
||||
//user provided
|
||||
_fill_std140_variant_ubo_value(E->get().type,V->get(),data);
|
||||
} else if (E->get().default_value.size()){
|
||||
//default value
|
||||
_fill_std140_ubo_value(E->get().type,E->get().default_value,data);
|
||||
//value=E->get().default_value;
|
||||
} else {
|
||||
//zero because it was not provided
|
||||
_fill_std140_ubo_empty(E->get().type,data);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
glBindBuffer(GL_UNIFORM_BUFFER,material->ubo_id);
|
||||
glBufferSubData(GL_UNIFORM_BUFFER, 0, material->ubo_size, local_ubo);
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
||||
}
|
||||
|
||||
//set up the texture array, for easy access when it needs to be drawn
|
||||
if (material->shader && material->shader->texture_count) {
|
||||
|
||||
material->textures.resize(material->shader->texture_count);
|
||||
|
||||
for(Map<StringName,ShaderLanguage::ShaderNode::Uniform>::Element *E=material->shader->uniforms.front();E;E=E->next()) {
|
||||
|
||||
if (E->get().texture_order<0)
|
||||
continue; // not a texture, does not go here
|
||||
|
||||
RID texture;
|
||||
|
||||
Map<StringName,Variant>::Element *V = material->params.find(E->key());
|
||||
if (V) {
|
||||
texture=V->get();
|
||||
}
|
||||
|
||||
if (!texture.is_valid()) {
|
||||
Map<StringName,RID>::Element *W = material->shader->default_textures.find(E->key());
|
||||
if (W) {
|
||||
texture=W->get();
|
||||
}
|
||||
}
|
||||
|
||||
material->textures[ E->get().texture_order ]=texture;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
material->textures.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void RasterizerStorageGLES3::update_dirty_materials() {
|
||||
|
||||
while( _material_dirty_list.first() ) {
|
||||
|
||||
Material *material = _material_dirty_list.first()->self();
|
||||
|
||||
_update_material(material);
|
||||
}
|
||||
}
|
||||
|
||||
/* MESH API */
|
||||
|
||||
RID RasterizerStorageGLES3::mesh_create(){
|
||||
|
@ -1950,6 +2792,49 @@ bool RasterizerStorageGLES3::free(RID p_rid){
|
|||
info.texture_mem-=texture->total_data_size;
|
||||
texture_owner.free(p_rid);
|
||||
memdelete(texture);
|
||||
|
||||
} else if (shader_owner.owns(p_rid)) {
|
||||
|
||||
// delete the texture
|
||||
Shader *shader = shader_owner.get(p_rid);
|
||||
|
||||
if (shader->shader)
|
||||
shader->shader->free_custom_shader(shader->custom_code_id);
|
||||
|
||||
if (shader->dirty_list.in_list())
|
||||
_shader_dirty_list.remove(&shader->dirty_list);
|
||||
|
||||
while (shader->materials.first()) {
|
||||
|
||||
Material *mat = shader->materials.first()->self();
|
||||
|
||||
mat->shader=NULL;
|
||||
_material_make_dirty(mat);
|
||||
|
||||
shader->materials.remove( shader->materials.first() );
|
||||
}
|
||||
|
||||
//material_shader.free_custom_shader(shader->custom_code_id);
|
||||
shader_owner.free(p_rid);
|
||||
memdelete(shader);
|
||||
|
||||
} else if (material_owner.owns(p_rid)) {
|
||||
|
||||
// delete the texture
|
||||
Material *material = material_owner.get(p_rid);
|
||||
|
||||
if (material->shader) {
|
||||
material->shader->materials.remove( & material->list );
|
||||
}
|
||||
|
||||
if (material->ubo_id) {
|
||||
glDeleteBuffers(1,&material->ubo_id);
|
||||
}
|
||||
|
||||
material_owner.free(p_rid);
|
||||
memdelete(material);
|
||||
|
||||
|
||||
} else if (canvas_occluder_owner.owns(p_rid)) {
|
||||
|
||||
|
||||
|
|
|
@ -2,16 +2,21 @@
|
|||
#define RASTERIZERSTORAGEGLES3_H
|
||||
|
||||
#include "servers/visual/rasterizer.h"
|
||||
#include "servers/visual/shader_language.h"
|
||||
#include "shader_gles3.h"
|
||||
#include "shaders/copy.glsl.h"
|
||||
#include "shaders/canvas.glsl.h"
|
||||
#include "self_list.h"
|
||||
#include "shader_compiler_gles3.h"
|
||||
|
||||
|
||||
class RasterizerCanvasGLES3;
|
||||
|
||||
|
||||
class RasterizerStorageGLES3 : public RasterizerStorage {
|
||||
public:
|
||||
|
||||
RasterizerCanvasGLES3 *canvas;
|
||||
|
||||
enum FBOFormat {
|
||||
FBO_FORMAT_16_BITS,
|
||||
FBO_FORMAT_32_BITS,
|
||||
|
@ -47,9 +52,13 @@ public:
|
|||
Set<String> extensions;
|
||||
} config;
|
||||
|
||||
struct Shaders {
|
||||
mutable struct Shaders {
|
||||
|
||||
CopyShaderGLES3 copy;
|
||||
|
||||
ShaderCompilerGLES3 compiler;
|
||||
|
||||
ShaderCompilerGLES3::IdentifierActions actions_canvas;
|
||||
} shaders;
|
||||
|
||||
struct Resources {
|
||||
|
@ -169,11 +178,71 @@ public:
|
|||
|
||||
/* SHADER API */
|
||||
|
||||
struct Material;
|
||||
|
||||
struct Shader : public RID_Data {
|
||||
|
||||
RID self;
|
||||
|
||||
VS::ShaderMode mode;
|
||||
ShaderGLES3 *shader;
|
||||
String code;
|
||||
SelfList<Material>::List materials;
|
||||
|
||||
|
||||
|
||||
Map<StringName,ShaderLanguage::ShaderNode::Uniform> uniforms;
|
||||
Vector<uint32_t> ubo_offsets;
|
||||
uint32_t ubo_size;
|
||||
|
||||
uint32_t texture_count;
|
||||
|
||||
uint32_t custom_code_id;
|
||||
uint32_t version;
|
||||
|
||||
SelfList<Shader> dirty_list;
|
||||
|
||||
Map<StringName,RID> default_textures;
|
||||
|
||||
bool valid;
|
||||
|
||||
String path;
|
||||
|
||||
struct CanvasItem {
|
||||
|
||||
enum BlendMode {
|
||||
BLEND_MODE_MIX,
|
||||
BLEND_MODE_ADD,
|
||||
BLEND_MODE_SUB,
|
||||
BLEND_MODE_MUL,
|
||||
BLEND_MODE_PMALPHA,
|
||||
};
|
||||
|
||||
int blend_mode;
|
||||
|
||||
enum LightMode {
|
||||
LIGHT_MODE_NORMAL,
|
||||
LIGHT_MODE_UNSHADED,
|
||||
LIGHT_MODE_LIGHT_ONLY
|
||||
};
|
||||
|
||||
int light_mode;
|
||||
|
||||
} canvas_item;
|
||||
|
||||
Shader() : dirty_list(this) {
|
||||
|
||||
shader=NULL;
|
||||
valid=false;
|
||||
custom_code_id=0;
|
||||
version=1;
|
||||
}
|
||||
};
|
||||
|
||||
mutable SelfList<Shader>::List _shader_dirty_list;
|
||||
void _shader_make_dirty(Shader* p_shader);
|
||||
|
||||
mutable RID_Owner<Shader> shader_owner;
|
||||
|
||||
virtual RID shader_create(VS::ShaderMode p_mode=VS::SHADER_SPATIAL);
|
||||
|
||||
|
@ -187,17 +256,48 @@ public:
|
|||
virtual void shader_set_default_texture_param(RID p_shader, const StringName& p_name, RID p_texture);
|
||||
virtual RID shader_get_default_texture_param(RID p_shader, const StringName& p_name) const;
|
||||
|
||||
void _update_shader(Shader* p_shader) const;
|
||||
|
||||
void update_dirty_shaders();
|
||||
|
||||
/* COMMON MATERIAL API */
|
||||
|
||||
struct Material : public RID_Data {
|
||||
|
||||
Shader *shader;
|
||||
GLuint ubo_id;
|
||||
uint32_t ubo_size;
|
||||
Map<StringName,Variant> params;
|
||||
SelfList<Material> list;
|
||||
SelfList<Material> dirty_list;
|
||||
Vector<RID> textures;
|
||||
|
||||
Material() : list(this), dirty_list(this) {
|
||||
shader=NULL;
|
||||
ubo_id=0;
|
||||
ubo_size=0;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
mutable SelfList<Material>::List _material_dirty_list;
|
||||
void _material_make_dirty(Material *p_material) const;
|
||||
|
||||
|
||||
mutable RID_Owner<Material> material_owner;
|
||||
|
||||
virtual RID material_create();
|
||||
|
||||
virtual void material_set_shader(RID p_shader_material, RID p_shader);
|
||||
virtual RID material_get_shader(RID p_shader_material) const;
|
||||
virtual void material_set_shader(RID p_material, RID p_shader);
|
||||
virtual RID material_get_shader(RID p_material) const;
|
||||
|
||||
virtual void material_set_param(RID p_material, const StringName& p_param, const Variant& p_value);
|
||||
virtual Variant material_get_param(RID p_material, const StringName& p_param) const;
|
||||
|
||||
void _update_material(Material* material);
|
||||
|
||||
void update_dirty_materials();
|
||||
|
||||
/* MESH API */
|
||||
|
||||
virtual RID mesh_create();
|
||||
|
@ -432,6 +532,7 @@ public:
|
|||
bool clear_request;
|
||||
Color clear_request_color;
|
||||
int canvas_draw_commands;
|
||||
float time[4];
|
||||
} frame;
|
||||
|
||||
void initialize();
|
||||
|
|
528
drivers/gles3/shader_compiler_gles3.cpp
Normal file
528
drivers/gles3/shader_compiler_gles3.cpp
Normal file
|
@ -0,0 +1,528 @@
|
|||
#include "shader_compiler_gles3.h"
|
||||
#include "os/os.h"
|
||||
|
||||
#define SL ShaderLanguage
|
||||
|
||||
static String _mktab(int p_level) {
|
||||
|
||||
String tb;
|
||||
for(int i=0;i<p_level;i++) {
|
||||
tb+="\t";
|
||||
}
|
||||
|
||||
return tb;
|
||||
}
|
||||
|
||||
static String _typestr(SL::DataType p_type) {
|
||||
|
||||
return ShaderLanguage::get_datatype_name(p_type);
|
||||
}
|
||||
|
||||
static int _get_datatype_size(SL::DataType p_type) {
|
||||
|
||||
switch(p_type) {
|
||||
|
||||
case SL::TYPE_VOID: return 0;
|
||||
case SL::TYPE_BOOL: return 4;
|
||||
case SL::TYPE_BVEC2: return 8;
|
||||
case SL::TYPE_BVEC3: return 16;
|
||||
case SL::TYPE_BVEC4: return 16;
|
||||
case SL::TYPE_INT: return 4;
|
||||
case SL::TYPE_IVEC2: return 8;
|
||||
case SL::TYPE_IVEC3: return 16;
|
||||
case SL::TYPE_IVEC4: return 16;
|
||||
case SL::TYPE_UINT: return 4;
|
||||
case SL::TYPE_UVEC2: return 8;
|
||||
case SL::TYPE_UVEC3: return 16;
|
||||
case SL::TYPE_UVEC4: return 16;
|
||||
case SL::TYPE_FLOAT: return 4;
|
||||
case SL::TYPE_VEC2: return 8;
|
||||
case SL::TYPE_VEC3: return 16;
|
||||
case SL::TYPE_VEC4: return 16;
|
||||
case SL::TYPE_MAT2: return 16;
|
||||
case SL::TYPE_MAT3: return 48;
|
||||
case SL::TYPE_MAT4: return 64;
|
||||
case SL::TYPE_SAMPLER2D: return 16;
|
||||
case SL::TYPE_ISAMPLER2D: return 16;
|
||||
case SL::TYPE_USAMPLER2D: return 16;
|
||||
case SL::TYPE_SAMPLERCUBE: return 16;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
static String _prestr(SL::DataPrecision p_pres) {
|
||||
|
||||
|
||||
switch(p_pres) {
|
||||
case SL::PRECISION_LOWP: return "lowp ";
|
||||
case SL::PRECISION_MEDIUMP: return "mediump ";
|
||||
case SL::PRECISION_HIGHP: return "highp ";
|
||||
case SL::PRECISION_DEFAULT: return "";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
static String _opstr(SL::Operator p_op) {
|
||||
|
||||
return SL::get_operator_text(p_op);
|
||||
}
|
||||
|
||||
static String _mkid(const String& p_id) {
|
||||
|
||||
return "m_"+p_id;
|
||||
}
|
||||
|
||||
static String get_constant_text(SL::DataType p_type, const Vector<SL::ConstantNode::Value>& p_values) {
|
||||
|
||||
switch(p_type) {
|
||||
case SL::TYPE_BOOL: return p_values[0].boolean?"true":"false";
|
||||
case SL::TYPE_BVEC2: return String()+"bvec2("+(p_values[0].boolean?"true":"false")+(p_values[1].boolean?"true":"false")+")";
|
||||
case SL::TYPE_BVEC3: return String()+"bvec3("+(p_values[0].boolean?"true":"false")+","+(p_values[1].boolean?"true":"false")+","+(p_values[2].boolean?"true":"false")+")";
|
||||
case SL::TYPE_BVEC4: return String()+"bvec4("+(p_values[0].boolean?"true":"false")+","+(p_values[1].boolean?"true":"false")+","+(p_values[2].boolean?"true":"false")+","+(p_values[3].boolean?"true":"false")+")";
|
||||
case SL::TYPE_INT: return rtos(p_values[0].sint);
|
||||
case SL::TYPE_IVEC2: return String()+"ivec2("+rtos(p_values[0].sint)+","+rtos(p_values[1].sint)+")";
|
||||
case SL::TYPE_IVEC3: return String()+"ivec3("+rtos(p_values[0].sint)+","+rtos(p_values[1].sint)+","+rtos(p_values[2].sint)+")";
|
||||
case SL::TYPE_IVEC4: return String()+"ivec4("+rtos(p_values[0].sint)+","+rtos(p_values[1].sint)+","+rtos(p_values[2].sint)+","+rtos(p_values[3].sint)+")";
|
||||
case SL::TYPE_UINT: return rtos(p_values[0].real);
|
||||
case SL::TYPE_UVEC2: return String()+"uvec2("+rtos(p_values[0].real)+","+rtos(p_values[1].real)+")";
|
||||
case SL::TYPE_UVEC3: return String()+"uvec3("+rtos(p_values[0].real)+","+rtos(p_values[1].real)+","+rtos(p_values[2].real)+")";
|
||||
case SL::TYPE_UVEC4: return String()+"uvec4("+rtos(p_values[0].real)+","+rtos(p_values[1].real)+","+rtos(p_values[2].real)+","+rtos(p_values[3].real)+")";
|
||||
case SL::TYPE_FLOAT: return rtos(p_values[0].real);
|
||||
case SL::TYPE_VEC2: return String()+"vec2("+rtos(p_values[0].real)+","+rtos(p_values[1].real)+")";
|
||||
case SL::TYPE_VEC3: return String()+"vec3("+rtos(p_values[0].real)+","+rtos(p_values[1].real)+","+rtos(p_values[2].real)+")";
|
||||
case SL::TYPE_VEC4: return String()+"vec4("+rtos(p_values[0].real)+","+rtos(p_values[1].real)+","+rtos(p_values[2].real)+","+rtos(p_values[3].real)+")";
|
||||
default: ERR_FAIL_V(String());
|
||||
}
|
||||
}
|
||||
|
||||
void ShaderCompilerGLES3::_dump_function_deps(SL::ShaderNode* p_node, const StringName& p_for_func, const Map<StringName,String>& p_func_code, String& r_to_add, Set<StringName> &added) {
|
||||
|
||||
int fidx=-1;
|
||||
|
||||
for(int i=0;i<p_node->functions.size();i++) {
|
||||
if (p_node->functions[i].name==p_for_func) {
|
||||
fidx=i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ERR_FAIL_COND(fidx==-1);
|
||||
|
||||
for (Set<StringName>::Element *E=p_node->functions[fidx].uses_function.front();E;E=E->next()) {
|
||||
|
||||
if (added.has(E->get())) {
|
||||
continue; //was added already
|
||||
}
|
||||
|
||||
_dump_function_deps(p_node,E->get(),p_func_code,r_to_add,added);
|
||||
|
||||
SL::FunctionNode *fnode=NULL;
|
||||
|
||||
for(int i=0;i<p_node->functions.size();i++) {
|
||||
if (p_node->functions[i].name==E->get()) {
|
||||
fnode=p_node->functions[i].function;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ERR_FAIL_COND(!fnode);
|
||||
|
||||
r_to_add+="\n";
|
||||
|
||||
String header;
|
||||
header=_typestr(fnode->return_type)+" "+_mkid(fnode->name)+"(";
|
||||
for(int i=0;i<fnode->arguments.size();i++) {
|
||||
|
||||
if (i>0)
|
||||
header+=", ";
|
||||
header+=_prestr(fnode->arguments[i].precision)+_typestr(fnode->arguments[i].type)+" "+_mkid(fnode->arguments[i].name);
|
||||
}
|
||||
|
||||
header+=")\n";
|
||||
r_to_add+=header;
|
||||
r_to_add+=p_func_code[E->get()];
|
||||
|
||||
added.insert(E->get());
|
||||
}
|
||||
}
|
||||
|
||||
String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, GeneratedCode& r_gen_code, IdentifierActions &p_actions, const DefaultIdentifierActions &p_default_actions) {
|
||||
|
||||
String code;
|
||||
|
||||
switch(p_node->type) {
|
||||
|
||||
case SL::Node::TYPE_SHADER: {
|
||||
|
||||
SL::ShaderNode *pnode=(SL::ShaderNode*)p_node;
|
||||
|
||||
for(int i=0;i<pnode->render_modes.size();i++) {
|
||||
|
||||
if (p_default_actions.render_mode_defines.has(pnode->render_modes[i]) && !used_rmode_defines.has(pnode->render_modes[i])) {
|
||||
|
||||
r_gen_code.defines.push_back(p_default_actions.render_mode_defines[pnode->render_modes[i]].utf8());
|
||||
used_rmode_defines.insert(pnode->render_modes[i]);
|
||||
}
|
||||
|
||||
if (p_actions.render_mode_flags.has(pnode->render_modes[i])) {
|
||||
*p_actions.render_mode_flags[pnode->render_modes[i]]=true;
|
||||
}
|
||||
|
||||
if (p_actions.render_mode_values.has(pnode->render_modes[i])) {
|
||||
Pair<int*,int> &p = p_actions.render_mode_values[pnode->render_modes[i]];
|
||||
*p.first=p.second;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int max_texture_uniforms=0;
|
||||
int max_uniforms=0;
|
||||
|
||||
for(Map<StringName,SL::ShaderNode::Uniform>::Element *E=pnode->uniforms.front();E;E=E->next()) {
|
||||
if (SL::is_sampler_type(E->get().type))
|
||||
max_texture_uniforms++;
|
||||
else
|
||||
max_uniforms++;
|
||||
}
|
||||
|
||||
r_gen_code.texture_uniforms.resize(max_texture_uniforms);
|
||||
|
||||
Vector<int> uniform_sizes;
|
||||
uniform_sizes.resize(max_uniforms);
|
||||
|
||||
for(Map<StringName,SL::ShaderNode::Uniform>::Element *E=pnode->uniforms.front();E;E=E->next()) {
|
||||
|
||||
String ucode="uniform ";
|
||||
ucode+=_prestr(E->get().precission);
|
||||
ucode+=_typestr(E->get().type);
|
||||
ucode+=" "+_mkid(E->key());
|
||||
ucode+=";\n";
|
||||
if (SL::is_sampler_type(E->get().type)) {
|
||||
r_gen_code.vertex_global+=ucode;
|
||||
r_gen_code.fragment_global+=ucode;
|
||||
r_gen_code.texture_uniforms[E->get().texture_order]=_mkid(E->key());
|
||||
} else {
|
||||
if (r_gen_code.uniforms.empty()) {
|
||||
|
||||
r_gen_code.defines.push_back(String("#define USE_MATERIAL\n").ascii());
|
||||
}
|
||||
r_gen_code.uniforms+=ucode;
|
||||
uniform_sizes[E->get().order]=_get_datatype_size(E->get().type);
|
||||
}
|
||||
|
||||
p_actions.uniforms->insert(E->key(),E->get());
|
||||
|
||||
}
|
||||
|
||||
// add up
|
||||
for(int i=0;i<uniform_sizes.size();i++) {
|
||||
|
||||
if (i>0)
|
||||
uniform_sizes[i]=uniform_sizes[i]+uniform_sizes[i-1];
|
||||
}
|
||||
//offset
|
||||
r_gen_code.uniform_offsets.resize(uniform_sizes.size());
|
||||
for(int i=0;i<uniform_sizes.size();i++) {
|
||||
|
||||
if (i>0)
|
||||
r_gen_code.uniform_offsets[i]=uniform_sizes[i]-1;
|
||||
else
|
||||
r_gen_code.uniform_offsets[i]=0;
|
||||
}
|
||||
|
||||
if (uniform_sizes.size()) {
|
||||
r_gen_code.uniform_total_size=uniform_sizes[ uniform_sizes.size() -1 ];
|
||||
} else {
|
||||
r_gen_code.uniform_total_size=0;
|
||||
}
|
||||
|
||||
for(Map<StringName,SL::ShaderNode::Varying>::Element *E=pnode->varyings.front();E;E=E->next()) {
|
||||
|
||||
String vcode;
|
||||
vcode+=_prestr(E->get().precission);
|
||||
vcode+=_typestr(E->get().type);
|
||||
vcode+=" "+String(E->key());
|
||||
vcode+=";\n";
|
||||
r_gen_code.vertex_global+="out "+vcode;
|
||||
r_gen_code.fragment_global+="in "+vcode;
|
||||
}
|
||||
|
||||
Map<StringName,String> function_code;
|
||||
|
||||
//code for functions
|
||||
for(int i=0;i<pnode->functions.size();i++) {
|
||||
SL::FunctionNode *fnode=pnode->functions[i].function;
|
||||
function_code[fnode->name]=_dump_node_code(fnode->body,p_level+1,r_gen_code,p_actions,p_default_actions);
|
||||
}
|
||||
|
||||
//place functions in actual code
|
||||
|
||||
Set<StringName> added_vtx;
|
||||
Set<StringName> added_fragment; //share for light
|
||||
|
||||
for(int i=0;i<pnode->functions.size();i++) {
|
||||
|
||||
SL::FunctionNode *fnode=pnode->functions[i].function;
|
||||
|
||||
|
||||
if (fnode->name=="vertex") {
|
||||
|
||||
_dump_function_deps(pnode,fnode->name,function_code,r_gen_code.vertex_global,added_vtx);
|
||||
r_gen_code.vertex=function_code["vertex"];
|
||||
}
|
||||
|
||||
if (fnode->name=="fragment") {
|
||||
|
||||
_dump_function_deps(pnode,fnode->name,function_code,r_gen_code.fragment_global,added_fragment);
|
||||
r_gen_code.fragment=function_code["fragment"];
|
||||
}
|
||||
|
||||
if (fnode->name=="light") {
|
||||
|
||||
_dump_function_deps(pnode,fnode->name,function_code,r_gen_code.fragment_global,added_fragment);
|
||||
r_gen_code.light=function_code["light"];
|
||||
}
|
||||
}
|
||||
|
||||
//code+=dump_node_code(pnode->body,p_level);
|
||||
} break;
|
||||
case SL::Node::TYPE_FUNCTION: {
|
||||
|
||||
} break;
|
||||
case SL::Node::TYPE_BLOCK: {
|
||||
SL::BlockNode *bnode=(SL::BlockNode*)p_node;
|
||||
|
||||
//variables
|
||||
code+=_mktab(p_level-1)+"{\n";
|
||||
for(Map<StringName,SL::BlockNode::Variable>::Element *E=bnode->variables.front();E;E=E->next()) {
|
||||
|
||||
code+=_mktab(p_level)+_prestr(E->get().precision)+_typestr(E->get().type)+" "+_mkid(E->key())+";\n";
|
||||
}
|
||||
|
||||
for(int i=0;i<bnode->statements.size();i++) {
|
||||
|
||||
String scode = _dump_node_code(bnode->statements[i],p_level,r_gen_code,p_actions,p_default_actions);
|
||||
|
||||
if (bnode->statements[i]->type==SL::Node::TYPE_CONTROL_FLOW || bnode->statements[i]->type==SL::Node::TYPE_CONTROL_FLOW) {
|
||||
code+=scode; //use directly
|
||||
} else {
|
||||
code+=_mktab(p_level)+scode+";\n";
|
||||
}
|
||||
}
|
||||
code+=_mktab(p_level-1)+"}\n";
|
||||
|
||||
|
||||
} break;
|
||||
case SL::Node::TYPE_VARIABLE: {
|
||||
SL::VariableNode *vnode=(SL::VariableNode*)p_node;
|
||||
|
||||
if (p_default_actions.usage_defines.has(vnode->name) && !used_name_defines.has(vnode->name)) {
|
||||
r_gen_code.defines.push_back(p_default_actions.usage_defines[vnode->name].utf8());
|
||||
used_name_defines.insert(vnode->name);
|
||||
}
|
||||
|
||||
if (p_actions.usage_flag_pointers.has(vnode->name) && !used_name_defines.has(vnode->name)) {
|
||||
*p_actions.usage_flag_pointers[vnode->name]=true;
|
||||
used_name_defines.insert(vnode->name);
|
||||
}
|
||||
|
||||
if (p_default_actions.renames.has(vnode->name))
|
||||
code=p_default_actions.renames[vnode->name];
|
||||
else
|
||||
code=_mkid(vnode->name);
|
||||
|
||||
|
||||
} break;
|
||||
case SL::Node::TYPE_CONSTANT: {
|
||||
SL::ConstantNode *cnode=(SL::ConstantNode*)p_node;
|
||||
return get_constant_text(cnode->datatype,cnode->values);
|
||||
|
||||
} break;
|
||||
case SL::Node::TYPE_OPERATOR: {
|
||||
SL::OperatorNode *onode=(SL::OperatorNode*)p_node;
|
||||
|
||||
|
||||
switch(onode->op) {
|
||||
|
||||
case SL::OP_ASSIGN:
|
||||
case SL::OP_ASSIGN_ADD:
|
||||
case SL::OP_ASSIGN_SUB:
|
||||
case SL::OP_ASSIGN_MUL:
|
||||
case SL::OP_ASSIGN_DIV:
|
||||
case SL::OP_ASSIGN_SHIFT_LEFT:
|
||||
case SL::OP_ASSIGN_SHIFT_RIGHT:
|
||||
case SL::OP_ASSIGN_MOD:
|
||||
case SL::OP_ASSIGN_BIT_AND:
|
||||
case SL::OP_ASSIGN_BIT_OR:
|
||||
case SL::OP_ASSIGN_BIT_XOR:
|
||||
code=_dump_node_code(onode->arguments[0],p_level,r_gen_code,p_actions,p_default_actions)+_opstr(onode->op)+_dump_node_code(onode->arguments[1],p_level,r_gen_code,p_actions,p_default_actions);
|
||||
break;
|
||||
case SL::OP_BIT_INVERT:
|
||||
case SL::OP_NEGATE:
|
||||
case SL::OP_NOT:
|
||||
case SL::OP_DECREMENT:
|
||||
case SL::OP_INCREMENT:
|
||||
code=_opstr(onode->op)+_dump_node_code(onode->arguments[0],p_level,r_gen_code,p_actions,p_default_actions);
|
||||
break;
|
||||
case SL::OP_POST_DECREMENT:
|
||||
case SL::OP_POST_INCREMENT:
|
||||
code=_dump_node_code(onode->arguments[0],p_level,r_gen_code,p_actions,p_default_actions)+_opstr(onode->op);
|
||||
break;
|
||||
case SL::OP_CALL:
|
||||
case SL::OP_CONSTRUCT: {
|
||||
|
||||
ERR_FAIL_COND_V(onode->arguments[0]->type!=SL::Node::TYPE_VARIABLE,String());
|
||||
|
||||
SL::VariableNode *vnode=(SL::VariableNode*)onode->arguments[0];
|
||||
|
||||
if (onode->op==SL::OP_CONSTRUCT) {
|
||||
code+=String(vnode->name);
|
||||
} else {
|
||||
|
||||
if (internal_functions.has(vnode->name)) {
|
||||
code+=vnode->name;
|
||||
} else if (p_default_actions.renames.has(vnode->name)) {
|
||||
code+=p_default_actions.renames[vnode->name];
|
||||
} else {
|
||||
code+=_mkid(vnode->name);
|
||||
}
|
||||
}
|
||||
|
||||
code+="(";
|
||||
|
||||
for(int i=1;i<onode->arguments.size();i++) {
|
||||
if (i>1)
|
||||
code+=", ";
|
||||
code+=_dump_node_code(onode->arguments[i],p_level,r_gen_code,p_actions,p_default_actions);
|
||||
}
|
||||
code+=")";
|
||||
} break;
|
||||
default: {
|
||||
|
||||
code="("+_dump_node_code(onode->arguments[0],p_level,r_gen_code,p_actions,p_default_actions)+_opstr(onode->op)+_dump_node_code(onode->arguments[1],p_level,r_gen_code,p_actions,p_default_actions)+")";
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
} break;
|
||||
case SL::Node::TYPE_CONTROL_FLOW: {
|
||||
SL::ControlFlowNode *cfnode=(SL::ControlFlowNode*)p_node;
|
||||
if (cfnode->flow_op==SL::FLOW_OP_IF) {
|
||||
|
||||
code+=_mktab(p_level)+"if ("+_dump_node_code(cfnode->expressions[0],p_level,r_gen_code,p_actions,p_default_actions)+")\n";
|
||||
code+=_dump_node_code(cfnode->blocks[0],p_level+1,r_gen_code,p_actions,p_default_actions);
|
||||
if (cfnode->blocks.size()==2) {
|
||||
|
||||
code+=_mktab(p_level)+"else\n";
|
||||
code+=_dump_node_code(cfnode->blocks[1],p_level+1,r_gen_code,p_actions,p_default_actions);
|
||||
}
|
||||
|
||||
|
||||
} else if (cfnode->flow_op==SL::FLOW_OP_RETURN) {
|
||||
|
||||
if (cfnode->blocks.size()) {
|
||||
code="return "+_dump_node_code(cfnode->blocks[0],p_level,r_gen_code,p_actions,p_default_actions);
|
||||
} else {
|
||||
code="return";
|
||||
}
|
||||
}
|
||||
|
||||
} break;
|
||||
case SL::Node::TYPE_MEMBER: {
|
||||
SL::MemberNode *mnode=(SL::MemberNode*)p_node;
|
||||
code=_dump_node_code(mnode->owner,p_level,r_gen_code,p_actions,p_default_actions)+"."+mnode->name;
|
||||
|
||||
} break;
|
||||
}
|
||||
|
||||
return code;
|
||||
|
||||
}
|
||||
|
||||
|
||||
Error ShaderCompilerGLES3::compile(VS::ShaderMode p_mode, const String& p_code, IdentifierActions* p_actions, const String &p_path,GeneratedCode& r_gen_code) {
|
||||
|
||||
|
||||
|
||||
Error err = parser.compile(p_code,ShaderTypes::get_singleton()->get_functions(p_mode),ShaderTypes::get_singleton()->get_modes(p_mode));
|
||||
|
||||
if (err!=OK) {
|
||||
_err_print_error(NULL,p_path.utf8().get_data(),parser.get_error_line(),parser.get_error_text().utf8().get_data(),ERR_HANDLER_SHADER);
|
||||
return err;
|
||||
}
|
||||
|
||||
r_gen_code.defines.clear();
|
||||
r_gen_code.vertex=String();
|
||||
r_gen_code.vertex_global=String();
|
||||
r_gen_code.fragment=String();
|
||||
r_gen_code.fragment_global=String();
|
||||
r_gen_code.light=String();
|
||||
|
||||
|
||||
|
||||
used_name_defines.clear();
|
||||
used_rmode_defines.clear();
|
||||
|
||||
_dump_node_code(parser.get_shader(),1,r_gen_code,*p_actions,actions[p_mode]);
|
||||
|
||||
return OK;
|
||||
|
||||
}
|
||||
|
||||
|
||||
ShaderCompilerGLES3::ShaderCompilerGLES3() {
|
||||
|
||||
/** CANVAS ITEM SHADER **/
|
||||
|
||||
actions[VS::SHADER_CANVAS_ITEM].renames["SRC_VERTEX"]="vertex";
|
||||
actions[VS::SHADER_CANVAS_ITEM].renames["VERTEX"]="outvec.xy";
|
||||
actions[VS::SHADER_CANVAS_ITEM].renames["VERTEX_COLOR"]="vertex_color";
|
||||
actions[VS::SHADER_CANVAS_ITEM].renames["UV"]="uv_interp";
|
||||
actions[VS::SHADER_CANVAS_ITEM].renames["POINT_SIZE"]="gl_PointSize";
|
||||
|
||||
actions[VS::SHADER_CANVAS_ITEM].renames["WORLD_MATRIX"]="modelview_matrix";
|
||||
actions[VS::SHADER_CANVAS_ITEM].renames["PROJECTION_MATRIX"]="projection_matrix";
|
||||
actions[VS::SHADER_CANVAS_ITEM].renames["EXTRA_MATRIX"]=="extra_matrix";
|
||||
actions[VS::SHADER_CANVAS_ITEM].renames["TIME"]="time";
|
||||
|
||||
actions[VS::SHADER_CANVAS_ITEM].renames["COLOR"]="color";
|
||||
actions[VS::SHADER_CANVAS_ITEM].renames["NORMAL"]="normal";
|
||||
actions[VS::SHADER_CANVAS_ITEM].renames["NORMALMAP"]="normal_map";
|
||||
actions[VS::SHADER_CANVAS_ITEM].renames["NORMALMAP_DEPTH"]="normal_depth";
|
||||
actions[VS::SHADER_CANVAS_ITEM].renames["UV"]="uv_interp";
|
||||
actions[VS::SHADER_CANVAS_ITEM].renames["COLOR"]="color";
|
||||
actions[VS::SHADER_CANVAS_ITEM].renames["TEXTURE"]="color_texture";
|
||||
actions[VS::SHADER_CANVAS_ITEM].renames["TEXTURE_PIXEL_SIZE"]="color_texpixel_size";
|
||||
actions[VS::SHADER_CANVAS_ITEM].renames["SCREEN_UV"]="screen_uv";
|
||||
actions[VS::SHADER_CANVAS_ITEM].renames["SCREEN_TEXTURE"]="screen_texture";
|
||||
actions[VS::SHADER_CANVAS_ITEM].renames["POINT_COORD"]="gl_PointCoord";
|
||||
|
||||
actions[VS::SHADER_CANVAS_ITEM].renames["LIGHT_VEC"]="light_vec";
|
||||
actions[VS::SHADER_CANVAS_ITEM].renames["LIGHT_HEIGHT"]="light_height";
|
||||
actions[VS::SHADER_CANVAS_ITEM].renames["LIGHT_COLOR"]="light_color";
|
||||
actions[VS::SHADER_CANVAS_ITEM].renames["LIGHT_UV"]="light_uv";
|
||||
//actions[VS::SHADER_CANVAS_ITEM].renames["LIGHT_SHADOW_COLOR"]="light_shadow_color";
|
||||
actions[VS::SHADER_CANVAS_ITEM].renames["LIGHT"]="light";
|
||||
actions[VS::SHADER_CANVAS_ITEM].renames["SHADOW_COLOR"]="shadow_color";
|
||||
|
||||
actions[VS::SHADER_CANVAS_ITEM].usage_defines["COLOR"]="#define COLOR_USED\n";
|
||||
actions[VS::SHADER_CANVAS_ITEM].usage_defines["SCREEN_TEXTURE"]="#define SCREEN_TEXTURE_USED\n";
|
||||
actions[VS::SHADER_CANVAS_ITEM].usage_defines["SCREEN_UV"]="#define SCREEN_UV_USED\n";
|
||||
actions[VS::SHADER_CANVAS_ITEM].usage_defines["NORMAL"]="#define NORMAL_USED\n";
|
||||
actions[VS::SHADER_CANVAS_ITEM].usage_defines["NORMALMAP"]="#define NORMALMAP_USED\n";
|
||||
actions[VS::SHADER_CANVAS_ITEM].usage_defines["SHADOW_COLOR"]="#define SHADOW_COLOR_USED\n";
|
||||
|
||||
actions[VS::SHADER_CANVAS_ITEM].render_mode_defines["skip_transform"]="#define SKIP_TRANSFORM_USED\n";
|
||||
|
||||
List<String> func_list;
|
||||
|
||||
ShaderLanguage::get_builtin_funcs(&func_list);
|
||||
|
||||
for (List<String>::Element *E=func_list.front();E;E=E->next()) {
|
||||
internal_functions.insert(E->get());
|
||||
}
|
||||
}
|
67
drivers/gles3/shader_compiler_gles3.h
Normal file
67
drivers/gles3/shader_compiler_gles3.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
#ifndef SHADERCOMPILERGLES3_H
|
||||
#define SHADERCOMPILERGLES3_H
|
||||
|
||||
#include "servers/visual/shader_language.h"
|
||||
#include "servers/visual/shader_types.h"
|
||||
#include "servers/visual_server.h"
|
||||
#include "pair.h"
|
||||
|
||||
class ShaderCompilerGLES3 {
|
||||
public:
|
||||
struct IdentifierActions {
|
||||
|
||||
Map<StringName,Pair<int*,int> > render_mode_values;
|
||||
Map<StringName,bool*> render_mode_flags;
|
||||
Map<StringName,bool*> usage_flag_pointers;
|
||||
|
||||
Map<StringName,ShaderLanguage::ShaderNode::Uniform> *uniforms;
|
||||
};
|
||||
|
||||
struct GeneratedCode {
|
||||
|
||||
Vector<CharString> defines;
|
||||
Vector<StringName> texture_uniforms;
|
||||
Vector<uint32_t> uniform_offsets;
|
||||
uint32_t uniform_total_size;
|
||||
String uniforms;
|
||||
String vertex_global;
|
||||
String vertex;
|
||||
String fragment_global;
|
||||
String fragment;
|
||||
String light;
|
||||
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
ShaderLanguage parser;
|
||||
|
||||
struct DefaultIdentifierActions {
|
||||
|
||||
Map<StringName,String> renames;
|
||||
Map<StringName,String> render_mode_defines;
|
||||
Map<StringName,String> usage_defines;
|
||||
};
|
||||
|
||||
void _dump_function_deps(ShaderLanguage::ShaderNode *p_node, const StringName& p_for_func, const Map<StringName, String> &p_func_code, String& r_to_add,Set<StringName> &added);
|
||||
String _dump_node_code(ShaderLanguage::Node *p_node, int p_level, GeneratedCode &r_gen_code, IdentifierActions& p_actions, const DefaultIdentifierActions& p_default_actions);
|
||||
|
||||
|
||||
|
||||
Set<StringName> used_name_defines;
|
||||
Set<StringName> used_rmode_defines;
|
||||
Set<StringName> internal_functions;
|
||||
|
||||
|
||||
DefaultIdentifierActions actions[VS::SHADER_MAX];
|
||||
|
||||
public:
|
||||
|
||||
|
||||
Error compile(VS::ShaderMode p_mode, const String& p_code, IdentifierActions* p_actions, const String& p_path, GeneratedCode& r_gen_code);
|
||||
|
||||
|
||||
ShaderCompilerGLES3();
|
||||
};
|
||||
|
||||
#endif // SHADERCOMPILERGLES3_H
|
|
@ -214,6 +214,8 @@ ShaderGLES3::Version* ShaderGLES3::get_current_version() {
|
|||
|
||||
}
|
||||
|
||||
|
||||
|
||||
v.ok=false;
|
||||
/* SETUP CONDITIONALS */
|
||||
|
||||
|
@ -245,6 +247,7 @@ ShaderGLES3::Version* ShaderGLES3::get_current_version() {
|
|||
CharString code_string;
|
||||
CharString code_string2;
|
||||
CharString code_globals;
|
||||
CharString material_string;
|
||||
|
||||
|
||||
//print_line("code version? "+itos(conditional_version.code_version));
|
||||
|
@ -258,6 +261,7 @@ ShaderGLES3::Version* ShaderGLES3::get_current_version() {
|
|||
cc=&custom_code_map[conditional_version.code_version];
|
||||
v.code_version=cc->version;
|
||||
define_line_ofs+=2;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -273,7 +277,7 @@ ShaderGLES3::Version* ShaderGLES3::get_current_version() {
|
|||
if (cc) {
|
||||
for(int i=0;i<cc->custom_defines.size();i++) {
|
||||
|
||||
strings.push_back(cc->custom_defines[i]);
|
||||
strings.push_back(cc->custom_defines[i].get_data());
|
||||
DEBUG_PRINT("CD #"+itos(i)+": "+String(cc->custom_defines[i]));
|
||||
}
|
||||
}
|
||||
|
@ -305,14 +309,22 @@ ShaderGLES3::Version* ShaderGLES3::get_current_version() {
|
|||
code_globals=cc->vertex_globals.ascii();
|
||||
strings.push_back(code_globals.get_data());
|
||||
}
|
||||
|
||||
strings.push_back(vertex_code1.get_data());
|
||||
|
||||
if (cc) {
|
||||
material_string=cc->uniforms.ascii();
|
||||
strings.push_back(material_string.get_data());
|
||||
}
|
||||
|
||||
strings.push_back(vertex_code2.get_data());
|
||||
|
||||
if (cc) {
|
||||
code_string=cc->vertex.ascii();
|
||||
strings.push_back(code_string.get_data());
|
||||
}
|
||||
|
||||
strings.push_back(vertex_code2.get_data());
|
||||
strings.push_back(vertex_code3.get_data());
|
||||
#ifdef DEBUG_SHADER
|
||||
|
||||
DEBUG_PRINT("\nVertex Code:\n\n"+String(code_string.get_data()));
|
||||
|
@ -367,7 +379,8 @@ ShaderGLES3::Version* ShaderGLES3::get_current_version() {
|
|||
|
||||
ERR_FAIL_V(NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* FRAGMENT SHADER */
|
||||
|
||||
strings.resize(strings_base_size);
|
||||
|
@ -396,21 +409,29 @@ ShaderGLES3::Version* ShaderGLES3::get_current_version() {
|
|||
code_globals=cc->fragment_globals.ascii();
|
||||
strings.push_back(code_globals.get_data());
|
||||
}
|
||||
|
||||
strings.push_back(fragment_code1.get_data());
|
||||
|
||||
if (cc) {
|
||||
material_string=cc->uniforms.ascii();
|
||||
strings.push_back(material_string.get_data());
|
||||
}
|
||||
|
||||
strings.push_back(fragment_code2.get_data());
|
||||
|
||||
if (cc) {
|
||||
code_string=cc->fragment.ascii();
|
||||
strings.push_back(code_string.get_data());
|
||||
}
|
||||
|
||||
strings.push_back(fragment_code2.get_data());
|
||||
strings.push_back(fragment_code3.get_data());
|
||||
|
||||
if (cc) {
|
||||
code_string2=cc->light.ascii();
|
||||
strings.push_back(code_string2.get_data());
|
||||
}
|
||||
|
||||
strings.push_back(fragment_code3.get_data());
|
||||
strings.push_back(fragment_code4.get_data());
|
||||
|
||||
#ifdef DEBUG_SHADER
|
||||
DEBUG_PRINT("\nFragment Code:\n\n"+String(code_string.get_data()));
|
||||
|
@ -463,7 +484,7 @@ ShaderGLES3::Version* ShaderGLES3::get_current_version() {
|
|||
|
||||
ERR_FAIL_V( NULL );
|
||||
}
|
||||
|
||||
|
||||
glAttachShader(v.id,v.frag_id);
|
||||
glAttachShader(v.id,v.vert_id);
|
||||
|
||||
|
@ -552,10 +573,11 @@ ShaderGLES3::Version* ShaderGLES3::get_current_version() {
|
|||
|
||||
if ( cc ) {
|
||||
|
||||
v.custom_uniform_locations.resize(cc->custom_uniforms.size());
|
||||
for(int i=0;i<cc->custom_uniforms.size();i++) {
|
||||
v.texture_uniform_locations.resize(cc->texture_uniforms.size());
|
||||
for(int i=0;i<cc->texture_uniforms.size();i++) {
|
||||
|
||||
v.custom_uniform_locations[i]=glGetUniformLocation(v.id,String(cc->custom_uniforms[i]).ascii().get_data());
|
||||
v.texture_uniform_locations[i]=glGetUniformLocation(v.id,String(cc->texture_uniforms[i]).ascii().get_data());
|
||||
glUniform1i(v.texture_uniform_locations[i],i+base_material_tex_index);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -597,6 +619,7 @@ void ShaderGLES3::setup(const char** p_conditional_defines, int p_conditional_co
|
|||
//split vertex and shader code (thank you, retarded shader compiler programmers from you know what company).
|
||||
{
|
||||
String globals_tag="\nVERTEX_SHADER_GLOBALS";
|
||||
String material_tag="\nMATERIAL_UNIFORMS";
|
||||
String code_tag="\nVERTEX_SHADER_CODE";
|
||||
String code = vertex_code;
|
||||
int cpos = code.find(globals_tag);
|
||||
|
@ -606,20 +629,31 @@ void ShaderGLES3::setup(const char** p_conditional_defines, int p_conditional_co
|
|||
vertex_code0=code.substr(0,cpos).ascii();
|
||||
code = code.substr(cpos+globals_tag.length(),code.length());
|
||||
|
||||
cpos = code.find(code_tag);
|
||||
cpos = code.find(material_tag);
|
||||
|
||||
if (cpos==-1) {
|
||||
vertex_code1=code.ascii();
|
||||
} else {
|
||||
|
||||
vertex_code1=code.substr(0,cpos).ascii();
|
||||
vertex_code2=code.substr(cpos+code_tag.length(),code.length()).ascii();
|
||||
String code2 = code.substr(cpos+material_tag.length(),code.length());
|
||||
|
||||
cpos = code2.find(code_tag);
|
||||
if (cpos==-1) {
|
||||
vertex_code2=code2.ascii();
|
||||
} else {
|
||||
|
||||
vertex_code2=code2.substr(0,cpos).ascii();
|
||||
vertex_code3 = code2.substr(cpos+code_tag.length(),code2.length()).ascii();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
String globals_tag="\nFRAGMENT_SHADER_GLOBALS";
|
||||
String material_tag="\nMATERIAL_UNIFORMS";
|
||||
String code_tag="\nFRAGMENT_SHADER_CODE";
|
||||
String light_code_tag="\nLIGHT_SHADER_CODE";
|
||||
String code = fragment_code;
|
||||
|
@ -630,22 +664,31 @@ void ShaderGLES3::setup(const char** p_conditional_defines, int p_conditional_co
|
|||
fragment_code0=code.substr(0,cpos).ascii();
|
||||
code = code.substr(cpos+globals_tag.length(),code.length());
|
||||
|
||||
cpos = code.find(code_tag);
|
||||
cpos = code.find(material_tag);
|
||||
|
||||
if (cpos==-1) {
|
||||
fragment_code1=code.ascii();
|
||||
} else {
|
||||
|
||||
fragment_code1=code.substr(0,cpos).ascii();
|
||||
String code2 = code.substr(cpos+code_tag.length(),code.length());
|
||||
String code2 = code.substr(cpos+material_tag.length(),code.length());
|
||||
|
||||
cpos = code2.find(light_code_tag);
|
||||
cpos = code2.find(code_tag);
|
||||
if (cpos==-1) {
|
||||
fragment_code2=code2.ascii();
|
||||
} else {
|
||||
|
||||
fragment_code2=code2.substr(0,cpos).ascii();
|
||||
fragment_code3 = code2.substr(cpos+light_code_tag.length(),code2.length()).ascii();
|
||||
String code3 = code2.substr(cpos+code_tag.length(),code2.length());
|
||||
|
||||
cpos = code3.find(light_code_tag);
|
||||
if (cpos==-1) {
|
||||
fragment_code3=code3.ascii();
|
||||
} else {
|
||||
|
||||
fragment_code3=code3.substr(0,cpos).ascii();
|
||||
fragment_code4 = code3.substr(cpos+light_code_tag.length(),code3.length()).ascii();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -697,7 +740,7 @@ uint32_t ShaderGLES3::create_custom_shader() {
|
|||
return last_custom_code++;
|
||||
}
|
||||
|
||||
void ShaderGLES3::set_custom_shader_code(uint32_t p_code_id, const String& p_vertex, const String& p_vertex_globals,const String& p_fragment,const String& p_light, const String& p_fragment_globals,const Vector<StringName>& p_uniforms,const Vector<const char*> &p_custom_defines) {
|
||||
void ShaderGLES3::set_custom_shader_code(uint32_t p_code_id, const String& p_vertex, const String& p_vertex_globals, const String& p_fragment, const String& p_light, const String& p_fragment_globals, const String &p_uniforms, const Vector<StringName> &p_texture_uniforms, const Vector<CharString> &p_custom_defines) {
|
||||
|
||||
ERR_FAIL_COND(!custom_code_map.has(p_code_id));
|
||||
CustomCode *cc=&custom_code_map[p_code_id];
|
||||
|
@ -707,7 +750,8 @@ void ShaderGLES3::set_custom_shader_code(uint32_t p_code_id, const String& p_ver
|
|||
cc->fragment=p_fragment;
|
||||
cc->fragment_globals=p_fragment_globals;
|
||||
cc->light=p_light;
|
||||
cc->custom_uniforms=p_uniforms;
|
||||
cc->texture_uniforms=p_texture_uniforms;
|
||||
cc->uniforms=p_uniforms;
|
||||
cc->custom_defines=p_custom_defines;
|
||||
cc->version++;
|
||||
}
|
||||
|
@ -734,13 +778,16 @@ void ShaderGLES3::free_custom_shader(uint32_t p_code_id) {
|
|||
|
||||
}
|
||||
|
||||
void ShaderGLES3::set_base_material_tex_index(int p_idx) {
|
||||
|
||||
base_material_tex_index=p_idx;
|
||||
}
|
||||
|
||||
ShaderGLES3::ShaderGLES3() {
|
||||
version=NULL;
|
||||
last_custom_code=1;
|
||||
uniforms_dirty = true;
|
||||
|
||||
base_material_tex_index=0;
|
||||
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS,&max_image_units);
|
||||
}
|
||||
|
||||
|
|
|
@ -105,9 +105,10 @@ private:
|
|||
String fragment;
|
||||
String fragment_globals;
|
||||
String light;
|
||||
String uniforms;
|
||||
uint32_t version;
|
||||
Vector<StringName> custom_uniforms;
|
||||
Vector<const char*> custom_defines;
|
||||
Vector<StringName> texture_uniforms;
|
||||
Vector<CharString> custom_defines;
|
||||
|
||||
};
|
||||
|
||||
|
@ -118,7 +119,7 @@ private:
|
|||
GLuint vert_id;
|
||||
GLuint frag_id;
|
||||
GLint *uniform_location;
|
||||
Vector<GLint> custom_uniform_locations;
|
||||
Vector<GLint> texture_uniform_locations;
|
||||
uint32_t code_version;
|
||||
bool ok;
|
||||
Version() { code_version=0; ok=false; uniform_location=NULL; }
|
||||
|
@ -166,10 +167,14 @@ private:
|
|||
CharString fragment_code1;
|
||||
CharString fragment_code2;
|
||||
CharString fragment_code3;
|
||||
CharString fragment_code4;
|
||||
|
||||
CharString vertex_code0;
|
||||
CharString vertex_code1;
|
||||
CharString vertex_code2;
|
||||
CharString vertex_code3;
|
||||
|
||||
int base_material_tex_index;
|
||||
|
||||
Version * get_current_version();
|
||||
|
||||
|
@ -308,7 +313,7 @@ public:
|
|||
void clear_caches();
|
||||
|
||||
uint32_t create_custom_shader();
|
||||
void set_custom_shader_code(uint32_t p_id,const String& p_vertex, const String& p_vertex_globals,const String& p_fragment,const String& p_p_light,const String& p_fragment_globals,const Vector<StringName>& p_uniforms,const Vector<const char*> &p_custom_defines);
|
||||
void set_custom_shader_code(uint32_t p_id,const String& p_vertex, const String& p_vertex_globals,const String& p_fragment,const String& p_p_light,const String& p_fragment_globals,const String& p_uniforms,const Vector<StringName>& p_texture_uniforms,const Vector<CharString> &p_custom_defines);
|
||||
void set_custom_shader(uint32_t p_id);
|
||||
void free_custom_shader(uint32_t p_id);
|
||||
|
||||
|
@ -332,23 +337,25 @@ public:
|
|||
uniforms_dirty = true;
|
||||
};
|
||||
|
||||
_FORCE_INLINE_ void set_custom_uniform(int p_idx, const Variant& p_value) {
|
||||
_FORCE_INLINE_ void set_texture_uniform(int p_idx, const Variant& p_value) {
|
||||
|
||||
ERR_FAIL_COND(!version);
|
||||
ERR_FAIL_INDEX(p_idx,version->custom_uniform_locations.size());
|
||||
_set_uniform_variant( version->custom_uniform_locations[p_idx], p_value );
|
||||
ERR_FAIL_INDEX(p_idx,version->texture_uniform_locations.size());
|
||||
_set_uniform_variant( version->texture_uniform_locations[p_idx], p_value );
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ GLint get_custom_uniform_location(int p_idx) {
|
||||
_FORCE_INLINE_ GLint get_texture_uniform_location(int p_idx) {
|
||||
|
||||
ERR_FAIL_COND_V(!version,-1);
|
||||
ERR_FAIL_INDEX_V(p_idx,version->custom_uniform_locations.size(),-1);
|
||||
return version->custom_uniform_locations[p_idx];
|
||||
ERR_FAIL_INDEX_V(p_idx,version->texture_uniform_locations.size(),-1);
|
||||
return version->texture_uniform_locations[p_idx];
|
||||
}
|
||||
|
||||
virtual void init()=0;
|
||||
void finish();
|
||||
|
||||
void set_base_material_tex_index(int p_idx);
|
||||
|
||||
virtual ~ShaderGLES3();
|
||||
|
||||
};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[vertex]
|
||||
|
||||
|
||||
layout(location=0) in highp vec3 vertex;
|
||||
layout(location=0) in highp vec2 vertex;
|
||||
layout(location=3) in vec4 color_attrib;
|
||||
|
||||
#ifdef USE_TEXTURE_RECT
|
||||
|
@ -20,6 +20,7 @@ layout(location=4) in highp vec2 uv_attrib;
|
|||
layout(std140) uniform CanvasItemData { //ubo:0
|
||||
|
||||
highp mat4 projection_matrix;
|
||||
highp vec4 time;
|
||||
};
|
||||
|
||||
uniform highp mat4 modelview_matrix;
|
||||
|
@ -29,10 +30,6 @@ uniform highp mat4 extra_matrix;
|
|||
out mediump vec2 uv_interp;
|
||||
out mediump vec4 color_interp;
|
||||
|
||||
#if defined(USE_TIME)
|
||||
uniform float time;
|
||||
#endif
|
||||
|
||||
#ifdef USE_LIGHTING
|
||||
|
||||
layout(std140) uniform LightData { //ubo:1
|
||||
|
@ -51,6 +48,7 @@ layout(std140) uniform LightData { //ubo:1
|
|||
highp float shadow_distance_mult;
|
||||
};
|
||||
|
||||
|
||||
out vec4 light_uv_interp;
|
||||
|
||||
#if defined(NORMAL_USED)
|
||||
|
@ -66,20 +64,30 @@ out highp vec2 pos;
|
|||
|
||||
VERTEX_SHADER_GLOBALS
|
||||
|
||||
#if defined(USE_MATERIAL)
|
||||
|
||||
layout(std140) uniform UniformData { //ubo:2
|
||||
|
||||
MATERIAL_UNIFORMS
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
void main() {
|
||||
|
||||
color_interp = color_attrib;
|
||||
vec4 vertex_color = color_attrib;
|
||||
|
||||
|
||||
#ifdef USE_TEXTURE_RECT
|
||||
|
||||
|
||||
uv_interp = src_rect.xy + abs(src_rect.zw) * vertex.xy;
|
||||
highp vec4 outvec = vec4(dst_rect.xy + dst_rect.zw * mix(vertex.xy,vec2(1.0,1.0)-vertex.xy,lessThan(src_rect.zw,vec2(0.0,0.0))),0.0,1.0);
|
||||
uv_interp = src_rect.xy + abs(src_rect.zw) * vertex;
|
||||
highp vec4 outvec = vec4(dst_rect.xy + dst_rect.zw * mix(vertex,vec2(1.0,1.0)-vertex,lessThan(src_rect.zw,vec2(0.0,0.0))),0.0,1.0);
|
||||
|
||||
#else
|
||||
uv_interp = uv_attrib;
|
||||
highp vec4 outvec = vec4(vertex, 1.0);
|
||||
highp vec4 outvec = vec4(vertex,0.0,1.0);
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -90,16 +98,16 @@ VERTEX_SHADER_CODE
|
|||
|
||||
}
|
||||
|
||||
#if !defined(USE_WORLD_VEC)
|
||||
#if !defined(SKIP_TRANSFORM_USED)
|
||||
outvec = extra_matrix * outvec;
|
||||
outvec = modelview_matrix * outvec;
|
||||
#endif
|
||||
|
||||
|
||||
color_interp = vertex_color;
|
||||
|
||||
#ifdef USE_PIXEL_SNAP
|
||||
|
||||
outvec.xy=floor(outvec.xy+0.5);
|
||||
outvec.xy=floor(outvec+0.5);
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -132,20 +140,24 @@ VERTEX_SHADER_CODE
|
|||
|
||||
|
||||
uniform mediump sampler2D color_texture; // texunit:0
|
||||
uniform highp vec2 color_texpixel_size;
|
||||
|
||||
in mediump vec2 uv_interp;
|
||||
in mediump vec4 color_interp;
|
||||
|
||||
|
||||
#if defined(ENABLE_TEXSCREEN)
|
||||
#if defined(SCREEN_TEXTURE_USED)
|
||||
|
||||
uniform sampler2D texscreen_tex; // texunit:-3
|
||||
uniform sampler2D screen_texture; // texunit:-3
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(USE_TIME)
|
||||
uniform float time;
|
||||
#endif
|
||||
layout(std140) uniform CanvasItemData {
|
||||
|
||||
highp mat4 projection_matrix;
|
||||
highp vec4 time;
|
||||
};
|
||||
|
||||
|
||||
#ifdef USE_LIGHTING
|
||||
|
||||
|
@ -188,6 +200,17 @@ FRAGMENT_SHADER_GLOBALS
|
|||
|
||||
layout(location=0) out mediump vec4 frag_color;
|
||||
|
||||
|
||||
#if defined(USE_MATERIAL)
|
||||
|
||||
layout(std140) uniform UniformData {
|
||||
|
||||
MATERIAL_UNIFORMS
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
void main() {
|
||||
|
||||
vec4 color = color_interp;
|
||||
|
@ -195,6 +218,9 @@ void main() {
|
|||
vec3 normal = vec3(0.0,0.0,1.0);
|
||||
#endif
|
||||
|
||||
#if !defined(COLOR_USED)
|
||||
//default behavior, texture by color
|
||||
|
||||
#ifdef USE_DISTANCE_FIELD
|
||||
const float smoothing = 1.0/32.0;
|
||||
float distance = texture(color_texture, uv_interp).a;
|
||||
|
@ -204,6 +230,7 @@ void main() {
|
|||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(ENABLE_SCREEN_UV)
|
||||
vec2 screen_uv = gl_FragCoord.xy*screen_uv_mult;
|
||||
|
@ -211,14 +238,15 @@ void main() {
|
|||
|
||||
|
||||
{
|
||||
#if defined(USE_NORMALMAP)
|
||||
vec3 normal_map=vec3(0.0,0.0,1.0);
|
||||
float normal_depth=1.0;
|
||||
|
||||
#if defined(NORMALMAP_USED)
|
||||
vec3 normal_map=vec3(0.0,0.0,1.0);
|
||||
#endif
|
||||
|
||||
FRAGMENT_SHADER_CODE
|
||||
|
||||
#if defined(USE_NORMALMAP)
|
||||
#if defined(NORMALMAP_USED)
|
||||
normal = mix(vec3(0.0,0.0,1.0), normal_map * vec3(2.0,-2.0,1.0) - vec3( 1.0, -1.0, 0.0 ), normal_depth );
|
||||
#endif
|
||||
|
||||
|
@ -246,7 +274,7 @@ FRAGMENT_SHADER_CODE
|
|||
|
||||
vec2 light_uv = light_uv_interp.xy;
|
||||
vec4 light = texture(light_texture,light_uv) * light_color;
|
||||
#if defined(USE_OUTPUT_SHADOW_COLOR)
|
||||
#if defined(SHADOW_COLOR_USED)
|
||||
vec4 shadow_color=vec4(0.0,0.0,0.0,0.0);
|
||||
#endif
|
||||
|
||||
|
@ -409,7 +437,7 @@ LIGHT_SHADER_CODE
|
|||
#endif
|
||||
|
||||
|
||||
#if defined(USE_OUTPUT_SHADOW_COLOR)
|
||||
#if defined(SHADOW_COLOR_USED)
|
||||
color=mix(shadow_color,color,shadow_attenuation);
|
||||
#else
|
||||
//color*=shadow_attenuation;
|
||||
|
|
|
@ -88,6 +88,10 @@ void OS_Unix::print_error(const char* p_function,const char* p_file,int p_line,c
|
|||
print("\E[1;35mSCRIPT ERROR: %s: \E[0m\E[1m%s\n",p_function,err_details);
|
||||
print("\E[0;35m At: %s:%i.\E[0m\n",p_file,p_line);
|
||||
break;
|
||||
case ERR_SHADER:
|
||||
print("\E[1;36mSHADER ERROR: %s: \E[0m\E[1m%s\n",p_function,err_details);
|
||||
print("\E[0;36m At: %s:%i.\E[0m\n",p_file,p_line);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1727,6 +1727,10 @@ void OS_Windows::print_error(const char* p_function, const char* p_file, int p_l
|
|||
print("SCRIPT ERROR: %s: %s\n", p_function, err_details);
|
||||
print(" At: %s:%i\n", p_file, p_line);
|
||||
break;
|
||||
case ERR_SHADER:
|
||||
print("SHADER ERROR: %s: %s\n", p_function, err_details);
|
||||
print(" At: %s:%i\n", p_file, p_line);
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
@ -1742,6 +1746,7 @@ void OS_Windows::print_error(const char* p_function, const char* p_file, int p_l
|
|||
case ERR_ERROR: basecol = FOREGROUND_RED; break;
|
||||
case ERR_WARNING: basecol = FOREGROUND_RED | FOREGROUND_GREEN; break;
|
||||
case ERR_SCRIPT: basecol = FOREGROUND_RED | FOREGROUND_BLUE; break;
|
||||
case ERR_SHADER: basecol = FOREGROUND_GREEN | FOREGROUND_BLUE; break;
|
||||
}
|
||||
|
||||
basecol |= current_bg;
|
||||
|
@ -1753,6 +1758,7 @@ void OS_Windows::print_error(const char* p_function, const char* p_file, int p_l
|
|||
case ERR_ERROR: print("ERROR: "); break;
|
||||
case ERR_WARNING: print("WARNING: "); break;
|
||||
case ERR_SCRIPT: print("SCRIPT ERROR: "); break;
|
||||
case ERR_SCRIPT: print("SHADER ERROR: "); break;
|
||||
}
|
||||
|
||||
SetConsoleTextAttribute(hCon, current_fg | current_bg | FOREGROUND_INTENSITY);
|
||||
|
@ -1763,6 +1769,7 @@ void OS_Windows::print_error(const char* p_function, const char* p_file, int p_l
|
|||
case ERR_ERROR: print(" At: "); break;
|
||||
case ERR_WARNING: print(" At: "); break;
|
||||
case ERR_SCRIPT: print(" At: "); break;
|
||||
case ERR_SHADER: print(" At: "); break;
|
||||
}
|
||||
|
||||
SetConsoleTextAttribute(hCon, current_fg | current_bg);
|
||||
|
@ -1775,6 +1782,7 @@ void OS_Windows::print_error(const char* p_function, const char* p_file, int p_l
|
|||
case ERR_ERROR: print("ERROR: %s: ", p_function); break;
|
||||
case ERR_WARNING: print("WARNING: %s: ", p_function); break;
|
||||
case ERR_SCRIPT: print("SCRIPT ERROR: %s: ", p_function); break;
|
||||
case ERR_SHADER: print("SCRIPT ERROR: %s: ", p_function); break;
|
||||
}
|
||||
|
||||
SetConsoleTextAttribute(hCon, current_fg | current_bg | FOREGROUND_INTENSITY);
|
||||
|
@ -1785,6 +1793,7 @@ void OS_Windows::print_error(const char* p_function, const char* p_file, int p_l
|
|||
case ERR_ERROR: print(" At: "); break;
|
||||
case ERR_WARNING: print(" At: "); break;
|
||||
case ERR_SCRIPT: print(" At: "); break;
|
||||
case ERR_SHADER: print(" At: "); break;
|
||||
}
|
||||
|
||||
SetConsoleTextAttribute(hCon, current_fg | current_bg);
|
||||
|
|
|
@ -55,7 +55,7 @@ bool CanvasItemMaterial::_set(const StringName& p_name, const Variant& p_value)
|
|||
}
|
||||
}
|
||||
if (pr) {
|
||||
VisualServer::get_singleton()->material_set_param(material,pr,p_value);
|
||||
VisualServer::get_singleton()->material_set_param(_get_material(),pr,p_value);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ bool CanvasItemMaterial::_get(const StringName& p_name,Variant &r_ret) const {
|
|||
|
||||
StringName pr = shader->remap_param(p_name);
|
||||
if (pr) {
|
||||
r_ret=VisualServer::get_singleton()->material_get_param(material,pr);
|
||||
r_ret=VisualServer::get_singleton()->material_get_param(_get_material(),pr);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -111,7 +111,7 @@ void CanvasItemMaterial::set_shader(const Ref<Shader>& p_shader) {
|
|||
if (shader.is_valid())
|
||||
rid=shader->get_rid();
|
||||
|
||||
VS::get_singleton()->material_set_shader(material,rid);
|
||||
VS::get_singleton()->material_set_shader(_get_material(),rid);
|
||||
_change_notify(); //properties for shader exposed
|
||||
emit_changed();
|
||||
}
|
||||
|
@ -123,18 +123,14 @@ Ref<Shader> CanvasItemMaterial::get_shader() const{
|
|||
|
||||
void CanvasItemMaterial::set_shader_param(const StringName& p_param,const Variant& p_value){
|
||||
|
||||
VS::get_singleton()->material_set_param(material,p_param,p_value);
|
||||
VS::get_singleton()->material_set_param(_get_material(),p_param,p_value);
|
||||
}
|
||||
|
||||
Variant CanvasItemMaterial::get_shader_param(const StringName& p_param) const{
|
||||
|
||||
return VS::get_singleton()->material_get_param(material,p_param);
|
||||
return VS::get_singleton()->material_get_param(_get_material(),p_param);
|
||||
}
|
||||
|
||||
RID CanvasItemMaterial::get_rid() const {
|
||||
|
||||
return material;
|
||||
}
|
||||
|
||||
|
||||
void CanvasItemMaterial::_bind_methods() {
|
||||
|
|
|
@ -41,10 +41,9 @@ class Font;
|
|||
|
||||
class StyleBox;
|
||||
|
||||
class CanvasItemMaterial : public Material{
|
||||
class CanvasItemMaterial : public Material {
|
||||
|
||||
OBJ_TYPE(CanvasItemMaterial,Material);
|
||||
RID material;
|
||||
Ref<Shader> shader;
|
||||
public:
|
||||
/*enum ShadingMode {
|
||||
|
@ -70,7 +69,6 @@ public:
|
|||
void set_shader_param(const StringName& p_param,const Variant& p_value);
|
||||
Variant get_shader_param(const StringName& p_param) const;
|
||||
|
||||
virtual RID get_rid() const;
|
||||
CanvasItemMaterial();
|
||||
~CanvasItemMaterial();
|
||||
};
|
||||
|
|
|
@ -34,31 +34,12 @@
|
|||
#include "os/input.h"
|
||||
#include "os/keyboard.h"
|
||||
|
||||
void update_material(Ref<CanvasItemMaterial>mat,const Color& p_color,float h,float s,float v) {
|
||||
if (!mat.is_valid())
|
||||
return;
|
||||
Ref<Shader> sdr = mat->get_shader();
|
||||
if (!sdr.is_valid())
|
||||
return;
|
||||
|
||||
mat->set_shader_param("R",p_color.r);
|
||||
mat->set_shader_param("G",p_color.g);
|
||||
mat->set_shader_param("B",p_color.b);
|
||||
mat->set_shader_param("H",h);
|
||||
mat->set_shader_param("S",s);
|
||||
mat->set_shader_param("V",v);
|
||||
mat->set_shader_param("A",p_color.a);
|
||||
}
|
||||
|
||||
void ColorPicker::_notification(int p_what) {
|
||||
|
||||
|
||||
switch(p_what) {
|
||||
case NOTIFICATION_THEME_CHANGED: {
|
||||
uv_material->set_shader(get_shader("uv_editor"));
|
||||
w_material->set_shader(get_shader("w_editor"));
|
||||
update_material(uv_material,color,h,s,v);
|
||||
update_material(w_material,color,h,s,v);
|
||||
uv_edit->set_texture(get_icon("color_main"));
|
||||
w_edit->set_texture(get_icon("color_hue"));
|
||||
sample->set_texture(get_icon("color_sample"));
|
||||
|
@ -68,8 +49,6 @@ void ColorPicker::_notification(int p_what) {
|
|||
|
||||
case NOTIFICATION_ENTER_TREE: {
|
||||
btn_pick->set_icon(get_icon("screen_picker", "ColorPicker"));
|
||||
update_material(uv_material, color,h,s,v);
|
||||
update_material(w_material, color,h,s,v);
|
||||
|
||||
uv_edit->get_child(0)->cast_to<Control>()->update();
|
||||
w_edit->get_child(0)->cast_to<Control>()->update();
|
||||
|
@ -113,8 +92,6 @@ void ColorPicker::set_color(const Color& p_color) {
|
|||
if (!is_inside_tree())
|
||||
return;
|
||||
|
||||
update_material(uv_material, color,h,s,v);
|
||||
update_material(w_material, color,h,s,v);
|
||||
|
||||
uv_edit->get_child(0)->cast_to<Control>()->update();
|
||||
w_edit->get_child(0)->cast_to<Control>()->update();
|
||||
|
@ -509,7 +486,6 @@ ColorPicker::ColorPicker() :
|
|||
uv_edit->add_child(c);
|
||||
c->set_area_as_parent_rect();
|
||||
c->set_stop_mouse(false);
|
||||
c->set_material(memnew ( CanvasItemMaterial ));
|
||||
Vector<Variant> args=Vector<Variant>();
|
||||
args.push_back(0);
|
||||
args.push_back(c);
|
||||
|
@ -525,7 +501,6 @@ ColorPicker::ColorPicker() :
|
|||
w_edit->add_child(c);
|
||||
c->set_area_as_parent_rect();
|
||||
c->set_stop_mouse(false);
|
||||
c->set_material(memnew ( CanvasItemMaterial ));
|
||||
args.clear();
|
||||
args.push_back(1);
|
||||
args.push_back(c);
|
||||
|
@ -593,18 +568,6 @@ ColorPicker::ColorPicker() :
|
|||
//_update_color();
|
||||
updating=false;
|
||||
|
||||
uv_material.instance();
|
||||
Ref<Shader> s_uv = get_shader("uv_editor");
|
||||
uv_material->set_shader(s_uv);
|
||||
|
||||
w_material.instance();
|
||||
|
||||
Ref<Shader> s_w = get_shader("w_editor");
|
||||
w_material->set_shader(s_w);
|
||||
|
||||
uv_edit->set_material(uv_material);
|
||||
w_edit->set_material(w_material);
|
||||
|
||||
set_color(Color(1,1,1));
|
||||
|
||||
|
||||
|
|
|
@ -57,8 +57,6 @@ private:
|
|||
List<Color> presets;
|
||||
ToolButton *btn_pick;
|
||||
CheckButton *btn_mode;
|
||||
Ref<CanvasItemMaterial> uv_material;
|
||||
Ref<CanvasItemMaterial> w_material;
|
||||
HSlider *scroll[4];
|
||||
SpinBox *values[4];
|
||||
Label *labels[4];
|
||||
|
|
|
@ -46,6 +46,9 @@ class Material : public Resource {
|
|||
OBJ_SAVE_TYPE( Material );
|
||||
|
||||
RID material;
|
||||
protected:
|
||||
|
||||
_FORCE_INLINE_ RID _get_material() const { return material; }
|
||||
public:
|
||||
|
||||
virtual RID get_rid() const;
|
||||
|
|
|
@ -712,6 +712,8 @@ bool ShaderLanguage::is_token_nonvoid_datatype(TokenType p_type) {
|
|||
|
||||
void ShaderLanguage::clear() {
|
||||
|
||||
current_function=StringName();
|
||||
|
||||
completion_type=COMPLETION_NONE;
|
||||
completion_block=NULL;
|
||||
completion_function=StringName();
|
||||
|
@ -2096,6 +2098,12 @@ bool ShaderLanguage::is_scalar_type(DataType p_type) {
|
|||
return p_type==TYPE_BOOL || p_type==TYPE_INT || p_type==TYPE_UINT || p_type==TYPE_FLOAT;
|
||||
}
|
||||
|
||||
bool ShaderLanguage::is_sampler_type(DataType p_type) {
|
||||
|
||||
return p_type==TYPE_SAMPLER2D || p_type==TYPE_ISAMPLER2D || p_type==TYPE_USAMPLER2D || p_type==TYPE_SAMPLERCUBE;
|
||||
|
||||
}
|
||||
|
||||
void ShaderLanguage::get_keyword_list(List<String> *r_keywords) {
|
||||
|
||||
Set<String> kws;
|
||||
|
@ -2122,6 +2130,27 @@ void ShaderLanguage::get_keyword_list(List<String> *r_keywords) {
|
|||
}
|
||||
}
|
||||
|
||||
void ShaderLanguage::get_builtin_funcs(List<String> *r_keywords) {
|
||||
|
||||
|
||||
Set<String> kws;
|
||||
|
||||
int idx=0;
|
||||
|
||||
while (builtin_func_defs[idx].name) {
|
||||
|
||||
kws.insert(builtin_func_defs[idx].name);
|
||||
|
||||
idx++;
|
||||
}
|
||||
|
||||
for(Set<String>::Element *E=kws.front();E;E=E->next()) {
|
||||
r_keywords->push_back(E->get());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
ShaderLanguage::DataType ShaderLanguage::get_scalar_type(DataType p_type) {
|
||||
|
||||
static const DataType scalar_types[]={
|
||||
|
@ -2342,6 +2371,12 @@ ShaderLanguage::Node* ShaderLanguage::_parse_expression(BlockNode* p_block,const
|
|||
|
||||
bool ok =_parse_function_arguments(p_block,p_builtin_types,func,&carg);
|
||||
|
||||
for(int i=0;i<shader->functions.size();i++) {
|
||||
if (shader->functions[i].name==name) {
|
||||
shader->functions[i].uses_function.insert(name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (carg>=0) {
|
||||
|
@ -3140,6 +3175,9 @@ Error ShaderLanguage::_parse_shader(const Map< StringName, Map<StringName,DataTy
|
|||
|
||||
Token tk = _get_token();
|
||||
|
||||
int texture_uniforms = 0;
|
||||
int uniforms =0;
|
||||
|
||||
while(tk.type!=TK_EOF) {
|
||||
|
||||
switch(tk.type) {
|
||||
|
@ -3160,12 +3198,12 @@ Error ShaderLanguage::_parse_shader(const Map< StringName, Map<StringName,DataTy
|
|||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
|
||||
if (shader->render_modes.has(tk.text)) {
|
||||
if (shader->render_modes.find(tk.text)!=-1) {
|
||||
_set_error("Duplicate render mode: '"+String(tk.text)+"'");
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
|
||||
shader->render_modes.insert(tk.text);
|
||||
shader->render_modes.push_back(tk.text);
|
||||
|
||||
tk = _get_token();
|
||||
if (tk.type==TK_COMMA) {
|
||||
|
@ -3225,6 +3263,13 @@ Error ShaderLanguage::_parse_shader(const Map< StringName, Map<StringName,DataTy
|
|||
|
||||
ShaderNode::Uniform uniform;
|
||||
uniform.order=shader->uniforms.size();
|
||||
if (is_sampler_type(type)) {
|
||||
uniform.texture_order=texture_uniforms++;
|
||||
uniform.order=-1;
|
||||
} else {
|
||||
uniform.texture_order=-1;
|
||||
uniform.order=uniforms++;
|
||||
}
|
||||
uniform.type=type;
|
||||
uniform.precission=precision;
|
||||
|
||||
|
@ -3520,9 +3565,13 @@ Error ShaderLanguage::_parse_shader(const Map< StringName, Map<StringName,DataTy
|
|||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
|
||||
current_function = name;
|
||||
|
||||
Error err = _parse_block(func_node->body,builtin_types);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
current_function=StringName();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -370,6 +370,7 @@ public:
|
|||
struct Function {
|
||||
StringName name;
|
||||
FunctionNode*function;
|
||||
Set<StringName> uses_function;
|
||||
bool callable;
|
||||
};
|
||||
|
||||
|
@ -391,6 +392,7 @@ public:
|
|||
};
|
||||
|
||||
int order;
|
||||
int texture_order;
|
||||
DataType type;
|
||||
DataPrecision precission;
|
||||
Vector<ConstantNode::Value> default_value;
|
||||
|
@ -403,7 +405,7 @@ public:
|
|||
|
||||
Map<StringName,Varying> varyings;
|
||||
Map<StringName,Uniform> uniforms;
|
||||
Set<StringName> render_modes;
|
||||
Vector<StringName> render_modes;
|
||||
|
||||
Vector<Function> functions;
|
||||
|
||||
|
@ -461,8 +463,10 @@ public:
|
|||
static bool convert_constant(ConstantNode* p_constant, DataType p_to_type,ConstantNode::Value *p_value=NULL);
|
||||
static DataType get_scalar_type(DataType p_type);
|
||||
static bool is_scalar_type(DataType p_type);
|
||||
static bool is_sampler_type(DataType p_type);
|
||||
|
||||
static void get_keyword_list(List<String> *r_keywords);
|
||||
static void get_builtin_funcs(List<String> *r_keywords);
|
||||
private:
|
||||
|
||||
struct KeyWord { TokenType token; const char *text;};
|
||||
|
@ -476,6 +480,8 @@ private:
|
|||
int char_idx;
|
||||
int tk_line;
|
||||
|
||||
StringName current_function;
|
||||
|
||||
struct TkPos {
|
||||
int char_idx;
|
||||
int tk_line;
|
||||
|
|
|
@ -18,6 +18,7 @@ ShaderTypes::ShaderTypes()
|
|||
{
|
||||
singleton=this;
|
||||
|
||||
/*************** SPATIAL ***********************/
|
||||
|
||||
shader_modes[VS::SHADER_SPATIAL].functions["vertex"]["SRC_VERTEX"]=ShaderLanguage::TYPE_VEC3;
|
||||
shader_modes[VS::SHADER_SPATIAL].functions["vertex"]["SRC_NORMAL"]=ShaderLanguage::TYPE_VEC3;
|
||||
|
@ -96,4 +97,65 @@ ShaderTypes::ShaderTypes()
|
|||
shader_modes[VS::SHADER_SPATIAL].modes.insert("vertex_model_space");
|
||||
shader_modes[VS::SHADER_SPATIAL].modes.insert("vertex_camera_space");
|
||||
|
||||
/************ CANVAS ITEM **************************/
|
||||
|
||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"]["SRC_VERTEX"]=ShaderLanguage::TYPE_VEC2;
|
||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"]["VERTEX"]=ShaderLanguage::TYPE_VEC2;
|
||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"]["UV"]=ShaderLanguage::TYPE_VEC2;
|
||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"]["VERTEX_COLOR"]=ShaderLanguage::TYPE_VEC4;
|
||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"]["POINT_SIZE"]=ShaderLanguage::TYPE_FLOAT;
|
||||
|
||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"]["WORLD_MATRIX"]=ShaderLanguage::TYPE_MAT4;
|
||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"]["PROJECTION_MATRIX"]=ShaderLanguage::TYPE_MAT4;
|
||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"]["EXTRA_MATRIX"]=ShaderLanguage::TYPE_MAT4;
|
||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"]["TIME"]=ShaderLanguage::TYPE_FLOAT;
|
||||
|
||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"]["SRC_COLOR"]=ShaderLanguage::TYPE_VEC4;
|
||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"]["POSITION"]=ShaderLanguage::TYPE_VEC4;
|
||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"]["NORMAL"]=ShaderLanguage::TYPE_VEC3;
|
||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"]["NORMALMAP"]=ShaderLanguage::TYPE_VEC3;
|
||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"]["NORMALMAP_DEPTH"]=ShaderLanguage::TYPE_FLOAT;
|
||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"]["UV"]=ShaderLanguage::TYPE_VEC2;
|
||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"]["COLOR"]=ShaderLanguage::TYPE_VEC4;
|
||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"]["TEXTURE"]=ShaderLanguage::TYPE_SAMPLER2D;
|
||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"]["TEXTURE_PIXEL_SIZE"]=ShaderLanguage::TYPE_VEC2;
|
||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"]["SCREEN_UV"]=ShaderLanguage::TYPE_VEC2;
|
||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"]["POINT_COORD"]=ShaderLanguage::TYPE_VEC2;
|
||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"]["TIME"]=ShaderLanguage::TYPE_FLOAT;
|
||||
|
||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"]["POSITION"]=ShaderLanguage::TYPE_VEC4;
|
||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"]["NORMAL"]=ShaderLanguage::TYPE_VEC3;
|
||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"]["UV"]=ShaderLanguage::TYPE_VEC2;
|
||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"]["COLOR"]=ShaderLanguage::TYPE_VEC4;
|
||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"]["TEXTURE"]=ShaderLanguage::TYPE_SAMPLER2D;
|
||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"]["TEXTURE_PIXEL_SIZE"]=ShaderLanguage::TYPE_VEC2;
|
||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"]["VAR1"]=ShaderLanguage::TYPE_VEC4;
|
||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"]["VAR2"]=ShaderLanguage::TYPE_VEC4;
|
||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"]["SCREEN_UV"]=ShaderLanguage::TYPE_VEC2;
|
||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"]["LIGHT_VEC"]=ShaderLanguage::TYPE_VEC2;
|
||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"]["LIGHT_HEIGHT"]=ShaderLanguage::TYPE_FLOAT;
|
||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"]["LIGHT_COLOR"]=ShaderLanguage::TYPE_VEC4;
|
||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"]["LIGHT_UV"]=ShaderLanguage::TYPE_VEC2;
|
||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"]["LIGHT_SHADOW"]=ShaderLanguage::TYPE_VEC4;
|
||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"]["LIGHT"]=ShaderLanguage::TYPE_VEC4;
|
||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"]["SHADOW"]=ShaderLanguage::TYPE_VEC4;
|
||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"]["POINT_COORD"]=ShaderLanguage::TYPE_VEC2;
|
||||
shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"]["TIME"]=ShaderLanguage::TYPE_FLOAT;
|
||||
|
||||
shader_modes[VS::SHADER_SPATIAL].modes.insert("skip_transform");
|
||||
|
||||
shader_modes[VS::SHADER_SPATIAL].modes.insert("blend_mix");
|
||||
shader_modes[VS::SHADER_SPATIAL].modes.insert("blend_add");
|
||||
shader_modes[VS::SHADER_SPATIAL].modes.insert("blend_sub");
|
||||
shader_modes[VS::SHADER_SPATIAL].modes.insert("blend_mul");
|
||||
shader_modes[VS::SHADER_SPATIAL].modes.insert("blend_premul_alpha");
|
||||
|
||||
shader_modes[VS::SHADER_SPATIAL].modes.insert("unshaded");
|
||||
shader_modes[VS::SHADER_SPATIAL].modes.insert("light_only");
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -140,6 +140,7 @@ public:
|
|||
SHADER_SPATIAL,
|
||||
SHADER_CANVAS_ITEM,
|
||||
SHADER_LIGHT,
|
||||
SHADER_MAX
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -67,6 +67,10 @@ void EditorLog::_error_handler(void *p_self, const char*p_func, const char*p_fil
|
|||
|
||||
icon = self->get_icon("ScriptError","EditorIcons");
|
||||
} break;
|
||||
case ERR_HANDLER_SHADER: {
|
||||
|
||||
icon = self->get_icon("Shader","EditorIcons");
|
||||
} break;
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue