From bb20f230ad307a2a5f18c03bece3793d29ae208a Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Sun, 28 May 2017 21:46:48 -0300 Subject: [PATCH] -Added .hdr format support -Added default environment editor setting -Added environment created by default in new projects -Removed default light and ambient from spatial editor, to make the editor more PBR compliant --- core/color.h | 34 ++ core/image.cpp | 30 +- core/os/file_access.cpp | 21 ++ core/os/file_access.h | 1 + core/variant_parser.cpp | 159 +++++++- editor/editor_node.cpp | 32 +- editor/editor_node.h | 1 + editor/plugins/color_ramp_editor_plugin.cpp | 4 +- editor/plugins/color_ramp_editor_plugin.h | 2 +- editor/plugins/spatial_editor_plugin.cpp | 151 -------- editor/plugins/spatial_editor_plugin.h | 20 - editor/project_manager.cpp | 15 +- main/tests/test_math.cpp | 53 +++ modules/hdr/SCsub | 9 + modules/hdr/config.py | 7 + modules/hdr/image_loader_hdr.cpp | 151 ++++++++ modules/hdr/image_loader_hdr.h | 46 +++ modules/hdr/register_types.cpp | 45 +++ modules/hdr/register_types.h | 31 ++ scene/2d/line_2d.cpp | 4 +- scene/2d/line_2d.h | 6 +- scene/2d/line_builder.h | 2 +- scene/2d/particles_2d.cpp | 6 +- scene/2d/particles_2d.h | 6 +- scene/gui/color_ramp_edit.cpp | 18 +- scene/gui/color_ramp_edit.h | 6 +- scene/main/scene_main_loop.cpp | 60 ++- scene/register_scene_types.cpp | 3 +- scene/resources/color_ramp.cpp | 56 +-- scene/resources/color_ramp.h | 10 +- scene/resources/sky_box.cpp | 391 ++++++++++++++++++++ scene/resources/sky_box.h | 112 +++++- scene/resources/world.cpp | 17 + scene/resources/world.h | 5 + 34 files changed, 1222 insertions(+), 292 deletions(-) create mode 100644 modules/hdr/SCsub create mode 100644 modules/hdr/config.py create mode 100644 modules/hdr/image_loader_hdr.cpp create mode 100644 modules/hdr/image_loader_hdr.h create mode 100644 modules/hdr/register_types.cpp create mode 100644 modules/hdr/register_types.h diff --git a/core/color.h b/core/color.h index 46386fac64d..c83dcda4b43 100644 --- a/core/color.h +++ b/core/color.h @@ -83,6 +83,40 @@ struct Color { return res; } + _FORCE_INLINE_ uint32_t to_rgbe9995() const { + + const float pow2to9 = 512.0f; + const float B = 15.0f; + //const float Emax = 31.0f; + const float N = 9.0f; + + float sharedexp = 65408.000f; //(( pow2to9 - 1.0f)/ pow2to9)*powf( 2.0f, 31.0f - 15.0f); + + float cRed = MAX(0.0f, MIN(sharedexp, r)); + float cGreen = MAX(0.0f, MIN(sharedexp, g)); + float cBlue = MAX(0.0f, MIN(sharedexp, b)); + + float cMax = MAX(cRed, MAX(cGreen, cBlue)); + + // expp = MAX(-B - 1, log2(maxc)) + 1 + B + + float expp = MAX(-B - 1.0f, floor(Math::log(cMax) / Math_LN2)) + 1.0f + B; + + float sMax = (float)floor((cMax / Math::pow(2.0f, expp - B - N)) + 0.5f); + + float exps = expp + 1.0f; + + if (0.0 <= sMax && sMax < pow2to9) { + exps = expp; + } + + float sRed = Math::floor((cRed / pow(2.0f, exps - B - N)) + 0.5f); + float sGreen = Math::floor((cGreen / pow(2.0f, exps - B - N)) + 0.5f); + float sBlue = Math::floor((cBlue / pow(2.0f, exps - B - N)) + 0.5f); + + return (uint32_t(Math::fast_ftoi(sRed)) & 0x1FF) | ((uint32_t(Math::fast_ftoi(sGreen)) & 0x1FF) << 9) | ((uint32_t(Math::fast_ftoi(sBlue)) & 0x1FF) << 18) | ((uint32_t(Math::fast_ftoi(exps)) & 0x1F) << 27); + } + _FORCE_INLINE_ Color blend(const Color &p_over) const { Color res; diff --git a/core/image.cpp b/core/image.cpp index 2496fd136c3..deff2a81cac 100644 --- a/core/image.cpp +++ b/core/image.cpp @@ -1981,35 +1981,7 @@ void Image::put_pixel(int p_x, int p_y, const Color &p_color) { } break; case FORMAT_RGBE9995: { - const float pow2to9 = 512.0f; - const float B = 7.0f; - //const float Emax = 31.0f; - const float N = 9.0f; - - float sharedexp = 65408.000f; //(( pow2to9 - 1.0f)/ pow2to9)*powf( 2.0f, 31.0f - 15.0f); - - float cRed = MAX(0.0f, MIN(sharedexp, p_color.r)); - float cGreen = MAX(0.0f, MIN(sharedexp, p_color.g)); - float cBlue = MAX(0.0f, MIN(sharedexp, p_color.b)); - - float cMax = MAX(cRed, MAX(cGreen, cBlue)); - - // expp = MAX(-B - 1, log2(maxc)) + 1 + B - float expp = MAX(-B - 1.0f, floor(Math::log(cMax) / Math::log(2.0))) + 1.0f + B; - - float sMax = (float)floor((cMax / Math::pow(2.0f, expp - B - N)) + 0.5f); - - float exps = expp + 1.0f; - - if (0.0 <= sMax && sMax < pow2to9) { - exps = expp; - } - - float sRed = (cRed / pow(2.0f, exps - B - N)) + 0.5f; - float sGreen = (cGreen / pow(2.0f, exps - B - N)) + 0.5f; - float sBlue = (cBlue / pow(2.0f, exps - B - N)) + 0.5f; - - ((uint32_t *)ptr)[ofs] = ((uint32_t)(sRed)&0x1FF) | (((uint32_t)(sGreen)&0x1FF) << 9) | (((uint32_t)(sBlue)&0x1FF) << 18) | (((uint32_t)(exps)&0x1F) << 27); + ((uint32_t *)ptr)[ofs] = p_color.to_rgbe9995(); } break; default: { diff --git a/core/os/file_access.cpp b/core/os/file_access.cpp index 375121c0ccd..805b66b9831 100644 --- a/core/os/file_access.cpp +++ b/core/os/file_access.cpp @@ -252,6 +252,27 @@ double FileAccess::get_double() const { return m.d; }; +String FileAccess::get_token() const { + + CharString token; + + CharType c = get_8(); + + while (!eof_reached()) { + + if (c <= ' ') { + if (!token.empty()) + break; + } else { + token.push_back(c); + } + c = get_8(); + } + + token.push_back(0); + return String::utf8(token.get_data()); +} + String FileAccess::get_line() const { CharString line; diff --git a/core/os/file_access.h b/core/os/file_access.h index da15ddc544a..6d3e4911671 100644 --- a/core/os/file_access.h +++ b/core/os/file_access.h @@ -106,6 +106,7 @@ public: virtual int get_buffer(uint8_t *p_dst, int p_length) const; ///< get an array of bytes virtual String get_line() const; + virtual String get_token() const; virtual Vector get_csv_line(String delim = ",") const; /**< use this for files WRITTEN in _big_ endian machines (ie, amiga/mac) diff --git a/core/variant_parser.cpp b/core/variant_parser.cpp index 0d4d0429e71..55e2bb42e3c 100644 --- a/core/variant_parser.cpp +++ b/core/variant_parser.cpp @@ -694,6 +694,106 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, return ERR_PARSE_ERROR; } + return OK; + } else if (id == "Object") { + + get_token(p_stream, token, line, r_err_str); + if (token.type != TK_PARENTHESIS_OPEN) { + r_err_str = "Expected '('"; + return ERR_PARSE_ERROR; + } + + get_token(p_stream, token, line, r_err_str); + + if (token.type != TK_IDENTIFIER) { + r_err_str = "Expected identifier with type of object"; + return ERR_PARSE_ERROR; + } + + String type = token.value; + + Object *obj = ClassDB::instance(type); + + if (!obj) { + r_err_str = "Can't instance Object() of type: " + type; + return ERR_PARSE_ERROR; + } + + get_token(p_stream, token, line, r_err_str); + if (token.type != TK_COMMA) { + r_err_str = "Expected ',' after object type"; + return ERR_PARSE_ERROR; + } + + bool at_key = true; + String key; + Token token; + bool need_comma = false; + + while (true) { + + if (p_stream->is_eof()) { + r_err_str = "Unexpected End of File while parsing Object()"; + return ERR_FILE_CORRUPT; + } + + if (at_key) { + + Error err = get_token(p_stream, token, line, r_err_str); + if (err != OK) + return err; + + if (token.type == TK_PARENTHESIS_CLOSE) { + + return OK; + } + + if (need_comma) { + + if (token.type != TK_COMMA) { + + r_err_str = "Expected '}' or ','"; + return ERR_PARSE_ERROR; + } else { + need_comma = false; + continue; + } + } + + get_token(p_stream, token, line, r_err_str); + if (token.type != TK_STRING) { + r_err_str = "Expected property name as string"; + return ERR_PARSE_ERROR; + } + + key = token.value; + + err = get_token(p_stream, token, line, r_err_str); + + if (err != OK) + return err; + if (token.type != TK_COLON) { + + r_err_str = "Expected ':'"; + return ERR_PARSE_ERROR; + } + at_key = false; + } else { + + Error err = get_token(p_stream, token, line, r_err_str); + if (err != OK) + return err; + + Variant v; + err = parse_value(token, v, p_stream, line, r_err_str, p_res_parser); + if (err) + return err; + obj->set(key, v); + need_comma = true; + at_key = true; + } + } + return OK; } else if (id == "Resource" || id == "SubResource" || id == "ExtResource") { @@ -1611,30 +1711,63 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str case Variant::OBJECT: { - RES res = p_variant; - if (res.is_null()) { + Object *obj = p_variant; + + if (!obj) { p_store_string_func(p_store_string_ud, "null"); break; // don't save it } - String res_text; + RES res = p_variant; + if (res.is_valid()) { + //is resource + String res_text; - if (p_encode_res_func) { + //try external function + if (p_encode_res_func) { - res_text = p_encode_res_func(p_encode_res_ud, res); + res_text = p_encode_res_func(p_encode_res_ud, res); + } + + //try path because it's a file + if (res_text == String() && res->get_path().is_resource_file()) { + + //external resource + String path = res->get_path(); + res_text = "Resource( \"" + path + "\")"; + } + + //could come up with some sort of text + if (res_text != String()) { + p_store_string_func(p_store_string_ud, res_text); + break; + } } - if (res_text == String() && res->get_path().is_resource_file()) { + //store as generic object - //external resource - String path = res->get_path(); - res_text = "Resource( \"" + path + "\")"; + p_store_string_func(p_store_string_ud, "Object(" + obj->get_class() + ","); + + List props; + obj->get_property_list(&props); + bool first = true; + for (List::Element *E = props.front(); E; E = E->next()) { + + if (E->get().usage & PROPERTY_USAGE_STORAGE || E->get().usage & PROPERTY_USAGE_SCRIPT_VARIABLE) { + //must be serialized + + if (first) { + first = false; + } else { + p_store_string_func(p_store_string_ud, ","); + } + + p_store_string_func(p_store_string_ud, "\"" + E->get().name + "\":"); + write(obj->get(E->get().name), p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud); + } } - if (res_text == String()) - res_text = "null"; - - p_store_string_func(p_store_string_ud, res_text); + p_store_string_func(p_store_string_ud, ")\n"); } break; diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index f00ad97ee84..245b350790c 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -889,6 +889,7 @@ void EditorNode::_save_scene(String p_file, int idx) { } editor_data.apply_changes_in_editors(); + _save_default_environment(); _set_scene_metadata(p_file, idx); @@ -950,7 +951,7 @@ void EditorNode::_save_scene(String p_file, int idx) { _dialog_display_file_error(p_file, err); } -}; +} void EditorNode::_import_action(const String &p_action) { #if 0 @@ -1113,6 +1114,7 @@ void EditorNode::_dialog_action(String p_file) { if (file->get_mode() == EditorFileDialog::MODE_SAVE_FILE) { //_save_scene(p_file); + _save_default_environment(); _save_scene_with_preview(p_file); } @@ -1122,6 +1124,7 @@ void EditorNode::_dialog_action(String p_file) { if (file->get_mode() == EditorFileDialog::MODE_SAVE_FILE) { //_save_scene(p_file); + _save_default_environment(); _save_scene_with_preview(p_file); _call_build(); _run(true); @@ -1375,6 +1378,17 @@ void EditorNode::_property_editor_back() { _edit_current(); } +void EditorNode::_save_default_environment() { + + Ref fallback = get_scene_root()->get_world()->get_fallback_environment(); + + if (fallback.is_valid() && fallback->get_path().is_resource_file()) { + Map processed; + _find_and_save_edited_subresources(fallback.ptr(), processed, 0); + save_resource_in_path(fallback, fallback->get_path()); + } +} + void EditorNode::_imported(Node *p_node) { /* @@ -1453,11 +1467,16 @@ void EditorNode::_edit_current() { Node *current_node = current_obj->cast_to(); ERR_FAIL_COND(!current_node); - ERR_FAIL_COND(!current_node->is_inside_tree()); + // ERR_FAIL_COND(!current_node->is_inside_tree()); property_editor->edit(current_node); - node_dock->set_node(current_node); - scene_tree_dock->set_selected(current_node); + if (current_node->is_inside_tree()) { + node_dock->set_node(current_node); + scene_tree_dock->set_selected(current_node); + } else { + node_dock->set_node(NULL); + scene_tree_dock->set_selected(NULL); + } object_menu->get_popup()->clear(); //top_pallete->set_current_tab(0); @@ -1951,6 +1970,8 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { } } // else: ignore new scenes } + + _save_default_environment(); } break; case FILE_SAVE_BEFORE_RUN: { if (!p_confirmed) { @@ -2384,6 +2405,8 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { } break; case RUN_PLAY_SCENE: { + + _save_default_environment(); _menu_option_confirm(RUN_STOP, true); _call_build(); _run(true); @@ -5237,6 +5260,7 @@ EditorNode::EditorNode() { p->add_separator(); p->add_item(TTR("Project Settings"), RUN_SETTINGS); p->add_separator(); + #ifdef OSX_ENABLED p->add_item(TTR("Quit to Project List"), RUN_PROJECT_MANAGER, KEY_MASK_SHIFT + KEY_MASK_ALT + KEY_Q); #else diff --git a/editor/editor_node.h b/editor/editor_node.h index 55b3aa94d34..bb5b57a4547 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -593,6 +593,7 @@ private: static int plugin_init_callback_count; static EditorPluginInitializeCallback plugin_init_callbacks[MAX_INIT_CALLBACKS]; + void _save_default_environment(); void _call_build(); static int build_callback_count; diff --git a/editor/plugins/color_ramp_editor_plugin.cpp b/editor/plugins/color_ramp_editor_plugin.cpp index 63369e5475e..e4172db415b 100644 --- a/editor/plugins/color_ramp_editor_plugin.cpp +++ b/editor/plugins/color_ramp_editor_plugin.cpp @@ -46,10 +46,10 @@ ColorRampEditorPlugin::ColorRampEditorPlugin(EditorNode *p_node) { void ColorRampEditorPlugin::edit(Object *p_object) { - ColorRamp *color_ramp = p_object->cast_to(); + Gradient *color_ramp = p_object->cast_to(); if (!color_ramp) return; - color_ramp_ref = Ref(color_ramp); + color_ramp_ref = Ref(color_ramp); ramp_editor->set_points(color_ramp_ref->get_points()); } diff --git a/editor/plugins/color_ramp_editor_plugin.h b/editor/plugins/color_ramp_editor_plugin.h index 73b15b85a10..35446062b55 100644 --- a/editor/plugins/color_ramp_editor_plugin.h +++ b/editor/plugins/color_ramp_editor_plugin.h @@ -39,7 +39,7 @@ class ColorRampEditorPlugin : public EditorPlugin { GDCLASS(ColorRampEditorPlugin, EditorPlugin); bool _2d; - Ref color_ramp_ref; + Ref color_ramp_ref; ColorRampEdit *ramp_editor; EditorNode *editor; diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index c4595b477e3..ff4b5e430e2 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -2493,17 +2493,11 @@ Dictionary SpatialEditor::get_state() const { d["viewports"] = vpdata; - d["default_light"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_DEFAULT_LIGHT)); - d["ambient_light_color"] = settings_ambient_color->get_pick_color(); - - d["default_srgb"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_DEFAULT_SRGB)); d["show_grid"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_GRID)); d["show_origin"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_ORIGIN)); d["fov"] = get_fov(); d["znear"] = get_znear(); d["zfar"] = get_zfar(); - d["deflight_rot_x"] = settings_default_light_rot_x; - d["deflight_rot_y"] = settings_default_light_rot_y; return d; } @@ -2565,26 +2559,6 @@ void SpatialEditor::set_state(const Dictionary &p_state) { if (d.has("fov")) settings_fov->set_value(float(d["fov"])); - if (d.has("default_light")) { - bool use = d["default_light"]; - - bool existing = light_instance.is_valid(); - if (use != existing) { - if (existing) { - VisualServer::get_singleton()->free(light_instance); - light_instance = RID(); - } else { - light_instance = VisualServer::get_singleton()->instance_create2(light, get_tree()->get_root()->get_world()->get_scenario()); - VisualServer::get_singleton()->instance_set_transform(light_instance, light_transform); - } - view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_DEFAULT_LIGHT), light_instance.is_valid()); - } - } - if (d.has("ambient_light_color")) { - settings_ambient_color->set_pick_color(d["ambient_light_color"]); - //viewport_environment->fx_set_param(Environment::FX_PARAM_AMBIENT_LIGHT_COLOR,d["ambient_light_color"]); - } - if (d.has("default_srgb")) { bool use = d["default_srgb"]; @@ -2607,13 +2581,6 @@ void SpatialEditor::set_state(const Dictionary &p_state) { VisualServer::get_singleton()->instance_set_visible(origin_instance, use); } } - - if (d.has("deflight_rot_x")) - settings_default_light_rot_x = d["deflight_rot_x"]; - if (d.has("deflight_rot_y")) - settings_default_light_rot_y = d["deflight_rot_y"]; - - _update_default_light_angle(); } void SpatialEditor::edit(Spatial *p_spatial) { @@ -2749,38 +2716,6 @@ void SpatialEditor::_menu_item_pressed(int p_option) { xform_dialog->popup_centered(Size2(200, 200)); - } break; - case MENU_VIEW_USE_DEFAULT_LIGHT: { - - bool is_checked = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(p_option)); - - if (is_checked) { - VisualServer::get_singleton()->free(light_instance); - light_instance = RID(); - } else { - light_instance = VisualServer::get_singleton()->instance_create2(light, get_tree()->get_root()->get_world()->get_scenario()); - VisualServer::get_singleton()->instance_set_transform(light_instance, light_transform); - - _update_default_light_angle(); - } - - view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(p_option), light_instance.is_valid()); - - } break; - case MENU_VIEW_USE_DEFAULT_SRGB: { - - bool is_checked = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(p_option)); - - if (is_checked) { - //viewport_environment->set_enable_fx(Environment::FX_SRGB,false); - } else { - //viewport_environment->set_enable_fx(Environment::FX_SRGB,true); - } - - is_checked = !is_checked; - - view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(p_option), is_checked); - } break; case MENU_VIEW_USE_1_VIEWPORT: { @@ -2993,14 +2928,6 @@ void SpatialEditor::_menu_item_pressed(int p_option) { void SpatialEditor::_init_indicators() { - //make sure that the camera indicator is not selectable - light = VisualServer::get_singleton()->light_create(VisualServer::LIGHT_DIRECTIONAL); - //VisualServer::get_singleton()->light_set_shadow( light, true ); - light_instance = VisualServer::get_singleton()->instance_create2(light, get_tree()->get_root()->get_world()->get_scenario()); - - light_transform.rotate(Vector3(1, 0, 0), -Math_PI / 5.0); - VisualServer::get_singleton()->instance_set_transform(light_instance, light_transform); - //RID mat = VisualServer::get_singleton()->fixed_material_create(); ///VisualServer::get_singleton()->fixed_material_set_flag(mat, VisualServer::FIXED_MATERIAL_FLAG_USE_ALPHA,true); //VisualServer::get_singleton()->fixed_material_set_flag(mat, VisualServer::FIXED_MATERIAL_FLAG_USE_COLOR_ARRAY,true); @@ -3258,8 +3185,6 @@ void SpatialEditor::_finish_indicators() { VisualServer::get_singleton()->free(grid_instance[i]); VisualServer::get_singleton()->free(grid[i]); } - VisualServer::get_singleton()->free(light_instance); - VisualServer::get_singleton()->free(light); //VisualServer::get_singleton()->free(poly); //VisualServer::get_singleton()->free(indicators_instance); //VisualServer::get_singleton()->free(indicators); @@ -3351,14 +3276,12 @@ void SpatialEditor::_notification(int p_what) { _menu_item_pressed(MENU_VIEW_USE_1_VIEWPORT); get_tree()->connect("node_removed", this, "_node_removed"); - VS::get_singleton()->scenario_set_fallback_environment(get_viewport()->find_world()->get_scenario(), viewport_environment->get_rid()); } if (p_what == NOTIFICATION_ENTER_TREE) { gizmos = memnew(SpatialEditorGizmos); _init_indicators(); - _update_default_light_angle(); } if (p_what == NOTIFICATION_EXIT_TREE) { @@ -3481,8 +3404,6 @@ void SpatialEditor::_bind_methods() { ClassDB::bind_method("_xform_dialog_action", &SpatialEditor::_xform_dialog_action); ClassDB::bind_method("_get_editor_data", &SpatialEditor::_get_editor_data); ClassDB::bind_method("_request_gizmo", &SpatialEditor::_request_gizmo); - ClassDB::bind_method("_default_light_angle_input", &SpatialEditor::_default_light_angle_input); - ClassDB::bind_method("_update_ambient_light_color", &SpatialEditor::_update_ambient_light_color); ClassDB::bind_method("_toggle_maximize_view", &SpatialEditor::_toggle_maximize_view); ADD_SIGNAL(MethodInfo("transform_key_request")); @@ -3517,43 +3438,6 @@ void SpatialEditor::clear() { } view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_GRID), true); - - settings_default_light_rot_x = Math_PI * 0.3; - settings_default_light_rot_y = Math_PI * 0.2; - - //viewport_environment->fx_set_param(Environment::FX_PARAM_AMBIENT_LIGHT_COLOR,Color(0.15,0.15,0.15)); - settings_ambient_color->set_pick_color(Color(0.15, 0.15, 0.15)); - if (!light_instance.is_valid()) - _menu_item_pressed(MENU_VIEW_USE_DEFAULT_LIGHT); - - _update_default_light_angle(); -} - -void SpatialEditor::_update_ambient_light_color(const Color &p_color) { - - //viewport_environment->fx_set_param(Environment::FX_PARAM_AMBIENT_LIGHT_COLOR,settings_ambient_color->get_color()); -} - -void SpatialEditor::_update_default_light_angle() { - - Transform t; - t.basis.rotate(Vector3(1, 0, 0), -settings_default_light_rot_x); - t.basis.rotate(Vector3(0, 1, 0), -settings_default_light_rot_y); - settings_dlight->set_transform(t); - if (light_instance.is_valid()) { - VS::get_singleton()->instance_set_transform(light_instance, t); - } -} - -void SpatialEditor::_default_light_angle_input(const Ref &p_event) { - - Ref mm = p_event; - if (mm.is_valid() && mm->get_button_mask() & (0x1 | 0x2 | 0x4)) { - - settings_default_light_rot_y = Math::fposmod(settings_default_light_rot_y - mm->get_relative().x * 0.01, Math_PI * 2.0); - settings_default_light_rot_x = Math::fposmod(settings_default_light_rot_x - mm->get_relative().y * 0.01, Math_PI * 2.0); - _update_default_light_angle(); - } } SpatialEditor::SpatialEditor(EditorNode *p_editor) { @@ -3674,10 +3558,6 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { p = view_menu->get_popup(); - p->add_check_shortcut(ED_SHORTCUT("spatial_editor/use_default_light", TTR("Use Default Light")), MENU_VIEW_USE_DEFAULT_LIGHT); - p->add_check_shortcut(ED_SHORTCUT("spatial_editor/use_default_srgb", TTR("Use Default sRGB")), MENU_VIEW_USE_DEFAULT_SRGB); - p->add_separator(); - p->add_check_shortcut(ED_SHORTCUT("spatial_editor/1_viewport", TTR("1 Viewport"), KEY_MASK_CMD + KEY_1), MENU_VIEW_USE_1_VIEWPORT); p->add_check_shortcut(ED_SHORTCUT("spatial_editor/2_viewports", TTR("2 Viewports"), KEY_MASK_CMD + KEY_2), MENU_VIEW_USE_2_VIEWPORTS); p->add_check_shortcut(ED_SHORTCUT("spatial_editor/2_viewports_alt", TTR("2 Viewports (Alt)"), KEY_MASK_ALT + KEY_MASK_CMD + KEY_2), MENU_VIEW_USE_2_VIEWPORTS_ALT); @@ -3696,7 +3576,6 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { p->add_separator(); p->add_shortcut(ED_SHORTCUT("spatial_editor/settings", TTR("Settings")), MENU_VIEW_CAMERA_SETTINGS); - p->set_item_checked(p->get_item_index(MENU_VIEW_USE_DEFAULT_LIGHT), true); p->set_item_checked(p->get_item_index(MENU_VIEW_DISPLAY_NORMAL), true); p->set_item_checked(p->get_item_index(MENU_VIEW_ORIGIN), true); p->set_item_checked(p->get_item_index(MENU_VIEW_GRID), true); @@ -3755,36 +3634,6 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { settings_dialog->add_child(settings_vbc); //settings_dialog->set_child_rect(settings_vbc); - settings_light_base = memnew(ViewportContainer); - settings_light_base->set_custom_minimum_size(Size2(128, 128)); - settings_light_base->connect("gui_input", this, "_default_light_angle_input"); - settings_vbc->add_margin_child(TTR("Default Light Normal:"), settings_light_base); - settings_light_vp = memnew(Viewport); - settings_light_vp->set_disable_input(true); - settings_light_vp->set_use_own_world(true); - settings_light_base->add_child(settings_light_vp); - - settings_dlight = memnew(DirectionalLight); - settings_light_vp->add_child(settings_dlight); - settings_sphere = memnew(ImmediateGeometry); - settings_sphere->begin(Mesh::PRIMITIVE_TRIANGLES, Ref()); - settings_sphere->set_color(Color(1, 1, 1)); - settings_sphere->add_sphere(32, 16, 1); - settings_sphere->end(); - settings_light_vp->add_child(settings_sphere); - settings_camera = memnew(Camera); - settings_light_vp->add_child(settings_camera); - settings_camera->set_translation(Vector3(0, 0, 2)); - settings_camera->set_orthogonal(2.1, 0.1, 5); - - settings_default_light_rot_x = Math_PI * 0.3; - settings_default_light_rot_y = Math_PI * 0.2; - - settings_ambient_color = memnew(ColorPickerButton); - settings_vbc->add_margin_child(TTR("Ambient Light Color:"), settings_ambient_color); - settings_ambient_color->connect("color_changed", this, "_update_ambient_light_color"); - settings_ambient_color->set_pick_color(Color(0.15, 0.15, 0.15)); - settings_fov = memnew(SpinBox); settings_fov->set_max(179); settings_fov->set_min(1); diff --git a/editor/plugins/spatial_editor_plugin.h b/editor/plugins/spatial_editor_plugin.h index 1f76d9bfb8c..88245ad0dc5 100644 --- a/editor/plugins/spatial_editor_plugin.h +++ b/editor/plugins/spatial_editor_plugin.h @@ -321,10 +321,6 @@ private: VisualServer::ScenarioDebugMode scenario_debug; - RID light; - RID light_instance; - Transform light_transform; - RID origin; RID origin_instance; RID grid[3]; @@ -383,8 +379,6 @@ private: MENU_VIEW_USE_3_VIEWPORTS, MENU_VIEW_USE_3_VIEWPORTS_ALT, MENU_VIEW_USE_4_VIEWPORTS, - MENU_VIEW_USE_DEFAULT_LIGHT, - MENU_VIEW_USE_DEFAULT_SRGB, MENU_VIEW_DISPLAY_NORMAL, MENU_VIEW_DISPLAY_WIREFRAME, MENU_VIEW_DISPLAY_OVERDRAW, @@ -419,16 +413,6 @@ private: SpinBox *settings_fov; SpinBox *settings_znear; SpinBox *settings_zfar; - DirectionalLight *settings_dlight; - ImmediateGeometry *settings_sphere; - Camera *settings_camera; - float settings_default_light_rot_x; - float settings_default_light_rot_y; - - ViewportContainer *settings_light_base; - Viewport *settings_light_vp; - ColorPickerButton *settings_ambient_color; - Ref settings_light_dir_image; void _xform_dialog_action(); void _menu_item_pressed(int p_option); @@ -462,10 +446,6 @@ private: SpatialEditorGizmos *gizmos; SpatialEditor(); - void _update_ambient_light_color(const Color &p_color); - void _update_default_light_angle(); - void _default_light_angle_input(const Ref &p_event); - bool is_any_freelook_active() const; protected: diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 50b518afba6..a4e8ef70cec 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -203,10 +203,23 @@ private: f->store_line("\n"); f->store_line("name=\"" + project_name->get_text() + "\""); f->store_line("icon=\"res://icon.png\""); - + f->store_line("[rendering]"); + f->store_line("viewport/default_environment=\"res://default_env.tres\""); memdelete(f); ResourceSaver::save(dir.plus_file("/icon.png"), get_icon("DefaultProjectIcon", "EditorIcons")); + + f = FileAccess::open(dir.plus_file("/default_env.tres"), FileAccess::WRITE); + if (!f) { + error->set_text(TTR("Couldn't create project.godot in project path.")); + } else { + f->store_line("[gd_resource type=\"Environment\" load_steps=2 format=2]"); + f->store_line("[sub_resource type=\"ProceduralSky\" id=1]"); + f->store_line("[resource]"); + f->store_line("background_mode = 2"); + f->store_line("background_sky = SubResource( 1 )"); + memdelete(f); + } } } else if (mode == MODE_INSTALL) { diff --git a/main/tests/test_math.cpp b/main/tests/test_math.cpp index 95a1672e67a..d21be24dab1 100644 --- a/main/tests/test_math.cpp +++ b/main/tests/test_math.cpp @@ -462,6 +462,59 @@ uint32_t ihash3(uint32_t a) { MainLoop *test() { + { + float r = 1; + float g = 0.5; + float b = 0.1; + + const float pow2to9 = 512.0f; + const float B = 15.0f; + //const float Emax = 31.0f; + const float N = 9.0f; + + float sharedexp = 65408.000f; //(( pow2to9 - 1.0f)/ pow2to9)*powf( 2.0f, 31.0f - 15.0f); + + float cRed = MAX(0.0f, MIN(sharedexp, r)); + float cGreen = MAX(0.0f, MIN(sharedexp, g)); + float cBlue = MAX(0.0f, MIN(sharedexp, b)); + + float cMax = MAX(cRed, MAX(cGreen, cBlue)); + + // expp = MAX(-B - 1, log2(maxc)) + 1 + B + + float expp = MAX(-B - 1.0f, floor(Math::log(cMax) / Math_LN2)) + 1.0f + B; + + float sMax = (float)floor((cMax / Math::pow(2.0f, expp - B - N)) + 0.5f); + + float exps = expp + 1.0f; + + if (0.0 <= sMax && sMax < pow2to9) { + exps = expp; + } + + float sRed = Math::floor((cRed / pow(2.0f, exps - B - N)) + 0.5f); + float sGreen = Math::floor((cGreen / pow(2.0f, exps - B - N)) + 0.5f); + float sBlue = Math::floor((cBlue / pow(2.0f, exps - B - N)) + 0.5f); + + print_line("R: " + rtos(sRed) + " G: " + rtos(sGreen) + " B: " + rtos(sBlue) + " EXP: " + rtos(exps)); + + uint32_t rgbe = (Math::fast_ftoi(sRed) & 0x1FF) | ((Math::fast_ftoi(sGreen) & 0x1FF) << 9) | ((Math::fast_ftoi(sBlue) & 0x1FF) << 18) | ((Math::fast_ftoi(exps) & 0x1F) << 27); + + float rb = rgbe & 0x1ff; + float gb = (rgbe >> 9) & 0x1ff; + float bb = (rgbe >> 18) & 0x1ff; + float eb = (rgbe >> 27); + float mb = Math::pow(2, eb - 15.0 - 9.0); + ; + float rd = rb * mb; + float gd = gb * mb; + float bd = bb * mb; + + print_line("RGBE: " + Color(rd, gd, bd)); + + return NULL; + } + print_line("Dvectors: " + itos(MemoryPool::allocs_used)); print_line("Mem used: " + itos(MemoryPool::total_memory)); print_line("MAx mem used: " + itos(MemoryPool::max_memory)); diff --git a/modules/hdr/SCsub b/modules/hdr/SCsub new file mode 100644 index 00000000000..c960e8126b1 --- /dev/null +++ b/modules/hdr/SCsub @@ -0,0 +1,9 @@ +#!/usr/bin/env python + +Import('env') +Import('env_modules') + +env_hdr = env_modules.Clone() + +# Godot's own source files +env_hdr.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/hdr/config.py b/modules/hdr/config.py new file mode 100644 index 00000000000..fb920482f5f --- /dev/null +++ b/modules/hdr/config.py @@ -0,0 +1,7 @@ + +def can_build(platform): + return True + + +def configure(env): + pass diff --git a/modules/hdr/image_loader_hdr.cpp b/modules/hdr/image_loader_hdr.cpp new file mode 100644 index 00000000000..4c897e66af0 --- /dev/null +++ b/modules/hdr/image_loader_hdr.cpp @@ -0,0 +1,151 @@ +/*************************************************************************/ +/* image_loader_jpegd.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.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 "image_loader_hdr.h" + +#include "os/os.h" +#include "print_string.h" + +#include "thirdparty/tinyexr/tinyexr.h" + +Error ImageLoaderHDR::load_image(Ref p_image, FileAccess *f) { + + String header = f->get_token(); + + print_line("HEADER: " + header); + ERR_FAIL_COND_V(header != "#?RADIANCE", ERR_FILE_UNRECOGNIZED); + + String format = f->get_token(); + print_line("FORMAT: " + format); + + ERR_FAIL_COND_V(format != "FORMAT=32-bit_rle_rgbe", ERR_FILE_UNRECOGNIZED); + + String token = f->get_token(); + + ERR_FAIL_COND_V(token != "-Y", ERR_FILE_CORRUPT); + + int height = f->get_token().to_int(); + + token = f->get_token(); + + ERR_FAIL_COND_V(token != "+X", ERR_FILE_CORRUPT); + + int width = f->get_line().to_int(); + + print_line("HDR w: " + itos(width) + " h:" + itos(height)); + + PoolVector imgdata; + + imgdata.resize(height * width * sizeof(uint32_t)); + + { + + PoolVector::Write w = imgdata.write(); + + uint8_t *ptr = (uint8_t *)w.ptr(); + + if (width < 8 || width >= 32768) { + // Read flat data + + f->get_buffer(ptr, width * height * 4); + } else { + // Read RLE-encoded data + + for (int j = 0; j < height; ++j) { + int c1 = f->get_8(); + int c2 = f->get_8(); + int len = f->get_8(); + if (c1 != 2 || c2 != 2 || (len & 0x80)) { + // not run-length encoded, so we have to actually use THIS data as a decoded + // pixel (note this can't be a valid pixel--one of RGB must be >= 128) + + ptr[(j * width) * 4 + 0] = uint8_t(c1); + ptr[(j * width) * 4 + 1] = uint8_t(c2); + ptr[(j * width) * 4 + 2] = uint8_t(len); + ptr[(j * width) * 4 + 3] = f->get_8(); + + f->get_buffer(&ptr[(j * width + 1) * 4], (width - 1) * 4); + continue; + } + len <<= 8; + len |= f->get_8(); + + print_line("line: " + itos(len)); + if (len != width) { + ERR_EXPLAIN("invalid decoded scanline length, corrupt HDR"); + ERR_FAIL_V(ERR_FILE_CORRUPT); + } + + for (int k = 0; k < 4; ++k) { + int i = 0; + while (i < width) { + int count = f->get_8(); + if (count > 128) { + // Run + int value = f->get_8(); + count -= 128; + for (int z = 0; z < count; ++z) + ptr[(j * width + i++) * 4 + k] = uint8_t(value); + } else { + // Dump + for (int z = 0; z < count; ++z) + ptr[(j * width + i++) * 4 + k] = f->get_8(); + } + } + } + } + } + + //convert + for (int i = 0; i < width * height; i++) { + + float exp = pow(2, ptr[3] - 128); + + Color c( + ptr[0] * exp / 255.0, + ptr[1] * exp / 255.0, + ptr[2] * exp / 255.0); + + *(uint32_t *)ptr = c.to_rgbe9995(); + ptr += 4; + } + } + + p_image->create(width, height, false, Image::FORMAT_RGBE9995, imgdata); + + return OK; +} + +void ImageLoaderHDR::get_recognized_extensions(List *p_extensions) const { + + p_extensions->push_back("hdr"); +} + +ImageLoaderHDR::ImageLoaderHDR() { +} diff --git a/modules/hdr/image_loader_hdr.h b/modules/hdr/image_loader_hdr.h new file mode 100644 index 00000000000..93bb0fdc03a --- /dev/null +++ b/modules/hdr/image_loader_hdr.h @@ -0,0 +1,46 @@ +/*************************************************************************/ +/* image_loader_jpegd.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.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 IMAGE_LOADER_TINYEXR_H +#define IMAGE_LOADER_TINYEXR_H + +#include "io/image_loader.h" + +/** + @author Juan Linietsky +*/ +class ImageLoaderHDR : public ImageFormatLoader { + +public: + virtual Error load_image(Ref p_image, FileAccess *f); + virtual void get_recognized_extensions(List *p_extensions) const; + ImageLoaderHDR(); +}; + +#endif diff --git a/modules/hdr/register_types.cpp b/modules/hdr/register_types.cpp new file mode 100644 index 00000000000..e4f7c14aa7e --- /dev/null +++ b/modules/hdr/register_types.cpp @@ -0,0 +1,45 @@ +/*************************************************************************/ +/* register_types.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.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 "register_types.h" + +#include "image_loader_hdr.h" + +static ImageLoaderHDR *image_loader_hdr = NULL; + +void register_hdr_types() { + + image_loader_hdr = memnew(ImageLoaderHDR); + ImageLoader::add_image_format_loader(image_loader_hdr); +} + +void unregister_hdr_types() { + + memdelete(image_loader_hdr); +} diff --git a/modules/hdr/register_types.h b/modules/hdr/register_types.h new file mode 100644 index 00000000000..3d901ea0036 --- /dev/null +++ b/modules/hdr/register_types.h @@ -0,0 +1,31 @@ +/*************************************************************************/ +/* register_types.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.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. */ +/*************************************************************************/ +void register_hdr_types(); +void unregister_hdr_types(); diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp index c782968ea00..80969d11b37 100644 --- a/scene/2d/line_2d.cpp +++ b/scene/2d/line_2d.cpp @@ -99,7 +99,7 @@ Color Line2D::get_default_color() const { return _default_color; } -void Line2D::set_gradient(const Ref &gradient) { +void Line2D::set_gradient(const Ref &gradient) { // Cleanup previous connection if any if (_gradient.is_valid()) { @@ -116,7 +116,7 @@ void Line2D::set_gradient(const Ref &gradient) { update(); } -Ref Line2D::get_gradient() const { +Ref Line2D::get_gradient() const { return _gradient; } diff --git a/scene/2d/line_2d.h b/scene/2d/line_2d.h index fee1cad942c..e8ca5e6e7c3 100644 --- a/scene/2d/line_2d.h +++ b/scene/2d/line_2d.h @@ -57,8 +57,8 @@ public: void set_default_color(Color color); Color get_default_color() const; - void set_gradient(const Ref &gradient); - Ref get_gradient() const; + void set_gradient(const Ref &gradient); + Ref get_gradient() const; void set_texture(const Ref &texture); Ref get_texture() const; @@ -97,7 +97,7 @@ private: LineCapMode _end_cap_mode; float _width; Color _default_color; - Ref _gradient; + Ref _gradient; Ref _texture; LineTextureMode _texture_mode; float _sharp_limit; diff --git a/scene/2d/line_builder.h b/scene/2d/line_builder.h index eed9cac0aa1..0e1a2aaf507 100644 --- a/scene/2d/line_builder.h +++ b/scene/2d/line_builder.h @@ -62,7 +62,7 @@ public: LineCapMode end_cap_mode; float width; Color default_color; - ColorRamp *gradient; + Gradient *gradient; LineTextureMode texture_mode; float sharp_limit; int round_precision; diff --git a/scene/2d/particles_2d.cpp b/scene/2d/particles_2d.cpp index b91d9b835ce..951861256e3 100644 --- a/scene/2d/particles_2d.cpp +++ b/scene/2d/particles_2d.cpp @@ -774,12 +774,12 @@ Color Particles2D::get_color() const { return default_color; } -void Particles2D::set_color_ramp(const Ref &p_color_ramp) { +void Particles2D::set_color_ramp(const Ref &p_color_ramp) { color_ramp = p_color_ramp; } -Ref Particles2D::get_color_ramp() const { +Ref Particles2D::get_color_ramp() const { return color_ramp; } @@ -810,7 +810,7 @@ void Particles2D::set_color_phases(int p_phases) { //Create color ramp if we have 2 or more phases. //Otherwise first phase phase will be assigned to default color. if (p_phases > 1 && color_ramp.is_null()) { - color_ramp = Ref(memnew(ColorRamp())); + color_ramp = Ref(memnew(Gradient())); } if (color_ramp.is_valid()) { color_ramp->get_points().resize(p_phases); diff --git a/scene/2d/particles_2d.h b/scene/2d/particles_2d.h index 4b87a261956..5769fdd2518 100644 --- a/scene/2d/particles_2d.h +++ b/scene/2d/particles_2d.h @@ -169,7 +169,7 @@ private: //If no color ramp is set then default color is used. Created as simple alternative to color_ramp. Color default_color; - Ref color_ramp; + Ref color_ramp; void _process_particles(float p_delta); friend class ParticleAttractor2D; @@ -241,8 +241,8 @@ public: void set_color(const Color &p_color); Color get_color() const; - void set_color_ramp(const Ref &p_texture); - Ref get_color_ramp() const; + void set_color_ramp(const Ref &p_texture); + Ref get_color_ramp() const; void set_emissor_offset(const Point2 &p_offset); Point2 get_emissor_offset() const; diff --git a/scene/gui/color_ramp_edit.cpp b/scene/gui/color_ramp_edit.cpp index 9270b97e026..8c47f8559ad 100644 --- a/scene/gui/color_ramp_edit.cpp +++ b/scene/gui/color_ramp_edit.cpp @@ -114,7 +114,7 @@ void ColorRampEdit::_gui_input(const Ref &p_event) { if (grabbed != -1) { int total_w = get_size().width - get_size().height - 3; - ColorRamp::Point newPoint = points[grabbed]; + Gradient::Point newPoint = points[grabbed]; newPoint.offset = CLAMP(x / float(total_w), 0, 1); points.push_back(newPoint); @@ -152,11 +152,11 @@ void ColorRampEdit::_gui_input(const Ref &p_event) { } //insert - ColorRamp::Point newPoint; + Gradient::Point newPoint; newPoint.offset = CLAMP(x / float(total_w), 0, 1); - ColorRamp::Point prev; - ColorRamp::Point next; + Gradient::Point prev; + Gradient::Point next; int pos = -1; for (int i = 0; i < points.size(); i++) { @@ -293,7 +293,7 @@ void ColorRampEdit::_notification(int p_what) { _draw_checker(0, 0, total_w, h); //Draw color ramp - ColorRamp::Point prev; + Gradient::Point prev; prev.offset = 0; if (points.size() == 0) prev.color = Color(0, 0, 0); //Draw black rectangle if we have no points @@ -302,7 +302,7 @@ void ColorRampEdit::_notification(int p_what) { for (int i = -1; i < points.size(); i++) { - ColorRamp::Point next; + Gradient::Point next; //If there is no next point if (i + 1 == points.size()) { if (points.size() == 0) @@ -410,7 +410,7 @@ void ColorRampEdit::set_ramp(const Vector &p_offsets, const Vector ERR_FAIL_COND(p_offsets.size() != p_colors.size()); points.clear(); for (int i = 0; i < p_offsets.size(); i++) { - ColorRamp::Point p; + Gradient::Point p; p.offset = p_offsets[i]; p.color = p_colors[i]; points.push_back(p); @@ -434,14 +434,14 @@ Vector ColorRampEdit::get_colors() const { return ret; } -void ColorRampEdit::set_points(Vector &p_points) { +void ColorRampEdit::set_points(Vector &p_points) { if (points.size() != p_points.size()) grabbed = -1; points.clear(); points = p_points; } -Vector &ColorRampEdit::get_points() { +Vector &ColorRampEdit::get_points() { return points; } diff --git a/scene/gui/color_ramp_edit.h b/scene/gui/color_ramp_edit.h index ede89540407..0fe447c43ac 100644 --- a/scene/gui/color_ramp_edit.h +++ b/scene/gui/color_ramp_edit.h @@ -48,7 +48,7 @@ class ColorRampEdit : public Control { bool grabbing; int grabbed; - Vector points; + Vector points; void _draw_checker(int x, int y, int w, int h); void _color_changed(const Color &p_color); @@ -64,8 +64,8 @@ public: void set_ramp(const Vector &p_offsets, const Vector &p_colors); Vector get_offsets() const; Vector get_colors() const; - void set_points(Vector &p_points); - Vector &get_points(); + void set_points(Vector &p_points); + Vector &get_points(); virtual Size2 get_minimum_size() const; ColorRampEdit(); diff --git a/scene/main/scene_main_loop.cpp b/scene/main/scene_main_loop.cpp index b55a925f553..96a35198406 100644 --- a/scene/main/scene_main_loop.cpp +++ b/scene/main/scene_main_loop.cpp @@ -37,6 +37,7 @@ #include "print_string.h" #include //#include "servers/spatial_sound_2d_server.h" + #include "io/marshalls.h" #include "io/resource_loader.h" #include "scene/resources/material.h" @@ -609,6 +610,30 @@ bool SceneTree::idle(float p_time) { _call_idle_callbacks(); +#ifdef TOOLS_ENABLED + + if (is_editor_hint()) { + //simple hack to reload fallback environment if it changed from editor + String env_path = GlobalConfig::get_singleton()->get("rendering/viewport/default_environment"); + env_path = env_path.strip_edges(); //user may have added a space or two + String cpath; + Ref fallback = get_root()->get_world()->get_fallback_environment(); + if (fallback.is_valid()) { + cpath = fallback->get_path(); + } + if (cpath != env_path) { + + if (env_path != String()) { + fallback = ResourceLoader::load(env_path); + } else { + fallback.unref(); + } + get_root()->get_world()->set_fallback_environment(fallback); + } + } + +#endif + return _quit; } @@ -2301,7 +2326,9 @@ SceneTree::SceneTree() { root = memnew(Viewport); root->set_name("root"); - root->set_world(Ref(memnew(World))); + if (!root->get_world().is_valid()) + root->set_world(Ref(memnew(World))); + //root->set_world_2d( Ref( memnew( World2D ))); root->set_as_audio_listener(true); root->set_as_audio_listener_2d(true); @@ -2317,6 +2344,37 @@ SceneTree::SceneTree() { VS::get_singleton()->scenario_set_reflection_atlas_size(root->get_world()->get_scenario(), ref_atlas_size, ref_atlas_subdiv); + { //load default fallback environment + //get possible extensions + List exts; + ResourceLoader::get_recognized_extensions_for_type("Environment", &exts); + String ext_hint; + for (List::Element *E = exts.front(); E; E = E->next()) { + if (ext_hint != String()) + ext_hint += ","; + ext_hint += "*." + E->get(); + } + //get path + String env_path = GLOBAL_DEF("rendering/viewport/default_environment", ""); + //setup property + GlobalConfig::get_singleton()->set_custom_property_info("rendering/viewport/default_environment", PropertyInfo(Variant::STRING, "rendering/viewport/default_environment", PROPERTY_HINT_FILE, ext_hint)); + env_path = env_path.strip_edges(); + if (env_path != String()) { + Ref env = ResourceLoader::load(env_path); + if (env.is_valid()) { + root->get_world()->set_fallback_environment(env); + } else { + if (is_editor_hint()) { + //file was erased, clear the field. + GlobalConfig::get_singleton()->set("rendering/viewport/default_environment", ""); + } else { + //file was erased, notify user. + ERR_PRINTS(RTR("Default Environment as specified in Project Setings (Rendering -> Viewport -> Default Environment) could not be loaded.")); + } + } + } + } + stretch_mode = STRETCH_MODE_DISABLED; stretch_aspect = STRETCH_ASPECT_IGNORE; diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 4c359f73ab3..0a3f64eacd7 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -563,6 +563,7 @@ void register_scene_types() { ClassDB::register_virtual_class(); ClassDB::register_virtual_class(); ClassDB::register_class(); + ClassDB::register_class(); ClassDB::register_class(); ClassDB::register_class(); ClassDB::register_class(); @@ -584,7 +585,7 @@ void register_scene_types() { ClassDB::register_class(); ClassDB::register_class(); - ClassDB::register_class(); + ClassDB::register_class(); OS::get_singleton()->yield(); //may take time to init diff --git a/scene/resources/color_ramp.cpp b/scene/resources/color_ramp.cpp index 3c58a76998f..3cf88451893 100644 --- a/scene/resources/color_ramp.cpp +++ b/scene/resources/color_ramp.cpp @@ -36,7 +36,7 @@ #define COLOR_RAMP_SET_OFFSETS "set_offsets" #define COLOR_RAMP_SET_COLORS "set_colors" -ColorRamp::ColorRamp() { +Gradient::Gradient() { //Set initial color ramp transition from black to white points.resize(2); points[0].color = Color(0, 0, 0, 1); @@ -46,35 +46,35 @@ ColorRamp::ColorRamp() { is_sorted = true; } -ColorRamp::~ColorRamp() { +Gradient::~Gradient() { } -void ColorRamp::_bind_methods() { +void Gradient::_bind_methods() { - ClassDB::bind_method(D_METHOD("add_point", "offset", "color"), &ColorRamp::add_point); - ClassDB::bind_method(D_METHOD("remove_point", "offset", "color"), &ColorRamp::remove_point); + ClassDB::bind_method(D_METHOD("add_point", "offset", "color"), &Gradient::add_point); + ClassDB::bind_method(D_METHOD("remove_point", "offset", "color"), &Gradient::remove_point); - ClassDB::bind_method(D_METHOD("set_offset", "point", "offset"), &ColorRamp::set_offset); - ClassDB::bind_method(D_METHOD("get_offset", "point"), &ColorRamp::get_offset); + ClassDB::bind_method(D_METHOD("set_offset", "point", "offset"), &Gradient::set_offset); + ClassDB::bind_method(D_METHOD("get_offset", "point"), &Gradient::get_offset); - ClassDB::bind_method(D_METHOD("set_color", "point", "color"), &ColorRamp::set_color); - ClassDB::bind_method(D_METHOD("get_color", "point"), &ColorRamp::get_color); + ClassDB::bind_method(D_METHOD("set_color", "point", "color"), &Gradient::set_color); + ClassDB::bind_method(D_METHOD("get_color", "point"), &Gradient::get_color); - ClassDB::bind_method(D_METHOD("interpolate", "offset"), &ColorRamp::get_color_at_offset); + ClassDB::bind_method(D_METHOD("interpolate", "offset"), &Gradient::get_color_at_offset); - ClassDB::bind_method(D_METHOD("get_point_count"), &ColorRamp::get_points_count); + ClassDB::bind_method(D_METHOD("get_point_count"), &Gradient::get_points_count); - ClassDB::bind_method(D_METHOD(COLOR_RAMP_SET_OFFSETS, "offsets"), &ColorRamp::set_offsets); - ClassDB::bind_method(D_METHOD(COLOR_RAMP_GET_OFFSETS), &ColorRamp::get_offsets); + ClassDB::bind_method(D_METHOD(COLOR_RAMP_SET_OFFSETS, "offsets"), &Gradient::set_offsets); + ClassDB::bind_method(D_METHOD(COLOR_RAMP_GET_OFFSETS), &Gradient::get_offsets); - ClassDB::bind_method(D_METHOD(COLOR_RAMP_SET_COLORS, "colors"), &ColorRamp::set_colors); - ClassDB::bind_method(D_METHOD(COLOR_RAMP_GET_COLORS), &ColorRamp::get_colors); + ClassDB::bind_method(D_METHOD(COLOR_RAMP_SET_COLORS, "colors"), &Gradient::set_colors); + ClassDB::bind_method(D_METHOD(COLOR_RAMP_GET_COLORS), &Gradient::get_colors); ADD_PROPERTY(PropertyInfo(Variant::REAL, "offsets"), COLOR_RAMP_SET_OFFSETS, COLOR_RAMP_GET_OFFSETS); ADD_PROPERTY(PropertyInfo(Variant::REAL, "colors"), COLOR_RAMP_SET_COLORS, COLOR_RAMP_GET_COLORS); } -Vector ColorRamp::get_offsets() const { +Vector Gradient::get_offsets() const { Vector offsets; offsets.resize(points.size()); for (int i = 0; i < points.size(); i++) { @@ -83,7 +83,7 @@ Vector ColorRamp::get_offsets() const { return offsets; } -Vector ColorRamp::get_colors() const { +Vector Gradient::get_colors() const { Vector colors; colors.resize(points.size()); for (int i = 0; i < points.size(); i++) { @@ -92,7 +92,7 @@ Vector ColorRamp::get_colors() const { return colors; } -void ColorRamp::set_offsets(const Vector &p_offsets) { +void Gradient::set_offsets(const Vector &p_offsets) { points.resize(p_offsets.size()); for (int i = 0; i < points.size(); i++) { points[i].offset = p_offsets[i]; @@ -101,7 +101,7 @@ void ColorRamp::set_offsets(const Vector &p_offsets) { emit_signal(CoreStringNames::get_singleton()->changed); } -void ColorRamp::set_colors(const Vector &p_colors) { +void Gradient::set_colors(const Vector &p_colors) { if (points.size() < p_colors.size()) is_sorted = false; points.resize(p_colors.size()); @@ -111,11 +111,11 @@ void ColorRamp::set_colors(const Vector &p_colors) { emit_signal(CoreStringNames::get_singleton()->changed); } -Vector &ColorRamp::get_points() { +Vector &Gradient::get_points() { return points; } -void ColorRamp::add_point(float p_offset, const Color &p_color) { +void Gradient::add_point(float p_offset, const Color &p_color) { Point p; p.offset = p_offset; @@ -126,7 +126,7 @@ void ColorRamp::add_point(float p_offset, const Color &p_color) { emit_signal(CoreStringNames::get_singleton()->changed); } -void ColorRamp::remove_point(int p_index) { +void Gradient::remove_point(int p_index) { ERR_FAIL_INDEX(p_index, points.size()); ERR_FAIL_COND(points.size() <= 2); @@ -134,13 +134,13 @@ void ColorRamp::remove_point(int p_index) { emit_signal(CoreStringNames::get_singleton()->changed); } -void ColorRamp::set_points(Vector &p_points) { +void Gradient::set_points(Vector &p_points) { points = p_points; is_sorted = false; emit_signal(CoreStringNames::get_singleton()->changed); } -void ColorRamp::set_offset(int pos, const float offset) { +void Gradient::set_offset(int pos, const float offset) { if (points.size() <= pos) points.resize(pos + 1); points[pos].offset = offset; @@ -148,13 +148,13 @@ void ColorRamp::set_offset(int pos, const float offset) { emit_signal(CoreStringNames::get_singleton()->changed); } -float ColorRamp::get_offset(int pos) const { +float Gradient::get_offset(int pos) const { if (points.size() > pos) return points[pos].offset; return 0; //TODO: Maybe throw some error instead? } -void ColorRamp::set_color(int pos, const Color &color) { +void Gradient::set_color(int pos, const Color &color) { if (points.size() <= pos) { points.resize(pos + 1); is_sorted = false; @@ -163,12 +163,12 @@ void ColorRamp::set_color(int pos, const Color &color) { emit_signal(CoreStringNames::get_singleton()->changed); } -Color ColorRamp::get_color(int pos) const { +Color Gradient::get_color(int pos) const { if (points.size() > pos) return points[pos].color; return Color(0, 0, 0, 1); //TODO: Maybe throw some error instead? } -int ColorRamp::get_points_count() const { +int Gradient::get_points_count() const { return points.size(); } diff --git a/scene/resources/color_ramp.h b/scene/resources/color_ramp.h index e231e9fc52a..d7ec20b3247 100644 --- a/scene/resources/color_ramp.h +++ b/scene/resources/color_ramp.h @@ -32,9 +32,9 @@ #include "resource.h" -class ColorRamp : public Resource { - GDCLASS(ColorRamp, Resource); - OBJ_SAVE_TYPE(ColorRamp); +class Gradient : public Resource { + GDCLASS(Gradient, Resource); + OBJ_SAVE_TYPE(Gradient); public: struct Point { @@ -54,8 +54,8 @@ protected: static void _bind_methods(); public: - ColorRamp(); - virtual ~ColorRamp(); + Gradient(); + virtual ~Gradient(); void add_point(float p_offset, const Color &p_color); void remove_point(int p_index); diff --git a/scene/resources/sky_box.cpp b/scene/resources/sky_box.cpp index 59ade4a7294..61aaaf8fb4b 100644 --- a/scene/resources/sky_box.cpp +++ b/scene/resources/sky_box.cpp @@ -112,3 +112,394 @@ PanoramaSky::~PanoramaSky() { VS::get_singleton()->free(sky); } +////////////////////////////////// + +void ProceduralSky::_radiance_changed() { + + if (update_queued) + return; //do nothing yet + + static const int size[RADIANCE_SIZE_MAX] = { + 256, 512, 1024, 2048 + }; + VS::get_singleton()->sky_set_texture(sky, texture, size[get_radiance_size()]); +} + +void ProceduralSky::_update_sky() { + + update_queued = false; + + PoolVector imgdata; + + static const int size[TEXTURE_SIZE_MAX] = { + 1024, 2048, 4096 + }; + + int w = size[texture_size]; + int h = w / 2; + + imgdata.resize(w * h * 4); //RGBE + + { + PoolVector::Write dataw = imgdata.write(); + + uint32_t *ptr = (uint32_t *)dataw.ptr(); + + Color sky_top_linear = sky_top_color.to_linear(); + Color sky_horizon_linear = sky_horizon_color.to_linear(); + + Color ground_bottom_linear = ground_bottom_color.to_linear(); + Color ground_horizon_linear = ground_horizon_color.to_linear(); + + //Color sun_linear = sun_color.to_linear(); + + Vector3 sun(0, 0, -1); + + sun = Basis(Vector3(1, 0, 0), Math::deg2rad(sun_latitude)).xform(sun); + sun = Basis(Vector3(0, 1, 0), Math::deg2rad(sun_longitude)).xform(sun); + + sun.normalize(); + + for (int i = 0; i < w; i++) { + + float u = float(i) / (w - 1); + float phi = u * 2.0 * Math_PI; + + for (int j = 0; j < h; j++) { + + float v = float(j) / (h - 1); + float theta = v * Math_PI; + + Vector3 normal( + Math::sin(phi) * Math::sin(theta) * -1.0, + Math::cos(theta), + Math::cos(phi) * Math::sin(theta) * -1.0); + + normal.normalize(); + + float v_angle = Math::acos(normal.y); + + Color color; + + if (normal.y < 0) { + //ground + + float c = (v_angle - (Math_PI * 0.5)) / (Math_PI * 0.5); + color = ground_horizon_linear.linear_interpolate(ground_bottom_linear, Math::ease(c, ground_curve)); + } else { + float c = v_angle / (Math_PI * 0.5); + color = sky_horizon_linear.linear_interpolate(sky_top_linear, Math::ease(1.0 - c, sky_curve)); + + float sun_angle = Math::rad2deg(Math::acos(sun.dot(normal))); + + if (sun_angle < sun_angle_min) { + color = color.blend(sun_color); + } else if (sun_angle < sun_angle_max) { + + float c2 = (sun_angle - sun_angle_min) / (sun_angle_max - sun_angle_min); + c2 = Math::ease(c2, sun_curve); + + color = color.blend(sun_color).linear_interpolate(color, c2); + } + } + + ptr[j * w + i] = color.to_rgbe9995(); + } + } + } + + Ref image; + image.instance(); + image->create(w, h, false, Image::FORMAT_RGBE9995, imgdata); + + VS::get_singleton()->texture_allocate(texture, w, h, Image::FORMAT_RGBE9995, VS::TEXTURE_FLAG_FILTER | VS::TEXTURE_FLAG_REPEAT); + VS::get_singleton()->texture_set_data(texture, image); + _radiance_changed(); +} + +void ProceduralSky::set_sky_top_color(const Color &p_sky_top) { + + sky_top_color = p_sky_top; + _queue_update(); +} + +Color ProceduralSky::get_sky_top_color() const { + + return sky_top_color; +} + +void ProceduralSky::set_sky_horizon_color(const Color &p_sky_horizon) { + + sky_horizon_color = p_sky_horizon; + _queue_update(); +} +Color ProceduralSky::get_sky_horizon_color() const { + + return sky_horizon_color; +} + +void ProceduralSky::set_sky_curve(float p_curve) { + + sky_curve = p_curve; + _queue_update(); +} +float ProceduralSky::get_sky_curve() const { + + return sky_curve; +} + +void ProceduralSky::set_sky_energy(float p_energy) { + + sky_energy = p_energy; + _queue_update(); +} +float ProceduralSky::get_sky_energy() const { + + return sky_energy; +} + +void ProceduralSky::set_ground_bottom_color(const Color &p_ground_bottom) { + + ground_bottom_color = p_ground_bottom; + _queue_update(); +} +Color ProceduralSky::get_ground_bottom_color() const { + + return ground_bottom_color; +} + +void ProceduralSky::set_ground_horizon_color(const Color &p_ground_horizon) { + + ground_horizon_color = p_ground_horizon; + _queue_update(); +} +Color ProceduralSky::get_ground_horizon_color() const { + + return ground_horizon_color; +} + +void ProceduralSky::set_ground_curve(float p_curve) { + + ground_curve = p_curve; + _queue_update(); +} +float ProceduralSky::get_ground_curve() const { + + return ground_curve; +} + +void ProceduralSky::set_ground_energy(float p_energy) { + + ground_energy = p_energy; + _queue_update(); +} +float ProceduralSky::get_ground_energy() const { + + return ground_energy; +} + +void ProceduralSky::set_sun_color(const Color &p_sun) { + + sun_color = p_sun; + _queue_update(); +} +Color ProceduralSky::get_sun_color() const { + + return sun_color; +} + +void ProceduralSky::set_sun_latitude(float p_angle) { + + sun_latitude = p_angle; + _queue_update(); +} +float ProceduralSky::get_sun_latitude() const { + + return sun_latitude; +} + +void ProceduralSky::set_sun_longitude(float p_angle) { + + sun_longitude = p_angle; + _queue_update(); +} +float ProceduralSky::get_sun_longitude() const { + + return sun_longitude; +} + +void ProceduralSky::set_sun_angle_min(float p_angle) { + + sun_angle_min = p_angle; + _queue_update(); +} +float ProceduralSky::get_sun_angle_min() const { + + return sun_angle_min; +} + +void ProceduralSky::set_sun_angle_max(float p_angle) { + + sun_angle_max = p_angle; + _queue_update(); +} +float ProceduralSky::get_sun_angle_max() const { + + return sun_angle_max; +} + +void ProceduralSky::set_sun_curve(float p_curve) { + + sun_curve = p_curve; + _queue_update(); +} +float ProceduralSky::get_sun_curve() const { + + return sun_curve; +} + +void ProceduralSky::set_sun_energy(float p_energy) { + + sun_energy = p_energy; + _queue_update(); +} +float ProceduralSky::get_sun_energy() const { + + return sun_energy; +} + +void ProceduralSky::set_texture_size(TextureSize p_size) { + ERR_FAIL_INDEX(p_size, TEXTURE_SIZE_MAX); + + texture_size = p_size; + _queue_update(); +} +ProceduralSky::TextureSize ProceduralSky::get_texture_size() const { + return texture_size; +} + +RID ProceduralSky::get_rid() const { + return sky; +} + +void ProceduralSky::_queue_update() { + + if (update_queued) + return; + + update_queued = true; + call_deferred("_update_sky"); +} + +void ProceduralSky::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_update_sky"), &ProceduralSky::_update_sky); + + ClassDB::bind_method(D_METHOD("set_sky_top_color", "color"), &ProceduralSky::set_sky_top_color); + ClassDB::bind_method(D_METHOD("get_sky_top_color"), &ProceduralSky::get_sky_top_color); + + ClassDB::bind_method(D_METHOD("set_sky_horizon_color", "color"), &ProceduralSky::set_sky_horizon_color); + ClassDB::bind_method(D_METHOD("get_sky_horizon_color"), &ProceduralSky::get_sky_horizon_color); + + ClassDB::bind_method(D_METHOD("set_sky_curve", "curve"), &ProceduralSky::set_sky_curve); + ClassDB::bind_method(D_METHOD("get_sky_curve"), &ProceduralSky::get_sky_curve); + + ClassDB::bind_method(D_METHOD("set_sky_energy", "energy"), &ProceduralSky::set_sky_energy); + ClassDB::bind_method(D_METHOD("get_sky_energy"), &ProceduralSky::get_sky_energy); + + ClassDB::bind_method(D_METHOD("set_ground_bottom_color", "color"), &ProceduralSky::set_ground_bottom_color); + ClassDB::bind_method(D_METHOD("get_ground_bottom_color"), &ProceduralSky::get_ground_bottom_color); + + ClassDB::bind_method(D_METHOD("set_ground_horizon_color", "color"), &ProceduralSky::set_ground_horizon_color); + ClassDB::bind_method(D_METHOD("get_ground_horizon_color"), &ProceduralSky::get_ground_horizon_color); + + ClassDB::bind_method(D_METHOD("set_ground_curve", "curve"), &ProceduralSky::set_ground_curve); + ClassDB::bind_method(D_METHOD("get_ground_curve"), &ProceduralSky::get_ground_curve); + + ClassDB::bind_method(D_METHOD("set_ground_energy", "energy"), &ProceduralSky::set_ground_energy); + ClassDB::bind_method(D_METHOD("get_ground_energy"), &ProceduralSky::get_ground_energy); + + ClassDB::bind_method(D_METHOD("set_sun_color", "color"), &ProceduralSky::set_sun_color); + ClassDB::bind_method(D_METHOD("get_sun_color"), &ProceduralSky::get_sun_color); + + ClassDB::bind_method(D_METHOD("set_sun_latitude", "degrees"), &ProceduralSky::set_sun_latitude); + ClassDB::bind_method(D_METHOD("get_sun_latitude"), &ProceduralSky::get_sun_latitude); + + ClassDB::bind_method(D_METHOD("set_sun_longitude", "degrees"), &ProceduralSky::set_sun_longitude); + ClassDB::bind_method(D_METHOD("get_sun_longitude"), &ProceduralSky::get_sun_longitude); + + ClassDB::bind_method(D_METHOD("set_sun_angle_min", "degrees"), &ProceduralSky::set_sun_angle_min); + ClassDB::bind_method(D_METHOD("get_sun_angle_min"), &ProceduralSky::get_sun_angle_min); + + ClassDB::bind_method(D_METHOD("set_sun_angle_max", "degrees"), &ProceduralSky::set_sun_angle_max); + ClassDB::bind_method(D_METHOD("get_sun_angle_max"), &ProceduralSky::get_sun_angle_max); + + ClassDB::bind_method(D_METHOD("set_sun_curve", "curve"), &ProceduralSky::set_sun_curve); + ClassDB::bind_method(D_METHOD("get_sun_curve"), &ProceduralSky::get_sun_curve); + + ClassDB::bind_method(D_METHOD("set_sun_energy", "energy"), &ProceduralSky::set_sun_energy); + ClassDB::bind_method(D_METHOD("get_sun_energy"), &ProceduralSky::get_sun_energy); + + ClassDB::bind_method(D_METHOD("set_texture_size", "size"), &ProceduralSky::set_texture_size); + ClassDB::bind_method(D_METHOD("get_texture_size"), &ProceduralSky::get_texture_size); + + ADD_GROUP("Sky", "sky_"); + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_top_color"), "set_sky_top_color", "get_sky_top_color"); + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_horizon_color"), "set_sky_horizon_color", "get_sky_horizon_color"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "sky_curve", PROPERTY_HINT_EXP_EASING), "set_sky_curve", "get_sky_curve"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "sky_energy", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_sky_energy", "get_sky_energy"); + + ADD_GROUP("Ground", "ground_"); + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ground_bottom_color"), "set_ground_bottom_color", "get_ground_bottom_color"); + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ground_horizon_color"), "set_ground_horizon_color", "get_ground_horizon_color"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "ground_curve", PROPERTY_HINT_EXP_EASING), "set_ground_curve", "get_ground_curve"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "ground_energy", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_ground_energy", "get_ground_energy"); + + ADD_GROUP("Sun", "sun_"); + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sun_color"), "set_sun_color", "get_sun_color"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "sun_latitude", PROPERTY_HINT_RANGE, "-180,180,0.01"), "set_sun_latitude", "get_sun_latitude"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "sun_longitude", PROPERTY_HINT_RANGE, "-180,180,0.01"), "set_sun_longitude", "get_sun_longitude"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "sun_angle_min", PROPERTY_HINT_RANGE, "0,360,0.01"), "set_sun_angle_min", "get_sun_angle_min"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "sun_angle_max", PROPERTY_HINT_RANGE, "0,360,0.01"), "set_sun_angle_max", "get_sun_angle_max"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "sun_curve", PROPERTY_HINT_EXP_EASING), "set_sun_curve", "get_sun_curve"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "sun_energy", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_sun_energy", "get_sun_energy"); + + ADD_GROUP("Texture", "texture_"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_size", PROPERTY_HINT_ENUM, "1024,2048,4096"), "set_texture_size", "get_texture_size"); +} + +ProceduralSky::ProceduralSky() { + + sky = VS::get_singleton()->sky_create(); + texture = VS::get_singleton()->texture_create(); + + update_queued = false; + + sky_top_color = Color::hex(0x4d67e8ff); + sky_horizon_color = Color::hex(0x8ed2e8ff); + sky_curve = 0.25; + sky_energy = 1; + + ground_bottom_color = Color::hex(0x322719ff); + ground_horizon_color = Color::hex(0x543610ff); + ground_curve = 0.25; + ground_energy = 1; + + sun_color = Color(1, 1, 1); + sun_latitude = 35; + sun_longitude = 0; + sun_angle_min = 1; + sun_angle_max = 100; + sun_curve = 0.05; + sun_energy = 16; + + texture_size = TEXTURE_SIZE_1024; + + _queue_update(); +} + +ProceduralSky::~ProceduralSky() { + + VS::get_singleton()->free(sky); + VS::get_singleton()->free(texture); +} diff --git a/scene/resources/sky_box.h b/scene/resources/sky_box.h index afbfb3019e4..7b707af3a64 100644 --- a/scene/resources/sky_box.h +++ b/scene/resources/sky_box.h @@ -62,17 +62,6 @@ VARIANT_ENUM_CAST(Sky::RadianceSize) class PanoramaSky : public Sky { GDCLASS(PanoramaSky, Sky); -public: - enum ImagePath { - IMAGE_PATH_NEGATIVE_X, - IMAGE_PATH_POSITIVE_X, - IMAGE_PATH_NEGATIVE_Y, - IMAGE_PATH_POSITIVE_Y, - IMAGE_PATH_NEGATIVE_Z, - IMAGE_PATH_POSITIVE_Z, - IMAGE_PATH_MAX - }; - private: RID sky; Ref panorama; @@ -91,6 +80,105 @@ public: ~PanoramaSky(); }; -VARIANT_ENUM_CAST(PanoramaSky::ImagePath) +class ProceduralSky : public Sky { + GDCLASS(ProceduralSky, Sky); + +public: + enum TextureSize { + TEXTURE_SIZE_1024, + TEXTURE_SIZE_2048, + TEXTURE_SIZE_4096, + TEXTURE_SIZE_MAX + }; + +private: + Color sky_top_color; + Color sky_horizon_color; + float sky_curve; + float sky_energy; + + Color ground_bottom_color; + Color ground_horizon_color; + float ground_curve; + float ground_energy; + + Color sun_color; + float sun_latitude; + float sun_longitude; + float sun_angle_min; + float sun_angle_max; + float sun_curve; + float sun_energy; + + TextureSize texture_size; + + RID sky; + RID texture; + + bool update_queued; + +protected: + static void _bind_methods(); + virtual void _radiance_changed(); + + void _update_sky(); + void _queue_update(); + +public: + void set_sky_top_color(const Color &p_sky_top); + Color get_sky_top_color() const; + + void set_sky_horizon_color(const Color &p_sky_horizon); + Color get_sky_horizon_color() const; + + void set_sky_curve(float p_curve); + float get_sky_curve() const; + + void set_sky_energy(float p_energy); + float get_sky_energy() const; + + void set_ground_bottom_color(const Color &p_ground_bottom); + Color get_ground_bottom_color() const; + + void set_ground_horizon_color(const Color &p_ground_horizon); + Color get_ground_horizon_color() const; + + void set_ground_curve(float p_curve); + float get_ground_curve() const; + + void set_ground_energy(float p_energy); + float get_ground_energy() const; + + void set_sun_color(const Color &p_sun); + Color get_sun_color() const; + + void set_sun_latitude(float p_angle); + float get_sun_latitude() const; + + void set_sun_longitude(float p_angle); + float get_sun_longitude() const; + + void set_sun_angle_min(float p_angle); + float get_sun_angle_min() const; + + void set_sun_angle_max(float p_angle); + float get_sun_angle_max() const; + + void set_sun_curve(float p_curve); + float get_sun_curve() const; + + void set_sun_energy(float p_energy); + float get_sun_energy() const; + + void set_texture_size(TextureSize p_size); + TextureSize get_texture_size() const; + + virtual RID get_rid() const; + + ProceduralSky(); + ~ProceduralSky(); +}; + +VARIANT_ENUM_CAST(ProceduralSky::TextureSize) #endif // Sky_H diff --git a/scene/resources/world.cpp b/scene/resources/world.cpp index eab7cf6098a..24551e91352 100644 --- a/scene/resources/world.cpp +++ b/scene/resources/world.cpp @@ -280,6 +280,20 @@ Ref World::get_environment() const { return environment; } +void World::set_fallback_environment(const Ref &p_environment) { + + fallback_environment = p_environment; + if (fallback_environment.is_valid()) + VS::get_singleton()->scenario_set_fallback_environment(scenario, p_environment->get_rid()); + else + VS::get_singleton()->scenario_set_fallback_environment(scenario, RID()); +} + +Ref World::get_fallback_environment() const { + + return fallback_environment; +} + PhysicsDirectSpaceState *World::get_direct_space_state() { return PhysicsServer::get_singleton()->space_get_direct_state(space); @@ -291,8 +305,11 @@ void World::_bind_methods() { ClassDB::bind_method(D_METHOD("get_scenario"), &World::get_scenario); ClassDB::bind_method(D_METHOD("set_environment", "env:Environment"), &World::set_environment); ClassDB::bind_method(D_METHOD("get_environment:Environment"), &World::get_environment); + ClassDB::bind_method(D_METHOD("set_fallback_environment", "env:Environment"), &World::set_fallback_environment); + ClassDB::bind_method(D_METHOD("get_fallback_environment:Environment"), &World::get_fallback_environment); ClassDB::bind_method(D_METHOD("get_direct_space_state:PhysicsDirectSpaceState"), &World::get_direct_space_state); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"), "set_environment", "get_environment"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "fallback_environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"), "set_fallback_environment", "get_fallback_environment"); } World::World() { diff --git a/scene/resources/world.h b/scene/resources/world.h index f2c85f31f6c..96857a577a1 100644 --- a/scene/resources/world.h +++ b/scene/resources/world.h @@ -48,6 +48,7 @@ private: RID scenario; SpatialIndexer *indexer; Ref environment; + Ref fallback_environment; protected: static void _bind_methods(); @@ -68,9 +69,13 @@ protected: public: RID get_space() const; RID get_scenario() const; + void set_environment(const Ref &p_environment); Ref get_environment() const; + void set_fallback_environment(const Ref &p_environment); + Ref get_fallback_environment() const; + PhysicsDirectSpaceState *get_direct_space_state(); World();