Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Transform snapping moved to AdvancedSettings #46614

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion core/engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "core/authors.gen.h"
#include "core/donors.gen.h"
#include "core/license.gen.h"
#include "core/snappers.h"
#include "core/version.h"
#include "core/version_hash.gen.h"

Expand Down Expand Up @@ -228,13 +229,21 @@ Engine::Engine() {
_target_fps = 0;
_time_scale = 1.0;
_gpu_pixel_snap = false;
_snap_2d_transforms = false;
_physics_frames = 0;
_idle_frames = 0;
_in_physics = false;
_frame_ticks = 0;
_frame_step = 0;
editor_hint = false;

_snappers = memnew(Snappers);
}

Engine::~Engine() {
if (_snappers) {
memdelete(_snappers);
_snappers = nullptr;
}
}

Engine::Singleton::Singleton(const StringName &p_name, Object *p_ptr) :
Expand Down
14 changes: 8 additions & 6 deletions core/engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
#include "core/ustring.h"
#include "core/vector.h"

class Snappers;

class Engine {

public:
Expand All @@ -58,15 +60,15 @@ class Engine {
float _fps;
int _target_fps;
float _time_scale;
bool _gpu_pixel_snap;
bool _snap_2d_transforms;
bool _snap_2d_viewports;
uint64_t _physics_frames;
float _physics_interpolation_fraction;

uint64_t _idle_frames;
bool _in_physics;

bool _gpu_pixel_snap;
Snappers *_snappers;

List<Singleton> singletons;
Map<StringName, Object *> singleton_ptrs;

Expand Down Expand Up @@ -109,8 +111,8 @@ class Engine {
Object *get_singleton_object(const String &p_name) const;

_FORCE_INLINE_ bool get_use_gpu_pixel_snap() const { return _gpu_pixel_snap; }
bool get_snap_2d_transforms() const { return _snap_2d_transforms; }
bool get_snap_2d_viewports() const { return _snap_2d_viewports; }
const Snappers &get_snappers() const { return *_snappers; }
Snappers &get_snappers() { return *_snappers; }

#ifdef TOOLS_ENABLED
_FORCE_INLINE_ void set_editor_hint(bool p_enabled) { editor_hint = p_enabled; }
Expand All @@ -128,7 +130,7 @@ class Engine {
String get_license_text() const;

Engine();
virtual ~Engine() {}
virtual ~Engine();
};

#endif // ENGINE_H
74 changes: 74 additions & 0 deletions core/snappers.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*************************************************************************/
/* snappers.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 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 "snappers.h"
#include "core/project_settings.h"

void Snappers::snap_read_item(Vector2 &r_pos) const {
if (snapper_canvas_item_read.is_enabled()) {
snapper_canvas_item_read.snap(r_pos);
} else if (_gpu_snap_enabled) {
r_pos = r_pos.floor();
}
}

void Snappers::set_stretch_mode(String p_mode) {
_stretch_mode_viewport = p_mode == "viewport";
}

void Snappers::set_transform_snap_2d(AdvancedSettings::Snap2DType p_type, AdvancedSettings::RoundMode p_mode_x, AdvancedSettings::RoundMode p_mode_y) {
switch (p_type) {
case AdvancedSettings::SNAP2D_TYPE_ITEM_PRE: {
snapper_canvas_item_pre.set_snap_modes(p_mode_x, p_mode_y);
} break;
case AdvancedSettings::SNAP2D_TYPE_ITEM_POST: {
snapper_canvas_item_post.set_snap_modes(p_mode_x, p_mode_y);
} break;
case AdvancedSettings::SNAP2D_TYPE_ITEM_READ: {
snapper_canvas_item_read.set_snap_modes(p_mode_x, p_mode_y);
} break;
case AdvancedSettings::SNAP2D_TYPE_VIEWPORT_PRE: {
snapper_viewport_pre.set_snap_modes(p_mode_x, p_mode_y);
} break;
case AdvancedSettings::SNAP2D_TYPE_VIEWPORT_POST: {
snapper_viewport_post.set_snap_modes(p_mode_x, p_mode_y);
} break;
case AdvancedSettings::SNAP2D_TYPE_VIEWPORT_PARENT_PRE: {
snapper_viewport_parent_pre.set_snap_modes(p_mode_x, p_mode_y);
} break;
default: {
} break;
}
}

void Snappers::initialize(bool p_gpu_snap) {
_gpu_snap_enabled = p_gpu_snap;
_snap_transforms_enabled = false;
}
108 changes: 108 additions & 0 deletions core/snappers.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/*************************************************************************/
/* snappers.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 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 SNAPPERS_H
#define SNAPPERS_H

#include "core/math/math_funcs.h"
#include "core/math/vector2.h"
#include "scene/main/advanced_settings.h"

// generic class for handling 2d snapping
class Snapper2D {
public:
void snap(Vector2 &r_pos) const {
if (!_enabled) {
return;
}

r_pos.x = snap_value(r_pos.x, _snap_mode_x);
r_pos.y = snap_value(r_pos.y, _snap_mode_y);
}

void set_snap_modes(AdvancedSettings::RoundMode p_mode_x, AdvancedSettings::RoundMode p_mode_y) {
_snap_mode_x = p_mode_x;
_snap_mode_y = p_mode_y;
_enabled = !((_snap_mode_x == AdvancedSettings::ROUND_MODE_DISABLED) && (_snap_mode_y == AdvancedSettings::ROUND_MODE_DISABLED));
}

bool is_enabled() const { return _enabled; }

private:
real_t snap_value(real_t p_value, AdvancedSettings::RoundMode p_mode) const {
switch (p_mode) {
default:
break;
case AdvancedSettings::ROUND_MODE_FLOOR: {
return Math::floor(p_value);
} break;
case AdvancedSettings::ROUND_MODE_CEILING: {
return Math::ceil(p_value);
} break;
case AdvancedSettings::ROUND_MODE_ROUND: {
return Math::round(p_value);
} break;
}
return p_value;
}

bool _enabled = false;
AdvancedSettings::RoundMode _snap_mode_x = AdvancedSettings::ROUND_MODE_DISABLED;
AdvancedSettings::RoundMode _snap_mode_y = AdvancedSettings::ROUND_MODE_DISABLED;
};

// All the 2D snapping in one place.
// This is called from the various places it needs to be introduced, but the logic
// can be self contained here to make it easier to change / debug.
class Snappers {
public:
void initialize(bool p_gpu_snap);
void set_stretch_mode(String p_mode);
void set_transform_snap_2d(AdvancedSettings::Snap2DType p_type, AdvancedSettings::RoundMode p_mode_x, AdvancedSettings::RoundMode p_mode_y);

// for positioning of sprites etc, not the main draw call
void snap_read_item(Vector2 &r_pos) const;

Snapper2D snapper_canvas_item_pre;
Snapper2D snapper_canvas_item_post;
Snapper2D snapper_canvas_item_read;

Snapper2D snapper_viewport_pre;
Snapper2D snapper_viewport_post;
Snapper2D snapper_viewport_parent_pre;

private:
// local version
bool _gpu_snap_enabled = false;
bool _snap_transforms_enabled = false;
bool _stretch_mode_viewport = false;
};

#endif // SNAPPERS_H
62 changes: 62 additions & 0 deletions doc/classes/AdvancedSettings.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="AdvancedSettings" inherits="Reference" version="3.2">
<brief_description>
Access to engine advanced settings.
</brief_description>
<description>
</description>
<tutorials>
</tutorials>
<methods>
<method name="set_transform_snap_2d">
<return type="void">
</return>
<argument index="0" name="snap_type" type="int" enum="AdvancedSettings.Snap2DType">
</argument>
<argument index="1" name="mode_x" type="int" enum="AdvancedSettings.RoundMode">
Round mode applied to x coordinate.
</argument>
<argument index="2" name="mode_y" type="int" enum="AdvancedSettings.RoundMode">
Round mode applied to y coordinate.
Note that in Godot 2D, y increases down the screen, so using ceiling mode may give a better result than floor.
</argument>
<description>
Gives total control over CPU transform snapping.
The engine defaults to all transform snapping disabled, but you can specify rounding modes for each part of the 2d pipeline. Items are items to be drawn, and viewports normally equate to cameras.
In general, for [code]viewport[/code] window stretch mode, pre transform snapping is most relevant, and for [code]2d[/code] window stretch mode, post transform snapping is most relevant.
</description>
</method>
</methods>
<constants>
<constant name="SNAP2D_TYPE_ITEM_PRE" value="0" enum="Snap2DType">
Snap the item local position when drawing.
</constant>
<constant name="SNAP2D_TYPE_ITEM_POST" value="1" enum="Snap2DType">
Snap the item position after applying parent transform when drawing.
</constant>
<constant name="SNAP2D_TYPE_ITEM_READ" value="2" enum="Snap2DType">
Snap the item local position when reading.
</constant>
<constant name="SNAP2D_TYPE_VIEWPORT_PRE" value="3" enum="Snap2DType">
Snap canvas position.
</constant>
<constant name="SNAP2D_TYPE_VIEWPORT_POST" value="4" enum="Snap2DType">
Snap canvas position after applying global transform.
</constant>
<constant name="SNAP2D_TYPE_VIEWPORT_PARENT_PRE" value="5" enum="Snap2DType">
Snap canvas parent transform.
</constant>
<constant name="ROUND_MODE_DISABLED" value="0" enum="RoundMode">
No snapping applied.
</constant>
<constant name="ROUND_MODE_FLOOR" value="1" enum="RoundMode">
Snapping uses floor function (rounds down to the nearest whole number).
</constant>
<constant name="ROUND_MODE_CEILING" value="2" enum="RoundMode">
Snapping uses ceiling function (rounds up to the nearest whole number).
</constant>
<constant name="ROUND_MODE_ROUND" value="3" enum="RoundMode">
Snapping uses round function (rounds to the nearest whole number).
</constant>
</constants>
</class>
8 changes: 0 additions & 8 deletions doc/classes/ProjectSettings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1044,19 +1044,11 @@
Currently only available when [member rendering/batching/options/use_batching] is active.
[b]Note:[/b] Antialiased software skinned polys are not supported, and will be rendered without antialiasing.
</member>
<member name="rendering/2d/snapping/use_camera_snap" type="bool" setter="" getter="" default="false">
If [code]true[/code], forces snapping of 2D viewports to the nearest whole coordinate.
Can reduce unwanted camera relative movement in pixel art styles.
</member>
<member name="rendering/2d/snapping/use_gpu_pixel_snap" type="bool" setter="" getter="" default="false">
If [code]true[/code], forces snapping of vertices to pixels in 2D rendering. May help in some pixel art styles.
This snapping is performed on the GPU in the vertex shader.
Consider using the project setting [member rendering/batching/precision/uv_contract] to prevent artifacts.
</member>
<member name="rendering/2d/snapping/use_transform_snap" type="bool" setter="" getter="" default="false">
If [code]true[/code], forces snapping of 2D object transforms to the nearest whole coordinate.
Can help prevent unwanted relative movement in pixel art styles.
</member>
<member name="rendering/batching/debug/diagnose_frame" type="bool" setter="" getter="" default="false">
When batching is on, this regularly prints a frame diagnosis log. Note that this will degrade performance.
</member>
Expand Down
11 changes: 8 additions & 3 deletions main/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#include "core/register_core_types.h"
#include "core/script_debugger_local.h"
#include "core/script_language.h"
#include "core/snappers.h"
#include "core/translation.h"
#include "core/version.h"
#include "core/version_hash.gen.h"
Expand Down Expand Up @@ -1125,8 +1126,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
}

Engine::get_singleton()->_gpu_pixel_snap = GLOBAL_DEF("rendering/2d/snapping/use_gpu_pixel_snap", false);
Engine::get_singleton()->_snap_2d_transforms = GLOBAL_DEF("rendering/2d/snapping/use_transform_snap", false);
Engine::get_singleton()->_snap_2d_viewports = GLOBAL_DEF("rendering/2d/snapping/use_camera_snap", false);
Engine::get_singleton()->_snappers->initialize(Engine::get_singleton()->get_use_gpu_pixel_snap());

OS::get_singleton()->_keep_screen_on = GLOBAL_DEF("display/window/energy_saving/keep_screen_on", true);
if (rtm == -1) {
rtm = GLOBAL_DEF("rendering/threads/thread_model", OS::RENDER_THREAD_SAFE);
Expand Down Expand Up @@ -1823,11 +1824,15 @@ bool Main::start() {
Size2i stretch_size = Size2(GLOBAL_DEF("display/window/size/width", 0), GLOBAL_DEF("display/window/size/height", 0));
real_t stretch_shrink = GLOBAL_DEF("display/window/stretch/shrink", 1.0);

// the snappers need to know the stretch_mode
Engine::get_singleton()->_snappers->set_stretch_mode(stretch_mode);

SceneTree::StretchMode sml_sm = SceneTree::STRETCH_MODE_DISABLED;
if (stretch_mode == "2d")
sml_sm = SceneTree::STRETCH_MODE_2D;
else if (stretch_mode == "viewport")
else if (stretch_mode == "viewport") {
sml_sm = SceneTree::STRETCH_MODE_VIEWPORT;
}

SceneTree::StretchAspect sml_aspect = SceneTree::STRETCH_ASPECT_IGNORE;
if (stretch_aspect == "keep")
Expand Down
Loading