add GLES 2 renderer for 2D

This commit adds a new rendering backend, GLES2, and adds a
project setting to enable it.

Currently this backend can only be used on the X11 platform,
but integrating into other platforms is planned.
This commit is contained in:
karroffel 2017-12-04 13:41:34 +01:00
parent 7f3024d343
commit eac4c984df
41 changed files with 12286 additions and 719 deletions

View file

@ -145,7 +145,7 @@ opts = Variables(customs, ARGUMENTS)
# Target build options
opts.Add('arch', "Platform-dependent architecture (arm/arm64/x86/x64/mips/etc)", '')
opts.Add(EnumVariable('bits', "Target platform bits", 'default', ('default', '32', '64')))
opts.Add(EnumVariable('bits', "Target platform bits", 'default', ('default', '32', '64', 'fat')))
opts.Add('p', "Platform (alias for 'platform')", '')
opts.Add('platform', "Target platform (%s)" % ('|'.join(platform_list), ), '')
opts.Add(EnumVariable('target', "Compilation target", 'debug', ('debug', 'release_debug', 'release')))
@ -161,11 +161,11 @@ opts.Add(BoolVariable('xml', "XML format support for resources", True))
# Advanced options
opts.Add(BoolVariable('disable_3d', "Disable 3D nodes for smaller executable", False))
opts.Add(BoolVariable('disable_advanced_gui', "Disable advanced 3D gui nodes and behaviors", False))
opts.Add(BoolVariable('disable_advanced_gui', "Disable advance 3D gui nodes and behaviors", False))
opts.Add('extra_suffix', "Custom extra suffix added to the base filename of all generated binary files", '')
opts.Add('unix_global_settings_path', "UNIX-specific path to system-wide settings. Currently only used for templates", '')
opts.Add(BoolVariable('verbose', "Enable verbose output for the compilation", False))
opts.Add(BoolVariable('vsproj', "Generate Visual Studio Project", False))
opts.Add(BoolVariable('vsproj', "Generate Visual Studio Project.", False))
opts.Add(EnumVariable('warnings', "Set the level of warnings emitted during compilation", 'no', ('extra', 'all', 'moderate', 'no')))
opts.Add(BoolVariable('progress', "Show a progress indicator during build", True))
opts.Add(BoolVariable('dev', "If yes, alias for verbose=yes warnings=all", False))
@ -353,7 +353,6 @@ if selected_platform in platform_list:
env.Append(CCFLAGS=['-Wall', '-Wno-unused'])
else: # 'no'
env.Append(CCFLAGS=['-w'])
env.Append(CCFLAGS=['-Werror=return-type'])
#env['platform_libsuffix'] = env['LIBSUFFIX']
@ -383,6 +382,8 @@ if selected_platform in platform_list:
suffix += ".32"
elif (env["bits"] == "64"):
suffix += ".64"
elif (env["bits"] == "fat"):
suffix += ".fat"
suffix += env.extra_suffix
@ -445,7 +446,8 @@ if selected_platform in platform_list:
methods.no_verbose(sys, env)
if (not env["platform"] == "server"): # FIXME: detect GLES3
env.Append( BUILDERS = { 'GLES3_GLSL' : env.Builder(action = methods.build_gles3_headers, suffix = 'glsl.gen.h',src_suffix = '.glsl') } )
env.Append( BUILDERS = { 'GLES3_GLSL' : env.Builder(action = methods.build_gles3_headers, suffix = 'glsl.gen.h', src_suffix = '.glsl') } )
env.Append( BUILDERS = { 'GLES2_GLSL' : env.Builder(action = methods.build_gles2_headers, suffix = 'glsl.gen.h', src_suffix = '.glsl') } )
scons_cache_path = os.environ.get("SCONS_CACHE")
if scons_cache_path != None:

1
drivers/SCsub vendored
View file

@ -24,6 +24,7 @@ if env['xaudio2']:
# Graphics drivers
if (env["platform"] != "server"):
SConscript('gles3/SCsub')
SConscript('gles2/SCsub')
SConscript('gl_context/SCsub')
else:
SConscript('dummy/SCsub')

7
drivers/gles2/SCsub Normal file
View file

@ -0,0 +1,7 @@
#!/usr/bin/env python
Import('env')
env.add_source_files(env.drivers_sources,"*.cpp")
SConscript("shaders/SCsub")

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,129 @@
/*************************************************************************/
/* rasterizer_canvas_gles2.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifndef RASTERIZERCANVASGLES2_H
#define RASTERIZERCANVASGLES2_H
#include "rasterizer_storage_gles2.h"
#include "servers/visual/rasterizer.h"
#include "shaders/canvas.glsl.gen.h"
// #include "shaders/canvas_shadow.glsl.gen.h"
class RasterizerSceneGLES2;
class RasterizerCanvasGLES2 : public RasterizerCanvas {
public:
struct Uniforms {
Transform projection_matrix;
Transform2D modelview_matrix;
Transform2D extra_matrix;
Color final_modulate;
float time;
};
struct Data {
GLuint canvas_quad_vertices;
GLuint polygon_buffer;
GLuint polygon_index_buffer;
uint32_t polygon_buffer_size;
GLuint ninepatch_vertices;
GLuint ninepatch_elements;
} data;
struct State {
Uniforms uniforms;
bool canvas_texscreen_used;
CanvasShaderGLES2 canvas_shader;
// CanvasShadowShaderGLES3 canvas_shadow_shader;
bool using_texture_rect;
bool using_ninepatch;
RID current_tex;
RID current_normal;
RasterizerStorageGLES2::Texture *current_tex_ptr;
Transform vp;
} state;
typedef void Texture;
RasterizerSceneGLES2 *scene_render;
RasterizerStorageGLES2 *storage;
virtual RID light_internal_create();
virtual void light_internal_update(RID p_rid, Light *p_light);
virtual void light_internal_free(RID p_rid);
void _set_uniforms();
virtual void canvas_begin();
virtual void canvas_end();
_FORCE_INLINE_ void _set_texture_rect_mode(bool p_enable, bool p_ninepatch = false);
_FORCE_INLINE_ void _draw_gui_primitive(int p_points, const Vector2 *p_vertices, const Color *p_colors, const Vector2 *p_uvs);
_FORCE_INLINE_ void _draw_polygon(const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor);
_FORCE_INLINE_ void _draw_generic(GLuint p_primitive, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor);
_FORCE_INLINE_ void _canvas_item_render_commands(Item *p_item, Item *current_clip, bool &reclip);
_FORCE_INLINE_ void _copy_texscreen(const Rect2 &p_rect);
virtual void canvas_render_items(Item *p_item_list, int p_z, const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform);
virtual void canvas_debug_viewport_shadows(Light *p_lights_with_shadow);
virtual void canvas_light_shadow_buffer_update(RID p_buffer, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders, CameraMatrix *p_xform_cache);
virtual void reset_canvas();
RasterizerStorageGLES2::Texture *_bind_canvas_texture(const RID &p_texture, const RID &p_normal_map);
void _bind_quad_buffer();
void draw_generic_textured_rect(const Rect2 &p_rect, const Rect2 &p_src);
void initialize();
void finalize();
virtual void draw_window_margins(int *black_margin, RID *black_image);
RasterizerCanvasGLES2();
};
#endif // RASTERIZERCANVASGLES2_H

View file

@ -0,0 +1,383 @@
/*************************************************************************/
/* rasterizer_gles2.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "rasterizer_gles2.h"
#include "gl_context/context_gl.h"
#include "os/os.h"
#include "project_settings.h"
#include <string.h>
#define _EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB 0x8242
#define _EXT_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB 0x8243
#define _EXT_DEBUG_CALLBACK_FUNCTION_ARB 0x8244
#define _EXT_DEBUG_CALLBACK_USER_PARAM_ARB 0x8245
#define _EXT_DEBUG_SOURCE_API_ARB 0x8246
#define _EXT_DEBUG_SOURCE_WINDOW_SYSTEM_ARB 0x8247
#define _EXT_DEBUG_SOURCE_SHADER_COMPILER_ARB 0x8248
#define _EXT_DEBUG_SOURCE_THIRD_PARTY_ARB 0x8249
#define _EXT_DEBUG_SOURCE_APPLICATION_ARB 0x824A
#define _EXT_DEBUG_SOURCE_OTHER_ARB 0x824B
#define _EXT_DEBUG_TYPE_ERROR_ARB 0x824C
#define _EXT_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB 0x824D
#define _EXT_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB 0x824E
#define _EXT_DEBUG_TYPE_PORTABILITY_ARB 0x824F
#define _EXT_DEBUG_TYPE_PERFORMANCE_ARB 0x8250
#define _EXT_DEBUG_TYPE_OTHER_ARB 0x8251
#define _EXT_MAX_DEBUG_MESSAGE_LENGTH_ARB 0x9143
#define _EXT_MAX_DEBUG_LOGGED_MESSAGES_ARB 0x9144
#define _EXT_DEBUG_LOGGED_MESSAGES_ARB 0x9145
#define _EXT_DEBUG_SEVERITY_HIGH_ARB 0x9146
#define _EXT_DEBUG_SEVERITY_MEDIUM_ARB 0x9147
#define _EXT_DEBUG_SEVERITY_LOW_ARB 0x9148
#define _EXT_DEBUG_OUTPUT 0x92E0
#if (defined WINDOWS_ENABLED) && !(defined UWP_ENABLED)
#define GLAPIENTRY APIENTRY
#else
#define GLAPIENTRY
#endif
static void GLAPIENTRY _gl_debug_print(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const GLvoid *userParam) {
if (type == _EXT_DEBUG_TYPE_OTHER_ARB)
return;
if (type == _EXT_DEBUG_TYPE_PERFORMANCE_ARB)
return; //these are ultimately annoying, so removing for now
char debSource[256], debType[256], debSev[256];
if (source == _EXT_DEBUG_SOURCE_API_ARB)
strcpy(debSource, "OpenGL");
else if (source == _EXT_DEBUG_SOURCE_WINDOW_SYSTEM_ARB)
strcpy(debSource, "Windows");
else if (source == _EXT_DEBUG_SOURCE_SHADER_COMPILER_ARB)
strcpy(debSource, "Shader Compiler");
else if (source == _EXT_DEBUG_SOURCE_THIRD_PARTY_ARB)
strcpy(debSource, "Third Party");
else if (source == _EXT_DEBUG_SOURCE_APPLICATION_ARB)
strcpy(debSource, "Application");
else if (source == _EXT_DEBUG_SOURCE_OTHER_ARB)
strcpy(debSource, "Other");
if (type == _EXT_DEBUG_TYPE_ERROR_ARB)
strcpy(debType, "Error");
else if (type == _EXT_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB)
strcpy(debType, "Deprecated behavior");
else if (type == _EXT_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB)
strcpy(debType, "Undefined behavior");
else if (type == _EXT_DEBUG_TYPE_PORTABILITY_ARB)
strcpy(debType, "Portability");
else if (type == _EXT_DEBUG_TYPE_PERFORMANCE_ARB)
strcpy(debType, "Performance");
else if (type == _EXT_DEBUG_TYPE_OTHER_ARB)
strcpy(debType, "Other");
if (severity == _EXT_DEBUG_SEVERITY_HIGH_ARB)
strcpy(debSev, "High");
else if (severity == _EXT_DEBUG_SEVERITY_MEDIUM_ARB)
strcpy(debSev, "Medium");
else if (severity == _EXT_DEBUG_SEVERITY_LOW_ARB)
strcpy(debSev, "Low");
String output = String() + "GL ERROR: Source: " + debSource + "\tType: " + debType + "\tID: " + itos(id) + "\tSeverity: " + debSev + "\tMessage: " + message;
ERR_PRINTS(output);
}
typedef void (*DEBUGPROCARB)(GLenum source,
GLenum type,
GLuint id,
GLenum severity,
GLsizei length,
const char *message,
const void *userParam);
typedef void (*DebugMessageCallbackARB)(DEBUGPROCARB callback, const void *userParam);
RasterizerStorage *RasterizerGLES2::get_storage() {
return storage;
}
RasterizerCanvas *RasterizerGLES2::get_canvas() {
return canvas;
}
RasterizerScene *RasterizerGLES2::get_scene() {
return scene;
}
void RasterizerGLES2::initialize() {
if (OS::get_singleton()->is_stdout_verbose()) {
print_line("Using GLES2 video driver");
}
#ifdef GLAD_ENABLED
if (!gladLoadGL()) {
ERR_PRINT("Error initializing GLAD");
}
// GLVersion seems to be used for both GL and GL ES, so we need different version checks for them
#ifdef OPENGL_ENABLED // OpenGL 3.3 Core Profile required
if (GLVersion.major < 3) {
#else // OpenGL ES 3.0
if (GLVersion.major < 2) {
#endif
ERR_PRINT("Your system's graphic drivers seem not to support OpenGL 2.1 / OpenGL ES 2.0, sorry :(\n"
"Try a drivers update, buy a new GPU or try software rendering on Linux; Godot will now crash with a segmentation fault.");
OS::get_singleton()->alert("Your system's graphic drivers seem not to support OpenGL 2.1 / OpenGL ES 2.0, sorry :(\n"
"Godot Engine will self-destruct as soon as you acknowledge this error message.",
"Fatal error: Insufficient OpenGL / GLES driver support");
}
#ifdef __APPLE__
// FIXME glDebugMessageCallbackARB does not seem to work on Mac OS X and opengl 3, this may be an issue with our opengl canvas..
#else
if (true || OS::get_singleton()->is_stdout_verbose()) {
glEnable(_EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
glDebugMessageCallbackARB(_gl_debug_print, NULL);
glEnable(_EXT_DEBUG_OUTPUT);
}
#endif
#endif // GLAD_ENABLED
// For debugging
#ifdef GLES_OVER_GL
glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_ERROR_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, NULL, GL_TRUE);
glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, NULL, GL_TRUE);
glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, NULL, GL_TRUE);
glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_PORTABILITY_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, NULL, GL_TRUE);
glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_PERFORMANCE_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, NULL, GL_TRUE);
glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_OTHER_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, NULL, GL_TRUE);
#endif
/* glDebugMessageInsertARB(
GL_DEBUG_SOURCE_API_ARB,
GL_DEBUG_TYPE_OTHER_ARB, 1,
GL_DEBUG_SEVERITY_HIGH_ARB, 5, "hello");
*/
const GLubyte *renderer = glGetString(GL_RENDERER);
print_line("OpenGL ES 2.0 Renderer: " + String((const char *)renderer));
storage->initialize();
canvas->initialize();
scene->initialize();
}
void RasterizerGLES2::begin_frame() {
uint64_t tick = OS::get_singleton()->get_ticks_usec();
double delta = double(tick - prev_ticks) / 1000000.0;
delta *= Engine::get_singleton()->get_time_scale();
time_total += delta;
if (delta == 0) {
//to avoid hiccups
delta = 0.001;
}
prev_ticks = tick;
// double time_roll_over = GLOBAL_GET("rendering/limits/time/time_rollover_secs");
// if (time_total > time_roll_over)
// time_total = 0; //roll over every day (should be customz
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->frame.count++;
storage->frame.delta = delta;
storage->frame.prev_tick = tick;
storage->update_dirty_resources();
storage->info.render_final = storage->info.render;
storage->info.render.reset();
scene->iteration();
}
void RasterizerGLES2::set_current_render_target(RID p_render_target) {
if (!p_render_target.is_valid() && storage->frame.current_rt && storage->frame.clear_request) {
// pending clear request. Do that first.
glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo);
glClearColor(storage->frame.clear_request_color.r,
storage->frame.clear_request_color.g,
storage->frame.clear_request_color.b,
storage->frame.clear_request_color.a);
glClear(GL_COLOR_BUFFER_BIT);
}
if (p_render_target.is_valid()) {
RasterizerStorageGLES2::RenderTarget *rt = storage->render_target_owner.getornull(p_render_target);
storage->frame.current_rt = rt;
ERR_FAIL_COND(!rt);
storage->frame.clear_request = false;
glViewport(0, 0, rt->width, rt->height);
} else {
storage->frame.current_rt = NULL;
storage->frame.clear_request = false;
glViewport(0, 0, OS::get_singleton()->get_window_size().width, OS::get_singleton()->get_window_size().height);
glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES2::system_fbo);
}
}
void RasterizerGLES2::restore_render_target() {
ERR_FAIL_COND(storage->frame.current_rt == NULL);
RasterizerStorageGLES2::RenderTarget *rt = storage->frame.current_rt;
glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo);
glViewport(0, 0, rt->width, rt->height);
}
void RasterizerGLES2::clear_render_target(const Color &p_color) {
ERR_FAIL_COND(!storage->frame.current_rt);
storage->frame.clear_request = true;
storage->frame.clear_request_color = p_color;
}
void RasterizerGLES2::set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale) {
if (p_image.is_null() || p_image->empty())
return;
int window_w = OS::get_singleton()->get_video_mode(0).width;
int window_h = OS::get_singleton()->get_video_mode(0).height;
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, window_w, window_h);
glDisable(GL_BLEND);
glDepthMask(GL_FALSE);
glClearColor(p_color.r, p_color.g, p_color.b, p_color.a);
glClear(GL_COLOR_BUFFER_BIT);
canvas->canvas_begin();
RID texture = storage->texture_create();
storage->texture_allocate(texture, p_image->get_width(), p_image->get_height(), p_image->get_format(), VS::TEXTURE_FLAG_FILTER);
storage->texture_set_data(texture, p_image);
Rect2 imgrect(0, 0, p_image->get_width(), p_image->get_height());
Rect2 screenrect;
screenrect = imgrect;
screenrect.position += ((Size2(window_w, window_h) - screenrect.size) / 2.0).floor();
RasterizerStorageGLES2::Texture *t = storage->texture_owner.get(texture);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, t->tex_id);
canvas->draw_generic_textured_rect(screenrect, Rect2(0, 0, 1, 1));
glBindTexture(GL_TEXTURE_2D, 0);
canvas->canvas_end();
storage->free(texture);
OS::get_singleton()->swap_buffers();
}
void RasterizerGLES2::blit_render_target_to_screen(RID p_render_target, const Rect2 &p_screen_rect, int p_screen) {
ERR_FAIL_COND(storage->frame.current_rt);
RasterizerStorageGLES2::RenderTarget *rt = storage->render_target_owner.getornull(p_render_target);
ERR_FAIL_COND(!rt);
canvas->state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, true);
canvas->state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, false);
canvas->state.canvas_shader.bind();
canvas->canvas_begin();
canvas->state.canvas_shader.set_uniform(CanvasShaderGLES2::BLIT_PASS, true);
glDisable(GL_BLEND);
glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES2::system_fbo);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, rt->color);
// TODO normals
canvas->draw_generic_textured_rect(p_screen_rect, Rect2(0, 0, 1, -1));
canvas->state.canvas_shader.set_uniform(CanvasShaderGLES2::BLIT_PASS, false);
glBindTexture(GL_TEXTURE_2D, 0);
canvas->canvas_end();
}
void RasterizerGLES2::end_frame(bool p_swap_buffers) {
if (p_swap_buffers)
OS::get_singleton()->swap_buffers();
else
glFinish();
}
void RasterizerGLES2::finalize() {
}
Rasterizer *RasterizerGLES2::_create_current() {
return memnew(RasterizerGLES2);
}
void RasterizerGLES2::make_current() {
_create_func = _create_current;
}
void RasterizerGLES2::register_config() {
}
RasterizerGLES2::RasterizerGLES2() {
storage = memnew(RasterizerStorageGLES2);
canvas = memnew(RasterizerCanvasGLES2);
scene = memnew(RasterizerSceneGLES2);
canvas->storage = storage;
canvas->scene_render = scene;
storage->canvas = canvas;
scene->storage = storage;
storage->scene = scene;
prev_ticks = 0;
time_total = 0;
}
RasterizerGLES2::~RasterizerGLES2() {
memdelete(storage);
memdelete(canvas);
}

View file

@ -0,0 +1,72 @@
/*************************************************************************/
/* rasterizer_gles2.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifndef RASTERIZERGLES2_H
#define RASTERIZERGLES2_H
#include "rasterizer_canvas_gles2.h"
#include "rasterizer_scene_gles2.h"
#include "rasterizer_storage_gles2.h"
#include "servers/visual/rasterizer.h"
class RasterizerGLES2 : public Rasterizer {
static Rasterizer *_create_current();
RasterizerStorageGLES2 *storage;
RasterizerCanvasGLES2 *canvas;
RasterizerSceneGLES2 *scene;
uint64_t prev_ticks;
double time_total;
public:
virtual RasterizerStorage *get_storage();
virtual RasterizerCanvas *get_canvas();
virtual RasterizerScene *get_scene();
virtual void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale);
virtual void initialize();
virtual void begin_frame();
virtual void set_current_render_target(RID p_render_target);
virtual void restore_render_target();
virtual void clear_render_target(const Color &p_color);
virtual void blit_render_target_to_screen(RID p_render_target, const Rect2 &p_screen_rect, int p_screen = 0);
virtual void end_frame(bool p_swap_buffers);
virtual void finalize();
static void make_current();
static void register_config();
RasterizerGLES2();
~RasterizerGLES2();
};
#endif // RASTERIZERGLES2_H

View file

@ -0,0 +1,235 @@
/*************************************************************************/
/* rasterizer_scene_gles2.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "rasterizer_scene_gles2.h"
#include "math_funcs.h"
#include "os/os.h"
#include "project_settings.h"
#include "rasterizer_canvas_gles2.h"
#include "servers/visual/visual_server_raster.h"
#ifndef GLES_OVER_GL
#define glClearDepth glClearDepthf
#endif
/* SHADOW ATLAS API */
RID RasterizerSceneGLES2::shadow_atlas_create() {
return RID();
}
void RasterizerSceneGLES2::shadow_atlas_set_size(RID p_atlas, int p_size) {
}
void RasterizerSceneGLES2::shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) {
}
bool RasterizerSceneGLES2::shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) {
return false;
}
void RasterizerSceneGLES2::set_directional_shadow_count(int p_count) {
}
int RasterizerSceneGLES2::get_directional_light_shadow_size(RID p_light_intance) {
return 0;
}
//////////////////////////////////////////////////////
RID RasterizerSceneGLES2::reflection_atlas_create() {
return RID();
}
void RasterizerSceneGLES2::reflection_atlas_set_size(RID p_ref_atlas, int p_size) {
}
void RasterizerSceneGLES2::reflection_atlas_set_subdivision(RID p_ref_atlas, int p_subdiv) {
}
////////////////////////////////////////////////////
RID RasterizerSceneGLES2::reflection_probe_instance_create(RID p_probe) {
return RID();
}
void RasterizerSceneGLES2::reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform) {
}
void RasterizerSceneGLES2::reflection_probe_release_atlas_index(RID p_instance) {
}
bool RasterizerSceneGLES2::reflection_probe_instance_needs_redraw(RID p_instance) {
return false;
}
bool RasterizerSceneGLES2::reflection_probe_instance_has_reflection(RID p_instance) {
return false;
}
bool RasterizerSceneGLES2::reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) {
return false;
}
bool RasterizerSceneGLES2::reflection_probe_instance_postprocess_step(RID p_instance) {
return false;
}
/* ENVIRONMENT API */
RID RasterizerSceneGLES2::environment_create() {
return RID();
}
void RasterizerSceneGLES2::environment_set_background(RID p_env, VS::EnvironmentBG p_bg) {
}
void RasterizerSceneGLES2::environment_set_sky(RID p_env, RID p_sky) {
}
void RasterizerSceneGLES2::environment_set_sky_custom_fov(RID p_env, float p_scale) {
}
void RasterizerSceneGLES2::environment_set_bg_color(RID p_env, const Color &p_color) {
}
void RasterizerSceneGLES2::environment_set_bg_energy(RID p_env, float p_energy) {
}
void RasterizerSceneGLES2::environment_set_canvas_max_layer(RID p_env, int p_max_layer) {
}
void RasterizerSceneGLES2::environment_set_ambient_light(RID p_env, const Color &p_color, float p_energy, float p_sky_contribution) {
}
void RasterizerSceneGLES2::environment_set_dof_blur_far(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality) {
}
void RasterizerSceneGLES2::environment_set_dof_blur_near(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality) {
}
void RasterizerSceneGLES2::environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, bool p_bicubic_upscale) {
}
void RasterizerSceneGLES2::environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture) {
}
void RasterizerSceneGLES2::environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_in, float p_fade_out, float p_depth_tolerance, bool p_roughness) {
}
void RasterizerSceneGLES2::environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_radius2, float p_intensity2, float p_bias, float p_light_affect, const Color &p_color, VS::EnvironmentSSAOQuality p_quality, VisualServer::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness) {
}
void RasterizerSceneGLES2::environment_set_tonemap(RID p_env, VS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale) {
}
void RasterizerSceneGLES2::environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp) {
}
void RasterizerSceneGLES2::environment_set_fog(RID p_env, bool p_enable, const Color &p_color, const Color &p_sun_color, float p_sun_amount) {
}
void RasterizerSceneGLES2::environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_curve, bool p_transmit, float p_transmit_curve) {
}
void RasterizerSceneGLES2::environment_set_fog_height(RID p_env, bool p_enable, float p_min_height, float p_max_height, float p_height_curve) {
}
bool RasterizerSceneGLES2::is_environment(RID p_env) {
return false;
}
VS::EnvironmentBG RasterizerSceneGLES2::environment_get_background(RID p_env) {
return VS::ENV_BG_CLEAR_COLOR;
}
int RasterizerSceneGLES2::environment_get_canvas_max_layer(RID p_env) {
return 0;
}
RID RasterizerSceneGLES2::light_instance_create(RID p_light) {
return RID();
}
void RasterizerSceneGLES2::light_instance_set_transform(RID p_light_instance, const Transform &p_transform) {
}
void RasterizerSceneGLES2::light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_bias_scale) {
}
void RasterizerSceneGLES2::light_instance_mark_visible(RID p_light_instance) {
}
//////////////////////
RID RasterizerSceneGLES2::gi_probe_instance_create() {
return RID();
}
void RasterizerSceneGLES2::gi_probe_instance_set_light_data(RID p_probe, RID p_base, RID p_data) {
}
void RasterizerSceneGLES2::gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) {
}
void RasterizerSceneGLES2::gi_probe_instance_set_bounds(RID p_probe, const Vector3 &p_bounds) {
}
////////////////////////////
////////////////////////////
////////////////////////////
void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) {
}
void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) {
}
void RasterizerSceneGLES2::set_scene_pass(uint64_t p_pass) {
}
bool RasterizerSceneGLES2::free(RID p_rid) {
return true;
}
void RasterizerSceneGLES2::set_debug_draw_mode(VS::ViewportDebugDraw p_debug_draw) {
}
void RasterizerSceneGLES2::initialize() {
}
void RasterizerSceneGLES2::iteration() {
}
void RasterizerSceneGLES2::finalize() {
}
RasterizerSceneGLES2::RasterizerSceneGLES2() {
}

View file

@ -0,0 +1,258 @@
/*************************************************************************/
/* rasterizer_scene_gles2.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifndef RASTERIZERSCENEGLES2_H
#define RASTERIZERSCENEGLES2_H
/* Must come before shaders or the Windows build fails... */
#include "rasterizer_storage_gles2.h"
#include "shaders/scene.glsl.gen.h"
/*
#include "drivers/gles3/shaders/cube_to_dp.glsl.gen.h"
#include "drivers/gles3/shaders/effect_blur.glsl.gen.h"
#include "drivers/gles3/shaders/exposure.glsl.gen.h"
#include "drivers/gles3/shaders/resolve.glsl.gen.h"
#include "drivers/gles3/shaders/scene.glsl.gen.h"
#include "drivers/gles3/shaders/screen_space_reflection.glsl.gen.h"
#include "drivers/gles3/shaders/ssao.glsl.gen.h"
#include "drivers/gles3/shaders/ssao_blur.glsl.gen.h"
#include "drivers/gles3/shaders/ssao_minify.glsl.gen.h"
#include "drivers/gles3/shaders/subsurf_scattering.glsl.gen.h"
#include "drivers/gles3/shaders/tonemap.glsl.gen.h"
*/
class RasterizerSceneGLES2 : public RasterizerScene {
public:
RasterizerStorageGLES2 *storage;
struct State {
bool texscreen_copied;
int current_blend_mode;
float current_line_width;
int current_depth_draw;
bool current_depth_test;
GLuint current_main_tex;
SceneShaderGLES2 scene_shader;
// CubeToDpShaderGLES3 cube_to_dp_shader;
// ResolveShaderGLES3 resolve_shader;
// ScreenSpaceReflectionShaderGLES3 ssr_shader;
// EffectBlurShaderGLES3 effect_blur_shader;
// SubsurfScatteringShaderGLES3 sss_shader;
// SsaoMinifyShaderGLES3 ssao_minify_shader;
// SsaoShaderGLES3 ssao_shader;
// SsaoBlurShaderGLES3 ssao_blur_shader;
// ExposureShaderGLES3 exposure_shader;
// TonemapShaderGLES3 tonemap_shader;
/*
struct SceneDataUBO {
//this is a std140 compatible struct. Please read the OpenGL 3.3 Specificaiton spec before doing any changes
float projection_matrix[16];
float inv_projection_matrix[16];
float camera_inverse_matrix[16];
float camera_matrix[16];
float ambient_light_color[4];
float bg_color[4];
float fog_color_enabled[4];
float fog_sun_color_amount[4];
float ambient_energy;
float bg_energy;
float z_offset;
float z_slope_scale;
float shadow_dual_paraboloid_render_zfar;
float shadow_dual_paraboloid_render_side;
float viewport_size[2];
float screen_pixel_size[2];
float shadow_atlas_pixel_size[2];
float shadow_directional_pixel_size[2];
float time;
float z_far;
float reflection_multiplier;
float subsurface_scatter_width;
float ambient_occlusion_affect_light;
uint32_t fog_depth_enabled;
float fog_depth_begin;
float fog_depth_curve;
uint32_t fog_transmit_enabled;
float fog_transmit_curve;
uint32_t fog_height_enabled;
float fog_height_min;
float fog_height_max;
float fog_height_curve;
// make sure this struct is padded to be a multiple of 16 bytes for webgl
} ubo_data;
GLuint scene_ubo;
struct EnvironmentRadianceUBO {
float transform[16];
float ambient_contribution;
uint8_t padding[12];
} env_radiance_data;
GLuint env_radiance_ubo;
GLuint sky_verts;
GLuint sky_array;
GLuint directional_ubo;
GLuint spot_array_ubo;
GLuint omni_array_ubo;
GLuint reflection_array_ubo;
GLuint immediate_buffer;
GLuint immediate_array;
uint32_t ubo_light_size;
uint8_t *spot_array_tmp;
uint8_t *omni_array_tmp;
uint8_t *reflection_array_tmp;
int max_ubo_lights;
int max_forward_lights_per_object;
int max_ubo_reflections;
int max_skeleton_bones;
bool used_contact_shadows;
int spot_light_count;
int omni_light_count;
int directional_light_count;
int reflection_probe_count;
bool cull_front;
bool cull_disabled;
bool used_sss;
bool used_screen_texture;
bool using_contact_shadows;
VS::ViewportDebugDraw debug_draw;
*/
} state;
/* SHADOW ATLAS API */
RID shadow_atlas_create();
void shadow_atlas_set_size(RID p_atlas, int p_size);
void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision);
bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version);
virtual int get_directional_light_shadow_size(RID p_light_intance);
virtual void set_directional_shadow_count(int p_count);
/* REFLECTION PROBE ATLAS API */
virtual RID reflection_atlas_create();
virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_size);
virtual void reflection_atlas_set_subdivision(RID p_ref_atlas, int p_subdiv);
/* REFLECTION CUBEMAPS */
/* REFLECTION PROBE INSTANCE */
virtual RID reflection_probe_instance_create(RID p_probe);
virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform);
virtual void reflection_probe_release_atlas_index(RID p_instance);
virtual bool reflection_probe_instance_needs_redraw(RID p_instance);
virtual bool reflection_probe_instance_has_reflection(RID p_instance);
virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas);
virtual bool reflection_probe_instance_postprocess_step(RID p_instance);
/* ENVIRONMENT API */
virtual RID environment_create();
virtual void environment_set_background(RID p_env, VS::EnvironmentBG p_bg);
virtual void environment_set_sky(RID p_env, RID p_sky);
virtual void environment_set_sky_custom_fov(RID p_env, float p_scale);
virtual void environment_set_bg_color(RID p_env, const Color &p_color);
virtual void environment_set_bg_energy(RID p_env, float p_energy);
virtual void environment_set_canvas_max_layer(RID p_env, int p_max_layer);
virtual void environment_set_ambient_light(RID p_env, const Color &p_color, float p_energy = 1.0, float p_sky_contribution = 0.0);
virtual void environment_set_dof_blur_near(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality);
virtual void environment_set_dof_blur_far(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality);
virtual void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, bool p_bicubic_upscale);
virtual void environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture);
virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_in, float p_fade_out, float p_depth_tolerance, bool p_roughness);
virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_radius2, float p_intensity2, float p_bias, float p_light_affect, const Color &p_color, VS::EnvironmentSSAOQuality p_quality, VS::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness);
virtual void environment_set_tonemap(RID p_env, VS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale);
virtual void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp);
virtual void environment_set_fog(RID p_env, bool p_enable, const Color &p_color, const Color &p_sun_color, float p_sun_amount);
virtual void environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_curve, bool p_transmit, float p_transmit_curve);
virtual void environment_set_fog_height(RID p_env, bool p_enable, float p_min_height, float p_max_height, float p_height_curve);
virtual bool is_environment(RID p_env);
virtual VS::EnvironmentBG environment_get_background(RID p_env);
virtual int environment_get_canvas_max_layer(RID p_env);
/* LIGHT INSTANCE */
virtual RID light_instance_create(RID p_light);
virtual void light_instance_set_transform(RID p_light_instance, const Transform &p_transform);
virtual void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_bias_scale = 1.0);
virtual void light_instance_mark_visible(RID p_light_instance);
/* REFLECTION INSTANCE */
virtual RID gi_probe_instance_create();
virtual void gi_probe_instance_set_light_data(RID p_probe, RID p_base, RID p_data);
virtual void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform);
virtual void gi_probe_instance_set_bounds(RID p_probe, const Vector3 &p_bounds);
/* RENDER LIST */
virtual void render_scene(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass);
virtual void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count);
virtual bool free(RID p_rid);
virtual void set_scene_pass(uint64_t p_pass);
virtual void set_debug_draw_mode(VS::ViewportDebugDraw p_debug_draw);
void iteration();
void initialize();
void finalize();
RasterizerSceneGLES2();
};
#endif // RASTERIZERSCENEGLES2_H

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,838 @@
/*************************************************************************/
/* rasterizer_storage_gles2.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifndef RASTERIZERSTORAGEGLES2_H
#define RASTERIZERSTORAGEGLES2_H
#include "self_list.h"
#include "servers/visual/rasterizer.h"
#include "servers/visual/shader_language.h"
#include "shader_compiler_gles2.h"
#include "shader_gles2.h"
#include "shaders/copy.glsl.gen.h"
/*
#include "shaders/blend_shape.glsl.gen.h"
#include "shaders/canvas.glsl.gen.h"
#include "shaders/copy.glsl.gen.h"
#include "shaders/cubemap_filter.glsl.gen.h"
#include "shaders/particles.glsl.gen.h"
*/
class RasterizerCanvasGLES2;
class RasterizerSceneGLES2;
class RasterizerStorageGLES2 : public RasterizerStorage {
public:
RasterizerCanvasGLES2 *canvas;
RasterizerSceneGLES2 *scene;
static GLuint system_fbo;
struct Config {
bool shrink_textures_x2;
bool use_fast_texture_filter;
// bool use_anisotropic_filter;
bool hdr_supported;
bool use_rgba_2d_shadows;
// float anisotropic_level;
int max_texture_image_units;
int max_texture_size;
bool generate_wireframes;
bool use_texture_array_environment;
Set<String> extensions;
bool keep_original_textures;
bool no_depth_prepass;
bool force_vertex_shading;
} config;
struct Resources {
GLuint white_tex;
GLuint black_tex;
GLuint normal_tex;
GLuint aniso_tex;
GLuint quadie;
GLuint quadie_array;
} resources;
mutable struct Shaders {
ShaderCompilerGLES2 compiler;
CopyShaderGLES2 copy;
ShaderCompilerGLES2::IdentifierActions actions_canvas;
ShaderCompilerGLES2::IdentifierActions actions_scene;
ShaderCompilerGLES2::IdentifierActions actions_particles;
} shaders;
struct Info {
uint64_t texture_mem;
uint64_t vertex_mem;
struct Render {
uint32_t object_count;
uint32_t draw_call_count;
uint32_t material_switch_count;
uint32_t surface_switch_count;
uint32_t shader_rebind_count;
uint32_t vertices_count;
void reset() {
object_count = 0;
draw_call_count = 0;
material_switch_count = 0;
surface_switch_count = 0;
shader_rebind_count = 0;
vertices_count = 0;
}
} render, render_final, snap;
Info() {
texture_mem = 0;
vertex_mem = 0;
render.reset();
render_final.reset();
}
} info;
/////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////DATA///////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////API////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
/* TEXTURE API */
struct RenderTarget;
struct Texture : RID_Data {
Texture *proxy;
Set<Texture *> proxy_owners;
String path;
uint32_t flags;
int width, height;
int alloc_width, alloc_height;
Image::Format format;
GLenum target;
GLenum gl_format_cache;
GLenum gl_internal_format_cache;
GLenum gl_type_cache;
int data_size;
int total_data_size;
bool ignore_mipmaps;
int mipmaps;
bool active;
GLenum tex_id;
uint16_t stored_cube_sides;
RenderTarget *render_target;
Ref<Image> images[6];
Texture() {
flags = 0;
width = 0;
height = 0;
alloc_width = 0;
alloc_height = 0;
format = Image::FORMAT_L8;
target = 0;
data_size = 0;
total_data_size = 0;
ignore_mipmaps = false;
active = false;
tex_id = 0;
stored_cube_sides = 0;
proxy = NULL;
render_target = NULL;
}
_ALWAYS_INLINE_ Texture *get_ptr() {
if (proxy) {
return proxy; //->get_ptr(); only one level of indirection, else not inlining possible.
} else {
return this;
}
}
~Texture() {
if (tex_id != 0) {
glDeleteTextures(1, &tex_id);
}
for (Set<Texture *>::Element *E = proxy_owners.front(); E; E = E->next()) {
E->get()->proxy = NULL;
}
if (proxy) {
proxy->proxy_owners.erase(this);
}
}
};
mutable RID_Owner<Texture> texture_owner;
Ref<Image> _get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type);
virtual RID texture_create();
virtual void texture_allocate(RID p_texture, int p_width, int p_height, Image::Format p_format, uint32_t p_flags = VS::TEXTURE_FLAGS_DEFAULT);
virtual void texture_set_data(RID p_texture, const Ref<Image> &p_image, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT);
virtual Ref<Image> texture_get_data(RID p_texture, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT) const;
virtual void texture_set_flags(RID p_texture, uint32_t p_flags);
virtual uint32_t texture_get_flags(RID p_texture) const;
virtual Image::Format texture_get_format(RID p_texture) const;
virtual uint32_t texture_get_texid(RID p_texture) const;
virtual uint32_t texture_get_width(RID p_texture) const;
virtual uint32_t texture_get_height(RID p_texture) const;
virtual void texture_set_size_override(RID p_texture, int p_width, int p_height);
virtual void texture_set_path(RID p_texture, const String &p_path);
virtual String texture_get_path(RID p_texture) const;
virtual void texture_set_shrink_all_x2_on_set_data(bool p_enable);
virtual void texture_debug_usage(List<VS::TextureInfo> *r_info);
virtual RID texture_create_radiance_cubemap(RID p_source, int p_resolution = -1) const;
virtual void textures_keep_original(bool p_enable);
virtual void texture_set_proxy(RID p_texture, RID p_proxy);
virtual void texture_set_detect_3d_callback(RID p_texture, VisualServer::TextureDetectCallback p_callback, void *p_userdata);
virtual void texture_set_detect_srgb_callback(RID p_texture, VisualServer::TextureDetectCallback p_callback, void *p_userdata);
virtual void texture_set_detect_normal_callback(RID p_texture, VisualServer::TextureDetectCallback p_callback, void *p_userdata);
/* SKY API */
virtual RID sky_create();
virtual void sky_set_texture(RID p_sky, RID p_panorama, int p_radiance_size);
/* SHADER API */
struct Material;
struct Shader : public RID_Data {
RID self;
VS::ShaderMode mode;
ShaderGLES2 *shader;
String code;
SelfList<Material>::List materials;
Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
uint32_t texture_count;
uint32_t custom_code_id;
uint32_t version;
SelfList<Shader> dirty_list;
Map<StringName, RID> default_textures;
Vector<ShaderLanguage::ShaderNode::Uniform::Hint> texture_hints;
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;
*/
bool uses_screen_texture;
bool uses_screen_uv;
bool uses_time;
} canvas_item;
/*
struct Spatial {
enum BlendMode {
BLEND_MODE_MIX,
BLEND_MODE_ADD,
BLEND_MODE_SUB,
BLEND_MODE_MUL,
};
int blend_mode;
enum DepthDrawMode {
DEPTH_DRAW_OPAQUE,
DEPTH_DRAW_ALWAYS,
DEPTH_DRAW_NEVER,
DEPTH_DRAW_ALPHA_PREPASS,
};
int depth_draw_mode;
enum CullMode {
CULL_MODE_FRONT,
CULL_MODE_BACK,
CULL_MODE_DISABLED,
};
int cull_mode;
bool uses_alpha;
bool uses_alpha_scissor;
bool unshaded;
bool no_depth_test;
bool uses_vertex;
bool uses_discard;
bool uses_sss;
bool uses_screen_texture;
bool uses_time;
bool writes_modelview_or_projection;
bool uses_vertex_lighting;
bool uses_world_coordinates;
} spatial;
struct Particles {
} particles;
*/
bool uses_vertex_time;
bool uses_fragment_time;
Shader() :
dirty_list(this) {
shader = NULL;
valid = false;
custom_code_id = 0;
version = 1;
}
};
mutable RID_Owner<Shader> shader_owner;
mutable SelfList<Shader>::List _shader_dirty_list;
void _shader_make_dirty(Shader *p_shader);
virtual RID shader_create();
virtual void shader_set_code(RID p_shader, const String &p_code);
virtual String shader_get_code(RID p_shader) const;
virtual void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const;
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;
Map<StringName, Variant> params;
SelfList<Material> list;
SelfList<Material> dirty_list;
Vector<RID> textures;
float line_width;
int render_priority;
RID next_pass;
uint32_t index;
uint64_t last_pass;
Map<Geometry *, int> geometry_owners;
Map<RasterizerScene::InstanceBase *, int> instance_owners;
bool can_cast_shadow_cache;
bool is_animated_cache;
Material() :
list(this),
dirty_list(this) {
can_cast_shadow_cache = false;
is_animated_cache = false;
shader = NULL;
line_width = 1.0;
last_pass = 0;
render_priority = 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_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;
virtual void material_set_line_width(RID p_material, float p_width);
virtual void material_set_next_pass(RID p_material, RID p_next_material);
virtual bool material_is_animated(RID p_material);
virtual bool material_casts_shadows(RID p_material);
virtual void material_add_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance);
virtual void material_remove_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance);
virtual void material_set_render_priority(RID p_material, int priority);
void update_dirty_materials();
/* MESH API */
virtual RID mesh_create();
virtual void mesh_add_surface(RID p_mesh, uint32_t p_format, VS::PrimitiveType p_primitive, const PoolVector<uint8_t> &p_array, int p_vertex_count, const PoolVector<uint8_t> &p_index_array, int p_index_count, const AABB &p_aabb, const Vector<PoolVector<uint8_t> > &p_blend_shapes = Vector<PoolVector<uint8_t> >(), const Vector<AABB> &p_bone_aabbs = Vector<AABB>());
virtual void mesh_set_blend_shape_count(RID p_mesh, int p_amount);
virtual int mesh_get_blend_shape_count(RID p_mesh) const;
virtual void mesh_set_blend_shape_mode(RID p_mesh, VS::BlendShapeMode p_mode);
virtual VS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const;
virtual void mesh_surface_update_region(RID p_mesh, int p_surface, int p_offset, const PoolVector<uint8_t> &p_data);
virtual void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material);
virtual RID mesh_surface_get_material(RID p_mesh, int p_surface) const;
virtual int mesh_surface_get_array_len(RID p_mesh, int p_surface) const;
virtual int mesh_surface_get_array_index_len(RID p_mesh, int p_surface) const;
virtual PoolVector<uint8_t> mesh_surface_get_array(RID p_mesh, int p_surface) const;
virtual PoolVector<uint8_t> mesh_surface_get_index_array(RID p_mesh, int p_surface) const;
virtual uint32_t mesh_surface_get_format(RID p_mesh, int p_surface) const;
virtual VS::PrimitiveType mesh_surface_get_primitive_type(RID p_mesh, int p_surface) const;
virtual AABB mesh_surface_get_aabb(RID p_mesh, int p_surface) const;
virtual Vector<PoolVector<uint8_t> > mesh_surface_get_blend_shapes(RID p_mesh, int p_surface) const;
virtual Vector<AABB> mesh_surface_get_skeleton_aabb(RID p_mesh, int p_surface) const;
virtual void mesh_remove_surface(RID p_mesh, int p_surface);
virtual int mesh_get_surface_count(RID p_mesh) const;
virtual void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb);
virtual AABB mesh_get_custom_aabb(RID p_mesh) const;
virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton) const;
virtual void mesh_clear(RID p_mesh);
/* MULTIMESH API */
virtual RID multimesh_create();
virtual void multimesh_allocate(RID p_multimesh, int p_instances, VS::MultimeshTransformFormat p_transform_format, VS::MultimeshColorFormat p_color_format);
virtual int multimesh_get_instance_count(RID p_multimesh) const;
virtual void multimesh_set_mesh(RID p_multimesh, RID p_mesh);
virtual void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform);
virtual void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform);
virtual void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color);
virtual RID multimesh_get_mesh(RID p_multimesh) const;
virtual Transform multimesh_instance_get_transform(RID p_multimesh, int p_index) const;
virtual Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const;
virtual Color multimesh_instance_get_color(RID p_multimesh, int p_index) const;
virtual void multimesh_set_visible_instances(RID p_multimesh, int p_visible);
virtual int multimesh_get_visible_instances(RID p_multimesh) const;
virtual AABB multimesh_get_aabb(RID p_multimesh) const;
void update_dirty_multimeshes();
/* IMMEDIATE API */
virtual RID immediate_create();
virtual void immediate_begin(RID p_immediate, VS::PrimitiveType p_rimitive, RID p_texture = RID());
virtual void immediate_vertex(RID p_immediate, const Vector3 &p_vertex);
virtual void immediate_normal(RID p_immediate, const Vector3 &p_normal);
virtual void immediate_tangent(RID p_immediate, const Plane &p_tangent);
virtual void immediate_color(RID p_immediate, const Color &p_color);
virtual void immediate_uv(RID p_immediate, const Vector2 &tex_uv);
virtual void immediate_uv2(RID p_immediate, const Vector2 &tex_uv);
virtual void immediate_end(RID p_immediate);
virtual void immediate_clear(RID p_immediate);
virtual void immediate_set_material(RID p_immediate, RID p_material);
virtual RID immediate_get_material(RID p_immediate) const;
virtual AABB immediate_get_aabb(RID p_immediate) const;
/* SKELETON API */
void update_dirty_skeletons();
virtual RID skeleton_create();
virtual void skeleton_allocate(RID p_skeleton, int p_bones, bool p_2d_skeleton = false);
virtual int skeleton_get_bone_count(RID p_skeleton) const;
virtual void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform &p_transform);
virtual Transform skeleton_bone_get_transform(RID p_skeleton, int p_bone) const;
virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform);
virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const;
/* Light API */
virtual RID light_create(VS::LightType p_type);
virtual void light_set_color(RID p_light, const Color &p_color);
virtual void light_set_param(RID p_light, VS::LightParam p_param, float p_value);
virtual void light_set_shadow(RID p_light, bool p_enabled);
virtual void light_set_shadow_color(RID p_light, const Color &p_color);
virtual void light_set_projector(RID p_light, RID p_texture);
virtual void light_set_negative(RID p_light, bool p_enable);
virtual void light_set_cull_mask(RID p_light, uint32_t p_mask);
virtual void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled);
virtual void light_omni_set_shadow_mode(RID p_light, VS::LightOmniShadowMode p_mode);
virtual void light_omni_set_shadow_detail(RID p_light, VS::LightOmniShadowDetail p_detail);
virtual void light_directional_set_shadow_mode(RID p_light, VS::LightDirectionalShadowMode p_mode);
virtual void light_directional_set_blend_splits(RID p_light, bool p_enable);
virtual bool light_directional_get_blend_splits(RID p_light) const;
virtual VS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light);
virtual VS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light);
virtual void light_directional_set_shadow_depth_range_mode(RID p_light, VS::LightDirectionalShadowDepthRangeMode p_range_mode);
virtual VS::LightDirectionalShadowDepthRangeMode light_directional_get_shadow_depth_range_mode(RID p_light) const;
virtual bool light_has_shadow(RID p_light) const;
virtual VS::LightType light_get_type(RID p_light) const;
virtual float light_get_param(RID p_light, VS::LightParam p_param);
virtual Color light_get_color(RID p_light);
virtual AABB light_get_aabb(RID p_light) const;
virtual uint64_t light_get_version(RID p_light) const;
/* PROBE API */
virtual RID reflection_probe_create();
virtual void reflection_probe_set_update_mode(RID p_probe, VS::ReflectionProbeUpdateMode p_mode);
virtual void reflection_probe_set_intensity(RID p_probe, float p_intensity);
virtual void reflection_probe_set_interior_ambient(RID p_probe, const Color &p_ambient);
virtual void reflection_probe_set_interior_ambient_energy(RID p_probe, float p_energy);
virtual void reflection_probe_set_interior_ambient_probe_contribution(RID p_probe, float p_contrib);
virtual void reflection_probe_set_max_distance(RID p_probe, float p_distance);
virtual void reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents);
virtual void reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset);
virtual void reflection_probe_set_as_interior(RID p_probe, bool p_enable);
virtual void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable);
virtual void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable);
virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers);
virtual AABB reflection_probe_get_aabb(RID p_probe) const;
virtual VS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const;
virtual uint32_t reflection_probe_get_cull_mask(RID p_probe) const;
virtual Vector3 reflection_probe_get_extents(RID p_probe) const;
virtual Vector3 reflection_probe_get_origin_offset(RID p_probe) const;
virtual float reflection_probe_get_origin_max_distance(RID p_probe) const;
virtual bool reflection_probe_renders_shadows(RID p_probe) const;
/* GI PROBE API */
virtual RID gi_probe_create();
virtual void gi_probe_set_bounds(RID p_probe, const AABB &p_bounds);
virtual AABB gi_probe_get_bounds(RID p_probe) const;
virtual void gi_probe_set_cell_size(RID p_probe, float p_size);
virtual float gi_probe_get_cell_size(RID p_probe) const;
virtual void gi_probe_set_to_cell_xform(RID p_probe, const Transform &p_xform);
virtual Transform gi_probe_get_to_cell_xform(RID p_probe) const;
virtual void gi_probe_set_dynamic_data(RID p_probe, const PoolVector<int> &p_data);
virtual PoolVector<int> gi_probe_get_dynamic_data(RID p_probe) const;
virtual void gi_probe_set_dynamic_range(RID p_probe, int p_range);
virtual int gi_probe_get_dynamic_range(RID p_probe) const;
virtual void gi_probe_set_energy(RID p_probe, float p_range);
virtual float gi_probe_get_energy(RID p_probe) const;
virtual void gi_probe_set_bias(RID p_probe, float p_range);
virtual float gi_probe_get_bias(RID p_probe) const;
virtual void gi_probe_set_normal_bias(RID p_probe, float p_range);
virtual float gi_probe_get_normal_bias(RID p_probe) const;
virtual void gi_probe_set_propagation(RID p_probe, float p_range);
virtual float gi_probe_get_propagation(RID p_probe) const;
virtual void gi_probe_set_interior(RID p_probe, bool p_enable);
virtual bool gi_probe_is_interior(RID p_probe) const;
virtual void gi_probe_set_compress(RID p_probe, bool p_enable);
virtual bool gi_probe_is_compressed(RID p_probe) const;
virtual uint32_t gi_probe_get_version(RID p_probe);
virtual GIProbeCompression gi_probe_get_dynamic_data_get_preferred_compression() const;
virtual RID gi_probe_dynamic_data_create(int p_width, int p_height, int p_depth, GIProbeCompression p_compression);
virtual void gi_probe_dynamic_data_update(RID p_gi_probe_data, int p_depth_slice, int p_slice_count, int p_mipmap, const void *p_data);
/* LIGHTMAP */
virtual RID lightmap_capture_create();
virtual void lightmap_capture_set_bounds(RID p_capture, const AABB &p_bounds);
virtual AABB lightmap_capture_get_bounds(RID p_capture) const;
virtual void lightmap_capture_set_octree(RID p_capture, const PoolVector<uint8_t> &p_octree);
virtual PoolVector<uint8_t> lightmap_capture_get_octree(RID p_capture) const;
virtual void lightmap_capture_set_octree_cell_transform(RID p_capture, const Transform &p_xform);
virtual Transform lightmap_capture_get_octree_cell_transform(RID p_capture) const;
virtual void lightmap_capture_set_octree_cell_subdiv(RID p_capture, int p_subdiv);
virtual int lightmap_capture_get_octree_cell_subdiv(RID p_capture) const;
virtual void lightmap_capture_set_energy(RID p_capture, float p_energy);
virtual float lightmap_capture_get_energy(RID p_capture) const;
virtual const PoolVector<LightmapCaptureOctree> *lightmap_capture_get_octree_ptr(RID p_capture) const;
/* PARTICLES */
void update_particles();
virtual RID particles_create();
virtual void particles_set_emitting(RID p_particles, bool p_emitting);
virtual bool particles_get_emitting(RID p_particles);
virtual void particles_set_amount(RID p_particles, int p_amount);
virtual void particles_set_lifetime(RID p_particles, float p_lifetime);
virtual void particles_set_one_shot(RID p_particles, bool p_one_shot);
virtual void particles_set_pre_process_time(RID p_particles, float p_time);
virtual void particles_set_explosiveness_ratio(RID p_particles, float p_ratio);
virtual void particles_set_randomness_ratio(RID p_particles, float p_ratio);
virtual void particles_set_custom_aabb(RID p_particles, const AABB &p_aabb);
virtual void particles_set_speed_scale(RID p_particles, float p_scale);
virtual void particles_set_use_local_coordinates(RID p_particles, bool p_enable);
virtual void particles_set_process_material(RID p_particles, RID p_material);
virtual void particles_set_fixed_fps(RID p_particles, int p_fps);
virtual void particles_set_fractional_delta(RID p_particles, bool p_enable);
virtual void particles_restart(RID p_particles);
virtual void particles_set_draw_order(RID p_particles, VS::ParticlesDrawOrder p_order);
virtual void particles_set_draw_passes(RID p_particles, int p_passes);
virtual void particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh);
virtual void particles_request_process(RID p_particles);
virtual AABB particles_get_current_aabb(RID p_particles);
virtual AABB particles_get_aabb(RID p_particles) const;
virtual void particles_set_emission_transform(RID p_particles, const Transform &p_transform);
virtual int particles_get_draw_passes(RID p_particles) const;
virtual RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const;
/* INSTANCE */
virtual void instance_add_skeleton(RID p_skeleton, RasterizerScene::InstanceBase *p_instance);
virtual void instance_remove_skeleton(RID p_skeleton, RasterizerScene::InstanceBase *p_instance);
virtual void instance_add_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance);
virtual void instance_remove_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance);
/* RENDER TARGET */
struct RenderTarget : public RID_Data {
GLuint fbo;
GLuint color;
GLuint depth;
// TODO post processing effects?
// TODO HDR?
// TODO this is hardcoded for texscreen copies for now
struct Effect {
GLuint fbo;
int width;
int height;
GLuint color;
Effect() {
fbo = 0;
width = 0;
height = 0;
color = 0;
}
};
Effect copy_screen_effect;
int width, height;
bool flags[RENDER_TARGET_FLAG_MAX];
bool used_in_frame;
VS::ViewportMSAA msaa;
RID texture;
RenderTarget() {
fbo = 0;
color = 0;
depth = 0;
width = 0;
height = 0;
for (int i = 0; i < RENDER_TARGET_FLAG_MAX; i++) {
flags[i] = false;
}
used_in_frame = false;
msaa = VS::VIEWPORT_MSAA_DISABLED;
}
};
mutable RID_Owner<RenderTarget> render_target_owner;
void _render_target_clear(RenderTarget *rt);
void _render_target_allocate(RenderTarget *rt);
virtual RID render_target_create();
virtual void render_target_set_size(RID p_render_target, int p_width, int p_height);
virtual RID render_target_get_texture(RID p_render_target) const;
virtual void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value);
virtual bool render_target_was_used(RID p_render_target);
virtual void render_target_clear_used(RID p_render_target);
virtual void render_target_set_msaa(RID p_render_target, VS::ViewportMSAA p_msaa);
/* CANVAS SHADOW */
virtual RID canvas_light_shadow_buffer_create(int p_width);
/* LIGHT SHADOW MAPPING */
virtual RID canvas_light_occluder_create();
virtual void canvas_light_occluder_set_polylines(RID p_occluder, const PoolVector<Vector2> &p_lines);
virtual VS::InstanceType get_base_type(RID p_rid) const;
virtual bool free(RID p_rid);
struct Frame {
RenderTarget *current_rt;
bool clear_request;
Color clear_request_color;
int canvas_draw_commands;
float time[4];
float delta;
uint64_t prev_tick;
uint64_t count;
} frame;
void initialize();
void finalize();
virtual bool has_os_feature(const String &p_feature) const;
virtual void update_dirty_resources();
virtual void set_debug_generate_wireframes(bool p_generate);
virtual void render_info_begin_capture();
virtual void render_info_end_capture();
virtual int get_captured_render_info(VS::RenderInfo p_info);
virtual int get_render_info(VS::RenderInfo p_info);
RasterizerStorageGLES2();
};
#endif // RASTERIZERSTORAGEGLES2_H

View file

@ -0,0 +1,891 @@
/*************************************************************************/
/* shader_compiler_gles3.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "shader_compiler_gles2.h"
#include "os/os.h"
#include "string_buffer.h"
#include "string_builder.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 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 _qualstr(SL::ArgumentQualifier p_qual) {
switch (p_qual) {
case SL::ARGUMENT_QUALIFIER_IN: return "in ";
case SL::ARGUMENT_QUALIFIER_OUT: return "out ";
case SL::ARGUMENT_QUALIFIER_INOUT: return "inout ";
}
return "";
}
static String _opstr(SL::Operator p_op) {
return SL::get_operator_text(p_op);
}
static String _mkid(const String &p_id) {
StringBuffer<> id;
id += "m_";
id += p_id;
return id.as_string();
}
static String f2sp0(float p_float) {
if (int(p_float) == p_float)
return itos(p_float) + ".0";
else
return rtoss(p_float);
}
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:
case SL::TYPE_BVEC3:
case SL::TYPE_BVEC4: {
StringBuffer<> text;
text += "bvec";
text += itos(p_type - SL::TYPE_BOOL + 1);
text += "(";
for (int i = 0; i < p_values.size(); i++) {
if (i > 0)
text += ",";
text += p_values[i].boolean ? "true" : "false";
}
text += ")";
return text.as_string();
}
// GLSL ES 2 doesn't support uints, so we just use signed ints instead...
case SL::TYPE_UINT: return itos(p_values[0].uint);
case SL::TYPE_UVEC2:
case SL::TYPE_UVEC3:
case SL::TYPE_UVEC4: {
StringBuffer<> text;
text += "ivec";
text += itos(p_type - SL::TYPE_UINT + 1);
text += "(";
for (int i = 0; i < p_values.size(); i++) {
if (i > 0)
text += ",";
text += itos(p_values[i].uint);
}
text += ")";
return text.as_string();
} break;
case SL::TYPE_INT: return itos(p_values[0].sint);
case SL::TYPE_IVEC2:
case SL::TYPE_IVEC3:
case SL::TYPE_IVEC4: {
StringBuffer<> text;
text += "ivec";
text += itos(p_type - SL::TYPE_INT + 1);
text += "(";
for (int i = 0; i < p_values.size(); i++) {
if (i > 0)
text += ",";
text += itos(p_values[i].sint);
}
text += ")";
return text.as_string();
} break;
case SL::TYPE_FLOAT: return f2sp0(p_values[0].real) + "f";
case SL::TYPE_VEC2:
case SL::TYPE_VEC3:
case SL::TYPE_VEC4: {
StringBuffer<> text;
text += "vec";
text += itos(p_type - SL::TYPE_FLOAT + 1);
text += "(";
for (int i = 0; i < p_values.size(); i++) {
if (i > 0)
text += ",";
text += f2sp0(p_values[i].real);
}
text += ")";
return text.as_string();
} break;
case SL::TYPE_MAT2:
case SL::TYPE_MAT3:
case SL::TYPE_MAT4: {
StringBuffer<> text;
text += "mat";
text += itos(p_type - SL::TYPE_MAT2 + 2);
text += "(";
for (int i = 0; i < p_values.size(); i++) {
if (i > 0)
text += ",";
text += f2sp0(p_values[i].real);
}
text += ")";
return text.as_string();
} break;
default: ERR_FAIL_V(String());
}
}
void ShaderCompilerGLES2::_dump_function_deps(SL::ShaderNode *p_node, const StringName &p_for_func, const Map<StringName, String> &p_func_code, StringBuilder &r_to_add, Set<StringName> &r_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 (r_added.has(E->get())) {
continue;
}
_dump_function_deps(p_node, E->get(), p_func_code, r_to_add, r_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";
StringBuffer<128> header;
header += _typestr(fnode->return_type);
header += " ";
header += _mkid(fnode->name);
header += "(";
for (int i = 0; i < fnode->arguments.size(); i++) {
if (i > 0)
header += ", ";
header += _qualstr(fnode->arguments[i].qualifier);
header += _prestr(fnode->arguments[i].precision);
header += _typestr(fnode->arguments[i].type);
header += " ";
header += _mkid(fnode->arguments[i].name);
}
header += ")\n";
r_to_add += header.as_string();
r_to_add += p_func_code[E->get()];
r_added.insert(E->get());
}
}
String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, GeneratedCode &r_gen_code, IdentifierActions &p_actions, const DefaultIdentifierActions &p_default_actions, bool p_assigning) {
StringBuilder code;
switch (p_node->type) {
case SL::Node::TYPE_SHADER: {
SL::ShaderNode *snode = (SL::ShaderNode *)p_node;
for (int i = 0; i < snode->render_modes.size(); i++) {
if (p_default_actions.render_mode_defines.has(snode->render_modes[i]) && !used_rmode_defines.has(snode->render_modes[i])) {
r_gen_code.custom_defines.push_back(p_default_actions.render_mode_defines[snode->render_modes[i]].utf8());
used_rmode_defines.insert(snode->render_modes[i]);
}
if (p_actions.render_mode_flags.has(snode->render_modes[i])) {
*p_actions.render_mode_flags[snode->render_modes[i]] = true;
}
if (p_actions.render_mode_values.has(snode->render_modes[i])) {
Pair<int *, int> &p = p_actions.render_mode_values[snode->render_modes[i]];
*p.first = p.second;
}
}
int max_texture_uniforms = 0;
int max_uniforms = 0;
for (Map<StringName, SL::ShaderNode::Uniform>::Element *E = snode->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);
r_gen_code.texture_hints.resize(max_texture_uniforms);
r_gen_code.uniforms.resize(max_uniforms + max_texture_uniforms);
StringBuilder vertex_global;
StringBuilder fragment_global;
// uniforms
for (Map<StringName, SL::ShaderNode::Uniform>::Element *E = snode->uniforms.front(); E; E = E->next()) {
StringBuffer<> uniform_code;
uniform_code += "uniform ";
uniform_code += _prestr(E->get().precission);
uniform_code += _typestr(E->get().type);
uniform_code += " ";
uniform_code += _mkid(E->key());
uniform_code += ";\n";
if (SL::is_sampler_type(E->get().type)) {
r_gen_code.texture_uniforms[E->get().texture_order] = _mkid(E->key());
r_gen_code.texture_hints[E->get().texture_order] = E->get().hint;
} else {
r_gen_code.uniforms[E->get().order] = E->key();
}
vertex_global += uniform_code.as_string();
fragment_global += uniform_code.as_string();
p_actions.uniforms->insert(E->key(), E->get());
}
// varyings
for (Map<StringName, SL::ShaderNode::Varying>::Element *E = snode->varyings.front(); E; E = E->next()) {
StringBuffer<> varying_code;
varying_code += "varying ";
varying_code += _prestr(E->get().precission);
varying_code += _typestr(E->get().type);
varying_code += " ";
varying_code += _mkid(E->key());
varying_code += ";\n";
String final_code = varying_code.as_string();
vertex_global += final_code;
fragment_global += final_code;
}
// functions
Map<StringName, String> function_code;
for (int i = 0; i < snode->functions.size(); i++) {
SL::FunctionNode *fnode = snode->functions[i].function;
function_code[fnode->name] = _dump_node_code(fnode->body, 1, r_gen_code, p_actions, p_default_actions, p_assigning);
}
Set<StringName> added_vertex;
Set<StringName> added_fragment;
for (int i = 0; i < snode->functions.size(); i++) {
SL::FunctionNode *fnode = snode->functions[i].function;
current_func_name = fnode->name;
if (fnode->name == vertex_name) {
_dump_function_deps(snode, fnode->name, function_code, vertex_global, added_vertex);
r_gen_code.vertex = function_code[vertex_name];
} else if (fnode->name == fragment_name) {
_dump_function_deps(snode, fnode->name, function_code, fragment_global, added_fragment);
r_gen_code.fragment = function_code[fragment_name];
} else if (fnode->name == light_name) {
_dump_function_deps(snode, fnode->name, function_code, fragment_global, added_fragment);
r_gen_code.light = function_code[light_name];
}
}
r_gen_code.vertex_global = vertex_global.as_string();
r_gen_code.fragment_global = fragment_global.as_string();
} break;
case SL::Node::TYPE_FUNCTION: {
} break;
case SL::Node::TYPE_BLOCK: {
SL::BlockNode *bnode = (SL::BlockNode *)p_node;
if (!bnode->single_statement) {
code += _mktab(p_level - 1);
code += "{\n";
}
for (int i = 0; i < bnode->statements.size(); i++) {
String statement_code = _dump_node_code(bnode->statements[i], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
if (bnode->statements[i]->type == SL::Node::TYPE_CONTROL_FLOW || bnode->single_statement) {
code += statement_code;
} else {
code += _mktab(p_level);
code += statement_code;
code += ";\n";
}
}
if (!bnode->single_statement) {
code += _mktab(p_level - 1);
code += "}\n";
}
} break;
case SL::Node::TYPE_VARIABLE_DECLARATION: {
SL::VariableDeclarationNode *var_dec_node = (SL::VariableDeclarationNode *)p_node;
StringBuffer<> declaration;
declaration += _prestr(var_dec_node->precision);
declaration += _typestr(var_dec_node->datatype);
for (int i = 0; i < var_dec_node->declarations.size(); i++) {
if (i > 0) {
declaration += ",";
}
declaration += " ";
declaration += _mkid(var_dec_node->declarations[i].name);
if (var_dec_node->declarations[i].initializer) {
declaration += " = ";
declaration += _dump_node_code(var_dec_node->declarations[i].initializer, p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
}
}
code += declaration.as_string();
} break;
case SL::Node::TYPE_VARIABLE: {
SL::VariableNode *var_node = (SL::VariableNode *)p_node;
if (p_assigning && p_actions.write_flag_pointers.has(var_node->name)) {
*p_actions.write_flag_pointers[var_node->name] = true;
}
if (p_default_actions.usage_defines.has(var_node->name) && !used_name_defines.has(var_node->name)) {
String define = p_default_actions.usage_defines[var_node->name];
if (define.begins_with("@")) {
define = p_default_actions.usage_defines[define.substr(1, define.length())];
}
r_gen_code.custom_defines.push_back(define.utf8());
used_name_defines.insert(var_node->name);
}
if (p_actions.usage_flag_pointers.has(var_node->name) && !used_flag_pointers.has(var_node->name)) {
*p_actions.usage_flag_pointers[var_node->name] = true;
used_flag_pointers.insert(var_node->name);
}
if (p_default_actions.renames.has(var_node->name)) {
code += p_default_actions.renames[var_node->name];
} else {
code += _mkid(var_node->name);
}
if (var_node->name == time_name) {
if (current_func_name == vertex_name) {
r_gen_code.uses_vertex_time = true;
}
if (current_func_name == fragment_name || current_func_name == light_name) {
r_gen_code.uses_fragment_time = true;
}
}
} break;
case SL::Node::TYPE_CONSTANT: {
SL::ConstantNode *const_node = (SL::ConstantNode *)p_node;
return get_constant_text(const_node->datatype, const_node->values);
} break;
case SL::Node::TYPE_OPERATOR: {
SL::OperatorNode *op_node = (SL::OperatorNode *)p_node;
switch (op_node->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(op_node->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, true);
code += " ";
code += _opstr(op_node->op);
code += " ";
code += _dump_node_code(op_node->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
} break;
case SL::OP_BIT_INVERT:
case SL::OP_NEGATE:
case SL::OP_NOT:
case SL::OP_DECREMENT:
case SL::OP_INCREMENT: {
code += _opstr(op_node->op);
code += _dump_node_code(op_node->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
} break;
case SL::OP_POST_DECREMENT:
case SL::OP_POST_INCREMENT: {
code += _dump_node_code(op_node->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
code += _opstr(op_node->op);
} break;
case SL::OP_CALL:
case SL::OP_CONSTRUCT: {
ERR_FAIL_COND_V(op_node->arguments[0]->type != SL::Node::TYPE_VARIABLE, String());
SL::VariableNode *var_node = (SL::VariableNode *)op_node->arguments[0];
if (op_node->op == SL::OP_CONSTRUCT) {
code += var_node->name;
} else {
if (var_node->name == "texture") {
// emit texture call
if (op_node->arguments[1]->get_datatype() == SL::TYPE_SAMPLER2D) {
code += "texture2D";
} else if (op_node->arguments[1]->get_datatype() == SL::TYPE_SAMPLERCUBE) {
code += "textureCube";
}
} else if (p_default_actions.renames.has(var_node->name)) {
code += p_default_actions.renames[var_node->name];
} else if (internal_functions.has(var_node->name)) {
code += var_node->name;
} else {
code += _mkid(var_node->name);
}
}
code += "(";
for (int i = 1; i < op_node->arguments.size(); i++) {
if (i > 1) {
code += ", ";
}
code += _dump_node_code(op_node->arguments[i], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
}
code += ")";
} break;
case SL::OP_INDEX: {
code += _dump_node_code(op_node->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
code += "[";
code += _dump_node_code(op_node->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
code += "]";
} break;
case SL::OP_SELECT_IF: {
code += _dump_node_code(op_node->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
code += " ? ";
code += _dump_node_code(op_node->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
code += " : ";
code += _dump_node_code(op_node->arguments[2], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
} break;
default: {
code += "(";
code += _dump_node_code(op_node->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
code += " ";
code += _opstr(op_node->op);
code += " ";
code += _dump_node_code(op_node->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
code += ")";
} break;
}
} break;
case SL::Node::TYPE_CONTROL_FLOW: {
SL::ControlFlowNode *cf_node = (SL::ControlFlowNode *)p_node;
if (cf_node->flow_op == SL::FLOW_OP_IF) {
code += _mktab(p_level);
code += "if (";
code += _dump_node_code(cf_node->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
code += ")\n";
code += _dump_node_code(cf_node->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning);
if (cf_node->blocks.size() == 2) {
code += _mktab(p_level);
code += "else\n";
code += _dump_node_code(cf_node->blocks[1], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning);
}
} else if (cf_node->flow_op == SL::FLOW_OP_WHILE) {
code += _mktab(p_level);
code += "while (";
code += _dump_node_code(cf_node->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
code += ")\n";
code += _dump_node_code(cf_node->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning);
} else if (cf_node->flow_op == SL::FLOW_OP_FOR) {
code += _mktab(p_level);
code += "for (";
code += _dump_node_code(cf_node->blocks[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
code += "; ";
code += _dump_node_code(cf_node->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
code += "; ";
code += _dump_node_code(cf_node->expressions[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
code += ")\n";
code += _dump_node_code(cf_node->blocks[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
} else if (cf_node->flow_op == SL::FLOW_OP_RETURN) {
code += _mktab(p_level);
code += "return";
if (cf_node->expressions.size()) {
code += " ";
code += _dump_node_code(cf_node->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
}
code += ";\n";
} else if (cf_node->flow_op == SL::FLOW_OP_DISCARD) {
code += "discard;";
} else if (cf_node->flow_op == SL::FLOW_OP_CONTINUE) {
code += "continue;";
} else if (cf_node->flow_op == SL::FLOW_OP_BREAK) {
code += "break;";
}
} break;
case SL::Node::TYPE_MEMBER: {
SL::MemberNode *member_node = (SL::MemberNode *)p_node;
code += _dump_node_code(member_node->owner, p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
code += ".";
code += member_node->name;
} break;
}
return code.as_string();
}
Error ShaderCompilerGLES2::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), ShaderTypes::get_singleton()->get_types());
if (err != OK) {
Vector<String> shader = p_code.split("\n");
for (int i = 0; i < shader.size(); i++) {
print_line(itos(i) + " " + shader[i]);
}
_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.custom_defines.clear();
r_gen_code.uniforms.clear();
r_gen_code.texture_uniforms.clear();
r_gen_code.texture_hints.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();
r_gen_code.uses_fragment_time = false;
r_gen_code.uses_vertex_time = false;
used_name_defines.clear();
used_rmode_defines.clear();
used_flag_pointers.clear();
_dump_node_code(parser.get_shader(), 1, r_gen_code, *p_actions, actions[p_mode], false);
return OK;
}
ShaderCompilerGLES2::ShaderCompilerGLES2() {
/** CANVAS ITEM SHADER **/
actions[VS::SHADER_CANVAS_ITEM].renames["VERTEX"] = "outvec.xy";
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["AT_LIGHT_PASS"] = "at_light_pass";
actions[VS::SHADER_CANVAS_ITEM].renames["INSTANCE_CUSTOM"] = "instance_custom";
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["NORMAL_TEXTURE"] = "normal_texture";
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["SCREEN_PIXEL_SIZE"] = "screen_pixel_size";
actions[VS::SHADER_CANVAS_ITEM].renames["FRAGCOORD"] = "gl_FragCoord";
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["SCREEN_PIXEL_SIZE"] = "@SCREEN_UV";
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].usage_defines["LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
actions[VS::SHADER_CANVAS_ITEM].render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n";
/** SPATIAL SHADER **/
actions[VS::SHADER_SPATIAL].renames["WORLD_MATRIX"] = "world_transform";
actions[VS::SHADER_SPATIAL].renames["INV_CAMERA_MATRIX"] = "camera_inverse_matrix";
actions[VS::SHADER_SPATIAL].renames["CAMERA_MATRIX"] = "camera_matrix";
actions[VS::SHADER_SPATIAL].renames["PROJECTION_MATRIX"] = "projection_matrix";
actions[VS::SHADER_SPATIAL].renames["INV_PROJECTION_MATRIX"] = "inv_projection_matrix";
actions[VS::SHADER_SPATIAL].renames["MODELVIEW_MATRIX"] = "modelview";
actions[VS::SHADER_SPATIAL].renames["VERTEX"] = "vertex.xyz";
actions[VS::SHADER_SPATIAL].renames["NORMAL"] = "normal";
actions[VS::SHADER_SPATIAL].renames["TANGENT"] = "tangent";
actions[VS::SHADER_SPATIAL].renames["BINORMAL"] = "binormal";
actions[VS::SHADER_SPATIAL].renames["UV"] = "uv_interp";
actions[VS::SHADER_SPATIAL].renames["UV2"] = "uv2_interp";
actions[VS::SHADER_SPATIAL].renames["COLOR"] = "color_interp";
actions[VS::SHADER_SPATIAL].renames["POINT_SIZE"] = "gl_PointSize";
//actions[VS::SHADER_SPATIAL].renames["INSTANCE_ID"]=ShaderLanguage::TYPE_INT;
//builtins
actions[VS::SHADER_SPATIAL].renames["TIME"] = "time";
actions[VS::SHADER_SPATIAL].renames["VIEWPORT_SIZE"] = "viewport_size";
actions[VS::SHADER_SPATIAL].renames["FRAGCOORD"] = "gl_FragCoord";
actions[VS::SHADER_SPATIAL].renames["FRONT_FACING"] = "gl_FrontFacing";
actions[VS::SHADER_SPATIAL].renames["NORMALMAP"] = "normalmap";
actions[VS::SHADER_SPATIAL].renames["NORMALMAP_DEPTH"] = "normaldepth";
actions[VS::SHADER_SPATIAL].renames["ALBEDO"] = "albedo";
actions[VS::SHADER_SPATIAL].renames["ALPHA"] = "alpha";
actions[VS::SHADER_SPATIAL].renames["METALLIC"] = "metallic";
actions[VS::SHADER_SPATIAL].renames["SPECULAR"] = "specular";
actions[VS::SHADER_SPATIAL].renames["ROUGHNESS"] = "roughness";
actions[VS::SHADER_SPATIAL].renames["RIM"] = "rim";
actions[VS::SHADER_SPATIAL].renames["RIM_TINT"] = "rim_tint";
actions[VS::SHADER_SPATIAL].renames["CLEARCOAT"] = "clearcoat";
actions[VS::SHADER_SPATIAL].renames["CLEARCOAT_GLOSS"] = "clearcoat_gloss";
actions[VS::SHADER_SPATIAL].renames["ANISOTROPY"] = "anisotropy";
actions[VS::SHADER_SPATIAL].renames["ANISOTROPY_FLOW"] = "anisotropy_flow";
//actions[VS::SHADER_SPATIAL].renames["SSS_SPREAD"] = "sss_spread";
actions[VS::SHADER_SPATIAL].renames["SSS_STRENGTH"] = "sss_strength";
actions[VS::SHADER_SPATIAL].renames["TRANSMISSION"] = "transmission";
actions[VS::SHADER_SPATIAL].renames["AO"] = "ao";
actions[VS::SHADER_SPATIAL].renames["AO_LIGHT_AFFECT"] = "ao_light_affect";
actions[VS::SHADER_SPATIAL].renames["EMISSION"] = "emission";
//actions[VS::SHADER_SPATIAL].renames["SCREEN_UV"]=ShaderLanguage::TYPE_VEC2;
actions[VS::SHADER_SPATIAL].renames["POINT_COORD"] = "gl_PointCoord";
actions[VS::SHADER_SPATIAL].renames["INSTANCE_CUSTOM"] = "instance_custom";
actions[VS::SHADER_SPATIAL].renames["SCREEN_UV"] = "screen_uv";
actions[VS::SHADER_SPATIAL].renames["SCREEN_TEXTURE"] = "screen_texture";
actions[VS::SHADER_SPATIAL].renames["DEPTH_TEXTURE"] = "depth_buffer";
actions[VS::SHADER_SPATIAL].renames["SIDE"] = "side";
actions[VS::SHADER_SPATIAL].renames["ALPHA_SCISSOR"] = "alpha_scissor";
//for light
actions[VS::SHADER_SPATIAL].renames["VIEW"] = "view";
actions[VS::SHADER_SPATIAL].renames["LIGHT_COLOR"] = "light_color";
actions[VS::SHADER_SPATIAL].renames["ATTENUATION"] = "attenuation";
actions[VS::SHADER_SPATIAL].renames["DIFFUSE_LIGHT"] = "diffuse_light";
actions[VS::SHADER_SPATIAL].renames["SPECULAR_LIGHT"] = "specular_light";
actions[VS::SHADER_SPATIAL].usage_defines["TANGENT"] = "#define ENABLE_TANGENT_INTERP\n";
actions[VS::SHADER_SPATIAL].usage_defines["BINORMAL"] = "@TANGENT";
actions[VS::SHADER_SPATIAL].usage_defines["RIM"] = "#define LIGHT_USE_RIM\n";
actions[VS::SHADER_SPATIAL].usage_defines["RIM_TINT"] = "@RIM";
actions[VS::SHADER_SPATIAL].usage_defines["CLEARCOAT"] = "#define LIGHT_USE_CLEARCOAT\n";
actions[VS::SHADER_SPATIAL].usage_defines["CLEARCOAT_GLOSS"] = "@CLEARCOAT";
actions[VS::SHADER_SPATIAL].usage_defines["ANISOTROPY"] = "#define LIGHT_USE_ANISOTROPY\n";
actions[VS::SHADER_SPATIAL].usage_defines["ANISOTROPY_FLOW"] = "@ANISOTROPY";
actions[VS::SHADER_SPATIAL].usage_defines["AO"] = "#define ENABLE_AO\n";
actions[VS::SHADER_SPATIAL].usage_defines["AO_LIGHT_AFFECT"] = "#define ENABLE_AO\n";
actions[VS::SHADER_SPATIAL].usage_defines["UV"] = "#define ENABLE_UV_INTERP\n";
actions[VS::SHADER_SPATIAL].usage_defines["UV2"] = "#define ENABLE_UV2_INTERP\n";
actions[VS::SHADER_SPATIAL].usage_defines["NORMALMAP"] = "#define ENABLE_NORMALMAP\n";
actions[VS::SHADER_SPATIAL].usage_defines["NORMALMAP_DEPTH"] = "@NORMALMAP";
actions[VS::SHADER_SPATIAL].usage_defines["COLOR"] = "#define ENABLE_COLOR_INTERP\n";
actions[VS::SHADER_SPATIAL].usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n";
actions[VS::SHADER_SPATIAL].usage_defines["ALPHA_SCISSOR"] = "#define ALPHA_SCISSOR_USED\n";
actions[VS::SHADER_SPATIAL].usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n";
actions[VS::SHADER_SPATIAL].usage_defines["TRANSMISSION"] = "#define TRANSMISSION_USED\n";
actions[VS::SHADER_SPATIAL].usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n";
actions[VS::SHADER_SPATIAL].usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n";
actions[VS::SHADER_SPATIAL].usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
actions[VS::SHADER_SPATIAL].usage_defines["SPECULAR_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
actions[VS::SHADER_SPATIAL].renames["SSS_STRENGTH"] = "sss_strength";
actions[VS::SHADER_SPATIAL].render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n";
actions[VS::SHADER_SPATIAL].render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n";
actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n";
actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_oren_nayar"] = "#define DIFFUSE_OREN_NAYAR\n";
actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n";
actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n";
actions[VS::SHADER_SPATIAL].render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n";
actions[VS::SHADER_SPATIAL].render_mode_defines["specular_blinn"] = "#define SPECULAR_BLINN\n";
actions[VS::SHADER_SPATIAL].render_mode_defines["specular_phong"] = "#define SPECULAR_PHONG\n";
actions[VS::SHADER_SPATIAL].render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n";
actions[VS::SHADER_SPATIAL].render_mode_defines["specular_disabled"] = "#define SPECULAR_DISABLED\n";
/* PARTICLES SHADER */
actions[VS::SHADER_PARTICLES].renames["COLOR"] = "out_color";
actions[VS::SHADER_PARTICLES].renames["VELOCITY"] = "out_velocity_active.xyz";
actions[VS::SHADER_PARTICLES].renames["MASS"] = "mass";
actions[VS::SHADER_PARTICLES].renames["ACTIVE"] = "active";
actions[VS::SHADER_PARTICLES].renames["RESTART"] = "restart";
actions[VS::SHADER_PARTICLES].renames["CUSTOM"] = "out_custom";
actions[VS::SHADER_PARTICLES].renames["TRANSFORM"] = "xform";
actions[VS::SHADER_PARTICLES].renames["TIME"] = "time";
actions[VS::SHADER_PARTICLES].renames["LIFETIME"] = "lifetime";
actions[VS::SHADER_PARTICLES].renames["DELTA"] = "local_delta";
actions[VS::SHADER_PARTICLES].renames["NUMBER"] = "particle_number";
actions[VS::SHADER_PARTICLES].renames["INDEX"] = "index";
actions[VS::SHADER_PARTICLES].renames["GRAVITY"] = "current_gravity";
actions[VS::SHADER_PARTICLES].renames["EMISSION_TRANSFORM"] = "emission_transform";
actions[VS::SHADER_PARTICLES].renames["RANDOM_SEED"] = "random_seed";
actions[VS::SHADER_SPATIAL].render_mode_defines["disable_force"] = "#define DISABLE_FORCE\n";
actions[VS::SHADER_SPATIAL].render_mode_defines["disable_velocity"] = "#define DISABLE_VELOCITY\n";
actions[VS::SHADER_SPATIAL].render_mode_defines["keep_data"] = "#define ENABLE_KEEP_DATA\n";
vertex_name = "vertex";
fragment_name = "fragment";
light_name = "light";
time_name = "TIME";
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());
}
}

View file

@ -0,0 +1,101 @@
/*************************************************************************/
/* shader_compiler_gles2.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifndef SHADERCOMPILERGLES2_H
#define SHADERCOMPILERGLES2_H
#include "pair.h"
#include "servers/visual/shader_language.h"
#include "servers/visual/shader_types.h"
#include "servers/visual_server.h"
#include "string_builder.h"
class ShaderCompilerGLES2 {
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, bool *> write_flag_pointers;
Map<StringName, ShaderLanguage::ShaderNode::Uniform> *uniforms;
};
struct GeneratedCode {
Vector<CharString> custom_defines;
Vector<StringName> uniforms;
Vector<StringName> texture_uniforms;
Vector<ShaderLanguage::ShaderNode::Uniform::Hint> texture_hints;
String vertex_global;
String vertex;
String fragment_global;
String fragment;
String light;
bool uses_fragment_time;
bool uses_vertex_time;
};
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, StringBuilder &r_to_add, Set<StringName> &r_added);
String _dump_node_code(ShaderLanguage::Node *p_node, int p_level, GeneratedCode &r_gen_code, IdentifierActions &p_actions, const DefaultIdentifierActions &p_default_actions, bool p_assigning);
StringName current_func_name;
StringName vertex_name;
StringName fragment_name;
StringName light_name;
StringName time_name;
Set<StringName> used_name_defines;
Set<StringName> used_flag_pointers;
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);
ShaderCompilerGLES2();
};
#endif // SHADERCOMPILERGLES3_H

View file

@ -0,0 +1,689 @@
/*************************************************************************/
/* shader_gles2.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "shader_gles2.h"
#include "memory.h"
#include "print_string.h"
#include "string_builder.h"
//#define DEBUG_OPENGL
// #include "shaders/copy.glsl.gen.h"
#ifdef DEBUG_OPENGL
#define DEBUG_TEST_ERROR(m_section) \
{ \
uint32_t err = glGetError(); \
if (err) { \
print_line("OpenGL Error #" + itos(err) + " at: " + m_section); \
} \
}
#else
#define DEBUG_TEST_ERROR(m_section)
#endif
ShaderGLES2 *ShaderGLES2::active = NULL;
//#define DEBUG_SHADER
#ifdef DEBUG_SHADER
#define DEBUG_PRINT(m_text) print_line(m_text);
#else
#define DEBUG_PRINT(m_text)
#endif
void ShaderGLES2::bind_uniforms() {
if (!uniforms_dirty)
return;
// regular uniforms
const Map<uint32_t, Variant>::Element *E = uniform_defaults.front();
while (E) {
int idx = E->key();
int location = version->uniform_location[idx];
if (location < 0) {
E = E->next();
continue;
}
const Variant &v = E->value();
_set_uniform_variant(location, v);
E = E->next();
}
// camera uniforms
const Map<uint32_t, CameraMatrix>::Element *C = uniform_cameras.front();
while (C) {
int idx = E->key();
int location = version->uniform_location[idx];
if (location < 0) {
C = C->next();
continue;
}
glUniformMatrix4fv(location, 1, GL_FALSE, &(C->get().matrix[0][0]));
C = C->next();
}
uniforms_dirty = false;
}
GLint ShaderGLES2::get_uniform_location(int p_index) const {
ERR_FAIL_COND_V(!version, -1);
return version->uniform_location[p_index];
}
bool ShaderGLES2::bind() {
if (active != this || !version || new_conditional_version.key != conditional_version.key) {
conditional_version = new_conditional_version;
version = get_current_version();
} else {
return false;
}
ERR_FAIL_COND_V(!version, false);
glUseProgram(version->id);
DEBUG_TEST_ERROR("use program");
active = this;
uniforms_dirty = true;
return true;
}
void ShaderGLES2::unbind() {
version = NULL;
glUseProgram(0);
uniforms_dirty = true;
active = NULL;
}
static String _fix_error_code_line(const String &p_error, int p_code_start, int p_offset) {
int last_find_pos = -1;
// NVIDIA
String error = p_error;
while ((last_find_pos = p_error.find("(", last_find_pos + 1)) != -1) {
int end_pos = last_find_pos + 1;
while (true) {
if (p_error[end_pos] >= '0' && p_error[end_pos] <= '9') {
end_pos++;
continue;
} else if (p_error[end_pos] == ')') {
break;
} else {
end_pos = -1;
break;
}
}
if (end_pos == -1)
continue;
String numstr = error.substr(last_find_pos + 1, (end_pos - last_find_pos) - 1);
String begin = error.substr(0, last_find_pos + 1);
String end = error.substr(end_pos, error.length());
int num = numstr.to_int() + p_code_start - p_offset;
error = begin + itos(num) + end;
}
// ATI
last_find_pos = -1;
while ((last_find_pos = p_error.find("ERROR: ", last_find_pos + 1)) != -1) {
last_find_pos += 6;
int end_pos = last_find_pos + 1;
while (true) {
if (p_error[end_pos] >= '0' && p_error[end_pos] <= '9') {
end_pos++;
continue;
} else if (p_error[end_pos] == ':') {
break;
} else {
end_pos = -1;
break;
}
}
continue;
if (end_pos == -1)
continue;
String numstr = error.substr(last_find_pos + 1, (end_pos - last_find_pos) - 1);
print_line("numstr: " + numstr);
String begin = error.substr(0, last_find_pos + 1);
String end = error.substr(end_pos, error.length());
int num = numstr.to_int() + p_code_start - p_offset;
error = begin + itos(num) + end;
}
return error;
}
ShaderGLES2::Version *ShaderGLES2::get_current_version() {
Version *_v = version_map.getptr(conditional_version);
if (_v) {
if (conditional_version.code_version != 0) {
CustomCode *cc = custom_code_map.getptr(conditional_version.code_version);
ERR_FAIL_COND_V(!cc, _v);
if (cc->version == _v->code_version)
return _v;
} else {
return _v;
}
}
if (!_v)
version_map[conditional_version];
Version &v = version_map[conditional_version];
if (!_v) {
v.uniform_location = memnew_arr(GLint, uniform_count);
} else {
if (v.ok) {
glDeleteShader(v.vert_id);
glDeleteShader(v.frag_id);
glDeleteProgram(v.id);
v.id = 0;
}
}
v.ok = false;
Vector<const char *> strings;
#ifdef GLES_OVER_GL
strings.push_back("#version 120\n");
strings.push_back("#define USE_GLES_OVER_GL\n");
#else
strings.push_back("#version 100\n");
#endif
int define_line_ofs = 1;
for (int j = 0; j < conditional_count; j++) {
bool enable = (conditional_version.version & (1 << j)) > 0;
if (enable) {
strings.push_back(conditional_defines[j]);
define_line_ofs++;
DEBUG_PRINT(conditional_defines[j]);
}
}
// keep them around during the functino
CharString code_string;
CharString code_string2;
CharString code_globals;
CustomCode *cc = NULL;
if (conditional_version.code_version > 0) {
cc = custom_code_map.getptr(conditional_version.code_version);
ERR_FAIL_COND_V(!cc, NULL);
v.code_version = cc->version;
define_line_ofs += 2;
}
// program
v.id = glCreateProgram();
ERR_FAIL_COND_V(v.id == 0, NULL);
if (cc) {
for (int i = 0; i < cc->custom_defines.size(); i++) {
strings.push_back(cc->custom_defines[i]);
DEBUG_PRINT("CD #" + itos(i) + ": " + String(cc->custom_defines[i]));
}
}
// vertex shader
int string_base_size = strings.size();
strings.push_back(vertex_code0.get_data());
if (cc) {
code_globals = cc->vertex_globals.ascii();
strings.push_back(code_globals.get_data());
}
strings.push_back(vertex_code1.get_data());
if (cc) {
code_string = cc->vertex.ascii();
strings.push_back(code_string.get_data());
}
strings.push_back(vertex_code2.get_data());
#ifdef DEBUG_SHADER
DEBUG_PRINT("\nVertex Code:\n\n" + String(code_string.get_data()));
#endif
v.vert_id = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(v.vert_id, strings.size(), &strings[0], NULL);
glCompileShader(v.vert_id);
GLint status;
glGetShaderiv(v.vert_id, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE) {
GLsizei iloglen;
glGetShaderiv(v.vert_id, GL_INFO_LOG_LENGTH, &iloglen);
if (iloglen < 0) {
glDeleteShader(v.vert_id);
glDeleteProgram(v.id);
v.id = 0;
ERR_PRINT("No OpenGL vertex shader compiler log. What the frick?");
} else {
if (iloglen == 0) {
iloglen = 4096; // buggy driver (Adreno 220+)
}
char *ilogmem = (char *)Memory::alloc_static(iloglen + 1);
ilogmem[iloglen] = '\0';
glGetShaderInfoLog(v.vert_id, iloglen, &iloglen, ilogmem);
String err_string = get_shader_name() + ": Vertex shader compilation failed:\n";
err_string += ilogmem;
err_string = _fix_error_code_line(err_string, vertex_code_start, define_line_ofs);
ERR_PRINTS(err_string);
Memory::free_static(ilogmem);
glDeleteShader(v.vert_id);
glDeleteProgram(v.id);
v.id = 0;
}
ERR_FAIL_V(NULL);
}
strings.resize(string_base_size);
// fragment shader
strings.push_back(fragment_code0.get_data());
if (cc) {
code_globals = cc->fragment_globals.ascii();
strings.push_back(code_globals.get_data());
}
strings.push_back(fragment_code1.get_data());
if (cc) {
code_string = cc->fragment.ascii();
strings.push_back(code_string.get_data());
}
strings.push_back(fragment_code2.get_data());
if (cc) {
code_string2 = cc->light.ascii();
strings.push_back(code_string2.get_data());
}
strings.push_back(fragment_code3.get_data());
#ifdef DEBUG_SHADER
DEBUG_PRINT("\nFragment Code:\n\n" + String(code_string.get_data()));
#endif
v.frag_id = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(v.frag_id, strings.size(), &strings[0], NULL);
glCompileShader(v.frag_id);
glGetShaderiv(v.frag_id, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE) {
GLsizei iloglen;
glGetShaderiv(v.frag_id, GL_INFO_LOG_LENGTH, &iloglen);
if (iloglen < 0) {
glDeleteShader(v.frag_id);
glDeleteShader(v.vert_id);
glDeleteProgram(v.id);
v.id = 0;
ERR_PRINT("No OpenGL fragment shader compiler log. What the frick?");
} else {
if (iloglen == 0) {
iloglen = 4096; // buggy driver (Adreno 220+)
}
char *ilogmem = (char *)Memory::alloc_static(iloglen + 1);
ilogmem[iloglen] = '\0';
glGetShaderInfoLog(v.frag_id, iloglen, &iloglen, ilogmem);
String err_string = get_shader_name() + ": Fragment shader compilation failed:\n";
err_string += ilogmem;
err_string = _fix_error_code_line(err_string, fragment_code_start, define_line_ofs);
ERR_PRINTS(err_string);
Memory::free_static(ilogmem);
glDeleteShader(v.frag_id);
glDeleteShader(v.vert_id);
glDeleteProgram(v.id);
v.id = 0;
}
ERR_FAIL_V(NULL);
}
glAttachShader(v.id, v.frag_id);
glAttachShader(v.id, v.vert_id);
// bind the attribute locations. This has to be done before linking so that the
// linker doesn't assign some random indices
for (int i = 0; i < attribute_pair_count; i++) {
glBindAttribLocation(v.id, attribute_pairs[i].index, attribute_pairs[i].name);
}
glLinkProgram(v.id);
glGetProgramiv(v.id, GL_LINK_STATUS, &status);
if (status == GL_FALSE) {
GLsizei iloglen;
glGetProgramiv(v.id, GL_INFO_LOG_LENGTH, &iloglen);
if (iloglen < 0) {
glDeleteShader(v.frag_id);
glDeleteShader(v.vert_id);
glDeleteProgram(v.id);
v.id = 0;
ERR_PRINT("No OpenGL program link log. What the frick?");
ERR_FAIL_V(NULL);
}
if (iloglen == 0) {
iloglen = 4096; // buggy driver (Adreno 220+)
}
char *ilogmem = (char *)Memory::alloc_static(iloglen + 1);
ilogmem[iloglen] = '\0';
glGetProgramInfoLog(v.id, iloglen, &iloglen, ilogmem);
String err_string = get_shader_name() + ": Program linking failed:\n";
err_string += ilogmem;
err_string = _fix_error_code_line(err_string, fragment_code_start, define_line_ofs);
ERR_PRINTS(err_string);
Memory::free_static(ilogmem);
glDeleteShader(v.frag_id);
glDeleteShader(v.vert_id);
glDeleteProgram(v.id);
v.id = 0;
ERR_FAIL_V(NULL);
}
// get uniform locations
glUseProgram(v.id);
for (int i = 0; i < uniform_count; i++) {
v.uniform_location[i] = glGetUniformLocation(v.id, uniform_names[i]);
}
for (int i = 0; i < texunit_pair_count; i++) {
GLint loc = glGetUniformLocation(v.id, texunit_pairs[i].name);
if (loc >= 0)
glUniform1i(loc, texunit_pairs[i].index);
}
if (cc) {
v.custom_uniform_locations.resize(cc->custom_uniforms.size());
for (int i = 0; i < cc->custom_uniforms.size(); i++) {
v.custom_uniform_locations[i] = glGetUniformLocation(v.id, String(cc->custom_uniforms[i]).ascii().get_data());
}
}
glUseProgram(0);
v.ok = true;
return &v;
}
GLint ShaderGLES2::get_uniform_location(const String &p_name) const {
ERR_FAIL_COND_V(!version, -1);
return glGetUniformLocation(version->id, p_name.ascii().get_data());
}
void ShaderGLES2::setup(
const char **p_conditional_defines,
int p_conditional_count,
const char **p_uniform_names,
int p_uniform_count,
const AttributePair *p_attribute_pairs,
int p_attribute_count,
const TexUnitPair *p_texunit_pairs,
int p_texunit_pair_count,
const char *p_vertex_code,
const char *p_fragment_code,
int p_vertex_code_start,
int p_fragment_code_start) {
ERR_FAIL_COND(version);
conditional_version.key = 0;
new_conditional_version.key = 0;
uniform_count = p_uniform_count;
conditional_count = p_conditional_count;
conditional_defines = p_conditional_defines;
uniform_names = p_uniform_names;
vertex_code = p_vertex_code;
fragment_code = p_fragment_code;
texunit_pairs = p_texunit_pairs;
texunit_pair_count = p_texunit_pair_count;
vertex_code_start = p_vertex_code_start;
fragment_code_start = p_fragment_code_start;
attribute_pairs = p_attribute_pairs;
attribute_pair_count = p_attribute_count;
{
String globals_tag = "\nVERTEX_SHADER_GLOBALS";
String code_tag = "\nVERTEX_SHADER_CODE";
String code = vertex_code;
int cpos = code.find(globals_tag);
if (cpos == -1) {
vertex_code0 = code.ascii();
} else {
vertex_code0 = code.substr(0, cpos).ascii();
code = code.substr(cpos + globals_tag.length(), code.length());
cpos = code.find(code_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 globals_tag = "\nFRAGMENT_SHADER_GLOBALS";
String code_tag = "\nFRAGMENT_SHADER_CODE";
String light_code_tag = "\nLIGHT_SHADER_CODE";
String code = fragment_code;
int cpos = code.find(globals_tag);
if (cpos == -1) {
fragment_code0 = code.ascii();
} else {
fragment_code0 = code.substr(0, cpos).ascii();
code = code.substr(cpos + globals_tag.length(), code.length());
cpos = code.find(code_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());
cpos = code2.find(light_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();
}
}
}
}
}
void ShaderGLES2::finish() {
const VersionKey *V = NULL;
while ((V = version_map.next(V))) {
Version &v = version_map[*V];
glDeleteShader(v.vert_id);
glDeleteShader(v.frag_id);
glDeleteProgram(v.id);
memdelete_arr(v.uniform_location);
}
}
void ShaderGLES2::clear_caches() {
const VersionKey *V = NULL;
while ((V = version_map.next(V))) {
Version &v = version_map[*V];
glDeleteShader(v.vert_id);
glDeleteShader(v.frag_id);
glDeleteProgram(v.id);
memdelete_arr(v.uniform_location);
}
version_map.clear();
custom_code_map.clear();
version = NULL;
last_custom_code = 1;
uniforms_dirty = true;
}
uint32_t ShaderGLES2::create_custom_shader() {
custom_code_map[last_custom_code] = CustomCode();
custom_code_map[last_custom_code].version = 1;
return last_custom_code++;
}
void ShaderGLES2::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<StringName> &p_texture_uniforms,
const Vector<CharString> &p_custom_defines) {
CustomCode *cc = custom_code_map.getptr(p_code_id);
ERR_FAIL_COND(!cc);
cc->vertex = p_vertex;
cc->vertex_globals = p_vertex_globals;
cc->fragment = p_fragment;
cc->fragment_globals = p_fragment_globals;
cc->light = p_light;
cc->custom_uniforms = p_uniforms;
cc->custom_defines = p_custom_defines;
cc->version++;
}
void ShaderGLES2::set_custom_shader(uint32_t p_code_id) {
new_conditional_version.code_version = p_code_id;
}
void ShaderGLES2::free_custom_shader(uint32_t p_code_id) {
ERR_FAIL_COND(!custom_code_map.has(p_code_id));
if (conditional_version.code_version == p_code_id)
conditional_version.code_version = 0;
custom_code_map.erase(p_code_id);
}
void ShaderGLES2::set_base_material_tex_index(int p_idx) {
}
ShaderGLES2::ShaderGLES2() {
version = NULL;
last_custom_code = 1;
uniforms_dirty = true;
}
ShaderGLES2::~ShaderGLES2() {
finish();
}

View file

@ -0,0 +1,386 @@
/*************************************************************************/
/* shader_gles2.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifndef SHADER_GLES2_H
#define SHADER_GLES2_H
#include <stdio.h>
#include "platform_config.h"
#ifndef GLES2_INCLUDE_H
#include <GLES2/gl2.h>
#else
#include GLES2_INCLUDE_H
#endif
#include "camera_matrix.h"
#include "hash_map.h"
#include "map.h"
#include "variant.h"
class ShaderGLES2 {
protected:
struct Enum {
uint64_t mask;
uint64_t shift;
const char *defines[16];
};
struct EnumValue {
uint64_t set_mask;
uint64_t clear_mask;
};
struct AttributePair {
const char *name;
int index;
};
struct UniformPair {
const char *name;
Variant::Type type_hint;
};
struct TexUnitPair {
const char *name;
int index;
};
bool uniforms_dirty;
private:
//@TODO Optimize to a fixed set of shader pools and use a LRU
int uniform_count;
int texunit_pair_count;
int conditional_count;
int vertex_code_start;
int fragment_code_start;
int attribute_pair_count;
struct CustomCode {
String vertex;
String vertex_globals;
String fragment;
String fragment_globals;
String light;
uint32_t version;
Vector<StringName> texture_uniforms;
Vector<StringName> custom_uniforms;
Vector<CharString> custom_defines;
};
struct Version {
GLuint id;
GLuint vert_id;
GLuint frag_id;
GLint *uniform_location;
Vector<GLint> texture_uniform_locations;
Vector<GLint> custom_uniform_locations;
uint32_t code_version;
bool ok;
Version() {
code_version = 0;
ok = false;
uniform_location = NULL;
}
};
Version *version;
union VersionKey {
struct {
uint32_t version;
uint32_t code_version;
};
uint64_t key;
bool operator==(const VersionKey &p_key) const { return key == p_key.key; }
bool operator<(const VersionKey &p_key) const { return key < p_key.key; }
};
struct VersionKeyHash {
static _FORCE_INLINE_ uint32_t hash(const VersionKey &p_key) { return HashMapHasherDefault::hash(p_key.key); }
};
//this should use a way more cachefriendly version..
HashMap<VersionKey, Version, VersionKeyHash> version_map;
HashMap<uint32_t, CustomCode> custom_code_map;
uint32_t last_custom_code;
VersionKey conditional_version;
VersionKey new_conditional_version;
virtual String get_shader_name() const = 0;
const char **conditional_defines;
const char **uniform_names;
const AttributePair *attribute_pairs;
const TexUnitPair *texunit_pairs;
const char *vertex_code;
const char *fragment_code;
CharString fragment_code0;
CharString fragment_code1;
CharString fragment_code2;
CharString fragment_code3;
CharString vertex_code0;
CharString vertex_code1;
CharString vertex_code2;
Vector<CharString> custom_defines;
Version *get_current_version();
static ShaderGLES2 *active;
int max_image_units;
_FORCE_INLINE_ void _set_uniform_variant(GLint p_uniform, const Variant &p_value) {
if (p_uniform < 0)
return; // do none
switch (p_value.get_type()) {
case Variant::BOOL:
case Variant::INT: {
int val = p_value;
glUniform1i(p_uniform, val);
} break;
case Variant::REAL: {
real_t val = p_value;
glUniform1f(p_uniform, val);
} break;
case Variant::COLOR: {
Color val = p_value;
glUniform4f(p_uniform, val.r, val.g, val.b, val.a);
} break;
case Variant::VECTOR2: {
Vector2 val = p_value;
glUniform2f(p_uniform, val.x, val.y);
} break;
case Variant::VECTOR3: {
Vector3 val = p_value;
glUniform3f(p_uniform, val.x, val.y, val.z);
} break;
case Variant::PLANE: {
Plane val = p_value;
glUniform4f(p_uniform, val.normal.x, val.normal.y, val.normal.z, val.d);
} break;
case Variant::QUAT: {
Quat val = p_value;
glUniform4f(p_uniform, val.x, val.y, val.z, val.w);
} break;
case Variant::TRANSFORM2D: {
Transform2D tr = p_value;
GLfloat matrix[16] = { /* build a 16x16 matrix */
tr.elements[0][0],
tr.elements[0][1],
0,
0,
tr.elements[1][0],
tr.elements[1][1],
0,
0,
0,
0,
1,
0,
tr.elements[2][0],
tr.elements[2][1],
0,
1
};
glUniformMatrix4fv(p_uniform, 1, false, matrix);
} break;
case Variant::BASIS:
case Variant::TRANSFORM: {
Transform tr = p_value;
GLfloat matrix[16] = { /* build a 16x16 matrix */
tr.basis.elements[0][0],
tr.basis.elements[1][0],
tr.basis.elements[2][0],
0,
tr.basis.elements[0][1],
tr.basis.elements[1][1],
tr.basis.elements[2][1],
0,
tr.basis.elements[0][2],
tr.basis.elements[1][2],
tr.basis.elements[2][2],
0,
tr.origin.x,
tr.origin.y,
tr.origin.z,
1
};
glUniformMatrix4fv(p_uniform, 1, false, matrix);
} break;
default: { ERR_FAIL(); } // do nothing
}
}
Map<uint32_t, Variant> uniform_defaults;
Map<uint32_t, CameraMatrix> uniform_cameras;
protected:
_FORCE_INLINE_ int _get_uniform(int p_which) const;
_FORCE_INLINE_ void _set_conditional(int p_which, bool p_value);
void setup(const char **p_conditional_defines,
int p_conditional_count,
const char **p_uniform_names,
int p_uniform_count,
const AttributePair *p_attribute_pairs,
int p_attribute_count,
const TexUnitPair *p_texunit_pairs,
int p_texunit_pair_count,
const char *p_vertex_code,
const char *p_fragment_code,
int p_vertex_code_start,
int p_fragment_code_start);
ShaderGLES2();
public:
enum {
CUSTOM_SHADER_DISABLED = 0
};
GLint get_uniform_location(const String &p_name) const;
GLint get_uniform_location(int p_index) const;
static _FORCE_INLINE_ ShaderGLES2 *get_active() { return active; }
bool bind();
void unbind();
void bind_uniforms();
inline GLuint get_program() const { return version ? version->id : 0; }
void clear_caches();
uint32_t create_custom_shader();
void 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<StringName> &p_texture_uniforms,
const Vector<CharString> &p_custom_defines);
void set_custom_shader(uint32_t p_code_id);
void free_custom_shader(uint32_t p_code_id);
void set_uniform_default(int p_idx, const Variant &p_value) {
if (p_value.get_type() == Variant::NIL) {
uniform_defaults.erase(p_idx);
} else {
uniform_defaults[p_idx] = p_value;
}
uniforms_dirty = true;
}
uint32_t get_version() const { return new_conditional_version.version; }
void set_uniform_camera(int p_idx, const CameraMatrix &p_mat) {
uniform_cameras[p_idx] = p_mat;
uniforms_dirty = true;
}
_FORCE_INLINE_ void set_texture_uniform(int p_idx, const Variant &p_value) {
ERR_FAIL_COND(!version);
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_texture_uniform_location(int p_idx) {
ERR_FAIL_COND_V(!version, -1);
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);
void add_custom_define(const String &p_define) {
custom_defines.push_back(p_define.utf8());
}
virtual ~ShaderGLES2();
};
// called a lot, made inline
int ShaderGLES2::_get_uniform(int p_which) const {
ERR_FAIL_INDEX_V(p_which, uniform_count, -1);
ERR_FAIL_COND_V(!version, -1);
return version->uniform_location[p_which];
}
void ShaderGLES2::_set_conditional(int p_which, bool p_value) {
ERR_FAIL_INDEX(p_which, conditional_count);
if (p_value)
new_conditional_version.version |= (1 << p_which);
else
new_conditional_version.version &= ~(1 << p_which);
}
#endif

View file

@ -0,0 +1,22 @@
#!/usr/bin/env python
Import('env')
if 'GLES2_GLSL' in env['BUILDERS']:
env.GLES2_GLSL('copy.glsl');
# env.GLES2_GLSL('resolve.glsl');
env.GLES2_GLSL('canvas.glsl');
# env.GLES2_GLSL('canvas_shadow.glsl');
env.GLES2_GLSL('scene.glsl');
# env.GLES2_GLSL('cubemap_filter.glsl');
# env.GLES2_GLSL('cube_to_dp.glsl');
# env.GLES2_GLSL('blend_shape.glsl');
# env.GLES2_GLSL('screen_space_reflection.glsl');
# env.GLES2_GLSL('effect_blur.glsl');
# env.GLES2_GLSL('subsurf_scattering.glsl');
# env.GLES2_GLSL('ssao.glsl');
# env.GLES2_GLSL('ssao_minify.glsl');
# env.GLES2_GLSL('ssao_blur.glsl');
# env.GLES2_GLSL('exposure.glsl');
# env.GLES2_GLSL('tonemap.glsl');
# env.GLES2_GLSL('particles.glsl');

View file

@ -0,0 +1,197 @@
[vertex]
/*
from VisualServer:
ARRAY_VERTEX=0,
ARRAY_NORMAL=1,
ARRAY_TANGENT=2,
ARRAY_COLOR=3,
ARRAY_TEX_UV=4,
ARRAY_TEX_UV2=5,
ARRAY_BONES=6,
ARRAY_WEIGHTS=7,
ARRAY_INDEX=8,
*/
#ifdef USE_2D_VERTEX
#define VFORMAT vec2
#else
#define VFORMAT vec3
#endif
/* INPUT ATTRIBS */
layout(location=0) in highp VFORMAT vertex_attrib;
layout(location=1) in vec3 normal_attrib;
#ifdef ENABLE_TANGENT
layout(location=2) in vec4 tangent_attrib;
#endif
#ifdef ENABLE_COLOR
layout(location=3) in vec4 color_attrib;
#endif
#ifdef ENABLE_UV
layout(location=4) in vec2 uv_attrib;
#endif
#ifdef ENABLE_UV2
layout(location=5) in vec2 uv2_attrib;
#endif
#ifdef ENABLE_SKELETON
layout(location=6) in ivec4 bone_attrib;
layout(location=7) in vec4 weight_attrib;
#endif
/* BLEND ATTRIBS */
#ifdef ENABLE_BLEND
layout(location=8) in highp VFORMAT vertex_attrib_blend;
layout(location=9) in vec3 normal_attrib_blend;
#ifdef ENABLE_TANGENT
layout(location=10) in vec4 tangent_attrib_blend;
#endif
#ifdef ENABLE_COLOR
layout(location=11) in vec4 color_attrib_blend;
#endif
#ifdef ENABLE_UV
layout(location=12) in vec2 uv_attrib_blend;
#endif
#ifdef ENABLE_UV2
layout(location=13) in vec2 uv2_attrib_blend;
#endif
#ifdef ENABLE_SKELETON
layout(location=14) in ivec4 bone_attrib_blend;
layout(location=15) in vec4 weight_attrib_blend;
#endif
#endif
/* OUTPUTS */
out VFORMAT vertex_out; //tfb:
#ifdef ENABLE_NORMAL
out vec3 normal_out; //tfb:ENABLE_NORMAL
#endif
#ifdef ENABLE_TANGENT
out vec4 tangent_out; //tfb:ENABLE_TANGENT
#endif
#ifdef ENABLE_COLOR
out vec4 color_out; //tfb:ENABLE_COLOR
#endif
#ifdef ENABLE_UV
out vec2 uv_out; //tfb:ENABLE_UV
#endif
#ifdef ENABLE_UV2
out vec2 uv2_out; //tfb:ENABLE_UV2
#endif
#ifdef ENABLE_SKELETON
out ivec4 bone_out; //tfb:ENABLE_SKELETON
out vec4 weight_out; //tfb:ENABLE_SKELETON
#endif
uniform float blend_amount;
void main() {
#ifdef ENABLE_BLEND
vertex_out = vertex_attrib_blend + vertex_attrib * blend_amount;
#ifdef ENABLE_NORMAL
normal_out = normal_attrib_blend + normal_attrib * blend_amount;
#endif
#ifdef ENABLE_TANGENT
tangent_out.xyz = tangent_attrib_blend.xyz + tangent_attrib.xyz * blend_amount;
tangent_out.w = tangent_attrib_blend.w; //just copy, no point in blending his
#endif
#ifdef ENABLE_COLOR
color_out = color_attrib_blend + color_attrib * blend_amount;
#endif
#ifdef ENABLE_UV
uv_out = uv_attrib_blend + uv_attrib * blend_amount;
#endif
#ifdef ENABLE_UV2
uv2_out = uv2_attrib_blend + uv2_attrib * blend_amount;
#endif
#ifdef ENABLE_SKELETON
bone_out = bone_attrib_blend;
weight_out = weight_attrib_blend + weight_attrib * blend_amount;
#endif
#else //ENABLE_BLEND
vertex_out = vertex_attrib * blend_amount;
#ifdef ENABLE_NORMAL
normal_out = normal_attrib * blend_amount;
#endif
#ifdef ENABLE_TANGENT
tangent_out.xyz = tangent_attrib.xyz * blend_amount;
tangent_out.w = tangent_attrib.w; //just copy, no point in blending his
#endif
#ifdef ENABLE_COLOR
color_out = color_attrib * blend_amount;
#endif
#ifdef ENABLE_UV
uv_out = uv_attrib * blend_amount;
#endif
#ifdef ENABLE_UV2
uv2_out = uv2_attrib * blend_amount;
#endif
#ifdef ENABLE_SKELETON
bone_out = bone_attrib;
weight_out = weight_attrib * blend_amount;
#endif
#endif
gl_Position = vec4(0.0);
}
[fragment]
void main() {
}

View file

@ -0,0 +1,141 @@
[vertex]
#ifdef USE_GLES_OVER_GL
#define mediump
#define highp
#else
precision mediump float;
precision mediump int;
#endif
uniform highp mat4 projection_matrix;
uniform highp mat4 modelview_matrix;
uniform highp mat4 extra_matrix;
attribute highp vec2 vertex; // attrib:0
attribute vec4 color_attrib; // attrib:3
attribute vec2 uv_attrib; // attrib:4
varying vec2 uv_interp;
varying vec4 color_interp;
uniform highp vec2 color_texpixel_size;
#ifdef USE_TEXTURE_RECT
uniform vec4 dst_rect;
uniform vec4 src_rect;
#endif
uniform bool blit_pass;
VERTEX_SHADER_GLOBALS
vec2 select(vec2 a, vec2 b, bvec2 c) {
vec2 ret;
ret.x = c.x ? b.x : a.x;
ret.y = c.y ? b.y : a.y;
return ret;
}
void main() {
vec4 color = color_attrib;
#ifdef USE_TEXTURE_RECT
if (dst_rect.z < 0.0) { // Transpose is encoded as negative dst_rect.z
uv_interp = src_rect.xy + abs(src_rect.zw) * vertex.yx;
} else {
uv_interp = src_rect.xy + abs(src_rect.zw) * vertex;
}
vec4 outvec = vec4(0.0, 0.0, 0.0, 1.0);
// This is what is done in the GLES 3 bindings and should
// take care of flipped rects.
//
// But it doesn't.
// I don't know why, will need to investigate further.
outvec.xy = dst_rect.xy + abs(dst_rect.zw) * select(vertex, vec2(1.0, 1.0) - vertex, lessThan(src_rect.zw, vec2(0.0, 0.0)));
// outvec.xy = dst_rect.xy + abs(dst_rect.zw) * vertex;
#else
vec4 outvec = vec4(vertex.xy, 0.0, 1.0);
#ifdef USE_UV_ATTRIBUTE
uv_interp = uv_attrib;
#else
uv_interp = vertex.xy;
#endif
#endif
{
vec2 src_vtx=outvec.xy;
VERTEX_SHADER_CODE
}
color_interp = color;
gl_Position = projection_matrix * modelview_matrix * outvec;
}
[fragment]
#ifdef USE_GLES_OVER_GL
#define mediump
#define highp
#else
precision mediump float;
precision mediump int;
#endif
uniform sampler2D color_texture; // texunit:0
uniform highp vec2 color_texpixel_size;
uniform mediump sampler2D normal_texture; // texunit:1
varying mediump vec2 uv_interp;
varying mediump vec4 color_interp;
uniform bool blit_pass;
uniform vec4 final_modulate;
#ifdef SCREEN_TEXTURE_USED
uniform sampler2D screen_texture; // texunit:2
#endif
#ifdef SCREEN_UV_USED
uniform vec2 screen_pixel_size;
#endif
FRAGMENT_SHADER_GLOBALS
void main() {
vec4 color = color_interp;
color *= texture2D(color_texture, uv_interp);
{
FRAGMENT_SHADER_CODE
}
color *= final_modulate;
gl_FragColor = color;
}

View file

@ -0,0 +1,49 @@
[vertex]
uniform highp mat4 projection_matrix;
uniform highp mat4 light_matrix;
uniform highp mat4 world_matrix;
uniform highp float distance_norm;
layout(location=0) in highp vec3 vertex;
out highp vec4 position_interp;
void main() {
gl_Position = projection_matrix * (light_matrix * (world_matrix * vec4(vertex,1.0)));
position_interp=gl_Position;
}
[fragment]
in highp vec4 position_interp;
#ifdef USE_RGBA_SHADOWS
layout(location=0) out lowp vec4 distance_buf;
#else
layout(location=0) out highp float distance_buf;
#endif
void main() {
highp float depth = ((position_interp.z / position_interp.w) + 1.0) * 0.5 + 0.0;//bias;
#ifdef USE_RGBA_SHADOWS
highp vec4 comp = fract(depth * vec4(256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0));
comp -= comp.xxyz * vec4(0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0);
distance_buf=comp;
#else
distance_buf=depth;
#endif
}

View file

@ -0,0 +1,72 @@
[vertex]
#ifdef USE_GLES_OVER_GL
#define mediump
#define highp
#else
precision mediump float;
precision mediump int;
#endif
attribute highp vec4 vertex_attrib; // attrib:0
attribute vec2 uv_in; // attrib:4
attribute vec2 uv2_in; // attrib:5
varying vec2 uv_interp;
varying vec2 uv2_interp;
#ifdef USE_COPY_SECTION
uniform vec4 copy_section;
#endif
void main() {
uv_interp = uv_in;
uv2_interp = uv2_in;
gl_Position = vertex_attrib;
#ifdef USE_COPY_SECTION
uv_interp = copy_section.xy + uv_interp * copy_section.zw;
gl_Position.xy = (copy_section.xy + (gl_Position.xy * 0.5 + 0.5) * copy_section.zw) * 2.0 - 1.0;
#endif
}
[fragment]
#ifdef USE_GLES_OVER_GL
#define mediump
#define highp
#else
precision mediump float;
precision mediump int;
#endif
varying vec2 uv_interp;
uniform sampler2D source; // texunit:0
varying vec2 uv2_interp;
#ifdef USE_CUSTOM_ALPHA
uniform float custom_alpha;
#endif
void main() {
//vec4 color = color_interp;
vec4 color = texture2D( source, uv_interp );
#ifdef USE_NO_ALPHA
color.a=1.0;
#endif
#ifdef USE_CUSTOM_ALPHA
color.a=custom_alpha;
#endif
gl_FragColor = color;
}

View file

@ -0,0 +1,79 @@
[vertex]
layout(location=0) in highp vec4 vertex_attrib;
layout(location=4) in vec2 uv_in;
out vec2 uv_interp;
void main() {
uv_interp = uv_in;
gl_Position = vertex_attrib;
}
[fragment]
uniform highp samplerCube source_cube; //texunit:0
in vec2 uv_interp;
uniform bool z_flip;
uniform highp float z_far;
uniform highp float z_near;
uniform highp float bias;
void main() {
highp vec3 normal = vec3( uv_interp * 2.0 - 1.0, 0.0 );
/*
if(z_flip) {
normal.z = 0.5 - 0.5*((normal.x * normal.x) + (normal.y * normal.y));
} else {
normal.z = -0.5 + 0.5*((normal.x * normal.x) + (normal.y * normal.y));
}
*/
//normal.z = sqrt(1.0-dot(normal.xy,normal.xy));
//normal.xy*=1.0+normal.z;
normal.z = 0.5 - 0.5*((normal.x * normal.x) + (normal.y * normal.y));
normal = normalize(normal);
/*
normal.z=0.5;
normal=normalize(normal);
*/
if (!z_flip) {
normal.z=-normal.z;
}
//normal = normalize(vec3( uv_interp * 2.0 - 1.0, 1.0 ));
float depth = texture(source_cube,normal).r;
// absolute values for direction cosines, bigger value equals closer to basis axis
vec3 unorm = abs(normal);
if ( (unorm.x >= unorm.y) && (unorm.x >= unorm.z) ) {
// x code
unorm = normal.x > 0.0 ? vec3( 1.0, 0.0, 0.0 ) : vec3( -1.0, 0.0, 0.0 ) ;
} else if ( (unorm.y > unorm.x) && (unorm.y >= unorm.z) ) {
// y code
unorm = normal.y > 0.0 ? vec3( 0.0, 1.0, 0.0 ) : vec3( 0.0, -1.0, 0.0 ) ;
} else if ( (unorm.z > unorm.x) && (unorm.z > unorm.y) ) {
// z code
unorm = normal.z > 0.0 ? vec3( 0.0, 0.0, 1.0 ) : vec3( 0.0, 0.0, -1.0 ) ;
} else {
// oh-no we messed up code
// has to be
unorm = vec3( 1.0, 0.0, 0.0 );
}
float depth_fix = 1.0 / dot(normal,unorm);
depth = 2.0 * depth - 1.0;
float linear_depth = 2.0 * z_near * z_far / (z_far + z_near - depth * (z_far - z_near));
gl_FragDepth = (linear_depth*depth_fix+bias) / z_far;
}

View file

@ -0,0 +1,294 @@
[vertex]
layout(location=0) in highp vec2 vertex;
layout(location=4) in highp vec2 uv;
out highp vec2 uv_interp;
void main() {
uv_interp=uv;
gl_Position=vec4(vertex,0,1);
}
[fragment]
precision highp float;
precision highp int;
#ifdef USE_SOURCE_PANORAMA
uniform sampler2D source_panorama; //texunit:0
#endif
#ifdef USE_SOURCE_DUAL_PARABOLOID_ARRAY
uniform sampler2DArray source_dual_paraboloid_array; //texunit:0
uniform int source_array_index;
#endif
#if !defined(USE_SOURCE_DUAL_PARABOLOID_ARRAY) && !defined(USE_SOURCE_PANORAMA)
uniform samplerCube source_cube; //texunit:0
#endif
uniform int face_id;
uniform float roughness;
in highp vec2 uv_interp;
layout(location = 0) out vec4 frag_color;
#define M_PI 3.14159265359
vec3 texelCoordToVec(vec2 uv, int faceID)
{
mat3 faceUvVectors[6];
/*
// -x
faceUvVectors[1][0] = vec3(0.0, 0.0, 1.0); // u -> +z
faceUvVectors[1][1] = vec3(0.0, -1.0, 0.0); // v -> -y
faceUvVectors[1][2] = vec3(-1.0, 0.0, 0.0); // -x face
// +x
faceUvVectors[0][0] = vec3(0.0, 0.0, -1.0); // u -> -z
faceUvVectors[0][1] = vec3(0.0, -1.0, 0.0); // v -> -y
faceUvVectors[0][2] = vec3(1.0, 0.0, 0.0); // +x face
// -y
faceUvVectors[3][0] = vec3(1.0, 0.0, 0.0); // u -> +x
faceUvVectors[3][1] = vec3(0.0, 0.0, -1.0); // v -> -z
faceUvVectors[3][2] = vec3(0.0, -1.0, 0.0); // -y face
// +y
faceUvVectors[2][0] = vec3(1.0, 0.0, 0.0); // u -> +x
faceUvVectors[2][1] = vec3(0.0, 0.0, 1.0); // v -> +z
faceUvVectors[2][2] = vec3(0.0, 1.0, 0.0); // +y face
// -z
faceUvVectors[5][0] = vec3(-1.0, 0.0, 0.0); // u -> -x
faceUvVectors[5][1] = vec3(0.0, -1.0, 0.0); // v -> -y
faceUvVectors[5][2] = vec3(0.0, 0.0, -1.0); // -z face
// +z
faceUvVectors[4][0] = vec3(1.0, 0.0, 0.0); // u -> +x
faceUvVectors[4][1] = vec3(0.0, -1.0, 0.0); // v -> -y
faceUvVectors[4][2] = vec3(0.0, 0.0, 1.0); // +z face
*/
// -x
faceUvVectors[0][0] = vec3(0.0, 0.0, 1.0); // u -> +z
faceUvVectors[0][1] = vec3(0.0, -1.0, 0.0); // v -> -y
faceUvVectors[0][2] = vec3(-1.0, 0.0, 0.0); // -x face
// +x
faceUvVectors[1][0] = vec3(0.0, 0.0, -1.0); // u -> -z
faceUvVectors[1][1] = vec3(0.0, -1.0, 0.0); // v -> -y
faceUvVectors[1][2] = vec3(1.0, 0.0, 0.0); // +x face
// -y
faceUvVectors[2][0] = vec3(1.0, 0.0, 0.0); // u -> +x
faceUvVectors[2][1] = vec3(0.0, 0.0, -1.0); // v -> -z
faceUvVectors[2][2] = vec3(0.0, -1.0, 0.0); // -y face
// +y
faceUvVectors[3][0] = vec3(1.0, 0.0, 0.0); // u -> +x
faceUvVectors[3][1] = vec3(0.0, 0.0, 1.0); // v -> +z
faceUvVectors[3][2] = vec3(0.0, 1.0, 0.0); // +y face
// -z
faceUvVectors[4][0] = vec3(-1.0, 0.0, 0.0); // u -> -x
faceUvVectors[4][1] = vec3(0.0, -1.0, 0.0); // v -> -y
faceUvVectors[4][2] = vec3(0.0, 0.0, -1.0); // -z face
// +z
faceUvVectors[5][0] = vec3(1.0, 0.0, 0.0); // u -> +x
faceUvVectors[5][1] = vec3(0.0, -1.0, 0.0); // v -> -y
faceUvVectors[5][2] = vec3(0.0, 0.0, 1.0); // +z face
// out = u * s_faceUv[0] + v * s_faceUv[1] + s_faceUv[2].
vec3 result = (faceUvVectors[faceID][0] * uv.x) + (faceUvVectors[faceID][1] * uv.y) + faceUvVectors[faceID][2];
return normalize(result);
}
vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N)
{
float a = Roughness * Roughness; // DISNEY'S ROUGHNESS [see Burley'12 siggraph]
// Compute distribution direction
float Phi = 2.0 * M_PI * Xi.x;
float CosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a*a - 1.0) * Xi.y));
float SinTheta = sqrt(1.0 - CosTheta * CosTheta);
// Convert to spherical direction
vec3 H;
H.x = SinTheta * cos(Phi);
H.y = SinTheta * sin(Phi);
H.z = CosTheta;
vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
vec3 TangentX = normalize(cross(UpVector, N));
vec3 TangentY = cross(N, TangentX);
// Tangent to world space
return TangentX * H.x + TangentY * H.y + N * H.z;
}
// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html
float GGX(float NdotV, float a)
{
float k = a / 2.0;
return NdotV / (NdotV * (1.0 - k) + k);
}
// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html
float G_Smith(float a, float nDotV, float nDotL)
{
return GGX(nDotL, a * a) * GGX(nDotV, a * a);
}
float radicalInverse_VdC(uint bits) {
bits = (bits << 16u) | (bits >> 16u);
bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
return float(bits) * 2.3283064365386963e-10; // / 0x100000000
}
vec2 Hammersley(uint i, uint N) {
return vec2(float(i)/float(N), radicalInverse_VdC(i));
}
#ifdef LOW_QUALITY
#define SAMPLE_COUNT 64u
#else
#define SAMPLE_COUNT 512u
#endif
uniform bool z_flip;
#ifdef USE_SOURCE_PANORAMA
vec4 texturePanorama(vec3 normal,sampler2D pano ) {
vec2 st = vec2(
atan(normal.x, normal.z),
acos(normal.y)
);
if(st.x < 0.0)
st.x += M_PI*2.0;
st/=vec2(M_PI*2.0,M_PI);
return textureLod(pano,st,0.0);
}
#endif
#ifdef USE_SOURCE_DUAL_PARABOLOID_ARRAY
vec4 textureDualParaboloidArray(vec3 normal) {
vec3 norm = normalize(normal);
norm.xy/=1.0+abs(norm.z);
norm.xy=norm.xy * vec2(0.5,0.25) + vec2(0.5,0.25);
if (norm.z<0.0) {
norm.y=0.5-norm.y+0.5;
}
return textureLod(source_dual_paraboloid_array, vec3(norm.xy, float(source_array_index) ), 0.0);
}
#endif
void main() {
#ifdef USE_DUAL_PARABOLOID
vec3 N = vec3( uv_interp * 2.0 - 1.0, 0.0 );
N.z = 0.5 - 0.5*((N.x * N.x) + (N.y * N.y));
N = normalize(N);
if (z_flip) {
N.y=-N.y; //y is flipped to improve blending between both sides
N.z=-N.z;
}
#else
vec2 uv = (uv_interp * 2.0) - 1.0;
vec3 N = texelCoordToVec(uv, face_id);
#endif
//vec4 color = color_interp;
#ifdef USE_DIRECT_WRITE
#ifdef USE_SOURCE_PANORAMA
frag_color=vec4(texturePanorama(N,source_panorama).rgb,1.0);
#endif
#ifdef USE_SOURCE_DUAL_PARABOLOID_ARRAY
frag_color=vec4(textureDualParaboloidArray(N).rgb,1.0);
#endif
#if !defined(USE_SOURCE_DUAL_PARABOLOID_ARRAY) && !defined(USE_SOURCE_PANORAMA)
N.y=-N.y;
frag_color=vec4(texture(N,source_cube).rgb,1.0);
#endif
#else
vec4 sum = vec4(0.0, 0.0, 0.0, 0.0);
for(uint sampleNum = 0u; sampleNum < SAMPLE_COUNT; sampleNum++) {
vec2 xi = Hammersley(sampleNum, SAMPLE_COUNT);
vec3 H = ImportanceSampleGGX( xi, roughness, N );
vec3 V = N;
vec3 L = normalize(2.0 * dot( V, H ) * H - V);
float ndotl = clamp(dot(N, L),0.0,1.0);
if (ndotl>0.0) {
#ifdef USE_SOURCE_PANORAMA
sum.rgb += texturePanorama(H,source_panorama).rgb *ndotl;
#endif
#ifdef USE_SOURCE_DUAL_PARABOLOID_ARRAY
sum.rgb += textureDualParaboloidArray(H).rgb *ndotl;
#endif
#if !defined(USE_SOURCE_DUAL_PARABOLOID_ARRAY) && !defined(USE_SOURCE_PANORAMA)
H.y=-H.y;
sum.rgb += textureLod(source_cube, H, 0.0).rgb *ndotl;
#endif
sum.a += ndotl;
}
}
sum /= sum.a;
frag_color = vec4(sum.rgb, 1.0);
#endif
}

View file

@ -0,0 +1,301 @@
[vertex]
layout(location=0) in highp vec4 vertex_attrib;
layout(location=4) in vec2 uv_in;
out vec2 uv_interp;
#ifdef USE_BLUR_SECTION
uniform vec4 blur_section;
#endif
void main() {
uv_interp = uv_in;
gl_Position = vertex_attrib;
#ifdef USE_BLUR_SECTION
uv_interp = blur_section.xy + uv_interp * blur_section.zw;
gl_Position.xy = (blur_section.xy + (gl_Position.xy * 0.5 + 0.5) * blur_section.zw) * 2.0 - 1.0;
#endif
}
[fragment]
#if !defined(GLES_OVER_GL)
precision mediump float;
#endif
in vec2 uv_interp;
uniform sampler2D source_color; //texunit:0
#ifdef SSAO_MERGE
uniform sampler2D source_ssao; //texunit:1
#endif
uniform float lod;
uniform vec2 pixel_size;
layout(location = 0) out vec4 frag_color;
#ifdef SSAO_MERGE
uniform vec4 ssao_color;
#endif
#if defined (GLOW_GAUSSIAN_HORIZONTAL) || defined(GLOW_GAUSSIAN_VERTICAL)
uniform float glow_strength;
#endif
#if defined(DOF_FAR_BLUR) || defined (DOF_NEAR_BLUR)
#ifdef DOF_QUALITY_LOW
const int dof_kernel_size=5;
const int dof_kernel_from=2;
const float dof_kernel[5] = float[] (0.153388,0.221461,0.250301,0.221461,0.153388);
#endif
#ifdef DOF_QUALITY_MEDIUM
const int dof_kernel_size=11;
const int dof_kernel_from=5;
const float dof_kernel[11] = float[] (0.055037,0.072806,0.090506,0.105726,0.116061,0.119726,0.116061,0.105726,0.090506,0.072806,0.055037);
#endif
#ifdef DOF_QUALITY_HIGH
const int dof_kernel_size=21;
const int dof_kernel_from=10;
const float dof_kernel[21] = float[] (0.028174,0.032676,0.037311,0.041944,0.046421,0.050582,0.054261,0.057307,0.059587,0.060998,0.061476,0.060998,0.059587,0.057307,0.054261,0.050582,0.046421,0.041944,0.037311,0.032676,0.028174);
#endif
uniform sampler2D dof_source_depth; //texunit:1
uniform float dof_begin;
uniform float dof_end;
uniform vec2 dof_dir;
uniform float dof_radius;
#ifdef DOF_NEAR_BLUR_MERGE
uniform sampler2D source_dof_original; //texunit:2
#endif
#endif
#ifdef GLOW_FIRST_PASS
uniform float exposure;
uniform float white;
#ifdef GLOW_USE_AUTO_EXPOSURE
uniform highp sampler2D source_auto_exposure; //texunit:1
uniform highp float auto_exposure_grey;
#endif
uniform float glow_bloom;
uniform float glow_hdr_threshold;
uniform float glow_hdr_scale;
#endif
uniform float camera_z_far;
uniform float camera_z_near;
void main() {
#ifdef GAUSSIAN_HORIZONTAL
vec2 pix_size = pixel_size;
pix_size*=0.5; //reading from larger buffer, so use more samples
vec4 color =textureLod( source_color, uv_interp+vec2( 0.0, 0.0)*pix_size,lod )*0.214607;
color+=textureLod( source_color, uv_interp+vec2( 1.0, 0.0)*pix_size,lod )*0.189879;
color+=textureLod( source_color, uv_interp+vec2( 2.0, 0.0)*pix_size,lod )*0.157305;
color+=textureLod( source_color, uv_interp+vec2( 3.0, 0.0)*pix_size,lod )*0.071303;
color+=textureLod( source_color, uv_interp+vec2(-1.0, 0.0)*pix_size,lod )*0.189879;
color+=textureLod( source_color, uv_interp+vec2(-2.0, 0.0)*pix_size,lod )*0.157305;
color+=textureLod( source_color, uv_interp+vec2(-3.0, 0.0)*pix_size,lod )*0.071303;
frag_color = color;
#endif
#ifdef GAUSSIAN_VERTICAL
vec4 color =textureLod( source_color, uv_interp+vec2( 0.0, 0.0)*pixel_size,lod )*0.38774;
color+=textureLod( source_color, uv_interp+vec2( 0.0, 1.0)*pixel_size,lod )*0.24477;
color+=textureLod( source_color, uv_interp+vec2( 0.0, 2.0)*pixel_size,lod )*0.06136;
color+=textureLod( source_color, uv_interp+vec2( 0.0,-1.0)*pixel_size,lod )*0.24477;
color+=textureLod( source_color, uv_interp+vec2( 0.0,-2.0)*pixel_size,lod )*0.06136;
frag_color = color;
#endif
//glow uses larger sigma for a more rounded blur effect
#ifdef GLOW_GAUSSIAN_HORIZONTAL
vec2 pix_size = pixel_size;
pix_size*=0.5; //reading from larger buffer, so use more samples
vec4 color =textureLod( source_color, uv_interp+vec2( 0.0, 0.0)*pix_size,lod )*0.174938;
color+=textureLod( source_color, uv_interp+vec2( 1.0, 0.0)*pix_size,lod )*0.165569;
color+=textureLod( source_color, uv_interp+vec2( 2.0, 0.0)*pix_size,lod )*0.140367;
color+=textureLod( source_color, uv_interp+vec2( 3.0, 0.0)*pix_size,lod )*0.106595;
color+=textureLod( source_color, uv_interp+vec2(-1.0, 0.0)*pix_size,lod )*0.165569;
color+=textureLod( source_color, uv_interp+vec2(-2.0, 0.0)*pix_size,lod )*0.140367;
color+=textureLod( source_color, uv_interp+vec2(-3.0, 0.0)*pix_size,lod )*0.106595;
color*=glow_strength;
frag_color = color;
#endif
#ifdef GLOW_GAUSSIAN_VERTICAL
vec4 color =textureLod( source_color, uv_interp+vec2(0.0, 0.0)*pixel_size,lod )*0.288713;
color+=textureLod( source_color, uv_interp+vec2(0.0, 1.0)*pixel_size,lod )*0.233062;
color+=textureLod( source_color, uv_interp+vec2(0.0, 2.0)*pixel_size,lod )*0.122581;
color+=textureLod( source_color, uv_interp+vec2(0.0,-1.0)*pixel_size,lod )*0.233062;
color+=textureLod( source_color, uv_interp+vec2(0.0,-2.0)*pixel_size,lod )*0.122581;
color*=glow_strength;
frag_color = color;
#endif
#ifdef DOF_FAR_BLUR
vec4 color_accum = vec4(0.0);
float depth = textureLod( dof_source_depth, uv_interp, 0.0).r;
depth = depth * 2.0 - 1.0;
#ifdef USE_ORTHOGONAL_PROJECTION
depth = ((depth + (camera_z_far + camera_z_near)/(camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near))/2.0;
#else
depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth * (camera_z_far - camera_z_near));
#endif
float amount = smoothstep(dof_begin,dof_end,depth);
float k_accum=0.0;
for(int i=0;i<dof_kernel_size;i++) {
int int_ofs = i-dof_kernel_from;
vec2 tap_uv = uv_interp + dof_dir * float(int_ofs) * amount * dof_radius;
float tap_k = dof_kernel[i];
float tap_depth = texture( dof_source_depth, tap_uv, 0.0).r;
tap_depth = tap_depth * 2.0 - 1.0;
#ifdef USE_ORTHOGONAL_PROJECTION
tap_depth = ((tap_depth + (camera_z_far + camera_z_near)/(camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near))/2.0;
#else
tap_depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - tap_depth * (camera_z_far - camera_z_near));
#endif
float tap_amount = mix(smoothstep(dof_begin,dof_end,tap_depth),1.0,int_ofs==0);
tap_amount*=tap_amount*tap_amount; //prevent undesired glow effect
vec4 tap_color = textureLod( source_color, tap_uv, 0.0) * tap_k;
k_accum+=tap_k*tap_amount;
color_accum+=tap_color*tap_amount;
}
if (k_accum>0.0) {
color_accum/=k_accum;
}
frag_color = color_accum;///k_accum;
#endif
#ifdef DOF_NEAR_BLUR
vec4 color_accum = vec4(0.0);
float max_accum=0;
for(int i=0;i<dof_kernel_size;i++) {
int int_ofs = i-dof_kernel_from;
vec2 tap_uv = uv_interp + dof_dir * float(int_ofs) * dof_radius;
float ofs_influence = max(0.0,1.0-float(abs(int_ofs))/float(dof_kernel_from));
float tap_k = dof_kernel[i];
vec4 tap_color = textureLod( source_color, tap_uv, 0.0);
float tap_depth = texture( dof_source_depth, tap_uv, 0.0).r;
tap_depth = tap_depth * 2.0 - 1.0;
#ifdef USE_ORTHOGONAL_PROJECTION
tap_depth = ((tap_depth + (camera_z_far + camera_z_near)/(camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near))/2.0;
#else
tap_depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - tap_depth * (camera_z_far - camera_z_near));
#endif
float tap_amount = 1.0-smoothstep(dof_end,dof_begin,tap_depth);
tap_amount*=tap_amount*tap_amount; //prevent undesired glow effect
#ifdef DOF_NEAR_FIRST_TAP
tap_color.a= 1.0-smoothstep(dof_end,dof_begin,tap_depth);
#endif
max_accum=max(max_accum,tap_amount*ofs_influence);
color_accum+=tap_color*tap_k;
}
color_accum.a=max(color_accum.a,sqrt(max_accum));
#ifdef DOF_NEAR_BLUR_MERGE
vec4 original = textureLod( source_dof_original, uv_interp, 0.0);
color_accum = mix(original,color_accum,color_accum.a);
#endif
#ifndef DOF_NEAR_FIRST_TAP
//color_accum=vec4(vec3(color_accum.a),1.0);
#endif
frag_color = color_accum;
#endif
#ifdef GLOW_FIRST_PASS
#ifdef GLOW_USE_AUTO_EXPOSURE
frag_color/=texelFetch(source_auto_exposure,ivec2(0,0),0).r/auto_exposure_grey;
#endif
frag_color*=exposure;
float luminance = max(frag_color.r,max(frag_color.g,frag_color.b));
float feedback = max( smoothstep(glow_hdr_threshold,glow_hdr_threshold+glow_hdr_scale,luminance), glow_bloom );
frag_color *= feedback;
#endif
#ifdef SIMPLE_COPY
vec4 color =textureLod( source_color, uv_interp,0.0);
frag_color = color;
#endif
#ifdef SSAO_MERGE
vec4 color =textureLod( source_color, uv_interp,0.0);
float ssao =textureLod( source_ssao, uv_interp,0.0).r;
frag_color = vec4( mix(color.rgb,color.rgb*mix(ssao_color.rgb,vec3(1.0),ssao),color.a), 1.0 );
#endif
}

View file

@ -0,0 +1,98 @@
[vertex]
layout(location=0) in highp vec4 vertex_attrib;
void main() {
gl_Position = vertex_attrib;
}
[fragment]
uniform highp sampler2D source_exposure; //texunit:0
#ifdef EXPOSURE_BEGIN
uniform highp ivec2 source_render_size;
uniform highp ivec2 target_size;
#endif
#ifdef EXPOSURE_END
uniform highp sampler2D prev_exposure; //texunit:1
uniform highp float exposure_adjust;
uniform highp float min_luminance;
uniform highp float max_luminance;
#endif
layout(location = 0) out highp float exposure;
void main() {
#ifdef EXPOSURE_BEGIN
ivec2 src_pos = ivec2(gl_FragCoord.xy)*source_render_size/target_size;
#if 1
//more precise and expensive, but less jittery
ivec2 next_pos = ivec2(gl_FragCoord.xy+ivec2(1))*source_render_size/target_size;
next_pos = max(next_pos,src_pos+ivec2(1)); //so it at least reads one pixel
highp vec3 source_color=vec3(0.0);
for(int i=src_pos.x;i<next_pos.x;i++) {
for(int j=src_pos.y;j<next_pos.y;j++) {
source_color += texelFetch(source_exposure,ivec2(i,j),0).rgb;
}
}
source_color/=float( (next_pos.x-src_pos.x)*(next_pos.y-src_pos.y) );
#else
highp vec3 source_color = texelFetch(source_exposure,src_pos,0).rgb;
#endif
exposure = max(source_color.r,max(source_color.g,source_color.b));
#else
ivec2 coord = ivec2(gl_FragCoord.xy);
exposure = texelFetch(source_exposure,coord*3+ivec2(0,0),0).r;
exposure += texelFetch(source_exposure,coord*3+ivec2(1,0),0).r;
exposure += texelFetch(source_exposure,coord*3+ivec2(2,0),0).r;
exposure += texelFetch(source_exposure,coord*3+ivec2(0,1),0).r;
exposure += texelFetch(source_exposure,coord*3+ivec2(1,1),0).r;
exposure += texelFetch(source_exposure,coord*3+ivec2(2,1),0).r;
exposure += texelFetch(source_exposure,coord*3+ivec2(0,2),0).r;
exposure += texelFetch(source_exposure,coord*3+ivec2(1,2),0).r;
exposure += texelFetch(source_exposure,coord*3+ivec2(2,2),0).r;
exposure *= (1.0/9.0);
#ifdef EXPOSURE_END
#ifdef EXPOSURE_FORCE_SET
//will stay as is
#else
highp float prev_lum = texelFetch(prev_exposure,ivec2(0,0),0).r; //1 pixel previous exposure
exposure = clamp( prev_lum + (exposure-prev_lum)*exposure_adjust,min_luminance,max_luminance);
#endif //EXPOSURE_FORCE_SET
#endif //EXPOSURE_END
#endif //EXPOSURE_BEGIN
}

View file

@ -0,0 +1,260 @@
[vertex]
layout(location=0) in highp vec4 color;
layout(location=1) in highp vec4 velocity_active;
layout(location=2) in highp vec4 custom;
layout(location=3) in highp vec4 xform_1;
layout(location=4) in highp vec4 xform_2;
layout(location=5) in highp vec4 xform_3;
struct Attractor {
vec3 pos;
vec3 dir;
float radius;
float eat_radius;
float strength;
float attenuation;
};
#define MAX_ATTRACTORS 64
uniform bool emitting;
uniform float system_phase;
uniform float prev_system_phase;
uniform int total_particles;
uniform float explosiveness;
uniform float randomness;
uniform float time;
uniform float delta;
uniform int attractor_count;
uniform Attractor attractors[MAX_ATTRACTORS];
uniform bool clear;
uniform uint cycle;
uniform float lifetime;
uniform mat4 emission_transform;
uniform uint random_seed;
out highp vec4 out_color; //tfb:
out highp vec4 out_velocity_active; //tfb:
out highp vec4 out_custom; //tfb:
out highp vec4 out_xform_1; //tfb:
out highp vec4 out_xform_2; //tfb:
out highp vec4 out_xform_3; //tfb:
#if defined(USE_MATERIAL)
layout(std140) uniform UniformData { //ubo:0
MATERIAL_UNIFORMS
};
#endif
VERTEX_SHADER_GLOBALS
uint hash(uint x) {
x = ((x >> uint(16)) ^ x) * uint(0x45d9f3b);
x = ((x >> uint(16)) ^ x) * uint(0x45d9f3b);
x = (x >> uint(16)) ^ x;
return x;
}
void main() {
#ifdef PARTICLES_COPY
out_color=color;
out_velocity_active=velocity_active;
out_custom = custom;
out_xform_1 = xform_1;
out_xform_2 = xform_2;
out_xform_3 = xform_3;
#else
bool apply_forces=true;
bool apply_velocity=true;
float local_delta=delta;
float mass = 1.0;
float restart_phase = float(gl_VertexID)/float(total_particles);
if (randomness>0.0) {
uint seed = cycle;
if (restart_phase >= system_phase) {
seed-=uint(1);
}
seed*=uint(total_particles);
seed+=uint(gl_VertexID);
float random = float(hash(seed) % uint(65536)) / 65536.0;
restart_phase+=randomness * random * 1.0 / float(total_particles);
}
restart_phase*= (1.0-explosiveness);
bool restart=false;
bool shader_active = velocity_active.a > 0.5;
if (system_phase > prev_system_phase) {
// restart_phase >= prev_system_phase is used so particles emit in the first frame they are processed
if (restart_phase >= prev_system_phase && restart_phase < system_phase ) {
restart=true;
#ifdef USE_FRACTIONAL_DELTA
local_delta = (system_phase - restart_phase) * lifetime;
#endif
}
} else {
if (restart_phase >= prev_system_phase) {
restart=true;
#ifdef USE_FRACTIONAL_DELTA
local_delta = (1.0 - restart_phase + system_phase) * lifetime;
#endif
} else if (restart_phase < system_phase ) {
restart=true;
#ifdef USE_FRACTIONAL_DELTA
local_delta = (system_phase - restart_phase) * lifetime;
#endif
}
}
uint current_cycle = cycle;
if (system_phase < restart_phase) {
current_cycle-=uint(1);
}
uint particle_number = current_cycle * uint(total_particles) + uint(gl_VertexID);
int index = int(gl_VertexID);
if (restart) {
shader_active=emitting;
}
mat4 xform;
#if defined(ENABLE_KEEP_DATA)
if (clear) {
#else
if (clear || restart) {
#endif
out_color=vec4(1.0);
out_velocity_active=vec4(0.0);
out_custom=vec4(0.0);
if (!restart)
shader_active=false;
xform = mat4(
vec4(1.0,0.0,0.0,0.0),
vec4(0.0,1.0,0.0,0.0),
vec4(0.0,0.0,1.0,0.0),
vec4(0.0,0.0,0.0,1.0)
);
} else {
out_color=color;
out_velocity_active=velocity_active;
out_custom=custom;
xform = transpose(mat4(xform_1,xform_2,xform_3,vec4(vec3(0.0),1.0)));
}
if (shader_active) {
//execute shader
{
VERTEX_SHADER_CODE
}
#if !defined(DISABLE_FORCE)
if (false) {
vec3 force = vec3(0.0);
for(int i=0;i<attractor_count;i++) {
vec3 rel_vec = xform[3].xyz - attractors[i].pos;
float dist = length(rel_vec);
if (attractors[i].radius < dist)
continue;
if (attractors[i].eat_radius>0.0 && attractors[i].eat_radius > dist) {
out_velocity_active.a=0.0;
}
rel_vec = normalize(rel_vec);
float attenuation = pow(dist / attractors[i].radius,attractors[i].attenuation);
if (attractors[i].dir==vec3(0.0)) {
//towards center
force+=attractors[i].strength * rel_vec * attenuation * mass;
} else {
force+=attractors[i].strength * attractors[i].dir * attenuation *mass;
}
}
out_velocity_active.xyz += force * local_delta;
}
#endif
#if !defined(DISABLE_VELOCITY)
if (true) {
xform[3].xyz += out_velocity_active.xyz * local_delta;
}
#endif
} else {
xform=mat4(0.0);
}
xform = transpose(xform);
out_velocity_active.a = mix(0.0,1.0,shader_active);
out_xform_1 = xform[0];
out_xform_2 = xform[1];
out_xform_3 = xform[2];
#endif //PARTICLES_COPY
}
[fragment]
//any code here is never executed, stuff is filled just so it works
#if defined(USE_MATERIAL)
layout(std140) uniform UniformData {
MATERIAL_UNIFORMS
};
#endif
FRAGMENT_SHADER_GLOBALS
void main() {
{
LIGHT_SHADER_CODE
}
{
FRAGMENT_SHADER_CODE
}
}

View file

@ -0,0 +1,44 @@
[vertex]
layout(location=0) in highp vec4 vertex_attrib;
layout(location=4) in vec2 uv_in;
out vec2 uv_interp;
void main() {
uv_interp = uv_in;
gl_Position = vertex_attrib;
}
[fragment]
#if !defined(GLES_OVER_GL)
precision mediump float;
#endif
in vec2 uv_interp;
uniform sampler2D source_specular; //texunit:0
uniform sampler2D source_ssr; //texunit:1
uniform vec2 pixel_size;
in vec2 uv2_interp;
layout(location = 0) out vec4 frag_color;
void main() {
vec4 specular = texture( source_specular, uv_interp );
#ifdef USE_SSR
vec4 ssr = textureLod(source_ssr,uv_interp,0.0);
specular.rgb = mix(specular.rgb,ssr.rgb*specular.a,ssr.a);
#endif
frag_color = vec4(specular.rgb,1.0);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,318 @@
[vertex]
layout(location=0) in highp vec4 vertex_attrib;
layout(location=4) in vec2 uv_in;
out vec2 uv_interp;
out vec2 pos_interp;
void main() {
uv_interp = uv_in;
gl_Position = vertex_attrib;
pos_interp.xy=gl_Position.xy;
}
[fragment]
in vec2 uv_interp;
in vec2 pos_interp;
uniform sampler2D source_diffuse; //texunit:0
uniform sampler2D source_normal_roughness; //texunit:1
uniform sampler2D source_depth; //texunit:2
uniform float camera_z_near;
uniform float camera_z_far;
uniform vec2 viewport_size;
uniform vec2 pixel_size;
uniform float filter_mipmap_levels;
uniform mat4 inverse_projection;
uniform mat4 projection;
uniform int num_steps;
uniform float depth_tolerance;
uniform float distance_fade;
uniform float curve_fade_in;
layout(location = 0) out vec4 frag_color;
vec2 view_to_screen(vec3 view_pos,out float w) {
vec4 projected = projection * vec4(view_pos, 1.0);
projected.xyz /= projected.w;
projected.xy = projected.xy * 0.5 + 0.5;
w=projected.w;
return projected.xy;
}
#define M_PI 3.14159265359
void main() {
////
vec4 diffuse = texture( source_diffuse, uv_interp );
vec4 normal_roughness = texture( source_normal_roughness, uv_interp);
vec3 normal;
normal = normal_roughness.xyz*2.0-1.0;
float roughness = normal_roughness.w;
float depth_tex = texture(source_depth,uv_interp).r;
vec4 world_pos = inverse_projection * vec4( uv_interp*2.0-1.0, depth_tex*2.0-1.0, 1.0 );
vec3 vertex = world_pos.xyz/world_pos.w;
vec3 view_dir = normalize(vertex);
vec3 ray_dir = normalize(reflect(view_dir, normal));
if (dot(ray_dir,normal)<0.001) {
frag_color=vec4(0.0);
return;
}
//ray_dir = normalize(view_dir - normal * dot(normal,view_dir) * 2.0);
//ray_dir = normalize(vec3(1,1,-1));
////////////////
//make ray length and clip it against the near plane (don't want to trace beyond visible)
float ray_len = (vertex.z + ray_dir.z * camera_z_far) > -camera_z_near ? (-camera_z_near - vertex.z) / ray_dir.z : camera_z_far;
vec3 ray_end = vertex + ray_dir*ray_len;
float w_begin;
vec2 vp_line_begin = view_to_screen(vertex,w_begin);
float w_end;
vec2 vp_line_end = view_to_screen( ray_end, w_end);
vec2 vp_line_dir = vp_line_end-vp_line_begin;
//we need to interpolate w along the ray, to generate perspective correct reflections
w_begin = 1.0/w_begin;
w_end = 1.0/w_end;
float z_begin = vertex.z*w_begin;
float z_end = ray_end.z*w_end;
vec2 line_begin = vp_line_begin/pixel_size;
vec2 line_dir = vp_line_dir/pixel_size;
float z_dir = z_end - z_begin;
float w_dir = w_end - w_begin;
// clip the line to the viewport edges
float scale_max_x = min(1.0, 0.99 * (1.0 - vp_line_begin.x) / max(1e-5, vp_line_dir.x));
float scale_max_y = min(1.0, 0.99 * (1.0 - vp_line_begin.y) / max(1e-5, vp_line_dir.y));
float scale_min_x = min(1.0, 0.99 * vp_line_begin.x / max(1e-5, -vp_line_dir.x));
float scale_min_y = min(1.0, 0.99 * vp_line_begin.y / max(1e-5, -vp_line_dir.y));
float line_clip = min(scale_max_x, scale_max_y) * min(scale_min_x, scale_min_y);
line_dir *= line_clip;
z_dir *= line_clip;
w_dir *=line_clip;
//clip z and w advance to line advance
vec2 line_advance = normalize(line_dir); //down to pixel
float step_size = length(line_advance)/length(line_dir);
float z_advance = z_dir*step_size; // adapt z advance to line advance
float w_advance = w_dir*step_size; // adapt w advance to line advance
//make line advance faster if direction is closer to pixel edges (this avoids sampling the same pixel twice)
float advance_angle_adj = 1.0/max(abs(line_advance.x),abs(line_advance.y));
line_advance*=advance_angle_adj; // adapt z advance to line advance
z_advance*=advance_angle_adj;
w_advance*=advance_angle_adj;
vec2 pos = line_begin;
float z = z_begin;
float w = w_begin;
float z_from=z/w;
float z_to=z_from;
float depth;
vec2 prev_pos=pos;
bool found=false;
float steps_taken=0.0;
for(int i=0;i<num_steps;i++) {
pos+=line_advance;
z+=z_advance;
w+=w_advance;
//convert to linear depth
depth = texture(source_depth, pos*pixel_size).r * 2.0 - 1.0;
#ifdef USE_ORTHOGONAL_PROJECTION
depth = ((depth + (camera_z_far + camera_z_near)/(camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near))/2.0;
#else
depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth * (camera_z_far - camera_z_near));
#endif
depth=-depth;
z_from = z_to;
z_to = z/w;
if (depth>z_to) {
//if depth was surpassed
if (depth<=max(z_to,z_from)+depth_tolerance) {
//check the depth tolerance
found=true;
}
break;
}
steps_taken+=1.0;
prev_pos=pos;
}
if (found) {
float margin_blend=1.0;
vec2 margin = vec2((viewport_size.x+viewport_size.y)*0.5*0.05); //make a uniform margin
if (any(bvec4(lessThan(pos,-margin),greaterThan(pos,viewport_size+margin)))) {
//clip outside screen + margin
frag_color=vec4(0.0);
return;
}
{
//blend fading out towards external margin
vec2 margin_grad = mix(pos-viewport_size,-pos,lessThan(pos,vec2(0.0)));
margin_blend = 1.0-smoothstep(0.0,margin.x,max(margin_grad.x,margin_grad.y));
//margin_blend=1.0;
}
vec2 final_pos;
float grad;
grad=steps_taken/float(num_steps);
float initial_fade = curve_fade_in==0.0 ? 1.0 : pow(clamp(grad,0.0,1.0),curve_fade_in);
float fade = pow(clamp(1.0-grad,0.0,1.0),distance_fade)*initial_fade;
final_pos=pos;
#ifdef REFLECT_ROUGHNESS
vec4 final_color;
//if roughness is enabled, do screen space cone tracing
if (roughness > 0.001) {
///////////////////////////////////////////////////////////////////////////////////////
//use a blurred version (in consecutive mipmaps) of the screen to simulate roughness
float gloss = 1.0-roughness;
float cone_angle = roughness * M_PI * 0.5;
vec2 cone_dir = final_pos - line_begin;
float cone_len = length(cone_dir);
cone_dir = normalize(cone_dir); //will be used normalized from now on
float max_mipmap = filter_mipmap_levels - 1.0;
float gloss_mult=gloss;
float rem_alpha=1.0;
final_color = vec4(0.0);
for(int i=0;i<7;i++) {
float op_len = 2.0 * tan(cone_angle) * cone_len; //opposite side of iso triangle
float radius;
{
//fit to sphere inside cone (sphere ends at end of cone), something like this:
// ___
// \O/
// V
//
// as it avoids bleeding from beyond the reflection as much as possible. As a plus
// it also makes the rough reflection more elongated.
float a = op_len;
float h = cone_len;
float a2 = a * a;
float fh2 = 4.0f * h * h;
radius = (a * (sqrt(a2 + fh2) - a)) / (4.0f * h);
}
//find the place where screen must be sampled
vec2 sample_pos = ( line_begin + cone_dir * (cone_len - radius) ) * pixel_size;
//radius is in pixels, so it's natural that log2(radius) maps to the right mipmap for the amount of pixels
float mipmap = clamp( log2( radius ), 0.0, max_mipmap );
//mipmap = max(mipmap-1.0,0.0);
//do sampling
vec4 sample_color;
{
sample_color = textureLod(source_diffuse,sample_pos,mipmap);
}
//multiply by gloss
sample_color.rgb*=gloss_mult;
sample_color.a=gloss_mult;
rem_alpha -= sample_color.a;
if(rem_alpha < 0.0) {
sample_color.rgb *= (1.0 - abs(rem_alpha));
}
final_color+=sample_color;
if (final_color.a>=0.95) {
// This code of accumulating gloss and aborting on near one
// makes sense when you think of cone tracing.
// Think of it as if roughness was 0, then we could abort on the first
// iteration. For lesser roughness values, we need more iterations, but
// each needs to have less influence given the sphere is smaller
break;
}
cone_len-=radius*2.0; //go to next (smaller) circle.
gloss_mult*=gloss;
}
} else {
final_color = textureLod(source_diffuse,final_pos*pixel_size,0.0);
}
frag_color = vec4(final_color.rgb,fade*margin_blend);
#else
frag_color = vec4(textureLod(source_diffuse,final_pos*pixel_size,0.0).rgb,fade*margin_blend);
#endif
} else {
frag_color = vec4(0.0,0.0,0.0,0.0);
}
}

View file

@ -0,0 +1,293 @@
[vertex]
layout(location=0) in highp vec4 vertex_attrib;
void main() {
gl_Position = vertex_attrib;
gl_Position.z=1.0;
}
[fragment]
#define TWO_PI 6.283185307179586476925286766559
#ifdef SSAO_QUALITY_HIGH
#define NUM_SAMPLES (80)
#endif
#ifdef SSAO_QUALITY_LOW
#define NUM_SAMPLES (15)
#endif
#if !defined(SSAO_QUALITY_LOW) && !defined(SSAO_QUALITY_HIGH)
#define NUM_SAMPLES (40)
#endif
// If using depth mip levels, the log of the maximum pixel offset before we need to switch to a lower
// miplevel to maintain reasonable spatial locality in the cache
// If this number is too small (< 3), too many taps will land in the same pixel, and we'll get bad variance that manifests as flashing.
// If it is too high (> 5), we'll get bad performance because we're not using the MIP levels effectively
#define LOG_MAX_OFFSET (3)
// This must be less than or equal to the MAX_MIP_LEVEL defined in SSAO.cpp
#define MAX_MIP_LEVEL (4)
// This is the number of turns around the circle that the spiral pattern makes. This should be prime to prevent
// taps from lining up. This particular choice was tuned for NUM_SAMPLES == 9
const int ROTATIONS[] = int[]( 1, 1, 2, 3, 2, 5, 2, 3, 2,
3, 3, 5, 5, 3, 4, 7, 5, 5, 7,
9, 8, 5, 5, 7, 7, 7, 8, 5, 8,
11, 12, 7, 10, 13, 8, 11, 8, 7, 14,
11, 11, 13, 12, 13, 19, 17, 13, 11, 18,
19, 11, 11, 14, 17, 21, 15, 16, 17, 18,
13, 17, 11, 17, 19, 18, 25, 18, 19, 19,
29, 21, 19, 27, 31, 29, 21, 18, 17, 29,
31, 31, 23, 18, 25, 26, 25, 23, 19, 34,
19, 27, 21, 25, 39, 29, 17, 21, 27 );
//#define NUM_SPIRAL_TURNS (7)
const int NUM_SPIRAL_TURNS = ROTATIONS[NUM_SAMPLES-1];
uniform sampler2D source_depth; //texunit:0
uniform highp usampler2D source_depth_mipmaps; //texunit:1
uniform sampler2D source_normal; //texunit:2
uniform ivec2 screen_size;
uniform float camera_z_far;
uniform float camera_z_near;
uniform float intensity_div_r6;
uniform float radius;
#ifdef ENABLE_RADIUS2
uniform float intensity_div_r62;
uniform float radius2;
#endif
uniform float bias;
uniform float proj_scale;
layout(location = 0) out float visibility;
uniform vec4 proj_info;
vec3 reconstructCSPosition(vec2 S, float z) {
#ifdef USE_ORTHOGONAL_PROJECTION
return vec3((S.xy * proj_info.xy + proj_info.zw), z);
#else
return vec3((S.xy * proj_info.xy + proj_info.zw) * z, z);
#endif
}
vec3 getPosition(ivec2 ssP) {
vec3 P;
P.z = texelFetch(source_depth, ssP, 0).r;
P.z = P.z * 2.0 - 1.0;
#ifdef USE_ORTHOGONAL_PROJECTION
P.z = ((P.z + (camera_z_far + camera_z_near)/(camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near))/2.0;
#else
P.z = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - P.z * (camera_z_far - camera_z_near));
#endif
P.z = -P.z;
// Offset to pixel center
P = reconstructCSPosition(vec2(ssP) + vec2(0.5), P.z);
return P;
}
/** Reconstructs screen-space unit normal from screen-space position */
vec3 reconstructCSFaceNormal(vec3 C) {
return normalize(cross(dFdy(C), dFdx(C)));
}
/** Returns a unit vector and a screen-space radius for the tap on a unit disk (the caller should scale by the actual disk radius) */
vec2 tapLocation(int sampleNumber, float spinAngle, out float ssR){
// Radius relative to ssR
float alpha = (float(sampleNumber) + 0.5) * (1.0 / float(NUM_SAMPLES));
float angle = alpha * (float(NUM_SPIRAL_TURNS) * 6.28) + spinAngle;
ssR = alpha;
return vec2(cos(angle), sin(angle));
}
/** Read the camera-space position of the point at screen-space pixel ssP + unitOffset * ssR. Assumes length(unitOffset) == 1 */
vec3 getOffsetPosition(ivec2 ssC, vec2 unitOffset, float ssR) {
// Derivation:
// mipLevel = floor(log(ssR / MAX_OFFSET));
int mipLevel = clamp(int(floor(log2(ssR))) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL);
ivec2 ssP = ivec2(ssR * unitOffset) + ssC;
vec3 P;
// We need to divide by 2^mipLevel to read the appropriately scaled coordinate from a MIP-map.
// Manually clamp to the texture size because texelFetch bypasses the texture unit
ivec2 mipP = clamp(ssP >> mipLevel, ivec2(0), (screen_size >> mipLevel) - ivec2(1));
if (mipLevel < 1) {
//read from depth buffer
P.z = texelFetch(source_depth, mipP, 0).r;
P.z = P.z * 2.0 - 1.0;
#ifdef USE_ORTHOGONAL_PROJECTION
P.z = ((P.z + (camera_z_far + camera_z_near)/(camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near))/2.0;
#else
P.z = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - P.z * (camera_z_far - camera_z_near));
#endif
P.z = -P.z;
} else {
//read from mipmaps
uint d = texelFetch(source_depth_mipmaps, mipP, mipLevel-1).r;
P.z = -(float(d)/65535.0)*camera_z_far;
}
// Offset to pixel center
P = reconstructCSPosition(vec2(ssP) + vec2(0.5), P.z);
return P;
}
/** Compute the occlusion due to sample with index \a i about the pixel at \a ssC that corresponds
to camera-space point \a C with unit normal \a n_C, using maximum screen-space sampling radius \a ssDiskRadius
Note that units of H() in the HPG12 paper are meters, not
unitless. The whole falloff/sampling function is therefore
unitless. In this implementation, we factor out (9 / radius).
Four versions of the falloff function are implemented below
*/
float sampleAO(in ivec2 ssC, in vec3 C, in vec3 n_C, in float ssDiskRadius,in float p_radius, in int tapIndex, in float randomPatternRotationAngle) {
// Offset on the unit disk, spun for this pixel
float ssR;
vec2 unitOffset = tapLocation(tapIndex, randomPatternRotationAngle, ssR);
ssR *= ssDiskRadius;
// The occluding point in camera space
vec3 Q = getOffsetPosition(ssC, unitOffset, ssR);
vec3 v = Q - C;
float vv = dot(v, v);
float vn = dot(v, n_C);
const float epsilon = 0.01;
float radius2 = p_radius*p_radius;
// A: From the HPG12 paper
// Note large epsilon to avoid overdarkening within cracks
//return float(vv < radius2) * max((vn - bias) / (epsilon + vv), 0.0) * radius2 * 0.6;
// B: Smoother transition to zero (lowers contrast, smoothing out corners). [Recommended]
float f=max(radius2 - vv, 0.0);
return f * f * f * max((vn - bias) / (epsilon + vv), 0.0);
// C: Medium contrast (which looks better at high radii), no division. Note that the
// contribution still falls off with radius^2, but we've adjusted the rate in a way that is
// more computationally efficient and happens to be aesthetically pleasing.
// return 4.0 * max(1.0 - vv * invRadius2, 0.0) * max(vn - bias, 0.0);
// D: Low contrast, no division operation
// return 2.0 * float(vv < radius * radius) * max(vn - bias, 0.0);
}
void main() {
// Pixel being shaded
ivec2 ssC = ivec2(gl_FragCoord.xy);
// World space point being shaded
vec3 C = getPosition(ssC);
/* if (C.z <= -camera_z_far*0.999) {
// We're on the skybox
visibility=1.0;
return;
}*/
//visibility=-C.z/camera_z_far;
//return;
#if 0
vec3 n_C = texelFetch(source_normal,ssC,0).rgb * 2.0 - 1.0;
#else
vec3 n_C = reconstructCSFaceNormal(C);
n_C = -n_C;
#endif
// Hash function used in the HPG12 AlchemyAO paper
float randomPatternRotationAngle = mod(float((3 * ssC.x ^ ssC.y + ssC.x * ssC.y) * 10), TWO_PI);
// Reconstruct normals from positions. These will lead to 1-pixel black lines
// at depth discontinuities, however the blur will wipe those out so they are not visible
// in the final image.
// Choose the screen-space sample radius
// proportional to the projected area of the sphere
#ifdef USE_ORTHOGONAL_PROJECTION
float ssDiskRadius = -proj_scale * radius;
#else
float ssDiskRadius = -proj_scale * radius / C.z;
#endif
float sum = 0.0;
for (int i = 0; i < NUM_SAMPLES; ++i) {
sum += sampleAO(ssC, C, n_C, ssDiskRadius, radius,i, randomPatternRotationAngle);
}
float A = max(0.0, 1.0 - sum * intensity_div_r6 * (5.0 / float(NUM_SAMPLES)));
#ifdef ENABLE_RADIUS2
//go again for radius2
randomPatternRotationAngle = mod(float((5 * ssC.x ^ ssC.y + ssC.x * ssC.y) * 11), TWO_PI);
// Reconstruct normals from positions. These will lead to 1-pixel black lines
// at depth discontinuities, however the blur will wipe those out so they are not visible
// in the final image.
// Choose the screen-space sample radius
// proportional to the projected area of the sphere
ssDiskRadius = -proj_scale * radius2 / C.z;
sum = 0.0;
for (int i = 0; i < NUM_SAMPLES; ++i) {
sum += sampleAO(ssC, C, n_C, ssDiskRadius,radius2, i, randomPatternRotationAngle);
}
A= min(A,max(0.0, 1.0 - sum * intensity_div_r62 * (5.0 / float(NUM_SAMPLES))));
#endif
// Bilateral box-filter over a quad for free, respecting depth edges
// (the difference that this makes is subtle)
if (abs(dFdx(C.z)) < 0.02) {
A -= dFdx(A) * (float(ssC.x & 1) - 0.5);
}
if (abs(dFdy(C.z)) < 0.02) {
A -= dFdy(A) * (float(ssC.y & 1) - 0.5);
}
visibility = A;
}

View file

@ -0,0 +1,124 @@
[vertex]
layout(location=0) in highp vec4 vertex_attrib;
void main() {
gl_Position = vertex_attrib;
gl_Position.z=1.0;
}
[fragment]
uniform sampler2D source_ssao; //texunit:0
uniform sampler2D source_depth; //texunit:1
uniform sampler2D source_normal; //texunit:3
layout(location = 0) out float visibility;
//////////////////////////////////////////////////////////////////////////////////////////////
// Tunable Parameters:
/** Increase to make depth edges crisper. Decrease to reduce flicker. */
uniform float edge_sharpness;
/** Step in 2-pixel intervals since we already blurred against neighbors in the
first AO pass. This constant can be increased while R decreases to improve
performance at the expense of some dithering artifacts.
Morgan found that a scale of 3 left a 1-pixel checkerboard grid that was
unobjectionable after shading was applied but eliminated most temporal incoherence
from using small numbers of sample taps.
*/
uniform int filter_scale;
/** Filter radius in pixels. This will be multiplied by SCALE. */
#define R (4)
//////////////////////////////////////////////////////////////////////////////////////////////
// Gaussian coefficients
const float gaussian[R + 1] =
// float[](0.356642, 0.239400, 0.072410, 0.009869);
// float[](0.398943, 0.241971, 0.053991, 0.004432, 0.000134); // stddev = 1.0
float[](0.153170, 0.144893, 0.122649, 0.092902, 0.062970); // stddev = 2.0
// float[](0.111220, 0.107798, 0.098151, 0.083953, 0.067458, 0.050920, 0.036108); // stddev = 3.0
/** (1, 0) or (0, 1)*/
uniform ivec2 axis;
uniform float camera_z_far;
uniform float camera_z_near;
uniform ivec2 screen_size;
void main() {
ivec2 ssC = ivec2(gl_FragCoord.xy);
float depth = texelFetch(source_depth, ssC, 0).r;
//vec3 normal = texelFetch(source_normal,ssC,0).rgb * 2.0 - 1.0;
depth = depth * 2.0 - 1.0;
depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth * (camera_z_far - camera_z_near));
float depth_divide = 1.0 / camera_z_far;
// depth*=depth_divide;
/*
if (depth > camera_z_far*0.999) {
discard;//skybox
}
*/
float sum = texelFetch(source_ssao, ssC, 0).r;
// Base weight for depth falloff. Increase this for more blurriness,
// decrease it for better edge discrimination
float BASE = gaussian[0];
float totalWeight = BASE;
sum *= totalWeight;
ivec2 clamp_limit = screen_size - ivec2(1);
for (int r = -R; r <= R; ++r) {
// We already handled the zero case above. This loop should be unrolled and the static branch optimized out,
// so the IF statement has no runtime cost
if (r != 0) {
ivec2 ppos = ssC + axis * (r * filter_scale);
float value = texelFetch(source_ssao, clamp(ppos,ivec2(0),clamp_limit), 0).r;
ivec2 rpos = clamp(ppos,ivec2(0),clamp_limit);
float temp_depth = texelFetch(source_depth, rpos, 0).r;
//vec3 temp_normal = texelFetch(source_normal, rpos, 0).rgb * 2.0 - 1.0;
temp_depth = temp_depth * 2.0 - 1.0;
temp_depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - temp_depth * (camera_z_far - camera_z_near));
// temp_depth *= depth_divide;
// spatial domain: offset gaussian tap
float weight = 0.3 + gaussian[abs(r)];
//weight *= max(0.0,dot(temp_normal,normal));
// range domain (the "bilateral" weight). As depth difference increases, decrease weight.
weight *= max(0.0, 1.0
- edge_sharpness * abs(temp_depth - depth)
);
sum += value * weight;
totalWeight += weight;
}
}
const float epsilon = 0.0001;
visibility = sum / (totalWeight + epsilon);
}

View file

@ -0,0 +1,59 @@
[vertex]
layout(location=0) in highp vec4 vertex_attrib;
void main() {
gl_Position = vertex_attrib;
}
[fragment]
#ifdef MINIFY_START
#define SDEPTH_TYPE highp sampler2D
uniform float camera_z_far;
uniform float camera_z_near;
#else
#define SDEPTH_TYPE mediump usampler2D
#endif
uniform SDEPTH_TYPE source_depth; //texunit:0
uniform ivec2 from_size;
uniform int source_mipmap;
layout(location = 0) out mediump uint depth;
void main() {
ivec2 ssP = ivec2(gl_FragCoord.xy);
// Rotated grid subsampling to avoid XY directional bias or Z precision bias while downsampling.
// On DX9, the bit-and can be implemented with floating-point modulo
#ifdef MINIFY_START
float fdepth = texelFetch(source_depth, clamp(ssP * 2 + ivec2(ssP.y & 1, ssP.x & 1), ivec2(0), from_size - ivec2(1)), source_mipmap).r;
fdepth = fdepth * 2.0 - 1.0;
#ifdef USE_ORTHOGONAL_PROJECTION
fdepth = ((fdepth + (camera_z_far + camera_z_near)/(camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near))/2.0;
#else
fdepth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - fdepth * (camera_z_far - camera_z_near));
#endif
fdepth /= camera_z_far;
depth = uint(clamp(fdepth*65535.0,0.0,65535.0));
#else
depth = texelFetch(source_depth, clamp(ssP * 2 + ivec2(ssP.y & 1, ssP.x & 1), ivec2(0), from_size - ivec2(1)), source_mipmap).r;
#endif
}

View file

@ -0,0 +1,192 @@
[vertex]
layout(location=0) in highp vec4 vertex_attrib;
layout(location=4) in vec2 uv_in;
out vec2 uv_interp;
void main() {
uv_interp = uv_in;
gl_Position = vertex_attrib;
}
[fragment]
//#define QUALIFIER uniform // some guy on the interweb says it may be faster with this
#define QUALIFIER const
#ifdef USE_25_SAMPLES
const int kernel_size=25;
QUALIFIER vec2 kernel[25] = vec2[] (
vec2(0.530605, 0.0),
vec2(0.000973794, -3.0),
vec2(0.00333804, -2.52083),
vec2(0.00500364, -2.08333),
vec2(0.00700976, -1.6875),
vec2(0.0094389, -1.33333),
vec2(0.0128496, -1.02083),
vec2(0.017924, -0.75),
vec2(0.0263642, -0.520833),
vec2(0.0410172, -0.333333),
vec2(0.0493588, -0.1875),
vec2(0.0402784, -0.0833333),
vec2(0.0211412, -0.0208333),
vec2(0.0211412, 0.0208333),
vec2(0.0402784, 0.0833333),
vec2(0.0493588, 0.1875),
vec2(0.0410172, 0.333333),
vec2(0.0263642, 0.520833),
vec2(0.017924, 0.75),
vec2(0.0128496, 1.02083),
vec2(0.0094389, 1.33333),
vec2(0.00700976, 1.6875),
vec2(0.00500364, 2.08333),
vec2(0.00333804, 2.52083),
vec2(0.000973794, 3.0)
);
#endif //USE_25_SAMPLES
#ifdef USE_17_SAMPLES
const int kernel_size=17;
QUALIFIER vec2 kernel[17] = vec2[](
vec2(0.536343, 0.0),
vec2(0.00317394, -2.0),
vec2(0.0100386, -1.53125),
vec2(0.0144609, -1.125),
vec2(0.0216301, -0.78125),
vec2(0.0347317, -0.5),
vec2(0.0571056, -0.28125),
vec2(0.0582416, -0.125),
vec2(0.0324462, -0.03125),
vec2(0.0324462, 0.03125),
vec2(0.0582416, 0.125),
vec2(0.0571056, 0.28125),
vec2(0.0347317, 0.5),
vec2(0.0216301, 0.78125),
vec2(0.0144609, 1.125),
vec2(0.0100386, 1.53125),
vec2(0.00317394,2.0)
);
#endif //USE_17_SAMPLES
#ifdef USE_11_SAMPLES
const int kernel_size=11;
QUALIFIER vec2 kernel[11] = vec2[](
vec2(0.560479, 0.0),
vec2(0.00471691, -2.0),
vec2(0.0192831, -1.28),
vec2(0.03639, -0.72),
vec2(0.0821904, -0.32),
vec2(0.0771802, -0.08),
vec2(0.0771802, 0.08),
vec2(0.0821904, 0.32),
vec2(0.03639, 0.72),
vec2(0.0192831, 1.28),
vec2(0.00471691,2.0)
);
#endif //USE_11_SAMPLES
uniform float max_radius;
uniform float camera_z_far;
uniform float camera_z_near;
uniform float unit_size;
uniform vec2 dir;
in vec2 uv_interp;
uniform sampler2D source_diffuse; //texunit:0
uniform sampler2D source_sss; //texunit:1
uniform sampler2D source_depth; //texunit:2
layout(location = 0) out vec4 frag_color;
void main() {
float strength = texture(source_sss,uv_interp).r;
strength*=strength; //stored as sqrt
// Fetch color of current pixel:
vec4 base_color = texture(source_diffuse, uv_interp);
if (strength>0.0) {
// Fetch linear depth of current pixel:
float depth = texture(source_depth, uv_interp).r * 2.0 - 1.0;
#ifdef USE_ORTHOGONAL_PROJECTION
depth = ((depth + (camera_z_far + camera_z_near)/(camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near))/2.0;
float scale = unit_size; //remember depth is negative by default in OpenGL
#else
depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth * (camera_z_far - camera_z_near));
float scale = unit_size / depth; //remember depth is negative by default in OpenGL
#endif
// Calculate the final step to fetch the surrounding pixels:
vec2 step = max_radius * scale * dir;
step *= strength; // Modulate it using the alpha channel.
step *= 1.0 / 3.0; // Divide by 3 as the kernels range from -3 to 3.
// Accumulate the center sample:
vec3 color_accum = base_color.rgb;
color_accum *= kernel[0].x;
#ifdef ENABLE_STRENGTH_WEIGHTING
float color_weight = kernel[0].x;
#endif
// Accumulate the other samples:
for (int i = 1; i < kernel_size; i++) {
// Fetch color and depth for current sample:
vec2 offset = uv_interp + kernel[i].y * step;
vec3 color = texture(source_diffuse, offset).rgb;
#ifdef ENABLE_FOLLOW_SURFACE
// If the difference in depth is huge, we lerp color back to "colorM":
float depth_cmp = texture(source_depth, offset).r *2.0 - 1.0;
#ifdef USE_ORTHOGONAL_PROJECTION
depth_cmp = ((depth_cmp + (camera_z_far + camera_z_near)/(camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near))/2.0;
#else
depth_cmp = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth_cmp * (camera_z_far - camera_z_near));
#endif
float s = clamp(300.0f * scale *
max_radius * abs(depth - depth_cmp),0.0,1.0);
color = mix(color, base_color.rgb, s);
#endif
// Accumulate:
color*=kernel[i].x;
#ifdef ENABLE_STRENGTH_WEIGHTING
float color_s = texture(source_sss, offset).r;
color_weight+=color_s * kernel[i].x;
color*=color_s;
#endif
color_accum += color;
}
#ifdef ENABLE_STRENGTH_WEIGHTING
color_accum/=color_weight;
#endif
frag_color = vec4(color_accum,base_color.a); //keep alpha (used for SSAO)
} else {
frag_color = base_color;
}
}

View file

@ -0,0 +1,323 @@
[vertex]
layout(location=0) in highp vec4 vertex_attrib;
layout(location=4) in vec2 uv_in;
out vec2 uv_interp;
void main() {
gl_Position = vertex_attrib;
uv_interp = uv_in;
#ifdef V_FLIP
uv_interp.y = 1.0-uv_interp.y;
#endif
}
[fragment]
#if !defined(GLES_OVER_GL)
precision mediump float;
#endif
in vec2 uv_interp;
uniform highp sampler2D source; //texunit:0
uniform float exposure;
uniform float white;
#ifdef USE_AUTO_EXPOSURE
uniform highp sampler2D source_auto_exposure; //texunit:1
uniform highp float auto_exposure_grey;
#endif
#if defined(USE_GLOW_LEVEL1) || defined(USE_GLOW_LEVEL2) || defined(USE_GLOW_LEVEL3) || defined(USE_GLOW_LEVEL4) || defined(USE_GLOW_LEVEL5) || defined(USE_GLOW_LEVEL6) || defined(USE_GLOW_LEVEL7)
uniform highp sampler2D source_glow; //texunit:2
uniform highp float glow_intensity;
#endif
#ifdef USE_BCS
uniform vec3 bcs;
#endif
#ifdef USE_COLOR_CORRECTION
uniform sampler2D color_correction; //texunit:3
#endif
layout(location = 0) out vec4 frag_color;
#ifdef USE_GLOW_FILTER_BICUBIC
// w0, w1, w2, and w3 are the four cubic B-spline basis functions
float w0(float a)
{
return (1.0/6.0)*(a*(a*(-a + 3.0) - 3.0) + 1.0);
}
float w1(float a)
{
return (1.0/6.0)*(a*a*(3.0*a - 6.0) + 4.0);
}
float w2(float a)
{
return (1.0/6.0)*(a*(a*(-3.0*a + 3.0) + 3.0) + 1.0);
}
float w3(float a)
{
return (1.0/6.0)*(a*a*a);
}
// g0 and g1 are the two amplitude functions
float g0(float a)
{
return w0(a) + w1(a);
}
float g1(float a)
{
return w2(a) + w3(a);
}
// h0 and h1 are the two offset functions
float h0(float a)
{
return -1.0 + w1(a) / (w0(a) + w1(a));
}
float h1(float a)
{
return 1.0 + w3(a) / (w2(a) + w3(a));
}
uniform ivec2 glow_texture_size;
vec4 texture2D_bicubic(sampler2D tex, vec2 uv,int p_lod)
{
float lod=float(p_lod);
vec2 tex_size = vec2(glow_texture_size >> p_lod);
vec2 pixel_size =1.0/tex_size;
uv = uv*tex_size + 0.5;
vec2 iuv = floor( uv );
vec2 fuv = fract( uv );
float g0x = g0(fuv.x);
float g1x = g1(fuv.x);
float h0x = h0(fuv.x);
float h1x = h1(fuv.x);
float h0y = h0(fuv.y);
float h1y = h1(fuv.y);
vec2 p0 = (vec2(iuv.x + h0x, iuv.y + h0y) - 0.5) * pixel_size;
vec2 p1 = (vec2(iuv.x + h1x, iuv.y + h0y) - 0.5) * pixel_size;
vec2 p2 = (vec2(iuv.x + h0x, iuv.y + h1y) - 0.5) * pixel_size;
vec2 p3 = (vec2(iuv.x + h1x, iuv.y + h1y) - 0.5) * pixel_size;
return g0(fuv.y) * (g0x * textureLod(tex, p0,lod) +
g1x * textureLod(tex, p1,lod)) +
g1(fuv.y) * (g0x * textureLod(tex, p2,lod) +
g1x * textureLod(tex, p3,lod));
}
#define GLOW_TEXTURE_SAMPLE(m_tex,m_uv,m_lod) texture2D_bicubic(m_tex,m_uv,m_lod)
#else
#define GLOW_TEXTURE_SAMPLE(m_tex,m_uv,m_lod) textureLod(m_tex,m_uv,float(m_lod))
#endif
vec3 tonemap_filmic(vec3 color,float white) {
float A = 0.15;
float B = 0.50;
float C = 0.10;
float D = 0.20;
float E = 0.02;
float F = 0.30;
float W = 11.2;
vec3 coltn = ((color*(A*color+C*B)+D*E)/(color*(A*color+B)+D*F))-E/F;
float whitetn = ((white*(A*white+C*B)+D*E)/(white*(A*white+B)+D*F))-E/F;
return coltn/whitetn;
}
vec3 tonemap_aces(vec3 color) {
float a = 2.51f;
float b = 0.03f;
float c = 2.43f;
float d = 0.59f;
float e = 0.14f;
return color = clamp((color*(a*color+b))/(color*(c*color+d)+e),vec3(0.0),vec3(1.0));
}
vec3 tonemap_reindhart(vec3 color,float white) {
return ( color * ( 1.0 + ( color / ( white) ) ) ) / ( 1.0 + color );
}
void main() {
vec4 color = textureLod(source, uv_interp, 0.0);
#ifdef USE_AUTO_EXPOSURE
color/=texelFetch(source_auto_exposure,ivec2(0,0),0).r/auto_exposure_grey;
#endif
color*=exposure;
#if defined(USE_GLOW_LEVEL1) || defined(USE_GLOW_LEVEL2) || defined(USE_GLOW_LEVEL3) || defined(USE_GLOW_LEVEL4) || defined(USE_GLOW_LEVEL5) || defined(USE_GLOW_LEVEL6) || defined(USE_GLOW_LEVEL7)
#define USING_GLOW
#endif
#if defined(USING_GLOW)
vec3 glow = vec3(0.0);
#ifdef USE_GLOW_LEVEL1
glow+=GLOW_TEXTURE_SAMPLE(source_glow,uv_interp,1).rgb;
#endif
#ifdef USE_GLOW_LEVEL2
glow+=GLOW_TEXTURE_SAMPLE(source_glow,uv_interp,2).rgb;
#endif
#ifdef USE_GLOW_LEVEL3
glow+=GLOW_TEXTURE_SAMPLE(source_glow,uv_interp,3).rgb;
#endif
#ifdef USE_GLOW_LEVEL4
glow+=GLOW_TEXTURE_SAMPLE(source_glow,uv_interp,4).rgb;
#endif
#ifdef USE_GLOW_LEVEL5
glow+=GLOW_TEXTURE_SAMPLE(source_glow,uv_interp,5).rgb;
#endif
#ifdef USE_GLOW_LEVEL6
glow+=GLOW_TEXTURE_SAMPLE(source_glow,uv_interp,6).rgb;
#endif
#ifdef USE_GLOW_LEVEL7
glow+=GLOW_TEXTURE_SAMPLE(source_glow,uv_interp,7).rgb;
#endif
glow *= glow_intensity;
#endif
#ifdef USE_REINDHART_TONEMAPPER
color.rgb = tonemap_reindhart(color.rgb,white);
# if defined(USING_GLOW)
glow = tonemap_reindhart(glow,white);
# endif
#endif
#ifdef USE_FILMIC_TONEMAPPER
color.rgb = tonemap_filmic(color.rgb,white);
# if defined(USING_GLOW)
glow = tonemap_filmic(glow,white);
# endif
#endif
#ifdef USE_ACES_TONEMAPPER
color.rgb = tonemap_aces(color.rgb);
# if defined(USING_GLOW)
glow = tonemap_aces(glow);
# endif
#endif
//regular Linear -> SRGB conversion
vec3 a = vec3(0.055);
color.rgb = mix( (vec3(1.0)+a)*pow(color.rgb,vec3(1.0/2.4))-a , 12.92*color.rgb , lessThan(color.rgb,vec3(0.0031308)));
#if defined(USING_GLOW)
glow = mix( (vec3(1.0)+a)*pow(glow,vec3(1.0/2.4))-a , 12.92*glow , lessThan(glow,vec3(0.0031308)));
#endif
//glow needs to be added in SRGB space (together with image space effects)
color.rgb = clamp(color.rgb,0.0,1.0);
#if defined(USING_GLOW)
glow = clamp(glow,0.0,1.0);
#endif
#ifdef USE_GLOW_REPLACE
color.rgb = glow;
#endif
#ifdef USE_GLOW_SCREEN
color.rgb = max((color.rgb + glow) - (color.rgb * glow), vec3(0.0));
#endif
#ifdef USE_GLOW_SOFTLIGHT
{
glow = (glow * 0.5) + 0.5;
color.r = (glow.r <= 0.5) ? (color.r - (1.0 - 2.0 * glow.r) * color.r * (1.0 - color.r)) : (((glow.r > 0.5) && (color.r <= 0.25)) ? (color.r + (2.0 * glow.r - 1.0) * (4.0 * color.r * (4.0 * color.r + 1.0) * (color.r - 1.0) + 7.0 * color.r)) : (color.r + (2.0 * glow.r - 1.0) * (sqrt(color.r) - color.r)));
color.g = (glow.g <= 0.5) ? (color.g - (1.0 - 2.0 * glow.g) * color.g * (1.0 - color.g)) : (((glow.g > 0.5) && (color.g <= 0.25)) ? (color.g + (2.0 * glow.g - 1.0) * (4.0 * color.g * (4.0 * color.g + 1.0) * (color.g - 1.0) + 7.0 * color.g)) : (color.g + (2.0 * glow.g - 1.0) * (sqrt(color.g) - color.g)));
color.b = (glow.b <= 0.5) ? (color.b - (1.0 - 2.0 * glow.b) * color.b * (1.0 - color.b)) : (((glow.b > 0.5) && (color.b <= 0.25)) ? (color.b + (2.0 * glow.b - 1.0) * (4.0 * color.b * (4.0 * color.b + 1.0) * (color.b - 1.0) + 7.0 * color.b)) : (color.b + (2.0 * glow.b - 1.0) * (sqrt(color.b) - color.b)));
}
#endif
#if defined(USING_GLOW) && !defined(USE_GLOW_SCREEN) && !defined(USE_GLOW_SOFTLIGHT) && !defined(USE_GLOW_REPLACE)
//additive
color.rgb+=glow;
#endif
#ifdef USE_BCS
color.rgb = mix(vec3(0.0),color.rgb,bcs.x);
color.rgb = mix(vec3(0.5),color.rgb,bcs.y);
color.rgb = mix(vec3(dot(vec3(1.0),color.rgb)*0.33333),color.rgb,bcs.z);
#endif
#ifdef USE_COLOR_CORRECTION
color.r = texture(color_correction,vec2(color.r,0.0)).r;
color.g = texture(color_correction,vec2(color.g,0.0)).g;
color.b = texture(color_correction,vec2(color.b,0.0)).b;
#endif
frag_color=vec4(color.rgb,1.0);
}

View file

@ -19,637 +19,6 @@ def add_source_files(self, sources, filetype, lib_env=None, shared=False):
sources.append(self.Object(f))
def build_shader_header(target, source, env):
for x in source:
print(x)
name = str(x)
name = name[name.rfind("/") + 1:]
name = name[name.rfind("\\") + 1:]
name = name.replace(".", "_")
fs = open(str(x), "r")
fd = open(str(x) + ".gen.h", "w")
fd.write("/* this file has been generated by SCons, do not edit! */\n")
fd.write("static const char *" + name + "=\n")
line = fs.readline()
while(line):
line = line.replace("\r", "")
line = line.replace("\n", "")
line = line.replace("\\", "\\\\")
line = line.replace("\"", "\\\"")
fd.write("\"" + line + "\\n\"\n")
line = fs.readline()
fd.write(";\n")
return 0
def build_glsl_header(filename):
fs = open(filename, "r")
line = fs.readline()
vertex_lines = []
fragment_lines = []
uniforms = []
attributes = []
fbos = []
conditionals = []
texunits = []
texunit_names = []
ubos = []
ubo_names = []
reading = ""
line_offset = 0
vertex_offset = 0
fragment_offset = 0
while(line):
if (line.find("[vertex]") != -1):
reading = "vertex"
line = fs.readline()
line_offset += 1
vertex_offset = line_offset
continue
if (line.find("[fragment]") != -1):
reading = "fragment"
line = fs.readline()
line_offset += 1
fragment_offset = line_offset
continue
if (line.find("#ifdef ") != -1):
ifdefline = line.replace("#ifdef ", "").strip()
if (not ifdefline in conditionals):
conditionals += [ifdefline]
if (line.find("#elif defined(") != -1):
ifdefline = line.replace("#elif defined(", "").strip()
ifdefline = ifdefline.replace(")", "").strip()
if (not ifdefline in conditionals):
conditionals += [ifdefline]
import re
if re.search(r"^\s*uniform", line):
if (line.lower().find("texunit:") != -1):
# texture unit
texunit = str(int(line[line.find(":") + 1:].strip()))
uline = line[:line.lower().find("//")]
uline = uline.replace("uniform", "")
uline = uline.replace(";", "")
lines = uline.split(",")
for x in lines:
x = x.strip()
x = x[x.rfind(" ") + 1:]
if (x.find("[") != -1):
# unfiorm array
x = x[:x.find("[")]
if (not x in texunit_names):
texunits += [(x, texunit)]
texunit_names += [x]
elif (line.lower().find("ubo:") != -1):
# ubo
uboidx = str(int(line[line.find(":") + 1:].strip()))
uline = line[:line.lower().find("//")]
uline = uline[uline.find("uniform") + len("uniform"):]
uline = uline.replace(";", "")
uline = uline.replace("{", "").strip()
lines = uline.split(",")
for x in lines:
x = x.strip()
x = x[x.rfind(" ") + 1:]
if (x.find("[") != -1):
# unfiorm array
x = x[:x.find("[")]
if (not x in ubo_names):
ubos += [(x, uboidx)]
ubo_names += [x]
else:
uline = line.replace("uniform", "")
uline = uline.replace(";", "")
lines = uline.split(",")
for x in lines:
x = x.strip()
x = x[x.rfind(" ") + 1:]
if (x.find("[") != -1):
# unfiorm array
x = x[:x.find("[")]
if (not x in uniforms):
uniforms += [x]
if ((line.strip().find("in ") == 0 or line.strip().find("attribute ") == 0) and line.find("attrib:") != -1):
uline = line.replace("in ", "")
uline = uline.replace("attribute ", "")
uline = uline.replace(";", "")
uline = uline[uline.find(" "):].strip()
if (uline.find("//") != -1):
name, bind = uline.split("//")
if (bind.find("attrib:") != -1):
name = name.strip()
bind = bind.replace("attrib:", "").strip()
attributes += [(name, bind)]
if (line.strip().find("out ") == 0):
uline = line.replace("out", "").strip()
uline = uline.replace(";", "")
uline = uline[uline.find(" "):].strip()
if (uline.find("//") != -1):
name, bind = uline.split("//")
if (bind.find("drawbuffer:") != -1):
name = name.strip()
bind = bind.replace("drawbuffer:", "").strip()
fbos += [(name, bind)]
line = line.replace("\r", "")
line = line.replace("\n", "")
line = line.replace("\\", "\\\\")
line = line.replace("\"", "\\\"")
# line=line+"\\n\\" no need to anymore
if (reading == "vertex"):
vertex_lines += [line]
if (reading == "fragment"):
fragment_lines += [line]
line = fs.readline()
line_offset += 1
fs.close()
out_file = filename + ".gen.h"
fd = open(out_file, "w")
fd.write("/* WARNING, THIS FILE WAS GENERATED, DO NOT EDIT */\n")
out_file_base = out_file
out_file_base = out_file_base[out_file_base.rfind("/") + 1:]
out_file_base = out_file_base[out_file_base.rfind("\\") + 1:]
# print("out file "+out_file+" base " +out_file_base)
out_file_ifdef = out_file_base.replace(".", "_").upper()
fd.write("#ifndef " + out_file_ifdef + "\n")
fd.write("#define " + out_file_ifdef + "\n")
out_file_class = out_file_base.replace(".glsl.h", "").title().replace("_", "").replace(".", "") + "ShaderGL"
fd.write("\n\n")
fd.write("#include \"drivers/opengl/shader_gl.h\"\n\n\n")
fd.write("class " + out_file_class + " : public ShaderGL {\n\n")
fd.write("\t virtual String get_shader_name() const { return \"" + out_file_class + "\"; }\n")
fd.write("public:\n\n")
if (len(conditionals)):
fd.write("\tenum Conditionals {\n")
for x in conditionals:
fd.write("\t\t" + x + ",\n")
fd.write("\t};\n\n")
if (len(uniforms)):
fd.write("\tenum Uniforms {\n")
for x in uniforms:
fd.write("\t\t" + x.upper() + ",\n")
fd.write("\t};\n\n")
fd.write("\t_FORCE_INLINE_ int get_uniform(Uniforms p_uniform) const { return _get_uniform(p_uniform); }\n\n")
if (len(conditionals)):
fd.write("\t_FORCE_INLINE_ void set_conditional(Conditionals p_conditional,bool p_enable) { _set_conditional(p_conditional,p_enable); }\n\n")
fd.write("\t#define _FU if (get_uniform(p_uniform)<0) return; ERR_FAIL_COND( get_active()!=this );\n\n ")
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, bool p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value?1:0); }\n\n")
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_value) { _FU glUniform1f(get_uniform(p_uniform),p_value); }\n\n")
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, double p_value) { _FU glUniform1f(get_uniform(p_uniform),p_value); }\n\n")
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, uint8_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n")
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, int8_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n")
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, uint16_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n")
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, int16_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n")
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, uint32_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n")
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, int32_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n")
#fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, uint64_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n");
#fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, int64_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n");
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, unsigned long p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n")
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, long p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n")
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Color& p_color) { _FU GLfloat col[4]={p_color.r,p_color.g,p_color.b,p_color.a}; glUniform4fv(get_uniform(p_uniform),1,col); }\n\n")
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Vector2& p_vec2) { _FU GLfloat vec2[2]={p_vec2.x,p_vec2.y}; glUniform2fv(get_uniform(p_uniform),1,vec2); }\n\n")
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Vector3& p_vec3) { _FU GLfloat vec3[3]={p_vec3.x,p_vec3.y,p_vec3.z}; glUniform3fv(get_uniform(p_uniform),1,vec3); }\n\n")
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Plane& p_plane) { _FU GLfloat plane[4]={p_plane.normal.x,p_plane.normal.y,p_plane.normal.z,p_plane.d}; glUniform4fv(get_uniform(p_uniform),1,plane); }\n\n")
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_a, float p_b) { _FU glUniform2f(get_uniform(p_uniform),p_a,p_b); }\n\n")
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_a, float p_b, float p_c) { _FU glUniform3f(get_uniform(p_uniform),p_a,p_b,p_c); }\n\n")
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_a, float p_b, float p_c, float p_d) { _FU glUniform4f(get_uniform(p_uniform),p_a,p_b,p_c,p_d); }\n\n")
fd.write("""\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Transform& p_transform) { _FU
const Transform &tr = p_transform;
GLfloat matrix[16]={ /* build a 16x16 matrix */
tr.basis.elements[0][0],
tr.basis.elements[1][0],
tr.basis.elements[2][0],
0,
tr.basis.elements[0][1],
tr.basis.elements[1][1],
tr.basis.elements[2][1],
0,
tr.basis.elements[0][2],
tr.basis.elements[1][2],
tr.basis.elements[2][2],
0,
tr.origin.x,
tr.origin.y,
tr.origin.z,
1
};
glUniformMatrix4fv(get_uniform(p_uniform),1,false,matrix);
}
""")
fd.write("""\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Transform2D& p_transform) { _FU
const Transform2D &tr = p_transform;
GLfloat matrix[16]={ /* build a 16x16 matrix */
tr.elements[0][0],
tr.elements[0][1],
0,
0,
tr.elements[1][0],
tr.elements[1][1],
0,
0,
0,
0,
1,
0,
tr.elements[2][0],
tr.elements[2][1],
0,
1
};
glUniformMatrix4fv(get_uniform(p_uniform),1,false,matrix);
}
""")
fd.write("""\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const CameraMatrix& p_matrix) { _FU
GLfloat matrix[16];
for (int i=0;i<4;i++) {
for (int j=0;j<4;j++) {
matrix[i*4+j]=p_matrix.matrix[i][j];
}
}
glUniformMatrix4fv(get_uniform(p_uniform),1,false,matrix);
}; """)
fd.write("\n\n#undef _FU\n\n\n")
fd.write("\tvirtual void init() {\n\n")
if (len(conditionals)):
fd.write("\t\tstatic const char* _conditional_strings[]={\n")
if (len(conditionals)):
for x in conditionals:
fd.write("\t\t\t\"#define " + x + "\\n\",\n")
fd.write("\t\t};\n\n")
else:
fd.write("\t\tstatic const char **_conditional_strings=NULL;\n")
if (len(uniforms)):
fd.write("\t\tstatic const char* _uniform_strings[]={\n")
if (len(uniforms)):
for x in uniforms:
fd.write("\t\t\t\"" + x + "\",\n")
fd.write("\t\t};\n\n")
else:
fd.write("\t\tstatic const char **_uniform_strings=NULL;\n")
if (len(attributes)):
fd.write("\t\tstatic AttributePair _attribute_pairs[]={\n")
for x in attributes:
fd.write("\t\t\t{\"" + x[0] + "\"," + x[1] + "},\n")
fd.write("\t\t};\n\n")
else:
fd.write("\t\tstatic AttributePair *_attribute_pairs=NULL;\n")
if (len(fbos)):
fd.write("\t\tstatic FBOPair _fbo_pairs[]={\n")
for x in fbos:
fd.write("\t\t\t{\"" + x[0] + "\"," + x[1] + "},\n")
fd.write("\t\t};\n\n")
else:
fd.write("\t\tstatic FBOPair *_fbo_pairs=NULL;\n")
if (len(ubos)):
fd.write("\t\tstatic UBOPair _ubo_pairs[]={\n")
for x in ubos:
fd.write("\t\t\t{\"" + x[0] + "\"," + x[1] + "},\n")
fd.write("\t\t};\n\n")
else:
fd.write("\t\tstatic UBOPair *_ubo_pairs=NULL;\n")
if (len(texunits)):
fd.write("\t\tstatic TexUnitPair _texunit_pairs[]={\n")
for x in texunits:
fd.write("\t\t\t{\"" + x[0] + "\"," + x[1] + "},\n")
fd.write("\t\t};\n\n")
else:
fd.write("\t\tstatic TexUnitPair *_texunit_pairs=NULL;\n")
fd.write("\t\tstatic const char* _vertex_code=\"\\\n")
for x in vertex_lines:
fd.write("\t\t\t" + x + "\n")
fd.write("\t\t\";\n\n")
fd.write("\t\tstatic const int _vertex_code_start=" + str(vertex_offset) + ";\n")
fd.write("\t\tstatic const char* _fragment_code=\"\\\n")
for x in fragment_lines:
fd.write("\t\t\t" + x + "\n")
fd.write("\t\t\";\n\n")
fd.write("\t\tstatic const int _fragment_code_start=" + str(fragment_offset) + ";\n")
fd.write("\t\tsetup(_conditional_strings," + str(len(conditionals)) + ",_uniform_strings," + str(len(uniforms)) + ",_attribute_pairs," + str(len(attributes)) + ",_fbo_pairs," + str(len(fbos)) + ",_ubo_pairs," + str(len(ubos)) + ",_texunit_pairs," + str(len(texunits)) + ",_vertex_code,_fragment_code,_vertex_code_start,_fragment_code_start);\n")
fd.write("\t};\n\n")
fd.write("};\n\n")
fd.write("#endif\n\n")
fd.close()
def build_glsl_headers(target, source, env):
for x in source:
build_glsl_header(str(x))
return 0
def build_hlsl_dx9_header(filename):
fs = open(filename, "r")
line = fs.readline()
vertex_lines = []
fragment_lines = []
uniforms = []
fragment_uniforms = []
attributes = []
fbos = []
conditionals = []
reading = ""
line_offset = 0
vertex_offset = 0
fragment_offset = 0
while(line):
if (line.find("[vertex]") != -1):
reading = "vertex"
line = fs.readline()
line_offset += 1
vertex_offset = line_offset
continue
if (line.find("[fragment]") != -1):
reading = "fragment"
line = fs.readline()
line_offset += 1
fragment_offset = line_offset
continue
if (line.find("#ifdef ") != -1):
ifdefline = line.replace("#ifdef ", "").strip()
if (not ifdefline in conditionals):
conditionals += [ifdefline]
if (line.find("#elif defined(") != -1):
ifdefline = line.replace("#elif defined(", "").strip()
ifdefline = ifdefline.replace(")", "").strip()
if (not ifdefline in conditionals):
conditionals += [ifdefline]
if (line.find("uniform") != -1):
uline = line.replace("uniform", "")
uline = uline.replace(";", "")
lines = uline.split(",")
for x in lines:
x = x.strip()
x = x[x.rfind(" ") + 1:]
if (x.find("[") != -1):
# unfiorm array
x = x[:x.find("[")]
if (not x in uniforms):
uniforms += [x]
fragment_uniforms += [reading == "fragment"]
line = line.replace("\r", "")
line = line.replace("\n", "")
line = line.replace("\\", "\\\\")
line = line.replace("\"", "\\\"")
line = line + "\\n\\"
if (reading == "vertex"):
vertex_lines += [line]
if (reading == "fragment"):
fragment_lines += [line]
line = fs.readline()
line_offset += 1
fs.close()
out_file = filename + ".gen.h"
fd = open(out_file, "w")
fd.write("/* WARNING, THIS FILE WAS GENERATED, DO NOT EDIT */\n")
out_file_base = out_file
out_file_base = out_file_base[out_file_base.rfind("/") + 1:]
out_file_base = out_file_base[out_file_base.rfind("\\") + 1:]
# print("out file "+out_file+" base " +out_file_base)
out_file_ifdef = out_file_base.replace(".", "_").upper()
fd.write("#ifndef " + out_file_ifdef + "\n")
fd.write("#define " + out_file_ifdef + "\n")
out_file_class = out_file_base.replace(".hlsl.h", "").title().replace("_", "").replace(".", "") + "ShaderDX9"
fd.write("\n\n")
fd.write("#include \"drivers/directx9/shader_dx9.h\"\n\n\n")
fd.write("class " + out_file_class + " : public ShaderDX9 {\n\n")
fd.write("\t virtual String get_shader_name() const { return \"" + out_file_class + "\"; }\n")
fd.write("public:\n\n")
if (len(conditionals)):
fd.write("\tenum Conditionals {\n")
for x in conditionals:
fd.write("\t\t" + x + ",\n")
fd.write("\t};\n\n")
if (len(uniforms)):
fd.write("\tenum Uniforms {\n")
for x in uniforms:
fd.write("\t\t" + x.upper() + ",\n")
fd.write("\t};\n\n")
if (len(conditionals)):
fd.write("\t_FORCE_INLINE_ void set_conditional(Conditionals p_conditional,bool p_enable) { _set_conditional(p_conditional,p_enable); }\n\n")
fd.write("\t#define _FU if (!_uniform_valid(p_uniform)) return; ERR_FAIL_COND( get_active()!=this );\n\n ")
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, bool p_value) { _FU set_uniformb(p_uniform,p_value); }\n\n")
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_value) { _FU set_uniformf(p_uniform,p_value); }\n\n")
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, double p_value) { _FU set_uniformf(p_uniform,p_value); }\n\n")
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, uint8_t p_value) { _FU set_uniformi(p_uniform,p_value); }\n\n")
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, int8_t p_value) { _FU set_uniformi(p_uniform,p_value); }\n\n")
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, uint16_t p_value) { _FU set_uniformi(p_uniform,p_value); }\n\n")
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, int16_t p_value) { _FU set_uniformi(p_uniform,p_value); }\n\n")
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, uint32_t p_value) { _FU set_uniformi(p_uniform,p_value); }\n\n")
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, int32_t p_value) { _FU set_uniformi(p_uniform,p_value); }\n\n")
#fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, uint64_t p_value) { _FU set_uniformi(p_uniform,p_value); }\n\n");
#fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, int64_t p_value) { _FU set_uniformi(p_uniform,p_value); }\n\n");
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, unsigned long p_value) { _FU set_uniformi(p_uniform,p_value); }\n\n")
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, long p_value) { _FU set_uniformi(p_uniform,p_value); }\n\n")
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Color& p_color) { _FU float col[4]={p_color.r,p_color.g,p_color.b,p_color.a}; set_uniformfv(p_uniform,col); }\n\n")
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Vector2& p_vec2) { _FU float vec2[4]={p_vec2.x,p_vec2.y,0,0}; set_uniformfv(p_uniform,vec2); }\n\n")
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Vector3& p_vec3) { _FU float vec3[4]={p_vec3.x,p_vec3.y,p_vec3.z,0}; set_uniformfv(p_uniform,vec3); }\n\n")
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_a, float p_b) { _FU float vec2[4]={p_a,p_b,0,0}; set_uniformfv(p_uniform,vec2); }\n\n")
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_a, float p_b, float p_c) { _FU float vec3[4]={p_a,p_b,p_c,0}; set_uniformfv(p_uniform,vec3); }\n\n")
fd.write("\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_a, float p_b, float p_c, float p_d) { _FU float vec4[4]={p_a,p_b,p_c,p_d}; set_uniformfv(p_uniform,vec4); }\n\n")
fd.write("""\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Transform& p_transform) { _FU
const Transform &tr = p_transform;
float matrix[16]={ /* build a 16x16 matrix */
tr.basis.elements[0][0],
tr.basis.elements[0][1],
tr.basis.elements[0][2],
tr.origin.x,
tr.basis.elements[1][0],
tr.basis.elements[1][1],
tr.basis.elements[1][2],
tr.origin.y,
tr.basis.elements[2][0],
tr.basis.elements[2][1],
tr.basis.elements[2][2],
tr.origin.z,
0,
0,
0,
1
};
set_uniformfv(p_uniform,&matrix[0],4);
}
""")
fd.write("""\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const CameraMatrix& p_matrix) { _FU
float matrix[16];
for (int i=0;i<4;i++) {
for (int j=0;j<4;j++) {
matrix[i*4+j]=p_matrix.matrix[j][i];
}
}
set_uniformfv(p_uniform,&matrix[0],4);
}; """)
fd.write("\n\n#undef _FU\n\n\n")
fd.write("\tvirtual void init(IDirect3DDevice9 *p_device,ShaderSupport p_version) {\n\n")
if (len(conditionals)):
fd.write("\t\tstatic const char* _conditional_strings[]={\n")
if (len(conditionals)):
for x in conditionals:
fd.write("\t\t\t\"" + x + "\",\n")
fd.write("\t\t};\n\n")
else:
fd.write("\t\tstatic const char **_conditional_strings=NULL;\n")
if (len(uniforms)):
fd.write("\t\tstatic const char* _uniform_strings[]={\n")
if (len(uniforms)):
for x in uniforms:
fd.write("\t\t\t\"" + x + "\",\n")
fd.write("\t\t};\n\n")
fd.write("\t\tstatic const bool _fragment_uniforms[]={\n")
if (len(uniforms)):
for x in fragment_uniforms:
if (x):
fd.write("\t\t\ttrue,\n")
else:
fd.write("\t\t\tfalse,\n")
fd.write("\t\t};\n\n")
else:
fd.write("\t\tstatic const char **_uniform_strings=NULL;\n")
fd.write("\t\tstatic const bool *_fragment_uniforms=NULL;\n")
fd.write("\t\tstatic const char* _vertex_code=\"\\\n")
for x in vertex_lines:
fd.write("\t\t\t" + x + "\n")
fd.write("\t\t\";\n\n")
fd.write("\t\tstatic const int _vertex_code_start=" + str(vertex_offset) + ";\n")
fd.write("\t\tstatic const char* _fragment_code=\"\\\n")
for x in fragment_lines:
fd.write("\t\t\t" + x + "\n")
fd.write("\t\t\";\n\n")
fd.write("\t\tstatic const int _fragment_code_start=" + str(fragment_offset) + ";\n")
fd.write("\t\tsetup(p_device,p_version,_conditional_strings," + str(len(conditionals)) + ",_uniform_strings," + str(len(uniforms)) + ",_fragment_uniforms,_vertex_code,_fragment_code,_vertex_code_start,_fragment_code_start);\n")
fd.write("\t};\n\n")
fd.write("};\n\n")
fd.write("#endif\n\n")
fd.close()
def build_hlsl_dx9_headers(target, source, env):
for x in source:
build_hlsl_dx9_header(str(x))
return 0
class LegacyGLHeaderStruct:
@ -840,7 +209,7 @@ def include_file_in_legacygl_header(filename, header_data, depth):
return header_data
def build_legacygl_header(filename, include, class_suffix, output_attribs):
def build_legacygl_header(filename, include, class_suffix, output_attribs, gles2=False):
header_data = LegacyGLHeaderStruct()
include_file_in_legacygl_header(filename, header_data, 0)
@ -928,14 +297,14 @@ def build_legacygl_header(filename, include, class_suffix, output_attribs):
};
glUniformMatrix4fv(get_uniform(p_uniform),1,false,matrix);
glUniformMatrix4fv(get_uniform(p_uniform),1,false,matrix);
}
""")
fd.write("""\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Transform2D& p_transform) { _FU
fd.write("""_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Transform2D& p_transform) { _FU
const Transform2D &tr = p_transform;
@ -959,14 +328,14 @@ def build_legacygl_header(filename, include, class_suffix, output_attribs):
};
glUniformMatrix4fv(get_uniform(p_uniform),1,false,matrix);
glUniformMatrix4fv(get_uniform(p_uniform),1,false,matrix);
}
""")
fd.write("""\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const CameraMatrix& p_matrix) { _FU
fd.write("""_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const CameraMatrix& p_matrix) { _FU
GLfloat matrix[16];
@ -978,7 +347,7 @@ def build_legacygl_header(filename, include, class_suffix, output_attribs):
}
glUniformMatrix4fv(get_uniform(p_uniform),1,false,matrix);
}; """)
} """)
fd.write("\n\n#undef _FU\n\n\n")
@ -1061,7 +430,7 @@ def build_legacygl_header(filename, include, class_suffix, output_attribs):
feedback_count = 0
if (len(header_data.feedbacks)):
if (not gles2 and len(header_data.feedbacks)):
fd.write("\t\tstatic const Feedback _feedbacks[]={\n")
for x in header_data.feedbacks:
@ -1076,7 +445,10 @@ def build_legacygl_header(filename, include, class_suffix, output_attribs):
fd.write("\t\t};\n\n")
else:
fd.write("\t\tstatic const Feedback* _feedbacks=NULL;\n")
if gles2:
pass
else:
fd.write("\t\tstatic const Feedback* _feedbacks=NULL;\n")
if (len(header_data.texunits)):
fd.write("\t\tstatic TexUnitPair _texunit_pairs[]={\n")
@ -1086,13 +458,16 @@ def build_legacygl_header(filename, include, class_suffix, output_attribs):
else:
fd.write("\t\tstatic TexUnitPair *_texunit_pairs=NULL;\n")
if (len(header_data.ubos)):
if (not gles2 and len(header_data.ubos)):
fd.write("\t\tstatic UBOPair _ubo_pairs[]={\n")
for x in header_data.ubos:
fd.write("\t\t\t{\"" + x[0] + "\"," + x[1] + "},\n")
fd.write("\t\t};\n\n")
else:
fd.write("\t\tstatic UBOPair *_ubo_pairs=NULL;\n")
if gles2:
pass
else:
fd.write("\t\tstatic UBOPair *_ubo_pairs=NULL;\n")
fd.write("\t\tstatic const char _vertex_code[]={\n")
for x in header_data.vertex_lines:
@ -1115,11 +490,17 @@ def build_legacygl_header(filename, include, class_suffix, output_attribs):
fd.write("\t\tstatic const int _fragment_code_start=" + str(header_data.fragment_offset) + ";\n")
if output_attribs:
fd.write("\t\tsetup(_conditional_strings," + str(len(header_data.conditionals)) + ",_uniform_strings," + str(len(header_data.uniforms)) + ",_attribute_pairs," + str(len(header_data.attributes)) + ", _texunit_pairs," + str(len(header_data.texunits)) + ",_ubo_pairs," + str(len(header_data.ubos)) + ",_feedbacks," + str(feedback_count) + ",_vertex_code,_fragment_code,_vertex_code_start,_fragment_code_start);\n")
if gles2:
fd.write("\t\tsetup(_conditional_strings," + str(len(header_data.conditionals)) + ",_uniform_strings," + str(len(header_data.uniforms)) + ",_attribute_pairs," + str(len(header_data.attributes)) + ", _texunit_pairs," + str(len(header_data.texunits)) + ",_vertex_code,_fragment_code,_vertex_code_start,_fragment_code_start);\n")
else:
fd.write("\t\tsetup(_conditional_strings," + str(len(header_data.conditionals)) + ",_uniform_strings," + str(len(header_data.uniforms)) + ",_attribute_pairs," + str(len(header_data.attributes)) + ", _texunit_pairs," + str(len(header_data.texunits)) + ",_ubo_pairs," + str(len(header_data.ubos)) + ",_feedbacks," + str(feedback_count) + ",_vertex_code,_fragment_code,_vertex_code_start,_fragment_code_start);\n")
else:
fd.write("\t\tsetup(_conditional_strings," + str(len(header_data.conditionals)) + ",_uniform_strings," + str(len(header_data.uniforms)) + ",_texunit_pairs," + str(len(header_data.texunits)) + ",_enums," + str(len(header_data.enums)) + ",_enum_values," + str(enum_value_count) + ",_ubo_pairs," + str(len(header_data.ubos)) + ",_feedbacks," + str(feedback_count) + ",_vertex_code,_fragment_code,_vertex_code_start,_fragment_code_start);\n")
if gles2:
fd.write("\t\tsetup(_conditional_strings," + str(len(header_data.conditionals)) + ",_uniform_strings," + str(len(header_data.uniforms)) + ",_texunit_pairs," + str(len(header_data.texunits)) + ",_enums," + str(len(header_data.enums)) + ",_enum_values," + str(enum_value_count) + ",_vertex_code,_fragment_code,_vertex_code_start,_fragment_code_start);\n")
else:
fd.write("\t\tsetup(_conditional_strings," + str(len(header_data.conditionals)) + ",_uniform_strings," + str(len(header_data.uniforms)) + ",_texunit_pairs," + str(len(header_data.texunits)) + ",_enums," + str(len(header_data.enums)) + ",_enum_values," + str(enum_value_count) + ",_ubo_pairs," + str(len(header_data.ubos)) + ",_feedbacks," + str(feedback_count) + ",_vertex_code,_fragment_code,_vertex_code_start,_fragment_code_start);\n")
fd.write("\t};\n\n")
fd.write("\t}\n\n")
if (len(enum_constants)):
@ -1134,21 +515,17 @@ def build_legacygl_header(filename, include, class_suffix, output_attribs):
fd.close()
def build_legacygl_headers(target, source, env):
for x in source:
build_legacygl_header(str(x), include="drivers/legacygl/shader_lgl.h", class_suffix="LGL", output_attribs=False)
return 0
def build_gles3_headers(target, source, env):
for x in source:
build_legacygl_header(str(x), include="drivers/gles3/shader_gles3.h", class_suffix="GLES3", output_attribs=True)
def build_gles2_headers(target, source, env):
for x in source:
build_legacygl_header(str(x), include="drivers/gles2/shader_gles2.h", class_suffix="GLES2", output_attribs=True, gles2=True)
def add_module_version_string(self,s):
self.module_version_string += "." + s
@ -1220,45 +597,6 @@ def parse_cg_file(fname, uniforms, sizes, conditionals):
line = fs.readline()
def build_cg_shader(sname):
vp_uniforms = []
vp_uniform_sizes = []
vp_conditionals = []
parse_cg_file("vp_" + sname + ".cg", vp_uniforms, vp_uniform_sizes, vp_conditionals)
fp_uniforms = []
fp_uniform_sizes = []
fp_conditionals = []
parse_cg_file("fp_" + sname + ".cg", fp_uniforms, fp_uniform_sizes, fp_conditionals)
fd = open("shader_" + sname + ".cg.gen.h", "w")
fd.write('\n#include "shader_cell.h"\n')
fd.write("\nclass Shader_" + sname + " : public ShaderCell {\n")
fd.write("\n\tstatic struct VertexUniforms[] = {\n")
offset = 0
for i in range(0, len(vp_uniforms)):
fd.write('\t\t{ "%s", %d, %d },\n' % (vp_uniforms[i], offset, vp_uniform_sizes[i]))
offset = offset + vp_uniform_sizes[i]
fd.write("\t};\n\n")
fd.write("public:\n\n")
fd.write("\tenum {\n")
for i in range(0, len(vp_uniforms)):
fd.write('\t\tVP_%s,\n' % vp_uniforms[i].upper())
fd.write("\t};\n")
import glob

View file

@ -1,6 +1,6 @@
def can_build(platform):
# should probably change this to only be true on iOS and Android
return True
return False
def configure(env):
pass

View file

@ -31,4 +31,5 @@
#include <alloca.h>
#define GLES3_INCLUDE_H "glad/glad.h"
#define GLES2_INCLUDE_H "glad/glad.h"
#define PTHREAD_RENAME_SELF

View file

@ -33,3 +33,4 @@
//#include <alloca.h>
//#endif
#define GLES3_INCLUDE_H "glad/glad.h"
#define GLES2_INCLUDE_H "glad/glad.h"

View file

@ -146,20 +146,38 @@ Error ContextGL_X11::initialize() {
int (*oldHandler)(Display *, XErrorEvent *) =
XSetErrorHandler(&ctxErrorHandler);
if (!opengl_3_context) {
//oldstyle context:
p->glx_context = glXCreateContext(x11_display, vi, 0, GL_TRUE);
} else {
static int context_attribs[] = {
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
GLX_CONTEXT_MINOR_VERSION_ARB, 3,
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB /*|GLX_CONTEXT_DEBUG_BIT_ARB*/,
None
};
switch (context_type) {
case GLES_2_0_COMPATIBLE:
case OLDSTYLE: {
p->glx_context = glXCreateContext(x11_display, vi, 0, GL_TRUE);
} break;
/*
case ContextType::GLES_2_0_COMPATIBLE: {
p->glx_context = glXCreateContextAttribsARB(x11_display, fbc[0], NULL, true, context_attribs);
ERR_EXPLAIN("Could not obtain an OpenGL 3.3 context!");
ERR_FAIL_COND_V(ctxErrorOccurred || !p->glx_context, ERR_UNCONFIGURED);
static int context_attribs[] = {
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
GLX_CONTEXT_MINOR_VERSION_ARB, 0,
None
};
p->glx_context = glXCreateContextAttribsARB(x11_display, fbc[0], NULL, true, context_attribs);
ERR_EXPLAIN("Could not obtain an OpenGL 3.0 context!");
ERR_FAIL_COND_V(!p->glx_context, ERR_UNCONFIGURED);
} break;
*/
case GLES_3_0_COMPATIBLE: {
static int context_attribs[] = {
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
GLX_CONTEXT_MINOR_VERSION_ARB, 3,
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB /*|GLX_CONTEXT_DEBUG_BIT_ARB*/,
None
};
p->glx_context = glXCreateContextAttribsARB(x11_display, fbc[0], NULL, true, context_attribs);
ERR_EXPLAIN("Could not obtain an OpenGL 3.3 context!");
ERR_FAIL_COND_V(ctxErrorOccurred || !p->glx_context, ERR_UNCONFIGURED);
} break;
}
XSync(x11_display, False);
@ -229,13 +247,13 @@ bool ContextGL_X11::is_using_vsync() const {
return use_vsync;
}
ContextGL_X11::ContextGL_X11(::Display *p_x11_display, ::Window &p_x11_window, const OS::VideoMode &p_default_video_mode, bool p_opengl_3_context) :
ContextGL_X11::ContextGL_X11(::Display *p_x11_display, ::Window &p_x11_window, const OS::VideoMode &p_default_video_mode, ContextType p_context_type) :
x11_window(p_x11_window) {
default_video_mode = p_default_video_mode;
x11_display = p_x11_display;
opengl_3_context = p_opengl_3_context;
context_type = p_context_type;
double_buffer = false;
direct_render = false;

View file

@ -46,6 +46,14 @@ struct ContextGL_X11_Private;
class ContextGL_X11 : public ContextGL {
public:
enum ContextType {
OLDSTYLE,
GLES_2_0_COMPATIBLE,
GLES_3_0_COMPATIBLE
};
private:
ContextGL_X11_Private *p;
OS::VideoMode default_video_mode;
//::Colormap x11_colormap;
@ -54,8 +62,8 @@ class ContextGL_X11 : public ContextGL {
bool double_buffer;
bool direct_render;
int glx_minor, glx_major;
bool opengl_3_context;
bool use_vsync;
ContextType context_type;
public:
virtual void release_current();
@ -69,7 +77,7 @@ public:
virtual void set_use_vsync(bool p_use);
virtual bool is_using_vsync() const;
ContextGL_X11(::Display *p_x11_display, ::Window &p_x11_window, const OS::VideoMode &p_default_video_mode, bool p_opengl_3_context);
ContextGL_X11(::Display *p_x11_display, ::Window &p_x11_window, const OS::VideoMode &p_default_video_mode, ContextType p_context_type);
~ContextGL_X11();
};

View file

@ -29,6 +29,7 @@
/*************************************************************************/
#include "os_x11.h"
#include "drivers/gles2/rasterizer_gles2.h"
#include "drivers/gles3/rasterizer_gles3.h"
#include "errno.h"
#include "key_mapping_x11.h"
@ -81,6 +82,11 @@ int OS_X11::get_video_driver_count() const {
}
const char *OS_X11::get_video_driver_name(int p_driver) const {
String driver_name = GLOBAL_GET("rendering/quality/driver/driver_name");
if (driver_name == "GLES2") {
return "GLES2";
}
return "GLES3";
}
@ -283,12 +289,29 @@ Error OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
//print_line("def videomode "+itos(current_videomode.width)+","+itos(current_videomode.height));
#if defined(OPENGL_ENABLED)
context_gl = memnew(ContextGL_X11(x11_display, x11_window, current_videomode, true));
String setting_name = "rendering/quality/driver/driver_name";
ProjectSettings::get_singleton()->set_custom_property_info(setting_name, PropertyInfo(Variant::STRING, setting_name, PROPERTY_HINT_ENUM, "GLES3,GLES2"));
String video_driver_name = GLOBAL_DEF("rendering/quality/driver/driver_name", "GLES3");
ContextGL_X11::ContextType opengl_api_type = ContextGL_X11::GLES_3_0_COMPATIBLE;
if (video_driver_name == "GLES2") {
opengl_api_type = ContextGL_X11::GLES_2_0_COMPATIBLE;
}
context_gl = memnew(ContextGL_X11(x11_display, x11_window, current_videomode, opengl_api_type));
context_gl->initialize();
RasterizerGLES3::register_config();
RasterizerGLES3::make_current();
switch (opengl_api_type) {
case ContextGL_X11::GLES_2_0_COMPATIBLE: {
RasterizerGLES2::register_config();
RasterizerGLES2::make_current();
} break;
case ContextGL_X11::GLES_3_0_COMPATIBLE: {
RasterizerGLES3::register_config();
RasterizerGLES3::make_current();
} break;
}
context_gl->set_use_vsync(current_videomode.use_vsync);

View file

@ -37,3 +37,4 @@
#endif
#define GLES3_INCLUDE_H "glad/glad.h"
#define GLES2_INCLUDE_H "glad/glad.h"