summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/SCsub20
-rw-r--r--drivers/gles2/rasterizer_gles2.cpp116
-rw-r--r--drivers/gles2/rasterizer_gles2.h6
-rw-r--r--drivers/gles2/shader_compiler_gles2.cpp238
-rw-r--r--drivers/gles2/shader_compiler_gles2.h5
-rw-r--r--drivers/nrex/README.md57
-rw-r--r--drivers/nrex/nrex.cpp790
-rw-r--r--drivers/nrex/nrex.hpp10
-rw-r--r--drivers/nrex/regex.cpp10
-rw-r--r--drivers/nrex/regex.h2
-rw-r--r--drivers/opus/opus_config.h8
-rw-r--r--drivers/theora/decode.c46
-rw-r--r--drivers/theora/video_stream_theora.cpp58
-rw-r--r--drivers/theora/video_stream_theora.h3
-rw-r--r--drivers/unix/os_unix.cpp28
-rw-r--r--drivers/vorbis/audio_stream_ogg_vorbis.cpp3
-rw-r--r--drivers/vorbis/audio_stream_ogg_vorbis.h2
17 files changed, 996 insertions, 406 deletions
diff --git a/drivers/SCsub b/drivers/SCsub
index bc46bf2cec..2361968a43 100644
--- a/drivers/SCsub
+++ b/drivers/SCsub
@@ -69,21 +69,27 @@ for f in env.drivers_sources:
fname = env.File(f).path
else:
fname = env.File(f)[0].path
- #base = string.join(fname.split("/")[:-1], "/")
fname = fname.replace("\\", "/")
base = string.join(fname.split("/")[:2], "/")
if base != cur_base and len(list) > max_src:
- lib = env.Library("drivers"+str(num), list)
- lib_list.append(lib)
- list = []
+ if num > 0:
+ lib = env.Library("drivers"+str(num), list)
+ lib_list.append(lib)
+ list = []
num = num+1
cur_base = base
list.append(f)
-if len(list) > 0:
- lib = env.Library("drivers"+str(num), list)
- lib_list.append(lib)
+lib = env.Library("drivers"+str(num), list)
+lib_list.append(lib)
+if len(lib_list) > 0:
+ import os, sys
+ if os.name=='posix' and sys.platform=='msys':
+ env.Replace(ARFLAGS=['rcsT'])
+
+ lib = env.Library("drivers_collated", lib_list)
+ lib_list = [lib]
drivers_base=[]
env.add_source_files(drivers_base,"*.cpp")
diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp
index d84ee5a758..b473e8493f 100644
--- a/drivers/gles2/rasterizer_gles2.cpp
+++ b/drivers/gles2/rasterizer_gles2.cpp
@@ -4075,6 +4075,8 @@ void RasterizerGLES2::render_target_set_size(RID p_render_target,int p_width,int
glDeleteTextures(1,&rt->color);
rt->fbo=0;
+ rt->depth=0;
+ rt->color=0;
rt->width=0;
rt->height=0;
rt->texture_ptr->tex_id=0;
@@ -4094,12 +4096,14 @@ void RasterizerGLES2::render_target_set_size(RID p_render_target,int p_width,int
glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo);
//depth
- glGenRenderbuffers(1, &rt->depth);
- glBindRenderbuffer(GL_RENDERBUFFER, rt->depth );
+ if (!low_memory_2d) {
+ glGenRenderbuffers(1, &rt->depth);
+ glBindRenderbuffer(GL_RENDERBUFFER, rt->depth );
- glRenderbufferStorage(GL_RENDERBUFFER, use_depth24?_DEPTH_COMPONENT24_OES:GL_DEPTH_COMPONENT16, rt->width,rt->height);
+ glRenderbufferStorage(GL_RENDERBUFFER, use_depth24?_DEPTH_COMPONENT24_OES:GL_DEPTH_COMPONENT16, rt->width,rt->height);
- glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->depth);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->depth);
+ }
//color
glGenTextures(1, &rt->color);
@@ -4641,6 +4645,9 @@ void RasterizerGLES2::_update_shader( Shader* p_shader) const {
enablers.push_back("#define USE_TIME\n");
uses_time=true;
}
+ if (vertex_flags.vertex_code_writes_position) {
+ enablers.push_back("#define VERTEX_SHADER_WRITE_POSITION\n");
+ }
material_shader.set_custom_shader_code(p_shader->custom_code_id,vertex_code, vertex_globals,fragment_code, light_code, fragment_globals,uniform_names,enablers);
} else if (p_shader->mode==VS::SHADER_CANVAS_ITEM) {
@@ -6526,80 +6533,84 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans
material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_LIGHTMAP,false);
material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_DP_SAMPLER,false);
- if (e->instance->sampled_light.is_valid()) {
+ if (material->flags[VS::MATERIAL_FLAG_UNSHADED] == false && current_debug != VS::SCENARIO_DEBUG_SHADELESS) {
- SampledLight *sl = sampled_light_owner.get(e->instance->sampled_light);
- if (sl) {
+ if (e->instance->sampled_light.is_valid()) {
- baked_light=NULL; //can't mix
- material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_DP_SAMPLER,true);
- glActiveTexture(GL_TEXTURE0+max_texture_units-3);
- glBindTexture(GL_TEXTURE_2D,sl->texture); //bind the texture
- sampled_light_dp_multiplier=sl->multiplier;
- bind_dp_sampler=true;
+ SampledLight *sl = sampled_light_owner.get(e->instance->sampled_light);
+ if (sl) {
+
+ baked_light = NULL; //can't mix
+ material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_DP_SAMPLER, true);
+ glActiveTexture(GL_TEXTURE0 + max_texture_units - 3);
+ glBindTexture(GL_TEXTURE_2D, sl->texture); //bind the texture
+ sampled_light_dp_multiplier = sl->multiplier;
+ bind_dp_sampler = true;
+ }
}
- }
- if (!additive && baked_light) {
+ if (!additive && baked_light) {
- if (baked_light->mode==VS::BAKED_LIGHT_OCTREE && baked_light->octree_texture.is_valid() && e->instance->baked_light_octree_xform) {
- material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_OCTREE,true);
- bind_baked_light_octree=true;
- if (prev_baked_light!=baked_light) {
- Texture *tex=texture_owner.get(baked_light->octree_texture);
- if (tex) {
+ if (baked_light->mode == VS::BAKED_LIGHT_OCTREE && baked_light->octree_texture.is_valid() && e->instance->baked_light_octree_xform) {
+ material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_OCTREE, true);
+ bind_baked_light_octree = true;
+ if (prev_baked_light != baked_light) {
+ Texture *tex = texture_owner.get(baked_light->octree_texture);
+ if (tex) {
- glActiveTexture(GL_TEXTURE0+max_texture_units-3);
- glBindTexture(tex->target,tex->tex_id); //bind the texture
- }
- if (baked_light->light_texture.is_valid()) {
- Texture *texl=texture_owner.get(baked_light->light_texture);
- if (texl) {
- glActiveTexture(GL_TEXTURE0+max_texture_units-4);
- glBindTexture(texl->target,texl->tex_id); //bind the light texture
+ glActiveTexture(GL_TEXTURE0 + max_texture_units - 3);
+ glBindTexture(tex->target, tex->tex_id); //bind the texture
+ }
+ if (baked_light->light_texture.is_valid()) {
+ Texture *texl = texture_owner.get(baked_light->light_texture);
+ if (texl) {
+ glActiveTexture(GL_TEXTURE0 + max_texture_units - 4);
+ glBindTexture(texl->target, texl->tex_id); //bind the light texture
+ }
}
- }
+ }
}
- } else if (baked_light->mode==VS::BAKED_LIGHT_LIGHTMAPS) {
+ else if (baked_light->mode == VS::BAKED_LIGHT_LIGHTMAPS) {
- int lightmap_idx = e->instance->baked_lightmap_id;
+ int lightmap_idx = e->instance->baked_lightmap_id;
- material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_LIGHTMAP,false);
- bind_baked_lightmap=false;
+ material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_LIGHTMAP, false);
+ bind_baked_lightmap = false;
- if (baked_light->lightmaps.has(lightmap_idx)) {
+ if (baked_light->lightmaps.has(lightmap_idx)) {
- RID texid = baked_light->lightmaps[lightmap_idx];
+ RID texid = baked_light->lightmaps[lightmap_idx];
- if (prev_baked_light!=baked_light || texid!=prev_baked_light_texture) {
+ if (prev_baked_light != baked_light || texid != prev_baked_light_texture) {
- Texture *tex = texture_owner.get(texid);
- if (tex) {
+ Texture *tex = texture_owner.get(texid);
+ if (tex) {
+
+ glActiveTexture(GL_TEXTURE0 + max_texture_units - 3);
+ glBindTexture(tex->target, tex->tex_id); //bind the texture
+ }
- glActiveTexture(GL_TEXTURE0+max_texture_units-3);
- glBindTexture(tex->target,tex->tex_id); //bind the texture
+ prev_baked_light_texture = texid;
}
- prev_baked_light_texture=texid;
- }
+ if (texid.is_valid()) {
+ material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_LIGHTMAP, true);
+ bind_baked_lightmap = true;
+ }
- if (texid.is_valid()) {
- material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_LIGHTMAP,true);
- bind_baked_lightmap=true;
}
-
}
}
- }
- if (int(prev_baked_light!=NULL) ^ int(baked_light!=NULL)) {
- rebind=true;
+ if (int(prev_baked_light != NULL) ^ int(baked_light != NULL)) {
+ rebind = true;
+ }
}
}
@@ -10293,7 +10304,11 @@ void RasterizerGLES2::_update_framebuffer() {
framebuffer.fbo=0;
}
+#ifdef TOOLS_ENABLED
framebuffer.active=use_fbo;
+#else
+ framebuffer.active=use_fbo && !low_memory_2d;
+#endif
framebuffer.width=dwidth;
framebuffer.height=dheight;
framebuffer.scale=scale;
@@ -11203,6 +11218,7 @@ RasterizerGLES2::RasterizerGLES2(bool p_compress_arrays,bool p_keep_ram_copy,boo
use_fp16_fb=bool(GLOBAL_DEF("rasterizer/fp16_framebuffer",true));
use_shadow_mapping=true;
use_fast_texture_filter=!bool(GLOBAL_DEF("rasterizer/trilinear_mipmap_filter",true));
+ low_memory_2d=bool(GLOBAL_DEF("rasterizer/low_memory_2d_mode",false));
skel_default.resize(1024*4);
for(int i=0;i<1024/3;i++) {
diff --git a/drivers/gles2/rasterizer_gles2.h b/drivers/gles2/rasterizer_gles2.h
index 507e46ae75..d6d9593da8 100644
--- a/drivers/gles2/rasterizer_gles2.h
+++ b/drivers/gles2/rasterizer_gles2.h
@@ -105,13 +105,13 @@ class RasterizerGLES2 : public Rasterizer {
float anisotropic_level;
bool use_half_float;
-
+ bool low_memory_2d;
Vector<float> skel_default;
Image _get_gl_image_and_format(const Image& p_image, Image::Format p_format, uint32_t p_flags,GLenum& r_gl_format,GLenum& r_gl_internal_format,int &r_gl_components,bool &r_has_alpha_cache,bool &r_compressed);
- class RenderTarget;
+ struct RenderTarget;
struct Texture {
@@ -305,7 +305,7 @@ class RasterizerGLES2 : public Rasterizer {
virtual ~GeometryOwner() {}
};
- class Mesh;
+ struct Mesh;
struct Surface : public Geometry {
diff --git a/drivers/gles2/shader_compiler_gles2.cpp b/drivers/gles2/shader_compiler_gles2.cpp
index d57512c936..c8f59ce22b 100644
--- a/drivers/gles2/shader_compiler_gles2.cpp
+++ b/drivers/gles2/shader_compiler_gles2.cpp
@@ -154,6 +154,9 @@ String ShaderCompilerGLES2::dump_node_code(SL::Node *p_node,int p_level,bool p_a
if (vnode->name==vname_vertex && p_assign_left) {
vertex_code_writes_vertex=true;
}
+ if (vnode->name == vname_position && p_assign_left) {
+ vertex_code_writes_position = true;
+ }
if (vnode->name==vname_color_interp) {
flags->use_color_interp=true;
}
@@ -659,6 +662,7 @@ Error ShaderCompilerGLES2::compile(const String& p_code, ShaderLanguage::ShaderT
uses_texpixel_size=false;
uses_worldvec=false;
vertex_code_writes_vertex=false;
+ vertex_code_writes_position = false;
uses_shadow_color=false;
uniforms=r_uniforms;
flags=&r_flags;
@@ -690,6 +694,7 @@ Error ShaderCompilerGLES2::compile(const String& p_code, ShaderLanguage::ShaderT
r_flags.uses_texscreen=uses_texscreen;
r_flags.uses_texpos=uses_texpos;
r_flags.vertex_code_writes_vertex=vertex_code_writes_vertex;
+ r_flags.vertex_code_writes_position=vertex_code_writes_position;
r_flags.uses_discard=uses_discard;
r_flags.uses_screen_uv=uses_screen_uv;
r_flags.uses_light=uses_light;
@@ -778,125 +783,127 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() {
replace_table["texscreen"]= "texscreen";
replace_table["texpos"]= "texpos";
- mode_replace_table[0]["SRC_VERTEX"]="vertex_in.xyz";
- mode_replace_table[0]["SRC_NORMAL"]="normal_in";
- mode_replace_table[0]["SRC_TANGENT"]="tangent_in";
- mode_replace_table[0]["SRC_BINORMALF"]="binormalf";
-
- mode_replace_table[0]["VERTEX"]="vertex_interp";
- mode_replace_table[0]["NORMAL"]="normal_interp";
- mode_replace_table[0]["TANGENT"]="tangent_interp";
- mode_replace_table[0]["BINORMAL"]="binormal_interp";
- mode_replace_table[0]["UV"]="uv_interp.xy";
- mode_replace_table[0]["UV2"]="uv_interp.zw";
- mode_replace_table[0]["COLOR"]="color_interp";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["POSITION"] = "gl_Position";
+
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["SRC_VERTEX"] = "vertex_in.xyz";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["SRC_NORMAL"] = "normal_in";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["SRC_TANGENT"]="tangent_in";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["SRC_BINORMALF"]="binormalf";
+
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["VERTEX"]="vertex_interp";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["NORMAL"]="normal_interp";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["TANGENT"]="tangent_interp";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["BINORMAL"]="binormal_interp";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["UV"]="uv_interp.xy";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["UV2"]="uv_interp.zw";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["COLOR"]="color_interp";
//@TODO convert to glsl stuff
- mode_replace_table[0]["SPEC_EXP"]="vertex_specular_exp";
- mode_replace_table[0]["WORLD_MATRIX"]="world_transform";
- mode_replace_table[0]["INV_CAMERA_MATRIX"]="camera_inverse_transform";
- mode_replace_table[0]["PROJECTION_MATRIX"]="projection_transform";
- mode_replace_table[0]["MODELVIEW_MATRIX"]="modelview";
- mode_replace_table[0]["POINT_SIZE"]="gl_PointSize";
- mode_replace_table[0]["VAR1"]="var1_interp";
- mode_replace_table[0]["VAR2"]="var2_interp";
-
-// mode_replace_table[0]["SCREEN_POS"]="SCREEN_POS";
-// mode_replace_table[0]["SCREEN_SIZE"]="SCREEN_SIZE";
- mode_replace_table[0]["INSTANCE_ID"]="instance_id";
- mode_replace_table[0]["TIME"]="time";
-
- mode_replace_table[1]["VERTEX"]="vertex";
- //mode_replace_table[1]["POSITION"]="IN_POSITION";
- mode_replace_table[1]["NORMAL"]="normal";
- mode_replace_table[1]["TANGENT"]="tangent";
- mode_replace_table[1]["POSITION"]="gl_Position";
- mode_replace_table[1]["BINORMAL"]="binormal";
- mode_replace_table[1]["NORMALMAP"]="normalmap";
- mode_replace_table[1]["NORMALMAP_DEPTH"]="normaldepth";
- mode_replace_table[1]["VAR1"]="var1_interp";
- mode_replace_table[1]["VAR2"]="var2_interp";
- mode_replace_table[1]["UV"]="uv";
- mode_replace_table[1]["UV2"]="uv2";
- mode_replace_table[1]["SCREEN_UV"]="screen_uv";
- mode_replace_table[1]["VAR1"]="var1_interp";
- mode_replace_table[1]["VAR2"]="var2_interp";
- mode_replace_table[1]["COLOR"]="color";
- mode_replace_table[1]["DIFFUSE"]="diffuse.rgb";
- mode_replace_table[1]["DIFFUSE_ALPHA"]="diffuse";
- mode_replace_table[1]["SPECULAR"]="specular";
- mode_replace_table[1]["EMISSION"]="emission";
- mode_replace_table[1]["SHADE_PARAM"]="shade_param";
- mode_replace_table[1]["SPEC_EXP"]="specular_exp";
- mode_replace_table[1]["GLOW"]="glow";
- mode_replace_table[1]["DISCARD"]="discard_";
- mode_replace_table[1]["POINT_COORD"]="gl_PointCoord";
- mode_replace_table[1]["INV_CAMERA_MATRIX"]="camera_inverse_transform";
-
- //mode_replace_table[1]["SCREEN_POS"]="SCREEN_POS";
- //mode_replace_table[1]["SCREEN_TEXEL_SIZE"]="SCREEN_TEXEL_SIZE";
- mode_replace_table[1]["TIME"]="time";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["SPEC_EXP"]="vertex_specular_exp";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["WORLD_MATRIX"]="world_transform";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["INV_CAMERA_MATRIX"]="camera_inverse_transform";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["PROJECTION_MATRIX"]="projection_transform";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["MODELVIEW_MATRIX"]="modelview";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["POINT_SIZE"]="gl_PointSize";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["VAR1"]="var1_interp";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["VAR2"]="var2_interp";
+
+// mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["SCREEN_POS"]="SCREEN_POS";
+// mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["SCREEN_SIZE"]="SCREEN_SIZE";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["INSTANCE_ID"]="instance_id";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["TIME"]="time";
+
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["VERTEX"]="vertex";
+ //mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["POSITION"]="IN_POSITION";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["NORMAL"]="normal";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["TANGENT"]="tangent";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["POSITION"]="gl_Position";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["BINORMAL"]="binormal";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["NORMALMAP"]="normalmap";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["NORMALMAP_DEPTH"]="normaldepth";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["VAR1"]="var1_interp";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["VAR2"]="var2_interp";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["UV"]="uv";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["UV2"]="uv2";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["SCREEN_UV"]="screen_uv";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["VAR1"]="var1_interp";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["VAR2"]="var2_interp";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["COLOR"]="color";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["DIFFUSE"]="diffuse.rgb";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["DIFFUSE_ALPHA"]="diffuse";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["SPECULAR"]="specular";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["EMISSION"]="emission";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["SHADE_PARAM"]="shade_param";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["SPEC_EXP"]="specular_exp";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["GLOW"]="glow";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["DISCARD"]="discard_";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["POINT_COORD"]="gl_PointCoord";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["INV_CAMERA_MATRIX"]="camera_inverse_transform";
+
+ //mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["SCREEN_POS"]="SCREEN_POS";
+ //mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["SCREEN_TEXEL_SIZE"]="SCREEN_TEXEL_SIZE";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["TIME"]="time";
//////////////
- mode_replace_table[2]["NORMAL"]="normal";
- //mode_replace_table[2]["POSITION"]="IN_POSITION";
- mode_replace_table[2]["LIGHT_DIR"]="light_dir";
- mode_replace_table[2]["LIGHT_DIFFUSE"]="light_diffuse";
- mode_replace_table[2]["LIGHT_SPECULAR"]="light_specular";
- mode_replace_table[2]["EYE_VEC"]="eye_vec";
- mode_replace_table[2]["DIFFUSE"]="mdiffuse";
- mode_replace_table[2]["SPECULAR"]="specular";
- mode_replace_table[2]["SPECULAR_EXP"]="specular_exp";
- mode_replace_table[2]["SHADE_PARAM"]="shade_param";
- mode_replace_table[2]["LIGHT"]="light";
- mode_replace_table[2]["POINT_COORD"]="gl_PointCoord";
- mode_replace_table[2]["TIME"]="time";
-
- mode_replace_table[3]["SRC_VERTEX"]="src_vtx";
- mode_replace_table[3]["VERTEX"]="outvec.xy";
- mode_replace_table[3]["WORLD_VERTEX"]="outvec.xy";
- mode_replace_table[3]["UV"]="uv_interp";
- mode_replace_table[3]["COLOR"]="color_interp";
- mode_replace_table[3]["VAR1"]="var1_interp";
- mode_replace_table[3]["VAR2"]="var2_interp";
- mode_replace_table[3]["POINT_SIZE"]="gl_PointSize";
- mode_replace_table[3]["WORLD_MATRIX"]="modelview_matrix";
- mode_replace_table[3]["PROJECTION_MATRIX"]="projection_matrix";
- mode_replace_table[3]["EXTRA_MATRIX"]="extra_matrix";
- mode_replace_table[3]["TIME"]="time";
-
- mode_replace_table[4]["POSITION"]="gl_Position";
- mode_replace_table[4]["NORMAL"]="normal";
- mode_replace_table[4]["NORMALMAP"]="normal_map";
- mode_replace_table[4]["NORMALMAP_DEPTH"]="normal_depth";
- mode_replace_table[4]["UV"]="uv_interp";
- mode_replace_table[4]["SRC_COLOR"]="color_interp";
- mode_replace_table[4]["COLOR"]="color";
- mode_replace_table[4]["TEXTURE"]="texture";
- mode_replace_table[4]["TEXTURE_PIXEL_SIZE"]="texpixel_size";
- mode_replace_table[4]["VAR1"]="var1_interp";
- mode_replace_table[4]["VAR2"]="var2_interp";
- mode_replace_table[4]["SCREEN_UV"]="screen_uv";
- mode_replace_table[4]["POINT_COORD"]="gl_PointCoord";
- mode_replace_table[4]["TIME"]="time";
-
- mode_replace_table[5]["POSITION"]="gl_Position";
- mode_replace_table[5]["NORMAL"]="normal";
- mode_replace_table[5]["UV"]="uv_interp";
- mode_replace_table[5]["COLOR"]="color";
- mode_replace_table[5]["TEXTURE"]="texture";
- mode_replace_table[5]["TEXTURE_PIXEL_SIZE"]="texpixel_size";
- mode_replace_table[5]["VAR1"]="var1_interp";
- mode_replace_table[5]["VAR2"]="var2_interp";
- mode_replace_table[5]["LIGHT_VEC"]="light_vec";
- mode_replace_table[5]["LIGHT_HEIGHT"]="light_height";
- mode_replace_table[5]["LIGHT_COLOR"]="light";
- mode_replace_table[5]["LIGHT_UV"]="light_uv";
- mode_replace_table[5]["LIGHT"]="light_out";
- mode_replace_table[5]["SHADOW"]="shadow_color";
- mode_replace_table[5]["SCREEN_UV"]="screen_uv";
- mode_replace_table[5]["POINT_COORD"]="gl_PointCoord";
- mode_replace_table[5]["TIME"]="time";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_LIGHT]["NORMAL"]="normal";
+ //mode_replace_table[ShaderLanguage::SHADER_MATERIAL_LIGHT]["POSITION"]="IN_POSITION";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_LIGHT]["LIGHT_DIR"]="light_dir";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_LIGHT]["LIGHT_DIFFUSE"]="light_diffuse";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_LIGHT]["LIGHT_SPECULAR"]="light_specular";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_LIGHT]["EYE_VEC"]="eye_vec";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_LIGHT]["DIFFUSE"]="mdiffuse";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_LIGHT]["SPECULAR"]="specular";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_LIGHT]["SPECULAR_EXP"]="specular_exp";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_LIGHT]["SHADE_PARAM"]="shade_param";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_LIGHT]["LIGHT"]="light";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_LIGHT]["POINT_COORD"]="gl_PointCoord";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_LIGHT]["TIME"]="time";
+
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_VERTEX]["SRC_VERTEX"]="src_vtx";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_VERTEX]["VERTEX"]="outvec.xy";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_VERTEX]["WORLD_VERTEX"]="outvec.xy";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_VERTEX]["UV"]="uv_interp";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_VERTEX]["COLOR"]="color_interp";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_VERTEX]["VAR1"]="var1_interp";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_VERTEX]["VAR2"]="var2_interp";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_VERTEX]["POINT_SIZE"]="gl_PointSize";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_VERTEX]["WORLD_MATRIX"]="modelview_matrix";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_VERTEX]["PROJECTION_MATRIX"]="projection_matrix";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_VERTEX]["EXTRA_MATRIX"]="extra_matrix";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_VERTEX]["TIME"]="time";
+
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_FRAGMENT]["POSITION"]="gl_Position";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_FRAGMENT]["NORMAL"]="normal";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_FRAGMENT]["NORMALMAP"]="normal_map";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_FRAGMENT]["NORMALMAP_DEPTH"]="normal_depth";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_FRAGMENT]["UV"]="uv_interp";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_FRAGMENT]["SRC_COLOR"]="color_interp";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_FRAGMENT]["COLOR"]="color";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_FRAGMENT]["TEXTURE"]="texture";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_FRAGMENT]["TEXTURE_PIXEL_SIZE"]="texpixel_size";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_FRAGMENT]["VAR1"]="var1_interp";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_FRAGMENT]["VAR2"]="var2_interp";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_FRAGMENT]["SCREEN_UV"]="screen_uv";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_FRAGMENT]["POINT_COORD"]="gl_PointCoord";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_FRAGMENT]["TIME"]="time";
+
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT]["POSITION"]="gl_Position";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT]["NORMAL"]="normal";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT]["UV"]="uv_interp";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT]["COLOR"]="color";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT]["TEXTURE"]="texture";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT]["TEXTURE_PIXEL_SIZE"]="texpixel_size";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT]["VAR1"]="var1_interp";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT]["VAR2"]="var2_interp";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT]["LIGHT_VEC"]="light_vec";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT]["LIGHT_HEIGHT"]="light_height";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT]["LIGHT_COLOR"]="light";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT]["LIGHT_UV"]="light_uv";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT]["LIGHT"]="light_out";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT]["SHADOW"]="shadow_color";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT]["SCREEN_UV"]="screen_uv";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT]["POINT_COORD"]="gl_PointCoord";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT]["TIME"]="time";
@@ -917,6 +924,7 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() {
vname_var1_interp="VAR1";
vname_var2_interp="VAR2";
vname_vertex="VERTEX";
+ vname_position = "POSITION";
vname_light="LIGHT";
vname_time="TIME";
vname_normalmap="NORMALMAP";
diff --git a/drivers/gles2/shader_compiler_gles2.h b/drivers/gles2/shader_compiler_gles2.h
index 43902a7536..46ef2e035f 100644
--- a/drivers/gles2/shader_compiler_gles2.h
+++ b/drivers/gles2/shader_compiler_gles2.h
@@ -34,7 +34,7 @@ class ShaderCompilerGLES2 {
class Uniform;
public:
- class Flags;
+ struct Flags;
private:
ShaderLanguage::ProgramNode *program_node;
@@ -55,6 +55,7 @@ private:
bool uses_texpixel_size;
bool uses_worldvec;
bool vertex_code_writes_vertex;
+ bool vertex_code_writes_position;
bool uses_shadow_color;
bool sinh_used;
@@ -76,6 +77,7 @@ private:
StringName vname_var1_interp;
StringName vname_var2_interp;
StringName vname_vertex;
+ StringName vname_position;
StringName vname_light;
StringName vname_time;
StringName vname_normalmap;
@@ -107,6 +109,7 @@ public:
bool uses_texpos;
bool uses_normalmap;
bool vertex_code_writes_vertex;
+ bool vertex_code_writes_position;
bool uses_discard;
bool uses_screen_uv;
bool use_color_interp;
diff --git a/drivers/nrex/README.md b/drivers/nrex/README.md
index f150a5d76f..951b301c1e 100644
--- a/drivers/nrex/README.md
+++ b/drivers/nrex/README.md
@@ -18,47 +18,42 @@ More details about its use is documented in `nrex.hpp`
Currently supported features:
* Capturing `()` and non-capturing `(?:)` groups
- * Any character `.`
+ * Any character `.` (includes newlines)
* Shorthand caracter classes `\w\W\s\S\d\D`
- * User-defined character classes such as `[A-Za-z]`
+ * POSIX character classes such as `[[:alnum:]]`
+ * Bracket expressions such as `[A-Za-z]`
* Simple quantifiers `?`, `*` and `+`
* Range quantifiers `{0,1}`
* Lazy (non-greedy) quantifiers `*?`
* Begining `^` and end `$` anchors
+ * Word boundaries `\b`
* Alternation `|`
- * Backreferences `\1` to `\99`
-
-To do list:
+ * ASCII `\xFF` code points
* Unicode `\uFFFF` code points
+ * Positive `(?=)` and negative `(?!)` lookahead
+ * Positive `(?<=)` and negative `(?<!)` lookbehind (fixed length and no alternations)
+ * Backreferences `\1` to `\9` (with option to expand to `\99`)
## License
Copyright (c) 2015, Zher Huei Lee
All rights reserved.
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- 3. Neither the name of the copyright holder nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
-TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
-PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
-TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would
+ be appreciated but is not required.
+
+ 2. Altered source versions must be plainly marked as such, and must not
+ be misrepresented as being the original software.
+
+ 3. This notice may not be removed or altered from any source
+ distribution.
diff --git a/drivers/nrex/nrex.cpp b/drivers/nrex/nrex.cpp
index 696d46240e..104e07f887 100644
--- a/drivers/nrex/nrex.cpp
+++ b/drivers/nrex/nrex.cpp
@@ -29,11 +29,13 @@
#include <wctype.h>
#include <wchar.h>
#define NREX_ISALPHANUM iswalnum
+#define NREX_ISSPACE iswspace
#define NREX_STRLEN wcslen
#else
#include <ctype.h>
#include <string.h>
#define NREX_ISALPHANUM isalnum
+#define NREX_ISSPACE isspace
#define NREX_STRLEN strlen
#endif
@@ -116,34 +118,72 @@ class nrex_array
}
};
-static nrex_char nrex_unescape(nrex_char repr)
+static int nrex_parse_hex(nrex_char c)
{
- switch (repr)
+ if ('0' <= c && c <= '9')
+ {
+ return int(c - '0');
+ }
+ else if ('a' <= c && c <= 'f')
+ {
+ return int(c - 'a') + 10;
+ }
+ else if ('A' <= c && c <= 'F')
{
- case '^': return '^';
- case '$': return '$';
- case '(': return '(';
- case ')': return ')';
- case '\\': return '\\';
- case '.': return '.';
- case '+': return '+';
- case '*': return '*';
- case '?': return '?';
- case '-': return '-';
- case 'a': return '\a';
- case 'e': return '\e';
- case 'f': return '\f';
- case 'n': return '\n';
- case 'r': return '\r';
- case 't': return '\t';
- case 'v': return '\v';
+ return int(c - 'A') + 10;
}
- return 0;
+ return -1;
+}
+
+static nrex_char nrex_unescape(const nrex_char*& c)
+{
+ switch (c[1])
+ {
+ case '0': ++c; return '\0';
+ case 'a': ++c; return '\a';
+ case 'e': ++c; return '\e';
+ case 'f': ++c; return '\f';
+ case 'n': ++c; return '\n';
+ case 'r': ++c; return '\r';
+ case 't': ++c; return '\t';
+ case 'v': ++c; return '\v';
+ case 'b': ++c; return '\b';
+ case 'x':
+ {
+ int point = 0;
+ for (int i = 2; i <= 3; ++i)
+ {
+ int res = nrex_parse_hex(c[i]);
+ if (res == -1)
+ {
+ return '\0';
+ }
+ point = (point << 4) + res;
+ }
+ c = &c[3];
+ return nrex_char(point);
+ }
+ case 'u':
+ {
+ int point = 0;
+ for (int i = 2; i <= 5; ++i)
+ {
+ int res = nrex_parse_hex(c[i]);
+ if (res == -1)
+ {
+ return '\0';
+ }
+ point = (point << 4) + res;
+ }
+ c = &c[5];
+ return nrex_char(point);
+ }
+ }
+ return (++c)[0];
}
struct nrex_search
{
- public:
const nrex_char* str;
nrex_result* captures;
int end;
@@ -168,12 +208,14 @@ struct nrex_node
nrex_node* previous;
nrex_node* parent;
bool quantifiable;
+ int length;
nrex_node(bool quantify = false)
: next(NULL)
, previous(NULL)
, parent(NULL)
, quantifiable(quantify)
+ , length(-1)
{
}
@@ -206,21 +248,57 @@ struct nrex_node
}
return pos;
}
+
+ void increment_length(int amount, bool subtract = false)
+ {
+ if (amount >= 0 && length >= 0)
+ {
+ if (!subtract)
+ {
+ length += amount;
+ }
+ else
+ {
+ length -= amount;
+ }
+ }
+ else
+ {
+ length = -1;
+ }
+ if (parent)
+ {
+ parent->increment_length(amount, subtract);
+ }
+ }
};
struct nrex_node_group : public nrex_node
{
- int capturing;
+ static const int NonCapture = -1;
+ static const int Bracket = -2;
+ static const int LookAhead = -3;
+ static const int LookBehind = -4;
+
+ int mode;
bool negate;
nrex_array<nrex_node*> childset;
nrex_node* back;
- nrex_node_group(int capturing)
+ nrex_node_group(int mode)
: nrex_node(true)
- , capturing(capturing)
+ , mode(mode)
, negate(false)
, back(NULL)
{
+ if (mode != Bracket)
+ {
+ length = 0;
+ }
+ else
+ {
+ length = 1;
+ }
}
virtual ~nrex_node_group()
@@ -234,14 +312,19 @@ struct nrex_node_group : public nrex_node
int test(nrex_search* s, int pos) const
{
- if (capturing >= 0)
+ if (mode >= 0)
{
- s->captures[capturing].start = pos;
+ s->captures[mode].start = pos;
}
for (unsigned int i = 0; i < childset.size(); ++i)
{
s->complete = false;
- int res = childset[i]->test(s, pos);
+ int offset = 0;
+ if (mode == LookBehind)
+ {
+ offset = length;
+ }
+ int res = childset[i]->test(s, pos - offset);
if (s->complete)
{
return res;
@@ -256,12 +339,20 @@ struct nrex_node_group : public nrex_node
{
return -1;
}
+ if (i + 1 < childset.size())
+ {
+ continue;
+ }
}
if (res >= 0)
{
- if (capturing >= 0)
+ if (mode >= 0)
{
- s->captures[capturing].length = res - pos;
+ s->captures[mode].length = res - pos;
+ }
+ else if (mode == LookAhead || mode == LookBehind)
+ {
+ res = pos;
}
return next ? next->test(s, res) : res;
}
@@ -271,15 +362,19 @@ struct nrex_node_group : public nrex_node
virtual int test_parent(nrex_search* s, int pos) const
{
- if (capturing >= 0)
+ if (mode >= 0)
{
- s->captures[capturing].length = pos - s->captures[capturing].start;
+ s->captures[mode].length = pos - s->captures[mode].start;
}
return nrex_node::test_parent(s, pos);
}
void add_childset()
{
+ if (childset.size() > 0 && mode != Bracket)
+ {
+ length = -1;
+ }
back = NULL;
}
@@ -287,7 +382,7 @@ struct nrex_node_group : public nrex_node
{
node->parent = this;
node->previous = back;
- if (back)
+ if (back && mode != Bracket)
{
back->next = node;
}
@@ -295,6 +390,10 @@ struct nrex_node_group : public nrex_node
{
childset.push(node);
}
+ if (mode != Bracket)
+ {
+ increment_length(node->length);
+ }
back = node;
}
@@ -310,10 +409,32 @@ struct nrex_node_group : public nrex_node
{
childset.pop();
}
+ if (mode != Bracket)
+ {
+ increment_length(old->length, true);
+ }
back = old->previous;
add_child(node);
return old;
}
+
+ void pop_back()
+ {
+ if (back)
+ {
+ nrex_node* old = back;
+ if (!old->previous)
+ {
+ childset.pop();
+ }
+ if (mode != Bracket)
+ {
+ increment_length(old->length, true);
+ }
+ back = old->previous;
+ NREX_DELETE(old);
+ }
+ }
};
struct nrex_node_char : public nrex_node
@@ -324,6 +445,7 @@ struct nrex_node_char : public nrex_node
: nrex_node(true)
, ch(c)
{
+ length = 1;
}
int test(nrex_search* s, int pos) const
@@ -346,6 +468,7 @@ struct nrex_node_range : public nrex_node
, start(s)
, end(e)
{
+ length = 1;
}
int test(nrex_search* s, int pos) const
@@ -363,20 +486,219 @@ struct nrex_node_range : public nrex_node
}
};
-static bool nrex_is_whitespace(nrex_char repr)
+enum nrex_class_type
{
- switch (repr)
+ nrex_class_none,
+ nrex_class_alnum,
+ nrex_class_alpha,
+ nrex_class_blank,
+ nrex_class_cntrl,
+ nrex_class_digit,
+ nrex_class_graph,
+ nrex_class_lower,
+ nrex_class_print,
+ nrex_class_punct,
+ nrex_class_space,
+ nrex_class_upper,
+ nrex_class_xdigit,
+ nrex_class_word
+};
+
+static bool nrex_compare_class(const nrex_char** pos, const char* text)
+{
+ unsigned int i = 0;
+ for (i = 0; text[i] != '\0'; ++i)
{
- case ' ':
- case '\t':
- case '\r':
- case '\n':
- case '\f':
- return true;
+ if ((*pos)[i] != text[i])
+ {
+ return false;
+ }
}
- return false;
+ if ((*pos)[i++] != ':' || (*pos)[i] != ']')
+ {
+ return false;
+ }
+ *pos = &(*pos)[i];
+ return true;
}
+#define NREX_COMPARE_CLASS(POS, NAME) if (nrex_compare_class(POS, #NAME)) return nrex_class_ ## NAME
+
+static nrex_class_type nrex_parse_class(const nrex_char** pos)
+{
+ NREX_COMPARE_CLASS(pos, alnum);
+ NREX_COMPARE_CLASS(pos, alpha);
+ NREX_COMPARE_CLASS(pos, blank);
+ NREX_COMPARE_CLASS(pos, cntrl);
+ NREX_COMPARE_CLASS(pos, digit);
+ NREX_COMPARE_CLASS(pos, graph);
+ NREX_COMPARE_CLASS(pos, lower);
+ NREX_COMPARE_CLASS(pos, print);
+ NREX_COMPARE_CLASS(pos, punct);
+ NREX_COMPARE_CLASS(pos, space);
+ NREX_COMPARE_CLASS(pos, upper);
+ NREX_COMPARE_CLASS(pos, xdigit);
+ NREX_COMPARE_CLASS(pos, word);
+ return nrex_class_none;
+}
+
+struct nrex_node_class : public nrex_node
+{
+ nrex_class_type type;
+
+ nrex_node_class(nrex_class_type t)
+ : nrex_node(true)
+ , type(t)
+ {
+ length = 1;
+ }
+
+ int test(nrex_search* s, int pos) const
+ {
+ if (s->end == pos)
+ {
+ return -1;
+ }
+ if (!test_class(s->at(pos)))
+ {
+ return -1;
+ }
+ return next ? next->test(s, pos + 1) : pos + 1;
+ }
+
+ bool test_class(nrex_char c) const
+ {
+ if ((0 <= c && c <= 0x1F) || c == 0x7F)
+ {
+ if (type == nrex_class_cntrl)
+ {
+ return true;
+ }
+ }
+ else if (c < 0x7F)
+ {
+ if (type == nrex_class_print)
+ {
+ return true;
+ }
+ else if (type == nrex_class_graph && c != ' ')
+ {
+ return true;
+ }
+ else if ('0' <= c && c <= '9')
+ {
+ switch (type)
+ {
+ case nrex_class_alnum:
+ case nrex_class_digit:
+ case nrex_class_xdigit:
+ case nrex_class_word:
+ return true;
+ default:
+ break;
+ }
+ }
+ else if ('A' <= c && c <= 'Z')
+ {
+ switch (type)
+ {
+ case nrex_class_alnum:
+ case nrex_class_alpha:
+ case nrex_class_upper:
+ case nrex_class_word:
+ return true;
+ case nrex_class_xdigit:
+ if (c <= 'F')
+ {
+ return true;
+ }
+ default:
+ break;
+ }
+ }
+ else if ('a' <= c && c <= 'z')
+ {
+ switch (type)
+ {
+ case nrex_class_alnum:
+ case nrex_class_alpha:
+ case nrex_class_lower:
+ case nrex_class_word:
+ return true;
+ case nrex_class_xdigit:
+ if (c <= 'f')
+ {
+ return true;
+ }
+ default:
+ break;
+ }
+ }
+ }
+ switch (c)
+ {
+ case ' ':
+ case '\t':
+ if (type == nrex_class_blank)
+ {
+ return true;
+ }
+ case '\r':
+ case '\n':
+ case '\f':
+ if (type == nrex_class_space)
+ {
+ return true;
+ }
+ break;
+ case '_':
+ if (type == nrex_class_word)
+ {
+ return true;
+ }
+ case ']':
+ case '[':
+ case '!':
+ case '"':
+ case '#':
+ case '$':
+ case '%':
+ case '&':
+ case '\'':
+ case '(':
+ case ')':
+ case '*':
+ case '+':
+ case ',':
+ case '.':
+ case '/':
+ case ':':
+ case ';':
+ case '<':
+ case '=':
+ case '>':
+ case '?':
+ case '@':
+ case '\\':
+ case '^':
+ case '`':
+ case '{':
+ case '|':
+ case '}':
+ case '~':
+ case '-':
+ if (type == nrex_class_punct)
+ {
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+ return false;
+ }
+};
+
static bool nrex_is_shorthand(nrex_char repr)
{
switch (repr)
@@ -400,6 +722,7 @@ struct nrex_node_shorthand : public nrex_node
: nrex_node(true)
, repr(c)
{
+ length = 1;
}
int test(nrex_search* s, int pos) const
@@ -435,7 +758,7 @@ struct nrex_node_shorthand : public nrex_node
case 'S':
invert = true;
case 's':
- if (nrex_is_whitespace(c))
+ if (NREX_ISSPACE(c))
{
found = true;
}
@@ -469,10 +792,10 @@ struct nrex_node_quantifier : public nrex_node
bool greedy;
nrex_node* child;
- nrex_node_quantifier()
+ nrex_node_quantifier(int min, int max)
: nrex_node()
- , min(0)
- , max(0)
+ , min(min)
+ , max(max)
, greedy(true)
, child(NULL)
{
@@ -488,17 +811,49 @@ struct nrex_node_quantifier : public nrex_node
int test(nrex_search* s, int pos) const
{
- nrex_array<int> backtrack;
- backtrack.push(pos);
- while (backtrack.top() <= s->end)
+ return test_step(s, pos, 1);
+ }
+
+ int test_step(nrex_search* s, int pos, int level) const
+ {
+ if (max == 0)
{
- if (max >= 1 && backtrack.size() > (unsigned int)max)
+ return pos;
+ }
+ if ((max >= 1 && level > max) || pos > s->end)
+ {
+ return -1;
+ }
+ if (!greedy && level > min)
+ {
+ int res = pos;
+ if (next)
{
- break;
+ res = next->test(s, res);
+ }
+ if (s->complete)
+ {
+ return res;
}
- if (!greedy && (unsigned int)min < backtrack.size())
+ if (res >= 0 && parent->test_parent(s, res) >= 0)
+ {
+ return res;
+ }
+ }
+ int res = child->test(s, pos);
+ if (s->complete)
+ {
+ return res;
+ }
+ if (res >= 0)
+ {
+ int res_step = test_step(s, res, level + 1);
+ if (res_step >= 0)
+ {
+ return res_step;
+ }
+ else if (greedy && level >= min)
{
- int res = backtrack.top();
if (next)
{
res = next->test(s, res);
@@ -512,33 +867,6 @@ struct nrex_node_quantifier : public nrex_node
return res;
}
}
- int res = child->test(s, backtrack.top());
- if (s->complete)
- {
- return res;
- }
- if (res < 0 || res == backtrack.top())
- {
- break;
- }
- backtrack.push(res);
- }
- while (greedy && (unsigned int) min < backtrack.size())
- {
- int res = backtrack.top();
- if (next)
- {
- res = next->test(s, res);
- }
- if (res >= 0 && parent->test_parent(s, res) >= 0)
- {
- return res;
- }
- if (s->complete)
- {
- return res;
- }
- backtrack.pop();
}
return -1;
}
@@ -552,6 +880,7 @@ struct nrex_node_anchor : public nrex_node
: nrex_node()
, end(end)
{
+ length = 0;
}
int test(nrex_search* s, int pos) const
@@ -568,6 +897,45 @@ struct nrex_node_anchor : public nrex_node
}
};
+struct nrex_node_word_boundary : public nrex_node
+{
+ bool inverse;
+
+ nrex_node_word_boundary(bool inverse)
+ : nrex_node()
+ , inverse(inverse)
+ {
+ length = 0;
+ }
+
+ int test(nrex_search* s, int pos) const
+ {
+ bool left = false;
+ bool right = false;
+ if (pos != 0)
+ {
+ nrex_char c = s->at(pos - 1);
+ if (c == '_' || NREX_ISALPHANUM(c))
+ {
+ left = true;
+ }
+ }
+ if (pos != s->end)
+ {
+ nrex_char c = s->at(pos);
+ if (c == '_' || NREX_ISALPHANUM(c))
+ {
+ right = true;
+ }
+ }
+ if ((left != right) == inverse)
+ {
+ return -1;
+ }
+ return next ? next->test(s, pos) : pos;
+ }
+};
+
struct nrex_node_backreference : public nrex_node
{
int ref;
@@ -576,6 +944,7 @@ struct nrex_node_backreference : public nrex_node
: nrex_node(true)
, ref(ref)
{
+ length = -1;
}
int test(nrex_search* s, int pos) const
@@ -596,6 +965,18 @@ struct nrex_node_backreference : public nrex_node
}
};
+bool nrex_has_lookbehind(nrex_array<nrex_node_group*>& stack)
+{
+ for (unsigned int i = 0; i < stack.size(); i++)
+ {
+ if (stack[i]->mode == nrex_node_group::LookBehind)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
nrex::nrex()
: _capturing(0)
, _root(NULL)
@@ -630,7 +1011,7 @@ int nrex::capture_size() const
return _capturing + 1;
}
-bool nrex::compile(const nrex_char* pattern)
+bool nrex::compile(const nrex_char* pattern, bool extended)
{
reset();
nrex_node_group* root = NREX_NEW(nrex_node_group(_capturing));
@@ -647,16 +1028,32 @@ bool nrex::compile(const nrex_char* pattern)
if (c[2] == ':')
{
c = &c[2];
- nrex_node_group* group = NREX_NEW(nrex_node_group(-1));
+ nrex_node_group* group = NREX_NEW(nrex_node_group(nrex_node_group::NonCapture));
+ stack.top()->add_child(group);
+ stack.push(group);
+ }
+ else if (c[2] == '!' || c[2] == '=')
+ {
+ c = &c[2];
+ nrex_node_group* group = NREX_NEW(nrex_node_group(nrex_node_group::LookAhead));
+ group->negate = (c[0] == '!');
+ stack.top()->add_child(group);
+ stack.push(group);
+ }
+ else if (c[2] == '<' && (c[3] == '!' || c[3] == '='))
+ {
+ c = &c[3];
+ nrex_node_group* group = NREX_NEW(nrex_node_group(nrex_node_group::LookBehind));
+ group->negate = (c[0] == '!');
stack.top()->add_child(group);
stack.push(group);
}
else
{
- NREX_COMPILE_ERROR("unrecognised qualifier for parenthesis");
+ NREX_COMPILE_ERROR("unrecognised qualifier for group");
}
}
- else if (_capturing < 99)
+ else if ((!extended && _capturing < 9) || (extended && _capturing < 99))
{
nrex_node_group* group = NREX_NEW(nrex_node_group(++_capturing));
stack.top()->add_child(group);
@@ -664,7 +1061,7 @@ bool nrex::compile(const nrex_char* pattern)
}
else
{
- nrex_node_group* group = NREX_NEW(nrex_node_group(-1));
+ nrex_node_group* group = NREX_NEW(nrex_node_group(nrex_node_group::NonCapture));
stack.top()->add_child(group);
stack.push(group);
}
@@ -682,152 +1079,233 @@ bool nrex::compile(const nrex_char* pattern)
}
else if (c[0] == '[')
{
- nrex_node_group* group = NREX_NEW(nrex_node_group(-1));
+ nrex_node_group* group = NREX_NEW(nrex_node_group(nrex_node_group::Bracket));
stack.top()->add_child(group);
if (c[1] == '^')
{
group->negate = true;
++c;
}
+ bool first_child = true;
+ nrex_char previous_child;
+ bool previous_child_single = false;
while (true)
{
group->add_childset();
++c;
if (c[0] == '\0')
{
- NREX_COMPILE_ERROR("unclosed character class '[]'");
+ NREX_COMPILE_ERROR("unclosed bracket expression '['");
}
- if (c[0] == ']')
+ if (c[0] == '[' && c[1] == ':')
+ {
+ const nrex_char* d = &c[2];
+ nrex_class_type cls = nrex_parse_class(&d);
+ if (cls != nrex_class_none)
+ {
+ c = d;
+ group->add_child(NREX_NEW(nrex_node_class(cls)));
+ previous_child_single = false;
+ }
+ else
+ {
+ group->add_child(NREX_NEW(nrex_node_char('[')));
+ previous_child = '[';
+ previous_child_single = true;
+ }
+ }
+ else if (c[0] == ']' && !first_child)
{
break;
}
else if (c[0] == '\\')
{
- nrex_char unescaped = nrex_unescape(c[1]);
- if (unescaped)
- {
- group->add_child(NREX_NEW(nrex_node_char(unescaped)));
- ++c;
- }
- else if (nrex_is_shorthand(c[1]))
+ if (nrex_is_shorthand(c[1]))
{
group->add_child(NREX_NEW(nrex_node_shorthand(c[1])));
++c;
+ previous_child_single = false;
}
else
{
- NREX_COMPILE_ERROR("escape token not recognised");
+ const nrex_char* d = c;
+ nrex_char unescaped = nrex_unescape(d);
+ if (c == d)
+ {
+ NREX_COMPILE_ERROR("invalid escape token");
+ }
+ group->add_child(NREX_NEW(nrex_node_char(unescaped)));
+ c = d;
+ previous_child = unescaped;
+ previous_child_single = true;
}
}
- else
+ else if (previous_child_single && c[0] == '-')
{
- if (c[1] == '-' && c[2] != '\0')
+ bool is_range = false;
+ nrex_char next;
+ if (c[1] != '\0' && c[1] != ']')
{
- bool range = false;
- if ('A' <= c[0] && c[0] <= 'Z' && 'A' <= c[2] && c[2] <= 'Z')
+ if (c[1] == '\\')
{
- range = true;
+ const nrex_char* d = ++c;
+ next = nrex_unescape(d);
+ if (c == d)
+ {
+ NREX_COMPILE_ERROR("invalid escape token in range");
+ }
}
- if ('a' <= c[0] && c[0] <= 'z' && 'a' <= c[2] && c[2] <= 'z')
- {
- range = true;
- }
- if ('0' <= c[0] && c[0] <= '9' && '0' <= c[2] && c[2] <= '9')
+ else
{
- range = true;
+ next = c[1];
+ ++c;
}
- if (range)
+ is_range = true;
+ }
+ if (is_range)
+ {
+ if (next < previous_child)
{
- group->add_child(NREX_NEW(nrex_node_range(c[0], c[2])));
- c = &c[2];
- continue;
+ NREX_COMPILE_ERROR("text range out of order");
}
+ group->pop_back();
+ group->add_child(NREX_NEW(nrex_node_range(previous_child, next)));
+ previous_child_single = false;
+ }
+ else
+ {
+ group->add_child(NREX_NEW(nrex_node_char(c[0])));
+ previous_child = c[0];
+ previous_child_single = true;
}
+ }
+ else
+ {
group->add_child(NREX_NEW(nrex_node_char(c[0])));
+ previous_child = c[0];
+ previous_child_single = true;
}
-
+ first_child = false;
}
}
else if (nrex_is_quantifier(c[0]))
{
- nrex_node_quantifier* quant = NREX_NEW(nrex_node_quantifier);
- quant->child = stack.top()->swap_back(quant);
- if (quant->child == NULL || !quant->child->quantifiable)
+ if (stack.top()->back == NULL || !stack.top()->back->quantifiable)
{
+ if (c[0] == '{')
+ {
+ stack.top()->add_child(NREX_NEW(nrex_node_char('{')));
+ continue;
+ }
NREX_COMPILE_ERROR("element not quantifiable");
}
- quant->child->previous = NULL;
- quant->child->next = NULL;
- quant->child->parent = quant;
+ int min = 0;
+ int max = -1;
+ bool valid_quantifier = true;
if (c[0] == '?')
{
- quant->min = 0;
- quant->max = 1;
+ min = 0;
+ max = 1;
}
else if (c[0] == '+')
{
- quant->min = 1;
- quant->max = -1;
+ min = 1;
+ max = -1;
}
else if (c[0] == '*')
{
- quant->min = 0;
- quant->max = -1;
+ min = 0;
+ max = -1;
}
else if (c[0] == '{')
{
bool max_set = false;
- quant->min = 0;
- quant->max = -1;
+ const nrex_char* d = c;
while (true)
{
- ++c;
- if (c[0] == '\0')
+ ++d;
+ if (d[0] == '\0')
{
- NREX_COMPILE_ERROR("unclosed range quantifier '{}'");
+ valid_quantifier = false;
+ break;
}
- else if (c[0] == '}')
+ else if (d[0] == '}')
{
break;
}
- else if (c[0] == ',')
+ else if (d[0] == ',')
{
max_set = true;
continue;
}
- else if (c[0] < '0' || '9' < c[0])
+ else if (d[0] < '0' || '9' < d[0])
{
- NREX_COMPILE_ERROR("expected numeric digits, ',' or '}'");
+ valid_quantifier = false;
+ break;
}
if (max_set)
{
- if (quant->max < 0)
+ if (max < 0)
{
- quant->max = int(c[0] - '0');
+ max = int(d[0] - '0');
}
else
{
- quant->max = quant->max * 10 + int(c[0] - '0');
+ max = max * 10 + int(d[0] - '0');
}
}
else
{
- quant->min = quant->min * 10 + int(c[0] - '0');
+ min = min * 10 + int(d[0] - '0');
}
}
if (!max_set)
{
- quant->max = quant->min;
+ max = min;
+ }
+ if (valid_quantifier)
+ {
+ c = d;
}
}
- if (c[1] == '?')
+ if (valid_quantifier)
{
- quant->greedy = false;
- ++c;
+ nrex_node_quantifier* quant = NREX_NEW(nrex_node_quantifier(min, max));
+ if (min == max)
+ {
+ if (stack.top()->back->length >= 0)
+ {
+ quant->length = max * stack.top()->back->length;
+ }
+ }
+ else
+ {
+ if (nrex_has_lookbehind(stack))
+ {
+ NREX_COMPILE_ERROR("variable length quantifiers inside lookbehind not supported");
+ }
+ }
+ quant->child = stack.top()->swap_back(quant);
+ quant->child->previous = NULL;
+ quant->child->next = NULL;
+ quant->child->parent = quant;
+ if (c[1] == '?')
+ {
+ quant->greedy = false;
+ ++c;
+ }
+ }
+ else
+ {
+ stack.top()->add_child(NREX_NEW(nrex_node_char(c[0])));
}
}
else if (c[0] == '|')
{
+ if (nrex_has_lookbehind(stack))
+ {
+ NREX_COMPILE_ERROR("alternations inside lookbehind not supported");
+ }
stack.top()->add_childset();
}
else if (c[0] == '^' || c[0] == '$')
@@ -840,13 +1318,7 @@ bool nrex::compile(const nrex_char* pattern)
}
else if (c[0] == '\\')
{
- nrex_char unescaped = nrex_unescape(c[1]);
- if (unescaped)
- {
- stack.top()->add_child(NREX_NEW(nrex_node_char(unescaped)));
- ++c;
- }
- else if (nrex_is_shorthand(c[1]))
+ if (nrex_is_shorthand(c[1]))
{
stack.top()->add_child(NREX_NEW(nrex_node_shorthand(c[1])));
++c;
@@ -854,7 +1326,7 @@ bool nrex::compile(const nrex_char* pattern)
else if ('1' <= c[1] && c[1] <= '9')
{
int ref = 0;
- if ('0' <= c[2] && c[2] <= '9')
+ if (extended && '0' <= c[2] && c[2] <= '9')
{
ref = int(c[1] - '0') * 10 + int(c[2] - '0');
c = &c[2];
@@ -868,11 +1340,27 @@ bool nrex::compile(const nrex_char* pattern)
{
NREX_COMPILE_ERROR("backreference to non-existent capture");
}
+ if (nrex_has_lookbehind(stack))
+ {
+ NREX_COMPILE_ERROR("backreferences inside lookbehind not supported");
+ }
stack.top()->add_child(NREX_NEW(nrex_node_backreference(ref)));
}
+ else if (c[1] == 'b' || c[1] == 'B')
+ {
+ stack.top()->add_child(NREX_NEW(nrex_node_word_boundary(c[1] == 'B')));
+ ++c;
+ }
else
{
- NREX_COMPILE_ERROR("escape token not recognised");
+ const nrex_char* d = c;
+ nrex_char unescaped = nrex_unescape(d);
+ if (c == d)
+ {
+ NREX_COMPILE_ERROR("invalid escape token");
+ }
+ stack.top()->add_child(NREX_NEW(nrex_node_char(unescaped)));
+ c = d;
}
}
else
@@ -880,6 +1368,10 @@ bool nrex::compile(const nrex_char* pattern)
stack.top()->add_child(NREX_NEW(nrex_node_char(c[0])));
}
}
+ if (stack.size() > 1)
+ {
+ NREX_COMPILE_ERROR("unclosed group '('");
+ }
return true;
}
diff --git a/drivers/nrex/nrex.hpp b/drivers/nrex/nrex.hpp
index 2a6aa08e1d..e26a61c39a 100644
--- a/drivers/nrex/nrex.hpp
+++ b/drivers/nrex/nrex.hpp
@@ -79,7 +79,8 @@ class nrex
* This is used to provide the array size of the captures needed for
* nrex::match() to work. The size is actually the number of capture
* groups + one for the matching of the entire pattern. The result is
- * always capped at 100.
+ * always capped at 10 or 100, depending on the extend option given in
+ * nrex::compile() (default 10).
*
* \return The number of captures
*/
@@ -95,10 +96,13 @@ class nrex
* runtime error nrex_compile_error if it encounters a problem when
* parsing the pattern.
*
- * \param The regex pattern
+ * \param pattern The regex pattern
+ * \param extended If true, raises the limit on number of capture
+ * groups and back-references to 99. Otherwise limited
+ * to 9. Defaults to false.
* \return True if the pattern was succesfully compiled
*/
- bool compile(const nrex_char* pattern);
+ bool compile(const nrex_char* pattern, bool extended = false);
/*!
* \brief Uses the pattern to search through the provided string
diff --git a/drivers/nrex/regex.cpp b/drivers/nrex/regex.cpp
index 0a813c3490..246384b10a 100644
--- a/drivers/nrex/regex.cpp
+++ b/drivers/nrex/regex.cpp
@@ -15,7 +15,7 @@
void RegEx::_bind_methods() {
- ObjectTypeDB::bind_method(_MD("compile","pattern"),&RegEx::compile);
+ ObjectTypeDB::bind_method(_MD("compile","pattern", "expanded"),&RegEx::compile, DEFVAL(true));
ObjectTypeDB::bind_method(_MD("find","text","start","end"),&RegEx::find, DEFVAL(0), DEFVAL(-1));
ObjectTypeDB::bind_method(_MD("clear"),&RegEx::clear);
ObjectTypeDB::bind_method(_MD("is_valid"),&RegEx::is_valid);
@@ -54,7 +54,9 @@ bool RegEx::is_valid() const {
};
int RegEx::get_capture_count() const {
-
+
+ ERR_FAIL_COND_V( !exp.valid(), 0 );
+
return exp.capture_size();
}
@@ -66,11 +68,11 @@ String RegEx::get_capture(int capture) const {
}
-Error RegEx::compile(const String& p_pattern) {
+Error RegEx::compile(const String& p_pattern, bool expanded) {
clear();
- exp.compile(p_pattern.c_str());
+ exp.compile(p_pattern.c_str(), expanded);
ERR_FAIL_COND_V( !exp.valid(), FAILED );
diff --git a/drivers/nrex/regex.h b/drivers/nrex/regex.h
index 0626029705..be52da8149 100644
--- a/drivers/nrex/regex.h
+++ b/drivers/nrex/regex.h
@@ -36,7 +36,7 @@ public:
bool is_valid() const;
int get_capture_count() const;
String get_capture(int capture) const;
- Error compile(const String& p_pattern);
+ Error compile(const String& p_pattern, bool expanded = false);
int find(const String& p_text, int p_start = 0, int p_end = -1) const;
RegEx();
diff --git a/drivers/opus/opus_config.h b/drivers/opus/opus_config.h
index c6470e92c3..98c3e87cc6 100644
--- a/drivers/opus/opus_config.h
+++ b/drivers/opus/opus_config.h
@@ -7,12 +7,16 @@
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
+#if (!defined( _MSC_VER ) || ( _MSC_VER >= 1800 ))
+
/* Define to 1 if you have the `lrint' function. */
#define HAVE_LRINT 1
/* Define to 1 if you have the `lrintf' function. */
#define HAVE_LRINTF 1
+#endif
+
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
@@ -109,7 +113,11 @@
/* Define to the equivalent of the C99 'restrict' keyword, or to
nothing if this is not supported. Do not define if restrict is
supported directly. */
+#if (!defined( _MSC_VER ) || ( _MSC_VER >= 1800 ))
#define restrict __restrict
+#else
+#undef restrict
+#endif
/* Work around a bug in Sun C++: it does not support _Restrict or
__restrict__, even though the corresponding Sun C compiler ends up with
"#define restrict _Restrict" or "#define restrict __restrict__" in the
diff --git a/drivers/theora/decode.c b/drivers/theora/decode.c
index 7be66463d8..882606ae77 100644
--- a/drivers/theora/decode.c
+++ b/drivers/theora/decode.c
@@ -1611,28 +1611,35 @@ static void oc_filter_hedge(unsigned char *_dst,int _dst_ystride,
int sum1;
int bx;
int by;
+ int _rlimit1;
+ int _rlimit2;
rdst=_dst;
rsrc=_src;
- for(bx=0;bx<8;bx++){
+ for(bx=0;bx<8;++bx){
cdst=rdst;
csrc=rsrc;
- for(by=0;by<10;by++){
+ _rlimit1 = _rlimit2 = _flimit;
+ for(by=0;by<10;++by){
r[by]=*csrc;
csrc+=_src_ystride;
}
sum0=sum1=0;
- for(by=0;by<4;by++){
- sum0+=abs(r[by+1]-r[by]);
- sum1+=abs(r[by+5]-r[by+6]);
+ for(by=0;by<4;++by){
+ int sumed = abs(r[by+1]-r[by]);
+ sum0+=sumed;
+ _rlimit1-=sumed;
+ sumed = abs(r[by+5]-r[by+6]);
+ sum1+=sumed;
+ _rlimit2-=sumed;
}
*_variance0+=OC_MINI(255,sum0);
*_variance1+=OC_MINI(255,sum1);
- if(sum0<_flimit&&sum1<_flimit&&r[5]-r[4]<_qstep&&r[4]-r[5]<_qstep){
+ if(_rlimit1&&_rlimit2&&!(r[5]-r[4]-_qstep)&&!(r[4]-r[5]-_qstep)){
*cdst=(unsigned char)(r[0]*3+r[1]*2+r[2]+r[3]+r[4]+4>>3);
cdst+=_dst_ystride;
*cdst=(unsigned char)(r[0]*2+r[1]+r[2]*2+r[3]+r[4]+r[5]+4>>3);
cdst+=_dst_ystride;
- for(by=0;by<4;by++){
+ for(by=0;by<4;++by){
*cdst=(unsigned char)(r[by]+r[by+1]+r[by+2]+r[by+3]*2+
r[by+4]+r[by+5]+r[by+6]+4>>3);
cdst+=_dst_ystride;
@@ -1642,13 +1649,13 @@ static void oc_filter_hedge(unsigned char *_dst,int _dst_ystride,
*cdst=(unsigned char)(r[5]+r[6]+r[7]+r[8]*2+r[9]*3+4>>3);
}
else{
- for(by=1;by<=8;by++){
+ for(by=1;by<=8;++by){
*cdst=(unsigned char)r[by];
cdst+=_dst_ystride;
}
}
- rdst++;
- rsrc++;
+ ++rdst;
+ ++rsrc;
}
}
@@ -1663,19 +1670,26 @@ static void oc_filter_vedge(unsigned char *_dst,int _dst_ystride,
int sum1;
int bx;
int by;
+ int _rlimit1;
+ int _rlimit2;
cdst=_dst;
- for(by=0;by<8;by++){
+ for(by=0;by<8;++by){
rsrc=cdst-1;
rdst=cdst;
- for(bx=0;bx<10;bx++)r[bx]=*rsrc++;
+ for(bx=0;bx<10;++bx)r[bx]=*rsrc++;
sum0=sum1=0;
- for(bx=0;bx<4;bx++){
- sum0+=abs(r[bx+1]-r[bx]);
- sum1+=abs(r[bx+5]-r[bx+6]);
+ _rlimit1 = _rlimit2 = _flimit;
+ for(bx=0;bx<4;++bx){
+ int sumed = abs(r[bx+1]-r[bx]);
+ sum0+=sumed;
+ _rlimit1-=sumed;
+ sumed = abs(r[bx+5]-r[bx+6]);
+ sum1+=sumed;
+ _rlimit2-=sumed;
}
_variances[0]+=OC_MINI(255,sum0);
_variances[1]+=OC_MINI(255,sum1);
- if(sum0<_flimit&&sum1<_flimit&&r[5]-r[4]<_qstep&&r[4]-r[5]<_qstep){
+ if(_rlimit1&&_rlimit2&&!(r[5]-r[4]-_qstep)&&!(r[4]-r[5]-_qstep)){
*rdst++=(unsigned char)(r[0]*3+r[1]*2+r[2]+r[3]+r[4]+4>>3);
*rdst++=(unsigned char)(r[0]*2+r[1]+r[2]*2+r[3]+r[4]+r[5]+4>>3);
for(bx=0;bx<4;bx++){
diff --git a/drivers/theora/video_stream_theora.cpp b/drivers/theora/video_stream_theora.cpp
index bea49e34b7..ed2565177a 100644
--- a/drivers/theora/video_stream_theora.cpp
+++ b/drivers/theora/video_stream_theora.cpp
@@ -178,7 +178,7 @@ void VideoStreamPlaybackTheora::video_write(void){
void VideoStreamPlaybackTheora::clear() {
- if (file_name == "")
+ if (!file)
return;
if(vorbis_p){
@@ -208,6 +208,10 @@ void VideoStreamPlaybackTheora::clear() {
frames_pending = 0;
videobuf_time = 0;
+ if (file) {
+ memdelete(file);
+ }
+ file=NULL;
playing = false;
};
@@ -239,7 +243,9 @@ void VideoStreamPlaybackTheora::set_file(const String& p_file) {
/* Only interested in Vorbis/Theora streams */
int stateflag = 0;
- int audio_track_skip=audio_track;
+ int audio_track_skip=audio_track;
+
+
while(!stateflag){
int ret=buffer_data();
if(ret==0)break;
@@ -265,15 +271,21 @@ void VideoStreamPlaybackTheora::set_file(const String& p_file) {
copymem(&to,&test,sizeof(test));
theora_p=1;
}else if(!vorbis_p && vorbis_synthesis_headerin(&vi,&vc,&op)>=0){
+
+
/* it is vorbis */
- if (audio_track_skip) {
- vorbis_info_clear(&vi);
- vorbis_comment_clear(&vc);
- audio_track_skip--;
- } else {
- copymem(&vo,&test,sizeof(test));
- vorbis_p=1;
- }
+ if (audio_track_skip) {
+ vorbis_info_clear(&vi);
+ vorbis_comment_clear(&vc);
+ ogg_stream_clear(&test);
+ vorbis_info_init(&vi);
+ vorbis_comment_init(&vc);
+
+ audio_track_skip--;
+ } else {
+ copymem(&vo,&test,sizeof(test));
+ vorbis_p=1;
+ }
}else{
/* whatever it is, we don't care about it */
ogg_stream_clear(&test);
@@ -392,6 +404,7 @@ void VideoStreamPlaybackTheora::set_file(const String& p_file) {
fprintf(stderr,"Ogg logical stream %lx is Vorbis %d channel %ld Hz audio.\n",
vo.serialno,vi.channels,vi.rate);
//_setup(vi.channels, vi.rate);
+
}else{
/* tear down the partial vorbis setup */
vorbis_info_clear(&vi);
@@ -401,6 +414,7 @@ void VideoStreamPlaybackTheora::set_file(const String& p_file) {
playing = false;
buffering=true;
time=0;
+ audio_frames_wrote=0;
};
float VideoStreamPlaybackTheora::get_time() const {
@@ -431,8 +445,9 @@ void VideoStreamPlaybackTheora::update(float p_delta) {
return; //no new frames need to be produced
bool frame_done=false;
+ bool audio_done=false;
- while (!frame_done) {
+ while (!frame_done || !audio_done) {
//a frame needs to be produced
ogg_packet op;
@@ -490,6 +505,17 @@ void VideoStreamPlaybackTheora::update(float p_delta) {
audio_pending=true;
+ if (vd.granulepos>=0) {
+ // print_line("wrote: "+itos(audio_frames_wrote)+" gpos: "+itos(vd.granulepos));
+ }
+
+ //print_line("mix audio!");
+
+ audio_frames_wrote+=ret-to_read;
+
+ //print_line("AGP: "+itos(vd.granulepos)+" added "+itos(ret-to_read));
+
+
} else {
/* no pending audio; is there a pending packet to decode? */
@@ -503,6 +529,9 @@ void VideoStreamPlaybackTheora::update(float p_delta) {
};
}
+
+ audio_done = videobuf_time < (audio_frames_wrote/float(vi.rate));
+
if (buffer_full)
break;
}
@@ -567,7 +596,9 @@ void VideoStreamPlaybackTheora::update(float p_delta) {
}
}
#else
- if (!frame_done){
+
+
+ if (!frame_done || !audio_done){
//what's the point of waiting for audio to grab a page?
buffer_data();
@@ -709,8 +740,9 @@ VideoStreamPlaybackTheora::VideoStreamPlaybackTheora() {
texture = Ref<ImageTexture>( memnew(ImageTexture ));
mix_callback=NULL;
mix_udata=NULL;
- audio_track=0;
+ audio_track=0;
delay_compensation=0;
+ audio_frames_wrote=0;
};
VideoStreamPlaybackTheora::~VideoStreamPlaybackTheora() {
diff --git a/drivers/theora/video_stream_theora.h b/drivers/theora/video_stream_theora.h
index 95c7fe88f6..5540f050f9 100644
--- a/drivers/theora/video_stream_theora.h
+++ b/drivers/theora/video_stream_theora.h
@@ -32,6 +32,7 @@ class VideoStreamPlaybackTheora : public VideoStreamPlayback {
void video_write(void);
float get_time() const;
+
ogg_sync_state oy;
ogg_page og;
ogg_stream_state vo;
@@ -122,7 +123,7 @@ public:
Ref<VideoStreamPlayback> instance_playback() {
Ref<VideoStreamPlaybackTheora> pb = memnew( VideoStreamPlaybackTheora );
- pb->set_audio_track(audio_track);
+ pb->set_audio_track(audio_track);
pb->set_file(file);
return pb;
}
diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp
index 8617061ad4..fd8c26f6d9 100644
--- a/drivers/unix/os_unix.cpp
+++ b/drivers/unix/os_unix.cpp
@@ -65,15 +65,25 @@ void OS_Unix::print_error(const char* p_function,const char* p_file,int p_line,c
if (!_print_error_enabled)
return;
- if (p_rationale && p_rationale[0]) {
-
- print("\E[1;31;40mERROR: %s: \E[1;37;40m%s\n",p_function,p_rationale);
- print("\E[0;31;40m At: %s:%i.\E[0;0;37m\n",p_file,p_line);
-
- } else {
- print("\E[1;31;40mERROR: %s: \E[1;37;40m%s\n",p_function,p_code);
- print("\E[0;31;40m At: %s:%i.\E[0;0;37m\n",p_file,p_line);
-
+ const char* err_details;
+ if (p_rationale && p_rationale[0])
+ err_details=p_rationale;
+ else
+ err_details=p_code;
+
+ switch(p_type) {
+ case ERR_ERROR:
+ print("\E[1;31mERROR: %s: \E[0m\E[1m%s\n",p_function,err_details);
+ print("\E[0;31m At: %s:%i.\E[0m\n",p_file,p_line);
+ break;
+ case ERR_WARNING:
+ print("\E[1;33mWARNING: %s: \E[0m\E[1m%s\n",p_function,err_details);
+ print("\E[0;33m At: %s:%i.\E[0m\n",p_file,p_line);
+ break;
+ case ERR_SCRIPT:
+ 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;
}
}
diff --git a/drivers/vorbis/audio_stream_ogg_vorbis.cpp b/drivers/vorbis/audio_stream_ogg_vorbis.cpp
index 8c1c05006f..9a60098526 100644
--- a/drivers/vorbis/audio_stream_ogg_vorbis.cpp
+++ b/drivers/vorbis/audio_stream_ogg_vorbis.cpp
@@ -289,8 +289,7 @@ Error AudioStreamPlaybackOGGVorbis::set_file(const String& p_file) {
const vorbis_info *vinfo=ov_info(&vf,-1);
stream_channels=vinfo->channels;
stream_srate=vinfo->rate;
- ogg_int64_t len = ov_time_total(&vf,-1);
- length=len/1000.0;
+ length = ov_time_total(&vf,-1);
ov_clear(&vf);
memdelete(f);
f=NULL;
diff --git a/drivers/vorbis/audio_stream_ogg_vorbis.h b/drivers/vorbis/audio_stream_ogg_vorbis.h
index 827d8b0be3..5dbada962a 100644
--- a/drivers/vorbis/audio_stream_ogg_vorbis.h
+++ b/drivers/vorbis/audio_stream_ogg_vorbis.h
@@ -85,7 +85,7 @@ public:
virtual void stop();
virtual bool is_playing() const;
- virtual void set_loop_restart_time(float p_time) { loop_restart_time=0; }
+ virtual void set_loop_restart_time(float p_time) { loop_restart_time=p_time; }
virtual void set_paused(bool p_paused);
virtual bool is_paused(bool p_paused) const;