feat: updated engine version to 4.4-rc1
This commit is contained in:
parent
ee00efde1f
commit
21ba8e33af
5459 changed files with 1128836 additions and 198305 deletions
|
|
@ -1,4 +1,5 @@
|
|||
#!/usr/bin/env python
|
||||
from misc.utility.scons_hints import *
|
||||
|
||||
Import("env")
|
||||
Import("env_modules")
|
||||
|
|
@ -63,7 +64,8 @@ if env["builtin_harfbuzz"]:
|
|||
# "src/hb-cairo-utils.cc",
|
||||
# "src/hb-cairo.cc",
|
||||
"src/hb-common.cc",
|
||||
# "src/hb-coretext.cc",
|
||||
# "src/hb-coretext-font.cc",
|
||||
# "src/hb-coretext-shape.cc",
|
||||
# "src/hb-directwrite.cc",
|
||||
"src/hb-draw.cc",
|
||||
"src/hb-face-builder.cc",
|
||||
|
|
@ -125,6 +127,7 @@ if env["builtin_harfbuzz"]:
|
|||
"src/hb-ucd.cc",
|
||||
"src/hb-unicode.cc",
|
||||
# "src/hb-uniscribe.cc",
|
||||
"src/OT/Var/VARC/VARC.cc",
|
||||
]
|
||||
|
||||
if freetype_enabled:
|
||||
|
|
@ -142,7 +145,14 @@ if env["builtin_harfbuzz"]:
|
|||
env_harfbuzz.Append(CCFLAGS=["-DHAVE_ICU"])
|
||||
if env["builtin_icu4c"]:
|
||||
env_harfbuzz.Prepend(CPPPATH=["#thirdparty/icu4c/common/", "#thirdparty/icu4c/i18n/"])
|
||||
env_harfbuzz.Append(CCFLAGS=["-DU_HAVE_LIB_SUFFIX=1", "-DU_LIB_SUFFIX_C_NAME=_godot", "-DHAVE_ICU_BUILTIN"])
|
||||
env_harfbuzz.Append(
|
||||
CCFLAGS=[
|
||||
"-DU_STATIC_IMPLEMENTATION",
|
||||
"-DU_HAVE_LIB_SUFFIX=1",
|
||||
"-DU_LIB_SUFFIX_C_NAME=_godot",
|
||||
"-DHAVE_ICU_BUILTIN",
|
||||
]
|
||||
)
|
||||
|
||||
if freetype_enabled:
|
||||
env_harfbuzz.Append(
|
||||
|
|
@ -468,11 +478,10 @@ if env["builtin_icu4c"]:
|
|||
]
|
||||
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
|
||||
|
||||
icu_data_name = "icudt75l.dat"
|
||||
|
||||
if env.editor_build:
|
||||
env_icu.Depends("#thirdparty/icu4c/icudata.gen.h", "#thirdparty/icu4c/" + icu_data_name)
|
||||
env_icu.Command("#thirdparty/icu4c/icudata.gen.h", "#thirdparty/icu4c/" + icu_data_name, make_icu_data)
|
||||
env_icu.CommandNoCache(
|
||||
"#thirdparty/icu4c/icudata.gen.h", "#thirdparty/icu4c/icudt_godot.dat", env.Run(make_icu_data)
|
||||
)
|
||||
env_text_server_adv.Prepend(CPPPATH=["#thirdparty/icu4c/"])
|
||||
else:
|
||||
thirdparty_sources += ["icu_data/icudata_stub.cpp"]
|
||||
|
|
@ -494,14 +503,13 @@ if env["builtin_icu4c"]:
|
|||
"-DU_ENABLE_DYLOAD=0",
|
||||
"-DU_HAVE_LIB_SUFFIX=1",
|
||||
"-DU_LIB_SUFFIX_C_NAME=_godot",
|
||||
"-DICU_DATA_NAME=" + icu_data_name,
|
||||
]
|
||||
)
|
||||
env_text_server_adv.Append(
|
||||
CXXFLAGS=[
|
||||
"-DU_STATIC_IMPLEMENTATION",
|
||||
"-DU_HAVE_LIB_SUFFIX=1",
|
||||
"-DU_LIB_SUFFIX_C_NAME=_godot",
|
||||
"-DICU_DATA_NAME=" + icu_data_name,
|
||||
]
|
||||
)
|
||||
if env.editor_build:
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
def can_build(env, platform):
|
||||
env.module_add_dependencies("text_server_adv", ["freetype", "msdfgen", "svg"], True)
|
||||
return True
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,28 +1,8 @@
|
|||
#!/usr/bin/env python
|
||||
import atexit
|
||||
import sys
|
||||
import time
|
||||
# ruff: noqa: F821
|
||||
|
||||
import methods
|
||||
|
||||
# Enable ANSI escape code support on Windows 10 and later (for colored console output).
|
||||
# <https://github.com/python/cpython/issues/73245>
|
||||
if sys.stdout.isatty() and sys.platform == "win32":
|
||||
try:
|
||||
from ctypes import WinError, byref, windll # type: ignore
|
||||
from ctypes.wintypes import DWORD # type: ignore
|
||||
|
||||
stdout_handle = windll.kernel32.GetStdHandle(DWORD(-11))
|
||||
mode = DWORD(0)
|
||||
if not windll.kernel32.GetConsoleMode(stdout_handle, byref(mode)):
|
||||
raise WinError()
|
||||
mode = DWORD(mode.value | 4)
|
||||
if not windll.kernel32.SetConsoleMode(stdout_handle, mode):
|
||||
raise WinError()
|
||||
except Exception as e:
|
||||
methods._colorize = False
|
||||
methods.print_error(f"Failed to enable ANSI escape code support, disabling color output.\n{e}")
|
||||
|
||||
# For the reference:
|
||||
# - CCFLAGS are compilation flags shared between C and C++
|
||||
# - CFLAGS are for C-specific compilation flags
|
||||
|
|
@ -31,8 +11,6 @@ if sys.stdout.isatty() and sys.platform == "win32":
|
|||
# - CPPDEFINES are for pre-processor defines
|
||||
# - LINKFLAGS are for linking flags
|
||||
|
||||
time_at_start = time.time()
|
||||
|
||||
env = SConscript("./godot-cpp/SConstruct")
|
||||
env.__class__.disable_warnings = methods.disable_warnings
|
||||
|
||||
|
|
@ -47,9 +25,6 @@ opts.Add(BoolVariable("verbose", "Enable verbose output for the compilation", Fa
|
|||
|
||||
opts.Update(env)
|
||||
|
||||
if not env["verbose"]:
|
||||
methods.no_verbose(env)
|
||||
|
||||
if env["platform"] == "windows" and not env["use_mingw"]:
|
||||
env.AppendUnique(CCFLAGS=["/utf-8"]) # Force to use Unicode encoding.
|
||||
|
||||
|
|
@ -135,7 +110,7 @@ if env["thorvg_enabled"] and env["freetype_enabled"]:
|
|||
env.Append(CPPDEFINES=["MODULE_SVG_ENABLED"])
|
||||
|
||||
lib = env_tvg.Library(
|
||||
f'tvg_builtin{env["suffix"]}{env["LIBSUFFIX"]}',
|
||||
f"tvg_builtin{env['suffix']}{env['LIBSUFFIX']}",
|
||||
thirdparty_tvg_sources,
|
||||
)
|
||||
env.Append(LIBS=[lib])
|
||||
|
|
@ -148,6 +123,7 @@ if env["msdfgen_enabled"] and env["freetype_enabled"]:
|
|||
thirdparty_msdfgen_dir = "../../../thirdparty/msdfgen/"
|
||||
thirdparty_msdfgen_sources = [
|
||||
"core/Contour.cpp",
|
||||
"core/DistanceMapping.cpp",
|
||||
"core/EdgeHolder.cpp",
|
||||
"core/MSDFErrorCorrection.cpp",
|
||||
"core/Projection.cpp",
|
||||
|
|
@ -158,10 +134,15 @@ if env["msdfgen_enabled"] and env["freetype_enabled"]:
|
|||
"core/edge-segments.cpp",
|
||||
"core/edge-selectors.cpp",
|
||||
"core/equation-solver.cpp",
|
||||
# "core/export-svg.cpp",
|
||||
"core/msdf-error-correction.cpp",
|
||||
"core/msdfgen.cpp",
|
||||
"core/rasterization.cpp",
|
||||
"core/render-sdf.cpp",
|
||||
# "core/save-bmp.cpp",
|
||||
# "core/save-fl32.cpp",
|
||||
# "core/save-rgba.cpp",
|
||||
# "core/save-tiff.cpp",
|
||||
"core/sdf-error-estimation.cpp",
|
||||
"core/shape-description.cpp",
|
||||
]
|
||||
|
|
@ -174,7 +155,7 @@ if env["msdfgen_enabled"] and env["freetype_enabled"]:
|
|||
env.Append(CPPDEFINES=["MODULE_MSDFGEN_ENABLED"])
|
||||
|
||||
lib = env_msdfgen.Library(
|
||||
f'msdfgen_builtin{env["suffix"]}{env["LIBSUFFIX"]}',
|
||||
f"msdfgen_builtin{env['suffix']}{env['LIBSUFFIX']}",
|
||||
thirdparty_msdfgen_sources,
|
||||
)
|
||||
env.Append(LIBS=[lib])
|
||||
|
|
@ -303,7 +284,7 @@ if env["freetype_enabled"]:
|
|||
env.Append(CPPDEFINES=["MODULE_FREETYPE_ENABLED"])
|
||||
|
||||
lib = env_freetype.Library(
|
||||
f'freetype_builtin{env["suffix"]}{env["LIBSUFFIX"]}',
|
||||
f"freetype_builtin{env['suffix']}{env['LIBSUFFIX']}",
|
||||
thirdparty_freetype_sources,
|
||||
)
|
||||
env.Append(LIBS=[lib])
|
||||
|
|
@ -323,7 +304,8 @@ thirdparty_harfbuzz_sources = [
|
|||
# "src/hb-cairo-utils.cc",
|
||||
# "src/hb-cairo.cc",
|
||||
"src/hb-common.cc",
|
||||
# "src/hb-coretext.cc",
|
||||
# "src/hb-coretext-font.cc",
|
||||
# "src/hb-coretext-shape.cc",
|
||||
# "src/hb-directwrite.cc",
|
||||
"src/hb-draw.cc",
|
||||
"src/hb-face-builder.cc",
|
||||
|
|
@ -385,6 +367,7 @@ thirdparty_harfbuzz_sources = [
|
|||
"src/hb-ucd.cc",
|
||||
"src/hb-unicode.cc",
|
||||
# "src/hb-uniscribe.cc",
|
||||
"src/OT/Var/VARC/VARC.cc",
|
||||
]
|
||||
|
||||
if env["freetype_enabled"]:
|
||||
|
|
@ -415,6 +398,7 @@ if env["platform"] == "android" or env["platform"] == "linuxbsd":
|
|||
|
||||
env_harfbuzz.Append(
|
||||
CCFLAGS=[
|
||||
"-DU_STATIC_IMPLEMENTATION",
|
||||
"-DU_HAVE_LIB_SUFFIX=1",
|
||||
"-DU_LIB_SUFFIX_C_NAME=_godot",
|
||||
"-DHAVE_ICU_BUILTIN",
|
||||
|
|
@ -434,7 +418,7 @@ if env["freetype_enabled"]:
|
|||
env.Append(CPPPATH=["../../../thirdparty/harfbuzz/src"])
|
||||
|
||||
lib = env_harfbuzz.Library(
|
||||
f'harfbuzz_builtin{env["suffix"]}{env["LIBSUFFIX"]}',
|
||||
f"harfbuzz_builtin{env['suffix']}{env['LIBSUFFIX']}",
|
||||
thirdparty_harfbuzz_sources,
|
||||
)
|
||||
env.Prepend(LIBS=[lib])
|
||||
|
|
@ -494,7 +478,7 @@ if env["graphite_enabled"] and env["freetype_enabled"]:
|
|||
)
|
||||
|
||||
lib = env_graphite.Library(
|
||||
f'graphite_builtin{env["suffix"]}{env["LIBSUFFIX"]}',
|
||||
f"graphite_builtin{env['suffix']}{env['LIBSUFFIX']}",
|
||||
thirdparty_graphite_sources,
|
||||
)
|
||||
env.Append(LIBS=[lib])
|
||||
|
|
@ -713,12 +697,10 @@ thirdparty_icu_sources = [
|
|||
]
|
||||
thirdparty_icu_sources = [thirdparty_icu_dir + file for file in thirdparty_icu_sources]
|
||||
|
||||
icu_data_name = "icudt75l.dat"
|
||||
|
||||
if env["static_icu_data"]:
|
||||
env_icu.Depends("../../../thirdparty/icu4c/icudata.gen.h", "../../../thirdparty/icu4c/" + icu_data_name)
|
||||
env_icu.Depends("../../../thirdparty/icu4c/icudata.gen.h", "../../../thirdparty/icu4c/icudt_godot.dat")
|
||||
env_icu.Command(
|
||||
"../../../thirdparty/icu4c/icudata.gen.h", "../../../thirdparty/icu4c/" + icu_data_name, methods.make_icu_data
|
||||
"../../../thirdparty/icu4c/icudata.gen.h", "../../../thirdparty/icu4c/icudt_godot.dat", methods.make_icu_data
|
||||
)
|
||||
env.Append(CXXFLAGS=["-DICU_STATIC_DATA"])
|
||||
env.Append(CPPPATH=["../../../thirdparty/icu4c/"])
|
||||
|
|
@ -741,14 +723,13 @@ env_icu.Append(
|
|||
"-DU_ENABLE_DYLOAD=0",
|
||||
"-DU_HAVE_LIB_SUFFIX=1",
|
||||
"-DU_LIB_SUFFIX_C_NAME=_godot",
|
||||
"-DICU_DATA_NAME=" + icu_data_name,
|
||||
]
|
||||
)
|
||||
env.Append(
|
||||
CXXFLAGS=[
|
||||
"-DU_STATIC_IMPLEMENTATION",
|
||||
"-DU_HAVE_LIB_SUFFIX=1",
|
||||
"-DU_LIB_SUFFIX_C_NAME=_godot",
|
||||
"-DICU_DATA_NAME=" + icu_data_name,
|
||||
]
|
||||
)
|
||||
env.Append(CPPPATH=["../../../thirdparty/icu4c/common/", "../../../thirdparty/icu4c/i18n/"])
|
||||
|
|
@ -756,7 +737,7 @@ env.Append(CPPPATH=["../../../thirdparty/icu4c/common/", "../../../thirdparty/ic
|
|||
if env["platform"] == "windows":
|
||||
env.Append(LIBS=["advapi32"])
|
||||
|
||||
lib = env_icu.Library(f'icu_builtin{env["suffix"]}{env["LIBSUFFIX"]}', thirdparty_icu_sources)
|
||||
lib = env_icu.Library(f"icu_builtin{env['suffix']}{env['LIBSUFFIX']}", thirdparty_icu_sources)
|
||||
env.Append(LIBS=[lib])
|
||||
|
||||
env.Append(CPPDEFINES=["GDEXTENSION"])
|
||||
|
|
@ -765,35 +746,21 @@ sources = Glob("../*.cpp")
|
|||
|
||||
if env["platform"] == "macos":
|
||||
methods.write_macos_plist(
|
||||
f'./bin/libtextserver_advanced.macos.{env["target"]}.framework',
|
||||
f'libtextserver_advanced.macos.{env["target"]}',
|
||||
f"./bin/libtextserver_advanced.macos.{env['target']}.framework",
|
||||
f"libtextserver_advanced.macos.{env['target']}",
|
||||
"org.godotengine.textserver_advanced",
|
||||
"ICU / HarfBuzz / Graphite Text Server",
|
||||
)
|
||||
library = env.SharedLibrary(
|
||||
f'./bin/libtextserver_advanced.macos.{env["target"]}.framework/libtextserver_advanced.macos.{env["target"]}',
|
||||
f"./bin/libtextserver_advanced.macos.{env['target']}.framework/libtextserver_advanced.macos.{env['target']}",
|
||||
source=sources,
|
||||
)
|
||||
else:
|
||||
library = env.SharedLibrary(
|
||||
f'./bin/libtextserver_advanced{env["suffix"]}{env["SHLIBSUFFIX"]}',
|
||||
f"./bin/libtextserver_advanced{env['suffix']}{env['SHLIBSUFFIX']}",
|
||||
source=sources,
|
||||
)
|
||||
|
||||
Default(library)
|
||||
|
||||
|
||||
def print_elapsed_time():
|
||||
elapsed_time_sec = round(time.time() - time_at_start, 2)
|
||||
time_centiseconds = round((elapsed_time_sec % 1) * 100)
|
||||
print(
|
||||
"{}[Time elapsed: {}.{:02}]{}".format(
|
||||
methods.ANSI.GRAY,
|
||||
time.strftime("%H:%M:%S", time.gmtime(elapsed_time_sec)),
|
||||
time_centiseconds,
|
||||
methods.ANSI.RESET,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
atexit.register(print_elapsed_time)
|
||||
methods.prepare_timer()
|
||||
|
|
|
|||
|
|
@ -1,93 +1,28 @@
|
|||
import os
|
||||
import sys
|
||||
from enum import Enum
|
||||
|
||||
# Colors are disabled in non-TTY environments such as pipes. This means
|
||||
# that if output is redirected to a file, it won't contain color codes.
|
||||
# Colors are always enabled on continuous integration.
|
||||
_colorize = bool(sys.stdout.isatty() or os.environ.get("CI"))
|
||||
|
||||
|
||||
class ANSI(Enum):
|
||||
"""
|
||||
Enum class for adding ansi colorcodes directly into strings.
|
||||
Automatically converts values to strings representing their
|
||||
internal value, or an empty string in a non-colorized scope.
|
||||
"""
|
||||
|
||||
RESET = "\x1b[0m"
|
||||
|
||||
BOLD = "\x1b[1m"
|
||||
ITALIC = "\x1b[3m"
|
||||
UNDERLINE = "\x1b[4m"
|
||||
STRIKETHROUGH = "\x1b[9m"
|
||||
REGULAR = "\x1b[22;23;24;29m"
|
||||
|
||||
BLACK = "\x1b[30m"
|
||||
RED = "\x1b[31m"
|
||||
GREEN = "\x1b[32m"
|
||||
YELLOW = "\x1b[33m"
|
||||
BLUE = "\x1b[34m"
|
||||
MAGENTA = "\x1b[35m"
|
||||
CYAN = "\x1b[36m"
|
||||
WHITE = "\x1b[37m"
|
||||
|
||||
PURPLE = "\x1b[38;5;93m"
|
||||
PINK = "\x1b[38;5;206m"
|
||||
ORANGE = "\x1b[38;5;214m"
|
||||
GRAY = "\x1b[38;5;244m"
|
||||
|
||||
def __str__(self) -> str:
|
||||
global _colorize
|
||||
return str(self.value) if _colorize else ""
|
||||
|
||||
|
||||
def no_verbose(env):
|
||||
colors = [ANSI.BLUE, ANSI.BOLD, ANSI.REGULAR, ANSI.RESET]
|
||||
|
||||
# There is a space before "..." to ensure that source file names can be
|
||||
# Ctrl + clicked in the VS Code terminal.
|
||||
compile_source_message = "{}Compiling {}$SOURCE{} ...{}".format(*colors)
|
||||
java_compile_source_message = "{}Compiling {}$SOURCE{} ...{}".format(*colors)
|
||||
compile_shared_source_message = "{}Compiling shared {}$SOURCE{} ...{}".format(*colors)
|
||||
link_program_message = "{}Linking Program {}$TARGET{} ...{}".format(*colors)
|
||||
link_library_message = "{}Linking Static Library {}$TARGET{} ...{}".format(*colors)
|
||||
ranlib_library_message = "{}Ranlib Library {}$TARGET{} ...{}".format(*colors)
|
||||
link_shared_library_message = "{}Linking Shared Library {}$TARGET{} ...{}".format(*colors)
|
||||
java_library_message = "{}Creating Java Archive {}$TARGET{} ...{}".format(*colors)
|
||||
compiled_resource_message = "{}Creating Compiled Resource {}$TARGET{} ...{}".format(*colors)
|
||||
generated_file_message = "{}Generating {}$TARGET{} ...{}".format(*colors)
|
||||
|
||||
env["CXXCOMSTR"] = compile_source_message
|
||||
env["CCCOMSTR"] = compile_source_message
|
||||
env["SHCCCOMSTR"] = compile_shared_source_message
|
||||
env["SHCXXCOMSTR"] = compile_shared_source_message
|
||||
env["ARCOMSTR"] = link_library_message
|
||||
env["RANLIBCOMSTR"] = ranlib_library_message
|
||||
env["SHLINKCOMSTR"] = link_shared_library_message
|
||||
env["LINKCOMSTR"] = link_program_message
|
||||
env["JARCOMSTR"] = java_library_message
|
||||
env["JAVACCOMSTR"] = java_compile_source_message
|
||||
env["RCCOMSTR"] = compiled_resource_message
|
||||
env["GENCOMSTR"] = generated_file_message
|
||||
|
||||
|
||||
def disable_warnings(self):
|
||||
# 'self' is the environment
|
||||
if self["platform"] == "windows" and not self["use_mingw"]:
|
||||
# We have to remove existing warning level defines before appending /w,
|
||||
# otherwise we get: "warning D9025 : overriding '/W3' with '/w'"
|
||||
warn_flags = ["/Wall", "/W4", "/W3", "/W2", "/W1", "/WX"]
|
||||
self.Append(CCFLAGS=["/w"])
|
||||
self.Append(CFLAGS=["/w"])
|
||||
self.Append(CXXFLAGS=["/w"])
|
||||
self["CCFLAGS"] = [x for x in self["CCFLAGS"] if x not in warn_flags]
|
||||
self["CFLAGS"] = [x for x in self["CFLAGS"] if x not in warn_flags]
|
||||
self["CXXFLAGS"] = [x for x in self["CXXFLAGS"] if x not in warn_flags]
|
||||
WARN_FLAGS = ["/Wall", "/W4", "/W3", "/W2", "/W1", "/W0"]
|
||||
self["CCFLAGS"] = [x for x in self["CCFLAGS"] if x not in WARN_FLAGS]
|
||||
self["CFLAGS"] = [x for x in self["CFLAGS"] if x not in WARN_FLAGS]
|
||||
self["CXXFLAGS"] = [x for x in self["CXXFLAGS"] if x not in WARN_FLAGS]
|
||||
self.AppendUnique(CCFLAGS=["/w"])
|
||||
else:
|
||||
self.Append(CCFLAGS=["-w"])
|
||||
self.Append(CFLAGS=["-w"])
|
||||
self.Append(CXXFLAGS=["-w"])
|
||||
self.AppendUnique(CCFLAGS=["-w"])
|
||||
|
||||
|
||||
def prepare_timer():
|
||||
import atexit
|
||||
import time
|
||||
|
||||
def print_elapsed_time(time_at_start: float):
|
||||
time_elapsed = time.time() - time_at_start
|
||||
time_formatted = time.strftime("%H:%M:%S", time.gmtime(time_elapsed))
|
||||
time_centiseconds = round((time_elapsed % 1) * 100)
|
||||
print(f"[Time elapsed: {time_formatted}.{time_centiseconds}]")
|
||||
|
||||
atexit.register(print_elapsed_time, time.time())
|
||||
|
||||
|
||||
def make_icu_data(target, source, env):
|
||||
|
|
@ -115,6 +50,8 @@ def make_icu_data(target, source, env):
|
|||
|
||||
|
||||
def write_macos_plist(target, binary_name, identifier, name):
|
||||
import os
|
||||
|
||||
os.makedirs(f"{target}/Resource/", exist_ok=True)
|
||||
with open(f"{target}/Resource/Info.plist", "w", encoding="utf-8", newline="\n") as f:
|
||||
f.write(f"""\
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -74,6 +74,7 @@
|
|||
#include <godot_cpp/templates/hash_map.hpp>
|
||||
#include <godot_cpp/templates/hash_set.hpp>
|
||||
#include <godot_cpp/templates/rid_owner.hpp>
|
||||
#include <godot_cpp/templates/safe_refcount.hpp>
|
||||
#include <godot_cpp/templates/vector.hpp>
|
||||
|
||||
using namespace godot;
|
||||
|
|
@ -82,9 +83,9 @@ using namespace godot;
|
|||
// Headers for building as built-in module.
|
||||
|
||||
#include "core/extension/ext_wrappers.gen.inc"
|
||||
#include "core/object/worker_thread_pool.h"
|
||||
#include "core/templates/hash_map.h"
|
||||
#include "core/templates/rid_owner.h"
|
||||
#include "core/templates/safe_refcount.h"
|
||||
#include "scene/resources/image_texture.h"
|
||||
#include "servers/text/text_server_extension.h"
|
||||
|
||||
|
|
@ -94,6 +95,11 @@ using namespace godot;
|
|||
|
||||
// Thirdparty headers.
|
||||
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wshadow"
|
||||
#endif
|
||||
|
||||
#include <unicode/ubidi.h>
|
||||
#include <unicode/ubrk.h>
|
||||
#include <unicode/uchar.h>
|
||||
|
|
@ -107,6 +113,10 @@ using namespace godot;
|
|||
#include <unicode/ustring.h>
|
||||
#include <unicode/utypes.h>
|
||||
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#ifdef MODULE_FREETYPE_ENABLED
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
|
|
@ -137,7 +147,8 @@ class TextServerAdvanced : public TextServerExtension {
|
|||
HashSet<StringName> lang;
|
||||
String digits;
|
||||
String percent_sign;
|
||||
String exp;
|
||||
String exp_l;
|
||||
String exp_u;
|
||||
};
|
||||
|
||||
Vector<NumSystemData> num_systems;
|
||||
|
|
@ -151,6 +162,9 @@ class TextServerAdvanced : public TextServerExtension {
|
|||
HashMap<StringName, int32_t> feature_sets;
|
||||
HashMap<int32_t, FeatureInfo> feature_sets_inv;
|
||||
|
||||
SafeNumeric<TextServer::FontLCDSubpixelLayout> lcd_subpixel_layout{ TextServer::FontLCDSubpixelLayout::FONT_LCD_SUBPIXEL_LAYOUT_NONE };
|
||||
void _update_settings();
|
||||
|
||||
void _insert_num_systems_lang();
|
||||
void _insert_feature_sets();
|
||||
_FORCE_INLINE_ void _insert_feature(const StringName &p_name, int32_t p_tag, Variant::Type p_vtype = Variant::INT, bool p_hidden = false);
|
||||
|
|
@ -314,6 +328,7 @@ class TextServerAdvanced : public TextServerExtension {
|
|||
bool force_autohinter = false;
|
||||
TextServer::Hinting hinting = TextServer::HINTING_LIGHT;
|
||||
TextServer::SubpixelPositioning subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_AUTO;
|
||||
bool keep_rounding_remainders = true;
|
||||
Dictionary variation_coordinates;
|
||||
double oversampling = 0.0;
|
||||
double embolden = 0.0;
|
||||
|
|
@ -327,7 +342,7 @@ class TextServerAdvanced : public TextServerExtension {
|
|||
int extra_spacing[4] = { 0, 0, 0, 0 };
|
||||
double baseline_offset = 0.0;
|
||||
|
||||
HashMap<Vector2i, FontForSizeAdvanced *, VariantHasher, VariantComparator> cache;
|
||||
HashMap<Vector2i, FontForSizeAdvanced *> cache;
|
||||
|
||||
bool face_init = false;
|
||||
HashSet<uint32_t> supported_scripts;
|
||||
|
|
@ -359,8 +374,9 @@ class TextServerAdvanced : public TextServerExtension {
|
|||
#ifdef MODULE_FREETYPE_ENABLED
|
||||
_FORCE_INLINE_ FontGlyph rasterize_bitmap(FontForSizeAdvanced *p_data, int p_rect_margin, FT_Bitmap p_bitmap, int p_yofs, int p_xofs, const Vector2 &p_advance, bool p_bgra) const;
|
||||
#endif
|
||||
_FORCE_INLINE_ bool _ensure_glyph(FontAdvanced *p_font_data, const Vector2i &p_size, int32_t p_glyph) const;
|
||||
_FORCE_INLINE_ bool _ensure_cache_for_size(FontAdvanced *p_font_data, const Vector2i &p_size) const;
|
||||
_FORCE_INLINE_ bool _ensure_glyph(FontAdvanced *p_font_data, const Vector2i &p_size, int32_t p_glyph, FontGlyph &r_glyph) const;
|
||||
_FORCE_INLINE_ bool _ensure_cache_for_size(FontAdvanced *p_font_data, const Vector2i &p_size, FontForSizeAdvanced *&r_cache_for_size, bool p_silent = false) const;
|
||||
_FORCE_INLINE_ bool _font_validate(const RID &p_font_rid) const;
|
||||
_FORCE_INLINE_ void _font_clear_cache(FontAdvanced *p_font_data);
|
||||
static void _generateMTSDF_threaded(void *p_td, uint32_t p_y);
|
||||
|
||||
|
|
@ -474,6 +490,8 @@ class TextServerAdvanced : public TextServerExtension {
|
|||
Variant meta;
|
||||
};
|
||||
Vector<Span> spans;
|
||||
int first_span = 0; // First span in the parent ShapedTextData.
|
||||
int last_span = 0;
|
||||
|
||||
struct EmbeddedObject {
|
||||
int start = -1;
|
||||
|
|
@ -487,7 +505,7 @@ class TextServerAdvanced : public TextServerExtension {
|
|||
/* Shaped data */
|
||||
TextServer::Direction para_direction = DIRECTION_LTR; // Detected text direction.
|
||||
int base_para_direction = UBIDI_DEFAULT_LTR;
|
||||
bool valid = false; // String is shaped.
|
||||
SafeFlag valid{ false }; // String is shaped.
|
||||
bool line_breaks_valid = false; // Line and word break flags are populated (and virtual zero width spaces inserted).
|
||||
bool justification_ops_valid = false; // Virtual elongation glyphs are added to the string.
|
||||
bool sort_valid = false;
|
||||
|
|
@ -573,6 +591,7 @@ class TextServerAdvanced : public TextServerExtension {
|
|||
int fixed_size = 0;
|
||||
TextServer::Hinting hinting = TextServer::HINTING_LIGHT;
|
||||
TextServer::SubpixelPositioning subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_AUTO;
|
||||
bool keep_rounding_remainders = true;
|
||||
Dictionary variation_coordinates;
|
||||
double oversampling = 0.0;
|
||||
double embolden = 0.0;
|
||||
|
|
@ -581,7 +600,7 @@ class TextServerAdvanced : public TextServerExtension {
|
|||
double baseline_offset = 0.0;
|
||||
|
||||
bool operator==(const SystemFontKey &p_b) const {
|
||||
return (font_name == p_b.font_name) && (antialiasing == p_b.antialiasing) && (italic == p_b.italic) && (disable_embedded_bitmaps == p_b.disable_embedded_bitmaps) && (mipmaps == p_b.mipmaps) && (msdf == p_b.msdf) && (force_autohinter == p_b.force_autohinter) && (weight == p_b.weight) && (stretch == p_b.stretch) && (msdf_range == p_b.msdf_range) && (msdf_source_size == p_b.msdf_source_size) && (fixed_size == p_b.fixed_size) && (hinting == p_b.hinting) && (subpixel_positioning == p_b.subpixel_positioning) && (variation_coordinates == p_b.variation_coordinates) && (oversampling == p_b.oversampling) && (embolden == p_b.embolden) && (transform == p_b.transform) && (extra_spacing[SPACING_TOP] == p_b.extra_spacing[SPACING_TOP]) && (extra_spacing[SPACING_BOTTOM] == p_b.extra_spacing[SPACING_BOTTOM]) && (extra_spacing[SPACING_SPACE] == p_b.extra_spacing[SPACING_SPACE]) && (extra_spacing[SPACING_GLYPH] == p_b.extra_spacing[SPACING_GLYPH]) && (baseline_offset == p_b.baseline_offset);
|
||||
return (font_name == p_b.font_name) && (antialiasing == p_b.antialiasing) && (italic == p_b.italic) && (disable_embedded_bitmaps == p_b.disable_embedded_bitmaps) && (mipmaps == p_b.mipmaps) && (msdf == p_b.msdf) && (force_autohinter == p_b.force_autohinter) && (weight == p_b.weight) && (stretch == p_b.stretch) && (msdf_range == p_b.msdf_range) && (msdf_source_size == p_b.msdf_source_size) && (fixed_size == p_b.fixed_size) && (hinting == p_b.hinting) && (subpixel_positioning == p_b.subpixel_positioning) && (keep_rounding_remainders == p_b.keep_rounding_remainders) && (variation_coordinates == p_b.variation_coordinates) && (oversampling == p_b.oversampling) && (embolden == p_b.embolden) && (transform == p_b.transform) && (extra_spacing[SPACING_TOP] == p_b.extra_spacing[SPACING_TOP]) && (extra_spacing[SPACING_BOTTOM] == p_b.extra_spacing[SPACING_BOTTOM]) && (extra_spacing[SPACING_SPACE] == p_b.extra_spacing[SPACING_SPACE]) && (extra_spacing[SPACING_GLYPH] == p_b.extra_spacing[SPACING_GLYPH]) && (baseline_offset == p_b.baseline_offset);
|
||||
}
|
||||
|
||||
SystemFontKey(const String &p_font_name, bool p_italic, int p_weight, int p_stretch, RID p_font, const TextServerAdvanced *p_fb) {
|
||||
|
|
@ -599,6 +618,7 @@ class TextServerAdvanced : public TextServerExtension {
|
|||
force_autohinter = p_fb->_font_is_force_autohinter(p_font);
|
||||
hinting = p_fb->_font_get_hinting(p_font);
|
||||
subpixel_positioning = p_fb->_font_get_subpixel_positioning(p_font);
|
||||
keep_rounding_remainders = p_fb->_font_get_keep_rounding_remainders(p_font);
|
||||
variation_coordinates = p_fb->_font_get_variation_coordinates(p_font);
|
||||
oversampling = p_fb->_font_get_oversampling(p_font);
|
||||
embolden = p_fb->_font_get_embolden(p_font);
|
||||
|
|
@ -641,7 +661,7 @@ class TextServerAdvanced : public TextServerExtension {
|
|||
hash = hash_murmur3_one_32(p_a.extra_spacing[SPACING_SPACE], hash);
|
||||
hash = hash_murmur3_one_32(p_a.extra_spacing[SPACING_GLYPH], hash);
|
||||
hash = hash_murmur3_one_double(p_a.baseline_offset, hash);
|
||||
return hash_fmix32(hash_murmur3_one_32(((int)p_a.mipmaps) | ((int)p_a.msdf << 1) | ((int)p_a.italic << 2) | ((int)p_a.force_autohinter << 3) | ((int)p_a.hinting << 4) | ((int)p_a.subpixel_positioning << 8) | ((int)p_a.antialiasing << 12) | ((int)p_a.disable_embedded_bitmaps << 14), hash));
|
||||
return hash_fmix32(hash_murmur3_one_32(((int)p_a.mipmaps) | ((int)p_a.msdf << 1) | ((int)p_a.italic << 2) | ((int)p_a.force_autohinter << 3) | ((int)p_a.hinting << 4) | ((int)p_a.subpixel_positioning << 8) | ((int)p_a.antialiasing << 12) | ((int)p_a.disable_embedded_bitmaps << 14) | ((int)p_a.keep_rounding_remainders << 15), hash));
|
||||
}
|
||||
};
|
||||
mutable HashMap<SystemFontKey, SystemFontCache, SystemFontKeyHasher> system_fonts;
|
||||
|
|
@ -700,7 +720,7 @@ class TextServerAdvanced : public TextServerExtension {
|
|||
};
|
||||
|
||||
protected:
|
||||
static void _bind_methods(){};
|
||||
static void _bind_methods() {}
|
||||
|
||||
void full_copy(ShapedTextDataAdvanced *p_shaped);
|
||||
void invalidate(ShapedTextDataAdvanced *p_shaped, bool p_text = false);
|
||||
|
|
@ -717,6 +737,7 @@ public:
|
|||
MODBIND0RC(String, get_support_data_filename);
|
||||
MODBIND0RC(String, get_support_data_info);
|
||||
MODBIND1RC(bool, save_support_data, const String &);
|
||||
MODBIND0RC(PackedByteArray, get_support_data);
|
||||
|
||||
MODBIND1RC(bool, is_locale_right_to_left, const String &);
|
||||
|
||||
|
|
@ -785,6 +806,9 @@ public:
|
|||
MODBIND2(font_set_subpixel_positioning, const RID &, SubpixelPositioning);
|
||||
MODBIND1RC(SubpixelPositioning, font_get_subpixel_positioning, const RID &);
|
||||
|
||||
MODBIND2(font_set_keep_rounding_remainders, const RID &, bool);
|
||||
MODBIND1RC(bool, font_get_keep_rounding_remainders, const RID &);
|
||||
|
||||
MODBIND2(font_set_embolden, const RID &, double);
|
||||
MODBIND1RC(double, font_get_embolden, const RID &);
|
||||
|
||||
|
|
@ -871,6 +895,7 @@ public:
|
|||
|
||||
MODBIND2RC(bool, font_has_char, const RID &, int64_t);
|
||||
MODBIND1RC(String, font_get_supported_chars, const RID &);
|
||||
MODBIND1RC(PackedInt32Array, font_get_supported_glyphs, const RID &);
|
||||
|
||||
MODBIND4(font_render_range, const RID &, const Vector2i &, int64_t, int64_t);
|
||||
MODBIND3(font_render_glyph, const RID &, const Vector2i &, int64_t);
|
||||
|
|
@ -935,6 +960,7 @@ public:
|
|||
|
||||
MODBIND1RC(int64_t, shaped_get_span_count, const RID &);
|
||||
MODBIND2RC(Variant, shaped_get_span_meta, const RID &, int64_t);
|
||||
MODBIND2RC(Variant, shaped_get_span_embedded_object, const RID &, int64_t);
|
||||
MODBIND5(shaped_set_span_update_font, const RID &, int64_t, const TypedArray<RID> &, int64_t, const Dictionary &);
|
||||
|
||||
MODBIND3RC(RID, shaped_text_substr, const RID &, int64_t, int64_t);
|
||||
|
|
|
|||
|
|
@ -1,70 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* thorvg_bounds_iterator.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifdef GDEXTENSION
|
||||
// Headers for building as GDExtension plug-in.
|
||||
|
||||
#include <godot_cpp/godot.hpp>
|
||||
|
||||
using namespace godot;
|
||||
|
||||
#elif defined(GODOT_MODULE)
|
||||
// Headers for building as built-in module.
|
||||
|
||||
#include "core/typedefs.h"
|
||||
|
||||
#include "modules/modules_enabled.gen.h" // For svg.
|
||||
#endif
|
||||
|
||||
#ifdef MODULE_SVG_ENABLED
|
||||
|
||||
#include "thorvg_bounds_iterator.h"
|
||||
|
||||
#include <tvgIteratorAccessor.h>
|
||||
#include <tvgPaint.h>
|
||||
|
||||
// This function uses private ThorVG API to get bounding box of top level children elements.
|
||||
|
||||
void tvg_get_bounds(tvg::Picture *p_picture, float &r_min_x, float &r_min_y, float &r_max_x, float &r_max_y) {
|
||||
tvg::IteratorAccessor itrAccessor;
|
||||
if (tvg::Iterator *it = itrAccessor.iterator(p_picture)) {
|
||||
while (const tvg::Paint *child = it->next()) {
|
||||
float x = 0, y = 0, w = 0, h = 0;
|
||||
child->bounds(&x, &y, &w, &h, true);
|
||||
r_min_x = MIN(x, r_min_x);
|
||||
r_min_y = MIN(y, r_min_y);
|
||||
r_max_x = MAX(x + w, r_max_x);
|
||||
r_max_y = MAX(y + h, r_max_y);
|
||||
}
|
||||
delete (it);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MODULE_SVG_ENABLED
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* thorvg_bounds_iterator.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef THORVG_BOUNDS_ITERATOR_H
|
||||
#define THORVG_BOUNDS_ITERATOR_H
|
||||
|
||||
#ifdef GDEXTENSION
|
||||
// Headers for building as GDExtension plug-in.
|
||||
|
||||
#include <godot_cpp/core/mutex_lock.hpp>
|
||||
#include <godot_cpp/godot.hpp>
|
||||
|
||||
using namespace godot;
|
||||
|
||||
#elif defined(GODOT_MODULE)
|
||||
// Headers for building as built-in module.
|
||||
|
||||
#include "core/typedefs.h"
|
||||
|
||||
#include "modules/modules_enabled.gen.h" // For svg.
|
||||
#endif
|
||||
|
||||
#ifdef MODULE_SVG_ENABLED
|
||||
|
||||
#include <thorvg.h>
|
||||
|
||||
void tvg_get_bounds(tvg::Picture *p_picture, float &r_min_x, float &r_min_y, float &r_max_x, float &r_max_y);
|
||||
|
||||
#endif // MODULE_SVG_ENABLED
|
||||
|
||||
#endif // THORVG_BOUNDS_ITERATOR_H
|
||||
|
|
@ -57,8 +57,6 @@ using namespace godot;
|
|||
|
||||
#include "thorvg_svg_in_ot.h"
|
||||
|
||||
#include "thorvg_bounds_iterator.h"
|
||||
|
||||
#include <freetype/otsvg.h>
|
||||
#include <ft2build.h>
|
||||
|
||||
|
|
@ -76,6 +74,46 @@ void tvg_svg_in_ot_free(FT_Pointer *p_state) {
|
|||
memdelete(state);
|
||||
}
|
||||
|
||||
static void construct_xml(Ref<XMLParser> &parser, double &r_embox_x, double &r_embox_y, String *p_xml, int64_t &r_tag_count) {
|
||||
if (parser->get_node_type() == XMLParser::NODE_ELEMENT) {
|
||||
*p_xml += vformat("<%s", parser->get_node_name());
|
||||
bool is_svg_tag = parser->get_node_name() == "svg";
|
||||
for (int i = 0; i < parser->get_attribute_count(); i++) {
|
||||
String aname = parser->get_attribute_name(i);
|
||||
String value = parser->get_attribute_value(i);
|
||||
if (is_svg_tag && aname == "viewBox") {
|
||||
PackedStringArray vb = value.split(" ");
|
||||
if (vb.size() == 4) {
|
||||
r_embox_x = vb[2].to_float();
|
||||
r_embox_y = vb[3].to_float();
|
||||
}
|
||||
} else if (is_svg_tag && aname == "width") {
|
||||
r_embox_x = value.to_float();
|
||||
} else if (is_svg_tag && aname == "height") {
|
||||
r_embox_y = value.to_float();
|
||||
} else {
|
||||
*p_xml += vformat(" %s=\"%s\"", aname, value);
|
||||
}
|
||||
}
|
||||
|
||||
if (parser->is_empty()) {
|
||||
*p_xml += "/>";
|
||||
} else {
|
||||
*p_xml += ">";
|
||||
if (r_tag_count >= 0) {
|
||||
r_tag_count++;
|
||||
}
|
||||
}
|
||||
} else if (parser->get_node_type() == XMLParser::NODE_TEXT) {
|
||||
*p_xml += parser->get_node_data();
|
||||
} else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END) {
|
||||
*p_xml += vformat("</%s>", parser->get_node_name());
|
||||
if (r_tag_count > 0) {
|
||||
r_tag_count--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Pointer *p_state) {
|
||||
TVG_State *state = *reinterpret_cast<TVG_State **>(p_state);
|
||||
if (!state) {
|
||||
|
|
@ -92,132 +130,164 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
|
|||
parser.instantiate();
|
||||
parser->_open_buffer((const uint8_t *)document->svg_document, document->svg_document_length);
|
||||
|
||||
float aspect = 1.0f;
|
||||
String xml_body;
|
||||
while (parser->read() == OK) {
|
||||
if (parser->has_attribute("id")) {
|
||||
const String &gl_name = parser->get_named_attribute_value("id");
|
||||
if (gl_name.begins_with("glyph")) {
|
||||
int dot_pos = gl_name.find(".");
|
||||
int64_t gl_idx = gl_name.substr(5, (dot_pos > 0) ? dot_pos - 5 : -1).to_int();
|
||||
if (p_slot->glyph_index != gl_idx) {
|
||||
parser->skip_section();
|
||||
continue;
|
||||
|
||||
double embox_x = document->units_per_EM;
|
||||
double embox_y = document->units_per_EM;
|
||||
|
||||
TVG_DocumentCache &cache = state->document_map[document->svg_document];
|
||||
|
||||
if (!cache.xml_body.is_empty()) {
|
||||
// If we have a cached document, that means we have already parsed it.
|
||||
// All node cache should be available.
|
||||
|
||||
xml_body = cache.xml_body;
|
||||
embox_x = cache.embox_x;
|
||||
embox_y = cache.embox_y;
|
||||
|
||||
ERR_FAIL_COND_V(!cache.node_caches.has(p_slot->glyph_index), FT_Err_Invalid_SVG_Document);
|
||||
Vector<TVG_NodeCache> &ncs = cache.node_caches[p_slot->glyph_index];
|
||||
|
||||
uint64_t offset = 0;
|
||||
for (TVG_NodeCache &nc : ncs) {
|
||||
// Seek will call read() internally.
|
||||
if (parser->seek(nc.document_offset) == OK) {
|
||||
int64_t tag_count = 0;
|
||||
String xml_node;
|
||||
|
||||
// We only parse the glyph node.
|
||||
do {
|
||||
construct_xml(parser, embox_x, embox_y, &xml_node, tag_count);
|
||||
} while (tag_count != 0 && parser->read() == OK);
|
||||
|
||||
xml_body = xml_body.insert(nc.body_offset + offset, xml_node);
|
||||
offset += xml_node.length();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
String xml_node;
|
||||
String xml_body_temp;
|
||||
|
||||
String *p_xml = &xml_body_temp;
|
||||
int64_t tag_count = -1;
|
||||
|
||||
while (parser->read() == OK) {
|
||||
if (parser->has_attribute("id")) {
|
||||
const String &gl_name = parser->get_named_attribute_value("id");
|
||||
if (gl_name.begins_with("glyph")) {
|
||||
#ifdef GDEXTENSION
|
||||
int dot_pos = gl_name.find(".");
|
||||
#else
|
||||
int dot_pos = gl_name.find_char('.');
|
||||
#endif // GDEXTENSION
|
||||
int64_t gl_idx = gl_name.substr(5, (dot_pos > 0) ? dot_pos - 5 : -1).to_int();
|
||||
|
||||
TVG_NodeCache node_cache = TVG_NodeCache();
|
||||
node_cache.document_offset = parser->get_node_offset(),
|
||||
node_cache.body_offset = (uint64_t)cache.xml_body.length();
|
||||
cache.node_caches[gl_idx].push_back(node_cache);
|
||||
|
||||
if (p_slot->glyph_index != gl_idx) {
|
||||
parser->skip_section();
|
||||
continue;
|
||||
}
|
||||
tag_count = 0;
|
||||
xml_node = "";
|
||||
p_xml = &xml_node;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (parser->get_node_type() == XMLParser::NODE_ELEMENT && parser->get_node_name() == "svg") {
|
||||
if (parser->has_attribute("viewBox")) {
|
||||
PackedStringArray vb = parser->get_named_attribute_value("viewBox").split(" ");
|
||||
|
||||
if (vb.size() == 4) {
|
||||
aspect = vb[2].to_float() / vb[3].to_float();
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (parser->get_node_type() == XMLParser::NODE_ELEMENT) {
|
||||
xml_body += vformat("<%s", parser->get_node_name());
|
||||
for (int i = 0; i < parser->get_attribute_count(); i++) {
|
||||
xml_body += vformat(" %s=\"%s\"", parser->get_attribute_name(i), parser->get_attribute_value(i));
|
||||
xml_body_temp = "";
|
||||
construct_xml(parser, embox_x, embox_y, p_xml, tag_count);
|
||||
|
||||
if (xml_body_temp.length() > 0) {
|
||||
xml_body += xml_body_temp;
|
||||
cache.xml_body += xml_body_temp;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (parser->is_empty()) {
|
||||
xml_body += "/>";
|
||||
} else {
|
||||
xml_body += ">";
|
||||
if (tag_count == 0) {
|
||||
p_xml = &xml_body_temp;
|
||||
tag_count = -1;
|
||||
xml_body += xml_node;
|
||||
}
|
||||
} else if (parser->get_node_type() == XMLParser::NODE_TEXT) {
|
||||
xml_body += parser->get_node_data();
|
||||
} else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END) {
|
||||
xml_body += vformat("</%s>", parser->get_node_name());
|
||||
}
|
||||
|
||||
cache.embox_x = embox_x;
|
||||
cache.embox_y = embox_y;
|
||||
}
|
||||
String temp_xml_str = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 1 1\">" + xml_body;
|
||||
CharString temp_xml = temp_xml_str.utf8();
|
||||
|
||||
std::unique_ptr<tvg::Picture> picture = tvg::Picture::gen();
|
||||
tvg::Result result = picture->load(temp_xml.get_data(), temp_xml.length(), "svg+xml", false);
|
||||
if (result != tvg::Result::Success) {
|
||||
ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to load SVG document (bounds detection).");
|
||||
}
|
||||
gl_state.xml_code = xml_body.utf8();
|
||||
|
||||
float min_x = INFINITY, min_y = INFINITY, max_x = -INFINITY, max_y = -INFINITY;
|
||||
tvg_get_bounds(picture.get(), min_x, min_y, max_x, max_y);
|
||||
|
||||
float new_h = (max_y - min_y);
|
||||
float new_w = (max_x - min_x);
|
||||
|
||||
if (new_h * aspect >= new_w) {
|
||||
new_w = (new_h * aspect);
|
||||
} else {
|
||||
new_h = (new_w / aspect);
|
||||
}
|
||||
|
||||
String xml_code_str = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"" + rtos(min_x) + " " + rtos(min_y) + " " + rtos(new_w) + " " + rtos(new_h) + "\">" + xml_body;
|
||||
gl_state.xml_code = xml_code_str.utf8();
|
||||
|
||||
picture = tvg::Picture::gen();
|
||||
result = picture->load(gl_state.xml_code.get_data(), gl_state.xml_code.length(), "svg+xml", false);
|
||||
tvg::Result result = picture->load(gl_state.xml_code.get_data(), gl_state.xml_code.length(), "svg+xml", false);
|
||||
if (result != tvg::Result::Success) {
|
||||
ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to load SVG document (glyph metrics).");
|
||||
}
|
||||
|
||||
float x_svg_to_out, y_svg_to_out;
|
||||
x_svg_to_out = (float)metrics.x_ppem / new_w;
|
||||
y_svg_to_out = (float)metrics.y_ppem / new_h;
|
||||
float svg_width, svg_height;
|
||||
picture->size(&svg_width, &svg_height);
|
||||
double aspect = svg_width / svg_height;
|
||||
|
||||
gl_state.m.e11 = (double)document->transform.xx / (1 << 16) * x_svg_to_out;
|
||||
gl_state.m.e12 = -(double)document->transform.xy / (1 << 16) * x_svg_to_out;
|
||||
gl_state.m.e21 = -(double)document->transform.yx / (1 << 16) * y_svg_to_out;
|
||||
gl_state.m.e22 = (double)document->transform.yy / (1 << 16) * y_svg_to_out;
|
||||
gl_state.m.e13 = (double)document->delta.x / 64 * new_w / metrics.x_ppem;
|
||||
gl_state.m.e23 = -(double)document->delta.y / 64 * new_h / metrics.y_ppem;
|
||||
result = picture->size(embox_x * aspect, embox_y);
|
||||
if (result != tvg::Result::Success) {
|
||||
ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to resize SVG document.");
|
||||
}
|
||||
|
||||
double x_svg_to_out = (double)metrics.x_ppem / embox_x;
|
||||
double y_svg_to_out = (double)metrics.y_ppem / embox_y;
|
||||
|
||||
gl_state.m.e11 = (double)document->transform.xx / (1 << 16);
|
||||
gl_state.m.e12 = -(double)document->transform.xy / (1 << 16);
|
||||
gl_state.m.e21 = -(double)document->transform.yx / (1 << 16);
|
||||
gl_state.m.e22 = (double)document->transform.yy / (1 << 16);
|
||||
gl_state.m.e13 = (double)document->delta.x / 64 * embox_x / metrics.x_ppem;
|
||||
gl_state.m.e23 = -(double)document->delta.y / 64 * embox_y / metrics.y_ppem;
|
||||
gl_state.m.e31 = 0;
|
||||
gl_state.m.e32 = 0;
|
||||
gl_state.m.e33 = 1;
|
||||
|
||||
result = picture->size(embox_x * aspect * x_svg_to_out, embox_y * y_svg_to_out);
|
||||
if (result != tvg::Result::Success) {
|
||||
ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to resize SVG document.");
|
||||
}
|
||||
|
||||
result = picture->transform(gl_state.m);
|
||||
if (result != tvg::Result::Success) {
|
||||
ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to apply transform to SVG document.");
|
||||
}
|
||||
|
||||
result = picture->bounds(&gl_state.x, &gl_state.y, &gl_state.w, &gl_state.h, true);
|
||||
if (result != tvg::Result::Success) {
|
||||
ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to get SVG bounds.");
|
||||
}
|
||||
|
||||
gl_state.bmp_y = gl_state.h + metrics.descender / 64.f;
|
||||
gl_state.bmp_x = 0;
|
||||
picture->size(&gl_state.w, &gl_state.h);
|
||||
gl_state.x = (gl_state.h - gl_state.w) / 2.0;
|
||||
gl_state.y = -gl_state.h;
|
||||
|
||||
gl_state.ready = true;
|
||||
}
|
||||
|
||||
p_slot->bitmap_left = (FT_Int)gl_state.bmp_x;
|
||||
p_slot->bitmap_top = (FT_Int)gl_state.bmp_y;
|
||||
p_slot->bitmap_left = (FT_Int)gl_state.x;
|
||||
p_slot->bitmap_top = (FT_Int)-gl_state.y;
|
||||
|
||||
float tmp = ceil(gl_state.h);
|
||||
p_slot->bitmap.rows = (unsigned int)tmp;
|
||||
tmp = ceil(gl_state.w);
|
||||
p_slot->bitmap.width = (unsigned int)tmp;
|
||||
double tmpd = Math::ceil(gl_state.h);
|
||||
p_slot->bitmap.rows = (unsigned int)tmpd;
|
||||
tmpd = Math::ceil(gl_state.w);
|
||||
p_slot->bitmap.width = (unsigned int)tmpd;
|
||||
p_slot->bitmap.pitch = (int)p_slot->bitmap.width * 4;
|
||||
|
||||
p_slot->bitmap.pixel_mode = FT_PIXEL_MODE_BGRA;
|
||||
|
||||
float metrics_width, metrics_height;
|
||||
float horiBearingX, horiBearingY;
|
||||
float vertBearingX, vertBearingY;
|
||||
float metrics_width = (float)gl_state.w;
|
||||
float metrics_height = (float)gl_state.h;
|
||||
|
||||
metrics_width = (float)gl_state.w;
|
||||
metrics_height = (float)gl_state.h;
|
||||
horiBearingX = (float)gl_state.x;
|
||||
horiBearingY = (float)-gl_state.y;
|
||||
vertBearingX = p_slot->metrics.horiBearingX / 64.0f - p_slot->metrics.horiAdvance / 64.0f / 2;
|
||||
vertBearingY = (p_slot->metrics.vertAdvance / 64.0f - p_slot->metrics.height / 64.0f) / 2;
|
||||
float horiBearingX = (float)gl_state.x;
|
||||
float horiBearingY = (float)-gl_state.y;
|
||||
|
||||
tmp = roundf(metrics_width * 64);
|
||||
p_slot->metrics.width = (FT_Pos)tmp;
|
||||
tmp = roundf(metrics_height * 64);
|
||||
p_slot->metrics.height = (FT_Pos)tmp;
|
||||
float vertBearingX = p_slot->metrics.horiBearingX / 64.0f - p_slot->metrics.horiAdvance / 64.0f / 2;
|
||||
float vertBearingY = (p_slot->metrics.vertAdvance / 64.0f - p_slot->metrics.height / 64.0f) / 2;
|
||||
|
||||
float tmpf = Math::round(metrics_width * 64);
|
||||
p_slot->metrics.width = (FT_Pos)tmpf;
|
||||
tmpf = Math::round(metrics_height * 64);
|
||||
p_slot->metrics.height = (FT_Pos)tmpf;
|
||||
|
||||
p_slot->metrics.horiBearingX = (FT_Pos)(horiBearingX * 64);
|
||||
p_slot->metrics.horiBearingY = (FT_Pos)(horiBearingY * 64);
|
||||
|
|
@ -250,6 +320,10 @@ FT_Error tvg_svg_in_ot_render(FT_GlyphSlot p_slot, FT_Pointer *p_state) {
|
|||
if (res != tvg::Result::Success) {
|
||||
ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to load SVG document (glyph rendering).");
|
||||
}
|
||||
res = picture->size(gl_state.w, gl_state.h);
|
||||
if (res != tvg::Result::Success) {
|
||||
ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to resize SVG document.");
|
||||
}
|
||||
res = picture->transform(gl_state.m);
|
||||
if (res != tvg::Result::Success) {
|
||||
ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to apply transform to SVG document.");
|
||||
|
|
|
|||
|
|
@ -60,8 +60,6 @@ using namespace godot;
|
|||
|
||||
struct GL_State {
|
||||
bool ready = false;
|
||||
float bmp_x = 0;
|
||||
float bmp_y = 0;
|
||||
float x = 0;
|
||||
float y = 0;
|
||||
float w = 0;
|
||||
|
|
@ -70,9 +68,22 @@ struct GL_State {
|
|||
tvg::Matrix m;
|
||||
};
|
||||
|
||||
struct TVG_NodeCache {
|
||||
uint64_t document_offset;
|
||||
uint64_t body_offset;
|
||||
};
|
||||
|
||||
struct TVG_DocumentCache {
|
||||
String xml_body;
|
||||
double embox_x;
|
||||
double embox_y;
|
||||
HashMap<int64_t, Vector<TVG_NodeCache>> node_caches;
|
||||
};
|
||||
|
||||
struct TVG_State {
|
||||
Mutex mutex;
|
||||
HashMap<uint32_t, GL_State> glyph_map;
|
||||
HashMap<FT_Byte *, TVG_DocumentCache> document_map;
|
||||
};
|
||||
|
||||
FT_Error tvg_svg_in_ot_init(FT_Pointer *p_state);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue