Merge pull request #39280 from akien-mga/3.2-cherrypicks
Cherry-picks for the 3.2 branch (future 3.2.2) - 7th batch
This commit is contained in:
commit
ed1fc50bb9
|
@ -95,6 +95,7 @@ name is available.
|
|||
Indah Sylvia (ISylvox)
|
||||
J08nY
|
||||
Jakub Grzesik (kubecz3k)
|
||||
James Buck (jbuck3)
|
||||
Jérôme Gully (Nutriz)
|
||||
Joan Fons Sanchez (JFonS)
|
||||
Johan Manuel (29jm)
|
||||
|
|
|
@ -350,7 +350,7 @@ License: Expat
|
|||
|
||||
Files: ./thirdparty/xatlas/
|
||||
Comment: xatlas
|
||||
Copyright: 2018, Jonathan Young
|
||||
Copyright: 2018-2020, Jonathan Young
|
||||
2013, Thekla, Inc
|
||||
2006, NVIDIA Corporation, Ignacio Castano
|
||||
License: Expat
|
||||
|
|
87
DONORS.md
87
DONORS.md
|
@ -24,11 +24,12 @@ generous deed immortalized in the next stable release of Godot Engine.
|
|||
|
||||
AD Ford
|
||||
Alan Beauchamp
|
||||
Anand Mallik
|
||||
albinaask
|
||||
Andrew Dunai
|
||||
Brandon Lamb
|
||||
Christian Baune
|
||||
Christopher Montesano
|
||||
Darius Pranskus
|
||||
Darkhan Baimyrza
|
||||
Darrin Massena
|
||||
Dov Zimring
|
||||
|
@ -41,15 +42,18 @@ generous deed immortalized in the next stable release of Godot Engine.
|
|||
Jasper Brooks
|
||||
Javary Co.
|
||||
Jeffery Chiu
|
||||
John Benard (Linuxydable)
|
||||
Justin Arnold
|
||||
Justo Delgado Baudí
|
||||
Kyle Szklenski
|
||||
Marcel Kräml
|
||||
Matthieu Huvé
|
||||
Maxim Karsten
|
||||
Mike King
|
||||
Nathan Warden
|
||||
Neal Gompa (Conan Kudo)
|
||||
Péter Magyar
|
||||
Ronnie Cheng
|
||||
Slobodan Milnovic
|
||||
Stephan Lanfermann
|
||||
Steve
|
||||
|
@ -58,12 +62,14 @@ generous deed immortalized in the next stable release of Godot Engine.
|
|||
|
||||
## Gold donors
|
||||
|
||||
Bjarke
|
||||
David Gehrig
|
||||
David Graham
|
||||
David Snopek
|
||||
Ed Morley
|
||||
Florian Rämisch
|
||||
Jakub Grzesik
|
||||
HardRound
|
||||
Manuele Finocchiaro
|
||||
Officine Pixel S.n.c.
|
||||
Ronan Zeegers
|
||||
|
@ -92,10 +98,10 @@ generous deed immortalized in the next stable release of Godot Engine.
|
|||
Maciej Pendolski
|
||||
Matthew Hillier
|
||||
Mohamed Ikbel Boulabiar
|
||||
Mored4u
|
||||
Rene
|
||||
Retro Village
|
||||
Rob Messick
|
||||
Roland Fredenhagen
|
||||
Ryan Badour
|
||||
Sandro Jenny
|
||||
Scott Wadden
|
||||
|
@ -108,16 +114,19 @@ generous deed immortalized in the next stable release of Godot Engine.
|
|||
|
||||
Alex Khayrullin
|
||||
alice gambrell
|
||||
Barugon
|
||||
Chris Goddard
|
||||
Chris Serino
|
||||
Christian Padilla
|
||||
Conrad Curry
|
||||
Craig Smith
|
||||
Darrian Little
|
||||
Hoai Nam Tran
|
||||
Horváth Péter
|
||||
Ivan Trombley
|
||||
Jamal Aboudrar
|
||||
Joan Fons
|
||||
Joshua Flores
|
||||
Leo Fidel R Liban
|
||||
Petr Malac
|
||||
Rami
|
||||
Rob
|
||||
|
@ -149,20 +158,20 @@ generous deed immortalized in the next stable release of Godot Engine.
|
|||
Christoph Schröder
|
||||
Codee Leaf
|
||||
Cody Parker
|
||||
Coldragon
|
||||
Craig Ostrin
|
||||
curtis Kramer
|
||||
D
|
||||
Easypete
|
||||
Edgar Sun
|
||||
Eric Monson
|
||||
Eugenio Hugo Salgüero Jáñez
|
||||
Fain
|
||||
flesk
|
||||
Gary Hulst
|
||||
gavlig
|
||||
GGGames.org
|
||||
Guilherme Felipe de C. G. da Silva
|
||||
Halom Vered
|
||||
Heath Hayes
|
||||
Hu Hund
|
||||
Isaac Clausman
|
||||
Jared White
|
||||
Jeff Nyte
|
||||
|
@ -171,18 +180,21 @@ generous deed immortalized in the next stable release of Godot Engine.
|
|||
Jose Malheiro
|
||||
Joshua Lesperance
|
||||
Juan Velandia
|
||||
Julian Todd
|
||||
Juraj Móza
|
||||
Kelteseth
|
||||
kickmaniac
|
||||
kinfox
|
||||
Lain Ballard
|
||||
Marcelo Dornbusch Lopes
|
||||
Marcelo Henrique Gonçalves
|
||||
Markus Fehr
|
||||
Markus Wiesner
|
||||
Martin Eigel
|
||||
Matt Eunson
|
||||
m kaersten
|
||||
MuffinManKen
|
||||
Nick Abousselam
|
||||
Oliver Dick
|
||||
Oscar Campos
|
||||
Patrick Ting
|
||||
|
@ -197,14 +209,16 @@ generous deed immortalized in the next stable release of Godot Engine.
|
|||
Samuel Judd
|
||||
Scott Pilet
|
||||
Sean Morgan
|
||||
Sean Robertson
|
||||
Sébastien
|
||||
Serban Serafimescu
|
||||
Sindre Sømme
|
||||
SleepCircle
|
||||
spilldata
|
||||
Stoned Xander
|
||||
TheLevelOfDetail .
|
||||
Thomas Kurz
|
||||
Tobias Bocanegra
|
||||
Trent Fehl
|
||||
Urho
|
||||
William Foster
|
||||
Zhou Tuizhi
|
||||
|
@ -214,6 +228,7 @@ generous deed immortalized in the next stable release of Godot Engine.
|
|||
## Silver donors
|
||||
|
||||
1D_Inc
|
||||
Aaron Winter
|
||||
Abraham Haskins
|
||||
Acheron
|
||||
Adam
|
||||
|
@ -229,7 +244,6 @@ generous deed immortalized in the next stable release of Godot Engine.
|
|||
Agustinus Arya
|
||||
Aidan O'Flannagain
|
||||
Aki Mimoto
|
||||
Alan Mervitz
|
||||
Alan Stice
|
||||
Albin Jonasson Svärdsby
|
||||
Alder Stefano
|
||||
|
@ -237,14 +251,17 @@ generous deed immortalized in the next stable release of Godot Engine.
|
|||
Alessandro Senese
|
||||
Alexander Erlemann
|
||||
alex clavelle
|
||||
Alfred Reinold Baudisch
|
||||
Allan Davis
|
||||
Allen Schade
|
||||
Andreas Evers
|
||||
Andreas Krampitz
|
||||
Andres Hernandez
|
||||
André Simões
|
||||
andrew james morris
|
||||
Andrew Mansuetti
|
||||
Andrew Thomas
|
||||
Ano Nim
|
||||
Anthony Avina
|
||||
Anthony Staunton
|
||||
AP Condomines
|
||||
Arda Erol
|
||||
Armin Preiml
|
||||
|
@ -252,10 +269,11 @@ generous deed immortalized in the next stable release of Godot Engine.
|
|||
Arthur S. Muszynski
|
||||
Asger
|
||||
Ashley Claymore
|
||||
Ashton Scott Snapp
|
||||
Aubrey Falconer
|
||||
Avencherus
|
||||
B A
|
||||
Balázs Batári
|
||||
Bartosz Bielecki
|
||||
Benedikt
|
||||
Ben Vercammen
|
||||
Bernd Jänichen
|
||||
|
@ -265,10 +283,8 @@ generous deed immortalized in the next stable release of Godot Engine.
|
|||
Bobby CC Wong
|
||||
Bram
|
||||
brian
|
||||
bugcaptor
|
||||
Burney Waring
|
||||
Cameron Meyer
|
||||
Carlo Sitaro
|
||||
Carl van der Geest
|
||||
Carwyn Edwards
|
||||
Cas Brugman
|
||||
|
@ -289,7 +305,7 @@ generous deed immortalized in the next stable release of Godot Engine.
|
|||
Daniel Tebbutt
|
||||
David May
|
||||
David Woodard
|
||||
DiCola Jamn
|
||||
Dimitri Stanojevic
|
||||
Dominic Cooney
|
||||
Dominik Wetzel
|
||||
Donn Eddy
|
||||
|
@ -301,24 +317,25 @@ generous deed immortalized in the next stable release of Godot Engine.
|
|||
Eduardo Teixeira
|
||||
Edward Herbert
|
||||
Edward Swartz
|
||||
Eelco F Hillenius
|
||||
Egon Elbre
|
||||
Elgenzay
|
||||
Elias Nykrem
|
||||
Elmeri '- Duy Kevin Nguyen
|
||||
Ephemeral
|
||||
Eric Ellingson
|
||||
Eric Rogers
|
||||
Eric Williams
|
||||
Erkki Seppälä
|
||||
Evan Rose
|
||||
Fain
|
||||
Faisal Alkubaisi
|
||||
Fancy Ants Studios
|
||||
Fekinox
|
||||
Felix Bohmann
|
||||
Felix Kollmann
|
||||
Flaredown
|
||||
Forty Doubleu
|
||||
fox
|
||||
FuDiggity
|
||||
Frank
|
||||
Gadzhi Kharkharov
|
||||
gamedev by Celio
|
||||
Gary Thomas
|
||||
|
@ -328,16 +345,17 @@ generous deed immortalized in the next stable release of Godot Engine.
|
|||
Greyson Richey
|
||||
Grid
|
||||
Guillaume Audirac
|
||||
Guillaume Pham Ngoc
|
||||
Guldoman
|
||||
Hal A
|
||||
Heribert Hirth
|
||||
Hunter Jones
|
||||
Hylpher
|
||||
Ichiro Dohi
|
||||
Iiari
|
||||
iKlem
|
||||
IndustrialRobot
|
||||
Ivan Nikolaev
|
||||
Jackson Harmer
|
||||
Jacob
|
||||
Jaiden Gerig
|
||||
Jaime Ruiz-Borau Vizárraga
|
||||
|
@ -346,9 +364,11 @@ generous deed immortalized in the next stable release of Godot Engine.
|
|||
Janders
|
||||
Jannik Gröger
|
||||
JARKKO PARVIAINEN
|
||||
Jean-Baptiste LEPESME
|
||||
Jeff Hungerford
|
||||
Jennifer Graves
|
||||
Jesse Dubay
|
||||
Joe Alden
|
||||
Joel Fivat
|
||||
Joel Höglund
|
||||
Joel Setterberg
|
||||
|
@ -363,14 +383,18 @@ generous deed immortalized in the next stable release of Godot Engine.
|
|||
Jonathan G
|
||||
Jon Bonazza
|
||||
Jon Sully
|
||||
Jordy Goodridge
|
||||
Jorge Antunes
|
||||
Jorge Caballero
|
||||
Jose Aleman
|
||||
Jose C. Rubio
|
||||
Joseph Catrambone
|
||||
Josh Mitchell
|
||||
Joshua Southerland
|
||||
Juanfran
|
||||
Judd
|
||||
Julian Murgia
|
||||
June Little
|
||||
JungleRobba
|
||||
Justin Hamilton
|
||||
Justin Spedding
|
||||
|
@ -382,7 +406,6 @@ generous deed immortalized in the next stable release of Godot Engine.
|
|||
Kent Jofur
|
||||
Kevin McPhillips
|
||||
Kiri Jolly
|
||||
Kiyohiro Kawamura (kyorohiro)
|
||||
Kjetil Haugland
|
||||
Klagsam
|
||||
KsyTek Games
|
||||
|
@ -390,26 +413,24 @@ generous deed immortalized in the next stable release of Godot Engine.
|
|||
kycho
|
||||
Kyle Appelgate
|
||||
Laurent Tréguier
|
||||
Leonard Meagher
|
||||
Leonardo Dimano
|
||||
Levi Lindsey
|
||||
Lin Chear
|
||||
Linus Lind Lundgren
|
||||
Lionel Gaillard
|
||||
Lukáš Rendvanský
|
||||
Luigi Renna
|
||||
LunaticInAHat
|
||||
Lurkars
|
||||
Major Haul
|
||||
Malcolm
|
||||
Malik Ahmed
|
||||
Malik Nejer
|
||||
Marco Lardelli
|
||||
Markus Michael Egger
|
||||
Martin Holas
|
||||
Martin Liška
|
||||
Marvin
|
||||
Mathieu Rimelen
|
||||
Mathieu
|
||||
Matt Edwards
|
||||
Matthew Little
|
||||
Mauro Pellegrini
|
||||
Max Fiedler
|
||||
Maxime Blade
|
||||
|
@ -426,7 +447,7 @@ generous deed immortalized in the next stable release of Godot Engine.
|
|||
Mikayla
|
||||
Mike Birkhead
|
||||
Mike Cunningham
|
||||
Mitchell J. Wagner
|
||||
Molinghu
|
||||
MoM
|
||||
Mored4u
|
||||
Nathan Fish
|
||||
|
@ -435,8 +456,10 @@ generous deed immortalized in the next stable release of Godot Engine.
|
|||
Neil Blakey-Milner
|
||||
Neil Wang
|
||||
Nerdforge
|
||||
Nerdyninja
|
||||
Nicholas
|
||||
Nicholas Girga
|
||||
Nick Allen
|
||||
Nick Macholl
|
||||
Niclas Eriksen
|
||||
Nicolás Montaña
|
||||
|
@ -453,11 +476,12 @@ generous deed immortalized in the next stable release of Godot Engine.
|
|||
Paweł Kowal
|
||||
Pedro Assuncao
|
||||
Penguin
|
||||
Peter
|
||||
Philip Cohoe
|
||||
Point08
|
||||
pwab
|
||||
Rad Cat
|
||||
Rafa Laguna
|
||||
rainerLinux
|
||||
Remi Rampin
|
||||
Rémi Verschelde
|
||||
Ricardo Alcantara
|
||||
|
@ -470,6 +494,7 @@ generous deed immortalized in the next stable release of Godot Engine.
|
|||
Roman Tinkov
|
||||
Ronald Ho Hip (CrimsonZA)
|
||||
Ronan
|
||||
Ronny Mühle
|
||||
Ryan Groom
|
||||
Ryan Hentz
|
||||
Sam Edson
|
||||
|
@ -483,6 +508,7 @@ generous deed immortalized in the next stable release of Godot Engine.
|
|||
Shane
|
||||
Shane Sicienski
|
||||
Shane Spoor
|
||||
Shiomi '- Duy Kevin Nguyen
|
||||
Siim Raidma
|
||||
Simon Jonas Larsen
|
||||
Simon Wenner
|
||||
|
@ -490,17 +516,21 @@ generous deed immortalized in the next stable release of Godot Engine.
|
|||
SK
|
||||
smbe19
|
||||
smo1704
|
||||
soft circles
|
||||
Squirrel
|
||||
Stefano Caronia
|
||||
Steve Cloete
|
||||
Svenne Krap
|
||||
Taylor Fahlman
|
||||
Terry
|
||||
tezuvholovdr
|
||||
TheVoiceInMyHead
|
||||
thomas
|
||||
Thomas Bechtold
|
||||
Thomas Detoy
|
||||
Thomas Kelly
|
||||
Tim Drumheller
|
||||
Tim Erskine
|
||||
Timothy B. MacDonald
|
||||
Title Plinsut
|
||||
Tobbun
|
||||
|
@ -516,6 +546,7 @@ generous deed immortalized in the next stable release of Godot Engine.
|
|||
Tyler Compton
|
||||
Tyler Stafos
|
||||
UltyX
|
||||
Valentí Gàmez
|
||||
Vaughan Ling
|
||||
Victor
|
||||
Vigilant Watch
|
||||
|
@ -525,10 +556,12 @@ generous deed immortalized in the next stable release of Godot Engine.
|
|||
werner mendizabal
|
||||
Wiley Thompson
|
||||
Will
|
||||
William Hogben
|
||||
Wyatt Goodin
|
||||
Yegor
|
||||
Yuri LaPointe
|
||||
Yuri Sizov
|
||||
Zgegnesh Hemomancer
|
||||
郝晨煜
|
||||
|
||||
## Bronze donors
|
||||
|
||||
|
|
13
SConstruct
13
SConstruct
|
@ -177,12 +177,16 @@ for k in platform_opts.keys():
|
|||
for o in opt_list:
|
||||
opts.Add(o)
|
||||
|
||||
# Update the environment now as the "custom_modules" option may be
|
||||
# defined in a file rather than specified via the command line.
|
||||
opts.Update(env_base)
|
||||
|
||||
# Detect modules.
|
||||
modules_detected = OrderedDict()
|
||||
module_search_paths = ["modules"] # Built-in path.
|
||||
|
||||
if ARGUMENTS.get("custom_modules"):
|
||||
paths = ARGUMENTS.get("custom_modules").split(",")
|
||||
if env_base["custom_modules"]:
|
||||
paths = env_base["custom_modules"].split(",")
|
||||
for p in paths:
|
||||
try:
|
||||
module_search_paths.append(methods.convert_custom_modules_path(p))
|
||||
|
@ -213,8 +217,9 @@ for name, path in modules_detected.items():
|
|||
|
||||
methods.write_modules(modules_detected)
|
||||
|
||||
opts.Update(env_base) # update environment
|
||||
Help(opts.GenerateHelpText(env_base)) # generate help
|
||||
# Update the environment again after all the module options are added.
|
||||
opts.Update(env_base)
|
||||
Help(opts.GenerateHelpText(env_base))
|
||||
|
||||
# add default include paths
|
||||
|
||||
|
|
|
@ -728,19 +728,25 @@ PoolStringArray OS::get_connected_midi_inputs() {
|
|||
return MIDIDriver::get_singleton()->get_connected_inputs();
|
||||
|
||||
PoolStringArray list;
|
||||
return list;
|
||||
ERR_FAIL_V_MSG(list, vformat("MIDI input isn't supported on %s.", OS::get_singleton()->get_name()));
|
||||
}
|
||||
|
||||
void OS::open_midi_inputs() {
|
||||
|
||||
if (MIDIDriver::get_singleton())
|
||||
if (MIDIDriver::get_singleton()) {
|
||||
MIDIDriver::get_singleton()->open();
|
||||
} else {
|
||||
ERR_PRINT(vformat("MIDI input isn't supported on %s.", OS::get_singleton()->get_name()));
|
||||
}
|
||||
}
|
||||
|
||||
void OS::close_midi_inputs() {
|
||||
|
||||
if (MIDIDriver::get_singleton())
|
||||
if (MIDIDriver::get_singleton()) {
|
||||
MIDIDriver::get_singleton()->close();
|
||||
} else {
|
||||
ERR_PRINT(vformat("MIDI input isn't supported on %s.", OS::get_singleton()->get_name()));
|
||||
}
|
||||
}
|
||||
|
||||
OS::OS() {
|
||||
|
|
|
@ -307,10 +307,16 @@ void ProjectSettings::_convert_to_last_version(int p_from_version) {
|
|||
* using the following merit order:
|
||||
* - If using NetworkClient, try to lookup project file or fail.
|
||||
* - If --main-pack was passed by the user (`p_main_pack`), load it or fail.
|
||||
* - Search for .pck file matching binary name. There are two possibilities:
|
||||
* o exec_path.get_basename() + '.pck' (e.g. 'win_game.exe' -> 'win_game.pck')
|
||||
* o exec_path + '.pck' (e.g. 'linux_game' -> 'linux_game.pck')
|
||||
* For each tentative, if the file exists, load it or fail.
|
||||
* - Search for project PCKs automatically. For each step we try loading a potential
|
||||
* PCK, and if it doesn't work, we proceed to the next step. If any step succeeds,
|
||||
* we try loading the project settings, and abort if it fails. Steps:
|
||||
* o Bundled PCK in the executable.
|
||||
* o [macOS only] PCK with same basename as the binary in the .app resource dir.
|
||||
* o PCK with same basename as the binary in the binary's directory. We handle both
|
||||
* changing the extension to '.pck' (e.g. 'win_game.exe' -> 'win_game.pck') and
|
||||
* appending '.pck' to the binary name (e.g. 'linux_game' -> 'linux_game.pck').
|
||||
* o PCK with the same basename as the binary in the current working directory.
|
||||
* Same as above for the two possible PCK file names.
|
||||
* - On relevant platforms (Android/iOS), lookup project file in OS resource path.
|
||||
* If found, load it or fail.
|
||||
* - Lookup project file in passed `p_path` (--path passed by the user), i.e. we
|
||||
|
@ -354,65 +360,68 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
|
|||
String exec_path = OS::get_singleton()->get_executable_path();
|
||||
|
||||
if (exec_path != "") {
|
||||
// Attempt with exec_name.pck
|
||||
// We do several tests sequentially until one succeeds to find a PCK,
|
||||
// and if so we attempt loading it at the end.
|
||||
|
||||
// Attempt with PCK bundled into executable.
|
||||
bool found = _load_resource_pack(exec_path);
|
||||
|
||||
// Attempt with exec_name.pck.
|
||||
// (This is the usual case when distributing a Godot game.)
|
||||
String exec_dir = exec_path.get_base_dir();
|
||||
String exec_filename = exec_path.get_file();
|
||||
String exec_basename = exec_filename.get_basename();
|
||||
|
||||
// Based on the OS, it can be the exec path + '.pck' (Linux w/o extension, macOS in .app bundle)
|
||||
// or the exec path's basename + '.pck' (Windows).
|
||||
// We need to test both possibilities as extensions for Linux binaries are optional
|
||||
// (so both 'mygame.bin' and 'mygame' should be able to find 'mygame.pck').
|
||||
|
||||
String exec_dir = exec_path.get_base_dir();
|
||||
String exec_filename = exec_path.get_file();
|
||||
String exec_basename = exec_filename.get_basename();
|
||||
|
||||
// Attempt with PCK bundled into executable
|
||||
bool found = _load_resource_pack(exec_path);
|
||||
|
||||
#ifdef OSX_ENABLED
|
||||
if (!found) {
|
||||
// Attempt to load PCK from macOS .app bundle resources
|
||||
// Attempt to load PCK from macOS .app bundle resources.
|
||||
found = _load_resource_pack(OS::get_singleton()->get_bundle_resource_dir().plus_file(exec_basename + ".pck"));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!found) {
|
||||
// Try to load data pack at the location of the executable
|
||||
// As mentioned above, we have two potential names to attempt
|
||||
// Try to load data pack at the location of the executable.
|
||||
// As mentioned above, we have two potential names to attempt.
|
||||
found = _load_resource_pack(exec_dir.plus_file(exec_basename + ".pck")) || _load_resource_pack(exec_dir.plus_file(exec_filename + ".pck"));
|
||||
|
||||
if (!found) {
|
||||
// If we couldn't find them next to the executable, we attempt
|
||||
// the current working directory. Same story, two tests.
|
||||
found = _load_resource_pack(exec_basename + ".pck") || _load_resource_pack(exec_filename + ".pck");
|
||||
}
|
||||
}
|
||||
|
||||
// If we opened our package, try and load our project
|
||||
if (!found) {
|
||||
// If we couldn't find them next to the executable, we attempt
|
||||
// the current working directory. Same story, two tests.
|
||||
found = _load_resource_pack(exec_basename + ".pck") || _load_resource_pack(exec_filename + ".pck");
|
||||
}
|
||||
|
||||
// If we opened our package, try and load our project.
|
||||
if (found) {
|
||||
Error err = _load_settings_text_or_binary("res://project.godot", "res://project.binary");
|
||||
if (err == OK) {
|
||||
// Load override from location of executable
|
||||
// Optional, we don't mind if it fails
|
||||
// Load override from location of the executable.
|
||||
// Optional, we don't mind if it fails.
|
||||
_load_settings_text(exec_path.get_base_dir().plus_file("override.cfg"));
|
||||
}
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
// Try to use the filesystem for files, according to OS. (only Android -when reading from pck- and iOS use this)
|
||||
// Try to use the filesystem for files, according to OS.
|
||||
// (Only Android -when reading from pck- and iOS use this.)
|
||||
|
||||
if (OS::get_singleton()->get_resource_dir() != "") {
|
||||
// OS will call ProjectSettings->get_resource_path which will be empty if not overridden!
|
||||
// If the OS would rather use a specific location, then it will not be empty.
|
||||
resource_path = OS::get_singleton()->get_resource_dir().replace("\\", "/");
|
||||
if (resource_path != "" && resource_path[resource_path.length() - 1] == '/') {
|
||||
resource_path = resource_path.substr(0, resource_path.length() - 1); // chop end
|
||||
resource_path = resource_path.substr(0, resource_path.length() - 1); // Chop end.
|
||||
}
|
||||
|
||||
Error err = _load_settings_text_or_binary("res://project.godot", "res://project.binary");
|
||||
if (err == OK) {
|
||||
// Optional, we don't mind if it fails
|
||||
// Optional, we don't mind if it fails.
|
||||
_load_settings_text("res://override.cfg");
|
||||
}
|
||||
return err;
|
||||
|
@ -433,7 +442,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
|
|||
while (true) {
|
||||
err = _load_settings_text_or_binary(current_dir.plus_file("project.godot"), current_dir.plus_file("project.binary"));
|
||||
if (err == OK) {
|
||||
// Optional, we don't mind if it fails
|
||||
// Optional, we don't mind if it fails.
|
||||
_load_settings_text(current_dir.plus_file("override.cfg"));
|
||||
candidate = current_dir;
|
||||
found = true;
|
||||
|
@ -452,14 +461,15 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
|
|||
}
|
||||
|
||||
resource_path = candidate;
|
||||
resource_path = resource_path.replace("\\", "/"); // windows path to unix path just in case
|
||||
resource_path = resource_path.replace("\\", "/"); // Windows path to Unix path just in case.
|
||||
memdelete(d);
|
||||
|
||||
if (!found)
|
||||
return err;
|
||||
|
||||
if (resource_path.length() && resource_path[resource_path.length() - 1] == '/')
|
||||
resource_path = resource_path.substr(0, resource_path.length() - 1); // chop end
|
||||
if (resource_path.length() && resource_path[resource_path.length() - 1] == '/') {
|
||||
resource_path = resource_path.substr(0, resource_path.length() - 1); // Chop end.
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
A node to be used for advanced animation transitions in an [AnimationPlayer].
|
||||
</brief_description>
|
||||
<description>
|
||||
Note: When linked with an [AnimationPlayer], several properties and methods of the corresponding [AnimationPlayer] will not function as expected. Playback and transitions should be handled using only the [AnimationTree] and its constituent [AnimationNode](s). The [AnimationPlayer] node should be used solely for adding, deleting, and editing animations.
|
||||
</description>
|
||||
<tutorials>
|
||||
<link>https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
|
||||
|
@ -23,6 +24,7 @@
|
|||
<return type="Transform">
|
||||
</return>
|
||||
<description>
|
||||
Retrieve the motion of the [member root_motion_track] as a [Transform] that can be used elsewhere. If [member root_motion_track] is not a path to a track of type [constant Animation.TYPE_TRANSFORM], returns an identity transformation.
|
||||
</description>
|
||||
</method>
|
||||
<method name="rename_parameter">
|
||||
|
@ -47,6 +49,8 @@
|
|||
The process mode of this [AnimationTree]. See [enum AnimationProcessMode] for available modes.
|
||||
</member>
|
||||
<member name="root_motion_track" type="NodePath" setter="set_root_motion_track" getter="get_root_motion_track" default="NodePath("")">
|
||||
The path to the Animation track used for root motion. Paths must be valid scene-tree paths to a node, and must be specified starting from the parent node of the node that will reproduce the animation. To specify a track that controls properties or bones, append its name after the path, separated by [code]":"[/code]. For example, [code]"character/skeleton:ankle"[/code] or [code]"character/mesh:transform/local"[/code].
|
||||
If the track has type [constant Animation.TYPE_TRANSFORM], the transformation will be cancelled visually, and the animation will appear to stay in place.
|
||||
</member>
|
||||
<member name="tree_root" type="AnimationNode" setter="set_tree_root" getter="get_tree_root">
|
||||
The root animation node of this [AnimationTree]. See [AnimationNode].
|
||||
|
|
|
@ -65,17 +65,6 @@
|
|||
Creates a BitmapFont from the [code]*.fnt[/code] file at [code]path[/code].
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_char_size" qualifiers="const">
|
||||
<return type="Vector2">
|
||||
</return>
|
||||
<argument index="0" name="char" type="int">
|
||||
</argument>
|
||||
<argument index="1" name="next" type="int" default="0">
|
||||
</argument>
|
||||
<description>
|
||||
Returns the size of a character, optionally taking kerning into account if the next character is provided.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_kerning_pair" qualifiers="const">
|
||||
<return type="int">
|
||||
</return>
|
||||
|
|
|
@ -43,19 +43,19 @@
|
|||
</members>
|
||||
<constants>
|
||||
<constant name="SHADOW_ORTHOGONAL" value="0" enum="ShadowMode">
|
||||
Renders the entire scene's shadow map from an orthogonal point of view. May result in blockier shadows on close objects.
|
||||
Renders the entire scene's shadow map from an orthogonal point of view. This is the fastest directional shadow mode. May result in blurrier shadows on close objects.
|
||||
</constant>
|
||||
<constant name="SHADOW_PARALLEL_2_SPLITS" value="1" enum="ShadowMode">
|
||||
Splits the view frustum in 2 areas, each with its own shadow map.
|
||||
Splits the view frustum in 2 areas, each with its own shadow map. This shadow mode is a compromise between [constant SHADOW_ORTHOGONAL] and [constant SHADOW_PARALLEL_4_SPLITS] in terms of performance.
|
||||
</constant>
|
||||
<constant name="SHADOW_PARALLEL_4_SPLITS" value="2" enum="ShadowMode">
|
||||
Splits the view frustum in 4 areas, each with its own shadow map.
|
||||
Splits the view frustum in 4 areas, each with its own shadow map. This is the slowest directional shadow mode.
|
||||
</constant>
|
||||
<constant name="SHADOW_DEPTH_RANGE_STABLE" value="0" enum="ShadowDepthRange">
|
||||
Keeps the shadow stable when the camera moves, at the cost of lower effective shadow resolution.
|
||||
</constant>
|
||||
<constant name="SHADOW_DEPTH_RANGE_OPTIMIZED" value="1" enum="ShadowDepthRange">
|
||||
Tries to achieve maximum shadow resolution. May result in saw effect on shadow edges.
|
||||
Tries to achieve maximum shadow resolution. May result in saw effect on shadow edges. This mode typically works best in games where the camera will often move at high speeds, such as most racing games.
|
||||
</constant>
|
||||
</constants>
|
||||
</class>
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
</methods>
|
||||
<members>
|
||||
<member name="antialiased" type="bool" setter="set_antialiased" getter="is_antialiased" default="true">
|
||||
If [code]true[/code], the font is rendered with anti-aliasing.
|
||||
If [code]true[/code], the font is rendered with anti-aliasing. This property applies both to the main font and its outline (if it has one).
|
||||
</member>
|
||||
<member name="font_path" type="String" setter="set_font_path" getter="get_font_path" default="""">
|
||||
The path to the vector font file.
|
||||
|
|
|
@ -182,14 +182,6 @@
|
|||
Selects the file, with the path provided by [code]file[/code], in the FileSystem dock.
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_distraction_free_mode">
|
||||
<return type="void">
|
||||
</return>
|
||||
<argument index="0" name="enter" type="bool">
|
||||
</argument>
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_main_screen_editor">
|
||||
<return type="void">
|
||||
</return>
|
||||
|
@ -210,6 +202,10 @@
|
|||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
<members>
|
||||
<member name="distraction_free_mode" type="bool" setter="set_distraction_free_mode" getter="is_distraction_free_mode_enabled">
|
||||
</member>
|
||||
</members>
|
||||
<constants>
|
||||
</constants>
|
||||
</class>
|
||||
|
|
|
@ -54,6 +54,17 @@
|
|||
Returns the font ascent (number of pixels above the baseline).
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_char_size" qualifiers="const">
|
||||
<return type="Vector2">
|
||||
</return>
|
||||
<argument index="0" name="char" type="int">
|
||||
</argument>
|
||||
<argument index="1" name="next" type="int" default="0">
|
||||
</argument>
|
||||
<description>
|
||||
Returns the size of a character, optionally taking kerning into account if the next character is provided.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_descent" qualifiers="const">
|
||||
<return type="float">
|
||||
</return>
|
||||
|
|
|
@ -137,7 +137,7 @@
|
|||
<argument index="0" name="file" type="String">
|
||||
</argument>
|
||||
<description>
|
||||
Saves the configuration to a custom file.
|
||||
Saves the configuration to a custom file. The file extension must be [code].godot[/code] (to save in text-based [ConfigFile] format) or [code].binary[/code] (to save in binary format).
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_initial_value">
|
||||
|
|
|
@ -276,6 +276,8 @@ def main(): # type: () -> None
|
|||
group.add_argument("--dry-run", action="store_true", help="If passed, no output will be generated and XML files are only checked for errors.")
|
||||
args = parser.parse_args()
|
||||
|
||||
print("Checking for errors in the XML class reference...")
|
||||
|
||||
file_list = [] # type: List[str]
|
||||
|
||||
for path in args.path:
|
||||
|
@ -334,7 +336,10 @@ def main(): # type: () -> None
|
|||
state.current_class = class_name
|
||||
make_rst_class(class_def, state, args.dry_run, args.output)
|
||||
|
||||
if state.errored:
|
||||
if not state.errored:
|
||||
print("No errors found.")
|
||||
else:
|
||||
print("Errors were found in the class reference XML. Please check the messages above.")
|
||||
exit(1)
|
||||
|
||||
def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, State, bool, str) -> None
|
||||
|
@ -549,71 +554,6 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
|
|||
index += 1
|
||||
|
||||
|
||||
def make_class_list(class_list, columns): # type: (List[str], int) -> None
|
||||
# This function is no longer used.
|
||||
f = open('class_list.rst', 'w', encoding='utf-8')
|
||||
col_max = len(class_list) // columns + 1
|
||||
print(('col max is ', col_max))
|
||||
fit_columns = [] # type: List[List[str]]
|
||||
|
||||
for _ in range(0, columns):
|
||||
fit_columns.append([])
|
||||
|
||||
indexers = [] # type List[str]
|
||||
last_initial = ''
|
||||
|
||||
for idx, name in enumerate(class_list):
|
||||
col = idx // col_max
|
||||
if col >= columns:
|
||||
col = columns - 1
|
||||
fit_columns[col].append(name)
|
||||
idx += 1
|
||||
if name[:1] != last_initial:
|
||||
indexers.append(name)
|
||||
last_initial = name[:1]
|
||||
|
||||
row_max = 0
|
||||
f.write("\n")
|
||||
|
||||
for n in range(0, columns):
|
||||
if len(fit_columns[n]) > row_max:
|
||||
row_max = len(fit_columns[n])
|
||||
|
||||
f.write("| ")
|
||||
for n in range(0, columns):
|
||||
f.write(" | |")
|
||||
|
||||
f.write("\n")
|
||||
f.write("+")
|
||||
for n in range(0, columns):
|
||||
f.write("--+-------+")
|
||||
f.write("\n")
|
||||
|
||||
for r in range(0, row_max):
|
||||
s = '+ '
|
||||
for c in range(0, columns):
|
||||
if r >= len(fit_columns[c]):
|
||||
continue
|
||||
|
||||
classname = fit_columns[c][r]
|
||||
initial = classname[0]
|
||||
if classname in indexers:
|
||||
s += '**' + initial + '** | '
|
||||
else:
|
||||
s += ' | '
|
||||
|
||||
s += '[' + classname + '](class_' + classname.lower() + ') | '
|
||||
|
||||
s += '\n'
|
||||
f.write(s)
|
||||
|
||||
for n in range(0, columns):
|
||||
f.write("--+-------+")
|
||||
f.write("\n")
|
||||
|
||||
f.close()
|
||||
|
||||
|
||||
def escape_rst(text, until_pos=-1): # type: (str) -> str
|
||||
# Escape \ character, otherwise it ends up as an escape character in rst
|
||||
pos = 0
|
||||
|
|
|
@ -308,10 +308,6 @@ Error DirAccessWindows::remove(String p_path) {
|
|||
|
||||
p_path = fix_path(p_path);
|
||||
|
||||
printf("erasing %s\n", p_path.utf8().get_data());
|
||||
//WIN32_FILE_ATTRIBUTE_DATA fileInfo;
|
||||
//DWORD fileAttr = GetFileAttributesExW(p_path.c_str(), GetFileExInfoStandard, &fileInfo);
|
||||
|
||||
DWORD fileAttr;
|
||||
|
||||
fileAttr = GetFileAttributesW(p_path.c_str());
|
||||
|
|
|
@ -55,13 +55,15 @@ void CreateDialog::popup_create(bool p_dont_clear, bool p_replace_mode, const St
|
|||
|
||||
TreeItem *root = recent->create_item();
|
||||
|
||||
String icon_fallback = has_icon(base_type, "EditorIcons") ? base_type : "Object";
|
||||
|
||||
while (!f->eof_reached()) {
|
||||
String l = f->get_line().strip_edges();
|
||||
String name = l.split(" ")[0];
|
||||
if ((ClassDB::class_exists(name) || ScriptServer::is_global_class(name)) && !_is_class_disabled_by_feature_profile(name)) {
|
||||
TreeItem *ti = recent->create_item(root);
|
||||
ti->set_text(0, l);
|
||||
ti->set_icon(0, EditorNode::get_singleton()->get_class_icon(l, base_type));
|
||||
ti->set_icon(0, EditorNode::get_singleton()->get_class_icon(name, icon_fallback));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -251,7 +253,8 @@ void CreateDialog::add_type(const String &p_type, HashMap<String, TreeItem *> &p
|
|||
const String &description = EditorHelp::get_doc_data()->class_list[p_type].brief_description;
|
||||
item->set_tooltip(0, description);
|
||||
|
||||
item->set_icon(0, EditorNode::get_singleton()->get_class_icon(p_type, base_type));
|
||||
String icon_fallback = has_icon(base_type, "EditorIcons") ? base_type : "Object";
|
||||
item->set_icon(0, EditorNode::get_singleton()->get_class_icon(p_type, icon_fallback));
|
||||
|
||||
p_types[p_type] = item;
|
||||
}
|
||||
|
@ -310,9 +313,8 @@ void CreateDialog::_update_search() {
|
|||
EditorData &ed = EditorNode::get_editor_data();
|
||||
|
||||
root->set_text(0, base_type);
|
||||
if (has_icon(base_type, "EditorIcons")) {
|
||||
root->set_icon(0, get_icon(base_type, "EditorIcons"));
|
||||
}
|
||||
String base_icon = has_icon(base_type, "EditorIcons") ? base_type : "Object";
|
||||
root->set_icon(0, get_icon(base_icon, "EditorIcons"));
|
||||
|
||||
TreeItem *to_select = search_box->get_text() == base_type ? root : NULL;
|
||||
|
||||
|
@ -395,9 +397,7 @@ void CreateDialog::_update_search() {
|
|||
TreeItem *item = search_options->create_item(ti);
|
||||
item->set_metadata(0, type);
|
||||
item->set_text(0, ct[i].name);
|
||||
if (ct[i].icon.is_valid()) {
|
||||
item->set_icon(0, ct[i].icon);
|
||||
}
|
||||
item->set_icon(0, ct[i].icon.is_valid() ? ct[i].icon : get_icon(base_icon, "EditorIcons"));
|
||||
|
||||
if (!to_select || ct[i].name == search_box->get_text()) {
|
||||
to_select = item;
|
||||
|
@ -600,15 +600,20 @@ void CreateDialog::_save_favorite_list() {
|
|||
void CreateDialog::_update_favorite_list() {
|
||||
|
||||
favorites->clear();
|
||||
|
||||
TreeItem *root = favorites->create_item();
|
||||
|
||||
String icon_fallback = has_icon(base_type, "EditorIcons") ? base_type : "Object";
|
||||
|
||||
for (int i = 0; i < favorite_list.size(); i++) {
|
||||
String l = favorite_list[i];
|
||||
String name = l.split(" ")[0];
|
||||
if (!((ClassDB::class_exists(name) || ScriptServer::is_global_class(name)) && !_is_class_disabled_by_feature_profile(name)))
|
||||
continue;
|
||||
|
||||
TreeItem *ti = favorites->create_item(root);
|
||||
ti->set_text(0, l);
|
||||
ti->set_icon(0, EditorNode::get_singleton()->get_class_icon(l, base_type));
|
||||
ti->set_icon(0, EditorNode::get_singleton()->get_class_icon(name, icon_fallback));
|
||||
}
|
||||
emit_signal("favorites_updated");
|
||||
}
|
||||
|
|
|
@ -669,18 +669,18 @@ bool EditorAutoloadSettings::autoload_add(const String &p_name, const String &p_
|
|||
|
||||
String error;
|
||||
if (!_autoload_name_is_valid(name, &error)) {
|
||||
EditorNode::get_singleton()->show_warning(error);
|
||||
EditorNode::get_singleton()->show_warning(TTR("Can't add autoload:") + "\n" + error);
|
||||
return false;
|
||||
}
|
||||
|
||||
const String &path = p_path;
|
||||
if (!FileAccess::exists(path)) {
|
||||
EditorNode::get_singleton()->show_warning(TTR("Invalid path.") + "\n" + TTR("File does not exist."));
|
||||
EditorNode::get_singleton()->show_warning(TTR("Can't add autoload:") + "\n" + TTR(vformat("%s is an invalid path. File does not exist.", path)));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!path.begins_with("res://")) {
|
||||
EditorNode::get_singleton()->show_warning(TTR("Invalid path.") + "\n" + TTR("Not in resource path."));
|
||||
EditorNode::get_singleton()->show_warning(TTR("Can't add autoload:") + "\n" + TTR(vformat("%s is an invalid path. Not in resource path (res://).", path)));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -2847,8 +2847,8 @@ void EditorNode::_update_debug_options() {
|
|||
bool check_file_server = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_file_server", false);
|
||||
bool check_debug_collisons = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_debug_collisons", false);
|
||||
bool check_debug_navigation = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_debug_navigation", false);
|
||||
bool check_live_debug = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_live_debug", false);
|
||||
bool check_reload_scripts = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_reload_scripts", false);
|
||||
bool check_live_debug = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_live_debug", true);
|
||||
bool check_reload_scripts = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_reload_scripts", true);
|
||||
|
||||
if (check_deploy_remote) _menu_option_confirm(RUN_DEPLOY_REMOTE_DEBUG, true);
|
||||
if (check_file_server) _menu_option_confirm(RUN_FILE_SERVER, true);
|
||||
|
@ -4945,7 +4945,7 @@ void EditorNode::set_distraction_free_mode(bool p_enter) {
|
|||
}
|
||||
}
|
||||
|
||||
bool EditorNode::get_distraction_free_mode() const {
|
||||
bool EditorNode::is_distraction_free_mode_enabled() const {
|
||||
return distraction_free->is_pressed();
|
||||
}
|
||||
|
||||
|
@ -6229,13 +6229,10 @@ EditorNode::EditorNode() {
|
|||
p->add_check_shortcut(ED_SHORTCUT("editor/visible_navigation", TTR("Visible Navigation")), RUN_DEBUG_NAVIGATION);
|
||||
p->set_item_tooltip(p->get_item_count() - 1, TTR("Navigation meshes and polygons will be visible on the running game if this option is turned on."));
|
||||
p->add_separator();
|
||||
//those are now on by default, since they are harmless
|
||||
p->add_check_shortcut(ED_SHORTCUT("editor/sync_scene_changes", TTR("Sync Scene Changes")), RUN_LIVE_DEBUG);
|
||||
p->set_item_tooltip(p->get_item_count() - 1, TTR("When this option is turned on, any changes made to the scene in the editor will be replicated in the running game.\nWhen used remotely on a device, this is more efficient with network filesystem."));
|
||||
p->set_item_checked(p->get_item_count() - 1, true);
|
||||
p->add_check_shortcut(ED_SHORTCUT("editor/sync_script_changes", TTR("Sync Script Changes")), RUN_RELOAD_SCRIPTS);
|
||||
p->set_item_tooltip(p->get_item_count() - 1, TTR("When this option is turned on, any script that is saved will be reloaded on the running game.\nWhen used remotely on a device, this is more efficient with network filesystem."));
|
||||
p->set_item_checked(p->get_item_count() - 1, true);
|
||||
p->connect("id_pressed", this, "_menu_option");
|
||||
|
||||
menu_hb->add_spacer();
|
||||
|
|
|
@ -691,7 +691,7 @@ public:
|
|||
bool get_docks_visible() const;
|
||||
|
||||
void set_distraction_free_mode(bool p_enter);
|
||||
bool get_distraction_free_mode() const;
|
||||
bool is_distraction_free_mode_enabled() const;
|
||||
|
||||
void add_control_to_dock(DockSlot p_slot, Control *p_control);
|
||||
void remove_control_from_dock(Control *p_control);
|
||||
|
|
|
@ -281,6 +281,10 @@ void EditorInterface::set_distraction_free_mode(bool p_enter) {
|
|||
|
||||
EditorInterface *EditorInterface::singleton = NULL;
|
||||
|
||||
bool EditorInterface::is_distraction_free_mode_enabled() const {
|
||||
return EditorNode::get_singleton()->is_distraction_free_mode_enabled();
|
||||
}
|
||||
|
||||
void EditorInterface::_bind_methods() {
|
||||
|
||||
ClassDB::bind_method(D_METHOD("inspect_object", "object", "for_property"), &EditorInterface::inspect_object, DEFVAL(String()));
|
||||
|
@ -312,6 +316,9 @@ void EditorInterface::_bind_methods() {
|
|||
|
||||
ClassDB::bind_method(D_METHOD("set_main_screen_editor", "name"), &EditorInterface::set_main_screen_editor);
|
||||
ClassDB::bind_method(D_METHOD("set_distraction_free_mode", "enter"), &EditorInterface::set_distraction_free_mode);
|
||||
ClassDB::bind_method(D_METHOD("is_distraction_free_mode_enabled"), &EditorInterface::is_distraction_free_mode_enabled);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "distraction_free_mode"), "set_distraction_free_mode", "is_distraction_free_mode_enabled");
|
||||
}
|
||||
|
||||
EditorInterface::EditorInterface() {
|
||||
|
|
|
@ -105,6 +105,7 @@ public:
|
|||
|
||||
void set_main_screen_editor(const String &p_name);
|
||||
void set_distraction_free_mode(bool p_enter);
|
||||
bool is_distraction_free_mode_enabled() const;
|
||||
|
||||
EditorInterface();
|
||||
};
|
||||
|
|
|
@ -81,7 +81,7 @@ String ResourceImporterLayeredTexture::get_preset_name(int p_idx) const {
|
|||
|
||||
void ResourceImporterLayeredTexture::get_import_options(List<ImportOption> *r_options, int p_preset) const {
|
||||
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/mode", PROPERTY_HINT_ENUM, "Lossless,Video RAM,Uncompressed", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), p_preset == PRESET_3D ? 1 : 0));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/mode", PROPERTY_HINT_ENUM, "Lossless (PNG),Lossy (WebP),Video RAM (S3TC/ETC/BPTC),Uncompressed", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), p_preset == PRESET_3D ? 1 : 0));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "compress/no_bptc_if_rgb"), false));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "flags/repeat", PROPERTY_HINT_ENUM, "Disabled,Enabled,Mirrored"), 0));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "flags/filter"), true));
|
||||
|
|
|
@ -137,7 +137,8 @@ static void _plot_triangle(Vector2 *vertices, const Vector2 &p_offset, bool p_tr
|
|||
double dx_low = double(x[2] - x[1]) / (y[2] - y[1] + 1);
|
||||
double xf = x[0];
|
||||
double xt = x[0] + dx_upper; // if y[0] == y[1], special case
|
||||
for (int yi = y[0]; yi <= (y[2] > height - 1 ? height - 1 : y[2]); yi++) {
|
||||
int max_y = MIN(y[2], height - p_offset.y - 1);
|
||||
for (int yi = y[0]; yi <= max_y; yi++) {
|
||||
if (yi >= 0) {
|
||||
for (int xi = (xf > 0 ? int(xf) : 0); xi <= (xt < width ? xt : width - 1); xi++) {
|
||||
|
||||
|
|
|
@ -86,7 +86,6 @@ public:
|
|||
GridContainer *child_container;
|
||||
|
||||
set_title(TTR("Configure Snap"));
|
||||
get_ok()->set_text(TTR("Close"));
|
||||
|
||||
container = memnew(VBoxContainer);
|
||||
add_child(container);
|
||||
|
@ -5490,6 +5489,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
|
|||
hb->add_child(pan_button);
|
||||
pan_button->set_toggle_mode(true);
|
||||
pan_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_PAN));
|
||||
pan_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/pan_mode", TTR("Pan Mode"), KEY_G));
|
||||
pan_button->set_tooltip(TTR("Pan Mode"));
|
||||
|
||||
ruler_button = memnew(ToolButton);
|
||||
|
|
|
@ -625,6 +625,18 @@ void ScriptTextEditor::_validate_script() {
|
|||
for (List<ScriptLanguage::Warning>::Element *E = warnings.front(); E; E = E->next()) {
|
||||
ScriptLanguage::Warning w = E->get();
|
||||
|
||||
Dictionary ignore_meta;
|
||||
ignore_meta["line"] = w.line;
|
||||
ignore_meta["code"] = w.string_code.to_lower();
|
||||
warnings_panel->push_cell();
|
||||
warnings_panel->push_meta(ignore_meta);
|
||||
warnings_panel->push_color(
|
||||
warnings_panel->get_color("accent_color", "Editor").linear_interpolate(warnings_panel->get_color("mono_color", "Editor"), 0.5));
|
||||
warnings_panel->add_text(TTR("[Ignore]"));
|
||||
warnings_panel->pop(); // Color.
|
||||
warnings_panel->pop(); // Meta ignore.
|
||||
warnings_panel->pop(); // Cell.
|
||||
|
||||
warnings_panel->push_cell();
|
||||
warnings_panel->push_meta(w.line - 1);
|
||||
warnings_panel->push_color(warnings_panel->get_color("warning_color", "Editor"));
|
||||
|
@ -637,15 +649,6 @@ void ScriptTextEditor::_validate_script() {
|
|||
warnings_panel->push_cell();
|
||||
warnings_panel->add_text(w.message);
|
||||
warnings_panel->pop(); // Cell.
|
||||
|
||||
Dictionary ignore_meta;
|
||||
ignore_meta["line"] = w.line;
|
||||
ignore_meta["code"] = w.string_code.to_lower();
|
||||
warnings_panel->push_cell();
|
||||
warnings_panel->push_meta(ignore_meta);
|
||||
warnings_panel->add_text(TTR("(ignore)"));
|
||||
warnings_panel->pop(); // Meta ignore.
|
||||
warnings_panel->pop(); // Cell.
|
||||
}
|
||||
warnings_panel->pop(); // Table.
|
||||
|
||||
|
@ -1805,6 +1808,8 @@ ScriptTextEditor::ScriptTextEditor() {
|
|||
|
||||
warnings_panel = memnew(RichTextLabel);
|
||||
editor_box->add_child(warnings_panel);
|
||||
warnings_panel->add_font_override(
|
||||
"normal_font", EditorNode::get_singleton()->get_gui_base()->get_font("main", "EditorFonts"));
|
||||
warnings_panel->set_custom_minimum_size(Size2(0, 100 * EDSCALE));
|
||||
warnings_panel->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
warnings_panel->set_meta_underline(true);
|
||||
|
|
|
@ -205,6 +205,21 @@ void TileMapEditor::_palette_multi_selected(int index, bool selected) {
|
|||
_update_palette();
|
||||
}
|
||||
|
||||
void TileMapEditor::_palette_input(const Ref<InputEvent> &p_event) {
|
||||
const Ref<InputEventMouseButton> mb = p_event;
|
||||
|
||||
// Zoom in/out using Ctrl + mouse wheel.
|
||||
if (mb.is_valid() && mb->is_pressed() && mb->get_command()) {
|
||||
if (mb->is_pressed() && mb->get_button_index() == BUTTON_WHEEL_UP) {
|
||||
size_slider->set_value(size_slider->get_value() + 0.2);
|
||||
}
|
||||
|
||||
if (mb->is_pressed() && mb->get_button_index() == BUTTON_WHEEL_DOWN) {
|
||||
size_slider->set_value(size_slider->get_value() - 0.2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TileMapEditor::_canvas_mouse_enter() {
|
||||
|
||||
mouse_over = true;
|
||||
|
@ -1834,6 +1849,7 @@ void TileMapEditor::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("_clear_transform"), &TileMapEditor::_clear_transform);
|
||||
ClassDB::bind_method(D_METHOD("_palette_selected"), &TileMapEditor::_palette_selected);
|
||||
ClassDB::bind_method(D_METHOD("_palette_multi_selected"), &TileMapEditor::_palette_multi_selected);
|
||||
ClassDB::bind_method(D_METHOD("_palette_input"), &TileMapEditor::_palette_input);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("_fill_points"), &TileMapEditor::_fill_points);
|
||||
ClassDB::bind_method(D_METHOD("_erase_points"), &TileMapEditor::_erase_points);
|
||||
|
@ -1996,6 +2012,7 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) {
|
|||
palette->add_constant_override("vseparation", 8 * EDSCALE);
|
||||
palette->connect("item_selected", this, "_palette_selected");
|
||||
palette->connect("multi_selected", this, "_palette_multi_selected");
|
||||
palette->connect("gui_input", this, "_palette_input");
|
||||
palette_container->add_child(palette);
|
||||
|
||||
// Add message for when no texture is selected.
|
||||
|
@ -2034,7 +2051,7 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) {
|
|||
toolbar->add_child(paint_button);
|
||||
|
||||
bucket_fill_button = memnew(ToolButton);
|
||||
bucket_fill_button->set_shortcut(ED_SHORTCUT("tile_map_editor/bucket_fill", TTR("Bucket Fill"), KEY_G));
|
||||
bucket_fill_button->set_shortcut(ED_SHORTCUT("tile_map_editor/bucket_fill", TTR("Bucket Fill"), KEY_B));
|
||||
bucket_fill_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_BUCKET));
|
||||
bucket_fill_button->set_toggle_mode(true);
|
||||
toolbar->add_child(bucket_fill_button);
|
||||
|
|
|
@ -192,6 +192,7 @@ class TileMapEditor : public VBoxContainer {
|
|||
void _menu_option(int p_option);
|
||||
void _palette_selected(int index);
|
||||
void _palette_multi_selected(int index, bool selected);
|
||||
void _palette_input(const Ref<InputEvent> &p_event);
|
||||
|
||||
Dictionary _create_cell_dictionary(int tile, bool flip_x, bool flip_y, bool transpose, Vector2 autotile_coord);
|
||||
void _start_undo(const String &p_action);
|
||||
|
|
|
@ -265,6 +265,7 @@ void TileSetEditor::_bind_methods() {
|
|||
ClassDB::bind_method("_on_tileset_toolbar_confirm", &TileSetEditor::_on_tileset_toolbar_confirm);
|
||||
ClassDB::bind_method("_on_texture_list_selected", &TileSetEditor::_on_texture_list_selected);
|
||||
ClassDB::bind_method("_on_edit_mode_changed", &TileSetEditor::_on_edit_mode_changed);
|
||||
ClassDB::bind_method("_on_scroll_container_input", &TileSetEditor::_on_scroll_container_input);
|
||||
ClassDB::bind_method("_on_workspace_mode_changed", &TileSetEditor::_on_workspace_mode_changed);
|
||||
ClassDB::bind_method("_on_workspace_overlay_draw", &TileSetEditor::_on_workspace_overlay_draw);
|
||||
ClassDB::bind_method("_on_workspace_process", &TileSetEditor::_on_workspace_process);
|
||||
|
@ -592,6 +593,7 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) {
|
|||
scroll = memnew(ScrollContainer);
|
||||
main_vb->add_child(scroll);
|
||||
scroll->set_v_size_flags(SIZE_EXPAND_FILL);
|
||||
scroll->connect("gui_input", this, "_on_scroll_container_input");
|
||||
scroll->set_clip_contents(true);
|
||||
|
||||
empty_message = memnew(Label);
|
||||
|
@ -1216,6 +1218,27 @@ bool TileSetEditor::is_within_grabbing_distance_of_first_point(const Vector2 &p_
|
|||
return distance < p_grab_threshold;
|
||||
}
|
||||
|
||||
void TileSetEditor::_on_scroll_container_input(const Ref<InputEvent> &p_event) {
|
||||
const Ref<InputEventMouseButton> mb = p_event;
|
||||
|
||||
if (mb.is_valid()) {
|
||||
// Zoom in/out using Ctrl + mouse wheel. This is done on the ScrollContainer
|
||||
// to allow performing this action anywhere, even if the cursor isn't
|
||||
// hovering the texture in the workspace.
|
||||
if (mb->get_button_index() == BUTTON_WHEEL_UP && mb->is_pressed() && mb->get_control()) {
|
||||
print_line("zooming in");
|
||||
_zoom_in();
|
||||
// Don't scroll up after zooming in.
|
||||
accept_event();
|
||||
} else if (mb->get_button_index() == BUTTON_WHEEL_DOWN && mb->is_pressed() && mb->get_control()) {
|
||||
print_line("zooming out");
|
||||
_zoom_out();
|
||||
// Don't scroll down after zooming out.
|
||||
accept_event();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
|
||||
|
||||
if (tileset.is_null() || !get_current_texture().is_valid())
|
||||
|
@ -1232,8 +1255,8 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
|
|||
}
|
||||
current_tile_region.position += WORKSPACE_MARGIN;
|
||||
|
||||
Ref<InputEventMouseButton> mb = p_ie;
|
||||
Ref<InputEventMouseMotion> mm = p_ie;
|
||||
const Ref<InputEventMouseButton> mb = p_ie;
|
||||
const Ref<InputEventMouseMotion> mm = p_ie;
|
||||
|
||||
if (mb.is_valid()) {
|
||||
if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && !creating_shape) {
|
||||
|
@ -1257,13 +1280,6 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
|
|||
delete tiles;
|
||||
}
|
||||
}
|
||||
|
||||
// Mouse Wheel Event
|
||||
if (mb->get_button_index() == BUTTON_WHEEL_UP && mb->is_pressed() && mb->get_control()) {
|
||||
_zoom_in();
|
||||
} else if (mb->get_button_index() == BUTTON_WHEEL_DOWN && mb->is_pressed() && mb->get_control()) {
|
||||
_zoom_out();
|
||||
}
|
||||
}
|
||||
// Drag Middle Mouse
|
||||
if (mm.is_valid()) {
|
||||
|
|
|
@ -201,6 +201,7 @@ private:
|
|||
void _on_workspace_overlay_draw();
|
||||
void _on_workspace_draw();
|
||||
void _on_workspace_process();
|
||||
void _on_scroll_container_input(const Ref<InputEvent> &p_event);
|
||||
void _on_workspace_input(const Ref<InputEvent> &p_ie);
|
||||
void _on_tool_clicked(int p_tool);
|
||||
void _on_priority_changed(float val);
|
||||
|
|
|
@ -945,6 +945,8 @@ public:
|
|||
icon = NULL;
|
||||
icon_needs_reload = true;
|
||||
hover = false;
|
||||
|
||||
set_focus_mode(FocusMode::FOCUS_ALL);
|
||||
}
|
||||
|
||||
void set_is_favorite(bool fav) {
|
||||
|
@ -1728,6 +1730,10 @@ void ProjectList::_panel_input(const Ref<InputEvent> &p_ev, Node *p_hb) {
|
|||
select_project(clicked_index);
|
||||
}
|
||||
|
||||
if (_selected_project_keys.has(clicked_project.project_key)) {
|
||||
clicked_project.control->grab_focus();
|
||||
}
|
||||
|
||||
emit_signal(SIGNAL_SELECTION_CHANGED);
|
||||
|
||||
if (!mb->get_control() && mb->is_doubleclick()) {
|
||||
|
|
|
@ -2591,6 +2591,11 @@ void SceneTreeDock::_focus_node() {
|
|||
}
|
||||
|
||||
void SceneTreeDock::attach_script_to_selected(bool p_extend) {
|
||||
if (ScriptServer::get_language_count() == 0) {
|
||||
EditorNode::get_singleton()->show_warning(TTR("Cannot attach a script: there are no languages registered.\nThis is probably because this editor was built with all language modules disabled."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!profile_allow_script_editing) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -800,7 +800,7 @@ ScriptCreateDialog::ScriptCreateDialog() {
|
|||
gc->add_child(memnew(Label(TTR("Language:"))));
|
||||
gc->add_child(language_menu);
|
||||
|
||||
default_language = 0;
|
||||
default_language = -1;
|
||||
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
|
||||
|
||||
String lang = ScriptServer::get_language(i)->get_name();
|
||||
|
@ -809,8 +809,9 @@ ScriptCreateDialog::ScriptCreateDialog() {
|
|||
default_language = i;
|
||||
}
|
||||
}
|
||||
|
||||
language_menu->select(default_language);
|
||||
if (default_language >= 0) {
|
||||
language_menu->select(default_language);
|
||||
}
|
||||
current_language = default_language;
|
||||
|
||||
language_menu->connect("item_selected", this, "_lang_changed");
|
||||
|
|
|
@ -149,7 +149,7 @@ def detect_modules(at_path):
|
|||
|
||||
|
||||
def is_module(path):
|
||||
return os.path.isdir(path) and os.path.exists(path + "/config.py")
|
||||
return os.path.isdir(path) and os.path.exists(os.path.join(path, "SCsub"))
|
||||
|
||||
|
||||
def write_modules(module_list):
|
||||
|
|
|
@ -1501,11 +1501,14 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||
|
||||
#ifdef DEBUG_ENABLED
|
||||
GET_VARIANT_PTR(test, 1);
|
||||
GET_VARIANT_PTR(message, 2);
|
||||
bool result = test->booleanize();
|
||||
|
||||
if (!result) {
|
||||
const String &message_str = *message;
|
||||
String message_str;
|
||||
if (_code_ptr[ip + 2] != 0) {
|
||||
GET_VARIANT_PTR(message, 2);
|
||||
message_str = *message;
|
||||
}
|
||||
if (message_str.empty()) {
|
||||
err_text = "Assertion failed.";
|
||||
} else {
|
||||
|
|
|
@ -2629,7 +2629,9 @@ bool CSharpScript::_get_member_export(IMonoClassMember *p_member, bool p_inspect
|
|||
return true;
|
||||
}
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
MonoObject *attr = p_member->get_attribute(CACHED_CLASS(ExportAttribute));
|
||||
#endif
|
||||
|
||||
PropertyHint hint = PROPERTY_HINT_NONE;
|
||||
String hint_string;
|
||||
|
|
|
@ -436,7 +436,7 @@ namespace GodotTools
|
|||
aboutLabel.Text =
|
||||
"C# support in Godot Engine is in late alpha stage and, while already usable, " +
|
||||
"it is not meant for use in production.\n\n" +
|
||||
"Projects can be exported to Linux, macOS, Windows and Android, but not yet to iOS, HTML5 or UWP. " +
|
||||
"Projects can be exported to Linux, macOS, Windows, Android, iOS and HTML5, but not yet to UWP. " +
|
||||
"Bugs and usability issues will be addressed gradually over future releases, " +
|
||||
"potentially including compatibility breaking changes as new features are implemented for a better overall C# experience.\n\n" +
|
||||
"If you experience issues with this Mono build, please report them on Godot's issue tracker with details about your system, MSBuild version, IDE, etc.:\n\n" +
|
||||
|
|
|
@ -425,10 +425,10 @@ void GDMono::initialize_load_assemblies() {
|
|||
#if defined(TOOLS_ENABLED)
|
||||
bool tool_assemblies_loaded = _load_tools_assemblies();
|
||||
CRASH_COND_MSG(!tool_assemblies_loaded, "Mono: Failed to load '" TOOLS_ASM_NAME "' assemblies.");
|
||||
#endif
|
||||
|
||||
if (Main::is_project_manager())
|
||||
return;
|
||||
#endif
|
||||
|
||||
// Load the project's main assembly. This doesn't necessarily need to succeed.
|
||||
// The game may not be using .NET at all, or if the project does use .NET and
|
||||
|
|
|
@ -3126,6 +3126,7 @@ void VisualScriptEditor::_move_nodes_with_rescan(const StringName &p_func_from,
|
|||
{
|
||||
List<VisualScript::DataConnection> data_connections;
|
||||
script->get_data_connection_list(p_func_from, &data_connections);
|
||||
int func_from_node_id = script->get_function_node_id(p_func_from);
|
||||
|
||||
HashMap<int, Map<int, Pair<int, int> > > connections;
|
||||
|
||||
|
@ -3135,6 +3136,11 @@ void VisualScriptEditor::_move_nodes_with_rescan(const StringName &p_func_from,
|
|||
int out_p = E->get().from_port;
|
||||
int in_p = E->get().to_port;
|
||||
|
||||
// skip if the from_node is a function node
|
||||
if (from == func_from_node_id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!connections.has(to))
|
||||
connections.set(to, Map<int, Pair<int, int> >());
|
||||
connections[to].insert(in_p, Pair<int, int>(from, out_p));
|
||||
|
|
|
@ -68,7 +68,7 @@ bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver
|
|||
ERR_FAIL_COND_V_MSG(err != xatlas::AddMeshError::Enum::Success, false, xatlas::StringForEnum(err));
|
||||
|
||||
printf("Generate..\n");
|
||||
xatlas::Generate(atlas, chart_options, NULL, pack_options);
|
||||
xatlas::Generate(atlas, chart_options, xatlas::ParameterizeOptions(), pack_options);
|
||||
|
||||
*r_size_hint_x = atlas->width;
|
||||
*r_size_hint_y = atlas->height;
|
||||
|
|
|
@ -257,6 +257,8 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
|
|||
};
|
||||
|
||||
Vector<PluginConfig> plugins;
|
||||
String last_plugin_names;
|
||||
uint64_t last_custom_build_time = 0;
|
||||
volatile bool plugins_changed;
|
||||
Mutex *plugins_lock;
|
||||
Vector<Device> devices;
|
||||
|
@ -1786,23 +1788,32 @@ public:
|
|||
// Look for export templates (first official, and if defined custom templates).
|
||||
|
||||
if (!bool(p_preset->get("custom_template/use_custom_build"))) {
|
||||
bool dvalid = exists_export_template("android_debug.apk", &err);
|
||||
bool rvalid = exists_export_template("android_release.apk", &err);
|
||||
String template_err;
|
||||
bool dvalid = false;
|
||||
bool rvalid = false;
|
||||
|
||||
if (p_preset->get("custom_template/debug") != "") {
|
||||
dvalid = FileAccess::exists(p_preset->get("custom_template/debug"));
|
||||
if (!dvalid) {
|
||||
err += TTR("Custom debug template not found.") + "\n";
|
||||
template_err += TTR("Custom debug template not found.") + "\n";
|
||||
}
|
||||
} else {
|
||||
dvalid = exists_export_template("android_debug.apk", &template_err);
|
||||
}
|
||||
|
||||
if (p_preset->get("custom_template/release") != "") {
|
||||
rvalid = FileAccess::exists(p_preset->get("custom_template/release"));
|
||||
if (!rvalid) {
|
||||
err += TTR("Custom release template not found.") + "\n";
|
||||
template_err += TTR("Custom release template not found.") + "\n";
|
||||
}
|
||||
} else {
|
||||
rvalid = exists_export_template("android_release.apk", &template_err);
|
||||
}
|
||||
|
||||
valid = dvalid || rvalid;
|
||||
if (!valid) {
|
||||
err += template_err;
|
||||
}
|
||||
} else {
|
||||
valid = exists_export_template("android_source.zip", &err);
|
||||
}
|
||||
|
@ -2201,6 +2212,29 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
inline bool is_clean_build_required(Vector<PluginConfig> enabled_plugins) {
|
||||
String plugin_names = get_plugins_names(enabled_plugins);
|
||||
bool first_build = last_custom_build_time == 0;
|
||||
bool have_plugins_changed = false;
|
||||
|
||||
if (!first_build) {
|
||||
have_plugins_changed = plugin_names != last_plugin_names;
|
||||
if (!have_plugins_changed) {
|
||||
for (int i = 0; i < enabled_plugins.size(); i++) {
|
||||
if (enabled_plugins.get(i).last_updated > last_custom_build_time) {
|
||||
have_plugins_changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
last_custom_build_time = OS::get_singleton()->get_unix_time();
|
||||
last_plugin_names = plugin_names;
|
||||
|
||||
return have_plugins_changed || first_build;
|
||||
}
|
||||
|
||||
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) {
|
||||
|
||||
ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
|
||||
|
@ -2250,8 +2284,12 @@ public:
|
|||
String local_plugins_binaries = get_plugins_binaries(BINARY_TYPE_LOCAL, enabled_plugins);
|
||||
String remote_plugins_binaries = get_plugins_binaries(BINARY_TYPE_REMOTE, enabled_plugins);
|
||||
String custom_maven_repos = get_plugins_custom_maven_repos(enabled_plugins);
|
||||
bool clean_build_required = is_clean_build_required(enabled_plugins);
|
||||
|
||||
List<String> cmdline;
|
||||
if (clean_build_required) {
|
||||
cmdline.push_back("clean");
|
||||
}
|
||||
cmdline.push_back("build");
|
||||
cmdline.push_back("-Pexport_package_name=" + package_name); // argument to specify the package name.
|
||||
cmdline.push_back("-Pplugins_local_binaries=" + local_plugins_binaries); // argument to specify the list of plugins local dependencies.
|
||||
|
|
|
@ -87,6 +87,11 @@ android {
|
|||
}
|
||||
|
||||
defaultConfig {
|
||||
// The default ignore pattern for the 'assets' directory includes hidden files and directories which are used by Godot projects.
|
||||
aaptOptions {
|
||||
ignoreAssetsPattern "!.svn:!.git:!.ds_store:!*.scc:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"
|
||||
}
|
||||
|
||||
// Feel free to modify the application id to your own.
|
||||
applicationId getExportPackageName()
|
||||
minSdkVersion versions.minSdk
|
||||
|
|
|
@ -70,6 +70,8 @@ The `dependencies` section and fields are optional and defined as follow:
|
|||
struct PluginConfig {
|
||||
// Set to true when the config file is properly loaded.
|
||||
bool valid_config = false;
|
||||
// Unix timestamp of last change to this plugin.
|
||||
uint64_t last_updated = 0;
|
||||
|
||||
// Required config section
|
||||
String name;
|
||||
|
@ -87,6 +89,7 @@ struct PluginConfig {
|
|||
*/
|
||||
static const PluginConfig GODOT_PAYMENT = {
|
||||
/*.valid_config =*/true,
|
||||
/*.last_updated =*/0,
|
||||
/*.name =*/"GodotPayment",
|
||||
/*.binary_type =*/"local",
|
||||
/*.binary =*/"res://android/build/libs/plugins/GodotPayment.release.aar",
|
||||
|
@ -150,6 +153,18 @@ static inline bool is_plugin_config_valid(PluginConfig plugin_config) {
|
|||
return valid_name && valid_binary && valid_binary_type && valid_local_dependencies;
|
||||
}
|
||||
|
||||
static inline uint64_t get_plugin_modification_time(const PluginConfig &plugin_config, const String &config_path) {
|
||||
uint64_t last_updated = FileAccess::get_modified_time(config_path);
|
||||
last_updated = MAX(last_updated, FileAccess::get_modified_time(plugin_config.binary));
|
||||
|
||||
for (int i = 0; i < plugin_config.local_dependencies.size(); i++) {
|
||||
String binary = plugin_config.local_dependencies.get(i);
|
||||
last_updated = MAX(last_updated, FileAccess::get_modified_time(binary));
|
||||
}
|
||||
|
||||
return last_updated;
|
||||
}
|
||||
|
||||
static inline PluginConfig load_plugin_config(Ref<ConfigFile> config_file, const String &path) {
|
||||
PluginConfig plugin_config = {};
|
||||
|
||||
|
@ -177,6 +192,7 @@ static inline PluginConfig load_plugin_config(Ref<ConfigFile> config_file, const
|
|||
}
|
||||
|
||||
plugin_config.valid_config = is_plugin_config_valid(plugin_config);
|
||||
plugin_config.last_updated = get_plugin_modification_time(plugin_config, path);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -314,9 +314,16 @@ bool JoypadOSX::configure_joypad(IOHIDDeviceRef p_device_ref, joypad *p_joy) {
|
|||
if (refCF) {
|
||||
CFNumberGetValue((CFNumberRef)refCF, kCFNumberSInt32Type, &product_id);
|
||||
}
|
||||
|
||||
int version = 0;
|
||||
refCF = IOHIDDeviceGetProperty(p_device_ref, CFSTR(kIOHIDVersionNumberKey));
|
||||
if (refCF) {
|
||||
CFNumberGetValue((CFNumberRef)refCF, kCFNumberSInt32Type, &version);
|
||||
}
|
||||
|
||||
if (vendor && product_id) {
|
||||
char uid[128];
|
||||
sprintf(uid, "%04x%08x%04x%08x", OSSwapHostToBigInt32(vendor), 0, OSSwapHostToBigInt32(product_id), 0);
|
||||
sprintf(uid, "%08x%08x%08x%08x", OSSwapHostToBigInt32(3), OSSwapHostToBigInt32(vendor), OSSwapHostToBigInt32(product_id), OSSwapHostToBigInt32(version));
|
||||
input->joy_connection_changed(id, true, name, uid);
|
||||
} else {
|
||||
//bluetooth device
|
||||
|
|
|
@ -33,10 +33,6 @@
|
|||
#include <oleauto.h>
|
||||
#include <wbemidl.h>
|
||||
|
||||
#ifndef __GNUC__
|
||||
#define __builtin_bswap32 _byteswap_ulong
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__)
|
||||
// Workaround GCC warning from -Wcast-function-type.
|
||||
#define GetProcAddress (void *)GetProcAddress
|
||||
|
@ -67,18 +63,26 @@ JoypadWindows::JoypadWindows(InputDefault *_input, HWND *hwnd) {
|
|||
for (int i = 0; i < JOYPADS_MAX; i++)
|
||||
attached_joypads[i] = false;
|
||||
|
||||
HRESULT result;
|
||||
result = DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void **)&dinput, NULL);
|
||||
if (FAILED(result)) {
|
||||
printf("failed init DINPUT: %ld\n", result);
|
||||
HRESULT result = DirectInput8Create(GetModuleHandle(nullptr), DIRECTINPUT_VERSION, IID_IDirectInput8, (void **)&dinput, nullptr);
|
||||
if (result == DI_OK) {
|
||||
probe_joypads();
|
||||
} else {
|
||||
ERR_PRINT("Couldn't initialize DirectInput. Error: " + itos(result));
|
||||
if (result == DIERR_OUTOFMEMORY) {
|
||||
ERR_PRINT("The Windows DirectInput subsystem could not allocate sufficient memory.");
|
||||
ERR_PRINT("Rebooting your PC may solve this issue.");
|
||||
}
|
||||
// Ensure dinput is still a nullptr.
|
||||
dinput = nullptr;
|
||||
}
|
||||
probe_joypads();
|
||||
}
|
||||
|
||||
JoypadWindows::~JoypadWindows() {
|
||||
|
||||
close_joypad();
|
||||
dinput->Release();
|
||||
if (dinput) {
|
||||
dinput->Release();
|
||||
}
|
||||
unload_xinput();
|
||||
}
|
||||
|
||||
|
@ -142,6 +146,7 @@ bool JoypadWindows::is_xinput_device(const GUID *p_guid) {
|
|||
|
||||
bool JoypadWindows::setup_dinput_joypad(const DIDEVICEINSTANCE *instance) {
|
||||
|
||||
ERR_FAIL_NULL_V_MSG(dinput, false, "DirectInput not initialized. Rebooting your PC may solve this issue.");
|
||||
HRESULT hr;
|
||||
int num = input->get_unused_joy_id();
|
||||
|
||||
|
@ -165,10 +170,13 @@ bool JoypadWindows::setup_dinput_joypad(const DIDEVICEINSTANCE *instance) {
|
|||
|
||||
const GUID &guid = instance->guidProduct;
|
||||
char uid[128];
|
||||
sprintf_s(uid, "%08lx%04hx%04hx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
|
||||
__builtin_bswap32(guid.Data1), guid.Data2, guid.Data3,
|
||||
guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3],
|
||||
guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
|
||||
|
||||
ERR_FAIL_COND_V_MSG(memcmp(&guid.Data4[2], "PIDVID", 6), false, "DirectInput device not recognised.");
|
||||
WORD type = BSWAP16(0x03);
|
||||
WORD vendor = BSWAP16(LOWORD(guid.Data1));
|
||||
WORD product = BSWAP16(HIWORD(guid.Data1));
|
||||
WORD version = 0;
|
||||
sprintf_s(uid, "%04x%04x%04x%04x%04x%04x%04x%04x", type, 0, vendor, 0, product, 0, version, 0);
|
||||
|
||||
id_to_change = joypad_count;
|
||||
|
||||
|
@ -280,6 +288,7 @@ void JoypadWindows::close_joypad(int id) {
|
|||
|
||||
void JoypadWindows::probe_joypads() {
|
||||
|
||||
ERR_FAIL_NULL_MSG(dinput, "DirectInput not initialized. Rebooting your PC may solve this issue.");
|
||||
DWORD dwResult;
|
||||
for (DWORD i = 0; i < XUSER_MAX_COUNT; i++) {
|
||||
|
||||
|
|
|
@ -3508,6 +3508,9 @@ String OS_Windows::get_current_tablet_driver() const {
|
|||
}
|
||||
|
||||
void OS_Windows::set_current_tablet_driver(const String &p_driver) {
|
||||
if (get_tablet_driver_count() == 0) {
|
||||
return;
|
||||
}
|
||||
bool found = false;
|
||||
for (int i = 0; i < get_tablet_driver_count(); i++) {
|
||||
if (p_driver == get_tablet_driver_name(i)) {
|
||||
|
|
|
@ -389,7 +389,7 @@ void DirectionalLight::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("is_blend_splits_enabled"), &DirectionalLight::is_blend_splits_enabled);
|
||||
|
||||
ADD_GROUP("Directional Shadow", "directional_shadow_");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "directional_shadow_mode", PROPERTY_HINT_ENUM, "Orthogonal,PSSM 2 Splits,PSSM 4 Splits"), "set_shadow_mode", "get_shadow_mode");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "directional_shadow_mode", PROPERTY_HINT_ENUM, "Orthogonal (Fast),PSSM 2 Splits (Average),PSSM 4 Splits (Slow)"), "set_shadow_mode", "get_shadow_mode");
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_split_1", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_param", "get_param", PARAM_SHADOW_SPLIT_1_OFFSET);
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_split_2", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_param", "get_param", PARAM_SHADOW_SPLIT_2_OFFSET);
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_split_3", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_param", "get_param", PARAM_SHADOW_SPLIT_3_OFFSET);
|
||||
|
|
|
@ -70,7 +70,7 @@ void ColorPicker::_notification(int p_what) {
|
|||
case NOTIFICATION_PARENTED: {
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
set_margin((Margin)i, get_constant("margin"));
|
||||
set_margin((Margin)i, get_margin((Margin)i) + get_constant("margin"));
|
||||
} break;
|
||||
case NOTIFICATION_VISIBILITY_CHANGED: {
|
||||
|
||||
|
|
|
@ -247,6 +247,11 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
|
|||
lh = line < l.height_caches.size() ? l.height_caches[line] : 1; \
|
||||
line_ascent = line < l.ascent_caches.size() ? l.ascent_caches[line] : 1; \
|
||||
line_descent = line < l.descent_caches.size() ? l.descent_caches[line] : 1; \
|
||||
if (p_mode == PROCESS_DRAW) { \
|
||||
if (line < l.offset_caches.size()) { \
|
||||
wofs = l.offset_caches[line]; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
if (p_mode == PROCESS_POINTER && r_click_item && p_click_pos.y >= p_ofs.y + y && p_click_pos.y <= p_ofs.y + y + lh && p_click_pos.x < p_ofs.x + wofs) { \
|
||||
if (r_outside) *r_outside = true; \
|
||||
|
@ -870,7 +875,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
|
|||
|
||||
void RichTextLabel::_scroll_changed(double) {
|
||||
|
||||
if (updating_scroll || !scroll_active)
|
||||
if (updating_scroll)
|
||||
return;
|
||||
|
||||
if (scroll_follow && vscroll->get_value() >= (vscroll->get_max() - vscroll->get_page()))
|
||||
|
@ -2009,6 +2014,7 @@ void RichTextLabel::set_scroll_active(bool p_active) {
|
|||
return;
|
||||
|
||||
scroll_active = p_active;
|
||||
vscroll->set_drag_node_enabled(p_active);
|
||||
update();
|
||||
}
|
||||
|
||||
|
|
|
@ -545,6 +545,9 @@ void ScrollBar::_drag_node_exit() {
|
|||
}
|
||||
|
||||
void ScrollBar::_drag_node_input(const Ref<InputEvent> &p_input) {
|
||||
if (!drag_node_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
Ref<InputEventMouseButton> mb = p_input;
|
||||
|
||||
|
@ -638,6 +641,10 @@ NodePath ScrollBar::get_drag_node() const {
|
|||
return drag_node_path;
|
||||
}
|
||||
|
||||
void ScrollBar::set_drag_node_enabled(bool p_enable) {
|
||||
drag_node_enabled = p_enable;
|
||||
}
|
||||
|
||||
void ScrollBar::set_smooth_scroll_enabled(bool p_enable) {
|
||||
smooth_scroll_enabled = p_enable;
|
||||
}
|
||||
|
@ -668,6 +675,7 @@ ScrollBar::ScrollBar(Orientation p_orientation) {
|
|||
|
||||
drag.active = false;
|
||||
|
||||
drag_node_enabled = true;
|
||||
drag_node_speed = Vector2();
|
||||
drag_node_touching = false;
|
||||
drag_node_touching_deaccel = false;
|
||||
|
|
|
@ -53,7 +53,6 @@ class ScrollBar : public Range {
|
|||
HighlightStatus highlight;
|
||||
|
||||
struct Drag {
|
||||
|
||||
bool active;
|
||||
float pos_at_click;
|
||||
float value_at_click;
|
||||
|
@ -70,6 +69,7 @@ class ScrollBar : public Range {
|
|||
|
||||
Node *drag_node;
|
||||
NodePath drag_node_path;
|
||||
bool drag_node_enabled;
|
||||
|
||||
Vector2 drag_node_speed;
|
||||
Vector2 drag_node_accum;
|
||||
|
@ -101,6 +101,7 @@ public:
|
|||
|
||||
void set_drag_node(const NodePath &p_path);
|
||||
NodePath get_drag_node() const;
|
||||
void set_drag_node_enabled(bool p_enable);
|
||||
|
||||
void set_smooth_scroll_enabled(bool p_enable);
|
||||
bool is_smooth_scroll_enabled() const;
|
||||
|
|
|
@ -577,7 +577,7 @@ DynamicFontAtSize::Character DynamicFontAtSize::_make_outline_char(CharType p_ch
|
|||
goto cleanup_stroker;
|
||||
if (FT_Glyph_Stroke(&glyph, stroker, 1) != 0)
|
||||
goto cleanup_glyph;
|
||||
if (FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1) != 0)
|
||||
if (FT_Glyph_To_Bitmap(&glyph, font->antialiased ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO, nullptr, 1) != 0)
|
||||
goto cleanup_glyph;
|
||||
|
||||
glyph_bitmap = (FT_BitmapGlyph)glyph;
|
||||
|
|
|
@ -95,6 +95,7 @@ void Font::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("get_descent"), &Font::get_descent);
|
||||
ClassDB::bind_method(D_METHOD("get_height"), &Font::get_height);
|
||||
ClassDB::bind_method(D_METHOD("is_distance_field_hint"), &Font::is_distance_field_hint);
|
||||
ClassDB::bind_method(D_METHOD("get_char_size", "char", "next"), &Font::get_char_size, DEFVAL(0));
|
||||
ClassDB::bind_method(D_METHOD("get_string_size", "string"), &Font::get_string_size);
|
||||
ClassDB::bind_method(D_METHOD("get_wordwrap_string_size", "string", "width"), &Font::get_wordwrap_string_size);
|
||||
ClassDB::bind_method(D_METHOD("has_outline"), &Font::has_outline);
|
||||
|
@ -606,8 +607,6 @@ void BitmapFont::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("get_texture_count"), &BitmapFont::get_texture_count);
|
||||
ClassDB::bind_method(D_METHOD("get_texture", "idx"), &BitmapFont::get_texture);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_char_size", "char", "next"), &BitmapFont::get_char_size, DEFVAL(0));
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_distance_field_hint", "enable"), &BitmapFont::set_distance_field_hint);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("clear"), &BitmapFont::clear);
|
||||
|
|
|
@ -507,7 +507,7 @@ File extracted from upstream release tarball:
|
|||
## xatlas
|
||||
|
||||
- Upstream: https://github.com/jpcy/xatlas
|
||||
- Version: git (e12ea82, 2019)
|
||||
- Version: git (470576d3516f7e6d8b4554e7c941194a935969fd, 2020)
|
||||
- License: MIT
|
||||
|
||||
Files extracted from upstream source:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2018-2019 Jonathan Young
|
||||
Copyright (c) 2018-2020 Jonathan Young
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018-2019 Jonathan Young
|
||||
Copyright (c) 2018-2020 Jonathan Young
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -42,18 +42,19 @@ struct ChartType
|
|||
Planar,
|
||||
Ortho,
|
||||
LSCM,
|
||||
Piecewise
|
||||
Piecewise,
|
||||
Invalid
|
||||
};
|
||||
};
|
||||
|
||||
// A group of connected faces, belonging to a single atlas.
|
||||
struct Chart
|
||||
{
|
||||
uint32_t atlasIndex; // Sub-atlas index.
|
||||
uint32_t *faceArray;
|
||||
uint32_t atlasIndex; // Sub-atlas index.
|
||||
uint32_t faceCount;
|
||||
uint32_t material;
|
||||
ChartType::Enum type;
|
||||
uint32_t material;
|
||||
};
|
||||
|
||||
// Output vertex.
|
||||
|
@ -69,10 +70,10 @@ struct Vertex
|
|||
struct Mesh
|
||||
{
|
||||
Chart *chartArray;
|
||||
uint32_t chartCount;
|
||||
uint32_t *indexArray;
|
||||
uint32_t indexCount;
|
||||
Vertex *vertexArray;
|
||||
uint32_t chartCount;
|
||||
uint32_t indexCount;
|
||||
uint32_t vertexCount;
|
||||
};
|
||||
|
||||
|
@ -84,15 +85,15 @@ static const uint32_t kImageIsPaddingBit = 0x20000000;
|
|||
// Empty on creation. Populated after charts are packed.
|
||||
struct Atlas
|
||||
{
|
||||
uint32_t *image;
|
||||
Mesh *meshes; // The output meshes, corresponding to each AddMesh call.
|
||||
uint32_t width; // Atlas width in texels.
|
||||
uint32_t height; // Atlas height in texels.
|
||||
uint32_t atlasCount; // Number of sub-atlases. Equal to 0 unless PackOptions resolution is changed from default (0).
|
||||
uint32_t chartCount; // Total number of charts in all meshes.
|
||||
uint32_t meshCount; // Number of output meshes. Equal to the number of times AddMesh was called.
|
||||
Mesh *meshes; // The output meshes, corresponding to each AddMesh call.
|
||||
float *utilization; // Normalized atlas texel utilization array. E.g. a value of 0.8 means 20% empty space. atlasCount in length.
|
||||
float texelsPerUnit; // Equal to PackOptions texelsPerUnit if texelsPerUnit > 0, otherwise an estimated value to match PackOptions resolution.
|
||||
uint32_t *image;
|
||||
};
|
||||
|
||||
// Create an empty atlas.
|
||||
|
@ -112,22 +113,23 @@ struct IndexFormat
|
|||
// Input mesh declaration.
|
||||
struct MeshDecl
|
||||
{
|
||||
uint32_t vertexCount = 0;
|
||||
const void *vertexPositionData = nullptr;
|
||||
uint32_t vertexPositionStride = 0;
|
||||
const void *vertexNormalData = nullptr; // optional
|
||||
uint32_t vertexNormalStride = 0; // optional
|
||||
const void *vertexUvData = nullptr; // optional. The input UVs are provided as a hint to the chart generator.
|
||||
uint32_t vertexUvStride = 0; // optional
|
||||
uint32_t indexCount = 0;
|
||||
const void *indexData = nullptr; // optional
|
||||
int32_t indexOffset = 0; // optional. Add this offset to all indices.
|
||||
IndexFormat::Enum indexFormat = IndexFormat::UInt16;
|
||||
|
||||
// Optional. indexCount / 3 (triangle count) in length.
|
||||
// Don't atlas faces set to true. Ignored faces still exist in the output meshes, Vertex uv is set to (0, 0) and Vertex atlasIndex to -1.
|
||||
const bool *faceIgnoreData = nullptr;
|
||||
|
||||
uint32_t vertexCount = 0;
|
||||
uint32_t vertexPositionStride = 0;
|
||||
uint32_t vertexNormalStride = 0; // optional
|
||||
uint32_t vertexUvStride = 0; // optional
|
||||
uint32_t indexCount = 0;
|
||||
int32_t indexOffset = 0; // optional. Add this offset to all indices.
|
||||
IndexFormat::Enum indexFormat = IndexFormat::UInt16;
|
||||
|
||||
// Vertex positions within epsilon distance of each other are considered colocal.
|
||||
float epsilon = 1.192092896e-07F;
|
||||
};
|
||||
|
@ -151,14 +153,14 @@ void AddMeshJoin(Atlas *atlas);
|
|||
|
||||
struct UvMeshDecl
|
||||
{
|
||||
const void *vertexUvData = nullptr;
|
||||
const void *indexData = nullptr; // optional
|
||||
const uint32_t *faceMaterialData = nullptr; // Optional. Faces with different materials won't be assigned to the same chart. Must be indexCount / 3 in length.
|
||||
uint32_t vertexCount = 0;
|
||||
uint32_t vertexStride = 0;
|
||||
const void *vertexUvData = nullptr;
|
||||
uint32_t indexCount = 0;
|
||||
const void *indexData = nullptr; // optional
|
||||
int32_t indexOffset = 0; // optional. Add this offset to all indices.
|
||||
IndexFormat::Enum indexFormat = IndexFormat::UInt16;
|
||||
const uint32_t *faceMaterialData = nullptr; // Optional. Faces with different materials won't be assigned to the same chart. Must be indexCount / 3 in length.
|
||||
bool rotateCharts = true;
|
||||
};
|
||||
|
||||
|
@ -170,24 +172,31 @@ struct ChartOptions
|
|||
float maxBoundaryLength = 0.0f; // Don't grow charts to have a longer boundary than this. 0 means no limit.
|
||||
|
||||
// Weights determine chart growth. Higher weights mean higher cost for that metric.
|
||||
float proxyFitMetricWeight = 2.0f; // Angle between face and average chart normal.
|
||||
float roundnessMetricWeight = 0.01f;
|
||||
float straightnessMetricWeight = 6.0f;
|
||||
float normalSeamMetricWeight = 4.0f; // If > 1000, normal seams are fully respected.
|
||||
float textureSeamMetricWeight = 0.5f;
|
||||
float normalDeviationWeight = 2.0f; // Angle between face and average chart normal.
|
||||
float roundnessWeight = 0.01f;
|
||||
float straightnessWeight = 6.0f;
|
||||
float normalSeamWeight = 4.0f; // If > 1000, normal seams are fully respected.
|
||||
float textureSeamWeight = 0.5f;
|
||||
|
||||
float maxThreshold = 2.0f; // If total of all metrics * weights > maxThreshold, don't grow chart. Lower values result in more charts.
|
||||
float maxCost = 2.0f; // If total of all metrics * weights > maxCost, don't grow chart. Lower values result in more charts.
|
||||
uint32_t maxIterations = 1; // Number of iterations of the chart growing and seeding phases. Higher values result in better charts.
|
||||
};
|
||||
|
||||
// Call after all AddMesh calls. Can be called multiple times to recompute charts with different options.
|
||||
void ComputeCharts(Atlas *atlas, ChartOptions chartOptions = ChartOptions());
|
||||
void ComputeCharts(Atlas *atlas, ChartOptions options = ChartOptions());
|
||||
|
||||
// Custom parameterization function. texcoords initial values are an orthogonal parameterization.
|
||||
typedef void (*ParameterizeFunc)(const float *positions, float *texcoords, uint32_t vertexCount, const uint32_t *indices, uint32_t indexCount);
|
||||
|
||||
struct ParameterizeOptions
|
||||
{
|
||||
ParameterizeFunc func = nullptr;
|
||||
bool closeHoles = true; // If the custom parameterization function works with multiple boundaries, this can be set to false to improve performance.
|
||||
bool fixTJunctions = true; // If meshes don't have T-junctions, this can be set to false to improve performance.
|
||||
};
|
||||
|
||||
// Call after ComputeCharts. Can be called multiple times to re-parameterize charts with a different ParameterizeFunc.
|
||||
void ParameterizeCharts(Atlas *atlas, ParameterizeFunc func = nullptr);
|
||||
void ParameterizeCharts(Atlas *atlas, ParameterizeOptions options = ParameterizeOptions());
|
||||
|
||||
struct PackOptions
|
||||
{
|
||||
|
@ -224,7 +233,7 @@ struct PackOptions
|
|||
void PackCharts(Atlas *atlas, PackOptions packOptions = PackOptions());
|
||||
|
||||
// Equivalent to calling ComputeCharts, ParameterizeCharts and PackCharts in sequence. Can be called multiple times to regenerate with different options.
|
||||
void Generate(Atlas *atlas, ChartOptions chartOptions = ChartOptions(), ParameterizeFunc paramFunc = nullptr, PackOptions packOptions = PackOptions());
|
||||
void Generate(Atlas *atlas, ChartOptions chartOptions = ChartOptions(), ParameterizeOptions parameterizeOptions = ParameterizeOptions(), PackOptions packOptions = PackOptions());
|
||||
|
||||
// Progress tracking.
|
||||
struct ProgressCategory
|
||||
|
|
Loading…
Reference in New Issue