Compare commits
196 Commits
Author | SHA1 | Date |
---|---|---|
Rémi Verschelde | 6699ae7897 | |
Rémi Verschelde | 53cde2eb85 | |
Rémi Verschelde | 6225d39826 | |
patwork | 3a2804a7e7 | |
Silc Lizard (Tokage) Renew | 7b32e96f3d | |
Hilderin | 15129c044e | |
Raffaele Picca | 56a1d07421 | |
Pedro J. Estébanez | 2c612abdd1 | |
Rémi Verschelde | f273c7c773 | |
Rémi Verschelde | 99a8821a71 | |
Rémi Verschelde | 7a7e4129bd | |
Rémi Verschelde | 4abc358952 | |
Robert Cadena | f7ad4dca8c | |
bruvzg | 35b4a1f374 | |
bruvzg | 4944d59198 | |
Mounir Tohami | 0a83f06608 | |
HolonProduction | 03168cc9d1 | |
Silc Lizard (Tokage) Renew | 47f34e8436 | |
Daylily-Zeleen | abe68d397e | |
Hilderin | 7246e1488e | |
HolonProduction | a2e3c13451 | |
Pedro J. Estébanez | 3030d4b806 | |
Pedro J. Estébanez | 018f8be3d5 | |
Lisandro Lorea | d92f9017c6 | |
A Thousand Ships | 34251cf5b3 | |
Giganzo | d00e4fbb16 | |
Giganzo | 927d7a9250 | |
Giganzo | 13701384ab | |
Hristo Iliev | f4b71b5325 | |
DeeJayLSP | 51c86eb085 | |
BlueCube3310 | 4addddd8df | |
Dowsley | 6dd8e7fece | |
bruvzg | 69713dadf0 | |
Mikael Hermansson | 90f1c3e7bd | |
A Thousand Ships | d51be1f68d | |
Rudolph Bester | 3fac9e43af | |
Haoyu Qiu | 1d790deedb | |
kleonc | 88370e44d8 | |
shahriarlabib000 | c7a173aa60 | |
Yaohua Xiong | e7e723b3e3 | |
Praytic | 281642831c | |
bruvzg | 6b7f36e2a9 | |
Pedro J. Estébanez | f757cc9a70 | |
ajreckof | cab91cf8fb | |
Adam Scott | 0b815cbb99 | |
Pedro J. Estébanez | f11f9e3b7f | |
A Thousand Ships | b2b882cc1d | |
Gustavo Jaruga Cruz | f5b5b6cbfe | |
RedMser | 02c45088ea | |
RedMser | 7f0cc1aa35 | |
kleonc | 21a0a84c6f | |
jsjtxietian | fb1758ce23 | |
Danil Alexeev | c4525f24e3 | |
Giganzo | 61b2ad9242 | |
smix8 | d7a8654edd | |
Giganzo | 1629e9b1fa | |
A Thousand Ships | 3783527410 | |
A Thousand Ships | 00866dc80a | |
Hilderin | d842870331 | |
detomon | 2635ff777e | |
ev13bird | cbcc5f8d19 | |
A Thousand Ships | 64cbde426f | |
bruvzg | b1c1c40250 | |
clayjohn | e09cada53f | |
Alexis Breust | 2b05cf154a | |
Arsh Panesar | 26cc13705a | |
Radiant | af8caffd0e | |
aaronp64 | ec20c3ff76 | |
aaronp64 | a2f64b3c10 | |
kobewi | fc5e7c7411 | |
Giganzo | 1e5d7a0907 | |
Hilderin | 4d0f10a543 | |
kerstop | f8c9ec3f37 | |
bruvzg | fd17fae4bd | |
clayjohn | b1fda8f5c4 | |
clayjohn | 1250b4568a | |
ComycSans | 430a69baed | |
Silc Lizard (Tokage) Renew | b60bf28a2f | |
NotWearingPants | 5567fedd04 | |
Fabio Alessandrelli | 1a5ac1fd59 | |
Haoyu Qiu | e72e42fe9b | |
Lars Pettersson | f783cf7b81 | |
viksl | f3848b75cb | |
David Snopek | 19843328d9 | |
Hilderin | 1e9f578740 | |
clayjohn | 0a1724f713 | |
Leonardo Demartino | e79157af72 | |
Hristo Iliev | 6ab9ec33f2 | |
MBCX | 4acc73dbfa | |
kleonc | e549ab35fa | |
RedOrbweaver | 43fa723659 | |
passivestar | 1c9ba616d5 | |
DeeJayLSP | 682ee73f64 | |
David Snopek | 9946eba398 | |
Saracen | 30bba8745c | |
Togira | c4351c8d98 | |
jsjtxietian | e2184c5da0 | |
kit | 4fabc1ba58 | |
kleonc | 4d7feff723 | |
Fabio Alessandrelli | 1d775b5b97 | |
bruvzg | b6055941b9 | |
Sen | e5be133032 | |
Fredia Huya-Kouadio | 0f33a4b97e | |
Rakka Rage | f9bcd4f0ca | |
Jason Wodicka | 169b568e65 | |
Mikael Hermansson | 95a0525361 | |
BlueCube3310 | 8e1d1a54fe | |
Paul Joannon | 99dde70ad3 | |
bruvzg | e59f59a439 | |
Joel Winarske | afc330e33f | |
Adam Scott | 219ddde30c | |
kobewi | 2dd696867f | |
Dungeon Master | 9cf21b4b03 | |
Tallivm | 497570b1cf | |
David Snopek | 70a8761deb | |
Z0rb14n | 19bed8fee7 | |
aaronp64 | 7874dad279 | |
jsjtxietian | 05860062a5 | |
Hilderin | 8496e0738f | |
tetrapod00 | 20ce427a6c | |
Arseny Kapoulkine | 40dcdcbe79 | |
Arseny Kapoulkine | b2c83b42f6 | |
Giganzo | cf40a5bc5a | |
Mikael Hermansson | 1ecf20c783 | |
Hilderin | b05470efd0 | |
aryan-11825114 | 433509b489 | |
jsjtxietian | 139f5ee15e | |
matheusmdx | bd552ff609 | |
Orion Lawlor | ecbb9a9c6a | |
Juan Pablo Arce | d0c4f19dd2 | |
kleonc | df6bbb2538 | |
Aaron Franke | 1d0bcae019 | |
voidedWarranties | df522db6f0 | |
clayjohn | c684d65c64 | |
Pedro J. Estébanez | 5676d398e0 | |
jordi | 32f2b851ab | |
Gergely Kis | bf5907b724 | |
Robert Yevdokimov | cff0ebd603 | |
MrPersonDev | 9af6e04a15 | |
Hilderin | 39fb871310 | |
Silc Lizard (Tokage) Renew | eaa8ecb182 | |
kleonc | c7dbcbd6d4 | |
kleonc | f0f69a7b7c | |
Artemy Fedotov | 4168220169 | |
Hilderin | d8c13f88ed | |
Radiant | 7266418bdf | |
Hilderin | b7fc063038 | |
clayjohn | 6c202154a7 | |
Rémi Verschelde | 6d41487459 | |
Cory Petkovsek | 3876287162 | |
Kusok | 8ea64814ed | |
Nodragem | 6b323241b1 | |
clayjohn | 2d7266e764 | |
Rio Arswendo Rachmad | 7726ced085 | |
jsjtxietian | bba8f85945 | |
Juan Pablo Arce | 63ff665fd0 | |
Joel Croteau | 6e78eec37f | |
ocean | 6eea970e8c | |
kevinkuo52 | 6aff947ee5 | |
bruvzg | 686591b948 | |
Jiří Švejda | acba31b746 | |
kleonc | d915947f3d | |
kleonc | a031407e82 | |
Fredia Huya-Kouadio | 26b151a945 | |
tetrapod00 | 2eb2052cb9 | |
kit | 1f92092b08 | |
Pedro J. Estébanez | c831bdbbe2 | |
smix8 | ea5989e3f5 | |
Jordyfel | 6073b86e71 | |
jsjtxietian | b84dbab84d | |
Michael Alexsander | 1ebf488a4e | |
Hilderin | 4a64c95732 | |
Yahkub-R | 2b4ade1ed6 | |
Haoyu Qiu | 562e583872 | |
Ian McCleary | cfa33666c9 | |
Chaosus | 3dc376ec0b | |
bruvzg | a7d79f9e6c | |
bruvzg | fac12603ef | |
bruvzg | 8c5edcb03a | |
bruvzg | 79848620ce | |
Jonatan Röjder Delnavaz | 91ed3cd307 | |
aaronp64 | 302af188a1 | |
Zi Ye | 2eec361f5f | |
jsjtxietian | a70df8537e | |
clayjohn | cbee16418a | |
clayjohn | 5a33e45fed | |
Hugo Locurcio | 6595395b8b | |
Miley Hollenberg | a7756d530e | |
Kyle Appelgate | 2df506ea15 | |
Slashscreen | 13d5227911 | |
Chris Cranford | b9271608df | |
Silc Lizard (Tokage) Renew | 5caaa6ce19 | |
David Snopek | e1af61467a | |
Rémi Verschelde | d40fc50f08 | |
Bastiaan Olij | 620cc30f2a | |
Rémi Verschelde | ff9bc04223 |
|
@ -5,7 +5,7 @@ on:
|
||||||
# Global Settings
|
# Global Settings
|
||||||
env:
|
env:
|
||||||
# Used for the cache key. Add version suffix to force clean build.
|
# Used for the cache key. Add version suffix to force clean build.
|
||||||
GODOT_BASE_BRANCH: master
|
GODOT_BASE_BRANCH: 4.3
|
||||||
SCONSFLAGS: verbose=yes warnings=extra werror=yes debug_symbols=no module_text_server_fb_enabled=yes
|
SCONSFLAGS: verbose=yes warnings=extra werror=yes debug_symbols=no module_text_server_fb_enabled=yes
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
|
|
|
@ -5,7 +5,7 @@ on:
|
||||||
# Global Settings
|
# Global Settings
|
||||||
env:
|
env:
|
||||||
# Used for the cache key. Add version suffix to force clean build.
|
# Used for the cache key. Add version suffix to force clean build.
|
||||||
GODOT_BASE_BRANCH: master
|
GODOT_BASE_BRANCH: 4.3
|
||||||
# Used for the godot-cpp checkout.
|
# Used for the godot-cpp checkout.
|
||||||
GODOT_CPP_BRANCH: '4.2'
|
GODOT_CPP_BRANCH: '4.2'
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ on:
|
||||||
# Global Settings
|
# Global Settings
|
||||||
env:
|
env:
|
||||||
# Used for the cache key. Add version suffix to force clean build.
|
# Used for the cache key. Add version suffix to force clean build.
|
||||||
GODOT_BASE_BRANCH: master
|
GODOT_BASE_BRANCH: 4.3
|
||||||
SCONSFLAGS: verbose=yes warnings=extra werror=yes debug_symbols=no module_text_server_fb_enabled=yes
|
SCONSFLAGS: verbose=yes warnings=extra werror=yes debug_symbols=no module_text_server_fb_enabled=yes
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
|
|
|
@ -5,7 +5,7 @@ on:
|
||||||
# Global Settings
|
# Global Settings
|
||||||
env:
|
env:
|
||||||
# Used for the cache key. Add version suffix to force clean build.
|
# Used for the cache key. Add version suffix to force clean build.
|
||||||
GODOT_BASE_BRANCH: master
|
GODOT_BASE_BRANCH: 4.3
|
||||||
SCONSFLAGS: verbose=yes warnings=extra werror=yes module_text_server_fb_enabled=yes
|
SCONSFLAGS: verbose=yes warnings=extra werror=yes module_text_server_fb_enabled=yes
|
||||||
DOTNET_NOLOGO: true
|
DOTNET_NOLOGO: true
|
||||||
DOTNET_CLI_TELEMETRY_OPTOUT: true
|
DOTNET_CLI_TELEMETRY_OPTOUT: true
|
||||||
|
|
|
@ -5,7 +5,7 @@ on:
|
||||||
# Global Settings
|
# Global Settings
|
||||||
env:
|
env:
|
||||||
# Used for the cache key. Add version suffix to force clean build.
|
# Used for the cache key. Add version suffix to force clean build.
|
||||||
GODOT_BASE_BRANCH: master
|
GODOT_BASE_BRANCH: 4.3
|
||||||
SCONSFLAGS: verbose=yes warnings=extra werror=yes module_text_server_fb_enabled=yes
|
SCONSFLAGS: verbose=yes warnings=extra werror=yes module_text_server_fb_enabled=yes
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
|
|
|
@ -5,7 +5,7 @@ on:
|
||||||
# Global Settings
|
# Global Settings
|
||||||
env:
|
env:
|
||||||
# Used for the cache key. Add version suffix to force clean build.
|
# Used for the cache key. Add version suffix to force clean build.
|
||||||
GODOT_BASE_BRANCH: master
|
GODOT_BASE_BRANCH: 4.3
|
||||||
SCONSFLAGS: verbose=yes warnings=extra werror=yes debug_symbols=no use_closure_compiler=yes
|
SCONSFLAGS: verbose=yes warnings=extra werror=yes debug_symbols=no use_closure_compiler=yes
|
||||||
EM_VERSION: 3.1.64
|
EM_VERSION: 3.1.64
|
||||||
EM_CACHE_FOLDER: "emsdk-cache"
|
EM_CACHE_FOLDER: "emsdk-cache"
|
||||||
|
|
|
@ -6,7 +6,7 @@ on:
|
||||||
# SCONS_CACHE for windows must be set in the build environment
|
# SCONS_CACHE for windows must be set in the build environment
|
||||||
env:
|
env:
|
||||||
# Used for the cache key. Add version suffix to force clean build.
|
# Used for the cache key. Add version suffix to force clean build.
|
||||||
GODOT_BASE_BRANCH: master
|
GODOT_BASE_BRANCH: 4.3
|
||||||
SCONSFLAGS: verbose=yes warnings=extra werror=yes module_text_server_fb_enabled=yes d3d12=yes "angle_libs=${{github.workspace}}/"
|
SCONSFLAGS: verbose=yes warnings=extra werror=yes module_text_server_fb_enabled=yes d3d12=yes "angle_libs=${{github.workspace}}/"
|
||||||
SCONS_CACHE_MSVC_CONFIG: true
|
SCONS_CACHE_MSVC_CONFIG: true
|
||||||
|
|
||||||
|
|
3
.mailmap
3
.mailmap
|
@ -84,6 +84,7 @@ Jean-Michel Bernard <jmb462@gmail.com>
|
||||||
Jérôme Gully <jerome.gully0@gmail.com>
|
Jérôme Gully <jerome.gully0@gmail.com>
|
||||||
JFonS <joan.fonssanchez@gmail.com>
|
JFonS <joan.fonssanchez@gmail.com>
|
||||||
jitspoe <jitspoe@yahoo.com> <jitspoeAyahoooDcom>
|
jitspoe <jitspoe@yahoo.com> <jitspoeAyahoooDcom>
|
||||||
|
Johan Aires Rastén <johan@oljud.se>
|
||||||
Juan Linietsky <reduzio@gmail.com>
|
Juan Linietsky <reduzio@gmail.com>
|
||||||
Juan Linietsky <reduzio@gmail.com> <juan@godotengine.org>
|
Juan Linietsky <reduzio@gmail.com> <juan@godotengine.org>
|
||||||
Juan Linietsky <reduzio@gmail.com> <juan@okamstudio.com>
|
Juan Linietsky <reduzio@gmail.com> <juan@okamstudio.com>
|
||||||
|
@ -97,6 +98,7 @@ karroffel <therzog@mail.de> <thomas.herzog@simedis.com>
|
||||||
Kelly Thomas <kelly.thomas@hotmail.com.au>
|
Kelly Thomas <kelly.thomas@hotmail.com.au>
|
||||||
Kongfa Waroros <gongpha@hotmail.com>
|
Kongfa Waroros <gongpha@hotmail.com>
|
||||||
K. S. Ernest (iFire) Lee <ernest.lee@chibifire.com>
|
K. S. Ernest (iFire) Lee <ernest.lee@chibifire.com>
|
||||||
|
K. S. Ernest (iFire) Lee <ernest.lee@chibifire.com> <fire@users.noreply.github.com>
|
||||||
kleonc <9283098+kleonc@users.noreply.github.com> <kleonc@users.noreply.github.com>
|
kleonc <9283098+kleonc@users.noreply.github.com> <kleonc@users.noreply.github.com>
|
||||||
Leon Krause <lk@leonkrause.com> <eska@eska.me>
|
Leon Krause <lk@leonkrause.com> <eska@eska.me>
|
||||||
Leon Krause <lk@leonkrause.com> <eska014@users.noreply.github.com>
|
Leon Krause <lk@leonkrause.com> <eska014@users.noreply.github.com>
|
||||||
|
@ -142,6 +144,7 @@ Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
|
||||||
Pieter-Jan Briers <pieterjan.briers+git@gmail.com> <pieterjan.briers@gmail.com>
|
Pieter-Jan Briers <pieterjan.briers+git@gmail.com> <pieterjan.briers@gmail.com>
|
||||||
Poommetee Ketson <poommetee@protonmail.com>
|
Poommetee Ketson <poommetee@protonmail.com>
|
||||||
Przemysław Gołąb (n-pigeon) <golab.przemyslaw@gmail.com>
|
Przemysław Gołąb (n-pigeon) <golab.przemyslaw@gmail.com>
|
||||||
|
Radiant <69520693+RadiantUwU@users.noreply.github.com> <i.like.using.discord@gmail.com>
|
||||||
Rafał Mikrut <mikrutrafal@protonmail.com>
|
Rafał Mikrut <mikrutrafal@protonmail.com>
|
||||||
Rafał Mikrut <mikrutrafal@protonmail.com> <mikrutrafal54@gmail.com>
|
Rafał Mikrut <mikrutrafal@protonmail.com> <mikrutrafal54@gmail.com>
|
||||||
Ralf Hölzemer <r.hoelzemer@posteo.de> <rollenrolm@posteo.de>
|
Ralf Hölzemer <r.hoelzemer@posteo.de> <rollenrolm@posteo.de>
|
||||||
|
|
34
AUTHORS.md
34
AUTHORS.md
|
@ -1,11 +1,17 @@
|
||||||
# Godot Engine authors
|
# Godot Engine authors
|
||||||
|
|
||||||
Godot Engine is developed by a community of voluntary contributors who
|
Godot Engine is developed by a community of voluntary contributors who
|
||||||
contribute code, bug reports, documentation, artwork, support, etc.
|
contribute code, bug reports, documentation, translations, support, etc.,
|
||||||
|
across multiple repositories.
|
||||||
|
|
||||||
It is impossible to list them all; nevertheless, this file aims at listing
|
It is impossible to list them all; nevertheless, this file aims at listing
|
||||||
the developers who contributed significant patches to this MIT licensed
|
the developers who contributed significant improvements to the engine code.
|
||||||
source code. "Significant" is arbitrarily decided, but should be fair :)
|
|
||||||
|
To keep the list curated, we use a threshold of a minimum of 11 commits.
|
||||||
|
|
||||||
|
This file does not strictly reflect copyright ownership for the engine
|
||||||
|
source code. For this, refer to the Git history to know which contributor
|
||||||
|
wrote which part of the codebase.
|
||||||
|
|
||||||
GitHub usernames are indicated in parentheses, or as sole entry when no other
|
GitHub usernames are indicated in parentheses, or as sole entry when no other
|
||||||
name is available.
|
name is available.
|
||||||
|
@ -25,8 +31,6 @@ name is available.
|
||||||
|
|
||||||
## Developers
|
## Developers
|
||||||
|
|
||||||
(in alphabetical order, with over 10 commits excluding merges)
|
|
||||||
|
|
||||||
Aaron Franke (aaronfranke)
|
Aaron Franke (aaronfranke)
|
||||||
Aaron Pagano (aaronp64)
|
Aaron Pagano (aaronp64)
|
||||||
Aaron Record (LightningAA)
|
Aaron Record (LightningAA)
|
||||||
|
@ -38,6 +42,7 @@ name is available.
|
||||||
Alfred Reinold Baudisch (alfredbaudisch)
|
Alfred Reinold Baudisch (alfredbaudisch)
|
||||||
Alistair Leslie-Hughes (alesliehughes)
|
Alistair Leslie-Hughes (alesliehughes)
|
||||||
Alket Rexhepi (alketii)
|
Alket Rexhepi (alketii)
|
||||||
|
Alvin Wong (alvinhochun)
|
||||||
Andrea Catania (AndreaCatania)
|
Andrea Catania (AndreaCatania)
|
||||||
Andreia Gaita (shana)
|
Andreia Gaita (shana)
|
||||||
Andrii Doroshenko (Xrayez)
|
Andrii Doroshenko (Xrayez)
|
||||||
|
@ -46,11 +51,13 @@ name is available.
|
||||||
Angad Kambli (angad-k)
|
Angad Kambli (angad-k)
|
||||||
Anilforextra (AnilBK)
|
Anilforextra (AnilBK)
|
||||||
Anish Bhobe (KidRigger)
|
Anish Bhobe (KidRigger)
|
||||||
|
Anni Ryynänen (anniryynanen)
|
||||||
Anton Yabchinskiy (a12n)
|
Anton Yabchinskiy (a12n)
|
||||||
Anutrix
|
Anutrix
|
||||||
Aren Villanueva (kurikaesu)
|
Aren Villanueva (kurikaesu)
|
||||||
Ariel Manzur (punto-)
|
Ariel Manzur (punto-)
|
||||||
Arman Elgudzhyan (puchik)
|
Arman Elgudzhyan (puchik)
|
||||||
|
Arseny Kapoulkine (zeux)
|
||||||
AThousandShips
|
AThousandShips
|
||||||
aXu-AP
|
aXu-AP
|
||||||
Bartłomiej T. Listwon (Listwon)
|
Bartłomiej T. Listwon (Listwon)
|
||||||
|
@ -72,6 +79,7 @@ name is available.
|
||||||
Carter Anderson (cart)
|
Carter Anderson (cart)
|
||||||
ChibiDenDen
|
ChibiDenDen
|
||||||
Chris Bradfield (cbscribe)
|
Chris Bradfield (cbscribe)
|
||||||
|
Chris Cranford (Naros)
|
||||||
Christian Kaiser (ckaiser)
|
Christian Kaiser (ckaiser)
|
||||||
Clay John (clayjohn)
|
Clay John (clayjohn)
|
||||||
ConteZero
|
ConteZero
|
||||||
|
@ -86,7 +94,9 @@ name is available.
|
||||||
David Cambré (Gallilus)
|
David Cambré (Gallilus)
|
||||||
David Sichma (DavidSichma)
|
David Sichma (DavidSichma)
|
||||||
David Snopek (dsnopek)
|
David Snopek (dsnopek)
|
||||||
|
derammo
|
||||||
Dharkael (lupoDharkael)
|
Dharkael (lupoDharkael)
|
||||||
|
Dirk Steinmetz (rsjtdrjgfuzkfg)
|
||||||
Dmitry Koteroff (Krakean)
|
Dmitry Koteroff (Krakean)
|
||||||
Dmitry Maganov (vonagam)
|
Dmitry Maganov (vonagam)
|
||||||
Dominik Jasiński (dreamsComeTrue)
|
Dominik Jasiński (dreamsComeTrue)
|
||||||
|
@ -117,6 +127,7 @@ name is available.
|
||||||
Geequlim
|
Geequlim
|
||||||
George Marques (vnen)
|
George Marques (vnen)
|
||||||
Gerrit Großkopf (Grosskopf)
|
Gerrit Großkopf (Grosskopf)
|
||||||
|
Giganzo
|
||||||
Gilles Roudiere (groud)
|
Gilles Roudiere (groud)
|
||||||
Gordon MacPherson (RevoluPowered)
|
Gordon MacPherson (RevoluPowered)
|
||||||
Guilherme Felipe de C. G. da Silva (guilhermefelipecgs)
|
Guilherme Felipe de C. G. da Silva (guilhermefelipecgs)
|
||||||
|
@ -126,7 +137,6 @@ name is available.
|
||||||
Hein-Pieter van Braam-Stewart (hpvb)
|
Hein-Pieter van Braam-Stewart (hpvb)
|
||||||
Hendrik Brucker (Geometror)
|
Hendrik Brucker (Geometror)
|
||||||
Hilderin
|
Hilderin
|
||||||
hilfazer
|
|
||||||
Hiroshi Ogawa (hi-ogawa)
|
Hiroshi Ogawa (hi-ogawa)
|
||||||
HolonProduction
|
HolonProduction
|
||||||
homer666
|
homer666
|
||||||
|
@ -151,6 +161,7 @@ name is available.
|
||||||
Jia Jun Chai (SkyLucilfer)
|
Jia Jun Chai (SkyLucilfer)
|
||||||
jitspoe
|
jitspoe
|
||||||
Joan Fons Sanchez (JFonS)
|
Joan Fons Sanchez (JFonS)
|
||||||
|
Johan Aires Rastén (JohanAR)
|
||||||
Johan Manuel (29jm)
|
Johan Manuel (29jm)
|
||||||
Johannes Witt (HaSa1002)
|
Johannes Witt (HaSa1002)
|
||||||
Jonathan Nicholl (jtnicholl)
|
Jonathan Nicholl (jtnicholl)
|
||||||
|
@ -163,11 +174,13 @@ name is available.
|
||||||
Jummit
|
Jummit
|
||||||
Justo Delgado (mrcdk)
|
Justo Delgado (mrcdk)
|
||||||
karroffel
|
karroffel
|
||||||
|
Kassandra Pucher (PucklaJ)
|
||||||
Kelly Thomas (KellyThomas)
|
Kelly Thomas (KellyThomas)
|
||||||
kleonc
|
kleonc
|
||||||
Kongfa Waroros (gongpha)
|
Kongfa Waroros (gongpha)
|
||||||
Kostadin Damyanov (Max-Might)
|
Kostadin Damyanov (Max-Might)
|
||||||
K. S. Ernest (iFire) Lee (fire)
|
K. S. Ernest (iFire) Lee (fire)
|
||||||
|
Kyle Eichlin (likeich)
|
||||||
lawnjelly
|
lawnjelly
|
||||||
Leon Krause (leonkrause)
|
Leon Krause (leonkrause)
|
||||||
Liz Haas (27thLiz)
|
Liz Haas (27thLiz)
|
||||||
|
@ -185,6 +198,7 @@ name is available.
|
||||||
Marcus Brummer (mbrlabs)
|
Marcus Brummer (mbrlabs)
|
||||||
Marcus Elg (MCrafterzz)
|
Marcus Elg (MCrafterzz)
|
||||||
Mariano Javier Suligoy (MarianoGnu)
|
Mariano Javier Suligoy (MarianoGnu)
|
||||||
|
Mario Liebisch (MarioLiebisch)
|
||||||
Mario Schlack (hurikhan)
|
Mario Schlack (hurikhan)
|
||||||
Marios Staikopoulos (marstaik)
|
Marios Staikopoulos (marstaik)
|
||||||
Marius Hanl (Maran23)
|
Marius Hanl (Maran23)
|
||||||
|
@ -198,6 +212,7 @@ name is available.
|
||||||
Masoud BH (masoudbh3)
|
Masoud BH (masoudbh3)
|
||||||
Mateo Kuruk Miccino (kuruk-mm)
|
Mateo Kuruk Miccino (kuruk-mm)
|
||||||
Matias N. Goldberg (darksylinc)
|
Matias N. Goldberg (darksylinc)
|
||||||
|
Matthew Murphy (mashumafi)
|
||||||
Matthew (skyace65)
|
Matthew (skyace65)
|
||||||
Matthias Hölzl (hoelzl)
|
Matthias Hölzl (hoelzl)
|
||||||
Max Hilbrunner (mhilbrunner)
|
Max Hilbrunner (mhilbrunner)
|
||||||
|
@ -209,9 +224,10 @@ name is available.
|
||||||
MichiRecRoom (LikeLakers2)
|
MichiRecRoom (LikeLakers2)
|
||||||
Micky (Mickeon)
|
Micky (Mickeon)
|
||||||
Mikael Hermansson (mihe)
|
Mikael Hermansson (mihe)
|
||||||
|
Mika Viskari (miv391)
|
||||||
MinusKube
|
MinusKube
|
||||||
MJacred
|
MJacred
|
||||||
Morris "Tabor" Arroad (mortarroad)
|
Mounir Tohami (WhalesState)
|
||||||
mrezai
|
mrezai
|
||||||
Muhammad Huri (CakHuri)
|
Muhammad Huri (CakHuri)
|
||||||
muiroc
|
muiroc
|
||||||
|
@ -234,6 +250,7 @@ name is available.
|
||||||
Patrick Dawson (pkdawson)
|
Patrick Dawson (pkdawson)
|
||||||
Patrick Exner (FlameLizard)
|
Patrick Exner (FlameLizard)
|
||||||
Patrick (firefly2442)
|
Patrick (firefly2442)
|
||||||
|
patwork
|
||||||
Paul Batty (Paulb23)
|
Paul Batty (Paulb23)
|
||||||
Paul Joannon (paulloz)
|
Paul Joannon (paulloz)
|
||||||
Paul Trojahn (ptrojahn)
|
Paul Trojahn (ptrojahn)
|
||||||
|
@ -245,6 +262,7 @@ name is available.
|
||||||
Pieter-Jan Briers (PJB3005)
|
Pieter-Jan Briers (PJB3005)
|
||||||
Poommetee Ketson (Noshyaar)
|
Poommetee Ketson (Noshyaar)
|
||||||
Przemysław Gołąb (n-pigeon)
|
Przemysław Gołąb (n-pigeon)
|
||||||
|
Radiant (RadiantUwU)
|
||||||
Rafael M. G. (rafallus)
|
Rafael M. G. (rafallus)
|
||||||
Rafał Mikrut (qarmin)
|
Rafał Mikrut (qarmin)
|
||||||
Raffaele Picca (RPicster)
|
Raffaele Picca (RPicster)
|
||||||
|
@ -282,6 +300,7 @@ name is available.
|
||||||
Stanislav Labzyuk (DarkMessiah)
|
Stanislav Labzyuk (DarkMessiah)
|
||||||
Stijn Hinlopen (hinlopen)
|
Stijn Hinlopen (hinlopen)
|
||||||
stmSi
|
stmSi
|
||||||
|
Stuart Carnie (stuartcarnie)
|
||||||
Swarnim Arun (minraws)
|
Swarnim Arun (minraws)
|
||||||
TC (floppyhammer)
|
TC (floppyhammer)
|
||||||
TechnoPorg
|
TechnoPorg
|
||||||
|
@ -289,6 +308,7 @@ name is available.
|
||||||
Thakee Nathees (ThakeeNathees)
|
Thakee Nathees (ThakeeNathees)
|
||||||
thebestnom
|
thebestnom
|
||||||
Theo Hallenius (TheoXD)
|
Theo Hallenius (TheoXD)
|
||||||
|
Thomas ten Cate (ttencate)
|
||||||
Timo Schwarzer (timoschwarzer)
|
Timo Schwarzer (timoschwarzer)
|
||||||
Timothé Bonhoure (ajreckof)
|
Timothé Bonhoure (ajreckof)
|
||||||
Timo (toger5)
|
Timo (toger5)
|
||||||
|
|
77
DONORS.md
77
DONORS.md
|
@ -12,12 +12,12 @@ generous deed immortalized in the next stable release of Godot Engine.
|
||||||
|
|
||||||
## Patrons
|
## Patrons
|
||||||
|
|
||||||
|
Khronos® Group <https://www.khronos.org/>
|
||||||
OSS Capital <https://oss.capital/>
|
OSS Capital <https://oss.capital/>
|
||||||
Re-Logic <https://re-logic.com/>
|
|
||||||
|
|
||||||
## Platinum sponsors
|
## Platinum sponsors
|
||||||
|
|
||||||
Google Play <https://play.google.com/>
|
Google Play <https://play.google.com>
|
||||||
Ramatak <https://ramatak.com/>
|
Ramatak <https://ramatak.com/>
|
||||||
V-Sekai <https://github.com/V-Sekai>
|
V-Sekai <https://github.com/V-Sekai>
|
||||||
W4 Games <https://w4games.com/>
|
W4 Games <https://w4games.com/>
|
||||||
|
@ -25,53 +25,56 @@ generous deed immortalized in the next stable release of Godot Engine.
|
||||||
## Gold sponsors
|
## Gold sponsors
|
||||||
|
|
||||||
Mega Crit <https://www.megacrit.com/>
|
Mega Crit <https://www.megacrit.com/>
|
||||||
Pirate Software <https://gopiratesoftware.com/>
|
Pirate Software <https://gopiratesoftware.com>
|
||||||
Prehensile Tales <https://prehensile-tales.com/>
|
Prehensile Tales <https://prehensile-tales.com>
|
||||||
Robot Gentleman <http://robotgentleman.com/>
|
Robot Gentleman <http://robotgentleman.com/>
|
||||||
|
|
||||||
## Silver sponsors
|
## Silver sponsors
|
||||||
|
|
||||||
Broken Rules <https://brokenrul.es/>
|
Broken Rules <https://brokenrul.es>
|
||||||
Chasing Carrots <https://www.chasing-carrots.com/>
|
Chasing Carrots <https://www.chasing-carrots.com>
|
||||||
Copia Wealth Studios <https://copiawealthstudios.com/>
|
Copia Wealth Studios <https://copiawealthstudios.com/>
|
||||||
Indoor Astronaut <https://indoorastronaut.ch/>
|
Indoor Astronaut <https://indoorastronaut.ch/>
|
||||||
Load Complete <https://loadcomplete.com/>
|
LoadComplete <https://loadcomplete.com/>
|
||||||
Null <https://null.com/>
|
Null <https://null.com/>
|
||||||
Orbital Knight <https://www.orbitalknight.com/>
|
Orbital Knight <https://www.orbitalknight.com/>
|
||||||
Playful Studios <https://playfulstudios.com/>
|
Playful Studios <https://playfulstudios.com/>
|
||||||
|
Re-Logic <https://re-logic.com/>
|
||||||
|
|
||||||
## Diamond members
|
## Diamond members
|
||||||
|
|
||||||
Bippinbits <http://domekeepergame.com/>
|
Bippinbits <http://domekeepergame.com/>
|
||||||
Sealow
|
Sylv <https://rankith.itch.io/unnamed-space-idle-prototype>
|
||||||
And 5 anonymous donors
|
And 3 anonymous donors
|
||||||
|
|
||||||
## Titanium members
|
## Titanium members
|
||||||
|
|
||||||
Adriaan de Jongh <https://adriaan.games/>
|
Adriaan de Jongh <https://adriaan.games>
|
||||||
Anitya Space <https://www.anitya.space/>
|
Anitya Space <https://www.anitya.space>
|
||||||
Basically Games
|
Basically Games
|
||||||
FDG Entertainment <https://www.fdg-entertainment.com/>
|
FDG Entertainment <https://www.fdg-entertainment.com>
|
||||||
Game Dev Artisan <https://gamedevartisan.com/>
|
Game Dev Artisan <https://gamedevartisan.com>
|
||||||
Garry Newman
|
Garry Newman
|
||||||
Isaiah Smith <https://www.isaiahsmith.dev/>
|
Kenney <https://kenney.nl/>
|
||||||
Libretrend <https://libretrend.com/>
|
Libretrend <https://libretrend.com>
|
||||||
Life Art Studios <https://lifeartstudios.net/>
|
Life Art Studios <https://lifeartstudios.net/>
|
||||||
Lucid Silence Games
|
Lucid Silence Games
|
||||||
Matthew Campbell
|
Matthew Campbell
|
||||||
PolyMars <https://polymars.dev/>
|
PolyMars <https://polymars.dev/>
|
||||||
RPG in a Box <https://www.rpginabox.com/>
|
|
||||||
Razenpok <https://www.youtube.com/watch?v=-QxI-RP6-HM>
|
Razenpok <https://www.youtube.com/watch?v=-QxI-RP6-HM>
|
||||||
Smirk Software <https://smirk.gg/>
|
RPG in a Box <https://www.rpginabox.com>
|
||||||
|
Smirk Software <https://smirk.gg>
|
||||||
|
Studio Sunshower <https://www.studiosunshower.com/>
|
||||||
|
TrampolineTales <https://TrampolineTales.com/>
|
||||||
粟二华 (Su Erhua)
|
粟二华 (Su Erhua)
|
||||||
And 6 anonymous donors
|
And 4 anonymous donors
|
||||||
|
|
||||||
## Platinum members
|
## Platinum members
|
||||||
|
|
||||||
Andy Touch
|
Andy Touch
|
||||||
BlockImperiumGames (BIG)
|
BlockImperiumGames (BIG)
|
||||||
Christoph Woinke
|
|
||||||
Christopher Shifflett
|
Christopher Shifflett
|
||||||
|
Christoph Woinke
|
||||||
Cody Bentley
|
Cody Bentley
|
||||||
Darrin Massena
|
Darrin Massena
|
||||||
Edward Flick
|
Edward Flick
|
||||||
|
@ -79,8 +82,8 @@ generous deed immortalized in the next stable release of Godot Engine.
|
||||||
HP van Braam
|
HP van Braam
|
||||||
iCommitGames
|
iCommitGames
|
||||||
Jonah Stich
|
Jonah Stich
|
||||||
|
Justo Delgado Baudí
|
||||||
katnamag
|
katnamag
|
||||||
Marek Belski
|
|
||||||
Matthew Ekenstedt
|
Matthew Ekenstedt
|
||||||
Memories in 8Bit
|
Memories in 8Bit
|
||||||
Mike King
|
Mike King
|
||||||
|
@ -97,13 +100,14 @@ generous deed immortalized in the next stable release of Godot Engine.
|
||||||
TigerJ
|
TigerJ
|
||||||
Violin Iliev
|
Violin Iliev
|
||||||
Vladimír Chvátil
|
Vladimír Chvátil
|
||||||
And 16 anonymous donors
|
And 13 anonymous donors
|
||||||
|
|
||||||
## Gold members
|
## Gold members
|
||||||
|
|
||||||
80px
|
80px
|
||||||
afreytes
|
afreytes
|
||||||
alMoo Games
|
alMoo Games
|
||||||
|
alMoo Games
|
||||||
Alva Majo
|
Alva Majo
|
||||||
Antti Vesanen
|
Antti Vesanen
|
||||||
Asher Glick
|
Asher Glick
|
||||||
|
@ -119,6 +123,8 @@ generous deed immortalized in the next stable release of Godot Engine.
|
||||||
Bryce Dixon
|
Bryce Dixon
|
||||||
c64cosmin
|
c64cosmin
|
||||||
Carlo del Mundo
|
Carlo del Mundo
|
||||||
|
Carl van der Geest
|
||||||
|
Chocolate Software
|
||||||
Cindy Trieu
|
Cindy Trieu
|
||||||
ClarkThyLord
|
ClarkThyLord
|
||||||
Codex404
|
Codex404
|
||||||
|
@ -135,17 +141,21 @@ generous deed immortalized in the next stable release of Godot Engine.
|
||||||
dgehrig
|
dgehrig
|
||||||
dhanielk
|
dhanielk
|
||||||
Distorted Realities
|
Distorted Realities
|
||||||
|
Donkung
|
||||||
Dono
|
Dono
|
||||||
Don't You Know Who I Am? Inc.
|
Don't You Know Who I Am? Inc.
|
||||||
Dustuu
|
Dustuu
|
||||||
|
Dylan P.
|
||||||
Edelweiss
|
Edelweiss
|
||||||
Ends
|
Ends
|
||||||
Eren Ogrul
|
Eren Ogrul
|
||||||
Eric Brand
|
Eric Brand
|
||||||
Eric Phy
|
Eric Phy
|
||||||
Faisal Al-Kubaisi (QatariGameDev)
|
Faisal Al-Kubaisi (QatariGameDev)
|
||||||
|
Felix Adam
|
||||||
FeralBytes
|
FeralBytes
|
||||||
Festzeltgaming.de
|
Festzeltgaming.de
|
||||||
|
Frozen Fractal
|
||||||
Gaudipern
|
Gaudipern
|
||||||
GlassBrick
|
GlassBrick
|
||||||
Grau
|
Grau
|
||||||
|
@ -153,6 +163,7 @@ generous deed immortalized in the next stable release of Godot Engine.
|
||||||
Hayden Oliver
|
Hayden Oliver
|
||||||
hiulit
|
hiulit
|
||||||
Illyan
|
Illyan
|
||||||
|
Immaculate Lift Studio
|
||||||
Ivan Tabashki
|
Ivan Tabashki
|
||||||
Jacob (HACKhalo2 Studios)
|
Jacob (HACKhalo2 Studios)
|
||||||
Jam
|
Jam
|
||||||
|
@ -160,13 +171,12 @@ generous deed immortalized in the next stable release of Godot Engine.
|
||||||
Javier Roman
|
Javier Roman
|
||||||
Jeff Hungerford
|
Jeff Hungerford
|
||||||
Jeronimo Schreyer
|
Jeronimo Schreyer
|
||||||
Joel Martinez
|
|
||||||
Johannes Wuensch
|
Johannes Wuensch
|
||||||
John Gabriel
|
John Gabriel
|
||||||
Jonas Yamazaki
|
Jonas Yamazaki
|
||||||
|
Jonathan
|
||||||
José Canepa
|
José Canepa
|
||||||
Joshua Stelly
|
Joshua Stelly
|
||||||
Justin Sasso
|
|
||||||
Kalydi Balázs
|
Kalydi Balázs
|
||||||
KAR Games
|
KAR Games
|
||||||
Kiri "ExpiredPopsicle" Artemis
|
Kiri "ExpiredPopsicle" Artemis
|
||||||
|
@ -181,7 +191,9 @@ generous deed immortalized in the next stable release of Godot Engine.
|
||||||
m1n1ster
|
m1n1ster
|
||||||
Manuel Requena
|
Manuel Requena
|
||||||
Mara Huldra
|
Mara Huldra
|
||||||
|
Marek Belski
|
||||||
Martin Šenkeřík
|
Martin Šenkeřík
|
||||||
|
MHDante
|
||||||
Michael Gooch
|
Michael Gooch
|
||||||
Modus Ponens
|
Modus Ponens
|
||||||
Moshe Harris
|
Moshe Harris
|
||||||
|
@ -190,6 +202,7 @@ generous deed immortalized in the next stable release of Godot Engine.
|
||||||
Nassor Paulino da Silva
|
Nassor Paulino da Silva
|
||||||
nezticle
|
nezticle
|
||||||
Niklas Wahrman
|
Niklas Wahrman
|
||||||
|
Nitzan Bueno
|
||||||
Niwl Games
|
Niwl Games
|
||||||
NotNet
|
NotNet
|
||||||
Oathbringer
|
Oathbringer
|
||||||
|
@ -207,6 +220,7 @@ generous deed immortalized in the next stable release of Godot Engine.
|
||||||
re:thinc
|
re:thinc
|
||||||
Richard Ivánek
|
Richard Ivánek
|
||||||
Rudi P
|
Rudi P
|
||||||
|
Sam Leathers
|
||||||
Samuel Judd
|
Samuel Judd
|
||||||
ScoreSpace
|
ScoreSpace
|
||||||
Shiny Shinken
|
Shiny Shinken
|
||||||
|
@ -238,12 +252,12 @@ generous deed immortalized in the next stable release of Godot Engine.
|
||||||
Zhu Li
|
Zhu Li
|
||||||
zikes
|
zikes
|
||||||
嗯大爷
|
嗯大爷
|
||||||
|
潘彦圣
|
||||||
|
|
||||||
Alex Khayrullin
|
Alex Khayrullin
|
||||||
Algebrute
|
Algebrute
|
||||||
Andriy
|
Andriy
|
||||||
Antanas Paskauskas
|
Antanas Paskauskas
|
||||||
anti666
|
|
||||||
Ari
|
Ari
|
||||||
Arisaka Mayuki
|
Arisaka Mayuki
|
||||||
Arthur S. Muszynski
|
Arthur S. Muszynski
|
||||||
|
@ -269,13 +283,11 @@ generous deed immortalized in the next stable release of Godot Engine.
|
||||||
Liam Smyth
|
Liam Smyth
|
||||||
LoparPanda
|
LoparPanda
|
||||||
Martin Gulliksson
|
Martin Gulliksson
|
||||||
Martin Soucek
|
|
||||||
Michael Dürwald
|
Michael Dürwald
|
||||||
Michael Policastro
|
Michael Policastro
|
||||||
n00sh
|
n00sh
|
||||||
Nicolás Monner Sans
|
Nicolás Monner Sans
|
||||||
Nikita Rotskov
|
Nikita Rotskov
|
||||||
Nikola Whallon
|
|
||||||
Oliver Dick
|
Oliver Dick
|
||||||
Patrick Wuttke
|
Patrick Wuttke
|
||||||
Pete Goodwin
|
Pete Goodwin
|
||||||
|
@ -298,7 +310,6 @@ generous deed immortalized in the next stable release of Godot Engine.
|
||||||
VoidPointer
|
VoidPointer
|
||||||
Yifan Lai
|
Yifan Lai
|
||||||
|
|
||||||
Aaron Mayfield
|
|
||||||
Adam Carr
|
Adam Carr
|
||||||
Adam Smeltzer
|
Adam Smeltzer
|
||||||
Adisibio
|
Adisibio
|
||||||
|
@ -315,7 +326,6 @@ generous deed immortalized in the next stable release of Godot Engine.
|
||||||
Ano Nim
|
Ano Nim
|
||||||
Arch Toasty
|
Arch Toasty
|
||||||
Arda Erol
|
Arda Erol
|
||||||
A Really Tall Horse
|
|
||||||
Arturo Rosales
|
Arturo Rosales
|
||||||
Ash K
|
Ash K
|
||||||
Aubrey Falconer
|
Aubrey Falconer
|
||||||
|
@ -343,6 +353,7 @@ generous deed immortalized in the next stable release of Godot Engine.
|
||||||
Dakota Watkins
|
Dakota Watkins
|
||||||
Daniele Tolomelli
|
Daniele Tolomelli
|
||||||
Daniel Ramos
|
Daniel Ramos
|
||||||
|
Daren Scot Wilson
|
||||||
Dave Jansen
|
Dave Jansen
|
||||||
Davesnothere
|
Davesnothere
|
||||||
David Baker
|
David Baker
|
||||||
|
@ -361,12 +372,11 @@ generous deed immortalized in the next stable release of Godot Engine.
|
||||||
Eric Stokes
|
Eric Stokes
|
||||||
Eric Williams
|
Eric Williams
|
||||||
Erkki Seppälä
|
Erkki Seppälä
|
||||||
Ewan Holmes
|
|
||||||
Felix Adam
|
|
||||||
Frank
|
Frank
|
||||||
Frying☆Pan
|
Frying☆Pan
|
||||||
Game Endeavor
|
Game Endeavor
|
||||||
gamerminstrel
|
gamerminstrel
|
||||||
|
Garrett S
|
||||||
Gary Thomas
|
Gary Thomas
|
||||||
gebba
|
gebba
|
||||||
Greyson Richey
|
Greyson Richey
|
||||||
|
@ -385,7 +395,6 @@ generous deed immortalized in the next stable release of Godot Engine.
|
||||||
Jamie Massey
|
Jamie Massey
|
||||||
JARKKO PARVIAINEN
|
JARKKO PARVIAINEN
|
||||||
Jason Evans
|
Jason Evans
|
||||||
Joakim Askenbäck
|
|
||||||
Jonas
|
Jonas
|
||||||
Jonas Arndt
|
Jonas Arndt
|
||||||
Jonas Yamazaki
|
Jonas Yamazaki
|
||||||
|
@ -421,7 +430,6 @@ generous deed immortalized in the next stable release of Godot Engine.
|
||||||
Martin Holas
|
Martin Holas
|
||||||
Martin Liška
|
Martin Liška
|
||||||
Martin Trbola
|
Martin Trbola
|
||||||
Matěj Drábek
|
|
||||||
Mathieu
|
Mathieu
|
||||||
Matt Edwards
|
Matt Edwards
|
||||||
Maverick
|
Maverick
|
||||||
|
@ -441,7 +449,6 @@ generous deed immortalized in the next stable release of Godot Engine.
|
||||||
Neofytos Chimonas
|
Neofytos Chimonas
|
||||||
Nerdforge
|
Nerdforge
|
||||||
Nerdyninja
|
Nerdyninja
|
||||||
Nick Eldrenkamp
|
|
||||||
Nik Rudenko
|
Nik Rudenko
|
||||||
Noel Billig
|
Noel Billig
|
||||||
ozrk
|
ozrk
|
||||||
|
@ -450,7 +457,6 @@ generous deed immortalized in the next stable release of Godot Engine.
|
||||||
Patrick Nafarrete
|
Patrick Nafarrete
|
||||||
Paul Black
|
Paul Black
|
||||||
Paul Gieske
|
Paul Gieske
|
||||||
Paul Mozet
|
|
||||||
Pete
|
Pete
|
||||||
Phoenix Jauregui
|
Phoenix Jauregui
|
||||||
Pierre Caye
|
Pierre Caye
|
||||||
|
@ -462,7 +468,6 @@ generous deed immortalized in the next stable release of Godot Engine.
|
||||||
Raghava Kovvali
|
Raghava Kovvali
|
||||||
Ragnar Pettersson
|
Ragnar Pettersson
|
||||||
Rammeow
|
Rammeow
|
||||||
Rebecca H
|
|
||||||
Richard Hayes
|
Richard Hayes
|
||||||
Riley
|
Riley
|
||||||
RobotCritter
|
RobotCritter
|
||||||
|
@ -508,7 +513,7 @@ generous deed immortalized in the next stable release of Godot Engine.
|
||||||
ケルベロス
|
ケルベロス
|
||||||
貴宏 小松
|
貴宏 小松
|
||||||
|
|
||||||
And 181 anonymous donors
|
And 176 anonymous donors
|
||||||
|
|
||||||
## Silver and bronze donors
|
## Silver and bronze donors
|
||||||
|
|
||||||
|
|
|
@ -1070,7 +1070,6 @@ if "check_c_headers" in env:
|
||||||
env.AppendUnique(CPPDEFINES=[headers[header]])
|
env.AppendUnique(CPPDEFINES=[headers[header]])
|
||||||
|
|
||||||
|
|
||||||
# FIXME: This method mixes both cosmetic progress stuff and cache handling...
|
|
||||||
methods.show_progress(env)
|
methods.show_progress(env)
|
||||||
# TODO: replace this with `env.Dump(format="json")`
|
# TODO: replace this with `env.Dump(format="json")`
|
||||||
# once we start requiring SCons 4.0 as min version.
|
# once we start requiring SCons 4.0 as min version.
|
||||||
|
@ -1102,3 +1101,5 @@ def purge_flaky_files():
|
||||||
|
|
||||||
|
|
||||||
atexit.register(purge_flaky_files)
|
atexit.register(purge_flaky_files)
|
||||||
|
|
||||||
|
methods.clean_cache(env)
|
||||||
|
|
|
@ -140,7 +140,7 @@ if env["builtin_zstd"]:
|
||||||
"decompress/zstd_decompress_block.c",
|
"decompress/zstd_decompress_block.c",
|
||||||
"decompress/zstd_decompress.c",
|
"decompress/zstd_decompress.c",
|
||||||
]
|
]
|
||||||
if env["platform"] in ["android", "ios", "linuxbsd", "macos"]:
|
if env["platform"] in ["android", "ios", "linuxbsd", "macos"] and env["arch"] == "x86_64":
|
||||||
# Match platforms with ZSTD_ASM_SUPPORTED in common/portability_macros.h
|
# Match platforms with ZSTD_ASM_SUPPORTED in common/portability_macros.h
|
||||||
thirdparty_zstd_sources.append("decompress/huf_decompress_amd64.S")
|
thirdparty_zstd_sources.append("decompress/huf_decompress_amd64.S")
|
||||||
thirdparty_zstd_sources = [thirdparty_zstd_dir + file for file in thirdparty_zstd_sources]
|
thirdparty_zstd_sources = [thirdparty_zstd_dir + file for file in thirdparty_zstd_sources]
|
||||||
|
|
|
@ -1489,15 +1489,6 @@ ProjectSettings::ProjectSettings() {
|
||||||
GLOBAL_DEF(PropertyInfo(Variant::INT, "audio/general/ios/session_category", PROPERTY_HINT_ENUM, "Ambient,Multi Route,Play and Record,Playback,Record,Solo Ambient"), 0);
|
GLOBAL_DEF(PropertyInfo(Variant::INT, "audio/general/ios/session_category", PROPERTY_HINT_ENUM, "Ambient,Multi Route,Play and Record,Playback,Record,Solo Ambient"), 0);
|
||||||
GLOBAL_DEF("audio/general/ios/mix_with_others", false);
|
GLOBAL_DEF("audio/general/ios/mix_with_others", false);
|
||||||
|
|
||||||
PackedStringArray extensions;
|
|
||||||
extensions.push_back("gd");
|
|
||||||
if (ClassDB::class_exists("CSharpScript")) {
|
|
||||||
extensions.push_back("cs");
|
|
||||||
}
|
|
||||||
extensions.push_back("gdshader");
|
|
||||||
|
|
||||||
GLOBAL_DEF(PropertyInfo(Variant::PACKED_STRING_ARRAY, "editor/script/search_in_file_extensions"), extensions);
|
|
||||||
|
|
||||||
_add_builtin_input_map();
|
_add_builtin_input_map();
|
||||||
|
|
||||||
// Keep the enum values in sync with the `DisplayServer::ScreenOrientation` enum.
|
// Keep the enum values in sync with the `DisplayServer::ScreenOrientation` enum.
|
||||||
|
|
|
@ -781,23 +781,14 @@ Error GDExtension::open_library(const String &p_path, const String &p_entry_symb
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String actual_lib_path;
|
|
||||||
OS::GDExtensionData data = {
|
OS::GDExtensionData data = {
|
||||||
true, // also_set_library_path
|
true, // also_set_library_path
|
||||||
&actual_lib_path, // r_resolved_path
|
&library_path, // r_resolved_path
|
||||||
Engine::get_singleton()->is_editor_hint(), // generate_temp_files
|
Engine::get_singleton()->is_editor_hint(), // generate_temp_files
|
||||||
&abs_dependencies_paths, // library_dependencies
|
&abs_dependencies_paths, // library_dependencies
|
||||||
};
|
};
|
||||||
Error err = OS::get_singleton()->open_dynamic_library(abs_path, library, &data);
|
Error err = OS::get_singleton()->open_dynamic_library(abs_path, library, &data);
|
||||||
|
|
||||||
if (actual_lib_path.get_file() != abs_path.get_file()) {
|
|
||||||
// If temporary files are generated, let's change the library path to point at the original,
|
|
||||||
// because that's what we want to check to see if it's changed.
|
|
||||||
library_path = actual_lib_path.get_base_dir().path_join(p_path.get_file());
|
|
||||||
} else {
|
|
||||||
library_path = actual_lib_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
ERR_FAIL_COND_V_MSG(err == ERR_FILE_NOT_FOUND, err, "GDExtension dynamic library not found: " + abs_path);
|
ERR_FAIL_COND_V_MSG(err == ERR_FILE_NOT_FOUND, err, "GDExtension dynamic library not found: " + abs_path);
|
||||||
ERR_FAIL_COND_V_MSG(err != OK, err, "Can't open GDExtension dynamic library: " + abs_path);
|
ERR_FAIL_COND_V_MSG(err != OK, err, "Can't open GDExtension dynamic library: " + abs_path);
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ __XINPUT_DEVICE__,XInput Gamepad,a:b12,b:b13,x:b14,y:b15,start:b4,guide:b10,back
|
||||||
Default Android Gamepad,Default Controller,leftx:a0,lefty:a1,dpdown:h0.4,rightstick:b8,rightshoulder:b10,rightx:a2,start:b6,righty:a3,dpleft:h0.8,lefttrigger:a4,x:b2,dpup:h0.1,back:b4,leftstick:b7,leftshoulder:b9,y:b3,a:b0,dpright:h0.2,righttrigger:a5,b:b1,platform:Android,
|
Default Android Gamepad,Default Controller,leftx:a0,lefty:a1,dpdown:h0.4,rightstick:b8,rightshoulder:b10,rightx:a2,start:b6,righty:a3,dpleft:h0.8,lefttrigger:a4,x:b2,dpup:h0.1,back:b4,leftstick:b7,leftshoulder:b9,y:b3,a:b0,dpright:h0.2,righttrigger:a5,b:b1,platform:Android,
|
||||||
|
|
||||||
# Web
|
# Web
|
||||||
standard,Standard Gamepad Mapping,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b8,start:b9,leftstick:b10,rightstick:b11,dpup:b12,dpdown:b13,dpleft:b14,dpright:b15,guide:b16,leftstick:b10,rightstick:b11,platform:Web,
|
standard,Standard Gamepad Mapping,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:+a4,righttrigger:+a5,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b8,start:b9,leftstick:b10,rightstick:b11,dpup:b12,dpdown:b13,dpleft:b14,dpright:b15,guide:b16,leftstick:b10,rightstick:b11,platform:Web,
|
||||||
Linux24c6581a,PowerA Xbox One Cabled,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web,
|
Linux24c6581a,PowerA Xbox One Cabled,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web,
|
||||||
Linux0e6f0301,Logic 3 Controller (xbox compatible),a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web,
|
Linux0e6f0301,Logic 3 Controller (xbox compatible),a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web,
|
||||||
Linux045e028e,Microsoft X-Box 360 pad,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web,
|
Linux045e028e,Microsoft X-Box 360 pad,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web,
|
||||||
|
|
|
@ -30,12 +30,7 @@
|
||||||
|
|
||||||
#include "expression.h"
|
#include "expression.h"
|
||||||
|
|
||||||
#include "core/io/marshalls.h"
|
|
||||||
#include "core/math/math_funcs.h"
|
|
||||||
#include "core/object/class_db.h"
|
#include "core/object/class_db.h"
|
||||||
#include "core/object/ref_counted.h"
|
|
||||||
#include "core/os/os.h"
|
|
||||||
#include "core/variant/variant_parser.h"
|
|
||||||
|
|
||||||
Error Expression::_get_token(Token &r_token) {
|
Error Expression::_get_token(Token &r_token) {
|
||||||
while (true) {
|
while (true) {
|
||||||
|
@ -392,7 +387,6 @@ Error Expression::_get_token(Token &r_token) {
|
||||||
if (is_digit(c)) {
|
if (is_digit(c)) {
|
||||||
} else if (c == 'e') {
|
} else if (c == 'e') {
|
||||||
reading = READING_EXP;
|
reading = READING_EXP;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
reading = READING_DONE;
|
reading = READING_DONE;
|
||||||
}
|
}
|
||||||
|
@ -419,7 +413,9 @@ Error Expression::_get_token(Token &r_token) {
|
||||||
is_first_char = false;
|
is_first_char = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
str_ofs--;
|
if (c != 0) {
|
||||||
|
str_ofs--;
|
||||||
|
}
|
||||||
|
|
||||||
r_token.type = TK_CONSTANT;
|
r_token.type = TK_CONSTANT;
|
||||||
|
|
||||||
|
|
|
@ -105,6 +105,9 @@ public:
|
||||||
static _ALWAYS_INLINE_ double fmod(double p_x, double p_y) { return ::fmod(p_x, p_y); }
|
static _ALWAYS_INLINE_ double fmod(double p_x, double p_y) { return ::fmod(p_x, p_y); }
|
||||||
static _ALWAYS_INLINE_ float fmod(float p_x, float p_y) { return ::fmodf(p_x, p_y); }
|
static _ALWAYS_INLINE_ float fmod(float p_x, float p_y) { return ::fmodf(p_x, p_y); }
|
||||||
|
|
||||||
|
static _ALWAYS_INLINE_ double modf(double p_x, double *r_y) { return ::modf(p_x, r_y); }
|
||||||
|
static _ALWAYS_INLINE_ float modf(float p_x, float *r_y) { return ::modff(p_x, r_y); }
|
||||||
|
|
||||||
static _ALWAYS_INLINE_ double floor(double p_x) { return ::floor(p_x); }
|
static _ALWAYS_INLINE_ double floor(double p_x) { return ::floor(p_x); }
|
||||||
static _ALWAYS_INLINE_ float floor(float p_x) { return ::floorf(p_x); }
|
static _ALWAYS_INLINE_ float floor(float p_x) { return ::floorf(p_x); }
|
||||||
|
|
||||||
|
|
|
@ -60,6 +60,11 @@ int64_t RandomPCG::rand_weighted(const Vector<float> &p_weights) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (int64_t i = weights_size - 1; i >= 0; --i) {
|
||||||
|
if (weights[i] > 0) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,14 +45,17 @@
|
||||||
#ifdef DEBUG_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
|
|
||||||
struct _ObjectDebugLock {
|
struct _ObjectDebugLock {
|
||||||
Object *obj;
|
ObjectID obj_id;
|
||||||
|
|
||||||
_ObjectDebugLock(Object *p_obj) {
|
_ObjectDebugLock(Object *p_obj) {
|
||||||
obj = p_obj;
|
obj_id = p_obj->get_instance_id();
|
||||||
obj->_lock_index.ref();
|
p_obj->_lock_index.ref();
|
||||||
}
|
}
|
||||||
~_ObjectDebugLock() {
|
~_ObjectDebugLock() {
|
||||||
obj->_lock_index.unref();
|
Object *obj_ptr = ObjectDB::get_instance(obj_id);
|
||||||
|
if (likely(obj_ptr)) {
|
||||||
|
obj_ptr->_lock_index.unref();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2097,7 +2100,11 @@ Object::~Object() {
|
||||||
// Disconnect signals that connect to this object.
|
// Disconnect signals that connect to this object.
|
||||||
while (connections.size()) {
|
while (connections.size()) {
|
||||||
Connection c = connections.front()->get();
|
Connection c = connections.front()->get();
|
||||||
bool disconnected = c.signal.get_object()->_disconnect(c.signal.get_name(), c.callable, true);
|
Object *obj = c.callable.get_object();
|
||||||
|
bool disconnected = false;
|
||||||
|
if (likely(obj)) {
|
||||||
|
disconnected = c.signal.get_object()->_disconnect(c.signal.get_name(), c.callable, true);
|
||||||
|
}
|
||||||
if (unlikely(!disconnected)) {
|
if (unlikely(!disconnected)) {
|
||||||
// If the disconnect has failed, abandon the connection to avoid getting trapped in an infinite loop here.
|
// If the disconnect has failed, abandon the connection to avoid getting trapped in an infinite loop here.
|
||||||
connections.pop_front();
|
connections.pop_front();
|
||||||
|
|
|
@ -142,6 +142,7 @@ void ScriptLanguageExtension::_bind_methods() {
|
||||||
GDVIRTUAL_BIND(_debug_get_current_stack_info);
|
GDVIRTUAL_BIND(_debug_get_current_stack_info);
|
||||||
|
|
||||||
GDVIRTUAL_BIND(_reload_all_scripts);
|
GDVIRTUAL_BIND(_reload_all_scripts);
|
||||||
|
GDVIRTUAL_BIND(_reload_scripts, "scripts", "soft_reload");
|
||||||
GDVIRTUAL_BIND(_reload_tool_script, "script", "soft_reload");
|
GDVIRTUAL_BIND(_reload_tool_script, "script", "soft_reload");
|
||||||
|
|
||||||
GDVIRTUAL_BIND(_get_recognized_extensions);
|
GDVIRTUAL_BIND(_get_recognized_extensions);
|
||||||
|
|
|
@ -468,7 +468,10 @@ void WorkerThreadPool::_wait_collaboratively(ThreadData *p_caller_pool_thread, T
|
||||||
p_caller_pool_thread->signaled = false;
|
p_caller_pool_thread->signaled = false;
|
||||||
|
|
||||||
if (IS_WAIT_OVER) {
|
if (IS_WAIT_OVER) {
|
||||||
p_caller_pool_thread->yield_is_over = false;
|
if (unlikely(p_task == ThreadData::YIELDING)) {
|
||||||
|
p_caller_pool_thread->yield_is_over = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!exit_threads && was_signaled) {
|
if (!exit_threads && was_signaled) {
|
||||||
// This thread was awaken for some additional reason, but it's about to exit.
|
// This thread was awaken for some additional reason, but it's about to exit.
|
||||||
// Let's find out what may be pending and forward the requests.
|
// Let's find out what may be pending and forward the requests.
|
||||||
|
|
|
@ -39,19 +39,10 @@ StaticCString StaticCString::create(const char *p_ptr) {
|
||||||
return scs;
|
return scs;
|
||||||
}
|
}
|
||||||
|
|
||||||
StringName::_Data *StringName::_table[STRING_TABLE_LEN];
|
|
||||||
|
|
||||||
StringName _scs_create(const char *p_chr, bool p_static) {
|
StringName _scs_create(const char *p_chr, bool p_static) {
|
||||||
return (p_chr[0] ? StringName(StaticCString::create(p_chr), p_static) : StringName());
|
return (p_chr[0] ? StringName(StaticCString::create(p_chr), p_static) : StringName());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StringName::configured = false;
|
|
||||||
Mutex StringName::mutex;
|
|
||||||
|
|
||||||
#ifdef DEBUG_ENABLED
|
|
||||||
bool StringName::debug_stringname = false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void StringName::setup() {
|
void StringName::setup() {
|
||||||
ERR_FAIL_COND(configured);
|
ERR_FAIL_COND(configured);
|
||||||
for (int i = 0; i < STRING_TABLE_LEN; i++) {
|
for (int i = 0; i < STRING_TABLE_LEN; i++) {
|
||||||
|
|
|
@ -67,7 +67,7 @@ class StringName {
|
||||||
_Data() {}
|
_Data() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
static _Data *_table[STRING_TABLE_LEN];
|
static inline _Data *_table[STRING_TABLE_LEN];
|
||||||
|
|
||||||
_Data *_data = nullptr;
|
_Data *_data = nullptr;
|
||||||
|
|
||||||
|
@ -75,10 +75,10 @@ class StringName {
|
||||||
friend void register_core_types();
|
friend void register_core_types();
|
||||||
friend void unregister_core_types();
|
friend void unregister_core_types();
|
||||||
friend class Main;
|
friend class Main;
|
||||||
static Mutex mutex;
|
static inline Mutex mutex;
|
||||||
static void setup();
|
static void setup();
|
||||||
static void cleanup();
|
static void cleanup();
|
||||||
static bool configured;
|
static inline bool configured = false;
|
||||||
#ifdef DEBUG_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
struct DebugSortReferences {
|
struct DebugSortReferences {
|
||||||
bool operator()(const _Data *p_left, const _Data *p_right) const {
|
bool operator()(const _Data *p_left, const _Data *p_right) const {
|
||||||
|
@ -86,7 +86,7 @@ class StringName {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool debug_stringname;
|
static inline bool debug_stringname = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
StringName(_Data *p_data) { _data = p_data; }
|
StringName(_Data *p_data) { _data = p_data; }
|
||||||
|
|
|
@ -1537,13 +1537,16 @@ Vector<double> String::split_floats(const String &p_splitter, bool p_allow_empty
|
||||||
int from = 0;
|
int from = 0;
|
||||||
int len = length();
|
int len = length();
|
||||||
|
|
||||||
|
String buffer = *this;
|
||||||
while (true) {
|
while (true) {
|
||||||
int end = find(p_splitter, from);
|
int end = find(p_splitter, from);
|
||||||
if (end < 0) {
|
if (end < 0) {
|
||||||
end = len;
|
end = len;
|
||||||
}
|
}
|
||||||
if (p_allow_empty || (end > from)) {
|
if (p_allow_empty || (end > from)) {
|
||||||
ret.push_back(String::to_float(&get_data()[from]));
|
buffer[end] = 0;
|
||||||
|
ret.push_back(String::to_float(&buffer.get_data()[from]));
|
||||||
|
buffer[end] = _cowdata.get(end);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (end == len) {
|
if (end == len) {
|
||||||
|
@ -1561,6 +1564,7 @@ Vector<float> String::split_floats_mk(const Vector<String> &p_splitters, bool p_
|
||||||
int from = 0;
|
int from = 0;
|
||||||
int len = length();
|
int len = length();
|
||||||
|
|
||||||
|
String buffer = *this;
|
||||||
while (true) {
|
while (true) {
|
||||||
int idx;
|
int idx;
|
||||||
int end = findmk(p_splitters, from, &idx);
|
int end = findmk(p_splitters, from, &idx);
|
||||||
|
@ -1572,7 +1576,9 @@ Vector<float> String::split_floats_mk(const Vector<String> &p_splitters, bool p_
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p_allow_empty || (end > from)) {
|
if (p_allow_empty || (end > from)) {
|
||||||
ret.push_back(String::to_float(&get_data()[from]));
|
buffer[end] = 0;
|
||||||
|
ret.push_back(String::to_float(&buffer.get_data()[from]));
|
||||||
|
buffer[end] = _cowdata.get(end);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (end == len) {
|
if (end == len) {
|
||||||
|
|
|
@ -169,7 +169,7 @@
|
||||||
astar.ConnectPoints(2, 3, false);
|
astar.ConnectPoints(2, 3, false);
|
||||||
astar.ConnectPoints(4, 3, false);
|
astar.ConnectPoints(4, 3, false);
|
||||||
astar.ConnectPoints(1, 4, false);
|
astar.ConnectPoints(1, 4, false);
|
||||||
int[] res = astar.GetIdPath(1, 3); // Returns [1, 2, 3]
|
long[] res = astar.GetIdPath(1, 3); // Returns [1, 2, 3]
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
If you change the 2nd point's weight to 3, then the result will be [code][1, 4, 3][/code] instead, because now even though the distance is longer, it's "easier" to get through point 4 than through point 2.
|
If you change the 2nd point's weight to 3, then the result will be [code][1, 4, 3][/code] instead, because now even though the distance is longer, it's "easier" to get through point 4 than through point 2.
|
||||||
|
@ -209,7 +209,7 @@
|
||||||
astar.ConnectPoints(1, 2, true);
|
astar.ConnectPoints(1, 2, true);
|
||||||
astar.ConnectPoints(1, 3, true);
|
astar.ConnectPoints(1, 3, true);
|
||||||
|
|
||||||
int[] neighbors = astar.GetPointConnections(1); // Returns [2, 3]
|
long[] neighbors = astar.GetPointConnections(1); // Returns [2, 3]
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
</description>
|
</description>
|
||||||
|
|
|
@ -197,7 +197,7 @@
|
||||||
astar.ConnectPoints(2, 3, false);
|
astar.ConnectPoints(2, 3, false);
|
||||||
astar.ConnectPoints(4, 3, false);
|
astar.ConnectPoints(4, 3, false);
|
||||||
astar.ConnectPoints(1, 4, false);
|
astar.ConnectPoints(1, 4, false);
|
||||||
int[] res = astar.GetIdPath(1, 3); // Returns [1, 2, 3]
|
long[] res = astar.GetIdPath(1, 3); // Returns [1, 2, 3]
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
If you change the 2nd point's weight to 3, then the result will be [code][1, 4, 3][/code] instead, because now even though the distance is longer, it's "easier" to get through point 4 than through point 2.
|
If you change the 2nd point's weight to 3, then the result will be [code][1, 4, 3][/code] instead, because now even though the distance is longer, it's "easier" to get through point 4 than through point 2.
|
||||||
|
@ -236,7 +236,7 @@
|
||||||
astar.ConnectPoints(1, 2, true);
|
astar.ConnectPoints(1, 2, true);
|
||||||
astar.ConnectPoints(1, 3, true);
|
astar.ConnectPoints(1, 3, true);
|
||||||
|
|
||||||
int[] neighbors = astar.GetPointConnections(1); // Returns [2, 3]
|
long[] neighbors = astar.GetPointConnections(1); // Returns [2, 3]
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
</description>
|
</description>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
</brief_description>
|
</brief_description>
|
||||||
<description>
|
<description>
|
||||||
A resource used by [AnimationNodeBlendTree].
|
A resource used by [AnimationNodeBlendTree].
|
||||||
[AnimationNodeBlendSpace1D] represents a virtual 2D space on which [AnimationRootNode]s are placed. Outputs the linear blend of the three adjacent animations using a [Vector2] weight. Adjacent in this context means the three [AnimationRootNode]s making up the triangle that contains the current value.
|
[AnimationNodeBlendSpace2D] represents a virtual 2D space on which [AnimationRootNode]s are placed. Outputs the linear blend of the three adjacent animations using a [Vector2] weight. Adjacent in this context means the three [AnimationRootNode]s making up the triangle that contains the current value.
|
||||||
You can add vertices to the blend space with [method add_blend_point] and automatically triangulate it by setting [member auto_triangles] to [code]true[/code]. Otherwise, use [method add_triangle] and [method remove_triangle] to triangulate the blend space by hand.
|
You can add vertices to the blend space with [method add_blend_point] and automatically triangulate it by setting [member auto_triangles] to [code]true[/code]. Otherwise, use [method add_triangle] and [method remove_triangle] to triangulate the blend space by hand.
|
||||||
</description>
|
</description>
|
||||||
<tutorials>
|
<tutorials>
|
||||||
|
@ -93,7 +93,7 @@
|
||||||
<param index="0" name="point" type="int" />
|
<param index="0" name="point" type="int" />
|
||||||
<param index="1" name="pos" type="Vector2" />
|
<param index="1" name="pos" type="Vector2" />
|
||||||
<description>
|
<description>
|
||||||
Updates the position of the point at index [param point] on the blend axis.
|
Updates the position of the point at index [param point] in the blend space.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
</methods>
|
</methods>
|
||||||
|
|
|
@ -243,7 +243,7 @@
|
||||||
var numbers = [1, 2, 3]
|
var numbers = [1, 2, 3]
|
||||||
var extra = [4, 5, 6]
|
var extra = [4, 5, 6]
|
||||||
numbers.append_array(extra)
|
numbers.append_array(extra)
|
||||||
print(nums) # Prints [1, 2, 3, 4, 5, 6]
|
print(numbers) # Prints [1, 2, 3, 4, 5, 6]
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
@ -715,7 +715,7 @@
|
||||||
<param index="0" name="func" type="Callable" />
|
<param index="0" name="func" type="Callable" />
|
||||||
<description>
|
<description>
|
||||||
Sorts the array using a custom [Callable].
|
Sorts the array using a custom [Callable].
|
||||||
[param func] is called as many times as necessary, receiving two array elements as arguments. The function should return [code]true[/code] if the first element should be moved [i]behind[/i] the second one, otherwise it should return [code]false[/code].
|
[param func] is called as many times as necessary, receiving two array elements as arguments. The function should return [code]true[/code] if the first element should be moved [i]before[/i] the second one, otherwise it should return [code]false[/code].
|
||||||
[codeblock]
|
[codeblock]
|
||||||
func sort_ascending(a, b):
|
func sort_ascending(a, b):
|
||||||
if a[1] < b[1]:
|
if a[1] < b[1]:
|
||||||
|
@ -728,7 +728,7 @@
|
||||||
print(my_items) # Prints [["Rice", 4], ["Tomato", 5], ["Apple", 9]]
|
print(my_items) # Prints [["Rice", 4], ["Tomato", 5], ["Apple", 9]]
|
||||||
|
|
||||||
# Sort descending, using a lambda function.
|
# Sort descending, using a lambda function.
|
||||||
my_items.sort_custom(func(a, b): return a[0] > b[0])
|
my_items.sort_custom(func(a, b): return a[1] > b[1])
|
||||||
print(my_items) # Prints [["Apple", 9], ["Tomato", 5], ["Rice", 4]]
|
print(my_items) # Prints [["Apple", 9], ["Tomato", 5], ["Rice", 4]]
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
It may also be necessary to use this method to sort strings by natural order, with [method String.naturalnocasecmp_to], as in the following example:
|
It may also be necessary to use this method to sort strings by natural order, with [method String.naturalnocasecmp_to], as in the following example:
|
||||||
|
|
|
@ -88,7 +88,7 @@
|
||||||
<param index="0" name="idx" type="int" />
|
<param index="0" name="idx" type="int" />
|
||||||
<param index="1" name="t" type="float" />
|
<param index="1" name="t" type="float" />
|
||||||
<description>
|
<description>
|
||||||
Returns the position between the vertex [param idx] and the vertex [code]idx + 1[/code], where [param t] controls if the point is the first vertex ([code]t = 0.0[/code]), the last vertex ([code]t = 1.0[/code]), or in between. Values of [param t] outside the range ([code]0.0 >= t <=1[/code]) give strange, but predictable results.
|
Returns the position between the vertex [param idx] and the vertex [code]idx + 1[/code], where [param t] controls if the point is the first vertex ([code]t = 0.0[/code]), the last vertex ([code]t = 1.0[/code]), or in between. Values of [param t] outside the range ([code]0.0 <= t <= 1.0[/code]) give strange, but predictable results.
|
||||||
If [param idx] is out of bounds it is truncated to the first or last vertex, and [param t] is ignored. If the curve has no points, the function sends an error to the console, and returns [code](0, 0)[/code].
|
If [param idx] is out of bounds it is truncated to the first or last vertex, and [param t] is ignored. If the curve has no points, the function sends an error to the console, and returns [code](0, 0)[/code].
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
|
|
@ -29,6 +29,12 @@
|
||||||
Returns whether or not the specified layer of the [member navigation_layers] bitmask is enabled, given a [param layer_number] between 1 and 32.
|
Returns whether or not the specified layer of the [member navigation_layers] bitmask is enabled, given a [param layer_number] between 1 and 32.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="get_navigation_map" qualifiers="const">
|
||||||
|
<return type="RID" />
|
||||||
|
<description>
|
||||||
|
Returns the current navigation map [RID] used by this link.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
<method name="get_rid" qualifiers="const">
|
<method name="get_rid" qualifiers="const">
|
||||||
<return type="RID" />
|
<return type="RID" />
|
||||||
<description>
|
<description>
|
||||||
|
@ -57,6 +63,13 @@
|
||||||
Based on [param value], enables or disables the specified layer in the [member navigation_layers] bitmask, given a [param layer_number] between 1 and 32.
|
Based on [param value], enables or disables the specified layer in the [member navigation_layers] bitmask, given a [param layer_number] between 1 and 32.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="set_navigation_map">
|
||||||
|
<return type="void" />
|
||||||
|
<param index="0" name="navigation_map" type="RID" />
|
||||||
|
<description>
|
||||||
|
Sets the [RID] of the navigation map this link should use. By default the link will automatically join the [World2D] default navigation map so this function is only required to override the default map.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
</methods>
|
</methods>
|
||||||
<members>
|
<members>
|
||||||
<member name="bidirectional" type="bool" setter="set_bidirectional" getter="is_bidirectional" default="true">
|
<member name="bidirectional" type="bool" setter="set_bidirectional" getter="is_bidirectional" default="true">
|
||||||
|
|
|
@ -29,6 +29,12 @@
|
||||||
Returns whether or not the specified layer of the [member navigation_layers] bitmask is enabled, given a [param layer_number] between 1 and 32.
|
Returns whether or not the specified layer of the [member navigation_layers] bitmask is enabled, given a [param layer_number] between 1 and 32.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="get_navigation_map" qualifiers="const">
|
||||||
|
<return type="RID" />
|
||||||
|
<description>
|
||||||
|
Returns the current navigation map [RID] used by this link.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
<method name="get_rid" qualifiers="const">
|
<method name="get_rid" qualifiers="const">
|
||||||
<return type="RID" />
|
<return type="RID" />
|
||||||
<description>
|
<description>
|
||||||
|
@ -57,6 +63,13 @@
|
||||||
Based on [param value], enables or disables the specified layer in the [member navigation_layers] bitmask, given a [param layer_number] between 1 and 32.
|
Based on [param value], enables or disables the specified layer in the [member navigation_layers] bitmask, given a [param layer_number] between 1 and 32.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="set_navigation_map">
|
||||||
|
<return type="void" />
|
||||||
|
<param index="0" name="navigation_map" type="RID" />
|
||||||
|
<description>
|
||||||
|
Sets the [RID] of the navigation map this link should use. By default the link will automatically join the [World3D] default navigation map so this function is only required to override the default map.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
</methods>
|
</methods>
|
||||||
<members>
|
<members>
|
||||||
<member name="bidirectional" type="bool" setter="set_bidirectional" getter="is_bidirectional" default="true">
|
<member name="bidirectional" type="bool" setter="set_bidirectional" getter="is_bidirectional" default="true">
|
||||||
|
|
|
@ -136,7 +136,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<int> _numbers = new();
|
private Godot.Collections.Array<int> _numbers = new();
|
||||||
|
|
||||||
public override Godot.Collections.Array<Godot.Collections.Dictionary> _GetPropertyList()
|
public override Godot.Collections.Array<Godot.Collections.Dictionary> _GetPropertyList()
|
||||||
{
|
{
|
||||||
|
@ -173,7 +173,7 @@
|
||||||
if (propertyName.StartsWith("number_"))
|
if (propertyName.StartsWith("number_"))
|
||||||
{
|
{
|
||||||
int index = int.Parse(propertyName.Substring("number_".Length));
|
int index = int.Parse(propertyName.Substring("number_".Length));
|
||||||
numbers[index] = value.As<int>();
|
_numbers[index] = value.As<int>();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -1000,7 +1000,7 @@
|
||||||
prime-run %command%
|
prime-run %command%
|
||||||
[/codeblock]
|
[/codeblock]
|
||||||
</member>
|
</member>
|
||||||
<member name="editor/script/search_in_file_extensions" type="PackedStringArray" setter="" getter="" default="PackedStringArray("gd", "gdshader")">
|
<member name="editor/script/search_in_file_extensions" type="PackedStringArray" setter="" getter="">
|
||||||
Text-based file extensions to include in the script editor's "Find in Files" feature. You can add e.g. [code]tscn[/code] if you wish to also parse your scene files, especially if you use built-in scripts which are serialized in the scene files.
|
Text-based file extensions to include in the script editor's "Find in Files" feature. You can add e.g. [code]tscn[/code] if you wish to also parse your scene files, especially if you use built-in scripts which are serialized in the scene files.
|
||||||
</member>
|
</member>
|
||||||
<member name="editor/script/templates_search_path" type="String" setter="" getter="" default=""res://script_templates"">
|
<member name="editor/script/templates_search_path" type="String" setter="" getter="" default=""res://script_templates"">
|
||||||
|
|
|
@ -944,7 +944,8 @@
|
||||||
<param index="1" name="item" type="RID" />
|
<param index="1" name="item" type="RID" />
|
||||||
<param index="2" name="mirroring" type="Vector2" />
|
<param index="2" name="mirroring" type="Vector2" />
|
||||||
<description>
|
<description>
|
||||||
A copy of the canvas item will be drawn with a local offset of the mirroring [Vector2].
|
A copy of the canvas item will be drawn with a local offset of the [param mirroring].
|
||||||
|
[b]Note:[/b] This is equivalent to calling [method canvas_set_item_repeat] like [code]canvas_set_item_repeat(item, mirroring, 1)[/code], with an additional check ensuring [param canvas] is a parent of [param item].
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="canvas_set_item_repeat">
|
<method name="canvas_set_item_repeat">
|
||||||
|
|
|
@ -40,7 +40,7 @@
|
||||||
</member>
|
</member>
|
||||||
<member name="kerning_pairs" type="PackedStringArray" setter="" getter="" default="PackedStringArray()">
|
<member name="kerning_pairs" type="PackedStringArray" setter="" getter="" default="PackedStringArray()">
|
||||||
Kerning pairs for the font. Kerning pair adjust the spacing between two characters.
|
Kerning pairs for the font. Kerning pair adjust the spacing between two characters.
|
||||||
Each string consist of three space separated values: "from" string, "to" string and integer offset. Each combination form the two string for a kerning pair, e.g, [code]ab cd -3[/code] will create kerning pairs [code]ac[/code], [code]ad[/code], [code]bc[/code], and [code]bd[/code] with offset [code]-3[/code].
|
Each string consist of three space separated values: "from" string, "to" string and integer offset. Each combination form the two string for a kerning pair, e.g, [code]ab cd -3[/code] will create kerning pairs [code]ac[/code], [code]ad[/code], [code]bc[/code], and [code]bd[/code] with offset [code]-3[/code]. [code]\uXXXX[/code] escape sequences can be used to add Unicode characters.
|
||||||
</member>
|
</member>
|
||||||
<member name="rows" type="int" setter="" getter="" default="1">
|
<member name="rows" type="int" setter="" getter="" default="1">
|
||||||
Number of rows in the font image. See also [member columns].
|
Number of rows in the font image. See also [member columns].
|
||||||
|
|
|
@ -314,6 +314,13 @@
|
||||||
<description>
|
<description>
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="_reload_scripts" qualifiers="virtual">
|
||||||
|
<return type="void" />
|
||||||
|
<param index="0" name="scripts" type="Array" />
|
||||||
|
<param index="1" name="soft_reload" type="bool" />
|
||||||
|
<description>
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
<method name="_reload_tool_script" qualifiers="virtual">
|
<method name="_reload_tool_script" qualifiers="virtual">
|
||||||
<return type="void" />
|
<return type="void" />
|
||||||
<param index="0" name="script" type="Script" />
|
<param index="0" name="script" type="Script" />
|
||||||
|
|
|
@ -551,7 +551,7 @@
|
||||||
</member>
|
</member>
|
||||||
<member name="default_font_size" type="int" setter="set_default_font_size" getter="get_default_font_size" default="-1">
|
<member name="default_font_size" type="int" setter="set_default_font_size" getter="get_default_font_size" default="-1">
|
||||||
The default font size of this theme resource. Used as the default value when trying to fetch a font size value that doesn't exist in this theme or is in invalid state. If the default font size is also missing or invalid, the engine fallback value is used (see [member ThemeDB.fallback_font_size]).
|
The default font size of this theme resource. Used as the default value when trying to fetch a font size value that doesn't exist in this theme or is in invalid state. If the default font size is also missing or invalid, the engine fallback value is used (see [member ThemeDB.fallback_font_size]).
|
||||||
Values below [code]0[/code] are invalid and can be used to unset the property. Use [method has_default_font_size] to check if this value is valid.
|
Values below [code]1[/code] are invalid and can be used to unset the property. Use [method has_default_font_size] to check if this value is valid.
|
||||||
</member>
|
</member>
|
||||||
</members>
|
</members>
|
||||||
<constants>
|
<constants>
|
||||||
|
|
|
@ -12226,65 +12226,6 @@ msgstr ""
|
||||||
"5[/code] reicht. Es ist die Position im Segment, die dem angegebenen Punkt am "
|
"5[/code] reicht. Es ist die Position im Segment, die dem angegebenen Punkt am "
|
||||||
"nächsten liegt."
|
"nächsten liegt."
|
||||||
|
|
||||||
msgid ""
|
|
||||||
"Returns an array with the IDs of the points that form the connection with the "
|
|
||||||
"given point.\n"
|
|
||||||
"[codeblocks]\n"
|
|
||||||
"[gdscript]\n"
|
|
||||||
"var astar = AStar2D.new()\n"
|
|
||||||
"astar.add_point(1, Vector2(0, 0))\n"
|
|
||||||
"astar.add_point(2, Vector2(0, 1))\n"
|
|
||||||
"astar.add_point(3, Vector2(1, 1))\n"
|
|
||||||
"astar.add_point(4, Vector2(2, 0))\n"
|
|
||||||
"\n"
|
|
||||||
"astar.connect_points(1, 2, true)\n"
|
|
||||||
"astar.connect_points(1, 3, true)\n"
|
|
||||||
"\n"
|
|
||||||
"var neighbors = astar.get_point_connections(1) # Returns [2, 3]\n"
|
|
||||||
"[/gdscript]\n"
|
|
||||||
"[csharp]\n"
|
|
||||||
"var astar = new AStar2D();\n"
|
|
||||||
"astar.AddPoint(1, new Vector2(0, 0));\n"
|
|
||||||
"astar.AddPoint(2, new Vector2(0, 1));\n"
|
|
||||||
"astar.AddPoint(3, new Vector2(1, 1));\n"
|
|
||||||
"astar.AddPoint(4, new Vector2(2, 0));\n"
|
|
||||||
"\n"
|
|
||||||
"astar.ConnectPoints(1, 2, true);\n"
|
|
||||||
"astar.ConnectPoints(1, 3, true);\n"
|
|
||||||
"\n"
|
|
||||||
"int[] neighbors = astar.GetPointConnections(1); // Returns [2, 3]\n"
|
|
||||||
"[/csharp]\n"
|
|
||||||
"[/codeblocks]"
|
|
||||||
msgstr ""
|
|
||||||
"Gibt ein Array mit den IDs der Punkte zurück, die eine Verbindung mit dem "
|
|
||||||
"angegebenen Punkt bilden.\n"
|
|
||||||
"[codeblocks]\n"
|
|
||||||
"[gdscript]\n"
|
|
||||||
"var astar = AStar2D.new()\n"
|
|
||||||
"astar.add_point(1, Vector2(0, 0))\n"
|
|
||||||
"astar.add_point(2, Vector2(0, 1))\n"
|
|
||||||
"astar.add_point(3, Vector2(1, 1))\n"
|
|
||||||
"astar.add_point(4, Vector2(2, 0))\n"
|
|
||||||
"\n"
|
|
||||||
"astar.connect_points(1, 2, true)\n"
|
|
||||||
"astar.connect_points(1, 3, true)\n"
|
|
||||||
"\n"
|
|
||||||
"var neighbors = astar.get_point_connections(1) # Gibt [2, 3] zurück\n"
|
|
||||||
"[/gdscript]\n"
|
|
||||||
"[csharp]\n"
|
|
||||||
"var astar = new AStar2D();\n"
|
|
||||||
"astar.AddPoint(1, new Vector2(0, 0));\n"
|
|
||||||
"astar.AddPoint(2, new Vector2(0, 1));\n"
|
|
||||||
"astar.AddPoint(3, new Vector2(1, 1));\n"
|
|
||||||
"astar.AddPoint(4, new Vector2(2, 0));\n"
|
|
||||||
"\n"
|
|
||||||
"astar.ConnectPoints(1, 2, true);\n"
|
|
||||||
"astar.ConnectPoints(1, 3, true);\n"
|
|
||||||
"\n"
|
|
||||||
"int[] neighbors = astar.GetPointConnections(1); // Gibt [2, 3] zurück\n"
|
|
||||||
"[/csharp]\n"
|
|
||||||
"[/codeblocks]"
|
|
||||||
|
|
||||||
msgid "Returns the number of points currently in the points pool."
|
msgid "Returns the number of points currently in the points pool."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Gibt die Anzahl der Punkte zurück, die sich derzeit im Punktepool befinden."
|
"Gibt die Anzahl der Punkte zurück, die sich derzeit im Punktepool befinden."
|
||||||
|
@ -12523,63 +12464,6 @@ msgstr ""
|
||||||
"5[/code] reicht. Es ist die Position im Segment, die dem angegebenen Punkt am "
|
"5[/code] reicht. Es ist die Position im Segment, die dem angegebenen Punkt am "
|
||||||
"nächsten liegt."
|
"nächsten liegt."
|
||||||
|
|
||||||
msgid ""
|
|
||||||
"Returns an array with the IDs of the points that form the connection with the "
|
|
||||||
"given point.\n"
|
|
||||||
"[codeblocks]\n"
|
|
||||||
"[gdscript]\n"
|
|
||||||
"var astar = AStar3D.new()\n"
|
|
||||||
"astar.add_point(1, Vector3(0, 0, 0))\n"
|
|
||||||
"astar.add_point(2, Vector3(0, 1, 0))\n"
|
|
||||||
"astar.add_point(3, Vector3(1, 1, 0))\n"
|
|
||||||
"astar.add_point(4, Vector3(2, 0, 0))\n"
|
|
||||||
"\n"
|
|
||||||
"astar.connect_points(1, 2, true)\n"
|
|
||||||
"astar.connect_points(1, 3, true)\n"
|
|
||||||
"\n"
|
|
||||||
"var neighbors = astar.get_point_connections(1) # Returns [2, 3]\n"
|
|
||||||
"[/gdscript]\n"
|
|
||||||
"[csharp]\n"
|
|
||||||
"var astar = new AStar3D();\n"
|
|
||||||
"astar.AddPoint(1, new Vector3(0, 0, 0));\n"
|
|
||||||
"astar.AddPoint(2, new Vector3(0, 1, 0));\n"
|
|
||||||
"astar.AddPoint(3, new Vector3(1, 1, 0));\n"
|
|
||||||
"astar.AddPoint(4, new Vector3(2, 0, 0));\n"
|
|
||||||
"astar.ConnectPoints(1, 2, true);\n"
|
|
||||||
"astar.ConnectPoints(1, 3, true);\n"
|
|
||||||
"\n"
|
|
||||||
"int[] neighbors = astar.GetPointConnections(1); // Returns [2, 3]\n"
|
|
||||||
"[/csharp]\n"
|
|
||||||
"[/codeblocks]"
|
|
||||||
msgstr ""
|
|
||||||
"Gibt ein Array mit den IDs der Punkte zurück, die eine Verbindung mit dem "
|
|
||||||
"angegebenen Punkt bilden.\n"
|
|
||||||
"[codeblocks]\n"
|
|
||||||
"[gdscript]\n"
|
|
||||||
"var astar = AStar3D.new()\n"
|
|
||||||
"astar.add_point(1, Vector3(0, 0, 0))\n"
|
|
||||||
"astar.add_point(2, Vector3(0, 1, 0))\n"
|
|
||||||
"astar.add_point(3, Vector3(1, 1, 0))\n"
|
|
||||||
"astar.add_point(4, Vector3(2, 0, 0))\n"
|
|
||||||
"\n"
|
|
||||||
"astar.connect_points(1, 2, true)\n"
|
|
||||||
"astar.connect_points(1, 3, true)\n"
|
|
||||||
"\n"
|
|
||||||
"var neighbors = astar.get_point_connections(1) # Gibt [2, 3] zurück\n"
|
|
||||||
"[/gdscript]\n"
|
|
||||||
"[csharp]\n"
|
|
||||||
"var astar = new AStar3D();\n"
|
|
||||||
"astar.AddPoint(1, new Vector3(0, 0, 0));\n"
|
|
||||||
"astar.AddPoint(2, new Vector3(0, 1, 0));\n"
|
|
||||||
"astar.AddPoint(3, new Vector3(1, 1, 0));\n"
|
|
||||||
"astar.AddPoint(4, new Vector3(2, 0, 0));\n"
|
|
||||||
"astar.ConnectPoints(1, 2, true);\n"
|
|
||||||
"astar.ConnectPoints(1, 3, true);\n"
|
|
||||||
"\n"
|
|
||||||
"int[] neighbors = astar.GetPointConnections(1); // Gibt [2, 3] zurück\n"
|
|
||||||
"[/csharp]\n"
|
|
||||||
"[/codeblocks]"
|
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"[AStarGrid2D] is a variant of [AStar2D] that is specialized for partial 2D "
|
"[AStarGrid2D] is a variant of [AStar2D] that is specialized for partial 2D "
|
||||||
"grids. It is simpler to use because it doesn't require you to manually create "
|
"grids. It is simpler to use because it doesn't require you to manually create "
|
||||||
|
|
|
@ -87,13 +87,16 @@
|
||||||
# Alejandro Moctezuma <moctezumaalejandro25@gmail.com>, 2024.
|
# Alejandro Moctezuma <moctezumaalejandro25@gmail.com>, 2024.
|
||||||
# gallegonovato <fran-carro@hotmail.es>, 2024.
|
# gallegonovato <fran-carro@hotmail.es>, 2024.
|
||||||
# Andres David Calderon <andresdavidcalderonjimenez@gmail.com>, 2024.
|
# Andres David Calderon <andresdavidcalderonjimenez@gmail.com>, 2024.
|
||||||
|
# MayorTom4815 <domiisac2004@proton.me>, 2024.
|
||||||
|
# Jesús Arriaza <jesusarriaza0@gmail.com>, 2024.
|
||||||
|
# Simja 82 <simja.82@hotmail.com>, 2024.
|
||||||
|
# Keider Kaize <keiderkaize@gmail.com>, 2024.
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: Godot Engine class reference\n"
|
"Project-Id-Version: Godot Engine class reference\n"
|
||||||
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
|
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
|
||||||
"PO-Revision-Date: 2024-08-07 15:09+0000\n"
|
"PO-Revision-Date: 2024-09-13 04:52+0000\n"
|
||||||
"Last-Translator: Andres David Calderon <andresdavidcalderonjimenez@gmail."
|
"Last-Translator: Keider Kaize <keiderkaize@gmail.com>\n"
|
||||||
"com>\n"
|
|
||||||
"Language-Team: Spanish <https://hosted.weblate.org/projects/godot-engine/"
|
"Language-Team: Spanish <https://hosted.weblate.org/projects/godot-engine/"
|
||||||
"godot-class-reference/es/>\n"
|
"godot-class-reference/es/>\n"
|
||||||
"Language: es\n"
|
"Language: es\n"
|
||||||
|
@ -101,7 +104,7 @@ msgstr ""
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8-bit\n"
|
"Content-Transfer-Encoding: 8-bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||||
"X-Generator: Weblate 5.7-dev\n"
|
"X-Generator: Weblate 5.8-dev\n"
|
||||||
|
|
||||||
msgid "All classes"
|
msgid "All classes"
|
||||||
msgstr "Todas las clases"
|
msgstr "Todas las clases"
|
||||||
|
@ -777,6 +780,34 @@ msgstr ""
|
||||||
"[b]Nota:[/b] No se soporta la llamada a esta función desde un [Thread]. Si lo "
|
"[b]Nota:[/b] No se soporta la llamada a esta función desde un [Thread]. Si lo "
|
||||||
"hace, se imprimirá el ID del hilo."
|
"hace, se imprimirá el ID del hilo."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Prints a stack trace at the current code location. See also [method "
|
||||||
|
"get_stack].\n"
|
||||||
|
"The output in the console may look like the following:\n"
|
||||||
|
"[codeblock lang=text]\n"
|
||||||
|
"Frame 0 - res://test.gd:16 in function '_process'\n"
|
||||||
|
"[/codeblock]\n"
|
||||||
|
"[b]Note:[/b] This function only works if the running instance is connected to "
|
||||||
|
"a debugging server (i.e. an editor instance). [method print_stack] will not "
|
||||||
|
"work in projects exported in release mode, or in projects exported in debug "
|
||||||
|
"mode if not connected to a debugging server.\n"
|
||||||
|
"[b]Note:[/b] Calling this function from a [Thread] is not supported. Doing so "
|
||||||
|
"will instead print the thread ID."
|
||||||
|
msgstr ""
|
||||||
|
"Imprime un seguimiento de la pila en la ubicación de código actual. Véase "
|
||||||
|
"también [method get_stack].\n"
|
||||||
|
"La salida en la consola puede verse similar a la siguiente:\n"
|
||||||
|
"[codeblock lang=text]\n"
|
||||||
|
"Frame 0 - res://test.gd:16 in function '_process'\n"
|
||||||
|
"[/codeblock]\n"
|
||||||
|
"[b]Nota:[/b] Esta función solo actua correctamente si la instancia ejecutada "
|
||||||
|
"está conectada a un servidor de depuración (p.e. una instancia de editor). "
|
||||||
|
"[method print_stack] no funcionará en proyectos exportados en modo release, o "
|
||||||
|
"en proyectos exportados en modo depurar si no está conectado a un servidor de "
|
||||||
|
"depuración.\n"
|
||||||
|
"[b]Nota:[/b] Llamar a esta función desde [Thread] no está soportado. Hacerlo "
|
||||||
|
"en este caso imprimirá el ID del hilo."
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Returns [code]true[/code] if the given [Object]-derived class exists in "
|
"Returns [code]true[/code] if the given [Object]-derived class exists in "
|
||||||
"[ClassDB]. Note that [Variant] data types are not registered in [ClassDB].\n"
|
"[ClassDB]. Note that [Variant] data types are not registered in [ClassDB].\n"
|
||||||
|
@ -1526,6 +1557,28 @@ msgstr ""
|
||||||
"argumentos de cualquier tipo en una cadena de la mejor manera posible y los "
|
"argumentos de cualquier tipo en una cadena de la mejor manera posible y los "
|
||||||
"imprime en la consola."
|
"imprime en la consola."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Prints one or more arguments to the console with a space between each "
|
||||||
|
"argument.\n"
|
||||||
|
"[codeblocks]\n"
|
||||||
|
"[gdscript]\n"
|
||||||
|
"prints(\"A\", \"B\", \"C\") # Prints A B C\n"
|
||||||
|
"[/gdscript]\n"
|
||||||
|
"[csharp]\n"
|
||||||
|
"GD.PrintS(\"A\", \"B\", \"C\"); // Prints A B C\n"
|
||||||
|
"[/csharp]\n"
|
||||||
|
"[/codeblocks]"
|
||||||
|
msgstr ""
|
||||||
|
"Imprime uno o más argumentos en la consola con un espacio entre cada "
|
||||||
|
"argumento.\n"
|
||||||
|
"[codeblock]\n"
|
||||||
|
"[gdscript]\n"
|
||||||
|
"prints(\"A\", \"B\", \"C\") # Imprime A B C\n"
|
||||||
|
"[/gdscript]\n"
|
||||||
|
"GD.PrintS(\"A\",\"B\",\"C\");//Imprime A B C\n"
|
||||||
|
"[/csharp]\n"
|
||||||
|
"[/codeblocks]"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Given a [param seed], returns a [PackedInt64Array] of size [code]2[/code], "
|
"Given a [param seed], returns a [PackedInt64Array] of size [code]2[/code], "
|
||||||
"where its first element is the randomized [int] value, and the second element "
|
"where its first element is the randomized [int] value, and the second element "
|
||||||
|
@ -1554,6 +1607,107 @@ msgstr ""
|
||||||
"print(a[1])\t# Prints 4\n"
|
"print(a[1])\t# Prints 4\n"
|
||||||
"[/codeblock]"
|
"[/codeblock]"
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Randomizes the seed (or the internal state) of the random number generator. "
|
||||||
|
"The current implementation uses a number based on the device's time.\n"
|
||||||
|
"[b]Note:[/b] This function is called automatically when the project is run. "
|
||||||
|
"If you need to fix the seed to have consistent, reproducible results, use "
|
||||||
|
"[method seed] to initialize the random number generator."
|
||||||
|
msgstr ""
|
||||||
|
"Aleatorizar la semilla (o el estado interno) del generador de números "
|
||||||
|
"aleatorios. Es una implementación actual que utiliza un numero basado en el "
|
||||||
|
"tiempo del dispositivo.\n"
|
||||||
|
"[b]Nota:[/b] Esta función es llamada automáticamente cuando se ejecuta el "
|
||||||
|
"proyecto. Si se necesita arreglar la semilla para mas consistencia o "
|
||||||
|
"reproducir resultados, usa [method seed] para inicializar el generador de "
|
||||||
|
"números aleatorios."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Maps a [param value] from range [code][istart, istop][/code] to [code]"
|
||||||
|
"[ostart, ostop][/code]. See also [method lerp] and [method inverse_lerp]. If "
|
||||||
|
"[param value] is outside [code][istart, istop][/code], then the resulting "
|
||||||
|
"value will also be outside [code][ostart, ostop][/code]. If this is not "
|
||||||
|
"desired, use [method clamp] on the result of this function.\n"
|
||||||
|
"[codeblock]\n"
|
||||||
|
"remap(75, 0, 100, -1, 1) # Returns 0.5\n"
|
||||||
|
"[/codeblock]\n"
|
||||||
|
"For complex use cases where multiple ranges are needed, consider using "
|
||||||
|
"[Curve] or [Gradient] instead.\n"
|
||||||
|
"[b]Note:[/b] If [code]istart == istop[/code], the return value is undefined "
|
||||||
|
"(most likely NaN, INF, or -INF)."
|
||||||
|
msgstr ""
|
||||||
|
"Mapea un [param value] en un rango de [code][istart, istop][/code] a [code]"
|
||||||
|
"[ostart, ostop][/code]. Ver también [method lerp] y [method inverse_lerp]. Si "
|
||||||
|
"[param value] esta afuera [code][istart, istop][/code], entonces el valor "
|
||||||
|
"resultante también estara fuera [code][ostart, ostop][/code]. Si esto no es "
|
||||||
|
"lo deseado, use [method clamp] en el resultado de esta función.\n"
|
||||||
|
"[codeblock]\n"
|
||||||
|
"remap(75, 0, 100, -1, 1) #Devuelve 0.5\n"
|
||||||
|
"[/codeblock]\n"
|
||||||
|
"Para casos mas complejos en donde se requieran multiples rangos, considere "
|
||||||
|
"usar [Curve] o [Gradient] en su lugar.\n"
|
||||||
|
"[b]Nota:[/b] Si [code]istart == istop[/code], el valor devuelto es indefinido "
|
||||||
|
"(probablemente NaN, INF, o -INF)."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Allocates a unique ID which can be used by the implementation to construct an "
|
||||||
|
"RID. This is used mainly from native extensions to implement servers."
|
||||||
|
msgstr ""
|
||||||
|
"Asigna un ID único que puede se usado por la implementación para la "
|
||||||
|
"construcción de un RID. Esto se utiliza principalmente desde extensiones "
|
||||||
|
"nativas para implementar en servidores."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Creates an RID from a [param base]. This is used mainly from native "
|
||||||
|
"extensions to build servers."
|
||||||
|
msgstr ""
|
||||||
|
"Crea un RID a partir de un [param base]. Esto es usado principalmente por "
|
||||||
|
"extensiones nativas para la constricción de servidores."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Rounds [param x] to the nearest whole number, with halfway cases rounded away "
|
||||||
|
"from 0. Supported types: [int], [float], [Vector2], [Vector2i], [Vector3], "
|
||||||
|
"[Vector3i], [Vector4], [Vector4i].\n"
|
||||||
|
"[codeblock]\n"
|
||||||
|
"round(2.4) # Returns 2\n"
|
||||||
|
"round(2.5) # Returns 3\n"
|
||||||
|
"round(2.6) # Returns 3\n"
|
||||||
|
"[/codeblock]\n"
|
||||||
|
"See also [method floor], [method ceil], and [method snapped].\n"
|
||||||
|
"[b]Note:[/b] For better type safety, use [method roundf], [method roundi], "
|
||||||
|
"[method Vector2.round], [method Vector3.round], or [method Vector4.round]."
|
||||||
|
msgstr ""
|
||||||
|
"Redondea [param x] al número entero más cercano, con los casos intermedios "
|
||||||
|
"redondeados a partir de 0. Datos soportados: [int], [float], [Vector2], "
|
||||||
|
"[Vector2i], [Vector3], [Vector3i], [Vector4], [Vector4i].\n"
|
||||||
|
"[codeblock]\n"
|
||||||
|
"round(2.4) # Devuelve 2\n"
|
||||||
|
"round(2.5) # Devuelve 3\n"
|
||||||
|
"round(2.6) # Devuelve 3\n"
|
||||||
|
"[/codeblock]\n"
|
||||||
|
"Ver también [method floor], [method ceil], y [method snapped].\n"
|
||||||
|
"[b]Nota:[/b] Para un mejor tipado seguro, use [method roundf], [method "
|
||||||
|
"roundi], [method Vector2.round], [method Vector3.round], o [method Vector4."
|
||||||
|
"round]."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Rounds [param x] to the nearest whole number, with halfway cases rounded away "
|
||||||
|
"from 0.\n"
|
||||||
|
"A type-safe version of [method round], returning a [float]."
|
||||||
|
msgstr ""
|
||||||
|
"Redondea [param x] al numero entero mas cercano, con los casos intermedios "
|
||||||
|
"redondeados a partir de 0.\n"
|
||||||
|
"Es una version de tipado seguro del [method round] , retorna un [float]."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Rounds [param x] to the nearest whole number, with halfway cases rounded away "
|
||||||
|
"from 0.\n"
|
||||||
|
"A type-safe version of [method round], returning an [int]."
|
||||||
|
msgstr ""
|
||||||
|
"Redondea [param x] al numero entero mas cercano, con los casos intermedios "
|
||||||
|
"redondeados a partir de 0.\n"
|
||||||
|
"Es una version de tipado seguro del [method round] , retorna un [int]."
|
||||||
|
|
||||||
msgid "The [AudioServer] singleton."
|
msgid "The [AudioServer] singleton."
|
||||||
msgstr "El singleton [AudioServer]."
|
msgstr "El singleton [AudioServer]."
|
||||||
|
|
||||||
|
@ -2449,9 +2603,6 @@ msgstr "Operador NOT lógico ([code]NOT[/code] o [code]![/code])."
|
||||||
msgid "Logical IN operator ([code]in[/code])."
|
msgid "Logical IN operator ([code]in[/code])."
|
||||||
msgstr "Operador lógico In ([code]in[/code])."
|
msgstr "Operador lógico In ([code]in[/code])."
|
||||||
|
|
||||||
msgid "Represents the size of the [enum Variant.Operator] enum."
|
|
||||||
msgstr "Representa el tamaño del enum [enum Variant.Operator]."
|
|
||||||
|
|
||||||
msgid "Math documentation index"
|
msgid "Math documentation index"
|
||||||
msgstr "Índice de documentación matemática"
|
msgstr "Índice de documentación matemática"
|
||||||
|
|
||||||
|
@ -15622,13 +15773,6 @@ msgstr ""
|
||||||
msgid "Sets the shape of the occluder polygon."
|
msgid "Sets the shape of the occluder polygon."
|
||||||
msgstr "Establece la forma del polígono oclusor."
|
msgstr "Establece la forma del polígono oclusor."
|
||||||
|
|
||||||
msgid ""
|
|
||||||
"A copy of the canvas item will be drawn with a local offset of the mirroring "
|
|
||||||
"[Vector2]."
|
|
||||||
msgstr ""
|
|
||||||
"Se dibujará una copia del objeto de canvas con un desplazamiento local del "
|
|
||||||
"espejo [Vector2]."
|
|
||||||
|
|
||||||
msgid "Modulates all colors in the given canvas."
|
msgid "Modulates all colors in the given canvas."
|
||||||
msgstr "Modula todos los colores en el canvas dado."
|
msgstr "Modula todos los colores en el canvas dado."
|
||||||
|
|
||||||
|
|
|
@ -105,13 +105,15 @@
|
||||||
# Unreal Vision <unrealvisionyt@gmail.com>, 2024.
|
# Unreal Vision <unrealvisionyt@gmail.com>, 2024.
|
||||||
# Romain Defente <rdefente@gmail.com>, 2024.
|
# Romain Defente <rdefente@gmail.com>, 2024.
|
||||||
# zefdzeqf <azrzrezfafe@users.noreply.hosted.weblate.org>, 2024.
|
# zefdzeqf <azrzrezfafe@users.noreply.hosted.weblate.org>, 2024.
|
||||||
|
# Edvard Fauchelevent <edvardfauchelevent@gmail.com>, 2024.
|
||||||
|
# Fontaine Nathan <nathan.fontaine53@gmail.com>, 2024.
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: Godot Engine class reference\n"
|
"Project-Id-Version: Godot Engine class reference\n"
|
||||||
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
|
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
|
||||||
"POT-Creation-Date: \n"
|
"POT-Creation-Date: \n"
|
||||||
"PO-Revision-Date: 2024-07-16 05:13+0000\n"
|
"PO-Revision-Date: 2024-09-04 20:31+0000\n"
|
||||||
"Last-Translator: zefdzeqf <azrzrezfafe@users.noreply.hosted.weblate.org>\n"
|
"Last-Translator: Fontaine Nathan <nathan.fontaine53@gmail.com>\n"
|
||||||
"Language-Team: French <https://hosted.weblate.org/projects/godot-engine/godot-"
|
"Language-Team: French <https://hosted.weblate.org/projects/godot-engine/godot-"
|
||||||
"class-reference/fr/>\n"
|
"class-reference/fr/>\n"
|
||||||
"Language: fr\n"
|
"Language: fr\n"
|
||||||
|
@ -119,7 +121,7 @@ msgstr ""
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=n > 1;\n"
|
"Plural-Forms: nplurals=2; plural=n > 1;\n"
|
||||||
"X-Generator: Weblate 5.7-dev\n"
|
"X-Generator: Weblate 5.7.2-rc\n"
|
||||||
|
|
||||||
msgid "All classes"
|
msgid "All classes"
|
||||||
msgstr "Toutes les classes"
|
msgstr "Toutes les classes"
|
||||||
|
@ -6937,6 +6939,121 @@ msgstr "Toutes les particules seront émises depuis l'intérieur d'une boite."
|
||||||
msgid "Particles will be emitted in a ring or cylinder."
|
msgid "Particles will be emitted in a ring or cylinder."
|
||||||
msgstr "Toutes les particules seront émises depuis un anneau ou un cylindre."
|
msgstr "Toutes les particules seront émises depuis un anneau ou un cylindre."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"The Crypto class provides access to advanced cryptographic functionalities.\n"
|
||||||
|
"Currently, this includes asymmetric key encryption/decryption, signing/"
|
||||||
|
"verification, and generating cryptographically secure random bytes, RSA keys, "
|
||||||
|
"HMAC digests, and self-signed [X509Certificate]s.\n"
|
||||||
|
"[codeblocks]\n"
|
||||||
|
"[gdscript]\n"
|
||||||
|
"var crypto = Crypto.new()\n"
|
||||||
|
"\n"
|
||||||
|
"# Generate new RSA key.\n"
|
||||||
|
"var key = crypto.generate_rsa(4096)\n"
|
||||||
|
"\n"
|
||||||
|
"# Generate new self-signed certificate with the given key.\n"
|
||||||
|
"var cert = crypto.generate_self_signed_certificate(key, \"CN=mydomain.com,"
|
||||||
|
"O=My Game Company,C=IT\")\n"
|
||||||
|
"\n"
|
||||||
|
"# Save key and certificate in the user folder.\n"
|
||||||
|
"key.save(\"user://generated.key\")\n"
|
||||||
|
"cert.save(\"user://generated.crt\")\n"
|
||||||
|
"\n"
|
||||||
|
"# Encryption\n"
|
||||||
|
"var data = \"Some data\"\n"
|
||||||
|
"var encrypted = crypto.encrypt(key, data.to_utf8_buffer())\n"
|
||||||
|
"\n"
|
||||||
|
"# Decryption\n"
|
||||||
|
"var decrypted = crypto.decrypt(key, encrypted)\n"
|
||||||
|
"\n"
|
||||||
|
"# Signing\n"
|
||||||
|
"var signature = crypto.sign(HashingContext.HASH_SHA256, data.sha256_buffer(), "
|
||||||
|
"key)\n"
|
||||||
|
"\n"
|
||||||
|
"# Verifying\n"
|
||||||
|
"var verified = crypto.verify(HashingContext.HASH_SHA256, data."
|
||||||
|
"sha256_buffer(), signature, key)\n"
|
||||||
|
"\n"
|
||||||
|
"# Checks\n"
|
||||||
|
"assert(verified)\n"
|
||||||
|
"assert(data.to_utf8_buffer() == decrypted)\n"
|
||||||
|
"[/gdscript]\n"
|
||||||
|
"[csharp]\n"
|
||||||
|
"using Godot;\n"
|
||||||
|
"using System.Diagnostics;\n"
|
||||||
|
"\n"
|
||||||
|
"Crypto crypto = new Crypto();\n"
|
||||||
|
"\n"
|
||||||
|
"// Generate new RSA key.\n"
|
||||||
|
"CryptoKey key = crypto.GenerateRsa(4096);\n"
|
||||||
|
"\n"
|
||||||
|
"// Generate new self-signed certificate with the given key.\n"
|
||||||
|
"X509Certificate cert = crypto.GenerateSelfSignedCertificate(key, "
|
||||||
|
"\"CN=mydomain.com,O=My Game Company,C=IT\");\n"
|
||||||
|
"\n"
|
||||||
|
"// Save key and certificate in the user folder.\n"
|
||||||
|
"key.Save(\"user://generated.key\");\n"
|
||||||
|
"cert.Save(\"user://generated.crt\");\n"
|
||||||
|
"\n"
|
||||||
|
"// Encryption\n"
|
||||||
|
"string data = \"Some data\";\n"
|
||||||
|
"byte[] encrypted = crypto.Encrypt(key, data.ToUtf8Buffer());\n"
|
||||||
|
"\n"
|
||||||
|
"// Decryption\n"
|
||||||
|
"byte[] decrypted = crypto.Decrypt(key, encrypted);\n"
|
||||||
|
"\n"
|
||||||
|
"// Signing\n"
|
||||||
|
"byte[] signature = crypto.Sign(HashingContext.HashType.Sha256, Data."
|
||||||
|
"Sha256Buffer(), key);\n"
|
||||||
|
"\n"
|
||||||
|
"// Verifying\n"
|
||||||
|
"bool verified = crypto.Verify(HashingContext.HashType.Sha256, Data."
|
||||||
|
"Sha256Buffer(), signature, key);\n"
|
||||||
|
"\n"
|
||||||
|
"// Checks\n"
|
||||||
|
"Debug.Assert(verified);\n"
|
||||||
|
"Debug.Assert(data.ToUtf8Buffer() == decrypted);\n"
|
||||||
|
"[/csharp]\n"
|
||||||
|
"[/codeblocks]"
|
||||||
|
msgstr ""
|
||||||
|
"La classe Crypto permet d'accéder à des fonctionnalités cryptographiques plus "
|
||||||
|
"avancées dans Godot.\n"
|
||||||
|
"Pour l'instant, cela inclus la génération de données aléatoires pour des "
|
||||||
|
"utilisations cryptographiques, la génération de clés RSA et de certificats "
|
||||||
|
"auto-signés X509, de clé asymétriques de cryptage/décryptage, la signature et "
|
||||||
|
"la vérification.\n"
|
||||||
|
"[codeblock]\n"
|
||||||
|
"extends Node\n"
|
||||||
|
"\n"
|
||||||
|
"var crypto = Crypto.new()\n"
|
||||||
|
"var key = CryptoKey.new()\n"
|
||||||
|
"var cert = X509Certificate.new()\n"
|
||||||
|
"\n"
|
||||||
|
"func _ready():\n"
|
||||||
|
" # Générer une nouvelle clé RSA.\n"
|
||||||
|
" key = crypto.generate_rsa(4096)\n"
|
||||||
|
" # Générer un nouveau certificat auto-signé avec le clé.\n"
|
||||||
|
" cert = crypto.generate_self_signed_certificate(key, \"CN=mydomain.com,"
|
||||||
|
"O=My Game Company,C=IT\")\n"
|
||||||
|
" # Enregistrer la clé et le certificat dans le dossier utilisateur.\n"
|
||||||
|
" key.save(\"user://generated.key\")\n"
|
||||||
|
" cert.save(\"user://generated.crt\")\n"
|
||||||
|
" # Cryptage\n"
|
||||||
|
" var data = \"Des données\"\n"
|
||||||
|
" var encrypted = crypto.encrypt(key, data.to_utf8())\n"
|
||||||
|
" # Décryptage\n"
|
||||||
|
" var decrypted = crypto.decrypt(key, encrypted)\n"
|
||||||
|
" # Signature\n"
|
||||||
|
" var signature = crypto.sign(HashingContext.HASH_SHA256, data."
|
||||||
|
"sha256_buffer(), key)\n"
|
||||||
|
" # Vérification\n"
|
||||||
|
" var verified = crypto.verify(HashingContext.HASH_SHA256, data."
|
||||||
|
"sha256_buffer(), signature, key)\n"
|
||||||
|
" # Tests\n"
|
||||||
|
" assert(verified)\n"
|
||||||
|
" assert(data.to_utf8() == decrypted)\n"
|
||||||
|
"[/codeblock]"
|
||||||
|
|
||||||
msgid "SSL certificates"
|
msgid "SSL certificates"
|
||||||
msgstr "Certificats SSL"
|
msgstr "Certificats SSL"
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -10762,23 +10762,6 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Appende [param value] alla fine dell'array (alias di [method push_back])."
|
"Appende [param value] alla fine dell'array (alias di [method push_back])."
|
||||||
|
|
||||||
msgid ""
|
|
||||||
"Appends another [param array] at the end of this array.\n"
|
|
||||||
"[codeblock]\n"
|
|
||||||
"var numbers = [1, 2, 3]\n"
|
|
||||||
"var extra = [4, 5, 6]\n"
|
|
||||||
"numbers.append_array(extra)\n"
|
|
||||||
"print(nums) # Prints [1, 2, 3, 4, 5, 6]\n"
|
|
||||||
"[/codeblock]"
|
|
||||||
msgstr ""
|
|
||||||
"Accoda un altro [param array] alla fine di questo array.\n"
|
|
||||||
"[codeblock]\n"
|
|
||||||
"numeri = [1, 2, 3]\n"
|
|
||||||
"var aggiuntivi = [4, 5, 6]\n"
|
|
||||||
"numeri.append_array(aggiuntivi)\n"
|
|
||||||
"print(numeri) # Stampa [1, 2, 3, 4, 5, 6]\n"
|
|
||||||
"[/codeblock]"
|
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Assigns elements of another [param array] into the array. Resizes the array "
|
"Assigns elements of another [param array] into the array. Resizes the array "
|
||||||
"to match [param array]. Performs type conversions if the array is typed."
|
"to match [param array]. Performs type conversions if the array is typed."
|
||||||
|
@ -11579,87 +11562,6 @@ msgstr ""
|
||||||
"print(lettere.slice(4, 1, -1)) # Stampa [\"E\", \"D\", \"C\"]\n"
|
"print(lettere.slice(4, 1, -1)) # Stampa [\"E\", \"D\", \"C\"]\n"
|
||||||
"[/codeblock]"
|
"[/codeblock]"
|
||||||
|
|
||||||
msgid ""
|
|
||||||
"Sorts the array using a custom [Callable].\n"
|
|
||||||
"[param func] is called as many times as necessary, receiving two array "
|
|
||||||
"elements as arguments. The function should return [code]true[/code] if the "
|
|
||||||
"first element should be moved [i]behind[/i] the second one, otherwise it "
|
|
||||||
"should return [code]false[/code].\n"
|
|
||||||
"[codeblock]\n"
|
|
||||||
"func sort_ascending(a, b):\n"
|
|
||||||
" if a[1] < b[1]:\n"
|
|
||||||
" return true\n"
|
|
||||||
" return false\n"
|
|
||||||
"\n"
|
|
||||||
"func _ready():\n"
|
|
||||||
" var my_items = [[\"Tomato\", 5], [\"Apple\", 9], [\"Rice\", 4]]\n"
|
|
||||||
" my_items.sort_custom(sort_ascending)\n"
|
|
||||||
" print(my_items) # Prints [[\"Rice\", 4], [\"Tomato\", 5], [\"Apple\", "
|
|
||||||
"9]]\n"
|
|
||||||
"\n"
|
|
||||||
" # Sort descending, using a lambda function.\n"
|
|
||||||
" my_items.sort_custom(func(a, b): return a[0] > b[0])\n"
|
|
||||||
" print(my_items) # Prints [[\"Apple\", 9], [\"Tomato\", 5], [\"Rice\", "
|
|
||||||
"4]]\n"
|
|
||||||
"[/codeblock]\n"
|
|
||||||
"It may also be necessary to use this method to sort strings by natural order, "
|
|
||||||
"with [method String.naturalnocasecmp_to], as in the following example:\n"
|
|
||||||
"[codeblock]\n"
|
|
||||||
"var files = [\"newfile1\", \"newfile2\", \"newfile10\", \"newfile11\"]\n"
|
|
||||||
"files.sort_custom(func(a, b): return a.naturalnocasecmp_to(b) < 0)\n"
|
|
||||||
"print(files) # Prints [\"newfile1\", \"newfile2\", \"newfile10\", "
|
|
||||||
"\"newfile11\"]\n"
|
|
||||||
"[/codeblock]\n"
|
|
||||||
"[b]Note:[/b] In C#, this method is not supported.\n"
|
|
||||||
"[b]Note:[/b] The sorting algorithm used is not [url=https://en.wikipedia.org/"
|
|
||||||
"wiki/Sorting_algorithm#Stability]stable[/url]. This means that values "
|
|
||||||
"considered equal may have their order changed when calling this method.\n"
|
|
||||||
"[b]Note:[/b] You should not randomize the return value of [param func], as "
|
|
||||||
"the heapsort algorithm expects a consistent result. Randomizing the return "
|
|
||||||
"value will result in unexpected behavior."
|
|
||||||
msgstr ""
|
|
||||||
"Ordina l'array utilizzando un [Callable] personalizzato.\n"
|
|
||||||
"[param func] è chiamato quante più volte è necessario, ricevendo due elementi "
|
|
||||||
"dell'array come argomenti. La funzione dovrebbe restituire [code]true[/code] "
|
|
||||||
"se il primo elemento deve essere spostato [i]dietro[/i] al secondo, "
|
|
||||||
"altrimenti dovrebbe restituire [code]false[/code].\n"
|
|
||||||
"[codeblock]\n"
|
|
||||||
"func sort_ascending(a, b):\n"
|
|
||||||
" if a[1] < b[1]:\n"
|
|
||||||
" return true\n"
|
|
||||||
" return false\n"
|
|
||||||
"\n"
|
|
||||||
"func _ready():\n"
|
|
||||||
" var my_items = [[\"Pomodoro\", 5], [\"Mela\", 9], [\"Riso\", 4]]\n"
|
|
||||||
" my_items.sort_custom(sort_ascending)\n"
|
|
||||||
" print(my_items) # Stampa [[\"Riso\", 4], [\"Pomodoro\", 5], [\"Mela\", "
|
|
||||||
"9]]\n"
|
|
||||||
"\n"
|
|
||||||
" # Ordina in ordine decrescente, usando una funzione lambda.\n"
|
|
||||||
" my_items.sort_custom(func(a, b): return a[0] > b[0])\n"
|
|
||||||
" print(my_items) # Stampa [[\"Mela\", 9], [\"Pomodoro\", 5], [\"Riso\", "
|
|
||||||
"4]]\n"
|
|
||||||
"[/codeblock]\n"
|
|
||||||
"Può anche essere necessario utilizzare questo metodo per ordinare le stringhe "
|
|
||||||
"per ordine naturale, con [method String.naturalnocasecmp_to], come "
|
|
||||||
"nell'esempio seguente:\n"
|
|
||||||
"[codeblock]\n"
|
|
||||||
"var file_array = [\"nuovofile1\", \"nuovofile2\", \"nuovofile10\", "
|
|
||||||
"\"nuovofile11\"]\n"
|
|
||||||
"file_array.sort_custom(func(a, b): return a.naturalnocasecmp_to(b) < 0)\n"
|
|
||||||
"print(file_array) # Stampa [\"newfile1\", \"newfile2\", \"newfile10\", "
|
|
||||||
"\"newfile11\"]\n"
|
|
||||||
"[/codeblock]\n"
|
|
||||||
"[b]Nota:[/b] In C#, questo metodo non è supportato.\n"
|
|
||||||
"[b]Nota:[/b] L'algoritmo di selezione utilizzato non è [url=https://it."
|
|
||||||
"wikipedia.org/wiki/"
|
|
||||||
"Algoritmo_di_ordinamento#Stabilit%C3%A0_di_un_algoritmo]stabile[/url]. Ciò "
|
|
||||||
"significa che gli elementi considerati equivalenti potrebbero avere il loro "
|
|
||||||
"ordine cambiato quando si chiama [method sort].\n"
|
|
||||||
"[b]Nota:[/b] Non si dovrebbe randomizzare il valore di ritorno di [param "
|
|
||||||
"func], poiché l'algoritmo di heapsort si aspetta un risultato coerente. "
|
|
||||||
"Randomizzare il valore restituito risulterà in comportamento inaspettato."
|
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Returns [code]true[/code] if the array's size or its elements are different "
|
"Returns [code]true[/code] if the array's size or its elements are different "
|
||||||
"than [param right]'s."
|
"than [param right]'s."
|
||||||
|
@ -12187,85 +12089,6 @@ msgstr ""
|
||||||
"Il risultato è nel segmento che va da [code]y = 0[/code] a [code]y = 5[/"
|
"Il risultato è nel segmento che va da [code]y = 0[/code] a [code]y = 5[/"
|
||||||
"code]. È la posizione più vicina nel segmento al punto indicato."
|
"code]. È la posizione più vicina nel segmento al punto indicato."
|
||||||
|
|
||||||
msgid ""
|
|
||||||
"Returns an array with the IDs of the points that form the path found by "
|
|
||||||
"AStar2D between the given points. The array is ordered from the starting "
|
|
||||||
"point to the ending point of the path.\n"
|
|
||||||
"If there is no valid path to the target, and [param allow_partial_path] is "
|
|
||||||
"[code]true[/code], returns a path to the point closest to the target that can "
|
|
||||||
"be reached.\n"
|
|
||||||
"[codeblocks]\n"
|
|
||||||
"[gdscript]\n"
|
|
||||||
"var astar = AStar2D.new()\n"
|
|
||||||
"astar.add_point(1, Vector2(0, 0))\n"
|
|
||||||
"astar.add_point(2, Vector2(0, 1), 1) # Default weight is 1\n"
|
|
||||||
"astar.add_point(3, Vector2(1, 1))\n"
|
|
||||||
"astar.add_point(4, Vector2(2, 0))\n"
|
|
||||||
"\n"
|
|
||||||
"astar.connect_points(1, 2, false)\n"
|
|
||||||
"astar.connect_points(2, 3, false)\n"
|
|
||||||
"astar.connect_points(4, 3, false)\n"
|
|
||||||
"astar.connect_points(1, 4, false)\n"
|
|
||||||
"\n"
|
|
||||||
"var res = astar.get_id_path(1, 3) # Returns [1, 2, 3]\n"
|
|
||||||
"[/gdscript]\n"
|
|
||||||
"[csharp]\n"
|
|
||||||
"var astar = new AStar2D();\n"
|
|
||||||
"astar.AddPoint(1, new Vector2(0, 0));\n"
|
|
||||||
"astar.AddPoint(2, new Vector2(0, 1), 1); // Default weight is 1\n"
|
|
||||||
"astar.AddPoint(3, new Vector2(1, 1));\n"
|
|
||||||
"astar.AddPoint(4, new Vector2(2, 0));\n"
|
|
||||||
"\n"
|
|
||||||
"astar.ConnectPoints(1, 2, false);\n"
|
|
||||||
"astar.ConnectPoints(2, 3, false);\n"
|
|
||||||
"astar.ConnectPoints(4, 3, false);\n"
|
|
||||||
"astar.ConnectPoints(1, 4, false);\n"
|
|
||||||
"int[] res = astar.GetIdPath(1, 3); // Returns [1, 2, 3]\n"
|
|
||||||
"[/csharp]\n"
|
|
||||||
"[/codeblocks]\n"
|
|
||||||
"If you change the 2nd point's weight to 3, then the result will be [code][1, "
|
|
||||||
"4, 3][/code] instead, because now even though the distance is longer, it's "
|
|
||||||
"\"easier\" to get through point 4 than through point 2."
|
|
||||||
msgstr ""
|
|
||||||
"Restituisce un array con gli ID dei punti che formano il percorso trovato da "
|
|
||||||
"AStar2D tra i punti indicati. L'array è ordinato dal punto iniziale al punto "
|
|
||||||
"finale del percorso.\n"
|
|
||||||
"Se non c'è un percorso valido per l'obiettivo, e [param allow_partial_path] è "
|
|
||||||
"[code]true[/code], restituisce un percorso al punto più vicino all'obiettivo "
|
|
||||||
"che può essere raggiunto.\n"
|
|
||||||
"[codeblocks]\n"
|
|
||||||
"[gdscript]\n"
|
|
||||||
"var astar = AStar2D.new()\n"
|
|
||||||
"astar.add_point(1, Vector2(0, 0))\n"
|
|
||||||
"astar.add_point(2, Vector2(0, 1), 1) # Il peso predefinito è 1\n"
|
|
||||||
"astar.add_point(3, Vector2(1, 1))\n"
|
|
||||||
"astar.add_point(4, Vector2(2, 0))\n"
|
|
||||||
"\n"
|
|
||||||
"astar.connect_points(1, 2, false)\n"
|
|
||||||
"astar.connect_points(2, 3, false)\n"
|
|
||||||
"astar.connect_points(4, 3, false)\n"
|
|
||||||
"astar.connect_points(1, 4, false)\n"
|
|
||||||
"\n"
|
|
||||||
"var res = astar.get_id_path(1, 3) # Restituisce [1, 2, 3]\n"
|
|
||||||
"[/gdscript]\n"
|
|
||||||
"[csharp]\n"
|
|
||||||
"var astar = new AStar2D();\n"
|
|
||||||
"astar.AddPoint(1, new Vector2(0, 0));\n"
|
|
||||||
"astar.AddPoint(2, new Vector2(0, 1), 1); // Il peso predefinito è 1\n"
|
|
||||||
"astar.AddPoint(3, new Vector2(1, 1));\n"
|
|
||||||
"astar.AddPoint(4, new Vector2(2, 0));\n"
|
|
||||||
"\n"
|
|
||||||
"astar.ConnectPoints(1, 2, false);\n"
|
|
||||||
"astar.ConnectPoints(2, 3, false);\n"
|
|
||||||
"astar.ConnectPoints(4, 3, false);\n"
|
|
||||||
"astar.ConnectPoints(1, 4, false);\n"
|
|
||||||
"int[] res = astar.GetIdPath(1, 3); // Restituisce [1, 2, 3]\n"
|
|
||||||
"[/csharp]\n"
|
|
||||||
"[/codeblocks]\n"
|
|
||||||
"Se si cambia il peso a 3 per il punto 2, allora il risultato sarà [code][1, "
|
|
||||||
"4, 3][/code] invece, poiché adesso anche se la distanza è più lunga, è \"più "
|
|
||||||
"facile\" arrivare attraverso il punto 4 che attraverso il punto 2."
|
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Returns the capacity of the structure backing the points, useful in "
|
"Returns the capacity of the structure backing the points, useful in "
|
||||||
"conjunction with [method reserve_space]."
|
"conjunction with [method reserve_space]."
|
||||||
|
@ -12273,65 +12096,6 @@ msgstr ""
|
||||||
"Restituisce la capacità della struttura che sostiene i punti, utile in "
|
"Restituisce la capacità della struttura che sostiene i punti, utile in "
|
||||||
"combinazione con [method reserve_space]."
|
"combinazione con [method reserve_space]."
|
||||||
|
|
||||||
msgid ""
|
|
||||||
"Returns an array with the IDs of the points that form the connection with the "
|
|
||||||
"given point.\n"
|
|
||||||
"[codeblocks]\n"
|
|
||||||
"[gdscript]\n"
|
|
||||||
"var astar = AStar2D.new()\n"
|
|
||||||
"astar.add_point(1, Vector2(0, 0))\n"
|
|
||||||
"astar.add_point(2, Vector2(0, 1))\n"
|
|
||||||
"astar.add_point(3, Vector2(1, 1))\n"
|
|
||||||
"astar.add_point(4, Vector2(2, 0))\n"
|
|
||||||
"\n"
|
|
||||||
"astar.connect_points(1, 2, true)\n"
|
|
||||||
"astar.connect_points(1, 3, true)\n"
|
|
||||||
"\n"
|
|
||||||
"var neighbors = astar.get_point_connections(1) # Returns [2, 3]\n"
|
|
||||||
"[/gdscript]\n"
|
|
||||||
"[csharp]\n"
|
|
||||||
"var astar = new AStar2D();\n"
|
|
||||||
"astar.AddPoint(1, new Vector2(0, 0));\n"
|
|
||||||
"astar.AddPoint(2, new Vector2(0, 1));\n"
|
|
||||||
"astar.AddPoint(3, new Vector2(1, 1));\n"
|
|
||||||
"astar.AddPoint(4, new Vector2(2, 0));\n"
|
|
||||||
"\n"
|
|
||||||
"astar.ConnectPoints(1, 2, true);\n"
|
|
||||||
"astar.ConnectPoints(1, 3, true);\n"
|
|
||||||
"\n"
|
|
||||||
"int[] neighbors = astar.GetPointConnections(1); // Returns [2, 3]\n"
|
|
||||||
"[/csharp]\n"
|
|
||||||
"[/codeblocks]"
|
|
||||||
msgstr ""
|
|
||||||
"Restituisce un array con gli ID dei punti che formano la connessione con il "
|
|
||||||
"punto indicato.\n"
|
|
||||||
"[codeblocks]\n"
|
|
||||||
"[gdscript]\n"
|
|
||||||
"var astar = AStar2D.new()\n"
|
|
||||||
"astar.add_point(1, Vector2(0, 0))\n"
|
|
||||||
"astar.add_point(2, Vector2(0, 1))\n"
|
|
||||||
"astar.add_point(3, Vector2(1, 1))\n"
|
|
||||||
"astar.add_point(4, Vector2(2, 0))\n"
|
|
||||||
"\n"
|
|
||||||
"astar.connect_points(1, 2, true)\n"
|
|
||||||
"astar.connect_points(1, 3, true)\n"
|
|
||||||
"\n"
|
|
||||||
"var neighbors = astar.get_point_connections(1) # Restituisce [2, 3]\n"
|
|
||||||
"[/gdscript]\n"
|
|
||||||
"[csharp]\n"
|
|
||||||
"var astar = new AStar2D();\n"
|
|
||||||
"astar.AddPoint(1, new Vector2(0, 0));\n"
|
|
||||||
"astar.AddPoint(2, new Vector2(0, 1));\n"
|
|
||||||
"astar.AddPoint(3, new Vector2(1, 1));\n"
|
|
||||||
"astar.AddPoint(4, new Vector2(2, 0));\n"
|
|
||||||
"\n"
|
|
||||||
"astar.ConnectPoints(1, 2, true);\n"
|
|
||||||
"astar.ConnectPoints(1, 3, true);\n"
|
|
||||||
"\n"
|
|
||||||
"int[] neighbors = astar.GetPointConnections(1); // Restituisce [2, 3]\n"
|
|
||||||
"[/csharp]\n"
|
|
||||||
"[/codeblocks]"
|
|
||||||
|
|
||||||
msgid "Returns the number of points currently in the points pool."
|
msgid "Returns the number of points currently in the points pool."
|
||||||
msgstr "Restituisce il numero di punti attualmente nell'insieme dei punti."
|
msgstr "Restituisce il numero di punti attualmente nell'insieme dei punti."
|
||||||
|
|
||||||
|
@ -12444,140 +12208,6 @@ msgstr ""
|
||||||
"movimento da [param id] a [param to_id] è possibile attraverso questo "
|
"movimento da [param id] a [param to_id] è possibile attraverso questo "
|
||||||
"segmento."
|
"segmento."
|
||||||
|
|
||||||
msgid ""
|
|
||||||
"Returns an array with the IDs of the points that form the path found by "
|
|
||||||
"AStar3D between the given points. The array is ordered from the starting "
|
|
||||||
"point to the ending point of the path.\n"
|
|
||||||
"If there is no valid path to the target, and [param allow_partial_path] is "
|
|
||||||
"[code]true[/code], returns a path to the point closest to the target that can "
|
|
||||||
"be reached.\n"
|
|
||||||
"[codeblocks]\n"
|
|
||||||
"[gdscript]\n"
|
|
||||||
"var astar = AStar3D.new()\n"
|
|
||||||
"astar.add_point(1, Vector3(0, 0, 0))\n"
|
|
||||||
"astar.add_point(2, Vector3(0, 1, 0), 1) # Default weight is 1\n"
|
|
||||||
"astar.add_point(3, Vector3(1, 1, 0))\n"
|
|
||||||
"astar.add_point(4, Vector3(2, 0, 0))\n"
|
|
||||||
"\n"
|
|
||||||
"astar.connect_points(1, 2, false)\n"
|
|
||||||
"astar.connect_points(2, 3, false)\n"
|
|
||||||
"astar.connect_points(4, 3, false)\n"
|
|
||||||
"astar.connect_points(1, 4, false)\n"
|
|
||||||
"\n"
|
|
||||||
"var res = astar.get_id_path(1, 3) # Returns [1, 2, 3]\n"
|
|
||||||
"[/gdscript]\n"
|
|
||||||
"[csharp]\n"
|
|
||||||
"var astar = new AStar3D();\n"
|
|
||||||
"astar.AddPoint(1, new Vector3(0, 0, 0));\n"
|
|
||||||
"astar.AddPoint(2, new Vector3(0, 1, 0), 1); // Default weight is 1\n"
|
|
||||||
"astar.AddPoint(3, new Vector3(1, 1, 0));\n"
|
|
||||||
"astar.AddPoint(4, new Vector3(2, 0, 0));\n"
|
|
||||||
"astar.ConnectPoints(1, 2, false);\n"
|
|
||||||
"astar.ConnectPoints(2, 3, false);\n"
|
|
||||||
"astar.ConnectPoints(4, 3, false);\n"
|
|
||||||
"astar.ConnectPoints(1, 4, false);\n"
|
|
||||||
"int[] res = astar.GetIdPath(1, 3); // Returns [1, 2, 3]\n"
|
|
||||||
"[/csharp]\n"
|
|
||||||
"[/codeblocks]\n"
|
|
||||||
"If you change the 2nd point's weight to 3, then the result will be [code][1, "
|
|
||||||
"4, 3][/code] instead, because now even though the distance is longer, it's "
|
|
||||||
"\"easier\" to get through point 4 than through point 2."
|
|
||||||
msgstr ""
|
|
||||||
"Restituisce un array con gli ID dei punti che formano il percorso trovato da "
|
|
||||||
"AStar3D tra i punti indicati. L'array è ordinato dal punto iniziale al punto "
|
|
||||||
"finale del percorso.\n"
|
|
||||||
"Se non c'è un percorso valido per l'obiettivo, e [param allow_partial_path] è "
|
|
||||||
"[code]true[/code], restituisce un percorso al punto più vicino all'obiettivo "
|
|
||||||
"che può essere raggiunto.\n"
|
|
||||||
"[codeblocks]\n"
|
|
||||||
"[gdscript]\n"
|
|
||||||
"var astar = AStar3D.new()\n"
|
|
||||||
"astar.add_point(1, Vector3(0, 0, 0))\n"
|
|
||||||
"astar.add_point(2, Vector3(0, 1, 0), 1) # Il peso predefinito è 1\n"
|
|
||||||
"astar.add_point(3, Vector3(1, 1, 0))\n"
|
|
||||||
"astar.add_point(4, Vector3(2, 0, 0))\n"
|
|
||||||
"\n"
|
|
||||||
"astar.connect_points(1, 2, false)\n"
|
|
||||||
"astar.connect_points(2, 3, false)\n"
|
|
||||||
"astar.connect_points(4, 3, false)\n"
|
|
||||||
"astar.connect_points(1, 4, false)\n"
|
|
||||||
"\n"
|
|
||||||
"var res = astar.get_id_path(1, 3) # Restituisce [1, 2, 3]\n"
|
|
||||||
"[/gdscript]\n"
|
|
||||||
"[csharp]\n"
|
|
||||||
"var astar = new AStar3D();\n"
|
|
||||||
"astar.AddPoint(1, new Vector3(0, 0, 0));\n"
|
|
||||||
"astar.AddPoint(2, new Vector3(0, 1, 0), 1); // Il peso predefinito è 1\n"
|
|
||||||
"astar.AddPoint(3, new Vector3(1, 1, 0));\n"
|
|
||||||
"astar.AddPoint(4, new Vector3(2, 0, 0));\n"
|
|
||||||
"astar.ConnectPoints(1, 2, false);\n"
|
|
||||||
"astar.ConnectPoints(2, 3, false);\n"
|
|
||||||
"astar.ConnectPoints(4, 3, false);\n"
|
|
||||||
"astar.ConnectPoints(1, 4, false);\n"
|
|
||||||
"int[] res = astar.GetIdPath(1, 3); // Restituisce [1, 2, 3]\n"
|
|
||||||
"[/csharp]\n"
|
|
||||||
"[/codeblocks]\n"
|
|
||||||
"Se si cambia il peso a 3 per il punto 2, allora il risultato sarà [code][1, "
|
|
||||||
"4, 3][/code] invece, poiché adesso anche se la distanza è più lunga, è \"più "
|
|
||||||
"facile\" arrivare attraverso il punto 4 che attraverso il punto 2."
|
|
||||||
|
|
||||||
msgid ""
|
|
||||||
"Returns an array with the IDs of the points that form the connection with the "
|
|
||||||
"given point.\n"
|
|
||||||
"[codeblocks]\n"
|
|
||||||
"[gdscript]\n"
|
|
||||||
"var astar = AStar3D.new()\n"
|
|
||||||
"astar.add_point(1, Vector3(0, 0, 0))\n"
|
|
||||||
"astar.add_point(2, Vector3(0, 1, 0))\n"
|
|
||||||
"astar.add_point(3, Vector3(1, 1, 0))\n"
|
|
||||||
"astar.add_point(4, Vector3(2, 0, 0))\n"
|
|
||||||
"\n"
|
|
||||||
"astar.connect_points(1, 2, true)\n"
|
|
||||||
"astar.connect_points(1, 3, true)\n"
|
|
||||||
"\n"
|
|
||||||
"var neighbors = astar.get_point_connections(1) # Returns [2, 3]\n"
|
|
||||||
"[/gdscript]\n"
|
|
||||||
"[csharp]\n"
|
|
||||||
"var astar = new AStar3D();\n"
|
|
||||||
"astar.AddPoint(1, new Vector3(0, 0, 0));\n"
|
|
||||||
"astar.AddPoint(2, new Vector3(0, 1, 0));\n"
|
|
||||||
"astar.AddPoint(3, new Vector3(1, 1, 0));\n"
|
|
||||||
"astar.AddPoint(4, new Vector3(2, 0, 0));\n"
|
|
||||||
"astar.ConnectPoints(1, 2, true);\n"
|
|
||||||
"astar.ConnectPoints(1, 3, true);\n"
|
|
||||||
"\n"
|
|
||||||
"int[] neighbors = astar.GetPointConnections(1); // Returns [2, 3]\n"
|
|
||||||
"[/csharp]\n"
|
|
||||||
"[/codeblocks]"
|
|
||||||
msgstr ""
|
|
||||||
"Restituisce un array con gli ID dei punti che formano la connessione con il "
|
|
||||||
"punto indicato.\n"
|
|
||||||
"[codeblocks]\n"
|
|
||||||
"[gdscript]\n"
|
|
||||||
"var astar = AStar3D.new()\n"
|
|
||||||
"astar.add_point(1, Vector3(0, 0, 0))\n"
|
|
||||||
"astar.add_point(2, Vector3(0, 1, 0))\n"
|
|
||||||
"astar.add_point(3, Vector3(1, 1, 0))\n"
|
|
||||||
"astar.add_point(4, Vector3(2, 0, 0))\n"
|
|
||||||
"\n"
|
|
||||||
"astar.connect_points(1, 2, true)\n"
|
|
||||||
"astar.connect_points(1, 3, true)\n"
|
|
||||||
"\n"
|
|
||||||
"var neighbors = astar.get_point_connections(1) # Restituisce [2, 3]\n"
|
|
||||||
"[/gdscript]\n"
|
|
||||||
"[csharp]\n"
|
|
||||||
"var astar = new AStar3D();\n"
|
|
||||||
"astar.AddPoint(1, new Vector3(0, 0, 0));\n"
|
|
||||||
"astar.AddPoint(2, new Vector3(0, 1, 0));\n"
|
|
||||||
"astar.AddPoint(3, new Vector3(1, 1, 0));\n"
|
|
||||||
"astar.AddPoint(4, new Vector3(2, 0, 0));\n"
|
|
||||||
"astar.ConnectPoints(1, 2, true);\n"
|
|
||||||
"astar.ConnectPoints(1, 3, true);\n"
|
|
||||||
"\n"
|
|
||||||
"int[] neighbors = astar.GetPointConnections(1); // Restituisce [2, 3]\n"
|
|
||||||
"[/csharp]\n"
|
|
||||||
"[/codeblocks]"
|
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Returns an array with the points that are in the path found by AStar3D "
|
"Returns an array with the points that are in the path found by AStar3D "
|
||||||
"between the given points. The array is ordered from the starting point to the "
|
"between the given points. The array is ordered from the starting point to the "
|
||||||
|
@ -28011,25 +27641,6 @@ msgstr ""
|
||||||
"Elimina il punto all'indice [param idx] dalla curva. Invia un errore alla "
|
"Elimina il punto all'indice [param idx] dalla curva. Invia un errore alla "
|
||||||
"console se [param idx] è fuori dai limiti."
|
"console se [param idx] è fuori dai limiti."
|
||||||
|
|
||||||
msgid ""
|
|
||||||
"Returns the position between the vertex [param idx] and the vertex [code]idx "
|
|
||||||
"+ 1[/code], where [param t] controls if the point is the first vertex "
|
|
||||||
"([code]t = 0.0[/code]), the last vertex ([code]t = 1.0[/code]), or in "
|
|
||||||
"between. Values of [param t] outside the range ([code]0.0 >= t <=1[/code]) "
|
|
||||||
"give strange, but predictable results.\n"
|
|
||||||
"If [param idx] is out of bounds it is truncated to the first or last vertex, "
|
|
||||||
"and [param t] is ignored. If the curve has no points, the function sends an "
|
|
||||||
"error to the console, and returns [code](0, 0)[/code]."
|
|
||||||
msgstr ""
|
|
||||||
"Restituisce la posizione tra il vertice [param idx] e il vertice [code]idx + "
|
|
||||||
"1[/code], dove [param t] controlla se il punto è il primo vertice ([code]t = "
|
|
||||||
"0,0[/code]), l'ultimo vertice ([code]t = 1,0[/code]) o intermedio. I valori "
|
|
||||||
"di [param t] al di fuori dell'intervallo ([code]0,0 >= t <=1[/code]) danno "
|
|
||||||
"risultati strani, ma prevedibili.\n"
|
|
||||||
"Se [param idx] è fuori dai limiti, viene troncato al primo o all'ultimo "
|
|
||||||
"vertice e [param t] viene ignorato. Se la curva non ha punti, la funzione "
|
|
||||||
"invia un errore alla console e restituisce [code](0, 0)[/code]."
|
|
||||||
|
|
||||||
msgid "Returns the cache of points as a [PackedVector3Array]."
|
msgid "Returns the cache of points as a [PackedVector3Array]."
|
||||||
msgstr "Restituisce i punti memorizzati nella cache come [PackedVector3Array]."
|
msgstr "Restituisce i punti memorizzati nella cache come [PackedVector3Array]."
|
||||||
|
|
||||||
|
@ -93310,23 +92921,6 @@ msgstr ""
|
||||||
"ThemeDB.fallback_font]).\n"
|
"ThemeDB.fallback_font]).\n"
|
||||||
"Usa [method has_default_font] per verificare se questo valore è valido."
|
"Usa [method has_default_font] per verificare se questo valore è valido."
|
||||||
|
|
||||||
msgid ""
|
|
||||||
"The default font size of this theme resource. Used as the default value when "
|
|
||||||
"trying to fetch a font size value that doesn't exist in this theme or is in "
|
|
||||||
"invalid state. If the default font size is also missing or invalid, the "
|
|
||||||
"engine fallback value is used (see [member ThemeDB.fallback_font_size]).\n"
|
|
||||||
"Values below [code]0[/code] are invalid and can be used to unset the "
|
|
||||||
"property. Use [method has_default_font_size] to check if this value is valid."
|
|
||||||
msgstr ""
|
|
||||||
"La dimensione predefinita del font di questa risorsa tema. Utilizzata come "
|
|
||||||
"valore predefinito quando si tenta di recuperare un valore di dimensione del "
|
|
||||||
"font che non esiste in questo tema o è in uno stato non valido. Se anche la "
|
|
||||||
"dimensione predefinita del font è mancante o non valida, viene utilizzato il "
|
|
||||||
"valore di riserva del motore (vedi [member ThemeDB.fallback_font_size]).\n"
|
|
||||||
"I valori inferiori a [code]0[/code] non sono validi e possono essere "
|
|
||||||
"utilizzati per annullare l'impostazione della proprietà. Usa [method "
|
|
||||||
"has_default_font_size] per verificare se questo valore è valido."
|
|
||||||
|
|
||||||
msgid "Theme's [Color] item type."
|
msgid "Theme's [Color] item type."
|
||||||
msgstr "Il tipo di [Color] del tema."
|
msgstr "Il tipo di [Color] del tema."
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -6370,26 +6370,6 @@ msgstr ""
|
||||||
"一組放置在 2D 座標上的 [AnimationRootNode],在三個相鄰節點之間交叉淡化。被 "
|
"一組放置在 2D 座標上的 [AnimationRootNode],在三個相鄰節點之間交叉淡化。被 "
|
||||||
"[AnimationTree] 使用。"
|
"[AnimationTree] 使用。"
|
||||||
|
|
||||||
msgid ""
|
|
||||||
"A resource used by [AnimationNodeBlendTree].\n"
|
|
||||||
"[AnimationNodeBlendSpace1D] represents a virtual 2D space on which "
|
|
||||||
"[AnimationRootNode]s are placed. Outputs the linear blend of the three "
|
|
||||||
"adjacent animations using a [Vector2] weight. Adjacent in this context means "
|
|
||||||
"the three [AnimationRootNode]s making up the triangle that contains the "
|
|
||||||
"current value.\n"
|
|
||||||
"You can add vertices to the blend space with [method add_blend_point] and "
|
|
||||||
"automatically triangulate it by setting [member auto_triangles] to "
|
|
||||||
"[code]true[/code]. Otherwise, use [method add_triangle] and [method "
|
|
||||||
"remove_triangle] to triangulate the blend space by hand."
|
|
||||||
msgstr ""
|
|
||||||
"[AnimationNodeBlendTree] 使用的資源。\n"
|
|
||||||
"[AnimationNodeBlendSpace1D] 代表放置 [AnimationRootNode] 的虛擬 2D 空間。輸出"
|
|
||||||
"的是使用 [Vector2] 權重對相鄰的三個動畫進行線性混合的結果。此處的“相鄰”指的是"
|
|
||||||
"構成包含目前值的三角形的三個 [AnimationRootNode]。\n"
|
|
||||||
"你可以使用 [method add_blend_point] 向混合空間中新增頂點,將 [member "
|
|
||||||
"auto_triangles] 設為 [code]true[/code] 可以將其自動三角形化。否則,請使用 "
|
|
||||||
"[method add_triangle] 和 [method remove_triangle] 手動對混合空間進行三角形化。"
|
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Adds a new point that represents a [param node] at the position set by [param "
|
"Adds a new point that represents a [param node] at the position set by [param "
|
||||||
"pos]. You can insert it at a specific index using the [param at_index] "
|
"pos]. You can insert it at a specific index using the [param at_index] "
|
||||||
|
@ -8728,64 +8708,6 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"該函式返回支援點的資料結構的容量,可以與 [method reserve_space] 方法一起使用。"
|
"該函式返回支援點的資料結構的容量,可以與 [method reserve_space] 方法一起使用。"
|
||||||
|
|
||||||
msgid ""
|
|
||||||
"Returns an array with the IDs of the points that form the connection with the "
|
|
||||||
"given point.\n"
|
|
||||||
"[codeblocks]\n"
|
|
||||||
"[gdscript]\n"
|
|
||||||
"var astar = AStar2D.new()\n"
|
|
||||||
"astar.add_point(1, Vector2(0, 0))\n"
|
|
||||||
"astar.add_point(2, Vector2(0, 1))\n"
|
|
||||||
"astar.add_point(3, Vector2(1, 1))\n"
|
|
||||||
"astar.add_point(4, Vector2(2, 0))\n"
|
|
||||||
"\n"
|
|
||||||
"astar.connect_points(1, 2, true)\n"
|
|
||||||
"astar.connect_points(1, 3, true)\n"
|
|
||||||
"\n"
|
|
||||||
"var neighbors = astar.get_point_connections(1) # Returns [2, 3]\n"
|
|
||||||
"[/gdscript]\n"
|
|
||||||
"[csharp]\n"
|
|
||||||
"var astar = new AStar2D();\n"
|
|
||||||
"astar.AddPoint(1, new Vector2(0, 0));\n"
|
|
||||||
"astar.AddPoint(2, new Vector2(0, 1));\n"
|
|
||||||
"astar.AddPoint(3, new Vector2(1, 1));\n"
|
|
||||||
"astar.AddPoint(4, new Vector2(2, 0));\n"
|
|
||||||
"\n"
|
|
||||||
"astar.ConnectPoints(1, 2, true);\n"
|
|
||||||
"astar.ConnectPoints(1, 3, true);\n"
|
|
||||||
"\n"
|
|
||||||
"int[] neighbors = astar.GetPointConnections(1); // Returns [2, 3]\n"
|
|
||||||
"[/csharp]\n"
|
|
||||||
"[/codeblocks]"
|
|
||||||
msgstr ""
|
|
||||||
"返回一個陣列,其中包含與給定點形成連接的點的 ID。\n"
|
|
||||||
"[codeblocks]\n"
|
|
||||||
"[gdscript]\n"
|
|
||||||
"var astar = AStar2D.new()\n"
|
|
||||||
"astar.add_point(1, Vector2(0, 0))\n"
|
|
||||||
"astar.add_point(2, Vector2(0, 1))\n"
|
|
||||||
"astar.add_point(3, Vector2(1, 1))\n"
|
|
||||||
"astar.add_point(4, Vector2(2, 0))\n"
|
|
||||||
"\n"
|
|
||||||
"astar.connect_points(1, 2, true)\n"
|
|
||||||
"astar.connect_points(1, 3, true)\n"
|
|
||||||
"\n"
|
|
||||||
"var neighbors = astar.get_point_connections(1) # 返回 [2, 3]\n"
|
|
||||||
"[/gdscript]\n"
|
|
||||||
"[csharp]\n"
|
|
||||||
"var astar = new AStar2D();\n"
|
|
||||||
"astar.AddPoint(1, new Vector2(0, 0));\n"
|
|
||||||
"astar.AddPoint(2, new Vector2(0, 1));\n"
|
|
||||||
"astar.AddPoint(3, new Vector2(1, 1));\n"
|
|
||||||
"astar.AddPoint(4, new Vector2(2, 0));\n"
|
|
||||||
"\n"
|
|
||||||
"astar.ConnectPoints(1, 2, true);\n"
|
|
||||||
"astar.ConnectPoints(1, 3, true);\n"
|
|
||||||
"\n"
|
|
||||||
"int[] neighbors = astar.GetPointConnections(1); // 返回 [2, 3]\n"
|
|
||||||
"[/csharp]\n"
|
|
||||||
"[/codeblocks]"
|
|
||||||
|
|
||||||
msgid "Returns the number of points currently in the points pool."
|
msgid "Returns the number of points currently in the points pool."
|
||||||
msgstr "返回點池中目前的點數。"
|
msgstr "返回點池中目前的點數。"
|
||||||
|
|
||||||
|
@ -8975,62 +8897,6 @@ msgstr ""
|
||||||
"結果是在從 [code]y = 0[/code] 到 [code]y = 5[/code] 的線段中。它是線段中距離給"
|
"結果是在從 [code]y = 0[/code] 到 [code]y = 5[/code] 的線段中。它是線段中距離給"
|
||||||
"定點最近的位置。"
|
"定點最近的位置。"
|
||||||
|
|
||||||
msgid ""
|
|
||||||
"Returns an array with the IDs of the points that form the connection with the "
|
|
||||||
"given point.\n"
|
|
||||||
"[codeblocks]\n"
|
|
||||||
"[gdscript]\n"
|
|
||||||
"var astar = AStar3D.new()\n"
|
|
||||||
"astar.add_point(1, Vector3(0, 0, 0))\n"
|
|
||||||
"astar.add_point(2, Vector3(0, 1, 0))\n"
|
|
||||||
"astar.add_point(3, Vector3(1, 1, 0))\n"
|
|
||||||
"astar.add_point(4, Vector3(2, 0, 0))\n"
|
|
||||||
"\n"
|
|
||||||
"astar.connect_points(1, 2, true)\n"
|
|
||||||
"astar.connect_points(1, 3, true)\n"
|
|
||||||
"\n"
|
|
||||||
"var neighbors = astar.get_point_connections(1) # Returns [2, 3]\n"
|
|
||||||
"[/gdscript]\n"
|
|
||||||
"[csharp]\n"
|
|
||||||
"var astar = new AStar3D();\n"
|
|
||||||
"astar.AddPoint(1, new Vector3(0, 0, 0));\n"
|
|
||||||
"astar.AddPoint(2, new Vector3(0, 1, 0));\n"
|
|
||||||
"astar.AddPoint(3, new Vector3(1, 1, 0));\n"
|
|
||||||
"astar.AddPoint(4, new Vector3(2, 0, 0));\n"
|
|
||||||
"astar.ConnectPoints(1, 2, true);\n"
|
|
||||||
"astar.ConnectPoints(1, 3, true);\n"
|
|
||||||
"\n"
|
|
||||||
"int[] neighbors = astar.GetPointConnections(1); // Returns [2, 3]\n"
|
|
||||||
"[/csharp]\n"
|
|
||||||
"[/codeblocks]"
|
|
||||||
msgstr ""
|
|
||||||
"返回一個陣列,其中包含與給定點形成連接的點的 ID。\n"
|
|
||||||
"[codeblocks]\n"
|
|
||||||
"[gdscript]\n"
|
|
||||||
"var astar = AStar3D.new()\n"
|
|
||||||
"astar.add_point(1, Vector3(0, 0, 0))\n"
|
|
||||||
"astar.add_point(2, Vector3(0, 1, 0))\n"
|
|
||||||
"astar.add_point(3, Vector3(1, 1, 0))\n"
|
|
||||||
"astar.add_point(4, Vector3(2, 0, 0))\n"
|
|
||||||
"\n"
|
|
||||||
"astar.connect_points(1, 2, true)\n"
|
|
||||||
"astar.connect_points(1, 3, true)\n"
|
|
||||||
"\n"
|
|
||||||
"var neighbors = astar.get_point_connections(1) # 返回 [2, 3]\n"
|
|
||||||
"[/gdscript]\n"
|
|
||||||
"[csharp]\n"
|
|
||||||
"var astar = new AStar3D();\n"
|
|
||||||
"astar.AddPoint(1, new Vector3(0, 0, 0));\n"
|
|
||||||
"astar.AddPoint(2, new Vector3(0, 1, 0));\n"
|
|
||||||
"astar.AddPoint(3, new Vector3(1, 1, 0));\n"
|
|
||||||
"astar.AddPoint(4, new Vector3(2, 0, 0));\n"
|
|
||||||
"astar.ConnectPoints(1, 2, true);\n"
|
|
||||||
"astar.ConnectPoints(1, 3, true);\n"
|
|
||||||
"\n"
|
|
||||||
"int[] neighbors = astar.GetPointConnections(1); // 返回 [2, 3]\n"
|
|
||||||
"[/csharp]\n"
|
|
||||||
"[/codeblocks]"
|
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Reserves space internally for [param num_nodes] points. Useful if you're "
|
"Reserves space internally for [param num_nodes] points. Useful if you're "
|
||||||
"adding a known large number of points at once, such as points on a grid. New "
|
"adding a known large number of points at once, such as points on a grid. New "
|
||||||
|
@ -24475,24 +24341,6 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"從曲線上刪除點 [param idx]。如果 [param idx] 越界,則會向控制台發送錯誤資訊。"
|
"從曲線上刪除點 [param idx]。如果 [param idx] 越界,則會向控制台發送錯誤資訊。"
|
||||||
|
|
||||||
msgid ""
|
|
||||||
"Returns the position between the vertex [param idx] and the vertex [code]idx "
|
|
||||||
"+ 1[/code], where [param t] controls if the point is the first vertex "
|
|
||||||
"([code]t = 0.0[/code]), the last vertex ([code]t = 1.0[/code]), or in "
|
|
||||||
"between. Values of [param t] outside the range ([code]0.0 >= t <=1[/code]) "
|
|
||||||
"give strange, but predictable results.\n"
|
|
||||||
"If [param idx] is out of bounds it is truncated to the first or last vertex, "
|
|
||||||
"and [param t] is ignored. If the curve has no points, the function sends an "
|
|
||||||
"error to the console, and returns [code](0, 0)[/code]."
|
|
||||||
msgstr ""
|
|
||||||
"返回頂點 [param idx] 和頂點 [code]idx + 1[/code] 之間的位置,其中 [param t] 控"
|
|
||||||
"制該點是否為第一個頂點([code]t = 0.0[/code])、最後一個頂點([code]t = 1.0[/"
|
|
||||||
"code])、或介於兩者之間。超出範圍([code]0.0 >= t <=1[/code])的 [param t] 的"
|
|
||||||
"值會給出奇怪但可預測的結果。\n"
|
|
||||||
"如果 [param idx] 越界,它將被截斷到第一個或最後一個頂點,而 [param t] 將被忽"
|
|
||||||
"略。如果曲線沒有點,則該函式將向控制台發送一個錯誤,並返回 [code](0, 0)[/"
|
|
||||||
"code]。"
|
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Returns a point within the curve at position [param offset], where [param "
|
"Returns a point within the curve at position [param offset], where [param "
|
||||||
"offset] is measured as a pixel distance along the curve.\n"
|
"offset] is measured as a pixel distance along the curve.\n"
|
||||||
|
@ -55642,26 +55490,6 @@ msgstr ""
|
||||||
"[member spawn_path] 指向的節點的子節點。\n"
|
"[member spawn_path] 指向的節點的子節點。\n"
|
||||||
"[b]注意:[/b]可出生的場景是自動出生的。[method spawn] 僅在自訂出生時需要。"
|
"[b]注意:[/b]可出生的場景是自動出生的。[method spawn] 僅在自訂出生時需要。"
|
||||||
|
|
||||||
msgid ""
|
|
||||||
"Method called on all peers when for every custom [method spawn] requested by "
|
|
||||||
"the authority. Will receive the [code]data[/code] parameter, and should "
|
|
||||||
"return a [Node] that is not in the scene tree.\n"
|
|
||||||
"[b]Note:[/b] The returned node should [b]not[/b] be added to the scene with "
|
|
||||||
"[method Node.add_child]. This is done automatically."
|
|
||||||
msgstr ""
|
|
||||||
"當每個自訂 [method spawn] 被授權端請求時,在所有對等體上呼叫的方法。將接收 "
|
|
||||||
"[code]data[/code] 參數,並且應該返回一個不在場景樹中的 [Node]。\n"
|
|
||||||
"[b]注意:[/b]返回的節點[b]不[/b]應該用 [method Node.add_child] 新增到場景中。"
|
|
||||||
"這是自動完成的。"
|
|
||||||
|
|
||||||
msgid ""
|
|
||||||
"Maximum nodes that is allowed to be spawned by this spawner. Includes both "
|
|
||||||
"spawnable scenes and custom spawns.\n"
|
|
||||||
"When set to [code]0[/code] (the default), there is no limit."
|
|
||||||
msgstr ""
|
|
||||||
"該出生器允許出生的最大節點數。包括可出生場景和自訂出生。\n"
|
|
||||||
"當設定為 [code]0[/code](預設值)時,沒有限制。"
|
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Path to the spawn root. Spawnable scenes that are added as direct children "
|
"Path to the spawn root. Spawnable scenes that are added as direct children "
|
||||||
"are replicated to other peers."
|
"are replicated to other peers."
|
||||||
|
@ -83450,11 +83278,6 @@ msgstr "設定遮擋多邊形剔除模式。詳見 [enum CanvasOccluderPolygonCu
|
||||||
msgid "Sets the shape of the occluder polygon."
|
msgid "Sets the shape of the occluder polygon."
|
||||||
msgstr "設定遮擋多邊形的形狀。"
|
msgstr "設定遮擋多邊形的形狀。"
|
||||||
|
|
||||||
msgid ""
|
|
||||||
"A copy of the canvas item will be drawn with a local offset of the mirroring "
|
|
||||||
"[Vector2]."
|
|
||||||
msgstr "畫布專案的副本將以鏡像的局部偏移量[Vector2]被繪製。"
|
|
||||||
|
|
||||||
msgid "Modulates all colors in the given canvas."
|
msgid "Modulates all colors in the given canvas."
|
||||||
msgstr "調變給定畫布中的所有顏色。"
|
msgstr "調變給定畫布中的所有顏色。"
|
||||||
|
|
||||||
|
@ -103778,20 +103601,6 @@ msgstr ""
|
||||||
"ThemeDB.fallback_font])。\n"
|
"ThemeDB.fallback_font])。\n"
|
||||||
"請使用 [method has_default_font] 來檢查該值是否有效。"
|
"請使用 [method has_default_font] 來檢查該值是否有效。"
|
||||||
|
|
||||||
msgid ""
|
|
||||||
"The default font size of this theme resource. Used as the default value when "
|
|
||||||
"trying to fetch a font size value that doesn't exist in this theme or is in "
|
|
||||||
"invalid state. If the default font size is also missing or invalid, the "
|
|
||||||
"engine fallback value is used (see [member ThemeDB.fallback_font_size]).\n"
|
|
||||||
"Values below [code]0[/code] are invalid and can be used to unset the "
|
|
||||||
"property. Use [method has_default_font_size] to check if this value is valid."
|
|
||||||
msgstr ""
|
|
||||||
"該主題資源的預設字形大小。嘗試獲取字形大小時,如果該主題中不存在或者為無效狀"
|
|
||||||
"態,則會用它作為預設值。如果預設字形大小也缺失或無效,則會使用引擎的退回值"
|
|
||||||
"(見 [member ThemeDB.fallback_font_size])。\n"
|
|
||||||
"小於 [code]0[/code] 的值無效,可用於清除對該屬性的設定。請使用 [method "
|
|
||||||
"has_default_font_size] 來檢查該值是否有效。"
|
|
||||||
|
|
||||||
msgid "Theme's [Color] item type."
|
msgid "Theme's [Color] item type."
|
||||||
msgstr "主題的 [Color] 顏色項型別。"
|
msgstr "主題的 [Color] 顏色項型別。"
|
||||||
|
|
||||||
|
|
|
@ -2143,17 +2143,28 @@ void RenderingDeviceDriverD3D12::command_pipeline_barrier(CommandBufferID p_cmd_
|
||||||
for (uint32_t i = 0; i < p_texture_barriers.size(); i++) {
|
for (uint32_t i = 0; i < p_texture_barriers.size(); i++) {
|
||||||
const TextureBarrier &texture_barrier_rd = p_texture_barriers[i];
|
const TextureBarrier &texture_barrier_rd = p_texture_barriers[i];
|
||||||
const TextureInfo *texture_info = (const TextureInfo *)(texture_barrier_rd.texture.id);
|
const TextureInfo *texture_info = (const TextureInfo *)(texture_barrier_rd.texture.id);
|
||||||
|
if (texture_info->main_texture) {
|
||||||
|
texture_info = texture_info->main_texture;
|
||||||
|
}
|
||||||
_rd_stages_and_access_to_d3d12(p_src_stages, texture_barrier_rd.prev_layout, texture_barrier_rd.src_access, texture_barrier_d3d12.SyncBefore, texture_barrier_d3d12.AccessBefore);
|
_rd_stages_and_access_to_d3d12(p_src_stages, texture_barrier_rd.prev_layout, texture_barrier_rd.src_access, texture_barrier_d3d12.SyncBefore, texture_barrier_d3d12.AccessBefore);
|
||||||
_rd_stages_and_access_to_d3d12(p_dst_stages, texture_barrier_rd.next_layout, texture_barrier_rd.dst_access, texture_barrier_d3d12.SyncAfter, texture_barrier_d3d12.AccessAfter);
|
_rd_stages_and_access_to_d3d12(p_dst_stages, texture_barrier_rd.next_layout, texture_barrier_rd.dst_access, texture_barrier_d3d12.SyncAfter, texture_barrier_d3d12.AccessAfter);
|
||||||
texture_barrier_d3d12.LayoutBefore = _rd_texture_layout_to_d3d12_barrier_layout(texture_barrier_rd.prev_layout);
|
texture_barrier_d3d12.LayoutBefore = _rd_texture_layout_to_d3d12_barrier_layout(texture_barrier_rd.prev_layout);
|
||||||
texture_barrier_d3d12.LayoutAfter = _rd_texture_layout_to_d3d12_barrier_layout(texture_barrier_rd.next_layout);
|
texture_barrier_d3d12.LayoutAfter = _rd_texture_layout_to_d3d12_barrier_layout(texture_barrier_rd.next_layout);
|
||||||
texture_barrier_d3d12.pResource = texture_info->resource;
|
texture_barrier_d3d12.pResource = texture_info->resource;
|
||||||
texture_barrier_d3d12.Subresources.IndexOrFirstMipLevel = texture_barrier_rd.subresources.base_mipmap;
|
if (texture_barrier_rd.subresources.mipmap_count == texture_info->mipmaps && texture_barrier_rd.subresources.layer_count == texture_info->layers) {
|
||||||
texture_barrier_d3d12.Subresources.NumMipLevels = texture_barrier_rd.subresources.mipmap_count;
|
// So, all resources. Then, let's be explicit about it so D3D12 doesn't think
|
||||||
texture_barrier_d3d12.Subresources.FirstArraySlice = texture_barrier_rd.subresources.base_layer;
|
// we are dealing with a subset of subresources.
|
||||||
texture_barrier_d3d12.Subresources.NumArraySlices = texture_barrier_rd.subresources.layer_count;
|
texture_barrier_d3d12.Subresources.IndexOrFirstMipLevel = 0xffffffff;
|
||||||
texture_barrier_d3d12.Subresources.FirstPlane = _compute_plane_slice(texture_info->format, texture_barrier_rd.subresources.aspect);
|
texture_barrier_d3d12.Subresources.NumMipLevels = 0;
|
||||||
texture_barrier_d3d12.Subresources.NumPlanes = format_get_plane_count(texture_info->format);
|
// Because NumMipLevels == 0, all the other fields are ignored by D3D12.
|
||||||
|
} else {
|
||||||
|
texture_barrier_d3d12.Subresources.IndexOrFirstMipLevel = texture_barrier_rd.subresources.base_mipmap;
|
||||||
|
texture_barrier_d3d12.Subresources.NumMipLevels = texture_barrier_rd.subresources.mipmap_count;
|
||||||
|
texture_barrier_d3d12.Subresources.FirstArraySlice = texture_barrier_rd.subresources.base_layer;
|
||||||
|
texture_barrier_d3d12.Subresources.NumArraySlices = texture_barrier_rd.subresources.layer_count;
|
||||||
|
texture_barrier_d3d12.Subresources.FirstPlane = _compute_plane_slice(texture_info->format, texture_barrier_rd.subresources.aspect);
|
||||||
|
texture_barrier_d3d12.Subresources.NumPlanes = format_get_plane_count(texture_info->format);
|
||||||
|
}
|
||||||
texture_barrier_d3d12.Flags = (texture_barrier_rd.prev_layout == RDD::TEXTURE_LAYOUT_UNDEFINED) ? D3D12_TEXTURE_BARRIER_FLAG_DISCARD : D3D12_TEXTURE_BARRIER_FLAG_NONE;
|
texture_barrier_d3d12.Flags = (texture_barrier_rd.prev_layout == RDD::TEXTURE_LAYOUT_UNDEFINED) ? D3D12_TEXTURE_BARRIER_FLAG_DISCARD : D3D12_TEXTURE_BARRIER_FLAG_NONE;
|
||||||
texture_barriers.push_back(texture_barrier_d3d12);
|
texture_barriers.push_back(texture_barrier_d3d12);
|
||||||
}
|
}
|
||||||
|
|
|
@ -468,7 +468,7 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
|
||||||
update_skeletons = false;
|
update_skeletons = false;
|
||||||
}
|
}
|
||||||
// Canvas group begins here, render until before this item
|
// Canvas group begins here, render until before this item
|
||||||
_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, r_sdf_used, false, r_render_info);
|
_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, r_sdf_used, false, r_render_info, material_screen_texture_mipmaps_cached);
|
||||||
item_count = 0;
|
item_count = 0;
|
||||||
|
|
||||||
if (ci->canvas_group_owner->canvas_group->mode != RS::CANVAS_GROUP_MODE_TRANSPARENT) {
|
if (ci->canvas_group_owner->canvas_group->mode != RS::CANVAS_GROUP_MODE_TRANSPARENT) {
|
||||||
|
@ -499,7 +499,7 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
|
||||||
mesh_storage->update_mesh_instances();
|
mesh_storage->update_mesh_instances();
|
||||||
update_skeletons = false;
|
update_skeletons = false;
|
||||||
}
|
}
|
||||||
_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, r_sdf_used, true, r_render_info);
|
_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, r_sdf_used, true, r_render_info, material_screen_texture_mipmaps_cached);
|
||||||
item_count = 0;
|
item_count = 0;
|
||||||
|
|
||||||
if (ci->canvas_group->blur_mipmaps) {
|
if (ci->canvas_group->blur_mipmaps) {
|
||||||
|
@ -523,7 +523,7 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
|
||||||
}
|
}
|
||||||
//render anything pending, including clearing if no items
|
//render anything pending, including clearing if no items
|
||||||
|
|
||||||
_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, r_sdf_used, false, r_render_info);
|
_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, r_sdf_used, false, r_render_info, material_screen_texture_mipmaps_cached);
|
||||||
item_count = 0;
|
item_count = 0;
|
||||||
|
|
||||||
texture_storage->render_target_copy_to_back_buffer(p_to_render_target, back_buffer_rect, backbuffer_gen_mipmaps);
|
texture_storage->render_target_copy_to_back_buffer(p_to_render_target, back_buffer_rect, backbuffer_gen_mipmaps);
|
||||||
|
@ -553,7 +553,7 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
|
||||||
mesh_storage->update_mesh_instances();
|
mesh_storage->update_mesh_instances();
|
||||||
update_skeletons = false;
|
update_skeletons = false;
|
||||||
}
|
}
|
||||||
_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, r_sdf_used, canvas_group_owner != nullptr, r_render_info);
|
_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, r_sdf_used, canvas_group_owner != nullptr, r_render_info, material_screen_texture_mipmaps_cached);
|
||||||
//then reset
|
//then reset
|
||||||
item_count = 0;
|
item_count = 0;
|
||||||
}
|
}
|
||||||
|
@ -573,10 +573,10 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
|
||||||
state.current_instance_buffer_index = 0;
|
state.current_instance_buffer_index = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool &r_sdf_used, bool p_to_backbuffer, RenderingMethod::RenderInfo *r_render_info) {
|
void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool &r_sdf_used, bool p_to_backbuffer, RenderingMethod::RenderInfo *r_render_info, bool p_backbuffer_has_mipmaps) {
|
||||||
GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
|
GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
|
||||||
|
|
||||||
canvas_begin(p_to_render_target, p_to_backbuffer);
|
canvas_begin(p_to_render_target, p_to_backbuffer, p_backbuffer_has_mipmaps);
|
||||||
|
|
||||||
if (p_item_count <= 0) {
|
if (p_item_count <= 0) {
|
||||||
// Nothing to draw, just call canvas_begin() to clear the render target and return.
|
// Nothing to draw, just call canvas_begin() to clear the render target and return.
|
||||||
|
@ -647,18 +647,17 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou
|
||||||
_record_item_commands(ci, p_to_render_target, p_canvas_transform_inverse, current_clip, blend_mode, p_lights, index, batch_broken, r_sdf_used, Point2());
|
_record_item_commands(ci, p_to_render_target, p_canvas_transform_inverse, current_clip, blend_mode, p_lights, index, batch_broken, r_sdf_used, Point2());
|
||||||
} else {
|
} else {
|
||||||
Point2 start_pos = ci->repeat_size * -(ci->repeat_times / 2);
|
Point2 start_pos = ci->repeat_size * -(ci->repeat_times / 2);
|
||||||
Point2 end_pos = ci->repeat_size * ci->repeat_times + ci->repeat_size + start_pos;
|
Point2 offset;
|
||||||
Point2 pos = start_pos;
|
|
||||||
|
|
||||||
do {
|
int repeat_times_x = ci->repeat_size.x ? ci->repeat_times : 0;
|
||||||
do {
|
int repeat_times_y = ci->repeat_size.y ? ci->repeat_times : 0;
|
||||||
_record_item_commands(ci, p_to_render_target, p_canvas_transform_inverse, current_clip, blend_mode, p_lights, index, batch_broken, r_sdf_used, pos);
|
for (int ry = 0; ry <= repeat_times_y; ry++) {
|
||||||
pos.y += ci->repeat_size.y;
|
offset.y = start_pos.y + ry * ci->repeat_size.y;
|
||||||
} while (pos.y < end_pos.y);
|
for (int rx = 0; rx <= repeat_times_x; rx++) {
|
||||||
|
offset.x = start_pos.x + rx * ci->repeat_size.x;
|
||||||
pos.x += ci->repeat_size.x;
|
_record_item_commands(ci, p_to_render_target, p_canvas_transform_inverse, current_clip, blend_mode, p_lights, index, batch_broken, r_sdf_used, offset);
|
||||||
pos.y = start_pos.y;
|
}
|
||||||
} while (pos.x < end_pos.x);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -809,7 +808,7 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou
|
||||||
state.last_item_index += index;
|
state.last_item_index += index;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_render_target, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip, GLES3::CanvasShaderData::BlendMode p_blend_mode, Light *p_lights, uint32_t &r_index, bool &r_batch_broken, bool &r_sdf_used, const Point2 &p_offset) {
|
void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_render_target, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip, GLES3::CanvasShaderData::BlendMode p_blend_mode, Light *p_lights, uint32_t &r_index, bool &r_batch_broken, bool &r_sdf_used, const Point2 &p_repeat_offset) {
|
||||||
RenderingServer::CanvasItemTextureFilter texture_filter = p_item->texture_filter == RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT ? state.default_filter : p_item->texture_filter;
|
RenderingServer::CanvasItemTextureFilter texture_filter = p_item->texture_filter == RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT ? state.default_filter : p_item->texture_filter;
|
||||||
|
|
||||||
if (texture_filter != state.canvas_instance_batches[state.current_batch_index].filter) {
|
if (texture_filter != state.canvas_instance_batches[state.current_batch_index].filter) {
|
||||||
|
@ -826,11 +825,11 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
|
||||||
state.canvas_instance_batches[state.current_batch_index].repeat = texture_repeat;
|
state.canvas_instance_batches[state.current_batch_index].repeat = texture_repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
Transform2D base_transform = p_canvas_transform_inverse * p_item->final_transform;
|
Transform2D base_transform = p_item->final_transform;
|
||||||
|
if (p_item->repeat_source_item && (p_repeat_offset.x || p_repeat_offset.y)) {
|
||||||
if (p_offset.x || p_offset.y) {
|
base_transform.columns[2] += p_item->repeat_source_item->final_transform.basis_xform(p_repeat_offset);
|
||||||
base_transform *= Transform2D(0, p_offset / p_item->xform_curr.get_scale()); // TODO: Interpolate or explain why not needed.
|
|
||||||
}
|
}
|
||||||
|
base_transform = p_canvas_transform_inverse * base_transform;
|
||||||
|
|
||||||
Transform2D draw_transform; // Used by transform command
|
Transform2D draw_transform; // Used by transform command
|
||||||
|
|
||||||
|
@ -2170,7 +2169,7 @@ bool RasterizerCanvasGLES3::free(RID p_rid) {
|
||||||
void RasterizerCanvasGLES3::update() {
|
void RasterizerCanvasGLES3::update() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerCanvasGLES3::canvas_begin(RID p_to_render_target, bool p_to_backbuffer) {
|
void RasterizerCanvasGLES3::canvas_begin(RID p_to_render_target, bool p_to_backbuffer, bool p_backbuffer_has_mipmaps) {
|
||||||
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
|
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
|
||||||
GLES3::Config *config = GLES3::Config::get_singleton();
|
GLES3::Config *config = GLES3::Config::get_singleton();
|
||||||
|
|
||||||
|
@ -2185,6 +2184,7 @@ void RasterizerCanvasGLES3::canvas_begin(RID p_to_render_target, bool p_to_backb
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, render_target->fbo);
|
glBindFramebuffer(GL_FRAMEBUFFER, render_target->fbo);
|
||||||
glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 4);
|
glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 4);
|
||||||
glBindTexture(GL_TEXTURE_2D, render_target->backbuffer);
|
glBindTexture(GL_TEXTURE_2D, render_target->backbuffer);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, p_backbuffer_has_mipmaps ? render_target->mipmap_count - 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (render_target->is_transparent || p_to_backbuffer) {
|
if (render_target->is_transparent || p_to_backbuffer) {
|
||||||
|
|
|
@ -335,7 +335,7 @@ public:
|
||||||
|
|
||||||
typedef void Texture;
|
typedef void Texture;
|
||||||
|
|
||||||
void canvas_begin(RID p_to_render_target, bool p_to_backbuffer);
|
void canvas_begin(RID p_to_render_target, bool p_to_backbuffer, bool p_backbuffer_has_mipmaps);
|
||||||
|
|
||||||
//virtual void draw_window_margins(int *black_margin, RID *black_image) override;
|
//virtual void draw_window_margins(int *black_margin, RID *black_image) override;
|
||||||
void draw_lens_distortion_rect(const Rect2 &p_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample);
|
void draw_lens_distortion_rect(const Rect2 &p_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample);
|
||||||
|
@ -361,8 +361,8 @@ public:
|
||||||
void _prepare_canvas_texture(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, uint32_t &r_index, Size2 &r_texpixel_size);
|
void _prepare_canvas_texture(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, uint32_t &r_index, Size2 &r_texpixel_size);
|
||||||
|
|
||||||
void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used, RenderingMethod::RenderInfo *r_render_info = nullptr) override;
|
void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used, RenderingMethod::RenderInfo *r_render_info = nullptr) override;
|
||||||
void _render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool &r_sdf_used, bool p_to_backbuffer = false, RenderingMethod::RenderInfo *r_render_info = nullptr);
|
void _render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool &r_sdf_used, bool p_to_backbuffer = false, RenderingMethod::RenderInfo *r_render_info = nullptr, bool p_backbuffer_has_mipmaps = false);
|
||||||
void _record_item_commands(const Item *p_item, RID p_render_target, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip, GLES3::CanvasShaderData::BlendMode p_blend_mode, Light *p_lights, uint32_t &r_index, bool &r_break_batch, bool &r_sdf_used, const Point2 &p_offset);
|
void _record_item_commands(const Item *p_item, RID p_render_target, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip, GLES3::CanvasShaderData::BlendMode p_blend_mode, Light *p_lights, uint32_t &r_index, bool &r_break_batch, bool &r_sdf_used, const Point2 &p_repeat_offset);
|
||||||
void _render_batch(Light *p_lights, uint32_t p_index, RenderingMethod::RenderInfo *r_render_info = nullptr);
|
void _render_batch(Light *p_lights, uint32_t p_index, RenderingMethod::RenderInfo *r_render_info = nullptr);
|
||||||
bool _bind_material(GLES3::CanvasMaterialData *p_material_data, CanvasShaderGLES3::ShaderVariant p_variant, uint64_t p_specialization);
|
bool _bind_material(GLES3::CanvasMaterialData *p_material_data, CanvasShaderGLES3::ShaderVariant p_variant, uint64_t p_specialization);
|
||||||
void _new_batch(bool &r_batch_broken);
|
void _new_batch(bool &r_batch_broken);
|
||||||
|
|
|
@ -62,6 +62,10 @@
|
||||||
#define _EXT_DEBUG_SEVERITY_LOW_ARB 0x9148
|
#define _EXT_DEBUG_SEVERITY_LOW_ARB 0x9148
|
||||||
#define _EXT_DEBUG_OUTPUT 0x92E0
|
#define _EXT_DEBUG_OUTPUT 0x92E0
|
||||||
|
|
||||||
|
#ifndef GL_FRAMEBUFFER_SRGB
|
||||||
|
#define GL_FRAMEBUFFER_SRGB 0x8DB9
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef GLAPIENTRY
|
#ifndef GLAPIENTRY
|
||||||
#if defined(WINDOWS_ENABLED)
|
#if defined(WINDOWS_ENABLED)
|
||||||
#define GLAPIENTRY APIENTRY
|
#define GLAPIENTRY APIENTRY
|
||||||
|
@ -345,6 +349,9 @@ RasterizerGLES3::RasterizerGLES3() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Disable OpenGL linear to sRGB conversion, because Godot will always do this conversion itself.
|
||||||
|
glDisable(GL_FRAMEBUFFER_SRGB);
|
||||||
|
|
||||||
// OpenGL needs to be initialized before initializing the Rasterizers
|
// OpenGL needs to be initialized before initializing the Rasterizers
|
||||||
config = memnew(GLES3::Config);
|
config = memnew(GLES3::Config);
|
||||||
utilities = memnew(GLES3::Utilities);
|
utilities = memnew(GLES3::Utilities);
|
||||||
|
|
|
@ -777,7 +777,6 @@ void RasterizerSceneGLES3::_draw_sky(RID p_env, const Projection &p_projection,
|
||||||
ERR_FAIL_COND(p_env.is_null());
|
ERR_FAIL_COND(p_env.is_null());
|
||||||
|
|
||||||
Sky *sky = sky_owner.get_or_null(environment_get_sky(p_env));
|
Sky *sky = sky_owner.get_or_null(environment_get_sky(p_env));
|
||||||
ERR_FAIL_NULL(sky);
|
|
||||||
|
|
||||||
GLES3::SkyMaterialData *material_data = nullptr;
|
GLES3::SkyMaterialData *material_data = nullptr;
|
||||||
RID sky_material;
|
RID sky_material;
|
||||||
|
@ -851,6 +850,15 @@ void RasterizerSceneGLES3::_draw_sky(RID p_env, const Projection &p_projection,
|
||||||
material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::SKY_ENERGY_MULTIPLIER, p_sky_energy_multiplier, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND, spec_constants);
|
material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::SKY_ENERGY_MULTIPLIER, p_sky_energy_multiplier, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND, spec_constants);
|
||||||
material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::LUMINANCE_MULTIPLIER, p_luminance_multiplier, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND, spec_constants);
|
material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::LUMINANCE_MULTIPLIER, p_luminance_multiplier, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND, spec_constants);
|
||||||
|
|
||||||
|
Color fog_color = environment_get_fog_light_color(p_env).srgb_to_linear() * environment_get_fog_light_energy(p_env);
|
||||||
|
material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::FOG_ENABLED, environment_get_fog_enabled(p_env), shader_data->version, SkyShaderGLES3::MODE_BACKGROUND, spec_constants);
|
||||||
|
material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::FOG_AERIAL_PERSPECTIVE, environment_get_fog_aerial_perspective(p_env), shader_data->version, SkyShaderGLES3::MODE_BACKGROUND, spec_constants);
|
||||||
|
material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::FOG_LIGHT_COLOR, fog_color, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND, spec_constants);
|
||||||
|
material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::FOG_SUN_SCATTER, environment_get_fog_sun_scatter(p_env), shader_data->version, SkyShaderGLES3::MODE_BACKGROUND, spec_constants);
|
||||||
|
material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::FOG_DENSITY, environment_get_fog_density(p_env), shader_data->version, SkyShaderGLES3::MODE_BACKGROUND, spec_constants);
|
||||||
|
material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::FOG_SKY_AFFECT, environment_get_fog_sky_affect(p_env), shader_data->version, SkyShaderGLES3::MODE_BACKGROUND, spec_constants);
|
||||||
|
material_storage->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::DIRECTIONAL_LIGHT_COUNT, sky_globals.directional_light_count, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND, spec_constants);
|
||||||
|
|
||||||
if (p_use_multiview) {
|
if (p_use_multiview) {
|
||||||
glBindBufferBase(GL_UNIFORM_BUFFER, SKY_MULTIVIEW_UNIFORM_LOCATION, scene_state.multiview_buffer);
|
glBindBufferBase(GL_UNIFORM_BUFFER, SKY_MULTIVIEW_UNIFORM_LOCATION, scene_state.multiview_buffer);
|
||||||
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
||||||
|
@ -904,7 +912,7 @@ void RasterizerSceneGLES3::_update_sky_radiance(RID p_env, const Projection &p_p
|
||||||
RS::SkyMode sky_mode = sky->mode;
|
RS::SkyMode sky_mode = sky->mode;
|
||||||
|
|
||||||
if (sky_mode == RS::SKY_MODE_AUTOMATIC) {
|
if (sky_mode == RS::SKY_MODE_AUTOMATIC) {
|
||||||
if (shader_data->uses_time || shader_data->uses_position) {
|
if ((shader_data->uses_time || shader_data->uses_position) && sky->radiance_size == 256) {
|
||||||
update_single_frame = true;
|
update_single_frame = true;
|
||||||
sky_mode = RS::SKY_MODE_REALTIME;
|
sky_mode = RS::SKY_MODE_REALTIME;
|
||||||
} else if (shader_data->uses_light || shader_data->ubo_size > 0) {
|
} else if (shader_data->uses_light || shader_data->ubo_size > 0) {
|
||||||
|
@ -925,7 +933,7 @@ void RasterizerSceneGLES3::_update_sky_radiance(RID p_env, const Projection &p_p
|
||||||
int max_processing_layer = sky->mipmap_count;
|
int max_processing_layer = sky->mipmap_count;
|
||||||
|
|
||||||
// Update radiance cubemap
|
// Update radiance cubemap
|
||||||
if (sky->reflection_dirty && (sky->processing_layer > max_processing_layer || update_single_frame)) {
|
if (sky->reflection_dirty && (sky->processing_layer >= max_processing_layer || update_single_frame)) {
|
||||||
static const Vector3 view_normals[6] = {
|
static const Vector3 view_normals[6] = {
|
||||||
Vector3(+1, 0, 0),
|
Vector3(+1, 0, 0),
|
||||||
Vector3(-1, 0, 0),
|
Vector3(-1, 0, 0),
|
||||||
|
@ -2587,7 +2595,7 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
|
||||||
|
|
||||||
scene_state.enable_gl_depth_draw(false);
|
scene_state.enable_gl_depth_draw(false);
|
||||||
|
|
||||||
if (draw_sky) {
|
if (draw_sky || draw_sky_fog_only) {
|
||||||
RENDER_TIMESTAMP("Render Sky");
|
RENDER_TIMESTAMP("Render Sky");
|
||||||
|
|
||||||
scene_state.enable_gl_depth_test(true);
|
scene_state.enable_gl_depth_test(true);
|
||||||
|
|
|
@ -698,7 +698,8 @@ void ShaderGLES3::_clear_version(Version *p_version) {
|
||||||
|
|
||||||
void ShaderGLES3::_initialize_version(Version *p_version) {
|
void ShaderGLES3::_initialize_version(Version *p_version) {
|
||||||
ERR_FAIL_COND(p_version->variants.size() > 0);
|
ERR_FAIL_COND(p_version->variants.size() > 0);
|
||||||
if (shader_cache_dir_valid && _load_from_cache(p_version)) {
|
bool use_cache = shader_cache_dir_valid && !(feedback_count > 0 && GLES3::Config::get_singleton()->disable_transform_feedback_shader_cache);
|
||||||
|
if (use_cache && _load_from_cache(p_version)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
p_version->variants.reserve(variant_count);
|
p_version->variants.reserve(variant_count);
|
||||||
|
@ -709,7 +710,7 @@ void ShaderGLES3::_initialize_version(Version *p_version) {
|
||||||
_compile_specialization(spec, i, p_version, specialization_default_mask);
|
_compile_specialization(spec, i, p_version, specialization_default_mask);
|
||||||
p_version->variants[i].insert(specialization_default_mask, spec);
|
p_version->variants[i].insert(specialization_default_mask, spec);
|
||||||
}
|
}
|
||||||
if (shader_cache_dir_valid) {
|
if (use_cache) {
|
||||||
_save_to_cache(p_version);
|
_save_to_cache(p_version);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -583,6 +583,8 @@ void main() {
|
||||||
|
|
||||||
#define SHADER_IS_SRGB true
|
#define SHADER_IS_SRGB true
|
||||||
|
|
||||||
|
#define FLAGS_NON_UNIFORM_SCALE (1 << 4)
|
||||||
|
|
||||||
/* Varyings */
|
/* Varyings */
|
||||||
|
|
||||||
#if defined(COLOR_USED)
|
#if defined(COLOR_USED)
|
||||||
|
@ -955,6 +957,7 @@ ivec2 multiview_uv(ivec2 uv) {
|
||||||
|
|
||||||
uniform highp mat4 world_transform;
|
uniform highp mat4 world_transform;
|
||||||
uniform mediump float opaque_prepass_threshold;
|
uniform mediump float opaque_prepass_threshold;
|
||||||
|
uniform highp uint model_flags;
|
||||||
|
|
||||||
#if defined(RENDER_MATERIAL)
|
#if defined(RENDER_MATERIAL)
|
||||||
layout(location = 0) out vec4 albedo_output_buffer;
|
layout(location = 0) out vec4 albedo_output_buffer;
|
||||||
|
@ -1521,6 +1524,13 @@ void main() {
|
||||||
vec3 light_vertex = vertex;
|
vec3 light_vertex = vertex;
|
||||||
#endif //LIGHT_VERTEX_USED
|
#endif //LIGHT_VERTEX_USED
|
||||||
|
|
||||||
|
highp mat3 model_normal_matrix;
|
||||||
|
if (bool(model_flags & uint(FLAGS_NON_UNIFORM_SCALE))) {
|
||||||
|
model_normal_matrix = transpose(inverse(mat3(model_matrix)));
|
||||||
|
} else {
|
||||||
|
model_normal_matrix = mat3(model_matrix);
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
#CODE : FRAGMENT
|
#CODE : FRAGMENT
|
||||||
}
|
}
|
||||||
|
@ -1728,16 +1738,10 @@ void main() {
|
||||||
|
|
||||||
vec3 n = normalize(lightmap_normal_xform * normal);
|
vec3 n = normalize(lightmap_normal_xform * normal);
|
||||||
|
|
||||||
ambient_light += lm_light_l0 * 0.282095f;
|
ambient_light += lm_light_l0 * lightmap_exposure_normalization;
|
||||||
ambient_light += lm_light_l1n1 * 0.32573 * n.y * lightmap_exposure_normalization;
|
ambient_light += lm_light_l1n1 * n.y * lightmap_exposure_normalization;
|
||||||
ambient_light += lm_light_l1_0 * 0.32573 * n.z * lightmap_exposure_normalization;
|
ambient_light += lm_light_l1_0 * n.z * lightmap_exposure_normalization;
|
||||||
ambient_light += lm_light_l1p1 * 0.32573 * n.x * lightmap_exposure_normalization;
|
ambient_light += lm_light_l1p1 * n.x * lightmap_exposure_normalization;
|
||||||
if (metallic > 0.01) { // Since the more direct bounced light is lost, we can kind of fake it with this trick.
|
|
||||||
vec3 r = reflect(normalize(-vertex), normal);
|
|
||||||
specular_light += lm_light_l1n1 * 0.32573 * r.y * lightmap_exposure_normalization;
|
|
||||||
specular_light += lm_light_l1_0 * 0.32573 * r.z * lightmap_exposure_normalization;
|
|
||||||
specular_light += lm_light_l1p1 * 0.32573 * r.x * lightmap_exposure_normalization;
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
ambient_light += textureLod(lightmap_textures, uvw, 0.0).rgb * lightmap_exposure_normalization;
|
ambient_light += textureLod(lightmap_textures, uvw, 0.0).rgb * lightmap_exposure_normalization;
|
||||||
#endif
|
#endif
|
||||||
|
@ -1871,7 +1875,7 @@ void main() {
|
||||||
alpha = min(alpha, clamp(length(ambient_light), 0.0, 1.0));
|
alpha = min(alpha, clamp(length(ambient_light), 0.0, 1.0));
|
||||||
|
|
||||||
#if defined(ALPHA_SCISSOR_USED)
|
#if defined(ALPHA_SCISSOR_USED)
|
||||||
if (alpha < alpha_scissor) {
|
if (alpha < alpha_scissor_threshold) {
|
||||||
discard;
|
discard;
|
||||||
}
|
}
|
||||||
#endif // !ALPHA_SCISSOR_USED
|
#endif // !ALPHA_SCISSOR_USED
|
||||||
|
|
|
@ -59,7 +59,7 @@ layout(location = 10) in highp uvec4 in_bone_attrib;
|
||||||
layout(location = 11) in mediump vec4 in_weight_attrib;
|
layout(location = 11) in mediump vec4 in_weight_attrib;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uniform mediump sampler2D skeleton_texture; // texunit:0
|
uniform highp sampler2D skeleton_texture; // texunit:0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
|
|
|
@ -108,11 +108,11 @@ uniform float sky_energy_multiplier;
|
||||||
uniform float luminance_multiplier;
|
uniform float luminance_multiplier;
|
||||||
|
|
||||||
uniform float fog_aerial_perspective;
|
uniform float fog_aerial_perspective;
|
||||||
uniform vec3 fog_light_color;
|
uniform vec4 fog_light_color;
|
||||||
uniform float fog_sun_scatter;
|
uniform float fog_sun_scatter;
|
||||||
uniform bool fog_enabled;
|
uniform bool fog_enabled;
|
||||||
uniform float fog_density;
|
uniform float fog_density;
|
||||||
uniform float z_far;
|
uniform float fog_sky_affect;
|
||||||
uniform uint directional_light_count;
|
uniform uint directional_light_count;
|
||||||
|
|
||||||
#ifdef USE_MULTIVIEW
|
#ifdef USE_MULTIVIEW
|
||||||
|
@ -135,6 +135,24 @@ vec3 interleaved_gradient_noise(vec2 pos) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !defined(DISABLE_FOG)
|
||||||
|
vec4 fog_process(vec3 view, vec3 sky_color) {
|
||||||
|
vec3 fog_color = mix(fog_light_color.rgb, sky_color, fog_aerial_perspective);
|
||||||
|
|
||||||
|
if (fog_sun_scatter > 0.001) {
|
||||||
|
vec4 sun_scatter = vec4(0.0);
|
||||||
|
float sun_total = 0.0;
|
||||||
|
for (uint i = 0u; i < directional_light_count; i++) {
|
||||||
|
vec3 light_color = directional_lights.data[i].color_size.xyz * directional_lights.data[i].direction_energy.w;
|
||||||
|
float light_amount = pow(max(dot(view, directional_lights.data[i].direction_energy.xyz), 0.0), 8.0);
|
||||||
|
fog_color += light_color * light_amount * fog_sun_scatter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return vec4(fog_color, 1.0);
|
||||||
|
}
|
||||||
|
#endif // !DISABLE_FOG
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec3 cube_normal;
|
vec3 cube_normal;
|
||||||
#ifdef USE_MULTIVIEW
|
#ifdef USE_MULTIVIEW
|
||||||
|
@ -203,6 +221,21 @@ void main() {
|
||||||
|
|
||||||
// Convert to Linear for tonemapping so color matches scene shader better
|
// Convert to Linear for tonemapping so color matches scene shader better
|
||||||
color = srgb_to_linear(color);
|
color = srgb_to_linear(color);
|
||||||
|
|
||||||
|
#if !defined(DISABLE_FOG) && !defined(USE_CUBEMAP_PASS)
|
||||||
|
|
||||||
|
// Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky.
|
||||||
|
if (fog_enabled) {
|
||||||
|
vec4 fog = fog_process(cube_normal, color.rgb);
|
||||||
|
color.rgb = mix(color.rgb, fog.rgb, fog.a * fog_sky_affect);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (custom_fog.a > 0.0) {
|
||||||
|
color.rgb = mix(color.rgb, custom_fog.rgb, custom_fog.a);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // DISABLE_FOG
|
||||||
|
|
||||||
color *= exposure;
|
color *= exposure;
|
||||||
#ifdef APPLY_TONEMAPPING
|
#ifdef APPLY_TONEMAPPING
|
||||||
color = apply_tonemapping(color, white);
|
color = apply_tonemapping(color, white);
|
||||||
|
|
|
@ -121,7 +121,7 @@ Config::Config() {
|
||||||
#ifdef WEB_ENABLED
|
#ifdef WEB_ENABLED
|
||||||
msaa_supported = (msaa_max_samples > 0);
|
msaa_supported = (msaa_max_samples > 0);
|
||||||
#else
|
#else
|
||||||
msaa_supported = extensions.has("GL_EXT_framebuffer_multisample");
|
msaa_supported = true;
|
||||||
#endif
|
#endif
|
||||||
#ifndef IOS_ENABLED
|
#ifndef IOS_ENABLED
|
||||||
#ifdef WEB_ENABLED
|
#ifdef WEB_ENABLED
|
||||||
|
@ -218,6 +218,8 @@ Config::Config() {
|
||||||
//https://github.com/godotengine/godot/issues/92662#issuecomment-2161199477
|
//https://github.com/godotengine/godot/issues/92662#issuecomment-2161199477
|
||||||
//disable_particles_workaround = false;
|
//disable_particles_workaround = false;
|
||||||
}
|
}
|
||||||
|
} else if (rendering_device_name == "PowerVR Rogue GE8320") {
|
||||||
|
disable_transform_feedback_shader_cache = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -96,6 +96,9 @@ public:
|
||||||
bool disable_particles_workaround = false; // set to 'true' to disable 'GPUParticles'
|
bool disable_particles_workaround = false; // set to 'true' to disable 'GPUParticles'
|
||||||
bool flip_xy_workaround = false;
|
bool flip_xy_workaround = false;
|
||||||
|
|
||||||
|
// PowerVR GE 8320 workaround
|
||||||
|
bool disable_transform_feedback_shader_cache = false;
|
||||||
|
|
||||||
#ifdef ANDROID_ENABLED
|
#ifdef ANDROID_ENABLED
|
||||||
PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC eglFramebufferTextureMultiviewOVR = nullptr;
|
PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC eglFramebufferTextureMultiviewOVR = nullptr;
|
||||||
PFNGLTEXSTORAGE3DMULTISAMPLEPROC eglTexStorage3DMultisample = nullptr;
|
PFNGLTEXSTORAGE3DMULTISAMPLEPROC eglTexStorage3DMultisample = nullptr;
|
||||||
|
|
|
@ -1518,6 +1518,11 @@ bool LightStorage::_shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_i
|
||||||
uint64_t min_pass = 0; // Pass of the existing one, try to use the least recently used one (LRU fashion).
|
uint64_t min_pass = 0; // Pass of the existing one, try to use the least recently used one (LRU fashion).
|
||||||
|
|
||||||
for (int j = 0; j < sc; j++) {
|
for (int j = 0; j < sc; j++) {
|
||||||
|
if (sarr[j].owner_is_omni != is_omni) {
|
||||||
|
// Existing light instance type doesn't match new light instance type skip.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
LightInstance *sli = light_instance_owner.get_or_null(sarr[j].owner);
|
LightInstance *sli = light_instance_owner.get_or_null(sarr[j].owner);
|
||||||
if (!sli) {
|
if (!sli) {
|
||||||
// Found a released light instance.
|
// Found a released light instance.
|
||||||
|
|
|
@ -301,7 +301,7 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
|
||||||
Vector<uint8_t> ir = new_surface.index_data;
|
Vector<uint8_t> ir = new_surface.index_data;
|
||||||
wr = wf_indices.ptrw();
|
wr = wf_indices.ptrw();
|
||||||
|
|
||||||
if (new_surface.vertex_count < (1 << 16)) {
|
if (new_surface.vertex_count <= 65536) {
|
||||||
// Read 16 bit indices.
|
// Read 16 bit indices.
|
||||||
const uint16_t *src_idx = (const uint16_t *)ir.ptr();
|
const uint16_t *src_idx = (const uint16_t *)ir.ptr();
|
||||||
for (uint32_t i = 0; i + 5 < wf_index_count; i += 6) {
|
for (uint32_t i = 0; i + 5 < wf_index_count; i += 6) {
|
||||||
|
@ -743,6 +743,7 @@ String MeshStorage::mesh_get_path(RID p_mesh) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshStorage::mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) {
|
void MeshStorage::mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) {
|
||||||
|
ERR_FAIL_COND_MSG(p_mesh == p_shadow_mesh, "Cannot set a mesh as its own shadow mesh.");
|
||||||
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
|
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
|
||||||
ERR_FAIL_NULL(mesh);
|
ERR_FAIL_NULL(mesh);
|
||||||
|
|
||||||
|
|
|
@ -1039,7 +1039,7 @@ Ref<Image> TextureStorage::texture_2d_get(RID p_texture) const {
|
||||||
data.resize(data_size);
|
data.resize(data_size);
|
||||||
|
|
||||||
ERR_FAIL_COND_V(data.is_empty(), Ref<Image>());
|
ERR_FAIL_COND_V(data.is_empty(), Ref<Image>());
|
||||||
image = Image::create_from_data(texture->width, texture->height, texture->mipmaps > 1, texture->real_format, data);
|
image = Image::create_from_data(texture->alloc_width, texture->alloc_height, texture->mipmaps > 1, texture->real_format, data);
|
||||||
ERR_FAIL_COND_V(image->is_empty(), Ref<Image>());
|
ERR_FAIL_COND_V(image->is_empty(), Ref<Image>());
|
||||||
if (texture->format != texture->real_format) {
|
if (texture->format != texture->real_format) {
|
||||||
image->convert(texture->format);
|
image->convert(texture->format);
|
||||||
|
@ -1095,7 +1095,7 @@ Ref<Image> TextureStorage::texture_2d_get(RID p_texture) const {
|
||||||
data.resize(data_size);
|
data.resize(data_size);
|
||||||
|
|
||||||
ERR_FAIL_COND_V(data.is_empty(), Ref<Image>());
|
ERR_FAIL_COND_V(data.is_empty(), Ref<Image>());
|
||||||
image = Image::create_from_data(texture->width, texture->height, false, Image::FORMAT_RGBA8, data);
|
image = Image::create_from_data(texture->alloc_width, texture->alloc_height, false, Image::FORMAT_RGBA8, data);
|
||||||
ERR_FAIL_COND_V(image->is_empty(), Ref<Image>());
|
ERR_FAIL_COND_V(image->is_empty(), Ref<Image>());
|
||||||
|
|
||||||
if (texture->format != Image::FORMAT_RGBA8) {
|
if (texture->format != Image::FORMAT_RGBA8) {
|
||||||
|
@ -1497,11 +1497,9 @@ void TextureStorage::_texture_set_data(RID p_texture, const Ref<Image> &p_image,
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
|
||||||
if (texture->target == GL_TEXTURE_2D_ARRAY) {
|
if (texture->target == GL_TEXTURE_2D_ARRAY) {
|
||||||
if (p_initialize) {
|
if (p_initialize) {
|
||||||
glCompressedTexImage3D(GL_TEXTURE_2D_ARRAY, i, internal_format, w, h, texture->layers, 0,
|
glCompressedTexImage3D(GL_TEXTURE_2D_ARRAY, i, internal_format, w, h, texture->layers, 0, size * texture->layers, nullptr);
|
||||||
size * texture->layers, &read[ofs]);
|
|
||||||
} else {
|
|
||||||
glCompressedTexSubImage3D(GL_TEXTURE_2D_ARRAY, i, 0, 0, p_layer, w, h, 1, internal_format, size, &read[ofs]);
|
|
||||||
}
|
}
|
||||||
|
glCompressedTexSubImage3D(GL_TEXTURE_2D_ARRAY, i, 0, 0, p_layer, w, h, 1, internal_format, size, &read[ofs]);
|
||||||
} else {
|
} else {
|
||||||
glCompressedTexImage2D(blit_target, i, internal_format, w, h, 0, size, &read[ofs]);
|
glCompressedTexImage2D(blit_target, i, internal_format, w, h, 0, size, &read[ofs]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -383,7 +383,7 @@ uint64_t FileAccessUnix::_get_modified_time(const String &p_file) {
|
||||||
if (!err) {
|
if (!err) {
|
||||||
return status.st_mtime;
|
return status.st_mtime;
|
||||||
} else {
|
} else {
|
||||||
print_verbose("Failed to get modified time for: " + p_file + "");
|
WARN_PRINT("Failed to get modified time for: " + p_file);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -553,15 +553,40 @@ uint64_t FileAccessWindows::_get_modified_time(const String &p_file) {
|
||||||
file = file.substr(0, file.length() - 1);
|
file = file.substr(0, file.length() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct _stat st;
|
HANDLE handle = CreateFileW((LPCWSTR)(file.utf16().get_data()), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
|
||||||
int rv = _wstat((LPCWSTR)(file.utf16().get_data()), &st);
|
|
||||||
|
|
||||||
if (rv == 0) {
|
if (handle != INVALID_HANDLE_VALUE) {
|
||||||
return st.st_mtime;
|
FILETIME ft_create, ft_write;
|
||||||
} else {
|
|
||||||
print_verbose("Failed to get modified time for: " + p_file + "");
|
bool status = GetFileTime(handle, &ft_create, nullptr, &ft_write);
|
||||||
return 0;
|
|
||||||
|
CloseHandle(handle);
|
||||||
|
|
||||||
|
if (status) {
|
||||||
|
uint64_t ret = 0;
|
||||||
|
|
||||||
|
// If write time is invalid, fallback to creation time.
|
||||||
|
if (ft_write.dwHighDateTime == 0 && ft_write.dwLowDateTime == 0) {
|
||||||
|
ret = ft_create.dwHighDateTime;
|
||||||
|
ret <<= 32;
|
||||||
|
ret |= ft_create.dwLowDateTime;
|
||||||
|
} else {
|
||||||
|
ret = ft_write.dwHighDateTime;
|
||||||
|
ret <<= 32;
|
||||||
|
ret |= ft_write.dwLowDateTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint64_t WINDOWS_TICKS_PER_SECOND = 10000000;
|
||||||
|
const uint64_t TICKS_TO_UNIX_EPOCH = 116444736000000000LL;
|
||||||
|
|
||||||
|
if (ret >= TICKS_TO_UNIX_EPOCH) {
|
||||||
|
return (ret - TICKS_TO_UNIX_EPOCH) / WINDOWS_TICKS_PER_SECOND;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print_verbose("Failed to get modified time for: " + p_file);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
BitField<FileAccess::UnixPermissionFlags> FileAccessWindows::_get_unix_permissions(const String &p_file) {
|
BitField<FileAccess::UnixPermissionFlags> FileAccessWindows::_get_unix_permissions(const String &p_file) {
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include "editor/editor_string_names.h"
|
#include "editor/editor_string_names.h"
|
||||||
#include "editor/editor_undo_redo_manager.h"
|
#include "editor/editor_undo_redo_manager.h"
|
||||||
#include "editor/gui/editor_spin_slider.h"
|
#include "editor/gui/editor_spin_slider.h"
|
||||||
|
#include "editor/plugins/animation_player_editor_plugin.h"
|
||||||
#include "editor/themes/editor_scale.h"
|
#include "editor/themes/editor_scale.h"
|
||||||
#include "scene/gui/view_panner.h"
|
#include "scene/gui/view_panner.h"
|
||||||
#include "scene/resources/text_line.h"
|
#include "scene/resources/text_line.h"
|
||||||
|
@ -868,6 +869,11 @@ void AnimationBezierTrackEdit::_change_selected_keys_handle_mode(Animation::Hand
|
||||||
undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", track_key_pair.first, track_key_pair.second, animation->bezier_track_get_key_out_handle(track_key_pair.first, track_key_pair.second));
|
undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", track_key_pair.first, track_key_pair.second, animation->bezier_track_get_key_out_handle(track_key_pair.first, track_key_pair.second));
|
||||||
undo_redo->add_do_method(editor, "_bezier_track_set_key_handle_mode", animation.ptr(), track_key_pair.first, track_key_pair.second, p_mode, p_auto ? Animation::HANDLE_SET_MODE_AUTO : Animation::HANDLE_SET_MODE_RESET);
|
undo_redo->add_do_method(editor, "_bezier_track_set_key_handle_mode", animation.ptr(), track_key_pair.first, track_key_pair.second, p_mode, p_auto ? Animation::HANDLE_SET_MODE_AUTO : Animation::HANDLE_SET_MODE_RESET);
|
||||||
}
|
}
|
||||||
|
AnimationPlayerEditor *ape = AnimationPlayerEditor::get_singleton();
|
||||||
|
if (ape) {
|
||||||
|
undo_redo->add_do_method(ape, "_animation_update_key_frame");
|
||||||
|
undo_redo->add_undo_method(ape, "_animation_update_key_frame");
|
||||||
|
}
|
||||||
undo_redo->commit_action();
|
undo_redo->commit_action();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1083,7 +1089,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
|
||||||
if (I.key == REMOVE_ICON) {
|
if (I.key == REMOVE_ICON) {
|
||||||
if (!read_only) {
|
if (!read_only) {
|
||||||
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
||||||
undo_redo->create_action("Remove Bezier Track");
|
undo_redo->create_action("Remove Bezier Track", UndoRedo::MERGE_DISABLE, animation.ptr());
|
||||||
|
|
||||||
undo_redo->add_do_method(this, "_update_locked_tracks_after", track);
|
undo_redo->add_do_method(this, "_update_locked_tracks_after", track);
|
||||||
undo_redo->add_do_method(this, "_update_hidden_tracks_after", track);
|
undo_redo->add_do_method(this, "_update_hidden_tracks_after", track);
|
||||||
|
@ -1559,6 +1565,11 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
|
||||||
undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_out_handle", moving_handle_track, moving_handle_key, moving_handle_right, ratio);
|
undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_out_handle", moving_handle_track, moving_handle_key, moving_handle_right, ratio);
|
||||||
undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", moving_handle_track, moving_handle_key, animation->bezier_track_get_key_out_handle(moving_handle_track, moving_handle_key), ratio);
|
undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", moving_handle_track, moving_handle_key, animation->bezier_track_get_key_out_handle(moving_handle_track, moving_handle_key), ratio);
|
||||||
}
|
}
|
||||||
|
AnimationPlayerEditor *ape = AnimationPlayerEditor::get_singleton();
|
||||||
|
if (ape) {
|
||||||
|
undo_redo->add_do_method(ape, "_animation_update_key_frame");
|
||||||
|
undo_redo->add_undo_method(ape, "_animation_update_key_frame");
|
||||||
|
}
|
||||||
undo_redo->commit_action();
|
undo_redo->commit_action();
|
||||||
moving_handle = 0;
|
moving_handle = 0;
|
||||||
queue_redraw();
|
queue_redraw();
|
||||||
|
@ -1672,6 +1683,11 @@ void AnimationBezierTrackEdit::_menu_selected(int p_index) {
|
||||||
undo_redo->add_do_method(animation.ptr(), "track_insert_key", selected_track, time, new_point);
|
undo_redo->add_do_method(animation.ptr(), "track_insert_key", selected_track, time, new_point);
|
||||||
undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation);
|
undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation);
|
||||||
undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", selected_track, time);
|
undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", selected_track, time);
|
||||||
|
AnimationPlayerEditor *ape = AnimationPlayerEditor::get_singleton();
|
||||||
|
if (ape) {
|
||||||
|
undo_redo->add_do_method(ape, "_animation_update_key_frame");
|
||||||
|
undo_redo->add_undo_method(ape, "_animation_update_key_frame");
|
||||||
|
}
|
||||||
undo_redo->commit_action();
|
undo_redo->commit_action();
|
||||||
queue_redraw();
|
queue_redraw();
|
||||||
}
|
}
|
||||||
|
@ -1772,6 +1788,11 @@ void AnimationBezierTrackEdit::duplicate_selected_keys(real_t p_ofs, bool p_ofs_
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AnimationPlayerEditor *ape = AnimationPlayerEditor::get_singleton();
|
||||||
|
if (ape) {
|
||||||
|
undo_redo->add_do_method(ape, "_animation_update_key_frame");
|
||||||
|
undo_redo->add_undo_method(ape, "_animation_update_key_frame");
|
||||||
|
}
|
||||||
undo_redo->add_do_method(this, "queue_redraw");
|
undo_redo->add_do_method(this, "queue_redraw");
|
||||||
undo_redo->add_undo_method(this, "queue_redraw");
|
undo_redo->add_undo_method(this, "queue_redraw");
|
||||||
undo_redo->commit_action();
|
undo_redo->commit_action();
|
||||||
|
@ -1821,6 +1842,15 @@ void AnimationBezierTrackEdit::copy_selected_keys(bool p_cut) {
|
||||||
undo_redo->add_undo_method(this, "_select_at_anim", animation, E->key().track, E->value().pos, i == 0);
|
undo_redo->add_undo_method(this, "_select_at_anim", animation, E->key().track, E->value().pos, i == 0);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AnimationPlayerEditor *ape = AnimationPlayerEditor::get_singleton();
|
||||||
|
if (ape) {
|
||||||
|
undo_redo->add_do_method(ape, "_animation_update_key_frame");
|
||||||
|
undo_redo->add_undo_method(ape, "_animation_update_key_frame");
|
||||||
|
}
|
||||||
|
undo_redo->add_do_method(this, "queue_redraw");
|
||||||
|
undo_redo->add_undo_method(this, "queue_redraw");
|
||||||
|
|
||||||
undo_redo->commit_action();
|
undo_redo->commit_action();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1899,9 +1929,15 @@ void AnimationBezierTrackEdit::paste_keys(real_t p_ofs, bool p_ofs_valid) {
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
undo_redo->commit_action();
|
AnimationPlayerEditor *ape = AnimationPlayerEditor::get_singleton();
|
||||||
|
if (ape) {
|
||||||
|
undo_redo->add_do_method(ape, "_animation_update_key_frame");
|
||||||
|
undo_redo->add_undo_method(ape, "_animation_update_key_frame");
|
||||||
|
}
|
||||||
|
undo_redo->add_do_method(this, "queue_redraw");
|
||||||
|
undo_redo->add_undo_method(this, "queue_redraw");
|
||||||
|
|
||||||
queue_redraw();
|
undo_redo->commit_action();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1916,6 +1952,11 @@ void AnimationBezierTrackEdit::delete_selection() {
|
||||||
}
|
}
|
||||||
undo_redo->add_do_method(this, "_clear_selection_for_anim", animation);
|
undo_redo->add_do_method(this, "_clear_selection_for_anim", animation);
|
||||||
undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation);
|
undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation);
|
||||||
|
AnimationPlayerEditor *ape = AnimationPlayerEditor::get_singleton();
|
||||||
|
if (ape) {
|
||||||
|
undo_redo->add_do_method(ape, "_animation_update_key_frame");
|
||||||
|
undo_redo->add_undo_method(ape, "_animation_update_key_frame");
|
||||||
|
}
|
||||||
undo_redo->commit_action();
|
undo_redo->commit_action();
|
||||||
|
|
||||||
//selection.clear();
|
//selection.clear();
|
||||||
|
@ -1925,6 +1966,15 @@ void AnimationBezierTrackEdit::delete_selection() {
|
||||||
void AnimationBezierTrackEdit::_bezier_track_insert_key_at_anim(const Ref<Animation> &p_anim, int p_track, double p_time, real_t p_value, const Vector2 &p_in_handle, const Vector2 &p_out_handle, const Animation::HandleMode p_handle_mode) {
|
void AnimationBezierTrackEdit::_bezier_track_insert_key_at_anim(const Ref<Animation> &p_anim, int p_track, double p_time, real_t p_value, const Vector2 &p_in_handle, const Vector2 &p_out_handle, const Animation::HandleMode p_handle_mode) {
|
||||||
int idx = p_anim->bezier_track_insert_key(p_track, p_time, p_value, p_in_handle, p_out_handle);
|
int idx = p_anim->bezier_track_insert_key(p_track, p_time, p_value, p_in_handle, p_out_handle);
|
||||||
p_anim->bezier_track_set_key_handle_mode(p_track, idx, p_handle_mode);
|
p_anim->bezier_track_set_key_handle_mode(p_track, idx, p_handle_mode);
|
||||||
|
|
||||||
|
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
||||||
|
undo_redo->create_action(TTR("Animation Bezier Curve Change Call"));
|
||||||
|
AnimationPlayerEditor *ape = AnimationPlayerEditor::get_singleton();
|
||||||
|
if (ape) {
|
||||||
|
undo_redo->add_do_method(ape, "_animation_update_key_frame");
|
||||||
|
undo_redo->add_undo_method(ape, "_animation_update_key_frame");
|
||||||
|
}
|
||||||
|
undo_redo->commit_action();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimationBezierTrackEdit::_bind_methods() {
|
void AnimationBezierTrackEdit::_bind_methods() {
|
||||||
|
|
|
@ -266,6 +266,11 @@ bool AnimationTrackKeyEdit::_set(const StringName &p_name, const Variant &p_valu
|
||||||
undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_value", track, key, prev);
|
undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_value", track, key, prev);
|
||||||
undo_redo->add_do_method(this, "_update_obj", animation);
|
undo_redo->add_do_method(this, "_update_obj", animation);
|
||||||
undo_redo->add_undo_method(this, "_update_obj", animation);
|
undo_redo->add_undo_method(this, "_update_obj", animation);
|
||||||
|
AnimationPlayerEditor *ape = AnimationPlayerEditor::get_singleton();
|
||||||
|
if (ape) {
|
||||||
|
undo_redo->add_do_method(ape, "_animation_update_key_frame");
|
||||||
|
undo_redo->add_undo_method(ape, "_animation_update_key_frame");
|
||||||
|
}
|
||||||
undo_redo->commit_action();
|
undo_redo->commit_action();
|
||||||
|
|
||||||
setting = false;
|
setting = false;
|
||||||
|
@ -282,6 +287,11 @@ bool AnimationTrackKeyEdit::_set(const StringName &p_name, const Variant &p_valu
|
||||||
undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", track, key, prev);
|
undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", track, key, prev);
|
||||||
undo_redo->add_do_method(this, "_update_obj", animation);
|
undo_redo->add_do_method(this, "_update_obj", animation);
|
||||||
undo_redo->add_undo_method(this, "_update_obj", animation);
|
undo_redo->add_undo_method(this, "_update_obj", animation);
|
||||||
|
AnimationPlayerEditor *ape = AnimationPlayerEditor::get_singleton();
|
||||||
|
if (ape) {
|
||||||
|
undo_redo->add_do_method(ape, "_animation_update_key_frame");
|
||||||
|
undo_redo->add_undo_method(ape, "_animation_update_key_frame");
|
||||||
|
}
|
||||||
undo_redo->commit_action();
|
undo_redo->commit_action();
|
||||||
|
|
||||||
setting = false;
|
setting = false;
|
||||||
|
@ -298,6 +308,11 @@ bool AnimationTrackKeyEdit::_set(const StringName &p_name, const Variant &p_valu
|
||||||
undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", track, key, prev);
|
undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", track, key, prev);
|
||||||
undo_redo->add_do_method(this, "_update_obj", animation);
|
undo_redo->add_do_method(this, "_update_obj", animation);
|
||||||
undo_redo->add_undo_method(this, "_update_obj", animation);
|
undo_redo->add_undo_method(this, "_update_obj", animation);
|
||||||
|
AnimationPlayerEditor *ape = AnimationPlayerEditor::get_singleton();
|
||||||
|
if (ape) {
|
||||||
|
undo_redo->add_do_method(ape, "_animation_update_key_frame");
|
||||||
|
undo_redo->add_undo_method(ape, "_animation_update_key_frame");
|
||||||
|
}
|
||||||
undo_redo->commit_action();
|
undo_redo->commit_action();
|
||||||
|
|
||||||
setting = false;
|
setting = false;
|
||||||
|
@ -318,6 +333,11 @@ bool AnimationTrackKeyEdit::_set(const StringName &p_name, const Variant &p_valu
|
||||||
undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", track, key, prev_in_handle);
|
undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", track, key, prev_in_handle);
|
||||||
undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", track, key, prev_out_handle);
|
undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", track, key, prev_out_handle);
|
||||||
undo_redo->add_undo_method(this, "_update_obj", animation);
|
undo_redo->add_undo_method(this, "_update_obj", animation);
|
||||||
|
AnimationPlayerEditor *ape = AnimationPlayerEditor::get_singleton();
|
||||||
|
if (ape) {
|
||||||
|
undo_redo->add_do_method(ape, "_animation_update_key_frame");
|
||||||
|
undo_redo->add_undo_method(ape, "_animation_update_key_frame");
|
||||||
|
}
|
||||||
undo_redo->commit_action();
|
undo_redo->commit_action();
|
||||||
|
|
||||||
setting = false;
|
setting = false;
|
||||||
|
@ -7032,7 +7052,10 @@ void AnimationTrackEditor::_update_snap_unit() {
|
||||||
if (timeline->is_using_fps()) {
|
if (timeline->is_using_fps()) {
|
||||||
snap_unit = 1.0 / step->get_value();
|
snap_unit = 1.0 / step->get_value();
|
||||||
} else {
|
} else {
|
||||||
snap_unit = 1.0 / Math::round(1.0 / step->get_value()); // Follow the snap behavior of the timeline editor.
|
double integer;
|
||||||
|
double fraction = Math::modf(step->get_value(), &integer);
|
||||||
|
fraction = 1.0 / Math::round(1.0 / fraction);
|
||||||
|
snap_unit = integer + fraction;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -994,6 +994,9 @@ Ref<Texture2D> CodeTextEditor::_get_completion_icon(const ScriptLanguage::CodeCo
|
||||||
tex = get_editor_theme_icon(p_option.display);
|
tex = get_editor_theme_icon(p_option.display);
|
||||||
} else {
|
} else {
|
||||||
tex = EditorNode::get_singleton()->get_class_icon(p_option.display);
|
tex = EditorNode::get_singleton()->get_class_icon(p_option.display);
|
||||||
|
if (!tex.is_valid()) {
|
||||||
|
tex = get_editor_theme_icon(SNAME("Object"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case ScriptLanguage::CODE_COMPLETION_KIND_ENUM:
|
case ScriptLanguage::CODE_COMPLETION_KIND_ENUM:
|
||||||
|
|
|
@ -578,32 +578,34 @@ void DependencyRemoveDialog::ok_pressed() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool project_settings_modified = false;
|
||||||
for (int i = 0; i < files_to_delete.size(); ++i) {
|
for (int i = 0; i < files_to_delete.size(); ++i) {
|
||||||
// If the file we are deleting for e.g. the main scene, default environment,
|
// If the file we are deleting for e.g. the main scene, default environment,
|
||||||
// or audio bus layout, we must clear its definition in Project Settings.
|
// or audio bus layout, we must clear its definition in Project Settings.
|
||||||
if (files_to_delete[i] == String(GLOBAL_GET("application/config/icon"))) {
|
if (files_to_delete[i] == String(GLOBAL_GET("application/config/icon"))) {
|
||||||
ProjectSettings::get_singleton()->set("application/config/icon", "");
|
ProjectSettings::get_singleton()->set("application/config/icon", "");
|
||||||
}
|
project_settings_modified = true;
|
||||||
if (files_to_delete[i] == String(GLOBAL_GET("application/run/main_scene"))) {
|
} else if (files_to_delete[i] == String(GLOBAL_GET("application/run/main_scene"))) {
|
||||||
ProjectSettings::get_singleton()->set("application/run/main_scene", "");
|
ProjectSettings::get_singleton()->set("application/run/main_scene", "");
|
||||||
}
|
project_settings_modified = true;
|
||||||
if (files_to_delete[i] == String(GLOBAL_GET("application/boot_splash/image"))) {
|
} else if (files_to_delete[i] == String(GLOBAL_GET("application/boot_splash/image"))) {
|
||||||
ProjectSettings::get_singleton()->set("application/boot_splash/image", "");
|
ProjectSettings::get_singleton()->set("application/boot_splash/image", "");
|
||||||
}
|
project_settings_modified = true;
|
||||||
if (files_to_delete[i] == String(GLOBAL_GET("rendering/environment/defaults/default_environment"))) {
|
} else if (files_to_delete[i] == String(GLOBAL_GET("rendering/environment/defaults/default_environment"))) {
|
||||||
ProjectSettings::get_singleton()->set("rendering/environment/defaults/default_environment", "");
|
ProjectSettings::get_singleton()->set("rendering/environment/defaults/default_environment", "");
|
||||||
}
|
project_settings_modified = true;
|
||||||
if (files_to_delete[i] == String(GLOBAL_GET("display/mouse_cursor/custom_image"))) {
|
} else if (files_to_delete[i] == String(GLOBAL_GET("display/mouse_cursor/custom_image"))) {
|
||||||
ProjectSettings::get_singleton()->set("display/mouse_cursor/custom_image", "");
|
ProjectSettings::get_singleton()->set("display/mouse_cursor/custom_image", "");
|
||||||
}
|
project_settings_modified = true;
|
||||||
if (files_to_delete[i] == String(GLOBAL_GET("gui/theme/custom"))) {
|
} else if (files_to_delete[i] == String(GLOBAL_GET("gui/theme/custom"))) {
|
||||||
ProjectSettings::get_singleton()->set("gui/theme/custom", "");
|
ProjectSettings::get_singleton()->set("gui/theme/custom", "");
|
||||||
}
|
project_settings_modified = true;
|
||||||
if (files_to_delete[i] == String(GLOBAL_GET("gui/theme/custom_font"))) {
|
} else if (files_to_delete[i] == String(GLOBAL_GET("gui/theme/custom_font"))) {
|
||||||
ProjectSettings::get_singleton()->set("gui/theme/custom_font", "");
|
ProjectSettings::get_singleton()->set("gui/theme/custom_font", "");
|
||||||
}
|
project_settings_modified = true;
|
||||||
if (files_to_delete[i] == String(GLOBAL_GET("audio/buses/default_bus_layout"))) {
|
} else if (files_to_delete[i] == String(GLOBAL_GET("audio/buses/default_bus_layout"))) {
|
||||||
ProjectSettings::get_singleton()->set("audio/buses/default_bus_layout", "");
|
ProjectSettings::get_singleton()->set("audio/buses/default_bus_layout", "");
|
||||||
|
project_settings_modified = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
String path = OS::get_singleton()->get_resource_dir() + files_to_delete[i].replace_first("res://", "/");
|
String path = OS::get_singleton()->get_resource_dir() + files_to_delete[i].replace_first("res://", "/");
|
||||||
|
@ -615,6 +617,9 @@ void DependencyRemoveDialog::ok_pressed() {
|
||||||
emit_signal(SNAME("file_removed"), files_to_delete[i]);
|
emit_signal(SNAME("file_removed"), files_to_delete[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (project_settings_modified) {
|
||||||
|
ProjectSettings::get_singleton()->save();
|
||||||
|
}
|
||||||
|
|
||||||
if (dirs_to_delete.size() == 0) {
|
if (dirs_to_delete.size() == 0) {
|
||||||
// If we only deleted files we should only need to tell the file system about the files we touched.
|
// If we only deleted files we should only need to tell the file system about the files we touched.
|
||||||
|
|
|
@ -457,7 +457,9 @@ void EditorAutoloadSettings::init_autoloads() {
|
||||||
|
|
||||||
for (const AutoloadInfo &info : autoload_cache) {
|
for (const AutoloadInfo &info : autoload_cache) {
|
||||||
if (info.node && info.in_editor) {
|
if (info.node && info.in_editor) {
|
||||||
callable_mp((Node *)get_tree()->get_root(), &Node::add_child).call_deferred(info.node, false, Node::INTERNAL_MODE_DISABLED);
|
// It's important to add the node without deferring because code in plugins or tool scripts
|
||||||
|
// could use the autoload node when they are enabled.
|
||||||
|
get_tree()->get_root()->add_child(info.node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -386,6 +386,8 @@ void EditorFileSystem::_scan_filesystem() {
|
||||||
// On the first scan, the first_scan_root_dir is created in _first_scan_filesystem.
|
// On the first scan, the first_scan_root_dir is created in _first_scan_filesystem.
|
||||||
if (first_scan) {
|
if (first_scan) {
|
||||||
sd = first_scan_root_dir;
|
sd = first_scan_root_dir;
|
||||||
|
// Will be updated on scan.
|
||||||
|
ResourceUID::get_singleton()->clear();
|
||||||
} else {
|
} else {
|
||||||
Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_RESOURCES);
|
Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_RESOURCES);
|
||||||
sd = memnew(ScannedDirectory);
|
sd = memnew(ScannedDirectory);
|
||||||
|
@ -1779,7 +1781,9 @@ String EditorFileSystem::_get_global_script_class(const String &p_type, const St
|
||||||
|
|
||||||
void EditorFileSystem::_update_file_icon_path(EditorFileSystemDirectory::FileInfo *file_info) {
|
void EditorFileSystem::_update_file_icon_path(EditorFileSystemDirectory::FileInfo *file_info) {
|
||||||
String icon_path;
|
String icon_path;
|
||||||
if (file_info->script_class_icon_path.is_empty() && !file_info->deps.is_empty()) {
|
if (file_info->resource_script_class != StringName()) {
|
||||||
|
icon_path = EditorNode::get_editor_data().script_class_get_icon_path(file_info->resource_script_class);
|
||||||
|
} else if (file_info->script_class_icon_path.is_empty() && !file_info->deps.is_empty()) {
|
||||||
const String &script_dep = file_info->deps[0]; // Assuming the first dependency is a script.
|
const String &script_dep = file_info->deps[0]; // Assuming the first dependency is a script.
|
||||||
const String &script_path = script_dep.contains("::") ? script_dep.get_slice("::", 2) : script_dep;
|
const String &script_path = script_dep.contains("::") ? script_dep.get_slice("::", 2) : script_dep;
|
||||||
if (!script_path.is_empty()) {
|
if (!script_path.is_empty()) {
|
||||||
|
@ -3059,7 +3063,6 @@ EditorFileSystem::EditorFileSystem() {
|
||||||
using_fat32_or_exfat = (da->get_filesystem_type() == "FAT32" || da->get_filesystem_type() == "exFAT");
|
using_fat32_or_exfat = (da->get_filesystem_type() == "FAT32" || da->get_filesystem_type() == "exFAT");
|
||||||
|
|
||||||
scan_total = 0;
|
scan_total = 0;
|
||||||
callable_mp(ResourceUID::get_singleton(), &ResourceUID::clear).call_deferred(); // Will be updated on scan.
|
|
||||||
ResourceSaver::set_get_resource_id_for_path(_resource_saver_get_resource_id_for_path);
|
ResourceSaver::set_get_resource_id_for_path(_resource_saver_get_resource_id_for_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -174,6 +174,32 @@ static const String EDITOR_NODE_CONFIG_SECTION = "EditorNode";
|
||||||
static const String REMOVE_ANDROID_BUILD_TEMPLATE_MESSAGE = "The Android build template is already installed in this project and it won't be overwritten.\nRemove the \"%s\" directory manually before attempting this operation again.";
|
static const String REMOVE_ANDROID_BUILD_TEMPLATE_MESSAGE = "The Android build template is already installed in this project and it won't be overwritten.\nRemove the \"%s\" directory manually before attempting this operation again.";
|
||||||
static const String INSTALL_ANDROID_BUILD_TEMPLATE_MESSAGE = "This will set up your project for gradle Android builds by installing the source template to \"%s\".\nNote that in order to make gradle builds instead of using pre-built APKs, the \"Use Gradle Build\" option should be enabled in the Android export preset.";
|
static const String INSTALL_ANDROID_BUILD_TEMPLATE_MESSAGE = "This will set up your project for gradle Android builds by installing the source template to \"%s\".\nNote that in order to make gradle builds instead of using pre-built APKs, the \"Use Gradle Build\" option should be enabled in the Android export preset.";
|
||||||
|
|
||||||
|
bool EditorProgress::step(const String &p_state, int p_step, bool p_force_refresh) {
|
||||||
|
if (Thread::is_main_thread()) {
|
||||||
|
return EditorNode::progress_task_step(task, p_state, p_step, p_force_refresh);
|
||||||
|
} else {
|
||||||
|
EditorNode::progress_task_step_bg(task, p_step);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorProgress::EditorProgress(const String &p_task, const String &p_label, int p_amount, bool p_can_cancel) {
|
||||||
|
if (Thread::is_main_thread()) {
|
||||||
|
EditorNode::progress_add_task(p_task, p_label, p_amount, p_can_cancel);
|
||||||
|
} else {
|
||||||
|
EditorNode::progress_add_task_bg(p_task, p_label, p_amount);
|
||||||
|
}
|
||||||
|
task = p_task;
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorProgress::~EditorProgress() {
|
||||||
|
if (Thread::is_main_thread()) {
|
||||||
|
EditorNode::progress_end_task(task);
|
||||||
|
} else {
|
||||||
|
EditorNode::progress_end_task_bg(task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void EditorNode::disambiguate_filenames(const Vector<String> p_full_paths, Vector<String> &r_filenames) {
|
void EditorNode::disambiguate_filenames(const Vector<String> p_full_paths, Vector<String> &r_filenames) {
|
||||||
ERR_FAIL_COND_MSG(p_full_paths.size() != r_filenames.size(), vformat("disambiguate_filenames requires two string vectors of same length (%d != %d).", p_full_paths.size(), r_filenames.size()));
|
ERR_FAIL_COND_MSG(p_full_paths.size() != r_filenames.size(), vformat("disambiguate_filenames requires two string vectors of same length (%d != %d).", p_full_paths.size(), r_filenames.size()));
|
||||||
|
|
||||||
|
@ -670,7 +696,10 @@ void EditorNode::_notification(int p_what) {
|
||||||
|
|
||||||
callable_mp(this, &EditorNode::_begin_first_scan).call_deferred();
|
callable_mp(this, &EditorNode::_begin_first_scan).call_deferred();
|
||||||
|
|
||||||
DisplayServer::get_singleton()->set_system_theme_change_callback(callable_mp(this, &EditorNode::_update_theme).bind(false));
|
last_dark_mode_state = DisplayServer::get_singleton()->is_dark_mode();
|
||||||
|
last_system_accent_color = DisplayServer::get_singleton()->get_accent_color();
|
||||||
|
last_system_base_color = DisplayServer::get_singleton()->get_base_color();
|
||||||
|
DisplayServer::get_singleton()->set_system_theme_change_callback(callable_mp(this, &EditorNode::_check_system_theme_changed));
|
||||||
|
|
||||||
/* DO NOT LOAD SCENES HERE, WAIT FOR FILE SCANNING AND REIMPORT TO COMPLETE */
|
/* DO NOT LOAD SCENES HERE, WAIT FOR FILE SCANNING AND REIMPORT TO COMPLETE */
|
||||||
} break;
|
} break;
|
||||||
|
@ -1658,17 +1687,17 @@ void EditorNode::_find_node_types(Node *p_node, int &count_2d, int &count_3d) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorNode::_save_scene_with_preview(String p_file, int p_idx) {
|
void EditorNode::_save_scene_with_preview(String p_file, int p_idx) {
|
||||||
EditorProgress save("save", TTR("Saving Scene"), 4);
|
save_scene_progress = memnew(EditorProgress("save", TTR("Saving Scene"), 4));
|
||||||
|
|
||||||
if (editor_data.get_edited_scene_root() != nullptr) {
|
if (editor_data.get_edited_scene_root() != nullptr) {
|
||||||
save.step(TTR("Analyzing"), 0);
|
save_scene_progress->step(TTR("Analyzing"), 0);
|
||||||
|
|
||||||
int c2d = 0;
|
int c2d = 0;
|
||||||
int c3d = 0;
|
int c3d = 0;
|
||||||
|
|
||||||
_find_node_types(editor_data.get_edited_scene_root(), c2d, c3d);
|
_find_node_types(editor_data.get_edited_scene_root(), c2d, c3d);
|
||||||
|
|
||||||
save.step(TTR("Creating Thumbnail"), 1);
|
save_scene_progress->step(TTR("Creating Thumbnail"), 1);
|
||||||
// Current view?
|
// Current view?
|
||||||
|
|
||||||
Ref<Image> img;
|
Ref<Image> img;
|
||||||
|
@ -1696,8 +1725,7 @@ void EditorNode::_save_scene_with_preview(String p_file, int p_idx) {
|
||||||
if (img.is_valid() && img->get_width() > 0 && img->get_height() > 0) {
|
if (img.is_valid() && img->get_width() > 0 && img->get_height() > 0) {
|
||||||
img = img->duplicate();
|
img = img->duplicate();
|
||||||
|
|
||||||
save.step(TTR("Creating Thumbnail"), 2);
|
save_scene_progress->step(TTR("Creating Thumbnail"), 3);
|
||||||
save.step(TTR("Creating Thumbnail"), 3);
|
|
||||||
|
|
||||||
int preview_size = EDITOR_GET("filesystem/file_dialog/thumbnail_size");
|
int preview_size = EDITOR_GET("filesystem/file_dialog/thumbnail_size");
|
||||||
preview_size *= EDSCALE;
|
preview_size *= EDSCALE;
|
||||||
|
@ -1733,12 +1761,19 @@ void EditorNode::_save_scene_with_preview(String p_file, int p_idx) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
save.step(TTR("Saving Scene"), 4);
|
save_scene_progress->step(TTR("Saving Scene"), 4);
|
||||||
_save_scene(p_file, p_idx);
|
_save_scene(p_file, p_idx);
|
||||||
|
|
||||||
if (!singleton->cmdline_export_mode) {
|
if (!singleton->cmdline_export_mode) {
|
||||||
EditorResourcePreview::get_singleton()->check_for_invalidation(p_file);
|
EditorResourcePreview::get_singleton()->check_for_invalidation(p_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_close_save_scene_progress();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorNode::_close_save_scene_progress() {
|
||||||
|
memdelete_notnull(save_scene_progress);
|
||||||
|
save_scene_progress = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EditorNode::_validate_scene_recursive(const String &p_filename, Node *p_node) {
|
bool EditorNode::_validate_scene_recursive(const String &p_filename, Node *p_node) {
|
||||||
|
@ -5132,6 +5167,7 @@ bool EditorNode::is_project_exporting() const {
|
||||||
void EditorNode::show_accept(const String &p_text, const String &p_title) {
|
void EditorNode::show_accept(const String &p_text, const String &p_title) {
|
||||||
current_menu_option = -1;
|
current_menu_option = -1;
|
||||||
if (accept) {
|
if (accept) {
|
||||||
|
_close_save_scene_progress();
|
||||||
accept->set_ok_button_text(p_title);
|
accept->set_ok_button_text(p_title);
|
||||||
accept->set_text(p_text);
|
accept->set_text(p_text);
|
||||||
EditorInterface::get_singleton()->popup_dialog_centered(accept);
|
EditorInterface::get_singleton()->popup_dialog_centered(accept);
|
||||||
|
@ -5141,6 +5177,7 @@ void EditorNode::show_accept(const String &p_text, const String &p_title) {
|
||||||
void EditorNode::show_save_accept(const String &p_text, const String &p_title) {
|
void EditorNode::show_save_accept(const String &p_text, const String &p_title) {
|
||||||
current_menu_option = -1;
|
current_menu_option = -1;
|
||||||
if (save_accept) {
|
if (save_accept) {
|
||||||
|
_close_save_scene_progress();
|
||||||
save_accept->set_ok_button_text(p_title);
|
save_accept->set_ok_button_text(p_title);
|
||||||
save_accept->set_text(p_text);
|
save_accept->set_text(p_text);
|
||||||
EditorInterface::get_singleton()->popup_dialog_centered(save_accept);
|
EditorInterface::get_singleton()->popup_dialog_centered(save_accept);
|
||||||
|
@ -5149,6 +5186,7 @@ void EditorNode::show_save_accept(const String &p_text, const String &p_title) {
|
||||||
|
|
||||||
void EditorNode::show_warning(const String &p_text, const String &p_title) {
|
void EditorNode::show_warning(const String &p_text, const String &p_title) {
|
||||||
if (warning) {
|
if (warning) {
|
||||||
|
_close_save_scene_progress();
|
||||||
warning->set_text(p_text);
|
warning->set_text(p_text);
|
||||||
warning->set_title(p_title);
|
warning->set_title(p_title);
|
||||||
EditorInterface::get_singleton()->popup_dialog_centered(warning);
|
EditorInterface::get_singleton()->popup_dialog_centered(warning);
|
||||||
|
@ -5296,14 +5334,18 @@ void EditorNode::_load_open_scenes_from_config(Ref<ConfigFile> p_layout) {
|
||||||
|
|
||||||
PackedStringArray scenes = p_layout->get_value(EDITOR_NODE_CONFIG_SECTION, "open_scenes");
|
PackedStringArray scenes = p_layout->get_value(EDITOR_NODE_CONFIG_SECTION, "open_scenes");
|
||||||
for (int i = 0; i < scenes.size(); i++) {
|
for (int i = 0; i < scenes.size(); i++) {
|
||||||
load_scene(scenes[i]);
|
if (FileAccess::exists(scenes[i])) {
|
||||||
|
load_scene(scenes[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p_layout->has_section_key(EDITOR_NODE_CONFIG_SECTION, "current_scene")) {
|
if (p_layout->has_section_key(EDITOR_NODE_CONFIG_SECTION, "current_scene")) {
|
||||||
String current_scene = p_layout->get_value(EDITOR_NODE_CONFIG_SECTION, "current_scene");
|
String current_scene = p_layout->get_value(EDITOR_NODE_CONFIG_SECTION, "current_scene");
|
||||||
int current_scene_idx = scenes.find(current_scene);
|
for (int i = 0; i < editor_data.get_edited_scene_count(); i++) {
|
||||||
if (current_scene_idx >= 0) {
|
if (editor_data.get_scene_path(i) == current_scene) {
|
||||||
_set_current_scene(current_scene_idx);
|
_set_current_scene(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6033,7 +6075,7 @@ void EditorNode::reload_instances_with_path_in_edited_scenes() {
|
||||||
base_packed_scene = current_packed_scene;
|
base_packed_scene = current_packed_scene;
|
||||||
}
|
}
|
||||||
if (!local_scene_cache.find(path)) {
|
if (!local_scene_cache.find(path)) {
|
||||||
current_packed_scene = ResourceLoader::load(path, "", ResourceFormatLoader::CACHE_MODE_REPLACE_DEEP, &err);
|
current_packed_scene = ResourceLoader::load(path, "", ResourceFormatLoader::CACHE_MODE_REPLACE, &err);
|
||||||
local_scene_cache[path] = current_packed_scene;
|
local_scene_cache[path] = current_packed_scene;
|
||||||
} else {
|
} else {
|
||||||
current_packed_scene = local_scene_cache[path];
|
current_packed_scene = local_scene_cache[path];
|
||||||
|
|
|
@ -122,6 +122,14 @@ class SurfaceUpgradeTool;
|
||||||
class SurfaceUpgradeDialog;
|
class SurfaceUpgradeDialog;
|
||||||
class WindowWrapper;
|
class WindowWrapper;
|
||||||
|
|
||||||
|
struct EditorProgress {
|
||||||
|
String task;
|
||||||
|
bool step(const String &p_state, int p_step = -1, bool p_force_refresh = true);
|
||||||
|
|
||||||
|
EditorProgress(const String &p_task, const String &p_label, int p_amount, bool p_can_cancel = false);
|
||||||
|
~EditorProgress();
|
||||||
|
};
|
||||||
|
|
||||||
class EditorNode : public Node {
|
class EditorNode : public Node {
|
||||||
GDCLASS(EditorNode, Node);
|
GDCLASS(EditorNode, Node);
|
||||||
|
|
||||||
|
@ -470,6 +478,7 @@ private:
|
||||||
String external_file;
|
String external_file;
|
||||||
String open_navigate;
|
String open_navigate;
|
||||||
String saving_scene;
|
String saving_scene;
|
||||||
|
EditorProgress *save_scene_progress = nullptr;
|
||||||
|
|
||||||
DynamicFontImportSettingsDialog *fontdata_import_settings = nullptr;
|
DynamicFontImportSettingsDialog *fontdata_import_settings = nullptr;
|
||||||
SceneImportSettingsDialog *scene_import_settings = nullptr;
|
SceneImportSettingsDialog *scene_import_settings = nullptr;
|
||||||
|
@ -624,6 +633,7 @@ private:
|
||||||
|
|
||||||
void _find_node_types(Node *p_node, int &count_2d, int &count_3d);
|
void _find_node_types(Node *p_node, int &count_2d, int &count_3d);
|
||||||
void _save_scene_with_preview(String p_file, int p_idx = -1);
|
void _save_scene_with_preview(String p_file, int p_idx = -1);
|
||||||
|
void _close_save_scene_progress();
|
||||||
|
|
||||||
bool _find_scene_in_use(Node *p_node, const String &p_path) const;
|
bool _find_scene_in_use(Node *p_node, const String &p_path) const;
|
||||||
|
|
||||||
|
@ -952,33 +962,6 @@ public:
|
||||||
bool ensure_main_scene(bool p_from_native);
|
bool ensure_main_scene(bool p_from_native);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EditorProgress {
|
|
||||||
String task;
|
|
||||||
bool step(const String &p_state, int p_step = -1, bool p_force_refresh = true) {
|
|
||||||
if (Thread::is_main_thread()) {
|
|
||||||
return EditorNode::progress_task_step(task, p_state, p_step, p_force_refresh);
|
|
||||||
} else {
|
|
||||||
EditorNode::progress_task_step_bg(task, p_step);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EditorProgress(const String &p_task, const String &p_label, int p_amount, bool p_can_cancel = false) {
|
|
||||||
if (Thread::is_main_thread()) {
|
|
||||||
EditorNode::progress_add_task(p_task, p_label, p_amount, p_can_cancel);
|
|
||||||
} else {
|
|
||||||
EditorNode::progress_add_task_bg(p_task, p_label, p_amount);
|
|
||||||
}
|
|
||||||
task = p_task;
|
|
||||||
}
|
|
||||||
~EditorProgress() {
|
|
||||||
if (Thread::is_main_thread()) {
|
|
||||||
EditorNode::progress_end_task(task);
|
|
||||||
} else {
|
|
||||||
EditorNode::progress_end_task_bg(task);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class EditorPluginList : public Object {
|
class EditorPluginList : public Object {
|
||||||
private:
|
private:
|
||||||
Vector<EditorPlugin *> plugins_list;
|
Vector<EditorPlugin *> plugins_list;
|
||||||
|
|
|
@ -2778,7 +2778,11 @@ void EditorPropertyNodePath::_update_menu() {
|
||||||
void EditorPropertyNodePath::_menu_option(int p_idx) {
|
void EditorPropertyNodePath::_menu_option(int p_idx) {
|
||||||
switch (p_idx) {
|
switch (p_idx) {
|
||||||
case ACTION_CLEAR: {
|
case ACTION_CLEAR: {
|
||||||
emit_changed(get_edited_property(), NodePath());
|
if (editing_node) {
|
||||||
|
emit_changed(get_edited_property(), Variant());
|
||||||
|
} else {
|
||||||
|
emit_changed(get_edited_property(), NodePath());
|
||||||
|
}
|
||||||
update_property();
|
update_property();
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
|
|
@ -175,6 +175,13 @@ void EditorResourcePicker::_file_quick_selected() {
|
||||||
_file_selected(quick_open->get_selected());
|
_file_selected(quick_open->get_selected());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EditorResourcePicker::_resource_saved(Object *p_resource) {
|
||||||
|
if (edited_resource.is_valid() && p_resource == edited_resource.ptr()) {
|
||||||
|
emit_signal(SNAME("resource_changed"), edited_resource);
|
||||||
|
_update_resource();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void EditorResourcePicker::_update_menu() {
|
void EditorResourcePicker::_update_menu() {
|
||||||
_update_menu_items();
|
_update_menu_items();
|
||||||
|
|
||||||
|
@ -408,6 +415,10 @@ void EditorResourcePicker::_edit_menu_cbk(int p_which) {
|
||||||
if (edited_resource.is_null()) {
|
if (edited_resource.is_null()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Callable resource_saved = callable_mp(this, &EditorResourcePicker::_resource_saved);
|
||||||
|
if (!EditorNode::get_singleton()->is_connected("resource_saved", resource_saved)) {
|
||||||
|
EditorNode::get_singleton()->connect("resource_saved", resource_saved);
|
||||||
|
}
|
||||||
EditorNode::get_singleton()->save_resource_as(edited_resource);
|
EditorNode::get_singleton()->save_resource_as(edited_resource);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
@ -833,6 +844,13 @@ void EditorResourcePicker::_notification(int p_what) {
|
||||||
assign_button->queue_redraw();
|
assign_button->queue_redraw();
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case NOTIFICATION_EXIT_TREE: {
|
||||||
|
Callable resource_saved = callable_mp(this, &EditorResourcePicker::_resource_saved);
|
||||||
|
if (EditorNode::get_singleton()->is_connected("resource_saved", resource_saved)) {
|
||||||
|
EditorNode::get_singleton()->disconnect("resource_saved", resource_saved);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -91,6 +91,8 @@ class EditorResourcePicker : public HBoxContainer {
|
||||||
void _file_quick_selected();
|
void _file_quick_selected();
|
||||||
void _file_selected(const String &p_path);
|
void _file_selected(const String &p_path);
|
||||||
|
|
||||||
|
void _resource_saved(Object *p_resource);
|
||||||
|
|
||||||
void _update_menu();
|
void _update_menu();
|
||||||
void _update_menu_items();
|
void _update_menu_items();
|
||||||
void _edit_menu_cbk(int p_which);
|
void _edit_menu_cbk(int p_which);
|
||||||
|
|
|
@ -685,7 +685,15 @@ void FileSystemDock::_tree_multi_selected(Object *p_item, int p_column, bool p_s
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector<String> FileSystemDock::get_selected_paths() const {
|
Vector<String> FileSystemDock::get_selected_paths() const {
|
||||||
return _tree_get_selected(false);
|
if (display_mode == DISPLAY_MODE_TREE_ONLY) {
|
||||||
|
return _tree_get_selected(false);
|
||||||
|
} else {
|
||||||
|
Vector<String> selected = _file_list_get_selected();
|
||||||
|
if (selected.is_empty()) {
|
||||||
|
selected.push_back(get_current_directory());
|
||||||
|
}
|
||||||
|
return selected;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String FileSystemDock::get_current_path() const {
|
String FileSystemDock::get_current_path() const {
|
||||||
|
@ -953,7 +961,8 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
|
||||||
files->set_max_columns(1);
|
files->set_max_columns(1);
|
||||||
files->set_max_text_lines(1);
|
files->set_max_text_lines(1);
|
||||||
files->set_fixed_column_width(0);
|
files->set_fixed_column_width(0);
|
||||||
files->set_fixed_icon_size(Size2());
|
const int icon_size = get_theme_constant(SNAME("class_icon_size"), EditorStringName(Editor));
|
||||||
|
files->set_fixed_icon_size(Size2(icon_size, icon_size));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ref<Texture2D> folder_icon = (use_thumbnails) ? folder_thumbnail : get_theme_icon(SNAME("folder"), SNAME("FileDialog"));
|
Ref<Texture2D> folder_icon = (use_thumbnails) ? folder_thumbnail : get_theme_icon(SNAME("folder"), SNAME("FileDialog"));
|
||||||
|
@ -2049,6 +2058,15 @@ Vector<String> FileSystemDock::_tree_get_selected(bool remove_self_inclusion, bo
|
||||||
return selected_strings;
|
return selected_strings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector<String> FileSystemDock::_file_list_get_selected() const {
|
||||||
|
Vector<String> selected;
|
||||||
|
|
||||||
|
for (int idx : files->get_selected_items()) {
|
||||||
|
selected.push_back(files->get_item_metadata(idx));
|
||||||
|
}
|
||||||
|
return selected;
|
||||||
|
}
|
||||||
|
|
||||||
Vector<String> FileSystemDock::_remove_self_included_paths(Vector<String> selected_strings) {
|
Vector<String> FileSystemDock::_remove_self_included_paths(Vector<String> selected_strings) {
|
||||||
// Remove paths or files that are included into another.
|
// Remove paths or files that are included into another.
|
||||||
if (selected_strings.size() > 1) {
|
if (selected_strings.size() > 1) {
|
||||||
|
@ -3392,6 +3410,11 @@ void FileSystemDock::_file_list_empty_clicked(const Vector2 &p_pos, MouseButton
|
||||||
|
|
||||||
current_path = current_path_line_edit->get_text();
|
current_path = current_path_line_edit->get_text();
|
||||||
|
|
||||||
|
// Favorites isn't a directory so don't show menu.
|
||||||
|
if (current_path == "Favorites") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
file_list_popup->clear();
|
file_list_popup->clear();
|
||||||
file_list_popup->reset_size();
|
file_list_popup->reset_size();
|
||||||
|
|
||||||
|
|
|
@ -359,6 +359,7 @@ private:
|
||||||
void _update_display_mode(bool p_force = false);
|
void _update_display_mode(bool p_force = false);
|
||||||
|
|
||||||
Vector<String> _tree_get_selected(bool remove_self_inclusion = true, bool p_include_unselected_cursor = false) const;
|
Vector<String> _tree_get_selected(bool remove_self_inclusion = true, bool p_include_unselected_cursor = false) const;
|
||||||
|
Vector<String> _file_list_get_selected() const;
|
||||||
|
|
||||||
bool _is_file_type_disabled_by_feature_profile(const StringName &p_class);
|
bool _is_file_type_disabled_by_feature_profile(const StringName &p_class);
|
||||||
|
|
||||||
|
|
|
@ -115,6 +115,8 @@ void EditorFileDialog::_native_dialog_cb(bool p_ok, const Vector<String> &p_file
|
||||||
file_name = ProjectSettings::get_singleton()->localize_path(file_name);
|
file_name = ProjectSettings::get_singleton()->localize_path(file_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
selected_options = p_selected_options;
|
||||||
|
|
||||||
String f = files[0];
|
String f = files[0];
|
||||||
if (mode == FILE_MODE_OPEN_FILES) {
|
if (mode == FILE_MODE_OPEN_FILES) {
|
||||||
emit_signal(SNAME("files_selected"), files);
|
emit_signal(SNAME("files_selected"), files);
|
||||||
|
@ -146,7 +148,6 @@ void EditorFileDialog::_native_dialog_cb(bool p_ok, const Vector<String> &p_file
|
||||||
}
|
}
|
||||||
file->set_text(f);
|
file->set_text(f);
|
||||||
dir->set_text(f.get_base_dir());
|
dir->set_text(f.get_base_dir());
|
||||||
selected_options = p_selected_options;
|
|
||||||
filter->select(p_filter);
|
filter->select(p_filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -614,13 +614,13 @@ void EditorSpinSlider::_value_focus_exited() {
|
||||||
// -> TAB was pressed
|
// -> TAB was pressed
|
||||||
// -> modal_close was not called
|
// -> modal_close was not called
|
||||||
// -> need to close/hide manually
|
// -> need to close/hide manually
|
||||||
if (value_input_closed_frame != Engine::get_singleton()->get_frames_drawn()) {
|
if (!is_visible_in_tree() || value_input_closed_frame != Engine::get_singleton()->get_frames_drawn()) {
|
||||||
|
// Hidden or something else took focus.
|
||||||
if (value_input_popup) {
|
if (value_input_popup) {
|
||||||
value_input_popup->hide();
|
value_input_popup->hide();
|
||||||
}
|
}
|
||||||
//tab was pressed
|
|
||||||
} else {
|
} else {
|
||||||
//enter, click, esc
|
// Enter or Esc was pressed.
|
||||||
grab_focus();
|
grab_focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -664,6 +664,10 @@ bool EditorSpinSlider::is_grabbing() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorSpinSlider::_focus_entered() {
|
void EditorSpinSlider::_focus_entered() {
|
||||||
|
if (is_read_only()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_ensure_input_popup();
|
_ensure_input_popup();
|
||||||
value_input->set_text(get_text_value());
|
value_input->set_text(get_text_value());
|
||||||
value_input_popup->set_size(get_size());
|
value_input_popup->set_size(get_size());
|
||||||
|
|
|
@ -490,10 +490,14 @@ void SceneTreeEditor::_update_node_tooltip(Node *p_node, TreeItem *p_item) {
|
||||||
String tooltip = p_node->get_name();
|
String tooltip = p_node->get_name();
|
||||||
|
|
||||||
if (p_node == get_scene_node() && p_node->get_scene_inherited_state().is_valid()) {
|
if (p_node == get_scene_node() && p_node->get_scene_inherited_state().is_valid()) {
|
||||||
p_item->add_button(0, get_editor_theme_icon(SNAME("InstanceOptions")), BUTTON_SUBSCENE, false, TTR("Open in Editor"));
|
if (p_item->get_button_by_id(0, BUTTON_SUBSCENE) == -1) {
|
||||||
|
p_item->add_button(0, get_editor_theme_icon(SNAME("InstanceOptions")), BUTTON_SUBSCENE, false, TTR("Open in Editor"));
|
||||||
|
}
|
||||||
tooltip += String("\n" + TTR("Inherits:") + " " + p_node->get_scene_inherited_state()->get_path());
|
tooltip += String("\n" + TTR("Inherits:") + " " + p_node->get_scene_inherited_state()->get_path());
|
||||||
} else if (p_node != get_scene_node() && !p_node->get_scene_file_path().is_empty() && can_open_instance) {
|
} else if (p_node != get_scene_node() && !p_node->get_scene_file_path().is_empty() && can_open_instance) {
|
||||||
p_item->add_button(0, get_editor_theme_icon(SNAME("InstanceOptions")), BUTTON_SUBSCENE, false, TTR("Open in Editor"));
|
if (p_item->get_button_by_id(0, BUTTON_SUBSCENE) == -1) {
|
||||||
|
p_item->add_button(0, get_editor_theme_icon(SNAME("InstanceOptions")), BUTTON_SUBSCENE, false, TTR("Open in Editor"));
|
||||||
|
}
|
||||||
tooltip += String("\n" + TTR("Instance:") + " " + p_node->get_scene_file_path());
|
tooltip += String("\n" + TTR("Instance:") + " " + p_node->get_scene_file_path());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1000,6 +1004,7 @@ void SceneTreeEditor::set_selected(Node *p_node, bool p_emit_selected) {
|
||||||
TreeItem *item = p_node ? _find(tree->get_root(), p_node->get_path()) : nullptr;
|
TreeItem *item = p_node ? _find(tree->get_root(), p_node->get_path()) : nullptr;
|
||||||
|
|
||||||
if (item) {
|
if (item) {
|
||||||
|
selected = p_node;
|
||||||
if (auto_expand_selected) {
|
if (auto_expand_selected) {
|
||||||
// Make visible when it's collapsed.
|
// Make visible when it's collapsed.
|
||||||
TreeItem *node = item->get_parent();
|
TreeItem *node = item->get_parent();
|
||||||
|
@ -1009,8 +1014,24 @@ void SceneTreeEditor::set_selected(Node *p_node, bool p_emit_selected) {
|
||||||
}
|
}
|
||||||
item->select(0);
|
item->select(0);
|
||||||
item->set_as_cursor(0);
|
item->set_as_cursor(0);
|
||||||
selected = p_node;
|
|
||||||
tree->ensure_cursor_is_visible();
|
tree->ensure_cursor_is_visible();
|
||||||
|
} else {
|
||||||
|
// Ensure the node is selected and visible for the user if the node
|
||||||
|
// is not collapsed.
|
||||||
|
bool collapsed = false;
|
||||||
|
TreeItem *node = item;
|
||||||
|
while (node && node != tree->get_root()) {
|
||||||
|
if (node->is_collapsed()) {
|
||||||
|
collapsed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
node = node->get_parent();
|
||||||
|
}
|
||||||
|
if (!collapsed) {
|
||||||
|
item->select(0);
|
||||||
|
item->set_as_cursor(0);
|
||||||
|
tree->ensure_cursor_is_visible();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!p_node) {
|
if (!p_node) {
|
||||||
|
|
|
@ -293,18 +293,20 @@ Error ResourceImporterImageFont::import(const String &p_source_file, const Strin
|
||||||
}
|
}
|
||||||
String from_tokens;
|
String from_tokens;
|
||||||
for (int i = 0; i < kp_tokens[0].length(); i++) {
|
for (int i = 0; i < kp_tokens[0].length(); i++) {
|
||||||
if (i <= kp_tokens[0].length() - 6 && kp_tokens[0][i] == '\\' && kp_tokens[0][i + 1] == 'u') {
|
if (i <= kp_tokens[0].length() - 6 && kp_tokens[0][i] == '\\' && kp_tokens[0][i + 1] == 'u' && is_hex_digit(kp_tokens[0][i + 2]) && is_hex_digit(kp_tokens[0][i + 3]) && is_hex_digit(kp_tokens[0][i + 4]) && is_hex_digit(kp_tokens[0][i + 5])) {
|
||||||
char32_t charcode = kp_tokens[0].substr(i + 2, 4).hex_to_int();
|
char32_t charcode = kp_tokens[0].substr(i + 2, 4).hex_to_int();
|
||||||
from_tokens += charcode;
|
from_tokens += charcode;
|
||||||
|
i += 5;
|
||||||
} else {
|
} else {
|
||||||
from_tokens += kp_tokens[0][i];
|
from_tokens += kp_tokens[0][i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
String to_tokens;
|
String to_tokens;
|
||||||
for (int i = 0; i < kp_tokens[1].length(); i++) {
|
for (int i = 0; i < kp_tokens[1].length(); i++) {
|
||||||
if (i <= kp_tokens[1].length() - 6 && kp_tokens[1][i] == '\\' && kp_tokens[1][i + 1] == 'u') {
|
if (i <= kp_tokens[1].length() - 6 && kp_tokens[1][i] == '\\' && kp_tokens[1][i + 1] == 'u' && is_hex_digit(kp_tokens[1][i + 2]) && is_hex_digit(kp_tokens[1][i + 3]) && is_hex_digit(kp_tokens[1][i + 4]) && is_hex_digit(kp_tokens[1][i + 5])) {
|
||||||
char32_t charcode = kp_tokens[1].substr(i + 2, 4).hex_to_int();
|
char32_t charcode = kp_tokens[1].substr(i + 2, 4).hex_to_int();
|
||||||
to_tokens += charcode;
|
to_tokens += charcode;
|
||||||
|
i += 5;
|
||||||
} else {
|
} else {
|
||||||
to_tokens += kp_tokens[1][i];
|
to_tokens += kp_tokens[1][i];
|
||||||
}
|
}
|
||||||
|
|
|
@ -428,10 +428,10 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s
|
||||||
loop_end = p_options["edit/loop_end"];
|
loop_end = p_options["edit/loop_end"];
|
||||||
// Wrap around to max frames, so `-1` can be used to select the end, etc.
|
// Wrap around to max frames, so `-1` can be used to select the end, etc.
|
||||||
if (loop_begin < 0) {
|
if (loop_begin < 0) {
|
||||||
loop_begin = CLAMP(loop_begin + frames + 1, 0, frames);
|
loop_begin = CLAMP(loop_begin + frames, 0, frames - 1);
|
||||||
}
|
}
|
||||||
if (loop_end < 0) {
|
if (loop_end < 0) {
|
||||||
loop_end = CLAMP(loop_end + frames + 1, 0, frames);
|
loop_end = CLAMP(loop_end + frames, 0, frames - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -517,16 +517,19 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s
|
||||||
Vector<uint8_t> dst_data;
|
Vector<uint8_t> dst_data;
|
||||||
if (compression == 2) {
|
if (compression == 2) {
|
||||||
dst_format = AudioStreamWAV::FORMAT_QOA;
|
dst_format = AudioStreamWAV::FORMAT_QOA;
|
||||||
qoa_desc desc = { 0, 0, 0, { { { 0 }, { 0 } } } };
|
qoa_desc desc = {};
|
||||||
uint32_t qoa_len = 0;
|
uint32_t qoa_len = 0;
|
||||||
|
|
||||||
desc.samplerate = rate;
|
desc.samplerate = rate;
|
||||||
desc.samples = frames;
|
desc.samples = frames;
|
||||||
desc.channels = format_channels;
|
desc.channels = format_channels;
|
||||||
|
|
||||||
void *encoded = qoa_encode((short *)pcm_data.ptrw(), &desc, &qoa_len);
|
void *encoded = qoa_encode((short *)pcm_data.ptr(), &desc, &qoa_len);
|
||||||
dst_data.resize(qoa_len);
|
if (encoded) {
|
||||||
memcpy(dst_data.ptrw(), encoded, qoa_len);
|
dst_data.resize(qoa_len);
|
||||||
|
memcpy(dst_data.ptrw(), encoded, qoa_len);
|
||||||
|
QOA_FREE(encoded);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
dst_data = pcm_data;
|
dst_data = pcm_data;
|
||||||
}
|
}
|
||||||
|
|
|
@ -751,7 +751,9 @@ AbstractPolygon2DEditor::AbstractPolygon2DEditor(bool p_wip_destructive) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbstractPolygon2DEditorPlugin::edit(Object *p_object) {
|
void AbstractPolygon2DEditorPlugin::edit(Object *p_object) {
|
||||||
polygon_editor->edit(Object::cast_to<Node>(p_object));
|
Node *polygon_node = Object::cast_to<Node>(p_object);
|
||||||
|
polygon_editor->edit(polygon_node);
|
||||||
|
make_visible(polygon_node != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AbstractPolygon2DEditorPlugin::handles(Object *p_object) const {
|
bool AbstractPolygon2DEditorPlugin::handles(Object *p_object) const {
|
||||||
|
|
|
@ -561,7 +561,9 @@ void AnimationLibraryEditor::_button_pressed(TreeItem *p_item, int p_column, int
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
anim = anim->duplicate(); // Users simply dont care about referencing, so making a copy works better here.
|
if (!anim->get_path().is_resource_file()) {
|
||||||
|
anim = anim->duplicate(); // Users simply dont care about referencing, so making a copy works better here.
|
||||||
|
}
|
||||||
|
|
||||||
String base_name;
|
String base_name;
|
||||||
if (anim->get_name() != "") {
|
if (anim->get_name() != "") {
|
||||||
|
|
|
@ -339,7 +339,17 @@ void AnimationPlayerEditor::_animation_selected(int p_which) {
|
||||||
|
|
||||||
track_editor->set_animation(anim, animation_is_readonly);
|
track_editor->set_animation(anim, animation_is_readonly);
|
||||||
Node *root = player->get_node_or_null(player->get_root_node());
|
Node *root = player->get_node_or_null(player->get_root_node());
|
||||||
if (root) {
|
|
||||||
|
// Player shouldn't access parent if it's the scene root.
|
||||||
|
if (!root || (player == get_tree()->get_edited_scene_root() && player->get_root_node() == SceneStringName(path_pp))) {
|
||||||
|
NodePath cached_root_path = player->get_path_to(get_cached_root_node());
|
||||||
|
if (player->get_node_or_null(cached_root_path) != nullptr) {
|
||||||
|
player->set_root_node(cached_root_path);
|
||||||
|
} else {
|
||||||
|
player->set_root_node(SceneStringName(path_pp)); // No other choice, preventing crash.
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cached_root_node_id = root->get_instance_id(); // Caching as `track_editor` can lose track of player's root node.
|
||||||
track_editor->set_root(root);
|
track_editor->set_root(root);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1824,6 +1834,10 @@ AnimationMixer *AnimationPlayerEditor::fetch_mixer_for_library() const {
|
||||||
return original_node;
|
return original_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Node *AnimationPlayerEditor::get_cached_root_node() const {
|
||||||
|
return Object::cast_to<Node>(ObjectDB::get_instance(cached_root_node_id));
|
||||||
|
}
|
||||||
|
|
||||||
bool AnimationPlayerEditor::_validate_tracks(const Ref<Animation> p_anim) {
|
bool AnimationPlayerEditor::_validate_tracks(const Ref<Animation> p_anim) {
|
||||||
bool is_valid = true;
|
bool is_valid = true;
|
||||||
if (!p_anim.is_valid()) {
|
if (!p_anim.is_valid()) {
|
||||||
|
|
|
@ -52,6 +52,7 @@ class AnimationPlayerEditor : public VBoxContainer {
|
||||||
AnimationPlayerEditorPlugin *plugin = nullptr;
|
AnimationPlayerEditorPlugin *plugin = nullptr;
|
||||||
AnimationMixer *original_node = nullptr; // For pinned mark in SceneTree.
|
AnimationMixer *original_node = nullptr; // For pinned mark in SceneTree.
|
||||||
AnimationPlayer *player = nullptr; // For AnimationPlayerEditor, could be dummy.
|
AnimationPlayer *player = nullptr; // For AnimationPlayerEditor, could be dummy.
|
||||||
|
ObjectID cached_root_node_id;
|
||||||
bool is_dummy = false;
|
bool is_dummy = false;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -251,6 +252,7 @@ public:
|
||||||
AnimationMixer *get_editing_node() const;
|
AnimationMixer *get_editing_node() const;
|
||||||
AnimationPlayer *get_player() const;
|
AnimationPlayer *get_player() const;
|
||||||
AnimationMixer *fetch_mixer_for_library() const;
|
AnimationMixer *fetch_mixer_for_library() const;
|
||||||
|
Node *get_cached_root_node() const;
|
||||||
|
|
||||||
static AnimationPlayerEditor *get_singleton() { return singleton; }
|
static AnimationPlayerEditor *get_singleton() { return singleton; }
|
||||||
|
|
||||||
|
|
|
@ -3999,6 +3999,8 @@ void CanvasItemEditor::_project_settings_changed() {
|
||||||
void CanvasItemEditor::_notification(int p_what) {
|
void CanvasItemEditor::_notification(int p_what) {
|
||||||
switch (p_what) {
|
switch (p_what) {
|
||||||
case NOTIFICATION_READY: {
|
case NOTIFICATION_READY: {
|
||||||
|
_update_lock_and_group_button();
|
||||||
|
|
||||||
EditorRunBar::get_singleton()->connect("play_pressed", callable_mp(this, &CanvasItemEditor::_update_override_camera_button).bind(true));
|
EditorRunBar::get_singleton()->connect("play_pressed", callable_mp(this, &CanvasItemEditor::_update_override_camera_button).bind(true));
|
||||||
EditorRunBar::get_singleton()->connect("stop_pressed", callable_mp(this, &CanvasItemEditor::_update_override_camera_button).bind(false));
|
EditorRunBar::get_singleton()->connect("stop_pressed", callable_mp(this, &CanvasItemEditor::_update_override_camera_button).bind(false));
|
||||||
ProjectSettings::get_singleton()->connect("settings_changed", callable_mp(this, &CanvasItemEditor::_project_settings_changed));
|
ProjectSettings::get_singleton()->connect("settings_changed", callable_mp(this, &CanvasItemEditor::_project_settings_changed));
|
||||||
|
@ -4108,7 +4110,8 @@ void CanvasItemEditor::_notification(int p_what) {
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NOTIFICATION_APPLICATION_FOCUS_OUT: {
|
case NOTIFICATION_APPLICATION_FOCUS_OUT:
|
||||||
|
case NOTIFICATION_WM_WINDOW_FOCUS_OUT: {
|
||||||
if (drag_type != DRAG_NONE) {
|
if (drag_type != DRAG_NONE) {
|
||||||
_reset_drag();
|
_reset_drag();
|
||||||
viewport->queue_redraw();
|
viewport->queue_redraw();
|
||||||
|
|
|
@ -81,6 +81,8 @@ void EditorNode3DGizmo::redraw() {
|
||||||
gizmo_plugin->redraw(this);
|
gizmo_plugin->redraw(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_update_bvh();
|
||||||
|
|
||||||
if (Node3DEditor::get_singleton()->is_current_selected_gizmo(this)) {
|
if (Node3DEditor::get_singleton()->is_current_selected_gizmo(this)) {
|
||||||
Node3DEditor::get_singleton()->update_transform_gizmo();
|
Node3DEditor::get_singleton()->update_transform_gizmo();
|
||||||
}
|
}
|
||||||
|
@ -244,6 +246,32 @@ void EditorNode3DGizmo::add_mesh(const Ref<Mesh> &p_mesh, const Ref<Material> &p
|
||||||
instances.push_back(ins);
|
instances.push_back(ins);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EditorNode3DGizmo::_update_bvh() {
|
||||||
|
ERR_FAIL_NULL(spatial_node);
|
||||||
|
|
||||||
|
Transform3D transform = spatial_node->get_global_transform();
|
||||||
|
|
||||||
|
float effective_icon_size = selectable_icon_size > 0.0f ? selectable_icon_size : 0.0f;
|
||||||
|
Vector3 icon_size_vector3 = Vector3(effective_icon_size, effective_icon_size, effective_icon_size);
|
||||||
|
AABB aabb(spatial_node->get_position() - icon_size_vector3 * 100.0f, icon_size_vector3 * 200.0f);
|
||||||
|
|
||||||
|
for (const Vector3 &segment_end : collision_segments) {
|
||||||
|
aabb.expand_to(transform.xform(segment_end));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (collision_mesh.is_valid()) {
|
||||||
|
for (const Face3 &face : collision_mesh->get_faces()) {
|
||||||
|
aabb.expand_to(transform.xform(face.vertex[0]));
|
||||||
|
aabb.expand_to(transform.xform(face.vertex[1]));
|
||||||
|
aabb.expand_to(transform.xform(face.vertex[2]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Node3DEditor::get_singleton()->update_gizmo_bvh_node(
|
||||||
|
bvh_node_id,
|
||||||
|
aabb);
|
||||||
|
}
|
||||||
|
|
||||||
void EditorNode3DGizmo::add_lines(const Vector<Vector3> &p_lines, const Ref<Material> &p_material, bool p_billboard, const Color &p_modulate) {
|
void EditorNode3DGizmo::add_lines(const Vector<Vector3> &p_lines, const Ref<Material> &p_material, bool p_billboard, const Color &p_modulate) {
|
||||||
add_vertices(p_lines, p_material, Mesh::PRIMITIVE_LINES, p_billboard, p_modulate);
|
add_vertices(p_lines, p_material, Mesh::PRIMITIVE_LINES, p_billboard, p_modulate);
|
||||||
}
|
}
|
||||||
|
@ -403,12 +431,13 @@ void EditorNode3DGizmo::add_handles(const Vector<Vector3> &p_handles, const Ref<
|
||||||
colors.resize(p_handles.size());
|
colors.resize(p_handles.size());
|
||||||
Color *w = colors.ptrw();
|
Color *w = colors.ptrw();
|
||||||
for (int i = 0; i < p_handles.size(); i++) {
|
for (int i = 0; i < p_handles.size(); i++) {
|
||||||
|
int id = p_ids.is_empty() ? i : p_ids[i];
|
||||||
|
|
||||||
Color col(1, 1, 1, 1);
|
Color col(1, 1, 1, 1);
|
||||||
if (is_handle_highlighted(i, p_secondary)) {
|
if (is_handle_highlighted(id, p_secondary)) {
|
||||||
col = Color(0, 0, 1, 0.9);
|
col = Color(0, 0, 1, 0.9);
|
||||||
}
|
}
|
||||||
|
|
||||||
int id = p_ids.is_empty() ? i : p_ids[i];
|
|
||||||
if (!is_current_hover_gizmo || current_hover_handle != id || p_secondary != current_hover_handle_secondary) {
|
if (!is_current_hover_gizmo || current_hover_handle != id || p_secondary != current_hover_handle_secondary) {
|
||||||
col.a = 0.8;
|
col.a = 0.8;
|
||||||
}
|
}
|
||||||
|
@ -765,6 +794,10 @@ void EditorNode3DGizmo::create() {
|
||||||
instances.write[i].create_instance(spatial_node, hidden);
|
instances.write[i].create_instance(spatial_node, hidden);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bvh_node_id = Node3DEditor::get_singleton()->insert_gizmo_bvh_node(
|
||||||
|
spatial_node,
|
||||||
|
AABB(spatial_node->get_position(), Vector3(0, 0, 0)));
|
||||||
|
|
||||||
transform();
|
transform();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -774,6 +807,8 @@ void EditorNode3DGizmo::transform() {
|
||||||
for (int i = 0; i < instances.size(); i++) {
|
for (int i = 0; i < instances.size(); i++) {
|
||||||
RS::get_singleton()->instance_set_transform(instances[i].instance, spatial_node->get_global_transform() * instances[i].xform);
|
RS::get_singleton()->instance_set_transform(instances[i].instance, spatial_node->get_global_transform() * instances[i].xform);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_update_bvh();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorNode3DGizmo::free() {
|
void EditorNode3DGizmo::free() {
|
||||||
|
@ -790,6 +825,9 @@ void EditorNode3DGizmo::free() {
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
|
|
||||||
|
Node3DEditor::get_singleton()->remove_gizmo_bvh_node(bvh_node_id);
|
||||||
|
bvh_node_id = DynamicBVH::ID();
|
||||||
|
|
||||||
valid = false;
|
valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#ifndef NODE_3D_EDITOR_GIZMOS_H
|
#ifndef NODE_3D_EDITOR_GIZMOS_H
|
||||||
#define NODE_3D_EDITOR_GIZMOS_H
|
#define NODE_3D_EDITOR_GIZMOS_H
|
||||||
|
|
||||||
|
#include "core/math/dynamic_bvh.h"
|
||||||
#include "core/templates/hash_map.h"
|
#include "core/templates/hash_map.h"
|
||||||
#include "core/templates/local_vector.h"
|
#include "core/templates/local_vector.h"
|
||||||
#include "scene/3d/camera_3d.h"
|
#include "scene/3d/camera_3d.h"
|
||||||
|
@ -72,8 +73,12 @@ class EditorNode3DGizmo : public Node3DGizmo {
|
||||||
Vector<Instance> instances;
|
Vector<Instance> instances;
|
||||||
Node3D *spatial_node = nullptr;
|
Node3D *spatial_node = nullptr;
|
||||||
|
|
||||||
|
DynamicBVH::ID bvh_node_id;
|
||||||
|
|
||||||
void _set_node_3d(Node *p_node) { set_node_3d(Object::cast_to<Node3D>(p_node)); }
|
void _set_node_3d(Node *p_node) { set_node_3d(Object::cast_to<Node3D>(p_node)); }
|
||||||
|
|
||||||
|
void _update_bvh();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
|
||||||
|
|
|
@ -770,7 +770,7 @@ void Node3DEditorViewport::_select_clicked(bool p_allow_locked) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p_allow_locked || !_is_node_locked(selected)) {
|
if (p_allow_locked || (selected != nullptr && !_is_node_locked(selected))) {
|
||||||
if (clicked_wants_append) {
|
if (clicked_wants_append) {
|
||||||
if (editor_selection->is_selected(selected)) {
|
if (editor_selection->is_selected(selected)) {
|
||||||
editor_selection->remove_node(selected);
|
editor_selection->remove_node(selected);
|
||||||
|
@ -800,7 +800,6 @@ ObjectID Node3DEditorViewport::_select_ray(const Point2 &p_pos) const {
|
||||||
RS::get_singleton()->sdfgi_set_debug_probe_select(pos, ray);
|
RS::get_singleton()->sdfgi_set_debug_probe_select(pos, ray);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector<ObjectID> instances = RenderingServer::get_singleton()->instances_cull_ray(pos, pos + ray * camera->get_far(), get_tree()->get_root()->get_world_3d()->get_scenario());
|
|
||||||
HashSet<Ref<EditorNode3DGizmo>> found_gizmos;
|
HashSet<Ref<EditorNode3DGizmo>> found_gizmos;
|
||||||
|
|
||||||
Node *edited_scene = get_tree()->get_edited_scene_root();
|
Node *edited_scene = get_tree()->get_edited_scene_root();
|
||||||
|
@ -808,9 +807,9 @@ ObjectID Node3DEditorViewport::_select_ray(const Point2 &p_pos) const {
|
||||||
Node *item = nullptr;
|
Node *item = nullptr;
|
||||||
float closest_dist = 1e20;
|
float closest_dist = 1e20;
|
||||||
|
|
||||||
for (int i = 0; i < instances.size(); i++) {
|
Vector<Node3D *> nodes_with_gizmos = Node3DEditor::get_singleton()->gizmo_bvh_ray_query(pos, pos + ray * camera->get_far());
|
||||||
Node3D *spat = Object::cast_to<Node3D>(ObjectDB::get_instance(instances[i]));
|
|
||||||
|
|
||||||
|
for (Node3D *spat : nodes_with_gizmos) {
|
||||||
if (!spat) {
|
if (!spat) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -863,12 +862,11 @@ void Node3DEditorViewport::_find_items_at_pos(const Point2 &p_pos, Vector<_RayRe
|
||||||
Vector3 ray = get_ray(p_pos);
|
Vector3 ray = get_ray(p_pos);
|
||||||
Vector3 pos = get_ray_pos(p_pos);
|
Vector3 pos = get_ray_pos(p_pos);
|
||||||
|
|
||||||
Vector<ObjectID> instances = RenderingServer::get_singleton()->instances_cull_ray(pos, pos + ray * camera->get_far(), get_tree()->get_root()->get_world_3d()->get_scenario());
|
Vector<Node3D *> nodes_with_gizmos = Node3DEditor::get_singleton()->gizmo_bvh_ray_query(pos, pos + ray * camera->get_far());
|
||||||
|
|
||||||
HashSet<Node3D *> found_nodes;
|
HashSet<Node3D *> found_nodes;
|
||||||
|
|
||||||
for (int i = 0; i < instances.size(); i++) {
|
for (Node3D *spat : nodes_with_gizmos) {
|
||||||
Node3D *spat = Object::cast_to<Node3D>(ObjectDB::get_instance(instances[i]));
|
|
||||||
|
|
||||||
if (!spat) {
|
if (!spat) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1046,7 +1044,7 @@ void Node3DEditorViewport::_select_region() {
|
||||||
_clear_selected();
|
_clear_selected();
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector<ObjectID> instances = RenderingServer::get_singleton()->instances_cull_convex(frustum, get_tree()->get_root()->get_world_3d()->get_scenario());
|
Vector<Node3D *> nodes_with_gizmos = Node3DEditor::get_singleton()->gizmo_bvh_frustum_query(frustum);
|
||||||
HashSet<Node3D *> found_nodes;
|
HashSet<Node3D *> found_nodes;
|
||||||
Vector<Node *> selected;
|
Vector<Node *> selected;
|
||||||
|
|
||||||
|
@ -1055,8 +1053,7 @@ void Node3DEditorViewport::_select_region() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < instances.size(); i++) {
|
for (Node3D *sp : nodes_with_gizmos) {
|
||||||
Node3D *sp = Object::cast_to<Node3D>(ObjectDB::get_instance(instances[i]));
|
|
||||||
if (!sp || _is_node_locked(sp)) {
|
if (!sp || _is_node_locked(sp)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1064,21 +1061,23 @@ void Node3DEditorViewport::_select_region() {
|
||||||
if (found_nodes.has(sp)) {
|
if (found_nodes.has(sp)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
found_nodes.insert(sp);
|
found_nodes.insert(sp);
|
||||||
|
|
||||||
Node *node = Object::cast_to<Node>(sp);
|
Node *node = Object::cast_to<Node>(sp);
|
||||||
if (node != edited_scene) {
|
|
||||||
node = edited_scene->get_deepest_editable_node(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prevent selection of nodes not owned by the edited scene.
|
// Selection requires that the node is the edited scene or its descendant, and has an owner.
|
||||||
while (node && node != edited_scene->get_parent()) {
|
if (node != edited_scene) {
|
||||||
Node *node_owner = node->get_owner();
|
if (!node->get_owner() || !edited_scene->is_ancestor_of(node)) {
|
||||||
if (node_owner == edited_scene || node == edited_scene || (node_owner != nullptr && edited_scene->is_editable_instance(node_owner))) {
|
continue;
|
||||||
break;
|
}
|
||||||
|
node = edited_scene->get_deepest_editable_node(node);
|
||||||
|
while (node != edited_scene) {
|
||||||
|
Node *node_owner = node->get_owner();
|
||||||
|
if (node_owner == edited_scene || (node_owner != nullptr && edited_scene->is_editable_instance(node_owner))) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
node = node->get_parent();
|
||||||
}
|
}
|
||||||
node = node->get_parent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replace the node by the group if grouped
|
// Replace the node by the group if grouped
|
||||||
|
@ -1952,7 +1951,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_edit.mode != TRANSFORM_NONE) {
|
if (!_edit.instant && _edit.mode != TRANSFORM_NONE) {
|
||||||
Node3D *selected = spatial_editor->get_single_selected_node();
|
Node3D *selected = spatial_editor->get_single_selected_node();
|
||||||
Node3DEditorSelectedItem *se = selected ? editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(selected) : nullptr;
|
Node3DEditorSelectedItem *se = selected ? editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(selected) : nullptr;
|
||||||
|
|
||||||
|
@ -2252,6 +2251,11 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_edit.mode == TRANSFORM_NONE) {
|
if (_edit.mode == TRANSFORM_NONE) {
|
||||||
|
if (_edit.gizmo.is_null() && is_freelook_active() && k->get_keycode() == Key::ESCAPE) {
|
||||||
|
set_freelook_active(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (_edit.gizmo.is_valid() && (k->get_keycode() == Key::ESCAPE || k->get_keycode() == Key::BACKSPACE)) {
|
if (_edit.gizmo.is_valid() && (k->get_keycode() == Key::ESCAPE || k->get_keycode() == Key::BACKSPACE)) {
|
||||||
// Restore.
|
// Restore.
|
||||||
_edit.gizmo->commit_handle(_edit.gizmo_handle, _edit.gizmo_handle_secondary, _edit.gizmo_initial_value, true);
|
_edit.gizmo->commit_handle(_edit.gizmo_handle, _edit.gizmo_handle_secondary, _edit.gizmo_initial_value, true);
|
||||||
|
@ -2390,15 +2394,30 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
|
||||||
if (ED_IS_SHORTCUT("spatial_editor/cancel_transform", p_event) && _edit.mode != TRANSFORM_NONE) {
|
if (ED_IS_SHORTCUT("spatial_editor/cancel_transform", p_event) && _edit.mode != TRANSFORM_NONE) {
|
||||||
cancel_transform();
|
cancel_transform();
|
||||||
}
|
}
|
||||||
if (!is_freelook_active()) {
|
if (!is_freelook_active() && !k->is_echo()) {
|
||||||
if (ED_IS_SHORTCUT("spatial_editor/instant_translate", p_event)) {
|
if (ED_IS_SHORTCUT("spatial_editor/instant_translate", p_event) && _edit.mode != TRANSFORM_TRANSLATE) {
|
||||||
begin_transform(TRANSFORM_TRANSLATE, true);
|
if (_edit.mode == TRANSFORM_NONE) {
|
||||||
|
begin_transform(TRANSFORM_TRANSLATE, true);
|
||||||
|
} else if (_edit.instant) {
|
||||||
|
commit_transform();
|
||||||
|
begin_transform(TRANSFORM_TRANSLATE, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (ED_IS_SHORTCUT("spatial_editor/instant_rotate", p_event)) {
|
if (ED_IS_SHORTCUT("spatial_editor/instant_rotate", p_event) && _edit.mode != TRANSFORM_ROTATE) {
|
||||||
begin_transform(TRANSFORM_ROTATE, true);
|
if (_edit.mode == TRANSFORM_NONE) {
|
||||||
|
begin_transform(TRANSFORM_ROTATE, true);
|
||||||
|
} else if (_edit.instant) {
|
||||||
|
commit_transform();
|
||||||
|
begin_transform(TRANSFORM_ROTATE, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (ED_IS_SHORTCUT("spatial_editor/instant_scale", p_event)) {
|
if (ED_IS_SHORTCUT("spatial_editor/instant_scale", p_event) && _edit.mode != TRANSFORM_SCALE) {
|
||||||
begin_transform(TRANSFORM_SCALE, true);
|
if (_edit.mode == TRANSFORM_NONE) {
|
||||||
|
begin_transform(TRANSFORM_SCALE, true);
|
||||||
|
} else if (_edit.instant) {
|
||||||
|
commit_transform();
|
||||||
|
begin_transform(TRANSFORM_SCALE, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3030,8 +3049,11 @@ void Node3DEditorViewport::_notification(int p_what) {
|
||||||
update_preview_node = false;
|
update_preview_node = false;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case NOTIFICATION_APPLICATION_FOCUS_OUT:
|
||||||
case NOTIFICATION_WM_WINDOW_FOCUS_OUT: {
|
case NOTIFICATION_WM_WINDOW_FOCUS_OUT: {
|
||||||
set_freelook_active(false);
|
set_freelook_active(false);
|
||||||
|
cursor.region_select = false;
|
||||||
|
surface->queue_redraw();
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NOTIFICATION_ENTER_TREE: {
|
case NOTIFICATION_ENTER_TREE: {
|
||||||
|
@ -3107,6 +3129,7 @@ void Node3DEditorViewport::_notification(int p_what) {
|
||||||
case NOTIFICATION_DRAG_END: {
|
case NOTIFICATION_DRAG_END: {
|
||||||
// Clear preview material when dropped outside applicable object.
|
// Clear preview material when dropped outside applicable object.
|
||||||
if (spatial_editor->get_preview_material().is_valid() && !is_drag_successful()) {
|
if (spatial_editor->get_preview_material().is_valid() && !is_drag_successful()) {
|
||||||
|
_reset_preview_material();
|
||||||
_remove_preview_material();
|
_remove_preview_material();
|
||||||
} else {
|
} else {
|
||||||
_remove_preview_node();
|
_remove_preview_node();
|
||||||
|
@ -4001,6 +4024,14 @@ void Node3DEditorViewport::set_state(const Dictionary &p_state) {
|
||||||
_menu_option(VIEW_GIZMOS);
|
_menu_option(VIEW_GIZMOS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (p_state.has("grid")) {
|
||||||
|
bool grid = p_state["grid"];
|
||||||
|
|
||||||
|
int idx = view_menu->get_popup()->get_item_index(VIEW_GRID);
|
||||||
|
if (view_menu->get_popup()->is_item_checked(idx) != grid) {
|
||||||
|
_menu_option(VIEW_GRID);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (p_state.has("information")) {
|
if (p_state.has("information")) {
|
||||||
bool information = p_state["information"];
|
bool information = p_state["information"];
|
||||||
|
|
||||||
|
@ -4079,6 +4110,7 @@ Dictionary Node3DEditorViewport::get_state() const {
|
||||||
d["listener"] = viewport->is_audio_listener_3d();
|
d["listener"] = viewport->is_audio_listener_3d();
|
||||||
d["doppler"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUDIO_DOPPLER));
|
d["doppler"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUDIO_DOPPLER));
|
||||||
d["gizmos"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_GIZMOS));
|
d["gizmos"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_GIZMOS));
|
||||||
|
d["grid"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_GRID));
|
||||||
d["information"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_INFORMATION));
|
d["information"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_INFORMATION));
|
||||||
d["frame_time"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_FRAME_TIME));
|
d["frame_time"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_FRAME_TIME));
|
||||||
d["half_res"] = subviewport_container->get_stretch_shrink() > 1;
|
d["half_res"] = subviewport_container->get_stretch_shrink() > 1;
|
||||||
|
@ -5001,14 +5033,24 @@ void Node3DEditorViewport::update_transform(bool p_shift) {
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case TRANSFORM_ROTATE: {
|
case TRANSFORM_ROTATE: {
|
||||||
Plane plane = Plane(_get_camera_normal(), _edit.center);
|
Plane plane;
|
||||||
|
if (camera->get_projection() == Camera3D::PROJECTION_PERSPECTIVE) {
|
||||||
|
Vector3 cam_to_obj = _edit.center - _get_camera_position();
|
||||||
|
if (!cam_to_obj.is_zero_approx()) {
|
||||||
|
plane = Plane(cam_to_obj.normalized(), _edit.center);
|
||||||
|
} else {
|
||||||
|
plane = Plane(_get_camera_normal(), _edit.center);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
plane = Plane(_get_camera_normal(), _edit.center);
|
||||||
|
}
|
||||||
|
|
||||||
Vector3 local_axis;
|
Vector3 local_axis;
|
||||||
Vector3 global_axis;
|
Vector3 global_axis;
|
||||||
switch (_edit.plane) {
|
switch (_edit.plane) {
|
||||||
case TRANSFORM_VIEW:
|
case TRANSFORM_VIEW:
|
||||||
// local_axis unused
|
// local_axis unused
|
||||||
global_axis = _get_camera_normal();
|
global_axis = plane.normal;
|
||||||
break;
|
break;
|
||||||
case TRANSFORM_X_AXIS:
|
case TRANSFORM_X_AXIS:
|
||||||
local_axis = Vector3(1, 0, 0);
|
local_axis = Vector3(1, 0, 0);
|
||||||
|
@ -5039,7 +5081,7 @@ void Node3DEditorViewport::update_transform(bool p_shift) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const float orthogonal_threshold = Math::cos(Math::deg_to_rad(87.0f));
|
static const float orthogonal_threshold = Math::cos(Math::deg_to_rad(85.0f));
|
||||||
bool axis_is_orthogonal = ABS(plane.normal.dot(global_axis)) < orthogonal_threshold;
|
bool axis_is_orthogonal = ABS(plane.normal.dot(global_axis)) < orthogonal_threshold;
|
||||||
|
|
||||||
double angle = 0.0f;
|
double angle = 0.0f;
|
||||||
|
@ -7746,6 +7788,9 @@ void Node3DEditor::_sun_environ_settings_pressed() {
|
||||||
sun_environ_popup->set_position(pos - Vector2(sun_environ_popup->get_contents_minimum_size().width / 2, 0));
|
sun_environ_popup->set_position(pos - Vector2(sun_environ_popup->get_contents_minimum_size().width / 2, 0));
|
||||||
sun_environ_popup->reset_size();
|
sun_environ_popup->reset_size();
|
||||||
sun_environ_popup->popup();
|
sun_environ_popup->popup();
|
||||||
|
// Grabbing the focus is required for Shift modifier checking to be functional
|
||||||
|
// (when the Add sun/environment buttons are pressed).
|
||||||
|
sun_environ_popup->grab_focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Node3DEditor::_add_sun_to_scene(bool p_already_added_environment) {
|
void Node3DEditor::_add_sun_to_scene(bool p_already_added_environment) {
|
||||||
|
@ -9208,6 +9253,49 @@ void Node3DEditor::remove_gizmo_plugin(Ref<EditorNode3DGizmoPlugin> p_plugin) {
|
||||||
_update_gizmos_menu();
|
_update_gizmos_menu();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DynamicBVH::ID Node3DEditor::insert_gizmo_bvh_node(Node3D *p_node, const AABB &p_aabb) {
|
||||||
|
return gizmo_bvh.insert(p_aabb, p_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Node3DEditor::update_gizmo_bvh_node(DynamicBVH::ID p_id, const AABB &p_aabb) {
|
||||||
|
gizmo_bvh.update(p_id, p_aabb);
|
||||||
|
gizmo_bvh.optimize_incremental(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Node3DEditor::remove_gizmo_bvh_node(DynamicBVH::ID p_id) {
|
||||||
|
gizmo_bvh.remove(p_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector<Node3D *> Node3DEditor::gizmo_bvh_ray_query(const Vector3 &p_ray_start, const Vector3 &p_ray_end) {
|
||||||
|
struct Result {
|
||||||
|
Vector<Node3D *> nodes;
|
||||||
|
bool operator()(void *p_data) {
|
||||||
|
nodes.append((Node3D *)p_data);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} result;
|
||||||
|
|
||||||
|
gizmo_bvh.ray_query(p_ray_start, p_ray_end, result);
|
||||||
|
|
||||||
|
return result.nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector<Node3D *> Node3DEditor::gizmo_bvh_frustum_query(const Vector<Plane> &p_frustum) {
|
||||||
|
Vector<Vector3> points = Geometry3D::compute_convex_mesh_points(&p_frustum[0], p_frustum.size());
|
||||||
|
|
||||||
|
struct Result {
|
||||||
|
Vector<Node3D *> nodes;
|
||||||
|
bool operator()(void *p_data) {
|
||||||
|
nodes.append((Node3D *)p_data);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} result;
|
||||||
|
|
||||||
|
gizmo_bvh.convex_query(p_frustum.ptr(), p_frustum.size(), points.ptr(), points.size(), result);
|
||||||
|
|
||||||
|
return result.nodes;
|
||||||
|
}
|
||||||
|
|
||||||
Node3DEditorPlugin::Node3DEditorPlugin() {
|
Node3DEditorPlugin::Node3DEditorPlugin() {
|
||||||
spatial_editor = memnew(Node3DEditor);
|
spatial_editor = memnew(Node3DEditor);
|
||||||
spatial_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
spatial_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#ifndef NODE_3D_EDITOR_PLUGIN_H
|
#ifndef NODE_3D_EDITOR_PLUGIN_H
|
||||||
#define NODE_3D_EDITOR_PLUGIN_H
|
#define NODE_3D_EDITOR_PLUGIN_H
|
||||||
|
|
||||||
|
#include "core/math/dynamic_bvh.h"
|
||||||
#include "editor/plugins/editor_plugin.h"
|
#include "editor/plugins/editor_plugin.h"
|
||||||
#include "editor/plugins/node_3d_editor_gizmos.h"
|
#include "editor/plugins/node_3d_editor_gizmos.h"
|
||||||
#include "editor/themes/editor_scale.h"
|
#include "editor/themes/editor_scale.h"
|
||||||
|
@ -629,6 +630,8 @@ private:
|
||||||
int current_hover_gizmo_handle;
|
int current_hover_gizmo_handle;
|
||||||
bool current_hover_gizmo_handle_secondary;
|
bool current_hover_gizmo_handle_secondary;
|
||||||
|
|
||||||
|
DynamicBVH gizmo_bvh;
|
||||||
|
|
||||||
real_t snap_translate_value;
|
real_t snap_translate_value;
|
||||||
real_t snap_rotate_value;
|
real_t snap_rotate_value;
|
||||||
real_t snap_scale_value;
|
real_t snap_scale_value;
|
||||||
|
@ -933,6 +936,12 @@ public:
|
||||||
void add_gizmo_plugin(Ref<EditorNode3DGizmoPlugin> p_plugin);
|
void add_gizmo_plugin(Ref<EditorNode3DGizmoPlugin> p_plugin);
|
||||||
void remove_gizmo_plugin(Ref<EditorNode3DGizmoPlugin> p_plugin);
|
void remove_gizmo_plugin(Ref<EditorNode3DGizmoPlugin> p_plugin);
|
||||||
|
|
||||||
|
DynamicBVH::ID insert_gizmo_bvh_node(Node3D *p_node, const AABB &p_aabb);
|
||||||
|
void update_gizmo_bvh_node(DynamicBVH::ID p_id, const AABB &p_aabb);
|
||||||
|
void remove_gizmo_bvh_node(DynamicBVH::ID p_id);
|
||||||
|
Vector<Node3D *> gizmo_bvh_ray_query(const Vector3 &p_ray_start, const Vector3 &p_ray_end);
|
||||||
|
Vector<Node3D *> gizmo_bvh_frustum_query(const Vector<Plane> &p_frustum);
|
||||||
|
|
||||||
void edit(Node3D *p_spatial);
|
void edit(Node3D *p_spatial);
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
|
|
|
@ -83,9 +83,8 @@ Error PackedSceneEditorTranslationParserPlugin::parse_file(const String &p_path,
|
||||||
|
|
||||||
int idx_last = atr_owners.size() - 1;
|
int idx_last = atr_owners.size() - 1;
|
||||||
if (idx_last > 0 && !parent_path.begins_with(atr_owners[idx_last].first)) {
|
if (idx_last > 0 && !parent_path.begins_with(atr_owners[idx_last].first)) {
|
||||||
// Switch to the previous auto translation owner this was nested in, if that was the case.
|
// Exit from the current owner nesting into the previous one.
|
||||||
atr_owners.remove_at(idx_last);
|
atr_owners.remove_at(idx_last);
|
||||||
idx_last -= 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (property == "auto_translate_mode") {
|
if (property == "auto_translate_mode") {
|
||||||
|
@ -106,7 +105,7 @@ Error PackedSceneEditorTranslationParserPlugin::parse_file(const String &p_path,
|
||||||
// If `auto_translate_mode` wasn't found, that means it is set to its default value (`AUTO_TRANSLATE_MODE_INHERIT`).
|
// If `auto_translate_mode` wasn't found, that means it is set to its default value (`AUTO_TRANSLATE_MODE_INHERIT`).
|
||||||
if (!auto_translate_mode_found) {
|
if (!auto_translate_mode_found) {
|
||||||
int idx_last = atr_owners.size() - 1;
|
int idx_last = atr_owners.size() - 1;
|
||||||
if (idx_last > 0 && atr_owners[idx_last].first == parent_path) {
|
if (idx_last > 0 && parent_path.begins_with(atr_owners[idx_last].first)) {
|
||||||
auto_translating = atr_owners[idx_last].second;
|
auto_translating = atr_owners[idx_last].second;
|
||||||
} else {
|
} else {
|
||||||
atr_owners.push_back(Pair(state->get_node_path(i), true));
|
atr_owners.push_back(Pair(state->get_node_path(i), true));
|
||||||
|
|
|
@ -197,12 +197,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
|
||||||
const Vector2 new_point = xform.affine_inverse().xform(gpoint2);
|
const Vector2 new_point = xform.affine_inverse().xform(gpoint2);
|
||||||
curve->add_point(new_point, Vector2(0, 0), Vector2(0, 0), insertion_point + 1);
|
curve->add_point(new_point, Vector2(0, 0), Vector2(0, 0), insertion_point + 1);
|
||||||
|
|
||||||
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
action = ACTION_MOVING_NEW_POINT_FROM_SPLIT;
|
||||||
undo_redo->create_action(TTR("Split Curve"));
|
|
||||||
undo_redo->add_do_method(curve.ptr(), "add_point", new_point, Vector2(0, 0), Vector2(0, 0), insertion_point + 1);
|
|
||||||
undo_redo->add_undo_method(curve.ptr(), "remove_point", insertion_point + 1);
|
|
||||||
|
|
||||||
action = ACTION_MOVING_NEW_POINT;
|
|
||||||
action_point = insertion_point + 1;
|
action_point = insertion_point + 1;
|
||||||
moving_from = curve->get_point_position(action_point);
|
moving_from = curve->get_point_position(action_point);
|
||||||
moving_screen_from = gpoint2;
|
moving_screen_from = gpoint2;
|
||||||
|
@ -245,6 +240,16 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
|
||||||
undo_redo->commit_action(false);
|
undo_redo->commit_action(false);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case ACTION_MOVING_NEW_POINT_FROM_SPLIT: {
|
||||||
|
undo_redo->create_action(TTR("Split Curve"));
|
||||||
|
undo_redo->add_do_method(curve.ptr(), "add_point", Vector2(), Vector2(), Vector2(), action_point);
|
||||||
|
undo_redo->add_do_method(curve.ptr(), "set_point_position", action_point, cpoint);
|
||||||
|
undo_redo->add_undo_method(curve.ptr(), "remove_point", action_point);
|
||||||
|
undo_redo->add_do_method(canvas_item_editor, "update_viewport");
|
||||||
|
undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
|
||||||
|
undo_redo->commit_action(false);
|
||||||
|
} break;
|
||||||
|
|
||||||
case ACTION_MOVING_IN: {
|
case ACTION_MOVING_IN: {
|
||||||
if (original_mouse_pos != gpoint) {
|
if (original_mouse_pos != gpoint) {
|
||||||
undo_redo->create_action(TTR("Move In-Control in Curve"));
|
undo_redo->create_action(TTR("Move In-Control in Curve"));
|
||||||
|
@ -350,7 +355,8 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ACTION_MOVING_POINT:
|
case ACTION_MOVING_POINT:
|
||||||
case ACTION_MOVING_NEW_POINT: {
|
case ACTION_MOVING_NEW_POINT:
|
||||||
|
case ACTION_MOVING_NEW_POINT_FROM_SPLIT: {
|
||||||
curve->set_point_position(action_point, cpoint);
|
curve->set_point_position(action_point, cpoint);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
@ -573,6 +579,10 @@ void Path2DEditor::_cancel_current_action() {
|
||||||
curve->remove_point(curve->get_point_count() - 1);
|
curve->remove_point(curve->get_point_count() - 1);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case ACTION_MOVING_NEW_POINT_FROM_SPLIT: {
|
||||||
|
curve->remove_point(action_point);
|
||||||
|
} break;
|
||||||
|
|
||||||
case ACTION_MOVING_IN: {
|
case ACTION_MOVING_IN: {
|
||||||
curve->set_point_in(action_point, moving_from);
|
curve->set_point_in(action_point, moving_from);
|
||||||
curve->set_point_out(action_point, mirror_handle_length ? -moving_from : (-moving_from.normalized() * orig_out_length));
|
curve->set_point_out(action_point, mirror_handle_length ? -moving_from : (-moving_from.normalized() * orig_out_length));
|
||||||
|
|
|
@ -81,6 +81,7 @@ class Path2DEditor : public HBoxContainer {
|
||||||
ACTION_NONE,
|
ACTION_NONE,
|
||||||
ACTION_MOVING_POINT,
|
ACTION_MOVING_POINT,
|
||||||
ACTION_MOVING_NEW_POINT,
|
ACTION_MOVING_NEW_POINT,
|
||||||
|
ACTION_MOVING_NEW_POINT_FROM_SPLIT,
|
||||||
ACTION_MOVING_IN,
|
ACTION_MOVING_IN,
|
||||||
ACTION_MOVING_OUT,
|
ACTION_MOVING_OUT,
|
||||||
};
|
};
|
||||||
|
|
|
@ -181,7 +181,7 @@ void Polygon2DEditor::_sync_bones() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (weights.size() == 0) { //create them
|
if (weights.size() == 0) { //create them
|
||||||
weights.resize(node->get_polygon().size());
|
weights.resize(wc);
|
||||||
float *w = weights.ptrw();
|
float *w = weights.ptrw();
|
||||||
for (int j = 0; j < wc; j++) {
|
for (int j = 0; j < wc; j++) {
|
||||||
w[j] = 0.0;
|
w[j] = 0.0;
|
||||||
|
@ -850,8 +850,8 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
|
||||||
if (mm.is_valid()) {
|
if (mm.is_valid()) {
|
||||||
if (uv_drag) {
|
if (uv_drag) {
|
||||||
Vector2 uv_drag_to = mm->get_position();
|
Vector2 uv_drag_to = mm->get_position();
|
||||||
uv_drag_to = snap_point(uv_drag_to); // FIXME: Only works correctly with 'UV_MODE_EDIT_POINT', it's imprecise with the rest.
|
uv_drag_to = snap_point(uv_drag_to);
|
||||||
Vector2 drag = mtx.affine_inverse().xform(uv_drag_to) - mtx.affine_inverse().xform(uv_drag_from);
|
Vector2 drag = mtx.affine_inverse().basis_xform(uv_drag_to - uv_drag_from);
|
||||||
|
|
||||||
switch (uv_move_current) {
|
switch (uv_move_current) {
|
||||||
case UV_MODE_CREATE: {
|
case UV_MODE_CREATE: {
|
||||||
|
@ -1166,12 +1166,8 @@ void Polygon2DEditor::_uv_draw() {
|
||||||
poly_line_color.a *= 0.25;
|
poly_line_color.a *= 0.25;
|
||||||
}
|
}
|
||||||
Color polygon_line_color = Color(0.5, 0.5, 0.9);
|
Color polygon_line_color = Color(0.5, 0.5, 0.9);
|
||||||
Vector<Color> polygon_fill_color;
|
Color polygon_fill_color = polygon_line_color;
|
||||||
{
|
polygon_fill_color.a *= 0.5;
|
||||||
Color pf = polygon_line_color;
|
|
||||||
pf.a *= 0.5;
|
|
||||||
polygon_fill_color.push_back(pf);
|
|
||||||
}
|
|
||||||
Color prev_color = Color(0.5, 0.5, 0.5);
|
Color prev_color = Color(0.5, 0.5, 0.5);
|
||||||
|
|
||||||
int uv_draw_max = uvs.size();
|
int uv_draw_max = uvs.size();
|
||||||
|
@ -1216,7 +1212,7 @@ void Polygon2DEditor::_uv_draw() {
|
||||||
uv_edit_draw->draw_line(mtx.xform(uvs[idx]), mtx.xform(uvs[idx_next]), polygon_line_color, Math::round(EDSCALE));
|
uv_edit_draw->draw_line(mtx.xform(uvs[idx]), mtx.xform(uvs[idx_next]), polygon_line_color, Math::round(EDSCALE));
|
||||||
}
|
}
|
||||||
if (points.size() >= 3) {
|
if (points.size() >= 3) {
|
||||||
uv_edit_draw->draw_polygon(polypoints, polygon_fill_color);
|
uv_edit_draw->draw_colored_polygon(polypoints, polygon_fill_color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1309,8 +1305,8 @@ void Polygon2DEditor::_bind_methods() {
|
||||||
|
|
||||||
Vector2 Polygon2DEditor::snap_point(Vector2 p_target) const {
|
Vector2 Polygon2DEditor::snap_point(Vector2 p_target) const {
|
||||||
if (use_snap) {
|
if (use_snap) {
|
||||||
p_target.x = Math::snap_scalar(snap_offset.x * uv_draw_zoom - uv_draw_ofs.x, snap_step.x * uv_draw_zoom, p_target.x);
|
p_target.x = Math::snap_scalar((snap_offset.x - uv_draw_ofs.x) * uv_draw_zoom, snap_step.x * uv_draw_zoom, p_target.x);
|
||||||
p_target.y = Math::snap_scalar(snap_offset.y * uv_draw_zoom - uv_draw_ofs.y, snap_step.y * uv_draw_zoom, p_target.y);
|
p_target.y = Math::snap_scalar((snap_offset.y - uv_draw_ofs.y) * uv_draw_zoom, snap_step.y * uv_draw_zoom, p_target.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
return p_target;
|
return p_target;
|
||||||
|
@ -1486,7 +1482,7 @@ Polygon2DEditor::Polygon2DEditor() {
|
||||||
|
|
||||||
grid_settings = memnew(AcceptDialog);
|
grid_settings = memnew(AcceptDialog);
|
||||||
grid_settings->set_title(TTR("Configure Grid:"));
|
grid_settings->set_title(TTR("Configure Grid:"));
|
||||||
add_child(grid_settings);
|
uv_edit->add_child(grid_settings);
|
||||||
VBoxContainer *grid_settings_vb = memnew(VBoxContainer);
|
VBoxContainer *grid_settings_vb = memnew(VBoxContainer);
|
||||||
grid_settings->add_child(grid_settings_vb);
|
grid_settings->add_child(grid_settings_vb);
|
||||||
|
|
||||||
|
|
|
@ -2711,9 +2711,11 @@ void ScriptEditor::apply_scripts() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptEditor::reload_scripts(bool p_refresh_only) {
|
void ScriptEditor::reload_scripts(bool p_refresh_only) {
|
||||||
if (external_editor_active) {
|
// Call deferred to make sure it runs on the main thread.
|
||||||
return;
|
callable_mp(this, &ScriptEditor::_reload_scripts).call_deferred(p_refresh_only);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScriptEditor::_reload_scripts(bool p_refresh_only) {
|
||||||
for (int i = 0; i < tab_container->get_tab_count(); i++) {
|
for (int i = 0; i < tab_container->get_tab_count(); i++) {
|
||||||
ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
|
ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
|
||||||
if (!se) {
|
if (!se) {
|
||||||
|
|
|
@ -436,6 +436,7 @@ class ScriptEditor : public PanelContainer {
|
||||||
void _file_removed(const String &p_file);
|
void _file_removed(const String &p_file);
|
||||||
void _autosave_scripts();
|
void _autosave_scripts();
|
||||||
void _update_autosave_timer();
|
void _update_autosave_timer();
|
||||||
|
void _reload_scripts(bool p_refresh_only = false);
|
||||||
|
|
||||||
void _update_members_overview_visibility();
|
void _update_members_overview_visibility();
|
||||||
void _update_members_overview();
|
void _update_members_overview();
|
||||||
|
|
|
@ -372,7 +372,7 @@ void TileAtlasView::_draw_base_tiles_shape_grid() {
|
||||||
for (int i = 0; i < tile_set_atlas_source->get_tiles_count(); i++) {
|
for (int i = 0; i < tile_set_atlas_source->get_tiles_count(); i++) {
|
||||||
Vector2i tile_id = tile_set_atlas_source->get_tile_id(i);
|
Vector2i tile_id = tile_set_atlas_source->get_tile_id(i);
|
||||||
Vector2 in_tile_base_offset = tile_set_atlas_source->get_tile_data(tile_id, 0)->get_texture_origin();
|
Vector2 in_tile_base_offset = tile_set_atlas_source->get_tile_data(tile_id, 0)->get_texture_origin();
|
||||||
if (tile_set_atlas_source->is_position_in_tile_texture_region(tile_id, 0, -tile_shape_size / 2) && tile_set_atlas_source->is_position_in_tile_texture_region(tile_id, 0, tile_shape_size / 2 - Vector2(1, 1))) {
|
if (tile_set_atlas_source->is_rect_in_tile_texture_region(tile_id, 0, Rect2(Vector2(-tile_shape_size) / 2, tile_shape_size))) {
|
||||||
for (int frame = 0; frame < tile_set_atlas_source->get_tile_animation_frames_count(tile_id); frame++) {
|
for (int frame = 0; frame < tile_set_atlas_source->get_tile_animation_frames_count(tile_id); frame++) {
|
||||||
Color color = grid_color;
|
Color color = grid_color;
|
||||||
if (frame > 0) {
|
if (frame > 0) {
|
||||||
|
|
|
@ -165,10 +165,14 @@ void GenericTilePolygonEditor::_base_control_draw() {
|
||||||
base_control->draw_set_transform_matrix(xform);
|
base_control->draw_set_transform_matrix(xform);
|
||||||
|
|
||||||
// Draw fill rect under texture region.
|
// Draw fill rect under texture region.
|
||||||
Rect2 texture_rect(-background_region.size / 2, background_region.size);
|
Rect2 texture_rect(Vector2(), background_region.size);
|
||||||
if (tile_data) {
|
if (tile_data) {
|
||||||
texture_rect.position -= tile_data->get_texture_origin();
|
texture_rect.position -= tile_data->get_texture_origin();
|
||||||
|
if (tile_data->get_transpose()) {
|
||||||
|
texture_rect.size = Size2(texture_rect.size.y, texture_rect.size.x);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
texture_rect.position -= texture_rect.size / 2; // Half-size offset must be applied after transposing.
|
||||||
base_control->draw_rect(texture_rect, Color(1, 1, 1, 0.3));
|
base_control->draw_rect(texture_rect, Color(1, 1, 1, 0.3));
|
||||||
|
|
||||||
// Draw the background.
|
// Draw the background.
|
||||||
|
@ -180,18 +184,14 @@ void GenericTilePolygonEditor::_base_control_draw() {
|
||||||
if (tile_data->get_flip_v()) {
|
if (tile_data->get_flip_v()) {
|
||||||
region_size.y = -region_size.y;
|
region_size.y = -region_size.y;
|
||||||
}
|
}
|
||||||
base_control->draw_texture_rect_region(background_atlas_source->get_texture(), Rect2(-background_region.size / 2 - tile_data->get_texture_origin(), region_size), background_region, tile_data->get_modulate(), tile_data->get_transpose());
|
// Destination rect position must account for transposing, size must not.
|
||||||
|
base_control->draw_texture_rect_region(background_atlas_source->get_texture(), Rect2(texture_rect.position, region_size), background_region, tile_data->get_modulate(), tile_data->get_transpose());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute and draw the grid area.
|
// Compute and draw the grid area.
|
||||||
Rect2 grid_area = Rect2(-base_tile_size / 2, base_tile_size);
|
Rect2 grid_area = Rect2(-base_tile_size / 2, base_tile_size);
|
||||||
if (tile_data) {
|
grid_area.expand_to(texture_rect.position);
|
||||||
grid_area.expand_to(-background_region.get_size() / 2 - tile_data->get_texture_origin());
|
grid_area.expand_to(texture_rect.get_end());
|
||||||
grid_area.expand_to(background_region.get_size() / 2 - tile_data->get_texture_origin());
|
|
||||||
} else {
|
|
||||||
grid_area.expand_to(-background_region.get_size() / 2);
|
|
||||||
grid_area.expand_to(background_region.get_size() / 2);
|
|
||||||
}
|
|
||||||
base_control->draw_rect(grid_area, Color(1, 1, 1, 0.3), false);
|
base_control->draw_rect(grid_area, Color(1, 1, 1, 0.3), false);
|
||||||
|
|
||||||
// Draw grid.
|
// Draw grid.
|
||||||
|
@ -1385,10 +1385,8 @@ void TileDataTextureOriginEditor::draw_over_tile(CanvasItem *p_canvas_item, Tran
|
||||||
|
|
||||||
TileSetSource *source = *(tile_set->get_source(p_cell.source_id));
|
TileSetSource *source = *(tile_set->get_source(p_cell.source_id));
|
||||||
TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
|
TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
|
||||||
if (atlas_source->is_position_in_tile_texture_region(p_cell.get_atlas_coords(), p_cell.alternative_tile, -tile_set_tile_size / 2) && atlas_source->is_position_in_tile_texture_region(p_cell.get_atlas_coords(), p_cell.alternative_tile, tile_set_tile_size / 2 - Vector2(1, 1))) {
|
if (atlas_source->is_rect_in_tile_texture_region(p_cell.get_atlas_coords(), p_cell.alternative_tile, Rect2(Vector2(-tile_set_tile_size) / 2, tile_set_tile_size))) {
|
||||||
Transform2D tile_xform;
|
tile_set->draw_tile_shape(p_canvas_item, p_transform.scaled_local(tile_set_tile_size), color);
|
||||||
tile_xform.set_scale(tile_set_tile_size);
|
|
||||||
tile_set->draw_tile_shape(p_canvas_item, p_transform * tile_xform, color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (atlas_source->is_position_in_tile_texture_region(p_cell.get_atlas_coords(), p_cell.alternative_tile, Vector2())) {
|
if (atlas_source->is_position_in_tile_texture_region(p_cell.get_atlas_coords(), p_cell.alternative_tile, Vector2())) {
|
||||||
|
|
|
@ -1366,11 +1366,13 @@ void TileMapLayerEditorTilesPlugin::_stop_dragging() {
|
||||||
Vector2i coords;
|
Vector2i coords;
|
||||||
HashMap<Vector2i, TileMapCell> cells_undo;
|
HashMap<Vector2i, TileMapCell> cells_undo;
|
||||||
for (int i = 0; i < selection_used_cells.size(); i++) {
|
for (int i = 0; i < selection_used_cells.size(); i++) {
|
||||||
coords = tile_set->map_pattern(top_left, selection_used_cells[i], selection_pattern);
|
|
||||||
cells_undo[coords] = TileMapCell(drag_modified[coords].source_id, drag_modified[coords].get_atlas_coords(), drag_modified[coords].alternative_tile);
|
|
||||||
coords = tile_set->map_pattern(top_left + offset, selection_used_cells[i], selection_pattern);
|
coords = tile_set->map_pattern(top_left + offset, selection_used_cells[i], selection_pattern);
|
||||||
cells_undo[coords] = TileMapCell(edited_layer->get_cell_source_id(coords), edited_layer->get_cell_atlas_coords(coords), edited_layer->get_cell_alternative_tile(coords));
|
cells_undo[coords] = TileMapCell(edited_layer->get_cell_source_id(coords), edited_layer->get_cell_atlas_coords(coords), edited_layer->get_cell_alternative_tile(coords));
|
||||||
}
|
}
|
||||||
|
for (int i = 0; i < selection_used_cells.size(); i++) {
|
||||||
|
coords = tile_set->map_pattern(top_left, selection_used_cells[i], selection_pattern);
|
||||||
|
cells_undo[coords] = TileMapCell(drag_modified[coords].source_id, drag_modified[coords].get_atlas_coords(), drag_modified[coords].alternative_tile);
|
||||||
|
}
|
||||||
|
|
||||||
// Build the list of cells to do.
|
// Build the list of cells to do.
|
||||||
HashMap<Vector2i, TileMapCell> cells_do;
|
HashMap<Vector2i, TileMapCell> cells_do;
|
||||||
|
|
|
@ -115,8 +115,8 @@ void VSGraphNode::_draw_port(int p_slot_index, Point2i p_pos, bool p_left, const
|
||||||
icon_offset = -port_icon->get_size() * 0.5;
|
icon_offset = -port_icon->get_size() * 0.5;
|
||||||
|
|
||||||
// Draw "shadow"/outline in the connection rim color.
|
// Draw "shadow"/outline in the connection rim color.
|
||||||
draw_texture_rect(port_icon, Rect2(p_pos + icon_offset - Size2(2, 2), port_icon->get_size() + Size2(4, 4)), false, p_rim_color);
|
draw_texture_rect(port_icon, Rect2(p_pos + (icon_offset - Size2(2, 2)) * EDSCALE, (port_icon->get_size() + Size2(4, 4)) * EDSCALE), false, p_rim_color);
|
||||||
draw_texture(port_icon, p_pos + icon_offset, p_color);
|
draw_texture_rect(port_icon, Rect2(p_pos + icon_offset * EDSCALE, port_icon->get_size() * EDSCALE), false, p_color);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VSGraphNode::draw_port(int p_slot_index, Point2i p_pos, bool p_left, const Color &p_color) {
|
void VSGraphNode::draw_port(int p_slot_index, Point2i p_pos, bool p_left, const Color &p_color) {
|
||||||
|
@ -154,7 +154,6 @@ VSRerouteNode::VSRerouteNode() {
|
||||||
title_lbl->hide();
|
title_lbl->hide();
|
||||||
|
|
||||||
const Size2 size = Size2(32, 32) * EDSCALE;
|
const Size2 size = Size2(32, 32) * EDSCALE;
|
||||||
print_line("VSRerouteNode size: " + size);
|
|
||||||
|
|
||||||
Control *slot_area = memnew(Control);
|
Control *slot_area = memnew(Control);
|
||||||
slot_area->set_custom_minimum_size(size);
|
slot_area->set_custom_minimum_size(size);
|
||||||
|
@ -2888,8 +2887,8 @@ void VisualShaderEditor::_frame_title_popup_show(const Point2 &p_position, int p
|
||||||
}
|
}
|
||||||
frame_title_change_edit->set_text(node->get_title());
|
frame_title_change_edit->set_text(node->get_title());
|
||||||
frame_title_change_popup->set_meta("id", p_node_id);
|
frame_title_change_popup->set_meta("id", p_node_id);
|
||||||
frame_title_change_popup->popup();
|
|
||||||
frame_title_change_popup->set_position(p_position);
|
frame_title_change_popup->set_position(p_position);
|
||||||
|
frame_title_change_popup->popup();
|
||||||
|
|
||||||
// Select current text.
|
// Select current text.
|
||||||
frame_title_change_edit->grab_focus();
|
frame_title_change_edit->grab_focus();
|
||||||
|
|
|
@ -162,7 +162,7 @@ void ProjectDialog::_validate_path() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target_path.is_empty() || target_path.is_relative_path()) {
|
if (target_path.is_relative_path()) {
|
||||||
_set_message(TTR("The path specified is invalid."), MESSAGE_ERROR, target_path_input_type);
|
_set_message(TTR("The path specified is invalid."), MESSAGE_ERROR, target_path_input_type);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -352,7 +352,7 @@ void ProjectDialog::_install_path_changed() {
|
||||||
|
|
||||||
void ProjectDialog::_browse_project_path() {
|
void ProjectDialog::_browse_project_path() {
|
||||||
String path = project_path->get_text();
|
String path = project_path->get_text();
|
||||||
if (path.is_empty()) {
|
if (path.is_relative_path()) {
|
||||||
path = EDITOR_GET("filesystem/directories/default_project_path");
|
path = EDITOR_GET("filesystem/directories/default_project_path");
|
||||||
}
|
}
|
||||||
if (mode == MODE_IMPORT && install_path->is_visible_in_tree()) {
|
if (mode == MODE_IMPORT && install_path->is_visible_in_tree()) {
|
||||||
|
@ -382,12 +382,16 @@ void ProjectDialog::_browse_project_path() {
|
||||||
void ProjectDialog::_browse_install_path() {
|
void ProjectDialog::_browse_install_path() {
|
||||||
ERR_FAIL_COND_MSG(mode != MODE_IMPORT, "Install path is only used for MODE_IMPORT.");
|
ERR_FAIL_COND_MSG(mode != MODE_IMPORT, "Install path is only used for MODE_IMPORT.");
|
||||||
|
|
||||||
|
String path = install_path->get_text();
|
||||||
|
if (path.is_relative_path() || !DirAccess::dir_exists_absolute(path)) {
|
||||||
|
path = EDITOR_GET("filesystem/directories/default_project_path");
|
||||||
|
}
|
||||||
if (create_dir->is_pressed()) {
|
if (create_dir->is_pressed()) {
|
||||||
// Select parent directory of install path.
|
// Select parent directory of install path.
|
||||||
fdialog_install->set_current_dir(install_path->get_text().get_base_dir());
|
fdialog_install->set_current_dir(path.get_base_dir());
|
||||||
} else {
|
} else {
|
||||||
// Select install path.
|
// Select install path.
|
||||||
fdialog_install->set_current_dir(install_path->get_text());
|
fdialog_install->set_current_dir(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
fdialog_install->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_DIR);
|
fdialog_install->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_DIR);
|
||||||
|
|
|
@ -760,7 +760,7 @@ void ProjectList::_create_project_item_control(int p_index) {
|
||||||
hb->set_tags(item.tags, this);
|
hb->set_tags(item.tags, this);
|
||||||
hb->set_unsupported_features(item.unsupported_features.duplicate());
|
hb->set_unsupported_features(item.unsupported_features.duplicate());
|
||||||
hb->set_project_version(item.project_version);
|
hb->set_project_version(item.project_version);
|
||||||
hb->set_last_edited_info(Time::get_singleton()->get_datetime_string_from_unix_time(item.last_edited, true));
|
hb->set_last_edited_info(!item.missing ? Time::get_singleton()->get_datetime_string_from_unix_time(item.last_edited, true) : TTR("Missing Date"));
|
||||||
|
|
||||||
hb->set_is_favorite(item.favorite);
|
hb->set_is_favorite(item.favorite);
|
||||||
hb->set_is_missing(item.missing);
|
hb->set_is_missing(item.missing);
|
||||||
|
|
|
@ -1181,7 +1181,16 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
|
||||||
case TOOL_OPEN_DOCUMENTATION: {
|
case TOOL_OPEN_DOCUMENTATION: {
|
||||||
List<Node *> selection = editor_selection->get_selected_node_list();
|
List<Node *> selection = editor_selection->get_selected_node_list();
|
||||||
for (const Node *node : selection) {
|
for (const Node *node : selection) {
|
||||||
ScriptEditor::get_singleton()->goto_help("class_name:" + node->get_class());
|
String class_name;
|
||||||
|
Ref<Script> script_base = node->get_script();
|
||||||
|
if (script_base.is_valid()) {
|
||||||
|
class_name = script_base->get_global_name();
|
||||||
|
}
|
||||||
|
if (class_name.is_empty()) {
|
||||||
|
class_name = node->get_class();
|
||||||
|
}
|
||||||
|
|
||||||
|
ScriptEditor::get_singleton()->goto_help("class_name:" + class_name);
|
||||||
}
|
}
|
||||||
EditorNode::get_singleton()->set_visible_editor(EditorNode::EDITOR_SCRIPT);
|
EditorNode::get_singleton()->set_visible_editor(EditorNode::EDITOR_SCRIPT);
|
||||||
} break;
|
} break;
|
||||||
|
@ -2226,8 +2235,7 @@ void SceneTreeDock::_node_reparent(NodePath p_path, bool p_keep_global_xform) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, Vector<Node *> p_nodes, bool p_keep_global_xform) {
|
void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, Vector<Node *> p_nodes, bool p_keep_global_xform) {
|
||||||
Node *new_parent = p_new_parent;
|
ERR_FAIL_NULL(p_new_parent);
|
||||||
ERR_FAIL_NULL(new_parent);
|
|
||||||
|
|
||||||
if (p_nodes.size() == 0) {
|
if (p_nodes.size() == 0) {
|
||||||
return; // Nothing to reparent.
|
return; // Nothing to reparent.
|
||||||
|
@ -2267,7 +2275,7 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
|
||||||
// Prevent selecting the hovered node and keep the reparented node(s) selected instead.
|
// Prevent selecting the hovered node and keep the reparented node(s) selected instead.
|
||||||
hovered_but_reparenting = true;
|
hovered_but_reparenting = true;
|
||||||
|
|
||||||
Node *validate = new_parent;
|
Node *validate = p_new_parent;
|
||||||
while (validate) {
|
while (validate) {
|
||||||
ERR_FAIL_COND_MSG(p_nodes.has(validate), "Selection changed at some point. Can't reparent.");
|
ERR_FAIL_COND_MSG(p_nodes.has(validate), "Selection changed at some point. Can't reparent.");
|
||||||
validate = validate->get_parent();
|
validate = validate->get_parent();
|
||||||
|
@ -2289,7 +2297,7 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
|
||||||
// No undo implemented for this yet.
|
// No undo implemented for this yet.
|
||||||
Node *node = p_nodes[ni];
|
Node *node = p_nodes[ni];
|
||||||
|
|
||||||
fill_path_renames(node, new_parent, &path_renames);
|
fill_path_renames(node, p_new_parent, &path_renames);
|
||||||
former_names.push_back(node->get_name());
|
former_names.push_back(node->get_name());
|
||||||
|
|
||||||
List<Node *> owned;
|
List<Node *> owned;
|
||||||
|
@ -2299,7 +2307,7 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
|
||||||
owners.push_back(E);
|
owners.push_back(E);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool same_parent = new_parent == node->get_parent();
|
bool same_parent = p_new_parent == node->get_parent();
|
||||||
if (same_parent && node->get_index(false) < p_position_in_parent + ni) {
|
if (same_parent && node->get_index(false) < p_position_in_parent + ni) {
|
||||||
inc--; // If the child will generate a gap when moved, adjust.
|
inc--; // If the child will generate a gap when moved, adjust.
|
||||||
}
|
}
|
||||||
|
@ -2310,17 +2318,17 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
|
||||||
need_edit = select_node_hovered_at_end_of_drag;
|
need_edit = select_node_hovered_at_end_of_drag;
|
||||||
} else {
|
} else {
|
||||||
undo_redo->add_do_method(node->get_parent(), "remove_child", node);
|
undo_redo->add_do_method(node->get_parent(), "remove_child", node);
|
||||||
undo_redo->add_do_method(new_parent, "add_child", node, true);
|
undo_redo->add_do_method(p_new_parent, "add_child", node, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
int new_position_in_parent = p_position_in_parent == -1 ? -1 : p_position_in_parent + inc;
|
int new_position_in_parent = p_position_in_parent == -1 ? -1 : p_position_in_parent + inc;
|
||||||
if (new_position_in_parent >= 0 || same_parent) {
|
if (new_position_in_parent >= 0 || same_parent) {
|
||||||
undo_redo->add_do_method(new_parent, "move_child", node, new_position_in_parent);
|
undo_redo->add_do_method(p_new_parent, "move_child", node, new_position_in_parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
|
EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
|
||||||
String old_name = former_names[ni];
|
String old_name = former_names[ni];
|
||||||
String new_name = new_parent->validate_child_name(node);
|
String new_name = p_new_parent->validate_child_name(node);
|
||||||
|
|
||||||
// Name was modified, fix the path renames.
|
// Name was modified, fix the path renames.
|
||||||
if (old_name.casecmp_to(new_name) != 0) {
|
if (old_name.casecmp_to(new_name) != 0) {
|
||||||
|
@ -2345,8 +2353,12 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
undo_redo->add_do_method(ed, "live_debug_reparent_node", edited_scene->get_path_to(node), edited_scene->get_path_to(new_parent), new_name, new_position_in_parent);
|
// FIXME: Live editing for "Reparent to New Node" option is broken.
|
||||||
undo_redo->add_undo_method(ed, "live_debug_reparent_node", NodePath(String(edited_scene->get_path_to(new_parent)).path_join(new_name)), edited_scene->get_path_to(node->get_parent()), node->get_name(), node->get_index(false));
|
// We must get the path to `p_new_parent` *after* it was added to the scene.
|
||||||
|
if (p_new_parent->is_inside_tree()) {
|
||||||
|
undo_redo->add_do_method(ed, "live_debug_reparent_node", edited_scene->get_path_to(node), edited_scene->get_path_to(p_new_parent), new_name, new_position_in_parent);
|
||||||
|
undo_redo->add_undo_method(ed, "live_debug_reparent_node", NodePath(String(edited_scene->get_path_to(p_new_parent)).path_join(new_name)), edited_scene->get_path_to(node->get_parent()), node->get_name(), node->get_index(false));
|
||||||
|
}
|
||||||
|
|
||||||
if (p_keep_global_xform) {
|
if (p_keep_global_xform) {
|
||||||
if (Object::cast_to<Node2D>(node)) {
|
if (Object::cast_to<Node2D>(node)) {
|
||||||
|
@ -2366,7 +2378,7 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
|
||||||
undo_redo->add_do_method(AnimationPlayerEditor::get_singleton()->get_track_editor(), "set_root", node);
|
undo_redo->add_do_method(AnimationPlayerEditor::get_singleton()->get_track_editor(), "set_root", node);
|
||||||
}
|
}
|
||||||
|
|
||||||
undo_redo->add_undo_method(new_parent, "remove_child", node);
|
undo_redo->add_undo_method(p_new_parent, "remove_child", node);
|
||||||
undo_redo->add_undo_method(node, "set_name", former_names[ni]);
|
undo_redo->add_undo_method(node, "set_name", former_names[ni]);
|
||||||
|
|
||||||
inc++;
|
inc++;
|
||||||
|
@ -2384,7 +2396,7 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
|
||||||
}
|
}
|
||||||
|
|
||||||
int child_pos = node->get_index(false);
|
int child_pos = node->get_index(false);
|
||||||
bool reparented_to_container = Object::cast_to<Container>(new_parent) && Object::cast_to<Control>(node);
|
bool reparented_to_container = Object::cast_to<Container>(p_new_parent) && Object::cast_to<Control>(node);
|
||||||
|
|
||||||
undo_redo->add_undo_method(node->get_parent(), "add_child", node, true);
|
undo_redo->add_undo_method(node->get_parent(), "add_child", node, true);
|
||||||
undo_redo->add_undo_method(node->get_parent(), "move_child", node, child_pos);
|
undo_redo->add_undo_method(node->get_parent(), "move_child", node, child_pos);
|
||||||
|
@ -2641,6 +2653,13 @@ void SceneTreeDock::_delete_confirm(bool p_cut) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!entire_scene) {
|
||||||
|
for (const Node *E : remove_list) {
|
||||||
|
// `move_child` + `get_index` doesn't really work for internal nodes.
|
||||||
|
ERR_FAIL_COND_MSG(E->get_internal_mode() != INTERNAL_MODE_DISABLED, "Trying to remove internal node, this is not supported.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
EditorNode::get_singleton()->hide_unused_editors(this);
|
EditorNode::get_singleton()->hide_unused_editors(this);
|
||||||
|
|
||||||
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
||||||
|
@ -2653,10 +2672,6 @@ void SceneTreeDock::_delete_confirm(bool p_cut) {
|
||||||
undo_redo->add_undo_method(scene_tree, "update_tree");
|
undo_redo->add_undo_method(scene_tree, "update_tree");
|
||||||
undo_redo->add_undo_reference(edited_scene);
|
undo_redo->add_undo_reference(edited_scene);
|
||||||
} else {
|
} else {
|
||||||
for (const Node *E : remove_list) {
|
|
||||||
// `move_child` + `get_index` doesn't really work for internal nodes.
|
|
||||||
ERR_FAIL_COND_MSG(E->get_internal_mode() != INTERNAL_MODE_DISABLED, "Trying to remove internal node, this is not supported.");
|
|
||||||
}
|
|
||||||
if (delete_tracks_checkbox->is_pressed() || p_cut) {
|
if (delete_tracks_checkbox->is_pressed() || p_cut) {
|
||||||
remove_list.sort_custom<Node::Comparator>(); // Sort nodes to keep positions.
|
remove_list.sort_custom<Node::Comparator>(); // Sort nodes to keep positions.
|
||||||
HashMap<Node *, NodePath> path_renames;
|
HashMap<Node *, NodePath> path_renames;
|
||||||
|
@ -2761,10 +2776,10 @@ void SceneTreeDock::_selection_changed() {
|
||||||
_update_script_button();
|
_update_script_button();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneTreeDock::_do_create(Node *p_parent) {
|
Node *SceneTreeDock::_do_create(Node *p_parent) {
|
||||||
Variant c = create_dialog->instantiate_selected();
|
Variant c = create_dialog->instantiate_selected();
|
||||||
Node *child = Object::cast_to<Node>(c);
|
Node *child = Object::cast_to<Node>(c);
|
||||||
ERR_FAIL_NULL(child);
|
ERR_FAIL_NULL_V(child, nullptr);
|
||||||
|
|
||||||
String new_name = p_parent->validate_child_name(child);
|
String new_name = p_parent->validate_child_name(child);
|
||||||
if (GLOBAL_GET("editor/naming/node_name_casing").operator int() != NAME_CASING_PASCAL_CASE) {
|
if (GLOBAL_GET("editor/naming/node_name_casing").operator int() != NAME_CASING_PASCAL_CASE) {
|
||||||
|
@ -2778,8 +2793,6 @@ void SceneTreeDock::_do_create(Node *p_parent) {
|
||||||
if (edited_scene) {
|
if (edited_scene) {
|
||||||
undo_redo->add_do_method(p_parent, "add_child", child, true);
|
undo_redo->add_do_method(p_parent, "add_child", child, true);
|
||||||
undo_redo->add_do_method(child, "set_owner", edited_scene);
|
undo_redo->add_do_method(child, "set_owner", edited_scene);
|
||||||
undo_redo->add_do_method(editor_selection, "clear");
|
|
||||||
undo_redo->add_do_method(editor_selection, "add_node", child);
|
|
||||||
undo_redo->add_do_reference(child);
|
undo_redo->add_do_reference(child);
|
||||||
undo_redo->add_undo_method(p_parent, "remove_child", child);
|
undo_redo->add_undo_method(p_parent, "remove_child", child);
|
||||||
|
|
||||||
|
@ -2794,28 +2807,34 @@ void SceneTreeDock::_do_create(Node *p_parent) {
|
||||||
undo_redo->add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr);
|
undo_redo->add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
undo_redo->add_do_method(this, "_post_do_create", child);
|
||||||
undo_redo->commit_action();
|
undo_redo->commit_action();
|
||||||
_push_item(c);
|
|
||||||
editor_selection->clear();
|
|
||||||
editor_selection->add_node(child);
|
|
||||||
if (Object::cast_to<Control>(c)) {
|
|
||||||
//make editor more comfortable, so some controls don't appear super shrunk
|
|
||||||
Control *ct = Object::cast_to<Control>(c);
|
|
||||||
|
|
||||||
Size2 ms = ct->get_minimum_size();
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneTreeDock::_post_do_create(Node *p_child) {
|
||||||
|
editor_selection->clear();
|
||||||
|
editor_selection->add_node(p_child);
|
||||||
|
_push_item(p_child);
|
||||||
|
|
||||||
|
// Make editor more comfortable, so some controls don't appear super shrunk.
|
||||||
|
Control *control = Object::cast_to<Control>(p_child);
|
||||||
|
if (control) {
|
||||||
|
Size2 ms = control->get_minimum_size();
|
||||||
if (ms.width < 4) {
|
if (ms.width < 4) {
|
||||||
ms.width = 40;
|
ms.width = 40;
|
||||||
}
|
}
|
||||||
if (ms.height < 4) {
|
if (ms.height < 4) {
|
||||||
ms.height = 40;
|
ms.height = 40;
|
||||||
}
|
}
|
||||||
if (ct->is_layout_rtl()) {
|
if (control->is_layout_rtl()) {
|
||||||
ct->set_position(ct->get_position() - Vector2(ms.x, 0));
|
control->set_position(control->get_position() - Vector2(ms.x, 0));
|
||||||
}
|
}
|
||||||
ct->set_size(ms);
|
control->set_size(ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
emit_signal(SNAME("node_created"), c);
|
emit_signal(SNAME("node_created"), p_child);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneTreeDock::_create() {
|
void SceneTreeDock::_create() {
|
||||||
|
@ -2898,22 +2917,24 @@ void SceneTreeDock::_create() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Node *parent = nullptr;
|
Node *parent = nullptr;
|
||||||
|
int original_position = -1;
|
||||||
if (only_one_top_node) {
|
if (only_one_top_node) {
|
||||||
parent = top_node->get_parent();
|
parent = top_node->get_parent();
|
||||||
|
original_position = top_node->get_index(false);
|
||||||
} else {
|
} else {
|
||||||
parent = top_node->get_parent()->get_parent();
|
parent = top_node->get_parent()->get_parent();
|
||||||
}
|
}
|
||||||
|
|
||||||
_do_create(parent);
|
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
||||||
|
undo_redo->create_action_for_history(TTR("Reparent to New Node"), editor_data->get_current_edited_scene_history_id());
|
||||||
|
|
||||||
|
Node *last_created = _do_create(parent);
|
||||||
|
|
||||||
Vector<Node *> nodes;
|
Vector<Node *> nodes;
|
||||||
for (Node *E : selection) {
|
for (Node *E : selection) {
|
||||||
nodes.push_back(E);
|
nodes.push_back(E);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This works because editor_selection was cleared and populated with last created node in _do_create()
|
|
||||||
Node *last_created = editor_selection->get_selected_node_list().front()->get();
|
|
||||||
|
|
||||||
if (center_parent) {
|
if (center_parent) {
|
||||||
// Find parent type and only average positions of relevant nodes.
|
// Find parent type and only average positions of relevant nodes.
|
||||||
Node3D *parent_node_3d = Object::cast_to<Node3D>(last_created);
|
Node3D *parent_node_3d = Object::cast_to<Node3D>(last_created);
|
||||||
|
@ -2952,6 +2973,11 @@ void SceneTreeDock::_create() {
|
||||||
}
|
}
|
||||||
|
|
||||||
_do_reparent(last_created, -1, nodes, true);
|
_do_reparent(last_created, -1, nodes, true);
|
||||||
|
|
||||||
|
if (only_one_top_node) {
|
||||||
|
undo_redo->add_do_method(parent, "move_child", last_created, original_position);
|
||||||
|
}
|
||||||
|
undo_redo->commit_action();
|
||||||
}
|
}
|
||||||
|
|
||||||
scene_tree->get_scene_tree()->grab_focus();
|
scene_tree->get_scene_tree()->grab_focus();
|
||||||
|
@ -4354,6 +4380,7 @@ void SceneTreeDock::_edit_subresource(int p_idx, const PopupMenu *p_from_menu) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneTreeDock::_bind_methods() {
|
void SceneTreeDock::_bind_methods() {
|
||||||
|
ClassDB::bind_method(D_METHOD("_post_do_create"), &SceneTreeDock::_post_do_create);
|
||||||
ClassDB::bind_method(D_METHOD("_set_owners"), &SceneTreeDock::_set_owners);
|
ClassDB::bind_method(D_METHOD("_set_owners"), &SceneTreeDock::_set_owners);
|
||||||
ClassDB::bind_method(D_METHOD("_reparent_nodes_to_root"), &SceneTreeDock::_reparent_nodes_to_root);
|
ClassDB::bind_method(D_METHOD("_reparent_nodes_to_root"), &SceneTreeDock::_reparent_nodes_to_root);
|
||||||
ClassDB::bind_method(D_METHOD("_reparent_nodes_to_paths_with_transform_and_name"), &SceneTreeDock::_reparent_nodes_to_paths_with_transform_and_name);
|
ClassDB::bind_method(D_METHOD("_reparent_nodes_to_paths_with_transform_and_name"), &SceneTreeDock::_reparent_nodes_to_paths_with_transform_and_name);
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue